Squashed 'third_party/protobuf/' changes from e35e248..48cb18e

48cb18e Updated change log for 3.6.1 release
9e1286b Updated version numbers to 3.6.1
e508fc0 Check the message to be encoded is the wrong type. (#4885) (#4949)
fc90fd6 Make assertEquals pass for message (#4947)
d85ffdc Merge pull request #4924 from xfxyjwf/3.6.x
8356d27 Add continuous test for ruby 2.3, 2.4 and 2.5 (#4829)
7fdebf2 Fix cpp_distcheck
6c82411 Fix php conformance test.
11e2eca protoc-artifacts: Update centos base from 6.6 to 6.9
6fc2bac Updated Docker setup to use GCC 4.8
b3e4e3a Remove js_embed binary. (#4709)
0b3b470 Fix cpp benchmark dependency on mac
ae8def6 Comment out unused command from release script.
9327dc7 Run autogen.sh in release script.
9209a41 Add protoc release script for Linux build.
4d0fbd1 Add cpp tests under release docker image.
474fd31 Update protoc build scripts.
b23429e Fix 32bit php tests
8758cc1 Fix php tests
bd1224e fix golang kokoro linux build
359889b fix python cpp kokoro build
c1e6c4d fix linux kokoro build in docker
22503a0 fix for API change in PHP 7.3 (#4898)
e529d16 Make ruby release configs consistent with protoc.
82019f9 Merge pull request #4900 from xfxyjwf/3.6.x
0e38f9e Fix bazel build of examples.
b5975c1 Add kokoro bazel configs for 3.6.x branch.
4a4a60b Merge pull request #4880 from nashimus/3.6.x
e184577 Merge pull request #4878 from acozzette/fix-msvc-initialization
1f7837a Additional support for building and deploying ppcle_64 artifacts
a9abc78 Fix initialization with Visual Studio
f7ada12 Build ruby gem on kokoro (#4819)
56d2753 Rename build_artifacts.cfg to release.cfg (#4818)
b907a03 Add files to build ruby artifact for mac on kokoro (#4814)
ad85c3b Added Kokoro protoc release build for OS X (#4770)
885be9c Work around MSVC issue with std::atomic initialization (#4777)
b0a8220 Added Kokoro Windows release build config for protoc (#4766)
ce04481 Use legacy name in php runtime (#4741)
d6353b4 Update php version to 3.6.0 (#4736)
ab8edf1 Merge pull request #4713 from acozzette/changelog
6ed0141 Merge pull request #4730 from acozzette/xcode
a3f31bf Update code to work for Xcode 10b1 (#4729)
9b77e9e Removed javanano from post_process_dist.sh
adf84b4 Updated the change log with changes for 3.6.0
7e199b9 Merge pull request #4706 from acozzette/cxx-11
39d2f70 Require C++11 and pass -std=c++11
a239ed2 Merge pull request #4702 from TeBoring/3.6.x
4f5eb10 Move methods out of class (#4697)
397ddf9 Add back GeneratedClassName to public (#4686)
d31864a Merge pull request #4696 from acozzette/csharp-fix
6c12ff5 Merge pull request #4695 from TeBoring/3.6.x
9d64d74 Removed duplicate using statement from ReflectionUtil.cs
5bf35ec Fix php memory leak test (#4692)
edaaea0 Merge pull request #4687 from acozzette/js-map-parsing-fix
d1af029 Fixed JS parsing of unspecified map keys
6f723a6 Always add -std=c++11 for mac (#4684)
4885b80 Merge pull request #4675 from TeBoring/3.6.x
dadc954 Fix array constructor in c extension for compatibility (#4667)
2774e54 PHP namespaces for nested messages and enums (#4536)
8b336f8 Implement array constructor in php c extension.
c9b404d PHP array constructors for protobuf messages (#4530)
7eba624 Add missing ruby/tests/test_ruby_package.proto
c19fcee Allows the json marshaller to be passed json marshal options (#4252)
5289ee0 Adopt ruby_package in ruby generated code. (#4627)
d8483a9 Adopt php_metadata_namespace in php code generator (#4622)
449e532 Merge pull request #4673 from acozzette/memory-leak-fix
daf039b Make sure to delete temporary maps used by FileDescriptorTables
15cde29 Merge pull request #4625 from liujisi/3.6.x
45eb28b Update version number to 3.6.0
b61dd9d Add file option php_metadata_namespace and ruby_package (#4609)
2213c1c Merge pull request #4538 from Mizux/patch-2
7377d81 Throw error if user want to access message properties (#4603)
5f7334f Avoid direct check of class name (#4601)
5f9232b use brew install instead of easy_install in OSX (#4537)
25625b9 Merge pull request #4590 from PetterS/undefined_fix
d14cacd Fix error in Clang UndefinedBehaviorSanitizer
513b35d Add VS2017 optional component dependency details to the C# readme (#4128)
4a09836 Fix python ext build on kokoro (#4527)
92898e9 Merge pull request #4586 from chronoxor/master
3474155 MinGW build failed
b0403a7 Merge pull request #4583 from chronoxor/master
f80a886 Cygwin build failed
05c2d01 Fix RepeatedField#delete_if (#4292)
0869b1a Add space between class name and concat message (#4577)
306f4e3 Merge pull request #4581 from Yeolar/3rd_rpc_raster
7d97808 [objectivec] Fix memory leak of exceptions raised by RaiseException() (#4556)
35e4430 Add third-party RPC implementation: raster - a network framework supports pbrpc by 'service' keyword.
fc922d1 Merge pull request #4568 from hectim/master
7f2c3ce Merge pull request #4550 from Mizux/master
1b219a1 Fix to allow AOT compilers to play nicely with reflection
9ba2fd3 typo
a21f225 Merge pull request #4553 from pherl/ruby
9972e16 Set ext.no_native = true for non mac platform
2bd7f51 fix duplicate mkdir in update_file_lists.sh
c3b152c CMake: Update CXX Standard management
3ad8efc Add .proto files to extract_includes.bat
8417871 Move to Xcode 9.3 which also means a High Sierra image.
b59da6d Remove the iOS Test App.
c36eeed Merge pull request #4520 from BSBandme/fix_kokoro_benchmark_build
4ca46ed Write messages to backing field in generated C# cloning code (#4440)
0dc4d75 Merge pull request #4504 from xfxyjwf/lite
a29e2bf Update Makefile.am for Java lite files.
8f35073 Fix benchmark build
9497a65 Merge pull request #4517 from rcane/feature/vc2017_build_fix
a9d9326 Merge pull request #4510 from BSBandme/fix_kokoro_benchmark_build
7d6d5f9 Fixed a Visual Studio 2017 build error. (#4488)
0921345 fix java benchmark, fix dashboard build
7d55040 Cleanup + documentation for Java Lite runtime.
320d56c Merge pull request #4478 from BSBandme/proto2_to_proto3_tools
e3af023 fix python
76d76ae fix conflicts
c703061 Add gogo benchmark
5fb73f8 Merge pull request #4415 from BSBandme/experiement
805174e Add script for run and upload the benchmark result to bq
d7d863e fix json_decode call parameters (#4381)
13e627a includes the expected class in the exception, otherwise the error is harder to track down (#3371)
451e044 Add __init__.py files to compiler and util subpackages (#4117)
3b6d027 For windows, all python version should use /MT (#4468)
dce8229 Add the files added in #4485.
ce24b8a Update Xcode settings
da3ce67 Deliberately call simple code to avoid Unity linker pruning
a72da27 Merge pull request #4475 from chenchuanyin/patch-1
e7e6c6b Merge pull request #4283 from ObsidianMinor/csharp/better-test-runners
f72ac9f Updated csharp/README.md to reflect testing changes
d3e8a54 Fix problem: cmake build failed in c++11  by clang
c931743 Merge branch (#4466)
579f81e js message support for jstype string on integers (#4332)
40d6eca Merge pull request #4467 from xfxyjwf/error
8f88a50 Improve error message when googletest is missing.
7f92711 Merge pull request #4411 from pravin-dsilva/protobuf-ppc64le
4274e6a Merge pull request #4447 from ejona86/cleaner-protoc-artifacts
c934d1d Merge pull request #4452 from xfxyjwf/doc
aab0f89 Merge pull request #4464 from thomasvl/includes3
bd941d5 Don't generate imports for the WKTs unless generating the WKTs.
e998b8f Add compile test sources for to test include order.
bca797d Trim imports for bundled generated protos.
014e76e Update instructions about getting protobuf source.
cdbfdd8 protoc-artifacts: Use ENTRYPOINT to enable devtoolset-1.1
67c1cd4 protoc-artifacts: Avoid storing temporary files and use fewer layers
5f052ae protoc-artifacts: Avoid checking out protobuf code
7bf47a6 Merge pull request #4433 from xfxyjwf/license
c8ed695 Merge pull request #4445 from xfxyjwf/badge
eac0e92 Add kokoro build status badges.
59c4328 Merge pull request #4442 from xfxyjwf/clean
107cd70 Delete unused directories.
d3d7cdb Merge pull request #4439 from acozzette/remove-atomicops-stub
612b670 Updated .gitignore to exclude downloaded gmock/ directory
4875dfe Removed atomicops.h since it is no longer used
2537bea Merge pull request #3794 from jskeet/reflection
9c05c35 Address review comments
7b19d20 Add extra C# file to Makefile.am
8e23d4e Work around an "old runtime" issue with reflection
aa59eaa Introduce a compatiblity shim to support .NET 3.5 delegate creation
8ba420f Change C# reflection to avoid using expression trees
63bba9b Merge pull request #4432 from xfxyjwf/rmnanokokoro
5050269 Merge pull request #4434 from xfxyjwf/buildstatus
9f5bded Remove broken build status icons.
9e080f7 Cleanup LICENSE file.
68de0cf Delete javanano kokoro build configs.
3c5442a Include googletest as a submodule (#3993)
1156ee7 source code info for interpreted options; fix source code info for extension range options (#4342)
d34e319 Merge pull request #4431 from xfxyjwf/rmnano
379b7ff Fixes MSVC compiler warning C4800 "Forcing value to bool 'true' or 'false'" (#4350)
ac67376 Merge pull request #4395 from stone4774/fixbug_enum2json2
d5a0024 Remove javanano.
416d418 Merge pull request #4424 from egorpugin/patch-1
dc68d98 Fix missing LIBPROTOC_EXPORT.
2c963d3 Merge pull request #4413 from pmuetschard/msvc
eff52b1 Merge pull request #4422 from acozzette/ruby-conformance
cf7af01 Merge pull request #4421 from acozzette/fix-bazel-build
f91cf05 Updated Ruby conformance test failure list
5bed368 Added missing .inc files to BUILD
a7a746f Merge pull request #4346 from BSBandme/performance_result
745ef89 Add performance.md and add instruction for linking tcmalloc
227363b Merge pull request #4412 from acozzette/remove-old-files
a6957f2 Don't assume Windows builds use MSVC.
0c5fcde Removed some unused C++ source files
36ba04b Add support for power ppc64le
c99f527 Merge branch 'master' into fixbug_enum2json2
d053271 Use the first enum value instead of 0 in DefaultValueObjectWriter::FindEnumDefault
ed4321d Merge pull request #4387 from acozzette/down-integrate
e436ee0 Merge pull request #4361 from BSBandme/go_benchmark
88a4884 Merge pull request #4345 from jskeet/list-json-null
11d26ce Removed unused variables in repeated_scalar_container.cc
fcde518 Try using a new version of Visual Studio on AppVeyor
8b3a72f Removed unused code pertaining to shared_ptr
ec40953 Updated conformance failure lists
ec57f51 Added map_lite_test.proto to fix LiteTest
c5fcce5 Added pyext/thread_unsafe_shared_ptr.h
3fa5dad Removed unrecognized option from no_package.proto
00b1c14 Added new test source files to Makefile.am
616fe05 Removed use of some type traits
d6323c8 Change to deal all messages in one loop
d6a17aa Merge pull request #4397 from pherl/catlog
4880027 Cat the test-suite.log on errors for presubits
773d8c3 Fix bug: whether always_print_enums_as_ints is true or false, it always print the default value of enums as strings
ab95b1b Merge pull request #4371 from Rasrack/gnuc_minor
aae10ed Merge pull request #4370 from felixjendrusch/objc-output-stream-write-check
813848d Merge pull request #4222 from JohnHBrock/increasing_max_csharp_message_size
d5f5725 Merge pull request #4310 from KindDragon/patch-1
837c94b Include no_package.proto in Python test
67952fa Deleted scoped_ptr.h
b1216d9 Updated checked-in generated code
64a5c80 Fixed up proto3_lite_unittest.cc
501c13f Rewrite go_benchmark
afe96b6 Merge branch 'master' into down-integrate
0400cca Integrated internal changes from Google
89b5333 Merge pull request #4378 from acozzette/node-buffer
4f11025 Merge pull request #4167 from mike9005/patch-1
6d2c6a0 some fix
5487d8c Merge pull request #4380 from mateuszmatejczyk/patch-1
4787519 Merge pull request #1333 from cgull/pkg-config-issue
294b575 Output *_pb2_grpc.py when use_grpc_plugin=True
0e34c86 Fix spelling error of __GNUC_MINOR__
f8005a5 Revert "Removed mention of Buffer in byteSourceToUint8Array"
8e44a86 Merge pull request #4347 from xfxyjwf/pluginpb
6ebfa14 Merge pull request #4375 from jo2y/protoc-default
950f5e4 Replace //:protoc and similar default macro arguments with @com_google_protobuf prefixed versions. This allows them to work in 3rd party repositories.
6dd563a Sync upb change (#4373)
1da9ffe Check return value on write of raw pointer
38508e9 Add test for failing write of raw pointer to output stream
4e3c413 Add go benchmark
a48d58d Convert descriptortype to type for upb_msgval_sizeof (#4357)
0f4ad85 For encoding upb needs descriptor type instead of type. (#4354)
55d0758 Merge pull request #4355 from acozzette/typo
5004d09 PHP: fixed typo in message.c
fd595fc Revert "Move `compiler/plugin.pb.cc` to libprotobuf with the other WKT sources."
5140bae Add conformance test for null value in list JSON
822b924 Allow list values to be null when parsing
9dc0a4d Merge pull request #4183 from pcc/win-libcxx
325ecff Merge pull request #4333 from jmillikin/update-file-lists-needs-bash
32db4d3 Merge pull request #4334 from jmillikin/blacklist-internal-proto-srcs
3aaed96 Merge pull request #4195 from alexey-malov/IgnoreUnknownEnumsInJson
bb40c0c Merge pull request #4291 from google/3.5.x
350b135 Blacklist all WELL_KNOWN_PROTOS from Bazel C++ code generation.
724f0be Move `compiler/plugin.pb.cc` to libprotobuf with the other WKT sources.
2e4c52a `update_file_lists.sh` depends on Bash features, thus needs Bash sebang.
a6037c5 Merge pull request #4324 from abdul-sami/master
ac021a0 Merge pull request #1 from abdul-sami/abdul-sami-patch-1
fe33c5f Added instruction for existing ZLIB configuration
177108a Merge pull request #4323 from dtapuska/master
af3813c Rename a shadowed variable.
0475607 Merge pull request #3186 from gkelly/remove-unused-variable
22c477d Support using MSVC intrinsics in Log2FloorNonZero
02452db The JsonParseOptions::ignore_unknown_fields option behavior treats unrecognized string values in enum fields as default ones.
e34ec60 Only check filenames when end with .py in _CalledFromGeneratedFile() (#4262)
96b535c Merge pull request #4302 from BSBandme/down_integ_benchmark
6cd4ec4 Sync internal benchmark changes
4da7706 Remove stray indent on normal imports.
b8e4783 Merge pull request #4288 from nico/nofall
07f0231 Fix up the docs to mention the WKTs generated files also.
c66dd6c Remove use of GOOGLE_FALLTHROUGH_INTENDED from protobuf.
8b2ba9e Remove Google.Protobuf.Test/Program.cs from Makefile.am
a731ecb Adjusted appveyor batch
e823897 Updated NUnit packages, removed NUnitLite added packages for dotnet and Visual Studio, changed dotnet command in buildall to dotnet test, and deleted Program.cs (because it's no longer required).
82e0231 Merge pull request #4259 from Mizux/master
5dad7cc Merge pull request #4257 from davido/support_java9
9717d6f Merge pull request #4265 from BSBandme/upgrade_benchmark_submodule
1ec9beb Use NEW behaviour for project VERSION variables.
8dd0f4e Even with MSVC enable zlib support as default behaviour.
f7a0584 Add CMake ALIAS targets
3bc0282 Add VERSION property to CMake library targets
7f14915 upgrade submodule
4e2bd9e Merge pull request #4266 from brunokim/patch-1
0d397a1 Fix link markup in third party list.
6456e5d Merge pull request #4239 from mrpi/master
85b488f Bazel: Support building with Java 9
864df89 Remove 64MB memory limit when deserializing messages in C#
cf016a4 Work around strange error with atomic and swift under Xcode 8.3.3.
d570d48 Don't assume c-strings are 4 byte aligned.
d83837d Fix to use "nil" instead of "NULL" for objc objects.
81aeed0 Work around the static analyzer false report.
953adb1 Add casts to removed undefined behaviors around shifts.
b718551 Merge pull request #4249 from nlochschmidt/patch-1
204a641 Move kokoro macOS builds to to Xcode 9.1.
14e8852 Fix -fpermissive: '<::' cannot begin a template-argument list
69b1fdc Propose kotlinx.serialization as 3rd party lib
25a90e8 Merge pull request #3825 from ras0219-msft/patch-1
aaf41c6 Add Vcpkg to C++ installation instructions for Windows
1681fe6 Merge pull request #4196 from mathstuf/cmake-private-target-sources
f438ebd Merge pull request #4240 from davido/generate_warning_free_java_code
da6b07a Merge pull request #4209 from acozzette/using-statements
86fdad0 Java: Generate warning free code
39a789e Removed using statements from common.h
91317c2 Merge pull request #4236 from pherl/3.5.x
2a8e102 Bumping number to fix ruby 2.1 on mac
c236896 Merge pull request #4229 from leighmcculloch/patch-1
4a3b42e Remove broken link to code.google.com/p/protorpc
ed14fe4 Merge pull request #3934 from xfxyjwf/builtsources
0c52335 Update .NET SDK to 2.0.3
51293f3 Fix more memory leak for php c extension (#4211)
94f3be0 Merge pull request #4226 from themattchan/patch-1
3e1587f Add an explicit import of stdatomic.h.
6fd2ae7 Bring back import of OSAtomic.
72337d6 Add Haskell implementations
1d02e45 Merge pull request #4224 from davido/drop_java_6_support
019ceea Drop java 6 support
c337d9f Remove the use of BUILT_SOURCES
9ab859f Create std::string in Arena memory
80e016e Merge pull request #4205 from xuwei-k/patch-2
a721bf6 Migrate away from deprecated OSAtomic APIs. (#4184)
1c3b20b fix typo in FieldMaskTree.java comment
9d0a44c cmake: privately add sources to targets
cbdeb6a Merge pull request #4185 from pherl/ruby2.5
53d907f Update rake file to build of 2.1.6.
3ba21cd Add support for libc++ on Windows.
979c2cd Merge pull request #4182 from pherl/ruby2.5
d9f0f0b Support ruby2.5
47b7d2c Add DiscardUnknownFields support for C#
2a6eaeb Fix scope resolution for MessageExts in Ruby
9f80df0 Merge pull request #4158 from BSBandme/FixBenchmarks
473a810 Update py_benchmark.py
fa60e55 Fix java benchmark to use parser, fix cpp benchmark new arena to use Reset, format some files
b77aa80 Merge pull request #4148 from datacompboy/patch-2
d4afdba Merge pull request #4147 from datacompboy/patch-1
bab843b Merge pull request #4132 from BSBandme/JavaCaliperCounter
195253c Add counter to Java benchmark
4adc5a4 Merge pull request #4065 from BSBandme/python_benchmark_real
091eeb1 Update time_test.cc
473c5cf Fix ValidateDateTime: check day instead month
3823897 Well known types are not initialized properly. (#4139)
2fc69b1 Add python benchmark
5aa8f98 Merge pull request #4146 from pherl/fix_protoc
366192f Bump protoc-artifact version for a patch rebuild
a3868af Merge pull request #4131 from pherl/merge
eca1d2a Merge pull request #4116 from amandeepgautam/master
0c0d481 whitelisting aix platform as it has sched_yield
4588e6e Force a copy when saving the NSData that came from another.
43caa38 Merge pull request #4014 from BSBandme/JavaCaliper
ec826c5 Merge remote-tracking branch 'origin/3.5.x' into master
383a494 Merge remote-tracking branch 'origin/3.5.x' into master
39f577c Merge pull request #4124 from pherl/nullptr
5b1caea Merge pull request #4090 from pherl/nopassword
156161d Properly copy maps with string keys but pod values.
aca6c15 Fix some bug
4f3d865 remove nullptr
a147a21 Changed README
8529f2a Resolved issue #3510. Malformed errorr messages replaced with meaningful description
8fc40b5 Fix uploading binary wheel.
88e5573 Merge pull request #4089 from pherl/nocache
7ad8e7a Disable pip cache when testing uploaded packages
099d997 Merge pull request #4083 from matt-kwong/kokoro_jobs
0b2be3c Shard 64-bit Linux languages into different Kokoro jobs
4b2977b Merge pull request #4082 from matt-kwong/kokoro_jobs
ae49cfd Collect xml results for Kokoro
106ffc0 Merge pull request #4073 from pherl/changelog
d69f333 Merge pull request #4080 from pherl/arm64
6003a61 Make Kokoro job pull Dockerimage from Dockerhub
ad8a82e Add support for Windows ARM64 build
b5f09c1 Merge pull request #4077 from mkamilov/master
a5b743f Merge pull request #4030 from cyyber/master
7bf1e19 Update changelog
1e418e4 Merge pull request #4068 from wsw2016/fix_4032
ac1fdd1 line breaks adjsted
e68caa3 formatting issues
d106399 Merge pull request #4072 from google/jieluo
6c3c7f6 Merge pull request #4076 from pherl/stringback
b308580 Cherrypick for csharp, including: Add preserve UnknownFields Compare floating point values bitwise Add auto-generated header to C# generated files
19d0e99 Fix string::back() usage in googletest.cc
62616e1 Update changelog
96810de Merge branch '3.5.x' of github.com:google/protobuf into changelog
eff55ec Merge pull request #4074 from pherl/mapat
8ac050f Migrate Jenkins jobs to Kokoro
9ce29bd Merge pull request #4070 from pherl/3.5.x
501093d Replace C++11 only method std::map::at
7bd1606 Update changelog for 3.5.1
050fc9a Update version number to 3.5.1
ffa18ad resolve issue 4032 and added a unit test
03fb099 Add support for Windows ARM64 build
860d693 Add Xcode 9.2 to the testing support
3a06fe1 Fix file permission for python package.
77d32bc Merge pull request #4053 from xfxyjwf/fixumask
c79ba5c Merge pull request #4034 from TeBoring/php-timestamp-bug
269884a Merge pull request #4040 from bazurbat/3.5.x
0fc85ac Fix file permission for python package.
4b02091 add cpp
396336e Merge pull request #4046 from acozzette/deprecated-valueof-issue-2054
8d6f13e Fix for php5.5
1237c3f Merge pull request #4045 from pherl/deprecate
d971cbf Merge pull request #4049 from pherl/py26
39159c8 Accept DatetimeInterface in fromDatetime
0e2089c Calling Keychecker before checking key in MessageMap
acadade Remove py2.6 support.
594ec22 Fix python descriptor test.
cd32aae Merge branch 'master' of https://github.com/google/protobuf into JavaCaliper
75523ec fix bugs
1a549d9 Avoid using php_date_get_date_ce() in case date extension is not available.
0350111 Generate an annotation to suppress deprecation warnings
426cf6f Add auto-generated header to C# generated files (#4038)
34843ed Fix bugs
a4f68d4 Merge pull request #4044 from xfxyjwf/issue3268
00ac5c1 Merge pull request #4041 from acozzette/fix-license-issue-1775
22e1cfd Add deprecation annotation for oneof case.
b3ac441 Update generated code.
bfd254e  Add unknown field support for csharp (#3936)
50ef6a6 Avoid two consecutive underscores in macro name.
82724e2 Merge pull request #4042 from pherl/cpp_enum
8521624 Merge pull request #4043 from pherl/flush
0a7120a Merge pull request #4037 from xfxyjwf/issue2880
6b01e64 Explicitly propagate the status of Flush().
7ef21dd Use matching enum type for IsPOD.
ecab9c6 Added our standard license header to structurally_valid.cc and its test
edcf15e Create containing directory before generating well_known_types_embed.cc
5ce724b Merge pull request #4036 from xfxyjwf/issue3093
fffe8d3 Call php method via function name instead of calling directly.
0f9bfa8 Merge pull request #4016 from jquesnelle/string-access-ub
27e877f Merge pull request #2834 from aj-michael/master
6c27550 Clarify default value behavior in JSON conversion.
75eceb8 Update generated code.
8489612 Update comments for Timestamp JSON format.
f69a5db Merge pull request #4028 from TeBoring/3.5.x
88102ea Replace private timelib_update_ts with public date_timestamp_get
9f6acea Add PROTOBUF_ENABLE_TIMESTAMP to let user decide whether timestamp util can be used at install time.
5e732e3 Add caliper supported to java benchmark
b1386e7 Merge pull request #4026 from TeBoring/3.5.x
3b13c3f Add backslach to make class explict in global namespace
fc5818b Merge branch '3.5.0.1' into 3.5.x
31c54d1 Regenerated code from previous C# codegen commit
3e5bd2f C# code generation changes to use bitwise comparisons for doubles
f3e9a65 Compare floating point values bitwise in C#
618f06f Merge pull request #4007 from graywolf/patch-1
a426833 Merge pull request #4000 from Kwizatz/master
cf7c15e Fix ruby gc_test in ruby 2.4 (#4011)
9b09a2a Merge pull request #4017 from acozzette/update-file-lists
0fcca8f Merge pull request #4018 from acozzette/android-portable-log2-floor
f5b0862 use const char* instead of const std::string& in normalize()
63a0afc Use the portable version of Log2Floor for Clang with older Android NDK versions
0e7b589 Add discard unknown API in ruby. (#3990)
609d752 Ran update_file_lists.sh to update Bazel and CMake file lists
b32c2a8 fix undefined behavior in C++03
24493ee Using binary one's complement to negate an unsigned int
c370f88 Recursively clear unknown fields in submessages. (#3982)
1b5b3b2 Merge pull request #4013 from laszlocsomor/io_win32
a3a1c93 io_win32_unittest: remove incorrect error check
eb3bd6e io_win32_unittest: fix condition in GetCwdAsUtf8
3f1b1a6 io_win32_unittest: use CWD as last tempdir
57a01c7 io_win32: add more encoding-related tests
65da9fd io_win32: support non-ASCII paths
953a025 io_win32_unittest: make //:win32_test run again
457f6a6 Add release log
ba60b85 Update php c extension version number to 3.5.0.1
212563d Fix memory leak in php7
3b7a5f4 Fix several more memory leak
7d34371 Fix memory leak when creating map field via array.
e0d3aa0 Fix memory leak when creating repeated field via array.
de44982 Remove duplicate typedef. (#3975)
0316ae8 --pre is not necessary
9021f62 Merge pull request #3988 from acozzette/down-integrate
173f304 Merge pull request #3926 from BSBandme/down_sync_benchmark
e372df5 Fixed failing JS tests
db7c043 Merge pull request #3968 from fahhem/patch-2
35119e3 Add a check_protobuf_required_bazel_version() for use in WORKSPACEs
1fd6c17 Fix bugs to pass tests
7bb8584 Updated conformance failure lists
b140cb3 Fix memory leak when creating map field via array.
716acc3 Remove Xcode directives on some configs.
1acacf4 Fix memory leak when creating repeated field via array.
1c062a6 Sync internal benchmark changes
5d647e1 Updated Makefile.am to add a new file to EXTRA_DIST
0ba8eea Merge branch 'master' into down-integrate
92a7e77 Integrated internal changes from Google
a711e3d Merge pull request #3979 from acozzette/3.5.x-merge
a27da09 Merge branch '3.5.x' into 3.5.x-merge
94bb1ee Remove duplicate typedef. (#3975)
74e7dec Provide discardUnknonwnFields API in php (#3976)
6de51ca Merge pull request #3824 from anuraaga/dev_rag
da89eb2 Merge pull request #3955 from linux-on-ibm-z/master
6d60995 Update csharp version number (#3958)
0289dd8 Merge pull request #2519 from rubynerd-forks/ruby-fix-repeated-message-type-field
74f64b6 Fix JsonTokenizer exception message
3e944ae Add a UTF-8 decoder that uses Unsafe to directly decode a byte buffer.
3c6fd3f Merge pull request #3960 from acozzette/libprotoc-export-fix
1b1d1ea Added back in LIBPROTOC_EXPORT which was removed by mistake
34e30e5 Merge pull request #3962 from jleni/fix_dotnet
582d6ac Upgrading dotnet to 1.0.4
f2127b6 Merge pull request #3416 from xiaoshuang-lu/PROTOBUF-3404
642e1ac Adding Release_CompareAndSwap 64-bit variant
8ff2284 [PROTOBUF-3404] add --with-zlib=PATH to configure.ac script
cf65a79 Update version for 3.5.0.post1
f466709 Merge pull request #3941 from google/anandolee-patch-2
45d99a1 Add _file_desc_by_toplevel_extension back
f08e4dd Merge pull request #3919 from jart/less-warnings
b819abf Merge pull request #3918 from OEP/fix-sdist
ac5371d Remove unhelpful build warnings
9935829 Include .cc and .h files in source distribution
baed06e Small code reorder to maybe make #3893 happy.
6700f41 Travis config cleanups and move ObjC to Xcode 9.1.
2b3aa1c Add Setter/Getter type verification. (#3880)
8537f1e Fix up warnings from Xcode 9.1 (#3887)
98836a5 Update version number for php c extension (#3896)
e99e5d0 Merge pull request #3895 from pherl/3.5.x
1ec45f8 Add protobuf-all in post release
857a021 Use fully qualifed name for DescriptorPool in Any.php to avoid name (#3886)
0d46688 Update README.md: C extension works on PHP 7 (#3888)
696653d Merge pull request #3892 from sergiocampama/32bit
7daa320 Merge pull request #3878 from Yangqing/master
02129f0 Fixes 32bit tests.
cf68531 Merge pull request #3891 from thomasvl/travis_cleanups
7417755 Merge pull request #3883 from dmaclach/map_optimizations
8ae6844 codereview cleanup
6552c5a Merge pull request #3884 from dmaclach/unsafe
4ba3092 code review cleanup
af5ad24 Merge pull request #3882 from dmaclach/removeclass2
a839c67 Remove the allowed_failure for python_cpp as the bug was fixed.
2e17639 Remove the ruby tests from travis configs.
c46571b Update some comments about testing.
73e8c8a Instead of listing and then excluding osx builds, just don't list them.
949596e Simplify getter/setter method implementations
9d7f313 Reduce size of GPBDictionary by getting rid of class creation methods
37a6672 Remove unreferenced 'GPBMessageSignatureProtocol' class.
91ff83c Remove non-C# options from C#-only test protos
cba18ef Allow one to omit building libprotoc and protoc binaries
d3537c2 Merge pull request #3834 from sviterok/patch-1
0cd2ad1 Update protoc-artfacts
2720cdc Update README.md
4041600 Merge branch '3.5.x' of github.com:google/protobuf into 3.5.x
4493595 Update release date
2761122 Merge pull request #3868 from pherl/3.5.x
b9f891e Merge pull request #3875 from hchasestevens/add-hypothesis-protobuf-doc
188f180 All integer types should accept null in json. (#3869)
3c33143 Add hypothesis-protobuf library to the 3rd party doc.
8cf53f8 MMinor fix-ups to C# tests from changes in earlier commits
b5cdf0e Regenerated test code for C#
aa77eab Move C#-only test protos to csharp/protos
9a9a66e Run C# codegen when testing it
9c197b7 Support win32 long path for cross compiled build
fe2b4af Merge pull request #3867 from jtattermusch/update_changelog
07df230 update changelog
966a9ed Merge pull request #3861 from jtattermusch/backport_3858
5f96191 ParseFrom<T> for array slice is missing
4a5e1bd check already performed by MergeFrom
435f611 allow message parsing from an array slice
ce0a532 Merge pull request #3858 from jtattermusch/parsing_from_slice
5eb717c Fix arm64 name
b879abc Supports Arm64 (aarch64) protoc artifacts
30b6e54 ParseFrom<T> for array slice is missing
07542e7 check already performed by MergeFrom
0c874a6 allow message parsing from an array slice
0971efb Merge pull request #3854 from pherl/3.5.x
662e8b2 Provide util funtions to figure out correct php class names. (#3850)
181e284 Fix Atomic32/AtomicWord on some platforms.
1144768 Merge pull request #3835 from pherl/3.5.x
8a3c5cc Fix java code example
ce2d528 Changelog for 3.5.0
c258fb3 Merge pull request #3822 from mehrdada/update-benchmark-submodule
2df4726 Fix php well known type conformance tests (#3828) (#3840)
bcda919 Fix php well known type conformance tests (#3828)
239dba5 Merge pull request #3839 from thomasvl/message_equality
1f57e54 When comparing message, require them to have the same descriptor.
1908012 Update generated descritpors.
97dd175 Update version number to 3.5.0
da3bfa6 Fix a typo in WKT's test suite
cbe2505 Fix merging with message-valued oneof
bb35f04 Update google/benchmark submodule to v1.2
6dd8224 Merge pull request #3817 from xuwei-k/joda-url
05b56d0 update joda-time javadoc url
e8c9ae1 Add parser settings WithXyz methods
a985451 Add JsonParser setting to ignore unknown field values
4526d8b Merge pull request #3722 from timou/cmake-windows-clean
23adfeb Reserve unknown in Ruby (#3763)
a08b03d Add missing files
9aaa8e1 Merge pull request #3804 from pherl/merge
2fc7aea Merge pull request #3791 from signalwerk/patch-1
cdc0d95 Merge remote-tracking branch 'origin/3.4.x' into master
ee8a091 Merge pull request #3787 from sergiocampama/coverage
b1f954e Improves coverage of GPBCodedInputStream
44daa59 To be clear that we set a new variable
a23669c Sort MSVC warning suppressions
cefa9d7 Merge pull request #3758 from spinorx/3.4.x
b189389 Merge pull request #3757 from spinorx/master
09e0dbc Merge pull request #3743 from Schtolc/master
2a14214 Merge pull request #3754 from toanju/gcc-fallthrough
07b9238 Merge pull request #3770 from pherl/3.5-integrate
2ee294d Fix Java 1.6 compile
9c407a1 Merge pull request #3751 from uykusuz/master
ca6187d Merge pull request #3578 from pherl/filedeprecation
dedf904 Merge pull request #3764 from zearen/patch-1
37f984f Merge pull request #3698 from hesmar/hesmar/fixProtocIncludeDirs
3d6cc0e Merge pull request #3641 from drivehappy/3.4.x_clang_cleanup_3
2e2614e Merge pull request #3706 from johanbrandhorst/patch-1
188755c Fix JS conformance tests
1c682e0 Fix bazel build
ecf2957 Update descriptor protos
30bfe36 Merge pull request #3736 from jleni/fix_rbpi
6b5912b Merge branch 'master' of github.com:google/protobuf
1a7a7fc Merge from google internal
dc9190f Merge pull request #3769 from pherl/io_win32
cc58be6 Fix unsiged underflow
7dbee32 Remove C++11 only usages in io_win32 tests.
c4f59dc Merge pull request #3760 from jmillikin-stripe/descriptor-memset-ub
aff1097 Fix undefined memory management found by Clang's sanitizers.
3130ce0 Fix iOS cc_library build for protobuf.
16792c6 Fix iOS cc_library build for protobuf.
37e112f fix implicit fallthrough in gcc 7
be13314 fixes issue #3750
f850188 Merge pull request #3744 from fmarier/json-escaping-namespace
5992e24 Move namespace closing brace inside the header guard block
a632f0d Merge pull request #3739 from pherl/merge3.4
1e58006 test for field reassignment
38fd94e CodedInputStream::SetTotalBytesLimit description fix
dd980cc Fix distcheck
de15e73 Merge remote-tracking branch 'origin/3.4.x' into master
08334f0 Converting to immutable hashable types
c4083bb Merge pull request #3735 from sgreenstein/patch-1
68ee916 Don't pass -lpthread and -lm on Windows
6032746 Reserve unknown fields in php (#3659)
d2a5f8b Update third_party.md
2a72840 Suppress VS2017 compiler/linker warnings
77f64bb Add well known types to php runtime. (#3697)
cd5f49d Fix ruby segment fault (#3708)
d6c32a8 Merge pull request #3714 from thomasvl/objc_increase_test_coverage
a274c67 Build out more complete code coverage in the tests.
9477123 Let Xcode 9 update project/scheme settings.
4207066 Merge pull request #3710 from thomasvl/xcode9
c4dce01 Merge pull request #3709 from thomasvl/unknown_field_merge_issue
b586e64 Add Xcode 9 support to the helper script.
3f2dcae ObjC: Fix merging of length delimited unknown fields.
210be26 Use constexpr more with VC++ 2017 (#3707)
fc7a6a2 Add GopherJS protobuf and gRPC links
bd798df Merge pull request #3690 from pherl/3.4.x
a38f876 Merge pull request #3691 from pherl/stringback
f7e2099 protobuf_generate: create include path only for proto files
d2738c0 Add spaces
5a501c6 Fix C++11 string accessors
6d0cf1b Remove ranged based for in io_win32.cc
fc5aa5d Merge pull request #3676 from hesmar/hesmar/fixProtobufGeneratePython
0e069e5 generate python code when calling PROTOBUF_GENERATE_PYTHON
ae55fd2 Enforce all error report for php tests. (#3670)
c204402 Merge pull request #3675 from hesmar/hesmar/cmakeAddDllExport
9829b8f protobuf_generate: add EXPORT_MACRO option
c627530 Merge pull request #3674 from pherl/shutdown
4fc7529 Merge pull request #3627 from zanker/zanker/add-submsg-hash-init
b091bfb Test Shutdown can be called multiple times.
633ef8b Update message.c
2b0ee3f Add $ before url_prefix_len to make it a variable. (#3668)
eade82c Merge pull request #3639 from zanker/zanker/fix-embedded-to_h
8eae3fe Update message.c
8771483 Allow initializing a chain of protos using only a hash
83264bd Fixed to_h with repeated messages to return hashes in Ruby
cf1b29d Merge pull request #2377 from mcos/chore/conformance-null-tests
fa5a69e Merge pull request #3624 from acozzette/down-integrate
655cc83 Merge pull request #3651 from pherl/3.4.x
2eb1bac Bumping minor version for ruby gems
5dd818c Merge pull request #3612 from TeBoring/php-bug
b04e5cb Merge pull request #3642 from pherl/3.4.x
dba647a Bump version for minor release
e3be1fe Clang warning cleanup for unused parameter.
13fd045 Integrated internal changes from Google
d1bc27c Merge pull request #3626 from xfxyjwf/fixgo
8136ccb Fix go example test.
c0d88ae Merge pull request #3635 from drivehappy/clang_cleanup
7f3ded6 Clang warning cleanup for unused parameter.
471b45e Merge pull request #3158 from yeswalrus/fix-policy-warning
3d78561 Merge pull request #3634 from TeBoring/ruby-bug
a459b22 Storing the frame on the map means we don't need the array
c1dd8e8 Move parse frame array to the Map object
8741da3 Revert "Fix js conformance tests. (#3604)" (#3633)
a425dd9 Rename ClassNamePrefix to ConstantNamePrefix
2bd55a9 Fix js conformance tests. (#3604)
f46a01d Exclude valid constant name from reserved name.
06aa8dc Merge pull request #3621 from jtattermusch/upport_3596
ed0a07e Merge pull request #3618 from hesmar/fix_protobuf_generate
5de0565 Google.Protobuf should target net45
444aecd fix protobuf_generate function
b1befb0 Merge pull request #3613 from xfxyjwf/bazel_examples
6945203 Exclude addressbook.proto from C# boostrap test.
ddb9ef9 Change array to map for reserved names in c extension
49b31dc Update C# generated file for addressbook.proto
49b88af Update examples file list.
89069de Change array to associate array.
174c82d Add well-known timestamps to JSON for PHP (#3564)
74bf45f Add bazel support for examples.
e5d000c Add prefix to php reserved keywords.
2ad5c0a Merge pull request #2576 from cristicbz/py-strutil
6a4ffb2 Merge pull request #3596 from jtattermusch/csharp_target_net45
054054c Merge pull request #3590 from NanXiao/patch-1
7f8b91f Add native php support for Duration. (#3583)
35b852f Merge pull request #3594 from buchgr/well-known-protos
699c0eb bazel: Add proto_library rules for well known types. Fixes #2763
50a6475 Google.Protobuf should target net45
f4ff17b Update autogen.sh
6699f2c Merge pull request #3560 from tenderlove/thread-safe-map
f9b8169 Add TODO
dd69d5c Fix dist check
baae7ea Add @Deprecated annotation support for proto file.
b70e0fd Add php support for Timestamp. (#3575)
2807436 change the field number of php_generic_service to fix the conflict with (#3576)
f55c6ec Storing the frame on the map means we don't need the array
d6152dd Move parse frame array to the Map object
c7457ef Add any support in php runtime. (#3486)
21b2372 Merge pull request #3565 from pherl/fixdist
d8c6193 Add mising cmake files in dist
98a3734 Merge pull request #3503 from gburgessiv/master
859d94a Merge pull request #3544 from anandolee/master
92ea0d2 Merge pull request #3556 from matt-kwong/kokoro_mac_v3
78432ea Remove pre-installed softwares
07de70e Merge pull request #3555 from pherl/fixdist
364060b Merge pull request #3547 from matt-kwong/kokoro_mac_build
55fdbe5 Make distcheck aware of test proto files.
e46caba Remove pre-installed softwares
c44c3af Merge pull request #3548 from google/3.4.x
30681c7 Merge pull request #3546 from pherl/deathtest
610e433 Drop python2.6
028d6f1 Add Python 3.5 3.6
6609e52 Disable death tests on windows
e416f5d Merge pull request #3537 from TeBoring/php-bug
7273b3c Merge pull request #3539 from drivehappy/3.4.x_clang_cleanup_1
09fd125 Merge pull request #3540 from drivehappy/3.4.x_clang_cleanup_2
7a43137 Merge pull request #3543 from tony612/patch-1
6cecd20 Work around a bug in clang's static analyzer
2fb7479 Add Elixir protobuf and gRPC to 3rd party doc
c27b56c Merge pull request #3494 from drivehappy/clang_warning_macro
36ac06f Merge pull request #3535 from drivehappy/clang_warn_cleanup
0b7e978 Merge pull request #3535 from drivehappy/clang_warn_cleanup
92d768c Merge pull request #3536 from pherl/io32_11
77a453a Fix compile errors
dd51909 Use message name as defined in php runtime.
4aadcd3 Remove C++11 features in io_win32.cc
ba4e547 Merge pull request #3529 from pherl/merge3.4.x
472f700 remove the parens from the cmp() lambda definition (#3526)
1183f48 Fixing unused parameter warnings under Clang.
139775c Merge remote-tracking branch 'origin/3.4.x' into mergemaster
26ac3e8 Merge pull request #3528 from pherl/rubyfix
fdb5cd5 Merge pull request #3504 from pherl/3.4.x
d76e4c7 Bump gemspec again
1825d6d Merge pull request #3317 from ejona86/protoc-artifacts-jdk8
c2aa26e Revert "Drop Python 3.3 from testing & add Python 3.5, 3.6 (#3512)" (#3524)
703f414 Drop Python 3.3 from testing & add Python 3.5, 3.6 (#3512)
a04eb8c Define cmp() for Python 3 (#3517)
1aa2c34 Merge pull request #3516 from cclauss/patch-3
dded80f define long() for Python 3
6f4c9b0 print() function for Python 3
a1acf25 print() function and lose the semicolons (;)
067543c from __future__ import print_function
7daedbd print() function & define raw_input() for Python 3
45483fd file() was removed in Python 3, use open() instead
5ab8ae7 Merge pull request #3511 from cclauss/patch-3
fa46d11 Merge pull request #3514 from pherl/rubyfix
29c24ab Merge pull request #3502 from pherl/pypi
1926636 Bump gem version for the next upload
958412e Old style exception --> new style exception
d1484cd Update CHANGES.txt
55d938c Update CHANGES.txt
98c6d04 Prefer system distributed binaries/libraries.
e243082 Update php version number to 3.4.0
82dd4b3 Update php c extension version number.
5d5df84 clean up
19a7e20 Update testpypi addresses.
80a37e0 Merge pull request #3495 from pherl/c++11
5e39ecc Merge pull request #3494 from drivehappy/clang_warning_macro
3d2f72b Merge pull request #3496 from pherl/mingw64
6654c8d Update readme
f619621 Merge pull request #3493 from pherl/cmath
d909834 static link for 32 bit build as well.
f7b3dd4 Update comments that cross compile is feasible now
fa086c8 First try static linking pthread
4a4c67b Add std::forward and std::move autoconf check
a23e198 Fixing warning under Clang 6.x (-Wexpansion-to-defined) where the macro expansion producing 'defined' was warning on undefined behavior.
3908b4e Fix cmath/math.h include with non C++11 libstdc++
1cc4ecd Merge pull request #3488 from pherl/changelog
3ae8c4c Update changelog for 3.4.x
eaeca0d Merge pull request #3485 from pherl/mingw
1bd2d1f Merge pull request #3484 from pherl/qualifier
651429b Fix comments
31b3bd9 Make compilers without ref-qualifier support happy.
b4c0cfe Add malloc cast
fd31899 implement remove strdup usage and implement our own
34ebca0 Adding missing imports for strdup
40d1855 Fix mkdir
564f02c Make win32_io only for MSVC
7afa796 Fix the declaration order in ming32
db125b8 Fixing io_win32 for MinGW32
e0d24cc Detect invalid tags with a field number of 0 in C#
d2f3adb Merge pull request #3481 from pherl/nowarning
ccb6b62 Merge pull request #3480 from bklarson/master
1b42347 Clean up typedefs for Atomic32/Atomic64
e8fc066 Make no warning test stricter.
9adb4e8 Merge pull request #3478 from pherl/warning
97d50e3 Make code free of missing-field-initializers warnings
35db267 Merge pull request #3473 from AlanBurlison/master
80e984e Merge pull request #3467 from thomasvl/bump_xcode_version
a68a800 PROTBUF-3394 Potential SIGBUS with UnsafeUtil.getLong
3afcded Merge pull request #3461 from TeBoring/3.4.x
176713d Merge pull request #3468 from vladmos/3.4.x
fae3816 Merge pull request #3454 from anandolee/master
06a825c Make .bzl files compatible with future versions of Bazel
d08c291 Merge pull request #3465 from vladmos/list_plus_equals
fe68821 Move travis to the Xcode 8.3 (8.3.3) image.
ba81c59 Fix up Xcode 8.3.x support.
4fc9304 Make .bzl files compatible with future versions of Bazel
8f4b8e4 Merge branch 'master' into 3.4.x
f14703c Update commit id in Dockerfile to reflect change in #3391 (#3459)
49b44bf Fix the bug in php c extension that setting one field can change anotherĀ field's value. (#3455)
21b0e55 Update PHP descriptors (#3391)
f5817b3 PY26 tests compatibility 1, Some tests in reflection_test PY26 raise TypeError but other versions raise ValueError for convert negative long to unsigned 2, Change compare exception type to compare exception str for testDuplicateExtensionNumber. Original code raise 'Double registration of Extensions' is not an instance of (<type 'exceptions.AssertionError'>, <type 'exceptions.ValueError'>) for PY26 cpp implementation
1ab5adb Merge pull request #3456 from giorgioazzinnaro/patch-1
a3e1752 Update third party addons with ProfaneDB
9150cd8 Skip setUpClass which is newly added in python2.7 for python2.6
d58df3b Add python 2.6 test back for cpp implementation. Json format issue was fixed in #869
c2f69d6 Merge pull request #3450 from pherl/invalidoffset
e243fd8 Merge pull request #3451 from pherl/fixtypo
39a91d3 Fix typo.
4cbbf33 Fix invalid offsetof warning.
25672c1 Add getClass for php Descriptor in c extension (#3443)
7781784 Add destructors for default instances to the shutdown code. Verified test succeed under draconian heap checker
53ae6de Merge pull request #3442 from pherl/csharpversion
6c64f11 Bump csharp version
e0288e7 Merge pull request #3438 from pherl/changelog
9df89cc Fixing HHVM Compatibility (#3437)
c15a326 Expose descriptor API in php c extension (#3422)
8a5208f Update change log
502624f Merge pull request #3419 from pherl/3.4.x
d77c8c5 remove the duplication
bcf1733 Adding the missing header
ebeb472 Export functions in io_win32.h in win DLL build
be73938 Change divideInt64ToInt32 to static (#3436)
d32f5b4 Removes unnecessary pass-by-references in PHP internal classes (#3433)
0724314 Merge pull request #3429 from king6cong/master
d6bd959 Merge pull request #3406 from ax3l/bg-3.4-cmake-pkgconfig
547d76e Add classpath for java example Makefile
9b505a9 Merge pull request #3421 from thomasvl/update_comment
9a4692d Update the comment on the message_type to cover what it should be.
5eb95ef Merge pull request #3420 from thomasvl/objc_proto2_conformance
3caf9fd Review feedback.
c2831a3 Add the proto2 message conformance support for ObjC.
9fd5e59 Generate the proto2 test file and link it in for ObjC.
21800ff Add a objc_class_prefix to test_messages_proto3.proto.
19b8c8b Update conformance tests again.
8d5f2c5 Merge pull request #3410 from adam-26/1745
12c186f Fix makefile.am
de6debc Fix conformance tests
e177739 Fix build files
9b8f658 Remove dependency on guava 20
d974cc2 Update conformance tests
f39d4de Merge remote-tracking branch 'origin/master' into merge
759245a Merge from master
bb86644 need for php math functions. used in mergeFromJsonString (#3409)
e9f4e8e Merge pull request #3407 from bklarson/master
451d061 Fix cycle dependency for repeated field not collected by gc (#3399)
4bff88e Merge pull request #3413 from pherl/3.4.x
ce44167 Merge remote-tracking branch 'origin/3.4.x' into vb
4ae94d6 Merge pull request #3414 from pherl/fixzip
eb6b332 Merge pull request #3412 from anandolee/3.4.x
02250a7 Omit the zip test if tools are not available
9c012ed Add __bool__ as well as __nonzero__ for python3
11b4d5e Update required version on pre-generated files
8b24feb Update pre generated files
7bb39be Update version number for 3.4.0
a484794 Use keys() instead of iterkeys() to be python3 compatbile.
72cc5a6 Merge pull request #3393 from pherl/3.4.x
b6da226 Put AddDescriptorsImpl() in anonymous namespace
a713b73 Merge pull request #3281 from BSBandme/ConformanceTestYilunChong
2b6db00 Fix quotation marks
a3a65b3 Fix issue #1745 - javascript allow dot in filename
f15185d Merge pull request #2969 from laszlocsomor/master
0d9a34c Add -Werror=missing-declarations to test builds
ebe659d Travis: Exclude CMake .pc files
2f3cf52 CMake: Install .pc Files
eef2edc Merge pull request #3403 from ax3l/topic-cmake-pkgconfig
74dcf44 Travis: Exclude CMake .pc files
668712c CMake: Install .pc Files
e8a32d0 Merge pull request #3401 from aschrijver/patch-2
d640cdd Updated outdated hyperlink
062df3d Merge pull request #3179 from bjwatson/fix-duration-typo
040f56e Merge pull request #3397 from acozzette/initialization
bba4c4a Merge pull request #3262 from snnn/master
417aae6 Fixed dynamic initialization for C++ lite
dd091aa Fix code to use values() instead
aa61bb0 compiles removal of newline (#3333) (#3370)
1876a27 Update filelist again
66c1dac Add lite and python extra_dist files
bf658c2 Add java and JS dist files.
988376c remove broken imports in JS
b07cdb6 Use itmes() instead of itervalues() to be python3 compatbile.
e45214e Fix distcheck
8084e03 remove profile
11b6661 update build file list
7986ca7 Update conformance tests
50aa4fe Merge pull request #3375 from TeBoring/3.3.x
3af881c Merge master into 3.4.x
8697530 Update csharp and php descriptor
09354db Merge from Google internal for 3.4 release
942a29c Merge pull request #3390 from danielgtaylor-isp/patch-1
6ec0b7e Merge 3.3.x into master
3370299 Merge pull request #3385 from anandolee/master
4b5b1e6 Add note about includes to README
9e745f7 Support PHP generic services (#3269)
b764e67 Set PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION for pure python comformance test
3354558 Merge pull request #3348 from matthauck/fix-gcc41-again
dd6e420 Merge pull request #3357 from bklarson/master
eb8e3d3 Merge pull request #3134 from lundefugl/javabug1
aaa2550 Merge pull request #3372 from dylanetaft/master
324b20a remove pass by reference for php setters (#3344)
29ff49f Fix Implicit Return Types (#3363)
36fcc2a Expand documentation in Readme.md
c78dbd7 Initial value in generated code cannot be used by c extension. (#3367)
ec3f5dc removes an accidental newline in printing for the php generator (#3333)
3a0382e Add map iterator for c extension (#3350)
d3bbf1c Add space between arrow and casted type (#3353)
6aa4b20 Merge pull request #3327 from htuch/fix-3322
71f2f0d Fix repository URL in C# project file
81142e1 Fix build when using -Werror=undef
727c0dc C#: Implement IReadOnlyDictionary<K,V> in MapField<K,V>
2130fea Fix map_field_inl.h for gcc 4.1
e05e777 Windows: support long paths
9ab7c73 Fix missing std::tr1::hash on GCC 4.1 (#2907)
126082c Add std:: namespace prefix to set and map (#3332)
b9c4daa Uncomment php tests (#3301)
f6ff32c Use consistent hash across NDEBUG/!NDEBUG builds.
bd5ab15 Merge pull request #2482 from andreaseger/fix_ruby_timestamp_accuracy
a9e7a15 protoc-artifacts: Bump JDK to 8u131
bceb830 add comments in makefile.am
6bd51a5 add Grpc Protobuf validation (#3311)
32c8ed3 change csharp failure list
30b4194 Merge branch 'ConformanceTestYilunChong' of github.com:BSBandme/protobuf into ConformanceTestYilunChong
7339c25 delete backup files
cbf7dfb fix php failing list and csharp generated proto
e264b20 Merge pull request #3315 from thomasvl/mutate_unknowns
b30dee3 Expose the initializer for unknown fields.
cdd524a Ensure leaveOpen is true when writing to a buffer
62d7fe5 Make Any easier to work with in C#
e82ba0b Merge branch 'master' into ConformanceTestYilunChong
726ba33 changed php's failing list
5085102 remove backup files
3adb054 add some test proto2 supported, add js proto2 supported, fixed some error
ecca6ea Add json encode/decode for php. (#3226)
a7d5be6 change php objc nodejs csharp ruby
fcb9268 change java to uniform message, revert TestValidDataForType's parameters
020a24d change cpp and python to uniform message
5a52b35 Merge pull request #3287 from sergiocampama/initialized
e55782f Add initialized as a reserved keyword as that's the actual property name
467c1cc fix csharp conformance test
db379e6 fix csharp conformance test
176bac6 Add scripts to build python wheel for linux. (#2693)
ff773c1 fix csharp
cd1dc3f add csharp support
3645021 add message set test case
06c9057 add objec support
5e7e2d3 revert ruby proto built files
cf7b6a4 delete backup files
6c59c25 delete binary
91da852 update .gitignore
0255431 revert .gitignore
696cf77 add java supported
0fa4e58 change ignore
18a0c2c add proto2 supported for cpp,python,nodejs,ruby,php
12acbc2 adds PHPDoc @return and @param for getters and setters respectively (#3131)
2ad74e1 add support for proto2
097bfb5 Merge pull request #3084 from lukaszx0/patch-1
dd7265e Merge pull request #3264 from TeBoring/php-bug
e3c807d Fix more implicit type conversions in public headers and generated code.
1a7e49d Merge pull request #2968 from ngg/cpp-proper-fwd
9c0b35c Enusre public header and generated code have no implicit converion.
4e67590 fix readme.md
58a3c74 add test_proto2_message.proto and change conformnace/makefile.am
f752d81 Merge pull request #3266 from mbrickn/patch-1
d07efba Updated links to use https
eca0f4e Merge pull request #3261 from thomasvl/super_oddcase
db45687 If we fail to get a descriptor just super the method resolving.
4987dda Fix a bazel build error on Windows
5555d3b Fix typos in comment
5532abc Merge pull request #3258 from TeBoring/3.3.x
5520b43 Update C++ generated code.
e7bcfc4 Update version number to 3.3.2
8ecae34 Merge pull request #3255 from TeBoring/3.3.x-3
3b1a875 Remove inclusion of ext/json/php_json.h. (#3241)
c344fe8 Oneof field should be serialized even it's equal to default. (#3153)
dba8928 Add ARRAY for reserved name (#3150)
703cd8e Switch to addEnumType to fix fatal error (#3225)
1325588 Updated upb to fix JSON conformance issues. (#3206)
c2fdef0 Merge pull request #3243 from yjjnls/master
73b7cc0 Merge pull request #3244 from thomasvl/complete_docs
5fd71ce ObjC: Document the exceptions on some of the writing apis.
72e293a Merge pull request #3240 from thomasvl/float_fun
8f367c0 replenish missed header files in install step
5729cf7 Remove inclusion of ext/json/php_json.h. (#3241)
dd19b87 Raise the number of digits used for floats.
710543d Merge pull request #3237 from calder/patch-1
491b320 Merge pull request #3236 from buchgr/bazel-links
888e287 Merge pull request #3235 from buchgr/java-target
4b36d40 Qualify string in java_options.h
36e63da bazel: Make compiled jars java 6 binary compatible.
d0e6f3b bazel: add bazel symlinks to .gitignore
91bf623 Fix php jenkins test (#3233)
8d97b3d Fix incorrect function call (#3232)
b9b34e9 Follows proper autoloading standards (#3123)
09d2994 Merge pull request #3228 from thomasvl/add_tvos_to_podspec
6ecf38f Add tvOS to the podspec.
c722c3d Merge pull request #3216 from traversaro/patch-1
9094bf0 Export symbols used in inline functions
9ba7d1c C++: Do not forward-declare dependencies in generated .h files
96095f3 Merge pull request #3176 from acozzette/fix-3114
c202b06 Merge pull request #3196 from matt-kwong/kokoro
0871e6a Add continuous testing config files for Kokoro
d4d41af Merge pull request #3191 from matt-kwong/kokoro
6156af1 Add MacOS and Linux tests to Kokoro
d555775 Merge pull request #3189 from thomasvl/objc_proto3_unknown_fields
2aeb4ab Merge pull request #3160 from meteorcloudy/winbuild
ddbe360 Merge pull request #3159 from yeswalrus/new-generate
1d0988b ObjC: Preserve unknown fields in proto3 syntax files.
516a81a Merge pull request #3190 from thomasvl/objc_IllegalZeroFieldNum
ecc0f54 Properly error on a tag with field number zero.
656dedb Merge pull request #3157 from yeswalrus/fix-version-check
7ccb251 Remove unused output_file variable from js_embed
6f32580 Add new file option php_namespace. (#3162)
df3f8cf fix check_and_save_build_option not correctly exporting build options
0336770 add protobuf_generate function, allows use of target_sources where available
e9c15d6 Ensure that for Java, imports of .proto files with empty packages works
fbaad36 Merge pull request #3169 from dmaclach/master
63a9728 Merge pull request #3170 from thomasvl/int64_map_issue
46f36d7 Fix some cases of reading of 64bit map values.
ea43e0c Optimize GPBDictionary.m codegen to reduce size of overall library by 46K per architecture.
0b059a3 Refactor cc options in BUILD file for Windows
d8c5865 Fix policy warning CMP0054
a183a0d Fix the check_and_save_build_option macro never evaluating to true
faa5398 fix check_and_save_build_option not correctly exporting build options
ae85cb8 Fix find module not working when no version number was given
d6470ab not to use std::random_device for map.Seed(). (#3133)
e222997 Merge pull request #3149 from KarrokDC/master
1e86ef4 Oneof field should be serialized even it's equal to default. (#3153)
282fb9e Add ARRAY for reserved name (#3150)
4d5daf4 Adds fluent setters for PHP (#3130)
4eb02fe Add headers as part of cmake project tested only on windows with visual studio 2015 as generator
4674cc7 Merge pull request #3113 from phst/master
95749d5 update csharp README and fix .NET 3.5 build error
aea4374 Issue 3112: Object class with fully qualified name
0b07d7e Add IncludeSource in csproj as per review comments
f26e8c2 Convert C# projects to MSBuild (csproj) format
40da1ed Removing undefined behavior and compiler warnings (#1315)
ba987a7 Merge pull request #3126 from mbrukman/fix-readme-formatting
c5125f3 Merge pull request #3117 from KarrokDC/master
d2c1865 Merge pull request #3103 from sergiocampama/perf
2465ae7 Adds serial and parallel parsing tests to check if parallel parsing is faster than serial parsing, which it should
6775570 Fix Markdown formatting in README.
979107e Improve fix for https://github.com/google/protobuf/issues/295
3b22761 show help if protoc is called without any arguments, pre-empts -h and --help to show a useful message instead of just 'Missing input file.'
bf04c83 Merge pull request #3085 from scpeters/issue_3059
8546620 Merge pull request #3104 from thomasvl/ext_registry_copy
49e4ba6 Fix ExtensionRegistry copying and add tests.
b28617b Merge pull request #2815 from devwout/ruby_json_emit_defaults
78cb804 change test for nanosecond accurate timestamps
ad203bc fix floating point accuracy problem in Timestamp#to_f
49a56da Update jenkins Java deps.
129a6e2 Revert guava depedency to version 19.
969e0be regenerate plugin and profile message code
26f0011 Use bool deterministic to suppress warning
474cca5 Add LICENSE in package.xml (#3083)
13f532e Merge pull request #3074 from xfxyjwf/3.3.x
82e50ba Workaround the docker bug when compiling artifacts
de6ae7d Fix upb load descriptor when no messages defined in prorto. (#3080)
2231931 Fix c extension for php7.1. (#3077)
757cc9f Update C++ generated code.
58538ea Update version number to 3.3.1
c2154e1 Merge pull request #3073 from xfxyjwf/3.3.x
d22493b Merge pull request #3064 from randomguy3/offset-type
9b82fce Workaround gcc < 4.5.0 bug
455b61c Merge pull request #3062 from Oppen/master
e062f70 Fix compilation
e82d81a Fix offset type to match the tables it is used in
25abd7b Add compatibility test for php. (#3041)
3c369dc Merge pull request #3057 from xfxyjwf/3.3.x
cd0efc0 Workaround gcc < 4.5.0 bug
99cf2ef Merge pull request #3056 from acozzette/cherry-pick-pr-2873
7378ec2 Add missing LIBRPOTOC_EXPORT.
3a5a072 Skip C# test in C++ only distribution.
8859c07 Add missing files to build files.
4833960 Merge pull request #3043 from acozzette/javascript
22c8772 Fix #1562 by using goog.crypt.byteArrayToString instead of String.fromCharCode.apply
dd0a233 Merge pull request #3055 from chrisn-arm/3.3.x
c3093d3 Fix issue 3046: compilation on alpine 3.5
f00e06c Removed mention of Buffer in byteSourceToUint8Array
a64497c Merge pull request #2873 from myitcv/fix_1562
bcb3506 Fix #1562 by using goog.crypt.byteArrayToString instead of String.fromCharCode.apply
2f4489a Merge pull request #3024 from acozzette/merge-3.3-to-master
286f059 added "objectivec" build target (#3033)
9053033 Merge remote-tracking branch 'remotes/google/3.3.x' into merge-3.3-to-master
067b1ee Merge pull request #3023 from acozzette/min
07c284f Fully qualify min as std::min in wire_format_lite.cc
a6189ac Add prefix to enum value with reserved name. (#3020)
cbd08cb Merge pull request #3018 from acozzette/using-namespace-std
54d1701 Merge pull request #3015 from buchgr/unused-consts
7c76ac1 Remove "using namespace std" from stubs/common.h
3c0855e Add a test case for nested enum, which was missed previously. (#3010)
b1c75bc Remove unused constants.
4920e27 Merge pull request #3008 from postmasters/patch-1
fba2acd Add nested enum descriptor in php rumtime. (#3009)
e64b618 Update php version number to 3.3.0 (#3001)
4777574 Add a link to dart-lang/protobuf
6fff091 Throw exception when parsing invalid data. (#3000)
f418b9e Merge pull request #2996 from xfxyjwf/3.3.x
4523c9c Allow proto files to import descriptor.proto (#2995)
478119f Fix python3 issue.
14afc3f Merge pull request #2992 from xiaogaozi/patch-1
f85eecb Add gogoprotobuf to third-party add-ons list
4c57e84 Prepend "PB" to generated classes whose name are reserved words. (#2990)
b97cd57 Add test for nested enum for php (#2989)
7be0882 Enum defined without package have incorrect class name. (#2988)
190b527 Make PHP c extension work with PHP7 (#2951)
357afc3 Merge pull request #2508 from yliu120/pass_default_env_to_protoc
0a93f67 Merge pull request #2987 from konsumer/patch-1
594f810 Merge pull request #2982 from mda000/issue2972
3055a02 Add node-protoc-plugin to "Other Utilities"
a3873ca Merge pull request #2985 from thomasvl/class_check_tweaks
f5a01d1 Tighten up class usage/checks.
2240a78 Simplify the Element dtor invocation when freeing elements in InternalDeallocate to avoid confusing the compiler when there's a class named Element already defined in the global namespace.
8aa927f Merge pull request #2950 from anuraaga/dev_rag
4323482 Merge pull request #2967 from xfxyjwf/3.3.x
5777259 Cherry-pick cl/152450543
cad0258 Cherry-pick cl/151775298
fc3ea97 Merge pull request #2955 from xfxyjwf/3.3.x
899460c cherrypick descriptor_pool.FindFileContainingSymbol by extensions (#2962)
bfeeb98 Add include for INT_MAX
e91caa1 Merge pull request #2949 from xfxyjwf/3.3.x
bf483df Allow unknown values for Map put*Value methods just like every other enum mutation method.
ee9c7f1 Cleanup reflection objects for map entry.
efec757 Merge pull request #2937 from anuraaga/dev_rag2
18c13c9 Merge pull request #2942 from xfxyjwf/3.3.x
21b0b3c Update generated code.
80f0c0a Update version number and changelog for 3.3.0
69bfde2 Merge pull request #2922 from anandolee/master
09328db Fix test for unexpected type url when parsing Any. Currently, the test fails since TestAllTypes doesn't have field '@type', which is the same test as testUnknownFields.
139fd0a Merge pull request #2933 from mharrend/patch-1
37c7b76 Merge pull request #2930 from anuraaga/dev_rag
662f978 Fix duplicate fields test. The repeated version is passing because null values in a repeated field are rejected and not testing what it wanted to. Also adds a oneof version that verifies the case of oneof fields of different names (currently only same name check seems to be tested).
cc3fa2e Merge pull request #2676 from acozzette/js-compatibility-tests
10ea251 Added compatibility tests for version 3.0.0
7e5f980 Split test protos into two groups
dd04ffb Adding default shell env
58373fa Fix error message for int64 parse error.
11c902e Add IntelliJ project to gitignore for java project.
bd74319 Update Java conformance failure list.
32ad5a3 Use "git reset --hard" to actually reset the code.
b7c813f Update jenkins Java dependencies.
c2b3b3e Update Java version number and dependency.
624d44f Update objective-c conformance failure list.
d582778 Fix C++ distcheck.
fe97d79 Fix MSVC DLL build.
fab8812 Update python conformance failure list.
c52e54f Update jenkins Java maven dependencies.
057a285 Update C# conformance failure list.
e47c068 Update python conformance failure list.
84f6954 Fix Java build.
c348d46 Use PyUnicode_AsEncodedString() instead of PyUnicode_AsEncodedObject()
acde165 Update BUILD file for C# tests.
32d7830 Fix C++ build for down-integration.
d36c0c5 Down-integrate from google3.
4a0dd03 Removes ignored const from return type (#2915)
258406b Merge pull request #2919 from thomasvl/drop_dispatch
130c166 Remove the use of dispatch_once that is heap backed.
ba3fa41 Merge pull request #2918 from thomasvl/xcode_8_3
558ba98 Add support for Xcode 8.3 to the build helper.
04c77c4 Merge pull request #2913 from thomasvl/conformance_ignores
d43eaf2 Fix gcc warning when using map (#2213)
5859932 Merge pull request #2914 from acozzette/nacl
f316375 Added a workaround to allow building for NaCl
8adf57e Add some new ignores for things generated in conformance.
b3f3e12 Merge pull request #2912 from thomasvl/objc_recursion_limit
ddb4388 Raise the recursion limit to 100 to match other languages.
d9e0119 Merge pull request #2858 from haberman/gopackage
c565e25 Merge pull request #1662 from haberman/jsconformance
7610f10 Merge pull request #2884 from anandolee/master
689e4bf Add FormatEnumAsInt support for Json Format. And scale JsonFormatter.Settings to multiple options.
373809e Merge pull request #2897 from cgrushko/patch-5
6f21e29 Compile the Java proto runtime with Java 6
1387a67 Update commit number in Docker to update composer dependency (#2869)
ffa932b Merge pull request #2861 from byronyi/#710
312e2db Update BUILD
db3ef48 Merge pull request #2860 from prehistoric-penguin/master
20181f6 Merge pull request #2854 from hesmar/attributesFix
4d273f2 Merge pull request #2870 from acozzette/memcpy-memmove
15b60bc Merge pull request #2867 from mojoBrendan/master
ea5ef14 Ruby: only link against specific version of memcpy if we're using glibc
c12cc34 Merge pull request #2837 from anandolee/master
6b27c1f Add file option php_class_prefix (#2849)
c0871aa Merge pull request #2848 from xfxyjwf/freebsd
e8e6aa2 Update delimited_message_util_test.cc
89eb4e5 Add option to preserve original proto field names
aec0711 Ruby tests compare parsed JSON instead of raw JSON
1eee320 Add use_snake_case_for_field_names option to JsonPrintOptions
c415a14 fix several issues
44dc555 Merge pull request #2866 from xfxyjwf/nano
ddc0096 Add a notice for nano.
1b0db1c Removed obsolete comments and added docs.
0df2028 Properly regenerated descriptor.proto.
89c3c45 Merge pull request #2859 from haberman/junit-dep-scope
2957703 Merge pull request #2847 from haberman/ruby-toh
0fad0e1 Merge pull request #2794 from acozzette/jspb-extensions
acaa940 add delimited_message_util.cc to libprotobuf.cmake
7008a88 add LIBPROTOBUF_EXPORT to make msvc happy
cb3e84b migrate delimited messages functions to util package
33cc25f Remove duplicated copyright statement
496cd48 Changed scope of Java deps to "test".
e62e30c Changed go_package for plugin.proto.
4842363 Merge pull request #2023 from odeke-em/fix-print-help-to-stdout
e77a09e Incremented Ruby version number to 3.2.0.1
8c40b51 Ruby: update Gemspec.
97cbc42 Fix libprotoc.cmake to generate well_known_types_embed.cc
f23869c Bug fix: When encoding, negative int32 values should be padded to int64 (#2660)
014a550 Ruby: build packages for Ruby 2.4.
c57c77b Merge pull request #2829 from afrantzis/hide-unnecessary-library-symbols
324a299 Made formatting more consistent.
ed0ef54 Merge pull request #2846 from acozzette/bytestream-comment
d18df81 Merge pull request #2855 from thomasvl/copy_note
5e4f14f Document deep copy in the header
b4b855c fix attributes warning
416f909 Fix freebsd build.
9c6b8cb Ruby: fixed Message#to_h for map fields.
95b4427 Build system fixes for JS conformance tests.
43f2db7 Merge pull request #2843 from haberman/check
746ca59 Updated an outdated comment in bytestream.h
874e382 Replace CHECK() with GOOGLE_CHECK().
8df69f0 Conformance test for JS now work, though 15 tests fail.
f0a5c10 Merge pull request #2836 from xfxyjwf/i894
ddfc86b Merge pull request #2835 from pherl/javaep
13d165d Hide unnecessary exported library symbols
d59592a DefaultValueObjectWriter should populate oneof message field
c94555f Double-quote file paths in extract_includes.bat.in
f4f31e7 Suppress the last unchecked warning.
a69bc9d Merge pull request #2822 from anandolee/master
f54fb9d Merge pull request #2832 from pherl/javaep
e11cd3e Merge pull request #2818 from xfxyjwf/i1470
6044b24 Make //:protobuf_python have correct __init__.py.
92064a4 Merge pull request #2824 from xfxyjwf/i1415
cd6eb91 Merge pull request #2826 from xfxyjwf/i1374
81f4fe5 Merge pull request #2827 from xfxyjwf/i1251
81fe52f Fix java code according to error prone.
616e68e Repeated/Map field setter should accept a regular PHP array (#2817)
ae220cd Add auto detect for generated code of WKT protos, addressbook.proto and conformance.proto
03c8c8b Update comments for setSizeLimit.
a1bb147 Merge pull request #2825 from pherl/javawarning
1ece7c0 Add missing thread dependency in cmake.
009e491 Fix GeneratedMessageV3 warnings.
da00355 Merge pull request #2809 from xfxyjwf/i2464
61e87f3 Use per-type table to lookup JSON name.
7c75344 Fix lint warnings in the javalite branch.
cad6a51 Merge pull request #2819 from haberman/pythonexcept
3e6245e update_failure_list.py: fixed Python "raise" statement.
075475f Don't expose gson exceptions in JsonFormat.
bbfb9d5 Merge pull request #2804 from acozzette/ruby-memcpy
8e465dc Merge pull request #2810 from xfxyjwf/i1994
af2d5f5 Merge pull request #2775 from xfxyjwf/fixmajor
9afacb4 Merge pull request #2814 from pherl/javadeprecate
baceff7 Add annotations for deprecated messages in Java
008dc92 Ruby version optionally emits default values in JSON encoding.
9fa4031 Ruby: wrap calls to memcpy so that gem is compatible with pre-2.14 glibc
c311543 Avoid redundant type casts for oneof bytes fields.
4ae8656 Make JsonFormat locale independent.
fa17880 Merge pull request #2602 from GreatFruitOmsk/issue-2428
920af75 Fix Bad Link for Common Lisp
dd8d5f5 Rename encode/decode to serializeToString/mergeFromString (#2795)
769b693 compiler/cli: PrintHelpText prints to stdout instead of stderr
2b7430d Merge pull request #2793 from keveman/master
f6d8c83 Merge pull request #2613 from aausch/fix_memory_leak
21b58b5 Removed a stray return statement, causing compilation error.
651ba62 JS: ensure that extension values are serialized even if they're falsy
06f9f60 Detect if Descriptor.cs changes for csharp
f873d32 Added JavaScript conformance tests.  All tests pass!
27b1f2b WIP.
0c0a887 Merge pull request #2751 from keveman/master
008ff03 Merge pull request #2784 from acozzette/log-2-floor-int
6837b2d Added comment explaining the protobuf_headers target.
af13bff Detect if Descriptor.cs changes for csharp
8610d0a Merge pull request #2755 from xfxyjwf/rubycomp
352526c Merge pull request #2785 from thomasvl/threading_race
2d1c5e2 Handing threading race resolving methods.
938206d Return uint32 from Log2FloorNonZero64
a7e3b0a Merge pull request #2774 from acozzette/closure-builder
8b182cc Disable static analyzer for message semaphore creation (#2748)
6011d7c Fix gcc 4.1 build (#1035) (#1913)
25ecd55 Change hint type to `const void*` (#2568)
bcbaabe Add mergeFrom method on Message (#2766)
671e075 Use closurebuilder.py in favor of calcdeps.py for compiling JavaScript
7339fc0 Merge pull request #2674 from acozzette/js-test-cleanup
b7f25d4 Undef major/minor if they are defined as macro.
aff9d9d Removed log statement from writer_test.js
5274d6e Merge pull request #2770 from xfxyjwf/fixcmake
83b0cc9 Merge pull request #2772 from sschuberth/master
606cb7e There might be duplicated enum values when allow_alias is true. Add PreferredAlias into OriginalNameAttribute to remove the duplication (#2727)
902af08 Prefer the term "3-Clause BSD License" over "New BSD License"
6395a1c Fix links to the New BSD License in meta-data
ffde972 Remove the use of C++11 features.
9118ad6 Add Ruby compatibilty test against 3.0.0.
d41c47f Merge pull request #2733 from wmamrak/patch-1
8d61f9c Merge pull request #2729 from MarcelRaad/fix_inline_msvc12
b4b0e30 Merge pull request #2355 from xfxyjwf/fixjson
8387b88 Merge pull request #2732 from AsturaPhoenix/master
66c64e7 Merge pull request #2747 from liutikas/master
8c8b8e6 Merge pull request #2734 from msabramo/patch-1
72b82e6 Merge pull request #2630 from blodan/master
963473b Merge pull request #2753 from thomasvl/recursive_drop
d071766 Add GPBMessageDropUnknownFieldsRecursively() and tests.
2d430f8 Added a header only cc_library target for the protobuf library.
17174b5 Updating README
f83d129 Upgrading test-related libraries
c9b2c8f Fixes for .NET 3.5 compatibility
a434bfc Fix compiler warnings about unused variables in generated_message_reflection.h
1a8cbfd Merge pull request #2736 from na-ka-na/master3
172e0a6 Add an option to always print enums as ints in Json API
86208c5 README.md: Make docs URL a link
37bd5d5 Disable MSVC warning C4309
01a05a5 const FieldDescriptorCompare
8f9c0a4 Fix unresolved symbols with MSVC12 and /Zc:inline
a9ab38c Merge pull request #2722 from ckennelly/unified
8af35f2 Keep loop bounds in a local variable for string fields.
a6c30d9 Keep loop bounds in a local variable.
9db5b11 Work with truncated tag numbers.
0026dff Expose rvalue setters for repeated string fields.
38b1440 Merge pull request #2663 from ckennelly/varint-size
15360e5 Merge pull request #2689 from ckennelly/aliasing-fixed32-fixed64
38c238e Improve support for plugin parameters.
d2dfe46 Merge pull request #2609 from yixiang/patch-1
3f6f73b Merge pull request #2701 from anandolee/master
ed423c2 Merge pull request #2451 from podsvirov/json-primitive-map
aa78aeb Merge pull request #2704 from liutikas/master
74eb9a0 Add clear method to PHP message (#2700)
46c022a JsonUtilTest: Add ParsePrimitiveMapIn subtest
9079079 Fix compiler warnings about unused variables in wire_format.h
ef927cc Switch to gcc atomic intrinsics for macOS and delete the file that uses (#2699)
7288689 Add csharp compatibility tests against v3.0.0 and run on Travis.
1d2736f Merge pull request #2656 from pcj/patch-1
9f09d18 Add proto and test files for csharp compatibility tests against v3.0.0. All the files are copied from 3.0.0 (JosnFormaterTest was deleted)
c6e0d0e Merge pull request #2647 from anandolee/master
42e1e2a Fix python compatibility test when a new generated code imports an old version(2.6.1 or older) generated code.
e844510 Merge pull request #2692 from cgrushko/patch-3
65a4d20 Update load() statement to latest style
a60cc08 Merge pull request #2691 from cgrushko/patch-3
cba04b1 Implement json encoding decoding for php. (#2682)
6fffd4a Bazel can build protobuf when it's not in the root
56da828 Avoid aliasing CodedInputStream::buffer_ when parsing little endian integers.
c002743 Add fixed version to phpunit used in travis (#2673)
36f51f9 Merge pull request #2681 from sergiocampama/spaces
e7f5c9d Removes trailing whitespaces
5a3405c Update upb for php. (#2662)
bd29f86 Fix CopyTo argument validation
36f68e0 Inline branch-less VarintSize32/VarintSize64 implementations.
3975664 Add conformance test for php (#2655)
7b54b34 Add bazel protobuf resources
7f3e237 Merge 3.2.x branch into master (#2648)
9d3288e Merge pull request #2226 from kchodorow/master
2c36cc3 cache generated classes, optimization and quick workaround to memory leak
afc59ab C#: Implement IReadOnlyList<T> in RepeatedField<T>
87e4976 Merge pull request #2639 from anandolee/master
1ee09c8 python: do not include internal 'strutil.h' header
a83ac86 fix compile error on centos in metadata.h for constructors. (#2599)
a323f1e Oneof accessor should return the field name that is actually set. (#2631)
ccb76ff Add Oneof custom options test
5af0b54 Merge pull request #2619 from anandolee/master
1f09786 Merge pull request #2633 from anandolee/jieluo_branch1
ea51149 Add python compatibility tests against v2.5.0 amd run on Travis.
c15217f Allow OneofOptions to be extended in proto3.
c2a5669 Merge pull request #2626 from sergiocampama/8_3
32fa55e FreeBSD compatibility
4e7ecde Update genfiles paths to work with a different execroot arrangement
3d7b42d Adds nullability modifiers to resolve Xcode 8.3 warnings
140e28d Add python compatibility tests against v2.5.0: copy tests and proto files from v2.5.0
0aa5af3 Merge pull request #2614 from acozzette/gzip-output-stream-options
a101fa5 Set LIBPROTOBUF_EXPORT on GzipOutputStream::Options
e41b667 Undef TYPE_BOOL to avoid conflict with iOS.
047575f Support custom options in C#
eed9951 Merge pull request #2591 from thomasvl/objc_timestamps_take2
24908e1 Update AbstractMessage.java
d0bc096 Timestamp helper fix, Duration helper cleanup.
c9cd6ac Merge pull request #2587 from google/revert-2586-objc_timestamp
1651342 Revert "Fix Timestamps with dates before the Unix epoch that contain fractional seconds."
cf477d4 Merge pull request #2586 from thomasvl/objc_timestamp
adcccd0 Fix Timestamps with dates before the Unix epoch that contain fractional seconds.
feb78fb Merge pull request #2584 from cgrushko/patch-2
e4baf3f Add a proto_lang_toolchain for Java
e53dd99 Merge pull request #2529 from wackoisgod/master
fac90c6 Update AbstractMessage.java
75ac397 Fixing code formatting issues
effcb13 Merge branch 'master' of https://github.com/wackoisgod/protobuf
228d242 Merge pull request #2567 from acozzette/distcheck-fix
fb71df9 Add ByteString.FromStream and ByteString.FromStreamAsync in C#
e76d91a Add global.json file to pick dotnet core SDK version.
0bdf4a6 Fixed "make distcheck" for the Autotools build
2bddffc PHP fix int64 decoding (#2516)
2c16f69 Fix generation of extending nested messages in JavaScript (#2439)
ffa71f8 A few more cases for binary conformance tests. (#2500)
1041710 Merge pull request #2565 from acozzette/cross-compilation
24f0d56 Merge pull request #2563 from thomasvl/autocreator_tweaks
988ffe0 Minor fix for autocreated object repeated fields and maps.
2deb139 Merge pull request #2544 from tiziano88/master
17a8a76 Merge pull request #2536 from jbrianceau/fix-js-embed-include-style
c55175c Merge pull request #2564 from acozzette/arena-nc
a592052 Removed arena_nc.cc and arena_nc_test.py
b40d318 Fixed cross compilations with the Autotools build
f3e86fd handle sanity check for repeating enums correctly
4cb113a Fixed issue with autoloading - Invalid paths (#2538)
30250cd Add link to Elm proto plugin
5f65ee6 Merge pull request #2542 from jbrianceau/fix-embed-cc-warning
4455cdf Fix include in auto-generated well_known_types_embed.cc
05b019a Fix warning in compiler/js/embed.cc
f52e188 Merge pull request #2523 from jbrianceau/init-index-in-metadata
137dc02 Merge pull request #2525 from camillol/lite
abe1725 simpler, cheaper callback to LazyStringOutputStream
4e229c8 add MethodResultCallback_0_0
15a15e3 Init index_in_metadata_ without condition
6c021b3 Added the support for class level deprecation which will in turn also deprecate any fields that are currently using that type
d948b66 Merge pull request #2521 from acozzette/fix-bazel
5731ca5 Added well_known_types_embed.cc to CLEANFILES so that it gets cleaned up
ee0a243 Updated Makefile.am to fix out-of-tree builds
d1e7bd9 Added Bazel genrule for generating well_known_types_embed.cc
cdc2766 Merge pull request #2506 from ckennelly/rvalue-setters
bb2c6b2 Merge pull request #2505 from ckennelly/master
c64830b unwrap descriptor class before comparison of RepeatedField types
fb15862 Merge pull request #2517 from acozzette/js-embed
98d89d4 Fixed "make check" for cmake build
1b3a0c1 Auto-generate well_known_types_embed.cc
183d31c Add rvalue setters for non-arena strings on C++11.
f39cf88 Merge pull request #2227 from KindDragon/3.1.x
b18bc9b Give C# ByteString a sensible GetHashCode implementation.
ef61a9d add a key to ctx.action dict to prevent protoc losing the default env
ba63fa7 Remove spurious NULL checks in ArenaStringPtr::CreateInstance.
a95e38c Merge pull request #2499 from ckennelly/master
a902e25 Define LANG_CXX11 for port.h and use this to guard C++11 features.
83d681e Merge pull request #2495 from acozzette/android-hash
d1c1dad Merge pull request #2498 from sergiocampama/enum
c68fc58 Fixes and expands comments on how to use GPB_ENUM_FWD_DECLARE
2ff42dc Added conformance testing for binary primitive types. (#2491)
f983302 Merge pull request #2496 from xyzzyz/fix-overflow
837fd6b Merge pull request #2493 from jbrianceau/add-missing-climits-include
f77b7d9 Merge pull request #2484 from ngg/uwp_build
4c5d3ed Fix integer overflow in FastUInt32ToBufferLeft
5587562 Removed Android-specific code from stubs/hash.h
7b220f3 Add missing include in embed.cc
9d709f4 Merge pull request #2487 from jtattermusch/csharp_leading_whitespace
83c728a Add missing includes
eb455ce Merge pull request #2471 from jbrianceau/fix-include-style
6b86a89 Merge pull request #2490 from xfxyjwf/icon2
4c252dd Add a badge for bazel build status.
ec021f5 Add support for Windows ARM builds
29fb87e Merge pull request #2454 from pongad/go_package
fda9049 remove leading whitespace in C# xml comments
277a8b6 generate_changelog.py: flush output so piping works correctly.
8494846 Merge pull request #2476 from acozzette/generated-message-reflection-fix
dc11940 Merge pull request #2475 from sergiocampama/rvm2
e19f3b5 Use uint32 in GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET macro
1ac8944 Reenable cocoapods objc test and remove unnecessary workaround for rvm
e43f73e Merge pull request #2473 from thomasvl/update_xcodes
70e21d7 Mark objectivec_cocoapods_integration as failing
bc9d077 Skip benchmark test if cmake isn't installed.
2754586 Xcode 8.1 support
e3da722 Fix #include in cc files
243ebec Merge pull request #2468 from sergei-ivanov/patch-1
d8f54c4 Disable jruby test. (#2469)
09dc933 Update third_party.md
e3e38b8 Update commit id in Dockerfile to trigger update. (#2467)
4474c04 Merge pull request #2462 from jbrianceau/fix-comp-builds-part2
6b4eee4 Merge pull request #2461 from jbrianceau/add-missing-include-in-embed-cc
34a1b6e Merge pull request #2394 from cwelton/formatting
46ae90d Make php generated code conform to PSR-4. (#2435)
631f461 Merge pull request #2466 from thomasvl/deprecation_followup
4c84b47 Merge pull request #2460 from sergiocampama/c11
dad775b Improve ObjC deprecated annotation support.
e219be7 Regenerate descriptor proto
b1295ee C++: export _xxx_default_instance_ symbols
867dbac Add missing include in embed.cc
c836ad4 Merge pull request #2459 from acozzette/android-logging
1d91c25 Include -std=c++11 when compiling protobuf if available.
2f29f0a Send all protobuf logging to logcat by default on Android
057389c Ruby: removed redundant RepeatedField#slice. (#2449)
850d573 Merge pull request #2407 from jbrianceau/fix-comp-builds
788d14a Export symbols used in inline functions
bb77cbf update descriptor.proto's go_package
607b921 Merge pull request #2437 from xfxyjwf/plugin
1a56251 oneOf fix for JsonFormat includingDefaultValueFields
ced8f73 Add version number to plugin protocol.
0509072 Merge pull request #2445 from ramrunner/master
c664b66 Merge pull request #2442 from pherl/fix-bazel
4cc160e when on OpenBSD we include the correct headers for endianess and check the apropriate defines
f92b455 Add missing files.
f1ce60e Factored Conformance and Benchmark test messages into shared test schema. (#1971)
4280c27 Merge pull request #2436 from cgrushko/patch-1
45d92ae Add a proto_lang_toolchain() for cc_proto_library
6b60ddd Merge pull request #2431 from saintstack/2228v2
7550bcd Change CodedInputStream#DEFAULT_SIZE_LIMIT from 64MB to Integer.MAX_SIZE (0x7FFFFFF) #2228
f8ca3ac Generate phpdoc in php generated files. (#2406)
34dc96b LIBPROTOC_EXPORT added to others functions in csharp_names.h and objectivec_helpers.h
b790da5 Missed LIBPROTOC_EXPORT for GRPC added
851cb81 Merge pull request #2429 from thomasvl/issue1833_swift_prefix
f813bd9 Add a swift_prefix file option.
39f9b43 Merge pull request #2403 from google/down-integrate-with-msvc-fix
65479cb Fixed Ruby tests for JRuby 1.7
259dd7e Updated descriptor_pool.py to be compatible with Python 3
db35fe7 Add a "u" suffix to tag numbers in generated code
a7f300d Fixed descriptor_pool_test.py for Python 2.6
c950471 Merge pull request #2404 from wiktortomczak/master
0fa31b2 Support grpc plugin in py_proto_library
a41090e Updated failure_list_java.txt for Java conformance test
72002d8 Merge pull request #2400 from acozzette/jspb-test-fixes
fda876a Added back in binary serialization round-trip in message_test.js
b763246 Merge pull request #2398 from jbrianceau/no-static-init-define-fix
04bd614 Merge pull request #2392 from xfxyjwf/fixdown
40f3586 Fixed remaining JSPB test failures
315350b Updated message_test.js so that it does not depend on fromObject
b4dd686 Updated enum names in test.proto to avoid conflicting with testbinary.proto
a5c30ce C++: Fix use with GOOGLE_PROTOBUF_NO_STATIC_INITIALIZER
7807932 Restore jenkins files.
599613e Update EXTRA_DIST lists.
1f077a0 Update conformance failure lists.
530ae30 Add back missing LIBPROTOBUF_EXPORT.
1673389 Updated libprotoc.cmake
5d63097 Merge branch 'master' into down-integrate-with-msvc-fix
5a76e63 Integrated internal changes from Google
cd315dc Merge pull request #2383 from snapsam/patch-1
44edefa Merge pull request #2382 from zhsyourai/master
d571d39 Update README.md
14c147e Add LL to large constant
cb54caf Add tests to demonstrate json parsing for null Timestamp and Duration types
99564c3 Rename Empty to GPBEmpty in php generated file.
fc27ead Merge pull request #2362 from wujingchao/patch-1
a3dfbe6 Merge pull request #2378 from ianfhunter/patch-1
01d321c Merge pull request #2367 from jbrianceau/add-missing-include-in-message-lite-cc
130bb07 typo
83d6411 Fix jenkins tests.
bf37971 Merge pull request #2323 from marcinwyszynski/master
c6f3d70 Merge pull request #1907 from evokly/js-utf8-fix
bd850a2 JS: Well, this is the right place for surrogates.
292c2c9 JS: Re-added comment, moved surrogates code to the right place
6e93fa4 Merge pull request #2366 from jbrianceau/reland-fix-include-js-generator
a95d052 Merge pull request #2368 from jbrianceau/fix-json-style-in-project-json
3c0e0ce Fix csharp/src/Google.Protobuf.Test/project.json
aac9ed8 Add missing include in message_lite.cc
3316062 Fix #include in js_generator.cc
74a636a Move variable declarations before actual code
0c0f7e2 Merge pull request #2364 from haberman/jslicense
5d9dbe3 Fixed JavaScript license declaration.
abeff7b Class is final but declares protected field
a30e5af Merge pull request #2358 from ckennelly/master
e02cb2b Resolve old TODO for StringTypeHandler.
8a4b2c5 Merge pull request #2353 from guptasu/master
df56736 Merge pull request #2357 from D3Hunter/master
ed08341 #2356 : fix ExceptionInInitializerError on IBM J9
bd158fc Speed up JSON parsing.
df83907 Fix php c extension on 32-bit machines. (#2348)
9f75c5a Merge pull request #2337 from sergiocampama/deprecation
fce8b6b Made helper code also consider package name 'proto2' when dealing with MessageOptions.
e75cf40 Fixing references to the removed atomicops_internals_pnacl.h file.
ce5160b Merge pull request #2332 from Kwizatz/master
d584321 Merge pull request #2327 from ctubbsii/fix-maven-compiler-plugin
1f2dbc8 Implement RepeatedFieldIter for c extension. (#2333)
ecc460a Renamed the pnacl version of atomicops.h into C11 atomic, and flagged the mac version to that if atomic is enabled
975d577 Added explicit cast to avoid size warning on Win64.
0d7199e Merge pull request #2329 from acozzette/unused-parameter
ca800ea Merge pull request #2330 from manupsunny/master
089aaa9 Fix message for InvalidProtocolBufferException
8785004 Fix unused parameter warnings in arena_free
eb7f3a3 Use latest maven-compiler-plugin (2.6.0)
7bd11fc Merge pull request #2301 from jbrianceau/arm-atomic-kuser-helpers-fix-v2
4c310d7 Update conformance test failure list
50a37e0 Change JSON field name formatting
cb81314 Fix copy pasta in test
3bdaaa5 More Ruby-eqsue interface
93a4fa2 Merge pull request #2302 from jbrianceau/generic-gcc-atomics-strong-cmpxchg
750b9e2 Merge pull request #2318 from mavrukin/patch-1
4d813de Fix compiler warnings when running :protobuf_test
8fcd24b Merge pull request #2307 from sinzianag/swift_protobuf
ea928a1 Merge pull request #2309 from thomasvl/note_about_coding_support
98c0185 Add note about extension use and Coding support.
9819b72 Adding Apple's Swift Protobuf
a5a2c1d generic atomicops: Use strong compare_exchange
4587a3f [arm/gcc] Don't rely on KUSER_HELPERS feature for atomics
d58b92a Adds pushLimit: and popLimit: into GPBCodedInputStream (#2297)
795976e Trigger update of docker for new changes in #2282. (#2288)
e9d9e56 Merge pull request #2290 from ramrunner/OpenBSDsupport
bfc1299 define no_threadlocal on OpenBSD
734930f Merge pull request #2284 from pherl/plugin_opt
2e314a6 Add comments about converting directives into PluginName
59cd5d0 Support extra parameters for plugins.
51c5ff8 Fix pure php implementation for 32-bit machine. (#2282)
58580da Merge pull request #2274 from nmittler/gae
c0f95c6 Hacking ByteBufferWriter to work with GAE
9c6940f Merge pull request #2264 from rshin/master
7c913d8 Use -DPROTOBUF_PYTHON_ALLOW_OVERSIZE_PROTOS
df5841f Place Python extensions correctly in Bazel build.
008b5a2 Merge pull request #2254 from JasonLunn/patch-1
9ec7a47 Use git clean before installing via bundler
993d604 Merge pull request #1959 from abergmeier-dsfishlabs/feature/cpp
ad88f90 Merge pull request #2251 from TeBoring/master
686a19c Merge 3.1.x into master.
e28286f Add 32-bit machine test on jenkins. (#2245)
afaa827 Merge pull request #2246 from fweikert/patch-1
c2b3e70 Declare all inputs of protoc action
60d95f3 Fix the bug that message without namespace is not found in the descriptor pool. (#2240)
0321baf Merge pull request #2203 from mrry/msvc_fix
7332ffb JS: Replaced fromCodePoint/codePointAt with fromCharCode/charCodeAt because of functions limited availability, fixed typo in tests.
fd046f6 Merge pull request #2234 from TeBoring/master
daba665 Fix python_cpp test on Mac. Link staticly when building extension, so that the extension doesn't require installing protobuf library. (#2232)
5be6325 Add csharp/build_tools.sh for dist check.
63448e6 Fix compile error for php on Mac.
4f3d20a Fix segmentation fault when ZTS is defined.
1e5d4ba PHP: fix ZTS tsrm_ls errors (#2189)
c96dd66 Add test for php zts build.
447dee1 Prepare jenkins for testing php zts build.
7047761 Do strict enum name checking only for proto3
34cdaf4 Add travis test on Mac for php.
c8bd36e Test php5.5_c test on jenkins
c0719f0 Trigger automated tests for php.
91bbff2 Set up environment for php automated tests.
fd332d1 Add php test script for automated tests.
89db7ce Add script to build Google.Protobuf.Tools for csharp.
f2eeaf7 Added alias getFieldProto3 as used by older generated code.
4a4a162 Fixed references to foreign nested messages with CommonJS-style imports
0bf5482 Fixing inconsistent php version number.
ae9455c Fix MSVC stack overflow issue.
e0a6e52 Add php files for make dist.
17cc42a Update change log for 3.1.0 (#2173)
8db25a2 Force a rebuild of Jenkins docker image.
a41349d php: support 5.5.9 for pecl extension (#2174)
39685f6 Fix VS test failures.
2937c67 Use "appveyor DownloadFile"
b155958 Update php supported version.
9e260a3 Reduce test length to avoid stack overflow on VS.
1c4cf0e Fix python cpp.
460e7dd Fix Visual Studio compile issues.
4cf0722 Fix default instance destructor
f9f3c35 Update version number.
0c78525 Bump library version to 11
e62d1f1 Add back removed descriptor field.
fac876d Modify php api version and minimum supported php version.
9372292 PHP: support 7.0 on PHP implementation (#2162)
f933d10 Update version number.
04d72c2 Fix java compatibilty tests.
9d4657a update files to include php generators
633fdfb Update minimum support php version to 5.5
9526385 Fix bugs for internal integration.
89d8e43 Fix travis, jenkins environment issues.
7fecfdb Added new has_bits.h file to cmake/extract_includes.bat.in (#2152)
f7bb847 Fixed quadratic behavior in JSPB deserialization of repeated fields (#2117) (#2146)
31dd499 Fix bugs for csharp and ruby for internal integration.
23d4688 Fix python bugs for internal integration.
93007e1 Bump library veriosn to 3.1
fe1aaad Fix bugs for internal integration.
15f4db6 Bump version number to 3.1.0-alpha-1.
af62fde Fix for maps_test.js in JavaScript. (#2145)
e3f0689 Fix bugs for internal integration.
cc8ca5b Integrate internal changes
337a028 Merge pull request #2236 from hochhaus/master
b2b6584 Silence compile warnings in bazel
bc3bff1 Fix python_cpp test on Mac. Link staticly when building extension, so that the extension doesn't require installing protobuf library. (#2232)
c0c3aee Merge pull request #2229 from xfxyjwf/fixbuild
431cee6 Remove inexist files from build.
d947308 update files to include php generators (#2165)
b0d62dd Add csharp/build_tools.sh for dist check.
96e2d76 Fix compile error for php on Mac.
75b6988 Fix segmentation fault when ZTS is defined.
52ab3b0 PHP: fix ZTS tsrm_ls errors (#2189)
71e5994 Merge pull request #2193 from acozzette/common-js-fix
60bc203 Merge pull request #2199 from JasonLunn/patch-1
2d897c8 Add test for php zts build.
3a055be Prepare jenkins for testing php zts build.
640c947 Merge pull request #2204 from acozzette/enum-names
149659b Do strict enum name checking only for proto3
858db7a Add travis test on Mac for php.
4d87527 Merge pull request #2218 from thomasvl/xcode8_updates
bcb32c0 Test php5.5_c test on jenkins
297449a Update the ObjC projects for Xcode 8
fe1d0a1 JS: Added string encoding/decoding tests for UTF-8
23f108d JS: Fixed UTF-8 string encoder/decoder for high codepoints.
350d494 Merge pull request #2206 from acozzette/gitignore
dae50dc Trigger automated tests for php.
f17528a Set up environment for php automated tests.
1baaedf Add php test script for automated tests.
25dbc8b Updated .gitignore with Java and JavaScript build artifacts
6005648 Add development dependency requirements
1d2c7b6 Fix MSVC build when HAVE_LONG_LONG is defined.
ee19a7c Remove hanging reference to Gemfile.lock
d94ff41 Delete Gemfile.lock
07f3cab Set platform to "java" under JRuby
b9bad65 Add script to build Google.Protobuf.Tools for csharp.
3b88a4a Merge pull request #2196 from haberman/nodefix
3d598ee Merge pull request #2197 from thomasvl/swift_docs
fb85b43 Drop the swift docs directory (and content).
8b54280 Added alias getFieldProto3 as used by older generated code.
c4d7012 Fixed references to foreign nested messages with CommonJS-style imports
3f59452 Merge pull request #2192 from google/3.0.x
787f3fb Fixing inconsistent php version number.
c531b49 Merge pull request #2181 from google/jtattermusch-patch-2
530eede Update README.md
4d3e4cf Fix MSVC stack overflow issue.
a428e42 Add php files for make dist.
e7269aa Update change log for 3.1.0 (#2173)
87d61e4 Merge pull request #2175 from xfxyjwf/fix_json
5248f61 Force a rebuild of Jenkins docker image.
907a075 php: support 5.5.9 for pecl extension (#2174)
3c88e1b Fix VS test failures.
c454b44 Merge pull request #2171 from xfxyjwf/fix_json
73c8723 Use "appveyor DownloadFile"
18f336b Update php supported version.
f6b4d18 Reduce test length to avoid stack overflow on VS.
411968d Fix python cpp.
37c3d05 Merge pull request #2167 from xfxyjwf/fix_vs
0798d91 Fix Visual Studio compile issues.
3bfc09d Merge pull request #2170 from pherl/3.1.x
f184cb6 Fix default instance destructor
34996c3 Merge branch '3.1.x' of github.com:google/protobuf into 3.1.x
a289d43 Added C++ benchmark. (#1525)
d9ff3ef Merge pull request #2153 from haberman/generatechangelog
8c88762 Update version number.
94bbeb4 Bump library version to 11
1b7a844 Add back removed descriptor field.
9cb812f Modify php api version and minimum supported php version.
11433f7 PHP: support 7.0 on PHP implementation (#2162)
39a2a25 update files to include php generators (#2165)
2649844 Update version number.
5270e93 Fix java compatibilty tests.
923314c update files to include php generators
1bf97d8 Merge pull request #2159 from google/jtattermusch-patch-1
da7c026 Update README.md
ca21b28 Merge pull request #2157 from google/csharp_remove_beta_notice
ca8120c Update README.md
8352d52 Update minimum support php version to 5.5
bee5213 Fix bugs for internal integration.
525c632 Fix hash computation for JRuby's RubyMessage
b8e7e89 Fix travis, jenkins environment issues.
b28ab73 Fix gson dependency. gson 2.3 has internal bug that it doesn't work with some versions of maven.
142e2fa Merge pull request #2035 from sergiocampama/cpp
a2e7364 Added convenient script for generating changelog draft.
e25c56a Merge pull request #2149 from khingblue/remove-obsoleted-project
050c014 Added new has_bits.h file to cmake/extract_includes.bat.in (#2152)
f81d44f Fixed quadratic behavior in JSPB deserialization of repeated fields (#2117) (#2146)
741aa87 Remove obsoleted project of j2me
b9bc990 Fix bugs for csharp and ruby for internal integration.
c8b9d41 Fix python bugs for internal integration.
1af7c4c Fixes static analyzer issues from xcode.
08e9f70 Bump library veriosn to 3.1
22d7248 Fix bugs for internal integration.
4f379f8 Merge pull request #2144 from abscondment/fix-jruby-hash
6cb6bd9 Fix gson dependency. gson 2.3 has internal bug that it doesn't work with some versions of maven.
ebcda12 Bump version number to 3.1.0-alpha-1.
679381f Fix for maps_test.js in JavaScript. (#2145)
05aa0df Fix hash computation for JRuby's RubyMessage
a2c6501 Fix bugs for internal integration.
0dca5a5 Use a custom dictionary to avoid NSNumber operations.
96c469d Remove the custom key functions and just use the system provided defaults.
98835fb Integrate internal changes
7b00595 Merge pull request #2137 from thomasvl/objc_extensions_tweak
6ab51a0 Use a custom dictionary to avoid NSNumber operations.
5904279 Remove the custom key functions and just use the system provided defaults.
b5bbdb0 Merge pull request #2037 from abscondment/fix-2036-ruby-hash
c44ca26 Merge pull request #2130 from kilink/substring-comment-fix
9ac84f8 Fix erroneous comment regarding String.substring
3b001ca Some php engine implementation doesn't have return_value_ptr properly set. Explicitly use &return_value.
c6fa9c7 Auto-generate proto files for tests.
f174d36 Add back missing test proto files.
37e0e1f Merge pull request #2111 from pherl/3.0.x
9c4be5f Merge pull request #2112 from pherl/merge
b4235ac Merge pull request #2123 from thomasvl/objc_better_versioning_take2
1aa6500 Update the ObjC version checks to support a min and current version.
e0e5466 Check in php implementation. (#2052)
683412b Update generated files.
58860c0 Merge remote-tracking branch 'origin/3.0.x' into merge
13d6d17 Fix the version number for 3.0.2
86fcd87 Merge pull request #1765 from mbarbon/master
1affbd8 Merge pull request #2021 from zlim/bench-fix
4f032cd Merge pull request #2100 from vladmos/patch-1
22e7fa6 Merge pull request #2092 from dprotaso/master
5caf516 Resolved a conflict
78aee1b Merge pull request #2044 from wychen/Win32ANSI
643a02b Merge pull request #1636 from yugui/feature/generic-plugin
53387e5 Merge pull request #2090 from guoxiao/find
e90292b Merge pull request #2103 from adrianludwin/fix-gtest
1327e6f Update repo to use google test
7377eb2 Merge pull request #1970 from thomasvl/objc_any_helpers
a86e6d8 Compatibility with the new version of Bazel.
5d35e60 Merge pull request #2094 from thomasvl/update_wkt_comments
57170b9 Merge pull request #2096 from pherl/3.0.x
5699b92 More complete nil/reset tests within a oneof
708296e Fix some constants to be correct for the message class in use.
161b937 Fix error and add note about lossy issues
14e74f6 Support the -Wassign-enum compiler flag. (#2085)
1fc416b Allow the JsonFormat.Parser to ignore unknown fields
a15df74 Merge pull request #2087 from khingblue/fix-unused-param
337ec30 Add ObjC helpers for Any WKT.
82133ba include std::find()
08b1c71 Fix #2032 unused parameter 'deterministic'
4bc1657 Merge pull request #2079 from khingblue/fix-generate-descriptor
30e55ae Merge pull request #2083 from pherl/3.0.x
7645a3d Merge pull request #1884 from hochhaus/valueWriterFn
f9fc56c Fix #2071 replacing /bin/sh with bash
1a58673 Merge pull request #2077 from pherl/3.0.x
e298ce5 Update release date in the change log
74638a2 Merge pull request #2047 from jonathon-love/master
65a595d Merge pull request #2062 from pherl/3.0.2
01d1750 Merge pull request #2061 from pherl/changelog
9b8da10 Rm check on dependency in the C# reflection API (#2051)
96a9d97 Merge pull request #2059 from chih-hung/master
7c3f7c6 Fix #1955 clang-tidy warning misc-macro-parentheses
6e11540 Bump version number to 3.0.2
0c9999f ruby, js and c# changes
a098e80 Merge pull request #1862 from pherl/3.0.0-GA
4041ed4 objc change log
9befe47 Merge pull request #1978 from pherl/cp
9d30a98 Merge pull request #2026 from pherl/cpjs
fa6428e Merge pull request #2045 from mike07026/master
85c1adf Merge pull request #2053 from thomasvl/improve_root_registry_wiring
64958cd Fix to typo/oversight in python tests
a7eaf36 Rename UNICODE to protobuf_UNICODE
13a4124 Make Root's +extensionRegistry generation smarter.
d00cab0 Merge pull request #2039 from khingblue/remove-unused-vector
df6088a detect invaild JSON encoding in bytes field
5a17660 detect invaild JSON encoding in bytes field
e514f23 fix #1342 cause by ownership issues
48811b2 Fix Win32ErrorMessage on Unicode build
11d6cb5 Add test for Win32ErrorMessage
588a803 Support Unicode build on Windows
b964976 Merge pull request #2024 from pstavirs/master
52e491b Use 64-bit protoc binaries in compatibility tests.
8ee6f56 Remove unused vector
de02863 fix #2036: use `rb_hash_*` to accumulate hashes
047419a failing test for #2036:
c0a6a6b Merge pull request #2033 from frett/osgiExport
b6dec9b update the OSGi SymbolicName and ExportedPackage for the javanano library
dd45c0b Merge pull request #2012 from haberman/rubymapgcfix
8c93606 Merge pull request #2031 from thomasvl/dont_require_filegenerators
78a6d31 Speed up ObjC Generation with large dependency trees
e721ce6 Merge pull request #2012 from haberman/rubymapgcfix
8335b7d Fix missing import of jspb.Map (#1885)
3a674ff upb bugfix: JSON map entry keys were passing the wrong closure.
eedc7be Restore New*Callback into google::protobuf namespace since these are used by the service stubs code
7e62773 Merge pull request #1920 from gegles/master
c32b9dd Merge pull request #2018 from thomasvl/support_generate_all
f5c7a48 benchmarks: update readme.txt
4fd4471 Merge pull request #2014 from pherl/fixgmock
2e66a61 Support GenerateAll().
1760feb Update gmock links.
1e6dc7d Update links in appveyor.yml
d4213d8 Ruby: make sure map parsing frames are GC-rooted.
3d9d1a1 Merge pull request #2013 from xfxyjwf/gmock
c4a84ab Update links in appveyor.yml
bba446b Update gmock links.
08951c3 Merge pull request #2011 from tomas-abrahamsson/patch-1
4d04fcd Add an Erlang project, gpb, to third_party.md
b97a4a5 Merge pull request #2001 from nicolasnoble/patch-1
866d3e5 Fixing regular expression...
569d5ce Merge pull request #1997 from thomasvl/move_include_package_into_helpers
290d26b Remove the compiler options from ImportWriter.
93362a5 Move the ImportWriter into the ObjC Helpers.
80f65d2 Add note about JSON tests maybe being wrong. (#1992)
b5794ed Merge pull request #1984 from thomasvl/more_json_tests
7437774 More JSON tests
ff2a660 Adds better support for protos without packages  (#1979)
8b30145 Add a jenkins test status badge.
45d04d0 Merge pull request #1977 from thomasvl/bump_cocoapod_spec
584917f Bump the version in prep for the 3.0.2 tag being cut
564c02f Merge pull request #1975 from pherl/cp
a877fdf Record zero for "has" for proto3 if in a oneof.
116596a Never use strlen on utf8 runs so null characters work.
62f2ff8 Fixes extra whitespace on generated comments. (#1950)
a989501 Adds support for appledoc in generated code.  (#1928)
42ab9b4 Migrating documentation of the ObjectiveC runtime code to appledoc. (#1867)
549dde1 Merge pull request #1967 from sergiocampama/cast
e505098 Adding casts so that code importing protobug using -Wconversion does not generate warnings.
e389165 Add more JSON tests around underscores (#1963)
4763e64 Merge pull request #1957 from xfxyjwf/jenkins_badge
d9ccf4d Merge pull request #1964 from thomasvl/missing_ignores
8156410 Fix up ignores and conformance generation
336ee28 Merge pull request #1960 from jskeet/oneof
f9d93f3 Regenerate conformance files to include extra oneof fields.
bbeb983 Need to expose generated protobuf C++ headers so they can actually be accessed from other libraries.
f8c37b9 Add a jenkins test status badge.
a248420 Fixes extra whitespace on generated comments. (#1950)
cd561dd Merge pull request #1949 from thomasvl/objc_more_reset_tests
ff85a17 More complete nil/reset tests within a oneof
a0df678 Fix some constants to be correct for the message class in use.
17d601a More explicit tests for nil behaviors on fields.
91b6d04 Merge pull request #1942 from thomasvl/objc_fix_oneof_zeros
27c8962 Add more types to the zero oneof cases.
ca5b775 Record zero for "has" for proto3 if in a oneof.
ac3df39 Add conformance test for zero fields in oneofs. (#1939)
30bbbe9 Merge pull request #1934 from thomasvl/objc_strings_with_null
1a6c1d0 Never use strlen on utf8 runs so null characters work.
237f321 Adds support for appledoc in generated code.  (#1928)
56b8f44 Merge pull request #1842 from udnaan/master
32fadc0 Migrating documentation of the ObjectiveC runtime code to appledoc. (#1867)
1102a8a Merge pull request #1923 from bryongloden/patch-1
a375e1a close opened file descriptors properly
e30b7b4 Merge pull request #1924 from PiotrSikora/export_license
f1f30b5 Merge pull request #1926 from hotpxl/master
ddf6d1e [master] Add dependency cl. Fixes google/protobuf#295.
faea19c Bazel: export LICENSE file.
c59473d Merge pull request #1044 from mark-whiting/master
6d134ea Merge pull request #1898 from sergiocampama/watchos
ea081fe Fix missing import of jspb.Map (#1885)
0dca3cc Merge pull request #1865 from podsvirov/topic-cmake-project
dedd8ae Merge pull request #1914 from adamatan/typo-fix
3886860 Typo: beffer -> buffer
cf42b60 Merge pull request #1905 from pherl/fixdoc
eefd1fd CMake: Auto find ZLIB from package config if nedded
3916a0a Add and fix C++ runtime docs
8d8115b Merge pull request #1878 from haberman/rubywkt
e0779d5 Merge pull request #1903 from xfxyjwf/compatibility_tests
3cec2ea Ruby: added custom Struct exception type and fixed Makefile.am.
30647ca Use 64-bit protoc binaries in compatibility tests.
ff46627 Merge pull request #1902 from podsvirov/topic-cmake-extract-includes
7d275ec CMake: remove repeated_field_reflection.h from extract list
00d5a7f Amend the conformance tests to only use Int64/Uint64 non-wrapped values which (#1164)
275db04 Adds watch os deployment target for protobuf
6b3d120 Merge pull request #1887 from sheffatguidance/fix-js-api-documentation
1112989 Merge pull request #1884 from hochhaus/valueWriterFn
915d79e Merge pull request #1895 from google/3.0.0-GA
3ef0756 Merge pull request #1894 from pherl/fixdist
e139117 Add python/setup.cfg into dist files
169d0ca Merge pull request #1893 from google/3.0.0-GA
c479042 Merge pull request #1892 from xfxyjwf/compatibility_tests
baa4023 Run Java compatibility tests on Travis.
f3449e5 Merge pull request #1891 from pherl/python
811674f add setup.cfg for building wheels
42e5487 Merge pull request #1882 from legrosbuffle/fix-check
7e93458 Merge pull request #1888 from pherl/fixbuildzip
6a59ac9 Fix the build-zip.sh to add .exe for win packages.
9a11ab4 Fix Issue #1869: faulty js API documentation
a217408 Fix valueWriterFn variable name
c466f4b Be consistent with the use of CHECK()/ GOOGLE_CHECK().
a207a2b Fix for JRuby (assert_true is not present).
e3094a8 Ruby: added API support for well-known types.
de30c56 Merge pull request #1874 from pherl/buildzip
e3fac65 Change the build.zip.sh to support lite
2662fd3 Merge pull request #1871 from pherl/fixwin
1b1a8f4 Fix build protoc script for windows
33d2b2a CMake: Bugfix for protobuf_MODULE_COMPATIBLE
38c5f2f CMake: Link to ZLIB only if protobuf_WITH_ZLIB enabled
e8ae137 Merge pull request #1864 from pherl/galogs
e7982e4 Fixed Makefile.am for Ruby file rename.
e0d817e Change log for 3.0 GA release.
4e169bf Bring C#'s ToPascalCase method in line with C++. (This still doesn't fix the conformance tests, but at least we're now consistent with the C++ code.)
86535a1 Remove legacy_enum_values flag for GA.
be78976 Merge pull request #1861 from jskeet/fix_to_camel_case
af2fa05 Merge pull request #1859 from jskeet/remove-flag
a8aae89 Bring C#'s ToPascalCase method in line with C++. (This still doesn't fix the conformance tests, but at least we're now consistent with the C++ code.)
e672047 Remove legacy_enum_values flag for GA.
7ba044a Merge pull request #1853 from pherl/3.0.0-GA
7c9c314 fix comments.
0750797 Merge remote-tracking branch 'origin/3.0.0-GA' into 3.0.0-GA
54feb9a Fix the script comments.
b1aac0b Make protoc-artifacts able to build plugin.
032fb91 Merge branch 'master' of github.com:google/protobuf into 3.0.0-GA
154e278 fixed cmake config files install path
b6b521b Merge pull request #1851 from xfxyjwf/cint
12581b4 Fixes traivs cpp build.
234ec01 Merge pull request #1847 from haberman/GAfixes
43b36dd Fixed Makefile.am for Ruby file rename.
f11a4f1 Merge pull request #1841 from pherl/3.0.0-GA
b3b07cd Merge branch 'master' into 3.0.0-GA
ba52f2b Merge pull request #1788 from google/rubypackagecap
c43f718 Merge pull request #1846 from xfxyjwf/zip
97e2026 Added new file to ruby_EXTRA_DIST.
6d92233 Added unit test for PascalCasing package names in Ruby.
6cab568 Ruby: translate package names from snake_case -> PascalCase.
b553b87 Add a script to build protoc zip packages.
b1cecb6 Merge pull request #1837 from haberman/rubygencodename
0973822 remove extra zeros.
5a6c921 Make jruby still depend on beta-4
a17367f Define intX as standard exact-width integer types.
fb7a7c5 Bump version number for GA
4f19797 Ruby: generated foo.proto -> foo_pb.rb instead of foo.rb.
868ea59 Merge pull request #1831 from xfxyjwf/protoc
b6cd9dd Merge pull request #1834 from sergiocampama/framework
44bd6bd Merge pull request #1821 from haberman/rubyfreezestr
d07a996 Ruby: fixed string freezing for JRuby.
9e3c98f Fix maven path.
3a1259c Correctly sets the generate_for_named_framework option after parsing.
0622030 Merge pull request #1830 from xfxyjwf/travis
1b3796c Merge pull request #1829 from xfxyjwf/fixcpp
fdd970e Fix maven links.
9702b9f Keep cpp_distcheck on travis for now.
c2ced9a Remove linux tests from travis.
9009662 Fix sign-comparison warnings in public header files.
16adea3 Add a test to catch sign-comparison warnings.
4ddaad4 Merge pull request #1825 from xfxyjwf/jenkins2
de5236d Merge pull request #1828 from sergiocampama/framework
2ff9349 Fixes the parsing of the proto-framework map file.
20fbb35 Add more tests to jenkins.
2ba058c Merge pull request #1822 from xfxyjwf/java6
ff7f68a Ruby: encode and freeze strings when the are assigned or decoded.
ad49ed7 Update travis tests for Java.
30d8416 Merge pull request #1811 from xfxyjwf/fixdist
a4f68b1 Add missing files in EXTRA_DIST and add a test.
af8732e Merge pull request #1810 from xfxyjwf/versioning
e465f26 Merge pull request #1812 from jskeet/fix-travis
dd3d9d6 Merge pull request #1447 from seishun/defaults
73e0b49 fix debug.dump
deaea21 Use the dotnet-release package feed for Travis.
60cb094 Add files missing from "make dist".
36adb40 Update compatibility tests as well.
2e30301 Versioning Java GeneratedMessage.
e4b129f restore old behavior for toObject
db1b2a0 nits
970a4fd Make implicit defaults consistent with explicit defaults
77b08af Merge pull request #1802 from haberman/jsmapbin
e0e7377 Fix goog.require()/goog.provide() ordering.
24ac9c0 Merge pull request #1803 from xfxyjwf/javadoc
fa52702 Include javadoc/source in Java release packages.
7429b91 JavaScript: move extension binary info to separate struct.
2078f61 Merge remote-tracking branch 'origin/3.0.0-beta-4'
923eae8 JavaScript maps: move binary callbacks out of constructor.
56855f6 Merge pull request #1792 from xfxyjwf/changelog
82b43d1 Remove Java deterministic API.
b6a620d Merge pull request #1801 from thomasvl/oneof_framework_build_issues
2e98ed5 Use public methods to fetch oneofs in generated code.
3d9726f Mention Java lite in the changelog.
b99577c Exposes the currently registered extensions for a message and removes the internal sortedExtensionsInUse
f6d1d1a Uses head version of rvm to avoid shell_update_session not found error (#1791)
1349fb8 Added 3.0.0-beta-4 changelog.
3a8d8ea Merge pull request #1787 from xfxyjwf/steppingstone
1bce70d Fix compatiblity issues.
0b68255 Add missing golden test file.
e1f146b Merge pull request #1785 from jskeet/merge-csharp
b5ce525 Move to dotnet cli for building, and .NET Core (netstandard1.0) as target platform (#1727)
5e0de1e Remove the overload for Add(RepeatedField<T>)
2ee1e52 Optimize AddRange for sequences implementing ICollection
b053b92 Implement RepeatedField.AddRange.
d9334ea Improve exception throwing implementation in collections
10a8fb4 Move to dotnet cli for building, and .NET Core (netstandard1.0) as target platform (#1727)
4e0d051 Merge pull request #1781 from xfxyjwf/update_version
c2ebdec Update version number in AssemblyInfo.cs.
8b659b2 Merge pull request #1783 from xfxyjwf/fixlite
047a3b4 Exclude Java lite module from parent pom.xml
dd37b99 Comment out lite conformance test.
932f94e Update version number to 3.0.0-beta-4
06a0248 Add missing LIBPROTOBUF_EXPORT
7a7913e Add missing LIBPROTOBUF_EXPORT.
443eb27 Update generated files.
9086d96 Integrate from internal code base.
042993b Implement RepeatedField.AddRange (#1733)
8eb90e3 Merge pull request #1778 from yeswalrus/fix-prerelease-version
5520447 Fix a bad variable dereference causing <package>_FIND_VERSION_PRERELEASE to be ignored.
70c1ac7 Merge pull request #1776 from thomasvl/fix_dist
0d079bc Remove the baseline files from the make dist file list.
790e6af Fixed out-of-date documentation for CodedInputStream.ReadEnum. (#1581)
3560cc9 Merge pull request #1702 from lukebakken/csharp-nuget-doc-update
297ec74 Add https://metacpan.org/pod/Google::ProtocolBuffers::Dynamic
8779cba Merge pull request #1764 from jskeet/remove-is-value-type
3df146e Remove unnecessary reflection call
c404c2a Merge pull request #1762 from thomasvl/drop_perf_profiles
8c23655 Drop the performace baselines.
8b00675 Merge pull request #1757 from thomasvl/avoid_importing_src
03d9e09 Merge pull request #1735 from jskeet/attribute-placement
c850ebc Merge pull request #1758 from dago/pathmax2
e9a7fc8 Remove WriteGeneratedTypeAttributes which is a no-op
57638d5 Make sure also Solaris x86 gets PATH_MAX
eaf3451 Merge pull request #1753 from xfxyjwf/fixup
be0d7f6 Don't #import the .m files.
0d5091e Merge pull request #1742 from ottok/fix-spelling
d84d0ca Fix data member declaration order.
a29a9c5 Don't support global ::string in stringpiece.h
c10938a Merge pull request #1752 from acozzette/fix-js-tests
c64d86e Fixed failing JS tests
ec45897 Merge pull request #1712 from dkharrat/swift-error-handling
523bfd4 add nullable qualifier to nil return types
c534845 Changes to generated code from previous commit
ada0a81 Move DebuggerNonUserCodeAttribute to function members
d2ae496 Fix spelling error in function ParseTime parameter
3808d09 Fix spelling in strings and comments
cae3b0c Merge pull request #1704 from lizan/json_parse_options
02b55d2 Merge pull request #1738 from xfxyjwf/fixbuild
e102db1 Fix some failing travis tests.
aeff638 Merge pull request #1710 from chezRong/master
7e8c893 Merge pull request #1723 from thomasvl/objc_test_coverage
454dbf1 added minified JSON formatting functionality with test
2fe0556 Fix windows build.
69cc213 Updated failure_list_java.txt to remove tests that now pass
b83af52 Fixed string formatting in text_format.py to be Python2.6-compatible
d64a2d9 Integrated internal changes from Google
6cfc19e Xcode project cleanup/setup.
c18aa77 Validate the tag numbers when parsing. (#1725)
e0016c5 Merge pull request #1720 from thomasvl/issue_1716
31999a3 Add JsonParseOptions to ignore unknown fields
dc0aeaa Adding conditional compiler symbol to support .NET 3.5 (#1713)
fc4c617 Fix GPBGetMessage{Repeated,Map}Field()
7b5648c Merge pull request #1719 from esteluk/patch-1
3be6110 Fix Objective-C generator option typo
2bcd43a Merge pull request #1714 from dnkoutso/master
37ca94f Get value from text format name in GPBEnumDescriptor
0ab78e1 Merge pull request #1705 from haberman/revjsver
6a6f95d JS package.json: Added author and updated Closure Library version.
6f67be6 Merge pull request #1707 from jskeet/format-value
0421238 Expose JsonFormatter.WriteValue.
1dc6280 Moved all dependencies to devDependencies.
48735cb Add "google" to package.json "files" for WKT.
c4b40a3 Create patch release for JS to include WKT.
8069466 Modify csharp README since there are now two NuGet packages
a897ebb Merge pull request #1700 from jskeet/ordering
a230b5d Rename methods to avoid ObjC KVC collisions. (#1699)
e3f6e2b Remove ordering guarantees in the MapField documentation
1a5333b Adds destination flag to xcodebuild to avoid possible flake errors (#1697)
4f93098 Merge pull request #1666 from yeswalrus/cmake-prerelease-examples
b7560df Merge pull request #1696 from haberman/jswkt
8c20e55 Add new generation option for using proto sources from other frameworks.
104723f Fix tests for CommonJS.
98bd6d7 Merge pull request #1692 from vjpai/friendless
4308cc4 Added plugin.proto to well-known types for JS.
6daf3d2 Address review comments on function name
0e27112 Bugfix: base the require logic on the file being required.
1337486 JS: import well-known types from google-protobuf package.
37eaae2 Remove a friend-class template that is only used for the constructor, and instead create an _internal_only getter that gets the needed information. This is a workaround for a deficiency in gcc-4.4 that does not properly support templated friend classes.
52598c6 Merge pull request #1658 from yeswalrus/cmake-fixup-module
a5e116a Merge pull request #1665 from yeswalrus/cmake-package-requirements
f180ef6 Merge pull request #1683 from thomasvl/third_party_framework
a2a3399 Add support for generation sources into a framework.
f0c1492 Add the CocoaPods integration tests to Travis.
71f4a9c Fixes Xcode 8 analyzer warning saying that it was missing a release in dealloc (#1678)
088c5c4 Merge pull request #1664 from bshaffer/patch-1
4150a91 make protobuf_MSVC_STATIC_RUNTIME a dependent option to reflect it's use.
78b3498 Save the relevant options used to create a package, allow users to reject packages based on them.
5ebcfc1 Fix prerelease version matching to be more consistent with the find_package arguments.
f8a969d proper codeblock in README
fba7976 Merge pull request #879 from mathstuf/support-equals-in-proto-path
cadfbc8 Removed handling for ALIASED targets since they are unused.
401e07d Add GOOGLE_ prefix before PROTOBUF_DEPRECATED_ATTR
b60e615 Fix the undefined behavior for opensource users.
6aa981f Merge pull request #1624 from yeswalrus/cmake-prerelease-versioning
dfe0c9a Merge pull request #1643 from yeswalrus/cmake-examples
ed1d560 Merge pull request #1541 from haberman/conformancestrict
350453f Make surrogate regex even more lenient.
923d2c7 JSON surrogates Python: adjust regex for OSX error message.
23fef56 Replace handwritten protobuf-targets with exported version.
09f6a5c Use ExternalProject_Add to build the examples in a stand-alone fashion.
7155629 CMake project updates
6a61894 Added test for surrogates (valid and invalid).
84a1b60 Added update_failure_list.py.
4833b4c Surrogate checking is unpredictable, so always manually check.
bd98eae Fixed Python by updating failure lists and fixed a few broken tests.
ef7894e Make conformance tests more strict about the failure list.
20b5325 Integrate interanl changes
e34c091 Improving the granularity parsing errors (#1623)
0ab7a7f Merge pull request #1640 from os72/master
5977fb0 Generalize plugin support in Bazel Skylark rule
f6be0d1 Add https://github.com/os72/protobuf-dynamic
0420eab For prerelease versions, require protobuf_FIND_VERSION to be set.
f1091ab Include the prerelease version in the protobuf_VERSION
18a9140 Merge pull request #1625 from yeswalrus/note-versions
cc30be1 Merge pull request #1613 from yeswalrus/cmake-min-version
c461193 Merge pull request #1629 from zhongfq/patch-1
a315bb8 Merge pull request #1614 from yeswalrus/cmake-cleanup
e215828 Merge pull request #1630 from google/beta-3
e845187 Merge pull request #1620 from sergiocampama/cleanup1
4629659 add protobuf as3 lib and code generator for as3
457a297 Remove __PROTOBUF_PACKAGE_PREFIX
61c9696 Update the list of places where the version is stored.
a714c40 Removing unused GPBExceptionMessageKey
40ff94e Merge pull request #1617 from thomasvl/more_warnings
86e8f1f Merge pull request #1604 from jonwallg/repeated_types
38b9e74 Add -Woverriding-method-mismatch.
d13b3d0 remove useless cleanup - config.cmake files are executed in their own context.
c57c6ea Bump to the *real* minimum required version. Setting CMP0022 breaks CMake versions < 2.8.12
04265e4 Remove if(TRUE)
e72805e fix expected class checking in GPBSetMessageRepeatedField
0f27cab Merge pull request #1600 from thomasvl/objc_tighter_warnings
ed87c1f Merge pull request #1586 from davidzchen/python
02cd45c Bazel build: Keep generated sources and Python runtime in the same directory.
c8a440d Add more warnings to for the ObjC runtime build
d089f04 Merge pull request #1595 from thomasvl/objc_travis_tweaks
368a2f4 Automated testing tweaks for ObjC
5d0c2ee Merge pull request #1593 from thomasvl/framework_includes
173daf1 Merge pull request #1589 from hochhaus/master
7da023b Better support for using the proto library from a framework.
2131b2d Merge pull request #1588 from jeffmvr/master
7336092 Add js/binary/encoder.js to js_EXTRA_DIST.
733ef98 added missing closing bracket for _cmakedir_desc in cmake/install.cmake line 88
594ce56 Merge pull request #1578 from wal-rus/cmake-install-namespace
28f35b4 add protobuf:: namespace to installed targets
38e4713 Merge pull request #1523 from xfxyjwf/compatibility_tests
a31d14b Describe platform requirements for the compatibility tests.
5c6518f Merge pull request #1583 from thomasvl/pods_integration_followup
2338e03 Merge pull request #1576 from wal-rus/cmake-versionfile
beca1f5 Merge pull request #1575 from wal-rus/cmake-install-msvc
6c47faa Make the CocoaPods integration tests more robust
02a28a8 Update protobuf-config-version.cmake.in to correctly set the required variables (PACKAGE_VERSION_EXACT, PACKAGE_VERSION_COMPATIBLE, PACKAGE_VERSION_UNSUITABLE)
7d79458 Fix the cmake configuration file install path to be more standards compliant (See the description of cmake's config search behavior on https://cmake.org/cmake/help/v3.4/command/find_package.html)
c034ba7 Merge pull request #1574 from thomasvl/test_schemes
20b5bf6 Add shared schemes for the CocoaPods integration tests
12dffd9 Merge pull request #1572 from thomasvl/podspec_tests_2
16dd477 CocoaPod Integration Tests
cc5296b Merge pull request #1558 from haberman/rubyoneof
daec44f Expand the OS X/Xcode gitignores
2d514ce Fixed oneof behavior for enums and fixed JRuby.
b8ded18 Merge pull request #1561 from pherl/beta-3
d550528 Bump objc podspec version number
431ba4b Merge pull request #1549 from xyzzyz/arena_export
ba696e7 Merge pull request #1547 from xyzzyz/js_generator
cbb9183 Merge pull request #1559 from google/beta-3
545527e Ruby oneofs: return default instead of nil for unset fields.
32e3d7a Merge pull request #1412 from google/internal
6673283 Integrate interanl changes
718eb75 Merge pull request #1548 from anandolee/master
97aa8a0 Merge pull request #1551 from pherl/beta-3
fe06eb6 Fix protoc artifact pom version
b01b1a8 JSON format for Any message must print @type first, use OrderedDict instead of {}
4f630a6 Add compatiblity tests against v2.5.0
810ba9b Export class Arena to shared library.
f2885f6 Fix #include in js_generator.cc
67d2d45 Merge pull request #1546 from pherl/beta-3
b3bb46c Added download_url to be able to upload to pypi.
c8be6ee Merge pull request #1542 from google/beta-3
3470b68 Merge pull request #1540 from pherl/changelog
cf1fd7e Merge pull request #1533 from pherl/mapcomment
0ec34bf Update changes for lite
5e7c4cb Remove the comments about iterator validation
f2db1e0 Merge pull request #1532 from pherl/changelog
034867f Update changelogs for C++ maps
dc49706 Merge pull request #1529 from gkraynov/test-redundant-varint
5c29835 Merge pull request #1528 from pherl/master
b126706 Merge pull request #1527 from haberman/changelog
d346f49 Added release notes for Ruby and JavaScript.
ce7e502 Remove the instructions for pbconfig.h
7b87f77 Merge pull request #1521 from zhangkun83/master
04757db Fix the server id in example
9f84114 Merge pull request #1520 from pherl/hashmapvs2008
325cc42 Merge pull request #1522 from xfxyjwf/compatibility_notice
f9fd450 Merge pull request #1524 from anandolee/master
5d54a85 Test redundant varint fields decoding in JS.
371d341 Merge pull request #1518 from jskeet/move_test
e4ca694 python changes
09732c9 Add compatibility notice for Java.
28cb77f Fine-tune build scripts and better documentation.
e1f588a Merge pull request #1 from google/beta-3
71dd9c4 Merge pull request #1515 from pherl/changelog-beta3
ede9cc4 Update comments for csharp, zero-copy and objc.
19472bf Merge pull request #1512 from pherl/beta-3
017d390 Fix csharp version
dbdf6d9 Bridge vs2008 hashmaps.
5668e2e Fix typo.
920ee73 Merge pull request #1483 from wal-rus/fix-boost-incompatibility
7cc9cb4 Move test for standalone BoolValue to JsonParserTest
cca2d44 Merge pull request #1517 from jhickson/boolvalue
835fb94 Fixed parsing of BoolValue.
2b22b61 Merge remote-tracking branch 'refs/remotes/google/master'
c67879b Merge pull request #1514 from pherl/fix_heap_check
0e4d1ea Initial draft for changelog.
e8737d8 Fix the command line interface unittest again
cdd3ec7 Merge pull request #1513 from pherl/fix-build-protoc
25dd690 Fix protoc build artifact script.
5dea201 Update version numbers for other languages
dbed8a0 Update version numbers for beta3
a1938b2 Merge pull request #1510 from thomasvl/nonnull
4755bdc Declare an init and avoid passing NULL to initWithValue:count:
4c6259b Merge pull request #1498 from thomasvl/build_cleanup
f4bc9e0 Remove confounding and unused #define - breaks boost/predef/other/endian.h
d392ed4 Merge pull request #1502 from pherl/master
ce6bec7 Remove accidentally restored deleted files.
9d0f560 Merge pull request #1494 from pherl/master
76a96d4 Merge pull request #1499 from beardedN5rd/master
2eb774e after comment of Feng Xiao changed the entry to g++
ace2690 Merge pull request #1496 from ozkuran/master
b661fb5 Add the missing maintiner-clean entry for benchmarks
ce2ef0d Properly express all outputs for the conformance build
f367642 Add two missing ignores for conformance directory.
b12f630 updated README
9b3357d Updated README.md
5b5e369 Merge pull request #1471 from jskeet/any-host
f8a5c5f Fix using std::shared_ptr
75e5898 Fix the std::string error introduced in integration.
17b6fc3 Merge pull request #1409 from eeight/fix_enum_corruption
72e162c Merge pull request #1482 from nicolasnoble/rake-tweaks-2
edd2949 Properly generating well known proto files for the macos build.
07bcf21 Merge pull request #1464 from google/benchmarks
7dda312 Merge pull request #1473 from nicolasnoble/rake-tweaks
247ef1f Addressed PR comments.
09f1757 Merge pull request #1467 from pherl/master
236b939 Addressing concerns.
e0df23a Update descritpor protos for objc
aed7b34 Merge pull request #1474 from pherl/fixscript
454d5be Merge the script fix.
cf7e99d Fix cp -r usage to be portable.
1f8b6da Few tweaks to the rakefile to permit native gems compilation with the proto files generation.
b2d4b1a Fixed for pre-C++11 ifstream which does not accept std::string.
49a8918 Read files directly from filesystem since xxd isn't always available.
cb36bde Make the C++ tests build the benchmarking code.
1ce5bd8 Updates for PR comments.
61307b8 Allow custom type URL prefixes in Any.Pack
f86d39c Update file lists.
12fdeb9 Merge branch 'master' of github.com:google/protobuf
cf14183 Down integrate from Google internal.
b53417c Merge pull request #1462 from acozzette/ruby-2.3
30a2f70 Added README describing the directory.
2e83110 Added framework for generating/consuming benchmarking data sets.
cbb6b28 Merge pull request #1461 from thomasvl/fix_bool_handing
3064628 Fix up -hash/-isEqual: for bool storage.
bbb68fe Added dig and bsearch_index to RepeatedField methods forwarded to array
f53f911 Merge pull request #1455 from haberman/updateupb
66f0745 Merge pull request #1454 from thomasvl/enum_defaults
18b6a32 Proper checking of enum with non zero default
d419ca1 Updated upb and simplified ruby code a bit with new upb method.
4057447 Merge pull request #1444 from mbrtargeting/master
385755e Add initial design document for Swift protocol buffers. (#1442)
db93833 Added serialVersionUID to ExtendableMessage.
034294b Merge pull request #1438 from xfxyjwf/docs
f4f9aec Fix bug with silent message corruption in LITE_RUNTIME.
0ad2048 Merge pull request #1416 from cwhipkey/master
8052dc7 Add a docs directory and move the third-party add-ons page here.
462e7fa protoc: support '=' in --proto_path arguments
f00300d Merge pull request #1414 from xyzzyz/googletest
1ccb4ca Merge pull request #1434 from jskeet/regenerate
c588ac4 Regenerate well-known types for C#
e539e98 Merge pull request #1433 from thomasvl/check_wkt
511f28b ObjC support for failing the build in the generated WKTs are out of date
f265fb8 Merge pull request #1401 from jskeet/enum-casing
36978c3 Merge pull request #1417 from seishun/windows2
d90d615 Attempt to fix AppVeyor build by exporting GetEnumValueName
790f4c8 Use the original name in JSON formatting.
84ea2c7 Regenerate all C# code and make it compile
75626ed Add C# codegen changes to enum value names (mostly C++)
1dc8194 Merge pull request #1428 from pherl/master
1b0ff34 Add missing includes in field mask test
52825bf Merge pull request #1426 from thomasvl/fix_comment_typo
e664aa6 Regenerate the WKT to pick up current changes to the proto files.
83a7a5e Merge pull request #1402 from davidzchen/py2and3
3633bcd Fix comment typo
072296f Merge pull request #1422 from pherl/master
1f4f3e2 Update file list to include the missing extension lite file.
7ff229f Support Windows in gulpfile.js
ca9bbd7 Merge pull request #1413 from haberman/updateupb
baf52bd Change protobuf CPP proto generator to support the 'lite' option in proto3.
e67ef3d Bugfix for JSON error case.
800e986 Remove no longer applicable documentation from README.md.
194ad62 Ruby JSON: always accept both camelCase and original field names.
1b912fc Remove googletest.h header from stringprintf.cc
90c7f6e Documented the JSON change and compatibility flags.
94e54b3 Updated upb: picked up legacy JSON flags to help Ruby users migrate.
814685c Merge pull request #1397 from google/internal-merge
3c4ce52 Fix for gulpfile.js.
2a197b3 Use 0 as the default value for all enums, rather than finding the actual enum value name
3ffbdd7 Merge pull request #1400 from jskeet/fix-internal
5ebeefb Add missing PY2AND3 srcs_versions attributes to Python Bazel build targets.
0a902ee Fix to csharp_options - initialize internal_access to false.
2cd79bf Removed duplicated operator delete from merge conflict.
4465daa Merge branch 'master' into internal-merge
667f4a6 Merge pull request #1393 from gvaish/master
1523936 Fix for CommonJS tests.
09292d5 Merge pull request #1392 from anandolee/master
a6e3931 Added support for internal_access for C#
cef46e1 Merge pull request #1390 from jskeet/tidy-up
c612074 sync the Manually integrate changes in google3/third_party
28c5c25 Merge pull request #1391 from thomasvl/string_tweaks
f98d2f5 Updating Xcode Settings to use iOS 9.3
2a18bb5 Add more documentation for csharp_options.h
bfd1c84 Line-wrapping changes only for C# generator code
c9167f2 Error during parsing for invalid UTF-8 instead of dropping dropping data.
f3f5b3f Add tests to ensure we read strings with BOMs so we don't forget about lessons of the past.
89719f0 Merge pull request #1349 from gvaish/master
f3fe75b Merge pull request #1386 from andrewharp/patch-2
74d8b0b Added access_level for types
3b4e7dc Update BUILD
b56b461 Do not link in pthread library for Android builds.
a771c9e Merge pull request #852 from qzix/master
268ce28 Added deprecated option handling for objective-c generator
aeacf51 Merge pull request #1381 from pherl/internal-merge
7630a83 Merge branch 'master' into internal-merge
cba75ad Merge branch 'master' of github.com:google/protobuf
89343d8 Do not use C++11 unicode escape in unittest.
452e2b2 Merge pull request #1353 from keveman/master
cf828de Linking the cpp implementation extension statically with libprotobuf
93811ca Do not let windows.h define min/max macros
3b6df06 Allow bigobj for map_unittest
9d7a172 Merge pull request #1377 from jskeet/remove-duplicate-tests
a293180 Merge pull request #1378 from thomasvl/manual_stream_parsing_helpers
331cee5 Add -position and -isAtEnd for use when manually parsing input streams.
46e088e Remove duplicate test cases.
099ff1e Merge pull request #1369 from jskeet/tools-nuspec
203bb5e Fix re-definition issue of winsock.h and winsock2.h
1bf446c Disable sign-compare warning.
7b1cbbd Fix signed-compare warning.
012ac9a revert unexpected change for py26
bc1f2e7 Fix WIN32 build for map_test.
cbfd9d4 Remove export macros for classes nested in a template class.
81eb84c Merge pull request #1371 from keveman/oversize_protos
1283625 Added an API to allow oversize protos when using C++ extension in Python
5805c2d Fix javanano package
fc7eeda Fix json_format.py in py26
5c63266 Merge pull request #1366 from xyzzyz/int128_ostream
94aa50f Fix breakage of referring to table_ in static func
9e7fa06 Temporarily disable begin is fast test.
dfd4760 Remove duplicate line
ca0461c Introduce a new nuget package, Google.Protobuf.Tools, basically to contain protoc on multiple platforms.
a16c8a5 Merge pull request #1362 from jskeet/tweak_json_name
955841e Replace #include <iostream> with #include <ostream>
0de06f5 Merge branch 'master' of github.com:google/protobuf
3b3c8ab Integrate google internal changes.
a25e996 Merge pull request #1360 from pherl/master
34d0cc2 Merge pull request #1295 from haberman/docker
71e8dca Refactoring of FieldDescriptor
261fde1 Merge pull request #1326 from the-alien/csharp_json_name
a15b916 Merge branch 'master' into docker
e164f10 Use the T() instead of NULL for the default value.
af34538 Merge branch 'master' of https://github.com/google/protobuf into csharp_json_name
6f8dd21 Code review fixes
261ee02 Merge pull request #1358 from thomasvl/travis_tweaks
8d47d78 Mark iOS tests as able to fail.
9240acd Merge pull request #1350 from thomasvl/over_release
3f91744 The message was autoreleased, the -releases are an over release.
8126912 Merge pull request #1345 from smparkes/smparkes/well-known-protos
d5a5732 export well known protos
34eeeff Merge pull request #1344 from topillar/patch-1
64dfb5f Update coded_stream.h
698fa8e Merge pull request #1335 from pradeepg26/master
9209136 Merge pull request #1339 from thomasvl/delay_dispatch_semaphore_creation
bd41a39 Only create the readonlySemaphore on demand.
4d98369 Allow custom URLs for Any in JsonFormat
cab5eae Replace ancient m4/acx_pthread.m4 with m4/ax_pthread.m4
0d32ab3 csharp: add support for the json_name option
5e93384 Merge pull request #1325 from thomasvl/shrink_overhead
79a23c4 Shrink ObjC overhead (generated size and some runtime sizes)
ca3dc15 Merge pull request #1318 from smparkes/smparkes/grpc
44fdead Merge pull request #1291 from sergiocampama/devel
9aea0ef Merge pull request #1312 from petewarden/master
a9244ca add java/util support based on java/util/pom.xml
c71f184 Merge pull request #1278 from smparkes/master
dfaf1aa Merge pull request #1317 from benvanik/patch-1
58f0764 Fixing compilation error when building with emscripten.
ea18866 pass correct args to protoc for java wellknown protos when used as an external repository
bc2d6c2 Merge remote-tracking branch 'upstream/master'
f0c1a86 Added iOS settings to Bazel build
48ebb29 Merge pull request #1299 from tatraian/master
e2fb1d9 Comment has been added to fix (issue #1266)
a8db268 Merge pull request #1309 from thomasvl/leading_special_prop_names
1bf4b38 Fix up handing of fields with leading names that should be all caps.
3dd3238 Merge pull request #1306 from silviulica/master
4573edb Update version to 3.0.0b2.post2
6a8815b Merge pull request #1304 from thomasvl/headerdocs
36650a0 HeaderDoc support in the library and generated sources
f2d3408 Merge pull request #1301 from avgweb/master
ad2d775 Replace StringBuilder with TextWriter in JsonFormatter
9242d9b Merge pull request #1298 from craigcitro/fix_setup
3cc35ad Fix compiling clang/libc++ builds. (Issue: #1266)
0e7c0c2 Add back the namespace_packages arg in setup.py.
e70f925 Merge pull request #1139 from haberman/rubyjsoncamel
67c727c Rearranged and commented files for running under Jenkins.
37663e8 Merge pull request #1292 from haberman/ruby-allow-descriptor
35227b4 Removed the generated Ruby file from Makefile.am.
7d793c1 Disable attempt to use ccache for docker build.
2bda98f Properly report C++ build time.
1ee0fda Use a local Maven repository to avoid network fetches during tests.
513875d Generate well-known types in Ruby extension and prune unneeded proto2 dependencies.
b5a35b4 Adds more information to Objective C error when the expected objc_class_prefix option is missing.
2f3f1de Make Java copy into separate directories so the tests can run concurrently.
38bc155 Added code to generate XML output file for more granular results.
ffc8118 Added Ruby 2.1, Oracle Java, and C#.
78f9b68 Upgrade Python packages using pip.
f6153b5 Work around tox bug.
b28b3f6 Configure ccache directory.
d08c39c Put Maven in batch mode to avoid spamming the logs.
483533d Install Python deps in Docker image.
0b931bc Add another test (javanano), but run it in parallel.
0f8c25d Properly add JDK deps in the Docker image.
738393b Try running multiple tests in a row.
d33e93b Added ccache support.
57be1d7 Added some initial shell scripts and docker file.
7810589 Merge pull request #1260 from legrosbuffle/master
584233b Merge pull request #1287 from jskeet/fix-typo
f222a9a Fix copy/paste typo in CodedInputStreamTest
52f62e3 Merge pull request #1274 from murgatroid99/node_relative_requires
9f775a8 Merge pull request #1286 from jskeet/idisposable
c0cf71b Implement IDisposable for CodedInputStream and CodedOutputStream
60a0d41 Merge pull request #1233 from davidzchen/python-path
985c968 Remove hack for building Python support with Bazel.
fb714b3 Merge pull request #1275 from keveman/grpc_support
f5c7363 Fixed grpc C++ plugin support.
c9f8a1b Moved CommonJS-specific files into commonjs directory
a862b6b Fix CommonJS relative require generation, and test it
cc775f7 Merge pull request #1259 from silviulica/master
fc51bdc Merge pull request #1268 from keveman/grpc_support
cb39204 Updated library generation with iOS options
f0966a7 Added grpc plugin support to cc_proto_library.
8f67b16 Merge pull request #1267 from jskeet/vs2015
513a8a6 Merge pull request #804 from bsilver8192/master
4237146 Require VS2015 in the solution file
32daf51 Merge pull request #1215 from haberman/commonjs
24c5424 Added a bit more to README.md, and allowed custom PROTOC var in tests.
894c4d6 Merge pull request #1257 from thomasvl/objc_generics
b3d802d Make cpp generated enum constants constexpr when Options::proto_h is specified.
786f80f Add a modified patch from craigcitro@ to handle namespace sharing.
c003abb Merge pull request #1240 from jskeet/validate_group
4ab9186 Merge pull request #1258 from haberman/releasenotes
81e75c1 Some fixes for the most recent release notes.
f654d49 Updated upb from latest changes.
2480acb Support ObjC Generic Collections
78da666 Changed Ruby to properly camelCase its JSON by default.
907ad4a Properly camelCase when translating to CommonJS.
29d58d3 Removed unused directives from tests that aren't run under CommonJS.
c348af2 Addressed more code review comments.
7726cd2 Integrate review comments.
5195b7f Greatly expanded README.md.
59ea500 Use "node" as binary instead of "nodejs".
35298f9 Fixed definition of extensions, and added CommonJS tests to Travis.
77af5d0 Fixed nested message scopes for CommonJS.
d6a186a Added some documentation in comments.
9e60036 Moved CommonJS-specific files to commonjs/.
e9f31ee CommonJS tests are now passing.
55cc3aa WIP.
9ab11c6 Merge pull request #1255 from thomasvl/mark_os_x_python_cpp_failing
e0dd14c List python_cpp as failing on OS X
507213b Merge pull request #1254 from thomasvl/disable_xctool_updates
8c78450 Disable the xctool updates
abc09f7 Merge pull request #1239 from jskeet/call_generate_protos
c40f8c1 Merge pull request #1229 from keveman/unlimited_binary_proto
61e8e21 Merge pull request #1241 from jskeet/more-merge-wrapper-tests
d41db75 Merge pull request #260 from ejsd1989/issue-#242
8fc045d Merge pull request #1224 from google/rubysentinel
99a3e30 Added PROTOBUF_PYTHON_ALLOW_OVERSIZE_PROTOS macro and setting it when --allow_oversize_protos=true is passed to bazel build. When this macro is set, SetTotalBytesLimit is called to remove the 64MB limit on binary protos when during ParseFromString.
7cf5b81 Merge pull request #1247 from thomasvl/xctool_plain_output
efca368 Move the xctool use of -reporter into a common spot and always use "plain" to get more readable logs on travis.
ee819ea Merge pull request #1245 from thomasvl/tweak_xctool_ios_run
30e645b Tweak the xctool run for iOS tests to try and sort out flake
7d1cc10 Merge pull request #1244 from thomasvl/bump_xcode_version
1324119 Bump up travis to Xcode 7.2
0262e04 Add more tests around merging wrappers
9bdc848 Validate that end-group tags match their corresponding start-group tags
957e877 Generate C# code whenever descriptor.proto changes
69ac430 Removed 'optional' from proto3 syntax file.
fd1c289 Adding missing generic gcc 64-bit atomicops.
ff156e4 Add atomics support for 32-bit PPC.
914605c Removal of null check
a1c5e45 Removal of null check

Change-Id: Id88028efe92b49fd68a02de01e4f991765798c40
git-subtree-dir: third_party/protobuf
git-subtree-split: 48cb18e5c419ddd23d9badcfe4e9df7bde1979b2
diff --git a/php/ext/google/protobuf/array.c b/php/ext/google/protobuf/array.c
new file mode 100644
index 0000000..e69bef4
--- /dev/null
+++ b/php/ext/google/protobuf/array.c
@@ -0,0 +1,545 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// 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.
+
+#include <ext/spl/spl_iterators.h>
+#include <Zend/zend_API.h>
+#include <Zend/zend_interfaces.h>
+
+#include "protobuf.h"
+
+ZEND_BEGIN_ARG_INFO_EX(arginfo_offsetGet, 0, 0, 1)
+  ZEND_ARG_INFO(0, index)
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_INFO_EX(arginfo_offsetSet, 0, 0, 2)
+  ZEND_ARG_INFO(0, index)
+  ZEND_ARG_INFO(0, newval)
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_INFO(arginfo_void, 0)
+ZEND_END_ARG_INFO()
+
+static zend_function_entry repeated_field_methods[] = {
+  PHP_ME(RepeatedField, __construct,  NULL,              ZEND_ACC_PUBLIC)
+  PHP_ME(RepeatedField, append,       NULL,              ZEND_ACC_PUBLIC)
+  PHP_ME(RepeatedField, offsetExists, arginfo_offsetGet, ZEND_ACC_PUBLIC)
+  PHP_ME(RepeatedField, offsetGet,    arginfo_offsetGet, ZEND_ACC_PUBLIC)
+  PHP_ME(RepeatedField, offsetSet,    arginfo_offsetSet, ZEND_ACC_PUBLIC)
+  PHP_ME(RepeatedField, offsetUnset,  arginfo_offsetGet, ZEND_ACC_PUBLIC)
+  PHP_ME(RepeatedField, count,        arginfo_void,      ZEND_ACC_PUBLIC)
+  PHP_ME(RepeatedField, getIterator,  arginfo_void,      ZEND_ACC_PUBLIC)
+  ZEND_FE_END
+};
+
+static zend_function_entry repeated_field_iter_methods[] = {
+  PHP_ME(RepeatedFieldIter, rewind,      arginfo_void, ZEND_ACC_PUBLIC)
+  PHP_ME(RepeatedFieldIter, current,     arginfo_void, ZEND_ACC_PUBLIC)
+  PHP_ME(RepeatedFieldIter, key,         arginfo_void, ZEND_ACC_PUBLIC)
+  PHP_ME(RepeatedFieldIter, next,        arginfo_void, ZEND_ACC_PUBLIC)
+  PHP_ME(RepeatedFieldIter, valid,       arginfo_void, ZEND_ACC_PUBLIC)
+  ZEND_FE_END
+};
+
+// Forward declare static functions.
+
+static int repeated_field_array_init(zval *array, upb_fieldtype_t type,
+                                     uint size ZEND_FILE_LINE_DC);
+static void repeated_field_write_dimension(zval *object, zval *offset,
+                                           zval *value TSRMLS_DC);
+static int repeated_field_has_dimension(zval *object, zval *offset TSRMLS_DC);
+static HashTable *repeated_field_get_gc(zval *object, CACHED_VALUE **table,
+                                        int *n TSRMLS_DC);
+#if PHP_MAJOR_VERSION < 7
+static zend_object_value repeated_field_create(zend_class_entry *ce TSRMLS_DC);
+static zend_object_value repeated_field_iter_create(zend_class_entry *ce TSRMLS_DC);
+#else
+static zend_object *repeated_field_create(zend_class_entry *ce TSRMLS_DC);
+static zend_object *repeated_field_iter_create(zend_class_entry *ce TSRMLS_DC);
+#endif
+
+// -----------------------------------------------------------------------------
+// RepeatedField creation/desctruction
+// -----------------------------------------------------------------------------
+
+zend_class_entry* repeated_field_type;
+zend_class_entry* repeated_field_iter_type;
+zend_object_handlers* repeated_field_handlers;
+zend_object_handlers* repeated_field_iter_handlers;
+
+// Define object free method.
+PHP_PROTO_OBJECT_FREE_START(RepeatedField, repeated_field)
+#if PHP_MAJOR_VERSION < 7
+php_proto_zval_ptr_dtor(intern->array);
+#else
+php_proto_zval_ptr_dtor(&intern->array);
+#endif
+PHP_PROTO_OBJECT_FREE_END
+
+PHP_PROTO_OBJECT_DTOR_START(RepeatedField, repeated_field)
+PHP_PROTO_OBJECT_DTOR_END
+
+// Define object create method.
+PHP_PROTO_OBJECT_CREATE_START(RepeatedField, repeated_field)
+#if PHP_MAJOR_VERSION < 7
+intern->array = NULL;
+#endif
+intern->type = 0;
+intern->msg_ce = NULL;
+PHP_PROTO_OBJECT_CREATE_END(RepeatedField, repeated_field)
+
+// Init class entry.
+PHP_PROTO_INIT_CLASS_START("Google\\Protobuf\\Internal\\RepeatedField",
+                           RepeatedField, repeated_field)
+zend_class_implements(repeated_field_type TSRMLS_CC, 3, spl_ce_ArrayAccess,
+                      zend_ce_aggregate, spl_ce_Countable);
+repeated_field_handlers->write_dimension = repeated_field_write_dimension;
+repeated_field_handlers->get_gc = repeated_field_get_gc;
+PHP_PROTO_INIT_CLASS_END
+
+// Define array element free function.
+#if PHP_MAJOR_VERSION < 7
+static inline void php_proto_array_string_release(void *value) {
+  zval_ptr_dtor(value);
+}
+
+static inline void php_proto_array_object_release(void *value) {
+  zval_ptr_dtor(value);
+}
+static inline void php_proto_array_default_release(void *value) {
+}
+#else
+static inline void php_proto_array_string_release(zval *value) {
+  void* ptr = Z_PTR_P(value);
+  zend_string* object = *(zend_string**)ptr;
+  zend_string_release(object);
+  efree(ptr);
+}
+static inline void php_proto_array_object_release(zval *value) {
+  zval_ptr_dtor(value);
+}
+static void php_proto_array_default_release(zval* value) {
+  void* ptr = Z_PTR_P(value);
+  efree(ptr);
+}
+#endif
+
+static int repeated_field_array_init(zval *array, upb_fieldtype_t type,
+                                     uint size ZEND_FILE_LINE_DC) {
+  PHP_PROTO_ALLOC_ARRAY(array);
+
+  switch (type) {
+    case UPB_TYPE_STRING:
+    case UPB_TYPE_BYTES:
+      zend_hash_init(Z_ARRVAL_P(array), size, NULL,
+                     php_proto_array_string_release, 0);
+      break;
+    case UPB_TYPE_MESSAGE:
+      zend_hash_init(Z_ARRVAL_P(array), size, NULL,
+                     php_proto_array_object_release, 0);
+      break;
+    default:
+      zend_hash_init(Z_ARRVAL_P(array), size, NULL,
+                     php_proto_array_default_release, 0);
+  }
+  return SUCCESS;
+}
+
+// -----------------------------------------------------------------------------
+// RepeatedField Handlers
+// -----------------------------------------------------------------------------
+
+static void repeated_field_write_dimension(zval *object, zval *offset,
+                                           zval *value TSRMLS_DC) {
+  uint64_t index;
+
+  RepeatedField *intern = UNBOX(RepeatedField, object);
+  HashTable *ht = PHP_PROTO_HASH_OF(intern->array);
+  int size = native_slot_size(intern->type);
+
+  unsigned char memory[NATIVE_SLOT_MAX_SIZE];
+  memset(memory, 0, NATIVE_SLOT_MAX_SIZE);
+
+  if (!native_slot_set_by_array(intern->type, intern->msg_ce, memory,
+                                value TSRMLS_CC)) {
+    return;
+  }
+
+  if (!offset || Z_TYPE_P(offset) == IS_NULL) {
+    index = zend_hash_num_elements(PHP_PROTO_HASH_OF(intern->array));
+  } else {
+    if (protobuf_convert_to_uint64(offset, &index)) {
+      if (!zend_hash_index_exists(ht, index)) {
+        zend_error(E_USER_ERROR, "Element at %llu doesn't exist.\n",
+                   (long long unsigned int)index);
+        return;
+      }
+    } else {
+      return;
+    }
+  }
+
+  if (intern->type == UPB_TYPE_MESSAGE) {
+    php_proto_zend_hash_index_update_zval(ht, index, *(zval**)memory);
+  } else {
+    php_proto_zend_hash_index_update_mem(ht, index, memory, size, NULL);
+  }
+}
+
+#if PHP_MAJOR_VERSION < 7
+static HashTable *repeated_field_get_gc(zval *object, zval ***table,
+                                        int *n TSRMLS_DC) {
+#else
+static HashTable *repeated_field_get_gc(zval *object, zval **table, int *n) {
+#endif
+  *table = NULL;
+  *n = 0;
+  RepeatedField *intern = UNBOX(RepeatedField, object);
+  return PHP_PROTO_HASH_OF(intern->array);
+}
+
+// -----------------------------------------------------------------------------
+// C RepeatedField Utilities
+// -----------------------------------------------------------------------------
+
+void *repeated_field_index_native(RepeatedField *intern, int index TSRMLS_DC) {
+  HashTable *ht = PHP_PROTO_HASH_OF(intern->array);
+  void *value;
+
+  if (intern->type == UPB_TYPE_MESSAGE) {
+    if (php_proto_zend_hash_index_find_zval(ht, index, (void **)&value) ==
+        FAILURE) {
+      zend_error(E_USER_ERROR, "Element at %d doesn't exist.\n", index);
+      return NULL;
+    }
+  } else {
+    if (php_proto_zend_hash_index_find_mem(ht, index, (void **)&value) ==
+        FAILURE) {
+      zend_error(E_USER_ERROR, "Element at %d doesn't exist.\n", index);
+      return NULL;
+    }
+  }
+
+  return value;
+}
+
+void repeated_field_push_native(RepeatedField *intern, void *value) {
+  HashTable *ht = PHP_PROTO_HASH_OF(intern->array);
+  int size = native_slot_size(intern->type);
+  if (intern->type == UPB_TYPE_MESSAGE) {
+    php_proto_zend_hash_next_index_insert_zval(ht, value);
+  } else {
+    php_proto_zend_hash_next_index_insert_mem(ht, (void **)value, size, NULL);
+  }
+}
+
+void repeated_field_create_with_field(
+    zend_class_entry *ce, const upb_fielddef *field,
+    CACHED_VALUE *repeated_field PHP_PROTO_TSRMLS_DC) {
+  upb_fieldtype_t type = upb_fielddef_type(field);
+  const zend_class_entry *msg_ce = field_type_class(field PHP_PROTO_TSRMLS_CC);
+  repeated_field_create_with_type(ce, type, msg_ce,
+                                  repeated_field PHP_PROTO_TSRMLS_CC);
+}
+
+void repeated_field_create_with_type(
+    zend_class_entry *ce, upb_fieldtype_t type, const zend_class_entry *msg_ce,
+    CACHED_VALUE *repeated_field PHP_PROTO_TSRMLS_DC) {
+  CREATE_OBJ_ON_ALLOCATED_ZVAL_PTR(CACHED_PTR_TO_ZVAL_PTR(repeated_field),
+                                   repeated_field_type);
+
+  RepeatedField *intern =
+      UNBOX(RepeatedField, CACHED_TO_ZVAL_PTR(*repeated_field));
+  intern->type = type;
+  intern->msg_ce = msg_ce;
+#if PHP_MAJOR_VERSION < 7
+  MAKE_STD_ZVAL(intern->array);
+  repeated_field_array_init(intern->array, intern->type, 0 ZEND_FILE_LINE_CC);
+#else
+  repeated_field_array_init(&intern->array, intern->type, 0 ZEND_FILE_LINE_CC);
+#endif
+
+  // TODO(teboring): Link class entry for message and enum
+}
+
+
+// -----------------------------------------------------------------------------
+// PHP RepeatedField Methods
+// -----------------------------------------------------------------------------
+
+/**
+ * Constructs an instance of RepeatedField.
+ * @param long Type of the stored element.
+ * @param string Message/Enum class name (message/enum fields only).
+ */
+PHP_METHOD(RepeatedField, __construct) {
+  long type;
+  zend_class_entry* klass = NULL;
+
+  if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l|C", &type, &klass) ==
+      FAILURE) {
+    return;
+  }
+
+  RepeatedField *intern = UNBOX(RepeatedField, getThis());
+  intern->type = to_fieldtype(type);
+  intern->msg_ce = klass;
+
+#if PHP_MAJOR_VERSION < 7
+  MAKE_STD_ZVAL(intern->array);
+  repeated_field_array_init(intern->array, intern->type, 0 ZEND_FILE_LINE_CC);
+#else
+  repeated_field_array_init(&intern->array, intern->type, 0 ZEND_FILE_LINE_CC);
+#endif
+
+  if (intern->type == UPB_TYPE_MESSAGE && klass == NULL) {
+    zend_error(E_USER_ERROR, "Message type must have concrete class.");
+    return;
+  }
+
+  // TODO(teboring): Consider enum.
+}
+
+/**
+ * Append element to the end of the repeated field.
+ * @param object The element to be added.
+ */
+PHP_METHOD(RepeatedField, append) {
+  zval *value;
+
+  if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &value) ==
+      FAILURE) {
+    return;
+  }
+  repeated_field_write_dimension(getThis(), NULL, value TSRMLS_CC);
+}
+
+/**
+ * Check whether the element at given index exists.
+ * @param long The index to be checked.
+ * @return bool True if the element at the given index exists.
+ */
+PHP_METHOD(RepeatedField, offsetExists) {
+  long index;
+
+  if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &index) ==
+      FAILURE) {
+    return;
+  }
+
+  RepeatedField *intern = UNBOX(RepeatedField, getThis());
+
+  RETURN_BOOL(index >= 0 &&
+              index < zend_hash_num_elements(PHP_PROTO_HASH_OF(intern->array)));
+}
+
+/**
+ * Return the element at the given index.
+ * This will also be called for: $ele = $arr[0]
+ * @param long The index of the element to be fetched.
+ * @return object The stored element at given index.
+ * @exception Invalid type for index.
+ * @exception Non-existing index.
+ */
+PHP_METHOD(RepeatedField, offsetGet) {
+  long index;
+  void *memory;
+
+  if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &index) ==
+      FAILURE) {
+    return;
+  }
+
+  RepeatedField *intern = UNBOX(RepeatedField, getThis());
+  HashTable *table = PHP_PROTO_HASH_OF(intern->array);
+
+  if (intern->type == UPB_TYPE_MESSAGE) {
+    if (php_proto_zend_hash_index_find_zval(table, index, (void **)&memory) ==
+        FAILURE) {
+      zend_error(E_USER_ERROR, "Element at %ld doesn't exist.\n", index);
+      return;
+    }
+  } else {
+    if (php_proto_zend_hash_index_find_mem(table, index, (void **)&memory) ==
+        FAILURE) {
+      zend_error(E_USER_ERROR, "Element at %ld doesn't exist.\n", index);
+      return;
+    }
+  }
+  native_slot_get_by_array(intern->type, memory,
+                           ZVAL_PTR_TO_CACHED_PTR(return_value) TSRMLS_CC);
+}
+
+/**
+ * Assign the element at the given index.
+ * This will also be called for: $arr []= $ele and $arr[0] = ele
+ * @param long The index of the element to be assigned.
+ * @param object The element to be assigned.
+ * @exception Invalid type for index.
+ * @exception Non-existing index.
+ * @exception Incorrect type of the element.
+ */
+PHP_METHOD(RepeatedField, offsetSet) {
+  zval *index, *value;
+  if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "zz", &index, &value) ==
+      FAILURE) {
+    return;
+  }
+  repeated_field_write_dimension(getThis(), index, value TSRMLS_CC);
+}
+
+/**
+ * Remove the element at the given index.
+ * This will also be called for: unset($arr)
+ * @param long The index of the element to be removed.
+ * @exception Invalid type for index.
+ * @exception The element to be removed is not at the end of the RepeatedField.
+ */
+PHP_METHOD(RepeatedField, offsetUnset) {
+  long index;
+  if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &index) ==
+      FAILURE) {
+    return;
+  }
+
+  RepeatedField *intern = UNBOX(RepeatedField, getThis());
+
+  // Only the element at the end of the array can be removed.
+  if (index == -1 ||
+      index != (zend_hash_num_elements(PHP_PROTO_HASH_OF(intern->array)) - 1)) {
+    zend_error(E_USER_ERROR, "Cannot remove element at %ld.\n", index);
+    return;
+  }
+
+  zend_hash_index_del(PHP_PROTO_HASH_OF(intern->array), index);
+}
+
+/**
+ * Return the number of stored elements.
+ * This will also be called for: count($arr)
+ * @return long The number of stored elements.
+ */
+PHP_METHOD(RepeatedField, count) {
+  RepeatedField *intern = UNBOX(RepeatedField, getThis());
+
+  if (zend_parse_parameters_none() == FAILURE) {
+    return;
+  }
+
+  RETURN_LONG(zend_hash_num_elements(PHP_PROTO_HASH_OF(intern->array)));
+}
+
+/**
+ * Return the beginning iterator.
+ * This will also be called for: foreach($arr)
+ * @return object Beginning iterator.
+ */
+PHP_METHOD(RepeatedField, getIterator) {
+  CREATE_OBJ_ON_ALLOCATED_ZVAL_PTR(return_value,
+                                   repeated_field_iter_type);
+
+  RepeatedField *intern = UNBOX(RepeatedField, getThis());
+  RepeatedFieldIter *iter = UNBOX(RepeatedFieldIter, return_value);
+  iter->repeated_field = intern;
+  iter->position = 0;
+}
+
+// -----------------------------------------------------------------------------
+// RepeatedFieldIter creation/desctruction
+// -----------------------------------------------------------------------------
+
+// Define object free method.
+PHP_PROTO_OBJECT_FREE_START(RepeatedFieldIter, repeated_field_iter)
+PHP_PROTO_OBJECT_FREE_END
+
+PHP_PROTO_OBJECT_DTOR_START(RepeatedFieldIter, repeated_field_iter)
+PHP_PROTO_OBJECT_DTOR_END
+
+// Define object create method.
+PHP_PROTO_OBJECT_CREATE_START(RepeatedFieldIter, repeated_field_iter)
+intern->repeated_field = NULL;
+intern->position = 0;
+PHP_PROTO_OBJECT_CREATE_END(RepeatedFieldIter, repeated_field_iter)
+
+// Init class entry.
+PHP_PROTO_INIT_CLASS_START("Google\\Protobuf\\Internal\\RepeatedFieldIter",
+                           RepeatedFieldIter, repeated_field_iter)
+zend_class_implements(repeated_field_iter_type TSRMLS_CC, 1, zend_ce_iterator);
+PHP_PROTO_INIT_CLASS_END
+
+// -----------------------------------------------------------------------------
+// PHP RepeatedFieldIter Methods
+// -----------------------------------------------------------------------------
+
+PHP_METHOD(RepeatedFieldIter, rewind) {
+  RepeatedFieldIter *intern = UNBOX(RepeatedFieldIter, getThis());
+  intern->position = 0;
+}
+
+PHP_METHOD(RepeatedFieldIter, current) {
+  RepeatedFieldIter *intern = UNBOX(RepeatedFieldIter, getThis());
+  RepeatedField *repeated_field = intern->repeated_field;
+
+  long index;
+  void *memory;
+
+  HashTable *table = PHP_PROTO_HASH_OF(repeated_field->array);
+
+  if (repeated_field->type == UPB_TYPE_MESSAGE) {
+    if (php_proto_zend_hash_index_find_zval(table, intern->position,
+                                            (void **)&memory) == FAILURE) {
+      zend_error(E_USER_ERROR, "Element at %d doesn't exist.\n", index);
+      return;
+    }
+  } else {
+    if (php_proto_zend_hash_index_find_mem(table, intern->position,
+                                           (void **)&memory) == FAILURE) {
+      zend_error(E_USER_ERROR, "Element at %d doesn't exist.\n", index);
+      return;
+    }
+  }
+  native_slot_get_by_array(repeated_field->type, memory,
+                           ZVAL_PTR_TO_CACHED_PTR(return_value) TSRMLS_CC);
+}
+
+PHP_METHOD(RepeatedFieldIter, key) {
+  RepeatedFieldIter *intern = UNBOX(RepeatedFieldIter, getThis());
+  RETURN_LONG(intern->position);
+}
+
+PHP_METHOD(RepeatedFieldIter, next) {
+  RepeatedFieldIter *intern = UNBOX(RepeatedFieldIter, getThis());
+  ++intern->position;
+}
+
+PHP_METHOD(RepeatedFieldIter, valid) {
+  RepeatedFieldIter *intern = UNBOX(RepeatedFieldIter, getThis());
+  RETURN_BOOL(zend_hash_num_elements(PHP_PROTO_HASH_OF(
+                  intern->repeated_field->array)) > intern->position);
+}
diff --git a/php/ext/google/protobuf/config.m4 b/php/ext/google/protobuf/config.m4
new file mode 100644
index 0000000..ab032e4
--- /dev/null
+++ b/php/ext/google/protobuf/config.m4
@@ -0,0 +1,10 @@
+PHP_ARG_ENABLE(protobuf, whether to enable Protobuf extension, [  --enable-protobuf   Enable Protobuf extension])
+
+if test "$PHP_PROTOBUF" != "no"; then
+
+  PHP_NEW_EXTENSION(
+    protobuf,
+    array.c def.c encode_decode.c map.c message.c protobuf.c storage.c type_check.c upb.c utf8.c,
+    $ext_shared)
+
+fi
diff --git a/php/ext/google/protobuf/def.c b/php/ext/google/protobuf/def.c
new file mode 100644
index 0000000..238a924
--- /dev/null
+++ b/php/ext/google/protobuf/def.c
@@ -0,0 +1,1076 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// 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.
+
+#include "protobuf.h"
+
+// Forward declare.
+static void descriptor_init_c_instance(Descriptor* intern TSRMLS_DC);
+static void descriptor_free_c(Descriptor* object TSRMLS_DC);
+
+static void field_descriptor_init_c_instance(FieldDescriptor* intern TSRMLS_DC);
+static void field_descriptor_free_c(FieldDescriptor* object TSRMLS_DC);
+
+static void enum_descriptor_init_c_instance(EnumDescriptor* intern TSRMLS_DC);
+static void enum_descriptor_free_c(EnumDescriptor* object TSRMLS_DC);
+
+static void enum_value_descriptor_init_c_instance(
+    EnumValueDescriptor *intern TSRMLS_DC);
+static void enum_value_descriptor_free_c(EnumValueDescriptor *object TSRMLS_DC);
+
+static void descriptor_pool_free_c(DescriptorPool* object TSRMLS_DC);
+static void descriptor_pool_init_c_instance(DescriptorPool* pool TSRMLS_DC);
+
+static void internal_descriptor_pool_free_c(
+    InternalDescriptorPool *object TSRMLS_DC);
+static void internal_descriptor_pool_init_c_instance(
+    InternalDescriptorPool *pool TSRMLS_DC);
+
+static void oneof_descriptor_free_c(Oneof* object TSRMLS_DC);
+static void oneof_descriptor_init_c_instance(Oneof* pool TSRMLS_DC);
+
+// -----------------------------------------------------------------------------
+// Common Utilities
+// -----------------------------------------------------------------------------
+
+static void check_upb_status(const upb_status* status, const char* msg) {
+  if (!upb_ok(status)) {
+    zend_error(E_ERROR, "%s: %s\n", msg, upb_status_errmsg(status));
+  }
+}
+
+static void upb_filedef_free(void *r) {
+  upb_filedef *f = *(upb_filedef **)r;
+  size_t i;
+
+  for (i = 0; i < upb_filedef_depcount(f); i++) {
+    upb_filedef_unref(upb_filedef_dep(f, i), f);
+  }
+
+  upb_inttable_uninit(&f->defs);
+  upb_inttable_uninit(&f->deps);
+  upb_gfree((void *)f->name);
+  upb_gfree((void *)f->package);
+  upb_gfree(f);
+}
+
+// Camel-case the field name and append "Entry" for generated map entry name.
+// e.g. map<KeyType, ValueType> foo_map => FooMapEntry
+static void append_map_entry_name(char *result, const char *field_name,
+                                  int pos) {
+  bool cap_next = true;
+  int i;
+
+  for (i = 0; i < strlen(field_name); ++i) {
+    if (field_name[i] == '_') {
+      cap_next = true;
+    } else if (cap_next) {
+      // Note: Do not use ctype.h due to locales.
+      if ('a' <= field_name[i] && field_name[i] <= 'z') {
+        result[pos++] = field_name[i] - 'a' + 'A';
+      } else {
+        result[pos++] = field_name[i];
+      }
+      cap_next = false;
+    } else {
+      result[pos++] = field_name[i];
+    }
+  }
+  strcat(result, "Entry");
+}
+
+#define CHECK_UPB(code, msg)             \
+  do {                                   \
+    upb_status status = UPB_STATUS_INIT; \
+    code;                                \
+    check_upb_status(&status, msg);      \
+  } while (0)
+
+// -----------------------------------------------------------------------------
+// GPBType
+// -----------------------------------------------------------------------------
+
+zend_class_entry* gpb_type_type;
+
+static zend_function_entry gpb_type_methods[] = {
+  ZEND_FE_END
+};
+
+void gpb_type_init(TSRMLS_D) {
+  zend_class_entry class_type;
+  INIT_CLASS_ENTRY(class_type, "Google\\Protobuf\\Internal\\GPBType",
+                   gpb_type_methods);
+  gpb_type_type = zend_register_internal_class(&class_type TSRMLS_CC);
+  zend_declare_class_constant_long(gpb_type_type, STR("DOUBLE"),  1 TSRMLS_CC);
+  zend_declare_class_constant_long(gpb_type_type, STR("FLOAT"),   2 TSRMLS_CC);
+  zend_declare_class_constant_long(gpb_type_type, STR("INT64"),   3 TSRMLS_CC);
+  zend_declare_class_constant_long(gpb_type_type, STR("UINT64"),  4 TSRMLS_CC);
+  zend_declare_class_constant_long(gpb_type_type, STR("INT32"),   5 TSRMLS_CC);
+  zend_declare_class_constant_long(gpb_type_type, STR("FIXED64"), 6 TSRMLS_CC);
+  zend_declare_class_constant_long(gpb_type_type, STR("FIXED32"), 7 TSRMLS_CC);
+  zend_declare_class_constant_long(gpb_type_type, STR("BOOL"),    8 TSRMLS_CC);
+  zend_declare_class_constant_long(gpb_type_type, STR("STRING"),  9 TSRMLS_CC);
+  zend_declare_class_constant_long(gpb_type_type, STR("GROUP"),   10 TSRMLS_CC);
+  zend_declare_class_constant_long(gpb_type_type, STR("MESSAGE"), 11 TSRMLS_CC);
+  zend_declare_class_constant_long(gpb_type_type, STR("BYTES"),   12 TSRMLS_CC);
+  zend_declare_class_constant_long(gpb_type_type, STR("UINT32"),  13 TSRMLS_CC);
+  zend_declare_class_constant_long(gpb_type_type, STR("ENUM"),    14 TSRMLS_CC);
+  zend_declare_class_constant_long(gpb_type_type, STR("SFIXED32"),
+                                   15 TSRMLS_CC);
+  zend_declare_class_constant_long(gpb_type_type, STR("SFIXED64"),
+                                   16 TSRMLS_CC);
+  zend_declare_class_constant_long(gpb_type_type, STR("SINT32"), 17 TSRMLS_CC);
+  zend_declare_class_constant_long(gpb_type_type, STR("SINT64"), 18 TSRMLS_CC);
+}
+
+// -----------------------------------------------------------------------------
+// Descriptor
+// -----------------------------------------------------------------------------
+
+static zend_function_entry descriptor_methods[] = {
+  PHP_ME(Descriptor, getClass, NULL, ZEND_ACC_PUBLIC)
+  PHP_ME(Descriptor, getFullName, NULL, ZEND_ACC_PUBLIC)
+  PHP_ME(Descriptor, getField, NULL, ZEND_ACC_PUBLIC)
+  PHP_ME(Descriptor, getFieldCount, NULL, ZEND_ACC_PUBLIC)
+  PHP_ME(Descriptor, getOneofDecl, NULL, ZEND_ACC_PUBLIC)
+  PHP_ME(Descriptor, getOneofDeclCount, NULL, ZEND_ACC_PUBLIC)
+  ZEND_FE_END
+};
+
+DEFINE_CLASS(Descriptor, descriptor, "Google\\Protobuf\\Descriptor");
+
+static void descriptor_free_c(Descriptor *self TSRMLS_DC) {
+  if (self->layout) {
+    free_layout(self->layout);
+  }
+  if (self->fill_handlers) {
+    upb_handlers_unref(self->fill_handlers, &self->fill_handlers);
+  }
+  if (self->fill_method) {
+    upb_pbdecodermethod_unref(self->fill_method, &self->fill_method);
+  }
+  if (self->json_fill_method) {
+    upb_json_parsermethod_unref(self->json_fill_method,
+                                &self->json_fill_method);
+  }
+  if (self->pb_serialize_handlers) {
+    upb_handlers_unref(self->pb_serialize_handlers,
+                       &self->pb_serialize_handlers);
+  }
+  if (self->json_serialize_handlers) {
+    upb_handlers_unref(self->json_serialize_handlers,
+                       &self->json_serialize_handlers);
+  }
+  if (self->json_serialize_handlers_preserve) {
+    upb_handlers_unref(self->json_serialize_handlers_preserve,
+                       &self->json_serialize_handlers_preserve);
+  }
+}
+
+static void descriptor_init_c_instance(Descriptor *desc TSRMLS_DC) {
+  desc->msgdef = NULL;
+  desc->layout = NULL;
+  desc->klass = NULL;
+  desc->fill_handlers = NULL;
+  desc->fill_method = NULL;
+  desc->json_fill_method = NULL;
+  desc->pb_serialize_handlers = NULL;
+  desc->json_serialize_handlers = NULL;
+  desc->json_serialize_handlers_preserve = NULL;
+}
+
+PHP_METHOD(Descriptor, getClass) {
+  Descriptor *intern = UNBOX(Descriptor, getThis());
+#if PHP_MAJOR_VERSION < 7
+  const char* classname = intern->klass->name;
+#else
+  const char* classname = ZSTR_VAL(intern->klass->name);
+#endif
+  PHP_PROTO_RETVAL_STRINGL(classname, strlen(classname), 1);
+}
+
+PHP_METHOD(Descriptor, getFullName) {
+  Descriptor *intern = UNBOX(Descriptor, getThis());
+  const char* fullname = upb_msgdef_fullname(intern->msgdef);
+  PHP_PROTO_RETVAL_STRINGL(fullname, strlen(fullname), 1);
+}
+
+PHP_METHOD(Descriptor, getField) {
+  long index;
+  if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &index) ==
+      FAILURE) {
+    zend_error(E_USER_ERROR, "Expect integer for index.\n");
+    return;
+  }
+
+  Descriptor *intern = UNBOX(Descriptor, getThis());
+  int field_num = upb_msgdef_numfields(intern->msgdef);
+  if (index < 0 || index >= field_num) {
+    zend_error(E_USER_ERROR, "Cannot get element at %ld.\n", index);
+    return;
+  }
+
+  upb_msg_field_iter iter;
+  int i;
+  for(upb_msg_field_begin(&iter, intern->msgdef), i = 0;
+      !upb_msg_field_done(&iter) && i < index;
+      upb_msg_field_next(&iter), i++);
+  const upb_fielddef *field = upb_msg_iter_field(&iter);
+
+  PHP_PROTO_HASHTABLE_VALUE field_hashtable_value = get_def_obj(field);
+  if (field_hashtable_value == NULL) {
+#if PHP_MAJOR_VERSION < 7
+    MAKE_STD_ZVAL(field_hashtable_value);
+    ZVAL_OBJ(field_hashtable_value, field_descriptor_type->create_object(
+                                        field_descriptor_type TSRMLS_CC));
+    Z_DELREF_P(field_hashtable_value);
+#else
+    field_hashtable_value =
+        field_descriptor_type->create_object(field_descriptor_type TSRMLS_CC);
+    GC_DELREF(field_hashtable_value);
+#endif
+    FieldDescriptor *field_php =
+        UNBOX_HASHTABLE_VALUE(FieldDescriptor, field_hashtable_value);
+    field_php->fielddef = field;
+    add_def_obj(field, field_hashtable_value);
+  }
+
+#if PHP_MAJOR_VERSION < 7
+  RETURN_ZVAL(field_hashtable_value, 1, 0);
+#else
+  GC_ADDREF(field_hashtable_value);
+  RETURN_OBJ(field_hashtable_value);
+#endif
+}
+
+PHP_METHOD(Descriptor, getFieldCount) {
+  Descriptor *intern = UNBOX(Descriptor, getThis());
+  RETURN_LONG(upb_msgdef_numfields(intern->msgdef));
+}
+
+PHP_METHOD(Descriptor, getOneofDecl) {
+  long index;
+  if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &index) ==
+      FAILURE) {
+    zend_error(E_USER_ERROR, "Expect integer for index.\n");
+    return;
+  }
+
+  Descriptor *intern = UNBOX(Descriptor, getThis());
+  int field_num = upb_msgdef_numoneofs(intern->msgdef);
+  if (index < 0 || index >= field_num) {
+    zend_error(E_USER_ERROR, "Cannot get element at %ld.\n", index);
+    return;
+  }
+
+  upb_msg_oneof_iter iter;
+  int i;
+  for(upb_msg_oneof_begin(&iter, intern->msgdef), i = 0;
+      !upb_msg_oneof_done(&iter) && i < index;
+      upb_msg_oneof_next(&iter), i++);
+  upb_oneofdef *oneof = upb_msg_iter_oneof(&iter);
+
+  ZVAL_OBJ(return_value, oneof_descriptor_type->create_object(
+                             oneof_descriptor_type TSRMLS_CC));
+  Oneof *oneof_php = UNBOX(Oneof, return_value);
+  oneof_php->oneofdef = oneof;
+}
+
+PHP_METHOD(Descriptor, getOneofDeclCount) {
+  Descriptor *intern = UNBOX(Descriptor, getThis());
+  RETURN_LONG(upb_msgdef_numoneofs(intern->msgdef));
+}
+
+// -----------------------------------------------------------------------------
+// EnumDescriptor
+// -----------------------------------------------------------------------------
+
+static zend_function_entry enum_descriptor_methods[] = {
+  PHP_ME(EnumDescriptor, getValue, NULL, ZEND_ACC_PUBLIC)
+  PHP_ME(EnumDescriptor, getValueCount, NULL, ZEND_ACC_PUBLIC)
+  ZEND_FE_END
+};
+
+DEFINE_CLASS(EnumDescriptor, enum_descriptor,
+             "Google\\Protobuf\\EnumDescriptor");
+
+static void enum_descriptor_free_c(EnumDescriptor *self TSRMLS_DC) {
+}
+
+static void enum_descriptor_init_c_instance(EnumDescriptor *self TSRMLS_DC) {
+  self->enumdef = NULL;
+  self->klass = NULL;
+}
+
+PHP_METHOD(EnumDescriptor, getValue) {
+  long index;
+  if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &index) ==
+      FAILURE) {
+    zend_error(E_USER_ERROR, "Expect integer for index.\n");
+    return;
+  }
+
+  EnumDescriptor *intern = UNBOX(EnumDescriptor, getThis());
+  int field_num = upb_enumdef_numvals(intern->enumdef);
+  if (index < 0 || index >= field_num) {
+    zend_error(E_USER_ERROR, "Cannot get element at %ld.\n", index);
+    return;
+  }
+
+  upb_enum_iter iter;
+  int i;
+  for(upb_enum_begin(&iter, intern->enumdef), i = 0;
+      !upb_enum_done(&iter) && i < index;
+      upb_enum_next(&iter), i++);
+
+  ZVAL_OBJ(return_value, enum_value_descriptor_type->create_object(
+                             enum_value_descriptor_type TSRMLS_CC));
+  EnumValueDescriptor *enum_value_php =
+      UNBOX(EnumValueDescriptor, return_value);
+  enum_value_php->name = upb_enum_iter_name(&iter);
+  enum_value_php->number = upb_enum_iter_number(&iter);
+}
+
+PHP_METHOD(EnumDescriptor, getValueCount) {
+  EnumDescriptor *intern = UNBOX(EnumDescriptor, getThis());
+  RETURN_LONG(upb_enumdef_numvals(intern->enumdef));
+}
+
+// -----------------------------------------------------------------------------
+// EnumValueDescriptor
+// -----------------------------------------------------------------------------
+
+static zend_function_entry enum_value_descriptor_methods[] = {
+  PHP_ME(EnumValueDescriptor, getName, NULL, ZEND_ACC_PUBLIC)
+  PHP_ME(EnumValueDescriptor, getNumber, NULL, ZEND_ACC_PUBLIC)
+  ZEND_FE_END
+};
+
+DEFINE_CLASS(EnumValueDescriptor, enum_value_descriptor,
+             "Google\\Protobuf\\EnumValueDescriptor");
+
+static void enum_value_descriptor_free_c(EnumValueDescriptor *self TSRMLS_DC) {
+}
+
+static void enum_value_descriptor_init_c_instance(EnumValueDescriptor *self TSRMLS_DC) {
+  self->name = NULL;
+  self->number = 0;
+}
+
+PHP_METHOD(EnumValueDescriptor, getName) {
+  EnumValueDescriptor *intern = UNBOX(EnumValueDescriptor, getThis());
+  PHP_PROTO_RETVAL_STRINGL(intern->name, strlen(intern->name), 1);
+}
+
+PHP_METHOD(EnumValueDescriptor, getNumber) {
+  EnumValueDescriptor *intern = UNBOX(EnumValueDescriptor, getThis());
+  RETURN_LONG(intern->number);
+}
+
+// -----------------------------------------------------------------------------
+// FieldDescriptor
+// -----------------------------------------------------------------------------
+
+static zend_function_entry field_descriptor_methods[] = {
+  PHP_ME(FieldDescriptor, getName,   NULL, ZEND_ACC_PUBLIC)
+  PHP_ME(FieldDescriptor, getNumber, NULL, ZEND_ACC_PUBLIC)
+  PHP_ME(FieldDescriptor, getLabel,  NULL, ZEND_ACC_PUBLIC)
+  PHP_ME(FieldDescriptor, getType,   NULL, ZEND_ACC_PUBLIC)
+  PHP_ME(FieldDescriptor, isMap,     NULL, ZEND_ACC_PUBLIC)
+  PHP_ME(FieldDescriptor, getEnumType, NULL, ZEND_ACC_PUBLIC)
+  PHP_ME(FieldDescriptor, getMessageType, NULL, ZEND_ACC_PUBLIC)
+  ZEND_FE_END
+};
+
+DEFINE_CLASS(FieldDescriptor, field_descriptor,
+             "Google\\Protobuf\\FieldDescriptor");
+
+static void field_descriptor_free_c(FieldDescriptor *self TSRMLS_DC) {
+}
+
+static void field_descriptor_init_c_instance(FieldDescriptor *self TSRMLS_DC) {
+  self->fielddef = NULL;
+}
+
+upb_fieldtype_t to_fieldtype(upb_descriptortype_t type) {
+  switch (type) {
+#define CASE(descriptor_type, type)           \
+  case UPB_DESCRIPTOR_TYPE_##descriptor_type: \
+    return UPB_TYPE_##type;
+
+  CASE(FLOAT,    FLOAT);
+  CASE(DOUBLE,   DOUBLE);
+  CASE(BOOL,     BOOL);
+  CASE(STRING,   STRING);
+  CASE(BYTES,    BYTES);
+  CASE(MESSAGE,  MESSAGE);
+  CASE(GROUP,    MESSAGE);
+  CASE(ENUM,     ENUM);
+  CASE(INT32,    INT32);
+  CASE(INT64,    INT64);
+  CASE(UINT32,   UINT32);
+  CASE(UINT64,   UINT64);
+  CASE(SINT32,   INT32);
+  CASE(SINT64,   INT64);
+  CASE(FIXED32,  UINT32);
+  CASE(FIXED64,  UINT64);
+  CASE(SFIXED32, INT32);
+  CASE(SFIXED64, INT64);
+
+#undef CONVERT
+
+  }
+
+  zend_error(E_ERROR, "Unknown field type.");
+  return 0;
+}
+
+PHP_METHOD(FieldDescriptor, getName) {
+  FieldDescriptor *intern = UNBOX(FieldDescriptor, getThis());
+  const char* name = upb_fielddef_name(intern->fielddef);
+  PHP_PROTO_RETVAL_STRINGL(name, strlen(name), 1);
+}
+
+PHP_METHOD(FieldDescriptor, getNumber) {
+  FieldDescriptor *intern = UNBOX(FieldDescriptor, getThis());
+  RETURN_LONG(upb_fielddef_number(intern->fielddef));
+}
+
+PHP_METHOD(FieldDescriptor, getLabel) {
+  FieldDescriptor *intern = UNBOX(FieldDescriptor, getThis());
+  RETURN_LONG(upb_fielddef_label(intern->fielddef));
+}
+
+PHP_METHOD(FieldDescriptor, getType) {
+  FieldDescriptor *intern = UNBOX(FieldDescriptor, getThis());
+  RETURN_LONG(upb_fielddef_descriptortype(intern->fielddef));
+}
+
+PHP_METHOD(FieldDescriptor, isMap) {
+  FieldDescriptor *intern = UNBOX(FieldDescriptor, getThis());
+  RETURN_BOOL(upb_fielddef_ismap(intern->fielddef));
+}
+
+PHP_METHOD(FieldDescriptor, getEnumType) {
+  FieldDescriptor *intern = UNBOX(FieldDescriptor, getThis());
+  const upb_enumdef *enumdef = upb_fielddef_enumsubdef(intern->fielddef);
+  if (enumdef == NULL) {
+    char error_msg[100];
+    sprintf(error_msg, "Cannot get enum type for non-enum field '%s'",
+            upb_fielddef_name(intern->fielddef));
+    zend_throw_exception(NULL, error_msg, 0 TSRMLS_CC);
+    return;
+  }
+  PHP_PROTO_HASHTABLE_VALUE desc = get_def_obj(enumdef);
+
+#if PHP_MAJOR_VERSION < 7
+  RETURN_ZVAL(desc, 1, 0);
+#else
+  GC_ADDREF(desc);
+  RETURN_OBJ(desc);
+#endif
+}
+
+PHP_METHOD(FieldDescriptor, getMessageType) {
+  FieldDescriptor *intern = UNBOX(FieldDescriptor, getThis());
+  const upb_msgdef *msgdef = upb_fielddef_msgsubdef(intern->fielddef);
+  if (msgdef == NULL) {
+    char error_msg[100];
+    sprintf(error_msg, "Cannot get message type for non-message field '%s'",
+            upb_fielddef_name(intern->fielddef));
+    zend_throw_exception(NULL, error_msg, 0 TSRMLS_CC);
+    return;
+  }
+  PHP_PROTO_HASHTABLE_VALUE desc = get_def_obj(msgdef);
+
+#if PHP_MAJOR_VERSION < 7
+  RETURN_ZVAL(desc, 1, 0);
+#else
+  GC_ADDREF(desc);
+  RETURN_OBJ(desc);
+#endif
+}
+
+// -----------------------------------------------------------------------------
+// Oneof
+// -----------------------------------------------------------------------------
+
+static zend_function_entry oneof_descriptor_methods[] = {
+  PHP_ME(Oneof, getName,  NULL, ZEND_ACC_PUBLIC)
+  PHP_ME(Oneof, getField, NULL, ZEND_ACC_PUBLIC)
+  PHP_ME(Oneof, getFieldCount, NULL, ZEND_ACC_PUBLIC)
+  ZEND_FE_END
+};
+
+DEFINE_CLASS(Oneof, oneof_descriptor,
+             "Google\\Protobuf\\OneofDescriptor");
+
+static void oneof_descriptor_free_c(Oneof *self TSRMLS_DC) {
+}
+
+static void oneof_descriptor_init_c_instance(Oneof *self TSRMLS_DC) {
+  self->oneofdef = NULL;
+}
+
+PHP_METHOD(Oneof, getName) {
+  Oneof *intern = UNBOX(Oneof, getThis());
+  const char *name = upb_oneofdef_name(intern->oneofdef);
+  PHP_PROTO_RETVAL_STRINGL(name, strlen(name), 1);
+}
+
+PHP_METHOD(Oneof, getField) {
+  long index;
+  if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &index) ==
+      FAILURE) {
+    zend_error(E_USER_ERROR, "Expect integer for index.\n");
+    return;
+  }
+
+  Oneof *intern = UNBOX(Oneof, getThis());
+  int field_num = upb_oneofdef_numfields(intern->oneofdef);
+  if (index < 0 || index >= field_num) {
+    zend_error(E_USER_ERROR, "Cannot get element at %ld.\n", index);
+    return;
+  }
+
+  upb_oneof_iter iter;
+  int i;
+  for(upb_oneof_begin(&iter, intern->oneofdef), i = 0;
+      !upb_oneof_done(&iter) && i < index;
+      upb_oneof_next(&iter), i++);
+  const upb_fielddef *field = upb_oneof_iter_field(&iter);
+
+  PHP_PROTO_HASHTABLE_VALUE field_hashtable_value = get_def_obj(field);
+  if (field_hashtable_value == NULL) {
+#if PHP_MAJOR_VERSION < 7
+    MAKE_STD_ZVAL(field_hashtable_value);
+    ZVAL_OBJ(field_hashtable_value, field_descriptor_type->create_object(
+                                        field_descriptor_type TSRMLS_CC));
+#else
+    field_hashtable_value =
+        field_descriptor_type->create_object(field_descriptor_type TSRMLS_CC);
+#endif
+    FieldDescriptor *field_php =
+        UNBOX_HASHTABLE_VALUE(FieldDescriptor, field_hashtable_value);
+    field_php->fielddef = field;
+    add_def_obj(field, field_hashtable_value);
+  }
+
+#if PHP_MAJOR_VERSION < 7
+  RETURN_ZVAL(field_hashtable_value, 1, 0);
+#else
+  GC_ADDREF(field_hashtable_value);
+  RETURN_OBJ(field_hashtable_value);
+#endif
+}
+
+PHP_METHOD(Oneof, getFieldCount) {
+  Oneof *intern = UNBOX(Oneof, getThis());
+  RETURN_LONG(upb_oneofdef_numfields(intern->oneofdef));
+}
+
+// -----------------------------------------------------------------------------
+// DescriptorPool
+// -----------------------------------------------------------------------------
+
+static zend_function_entry descriptor_pool_methods[] = {
+  PHP_ME(DescriptorPool, getGeneratedPool, NULL,
+         ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
+  PHP_ME(DescriptorPool, getDescriptorByClassName, NULL, ZEND_ACC_PUBLIC)
+  PHP_ME(DescriptorPool, getEnumDescriptorByClassName, NULL, ZEND_ACC_PUBLIC)
+  ZEND_FE_END
+};
+
+static zend_function_entry internal_descriptor_pool_methods[] = {
+  PHP_ME(InternalDescriptorPool, getGeneratedPool, NULL,
+         ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
+  PHP_ME(InternalDescriptorPool, internalAddGeneratedFile, NULL, ZEND_ACC_PUBLIC)
+  ZEND_FE_END
+};
+
+DEFINE_CLASS(DescriptorPool, descriptor_pool,
+             "Google\\Protobuf\\DescriptorPool");
+DEFINE_CLASS(InternalDescriptorPool, internal_descriptor_pool,
+             "Google\\Protobuf\\Internal\\DescriptorPool");
+
+// wrapper of generated pool
+#if PHP_MAJOR_VERSION < 7
+zval* generated_pool_php;
+zval* internal_generated_pool_php;
+#else
+zend_object *generated_pool_php;
+zend_object *internal_generated_pool_php;
+#endif
+InternalDescriptorPool *generated_pool;  // The actual generated pool
+
+void init_generated_pool_once(TSRMLS_D) {
+  if (generated_pool == NULL) {
+#if PHP_MAJOR_VERSION < 7
+    MAKE_STD_ZVAL(generated_pool_php);
+    MAKE_STD_ZVAL(internal_generated_pool_php);
+    ZVAL_OBJ(internal_generated_pool_php,
+             internal_descriptor_pool_type->create_object(
+                 internal_descriptor_pool_type TSRMLS_CC));
+    generated_pool = UNBOX(InternalDescriptorPool, internal_generated_pool_php);
+    ZVAL_OBJ(generated_pool_php, descriptor_pool_type->create_object(
+                                     descriptor_pool_type TSRMLS_CC));
+#else
+    internal_generated_pool_php = internal_descriptor_pool_type->create_object(
+        internal_descriptor_pool_type TSRMLS_CC);
+    generated_pool = (InternalDescriptorPool *)((char *)internal_generated_pool_php -
+                                        XtOffsetOf(InternalDescriptorPool, std));
+    generated_pool_php =
+        descriptor_pool_type->create_object(descriptor_pool_type TSRMLS_CC);
+#endif
+  }
+}
+
+static void internal_descriptor_pool_init_c_instance(
+    InternalDescriptorPool *pool TSRMLS_DC) {
+  pool->symtab = upb_symtab_new();
+
+  ALLOC_HASHTABLE(pool->pending_list);
+  zend_hash_init(pool->pending_list, 1, NULL, ZVAL_PTR_DTOR, 0);
+}
+
+static void internal_descriptor_pool_free_c(
+    InternalDescriptorPool *pool TSRMLS_DC) {
+  upb_symtab_free(pool->symtab);
+
+  zend_hash_destroy(pool->pending_list);
+  FREE_HASHTABLE(pool->pending_list);
+}
+
+static void descriptor_pool_init_c_instance(DescriptorPool *pool TSRMLS_DC) {
+  assert(generated_pool != NULL);
+  pool->intern = generated_pool;
+}
+
+static void descriptor_pool_free_c(DescriptorPool *pool TSRMLS_DC) {
+}
+
+static void validate_enumdef(const upb_enumdef *enumdef) {
+  // Verify that an entry exists with integer value 0. (This is the default
+  // value.)
+  const char *lookup = upb_enumdef_iton(enumdef, 0);
+  if (lookup == NULL) {
+    zend_error(E_USER_ERROR,
+               "Enum definition does not contain a value for '0'.");
+  }
+}
+
+static void validate_msgdef(const upb_msgdef* msgdef) {
+  // Verify that no required fields exist. proto3 does not support these.
+  upb_msg_field_iter it;
+  for (upb_msg_field_begin(&it, msgdef);
+       !upb_msg_field_done(&it);
+       upb_msg_field_next(&it)) {
+    const upb_fielddef* field = upb_msg_iter_field(&it);
+    if (upb_fielddef_label(field) == UPB_LABEL_REQUIRED) {
+      zend_error(E_ERROR, "Required fields are unsupported in proto3.");
+    }
+  }
+}
+
+PHP_METHOD(DescriptorPool, getGeneratedPool) {
+  init_generated_pool_once(TSRMLS_C);
+#if PHP_MAJOR_VERSION < 7
+  RETURN_ZVAL(generated_pool_php, 1, 0);
+#else
+  GC_ADDREF(generated_pool_php);
+  RETURN_OBJ(generated_pool_php);
+#endif
+}
+
+PHP_METHOD(InternalDescriptorPool, getGeneratedPool) {
+  init_generated_pool_once(TSRMLS_C);
+#if PHP_MAJOR_VERSION < 7
+  RETURN_ZVAL(internal_generated_pool_php, 1, 0);
+#else
+  GC_ADDREF(internal_generated_pool_php);
+  RETURN_OBJ(internal_generated_pool_php);
+#endif
+}
+
+static size_t classname_len_max(const char *fullname,
+                                const char *package,
+                                const char *php_namespace,
+                                const char *prefix) {
+  size_t fullname_len = strlen(fullname);
+  size_t package_len = 0;
+  size_t prefix_len = 0;
+  size_t namespace_len = 0;
+  size_t length = fullname_len;
+  int i, segment, classname_start = 0;
+
+  if (package != NULL) {
+    package_len = strlen(package);
+  }
+  if (prefix != NULL) {
+    prefix_len = strlen(prefix);
+  }
+  if (php_namespace != NULL) {
+    namespace_len = strlen(php_namespace);
+  }
+
+  // Process package
+  if (package_len > 0) {
+    segment = 1;
+    for (i = 0; i < package_len; i++) {
+      if (package[i] == '.') {
+        segment++;
+      }
+    }
+    // In case of reserved name in package.
+    length += 3 * segment;
+
+    classname_start = package_len + 1;
+  }
+
+  // Process class name
+  segment = 1;
+  for (i = classname_start; i < fullname_len; i++) {
+    if (fullname[i] == '.') {
+      segment++;
+    }
+  }
+  if (prefix_len == 0) {
+    length += 3 * segment;
+  } else {
+    length += prefix_len * segment;
+  }
+
+  // The additional 2, one is for preceding '.' and the other is for trailing 0.
+  return length + namespace_len + 2;
+}
+
+static bool is_reserved(const char *segment, int length) {
+  bool result;
+  char* lower = ALLOC_N(char, length + 1);
+  memset(lower, 0, length + 1);
+  memcpy(lower, segment, length);
+  int i = 0;
+  while(lower[i]) {
+    lower[i] = (char)tolower(lower[i]);
+    i++;
+  }
+  lower[length] = 0;
+  result = is_reserved_name(lower);
+  FREE(lower);
+  return result;
+}
+
+static char* fill_prefix(const char *segment, int length,
+                         const char *prefix_given,
+                         const char *package_name, char *classname) {
+  size_t i;
+
+  if (prefix_given != NULL && strcmp(prefix_given, "") != 0) {
+    size_t prefix_len = strlen(prefix_given);
+    memcpy(classname, prefix_given, strlen(prefix_given));
+    classname += prefix_len;
+  } else {
+    if (is_reserved(segment, length)) {
+      if (package_name != NULL &&
+          strcmp("google.protobuf", package_name) == 0) {
+        memcpy(classname, "GPB", 3);
+        classname += 3;
+      } else {
+        memcpy(classname, "PB", 2);
+        classname += 2;
+      }
+    }
+  }
+  return classname;
+}
+
+static char* fill_segment(const char *segment, int length,
+                          char *classname, bool use_camel) {
+  memcpy(classname, segment, length);
+  if (use_camel && (segment[0] < 'A' || segment[0] > 'Z')) {
+    classname[0] += 'A' - 'a';
+  }
+  return classname + length;
+}
+
+static char* fill_namespace(const char *package, const char *namespace_given,
+                            char *classname) {
+  if (namespace_given != NULL) {
+    size_t namespace_len = strlen(namespace_given);
+    memcpy(classname, namespace_given, namespace_len);
+    classname += namespace_len;
+    *classname = '\\';
+    classname++;
+  } else if (package != NULL) {
+    int i = 0, j, offset = 0;
+    size_t package_len = strlen(package);
+    while (i < package_len) {
+      j = i;
+      while (j < package_len && package[j] != '.') {
+        j++;
+      }
+      classname = fill_prefix(package + i, j - i, "", package, classname);
+      classname = fill_segment(package + i, j - i, classname, true);
+      classname[0] = '\\';
+      classname++;
+      i = j + 1;
+    }
+  }
+  return classname;
+}
+
+static char* fill_classname(const char *fullname,
+                            const char *package,
+                            const char *namespace_given,
+                            const char *prefix, char *classname) {
+  int classname_start = 0;
+  if (package != NULL) {
+    size_t package_len = strlen(package);
+    classname_start = package_len == 0 ? 0 : package_len + 1;
+  }
+  size_t fullname_len = strlen(fullname);
+  classname = fill_prefix(fullname + classname_start,
+                          fullname_len - classname_start,
+                          prefix, package, classname);
+
+  int i = classname_start, j;
+  while (i < fullname_len) {
+    j = i;
+    while (j < fullname_len && fullname[j] != '.') {
+      j++;
+    }
+    classname = fill_segment(fullname + i, j - i, classname, false);
+    if (j != fullname_len) {
+      *classname = '_';
+      classname++;
+    }
+    i = j + 1;
+  }
+  return classname;
+}
+
+static char* fill_qualified_classname(const char *fullname,
+                                      const char *package,
+                                      const char *namespace_given,
+                                      const char *prefix, char *classname) {
+  classname = fill_namespace(package, namespace_given, classname);
+  return fill_classname(fullname, package, namespace_given, prefix, classname);
+}
+
+static void classname_no_prefix(const char *fullname, const char *package_name,
+                                char *class_name) {
+  size_t i = 0, j;
+  bool first_char = true, is_reserved = false;
+  size_t pkg_name_len = package_name == NULL ? 0 : strlen(package_name);
+  size_t message_name_start = package_name == NULL ? 0 : pkg_name_len + 1;
+  size_t message_len = (strlen(fullname) - message_name_start);
+
+  // Submessage is concatenated with its containing messages by '_'.
+  for (j = message_name_start; j < message_name_start + message_len; j++) {
+    if (fullname[j] == '.') {
+      class_name[i++] = '_';
+    } else {
+      class_name[i++] = fullname[j];
+    }
+  }
+}
+
+void internal_add_generated_file(const char *data, PHP_PROTO_SIZE data_len,
+                                 InternalDescriptorPool *pool TSRMLS_DC) {
+  upb_filedef **files;
+  size_t i;
+
+  CHECK_UPB(files = upb_loaddescriptor(data, data_len, &pool, &status),
+            "Parse binary descriptors to internal descriptors failed");
+
+  // This method is called only once in each file.
+  assert(files[0] != NULL);
+  assert(files[1] == NULL);
+
+  CHECK_UPB(upb_symtab_addfile(pool->symtab, files[0], &status),
+            "Unable to add file to DescriptorPool");
+
+  // For each enum/message, we need its PHP class, upb descriptor and its PHP
+  // wrapper. These information are needed later for encoding, decoding and type
+  // checking. However, sometimes we just have one of them. In order to find
+  // them quickly, here, we store the mapping for them.
+  for (i = 0; i < upb_filedef_defcount(files[0]); i++) {
+    const upb_def *def = upb_filedef_def(files[0], i);
+    switch (upb_def_type(def)) {
+#define CASE_TYPE(def_type, def_type_lower, desc_type, desc_type_lower)        \
+  case UPB_DEF_##def_type: {                                                   \
+    CREATE_HASHTABLE_VALUE(desc, desc_php, desc_type, desc_type_lower##_type); \
+    const upb_##def_type_lower *def_type_lower =                               \
+        upb_downcast_##def_type_lower(def);                                    \
+    desc->def_type_lower = def_type_lower;                                     \
+    add_def_obj(desc->def_type_lower, desc_php);                               \
+    /* Unlike other messages, MapEntry is shared by all map fields and doesn't \
+     * have generated PHP class.*/                                             \
+    if (upb_def_type(def) == UPB_DEF_MSG &&                                    \
+        upb_msgdef_mapentry(upb_downcast_msgdef(def))) {                       \
+      break;                                                                   \
+    }                                                                          \
+    /* Prepend '.' to package name to make it absolute. In the 5 additional    \
+     * bytes allocated, one for '.', one for trailing 0, and 3 for 'GPB' if    \
+     * given message is google.protobuf.Empty.*/                               \
+    const char *fullname = upb_##def_type_lower##_fullname(def_type_lower);    \
+    const char *package = upb_filedef_package(files[0]);                       \
+    const char *php_namespace = upb_filedef_phpnamespace(files[0]);            \
+    const char *prefix_given = upb_filedef_phpprefix(files[0]);                \
+    size_t classname_len = classname_len_max(fullname, package,                \
+                                             php_namespace, prefix_given);     \
+    char *classname = ecalloc(sizeof(char), classname_len);                    \
+    fill_qualified_classname(fullname, package, php_namespace,                 \
+                             prefix_given, classname);                         \
+    PHP_PROTO_CE_DECLARE pce;                                                  \
+    if (php_proto_zend_lookup_class(classname, strlen(classname), &pce) ==     \
+        FAILURE) {                                                             \
+      zend_error(E_ERROR, "Generated message class %s hasn't been defined",    \
+                 classname);                                                   \
+      return;                                                                  \
+    } else {                                                                   \
+      desc->klass = PHP_PROTO_CE_UNREF(pce);                                   \
+    }                                                                          \
+    add_ce_obj(desc->klass, desc_php);                                         \
+    add_proto_obj(upb_##def_type_lower##_fullname(desc->def_type_lower),       \
+                  desc_php);                                                   \
+    efree(classname);                                                          \
+    break;                                                                     \
+  }
+
+      CASE_TYPE(MSG, msgdef, Descriptor, descriptor)
+      CASE_TYPE(ENUM, enumdef, EnumDescriptor, enum_descriptor)
+#undef CASE_TYPE
+
+      default:
+        break;
+    }
+  }
+
+  for (i = 0; i < upb_filedef_defcount(files[0]); i++) {
+    const upb_def *def = upb_filedef_def(files[0], i);
+    if (upb_def_type(def) == UPB_DEF_MSG) {
+      const upb_msgdef *msgdef = upb_downcast_msgdef(def);
+      PHP_PROTO_HASHTABLE_VALUE desc_php = get_def_obj(msgdef);
+      build_class_from_descriptor(desc_php TSRMLS_CC);
+    }
+  }
+
+  upb_filedef_unref(files[0], &pool);
+  upb_gfree(files);
+}
+
+PHP_METHOD(InternalDescriptorPool, internalAddGeneratedFile) {
+  char *data = NULL;
+  PHP_PROTO_SIZE data_len;
+  upb_filedef **files;
+  size_t i;
+
+  if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &data, &data_len) ==
+      FAILURE) {
+    return;
+  }
+
+  InternalDescriptorPool *pool = UNBOX(InternalDescriptorPool, getThis());
+  internal_add_generated_file(data, data_len, pool TSRMLS_CC);
+}
+
+PHP_METHOD(DescriptorPool, getDescriptorByClassName) {
+  DescriptorPool *public_pool = UNBOX(DescriptorPool, getThis());
+  InternalDescriptorPool *pool = public_pool->intern;
+
+  char *classname = NULL;
+  PHP_PROTO_SIZE classname_len;
+
+  if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &classname,
+                            &classname_len) == FAILURE) {
+    return;
+  }
+
+  PHP_PROTO_CE_DECLARE pce;
+  if (php_proto_zend_lookup_class(classname, classname_len, &pce) ==
+      FAILURE) {
+    RETURN_NULL();
+  }
+
+  PHP_PROTO_HASHTABLE_VALUE desc = get_ce_obj(PHP_PROTO_CE_UNREF(pce));
+  if (desc == NULL) {
+    RETURN_NULL();
+  }
+
+  zend_class_entry* instance_ce = HASHTABLE_VALUE_CE(desc);
+
+  if (!instanceof_function(instance_ce, descriptor_type TSRMLS_CC)) {
+    RETURN_NULL();
+  }
+
+#if PHP_MAJOR_VERSION < 7
+  RETURN_ZVAL(desc, 1, 0);
+#else
+  GC_ADDREF(desc);
+  RETURN_OBJ(desc);
+#endif
+}
+
+PHP_METHOD(DescriptorPool, getEnumDescriptorByClassName) {
+  DescriptorPool *public_pool = UNBOX(DescriptorPool, getThis());
+  InternalDescriptorPool *pool = public_pool->intern;
+
+  char *classname = NULL;
+  PHP_PROTO_SIZE classname_len;
+
+  if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &classname,
+                            &classname_len) == FAILURE) {
+    return;
+  }
+
+  PHP_PROTO_CE_DECLARE pce;
+  if (php_proto_zend_lookup_class(classname, classname_len, &pce) ==
+      FAILURE) {
+    RETURN_NULL();
+  }
+
+  PHP_PROTO_HASHTABLE_VALUE desc = get_ce_obj(PHP_PROTO_CE_UNREF(pce));
+  if (desc == NULL) {
+    RETURN_NULL();
+  }
+
+  zend_class_entry* instance_ce = HASHTABLE_VALUE_CE(desc);
+
+  if (!instanceof_function(instance_ce, enum_descriptor_type TSRMLS_CC)) {
+    RETURN_NULL();
+  }
+
+#if PHP_MAJOR_VERSION < 7
+  RETURN_ZVAL(desc, 1, 0);
+#else
+  GC_ADDREF(desc);
+  RETURN_OBJ(desc);
+#endif
+}
diff --git a/php/ext/google/protobuf/encode_decode.c b/php/ext/google/protobuf/encode_decode.c
new file mode 100644
index 0000000..de13dfa
--- /dev/null
+++ b/php/ext/google/protobuf/encode_decode.c
@@ -0,0 +1,1715 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// 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.
+
+#include "protobuf.h"
+#include "utf8.h"
+
+/* stringsink *****************************************************************/
+
+typedef struct {
+  upb_byteshandler handler;
+  upb_bytessink sink;
+  char *ptr;
+  size_t len, size;
+} stringsink;
+
+
+static void *stringsink_start(void *_sink, const void *hd, size_t size_hint) {
+  stringsink *sink = _sink;
+  sink->len = 0;
+  return sink;
+}
+
+static size_t stringsink_string(void *_sink, const void *hd, const char *ptr,
+                                size_t len, const upb_bufhandle *handle) {
+  stringsink *sink = _sink;
+  size_t new_size = sink->size;
+
+  UPB_UNUSED(hd);
+  UPB_UNUSED(handle);
+
+  while (sink->len + len > new_size) {
+    new_size *= 2;
+  }
+
+  if (new_size != sink->size) {
+    sink->ptr = realloc(sink->ptr, new_size);
+    sink->size = new_size;
+  }
+
+  memcpy(sink->ptr + sink->len, ptr, len);
+  sink->len += len;
+
+  return len;
+}
+
+void stringsink_init(stringsink *sink) {
+  upb_byteshandler_init(&sink->handler);
+  upb_byteshandler_setstartstr(&sink->handler, stringsink_start, NULL);
+  upb_byteshandler_setstring(&sink->handler, stringsink_string, NULL);
+
+  upb_bytessink_reset(&sink->sink, &sink->handler, sink);
+
+  sink->size = 32;
+  sink->ptr = malloc(sink->size);
+  sink->len = 0;
+}
+
+void stringsink_uninit(stringsink *sink) { free(sink->ptr); }
+
+/* stackenv *****************************************************************/
+
+// Stack-allocated context during an encode/decode operation. Contains the upb
+// environment and its stack-based allocator, an initial buffer for allocations
+// to avoid malloc() when possible, and a template for PHP exception messages
+// if any error occurs.
+#define STACK_ENV_STACKBYTES 4096
+typedef struct {
+  upb_env env;
+  const char *php_error_template;
+  char allocbuf[STACK_ENV_STACKBYTES];
+} stackenv;
+
+
+static void stackenv_init(stackenv* se, const char* errmsg);
+static void stackenv_uninit(stackenv* se);
+
+// Callback invoked by upb if any error occurs during parsing or serialization.
+static bool env_error_func(void* ud, const upb_status* status) {
+    char err_msg[100] = "";
+    stackenv* se = ud;
+    // Free the env -- zend_error will longjmp up the stack past the
+    // encode/decode function so it would not otherwise have been freed.
+    stackenv_uninit(se);
+
+    // TODO(teboring): have a way to verify that this is actually a parse error,
+    // instead of just throwing "parse error" unconditionally.
+    sprintf(err_msg, se->php_error_template, upb_status_errmsg(status));
+    TSRMLS_FETCH();
+    zend_throw_exception(NULL, err_msg, 0 TSRMLS_CC);
+    // Never reached.
+    return false;
+}
+
+static void stackenv_init(stackenv* se, const char* errmsg) {
+  se->php_error_template = errmsg;
+  upb_env_init2(&se->env, se->allocbuf, sizeof(se->allocbuf), NULL);
+  upb_env_seterrorfunc(&se->env, env_error_func, se);
+}
+
+static void stackenv_uninit(stackenv* se) {
+  upb_env_uninit(&se->env);
+}
+
+// -----------------------------------------------------------------------------
+// Parsing.
+// -----------------------------------------------------------------------------
+
+#define DEREF(msg, ofs, type) *(type*)(((uint8_t *)msg) + ofs)
+
+// Creates a handlerdata that simply contains the offset for this field.
+static const void* newhandlerdata(upb_handlers* h, uint32_t ofs) {
+  size_t* hd_ofs = (size_t*)malloc(sizeof(size_t));
+  *hd_ofs = ofs;
+  upb_handlers_addcleanup(h, hd_ofs, free);
+  return hd_ofs;
+}
+
+typedef size_t (*encodeunknown_handlerfunc)(void* _sink, const void* hd,
+                                            const char* ptr, size_t len,
+                                            const upb_bufhandle* handle);
+
+typedef struct {
+  encodeunknown_handlerfunc handler;
+} unknownfields_handlerdata_t;
+
+// Creates a handlerdata for unknown fields.
+static const void *newunknownfieldshandlerdata(upb_handlers* h) {
+  unknownfields_handlerdata_t* hd =
+      (unknownfields_handlerdata_t*)malloc(sizeof(unknownfields_handlerdata_t));
+  hd->handler = stringsink_string;
+  upb_handlers_addcleanup(h, hd, free);
+  return hd;
+}
+
+typedef struct {
+  size_t ofs;
+  const upb_msgdef *md;
+} submsg_handlerdata_t;
+
+// Creates a handlerdata that contains offset and submessage type information.
+static const void *newsubmsghandlerdata(upb_handlers* h, uint32_t ofs,
+                                        const upb_fielddef* f) {
+  submsg_handlerdata_t* hd =
+      (submsg_handlerdata_t*)malloc(sizeof(submsg_handlerdata_t));
+  hd->ofs = ofs;
+  hd->md = upb_fielddef_msgsubdef(f);
+  upb_handlers_addcleanup(h, hd, free);
+  return hd;
+}
+
+typedef struct {
+  size_t ofs;              // union data slot
+  size_t case_ofs;         // oneof_case field
+  int property_ofs;        // properties table cache
+  uint32_t oneof_case_num; // oneof-case number to place in oneof_case field
+  const upb_msgdef *md;    // msgdef, for oneof submessage handler
+  const upb_msgdef *parent_md;  // msgdef, for parent submessage
+} oneof_handlerdata_t;
+
+static const void *newoneofhandlerdata(upb_handlers *h,
+                                       uint32_t ofs,
+                                       uint32_t case_ofs,
+                                       int property_ofs,
+                                       const upb_msgdef *m,
+                                       const upb_fielddef *f) {
+  oneof_handlerdata_t* hd =
+      (oneof_handlerdata_t*)malloc(sizeof(oneof_handlerdata_t));
+  hd->ofs = ofs;
+  hd->case_ofs = case_ofs;
+  hd->property_ofs = property_ofs;
+  hd->parent_md = m;
+  // We reuse the field tag number as a oneof union discriminant tag. Note that
+  // we don't expose these numbers to the user, so the only requirement is that
+  // we have some unique ID for each union case/possibility. The field tag
+  // numbers are already present and are easy to use so there's no reason to
+  // create a separate ID space. In addition, using the field tag number here
+  // lets us easily look up the field in the oneof accessor.
+  hd->oneof_case_num = upb_fielddef_number(f);
+  if (upb_fielddef_type(f) == UPB_TYPE_MESSAGE) {
+    hd->md = upb_fielddef_msgsubdef(f);
+  } else {
+    hd->md = NULL;
+  }
+  upb_handlers_addcleanup(h, hd, free);
+  return hd;
+}
+
+// A handler that starts a repeated field.  Gets the Repeated*Field instance for
+// this field (such an instance always exists even in an empty message).
+static void *startseq_handler(void* closure, const void* hd) {
+  MessageHeader* msg = closure;
+  const size_t *ofs = hd;
+  return CACHED_PTR_TO_ZVAL_PTR(DEREF(message_data(msg), *ofs, CACHED_VALUE*));
+}
+
+// Handlers that append primitive values to a repeated field.
+#define DEFINE_APPEND_HANDLER(type, ctype)                          \
+  static bool append##type##_handler(void* closure, const void* hd, \
+                                     ctype val) {                   \
+    zval* array = (zval*)closure;                                   \
+    TSRMLS_FETCH();                                                 \
+    RepeatedField* intern = UNBOX(RepeatedField, array);            \
+    repeated_field_push_native(intern, &val);                       \
+    return true;                                                    \
+  }
+
+DEFINE_APPEND_HANDLER(bool,   bool)
+DEFINE_APPEND_HANDLER(int32,  int32_t)
+DEFINE_APPEND_HANDLER(uint32, uint32_t)
+DEFINE_APPEND_HANDLER(float,  float)
+DEFINE_APPEND_HANDLER(int64,  int64_t)
+DEFINE_APPEND_HANDLER(uint64, uint64_t)
+DEFINE_APPEND_HANDLER(double, double)
+
+// Appends a string to a repeated field.
+static void* appendstr_handler(void *closure,
+                               const void *hd,
+                               size_t size_hint) {
+  zval* array = (zval*)closure;
+  TSRMLS_FETCH();
+  RepeatedField* intern = UNBOX(RepeatedField, array);
+
+#if PHP_MAJOR_VERSION < 7
+  zval* str;
+  MAKE_STD_ZVAL(str);
+  PHP_PROTO_ZVAL_STRING(str, "", 1);
+  repeated_field_push_native(intern, &str);
+  return (void*)str;
+#else
+  zend_string* str = zend_string_init("", 0, 1);
+  repeated_field_push_native(intern, &str);
+  return intern;
+#endif
+}
+
+// Appends a 'bytes' string to a repeated field.
+static void* appendbytes_handler(void *closure,
+                                 const void *hd,
+                                 size_t size_hint) {
+  zval* array = (zval*)closure;
+  TSRMLS_FETCH();
+  RepeatedField* intern = UNBOX(RepeatedField, array);
+
+#if PHP_MAJOR_VERSION < 7
+  zval* str;
+  MAKE_STD_ZVAL(str);
+  PHP_PROTO_ZVAL_STRING(str, "", 1);
+  repeated_field_push_native(intern, &str);
+  return (void*)str;
+#else
+  zend_string* str = zend_string_init("", 0, 1);
+  repeated_field_push_native(intern, &str);
+  return intern;
+#endif
+}
+
+// Handlers that append primitive values to a repeated field.
+#define DEFINE_SINGULAR_HANDLER(type, ctype)                \
+  static bool type##_handler(void* closure, const void* hd, \
+                                     ctype val) {           \
+    MessageHeader* msg = (MessageHeader*)closure;           \
+    const size_t *ofs = hd;                                 \
+    DEREF(message_data(msg), *ofs, ctype) = val;            \
+    return true;                                            \
+  }
+
+DEFINE_SINGULAR_HANDLER(bool,   bool)
+DEFINE_SINGULAR_HANDLER(int32,  int32_t)
+DEFINE_SINGULAR_HANDLER(uint32, uint32_t)
+DEFINE_SINGULAR_HANDLER(float,  float)
+DEFINE_SINGULAR_HANDLER(int64,  int64_t)
+DEFINE_SINGULAR_HANDLER(uint64, uint64_t)
+DEFINE_SINGULAR_HANDLER(double, double)
+
+#undef DEFINE_SINGULAR_HANDLER
+
+#if PHP_MAJOR_VERSION < 7
+static void *empty_php_string(zval** value_ptr) {
+  SEPARATE_ZVAL_IF_NOT_REF(value_ptr);
+  if (Z_TYPE_PP(value_ptr) == IS_STRING &&
+      !IS_INTERNED(Z_STRVAL_PP(value_ptr))) {
+    FREE(Z_STRVAL_PP(value_ptr));
+  }
+  ZVAL_EMPTY_STRING(*value_ptr);
+  return (void*)(*value_ptr);
+}
+#else
+static void *empty_php_string(zval* value_ptr) {
+  if (Z_TYPE_P(value_ptr) == IS_STRING) {
+    zend_string_release(Z_STR_P(value_ptr));
+  }
+  ZVAL_EMPTY_STRING(value_ptr);
+  return value_ptr;
+}
+#endif
+
+// Sets a non-repeated string field in a message.
+static void* str_handler(void *closure,
+                         const void *hd,
+                         size_t size_hint) {
+  MessageHeader* msg = closure;
+  const size_t *ofs = hd;
+  return empty_php_string(DEREF(message_data(msg), *ofs, CACHED_VALUE*));
+}
+
+// Sets a non-repeated 'bytes' field in a message.
+static void* bytes_handler(void *closure,
+                           const void *hd,
+                           size_t size_hint) {
+  MessageHeader* msg = closure;
+  const size_t *ofs = hd;
+  return empty_php_string(DEREF(message_data(msg), *ofs, CACHED_VALUE*));
+}
+
+static size_t stringdata_handler(void* closure, const void* hd,
+                                 const char* str, size_t len,
+                                 const upb_bufhandle* handle) {
+  zval* php_str = (zval*)closure;
+#if PHP_MAJOR_VERSION < 7
+  // Oneof string/bytes fields may have NULL initial value, which doesn't need
+  // to be freed.
+  if (Z_TYPE_P(php_str) == IS_STRING && !IS_INTERNED(Z_STRVAL_P(php_str))) {
+    FREE(Z_STRVAL_P(php_str));
+  }
+  ZVAL_STRINGL(php_str, str, len, 1);
+#else
+  if (Z_TYPE_P(php_str) == IS_STRING) {
+    zend_string_release(Z_STR_P(php_str));
+  }
+  ZVAL_NEW_STR(php_str, zend_string_init(str, len, 0));
+#endif
+  return len;
+}
+
+#if PHP_MAJOR_VERSION >= 7
+static size_t zendstringdata_handler(void* closure, const void* hd,
+                                     const char* str, size_t len,
+                                     const upb_bufhandle* handle) {
+  RepeatedField* intern = (RepeatedField*)closure;
+
+  unsigned char memory[NATIVE_SLOT_MAX_SIZE];
+  memset(memory, 0, NATIVE_SLOT_MAX_SIZE);
+  *(zend_string**)memory = zend_string_init(str, len, 0);
+
+  HashTable *ht = PHP_PROTO_HASH_OF(intern->array);
+  int index = zend_hash_num_elements(ht) - 1;
+  php_proto_zend_hash_index_update_mem(
+      ht, index, memory, sizeof(zend_string*), NULL);
+
+  return len;
+}
+#endif
+
+// Appends a submessage to a repeated field.
+static void *appendsubmsg_handler(void *closure, const void *hd) {
+  zval* array = (zval*)closure;
+  TSRMLS_FETCH();
+  RepeatedField* intern = UNBOX(RepeatedField, array);
+
+  const submsg_handlerdata_t *submsgdata = hd;
+  Descriptor* subdesc =
+      UNBOX_HASHTABLE_VALUE(Descriptor, get_def_obj((void*)submsgdata->md));
+  zend_class_entry* subklass = subdesc->klass;
+  MessageHeader* submsg;
+
+#if PHP_MAJOR_VERSION < 7
+  zval* val = NULL;
+  MAKE_STD_ZVAL(val);
+  ZVAL_OBJ(val, subklass->create_object(subklass TSRMLS_CC));
+  repeated_field_push_native(intern, &val);
+  submsg = UNBOX(MessageHeader, val);
+#else
+  zend_object* obj = subklass->create_object(subklass TSRMLS_CC);
+  repeated_field_push_native(intern, &obj);
+  submsg = (MessageHeader*)((char*)obj - XtOffsetOf(MessageHeader, std));
+#endif
+  custom_data_init(subklass, submsg PHP_PROTO_TSRMLS_CC);
+
+  return submsg;
+}
+
+// Sets a non-repeated submessage field in a message.
+static void *submsg_handler(void *closure, const void *hd) {
+  MessageHeader* msg = closure;
+  const submsg_handlerdata_t* submsgdata = hd;
+  TSRMLS_FETCH();
+  Descriptor* subdesc =
+      UNBOX_HASHTABLE_VALUE(Descriptor, get_def_obj((void*)submsgdata->md));
+  zend_class_entry* subklass = subdesc->klass;
+  zval* submsg_php;
+  MessageHeader* submsg;
+
+  if (Z_TYPE_P(CACHED_PTR_TO_ZVAL_PTR(DEREF(message_data(msg), submsgdata->ofs,
+                                            CACHED_VALUE*))) == IS_NULL) {
+#if PHP_MAJOR_VERSION < 7
+    zval* val = NULL;
+    MAKE_STD_ZVAL(val);
+    ZVAL_OBJ(val, subklass->create_object(subklass TSRMLS_CC));
+    MessageHeader* intern = UNBOX(MessageHeader, val);
+    custom_data_init(subklass, intern PHP_PROTO_TSRMLS_CC);
+    php_proto_zval_ptr_dtor(*DEREF(message_data(msg), submsgdata->ofs, zval**));
+    *DEREF(message_data(msg), submsgdata->ofs, zval**) = val;
+#else
+    zend_object* obj = subklass->create_object(subklass TSRMLS_CC);
+    ZVAL_OBJ(DEREF(message_data(msg), submsgdata->ofs, zval*), obj);
+    MessageHeader* intern = UNBOX_HASHTABLE_VALUE(MessageHeader, obj);
+    custom_data_init(subklass, intern PHP_PROTO_TSRMLS_CC);
+#endif
+  }
+
+  submsg_php = CACHED_PTR_TO_ZVAL_PTR(
+      DEREF(message_data(msg), submsgdata->ofs, CACHED_VALUE*));
+
+  submsg = UNBOX(MessageHeader, submsg_php);
+  return submsg;
+}
+
+// Handler data for startmap/endmap handlers.
+typedef struct {
+  size_t ofs;
+  upb_fieldtype_t key_field_type;
+  upb_fieldtype_t value_field_type;
+
+  // We know that we can hold this reference because the handlerdata has the
+  // same lifetime as the upb_handlers struct, and the upb_handlers struct holds
+  // a reference to the upb_msgdef, which in turn has references to its subdefs.
+  const upb_def* value_field_subdef;
+} map_handlerdata_t;
+
+// Temporary frame for map parsing: at the beginning of a map entry message, a
+// submsg handler allocates a frame to hold (i) a reference to the Map object
+// into which this message will be inserted and (ii) storage slots to
+// temporarily hold the key and value for this map entry until the end of the
+// submessage. When the submessage ends, another handler is called to insert the
+// value into the map.
+typedef struct {
+  char key_storage[NATIVE_SLOT_MAX_SIZE];
+  char value_storage[NATIVE_SLOT_MAX_SIZE];
+} map_parse_frame_data_t;
+
+PHP_PROTO_WRAP_OBJECT_START(map_parse_frame_t)
+  map_parse_frame_data_t* data;  // Place needs to be consistent with
+                                 // MessageHeader.
+  zval* map;
+  // In php7, we cannot allocate zval dynamically. So we need to add zval here
+  // to help decoding.
+  zval key_zval;
+  zval value_zval;
+PHP_PROTO_WRAP_OBJECT_END
+typedef struct map_parse_frame_t map_parse_frame_t;
+
+static void map_slot_init(void* memory, upb_fieldtype_t type, zval* cache) {
+  switch (type) {
+    case UPB_TYPE_STRING:
+    case UPB_TYPE_BYTES: {
+#if PHP_MAJOR_VERSION < 7
+      // Store zval** in memory in order to be consistent with the layout of
+      // singular fields.
+      zval** holder = ALLOC(zval*);
+      *(zval***)memory = holder;
+      zval* tmp;
+      MAKE_STD_ZVAL(tmp);
+      PHP_PROTO_ZVAL_STRINGL(tmp, "", 0, 1);
+      *holder = tmp;
+#else
+      *(zval**)memory = cache;
+      PHP_PROTO_ZVAL_STRINGL(*(zval**)memory, "", 0, 1);
+#endif
+      break;
+    }
+    case UPB_TYPE_MESSAGE: {
+#if PHP_MAJOR_VERSION < 7
+      zval** holder = ALLOC(zval*);
+      zval* tmp;
+      MAKE_STD_ZVAL(tmp);
+      ZVAL_NULL(tmp);
+      *holder = tmp;
+      *(zval***)memory = holder;
+#else
+      *(zval**)memory = cache;
+      ZVAL_NULL(*(zval**)memory);
+#endif
+      break;
+    }
+    default:
+      native_slot_init(type, memory, NULL);
+  }
+}
+
+static void map_slot_uninit(void* memory, upb_fieldtype_t type) {
+  switch (type) {
+    case UPB_TYPE_MESSAGE:
+    case UPB_TYPE_STRING:
+    case UPB_TYPE_BYTES: {
+#if PHP_MAJOR_VERSION < 7
+      zval** holder = *(zval***)memory;
+      zval_ptr_dtor(holder);
+      FREE(holder);
+#else
+      php_proto_zval_ptr_dtor(*(zval**)memory);
+#endif
+      break;
+    }
+    default:
+      break;
+  }
+}
+
+static void map_slot_key(upb_fieldtype_t type, const void* from,
+                         const char** keyval,
+                         size_t* length) {
+  if (type == UPB_TYPE_STRING) {
+#if PHP_MAJOR_VERSION < 7
+    zval* key_php = **(zval***)from;
+#else
+    zval* key_php = *(zval**)from;
+#endif
+    *keyval = Z_STRVAL_P(key_php);
+    *length = Z_STRLEN_P(key_php);
+  } else {
+    *keyval = from;
+    *length = native_slot_size(type);
+  }
+}
+
+static void map_slot_value(upb_fieldtype_t type, const void* from,
+                           upb_value* v) {
+  size_t len;
+  void* to = upb_value_memory(v);
+#ifndef NDEBUG
+  v->ctype = UPB_CTYPE_UINT64;
+#endif
+
+  memset(to, 0, native_slot_size(type));
+
+  switch (type) {
+#if PHP_MAJOR_VERSION < 7
+    case UPB_TYPE_STRING:
+    case UPB_TYPE_BYTES:
+    case UPB_TYPE_MESSAGE: {
+      *(zval**)to = **(zval***)from;
+      Z_ADDREF_PP((zval**)to);
+      break;
+    }
+#else
+    case UPB_TYPE_STRING:
+    case UPB_TYPE_BYTES:
+      *(zend_string**)to = Z_STR_P(*(zval**)from);
+      zend_string_addref(*(zend_string**)to);
+      break;
+    case UPB_TYPE_MESSAGE:
+      *(zend_object**)to = Z_OBJ_P(*(zval**)from);
+      GC_ADDREF(*(zend_object**)to);
+      break;
+#endif
+    default:
+      len = native_slot_size(type);
+      memcpy(to, from, len);
+  }
+}
+
+// Handler to begin a map entry: allocates a temporary frame. This is the
+// 'startsubmsg' handler on the msgdef that contains the map field.
+static void *startmapentry_handler(void *closure, const void *hd) {
+  MessageHeader* msg = closure;
+  const map_handlerdata_t* mapdata = hd;
+  zval* map = CACHED_PTR_TO_ZVAL_PTR(
+      DEREF(message_data(msg), mapdata->ofs, CACHED_VALUE*));
+
+  map_parse_frame_t* frame = ALLOC(map_parse_frame_t);
+  frame->data = ALLOC(map_parse_frame_data_t);
+  frame->map = map;
+
+  map_slot_init(&frame->data->key_storage, mapdata->key_field_type,
+                &frame->key_zval);
+  map_slot_init(&frame->data->value_storage, mapdata->value_field_type,
+                &frame->value_zval);
+
+  return frame;
+}
+
+// Handler to end a map entry: inserts the value defined during the message into
+// the map. This is the 'endmsg' handler on the map entry msgdef.
+static bool endmap_handler(void* closure, const void* hd, upb_status* s) {
+  map_parse_frame_t* frame = closure;
+  const map_handlerdata_t* mapdata = hd;
+
+  TSRMLS_FETCH();
+  Map *map = UNBOX(Map, frame->map);
+
+  const char* keyval = NULL;
+  upb_value v;
+  size_t length;
+
+  map_slot_key(map->key_type, &frame->data->key_storage, &keyval, &length);
+  map_slot_value(map->value_type, &frame->data->value_storage, &v);
+
+  map_index_set(map, keyval, length, v);
+
+  map_slot_uninit(&frame->data->key_storage, mapdata->key_field_type);
+  map_slot_uninit(&frame->data->value_storage, mapdata->value_field_type);
+  FREE(frame->data);
+  FREE(frame);
+
+  return true;
+}
+
+// Allocates a new map_handlerdata_t given the map entry message definition. If
+// the offset of the field within the parent message is also given, that is
+// added to the handler data as well. Note that this is called *twice* per map
+// field: once in the parent message handler setup when setting the startsubmsg
+// handler and once in the map entry message handler setup when setting the
+// key/value and endmsg handlers. The reason is that there is no easy way to
+// pass the handlerdata down to the sub-message handler setup.
+static map_handlerdata_t* new_map_handlerdata(
+    size_t ofs,
+    const upb_msgdef* mapentry_def,
+    Descriptor* desc) {
+  const upb_fielddef* key_field;
+  const upb_fielddef* value_field;
+  // TODO(teboring): Use emalloc and efree.
+  map_handlerdata_t* hd =
+      (map_handlerdata_t*)malloc(sizeof(map_handlerdata_t));
+
+  hd->ofs = ofs;
+  key_field = upb_msgdef_itof(mapentry_def, MAP_KEY_FIELD);
+  assert(key_field != NULL);
+  hd->key_field_type = upb_fielddef_type(key_field);
+  value_field = upb_msgdef_itof(mapentry_def, MAP_VALUE_FIELD);
+  assert(value_field != NULL);
+  hd->value_field_type = upb_fielddef_type(value_field);
+  hd->value_field_subdef = upb_fielddef_subdef(value_field);
+
+  return hd;
+}
+
+// Handlers that set primitive values in oneofs.
+#define DEFINE_ONEOF_HANDLER(type, ctype)                          \
+  static bool oneof##type##_handler(void* closure, const void* hd, \
+                                    ctype val) {                   \
+    const oneof_handlerdata_t* oneofdata = hd;                     \
+    MessageHeader* msg = (MessageHeader*)closure;                  \
+    DEREF(message_data(closure), oneofdata->case_ofs, uint32_t) =  \
+        oneofdata->oneof_case_num;                                 \
+    DEREF(message_data(closure), oneofdata->ofs, ctype) = val;     \
+    return true;                                                   \
+  }
+
+DEFINE_ONEOF_HANDLER(bool,   bool)
+DEFINE_ONEOF_HANDLER(int32,  int32_t)
+DEFINE_ONEOF_HANDLER(uint32, uint32_t)
+DEFINE_ONEOF_HANDLER(float,  float)
+DEFINE_ONEOF_HANDLER(int64,  int64_t)
+DEFINE_ONEOF_HANDLER(uint64, uint64_t)
+DEFINE_ONEOF_HANDLER(double, double)
+
+#undef DEFINE_ONEOF_HANDLER
+
+static void oneof_cleanup(MessageHeader* msg,
+                          const oneof_handlerdata_t* oneofdata) {
+  uint32_t old_case_num =
+      DEREF(message_data(msg), oneofdata->case_ofs, uint32_t);
+  if (old_case_num == 0) {
+    return;
+  }
+
+  const upb_fielddef* old_field =
+      upb_msgdef_itof(oneofdata->parent_md, old_case_num);
+  bool need_clean = false;
+
+  switch (upb_fielddef_type(old_field)) {
+    case UPB_TYPE_STRING:
+    case UPB_TYPE_BYTES:
+      need_clean = true;
+      break;
+    case UPB_TYPE_MESSAGE:
+      if (oneofdata->oneof_case_num != old_case_num) {
+        need_clean = true;
+      }
+      break;
+    default:
+      break;
+  }
+
+  if (need_clean) {
+#if PHP_MAJOR_VERSION < 7
+    SEPARATE_ZVAL_IF_NOT_REF(
+        DEREF(message_data(msg), oneofdata->ofs, CACHED_VALUE*));
+    php_proto_zval_ptr_dtor(
+        *DEREF(message_data(msg), oneofdata->ofs, CACHED_VALUE*));
+    MAKE_STD_ZVAL(*DEREF(message_data(msg), oneofdata->ofs, CACHED_VALUE*));
+    ZVAL_NULL(*DEREF(message_data(msg), oneofdata->ofs, CACHED_VALUE*));
+#endif
+  }
+}
+
+// Handlers for string/bytes in a oneof.
+static void *oneofbytes_handler(void *closure,
+                                const void *hd,
+                                size_t size_hint) {
+  MessageHeader* msg = closure;
+  const oneof_handlerdata_t *oneofdata = hd;
+
+  oneof_cleanup(msg, oneofdata);
+
+  DEREF(message_data(msg), oneofdata->case_ofs, uint32_t) =
+      oneofdata->oneof_case_num;
+  DEREF(message_data(msg), oneofdata->ofs, CACHED_VALUE*) =
+      OBJ_PROP(&msg->std, oneofdata->property_ofs);
+
+   return empty_php_string(DEREF(
+       message_data(msg), oneofdata->ofs, CACHED_VALUE*));
+}
+
+static void *oneofstr_handler(void *closure,
+                              const void *hd,
+                              size_t size_hint) {
+  // TODO(teboring): Add it back.
+  // rb_enc_associate(str, kRubyString8bitEncoding);
+  return oneofbytes_handler(closure, hd, size_hint);
+}
+
+// Handler for a submessage field in a oneof.
+static void* oneofsubmsg_handler(void* closure, const void* hd) {
+  MessageHeader* msg = closure;
+  const oneof_handlerdata_t *oneofdata = hd;
+  uint32_t oldcase = DEREF(message_data(msg), oneofdata->case_ofs, uint32_t);
+  TSRMLS_FETCH();
+  Descriptor* subdesc =
+      UNBOX_HASHTABLE_VALUE(Descriptor, get_def_obj((void*)oneofdata->md));
+  zend_class_entry* subklass = subdesc->klass;
+  zval* submsg_php;
+  MessageHeader* submsg;
+
+  if (oldcase != oneofdata->oneof_case_num) {
+    oneof_cleanup(msg, oneofdata);
+
+    // Create new message.
+    DEREF(message_data(msg), oneofdata->ofs, CACHED_VALUE*) =
+        OBJ_PROP(&msg->std, oneofdata->property_ofs);
+    ZVAL_OBJ(CACHED_PTR_TO_ZVAL_PTR(
+        DEREF(message_data(msg), oneofdata->ofs, CACHED_VALUE*)),
+        subklass->create_object(subklass TSRMLS_CC));
+  }
+
+  DEREF(message_data(msg), oneofdata->case_ofs, uint32_t) =
+      oneofdata->oneof_case_num;
+
+  submsg_php = CACHED_PTR_TO_ZVAL_PTR(
+      DEREF(message_data(msg), oneofdata->ofs, CACHED_VALUE*));
+  submsg = UNBOX(MessageHeader, submsg_php);
+  custom_data_init(subklass, submsg PHP_PROTO_TSRMLS_CC);
+  return submsg;
+}
+
+// Set up handlers for a repeated field.
+static void add_handlers_for_repeated_field(upb_handlers *h,
+                                            const upb_fielddef *f,
+                                            size_t offset) {
+  upb_handlerattr attr = UPB_HANDLERATTR_INITIALIZER;
+  upb_handlerattr_sethandlerdata(&attr, newhandlerdata(h, offset));
+  upb_handlers_setstartseq(h, f, startseq_handler, &attr);
+  upb_handlerattr_uninit(&attr);
+
+  switch (upb_fielddef_type(f)) {
+
+#define SET_HANDLER(utype, ltype)                                 \
+  case utype:                                                     \
+    upb_handlers_set##ltype(h, f, append##ltype##_handler, NULL); \
+    break;
+
+    SET_HANDLER(UPB_TYPE_BOOL,   bool);
+    SET_HANDLER(UPB_TYPE_INT32,  int32);
+    SET_HANDLER(UPB_TYPE_UINT32, uint32);
+    SET_HANDLER(UPB_TYPE_ENUM,   int32);
+    SET_HANDLER(UPB_TYPE_FLOAT,  float);
+    SET_HANDLER(UPB_TYPE_INT64,  int64);
+    SET_HANDLER(UPB_TYPE_UINT64, uint64);
+    SET_HANDLER(UPB_TYPE_DOUBLE, double);
+
+#undef SET_HANDLER
+
+    case UPB_TYPE_STRING:
+    case UPB_TYPE_BYTES: {
+      bool is_bytes = upb_fielddef_type(f) == UPB_TYPE_BYTES;
+      upb_handlers_setstartstr(h, f, is_bytes ?
+                               appendbytes_handler : appendstr_handler,
+                               NULL);
+#if PHP_MAJOR_VERSION < 7
+      upb_handlers_setstring(h, f, stringdata_handler, NULL);
+#else
+      upb_handlers_setstring(h, f, zendstringdata_handler, NULL);
+#endif
+      break;
+    }
+    case UPB_TYPE_MESSAGE: {
+      upb_handlerattr attr = UPB_HANDLERATTR_INITIALIZER;
+      upb_handlerattr_sethandlerdata(&attr, newsubmsghandlerdata(h, 0, f));
+      upb_handlers_setstartsubmsg(h, f, appendsubmsg_handler, &attr);
+      upb_handlerattr_uninit(&attr);
+      break;
+    }
+  }
+}
+
+// Set up handlers for a singular field.
+static void add_handlers_for_singular_field(upb_handlers *h,
+                                            const upb_fielddef *f,
+                                            size_t offset) {
+  switch (upb_fielddef_type(f)) {
+
+#define SET_HANDLER(utype, ltype)                                     \
+  case utype: {                                                       \
+    upb_handlerattr attr = UPB_HANDLERATTR_INITIALIZER;               \
+    upb_handlerattr_sethandlerdata(&attr, newhandlerdata(h, offset)); \
+    upb_handlers_set##ltype(h, f, ltype##_handler, &attr);            \
+    break;                                                            \
+  }
+
+    SET_HANDLER(UPB_TYPE_BOOL,   bool);
+    SET_HANDLER(UPB_TYPE_INT32,  int32);
+    SET_HANDLER(UPB_TYPE_UINT32, uint32);
+    SET_HANDLER(UPB_TYPE_ENUM,   int32);
+    SET_HANDLER(UPB_TYPE_FLOAT,  float);
+    SET_HANDLER(UPB_TYPE_INT64,  int64);
+    SET_HANDLER(UPB_TYPE_UINT64, uint64);
+    SET_HANDLER(UPB_TYPE_DOUBLE, double);
+
+#undef SET_HANDLER
+
+    case UPB_TYPE_STRING:
+    case UPB_TYPE_BYTES: {
+      bool is_bytes = upb_fielddef_type(f) == UPB_TYPE_BYTES;
+      upb_handlerattr attr = UPB_HANDLERATTR_INITIALIZER;
+      upb_handlerattr_sethandlerdata(&attr, newhandlerdata(h, offset));
+      upb_handlers_setstartstr(h, f,
+                               is_bytes ? bytes_handler : str_handler,
+                               &attr);
+      upb_handlers_setstring(h, f, stringdata_handler, &attr);
+      upb_handlerattr_uninit(&attr);
+      break;
+    }
+    case UPB_TYPE_MESSAGE: {
+      upb_handlerattr attr = UPB_HANDLERATTR_INITIALIZER;
+      upb_handlerattr_sethandlerdata(&attr, newsubmsghandlerdata(h, offset, f));
+      upb_handlers_setstartsubmsg(h, f, submsg_handler, &attr);
+      upb_handlerattr_uninit(&attr);
+      break;
+    }
+  }
+}
+
+// Adds handlers to a map field.
+static void add_handlers_for_mapfield(upb_handlers* h,
+                                      const upb_fielddef* fielddef,
+                                      size_t offset,
+                                      Descriptor* desc) {
+  const upb_msgdef* map_msgdef = upb_fielddef_msgsubdef(fielddef);
+  map_handlerdata_t* hd = new_map_handlerdata(offset, map_msgdef, desc);
+  upb_handlerattr attr = UPB_HANDLERATTR_INITIALIZER;
+
+  upb_handlers_addcleanup(h, hd, free);
+  upb_handlerattr_sethandlerdata(&attr, hd);
+  upb_handlers_setstartsubmsg(h, fielddef, startmapentry_handler, &attr);
+  upb_handlerattr_uninit(&attr);
+}
+
+// Adds handlers to a map-entry msgdef.
+static void add_handlers_for_mapentry(const upb_msgdef* msgdef, upb_handlers* h,
+                                      Descriptor* desc) {
+  const upb_fielddef* key_field = map_entry_key(msgdef);
+  const upb_fielddef* value_field = map_entry_value(msgdef);
+  map_handlerdata_t* hd = new_map_handlerdata(0, msgdef, desc);
+  upb_handlerattr attr = UPB_HANDLERATTR_INITIALIZER;
+
+  upb_handlers_addcleanup(h, hd, free);
+  upb_handlerattr_sethandlerdata(&attr, hd);
+  upb_handlers_setendmsg(h, endmap_handler, &attr);
+
+  add_handlers_for_singular_field(h, key_field,
+                                  offsetof(map_parse_frame_data_t,
+                                           key_storage));
+  add_handlers_for_singular_field(h, value_field,
+                                  offsetof(map_parse_frame_data_t, 
+                                           value_storage));
+}
+
+// Set up handlers for a oneof field.
+static void add_handlers_for_oneof_field(upb_handlers *h,
+                                         const upb_msgdef *m,
+                                         const upb_fielddef *f,
+                                         size_t offset,
+                                         size_t oneof_case_offset,
+                                         int property_cache_offset) {
+
+  upb_handlerattr attr = UPB_HANDLERATTR_INITIALIZER;
+  upb_handlerattr_sethandlerdata(
+      &attr, newoneofhandlerdata(h, offset, oneof_case_offset,
+                                 property_cache_offset, m, f));
+
+  switch (upb_fielddef_type(f)) {
+
+#define SET_HANDLER(utype, ltype)                                 \
+  case utype:                                                     \
+    upb_handlers_set##ltype(h, f, oneof##ltype##_handler, &attr); \
+    break;
+
+    SET_HANDLER(UPB_TYPE_BOOL,   bool);
+    SET_HANDLER(UPB_TYPE_INT32,  int32);
+    SET_HANDLER(UPB_TYPE_UINT32, uint32);
+    SET_HANDLER(UPB_TYPE_ENUM,   int32);
+    SET_HANDLER(UPB_TYPE_FLOAT,  float);
+    SET_HANDLER(UPB_TYPE_INT64,  int64);
+    SET_HANDLER(UPB_TYPE_UINT64, uint64);
+    SET_HANDLER(UPB_TYPE_DOUBLE, double);
+
+#undef SET_HANDLER
+
+    case UPB_TYPE_STRING:
+    case UPB_TYPE_BYTES: {
+      bool is_bytes = upb_fielddef_type(f) == UPB_TYPE_BYTES;
+      upb_handlers_setstartstr(h, f, is_bytes ?
+                               oneofbytes_handler : oneofstr_handler,
+                               &attr);
+      upb_handlers_setstring(h, f, stringdata_handler, NULL);
+      break;
+    }
+    case UPB_TYPE_MESSAGE: {
+      upb_handlers_setstartsubmsg(h, f, oneofsubmsg_handler, &attr);
+      break;
+    }
+  }
+
+  upb_handlerattr_uninit(&attr);
+}
+
+static bool add_unknown_handler(void* closure, const void* hd, const char* buf,
+                         size_t size) {
+  encodeunknown_handlerfunc handler =
+      ((unknownfields_handlerdata_t*)hd)->handler;
+
+  MessageHeader* msg = (MessageHeader*)closure;
+  stringsink* unknown = DEREF(message_data(msg), 0, stringsink*);
+  if (unknown == NULL) {
+    DEREF(message_data(msg), 0, stringsink*) = ALLOC(stringsink);
+    unknown = DEREF(message_data(msg), 0, stringsink*);
+    stringsink_init(unknown);
+  }
+
+  handler(unknown, NULL, buf, size, NULL);
+
+  return true;
+}
+
+static void add_handlers_for_message(const void* closure,
+                                     upb_handlers* h) {
+  const upb_msgdef* msgdef = upb_handlers_msgdef(h);
+  TSRMLS_FETCH();
+  Descriptor* desc =
+      UNBOX_HASHTABLE_VALUE(Descriptor, get_def_obj((void*)msgdef));
+  upb_msg_field_iter i;
+
+  // If this is a mapentry message type, set up a special set of handlers and
+  // bail out of the normal (user-defined) message type handling.
+  if (upb_msgdef_mapentry(msgdef)) {
+    add_handlers_for_mapentry(msgdef, h, desc);
+    return;
+  }
+
+  // Ensure layout exists. We may be invoked to create handlers for a given
+  // message if we are included as a submsg of another message type before our
+  // class is actually built, so to work around this, we just create the layout
+  // (and handlers, in the class-building function) on-demand.
+  if (desc->layout == NULL) {
+    desc->layout = create_layout(desc->msgdef);
+  }
+
+  upb_handlerattr attr = UPB_HANDLERATTR_INITIALIZER;
+  upb_handlerattr_sethandlerdata(&attr, newunknownfieldshandlerdata(h));
+  upb_handlers_setunknown(h, add_unknown_handler, &attr);
+
+  for (upb_msg_field_begin(&i, desc->msgdef);
+       !upb_msg_field_done(&i);
+       upb_msg_field_next(&i)) {
+    const upb_fielddef *f = upb_msg_iter_field(&i);
+    size_t offset = desc->layout->fields[upb_fielddef_index(f)].offset;
+
+    if (upb_fielddef_containingoneof(f)) {
+      size_t oneof_case_offset =
+          desc->layout->fields[upb_fielddef_index(f)].case_offset;
+      int property_cache_index =
+          desc->layout->fields[upb_fielddef_index(f)].cache_index;
+      add_handlers_for_oneof_field(h, desc->msgdef, f, offset,
+                                   oneof_case_offset, property_cache_index);
+    } else if (is_map_field(f)) {
+      add_handlers_for_mapfield(h, f, offset, desc);
+    } else if (upb_fielddef_isseq(f)) {
+      add_handlers_for_repeated_field(h, f, offset);
+    } else {
+      add_handlers_for_singular_field(h, f, offset);
+    }
+  }
+}
+
+// Creates upb handlers for populating a message.
+static const upb_handlers *new_fill_handlers(Descriptor* desc,
+                                             const void* owner) {
+  // TODO(cfallin, haberman): once upb gets a caching/memoization layer for
+  // handlers, reuse subdef handlers so that e.g. if we already parse
+  // B-with-field-of-type-C, we don't have to rebuild the whole hierarchy to
+  // parse A-with-field-of-type-B-with-field-of-type-C.
+  return upb_handlers_newfrozen(desc->msgdef, owner,
+                                add_handlers_for_message, NULL);
+}
+
+// Constructs the handlers for filling a message's data into an in-memory
+// object.
+const upb_handlers* get_fill_handlers(Descriptor* desc) {
+  if (!desc->fill_handlers) {
+    desc->fill_handlers =
+        new_fill_handlers(desc, &desc->fill_handlers);
+  }
+  return desc->fill_handlers;
+}
+
+const upb_pbdecodermethod *new_fillmsg_decodermethod(Descriptor* desc,
+                                                     const void* owner) {
+  const upb_handlers* handlers = get_fill_handlers(desc);
+  upb_pbdecodermethodopts opts;
+  upb_pbdecodermethodopts_init(&opts, handlers);
+
+  return upb_pbdecodermethod_new(&opts, owner);
+}
+
+static const upb_pbdecodermethod *msgdef_decodermethod(Descriptor* desc) {
+  if (desc->fill_method == NULL) {
+    desc->fill_method = new_fillmsg_decodermethod(
+        desc, &desc->fill_method);
+  }
+  return desc->fill_method;
+}
+
+static const upb_json_parsermethod *msgdef_jsonparsermethod(Descriptor* desc) {
+  if (desc->json_fill_method == NULL) {
+    desc->json_fill_method =
+        upb_json_parsermethod_new(desc->msgdef, &desc->json_fill_method);
+  }
+  return desc->json_fill_method;
+}
+
+// -----------------------------------------------------------------------------
+// Serializing.
+// -----------------------------------------------------------------------------
+
+static void putmsg(zval* msg, const Descriptor* desc, upb_sink* sink,
+                   int depth TSRMLS_DC);
+static void putrawmsg(MessageHeader* msg, const Descriptor* desc,
+                      upb_sink* sink, int depth TSRMLS_DC);
+
+static void putstr(zval* str, const upb_fielddef* f, upb_sink* sink);
+
+static void putrawstr(const char* str, int len, const upb_fielddef* f,
+                      upb_sink* sink);
+
+static void putsubmsg(zval* submsg, const upb_fielddef* f, upb_sink* sink,
+                      int depth TSRMLS_DC);
+static void putrawsubmsg(MessageHeader* submsg, const upb_fielddef* f,
+                         upb_sink* sink, int depth TSRMLS_DC);
+
+static void putarray(zval* array, const upb_fielddef* f, upb_sink* sink,
+                     int depth TSRMLS_DC);
+static void putmap(zval* map, const upb_fielddef* f, upb_sink* sink,
+                   int depth TSRMLS_DC);
+
+static upb_selector_t getsel(const upb_fielddef* f, upb_handlertype_t type) {
+  upb_selector_t ret;
+  bool ok = upb_handlers_getselector(f, type, &ret);
+  UPB_ASSERT(ok);
+  return ret;
+}
+
+static void put_optional_value(const void* memory, int len, const upb_fielddef* f,
+                               int depth, upb_sink* sink TSRMLS_DC) {
+  assert(upb_fielddef_label(f) == UPB_LABEL_OPTIONAL);
+
+  switch (upb_fielddef_type(f)) {
+#define T(upbtypeconst, upbtype, ctype, default_value)                         \
+  case upbtypeconst: {                                                         \
+    ctype value = DEREF(memory, 0, ctype);                                     \
+    if (value != default_value) {                                              \
+      upb_selector_t sel = getsel(f, upb_handlers_getprimitivehandlertype(f)); \
+      upb_sink_put##upbtype(sink, sel, value);                                 \
+    }                                                                          \
+  } break;
+
+    T(UPB_TYPE_FLOAT, float, float, 0.0)
+    T(UPB_TYPE_DOUBLE, double, double, 0.0)
+    T(UPB_TYPE_BOOL, bool, uint8_t, 0)
+    T(UPB_TYPE_ENUM, int32, int32_t, 0)
+    T(UPB_TYPE_INT32, int32, int32_t, 0)
+    T(UPB_TYPE_UINT32, uint32, uint32_t, 0)
+    T(UPB_TYPE_INT64, int64, int64_t, 0)
+    T(UPB_TYPE_UINT64, uint64, uint64_t, 0)
+
+#undef T
+    case UPB_TYPE_STRING:
+    case UPB_TYPE_BYTES:
+      putrawstr(memory, len, f, sink);
+      break;
+    case UPB_TYPE_MESSAGE: {
+#if PHP_MAJOR_VERSION < 7
+      MessageHeader *submsg = UNBOX(MessageHeader, *(zval**)memory);
+#else
+      MessageHeader *submsg =
+          (MessageHeader*)((char*)(*(zend_object**)memory) -
+              XtOffsetOf(MessageHeader, std));
+#endif
+      putrawsubmsg(submsg, f, sink, depth TSRMLS_CC);
+      break;
+    }
+    default:
+      assert(false);
+  }
+}
+
+// Only string/bytes fields are stored as zval.
+static const char* raw_value(void* memory, const upb_fielddef* f) {
+  switch (upb_fielddef_type(f)) {
+    case UPB_TYPE_STRING:
+    case UPB_TYPE_BYTES:
+#if PHP_MAJOR_VERSION < 7
+      return Z_STRVAL_PP((zval**)memory);
+#else
+      return ZSTR_VAL(*(zend_string**)memory);
+#endif
+      break;
+    default:
+      return memory;
+  }
+}
+
+static int raw_value_len(void* memory, int len, const upb_fielddef* f) {
+  switch (upb_fielddef_type(f)) {
+    case UPB_TYPE_STRING:
+    case UPB_TYPE_BYTES:
+#if PHP_MAJOR_VERSION < 7
+      return Z_STRLEN_PP((zval**)memory);
+#else
+      return ZSTR_LEN(*(zend_string**)memory);
+#endif
+    default:
+      return len;
+  }
+}
+
+static void putmap(zval* map, const upb_fielddef* f, upb_sink* sink,
+                   int depth TSRMLS_DC) {
+  upb_sink subsink;
+  const upb_fielddef* key_field;
+  const upb_fielddef* value_field;
+  MapIter it;
+  int len, size;
+
+  assert(map != NULL);
+  Map* intern = UNBOX(Map, map);
+  size = upb_strtable_count(&intern->table);
+  if (size == 0) return;
+
+  upb_sink_startseq(sink, getsel(f, UPB_HANDLER_STARTSEQ), &subsink);
+
+  assert(upb_fielddef_type(f) == UPB_TYPE_MESSAGE);
+  key_field = map_field_key(f);
+  value_field = map_field_value(f);
+
+  for (map_begin(map, &it TSRMLS_CC); !map_done(&it); map_next(&it)) {
+    upb_status status;
+
+    upb_sink entry_sink;
+    upb_sink_startsubmsg(&subsink, getsel(f, UPB_HANDLER_STARTSUBMSG),
+                         &entry_sink);
+    upb_sink_startmsg(&entry_sink);
+
+    // Serialize key.
+    const char *key = map_iter_key(&it, &len);
+    put_optional_value(key, len, key_field, depth + 1, &entry_sink TSRMLS_CC);
+
+    // Serialize value.
+    upb_value value = map_iter_value(&it, &len);
+    put_optional_value(raw_value(upb_value_memory(&value), value_field),
+                       raw_value_len(upb_value_memory(&value), len, value_field),
+                       value_field, depth + 1, &entry_sink TSRMLS_CC);
+
+    upb_sink_endmsg(&entry_sink, &status);
+    upb_sink_endsubmsg(&subsink, getsel(f, UPB_HANDLER_ENDSUBMSG));
+  }
+
+  upb_sink_endseq(sink, getsel(f, UPB_HANDLER_ENDSEQ));
+}
+
+static void putmsg(zval* msg_php, const Descriptor* desc, upb_sink* sink,
+                   int depth TSRMLS_DC) {
+  MessageHeader* msg = UNBOX(MessageHeader, msg_php);
+  putrawmsg(msg, desc, sink, depth TSRMLS_CC);
+}
+
+static void putrawmsg(MessageHeader* msg, const Descriptor* desc,
+                      upb_sink* sink, int depth TSRMLS_DC) {
+  upb_msg_field_iter i;
+  upb_status status;
+
+  upb_sink_startmsg(sink);
+
+  // Protect against cycles (possible because users may freely reassign message
+  // and repeated fields) by imposing a maximum recursion depth.
+  if (depth > ENCODE_MAX_NESTING) {
+    zend_error(E_ERROR,
+             "Maximum recursion depth exceeded during encoding.");
+  }
+
+  for (upb_msg_field_begin(&i, desc->msgdef); !upb_msg_field_done(&i);
+       upb_msg_field_next(&i)) {
+    upb_fielddef* f = upb_msg_iter_field(&i);
+    uint32_t offset = desc->layout->fields[upb_fielddef_index(f)].offset;
+    bool containing_oneof = false;
+
+    if (upb_fielddef_containingoneof(f)) {
+      uint32_t oneof_case_offset =
+          desc->layout->fields[upb_fielddef_index(f)].case_offset;
+      // For a oneof, check that this field is actually present -- skip all the
+      // below if not.
+      if (DEREF(message_data(msg), oneof_case_offset, uint32_t) !=
+          upb_fielddef_number(f)) {
+        continue;
+      }
+      // Otherwise, fall through to the appropriate singular-field handler
+      // below.
+      containing_oneof = true;
+    }
+
+    if (is_map_field(f)) {
+      zval* map = CACHED_PTR_TO_ZVAL_PTR(
+          DEREF(message_data(msg), offset, CACHED_VALUE*));
+      if (map != NULL) {
+        putmap(map, f, sink, depth TSRMLS_CC);
+      }
+    } else if (upb_fielddef_isseq(f)) {
+      zval* array = CACHED_PTR_TO_ZVAL_PTR(
+          DEREF(message_data(msg), offset, CACHED_VALUE*));
+      if (array != NULL) {
+        putarray(array, f, sink, depth TSRMLS_CC);
+      }
+    } else if (upb_fielddef_isstring(f)) {
+      zval* str = CACHED_PTR_TO_ZVAL_PTR(
+          DEREF(message_data(msg), offset, CACHED_VALUE*));
+      if (containing_oneof || Z_STRLEN_P(str) > 0) {
+        putstr(str, f, sink);
+      }
+    } else if (upb_fielddef_issubmsg(f)) {
+      putsubmsg(CACHED_PTR_TO_ZVAL_PTR(
+                    DEREF(message_data(msg), offset, CACHED_VALUE*)),
+                f, sink, depth TSRMLS_CC);
+    } else {
+      upb_selector_t sel = getsel(f, upb_handlers_getprimitivehandlertype(f));
+
+#define T(upbtypeconst, upbtype, ctype, default_value)     \
+  case upbtypeconst: {                                     \
+    ctype value = DEREF(message_data(msg), offset, ctype); \
+    if (containing_oneof || value != default_value) {      \
+      upb_sink_put##upbtype(sink, sel, value);             \
+    }                                                      \
+  } break;
+
+      switch (upb_fielddef_type(f)) {
+        T(UPB_TYPE_FLOAT, float, float, 0.0)
+        T(UPB_TYPE_DOUBLE, double, double, 0.0)
+        T(UPB_TYPE_BOOL, bool, uint8_t, 0)
+        case UPB_TYPE_ENUM:
+        T(UPB_TYPE_INT32, int32, int32_t, 0)
+        T(UPB_TYPE_UINT32, uint32, uint32_t, 0)
+        T(UPB_TYPE_INT64, int64, int64_t, 0)
+        T(UPB_TYPE_UINT64, uint64, uint64_t, 0)
+
+        case UPB_TYPE_STRING:
+        case UPB_TYPE_BYTES:
+        case UPB_TYPE_MESSAGE:
+          zend_error(E_ERROR, "Internal error.");
+      }
+
+#undef T
+    }
+  }
+
+  stringsink* unknown = DEREF(message_data(msg), 0, stringsink*);
+  if (unknown != NULL) {
+    upb_sink_putunknown(sink, unknown->ptr, unknown->len);
+  }
+
+  upb_sink_endmsg(sink, &status);
+}
+
+static void putstr(zval* str, const upb_fielddef *f, upb_sink *sink) {
+  upb_sink subsink;
+
+  if (ZVAL_IS_NULL(str)) return;
+
+  assert(Z_TYPE_P(str) == IS_STRING);
+
+  upb_sink_startstr(sink, getsel(f, UPB_HANDLER_STARTSTR), Z_STRLEN_P(str),
+                    &subsink);
+
+  // For oneof string field, we may get here with string length is zero.
+  if (Z_STRLEN_P(str) > 0) {
+    // Ensure that the string has the correct encoding. We also check at
+    // field-set time, but the user may have mutated the string object since
+    // then.
+    if (upb_fielddef_type(f) == UPB_TYPE_STRING &&
+        !is_structurally_valid_utf8(Z_STRVAL_P(str), Z_STRLEN_P(str))) {
+      zend_error(E_USER_ERROR, "Given string is not UTF8 encoded.");
+      return;
+    }
+    upb_sink_putstring(&subsink, getsel(f, UPB_HANDLER_STRING), Z_STRVAL_P(str),
+                       Z_STRLEN_P(str), NULL);
+  }
+
+  upb_sink_endstr(sink, getsel(f, UPB_HANDLER_ENDSTR));
+}
+
+static void putrawstr(const char* str, int len, const upb_fielddef* f,
+                      upb_sink* sink) {
+  upb_sink subsink;
+
+  if (len == 0) return;
+
+  // Ensure that the string has the correct encoding. We also check at field-set
+  // time, but the user may have mutated the string object since then.
+  if (upb_fielddef_type(f) == UPB_TYPE_STRING &&
+      !is_structurally_valid_utf8(str, len)) {
+    zend_error(E_USER_ERROR, "Given string is not UTF8 encoded.");
+    return;
+  }
+
+  upb_sink_startstr(sink, getsel(f, UPB_HANDLER_STARTSTR), len, &subsink);
+  upb_sink_putstring(&subsink, getsel(f, UPB_HANDLER_STRING), str, len, NULL);
+  upb_sink_endstr(sink, getsel(f, UPB_HANDLER_ENDSTR));
+}
+
+static void putsubmsg(zval* submsg_php, const upb_fielddef* f, upb_sink* sink,
+                      int depth TSRMLS_DC) {
+  if (Z_TYPE_P(submsg_php) == IS_NULL) return;
+
+  MessageHeader *submsg = UNBOX(MessageHeader, submsg_php);
+  putrawsubmsg(submsg, f, sink, depth TSRMLS_CC);
+}
+
+static void putrawsubmsg(MessageHeader* submsg, const upb_fielddef* f,
+                         upb_sink* sink, int depth TSRMLS_DC) {
+  upb_sink subsink;
+
+  Descriptor* subdesc =
+      UNBOX_HASHTABLE_VALUE(Descriptor, get_def_obj(upb_fielddef_msgsubdef(f)));
+
+  upb_sink_startsubmsg(sink, getsel(f, UPB_HANDLER_STARTSUBMSG), &subsink);
+  putrawmsg(submsg, subdesc, &subsink, depth + 1 TSRMLS_CC);
+  upb_sink_endsubmsg(sink, getsel(f, UPB_HANDLER_ENDSUBMSG));
+}
+
+static void putarray(zval* array, const upb_fielddef* f, upb_sink* sink,
+                     int depth TSRMLS_DC) {
+  upb_sink subsink;
+  upb_fieldtype_t type = upb_fielddef_type(f);
+  upb_selector_t sel = 0;
+  int size, i;
+
+  assert(array != NULL);
+  RepeatedField* intern = UNBOX(RepeatedField, array);
+  HashTable *ht = PHP_PROTO_HASH_OF(intern->array);
+  size = zend_hash_num_elements(ht);
+  if (size == 0) return;
+
+  upb_sink_startseq(sink, getsel(f, UPB_HANDLER_STARTSEQ), &subsink);
+
+  if (upb_fielddef_isprimitive(f)) {
+    sel = getsel(f, upb_handlers_getprimitivehandlertype(f));
+  }
+
+  for (i = 0; i < size; i++) {
+    void* memory = repeated_field_index_native(intern, i TSRMLS_CC);
+    switch (type) {
+#define T(upbtypeconst, upbtype, ctype)                      \
+  case upbtypeconst:                                         \
+    upb_sink_put##upbtype(&subsink, sel, *((ctype*)memory)); \
+    break;
+
+      T(UPB_TYPE_FLOAT, float, float)
+      T(UPB_TYPE_DOUBLE, double, double)
+      T(UPB_TYPE_BOOL, bool, int8_t)
+      case UPB_TYPE_ENUM:
+        T(UPB_TYPE_INT32, int32, int32_t)
+        T(UPB_TYPE_UINT32, uint32, uint32_t)
+        T(UPB_TYPE_INT64, int64, int64_t)
+        T(UPB_TYPE_UINT64, uint64, uint64_t)
+
+      case UPB_TYPE_STRING:
+      case UPB_TYPE_BYTES: {
+#if PHP_MAJOR_VERSION < 7
+        const char* rawstr = Z_STRVAL_P(*(zval**)memory);
+        int len = Z_STRLEN_P(*(zval**)memory);
+#else
+        const char* rawstr = ZSTR_VAL(*(zend_string**)memory);
+        int len = ZSTR_LEN(*(zend_string**)memory);
+#endif
+        putrawstr(rawstr, len, f, &subsink);
+        break;
+      }
+      case UPB_TYPE_MESSAGE: {
+#if PHP_MAJOR_VERSION < 7
+        MessageHeader *submsg = UNBOX(MessageHeader, *(zval**)memory);
+#else
+        MessageHeader *submsg =
+            (MessageHeader*)((char*)(Z_OBJ_P((zval*)memory)) -
+                XtOffsetOf(MessageHeader, std));
+#endif
+        putrawsubmsg(submsg, f, &subsink, depth TSRMLS_CC);
+        break;
+      }
+
+#undef T
+    }
+  }
+  upb_sink_endseq(sink, getsel(f, UPB_HANDLER_ENDSEQ));
+}
+
+static const upb_handlers* msgdef_pb_serialize_handlers(Descriptor* desc) {
+  if (desc->pb_serialize_handlers == NULL) {
+    desc->pb_serialize_handlers =
+        upb_pb_encoder_newhandlers(desc->msgdef, &desc->pb_serialize_handlers);
+  }
+  return desc->pb_serialize_handlers;
+}
+
+static const upb_handlers* msgdef_json_serialize_handlers(
+    Descriptor* desc, bool preserve_proto_fieldnames) {
+  if (preserve_proto_fieldnames) {
+    if (desc->json_serialize_handlers == NULL) {
+      desc->json_serialize_handlers =
+          upb_json_printer_newhandlers(
+              desc->msgdef, true, &desc->json_serialize_handlers);
+    }
+    return desc->json_serialize_handlers;
+  } else {
+    if (desc->json_serialize_handlers_preserve == NULL) {
+      desc->json_serialize_handlers_preserve =
+          upb_json_printer_newhandlers(
+              desc->msgdef, false, &desc->json_serialize_handlers_preserve);
+    }
+    return desc->json_serialize_handlers_preserve;
+  }
+}
+
+// -----------------------------------------------------------------------------
+// PHP encode/decode methods
+// -----------------------------------------------------------------------------
+
+void serialize_to_string(zval* val, zval* return_value TSRMLS_DC) {
+  Descriptor* desc =
+      UNBOX_HASHTABLE_VALUE(Descriptor, get_ce_obj(Z_OBJCE_P(val)));
+
+  stringsink sink;
+  stringsink_init(&sink);
+
+  {
+    const upb_handlers* serialize_handlers = msgdef_pb_serialize_handlers(desc);
+
+    stackenv se;
+    upb_pb_encoder* encoder;
+
+    stackenv_init(&se, "Error occurred during encoding: %s");
+    encoder = upb_pb_encoder_create(&se.env, serialize_handlers, &sink.sink);
+
+    putmsg(val, desc, upb_pb_encoder_input(encoder), 0 TSRMLS_CC);
+
+    PHP_PROTO_RETVAL_STRINGL(sink.ptr, sink.len, 1);
+
+    stackenv_uninit(&se);
+    stringsink_uninit(&sink);
+  }
+}
+
+PHP_METHOD(Message, serializeToString) {
+  serialize_to_string(getThis(), return_value TSRMLS_CC);
+}
+
+void merge_from_string(const char* data, int data_len, const Descriptor* desc,
+                       MessageHeader* msg) {
+  const upb_pbdecodermethod* method = msgdef_decodermethod(desc);
+  const upb_handlers* h = upb_pbdecodermethod_desthandlers(method);
+  stackenv se;
+  upb_sink sink;
+  upb_pbdecoder* decoder;
+  stackenv_init(&se, "Error occurred during parsing: %s");
+
+  upb_sink_reset(&sink, h, msg);
+  decoder = upb_pbdecoder_create(&se.env, method, &sink);
+  upb_bufsrc_putbuf(data, data_len, upb_pbdecoder_input(decoder));
+
+  stackenv_uninit(&se);
+}
+
+PHP_METHOD(Message, mergeFromString) {
+  Descriptor* desc =
+      UNBOX_HASHTABLE_VALUE(Descriptor, get_ce_obj(Z_OBJCE_P(getThis())));
+  MessageHeader* msg = UNBOX(MessageHeader, getThis());
+
+  char *data = NULL;
+  PHP_PROTO_SIZE data_len;
+
+  if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &data, &data_len) ==
+      FAILURE) {
+    return;
+  }
+
+  merge_from_string(data, data_len, desc, msg);
+}
+
+PHP_METHOD(Message, serializeToJsonString) {
+  Descriptor* desc =
+      UNBOX_HASHTABLE_VALUE(Descriptor, get_ce_obj(Z_OBJCE_P(getThis())));
+
+  zend_bool preserve_proto_fieldnames = false;
+  if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|b",
+                            &preserve_proto_fieldnames) == FAILURE) {
+    return;
+  }
+
+  stringsink sink;
+  stringsink_init(&sink);
+
+  {
+    const upb_handlers* serialize_handlers =
+        msgdef_json_serialize_handlers(desc, preserve_proto_fieldnames);
+    upb_json_printer* printer;
+    stackenv se;
+
+    stackenv_init(&se, "Error occurred during encoding: %s");
+    printer = upb_json_printer_create(&se.env, serialize_handlers, &sink.sink);
+
+    putmsg(getThis(), desc, upb_json_printer_input(printer), 0 TSRMLS_CC);
+
+    PHP_PROTO_RETVAL_STRINGL(sink.ptr, sink.len, 1);
+
+    stackenv_uninit(&se);
+    stringsink_uninit(&sink);
+  }
+}
+
+PHP_METHOD(Message, mergeFromJsonString) {
+  Descriptor* desc =
+      UNBOX_HASHTABLE_VALUE(Descriptor, get_ce_obj(Z_OBJCE_P(getThis())));
+  MessageHeader* msg = UNBOX(MessageHeader, getThis());
+
+  char *data = NULL;
+  PHP_PROTO_SIZE data_len;
+
+  if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &data, &data_len) ==
+      FAILURE) {
+    return;
+  }
+
+  // TODO(teboring): Check and respect string encoding. If not UTF-8, we need to
+  // convert, because string handlers pass data directly to message string
+  // fields.
+
+  // TODO(teboring): Clear message.
+
+  {
+    const upb_json_parsermethod* method = msgdef_jsonparsermethod(desc);
+    stackenv se;
+    upb_sink sink;
+    upb_json_parser* parser;
+    stackenv_init(&se, "Error occurred during parsing: %s");
+
+    upb_sink_reset(&sink, get_fill_handlers(desc), msg);
+    parser = upb_json_parser_create(&se.env, method, &sink);
+    upb_bufsrc_putbuf(data, data_len, upb_json_parser_input(parser));
+
+    stackenv_uninit(&se);
+  }
+}
+
+// TODO(teboring): refactoring with putrawmsg
+static void discard_unknown_fields(MessageHeader* msg) {
+  upb_msg_field_iter it;
+
+  stringsink* unknown = DEREF(message_data(msg), 0, stringsink*);
+  if (unknown != NULL) {
+    stringsink_uninit(unknown);
+    FREE(unknown);
+    DEREF(message_data(msg), 0, stringsink*) = NULL;
+  }
+
+  // Recursively discard unknown fields of submessages.
+  Descriptor* desc = msg->descriptor;
+  TSRMLS_FETCH();
+  for (upb_msg_field_begin(&it, desc->msgdef);
+       !upb_msg_field_done(&it);
+       upb_msg_field_next(&it)) {
+    upb_fielddef* f = upb_msg_iter_field(&it);
+    uint32_t offset = desc->layout->fields[upb_fielddef_index(f)].offset;
+    bool containing_oneof = false;
+
+    if (upb_fielddef_containingoneof(f)) {
+      uint32_t oneof_case_offset =
+          desc->layout->fields[upb_fielddef_index(f)].case_offset;
+      // For a oneof, check that this field is actually present -- skip all the
+      // below if not.
+      if (DEREF(message_data(msg), oneof_case_offset, uint32_t) !=
+          upb_fielddef_number(f)) {
+        continue;
+      }
+      // Otherwise, fall through to the appropriate singular-field handler
+      // below.
+      containing_oneof = true;
+    }
+
+    if (is_map_field(f)) {
+      MapIter map_it;
+      int len, size;
+      const upb_fielddef* value_field;
+
+      value_field = map_field_value(f);
+      if (!upb_fielddef_issubmsg(value_field)) continue;
+
+      zval* map_php = CACHED_PTR_TO_ZVAL_PTR(
+          DEREF(message_data(msg), offset, CACHED_VALUE*));
+      if (map_php == NULL) continue;
+
+      Map* intern = UNBOX(Map, map_php);
+      for (map_begin(map_php, &map_it TSRMLS_CC);
+           !map_done(&map_it); map_next(&map_it)) {
+        upb_value value = map_iter_value(&map_it, &len);
+        void* memory = raw_value(upb_value_memory(&value), value_field);
+#if PHP_MAJOR_VERSION < 7
+        MessageHeader *submsg = UNBOX(MessageHeader, *(zval**)memory);
+#else
+        MessageHeader *submsg =
+            (MessageHeader*)((char*)(Z_OBJ_P((zval*)memory)) -
+                XtOffsetOf(MessageHeader, std));
+#endif
+        discard_unknown_fields(submsg);
+      }
+    } else if (upb_fielddef_isseq(f)) {
+      if (!upb_fielddef_issubmsg(f)) continue;
+
+      zval* array_php = CACHED_PTR_TO_ZVAL_PTR(
+          DEREF(message_data(msg), offset, CACHED_VALUE*));
+      if (array_php == NULL) continue;
+
+      int size, i;
+      RepeatedField* intern = UNBOX(RepeatedField, array_php);
+      HashTable *ht = PHP_PROTO_HASH_OF(intern->array);
+      size = zend_hash_num_elements(ht);
+      if (size == 0) continue;
+
+      for (i = 0; i < size; i++) {
+        void* memory = repeated_field_index_native(intern, i TSRMLS_CC);
+#if PHP_MAJOR_VERSION < 7
+        MessageHeader *submsg = UNBOX(MessageHeader, *(zval**)memory);
+#else
+        MessageHeader *submsg =
+            (MessageHeader*)((char*)(Z_OBJ_P((zval*)memory)) -
+                XtOffsetOf(MessageHeader, std));
+#endif
+        discard_unknown_fields(submsg);
+      }
+    } else if (upb_fielddef_issubmsg(f)) {
+      zval* submsg_php = CACHED_PTR_TO_ZVAL_PTR(
+          DEREF(message_data(msg), offset, CACHED_VALUE*));
+      if (Z_TYPE_P(submsg_php) == IS_NULL) continue;
+      MessageHeader* submsg = UNBOX(MessageHeader, submsg_php);
+      discard_unknown_fields(submsg);
+    }
+  }
+}
+
+PHP_METHOD(Message, discardUnknownFields) {
+  MessageHeader* msg = UNBOX(MessageHeader, getThis());
+  discard_unknown_fields(msg);
+}
diff --git a/php/ext/google/protobuf/map.c b/php/ext/google/protobuf/map.c
new file mode 100644
index 0000000..c5b500b
--- /dev/null
+++ b/php/ext/google/protobuf/map.c
@@ -0,0 +1,591 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// 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.
+
+#include <ext/spl/spl_iterators.h>
+#include <Zend/zend_API.h>
+#include <Zend/zend_interfaces.h>
+
+#include "protobuf.h"
+#include "utf8.h"
+
+ZEND_BEGIN_ARG_INFO_EX(arginfo_offsetGet, 0, 0, 1)
+  ZEND_ARG_INFO(0, index)
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_INFO_EX(arginfo_offsetSet, 0, 0, 2)
+  ZEND_ARG_INFO(0, index)
+  ZEND_ARG_INFO(0, newval)
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_INFO(arginfo_void, 0)
+ZEND_END_ARG_INFO()
+
+// Utilities
+
+void* upb_value_memory(upb_value* v) {
+  return (void*)(&v->val);
+}
+
+// -----------------------------------------------------------------------------
+// Basic map operations on top of upb's strtable.
+//
+// Note that we roll our own `Map` container here because, as for
+// `RepeatedField`, we want a strongly-typed container. This is so that any user
+// errors due to incorrect map key or value types are raised as close as
+// possible to the error site, rather than at some deferred point (e.g.,
+// serialization).
+//
+// We build our `Map` on top of upb_strtable so that we're able to take
+// advantage of the native_slot storage abstraction, as RepeatedField does.
+// (This is not quite a perfect mapping -- see the key conversions below -- but
+// gives us full support and error-checking for all value types for free.)
+// -----------------------------------------------------------------------------
+
+// Map values are stored using the native_slot abstraction (as with repeated
+// field values), but keys are a bit special. Since we use a strtable, we need
+// to store keys as sequences of bytes such that equality of those bytes maps
+// one-to-one to equality of keys. We store strings directly (i.e., they map to
+// their own bytes) and integers as native integers (using the native_slot
+// abstraction).
+
+// Note that there is another tradeoff here in keeping string keys as native
+// strings rather than PHP strings: traversing the Map requires conversion to
+// PHP string values on every traversal, potentially creating more garbage. We
+// should consider ways to cache a PHP version of the key if this becomes an
+// issue later.
+
+// Forms a key to use with the underlying strtable from a PHP key value. |buf|
+// must point to TABLE_KEY_BUF_LENGTH bytes of temporary space, used to
+// construct a key byte sequence if needed. |out_key| and |out_length| provide
+// the resulting key data/length.
+#define TABLE_KEY_BUF_LENGTH 8  // sizeof(uint64_t)
+static bool table_key(Map* self, zval* key,
+                      char* buf,
+                      const char** out_key,
+                      size_t* out_length TSRMLS_DC) {
+  switch (self->key_type) {
+    case UPB_TYPE_STRING:
+      if (!protobuf_convert_to_string(key)) {
+        return false;
+      }
+      if (!is_structurally_valid_utf8(Z_STRVAL_P(key), Z_STRLEN_P(key))) {
+        zend_error(E_USER_ERROR, "Given key is not UTF8 encoded.");
+        return false;
+      }
+      *out_key = Z_STRVAL_P(key);
+      *out_length = Z_STRLEN_P(key);
+      break;
+
+#define CASE_TYPE(upb_type, type, c_type, php_type)                     \
+  case UPB_TYPE_##upb_type: {                                           \
+    c_type type##_value;                                                \
+    if (!protobuf_convert_to_##type(key, &type##_value)) {              \
+      return false;                                                     \
+    }                                                                   \
+    native_slot_set_by_array(self->key_type, NULL, buf, key TSRMLS_CC); \
+    *out_key = buf;                                                     \
+    *out_length = native_slot_size(self->key_type);                     \
+    break;                                                              \
+  }
+      CASE_TYPE(BOOL, bool, int8_t, BOOL)
+      CASE_TYPE(INT32, int32, int32_t, LONG)
+      CASE_TYPE(INT64, int64, int64_t, LONG)
+      CASE_TYPE(UINT32, uint32, uint32_t, LONG)
+      CASE_TYPE(UINT64, uint64, uint64_t, LONG)
+
+#undef CASE_TYPE
+
+    default:
+      // Map constructor should not allow a Map with another key type to be
+      // constructed.
+      assert(false);
+      break;
+  }
+
+  return true;
+}
+
+// -----------------------------------------------------------------------------
+// MapField methods
+// -----------------------------------------------------------------------------
+
+static zend_function_entry map_field_methods[] = {
+  PHP_ME(MapField, __construct,  NULL,              ZEND_ACC_PUBLIC)
+  PHP_ME(MapField, offsetExists, arginfo_offsetGet, ZEND_ACC_PUBLIC)
+  PHP_ME(MapField, offsetGet,    arginfo_offsetGet, ZEND_ACC_PUBLIC)
+  PHP_ME(MapField, offsetSet,    arginfo_offsetSet, ZEND_ACC_PUBLIC)
+  PHP_ME(MapField, offsetUnset,  arginfo_offsetGet, ZEND_ACC_PUBLIC)
+  PHP_ME(MapField, count,        arginfo_void,      ZEND_ACC_PUBLIC)
+  PHP_ME(MapField, getIterator,  arginfo_void,      ZEND_ACC_PUBLIC)
+  ZEND_FE_END
+};
+
+// Forward declare static functions.
+
+static void map_field_write_dimension(zval *object, zval *key,
+                                      zval *value TSRMLS_DC);
+
+// -----------------------------------------------------------------------------
+// MapField creation/desctruction
+// -----------------------------------------------------------------------------
+
+zend_class_entry* map_field_type;
+zend_class_entry* map_field_iter_type;
+
+zend_object_handlers* map_field_handlers;
+zend_object_handlers* map_field_iter_handlers;
+
+static void map_begin_internal(Map *map, MapIter *iter) {
+  iter->self = map;
+  upb_strtable_begin(&iter->it, &map->table);
+}
+
+static HashTable *map_field_get_gc(zval *object, CACHED_VALUE **table, int *n) {
+  // TODO(teboring): Unfortunately, zend engine does not support garbage
+  // collection for custom array. We have to use zend engine's native array
+  // instead.
+  *table = NULL;
+  *n = 0;
+  return NULL;
+}
+
+// Define map value element free function.
+#if PHP_MAJOR_VERSION < 7
+static inline void php_proto_map_string_release(void *value) {
+  zval_ptr_dtor(value);
+}
+
+static inline void php_proto_map_object_release(void *value) {
+  zval_ptr_dtor(value);
+}
+#else
+static inline void php_proto_map_string_release(void *value) {
+  zend_string* object = *(zend_string**)value;
+  zend_string_release(object);
+}
+static inline void php_proto_map_object_release(void *value) {
+  zend_object* object = *(zend_object**)value;
+  GC_DELREF(object);
+  if(GC_REFCOUNT(object) == 0) {
+    zend_objects_store_del(object);
+  }
+}
+#endif
+
+// Define object free method.
+PHP_PROTO_OBJECT_FREE_START(Map, map_field)
+MapIter it;
+int len;
+for (map_begin_internal(intern, &it); !map_done(&it); map_next(&it)) {
+  upb_value value = map_iter_value(&it, &len);
+  void *mem = upb_value_memory(&value);
+  switch (intern->value_type) {
+    case UPB_TYPE_MESSAGE:
+      php_proto_map_object_release(mem);
+      break;
+    case UPB_TYPE_STRING:
+    case UPB_TYPE_BYTES:
+      php_proto_map_string_release(mem);
+      break;
+    default:
+      break;
+  }
+}
+upb_strtable_uninit(&intern->table);
+PHP_PROTO_OBJECT_FREE_END
+
+PHP_PROTO_OBJECT_DTOR_START(Map, map_field)
+PHP_PROTO_OBJECT_DTOR_END
+
+// Define object create method.
+PHP_PROTO_OBJECT_CREATE_START(Map, map_field)
+// Table value type is always UINT64: this ensures enough space to store the
+// native_slot value.
+if (!upb_strtable_init(&intern->table, UPB_CTYPE_UINT64)) {
+  zend_error(E_USER_ERROR, "Could not allocate table.");
+}
+PHP_PROTO_OBJECT_CREATE_END(Map, map_field)
+
+// Init class entry.
+PHP_PROTO_INIT_CLASS_START("Google\\Protobuf\\Internal\\MapField", Map,
+                           map_field)
+zend_class_implements(map_field_type TSRMLS_CC, 3, spl_ce_ArrayAccess,
+                      zend_ce_aggregate, spl_ce_Countable);
+map_field_handlers->write_dimension = map_field_write_dimension;
+map_field_handlers->get_gc = map_field_get_gc;
+PHP_PROTO_INIT_CLASS_END
+
+void map_field_create_with_field(const zend_class_entry *ce,
+                                 const upb_fielddef *field,
+                                 CACHED_VALUE *map_field PHP_PROTO_TSRMLS_DC) {
+  const upb_fielddef *key_field = map_field_key(field);
+  const upb_fielddef *value_field = map_field_value(field);
+  map_field_create_with_type(
+      ce, upb_fielddef_type(key_field), upb_fielddef_type(value_field),
+      field_type_class(value_field TSRMLS_CC), map_field PHP_PROTO_TSRMLS_CC);
+}
+
+void map_field_create_with_type(const zend_class_entry *ce,
+                                upb_fieldtype_t key_type,
+                                upb_fieldtype_t value_type,
+                                const zend_class_entry *msg_ce,
+                                CACHED_VALUE *map_field PHP_PROTO_TSRMLS_DC) {
+  CREATE_OBJ_ON_ALLOCATED_ZVAL_PTR(CACHED_PTR_TO_ZVAL_PTR(map_field),
+                                   map_field_type);
+  Map *intern = UNBOX(Map, CACHED_TO_ZVAL_PTR(*map_field));
+  intern->key_type = key_type;
+  intern->value_type = value_type;
+  intern->msg_ce = msg_ce;
+}
+
+// -----------------------------------------------------------------------------
+// MapField Handlers
+// -----------------------------------------------------------------------------
+
+static bool map_field_read_dimension(zval *object, zval *key, int type,
+                                     CACHED_VALUE *retval TSRMLS_DC) {
+  Map *intern = UNBOX(Map, object);
+
+  char keybuf[TABLE_KEY_BUF_LENGTH];
+  const char* keyval = NULL;
+  size_t length = 0;
+  upb_value v;
+#ifndef NDEBUG
+  v.ctype = UPB_CTYPE_UINT64;
+#endif
+  if (!table_key(intern, key, keybuf, &keyval, &length TSRMLS_CC)) {
+    return false;
+  }
+
+  if (upb_strtable_lookup2(&intern->table, keyval, length, &v)) {
+    void* mem = upb_value_memory(&v);
+    native_slot_get_by_map_value(intern->value_type, mem, retval TSRMLS_CC);
+    return true;
+  } else {
+    zend_error(E_USER_ERROR, "Given key doesn't exist.");
+    return false;
+  }
+}
+
+static bool map_index_unset(Map *intern, const char* keyval, int length) {
+  upb_value old_value;
+  if (upb_strtable_remove2(&intern->table, keyval, length, &old_value)) {
+    switch (intern->value_type) {
+      case UPB_TYPE_MESSAGE: {
+#if PHP_MAJOR_VERSION < 7
+        zval_ptr_dtor(upb_value_memory(&old_value));
+#else
+        zend_object* object = *(zend_object**)upb_value_memory(&old_value);
+        GC_DELREF(object);
+        if(GC_REFCOUNT(object) == 0) {
+          zend_objects_store_del(object);
+        }
+#endif
+        break;
+      }
+      case UPB_TYPE_STRING:
+      case UPB_TYPE_BYTES: {
+#if PHP_MAJOR_VERSION < 7
+        zval_ptr_dtor(upb_value_memory(&old_value));
+#else
+        zend_string* object = *(zend_string**)upb_value_memory(&old_value);
+        zend_string_release(object);
+#endif
+        break;
+      }
+      default:
+        break;
+    }
+  }
+}
+
+bool map_index_set(Map *intern, const char* keyval, int length, upb_value v) {
+  // Replace any existing value by issuing a 'remove' operation first.
+  map_index_unset(intern, keyval, length);
+
+  if (!upb_strtable_insert2(&intern->table, keyval, length, v)) {
+    zend_error(E_USER_ERROR, "Could not insert into table");
+    return false;
+  }
+
+  return true;
+}
+
+static void map_field_write_dimension(zval *object, zval *key,
+                                      zval *value TSRMLS_DC) {
+  Map *intern = UNBOX(Map, object);
+
+  char keybuf[TABLE_KEY_BUF_LENGTH];
+  const char* keyval = NULL;
+  size_t length = 0;
+  upb_value v;
+  void* mem;
+  if (!table_key(intern, key, keybuf, &keyval, &length TSRMLS_CC)) {
+    return;
+  }
+
+  mem = upb_value_memory(&v);
+  memset(mem, 0, native_slot_size(intern->value_type));
+  if (!native_slot_set_by_map(intern->value_type, intern->msg_ce, mem,
+                                value TSRMLS_CC)) {
+    return;
+  }
+#ifndef NDEBUG
+  v.ctype = UPB_CTYPE_UINT64;
+#endif
+
+  map_index_set(intern, keyval, length, v);
+}
+
+static bool map_field_unset_dimension(zval *object, zval *key TSRMLS_DC) {
+  Map *intern = UNBOX(Map, object);
+
+  char keybuf[TABLE_KEY_BUF_LENGTH];
+  const char* keyval = NULL;
+  size_t length = 0;
+  upb_value v;
+  if (!table_key(intern, key, keybuf, &keyval, &length TSRMLS_CC)) {
+    return false;
+  }
+#ifndef NDEBUG
+  v.ctype = UPB_CTYPE_UINT64;
+#endif
+
+  map_index_unset(intern, keyval, length);
+
+  return true;
+}
+
+// -----------------------------------------------------------------------------
+// PHP MapField Methods
+// -----------------------------------------------------------------------------
+
+PHP_METHOD(MapField, __construct) {
+  long key_type, value_type;
+  zend_class_entry* klass = NULL;
+
+  if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ll|C", &key_type,
+                            &value_type, &klass) == FAILURE) {
+    return;
+  }
+
+  Map *intern = UNBOX(Map, getThis());
+  intern->key_type = to_fieldtype(key_type);
+  intern->value_type = to_fieldtype(value_type);
+  intern->msg_ce = klass;
+
+  // Check that the key type is an allowed type.
+  switch (intern->key_type) {
+    case UPB_TYPE_INT32:
+    case UPB_TYPE_INT64:
+    case UPB_TYPE_UINT32:
+    case UPB_TYPE_UINT64:
+    case UPB_TYPE_BOOL:
+    case UPB_TYPE_STRING:
+    case UPB_TYPE_BYTES:
+      // These are OK.
+      break;
+    default:
+      zend_error(E_USER_ERROR, "Invalid key type for map.");
+  }
+}
+
+PHP_METHOD(MapField, offsetExists) {
+  zval *key;
+  if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &key) ==
+      FAILURE) {
+    return;
+  }
+
+  Map *intern = UNBOX(Map, getThis());
+
+  char keybuf[TABLE_KEY_BUF_LENGTH];
+  const char* keyval = NULL;
+  size_t length = 0;
+  upb_value v;
+#ifndef NDEBUG
+  v.ctype = UPB_CTYPE_UINT64;
+#endif
+  if (!table_key(intern, key, keybuf, &keyval, &length TSRMLS_CC)) {
+    RETURN_BOOL(false);
+  }
+
+  RETURN_BOOL(upb_strtable_lookup2(&intern->table, keyval, length, &v));
+}
+
+PHP_METHOD(MapField, offsetGet) {
+  zval *index, *value;
+  if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &index) ==
+      FAILURE) {
+    return;
+  }
+  map_field_read_dimension(getThis(), index, BP_VAR_R,
+                           ZVAL_PTR_TO_CACHED_PTR(return_value) TSRMLS_CC);
+}
+
+PHP_METHOD(MapField, offsetSet) {
+  zval *index, *value;
+  if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "zz", &index, &value) ==
+      FAILURE) {
+    return;
+  }
+  map_field_write_dimension(getThis(), index, value TSRMLS_CC);
+}
+
+PHP_METHOD(MapField, offsetUnset) {
+  zval *index;
+  if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &index) ==
+      FAILURE) {
+    return;
+  }
+  map_field_unset_dimension(getThis(), index TSRMLS_CC);
+}
+
+PHP_METHOD(MapField, count) {
+  Map *intern = UNBOX(Map, getThis());
+
+  if (zend_parse_parameters_none() == FAILURE) {
+    return;
+  }
+
+  RETURN_LONG(upb_strtable_count(&intern->table));
+}
+
+PHP_METHOD(MapField, getIterator) {
+  CREATE_OBJ_ON_ALLOCATED_ZVAL_PTR(return_value,
+                                   map_field_iter_type);
+
+  Map *intern = UNBOX(Map, getThis());
+  MapIter *iter = UNBOX(MapIter, return_value);
+  map_begin(getThis(), iter TSRMLS_CC);
+}
+
+// -----------------------------------------------------------------------------
+// Map Iterator
+// -----------------------------------------------------------------------------
+
+void map_begin(zval *map_php, MapIter *iter TSRMLS_DC) {
+  Map *self = UNBOX(Map, map_php);
+  map_begin_internal(self, iter);
+}
+
+void map_next(MapIter *iter) {
+  upb_strtable_next(&iter->it);
+}
+
+bool map_done(MapIter *iter) {
+  return upb_strtable_done(&iter->it);
+}
+
+const char *map_iter_key(MapIter *iter, int *len) {
+  *len = upb_strtable_iter_keylength(&iter->it);
+  return upb_strtable_iter_key(&iter->it);
+}
+
+upb_value map_iter_value(MapIter *iter, int *len) {
+  *len = native_slot_size(iter->self->value_type);
+  return upb_strtable_iter_value(&iter->it);
+}
+
+// -----------------------------------------------------------------------------
+// MapFieldIter methods
+// -----------------------------------------------------------------------------
+static zend_function_entry map_field_iter_methods[] = {
+  PHP_ME(MapFieldIter, rewind,      arginfo_void, ZEND_ACC_PUBLIC)
+  PHP_ME(MapFieldIter, current,     arginfo_void, ZEND_ACC_PUBLIC)
+  PHP_ME(MapFieldIter, key,         arginfo_void, ZEND_ACC_PUBLIC)
+  PHP_ME(MapFieldIter, next,        arginfo_void, ZEND_ACC_PUBLIC)
+  PHP_ME(MapFieldIter, valid,       arginfo_void, ZEND_ACC_PUBLIC)
+  ZEND_FE_END
+};
+
+// -----------------------------------------------------------------------------
+// MapFieldIter creation/desctruction
+// -----------------------------------------------------------------------------
+
+// Define object free method.
+PHP_PROTO_OBJECT_FREE_START(MapIter, map_field_iter)
+PHP_PROTO_OBJECT_FREE_END
+
+PHP_PROTO_OBJECT_DTOR_START(MapIter, map_field_iter)
+PHP_PROTO_OBJECT_DTOR_END
+
+// Define object create method.
+PHP_PROTO_OBJECT_CREATE_START(MapIter, map_field_iter)
+intern->self = NULL;
+PHP_PROTO_OBJECT_CREATE_END(MapIter, map_field_iter)
+
+// Init class entry.
+PHP_PROTO_INIT_CLASS_START("Google\\Protobuf\\Internal\\MapFieldIter",
+                           MapIter, map_field_iter)
+zend_class_implements(map_field_iter_type TSRMLS_CC, 1, zend_ce_iterator);
+PHP_PROTO_INIT_CLASS_END
+
+// -----------------------------------------------------------------------------
+// PHP MapFieldIter Methods
+// -----------------------------------------------------------------------------
+
+PHP_METHOD(MapFieldIter, rewind) {
+  MapIter *intern = UNBOX(MapIter, getThis());
+  map_begin_internal(intern->self, intern);
+}
+
+PHP_METHOD(MapFieldIter, current) {
+  MapIter *intern = UNBOX(MapIter, getThis());
+  Map *map_field = intern->self;
+
+  int value_length = 0;
+  upb_value value = map_iter_value(intern, &value_length);
+
+  void* mem = upb_value_memory(&value);
+  native_slot_get_by_map_value(map_field->value_type, mem,
+                               ZVAL_PTR_TO_CACHED_PTR(return_value) TSRMLS_CC);
+}
+
+PHP_METHOD(MapFieldIter, key) {
+  MapIter *intern = UNBOX(MapIter, getThis());
+  Map *map_field = intern->self;
+
+  int key_length = 0;
+  const char* key = map_iter_key(intern, &key_length);
+
+  native_slot_get_by_map_key(map_field->key_type, key, key_length,
+                             ZVAL_PTR_TO_CACHED_PTR(return_value) TSRMLS_CC);
+}
+
+PHP_METHOD(MapFieldIter, next) {
+  MapIter *intern = UNBOX(MapIter, getThis());
+  map_next(intern);
+}
+
+PHP_METHOD(MapFieldIter, valid) {
+  MapIter *intern = UNBOX(MapIter, getThis());
+  RETURN_BOOL(!map_done(intern));
+}
diff --git a/php/ext/google/protobuf/message.c b/php/ext/google/protobuf/message.c
new file mode 100644
index 0000000..76b97ee
--- /dev/null
+++ b/php/ext/google/protobuf/message.c
@@ -0,0 +1,2238 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2014 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// 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.
+
+#include <php.h>
+#include <stdlib.h>
+
+#include "protobuf.h"
+#include "utf8.h"
+
+zend_class_entry* message_type;
+zend_object_handlers* message_handlers;
+static const char TYPE_URL_PREFIX[] = "type.googleapis.com/";
+static void hex_to_binary(const char* hex, char** binary, int* binary_len);
+
+static  zend_function_entry message_methods[] = {
+  PHP_ME(Message, clear, NULL, ZEND_ACC_PUBLIC)
+  PHP_ME(Message, discardUnknownFields, NULL, ZEND_ACC_PUBLIC)
+  PHP_ME(Message, serializeToString, NULL, ZEND_ACC_PUBLIC)
+  PHP_ME(Message, mergeFromString, NULL, ZEND_ACC_PUBLIC)
+  PHP_ME(Message, serializeToJsonString, NULL, ZEND_ACC_PUBLIC)
+  PHP_ME(Message, mergeFromJsonString, NULL, ZEND_ACC_PUBLIC)
+  PHP_ME(Message, mergeFrom, NULL, ZEND_ACC_PUBLIC)
+  PHP_ME(Message, readOneof, NULL, ZEND_ACC_PROTECTED)
+  PHP_ME(Message, writeOneof, NULL, ZEND_ACC_PROTECTED)
+  PHP_ME(Message, whichOneof, NULL, ZEND_ACC_PROTECTED)
+  PHP_ME(Message, __construct, NULL, ZEND_ACC_PROTECTED)
+  {NULL, NULL, NULL}
+};
+
+// Forward declare static functions.
+
+#if PHP_MAJOR_VERSION < 7
+static void message_set_property(zval* object, zval* member, zval* value,
+                                 php_proto_zend_literal key TSRMLS_DC);
+static zval* message_get_property(zval* object, zval* member, int type,
+                                  const zend_literal* key TSRMLS_DC);
+static zval** message_get_property_ptr_ptr(zval* object, zval* member, int type,
+                                           php_proto_zend_literal key TSRMLS_DC);
+static HashTable* message_get_gc(zval* object, zval*** table, int* n TSRMLS_DC);
+#else
+static void message_set_property(zval* object, zval* member, zval* value,
+                                 void** cache_slot);
+static zval* message_get_property(zval* object, zval* member, int type,
+                                  void** cache_slot, zval* rv);
+static zval* message_get_property_ptr_ptr(zval* object, zval* member, int type,
+                                          void** cache_slot);
+static HashTable* message_get_gc(zval* object, zval** table, int* n);
+#endif
+static HashTable* message_get_properties(zval* object TSRMLS_DC);
+
+// -----------------------------------------------------------------------------
+// PHP Message Handlers
+// -----------------------------------------------------------------------------
+
+// Define object free method.
+PHP_PROTO_OBJECT_FREE_START(MessageHeader, message)
+  if (*(void**)intern->data != NULL) {
+    stringsink_uninit(*(void**)intern->data);
+    FREE(*(void**)intern->data);
+  }
+  FREE(intern->data);
+PHP_PROTO_OBJECT_FREE_END
+
+PHP_PROTO_OBJECT_DTOR_START(MessageHeader, message)
+PHP_PROTO_OBJECT_DTOR_END
+
+// Define object create method.
+PHP_PROTO_OBJECT_CREATE_START(MessageHeader, message)
+// Because php call this create func before calling the sub-message's
+// constructor defined in PHP, it's possible that the decriptor of this class
+// hasn't been added to descritpor pool (when the class is first
+// instantiated). In that case, we will defer the initialization of the custom
+// data to the parent Message's constructor, which will be called by
+// sub-message's constructors after the descriptor has been added.
+PHP_PROTO_OBJECT_CREATE_END(MessageHeader, message)
+
+// Init class entry.
+PHP_PROTO_INIT_CLASS_START("Google\\Protobuf\\Internal\\Message",
+                           MessageHeader, message)
+  message_handlers->write_property = message_set_property;
+  message_handlers->read_property = message_get_property;
+  message_handlers->get_property_ptr_ptr = message_get_property_ptr_ptr;
+  message_handlers->get_properties = message_get_properties;
+  message_handlers->get_gc = message_get_gc;
+PHP_PROTO_INIT_CLASS_END
+
+static void message_set_property_internal(zval* object, zval* member,
+                                          zval* value TSRMLS_DC) {
+  const upb_fielddef* field;
+
+  MessageHeader* self = UNBOX(MessageHeader, object);
+
+  field = upb_msgdef_ntofz(self->descriptor->msgdef, Z_STRVAL_P(member));
+  if (field == NULL) {
+    zend_error(E_USER_ERROR, "Unknown field: %s", Z_STRVAL_P(member));
+  }
+
+  layout_set(self->descriptor->layout, self, field, value TSRMLS_CC);
+}
+
+#if PHP_MAJOR_VERSION < 7
+static void message_set_property(zval* object, zval* member, zval* value,
+                                 php_proto_zend_literal key TSRMLS_DC) {
+#else
+static void message_set_property(zval* object, zval* member, zval* value,
+                                 void** cache_slot) {
+#endif
+  if (Z_TYPE_P(member) != IS_STRING) {
+    zend_error(E_USER_ERROR, "Unexpected type for field name");
+    return;
+  }
+
+#if PHP_MAJOR_VERSION < 7 || (PHP_MAJOR_VERSION == 7 && PHP_MINOR_VERSION == 0)
+  if (Z_OBJCE_P(object) != EG(scope)) {
+#else
+  if (Z_OBJCE_P(object) != zend_get_executed_scope()) {
+#endif
+    // User cannot set property directly (e.g., $m->a = 1)
+    zend_error(E_USER_ERROR, "Cannot access private property.");
+    return;
+  }
+
+  message_set_property_internal(object, member, value TSRMLS_CC);
+}
+
+static zval* message_get_property_internal(zval* object,
+                                           zval* member TSRMLS_DC) {
+  MessageHeader* self = UNBOX(MessageHeader, object);
+  const upb_fielddef* field;
+  field = upb_msgdef_ntofz(self->descriptor->msgdef, Z_STRVAL_P(member));
+  if (field == NULL) {
+    return PHP_PROTO_GLOBAL_UNINITIALIZED_ZVAL;
+  }
+
+  zend_property_info* property_info;
+#if PHP_MAJOR_VERSION < 7
+  property_info =
+      zend_get_property_info(Z_OBJCE_P(object), member, true TSRMLS_CC);
+#else
+  property_info =
+      zend_get_property_info(Z_OBJCE_P(object), Z_STR_P(member), true);
+#endif
+  return layout_get(
+      self->descriptor->layout, message_data(self), field,
+      OBJ_PROP(Z_OBJ_P(object), property_info->offset) TSRMLS_CC);
+}
+
+static void message_get_oneof_property_internal(zval* object, zval* member,
+                                                zval* return_value TSRMLS_DC) {
+  MessageHeader* self = UNBOX(MessageHeader, object);
+  const upb_fielddef* field;
+  field = upb_msgdef_ntofz(self->descriptor->msgdef, Z_STRVAL_P(member));
+  if (field == NULL) {
+    return;
+  }
+
+  layout_get(self->descriptor->layout, message_data(self), field,
+             ZVAL_PTR_TO_CACHED_PTR(return_value) TSRMLS_CC);
+}
+
+#if PHP_MAJOR_VERSION < 7
+static zval* message_get_property(zval* object, zval* member, int type,
+                                  const zend_literal* key TSRMLS_DC) {
+#else
+static zval* message_get_property(zval* object, zval* member, int type,
+                                  void** cache_slot, zval* rv) {
+#endif
+  if (Z_TYPE_P(member) != IS_STRING) {
+    zend_error(E_USER_ERROR, "Property name has to be a string.");
+    return PHP_PROTO_GLOBAL_UNINITIALIZED_ZVAL;
+  }
+
+#if PHP_MAJOR_VERSION < 7 || (PHP_MAJOR_VERSION == 7 && PHP_MINOR_VERSION == 0)
+  if (Z_OBJCE_P(object) != EG(scope)) {
+#else
+  if (Z_OBJCE_P(object) != zend_get_executed_scope()) {
+#endif
+    // User cannot get property directly (e.g., $a = $m->a)
+    zend_error(E_USER_ERROR, "Cannot access private property.");
+    return PHP_PROTO_GLOBAL_UNINITIALIZED_ZVAL;
+  }
+
+  return message_get_property_internal(object, member TSRMLS_CC);
+}
+
+#if PHP_MAJOR_VERSION < 7
+static zval** message_get_property_ptr_ptr(zval* object, zval* member, int type,
+                                           php_proto_zend_literal key
+                                               TSRMLS_DC) {
+#else
+static zval* message_get_property_ptr_ptr(zval* object, zval* member, int type,
+                                          void** cache_slot) {
+#endif
+  return NULL;
+}
+
+static HashTable* message_get_properties(zval* object TSRMLS_DC) {
+  return NULL;
+}
+
+static HashTable* message_get_gc(zval* object, CACHED_VALUE** table,
+                                 int* n TSRMLS_DC) {
+  zend_object* zobj = Z_OBJ_P(object);
+  *table = zobj->properties_table;
+  *n = zobj->ce->default_properties_count;
+  return NULL;
+}
+
+// -----------------------------------------------------------------------------
+// C Message Utilities
+// -----------------------------------------------------------------------------
+
+void* message_data(MessageHeader* msg) {
+  return msg->data;
+}
+
+void custom_data_init(const zend_class_entry* ce,
+                      MessageHeader* intern PHP_PROTO_TSRMLS_DC) {
+  Descriptor* desc = UNBOX_HASHTABLE_VALUE(Descriptor, get_ce_obj(ce));
+  intern->data = ALLOC_N(uint8_t, desc->layout->size);
+  memset(message_data(intern), 0, desc->layout->size);
+  // We wrap first so that everything in the message object is GC-rooted in
+  // case a collection happens during object creation in layout_init().
+  intern->descriptor = desc;
+  layout_init(desc->layout, message_data(intern),
+              &intern->std PHP_PROTO_TSRMLS_CC);
+}
+
+void build_class_from_descriptor(
+    PHP_PROTO_HASHTABLE_VALUE php_descriptor TSRMLS_DC) {
+  Descriptor* desc = UNBOX_HASHTABLE_VALUE(Descriptor, php_descriptor);
+
+  // Map entries don't have existing php class.
+  if (upb_msgdef_mapentry(desc->msgdef)) {
+    return;
+  }
+
+  zend_class_entry* registered_ce = desc->klass;
+
+  if (desc->layout == NULL) {
+    MessageLayout* layout = create_layout(desc->msgdef);
+    desc->layout = layout;
+  }
+
+  registered_ce->create_object = message_create;
+}
+
+// -----------------------------------------------------------------------------
+// PHP Methods
+// -----------------------------------------------------------------------------
+
+void Message_construct(zval* msg, zval* array_wrapper) {
+  TSRMLS_FETCH();
+  zend_class_entry* ce = Z_OBJCE_P(msg);
+  MessageHeader* intern = NULL;
+  if (EXPECTED(class_added(ce))) {
+    intern = UNBOX(MessageHeader, msg);
+    custom_data_init(ce, intern PHP_PROTO_TSRMLS_CC);
+  }
+
+  if (array_wrapper == NULL) {
+    return;
+  }
+
+  HashTable* array = Z_ARRVAL_P(array_wrapper);
+  HashPosition pointer;
+  zval key;
+  void* value;
+  const upb_fielddef* field;
+
+  for (zend_hash_internal_pointer_reset_ex(array, &pointer);
+       php_proto_zend_hash_get_current_data_ex(array, (void**)&value,
+                                               &pointer) == SUCCESS;
+       zend_hash_move_forward_ex(array, &pointer)) {
+    zend_hash_get_current_key_zval_ex(array, &key, &pointer);
+    field = upb_msgdef_ntofz(intern->descriptor->msgdef, Z_STRVAL_P(&key));
+    if (field == NULL) {
+      zend_error(E_USER_ERROR, "Unknown field: %s", Z_STRVAL_P(&key));
+    }
+    if (upb_fielddef_ismap(field)) {
+      PHP_PROTO_FAKE_SCOPE_BEGIN(Z_OBJCE_P(msg));
+      zval* submap = message_get_property_internal(msg, &key TSRMLS_CC);
+      PHP_PROTO_FAKE_SCOPE_END;
+      HashTable* subtable = HASH_OF(
+          CACHED_PTR_TO_ZVAL_PTR((CACHED_VALUE*)value));
+      HashPosition subpointer;
+      zval subkey;
+      void* memory;
+      for (zend_hash_internal_pointer_reset_ex(subtable, &subpointer);
+           php_proto_zend_hash_get_current_data_ex(subtable, (void**)&memory,
+                                                   &subpointer) == SUCCESS;
+           zend_hash_move_forward_ex(subtable, &subpointer)) {
+        zend_hash_get_current_key_zval_ex(subtable, &subkey, &subpointer);
+        map_field_handlers->write_dimension(
+            submap, &subkey,
+            CACHED_PTR_TO_ZVAL_PTR((CACHED_VALUE*)memory) TSRMLS_CC);
+        zval_dtor(&subkey);
+      }
+    } else if (upb_fielddef_isseq(field)) {
+      PHP_PROTO_FAKE_SCOPE_BEGIN(Z_OBJCE_P(msg));
+      zval* subarray = message_get_property_internal(msg, &key TSRMLS_CC);
+      PHP_PROTO_FAKE_SCOPE_END;
+      HashTable* subtable = HASH_OF(
+          CACHED_PTR_TO_ZVAL_PTR((CACHED_VALUE*)value));
+      HashPosition subpointer;
+      void* memory;
+      for (zend_hash_internal_pointer_reset_ex(subtable, &subpointer);
+           php_proto_zend_hash_get_current_data_ex(subtable, (void**)&memory,
+                                                   &subpointer) == SUCCESS;
+           zend_hash_move_forward_ex(subtable, &subpointer)) {
+        repeated_field_handlers->write_dimension(
+            subarray, NULL,
+            CACHED_PTR_TO_ZVAL_PTR((CACHED_VALUE*)memory) TSRMLS_CC);
+      }
+    } else if (upb_fielddef_issubmsg(field)) {
+      const upb_msgdef* submsgdef = upb_fielddef_msgsubdef(field);
+      PHP_PROTO_HASHTABLE_VALUE desc_php = get_def_obj(submsgdef);
+      Descriptor* desc = UNBOX_HASHTABLE_VALUE(Descriptor, desc_php);
+      zend_property_info* property_info;
+      PHP_PROTO_FAKE_SCOPE_BEGIN(Z_OBJCE_P(msg));
+#if PHP_MAJOR_VERSION < 7
+      property_info =
+          zend_get_property_info(Z_OBJCE_P(msg), &key, true TSRMLS_CC);
+#else
+      property_info =
+          zend_get_property_info(Z_OBJCE_P(msg), Z_STR_P(&key), true);
+#endif
+      PHP_PROTO_FAKE_SCOPE_END;
+      CACHED_VALUE* cached = OBJ_PROP(Z_OBJ_P(msg), property_info->offset);
+#if PHP_MAJOR_VERSION < 7
+      SEPARATE_ZVAL_IF_NOT_REF(cached);
+#endif
+      zval* submsg = CACHED_PTR_TO_ZVAL_PTR(cached);
+      ZVAL_OBJ(submsg, desc->klass->create_object(desc->klass TSRMLS_CC));
+      Message_construct(submsg, NULL);
+      MessageHeader* from = UNBOX(MessageHeader,
+                                  CACHED_PTR_TO_ZVAL_PTR((CACHED_VALUE*)value));
+      MessageHeader* to = UNBOX(MessageHeader, submsg);
+      if(from->descriptor != to->descriptor) {
+        zend_error(E_USER_ERROR, "Cannot merge messages with different class.");
+        return;
+      }
+
+      layout_merge(from->descriptor->layout, from, to TSRMLS_CC);
+    } else {
+      message_set_property_internal(msg, &key,
+          CACHED_PTR_TO_ZVAL_PTR((CACHED_VALUE*)value) TSRMLS_CC);
+    }
+    zval_dtor(&key);
+  }
+}
+
+// At the first time the message is created, the class entry hasn't been
+// modified. As a result, the first created instance will be a normal zend
+// object. Here, we manually modify it to our message in such a case.
+PHP_METHOD(Message, __construct) {
+  // Init message with array
+  zval* array_wrapper = NULL;
+  if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC,
+                            "|a!", &array_wrapper) == FAILURE) {
+    return;
+  }
+
+  Message_construct(getThis(), array_wrapper);
+}
+
+PHP_METHOD(Message, clear) {
+  MessageHeader* msg = UNBOX(MessageHeader, getThis());
+  Descriptor* desc = msg->descriptor;
+  zend_class_entry* ce = desc->klass;
+
+  zend_object_std_dtor(&msg->std TSRMLS_CC);
+  object_properties_init(&msg->std, ce);
+
+  layout_init(desc->layout, message_data(msg), &msg->std TSRMLS_CC);
+}
+
+PHP_METHOD(Message, mergeFrom) {
+  zval* value;
+  if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O", &value,
+                            message_type) == FAILURE) {
+    return;
+  }
+
+  MessageHeader* from = UNBOX(MessageHeader, value);
+  MessageHeader* to = UNBOX(MessageHeader, getThis());
+
+  if(from->descriptor != to->descriptor) {
+    zend_error(E_USER_ERROR, "Cannot merge messages with different class.");
+    return;
+  }
+
+  layout_merge(from->descriptor->layout, from, to TSRMLS_CC);
+}
+
+PHP_METHOD(Message, readOneof) {
+  PHP_PROTO_LONG index;
+
+  if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &index) ==
+      FAILURE) {
+    return;
+  }
+
+  MessageHeader* msg = UNBOX(MessageHeader, getThis());
+
+  const upb_fielddef* field = upb_msgdef_itof(msg->descriptor->msgdef, index);
+
+  // Unlike singular fields, oneof fields share cached property. So we cannot
+  // let lay_get modify the cached property. Instead, we pass in the return
+  // value directly.
+  layout_get(msg->descriptor->layout, message_data(msg), field,
+             ZVAL_PTR_TO_CACHED_PTR(return_value) TSRMLS_CC);
+}
+
+PHP_METHOD(Message, writeOneof) {
+  PHP_PROTO_LONG index;
+  zval* value;
+  if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "lz", &index, &value) ==
+      FAILURE) {
+    return;
+  }
+
+  MessageHeader* msg = UNBOX(MessageHeader, getThis());
+
+  const upb_fielddef* field = upb_msgdef_itof(msg->descriptor->msgdef, index);
+
+  layout_set(msg->descriptor->layout, msg, field, value TSRMLS_CC);
+}
+
+PHP_METHOD(Message, whichOneof) {
+  char* oneof_name;
+  PHP_PROTO_SIZE length;
+
+  if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &oneof_name,
+                            &length) == FAILURE) {
+    return;
+  }
+
+  MessageHeader* msg = UNBOX(MessageHeader, getThis());
+
+  const upb_oneofdef* oneof =
+      upb_msgdef_ntoo(msg->descriptor->msgdef, oneof_name, length);
+  const char* oneof_case_name = layout_get_oneof_case(
+      msg->descriptor->layout, message_data(msg), oneof TSRMLS_CC);
+  PHP_PROTO_RETURN_STRING(oneof_case_name, 1);
+}
+
+// -----------------------------------------------------------------------------
+// Well Known Types Support
+// -----------------------------------------------------------------------------
+
+#define PHP_PROTO_FIELD_ACCESSORS(UPPER_CLASS, LOWER_CLASS, UPPER_FIELD,       \
+                                  LOWER_FIELD)                                 \
+  PHP_METHOD(UPPER_CLASS, get##UPPER_FIELD) {                                  \
+    zval member;                                                               \
+    PHP_PROTO_ZVAL_STRING(&member, LOWER_FIELD, 1);                            \
+    PHP_PROTO_FAKE_SCOPE_BEGIN(LOWER_CLASS##_type);                            \
+    zval* value = message_get_property_internal(getThis(), &member TSRMLS_CC); \
+    PHP_PROTO_FAKE_SCOPE_END;                                                  \
+    zval_dtor(&member);                                                        \
+    PHP_PROTO_RETVAL_ZVAL(value);                                              \
+  }                                                                            \
+  PHP_METHOD(UPPER_CLASS, set##UPPER_FIELD) {                                  \
+    zval* value = NULL;                                                        \
+    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &value) ==       \
+        FAILURE) {                                                             \
+      return;                                                                  \
+    }                                                                          \
+    zval member;                                                               \
+    PHP_PROTO_ZVAL_STRING(&member, LOWER_FIELD, 1);                            \
+    message_set_property_internal(getThis(), &member, value TSRMLS_CC);        \
+    zval_dtor(&member);                                                        \
+    PHP_PROTO_RETVAL_ZVAL(getThis());                                          \
+  }
+
+#define PHP_PROTO_ONEOF_FIELD_ACCESSORS(UPPER_CLASS, LOWER_CLASS, UPPER_FIELD, \
+                                        LOWER_FIELD)                           \
+  PHP_METHOD(UPPER_CLASS, get##UPPER_FIELD) {                                  \
+    zval member;                                                               \
+    PHP_PROTO_ZVAL_STRING(&member, LOWER_FIELD, 1);                            \
+    PHP_PROTO_FAKE_SCOPE_BEGIN(LOWER_CLASS##_type);                            \
+    message_get_oneof_property_internal(getThis(), &member,                    \
+                                        return_value TSRMLS_CC);               \
+    PHP_PROTO_FAKE_SCOPE_END;                                                  \
+    zval_dtor(&member);                                                        \
+  }                                                                            \
+  PHP_METHOD(UPPER_CLASS, set##UPPER_FIELD) {                                  \
+    zval* value = NULL;                                                        \
+    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &value) ==       \
+        FAILURE) {                                                             \
+      return;                                                                  \
+    }                                                                          \
+    zval member;                                                               \
+    PHP_PROTO_ZVAL_STRING(&member, LOWER_FIELD, 1);                            \
+    message_set_property_internal(getThis(), &member, value TSRMLS_CC);        \
+    zval_dtor(&member);                                                        \
+    PHP_PROTO_RETVAL_ZVAL(getThis());                                          \
+  }
+
+#define PHP_PROTO_ONEOF_ACCESSORS(UPPER_CLASS, LOWER_CLASS, UPPER_FIELD, \
+                                  LOWER_FIELD)                           \
+  PHP_METHOD(UPPER_CLASS, get##UPPER_FIELD) {                            \
+    MessageHeader* msg = UNBOX(MessageHeader, getThis());                \
+    PHP_PROTO_FAKE_SCOPE_BEGIN(LOWER_CLASS##_type);                      \
+    const upb_oneofdef* oneof = upb_msgdef_ntoo(                         \
+        msg->descriptor->msgdef, LOWER_FIELD, strlen(LOWER_FIELD));      \
+    const char* oneof_case_name = layout_get_oneof_case(                 \
+        msg->descriptor->layout, message_data(msg), oneof TSRMLS_CC);    \
+    PHP_PROTO_FAKE_SCOPE_END;                                            \
+    PHP_PROTO_RETURN_STRING(oneof_case_name, 1);                         \
+  }
+
+// Forward declare file init functions
+static void init_file_any(TSRMLS_D);
+static void init_file_api(TSRMLS_D);
+static void init_file_duration(TSRMLS_D);
+static void init_file_field_mask(TSRMLS_D);
+static void init_file_empty(TSRMLS_D);
+static void init_file_source_context(TSRMLS_D);
+static void init_file_struct(TSRMLS_D);
+static void init_file_timestamp(TSRMLS_D);
+static void init_file_type(TSRMLS_D);
+static void init_file_wrappers(TSRMLS_D);
+
+// Define file init functions
+static void init_file_any(TSRMLS_D) {
+  if (is_inited_file_any) return;
+  init_generated_pool_once(TSRMLS_C);
+  const char* generated_file =
+      "0acd010a19676f6f676c652f70726f746f6275662f616e792e70726f746f"
+      "120f676f6f676c652e70726f746f62756622260a03416e7912100a087479"
+      "70655f75726c180120012809120d0a0576616c756518022001280c426f0a"
+      "13636f6d2e676f6f676c652e70726f746f6275664208416e7950726f746f"
+      "50015a256769746875622e636f6d2f676f6c616e672f70726f746f627566"
+      "2f7074797065732f616e79a20203475042aa021e476f6f676c652e50726f"
+      "746f6275662e57656c6c4b6e6f776e5479706573620670726f746f33";
+  char* binary;
+  int binary_len;
+  hex_to_binary(generated_file, &binary, &binary_len);
+  internal_add_generated_file(binary, binary_len, generated_pool TSRMLS_CC);
+  FREE(binary);
+  is_inited_file_any = true;
+}
+
+static void init_file_api(TSRMLS_D) {
+  if (is_inited_file_api) return;
+  init_file_source_context(TSRMLS_C);
+  init_file_type(TSRMLS_C);
+  init_generated_pool_once(TSRMLS_C);
+  const char* generated_file =
+      "0aee050a19676f6f676c652f70726f746f6275662f6170692e70726f746f"
+      "120f676f6f676c652e70726f746f6275661a24676f6f676c652f70726f74"
+      "6f6275662f736f757263655f636f6e746578742e70726f746f1a1a676f6f"
+      "676c652f70726f746f6275662f747970652e70726f746f2281020a034170"
+      "69120c0a046e616d6518012001280912280a076d6574686f647318022003"
+      "280b32172e676f6f676c652e70726f746f6275662e4d6574686f6412280a"
+      "076f7074696f6e7318032003280b32172e676f6f676c652e70726f746f62"
+      "75662e4f7074696f6e120f0a0776657273696f6e18042001280912360a0e"
+      "736f757263655f636f6e7465787418052001280b321e2e676f6f676c652e"
+      "70726f746f6275662e536f75726365436f6e7465787412260a066d697869"
+      "6e7318062003280b32162e676f6f676c652e70726f746f6275662e4d6978"
+      "696e12270a0673796e74617818072001280e32172e676f6f676c652e7072"
+      "6f746f6275662e53796e74617822d5010a064d6574686f64120c0a046e61"
+      "6d6518012001280912180a10726571756573745f747970655f75726c1802"
+      "2001280912190a11726571756573745f73747265616d696e671803200128"
+      "0812190a11726573706f6e73655f747970655f75726c180420012809121a"
+      "0a12726573706f6e73655f73747265616d696e6718052001280812280a07"
+      "6f7074696f6e7318062003280b32172e676f6f676c652e70726f746f6275"
+      "662e4f7074696f6e12270a0673796e74617818072001280e32172e676f6f"
+      "676c652e70726f746f6275662e53796e74617822230a054d6978696e120c"
+      "0a046e616d65180120012809120c0a04726f6f7418022001280942750a13"
+      "636f6d2e676f6f676c652e70726f746f627566420841706950726f746f50"
+      "015a2b676f6f676c652e676f6c616e672e6f72672f67656e70726f746f2f"
+      "70726f746f6275662f6170693b617069a20203475042aa021e476f6f676c"
+      "652e50726f746f6275662e57656c6c4b6e6f776e5479706573620670726f"
+      "746f33";
+  char* binary;
+  int binary_len;
+  hex_to_binary(generated_file, &binary, &binary_len);
+  internal_add_generated_file(binary, binary_len, generated_pool TSRMLS_CC);
+  FREE(binary);
+  is_inited_file_api = true;
+}
+
+static void init_file_duration(TSRMLS_D) {
+  if (is_inited_file_duration) return;
+  init_generated_pool_once(TSRMLS_C);
+  const char* generated_file =
+      "0ae3010a1e676f6f676c652f70726f746f6275662f6475726174696f6e2e"
+      "70726f746f120f676f6f676c652e70726f746f627566222a0a0844757261"
+      "74696f6e120f0a077365636f6e6473180120012803120d0a056e616e6f73"
+      "180220012805427c0a13636f6d2e676f6f676c652e70726f746f62756642"
+      "0d4475726174696f6e50726f746f50015a2a6769746875622e636f6d2f67"
+      "6f6c616e672f70726f746f6275662f7074797065732f6475726174696f6e"
+      "f80101a20203475042aa021e476f6f676c652e50726f746f6275662e5765"
+      "6c6c4b6e6f776e5479706573620670726f746f33";
+  char* binary;
+  int binary_len;
+  hex_to_binary(generated_file, &binary, &binary_len);
+  internal_add_generated_file(binary, binary_len, generated_pool TSRMLS_CC);
+  FREE(binary);
+  is_inited_file_duration = true;
+}
+
+static void init_file_field_mask(TSRMLS_D) {
+  if (is_inited_file_field_mask) return;
+  init_generated_pool_once(TSRMLS_C);
+  const char* generated_file =
+      "0ae3010a20676f6f676c652f70726f746f6275662f6669656c645f6d6173"
+      "6b2e70726f746f120f676f6f676c652e70726f746f627566221a0a094669"
+      "656c644d61736b120d0a0570617468731801200328094289010a13636f6d"
+      "2e676f6f676c652e70726f746f627566420e4669656c644d61736b50726f"
+      "746f50015a39676f6f676c652e676f6c616e672e6f72672f67656e70726f"
+      "746f2f70726f746f6275662f6669656c645f6d61736b3b6669656c645f6d"
+      "61736ba20203475042aa021e476f6f676c652e50726f746f6275662e5765"
+      "6c6c4b6e6f776e5479706573620670726f746f33";
+  char* binary;
+  int binary_len;
+  hex_to_binary(generated_file, &binary, &binary_len);
+  internal_add_generated_file(binary, binary_len, generated_pool TSRMLS_CC);
+  FREE(binary);
+  is_inited_file_field_mask = true;
+}
+
+static void init_file_empty(TSRMLS_D) {
+  if (is_inited_file_empty) return;
+  init_generated_pool_once(TSRMLS_C);
+  const char* generated_file =
+      "0ab7010a1b676f6f676c652f70726f746f6275662f656d7074792e70726f"
+      "746f120f676f6f676c652e70726f746f62756622070a05456d7074794276"
+      "0a13636f6d2e676f6f676c652e70726f746f627566420a456d7074795072"
+      "6f746f50015a276769746875622e636f6d2f676f6c616e672f70726f746f"
+      "6275662f7074797065732f656d707479f80101a20203475042aa021e476f"
+      "6f676c652e50726f746f6275662e57656c6c4b6e6f776e54797065736206"
+      "70726f746f33";
+  char* binary;
+  int binary_len;
+  hex_to_binary(generated_file, &binary, &binary_len);
+  internal_add_generated_file(binary, binary_len, generated_pool TSRMLS_CC);
+  FREE(binary);
+  is_inited_file_empty = true;
+}
+
+static void init_file_source_context(TSRMLS_D) {
+  if (is_inited_file_source_context) return;
+  init_generated_pool_once(TSRMLS_C);
+  const char* generated_file =
+      "0afb010a24676f6f676c652f70726f746f6275662f736f757263655f636f"
+      "6e746578742e70726f746f120f676f6f676c652e70726f746f6275662222"
+      "0a0d536f75726365436f6e7465787412110a0966696c655f6e616d651801"
+      "200128094295010a13636f6d2e676f6f676c652e70726f746f6275664212"
+      "536f75726365436f6e7465787450726f746f50015a41676f6f676c652e67"
+      "6f6c616e672e6f72672f67656e70726f746f2f70726f746f6275662f736f"
+      "757263655f636f6e746578743b736f757263655f636f6e74657874a20203"
+      "475042aa021e476f6f676c652e50726f746f6275662e57656c6c4b6e6f77"
+      "6e5479706573620670726f746f33";
+  char* binary;
+  int binary_len;
+  hex_to_binary(generated_file, &binary, &binary_len);
+  internal_add_generated_file(binary, binary_len, generated_pool TSRMLS_CC);
+  FREE(binary);
+  is_inited_file_source_context = true;
+}
+
+static void init_file_struct(TSRMLS_D) {
+  if (is_inited_file_struct) return;
+  init_generated_pool_once(TSRMLS_C);
+  const char* generated_file =
+      "0a81050a1c676f6f676c652f70726f746f6275662f7374727563742e7072"
+      "6f746f120f676f6f676c652e70726f746f6275662284010a065374727563"
+      "7412330a066669656c647318012003280b32232e676f6f676c652e70726f"
+      "746f6275662e5374727563742e4669656c6473456e7472791a450a0b4669"
+      "656c6473456e747279120b0a036b657918012001280912250a0576616c75"
+      "6518022001280b32162e676f6f676c652e70726f746f6275662e56616c75"
+      "653a02380122ea010a0556616c756512300a0a6e756c6c5f76616c756518"
+      "012001280e321a2e676f6f676c652e70726f746f6275662e4e756c6c5661"
+      "6c7565480012160a0c6e756d6265725f76616c7565180220012801480012"
+      "160a0c737472696e675f76616c7565180320012809480012140a0a626f6f"
+      "6c5f76616c75651804200128084800122f0a0c7374727563745f76616c75"
+      "6518052001280b32172e676f6f676c652e70726f746f6275662e53747275"
+      "6374480012300a0a6c6973745f76616c756518062001280b321a2e676f6f"
+      "676c652e70726f746f6275662e4c69737456616c7565480042060a046b69"
+      "6e6422330a094c69737456616c756512260a0676616c7565731801200328"
+      "0b32162e676f6f676c652e70726f746f6275662e56616c75652a1b0a094e"
+      "756c6c56616c7565120e0a0a4e554c4c5f56414c554510004281010a1363"
+      "6f6d2e676f6f676c652e70726f746f627566420b53747275637450726f74"
+      "6f50015a316769746875622e636f6d2f676f6c616e672f70726f746f6275"
+      "662f7074797065732f7374727563743b7374727563747062f80101a20203"
+      "475042aa021e476f6f676c652e50726f746f6275662e57656c6c4b6e6f77"
+      "6e5479706573620670726f746f33";
+  char* binary;
+  int binary_len;
+  hex_to_binary(generated_file, &binary, &binary_len);
+  internal_add_generated_file(binary, binary_len, generated_pool TSRMLS_CC);
+  FREE(binary);
+  is_inited_file_struct = true;
+}
+
+static void init_file_timestamp(TSRMLS_D) {
+  if (is_inited_file_timestamp) return;
+  init_generated_pool_once(TSRMLS_C);
+  const char* generated_file =
+      "0ae7010a1f676f6f676c652f70726f746f6275662f74696d657374616d70"
+      "2e70726f746f120f676f6f676c652e70726f746f627566222b0a0954696d"
+      "657374616d70120f0a077365636f6e6473180120012803120d0a056e616e"
+      "6f73180220012805427e0a13636f6d2e676f6f676c652e70726f746f6275"
+      "66420e54696d657374616d7050726f746f50015a2b6769746875622e636f"
+      "6d2f676f6c616e672f70726f746f6275662f7074797065732f74696d6573"
+      "74616d70f80101a20203475042aa021e476f6f676c652e50726f746f6275"
+      "662e57656c6c4b6e6f776e5479706573620670726f746f33";
+  char* binary;
+  int binary_len;
+  hex_to_binary(generated_file, &binary, &binary_len);
+  internal_add_generated_file(binary, binary_len, generated_pool TSRMLS_CC);
+  FREE(binary);
+  is_inited_file_timestamp = true;
+}
+
+static void init_file_type(TSRMLS_D) {
+  if (is_inited_file_type) return;
+  init_file_any(TSRMLS_C);
+  init_file_source_context(TSRMLS_C);
+  init_generated_pool_once(TSRMLS_C);
+  const char* generated_file =
+      "0aba0c0a1a676f6f676c652f70726f746f6275662f747970652e70726f74"
+      "6f120f676f6f676c652e70726f746f6275661a19676f6f676c652f70726f"
+      "746f6275662f616e792e70726f746f1a24676f6f676c652f70726f746f62"
+      "75662f736f757263655f636f6e746578742e70726f746f22d7010a045479"
+      "7065120c0a046e616d6518012001280912260a066669656c647318022003"
+      "280b32162e676f6f676c652e70726f746f6275662e4669656c64120e0a06"
+      "6f6e656f667318032003280912280a076f7074696f6e7318042003280b32"
+      "172e676f6f676c652e70726f746f6275662e4f7074696f6e12360a0e736f"
+      "757263655f636f6e7465787418052001280b321e2e676f6f676c652e7072"
+      "6f746f6275662e536f75726365436f6e7465787412270a0673796e746178"
+      "18062001280e32172e676f6f676c652e70726f746f6275662e53796e7461"
+      "7822d5050a054669656c6412290a046b696e6418012001280e321b2e676f"
+      "6f676c652e70726f746f6275662e4669656c642e4b696e6412370a0b6361"
+      "7264696e616c69747918022001280e32222e676f6f676c652e70726f746f"
+      "6275662e4669656c642e43617264696e616c697479120e0a066e756d6265"
+      "72180320012805120c0a046e616d6518042001280912100a08747970655f"
+      "75726c18062001280912130a0b6f6e656f665f696e646578180720012805"
+      "120e0a067061636b656418082001280812280a076f7074696f6e73180920"
+      "03280b32172e676f6f676c652e70726f746f6275662e4f7074696f6e1211"
+      "0a096a736f6e5f6e616d65180a2001280912150a0d64656661756c745f76"
+      "616c7565180b2001280922c8020a044b696e6412100a0c545950455f554e"
+      "4b4e4f574e1000120f0a0b545950455f444f55424c451001120e0a0a5459"
+      "50455f464c4f41541002120e0a0a545950455f494e5436341003120f0a0b"
+      "545950455f55494e5436341004120e0a0a545950455f494e543332100512"
+      "100a0c545950455f46495845443634100612100a0c545950455f46495845"
+      "4433321007120d0a09545950455f424f4f4c1008120f0a0b545950455f53"
+      "5452494e471009120e0a0a545950455f47524f5550100a12100a0c545950"
+      "455f4d455353414745100b120e0a0a545950455f4259544553100c120f0a"
+      "0b545950455f55494e543332100d120d0a09545950455f454e554d100e12"
+      "110a0d545950455f5346495845443332100f12110a0d545950455f534649"
+      "58454436341010120f0a0b545950455f53494e5433321011120f0a0b5459"
+      "50455f53494e543634101222740a0b43617264696e616c69747912170a13"
+      "43415244494e414c4954595f554e4b4e4f574e100012180a144341524449"
+      "4e414c4954595f4f5054494f4e414c100112180a1443415244494e414c49"
+      "54595f5245515549524544100212180a1443415244494e414c4954595f52"
+      "45504541544544100322ce010a04456e756d120c0a046e616d6518012001"
+      "2809122d0a09656e756d76616c756518022003280b321a2e676f6f676c65"
+      "2e70726f746f6275662e456e756d56616c756512280a076f7074696f6e73"
+      "18032003280b32172e676f6f676c652e70726f746f6275662e4f7074696f"
+      "6e12360a0e736f757263655f636f6e7465787418042001280b321e2e676f"
+      "6f676c652e70726f746f6275662e536f75726365436f6e7465787412270a"
+      "0673796e74617818052001280e32172e676f6f676c652e70726f746f6275"
+      "662e53796e74617822530a09456e756d56616c7565120c0a046e616d6518"
+      "0120012809120e0a066e756d62657218022001280512280a076f7074696f"
+      "6e7318032003280b32172e676f6f676c652e70726f746f6275662e4f7074"
+      "696f6e223b0a064f7074696f6e120c0a046e616d6518012001280912230a"
+      "0576616c756518022001280b32142e676f6f676c652e70726f746f627566"
+      "2e416e792a2e0a0653796e74617812110a0d53594e5441585f50524f544f"
+      "32100012110a0d53594e5441585f50524f544f331001427d0a13636f6d2e"
+      "676f6f676c652e70726f746f62756642095479706550726f746f50015a2f"
+      "676f6f676c652e676f6c616e672e6f72672f67656e70726f746f2f70726f"
+      "746f6275662f70747970653b7074797065f80101a20203475042aa021e47"
+      "6f6f676c652e50726f746f6275662e57656c6c4b6e6f776e547970657362"
+      "0670726f746f33";
+  char* binary;
+  int binary_len;
+  hex_to_binary(generated_file, &binary, &binary_len);
+  internal_add_generated_file(binary, binary_len, generated_pool TSRMLS_CC);
+  FREE(binary);
+  is_inited_file_type = true;
+}
+
+static void init_file_wrappers(TSRMLS_D) {
+  if (is_inited_file_wrappers) return;
+  init_generated_pool_once(TSRMLS_C);
+  const char* generated_file =
+      "0abf030a1e676f6f676c652f70726f746f6275662f77726170706572732e"
+      "70726f746f120f676f6f676c652e70726f746f627566221c0a0b446f7562"
+      "6c6556616c7565120d0a0576616c7565180120012801221b0a0a466c6f61"
+      "7456616c7565120d0a0576616c7565180120012802221b0a0a496e743634"
+      "56616c7565120d0a0576616c7565180120012803221c0a0b55496e743634"
+      "56616c7565120d0a0576616c7565180120012804221b0a0a496e74333256"
+      "616c7565120d0a0576616c7565180120012805221c0a0b55496e74333256"
+      "616c7565120d0a0576616c756518012001280d221a0a09426f6f6c56616c"
+      "7565120d0a0576616c7565180120012808221c0a0b537472696e6756616c"
+      "7565120d0a0576616c7565180120012809221b0a0a427974657356616c75"
+      "65120d0a0576616c756518012001280c427c0a13636f6d2e676f6f676c65"
+      "2e70726f746f627566420d577261707065727350726f746f50015a2a6769"
+      "746875622e636f6d2f676f6c616e672f70726f746f6275662f7074797065"
+      "732f7772617070657273f80101a20203475042aa021e476f6f676c652e50"
+      "726f746f6275662e57656c6c4b6e6f776e5479706573620670726f746f33";
+  char* binary;
+  int binary_len;
+  hex_to_binary(generated_file, &binary, &binary_len);
+  internal_add_generated_file(binary, binary_len, generated_pool TSRMLS_CC);
+  FREE(binary);
+  is_inited_file_wrappers = true;
+}
+
+// -----------------------------------------------------------------------------
+// Define enum
+// -----------------------------------------------------------------------------
+
+// -----------------------------------------------------------------------------
+// Field_Cardinality
+// -----------------------------------------------------------------------------
+
+static zend_function_entry field_cardinality_methods[] = {
+  {NULL, NULL, NULL}
+};
+
+zend_class_entry* field_cardinality_type;
+
+// Init class entry.
+PHP_PROTO_INIT_ENUMCLASS_START("Google\\Protobuf\\Field\\Cardinality",
+                                Field_Cardinality, field_cardinality)
+  zend_declare_class_constant_long(field_cardinality_type,
+                                   "CARDINALITY_UNKNOWN", 19, 0 TSRMLS_CC);
+  zend_declare_class_constant_long(field_cardinality_type,
+                                   "CARDINALITY_OPTIONAL", 20, 1 TSRMLS_CC);
+  zend_declare_class_constant_long(field_cardinality_type,
+                                   "CARDINALITY_REQUIRED", 20, 2 TSRMLS_CC);
+  zend_declare_class_constant_long(field_cardinality_type,
+                                   "CARDINALITY_REPEATED", 20, 3 TSRMLS_CC);
+  const char *alias = "Google\\Protobuf\\Field_Cardinality";
+#if PHP_VERSION_ID < 70300
+  zend_register_class_alias_ex(alias, strlen(alias), field_cardinality_type TSRMLS_CC);
+#else
+  zend_register_class_alias_ex(alias, strlen(alias), field_cardinality_type, 1);
+#endif
+PHP_PROTO_INIT_ENUMCLASS_END
+
+// -----------------------------------------------------------------------------
+// Field_Kind
+// -----------------------------------------------------------------------------
+
+static zend_function_entry field_kind_methods[] = {
+  {NULL, NULL, NULL}
+};
+
+zend_class_entry* field_kind_type;
+
+// Init class entry.
+PHP_PROTO_INIT_ENUMCLASS_START("Google\\Protobuf\\Field\\Kind",
+                                Field_Kind, field_kind)
+  zend_declare_class_constant_long(field_kind_type,
+                                   "TYPE_UNKNOWN", 12, 0 TSRMLS_CC);
+  zend_declare_class_constant_long(field_kind_type,
+                                   "TYPE_DOUBLE", 11, 1 TSRMLS_CC);
+  zend_declare_class_constant_long(field_kind_type,
+                                   "TYPE_FLOAT", 10, 2 TSRMLS_CC);
+  zend_declare_class_constant_long(field_kind_type,
+                                   "TYPE_INT64", 10, 3 TSRMLS_CC);
+  zend_declare_class_constant_long(field_kind_type,
+                                   "TYPE_UINT64", 11, 4 TSRMLS_CC);
+  zend_declare_class_constant_long(field_kind_type,
+                                   "TYPE_INT32", 10, 5 TSRMLS_CC);
+  zend_declare_class_constant_long(field_kind_type,
+                                   "TYPE_FIXED64", 12, 6 TSRMLS_CC);
+  zend_declare_class_constant_long(field_kind_type,
+                                   "TYPE_FIXED32", 12, 7 TSRMLS_CC);
+  zend_declare_class_constant_long(field_kind_type,
+                                   "TYPE_BOOL", 9, 8 TSRMLS_CC);
+  zend_declare_class_constant_long(field_kind_type,
+                                   "TYPE_STRING", 11, 9 TSRMLS_CC);
+  zend_declare_class_constant_long(field_kind_type,
+                                   "TYPE_GROUP", 10, 10 TSRMLS_CC);
+  zend_declare_class_constant_long(field_kind_type,
+                                   "TYPE_MESSAGE", 12, 11 TSRMLS_CC);
+  zend_declare_class_constant_long(field_kind_type,
+                                   "TYPE_BYTES", 10, 12 TSRMLS_CC);
+  zend_declare_class_constant_long(field_kind_type,
+                                   "TYPE_UINT32", 11, 13 TSRMLS_CC);
+  zend_declare_class_constant_long(field_kind_type,
+                                   "TYPE_ENUM", 9, 14 TSRMLS_CC);
+  zend_declare_class_constant_long(field_kind_type,
+                                   "TYPE_SFIXED32", 13, 15 TSRMLS_CC);
+  zend_declare_class_constant_long(field_kind_type,
+                                   "TYPE_SFIXED64", 13, 16 TSRMLS_CC);
+  zend_declare_class_constant_long(field_kind_type,
+                                   "TYPE_SINT32", 11, 17 TSRMLS_CC);
+  zend_declare_class_constant_long(field_kind_type,
+                                   "TYPE_SINT64", 11, 18 TSRMLS_CC);
+  const char *alias = "Google\\Protobuf\\Field_Kind";
+#if PHP_VERSION_ID < 70300
+  zend_register_class_alias_ex(alias, strlen(alias), field_kind_type TSRMLS_CC);
+#else
+  zend_register_class_alias_ex(alias, strlen(alias), field_kind_type, 1);
+#endif
+PHP_PROTO_INIT_ENUMCLASS_END
+
+// -----------------------------------------------------------------------------
+// NullValue
+// -----------------------------------------------------------------------------
+
+static zend_function_entry null_value_methods[] = {
+  {NULL, NULL, NULL}
+};
+
+zend_class_entry* null_value_type;
+
+// Init class entry.
+PHP_PROTO_INIT_ENUMCLASS_START("Google\\Protobuf\\NullValue",
+                                NullValue, null_value)
+  zend_declare_class_constant_long(null_value_type,
+                                   "NULL_VALUE", 10, 0 TSRMLS_CC);
+PHP_PROTO_INIT_ENUMCLASS_END
+
+// -----------------------------------------------------------------------------
+// Syntax
+// -----------------------------------------------------------------------------
+
+static zend_function_entry syntax_methods[] = {
+  {NULL, NULL, NULL}
+};
+
+zend_class_entry* syntax_type;
+
+// Init class entry.
+PHP_PROTO_INIT_ENUMCLASS_START("Google\\Protobuf\\Syntax",
+                                Syntax, syntax)
+  zend_declare_class_constant_long(syntax_type,
+                                   "SYNTAX_PROTO2", 13, 0 TSRMLS_CC);
+  zend_declare_class_constant_long(syntax_type,
+                                   "SYNTAX_PROTO3", 13, 1 TSRMLS_CC);
+PHP_PROTO_INIT_ENUMCLASS_END
+
+
+
+// -----------------------------------------------------------------------------
+// Define message
+// -----------------------------------------------------------------------------
+
+// -----------------------------------------------------------------------------
+// Any
+// -----------------------------------------------------------------------------
+
+static  zend_function_entry any_methods[] = {
+  PHP_ME(Any, __construct, NULL, ZEND_ACC_PUBLIC)
+  PHP_ME(Any, getTypeUrl, NULL, ZEND_ACC_PUBLIC)
+  PHP_ME(Any, setTypeUrl, NULL, ZEND_ACC_PUBLIC)
+  PHP_ME(Any, getValue, NULL, ZEND_ACC_PUBLIC)
+  PHP_ME(Any, setValue, NULL, ZEND_ACC_PUBLIC)
+  PHP_ME(Any, pack,     NULL, ZEND_ACC_PUBLIC)
+  PHP_ME(Any, unpack,   NULL, ZEND_ACC_PUBLIC)
+  PHP_ME(Any, is,       NULL, ZEND_ACC_PUBLIC)
+  {NULL, NULL, NULL}
+};
+
+zend_class_entry* any_type;
+
+// Init class entry.
+PHP_PROTO_INIT_SUBMSGCLASS_START("Google\\Protobuf\\Any", Any, any)
+  zend_class_implements(any_type TSRMLS_CC, 1, message_type);
+  zend_declare_property_string(any_type, "type_url", strlen("type_url"),
+                               "" ,ZEND_ACC_PRIVATE TSRMLS_CC);
+  zend_declare_property_string(any_type, "value", strlen("value"),
+                               "" ,ZEND_ACC_PRIVATE TSRMLS_CC);
+PHP_PROTO_INIT_SUBMSGCLASS_END
+
+static void hex_to_binary(const char* hex, char** binary, int* binary_len) {
+  int i;
+  int hex_len = strlen(hex);
+  *binary_len = hex_len / 2;
+  *binary = ALLOC_N(char, *binary_len);
+  for (i = 0; i < *binary_len; i++) {
+    char value = 0;
+    if (hex[i * 2] >= '0' && hex[i * 2] <= '9') {
+      value += (hex[i * 2] - '0') * 16;
+    } else {
+      value += (hex[i * 2] - 'a' + 10) * 16;
+    }
+    if (hex[i * 2 + 1] >= '0' && hex[i * 2 + 1] <= '9') {
+      value += hex[i * 2 + 1] - '0';
+    } else {
+      value += hex[i * 2 + 1] - 'a' + 10;
+    }
+    (*binary)[i] = value;
+  }
+}
+
+PHP_METHOD(Any, __construct) {
+  init_file_any(TSRMLS_C);
+  MessageHeader* intern = UNBOX(MessageHeader, getThis());
+  custom_data_init(any_type, intern PHP_PROTO_TSRMLS_CC);
+}
+
+PHP_PROTO_FIELD_ACCESSORS(Any, any, TypeUrl, "type_url")
+PHP_PROTO_FIELD_ACCESSORS(Any, any, Value,   "value")
+
+PHP_METHOD(Any, unpack) {
+  // Get type url.
+  zval type_url_member;
+  PHP_PROTO_ZVAL_STRING(&type_url_member, "type_url", 1);
+  PHP_PROTO_FAKE_SCOPE_BEGIN(any_type);
+  zval* type_url_php = php_proto_message_read_property(
+      getThis(), &type_url_member PHP_PROTO_TSRMLS_CC);
+  zval_dtor(&type_url_member);
+  PHP_PROTO_FAKE_SCOPE_END;
+
+  // Get fully-qualified name from type url.
+  size_t url_prefix_len = strlen(TYPE_URL_PREFIX);
+  const char* type_url = Z_STRVAL_P(type_url_php);
+  size_t type_url_len = Z_STRLEN_P(type_url_php);
+
+  if (url_prefix_len > type_url_len ||
+      strncmp(TYPE_URL_PREFIX, type_url, url_prefix_len) != 0) {
+    zend_throw_exception(
+        NULL, "Type url needs to be type.googleapis.com/fully-qualified",
+        0 TSRMLS_CC);
+    return;
+  }
+
+  const char* fully_qualified_name = type_url + url_prefix_len;
+  PHP_PROTO_HASHTABLE_VALUE desc_php = get_proto_obj(fully_qualified_name);
+  if (desc_php == NULL) {
+    zend_throw_exception(
+        NULL, "Specified message in any hasn't been added to descriptor pool",
+        0 TSRMLS_CC);
+    return;
+  }
+  Descriptor* desc = UNBOX_HASHTABLE_VALUE(Descriptor, desc_php);
+  zend_class_entry* klass = desc->klass;
+  ZVAL_OBJ(return_value, klass->create_object(klass TSRMLS_CC));
+  MessageHeader* msg = UNBOX(MessageHeader, return_value);
+  custom_data_init(klass, msg PHP_PROTO_TSRMLS_CC);
+
+  // Get value.
+  zval value_member;
+  PHP_PROTO_ZVAL_STRING(&value_member, "value", 1);
+  PHP_PROTO_FAKE_SCOPE_RESTART(any_type);
+  zval* value = php_proto_message_read_property(
+      getThis(), &value_member PHP_PROTO_TSRMLS_CC);
+  zval_dtor(&value_member);
+  PHP_PROTO_FAKE_SCOPE_END;
+
+  merge_from_string(Z_STRVAL_P(value), Z_STRLEN_P(value), desc, msg);
+}
+
+PHP_METHOD(Any, pack) {
+  zval* val;
+
+  if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "o", &val) ==
+      FAILURE) {
+    return;
+  }
+
+  if (!instanceof_function(Z_OBJCE_P(val), message_type TSRMLS_CC)) {
+    zend_error(E_USER_ERROR, "Given value is not an instance of Message.");
+    return;
+  }
+
+  // Set value by serialized data.
+  zval data;
+  serialize_to_string(val, &data TSRMLS_CC);
+
+  zval member;
+  PHP_PROTO_ZVAL_STRING(&member, "value", 1);
+
+  PHP_PROTO_FAKE_SCOPE_BEGIN(any_type);
+  message_handlers->write_property(getThis(), &member, &data,
+                                   NULL PHP_PROTO_TSRMLS_CC);
+  zval_dtor(&data);
+  zval_dtor(&member);
+  PHP_PROTO_FAKE_SCOPE_END;
+
+  // Set type url.
+  Descriptor* desc =
+      UNBOX_HASHTABLE_VALUE(Descriptor, get_ce_obj(Z_OBJCE_P(val)));
+  const char* fully_qualified_name = upb_msgdef_fullname(desc->msgdef);
+  size_t type_url_len =
+      strlen(TYPE_URL_PREFIX) + strlen(fully_qualified_name) + 1;
+  char* type_url = ALLOC_N(char, type_url_len);
+  sprintf(type_url, "%s%s", TYPE_URL_PREFIX, fully_qualified_name);
+  zval type_url_php;
+  PHP_PROTO_ZVAL_STRING(&type_url_php, type_url, 1);
+  PHP_PROTO_ZVAL_STRING(&member, "type_url", 1);
+
+  PHP_PROTO_FAKE_SCOPE_RESTART(any_type);
+  message_handlers->write_property(getThis(), &member, &type_url_php,
+                                   NULL PHP_PROTO_TSRMLS_CC);
+  zval_dtor(&type_url_php);
+  zval_dtor(&member);
+  PHP_PROTO_FAKE_SCOPE_END;
+  FREE(type_url);
+}
+
+PHP_METHOD(Any, is) {
+  zend_class_entry *klass = NULL;
+
+  if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "C", &klass) ==
+      FAILURE) {
+    return;
+  }
+
+  PHP_PROTO_HASHTABLE_VALUE desc_php = get_ce_obj(klass);
+  if (desc_php == NULL) {
+    RETURN_BOOL(false);
+  }
+
+  // Create corresponded type url.
+  Descriptor* desc =
+      UNBOX_HASHTABLE_VALUE(Descriptor, get_ce_obj(klass));
+  const char* fully_qualified_name = upb_msgdef_fullname(desc->msgdef);
+  size_t type_url_len =
+      strlen(TYPE_URL_PREFIX) + strlen(fully_qualified_name) + 1;
+  char* type_url = ALLOC_N(char, type_url_len);
+  sprintf(type_url, "%s%s", TYPE_URL_PREFIX, fully_qualified_name);
+
+  // Fetch stored type url.
+  zval member;
+  PHP_PROTO_ZVAL_STRING(&member, "type_url", 1);
+  PHP_PROTO_FAKE_SCOPE_BEGIN(any_type);
+  zval* value =
+      php_proto_message_read_property(getThis(), &member PHP_PROTO_TSRMLS_CC);
+  zval_dtor(&member);
+  PHP_PROTO_FAKE_SCOPE_END;
+
+  // Compare two type url.
+  bool is = strcmp(type_url, Z_STRVAL_P(value)) == 0;
+  FREE(type_url);
+
+  RETURN_BOOL(is);
+}
+
+// -----------------------------------------------------------------------------
+// Duration
+// -----------------------------------------------------------------------------
+
+static  zend_function_entry duration_methods[] = {
+  PHP_ME(Duration, __construct, NULL, ZEND_ACC_PUBLIC)
+  PHP_ME(Duration, getSeconds, NULL, ZEND_ACC_PUBLIC)
+  PHP_ME(Duration, setSeconds, NULL, ZEND_ACC_PUBLIC)
+  PHP_ME(Duration, getNanos, NULL, ZEND_ACC_PUBLIC)
+  PHP_ME(Duration, setNanos, NULL, ZEND_ACC_PUBLIC)
+  {NULL, NULL, NULL}
+};
+
+zend_class_entry* duration_type;
+
+// Init class entry.
+PHP_PROTO_INIT_SUBMSGCLASS_START("Google\\Protobuf\\Duration",
+                                 Duration, duration)
+  zend_class_implements(duration_type TSRMLS_CC, 1, message_type);
+  zend_declare_property_long(duration_type, "seconds", strlen("seconds"),
+                             0 ,ZEND_ACC_PRIVATE TSRMLS_CC);
+  zend_declare_property_long(duration_type, "nanos", strlen("nanos"),
+                             0 ,ZEND_ACC_PRIVATE TSRMLS_CC);
+PHP_PROTO_INIT_SUBMSGCLASS_END
+
+PHP_METHOD(Duration, __construct) {
+  init_file_duration(TSRMLS_C);
+  MessageHeader* intern = UNBOX(MessageHeader, getThis());
+  custom_data_init(duration_type, intern PHP_PROTO_TSRMLS_CC);
+}
+
+PHP_PROTO_FIELD_ACCESSORS(Duration, duration, Seconds, "seconds")
+PHP_PROTO_FIELD_ACCESSORS(Duration, duration, Nanos,   "nanos")
+
+// -----------------------------------------------------------------------------
+// Timestamp
+// -----------------------------------------------------------------------------
+
+static  zend_function_entry timestamp_methods[] = {
+  PHP_ME(Timestamp, __construct, NULL, ZEND_ACC_PUBLIC)
+  PHP_ME(Timestamp, fromDateTime, NULL, ZEND_ACC_PUBLIC)
+  PHP_ME(Timestamp, toDateTime, NULL, ZEND_ACC_PUBLIC)
+  PHP_ME(Timestamp, getSeconds, NULL, ZEND_ACC_PUBLIC)
+  PHP_ME(Timestamp, setSeconds, NULL, ZEND_ACC_PUBLIC)
+  PHP_ME(Timestamp, getNanos, NULL, ZEND_ACC_PUBLIC)
+  PHP_ME(Timestamp, setNanos, NULL, ZEND_ACC_PUBLIC)
+  {NULL, NULL, NULL}
+};
+
+zend_class_entry* timestamp_type;
+
+// Init class entry.
+PHP_PROTO_INIT_SUBMSGCLASS_START("Google\\Protobuf\\Timestamp",
+                                 Timestamp, timestamp)
+  zend_class_implements(timestamp_type TSRMLS_CC, 1, message_type);
+  zend_declare_property_long(timestamp_type, "seconds", strlen("seconds"),
+                             0 ,ZEND_ACC_PRIVATE TSRMLS_CC);
+  zend_declare_property_long(timestamp_type, "nanos", strlen("nanos"),
+                             0 ,ZEND_ACC_PRIVATE TSRMLS_CC);
+PHP_PROTO_INIT_SUBMSGCLASS_END
+
+PHP_METHOD(Timestamp, __construct) {
+  init_file_timestamp(TSRMLS_C);
+  MessageHeader* intern = UNBOX(MessageHeader, getThis());
+  custom_data_init(timestamp_type, intern PHP_PROTO_TSRMLS_CC);
+}
+
+PHP_PROTO_FIELD_ACCESSORS(Timestamp, timestamp, Seconds, "seconds")
+PHP_PROTO_FIELD_ACCESSORS(Timestamp, timestamp, Nanos,   "nanos")
+
+PHP_METHOD(Timestamp, fromDateTime) {
+  zval* datetime;
+  zval member;
+
+  PHP_PROTO_CE_DECLARE date_interface_ce;
+  if (php_proto_zend_lookup_class("\\DatetimeInterface", 18,
+                                  &date_interface_ce) == FAILURE) {
+    zend_error(E_ERROR, "Make sure date extension is enabled.");
+    return;
+  }
+
+  if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O", &datetime,
+                            PHP_PROTO_CE_UNREF(date_interface_ce)) == FAILURE) {
+    zend_error(E_USER_ERROR, "Expect DatetimeInterface.");
+    return;
+  }
+
+  // Get timestamp from Datetime object.
+  zval retval;
+  zval function_name;
+  int64_t timestamp;
+
+#if PHP_MAJOR_VERSION < 7
+  INIT_ZVAL(retval);
+  INIT_ZVAL(function_name);
+#endif
+
+  PHP_PROTO_ZVAL_STRING(&function_name, "date_timestamp_get", 1);
+
+  if (call_user_function(EG(function_table), NULL, &function_name, &retval, 1,
+          ZVAL_PTR_TO_CACHED_PTR(datetime) TSRMLS_CC) == FAILURE) {
+    zend_error(E_ERROR, "Cannot get timestamp from DateTime.");
+    return;
+  }
+
+  protobuf_convert_to_int64(&retval, &timestamp);
+
+  zval_dtor(&retval);
+  zval_dtor(&function_name);
+
+  // Set seconds
+  MessageHeader* self = UNBOX(MessageHeader, getThis());
+  const upb_fielddef* field =
+      upb_msgdef_ntofz(self->descriptor->msgdef, "seconds");
+  void* storage = message_data(self);
+  void* memory = slot_memory(self->descriptor->layout, storage, field);
+  *(int64_t*)memory = timestamp;
+
+  // Set nanos
+  field = upb_msgdef_ntofz(self->descriptor->msgdef, "nanos");
+  storage = message_data(self);
+  memory = slot_memory(self->descriptor->layout, storage, field);
+  *(int32_t*)memory = 0;
+
+  RETURN_NULL();
+}
+
+PHP_METHOD(Timestamp, toDateTime) {
+  // Get seconds
+  MessageHeader* self = UNBOX(MessageHeader, getThis());
+  const upb_fielddef* field =
+      upb_msgdef_ntofz(self->descriptor->msgdef, "seconds");
+  void* storage = message_data(self);
+  void* memory = slot_memory(self->descriptor->layout, storage, field);
+  int64_t seconds = *(int64_t*)memory;
+
+  // Get nanos
+  field = upb_msgdef_ntofz(self->descriptor->msgdef, "nanos");
+  memory = slot_memory(self->descriptor->layout, storage, field);
+  int32_t nanos = *(int32_t*)memory;
+
+  // Get formated time string.
+  char formated_time[50];
+  time_t raw_time = seconds;
+  struct tm *utc_time = gmtime(&raw_time);
+  strftime(formated_time, sizeof(formated_time), "%Y-%m-%dT%H:%M:%SUTC",
+           utc_time);
+
+  // Create Datetime object.
+  zval datetime;
+  zval formated_time_php;
+  zval function_name;
+  int64_t timestamp = 0;
+
+#if PHP_MAJOR_VERSION < 7
+  INIT_ZVAL(function_name);
+  INIT_ZVAL(formated_time_php);
+#endif
+
+  PHP_PROTO_ZVAL_STRING(&function_name, "date_create", 1);
+  PHP_PROTO_ZVAL_STRING(&formated_time_php, formated_time, 1);
+
+  CACHED_VALUE params[1] = {ZVAL_TO_CACHED_VALUE(formated_time_php)};
+
+  if (call_user_function(EG(function_table), NULL,
+                         &function_name, &datetime, 1,
+                         params TSRMLS_CC) == FAILURE) {
+    zend_error(E_ERROR, "Cannot create DateTime.");
+    return;
+  }
+
+  zval_dtor(&formated_time_php);
+  zval_dtor(&function_name);
+
+#if PHP_MAJOR_VERSION < 7
+  zval* datetime_ptr = &datetime;
+  PHP_PROTO_RETVAL_ZVAL(datetime_ptr);
+#else
+  ZVAL_OBJ(return_value, Z_OBJ(datetime));
+#endif
+}
+
+// -----------------------------------------------------------------------------
+// Api
+// -----------------------------------------------------------------------------
+
+static  zend_function_entry api_methods[] = {
+  PHP_ME(Api, __construct, NULL, ZEND_ACC_PUBLIC)
+  PHP_ME(Api, getName, NULL, ZEND_ACC_PUBLIC)
+  PHP_ME(Api, setName, NULL, ZEND_ACC_PUBLIC)
+  PHP_ME(Api, getMethods, NULL, ZEND_ACC_PUBLIC)
+  PHP_ME(Api, setMethods, NULL, ZEND_ACC_PUBLIC)
+  PHP_ME(Api, getOptions, NULL, ZEND_ACC_PUBLIC)
+  PHP_ME(Api, setOptions, NULL, ZEND_ACC_PUBLIC)
+  PHP_ME(Api, getVersion, NULL, ZEND_ACC_PUBLIC)
+  PHP_ME(Api, setVersion, NULL, ZEND_ACC_PUBLIC)
+  PHP_ME(Api, getSourceContext, NULL, ZEND_ACC_PUBLIC)
+  PHP_ME(Api, setSourceContext, NULL, ZEND_ACC_PUBLIC)
+  PHP_ME(Api, getMixins, NULL, ZEND_ACC_PUBLIC)
+  PHP_ME(Api, setMixins, NULL, ZEND_ACC_PUBLIC)
+  PHP_ME(Api, getSyntax, NULL, ZEND_ACC_PUBLIC)
+  PHP_ME(Api, setSyntax, NULL, ZEND_ACC_PUBLIC)
+  {NULL, NULL, NULL}
+};
+
+zend_class_entry* api_type;
+
+// Init class entry.
+PHP_PROTO_INIT_SUBMSGCLASS_START("Google\\Protobuf\\Api",
+                                 Api, api)
+  zend_class_implements(api_type TSRMLS_CC, 1, message_type);
+  zend_declare_property_null(api_type, "name", strlen("name"),
+                             ZEND_ACC_PRIVATE TSRMLS_CC);
+  zend_declare_property_null(api_type, "methods", strlen("methods"),
+                             ZEND_ACC_PRIVATE TSRMLS_CC);
+  zend_declare_property_null(api_type, "options", strlen("options"),
+                             ZEND_ACC_PRIVATE TSRMLS_CC);
+  zend_declare_property_null(api_type, "version", strlen("version"),
+                             ZEND_ACC_PRIVATE TSRMLS_CC);
+  zend_declare_property_null(api_type, "source_context", strlen("source_context"),
+                             ZEND_ACC_PRIVATE TSRMLS_CC);
+  zend_declare_property_null(api_type, "mixins", strlen("mixins"),
+                             ZEND_ACC_PRIVATE TSRMLS_CC);
+  zend_declare_property_null(api_type, "syntax", strlen("syntax"),
+                             ZEND_ACC_PRIVATE TSRMLS_CC);
+PHP_PROTO_INIT_SUBMSGCLASS_END
+
+PHP_METHOD(Api, __construct) {
+  init_file_api(TSRMLS_C);
+  MessageHeader* intern = UNBOX(MessageHeader, getThis());
+  custom_data_init(api_type, intern PHP_PROTO_TSRMLS_CC);
+}
+
+PHP_PROTO_FIELD_ACCESSORS(Api, api, Name, "name")
+PHP_PROTO_FIELD_ACCESSORS(Api, api, Methods, "methods")
+PHP_PROTO_FIELD_ACCESSORS(Api, api, Options, "options")
+PHP_PROTO_FIELD_ACCESSORS(Api, api, Version, "version")
+PHP_PROTO_FIELD_ACCESSORS(Api, api, SourceContext, "source_context")
+PHP_PROTO_FIELD_ACCESSORS(Api, api, Mixins, "mixins")
+PHP_PROTO_FIELD_ACCESSORS(Api, api, Syntax, "syntax")
+
+// -----------------------------------------------------------------------------
+// BoolValue
+// -----------------------------------------------------------------------------
+
+static  zend_function_entry bool_value_methods[] = {
+  PHP_ME(BoolValue, __construct, NULL, ZEND_ACC_PUBLIC)
+  PHP_ME(BoolValue, getValue, NULL, ZEND_ACC_PUBLIC)
+  PHP_ME(BoolValue, setValue, NULL, ZEND_ACC_PUBLIC)
+  {NULL, NULL, NULL}
+};
+
+zend_class_entry* bool_value_type;
+
+// Init class entry.
+PHP_PROTO_INIT_SUBMSGCLASS_START("Google\\Protobuf\\BoolValue",
+                                 BoolValue, bool_value)
+  zend_class_implements(bool_value_type TSRMLS_CC, 1, message_type);
+  zend_declare_property_null(bool_value_type, "value", strlen("value"),
+                             ZEND_ACC_PRIVATE TSRMLS_CC);
+PHP_PROTO_INIT_SUBMSGCLASS_END
+
+PHP_METHOD(BoolValue, __construct) {
+  init_file_wrappers(TSRMLS_C);
+  MessageHeader* intern = UNBOX(MessageHeader, getThis());
+  custom_data_init(bool_value_type, intern PHP_PROTO_TSRMLS_CC);
+}
+
+PHP_PROTO_FIELD_ACCESSORS(BoolValue, bool_value, Value, "value")
+
+// -----------------------------------------------------------------------------
+// BytesValue
+// -----------------------------------------------------------------------------
+
+static  zend_function_entry bytes_value_methods[] = {
+  PHP_ME(BytesValue, __construct, NULL, ZEND_ACC_PUBLIC)
+  PHP_ME(BytesValue, getValue, NULL, ZEND_ACC_PUBLIC)
+  PHP_ME(BytesValue, setValue, NULL, ZEND_ACC_PUBLIC)
+  {NULL, NULL, NULL}
+};
+
+zend_class_entry* bytes_value_type;
+
+// Init class entry.
+PHP_PROTO_INIT_SUBMSGCLASS_START("Google\\Protobuf\\BytesValue",
+                                 BytesValue, bytes_value)
+  zend_class_implements(bytes_value_type TSRMLS_CC, 1, message_type);
+  zend_declare_property_null(bytes_value_type, "value", strlen("value"),
+                             ZEND_ACC_PRIVATE TSRMLS_CC);
+PHP_PROTO_INIT_SUBMSGCLASS_END
+
+PHP_METHOD(BytesValue, __construct) {
+  init_file_wrappers(TSRMLS_C);
+  MessageHeader* intern = UNBOX(MessageHeader, getThis());
+  custom_data_init(bytes_value_type, intern PHP_PROTO_TSRMLS_CC);
+}
+
+PHP_PROTO_FIELD_ACCESSORS(BytesValue, bytes_value, Value, "value")
+
+// -----------------------------------------------------------------------------
+// DoubleValue
+// -----------------------------------------------------------------------------
+
+static  zend_function_entry double_value_methods[] = {
+  PHP_ME(DoubleValue, __construct, NULL, ZEND_ACC_PUBLIC)
+  PHP_ME(DoubleValue, getValue, NULL, ZEND_ACC_PUBLIC)
+  PHP_ME(DoubleValue, setValue, NULL, ZEND_ACC_PUBLIC)
+  {NULL, NULL, NULL}
+};
+
+zend_class_entry* double_value_type;
+
+// Init class entry.
+PHP_PROTO_INIT_SUBMSGCLASS_START("Google\\Protobuf\\DoubleValue",
+                                 DoubleValue, double_value)
+  zend_class_implements(double_value_type TSRMLS_CC, 1, message_type);
+  zend_declare_property_null(double_value_type, "value", strlen("value"),
+                             ZEND_ACC_PRIVATE TSRMLS_CC);
+PHP_PROTO_INIT_SUBMSGCLASS_END
+
+PHP_METHOD(DoubleValue, __construct) {
+  init_file_wrappers(TSRMLS_C);
+  MessageHeader* intern = UNBOX(MessageHeader, getThis());
+  custom_data_init(double_value_type, intern PHP_PROTO_TSRMLS_CC);
+}
+
+PHP_PROTO_FIELD_ACCESSORS(DoubleValue, double_value, Value, "value")
+
+// -----------------------------------------------------------------------------
+// Enum
+// -----------------------------------------------------------------------------
+
+static  zend_function_entry enum_methods[] = {
+  PHP_ME(Enum, __construct, NULL, ZEND_ACC_PUBLIC)
+  PHP_ME(Enum, getName, NULL, ZEND_ACC_PUBLIC)
+  PHP_ME(Enum, setName, NULL, ZEND_ACC_PUBLIC)
+  PHP_ME(Enum, getEnumvalue, NULL, ZEND_ACC_PUBLIC)
+  PHP_ME(Enum, setEnumvalue, NULL, ZEND_ACC_PUBLIC)
+  PHP_ME(Enum, getOptions, NULL, ZEND_ACC_PUBLIC)
+  PHP_ME(Enum, setOptions, NULL, ZEND_ACC_PUBLIC)
+  PHP_ME(Enum, getSourceContext, NULL, ZEND_ACC_PUBLIC)
+  PHP_ME(Enum, setSourceContext, NULL, ZEND_ACC_PUBLIC)
+  PHP_ME(Enum, getSyntax, NULL, ZEND_ACC_PUBLIC)
+  PHP_ME(Enum, setSyntax, NULL, ZEND_ACC_PUBLIC)
+  {NULL, NULL, NULL}
+};
+
+zend_class_entry* enum_type;
+
+// Init class entry.
+PHP_PROTO_INIT_SUBMSGCLASS_START("Google\\Protobuf\\Enum",
+                                 Enum, enum)
+  zend_class_implements(enum_type TSRMLS_CC, 1, message_type);
+  zend_declare_property_null(enum_type, "name", strlen("name"),
+                             ZEND_ACC_PRIVATE TSRMLS_CC);
+  zend_declare_property_null(enum_type, "enumvalue", strlen("enumvalue"),
+                             ZEND_ACC_PRIVATE TSRMLS_CC);
+  zend_declare_property_null(enum_type, "options", strlen("options"),
+                             ZEND_ACC_PRIVATE TSRMLS_CC);
+  zend_declare_property_null(enum_type, "source_context", strlen("source_context"),
+                             ZEND_ACC_PRIVATE TSRMLS_CC);
+  zend_declare_property_null(enum_type, "syntax", strlen("syntax"),
+                             ZEND_ACC_PRIVATE TSRMLS_CC);
+PHP_PROTO_INIT_SUBMSGCLASS_END
+
+PHP_METHOD(Enum, __construct) {
+  init_file_type(TSRMLS_C);
+  MessageHeader* intern = UNBOX(MessageHeader, getThis());
+  custom_data_init(enum_type, intern PHP_PROTO_TSRMLS_CC);
+}
+
+PHP_PROTO_FIELD_ACCESSORS(Enum, enum, Name, "name")
+PHP_PROTO_FIELD_ACCESSORS(Enum, enum, Enumvalue, "enumvalue")
+PHP_PROTO_FIELD_ACCESSORS(Enum, enum, Options, "options")
+PHP_PROTO_FIELD_ACCESSORS(Enum, enum, SourceContext, "source_context")
+PHP_PROTO_FIELD_ACCESSORS(Enum, enum, Syntax, "syntax")
+
+// -----------------------------------------------------------------------------
+// EnumValue
+// -----------------------------------------------------------------------------
+
+static  zend_function_entry enum_value_methods[] = {
+  PHP_ME(EnumValue, __construct, NULL, ZEND_ACC_PUBLIC)
+  PHP_ME(EnumValue, getName, NULL, ZEND_ACC_PUBLIC)
+  PHP_ME(EnumValue, setName, NULL, ZEND_ACC_PUBLIC)
+  PHP_ME(EnumValue, getNumber, NULL, ZEND_ACC_PUBLIC)
+  PHP_ME(EnumValue, setNumber, NULL, ZEND_ACC_PUBLIC)
+  PHP_ME(EnumValue, getOptions, NULL, ZEND_ACC_PUBLIC)
+  PHP_ME(EnumValue, setOptions, NULL, ZEND_ACC_PUBLIC)
+  {NULL, NULL, NULL}
+};
+
+zend_class_entry* enum_value_type;
+
+// Init class entry.
+PHP_PROTO_INIT_SUBMSGCLASS_START("Google\\Protobuf\\EnumValue",
+                                 EnumValue, enum_value)
+  zend_class_implements(enum_value_type TSRMLS_CC, 1, message_type);
+  zend_declare_property_null(enum_value_type, "name", strlen("name"),
+                             ZEND_ACC_PRIVATE TSRMLS_CC);
+  zend_declare_property_null(enum_value_type, "number", strlen("number"),
+                             ZEND_ACC_PRIVATE TSRMLS_CC);
+  zend_declare_property_null(enum_value_type, "options", strlen("options"),
+                             ZEND_ACC_PRIVATE TSRMLS_CC);
+PHP_PROTO_INIT_SUBMSGCLASS_END
+
+PHP_METHOD(EnumValue, __construct) {
+  init_file_type(TSRMLS_C);
+  MessageHeader* intern = UNBOX(MessageHeader, getThis());
+  custom_data_init(enum_value_type, intern PHP_PROTO_TSRMLS_CC);
+}
+
+PHP_PROTO_FIELD_ACCESSORS(EnumValue, enum_value, Name, "name")
+PHP_PROTO_FIELD_ACCESSORS(EnumValue, enum_value, Number, "number")
+PHP_PROTO_FIELD_ACCESSORS(EnumValue, enum_value, Options, "options")
+
+// -----------------------------------------------------------------------------
+// FieldMask
+// -----------------------------------------------------------------------------
+
+static  zend_function_entry field_mask_methods[] = {
+  PHP_ME(FieldMask, __construct, NULL, ZEND_ACC_PUBLIC)
+  PHP_ME(FieldMask, getPaths, NULL, ZEND_ACC_PUBLIC)
+  PHP_ME(FieldMask, setPaths, NULL, ZEND_ACC_PUBLIC)
+  {NULL, NULL, NULL}
+};
+
+zend_class_entry* field_mask_type;
+
+// Init class entry.
+PHP_PROTO_INIT_SUBMSGCLASS_START("Google\\Protobuf\\FieldMask",
+                                 FieldMask, field_mask)
+  zend_class_implements(field_mask_type TSRMLS_CC, 1, message_type);
+  zend_declare_property_null(field_mask_type, "paths", strlen("paths"),
+                             ZEND_ACC_PRIVATE TSRMLS_CC);
+PHP_PROTO_INIT_SUBMSGCLASS_END
+
+PHP_METHOD(FieldMask, __construct) {
+  init_file_field_mask(TSRMLS_C);
+  MessageHeader* intern = UNBOX(MessageHeader, getThis());
+  custom_data_init(field_mask_type, intern PHP_PROTO_TSRMLS_CC);
+}
+
+PHP_PROTO_FIELD_ACCESSORS(FieldMask, field_mask, Paths, "paths")
+
+// -----------------------------------------------------------------------------
+// Field
+// -----------------------------------------------------------------------------
+
+static  zend_function_entry field_methods[] = {
+  PHP_ME(Field, __construct, NULL, ZEND_ACC_PUBLIC)
+  PHP_ME(Field, getKind, NULL, ZEND_ACC_PUBLIC)
+  PHP_ME(Field, setKind, NULL, ZEND_ACC_PUBLIC)
+  PHP_ME(Field, getCardinality, NULL, ZEND_ACC_PUBLIC)
+  PHP_ME(Field, setCardinality, NULL, ZEND_ACC_PUBLIC)
+  PHP_ME(Field, getNumber, NULL, ZEND_ACC_PUBLIC)
+  PHP_ME(Field, setNumber, NULL, ZEND_ACC_PUBLIC)
+  PHP_ME(Field, getName, NULL, ZEND_ACC_PUBLIC)
+  PHP_ME(Field, setName, NULL, ZEND_ACC_PUBLIC)
+  PHP_ME(Field, getTypeUrl, NULL, ZEND_ACC_PUBLIC)
+  PHP_ME(Field, setTypeUrl, NULL, ZEND_ACC_PUBLIC)
+  PHP_ME(Field, getOneofIndex, NULL, ZEND_ACC_PUBLIC)
+  PHP_ME(Field, setOneofIndex, NULL, ZEND_ACC_PUBLIC)
+  PHP_ME(Field, getPacked, NULL, ZEND_ACC_PUBLIC)
+  PHP_ME(Field, setPacked, NULL, ZEND_ACC_PUBLIC)
+  PHP_ME(Field, getOptions, NULL, ZEND_ACC_PUBLIC)
+  PHP_ME(Field, setOptions, NULL, ZEND_ACC_PUBLIC)
+  PHP_ME(Field, getJsonName, NULL, ZEND_ACC_PUBLIC)
+  PHP_ME(Field, setJsonName, NULL, ZEND_ACC_PUBLIC)
+  PHP_ME(Field, getDefaultValue, NULL, ZEND_ACC_PUBLIC)
+  PHP_ME(Field, setDefaultValue, NULL, ZEND_ACC_PUBLIC)
+  {NULL, NULL, NULL}
+};
+
+zend_class_entry* field_type;
+
+// Init class entry.
+PHP_PROTO_INIT_SUBMSGCLASS_START("Google\\Protobuf\\Field",
+                                 Field, field)
+  zend_class_implements(field_type TSRMLS_CC, 1, message_type);
+  zend_declare_property_null(field_type, "kind", strlen("kind"),
+                             ZEND_ACC_PRIVATE TSRMLS_CC);
+  zend_declare_property_null(field_type, "cardinality", strlen("cardinality"),
+                             ZEND_ACC_PRIVATE TSRMLS_CC);
+  zend_declare_property_null(field_type, "number", strlen("number"),
+                             ZEND_ACC_PRIVATE TSRMLS_CC);
+  zend_declare_property_null(field_type, "name", strlen("name"),
+                             ZEND_ACC_PRIVATE TSRMLS_CC);
+  zend_declare_property_null(field_type, "type_url", strlen("type_url"),
+                             ZEND_ACC_PRIVATE TSRMLS_CC);
+  zend_declare_property_null(field_type, "oneof_index", strlen("oneof_index"),
+                             ZEND_ACC_PRIVATE TSRMLS_CC);
+  zend_declare_property_null(field_type, "packed", strlen("packed"),
+                             ZEND_ACC_PRIVATE TSRMLS_CC);
+  zend_declare_property_null(field_type, "options", strlen("options"),
+                             ZEND_ACC_PRIVATE TSRMLS_CC);
+  zend_declare_property_null(field_type, "json_name", strlen("json_name"),
+                             ZEND_ACC_PRIVATE TSRMLS_CC);
+  zend_declare_property_null(field_type, "default_value", strlen("default_value"),
+                             ZEND_ACC_PRIVATE TSRMLS_CC);
+PHP_PROTO_INIT_SUBMSGCLASS_END
+
+PHP_METHOD(Field, __construct) {
+  init_file_type(TSRMLS_C);
+  MessageHeader* intern = UNBOX(MessageHeader, getThis());
+  custom_data_init(field_type, intern PHP_PROTO_TSRMLS_CC);
+}
+
+PHP_PROTO_FIELD_ACCESSORS(Field, field, Kind, "kind")
+PHP_PROTO_FIELD_ACCESSORS(Field, field, Cardinality, "cardinality")
+PHP_PROTO_FIELD_ACCESSORS(Field, field, Number, "number")
+PHP_PROTO_FIELD_ACCESSORS(Field, field, Name, "name")
+PHP_PROTO_FIELD_ACCESSORS(Field, field, TypeUrl, "type_url")
+PHP_PROTO_FIELD_ACCESSORS(Field, field, OneofIndex, "oneof_index")
+PHP_PROTO_FIELD_ACCESSORS(Field, field, Packed, "packed")
+PHP_PROTO_FIELD_ACCESSORS(Field, field, Options, "options")
+PHP_PROTO_FIELD_ACCESSORS(Field, field, JsonName, "json_name")
+PHP_PROTO_FIELD_ACCESSORS(Field, field, DefaultValue, "default_value")
+
+// -----------------------------------------------------------------------------
+// FloatValue
+// -----------------------------------------------------------------------------
+
+static  zend_function_entry float_value_methods[] = {
+  PHP_ME(FloatValue, __construct, NULL, ZEND_ACC_PUBLIC)
+  PHP_ME(FloatValue, getValue, NULL, ZEND_ACC_PUBLIC)
+  PHP_ME(FloatValue, setValue, NULL, ZEND_ACC_PUBLIC)
+  {NULL, NULL, NULL}
+};
+
+zend_class_entry* float_value_type;
+
+// Init class entry.
+PHP_PROTO_INIT_SUBMSGCLASS_START("Google\\Protobuf\\FloatValue",
+                                 FloatValue, float_value)
+  zend_class_implements(float_value_type TSRMLS_CC, 1, message_type);
+  zend_declare_property_null(float_value_type, "value", strlen("value"),
+                             ZEND_ACC_PRIVATE TSRMLS_CC);
+PHP_PROTO_INIT_SUBMSGCLASS_END
+
+PHP_METHOD(FloatValue, __construct) {
+  init_file_wrappers(TSRMLS_C);
+  MessageHeader* intern = UNBOX(MessageHeader, getThis());
+  custom_data_init(float_value_type, intern PHP_PROTO_TSRMLS_CC);
+}
+
+PHP_PROTO_FIELD_ACCESSORS(FloatValue, float_value, Value, "value")
+
+// -----------------------------------------------------------------------------
+// GPBEmpty
+// -----------------------------------------------------------------------------
+
+static  zend_function_entry empty_methods[] = {
+  PHP_ME(GPBEmpty, __construct, NULL, ZEND_ACC_PUBLIC)
+  {NULL, NULL, NULL}
+};
+
+zend_class_entry* empty_type;
+
+// Init class entry.
+PHP_PROTO_INIT_SUBMSGCLASS_START("Google\\Protobuf\\GPBEmpty",
+                                 GPBEmpty, empty)
+  zend_class_implements(empty_type TSRMLS_CC, 1, message_type);
+PHP_PROTO_INIT_SUBMSGCLASS_END
+
+PHP_METHOD(GPBEmpty, __construct) {
+  init_file_empty(TSRMLS_C);
+  MessageHeader* intern = UNBOX(MessageHeader, getThis());
+  custom_data_init(empty_type, intern PHP_PROTO_TSRMLS_CC);
+}
+
+
+// -----------------------------------------------------------------------------
+// Int32Value
+// -----------------------------------------------------------------------------
+
+static  zend_function_entry int32_value_methods[] = {
+  PHP_ME(Int32Value, __construct, NULL, ZEND_ACC_PUBLIC)
+  PHP_ME(Int32Value, getValue, NULL, ZEND_ACC_PUBLIC)
+  PHP_ME(Int32Value, setValue, NULL, ZEND_ACC_PUBLIC)
+  {NULL, NULL, NULL}
+};
+
+zend_class_entry* int32_value_type;
+
+// Init class entry.
+PHP_PROTO_INIT_SUBMSGCLASS_START("Google\\Protobuf\\Int32Value",
+                                 Int32Value, int32_value)
+  zend_class_implements(int32_value_type TSRMLS_CC, 1, message_type);
+  zend_declare_property_null(int32_value_type, "value", strlen("value"),
+                             ZEND_ACC_PRIVATE TSRMLS_CC);
+PHP_PROTO_INIT_SUBMSGCLASS_END
+
+PHP_METHOD(Int32Value, __construct) {
+  init_file_wrappers(TSRMLS_C);
+  MessageHeader* intern = UNBOX(MessageHeader, getThis());
+  custom_data_init(int32_value_type, intern PHP_PROTO_TSRMLS_CC);
+}
+
+PHP_PROTO_FIELD_ACCESSORS(Int32Value, int32_value, Value, "value")
+
+// -----------------------------------------------------------------------------
+// Int64Value
+// -----------------------------------------------------------------------------
+
+static  zend_function_entry int64_value_methods[] = {
+  PHP_ME(Int64Value, __construct, NULL, ZEND_ACC_PUBLIC)
+  PHP_ME(Int64Value, getValue, NULL, ZEND_ACC_PUBLIC)
+  PHP_ME(Int64Value, setValue, NULL, ZEND_ACC_PUBLIC)
+  {NULL, NULL, NULL}
+};
+
+zend_class_entry* int64_value_type;
+
+// Init class entry.
+PHP_PROTO_INIT_SUBMSGCLASS_START("Google\\Protobuf\\Int64Value",
+                                 Int64Value, int64_value)
+  zend_class_implements(int64_value_type TSRMLS_CC, 1, message_type);
+  zend_declare_property_null(int64_value_type, "value", strlen("value"),
+                             ZEND_ACC_PRIVATE TSRMLS_CC);
+PHP_PROTO_INIT_SUBMSGCLASS_END
+
+PHP_METHOD(Int64Value, __construct) {
+  init_file_wrappers(TSRMLS_C);
+  MessageHeader* intern = UNBOX(MessageHeader, getThis());
+  custom_data_init(int64_value_type, intern PHP_PROTO_TSRMLS_CC);
+}
+
+PHP_PROTO_FIELD_ACCESSORS(Int64Value, int64_value, Value, "value")
+
+// -----------------------------------------------------------------------------
+// ListValue
+// -----------------------------------------------------------------------------
+
+static  zend_function_entry list_value_methods[] = {
+  PHP_ME(ListValue, __construct, NULL, ZEND_ACC_PUBLIC)
+  PHP_ME(ListValue, getValues, NULL, ZEND_ACC_PUBLIC)
+  PHP_ME(ListValue, setValues, NULL, ZEND_ACC_PUBLIC)
+  {NULL, NULL, NULL}
+};
+
+zend_class_entry* list_value_type;
+
+// Init class entry.
+PHP_PROTO_INIT_SUBMSGCLASS_START("Google\\Protobuf\\ListValue",
+                                 ListValue, list_value)
+  zend_class_implements(list_value_type TSRMLS_CC, 1, message_type);
+  zend_declare_property_null(list_value_type, "values", strlen("values"),
+                             ZEND_ACC_PRIVATE TSRMLS_CC);
+PHP_PROTO_INIT_SUBMSGCLASS_END
+
+PHP_METHOD(ListValue, __construct) {
+  init_file_struct(TSRMLS_C);
+  MessageHeader* intern = UNBOX(MessageHeader, getThis());
+  custom_data_init(list_value_type, intern PHP_PROTO_TSRMLS_CC);
+}
+
+PHP_PROTO_FIELD_ACCESSORS(ListValue, list_value, Values, "values")
+
+// -----------------------------------------------------------------------------
+// Method
+// -----------------------------------------------------------------------------
+
+static  zend_function_entry method_methods[] = {
+  PHP_ME(Method, __construct, NULL, ZEND_ACC_PUBLIC)
+  PHP_ME(Method, getName, NULL, ZEND_ACC_PUBLIC)
+  PHP_ME(Method, setName, NULL, ZEND_ACC_PUBLIC)
+  PHP_ME(Method, getRequestTypeUrl, NULL, ZEND_ACC_PUBLIC)
+  PHP_ME(Method, setRequestTypeUrl, NULL, ZEND_ACC_PUBLIC)
+  PHP_ME(Method, getRequestStreaming, NULL, ZEND_ACC_PUBLIC)
+  PHP_ME(Method, setRequestStreaming, NULL, ZEND_ACC_PUBLIC)
+  PHP_ME(Method, getResponseTypeUrl, NULL, ZEND_ACC_PUBLIC)
+  PHP_ME(Method, setResponseTypeUrl, NULL, ZEND_ACC_PUBLIC)
+  PHP_ME(Method, getResponseStreaming, NULL, ZEND_ACC_PUBLIC)
+  PHP_ME(Method, setResponseStreaming, NULL, ZEND_ACC_PUBLIC)
+  PHP_ME(Method, getOptions, NULL, ZEND_ACC_PUBLIC)
+  PHP_ME(Method, setOptions, NULL, ZEND_ACC_PUBLIC)
+  PHP_ME(Method, getSyntax, NULL, ZEND_ACC_PUBLIC)
+  PHP_ME(Method, setSyntax, NULL, ZEND_ACC_PUBLIC)
+  {NULL, NULL, NULL}
+};
+
+zend_class_entry* method_type;
+
+// Init class entry.
+PHP_PROTO_INIT_SUBMSGCLASS_START("Google\\Protobuf\\Method",
+                                 Method, method)
+  zend_class_implements(method_type TSRMLS_CC, 1, message_type);
+  zend_declare_property_null(method_type, "name", strlen("name"),
+                             ZEND_ACC_PRIVATE TSRMLS_CC);
+  zend_declare_property_null(method_type, "request_type_url", strlen("request_type_url"),
+                             ZEND_ACC_PRIVATE TSRMLS_CC);
+  zend_declare_property_null(method_type, "request_streaming", strlen("request_streaming"),
+                             ZEND_ACC_PRIVATE TSRMLS_CC);
+  zend_declare_property_null(method_type, "response_type_url", strlen("response_type_url"),
+                             ZEND_ACC_PRIVATE TSRMLS_CC);
+  zend_declare_property_null(method_type, "response_streaming", strlen("response_streaming"),
+                             ZEND_ACC_PRIVATE TSRMLS_CC);
+  zend_declare_property_null(method_type, "options", strlen("options"),
+                             ZEND_ACC_PRIVATE TSRMLS_CC);
+  zend_declare_property_null(method_type, "syntax", strlen("syntax"),
+                             ZEND_ACC_PRIVATE TSRMLS_CC);
+PHP_PROTO_INIT_SUBMSGCLASS_END
+
+PHP_METHOD(Method, __construct) {
+  init_file_api(TSRMLS_C);
+  MessageHeader* intern = UNBOX(MessageHeader, getThis());
+  custom_data_init(method_type, intern PHP_PROTO_TSRMLS_CC);
+}
+
+PHP_PROTO_FIELD_ACCESSORS(Method, method, Name, "name")
+PHP_PROTO_FIELD_ACCESSORS(Method, method, RequestTypeUrl, "request_type_url")
+PHP_PROTO_FIELD_ACCESSORS(Method, method, RequestStreaming, "request_streaming")
+PHP_PROTO_FIELD_ACCESSORS(Method, method, ResponseTypeUrl, "response_type_url")
+PHP_PROTO_FIELD_ACCESSORS(Method, method, ResponseStreaming, "response_streaming")
+PHP_PROTO_FIELD_ACCESSORS(Method, method, Options, "options")
+PHP_PROTO_FIELD_ACCESSORS(Method, method, Syntax, "syntax")
+
+// -----------------------------------------------------------------------------
+// Mixin
+// -----------------------------------------------------------------------------
+
+static  zend_function_entry mixin_methods[] = {
+  PHP_ME(Mixin, __construct, NULL, ZEND_ACC_PUBLIC)
+  PHP_ME(Mixin, getName, NULL, ZEND_ACC_PUBLIC)
+  PHP_ME(Mixin, setName, NULL, ZEND_ACC_PUBLIC)
+  PHP_ME(Mixin, getRoot, NULL, ZEND_ACC_PUBLIC)
+  PHP_ME(Mixin, setRoot, NULL, ZEND_ACC_PUBLIC)
+  {NULL, NULL, NULL}
+};
+
+zend_class_entry* mixin_type;
+
+// Init class entry.
+PHP_PROTO_INIT_SUBMSGCLASS_START("Google\\Protobuf\\Mixin",
+                                 Mixin, mixin)
+  zend_class_implements(mixin_type TSRMLS_CC, 1, message_type);
+  zend_declare_property_null(mixin_type, "name", strlen("name"),
+                             ZEND_ACC_PRIVATE TSRMLS_CC);
+  zend_declare_property_null(mixin_type, "root", strlen("root"),
+                             ZEND_ACC_PRIVATE TSRMLS_CC);
+PHP_PROTO_INIT_SUBMSGCLASS_END
+
+PHP_METHOD(Mixin, __construct) {
+  init_file_api(TSRMLS_C);
+  MessageHeader* intern = UNBOX(MessageHeader, getThis());
+  custom_data_init(mixin_type, intern PHP_PROTO_TSRMLS_CC);
+}
+
+PHP_PROTO_FIELD_ACCESSORS(Mixin, mixin, Name, "name")
+PHP_PROTO_FIELD_ACCESSORS(Mixin, mixin, Root, "root")
+
+// -----------------------------------------------------------------------------
+// Option
+// -----------------------------------------------------------------------------
+
+static  zend_function_entry option_methods[] = {
+  PHP_ME(Option, __construct, NULL, ZEND_ACC_PUBLIC)
+  PHP_ME(Option, getName, NULL, ZEND_ACC_PUBLIC)
+  PHP_ME(Option, setName, NULL, ZEND_ACC_PUBLIC)
+  PHP_ME(Option, getValue, NULL, ZEND_ACC_PUBLIC)
+  PHP_ME(Option, setValue, NULL, ZEND_ACC_PUBLIC)
+  {NULL, NULL, NULL}
+};
+
+zend_class_entry* option_type;
+
+// Init class entry.
+PHP_PROTO_INIT_SUBMSGCLASS_START("Google\\Protobuf\\Option",
+                                 Option, option)
+  zend_class_implements(option_type TSRMLS_CC, 1, message_type);
+  zend_declare_property_null(option_type, "name", strlen("name"),
+                             ZEND_ACC_PRIVATE TSRMLS_CC);
+  zend_declare_property_null(option_type, "value", strlen("value"),
+                             ZEND_ACC_PRIVATE TSRMLS_CC);
+PHP_PROTO_INIT_SUBMSGCLASS_END
+
+PHP_METHOD(Option, __construct) {
+  init_file_type(TSRMLS_C);
+  MessageHeader* intern = UNBOX(MessageHeader, getThis());
+  custom_data_init(option_type, intern PHP_PROTO_TSRMLS_CC);
+}
+
+PHP_PROTO_FIELD_ACCESSORS(Option, option, Name, "name")
+PHP_PROTO_FIELD_ACCESSORS(Option, option, Value, "value")
+
+// -----------------------------------------------------------------------------
+// SourceContext
+// -----------------------------------------------------------------------------
+
+static  zend_function_entry source_context_methods[] = {
+  PHP_ME(SourceContext, __construct, NULL, ZEND_ACC_PUBLIC)
+  PHP_ME(SourceContext, getFileName, NULL, ZEND_ACC_PUBLIC)
+  PHP_ME(SourceContext, setFileName, NULL, ZEND_ACC_PUBLIC)
+  {NULL, NULL, NULL}
+};
+
+zend_class_entry* source_context_type;
+
+// Init class entry.
+PHP_PROTO_INIT_SUBMSGCLASS_START("Google\\Protobuf\\SourceContext",
+                                 SourceContext, source_context)
+  zend_class_implements(source_context_type TSRMLS_CC, 1, message_type);
+  zend_declare_property_null(source_context_type, "file_name", strlen("file_name"),
+                             ZEND_ACC_PRIVATE TSRMLS_CC);
+PHP_PROTO_INIT_SUBMSGCLASS_END
+
+PHP_METHOD(SourceContext, __construct) {
+  init_file_source_context(TSRMLS_C);
+  MessageHeader* intern = UNBOX(MessageHeader, getThis());
+  custom_data_init(source_context_type, intern PHP_PROTO_TSRMLS_CC);
+}
+
+PHP_PROTO_FIELD_ACCESSORS(SourceContext, source_context, FileName, "file_name")
+
+// -----------------------------------------------------------------------------
+// StringValue
+// -----------------------------------------------------------------------------
+
+static  zend_function_entry string_value_methods[] = {
+  PHP_ME(StringValue, __construct, NULL, ZEND_ACC_PUBLIC)
+  PHP_ME(StringValue, getValue, NULL, ZEND_ACC_PUBLIC)
+  PHP_ME(StringValue, setValue, NULL, ZEND_ACC_PUBLIC)
+  {NULL, NULL, NULL}
+};
+
+zend_class_entry* string_value_type;
+
+// Init class entry.
+PHP_PROTO_INIT_SUBMSGCLASS_START("Google\\Protobuf\\StringValue",
+                                 StringValue, string_value)
+  zend_class_implements(string_value_type TSRMLS_CC, 1, message_type);
+  zend_declare_property_null(string_value_type, "value", strlen("value"),
+                             ZEND_ACC_PRIVATE TSRMLS_CC);
+PHP_PROTO_INIT_SUBMSGCLASS_END
+
+PHP_METHOD(StringValue, __construct) {
+  init_file_wrappers(TSRMLS_C);
+  MessageHeader* intern = UNBOX(MessageHeader, getThis());
+  custom_data_init(string_value_type, intern PHP_PROTO_TSRMLS_CC);
+}
+
+PHP_PROTO_FIELD_ACCESSORS(StringValue, string_value, Value, "value")
+
+// -----------------------------------------------------------------------------
+// Struct
+// -----------------------------------------------------------------------------
+
+static  zend_function_entry struct_methods[] = {
+  PHP_ME(Struct, __construct, NULL, ZEND_ACC_PUBLIC)
+  PHP_ME(Struct, getFields, NULL, ZEND_ACC_PUBLIC)
+  PHP_ME(Struct, setFields, NULL, ZEND_ACC_PUBLIC)
+  {NULL, NULL, NULL}
+};
+
+zend_class_entry* struct_type;
+
+// Init class entry.
+PHP_PROTO_INIT_SUBMSGCLASS_START("Google\\Protobuf\\Struct",
+                                 Struct, struct)
+  zend_class_implements(struct_type TSRMLS_CC, 1, message_type);
+  zend_declare_property_null(struct_type, "fields", strlen("fields"),
+                             ZEND_ACC_PRIVATE TSRMLS_CC);
+PHP_PROTO_INIT_SUBMSGCLASS_END
+
+PHP_METHOD(Struct, __construct) {
+  init_file_struct(TSRMLS_C);
+  MessageHeader* intern = UNBOX(MessageHeader, getThis());
+  custom_data_init(struct_type, intern PHP_PROTO_TSRMLS_CC);
+}
+
+PHP_PROTO_FIELD_ACCESSORS(Struct, struct, Fields, "fields")
+
+// -----------------------------------------------------------------------------
+// Type
+// -----------------------------------------------------------------------------
+
+static  zend_function_entry type_methods[] = {
+  PHP_ME(Type, __construct, NULL, ZEND_ACC_PUBLIC)
+  PHP_ME(Type, getName, NULL, ZEND_ACC_PUBLIC)
+  PHP_ME(Type, setName, NULL, ZEND_ACC_PUBLIC)
+  PHP_ME(Type, getFields, NULL, ZEND_ACC_PUBLIC)
+  PHP_ME(Type, setFields, NULL, ZEND_ACC_PUBLIC)
+  PHP_ME(Type, getOneofs, NULL, ZEND_ACC_PUBLIC)
+  PHP_ME(Type, setOneofs, NULL, ZEND_ACC_PUBLIC)
+  PHP_ME(Type, getOptions, NULL, ZEND_ACC_PUBLIC)
+  PHP_ME(Type, setOptions, NULL, ZEND_ACC_PUBLIC)
+  PHP_ME(Type, getSourceContext, NULL, ZEND_ACC_PUBLIC)
+  PHP_ME(Type, setSourceContext, NULL, ZEND_ACC_PUBLIC)
+  PHP_ME(Type, getSyntax, NULL, ZEND_ACC_PUBLIC)
+  PHP_ME(Type, setSyntax, NULL, ZEND_ACC_PUBLIC)
+  {NULL, NULL, NULL}
+};
+
+zend_class_entry* type_type;
+
+// Init class entry.
+PHP_PROTO_INIT_SUBMSGCLASS_START("Google\\Protobuf\\Type",
+                                 Type, type)
+  zend_class_implements(type_type TSRMLS_CC, 1, message_type);
+  zend_declare_property_null(type_type, "name", strlen("name"),
+                             ZEND_ACC_PRIVATE TSRMLS_CC);
+  zend_declare_property_null(type_type, "fields", strlen("fields"),
+                             ZEND_ACC_PRIVATE TSRMLS_CC);
+  zend_declare_property_null(type_type, "oneofs", strlen("oneofs"),
+                             ZEND_ACC_PRIVATE TSRMLS_CC);
+  zend_declare_property_null(type_type, "options", strlen("options"),
+                             ZEND_ACC_PRIVATE TSRMLS_CC);
+  zend_declare_property_null(type_type, "source_context", strlen("source_context"),
+                             ZEND_ACC_PRIVATE TSRMLS_CC);
+  zend_declare_property_null(type_type, "syntax", strlen("syntax"),
+                             ZEND_ACC_PRIVATE TSRMLS_CC);
+PHP_PROTO_INIT_SUBMSGCLASS_END
+
+PHP_METHOD(Type, __construct) {
+  init_file_type(TSRMLS_C);
+  MessageHeader* intern = UNBOX(MessageHeader, getThis());
+  custom_data_init(type_type, intern PHP_PROTO_TSRMLS_CC);
+}
+
+PHP_PROTO_FIELD_ACCESSORS(Type, type, Name, "name")
+PHP_PROTO_FIELD_ACCESSORS(Type, type, Fields, "fields")
+PHP_PROTO_FIELD_ACCESSORS(Type, type, Oneofs, "oneofs")
+PHP_PROTO_FIELD_ACCESSORS(Type, type, Options, "options")
+PHP_PROTO_FIELD_ACCESSORS(Type, type, SourceContext, "source_context")
+PHP_PROTO_FIELD_ACCESSORS(Type, type, Syntax, "syntax")
+
+// -----------------------------------------------------------------------------
+// UInt32Value
+// -----------------------------------------------------------------------------
+
+static  zend_function_entry u_int32_value_methods[] = {
+  PHP_ME(UInt32Value, __construct, NULL, ZEND_ACC_PUBLIC)
+  PHP_ME(UInt32Value, getValue, NULL, ZEND_ACC_PUBLIC)
+  PHP_ME(UInt32Value, setValue, NULL, ZEND_ACC_PUBLIC)
+  {NULL, NULL, NULL}
+};
+
+zend_class_entry* u_int32_value_type;
+
+// Init class entry.
+PHP_PROTO_INIT_SUBMSGCLASS_START("Google\\Protobuf\\UInt32Value",
+                                 UInt32Value, u_int32_value)
+  zend_class_implements(u_int32_value_type TSRMLS_CC, 1, message_type);
+  zend_declare_property_null(u_int32_value_type, "value", strlen("value"),
+                             ZEND_ACC_PRIVATE TSRMLS_CC);
+PHP_PROTO_INIT_SUBMSGCLASS_END
+
+PHP_METHOD(UInt32Value, __construct) {
+  init_file_wrappers(TSRMLS_C);
+  MessageHeader* intern = UNBOX(MessageHeader, getThis());
+  custom_data_init(u_int32_value_type, intern PHP_PROTO_TSRMLS_CC);
+}
+
+PHP_PROTO_FIELD_ACCESSORS(UInt32Value, u_int32_value, Value, "value")
+
+// -----------------------------------------------------------------------------
+// UInt64Value
+// -----------------------------------------------------------------------------
+
+static  zend_function_entry u_int64_value_methods[] = {
+  PHP_ME(UInt64Value, __construct, NULL, ZEND_ACC_PUBLIC)
+  PHP_ME(UInt64Value, getValue, NULL, ZEND_ACC_PUBLIC)
+  PHP_ME(UInt64Value, setValue, NULL, ZEND_ACC_PUBLIC)
+  {NULL, NULL, NULL}
+};
+
+zend_class_entry* u_int64_value_type;
+
+// Init class entry.
+PHP_PROTO_INIT_SUBMSGCLASS_START("Google\\Protobuf\\UInt64Value",
+                                 UInt64Value, u_int64_value)
+  zend_class_implements(u_int64_value_type TSRMLS_CC, 1, message_type);
+  zend_declare_property_null(u_int64_value_type, "value", strlen("value"),
+                             ZEND_ACC_PRIVATE TSRMLS_CC);
+PHP_PROTO_INIT_SUBMSGCLASS_END
+
+PHP_METHOD(UInt64Value, __construct) {
+  init_file_wrappers(TSRMLS_C);
+  MessageHeader* intern = UNBOX(MessageHeader, getThis());
+  custom_data_init(u_int64_value_type, intern PHP_PROTO_TSRMLS_CC);
+}
+
+PHP_PROTO_FIELD_ACCESSORS(UInt64Value, u_int64_value, Value, "value")
+
+// -----------------------------------------------------------------------------
+// Value
+// -----------------------------------------------------------------------------
+
+static zend_function_entry value_methods[] = {
+  PHP_ME(Value, __construct, NULL, ZEND_ACC_PUBLIC)
+  PHP_ME(Value, getNullValue, NULL, ZEND_ACC_PUBLIC)
+  PHP_ME(Value, setNullValue, NULL, ZEND_ACC_PUBLIC)
+  PHP_ME(Value, getNumberValue, NULL, ZEND_ACC_PUBLIC)
+  PHP_ME(Value, setNumberValue, NULL, ZEND_ACC_PUBLIC)
+  PHP_ME(Value, getStringValue, NULL, ZEND_ACC_PUBLIC)
+  PHP_ME(Value, setStringValue, NULL, ZEND_ACC_PUBLIC)
+  PHP_ME(Value, getBoolValue, NULL, ZEND_ACC_PUBLIC)
+  PHP_ME(Value, setBoolValue, NULL, ZEND_ACC_PUBLIC)
+  PHP_ME(Value, getStructValue, NULL, ZEND_ACC_PUBLIC)
+  PHP_ME(Value, setStructValue, NULL, ZEND_ACC_PUBLIC)
+  PHP_ME(Value, getListValue, NULL, ZEND_ACC_PUBLIC)
+  PHP_ME(Value, setListValue, NULL, ZEND_ACC_PUBLIC)
+  PHP_ME(Value, getKind, NULL, ZEND_ACC_PUBLIC)
+  {NULL, NULL, NULL}
+};
+
+zend_class_entry* value_type;
+
+// Init class entry.
+PHP_PROTO_INIT_SUBMSGCLASS_START("Google\\Protobuf\\Value",
+                                 Value, value)
+  zend_class_implements(value_type TSRMLS_CC, 1, message_type);
+  zend_declare_property_null(value_type, "kind", strlen("kind"),
+                             ZEND_ACC_PRIVATE TSRMLS_CC);
+PHP_PROTO_INIT_SUBMSGCLASS_END
+
+PHP_METHOD(Value, __construct) {
+  init_file_struct(TSRMLS_C);
+  MessageHeader* intern = UNBOX(MessageHeader, getThis());
+  custom_data_init(value_type, intern PHP_PROTO_TSRMLS_CC);
+}
+
+PHP_PROTO_ONEOF_FIELD_ACCESSORS(Value, value, NullValue, "null_value")
+PHP_PROTO_ONEOF_FIELD_ACCESSORS(Value, value, NumberValue, "number_value")
+PHP_PROTO_ONEOF_FIELD_ACCESSORS(Value, value, StringValue, "string_value")
+PHP_PROTO_ONEOF_FIELD_ACCESSORS(Value, value, BoolValue, "bool_value")
+PHP_PROTO_ONEOF_FIELD_ACCESSORS(Value, value, StructValue, "struct_value")
+PHP_PROTO_ONEOF_FIELD_ACCESSORS(Value, value, ListValue, "list_value")
+PHP_PROTO_ONEOF_ACCESSORS(Value, value, Kind, "kind")
+
+// -----------------------------------------------------------------------------
+// GPBMetadata files for well known types
+// -----------------------------------------------------------------------------
+
+#define DEFINE_GPBMETADATA_FILE(LOWERNAME, CAMELNAME, CLASSNAME)      \
+  zend_class_entry* gpb_metadata_##LOWERNAME##_type;                  \
+  static zend_function_entry gpb_metadata_##LOWERNAME##_methods[] = { \
+    PHP_ME(GPBMetadata_##CAMELNAME, initOnce, NULL,                   \
+           ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)                         \
+    ZEND_FE_END                                                       \
+  };                                                                  \
+  void gpb_metadata_##LOWERNAME##_init(TSRMLS_D) {                    \
+    zend_class_entry class_type;                                      \
+    INIT_CLASS_ENTRY(class_type, CLASSNAME,                           \
+                     gpb_metadata_##LOWERNAME##_methods);             \
+    gpb_metadata_##LOWERNAME##_type =                                 \
+        zend_register_internal_class(&class_type TSRMLS_CC);          \
+  }                                                                   \
+  PHP_METHOD(GPBMetadata_##CAMELNAME, initOnce) {                     \
+    init_file_##LOWERNAME(TSRMLS_C);                                  \
+  }
+
+DEFINE_GPBMETADATA_FILE(any, Any, "GPBMetadata\\Google\\Protobuf\\Any");
+DEFINE_GPBMETADATA_FILE(api, Api, "GPBMetadata\\Google\\Protobuf\\Api");
+DEFINE_GPBMETADATA_FILE(duration, Duration,
+                        "GPBMetadata\\Google\\Protobuf\\Duration");
+DEFINE_GPBMETADATA_FILE(field_mask, FieldMask,
+                        "GPBMetadata\\Google\\Protobuf\\FieldMask");
+DEFINE_GPBMETADATA_FILE(empty, Empty,
+                        "GPBMetadata\\Google\\Protobuf\\GPBEmpty");
+DEFINE_GPBMETADATA_FILE(source_context, SourceContext,
+                        "GPBMetadata\\Google\\Protobuf\\SourceContext");
+DEFINE_GPBMETADATA_FILE(struct, Struct,
+                        "GPBMetadata\\Google\\Protobuf\\Struct");
+DEFINE_GPBMETADATA_FILE(timestamp, Timestamp,
+                        "GPBMetadata\\Google\\Protobuf\\Timestamp");
+DEFINE_GPBMETADATA_FILE(type, Type, "GPBMetadata\\Google\\Protobuf\\Type");
+DEFINE_GPBMETADATA_FILE(wrappers, Wrappers,
+                        "GPBMetadata\\Google\\Protobuf\\Wrappers");
+
+#undef DEFINE_GPBMETADATA_FILE
diff --git a/php/ext/google/protobuf/package.xml b/php/ext/google/protobuf/package.xml
new file mode 100644
index 0000000..28d713f
--- /dev/null
+++ b/php/ext/google/protobuf/package.xml
@@ -0,0 +1,252 @@
+<?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>protobuf</name>
+ <channel>pecl.php.net</channel>
+ <summary>Google's language-neutral, platform-neutral, extensible mechanism for serializing structured data.</summary>
+ <description>https://developers.google.com/protocol-buffers/</description>
+ <lead>
+  <name>Bo Yang</name>
+  <user>stanleycheung</user>
+  <email>protobuf-opensource@google.com</email>
+  <active>yes</active>
+ </lead>
+ <date>2018-06-06</date>
+ <time>11:02:07</time>
+ <version>
+  <release>3.6.0</release>
+  <api>3.6.0</api>
+ </version>
+ <stability>
+  <release>stable</release>
+  <api>stable</api>
+ </stability>
+ <license uri="https://opensource.org/licenses/BSD-3-Clause">3-Clause BSD License</license>
+ <notes>
+GA release.
+ </notes>
+ <contents>
+  <dir baseinstalldir="/" name="/">
+    <file baseinstalldir="/" name="config.m4" role="src" />
+    <file baseinstalldir="/" name="array.c" role="src" />
+    <file baseinstalldir="/" name="def.c" role="src" />
+    <file baseinstalldir="/" name="encode_decode.c" role="src" />
+    <file baseinstalldir="/" name="map.c" role="src" />
+    <file baseinstalldir="/" name="message.c" role="src" />
+    <file baseinstalldir="/" name="protobuf.c" role="src" />
+    <file baseinstalldir="/" name="protobuf.h" role="src" />
+    <file baseinstalldir="/" name="storage.c" role="src" />
+    <file baseinstalldir="/" name="type_check.c" role="src" />
+    <file baseinstalldir="/" name="upb.c" role="src" />
+    <file baseinstalldir="/" name="upb.h" role="src" />
+    <file baseinstalldir="/" name="utf8.c" role="src" />
+    <file baseinstalldir="/" name="utf8.h" role="src" />
+    <file baseinstalldir="/" name="LICENSE" role="doc" />
+  </dir>
+ </contents>
+ <dependencies>
+  <required>
+   <php>
+    <min>5.5.9</min>
+   </php>
+   <pearinstaller>
+    <min>1.4.0</min>
+   </pearinstaller>
+  </required>
+ </dependencies>
+ <providesextension>protobuf</providesextension>
+ <extsrcrelease />
+ <changelog>
+  <release>
+   <version>
+    <release>3.1.0a1</release>
+    <api>3.1.0a1</api>
+   </version>
+   <stability>
+    <release>alpha</release>
+    <api>alpha</api>
+   </stability>
+   <date>2016-09-23</date>
+   <time>16:06:07</time>
+   <license uri="https://opensource.org/licenses/BSD-3-Clause">3-Clause BSD License</license>
+   <notes>
+First alpha release
+   </notes>
+  </release>
+  <release>
+   <version>
+    <release>3.2.0a1</release>
+    <api>3.2.0a1</api>
+   </version>
+   <stability>
+    <release>alpha</release>
+    <api>alpha</api>
+   </stability>
+   <date>2017-01-13</date>
+   <time>16:06:07</time>
+   <license uri="https://opensource.org/licenses/BSD-3-Clause">3-Clause BSD License</license>
+   <notes>
+Second alpha release.
+   </notes>
+  </release>
+  <release>
+   <version>
+    <release>3.3.0</release>
+    <api>3.3.0</api>
+   </version>
+   <stability>
+    <release>stable</release>
+    <api>stable</api>
+   </stability>
+   <date>2017-04-28</date>
+   <time>16:06:07</time>
+   <license uri="https://opensource.org/licenses/BSD-3-Clause">3-Clause BSD License</license>
+   <notes>
+GA release.
+   </notes>
+  </release>
+  <release>
+   <version>
+    <release>3.3.1</release>
+    <api>3.3.0</api>
+   </version>
+   <stability>
+    <release>stable</release>
+    <api>stable</api>
+   </stability>
+   <date>2017-05-08</date>
+   <time>15:33:07</time>
+   <license uri="https://opensource.org/licenses/BSD-3-Clause">3-Clause BSD License</license>
+   <notes>
+GA release.
+   </notes>
+  </release>
+  <release>
+   <version>
+    <release>3.3.2</release>
+    <api>3.3.0</api>
+   </version>
+   <stability>
+    <release>stable</release>
+    <api>stable</api>
+   </stability>
+   <date>2017-06-21</date>
+   <time>15:33:07</time>
+   <license uri="https://opensource.org/licenses/BSD-3-Clause">3-Clause BSD License</license>
+   <notes>
+GA release.
+   </notes>
+  </release>
+  <release>
+   <version>
+    <release>3.4.0</release>
+    <api>3.4.0</api>
+   </version>
+   <stability>
+    <release>stable</release>
+    <api>stable</api>
+   </stability>
+   <date>2017-08-16</date>
+   <time>15:33:07</time>
+   <license uri="https://opensource.org/licenses/BSD-3-Clause">3-Clause BSD License</license>
+   <notes>
+GA release.
+   </notes>
+  </release>
+  <release>
+   <version>
+    <release>3.4.1</release>
+    <api>3.4.1</api>
+   </version>
+   <stability>
+    <release>stable</release>
+    <api>stable</api>
+   </stability>
+   <date>2017-09-14</date>
+   <time>11:02:07</time>
+   <license uri="https://opensource.org/licenses/BSD-3-Clause">3-Clause BSD License</license>
+   <notes>
+GA release.
+   </notes>
+  </release>
+  <release>
+   <version>
+    <release>3.5.0</release>
+    <api>3.5.0</api>
+   </version>
+   <stability>
+    <release>stable</release>
+    <api>stable</api>
+   </stability>
+   <date>2017-11-15</date>
+   <time>11:02:07</time>
+   <license uri="https://opensource.org/licenses/BSD-3-Clause">3-Clause BSD License</license>
+   <notes>
+GA release.
+   </notes>
+  </release>
+  <release>
+   <version>
+    <release>3.5.0.1</release>
+    <api>3.5.0.1</api>
+   </version>
+   <stability>
+    <release>stable</release>
+    <api>stable</api>
+   </stability>
+   <date>2017-12-06</date>
+   <time>11:02:07</time>
+   <license uri="https://opensource.org/licenses/BSD-3-Clause">3-Clause BSD License</license>
+   <notes>
+GA release.
+   </notes>
+  </release>
+  <release>
+   <version>
+    <release>3.5.1</release>
+    <api>3.5.1</api>
+   </version>
+   <stability>
+    <release>stable</release>
+    <api>stable</api>
+   </stability>
+   <date>2017-12-11</date>
+   <time>11:02:07</time>
+   <license uri="https://opensource.org/licenses/BSD-3-Clause">3-Clause BSD License</license>
+   <notes>
+GA release.
+   </notes>
+  </release>
+  <release>
+   <version>
+    <release>3.5.2</release>
+    <api>3.5.2</api>
+   </version>
+   <stability>
+    <release>stable</release>
+    <api>stable</api>
+   </stability>
+   <date>2018-03-06</date>
+   <time>11:02:07</time>
+   <license uri="https://opensource.org/licenses/BSD-3-Clause">3-Clause BSD License</license>
+   <notes>
+G  A release.
+   </notes>
+  </release>
+  <release>
+   <version>
+    <release>3.6.0</release>
+    <api>3.6.0</api>
+   </version>
+   <stability>
+    <release>stable</release>
+    <api>stable</api>
+   </stability>
+   <date>2018-06-06</date>
+   <time>11:02:07</time>
+   <license uri="https://opensource.org/licenses/BSD-3-Clause">3-Clause BSD License</license>
+   <notes>
+G  A release.
+   </notes>
+  </release>
+ </changelog>
+</package>
diff --git a/php/ext/google/protobuf/protobuf.c b/php/ext/google/protobuf/protobuf.c
new file mode 100644
index 0000000..19cc5ef
--- /dev/null
+++ b/php/ext/google/protobuf/protobuf.c
@@ -0,0 +1,401 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// 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.
+
+#include "protobuf.h"
+
+#include <zend_hash.h>
+
+ZEND_DECLARE_MODULE_GLOBALS(protobuf)
+static PHP_GINIT_FUNCTION(protobuf);
+static PHP_GSHUTDOWN_FUNCTION(protobuf);
+static PHP_RINIT_FUNCTION(protobuf);
+static PHP_RSHUTDOWN_FUNCTION(protobuf);
+static PHP_MINIT_FUNCTION(protobuf);
+static PHP_MSHUTDOWN_FUNCTION(protobuf);
+
+// Global map from upb {msg,enum}defs to wrapper Descriptor/EnumDescriptor
+// instances.
+static HashTable* upb_def_to_php_obj_map;
+// Global map from message/enum's php class entry to corresponding wrapper
+// Descriptor/EnumDescriptor instances.
+static HashTable* ce_to_php_obj_map;
+// Global map from message/enum's proto fully-qualified name to corresponding
+// wrapper Descriptor/EnumDescriptor instances.
+static HashTable* proto_to_php_obj_map;
+static HashTable* reserved_names;
+
+// -----------------------------------------------------------------------------
+// Global maps.
+// -----------------------------------------------------------------------------
+
+static void add_to_table(HashTable* t, const void* def, void* value) {
+  uint nIndex = (ulong)def & t->nTableMask;
+
+  zval* pDest = NULL;
+  php_proto_zend_hash_index_update_mem(t, (zend_ulong)def, &value,
+                                       sizeof(zval*), (void**)&pDest);
+}
+
+static void* get_from_table(const HashTable* t, const void* def) {
+  void** value;
+  if (php_proto_zend_hash_index_find_mem(t, (zend_ulong)def, (void**)&value) ==
+      FAILURE) {
+    return NULL;
+  }
+  return *value;
+}
+
+static bool exist_in_table(const HashTable* t, const void* def) {
+  void** value;
+  return (php_proto_zend_hash_index_find_mem(t, (zend_ulong)def,
+                                             (void**)&value) == SUCCESS);
+}
+
+static void add_to_list(HashTable* t, void* value) {
+  zval* pDest = NULL;
+  php_proto_zend_hash_next_index_insert_mem(t, &value, sizeof(void*),
+                                        (void**)&pDest);
+}
+
+static void add_to_strtable(HashTable* t, const char* key, int key_size,
+                            void* value) {
+  zval* pDest = NULL;
+  php_proto_zend_hash_update_mem(t, key, key_size, &value, sizeof(void*),
+                                 (void**)&pDest);
+}
+
+static void* get_from_strtable(const HashTable* t, const char* key, int key_size) {
+  void** value;
+  if (php_proto_zend_hash_find_mem(t, key, key_size, (void**)&value) ==
+      FAILURE) {
+    return NULL;
+  }
+  return *value;
+}
+
+void add_def_obj(const void* def, PHP_PROTO_HASHTABLE_VALUE value) {
+#if PHP_MAJOR_VERSION < 7
+  Z_ADDREF_P(value);
+#else
+  GC_ADDREF(value);
+#endif
+  add_to_table(upb_def_to_php_obj_map, def, value);
+}
+
+PHP_PROTO_HASHTABLE_VALUE get_def_obj(const void* def) {
+  return (PHP_PROTO_HASHTABLE_VALUE)get_from_table(upb_def_to_php_obj_map, def);
+}
+
+void add_ce_obj(const void* ce, PHP_PROTO_HASHTABLE_VALUE value) {
+#if PHP_MAJOR_VERSION < 7
+  Z_ADDREF_P(value);
+#else
+  GC_ADDREF(value);
+#endif
+  add_to_table(ce_to_php_obj_map, ce, value);
+}
+
+PHP_PROTO_HASHTABLE_VALUE get_ce_obj(const void* ce) {
+  return (PHP_PROTO_HASHTABLE_VALUE)get_from_table(ce_to_php_obj_map, ce);
+}
+
+bool class_added(const void* ce) {
+  return exist_in_table(ce_to_php_obj_map, ce);
+}
+
+void add_proto_obj(const char* proto, PHP_PROTO_HASHTABLE_VALUE value) {
+#if PHP_MAJOR_VERSION < 7
+  Z_ADDREF_P(value);
+#else
+  GC_ADDREF(value);
+#endif
+  add_to_strtable(proto_to_php_obj_map, proto, strlen(proto), value);
+}
+
+PHP_PROTO_HASHTABLE_VALUE get_proto_obj(const char* proto) {
+  return (PHP_PROTO_HASHTABLE_VALUE)get_from_strtable(proto_to_php_obj_map,
+                                                      proto, strlen(proto));
+}
+
+// -----------------------------------------------------------------------------
+// Well Known Types.
+// -----------------------------------------------------------------------------
+
+bool is_inited_file_any;
+bool is_inited_file_api;
+bool is_inited_file_duration;
+bool is_inited_file_field_mask;
+bool is_inited_file_empty;
+bool is_inited_file_source_context;
+bool is_inited_file_struct;
+bool is_inited_file_timestamp;
+bool is_inited_file_type;
+bool is_inited_file_wrappers;
+
+// -----------------------------------------------------------------------------
+// Reserved Name.
+// -----------------------------------------------------------------------------
+
+// Although we already have kReservedNames, we still add them to hash table to
+// speed up look up.
+const char *const kReservedNames[] = {
+    "abstract",   "and",        "array",        "as",           "break",
+    "callable",   "case",       "catch",        "class",        "clone",
+    "const",      "continue",   "declare",      "default",      "die",
+    "do",         "echo",       "else",         "elseif",       "empty",
+    "enddeclare", "endfor",     "endforeach",   "endif",        "endswitch",
+    "endwhile",   "eval",       "exit",         "extends",      "final",
+    "for",        "foreach",    "function",     "global",       "goto",
+    "if",         "implements", "include",      "include_once", "instanceof",
+    "insteadof",  "interface",  "isset",        "list",         "namespace",
+    "new",        "or",         "print",        "private",      "protected",
+    "public",     "require",    "require_once", "return",       "static",
+    "switch",     "throw",      "trait",        "try",          "unset",
+    "use",        "var",        "while",        "xor",          "int",
+    "float",      "bool",       "string",       "true",         "false",
+    "null",       "void",       "iterable"};
+const int kReservedNamesSize = 73;
+
+bool is_reserved_name(const char* name) {
+  void** value;
+  return (php_proto_zend_hash_find(reserved_names, name, strlen(name),
+                                   (void**)&value) == SUCCESS);
+}
+
+// -----------------------------------------------------------------------------
+// Utilities.
+// -----------------------------------------------------------------------------
+
+zend_function_entry protobuf_functions[] = {
+  ZEND_FE_END
+};
+
+static const zend_module_dep protobuf_deps[] = {
+  ZEND_MOD_OPTIONAL("date")
+  ZEND_MOD_END
+};
+
+zend_module_entry protobuf_module_entry = {
+  STANDARD_MODULE_HEADER_EX,
+  NULL,
+  protobuf_deps,
+  PHP_PROTOBUF_EXTNAME,     // extension name
+  protobuf_functions,       // function list
+  PHP_MINIT(protobuf),      // process startup
+  PHP_MSHUTDOWN(protobuf),  // process shutdown
+  PHP_RINIT(protobuf),      // request shutdown
+  PHP_RSHUTDOWN(protobuf),  // request shutdown
+  NULL,                 // extension info
+  PHP_PROTOBUF_VERSION, // extension version
+  PHP_MODULE_GLOBALS(protobuf),  // globals descriptor
+  PHP_GINIT(protobuf),  // globals ctor
+  PHP_GSHUTDOWN(protobuf),  // globals dtor
+  NULL,  // post deactivate
+  STANDARD_MODULE_PROPERTIES_EX
+};
+
+// install module
+ZEND_GET_MODULE(protobuf)
+
+// global variables
+static PHP_GINIT_FUNCTION(protobuf) {
+}
+
+static PHP_GSHUTDOWN_FUNCTION(protobuf) {
+}
+
+#if PHP_MAJOR_VERSION >= 7
+static void php_proto_hashtable_descriptor_release(zval* value) {
+  void* ptr = Z_PTR_P(value);
+  zend_object* object = *(zend_object**)ptr;
+  GC_DELREF(object);
+  if(GC_REFCOUNT(object) == 0) {
+    zend_objects_store_del(object);
+  }
+  efree(ptr);
+}
+#endif
+
+static PHP_RINIT_FUNCTION(protobuf) {
+  int i = 0;
+
+  ALLOC_HASHTABLE(upb_def_to_php_obj_map);
+  zend_hash_init(upb_def_to_php_obj_map, 16, NULL, HASHTABLE_VALUE_DTOR, 0);
+
+  ALLOC_HASHTABLE(ce_to_php_obj_map);
+  zend_hash_init(ce_to_php_obj_map, 16, NULL, HASHTABLE_VALUE_DTOR, 0);
+
+  ALLOC_HASHTABLE(proto_to_php_obj_map);
+  zend_hash_init(proto_to_php_obj_map, 16, NULL, HASHTABLE_VALUE_DTOR, 0);
+
+  ALLOC_HASHTABLE(reserved_names);
+  zend_hash_init(reserved_names, 16, NULL, NULL, 0);
+  for (i = 0; i < kReservedNamesSize; i++) {
+    php_proto_zend_hash_update(reserved_names, kReservedNames[i],
+                               strlen(kReservedNames[i]));
+  }
+
+  generated_pool = NULL;
+  generated_pool_php = NULL;
+  internal_generated_pool_php = NULL;
+
+  is_inited_file_any = false;
+  is_inited_file_api = false;
+  is_inited_file_duration = false;
+  is_inited_file_field_mask = false;
+  is_inited_file_empty = false;
+  is_inited_file_source_context = false;
+  is_inited_file_struct = false;
+  is_inited_file_timestamp = false;
+  is_inited_file_type = false;
+  is_inited_file_wrappers = false;
+
+  return 0;
+}
+
+static PHP_RSHUTDOWN_FUNCTION(protobuf) {
+  zend_hash_destroy(upb_def_to_php_obj_map);
+  FREE_HASHTABLE(upb_def_to_php_obj_map);
+
+  zend_hash_destroy(ce_to_php_obj_map);
+  FREE_HASHTABLE(ce_to_php_obj_map);
+
+  zend_hash_destroy(proto_to_php_obj_map);
+  FREE_HASHTABLE(proto_to_php_obj_map);
+
+  zend_hash_destroy(reserved_names);
+  FREE_HASHTABLE(reserved_names);
+
+#if PHP_MAJOR_VERSION < 7
+  if (generated_pool_php != NULL) {
+    zval_dtor(generated_pool_php);
+    FREE_ZVAL(generated_pool_php);
+  }
+  if (internal_generated_pool_php != NULL) {
+    zval_dtor(internal_generated_pool_php);
+    FREE_ZVAL(internal_generated_pool_php);
+  }
+#else
+  if (generated_pool_php != NULL) {
+    zval tmp;
+    ZVAL_OBJ(&tmp, generated_pool_php);
+    zval_dtor(&tmp);
+  }
+  if (internal_generated_pool_php != NULL) {
+    zval tmp;
+    ZVAL_OBJ(&tmp, internal_generated_pool_php);
+    zval_dtor(&tmp);
+  }
+#endif
+
+  is_inited_file_any = true;
+  is_inited_file_api = true;
+  is_inited_file_duration = true;
+  is_inited_file_field_mask = true;
+  is_inited_file_empty = true;
+  is_inited_file_source_context = true;
+  is_inited_file_struct = true;
+  is_inited_file_timestamp = true;
+  is_inited_file_type = true;
+  is_inited_file_wrappers = true;
+
+  return 0;
+}
+
+static PHP_MINIT_FUNCTION(protobuf) {
+  descriptor_pool_init(TSRMLS_C);
+  descriptor_init(TSRMLS_C);
+  enum_descriptor_init(TSRMLS_C);
+  enum_value_descriptor_init(TSRMLS_C);
+  field_descriptor_init(TSRMLS_C);
+  gpb_type_init(TSRMLS_C);
+  internal_descriptor_pool_init(TSRMLS_C);
+  map_field_init(TSRMLS_C);
+  map_field_iter_init(TSRMLS_C);
+  message_init(TSRMLS_C);
+  oneof_descriptor_init(TSRMLS_C);
+  repeated_field_init(TSRMLS_C);
+  repeated_field_iter_init(TSRMLS_C);
+  util_init(TSRMLS_C);
+
+  gpb_metadata_any_init(TSRMLS_C);
+  gpb_metadata_api_init(TSRMLS_C);
+  gpb_metadata_duration_init(TSRMLS_C);
+  gpb_metadata_field_mask_init(TSRMLS_C);
+  gpb_metadata_empty_init(TSRMLS_C);
+  gpb_metadata_source_context_init(TSRMLS_C);
+  gpb_metadata_struct_init(TSRMLS_C);
+  gpb_metadata_timestamp_init(TSRMLS_C);
+  gpb_metadata_type_init(TSRMLS_C);
+  gpb_metadata_wrappers_init(TSRMLS_C);
+
+  any_init(TSRMLS_C);
+  api_init(TSRMLS_C);
+  bool_value_init(TSRMLS_C);
+  bytes_value_init(TSRMLS_C);
+  double_value_init(TSRMLS_C);
+  duration_init(TSRMLS_C);
+  enum_init(TSRMLS_C);
+  enum_value_init(TSRMLS_C);
+  field_cardinality_init(TSRMLS_C);
+  field_init(TSRMLS_C);
+  field_kind_init(TSRMLS_C);
+  field_mask_init(TSRMLS_C);
+  float_value_init(TSRMLS_C);
+  empty_init(TSRMLS_C);
+  int32_value_init(TSRMLS_C);
+  int64_value_init(TSRMLS_C);
+  list_value_init(TSRMLS_C);
+  method_init(TSRMLS_C);
+  mixin_init(TSRMLS_C);
+  null_value_init(TSRMLS_C);
+  option_init(TSRMLS_C);
+  source_context_init(TSRMLS_C);
+  string_value_init(TSRMLS_C);
+  struct_init(TSRMLS_C);
+  syntax_init(TSRMLS_C);
+  timestamp_init(TSRMLS_C);
+  type_init(TSRMLS_C);
+  u_int32_value_init(TSRMLS_C);
+  u_int64_value_init(TSRMLS_C);
+  value_init(TSRMLS_C);
+
+  return 0;
+}
+
+static PHP_MSHUTDOWN_FUNCTION(protobuf) {
+  PEFREE(message_handlers);
+  PEFREE(repeated_field_handlers);
+  PEFREE(repeated_field_iter_handlers);
+  PEFREE(map_field_handlers);
+  PEFREE(map_field_iter_handlers);
+
+  return 0;
+}
diff --git a/php/ext/google/protobuf/protobuf.h b/php/ext/google/protobuf/protobuf.h
new file mode 100644
index 0000000..48072a4
--- /dev/null
+++ b/php/ext/google/protobuf/protobuf.h
@@ -0,0 +1,1471 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// 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 __GOOGLE_PROTOBUF_PHP_PROTOBUF_H__
+#define __GOOGLE_PROTOBUF_PHP_PROTOBUF_H__
+
+#include <php.h>
+
+// ubp.h has to be placed after php.h. Othwise, php.h will introduce NDEBUG.
+#include "upb.h"
+
+#define PHP_PROTOBUF_EXTNAME "protobuf"
+#define PHP_PROTOBUF_VERSION "3.6.1"
+
+#define MAX_LENGTH_OF_INT64 20
+#define SIZEOF_INT64 8
+
+// -----------------------------------------------------------------------------
+// PHP7 Wrappers
+// ----------------------------------------------------------------------------
+
+#if PHP_VERSION_ID < 70300
+#define GC_ADDREF(h) ++GC_REFCOUNT(h)
+#define GC_DELREF(h) --GC_REFCOUNT(h)
+#endif
+
+#if PHP_MAJOR_VERSION < 7
+
+#define php_proto_zend_literal const zend_literal*
+#define PHP_PROTO_CASE_IS_BOOL IS_BOOL
+#define PHP_PROTO_SIZE int
+#define PHP_PROTO_LONG long
+#define PHP_PROTO_TSRMLS_DC TSRMLS_DC
+#define PHP_PROTO_TSRMLS_CC TSRMLS_CC
+
+// PHP String
+
+#define PHP_PROTO_ZVAL_STRING(zval_ptr, s, copy) \
+  ZVAL_STRING(zval_ptr, s, copy)
+#define PHP_PROTO_ZVAL_STRINGL(zval_ptr, s, len, copy) \
+  ZVAL_STRINGL(zval_ptr, s, len, copy)
+#define PHP_PROTO_RETURN_STRING(s, copy) RETURN_STRING(s, copy)
+#define PHP_PROTO_RETURN_STRINGL(s, len, copy) RETURN_STRINGL(s, len, copy)
+#define PHP_PROTO_RETVAL_STRINGL(s, len, copy) RETVAL_STRINGL(s, len, copy)
+#define php_proto_zend_make_printable_zval(from, to) \
+  {                                                  \
+    int use_copy;                                    \
+    zend_make_printable_zval(from, to, &use_copy);   \
+  }
+
+// PHP Array
+
+#define PHP_PROTO_HASH_OF(array) Z_ARRVAL_P(array)
+
+#define php_proto_zend_hash_index_update_zval(ht, h, pData) \
+  zend_hash_index_update(ht, h, &(pData), sizeof(void*), NULL)
+
+#define php_proto_zend_hash_update_zval(ht, key, key_len, value) \
+  zend_hash_update(ht, key, key_len, value, sizeof(void*), NULL)
+
+#define php_proto_zend_hash_update(ht, key, key_len) \
+  zend_hash_update(ht, key, key_len, 0, 0, NULL)
+
+#define php_proto_zend_hash_index_update_mem(ht, h, pData, nDataSize, pDest) \
+  zend_hash_index_update(ht, h, pData, nDataSize, pDest)
+
+#define php_proto_zend_hash_update_mem(ht, key, key_len, pData, nDataSize, \
+                                       pDest)                              \
+  zend_hash_update(ht, key, key_len, pData, nDataSize, pDest)
+
+#define php_proto_zend_hash_index_find_zval(ht, h, pDest) \
+  zend_hash_index_find(ht, h, pDest)
+
+#define php_proto_zend_hash_find(ht, key, key_len, pDest) \
+  zend_hash_find(ht, key, key_len, pDest)
+
+#define php_proto_zend_hash_index_find_mem(ht, h, pDest) \
+  zend_hash_index_find(ht, h, pDest)
+
+#define php_proto_zend_hash_find_zval(ht, key, key_len, pDest) \
+  zend_hash_find(ht, key, key_len, pDest)
+
+#define php_proto_zend_hash_find_mem(ht, key, key_len, pDest) \
+  zend_hash_find(ht, key, key_len, pDest)
+
+#define php_proto_zend_hash_next_index_insert_zval(ht, pData) \
+  zend_hash_next_index_insert(ht, pData, sizeof(void*), NULL)
+
+#define php_proto_zend_hash_next_index_insert_mem(ht, pData, nDataSize, pDest) \
+  zend_hash_next_index_insert(ht, pData, nDataSize, pDest)
+
+#define php_proto_zend_hash_get_current_data_ex(ht, pDest, pos) \
+  zend_hash_get_current_data_ex(ht, pDest, pos)
+
+// PHP Object
+
+#define PHP_PROTO_WRAP_OBJECT_START(name) \
+  struct name {                           \
+    zend_object std;
+#define PHP_PROTO_WRAP_OBJECT_END \
+  };
+
+#define PHP_PROTO_INIT_SUBMSGCLASS_START(CLASSNAME, CAMELNAME, LOWWERNAME)   \
+  void LOWWERNAME##_init(TSRMLS_D) {                                         \
+    zend_class_entry class_type;                                             \
+    const char* class_name = CLASSNAME;                                      \
+    INIT_CLASS_ENTRY_EX(class_type, CLASSNAME, strlen(CLASSNAME),            \
+                        LOWWERNAME##_methods);                               \
+    LOWWERNAME##_type = zend_register_internal_class(&class_type TSRMLS_CC); \
+    LOWWERNAME##_type->create_object = message_create;
+#define PHP_PROTO_INIT_SUBMSGCLASS_END \
+  }
+
+#define PHP_PROTO_INIT_ENUMCLASS_START(CLASSNAME, CAMELNAME, LOWWERNAME)     \
+  void LOWWERNAME##_init(TSRMLS_D) {                                         \
+    zend_class_entry class_type;                                             \
+    const char* class_name = CLASSNAME;                                      \
+    INIT_CLASS_ENTRY_EX(class_type, CLASSNAME, strlen(CLASSNAME),            \
+                        LOWWERNAME##_methods);                               \
+    LOWWERNAME##_type = zend_register_internal_class(&class_type TSRMLS_CC);
+#define PHP_PROTO_INIT_ENUMCLASS_END \
+  }
+
+#define PHP_PROTO_INIT_CLASS_START(CLASSNAME, CAMELNAME, LOWWERNAME)         \
+  void LOWWERNAME##_init(TSRMLS_D) {                                         \
+    zend_class_entry class_type;                                             \
+    const char* class_name = CLASSNAME;                                      \
+    INIT_CLASS_ENTRY_EX(class_type, CLASSNAME, strlen(CLASSNAME),            \
+                        LOWWERNAME##_methods);                               \
+    LOWWERNAME##_type = zend_register_internal_class(&class_type TSRMLS_CC); \
+    LOWWERNAME##_type->create_object = LOWWERNAME##_create;                  \
+    LOWWERNAME##_handlers = PEMALLOC(zend_object_handlers);                  \
+    memcpy(LOWWERNAME##_handlers, zend_get_std_object_handlers(),            \
+           sizeof(zend_object_handlers));
+#define PHP_PROTO_INIT_CLASS_END \
+  }
+
+#define PHP_PROTO_OBJECT_CREATE_START(NAME, LOWWERNAME) \
+  static zend_object_value LOWWERNAME##_create(         \
+      zend_class_entry* ce TSRMLS_DC) {                 \
+    PHP_PROTO_ALLOC_CLASS_OBJECT(NAME, ce);             \
+    zend_object_std_init(&intern->std, ce TSRMLS_CC);   \
+    object_properties_init(&intern->std, ce);
+#define PHP_PROTO_OBJECT_CREATE_END(NAME, LOWWERNAME)                          \
+  PHP_PROTO_FREE_CLASS_OBJECT(NAME, LOWWERNAME##_free, LOWWERNAME##_handlers); \
+  }
+
+#define PHP_PROTO_OBJECT_FREE_START(classname, lowername) \
+  void lowername##_free(void* object TSRMLS_DC) {         \
+    classname* intern = object;
+#define PHP_PROTO_OBJECT_FREE_END                 \
+    zend_object_std_dtor(&intern->std TSRMLS_CC); \
+    efree(intern);                                \
+  }
+
+#define PHP_PROTO_OBJECT_DTOR_START(classname, lowername)
+#define PHP_PROTO_OBJECT_DTOR_END
+
+#define CACHED_VALUE zval*
+#define CACHED_TO_ZVAL_PTR(VALUE) (VALUE)
+#define CACHED_PTR_TO_ZVAL_PTR(VALUE) (*VALUE)
+#define ZVAL_PTR_TO_CACHED_PTR(VALUE) (&VALUE)
+#define ZVAL_PTR_TO_CACHED_VALUE(VALUE) (VALUE)
+#define ZVAL_TO_CACHED_VALUE(VALUE) (&VALUE)
+
+#define CREATE_OBJ_ON_ALLOCATED_ZVAL_PTR(zval_ptr, class_type) \
+  ZVAL_OBJ(zval_ptr, class_type->create_object(class_type TSRMLS_CC));
+
+#define PHP_PROTO_SEPARATE_ZVAL_IF_NOT_REF(value) \
+  SEPARATE_ZVAL_IF_NOT_REF(value)
+
+#define PHP_PROTO_GLOBAL_UNINITIALIZED_ZVAL EG(uninitialized_zval_ptr)
+
+#define OBJ_PROP(OBJECT, OFFSET) &((OBJECT)->properties_table[OFFSET])
+
+#define php_proto_zval_ptr_dtor(zval_ptr) \
+  zval_ptr_dtor(&(zval_ptr))
+
+#define PHP_PROTO_ALLOC_CLASS_OBJECT(class_object, class_type) \
+  class_object* intern;                                        \
+  intern = (class_object*)emalloc(sizeof(class_object));       \
+  memset(intern, 0, sizeof(class_object));
+
+#define PHP_PROTO_FREE_CLASS_OBJECT(class_object, class_object_free, handler) \
+  zend_object_value retval = {0};                                             \
+  retval.handle = zend_objects_store_put(                                     \
+      intern, (zend_objects_store_dtor_t)zend_objects_destroy_object,         \
+      class_object_free, NULL TSRMLS_CC);                                     \
+  retval.handlers = handler;                                                  \
+  return retval;
+
+#define PHP_PROTO_ALLOC_ARRAY(zval_ptr)  \
+  ALLOC_HASHTABLE(Z_ARRVAL_P(zval_ptr)); \
+  Z_TYPE_P(zval_ptr) = IS_ARRAY;
+
+#define ZVAL_OBJ(zval_ptr, call_create) \
+  Z_TYPE_P(zval_ptr) = IS_OBJECT;       \
+  Z_OBJVAL_P(zval_ptr) = call_create;
+
+#define UNBOX(class_name, val) \
+  (class_name*)zend_object_store_get_object(val TSRMLS_CC);
+
+#define UNBOX_HASHTABLE_VALUE(class_name, val) UNBOX(class_name, val)
+
+#define HASHTABLE_VALUE_DTOR ZVAL_PTR_DTOR
+
+#define PHP_PROTO_HASHTABLE_VALUE zval*
+#define HASHTABLE_VALUE_CE(val) Z_OBJCE_P(val)
+
+#define CREATE_HASHTABLE_VALUE(OBJ, WRAPPED_OBJ, OBJ_TYPE, OBJ_CLASS_ENTRY) \
+  OBJ_TYPE* OBJ;                                                            \
+  PHP_PROTO_HASHTABLE_VALUE WRAPPED_OBJ;                                    \
+  MAKE_STD_ZVAL(WRAPPED_OBJ);                                               \
+  ZVAL_OBJ(WRAPPED_OBJ,                                                     \
+           OBJ_CLASS_ENTRY->create_object(OBJ_CLASS_ENTRY TSRMLS_CC));      \
+  OBJ = UNBOX_HASHTABLE_VALUE(OBJ_TYPE, WRAPPED_OBJ);                       \
+  Z_DELREF_P(desc_php);
+
+#define PHP_PROTO_CE_DECLARE zend_class_entry**
+#define PHP_PROTO_CE_UNREF(ce) (*ce)
+
+#define php_proto_zend_lookup_class(name, name_length, ce) \
+  zend_lookup_class(name, name_length, ce TSRMLS_CC)
+
+#define PHP_PROTO_RETVAL_ZVAL(value) ZVAL_ZVAL(return_value, value, 1, 0)
+
+#else  // PHP_MAJOR_VERSION >= 7
+
+#define php_proto_zend_literal void**
+#define PHP_PROTO_CASE_IS_BOOL IS_TRUE: case IS_FALSE
+#define PHP_PROTO_SIZE size_t
+#define PHP_PROTO_LONG zend_long
+#define PHP_PROTO_TSRMLS_DC
+#define PHP_PROTO_TSRMLS_CC
+
+// PHP String
+
+#define PHP_PROTO_ZVAL_STRING(zval_ptr, s, copy) \
+  ZVAL_STRING(zval_ptr, s)
+#define PHP_PROTO_ZVAL_STRINGL(zval_ptr, s, len, copy) \
+  ZVAL_STRINGL(zval_ptr, s, len)
+#define PHP_PROTO_RETURN_STRING(s, copy) RETURN_STRING(s)
+#define PHP_PROTO_RETURN_STRINGL(s, len, copy) RETURN_STRINGL(s, len)
+#define PHP_PROTO_RETVAL_STRINGL(s, len, copy) RETVAL_STRINGL(s, len)
+#define php_proto_zend_make_printable_zval(from, to) \
+  zend_make_printable_zval(from, to)
+
+// PHP Array
+
+#define PHP_PROTO_HASH_OF(array) Z_ARRVAL_P(&array)
+
+static inline int php_proto_zend_hash_index_update_zval(HashTable* ht, ulong h,
+                                                        zval* pData) {
+  void* result = NULL;
+  result = zend_hash_index_update(ht, h, pData);
+  return result != NULL ? SUCCESS : FAILURE;
+}
+
+static inline int php_proto_zend_hash_update(HashTable* ht, const char* key,
+                                             size_t key_len) {
+  void* result = NULL;
+  zval temp;
+  ZVAL_LONG(&temp, 0);
+  result = zend_hash_str_update(ht, key, key_len, &temp);
+  return result != NULL ? SUCCESS : FAILURE;
+}
+
+static inline int php_proto_zend_hash_index_update_mem(HashTable* ht, ulong h,
+                                                   void* pData, uint nDataSize,
+                                                   void** pDest) {
+  void* result = NULL;
+  result = zend_hash_index_update_mem(ht, h, pData, nDataSize);
+  if (pDest != NULL) *pDest = result;
+  return result != NULL ? SUCCESS : FAILURE;
+}
+
+static inline int php_proto_zend_hash_update_zval(HashTable* ht,
+                                                  const char* key, uint key_len,
+                                                  zval* pData) {
+  zend_string* internal_key = zend_string_init(key, key_len, 0);
+  zend_hash_update(ht, internal_key, pData);
+}
+
+static inline int php_proto_zend_hash_update_mem(HashTable* ht, const char* key,
+                                                 uint key_len, void* pData,
+                                                 uint nDataSize, void** pDest) {
+  zend_string* internal_key = zend_string_init(key, key_len, 0);
+  void* result = zend_hash_update_mem(ht, internal_key, pData, nDataSize);
+  zend_string_release(internal_key);
+  if (pDest != NULL) *pDest = result;
+  return result != NULL ? SUCCESS : FAILURE;
+}
+
+static inline int php_proto_zend_hash_index_find_zval(const HashTable* ht,
+                                                      ulong h, void** pDest) {
+  zval* result = zend_hash_index_find(ht, h);
+  if (pDest != NULL) *pDest = result;
+  return result != NULL ? SUCCESS : FAILURE;
+}
+
+static inline int php_proto_zend_hash_find(const HashTable* ht, const char* key,
+                                           size_t key_len, void** pDest) {
+  void* result = NULL;
+  result = zend_hash_str_find(ht, key, key_len);
+  return result != NULL ? SUCCESS : FAILURE;
+}
+
+static inline int php_proto_zend_hash_index_find_mem(const HashTable* ht,
+                                                     ulong h, void** pDest) {
+  void* result = NULL;
+  result = zend_hash_index_find_ptr(ht, h);
+  if (pDest != NULL) *pDest = result;
+  return result != NULL ? SUCCESS : FAILURE;
+}
+
+static inline int php_proto_zend_hash_find_zval(const HashTable* ht,
+                                                const char* key, uint key_len,
+                                                void** pDest) {
+  zend_string* internal_key = zend_string_init(key, key_len, 1);
+  zval* result = zend_hash_find(ht, internal_key);
+  if (pDest != NULL) *pDest = result;
+  return result != NULL ? SUCCESS : FAILURE;
+}
+
+static inline int php_proto_zend_hash_find_mem(const HashTable* ht,
+                                                const char* key, uint key_len,
+                                                void** pDest) {
+  zend_string* internal_key = zend_string_init(key, key_len, 1);
+  void* result = zend_hash_find_ptr(ht, internal_key);
+  zend_string_release(internal_key);
+  if (pDest != NULL) *pDest = result;
+  return result != NULL ? SUCCESS : FAILURE;
+}
+
+static inline int php_proto_zend_hash_next_index_insert_zval(HashTable* ht,
+                                                             void* pData) {
+  zval tmp;
+  ZVAL_OBJ(&tmp, *(zend_object**)pData);
+  zval* result = zend_hash_next_index_insert(ht, &tmp);
+  return result != NULL ? SUCCESS : FAILURE;
+}
+
+static inline int php_proto_zend_hash_next_index_insert_mem(HashTable* ht,
+                                                            void* pData,
+                                                            uint nDataSize,
+                                                            void** pDest) {
+  void* result = NULL;
+  result = zend_hash_next_index_insert_mem(ht, pData, nDataSize);
+  if (pDest != NULL) *pDest = result;
+  return result != NULL ? SUCCESS : FAILURE;
+}
+
+static inline int php_proto_zend_hash_get_current_data_ex(HashTable* ht,
+                                                          void** pDest,
+                                                          HashPosition* pos) {
+  void* result = NULL;
+  result = zend_hash_get_current_data_ex(ht, pos);
+  if (pDest != NULL) *pDest = result;
+  return result != NULL ? SUCCESS : FAILURE;
+}
+
+// PHP Object
+
+#define PHP_PROTO_WRAP_OBJECT_START(name) struct name {
+#define PHP_PROTO_WRAP_OBJECT_END \
+  zend_object std;                \
+  };
+
+#define PHP_PROTO_INIT_SUBMSGCLASS_START(CLASSNAME, CAMELNAME, LOWWERNAME)   \
+  void LOWWERNAME##_init(TSRMLS_D) {                                         \
+    zend_class_entry class_type;                                             \
+    const char* class_name = CLASSNAME;                                      \
+    INIT_CLASS_ENTRY_EX(class_type, CLASSNAME, strlen(CLASSNAME),            \
+                        LOWWERNAME##_methods);                               \
+    LOWWERNAME##_type = zend_register_internal_class(&class_type TSRMLS_CC); \
+    LOWWERNAME##_type->create_object = message_create;
+#define PHP_PROTO_INIT_SUBMSGCLASS_END \
+  }
+
+#define PHP_PROTO_INIT_ENUMCLASS_START(CLASSNAME, CAMELNAME, LOWWERNAME)     \
+  void LOWWERNAME##_init(TSRMLS_D) {                                         \
+    zend_class_entry class_type;                                             \
+    const char* class_name = CLASSNAME;                                      \
+    INIT_CLASS_ENTRY_EX(class_type, CLASSNAME, strlen(CLASSNAME),            \
+                        LOWWERNAME##_methods);                               \
+    LOWWERNAME##_type = zend_register_internal_class(&class_type TSRMLS_CC);
+#define PHP_PROTO_INIT_ENUMCLASS_END \
+  }
+
+#define PHP_PROTO_INIT_CLASS_START(CLASSNAME, CAMELNAME, LOWWERNAME)         \
+  void LOWWERNAME##_init(TSRMLS_D) {                                         \
+    zend_class_entry class_type;                                             \
+    const char* class_name = CLASSNAME;                                      \
+    INIT_CLASS_ENTRY_EX(class_type, CLASSNAME, strlen(CLASSNAME),            \
+                        LOWWERNAME##_methods);                               \
+    LOWWERNAME##_type = zend_register_internal_class(&class_type TSRMLS_CC); \
+    LOWWERNAME##_type->create_object = LOWWERNAME##_create;                  \
+    LOWWERNAME##_handlers = PEMALLOC(zend_object_handlers);                  \
+    memcpy(LOWWERNAME##_handlers, zend_get_std_object_handlers(),            \
+           sizeof(zend_object_handlers));                                    \
+    LOWWERNAME##_handlers->free_obj = LOWWERNAME##_free;                     \
+    LOWWERNAME##_handlers->dtor_obj = LOWWERNAME##_dtor;                     \
+    LOWWERNAME##_handlers->offset = XtOffsetOf(CAMELNAME, std);
+#define PHP_PROTO_INIT_CLASS_END \
+  }
+
+#define PHP_PROTO_OBJECT_FREE_START(classname, lowername) \
+  void lowername##_free(zend_object* object) {            \
+    classname* intern =                                   \
+        (classname*)((char*)object - XtOffsetOf(classname, std));
+#define PHP_PROTO_OBJECT_FREE_END           \
+  }
+
+#define PHP_PROTO_OBJECT_DTOR_START(classname, lowername) \
+  void lowername##_dtor(zend_object* object) {            \
+    classname* intern =                                   \
+        (classname*)((char*)object - XtOffsetOf(classname, std));
+#define PHP_PROTO_OBJECT_DTOR_END           \
+    zend_object_std_dtor(object TSRMLS_CC); \
+  }
+
+#define PHP_PROTO_OBJECT_CREATE_START(NAME, LOWWERNAME)                     \
+  static zend_object* LOWWERNAME##_create(zend_class_entry* ce TSRMLS_DC) { \
+    PHP_PROTO_ALLOC_CLASS_OBJECT(NAME, ce);                                 \
+    zend_object_std_init(&intern->std, ce TSRMLS_CC);                       \
+    object_properties_init(&intern->std, ce);
+#define PHP_PROTO_OBJECT_CREATE_END(NAME, LOWWERNAME)                          \
+  PHP_PROTO_FREE_CLASS_OBJECT(NAME, LOWWERNAME##_free, LOWWERNAME##_handlers); \
+  }
+
+#define CACHED_VALUE zval
+#define CACHED_TO_ZVAL_PTR(VALUE) (&VALUE)
+#define CACHED_PTR_TO_ZVAL_PTR(VALUE) (VALUE)
+#define ZVAL_PTR_TO_CACHED_PTR(VALUE) (VALUE)
+#define ZVAL_PTR_TO_CACHED_VALUE(VALUE) (*VALUE)
+#define ZVAL_TO_CACHED_VALUE(VALUE) (VALUE)
+
+#define CREATE_OBJ_ON_ALLOCATED_ZVAL_PTR(zval_ptr, class_type) \
+  ZVAL_OBJ(zval_ptr, class_type->create_object(class_type));
+
+#define PHP_PROTO_SEPARATE_ZVAL_IF_NOT_REF(value) ;
+
+#define PHP_PROTO_GLOBAL_UNINITIALIZED_ZVAL &EG(uninitialized_zval)
+
+#define php_proto_zval_ptr_dtor(zval_ptr) \
+  zval_ptr_dtor(zval_ptr)
+
+#define PHP_PROTO_ALLOC_CLASS_OBJECT(class_object, class_type)               \
+  class_object* intern;                                                      \
+  int size = sizeof(class_object) + zend_object_properties_size(class_type); \
+  intern = ecalloc(1, size);                                                 \
+  memset(intern, 0, size);
+
+#define PHP_PROTO_FREE_CLASS_OBJECT(class_object, class_object_free, handler) \
+  intern->std.handlers = handler;                                             \
+  return &intern->std;
+
+#define PHP_PROTO_ALLOC_ARRAY(zval_ptr) \
+  ZVAL_NEW_ARR(zval_ptr)
+
+#define UNBOX(class_name, val) \
+  (class_name*)((char*)Z_OBJ_P(val) - XtOffsetOf(class_name, std));
+
+#define UNBOX_HASHTABLE_VALUE(class_name, val) \
+  (class_name*)((char*)val - XtOffsetOf(class_name, std))
+
+#define HASHTABLE_VALUE_DTOR php_proto_hashtable_descriptor_release
+
+#define PHP_PROTO_HASHTABLE_VALUE zend_object*
+#define HASHTABLE_VALUE_CE(val) val->ce
+
+#define CREATE_HASHTABLE_VALUE(OBJ, WRAPPED_OBJ, OBJ_TYPE, OBJ_CLASS_ENTRY) \
+  OBJ_TYPE* OBJ;                                                            \
+  PHP_PROTO_HASHTABLE_VALUE WRAPPED_OBJ;                                    \
+  WRAPPED_OBJ = OBJ_CLASS_ENTRY->create_object(OBJ_CLASS_ENTRY);            \
+  OBJ = UNBOX_HASHTABLE_VALUE(OBJ_TYPE, WRAPPED_OBJ);                       \
+  GC_DELREF(WRAPPED_OBJ);
+
+#define PHP_PROTO_CE_DECLARE zend_class_entry*
+#define PHP_PROTO_CE_UNREF(ce) (ce)
+
+static inline int php_proto_zend_lookup_class(
+    const char* name, int name_length, zend_class_entry** ce TSRMLS_DC) {
+  zend_string *zstr_name = zend_string_init(name, name_length, 0);
+  *ce = zend_lookup_class(zstr_name);
+  zend_string_release(zstr_name);
+  return *ce != NULL ? SUCCESS : FAILURE;
+}
+
+#define PHP_PROTO_RETVAL_ZVAL(value) ZVAL_COPY(return_value, value)
+
+#endif  // PHP_MAJOR_VERSION >= 7
+
+#if PHP_MAJOR_VERSION < 7 || (PHP_MAJOR_VERSION == 7 && PHP_MINOR_VERSION == 0)
+#define PHP_PROTO_FAKE_SCOPE_BEGIN(klass)  \
+  zend_class_entry* old_scope = EG(scope); \
+  EG(scope) = klass;
+#define PHP_PROTO_FAKE_SCOPE_RESTART(klass) \
+  old_scope = EG(scope);                    \
+  EG(scope) = klass;
+#define PHP_PROTO_FAKE_SCOPE_END EG(scope) = old_scope;
+#else
+#define PHP_PROTO_FAKE_SCOPE_BEGIN(klass)       \
+  zend_class_entry* old_scope = EG(fake_scope); \
+  EG(fake_scope) = klass;
+#define PHP_PROTO_FAKE_SCOPE_RESTART(klass) \
+  old_scope = EG(fake_scope);               \
+  EG(fake_scope) = klass;
+#define PHP_PROTO_FAKE_SCOPE_END EG(fake_scope) = old_scope;
+#endif
+
+// Define PHP class
+#define DEFINE_PROTOBUF_INIT_CLASS(CLASSNAME, CAMELNAME, LOWERNAME) \
+  PHP_PROTO_INIT_CLASS_START(CLASSNAME, CAMELNAME, LOWERNAME)       \
+  PHP_PROTO_INIT_CLASS_END
+
+#define DEFINE_PROTOBUF_CREATE(NAME, LOWERNAME)  \
+  PHP_PROTO_OBJECT_CREATE_START(NAME, LOWERNAME) \
+  LOWERNAME##_init_c_instance(intern TSRMLS_CC); \
+  PHP_PROTO_OBJECT_CREATE_END(NAME, LOWERNAME)
+
+#define DEFINE_PROTOBUF_FREE(CAMELNAME, LOWERNAME)  \
+  PHP_PROTO_OBJECT_FREE_START(CAMELNAME, LOWERNAME) \
+  LOWERNAME##_free_c(intern TSRMLS_CC);             \
+  PHP_PROTO_OBJECT_FREE_END
+
+#define DEFINE_PROTOBUF_DTOR(CAMELNAME, LOWERNAME)  \
+  PHP_PROTO_OBJECT_DTOR_START(CAMELNAME, LOWERNAME) \
+  PHP_PROTO_OBJECT_DTOR_END
+
+#define DEFINE_CLASS(NAME, LOWERNAME, string_name) \
+  zend_class_entry *LOWERNAME##_type;              \
+  zend_object_handlers *LOWERNAME##_handlers;      \
+  DEFINE_PROTOBUF_FREE(NAME, LOWERNAME)            \
+  DEFINE_PROTOBUF_DTOR(NAME, LOWERNAME)            \
+  DEFINE_PROTOBUF_CREATE(NAME, LOWERNAME)          \
+  DEFINE_PROTOBUF_INIT_CLASS(string_name, NAME, LOWERNAME)
+
+// -----------------------------------------------------------------------------
+// Forward Declaration
+// ----------------------------------------------------------------------------
+
+struct Any;
+struct Api;
+struct BoolValue;
+struct BytesValue;
+struct Descriptor;
+struct DescriptorPool;
+struct DoubleValue;
+struct Duration;
+struct Enum;
+struct EnumDescriptor;
+struct EnumValue;
+struct EnumValueDescriptor;
+struct Field;
+struct FieldDescriptor;
+struct FieldMask;
+struct Field_Cardinality;
+struct Field_Kind;
+struct FloatValue;
+struct GPBEmpty;
+struct Int32Value;
+struct Int64Value;
+struct InternalDescriptorPool;
+struct ListValue;
+struct Map;
+struct MapIter;
+struct MessageField;
+struct MessageHeader;
+struct MessageLayout;
+struct Method;
+struct Mixin;
+struct NullValue;
+struct Oneof;
+struct Option;
+struct RepeatedField;
+struct RepeatedFieldIter;
+struct SourceContext;
+struct StringValue;
+struct Struct;
+struct Syntax;
+struct Timestamp;
+struct Type;
+struct UInt32Value;
+struct UInt64Value;
+struct Value;
+
+typedef struct Any Any;
+typedef struct Api Api;
+typedef struct BoolValue BoolValue;
+typedef struct BytesValue BytesValue;
+typedef struct Descriptor Descriptor;
+typedef struct DescriptorPool DescriptorPool;
+typedef struct DoubleValue DoubleValue;
+typedef struct Duration Duration;
+typedef struct EnumDescriptor EnumDescriptor;
+typedef struct Enum Enum;
+typedef struct EnumValueDescriptor EnumValueDescriptor;
+typedef struct EnumValue EnumValue;
+typedef struct Field_Cardinality Field_Cardinality;
+typedef struct FieldDescriptor FieldDescriptor;
+typedef struct Field Field;
+typedef struct Field_Kind Field_Kind;
+typedef struct FieldMask FieldMask;
+typedef struct FloatValue FloatValue;
+typedef struct GPBEmpty GPBEmpty;
+typedef struct Int32Value Int32Value;
+typedef struct Int64Value Int64Value;
+typedef struct InternalDescriptorPool InternalDescriptorPool;
+typedef struct ListValue ListValue;
+typedef struct MapIter MapIter;
+typedef struct Map Map;
+typedef struct MessageField MessageField;
+typedef struct MessageHeader MessageHeader;
+typedef struct MessageLayout MessageLayout;
+typedef struct Method Method;
+typedef struct Mixin Mixin;
+typedef struct NullValue NullValue;
+typedef struct Oneof Oneof;
+typedef struct Option Option;
+typedef struct RepeatedFieldIter RepeatedFieldIter;
+typedef struct RepeatedField RepeatedField;
+typedef struct SourceContext SourceContext;
+typedef struct StringValue StringValue;
+typedef struct Struct Struct;
+typedef struct Syntax Syntax;
+typedef struct Timestamp Timestamp;
+typedef struct Type Type;
+typedef struct UInt32Value UInt32Value;
+typedef struct UInt64Value UInt64Value;
+typedef struct Value Value;
+
+// -----------------------------------------------------------------------------
+// Globals.
+// -----------------------------------------------------------------------------
+
+ZEND_BEGIN_MODULE_GLOBALS(protobuf)
+ZEND_END_MODULE_GLOBALS(protobuf)
+
+// Init module and PHP classes.
+void any_init(TSRMLS_D);
+void api_init(TSRMLS_D);
+void bool_value_init(TSRMLS_D);
+void bytes_value_init(TSRMLS_D);
+void descriptor_init(TSRMLS_D);
+void descriptor_pool_init(TSRMLS_D);
+void double_value_init(TSRMLS_D);
+void duration_init(TSRMLS_D);
+void empty_init(TSRMLS_D);
+void enum_descriptor_init(TSRMLS_D);
+void enum_init(TSRMLS_D);
+void enum_value_init(TSRMLS_D);
+void field_cardinality_init(TSRMLS_D);
+void field_descriptor_init(TSRMLS_D);
+void field_init(TSRMLS_D);
+void field_kind_init(TSRMLS_D);
+void field_mask_init(TSRMLS_D);
+void float_value_init(TSRMLS_D);
+void gpb_type_init(TSRMLS_D);
+void int32_value_init(TSRMLS_D);
+void int64_value_init(TSRMLS_D);
+void internal_descriptor_pool_init(TSRMLS_D);
+void list_value_init(TSRMLS_D);
+void map_field_init(TSRMLS_D);
+void map_field_iter_init(TSRMLS_D);
+void message_init(TSRMLS_D);
+void method_init(TSRMLS_D);
+void mixin_init(TSRMLS_D);
+void null_value_init(TSRMLS_D);
+void oneof_descriptor_init(TSRMLS_D);
+void option_init(TSRMLS_D);
+void repeated_field_init(TSRMLS_D);
+void repeated_field_iter_init(TSRMLS_D);
+void source_context_init(TSRMLS_D);
+void string_value_init(TSRMLS_D);
+void struct_init(TSRMLS_D);
+void syntax_init(TSRMLS_D);
+void timestamp_init(TSRMLS_D);
+void type_init(TSRMLS_D);
+void uint32_value_init(TSRMLS_D);
+void uint64_value_init(TSRMLS_D);
+void util_init(TSRMLS_D);
+void value_init(TSRMLS_D);
+
+void gpb_metadata_any_init(TSRMLS_D);
+void gpb_metadata_api_init(TSRMLS_D);
+void gpb_metadata_duration_init(TSRMLS_D);
+void gpb_metadata_field_mask_init(TSRMLS_D);
+void gpb_metadata_empty_init(TSRMLS_D);
+void gpb_metadata_source_context_init(TSRMLS_D);
+void gpb_metadata_struct_init(TSRMLS_D);
+void gpb_metadata_timestamp_init(TSRMLS_D);
+void gpb_metadata_type_init(TSRMLS_D);
+void gpb_metadata_wrappers_init(TSRMLS_D);
+
+// Global map from upb {msg,enum}defs to wrapper Descriptor/EnumDescriptor
+// instances.
+void add_def_obj(const void* def, PHP_PROTO_HASHTABLE_VALUE value);
+PHP_PROTO_HASHTABLE_VALUE get_def_obj(const void* def);
+
+// Global map from PHP class entries to wrapper Descriptor/EnumDescriptor
+// instances.
+void add_ce_obj(const void* ce, PHP_PROTO_HASHTABLE_VALUE value);
+PHP_PROTO_HASHTABLE_VALUE get_ce_obj(const void* ce);
+bool class_added(const void* ce);
+
+// Global map from message/enum's proto fully-qualified name to corresponding
+// wrapper Descriptor/EnumDescriptor instances.
+void add_proto_obj(const char* proto, PHP_PROTO_HASHTABLE_VALUE value);
+PHP_PROTO_HASHTABLE_VALUE get_proto_obj(const char* proto);
+
+extern zend_class_entry* map_field_type;
+extern zend_class_entry* repeated_field_type;
+
+// -----------------------------------------------------------------------------
+// Descriptor.
+// -----------------------------------------------------------------------------
+
+PHP_PROTO_WRAP_OBJECT_START(DescriptorPool)
+  InternalDescriptorPool* intern;
+PHP_PROTO_WRAP_OBJECT_END
+
+PHP_METHOD(DescriptorPool, getGeneratedPool);
+PHP_METHOD(DescriptorPool, getDescriptorByClassName);
+PHP_METHOD(DescriptorPool, getEnumDescriptorByClassName);
+
+PHP_PROTO_WRAP_OBJECT_START(InternalDescriptorPool)
+  upb_symtab* symtab;
+  HashTable* pending_list;
+PHP_PROTO_WRAP_OBJECT_END
+
+PHP_METHOD(InternalDescriptorPool, getGeneratedPool);
+PHP_METHOD(InternalDescriptorPool, internalAddGeneratedFile);
+
+void internal_add_generated_file(const char* data, PHP_PROTO_SIZE data_len,
+                                 InternalDescriptorPool* pool TSRMLS_DC);
+void init_generated_pool_once(TSRMLS_D);
+
+// wrapper of generated pool
+#if PHP_MAJOR_VERSION < 7
+extern zval* generated_pool_php;
+extern zval* internal_generated_pool_php;
+void descriptor_pool_free(void* object TSRMLS_DC);
+void internal_descriptor_pool_free(void* object TSRMLS_DC);
+#else
+extern zend_object *generated_pool_php;
+extern zend_object *internal_generated_pool_php;
+void descriptor_pool_free(zend_object* object);
+void internal_descriptor_pool_free(zend_object* object);
+#endif
+extern InternalDescriptorPool* generated_pool;  // The actual generated pool
+
+PHP_PROTO_WRAP_OBJECT_START(Descriptor)
+  const upb_msgdef* msgdef;
+  MessageLayout* layout;
+  zend_class_entry* klass;  // begins as NULL
+  const upb_handlers* fill_handlers;
+  const upb_pbdecodermethod* fill_method;
+  const upb_json_parsermethod* json_fill_method;
+  const upb_handlers* pb_serialize_handlers;
+  const upb_handlers* json_serialize_handlers;
+  const upb_handlers* json_serialize_handlers_preserve;
+PHP_PROTO_WRAP_OBJECT_END
+
+PHP_METHOD(Descriptor, getClass);
+PHP_METHOD(Descriptor, getFullName);
+PHP_METHOD(Descriptor, getField);
+PHP_METHOD(Descriptor, getFieldCount);
+PHP_METHOD(Descriptor, getOneofDecl);
+PHP_METHOD(Descriptor, getOneofDeclCount);
+
+extern zend_class_entry* descriptor_type;
+
+void descriptor_name_set(Descriptor *desc, const char *name);
+
+PHP_PROTO_WRAP_OBJECT_START(FieldDescriptor)
+  const upb_fielddef* fielddef;
+PHP_PROTO_WRAP_OBJECT_END
+
+PHP_METHOD(FieldDescriptor, getName);
+PHP_METHOD(FieldDescriptor, getNumber);
+PHP_METHOD(FieldDescriptor, getLabel);
+PHP_METHOD(FieldDescriptor, getType);
+PHP_METHOD(FieldDescriptor, isMap);
+PHP_METHOD(FieldDescriptor, getEnumType);
+PHP_METHOD(FieldDescriptor, getMessageType);
+
+extern zend_class_entry* field_descriptor_type;
+
+PHP_PROTO_WRAP_OBJECT_START(EnumDescriptor)
+  const upb_enumdef* enumdef;
+  zend_class_entry* klass;  // begins as NULL
+PHP_PROTO_WRAP_OBJECT_END
+
+PHP_METHOD(EnumDescriptor, getValue);
+PHP_METHOD(EnumDescriptor, getValueCount);
+
+extern zend_class_entry* enum_descriptor_type;
+
+PHP_PROTO_WRAP_OBJECT_START(EnumValueDescriptor)
+  const char* name;
+  int32_t number;
+PHP_PROTO_WRAP_OBJECT_END
+
+PHP_METHOD(EnumValueDescriptor, getName);
+PHP_METHOD(EnumValueDescriptor, getNumber);
+
+extern zend_class_entry* enum_value_descriptor_type;
+
+// -----------------------------------------------------------------------------
+// Message class creation.
+// -----------------------------------------------------------------------------
+
+void* message_data(MessageHeader* msg);
+void custom_data_init(const zend_class_entry* ce,
+                      MessageHeader* msg PHP_PROTO_TSRMLS_DC);
+
+// Build PHP class for given descriptor. Instead of building from scratch, this
+// function modifies existing class which has been partially defined in PHP
+// code.
+void build_class_from_descriptor(
+    PHP_PROTO_HASHTABLE_VALUE php_descriptor TSRMLS_DC);
+
+extern zend_class_entry* message_type;
+extern zend_object_handlers* message_handlers;
+
+// -----------------------------------------------------------------------------
+// Message layout / storage.
+// -----------------------------------------------------------------------------
+
+/*
+ * In c extension, each protobuf message is a zval instance. The zval instance
+ * is like union, which can be used to store int, string, zend_object_value and
+ * etc. For protobuf message, the zval instance is used to store the
+ * zend_object_value.
+ *
+ * The zend_object_value is composed of handlers and a handle to look up the
+ * actual stored data. The handlers are pointers to functions, e.g., read,
+ * write, and etc, to access properties.
+ *
+ * The actual data of protobuf messages is stored as MessageHeader in zend
+ * engine's central repository. Each MessageHeader instance is composed of a
+ * zend_object, a Descriptor instance and the real message data.
+ *
+ * For the reason that PHP's native types may not be large enough to store
+ * protobuf message's field (e.g., int64), all message's data is stored in
+ * custom memory layout and is indexed by the Descriptor instance.
+ *
+ * The zend_object contains the zend class entry and the properties table. The
+ * zend class entry contains all information about protobuf message's
+ * corresponding PHP class. The most useful information is the offset table of
+ * properties. Because read access to properties requires returning zval
+ * instance, we need to convert data from the custom layout to zval instance.
+ * Instead of creating zval instance for every read access, we use the zval
+ * instances in the properties table in the zend_object as cache.  When
+ * accessing properties, the offset is needed to find the zval property in
+ * zend_object's properties table. These properties will be updated using the
+ * data from custom memory layout only when reading these properties.
+ *
+ * zval
+ * |-zend_object_value obj
+ *   |-zend_object_handlers* handlers -> |-read_property_handler
+ *   |                                   |-write_property_handler
+ *   |                              ++++++++++++++++++++++
+ *   |-zend_object_handle handle -> + central repository +
+ *                                  ++++++++++++++++++++++
+ *  MessageHeader <-----------------|
+ *  |-zend_object std
+ *  | |-class_entry* ce -> class_entry
+ *  | |                    |-HashTable properties_table (name->offset)
+ *  | |-zval** properties_table <------------------------------|
+ *  |                         |------> zval* property(cache)
+ *  |-Descriptor* desc (name->offset)
+ *  |-void** data <-----------|
+ *           |-----------------------> void* property(data)
+ *
+ */
+
+#define MESSAGE_FIELD_NO_CASE ((size_t)-1)
+
+struct MessageField {
+  size_t offset;
+  int cache_index;  // Each field except oneof field has a zval cache to avoid
+                    // multiple creation when being accessed.
+  size_t case_offset;   // for oneofs, a uint32. Else, MESSAGE_FIELD_NO_CASE.
+};
+
+struct MessageLayout {
+  const upb_msgdef* msgdef;
+  MessageField* fields;
+  size_t size;
+};
+
+PHP_PROTO_WRAP_OBJECT_START(MessageHeader)
+  void* data;  // Point to the real message data.
+               // Place needs to be consistent with map_parse_frame_data_t.
+  Descriptor* descriptor;  // Kept alive by self.class.descriptor reference.
+PHP_PROTO_WRAP_OBJECT_END
+
+MessageLayout* create_layout(const upb_msgdef* msgdef);
+void layout_init(MessageLayout* layout, void* storage,
+                 zend_object* object PHP_PROTO_TSRMLS_DC);
+zval* layout_get(MessageLayout* layout, const void* storage,
+                 const upb_fielddef* field, CACHED_VALUE* cache TSRMLS_DC);
+void layout_set(MessageLayout* layout, MessageHeader* header,
+                const upb_fielddef* field, zval* val TSRMLS_DC);
+void layout_merge(MessageLayout* layout, MessageHeader* from,
+                  MessageHeader* to TSRMLS_DC);
+const char* layout_get_oneof_case(MessageLayout* layout, const void* storage,
+                                  const upb_oneofdef* oneof TSRMLS_DC);
+void free_layout(MessageLayout* layout);
+void* slot_memory(MessageLayout* layout, const void* storage,
+                  const upb_fielddef* field);
+
+PHP_METHOD(Message, clear);
+PHP_METHOD(Message, mergeFrom);
+PHP_METHOD(Message, readOneof);
+PHP_METHOD(Message, writeOneof);
+PHP_METHOD(Message, whichOneof);
+PHP_METHOD(Message, __construct);
+
+// -----------------------------------------------------------------------------
+// Encode / Decode.
+// -----------------------------------------------------------------------------
+
+// Maximum depth allowed during encoding, to avoid stack overflows due to
+// cycles.
+#define ENCODE_MAX_NESTING 63
+
+// Constructs the upb decoder method for parsing messages of this type.
+// This is called from the message class creation code.
+const upb_pbdecodermethod *new_fillmsg_decodermethod(Descriptor *desc,
+                                                     const void *owner);
+void serialize_to_string(zval* val, zval* return_value TSRMLS_DC);
+void merge_from_string(const char* data, int data_len, const Descriptor* desc,
+                       MessageHeader* msg);
+
+PHP_METHOD(Message, serializeToString);
+PHP_METHOD(Message, mergeFromString);
+PHP_METHOD(Message, serializeToJsonString);
+PHP_METHOD(Message, mergeFromJsonString);
+PHP_METHOD(Message, discardUnknownFields);
+
+// -----------------------------------------------------------------------------
+// Type check / conversion.
+// -----------------------------------------------------------------------------
+
+bool protobuf_convert_to_int32(zval* from, int32_t* to);
+bool protobuf_convert_to_uint32(zval* from, uint32_t* to);
+bool protobuf_convert_to_int64(zval* from, int64_t* to);
+bool protobuf_convert_to_uint64(zval* from, uint64_t* to);
+bool protobuf_convert_to_float(zval* from, float* to);
+bool protobuf_convert_to_double(zval* from, double* to);
+bool protobuf_convert_to_bool(zval* from, int8_t* to);
+bool protobuf_convert_to_string(zval* from);
+
+void check_repeated_field(const zend_class_entry* klass, PHP_PROTO_LONG type,
+                          zval* val, zval* return_value);
+void check_map_field(const zend_class_entry* klass, PHP_PROTO_LONG key_type,
+                     PHP_PROTO_LONG value_type, zval* val, zval* return_value);
+
+PHP_METHOD(Util, checkInt32);
+PHP_METHOD(Util, checkUint32);
+PHP_METHOD(Util, checkInt64);
+PHP_METHOD(Util, checkUint64);
+PHP_METHOD(Util, checkEnum);
+PHP_METHOD(Util, checkFloat);
+PHP_METHOD(Util, checkDouble);
+PHP_METHOD(Util, checkBool);
+PHP_METHOD(Util, checkString);
+PHP_METHOD(Util, checkBytes);
+PHP_METHOD(Util, checkMessage);
+PHP_METHOD(Util, checkMapField);
+PHP_METHOD(Util, checkRepeatedField);
+
+// -----------------------------------------------------------------------------
+// Native slot storage abstraction.
+// -----------------------------------------------------------------------------
+
+#define NATIVE_SLOT_MAX_SIZE sizeof(uint64_t)
+
+size_t native_slot_size(upb_fieldtype_t type);
+bool native_slot_set(upb_fieldtype_t type, const zend_class_entry* klass,
+                     void* memory, zval* value TSRMLS_DC);
+// String/Message is stored differently in array/map from normal message fields.
+// So we need to make a special method to handle that.
+bool native_slot_set_by_array(upb_fieldtype_t type,
+                              const zend_class_entry* klass, void* memory,
+                              zval* value TSRMLS_DC);
+bool native_slot_set_by_map(upb_fieldtype_t type, const zend_class_entry* klass,
+                            void* memory, zval* value TSRMLS_DC);
+void native_slot_init(upb_fieldtype_t type, void* memory, CACHED_VALUE* cache);
+// For each property, in order to avoid conversion between the zval object and
+// the actual data type during parsing/serialization, the containing message
+// object use the custom memory layout to store the actual data type for each
+// property inside of it.  To access a property from php code, the property
+// needs to be converted to a zval object. The message object is not responsible
+// for providing such a zval object. Instead the caller needs to provide one
+// (cache) and update it with the actual data (memory).
+void native_slot_get(upb_fieldtype_t type, const void* memory,
+                     CACHED_VALUE* cache TSRMLS_DC);
+// String/Message is stored differently in array/map from normal message fields.
+// So we need to make a special method to handle that.
+void native_slot_get_by_array(upb_fieldtype_t type, const void* memory,
+                     CACHED_VALUE* cache TSRMLS_DC);
+void native_slot_get_by_map_key(upb_fieldtype_t type, const void* memory,
+                                int length, CACHED_VALUE* cache TSRMLS_DC);
+void native_slot_get_by_map_value(upb_fieldtype_t type, const void* memory,
+                                  CACHED_VALUE* cache TSRMLS_DC);
+void native_slot_get_default(upb_fieldtype_t type,
+                             CACHED_VALUE* cache TSRMLS_DC);
+
+// -----------------------------------------------------------------------------
+// Map Field.
+// -----------------------------------------------------------------------------
+
+extern zend_object_handlers* map_field_handlers;
+extern zend_object_handlers* map_field_iter_handlers;
+
+PHP_PROTO_WRAP_OBJECT_START(Map)
+  upb_fieldtype_t key_type;
+  upb_fieldtype_t value_type;
+  const zend_class_entry* msg_ce;  // class entry for value message
+  upb_strtable table;
+PHP_PROTO_WRAP_OBJECT_END
+
+PHP_PROTO_WRAP_OBJECT_START(MapIter)
+  Map* self;
+  upb_strtable_iter it;
+PHP_PROTO_WRAP_OBJECT_END
+
+void map_begin(zval* self, MapIter* iter TSRMLS_DC);
+void map_next(MapIter* iter);
+bool map_done(MapIter* iter);
+const char* map_iter_key(MapIter* iter, int* len);
+upb_value map_iter_value(MapIter* iter, int* len);
+
+// These operate on a map-entry msgdef.
+const upb_fielddef* map_entry_key(const upb_msgdef* msgdef);
+const upb_fielddef* map_entry_value(const upb_msgdef* msgdef);
+
+void map_field_create_with_field(const zend_class_entry* ce,
+                                 const upb_fielddef* field,
+                                 CACHED_VALUE* map_field PHP_PROTO_TSRMLS_DC);
+void map_field_create_with_type(const zend_class_entry* ce,
+                                upb_fieldtype_t key_type,
+                                upb_fieldtype_t value_type,
+                                const zend_class_entry* msg_ce,
+                                CACHED_VALUE* map_field PHP_PROTO_TSRMLS_DC);
+void* upb_value_memory(upb_value* v);
+
+#define MAP_KEY_FIELD 1
+#define MAP_VALUE_FIELD 2
+
+// These operate on a map field (i.e., a repeated field of submessages whose
+// submessage type is a map-entry msgdef).
+bool is_map_field(const upb_fielddef* field);
+const upb_fielddef* map_field_key(const upb_fielddef* field);
+const upb_fielddef* map_field_value(const upb_fielddef* field);
+
+bool map_index_set(Map *intern, const char* keyval, int length, upb_value v);
+
+PHP_METHOD(MapField, __construct);
+PHP_METHOD(MapField, offsetExists);
+PHP_METHOD(MapField, offsetGet);
+PHP_METHOD(MapField, offsetSet);
+PHP_METHOD(MapField, offsetUnset);
+PHP_METHOD(MapField, count);
+PHP_METHOD(MapField, getIterator);
+
+PHP_METHOD(MapFieldIter, rewind);
+PHP_METHOD(MapFieldIter, current);
+PHP_METHOD(MapFieldIter, key);
+PHP_METHOD(MapFieldIter, next);
+PHP_METHOD(MapFieldIter, valid);
+
+// -----------------------------------------------------------------------------
+// Repeated Field.
+// -----------------------------------------------------------------------------
+
+extern zend_object_handlers* repeated_field_handlers;
+extern zend_object_handlers* repeated_field_iter_handlers;
+
+PHP_PROTO_WRAP_OBJECT_START(RepeatedField)
+#if PHP_MAJOR_VERSION < 7
+  zval* array;
+#else
+  zval array;
+#endif
+  upb_fieldtype_t type;
+  const zend_class_entry* msg_ce;  // class entry for containing message
+                                   // (for message field only).
+PHP_PROTO_WRAP_OBJECT_END
+
+PHP_PROTO_WRAP_OBJECT_START(RepeatedFieldIter)
+  RepeatedField* repeated_field;
+  long position;
+PHP_PROTO_WRAP_OBJECT_END
+
+void repeated_field_create_with_field(
+    zend_class_entry* ce, const upb_fielddef* field,
+    CACHED_VALUE* repeated_field PHP_PROTO_TSRMLS_DC);
+void repeated_field_create_with_type(
+    zend_class_entry* ce, upb_fieldtype_t type, const zend_class_entry* msg_ce,
+    CACHED_VALUE* repeated_field PHP_PROTO_TSRMLS_DC);
+// Return the element at the index position from the repeated field. There is
+// not restriction on the type of stored elements.
+void *repeated_field_index_native(RepeatedField *intern, int index TSRMLS_DC);
+// Add the element to the end of the repeated field. There is not restriction on
+// the type of stored elements.
+void repeated_field_push_native(RepeatedField *intern, void *value);
+
+PHP_METHOD(RepeatedField, __construct);
+PHP_METHOD(RepeatedField, append);
+PHP_METHOD(RepeatedField, offsetExists);
+PHP_METHOD(RepeatedField, offsetGet);
+PHP_METHOD(RepeatedField, offsetSet);
+PHP_METHOD(RepeatedField, offsetUnset);
+PHP_METHOD(RepeatedField, count);
+PHP_METHOD(RepeatedField, getIterator);
+
+PHP_METHOD(RepeatedFieldIter, rewind);
+PHP_METHOD(RepeatedFieldIter, current);
+PHP_METHOD(RepeatedFieldIter, key);
+PHP_METHOD(RepeatedFieldIter, next);
+PHP_METHOD(RepeatedFieldIter, valid);
+
+// -----------------------------------------------------------------------------
+// Oneof Field.
+// -----------------------------------------------------------------------------
+
+PHP_PROTO_WRAP_OBJECT_START(Oneof)
+  upb_oneofdef* oneofdef;
+  int index;    // Index of field in oneof. -1 if not set.
+  char value[NATIVE_SLOT_MAX_SIZE];
+PHP_PROTO_WRAP_OBJECT_END
+
+PHP_METHOD(Oneof, getName);
+PHP_METHOD(Oneof, getField);
+PHP_METHOD(Oneof, getFieldCount);
+
+extern zend_class_entry* oneof_descriptor_type;
+
+// Oneof case slot value to indicate that no oneof case is set. The value `0` is
+// safe because field numbers are used as case identifiers, and no field can
+// have a number of 0.
+#define ONEOF_CASE_NONE 0
+
+// -----------------------------------------------------------------------------
+// Well Known Type.
+// -----------------------------------------------------------------------------
+
+extern bool is_inited_file_any;
+extern bool is_inited_file_api;
+extern bool is_inited_file_duration;
+extern bool is_inited_file_field_mask;
+extern bool is_inited_file_empty;
+extern bool is_inited_file_source_context;
+extern bool is_inited_file_struct;
+extern bool is_inited_file_timestamp;
+extern bool is_inited_file_type;
+extern bool is_inited_file_wrappers;
+
+PHP_METHOD(GPBMetadata_Any, initOnce);
+PHP_METHOD(GPBMetadata_Api, initOnce);
+PHP_METHOD(GPBMetadata_Duration, initOnce);
+PHP_METHOD(GPBMetadata_FieldMask, initOnce);
+PHP_METHOD(GPBMetadata_Empty, initOnce);
+PHP_METHOD(GPBMetadata_SourceContext, initOnce);
+PHP_METHOD(GPBMetadata_Struct, initOnce);
+PHP_METHOD(GPBMetadata_Timestamp, initOnce);
+PHP_METHOD(GPBMetadata_Type, initOnce);
+PHP_METHOD(GPBMetadata_Wrappers, initOnce);
+
+PHP_METHOD(Any, __construct);
+PHP_METHOD(Any, getTypeUrl);
+PHP_METHOD(Any, setTypeUrl);
+PHP_METHOD(Any, getValue);
+PHP_METHOD(Any, setValue);
+PHP_METHOD(Any, unpack);
+PHP_METHOD(Any, pack);
+PHP_METHOD(Any, is);
+
+PHP_METHOD(Duration, __construct);
+PHP_METHOD(Duration, getSeconds);
+PHP_METHOD(Duration, setSeconds);
+PHP_METHOD(Duration, getNanos);
+PHP_METHOD(Duration, setNanos);
+
+PHP_METHOD(Timestamp, __construct);
+PHP_METHOD(Timestamp, fromDateTime);
+PHP_METHOD(Timestamp, toDateTime);
+PHP_METHOD(Timestamp, getSeconds);
+PHP_METHOD(Timestamp, setSeconds);
+PHP_METHOD(Timestamp, getNanos);
+PHP_METHOD(Timestamp, setNanos);
+
+PHP_METHOD(Api, __construct);
+PHP_METHOD(Api, getName);
+PHP_METHOD(Api, setName);
+PHP_METHOD(Api, getMethods);
+PHP_METHOD(Api, setMethods);
+PHP_METHOD(Api, getOptions);
+PHP_METHOD(Api, setOptions);
+PHP_METHOD(Api, getVersion);
+PHP_METHOD(Api, setVersion);
+PHP_METHOD(Api, getSourceContext);
+PHP_METHOD(Api, setSourceContext);
+PHP_METHOD(Api, getMixins);
+PHP_METHOD(Api, setMixins);
+PHP_METHOD(Api, getSyntax);
+PHP_METHOD(Api, setSyntax);
+
+PHP_METHOD(BoolValue, __construct);
+PHP_METHOD(BoolValue, getValue);
+PHP_METHOD(BoolValue, setValue);
+
+PHP_METHOD(BytesValue, __construct);
+PHP_METHOD(BytesValue, getValue);
+PHP_METHOD(BytesValue, setValue);
+
+PHP_METHOD(DoubleValue, __construct);
+PHP_METHOD(DoubleValue, getValue);
+PHP_METHOD(DoubleValue, setValue);
+
+PHP_METHOD(Enum, __construct);
+PHP_METHOD(Enum, getName);
+PHP_METHOD(Enum, setName);
+PHP_METHOD(Enum, getEnumvalue);
+PHP_METHOD(Enum, setEnumvalue);
+PHP_METHOD(Enum, getOptions);
+PHP_METHOD(Enum, setOptions);
+PHP_METHOD(Enum, getSourceContext);
+PHP_METHOD(Enum, setSourceContext);
+PHP_METHOD(Enum, getSyntax);
+PHP_METHOD(Enum, setSyntax);
+
+PHP_METHOD(EnumValue, __construct);
+PHP_METHOD(EnumValue, getName);
+PHP_METHOD(EnumValue, setName);
+PHP_METHOD(EnumValue, getNumber);
+PHP_METHOD(EnumValue, setNumber);
+PHP_METHOD(EnumValue, getOptions);
+PHP_METHOD(EnumValue, setOptions);
+
+PHP_METHOD(FieldMask, __construct);
+PHP_METHOD(FieldMask, getPaths);
+PHP_METHOD(FieldMask, setPaths);
+
+PHP_METHOD(Field, __construct);
+PHP_METHOD(Field, getKind);
+PHP_METHOD(Field, setKind);
+PHP_METHOD(Field, getCardinality);
+PHP_METHOD(Field, setCardinality);
+PHP_METHOD(Field, getNumber);
+PHP_METHOD(Field, setNumber);
+PHP_METHOD(Field, getName);
+PHP_METHOD(Field, setName);
+PHP_METHOD(Field, getTypeUrl);
+PHP_METHOD(Field, setTypeUrl);
+PHP_METHOD(Field, getOneofIndex);
+PHP_METHOD(Field, setOneofIndex);
+PHP_METHOD(Field, getPacked);
+PHP_METHOD(Field, setPacked);
+PHP_METHOD(Field, getOptions);
+PHP_METHOD(Field, setOptions);
+PHP_METHOD(Field, getJsonName);
+PHP_METHOD(Field, setJsonName);
+PHP_METHOD(Field, getDefaultValue);
+PHP_METHOD(Field, setDefaultValue);
+
+PHP_METHOD(FloatValue, __construct);
+PHP_METHOD(FloatValue, getValue);
+PHP_METHOD(FloatValue, setValue);
+
+PHP_METHOD(GPBEmpty, __construct);
+
+PHP_METHOD(Int32Value, __construct);
+PHP_METHOD(Int32Value, getValue);
+PHP_METHOD(Int32Value, setValue);
+
+PHP_METHOD(Int64Value, __construct);
+PHP_METHOD(Int64Value, getValue);
+PHP_METHOD(Int64Value, setValue);
+
+PHP_METHOD(ListValue, __construct);
+PHP_METHOD(ListValue, getValues);
+PHP_METHOD(ListValue, setValues);
+
+PHP_METHOD(Method, __construct);
+PHP_METHOD(Method, getName);
+PHP_METHOD(Method, setName);
+PHP_METHOD(Method, getRequestTypeUrl);
+PHP_METHOD(Method, setRequestTypeUrl);
+PHP_METHOD(Method, getRequestStreaming);
+PHP_METHOD(Method, setRequestStreaming);
+PHP_METHOD(Method, getResponseTypeUrl);
+PHP_METHOD(Method, setResponseTypeUrl);
+PHP_METHOD(Method, getResponseStreaming);
+PHP_METHOD(Method, setResponseStreaming);
+PHP_METHOD(Method, getOptions);
+PHP_METHOD(Method, setOptions);
+PHP_METHOD(Method, getSyntax);
+PHP_METHOD(Method, setSyntax);
+
+PHP_METHOD(Mixin, __construct);
+PHP_METHOD(Mixin, getName);
+PHP_METHOD(Mixin, setName);
+PHP_METHOD(Mixin, getRoot);
+PHP_METHOD(Mixin, setRoot);
+
+PHP_METHOD(Option, __construct);
+PHP_METHOD(Option, getName);
+PHP_METHOD(Option, setName);
+PHP_METHOD(Option, getValue);
+PHP_METHOD(Option, setValue);
+
+PHP_METHOD(SourceContext, __construct);
+PHP_METHOD(SourceContext, getFileName);
+PHP_METHOD(SourceContext, setFileName);
+
+PHP_METHOD(StringValue, __construct);
+PHP_METHOD(StringValue, getValue);
+PHP_METHOD(StringValue, setValue);
+
+PHP_METHOD(Struct, __construct);
+PHP_METHOD(Struct, getFields);
+PHP_METHOD(Struct, setFields);
+
+PHP_METHOD(Type, __construct);
+PHP_METHOD(Type, getName);
+PHP_METHOD(Type, setName);
+PHP_METHOD(Type, getFields);
+PHP_METHOD(Type, setFields);
+PHP_METHOD(Type, getOneofs);
+PHP_METHOD(Type, setOneofs);
+PHP_METHOD(Type, getOptions);
+PHP_METHOD(Type, setOptions);
+PHP_METHOD(Type, getSourceContext);
+PHP_METHOD(Type, setSourceContext);
+PHP_METHOD(Type, getSyntax);
+PHP_METHOD(Type, setSyntax);
+
+PHP_METHOD(UInt32Value, __construct);
+PHP_METHOD(UInt32Value, getValue);
+PHP_METHOD(UInt32Value, setValue);
+
+PHP_METHOD(UInt64Value, __construct);
+PHP_METHOD(UInt64Value, getValue);
+PHP_METHOD(UInt64Value, setValue);
+
+PHP_METHOD(Value, __construct);
+PHP_METHOD(Value, getNullValue);
+PHP_METHOD(Value, setNullValue);
+PHP_METHOD(Value, getNumberValue);
+PHP_METHOD(Value, setNumberValue);
+PHP_METHOD(Value, getStringValue);
+PHP_METHOD(Value, setStringValue);
+PHP_METHOD(Value, getBoolValue);
+PHP_METHOD(Value, setBoolValue);
+PHP_METHOD(Value, getStructValue);
+PHP_METHOD(Value, setStructValue);
+PHP_METHOD(Value, getListValue);
+PHP_METHOD(Value, setListValue);
+PHP_METHOD(Value, getKind);
+
+extern zend_class_entry* any_type;
+extern zend_class_entry* api_type;
+extern zend_class_entry* bool_value_type;
+extern zend_class_entry* bytes_value_type;
+extern zend_class_entry* double_value_type;
+extern zend_class_entry* duration_type;
+extern zend_class_entry* empty_type;
+extern zend_class_entry* enum_type;
+extern zend_class_entry* enum_value_type;
+extern zend_class_entry* field_cardinality_type;
+extern zend_class_entry* field_kind_type;
+extern zend_class_entry* field_mask_type;
+extern zend_class_entry* field_type;
+extern zend_class_entry* float_value_type;
+extern zend_class_entry* int32_value_type;
+extern zend_class_entry* int64_value_type;
+extern zend_class_entry* list_value_type;
+extern zend_class_entry* method_type;
+extern zend_class_entry* mixin_type;
+extern zend_class_entry* null_value_type;
+extern zend_class_entry* option_type;
+extern zend_class_entry* source_context_type;
+extern zend_class_entry* string_value_type;
+extern zend_class_entry* struct_type;
+extern zend_class_entry* syntax_type;
+extern zend_class_entry* timestamp_type;
+extern zend_class_entry* type_type;
+extern zend_class_entry* uint32_value_type;
+extern zend_class_entry* uint64_value_type;
+extern zend_class_entry* value_type;
+
+// -----------------------------------------------------------------------------
+// Upb.
+// -----------------------------------------------------------------------------
+
+upb_fieldtype_t to_fieldtype(upb_descriptortype_t type);
+const zend_class_entry* field_type_class(
+    const upb_fielddef* field PHP_PROTO_TSRMLS_DC);
+
+// -----------------------------------------------------------------------------
+// Utilities.
+// -----------------------------------------------------------------------------
+
+// Memory management
+#define ALLOC(class_name) (class_name*) emalloc(sizeof(class_name))
+#define PEMALLOC(class_name) (class_name*) pemalloc(sizeof(class_name), 1)
+#define ALLOC_N(class_name, n) (class_name*) emalloc(sizeof(class_name) * n)
+#define FREE(object) efree(object)
+#define PEFREE(object) pefree(object, 1)
+
+// String argument.
+#define STR(str) (str), strlen(str)
+
+// Zend Value
+#if PHP_MAJOR_VERSION < 7
+#define Z_OBJ_P(zval_p)                                       \
+  ((zend_object*)(EG(objects_store)                           \
+                      .object_buckets[Z_OBJ_HANDLE_P(zval_p)] \
+                      .bucket.obj.object))
+#endif
+
+// Message handler
+static inline zval* php_proto_message_read_property(
+    zval* msg, zval* member PHP_PROTO_TSRMLS_DC) {
+#if PHP_MAJOR_VERSION < 7
+  return message_handlers->read_property(msg, member, BP_VAR_R,
+                                         NULL PHP_PROTO_TSRMLS_CC);
+#else
+  return message_handlers->read_property(msg, member, BP_VAR_R, NULL,
+                                         NULL PHP_PROTO_TSRMLS_CC);
+#endif
+}
+
+// Reserved name
+bool is_reserved_name(const char* name);
+bool is_valid_constant_name(const char* name);
+
+#endif  // __GOOGLE_PROTOBUF_PHP_PROTOBUF_H__
diff --git a/php/ext/google/protobuf/storage.c b/php/ext/google/protobuf/storage.c
new file mode 100644
index 0000000..a60fbe3
--- /dev/null
+++ b/php/ext/google/protobuf/storage.c
@@ -0,0 +1,1145 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// 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.
+
+#include <stdint.h>
+#include <protobuf.h>
+#include <Zend/zend.h>
+
+#include "utf8.h"
+
+// -----------------------------------------------------------------------------
+// Native slot storage.
+// -----------------------------------------------------------------------------
+
+#define DEREF(memory, type) *(type*)(memory)
+
+size_t native_slot_size(upb_fieldtype_t type) {
+  switch (type) {
+    case UPB_TYPE_FLOAT: return 4;
+    case UPB_TYPE_DOUBLE: return 8;
+    case UPB_TYPE_BOOL: return 1;
+    case UPB_TYPE_STRING: return sizeof(void*);
+    case UPB_TYPE_BYTES: return sizeof(void*);
+    case UPB_TYPE_MESSAGE: return sizeof(void*);
+    case UPB_TYPE_ENUM: return 4;
+    case UPB_TYPE_INT32: return 4;
+    case UPB_TYPE_INT64: return 8;
+    case UPB_TYPE_UINT32: return 4;
+    case UPB_TYPE_UINT64: return 8;
+    default: return 0;
+  }
+}
+
+static bool native_slot_is_default(upb_fieldtype_t type, const void* memory) {
+  switch (type) {
+#define CASE_TYPE(upb_type, c_type)    \
+  case UPB_TYPE_##upb_type: {          \
+    return DEREF(memory, c_type) == 0; \
+  }
+    CASE_TYPE(INT32,  int32_t )
+    CASE_TYPE(UINT32, uint32_t)
+    CASE_TYPE(ENUM,   int32_t )
+    CASE_TYPE(INT64,  int64_t )
+    CASE_TYPE(UINT64, uint64_t)
+    CASE_TYPE(FLOAT,  float   )
+    CASE_TYPE(DOUBLE, double  )
+    CASE_TYPE(BOOL,   int8_t  )
+
+#undef CASE_TYPE
+    case UPB_TYPE_STRING:
+    case UPB_TYPE_BYTES:
+      return Z_STRLEN_P(CACHED_PTR_TO_ZVAL_PTR(DEREF(memory, CACHED_VALUE*))) ==
+             0;
+    case UPB_TYPE_MESSAGE:
+      return Z_TYPE_P(CACHED_PTR_TO_ZVAL_PTR(DEREF(memory, CACHED_VALUE*))) ==
+             IS_NULL;
+    default: return false;
+  }
+}
+
+bool native_slot_set(upb_fieldtype_t type, const zend_class_entry* klass,
+                     void* memory, zval* value PHP_PROTO_TSRMLS_DC) {
+  switch (type) {
+    case UPB_TYPE_STRING:
+    case UPB_TYPE_BYTES: {
+      if (!protobuf_convert_to_string(value)) {
+        return false;
+      }
+      if (type == UPB_TYPE_STRING &&
+          !is_structurally_valid_utf8(Z_STRVAL_P(value), Z_STRLEN_P(value))) {
+        zend_error(E_USER_ERROR, "Given string is not UTF8 encoded.");
+        return false;
+      }
+
+      zval* cached_zval = CACHED_PTR_TO_ZVAL_PTR((CACHED_VALUE*)memory);
+      if (EXPECTED(cached_zval != NULL)) {
+#if PHP_MAJOR_VERSION < 7
+        REPLACE_ZVAL_VALUE((zval**)memory, value, 1);
+#else
+        zend_assign_to_variable(cached_zval, value, IS_CV);
+#endif
+      }
+      break;
+    }
+    case UPB_TYPE_MESSAGE: {
+      if (Z_TYPE_P(value) != IS_OBJECT && Z_TYPE_P(value) != IS_NULL) {
+        zend_error(E_USER_ERROR, "Given value is not message.");
+        return false;
+      }
+      if (Z_TYPE_P(value) == IS_OBJECT && klass != Z_OBJCE_P(value)) {
+        zend_error(E_USER_ERROR, "Given message does not have correct class.");
+        return false;
+      }
+
+      zval* property_ptr = CACHED_PTR_TO_ZVAL_PTR((CACHED_VALUE*)memory);
+      if (EXPECTED(property_ptr != value)) {
+        php_proto_zval_ptr_dtor(property_ptr);
+      }
+
+#if PHP_MAJOR_VERSION < 7
+      DEREF(memory, zval*) = value;
+      Z_ADDREF_P(value);
+#else
+      ZVAL_ZVAL(property_ptr, value, 1, 0);
+#endif
+      break;
+    }
+
+#define CASE_TYPE(upb_type, type, c_type, php_type)              \
+  case UPB_TYPE_##upb_type: {                                    \
+    c_type type##_value;                                         \
+    if (protobuf_convert_to_##type(value, &type##_value)) {      \
+      DEREF(memory, c_type) = type##_value;                      \
+    }                                                            \
+    break;                                                       \
+  }
+      CASE_TYPE(INT32,  int32,  int32_t,  LONG)
+      CASE_TYPE(UINT32, uint32, uint32_t, LONG)
+      CASE_TYPE(ENUM,   int32,  int32_t,  LONG)
+      CASE_TYPE(INT64,  int64,  int64_t,  LONG)
+      CASE_TYPE(UINT64, uint64, uint64_t, LONG)
+      CASE_TYPE(FLOAT,  float,  float,    DOUBLE)
+      CASE_TYPE(DOUBLE, double, double,   DOUBLE)
+      CASE_TYPE(BOOL,   bool,   int8_t,   BOOL)
+
+#undef CASE_TYPE
+
+    default:
+      break;
+  }
+
+  return true;
+}
+
+bool native_slot_set_by_array(upb_fieldtype_t type,
+                              const zend_class_entry* klass, void* memory,
+                              zval* value TSRMLS_DC) {
+  switch (type) {
+    case UPB_TYPE_STRING:
+    case UPB_TYPE_BYTES: {
+      if (!protobuf_convert_to_string(value)) {
+        return false;
+      }
+      if (type == UPB_TYPE_STRING &&
+          !is_structurally_valid_utf8(Z_STRVAL_P(value), Z_STRLEN_P(value))) {
+        zend_error(E_USER_ERROR, "Given string is not UTF8 encoded.");
+        return false;
+      }
+
+      // Handles repeated/map string field. Memory provided by
+      // RepeatedField/Map is not initialized.
+#if PHP_MAJOR_VERSION < 7
+      MAKE_STD_ZVAL(DEREF(memory, zval*));
+      PHP_PROTO_ZVAL_STRINGL(DEREF(memory, zval*), Z_STRVAL_P(value),
+                             Z_STRLEN_P(value), 1);
+#else
+      *(zend_string**)memory = zend_string_dup(Z_STR_P(value), 0);
+#endif
+      break;
+    }
+    case UPB_TYPE_MESSAGE: {
+      if (Z_TYPE_P(value) != IS_OBJECT) {
+        zend_error(E_USER_ERROR, "Given value is not message.");
+        return false;
+      }
+      if (Z_TYPE_P(value) == IS_OBJECT && klass != Z_OBJCE_P(value)) {
+        zend_error(E_USER_ERROR, "Given message does not have correct class.");
+        return false;
+      }
+#if PHP_MAJOR_VERSION < 7
+      if (EXPECTED(DEREF(memory, zval*) != value)) {
+        DEREF(memory, zval*) = value;
+        Z_ADDREF_P(value);
+      }
+#else
+      DEREF(memory, zval*) = value;
+      GC_ADDREF(Z_OBJ_P(value));
+#endif
+      break;
+    }
+    default:
+      return native_slot_set(type, klass, memory, value TSRMLS_CC);
+  }
+  return true;
+}
+
+bool native_slot_set_by_map(upb_fieldtype_t type, const zend_class_entry* klass,
+                            void* memory, zval* value TSRMLS_DC) {
+  switch (type) {
+    case UPB_TYPE_STRING:
+    case UPB_TYPE_BYTES: {
+      if (!protobuf_convert_to_string(value)) {
+        return false;
+      }
+      if (type == UPB_TYPE_STRING &&
+          !is_structurally_valid_utf8(Z_STRVAL_P(value), Z_STRLEN_P(value))) {
+        zend_error(E_USER_ERROR, "Given string is not UTF8 encoded.");
+        return false;
+      }
+
+      // Handles repeated/map string field. Memory provided by
+      // RepeatedField/Map is not initialized.
+#if PHP_MAJOR_VERSION < 7
+      MAKE_STD_ZVAL(DEREF(memory, zval*));
+      PHP_PROTO_ZVAL_STRINGL(DEREF(memory, zval*), Z_STRVAL_P(value),
+                             Z_STRLEN_P(value), 1);
+#else
+      *(zend_string**)memory = zend_string_dup(Z_STR_P(value), 0);
+#endif
+      break;
+    }
+    case UPB_TYPE_MESSAGE: {
+      if (Z_TYPE_P(value) != IS_OBJECT) {
+        zend_error(E_USER_ERROR, "Given value is not message.");
+        return false;
+      }
+      if (Z_TYPE_P(value) == IS_OBJECT && klass != Z_OBJCE_P(value)) {
+        zend_error(E_USER_ERROR, "Given message does not have correct class.");
+        return false;
+      }
+#if PHP_MAJOR_VERSION < 7
+      if (EXPECTED(DEREF(memory, zval*) != value)) {
+        DEREF(memory, zval*) = value;
+        Z_ADDREF_P(value);
+      }
+#else
+      DEREF(memory, zend_object*) = Z_OBJ_P(value);
+      GC_ADDREF(Z_OBJ_P(value));
+#endif
+      break;
+    }
+    default:
+      return native_slot_set(type, klass, memory, value TSRMLS_CC);
+  }
+  return true;
+}
+
+void native_slot_init(upb_fieldtype_t type, void* memory, CACHED_VALUE* cache) {
+  zval* tmp = NULL;
+  switch (type) {
+    case UPB_TYPE_FLOAT:
+      DEREF(memory, float) = 0.0;
+      break;
+    case UPB_TYPE_DOUBLE:
+      DEREF(memory, double) = 0.0;
+      break;
+    case UPB_TYPE_BOOL:
+      DEREF(memory, int8_t) = 0;
+      break;
+    case UPB_TYPE_STRING:
+    case UPB_TYPE_BYTES:
+    case UPB_TYPE_MESSAGE:
+      DEREF(memory, CACHED_VALUE*) = cache;
+      break;
+    case UPB_TYPE_ENUM:
+    case UPB_TYPE_INT32:
+      DEREF(memory, int32_t) = 0;
+      break;
+    case UPB_TYPE_INT64:
+      DEREF(memory, int64_t) = 0;
+      break;
+    case UPB_TYPE_UINT32:
+      DEREF(memory, uint32_t) = 0;
+      break;
+    case UPB_TYPE_UINT64:
+      DEREF(memory, uint64_t) = 0;
+      break;
+    default:
+      break;
+  }
+}
+
+void native_slot_get(upb_fieldtype_t type, const void* memory,
+                     CACHED_VALUE* cache TSRMLS_DC) {
+  switch (type) {
+#define CASE(upb_type, php_type, c_type)                                   \
+  case UPB_TYPE_##upb_type:                                                \
+    PHP_PROTO_SEPARATE_ZVAL_IF_NOT_REF(cache);                             \
+    ZVAL_##php_type(CACHED_PTR_TO_ZVAL_PTR(cache), DEREF(memory, c_type)); \
+    return;
+
+    CASE(FLOAT, DOUBLE, float)
+    CASE(DOUBLE, DOUBLE, double)
+    CASE(BOOL, BOOL, int8_t)
+    CASE(INT32, LONG, int32_t)
+    CASE(ENUM, LONG, uint32_t)
+
+#undef CASE
+
+#if SIZEOF_LONG == 4
+#define CASE(upb_type, c_type)                                       \
+  case UPB_TYPE_##upb_type: {                                        \
+    PHP_PROTO_SEPARATE_ZVAL_IF_NOT_REF(cache);                       \
+    char buffer[MAX_LENGTH_OF_INT64];                                \
+    sprintf(buffer, "%lld", DEREF(memory, c_type));                  \
+    PHP_PROTO_ZVAL_STRING(CACHED_PTR_TO_ZVAL_PTR(cache), buffer, 1); \
+    return;                                                          \
+  }
+#else
+#define CASE(upb_type, c_type)                                       \
+  case UPB_TYPE_##upb_type: {                                        \
+    PHP_PROTO_SEPARATE_ZVAL_IF_NOT_REF(cache);                       \
+    ZVAL_LONG(CACHED_PTR_TO_ZVAL_PTR(cache), DEREF(memory, c_type)); \
+    return;                                                          \
+  }
+#endif
+CASE(UINT64, uint64_t)
+CASE(INT64,  int64_t)
+#undef CASE
+
+    case UPB_TYPE_UINT32: {
+      // Prepend bit-1 for negative numbers, so that uint32 value will be
+      // consistent on both 32-bit and 64-bit architectures.
+      PHP_PROTO_SEPARATE_ZVAL_IF_NOT_REF(cache);
+      int value = DEREF(memory, int32_t);
+      if (sizeof(int) == 8) {
+        value |= (-((value >> 31) & 0x1) & 0xFFFFFFFF00000000);
+      }
+      ZVAL_LONG(CACHED_PTR_TO_ZVAL_PTR(cache), value);
+      return;
+    }
+
+    case UPB_TYPE_STRING:
+    case UPB_TYPE_BYTES: {
+      // For optional string/bytes/message fields, the cache is owned by the
+      // containing message and should have been updated during
+      // setting/decoding. However, oneof accessor call this function by
+      // providing the return value directly, which is not the same as the cache
+      // value.
+      zval* value = CACHED_PTR_TO_ZVAL_PTR((CACHED_VALUE*)memory);
+      if (CACHED_PTR_TO_ZVAL_PTR(cache) != value) {
+        PHP_PROTO_ZVAL_STRINGL(CACHED_PTR_TO_ZVAL_PTR(cache), Z_STRVAL_P(value),
+                               Z_STRLEN_P(value), 1);
+      }
+      break;
+    }
+    case UPB_TYPE_MESSAGE: {
+      // Same as above for string/bytes fields.
+      zval* value = CACHED_PTR_TO_ZVAL_PTR((CACHED_VALUE*)memory);
+      if (CACHED_PTR_TO_ZVAL_PTR(cache) != value) {
+        ZVAL_ZVAL(CACHED_PTR_TO_ZVAL_PTR(cache), value, 1, 0);
+      }
+      return;
+    }
+    default:
+      return;
+  }
+}
+
+void native_slot_get_by_array(upb_fieldtype_t type, const void* memory,
+                              CACHED_VALUE* cache TSRMLS_DC) {
+  switch (type) {
+    case UPB_TYPE_STRING:
+    case UPB_TYPE_BYTES: {
+#if PHP_MAJOR_VERSION < 7
+      zval* value = CACHED_PTR_TO_ZVAL_PTR((CACHED_VALUE*)memory);
+      if (EXPECTED(CACHED_PTR_TO_ZVAL_PTR(cache) != value)) {
+        PHP_PROTO_ZVAL_STRINGL(CACHED_PTR_TO_ZVAL_PTR(cache),
+                               Z_STRVAL_P(value), Z_STRLEN_P(value), 1);
+      }
+#else
+      ZVAL_NEW_STR(cache, zend_string_dup(*(zend_string**)memory, 0));
+#endif
+      return;
+    }
+    case UPB_TYPE_MESSAGE: {
+#if PHP_MAJOR_VERSION < 7
+      zval* value = CACHED_PTR_TO_ZVAL_PTR((CACHED_VALUE*)memory);
+      if (EXPECTED(CACHED_PTR_TO_ZVAL_PTR(cache) != value)) {
+        ZVAL_ZVAL(CACHED_PTR_TO_ZVAL_PTR(cache), value, 1, 0);
+      }
+#else
+      ZVAL_COPY(CACHED_PTR_TO_ZVAL_PTR(cache), memory);
+#endif
+      return;
+    }
+    default:
+      native_slot_get(type, memory, cache TSRMLS_CC);
+  }
+}
+
+void native_slot_get_by_map_key(upb_fieldtype_t type, const void* memory,
+                                int length, CACHED_VALUE* cache TSRMLS_DC) {
+  switch (type) {
+    case UPB_TYPE_STRING:
+    case UPB_TYPE_BYTES: {
+      PHP_PROTO_ZVAL_STRINGL(CACHED_PTR_TO_ZVAL_PTR(cache), memory, length, 1);
+      return;
+    }
+    default:
+      native_slot_get(type, memory, cache TSRMLS_CC);
+  }
+}
+
+void native_slot_get_by_map_value(upb_fieldtype_t type, const void* memory,
+                              CACHED_VALUE* cache TSRMLS_DC) {
+  switch (type) {
+    case UPB_TYPE_MESSAGE: {
+#if PHP_MAJOR_VERSION < 7
+      zval* value = CACHED_PTR_TO_ZVAL_PTR((CACHED_VALUE*)memory);
+      if (EXPECTED(CACHED_PTR_TO_ZVAL_PTR(cache) != value)) {
+        ZVAL_ZVAL(CACHED_PTR_TO_ZVAL_PTR(cache), value, 1, 0);
+      }
+#else
+      GC_ADDREF(*(zend_object**)memory);
+      ZVAL_OBJ(cache, *(zend_object**)memory);
+#endif
+      return;
+    }
+    default:
+      native_slot_get_by_array(type, memory, cache TSRMLS_CC);
+  }
+}
+
+void native_slot_get_default(upb_fieldtype_t type,
+                             CACHED_VALUE* cache TSRMLS_DC) {
+  switch (type) {
+#define CASE(upb_type, php_type)                       \
+  case UPB_TYPE_##upb_type:                            \
+    PHP_PROTO_SEPARATE_ZVAL_IF_NOT_REF(cache);         \
+    ZVAL_##php_type(CACHED_PTR_TO_ZVAL_PTR(cache), 0); \
+    return;
+
+    CASE(FLOAT, DOUBLE)
+    CASE(DOUBLE, DOUBLE)
+    CASE(BOOL, BOOL)
+    CASE(INT32, LONG)
+    CASE(UINT32, LONG)
+    CASE(ENUM, LONG)
+
+#undef CASE
+
+#if SIZEOF_LONG == 4
+#define CASE(upb_type)                                            \
+  case UPB_TYPE_##upb_type: {                                     \
+    PHP_PROTO_SEPARATE_ZVAL_IF_NOT_REF(cache);                    \
+    PHP_PROTO_ZVAL_STRING(CACHED_PTR_TO_ZVAL_PTR(cache), "0", 1); \
+    return;                                                       \
+  }
+#else
+#define CASE(upb_type)                           \
+  case UPB_TYPE_##upb_type: {                    \
+    PHP_PROTO_SEPARATE_ZVAL_IF_NOT_REF(cache);   \
+    ZVAL_LONG(CACHED_PTR_TO_ZVAL_PTR(cache), 0); \
+    return;                                      \
+  }
+#endif
+CASE(UINT64)
+CASE(INT64)
+#undef CASE
+
+    case UPB_TYPE_STRING:
+    case UPB_TYPE_BYTES: {
+      PHP_PROTO_SEPARATE_ZVAL_IF_NOT_REF(cache);
+      PHP_PROTO_ZVAL_STRINGL(CACHED_PTR_TO_ZVAL_PTR(cache), "", 0, 1);
+      break;
+    }
+    case UPB_TYPE_MESSAGE: {
+      PHP_PROTO_SEPARATE_ZVAL_IF_NOT_REF(cache);
+      ZVAL_NULL(CACHED_PTR_TO_ZVAL_PTR(cache));
+      return;
+    }
+    default:
+      return;
+  }
+}
+
+// -----------------------------------------------------------------------------
+// Map field utilities.
+// ----------------------------------------------------------------------------
+
+const upb_msgdef* tryget_map_entry_msgdef(const upb_fielddef* field) {
+  const upb_msgdef* subdef;
+  if (upb_fielddef_label(field) != UPB_LABEL_REPEATED ||
+      upb_fielddef_type(field) != UPB_TYPE_MESSAGE) {
+    return NULL;
+  }
+  subdef = upb_fielddef_msgsubdef(field);
+  return upb_msgdef_mapentry(subdef) ? subdef : NULL;
+}
+
+const upb_msgdef* map_entry_msgdef(const upb_fielddef* field) {
+  const upb_msgdef* subdef = tryget_map_entry_msgdef(field);
+  assert(subdef);
+  return subdef;
+}
+
+bool is_map_field(const upb_fielddef* field) {
+  return tryget_map_entry_msgdef(field) != NULL;
+}
+
+const upb_fielddef* map_field_key(const upb_fielddef* field) {
+  const upb_msgdef* subdef = map_entry_msgdef(field);
+  return map_entry_key(subdef);
+}
+
+const upb_fielddef* map_field_value(const upb_fielddef* field) {
+  const upb_msgdef* subdef = map_entry_msgdef(field);
+  return map_entry_value(subdef);
+}
+
+const upb_fielddef* map_entry_key(const upb_msgdef* msgdef) {
+  const upb_fielddef* key_field = upb_msgdef_itof(msgdef, MAP_KEY_FIELD);
+  assert(key_field != NULL);
+  return key_field;
+}
+
+const upb_fielddef* map_entry_value(const upb_msgdef* msgdef) {
+  const upb_fielddef* value_field = upb_msgdef_itof(msgdef, MAP_VALUE_FIELD);
+  assert(value_field != NULL);
+  return value_field;
+}
+
+const zend_class_entry* field_type_class(
+    const upb_fielddef* field PHP_PROTO_TSRMLS_DC) {
+  if (upb_fielddef_type(field) == UPB_TYPE_MESSAGE) {
+    Descriptor* desc = UNBOX_HASHTABLE_VALUE(
+        Descriptor, get_def_obj(upb_fielddef_subdef(field)));
+    return desc->klass;
+  } else if (upb_fielddef_type(field) == UPB_TYPE_ENUM) {
+    EnumDescriptor* desc = UNBOX_HASHTABLE_VALUE(
+        EnumDescriptor, get_def_obj(upb_fielddef_subdef(field)));
+    return desc->klass;
+  }
+  return NULL;
+}
+
+// -----------------------------------------------------------------------------
+// Memory layout management.
+// -----------------------------------------------------------------------------
+
+static size_t align_up_to(size_t offset, size_t granularity) {
+  // Granularity must be a power of two.
+  return (offset + granularity - 1) & ~(granularity - 1);
+}
+
+static uint32_t* slot_oneof_case(MessageLayout* layout, const void* storage,
+                                 const upb_fielddef* field) {
+  return (uint32_t*)(((uint8_t*)storage) +
+                     layout->fields[upb_fielddef_index(field)].case_offset);
+}
+
+static int slot_property_cache(MessageLayout* layout, const void* storage,
+                               const upb_fielddef* field) {
+  return layout->fields[upb_fielddef_index(field)].cache_index;
+}
+
+void* slot_memory(MessageLayout* layout, const void* storage,
+                         const upb_fielddef* field) {
+  return ((uint8_t*)storage) + layout->fields[upb_fielddef_index(field)].offset;
+}
+
+MessageLayout* create_layout(const upb_msgdef* msgdef) {
+  MessageLayout* layout = ALLOC(MessageLayout);
+  int nfields = upb_msgdef_numfields(msgdef);
+  upb_msg_field_iter it;
+  upb_msg_oneof_iter oit;
+  size_t off = 0;
+  int i = 0;
+
+  // Reserve space for unknown fields.
+  off += sizeof(void*);
+
+  TSRMLS_FETCH();
+  Descriptor* desc = UNBOX_HASHTABLE_VALUE(Descriptor, get_def_obj(msgdef));
+  layout->fields = ALLOC_N(MessageField, nfields);
+
+  for (upb_msg_field_begin(&it, msgdef); !upb_msg_field_done(&it);
+       upb_msg_field_next(&it)) {
+    const upb_fielddef* field = upb_msg_iter_field(&it);
+    size_t field_size;
+
+    if (upb_fielddef_containingoneof(field)) {
+      // Oneofs are handled separately below.
+      continue;
+    }
+
+    // Allocate |field_size| bytes for this field in the layout.
+    field_size = 0;
+    if (upb_fielddef_label(field) == UPB_LABEL_REPEATED) {
+      field_size = sizeof(zval*);
+    } else {
+      field_size = native_slot_size(upb_fielddef_type(field));
+    }
+
+    // Align current offset up to | size | granularity.
+    off = align_up_to(off, field_size);
+    layout->fields[upb_fielddef_index(field)].offset = off;
+    layout->fields[upb_fielddef_index(field)].case_offset =
+        MESSAGE_FIELD_NO_CASE;
+
+    const char* fieldname = upb_fielddef_name(field);
+
+#if PHP_MAJOR_VERSION < 7 || (PHP_MAJOR_VERSION == 7 && PHP_MINOR_VERSION == 0)
+    zend_class_entry* old_scope = EG(scope);
+    EG(scope) = desc->klass;
+#else
+    zend_class_entry* old_scope = EG(fake_scope);
+    EG(fake_scope) = desc->klass;
+#endif
+
+#if PHP_MAJOR_VERSION < 7
+    zval member;
+    ZVAL_STRINGL(&member, fieldname, strlen(fieldname), 0);
+    zend_property_info* property_info =
+        zend_get_property_info(desc->klass, &member, true TSRMLS_CC);
+#else
+    zend_string* member = zend_string_init(fieldname, strlen(fieldname), 1);
+    zend_property_info* property_info =
+        zend_get_property_info(desc->klass, member, true);
+    zend_string_release(member);
+#endif
+
+#if PHP_MAJOR_VERSION < 7 || (PHP_MAJOR_VERSION == 7 && PHP_MINOR_VERSION == 0)
+    EG(scope) = old_scope;
+#else
+    EG(fake_scope) = old_scope;
+#endif
+
+    layout->fields[upb_fielddef_index(field)].cache_index =
+        property_info->offset;
+    off += field_size;
+  }
+
+  // Handle oneofs now -- we iterate over oneofs specifically and allocate only
+  // one slot per oneof.
+  //
+  // We assign all value slots first, then pack the 'case' fields at the end,
+  // since in the common case (modern 64-bit platform) these are 8 bytes and 4
+  // bytes respectively and we want to avoid alignment overhead.
+  //
+  // Note that we reserve 4 bytes (a uint32) per 'case' slot because the value
+  // space for oneof cases is conceptually as wide as field tag numbers.  In
+  // practice, it's unlikely that a oneof would have more than e.g.  256 or 64K
+  // members (8 or 16 bits respectively), so conceivably we could assign
+  // consecutive case numbers and then pick a smaller oneof case slot size, but
+  // the complexity to implement this indirection is probably not worthwhile.
+  for (upb_msg_oneof_begin(&oit, msgdef); !upb_msg_oneof_done(&oit);
+       upb_msg_oneof_next(&oit)) {
+    const upb_oneofdef* oneof = upb_msg_iter_oneof(&oit);
+    upb_oneof_iter fit;
+
+    // Always allocate NATIVE_SLOT_MAX_SIZE bytes, but share the slot between
+    // all fields.
+    size_t field_size = NATIVE_SLOT_MAX_SIZE;
+    // Align the offset .
+    off = align_up_to( off, field_size);
+    // Assign all fields in the oneof this same offset.
+    const char* oneofname = upb_oneofdef_name(oneof);
+    for (upb_oneof_begin(&fit, oneof); !upb_oneof_done(&fit);
+         upb_oneof_next(&fit)) {
+      const upb_fielddef* field = upb_oneof_iter_field(&fit);
+      layout->fields[upb_fielddef_index(field)].offset = off;
+
+#if PHP_MAJOR_VERSION < 7 || (PHP_MAJOR_VERSION == 7 && PHP_MINOR_VERSION == 0)
+      zend_class_entry* old_scope = EG(scope);
+      EG(scope) = desc->klass;
+#else
+      zend_class_entry* old_scope = EG(fake_scope);
+      EG(fake_scope) = desc->klass;
+#endif
+
+#if PHP_MAJOR_VERSION < 7
+      zval member;
+      ZVAL_STRINGL(&member, oneofname, strlen(oneofname), 0);
+      zend_property_info* property_info =
+          zend_get_property_info(desc->klass, &member, true TSRMLS_CC);
+#else
+      zend_string* member = zend_string_init(oneofname, strlen(oneofname), 1);
+      zend_property_info* property_info =
+          zend_get_property_info(desc->klass, member, true);
+      zend_string_release(member);
+#endif
+
+#if PHP_MAJOR_VERSION < 7 || (PHP_MAJOR_VERSION == 7 && PHP_MINOR_VERSION == 0)
+      EG(scope) = old_scope;
+#else
+      EG(fake_scope) = old_scope;
+#endif
+
+      layout->fields[upb_fielddef_index(field)].cache_index =
+          property_info->offset;
+    }
+    i++;
+    off += field_size;
+  }
+
+  // Now the case offset.
+  for (upb_msg_oneof_begin(&oit, msgdef); !upb_msg_oneof_done(&oit);
+       upb_msg_oneof_next(&oit)) {
+    const upb_oneofdef* oneof = upb_msg_iter_oneof(&oit);
+    upb_oneof_iter fit;
+
+    size_t field_size = sizeof(uint32_t);
+    // Align the offset .
+    off = (off + field_size - 1) & ~(field_size - 1);
+    // Assign all fields in the oneof this same offset.
+    for (upb_oneof_begin(&fit, oneof); !upb_oneof_done(&fit);
+         upb_oneof_next(&fit)) {
+      const upb_fielddef* field = upb_oneof_iter_field(&fit);
+      layout->fields[upb_fielddef_index(field)].case_offset = off;
+    }
+    off += field_size;
+  }
+
+  layout->size = off;
+
+  layout->msgdef = msgdef;
+  upb_msgdef_ref(layout->msgdef, &layout->msgdef);
+
+  return layout;
+}
+
+void free_layout(MessageLayout* layout) {
+  FREE(layout->fields);
+  upb_msgdef_unref(layout->msgdef, &layout->msgdef);
+  FREE(layout);
+}
+
+void layout_init(MessageLayout* layout, void* storage,
+                 zend_object* object PHP_PROTO_TSRMLS_DC) {
+  int i;
+  upb_msg_field_iter it;
+
+  // Init unknown fields
+  memset(storage, 0, sizeof(void*));
+
+  for (upb_msg_field_begin(&it, layout->msgdef), i = 0; !upb_msg_field_done(&it);
+       upb_msg_field_next(&it), i++) {
+    const upb_fielddef* field = upb_msg_iter_field(&it);
+    void* memory = slot_memory(layout, storage, field);
+    uint32_t* oneof_case = slot_oneof_case(layout, storage, field);
+    int cache_index = slot_property_cache(layout, storage, field);
+    CACHED_VALUE* property_ptr = OBJ_PROP(object, cache_index);
+
+    if (upb_fielddef_containingoneof(field)) {
+      memset(memory, 0, NATIVE_SLOT_MAX_SIZE);
+      *oneof_case = ONEOF_CASE_NONE;
+    } else if (is_map_field(field)) {
+      zval_ptr_dtor(property_ptr);
+#if PHP_MAJOR_VERSION < 7
+      MAKE_STD_ZVAL(*property_ptr);
+#endif
+      map_field_create_with_field(map_field_type, field,
+                                  property_ptr PHP_PROTO_TSRMLS_CC);
+      DEREF(memory, CACHED_VALUE*) = property_ptr;
+    } else if (upb_fielddef_label(field) == UPB_LABEL_REPEATED) {
+      zval_ptr_dtor(property_ptr);
+#if PHP_MAJOR_VERSION < 7
+      MAKE_STD_ZVAL(*property_ptr);
+#endif
+      repeated_field_create_with_field(repeated_field_type, field,
+                                       property_ptr PHP_PROTO_TSRMLS_CC);
+      DEREF(memory, CACHED_VALUE*) = property_ptr;
+    } else {
+      native_slot_init(upb_fielddef_type(field), memory, property_ptr);
+    }
+  }
+}
+
+// For non-singular fields, the related memory needs to point to the actual
+// zval in properties table first.
+static void* value_memory(const upb_fielddef* field, void* memory) {
+  switch (upb_fielddef_type(field)) {
+    case UPB_TYPE_STRING:
+    case UPB_TYPE_BYTES:
+    case UPB_TYPE_MESSAGE:
+      memory = DEREF(memory, CACHED_VALUE*);
+      break;
+    default:
+      // No operation
+      break;
+  }
+  return memory;
+}
+
+zval* layout_get(MessageLayout* layout, const void* storage,
+                 const upb_fielddef* field, CACHED_VALUE* cache TSRMLS_DC) {
+  void* memory = slot_memory(layout, storage, field);
+  uint32_t* oneof_case = slot_oneof_case(layout, storage, field);
+
+  if (upb_fielddef_containingoneof(field)) {
+    if (*oneof_case != upb_fielddef_number(field)) {
+      native_slot_get_default(upb_fielddef_type(field), cache TSRMLS_CC);
+    } else {
+      native_slot_get(upb_fielddef_type(field), value_memory(field, memory),
+                      cache TSRMLS_CC);
+    }
+    return CACHED_PTR_TO_ZVAL_PTR(cache);
+  } else if (upb_fielddef_label(field) == UPB_LABEL_REPEATED) {
+    return CACHED_PTR_TO_ZVAL_PTR(cache);
+  } else {
+    native_slot_get(upb_fielddef_type(field), value_memory(field, memory),
+                    cache TSRMLS_CC);
+    return CACHED_PTR_TO_ZVAL_PTR(cache);
+  }
+}
+
+void layout_set(MessageLayout* layout, MessageHeader* header,
+                const upb_fielddef* field, zval* val TSRMLS_DC) {
+  void* storage = message_data(header);
+  void* memory = slot_memory(layout, storage, field);
+  uint32_t* oneof_case = slot_oneof_case(layout, storage, field);
+
+  if (upb_fielddef_containingoneof(field)) {
+    upb_fieldtype_t type = upb_fielddef_type(field);
+    zend_class_entry *ce = NULL;
+
+    // For non-singular fields, the related memory needs to point to the actual
+    // zval in properties table first.
+    switch (type) {
+      case UPB_TYPE_MESSAGE: {
+        const upb_msgdef* msg = upb_fielddef_msgsubdef(field);
+        Descriptor* desc = UNBOX_HASHTABLE_VALUE(Descriptor, get_def_obj(msg));
+        ce = desc->klass;
+        // Intentionally fall through.
+      }
+      case UPB_TYPE_STRING:
+      case UPB_TYPE_BYTES: {
+        int property_cache_index =
+            header->descriptor->layout->fields[upb_fielddef_index(field)]
+                .cache_index;
+        DEREF(memory, CACHED_VALUE*) =
+            OBJ_PROP(&header->std, property_cache_index);
+        memory = DEREF(memory, CACHED_VALUE*);
+        break;
+      }
+      default:
+        break;
+    }
+
+    native_slot_set(type, ce, memory, val TSRMLS_CC);
+    *oneof_case = upb_fielddef_number(field);
+  } else if (upb_fielddef_label(field) == UPB_LABEL_REPEATED) {
+    // Works for both repeated and map fields
+    memory = DEREF(memory, void**);
+    zval* property_ptr = CACHED_PTR_TO_ZVAL_PTR((CACHED_VALUE*)memory);
+
+    if (EXPECTED(property_ptr != val)) {
+      zend_class_entry *subce = NULL;
+      zval converted_value;
+
+      if (upb_fielddef_ismap(field)) {
+        const upb_msgdef* mapmsg = upb_fielddef_msgsubdef(field);
+        const upb_fielddef* keyfield = upb_msgdef_ntof(mapmsg, "key", 3);
+        const upb_fielddef* valuefield = upb_msgdef_ntof(mapmsg, "value", 5);
+        if (upb_fielddef_descriptortype(valuefield) ==
+            UPB_DESCRIPTOR_TYPE_MESSAGE) {
+          const upb_msgdef* submsg = upb_fielddef_msgsubdef(valuefield);
+          Descriptor* subdesc =
+              UNBOX_HASHTABLE_VALUE(Descriptor, get_def_obj(submsg));
+          subce = subdesc->klass;
+        }
+        check_map_field(subce, upb_fielddef_descriptortype(keyfield),
+                        upb_fielddef_descriptortype(valuefield), val,
+                        &converted_value);
+      } else {
+        if (upb_fielddef_type(field) == UPB_TYPE_MESSAGE) {
+          const upb_msgdef* submsg = upb_fielddef_msgsubdef(field);
+          Descriptor* subdesc =
+              UNBOX_HASHTABLE_VALUE(Descriptor, get_def_obj(submsg));
+          subce = subdesc->klass;
+        }
+
+        check_repeated_field(subce, upb_fielddef_descriptortype(field), val,
+                             &converted_value);
+      }
+#if PHP_MAJOR_VERSION < 7
+      REPLACE_ZVAL_VALUE((zval**)memory, &converted_value, 1);
+#else
+      php_proto_zval_ptr_dtor(property_ptr);
+      ZVAL_ZVAL(property_ptr, &converted_value, 1, 0);
+#endif
+      zval_dtor(&converted_value);
+    }
+  } else {
+    upb_fieldtype_t type = upb_fielddef_type(field);
+    zend_class_entry *ce = NULL;
+    if (type == UPB_TYPE_MESSAGE) {
+      const upb_msgdef* msg = upb_fielddef_msgsubdef(field);
+      Descriptor* desc = UNBOX_HASHTABLE_VALUE(Descriptor, get_def_obj(msg));
+      ce = desc->klass;
+    }
+    native_slot_set(type, ce, value_memory(field, memory), val TSRMLS_CC);
+  }
+}
+
+static void native_slot_merge(const upb_fielddef* field, const void* from_memory,
+                         void* to_memory PHP_PROTO_TSRMLS_DC) {
+  upb_fieldtype_t type = upb_fielddef_type(field);
+  zend_class_entry* ce = NULL;
+  if (!native_slot_is_default(type, from_memory)) {
+    switch (type) {
+#define CASE_TYPE(upb_type, c_type)                        \
+  case UPB_TYPE_##upb_type: {                              \
+    DEREF(to_memory, c_type) = DEREF(from_memory, c_type); \
+    break;                                                 \
+  }
+      CASE_TYPE(INT32, int32_t)
+      CASE_TYPE(UINT32, uint32_t)
+      CASE_TYPE(ENUM, int32_t)
+      CASE_TYPE(INT64, int64_t)
+      CASE_TYPE(UINT64, uint64_t)
+      CASE_TYPE(FLOAT, float)
+      CASE_TYPE(DOUBLE, double)
+      CASE_TYPE(BOOL, int8_t)
+
+#undef CASE_TYPE
+      case UPB_TYPE_STRING:
+      case UPB_TYPE_BYTES:
+        native_slot_set(type, NULL, value_memory(field, to_memory),
+                        CACHED_PTR_TO_ZVAL_PTR(DEREF(
+                            from_memory, CACHED_VALUE*)) PHP_PROTO_TSRMLS_CC);
+        break;
+      case UPB_TYPE_MESSAGE: {
+        const upb_msgdef* msg = upb_fielddef_msgsubdef(field);
+        Descriptor* desc = UNBOX_HASHTABLE_VALUE(Descriptor, get_def_obj(msg));
+        ce = desc->klass;
+        if (native_slot_is_default(type, to_memory)) {
+#if PHP_MAJOR_VERSION < 7
+          SEPARATE_ZVAL_IF_NOT_REF((zval**)value_memory(field, to_memory));
+#endif
+          CREATE_OBJ_ON_ALLOCATED_ZVAL_PTR(
+              CACHED_PTR_TO_ZVAL_PTR(DEREF(to_memory, CACHED_VALUE*)), ce);
+          MessageHeader* submsg =
+              UNBOX(MessageHeader,
+                    CACHED_PTR_TO_ZVAL_PTR(DEREF(to_memory, CACHED_VALUE*)));
+          custom_data_init(ce, submsg PHP_PROTO_TSRMLS_CC);
+        }
+
+        MessageHeader* sub_from =
+            UNBOX(MessageHeader,
+                  CACHED_PTR_TO_ZVAL_PTR(DEREF(from_memory, CACHED_VALUE*)));
+        MessageHeader* sub_to =
+            UNBOX(MessageHeader,
+                  CACHED_PTR_TO_ZVAL_PTR(DEREF(to_memory, CACHED_VALUE*)));
+
+        layout_merge(desc->layout, sub_from, sub_to PHP_PROTO_TSRMLS_CC);
+        break;
+      }
+    }
+  }
+}
+
+static void native_slot_merge_by_array(const upb_fielddef* field, const void* from_memory,
+                         void* to_memory PHP_PROTO_TSRMLS_DC) {
+  upb_fieldtype_t type = upb_fielddef_type(field);
+  switch (type) {
+    case UPB_TYPE_STRING:
+    case UPB_TYPE_BYTES: {
+#if PHP_MAJOR_VERSION < 7
+      MAKE_STD_ZVAL(DEREF(to_memory, zval*));
+      PHP_PROTO_ZVAL_STRINGL(DEREF(to_memory, zval*),
+                             Z_STRVAL_P(*(zval**)from_memory),
+                             Z_STRLEN_P(*(zval**)from_memory), 1);
+#else
+      DEREF(to_memory, zend_string*) =
+          zend_string_dup(*(zend_string**)from_memory, 0);
+#endif
+      break;
+    }
+    case UPB_TYPE_MESSAGE: {
+      const upb_msgdef* msg = upb_fielddef_msgsubdef(field);
+      Descriptor* desc = UNBOX_HASHTABLE_VALUE(Descriptor, get_def_obj(msg));
+      zend_class_entry* ce = desc->klass;
+#if PHP_MAJOR_VERSION < 7
+      MAKE_STD_ZVAL(DEREF(to_memory, zval*));
+      CREATE_OBJ_ON_ALLOCATED_ZVAL_PTR(DEREF(to_memory, zval*), ce);
+#else
+      DEREF(to_memory, zend_object*) = ce->create_object(ce TSRMLS_CC);
+#endif
+      MessageHeader* sub_from = UNBOX_HASHTABLE_VALUE(
+          MessageHeader, DEREF(from_memory, PHP_PROTO_HASHTABLE_VALUE));
+      MessageHeader* sub_to = UNBOX_HASHTABLE_VALUE(
+          MessageHeader, DEREF(to_memory, PHP_PROTO_HASHTABLE_VALUE));
+      custom_data_init(ce, sub_to PHP_PROTO_TSRMLS_CC);
+
+      layout_merge(desc->layout, sub_from, sub_to PHP_PROTO_TSRMLS_CC);
+      break;
+    }
+    default:
+      native_slot_merge(field, from_memory, to_memory PHP_PROTO_TSRMLS_CC);
+      break;
+  }
+}
+
+void layout_merge(MessageLayout* layout, MessageHeader* from,
+                  MessageHeader* to PHP_PROTO_TSRMLS_DC) {
+  int i, j;
+  upb_msg_field_iter it;
+
+  for (upb_msg_field_begin(&it, layout->msgdef), i = 0; !upb_msg_field_done(&it);
+       upb_msg_field_next(&it), i++) {
+    const upb_fielddef* field = upb_msg_iter_field(&it);
+
+    void* to_memory = slot_memory(layout, message_data(to), field);
+    void* from_memory = slot_memory(layout, message_data(from), field);
+
+    if (upb_fielddef_containingoneof(field)) {
+      uint32_t oneof_case_offset =
+          layout->fields[upb_fielddef_index(field)].case_offset;
+      // For a oneof, check that this field is actually present -- skip all the
+      // below if not.
+      if (DEREF((message_data(from) + oneof_case_offset), uint32_t) !=
+          upb_fielddef_number(field)) {
+        continue;
+      }
+      uint32_t* from_oneof_case = slot_oneof_case(layout, message_data(from), field);
+      uint32_t* to_oneof_case = slot_oneof_case(layout, message_data(to), field);
+
+      // For non-singular fields, the related memory needs to point to the
+      // actual zval in properties table first.
+      switch (upb_fielddef_type(field)) {
+        case UPB_TYPE_MESSAGE:
+        case UPB_TYPE_STRING:
+        case UPB_TYPE_BYTES: {
+          int property_cache_index =
+              layout->fields[upb_fielddef_index(field)].cache_index;
+          DEREF(to_memory, CACHED_VALUE*) =
+              OBJ_PROP(&to->std, property_cache_index);
+          break;
+        }
+        default:
+          break;
+      }
+
+      *to_oneof_case = *from_oneof_case;
+
+      // Otherwise, fall through to the appropriate singular-field handler
+      // below.
+    }
+
+    if (is_map_field(field)) {
+      int size, key_length, value_length;
+      MapIter map_it;
+
+      zval* to_map_php =
+          CACHED_PTR_TO_ZVAL_PTR(DEREF(to_memory, CACHED_VALUE*));
+      zval* from_map_php =
+          CACHED_PTR_TO_ZVAL_PTR(DEREF(from_memory, CACHED_VALUE*));
+      Map* to_map = UNBOX(Map, to_map_php);
+      Map* from_map = UNBOX(Map, from_map_php);
+
+      size = upb_strtable_count(&from_map->table);
+      if (size == 0) continue;
+
+      const upb_msgdef *mapentry_def = upb_fielddef_msgsubdef(field);
+      const upb_fielddef *value_field = upb_msgdef_itof(mapentry_def, 2);
+
+      for (map_begin(from_map_php, &map_it TSRMLS_CC); !map_done(&map_it);
+           map_next(&map_it)) {
+        const char* key = map_iter_key(&map_it, &key_length);
+        upb_value from_value = map_iter_value(&map_it, &value_length);
+        upb_value to_value;
+        void* from_mem = upb_value_memory(&from_value);
+        void* to_mem = upb_value_memory(&to_value);
+        memset(to_mem, 0, native_slot_size(to_map->value_type));
+
+        native_slot_merge_by_array(value_field, from_mem,
+                                   to_mem PHP_PROTO_TSRMLS_CC);
+
+        map_index_set(to_map, key, key_length, to_value);
+      }
+
+    } else if (upb_fielddef_label(field) == UPB_LABEL_REPEATED) {
+      zval* to_array_php = CACHED_PTR_TO_ZVAL_PTR(DEREF(to_memory, CACHED_VALUE*));
+      zval* from_array_php = CACHED_PTR_TO_ZVAL_PTR(DEREF(from_memory, CACHED_VALUE*));
+      RepeatedField* to_array = UNBOX(RepeatedField, to_array_php);
+      RepeatedField* from_array = UNBOX(RepeatedField, from_array_php);
+
+      int size = zend_hash_num_elements(PHP_PROTO_HASH_OF(from_array->array));
+      if (size > 0) {
+        for (j = 0; j < size; j++) {
+          void* from_memory = NULL;
+          void* to_memory =
+              ALLOC_N(char, native_slot_size(upb_fielddef_type(field)));
+          memset(to_memory, 0, native_slot_size(upb_fielddef_type(field)));
+
+          if (to_array->type == UPB_TYPE_MESSAGE) {
+            php_proto_zend_hash_index_find_zval(
+                PHP_PROTO_HASH_OF(from_array->array), j, (void**)&from_memory);
+#if PHP_MAJOR_VERSION >= 7
+            from_memory = &Z_OBJ_P((zval*)from_memory);
+#endif
+          } else {
+            php_proto_zend_hash_index_find_mem(
+                PHP_PROTO_HASH_OF(from_array->array), j, (void**)&from_memory);
+          }
+
+          native_slot_merge_by_array(field, from_memory,
+                                     to_memory PHP_PROTO_TSRMLS_CC);
+          repeated_field_push_native(to_array, to_memory);
+          FREE(to_memory);
+        }
+      }
+    } else {
+      native_slot_merge(field, from_memory, to_memory PHP_PROTO_TSRMLS_CC);
+    }
+  }
+}
+
+const char* layout_get_oneof_case(MessageLayout* layout, const void* storage,
+                                  const upb_oneofdef* oneof TSRMLS_DC) {
+  upb_oneof_iter i;
+  const upb_fielddef* first_field;
+
+  // Oneof is guaranteed to have at least one field. Get the first field.
+  for(upb_oneof_begin(&i, oneof); !upb_oneof_done(&i); upb_oneof_next(&i)) {
+    first_field = upb_oneof_iter_field(&i);
+    break;
+  }
+
+  uint32_t* oneof_case = slot_oneof_case(layout, storage, first_field);
+  if (*oneof_case == 0) {
+    return "";
+  }
+  const upb_fielddef* field = upb_oneofdef_itof(oneof, *oneof_case);
+  return upb_fielddef_name(field);
+}
diff --git a/php/ext/google/protobuf/type_check.c b/php/ext/google/protobuf/type_check.c
new file mode 100644
index 0000000..85f5051
--- /dev/null
+++ b/php/ext/google/protobuf/type_check.c
@@ -0,0 +1,575 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// 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.
+
+#include <Zend/zend_operators.h>
+
+#include "protobuf.h"
+#include "utf8.h"
+
+static zend_class_entry* util_type;
+static const char int64_min_digits[] = "9223372036854775808";
+
+ZEND_BEGIN_ARG_INFO_EX(arg_check_optional, 0, 0, 1)
+  ZEND_ARG_INFO(1, val)
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_INFO_EX(arg_check_message, 0, 0, 2)
+  ZEND_ARG_INFO(1, val)
+  ZEND_ARG_INFO(0, klass)
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_INFO_EX(arg_check_repeated, 0, 0, 2)
+  ZEND_ARG_INFO(1, val)
+  ZEND_ARG_INFO(0, type)
+  ZEND_ARG_INFO(0, klass)
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_INFO_EX(arg_check_map, 0, 0, 3)
+  ZEND_ARG_INFO(1, val)
+  ZEND_ARG_INFO(0, key_type)
+  ZEND_ARG_INFO(0, value_type)
+  ZEND_ARG_INFO(0, klass)
+ZEND_END_ARG_INFO()
+
+static zend_function_entry util_methods[] = {
+  PHP_ME(Util, checkInt32,  arg_check_optional, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
+  PHP_ME(Util, checkUint32, arg_check_optional, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
+  PHP_ME(Util, checkInt64,  arg_check_optional, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
+  PHP_ME(Util, checkUint64, arg_check_optional, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
+  PHP_ME(Util, checkEnum,   arg_check_optional, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
+  PHP_ME(Util, checkFloat,  arg_check_optional, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
+  PHP_ME(Util, checkDouble, arg_check_optional, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
+  PHP_ME(Util, checkBool,   arg_check_optional, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
+  PHP_ME(Util, checkString, arg_check_optional, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
+  PHP_ME(Util, checkBytes,  arg_check_optional, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
+  PHP_ME(Util, checkMessage, arg_check_message, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
+  PHP_ME(Util, checkMapField,    arg_check_map, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
+  PHP_ME(Util, checkRepeatedField, arg_check_repeated,
+         ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
+  ZEND_FE_END
+};
+
+void util_init(TSRMLS_D) {
+  zend_class_entry class_type;
+  INIT_CLASS_ENTRY(class_type, "Google\\Protobuf\\Internal\\GPBUtil",
+                   util_methods);
+  util_type = zend_register_internal_class(&class_type TSRMLS_CC);
+}
+
+// -----------------------------------------------------------------------------
+// Type checking/conversion.
+// -----------------------------------------------------------------------------
+
+// This is modified from is_numeric_string in zend_operators.h. The behavior of 
+// this function is the same as is_numeric_string, except that this takes
+// int64_t as input instead of long.
+static zend_uchar convert_numeric_string(
+    const char *str, int length, int64_t *lval, double *dval) {
+  const char *ptr;
+  int base = 10, digits = 0, dp_or_e = 0;
+  double local_dval = 0.0;
+  zend_uchar type;
+
+  if (length == 0) {
+    return IS_NULL;
+  }
+
+  while (*str == ' ' || *str == '\t' || *str == '\n' || 
+         *str == '\r' || *str == '\v' || *str == '\f') {
+    str++;
+    length--;
+  }
+  ptr = str;
+
+  if (*ptr == '-' || *ptr == '+') {
+    ptr++;
+  }
+
+  if (ZEND_IS_DIGIT(*ptr)) {
+    // Handle hex numbers
+    // str is used instead of ptr to disallow signs and keep old behavior.
+    if (length > 2 && *str == '0' && (str[1] == 'x' || str[1] == 'X')) {
+      base = 16;
+      ptr += 2;
+    }
+
+    // Skip any leading 0s.
+    while (*ptr == '0') {
+      ptr++;
+    }
+
+    // Count the number of digits. If a decimal point/exponent is found,
+    // it's a double. Otherwise, if there's a dval or no need to check for
+    // a full match, stop when there are too many digits for a int64 */
+    for (type = IS_LONG;
+        !(digits >= MAX_LENGTH_OF_INT64 && dval);
+        digits++, ptr++) {
+check_digits:
+      if (ZEND_IS_DIGIT(*ptr) || (base == 16 && ZEND_IS_XDIGIT(*ptr))) {
+        continue;
+      } else if (base == 10) {
+        if (*ptr == '.' && dp_or_e < 1) {
+          goto process_double;
+        } else if ((*ptr == 'e' || *ptr == 'E') && dp_or_e < 2) {
+          const char *e = ptr + 1;
+
+          if (*e == '-' || *e == '+') {
+            ptr = e++;
+          }
+          if (ZEND_IS_DIGIT(*e)) {
+            goto process_double;
+          }
+        }
+      }
+      break;
+    }
+
+    if (base == 10) {
+      if (digits >= MAX_LENGTH_OF_INT64) {
+        dp_or_e = -1;
+        goto process_double;
+      }
+    } else if (!(digits < SIZEOF_INT64 * 2 ||
+               (digits == SIZEOF_INT64 * 2 && ptr[-digits] <= '7'))) {
+      if (dval) {
+        local_dval = zend_hex_strtod(str, &ptr);
+      }
+      type = IS_DOUBLE;
+    }
+  } else if (*ptr == '.' && ZEND_IS_DIGIT(ptr[1])) {
+process_double:
+    type = IS_DOUBLE;
+
+    // If there's a dval, do the conversion; else continue checking
+    // the digits if we need to check for a full match.
+    if (dval) {
+      local_dval = zend_strtod(str, &ptr);
+    } else if (dp_or_e != -1) {
+      dp_or_e = (*ptr++ == '.') ? 1 : 2;
+      goto check_digits;
+    }
+  } else {
+    return IS_NULL;
+  }
+  if (ptr != str + length) {
+    zend_error(E_NOTICE, "A non well formed numeric value encountered");
+    return 0;
+  }
+
+  if (type == IS_LONG) {
+    if (digits == MAX_LENGTH_OF_INT64 - 1) {
+      int cmp = strcmp(&ptr[-digits], int64_min_digits);
+
+      if (!(cmp < 0 || (cmp == 0 && *str == '-'))) {
+        if (dval) {
+          *dval = zend_strtod(str, NULL);
+        }
+
+	return IS_DOUBLE;
+      }
+    }
+    if (lval) {
+      *lval = strtoll(str, NULL, base);
+    }
+    return IS_LONG;
+  } else {
+    if (dval) {
+      *dval = local_dval;
+    }
+    return IS_DOUBLE;
+  }
+}
+
+#define CONVERT_TO_INTEGER(type)                                             \
+  static bool convert_int64_to_##type(int64_t val, type##_t* type##_value) { \
+    *type##_value = (type##_t)val;                                           \
+    return true;                                                             \
+  }                                                                          \
+                                                                             \
+  static bool convert_double_to_##type(double val, type##_t* type##_value) { \
+    *type##_value = (type##_t)zend_dval_to_lval(val);                        \
+    return true;                                                             \
+  }                                                                          \
+                                                                             \
+  static bool convert_string_to_##type(const char* val, int len,             \
+                                       type##_t* type##_value) {             \
+    int64_t lval;                                                            \
+    double dval;                                                             \
+                                                                             \
+    switch (convert_numeric_string(val, len, &lval, &dval)) {                \
+      case IS_DOUBLE: {                                                      \
+        return convert_double_to_##type(dval, type##_value);                 \
+      }                                                                      \
+      case IS_LONG: {                                                        \
+        return convert_int64_to_##type(lval, type##_value);                  \
+      }                                                                      \
+      default:                                                               \
+        zend_error(E_USER_ERROR,                                             \
+                   "Given string value cannot be converted to integer.");    \
+        return false;                                                        \
+    }                                                                        \
+  }                                                                          \
+                                                                             \
+  bool protobuf_convert_to_##type(zval* from, type##_t* to) {                \
+    switch (Z_TYPE_P(from)) {                                                \
+      case IS_LONG: {                                                        \
+        return convert_int64_to_##type(Z_LVAL_P(from), to);                  \
+      }                                                                      \
+      case IS_DOUBLE: {                                                      \
+        return convert_double_to_##type(Z_DVAL_P(from), to);                 \
+      }                                                                      \
+      case IS_STRING: {                                                      \
+        return convert_string_to_##type(Z_STRVAL_P(from), Z_STRLEN_P(from),  \
+                                        to);                                 \
+      }                                                                      \
+      default: {                                                             \
+        zend_error(E_USER_ERROR,                                             \
+                   "Given value cannot be converted to integer.");           \
+        return false;                                                        \
+      }                                                                      \
+    }                                                                        \
+    return false;                                                            \
+  }
+
+CONVERT_TO_INTEGER(int32);
+CONVERT_TO_INTEGER(uint32);
+CONVERT_TO_INTEGER(int64);
+CONVERT_TO_INTEGER(uint64);
+
+#undef CONVERT_TO_INTEGER
+
+#define CONVERT_TO_FLOAT(type)                                              \
+  static bool convert_int64_to_##type(int64_t val, type* type##_value) {    \
+    *type##_value = (type)val;                                              \
+    return true;                                                            \
+  }                                                                         \
+                                                                            \
+  static bool convert_double_to_##type(double val, type* type##_value) {    \
+    *type##_value = (type)val;                                              \
+    return true;                                                            \
+  }                                                                         \
+                                                                            \
+  static bool convert_string_to_##type(const char* val, int len,            \
+                                       type* type##_value) {                \
+    int64_t lval;                                                           \
+    double dval;                                                            \
+                                                                            \
+    switch (convert_numeric_string(val, len, &lval, &dval)) {               \
+      case IS_DOUBLE: {                                                     \
+        *type##_value = (type)dval;                                         \
+        return true;                                                        \
+      }                                                                     \
+      case IS_LONG: {                                                       \
+        *type##_value = (type)lval;                                         \
+        return true;                                                        \
+      }                                                                     \
+      default:                                                              \
+        zend_error(E_USER_ERROR,                                            \
+                   "Given string value cannot be converted to integer.");   \
+        return false;                                                       \
+    }                                                                       \
+  }                                                                         \
+                                                                            \
+  bool protobuf_convert_to_##type(zval* from, type* to) {                   \
+    switch (Z_TYPE_P(from)) {                                               \
+      case IS_LONG: {                                                       \
+        return convert_int64_to_##type(Z_LVAL_P(from), to);                 \
+      }                                                                     \
+      case IS_DOUBLE: {                                                     \
+        return convert_double_to_##type(Z_DVAL_P(from), to);                \
+      }                                                                     \
+      case IS_STRING: {                                                     \
+        return convert_string_to_##type(Z_STRVAL_P(from), Z_STRLEN_P(from), \
+                                        to);                                \
+      }                                                                     \
+      default: {                                                            \
+        zend_error(E_USER_ERROR,                                            \
+                   "Given value cannot be converted to integer.");          \
+        return false;                                                       \
+      }                                                                     \
+    }                                                                       \
+    return false;                                                           \
+  }
+
+CONVERT_TO_FLOAT(float);
+CONVERT_TO_FLOAT(double);
+
+#undef CONVERT_TO_FLOAT
+
+bool protobuf_convert_to_bool(zval* from, int8_t* to) {
+  switch (Z_TYPE_P(from)) {
+#if PHP_MAJOR_VERSION < 7
+    case IS_BOOL:
+      *to = (int8_t)Z_BVAL_P(from);
+      break;
+#else
+    case IS_TRUE:
+      *to = 1;
+      break;
+    case IS_FALSE:
+      *to = 0;
+      break;
+#endif
+    case IS_LONG:
+      *to = (int8_t)(Z_LVAL_P(from) != 0);
+      break;
+    case IS_DOUBLE:
+      *to = (int8_t)(Z_LVAL_P(from) != 0);
+      break;
+    case IS_STRING: {
+      char* strval = Z_STRVAL_P(from);
+
+      if (Z_STRLEN_P(from) == 0 ||
+          (Z_STRLEN_P(from) == 1 && Z_STRVAL_P(from)[0] == '0')) {
+        *to = 0;
+      } else {
+        *to = 1;
+      }
+    } break;
+    default: {
+      zend_error(E_USER_ERROR, "Given value cannot be converted to bool.");
+      return false;
+    }
+  }
+  return true;
+}
+
+bool protobuf_convert_to_string(zval* from) {
+  switch (Z_TYPE_P(from)) {
+    case IS_STRING: {
+      return true;
+    }
+#if PHP_MAJOR_VERSION < 7
+    case IS_BOOL:
+#else
+    case IS_TRUE:
+    case IS_FALSE:
+#endif
+    case IS_LONG:
+    case IS_DOUBLE: {
+      zval tmp;
+      php_proto_zend_make_printable_zval(from, &tmp);
+      ZVAL_COPY_VALUE(from, &tmp);
+      return true;
+    }
+    default:
+      zend_error(E_USER_ERROR, "Given value cannot be converted to string.");
+      return false;
+  }
+}
+
+// -----------------------------------------------------------------------------
+// PHP Functions.
+// -----------------------------------------------------------------------------
+
+// The implementation of type checking for primitive fields is empty. This is
+// because type checking is done when direct assigning message fields (e.g.,
+// foo->a = 1). Functions defined here are place holders in generated code for
+// pure PHP implementation (c extension and pure PHP share the same generated
+// code).
+#define PHP_TYPE_CHECK(type) \
+  PHP_METHOD(Util, check##type) {}
+
+PHP_TYPE_CHECK(Int32)
+PHP_TYPE_CHECK(Uint32)
+PHP_TYPE_CHECK(Int64)
+PHP_TYPE_CHECK(Uint64)
+PHP_TYPE_CHECK(Enum)
+PHP_TYPE_CHECK(Float)
+PHP_TYPE_CHECK(Double)
+PHP_TYPE_CHECK(Bool)
+PHP_TYPE_CHECK(String)
+PHP_TYPE_CHECK(Bytes)
+
+#undef PHP_TYPE_CHECK
+
+PHP_METHOD(Util, checkMessage) {
+  zval* val;
+  zend_class_entry* klass = NULL;
+  if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "o!C", &val, &klass) ==
+      FAILURE) {
+    return;
+  }
+  if (val == NULL) {
+    RETURN_NULL();
+  }
+  if (!instanceof_function(Z_OBJCE_P(val), klass TSRMLS_CC)) {
+    zend_error(E_USER_ERROR, "Given value is not an instance of %s.",
+               klass->name);
+    return;
+  }
+  RETURN_ZVAL(val, 1, 0);
+}
+
+void check_repeated_field(const zend_class_entry* klass, PHP_PROTO_LONG type,
+                          zval* val, zval* return_value) {
+#if PHP_MAJOR_VERSION >= 7
+  if (Z_ISREF_P(val)) {
+    ZVAL_DEREF(val);
+  }
+#endif
+
+  TSRMLS_FETCH();
+  if (Z_TYPE_P(val) == IS_ARRAY) {
+    HashTable* table = HASH_OF(val);
+    HashPosition pointer;
+    void* memory;
+
+#if PHP_MAJOR_VERSION < 7
+    zval* repeated_field;
+    MAKE_STD_ZVAL(repeated_field);
+#else
+    zval repeated_field;
+#endif
+
+    repeated_field_create_with_type(repeated_field_type, to_fieldtype(type),
+                                    klass, &repeated_field TSRMLS_CC);
+
+    for (zend_hash_internal_pointer_reset_ex(table, &pointer);
+         php_proto_zend_hash_get_current_data_ex(table, (void**)&memory,
+                                                 &pointer) == SUCCESS;
+         zend_hash_move_forward_ex(table, &pointer)) {
+      repeated_field_handlers->write_dimension(
+          CACHED_TO_ZVAL_PTR(repeated_field), NULL,
+          CACHED_PTR_TO_ZVAL_PTR((CACHED_VALUE*)memory) TSRMLS_CC);
+    }
+
+    RETURN_ZVAL(CACHED_TO_ZVAL_PTR(repeated_field), 1, 1);
+
+  } else if (Z_TYPE_P(val) == IS_OBJECT) {
+    if (!instanceof_function(Z_OBJCE_P(val), repeated_field_type TSRMLS_CC)) {
+      zend_error(E_USER_ERROR, "Given value is not an instance of %s.",
+                 repeated_field_type->name);
+      return;
+    }
+    RepeatedField* intern = UNBOX(RepeatedField, val);
+    if (to_fieldtype(type) != intern->type) {
+      zend_error(E_USER_ERROR, "Incorrect repeated field type.");
+      return;
+    }
+    if (klass != NULL && intern->msg_ce != klass) {
+      zend_error(E_USER_ERROR,
+                 "Expect a repeated field of %s, but %s is given.", klass->name,
+                 intern->msg_ce->name);
+      return;
+    }
+    RETURN_ZVAL(val, 1, 0);
+  } else {
+    zend_error(E_USER_ERROR, "Incorrect repeated field type.");
+    return;
+  }
+}
+
+PHP_METHOD(Util, checkRepeatedField) {
+  zval* val;
+  PHP_PROTO_LONG type;
+  const zend_class_entry* klass = NULL;
+  if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "zl|C", &val, &type,
+                            &klass) == FAILURE) {
+    return;
+  }
+  RETURN_ZVAL(val, 1, 0);
+}
+
+void check_map_field(const zend_class_entry* klass, PHP_PROTO_LONG key_type,
+                     PHP_PROTO_LONG value_type, zval* val, zval* return_value) {
+#if PHP_MAJOR_VERSION >= 7
+  if (Z_ISREF_P(val)) {
+    ZVAL_DEREF(val);
+  }
+#endif
+
+  TSRMLS_FETCH();
+  if (Z_TYPE_P(val) == IS_ARRAY) {
+    HashTable* table = Z_ARRVAL_P(val);
+    HashPosition pointer;
+    zval key;
+    void* value;
+
+#if PHP_MAJOR_VERSION < 7
+    zval* map_field;
+    MAKE_STD_ZVAL(map_field);
+#else
+    zval map_field;
+#endif
+
+    map_field_create_with_type(map_field_type, to_fieldtype(key_type),
+                               to_fieldtype(value_type), klass,
+                               &map_field TSRMLS_CC);
+
+    for (zend_hash_internal_pointer_reset_ex(table, &pointer);
+         php_proto_zend_hash_get_current_data_ex(table, (void**)&value,
+                                                 &pointer) == SUCCESS;
+         zend_hash_move_forward_ex(table, &pointer)) {
+      zend_hash_get_current_key_zval_ex(table, &key, &pointer);
+      map_field_handlers->write_dimension(
+          CACHED_TO_ZVAL_PTR(map_field), &key,
+          CACHED_PTR_TO_ZVAL_PTR((CACHED_VALUE*)value) TSRMLS_CC);
+      zval_dtor(&key);
+    }
+
+    RETURN_ZVAL(CACHED_TO_ZVAL_PTR(map_field), 1, 1);
+  } else if (Z_TYPE_P(val) == IS_OBJECT) {
+    if (!instanceof_function(Z_OBJCE_P(val), map_field_type TSRMLS_CC)) {
+      zend_error(E_USER_ERROR, "Given value is not an instance of %s.",
+                 map_field_type->name);
+      return;
+    }
+    Map* intern = UNBOX(Map, val);
+    if (to_fieldtype(key_type) != intern->key_type) {
+      zend_error(E_USER_ERROR, "Incorrect map field key type.");
+      return;
+    }
+    if (to_fieldtype(value_type) != intern->value_type) {
+      zend_error(E_USER_ERROR, "Incorrect map field value type.");
+      return;
+    }
+    if (klass != NULL && intern->msg_ce != klass) {
+      zend_error(E_USER_ERROR, "Expect a map field of %s, but %s is given.",
+                 klass->name, intern->msg_ce->name);
+      return;
+    }
+    RETURN_ZVAL(val, 1, 0);
+  } else {
+    zend_error(E_USER_ERROR, "Incorrect map field type.");
+    return;
+  }
+}
+
+PHP_METHOD(Util, checkMapField) {
+  zval* val;
+  PHP_PROTO_LONG key_type, value_type;
+  const zend_class_entry* klass = NULL;
+  if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "zll|C", &val, &key_type,
+                            &value_type, &klass) == FAILURE) {
+    return;
+  }
+  RETURN_ZVAL(val, 1, 0);
+}
diff --git a/php/ext/google/protobuf/upb.c b/php/ext/google/protobuf/upb.c
new file mode 100644
index 0000000..e01f3bf
--- /dev/null
+++ b/php/ext/google/protobuf/upb.c
@@ -0,0 +1,16852 @@
+// Amalgamated source file
+#include "upb.h"
+/* This file was generated by upbc (the upb compiler) from the input
+ * file:
+ *
+ *     google/protobuf/descriptor.proto
+ *
+ * Do not edit -- your changes will be discarded when the file is
+ * regenerated. */
+
+#include <stddef.h>
+
+
+struct google_protobuf_FileDescriptorSet {
+  upb_array* file;
+};
+
+static const upb_msglayout_msginit_v1 *const google_protobuf_FileDescriptorSet_submsgs[1] = {
+  &google_protobuf_FileDescriptorProto_msginit,
+};
+
+static const upb_msglayout_fieldinit_v1 google_protobuf_FileDescriptorSet__fields[1] = {
+  {1, offsetof(google_protobuf_FileDescriptorSet, file), UPB_NO_HASBIT, UPB_NOT_IN_ONEOF, 0, 11, 3},
+};
+
+const upb_msglayout_msginit_v1 google_protobuf_FileDescriptorSet_msginit = {
+  &google_protobuf_FileDescriptorSet_submsgs[0],
+  &google_protobuf_FileDescriptorSet__fields[0],
+  NULL,
+  NULL, /* TODO. default_msg */
+  UPB_ALIGNED_SIZEOF(google_protobuf_FileDescriptorSet), 1, 0, false, true
+};
+
+google_protobuf_FileDescriptorSet *google_protobuf_FileDescriptorSet_new(upb_env *env) {
+  google_protobuf_FileDescriptorSet *msg = upb_env_malloc(env, sizeof(*msg));
+  memset(msg, 0, sizeof(*msg));  /* TODO: defaults */
+  return msg;
+}
+google_protobuf_FileDescriptorSet *google_protobuf_FileDescriptorSet_parsenew(upb_stringview buf, upb_env *env) {
+  google_protobuf_FileDescriptorSet *msg = google_protobuf_FileDescriptorSet_new(env);
+  if (upb_decode(buf, msg, &google_protobuf_FileDescriptorSet_msginit, env)) {
+    return msg;
+  } else {
+    return NULL;
+  }
+}
+char *google_protobuf_FileDescriptorSet_serialize(google_protobuf_FileDescriptorSet *msg, upb_env *env, size_t *size) {
+  return upb_encode(msg, &google_protobuf_FileDescriptorSet_msginit, env, size);
+}
+const upb_array* google_protobuf_FileDescriptorSet_file(const google_protobuf_FileDescriptorSet *msg) {
+  return msg->file;
+}
+void google_protobuf_FileDescriptorSet_set_file(google_protobuf_FileDescriptorSet *msg, upb_array* value) {
+  msg->file = value;
+}
+struct google_protobuf_FileDescriptorProto {
+  upb_stringview name;
+  upb_stringview package;
+  upb_stringview syntax;
+  google_protobuf_FileOptions* options;
+  google_protobuf_SourceCodeInfo* source_code_info;
+  upb_array* dependency;
+  upb_array* message_type;
+  upb_array* enum_type;
+  upb_array* service;
+  upb_array* extension;
+  upb_array* public_dependency;
+  upb_array* weak_dependency;
+};
+
+static const upb_msglayout_msginit_v1 *const google_protobuf_FileDescriptorProto_submsgs[6] = {
+  &google_protobuf_DescriptorProto_msginit,
+  &google_protobuf_EnumDescriptorProto_msginit,
+  &google_protobuf_FieldDescriptorProto_msginit,
+  &google_protobuf_FileOptions_msginit,
+  &google_protobuf_ServiceDescriptorProto_msginit,
+  &google_protobuf_SourceCodeInfo_msginit,
+};
+
+static const upb_msglayout_fieldinit_v1 google_protobuf_FileDescriptorProto__fields[12] = {
+  {1, offsetof(google_protobuf_FileDescriptorProto, name), 0, UPB_NOT_IN_ONEOF, UPB_NO_SUBMSG, 9, 1},
+  {2, offsetof(google_protobuf_FileDescriptorProto, package), 1, UPB_NOT_IN_ONEOF, UPB_NO_SUBMSG, 9, 1},
+  {3, offsetof(google_protobuf_FileDescriptorProto, dependency), UPB_NO_HASBIT, UPB_NOT_IN_ONEOF, UPB_NO_SUBMSG, 9, 3},
+  {4, offsetof(google_protobuf_FileDescriptorProto, message_type), UPB_NO_HASBIT, UPB_NOT_IN_ONEOF, 0, 11, 3},
+  {5, offsetof(google_protobuf_FileDescriptorProto, enum_type), UPB_NO_HASBIT, UPB_NOT_IN_ONEOF, 1, 11, 3},
+  {6, offsetof(google_protobuf_FileDescriptorProto, service), UPB_NO_HASBIT, UPB_NOT_IN_ONEOF, 4, 11, 3},
+  {7, offsetof(google_protobuf_FileDescriptorProto, extension), UPB_NO_HASBIT, UPB_NOT_IN_ONEOF, 2, 11, 3},
+  {8, offsetof(google_protobuf_FileDescriptorProto, options), 3, UPB_NOT_IN_ONEOF, 3, 11, 1},
+  {9, offsetof(google_protobuf_FileDescriptorProto, source_code_info), 4, UPB_NOT_IN_ONEOF, 5, 11, 1},
+  {10, offsetof(google_protobuf_FileDescriptorProto, public_dependency), UPB_NO_HASBIT, UPB_NOT_IN_ONEOF, UPB_NO_SUBMSG, 5, 3},
+  {11, offsetof(google_protobuf_FileDescriptorProto, weak_dependency), UPB_NO_HASBIT, UPB_NOT_IN_ONEOF, UPB_NO_SUBMSG, 5, 3},
+  {12, offsetof(google_protobuf_FileDescriptorProto, syntax), 2, UPB_NOT_IN_ONEOF, UPB_NO_SUBMSG, 9, 1},
+};
+
+const upb_msglayout_msginit_v1 google_protobuf_FileDescriptorProto_msginit = {
+  &google_protobuf_FileDescriptorProto_submsgs[0],
+  &google_protobuf_FileDescriptorProto__fields[0],
+  NULL,
+  NULL, /* TODO. default_msg */
+  UPB_ALIGNED_SIZEOF(google_protobuf_FileDescriptorProto), 12, 0, false, true
+};
+
+google_protobuf_FileDescriptorProto *google_protobuf_FileDescriptorProto_new(upb_env *env) {
+  google_protobuf_FileDescriptorProto *msg = upb_env_malloc(env, sizeof(*msg));
+  memset(msg, 0, sizeof(*msg));  /* TODO: defaults */
+  return msg;
+}
+google_protobuf_FileDescriptorProto *google_protobuf_FileDescriptorProto_parsenew(upb_stringview buf, upb_env *env) {
+  google_protobuf_FileDescriptorProto *msg = google_protobuf_FileDescriptorProto_new(env);
+  if (upb_decode(buf, msg, &google_protobuf_FileDescriptorProto_msginit, env)) {
+    return msg;
+  } else {
+    return NULL;
+  }
+}
+char *google_protobuf_FileDescriptorProto_serialize(google_protobuf_FileDescriptorProto *msg, upb_env *env, size_t *size) {
+  return upb_encode(msg, &google_protobuf_FileDescriptorProto_msginit, env, size);
+}
+upb_stringview google_protobuf_FileDescriptorProto_name(const google_protobuf_FileDescriptorProto *msg) {
+  return msg->name;
+}
+void google_protobuf_FileDescriptorProto_set_name(google_protobuf_FileDescriptorProto *msg, upb_stringview value) {
+  msg->name = value;
+}
+upb_stringview google_protobuf_FileDescriptorProto_package(const google_protobuf_FileDescriptorProto *msg) {
+  return msg->package;
+}
+void google_protobuf_FileDescriptorProto_set_package(google_protobuf_FileDescriptorProto *msg, upb_stringview value) {
+  msg->package = value;
+}
+const upb_array* google_protobuf_FileDescriptorProto_dependency(const google_protobuf_FileDescriptorProto *msg) {
+  return msg->dependency;
+}
+void google_protobuf_FileDescriptorProto_set_dependency(google_protobuf_FileDescriptorProto *msg, upb_array* value) {
+  msg->dependency = value;
+}
+const upb_array* google_protobuf_FileDescriptorProto_message_type(const google_protobuf_FileDescriptorProto *msg) {
+  return msg->message_type;
+}
+void google_protobuf_FileDescriptorProto_set_message_type(google_protobuf_FileDescriptorProto *msg, upb_array* value) {
+  msg->message_type = value;
+}
+const upb_array* google_protobuf_FileDescriptorProto_enum_type(const google_protobuf_FileDescriptorProto *msg) {
+  return msg->enum_type;
+}
+void google_protobuf_FileDescriptorProto_set_enum_type(google_protobuf_FileDescriptorProto *msg, upb_array* value) {
+  msg->enum_type = value;
+}
+const upb_array* google_protobuf_FileDescriptorProto_service(const google_protobuf_FileDescriptorProto *msg) {
+  return msg->service;
+}
+void google_protobuf_FileDescriptorProto_set_service(google_protobuf_FileDescriptorProto *msg, upb_array* value) {
+  msg->service = value;
+}
+const upb_array* google_protobuf_FileDescriptorProto_extension(const google_protobuf_FileDescriptorProto *msg) {
+  return msg->extension;
+}
+void google_protobuf_FileDescriptorProto_set_extension(google_protobuf_FileDescriptorProto *msg, upb_array* value) {
+  msg->extension = value;
+}
+const google_protobuf_FileOptions* google_protobuf_FileDescriptorProto_options(const google_protobuf_FileDescriptorProto *msg) {
+  return msg->options;
+}
+void google_protobuf_FileDescriptorProto_set_options(google_protobuf_FileDescriptorProto *msg, google_protobuf_FileOptions* value) {
+  msg->options = value;
+}
+const google_protobuf_SourceCodeInfo* google_protobuf_FileDescriptorProto_source_code_info(const google_protobuf_FileDescriptorProto *msg) {
+  return msg->source_code_info;
+}
+void google_protobuf_FileDescriptorProto_set_source_code_info(google_protobuf_FileDescriptorProto *msg, google_protobuf_SourceCodeInfo* value) {
+  msg->source_code_info = value;
+}
+const upb_array* google_protobuf_FileDescriptorProto_public_dependency(const google_protobuf_FileDescriptorProto *msg) {
+  return msg->public_dependency;
+}
+void google_protobuf_FileDescriptorProto_set_public_dependency(google_protobuf_FileDescriptorProto *msg, upb_array* value) {
+  msg->public_dependency = value;
+}
+const upb_array* google_protobuf_FileDescriptorProto_weak_dependency(const google_protobuf_FileDescriptorProto *msg) {
+  return msg->weak_dependency;
+}
+void google_protobuf_FileDescriptorProto_set_weak_dependency(google_protobuf_FileDescriptorProto *msg, upb_array* value) {
+  msg->weak_dependency = value;
+}
+upb_stringview google_protobuf_FileDescriptorProto_syntax(const google_protobuf_FileDescriptorProto *msg) {
+  return msg->syntax;
+}
+void google_protobuf_FileDescriptorProto_set_syntax(google_protobuf_FileDescriptorProto *msg, upb_stringview value) {
+  msg->syntax = value;
+}
+struct google_protobuf_DescriptorProto {
+  upb_stringview name;
+  google_protobuf_MessageOptions* options;
+  upb_array* field;
+  upb_array* nested_type;
+  upb_array* enum_type;
+  upb_array* extension_range;
+  upb_array* extension;
+  upb_array* oneof_decl;
+  upb_array* reserved_range;
+  upb_array* reserved_name;
+};
+
+static const upb_msglayout_msginit_v1 *const google_protobuf_DescriptorProto_submsgs[8] = {
+  &google_protobuf_DescriptorProto_msginit,
+  &google_protobuf_DescriptorProto_ExtensionRange_msginit,
+  &google_protobuf_DescriptorProto_ReservedRange_msginit,
+  &google_protobuf_EnumDescriptorProto_msginit,
+  &google_protobuf_FieldDescriptorProto_msginit,
+  &google_protobuf_MessageOptions_msginit,
+  &google_protobuf_OneofDescriptorProto_msginit,
+};
+
+static const upb_msglayout_fieldinit_v1 google_protobuf_DescriptorProto__fields[10] = {
+  {1, offsetof(google_protobuf_DescriptorProto, name), 0, UPB_NOT_IN_ONEOF, UPB_NO_SUBMSG, 9, 1},
+  {2, offsetof(google_protobuf_DescriptorProto, field), UPB_NO_HASBIT, UPB_NOT_IN_ONEOF, 4, 11, 3},
+  {3, offsetof(google_protobuf_DescriptorProto, nested_type), UPB_NO_HASBIT, UPB_NOT_IN_ONEOF, 0, 11, 3},
+  {4, offsetof(google_protobuf_DescriptorProto, enum_type), UPB_NO_HASBIT, UPB_NOT_IN_ONEOF, 3, 11, 3},
+  {5, offsetof(google_protobuf_DescriptorProto, extension_range), UPB_NO_HASBIT, UPB_NOT_IN_ONEOF, 1, 11, 3},
+  {6, offsetof(google_protobuf_DescriptorProto, extension), UPB_NO_HASBIT, UPB_NOT_IN_ONEOF, 4, 11, 3},
+  {7, offsetof(google_protobuf_DescriptorProto, options), 1, UPB_NOT_IN_ONEOF, 5, 11, 1},
+  {8, offsetof(google_protobuf_DescriptorProto, oneof_decl), UPB_NO_HASBIT, UPB_NOT_IN_ONEOF, 6, 11, 3},
+  {9, offsetof(google_protobuf_DescriptorProto, reserved_range), UPB_NO_HASBIT, UPB_NOT_IN_ONEOF, 2, 11, 3},
+  {10, offsetof(google_protobuf_DescriptorProto, reserved_name), UPB_NO_HASBIT, UPB_NOT_IN_ONEOF, UPB_NO_SUBMSG, 9, 3},
+};
+
+const upb_msglayout_msginit_v1 google_protobuf_DescriptorProto_msginit = {
+  &google_protobuf_DescriptorProto_submsgs[0],
+  &google_protobuf_DescriptorProto__fields[0],
+  NULL,
+  NULL, /* TODO. default_msg */
+  UPB_ALIGNED_SIZEOF(google_protobuf_DescriptorProto), 10, 0, false, true
+};
+
+google_protobuf_DescriptorProto *google_protobuf_DescriptorProto_new(upb_env *env) {
+  google_protobuf_DescriptorProto *msg = upb_env_malloc(env, sizeof(*msg));
+  memset(msg, 0, sizeof(*msg));  /* TODO: defaults */
+  return msg;
+}
+google_protobuf_DescriptorProto *google_protobuf_DescriptorProto_parsenew(upb_stringview buf, upb_env *env) {
+  google_protobuf_DescriptorProto *msg = google_protobuf_DescriptorProto_new(env);
+  if (upb_decode(buf, msg, &google_protobuf_DescriptorProto_msginit, env)) {
+    return msg;
+  } else {
+    return NULL;
+  }
+}
+char *google_protobuf_DescriptorProto_serialize(google_protobuf_DescriptorProto *msg, upb_env *env, size_t *size) {
+  return upb_encode(msg, &google_protobuf_DescriptorProto_msginit, env, size);
+}
+upb_stringview google_protobuf_DescriptorProto_name(const google_protobuf_DescriptorProto *msg) {
+  return msg->name;
+}
+void google_protobuf_DescriptorProto_set_name(google_protobuf_DescriptorProto *msg, upb_stringview value) {
+  msg->name = value;
+}
+const upb_array* google_protobuf_DescriptorProto_field(const google_protobuf_DescriptorProto *msg) {
+  return msg->field;
+}
+void google_protobuf_DescriptorProto_set_field(google_protobuf_DescriptorProto *msg, upb_array* value) {
+  msg->field = value;
+}
+const upb_array* google_protobuf_DescriptorProto_nested_type(const google_protobuf_DescriptorProto *msg) {
+  return msg->nested_type;
+}
+void google_protobuf_DescriptorProto_set_nested_type(google_protobuf_DescriptorProto *msg, upb_array* value) {
+  msg->nested_type = value;
+}
+const upb_array* google_protobuf_DescriptorProto_enum_type(const google_protobuf_DescriptorProto *msg) {
+  return msg->enum_type;
+}
+void google_protobuf_DescriptorProto_set_enum_type(google_protobuf_DescriptorProto *msg, upb_array* value) {
+  msg->enum_type = value;
+}
+const upb_array* google_protobuf_DescriptorProto_extension_range(const google_protobuf_DescriptorProto *msg) {
+  return msg->extension_range;
+}
+void google_protobuf_DescriptorProto_set_extension_range(google_protobuf_DescriptorProto *msg, upb_array* value) {
+  msg->extension_range = value;
+}
+const upb_array* google_protobuf_DescriptorProto_extension(const google_protobuf_DescriptorProto *msg) {
+  return msg->extension;
+}
+void google_protobuf_DescriptorProto_set_extension(google_protobuf_DescriptorProto *msg, upb_array* value) {
+  msg->extension = value;
+}
+const google_protobuf_MessageOptions* google_protobuf_DescriptorProto_options(const google_protobuf_DescriptorProto *msg) {
+  return msg->options;
+}
+void google_protobuf_DescriptorProto_set_options(google_protobuf_DescriptorProto *msg, google_protobuf_MessageOptions* value) {
+  msg->options = value;
+}
+const upb_array* google_protobuf_DescriptorProto_oneof_decl(const google_protobuf_DescriptorProto *msg) {
+  return msg->oneof_decl;
+}
+void google_protobuf_DescriptorProto_set_oneof_decl(google_protobuf_DescriptorProto *msg, upb_array* value) {
+  msg->oneof_decl = value;
+}
+const upb_array* google_protobuf_DescriptorProto_reserved_range(const google_protobuf_DescriptorProto *msg) {
+  return msg->reserved_range;
+}
+void google_protobuf_DescriptorProto_set_reserved_range(google_protobuf_DescriptorProto *msg, upb_array* value) {
+  msg->reserved_range = value;
+}
+const upb_array* google_protobuf_DescriptorProto_reserved_name(const google_protobuf_DescriptorProto *msg) {
+  return msg->reserved_name;
+}
+void google_protobuf_DescriptorProto_set_reserved_name(google_protobuf_DescriptorProto *msg, upb_array* value) {
+  msg->reserved_name = value;
+}
+struct google_protobuf_DescriptorProto_ExtensionRange {
+  int32_t start;
+  int32_t end;
+  google_protobuf_ExtensionRangeOptions* options;
+};
+
+static const upb_msglayout_msginit_v1 *const google_protobuf_DescriptorProto_ExtensionRange_submsgs[1] = {
+  &google_protobuf_ExtensionRangeOptions_msginit,
+};
+
+static const upb_msglayout_fieldinit_v1 google_protobuf_DescriptorProto_ExtensionRange__fields[3] = {
+  {1, offsetof(google_protobuf_DescriptorProto_ExtensionRange, start), 0, UPB_NOT_IN_ONEOF, UPB_NO_SUBMSG, 5, 1},
+  {2, offsetof(google_protobuf_DescriptorProto_ExtensionRange, end), 1, UPB_NOT_IN_ONEOF, UPB_NO_SUBMSG, 5, 1},
+  {3, offsetof(google_protobuf_DescriptorProto_ExtensionRange, options), 2, UPB_NOT_IN_ONEOF, 0, 11, 1},
+};
+
+const upb_msglayout_msginit_v1 google_protobuf_DescriptorProto_ExtensionRange_msginit = {
+  &google_protobuf_DescriptorProto_ExtensionRange_submsgs[0],
+  &google_protobuf_DescriptorProto_ExtensionRange__fields[0],
+  NULL,
+  NULL, /* TODO. default_msg */
+  UPB_ALIGNED_SIZEOF(google_protobuf_DescriptorProto_ExtensionRange), 3, 0, false, true
+};
+
+google_protobuf_DescriptorProto_ExtensionRange *google_protobuf_DescriptorProto_ExtensionRange_new(upb_env *env) {
+  google_protobuf_DescriptorProto_ExtensionRange *msg = upb_env_malloc(env, sizeof(*msg));
+  memset(msg, 0, sizeof(*msg));  /* TODO: defaults */
+  return msg;
+}
+google_protobuf_DescriptorProto_ExtensionRange *google_protobuf_DescriptorProto_ExtensionRange_parsenew(upb_stringview buf, upb_env *env) {
+  google_protobuf_DescriptorProto_ExtensionRange *msg = google_protobuf_DescriptorProto_ExtensionRange_new(env);
+  if (upb_decode(buf, msg, &google_protobuf_DescriptorProto_ExtensionRange_msginit, env)) {
+    return msg;
+  } else {
+    return NULL;
+  }
+}
+char *google_protobuf_DescriptorProto_ExtensionRange_serialize(google_protobuf_DescriptorProto_ExtensionRange *msg, upb_env *env, size_t *size) {
+  return upb_encode(msg, &google_protobuf_DescriptorProto_ExtensionRange_msginit, env, size);
+}
+int32_t google_protobuf_DescriptorProto_ExtensionRange_start(const google_protobuf_DescriptorProto_ExtensionRange *msg) {
+  return msg->start;
+}
+void google_protobuf_DescriptorProto_ExtensionRange_set_start(google_protobuf_DescriptorProto_ExtensionRange *msg, int32_t value) {
+  msg->start = value;
+}
+int32_t google_protobuf_DescriptorProto_ExtensionRange_end(const google_protobuf_DescriptorProto_ExtensionRange *msg) {
+  return msg->end;
+}
+void google_protobuf_DescriptorProto_ExtensionRange_set_end(google_protobuf_DescriptorProto_ExtensionRange *msg, int32_t value) {
+  msg->end = value;
+}
+const google_protobuf_ExtensionRangeOptions* google_protobuf_DescriptorProto_ExtensionRange_options(const google_protobuf_DescriptorProto_ExtensionRange *msg) {
+  return msg->options;
+}
+void google_protobuf_DescriptorProto_ExtensionRange_set_options(google_protobuf_DescriptorProto_ExtensionRange *msg, google_protobuf_ExtensionRangeOptions* value) {
+  msg->options = value;
+}
+struct google_protobuf_DescriptorProto_ReservedRange {
+  int32_t start;
+  int32_t end;
+};
+
+static const upb_msglayout_fieldinit_v1 google_protobuf_DescriptorProto_ReservedRange__fields[2] = {
+  {1, offsetof(google_protobuf_DescriptorProto_ReservedRange, start), 0, UPB_NOT_IN_ONEOF, UPB_NO_SUBMSG, 5, 1},
+  {2, offsetof(google_protobuf_DescriptorProto_ReservedRange, end), 1, UPB_NOT_IN_ONEOF, UPB_NO_SUBMSG, 5, 1},
+};
+
+const upb_msglayout_msginit_v1 google_protobuf_DescriptorProto_ReservedRange_msginit = {
+  NULL,
+  &google_protobuf_DescriptorProto_ReservedRange__fields[0],
+  NULL,
+  NULL, /* TODO. default_msg */
+  UPB_ALIGNED_SIZEOF(google_protobuf_DescriptorProto_ReservedRange), 2, 0, false, true
+};
+
+google_protobuf_DescriptorProto_ReservedRange *google_protobuf_DescriptorProto_ReservedRange_new(upb_env *env) {
+  google_protobuf_DescriptorProto_ReservedRange *msg = upb_env_malloc(env, sizeof(*msg));
+  memset(msg, 0, sizeof(*msg));  /* TODO: defaults */
+  return msg;
+}
+google_protobuf_DescriptorProto_ReservedRange *google_protobuf_DescriptorProto_ReservedRange_parsenew(upb_stringview buf, upb_env *env) {
+  google_protobuf_DescriptorProto_ReservedRange *msg = google_protobuf_DescriptorProto_ReservedRange_new(env);
+  if (upb_decode(buf, msg, &google_protobuf_DescriptorProto_ReservedRange_msginit, env)) {
+    return msg;
+  } else {
+    return NULL;
+  }
+}
+char *google_protobuf_DescriptorProto_ReservedRange_serialize(google_protobuf_DescriptorProto_ReservedRange *msg, upb_env *env, size_t *size) {
+  return upb_encode(msg, &google_protobuf_DescriptorProto_ReservedRange_msginit, env, size);
+}
+int32_t google_protobuf_DescriptorProto_ReservedRange_start(const google_protobuf_DescriptorProto_ReservedRange *msg) {
+  return msg->start;
+}
+void google_protobuf_DescriptorProto_ReservedRange_set_start(google_protobuf_DescriptorProto_ReservedRange *msg, int32_t value) {
+  msg->start = value;
+}
+int32_t google_protobuf_DescriptorProto_ReservedRange_end(const google_protobuf_DescriptorProto_ReservedRange *msg) {
+  return msg->end;
+}
+void google_protobuf_DescriptorProto_ReservedRange_set_end(google_protobuf_DescriptorProto_ReservedRange *msg, int32_t value) {
+  msg->end = value;
+}
+struct google_protobuf_ExtensionRangeOptions {
+  upb_array* uninterpreted_option;
+};
+
+static const upb_msglayout_msginit_v1 *const google_protobuf_ExtensionRangeOptions_submsgs[1] = {
+  &google_protobuf_UninterpretedOption_msginit,
+};
+
+static const upb_msglayout_fieldinit_v1 google_protobuf_ExtensionRangeOptions__fields[1] = {
+  {999, offsetof(google_protobuf_ExtensionRangeOptions, uninterpreted_option), UPB_NO_HASBIT, UPB_NOT_IN_ONEOF, 0, 11, 3},
+};
+
+const upb_msglayout_msginit_v1 google_protobuf_ExtensionRangeOptions_msginit = {
+  &google_protobuf_ExtensionRangeOptions_submsgs[0],
+  &google_protobuf_ExtensionRangeOptions__fields[0],
+  NULL,
+  NULL, /* TODO. default_msg */
+  UPB_ALIGNED_SIZEOF(google_protobuf_ExtensionRangeOptions), 1, 0, false, true
+};
+
+google_protobuf_ExtensionRangeOptions *google_protobuf_ExtensionRangeOptions_new(upb_env *env) {
+  google_protobuf_ExtensionRangeOptions *msg = upb_env_malloc(env, sizeof(*msg));
+  memset(msg, 0, sizeof(*msg));  /* TODO: defaults */
+  return msg;
+}
+google_protobuf_ExtensionRangeOptions *google_protobuf_ExtensionRangeOptions_parsenew(upb_stringview buf, upb_env *env) {
+  google_protobuf_ExtensionRangeOptions *msg = google_protobuf_ExtensionRangeOptions_new(env);
+  if (upb_decode(buf, msg, &google_protobuf_ExtensionRangeOptions_msginit, env)) {
+    return msg;
+  } else {
+    return NULL;
+  }
+}
+char *google_protobuf_ExtensionRangeOptions_serialize(google_protobuf_ExtensionRangeOptions *msg, upb_env *env, size_t *size) {
+  return upb_encode(msg, &google_protobuf_ExtensionRangeOptions_msginit, env, size);
+}
+const upb_array* google_protobuf_ExtensionRangeOptions_uninterpreted_option(const google_protobuf_ExtensionRangeOptions *msg) {
+  return msg->uninterpreted_option;
+}
+void google_protobuf_ExtensionRangeOptions_set_uninterpreted_option(google_protobuf_ExtensionRangeOptions *msg, upb_array* value) {
+  msg->uninterpreted_option = value;
+}
+struct google_protobuf_FieldDescriptorProto {
+  google_protobuf_FieldDescriptorProto_Label label;
+  google_protobuf_FieldDescriptorProto_Type type;
+  int32_t number;
+  int32_t oneof_index;
+  upb_stringview name;
+  upb_stringview extendee;
+  upb_stringview type_name;
+  upb_stringview default_value;
+  upb_stringview json_name;
+  google_protobuf_FieldOptions* options;
+};
+
+static const upb_msglayout_msginit_v1 *const google_protobuf_FieldDescriptorProto_submsgs[1] = {
+  &google_protobuf_FieldOptions_msginit,
+};
+
+static const upb_msglayout_fieldinit_v1 google_protobuf_FieldDescriptorProto__fields[10] = {
+  {1, offsetof(google_protobuf_FieldDescriptorProto, name), 4, UPB_NOT_IN_ONEOF, UPB_NO_SUBMSG, 9, 1},
+  {2, offsetof(google_protobuf_FieldDescriptorProto, extendee), 5, UPB_NOT_IN_ONEOF, UPB_NO_SUBMSG, 9, 1},
+  {3, offsetof(google_protobuf_FieldDescriptorProto, number), 2, UPB_NOT_IN_ONEOF, UPB_NO_SUBMSG, 5, 1},
+  {4, offsetof(google_protobuf_FieldDescriptorProto, label), 0, UPB_NOT_IN_ONEOF, UPB_NO_SUBMSG, 14, 1},
+  {5, offsetof(google_protobuf_FieldDescriptorProto, type), 1, UPB_NOT_IN_ONEOF, UPB_NO_SUBMSG, 14, 1},
+  {6, offsetof(google_protobuf_FieldDescriptorProto, type_name), 6, UPB_NOT_IN_ONEOF, UPB_NO_SUBMSG, 9, 1},
+  {7, offsetof(google_protobuf_FieldDescriptorProto, default_value), 7, UPB_NOT_IN_ONEOF, UPB_NO_SUBMSG, 9, 1},
+  {8, offsetof(google_protobuf_FieldDescriptorProto, options), 9, UPB_NOT_IN_ONEOF, 0, 11, 1},
+  {9, offsetof(google_protobuf_FieldDescriptorProto, oneof_index), 3, UPB_NOT_IN_ONEOF, UPB_NO_SUBMSG, 5, 1},
+  {10, offsetof(google_protobuf_FieldDescriptorProto, json_name), 8, UPB_NOT_IN_ONEOF, UPB_NO_SUBMSG, 9, 1},
+};
+
+const upb_msglayout_msginit_v1 google_protobuf_FieldDescriptorProto_msginit = {
+  &google_protobuf_FieldDescriptorProto_submsgs[0],
+  &google_protobuf_FieldDescriptorProto__fields[0],
+  NULL,
+  NULL, /* TODO. default_msg */
+  UPB_ALIGNED_SIZEOF(google_protobuf_FieldDescriptorProto), 10, 0, false, true
+};
+
+google_protobuf_FieldDescriptorProto *google_protobuf_FieldDescriptorProto_new(upb_env *env) {
+  google_protobuf_FieldDescriptorProto *msg = upb_env_malloc(env, sizeof(*msg));
+  memset(msg, 0, sizeof(*msg));  /* TODO: defaults */
+  return msg;
+}
+google_protobuf_FieldDescriptorProto *google_protobuf_FieldDescriptorProto_parsenew(upb_stringview buf, upb_env *env) {
+  google_protobuf_FieldDescriptorProto *msg = google_protobuf_FieldDescriptorProto_new(env);
+  if (upb_decode(buf, msg, &google_protobuf_FieldDescriptorProto_msginit, env)) {
+    return msg;
+  } else {
+    return NULL;
+  }
+}
+char *google_protobuf_FieldDescriptorProto_serialize(google_protobuf_FieldDescriptorProto *msg, upb_env *env, size_t *size) {
+  return upb_encode(msg, &google_protobuf_FieldDescriptorProto_msginit, env, size);
+}
+upb_stringview google_protobuf_FieldDescriptorProto_name(const google_protobuf_FieldDescriptorProto *msg) {
+  return msg->name;
+}
+void google_protobuf_FieldDescriptorProto_set_name(google_protobuf_FieldDescriptorProto *msg, upb_stringview value) {
+  msg->name = value;
+}
+upb_stringview google_protobuf_FieldDescriptorProto_extendee(const google_protobuf_FieldDescriptorProto *msg) {
+  return msg->extendee;
+}
+void google_protobuf_FieldDescriptorProto_set_extendee(google_protobuf_FieldDescriptorProto *msg, upb_stringview value) {
+  msg->extendee = value;
+}
+int32_t google_protobuf_FieldDescriptorProto_number(const google_protobuf_FieldDescriptorProto *msg) {
+  return msg->number;
+}
+void google_protobuf_FieldDescriptorProto_set_number(google_protobuf_FieldDescriptorProto *msg, int32_t value) {
+  msg->number = value;
+}
+google_protobuf_FieldDescriptorProto_Label google_protobuf_FieldDescriptorProto_label(const google_protobuf_FieldDescriptorProto *msg) {
+  return msg->label;
+}
+void google_protobuf_FieldDescriptorProto_set_label(google_protobuf_FieldDescriptorProto *msg, google_protobuf_FieldDescriptorProto_Label value) {
+  msg->label = value;
+}
+google_protobuf_FieldDescriptorProto_Type google_protobuf_FieldDescriptorProto_type(const google_protobuf_FieldDescriptorProto *msg) {
+  return msg->type;
+}
+void google_protobuf_FieldDescriptorProto_set_type(google_protobuf_FieldDescriptorProto *msg, google_protobuf_FieldDescriptorProto_Type value) {
+  msg->type = value;
+}
+upb_stringview google_protobuf_FieldDescriptorProto_type_name(const google_protobuf_FieldDescriptorProto *msg) {
+  return msg->type_name;
+}
+void google_protobuf_FieldDescriptorProto_set_type_name(google_protobuf_FieldDescriptorProto *msg, upb_stringview value) {
+  msg->type_name = value;
+}
+upb_stringview google_protobuf_FieldDescriptorProto_default_value(const google_protobuf_FieldDescriptorProto *msg) {
+  return msg->default_value;
+}
+void google_protobuf_FieldDescriptorProto_set_default_value(google_protobuf_FieldDescriptorProto *msg, upb_stringview value) {
+  msg->default_value = value;
+}
+const google_protobuf_FieldOptions* google_protobuf_FieldDescriptorProto_options(const google_protobuf_FieldDescriptorProto *msg) {
+  return msg->options;
+}
+void google_protobuf_FieldDescriptorProto_set_options(google_protobuf_FieldDescriptorProto *msg, google_protobuf_FieldOptions* value) {
+  msg->options = value;
+}
+int32_t google_protobuf_FieldDescriptorProto_oneof_index(const google_protobuf_FieldDescriptorProto *msg) {
+  return msg->oneof_index;
+}
+void google_protobuf_FieldDescriptorProto_set_oneof_index(google_protobuf_FieldDescriptorProto *msg, int32_t value) {
+  msg->oneof_index = value;
+}
+upb_stringview google_protobuf_FieldDescriptorProto_json_name(const google_protobuf_FieldDescriptorProto *msg) {
+  return msg->json_name;
+}
+void google_protobuf_FieldDescriptorProto_set_json_name(google_protobuf_FieldDescriptorProto *msg, upb_stringview value) {
+  msg->json_name = value;
+}
+struct google_protobuf_OneofDescriptorProto {
+  upb_stringview name;
+  google_protobuf_OneofOptions* options;
+};
+
+static const upb_msglayout_msginit_v1 *const google_protobuf_OneofDescriptorProto_submsgs[1] = {
+  &google_protobuf_OneofOptions_msginit,
+};
+
+static const upb_msglayout_fieldinit_v1 google_protobuf_OneofDescriptorProto__fields[2] = {
+  {1, offsetof(google_protobuf_OneofDescriptorProto, name), 0, UPB_NOT_IN_ONEOF, UPB_NO_SUBMSG, 9, 1},
+  {2, offsetof(google_protobuf_OneofDescriptorProto, options), 1, UPB_NOT_IN_ONEOF, 0, 11, 1},
+};
+
+const upb_msglayout_msginit_v1 google_protobuf_OneofDescriptorProto_msginit = {
+  &google_protobuf_OneofDescriptorProto_submsgs[0],
+  &google_protobuf_OneofDescriptorProto__fields[0],
+  NULL,
+  NULL, /* TODO. default_msg */
+  UPB_ALIGNED_SIZEOF(google_protobuf_OneofDescriptorProto), 2, 0, false, true
+};
+
+google_protobuf_OneofDescriptorProto *google_protobuf_OneofDescriptorProto_new(upb_env *env) {
+  google_protobuf_OneofDescriptorProto *msg = upb_env_malloc(env, sizeof(*msg));
+  memset(msg, 0, sizeof(*msg));  /* TODO: defaults */
+  return msg;
+}
+google_protobuf_OneofDescriptorProto *google_protobuf_OneofDescriptorProto_parsenew(upb_stringview buf, upb_env *env) {
+  google_protobuf_OneofDescriptorProto *msg = google_protobuf_OneofDescriptorProto_new(env);
+  if (upb_decode(buf, msg, &google_protobuf_OneofDescriptorProto_msginit, env)) {
+    return msg;
+  } else {
+    return NULL;
+  }
+}
+char *google_protobuf_OneofDescriptorProto_serialize(google_protobuf_OneofDescriptorProto *msg, upb_env *env, size_t *size) {
+  return upb_encode(msg, &google_protobuf_OneofDescriptorProto_msginit, env, size);
+}
+upb_stringview google_protobuf_OneofDescriptorProto_name(const google_protobuf_OneofDescriptorProto *msg) {
+  return msg->name;
+}
+void google_protobuf_OneofDescriptorProto_set_name(google_protobuf_OneofDescriptorProto *msg, upb_stringview value) {
+  msg->name = value;
+}
+const google_protobuf_OneofOptions* google_protobuf_OneofDescriptorProto_options(const google_protobuf_OneofDescriptorProto *msg) {
+  return msg->options;
+}
+void google_protobuf_OneofDescriptorProto_set_options(google_protobuf_OneofDescriptorProto *msg, google_protobuf_OneofOptions* value) {
+  msg->options = value;
+}
+struct google_protobuf_EnumDescriptorProto {
+  upb_stringview name;
+  google_protobuf_EnumOptions* options;
+  upb_array* value;
+  upb_array* reserved_range;
+  upb_array* reserved_name;
+};
+
+static const upb_msglayout_msginit_v1 *const google_protobuf_EnumDescriptorProto_submsgs[3] = {
+  &google_protobuf_EnumDescriptorProto_EnumReservedRange_msginit,
+  &google_protobuf_EnumOptions_msginit,
+  &google_protobuf_EnumValueDescriptorProto_msginit,
+};
+
+static const upb_msglayout_fieldinit_v1 google_protobuf_EnumDescriptorProto__fields[5] = {
+  {1, offsetof(google_protobuf_EnumDescriptorProto, name), 0, UPB_NOT_IN_ONEOF, UPB_NO_SUBMSG, 9, 1},
+  {2, offsetof(google_protobuf_EnumDescriptorProto, value), UPB_NO_HASBIT, UPB_NOT_IN_ONEOF, 2, 11, 3},
+  {3, offsetof(google_protobuf_EnumDescriptorProto, options), 1, UPB_NOT_IN_ONEOF, 1, 11, 1},
+  {4, offsetof(google_protobuf_EnumDescriptorProto, reserved_range), UPB_NO_HASBIT, UPB_NOT_IN_ONEOF, 0, 11, 3},
+  {5, offsetof(google_protobuf_EnumDescriptorProto, reserved_name), UPB_NO_HASBIT, UPB_NOT_IN_ONEOF, UPB_NO_SUBMSG, 9, 3},
+};
+
+const upb_msglayout_msginit_v1 google_protobuf_EnumDescriptorProto_msginit = {
+  &google_protobuf_EnumDescriptorProto_submsgs[0],
+  &google_protobuf_EnumDescriptorProto__fields[0],
+  NULL,
+  NULL, /* TODO. default_msg */
+  UPB_ALIGNED_SIZEOF(google_protobuf_EnumDescriptorProto), 5, 0, false, true
+};
+
+google_protobuf_EnumDescriptorProto *google_protobuf_EnumDescriptorProto_new(upb_env *env) {
+  google_protobuf_EnumDescriptorProto *msg = upb_env_malloc(env, sizeof(*msg));
+  memset(msg, 0, sizeof(*msg));  /* TODO: defaults */
+  return msg;
+}
+google_protobuf_EnumDescriptorProto *google_protobuf_EnumDescriptorProto_parsenew(upb_stringview buf, upb_env *env) {
+  google_protobuf_EnumDescriptorProto *msg = google_protobuf_EnumDescriptorProto_new(env);
+  if (upb_decode(buf, msg, &google_protobuf_EnumDescriptorProto_msginit, env)) {
+    return msg;
+  } else {
+    return NULL;
+  }
+}
+char *google_protobuf_EnumDescriptorProto_serialize(google_protobuf_EnumDescriptorProto *msg, upb_env *env, size_t *size) {
+  return upb_encode(msg, &google_protobuf_EnumDescriptorProto_msginit, env, size);
+}
+upb_stringview google_protobuf_EnumDescriptorProto_name(const google_protobuf_EnumDescriptorProto *msg) {
+  return msg->name;
+}
+void google_protobuf_EnumDescriptorProto_set_name(google_protobuf_EnumDescriptorProto *msg, upb_stringview value) {
+  msg->name = value;
+}
+const upb_array* google_protobuf_EnumDescriptorProto_value(const google_protobuf_EnumDescriptorProto *msg) {
+  return msg->value;
+}
+void google_protobuf_EnumDescriptorProto_set_value(google_protobuf_EnumDescriptorProto *msg, upb_array* value) {
+  msg->value = value;
+}
+const google_protobuf_EnumOptions* google_protobuf_EnumDescriptorProto_options(const google_protobuf_EnumDescriptorProto *msg) {
+  return msg->options;
+}
+void google_protobuf_EnumDescriptorProto_set_options(google_protobuf_EnumDescriptorProto *msg, google_protobuf_EnumOptions* value) {
+  msg->options = value;
+}
+const upb_array* google_protobuf_EnumDescriptorProto_reserved_range(const google_protobuf_EnumDescriptorProto *msg) {
+  return msg->reserved_range;
+}
+void google_protobuf_EnumDescriptorProto_set_reserved_range(google_protobuf_EnumDescriptorProto *msg, upb_array* value) {
+  msg->reserved_range = value;
+}
+const upb_array* google_protobuf_EnumDescriptorProto_reserved_name(const google_protobuf_EnumDescriptorProto *msg) {
+  return msg->reserved_name;
+}
+void google_protobuf_EnumDescriptorProto_set_reserved_name(google_protobuf_EnumDescriptorProto *msg, upb_array* value) {
+  msg->reserved_name = value;
+}
+struct google_protobuf_EnumDescriptorProto_EnumReservedRange {
+  int32_t start;
+  int32_t end;
+};
+
+static const upb_msglayout_fieldinit_v1 google_protobuf_EnumDescriptorProto_EnumReservedRange__fields[2] = {
+  {1, offsetof(google_protobuf_EnumDescriptorProto_EnumReservedRange, start), 0, UPB_NOT_IN_ONEOF, UPB_NO_SUBMSG, 5, 1},
+  {2, offsetof(google_protobuf_EnumDescriptorProto_EnumReservedRange, end), 1, UPB_NOT_IN_ONEOF, UPB_NO_SUBMSG, 5, 1},
+};
+
+const upb_msglayout_msginit_v1 google_protobuf_EnumDescriptorProto_EnumReservedRange_msginit = {
+  NULL,
+  &google_protobuf_EnumDescriptorProto_EnumReservedRange__fields[0],
+  NULL,
+  NULL, /* TODO. default_msg */
+  UPB_ALIGNED_SIZEOF(google_protobuf_EnumDescriptorProto_EnumReservedRange), 2, 0, false, true
+};
+
+google_protobuf_EnumDescriptorProto_EnumReservedRange *google_protobuf_EnumDescriptorProto_EnumReservedRange_new(upb_env *env) {
+  google_protobuf_EnumDescriptorProto_EnumReservedRange *msg = upb_env_malloc(env, sizeof(*msg));
+  memset(msg, 0, sizeof(*msg));  /* TODO: defaults */
+  return msg;
+}
+google_protobuf_EnumDescriptorProto_EnumReservedRange *google_protobuf_EnumDescriptorProto_EnumReservedRange_parsenew(upb_stringview buf, upb_env *env) {
+  google_protobuf_EnumDescriptorProto_EnumReservedRange *msg = google_protobuf_EnumDescriptorProto_EnumReservedRange_new(env);
+  if (upb_decode(buf, msg, &google_protobuf_EnumDescriptorProto_EnumReservedRange_msginit, env)) {
+    return msg;
+  } else {
+    return NULL;
+  }
+}
+char *google_protobuf_EnumDescriptorProto_EnumReservedRange_serialize(google_protobuf_EnumDescriptorProto_EnumReservedRange *msg, upb_env *env, size_t *size) {
+  return upb_encode(msg, &google_protobuf_EnumDescriptorProto_EnumReservedRange_msginit, env, size);
+}
+int32_t google_protobuf_EnumDescriptorProto_EnumReservedRange_start(const google_protobuf_EnumDescriptorProto_EnumReservedRange *msg) {
+  return msg->start;
+}
+void google_protobuf_EnumDescriptorProto_EnumReservedRange_set_start(google_protobuf_EnumDescriptorProto_EnumReservedRange *msg, int32_t value) {
+  msg->start = value;
+}
+int32_t google_protobuf_EnumDescriptorProto_EnumReservedRange_end(const google_protobuf_EnumDescriptorProto_EnumReservedRange *msg) {
+  return msg->end;
+}
+void google_protobuf_EnumDescriptorProto_EnumReservedRange_set_end(google_protobuf_EnumDescriptorProto_EnumReservedRange *msg, int32_t value) {
+  msg->end = value;
+}
+struct google_protobuf_EnumValueDescriptorProto {
+  int32_t number;
+  upb_stringview name;
+  google_protobuf_EnumValueOptions* options;
+};
+
+static const upb_msglayout_msginit_v1 *const google_protobuf_EnumValueDescriptorProto_submsgs[1] = {
+  &google_protobuf_EnumValueOptions_msginit,
+};
+
+static const upb_msglayout_fieldinit_v1 google_protobuf_EnumValueDescriptorProto__fields[3] = {
+  {1, offsetof(google_protobuf_EnumValueDescriptorProto, name), 1, UPB_NOT_IN_ONEOF, UPB_NO_SUBMSG, 9, 1},
+  {2, offsetof(google_protobuf_EnumValueDescriptorProto, number), 0, UPB_NOT_IN_ONEOF, UPB_NO_SUBMSG, 5, 1},
+  {3, offsetof(google_protobuf_EnumValueDescriptorProto, options), 2, UPB_NOT_IN_ONEOF, 0, 11, 1},
+};
+
+const upb_msglayout_msginit_v1 google_protobuf_EnumValueDescriptorProto_msginit = {
+  &google_protobuf_EnumValueDescriptorProto_submsgs[0],
+  &google_protobuf_EnumValueDescriptorProto__fields[0],
+  NULL,
+  NULL, /* TODO. default_msg */
+  UPB_ALIGNED_SIZEOF(google_protobuf_EnumValueDescriptorProto), 3, 0, false, true
+};
+
+google_protobuf_EnumValueDescriptorProto *google_protobuf_EnumValueDescriptorProto_new(upb_env *env) {
+  google_protobuf_EnumValueDescriptorProto *msg = upb_env_malloc(env, sizeof(*msg));
+  memset(msg, 0, sizeof(*msg));  /* TODO: defaults */
+  return msg;
+}
+google_protobuf_EnumValueDescriptorProto *google_protobuf_EnumValueDescriptorProto_parsenew(upb_stringview buf, upb_env *env) {
+  google_protobuf_EnumValueDescriptorProto *msg = google_protobuf_EnumValueDescriptorProto_new(env);
+  if (upb_decode(buf, msg, &google_protobuf_EnumValueDescriptorProto_msginit, env)) {
+    return msg;
+  } else {
+    return NULL;
+  }
+}
+char *google_protobuf_EnumValueDescriptorProto_serialize(google_protobuf_EnumValueDescriptorProto *msg, upb_env *env, size_t *size) {
+  return upb_encode(msg, &google_protobuf_EnumValueDescriptorProto_msginit, env, size);
+}
+upb_stringview google_protobuf_EnumValueDescriptorProto_name(const google_protobuf_EnumValueDescriptorProto *msg) {
+  return msg->name;
+}
+void google_protobuf_EnumValueDescriptorProto_set_name(google_protobuf_EnumValueDescriptorProto *msg, upb_stringview value) {
+  msg->name = value;
+}
+int32_t google_protobuf_EnumValueDescriptorProto_number(const google_protobuf_EnumValueDescriptorProto *msg) {
+  return msg->number;
+}
+void google_protobuf_EnumValueDescriptorProto_set_number(google_protobuf_EnumValueDescriptorProto *msg, int32_t value) {
+  msg->number = value;
+}
+const google_protobuf_EnumValueOptions* google_protobuf_EnumValueDescriptorProto_options(const google_protobuf_EnumValueDescriptorProto *msg) {
+  return msg->options;
+}
+void google_protobuf_EnumValueDescriptorProto_set_options(google_protobuf_EnumValueDescriptorProto *msg, google_protobuf_EnumValueOptions* value) {
+  msg->options = value;
+}
+struct google_protobuf_ServiceDescriptorProto {
+  upb_stringview name;
+  google_protobuf_ServiceOptions* options;
+  upb_array* method;
+};
+
+static const upb_msglayout_msginit_v1 *const google_protobuf_ServiceDescriptorProto_submsgs[2] = {
+  &google_protobuf_MethodDescriptorProto_msginit,
+  &google_protobuf_ServiceOptions_msginit,
+};
+
+static const upb_msglayout_fieldinit_v1 google_protobuf_ServiceDescriptorProto__fields[3] = {
+  {1, offsetof(google_protobuf_ServiceDescriptorProto, name), 0, UPB_NOT_IN_ONEOF, UPB_NO_SUBMSG, 9, 1},
+  {2, offsetof(google_protobuf_ServiceDescriptorProto, method), UPB_NO_HASBIT, UPB_NOT_IN_ONEOF, 0, 11, 3},
+  {3, offsetof(google_protobuf_ServiceDescriptorProto, options), 1, UPB_NOT_IN_ONEOF, 1, 11, 1},
+};
+
+const upb_msglayout_msginit_v1 google_protobuf_ServiceDescriptorProto_msginit = {
+  &google_protobuf_ServiceDescriptorProto_submsgs[0],
+  &google_protobuf_ServiceDescriptorProto__fields[0],
+  NULL,
+  NULL, /* TODO. default_msg */
+  UPB_ALIGNED_SIZEOF(google_protobuf_ServiceDescriptorProto), 3, 0, false, true
+};
+
+google_protobuf_ServiceDescriptorProto *google_protobuf_ServiceDescriptorProto_new(upb_env *env) {
+  google_protobuf_ServiceDescriptorProto *msg = upb_env_malloc(env, sizeof(*msg));
+  memset(msg, 0, sizeof(*msg));  /* TODO: defaults */
+  return msg;
+}
+google_protobuf_ServiceDescriptorProto *google_protobuf_ServiceDescriptorProto_parsenew(upb_stringview buf, upb_env *env) {
+  google_protobuf_ServiceDescriptorProto *msg = google_protobuf_ServiceDescriptorProto_new(env);
+  if (upb_decode(buf, msg, &google_protobuf_ServiceDescriptorProto_msginit, env)) {
+    return msg;
+  } else {
+    return NULL;
+  }
+}
+char *google_protobuf_ServiceDescriptorProto_serialize(google_protobuf_ServiceDescriptorProto *msg, upb_env *env, size_t *size) {
+  return upb_encode(msg, &google_protobuf_ServiceDescriptorProto_msginit, env, size);
+}
+upb_stringview google_protobuf_ServiceDescriptorProto_name(const google_protobuf_ServiceDescriptorProto *msg) {
+  return msg->name;
+}
+void google_protobuf_ServiceDescriptorProto_set_name(google_protobuf_ServiceDescriptorProto *msg, upb_stringview value) {
+  msg->name = value;
+}
+const upb_array* google_protobuf_ServiceDescriptorProto_method(const google_protobuf_ServiceDescriptorProto *msg) {
+  return msg->method;
+}
+void google_protobuf_ServiceDescriptorProto_set_method(google_protobuf_ServiceDescriptorProto *msg, upb_array* value) {
+  msg->method = value;
+}
+const google_protobuf_ServiceOptions* google_protobuf_ServiceDescriptorProto_options(const google_protobuf_ServiceDescriptorProto *msg) {
+  return msg->options;
+}
+void google_protobuf_ServiceDescriptorProto_set_options(google_protobuf_ServiceDescriptorProto *msg, google_protobuf_ServiceOptions* value) {
+  msg->options = value;
+}
+struct google_protobuf_MethodDescriptorProto {
+  bool client_streaming;
+  bool server_streaming;
+  upb_stringview name;
+  upb_stringview input_type;
+  upb_stringview output_type;
+  google_protobuf_MethodOptions* options;
+};
+
+static const upb_msglayout_msginit_v1 *const google_protobuf_MethodDescriptorProto_submsgs[1] = {
+  &google_protobuf_MethodOptions_msginit,
+};
+
+static const upb_msglayout_fieldinit_v1 google_protobuf_MethodDescriptorProto__fields[6] = {
+  {1, offsetof(google_protobuf_MethodDescriptorProto, name), 2, UPB_NOT_IN_ONEOF, UPB_NO_SUBMSG, 9, 1},
+  {2, offsetof(google_protobuf_MethodDescriptorProto, input_type), 3, UPB_NOT_IN_ONEOF, UPB_NO_SUBMSG, 9, 1},
+  {3, offsetof(google_protobuf_MethodDescriptorProto, output_type), 4, UPB_NOT_IN_ONEOF, UPB_NO_SUBMSG, 9, 1},
+  {4, offsetof(google_protobuf_MethodDescriptorProto, options), 5, UPB_NOT_IN_ONEOF, 0, 11, 1},
+  {5, offsetof(google_protobuf_MethodDescriptorProto, client_streaming), 0, UPB_NOT_IN_ONEOF, UPB_NO_SUBMSG, 8, 1},
+  {6, offsetof(google_protobuf_MethodDescriptorProto, server_streaming), 1, UPB_NOT_IN_ONEOF, UPB_NO_SUBMSG, 8, 1},
+};
+
+const upb_msglayout_msginit_v1 google_protobuf_MethodDescriptorProto_msginit = {
+  &google_protobuf_MethodDescriptorProto_submsgs[0],
+  &google_protobuf_MethodDescriptorProto__fields[0],
+  NULL,
+  NULL, /* TODO. default_msg */
+  UPB_ALIGNED_SIZEOF(google_protobuf_MethodDescriptorProto), 6, 0, false, true
+};
+
+google_protobuf_MethodDescriptorProto *google_protobuf_MethodDescriptorProto_new(upb_env *env) {
+  google_protobuf_MethodDescriptorProto *msg = upb_env_malloc(env, sizeof(*msg));
+  memset(msg, 0, sizeof(*msg));  /* TODO: defaults */
+  return msg;
+}
+google_protobuf_MethodDescriptorProto *google_protobuf_MethodDescriptorProto_parsenew(upb_stringview buf, upb_env *env) {
+  google_protobuf_MethodDescriptorProto *msg = google_protobuf_MethodDescriptorProto_new(env);
+  if (upb_decode(buf, msg, &google_protobuf_MethodDescriptorProto_msginit, env)) {
+    return msg;
+  } else {
+    return NULL;
+  }
+}
+char *google_protobuf_MethodDescriptorProto_serialize(google_protobuf_MethodDescriptorProto *msg, upb_env *env, size_t *size) {
+  return upb_encode(msg, &google_protobuf_MethodDescriptorProto_msginit, env, size);
+}
+upb_stringview google_protobuf_MethodDescriptorProto_name(const google_protobuf_MethodDescriptorProto *msg) {
+  return msg->name;
+}
+void google_protobuf_MethodDescriptorProto_set_name(google_protobuf_MethodDescriptorProto *msg, upb_stringview value) {
+  msg->name = value;
+}
+upb_stringview google_protobuf_MethodDescriptorProto_input_type(const google_protobuf_MethodDescriptorProto *msg) {
+  return msg->input_type;
+}
+void google_protobuf_MethodDescriptorProto_set_input_type(google_protobuf_MethodDescriptorProto *msg, upb_stringview value) {
+  msg->input_type = value;
+}
+upb_stringview google_protobuf_MethodDescriptorProto_output_type(const google_protobuf_MethodDescriptorProto *msg) {
+  return msg->output_type;
+}
+void google_protobuf_MethodDescriptorProto_set_output_type(google_protobuf_MethodDescriptorProto *msg, upb_stringview value) {
+  msg->output_type = value;
+}
+const google_protobuf_MethodOptions* google_protobuf_MethodDescriptorProto_options(const google_protobuf_MethodDescriptorProto *msg) {
+  return msg->options;
+}
+void google_protobuf_MethodDescriptorProto_set_options(google_protobuf_MethodDescriptorProto *msg, google_protobuf_MethodOptions* value) {
+  msg->options = value;
+}
+bool google_protobuf_MethodDescriptorProto_client_streaming(const google_protobuf_MethodDescriptorProto *msg) {
+  return msg->client_streaming;
+}
+void google_protobuf_MethodDescriptorProto_set_client_streaming(google_protobuf_MethodDescriptorProto *msg, bool value) {
+  msg->client_streaming = value;
+}
+bool google_protobuf_MethodDescriptorProto_server_streaming(const google_protobuf_MethodDescriptorProto *msg) {
+  return msg->server_streaming;
+}
+void google_protobuf_MethodDescriptorProto_set_server_streaming(google_protobuf_MethodDescriptorProto *msg, bool value) {
+  msg->server_streaming = value;
+}
+struct google_protobuf_FileOptions {
+  google_protobuf_FileOptions_OptimizeMode optimize_for;
+  bool java_multiple_files;
+  bool cc_generic_services;
+  bool java_generic_services;
+  bool py_generic_services;
+  bool java_generate_equals_and_hash;
+  bool deprecated;
+  bool java_string_check_utf8;
+  bool cc_enable_arenas;
+  bool php_generic_services;
+  upb_stringview java_package;
+  upb_stringview java_outer_classname;
+  upb_stringview go_package;
+  upb_stringview objc_class_prefix;
+  upb_stringview csharp_namespace;
+  upb_stringview swift_prefix;
+  upb_stringview php_class_prefix;
+  upb_stringview php_namespace;
+  upb_array* uninterpreted_option;
+};
+
+static const upb_msglayout_msginit_v1 *const google_protobuf_FileOptions_submsgs[1] = {
+  &google_protobuf_UninterpretedOption_msginit,
+};
+
+static const upb_msglayout_fieldinit_v1 google_protobuf_FileOptions__fields[19] = {
+  {1, offsetof(google_protobuf_FileOptions, java_package), 10, UPB_NOT_IN_ONEOF, UPB_NO_SUBMSG, 9, 1},
+  {8, offsetof(google_protobuf_FileOptions, java_outer_classname), 11, UPB_NOT_IN_ONEOF, UPB_NO_SUBMSG, 9, 1},
+  {9, offsetof(google_protobuf_FileOptions, optimize_for), 0, UPB_NOT_IN_ONEOF, UPB_NO_SUBMSG, 14, 1},
+  {10, offsetof(google_protobuf_FileOptions, java_multiple_files), 1, UPB_NOT_IN_ONEOF, UPB_NO_SUBMSG, 8, 1},
+  {11, offsetof(google_protobuf_FileOptions, go_package), 12, UPB_NOT_IN_ONEOF, UPB_NO_SUBMSG, 9, 1},
+  {16, offsetof(google_protobuf_FileOptions, cc_generic_services), 2, UPB_NOT_IN_ONEOF, UPB_NO_SUBMSG, 8, 1},
+  {17, offsetof(google_protobuf_FileOptions, java_generic_services), 3, UPB_NOT_IN_ONEOF, UPB_NO_SUBMSG, 8, 1},
+  {18, offsetof(google_protobuf_FileOptions, py_generic_services), 4, UPB_NOT_IN_ONEOF, UPB_NO_SUBMSG, 8, 1},
+  {20, offsetof(google_protobuf_FileOptions, java_generate_equals_and_hash), 5, UPB_NOT_IN_ONEOF, UPB_NO_SUBMSG, 8, 1},
+  {23, offsetof(google_protobuf_FileOptions, deprecated), 6, UPB_NOT_IN_ONEOF, UPB_NO_SUBMSG, 8, 1},
+  {27, offsetof(google_protobuf_FileOptions, java_string_check_utf8), 7, UPB_NOT_IN_ONEOF, UPB_NO_SUBMSG, 8, 1},
+  {31, offsetof(google_protobuf_FileOptions, cc_enable_arenas), 8, UPB_NOT_IN_ONEOF, UPB_NO_SUBMSG, 8, 1},
+  {36, offsetof(google_protobuf_FileOptions, objc_class_prefix), 13, UPB_NOT_IN_ONEOF, UPB_NO_SUBMSG, 9, 1},
+  {37, offsetof(google_protobuf_FileOptions, csharp_namespace), 14, UPB_NOT_IN_ONEOF, UPB_NO_SUBMSG, 9, 1},
+  {39, offsetof(google_protobuf_FileOptions, swift_prefix), 15, UPB_NOT_IN_ONEOF, UPB_NO_SUBMSG, 9, 1},
+  {40, offsetof(google_protobuf_FileOptions, php_class_prefix), 16, UPB_NOT_IN_ONEOF, UPB_NO_SUBMSG, 9, 1},
+  {41, offsetof(google_protobuf_FileOptions, php_namespace), 17, UPB_NOT_IN_ONEOF, UPB_NO_SUBMSG, 9, 1},
+  {42, offsetof(google_protobuf_FileOptions, php_generic_services), 9, UPB_NOT_IN_ONEOF, UPB_NO_SUBMSG, 8, 1},
+  {999, offsetof(google_protobuf_FileOptions, uninterpreted_option), UPB_NO_HASBIT, UPB_NOT_IN_ONEOF, 0, 11, 3},
+};
+
+const upb_msglayout_msginit_v1 google_protobuf_FileOptions_msginit = {
+  &google_protobuf_FileOptions_submsgs[0],
+  &google_protobuf_FileOptions__fields[0],
+  NULL,
+  NULL, /* TODO. default_msg */
+  UPB_ALIGNED_SIZEOF(google_protobuf_FileOptions), 19, 0, false, true
+};
+
+google_protobuf_FileOptions *google_protobuf_FileOptions_new(upb_env *env) {
+  google_protobuf_FileOptions *msg = upb_env_malloc(env, sizeof(*msg));
+  memset(msg, 0, sizeof(*msg));  /* TODO: defaults */
+  return msg;
+}
+google_protobuf_FileOptions *google_protobuf_FileOptions_parsenew(upb_stringview buf, upb_env *env) {
+  google_protobuf_FileOptions *msg = google_protobuf_FileOptions_new(env);
+  if (upb_decode(buf, msg, &google_protobuf_FileOptions_msginit, env)) {
+    return msg;
+  } else {
+    return NULL;
+  }
+}
+char *google_protobuf_FileOptions_serialize(google_protobuf_FileOptions *msg, upb_env *env, size_t *size) {
+  return upb_encode(msg, &google_protobuf_FileOptions_msginit, env, size);
+}
+upb_stringview google_protobuf_FileOptions_java_package(const google_protobuf_FileOptions *msg) {
+  return msg->java_package;
+}
+void google_protobuf_FileOptions_set_java_package(google_protobuf_FileOptions *msg, upb_stringview value) {
+  msg->java_package = value;
+}
+upb_stringview google_protobuf_FileOptions_java_outer_classname(const google_protobuf_FileOptions *msg) {
+  return msg->java_outer_classname;
+}
+void google_protobuf_FileOptions_set_java_outer_classname(google_protobuf_FileOptions *msg, upb_stringview value) {
+  msg->java_outer_classname = value;
+}
+google_protobuf_FileOptions_OptimizeMode google_protobuf_FileOptions_optimize_for(const google_protobuf_FileOptions *msg) {
+  return msg->optimize_for;
+}
+void google_protobuf_FileOptions_set_optimize_for(google_protobuf_FileOptions *msg, google_protobuf_FileOptions_OptimizeMode value) {
+  msg->optimize_for = value;
+}
+bool google_protobuf_FileOptions_java_multiple_files(const google_protobuf_FileOptions *msg) {
+  return msg->java_multiple_files;
+}
+void google_protobuf_FileOptions_set_java_multiple_files(google_protobuf_FileOptions *msg, bool value) {
+  msg->java_multiple_files = value;
+}
+upb_stringview google_protobuf_FileOptions_go_package(const google_protobuf_FileOptions *msg) {
+  return msg->go_package;
+}
+void google_protobuf_FileOptions_set_go_package(google_protobuf_FileOptions *msg, upb_stringview value) {
+  msg->go_package = value;
+}
+bool google_protobuf_FileOptions_cc_generic_services(const google_protobuf_FileOptions *msg) {
+  return msg->cc_generic_services;
+}
+void google_protobuf_FileOptions_set_cc_generic_services(google_protobuf_FileOptions *msg, bool value) {
+  msg->cc_generic_services = value;
+}
+bool google_protobuf_FileOptions_java_generic_services(const google_protobuf_FileOptions *msg) {
+  return msg->java_generic_services;
+}
+void google_protobuf_FileOptions_set_java_generic_services(google_protobuf_FileOptions *msg, bool value) {
+  msg->java_generic_services = value;
+}
+bool google_protobuf_FileOptions_py_generic_services(const google_protobuf_FileOptions *msg) {
+  return msg->py_generic_services;
+}
+void google_protobuf_FileOptions_set_py_generic_services(google_protobuf_FileOptions *msg, bool value) {
+  msg->py_generic_services = value;
+}
+bool google_protobuf_FileOptions_java_generate_equals_and_hash(const google_protobuf_FileOptions *msg) {
+  return msg->java_generate_equals_and_hash;
+}
+void google_protobuf_FileOptions_set_java_generate_equals_and_hash(google_protobuf_FileOptions *msg, bool value) {
+  msg->java_generate_equals_and_hash = value;
+}
+bool google_protobuf_FileOptions_deprecated(const google_protobuf_FileOptions *msg) {
+  return msg->deprecated;
+}
+void google_protobuf_FileOptions_set_deprecated(google_protobuf_FileOptions *msg, bool value) {
+  msg->deprecated = value;
+}
+bool google_protobuf_FileOptions_java_string_check_utf8(const google_protobuf_FileOptions *msg) {
+  return msg->java_string_check_utf8;
+}
+void google_protobuf_FileOptions_set_java_string_check_utf8(google_protobuf_FileOptions *msg, bool value) {
+  msg->java_string_check_utf8 = value;
+}
+bool google_protobuf_FileOptions_cc_enable_arenas(const google_protobuf_FileOptions *msg) {
+  return msg->cc_enable_arenas;
+}
+void google_protobuf_FileOptions_set_cc_enable_arenas(google_protobuf_FileOptions *msg, bool value) {
+  msg->cc_enable_arenas = value;
+}
+upb_stringview google_protobuf_FileOptions_objc_class_prefix(const google_protobuf_FileOptions *msg) {
+  return msg->objc_class_prefix;
+}
+void google_protobuf_FileOptions_set_objc_class_prefix(google_protobuf_FileOptions *msg, upb_stringview value) {
+  msg->objc_class_prefix = value;
+}
+upb_stringview google_protobuf_FileOptions_csharp_namespace(const google_protobuf_FileOptions *msg) {
+  return msg->csharp_namespace;
+}
+void google_protobuf_FileOptions_set_csharp_namespace(google_protobuf_FileOptions *msg, upb_stringview value) {
+  msg->csharp_namespace = value;
+}
+upb_stringview google_protobuf_FileOptions_swift_prefix(const google_protobuf_FileOptions *msg) {
+  return msg->swift_prefix;
+}
+void google_protobuf_FileOptions_set_swift_prefix(google_protobuf_FileOptions *msg, upb_stringview value) {
+  msg->swift_prefix = value;
+}
+upb_stringview google_protobuf_FileOptions_php_class_prefix(const google_protobuf_FileOptions *msg) {
+  return msg->php_class_prefix;
+}
+void google_protobuf_FileOptions_set_php_class_prefix(google_protobuf_FileOptions *msg, upb_stringview value) {
+  msg->php_class_prefix = value;
+}
+upb_stringview google_protobuf_FileOptions_php_namespace(const google_protobuf_FileOptions *msg) {
+  return msg->php_namespace;
+}
+void google_protobuf_FileOptions_set_php_namespace(google_protobuf_FileOptions *msg, upb_stringview value) {
+  msg->php_namespace = value;
+}
+bool google_protobuf_FileOptions_php_generic_services(const google_protobuf_FileOptions *msg) {
+  return msg->php_generic_services;
+}
+void google_protobuf_FileOptions_set_php_generic_services(google_protobuf_FileOptions *msg, bool value) {
+  msg->php_generic_services = value;
+}
+const upb_array* google_protobuf_FileOptions_uninterpreted_option(const google_protobuf_FileOptions *msg) {
+  return msg->uninterpreted_option;
+}
+void google_protobuf_FileOptions_set_uninterpreted_option(google_protobuf_FileOptions *msg, upb_array* value) {
+  msg->uninterpreted_option = value;
+}
+struct google_protobuf_MessageOptions {
+  bool message_set_wire_format;
+  bool no_standard_descriptor_accessor;
+  bool deprecated;
+  bool map_entry;
+  upb_array* uninterpreted_option;
+};
+
+static const upb_msglayout_msginit_v1 *const google_protobuf_MessageOptions_submsgs[1] = {
+  &google_protobuf_UninterpretedOption_msginit,
+};
+
+static const upb_msglayout_fieldinit_v1 google_protobuf_MessageOptions__fields[5] = {
+  {1, offsetof(google_protobuf_MessageOptions, message_set_wire_format), 0, UPB_NOT_IN_ONEOF, UPB_NO_SUBMSG, 8, 1},
+  {2, offsetof(google_protobuf_MessageOptions, no_standard_descriptor_accessor), 1, UPB_NOT_IN_ONEOF, UPB_NO_SUBMSG, 8, 1},
+  {3, offsetof(google_protobuf_MessageOptions, deprecated), 2, UPB_NOT_IN_ONEOF, UPB_NO_SUBMSG, 8, 1},
+  {7, offsetof(google_protobuf_MessageOptions, map_entry), 3, UPB_NOT_IN_ONEOF, UPB_NO_SUBMSG, 8, 1},
+  {999, offsetof(google_protobuf_MessageOptions, uninterpreted_option), UPB_NO_HASBIT, UPB_NOT_IN_ONEOF, 0, 11, 3},
+};
+
+const upb_msglayout_msginit_v1 google_protobuf_MessageOptions_msginit = {
+  &google_protobuf_MessageOptions_submsgs[0],
+  &google_protobuf_MessageOptions__fields[0],
+  NULL,
+  NULL, /* TODO. default_msg */
+  UPB_ALIGNED_SIZEOF(google_protobuf_MessageOptions), 5, 0, false, true
+};
+
+google_protobuf_MessageOptions *google_protobuf_MessageOptions_new(upb_env *env) {
+  google_protobuf_MessageOptions *msg = upb_env_malloc(env, sizeof(*msg));
+  memset(msg, 0, sizeof(*msg));  /* TODO: defaults */
+  return msg;
+}
+google_protobuf_MessageOptions *google_protobuf_MessageOptions_parsenew(upb_stringview buf, upb_env *env) {
+  google_protobuf_MessageOptions *msg = google_protobuf_MessageOptions_new(env);
+  if (upb_decode(buf, msg, &google_protobuf_MessageOptions_msginit, env)) {
+    return msg;
+  } else {
+    return NULL;
+  }
+}
+char *google_protobuf_MessageOptions_serialize(google_protobuf_MessageOptions *msg, upb_env *env, size_t *size) {
+  return upb_encode(msg, &google_protobuf_MessageOptions_msginit, env, size);
+}
+bool google_protobuf_MessageOptions_message_set_wire_format(const google_protobuf_MessageOptions *msg) {
+  return msg->message_set_wire_format;
+}
+void google_protobuf_MessageOptions_set_message_set_wire_format(google_protobuf_MessageOptions *msg, bool value) {
+  msg->message_set_wire_format = value;
+}
+bool google_protobuf_MessageOptions_no_standard_descriptor_accessor(const google_protobuf_MessageOptions *msg) {
+  return msg->no_standard_descriptor_accessor;
+}
+void google_protobuf_MessageOptions_set_no_standard_descriptor_accessor(google_protobuf_MessageOptions *msg, bool value) {
+  msg->no_standard_descriptor_accessor = value;
+}
+bool google_protobuf_MessageOptions_deprecated(const google_protobuf_MessageOptions *msg) {
+  return msg->deprecated;
+}
+void google_protobuf_MessageOptions_set_deprecated(google_protobuf_MessageOptions *msg, bool value) {
+  msg->deprecated = value;
+}
+bool google_protobuf_MessageOptions_map_entry(const google_protobuf_MessageOptions *msg) {
+  return msg->map_entry;
+}
+void google_protobuf_MessageOptions_set_map_entry(google_protobuf_MessageOptions *msg, bool value) {
+  msg->map_entry = value;
+}
+const upb_array* google_protobuf_MessageOptions_uninterpreted_option(const google_protobuf_MessageOptions *msg) {
+  return msg->uninterpreted_option;
+}
+void google_protobuf_MessageOptions_set_uninterpreted_option(google_protobuf_MessageOptions *msg, upb_array* value) {
+  msg->uninterpreted_option = value;
+}
+struct google_protobuf_FieldOptions {
+  google_protobuf_FieldOptions_CType ctype;
+  google_protobuf_FieldOptions_JSType jstype;
+  bool packed;
+  bool deprecated;
+  bool lazy;
+  bool weak;
+  upb_array* uninterpreted_option;
+};
+
+static const upb_msglayout_msginit_v1 *const google_protobuf_FieldOptions_submsgs[1] = {
+  &google_protobuf_UninterpretedOption_msginit,
+};
+
+static const upb_msglayout_fieldinit_v1 google_protobuf_FieldOptions__fields[7] = {
+  {1, offsetof(google_protobuf_FieldOptions, ctype), 0, UPB_NOT_IN_ONEOF, UPB_NO_SUBMSG, 14, 1},
+  {2, offsetof(google_protobuf_FieldOptions, packed), 2, UPB_NOT_IN_ONEOF, UPB_NO_SUBMSG, 8, 1},
+  {3, offsetof(google_protobuf_FieldOptions, deprecated), 3, UPB_NOT_IN_ONEOF, UPB_NO_SUBMSG, 8, 1},
+  {5, offsetof(google_protobuf_FieldOptions, lazy), 4, UPB_NOT_IN_ONEOF, UPB_NO_SUBMSG, 8, 1},
+  {6, offsetof(google_protobuf_FieldOptions, jstype), 1, UPB_NOT_IN_ONEOF, UPB_NO_SUBMSG, 14, 1},
+  {10, offsetof(google_protobuf_FieldOptions, weak), 5, UPB_NOT_IN_ONEOF, UPB_NO_SUBMSG, 8, 1},
+  {999, offsetof(google_protobuf_FieldOptions, uninterpreted_option), UPB_NO_HASBIT, UPB_NOT_IN_ONEOF, 0, 11, 3},
+};
+
+const upb_msglayout_msginit_v1 google_protobuf_FieldOptions_msginit = {
+  &google_protobuf_FieldOptions_submsgs[0],
+  &google_protobuf_FieldOptions__fields[0],
+  NULL,
+  NULL, /* TODO. default_msg */
+  UPB_ALIGNED_SIZEOF(google_protobuf_FieldOptions), 7, 0, false, true
+};
+
+google_protobuf_FieldOptions *google_protobuf_FieldOptions_new(upb_env *env) {
+  google_protobuf_FieldOptions *msg = upb_env_malloc(env, sizeof(*msg));
+  memset(msg, 0, sizeof(*msg));  /* TODO: defaults */
+  return msg;
+}
+google_protobuf_FieldOptions *google_protobuf_FieldOptions_parsenew(upb_stringview buf, upb_env *env) {
+  google_protobuf_FieldOptions *msg = google_protobuf_FieldOptions_new(env);
+  if (upb_decode(buf, msg, &google_protobuf_FieldOptions_msginit, env)) {
+    return msg;
+  } else {
+    return NULL;
+  }
+}
+char *google_protobuf_FieldOptions_serialize(google_protobuf_FieldOptions *msg, upb_env *env, size_t *size) {
+  return upb_encode(msg, &google_protobuf_FieldOptions_msginit, env, size);
+}
+google_protobuf_FieldOptions_CType google_protobuf_FieldOptions_ctype(const google_protobuf_FieldOptions *msg) {
+  return msg->ctype;
+}
+void google_protobuf_FieldOptions_set_ctype(google_protobuf_FieldOptions *msg, google_protobuf_FieldOptions_CType value) {
+  msg->ctype = value;
+}
+bool google_protobuf_FieldOptions_packed(const google_protobuf_FieldOptions *msg) {
+  return msg->packed;
+}
+void google_protobuf_FieldOptions_set_packed(google_protobuf_FieldOptions *msg, bool value) {
+  msg->packed = value;
+}
+bool google_protobuf_FieldOptions_deprecated(const google_protobuf_FieldOptions *msg) {
+  return msg->deprecated;
+}
+void google_protobuf_FieldOptions_set_deprecated(google_protobuf_FieldOptions *msg, bool value) {
+  msg->deprecated = value;
+}
+bool google_protobuf_FieldOptions_lazy(const google_protobuf_FieldOptions *msg) {
+  return msg->lazy;
+}
+void google_protobuf_FieldOptions_set_lazy(google_protobuf_FieldOptions *msg, bool value) {
+  msg->lazy = value;
+}
+google_protobuf_FieldOptions_JSType google_protobuf_FieldOptions_jstype(const google_protobuf_FieldOptions *msg) {
+  return msg->jstype;
+}
+void google_protobuf_FieldOptions_set_jstype(google_protobuf_FieldOptions *msg, google_protobuf_FieldOptions_JSType value) {
+  msg->jstype = value;
+}
+bool google_protobuf_FieldOptions_weak(const google_protobuf_FieldOptions *msg) {
+  return msg->weak;
+}
+void google_protobuf_FieldOptions_set_weak(google_protobuf_FieldOptions *msg, bool value) {
+  msg->weak = value;
+}
+const upb_array* google_protobuf_FieldOptions_uninterpreted_option(const google_protobuf_FieldOptions *msg) {
+  return msg->uninterpreted_option;
+}
+void google_protobuf_FieldOptions_set_uninterpreted_option(google_protobuf_FieldOptions *msg, upb_array* value) {
+  msg->uninterpreted_option = value;
+}
+struct google_protobuf_OneofOptions {
+  upb_array* uninterpreted_option;
+};
+
+static const upb_msglayout_msginit_v1 *const google_protobuf_OneofOptions_submsgs[1] = {
+  &google_protobuf_UninterpretedOption_msginit,
+};
+
+static const upb_msglayout_fieldinit_v1 google_protobuf_OneofOptions__fields[1] = {
+  {999, offsetof(google_protobuf_OneofOptions, uninterpreted_option), UPB_NO_HASBIT, UPB_NOT_IN_ONEOF, 0, 11, 3},
+};
+
+const upb_msglayout_msginit_v1 google_protobuf_OneofOptions_msginit = {
+  &google_protobuf_OneofOptions_submsgs[0],
+  &google_protobuf_OneofOptions__fields[0],
+  NULL,
+  NULL, /* TODO. default_msg */
+  UPB_ALIGNED_SIZEOF(google_protobuf_OneofOptions), 1, 0, false, true
+};
+
+google_protobuf_OneofOptions *google_protobuf_OneofOptions_new(upb_env *env) {
+  google_protobuf_OneofOptions *msg = upb_env_malloc(env, sizeof(*msg));
+  memset(msg, 0, sizeof(*msg));  /* TODO: defaults */
+  return msg;
+}
+google_protobuf_OneofOptions *google_protobuf_OneofOptions_parsenew(upb_stringview buf, upb_env *env) {
+  google_protobuf_OneofOptions *msg = google_protobuf_OneofOptions_new(env);
+  if (upb_decode(buf, msg, &google_protobuf_OneofOptions_msginit, env)) {
+    return msg;
+  } else {
+    return NULL;
+  }
+}
+char *google_protobuf_OneofOptions_serialize(google_protobuf_OneofOptions *msg, upb_env *env, size_t *size) {
+  return upb_encode(msg, &google_protobuf_OneofOptions_msginit, env, size);
+}
+const upb_array* google_protobuf_OneofOptions_uninterpreted_option(const google_protobuf_OneofOptions *msg) {
+  return msg->uninterpreted_option;
+}
+void google_protobuf_OneofOptions_set_uninterpreted_option(google_protobuf_OneofOptions *msg, upb_array* value) {
+  msg->uninterpreted_option = value;
+}
+struct google_protobuf_EnumOptions {
+  bool allow_alias;
+  bool deprecated;
+  upb_array* uninterpreted_option;
+};
+
+static const upb_msglayout_msginit_v1 *const google_protobuf_EnumOptions_submsgs[1] = {
+  &google_protobuf_UninterpretedOption_msginit,
+};
+
+static const upb_msglayout_fieldinit_v1 google_protobuf_EnumOptions__fields[3] = {
+  {2, offsetof(google_protobuf_EnumOptions, allow_alias), 0, UPB_NOT_IN_ONEOF, UPB_NO_SUBMSG, 8, 1},
+  {3, offsetof(google_protobuf_EnumOptions, deprecated), 1, UPB_NOT_IN_ONEOF, UPB_NO_SUBMSG, 8, 1},
+  {999, offsetof(google_protobuf_EnumOptions, uninterpreted_option), UPB_NO_HASBIT, UPB_NOT_IN_ONEOF, 0, 11, 3},
+};
+
+const upb_msglayout_msginit_v1 google_protobuf_EnumOptions_msginit = {
+  &google_protobuf_EnumOptions_submsgs[0],
+  &google_protobuf_EnumOptions__fields[0],
+  NULL,
+  NULL, /* TODO. default_msg */
+  UPB_ALIGNED_SIZEOF(google_protobuf_EnumOptions), 3, 0, false, true
+};
+
+google_protobuf_EnumOptions *google_protobuf_EnumOptions_new(upb_env *env) {
+  google_protobuf_EnumOptions *msg = upb_env_malloc(env, sizeof(*msg));
+  memset(msg, 0, sizeof(*msg));  /* TODO: defaults */
+  return msg;
+}
+google_protobuf_EnumOptions *google_protobuf_EnumOptions_parsenew(upb_stringview buf, upb_env *env) {
+  google_protobuf_EnumOptions *msg = google_protobuf_EnumOptions_new(env);
+  if (upb_decode(buf, msg, &google_protobuf_EnumOptions_msginit, env)) {
+    return msg;
+  } else {
+    return NULL;
+  }
+}
+char *google_protobuf_EnumOptions_serialize(google_protobuf_EnumOptions *msg, upb_env *env, size_t *size) {
+  return upb_encode(msg, &google_protobuf_EnumOptions_msginit, env, size);
+}
+bool google_protobuf_EnumOptions_allow_alias(const google_protobuf_EnumOptions *msg) {
+  return msg->allow_alias;
+}
+void google_protobuf_EnumOptions_set_allow_alias(google_protobuf_EnumOptions *msg, bool value) {
+  msg->allow_alias = value;
+}
+bool google_protobuf_EnumOptions_deprecated(const google_protobuf_EnumOptions *msg) {
+  return msg->deprecated;
+}
+void google_protobuf_EnumOptions_set_deprecated(google_protobuf_EnumOptions *msg, bool value) {
+  msg->deprecated = value;
+}
+const upb_array* google_protobuf_EnumOptions_uninterpreted_option(const google_protobuf_EnumOptions *msg) {
+  return msg->uninterpreted_option;
+}
+void google_protobuf_EnumOptions_set_uninterpreted_option(google_protobuf_EnumOptions *msg, upb_array* value) {
+  msg->uninterpreted_option = value;
+}
+struct google_protobuf_EnumValueOptions {
+  bool deprecated;
+  upb_array* uninterpreted_option;
+};
+
+static const upb_msglayout_msginit_v1 *const google_protobuf_EnumValueOptions_submsgs[1] = {
+  &google_protobuf_UninterpretedOption_msginit,
+};
+
+static const upb_msglayout_fieldinit_v1 google_protobuf_EnumValueOptions__fields[2] = {
+  {1, offsetof(google_protobuf_EnumValueOptions, deprecated), 0, UPB_NOT_IN_ONEOF, UPB_NO_SUBMSG, 8, 1},
+  {999, offsetof(google_protobuf_EnumValueOptions, uninterpreted_option), UPB_NO_HASBIT, UPB_NOT_IN_ONEOF, 0, 11, 3},
+};
+
+const upb_msglayout_msginit_v1 google_protobuf_EnumValueOptions_msginit = {
+  &google_protobuf_EnumValueOptions_submsgs[0],
+  &google_protobuf_EnumValueOptions__fields[0],
+  NULL,
+  NULL, /* TODO. default_msg */
+  UPB_ALIGNED_SIZEOF(google_protobuf_EnumValueOptions), 2, 0, false, true
+};
+
+google_protobuf_EnumValueOptions *google_protobuf_EnumValueOptions_new(upb_env *env) {
+  google_protobuf_EnumValueOptions *msg = upb_env_malloc(env, sizeof(*msg));
+  memset(msg, 0, sizeof(*msg));  /* TODO: defaults */
+  return msg;
+}
+google_protobuf_EnumValueOptions *google_protobuf_EnumValueOptions_parsenew(upb_stringview buf, upb_env *env) {
+  google_protobuf_EnumValueOptions *msg = google_protobuf_EnumValueOptions_new(env);
+  if (upb_decode(buf, msg, &google_protobuf_EnumValueOptions_msginit, env)) {
+    return msg;
+  } else {
+    return NULL;
+  }
+}
+char *google_protobuf_EnumValueOptions_serialize(google_protobuf_EnumValueOptions *msg, upb_env *env, size_t *size) {
+  return upb_encode(msg, &google_protobuf_EnumValueOptions_msginit, env, size);
+}
+bool google_protobuf_EnumValueOptions_deprecated(const google_protobuf_EnumValueOptions *msg) {
+  return msg->deprecated;
+}
+void google_protobuf_EnumValueOptions_set_deprecated(google_protobuf_EnumValueOptions *msg, bool value) {
+  msg->deprecated = value;
+}
+const upb_array* google_protobuf_EnumValueOptions_uninterpreted_option(const google_protobuf_EnumValueOptions *msg) {
+  return msg->uninterpreted_option;
+}
+void google_protobuf_EnumValueOptions_set_uninterpreted_option(google_protobuf_EnumValueOptions *msg, upb_array* value) {
+  msg->uninterpreted_option = value;
+}
+struct google_protobuf_ServiceOptions {
+  bool deprecated;
+  upb_array* uninterpreted_option;
+};
+
+static const upb_msglayout_msginit_v1 *const google_protobuf_ServiceOptions_submsgs[1] = {
+  &google_protobuf_UninterpretedOption_msginit,
+};
+
+static const upb_msglayout_fieldinit_v1 google_protobuf_ServiceOptions__fields[2] = {
+  {33, offsetof(google_protobuf_ServiceOptions, deprecated), 0, UPB_NOT_IN_ONEOF, UPB_NO_SUBMSG, 8, 1},
+  {999, offsetof(google_protobuf_ServiceOptions, uninterpreted_option), UPB_NO_HASBIT, UPB_NOT_IN_ONEOF, 0, 11, 3},
+};
+
+const upb_msglayout_msginit_v1 google_protobuf_ServiceOptions_msginit = {
+  &google_protobuf_ServiceOptions_submsgs[0],
+  &google_protobuf_ServiceOptions__fields[0],
+  NULL,
+  NULL, /* TODO. default_msg */
+  UPB_ALIGNED_SIZEOF(google_protobuf_ServiceOptions), 2, 0, false, true
+};
+
+google_protobuf_ServiceOptions *google_protobuf_ServiceOptions_new(upb_env *env) {
+  google_protobuf_ServiceOptions *msg = upb_env_malloc(env, sizeof(*msg));
+  memset(msg, 0, sizeof(*msg));  /* TODO: defaults */
+  return msg;
+}
+google_protobuf_ServiceOptions *google_protobuf_ServiceOptions_parsenew(upb_stringview buf, upb_env *env) {
+  google_protobuf_ServiceOptions *msg = google_protobuf_ServiceOptions_new(env);
+  if (upb_decode(buf, msg, &google_protobuf_ServiceOptions_msginit, env)) {
+    return msg;
+  } else {
+    return NULL;
+  }
+}
+char *google_protobuf_ServiceOptions_serialize(google_protobuf_ServiceOptions *msg, upb_env *env, size_t *size) {
+  return upb_encode(msg, &google_protobuf_ServiceOptions_msginit, env, size);
+}
+bool google_protobuf_ServiceOptions_deprecated(const google_protobuf_ServiceOptions *msg) {
+  return msg->deprecated;
+}
+void google_protobuf_ServiceOptions_set_deprecated(google_protobuf_ServiceOptions *msg, bool value) {
+  msg->deprecated = value;
+}
+const upb_array* google_protobuf_ServiceOptions_uninterpreted_option(const google_protobuf_ServiceOptions *msg) {
+  return msg->uninterpreted_option;
+}
+void google_protobuf_ServiceOptions_set_uninterpreted_option(google_protobuf_ServiceOptions *msg, upb_array* value) {
+  msg->uninterpreted_option = value;
+}
+struct google_protobuf_MethodOptions {
+  google_protobuf_MethodOptions_IdempotencyLevel idempotency_level;
+  bool deprecated;
+  upb_array* uninterpreted_option;
+};
+
+static const upb_msglayout_msginit_v1 *const google_protobuf_MethodOptions_submsgs[1] = {
+  &google_protobuf_UninterpretedOption_msginit,
+};
+
+static const upb_msglayout_fieldinit_v1 google_protobuf_MethodOptions__fields[3] = {
+  {33, offsetof(google_protobuf_MethodOptions, deprecated), 1, UPB_NOT_IN_ONEOF, UPB_NO_SUBMSG, 8, 1},
+  {34, offsetof(google_protobuf_MethodOptions, idempotency_level), 0, UPB_NOT_IN_ONEOF, UPB_NO_SUBMSG, 14, 1},
+  {999, offsetof(google_protobuf_MethodOptions, uninterpreted_option), UPB_NO_HASBIT, UPB_NOT_IN_ONEOF, 0, 11, 3},
+};
+
+const upb_msglayout_msginit_v1 google_protobuf_MethodOptions_msginit = {
+  &google_protobuf_MethodOptions_submsgs[0],
+  &google_protobuf_MethodOptions__fields[0],
+  NULL,
+  NULL, /* TODO. default_msg */
+  UPB_ALIGNED_SIZEOF(google_protobuf_MethodOptions), 3, 0, false, true
+};
+
+google_protobuf_MethodOptions *google_protobuf_MethodOptions_new(upb_env *env) {
+  google_protobuf_MethodOptions *msg = upb_env_malloc(env, sizeof(*msg));
+  memset(msg, 0, sizeof(*msg));  /* TODO: defaults */
+  return msg;
+}
+google_protobuf_MethodOptions *google_protobuf_MethodOptions_parsenew(upb_stringview buf, upb_env *env) {
+  google_protobuf_MethodOptions *msg = google_protobuf_MethodOptions_new(env);
+  if (upb_decode(buf, msg, &google_protobuf_MethodOptions_msginit, env)) {
+    return msg;
+  } else {
+    return NULL;
+  }
+}
+char *google_protobuf_MethodOptions_serialize(google_protobuf_MethodOptions *msg, upb_env *env, size_t *size) {
+  return upb_encode(msg, &google_protobuf_MethodOptions_msginit, env, size);
+}
+bool google_protobuf_MethodOptions_deprecated(const google_protobuf_MethodOptions *msg) {
+  return msg->deprecated;
+}
+void google_protobuf_MethodOptions_set_deprecated(google_protobuf_MethodOptions *msg, bool value) {
+  msg->deprecated = value;
+}
+google_protobuf_MethodOptions_IdempotencyLevel google_protobuf_MethodOptions_idempotency_level(const google_protobuf_MethodOptions *msg) {
+  return msg->idempotency_level;
+}
+void google_protobuf_MethodOptions_set_idempotency_level(google_protobuf_MethodOptions *msg, google_protobuf_MethodOptions_IdempotencyLevel value) {
+  msg->idempotency_level = value;
+}
+const upb_array* google_protobuf_MethodOptions_uninterpreted_option(const google_protobuf_MethodOptions *msg) {
+  return msg->uninterpreted_option;
+}
+void google_protobuf_MethodOptions_set_uninterpreted_option(google_protobuf_MethodOptions *msg, upb_array* value) {
+  msg->uninterpreted_option = value;
+}
+struct google_protobuf_UninterpretedOption {
+  uint64_t positive_int_value;
+  int64_t negative_int_value;
+  double double_value;
+  upb_stringview identifier_value;
+  upb_stringview string_value;
+  upb_stringview aggregate_value;
+  upb_array* name;
+};
+
+static const upb_msglayout_msginit_v1 *const google_protobuf_UninterpretedOption_submsgs[1] = {
+  &google_protobuf_UninterpretedOption_NamePart_msginit,
+};
+
+static const upb_msglayout_fieldinit_v1 google_protobuf_UninterpretedOption__fields[7] = {
+  {2, offsetof(google_protobuf_UninterpretedOption, name), UPB_NO_HASBIT, UPB_NOT_IN_ONEOF, 0, 11, 3},
+  {3, offsetof(google_protobuf_UninterpretedOption, identifier_value), 3, UPB_NOT_IN_ONEOF, UPB_NO_SUBMSG, 9, 1},
+  {4, offsetof(google_protobuf_UninterpretedOption, positive_int_value), 0, UPB_NOT_IN_ONEOF, UPB_NO_SUBMSG, 4, 1},
+  {5, offsetof(google_protobuf_UninterpretedOption, negative_int_value), 1, UPB_NOT_IN_ONEOF, UPB_NO_SUBMSG, 3, 1},
+  {6, offsetof(google_protobuf_UninterpretedOption, double_value), 2, UPB_NOT_IN_ONEOF, UPB_NO_SUBMSG, 1, 1},
+  {7, offsetof(google_protobuf_UninterpretedOption, string_value), 4, UPB_NOT_IN_ONEOF, UPB_NO_SUBMSG, 12, 1},
+  {8, offsetof(google_protobuf_UninterpretedOption, aggregate_value), 5, UPB_NOT_IN_ONEOF, UPB_NO_SUBMSG, 9, 1},
+};
+
+const upb_msglayout_msginit_v1 google_protobuf_UninterpretedOption_msginit = {
+  &google_protobuf_UninterpretedOption_submsgs[0],
+  &google_protobuf_UninterpretedOption__fields[0],
+  NULL,
+  NULL, /* TODO. default_msg */
+  UPB_ALIGNED_SIZEOF(google_protobuf_UninterpretedOption), 7, 0, false, true
+};
+
+google_protobuf_UninterpretedOption *google_protobuf_UninterpretedOption_new(upb_env *env) {
+  google_protobuf_UninterpretedOption *msg = upb_env_malloc(env, sizeof(*msg));
+  memset(msg, 0, sizeof(*msg));  /* TODO: defaults */
+  return msg;
+}
+google_protobuf_UninterpretedOption *google_protobuf_UninterpretedOption_parsenew(upb_stringview buf, upb_env *env) {
+  google_protobuf_UninterpretedOption *msg = google_protobuf_UninterpretedOption_new(env);
+  if (upb_decode(buf, msg, &google_protobuf_UninterpretedOption_msginit, env)) {
+    return msg;
+  } else {
+    return NULL;
+  }
+}
+char *google_protobuf_UninterpretedOption_serialize(google_protobuf_UninterpretedOption *msg, upb_env *env, size_t *size) {
+  return upb_encode(msg, &google_protobuf_UninterpretedOption_msginit, env, size);
+}
+const upb_array* google_protobuf_UninterpretedOption_name(const google_protobuf_UninterpretedOption *msg) {
+  return msg->name;
+}
+void google_protobuf_UninterpretedOption_set_name(google_protobuf_UninterpretedOption *msg, upb_array* value) {
+  msg->name = value;
+}
+upb_stringview google_protobuf_UninterpretedOption_identifier_value(const google_protobuf_UninterpretedOption *msg) {
+  return msg->identifier_value;
+}
+void google_protobuf_UninterpretedOption_set_identifier_value(google_protobuf_UninterpretedOption *msg, upb_stringview value) {
+  msg->identifier_value = value;
+}
+uint64_t google_protobuf_UninterpretedOption_positive_int_value(const google_protobuf_UninterpretedOption *msg) {
+  return msg->positive_int_value;
+}
+void google_protobuf_UninterpretedOption_set_positive_int_value(google_protobuf_UninterpretedOption *msg, uint64_t value) {
+  msg->positive_int_value = value;
+}
+int64_t google_protobuf_UninterpretedOption_negative_int_value(const google_protobuf_UninterpretedOption *msg) {
+  return msg->negative_int_value;
+}
+void google_protobuf_UninterpretedOption_set_negative_int_value(google_protobuf_UninterpretedOption *msg, int64_t value) {
+  msg->negative_int_value = value;
+}
+double google_protobuf_UninterpretedOption_double_value(const google_protobuf_UninterpretedOption *msg) {
+  return msg->double_value;
+}
+void google_protobuf_UninterpretedOption_set_double_value(google_protobuf_UninterpretedOption *msg, double value) {
+  msg->double_value = value;
+}
+upb_stringview google_protobuf_UninterpretedOption_string_value(const google_protobuf_UninterpretedOption *msg) {
+  return msg->string_value;
+}
+void google_protobuf_UninterpretedOption_set_string_value(google_protobuf_UninterpretedOption *msg, upb_stringview value) {
+  msg->string_value = value;
+}
+upb_stringview google_protobuf_UninterpretedOption_aggregate_value(const google_protobuf_UninterpretedOption *msg) {
+  return msg->aggregate_value;
+}
+void google_protobuf_UninterpretedOption_set_aggregate_value(google_protobuf_UninterpretedOption *msg, upb_stringview value) {
+  msg->aggregate_value = value;
+}
+struct google_protobuf_UninterpretedOption_NamePart {
+  bool is_extension;
+  upb_stringview name_part;
+};
+
+static const upb_msglayout_fieldinit_v1 google_protobuf_UninterpretedOption_NamePart__fields[2] = {
+  {1, offsetof(google_protobuf_UninterpretedOption_NamePart, name_part), 1, UPB_NOT_IN_ONEOF, UPB_NO_SUBMSG, 9, 2},
+  {2, offsetof(google_protobuf_UninterpretedOption_NamePart, is_extension), 0, UPB_NOT_IN_ONEOF, UPB_NO_SUBMSG, 8, 2},
+};
+
+const upb_msglayout_msginit_v1 google_protobuf_UninterpretedOption_NamePart_msginit = {
+  NULL,
+  &google_protobuf_UninterpretedOption_NamePart__fields[0],
+  NULL,
+  NULL, /* TODO. default_msg */
+  UPB_ALIGNED_SIZEOF(google_protobuf_UninterpretedOption_NamePart), 2, 0, false, true
+};
+
+google_protobuf_UninterpretedOption_NamePart *google_protobuf_UninterpretedOption_NamePart_new(upb_env *env) {
+  google_protobuf_UninterpretedOption_NamePart *msg = upb_env_malloc(env, sizeof(*msg));
+  memset(msg, 0, sizeof(*msg));  /* TODO: defaults */
+  return msg;
+}
+google_protobuf_UninterpretedOption_NamePart *google_protobuf_UninterpretedOption_NamePart_parsenew(upb_stringview buf, upb_env *env) {
+  google_protobuf_UninterpretedOption_NamePart *msg = google_protobuf_UninterpretedOption_NamePart_new(env);
+  if (upb_decode(buf, msg, &google_protobuf_UninterpretedOption_NamePart_msginit, env)) {
+    return msg;
+  } else {
+    return NULL;
+  }
+}
+char *google_protobuf_UninterpretedOption_NamePart_serialize(google_protobuf_UninterpretedOption_NamePart *msg, upb_env *env, size_t *size) {
+  return upb_encode(msg, &google_protobuf_UninterpretedOption_NamePart_msginit, env, size);
+}
+upb_stringview google_protobuf_UninterpretedOption_NamePart_name_part(const google_protobuf_UninterpretedOption_NamePart *msg) {
+  return msg->name_part;
+}
+void google_protobuf_UninterpretedOption_NamePart_set_name_part(google_protobuf_UninterpretedOption_NamePart *msg, upb_stringview value) {
+  msg->name_part = value;
+}
+bool google_protobuf_UninterpretedOption_NamePart_is_extension(const google_protobuf_UninterpretedOption_NamePart *msg) {
+  return msg->is_extension;
+}
+void google_protobuf_UninterpretedOption_NamePart_set_is_extension(google_protobuf_UninterpretedOption_NamePart *msg, bool value) {
+  msg->is_extension = value;
+}
+struct google_protobuf_SourceCodeInfo {
+  upb_array* location;
+};
+
+static const upb_msglayout_msginit_v1 *const google_protobuf_SourceCodeInfo_submsgs[1] = {
+  &google_protobuf_SourceCodeInfo_Location_msginit,
+};
+
+static const upb_msglayout_fieldinit_v1 google_protobuf_SourceCodeInfo__fields[1] = {
+  {1, offsetof(google_protobuf_SourceCodeInfo, location), UPB_NO_HASBIT, UPB_NOT_IN_ONEOF, 0, 11, 3},
+};
+
+const upb_msglayout_msginit_v1 google_protobuf_SourceCodeInfo_msginit = {
+  &google_protobuf_SourceCodeInfo_submsgs[0],
+  &google_protobuf_SourceCodeInfo__fields[0],
+  NULL,
+  NULL, /* TODO. default_msg */
+  UPB_ALIGNED_SIZEOF(google_protobuf_SourceCodeInfo), 1, 0, false, true
+};
+
+google_protobuf_SourceCodeInfo *google_protobuf_SourceCodeInfo_new(upb_env *env) {
+  google_protobuf_SourceCodeInfo *msg = upb_env_malloc(env, sizeof(*msg));
+  memset(msg, 0, sizeof(*msg));  /* TODO: defaults */
+  return msg;
+}
+google_protobuf_SourceCodeInfo *google_protobuf_SourceCodeInfo_parsenew(upb_stringview buf, upb_env *env) {
+  google_protobuf_SourceCodeInfo *msg = google_protobuf_SourceCodeInfo_new(env);
+  if (upb_decode(buf, msg, &google_protobuf_SourceCodeInfo_msginit, env)) {
+    return msg;
+  } else {
+    return NULL;
+  }
+}
+char *google_protobuf_SourceCodeInfo_serialize(google_protobuf_SourceCodeInfo *msg, upb_env *env, size_t *size) {
+  return upb_encode(msg, &google_protobuf_SourceCodeInfo_msginit, env, size);
+}
+const upb_array* google_protobuf_SourceCodeInfo_location(const google_protobuf_SourceCodeInfo *msg) {
+  return msg->location;
+}
+void google_protobuf_SourceCodeInfo_set_location(google_protobuf_SourceCodeInfo *msg, upb_array* value) {
+  msg->location = value;
+}
+struct google_protobuf_SourceCodeInfo_Location {
+  upb_stringview leading_comments;
+  upb_stringview trailing_comments;
+  upb_array* path;
+  upb_array* span;
+  upb_array* leading_detached_comments;
+};
+
+static const upb_msglayout_fieldinit_v1 google_protobuf_SourceCodeInfo_Location__fields[5] = {
+  {1, offsetof(google_protobuf_SourceCodeInfo_Location, path), UPB_NO_HASBIT, UPB_NOT_IN_ONEOF, UPB_NO_SUBMSG, 5, 3},
+  {2, offsetof(google_protobuf_SourceCodeInfo_Location, span), UPB_NO_HASBIT, UPB_NOT_IN_ONEOF, UPB_NO_SUBMSG, 5, 3},
+  {3, offsetof(google_protobuf_SourceCodeInfo_Location, leading_comments), 0, UPB_NOT_IN_ONEOF, UPB_NO_SUBMSG, 9, 1},
+  {4, offsetof(google_protobuf_SourceCodeInfo_Location, trailing_comments), 1, UPB_NOT_IN_ONEOF, UPB_NO_SUBMSG, 9, 1},
+  {6, offsetof(google_protobuf_SourceCodeInfo_Location, leading_detached_comments), UPB_NO_HASBIT, UPB_NOT_IN_ONEOF, UPB_NO_SUBMSG, 9, 3},
+};
+
+const upb_msglayout_msginit_v1 google_protobuf_SourceCodeInfo_Location_msginit = {
+  NULL,
+  &google_protobuf_SourceCodeInfo_Location__fields[0],
+  NULL,
+  NULL, /* TODO. default_msg */
+  UPB_ALIGNED_SIZEOF(google_protobuf_SourceCodeInfo_Location), 5, 0, false, true
+};
+
+google_protobuf_SourceCodeInfo_Location *google_protobuf_SourceCodeInfo_Location_new(upb_env *env) {
+  google_protobuf_SourceCodeInfo_Location *msg = upb_env_malloc(env, sizeof(*msg));
+  memset(msg, 0, sizeof(*msg));  /* TODO: defaults */
+  return msg;
+}
+google_protobuf_SourceCodeInfo_Location *google_protobuf_SourceCodeInfo_Location_parsenew(upb_stringview buf, upb_env *env) {
+  google_protobuf_SourceCodeInfo_Location *msg = google_protobuf_SourceCodeInfo_Location_new(env);
+  if (upb_decode(buf, msg, &google_protobuf_SourceCodeInfo_Location_msginit, env)) {
+    return msg;
+  } else {
+    return NULL;
+  }
+}
+char *google_protobuf_SourceCodeInfo_Location_serialize(google_protobuf_SourceCodeInfo_Location *msg, upb_env *env, size_t *size) {
+  return upb_encode(msg, &google_protobuf_SourceCodeInfo_Location_msginit, env, size);
+}
+const upb_array* google_protobuf_SourceCodeInfo_Location_path(const google_protobuf_SourceCodeInfo_Location *msg) {
+  return msg->path;
+}
+void google_protobuf_SourceCodeInfo_Location_set_path(google_protobuf_SourceCodeInfo_Location *msg, upb_array* value) {
+  msg->path = value;
+}
+const upb_array* google_protobuf_SourceCodeInfo_Location_span(const google_protobuf_SourceCodeInfo_Location *msg) {
+  return msg->span;
+}
+void google_protobuf_SourceCodeInfo_Location_set_span(google_protobuf_SourceCodeInfo_Location *msg, upb_array* value) {
+  msg->span = value;
+}
+upb_stringview google_protobuf_SourceCodeInfo_Location_leading_comments(const google_protobuf_SourceCodeInfo_Location *msg) {
+  return msg->leading_comments;
+}
+void google_protobuf_SourceCodeInfo_Location_set_leading_comments(google_protobuf_SourceCodeInfo_Location *msg, upb_stringview value) {
+  msg->leading_comments = value;
+}
+upb_stringview google_protobuf_SourceCodeInfo_Location_trailing_comments(const google_protobuf_SourceCodeInfo_Location *msg) {
+  return msg->trailing_comments;
+}
+void google_protobuf_SourceCodeInfo_Location_set_trailing_comments(google_protobuf_SourceCodeInfo_Location *msg, upb_stringview value) {
+  msg->trailing_comments = value;
+}
+const upb_array* google_protobuf_SourceCodeInfo_Location_leading_detached_comments(const google_protobuf_SourceCodeInfo_Location *msg) {
+  return msg->leading_detached_comments;
+}
+void google_protobuf_SourceCodeInfo_Location_set_leading_detached_comments(google_protobuf_SourceCodeInfo_Location *msg, upb_array* value) {
+  msg->leading_detached_comments = value;
+}
+struct google_protobuf_GeneratedCodeInfo {
+  upb_array* annotation;
+};
+
+static const upb_msglayout_msginit_v1 *const google_protobuf_GeneratedCodeInfo_submsgs[1] = {
+  &google_protobuf_GeneratedCodeInfo_Annotation_msginit,
+};
+
+static const upb_msglayout_fieldinit_v1 google_protobuf_GeneratedCodeInfo__fields[1] = {
+  {1, offsetof(google_protobuf_GeneratedCodeInfo, annotation), UPB_NO_HASBIT, UPB_NOT_IN_ONEOF, 0, 11, 3},
+};
+
+const upb_msglayout_msginit_v1 google_protobuf_GeneratedCodeInfo_msginit = {
+  &google_protobuf_GeneratedCodeInfo_submsgs[0],
+  &google_protobuf_GeneratedCodeInfo__fields[0],
+  NULL,
+  NULL, /* TODO. default_msg */
+  UPB_ALIGNED_SIZEOF(google_protobuf_GeneratedCodeInfo), 1, 0, false, true
+};
+
+google_protobuf_GeneratedCodeInfo *google_protobuf_GeneratedCodeInfo_new(upb_env *env) {
+  google_protobuf_GeneratedCodeInfo *msg = upb_env_malloc(env, sizeof(*msg));
+  memset(msg, 0, sizeof(*msg));  /* TODO: defaults */
+  return msg;
+}
+google_protobuf_GeneratedCodeInfo *google_protobuf_GeneratedCodeInfo_parsenew(upb_stringview buf, upb_env *env) {
+  google_protobuf_GeneratedCodeInfo *msg = google_protobuf_GeneratedCodeInfo_new(env);
+  if (upb_decode(buf, msg, &google_protobuf_GeneratedCodeInfo_msginit, env)) {
+    return msg;
+  } else {
+    return NULL;
+  }
+}
+char *google_protobuf_GeneratedCodeInfo_serialize(google_protobuf_GeneratedCodeInfo *msg, upb_env *env, size_t *size) {
+  return upb_encode(msg, &google_protobuf_GeneratedCodeInfo_msginit, env, size);
+}
+const upb_array* google_protobuf_GeneratedCodeInfo_annotation(const google_protobuf_GeneratedCodeInfo *msg) {
+  return msg->annotation;
+}
+void google_protobuf_GeneratedCodeInfo_set_annotation(google_protobuf_GeneratedCodeInfo *msg, upb_array* value) {
+  msg->annotation = value;
+}
+struct google_protobuf_GeneratedCodeInfo_Annotation {
+  int32_t begin;
+  int32_t end;
+  upb_stringview source_file;
+  upb_array* path;
+};
+
+static const upb_msglayout_fieldinit_v1 google_protobuf_GeneratedCodeInfo_Annotation__fields[4] = {
+  {1, offsetof(google_protobuf_GeneratedCodeInfo_Annotation, path), UPB_NO_HASBIT, UPB_NOT_IN_ONEOF, UPB_NO_SUBMSG, 5, 3},
+  {2, offsetof(google_protobuf_GeneratedCodeInfo_Annotation, source_file), 2, UPB_NOT_IN_ONEOF, UPB_NO_SUBMSG, 9, 1},
+  {3, offsetof(google_protobuf_GeneratedCodeInfo_Annotation, begin), 0, UPB_NOT_IN_ONEOF, UPB_NO_SUBMSG, 5, 1},
+  {4, offsetof(google_protobuf_GeneratedCodeInfo_Annotation, end), 1, UPB_NOT_IN_ONEOF, UPB_NO_SUBMSG, 5, 1},
+};
+
+const upb_msglayout_msginit_v1 google_protobuf_GeneratedCodeInfo_Annotation_msginit = {
+  NULL,
+  &google_protobuf_GeneratedCodeInfo_Annotation__fields[0],
+  NULL,
+  NULL, /* TODO. default_msg */
+  UPB_ALIGNED_SIZEOF(google_protobuf_GeneratedCodeInfo_Annotation), 4, 0, false, true
+};
+
+google_protobuf_GeneratedCodeInfo_Annotation *google_protobuf_GeneratedCodeInfo_Annotation_new(upb_env *env) {
+  google_protobuf_GeneratedCodeInfo_Annotation *msg = upb_env_malloc(env, sizeof(*msg));
+  memset(msg, 0, sizeof(*msg));  /* TODO: defaults */
+  return msg;
+}
+google_protobuf_GeneratedCodeInfo_Annotation *google_protobuf_GeneratedCodeInfo_Annotation_parsenew(upb_stringview buf, upb_env *env) {
+  google_protobuf_GeneratedCodeInfo_Annotation *msg = google_protobuf_GeneratedCodeInfo_Annotation_new(env);
+  if (upb_decode(buf, msg, &google_protobuf_GeneratedCodeInfo_Annotation_msginit, env)) {
+    return msg;
+  } else {
+    return NULL;
+  }
+}
+char *google_protobuf_GeneratedCodeInfo_Annotation_serialize(google_protobuf_GeneratedCodeInfo_Annotation *msg, upb_env *env, size_t *size) {
+  return upb_encode(msg, &google_protobuf_GeneratedCodeInfo_Annotation_msginit, env, size);
+}
+const upb_array* google_protobuf_GeneratedCodeInfo_Annotation_path(const google_protobuf_GeneratedCodeInfo_Annotation *msg) {
+  return msg->path;
+}
+void google_protobuf_GeneratedCodeInfo_Annotation_set_path(google_protobuf_GeneratedCodeInfo_Annotation *msg, upb_array* value) {
+  msg->path = value;
+}
+upb_stringview google_protobuf_GeneratedCodeInfo_Annotation_source_file(const google_protobuf_GeneratedCodeInfo_Annotation *msg) {
+  return msg->source_file;
+}
+void google_protobuf_GeneratedCodeInfo_Annotation_set_source_file(google_protobuf_GeneratedCodeInfo_Annotation *msg, upb_stringview value) {
+  msg->source_file = value;
+}
+int32_t google_protobuf_GeneratedCodeInfo_Annotation_begin(const google_protobuf_GeneratedCodeInfo_Annotation *msg) {
+  return msg->begin;
+}
+void google_protobuf_GeneratedCodeInfo_Annotation_set_begin(google_protobuf_GeneratedCodeInfo_Annotation *msg, int32_t value) {
+  msg->begin = value;
+}
+int32_t google_protobuf_GeneratedCodeInfo_Annotation_end(const google_protobuf_GeneratedCodeInfo_Annotation *msg) {
+  return msg->end;
+}
+void google_protobuf_GeneratedCodeInfo_Annotation_set_end(google_protobuf_GeneratedCodeInfo_Annotation *msg, int32_t value) {
+  msg->end = value;
+}
+
+
+/* Maps descriptor type -> upb field type.  */
+const uint8_t upb_desctype_to_fieldtype[] = {
+  UPB_WIRE_TYPE_END_GROUP,  /* ENDGROUP */
+  UPB_TYPE_DOUBLE,          /* DOUBLE */
+  UPB_TYPE_FLOAT,           /* FLOAT */
+  UPB_TYPE_INT64,           /* INT64 */
+  UPB_TYPE_UINT64,          /* UINT64 */
+  UPB_TYPE_INT32,           /* INT32 */
+  UPB_TYPE_UINT64,          /* FIXED64 */
+  UPB_TYPE_UINT32,          /* FIXED32 */
+  UPB_TYPE_BOOL,            /* BOOL */
+  UPB_TYPE_STRING,          /* STRING */
+  UPB_TYPE_MESSAGE,         /* GROUP */
+  UPB_TYPE_MESSAGE,         /* MESSAGE */
+  UPB_TYPE_BYTES,           /* BYTES */
+  UPB_TYPE_UINT32,          /* UINT32 */
+  UPB_TYPE_ENUM,            /* ENUM */
+  UPB_TYPE_INT32,           /* SFIXED32 */
+  UPB_TYPE_INT64,           /* SFIXED64 */
+  UPB_TYPE_INT32,           /* SINT32 */
+  UPB_TYPE_INT64,           /* SINT64 */
+};
+
+/* Data pertaining to the parse. */
+typedef struct {
+  upb_env *env;
+  /* Current decoding pointer.  Points to the beginning of a field until we
+   * have finished decoding the whole field. */
+  const char *ptr;
+} upb_decstate;
+
+/* Data pertaining to a single message frame. */
+typedef struct {
+  const char *limit;
+  int32_t group_number;  /* 0 if we are not parsing a group. */
+
+  /* These members are unset for an unknown group frame. */
+  char *msg;
+  const upb_msglayout_msginit_v1 *m;
+} upb_decframe;
+
+#define CHK(x) if (!(x)) { return false; }
+
+static bool upb_skip_unknowngroup(upb_decstate *d, int field_number,
+                                  const char *limit);
+static bool upb_decode_message(upb_decstate *d, const char *limit,
+                               int group_number, char *msg,
+                               const upb_msglayout_msginit_v1 *l);
+
+static bool upb_decode_varint(const char **ptr, const char *limit,
+                              uint64_t *val) {
+  uint8_t byte;
+  int bitpos = 0;
+  const char *p = *ptr;
+  *val = 0;
+
+  do {
+    CHK(bitpos < 70 && p < limit);
+    byte = *p;
+    *val |= (uint64_t)(byte & 0x7F) << bitpos;
+    p++;
+    bitpos += 7;
+  } while (byte & 0x80);
+
+  *ptr = p;
+  return true;
+}
+
+static bool upb_decode_varint32(const char **ptr, const char *limit,
+                                uint32_t *val) {
+  uint64_t u64;
+  CHK(upb_decode_varint(ptr, limit, &u64) && u64 <= UINT32_MAX);
+  *val = u64;
+  return true;
+}
+
+static bool upb_decode_64bit(const char **ptr, const char *limit,
+                             uint64_t *val) {
+  CHK(limit - *ptr >= 8);
+  memcpy(val, *ptr, 8);
+  *ptr += 8;
+  return true;
+}
+
+static bool upb_decode_32bit(const char **ptr, const char *limit,
+                             uint32_t *val) {
+  CHK(limit - *ptr >= 4);
+  memcpy(val, *ptr, 4);
+  *ptr += 4;
+  return true;
+}
+
+static bool upb_decode_tag(const char **ptr, const char *limit,
+                           int *field_number, int *wire_type) {
+  uint32_t tag = 0;
+  CHK(upb_decode_varint32(ptr, limit, &tag));
+  *field_number = tag >> 3;
+  *wire_type = tag & 7;
+  return true;
+}
+
+static int32_t upb_zzdecode_32(uint32_t n) {
+  return (n >> 1) ^ -(int32_t)(n & 1);
+}
+
+static int64_t upb_zzdecode_64(uint64_t n) {
+  return (n >> 1) ^ -(int64_t)(n & 1);
+}
+
+static bool upb_decode_string(const char **ptr, const char *limit,
+                              upb_stringview *val) {
+  uint32_t len;
+
+  CHK(upb_decode_varint32(ptr, limit, &len) &&
+      len < INT32_MAX &&
+      limit - *ptr >= (int32_t)len);
+
+  *val = upb_stringview_make(*ptr, len);
+  *ptr += len;
+  return true;
+}
+
+static void upb_set32(void *msg, size_t ofs, uint32_t val) {
+  memcpy((char*)msg + ofs, &val, sizeof(val));
+}
+
+static bool upb_append_unknown(upb_decstate *d, upb_decframe *frame,
+                               const char *start) {
+  UPB_UNUSED(d);
+  UPB_UNUSED(frame);
+  UPB_UNUSED(start);
+  return true;
+}
+
+static bool upb_skip_unknownfielddata(upb_decstate *d, upb_decframe *frame,
+                                      int field_number, int wire_type) {
+  switch (wire_type) {
+    case UPB_WIRE_TYPE_VARINT: {
+      uint64_t val;
+      return upb_decode_varint(&d->ptr, frame->limit, &val);
+    }
+    case UPB_WIRE_TYPE_32BIT: {
+      uint32_t val;
+      return upb_decode_32bit(&d->ptr, frame->limit, &val);
+    }
+    case UPB_WIRE_TYPE_64BIT: {
+      uint64_t val;
+      return upb_decode_64bit(&d->ptr, frame->limit, &val);
+    }
+    case UPB_WIRE_TYPE_DELIMITED: {
+      upb_stringview val;
+      return upb_decode_string(&d->ptr, frame->limit, &val);
+    }
+    case UPB_WIRE_TYPE_START_GROUP:
+      return upb_skip_unknowngroup(d, field_number, frame->limit);
+    case UPB_WIRE_TYPE_END_GROUP:
+      CHK(field_number == frame->group_number);
+      frame->limit = d->ptr;
+      return true;
+  }
+  return false;
+}
+
+static bool upb_array_grow(upb_array *arr, size_t elements) {
+  size_t needed = arr->len + elements;
+  size_t new_size = UPB_MAX(arr->size, 8);
+  size_t new_bytes;
+  size_t old_bytes;
+  void *new_data;
+
+  while (new_size < needed) {
+    new_size *= 2;
+  }
+
+  old_bytes = arr->len * arr->element_size;
+  new_bytes = new_size * arr->element_size;
+  new_data = upb_realloc(arr->alloc, arr->data, old_bytes, new_bytes);
+  CHK(new_data);
+
+  arr->data = new_data;
+  arr->size = new_size;
+  return true;
+}
+
+static void *upb_array_reserve(upb_array *arr, size_t elements) {
+  if (arr->size - arr->len < elements) {
+    CHK(upb_array_grow(arr, elements));
+  }
+  return (char*)arr->data + (arr->len * arr->element_size);
+}
+
+static void *upb_array_add(upb_array *arr, size_t elements) {
+  void *ret = upb_array_reserve(arr, elements);
+  arr->len += elements;
+  return ret;
+}
+
+static upb_array *upb_getarr(upb_decframe *frame,
+                             const upb_msglayout_fieldinit_v1 *field) {
+  UPB_ASSERT(field->label == UPB_LABEL_REPEATED);
+  return *(upb_array**)&frame->msg[field->offset];
+}
+
+static upb_array *upb_getorcreatearr(upb_decstate *d,
+                                     upb_decframe *frame,
+                                     const upb_msglayout_fieldinit_v1 *field) {
+  upb_array *arr = upb_getarr(frame, field);
+
+  if (!arr) {
+    arr = upb_env_malloc(d->env, sizeof(*arr));
+    if (!arr) {
+      return NULL;
+    }
+    upb_array_init(arr, upb_desctype_to_fieldtype[field->descriptortype],
+                   upb_arena_alloc(upb_env_arena(d->env)));
+    *(upb_array**)&frame->msg[field->offset] = arr;
+  }
+
+  return arr;
+}
+
+static void upb_sethasbit(upb_decframe *frame,
+                          const upb_msglayout_fieldinit_v1 *field) {
+  UPB_ASSERT(field->hasbit != UPB_NO_HASBIT);
+  frame->msg[field->hasbit / 8] |= (1 << (field->hasbit % 8));
+}
+
+static void upb_setoneofcase(upb_decframe *frame,
+                             const upb_msglayout_fieldinit_v1 *field) {
+  UPB_ASSERT(field->oneof_index != UPB_NOT_IN_ONEOF);
+  upb_set32(frame->msg, frame->m->oneofs[field->oneof_index].case_offset,
+            field->number);
+}
+
+static char *upb_decode_prepareslot(upb_decstate *d,
+                                    upb_decframe *frame,
+                                    const upb_msglayout_fieldinit_v1 *field) {
+  char *field_mem = frame->msg + field->offset;
+  upb_array *arr;
+
+  if (field->label == UPB_LABEL_REPEATED) {
+    arr = upb_getorcreatearr(d, frame, field);
+    field_mem = upb_array_reserve(arr, 1);
+  }
+
+  return field_mem;
+}
+
+static void upb_decode_setpresent(upb_decframe *frame,
+                                  const upb_msglayout_fieldinit_v1 *field) {
+  if (field->label == UPB_LABEL_REPEATED) {
+   upb_array *arr = upb_getarr(frame, field);
+   UPB_ASSERT(arr->len < arr->size);
+   arr->len++;
+  } else if (field->oneof_index != UPB_NOT_IN_ONEOF) {
+    upb_setoneofcase(frame, field);
+  } else if (field->hasbit != UPB_NO_HASBIT) {
+    upb_sethasbit(frame, field);
+  }
+}
+
+static bool upb_decode_submsg(upb_decstate *d,
+                              upb_decframe *frame,
+                              const char *limit,
+                              const upb_msglayout_fieldinit_v1 *field,
+                              int group_number) {
+  char *submsg_slot = upb_decode_prepareslot(d, frame, field);
+  char *submsg = *(void**)submsg_slot;
+  const upb_msglayout_msginit_v1 *subm;
+
+  UPB_ASSERT(field->submsg_index != UPB_NO_SUBMSG);
+  subm = frame->m->submsgs[field->submsg_index];
+  UPB_ASSERT(subm);
+
+  if (!submsg) {
+    submsg = upb_env_malloc(d->env, upb_msg_sizeof((upb_msglayout *)subm));
+    CHK(submsg);
+    submsg = upb_msg_init(
+        submsg, (upb_msglayout*)subm, upb_arena_alloc(upb_env_arena(d->env)));
+    *(void**)submsg_slot = submsg;
+  }
+
+  upb_decode_message(d, limit, group_number, submsg, subm);
+
+  return true;
+}
+
+static bool upb_decode_varintfield(upb_decstate *d, upb_decframe *frame,
+                                   const char *field_start,
+                                   const upb_msglayout_fieldinit_v1 *field) {
+  uint64_t val;
+  void *field_mem;
+
+  field_mem = upb_decode_prepareslot(d, frame, field);
+  CHK(field_mem);
+  CHK(upb_decode_varint(&d->ptr, frame->limit, &val));
+
+  switch ((upb_descriptortype_t)field->descriptortype) {
+    case UPB_DESCRIPTOR_TYPE_INT64:
+    case UPB_DESCRIPTOR_TYPE_UINT64:
+      memcpy(field_mem, &val, sizeof(val));
+      break;
+    case UPB_DESCRIPTOR_TYPE_INT32:
+    case UPB_DESCRIPTOR_TYPE_UINT32:
+    case UPB_DESCRIPTOR_TYPE_ENUM: {
+      uint32_t val32 = val;
+      memcpy(field_mem, &val32, sizeof(val32));
+      break;
+    }
+    case UPB_DESCRIPTOR_TYPE_BOOL: {
+      bool valbool = val != 0;
+      memcpy(field_mem, &valbool, sizeof(valbool));
+      break;
+    }
+    case UPB_DESCRIPTOR_TYPE_SINT32: {
+      int32_t decoded = upb_zzdecode_32(val);
+      memcpy(field_mem, &decoded, sizeof(decoded));
+      break;
+    }
+    case UPB_DESCRIPTOR_TYPE_SINT64: {
+      int64_t decoded = upb_zzdecode_64(val);
+      memcpy(field_mem, &decoded, sizeof(decoded));
+      break;
+    }
+    default:
+      return upb_append_unknown(d, frame, field_start);
+  }
+
+  upb_decode_setpresent(frame, field);
+  return true;
+}
+
+static bool upb_decode_64bitfield(upb_decstate *d, upb_decframe *frame,
+                                  const char *field_start,
+                                  const upb_msglayout_fieldinit_v1 *field) {
+  void *field_mem;
+  uint64_t val;
+
+  field_mem = upb_decode_prepareslot(d, frame, field);
+  CHK(field_mem);
+  CHK(upb_decode_64bit(&d->ptr, frame->limit, &val));
+
+  switch ((upb_descriptortype_t)field->descriptortype) {
+    case UPB_DESCRIPTOR_TYPE_DOUBLE:
+    case UPB_DESCRIPTOR_TYPE_FIXED64:
+    case UPB_DESCRIPTOR_TYPE_SFIXED64:
+      memcpy(field_mem, &val, sizeof(val));
+      break;
+    default:
+      return upb_append_unknown(d, frame, field_start);
+  }
+
+  upb_decode_setpresent(frame, field);
+  return true;
+}
+
+static bool upb_decode_32bitfield(upb_decstate *d, upb_decframe *frame,
+                                  const char *field_start,
+                                  const upb_msglayout_fieldinit_v1 *field) {
+  void *field_mem;
+  uint32_t val;
+
+  field_mem = upb_decode_prepareslot(d, frame, field);
+  CHK(field_mem);
+  CHK(upb_decode_32bit(&d->ptr, frame->limit, &val));
+
+  switch ((upb_descriptortype_t)field->descriptortype) {
+    case UPB_DESCRIPTOR_TYPE_FLOAT:
+    case UPB_DESCRIPTOR_TYPE_FIXED32:
+    case UPB_DESCRIPTOR_TYPE_SFIXED32:
+      memcpy(field_mem, &val, sizeof(val));
+      break;
+    default:
+      return upb_append_unknown(d, frame, field_start);
+  }
+
+  upb_decode_setpresent(frame, field);
+  return true;
+}
+
+static bool upb_decode_fixedpacked(upb_array *arr, upb_stringview data,
+                                   int elem_size) {
+  int elements = data.size / elem_size;
+  void *field_mem;
+
+  CHK((size_t)(elements * elem_size) == data.size);
+  field_mem = upb_array_add(arr, elements);
+  CHK(field_mem);
+  memcpy(field_mem, data.data, data.size);
+  return true;
+}
+
+static bool upb_decode_toarray(upb_decstate *d, upb_decframe *frame,
+                               const char *field_start,
+                               const upb_msglayout_fieldinit_v1 *field,
+                               upb_stringview val) {
+  upb_array *arr = upb_getorcreatearr(d, frame, field);
+
+#define VARINT_CASE(ctype, decode) { \
+  const char *ptr = val.data; \
+  const char *limit = ptr + val.size; \
+  while (ptr < limit) { \
+    uint64_t val; \
+    void *field_mem; \
+    ctype decoded; \
+    CHK(upb_decode_varint(&ptr, limit, &val)); \
+    decoded = (decode)(val); \
+    field_mem = upb_array_add(arr, 1); \
+    CHK(field_mem); \
+    memcpy(field_mem, &decoded, sizeof(ctype)); \
+  } \
+  return true; \
+}
+
+  switch ((upb_descriptortype_t)field->descriptortype) {
+    case UPB_DESCRIPTOR_TYPE_STRING:
+    case UPB_DESCRIPTOR_TYPE_BYTES: {
+      void *field_mem = upb_array_add(arr, 1);
+      CHK(field_mem);
+      memcpy(field_mem, &val, sizeof(val));
+      return true;
+    }
+    case UPB_DESCRIPTOR_TYPE_FLOAT:
+    case UPB_DESCRIPTOR_TYPE_FIXED32:
+    case UPB_DESCRIPTOR_TYPE_SFIXED32:
+      return upb_decode_fixedpacked(arr, val, sizeof(int32_t));
+    case UPB_DESCRIPTOR_TYPE_DOUBLE:
+    case UPB_DESCRIPTOR_TYPE_FIXED64:
+    case UPB_DESCRIPTOR_TYPE_SFIXED64:
+      return upb_decode_fixedpacked(arr, val, sizeof(int64_t));
+    case UPB_DESCRIPTOR_TYPE_INT32:
+    case UPB_DESCRIPTOR_TYPE_UINT32:
+    case UPB_DESCRIPTOR_TYPE_ENUM:
+      /* TODO: proto2 enum field that isn't in the enum. */
+      VARINT_CASE(uint32_t, uint32_t);
+    case UPB_DESCRIPTOR_TYPE_INT64:
+    case UPB_DESCRIPTOR_TYPE_UINT64:
+      VARINT_CASE(uint64_t, uint64_t);
+    case UPB_DESCRIPTOR_TYPE_BOOL:
+      VARINT_CASE(bool, bool);
+    case UPB_DESCRIPTOR_TYPE_SINT32:
+      VARINT_CASE(int32_t, upb_zzdecode_32);
+    case UPB_DESCRIPTOR_TYPE_SINT64:
+      VARINT_CASE(int64_t, upb_zzdecode_64);
+    case UPB_DESCRIPTOR_TYPE_MESSAGE: {
+      const upb_msglayout_msginit_v1 *subm;
+      char *submsg;
+      void *field_mem;
+
+      CHK(val.size <= (size_t)(frame->limit - val.data));
+      d->ptr -= val.size;
+
+      /* Create elemente message. */
+      UPB_ASSERT(field->submsg_index != UPB_NO_SUBMSG);
+      subm = frame->m->submsgs[field->submsg_index];
+      UPB_ASSERT(subm);
+
+      submsg = upb_env_malloc(d->env, upb_msg_sizeof((upb_msglayout *)subm));
+      CHK(submsg);
+      submsg = upb_msg_init(submsg, (upb_msglayout*)subm,
+                            upb_arena_alloc(upb_env_arena(d->env)));
+
+      field_mem = upb_array_add(arr, 1);
+      CHK(field_mem);
+      *(void**)field_mem = submsg;
+
+      return upb_decode_message(
+          d, val.data + val.size, frame->group_number, submsg, subm);
+    }
+    case UPB_DESCRIPTOR_TYPE_GROUP:
+      return upb_append_unknown(d, frame, field_start);
+  }
+#undef VARINT_CASE
+  UPB_UNREACHABLE();
+}
+
+static bool upb_decode_delimitedfield(upb_decstate *d, upb_decframe *frame,
+                                      const char *field_start,
+                                      const upb_msglayout_fieldinit_v1 *field) {
+  upb_stringview val;
+
+  CHK(upb_decode_string(&d->ptr, frame->limit, &val));
+
+  if (field->label == UPB_LABEL_REPEATED) {
+    return upb_decode_toarray(d, frame, field_start, field, val);
+  } else {
+    switch ((upb_descriptortype_t)field->descriptortype) {
+      case UPB_DESCRIPTOR_TYPE_STRING:
+      case UPB_DESCRIPTOR_TYPE_BYTES: {
+        void *field_mem = upb_decode_prepareslot(d, frame, field);
+        CHK(field_mem);
+        memcpy(field_mem, &val, sizeof(val));
+        break;
+      }
+      case UPB_DESCRIPTOR_TYPE_MESSAGE:
+        CHK(val.size <= (size_t)(frame->limit - val.data));
+        d->ptr -= val.size;
+        CHK(upb_decode_submsg(d, frame, val.data + val.size, field, 0));
+        break;
+      default:
+        /* TODO(haberman): should we accept the last element of a packed? */
+        return upb_append_unknown(d, frame, field_start);
+    }
+    upb_decode_setpresent(frame, field);
+    return true;
+  }
+}
+
+static const upb_msglayout_fieldinit_v1 *upb_find_field(
+    const upb_msglayout_msginit_v1 *l, uint32_t field_number) {
+  /* Lots of optimization opportunities here. */
+  int i;
+  for (i = 0; i < l->field_count; i++) {
+    if (l->fields[i].number == field_number) {
+      return &l->fields[i];
+    }
+  }
+
+  return NULL;  /* Unknown field. */
+}
+
+static bool upb_decode_field(upb_decstate *d, upb_decframe *frame) {
+  int field_number;
+  int wire_type;
+  const char *field_start = d->ptr;
+  const upb_msglayout_fieldinit_v1 *field;
+
+  CHK(upb_decode_tag(&d->ptr, frame->limit, &field_number, &wire_type));
+  field = upb_find_field(frame->m, field_number);
+
+  if (field) {
+    switch (wire_type) {
+      case UPB_WIRE_TYPE_VARINT:
+        return upb_decode_varintfield(d, frame, field_start, field);
+      case UPB_WIRE_TYPE_32BIT:
+        return upb_decode_32bitfield(d, frame, field_start, field);
+      case UPB_WIRE_TYPE_64BIT:
+        return upb_decode_64bitfield(d, frame, field_start, field);
+      case UPB_WIRE_TYPE_DELIMITED:
+        return upb_decode_delimitedfield(d, frame, field_start, field);
+      case UPB_WIRE_TYPE_START_GROUP:
+        CHK(field->descriptortype == UPB_DESCRIPTOR_TYPE_GROUP);
+        return upb_decode_submsg(d, frame, frame->limit, field, field_number);
+      case UPB_WIRE_TYPE_END_GROUP:
+        CHK(frame->group_number == field_number)
+        frame->limit = d->ptr;
+        return true;
+      default:
+        return false;
+    }
+  } else {
+    CHK(field_number != 0);
+    return upb_skip_unknownfielddata(d, frame, field_number, wire_type);
+  }
+}
+
+static bool upb_skip_unknowngroup(upb_decstate *d, int field_number,
+                                  const char *limit) {
+  upb_decframe frame;
+  frame.msg = NULL;
+  frame.m = NULL;
+  frame.group_number = field_number;
+  frame.limit = limit;
+
+  while (d->ptr < frame.limit) {
+    int wire_type;
+    int field_number;
+
+    CHK(upb_decode_tag(&d->ptr, frame.limit, &field_number, &wire_type));
+    CHK(upb_skip_unknownfielddata(d, &frame, field_number, wire_type));
+  }
+
+  return true;
+}
+
+static bool upb_decode_message(upb_decstate *d, const char *limit,
+                               int group_number, char *msg,
+                               const upb_msglayout_msginit_v1 *l) {
+  upb_decframe frame;
+  frame.group_number = group_number;
+  frame.limit = limit;
+  frame.msg = msg;
+  frame.m = l;
+
+  while (d->ptr < frame.limit) {
+    CHK(upb_decode_field(d, &frame));
+  }
+
+  return true;
+}
+
+bool upb_decode(upb_stringview buf, void *msg,
+                const upb_msglayout_msginit_v1 *l, upb_env *env) {
+  upb_decstate state;
+  state.ptr = buf.data;
+  state.env = env;
+
+  return upb_decode_message(&state, buf.data + buf.size, 0, msg, l);
+}
+
+#undef CHK
+
+
+#include <ctype.h>
+#include <stdlib.h>
+#include <string.h>
+
+typedef struct {
+  size_t len;
+  char str[1];  /* Null-terminated string data follows. */
+} str_t;
+
+static str_t *newstr(const char *data, size_t len) {
+  str_t *ret = upb_gmalloc(sizeof(*ret) + len);
+  if (!ret) return NULL;
+  ret->len = len;
+  memcpy(ret->str, data, len);
+  ret->str[len] = '\0';
+  return ret;
+}
+
+static void freestr(str_t *s) { upb_gfree(s); }
+
+/* isalpha() etc. from <ctype.h> are locale-dependent, which we don't want. */
+static bool upb_isbetween(char c, char low, char high) {
+  return c >= low && c <= high;
+}
+
+static bool upb_isletter(char c) {
+  return upb_isbetween(c, 'A', 'Z') || upb_isbetween(c, 'a', 'z') || c == '_';
+}
+
+static bool upb_isalphanum(char c) {
+  return upb_isletter(c) || upb_isbetween(c, '0', '9');
+}
+
+static bool upb_isident(const char *str, size_t len, bool full, upb_status *s) {
+  bool start = true;
+  size_t i;
+  for (i = 0; i < len; i++) {
+    char c = str[i];
+    if (c == '.') {
+      if (start || !full) {
+        upb_status_seterrf(s, "invalid name: unexpected '.' (%s)", str);
+        return false;
+      }
+      start = true;
+    } else if (start) {
+      if (!upb_isletter(c)) {
+        upb_status_seterrf(
+            s, "invalid name: path components must start with a letter (%s)",
+            str);
+        return false;
+      }
+      start = false;
+    } else {
+      if (!upb_isalphanum(c)) {
+        upb_status_seterrf(s, "invalid name: non-alphanumeric character (%s)",
+                           str);
+        return false;
+      }
+    }
+  }
+  return !start;
+}
+
+static bool upb_isoneof(const upb_refcounted *def) {
+  return def->vtbl == &upb_oneofdef_vtbl;
+}
+
+static bool upb_isfield(const upb_refcounted *def) {
+  return def->vtbl == &upb_fielddef_vtbl;
+}
+
+static const upb_oneofdef *upb_trygetoneof(const upb_refcounted *def) {
+  return upb_isoneof(def) ? (const upb_oneofdef*)def : NULL;
+}
+
+static const upb_fielddef *upb_trygetfield(const upb_refcounted *def) {
+  return upb_isfield(def) ? (const upb_fielddef*)def : NULL;
+}
+
+
+/* upb_def ********************************************************************/
+
+upb_deftype_t upb_def_type(const upb_def *d) { return d->type; }
+
+const char *upb_def_fullname(const upb_def *d) { return d->fullname; }
+
+const char *upb_def_name(const upb_def *d) {
+  const char *p;
+
+  if (d->fullname == NULL) {
+    return NULL;
+  } else if ((p = strrchr(d->fullname, '.')) == NULL) {
+    /* No '.' in the name, return the full string. */
+    return d->fullname;
+  } else {
+    /* Return one past the last '.'. */
+    return p + 1;
+  }
+}
+
+bool upb_def_setfullname(upb_def *def, const char *fullname, upb_status *s) {
+  UPB_ASSERT(!upb_def_isfrozen(def));
+  if (!upb_isident(fullname, strlen(fullname), true, s)) {
+    return false;
+  }
+
+  fullname = upb_gstrdup(fullname);
+  if (!fullname) {
+    upb_upberr_setoom(s);
+    return false;
+  }
+
+  upb_gfree((void*)def->fullname);
+  def->fullname = fullname;
+  return true;
+}
+
+const upb_filedef *upb_def_file(const upb_def *d) { return d->file; }
+
+static bool upb_def_init(upb_def *def, upb_deftype_t type,
+                         const struct upb_refcounted_vtbl *vtbl,
+                         const void *owner) {
+  if (!upb_refcounted_init(upb_def_upcast_mutable(def), vtbl, owner)) return false;
+  def->type = type;
+  def->fullname = NULL;
+  def->came_from_user = false;
+  def->file = NULL;
+  return true;
+}
+
+static void upb_def_uninit(upb_def *def) {
+  upb_gfree((void*)def->fullname);
+}
+
+static const char *msgdef_name(const upb_msgdef *m) {
+  const char *name = upb_def_fullname(upb_msgdef_upcast(m));
+  return name ? name : "(anonymous)";
+}
+
+static bool upb_validate_field(upb_fielddef *f, upb_status *s) {
+  if (upb_fielddef_name(f) == NULL || upb_fielddef_number(f) == 0) {
+    upb_status_seterrmsg(s, "fielddef must have name and number set");
+    return false;
+  }
+
+  if (!f->type_is_set_) {
+    upb_status_seterrmsg(s, "fielddef type was not initialized");
+    return false;
+  }
+
+  if (upb_fielddef_lazy(f) &&
+      upb_fielddef_descriptortype(f) != UPB_DESCRIPTOR_TYPE_MESSAGE) {
+    upb_status_seterrmsg(s,
+                         "only length-delimited submessage fields may be lazy");
+    return false;
+  }
+
+  if (upb_fielddef_hassubdef(f)) {
+    const upb_def *subdef;
+
+    if (f->subdef_is_symbolic) {
+      upb_status_seterrf(s, "field '%s.%s' has not been resolved",
+                         msgdef_name(f->msg.def), upb_fielddef_name(f));
+      return false;
+    }
+
+    subdef = upb_fielddef_subdef(f);
+    if (subdef == NULL) {
+      upb_status_seterrf(s, "field %s.%s is missing required subdef",
+                         msgdef_name(f->msg.def), upb_fielddef_name(f));
+      return false;
+    }
+
+    if (!upb_def_isfrozen(subdef) && !subdef->came_from_user) {
+      upb_status_seterrf(s,
+                         "subdef of field %s.%s is not frozen or being frozen",
+                         msgdef_name(f->msg.def), upb_fielddef_name(f));
+      return false;
+    }
+  }
+
+  if (upb_fielddef_type(f) == UPB_TYPE_ENUM) {
+    bool has_default_name = upb_fielddef_enumhasdefaultstr(f);
+    bool has_default_number = upb_fielddef_enumhasdefaultint32(f);
+
+    /* Previously verified by upb_validate_enumdef(). */
+    UPB_ASSERT(upb_enumdef_numvals(upb_fielddef_enumsubdef(f)) > 0);
+
+    /* We've already validated that we have an associated enumdef and that it
+     * has at least one member, so at least one of these should be true.
+     * Because if the user didn't set anything, we'll pick up the enum's
+     * default, but if the user *did* set something we should at least pick up
+     * the one they set (int32 or string). */
+    UPB_ASSERT(has_default_name || has_default_number);
+
+    if (!has_default_name) {
+      upb_status_seterrf(s,
+                         "enum default for field %s.%s (%d) is not in the enum",
+                         msgdef_name(f->msg.def), upb_fielddef_name(f),
+                         upb_fielddef_defaultint32(f));
+      return false;
+    }
+
+    if (!has_default_number) {
+      upb_status_seterrf(s,
+                         "enum default for field %s.%s (%s) is not in the enum",
+                         msgdef_name(f->msg.def), upb_fielddef_name(f),
+                         upb_fielddef_defaultstr(f, NULL));
+      return false;
+    }
+
+    /* Lift the effective numeric default into the field's default slot, in case
+     * we were only getting it "by reference" from the enumdef. */
+    upb_fielddef_setdefaultint32(f, upb_fielddef_defaultint32(f));
+  }
+
+  /* Ensure that MapEntry submessages only appear as repeated fields, not
+   * optional/required (singular) fields. */
+  if (upb_fielddef_type(f) == UPB_TYPE_MESSAGE &&
+      upb_fielddef_msgsubdef(f) != NULL) {
+    const upb_msgdef *subdef = upb_fielddef_msgsubdef(f);
+    if (upb_msgdef_mapentry(subdef) && !upb_fielddef_isseq(f)) {
+      upb_status_seterrf(s,
+                         "Field %s refers to mapentry message but is not "
+                         "a repeated field",
+                         upb_fielddef_name(f) ? upb_fielddef_name(f) :
+                         "(unnamed)");
+      return false;
+    }
+  }
+
+  return true;
+}
+
+static bool upb_validate_enumdef(const upb_enumdef *e, upb_status *s) {
+  if (upb_enumdef_numvals(e) == 0) {
+    upb_status_seterrf(s, "enum %s has no members (must have at least one)",
+                       upb_enumdef_fullname(e));
+    return false;
+  }
+
+  return true;
+}
+
+/* All submessage fields are lower than all other fields.
+ * Secondly, fields are increasing in order. */
+uint32_t field_rank(const upb_fielddef *f) {
+  uint32_t ret = upb_fielddef_number(f);
+  const uint32_t high_bit = 1 << 30;
+  UPB_ASSERT(ret < high_bit);
+  if (!upb_fielddef_issubmsg(f))
+    ret |= high_bit;
+  return ret;
+}
+
+int cmp_fields(const void *p1, const void *p2) {
+  const upb_fielddef *f1 = *(upb_fielddef*const*)p1;
+  const upb_fielddef *f2 = *(upb_fielddef*const*)p2;
+  return field_rank(f1) - field_rank(f2);
+}
+
+static bool assign_msg_indices(upb_msgdef *m, upb_status *s) {
+  /* Sort fields.  upb internally relies on UPB_TYPE_MESSAGE fields having the
+   * lowest indexes, but we do not publicly guarantee this. */
+  upb_msg_field_iter j;
+  upb_msg_oneof_iter k;
+  int i;
+  uint32_t selector;
+  int n = upb_msgdef_numfields(m);
+  upb_fielddef **fields;
+
+  if (n == 0) {
+    m->selector_count = UPB_STATIC_SELECTOR_COUNT;
+    m->submsg_field_count = 0;
+    return true;
+  }
+
+  fields = upb_gmalloc(n * sizeof(*fields));
+  if (!fields) {
+    upb_upberr_setoom(s);
+    return false;
+  }
+
+  m->submsg_field_count = 0;
+  for(i = 0, upb_msg_field_begin(&j, m);
+      !upb_msg_field_done(&j);
+      upb_msg_field_next(&j), i++) {
+    upb_fielddef *f = upb_msg_iter_field(&j);
+    UPB_ASSERT(f->msg.def == m);
+    if (!upb_validate_field(f, s)) {
+      upb_gfree(fields);
+      return false;
+    }
+    if (upb_fielddef_issubmsg(f)) {
+      m->submsg_field_count++;
+    }
+    fields[i] = f;
+  }
+
+  qsort(fields, n, sizeof(*fields), cmp_fields);
+
+  selector = UPB_STATIC_SELECTOR_COUNT + m->submsg_field_count;
+  for (i = 0; i < n; i++) {
+    upb_fielddef *f = fields[i];
+    f->index_ = i;
+    f->selector_base = selector + upb_handlers_selectorbaseoffset(f);
+    selector += upb_handlers_selectorcount(f);
+  }
+  m->selector_count = selector;
+
+#ifndef NDEBUG
+  {
+    /* Verify that all selectors for the message are distinct. */
+#define TRY(type) \
+    if (upb_handlers_getselector(f, type, &sel)) upb_inttable_insert(&t, sel, v);
+
+    upb_inttable t;
+    upb_value v;
+    upb_selector_t sel;
+
+    upb_inttable_init(&t, UPB_CTYPE_BOOL);
+    v = upb_value_bool(true);
+    upb_inttable_insert(&t, UPB_STARTMSG_SELECTOR, v);
+    upb_inttable_insert(&t, UPB_ENDMSG_SELECTOR, v);
+    upb_inttable_insert(&t, UPB_UNKNOWN_SELECTOR, v);
+    for(upb_msg_field_begin(&j, m);
+        !upb_msg_field_done(&j);
+        upb_msg_field_next(&j)) {
+      upb_fielddef *f = upb_msg_iter_field(&j);
+      /* These calls will assert-fail in upb_table if the value already
+       * exists. */
+      TRY(UPB_HANDLER_INT32);
+      TRY(UPB_HANDLER_INT64)
+      TRY(UPB_HANDLER_UINT32)
+      TRY(UPB_HANDLER_UINT64)
+      TRY(UPB_HANDLER_FLOAT)
+      TRY(UPB_HANDLER_DOUBLE)
+      TRY(UPB_HANDLER_BOOL)
+      TRY(UPB_HANDLER_STARTSTR)
+      TRY(UPB_HANDLER_STRING)
+      TRY(UPB_HANDLER_ENDSTR)
+      TRY(UPB_HANDLER_STARTSUBMSG)
+      TRY(UPB_HANDLER_ENDSUBMSG)
+      TRY(UPB_HANDLER_STARTSEQ)
+      TRY(UPB_HANDLER_ENDSEQ)
+    }
+    upb_inttable_uninit(&t);
+  }
+#undef TRY
+#endif
+
+  for(upb_msg_oneof_begin(&k, m), i = 0;
+      !upb_msg_oneof_done(&k);
+      upb_msg_oneof_next(&k), i++) {
+    upb_oneofdef *o = upb_msg_iter_oneof(&k);
+    o->index = i;
+  }
+
+  upb_gfree(fields);
+  return true;
+}
+
+bool _upb_def_validate(upb_def *const*defs, size_t n, upb_status *s) {
+  size_t i;
+
+  /* First perform validation, in two passes so we can check that we have a
+   * transitive closure without needing to search. */
+  for (i = 0; i < n; i++) {
+    upb_def *def = defs[i];
+    if (upb_def_isfrozen(def)) {
+      /* Could relax this requirement if it's annoying. */
+      upb_status_seterrmsg(s, "def is already frozen");
+      goto err;
+    } else if (def->type == UPB_DEF_FIELD) {
+      upb_status_seterrmsg(s, "standalone fielddefs can not be frozen");
+      goto err;
+    } else {
+      /* Set now to detect transitive closure in the second pass. */
+      def->came_from_user = true;
+
+      if (def->type == UPB_DEF_ENUM &&
+          !upb_validate_enumdef(upb_dyncast_enumdef(def), s)) {
+        goto err;
+      }
+    }
+  }
+
+  /* Second pass of validation.  Also assign selector bases and indexes, and
+   * compact tables. */
+  for (i = 0; i < n; i++) {
+    upb_def *def = defs[i];
+    upb_msgdef *m = upb_dyncast_msgdef_mutable(def);
+    upb_enumdef *e = upb_dyncast_enumdef_mutable(def);
+    if (m) {
+      upb_inttable_compact(&m->itof);
+      if (!assign_msg_indices(m, s)) {
+        goto err;
+      }
+    } else if (e) {
+      upb_inttable_compact(&e->iton);
+    }
+  }
+
+  return true;
+
+err:
+  for (i = 0; i < n; i++) {
+    upb_def *def = defs[i];
+    def->came_from_user = false;
+  }
+  UPB_ASSERT(!(s && upb_ok(s)));
+  return false;
+}
+
+bool upb_def_freeze(upb_def *const* defs, size_t n, upb_status *s) {
+  /* Def graph contains FieldDefs between each MessageDef, so double the
+   * limit. */
+  const size_t maxdepth = UPB_MAX_MESSAGE_DEPTH * 2;
+
+  if (!_upb_def_validate(defs, n, s)) {
+    return false;
+  }
+
+
+  /* Validation all passed; freeze the objects. */
+  return upb_refcounted_freeze((upb_refcounted *const*)defs, n, s, maxdepth);
+}
+
+
+/* upb_enumdef ****************************************************************/
+
+static void visitenum(const upb_refcounted *r, upb_refcounted_visit *visit,
+                      void *closure) {
+  const upb_enumdef *e = (const upb_enumdef*)r;
+  const upb_def *def = upb_enumdef_upcast(e);
+  if (upb_def_file(def)) {
+    visit(r, upb_filedef_upcast(upb_def_file(def)), closure);
+  }
+}
+
+static void freeenum(upb_refcounted *r) {
+  upb_enumdef *e = (upb_enumdef*)r;
+  upb_inttable_iter i;
+  upb_inttable_begin(&i, &e->iton);
+  for( ; !upb_inttable_done(&i); upb_inttable_next(&i)) {
+    /* To clean up the upb_gstrdup() from upb_enumdef_addval(). */
+    upb_gfree(upb_value_getcstr(upb_inttable_iter_value(&i)));
+  }
+  upb_strtable_uninit(&e->ntoi);
+  upb_inttable_uninit(&e->iton);
+  upb_def_uninit(upb_enumdef_upcast_mutable(e));
+  upb_gfree(e);
+}
+
+const struct upb_refcounted_vtbl upb_enumdef_vtbl = {&visitenum, &freeenum};
+
+upb_enumdef *upb_enumdef_new(const void *owner) {
+  upb_enumdef *e = upb_gmalloc(sizeof(*e));
+  if (!e) return NULL;
+
+  if (!upb_def_init(upb_enumdef_upcast_mutable(e), UPB_DEF_ENUM,
+                    &upb_enumdef_vtbl, owner)) {
+    goto err2;
+  }
+
+  if (!upb_strtable_init(&e->ntoi, UPB_CTYPE_INT32)) goto err2;
+  if (!upb_inttable_init(&e->iton, UPB_CTYPE_CSTR)) goto err1;
+  return e;
+
+err1:
+  upb_strtable_uninit(&e->ntoi);
+err2:
+  upb_gfree(e);
+  return NULL;
+}
+
+bool upb_enumdef_freeze(upb_enumdef *e, upb_status *status) {
+  upb_def *d = upb_enumdef_upcast_mutable(e);
+  return upb_def_freeze(&d, 1, status);
+}
+
+const char *upb_enumdef_fullname(const upb_enumdef *e) {
+  return upb_def_fullname(upb_enumdef_upcast(e));
+}
+
+const char *upb_enumdef_name(const upb_enumdef *e) {
+  return upb_def_name(upb_enumdef_upcast(e));
+}
+
+bool upb_enumdef_setfullname(upb_enumdef *e, const char *fullname,
+                             upb_status *s) {
+  return upb_def_setfullname(upb_enumdef_upcast_mutable(e), fullname, s);
+}
+
+bool upb_enumdef_addval(upb_enumdef *e, const char *name, int32_t num,
+                        upb_status *status) {
+  char *name2;
+
+  if (!upb_isident(name, strlen(name), false, status)) {
+    return false;
+  }
+
+  if (upb_enumdef_ntoiz(e, name, NULL)) {
+    upb_status_seterrf(status, "name '%s' is already defined", name);
+    return false;
+  }
+
+  if (!upb_strtable_insert(&e->ntoi, name, upb_value_int32(num))) {
+    upb_status_seterrmsg(status, "out of memory");
+    return false;
+  }
+
+  if (!upb_inttable_lookup(&e->iton, num, NULL)) {
+    name2 = upb_gstrdup(name);
+    if (!name2 || !upb_inttable_insert(&e->iton, num, upb_value_cstr(name2))) {
+      upb_status_seterrmsg(status, "out of memory");
+      upb_strtable_remove(&e->ntoi, name, NULL);
+      return false;
+    }
+  }
+
+  if (upb_enumdef_numvals(e) == 1) {
+    bool ok = upb_enumdef_setdefault(e, num, NULL);
+    UPB_ASSERT(ok);
+  }
+
+  return true;
+}
+
+int32_t upb_enumdef_default(const upb_enumdef *e) {
+  UPB_ASSERT(upb_enumdef_iton(e, e->defaultval));
+  return e->defaultval;
+}
+
+bool upb_enumdef_setdefault(upb_enumdef *e, int32_t val, upb_status *s) {
+  UPB_ASSERT(!upb_enumdef_isfrozen(e));
+  if (!upb_enumdef_iton(e, val)) {
+    upb_status_seterrf(s, "number '%d' is not in the enum.", val);
+    return false;
+  }
+  e->defaultval = val;
+  return true;
+}
+
+int upb_enumdef_numvals(const upb_enumdef *e) {
+  return upb_strtable_count(&e->ntoi);
+}
+
+void upb_enum_begin(upb_enum_iter *i, const upb_enumdef *e) {
+  /* We iterate over the ntoi table, to account for duplicate numbers. */
+  upb_strtable_begin(i, &e->ntoi);
+}
+
+void upb_enum_next(upb_enum_iter *iter) { upb_strtable_next(iter); }
+bool upb_enum_done(upb_enum_iter *iter) { return upb_strtable_done(iter); }
+
+bool upb_enumdef_ntoi(const upb_enumdef *def, const char *name,
+                      size_t len, int32_t *num) {
+  upb_value v;
+  if (!upb_strtable_lookup2(&def->ntoi, name, len, &v)) {
+    return false;
+  }
+  if (num) *num = upb_value_getint32(v);
+  return true;
+}
+
+const char *upb_enumdef_iton(const upb_enumdef *def, int32_t num) {
+  upb_value v;
+  return upb_inttable_lookup32(&def->iton, num, &v) ?
+      upb_value_getcstr(v) : NULL;
+}
+
+const char *upb_enum_iter_name(upb_enum_iter *iter) {
+  return upb_strtable_iter_key(iter);
+}
+
+int32_t upb_enum_iter_number(upb_enum_iter *iter) {
+  return upb_value_getint32(upb_strtable_iter_value(iter));
+}
+
+
+/* upb_fielddef ***************************************************************/
+
+static void upb_fielddef_init_default(upb_fielddef *f);
+
+static void upb_fielddef_uninit_default(upb_fielddef *f) {
+  if (f->type_is_set_ && f->default_is_string && f->defaultval.bytes)
+    freestr(f->defaultval.bytes);
+}
+
+const char *upb_fielddef_fullname(const upb_fielddef *e) {
+  return upb_def_fullname(upb_fielddef_upcast(e));
+}
+
+static void visitfield(const upb_refcounted *r, upb_refcounted_visit *visit,
+                       void *closure) {
+  const upb_fielddef *f = (const upb_fielddef*)r;
+  const upb_def *def = upb_fielddef_upcast(f);
+  if (upb_fielddef_containingtype(f)) {
+    visit(r, upb_msgdef_upcast2(upb_fielddef_containingtype(f)), closure);
+  }
+  if (upb_fielddef_containingoneof(f)) {
+    visit(r, upb_oneofdef_upcast(upb_fielddef_containingoneof(f)), closure);
+  }
+  if (upb_fielddef_subdef(f)) {
+    visit(r, upb_def_upcast(upb_fielddef_subdef(f)), closure);
+  }
+  if (upb_def_file(def)) {
+    visit(r, upb_filedef_upcast(upb_def_file(def)), closure);
+  }
+}
+
+static void freefield(upb_refcounted *r) {
+  upb_fielddef *f = (upb_fielddef*)r;
+  upb_fielddef_uninit_default(f);
+  if (f->subdef_is_symbolic)
+    upb_gfree(f->sub.name);
+  upb_def_uninit(upb_fielddef_upcast_mutable(f));
+  upb_gfree(f);
+}
+
+static const char *enumdefaultstr(const upb_fielddef *f) {
+  const upb_enumdef *e;
+  UPB_ASSERT(f->type_is_set_ && f->type_ == UPB_TYPE_ENUM);
+  e = upb_fielddef_enumsubdef(f);
+  if (f->default_is_string && f->defaultval.bytes) {
+    /* Default was explicitly set as a string. */
+    str_t *s = f->defaultval.bytes;
+    return s->str;
+  } else if (e) {
+    if (!f->default_is_string) {
+      /* Default was explicitly set as an integer; look it up in enumdef. */
+      const char *name = upb_enumdef_iton(e, f->defaultval.sint);
+      if (name) {
+        return name;
+      }
+    } else {
+      /* Default is completely unset; pull enumdef default. */
+      if (upb_enumdef_numvals(e) > 0) {
+        const char *name = upb_enumdef_iton(e, upb_enumdef_default(e));
+        UPB_ASSERT(name);
+        return name;
+      }
+    }
+  }
+  return NULL;
+}
+
+static bool enumdefaultint32(const upb_fielddef *f, int32_t *val) {
+  const upb_enumdef *e;
+  UPB_ASSERT(f->type_is_set_ && f->type_ == UPB_TYPE_ENUM);
+  e = upb_fielddef_enumsubdef(f);
+  if (!f->default_is_string) {
+    /* Default was explicitly set as an integer. */
+    *val = f->defaultval.sint;
+    return true;
+  } else if (e) {
+    if (f->defaultval.bytes) {
+      /* Default was explicitly set as a str; try to lookup corresponding int. */
+      str_t *s = f->defaultval.bytes;
+      if (upb_enumdef_ntoiz(e, s->str, val)) {
+        return true;
+      }
+    } else {
+      /* Default is unset; try to pull in enumdef default. */
+      if (upb_enumdef_numvals(e) > 0) {
+        *val = upb_enumdef_default(e);
+        return true;
+      }
+    }
+  }
+  return false;
+}
+
+const struct upb_refcounted_vtbl upb_fielddef_vtbl = {visitfield, freefield};
+
+upb_fielddef *upb_fielddef_new(const void *o) {
+  upb_fielddef *f = upb_gmalloc(sizeof(*f));
+  if (!f) return NULL;
+  if (!upb_def_init(upb_fielddef_upcast_mutable(f), UPB_DEF_FIELD,
+                    &upb_fielddef_vtbl, o)) {
+    upb_gfree(f);
+    return NULL;
+  }
+  f->msg.def = NULL;
+  f->sub.def = NULL;
+  f->oneof = NULL;
+  f->subdef_is_symbolic = false;
+  f->msg_is_symbolic = false;
+  f->label_ = UPB_LABEL_OPTIONAL;
+  f->type_ = UPB_TYPE_INT32;
+  f->number_ = 0;
+  f->type_is_set_ = false;
+  f->tagdelim = false;
+  f->is_extension_ = false;
+  f->lazy_ = false;
+  f->packed_ = true;
+
+  /* For the moment we default this to UPB_INTFMT_VARIABLE, since it will work
+   * with all integer types and is in some since more "default" since the most
+   * normal-looking proto2 types int32/int64/uint32/uint64 use variable.
+   *
+   * Other options to consider:
+   * - there is no default; users must set this manually (like type).
+   * - default signed integers to UPB_INTFMT_ZIGZAG, since it's more likely to
+   *   be an optimal default for signed integers. */
+  f->intfmt = UPB_INTFMT_VARIABLE;
+  return f;
+}
+
+bool upb_fielddef_typeisset(const upb_fielddef *f) {
+  return f->type_is_set_;
+}
+
+upb_fieldtype_t upb_fielddef_type(const upb_fielddef *f) {
+  UPB_ASSERT(f->type_is_set_);
+  return f->type_;
+}
+
+uint32_t upb_fielddef_index(const upb_fielddef *f) {
+  return f->index_;
+}
+
+upb_label_t upb_fielddef_label(const upb_fielddef *f) {
+  return f->label_;
+}
+
+upb_intfmt_t upb_fielddef_intfmt(const upb_fielddef *f) {
+  return f->intfmt;
+}
+
+bool upb_fielddef_istagdelim(const upb_fielddef *f) {
+  return f->tagdelim;
+}
+
+uint32_t upb_fielddef_number(const upb_fielddef *f) {
+  return f->number_;
+}
+
+bool upb_fielddef_isextension(const upb_fielddef *f) {
+  return f->is_extension_;
+}
+
+bool upb_fielddef_lazy(const upb_fielddef *f) {
+  return f->lazy_;
+}
+
+bool upb_fielddef_packed(const upb_fielddef *f) {
+  return f->packed_;
+}
+
+const char *upb_fielddef_name(const upb_fielddef *f) {
+  return upb_def_fullname(upb_fielddef_upcast(f));
+}
+
+size_t upb_fielddef_getjsonname(const upb_fielddef *f, char *buf, size_t len) {
+  const char *name = upb_fielddef_name(f);
+  size_t src, dst = 0;
+  bool ucase_next = false;
+
+#define WRITE(byte) \
+  ++dst; \
+  if (dst < len) buf[dst - 1] = byte; \
+  else if (dst == len) buf[dst - 1] = '\0'
+
+  if (!name) {
+    WRITE('\0');
+    return 0;
+  }
+
+  /* Implement the transformation as described in the spec:
+   *   1. upper case all letters after an underscore.
+   *   2. remove all underscores.
+   */
+  for (src = 0; name[src]; src++) {
+    if (name[src] == '_') {
+      ucase_next = true;
+      continue;
+    }
+
+    if (ucase_next) {
+      WRITE(toupper(name[src]));
+      ucase_next = false;
+    } else {
+      WRITE(name[src]);
+    }
+  }
+
+  WRITE('\0');
+  return dst;
+
+#undef WRITE
+}
+
+const upb_msgdef *upb_fielddef_containingtype(const upb_fielddef *f) {
+  return f->msg_is_symbolic ? NULL : f->msg.def;
+}
+
+const upb_oneofdef *upb_fielddef_containingoneof(const upb_fielddef *f) {
+  return f->oneof;
+}
+
+upb_msgdef *upb_fielddef_containingtype_mutable(upb_fielddef *f) {
+  return (upb_msgdef*)upb_fielddef_containingtype(f);
+}
+
+const char *upb_fielddef_containingtypename(upb_fielddef *f) {
+  return f->msg_is_symbolic ? f->msg.name : NULL;
+}
+
+static void release_containingtype(upb_fielddef *f) {
+  if (f->msg_is_symbolic) upb_gfree(f->msg.name);
+}
+
+bool upb_fielddef_setcontainingtypename(upb_fielddef *f, const char *name,
+                                        upb_status *s) {
+  char *name_copy;
+  UPB_ASSERT(!upb_fielddef_isfrozen(f));
+  if (upb_fielddef_containingtype(f)) {
+    upb_status_seterrmsg(s, "field has already been added to a message.");
+    return false;
+  }
+  /* TODO: validate name (upb_isident() doesn't quite work atm because this name
+   * may have a leading "."). */
+
+  name_copy = upb_gstrdup(name);
+  if (!name_copy) {
+    upb_upberr_setoom(s);
+    return false;
+  }
+
+  release_containingtype(f);
+  f->msg.name = name_copy;
+  f->msg_is_symbolic = true;
+  return true;
+}
+
+bool upb_fielddef_setname(upb_fielddef *f, const char *name, upb_status *s) {
+  if (upb_fielddef_containingtype(f) || upb_fielddef_containingoneof(f)) {
+    upb_status_seterrmsg(s, "Already added to message or oneof");
+    return false;
+  }
+  return upb_def_setfullname(upb_fielddef_upcast_mutable(f), name, s);
+}
+
+static void chkdefaulttype(const upb_fielddef *f, upb_fieldtype_t type) {
+  UPB_UNUSED(f);
+  UPB_UNUSED(type);
+  UPB_ASSERT(f->type_is_set_ && upb_fielddef_type(f) == type);
+}
+
+int64_t upb_fielddef_defaultint64(const upb_fielddef *f) {
+  chkdefaulttype(f, UPB_TYPE_INT64);
+  return f->defaultval.sint;
+}
+
+int32_t upb_fielddef_defaultint32(const upb_fielddef *f) {
+  if (f->type_is_set_ && upb_fielddef_type(f) == UPB_TYPE_ENUM) {
+    int32_t val;
+    bool ok = enumdefaultint32(f, &val);
+    UPB_ASSERT(ok);
+    return val;
+  } else {
+    chkdefaulttype(f, UPB_TYPE_INT32);
+    return f->defaultval.sint;
+  }
+}
+
+uint64_t upb_fielddef_defaultuint64(const upb_fielddef *f) {
+  chkdefaulttype(f, UPB_TYPE_UINT64);
+  return f->defaultval.uint;
+}
+
+uint32_t upb_fielddef_defaultuint32(const upb_fielddef *f) {
+  chkdefaulttype(f, UPB_TYPE_UINT32);
+  return f->defaultval.uint;
+}
+
+bool upb_fielddef_defaultbool(const upb_fielddef *f) {
+  chkdefaulttype(f, UPB_TYPE_BOOL);
+  return f->defaultval.uint;
+}
+
+float upb_fielddef_defaultfloat(const upb_fielddef *f) {
+  chkdefaulttype(f, UPB_TYPE_FLOAT);
+  return f->defaultval.flt;
+}
+
+double upb_fielddef_defaultdouble(const upb_fielddef *f) {
+  chkdefaulttype(f, UPB_TYPE_DOUBLE);
+  return f->defaultval.dbl;
+}
+
+const char *upb_fielddef_defaultstr(const upb_fielddef *f, size_t *len) {
+  UPB_ASSERT(f->type_is_set_);
+  UPB_ASSERT(upb_fielddef_type(f) == UPB_TYPE_STRING ||
+         upb_fielddef_type(f) == UPB_TYPE_BYTES ||
+         upb_fielddef_type(f) == UPB_TYPE_ENUM);
+
+  if (upb_fielddef_type(f) == UPB_TYPE_ENUM) {
+    const char *ret = enumdefaultstr(f);
+    UPB_ASSERT(ret);
+    /* Enum defaults can't have embedded NULLs. */
+    if (len) *len = strlen(ret);
+    return ret;
+  }
+
+  if (f->default_is_string) {
+    str_t *str = f->defaultval.bytes;
+    if (len) *len = str->len;
+    return str->str;
+  }
+
+  return NULL;
+}
+
+static void upb_fielddef_init_default(upb_fielddef *f) {
+  f->default_is_string = false;
+  switch (upb_fielddef_type(f)) {
+    case UPB_TYPE_DOUBLE: f->defaultval.dbl = 0; break;
+    case UPB_TYPE_FLOAT: f->defaultval.flt = 0; break;
+    case UPB_TYPE_INT32:
+    case UPB_TYPE_INT64: f->defaultval.sint = 0; break;
+    case UPB_TYPE_UINT64:
+    case UPB_TYPE_UINT32:
+    case UPB_TYPE_BOOL: f->defaultval.uint = 0; break;
+    case UPB_TYPE_STRING:
+    case UPB_TYPE_BYTES:
+      f->defaultval.bytes = newstr("", 0);
+      f->default_is_string = true;
+      break;
+    case UPB_TYPE_MESSAGE: break;
+    case UPB_TYPE_ENUM:
+      /* This is our special sentinel that indicates "not set" for an enum. */
+      f->default_is_string = true;
+      f->defaultval.bytes = NULL;
+      break;
+  }
+}
+
+const upb_def *upb_fielddef_subdef(const upb_fielddef *f) {
+  return f->subdef_is_symbolic ? NULL : f->sub.def;
+}
+
+const upb_msgdef *upb_fielddef_msgsubdef(const upb_fielddef *f) {
+  const upb_def *def = upb_fielddef_subdef(f);
+  return def ? upb_dyncast_msgdef(def) : NULL;
+}
+
+const upb_enumdef *upb_fielddef_enumsubdef(const upb_fielddef *f) {
+  const upb_def *def = upb_fielddef_subdef(f);
+  return def ? upb_dyncast_enumdef(def) : NULL;
+}
+
+upb_def *upb_fielddef_subdef_mutable(upb_fielddef *f) {
+  return (upb_def*)upb_fielddef_subdef(f);
+}
+
+const char *upb_fielddef_subdefname(const upb_fielddef *f) {
+  if (f->subdef_is_symbolic) {
+    return f->sub.name;
+  } else if (f->sub.def) {
+    return upb_def_fullname(f->sub.def);
+  } else {
+    return NULL;
+  }
+}
+
+bool upb_fielddef_setnumber(upb_fielddef *f, uint32_t number, upb_status *s) {
+  if (upb_fielddef_containingtype(f)) {
+    upb_status_seterrmsg(
+        s, "cannot change field number after adding to a message");
+    return false;
+  }
+  if (number == 0 || number > UPB_MAX_FIELDNUMBER) {
+    upb_status_seterrf(s, "invalid field number (%u)", number);
+    return false;
+  }
+  f->number_ = number;
+  return true;
+}
+
+void upb_fielddef_settype(upb_fielddef *f, upb_fieldtype_t type) {
+  UPB_ASSERT(!upb_fielddef_isfrozen(f));
+  UPB_ASSERT(upb_fielddef_checktype(type));
+  upb_fielddef_uninit_default(f);
+  f->type_ = type;
+  f->type_is_set_ = true;
+  upb_fielddef_init_default(f);
+}
+
+void upb_fielddef_setdescriptortype(upb_fielddef *f, int type) {
+  UPB_ASSERT(!upb_fielddef_isfrozen(f));
+  switch (type) {
+    case UPB_DESCRIPTOR_TYPE_DOUBLE:
+      upb_fielddef_settype(f, UPB_TYPE_DOUBLE);
+      break;
+    case UPB_DESCRIPTOR_TYPE_FLOAT:
+      upb_fielddef_settype(f, UPB_TYPE_FLOAT);
+      break;
+    case UPB_DESCRIPTOR_TYPE_INT64:
+    case UPB_DESCRIPTOR_TYPE_SFIXED64:
+    case UPB_DESCRIPTOR_TYPE_SINT64:
+      upb_fielddef_settype(f, UPB_TYPE_INT64);
+      break;
+    case UPB_DESCRIPTOR_TYPE_UINT64:
+    case UPB_DESCRIPTOR_TYPE_FIXED64:
+      upb_fielddef_settype(f, UPB_TYPE_UINT64);
+      break;
+    case UPB_DESCRIPTOR_TYPE_INT32:
+    case UPB_DESCRIPTOR_TYPE_SFIXED32:
+    case UPB_DESCRIPTOR_TYPE_SINT32:
+      upb_fielddef_settype(f, UPB_TYPE_INT32);
+      break;
+    case UPB_DESCRIPTOR_TYPE_UINT32:
+    case UPB_DESCRIPTOR_TYPE_FIXED32:
+      upb_fielddef_settype(f, UPB_TYPE_UINT32);
+      break;
+    case UPB_DESCRIPTOR_TYPE_BOOL:
+      upb_fielddef_settype(f, UPB_TYPE_BOOL);
+      break;
+    case UPB_DESCRIPTOR_TYPE_STRING:
+      upb_fielddef_settype(f, UPB_TYPE_STRING);
+      break;
+    case UPB_DESCRIPTOR_TYPE_BYTES:
+      upb_fielddef_settype(f, UPB_TYPE_BYTES);
+      break;
+    case UPB_DESCRIPTOR_TYPE_GROUP:
+    case UPB_DESCRIPTOR_TYPE_MESSAGE:
+      upb_fielddef_settype(f, UPB_TYPE_MESSAGE);
+      break;
+    case UPB_DESCRIPTOR_TYPE_ENUM:
+      upb_fielddef_settype(f, UPB_TYPE_ENUM);
+      break;
+    default: UPB_ASSERT(false);
+  }
+
+  if (type == UPB_DESCRIPTOR_TYPE_FIXED64 ||
+      type == UPB_DESCRIPTOR_TYPE_FIXED32 ||
+      type == UPB_DESCRIPTOR_TYPE_SFIXED64 ||
+      type == UPB_DESCRIPTOR_TYPE_SFIXED32) {
+    upb_fielddef_setintfmt(f, UPB_INTFMT_FIXED);
+  } else if (type == UPB_DESCRIPTOR_TYPE_SINT64 ||
+             type == UPB_DESCRIPTOR_TYPE_SINT32) {
+    upb_fielddef_setintfmt(f, UPB_INTFMT_ZIGZAG);
+  } else {
+    upb_fielddef_setintfmt(f, UPB_INTFMT_VARIABLE);
+  }
+
+  upb_fielddef_settagdelim(f, type == UPB_DESCRIPTOR_TYPE_GROUP);
+}
+
+upb_descriptortype_t upb_fielddef_descriptortype(const upb_fielddef *f) {
+  switch (upb_fielddef_type(f)) {
+    case UPB_TYPE_FLOAT:  return UPB_DESCRIPTOR_TYPE_FLOAT;
+    case UPB_TYPE_DOUBLE: return UPB_DESCRIPTOR_TYPE_DOUBLE;
+    case UPB_TYPE_BOOL:   return UPB_DESCRIPTOR_TYPE_BOOL;
+    case UPB_TYPE_STRING: return UPB_DESCRIPTOR_TYPE_STRING;
+    case UPB_TYPE_BYTES:  return UPB_DESCRIPTOR_TYPE_BYTES;
+    case UPB_TYPE_ENUM:   return UPB_DESCRIPTOR_TYPE_ENUM;
+    case UPB_TYPE_INT32:
+      switch (upb_fielddef_intfmt(f)) {
+        case UPB_INTFMT_VARIABLE: return UPB_DESCRIPTOR_TYPE_INT32;
+        case UPB_INTFMT_FIXED:    return UPB_DESCRIPTOR_TYPE_SFIXED32;
+        case UPB_INTFMT_ZIGZAG:   return UPB_DESCRIPTOR_TYPE_SINT32;
+      }
+    case UPB_TYPE_INT64:
+      switch (upb_fielddef_intfmt(f)) {
+        case UPB_INTFMT_VARIABLE: return UPB_DESCRIPTOR_TYPE_INT64;
+        case UPB_INTFMT_FIXED:    return UPB_DESCRIPTOR_TYPE_SFIXED64;
+        case UPB_INTFMT_ZIGZAG:   return UPB_DESCRIPTOR_TYPE_SINT64;
+      }
+    case UPB_TYPE_UINT32:
+      switch (upb_fielddef_intfmt(f)) {
+        case UPB_INTFMT_VARIABLE: return UPB_DESCRIPTOR_TYPE_UINT32;
+        case UPB_INTFMT_FIXED:    return UPB_DESCRIPTOR_TYPE_FIXED32;
+        case UPB_INTFMT_ZIGZAG:   return -1;
+      }
+    case UPB_TYPE_UINT64:
+      switch (upb_fielddef_intfmt(f)) {
+        case UPB_INTFMT_VARIABLE: return UPB_DESCRIPTOR_TYPE_UINT64;
+        case UPB_INTFMT_FIXED:    return UPB_DESCRIPTOR_TYPE_FIXED64;
+        case UPB_INTFMT_ZIGZAG:   return -1;
+      }
+    case UPB_TYPE_MESSAGE:
+      return upb_fielddef_istagdelim(f) ?
+          UPB_DESCRIPTOR_TYPE_GROUP : UPB_DESCRIPTOR_TYPE_MESSAGE;
+  }
+  return 0;
+}
+
+void upb_fielddef_setisextension(upb_fielddef *f, bool is_extension) {
+  UPB_ASSERT(!upb_fielddef_isfrozen(f));
+  f->is_extension_ = is_extension;
+}
+
+void upb_fielddef_setlazy(upb_fielddef *f, bool lazy) {
+  UPB_ASSERT(!upb_fielddef_isfrozen(f));
+  f->lazy_ = lazy;
+}
+
+void upb_fielddef_setpacked(upb_fielddef *f, bool packed) {
+  UPB_ASSERT(!upb_fielddef_isfrozen(f));
+  f->packed_ = packed;
+}
+
+void upb_fielddef_setlabel(upb_fielddef *f, upb_label_t label) {
+  UPB_ASSERT(!upb_fielddef_isfrozen(f));
+  UPB_ASSERT(upb_fielddef_checklabel(label));
+  f->label_ = label;
+}
+
+void upb_fielddef_setintfmt(upb_fielddef *f, upb_intfmt_t fmt) {
+  UPB_ASSERT(!upb_fielddef_isfrozen(f));
+  UPB_ASSERT(upb_fielddef_checkintfmt(fmt));
+  f->intfmt = fmt;
+}
+
+void upb_fielddef_settagdelim(upb_fielddef *f, bool tag_delim) {
+  UPB_ASSERT(!upb_fielddef_isfrozen(f));
+  f->tagdelim = tag_delim;
+  f->tagdelim = tag_delim;
+}
+
+static bool checksetdefault(upb_fielddef *f, upb_fieldtype_t type) {
+  if (!f->type_is_set_ || upb_fielddef_isfrozen(f) ||
+      upb_fielddef_type(f) != type) {
+    UPB_ASSERT(false);
+    return false;
+  }
+  if (f->default_is_string) {
+    str_t *s = f->defaultval.bytes;
+    UPB_ASSERT(s || type == UPB_TYPE_ENUM);
+    if (s) freestr(s);
+  }
+  f->default_is_string = false;
+  return true;
+}
+
+void upb_fielddef_setdefaultint64(upb_fielddef *f, int64_t value) {
+  if (checksetdefault(f, UPB_TYPE_INT64))
+    f->defaultval.sint = value;
+}
+
+void upb_fielddef_setdefaultint32(upb_fielddef *f, int32_t value) {
+  if ((upb_fielddef_type(f) == UPB_TYPE_ENUM &&
+       checksetdefault(f, UPB_TYPE_ENUM)) ||
+      checksetdefault(f, UPB_TYPE_INT32)) {
+    f->defaultval.sint = value;
+  }
+}
+
+void upb_fielddef_setdefaultuint64(upb_fielddef *f, uint64_t value) {
+  if (checksetdefault(f, UPB_TYPE_UINT64))
+    f->defaultval.uint = value;
+}
+
+void upb_fielddef_setdefaultuint32(upb_fielddef *f, uint32_t value) {
+  if (checksetdefault(f, UPB_TYPE_UINT32))
+    f->defaultval.uint = value;
+}
+
+void upb_fielddef_setdefaultbool(upb_fielddef *f, bool value) {
+  if (checksetdefault(f, UPB_TYPE_BOOL))
+    f->defaultval.uint = value;
+}
+
+void upb_fielddef_setdefaultfloat(upb_fielddef *f, float value) {
+  if (checksetdefault(f, UPB_TYPE_FLOAT))
+    f->defaultval.flt = value;
+}
+
+void upb_fielddef_setdefaultdouble(upb_fielddef *f, double value) {
+  if (checksetdefault(f, UPB_TYPE_DOUBLE))
+    f->defaultval.dbl = value;
+}
+
+bool upb_fielddef_setdefaultstr(upb_fielddef *f, const void *str, size_t len,
+                                upb_status *s) {
+  str_t *str2;
+  UPB_ASSERT(upb_fielddef_isstring(f) || f->type_ == UPB_TYPE_ENUM);
+  if (f->type_ == UPB_TYPE_ENUM && !upb_isident(str, len, false, s))
+    return false;
+
+  if (f->default_is_string) {
+    str_t *s = f->defaultval.bytes;
+    UPB_ASSERT(s || f->type_ == UPB_TYPE_ENUM);
+    if (s) freestr(s);
+  } else {
+    UPB_ASSERT(f->type_ == UPB_TYPE_ENUM);
+  }
+
+  str2 = newstr(str, len);
+  f->defaultval.bytes = str2;
+  f->default_is_string = true;
+  return true;
+}
+
+void upb_fielddef_setdefaultcstr(upb_fielddef *f, const char *str,
+                                 upb_status *s) {
+  UPB_ASSERT(f->type_is_set_);
+  upb_fielddef_setdefaultstr(f, str, str ? strlen(str) : 0, s);
+}
+
+bool upb_fielddef_enumhasdefaultint32(const upb_fielddef *f) {
+  int32_t val;
+  UPB_ASSERT(f->type_is_set_ && f->type_ == UPB_TYPE_ENUM);
+  return enumdefaultint32(f, &val);
+}
+
+bool upb_fielddef_enumhasdefaultstr(const upb_fielddef *f) {
+  UPB_ASSERT(f->type_is_set_ && f->type_ == UPB_TYPE_ENUM);
+  return enumdefaultstr(f) != NULL;
+}
+
+static bool upb_subdef_typecheck(upb_fielddef *f, const upb_def *subdef,
+                                 upb_status *s) {
+  if (f->type_ == UPB_TYPE_MESSAGE) {
+    if (upb_dyncast_msgdef(subdef)) return true;
+    upb_status_seterrmsg(s, "invalid subdef type for this submessage field");
+    return false;
+  } else if (f->type_ == UPB_TYPE_ENUM) {
+    if (upb_dyncast_enumdef(subdef)) return true;
+    upb_status_seterrmsg(s, "invalid subdef type for this enum field");
+    return false;
+  } else {
+    upb_status_seterrmsg(s, "only message and enum fields can have a subdef");
+    return false;
+  }
+}
+
+static void release_subdef(upb_fielddef *f) {
+  if (f->subdef_is_symbolic) {
+    upb_gfree(f->sub.name);
+  } else if (f->sub.def) {
+    upb_unref2(f->sub.def, f);
+  }
+}
+
+bool upb_fielddef_setsubdef(upb_fielddef *f, const upb_def *subdef,
+                            upb_status *s) {
+  UPB_ASSERT(!upb_fielddef_isfrozen(f));
+  UPB_ASSERT(upb_fielddef_hassubdef(f));
+  if (subdef && !upb_subdef_typecheck(f, subdef, s)) return false;
+  release_subdef(f);
+  f->sub.def = subdef;
+  f->subdef_is_symbolic = false;
+  if (f->sub.def) upb_ref2(f->sub.def, f);
+  return true;
+}
+
+bool upb_fielddef_setmsgsubdef(upb_fielddef *f, const upb_msgdef *subdef,
+                               upb_status *s) {
+  return upb_fielddef_setsubdef(f, upb_msgdef_upcast(subdef), s);
+}
+
+bool upb_fielddef_setenumsubdef(upb_fielddef *f, const upb_enumdef *subdef,
+                                upb_status *s) {
+  return upb_fielddef_setsubdef(f, upb_enumdef_upcast(subdef), s);
+}
+
+bool upb_fielddef_setsubdefname(upb_fielddef *f, const char *name,
+                                upb_status *s) {
+  char *name_copy;
+  UPB_ASSERT(!upb_fielddef_isfrozen(f));
+  if (!upb_fielddef_hassubdef(f)) {
+    upb_status_seterrmsg(s, "field type does not accept a subdef");
+    return false;
+  }
+
+  name_copy = upb_gstrdup(name);
+  if (!name_copy) {
+    upb_upberr_setoom(s);
+    return false;
+  }
+
+  /* TODO: validate name (upb_isident() doesn't quite work atm because this name
+   * may have a leading "."). */
+  release_subdef(f);
+  f->sub.name = name_copy;
+  f->subdef_is_symbolic = true;
+  return true;
+}
+
+bool upb_fielddef_issubmsg(const upb_fielddef *f) {
+  return upb_fielddef_type(f) == UPB_TYPE_MESSAGE;
+}
+
+bool upb_fielddef_isstring(const upb_fielddef *f) {
+  return upb_fielddef_type(f) == UPB_TYPE_STRING ||
+         upb_fielddef_type(f) == UPB_TYPE_BYTES;
+}
+
+bool upb_fielddef_isseq(const upb_fielddef *f) {
+  return upb_fielddef_label(f) == UPB_LABEL_REPEATED;
+}
+
+bool upb_fielddef_isprimitive(const upb_fielddef *f) {
+  return !upb_fielddef_isstring(f) && !upb_fielddef_issubmsg(f);
+}
+
+bool upb_fielddef_ismap(const upb_fielddef *f) {
+  return upb_fielddef_isseq(f) && upb_fielddef_issubmsg(f) &&
+         upb_msgdef_mapentry(upb_fielddef_msgsubdef(f));
+}
+
+bool upb_fielddef_haspresence(const upb_fielddef *f) {
+  if (upb_fielddef_isseq(f)) return false;
+  if (upb_fielddef_issubmsg(f)) return true;
+
+  /* Primitive field: return true unless there is a message that specifies
+   * presence should not exist. */
+  if (f->msg_is_symbolic || !f->msg.def) return true;
+  return f->msg.def->syntax == UPB_SYNTAX_PROTO2;
+}
+
+bool upb_fielddef_hassubdef(const upb_fielddef *f) {
+  return upb_fielddef_issubmsg(f) || upb_fielddef_type(f) == UPB_TYPE_ENUM;
+}
+
+static bool between(int32_t x, int32_t low, int32_t high) {
+  return x >= low && x <= high;
+}
+
+bool upb_fielddef_checklabel(int32_t label) { return between(label, 1, 3); }
+bool upb_fielddef_checktype(int32_t type) { return between(type, 1, 11); }
+bool upb_fielddef_checkintfmt(int32_t fmt) { return between(fmt, 1, 3); }
+
+bool upb_fielddef_checkdescriptortype(int32_t type) {
+  return between(type, 1, 18);
+}
+
+/* upb_msgdef *****************************************************************/
+
+static void visitmsg(const upb_refcounted *r, upb_refcounted_visit *visit,
+                     void *closure) {
+  upb_msg_oneof_iter o;
+  const upb_msgdef *m = (const upb_msgdef*)r;
+  const upb_def *def = upb_msgdef_upcast(m);
+  upb_msg_field_iter i;
+  for(upb_msg_field_begin(&i, m);
+      !upb_msg_field_done(&i);
+      upb_msg_field_next(&i)) {
+    upb_fielddef *f = upb_msg_iter_field(&i);
+    visit(r, upb_fielddef_upcast2(f), closure);
+  }
+  for(upb_msg_oneof_begin(&o, m);
+      !upb_msg_oneof_done(&o);
+      upb_msg_oneof_next(&o)) {
+    upb_oneofdef *f = upb_msg_iter_oneof(&o);
+    visit(r, upb_oneofdef_upcast(f), closure);
+  }
+  if (upb_def_file(def)) {
+    visit(r, upb_filedef_upcast(upb_def_file(def)), closure);
+  }
+}
+
+static void freemsg(upb_refcounted *r) {
+  upb_msgdef *m = (upb_msgdef*)r;
+  upb_strtable_uninit(&m->ntof);
+  upb_inttable_uninit(&m->itof);
+  upb_def_uninit(upb_msgdef_upcast_mutable(m));
+  upb_gfree(m);
+}
+
+const struct upb_refcounted_vtbl upb_msgdef_vtbl = {visitmsg, freemsg};
+
+upb_msgdef *upb_msgdef_new(const void *owner) {
+  upb_msgdef *m = upb_gmalloc(sizeof(*m));
+  if (!m) return NULL;
+
+  if (!upb_def_init(upb_msgdef_upcast_mutable(m), UPB_DEF_MSG, &upb_msgdef_vtbl,
+                    owner)) {
+    goto err2;
+  }
+
+  if (!upb_inttable_init(&m->itof, UPB_CTYPE_PTR)) goto err2;
+  if (!upb_strtable_init(&m->ntof, UPB_CTYPE_PTR)) goto err1;
+  m->map_entry = false;
+  m->syntax = UPB_SYNTAX_PROTO2;
+  return m;
+
+err1:
+  upb_inttable_uninit(&m->itof);
+err2:
+  upb_gfree(m);
+  return NULL;
+}
+
+bool upb_msgdef_freeze(upb_msgdef *m, upb_status *status) {
+  upb_def *d = upb_msgdef_upcast_mutable(m);
+  return upb_def_freeze(&d, 1, status);
+}
+
+const char *upb_msgdef_fullname(const upb_msgdef *m) {
+  return upb_def_fullname(upb_msgdef_upcast(m));
+}
+
+const char *upb_msgdef_name(const upb_msgdef *m) {
+  return upb_def_name(upb_msgdef_upcast(m));
+}
+
+bool upb_msgdef_setfullname(upb_msgdef *m, const char *fullname,
+                            upb_status *s) {
+  return upb_def_setfullname(upb_msgdef_upcast_mutable(m), fullname, s);
+}
+
+bool upb_msgdef_setsyntax(upb_msgdef *m, upb_syntax_t syntax) {
+  if (syntax != UPB_SYNTAX_PROTO2 && syntax != UPB_SYNTAX_PROTO3) {
+    return false;
+  }
+
+  m->syntax = syntax;
+  return true;
+}
+
+upb_syntax_t upb_msgdef_syntax(const upb_msgdef *m) {
+  return m->syntax;
+}
+
+/* Helper: check that the field |f| is safe to add to msgdef |m|. Set an error
+ * on status |s| and return false if not. */
+static bool check_field_add(const upb_msgdef *m, const upb_fielddef *f,
+                            upb_status *s) {
+  if (upb_fielddef_containingtype(f) != NULL) {
+    upb_status_seterrmsg(s, "fielddef already belongs to a message");
+    return false;
+  } else if (upb_fielddef_name(f) == NULL || upb_fielddef_number(f) == 0) {
+    upb_status_seterrmsg(s, "field name or number were not set");
+    return false;
+  } else if (upb_msgdef_itof(m, upb_fielddef_number(f))) {
+    upb_status_seterrmsg(s, "duplicate field number");
+    return false;
+  } else if (upb_strtable_lookup(&m->ntof, upb_fielddef_name(f), NULL)) {
+    upb_status_seterrmsg(s, "name conflicts with existing field or oneof");
+    return false;
+  }
+  return true;
+}
+
+static void add_field(upb_msgdef *m, upb_fielddef *f, const void *ref_donor) {
+  release_containingtype(f);
+  f->msg.def = m;
+  f->msg_is_symbolic = false;
+  upb_inttable_insert(&m->itof, upb_fielddef_number(f), upb_value_ptr(f));
+  upb_strtable_insert(&m->ntof, upb_fielddef_name(f), upb_value_ptr(f));
+  upb_ref2(f, m);
+  upb_ref2(m, f);
+  if (ref_donor) upb_fielddef_unref(f, ref_donor);
+}
+
+bool upb_msgdef_addfield(upb_msgdef *m, upb_fielddef *f, const void *ref_donor,
+                         upb_status *s) {
+  /* TODO: extensions need to have a separate namespace, because proto2 allows a
+   * top-level extension (ie. one not in any package) to have the same name as a
+   * field from the message.
+   *
+   * This also implies that there needs to be a separate lookup-by-name method
+   * for extensions.  It seems desirable for iteration to return both extensions
+   * and non-extensions though.
+   *
+   * We also need to validate that the field number is in an extension range iff
+   * it is an extension.
+   *
+   * This method is idempotent. Check if |f| is already part of this msgdef and
+   * return immediately if so. */
+  if (upb_fielddef_containingtype(f) == m) {
+    if (ref_donor) upb_fielddef_unref(f, ref_donor);
+    return true;
+  }
+
+  /* Check constraints for all fields before performing any action. */
+  if (!check_field_add(m, f, s)) {
+    return false;
+  } else if (upb_fielddef_containingoneof(f) != NULL) {
+    /* Fields in a oneof can only be added by adding the oneof to the msgdef. */
+    upb_status_seterrmsg(s, "fielddef is part of a oneof");
+    return false;
+  }
+
+  /* Constraint checks ok, perform the action. */
+  add_field(m, f, ref_donor);
+  return true;
+}
+
+bool upb_msgdef_addoneof(upb_msgdef *m, upb_oneofdef *o, const void *ref_donor,
+                         upb_status *s) {
+  upb_oneof_iter it;
+
+  /* Check various conditions that would prevent this oneof from being added. */
+  if (upb_oneofdef_containingtype(o)) {
+    upb_status_seterrmsg(s, "oneofdef already belongs to a message");
+    return false;
+  } else if (upb_oneofdef_name(o) == NULL) {
+    upb_status_seterrmsg(s, "oneofdef name was not set");
+    return false;
+  } else if (upb_strtable_lookup(&m->ntof, upb_oneofdef_name(o), NULL)) {
+    upb_status_seterrmsg(s, "name conflicts with existing field or oneof");
+    return false;
+  }
+
+  /* Check that all of the oneof's fields do not conflict with names or numbers
+   * of fields already in the message. */
+  for (upb_oneof_begin(&it, o); !upb_oneof_done(&it); upb_oneof_next(&it)) {
+    const upb_fielddef *f = upb_oneof_iter_field(&it);
+    if (!check_field_add(m, f, s)) {
+      return false;
+    }
+  }
+
+  /* Everything checks out -- commit now. */
+
+  /* Add oneof itself first. */
+  o->parent = m;
+  upb_strtable_insert(&m->ntof, upb_oneofdef_name(o), upb_value_ptr(o));
+  upb_ref2(o, m);
+  upb_ref2(m, o);
+
+  /* Add each field of the oneof directly to the msgdef. */
+  for (upb_oneof_begin(&it, o); !upb_oneof_done(&it); upb_oneof_next(&it)) {
+    upb_fielddef *f = upb_oneof_iter_field(&it);
+    add_field(m, f, NULL);
+  }
+
+  if (ref_donor) upb_oneofdef_unref(o, ref_donor);
+
+  return true;
+}
+
+const upb_fielddef *upb_msgdef_itof(const upb_msgdef *m, uint32_t i) {
+  upb_value val;
+  return upb_inttable_lookup32(&m->itof, i, &val) ?
+      upb_value_getptr(val) : NULL;
+}
+
+const upb_fielddef *upb_msgdef_ntof(const upb_msgdef *m, const char *name,
+                                    size_t len) {
+  upb_value val;
+
+  if (!upb_strtable_lookup2(&m->ntof, name, len, &val)) {
+    return NULL;
+  }
+
+  return upb_trygetfield(upb_value_getptr(val));
+}
+
+const upb_oneofdef *upb_msgdef_ntoo(const upb_msgdef *m, const char *name,
+                                    size_t len) {
+  upb_value val;
+
+  if (!upb_strtable_lookup2(&m->ntof, name, len, &val)) {
+    return NULL;
+  }
+
+  return upb_trygetoneof(upb_value_getptr(val));
+}
+
+bool upb_msgdef_lookupname(const upb_msgdef *m, const char *name, size_t len,
+                           const upb_fielddef **f, const upb_oneofdef **o) {
+  upb_value val;
+
+  if (!upb_strtable_lookup2(&m->ntof, name, len, &val)) {
+    return false;
+  }
+
+  *o = upb_trygetoneof(upb_value_getptr(val));
+  *f = upb_trygetfield(upb_value_getptr(val));
+  UPB_ASSERT((*o != NULL) ^ (*f != NULL));  /* Exactly one of the two should be set. */
+  return true;
+}
+
+int upb_msgdef_numfields(const upb_msgdef *m) {
+  /* The number table contains only fields. */
+  return upb_inttable_count(&m->itof);
+}
+
+int upb_msgdef_numoneofs(const upb_msgdef *m) {
+  /* The name table includes oneofs, and the number table does not. */
+  return upb_strtable_count(&m->ntof) - upb_inttable_count(&m->itof);
+}
+
+void upb_msgdef_setmapentry(upb_msgdef *m, bool map_entry) {
+  UPB_ASSERT(!upb_msgdef_isfrozen(m));
+  m->map_entry = map_entry;
+}
+
+bool upb_msgdef_mapentry(const upb_msgdef *m) {
+  return m->map_entry;
+}
+
+void upb_msg_field_begin(upb_msg_field_iter *iter, const upb_msgdef *m) {
+  upb_inttable_begin(iter, &m->itof);
+}
+
+void upb_msg_field_next(upb_msg_field_iter *iter) { upb_inttable_next(iter); }
+
+bool upb_msg_field_done(const upb_msg_field_iter *iter) {
+  return upb_inttable_done(iter);
+}
+
+upb_fielddef *upb_msg_iter_field(const upb_msg_field_iter *iter) {
+  return (upb_fielddef*)upb_value_getptr(upb_inttable_iter_value(iter));
+}
+
+void upb_msg_field_iter_setdone(upb_msg_field_iter *iter) {
+  upb_inttable_iter_setdone(iter);
+}
+
+void upb_msg_oneof_begin(upb_msg_oneof_iter *iter, const upb_msgdef *m) {
+  upb_strtable_begin(iter, &m->ntof);
+  /* We need to skip past any initial fields. */
+  while (!upb_strtable_done(iter) &&
+         !upb_isoneof(upb_value_getptr(upb_strtable_iter_value(iter)))) {
+    upb_strtable_next(iter);
+  }
+}
+
+void upb_msg_oneof_next(upb_msg_oneof_iter *iter) {
+  /* We need to skip past fields to return only oneofs. */
+  do {
+    upb_strtable_next(iter);
+  } while (!upb_strtable_done(iter) &&
+           !upb_isoneof(upb_value_getptr(upb_strtable_iter_value(iter))));
+}
+
+bool upb_msg_oneof_done(const upb_msg_oneof_iter *iter) {
+  return upb_strtable_done(iter);
+}
+
+upb_oneofdef *upb_msg_iter_oneof(const upb_msg_oneof_iter *iter) {
+  return (upb_oneofdef*)upb_value_getptr(upb_strtable_iter_value(iter));
+}
+
+void upb_msg_oneof_iter_setdone(upb_msg_oneof_iter *iter) {
+  upb_strtable_iter_setdone(iter);
+}
+
+/* upb_oneofdef ***************************************************************/
+
+static void visitoneof(const upb_refcounted *r, upb_refcounted_visit *visit,
+                       void *closure) {
+  const upb_oneofdef *o = (const upb_oneofdef*)r;
+  upb_oneof_iter i;
+  for (upb_oneof_begin(&i, o); !upb_oneof_done(&i); upb_oneof_next(&i)) {
+    const upb_fielddef *f = upb_oneof_iter_field(&i);
+    visit(r, upb_fielddef_upcast2(f), closure);
+  }
+  if (o->parent) {
+    visit(r, upb_msgdef_upcast2(o->parent), closure);
+  }
+}
+
+static void freeoneof(upb_refcounted *r) {
+  upb_oneofdef *o = (upb_oneofdef*)r;
+  upb_strtable_uninit(&o->ntof);
+  upb_inttable_uninit(&o->itof);
+  upb_gfree((void*)o->name);
+  upb_gfree(o);
+}
+
+const struct upb_refcounted_vtbl upb_oneofdef_vtbl = {visitoneof, freeoneof};
+
+upb_oneofdef *upb_oneofdef_new(const void *owner) {
+  upb_oneofdef *o = upb_gmalloc(sizeof(*o));
+
+  if (!o) {
+    return NULL;
+  }
+
+  o->parent = NULL;
+  o->name = NULL;
+
+  if (!upb_refcounted_init(upb_oneofdef_upcast_mutable(o), &upb_oneofdef_vtbl,
+                           owner)) {
+    goto err2;
+  }
+
+  if (!upb_inttable_init(&o->itof, UPB_CTYPE_PTR)) goto err2;
+  if (!upb_strtable_init(&o->ntof, UPB_CTYPE_PTR)) goto err1;
+
+  return o;
+
+err1:
+  upb_inttable_uninit(&o->itof);
+err2:
+  upb_gfree(o);
+  return NULL;
+}
+
+const char *upb_oneofdef_name(const upb_oneofdef *o) { return o->name; }
+
+bool upb_oneofdef_setname(upb_oneofdef *o, const char *name, upb_status *s) {
+  UPB_ASSERT(!upb_oneofdef_isfrozen(o));
+  if (upb_oneofdef_containingtype(o)) {
+    upb_status_seterrmsg(s, "oneof already added to a message");
+    return false;
+  }
+
+  if (!upb_isident(name, strlen(name), true, s)) {
+    return false;
+  }
+
+  name = upb_gstrdup(name);
+  if (!name) {
+    upb_status_seterrmsg(s, "One of memory");
+    return false;
+  }
+
+  upb_gfree((void*)o->name);
+  o->name = name;
+  return true;
+}
+
+const upb_msgdef *upb_oneofdef_containingtype(const upb_oneofdef *o) {
+  return o->parent;
+}
+
+int upb_oneofdef_numfields(const upb_oneofdef *o) {
+  return upb_strtable_count(&o->ntof);
+}
+
+uint32_t upb_oneofdef_index(const upb_oneofdef *o) {
+  return o->index;
+}
+
+bool upb_oneofdef_addfield(upb_oneofdef *o, upb_fielddef *f,
+                           const void *ref_donor,
+                           upb_status *s) {
+  UPB_ASSERT(!upb_oneofdef_isfrozen(o));
+  UPB_ASSERT(!o->parent || !upb_msgdef_isfrozen(o->parent));
+
+  /* This method is idempotent. Check if |f| is already part of this oneofdef
+   * and return immediately if so. */
+  if (upb_fielddef_containingoneof(f) == o) {
+    return true;
+  }
+
+  /* The field must have an OPTIONAL label. */
+  if (upb_fielddef_label(f) != UPB_LABEL_OPTIONAL) {
+    upb_status_seterrmsg(s, "fields in oneof must have OPTIONAL label");
+    return false;
+  }
+
+  /* Check that no field with this name or number exists already in the oneof.
+   * Also check that the field is not already part of a oneof. */
+  if (upb_fielddef_name(f) == NULL || upb_fielddef_number(f) == 0) {
+    upb_status_seterrmsg(s, "field name or number were not set");
+    return false;
+  } else if (upb_oneofdef_itof(o, upb_fielddef_number(f)) ||
+             upb_oneofdef_ntofz(o, upb_fielddef_name(f))) {
+    upb_status_seterrmsg(s, "duplicate field name or number");
+    return false;
+  } else if (upb_fielddef_containingoneof(f) != NULL) {
+    upb_status_seterrmsg(s, "fielddef already belongs to a oneof");
+    return false;
+  }
+
+  /* We allow adding a field to the oneof either if the field is not part of a
+   * msgdef, or if it is and we are also part of the same msgdef. */
+  if (o->parent == NULL) {
+    /* If we're not in a msgdef, the field cannot be either. Otherwise we would
+     * need to magically add this oneof to a msgdef to remain consistent, which
+     * is surprising behavior. */
+    if (upb_fielddef_containingtype(f) != NULL) {
+      upb_status_seterrmsg(s, "fielddef already belongs to a message, but "
+                              "oneof does not");
+      return false;
+    }
+  } else {
+    /* If we're in a msgdef, the user can add fields that either aren't in any
+     * msgdef (in which case they're added to our msgdef) or already a part of
+     * our msgdef. */
+    if (upb_fielddef_containingtype(f) != NULL &&
+        upb_fielddef_containingtype(f) != o->parent) {
+      upb_status_seterrmsg(s, "fielddef belongs to a different message "
+                              "than oneof");
+      return false;
+    }
+  }
+
+  /* Commit phase. First add the field to our parent msgdef, if any, because
+   * that may fail; then add the field to our own tables. */
+
+  if (o->parent != NULL && upb_fielddef_containingtype(f) == NULL) {
+    if (!upb_msgdef_addfield((upb_msgdef*)o->parent, f, NULL, s)) {
+      return false;
+    }
+  }
+
+  release_containingtype(f);
+  f->oneof = o;
+  upb_inttable_insert(&o->itof, upb_fielddef_number(f), upb_value_ptr(f));
+  upb_strtable_insert(&o->ntof, upb_fielddef_name(f), upb_value_ptr(f));
+  upb_ref2(f, o);
+  upb_ref2(o, f);
+  if (ref_donor) upb_fielddef_unref(f, ref_donor);
+
+  return true;
+}
+
+const upb_fielddef *upb_oneofdef_ntof(const upb_oneofdef *o,
+                                      const char *name, size_t length) {
+  upb_value val;
+  return upb_strtable_lookup2(&o->ntof, name, length, &val) ?
+      upb_value_getptr(val) : NULL;
+}
+
+const upb_fielddef *upb_oneofdef_itof(const upb_oneofdef *o, uint32_t num) {
+  upb_value val;
+  return upb_inttable_lookup32(&o->itof, num, &val) ?
+      upb_value_getptr(val) : NULL;
+}
+
+void upb_oneof_begin(upb_oneof_iter *iter, const upb_oneofdef *o) {
+  upb_inttable_begin(iter, &o->itof);
+}
+
+void upb_oneof_next(upb_oneof_iter *iter) {
+  upb_inttable_next(iter);
+}
+
+bool upb_oneof_done(upb_oneof_iter *iter) {
+  return upb_inttable_done(iter);
+}
+
+upb_fielddef *upb_oneof_iter_field(const upb_oneof_iter *iter) {
+  return (upb_fielddef*)upb_value_getptr(upb_inttable_iter_value(iter));
+}
+
+void upb_oneof_iter_setdone(upb_oneof_iter *iter) {
+  upb_inttable_iter_setdone(iter);
+}
+
+/* upb_filedef ****************************************************************/
+
+static void visitfiledef(const upb_refcounted *r, upb_refcounted_visit *visit,
+                         void *closure) {
+  const upb_filedef *f = (const upb_filedef*)r;
+  size_t i;
+
+  for(i = 0; i < upb_filedef_defcount(f); i++) {
+    visit(r, upb_def_upcast(upb_filedef_def(f, i)), closure);
+  }
+}
+
+static void freefiledef(upb_refcounted *r) {
+  upb_filedef *f = (upb_filedef*)r;
+  size_t i;
+
+  for(i = 0; i < upb_filedef_depcount(f); i++) {
+    upb_filedef_unref(upb_filedef_dep(f, i), f);
+  }
+
+  upb_inttable_uninit(&f->defs);
+  upb_inttable_uninit(&f->deps);
+  upb_gfree((void*)f->name);
+  upb_gfree((void*)f->package);
+  upb_gfree((void*)f->phpprefix);
+  upb_gfree((void*)f->phpnamespace);
+  upb_gfree(f);
+}
+
+const struct upb_refcounted_vtbl upb_filedef_vtbl = {visitfiledef, freefiledef};
+
+upb_filedef *upb_filedef_new(const void *owner) {
+  upb_filedef *f = upb_gmalloc(sizeof(*f));
+
+  if (!f) {
+    return NULL;
+  }
+
+  f->package = NULL;
+  f->name = NULL;
+  f->phpprefix = NULL;
+  f->phpnamespace = NULL;
+  f->syntax = UPB_SYNTAX_PROTO2;
+
+  if (!upb_refcounted_init(upb_filedef_upcast_mutable(f), &upb_filedef_vtbl,
+                           owner)) {
+    goto err;
+  }
+
+  if (!upb_inttable_init(&f->defs, UPB_CTYPE_CONSTPTR)) {
+    goto err;
+  }
+
+  if (!upb_inttable_init(&f->deps, UPB_CTYPE_CONSTPTR)) {
+    goto err2;
+  }
+
+  return f;
+
+
+err2:
+  upb_inttable_uninit(&f->defs);
+
+err:
+  upb_gfree(f);
+  return NULL;
+}
+
+const char *upb_filedef_name(const upb_filedef *f) {
+  return f->name;
+}
+
+const char *upb_filedef_package(const upb_filedef *f) {
+  return f->package;
+}
+
+const char *upb_filedef_phpprefix(const upb_filedef *f) {
+  return f->phpprefix;
+}
+
+const char *upb_filedef_phpnamespace(const upb_filedef *f) {
+  return f->phpnamespace;
+}
+
+upb_syntax_t upb_filedef_syntax(const upb_filedef *f) {
+  return f->syntax;
+}
+
+size_t upb_filedef_defcount(const upb_filedef *f) {
+  return upb_inttable_count(&f->defs);
+}
+
+size_t upb_filedef_depcount(const upb_filedef *f) {
+  return upb_inttable_count(&f->deps);
+}
+
+const upb_def *upb_filedef_def(const upb_filedef *f, size_t i) {
+  upb_value v;
+
+  if (upb_inttable_lookup32(&f->defs, i, &v)) {
+    return upb_value_getconstptr(v);
+  } else {
+    return NULL;
+  }
+}
+
+const upb_filedef *upb_filedef_dep(const upb_filedef *f, size_t i) {
+  upb_value v;
+
+  if (upb_inttable_lookup32(&f->deps, i, &v)) {
+    return upb_value_getconstptr(v);
+  } else {
+    return NULL;
+  }
+}
+
+bool upb_filedef_setname(upb_filedef *f, const char *name, upb_status *s) {
+  name = upb_gstrdup(name);
+  if (!name) {
+    upb_upberr_setoom(s);
+    return false;
+  }
+  upb_gfree((void*)f->name);
+  f->name = name;
+  return true;
+}
+
+bool upb_filedef_setpackage(upb_filedef *f, const char *package,
+                            upb_status *s) {
+  if (!upb_isident(package, strlen(package), true, s)) return false;
+  package = upb_gstrdup(package);
+  if (!package) {
+    upb_upberr_setoom(s);
+    return false;
+  }
+  upb_gfree((void*)f->package);
+  f->package = package;
+  return true;
+}
+
+bool upb_filedef_setphpprefix(upb_filedef *f, const char *phpprefix,
+                              upb_status *s) {
+  phpprefix = upb_gstrdup(phpprefix);
+  if (!phpprefix) {
+    upb_upberr_setoom(s);
+    return false;
+  }
+  upb_gfree((void*)f->phpprefix);
+  f->phpprefix = phpprefix;
+  return true;
+}
+
+bool upb_filedef_setphpnamespace(upb_filedef *f, const char *phpnamespace,
+                                 upb_status *s) {
+  phpnamespace = upb_gstrdup(phpnamespace);
+  if (!phpnamespace) {
+    upb_upberr_setoom(s);
+    return false;
+  }
+  upb_gfree((void*)f->phpnamespace);
+  f->phpnamespace = phpnamespace;
+  return true;
+}
+
+bool upb_filedef_setsyntax(upb_filedef *f, upb_syntax_t syntax,
+                           upb_status *s) {
+  UPB_UNUSED(s);
+  if (syntax != UPB_SYNTAX_PROTO2 &&
+      syntax != UPB_SYNTAX_PROTO3) {
+    upb_status_seterrmsg(s, "Unknown syntax value.");
+    return false;
+  }
+  f->syntax = syntax;
+
+  {
+    /* Set all messages in this file to match. */
+    size_t i;
+    for (i = 0; i < upb_filedef_defcount(f); i++) {
+      /* Casting const away is safe since all defs in mutable filedef must
+       * also be mutable. */
+      upb_def *def = (upb_def*)upb_filedef_def(f, i);
+
+      upb_msgdef *m = upb_dyncast_msgdef_mutable(def);
+      if (m) {
+        m->syntax = syntax;
+      }
+    }
+  }
+
+  return true;
+}
+
+bool upb_filedef_adddef(upb_filedef *f, upb_def *def, const void *ref_donor,
+                        upb_status *s) {
+  if (def->file) {
+    upb_status_seterrmsg(s, "Def is already part of another filedef.");
+    return false;
+  }
+
+  if (upb_inttable_push(&f->defs, upb_value_constptr(def))) {
+    def->file = f;
+    upb_ref2(def, f);
+    upb_ref2(f, def);
+    if (ref_donor) upb_def_unref(def, ref_donor);
+    if (def->type == UPB_DEF_MSG) {
+      upb_downcast_msgdef_mutable(def)->syntax = f->syntax;
+    }
+    return true;
+  } else {
+    upb_upberr_setoom(s);
+    return false;
+  }
+}
+
+bool upb_filedef_adddep(upb_filedef *f, const upb_filedef *dep) {
+  if (upb_inttable_push(&f->deps, upb_value_constptr(dep))) {
+    /* Regular ref instead of ref2 because files can't form cycles. */
+    upb_filedef_ref(dep, f);
+    return true;
+  } else {
+    return false;
+  }
+}
+
+void upb_symtab_free(upb_symtab *s) {
+  upb_strtable_iter i;
+  upb_strtable_begin(&i, &s->symtab);
+  for (; !upb_strtable_done(&i); upb_strtable_next(&i)) {
+    const upb_def *def = upb_value_getptr(upb_strtable_iter_value(&i));
+    upb_def_unref(def, s);
+  }
+  upb_strtable_uninit(&s->symtab);
+  upb_gfree(s);
+}
+
+upb_symtab *upb_symtab_new() {
+  upb_symtab *s = upb_gmalloc(sizeof(*s));
+  if (!s) {
+    return NULL;
+  }
+
+  upb_strtable_init(&s->symtab, UPB_CTYPE_PTR);
+  return s;
+}
+
+const upb_def *upb_symtab_lookup(const upb_symtab *s, const char *sym) {
+  upb_value v;
+  upb_def *ret = upb_strtable_lookup(&s->symtab, sym, &v) ?
+      upb_value_getptr(v) : NULL;
+  return ret;
+}
+
+const upb_msgdef *upb_symtab_lookupmsg(const upb_symtab *s, const char *sym) {
+  upb_value v;
+  upb_def *def = upb_strtable_lookup(&s->symtab, sym, &v) ?
+      upb_value_getptr(v) : NULL;
+  return def ? upb_dyncast_msgdef(def) : NULL;
+}
+
+const upb_enumdef *upb_symtab_lookupenum(const upb_symtab *s, const char *sym) {
+  upb_value v;
+  upb_def *def = upb_strtable_lookup(&s->symtab, sym, &v) ?
+      upb_value_getptr(v) : NULL;
+  return def ? upb_dyncast_enumdef(def) : NULL;
+}
+
+/* Given a symbol and the base symbol inside which it is defined, find the
+ * symbol's definition in t. */
+static upb_def *upb_resolvename(const upb_strtable *t,
+                                const char *base, const char *sym) {
+  if(strlen(sym) == 0) return NULL;
+  if(sym[0] == '.') {
+    /* Symbols starting with '.' are absolute, so we do a single lookup.
+     * Slice to omit the leading '.' */
+    upb_value v;
+    return upb_strtable_lookup(t, sym + 1, &v) ? upb_value_getptr(v) : NULL;
+  } else {
+    /* Remove components from base until we find an entry or run out.
+     * TODO: This branch is totally broken, but currently not used. */
+    (void)base;
+    UPB_ASSERT(false);
+    return NULL;
+  }
+}
+
+const upb_def *upb_symtab_resolve(const upb_symtab *s, const char *base,
+                                  const char *sym) {
+  upb_def *ret = upb_resolvename(&s->symtab, base, sym);
+  return ret;
+}
+
+/* TODO(haberman): we need a lot more testing of error conditions. */
+static bool symtab_add(upb_symtab *s, upb_def *const*defs, size_t n,
+                       void *ref_donor, upb_refcounted *freeze_also,
+                       upb_status *status) {
+  size_t i;
+  size_t add_n;
+  size_t freeze_n;
+  upb_strtable_iter iter;
+  upb_refcounted **add_objs = NULL;
+  upb_def **add_defs = NULL;
+  size_t add_objs_size;
+  upb_strtable addtab;
+
+  if (n == 0 && !freeze_also) {
+    return true;
+  }
+
+  if (!upb_strtable_init(&addtab, UPB_CTYPE_PTR)) {
+    upb_status_seterrmsg(status, "out of memory");
+    return false;
+  }
+
+  /* Add new defs to our "add" set. */
+  for (i = 0; i < n; i++) {
+    upb_def *def = defs[i];
+    const char *fullname;
+    upb_fielddef *f;
+
+    if (upb_def_isfrozen(def)) {
+      upb_status_seterrmsg(status, "added defs must be mutable");
+      goto err;
+    }
+    UPB_ASSERT(!upb_def_isfrozen(def));
+    fullname = upb_def_fullname(def);
+    if (!fullname) {
+      upb_status_seterrmsg(
+          status, "Anonymous defs cannot be added to a symtab");
+      goto err;
+    }
+
+    f = upb_dyncast_fielddef_mutable(def);
+
+    if (f) {
+      if (!upb_fielddef_containingtypename(f)) {
+        upb_status_seterrmsg(status,
+                             "Standalone fielddefs must have a containing type "
+                             "(extendee) name set");
+        goto err;
+      }
+    } else {
+      if (upb_strtable_lookup(&addtab, fullname, NULL)) {
+        upb_status_seterrf(status, "Conflicting defs named '%s'", fullname);
+        goto err;
+      }
+      if (upb_strtable_lookup(&s->symtab, fullname, NULL)) {
+        upb_status_seterrf(status, "Symtab already has a def named '%s'",
+                           fullname);
+        goto err;
+      }
+      if (!upb_strtable_insert(&addtab, fullname, upb_value_ptr(def)))
+        goto oom_err;
+      upb_def_donateref(def, ref_donor, s);
+    }
+
+    if (upb_dyncast_fielddef_mutable(def)) {
+      /* TODO(haberman): allow adding extensions attached to files. */
+      upb_status_seterrf(status, "Can't add extensions to symtab.\n");
+      goto err;
+    }
+  }
+
+  /* Now using the table, resolve symbolic references for subdefs. */
+  upb_strtable_begin(&iter, &addtab);
+  for (; !upb_strtable_done(&iter); upb_strtable_next(&iter)) {
+    const char *base;
+    upb_def *def = upb_value_getptr(upb_strtable_iter_value(&iter));
+    upb_msgdef *m = upb_dyncast_msgdef_mutable(def);
+    upb_msg_field_iter j;
+
+    if (!m) continue;
+    /* Type names are resolved relative to the message in which they appear. */
+    base = upb_msgdef_fullname(m);
+
+    for(upb_msg_field_begin(&j, m);
+        !upb_msg_field_done(&j);
+        upb_msg_field_next(&j)) {
+      upb_fielddef *f = upb_msg_iter_field(&j);
+      const char *name = upb_fielddef_subdefname(f);
+      if (name && !upb_fielddef_subdef(f)) {
+        /* Try the lookup in the current set of to-be-added defs first. If not
+         * there, try existing defs. */
+        upb_def *subdef = upb_resolvename(&addtab, base, name);
+        if (subdef == NULL) {
+          subdef = upb_resolvename(&s->symtab, base, name);
+        }
+        if (subdef == NULL) {
+          upb_status_seterrf(
+              status, "couldn't resolve name '%s' in message '%s'", name, base);
+          goto err;
+        } else if (!upb_fielddef_setsubdef(f, subdef, status)) {
+          goto err;
+        }
+      }
+    }
+  }
+
+  /* We need an array of the defs in addtab, for passing to
+   * upb_refcounted_freeze(). */
+  add_objs_size = upb_strtable_count(&addtab);
+  if (freeze_also) {
+    add_objs_size++;
+  }
+
+  add_defs = upb_gmalloc(sizeof(void*) * add_objs_size);
+  if (add_defs == NULL) goto oom_err;
+  upb_strtable_begin(&iter, &addtab);
+  for (add_n = 0; !upb_strtable_done(&iter); upb_strtable_next(&iter)) {
+    add_defs[add_n++] = upb_value_getptr(upb_strtable_iter_value(&iter));
+  }
+
+  /* Validate defs. */
+  if (!_upb_def_validate(add_defs, add_n, status)) {
+    goto err;
+  }
+
+  /* Cheat a little and give the array a new type.
+   * This is probably undefined behavior, but this code will be deleted soon. */
+  add_objs = (upb_refcounted**)add_defs;
+
+  freeze_n = add_n;
+  if (freeze_also) {
+    add_objs[freeze_n++] = freeze_also;
+  }
+
+  if (!upb_refcounted_freeze(add_objs, freeze_n, status,
+                             UPB_MAX_MESSAGE_DEPTH * 2)) {
+    goto err;
+  }
+
+  /* This must be delayed until all errors have been detected, since error
+   * recovery code uses this table to cleanup defs. */
+  upb_strtable_uninit(&addtab);
+
+  /* TODO(haberman) we don't properly handle errors after this point (like
+   * OOM in upb_strtable_insert() below). */
+  for (i = 0; i < add_n; i++) {
+    upb_def *def = (upb_def*)add_objs[i];
+    const char *name = upb_def_fullname(def);
+    bool success;
+    success = upb_strtable_insert(&s->symtab, name, upb_value_ptr(def));
+    UPB_ASSERT(success);
+  }
+  upb_gfree(add_defs);
+  return true;
+
+oom_err:
+  upb_status_seterrmsg(status, "out of memory");
+err: {
+    /* We need to donate the refs back. */
+    upb_strtable_begin(&iter, &addtab);
+    for (; !upb_strtable_done(&iter); upb_strtable_next(&iter)) {
+      upb_def *def = upb_value_getptr(upb_strtable_iter_value(&iter));
+      upb_def_donateref(def, s, ref_donor);
+    }
+  }
+  upb_strtable_uninit(&addtab);
+  upb_gfree(add_defs);
+  UPB_ASSERT(!upb_ok(status));
+  return false;
+}
+
+bool upb_symtab_add(upb_symtab *s, upb_def *const*defs, size_t n,
+                    void *ref_donor, upb_status *status) {
+  return symtab_add(s, defs, n, ref_donor, NULL, status);
+}
+
+bool upb_symtab_addfile(upb_symtab *s, upb_filedef *file, upb_status *status) {
+  size_t n;
+  size_t i;
+  upb_def **defs;
+  bool ret;
+
+  n = upb_filedef_defcount(file);
+  if (n == 0) {
+    return true;
+  }
+  defs = upb_gmalloc(sizeof(*defs) * n);
+
+  if (defs == NULL) {
+    upb_status_seterrmsg(status, "Out of memory");
+    return false;
+  }
+
+  for (i = 0; i < n; i++) {
+    defs[i] = upb_filedef_mutabledef(file, i);
+  }
+
+  ret = symtab_add(s, defs, n, NULL, upb_filedef_upcast_mutable(file), status);
+
+  upb_gfree(defs);
+  return ret;
+}
+
+/* Iteration. */
+
+static void advance_to_matching(upb_symtab_iter *iter) {
+  if (iter->type == UPB_DEF_ANY)
+    return;
+
+  while (!upb_strtable_done(&iter->iter) &&
+         iter->type != upb_symtab_iter_def(iter)->type) {
+    upb_strtable_next(&iter->iter);
+  }
+}
+
+void upb_symtab_begin(upb_symtab_iter *iter, const upb_symtab *s,
+                      upb_deftype_t type) {
+  upb_strtable_begin(&iter->iter, &s->symtab);
+  iter->type = type;
+  advance_to_matching(iter);
+}
+
+void upb_symtab_next(upb_symtab_iter *iter) {
+  upb_strtable_next(&iter->iter);
+  advance_to_matching(iter);
+}
+
+bool upb_symtab_done(const upb_symtab_iter *iter) {
+  return upb_strtable_done(&iter->iter);
+}
+
+const upb_def *upb_symtab_iter_def(const upb_symtab_iter *iter) {
+  return upb_value_getptr(upb_strtable_iter_value(&iter->iter));
+}
+/* We encode backwards, to avoid pre-computing lengths (one-pass encode). */
+
+
+#define UPB_PB_VARINT_MAX_LEN 10
+#define CHK(x) do { if (!(x)) { return false; } } while(0)
+
+/* Maps descriptor type -> upb field type.  */
+static const uint8_t upb_desctype_to_fieldtype2[] = {
+  UPB_WIRE_TYPE_END_GROUP,  /* ENDGROUP */
+  UPB_TYPE_DOUBLE,          /* DOUBLE */
+  UPB_TYPE_FLOAT,           /* FLOAT */
+  UPB_TYPE_INT64,           /* INT64 */
+  UPB_TYPE_UINT64,          /* UINT64 */
+  UPB_TYPE_INT32,           /* INT32 */
+  UPB_TYPE_UINT64,          /* FIXED64 */
+  UPB_TYPE_UINT32,          /* FIXED32 */
+  UPB_TYPE_BOOL,            /* BOOL */
+  UPB_TYPE_STRING,          /* STRING */
+  UPB_TYPE_MESSAGE,         /* GROUP */
+  UPB_TYPE_MESSAGE,         /* MESSAGE */
+  UPB_TYPE_BYTES,           /* BYTES */
+  UPB_TYPE_UINT32,          /* UINT32 */
+  UPB_TYPE_ENUM,            /* ENUM */
+  UPB_TYPE_INT32,           /* SFIXED32 */
+  UPB_TYPE_INT64,           /* SFIXED64 */
+  UPB_TYPE_INT32,           /* SINT32 */
+  UPB_TYPE_INT64,           /* SINT64 */
+};
+
+static size_t upb_encode_varint(uint64_t val, char *buf) {
+  size_t i;
+  if (val < 128) { buf[0] = val; return 1; }
+  i = 0;
+  while (val) {
+    uint8_t byte = val & 0x7fU;
+    val >>= 7;
+    if (val) byte |= 0x80U;
+    buf[i++] = byte;
+  }
+  return i;
+}
+
+static uint32_t upb_zzencode_32(int32_t n) { return (n << 1) ^ (n >> 31); }
+static uint64_t upb_zzencode_64(int64_t n) { return (n << 1) ^ (n >> 63); }
+
+typedef struct {
+  upb_env *env;
+  char *buf, *ptr, *limit;
+} upb_encstate;
+
+static size_t upb_roundup_pow2(size_t bytes) {
+  size_t ret = 128;
+  while (ret < bytes) {
+    ret *= 2;
+  }
+  return ret;
+}
+
+static bool upb_encode_growbuffer(upb_encstate *e, size_t bytes) {
+  size_t old_size = e->limit - e->buf;
+  size_t new_size = upb_roundup_pow2(bytes + (e->limit - e->ptr));
+  char *new_buf = upb_env_realloc(e->env, e->buf, old_size, new_size);
+  CHK(new_buf);
+
+  /* We want previous data at the end, realloc() put it at the beginning. */
+  memmove(new_buf + new_size - old_size, e->buf, old_size);
+
+  e->ptr = new_buf + new_size - (e->limit - e->ptr);
+  e->limit = new_buf + new_size;
+  e->buf = new_buf;
+  return true;
+}
+
+/* Call to ensure that at least "bytes" bytes are available for writing at
+ * e->ptr.  Returns false if the bytes could not be allocated. */
+static bool upb_encode_reserve(upb_encstate *e, size_t bytes) {
+  CHK(UPB_LIKELY((size_t)(e->ptr - e->buf) >= bytes) ||
+      upb_encode_growbuffer(e, bytes));
+
+  e->ptr -= bytes;
+  return true;
+}
+
+/* Writes the given bytes to the buffer, handling reserve/advance. */
+static bool upb_put_bytes(upb_encstate *e, const void *data, size_t len) {
+  CHK(upb_encode_reserve(e, len));
+  memcpy(e->ptr, data, len);
+  return true;
+}
+
+static bool upb_put_fixed64(upb_encstate *e, uint64_t val) {
+  /* TODO(haberman): byte-swap for big endian. */
+  return upb_put_bytes(e, &val, sizeof(uint64_t));
+}
+
+static bool upb_put_fixed32(upb_encstate *e, uint32_t val) {
+  /* TODO(haberman): byte-swap for big endian. */
+  return upb_put_bytes(e, &val, sizeof(uint32_t));
+}
+
+static bool upb_put_varint(upb_encstate *e, uint64_t val) {
+  size_t len;
+  char *start;
+  CHK(upb_encode_reserve(e, UPB_PB_VARINT_MAX_LEN));
+  len = upb_encode_varint(val, e->ptr);
+  start = e->ptr + UPB_PB_VARINT_MAX_LEN - len;
+  memmove(start, e->ptr, len);
+  e->ptr = start;
+  return true;
+}
+
+static bool upb_put_double(upb_encstate *e, double d) {
+  uint64_t u64;
+  UPB_ASSERT(sizeof(double) == sizeof(uint64_t));
+  memcpy(&u64, &d, sizeof(uint64_t));
+  return upb_put_fixed64(e, u64);
+}
+
+static bool upb_put_float(upb_encstate *e, float d) {
+  uint32_t u32;
+  UPB_ASSERT(sizeof(float) == sizeof(uint32_t));
+  memcpy(&u32, &d, sizeof(uint32_t));
+  return upb_put_fixed32(e, u32);
+}
+
+static uint32_t upb_readcase(const char *msg, const upb_msglayout_msginit_v1 *m,
+                             int oneof_index) {
+  uint32_t ret;
+  memcpy(&ret, msg + m->oneofs[oneof_index].case_offset, sizeof(ret));
+  return ret;
+}
+
+static bool upb_readhasbit(const char *msg,
+                           const upb_msglayout_fieldinit_v1 *f) {
+  UPB_ASSERT(f->hasbit != UPB_NO_HASBIT);
+  return msg[f->hasbit / 8] & (1 << (f->hasbit % 8));
+}
+
+static bool upb_put_tag(upb_encstate *e, int field_number, int wire_type) {
+  return upb_put_varint(e, (field_number << 3) | wire_type);
+}
+
+static bool upb_put_fixedarray(upb_encstate *e, const upb_array *arr,
+                               size_t size) {
+  size_t bytes = arr->len * size;
+  return upb_put_bytes(e, arr->data, bytes) && upb_put_varint(e, bytes);
+}
+
+bool upb_encode_message(upb_encstate *e, const char *msg,
+                        const upb_msglayout_msginit_v1 *m,
+                        size_t *size);
+
+static bool upb_encode_array(upb_encstate *e, const char *field_mem,
+                             const upb_msglayout_msginit_v1 *m,
+                             const upb_msglayout_fieldinit_v1 *f) {
+  const upb_array *arr = *(const upb_array**)field_mem;
+
+  if (arr == NULL || arr->len == 0) {
+    return true;
+  }
+
+  UPB_ASSERT(arr->type == upb_desctype_to_fieldtype2[f->descriptortype]);
+
+#define VARINT_CASE(ctype, encode) { \
+  ctype *start = arr->data; \
+  ctype *ptr = start + arr->len; \
+  size_t pre_len = e->limit - e->ptr; \
+  do { \
+    ptr--; \
+    CHK(upb_put_varint(e, encode)); \
+  } while (ptr != start); \
+  CHK(upb_put_varint(e, e->limit - e->ptr - pre_len)); \
+} \
+break; \
+do { ; } while(0)
+
+  switch (f->descriptortype) {
+    case UPB_DESCRIPTOR_TYPE_DOUBLE:
+      CHK(upb_put_fixedarray(e, arr, sizeof(double)));
+      break;
+    case UPB_DESCRIPTOR_TYPE_FLOAT:
+      CHK(upb_put_fixedarray(e, arr, sizeof(float)));
+      break;
+    case UPB_DESCRIPTOR_TYPE_SFIXED64:
+    case UPB_DESCRIPTOR_TYPE_FIXED64:
+      CHK(upb_put_fixedarray(e, arr, sizeof(uint64_t)));
+      break;
+    case UPB_DESCRIPTOR_TYPE_FIXED32:
+    case UPB_DESCRIPTOR_TYPE_SFIXED32:
+      CHK(upb_put_fixedarray(e, arr, sizeof(uint32_t)));
+      break;
+    case UPB_DESCRIPTOR_TYPE_INT64:
+    case UPB_DESCRIPTOR_TYPE_UINT64:
+      VARINT_CASE(uint64_t, *ptr);
+    case UPB_DESCRIPTOR_TYPE_UINT32:
+      VARINT_CASE(uint32_t, *ptr);
+    case UPB_DESCRIPTOR_TYPE_INT32:
+    case UPB_DESCRIPTOR_TYPE_ENUM:
+      VARINT_CASE(int32_t, (int64_t)*ptr);
+    case UPB_DESCRIPTOR_TYPE_BOOL:
+      VARINT_CASE(bool, *ptr);
+    case UPB_DESCRIPTOR_TYPE_SINT32:
+      VARINT_CASE(int32_t, upb_zzencode_32(*ptr));
+    case UPB_DESCRIPTOR_TYPE_SINT64:
+      VARINT_CASE(int64_t, upb_zzencode_64(*ptr));
+    case UPB_DESCRIPTOR_TYPE_STRING:
+    case UPB_DESCRIPTOR_TYPE_BYTES: {
+      upb_stringview *start = arr->data;
+      upb_stringview *ptr = start + arr->len;
+      do {
+        ptr--;
+        CHK(upb_put_bytes(e, ptr->data, ptr->size) &&
+            upb_put_varint(e, ptr->size) &&
+            upb_put_tag(e, f->number, UPB_WIRE_TYPE_DELIMITED));
+      } while (ptr != start);
+      return true;
+    }
+    case UPB_DESCRIPTOR_TYPE_GROUP: {
+      void **start = arr->data;
+      void **ptr = start + arr->len;
+      const upb_msglayout_msginit_v1 *subm = m->submsgs[f->submsg_index];
+      do {
+        size_t size;
+        ptr--;
+        CHK(upb_put_tag(e, f->number, UPB_WIRE_TYPE_END_GROUP) &&
+            upb_encode_message(e, *ptr, subm, &size) &&
+            upb_put_tag(e, f->number, UPB_WIRE_TYPE_START_GROUP));
+      } while (ptr != start);
+      return true;
+    }
+    case UPB_DESCRIPTOR_TYPE_MESSAGE: {
+      void **start = arr->data;
+      void **ptr = start + arr->len;
+      const upb_msglayout_msginit_v1 *subm = m->submsgs[f->submsg_index];
+      do {
+        size_t size;
+        ptr--;
+        CHK(upb_encode_message(e, *ptr, subm, &size) &&
+            upb_put_varint(e, size) &&
+            upb_put_tag(e, f->number, UPB_WIRE_TYPE_DELIMITED));
+      } while (ptr != start);
+      return true;
+    }
+  }
+#undef VARINT_CASE
+
+  /* We encode all primitive arrays as packed, regardless of what was specified
+   * in the .proto file.  Could special case 1-sized arrays. */
+  CHK(upb_put_tag(e, f->number, UPB_WIRE_TYPE_DELIMITED));
+  return true;
+}
+
+static bool upb_encode_scalarfield(upb_encstate *e, const char *field_mem,
+                                   const upb_msglayout_msginit_v1 *m,
+                                   const upb_msglayout_fieldinit_v1 *f,
+                                   bool is_proto3) {
+  bool skip_zero_value = is_proto3 && f->oneof_index == UPB_NOT_IN_ONEOF;
+
+#define CASE(ctype, type, wire_type, encodeval) do { \
+  ctype val = *(ctype*)field_mem; \
+  if (skip_zero_value && val == 0) { \
+    return true; \
+  } \
+  return upb_put_ ## type(e, encodeval) && \
+      upb_put_tag(e, f->number, wire_type); \
+} while(0)
+
+  switch (f->descriptortype) {
+    case UPB_DESCRIPTOR_TYPE_DOUBLE:
+      CASE(double, double, UPB_WIRE_TYPE_64BIT, val);
+    case UPB_DESCRIPTOR_TYPE_FLOAT:
+      CASE(float, float, UPB_WIRE_TYPE_32BIT, val);
+    case UPB_DESCRIPTOR_TYPE_INT64:
+    case UPB_DESCRIPTOR_TYPE_UINT64:
+      CASE(uint64_t, varint, UPB_WIRE_TYPE_VARINT, val);
+    case UPB_DESCRIPTOR_TYPE_UINT32:
+      CASE(uint32_t, varint, UPB_WIRE_TYPE_VARINT, val);
+    case UPB_DESCRIPTOR_TYPE_INT32:
+    case UPB_DESCRIPTOR_TYPE_ENUM:
+      CASE(int32_t, varint, UPB_WIRE_TYPE_VARINT, (int64_t)val);
+    case UPB_DESCRIPTOR_TYPE_SFIXED64:
+    case UPB_DESCRIPTOR_TYPE_FIXED64:
+      CASE(uint64_t, fixed64, UPB_WIRE_TYPE_64BIT, val);
+    case UPB_DESCRIPTOR_TYPE_FIXED32:
+    case UPB_DESCRIPTOR_TYPE_SFIXED32:
+      CASE(uint32_t, fixed32, UPB_WIRE_TYPE_32BIT, val);
+    case UPB_DESCRIPTOR_TYPE_BOOL:
+      CASE(bool, varint, UPB_WIRE_TYPE_VARINT, val);
+    case UPB_DESCRIPTOR_TYPE_SINT32:
+      CASE(int32_t, varint, UPB_WIRE_TYPE_VARINT, upb_zzencode_32(val));
+    case UPB_DESCRIPTOR_TYPE_SINT64:
+      CASE(int64_t, varint, UPB_WIRE_TYPE_VARINT, upb_zzencode_64(val));
+    case UPB_DESCRIPTOR_TYPE_STRING:
+    case UPB_DESCRIPTOR_TYPE_BYTES: {
+      upb_stringview view = *(upb_stringview*)field_mem;
+      if (skip_zero_value && view.size == 0) {
+        return true;
+      }
+      return upb_put_bytes(e, view.data, view.size) &&
+          upb_put_varint(e, view.size) &&
+          upb_put_tag(e, f->number, UPB_WIRE_TYPE_DELIMITED);
+    }
+    case UPB_DESCRIPTOR_TYPE_GROUP: {
+      size_t size;
+      void *submsg = *(void**)field_mem;
+      const upb_msglayout_msginit_v1 *subm = m->submsgs[f->submsg_index];
+      if (skip_zero_value && submsg == NULL) {
+        return true;
+      }
+      return upb_put_tag(e, f->number, UPB_WIRE_TYPE_END_GROUP) &&
+          upb_encode_message(e, submsg, subm, &size) &&
+          upb_put_tag(e, f->number, UPB_WIRE_TYPE_START_GROUP);
+    }
+    case UPB_DESCRIPTOR_TYPE_MESSAGE: {
+      size_t size;
+      void *submsg = *(void**)field_mem;
+      const upb_msglayout_msginit_v1 *subm = m->submsgs[f->submsg_index];
+      if (skip_zero_value && submsg == NULL) {
+        return true;
+      }
+      return upb_encode_message(e, submsg, subm, &size) &&
+          upb_put_varint(e, size) &&
+          upb_put_tag(e, f->number, UPB_WIRE_TYPE_DELIMITED);
+    }
+  }
+#undef CASE
+  UPB_UNREACHABLE();
+}
+
+bool upb_encode_hasscalarfield(const char *msg,
+                               const upb_msglayout_msginit_v1 *m,
+                               const upb_msglayout_fieldinit_v1 *f) {
+  if (f->oneof_index != UPB_NOT_IN_ONEOF) {
+    return upb_readcase(msg, m, f->oneof_index) == f->number;
+  } else if (m->is_proto2) {
+    return upb_readhasbit(msg, f);
+  } else {
+    /* For proto3, we'll test for the field being empty later. */
+    return true;
+  }
+}
+
+bool upb_encode_message(upb_encstate* e, const char *msg,
+                        const upb_msglayout_msginit_v1 *m,
+                        size_t *size) {
+  int i;
+  size_t pre_len = e->limit - e->ptr;
+
+  if (msg == NULL) {
+    return true;
+  }
+
+  for (i = m->field_count - 1; i >= 0; i--) {
+    const upb_msglayout_fieldinit_v1 *f = &m->fields[i];
+
+    if (f->label == UPB_LABEL_REPEATED) {
+      CHK(upb_encode_array(e, msg + f->offset, m, f));
+    } else {
+      if (upb_encode_hasscalarfield(msg, m, f)) {
+        if (f->oneof_index == UPB_NOT_IN_ONEOF) {
+          CHK(upb_encode_scalarfield(e, msg + f->offset, m, f, !m->is_proto2));
+        } else {
+          const upb_msglayout_oneofinit_v1 *o = &m->oneofs[f->oneof_index];
+          CHK(upb_encode_scalarfield(e, msg + o->data_offset,
+                                     m, f, !m->is_proto2));
+        }
+      }
+    }
+  }
+
+  *size = (e->limit - e->ptr) - pre_len;
+  return true;
+}
+
+char *upb_encode(const void *msg, const upb_msglayout_msginit_v1 *m,
+                 upb_env *env, size_t *size) {
+  upb_encstate e;
+  e.env = env;
+  e.buf = NULL;
+  e.limit = NULL;
+  e.ptr = NULL;
+
+  if (!upb_encode_message(&e, msg, m, size)) {
+    *size = 0;
+    return NULL;
+  }
+
+  *size = e.limit - e.ptr;
+
+  if (*size == 0) {
+    static char ch;
+    return &ch;
+  } else {
+    UPB_ASSERT(e.ptr);
+    return e.ptr;
+  }
+}
+
+#undef CHK
+/*
+** TODO(haberman): it's unclear whether a lot of the consistency checks should
+** UPB_ASSERT() or return false.
+*/
+
+
+#include <string.h>
+
+
+static void *upb_calloc(size_t size) {
+  void *mem = upb_gmalloc(size);
+  if (mem) {
+    memset(mem, 0, size);
+  }
+  return mem;
+}
+
+/* Defined for the sole purpose of having a unique pointer value for
+ * UPB_NO_CLOSURE. */
+char _upb_noclosure;
+
+static void freehandlers(upb_refcounted *r) {
+  upb_handlers *h = (upb_handlers*)r;
+
+  upb_inttable_iter i;
+  upb_inttable_begin(&i, &h->cleanup_);
+  for(; !upb_inttable_done(&i); upb_inttable_next(&i)) {
+    void *val = (void*)upb_inttable_iter_key(&i);
+    upb_value func_val = upb_inttable_iter_value(&i);
+    upb_handlerfree *func = upb_value_getfptr(func_val);
+    func(val);
+  }
+
+  upb_inttable_uninit(&h->cleanup_);
+  upb_msgdef_unref(h->msg, h);
+  upb_gfree(h->sub);
+  upb_gfree(h);
+}
+
+static void visithandlers(const upb_refcounted *r, upb_refcounted_visit *visit,
+                          void *closure) {
+  const upb_handlers *h = (const upb_handlers*)r;
+  upb_msg_field_iter i;
+  for(upb_msg_field_begin(&i, h->msg);
+      !upb_msg_field_done(&i);
+      upb_msg_field_next(&i)) {
+    upb_fielddef *f = upb_msg_iter_field(&i);
+    const upb_handlers *sub;
+    if (!upb_fielddef_issubmsg(f)) continue;
+    sub = upb_handlers_getsubhandlers(h, f);
+    if (sub) visit(r, upb_handlers_upcast(sub), closure);
+  }
+}
+
+static const struct upb_refcounted_vtbl vtbl = {visithandlers, freehandlers};
+
+typedef struct {
+  upb_inttable tab;  /* maps upb_msgdef* -> upb_handlers*. */
+  upb_handlers_callback *callback;
+  const void *closure;
+} dfs_state;
+
+/* TODO(haberman): discard upb_handlers* objects that do not actually have any
+ * handlers set and cannot reach any upb_handlers* object that does.  This is
+ * slightly tricky to do correctly. */
+static upb_handlers *newformsg(const upb_msgdef *m, const void *owner,
+                               dfs_state *s) {
+  upb_msg_field_iter i;
+  upb_handlers *h = upb_handlers_new(m, owner);
+  if (!h) return NULL;
+  if (!upb_inttable_insertptr(&s->tab, m, upb_value_ptr(h))) goto oom;
+
+  s->callback(s->closure, h);
+
+  /* For each submessage field, get or create a handlers object and set it as
+   * the subhandlers. */
+  for(upb_msg_field_begin(&i, m);
+      !upb_msg_field_done(&i);
+      upb_msg_field_next(&i)) {
+    upb_fielddef *f = upb_msg_iter_field(&i);
+    const upb_msgdef *subdef;
+    upb_value subm_ent;
+
+    if (!upb_fielddef_issubmsg(f)) continue;
+
+    subdef = upb_downcast_msgdef(upb_fielddef_subdef(f));
+    if (upb_inttable_lookupptr(&s->tab, subdef, &subm_ent)) {
+      upb_handlers_setsubhandlers(h, f, upb_value_getptr(subm_ent));
+    } else {
+      upb_handlers *sub_mh = newformsg(subdef, &sub_mh, s);
+      if (!sub_mh) goto oom;
+      upb_handlers_setsubhandlers(h, f, sub_mh);
+      upb_handlers_unref(sub_mh, &sub_mh);
+    }
+  }
+  return h;
+
+oom:
+  upb_handlers_unref(h, owner);
+  return NULL;
+}
+
+/* Given a selector for a STARTSUBMSG handler, resolves to a pointer to the
+ * subhandlers for this submessage field. */
+#define SUBH(h, selector) (h->sub[selector])
+
+/* The selector for a submessage field is the field index. */
+#define SUBH_F(h, f) SUBH(h, f->index_)
+
+static int32_t trygetsel(upb_handlers *h, const upb_fielddef *f,
+                         upb_handlertype_t type) {
+  upb_selector_t sel;
+  UPB_ASSERT(!upb_handlers_isfrozen(h));
+  if (upb_handlers_msgdef(h) != upb_fielddef_containingtype(f)) {
+    upb_status_seterrf(
+        &h->status_, "type mismatch: field %s does not belong to message %s",
+        upb_fielddef_name(f), upb_msgdef_fullname(upb_handlers_msgdef(h)));
+    return -1;
+  }
+  if (!upb_handlers_getselector(f, type, &sel)) {
+    upb_status_seterrf(
+        &h->status_,
+        "type mismatch: cannot register handler type %d for field %s",
+        type, upb_fielddef_name(f));
+    return -1;
+  }
+  return sel;
+}
+
+static upb_selector_t handlers_getsel(upb_handlers *h, const upb_fielddef *f,
+                             upb_handlertype_t type) {
+  int32_t sel = trygetsel(h, f, type);
+  UPB_ASSERT(sel >= 0);
+  return sel;
+}
+
+static const void **returntype(upb_handlers *h, const upb_fielddef *f,
+                               upb_handlertype_t type) {
+  return &h->table[handlers_getsel(h, f, type)].attr.return_closure_type_;
+}
+
+static bool doset(upb_handlers *h, int32_t sel, const upb_fielddef *f,
+                  upb_handlertype_t type, upb_func *func,
+                  upb_handlerattr *attr) {
+  upb_handlerattr set_attr = UPB_HANDLERATTR_INITIALIZER;
+  const void *closure_type;
+  const void **context_closure_type;
+
+  UPB_ASSERT(!upb_handlers_isfrozen(h));
+
+  if (sel < 0) {
+    upb_status_seterrmsg(&h->status_,
+                         "incorrect handler type for this field.");
+    return false;
+  }
+
+  if (h->table[sel].func) {
+    upb_status_seterrmsg(&h->status_,
+                         "cannot change handler once it has been set.");
+    return false;
+  }
+
+  if (attr) {
+    set_attr = *attr;
+  }
+
+  /* Check that the given closure type matches the closure type that has been
+   * established for this context (if any). */
+  closure_type = upb_handlerattr_closuretype(&set_attr);
+
+  if (type == UPB_HANDLER_STRING) {
+    context_closure_type = returntype(h, f, UPB_HANDLER_STARTSTR);
+  } else if (f && upb_fielddef_isseq(f) &&
+             type != UPB_HANDLER_STARTSEQ &&
+             type != UPB_HANDLER_ENDSEQ) {
+    context_closure_type = returntype(h, f, UPB_HANDLER_STARTSEQ);
+  } else {
+    context_closure_type = &h->top_closure_type;
+  }
+
+  if (closure_type && *context_closure_type &&
+      closure_type != *context_closure_type) {
+    /* TODO(haberman): better message for debugging. */
+    if (f) {
+      upb_status_seterrf(&h->status_,
+                         "closure type does not match for field %s",
+                         upb_fielddef_name(f));
+    } else {
+      upb_status_seterrmsg(
+          &h->status_, "closure type does not match for message-level handler");
+    }
+    return false;
+  }
+
+  if (closure_type)
+    *context_closure_type = closure_type;
+
+  /* If this is a STARTSEQ or STARTSTR handler, check that the returned pointer
+   * matches any pre-existing expectations about what type is expected. */
+  if (type == UPB_HANDLER_STARTSEQ || type == UPB_HANDLER_STARTSTR) {
+    const void *return_type = upb_handlerattr_returnclosuretype(&set_attr);
+    const void *table_return_type =
+        upb_handlerattr_returnclosuretype(&h->table[sel].attr);
+    if (return_type && table_return_type && return_type != table_return_type) {
+      upb_status_seterrmsg(&h->status_, "closure return type does not match");
+      return false;
+    }
+
+    if (table_return_type && !return_type)
+      upb_handlerattr_setreturnclosuretype(&set_attr, table_return_type);
+  }
+
+  h->table[sel].func = (upb_func*)func;
+  h->table[sel].attr = set_attr;
+  return true;
+}
+
+/* Returns the effective closure type for this handler (which will propagate
+ * from outer frames if this frame has no START* handler).  Not implemented for
+ * UPB_HANDLER_STRING at the moment since this is not needed.  Returns NULL is
+ * the effective closure type is unspecified (either no handler was registered
+ * to specify it or the handler that was registered did not specify the closure
+ * type). */
+const void *effective_closure_type(upb_handlers *h, const upb_fielddef *f,
+                                   upb_handlertype_t type) {
+  const void *ret;
+  upb_selector_t sel;
+
+  UPB_ASSERT(type != UPB_HANDLER_STRING);
+  ret = h->top_closure_type;
+
+  if (upb_fielddef_isseq(f) &&
+      type != UPB_HANDLER_STARTSEQ &&
+      type != UPB_HANDLER_ENDSEQ &&
+      h->table[sel = handlers_getsel(h, f, UPB_HANDLER_STARTSEQ)].func) {
+    ret = upb_handlerattr_returnclosuretype(&h->table[sel].attr);
+  }
+
+  if (type == UPB_HANDLER_STRING &&
+      h->table[sel = handlers_getsel(h, f, UPB_HANDLER_STARTSTR)].func) {
+    ret = upb_handlerattr_returnclosuretype(&h->table[sel].attr);
+  }
+
+  /* The effective type of the submessage; not used yet.
+   * if (type == SUBMESSAGE &&
+   *     h->table[sel = handlers_getsel(h, f, UPB_HANDLER_STARTSUBMSG)].func) {
+   *   ret = upb_handlerattr_returnclosuretype(&h->table[sel].attr);
+   * } */
+
+  return ret;
+}
+
+/* Checks whether the START* handler specified by f & type is missing even
+ * though it is required to convert the established type of an outer frame
+ * ("closure_type") into the established type of an inner frame (represented in
+ * the return closure type of this handler's attr. */
+bool checkstart(upb_handlers *h, const upb_fielddef *f, upb_handlertype_t type,
+                upb_status *status) {
+  const void *closure_type;
+  const upb_handlerattr *attr;
+  const void *return_closure_type;
+
+  upb_selector_t sel = handlers_getsel(h, f, type);
+  if (h->table[sel].func) return true;
+  closure_type = effective_closure_type(h, f, type);
+  attr = &h->table[sel].attr;
+  return_closure_type = upb_handlerattr_returnclosuretype(attr);
+  if (closure_type && return_closure_type &&
+      closure_type != return_closure_type) {
+    upb_status_seterrf(status,
+                       "expected start handler to return sub type for field %f",
+                       upb_fielddef_name(f));
+    return false;
+  }
+  return true;
+}
+
+/* Public interface ***********************************************************/
+
+upb_handlers *upb_handlers_new(const upb_msgdef *md, const void *owner) {
+  int extra;
+  upb_handlers *h;
+
+  UPB_ASSERT(upb_msgdef_isfrozen(md));
+
+  extra = sizeof(upb_handlers_tabent) * (md->selector_count - 1);
+  h = upb_calloc(sizeof(*h) + extra);
+  if (!h) return NULL;
+
+  h->msg = md;
+  upb_msgdef_ref(h->msg, h);
+  upb_status_clear(&h->status_);
+
+  if (md->submsg_field_count > 0) {
+    h->sub = upb_calloc(md->submsg_field_count * sizeof(*h->sub));
+    if (!h->sub) goto oom;
+  } else {
+    h->sub = 0;
+  }
+
+  if (!upb_refcounted_init(upb_handlers_upcast_mutable(h), &vtbl, owner))
+    goto oom;
+  if (!upb_inttable_init(&h->cleanup_, UPB_CTYPE_FPTR)) goto oom;
+
+  /* calloc() above initialized all handlers to NULL. */
+  return h;
+
+oom:
+  freehandlers(upb_handlers_upcast_mutable(h));
+  return NULL;
+}
+
+const upb_handlers *upb_handlers_newfrozen(const upb_msgdef *m,
+                                           const void *owner,
+                                           upb_handlers_callback *callback,
+                                           const void *closure) {
+  dfs_state state;
+  upb_handlers *ret;
+  bool ok;
+  upb_refcounted *r;
+
+  state.callback = callback;
+  state.closure = closure;
+  if (!upb_inttable_init(&state.tab, UPB_CTYPE_PTR)) return NULL;
+
+  ret = newformsg(m, owner, &state);
+
+  upb_inttable_uninit(&state.tab);
+  if (!ret) return NULL;
+
+  r = upb_handlers_upcast_mutable(ret);
+  ok = upb_refcounted_freeze(&r, 1, NULL, UPB_MAX_HANDLER_DEPTH);
+  UPB_ASSERT(ok);
+
+  return ret;
+}
+
+const upb_status *upb_handlers_status(upb_handlers *h) {
+  UPB_ASSERT(!upb_handlers_isfrozen(h));
+  return &h->status_;
+}
+
+void upb_handlers_clearerr(upb_handlers *h) {
+  UPB_ASSERT(!upb_handlers_isfrozen(h));
+  upb_status_clear(&h->status_);
+}
+
+#define SETTER(name, handlerctype, handlertype) \
+  bool upb_handlers_set ## name(upb_handlers *h, const upb_fielddef *f, \
+                                handlerctype func, upb_handlerattr *attr) { \
+    int32_t sel = trygetsel(h, f, handlertype); \
+    return doset(h, sel, f, handlertype, (upb_func*)func, attr); \
+  }
+
+SETTER(int32,       upb_int32_handlerfunc*,       UPB_HANDLER_INT32)
+SETTER(int64,       upb_int64_handlerfunc*,       UPB_HANDLER_INT64)
+SETTER(uint32,      upb_uint32_handlerfunc*,      UPB_HANDLER_UINT32)
+SETTER(uint64,      upb_uint64_handlerfunc*,      UPB_HANDLER_UINT64)
+SETTER(float,       upb_float_handlerfunc*,       UPB_HANDLER_FLOAT)
+SETTER(double,      upb_double_handlerfunc*,      UPB_HANDLER_DOUBLE)
+SETTER(bool,        upb_bool_handlerfunc*,        UPB_HANDLER_BOOL)
+SETTER(startstr,    upb_startstr_handlerfunc*,    UPB_HANDLER_STARTSTR)
+SETTER(string,      upb_string_handlerfunc*,      UPB_HANDLER_STRING)
+SETTER(endstr,      upb_endfield_handlerfunc*,    UPB_HANDLER_ENDSTR)
+SETTER(startseq,    upb_startfield_handlerfunc*,  UPB_HANDLER_STARTSEQ)
+SETTER(startsubmsg, upb_startfield_handlerfunc*,  UPB_HANDLER_STARTSUBMSG)
+SETTER(endsubmsg,   upb_endfield_handlerfunc*,    UPB_HANDLER_ENDSUBMSG)
+SETTER(endseq,      upb_endfield_handlerfunc*,    UPB_HANDLER_ENDSEQ)
+
+#undef SETTER
+
+bool upb_handlers_setunknown(upb_handlers *h, upb_unknown_handlerfunc *func,
+                             upb_handlerattr *attr) {
+  return doset(h, UPB_UNKNOWN_SELECTOR, NULL, UPB_HANDLER_INT32,
+               (upb_func *)func, attr);
+}
+
+bool upb_handlers_setstartmsg(upb_handlers *h, upb_startmsg_handlerfunc *func,
+                              upb_handlerattr *attr) {
+  return doset(h, UPB_STARTMSG_SELECTOR, NULL, UPB_HANDLER_INT32,
+               (upb_func *)func, attr);
+}
+
+bool upb_handlers_setendmsg(upb_handlers *h, upb_endmsg_handlerfunc *func,
+                            upb_handlerattr *attr) {
+  UPB_ASSERT(!upb_handlers_isfrozen(h));
+  return doset(h, UPB_ENDMSG_SELECTOR, NULL, UPB_HANDLER_INT32,
+               (upb_func *)func, attr);
+}
+
+bool upb_handlers_setsubhandlers(upb_handlers *h, const upb_fielddef *f,
+                                 const upb_handlers *sub) {
+  UPB_ASSERT(sub);
+  UPB_ASSERT(!upb_handlers_isfrozen(h));
+  UPB_ASSERT(upb_fielddef_issubmsg(f));
+  if (SUBH_F(h, f)) return false;  /* Can't reset. */
+  if (upb_msgdef_upcast(upb_handlers_msgdef(sub)) != upb_fielddef_subdef(f)) {
+    return false;
+  }
+  SUBH_F(h, f) = sub;
+  upb_ref2(sub, h);
+  return true;
+}
+
+const upb_handlers *upb_handlers_getsubhandlers(const upb_handlers *h,
+                                                const upb_fielddef *f) {
+  UPB_ASSERT(upb_fielddef_issubmsg(f));
+  return SUBH_F(h, f);
+}
+
+bool upb_handlers_getattr(const upb_handlers *h, upb_selector_t sel,
+                          upb_handlerattr *attr) {
+  if (!upb_handlers_gethandler(h, sel))
+    return false;
+  *attr = h->table[sel].attr;
+  return true;
+}
+
+const upb_handlers *upb_handlers_getsubhandlers_sel(const upb_handlers *h,
+                                                    upb_selector_t sel) {
+  /* STARTSUBMSG selector in sel is the field's selector base. */
+  return SUBH(h, sel - UPB_STATIC_SELECTOR_COUNT);
+}
+
+const upb_msgdef *upb_handlers_msgdef(const upb_handlers *h) { return h->msg; }
+
+bool upb_handlers_addcleanup(upb_handlers *h, void *p, upb_handlerfree *func) {
+  bool ok;
+  if (upb_inttable_lookupptr(&h->cleanup_, p, NULL)) {
+    return false;
+  }
+  ok = upb_inttable_insertptr(&h->cleanup_, p, upb_value_fptr(func));
+  UPB_ASSERT(ok);
+  return true;
+}
+
+
+/* "Static" methods ***********************************************************/
+
+bool upb_handlers_freeze(upb_handlers *const*handlers, int n, upb_status *s) {
+  /* TODO: verify we have a transitive closure. */
+  int i;
+  for (i = 0; i < n; i++) {
+    upb_msg_field_iter j;
+    upb_handlers *h = handlers[i];
+
+    if (!upb_ok(&h->status_)) {
+      upb_status_seterrf(s, "handlers for message %s had error status: %s",
+                         upb_msgdef_fullname(upb_handlers_msgdef(h)),
+                         upb_status_errmsg(&h->status_));
+      return false;
+    }
+
+    /* Check that there are no closure mismatches due to missing Start* handlers
+     * or subhandlers with different type-level types. */
+    for(upb_msg_field_begin(&j, h->msg);
+        !upb_msg_field_done(&j);
+        upb_msg_field_next(&j)) {
+
+      const upb_fielddef *f = upb_msg_iter_field(&j);
+      if (upb_fielddef_isseq(f)) {
+        if (!checkstart(h, f, UPB_HANDLER_STARTSEQ, s))
+          return false;
+      }
+
+      if (upb_fielddef_isstring(f)) {
+        if (!checkstart(h, f, UPB_HANDLER_STARTSTR, s))
+          return false;
+      }
+
+      if (upb_fielddef_issubmsg(f)) {
+        bool hashandler = false;
+        if (upb_handlers_gethandler(
+                h, handlers_getsel(h, f, UPB_HANDLER_STARTSUBMSG)) ||
+            upb_handlers_gethandler(
+                h, handlers_getsel(h, f, UPB_HANDLER_ENDSUBMSG))) {
+          hashandler = true;
+        }
+
+        if (upb_fielddef_isseq(f) &&
+            (upb_handlers_gethandler(
+                 h, handlers_getsel(h, f, UPB_HANDLER_STARTSEQ)) ||
+             upb_handlers_gethandler(
+                 h, handlers_getsel(h, f, UPB_HANDLER_ENDSEQ)))) {
+          hashandler = true;
+        }
+
+        if (hashandler && !upb_handlers_getsubhandlers(h, f)) {
+          /* For now we add an empty subhandlers in this case.  It makes the
+           * decoder code generator simpler, because it only has to handle two
+           * cases (submessage has handlers or not) as opposed to three
+           * (submessage has handlers in enclosing message but no subhandlers).
+           *
+           * This makes parsing less efficient in the case that we want to
+           * notice a submessage but skip its contents (like if we're testing
+           * for submessage presence or counting the number of repeated
+           * submessages).  In this case we will end up parsing the submessage
+           * field by field and throwing away the results for each, instead of
+           * skipping the whole delimited thing at once.  If this is an issue we
+           * can revisit it, but do remember that this only arises when you have
+           * handlers (startseq/startsubmsg/endsubmsg/endseq) set for the
+           * submessage but no subhandlers.  The uses cases for this are
+           * limited. */
+          upb_handlers *sub = upb_handlers_new(upb_fielddef_msgsubdef(f), &sub);
+          upb_handlers_setsubhandlers(h, f, sub);
+          upb_handlers_unref(sub, &sub);
+        }
+
+        /* TODO(haberman): check type of submessage.
+         * This is slightly tricky; also consider whether we should check that
+         * they match at setsubhandlers time. */
+      }
+    }
+  }
+
+  if (!upb_refcounted_freeze((upb_refcounted*const*)handlers, n, s,
+                             UPB_MAX_HANDLER_DEPTH)) {
+    return false;
+  }
+
+  return true;
+}
+
+upb_handlertype_t upb_handlers_getprimitivehandlertype(const upb_fielddef *f) {
+  switch (upb_fielddef_type(f)) {
+    case UPB_TYPE_INT32:
+    case UPB_TYPE_ENUM: return UPB_HANDLER_INT32;
+    case UPB_TYPE_INT64: return UPB_HANDLER_INT64;
+    case UPB_TYPE_UINT32: return UPB_HANDLER_UINT32;
+    case UPB_TYPE_UINT64: return UPB_HANDLER_UINT64;
+    case UPB_TYPE_FLOAT: return UPB_HANDLER_FLOAT;
+    case UPB_TYPE_DOUBLE: return UPB_HANDLER_DOUBLE;
+    case UPB_TYPE_BOOL: return UPB_HANDLER_BOOL;
+    default: UPB_ASSERT(false); return -1;  /* Invalid input. */
+  }
+}
+
+bool upb_handlers_getselector(const upb_fielddef *f, upb_handlertype_t type,
+                              upb_selector_t *s) {
+  switch (type) {
+    case UPB_HANDLER_INT32:
+    case UPB_HANDLER_INT64:
+    case UPB_HANDLER_UINT32:
+    case UPB_HANDLER_UINT64:
+    case UPB_HANDLER_FLOAT:
+    case UPB_HANDLER_DOUBLE:
+    case UPB_HANDLER_BOOL:
+      if (!upb_fielddef_isprimitive(f) ||
+          upb_handlers_getprimitivehandlertype(f) != type)
+        return false;
+      *s = f->selector_base;
+      break;
+    case UPB_HANDLER_STRING:
+      if (upb_fielddef_isstring(f)) {
+        *s = f->selector_base;
+      } else if (upb_fielddef_lazy(f)) {
+        *s = f->selector_base + 3;
+      } else {
+        return false;
+      }
+      break;
+    case UPB_HANDLER_STARTSTR:
+      if (upb_fielddef_isstring(f) || upb_fielddef_lazy(f)) {
+        *s = f->selector_base + 1;
+      } else {
+        return false;
+      }
+      break;
+    case UPB_HANDLER_ENDSTR:
+      if (upb_fielddef_isstring(f) || upb_fielddef_lazy(f)) {
+        *s = f->selector_base + 2;
+      } else {
+        return false;
+      }
+      break;
+    case UPB_HANDLER_STARTSEQ:
+      if (!upb_fielddef_isseq(f)) return false;
+      *s = f->selector_base - 2;
+      break;
+    case UPB_HANDLER_ENDSEQ:
+      if (!upb_fielddef_isseq(f)) return false;
+      *s = f->selector_base - 1;
+      break;
+    case UPB_HANDLER_STARTSUBMSG:
+      if (!upb_fielddef_issubmsg(f)) return false;
+      /* Selectors for STARTSUBMSG are at the beginning of the table so that the
+       * selector can also be used as an index into the "sub" array of
+       * subhandlers.  The indexes for the two into these two tables are the
+       * same, except that in the handler table the static selectors come first. */
+      *s = f->index_ + UPB_STATIC_SELECTOR_COUNT;
+      break;
+    case UPB_HANDLER_ENDSUBMSG:
+      if (!upb_fielddef_issubmsg(f)) return false;
+      *s = f->selector_base;
+      break;
+  }
+  UPB_ASSERT((size_t)*s < upb_fielddef_containingtype(f)->selector_count);
+  return true;
+}
+
+uint32_t upb_handlers_selectorbaseoffset(const upb_fielddef *f) {
+  return upb_fielddef_isseq(f) ? 2 : 0;
+}
+
+uint32_t upb_handlers_selectorcount(const upb_fielddef *f) {
+  uint32_t ret = 1;
+  if (upb_fielddef_isseq(f)) ret += 2;    /* STARTSEQ/ENDSEQ */
+  if (upb_fielddef_isstring(f)) ret += 2; /* [STRING]/STARTSTR/ENDSTR */
+  if (upb_fielddef_issubmsg(f)) {
+    /* ENDSUBMSG (STARTSUBMSG is at table beginning) */
+    ret += 0;
+    if (upb_fielddef_lazy(f)) {
+      /* STARTSTR/ENDSTR/STRING (for lazy) */
+      ret += 3;
+    }
+  }
+  return ret;
+}
+
+
+/* upb_handlerattr ************************************************************/
+
+void upb_handlerattr_init(upb_handlerattr *attr) {
+  upb_handlerattr from = UPB_HANDLERATTR_INITIALIZER;
+  memcpy(attr, &from, sizeof(*attr));
+}
+
+void upb_handlerattr_uninit(upb_handlerattr *attr) {
+  UPB_UNUSED(attr);
+}
+
+bool upb_handlerattr_sethandlerdata(upb_handlerattr *attr, const void *hd) {
+  attr->handler_data_ = hd;
+  return true;
+}
+
+bool upb_handlerattr_setclosuretype(upb_handlerattr *attr, const void *type) {
+  attr->closure_type_ = type;
+  return true;
+}
+
+const void *upb_handlerattr_closuretype(const upb_handlerattr *attr) {
+  return attr->closure_type_;
+}
+
+bool upb_handlerattr_setreturnclosuretype(upb_handlerattr *attr,
+                                          const void *type) {
+  attr->return_closure_type_ = type;
+  return true;
+}
+
+const void *upb_handlerattr_returnclosuretype(const upb_handlerattr *attr) {
+  return attr->return_closure_type_;
+}
+
+bool upb_handlerattr_setalwaysok(upb_handlerattr *attr, bool alwaysok) {
+  attr->alwaysok_ = alwaysok;
+  return true;
+}
+
+bool upb_handlerattr_alwaysok(const upb_handlerattr *attr) {
+  return attr->alwaysok_;
+}
+
+/* upb_bufhandle **************************************************************/
+
+size_t upb_bufhandle_objofs(const upb_bufhandle *h) {
+  return h->objofs_;
+}
+
+/* upb_byteshandler ***********************************************************/
+
+void upb_byteshandler_init(upb_byteshandler* h) {
+  memset(h, 0, sizeof(*h));
+}
+
+/* For when we support handlerfree callbacks. */
+void upb_byteshandler_uninit(upb_byteshandler* h) {
+  UPB_UNUSED(h);
+}
+
+bool upb_byteshandler_setstartstr(upb_byteshandler *h,
+                                  upb_startstr_handlerfunc *func, void *d) {
+  h->table[UPB_STARTSTR_SELECTOR].func = (upb_func*)func;
+  h->table[UPB_STARTSTR_SELECTOR].attr.handler_data_ = d;
+  return true;
+}
+
+bool upb_byteshandler_setstring(upb_byteshandler *h,
+                                upb_string_handlerfunc *func, void *d) {
+  h->table[UPB_STRING_SELECTOR].func = (upb_func*)func;
+  h->table[UPB_STRING_SELECTOR].attr.handler_data_ = d;
+  return true;
+}
+
+bool upb_byteshandler_setendstr(upb_byteshandler *h,
+                                upb_endfield_handlerfunc *func, void *d) {
+  h->table[UPB_ENDSTR_SELECTOR].func = (upb_func*)func;
+  h->table[UPB_ENDSTR_SELECTOR].attr.handler_data_ = d;
+  return true;
+}
+
+
+static bool is_power_of_two(size_t val) {
+  return (val & (val - 1)) == 0;
+}
+
+/* Align up to the given power of 2. */
+static size_t align_up(size_t val, size_t align) {
+  UPB_ASSERT(is_power_of_two(align));
+  return (val + align - 1) & ~(align - 1);
+}
+
+static size_t div_round_up(size_t n, size_t d) {
+  return (n + d - 1) / d;
+}
+
+bool upb_fieldtype_mapkeyok(upb_fieldtype_t type) {
+  return type == UPB_TYPE_BOOL || type == UPB_TYPE_INT32 ||
+         type == UPB_TYPE_UINT32 || type == UPB_TYPE_INT64 ||
+         type == UPB_TYPE_UINT64 || type == UPB_TYPE_STRING;
+}
+
+void *upb_array_pack(const upb_array *arr, void *p, size_t *ofs, size_t size);
+void *upb_map_pack(const upb_map *map, void *p, size_t *ofs, size_t size);
+
+#define PTR_AT(msg, ofs, type) (type*)((char*)msg + ofs)
+#define VOIDPTR_AT(msg, ofs) PTR_AT(msg, ofs, void)
+#define ENCODE_MAX_NESTING 64
+#define CHECK_TRUE(x) if (!(x)) { return false; }
+
+/** upb_msgval ****************************************************************/
+
+#define upb_alignof(t) offsetof(struct { char c; t x; }, x)
+
+/* These functions will generate real memcpy() calls on ARM sadly, because
+ * the compiler assumes they might not be aligned. */
+
+static upb_msgval upb_msgval_read(const void *p, size_t ofs,
+                                  uint8_t size) {
+  upb_msgval val;
+  p = (char*)p + ofs;
+  memcpy(&val, p, size);
+  return val;
+}
+
+static void upb_msgval_write(void *p, size_t ofs, upb_msgval val,
+                             uint8_t size) {
+  p = (char*)p + ofs;
+  memcpy(p, &val, size);
+}
+
+static size_t upb_msgval_sizeof(upb_fieldtype_t type) {
+  switch (type) {
+    case UPB_TYPE_DOUBLE:
+    case UPB_TYPE_INT64:
+    case UPB_TYPE_UINT64:
+      return 8;
+    case UPB_TYPE_ENUM:
+    case UPB_TYPE_INT32:
+    case UPB_TYPE_UINT32:
+    case UPB_TYPE_FLOAT:
+      return 4;
+    case UPB_TYPE_BOOL:
+      return 1;
+    case UPB_TYPE_MESSAGE:
+      return sizeof(void*);
+    case UPB_TYPE_BYTES:
+    case UPB_TYPE_STRING:
+      return sizeof(upb_stringview);
+  }
+  UPB_UNREACHABLE();
+}
+
+static uint8_t upb_msg_fieldsize(const upb_msglayout_fieldinit_v1 *field) {
+  if (field->label == UPB_LABEL_REPEATED) {
+    return sizeof(void*);
+  } else {
+    return upb_msgval_sizeof(upb_desctype_to_fieldtype[field->descriptortype]);
+  }
+}
+
+static uint8_t upb_msg_fielddefsize(const upb_fielddef *f) {
+  if (upb_fielddef_isseq(f)) {
+    return sizeof(void*);
+  } else {
+    return upb_msgval_sizeof(upb_fielddef_type(f));
+  }
+}
+
+/* TODO(haberman): this is broken right now because upb_msgval can contain
+ * a char* / size_t pair, which is too big for a upb_value.  To fix this
+ * we'll probably need to dynamically allocate a upb_msgval and store a
+ * pointer to that in the tables for extensions/maps. */
+static upb_value upb_toval(upb_msgval val) {
+  upb_value ret;
+  UPB_UNUSED(val);
+  memset(&ret, 0, sizeof(upb_value));  /* XXX */
+  return ret;
+}
+
+static upb_msgval upb_msgval_fromval(upb_value val) {
+  upb_msgval ret;
+  UPB_UNUSED(val);
+  memset(&ret, 0, sizeof(upb_msgval));  /* XXX */
+  return ret;
+}
+
+static upb_ctype_t upb_fieldtotabtype(upb_fieldtype_t type) {
+  switch (type) {
+    case UPB_TYPE_FLOAT: return UPB_CTYPE_FLOAT;
+    case UPB_TYPE_DOUBLE: return UPB_CTYPE_DOUBLE;
+    case UPB_TYPE_BOOL: return UPB_CTYPE_BOOL;
+    case UPB_TYPE_BYTES:
+    case UPB_TYPE_MESSAGE:
+    case UPB_TYPE_STRING: return UPB_CTYPE_CONSTPTR;
+    case UPB_TYPE_ENUM:
+    case UPB_TYPE_INT32: return UPB_CTYPE_INT32;
+    case UPB_TYPE_UINT32: return UPB_CTYPE_UINT32;
+    case UPB_TYPE_INT64: return UPB_CTYPE_INT64;
+    case UPB_TYPE_UINT64: return UPB_CTYPE_UINT64;
+    default: UPB_ASSERT(false); return 0;
+  }
+}
+
+static upb_msgval upb_msgval_fromdefault(const upb_fielddef *f) {
+  switch (upb_fielddef_type(f)) {
+      case UPB_TYPE_FLOAT:
+        return upb_msgval_float(upb_fielddef_defaultfloat(f));
+      case UPB_TYPE_DOUBLE:
+        return upb_msgval_double(upb_fielddef_defaultdouble(f));
+      case UPB_TYPE_BOOL:
+        return upb_msgval_bool(upb_fielddef_defaultbool(f));
+      case UPB_TYPE_STRING:
+      case UPB_TYPE_BYTES: {
+        size_t len;
+        const char *ptr = upb_fielddef_defaultstr(f, &len);
+        return upb_msgval_makestr(ptr, len);
+      }
+      case UPB_TYPE_MESSAGE:
+        return upb_msgval_msg(NULL);
+      case UPB_TYPE_ENUM:
+      case UPB_TYPE_INT32:
+        return upb_msgval_int32(upb_fielddef_defaultint32(f));
+      case UPB_TYPE_UINT32:
+        return upb_msgval_uint32(upb_fielddef_defaultuint32(f));
+      case UPB_TYPE_INT64:
+        return upb_msgval_int64(upb_fielddef_defaultint64(f));
+      case UPB_TYPE_UINT64:
+        return upb_msgval_uint64(upb_fielddef_defaultuint64(f));
+      default:
+        UPB_ASSERT(false);
+        return upb_msgval_msg(NULL);
+  }
+}
+
+
+/** upb_msglayout *************************************************************/
+
+struct upb_msglayout {
+  struct upb_msglayout_msginit_v1 data;
+};
+
+static void upb_msglayout_free(upb_msglayout *l) {
+  upb_gfree(l->data.default_msg);
+  upb_gfree(l);
+}
+
+static size_t upb_msglayout_place(upb_msglayout *l, size_t size) {
+  size_t ret;
+
+  l->data.size = align_up(l->data.size, size);
+  ret = l->data.size;
+  l->data.size += size;
+  return ret;
+}
+
+static uint32_t upb_msglayout_offset(const upb_msglayout *l,
+                                     const upb_fielddef *f) {
+  return l->data.fields[upb_fielddef_index(f)].offset;
+}
+
+static uint32_t upb_msglayout_hasbit(const upb_msglayout *l,
+                                     const upb_fielddef *f) {
+  return l->data.fields[upb_fielddef_index(f)].hasbit;
+}
+
+static bool upb_msglayout_initdefault(upb_msglayout *l, const upb_msgdef *m) {
+  upb_msg_field_iter it;
+
+  if (upb_msgdef_syntax(m) == UPB_SYNTAX_PROTO2 && l->data.size) {
+    /* Allocate default message and set default values in it. */
+    l->data.default_msg = upb_gmalloc(l->data.size);
+    if (!l->data.default_msg) {
+      return false;
+    }
+
+    memset(l->data.default_msg, 0, l->data.size);
+
+    for (upb_msg_field_begin(&it, m); !upb_msg_field_done(&it);
+         upb_msg_field_next(&it)) {
+      const upb_fielddef* f = upb_msg_iter_field(&it);
+
+      if (upb_fielddef_containingoneof(f)) {
+        continue;
+      }
+
+      /* TODO(haberman): handle strings. */
+      if (!upb_fielddef_isstring(f) &&
+          !upb_fielddef_issubmsg(f) &&
+          !upb_fielddef_isseq(f)) {
+        upb_msg_set(l->data.default_msg,
+                    upb_fielddef_index(f),
+                    upb_msgval_fromdefault(f),
+                    l);
+      }
+    }
+  }
+
+  return true;
+}
+
+static bool upb_msglayout_init(const upb_msgdef *m,
+                               upb_msglayout *l,
+                               upb_msgfactory *factory) {
+  upb_msg_field_iter it;
+  upb_msg_oneof_iter oit;
+  size_t hasbit;
+  size_t submsg_count = 0;
+  const upb_msglayout_msginit_v1 **submsgs;
+  upb_msglayout_fieldinit_v1 *fields;
+  upb_msglayout_oneofinit_v1 *oneofs;
+
+  for (upb_msg_field_begin(&it, m);
+       !upb_msg_field_done(&it);
+       upb_msg_field_next(&it)) {
+    const upb_fielddef* f = upb_msg_iter_field(&it);
+    if (upb_fielddef_issubmsg(f)) {
+      submsg_count++;
+    }
+  }
+
+  memset(l, 0, sizeof(*l));
+
+  fields = upb_gmalloc(upb_msgdef_numfields(m) * sizeof(*fields));
+  submsgs = upb_gmalloc(submsg_count * sizeof(*submsgs));
+  oneofs = upb_gmalloc(upb_msgdef_numoneofs(m) * sizeof(*oneofs));
+
+  if ((!fields && upb_msgdef_numfields(m)) ||
+      (!submsgs && submsg_count) ||
+      (!oneofs && upb_msgdef_numoneofs(m))) {
+    /* OOM. */
+    upb_gfree(fields);
+    upb_gfree(submsgs);
+    upb_gfree(oneofs);
+    return false;
+  }
+
+  l->data.field_count = upb_msgdef_numfields(m);
+  l->data.oneof_count = upb_msgdef_numoneofs(m);
+  l->data.fields = fields;
+  l->data.submsgs = submsgs;
+  l->data.oneofs = oneofs;
+  l->data.is_proto2 = (upb_msgdef_syntax(m) == UPB_SYNTAX_PROTO2);
+
+  /* Allocate data offsets in three stages:
+   *
+   * 1. hasbits.
+   * 2. regular fields.
+   * 3. oneof fields.
+   *
+   * OPT: There is a lot of room for optimization here to minimize the size.
+   */
+
+  /* Allocate hasbits and set basic field attributes. */
+  submsg_count = 0;
+  for (upb_msg_field_begin(&it, m), hasbit = 0;
+       !upb_msg_field_done(&it);
+       upb_msg_field_next(&it)) {
+    const upb_fielddef* f = upb_msg_iter_field(&it);
+    upb_msglayout_fieldinit_v1 *field = &fields[upb_fielddef_index(f)];
+
+    field->number = upb_fielddef_number(f);
+    field->descriptortype = upb_fielddef_descriptortype(f);
+    field->label = upb_fielddef_label(f);
+
+    if (upb_fielddef_containingoneof(f)) {
+      field->oneof_index = upb_oneofdef_index(upb_fielddef_containingoneof(f));
+    } else {
+      field->oneof_index = UPB_NOT_IN_ONEOF;
+    }
+
+    if (upb_fielddef_issubmsg(f)) {
+      const upb_msglayout *sub_layout =
+          upb_msgfactory_getlayout(factory, upb_fielddef_msgsubdef(f));
+      field->submsg_index = submsg_count++;
+      submsgs[field->submsg_index] = &sub_layout->data;
+    } else {
+      field->submsg_index = UPB_NO_SUBMSG;
+    }
+
+    if (upb_fielddef_haspresence(f) && !upb_fielddef_containingoneof(f)) {
+      field->hasbit = hasbit++;
+    } else {
+      field->hasbit = UPB_NO_HASBIT;
+    }
+  }
+
+  /* Account for space used by hasbits. */
+  l->data.size = div_round_up(hasbit, 8);
+
+  /* Allocate non-oneof fields. */
+  for (upb_msg_field_begin(&it, m); !upb_msg_field_done(&it);
+       upb_msg_field_next(&it)) {
+    const upb_fielddef* f = upb_msg_iter_field(&it);
+    size_t field_size = upb_msg_fielddefsize(f);
+    size_t index = upb_fielddef_index(f);
+
+    if (upb_fielddef_containingoneof(f)) {
+      /* Oneofs are handled separately below. */
+      continue;
+    }
+
+    fields[index].offset = upb_msglayout_place(l, field_size);
+  }
+
+  /* Allocate oneof fields.  Each oneof field consists of a uint32 for the case
+   * and space for the actual data. */
+  for (upb_msg_oneof_begin(&oit, m); !upb_msg_oneof_done(&oit);
+       upb_msg_oneof_next(&oit)) {
+    const upb_oneofdef* o = upb_msg_iter_oneof(&oit);
+    upb_oneof_iter fit;
+
+    size_t case_size = sizeof(uint32_t);  /* Could potentially optimize this. */
+    upb_msglayout_oneofinit_v1 *oneof = &oneofs[upb_oneofdef_index(o)];
+    size_t field_size = 0;
+
+    /* Calculate field size: the max of all field sizes. */
+    for (upb_oneof_begin(&fit, o);
+         !upb_oneof_done(&fit);
+         upb_oneof_next(&fit)) {
+      const upb_fielddef* f = upb_oneof_iter_field(&fit);
+      field_size = UPB_MAX(field_size, upb_msg_fielddefsize(f));
+    }
+
+    /* Align and allocate case offset. */
+    oneof->case_offset = upb_msglayout_place(l, case_size);
+    oneof->data_offset = upb_msglayout_place(l, field_size);
+  }
+
+  /* Size of the entire structure should be a multiple of its greatest
+   * alignment.  TODO: track overall alignment for real? */
+  l->data.size = align_up(l->data.size, 8);
+
+  return upb_msglayout_initdefault(l, m);
+}
+
+
+/** upb_msgfactory ************************************************************/
+
+struct upb_msgfactory {
+  const upb_symtab *symtab;  /* We own a ref. */
+  upb_inttable layouts;
+  upb_inttable mergehandlers;
+};
+
+upb_msgfactory *upb_msgfactory_new(const upb_symtab *symtab) {
+  upb_msgfactory *ret = upb_gmalloc(sizeof(*ret));
+
+  ret->symtab = symtab;
+  upb_inttable_init(&ret->layouts, UPB_CTYPE_PTR);
+  upb_inttable_init(&ret->mergehandlers, UPB_CTYPE_CONSTPTR);
+
+  return ret;
+}
+
+void upb_msgfactory_free(upb_msgfactory *f) {
+  upb_inttable_iter i;
+  upb_inttable_begin(&i, &f->layouts);
+  for(; !upb_inttable_done(&i); upb_inttable_next(&i)) {
+    upb_msglayout *l = upb_value_getptr(upb_inttable_iter_value(&i));
+    upb_msglayout_free(l);
+  }
+
+  upb_inttable_begin(&i, &f->mergehandlers);
+  for(; !upb_inttable_done(&i); upb_inttable_next(&i)) {
+    const upb_handlers *h = upb_value_getconstptr(upb_inttable_iter_value(&i));
+    upb_handlers_unref(h, f);
+  }
+
+  upb_inttable_uninit(&f->layouts);
+  upb_inttable_uninit(&f->mergehandlers);
+  upb_gfree(f);
+}
+
+const upb_symtab *upb_msgfactory_symtab(const upb_msgfactory *f) {
+  return f->symtab;
+}
+
+const upb_msglayout *upb_msgfactory_getlayout(upb_msgfactory *f,
+                                              const upb_msgdef *m) {
+  upb_value v;
+  UPB_ASSERT(upb_symtab_lookupmsg(f->symtab, upb_msgdef_fullname(m)) == m);
+  UPB_ASSERT(!upb_msgdef_mapentry(m));
+
+  if (upb_inttable_lookupptr(&f->layouts, m, &v)) {
+    UPB_ASSERT(upb_value_getptr(v));
+    return upb_value_getptr(v);
+  } else {
+    /* In case of circular dependency, layout has to be inserted first. */
+    upb_msglayout *l = upb_gmalloc(sizeof(*l));
+    upb_msgfactory *mutable_f = (void*)f;
+    upb_inttable_insertptr(&mutable_f->layouts, m, upb_value_ptr(l));
+    UPB_ASSERT(l);
+    if (!upb_msglayout_init(m, l, f)) {
+      upb_msglayout_free(l);
+    }
+    return l;
+  }
+}
+
+/* Our handlers that we don't expose externally. */
+
+void *upb_msg_startstr(void *msg, const void *hd, size_t size_hint) {
+  uint32_t ofs = (uintptr_t)hd;
+  upb_alloc *alloc = upb_msg_alloc(msg);
+  upb_msgval val;
+  UPB_UNUSED(size_hint);
+
+  val = upb_msgval_read(msg, ofs, upb_msgval_sizeof(UPB_TYPE_STRING));
+
+  upb_free(alloc, (void*)val.str.data);
+  val.str.data = NULL;
+  val.str.size = 0;
+
+  upb_msgval_write(msg, ofs, val, upb_msgval_sizeof(UPB_TYPE_STRING));
+  return msg;
+}
+
+size_t upb_msg_str(void *msg, const void *hd, const char *ptr, size_t size,
+                   const upb_bufhandle *handle) {
+  uint32_t ofs = (uintptr_t)hd;
+  upb_alloc *alloc = upb_msg_alloc(msg);
+  upb_msgval val;
+  size_t newsize;
+  UPB_UNUSED(handle);
+
+  val = upb_msgval_read(msg, ofs, upb_msgval_sizeof(UPB_TYPE_STRING));
+
+  newsize = val.str.size + size;
+  val.str.data = upb_realloc(alloc, (void*)val.str.data, val.str.size, newsize);
+
+  if (!val.str.data) {
+    return false;
+  }
+
+  memcpy((char*)val.str.data + val.str.size, ptr, size);
+  val.str.size = newsize;
+  upb_msgval_write(msg, ofs, val, upb_msgval_sizeof(UPB_TYPE_STRING));
+  return size;
+}
+
+static void callback(const void *closure, upb_handlers *h) {
+  upb_msgfactory *factory = (upb_msgfactory*)closure;
+  const upb_msgdef *md = upb_handlers_msgdef(h);
+  const upb_msglayout* layout = upb_msgfactory_getlayout(factory, md);
+  upb_msg_field_iter i;
+  UPB_UNUSED(factory);
+
+  for(upb_msg_field_begin(&i, md);
+      !upb_msg_field_done(&i);
+      upb_msg_field_next(&i)) {
+    const upb_fielddef *f = upb_msg_iter_field(&i);
+    size_t offset = upb_msglayout_offset(layout, f);
+    upb_handlerattr attr = UPB_HANDLERATTR_INITIALIZER;
+    upb_handlerattr_sethandlerdata(&attr, (void*)offset);
+
+    if (upb_fielddef_isseq(f)) {
+    } else if (upb_fielddef_isstring(f)) {
+      upb_handlers_setstartstr(h, f, upb_msg_startstr, &attr);
+      upb_handlers_setstring(h, f, upb_msg_str, &attr);
+    } else {
+      upb_msg_setscalarhandler(
+          h, f, offset, upb_msglayout_hasbit(layout, f));
+    }
+  }
+}
+
+const upb_handlers *upb_msgfactory_getmergehandlers(upb_msgfactory *f,
+                                                    const upb_msgdef *m) {
+  upb_msgfactory *mutable_f = (void*)f;
+
+  /* TODO(haberman): properly cache these. */
+  const upb_handlers *ret = upb_handlers_newfrozen(m, f, callback, f);
+  upb_inttable_push(&mutable_f->mergehandlers, upb_value_constptr(ret));
+
+  return ret;
+}
+
+const upb_visitorplan *upb_msgfactory_getvisitorplan(upb_msgfactory *f,
+                                                     const upb_handlers *h) {
+  const upb_msgdef *md = upb_handlers_msgdef(h);
+  return (const upb_visitorplan*)upb_msgfactory_getlayout(f, md);
+}
+
+
+/** upb_visitor ***************************************************************/
+
+struct upb_visitor {
+  const upb_msglayout *layout;
+  upb_sink *sink;
+};
+
+static upb_selector_t getsel2(const upb_fielddef *f, upb_handlertype_t type) {
+  upb_selector_t ret;
+  bool ok = upb_handlers_getselector(f, type, &ret);
+  UPB_ASSERT(ok);
+  return ret;
+}
+
+static bool upb_visitor_hasfield(const upb_msg *msg, const upb_fielddef *f,
+                                 const upb_msglayout *layout) {
+  int field_index = upb_fielddef_index(f);
+  if (upb_fielddef_isseq(f)) {
+    return upb_msgval_getarr(upb_msg_get(msg, field_index, layout)) != NULL;
+  } else if (upb_msgdef_syntax(upb_fielddef_containingtype(f)) ==
+             UPB_SYNTAX_PROTO2) {
+    return upb_msg_has(msg, field_index, layout);
+  } else {
+    upb_msgval val = upb_msg_get(msg, field_index, layout);
+    switch (upb_fielddef_type(f)) {
+      case UPB_TYPE_FLOAT:
+        return upb_msgval_getfloat(val) != 0;
+      case UPB_TYPE_DOUBLE:
+        return upb_msgval_getdouble(val) != 0;
+      case UPB_TYPE_BOOL:
+        return upb_msgval_getbool(val);
+      case UPB_TYPE_ENUM:
+      case UPB_TYPE_INT32:
+        return upb_msgval_getint32(val) != 0;
+      case UPB_TYPE_UINT32:
+        return upb_msgval_getuint32(val) != 0;
+      case UPB_TYPE_INT64:
+        return upb_msgval_getint64(val) != 0;
+      case UPB_TYPE_UINT64:
+        return upb_msgval_getuint64(val) != 0;
+      case UPB_TYPE_STRING:
+      case UPB_TYPE_BYTES:
+        return upb_msgval_getstr(val).size > 0;
+      case UPB_TYPE_MESSAGE:
+        return upb_msgval_getmsg(val) != NULL;
+    }
+    UPB_UNREACHABLE();
+  }
+}
+
+static bool upb_visitor_visitmsg2(const upb_msg *msg,
+                                  const upb_msglayout *layout, upb_sink *sink,
+                                  int depth) {
+  const upb_msgdef *md = upb_handlers_msgdef(sink->handlers);
+  upb_msg_field_iter i;
+  upb_status status;
+
+  upb_sink_startmsg(sink);
+
+  /* Protect against cycles (possible because users may freely reassign message
+   * and repeated fields) by imposing a maximum recursion depth. */
+  if (depth > ENCODE_MAX_NESTING) {
+    return false;
+  }
+
+  for (upb_msg_field_begin(&i, md);
+       !upb_msg_field_done(&i);
+       upb_msg_field_next(&i)) {
+    upb_fielddef *f = upb_msg_iter_field(&i);
+    upb_msgval val;
+
+    if (!upb_visitor_hasfield(msg, f, layout)) {
+      continue;
+    }
+
+    val = upb_msg_get(msg, upb_fielddef_index(f), layout);
+
+    if (upb_fielddef_isseq(f)) {
+      const upb_array *arr = upb_msgval_getarr(val);
+      UPB_ASSERT(arr);
+      /* TODO: putary(ary, f, sink, depth);*/
+    } else if (upb_fielddef_issubmsg(f)) {
+      const upb_map *map = upb_msgval_getmap(val);
+      UPB_ASSERT(map);
+      /* TODO: putmap(map, f, sink, depth);*/
+    } else if (upb_fielddef_isstring(f)) {
+      /* TODO putstr(); */
+    } else {
+      upb_selector_t sel = getsel2(f, upb_handlers_getprimitivehandlertype(f));
+      UPB_ASSERT(upb_fielddef_isprimitive(f));
+
+      switch (upb_fielddef_type(f)) {
+        case UPB_TYPE_FLOAT:
+          CHECK_TRUE(upb_sink_putfloat(sink, sel, upb_msgval_getfloat(val)));
+          break;
+        case UPB_TYPE_DOUBLE:
+          CHECK_TRUE(upb_sink_putdouble(sink, sel, upb_msgval_getdouble(val)));
+          break;
+        case UPB_TYPE_BOOL:
+          CHECK_TRUE(upb_sink_putbool(sink, sel, upb_msgval_getbool(val)));
+          break;
+        case UPB_TYPE_ENUM:
+        case UPB_TYPE_INT32:
+          CHECK_TRUE(upb_sink_putint32(sink, sel, upb_msgval_getint32(val)));
+          break;
+        case UPB_TYPE_UINT32:
+          CHECK_TRUE(upb_sink_putuint32(sink, sel, upb_msgval_getuint32(val)));
+          break;
+        case UPB_TYPE_INT64:
+          CHECK_TRUE(upb_sink_putint64(sink, sel, upb_msgval_getint64(val)));
+          break;
+        case UPB_TYPE_UINT64:
+          CHECK_TRUE(upb_sink_putuint64(sink, sel, upb_msgval_getuint64(val)));
+          break;
+        case UPB_TYPE_STRING:
+        case UPB_TYPE_BYTES:
+        case UPB_TYPE_MESSAGE:
+          UPB_UNREACHABLE();
+      }
+    }
+  }
+
+  upb_sink_endmsg(sink, &status);
+  return true;
+}
+
+upb_visitor *upb_visitor_create(upb_env *e, const upb_visitorplan *vp,
+                                upb_sink *output) {
+  upb_visitor *visitor = upb_env_malloc(e, sizeof(*visitor));
+  visitor->layout = (const upb_msglayout*)vp;
+  visitor->sink = output;
+  return visitor;
+}
+
+bool upb_visitor_visitmsg(upb_visitor *visitor, const upb_msg *msg) {
+  return upb_visitor_visitmsg2(msg, visitor->layout, visitor->sink, 0);
+}
+
+
+/** upb_msg *******************************************************************/
+
+/* If we always read/write as a consistent type to each address, this shouldn't
+ * violate aliasing.
+ */
+#define DEREF(msg, ofs, type) *PTR_AT(msg, ofs, type)
+
+/* Internal members of a upb_msg.  We can change this without breaking binary
+ * compatibility.  We put these before the user's data.  The user's upb_msg*
+ * points after the upb_msg_internal. */
+
+/* Used when a message is not extendable. */
+typedef struct {
+  /* TODO(haberman): add unknown fields. */
+  upb_alloc *alloc;
+} upb_msg_internal;
+
+/* Used when a message is extendable. */
+typedef struct {
+  upb_inttable *extdict;
+  upb_msg_internal base;
+} upb_msg_internal_withext;
+
+static int upb_msg_internalsize(const upb_msglayout *l) {
+    return sizeof(upb_msg_internal) - l->data.extendable * sizeof(void*);
+}
+
+static upb_msg_internal *upb_msg_getinternal(upb_msg *msg) {
+  return VOIDPTR_AT(msg, -sizeof(upb_msg_internal));
+}
+
+static const upb_msg_internal *upb_msg_getinternal_const(const upb_msg *msg) {
+  return VOIDPTR_AT(msg, -sizeof(upb_msg_internal));
+}
+
+static upb_msg_internal_withext *upb_msg_getinternalwithext(
+    upb_msg *msg, const upb_msglayout *l) {
+  UPB_ASSERT(l->data.extendable);
+  return VOIDPTR_AT(msg, -sizeof(upb_msg_internal_withext));
+}
+
+static const upb_msglayout_fieldinit_v1 *upb_msg_checkfield(
+    int field_index, const upb_msglayout *l) {
+  UPB_ASSERT(field_index >= 0 && field_index < l->data.field_count);
+  return &l->data.fields[field_index];
+}
+
+static bool upb_msg_inoneof(const upb_msglayout_fieldinit_v1 *field) {
+  return field->oneof_index != UPB_NOT_IN_ONEOF;
+}
+
+static uint32_t *upb_msg_oneofcase(const upb_msg *msg, int field_index,
+                                   const upb_msglayout *l) {
+  const upb_msglayout_fieldinit_v1 *field = upb_msg_checkfield(field_index, l);
+  UPB_ASSERT(upb_msg_inoneof(field));
+  return PTR_AT(msg, l->data.oneofs[field->oneof_index].case_offset, uint32_t);
+}
+
+size_t upb_msg_sizeof(const upb_msglayout *l) {
+  return l->data.size + upb_msg_internalsize(l);
+}
+
+upb_msg *upb_msg_init(void *mem, const upb_msglayout *l, upb_alloc *a) {
+  upb_msg *msg = VOIDPTR_AT(mem, upb_msg_internalsize(l));
+
+  /* Initialize normal members. */
+  if (l->data.default_msg) {
+    memcpy(msg, l->data.default_msg, l->data.size);
+  } else {
+    memset(msg, 0, l->data.size);
+  }
+
+  /* Initialize internal members. */
+  upb_msg_getinternal(msg)->alloc = a;
+
+  if (l->data.extendable) {
+    upb_msg_getinternalwithext(msg, l)->extdict = NULL;
+  }
+
+  return msg;
+}
+
+void *upb_msg_uninit(upb_msg *msg, const upb_msglayout *l) {
+  if (l->data.extendable) {
+    upb_inttable *ext_dict = upb_msg_getinternalwithext(msg, l)->extdict;
+    if (ext_dict) {
+      upb_inttable_uninit2(ext_dict, upb_msg_alloc(msg));
+      upb_free(upb_msg_alloc(msg), ext_dict);
+    }
+  }
+
+  return VOIDPTR_AT(msg, -upb_msg_internalsize(l));
+}
+
+upb_msg *upb_msg_new(const upb_msglayout *l, upb_alloc *a) {
+  void *mem = upb_malloc(a, upb_msg_sizeof(l));
+  return mem ? upb_msg_init(mem, l, a) : NULL;
+}
+
+void upb_msg_free(upb_msg *msg, const upb_msglayout *l) {
+  upb_free(upb_msg_alloc(msg), upb_msg_uninit(msg, l));
+}
+
+upb_alloc *upb_msg_alloc(const upb_msg *msg) {
+  return upb_msg_getinternal_const(msg)->alloc;
+}
+
+bool upb_msg_has(const upb_msg *msg,
+                 int field_index,
+                 const upb_msglayout *l) {
+  const upb_msglayout_fieldinit_v1 *field = upb_msg_checkfield(field_index, l);
+
+  UPB_ASSERT(l->data.is_proto2);
+
+  if (upb_msg_inoneof(field)) {
+    /* Oneofs are set when the oneof number is set to this field. */
+    return *upb_msg_oneofcase(msg, field_index, l) == field->number;
+  } else {
+    /* Other fields are set when their hasbit is set. */
+    uint32_t hasbit = l->data.fields[field_index].hasbit;
+    return DEREF(msg, hasbit / 8, char) | (1 << (hasbit % 8));
+  }
+}
+
+upb_msgval upb_msg_get(const upb_msg *msg, int field_index,
+                       const upb_msglayout *l) {
+  const upb_msglayout_fieldinit_v1 *field = upb_msg_checkfield(field_index, l);
+  int size = upb_msg_fieldsize(field);
+
+  if (upb_msg_inoneof(field)) {
+    if (*upb_msg_oneofcase(msg, field_index, l) == field->number) {
+      size_t ofs = l->data.oneofs[field->oneof_index].data_offset;
+      return upb_msgval_read(msg, ofs, size);
+    } else {
+      /* Return default. */
+      return upb_msgval_read(l->data.default_msg, field->offset, size);
+    }
+  } else {
+    return upb_msgval_read(msg, field->offset, size);
+  }
+}
+
+void upb_msg_set(upb_msg *msg, int field_index, upb_msgval val,
+                 const upb_msglayout *l) {
+  const upb_msglayout_fieldinit_v1 *field = upb_msg_checkfield(field_index, l);
+  int size = upb_msg_fieldsize(field);
+
+  if (upb_msg_inoneof(field)) {
+    size_t ofs = l->data.oneofs[field->oneof_index].data_offset;
+    *upb_msg_oneofcase(msg, field_index, l) = field->number;
+    upb_msgval_write(msg, ofs, val, size);
+  } else {
+    upb_msgval_write(msg, field->offset, val, size);
+  }
+}
+
+
+/** upb_array *****************************************************************/
+
+#define DEREF_ARR(arr, i, type) ((type*)arr->data)[i]
+
+size_t upb_array_sizeof(upb_fieldtype_t type) {
+  UPB_UNUSED(type);
+  return sizeof(upb_array);
+}
+
+void upb_array_init(upb_array *arr, upb_fieldtype_t type, upb_alloc *alloc) {
+  arr->type = type;
+  arr->data = NULL;
+  arr->len = 0;
+  arr->size = 0;
+  arr->element_size = upb_msgval_sizeof(type);
+  arr->alloc = alloc;
+}
+
+void upb_array_uninit(upb_array *arr) {
+  upb_free(arr->alloc, arr->data);
+}
+
+upb_array *upb_array_new(upb_fieldtype_t type, upb_alloc *a) {
+  upb_array *ret = upb_malloc(a, upb_array_sizeof(type));
+
+  if (ret) {
+    upb_array_init(ret, type, a);
+  }
+
+  return ret;
+}
+
+void upb_array_free(upb_array *arr) {
+  upb_array_uninit(arr);
+  upb_free(arr->alloc, arr);
+}
+
+size_t upb_array_size(const upb_array *arr) {
+  return arr->len;
+}
+
+upb_fieldtype_t upb_array_type(const upb_array *arr) {
+  return arr->type;
+}
+
+upb_msgval upb_array_get(const upb_array *arr, size_t i) {
+  UPB_ASSERT(i < arr->len);
+  return upb_msgval_read(arr->data, i * arr->element_size, arr->element_size);
+}
+
+bool upb_array_set(upb_array *arr, size_t i, upb_msgval val) {
+  UPB_ASSERT(i <= arr->len);
+
+  if (i == arr->len) {
+    /* Extending the array. */
+
+    if (i == arr->size) {
+      /* Need to reallocate. */
+      size_t new_size = UPB_MAX(arr->size * 2, 8);
+      size_t new_bytes = new_size * arr->element_size;
+      size_t old_bytes = arr->size * arr->element_size;
+      upb_msgval *new_data =
+          upb_realloc(arr->alloc, arr->data, old_bytes, new_bytes);
+
+      if (!new_data) {
+        return false;
+      }
+
+      arr->data = new_data;
+      arr->size = new_size;
+    }
+
+    arr->len = i + 1;
+  }
+
+  upb_msgval_write(arr->data, i * arr->element_size, val, arr->element_size);
+  return true;
+}
+
+
+/** upb_map *******************************************************************/
+
+struct upb_map {
+  upb_fieldtype_t key_type;
+  upb_fieldtype_t val_type;
+  /* We may want to optimize this to use inttable where possible, for greater
+   * efficiency and lower memory footprint. */
+  upb_strtable strtab;
+  upb_alloc *alloc;
+};
+
+static void upb_map_tokey(upb_fieldtype_t type, upb_msgval *key,
+                          const char **out_key, size_t *out_len) {
+  switch (type) {
+    case UPB_TYPE_STRING:
+      /* Point to string data of the input key. */
+      *out_key = key->str.data;
+      *out_len = key->str.size;
+      return;
+    case UPB_TYPE_BOOL:
+    case UPB_TYPE_INT32:
+    case UPB_TYPE_UINT32:
+    case UPB_TYPE_INT64:
+    case UPB_TYPE_UINT64:
+      /* Point to the key itself.  XXX: big-endian. */
+      *out_key = (const char*)key;
+      *out_len = upb_msgval_sizeof(type);
+      return;
+    case UPB_TYPE_BYTES:
+    case UPB_TYPE_DOUBLE:
+    case UPB_TYPE_ENUM:
+    case UPB_TYPE_FLOAT:
+    case UPB_TYPE_MESSAGE:
+      break;  /* Cannot be a map key. */
+  }
+  UPB_UNREACHABLE();
+}
+
+static upb_msgval upb_map_fromkey(upb_fieldtype_t type, const char *key,
+                                  size_t len) {
+  switch (type) {
+    case UPB_TYPE_STRING:
+      return upb_msgval_makestr(key, len);
+    case UPB_TYPE_BOOL:
+    case UPB_TYPE_INT32:
+    case UPB_TYPE_UINT32:
+    case UPB_TYPE_INT64:
+    case UPB_TYPE_UINT64:
+      return upb_msgval_read(key, 0, upb_msgval_sizeof(type));
+    case UPB_TYPE_BYTES:
+    case UPB_TYPE_DOUBLE:
+    case UPB_TYPE_ENUM:
+    case UPB_TYPE_FLOAT:
+    case UPB_TYPE_MESSAGE:
+      break;  /* Cannot be a map key. */
+  }
+  UPB_UNREACHABLE();
+}
+
+size_t upb_map_sizeof(upb_fieldtype_t ktype, upb_fieldtype_t vtype) {
+  /* Size does not currently depend on key/value type. */
+  UPB_UNUSED(ktype);
+  UPB_UNUSED(vtype);
+  return sizeof(upb_map);
+}
+
+bool upb_map_init(upb_map *map, upb_fieldtype_t ktype, upb_fieldtype_t vtype,
+                  upb_alloc *a) {
+  upb_ctype_t vtabtype = upb_fieldtotabtype(vtype);
+  UPB_ASSERT(upb_fieldtype_mapkeyok(ktype));
+  map->key_type = ktype;
+  map->val_type = vtype;
+  map->alloc = a;
+
+  if (!upb_strtable_init2(&map->strtab, vtabtype, a)) {
+    return false;
+  }
+
+  return true;
+}
+
+void upb_map_uninit(upb_map *map) {
+  upb_strtable_uninit2(&map->strtab, map->alloc);
+}
+
+upb_map *upb_map_new(upb_fieldtype_t ktype, upb_fieldtype_t vtype,
+                     upb_alloc *a) {
+  upb_map *map = upb_malloc(a, upb_map_sizeof(ktype, vtype));
+
+  if (!map) {
+    return NULL;
+  }
+
+  if (!upb_map_init(map, ktype, vtype, a)) {
+    return NULL;
+  }
+
+  return map;
+}
+
+void upb_map_free(upb_map *map) {
+  upb_map_uninit(map);
+  upb_free(map->alloc, map);
+}
+
+size_t upb_map_size(const upb_map *map) {
+  return upb_strtable_count(&map->strtab);
+}
+
+upb_fieldtype_t upb_map_keytype(const upb_map *map) {
+  return map->key_type;
+}
+
+upb_fieldtype_t upb_map_valuetype(const upb_map *map) {
+  return map->val_type;
+}
+
+bool upb_map_get(const upb_map *map, upb_msgval key, upb_msgval *val) {
+  upb_value tabval;
+  const char *key_str;
+  size_t key_len;
+  bool ret;
+
+  upb_map_tokey(map->key_type, &key, &key_str, &key_len);
+  ret = upb_strtable_lookup2(&map->strtab, key_str, key_len, &tabval);
+  if (ret) {
+    memcpy(val, &tabval, sizeof(tabval));
+  }
+
+  return ret;
+}
+
+bool upb_map_set(upb_map *map, upb_msgval key, upb_msgval val,
+                 upb_msgval *removed) {
+  const char *key_str;
+  size_t key_len;
+  upb_value tabval = upb_toval(val);
+  upb_value removedtabval;
+  upb_alloc *a = map->alloc;
+
+  upb_map_tokey(map->key_type, &key, &key_str, &key_len);
+
+  /* TODO(haberman): add overwrite operation to minimize number of lookups. */
+  if (upb_strtable_lookup2(&map->strtab, key_str, key_len, NULL)) {
+    upb_strtable_remove3(&map->strtab, key_str, key_len, &removedtabval, a);
+    memcpy(&removed, &removedtabval, sizeof(removed));
+  }
+
+  return upb_strtable_insert3(&map->strtab, key_str, key_len, tabval, a);
+}
+
+bool upb_map_del(upb_map *map, upb_msgval key) {
+  const char *key_str;
+  size_t key_len;
+  upb_alloc *a = map->alloc;
+
+  upb_map_tokey(map->key_type, &key, &key_str, &key_len);
+  return upb_strtable_remove3(&map->strtab, key_str, key_len, NULL, a);
+}
+
+
+/** upb_mapiter ***************************************************************/
+
+struct upb_mapiter {
+  upb_strtable_iter iter;
+  upb_fieldtype_t key_type;
+};
+
+size_t upb_mapiter_sizeof() {
+  return sizeof(upb_mapiter);
+}
+
+void upb_mapiter_begin(upb_mapiter *i, const upb_map *map) {
+  upb_strtable_begin(&i->iter, &map->strtab);
+  i->key_type = map->key_type;
+}
+
+upb_mapiter *upb_mapiter_new(const upb_map *t, upb_alloc *a) {
+  upb_mapiter *ret = upb_malloc(a, upb_mapiter_sizeof());
+
+  if (!ret) {
+    return NULL;
+  }
+
+  upb_mapiter_begin(ret, t);
+  return ret;
+}
+
+void upb_mapiter_free(upb_mapiter *i, upb_alloc *a) {
+  upb_free(a, i);
+}
+
+void upb_mapiter_next(upb_mapiter *i) {
+  upb_strtable_next(&i->iter);
+}
+
+bool upb_mapiter_done(const upb_mapiter *i) {
+  return upb_strtable_done(&i->iter);
+}
+
+upb_msgval upb_mapiter_key(const upb_mapiter *i) {
+  return upb_map_fromkey(i->key_type, upb_strtable_iter_key(&i->iter),
+                         upb_strtable_iter_keylength(&i->iter));
+}
+
+upb_msgval upb_mapiter_value(const upb_mapiter *i) {
+  return upb_msgval_fromval(upb_strtable_iter_value(&i->iter));
+}
+
+void upb_mapiter_setdone(upb_mapiter *i) {
+  upb_strtable_iter_setdone(&i->iter);
+}
+
+bool upb_mapiter_isequal(const upb_mapiter *i1, const upb_mapiter *i2) {
+  return upb_strtable_iter_isequal(&i1->iter, &i2->iter);
+}
+
+
+/** Handlers for upb_msg ******************************************************/
+
+typedef struct {
+  size_t offset;
+  int32_t hasbit;
+} upb_msg_handlerdata;
+
+/* Fallback implementation if the handler is not specialized by the producer. */
+#define MSG_WRITER(type, ctype)                                               \
+  bool upb_msg_set ## type (void *c, const void *hd, ctype val) {             \
+    uint8_t *m = c;                                                           \
+    const upb_msg_handlerdata *d = hd;                                        \
+    if (d->hasbit > 0)                                                        \
+      *(uint8_t*)&m[d->hasbit / 8] |= 1 << (d->hasbit % 8);                   \
+    *(ctype*)&m[d->offset] = val;                                             \
+    return true;                                                              \
+  }                                                                           \
+
+MSG_WRITER(double, double)
+MSG_WRITER(float,  float)
+MSG_WRITER(int32,  int32_t)
+MSG_WRITER(int64,  int64_t)
+MSG_WRITER(uint32, uint32_t)
+MSG_WRITER(uint64, uint64_t)
+MSG_WRITER(bool,   bool)
+
+bool upb_msg_setscalarhandler(upb_handlers *h, const upb_fielddef *f,
+                              size_t offset, int32_t hasbit) {
+  upb_handlerattr attr = UPB_HANDLERATTR_INITIALIZER;
+  bool ok;
+
+  upb_msg_handlerdata *d = upb_gmalloc(sizeof(*d));
+  if (!d) return false;
+  d->offset = offset;
+  d->hasbit = hasbit;
+
+  upb_handlerattr_sethandlerdata(&attr, d);
+  upb_handlerattr_setalwaysok(&attr, true);
+  upb_handlers_addcleanup(h, d, upb_gfree);
+
+#define TYPE(u, l) \
+  case UPB_TYPE_##u: \
+    ok = upb_handlers_set##l(h, f, upb_msg_set##l, &attr); break;
+
+  ok = false;
+
+  switch (upb_fielddef_type(f)) {
+    TYPE(INT64,  int64);
+    TYPE(INT32,  int32);
+    TYPE(ENUM,   int32);
+    TYPE(UINT64, uint64);
+    TYPE(UINT32, uint32);
+    TYPE(DOUBLE, double);
+    TYPE(FLOAT,  float);
+    TYPE(BOOL,   bool);
+    default: UPB_ASSERT(false); break;
+  }
+#undef TYPE
+
+  upb_handlerattr_uninit(&attr);
+  return ok;
+}
+
+bool upb_msg_getscalarhandlerdata(const upb_handlers *h,
+                                  upb_selector_t s,
+                                  upb_fieldtype_t *type,
+                                  size_t *offset,
+                                  int32_t *hasbit) {
+  const upb_msg_handlerdata *d;
+  upb_func *f = upb_handlers_gethandler(h, s);
+
+  if ((upb_int64_handlerfunc*)f == upb_msg_setint64) {
+    *type = UPB_TYPE_INT64;
+  } else if ((upb_int32_handlerfunc*)f == upb_msg_setint32) {
+    *type = UPB_TYPE_INT32;
+  } else if ((upb_uint64_handlerfunc*)f == upb_msg_setuint64) {
+    *type = UPB_TYPE_UINT64;
+  } else if ((upb_uint32_handlerfunc*)f == upb_msg_setuint32) {
+    *type = UPB_TYPE_UINT32;
+  } else if ((upb_double_handlerfunc*)f == upb_msg_setdouble) {
+    *type = UPB_TYPE_DOUBLE;
+  } else if ((upb_float_handlerfunc*)f == upb_msg_setfloat) {
+    *type = UPB_TYPE_FLOAT;
+  } else if ((upb_bool_handlerfunc*)f == upb_msg_setbool) {
+    *type = UPB_TYPE_BOOL;
+  } else {
+    return false;
+  }
+
+  d = upb_handlers_gethandlerdata(h, s);
+  *offset = d->offset;
+  *hasbit = d->hasbit;
+  return true;
+}
+/*
+** upb::RefCounted Implementation
+**
+** Our key invariants are:
+** 1. reference cycles never span groups
+** 2. for ref2(to, from), we increment to's count iff group(from) != group(to)
+**
+** The previous two are how we avoid leaking cycles.  Other important
+** invariants are:
+** 3. for mutable objects "from" and "to", if there exists a ref2(to, from)
+**    this implies group(from) == group(to).  (In practice, what we implement
+**    is even stronger; "from" and "to" will share a group if there has *ever*
+**    been a ref2(to, from), but all that is necessary for correctness is the
+**    weaker one).
+** 4. mutable and immutable objects are never in the same group.
+*/
+
+
+#include <setjmp.h>
+
+static void freeobj(upb_refcounted *o);
+
+const char untracked_val;
+const void *UPB_UNTRACKED_REF = &untracked_val;
+
+/* arch-specific atomic primitives  *******************************************/
+
+#ifdef UPB_THREAD_UNSAFE /*---------------------------------------------------*/
+
+static void atomic_inc(uint32_t *a) { (*a)++; }
+static bool atomic_dec(uint32_t *a) { return --(*a) == 0; }
+
+#elif defined(__GNUC__) || defined(__clang__) /*------------------------------*/
+
+static void atomic_inc(uint32_t *a) { __sync_fetch_and_add(a, 1); }
+static bool atomic_dec(uint32_t *a) { return __sync_sub_and_fetch(a, 1) == 0; }
+
+#elif defined(WIN32) /*-------------------------------------------------------*/
+
+#include <Windows.h>
+
+static void atomic_inc(upb_atomic_t *a) { InterlockedIncrement(&a->val); }
+static bool atomic_dec(upb_atomic_t *a) {
+  return InterlockedDecrement(&a->val) == 0;
+}
+
+#else
+#error Atomic primitives not defined for your platform/CPU.  \
+       Implement them or compile with UPB_THREAD_UNSAFE.
+#endif
+
+/* All static objects point to this refcount.
+ * It is special-cased in ref/unref below.  */
+uint32_t static_refcount = -1;
+
+/* We can avoid atomic ops for statically-declared objects.
+ * This is a minor optimization but nice since we can avoid degrading under
+ * contention in this case. */
+
+static void refgroup(uint32_t *group) {
+  if (group != &static_refcount)
+    atomic_inc(group);
+}
+
+static bool unrefgroup(uint32_t *group) {
+  if (group == &static_refcount) {
+    return false;
+  } else {
+    return atomic_dec(group);
+  }
+}
+
+
+/* Reference tracking (debug only) ********************************************/
+
+#ifdef UPB_DEBUG_REFS
+
+#ifdef UPB_THREAD_UNSAFE
+
+static void upb_lock() {}
+static void upb_unlock() {}
+
+#else
+
+/* User must define functions that lock/unlock a global mutex and link this
+ * file against them. */
+void upb_lock();
+void upb_unlock();
+
+#endif
+
+/* UPB_DEBUG_REFS mode counts on being able to malloc() memory in some
+ * code-paths that can normally never fail, like upb_refcounted_ref().  Since
+ * we have no way to propagage out-of-memory errors back to the user, and since
+ * these errors can only occur in UPB_DEBUG_REFS mode, we use an allocator that
+ * immediately aborts on failure (avoiding the global allocator, which might
+ * inject failures). */
+
+#include <stdlib.h>
+
+static void *upb_debugrefs_allocfunc(upb_alloc *alloc, void *ptr,
+                                     size_t oldsize, size_t size) {
+  UPB_UNUSED(alloc);
+  UPB_UNUSED(oldsize);
+  if (size == 0) {
+    free(ptr);
+    return NULL;
+  } else {
+    void *ret = realloc(ptr, size);
+
+    if (!ret) {
+      abort();
+    }
+
+    return ret;
+  }
+}
+
+upb_alloc upb_alloc_debugrefs = {&upb_debugrefs_allocfunc};
+
+typedef struct {
+  int count;  /* How many refs there are (duplicates only allowed for ref2). */
+  bool is_ref2;
+} trackedref;
+
+static trackedref *trackedref_new(bool is_ref2) {
+  trackedref *ret = upb_malloc(&upb_alloc_debugrefs, sizeof(*ret));
+  ret->count = 1;
+  ret->is_ref2 = is_ref2;
+  return ret;
+}
+
+static void track(const upb_refcounted *r, const void *owner, bool ref2) {
+  upb_value v;
+
+  UPB_ASSERT(owner);
+  if (owner == UPB_UNTRACKED_REF) return;
+
+  upb_lock();
+  if (upb_inttable_lookupptr(r->refs, owner, &v)) {
+    trackedref *ref = upb_value_getptr(v);
+    /* Since we allow multiple ref2's for the same to/from pair without
+     * allocating separate memory for each one, we lose the fine-grained
+     * tracking behavior we get with regular refs.  Since ref2s only happen
+     * inside upb, we'll accept this limitation until/unless there is a really
+     * difficult upb-internal bug that can't be figured out without it. */
+    UPB_ASSERT(ref2);
+    UPB_ASSERT(ref->is_ref2);
+    ref->count++;
+  } else {
+    trackedref *ref = trackedref_new(ref2);
+    upb_inttable_insertptr2(r->refs, owner, upb_value_ptr(ref),
+                            &upb_alloc_debugrefs);
+    if (ref2) {
+      /* We know this cast is safe when it is a ref2, because it's coming from
+       * another refcounted object. */
+      const upb_refcounted *from = owner;
+      UPB_ASSERT(!upb_inttable_lookupptr(from->ref2s, r, NULL));
+      upb_inttable_insertptr2(from->ref2s, r, upb_value_ptr(NULL),
+                              &upb_alloc_debugrefs);
+    }
+  }
+  upb_unlock();
+}
+
+static void untrack(const upb_refcounted *r, const void *owner, bool ref2) {
+  upb_value v;
+  bool found;
+  trackedref *ref;
+
+  UPB_ASSERT(owner);
+  if (owner == UPB_UNTRACKED_REF) return;
+
+  upb_lock();
+  found = upb_inttable_lookupptr(r->refs, owner, &v);
+  /* This assert will fail if an owner attempts to release a ref it didn't have. */
+  UPB_ASSERT(found);
+  ref = upb_value_getptr(v);
+  UPB_ASSERT(ref->is_ref2 == ref2);
+  if (--ref->count == 0) {
+    free(ref);
+    upb_inttable_removeptr(r->refs, owner, NULL);
+    if (ref2) {
+      /* We know this cast is safe when it is a ref2, because it's coming from
+       * another refcounted object. */
+      const upb_refcounted *from = owner;
+      bool removed = upb_inttable_removeptr(from->ref2s, r, NULL);
+      UPB_ASSERT(removed);
+    }
+  }
+  upb_unlock();
+}
+
+static void checkref(const upb_refcounted *r, const void *owner, bool ref2) {
+  upb_value v;
+  bool found;
+  trackedref *ref;
+
+  upb_lock();
+  found = upb_inttable_lookupptr(r->refs, owner, &v);
+  UPB_ASSERT(found);
+  ref = upb_value_getptr(v);
+  UPB_ASSERT(ref->is_ref2 == ref2);
+  upb_unlock();
+}
+
+/* Populates the given UPB_CTYPE_INT32 inttable with counts of ref2's that
+ * originate from the given owner. */
+static void getref2s(const upb_refcounted *owner, upb_inttable *tab) {
+  upb_inttable_iter i;
+
+  upb_lock();
+  upb_inttable_begin(&i, owner->ref2s);
+  for(; !upb_inttable_done(&i); upb_inttable_next(&i)) {
+    upb_value v;
+    upb_value count;
+    trackedref *ref;
+    bool found;
+
+    upb_refcounted *to = (upb_refcounted*)upb_inttable_iter_key(&i);
+
+    /* To get the count we need to look in the target's table. */
+    found = upb_inttable_lookupptr(to->refs, owner, &v);
+    UPB_ASSERT(found);
+    ref = upb_value_getptr(v);
+    count = upb_value_int32(ref->count);
+
+    upb_inttable_insertptr2(tab, to, count, &upb_alloc_debugrefs);
+  }
+  upb_unlock();
+}
+
+typedef struct {
+  upb_inttable ref2;
+  const upb_refcounted *obj;
+} check_state;
+
+static void visit_check(const upb_refcounted *obj, const upb_refcounted *subobj,
+                        void *closure) {
+  check_state *s = closure;
+  upb_inttable *ref2 = &s->ref2;
+  upb_value v;
+  bool removed;
+  int32_t newcount;
+
+  UPB_ASSERT(obj == s->obj);
+  UPB_ASSERT(subobj);
+  removed = upb_inttable_removeptr(ref2, subobj, &v);
+  /* The following assertion will fail if the visit() function visits a subobj
+   * that it did not have a ref2 on, or visits the same subobj too many times. */
+  UPB_ASSERT(removed);
+  newcount = upb_value_getint32(v) - 1;
+  if (newcount > 0) {
+    upb_inttable_insert2(ref2, (uintptr_t)subobj, upb_value_int32(newcount),
+                         &upb_alloc_debugrefs);
+  }
+}
+
+static void visit(const upb_refcounted *r, upb_refcounted_visit *v,
+                  void *closure) {
+  /* In DEBUG_REFS mode we know what existing ref2 refs there are, so we know
+   * exactly the set of nodes that visit() should visit.  So we verify visit()'s
+   * correctness here. */
+  check_state state;
+  state.obj = r;
+  upb_inttable_init2(&state.ref2, UPB_CTYPE_INT32, &upb_alloc_debugrefs);
+  getref2s(r, &state.ref2);
+
+  /* This should visit any children in the ref2 table. */
+  if (r->vtbl->visit) r->vtbl->visit(r, visit_check, &state);
+
+  /* This assertion will fail if the visit() function missed any children. */
+  UPB_ASSERT(upb_inttable_count(&state.ref2) == 0);
+  upb_inttable_uninit2(&state.ref2, &upb_alloc_debugrefs);
+  if (r->vtbl->visit) r->vtbl->visit(r, v, closure);
+}
+
+static void trackinit(upb_refcounted *r) {
+  r->refs = upb_malloc(&upb_alloc_debugrefs, sizeof(*r->refs));
+  r->ref2s = upb_malloc(&upb_alloc_debugrefs, sizeof(*r->ref2s));
+  upb_inttable_init2(r->refs, UPB_CTYPE_PTR, &upb_alloc_debugrefs);
+  upb_inttable_init2(r->ref2s, UPB_CTYPE_PTR, &upb_alloc_debugrefs);
+}
+
+static void trackfree(const upb_refcounted *r) {
+  upb_inttable_uninit2(r->refs, &upb_alloc_debugrefs);
+  upb_inttable_uninit2(r->ref2s, &upb_alloc_debugrefs);
+  upb_free(&upb_alloc_debugrefs, r->refs);
+  upb_free(&upb_alloc_debugrefs, r->ref2s);
+}
+
+#else
+
+static void track(const upb_refcounted *r, const void *owner, bool ref2) {
+  UPB_UNUSED(r);
+  UPB_UNUSED(owner);
+  UPB_UNUSED(ref2);
+}
+
+static void untrack(const upb_refcounted *r, const void *owner, bool ref2) {
+  UPB_UNUSED(r);
+  UPB_UNUSED(owner);
+  UPB_UNUSED(ref2);
+}
+
+static void checkref(const upb_refcounted *r, const void *owner, bool ref2) {
+  UPB_UNUSED(r);
+  UPB_UNUSED(owner);
+  UPB_UNUSED(ref2);
+}
+
+static void trackinit(upb_refcounted *r) {
+  UPB_UNUSED(r);
+}
+
+static void trackfree(const upb_refcounted *r) {
+  UPB_UNUSED(r);
+}
+
+static void visit(const upb_refcounted *r, upb_refcounted_visit *v,
+                  void *closure) {
+  if (r->vtbl->visit) r->vtbl->visit(r, v, closure);
+}
+
+#endif  /* UPB_DEBUG_REFS */
+
+
+/* freeze() *******************************************************************/
+
+/* The freeze() operation is by far the most complicated part of this scheme.
+ * We compute strongly-connected components and then mutate the graph such that
+ * we preserve the invariants documented at the top of this file.  And we must
+ * handle out-of-memory errors gracefully (without leaving the graph
+ * inconsistent), which adds to the fun. */
+
+/* The state used by the freeze operation (shared across many functions). */
+typedef struct {
+  int depth;
+  int maxdepth;
+  uint64_t index;
+  /* Maps upb_refcounted* -> attributes (color, etc).  attr layout varies by
+   * color. */
+  upb_inttable objattr;
+  upb_inttable stack;   /* stack of upb_refcounted* for Tarjan's algorithm. */
+  upb_inttable groups;  /* array of uint32_t*, malloc'd refcounts for new groups */
+  upb_status *status;
+  jmp_buf err;
+} tarjan;
+
+static void release_ref2(const upb_refcounted *obj,
+                         const upb_refcounted *subobj,
+                         void *closure);
+
+/* Node attributes -----------------------------------------------------------*/
+
+/* After our analysis phase all nodes will be either GRAY or WHITE. */
+
+typedef enum {
+  BLACK = 0,  /* Object has not been seen. */
+  GRAY,   /* Object has been found via a refgroup but may not be reachable. */
+  GREEN,  /* Object is reachable and is currently on the Tarjan stack. */
+  WHITE   /* Object is reachable and has been assigned a group (SCC). */
+} color_t;
+
+UPB_NORETURN static void err(tarjan *t) { longjmp(t->err, 1); }
+UPB_NORETURN static void oom(tarjan *t) {
+  upb_status_seterrmsg(t->status, "out of memory");
+  err(t);
+}
+
+static uint64_t trygetattr(const tarjan *t, const upb_refcounted *r) {
+  upb_value v;
+  return upb_inttable_lookupptr(&t->objattr, r, &v) ?
+      upb_value_getuint64(v) : 0;
+}
+
+static uint64_t getattr(const tarjan *t, const upb_refcounted *r) {
+  upb_value v;
+  bool found = upb_inttable_lookupptr(&t->objattr, r, &v);
+  UPB_ASSERT(found);
+  return upb_value_getuint64(v);
+}
+
+static void setattr(tarjan *t, const upb_refcounted *r, uint64_t attr) {
+  upb_inttable_removeptr(&t->objattr, r, NULL);
+  upb_inttable_insertptr(&t->objattr, r, upb_value_uint64(attr));
+}
+
+static color_t color(tarjan *t, const upb_refcounted *r) {
+  return trygetattr(t, r) & 0x3;  /* Color is always stored in the low 2 bits. */
+}
+
+static void set_gray(tarjan *t, const upb_refcounted *r) {
+  UPB_ASSERT(color(t, r) == BLACK);
+  setattr(t, r, GRAY);
+}
+
+/* Pushes an obj onto the Tarjan stack and sets it to GREEN. */
+static void push(tarjan *t, const upb_refcounted *r) {
+  UPB_ASSERT(color(t, r) == BLACK || color(t, r) == GRAY);
+  /* This defines the attr layout for the GREEN state.  "index" and "lowlink"
+   * get 31 bits, which is plenty (limit of 2B objects frozen at a time). */
+  setattr(t, r, GREEN | (t->index << 2) | (t->index << 33));
+  if (++t->index == 0x80000000) {
+    upb_status_seterrmsg(t->status, "too many objects to freeze");
+    err(t);
+  }
+  upb_inttable_push(&t->stack, upb_value_ptr((void*)r));
+}
+
+/* Pops an obj from the Tarjan stack and sets it to WHITE, with a ptr to its
+ * SCC group. */
+static upb_refcounted *pop(tarjan *t) {
+  upb_refcounted *r = upb_value_getptr(upb_inttable_pop(&t->stack));
+  UPB_ASSERT(color(t, r) == GREEN);
+  /* This defines the attr layout for nodes in the WHITE state.
+   * Top of group stack is [group, NULL]; we point at group. */
+  setattr(t, r, WHITE | (upb_inttable_count(&t->groups) - 2) << 8);
+  return r;
+}
+
+static void tarjan_newgroup(tarjan *t) {
+  uint32_t *group = upb_gmalloc(sizeof(*group));
+  if (!group) oom(t);
+  /* Push group and empty group leader (we'll fill in leader later). */
+  if (!upb_inttable_push(&t->groups, upb_value_ptr(group)) ||
+      !upb_inttable_push(&t->groups, upb_value_ptr(NULL))) {
+    upb_gfree(group);
+    oom(t);
+  }
+  *group = 0;
+}
+
+static uint32_t idx(tarjan *t, const upb_refcounted *r) {
+  UPB_ASSERT(color(t, r) == GREEN);
+  return (getattr(t, r) >> 2) & 0x7FFFFFFF;
+}
+
+static uint32_t lowlink(tarjan *t, const upb_refcounted *r) {
+  if (color(t, r) == GREEN) {
+    return getattr(t, r) >> 33;
+  } else {
+    return UINT32_MAX;
+  }
+}
+
+static void set_lowlink(tarjan *t, const upb_refcounted *r, uint32_t lowlink) {
+  UPB_ASSERT(color(t, r) == GREEN);
+  setattr(t, r, ((uint64_t)lowlink << 33) | (getattr(t, r) & 0x1FFFFFFFF));
+}
+
+static uint32_t *group(tarjan *t, upb_refcounted *r) {
+  uint64_t groupnum;
+  upb_value v;
+  bool found;
+
+  UPB_ASSERT(color(t, r) == WHITE);
+  groupnum = getattr(t, r) >> 8;
+  found = upb_inttable_lookup(&t->groups, groupnum, &v);
+  UPB_ASSERT(found);
+  return upb_value_getptr(v);
+}
+
+/* If the group leader for this object's group has not previously been set,
+ * the given object is assigned to be its leader. */
+static upb_refcounted *groupleader(tarjan *t, upb_refcounted *r) {
+  uint64_t leader_slot;
+  upb_value v;
+  bool found;
+
+  UPB_ASSERT(color(t, r) == WHITE);
+  leader_slot = (getattr(t, r) >> 8) + 1;
+  found = upb_inttable_lookup(&t->groups, leader_slot, &v);
+  UPB_ASSERT(found);
+  if (upb_value_getptr(v)) {
+    return upb_value_getptr(v);
+  } else {
+    upb_inttable_remove(&t->groups, leader_slot, NULL);
+    upb_inttable_insert(&t->groups, leader_slot, upb_value_ptr(r));
+    return r;
+  }
+}
+
+
+/* Tarjan's algorithm --------------------------------------------------------*/
+
+/* See:
+ *   http://en.wikipedia.org/wiki/Tarjan%27s_strongly_connected_components_algorithm */
+static void do_tarjan(const upb_refcounted *obj, tarjan *t);
+
+static void tarjan_visit(const upb_refcounted *obj,
+                         const upb_refcounted *subobj,
+                         void *closure) {
+  tarjan *t = closure;
+  if (++t->depth > t->maxdepth) {
+    upb_status_seterrf(t->status, "graph too deep to freeze (%d)", t->maxdepth);
+    err(t);
+  } else if (subobj->is_frozen || color(t, subobj) == WHITE) {
+    /* Do nothing: we don't want to visit or color already-frozen nodes,
+     * and WHITE nodes have already been assigned a SCC. */
+  } else if (color(t, subobj) < GREEN) {
+    /* Subdef has not yet been visited; recurse on it. */
+    do_tarjan(subobj, t);
+    set_lowlink(t, obj, UPB_MIN(lowlink(t, obj), lowlink(t, subobj)));
+  } else if (color(t, subobj) == GREEN) {
+    /* Subdef is in the stack and hence in the current SCC. */
+    set_lowlink(t, obj, UPB_MIN(lowlink(t, obj), idx(t, subobj)));
+  }
+  --t->depth;
+}
+
+static void do_tarjan(const upb_refcounted *obj, tarjan *t) {
+  if (color(t, obj) == BLACK) {
+    /* We haven't seen this object's group; mark the whole group GRAY. */
+    const upb_refcounted *o = obj;
+    do { set_gray(t, o); } while ((o = o->next) != obj);
+  }
+
+  push(t, obj);
+  visit(obj, tarjan_visit, t);
+  if (lowlink(t, obj) == idx(t, obj)) {
+    tarjan_newgroup(t);
+    while (pop(t) != obj)
+      ;
+  }
+}
+
+
+/* freeze() ------------------------------------------------------------------*/
+
+static void crossref(const upb_refcounted *r, const upb_refcounted *subobj,
+                     void *_t) {
+  tarjan *t = _t;
+  UPB_ASSERT(color(t, r) > BLACK);
+  if (color(t, subobj) > BLACK && r->group != subobj->group) {
+    /* Previously this ref was not reflected in subobj->group because they
+     * were in the same group; now that they are split a ref must be taken. */
+    refgroup(subobj->group);
+  }
+}
+
+static bool freeze(upb_refcounted *const*roots, int n, upb_status *s,
+                   int maxdepth) {
+  volatile bool ret = false;
+  int i;
+  upb_inttable_iter iter;
+
+  /* We run in two passes so that we can allocate all memory before performing
+   * any mutation of the input -- this allows us to leave the input unchanged
+   * in the case of memory allocation failure. */
+  tarjan t;
+  t.index = 0;
+  t.depth = 0;
+  t.maxdepth = maxdepth;
+  t.status = s;
+  if (!upb_inttable_init(&t.objattr, UPB_CTYPE_UINT64)) goto err1;
+  if (!upb_inttable_init(&t.stack, UPB_CTYPE_PTR)) goto err2;
+  if (!upb_inttable_init(&t.groups, UPB_CTYPE_PTR)) goto err3;
+  if (setjmp(t.err) != 0) goto err4;
+
+
+  for (i = 0; i < n; i++) {
+    if (color(&t, roots[i]) < GREEN) {
+      do_tarjan(roots[i], &t);
+    }
+  }
+
+  /* If we've made it this far, no further errors are possible so it's safe to
+   * mutate the objects without risk of leaving them in an inconsistent state. */
+  ret = true;
+
+  /* The transformation that follows requires care.  The preconditions are:
+   * - all objects in attr map are WHITE or GRAY, and are in mutable groups
+   *   (groups of all mutable objs)
+   * - no ref2(to, from) refs have incremented count(to) if both "to" and
+   *   "from" are in our attr map (this follows from invariants (2) and (3)) */
+
+  /* Pass 1: we remove WHITE objects from their mutable groups, and add them to
+   * new groups  according to the SCC's we computed.  These new groups will
+   * consist of only frozen objects.  None will be immediately collectible,
+   * because WHITE objects are by definition reachable from one of "roots",
+   * which the caller must own refs on. */
+  upb_inttable_begin(&iter, &t.objattr);
+  for(; !upb_inttable_done(&iter); upb_inttable_next(&iter)) {
+    upb_refcounted *obj = (upb_refcounted*)upb_inttable_iter_key(&iter);
+    /* Since removal from a singly-linked list requires access to the object's
+     * predecessor, we consider obj->next instead of obj for moving.  With the
+     * while() loop we guarantee that we will visit every node's predecessor.
+     * Proof:
+     *  1. every node's predecessor is in our attr map.
+     *  2. though the loop body may change a node's predecessor, it will only
+     *     change it to be the node we are currently operating on, so with a
+     *     while() loop we guarantee ourselves the chance to remove each node. */
+    while (color(&t, obj->next) == WHITE &&
+           group(&t, obj->next) != obj->next->group) {
+      upb_refcounted *leader;
+
+      /* Remove from old group. */
+      upb_refcounted *move = obj->next;
+      if (obj == move) {
+        /* Removing the last object from a group. */
+        UPB_ASSERT(*obj->group == obj->individual_count);
+        upb_gfree(obj->group);
+      } else {
+        obj->next = move->next;
+        /* This may decrease to zero; we'll collect GRAY objects (if any) that
+         * remain in the group in the third pass. */
+        UPB_ASSERT(*move->group >= move->individual_count);
+        *move->group -= move->individual_count;
+      }
+
+      /* Add to new group. */
+      leader = groupleader(&t, move);
+      if (move == leader) {
+        /* First object added to new group is its leader. */
+        move->group = group(&t, move);
+        move->next = move;
+        *move->group = move->individual_count;
+      } else {
+        /* Group already has at least one object in it. */
+        UPB_ASSERT(leader->group == group(&t, move));
+        move->group = group(&t, move);
+        move->next = leader->next;
+        leader->next = move;
+        *move->group += move->individual_count;
+      }
+
+      move->is_frozen = true;
+    }
+  }
+
+  /* Pass 2: GRAY and WHITE objects "obj" with ref2(to, obj) references must
+   * increment count(to) if group(obj) != group(to) (which could now be the
+   * case if "to" was just frozen). */
+  upb_inttable_begin(&iter, &t.objattr);
+  for(; !upb_inttable_done(&iter); upb_inttable_next(&iter)) {
+    upb_refcounted *obj = (upb_refcounted*)upb_inttable_iter_key(&iter);
+    visit(obj, crossref, &t);
+  }
+
+  /* Pass 3: GRAY objects are collected if their group's refcount dropped to
+   * zero when we removed its white nodes.  This can happen if they had only
+   * been kept alive by virtue of sharing a group with an object that was just
+   * frozen.
+   *
+   * It is important that we do this last, since the GRAY object's free()
+   * function could call unref2() on just-frozen objects, which will decrement
+   * refs that were added in pass 2. */
+  upb_inttable_begin(&iter, &t.objattr);
+  for(; !upb_inttable_done(&iter); upb_inttable_next(&iter)) {
+    upb_refcounted *obj = (upb_refcounted*)upb_inttable_iter_key(&iter);
+    if (obj->group == NULL || *obj->group == 0) {
+      if (obj->group) {
+        upb_refcounted *o;
+
+        /* We eagerly free() the group's count (since we can't easily determine
+         * the group's remaining size it's the easiest way to ensure it gets
+         * done). */
+        upb_gfree(obj->group);
+
+        /* Visit to release ref2's (done in a separate pass since release_ref2
+         * depends on o->group being unmodified so it can test merged()). */
+        o = obj;
+        do { visit(o, release_ref2, NULL); } while ((o = o->next) != obj);
+
+        /* Mark "group" fields as NULL so we know to free the objects later in
+         * this loop, but also don't try to delete the group twice. */
+        o = obj;
+        do { o->group = NULL; } while ((o = o->next) != obj);
+      }
+      freeobj(obj);
+    }
+  }
+
+err4:
+  if (!ret) {
+    upb_inttable_begin(&iter, &t.groups);
+    for(; !upb_inttable_done(&iter); upb_inttable_next(&iter))
+      upb_gfree(upb_value_getptr(upb_inttable_iter_value(&iter)));
+  }
+  upb_inttable_uninit(&t.groups);
+err3:
+  upb_inttable_uninit(&t.stack);
+err2:
+  upb_inttable_uninit(&t.objattr);
+err1:
+  return ret;
+}
+
+
+/* Misc internal functions  ***************************************************/
+
+static bool merged(const upb_refcounted *r, const upb_refcounted *r2) {
+  return r->group == r2->group;
+}
+
+static void merge(upb_refcounted *r, upb_refcounted *from) {
+  upb_refcounted *base;
+  upb_refcounted *tmp;
+
+  if (merged(r, from)) return;
+  *r->group += *from->group;
+  upb_gfree(from->group);
+  base = from;
+
+  /* Set all refcount pointers in the "from" chain to the merged refcount.
+   *
+   * TODO(haberman): this linear algorithm can result in an overall O(n^2) bound
+   * if the user continuously extends a group by one object.  Prevent this by
+   * using one of the techniques in this paper:
+   *     http://bioinfo.ict.ac.cn/~dbu/AlgorithmCourses/Lectures/Union-Find-Tarjan.pdf */
+  do { from->group = r->group; } while ((from = from->next) != base);
+
+  /* Merge the two circularly linked lists by swapping their next pointers. */
+  tmp = r->next;
+  r->next = base->next;
+  base->next = tmp;
+}
+
+static void unref(const upb_refcounted *r);
+
+static void release_ref2(const upb_refcounted *obj,
+                         const upb_refcounted *subobj,
+                         void *closure) {
+  UPB_UNUSED(closure);
+  untrack(subobj, obj, true);
+  if (!merged(obj, subobj)) {
+    UPB_ASSERT(subobj->is_frozen);
+    unref(subobj);
+  }
+}
+
+static void unref(const upb_refcounted *r) {
+  if (unrefgroup(r->group)) {
+    const upb_refcounted *o;
+
+    upb_gfree(r->group);
+
+    /* In two passes, since release_ref2 needs a guarantee that any subobjs
+     * are alive. */
+    o = r;
+    do { visit(o, release_ref2, NULL); } while((o = o->next) != r);
+
+    o = r;
+    do {
+      const upb_refcounted *next = o->next;
+      UPB_ASSERT(o->is_frozen || o->individual_count == 0);
+      freeobj((upb_refcounted*)o);
+      o = next;
+    } while(o != r);
+  }
+}
+
+static void freeobj(upb_refcounted *o) {
+  trackfree(o);
+  o->vtbl->free((upb_refcounted*)o);
+}
+
+
+/* Public interface ***********************************************************/
+
+bool upb_refcounted_init(upb_refcounted *r,
+                         const struct upb_refcounted_vtbl *vtbl,
+                         const void *owner) {
+#ifndef NDEBUG
+  /* Endianness check.  This is unrelated to upb_refcounted, it's just a
+   * convenient place to put the check that we can be assured will run for
+   * basically every program using upb. */
+  const int x = 1;
+#ifdef UPB_BIG_ENDIAN
+  UPB_ASSERT(*(char*)&x != 1);
+#else
+  UPB_ASSERT(*(char*)&x == 1);
+#endif
+#endif
+
+  r->next = r;
+  r->vtbl = vtbl;
+  r->individual_count = 0;
+  r->is_frozen = false;
+  r->group = upb_gmalloc(sizeof(*r->group));
+  if (!r->group) return false;
+  *r->group = 0;
+  trackinit(r);
+  upb_refcounted_ref(r, owner);
+  return true;
+}
+
+bool upb_refcounted_isfrozen(const upb_refcounted *r) {
+  return r->is_frozen;
+}
+
+void upb_refcounted_ref(const upb_refcounted *r, const void *owner) {
+  track(r, owner, false);
+  if (!r->is_frozen)
+    ((upb_refcounted*)r)->individual_count++;
+  refgroup(r->group);
+}
+
+void upb_refcounted_unref(const upb_refcounted *r, const void *owner) {
+  untrack(r, owner, false);
+  if (!r->is_frozen)
+    ((upb_refcounted*)r)->individual_count--;
+  unref(r);
+}
+
+void upb_refcounted_ref2(const upb_refcounted *r, upb_refcounted *from) {
+  UPB_ASSERT(!from->is_frozen);  /* Non-const pointer implies this. */
+  track(r, from, true);
+  if (r->is_frozen) {
+    refgroup(r->group);
+  } else {
+    merge((upb_refcounted*)r, from);
+  }
+}
+
+void upb_refcounted_unref2(const upb_refcounted *r, upb_refcounted *from) {
+  UPB_ASSERT(!from->is_frozen);  /* Non-const pointer implies this. */
+  untrack(r, from, true);
+  if (r->is_frozen) {
+    unref(r);
+  } else {
+    UPB_ASSERT(merged(r, from));
+  }
+}
+
+void upb_refcounted_donateref(
+    const upb_refcounted *r, const void *from, const void *to) {
+  UPB_ASSERT(from != to);
+  if (to != NULL)
+    upb_refcounted_ref(r, to);
+  if (from != NULL)
+    upb_refcounted_unref(r, from);
+}
+
+void upb_refcounted_checkref(const upb_refcounted *r, const void *owner) {
+  checkref(r, owner, false);
+}
+
+bool upb_refcounted_freeze(upb_refcounted *const*roots, int n, upb_status *s,
+                           int maxdepth) {
+  int i;
+  bool ret;
+  for (i = 0; i < n; i++) {
+    UPB_ASSERT(!roots[i]->is_frozen);
+  }
+  ret = freeze(roots, n, s, maxdepth);
+  UPB_ASSERT(!s || ret == upb_ok(s));
+  return ret;
+}
+
+
+bool upb_bufsrc_putbuf(const char *buf, size_t len, upb_bytessink *sink) {
+  void *subc;
+  bool ret;
+  upb_bufhandle handle;
+  upb_bufhandle_init(&handle);
+  upb_bufhandle_setbuf(&handle, buf, 0);
+  ret = upb_bytessink_start(sink, len, &subc);
+  if (ret && len != 0) {
+    ret = (upb_bytessink_putbuf(sink, subc, buf, len, &handle) >= len);
+  }
+  if (ret) {
+    ret = upb_bytessink_end(sink);
+  }
+  upb_bufhandle_uninit(&handle);
+  return ret;
+}
+
+struct upb_bufsink {
+  upb_byteshandler handler;
+  upb_bytessink sink;
+  upb_env *env;
+  char *ptr;
+  size_t len, size;
+};
+
+static void *upb_bufsink_start(void *_sink, const void *hd, size_t size_hint) {
+  upb_bufsink *sink = _sink;
+  UPB_UNUSED(hd);
+  UPB_UNUSED(size_hint);
+  sink->len = 0;
+  return sink;
+}
+
+static size_t upb_bufsink_string(void *_sink, const void *hd, const char *ptr,
+                                size_t len, const upb_bufhandle *handle) {
+  upb_bufsink *sink = _sink;
+  size_t new_size = sink->size;
+
+  UPB_ASSERT(new_size > 0);
+  UPB_UNUSED(hd);
+  UPB_UNUSED(handle);
+
+  while (sink->len + len > new_size) {
+    new_size *= 2;
+  }
+
+  if (new_size != sink->size) {
+    sink->ptr = upb_env_realloc(sink->env, sink->ptr, sink->size, new_size);
+    sink->size = new_size;
+  }
+
+  memcpy(sink->ptr + sink->len, ptr, len);
+  sink->len += len;
+
+  return len;
+}
+
+upb_bufsink *upb_bufsink_new(upb_env *env) {
+  upb_bufsink *sink = upb_env_malloc(env, sizeof(upb_bufsink));
+  upb_byteshandler_init(&sink->handler);
+  upb_byteshandler_setstartstr(&sink->handler, upb_bufsink_start, NULL);
+  upb_byteshandler_setstring(&sink->handler, upb_bufsink_string, NULL);
+
+  upb_bytessink_reset(&sink->sink, &sink->handler, sink);
+
+  sink->env = env;
+  sink->size = 32;
+  sink->ptr = upb_env_malloc(env, sink->size);
+  sink->len = 0;
+
+  return sink;
+}
+
+void upb_bufsink_free(upb_bufsink *sink) {
+  upb_env_free(sink->env, sink->ptr);
+  upb_env_free(sink->env, sink);
+}
+
+upb_bytessink *upb_bufsink_sink(upb_bufsink *sink) {
+  return &sink->sink;
+}
+
+const char *upb_bufsink_getdata(const upb_bufsink *sink, size_t *len) {
+  *len = sink->len;
+  return sink->ptr;
+}
+/*
+** upb_table Implementation
+**
+** Implementation is heavily inspired by Lua's ltable.c.
+*/
+
+
+#include <string.h>
+
+#define UPB_MAXARRSIZE 16  /* 64k. */
+
+/* From Chromium. */
+#define ARRAY_SIZE(x) \
+    ((sizeof(x)/sizeof(0[x])) / ((size_t)(!(sizeof(x) % sizeof(0[x])))))
+
+static void upb_check_alloc(upb_table *t, upb_alloc *a) {
+  UPB_UNUSED(t);
+  UPB_UNUSED(a);
+  UPB_ASSERT_DEBUGVAR(t->alloc == a);
+}
+
+static const double MAX_LOAD = 0.85;
+
+/* The minimum utilization of the array part of a mixed hash/array table.  This
+ * is a speed/memory-usage tradeoff (though it's not straightforward because of
+ * cache effects).  The lower this is, the more memory we'll use. */
+static const double MIN_DENSITY = 0.1;
+
+bool is_pow2(uint64_t v) { return v == 0 || (v & (v - 1)) == 0; }
+
+int log2ceil(uint64_t v) {
+  int ret = 0;
+  bool pow2 = is_pow2(v);
+  while (v >>= 1) ret++;
+  ret = pow2 ? ret : ret + 1;  /* Ceiling. */
+  return UPB_MIN(UPB_MAXARRSIZE, ret);
+}
+
+char *upb_strdup(const char *s, upb_alloc *a) {
+  return upb_strdup2(s, strlen(s), a);
+}
+
+char *upb_strdup2(const char *s, size_t len, upb_alloc *a) {
+  size_t n;
+  char *p;
+
+  /* Prevent overflow errors. */
+  if (len == SIZE_MAX) return NULL;
+  /* Always null-terminate, even if binary data; but don't rely on the input to
+   * have a null-terminating byte since it may be a raw binary buffer. */
+  n = len + 1;
+  p = upb_malloc(a, n);
+  if (p) {
+    memcpy(p, s, len);
+    p[len] = 0;
+  }
+  return p;
+}
+
+/* A type to represent the lookup key of either a strtable or an inttable. */
+typedef union {
+  uintptr_t num;
+  struct {
+    const char *str;
+    size_t len;
+  } str;
+} lookupkey_t;
+
+static lookupkey_t strkey2(const char *str, size_t len) {
+  lookupkey_t k;
+  k.str.str = str;
+  k.str.len = len;
+  return k;
+}
+
+static lookupkey_t intkey(uintptr_t key) {
+  lookupkey_t k;
+  k.num = key;
+  return k;
+}
+
+typedef uint32_t hashfunc_t(upb_tabkey key);
+typedef bool eqlfunc_t(upb_tabkey k1, lookupkey_t k2);
+
+/* Base table (shared code) ***************************************************/
+
+/* For when we need to cast away const. */
+static upb_tabent *mutable_entries(upb_table *t) {
+  return (upb_tabent*)t->entries;
+}
+
+static bool isfull(upb_table *t) {
+  if (upb_table_size(t) == 0) {
+    return true;
+  } else {
+    return ((double)(t->count + 1) / upb_table_size(t)) > MAX_LOAD;
+  }
+}
+
+static bool init(upb_table *t, upb_ctype_t ctype, uint8_t size_lg2,
+                 upb_alloc *a) {
+  size_t bytes;
+
+  t->count = 0;
+  t->ctype = ctype;
+  t->size_lg2 = size_lg2;
+  t->mask = upb_table_size(t) ? upb_table_size(t) - 1 : 0;
+#ifndef NDEBUG
+  t->alloc = a;
+#endif
+  bytes = upb_table_size(t) * sizeof(upb_tabent);
+  if (bytes > 0) {
+    t->entries = upb_malloc(a, bytes);
+    if (!t->entries) return false;
+    memset(mutable_entries(t), 0, bytes);
+  } else {
+    t->entries = NULL;
+  }
+  return true;
+}
+
+static void uninit(upb_table *t, upb_alloc *a) {
+  upb_check_alloc(t, a);
+  upb_free(a, mutable_entries(t));
+}
+
+static upb_tabent *emptyent(upb_table *t) {
+  upb_tabent *e = mutable_entries(t) + upb_table_size(t);
+  while (1) { if (upb_tabent_isempty(--e)) return e; UPB_ASSERT(e > t->entries); }
+}
+
+static upb_tabent *getentry_mutable(upb_table *t, uint32_t hash) {
+  return (upb_tabent*)upb_getentry(t, hash);
+}
+
+static const upb_tabent *findentry(const upb_table *t, lookupkey_t key,
+                                   uint32_t hash, eqlfunc_t *eql) {
+  const upb_tabent *e;
+
+  if (t->size_lg2 == 0) return NULL;
+  e = upb_getentry(t, hash);
+  if (upb_tabent_isempty(e)) return NULL;
+  while (1) {
+    if (eql(e->key, key)) return e;
+    if ((e = e->next) == NULL) return NULL;
+  }
+}
+
+static upb_tabent *findentry_mutable(upb_table *t, lookupkey_t key,
+                                     uint32_t hash, eqlfunc_t *eql) {
+  return (upb_tabent*)findentry(t, key, hash, eql);
+}
+
+static bool lookup(const upb_table *t, lookupkey_t key, upb_value *v,
+                   uint32_t hash, eqlfunc_t *eql) {
+  const upb_tabent *e = findentry(t, key, hash, eql);
+  if (e) {
+    if (v) {
+      _upb_value_setval(v, e->val.val, t->ctype);
+    }
+    return true;
+  } else {
+    return false;
+  }
+}
+
+/* The given key must not already exist in the table. */
+static void insert(upb_table *t, lookupkey_t key, upb_tabkey tabkey,
+                   upb_value val, uint32_t hash,
+                   hashfunc_t *hashfunc, eqlfunc_t *eql) {
+  upb_tabent *mainpos_e;
+  upb_tabent *our_e;
+
+  UPB_ASSERT(findentry(t, key, hash, eql) == NULL);
+  UPB_ASSERT_DEBUGVAR(val.ctype == t->ctype);
+
+  t->count++;
+  mainpos_e = getentry_mutable(t, hash);
+  our_e = mainpos_e;
+
+  if (upb_tabent_isempty(mainpos_e)) {
+    /* Our main position is empty; use it. */
+    our_e->next = NULL;
+  } else {
+    /* Collision. */
+    upb_tabent *new_e = emptyent(t);
+    /* Head of collider's chain. */
+    upb_tabent *chain = getentry_mutable(t, hashfunc(mainpos_e->key));
+    if (chain == mainpos_e) {
+      /* Existing ent is in its main posisiton (it has the same hash as us, and
+       * is the head of our chain).  Insert to new ent and append to this chain. */
+      new_e->next = mainpos_e->next;
+      mainpos_e->next = new_e;
+      our_e = new_e;
+    } else {
+      /* Existing ent is not in its main position (it is a node in some other
+       * chain).  This implies that no existing ent in the table has our hash.
+       * Evict it (updating its chain) and use its ent for head of our chain. */
+      *new_e = *mainpos_e;  /* copies next. */
+      while (chain->next != mainpos_e) {
+        chain = (upb_tabent*)chain->next;
+        UPB_ASSERT(chain);
+      }
+      chain->next = new_e;
+      our_e = mainpos_e;
+      our_e->next = NULL;
+    }
+  }
+  our_e->key = tabkey;
+  our_e->val.val = val.val;
+  UPB_ASSERT(findentry(t, key, hash, eql) == our_e);
+}
+
+static bool rm(upb_table *t, lookupkey_t key, upb_value *val,
+               upb_tabkey *removed, uint32_t hash, eqlfunc_t *eql) {
+  upb_tabent *chain = getentry_mutable(t, hash);
+  if (upb_tabent_isempty(chain)) return false;
+  if (eql(chain->key, key)) {
+    /* Element to remove is at the head of its chain. */
+    t->count--;
+    if (val) _upb_value_setval(val, chain->val.val, t->ctype);
+    if (removed) *removed = chain->key;
+    if (chain->next) {
+      upb_tabent *move = (upb_tabent*)chain->next;
+      *chain = *move;
+      move->key = 0;  /* Make the slot empty. */
+    } else {
+      chain->key = 0;  /* Make the slot empty. */
+    }
+    return true;
+  } else {
+    /* Element to remove is either in a non-head position or not in the
+     * table. */
+    while (chain->next && !eql(chain->next->key, key)) {
+      chain = (upb_tabent*)chain->next;
+    }
+    if (chain->next) {
+      /* Found element to remove. */
+      upb_tabent *rm = (upb_tabent*)chain->next;
+      t->count--;
+      if (val) _upb_value_setval(val, chain->next->val.val, t->ctype);
+      if (removed) *removed = rm->key;
+      rm->key = 0;  /* Make the slot empty. */
+      chain->next = rm->next;
+      return true;
+    } else {
+      /* Element to remove is not in the table. */
+      return false;
+    }
+  }
+}
+
+static size_t next(const upb_table *t, size_t i) {
+  do {
+    if (++i >= upb_table_size(t))
+      return SIZE_MAX;
+  } while(upb_tabent_isempty(&t->entries[i]));
+
+  return i;
+}
+
+static size_t begin(const upb_table *t) {
+  return next(t, -1);
+}
+
+
+/* upb_strtable ***************************************************************/
+
+/* A simple "subclass" of upb_table that only adds a hash function for strings. */
+
+static upb_tabkey strcopy(lookupkey_t k2, upb_alloc *a) {
+  char *str = upb_malloc(a, k2.str.len + sizeof(uint32_t) + 1);
+  if (str == NULL) return 0;
+  memcpy(str, &k2.str.len, sizeof(uint32_t));
+  memcpy(str + sizeof(uint32_t), k2.str.str, k2.str.len + 1);
+  return (uintptr_t)str;
+}
+
+static uint32_t strhash(upb_tabkey key) {
+  uint32_t len;
+  char *str = upb_tabstr(key, &len);
+  return MurmurHash2(str, len, 0);
+}
+
+static bool streql(upb_tabkey k1, lookupkey_t k2) {
+  uint32_t len;
+  char *str = upb_tabstr(k1, &len);
+  return len == k2.str.len && memcmp(str, k2.str.str, len) == 0;
+}
+
+bool upb_strtable_init2(upb_strtable *t, upb_ctype_t ctype, upb_alloc *a) {
+  return init(&t->t, ctype, 2, a);
+}
+
+void upb_strtable_uninit2(upb_strtable *t, upb_alloc *a) {
+  size_t i;
+  for (i = 0; i < upb_table_size(&t->t); i++)
+    upb_free(a, (void*)t->t.entries[i].key);
+  uninit(&t->t, a);
+}
+
+bool upb_strtable_resize(upb_strtable *t, size_t size_lg2, upb_alloc *a) {
+  upb_strtable new_table;
+  upb_strtable_iter i;
+
+  upb_check_alloc(&t->t, a);
+
+  if (!init(&new_table.t, t->t.ctype, size_lg2, a))
+    return false;
+  upb_strtable_begin(&i, t);
+  for ( ; !upb_strtable_done(&i); upb_strtable_next(&i)) {
+    upb_strtable_insert3(
+        &new_table,
+        upb_strtable_iter_key(&i),
+        upb_strtable_iter_keylength(&i),
+        upb_strtable_iter_value(&i),
+        a);
+  }
+  upb_strtable_uninit2(t, a);
+  *t = new_table;
+  return true;
+}
+
+bool upb_strtable_insert3(upb_strtable *t, const char *k, size_t len,
+                          upb_value v, upb_alloc *a) {
+  lookupkey_t key;
+  upb_tabkey tabkey;
+  uint32_t hash;
+
+  upb_check_alloc(&t->t, a);
+
+  if (isfull(&t->t)) {
+    /* Need to resize.  New table of double the size, add old elements to it. */
+    if (!upb_strtable_resize(t, t->t.size_lg2 + 1, a)) {
+      return false;
+    }
+  }
+
+  key = strkey2(k, len);
+  tabkey = strcopy(key, a);
+  if (tabkey == 0) return false;
+
+  hash = MurmurHash2(key.str.str, key.str.len, 0);
+  insert(&t->t, key, tabkey, v, hash, &strhash, &streql);
+  return true;
+}
+
+bool upb_strtable_lookup2(const upb_strtable *t, const char *key, size_t len,
+                          upb_value *v) {
+  uint32_t hash = MurmurHash2(key, len, 0);
+  return lookup(&t->t, strkey2(key, len), v, hash, &streql);
+}
+
+bool upb_strtable_remove3(upb_strtable *t, const char *key, size_t len,
+                         upb_value *val, upb_alloc *alloc) {
+  uint32_t hash = MurmurHash2(key, len, 0);
+  upb_tabkey tabkey;
+  if (rm(&t->t, strkey2(key, len), val, &tabkey, hash, &streql)) {
+    upb_free(alloc, (void*)tabkey);
+    return true;
+  } else {
+    return false;
+  }
+}
+
+/* Iteration */
+
+static const upb_tabent *str_tabent(const upb_strtable_iter *i) {
+  return &i->t->t.entries[i->index];
+}
+
+void upb_strtable_begin(upb_strtable_iter *i, const upb_strtable *t) {
+  i->t = t;
+  i->index = begin(&t->t);
+}
+
+void upb_strtable_next(upb_strtable_iter *i) {
+  i->index = next(&i->t->t, i->index);
+}
+
+bool upb_strtable_done(const upb_strtable_iter *i) {
+  return i->index >= upb_table_size(&i->t->t) ||
+         upb_tabent_isempty(str_tabent(i));
+}
+
+const char *upb_strtable_iter_key(const upb_strtable_iter *i) {
+  UPB_ASSERT(!upb_strtable_done(i));
+  return upb_tabstr(str_tabent(i)->key, NULL);
+}
+
+size_t upb_strtable_iter_keylength(const upb_strtable_iter *i) {
+  uint32_t len;
+  UPB_ASSERT(!upb_strtable_done(i));
+  upb_tabstr(str_tabent(i)->key, &len);
+  return len;
+}
+
+upb_value upb_strtable_iter_value(const upb_strtable_iter *i) {
+  UPB_ASSERT(!upb_strtable_done(i));
+  return _upb_value_val(str_tabent(i)->val.val, i->t->t.ctype);
+}
+
+void upb_strtable_iter_setdone(upb_strtable_iter *i) {
+  i->index = SIZE_MAX;
+}
+
+bool upb_strtable_iter_isequal(const upb_strtable_iter *i1,
+                               const upb_strtable_iter *i2) {
+  if (upb_strtable_done(i1) && upb_strtable_done(i2))
+    return true;
+  return i1->t == i2->t && i1->index == i2->index;
+}
+
+
+/* upb_inttable ***************************************************************/
+
+/* For inttables we use a hybrid structure where small keys are kept in an
+ * array and large keys are put in the hash table. */
+
+static uint32_t inthash(upb_tabkey key) { return upb_inthash(key); }
+
+static bool inteql(upb_tabkey k1, lookupkey_t k2) {
+  return k1 == k2.num;
+}
+
+static upb_tabval *mutable_array(upb_inttable *t) {
+  return (upb_tabval*)t->array;
+}
+
+static upb_tabval *inttable_val(upb_inttable *t, uintptr_t key) {
+  if (key < t->array_size) {
+    return upb_arrhas(t->array[key]) ? &(mutable_array(t)[key]) : NULL;
+  } else {
+    upb_tabent *e =
+        findentry_mutable(&t->t, intkey(key), upb_inthash(key), &inteql);
+    return e ? &e->val : NULL;
+  }
+}
+
+static const upb_tabval *inttable_val_const(const upb_inttable *t,
+                                            uintptr_t key) {
+  return inttable_val((upb_inttable*)t, key);
+}
+
+size_t upb_inttable_count(const upb_inttable *t) {
+  return t->t.count + t->array_count;
+}
+
+static void check(upb_inttable *t) {
+  UPB_UNUSED(t);
+#if defined(UPB_DEBUG_TABLE) && !defined(NDEBUG)
+  {
+    /* This check is very expensive (makes inserts/deletes O(N)). */
+    size_t count = 0;
+    upb_inttable_iter i;
+    upb_inttable_begin(&i, t);
+    for(; !upb_inttable_done(&i); upb_inttable_next(&i), count++) {
+      UPB_ASSERT(upb_inttable_lookup(t, upb_inttable_iter_key(&i), NULL));
+    }
+    UPB_ASSERT(count == upb_inttable_count(t));
+  }
+#endif
+}
+
+bool upb_inttable_sizedinit(upb_inttable *t, upb_ctype_t ctype,
+                            size_t asize, int hsize_lg2, upb_alloc *a) {
+  size_t array_bytes;
+
+  if (!init(&t->t, ctype, hsize_lg2, a)) return false;
+  /* Always make the array part at least 1 long, so that we know key 0
+   * won't be in the hash part, which simplifies things. */
+  t->array_size = UPB_MAX(1, asize);
+  t->array_count = 0;
+  array_bytes = t->array_size * sizeof(upb_value);
+  t->array = upb_malloc(a, array_bytes);
+  if (!t->array) {
+    uninit(&t->t, a);
+    return false;
+  }
+  memset(mutable_array(t), 0xff, array_bytes);
+  check(t);
+  return true;
+}
+
+bool upb_inttable_init2(upb_inttable *t, upb_ctype_t ctype, upb_alloc *a) {
+  return upb_inttable_sizedinit(t, ctype, 0, 4, a);
+}
+
+void upb_inttable_uninit2(upb_inttable *t, upb_alloc *a) {
+  uninit(&t->t, a);
+  upb_free(a, mutable_array(t));
+}
+
+bool upb_inttable_insert2(upb_inttable *t, uintptr_t key, upb_value val,
+                          upb_alloc *a) {
+  upb_tabval tabval;
+  tabval.val = val.val;
+  UPB_ASSERT(upb_arrhas(tabval));  /* This will reject (uint64_t)-1.  Fix this. */
+
+  upb_check_alloc(&t->t, a);
+
+  if (key < t->array_size) {
+    UPB_ASSERT(!upb_arrhas(t->array[key]));
+    t->array_count++;
+    mutable_array(t)[key].val = val.val;
+  } else {
+    if (isfull(&t->t)) {
+      /* Need to resize the hash part, but we re-use the array part. */
+      size_t i;
+      upb_table new_table;
+
+      if (!init(&new_table, t->t.ctype, t->t.size_lg2 + 1, a)) {
+        return false;
+      }
+
+      for (i = begin(&t->t); i < upb_table_size(&t->t); i = next(&t->t, i)) {
+        const upb_tabent *e = &t->t.entries[i];
+        uint32_t hash;
+        upb_value v;
+
+        _upb_value_setval(&v, e->val.val, t->t.ctype);
+        hash = upb_inthash(e->key);
+        insert(&new_table, intkey(e->key), e->key, v, hash, &inthash, &inteql);
+      }
+
+      UPB_ASSERT(t->t.count == new_table.count);
+
+      uninit(&t->t, a);
+      t->t = new_table;
+    }
+    insert(&t->t, intkey(key), key, val, upb_inthash(key), &inthash, &inteql);
+  }
+  check(t);
+  return true;
+}
+
+bool upb_inttable_lookup(const upb_inttable *t, uintptr_t key, upb_value *v) {
+  const upb_tabval *table_v = inttable_val_const(t, key);
+  if (!table_v) return false;
+  if (v) _upb_value_setval(v, table_v->val, t->t.ctype);
+  return true;
+}
+
+bool upb_inttable_replace(upb_inttable *t, uintptr_t key, upb_value val) {
+  upb_tabval *table_v = inttable_val(t, key);
+  if (!table_v) return false;
+  table_v->val = val.val;
+  return true;
+}
+
+bool upb_inttable_remove(upb_inttable *t, uintptr_t key, upb_value *val) {
+  bool success;
+  if (key < t->array_size) {
+    if (upb_arrhas(t->array[key])) {
+      upb_tabval empty = UPB_TABVALUE_EMPTY_INIT;
+      t->array_count--;
+      if (val) {
+        _upb_value_setval(val, t->array[key].val, t->t.ctype);
+      }
+      mutable_array(t)[key] = empty;
+      success = true;
+    } else {
+      success = false;
+    }
+  } else {
+    success = rm(&t->t, intkey(key), val, NULL, upb_inthash(key), &inteql);
+  }
+  check(t);
+  return success;
+}
+
+bool upb_inttable_push2(upb_inttable *t, upb_value val, upb_alloc *a) {
+  upb_check_alloc(&t->t, a);
+  return upb_inttable_insert2(t, upb_inttable_count(t), val, a);
+}
+
+upb_value upb_inttable_pop(upb_inttable *t) {
+  upb_value val;
+  bool ok = upb_inttable_remove(t, upb_inttable_count(t) - 1, &val);
+  UPB_ASSERT(ok);
+  return val;
+}
+
+bool upb_inttable_insertptr2(upb_inttable *t, const void *key, upb_value val,
+                             upb_alloc *a) {
+  upb_check_alloc(&t->t, a);
+  return upb_inttable_insert2(t, (uintptr_t)key, val, a);
+}
+
+bool upb_inttable_lookupptr(const upb_inttable *t, const void *key,
+                            upb_value *v) {
+  return upb_inttable_lookup(t, (uintptr_t)key, v);
+}
+
+bool upb_inttable_removeptr(upb_inttable *t, const void *key, upb_value *val) {
+  return upb_inttable_remove(t, (uintptr_t)key, val);
+}
+
+void upb_inttable_compact2(upb_inttable *t, upb_alloc *a) {
+  /* A power-of-two histogram of the table keys. */
+  size_t counts[UPB_MAXARRSIZE + 1] = {0};
+
+  /* The max key in each bucket. */
+  uintptr_t max[UPB_MAXARRSIZE + 1] = {0};
+
+  upb_inttable_iter i;
+  size_t arr_count;
+  int size_lg2;
+  upb_inttable new_t;
+
+  upb_check_alloc(&t->t, a);
+
+  upb_inttable_begin(&i, t);
+  for (; !upb_inttable_done(&i); upb_inttable_next(&i)) {
+    uintptr_t key = upb_inttable_iter_key(&i);
+    int bucket = log2ceil(key);
+    max[bucket] = UPB_MAX(max[bucket], key);
+    counts[bucket]++;
+  }
+
+  /* Find the largest power of two that satisfies the MIN_DENSITY
+   * definition (while actually having some keys). */
+  arr_count = upb_inttable_count(t);
+
+  for (size_lg2 = ARRAY_SIZE(counts) - 1; size_lg2 > 0; size_lg2--) {
+    if (counts[size_lg2] == 0) {
+      /* We can halve again without losing any entries. */
+      continue;
+    } else if (arr_count >= (1 << size_lg2) * MIN_DENSITY) {
+      break;
+    }
+
+    arr_count -= counts[size_lg2];
+  }
+
+  UPB_ASSERT(arr_count <= upb_inttable_count(t));
+
+  {
+    /* Insert all elements into new, perfectly-sized table. */
+    size_t arr_size = max[size_lg2] + 1;  /* +1 so arr[max] will fit. */
+    size_t hash_count = upb_inttable_count(t) - arr_count;
+    size_t hash_size = hash_count ? (hash_count / MAX_LOAD) + 1 : 0;
+    size_t hashsize_lg2 = log2ceil(hash_size);
+
+    upb_inttable_sizedinit(&new_t, t->t.ctype, arr_size, hashsize_lg2, a);
+    upb_inttable_begin(&i, t);
+    for (; !upb_inttable_done(&i); upb_inttable_next(&i)) {
+      uintptr_t k = upb_inttable_iter_key(&i);
+      upb_inttable_insert2(&new_t, k, upb_inttable_iter_value(&i), a);
+    }
+    UPB_ASSERT(new_t.array_size == arr_size);
+    UPB_ASSERT(new_t.t.size_lg2 == hashsize_lg2);
+  }
+  upb_inttable_uninit2(t, a);
+  *t = new_t;
+}
+
+/* Iteration. */
+
+static const upb_tabent *int_tabent(const upb_inttable_iter *i) {
+  UPB_ASSERT(!i->array_part);
+  return &i->t->t.entries[i->index];
+}
+
+static upb_tabval int_arrent(const upb_inttable_iter *i) {
+  UPB_ASSERT(i->array_part);
+  return i->t->array[i->index];
+}
+
+void upb_inttable_begin(upb_inttable_iter *i, const upb_inttable *t) {
+  i->t = t;
+  i->index = -1;
+  i->array_part = true;
+  upb_inttable_next(i);
+}
+
+void upb_inttable_next(upb_inttable_iter *iter) {
+  const upb_inttable *t = iter->t;
+  if (iter->array_part) {
+    while (++iter->index < t->array_size) {
+      if (upb_arrhas(int_arrent(iter))) {
+        return;
+      }
+    }
+    iter->array_part = false;
+    iter->index = begin(&t->t);
+  } else {
+    iter->index = next(&t->t, iter->index);
+  }
+}
+
+bool upb_inttable_done(const upb_inttable_iter *i) {
+  if (i->array_part) {
+    return i->index >= i->t->array_size ||
+           !upb_arrhas(int_arrent(i));
+  } else {
+    return i->index >= upb_table_size(&i->t->t) ||
+           upb_tabent_isempty(int_tabent(i));
+  }
+}
+
+uintptr_t upb_inttable_iter_key(const upb_inttable_iter *i) {
+  UPB_ASSERT(!upb_inttable_done(i));
+  return i->array_part ? i->index : int_tabent(i)->key;
+}
+
+upb_value upb_inttable_iter_value(const upb_inttable_iter *i) {
+  UPB_ASSERT(!upb_inttable_done(i));
+  return _upb_value_val(
+      i->array_part ? i->t->array[i->index].val : int_tabent(i)->val.val,
+      i->t->t.ctype);
+}
+
+void upb_inttable_iter_setdone(upb_inttable_iter *i) {
+  i->index = SIZE_MAX;
+  i->array_part = false;
+}
+
+bool upb_inttable_iter_isequal(const upb_inttable_iter *i1,
+                                          const upb_inttable_iter *i2) {
+  if (upb_inttable_done(i1) && upb_inttable_done(i2))
+    return true;
+  return i1->t == i2->t && i1->index == i2->index &&
+         i1->array_part == i2->array_part;
+}
+
+#ifdef UPB_UNALIGNED_READS_OK
+/* -----------------------------------------------------------------------------
+ * MurmurHash2, by Austin Appleby (released as public domain).
+ * Reformatted and C99-ified by Joshua Haberman.
+ * Note - This code makes a few assumptions about how your machine behaves -
+ *   1. We can read a 4-byte value from any address without crashing
+ *   2. sizeof(int) == 4 (in upb this limitation is removed by using uint32_t
+ * And it has a few limitations -
+ *   1. It will not work incrementally.
+ *   2. It will not produce the same results on little-endian and big-endian
+ *      machines. */
+uint32_t MurmurHash2(const void *key, size_t len, uint32_t seed) {
+  /* 'm' and 'r' are mixing constants generated offline.
+   * They're not really 'magic', they just happen to work well. */
+  const uint32_t m = 0x5bd1e995;
+  const int32_t r = 24;
+
+  /* Initialize the hash to a 'random' value */
+  uint32_t h = seed ^ len;
+
+  /* Mix 4 bytes at a time into the hash */
+  const uint8_t * data = (const uint8_t *)key;
+  while(len >= 4) {
+    uint32_t k = *(uint32_t *)data;
+
+    k *= m;
+    k ^= k >> r;
+    k *= m;
+
+    h *= m;
+    h ^= k;
+
+    data += 4;
+    len -= 4;
+  }
+
+  /* Handle the last few bytes of the input array */
+  switch(len) {
+    case 3: h ^= data[2] << 16;
+    case 2: h ^= data[1] << 8;
+    case 1: h ^= data[0]; h *= m;
+  };
+
+  /* Do a few final mixes of the hash to ensure the last few
+   * bytes are well-incorporated. */
+  h ^= h >> 13;
+  h *= m;
+  h ^= h >> 15;
+
+  return h;
+}
+
+#else /* !UPB_UNALIGNED_READS_OK */
+
+/* -----------------------------------------------------------------------------
+ * MurmurHashAligned2, by Austin Appleby
+ * Same algorithm as MurmurHash2, but only does aligned reads - should be safer
+ * on certain platforms.
+ * Performance will be lower than MurmurHash2 */
+
+#define MIX(h,k,m) { k *= m; k ^= k >> r; k *= m; h *= m; h ^= k; }
+
+uint32_t MurmurHash2(const void * key, size_t len, uint32_t seed) {
+  const uint32_t m = 0x5bd1e995;
+  const int32_t r = 24;
+  const uint8_t * data = (const uint8_t *)key;
+  uint32_t h = seed ^ len;
+  uint8_t align = (uintptr_t)data & 3;
+
+  if(align && (len >= 4)) {
+    /* Pre-load the temp registers */
+    uint32_t t = 0, d = 0;
+    int32_t sl;
+    int32_t sr;
+
+    switch(align) {
+      case 1: t |= data[2] << 16;
+      case 2: t |= data[1] << 8;
+      case 3: t |= data[0];
+    }
+
+    t <<= (8 * align);
+
+    data += 4-align;
+    len -= 4-align;
+
+    sl = 8 * (4-align);
+    sr = 8 * align;
+
+    /* Mix */
+
+    while(len >= 4) {
+      uint32_t k;
+
+      d = *(uint32_t *)data;
+      t = (t >> sr) | (d << sl);
+
+      k = t;
+
+      MIX(h,k,m);
+
+      t = d;
+
+      data += 4;
+      len -= 4;
+    }
+
+    /* Handle leftover data in temp registers */
+
+    d = 0;
+
+    if(len >= align) {
+      uint32_t k;
+
+      switch(align) {
+        case 3: d |= data[2] << 16;
+        case 2: d |= data[1] << 8;
+        case 1: d |= data[0];
+      }
+
+      k = (t >> sr) | (d << sl);
+      MIX(h,k,m);
+
+      data += align;
+      len -= align;
+
+      /* ----------
+       * Handle tail bytes */
+
+      switch(len) {
+        case 3: h ^= data[2] << 16;
+        case 2: h ^= data[1] << 8;
+        case 1: h ^= data[0]; h *= m;
+      };
+    } else {
+      switch(len) {
+        case 3: d |= data[2] << 16;
+        case 2: d |= data[1] << 8;
+        case 1: d |= data[0];
+        case 0: h ^= (t >> sr) | (d << sl); h *= m;
+      }
+    }
+
+    h ^= h >> 13;
+    h *= m;
+    h ^= h >> 15;
+
+    return h;
+  } else {
+    while(len >= 4) {
+      uint32_t k = *(uint32_t *)data;
+
+      MIX(h,k,m);
+
+      data += 4;
+      len -= 4;
+    }
+
+    /* ----------
+     * Handle tail bytes */
+
+    switch(len) {
+      case 3: h ^= data[2] << 16;
+      case 2: h ^= data[1] << 8;
+      case 1: h ^= data[0]; h *= m;
+    };
+
+    h ^= h >> 13;
+    h *= m;
+    h ^= h >> 15;
+
+    return h;
+  }
+}
+#undef MIX
+
+#endif /* UPB_UNALIGNED_READS_OK */
+
+#include <errno.h>
+#include <stdarg.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+bool upb_dumptostderr(void *closure, const upb_status* status) {
+  UPB_UNUSED(closure);
+  fprintf(stderr, "%s\n", upb_status_errmsg(status));
+  return false;
+}
+
+/* Guarantee null-termination and provide ellipsis truncation.
+ * It may be tempting to "optimize" this by initializing these final
+ * four bytes up-front and then being careful never to overwrite them,
+ * this is safer and simpler. */
+static void nullz(upb_status *status) {
+  const char *ellipsis = "...";
+  size_t len = strlen(ellipsis);
+  UPB_ASSERT(sizeof(status->msg) > len);
+  memcpy(status->msg + sizeof(status->msg) - len, ellipsis, len);
+}
+
+
+/* upb_upberr *****************************************************************/
+
+upb_errorspace upb_upberr = {"upb error"};
+
+void upb_upberr_setoom(upb_status *status) {
+  status->error_space_ = &upb_upberr;
+  upb_status_seterrmsg(status, "Out of memory");
+}
+
+
+/* upb_status *****************************************************************/
+
+void upb_status_clear(upb_status *status) {
+  if (!status) return;
+  status->ok_ = true;
+  status->code_ = 0;
+  status->msg[0] = '\0';
+}
+
+bool upb_ok(const upb_status *status) { return status->ok_; }
+
+upb_errorspace *upb_status_errspace(const upb_status *status) {
+  return status->error_space_;
+}
+
+int upb_status_errcode(const upb_status *status) { return status->code_; }
+
+const char *upb_status_errmsg(const upb_status *status) { return status->msg; }
+
+void upb_status_seterrmsg(upb_status *status, const char *msg) {
+  if (!status) return;
+  status->ok_ = false;
+  strncpy(status->msg, msg, sizeof(status->msg));
+  nullz(status);
+}
+
+void upb_status_seterrf(upb_status *status, const char *fmt, ...) {
+  va_list args;
+  va_start(args, fmt);
+  upb_status_vseterrf(status, fmt, args);
+  va_end(args);
+}
+
+void upb_status_vseterrf(upb_status *status, const char *fmt, va_list args) {
+  if (!status) return;
+  status->ok_ = false;
+  _upb_vsnprintf(status->msg, sizeof(status->msg), fmt, args);
+  nullz(status);
+}
+
+void upb_status_copy(upb_status *to, const upb_status *from) {
+  if (!to) return;
+  *to = *from;
+}
+
+
+/* upb_alloc ******************************************************************/
+
+static void *upb_global_allocfunc(upb_alloc *alloc, void *ptr, size_t oldsize,
+                                  size_t size) {
+  UPB_UNUSED(alloc);
+  UPB_UNUSED(oldsize);
+  if (size == 0) {
+    free(ptr);
+    return NULL;
+  } else {
+    return realloc(ptr, size);
+  }
+}
+
+upb_alloc upb_alloc_global = {&upb_global_allocfunc};
+
+
+/* upb_arena ******************************************************************/
+
+/* Be conservative and choose 16 in case anyone is using SSE. */
+static const size_t maxalign = 16;
+
+static size_t align_up_max(size_t size) {
+  return ((size + maxalign - 1) / maxalign) * maxalign;
+}
+
+typedef struct mem_block {
+  struct mem_block *next;
+  size_t size;
+  size_t used;
+  bool owned;
+  /* Data follows. */
+} mem_block;
+
+typedef struct cleanup_ent {
+  struct cleanup_ent *next;
+  upb_cleanup_func *cleanup;
+  void *ud;
+} cleanup_ent;
+
+static void upb_arena_addblock(upb_arena *a, void *ptr, size_t size,
+                               bool owned) {
+  mem_block *block = ptr;
+
+  block->next = a->block_head;
+  block->size = size;
+  block->used = align_up_max(sizeof(mem_block));
+  block->owned = owned;
+
+  a->block_head = block;
+
+  /* TODO(haberman): ASAN poison. */
+}
+
+
+static mem_block *upb_arena_allocblock(upb_arena *a, size_t size) {
+  size_t block_size = UPB_MAX(size, a->next_block_size) + sizeof(mem_block);
+  mem_block *block = upb_malloc(a->block_alloc, block_size);
+
+  if (!block) {
+    return NULL;
+  }
+
+  upb_arena_addblock(a, block, block_size, true);
+  a->next_block_size = UPB_MIN(block_size * 2, a->max_block_size);
+
+  return block;
+}
+
+static void *upb_arena_doalloc(upb_alloc *alloc, void *ptr, size_t oldsize,
+                               size_t size) {
+  upb_arena *a = (upb_arena*)alloc;  /* upb_alloc is initial member. */
+  mem_block *block = a->block_head;
+  void *ret;
+
+  if (size == 0) {
+    return NULL;  /* We are an arena, don't need individual frees. */
+  }
+
+  size = align_up_max(size);
+
+  /* TODO(haberman): special-case if this is a realloc of the last alloc? */
+
+  if (!block || block->size - block->used < size) {
+    /* Slow path: have to allocate a new block. */
+    block = upb_arena_allocblock(a, size);
+
+    if (!block) {
+      return NULL;  /* Out of memory. */
+    }
+  }
+
+  ret = (char*)block + block->used;
+  block->used += size;
+
+  if (oldsize > 0) {
+    memcpy(ret, ptr, oldsize);  /* Preserve existing data. */
+  }
+
+  /* TODO(haberman): ASAN unpoison. */
+
+  a->bytes_allocated += size;
+  return ret;
+}
+
+/* Public Arena API ***********************************************************/
+
+void upb_arena_init(upb_arena *a) {
+  a->alloc.func = &upb_arena_doalloc;
+  a->block_alloc = &upb_alloc_global;
+  a->bytes_allocated = 0;
+  a->next_block_size = 256;
+  a->max_block_size = 16384;
+  a->cleanup_head = NULL;
+  a->block_head = NULL;
+}
+
+void upb_arena_init2(upb_arena *a, void *mem, size_t size, upb_alloc *alloc) {
+  upb_arena_init(a);
+
+  if (size > sizeof(mem_block)) {
+    upb_arena_addblock(a, mem, size, false);
+  }
+
+  if (alloc) {
+    a->block_alloc = alloc;
+  }
+}
+
+void upb_arena_uninit(upb_arena *a) {
+  cleanup_ent *ent = a->cleanup_head;
+  mem_block *block = a->block_head;
+
+  while (ent) {
+    ent->cleanup(ent->ud);
+    ent = ent->next;
+  }
+
+  /* Must do this after running cleanup functions, because this will delete
+   * the memory we store our cleanup entries in! */
+  while (block) {
+    mem_block *next = block->next;
+
+    if (block->owned) {
+      upb_free(a->block_alloc, block);
+    }
+
+    block = next;
+  }
+
+  /* Protect against multiple-uninit. */
+  a->cleanup_head = NULL;
+  a->block_head = NULL;
+}
+
+bool upb_arena_addcleanup(upb_arena *a, upb_cleanup_func *func, void *ud) {
+  cleanup_ent *ent = upb_malloc(&a->alloc, sizeof(cleanup_ent));
+  if (!ent) {
+    return false;  /* Out of memory. */
+  }
+
+  ent->cleanup = func;
+  ent->ud = ud;
+  ent->next = a->cleanup_head;
+  a->cleanup_head = ent;
+
+  return true;
+}
+
+size_t upb_arena_bytesallocated(const upb_arena *a) {
+  return a->bytes_allocated;
+}
+
+
+/* Standard error functions ***************************************************/
+
+static bool default_err(void *ud, const upb_status *status) {
+  UPB_UNUSED(ud);
+  UPB_UNUSED(status);
+  return false;
+}
+
+static bool write_err_to(void *ud, const upb_status *status) {
+  upb_status *copy_to = ud;
+  upb_status_copy(copy_to, status);
+  return false;
+}
+
+
+/* upb_env ********************************************************************/
+
+void upb_env_initonly(upb_env *e) {
+  e->ok_ = true;
+  e->error_func_ = &default_err;
+  e->error_ud_ = NULL;
+}
+
+void upb_env_init(upb_env *e) {
+  upb_arena_init(&e->arena_);
+  upb_env_initonly(e);
+}
+
+void upb_env_init2(upb_env *e, void *mem, size_t n, upb_alloc *alloc) {
+  upb_arena_init2(&e->arena_, mem, n, alloc);
+  upb_env_initonly(e);
+}
+
+void upb_env_uninit(upb_env *e) {
+  upb_arena_uninit(&e->arena_);
+}
+
+void upb_env_seterrorfunc(upb_env *e, upb_error_func *func, void *ud) {
+  e->error_func_ = func;
+  e->error_ud_ = ud;
+}
+
+void upb_env_reporterrorsto(upb_env *e, upb_status *s) {
+  e->error_func_ = &write_err_to;
+  e->error_ud_ = s;
+}
+
+bool upb_env_reporterror(upb_env *e, const upb_status *status) {
+  e->ok_ = false;
+  return e->error_func_(e->error_ud_, status);
+}
+
+void *upb_env_malloc(upb_env *e, size_t size) {
+  return upb_malloc(&e->arena_.alloc, size);
+}
+
+void *upb_env_realloc(upb_env *e, void *ptr, size_t oldsize, size_t size) {
+  return upb_realloc(&e->arena_.alloc, ptr, oldsize, size);
+}
+
+void upb_env_free(upb_env *e, void *ptr) {
+  upb_free(&e->arena_.alloc, ptr);
+}
+
+bool upb_env_addcleanup(upb_env *e, upb_cleanup_func *func, void *ud) {
+  return upb_arena_addcleanup(&e->arena_, func, ud);
+}
+
+size_t upb_env_bytesallocated(const upb_env *e) {
+  return upb_arena_bytesallocated(&e->arena_);
+}
+/* This file was generated by upbc (the upb compiler) from the input
+ * file:
+ *
+ *     upb/descriptor/descriptor.proto
+ *
+ * Do not edit -- your changes will be discarded when the file is
+ * regenerated. */
+
+
+static const upb_msgdef msgs[22];
+static const upb_fielddef fields[107];
+static const upb_enumdef enums[5];
+static const upb_tabent strentries[236];
+static const upb_tabent intentries[18];
+static const upb_tabval arrays[187];
+
+#ifdef UPB_DEBUG_REFS
+static upb_inttable reftables[268];
+#endif
+
+static const upb_msgdef msgs[22] = {
+  UPB_MSGDEF_INIT("google.protobuf.DescriptorProto", 41, 8, UPB_INTTABLE_INIT(0, 0, UPB_CTYPE_PTR, 0, NULL, &arrays[0], 11, 10), UPB_STRTABLE_INIT(10, 15, UPB_CTYPE_PTR, 4, &strentries[0]), false, UPB_SYNTAX_PROTO2, &reftables[0], &reftables[1]),
+  UPB_MSGDEF_INIT("google.protobuf.DescriptorProto.ExtensionRange", 5, 0, UPB_INTTABLE_INIT(0, 0, UPB_CTYPE_PTR, 0, NULL, &arrays[11], 3, 2), UPB_STRTABLE_INIT(2, 3, UPB_CTYPE_PTR, 2, &strentries[16]), false, UPB_SYNTAX_PROTO2, &reftables[2], &reftables[3]),
+  UPB_MSGDEF_INIT("google.protobuf.DescriptorProto.ReservedRange", 5, 0, UPB_INTTABLE_INIT(0, 0, UPB_CTYPE_PTR, 0, NULL, &arrays[14], 3, 2), UPB_STRTABLE_INIT(2, 3, UPB_CTYPE_PTR, 2, &strentries[20]), false, UPB_SYNTAX_PROTO2, &reftables[4], &reftables[5]),
+  UPB_MSGDEF_INIT("google.protobuf.EnumDescriptorProto", 12, 2, UPB_INTTABLE_INIT(0, 0, UPB_CTYPE_PTR, 0, NULL, &arrays[17], 4, 3), UPB_STRTABLE_INIT(3, 3, UPB_CTYPE_PTR, 2, &strentries[24]), false, UPB_SYNTAX_PROTO2, &reftables[6], &reftables[7]),
+  UPB_MSGDEF_INIT("google.protobuf.EnumOptions", 9, 1, UPB_INTTABLE_INIT(1, 1, UPB_CTYPE_PTR, 1, &intentries[0], &arrays[21], 4, 2), UPB_STRTABLE_INIT(3, 3, UPB_CTYPE_PTR, 2, &strentries[28]), false, UPB_SYNTAX_PROTO2, &reftables[8], &reftables[9]),
+  UPB_MSGDEF_INIT("google.protobuf.EnumValueDescriptorProto", 9, 1, UPB_INTTABLE_INIT(0, 0, UPB_CTYPE_PTR, 0, NULL, &arrays[25], 4, 3), UPB_STRTABLE_INIT(3, 3, UPB_CTYPE_PTR, 2, &strentries[32]), false, UPB_SYNTAX_PROTO2, &reftables[10], &reftables[11]),
+  UPB_MSGDEF_INIT("google.protobuf.EnumValueOptions", 8, 1, UPB_INTTABLE_INIT(1, 1, UPB_CTYPE_PTR, 1, &intentries[2], &arrays[29], 2, 1), UPB_STRTABLE_INIT(2, 3, UPB_CTYPE_PTR, 2, &strentries[36]), false, UPB_SYNTAX_PROTO2, &reftables[12], &reftables[13]),
+  UPB_MSGDEF_INIT("google.protobuf.FieldDescriptorProto", 24, 1, UPB_INTTABLE_INIT(0, 0, UPB_CTYPE_PTR, 0, NULL, &arrays[31], 11, 10), UPB_STRTABLE_INIT(10, 15, UPB_CTYPE_PTR, 4, &strentries[40]), false, UPB_SYNTAX_PROTO2, &reftables[14], &reftables[15]),
+  UPB_MSGDEF_INIT("google.protobuf.FieldOptions", 13, 1, UPB_INTTABLE_INIT(1, 1, UPB_CTYPE_PTR, 1, &intentries[4], &arrays[42], 11, 6), UPB_STRTABLE_INIT(7, 15, UPB_CTYPE_PTR, 4, &strentries[56]), false, UPB_SYNTAX_PROTO2, &reftables[16], &reftables[17]),
+  UPB_MSGDEF_INIT("google.protobuf.FileDescriptorProto", 43, 6, UPB_INTTABLE_INIT(0, 0, UPB_CTYPE_PTR, 0, NULL, &arrays[53], 13, 12), UPB_STRTABLE_INIT(12, 15, UPB_CTYPE_PTR, 4, &strentries[72]), false, UPB_SYNTAX_PROTO2, &reftables[18], &reftables[19]),
+  UPB_MSGDEF_INIT("google.protobuf.FileDescriptorSet", 7, 1, UPB_INTTABLE_INIT(0, 0, UPB_CTYPE_PTR, 0, NULL, &arrays[66], 2, 1), UPB_STRTABLE_INIT(1, 3, UPB_CTYPE_PTR, 2, &strentries[88]), false, UPB_SYNTAX_PROTO2, &reftables[20], &reftables[21]),
+  UPB_MSGDEF_INIT("google.protobuf.FileOptions", 38, 1, UPB_INTTABLE_INIT(1, 1, UPB_CTYPE_PTR, 1, &intentries[6], &arrays[68], 42, 17), UPB_STRTABLE_INIT(18, 31, UPB_CTYPE_PTR, 5, &strentries[92]), false, UPB_SYNTAX_PROTO2, &reftables[22], &reftables[23]),
+  UPB_MSGDEF_INIT("google.protobuf.MessageOptions", 11, 1, UPB_INTTABLE_INIT(1, 1, UPB_CTYPE_PTR, 1, &intentries[8], &arrays[110], 8, 4), UPB_STRTABLE_INIT(5, 7, UPB_CTYPE_PTR, 3, &strentries[124]), false, UPB_SYNTAX_PROTO2, &reftables[24], &reftables[25]),
+  UPB_MSGDEF_INIT("google.protobuf.MethodDescriptorProto", 16, 1, UPB_INTTABLE_INIT(0, 0, UPB_CTYPE_PTR, 0, NULL, &arrays[118], 7, 6), UPB_STRTABLE_INIT(6, 7, UPB_CTYPE_PTR, 3, &strentries[132]), false, UPB_SYNTAX_PROTO2, &reftables[26], &reftables[27]),
+  UPB_MSGDEF_INIT("google.protobuf.MethodOptions", 8, 1, UPB_INTTABLE_INIT(2, 3, UPB_CTYPE_PTR, 2, &intentries[10], &arrays[125], 1, 0), UPB_STRTABLE_INIT(2, 3, UPB_CTYPE_PTR, 2, &strentries[140]), false, UPB_SYNTAX_PROTO2, &reftables[28], &reftables[29]),
+  UPB_MSGDEF_INIT("google.protobuf.OneofDescriptorProto", 6, 0, UPB_INTTABLE_INIT(0, 0, UPB_CTYPE_PTR, 0, NULL, &arrays[126], 2, 1), UPB_STRTABLE_INIT(1, 3, UPB_CTYPE_PTR, 2, &strentries[144]), false, UPB_SYNTAX_PROTO2, &reftables[30], &reftables[31]),
+  UPB_MSGDEF_INIT("google.protobuf.ServiceDescriptorProto", 12, 2, UPB_INTTABLE_INIT(0, 0, UPB_CTYPE_PTR, 0, NULL, &arrays[128], 4, 3), UPB_STRTABLE_INIT(3, 3, UPB_CTYPE_PTR, 2, &strentries[148]), false, UPB_SYNTAX_PROTO2, &reftables[32], &reftables[33]),
+  UPB_MSGDEF_INIT("google.protobuf.ServiceOptions", 8, 1, UPB_INTTABLE_INIT(2, 3, UPB_CTYPE_PTR, 2, &intentries[14], &arrays[132], 1, 0), UPB_STRTABLE_INIT(2, 3, UPB_CTYPE_PTR, 2, &strentries[152]), false, UPB_SYNTAX_PROTO2, &reftables[34], &reftables[35]),
+  UPB_MSGDEF_INIT("google.protobuf.SourceCodeInfo", 7, 1, UPB_INTTABLE_INIT(0, 0, UPB_CTYPE_PTR, 0, NULL, &arrays[133], 2, 1), UPB_STRTABLE_INIT(1, 3, UPB_CTYPE_PTR, 2, &strentries[156]), false, UPB_SYNTAX_PROTO2, &reftables[36], &reftables[37]),
+  UPB_MSGDEF_INIT("google.protobuf.SourceCodeInfo.Location", 20, 0, UPB_INTTABLE_INIT(0, 0, UPB_CTYPE_PTR, 0, NULL, &arrays[135], 7, 5), UPB_STRTABLE_INIT(5, 7, UPB_CTYPE_PTR, 3, &strentries[160]), false, UPB_SYNTAX_PROTO2, &reftables[38], &reftables[39]),
+  UPB_MSGDEF_INIT("google.protobuf.UninterpretedOption", 19, 1, UPB_INTTABLE_INIT(0, 0, UPB_CTYPE_PTR, 0, NULL, &arrays[142], 9, 7), UPB_STRTABLE_INIT(7, 15, UPB_CTYPE_PTR, 4, &strentries[168]), false, UPB_SYNTAX_PROTO2, &reftables[40], &reftables[41]),
+  UPB_MSGDEF_INIT("google.protobuf.UninterpretedOption.NamePart", 7, 0, UPB_INTTABLE_INIT(0, 0, UPB_CTYPE_PTR, 0, NULL, &arrays[151], 3, 2), UPB_STRTABLE_INIT(2, 3, UPB_CTYPE_PTR, 2, &strentries[184]), false, UPB_SYNTAX_PROTO2, &reftables[42], &reftables[43]),
+};
+
+static const upb_fielddef fields[107] = {
+  UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, false, false, false, "aggregate_value", 8, &msgs[20], NULL, 16, 6, {0},&reftables[44], &reftables[45]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BOOL, 0, false, false, false, false, "allow_alias", 2, &msgs[4], NULL, 7, 1, {0},&reftables[46], &reftables[47]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BOOL, 0, false, false, false, false, "cc_enable_arenas", 31, &msgs[11], NULL, 24, 12, {0},&reftables[48], &reftables[49]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BOOL, 0, false, false, false, false, "cc_generic_services", 16, &msgs[11], NULL, 18, 6, {0},&reftables[50], &reftables[51]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BOOL, 0, false, false, false, false, "client_streaming", 5, &msgs[13], NULL, 14, 4, {0},&reftables[52], &reftables[53]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, false, false, false, "csharp_namespace", 37, &msgs[11], NULL, 28, 14, {0},&reftables[54], &reftables[55]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_ENUM, 0, false, false, false, false, "ctype", 1, &msgs[8], (const upb_def*)(&enums[2]), 7, 1, {0},&reftables[56], &reftables[57]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, false, false, false, "default_value", 7, &msgs[7], NULL, 17, 7, {0},&reftables[58], &reftables[59]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_STRING, 0, false, false, false, false, "dependency", 3, &msgs[9], NULL, 31, 8, {0},&reftables[60], &reftables[61]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BOOL, 0, false, false, false, false, "deprecated", 3, &msgs[8], NULL, 9, 3, {0},&reftables[62], &reftables[63]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BOOL, 0, false, false, false, false, "deprecated", 33, &msgs[14], NULL, 7, 1, {0},&reftables[64], &reftables[65]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BOOL, 0, false, false, false, false, "deprecated", 3, &msgs[12], NULL, 9, 3, {0},&reftables[66], &reftables[67]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BOOL, 0, false, false, false, false, "deprecated", 23, &msgs[11], NULL, 22, 10, {0},&reftables[68], &reftables[69]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BOOL, 0, false, false, false, false, "deprecated", 1, &msgs[6], NULL, 7, 1, {0},&reftables[70], &reftables[71]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BOOL, 0, false, false, false, false, "deprecated", 3, &msgs[4], NULL, 8, 2, {0},&reftables[72], &reftables[73]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BOOL, 0, false, false, false, false, "deprecated", 33, &msgs[17], NULL, 7, 1, {0},&reftables[74], &reftables[75]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_DOUBLE, 0, false, false, false, false, "double_value", 6, &msgs[20], NULL, 12, 4, {0},&reftables[76], &reftables[77]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_INT32, UPB_INTFMT_VARIABLE, false, false, false, false, "end", 2, &msgs[2], NULL, 4, 1, {0},&reftables[78], &reftables[79]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_INT32, UPB_INTFMT_VARIABLE, false, false, false, false, "end", 2, &msgs[1], NULL, 4, 1, {0},&reftables[80], &reftables[81]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, false, false, false, "enum_type", 5, &msgs[9], (const upb_def*)(&msgs[3]), 14, 1, {0},&reftables[82], &reftables[83]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, false, false, false, "enum_type", 4, &msgs[0], (const upb_def*)(&msgs[3]), 19, 2, {0},&reftables[84], &reftables[85]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, false, false, false, "extendee", 2, &msgs[7], NULL, 8, 2, {0},&reftables[86], &reftables[87]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, false, false, false, "extension", 6, &msgs[0], (const upb_def*)(&msgs[7]), 25, 4, {0},&reftables[88], &reftables[89]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, false, false, false, "extension", 7, &msgs[9], (const upb_def*)(&msgs[7]), 20, 3, {0},&reftables[90], &reftables[91]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, false, false, false, "extension_range", 5, &msgs[0], (const upb_def*)(&msgs[1]), 22, 3, {0},&reftables[92], &reftables[93]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, false, false, false, "field", 2, &msgs[0], (const upb_def*)(&msgs[7]), 13, 0, {0},&reftables[94], &reftables[95]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, false, false, false, "file", 1, &msgs[10], (const upb_def*)(&msgs[9]), 6, 0, {0},&reftables[96], &reftables[97]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, false, false, false, "go_package", 11, &msgs[11], NULL, 15, 5, {0},&reftables[98], &reftables[99]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, false, false, false, "identifier_value", 3, &msgs[20], NULL, 7, 1, {0},&reftables[100], &reftables[101]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, false, false, false, "input_type", 2, &msgs[13], NULL, 8, 2, {0},&reftables[102], &reftables[103]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_REQUIRED, UPB_TYPE_BOOL, 0, false, false, false, false, "is_extension", 2, &msgs[21], NULL, 6, 1, {0},&reftables[104], &reftables[105]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BOOL, 0, false, false, false, false, "java_generate_equals_and_hash", 20, &msgs[11], NULL, 21, 9, {0},&reftables[106], &reftables[107]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BOOL, 0, false, false, false, false, "java_generic_services", 17, &msgs[11], NULL, 19, 7, {0},&reftables[108], &reftables[109]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BOOL, 0, false, false, false, false, "java_multiple_files", 10, &msgs[11], NULL, 14, 4, {0},&reftables[110], &reftables[111]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, false, false, false, "java_outer_classname", 8, &msgs[11], NULL, 10, 2, {0},&reftables[112], &reftables[113]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, false, false, false, "java_package", 1, &msgs[11], NULL, 7, 1, {0},&reftables[114], &reftables[115]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BOOL, 0, false, false, false, false, "java_string_check_utf8", 27, &msgs[11], NULL, 23, 11, {0},&reftables[116], &reftables[117]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BOOL, 0, false, false, false, false, "javanano_use_deprecated_package", 38, &msgs[11], NULL, 31, 15, {0},&reftables[118], &reftables[119]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, false, false, false, "json_name", 10, &msgs[7], NULL, 21, 9, {0},&reftables[120], &reftables[121]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_ENUM, 0, false, false, false, false, "jstype", 6, &msgs[8], (const upb_def*)(&enums[3]), 11, 5, {0},&reftables[122], &reftables[123]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_ENUM, 0, false, false, false, false, "label", 4, &msgs[7], (const upb_def*)(&enums[0]), 12, 4, {0},&reftables[124], &reftables[125]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BOOL, 0, false, false, false, false, "lazy", 5, &msgs[8], NULL, 10, 4, {0},&reftables[126], &reftables[127]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, false, false, false, "leading_comments", 3, &msgs[19], NULL, 9, 2, {0},&reftables[128], &reftables[129]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_STRING, 0, false, false, false, false, "leading_detached_comments", 6, &msgs[19], NULL, 17, 4, {0},&reftables[130], &reftables[131]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, false, false, false, "location", 1, &msgs[18], (const upb_def*)(&msgs[19]), 6, 0, {0},&reftables[132], &reftables[133]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BOOL, 0, false, false, false, false, "map_entry", 7, &msgs[12], NULL, 10, 4, {0},&reftables[134], &reftables[135]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BOOL, 0, false, false, false, false, "message_set_wire_format", 1, &msgs[12], NULL, 7, 1, {0},&reftables[136], &reftables[137]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, false, false, false, "message_type", 4, &msgs[9], (const upb_def*)(&msgs[0]), 11, 0, {0},&reftables[138], &reftables[139]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, false, false, false, "method", 2, &msgs[16], (const upb_def*)(&msgs[13]), 7, 0, {0},&reftables[140], &reftables[141]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, false, false, false, "name", 2, &msgs[20], (const upb_def*)(&msgs[21]), 6, 0, {0},&reftables[142], &reftables[143]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, false, false, false, "name", 1, &msgs[5], NULL, 5, 1, {0},&reftables[144], &reftables[145]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, false, false, false, "name", 1, &msgs[9], NULL, 23, 6, {0},&reftables[146], &reftables[147]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, false, false, false, "name", 1, &msgs[3], NULL, 9, 2, {0},&reftables[148], &reftables[149]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, false, false, false, "name", 1, &msgs[16], NULL, 9, 2, {0},&reftables[150], &reftables[151]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, false, false, false, "name", 1, &msgs[15], NULL, 3, 0, {0},&reftables[152], &reftables[153]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, false, false, false, "name", 1, &msgs[13], NULL, 5, 1, {0},&reftables[154], &reftables[155]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, false, false, false, "name", 1, &msgs[7], NULL, 5, 1, {0},&reftables[156], &reftables[157]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, false, false, false, "name", 1, &msgs[0], NULL, 33, 8, {0},&reftables[158], &reftables[159]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_REQUIRED, UPB_TYPE_STRING, 0, false, false, false, false, "name_part", 1, &msgs[21], NULL, 3, 0, {0},&reftables[160], &reftables[161]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_INT64, UPB_INTFMT_VARIABLE, false, false, false, false, "negative_int_value", 5, &msgs[20], NULL, 11, 3, {0},&reftables[162], &reftables[163]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, false, false, false, "nested_type", 3, &msgs[0], (const upb_def*)(&msgs[0]), 16, 1, {0},&reftables[164], &reftables[165]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BOOL, 0, false, false, false, false, "no_standard_descriptor_accessor", 2, &msgs[12], NULL, 8, 2, {0},&reftables[166], &reftables[167]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_INT32, UPB_INTFMT_VARIABLE, false, false, false, false, "number", 3, &msgs[7], NULL, 11, 3, {0},&reftables[168], &reftables[169]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_INT32, UPB_INTFMT_VARIABLE, false, false, false, false, "number", 2, &msgs[5], NULL, 8, 2, {0},&reftables[170], &reftables[171]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, false, false, false, "objc_class_prefix", 36, &msgs[11], NULL, 25, 13, {0},&reftables[172], &reftables[173]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, false, false, false, "oneof_decl", 8, &msgs[0], (const upb_def*)(&msgs[15]), 29, 6, {0},&reftables[174], &reftables[175]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_INT32, UPB_INTFMT_VARIABLE, false, false, false, false, "oneof_index", 9, &msgs[7], NULL, 20, 8, {0},&reftables[176], &reftables[177]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_ENUM, 0, false, false, false, false, "optimize_for", 9, &msgs[11], (const upb_def*)(&enums[4]), 13, 3, {0},&reftables[178], &reftables[179]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_MESSAGE, 0, false, false, false, false, "options", 7, &msgs[0], (const upb_def*)(&msgs[12]), 26, 5, {0},&reftables[180], &reftables[181]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_MESSAGE, 0, false, false, false, false, "options", 8, &msgs[9], (const upb_def*)(&msgs[11]), 21, 4, {0},&reftables[182], &reftables[183]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_MESSAGE, 0, false, false, false, false, "options", 8, &msgs[7], (const upb_def*)(&msgs[8]), 4, 0, {0},&reftables[184], &reftables[185]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_MESSAGE, 0, false, false, false, false, "options", 4, &msgs[13], (const upb_def*)(&msgs[14]), 4, 0, {0},&reftables[186], &reftables[187]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_MESSAGE, 0, false, false, false, false, "options", 3, &msgs[16], (const upb_def*)(&msgs[17]), 8, 1, {0},&reftables[188], &reftables[189]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_MESSAGE, 0, false, false, false, false, "options", 3, &msgs[3], (const upb_def*)(&msgs[4]), 8, 1, {0},&reftables[190], &reftables[191]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_MESSAGE, 0, false, false, false, false, "options", 3, &msgs[5], (const upb_def*)(&msgs[6]), 4, 0, {0},&reftables[192], &reftables[193]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, false, false, false, "output_type", 3, &msgs[13], NULL, 11, 3, {0},&reftables[194], &reftables[195]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, false, false, false, "package", 2, &msgs[9], NULL, 26, 7, {0},&reftables[196], &reftables[197]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BOOL, 0, false, false, false, false, "packed", 2, &msgs[8], NULL, 8, 2, {0},&reftables[198], &reftables[199]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_INT32, UPB_INTFMT_VARIABLE, false, false, false, true, "path", 1, &msgs[19], NULL, 5, 0, {0},&reftables[200], &reftables[201]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, false, false, false, "php_class_prefix", 40, &msgs[11], NULL, 32, 16, {0},&reftables[202], &reftables[203]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, false, false, false, "php_namespace", 41, &msgs[11], NULL, 35, 17, {0},&reftables[204], &reftables[205]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_UINT64, UPB_INTFMT_VARIABLE, false, false, false, false, "positive_int_value", 4, &msgs[20], NULL, 10, 2, {0},&reftables[206], &reftables[207]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_INT32, UPB_INTFMT_VARIABLE, false, false, false, false, "public_dependency", 10, &msgs[9], NULL, 36, 9, {0},&reftables[208], &reftables[209]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BOOL, 0, false, false, false, false, "py_generic_services", 18, &msgs[11], NULL, 20, 8, {0},&reftables[210], &reftables[211]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_STRING, 0, false, false, false, false, "reserved_name", 10, &msgs[0], NULL, 38, 9, {0},&reftables[212], &reftables[213]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, false, false, false, "reserved_range", 9, &msgs[0], (const upb_def*)(&msgs[2]), 32, 7, {0},&reftables[214], &reftables[215]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BOOL, 0, false, false, false, false, "server_streaming", 6, &msgs[13], NULL, 15, 5, {0},&reftables[216], &reftables[217]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, false, false, false, "service", 6, &msgs[9], (const upb_def*)(&msgs[16]), 17, 2, {0},&reftables[218], &reftables[219]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_MESSAGE, 0, false, false, false, false, "source_code_info", 9, &msgs[9], (const upb_def*)(&msgs[18]), 22, 5, {0},&reftables[220], &reftables[221]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_INT32, UPB_INTFMT_VARIABLE, false, false, false, true, "span", 2, &msgs[19], NULL, 8, 1, {0},&reftables[222], &reftables[223]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_INT32, UPB_INTFMT_VARIABLE, false, false, false, false, "start", 1, &msgs[2], NULL, 3, 0, {0},&reftables[224], &reftables[225]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_INT32, UPB_INTFMT_VARIABLE, false, false, false, false, "start", 1, &msgs[1], NULL, 3, 0, {0},&reftables[226], &reftables[227]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BYTES, 0, false, false, false, false, "string_value", 7, &msgs[20], NULL, 13, 5, {0},&reftables[228], &reftables[229]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, false, false, false, "syntax", 12, &msgs[9], NULL, 40, 11, {0},&reftables[230], &reftables[231]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, false, false, false, "trailing_comments", 4, &msgs[19], NULL, 12, 3, {0},&reftables[232], &reftables[233]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_ENUM, 0, false, false, false, false, "type", 5, &msgs[7], (const upb_def*)(&enums[1]), 13, 5, {0},&reftables[234], &reftables[235]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, false, false, false, "type_name", 6, &msgs[7], NULL, 14, 6, {0},&reftables[236], &reftables[237]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, false, false, false, "uninterpreted_option", 999, &msgs[12], (const upb_def*)(&msgs[20]), 6, 0, {0},&reftables[238], &reftables[239]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, false, false, false, "uninterpreted_option", 999, &msgs[17], (const upb_def*)(&msgs[20]), 6, 0, {0},&reftables[240], &reftables[241]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, false, false, false, "uninterpreted_option", 999, &msgs[11], (const upb_def*)(&msgs[20]), 6, 0, {0},&reftables[242], &reftables[243]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, false, false, false, "uninterpreted_option", 999, &msgs[14], (const upb_def*)(&msgs[20]), 6, 0, {0},&reftables[244], &reftables[245]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, false, false, false, "uninterpreted_option", 999, &msgs[8], (const upb_def*)(&msgs[20]), 6, 0, {0},&reftables[246], &reftables[247]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, false, false, false, "uninterpreted_option", 999, &msgs[6], (const upb_def*)(&msgs[20]), 6, 0, {0},&reftables[248], &reftables[249]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, false, false, false, "uninterpreted_option", 999, &msgs[4], (const upb_def*)(&msgs[20]), 6, 0, {0},&reftables[250], &reftables[251]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, false, false, false, "value", 2, &msgs[3], (const upb_def*)(&msgs[5]), 7, 0, {0},&reftables[252], &reftables[253]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BOOL, 0, false, false, false, false, "weak", 10, &msgs[8], NULL, 12, 6, {0},&reftables[254], &reftables[255]),
+  UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_INT32, UPB_INTFMT_VARIABLE, false, false, false, false, "weak_dependency", 11, &msgs[9], NULL, 39, 10, {0},&reftables[256], &reftables[257]),
+};
+
+static const upb_enumdef enums[5] = {
+  UPB_ENUMDEF_INIT("google.protobuf.FieldDescriptorProto.Label", UPB_STRTABLE_INIT(3, 3, UPB_CTYPE_INT32, 2, &strentries[188]), UPB_INTTABLE_INIT(0, 0, UPB_CTYPE_CSTR, 0, NULL, &arrays[154], 4, 3), 0, &reftables[258], &reftables[259]),
+  UPB_ENUMDEF_INIT("google.protobuf.FieldDescriptorProto.Type", UPB_STRTABLE_INIT(18, 31, UPB_CTYPE_INT32, 5, &strentries[192]), UPB_INTTABLE_INIT(0, 0, UPB_CTYPE_CSTR, 0, NULL, &arrays[158], 19, 18), 0, &reftables[260], &reftables[261]),
+  UPB_ENUMDEF_INIT("google.protobuf.FieldOptions.CType", UPB_STRTABLE_INIT(3, 3, UPB_CTYPE_INT32, 2, &strentries[224]), UPB_INTTABLE_INIT(0, 0, UPB_CTYPE_CSTR, 0, NULL, &arrays[177], 3, 3), 0, &reftables[262], &reftables[263]),
+  UPB_ENUMDEF_INIT("google.protobuf.FieldOptions.JSType", UPB_STRTABLE_INIT(3, 3, UPB_CTYPE_INT32, 2, &strentries[228]), UPB_INTTABLE_INIT(0, 0, UPB_CTYPE_CSTR, 0, NULL, &arrays[180], 3, 3), 0, &reftables[264], &reftables[265]),
+  UPB_ENUMDEF_INIT("google.protobuf.FileOptions.OptimizeMode", UPB_STRTABLE_INIT(3, 3, UPB_CTYPE_INT32, 2, &strentries[232]), UPB_INTTABLE_INIT(0, 0, UPB_CTYPE_CSTR, 0, NULL, &arrays[183], 4, 3), 0, &reftables[266], &reftables[267]),
+};
+
+static const upb_tabent strentries[236] = {
+  {UPB_TABKEY_STR("\011", "\000", "\000", "\000", "extension"), UPB_TABVALUE_PTR_INIT(&fields[22]), NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_STR("\015", "\000", "\000", "\000", "reserved_name"), UPB_TABVALUE_PTR_INIT(&fields[84]), NULL},
+  {UPB_TABKEY_STR("\004", "\000", "\000", "\000", "name"), UPB_TABVALUE_PTR_INIT(&fields[57]), NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_STR("\005", "\000", "\000", "\000", "field"), UPB_TABVALUE_PTR_INIT(&fields[25]), &strentries[12]},
+  {UPB_TABKEY_STR("\017", "\000", "\000", "\000", "extension_range"), UPB_TABVALUE_PTR_INIT(&fields[24]), &strentries[14]},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_STR("\013", "\000", "\000", "\000", "nested_type"), UPB_TABVALUE_PTR_INIT(&fields[60]), NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_STR("\016", "\000", "\000", "\000", "reserved_range"), UPB_TABVALUE_PTR_INIT(&fields[85]), NULL},
+  {UPB_TABKEY_STR("\007", "\000", "\000", "\000", "options"), UPB_TABVALUE_PTR_INIT(&fields[68]), NULL},
+  {UPB_TABKEY_STR("\012", "\000", "\000", "\000", "oneof_decl"), UPB_TABVALUE_PTR_INIT(&fields[65]), NULL},
+  {UPB_TABKEY_STR("\011", "\000", "\000", "\000", "enum_type"), UPB_TABVALUE_PTR_INIT(&fields[20]), &strentries[13]},
+  {UPB_TABKEY_STR("\005", "\000", "\000", "\000", "start"), UPB_TABVALUE_PTR_INIT(&fields[91]), NULL},
+  {UPB_TABKEY_STR("\003", "\000", "\000", "\000", "end"), UPB_TABVALUE_PTR_INIT(&fields[18]), NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_STR("\005", "\000", "\000", "\000", "start"), UPB_TABVALUE_PTR_INIT(&fields[90]), NULL},
+  {UPB_TABKEY_STR("\003", "\000", "\000", "\000", "end"), UPB_TABVALUE_PTR_INIT(&fields[17]), NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_STR("\005", "\000", "\000", "\000", "value"), UPB_TABVALUE_PTR_INIT(&fields[104]), NULL},
+  {UPB_TABKEY_STR("\007", "\000", "\000", "\000", "options"), UPB_TABVALUE_PTR_INIT(&fields[73]), NULL},
+  {UPB_TABKEY_STR("\004", "\000", "\000", "\000", "name"), UPB_TABVALUE_PTR_INIT(&fields[52]), &strentries[26]},
+  {UPB_TABKEY_STR("\024", "\000", "\000", "\000", "uninterpreted_option"), UPB_TABVALUE_PTR_INIT(&fields[103]), NULL},
+  {UPB_TABKEY_STR("\012", "\000", "\000", "\000", "deprecated"), UPB_TABVALUE_PTR_INIT(&fields[14]), NULL},
+  {UPB_TABKEY_STR("\013", "\000", "\000", "\000", "allow_alias"), UPB_TABVALUE_PTR_INIT(&fields[1]), NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_STR("\006", "\000", "\000", "\000", "number"), UPB_TABVALUE_PTR_INIT(&fields[63]), NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_STR("\007", "\000", "\000", "\000", "options"), UPB_TABVALUE_PTR_INIT(&fields[74]), NULL},
+  {UPB_TABKEY_STR("\004", "\000", "\000", "\000", "name"), UPB_TABVALUE_PTR_INIT(&fields[50]), &strentries[34]},
+  {UPB_TABKEY_STR("\024", "\000", "\000", "\000", "uninterpreted_option"), UPB_TABVALUE_PTR_INIT(&fields[102]), NULL},
+  {UPB_TABKEY_STR("\012", "\000", "\000", "\000", "deprecated"), UPB_TABVALUE_PTR_INIT(&fields[13]), NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_STR("\013", "\000", "\000", "\000", "oneof_index"), UPB_TABVALUE_PTR_INIT(&fields[66]), NULL},
+  {UPB_TABKEY_STR("\005", "\000", "\000", "\000", "label"), UPB_TABVALUE_PTR_INIT(&fields[40]), NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_STR("\004", "\000", "\000", "\000", "name"), UPB_TABVALUE_PTR_INIT(&fields[56]), NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_STR("\006", "\000", "\000", "\000", "number"), UPB_TABVALUE_PTR_INIT(&fields[62]), &strentries[53]},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_STR("\010", "\000", "\000", "\000", "extendee"), UPB_TABVALUE_PTR_INIT(&fields[21]), NULL},
+  {UPB_TABKEY_STR("\011", "\000", "\000", "\000", "type_name"), UPB_TABVALUE_PTR_INIT(&fields[96]), NULL},
+  {UPB_TABKEY_STR("\011", "\000", "\000", "\000", "json_name"), UPB_TABVALUE_PTR_INIT(&fields[38]), NULL},
+  {UPB_TABKEY_STR("\004", "\000", "\000", "\000", "type"), UPB_TABVALUE_PTR_INIT(&fields[95]), &strentries[50]},
+  {UPB_TABKEY_STR("\015", "\000", "\000", "\000", "default_value"), UPB_TABVALUE_PTR_INIT(&fields[7]), NULL},
+  {UPB_TABKEY_STR("\007", "\000", "\000", "\000", "options"), UPB_TABVALUE_PTR_INIT(&fields[70]), NULL},
+  {UPB_TABKEY_STR("\024", "\000", "\000", "\000", "uninterpreted_option"), UPB_TABVALUE_PTR_INIT(&fields[101]), NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_STR("\004", "\000", "\000", "\000", "weak"), UPB_TABVALUE_PTR_INIT(&fields[105]), NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_STR("\006", "\000", "\000", "\000", "packed"), UPB_TABVALUE_PTR_INIT(&fields[77]), NULL},
+  {UPB_TABKEY_STR("\004", "\000", "\000", "\000", "lazy"), UPB_TABVALUE_PTR_INIT(&fields[41]), NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_STR("\005", "\000", "\000", "\000", "ctype"), UPB_TABVALUE_PTR_INIT(&fields[6]), NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_STR("\006", "\000", "\000", "\000", "jstype"), UPB_TABVALUE_PTR_INIT(&fields[39]), NULL},
+  {UPB_TABKEY_STR("\012", "\000", "\000", "\000", "deprecated"), UPB_TABVALUE_PTR_INIT(&fields[9]), NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_STR("\011", "\000", "\000", "\000", "extension"), UPB_TABVALUE_PTR_INIT(&fields[23]), NULL},
+  {UPB_TABKEY_STR("\017", "\000", "\000", "\000", "weak_dependency"), UPB_TABVALUE_PTR_INIT(&fields[106]), NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_STR("\004", "\000", "\000", "\000", "name"), UPB_TABVALUE_PTR_INIT(&fields[51]), NULL},
+  {UPB_TABKEY_STR("\007", "\000", "\000", "\000", "service"), UPB_TABVALUE_PTR_INIT(&fields[87]), NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_STR("\020", "\000", "\000", "\000", "source_code_info"), UPB_TABVALUE_PTR_INIT(&fields[88]), NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_STR("\006", "\000", "\000", "\000", "syntax"), UPB_TABVALUE_PTR_INIT(&fields[93]), NULL},
+  {UPB_TABKEY_STR("\012", "\000", "\000", "\000", "dependency"), UPB_TABVALUE_PTR_INIT(&fields[8]), NULL},
+  {UPB_TABKEY_STR("\014", "\000", "\000", "\000", "message_type"), UPB_TABVALUE_PTR_INIT(&fields[47]), NULL},
+  {UPB_TABKEY_STR("\007", "\000", "\000", "\000", "package"), UPB_TABVALUE_PTR_INIT(&fields[76]), NULL},
+  {UPB_TABKEY_STR("\007", "\000", "\000", "\000", "options"), UPB_TABVALUE_PTR_INIT(&fields[69]), &strentries[86]},
+  {UPB_TABKEY_STR("\011", "\000", "\000", "\000", "enum_type"), UPB_TABVALUE_PTR_INIT(&fields[19]), NULL},
+  {UPB_TABKEY_STR("\021", "\000", "\000", "\000", "public_dependency"), UPB_TABVALUE_PTR_INIT(&fields[82]), &strentries[85]},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_STR("\004", "\000", "\000", "\000", "file"), UPB_TABVALUE_PTR_INIT(&fields[26]), NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_STR("\023", "\000", "\000", "\000", "cc_generic_services"), UPB_TABVALUE_PTR_INIT(&fields[3]), NULL},
+  {UPB_TABKEY_STR("\020", "\000", "\000", "\000", "csharp_namespace"), UPB_TABVALUE_PTR_INIT(&fields[5]), &strentries[116]},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_STR("\012", "\000", "\000", "\000", "go_package"), UPB_TABVALUE_PTR_INIT(&fields[27]), NULL},
+  {UPB_TABKEY_STR("\014", "\000", "\000", "\000", "java_package"), UPB_TABVALUE_PTR_INIT(&fields[35]), &strentries[120]},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_STR("\024", "\000", "\000", "\000", "java_outer_classname"), UPB_TABVALUE_PTR_INIT(&fields[34]), NULL},
+  {UPB_TABKEY_STR("\015", "\000", "\000", "\000", "php_namespace"), UPB_TABVALUE_PTR_INIT(&fields[80]), &strentries[113]},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_STR("\023", "\000", "\000", "\000", "java_multiple_files"), UPB_TABVALUE_PTR_INIT(&fields[33]), &strentries[117]},
+  {UPB_TABKEY_STR("\024", "\000", "\000", "\000", "uninterpreted_option"), UPB_TABVALUE_PTR_INIT(&fields[99]), NULL},
+  {UPB_TABKEY_STR("\025", "\000", "\000", "\000", "java_generic_services"), UPB_TABVALUE_PTR_INIT(&fields[32]), &strentries[118]},
+  {UPB_TABKEY_STR("\035", "\000", "\000", "\000", "java_generate_equals_and_hash"), UPB_TABVALUE_PTR_INIT(&fields[31]), NULL},
+  {UPB_TABKEY_STR("\020", "\000", "\000", "\000", "php_class_prefix"), UPB_TABVALUE_PTR_INIT(&fields[79]), NULL},
+  {UPB_TABKEY_STR("\037", "\000", "\000", "\000", "javanano_use_deprecated_package"), UPB_TABVALUE_PTR_INIT(&fields[37]), &strentries[123]},
+  {UPB_TABKEY_STR("\023", "\000", "\000", "\000", "py_generic_services"), UPB_TABVALUE_PTR_INIT(&fields[83]), NULL},
+  {UPB_TABKEY_STR("\014", "\000", "\000", "\000", "optimize_for"), UPB_TABVALUE_PTR_INIT(&fields[67]), NULL},
+  {UPB_TABKEY_STR("\026", "\000", "\000", "\000", "java_string_check_utf8"), UPB_TABVALUE_PTR_INIT(&fields[36]), NULL},
+  {UPB_TABKEY_STR("\012", "\000", "\000", "\000", "deprecated"), UPB_TABVALUE_PTR_INIT(&fields[12]), &strentries[119]},
+  {UPB_TABKEY_STR("\021", "\000", "\000", "\000", "objc_class_prefix"), UPB_TABVALUE_PTR_INIT(&fields[64]), NULL},
+  {UPB_TABKEY_STR("\020", "\000", "\000", "\000", "cc_enable_arenas"), UPB_TABVALUE_PTR_INIT(&fields[2]), NULL},
+  {UPB_TABKEY_STR("\027", "\000", "\000", "\000", "message_set_wire_format"), UPB_TABVALUE_PTR_INIT(&fields[46]), &strentries[128]},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_STR("\024", "\000", "\000", "\000", "uninterpreted_option"), UPB_TABVALUE_PTR_INIT(&fields[97]), NULL},
+  {UPB_TABKEY_STR("\012", "\000", "\000", "\000", "deprecated"), UPB_TABVALUE_PTR_INIT(&fields[11]), NULL},
+  {UPB_TABKEY_STR("\011", "\000", "\000", "\000", "map_entry"), UPB_TABVALUE_PTR_INIT(&fields[45]), NULL},
+  {UPB_TABKEY_STR("\037", "\000", "\000", "\000", "no_standard_descriptor_accessor"), UPB_TABVALUE_PTR_INIT(&fields[61]), NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_STR("\020", "\000", "\000", "\000", "client_streaming"), UPB_TABVALUE_PTR_INIT(&fields[4]), NULL},
+  {UPB_TABKEY_STR("\020", "\000", "\000", "\000", "server_streaming"), UPB_TABVALUE_PTR_INIT(&fields[86]), NULL},
+  {UPB_TABKEY_STR("\004", "\000", "\000", "\000", "name"), UPB_TABVALUE_PTR_INIT(&fields[55]), NULL},
+  {UPB_TABKEY_STR("\012", "\000", "\000", "\000", "input_type"), UPB_TABVALUE_PTR_INIT(&fields[29]), NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_STR("\013", "\000", "\000", "\000", "output_type"), UPB_TABVALUE_PTR_INIT(&fields[75]), NULL},
+  {UPB_TABKEY_STR("\007", "\000", "\000", "\000", "options"), UPB_TABVALUE_PTR_INIT(&fields[71]), NULL},
+  {UPB_TABKEY_STR("\024", "\000", "\000", "\000", "uninterpreted_option"), UPB_TABVALUE_PTR_INIT(&fields[100]), NULL},
+  {UPB_TABKEY_STR("\012", "\000", "\000", "\000", "deprecated"), UPB_TABVALUE_PTR_INIT(&fields[10]), NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_STR("\004", "\000", "\000", "\000", "name"), UPB_TABVALUE_PTR_INIT(&fields[54]), NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_STR("\007", "\000", "\000", "\000", "options"), UPB_TABVALUE_PTR_INIT(&fields[72]), &strentries[150]},
+  {UPB_TABKEY_STR("\006", "\000", "\000", "\000", "method"), UPB_TABVALUE_PTR_INIT(&fields[48]), NULL},
+  {UPB_TABKEY_STR("\004", "\000", "\000", "\000", "name"), UPB_TABVALUE_PTR_INIT(&fields[53]), &strentries[149]},
+  {UPB_TABKEY_STR("\024", "\000", "\000", "\000", "uninterpreted_option"), UPB_TABVALUE_PTR_INIT(&fields[98]), NULL},
+  {UPB_TABKEY_STR("\012", "\000", "\000", "\000", "deprecated"), UPB_TABVALUE_PTR_INIT(&fields[15]), NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_STR("\010", "\000", "\000", "\000", "location"), UPB_TABVALUE_PTR_INIT(&fields[44]), NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_STR("\004", "\000", "\000", "\000", "span"), UPB_TABVALUE_PTR_INIT(&fields[89]), &strentries[167]},
+  {UPB_TABKEY_STR("\031", "\000", "\000", "\000", "leading_detached_comments"), UPB_TABVALUE_PTR_INIT(&fields[43]), &strentries[165]},
+  {UPB_TABKEY_STR("\021", "\000", "\000", "\000", "trailing_comments"), UPB_TABVALUE_PTR_INIT(&fields[94]), NULL},
+  {UPB_TABKEY_STR("\020", "\000", "\000", "\000", "leading_comments"), UPB_TABVALUE_PTR_INIT(&fields[42]), &strentries[164]},
+  {UPB_TABKEY_STR("\004", "\000", "\000", "\000", "path"), UPB_TABVALUE_PTR_INIT(&fields[78]), NULL},
+  {UPB_TABKEY_STR("\014", "\000", "\000", "\000", "double_value"), UPB_TABVALUE_PTR_INIT(&fields[16]), NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_STR("\004", "\000", "\000", "\000", "name"), UPB_TABVALUE_PTR_INIT(&fields[49]), NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_STR("\022", "\000", "\000", "\000", "negative_int_value"), UPB_TABVALUE_PTR_INIT(&fields[59]), NULL},
+  {UPB_TABKEY_STR("\017", "\000", "\000", "\000", "aggregate_value"), UPB_TABVALUE_PTR_INIT(&fields[0]), NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_STR("\022", "\000", "\000", "\000", "positive_int_value"), UPB_TABVALUE_PTR_INIT(&fields[81]), NULL},
+  {UPB_TABKEY_STR("\020", "\000", "\000", "\000", "identifier_value"), UPB_TABVALUE_PTR_INIT(&fields[28]), NULL},
+  {UPB_TABKEY_STR("\014", "\000", "\000", "\000", "string_value"), UPB_TABVALUE_PTR_INIT(&fields[92]), &strentries[182]},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_STR("\014", "\000", "\000", "\000", "is_extension"), UPB_TABVALUE_PTR_INIT(&fields[30]), NULL},
+  {UPB_TABKEY_STR("\011", "\000", "\000", "\000", "name_part"), UPB_TABVALUE_PTR_INIT(&fields[58]), NULL},
+  {UPB_TABKEY_STR("\016", "\000", "\000", "\000", "LABEL_REQUIRED"), UPB_TABVALUE_INT_INIT(2), &strentries[190]},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_STR("\016", "\000", "\000", "\000", "LABEL_REPEATED"), UPB_TABVALUE_INT_INIT(3), NULL},
+  {UPB_TABKEY_STR("\016", "\000", "\000", "\000", "LABEL_OPTIONAL"), UPB_TABVALUE_INT_INIT(1), NULL},
+  {UPB_TABKEY_STR("\014", "\000", "\000", "\000", "TYPE_FIXED64"), UPB_TABVALUE_INT_INIT(6), NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_STR("\013", "\000", "\000", "\000", "TYPE_STRING"), UPB_TABVALUE_INT_INIT(9), NULL},
+  {UPB_TABKEY_STR("\012", "\000", "\000", "\000", "TYPE_FLOAT"), UPB_TABVALUE_INT_INIT(2), &strentries[221]},
+  {UPB_TABKEY_STR("\013", "\000", "\000", "\000", "TYPE_DOUBLE"), UPB_TABVALUE_INT_INIT(1), NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_STR("\012", "\000", "\000", "\000", "TYPE_INT32"), UPB_TABVALUE_INT_INIT(5), NULL},
+  {UPB_TABKEY_STR("\015", "\000", "\000", "\000", "TYPE_SFIXED32"), UPB_TABVALUE_INT_INIT(15), NULL},
+  {UPB_TABKEY_STR("\014", "\000", "\000", "\000", "TYPE_FIXED32"), UPB_TABVALUE_INT_INIT(7), NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_STR("\014", "\000", "\000", "\000", "TYPE_MESSAGE"), UPB_TABVALUE_INT_INIT(11), &strentries[222]},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_STR("\012", "\000", "\000", "\000", "TYPE_INT64"), UPB_TABVALUE_INT_INIT(3), &strentries[219]},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_STR("\011", "\000", "\000", "\000", "TYPE_ENUM"), UPB_TABVALUE_INT_INIT(14), NULL},
+  {UPB_TABKEY_STR("\013", "\000", "\000", "\000", "TYPE_UINT32"), UPB_TABVALUE_INT_INIT(13), NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_STR("\013", "\000", "\000", "\000", "TYPE_UINT64"), UPB_TABVALUE_INT_INIT(4), &strentries[218]},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_STR("\015", "\000", "\000", "\000", "TYPE_SFIXED64"), UPB_TABVALUE_INT_INIT(16), NULL},
+  {UPB_TABKEY_STR("\012", "\000", "\000", "\000", "TYPE_BYTES"), UPB_TABVALUE_INT_INIT(12), NULL},
+  {UPB_TABKEY_STR("\013", "\000", "\000", "\000", "TYPE_SINT64"), UPB_TABVALUE_INT_INIT(18), NULL},
+  {UPB_TABKEY_STR("\011", "\000", "\000", "\000", "TYPE_BOOL"), UPB_TABVALUE_INT_INIT(8), NULL},
+  {UPB_TABKEY_STR("\012", "\000", "\000", "\000", "TYPE_GROUP"), UPB_TABVALUE_INT_INIT(10), NULL},
+  {UPB_TABKEY_STR("\013", "\000", "\000", "\000", "TYPE_SINT32"), UPB_TABVALUE_INT_INIT(17), NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_STR("\004", "\000", "\000", "\000", "CORD"), UPB_TABVALUE_INT_INIT(1), NULL},
+  {UPB_TABKEY_STR("\006", "\000", "\000", "\000", "STRING"), UPB_TABVALUE_INT_INIT(0), &strentries[225]},
+  {UPB_TABKEY_STR("\014", "\000", "\000", "\000", "STRING_PIECE"), UPB_TABVALUE_INT_INIT(2), NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_STR("\011", "\000", "\000", "\000", "JS_NORMAL"), UPB_TABVALUE_INT_INIT(0), NULL},
+  {UPB_TABKEY_STR("\011", "\000", "\000", "\000", "JS_NUMBER"), UPB_TABVALUE_INT_INIT(2), NULL},
+  {UPB_TABKEY_STR("\011", "\000", "\000", "\000", "JS_STRING"), UPB_TABVALUE_INT_INIT(1), NULL},
+  {UPB_TABKEY_STR("\011", "\000", "\000", "\000", "CODE_SIZE"), UPB_TABVALUE_INT_INIT(2), NULL},
+  {UPB_TABKEY_STR("\005", "\000", "\000", "\000", "SPEED"), UPB_TABVALUE_INT_INIT(1), &strentries[235]},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_STR("\014", "\000", "\000", "\000", "LITE_RUNTIME"), UPB_TABVALUE_INT_INIT(3), NULL},
+};
+
+static const upb_tabent intentries[18] = {
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_NUM(999), UPB_TABVALUE_PTR_INIT(&fields[103]), NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_NUM(999), UPB_TABVALUE_PTR_INIT(&fields[102]), NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_NUM(999), UPB_TABVALUE_PTR_INIT(&fields[101]), NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_NUM(999), UPB_TABVALUE_PTR_INIT(&fields[99]), NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_NUM(999), UPB_TABVALUE_PTR_INIT(&fields[97]), NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_NUM(33), UPB_TABVALUE_PTR_INIT(&fields[10]), NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_NUM(999), UPB_TABVALUE_PTR_INIT(&fields[100]), NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_NUM(33), UPB_TABVALUE_PTR_INIT(&fields[15]), NULL},
+  {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL},
+  {UPB_TABKEY_NUM(999), UPB_TABVALUE_PTR_INIT(&fields[98]), NULL},
+};
+
+static const upb_tabval arrays[187] = {
+  UPB_TABVALUE_EMPTY_INIT,
+  UPB_TABVALUE_PTR_INIT(&fields[57]),
+  UPB_TABVALUE_PTR_INIT(&fields[25]),
+  UPB_TABVALUE_PTR_INIT(&fields[60]),
+  UPB_TABVALUE_PTR_INIT(&fields[20]),
+  UPB_TABVALUE_PTR_INIT(&fields[24]),
+  UPB_TABVALUE_PTR_INIT(&fields[22]),
+  UPB_TABVALUE_PTR_INIT(&fields[68]),
+  UPB_TABVALUE_PTR_INIT(&fields[65]),
+  UPB_TABVALUE_PTR_INIT(&fields[85]),
+  UPB_TABVALUE_PTR_INIT(&fields[84]),
+  UPB_TABVALUE_EMPTY_INIT,
+  UPB_TABVALUE_PTR_INIT(&fields[91]),
+  UPB_TABVALUE_PTR_INIT(&fields[18]),
+  UPB_TABVALUE_EMPTY_INIT,
+  UPB_TABVALUE_PTR_INIT(&fields[90]),
+  UPB_TABVALUE_PTR_INIT(&fields[17]),
+  UPB_TABVALUE_EMPTY_INIT,
+  UPB_TABVALUE_PTR_INIT(&fields[52]),
+  UPB_TABVALUE_PTR_INIT(&fields[104]),
+  UPB_TABVALUE_PTR_INIT(&fields[73]),
+  UPB_TABVALUE_EMPTY_INIT,
+  UPB_TABVALUE_EMPTY_INIT,
+  UPB_TABVALUE_PTR_INIT(&fields[1]),
+  UPB_TABVALUE_PTR_INIT(&fields[14]),
+  UPB_TABVALUE_EMPTY_INIT,
+  UPB_TABVALUE_PTR_INIT(&fields[50]),
+  UPB_TABVALUE_PTR_INIT(&fields[63]),
+  UPB_TABVALUE_PTR_INIT(&fields[74]),
+  UPB_TABVALUE_EMPTY_INIT,
+  UPB_TABVALUE_PTR_INIT(&fields[13]),
+  UPB_TABVALUE_EMPTY_INIT,
+  UPB_TABVALUE_PTR_INIT(&fields[56]),
+  UPB_TABVALUE_PTR_INIT(&fields[21]),
+  UPB_TABVALUE_PTR_INIT(&fields[62]),
+  UPB_TABVALUE_PTR_INIT(&fields[40]),
+  UPB_TABVALUE_PTR_INIT(&fields[95]),
+  UPB_TABVALUE_PTR_INIT(&fields[96]),
+  UPB_TABVALUE_PTR_INIT(&fields[7]),
+  UPB_TABVALUE_PTR_INIT(&fields[70]),
+  UPB_TABVALUE_PTR_INIT(&fields[66]),
+  UPB_TABVALUE_PTR_INIT(&fields[38]),
+  UPB_TABVALUE_EMPTY_INIT,
+  UPB_TABVALUE_PTR_INIT(&fields[6]),
+  UPB_TABVALUE_PTR_INIT(&fields[77]),
+  UPB_TABVALUE_PTR_INIT(&fields[9]),
+  UPB_TABVALUE_EMPTY_INIT,
+  UPB_TABVALUE_PTR_INIT(&fields[41]),
+  UPB_TABVALUE_PTR_INIT(&fields[39]),
+  UPB_TABVALUE_EMPTY_INIT,
+  UPB_TABVALUE_EMPTY_INIT,
+  UPB_TABVALUE_EMPTY_INIT,
+  UPB_TABVALUE_PTR_INIT(&fields[105]),
+  UPB_TABVALUE_EMPTY_INIT,
+  UPB_TABVALUE_PTR_INIT(&fields[51]),
+  UPB_TABVALUE_PTR_INIT(&fields[76]),
+  UPB_TABVALUE_PTR_INIT(&fields[8]),
+  UPB_TABVALUE_PTR_INIT(&fields[47]),
+  UPB_TABVALUE_PTR_INIT(&fields[19]),
+  UPB_TABVALUE_PTR_INIT(&fields[87]),
+  UPB_TABVALUE_PTR_INIT(&fields[23]),
+  UPB_TABVALUE_PTR_INIT(&fields[69]),
+  UPB_TABVALUE_PTR_INIT(&fields[88]),
+  UPB_TABVALUE_PTR_INIT(&fields[82]),
+  UPB_TABVALUE_PTR_INIT(&fields[106]),
+  UPB_TABVALUE_PTR_INIT(&fields[93]),
+  UPB_TABVALUE_EMPTY_INIT,
+  UPB_TABVALUE_PTR_INIT(&fields[26]),
+  UPB_TABVALUE_EMPTY_INIT,
+  UPB_TABVALUE_PTR_INIT(&fields[35]),
+  UPB_TABVALUE_EMPTY_INIT,
+  UPB_TABVALUE_EMPTY_INIT,
+  UPB_TABVALUE_EMPTY_INIT,
+  UPB_TABVALUE_EMPTY_INIT,
+  UPB_TABVALUE_EMPTY_INIT,
+  UPB_TABVALUE_EMPTY_INIT,
+  UPB_TABVALUE_PTR_INIT(&fields[34]),
+  UPB_TABVALUE_PTR_INIT(&fields[67]),
+  UPB_TABVALUE_PTR_INIT(&fields[33]),
+  UPB_TABVALUE_PTR_INIT(&fields[27]),
+  UPB_TABVALUE_EMPTY_INIT,
+  UPB_TABVALUE_EMPTY_INIT,
+  UPB_TABVALUE_EMPTY_INIT,
+  UPB_TABVALUE_EMPTY_INIT,
+  UPB_TABVALUE_PTR_INIT(&fields[3]),
+  UPB_TABVALUE_PTR_INIT(&fields[32]),
+  UPB_TABVALUE_PTR_INIT(&fields[83]),
+  UPB_TABVALUE_EMPTY_INIT,
+  UPB_TABVALUE_PTR_INIT(&fields[31]),
+  UPB_TABVALUE_EMPTY_INIT,
+  UPB_TABVALUE_EMPTY_INIT,
+  UPB_TABVALUE_PTR_INIT(&fields[12]),
+  UPB_TABVALUE_EMPTY_INIT,
+  UPB_TABVALUE_EMPTY_INIT,
+  UPB_TABVALUE_EMPTY_INIT,
+  UPB_TABVALUE_PTR_INIT(&fields[36]),
+  UPB_TABVALUE_EMPTY_INIT,
+  UPB_TABVALUE_EMPTY_INIT,
+  UPB_TABVALUE_EMPTY_INIT,
+  UPB_TABVALUE_PTR_INIT(&fields[2]),
+  UPB_TABVALUE_EMPTY_INIT,
+  UPB_TABVALUE_EMPTY_INIT,
+  UPB_TABVALUE_EMPTY_INIT,
+  UPB_TABVALUE_EMPTY_INIT,
+  UPB_TABVALUE_PTR_INIT(&fields[64]),
+  UPB_TABVALUE_PTR_INIT(&fields[5]),
+  UPB_TABVALUE_PTR_INIT(&fields[37]),
+  UPB_TABVALUE_EMPTY_INIT,
+  UPB_TABVALUE_PTR_INIT(&fields[79]),
+  UPB_TABVALUE_PTR_INIT(&fields[80]),
+  UPB_TABVALUE_EMPTY_INIT,
+  UPB_TABVALUE_PTR_INIT(&fields[46]),
+  UPB_TABVALUE_PTR_INIT(&fields[61]),
+  UPB_TABVALUE_PTR_INIT(&fields[11]),
+  UPB_TABVALUE_EMPTY_INIT,
+  UPB_TABVALUE_EMPTY_INIT,
+  UPB_TABVALUE_EMPTY_INIT,
+  UPB_TABVALUE_PTR_INIT(&fields[45]),
+  UPB_TABVALUE_EMPTY_INIT,
+  UPB_TABVALUE_PTR_INIT(&fields[55]),
+  UPB_TABVALUE_PTR_INIT(&fields[29]),
+  UPB_TABVALUE_PTR_INIT(&fields[75]),
+  UPB_TABVALUE_PTR_INIT(&fields[71]),
+  UPB_TABVALUE_PTR_INIT(&fields[4]),
+  UPB_TABVALUE_PTR_INIT(&fields[86]),
+  UPB_TABVALUE_EMPTY_INIT,
+  UPB_TABVALUE_EMPTY_INIT,
+  UPB_TABVALUE_PTR_INIT(&fields[54]),
+  UPB_TABVALUE_EMPTY_INIT,
+  UPB_TABVALUE_PTR_INIT(&fields[53]),
+  UPB_TABVALUE_PTR_INIT(&fields[48]),
+  UPB_TABVALUE_PTR_INIT(&fields[72]),
+  UPB_TABVALUE_EMPTY_INIT,
+  UPB_TABVALUE_EMPTY_INIT,
+  UPB_TABVALUE_PTR_INIT(&fields[44]),
+  UPB_TABVALUE_EMPTY_INIT,
+  UPB_TABVALUE_PTR_INIT(&fields[78]),
+  UPB_TABVALUE_PTR_INIT(&fields[89]),
+  UPB_TABVALUE_PTR_INIT(&fields[42]),
+  UPB_TABVALUE_PTR_INIT(&fields[94]),
+  UPB_TABVALUE_EMPTY_INIT,
+  UPB_TABVALUE_PTR_INIT(&fields[43]),
+  UPB_TABVALUE_EMPTY_INIT,
+  UPB_TABVALUE_EMPTY_INIT,
+  UPB_TABVALUE_PTR_INIT(&fields[49]),
+  UPB_TABVALUE_PTR_INIT(&fields[28]),
+  UPB_TABVALUE_PTR_INIT(&fields[81]),
+  UPB_TABVALUE_PTR_INIT(&fields[59]),
+  UPB_TABVALUE_PTR_INIT(&fields[16]),
+  UPB_TABVALUE_PTR_INIT(&fields[92]),
+  UPB_TABVALUE_PTR_INIT(&fields[0]),
+  UPB_TABVALUE_EMPTY_INIT,
+  UPB_TABVALUE_PTR_INIT(&fields[58]),
+  UPB_TABVALUE_PTR_INIT(&fields[30]),
+  UPB_TABVALUE_EMPTY_INIT,
+  UPB_TABVALUE_PTR_INIT("LABEL_OPTIONAL"),
+  UPB_TABVALUE_PTR_INIT("LABEL_REQUIRED"),
+  UPB_TABVALUE_PTR_INIT("LABEL_REPEATED"),
+  UPB_TABVALUE_EMPTY_INIT,
+  UPB_TABVALUE_PTR_INIT("TYPE_DOUBLE"),
+  UPB_TABVALUE_PTR_INIT("TYPE_FLOAT"),
+  UPB_TABVALUE_PTR_INIT("TYPE_INT64"),
+  UPB_TABVALUE_PTR_INIT("TYPE_UINT64"),
+  UPB_TABVALUE_PTR_INIT("TYPE_INT32"),
+  UPB_TABVALUE_PTR_INIT("TYPE_FIXED64"),
+  UPB_TABVALUE_PTR_INIT("TYPE_FIXED32"),
+  UPB_TABVALUE_PTR_INIT("TYPE_BOOL"),
+  UPB_TABVALUE_PTR_INIT("TYPE_STRING"),
+  UPB_TABVALUE_PTR_INIT("TYPE_GROUP"),
+  UPB_TABVALUE_PTR_INIT("TYPE_MESSAGE"),
+  UPB_TABVALUE_PTR_INIT("TYPE_BYTES"),
+  UPB_TABVALUE_PTR_INIT("TYPE_UINT32"),
+  UPB_TABVALUE_PTR_INIT("TYPE_ENUM"),
+  UPB_TABVALUE_PTR_INIT("TYPE_SFIXED32"),
+  UPB_TABVALUE_PTR_INIT("TYPE_SFIXED64"),
+  UPB_TABVALUE_PTR_INIT("TYPE_SINT32"),
+  UPB_TABVALUE_PTR_INIT("TYPE_SINT64"),
+  UPB_TABVALUE_PTR_INIT("STRING"),
+  UPB_TABVALUE_PTR_INIT("CORD"),
+  UPB_TABVALUE_PTR_INIT("STRING_PIECE"),
+  UPB_TABVALUE_PTR_INIT("JS_NORMAL"),
+  UPB_TABVALUE_PTR_INIT("JS_STRING"),
+  UPB_TABVALUE_PTR_INIT("JS_NUMBER"),
+  UPB_TABVALUE_EMPTY_INIT,
+  UPB_TABVALUE_PTR_INIT("SPEED"),
+  UPB_TABVALUE_PTR_INIT("CODE_SIZE"),
+  UPB_TABVALUE_PTR_INIT("LITE_RUNTIME"),
+};
+
+#ifdef UPB_DEBUG_REFS
+static upb_inttable reftables[268] = {
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+  UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR),
+};
+#endif
+
+static const upb_msgdef *refm(const upb_msgdef *m, const void *owner) {
+  upb_msgdef_ref(m, owner);
+  return m;
+}
+
+static const upb_enumdef *refe(const upb_enumdef *e, const void *owner) {
+  upb_enumdef_ref(e, owner);
+  return e;
+}
+
+/* Public API. */
+const upb_msgdef *upbdefs_google_protobuf_DescriptorProto_get(const void *owner) { return refm(&msgs[0], owner); }
+const upb_msgdef *upbdefs_google_protobuf_DescriptorProto_ExtensionRange_get(const void *owner) { return refm(&msgs[1], owner); }
+const upb_msgdef *upbdefs_google_protobuf_DescriptorProto_ReservedRange_get(const void *owner) { return refm(&msgs[2], owner); }
+const upb_msgdef *upbdefs_google_protobuf_EnumDescriptorProto_get(const void *owner) { return refm(&msgs[3], owner); }
+const upb_msgdef *upbdefs_google_protobuf_EnumOptions_get(const void *owner) { return refm(&msgs[4], owner); }
+const upb_msgdef *upbdefs_google_protobuf_EnumValueDescriptorProto_get(const void *owner) { return refm(&msgs[5], owner); }
+const upb_msgdef *upbdefs_google_protobuf_EnumValueOptions_get(const void *owner) { return refm(&msgs[6], owner); }
+const upb_msgdef *upbdefs_google_protobuf_FieldDescriptorProto_get(const void *owner) { return refm(&msgs[7], owner); }
+const upb_msgdef *upbdefs_google_protobuf_FieldOptions_get(const void *owner) { return refm(&msgs[8], owner); }
+const upb_msgdef *upbdefs_google_protobuf_FileDescriptorProto_get(const void *owner) { return refm(&msgs[9], owner); }
+const upb_msgdef *upbdefs_google_protobuf_FileDescriptorSet_get(const void *owner) { return refm(&msgs[10], owner); }
+const upb_msgdef *upbdefs_google_protobuf_FileOptions_get(const void *owner) { return refm(&msgs[11], owner); }
+const upb_msgdef *upbdefs_google_protobuf_MessageOptions_get(const void *owner) { return refm(&msgs[12], owner); }
+const upb_msgdef *upbdefs_google_protobuf_MethodDescriptorProto_get(const void *owner) { return refm(&msgs[13], owner); }
+const upb_msgdef *upbdefs_google_protobuf_MethodOptions_get(const void *owner) { return refm(&msgs[14], owner); }
+const upb_msgdef *upbdefs_google_protobuf_OneofDescriptorProto_get(const void *owner) { return refm(&msgs[15], owner); }
+const upb_msgdef *upbdefs_google_protobuf_ServiceDescriptorProto_get(const void *owner) { return refm(&msgs[16], owner); }
+const upb_msgdef *upbdefs_google_protobuf_ServiceOptions_get(const void *owner) { return refm(&msgs[17], owner); }
+const upb_msgdef *upbdefs_google_protobuf_SourceCodeInfo_get(const void *owner) { return refm(&msgs[18], owner); }
+const upb_msgdef *upbdefs_google_protobuf_SourceCodeInfo_Location_get(const void *owner) { return refm(&msgs[19], owner); }
+const upb_msgdef *upbdefs_google_protobuf_UninterpretedOption_get(const void *owner) { return refm(&msgs[20], owner); }
+const upb_msgdef *upbdefs_google_protobuf_UninterpretedOption_NamePart_get(const void *owner) { return refm(&msgs[21], owner); }
+
+const upb_enumdef *upbdefs_google_protobuf_FieldDescriptorProto_Label_get(const void *owner) { return refe(&enums[0], owner); }
+const upb_enumdef *upbdefs_google_protobuf_FieldDescriptorProto_Type_get(const void *owner) { return refe(&enums[1], owner); }
+const upb_enumdef *upbdefs_google_protobuf_FieldOptions_CType_get(const void *owner) { return refe(&enums[2], owner); }
+const upb_enumdef *upbdefs_google_protobuf_FieldOptions_JSType_get(const void *owner) { return refe(&enums[3], owner); }
+const upb_enumdef *upbdefs_google_protobuf_FileOptions_OptimizeMode_get(const void *owner) { return refe(&enums[4], owner); }
+/*
+** XXX: The routines in this file that consume a string do not currently
+** support having the string span buffers.  In the future, as upb_sink and
+** its buffering/sharing functionality evolve there should be an easy and
+** idiomatic way of correctly handling this case.  For now, we accept this
+** limitation since we currently only parse descriptors from single strings.
+*/
+
+
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+
+/* Compares a NULL-terminated string with a non-NULL-terminated string. */
+static bool upb_streq(const char *str, const char *buf, size_t n) {
+  return strlen(str) == n && memcmp(str, buf, n) == 0;
+}
+
+/* We keep a stack of all the messages scopes we are currently in, as well as
+ * the top-level file scope.  This is necessary to correctly qualify the
+ * definitions that are contained inside.  "name" tracks the name of the
+ * message or package (a bare name -- not qualified by any enclosing scopes). */
+typedef struct {
+  char *name;
+  /* Index of the first def that is under this scope.  For msgdefs, the
+   * msgdef itself is at start-1. */
+  int start;
+  uint32_t oneof_start;
+  uint32_t oneof_index;
+} upb_descreader_frame;
+
+/* The maximum number of nested declarations that are allowed, ie.
+ * message Foo {
+ *   message Bar {
+ *     message Baz {
+ *     }
+ *   }
+ * }
+ *
+ * This is a resource limit that affects how big our runtime stack can grow.
+ * TODO: make this a runtime-settable property of the Reader instance. */
+#define UPB_MAX_MESSAGE_NESTING 64
+
+struct upb_descreader {
+  upb_sink sink;
+  upb_inttable files;
+  upb_strtable files_by_name;
+  upb_filedef *file;  /* The last file in files. */
+  upb_descreader_frame stack[UPB_MAX_MESSAGE_NESTING];
+  int stack_len;
+  upb_inttable oneofs;
+
+  uint32_t number;
+  char *name;
+  bool saw_number;
+  bool saw_name;
+
+  char *default_string;
+
+  upb_fielddef *f;
+};
+
+static char *upb_gstrndup(const char *buf, size_t n) {
+  char *ret = upb_gmalloc(n + 1);
+  if (!ret) return NULL;
+  memcpy(ret, buf, n);
+  ret[n] = '\0';
+  return ret;
+}
+
+/* Returns a newly allocated string that joins input strings together, for
+ * example:
+ *   join("Foo.Bar", "Baz") -> "Foo.Bar.Baz"
+ *   join("", "Baz") -> "Baz"
+ * Caller owns a ref on the returned string. */
+static char *upb_join(const char *base, const char *name) {
+  if (!base || strlen(base) == 0) {
+    return upb_gstrdup(name);
+  } else {
+    char *ret = upb_gmalloc(strlen(base) + strlen(name) + 2);
+    if (!ret) {
+      return NULL;
+    }
+    ret[0] = '\0';
+    strcat(ret, base);
+    strcat(ret, ".");
+    strcat(ret, name);
+    return ret;
+  }
+}
+
+/* Qualify the defname for all defs starting with offset "start" with "str". */
+static bool upb_descreader_qualify(upb_filedef *f, char *str, int32_t start) {
+  size_t i;
+  for (i = start; i < upb_filedef_defcount(f); i++) {
+    upb_def *def = upb_filedef_mutabledef(f, i);
+    char *name = upb_join(str, upb_def_fullname(def));
+    if (!name) {
+      /* Need better logic here; at this point we've qualified some names but
+       * not others. */
+      return false;
+    }
+    upb_def_setfullname(def, name, NULL);
+    upb_gfree(name);
+  }
+  return true;
+}
+
+
+/* upb_descreader  ************************************************************/
+
+static upb_msgdef *upb_descreader_top(upb_descreader *r) {
+  int index;
+  UPB_ASSERT(r->stack_len > 1);
+  index = r->stack[r->stack_len-1].start - 1;
+  UPB_ASSERT(index >= 0);
+  return upb_downcast_msgdef_mutable(upb_filedef_mutabledef(r->file, index));
+}
+
+static upb_def *upb_descreader_last(upb_descreader *r) {
+  return upb_filedef_mutabledef(r->file, upb_filedef_defcount(r->file) - 1);
+}
+
+/* Start/end handlers for FileDescriptorProto and DescriptorProto (the two
+ * entities that have names and can contain sub-definitions. */
+void upb_descreader_startcontainer(upb_descreader *r) {
+  upb_descreader_frame *f = &r->stack[r->stack_len++];
+  f->start = upb_filedef_defcount(r->file);
+  f->oneof_start = upb_inttable_count(&r->oneofs);
+  f->oneof_index = 0;
+  f->name = NULL;
+}
+
+bool upb_descreader_endcontainer(upb_descreader *r) {
+  upb_descreader_frame *f = &r->stack[r->stack_len - 1];
+
+  while (upb_inttable_count(&r->oneofs) > f->oneof_start) {
+    upb_oneofdef *o = upb_value_getptr(upb_inttable_pop(&r->oneofs));
+    bool ok = upb_msgdef_addoneof(upb_descreader_top(r), o, &r->oneofs, NULL);
+    UPB_ASSERT(ok);
+  }
+
+  if (!upb_descreader_qualify(r->file, f->name, f->start)) {
+    return false;
+  }
+  upb_gfree(f->name);
+  f->name = NULL;
+
+  r->stack_len--;
+  return true;
+}
+
+void upb_descreader_setscopename(upb_descreader *r, char *str) {
+  upb_descreader_frame *f = &r->stack[r->stack_len-1];
+  upb_gfree(f->name);
+  f->name = str;
+}
+
+static upb_oneofdef *upb_descreader_getoneof(upb_descreader *r,
+                                             uint32_t index) {
+  bool found;
+  upb_value val;
+  upb_descreader_frame *f = &r->stack[r->stack_len-1];
+
+  /* DescriptorProto messages can be nested, so we will see the nested messages
+   * between when we see the FieldDescriptorProto and the OneofDescriptorProto.
+   * We need to preserve the oneofs in between these two things. */
+  index += f->oneof_start;
+
+  while (upb_inttable_count(&r->oneofs) <= index) {
+    upb_inttable_push(&r->oneofs, upb_value_ptr(upb_oneofdef_new(&r->oneofs)));
+  }
+
+  found = upb_inttable_lookup(&r->oneofs, index, &val);
+  UPB_ASSERT(found);
+  return upb_value_getptr(val);
+}
+
+/** Handlers for google.protobuf.FileDescriptorSet. ***************************/
+
+static void *fileset_startfile(void *closure, const void *hd) {
+  upb_descreader *r = closure;
+  UPB_UNUSED(hd);
+  r->file = upb_filedef_new(&r->files);
+  upb_inttable_push(&r->files, upb_value_ptr(r->file));
+  return r;
+}
+
+/** Handlers for google.protobuf.FileDescriptorProto. *************************/
+
+static bool file_start(void *closure, const void *hd) {
+  upb_descreader *r = closure;
+  UPB_UNUSED(hd);
+  upb_descreader_startcontainer(r);
+  return true;
+}
+
+static bool file_end(void *closure, const void *hd, upb_status *status) {
+  upb_descreader *r = closure;
+  UPB_UNUSED(hd);
+  UPB_UNUSED(status);
+  return upb_descreader_endcontainer(r);
+}
+
+static size_t file_onname(void *closure, const void *hd, const char *buf,
+                          size_t n, const upb_bufhandle *handle) {
+  upb_descreader *r = closure;
+  char *name;
+  bool ok;
+  UPB_UNUSED(hd);
+  UPB_UNUSED(handle);
+
+  name = upb_gstrndup(buf, n);
+  upb_strtable_insert(&r->files_by_name, name, upb_value_ptr(r->file));
+  /* XXX: see comment at the top of the file. */
+  ok = upb_filedef_setname(r->file, name, NULL);
+  upb_gfree(name);
+  UPB_ASSERT(ok);
+  return n;
+}
+
+static size_t file_onpackage(void *closure, const void *hd, const char *buf,
+                             size_t n, const upb_bufhandle *handle) {
+  upb_descreader *r = closure;
+  char *package;
+  bool ok;
+  UPB_UNUSED(hd);
+  UPB_UNUSED(handle);
+
+  package = upb_gstrndup(buf, n);
+  /* XXX: see comment at the top of the file. */
+  upb_descreader_setscopename(r, package);
+  ok = upb_filedef_setpackage(r->file, package, NULL);
+  UPB_ASSERT(ok);
+  return n;
+}
+
+static void *file_startphpnamespace(void *closure, const void *hd,
+                                    size_t size_hint) {
+  upb_descreader *r = closure;
+  bool ok;
+  UPB_UNUSED(hd);
+  UPB_UNUSED(size_hint);
+
+  ok = upb_filedef_setphpnamespace(r->file, "", NULL);
+  UPB_ASSERT(ok);
+  return closure;
+}
+
+static size_t file_onphpnamespace(void *closure, const void *hd,
+                                  const char *buf, size_t n,
+                                  const upb_bufhandle *handle) {
+  upb_descreader *r = closure;
+  char *php_namespace;
+  bool ok;
+  UPB_UNUSED(hd);
+  UPB_UNUSED(handle);
+
+  php_namespace = upb_gstrndup(buf, n);
+  ok = upb_filedef_setphpnamespace(r->file, php_namespace, NULL);
+  upb_gfree(php_namespace);
+  UPB_ASSERT(ok);
+  return n;
+}
+
+static size_t file_onphpprefix(void *closure, const void *hd, const char *buf,
+                             size_t n, const upb_bufhandle *handle) {
+  upb_descreader *r = closure;
+  char *prefix;
+  bool ok;
+  UPB_UNUSED(hd);
+  UPB_UNUSED(handle);
+
+  prefix = upb_gstrndup(buf, n);
+  ok = upb_filedef_setphpprefix(r->file, prefix, NULL);
+  upb_gfree(prefix);
+  UPB_ASSERT(ok);
+  return n;
+}
+
+static size_t file_onsyntax(void *closure, const void *hd, const char *buf,
+                            size_t n, const upb_bufhandle *handle) {
+  upb_descreader *r = closure;
+  bool ok;
+  UPB_UNUSED(hd);
+  UPB_UNUSED(handle);
+  /* XXX: see comment at the top of the file. */
+  if (upb_streq("proto2", buf, n)) {
+    ok = upb_filedef_setsyntax(r->file, UPB_SYNTAX_PROTO2, NULL);
+  } else if (upb_streq("proto3", buf, n)) {
+    ok = upb_filedef_setsyntax(r->file, UPB_SYNTAX_PROTO3, NULL);
+  } else {
+    ok = false;
+  }
+
+  UPB_ASSERT(ok);
+  return n;
+}
+
+static void *file_startmsg(void *closure, const void *hd) {
+  upb_descreader *r = closure;
+  upb_msgdef *m = upb_msgdef_new(&m);
+  bool ok = upb_filedef_addmsg(r->file, m, &m, NULL);
+  UPB_UNUSED(hd);
+  UPB_ASSERT(ok);
+  return r;
+}
+
+static void *file_startenum(void *closure, const void *hd) {
+  upb_descreader *r = closure;
+  upb_enumdef *e = upb_enumdef_new(&e);
+  bool ok = upb_filedef_addenum(r->file, e, &e, NULL);
+  UPB_UNUSED(hd);
+  UPB_ASSERT(ok);
+  return r;
+}
+
+static void *file_startext(void *closure, const void *hd) {
+  upb_descreader *r = closure;
+  bool ok;
+  r->f = upb_fielddef_new(r);
+  ok = upb_filedef_addext(r->file, r->f, r, NULL);
+  UPB_UNUSED(hd);
+  UPB_ASSERT(ok);
+  return r;
+}
+
+static size_t file_ondep(void *closure, const void *hd, const char *buf,
+                         size_t n, const upb_bufhandle *handle) {
+  upb_descreader *r = closure;
+  upb_value val;
+  if (upb_strtable_lookup2(&r->files_by_name, buf, n, &val)) {
+    upb_filedef_adddep(r->file, upb_value_getptr(val));
+  }
+  UPB_UNUSED(hd);
+  UPB_UNUSED(handle);
+  return n;
+}
+
+/** Handlers for google.protobuf.EnumValueDescriptorProto. *********************/
+
+static bool enumval_startmsg(void *closure, const void *hd) {
+  upb_descreader *r = closure;
+  UPB_UNUSED(hd);
+  r->saw_number = false;
+  r->saw_name = false;
+  return true;
+}
+
+static size_t enumval_onname(void *closure, const void *hd, const char *buf,
+                             size_t n, const upb_bufhandle *handle) {
+  upb_descreader *r = closure;
+  UPB_UNUSED(hd);
+  UPB_UNUSED(handle);
+  /* XXX: see comment at the top of the file. */
+  upb_gfree(r->name);
+  r->name = upb_gstrndup(buf, n);
+  r->saw_name = true;
+  return n;
+}
+
+static bool enumval_onnumber(void *closure, const void *hd, int32_t val) {
+  upb_descreader *r = closure;
+  UPB_UNUSED(hd);
+  r->number = val;
+  r->saw_number = true;
+  return true;
+}
+
+static bool enumval_endmsg(void *closure, const void *hd, upb_status *status) {
+  upb_descreader *r = closure;
+  upb_enumdef *e;
+  UPB_UNUSED(hd);
+
+  if(!r->saw_number || !r->saw_name) {
+    upb_status_seterrmsg(status, "Enum value missing name or number.");
+    return false;
+  }
+  e = upb_downcast_enumdef_mutable(upb_descreader_last(r));
+  upb_enumdef_addval(e, r->name, r->number, status);
+  upb_gfree(r->name);
+  r->name = NULL;
+  return true;
+}
+
+/** Handlers for google.protobuf.EnumDescriptorProto. *************************/
+
+static bool enum_endmsg(void *closure, const void *hd, upb_status *status) {
+  upb_descreader *r = closure;
+  upb_enumdef *e;
+  UPB_UNUSED(hd);
+
+  e = upb_downcast_enumdef_mutable(upb_descreader_last(r));
+  if (upb_def_fullname(upb_descreader_last(r)) == NULL) {
+    upb_status_seterrmsg(status, "Enum had no name.");
+    return false;
+  }
+  if (upb_enumdef_numvals(e) == 0) {
+    upb_status_seterrmsg(status, "Enum had no values.");
+    return false;
+  }
+  return true;
+}
+
+static size_t enum_onname(void *closure, const void *hd, const char *buf,
+                          size_t n, const upb_bufhandle *handle) {
+  upb_descreader *r = closure;
+  char *fullname = upb_gstrndup(buf, n);
+  UPB_UNUSED(hd);
+  UPB_UNUSED(handle);
+  /* XXX: see comment at the top of the file. */
+  upb_def_setfullname(upb_descreader_last(r), fullname, NULL);
+  upb_gfree(fullname);
+  return n;
+}
+
+/** Handlers for google.protobuf.FieldDescriptorProto *************************/
+
+static bool field_startmsg(void *closure, const void *hd) {
+  upb_descreader *r = closure;
+  UPB_UNUSED(hd);
+  UPB_ASSERT(r->f);
+  upb_gfree(r->default_string);
+  r->default_string = NULL;
+
+  /* fielddefs default to packed, but descriptors default to non-packed. */
+  upb_fielddef_setpacked(r->f, false);
+  return true;
+}
+
+/* Converts the default value in string "str" into "d".  Passes a ref on str.
+ * Returns true on success. */
+static bool parse_default(char *str, upb_fielddef *f) {
+  bool success = true;
+  char *end;
+  switch (upb_fielddef_type(f)) {
+    case UPB_TYPE_INT32: {
+      long val = strtol(str, &end, 0);
+      if (val > INT32_MAX || val < INT32_MIN || errno == ERANGE || *end)
+        success = false;
+      else
+        upb_fielddef_setdefaultint32(f, val);
+      break;
+    }
+    case UPB_TYPE_INT64: {
+      /* XXX: Need to write our own strtoll, since it's not available in c89. */
+      long long val = strtol(str, &end, 0);
+      if (val > INT64_MAX || val < INT64_MIN || errno == ERANGE || *end)
+        success = false;
+      else
+        upb_fielddef_setdefaultint64(f, val);
+      break;
+    }
+    case UPB_TYPE_UINT32: {
+      unsigned long val = strtoul(str, &end, 0);
+      if (val > UINT32_MAX || errno == ERANGE || *end)
+        success = false;
+      else
+        upb_fielddef_setdefaultuint32(f, val);
+      break;
+    }
+    case UPB_TYPE_UINT64: {
+      /* XXX: Need to write our own strtoull, since it's not available in c89. */
+      unsigned long long val = strtoul(str, &end, 0);
+      if (val > UINT64_MAX || errno == ERANGE || *end)
+        success = false;
+      else
+        upb_fielddef_setdefaultuint64(f, val);
+      break;
+    }
+    case UPB_TYPE_DOUBLE: {
+      double val = strtod(str, &end);
+      if (errno == ERANGE || *end)
+        success = false;
+      else
+        upb_fielddef_setdefaultdouble(f, val);
+      break;
+    }
+    case UPB_TYPE_FLOAT: {
+      /* XXX: Need to write our own strtof, since it's not available in c89. */
+      float val = strtod(str, &end);
+      if (errno == ERANGE || *end)
+        success = false;
+      else
+        upb_fielddef_setdefaultfloat(f, val);
+      break;
+    }
+    case UPB_TYPE_BOOL: {
+      if (strcmp(str, "false") == 0)
+        upb_fielddef_setdefaultbool(f, false);
+      else if (strcmp(str, "true") == 0)
+        upb_fielddef_setdefaultbool(f, true);
+      else
+        success = false;
+      break;
+    }
+    default: abort();
+  }
+  return success;
+}
+
+static bool field_endmsg(void *closure, const void *hd, upb_status *status) {
+  upb_descreader *r = closure;
+  upb_fielddef *f = r->f;
+  UPB_UNUSED(hd);
+
+  /* TODO: verify that all required fields were present. */
+  UPB_ASSERT(upb_fielddef_number(f) != 0);
+  UPB_ASSERT(upb_fielddef_name(f) != NULL);
+  UPB_ASSERT((upb_fielddef_subdefname(f) != NULL) == upb_fielddef_hassubdef(f));
+
+  if (r->default_string) {
+    if (upb_fielddef_issubmsg(f)) {
+      upb_status_seterrmsg(status, "Submessages cannot have defaults.");
+      return false;
+    }
+    if (upb_fielddef_isstring(f) || upb_fielddef_type(f) == UPB_TYPE_ENUM) {
+      upb_fielddef_setdefaultcstr(f, r->default_string, NULL);
+    } else {
+      if (r->default_string && !parse_default(r->default_string, f)) {
+        /* We don't worry too much about giving a great error message since the
+         * compiler should have ensured this was correct. */
+        upb_status_seterrmsg(status, "Error converting default value.");
+        return false;
+      }
+    }
+  }
+  return true;
+}
+
+static bool field_onlazy(void *closure, const void *hd, bool val) {
+  upb_descreader *r = closure;
+  UPB_UNUSED(hd);
+
+  upb_fielddef_setlazy(r->f, val);
+  return true;
+}
+
+static bool field_onpacked(void *closure, const void *hd, bool val) {
+  upb_descreader *r = closure;
+  UPB_UNUSED(hd);
+
+  upb_fielddef_setpacked(r->f, val);
+  return true;
+}
+
+static bool field_ontype(void *closure, const void *hd, int32_t val) {
+  upb_descreader *r = closure;
+  UPB_UNUSED(hd);
+
+  upb_fielddef_setdescriptortype(r->f, val);
+  return true;
+}
+
+static bool field_onlabel(void *closure, const void *hd, int32_t val) {
+  upb_descreader *r = closure;
+  UPB_UNUSED(hd);
+
+  upb_fielddef_setlabel(r->f, val);
+  return true;
+}
+
+static bool field_onnumber(void *closure, const void *hd, int32_t val) {
+  upb_descreader *r = closure;
+  bool ok;
+  UPB_UNUSED(hd);
+
+  ok = upb_fielddef_setnumber(r->f, val, NULL);
+  UPB_ASSERT(ok);
+  return true;
+}
+
+static size_t field_onname(void *closure, const void *hd, const char *buf,
+                           size_t n, const upb_bufhandle *handle) {
+  upb_descreader *r = closure;
+  char *name = upb_gstrndup(buf, n);
+  UPB_UNUSED(hd);
+  UPB_UNUSED(handle);
+
+  /* XXX: see comment at the top of the file. */
+  upb_fielddef_setname(r->f, name, NULL);
+  upb_gfree(name);
+  return n;
+}
+
+static size_t field_ontypename(void *closure, const void *hd, const char *buf,
+                               size_t n, const upb_bufhandle *handle) {
+  upb_descreader *r = closure;
+  char *name = upb_gstrndup(buf, n);
+  UPB_UNUSED(hd);
+  UPB_UNUSED(handle);
+
+  /* XXX: see comment at the top of the file. */
+  upb_fielddef_setsubdefname(r->f, name, NULL);
+  upb_gfree(name);
+  return n;
+}
+
+static size_t field_onextendee(void *closure, const void *hd, const char *buf,
+                               size_t n, const upb_bufhandle *handle) {
+  upb_descreader *r = closure;
+  char *name = upb_gstrndup(buf, n);
+  UPB_UNUSED(hd);
+  UPB_UNUSED(handle);
+
+  /* XXX: see comment at the top of the file. */
+  upb_fielddef_setcontainingtypename(r->f, name, NULL);
+  upb_gfree(name);
+  return n;
+}
+
+static size_t field_ondefaultval(void *closure, const void *hd, const char *buf,
+                                 size_t n, const upb_bufhandle *handle) {
+  upb_descreader *r = closure;
+  UPB_UNUSED(hd);
+  UPB_UNUSED(handle);
+
+  /* Have to convert from string to the correct type, but we might not know the
+   * type yet, so we save it as a string until the end of the field.
+   * XXX: see comment at the top of the file. */
+  upb_gfree(r->default_string);
+  r->default_string = upb_gstrndup(buf, n);
+  return n;
+}
+
+static bool field_ononeofindex(void *closure, const void *hd, int32_t index) {
+  upb_descreader *r = closure;
+  upb_oneofdef *o = upb_descreader_getoneof(r, index);
+  bool ok = upb_oneofdef_addfield(o, r->f, &r->f, NULL);
+  UPB_UNUSED(hd);
+
+  UPB_ASSERT(ok);
+  return true;
+}
+
+/** Handlers for google.protobuf.OneofDescriptorProto. ************************/
+
+static size_t oneof_name(void *closure, const void *hd, const char *buf,
+                         size_t n, const upb_bufhandle *handle) {
+  upb_descreader *r = closure;
+  upb_descreader_frame *f = &r->stack[r->stack_len-1];
+  upb_oneofdef *o = upb_descreader_getoneof(r, f->oneof_index++);
+  char *name_null_terminated = upb_gstrndup(buf, n);
+  bool ok = upb_oneofdef_setname(o, name_null_terminated, NULL);
+  UPB_UNUSED(hd);
+  UPB_UNUSED(handle);
+
+  UPB_ASSERT(ok);
+  free(name_null_terminated);
+  return n;
+}
+
+/** Handlers for google.protobuf.DescriptorProto ******************************/
+
+static bool msg_start(void *closure, const void *hd) {
+  upb_descreader *r = closure;
+  UPB_UNUSED(hd);
+
+  upb_descreader_startcontainer(r);
+  return true;
+}
+
+static bool msg_end(void *closure, const void *hd, upb_status *status) {
+  upb_descreader *r = closure;
+  upb_msgdef *m = upb_descreader_top(r);
+  UPB_UNUSED(hd);
+
+  if(!upb_def_fullname(upb_msgdef_upcast_mutable(m))) {
+    upb_status_seterrmsg(status, "Encountered message with no name.");
+    return false;
+  }
+  return upb_descreader_endcontainer(r);
+}
+
+static size_t msg_name(void *closure, const void *hd, const char *buf,
+                       size_t n, const upb_bufhandle *handle) {
+  upb_descreader *r = closure;
+  upb_msgdef *m = upb_descreader_top(r);
+  /* XXX: see comment at the top of the file. */
+  char *name = upb_gstrndup(buf, n);
+  UPB_UNUSED(hd);
+  UPB_UNUSED(handle);
+
+  upb_def_setfullname(upb_msgdef_upcast_mutable(m), name, NULL);
+  upb_descreader_setscopename(r, name);  /* Passes ownership of name. */
+  return n;
+}
+
+static void *msg_startmsg(void *closure, const void *hd) {
+  upb_descreader *r = closure;
+  upb_msgdef *m = upb_msgdef_new(&m);
+  bool ok = upb_filedef_addmsg(r->file, m, &m, NULL);
+  UPB_UNUSED(hd);
+  UPB_ASSERT(ok);
+  return r;
+}
+
+static void *msg_startext(void *closure, const void *hd) {
+  upb_descreader *r = closure;
+  upb_fielddef *f = upb_fielddef_new(&f);
+  bool ok = upb_filedef_addext(r->file, f, &f, NULL);
+  UPB_UNUSED(hd);
+  UPB_ASSERT(ok);
+  return r;
+}
+
+static void *msg_startfield(void *closure, const void *hd) {
+  upb_descreader *r = closure;
+  r->f = upb_fielddef_new(&r->f);
+  /* We can't add the new field to the message until its name/number are
+   * filled in. */
+  UPB_UNUSED(hd);
+  return r;
+}
+
+static bool msg_endfield(void *closure, const void *hd) {
+  upb_descreader *r = closure;
+  upb_msgdef *m = upb_descreader_top(r);
+  bool ok;
+  UPB_UNUSED(hd);
+
+  /* Oneof fields are added to the msgdef through their oneof, so don't need to
+   * be added here. */
+  if (upb_fielddef_containingoneof(r->f) == NULL) {
+    ok = upb_msgdef_addfield(m, r->f, &r->f, NULL);
+    UPB_ASSERT(ok);
+  }
+  r->f = NULL;
+  return true;
+}
+
+static bool msg_onmapentry(void *closure, const void *hd, bool mapentry) {
+  upb_descreader *r = closure;
+  upb_msgdef *m = upb_descreader_top(r);
+  UPB_UNUSED(hd);
+
+  upb_msgdef_setmapentry(m, mapentry);
+  r->f = NULL;
+  return true;
+}
+
+
+
+/** Code to register handlers *************************************************/
+
+#define F(msg, field) upbdefs_google_protobuf_ ## msg ## _f_ ## field(m)
+
+static void reghandlers(const void *closure, upb_handlers *h) {
+  const upb_msgdef *m = upb_handlers_msgdef(h);
+  UPB_UNUSED(closure);
+
+  if (upbdefs_google_protobuf_FileDescriptorSet_is(m)) {
+    upb_handlers_setstartsubmsg(h, F(FileDescriptorSet, file),
+                                &fileset_startfile, NULL);
+  } else if (upbdefs_google_protobuf_DescriptorProto_is(m)) {
+    upb_handlers_setstartmsg(h, &msg_start, NULL);
+    upb_handlers_setendmsg(h, &msg_end, NULL);
+    upb_handlers_setstring(h, F(DescriptorProto, name), &msg_name, NULL);
+    upb_handlers_setstartsubmsg(h, F(DescriptorProto, extension), &msg_startext,
+                                NULL);
+    upb_handlers_setstartsubmsg(h, F(DescriptorProto, nested_type),
+                                &msg_startmsg, NULL);
+    upb_handlers_setstartsubmsg(h, F(DescriptorProto, field),
+                                &msg_startfield, NULL);
+    upb_handlers_setendsubmsg(h, F(DescriptorProto, field),
+                              &msg_endfield, NULL);
+    upb_handlers_setstartsubmsg(h, F(DescriptorProto, enum_type),
+                                &file_startenum, NULL);
+  } else if (upbdefs_google_protobuf_FileDescriptorProto_is(m)) {
+    upb_handlers_setstartmsg(h, &file_start, NULL);
+    upb_handlers_setendmsg(h, &file_end, NULL);
+    upb_handlers_setstring(h, F(FileDescriptorProto, name), &file_onname,
+                           NULL);
+    upb_handlers_setstring(h, F(FileDescriptorProto, package), &file_onpackage,
+                           NULL);
+    upb_handlers_setstring(h, F(FileDescriptorProto, syntax), &file_onsyntax,
+                           NULL);
+    upb_handlers_setstartsubmsg(h, F(FileDescriptorProto, message_type),
+                                &file_startmsg, NULL);
+    upb_handlers_setstartsubmsg(h, F(FileDescriptorProto, enum_type),
+                                &file_startenum, NULL);
+    upb_handlers_setstartsubmsg(h, F(FileDescriptorProto, extension),
+                                &file_startext, NULL);
+    upb_handlers_setstring(h, F(FileDescriptorProto, dependency),
+                           &file_ondep, NULL);
+  } else if (upbdefs_google_protobuf_EnumValueDescriptorProto_is(m)) {
+    upb_handlers_setstartmsg(h, &enumval_startmsg, NULL);
+    upb_handlers_setendmsg(h, &enumval_endmsg, NULL);
+    upb_handlers_setstring(h, F(EnumValueDescriptorProto, name), &enumval_onname, NULL);
+    upb_handlers_setint32(h, F(EnumValueDescriptorProto, number), &enumval_onnumber,
+                          NULL);
+  } else if (upbdefs_google_protobuf_EnumDescriptorProto_is(m)) {
+    upb_handlers_setendmsg(h, &enum_endmsg, NULL);
+    upb_handlers_setstring(h, F(EnumDescriptorProto, name), &enum_onname, NULL);
+  } else if (upbdefs_google_protobuf_FieldDescriptorProto_is(m)) {
+    upb_handlers_setstartmsg(h, &field_startmsg, NULL);
+    upb_handlers_setendmsg(h, &field_endmsg, NULL);
+    upb_handlers_setint32(h, F(FieldDescriptorProto, type), &field_ontype,
+                          NULL);
+    upb_handlers_setint32(h, F(FieldDescriptorProto, label), &field_onlabel,
+                          NULL);
+    upb_handlers_setint32(h, F(FieldDescriptorProto, number), &field_onnumber,
+                          NULL);
+    upb_handlers_setstring(h, F(FieldDescriptorProto, name), &field_onname,
+                           NULL);
+    upb_handlers_setstring(h, F(FieldDescriptorProto, type_name),
+                           &field_ontypename, NULL);
+    upb_handlers_setstring(h, F(FieldDescriptorProto, extendee),
+                           &field_onextendee, NULL);
+    upb_handlers_setstring(h, F(FieldDescriptorProto, default_value),
+                           &field_ondefaultval, NULL);
+    upb_handlers_setint32(h, F(FieldDescriptorProto, oneof_index),
+                          &field_ononeofindex, NULL);
+  } else if (upbdefs_google_protobuf_OneofDescriptorProto_is(m)) {
+    upb_handlers_setstring(h, F(OneofDescriptorProto, name), &oneof_name, NULL);
+  } else if (upbdefs_google_protobuf_FieldOptions_is(m)) {
+    upb_handlers_setbool(h, F(FieldOptions, lazy), &field_onlazy, NULL);
+    upb_handlers_setbool(h, F(FieldOptions, packed), &field_onpacked, NULL);
+  } else if (upbdefs_google_protobuf_MessageOptions_is(m)) {
+    upb_handlers_setbool(h, F(MessageOptions, map_entry), &msg_onmapentry, NULL);
+  } else if (upbdefs_google_protobuf_FileOptions_is(m)) {
+    upb_handlers_setstring(h, F(FileOptions, php_class_prefix),
+                           &file_onphpprefix, NULL);
+    upb_handlers_setstartstr(h, F(FileOptions, php_namespace),
+                             &file_startphpnamespace, NULL);
+    upb_handlers_setstring(h, F(FileOptions, php_namespace),
+                           &file_onphpnamespace, NULL);
+  }
+
+  UPB_ASSERT(upb_ok(upb_handlers_status(h)));
+}
+
+#undef F
+
+void descreader_cleanup(void *_r) {
+  upb_descreader *r = _r;
+  size_t i;
+
+  for (i = 0; i < upb_descreader_filecount(r); i++) {
+    upb_filedef_unref(upb_descreader_file(r, i), &r->files);
+  }
+
+  upb_gfree(r->name);
+  upb_inttable_uninit(&r->files);
+  upb_strtable_uninit(&r->files_by_name);
+  upb_inttable_uninit(&r->oneofs);
+  upb_gfree(r->default_string);
+  while (r->stack_len > 0) {
+    upb_descreader_frame *f = &r->stack[--r->stack_len];
+    upb_gfree(f->name);
+  }
+}
+
+
+/* Public API  ****************************************************************/
+
+upb_descreader *upb_descreader_create(upb_env *e, const upb_handlers *h) {
+  upb_descreader *r = upb_env_malloc(e, sizeof(upb_descreader));
+  if (!r || !upb_env_addcleanup(e, descreader_cleanup, r)) {
+    return NULL;
+  }
+
+  upb_inttable_init(&r->files, UPB_CTYPE_PTR);
+  upb_strtable_init(&r->files_by_name, UPB_CTYPE_PTR);
+  upb_inttable_init(&r->oneofs, UPB_CTYPE_PTR);
+  upb_sink_reset(upb_descreader_input(r), h, r);
+  r->stack_len = 0;
+  r->name = NULL;
+  r->default_string = NULL;
+
+  return r;
+}
+
+size_t upb_descreader_filecount(const upb_descreader *r) {
+  return upb_inttable_count(&r->files);
+}
+
+upb_filedef *upb_descreader_file(const upb_descreader *r, size_t i) {
+  upb_value v;
+  if (upb_inttable_lookup(&r->files, i, &v)) {
+    return upb_value_getptr(v);
+  } else {
+    return NULL;
+  }
+}
+
+upb_sink *upb_descreader_input(upb_descreader *r) {
+  return &r->sink;
+}
+
+const upb_handlers *upb_descreader_newhandlers(const void *owner) {
+  const upb_msgdef *m = upbdefs_google_protobuf_FileDescriptorSet_get(&m);
+  const upb_handlers *h = upb_handlers_newfrozen(m, owner, reghandlers, NULL);
+  upb_msgdef_unref(m, &m);
+  return h;
+}
+/*
+** protobuf decoder bytecode compiler
+**
+** Code to compile a upb::Handlers into bytecode for decoding a protobuf
+** according to that specific schema and destination handlers.
+**
+** Compiling to bytecode is always the first step.  If we are using the
+** interpreted decoder we leave it as bytecode and interpret that.  If we are
+** using a JIT decoder we use a code generator to turn the bytecode into native
+** code, LLVM IR, etc.
+**
+** Bytecode definition is in decoder.int.h.
+*/
+
+#include <stdarg.h>
+
+#ifdef UPB_DUMP_BYTECODE
+#include <stdio.h>
+#endif
+
+#define MAXLABEL 5
+#define EMPTYLABEL -1
+
+/* mgroup *********************************************************************/
+
+static void freegroup(upb_refcounted *r) {
+  mgroup *g = (mgroup*)r;
+  upb_inttable_uninit(&g->methods);
+#ifdef UPB_USE_JIT_X64
+  upb_pbdecoder_freejit(g);
+#endif
+  upb_gfree(g->bytecode);
+  upb_gfree(g);
+}
+
+static void visitgroup(const upb_refcounted *r, upb_refcounted_visit *visit,
+                       void *closure) {
+  const mgroup *g = (const mgroup*)r;
+  upb_inttable_iter i;
+  upb_inttable_begin(&i, &g->methods);
+  for(; !upb_inttable_done(&i); upb_inttable_next(&i)) {
+    upb_pbdecodermethod *method = upb_value_getptr(upb_inttable_iter_value(&i));
+    visit(r, upb_pbdecodermethod_upcast(method), closure);
+  }
+}
+
+mgroup *newgroup(const void *owner) {
+  mgroup *g = upb_gmalloc(sizeof(*g));
+  static const struct upb_refcounted_vtbl vtbl = {visitgroup, freegroup};
+  upb_refcounted_init(mgroup_upcast_mutable(g), &vtbl, owner);
+  upb_inttable_init(&g->methods, UPB_CTYPE_PTR);
+  g->bytecode = NULL;
+  g->bytecode_end = NULL;
+  return g;
+}
+
+
+/* upb_pbdecodermethod ********************************************************/
+
+static void freemethod(upb_refcounted *r) {
+  upb_pbdecodermethod *method = (upb_pbdecodermethod*)r;
+
+  if (method->dest_handlers_) {
+    upb_handlers_unref(method->dest_handlers_, method);
+  }
+
+  upb_inttable_uninit(&method->dispatch);
+  upb_gfree(method);
+}
+
+static void visitmethod(const upb_refcounted *r, upb_refcounted_visit *visit,
+                        void *closure) {
+  const upb_pbdecodermethod *m = (const upb_pbdecodermethod*)r;
+  visit(r, m->group, closure);
+}
+
+static upb_pbdecodermethod *newmethod(const upb_handlers *dest_handlers,
+                                      mgroup *group) {
+  static const struct upb_refcounted_vtbl vtbl = {visitmethod, freemethod};
+  upb_pbdecodermethod *ret = upb_gmalloc(sizeof(*ret));
+  upb_refcounted_init(upb_pbdecodermethod_upcast_mutable(ret), &vtbl, &ret);
+  upb_byteshandler_init(&ret->input_handler_);
+
+  /* The method references the group and vice-versa, in a circular reference. */
+  upb_ref2(ret, group);
+  upb_ref2(group, ret);
+  upb_inttable_insertptr(&group->methods, dest_handlers, upb_value_ptr(ret));
+  upb_pbdecodermethod_unref(ret, &ret);
+
+  ret->group = mgroup_upcast_mutable(group);
+  ret->dest_handlers_ = dest_handlers;
+  ret->is_native_ = false;  /* If we JIT, it will update this later. */
+  upb_inttable_init(&ret->dispatch, UPB_CTYPE_UINT64);
+
+  if (ret->dest_handlers_) {
+    upb_handlers_ref(ret->dest_handlers_, ret);
+  }
+  return ret;
+}
+
+const upb_handlers *upb_pbdecodermethod_desthandlers(
+    const upb_pbdecodermethod *m) {
+  return m->dest_handlers_;
+}
+
+const upb_byteshandler *upb_pbdecodermethod_inputhandler(
+    const upb_pbdecodermethod *m) {
+  return &m->input_handler_;
+}
+
+bool upb_pbdecodermethod_isnative(const upb_pbdecodermethod *m) {
+  return m->is_native_;
+}
+
+const upb_pbdecodermethod *upb_pbdecodermethod_new(
+    const upb_pbdecodermethodopts *opts, const void *owner) {
+  const upb_pbdecodermethod *ret;
+  upb_pbcodecache cache;
+
+  upb_pbcodecache_init(&cache);
+  ret = upb_pbcodecache_getdecodermethod(&cache, opts);
+  upb_pbdecodermethod_ref(ret, owner);
+  upb_pbcodecache_uninit(&cache);
+  return ret;
+}
+
+
+/* bytecode compiler **********************************************************/
+
+/* Data used only at compilation time. */
+typedef struct {
+  mgroup *group;
+
+  uint32_t *pc;
+  int fwd_labels[MAXLABEL];
+  int back_labels[MAXLABEL];
+
+  /* For fields marked "lazy", parse them lazily or eagerly? */
+  bool lazy;
+} compiler;
+
+static compiler *newcompiler(mgroup *group, bool lazy) {
+  compiler *ret = upb_gmalloc(sizeof(*ret));
+  int i;
+
+  ret->group = group;
+  ret->lazy = lazy;
+  for (i = 0; i < MAXLABEL; i++) {
+    ret->fwd_labels[i] = EMPTYLABEL;
+    ret->back_labels[i] = EMPTYLABEL;
+  }
+  return ret;
+}
+
+static void freecompiler(compiler *c) {
+  upb_gfree(c);
+}
+
+const size_t ptr_words = sizeof(void*) / sizeof(uint32_t);
+
+/* How many words an instruction is. */
+static int instruction_len(uint32_t instr) {
+  switch (getop(instr)) {
+    case OP_SETDISPATCH: return 1 + ptr_words;
+    case OP_TAGN: return 3;
+    case OP_SETBIGGROUPNUM: return 2;
+    default: return 1;
+  }
+}
+
+bool op_has_longofs(int32_t instruction) {
+  switch (getop(instruction)) {
+    case OP_CALL:
+    case OP_BRANCH:
+    case OP_CHECKDELIM:
+      return true;
+    /* The "tag" instructions only have 8 bytes available for the jump target,
+     * but that is ok because these opcodes only require short jumps. */
+    case OP_TAG1:
+    case OP_TAG2:
+    case OP_TAGN:
+      return false;
+    default:
+      UPB_ASSERT(false);
+      return false;
+  }
+}
+
+static int32_t getofs(uint32_t instruction) {
+  if (op_has_longofs(instruction)) {
+    return (int32_t)instruction >> 8;
+  } else {
+    return (int8_t)(instruction >> 8);
+  }
+}
+
+static void setofs(uint32_t *instruction, int32_t ofs) {
+  if (op_has_longofs(*instruction)) {
+    *instruction = getop(*instruction) | ofs << 8;
+  } else {
+    *instruction = (*instruction & ~0xff00) | ((ofs & 0xff) << 8);
+  }
+  UPB_ASSERT(getofs(*instruction) == ofs);  /* Would fail in cases of overflow. */
+}
+
+static uint32_t pcofs(compiler *c) { return c->pc - c->group->bytecode; }
+
+/* Defines a local label at the current PC location.  All previous forward
+ * references are updated to point to this location.  The location is noted
+ * for any future backward references. */
+static void label(compiler *c, unsigned int label) {
+  int val;
+  uint32_t *codep;
+
+  UPB_ASSERT(label < MAXLABEL);
+  val = c->fwd_labels[label];
+  codep = (val == EMPTYLABEL) ? NULL : c->group->bytecode + val;
+  while (codep) {
+    int ofs = getofs(*codep);
+    setofs(codep, c->pc - codep - instruction_len(*codep));
+    codep = ofs ? codep + ofs : NULL;
+  }
+  c->fwd_labels[label] = EMPTYLABEL;
+  c->back_labels[label] = pcofs(c);
+}
+
+/* Creates a reference to a numbered label; either a forward reference
+ * (positive arg) or backward reference (negative arg).  For forward references
+ * the value returned now is actually a "next" pointer into a linked list of all
+ * instructions that use this label and will be patched later when the label is
+ * defined with label().
+ *
+ * The returned value is the offset that should be written into the instruction.
+ */
+static int32_t labelref(compiler *c, int label) {
+  UPB_ASSERT(label < MAXLABEL);
+  if (label == LABEL_DISPATCH) {
+    /* No resolving required. */
+    return 0;
+  } else if (label < 0) {
+    /* Backward local label.  Relative to the next instruction. */
+    uint32_t from = (c->pc + 1) - c->group->bytecode;
+    return c->back_labels[-label] - from;
+  } else {
+    /* Forward local label: prepend to (possibly-empty) linked list. */
+    int *lptr = &c->fwd_labels[label];
+    int32_t ret = (*lptr == EMPTYLABEL) ? 0 : *lptr - pcofs(c);
+    *lptr = pcofs(c);
+    return ret;
+  }
+}
+
+static void put32(compiler *c, uint32_t v) {
+  mgroup *g = c->group;
+  if (c->pc == g->bytecode_end) {
+    int ofs = pcofs(c);
+    size_t oldsize = g->bytecode_end - g->bytecode;
+    size_t newsize = UPB_MAX(oldsize * 2, 64);
+    /* TODO(haberman): handle OOM. */
+    g->bytecode = upb_grealloc(g->bytecode, oldsize * sizeof(uint32_t),
+                                            newsize * sizeof(uint32_t));
+    g->bytecode_end = g->bytecode + newsize;
+    c->pc = g->bytecode + ofs;
+  }
+  *c->pc++ = v;
+}
+
+static void putop(compiler *c, int op, ...) {
+  va_list ap;
+  va_start(ap, op);
+
+  switch (op) {
+    case OP_SETDISPATCH: {
+      uintptr_t ptr = (uintptr_t)va_arg(ap, void*);
+      put32(c, OP_SETDISPATCH);
+      put32(c, ptr);
+      if (sizeof(uintptr_t) > sizeof(uint32_t))
+        put32(c, (uint64_t)ptr >> 32);
+      break;
+    }
+    case OP_STARTMSG:
+    case OP_ENDMSG:
+    case OP_PUSHLENDELIM:
+    case OP_POP:
+    case OP_SETDELIM:
+    case OP_HALT:
+    case OP_RET:
+    case OP_DISPATCH:
+      put32(c, op);
+      break;
+    case OP_PARSE_DOUBLE:
+    case OP_PARSE_FLOAT:
+    case OP_PARSE_INT64:
+    case OP_PARSE_UINT64:
+    case OP_PARSE_INT32:
+    case OP_PARSE_FIXED64:
+    case OP_PARSE_FIXED32:
+    case OP_PARSE_BOOL:
+    case OP_PARSE_UINT32:
+    case OP_PARSE_SFIXED32:
+    case OP_PARSE_SFIXED64:
+    case OP_PARSE_SINT32:
+    case OP_PARSE_SINT64:
+    case OP_STARTSEQ:
+    case OP_ENDSEQ:
+    case OP_STARTSUBMSG:
+    case OP_ENDSUBMSG:
+    case OP_STARTSTR:
+    case OP_STRING:
+    case OP_ENDSTR:
+    case OP_PUSHTAGDELIM:
+      put32(c, op | va_arg(ap, upb_selector_t) << 8);
+      break;
+    case OP_SETBIGGROUPNUM:
+      put32(c, op);
+      put32(c, va_arg(ap, int));
+      break;
+    case OP_CALL: {
+      const upb_pbdecodermethod *method = va_arg(ap, upb_pbdecodermethod *);
+      put32(c, op | (method->code_base.ofs - (pcofs(c) + 1)) << 8);
+      break;
+    }
+    case OP_CHECKDELIM:
+    case OP_BRANCH: {
+      uint32_t instruction = op;
+      int label = va_arg(ap, int);
+      setofs(&instruction, labelref(c, label));
+      put32(c, instruction);
+      break;
+    }
+    case OP_TAG1:
+    case OP_TAG2: {
+      int label = va_arg(ap, int);
+      uint64_t tag = va_arg(ap, uint64_t);
+      uint32_t instruction = op | (tag << 16);
+      UPB_ASSERT(tag <= 0xffff);
+      setofs(&instruction, labelref(c, label));
+      put32(c, instruction);
+      break;
+    }
+    case OP_TAGN: {
+      int label = va_arg(ap, int);
+      uint64_t tag = va_arg(ap, uint64_t);
+      uint32_t instruction = op | (upb_value_size(tag) << 16);
+      setofs(&instruction, labelref(c, label));
+      put32(c, instruction);
+      put32(c, tag);
+      put32(c, tag >> 32);
+      break;
+    }
+  }
+
+  va_end(ap);
+}
+
+#if defined(UPB_USE_JIT_X64) || defined(UPB_DUMP_BYTECODE)
+
+const char *upb_pbdecoder_getopname(unsigned int op) {
+#define QUOTE(x) #x
+#define EXPAND_AND_QUOTE(x) QUOTE(x)
+#define OPNAME(x) OP_##x
+#define OP(x) case OPNAME(x): return EXPAND_AND_QUOTE(OPNAME(x));
+#define T(x) OP(PARSE_##x)
+  /* Keep in sync with list in decoder.int.h. */
+  switch ((opcode)op) {
+    T(DOUBLE) T(FLOAT) T(INT64) T(UINT64) T(INT32) T(FIXED64) T(FIXED32)
+    T(BOOL) T(UINT32) T(SFIXED32) T(SFIXED64) T(SINT32) T(SINT64)
+    OP(STARTMSG) OP(ENDMSG) OP(STARTSEQ) OP(ENDSEQ) OP(STARTSUBMSG)
+    OP(ENDSUBMSG) OP(STARTSTR) OP(STRING) OP(ENDSTR) OP(CALL) OP(RET)
+    OP(PUSHLENDELIM) OP(PUSHTAGDELIM) OP(SETDELIM) OP(CHECKDELIM)
+    OP(BRANCH) OP(TAG1) OP(TAG2) OP(TAGN) OP(SETDISPATCH) OP(POP)
+    OP(SETBIGGROUPNUM) OP(DISPATCH) OP(HALT)
+  }
+  return "<unknown op>";
+#undef OP
+#undef T
+}
+
+#endif
+
+#ifdef UPB_DUMP_BYTECODE
+
+static void dumpbc(uint32_t *p, uint32_t *end, FILE *f) {
+
+  uint32_t *begin = p;
+
+  while (p < end) {
+    fprintf(f, "%p  %8tx", p, p - begin);
+    uint32_t instr = *p++;
+    uint8_t op = getop(instr);
+    fprintf(f, " %s", upb_pbdecoder_getopname(op));
+    switch ((opcode)op) {
+      case OP_SETDISPATCH: {
+        const upb_inttable *dispatch;
+        memcpy(&dispatch, p, sizeof(void*));
+        p += ptr_words;
+        const upb_pbdecodermethod *method =
+            (void *)((char *)dispatch -
+                     offsetof(upb_pbdecodermethod, dispatch));
+        fprintf(f, " %s", upb_msgdef_fullname(
+                              upb_handlers_msgdef(method->dest_handlers_)));
+        break;
+      }
+      case OP_DISPATCH:
+      case OP_STARTMSG:
+      case OP_ENDMSG:
+      case OP_PUSHLENDELIM:
+      case OP_POP:
+      case OP_SETDELIM:
+      case OP_HALT:
+      case OP_RET:
+        break;
+      case OP_PARSE_DOUBLE:
+      case OP_PARSE_FLOAT:
+      case OP_PARSE_INT64:
+      case OP_PARSE_UINT64:
+      case OP_PARSE_INT32:
+      case OP_PARSE_FIXED64:
+      case OP_PARSE_FIXED32:
+      case OP_PARSE_BOOL:
+      case OP_PARSE_UINT32:
+      case OP_PARSE_SFIXED32:
+      case OP_PARSE_SFIXED64:
+      case OP_PARSE_SINT32:
+      case OP_PARSE_SINT64:
+      case OP_STARTSEQ:
+      case OP_ENDSEQ:
+      case OP_STARTSUBMSG:
+      case OP_ENDSUBMSG:
+      case OP_STARTSTR:
+      case OP_STRING:
+      case OP_ENDSTR:
+      case OP_PUSHTAGDELIM:
+        fprintf(f, " %d", instr >> 8);
+        break;
+      case OP_SETBIGGROUPNUM:
+        fprintf(f, " %d", *p++);
+        break;
+      case OP_CHECKDELIM:
+      case OP_CALL:
+      case OP_BRANCH:
+        fprintf(f, " =>0x%tx", p + getofs(instr) - begin);
+        break;
+      case OP_TAG1:
+      case OP_TAG2: {
+        fprintf(f, " tag:0x%x", instr >> 16);
+        if (getofs(instr)) {
+          fprintf(f, " =>0x%tx", p + getofs(instr) - begin);
+        }
+        break;
+      }
+      case OP_TAGN: {
+        uint64_t tag = *p++;
+        tag |= (uint64_t)*p++ << 32;
+        fprintf(f, " tag:0x%llx", (long long)tag);
+        fprintf(f, " n:%d", instr >> 16);
+        if (getofs(instr)) {
+          fprintf(f, " =>0x%tx", p + getofs(instr) - begin);
+        }
+        break;
+      }
+    }
+    fputs("\n", f);
+  }
+}
+
+#endif
+
+static uint64_t get_encoded_tag(const upb_fielddef *f, int wire_type) {
+  uint32_t tag = (upb_fielddef_number(f) << 3) | wire_type;
+  uint64_t encoded_tag = upb_vencode32(tag);
+  /* No tag should be greater than 5 bytes. */
+  UPB_ASSERT(encoded_tag <= 0xffffffffff);
+  return encoded_tag;
+}
+
+static void putchecktag(compiler *c, const upb_fielddef *f,
+                        int wire_type, int dest) {
+  uint64_t tag = get_encoded_tag(f, wire_type);
+  switch (upb_value_size(tag)) {
+    case 1:
+      putop(c, OP_TAG1, dest, tag);
+      break;
+    case 2:
+      putop(c, OP_TAG2, dest, tag);
+      break;
+    default:
+      putop(c, OP_TAGN, dest, tag);
+      break;
+  }
+}
+
+static upb_selector_t getsel(const upb_fielddef *f, upb_handlertype_t type) {
+  upb_selector_t selector;
+  bool ok = upb_handlers_getselector(f, type, &selector);
+  UPB_ASSERT(ok);
+  return selector;
+}
+
+/* Takes an existing, primary dispatch table entry and repacks it with a
+ * different alternate wire type.  Called when we are inserting a secondary
+ * dispatch table entry for an alternate wire type. */
+static uint64_t repack(uint64_t dispatch, int new_wt2) {
+  uint64_t ofs;
+  uint8_t wt1;
+  uint8_t old_wt2;
+  upb_pbdecoder_unpackdispatch(dispatch, &ofs, &wt1, &old_wt2);
+  UPB_ASSERT(old_wt2 == NO_WIRE_TYPE);  /* wt2 should not be set yet. */
+  return upb_pbdecoder_packdispatch(ofs, wt1, new_wt2);
+}
+
+/* Marks the current bytecode position as the dispatch target for this message,
+ * field, and wire type. */
+static void dispatchtarget(compiler *c, upb_pbdecodermethod *method,
+                           const upb_fielddef *f, int wire_type) {
+  /* Offset is relative to msg base. */
+  uint64_t ofs = pcofs(c) - method->code_base.ofs;
+  uint32_t fn = upb_fielddef_number(f);
+  upb_inttable *d = &method->dispatch;
+  upb_value v;
+  if (upb_inttable_remove(d, fn, &v)) {
+    /* TODO: prioritize based on packed setting in .proto file. */
+    uint64_t repacked = repack(upb_value_getuint64(v), wire_type);
+    upb_inttable_insert(d, fn, upb_value_uint64(repacked));
+    upb_inttable_insert(d, fn + UPB_MAX_FIELDNUMBER, upb_value_uint64(ofs));
+  } else {
+    uint64_t val = upb_pbdecoder_packdispatch(ofs, wire_type, NO_WIRE_TYPE);
+    upb_inttable_insert(d, fn, upb_value_uint64(val));
+  }
+}
+
+static void putpush(compiler *c, const upb_fielddef *f) {
+  if (upb_fielddef_descriptortype(f) == UPB_DESCRIPTOR_TYPE_MESSAGE) {
+    putop(c, OP_PUSHLENDELIM);
+  } else {
+    uint32_t fn = upb_fielddef_number(f);
+    if (fn >= 1 << 24) {
+      putop(c, OP_PUSHTAGDELIM, 0);
+      putop(c, OP_SETBIGGROUPNUM, fn);
+    } else {
+      putop(c, OP_PUSHTAGDELIM, fn);
+    }
+  }
+}
+
+static upb_pbdecodermethod *find_submethod(const compiler *c,
+                                           const upb_pbdecodermethod *method,
+                                           const upb_fielddef *f) {
+  const upb_handlers *sub =
+      upb_handlers_getsubhandlers(method->dest_handlers_, f);
+  upb_value v;
+  return upb_inttable_lookupptr(&c->group->methods, sub, &v)
+             ? upb_value_getptr(v)
+             : NULL;
+}
+
+static void putsel(compiler *c, opcode op, upb_selector_t sel,
+                   const upb_handlers *h) {
+  if (upb_handlers_gethandler(h, sel)) {
+    putop(c, op, sel);
+  }
+}
+
+/* Puts an opcode to call a callback, but only if a callback actually exists for
+ * this field and handler type. */
+static void maybeput(compiler *c, opcode op, const upb_handlers *h,
+                     const upb_fielddef *f, upb_handlertype_t type) {
+  putsel(c, op, getsel(f, type), h);
+}
+
+static bool haslazyhandlers(const upb_handlers *h, const upb_fielddef *f) {
+  if (!upb_fielddef_lazy(f))
+    return false;
+
+  return upb_handlers_gethandler(h, getsel(f, UPB_HANDLER_STARTSTR)) ||
+         upb_handlers_gethandler(h, getsel(f, UPB_HANDLER_STRING)) ||
+         upb_handlers_gethandler(h, getsel(f, UPB_HANDLER_ENDSTR));
+}
+
+
+/* bytecode compiler code generation ******************************************/
+
+/* Symbolic names for our local labels. */
+#define LABEL_LOOPSTART 1  /* Top of a repeated field loop. */
+#define LABEL_LOOPBREAK 2  /* To jump out of a repeated loop */
+#define LABEL_FIELD     3  /* Jump backward to find the most recent field. */
+#define LABEL_ENDMSG    4  /* To reach the OP_ENDMSG instr for this msg. */
+
+/* Generates bytecode to parse a single non-lazy message field. */
+static void generate_msgfield(compiler *c, const upb_fielddef *f,
+                              upb_pbdecodermethod *method) {
+  const upb_handlers *h = upb_pbdecodermethod_desthandlers(method);
+  const upb_pbdecodermethod *sub_m = find_submethod(c, method, f);
+  int wire_type;
+
+  if (!sub_m) {
+    /* Don't emit any code for this field at all; it will be parsed as an
+     * unknown field.
+     *
+     * TODO(haberman): we should change this to parse it as a string field
+     * instead.  It will probably be faster, but more importantly, once we
+     * start vending unknown fields, a field shouldn't be treated as unknown
+     * just because it doesn't have subhandlers registered. */
+    return;
+  }
+
+  label(c, LABEL_FIELD);
+
+  wire_type =
+      (upb_fielddef_descriptortype(f) == UPB_DESCRIPTOR_TYPE_MESSAGE)
+          ? UPB_WIRE_TYPE_DELIMITED
+          : UPB_WIRE_TYPE_START_GROUP;
+
+  if (upb_fielddef_isseq(f)) {
+    putop(c, OP_CHECKDELIM, LABEL_ENDMSG);
+    putchecktag(c, f, wire_type, LABEL_DISPATCH);
+   dispatchtarget(c, method, f, wire_type);
+    putop(c, OP_PUSHTAGDELIM, 0);
+    putop(c, OP_STARTSEQ, getsel(f, UPB_HANDLER_STARTSEQ));
+   label(c, LABEL_LOOPSTART);
+    putpush(c, f);
+    putop(c, OP_STARTSUBMSG, getsel(f, UPB_HANDLER_STARTSUBMSG));
+    putop(c, OP_CALL, sub_m);
+    putop(c, OP_POP);
+    maybeput(c, OP_ENDSUBMSG, h, f, UPB_HANDLER_ENDSUBMSG);
+    if (wire_type == UPB_WIRE_TYPE_DELIMITED) {
+      putop(c, OP_SETDELIM);
+    }
+    putop(c, OP_CHECKDELIM, LABEL_LOOPBREAK);
+    putchecktag(c, f, wire_type, LABEL_LOOPBREAK);
+    putop(c, OP_BRANCH, -LABEL_LOOPSTART);
+   label(c, LABEL_LOOPBREAK);
+    putop(c, OP_POP);
+    maybeput(c, OP_ENDSEQ, h, f, UPB_HANDLER_ENDSEQ);
+  } else {
+    putop(c, OP_CHECKDELIM, LABEL_ENDMSG);
+    putchecktag(c, f, wire_type, LABEL_DISPATCH);
+   dispatchtarget(c, method, f, wire_type);
+    putpush(c, f);
+    putop(c, OP_STARTSUBMSG, getsel(f, UPB_HANDLER_STARTSUBMSG));
+    putop(c, OP_CALL, sub_m);
+    putop(c, OP_POP);
+    maybeput(c, OP_ENDSUBMSG, h, f, UPB_HANDLER_ENDSUBMSG);
+    if (wire_type == UPB_WIRE_TYPE_DELIMITED) {
+      putop(c, OP_SETDELIM);
+    }
+  }
+}
+
+/* Generates bytecode to parse a single string or lazy submessage field. */
+static void generate_delimfield(compiler *c, const upb_fielddef *f,
+                                upb_pbdecodermethod *method) {
+  const upb_handlers *h = upb_pbdecodermethod_desthandlers(method);
+
+  label(c, LABEL_FIELD);
+  if (upb_fielddef_isseq(f)) {
+    putop(c, OP_CHECKDELIM, LABEL_ENDMSG);
+    putchecktag(c, f, UPB_WIRE_TYPE_DELIMITED, LABEL_DISPATCH);
+   dispatchtarget(c, method, f, UPB_WIRE_TYPE_DELIMITED);
+    putop(c, OP_PUSHTAGDELIM, 0);
+    putop(c, OP_STARTSEQ, getsel(f, UPB_HANDLER_STARTSEQ));
+   label(c, LABEL_LOOPSTART);
+    putop(c, OP_PUSHLENDELIM);
+    putop(c, OP_STARTSTR, getsel(f, UPB_HANDLER_STARTSTR));
+    /* Need to emit even if no handler to skip past the string. */
+    putop(c, OP_STRING, getsel(f, UPB_HANDLER_STRING));
+    putop(c, OP_POP);
+    maybeput(c, OP_ENDSTR, h, f, UPB_HANDLER_ENDSTR);
+    putop(c, OP_SETDELIM);
+    putop(c, OP_CHECKDELIM, LABEL_LOOPBREAK);
+    putchecktag(c, f, UPB_WIRE_TYPE_DELIMITED, LABEL_LOOPBREAK);
+    putop(c, OP_BRANCH, -LABEL_LOOPSTART);
+   label(c, LABEL_LOOPBREAK);
+    putop(c, OP_POP);
+    maybeput(c, OP_ENDSEQ, h, f, UPB_HANDLER_ENDSEQ);
+  } else {
+    putop(c, OP_CHECKDELIM, LABEL_ENDMSG);
+    putchecktag(c, f, UPB_WIRE_TYPE_DELIMITED, LABEL_DISPATCH);
+   dispatchtarget(c, method, f, UPB_WIRE_TYPE_DELIMITED);
+    putop(c, OP_PUSHLENDELIM);
+    putop(c, OP_STARTSTR, getsel(f, UPB_HANDLER_STARTSTR));
+    putop(c, OP_STRING, getsel(f, UPB_HANDLER_STRING));
+    putop(c, OP_POP);
+    maybeput(c, OP_ENDSTR, h, f, UPB_HANDLER_ENDSTR);
+    putop(c, OP_SETDELIM);
+  }
+}
+
+/* Generates bytecode to parse a single primitive field. */
+static void generate_primitivefield(compiler *c, const upb_fielddef *f,
+                                    upb_pbdecodermethod *method) {
+  const upb_handlers *h = upb_pbdecodermethod_desthandlers(method);
+  upb_descriptortype_t descriptor_type = upb_fielddef_descriptortype(f);
+  opcode parse_type;
+  upb_selector_t sel;
+  int wire_type;
+
+  label(c, LABEL_FIELD);
+
+  /* From a decoding perspective, ENUM is the same as INT32. */
+  if (descriptor_type == UPB_DESCRIPTOR_TYPE_ENUM)
+    descriptor_type = UPB_DESCRIPTOR_TYPE_INT32;
+
+  parse_type = (opcode)descriptor_type;
+
+  /* TODO(haberman): generate packed or non-packed first depending on "packed"
+   * setting in the fielddef.  This will favor (in speed) whichever was
+   * specified. */
+
+  UPB_ASSERT((int)parse_type >= 0 && parse_type <= OP_MAX);
+  sel = getsel(f, upb_handlers_getprimitivehandlertype(f));
+  wire_type = upb_pb_native_wire_types[upb_fielddef_descriptortype(f)];
+  if (upb_fielddef_isseq(f)) {
+    putop(c, OP_CHECKDELIM, LABEL_ENDMSG);
+    putchecktag(c, f, UPB_WIRE_TYPE_DELIMITED, LABEL_DISPATCH);
+   dispatchtarget(c, method, f, UPB_WIRE_TYPE_DELIMITED);
+    putop(c, OP_PUSHLENDELIM);
+    putop(c, OP_STARTSEQ, getsel(f, UPB_HANDLER_STARTSEQ));  /* Packed */
+   label(c, LABEL_LOOPSTART);
+    putop(c, parse_type, sel);
+    putop(c, OP_CHECKDELIM, LABEL_LOOPBREAK);
+    putop(c, OP_BRANCH, -LABEL_LOOPSTART);
+   dispatchtarget(c, method, f, wire_type);
+    putop(c, OP_PUSHTAGDELIM, 0);
+    putop(c, OP_STARTSEQ, getsel(f, UPB_HANDLER_STARTSEQ));  /* Non-packed */
+   label(c, LABEL_LOOPSTART);
+    putop(c, parse_type, sel);
+    putop(c, OP_CHECKDELIM, LABEL_LOOPBREAK);
+    putchecktag(c, f, wire_type, LABEL_LOOPBREAK);
+    putop(c, OP_BRANCH, -LABEL_LOOPSTART);
+   label(c, LABEL_LOOPBREAK);
+    putop(c, OP_POP);  /* Packed and non-packed join. */
+    maybeput(c, OP_ENDSEQ, h, f, UPB_HANDLER_ENDSEQ);
+    putop(c, OP_SETDELIM);  /* Could remove for non-packed by dup ENDSEQ. */
+  } else {
+    putop(c, OP_CHECKDELIM, LABEL_ENDMSG);
+    putchecktag(c, f, wire_type, LABEL_DISPATCH);
+   dispatchtarget(c, method, f, wire_type);
+    putop(c, parse_type, sel);
+  }
+}
+
+/* Adds bytecode for parsing the given message to the given decoderplan,
+ * while adding all dispatch targets to this message's dispatch table. */
+static void compile_method(compiler *c, upb_pbdecodermethod *method) {
+  const upb_handlers *h;
+  const upb_msgdef *md;
+  uint32_t* start_pc;
+  upb_msg_field_iter i;
+  upb_value val;
+
+  UPB_ASSERT(method);
+
+  /* Clear all entries in the dispatch table. */
+  upb_inttable_uninit(&method->dispatch);
+  upb_inttable_init(&method->dispatch, UPB_CTYPE_UINT64);
+
+  h = upb_pbdecodermethod_desthandlers(method);
+  md = upb_handlers_msgdef(h);
+
+ method->code_base.ofs = pcofs(c);
+  putop(c, OP_SETDISPATCH, &method->dispatch);
+  putsel(c, OP_STARTMSG, UPB_STARTMSG_SELECTOR, h);
+ label(c, LABEL_FIELD);
+  start_pc = c->pc;
+  for(upb_msg_field_begin(&i, md);
+      !upb_msg_field_done(&i);
+      upb_msg_field_next(&i)) {
+    const upb_fielddef *f = upb_msg_iter_field(&i);
+    upb_fieldtype_t type = upb_fielddef_type(f);
+
+    if (type == UPB_TYPE_MESSAGE && !(haslazyhandlers(h, f) && c->lazy)) {
+      generate_msgfield(c, f, method);
+    } else if (type == UPB_TYPE_STRING || type == UPB_TYPE_BYTES ||
+               type == UPB_TYPE_MESSAGE) {
+      generate_delimfield(c, f, method);
+    } else {
+      generate_primitivefield(c, f, method);
+    }
+  }
+
+  /* If there were no fields, or if no handlers were defined, we need to
+   * generate a non-empty loop body so that we can at least dispatch for unknown
+   * fields and check for the end of the message. */
+  if (c->pc == start_pc) {
+    /* Check for end-of-message. */
+    putop(c, OP_CHECKDELIM, LABEL_ENDMSG);
+    /* Unconditionally dispatch. */
+    putop(c, OP_DISPATCH, 0);
+  }
+
+  /* For now we just loop back to the last field of the message (or if none,
+   * the DISPATCH opcode for the message). */
+  putop(c, OP_BRANCH, -LABEL_FIELD);
+
+  /* Insert both a label and a dispatch table entry for this end-of-msg. */
+ label(c, LABEL_ENDMSG);
+  val = upb_value_uint64(pcofs(c) - method->code_base.ofs);
+  upb_inttable_insert(&method->dispatch, DISPATCH_ENDMSG, val);
+
+  putsel(c, OP_ENDMSG, UPB_ENDMSG_SELECTOR, h);
+  putop(c, OP_RET);
+
+  upb_inttable_compact(&method->dispatch);
+}
+
+/* Populate "methods" with new upb_pbdecodermethod objects reachable from "h".
+ * Returns the method for these handlers.
+ *
+ * Generates a new method for every destination handlers reachable from "h". */
+static void find_methods(compiler *c, const upb_handlers *h) {
+  upb_value v;
+  upb_msg_field_iter i;
+  const upb_msgdef *md;
+
+  if (upb_inttable_lookupptr(&c->group->methods, h, &v))
+    return;
+  newmethod(h, c->group);
+
+  /* Find submethods. */
+  md = upb_handlers_msgdef(h);
+  for(upb_msg_field_begin(&i, md);
+      !upb_msg_field_done(&i);
+      upb_msg_field_next(&i)) {
+    const upb_fielddef *f = upb_msg_iter_field(&i);
+    const upb_handlers *sub_h;
+    if (upb_fielddef_type(f) == UPB_TYPE_MESSAGE &&
+        (sub_h = upb_handlers_getsubhandlers(h, f)) != NULL) {
+      /* We only generate a decoder method for submessages with handlers.
+       * Others will be parsed as unknown fields. */
+      find_methods(c, sub_h);
+    }
+  }
+}
+
+/* (Re-)compile bytecode for all messages in "msgs."
+ * Overwrites any existing bytecode in "c". */
+static void compile_methods(compiler *c) {
+  upb_inttable_iter i;
+
+  /* Start over at the beginning of the bytecode. */
+  c->pc = c->group->bytecode;
+
+  upb_inttable_begin(&i, &c->group->methods);
+  for(; !upb_inttable_done(&i); upb_inttable_next(&i)) {
+    upb_pbdecodermethod *method = upb_value_getptr(upb_inttable_iter_value(&i));
+    compile_method(c, method);
+  }
+}
+
+static void set_bytecode_handlers(mgroup *g) {
+  upb_inttable_iter i;
+  upb_inttable_begin(&i, &g->methods);
+  for(; !upb_inttable_done(&i); upb_inttable_next(&i)) {
+    upb_pbdecodermethod *m = upb_value_getptr(upb_inttable_iter_value(&i));
+    upb_byteshandler *h = &m->input_handler_;
+
+    m->code_base.ptr = g->bytecode + m->code_base.ofs;
+
+    upb_byteshandler_setstartstr(h, upb_pbdecoder_startbc, m->code_base.ptr);
+    upb_byteshandler_setstring(h, upb_pbdecoder_decode, g);
+    upb_byteshandler_setendstr(h, upb_pbdecoder_end, m);
+  }
+}
+
+
+/* JIT setup. *****************************************************************/
+
+#ifdef UPB_USE_JIT_X64
+
+static void sethandlers(mgroup *g, bool allowjit) {
+  g->jit_code = NULL;
+  if (allowjit) {
+    /* Compile byte-code into machine code, create handlers. */
+    upb_pbdecoder_jit(g);
+  } else {
+    set_bytecode_handlers(g);
+  }
+}
+
+#else  /* UPB_USE_JIT_X64 */
+
+static void sethandlers(mgroup *g, bool allowjit) {
+  /* No JIT compiled in; use bytecode handlers unconditionally. */
+  UPB_UNUSED(allowjit);
+  set_bytecode_handlers(g);
+}
+
+#endif  /* UPB_USE_JIT_X64 */
+
+
+/* TODO(haberman): allow this to be constructed for an arbitrary set of dest
+ * handlers and other mgroups (but verify we have a transitive closure). */
+const mgroup *mgroup_new(const upb_handlers *dest, bool allowjit, bool lazy,
+                         const void *owner) {
+  mgroup *g;
+  compiler *c;
+
+  UPB_UNUSED(allowjit);
+  UPB_ASSERT(upb_handlers_isfrozen(dest));
+
+  g = newgroup(owner);
+  c = newcompiler(g, lazy);
+  find_methods(c, dest);
+
+  /* We compile in two passes:
+   * 1. all messages are assigned relative offsets from the beginning of the
+   *    bytecode (saved in method->code_base).
+   * 2. forwards OP_CALL instructions can be correctly linked since message
+   *    offsets have been previously assigned.
+   *
+   * Could avoid the second pass by linking OP_CALL instructions somehow. */
+  compile_methods(c);
+  compile_methods(c);
+  g->bytecode_end = c->pc;
+  freecompiler(c);
+
+#ifdef UPB_DUMP_BYTECODE
+  {
+    FILE *f = fopen("/tmp/upb-bytecode", "w");
+    UPB_ASSERT(f);
+    dumpbc(g->bytecode, g->bytecode_end, stderr);
+    dumpbc(g->bytecode, g->bytecode_end, f);
+    fclose(f);
+
+    f = fopen("/tmp/upb-bytecode.bin", "wb");
+    UPB_ASSERT(f);
+    fwrite(g->bytecode, 1, g->bytecode_end - g->bytecode, f);
+    fclose(f);
+  }
+#endif
+
+  sethandlers(g, allowjit);
+  return g;
+}
+
+
+/* upb_pbcodecache ************************************************************/
+
+void upb_pbcodecache_init(upb_pbcodecache *c) {
+  upb_inttable_init(&c->groups, UPB_CTYPE_CONSTPTR);
+  c->allow_jit_ = true;
+}
+
+void upb_pbcodecache_uninit(upb_pbcodecache *c) {
+  upb_inttable_iter i;
+  upb_inttable_begin(&i, &c->groups);
+  for(; !upb_inttable_done(&i); upb_inttable_next(&i)) {
+    const mgroup *group = upb_value_getconstptr(upb_inttable_iter_value(&i));
+    mgroup_unref(group, c);
+  }
+  upb_inttable_uninit(&c->groups);
+}
+
+bool upb_pbcodecache_allowjit(const upb_pbcodecache *c) {
+  return c->allow_jit_;
+}
+
+bool upb_pbcodecache_setallowjit(upb_pbcodecache *c, bool allow) {
+  if (upb_inttable_count(&c->groups) > 0)
+    return false;
+  c->allow_jit_ = allow;
+  return true;
+}
+
+const upb_pbdecodermethod *upb_pbcodecache_getdecodermethod(
+    upb_pbcodecache *c, const upb_pbdecodermethodopts *opts) {
+  upb_value v;
+  bool ok;
+
+  /* Right now we build a new DecoderMethod every time.
+   * TODO(haberman): properly cache methods by their true key. */
+  const mgroup *g = mgroup_new(opts->handlers, c->allow_jit_, opts->lazy, c);
+  upb_inttable_push(&c->groups, upb_value_constptr(g));
+
+  ok = upb_inttable_lookupptr(&g->methods, opts->handlers, &v);
+  UPB_ASSERT(ok);
+  return upb_value_getptr(v);
+}
+
+
+/* upb_pbdecodermethodopts ****************************************************/
+
+void upb_pbdecodermethodopts_init(upb_pbdecodermethodopts *opts,
+                                  const upb_handlers *h) {
+  opts->handlers = h;
+  opts->lazy = false;
+}
+
+void upb_pbdecodermethodopts_setlazy(upb_pbdecodermethodopts *opts, bool lazy) {
+  opts->lazy = lazy;
+}
+/*
+** upb::Decoder (Bytecode Decoder VM)
+**
+** Bytecode must previously have been generated using the bytecode compiler in
+** compile_decoder.c.  This decoder then walks through the bytecode op-by-op to
+** parse the input.
+**
+** Decoding is fully resumable; we just keep a pointer to the current bytecode
+** instruction and resume from there.  A fair amount of the logic here is to
+** handle the fact that values can span buffer seams and we have to be able to
+** be capable of suspending/resuming from any byte in the stream.  This
+** sometimes requires keeping a few trailing bytes from the last buffer around
+** in the "residual" buffer.
+*/
+
+#include <inttypes.h>
+#include <stddef.h>
+
+#ifdef UPB_DUMP_BYTECODE
+#include <stdio.h>
+#endif
+
+#define CHECK_SUSPEND(x) if (!(x)) return upb_pbdecoder_suspend(d);
+
+/* Error messages that are shared between the bytecode and JIT decoders. */
+const char *kPbDecoderStackOverflow = "Nesting too deep.";
+const char *kPbDecoderSubmessageTooLong =
+    "Submessage end extends past enclosing submessage.";
+
+/* Error messages shared within this file. */
+static const char *kUnterminatedVarint = "Unterminated varint.";
+
+/* upb_pbdecoder **************************************************************/
+
+static opcode halt = OP_HALT;
+
+/* A dummy character we can point to when the user passes us a NULL buffer.
+ * We need this because in C (NULL + 0) and (NULL - NULL) are undefined
+ * behavior, which would invalidate functions like curbufleft(). */
+static const char dummy_char;
+
+/* Whether an op consumes any of the input buffer. */
+static bool consumes_input(opcode op) {
+  switch (op) {
+    case OP_SETDISPATCH:
+    case OP_STARTMSG:
+    case OP_ENDMSG:
+    case OP_STARTSEQ:
+    case OP_ENDSEQ:
+    case OP_STARTSUBMSG:
+    case OP_ENDSUBMSG:
+    case OP_STARTSTR:
+    case OP_ENDSTR:
+    case OP_PUSHTAGDELIM:
+    case OP_POP:
+    case OP_SETDELIM:
+    case OP_SETBIGGROUPNUM:
+    case OP_CHECKDELIM:
+    case OP_CALL:
+    case OP_RET:
+    case OP_BRANCH:
+      return false;
+    default:
+      return true;
+  }
+}
+
+static size_t stacksize(upb_pbdecoder *d, size_t entries) {
+  UPB_UNUSED(d);
+  return entries * sizeof(upb_pbdecoder_frame);
+}
+
+static size_t callstacksize(upb_pbdecoder *d, size_t entries) {
+  UPB_UNUSED(d);
+
+#ifdef UPB_USE_JIT_X64
+  if (d->method_->is_native_) {
+    /* Each native stack frame needs two pointers, plus we need a few frames for
+     * the enter/exit trampolines. */
+    size_t ret = entries * sizeof(void*) * 2;
+    ret += sizeof(void*) * 10;
+    return ret;
+  }
+#endif
+
+  return entries * sizeof(uint32_t*);
+}
+
+
+static bool in_residual_buf(const upb_pbdecoder *d, const char *p);
+
+/* It's unfortunate that we have to micro-manage the compiler with
+ * UPB_FORCEINLINE and UPB_NOINLINE, especially since this tuning is necessarily
+ * specific to one hardware configuration.  But empirically on a Core i7,
+ * performance increases 30-50% with these annotations.  Every instance where
+ * these appear, gcc 4.2.1 made the wrong decision and degraded performance in
+ * benchmarks. */
+
+static void seterr(upb_pbdecoder *d, const char *msg) {
+  upb_status status = UPB_STATUS_INIT;
+  upb_status_seterrmsg(&status, msg);
+  upb_env_reporterror(d->env, &status);
+}
+
+void upb_pbdecoder_seterr(upb_pbdecoder *d, const char *msg) {
+  seterr(d, msg);
+}
+
+
+/* Buffering ******************************************************************/
+
+/* We operate on one buffer at a time, which is either the user's buffer passed
+ * to our "decode" callback or some residual bytes from the previous buffer. */
+
+/* How many bytes can be safely read from d->ptr without reading past end-of-buf
+ * or past the current delimited end. */
+static size_t curbufleft(const upb_pbdecoder *d) {
+  UPB_ASSERT(d->data_end >= d->ptr);
+  return d->data_end - d->ptr;
+}
+
+/* How many bytes are available before end-of-buffer. */
+static size_t bufleft(const upb_pbdecoder *d) {
+  return d->end - d->ptr;
+}
+
+/* Overall stream offset of d->ptr. */
+uint64_t offset(const upb_pbdecoder *d) {
+  return d->bufstart_ofs + (d->ptr - d->buf);
+}
+
+/* How many bytes are available before the end of this delimited region. */
+size_t delim_remaining(const upb_pbdecoder *d) {
+  return d->top->end_ofs - offset(d);
+}
+
+/* Advances d->ptr. */
+static void advance(upb_pbdecoder *d, size_t len) {
+  UPB_ASSERT(curbufleft(d) >= len);
+  d->ptr += len;
+}
+
+static bool in_buf(const char *p, const char *buf, const char *end) {
+  return p >= buf && p <= end;
+}
+
+static bool in_residual_buf(const upb_pbdecoder *d, const char *p) {
+  return in_buf(p, d->residual, d->residual_end);
+}
+
+/* Calculates the delim_end value, which is affected by both the current buffer
+ * and the parsing stack, so must be called whenever either is updated. */
+static void set_delim_end(upb_pbdecoder *d) {
+  size_t delim_ofs = d->top->end_ofs - d->bufstart_ofs;
+  if (delim_ofs <= (size_t)(d->end - d->buf)) {
+    d->delim_end = d->buf + delim_ofs;
+    d->data_end = d->delim_end;
+  } else {
+    d->data_end = d->end;
+    d->delim_end = NULL;
+  }
+}
+
+static void switchtobuf(upb_pbdecoder *d, const char *buf, const char *end) {
+  d->ptr = buf;
+  d->buf = buf;
+  d->end = end;
+  set_delim_end(d);
+}
+
+static void advancetobuf(upb_pbdecoder *d, const char *buf, size_t len) {
+  UPB_ASSERT(curbufleft(d) == 0);
+  d->bufstart_ofs += (d->end - d->buf);
+  switchtobuf(d, buf, buf + len);
+}
+
+static void checkpoint(upb_pbdecoder *d) {
+  /* The assertion here is in the interests of efficiency, not correctness.
+   * We are trying to ensure that we don't checkpoint() more often than
+   * necessary. */
+  UPB_ASSERT(d->checkpoint != d->ptr);
+  d->checkpoint = d->ptr;
+}
+
+/* Skips "bytes" bytes in the stream, which may be more than available.  If we
+ * skip more bytes than are available, we return a long read count to the caller
+ * indicating how many bytes can be skipped over before passing actual data
+ * again.  Skipped bytes can pass a NULL buffer and the decoder guarantees they
+ * won't actually be read.
+ */
+static int32_t skip(upb_pbdecoder *d, size_t bytes) {
+  UPB_ASSERT(!in_residual_buf(d, d->ptr) || d->size_param == 0);
+  UPB_ASSERT(d->skip == 0);
+  if (bytes > delim_remaining(d)) {
+    seterr(d, "Skipped value extended beyond enclosing submessage.");
+    return upb_pbdecoder_suspend(d);
+  } else if (bufleft(d) >= bytes) {
+    /* Skipped data is all in current buffer, and more is still available. */
+    advance(d, bytes);
+    d->skip = 0;
+    return DECODE_OK;
+  } else {
+    /* Skipped data extends beyond currently available buffers. */
+    d->pc = d->last;
+    d->skip = bytes - curbufleft(d);
+    d->bufstart_ofs += (d->end - d->buf);
+    d->residual_end = d->residual;
+    switchtobuf(d, d->residual, d->residual_end);
+    return d->size_param + d->skip;
+  }
+}
+
+
+/* Resumes the decoder from an initial state or from a previous suspend. */
+int32_t upb_pbdecoder_resume(upb_pbdecoder *d, void *p, const char *buf,
+                             size_t size, const upb_bufhandle *handle) {
+  UPB_UNUSED(p);  /* Useless; just for the benefit of the JIT. */
+
+  /* d->skip and d->residual_end could probably elegantly be represented
+   * as a single variable, to more easily represent this invariant. */
+  UPB_ASSERT(!(d->skip && d->residual_end > d->residual));
+
+  /* We need to remember the original size_param, so that the value we return
+   * is relative to it, even if we do some skipping first. */
+  d->size_param = size;
+  d->handle = handle;
+
+  /* Have to handle this case specially (ie. not with skip()) because the user
+   * is allowed to pass a NULL buffer here, which won't allow us to safely
+   * calculate a d->end or use our normal functions like curbufleft(). */
+  if (d->skip && d->skip >= size) {
+    d->skip -= size;
+    d->bufstart_ofs += size;
+    buf = &dummy_char;
+    size = 0;
+
+    /* We can't just return now, because we might need to execute some ops
+     * like CHECKDELIM, which could call some callbacks and pop the stack. */
+  }
+
+  /* We need to pretend that this was the actual buffer param, since some of the
+   * calculations assume that d->ptr/d->buf is relative to this. */
+  d->buf_param = buf;
+
+  if (!buf) {
+    /* NULL buf is ok if its entire span is covered by the "skip" above, but
+     * by this point we know that "skip" doesn't cover the buffer. */
+    seterr(d, "Passed NULL buffer over non-skippable region.");
+    return upb_pbdecoder_suspend(d);
+  }
+
+  if (d->residual_end > d->residual) {
+    /* We have residual bytes from the last buffer. */
+    UPB_ASSERT(d->ptr == d->residual);
+  } else {
+    switchtobuf(d, buf, buf + size);
+  }
+
+  d->checkpoint = d->ptr;
+
+  /* Handle skips that don't cover the whole buffer (as above). */
+  if (d->skip) {
+    size_t skip_bytes = d->skip;
+    d->skip = 0;
+    CHECK_RETURN(skip(d, skip_bytes));
+    checkpoint(d);
+  }
+
+  /* If we're inside an unknown group, continue to parse unknown values. */
+  if (d->top->groupnum < 0) {
+    CHECK_RETURN(upb_pbdecoder_skipunknown(d, -1, 0));
+    checkpoint(d);
+  }
+
+  return DECODE_OK;
+}
+
+/* Suspends the decoder at the last checkpoint, without saving any residual
+ * bytes.  If there are any unconsumed bytes, returns a short byte count. */
+size_t upb_pbdecoder_suspend(upb_pbdecoder *d) {
+  d->pc = d->last;
+  if (d->checkpoint == d->residual) {
+    /* Checkpoint was in residual buf; no user bytes were consumed. */
+    d->ptr = d->residual;
+    return 0;
+  } else {
+    size_t ret = d->size_param - (d->end - d->checkpoint);
+    UPB_ASSERT(!in_residual_buf(d, d->checkpoint));
+    UPB_ASSERT(d->buf == d->buf_param || d->buf == &dummy_char);
+
+    d->bufstart_ofs += (d->checkpoint - d->buf);
+    d->residual_end = d->residual;
+    switchtobuf(d, d->residual, d->residual_end);
+    return ret;
+  }
+}
+
+/* Suspends the decoder at the last checkpoint, and saves any unconsumed
+ * bytes in our residual buffer.  This is necessary if we need more user
+ * bytes to form a complete value, which might not be contiguous in the
+ * user's buffers.  Always consumes all user bytes. */
+static size_t suspend_save(upb_pbdecoder *d) {
+  /* We hit end-of-buffer before we could parse a full value.
+   * Save any unconsumed bytes (if any) to the residual buffer. */
+  d->pc = d->last;
+
+  if (d->checkpoint == d->residual) {
+    /* Checkpoint was in residual buf; append user byte(s) to residual buf. */
+    UPB_ASSERT((d->residual_end - d->residual) + d->size_param <=
+           sizeof(d->residual));
+    if (!in_residual_buf(d, d->ptr)) {
+      d->bufstart_ofs -= (d->residual_end - d->residual);
+    }
+    memcpy(d->residual_end, d->buf_param, d->size_param);
+    d->residual_end += d->size_param;
+  } else {
+    /* Checkpoint was in user buf; old residual bytes not needed. */
+    size_t save;
+    UPB_ASSERT(!in_residual_buf(d, d->checkpoint));
+
+    d->ptr = d->checkpoint;
+    save = curbufleft(d);
+    UPB_ASSERT(save <= sizeof(d->residual));
+    memcpy(d->residual, d->ptr, save);
+    d->residual_end = d->residual + save;
+    d->bufstart_ofs = offset(d);
+  }
+
+  switchtobuf(d, d->residual, d->residual_end);
+  return d->size_param;
+}
+
+/* Copies the next "bytes" bytes into "buf" and advances the stream.
+ * Requires that this many bytes are available in the current buffer. */
+UPB_FORCEINLINE static void consumebytes(upb_pbdecoder *d, void *buf,
+                                         size_t bytes) {
+  UPB_ASSERT(bytes <= curbufleft(d));
+  memcpy(buf, d->ptr, bytes);
+  advance(d, bytes);
+}
+
+/* Slow path for getting the next "bytes" bytes, regardless of whether they are
+ * available in the current buffer or not.  Returns a status code as described
+ * in decoder.int.h. */
+UPB_NOINLINE static int32_t getbytes_slow(upb_pbdecoder *d, void *buf,
+                                          size_t bytes) {
+  const size_t avail = curbufleft(d);
+  consumebytes(d, buf, avail);
+  bytes -= avail;
+  UPB_ASSERT(bytes > 0);
+  if (in_residual_buf(d, d->ptr)) {
+    advancetobuf(d, d->buf_param, d->size_param);
+  }
+  if (curbufleft(d) >= bytes) {
+    consumebytes(d, (char *)buf + avail, bytes);
+    return DECODE_OK;
+  } else if (d->data_end == d->delim_end) {
+    seterr(d, "Submessage ended in the middle of a value or group");
+    return upb_pbdecoder_suspend(d);
+  } else {
+    return suspend_save(d);
+  }
+}
+
+/* Gets the next "bytes" bytes, regardless of whether they are available in the
+ * current buffer or not.  Returns a status code as described in decoder.int.h.
+ */
+UPB_FORCEINLINE static int32_t getbytes(upb_pbdecoder *d, void *buf,
+                                        size_t bytes) {
+  if (curbufleft(d) >= bytes) {
+    /* Buffer has enough data to satisfy. */
+    consumebytes(d, buf, bytes);
+    return DECODE_OK;
+  } else {
+    return getbytes_slow(d, buf, bytes);
+  }
+}
+
+UPB_NOINLINE static size_t peekbytes_slow(upb_pbdecoder *d, void *buf,
+                                          size_t bytes) {
+  size_t ret = curbufleft(d);
+  memcpy(buf, d->ptr, ret);
+  if (in_residual_buf(d, d->ptr)) {
+    size_t copy = UPB_MIN(bytes - ret, d->size_param);
+    memcpy((char *)buf + ret, d->buf_param, copy);
+    ret += copy;
+  }
+  return ret;
+}
+
+UPB_FORCEINLINE static size_t peekbytes(upb_pbdecoder *d, void *buf,
+                                        size_t bytes) {
+  if (curbufleft(d) >= bytes) {
+    memcpy(buf, d->ptr, bytes);
+    return bytes;
+  } else {
+    return peekbytes_slow(d, buf, bytes);
+  }
+}
+
+
+/* Decoding of wire types *****************************************************/
+
+/* Slow path for decoding a varint from the current buffer position.
+ * Returns a status code as described in decoder.int.h. */
+UPB_NOINLINE int32_t upb_pbdecoder_decode_varint_slow(upb_pbdecoder *d,
+                                                      uint64_t *u64) {
+  uint8_t byte = 0x80;
+  int bitpos;
+  *u64 = 0;
+  for(bitpos = 0; bitpos < 70 && (byte & 0x80); bitpos += 7) {
+    CHECK_RETURN(getbytes(d, &byte, 1));
+    *u64 |= (uint64_t)(byte & 0x7F) << bitpos;
+  }
+  if(bitpos == 70 && (byte & 0x80)) {
+    seterr(d, kUnterminatedVarint);
+    return upb_pbdecoder_suspend(d);
+  }
+  return DECODE_OK;
+}
+
+/* Decodes a varint from the current buffer position.
+ * Returns a status code as described in decoder.int.h. */
+UPB_FORCEINLINE static int32_t decode_varint(upb_pbdecoder *d, uint64_t *u64) {
+  if (curbufleft(d) > 0 && !(*d->ptr & 0x80)) {
+    *u64 = *d->ptr;
+    advance(d, 1);
+    return DECODE_OK;
+  } else if (curbufleft(d) >= 10) {
+    /* Fast case. */
+    upb_decoderet r = upb_vdecode_fast(d->ptr);
+    if (r.p == NULL) {
+      seterr(d, kUnterminatedVarint);
+      return upb_pbdecoder_suspend(d);
+    }
+    advance(d, r.p - d->ptr);
+    *u64 = r.val;
+    return DECODE_OK;
+  } else {
+    /* Slow case -- varint spans buffer seam. */
+    return upb_pbdecoder_decode_varint_slow(d, u64);
+  }
+}
+
+/* Decodes a 32-bit varint from the current buffer position.
+ * Returns a status code as described in decoder.int.h. */
+UPB_FORCEINLINE static int32_t decode_v32(upb_pbdecoder *d, uint32_t *u32) {
+  uint64_t u64;
+  int32_t ret = decode_varint(d, &u64);
+  if (ret >= 0) return ret;
+  if (u64 > UINT32_MAX) {
+    seterr(d, "Unterminated 32-bit varint");
+    /* TODO(haberman) guarantee that this function return is >= 0 somehow,
+     * so we know this path will always be treated as error by our caller.
+     * Right now the size_t -> int32_t can overflow and produce negative values.
+     */
+    *u32 = 0;
+    return upb_pbdecoder_suspend(d);
+  }
+  *u32 = u64;
+  return DECODE_OK;
+}
+
+/* Decodes a fixed32 from the current buffer position.
+ * Returns a status code as described in decoder.int.h.
+ * TODO: proper byte swapping for big-endian machines. */
+UPB_FORCEINLINE static int32_t decode_fixed32(upb_pbdecoder *d, uint32_t *u32) {
+  return getbytes(d, u32, 4);
+}
+
+/* Decodes a fixed64 from the current buffer position.
+ * Returns a status code as described in decoder.int.h.
+ * TODO: proper byte swapping for big-endian machines. */
+UPB_FORCEINLINE static int32_t decode_fixed64(upb_pbdecoder *d, uint64_t *u64) {
+  return getbytes(d, u64, 8);
+}
+
+/* Non-static versions of the above functions.
+ * These are called by the JIT for fallback paths. */
+int32_t upb_pbdecoder_decode_f32(upb_pbdecoder *d, uint32_t *u32) {
+  return decode_fixed32(d, u32);
+}
+
+int32_t upb_pbdecoder_decode_f64(upb_pbdecoder *d, uint64_t *u64) {
+  return decode_fixed64(d, u64);
+}
+
+static double as_double(uint64_t n) { double d; memcpy(&d, &n, 8); return d; }
+static float  as_float(uint32_t n)  { float  f; memcpy(&f, &n, 4); return f; }
+
+/* Pushes a frame onto the decoder stack. */
+static bool decoder_push(upb_pbdecoder *d, uint64_t end) {
+  upb_pbdecoder_frame *fr = d->top;
+
+  if (end > fr->end_ofs) {
+    seterr(d, kPbDecoderSubmessageTooLong);
+    return false;
+  } else if (fr == d->limit) {
+    seterr(d, kPbDecoderStackOverflow);
+    return false;
+  }
+
+  fr++;
+  fr->end_ofs = end;
+  fr->dispatch = NULL;
+  fr->groupnum = 0;
+  d->top = fr;
+  return true;
+}
+
+static bool pushtagdelim(upb_pbdecoder *d, uint32_t arg) {
+  /* While we expect to see an "end" tag (either ENDGROUP or a non-sequence
+   * field number) prior to hitting any enclosing submessage end, pushing our
+   * existing delim end prevents us from continuing to parse values from a
+   * corrupt proto that doesn't give us an END tag in time. */
+  if (!decoder_push(d, d->top->end_ofs))
+    return false;
+  d->top->groupnum = arg;
+  return true;
+}
+
+/* Pops a frame from the decoder stack. */
+static void decoder_pop(upb_pbdecoder *d) { d->top--; }
+
+UPB_NOINLINE int32_t upb_pbdecoder_checktag_slow(upb_pbdecoder *d,
+                                                 uint64_t expected) {
+  uint64_t data = 0;
+  size_t bytes = upb_value_size(expected);
+  size_t read = peekbytes(d, &data, bytes);
+  if (read == bytes && data == expected) {
+    /* Advance past matched bytes. */
+    int32_t ok = getbytes(d, &data, read);
+    UPB_ASSERT(ok < 0);
+    return DECODE_OK;
+  } else if (read < bytes && memcmp(&data, &expected, read) == 0) {
+    return suspend_save(d);
+  } else {
+    return DECODE_MISMATCH;
+  }
+}
+
+int32_t upb_pbdecoder_skipunknown(upb_pbdecoder *d, int32_t fieldnum,
+                                  uint8_t wire_type) {
+  if (fieldnum >= 0)
+    goto have_tag;
+
+  while (true) {
+    uint32_t tag;
+    CHECK_RETURN(decode_v32(d, &tag));
+    wire_type = tag & 0x7;
+    fieldnum = tag >> 3;
+
+have_tag:
+    if (fieldnum == 0) {
+      seterr(d, "Saw invalid field number (0)");
+      return upb_pbdecoder_suspend(d);
+    }
+
+    switch (wire_type) {
+      case UPB_WIRE_TYPE_32BIT:
+        CHECK_RETURN(skip(d, 4));
+        break;
+      case UPB_WIRE_TYPE_64BIT:
+        CHECK_RETURN(skip(d, 8));
+        break;
+      case UPB_WIRE_TYPE_VARINT: {
+        uint64_t u64;
+        CHECK_RETURN(decode_varint(d, &u64));
+        break;
+      }
+      case UPB_WIRE_TYPE_DELIMITED: {
+        uint32_t len;
+        CHECK_RETURN(decode_v32(d, &len));
+        CHECK_RETURN(skip(d, len));
+        break;
+      }
+      case UPB_WIRE_TYPE_START_GROUP:
+        CHECK_SUSPEND(pushtagdelim(d, -fieldnum));
+        break;
+      case UPB_WIRE_TYPE_END_GROUP:
+        if (fieldnum == -d->top->groupnum) {
+          decoder_pop(d);
+        } else if (fieldnum == d->top->groupnum) {
+          return DECODE_ENDGROUP;
+        } else {
+          seterr(d, "Unmatched ENDGROUP tag.");
+          return upb_pbdecoder_suspend(d);
+        }
+        break;
+      default:
+        seterr(d, "Invalid wire type");
+        return upb_pbdecoder_suspend(d);
+    }
+
+    if (d->top->groupnum >= 0) {
+      /* TODO: More code needed for handling unknown groups. */
+      upb_sink_putunknown(&d->top->sink, d->checkpoint, d->ptr - d->checkpoint);
+      return DECODE_OK;
+    }
+
+    /* Unknown group -- continue looping over unknown fields. */
+    checkpoint(d);
+  }
+}
+
+static void goto_endmsg(upb_pbdecoder *d) {
+  upb_value v;
+  bool found = upb_inttable_lookup32(d->top->dispatch, DISPATCH_ENDMSG, &v);
+  UPB_ASSERT(found);
+  d->pc = d->top->base + upb_value_getuint64(v);
+}
+
+/* Parses a tag and jumps to the corresponding bytecode instruction for this
+ * field.
+ *
+ * If the tag is unknown (or the wire type doesn't match), parses the field as
+ * unknown.  If the tag is a valid ENDGROUP tag, jumps to the bytecode
+ * instruction for the end of message. */
+static int32_t dispatch(upb_pbdecoder *d) {
+  upb_inttable *dispatch = d->top->dispatch;
+  uint32_t tag;
+  uint8_t wire_type;
+  uint32_t fieldnum;
+  upb_value val;
+  int32_t retval;
+
+  /* Decode tag. */
+  CHECK_RETURN(decode_v32(d, &tag));
+  wire_type = tag & 0x7;
+  fieldnum = tag >> 3;
+
+  /* Lookup tag.  Because of packed/non-packed compatibility, we have to
+   * check the wire type against two possibilities. */
+  if (fieldnum != DISPATCH_ENDMSG &&
+      upb_inttable_lookup32(dispatch, fieldnum, &val)) {
+    uint64_t v = upb_value_getuint64(val);
+    if (wire_type == (v & 0xff)) {
+      d->pc = d->top->base + (v >> 16);
+      return DECODE_OK;
+    } else if (wire_type == ((v >> 8) & 0xff)) {
+      bool found =
+          upb_inttable_lookup(dispatch, fieldnum + UPB_MAX_FIELDNUMBER, &val);
+      UPB_ASSERT(found);
+      d->pc = d->top->base + upb_value_getuint64(val);
+      return DECODE_OK;
+    }
+  }
+
+  /* We have some unknown fields (or ENDGROUP) to parse.  The DISPATCH or TAG
+   * bytecode that triggered this is preceded by a CHECKDELIM bytecode which
+   * we need to back up to, so that when we're done skipping unknown data we
+   * can re-check the delimited end. */
+  d->last--;  /* Necessary if we get suspended */
+  d->pc = d->last;
+  UPB_ASSERT(getop(*d->last) == OP_CHECKDELIM);
+
+  /* Unknown field or ENDGROUP. */
+  retval = upb_pbdecoder_skipunknown(d, fieldnum, wire_type);
+
+  CHECK_RETURN(retval);
+
+  if (retval == DECODE_ENDGROUP) {
+    goto_endmsg(d);
+    return DECODE_OK;
+  }
+
+  return DECODE_OK;
+}
+
+/* Callers know that the stack is more than one deep because the opcodes that
+ * call this only occur after PUSH operations. */
+upb_pbdecoder_frame *outer_frame(upb_pbdecoder *d) {
+  UPB_ASSERT(d->top != d->stack);
+  return d->top - 1;
+}
+
+
+/* The main decoding loop *****************************************************/
+
+/* The main decoder VM function.  Uses traditional bytecode dispatch loop with a
+ * switch() statement. */
+size_t run_decoder_vm(upb_pbdecoder *d, const mgroup *group,
+                      const upb_bufhandle* handle) {
+
+#define VMCASE(op, code) \
+  case op: { code; if (consumes_input(op)) checkpoint(d); break; }
+#define PRIMITIVE_OP(type, wt, name, convfunc, ctype) \
+  VMCASE(OP_PARSE_ ## type, { \
+    ctype val; \
+    CHECK_RETURN(decode_ ## wt(d, &val)); \
+    upb_sink_put ## name(&d->top->sink, arg, (convfunc)(val)); \
+  })
+
+  while(1) {
+    int32_t instruction;
+    opcode op;
+    uint32_t arg;
+    int32_t longofs;
+
+    d->last = d->pc;
+    instruction = *d->pc++;
+    op = getop(instruction);
+    arg = instruction >> 8;
+    longofs = arg;
+    UPB_ASSERT(d->ptr != d->residual_end);
+    UPB_UNUSED(group);
+#ifdef UPB_DUMP_BYTECODE
+    fprintf(stderr, "s_ofs=%d buf_ofs=%d data_rem=%d buf_rem=%d delim_rem=%d "
+                    "%x %s (%d)\n",
+            (int)offset(d),
+            (int)(d->ptr - d->buf),
+            (int)(d->data_end - d->ptr),
+            (int)(d->end - d->ptr),
+            (int)((d->top->end_ofs - d->bufstart_ofs) - (d->ptr - d->buf)),
+            (int)(d->pc - 1 - group->bytecode),
+            upb_pbdecoder_getopname(op),
+            arg);
+#endif
+    switch (op) {
+      /* Technically, we are losing data if we see a 32-bit varint that is not
+       * properly sign-extended.  We could detect this and error about the data
+       * loss, but proto2 does not do this, so we pass. */
+      PRIMITIVE_OP(INT32,    varint,  int32,  int32_t,      uint64_t)
+      PRIMITIVE_OP(INT64,    varint,  int64,  int64_t,      uint64_t)
+      PRIMITIVE_OP(UINT32,   varint,  uint32, uint32_t,     uint64_t)
+      PRIMITIVE_OP(UINT64,   varint,  uint64, uint64_t,     uint64_t)
+      PRIMITIVE_OP(FIXED32,  fixed32, uint32, uint32_t,     uint32_t)
+      PRIMITIVE_OP(FIXED64,  fixed64, uint64, uint64_t,     uint64_t)
+      PRIMITIVE_OP(SFIXED32, fixed32, int32,  int32_t,      uint32_t)
+      PRIMITIVE_OP(SFIXED64, fixed64, int64,  int64_t,      uint64_t)
+      PRIMITIVE_OP(BOOL,     varint,  bool,   bool,         uint64_t)
+      PRIMITIVE_OP(DOUBLE,   fixed64, double, as_double,    uint64_t)
+      PRIMITIVE_OP(FLOAT,    fixed32, float,  as_float,     uint32_t)
+      PRIMITIVE_OP(SINT32,   varint,  int32,  upb_zzdec_32, uint64_t)
+      PRIMITIVE_OP(SINT64,   varint,  int64,  upb_zzdec_64, uint64_t)
+
+      VMCASE(OP_SETDISPATCH,
+        d->top->base = d->pc - 1;
+        memcpy(&d->top->dispatch, d->pc, sizeof(void*));
+        d->pc += sizeof(void*) / sizeof(uint32_t);
+      )
+      VMCASE(OP_STARTMSG,
+        CHECK_SUSPEND(upb_sink_startmsg(&d->top->sink));
+      )
+      VMCASE(OP_ENDMSG,
+        CHECK_SUSPEND(upb_sink_endmsg(&d->top->sink, d->status));
+      )
+      VMCASE(OP_STARTSEQ,
+        upb_pbdecoder_frame *outer = outer_frame(d);
+        CHECK_SUSPEND(upb_sink_startseq(&outer->sink, arg, &d->top->sink));
+      )
+      VMCASE(OP_ENDSEQ,
+        CHECK_SUSPEND(upb_sink_endseq(&d->top->sink, arg));
+      )
+      VMCASE(OP_STARTSUBMSG,
+        upb_pbdecoder_frame *outer = outer_frame(d);
+        CHECK_SUSPEND(upb_sink_startsubmsg(&outer->sink, arg, &d->top->sink));
+      )
+      VMCASE(OP_ENDSUBMSG,
+        CHECK_SUSPEND(upb_sink_endsubmsg(&d->top->sink, arg));
+      )
+      VMCASE(OP_STARTSTR,
+        uint32_t len = delim_remaining(d);
+        upb_pbdecoder_frame *outer = outer_frame(d);
+        CHECK_SUSPEND(upb_sink_startstr(&outer->sink, arg, len, &d->top->sink));
+        if (len == 0) {
+          d->pc++;  /* Skip OP_STRING. */
+        }
+      )
+      VMCASE(OP_STRING,
+        uint32_t len = curbufleft(d);
+        size_t n = upb_sink_putstring(&d->top->sink, arg, d->ptr, len, handle);
+        if (n > len) {
+          if (n > delim_remaining(d)) {
+            seterr(d, "Tried to skip past end of string.");
+            return upb_pbdecoder_suspend(d);
+          } else {
+            int32_t ret = skip(d, n);
+            /* This shouldn't return DECODE_OK, because n > len. */
+            UPB_ASSERT(ret >= 0);
+            return ret;
+          }
+        }
+        advance(d, n);
+        if (n < len || d->delim_end == NULL) {
+          /* We aren't finished with this string yet. */
+          d->pc--;  /* Repeat OP_STRING. */
+          if (n > 0) checkpoint(d);
+          return upb_pbdecoder_suspend(d);
+        }
+      )
+      VMCASE(OP_ENDSTR,
+        CHECK_SUSPEND(upb_sink_endstr(&d->top->sink, arg));
+      )
+      VMCASE(OP_PUSHTAGDELIM,
+        CHECK_SUSPEND(pushtagdelim(d, arg));
+      )
+      VMCASE(OP_SETBIGGROUPNUM,
+        d->top->groupnum = *d->pc++;
+      )
+      VMCASE(OP_POP,
+        UPB_ASSERT(d->top > d->stack);
+        decoder_pop(d);
+      )
+      VMCASE(OP_PUSHLENDELIM,
+        uint32_t len;
+        CHECK_RETURN(decode_v32(d, &len));
+        CHECK_SUSPEND(decoder_push(d, offset(d) + len));
+        set_delim_end(d);
+      )
+      VMCASE(OP_SETDELIM,
+        set_delim_end(d);
+      )
+      VMCASE(OP_CHECKDELIM,
+        /* We are guaranteed of this assert because we never allow ourselves to
+         * consume bytes beyond data_end, which covers delim_end when non-NULL.
+         */
+        UPB_ASSERT(!(d->delim_end && d->ptr > d->delim_end));
+        if (d->ptr == d->delim_end)
+          d->pc += longofs;
+      )
+      VMCASE(OP_CALL,
+        d->callstack[d->call_len++] = d->pc;
+        d->pc += longofs;
+      )
+      VMCASE(OP_RET,
+        UPB_ASSERT(d->call_len > 0);
+        d->pc = d->callstack[--d->call_len];
+      )
+      VMCASE(OP_BRANCH,
+        d->pc += longofs;
+      )
+      VMCASE(OP_TAG1,
+        uint8_t expected;
+        CHECK_SUSPEND(curbufleft(d) > 0);
+        expected = (arg >> 8) & 0xff;
+        if (*d->ptr == expected) {
+          advance(d, 1);
+        } else {
+          int8_t shortofs;
+         badtag:
+          shortofs = arg;
+          if (shortofs == LABEL_DISPATCH) {
+            CHECK_RETURN(dispatch(d));
+          } else {
+            d->pc += shortofs;
+            break; /* Avoid checkpoint(). */
+          }
+        }
+      )
+      VMCASE(OP_TAG2,
+        uint16_t expected;
+        CHECK_SUSPEND(curbufleft(d) > 0);
+        expected = (arg >> 8) & 0xffff;
+        if (curbufleft(d) >= 2) {
+          uint16_t actual;
+          memcpy(&actual, d->ptr, 2);
+          if (expected == actual) {
+            advance(d, 2);
+          } else {
+            goto badtag;
+          }
+        } else {
+          int32_t result = upb_pbdecoder_checktag_slow(d, expected);
+          if (result == DECODE_MISMATCH) goto badtag;
+          if (result >= 0) return result;
+        }
+      )
+      VMCASE(OP_TAGN, {
+        uint64_t expected;
+        int32_t result;
+        memcpy(&expected, d->pc, 8);
+        d->pc += 2;
+        result = upb_pbdecoder_checktag_slow(d, expected);
+        if (result == DECODE_MISMATCH) goto badtag;
+        if (result >= 0) return result;
+      })
+      VMCASE(OP_DISPATCH, {
+        CHECK_RETURN(dispatch(d));
+      })
+      VMCASE(OP_HALT, {
+        return d->size_param;
+      })
+    }
+  }
+}
+
+
+/* BytesHandler handlers ******************************************************/
+
+void *upb_pbdecoder_startbc(void *closure, const void *pc, size_t size_hint) {
+  upb_pbdecoder *d = closure;
+  UPB_UNUSED(size_hint);
+  d->top->end_ofs = UINT64_MAX;
+  d->bufstart_ofs = 0;
+  d->call_len = 1;
+  d->callstack[0] = &halt;
+  d->pc = pc;
+  d->skip = 0;
+  return d;
+}
+
+void *upb_pbdecoder_startjit(void *closure, const void *hd, size_t size_hint) {
+  upb_pbdecoder *d = closure;
+  UPB_UNUSED(hd);
+  UPB_UNUSED(size_hint);
+  d->top->end_ofs = UINT64_MAX;
+  d->bufstart_ofs = 0;
+  d->call_len = 0;
+  d->skip = 0;
+  return d;
+}
+
+bool upb_pbdecoder_end(void *closure, const void *handler_data) {
+  upb_pbdecoder *d = closure;
+  const upb_pbdecodermethod *method = handler_data;
+  uint64_t end;
+  char dummy;
+
+  if (d->residual_end > d->residual) {
+    seterr(d, "Unexpected EOF: decoder still has buffered unparsed data");
+    return false;
+  }
+
+  if (d->skip) {
+    seterr(d, "Unexpected EOF inside skipped data");
+    return false;
+  }
+
+  if (d->top->end_ofs != UINT64_MAX) {
+    seterr(d, "Unexpected EOF inside delimited string");
+    return false;
+  }
+
+  /* The user's end() call indicates that the message ends here. */
+  end = offset(d);
+  d->top->end_ofs = end;
+
+#ifdef UPB_USE_JIT_X64
+  if (method->is_native_) {
+    const mgroup *group = (const mgroup*)method->group;
+    if (d->top != d->stack)
+      d->stack->end_ofs = 0;
+    group->jit_code(closure, method->code_base.ptr, &dummy, 0, NULL);
+  } else
+#endif
+  {
+    const uint32_t *p = d->pc;
+    d->stack->end_ofs = end;
+    /* Check the previous bytecode, but guard against beginning. */
+    if (p != method->code_base.ptr) p--;
+    if (getop(*p) == OP_CHECKDELIM) {
+      /* Rewind from OP_TAG* to OP_CHECKDELIM. */
+      UPB_ASSERT(getop(*d->pc) == OP_TAG1 ||
+             getop(*d->pc) == OP_TAG2 ||
+             getop(*d->pc) == OP_TAGN ||
+             getop(*d->pc) == OP_DISPATCH);
+      d->pc = p;
+    }
+    upb_pbdecoder_decode(closure, handler_data, &dummy, 0, NULL);
+  }
+
+  if (d->call_len != 0) {
+    seterr(d, "Unexpected EOF inside submessage or group");
+    return false;
+  }
+
+  return true;
+}
+
+size_t upb_pbdecoder_decode(void *decoder, const void *group, const char *buf,
+                            size_t size, const upb_bufhandle *handle) {
+  int32_t result = upb_pbdecoder_resume(decoder, NULL, buf, size, handle);
+
+  if (result == DECODE_ENDGROUP) goto_endmsg(decoder);
+  CHECK_RETURN(result);
+
+  return run_decoder_vm(decoder, group, handle);
+}
+
+
+/* Public API *****************************************************************/
+
+void upb_pbdecoder_reset(upb_pbdecoder *d) {
+  d->top = d->stack;
+  d->top->groupnum = 0;
+  d->ptr = d->residual;
+  d->buf = d->residual;
+  d->end = d->residual;
+  d->residual_end = d->residual;
+}
+
+upb_pbdecoder *upb_pbdecoder_create(upb_env *e, const upb_pbdecodermethod *m,
+                                    upb_sink *sink) {
+  const size_t default_max_nesting = 64;
+#ifndef NDEBUG
+  size_t size_before = upb_env_bytesallocated(e);
+#endif
+
+  upb_pbdecoder *d = upb_env_malloc(e, sizeof(upb_pbdecoder));
+  if (!d) return NULL;
+
+  d->method_ = m;
+  d->callstack = upb_env_malloc(e, callstacksize(d, default_max_nesting));
+  d->stack = upb_env_malloc(e, stacksize(d, default_max_nesting));
+  if (!d->stack || !d->callstack) {
+    return NULL;
+  }
+
+  d->env = e;
+  d->limit = d->stack + default_max_nesting - 1;
+  d->stack_size = default_max_nesting;
+  d->status = NULL;
+
+  upb_pbdecoder_reset(d);
+  upb_bytessink_reset(&d->input_, &m->input_handler_, d);
+
+  UPB_ASSERT(sink);
+  if (d->method_->dest_handlers_) {
+    if (sink->handlers != d->method_->dest_handlers_)
+      return NULL;
+  }
+  upb_sink_reset(&d->top->sink, sink->handlers, sink->closure);
+
+  /* If this fails, increase the value in decoder.h. */
+  UPB_ASSERT_DEBUGVAR(upb_env_bytesallocated(e) - size_before <=
+                      UPB_PB_DECODER_SIZE);
+  return d;
+}
+
+uint64_t upb_pbdecoder_bytesparsed(const upb_pbdecoder *d) {
+  return offset(d);
+}
+
+const upb_pbdecodermethod *upb_pbdecoder_method(const upb_pbdecoder *d) {
+  return d->method_;
+}
+
+upb_bytessink *upb_pbdecoder_input(upb_pbdecoder *d) {
+  return &d->input_;
+}
+
+size_t upb_pbdecoder_maxnesting(const upb_pbdecoder *d) {
+  return d->stack_size;
+}
+
+bool upb_pbdecoder_setmaxnesting(upb_pbdecoder *d, size_t max) {
+  UPB_ASSERT(d->top >= d->stack);
+
+  if (max < (size_t)(d->top - d->stack)) {
+    /* Can't set a limit smaller than what we are currently at. */
+    return false;
+  }
+
+  if (max > d->stack_size) {
+    /* Need to reallocate stack and callstack to accommodate. */
+    size_t old_size = stacksize(d, d->stack_size);
+    size_t new_size = stacksize(d, max);
+    void *p = upb_env_realloc(d->env, d->stack, old_size, new_size);
+    if (!p) {
+      return false;
+    }
+    d->stack = p;
+
+    old_size = callstacksize(d, d->stack_size);
+    new_size = callstacksize(d, max);
+    p = upb_env_realloc(d->env, d->callstack, old_size, new_size);
+    if (!p) {
+      return false;
+    }
+    d->callstack = p;
+
+    d->stack_size = max;
+  }
+
+  d->limit = d->stack + max - 1;
+  return true;
+}
+/*
+** upb::Encoder
+**
+** Since we are implementing pure handlers (ie. without any out-of-band access
+** to pre-computed lengths), we have to buffer all submessages before we can
+** emit even their first byte.
+**
+** Not knowing the size of submessages also means we can't write a perfect
+** zero-copy implementation, even with buffering.  Lengths are stored as
+** varints, which means that we don't know how many bytes to reserve for the
+** length until we know what the length is.
+**
+** This leaves us with three main choices:
+**
+** 1. buffer all submessage data in a temporary buffer, then copy it exactly
+**    once into the output buffer.
+**
+** 2. attempt to buffer data directly into the output buffer, estimating how
+**    many bytes each length will take.  When our guesses are wrong, use
+**    memmove() to grow or shrink the allotted space.
+**
+** 3. buffer directly into the output buffer, allocating a max length
+**    ahead-of-time for each submessage length.  If we overallocated, we waste
+**    space, but no memcpy() or memmove() is required.  This approach requires
+**    defining a maximum size for submessages and rejecting submessages that
+**    exceed that size.
+**
+** (2) and (3) have the potential to have better performance, but they are more
+** complicated and subtle to implement:
+**
+**   (3) requires making an arbitrary choice of the maximum message size; it
+**       wastes space when submessages are shorter than this and fails
+**       completely when they are longer.  This makes it more finicky and
+**       requires configuration based on the input.  It also makes it impossible
+**       to perfectly match the output of reference encoders that always use the
+**       optimal amount of space for each length.
+**
+**   (2) requires guessing the the size upfront, and if multiple lengths are
+**       guessed wrong the minimum required number of memmove() operations may
+**       be complicated to compute correctly.  Implemented properly, it may have
+**       a useful amortized or average cost, but more investigation is required
+**       to determine this and what the optimal algorithm is to achieve it.
+**
+**   (1) makes you always pay for exactly one copy, but its implementation is
+**       the simplest and its performance is predictable.
+**
+** So for now, we implement (1) only.  If we wish to optimize later, we should
+** be able to do it without affecting users.
+**
+** The strategy is to buffer the segments of data that do *not* depend on
+** unknown lengths in one buffer, and keep a separate buffer of segment pointers
+** and lengths.  When the top-level submessage ends, we can go beginning to end,
+** alternating the writing of lengths with memcpy() of the rest of the data.
+** At the top level though, no buffering is required.
+*/
+
+
+
+/* The output buffer is divided into segments; a segment is a string of data
+ * that is "ready to go" -- it does not need any varint lengths inserted into
+ * the middle.  The seams between segments are where varints will be inserted
+ * once they are known.
+ *
+ * We also use the concept of a "run", which is a range of encoded bytes that
+ * occur at a single submessage level.  Every segment contains one or more runs.
+ *
+ * A segment can span messages.  Consider:
+ *
+ *                  .--Submessage lengths---------.
+ *                  |       |                     |
+ *                  |       V                     V
+ *                  V      | |---------------    | |-----------------
+ * Submessages:    | |-----------------------------------------------
+ * Top-level msg: ------------------------------------------------------------
+ *
+ * Segments:          -----   -------------------   -----------------
+ * Runs:              *----   *--------------*---   *----------------
+ * (* marks the start)
+ *
+ * Note that the top-level menssage is not in any segment because it does not
+ * have any length preceding it.
+ *
+ * A segment is only interrupted when another length needs to be inserted.  So
+ * observe how the second segment spans both the inner submessage and part of
+ * the next enclosing message. */
+typedef struct {
+  uint32_t msglen;  /* The length to varint-encode before this segment. */
+  uint32_t seglen;  /* Length of the segment. */
+} upb_pb_encoder_segment;
+
+struct upb_pb_encoder {
+  upb_env *env;
+
+  /* Our input and output. */
+  upb_sink input_;
+  upb_bytessink *output_;
+
+  /* The "subclosure" -- used as the inner closure as part of the bytessink
+   * protocol. */
+  void *subc;
+
+  /* The output buffer and limit, and our current write position.  "buf"
+   * initially points to "initbuf", but is dynamically allocated if we need to
+   * grow beyond the initial size. */
+  char *buf, *ptr, *limit;
+
+  /* The beginning of the current run, or undefined if we are at the top
+   * level. */
+  char *runbegin;
+
+  /* The list of segments we are accumulating. */
+  upb_pb_encoder_segment *segbuf, *segptr, *seglimit;
+
+  /* The stack of enclosing submessages.  Each entry in the stack points to the
+   * segment where this submessage's length is being accumulated. */
+  int *stack, *top, *stacklimit;
+
+  /* Depth of startmsg/endmsg calls. */
+  int depth;
+};
+
+/* low-level buffering ********************************************************/
+
+/* Low-level functions for interacting with the output buffer. */
+
+/* TODO(haberman): handle pushback */
+static void putbuf(upb_pb_encoder *e, const char *buf, size_t len) {
+  size_t n = upb_bytessink_putbuf(e->output_, e->subc, buf, len, NULL);
+  UPB_ASSERT(n == len);
+}
+
+static upb_pb_encoder_segment *top(upb_pb_encoder *e) {
+  return &e->segbuf[*e->top];
+}
+
+/* Call to ensure that at least "bytes" bytes are available for writing at
+ * e->ptr.  Returns false if the bytes could not be allocated. */
+static bool reserve(upb_pb_encoder *e, size_t bytes) {
+  if ((size_t)(e->limit - e->ptr) < bytes) {
+    /* Grow buffer. */
+    char *new_buf;
+    size_t needed = bytes + (e->ptr - e->buf);
+    size_t old_size = e->limit - e->buf;
+
+    size_t new_size = old_size;
+
+    while (new_size < needed) {
+      new_size *= 2;
+    }
+
+    new_buf = upb_env_realloc(e->env, e->buf, old_size, new_size);
+
+    if (new_buf == NULL) {
+      return false;
+    }
+
+    e->ptr = new_buf + (e->ptr - e->buf);
+    e->runbegin = new_buf + (e->runbegin - e->buf);
+    e->limit = new_buf + new_size;
+    e->buf = new_buf;
+  }
+
+  return true;
+}
+
+/* Call when "bytes" bytes have been writte at e->ptr.  The caller *must* have
+ * previously called reserve() with at least this many bytes. */
+static void encoder_advance(upb_pb_encoder *e, size_t bytes) {
+  UPB_ASSERT((size_t)(e->limit - e->ptr) >= bytes);
+  e->ptr += bytes;
+}
+
+/* Call when all of the bytes for a handler have been written.  Flushes the
+ * bytes if possible and necessary, returning false if this failed. */
+static bool commit(upb_pb_encoder *e) {
+  if (!e->top) {
+    /* We aren't inside a delimited region.  Flush our accumulated bytes to
+     * the output.
+     *
+     * TODO(haberman): in the future we may want to delay flushing for
+     * efficiency reasons. */
+    putbuf(e, e->buf, e->ptr - e->buf);
+    e->ptr = e->buf;
+  }
+
+  return true;
+}
+
+/* Writes the given bytes to the buffer, handling reserve/advance. */
+static bool encode_bytes(upb_pb_encoder *e, const void *data, size_t len) {
+  if (!reserve(e, len)) {
+    return false;
+  }
+
+  memcpy(e->ptr, data, len);
+  encoder_advance(e, len);
+  return true;
+}
+
+/* Finish the current run by adding the run totals to the segment and message
+ * length. */
+static void accumulate(upb_pb_encoder *e) {
+  size_t run_len;
+  UPB_ASSERT(e->ptr >= e->runbegin);
+  run_len = e->ptr - e->runbegin;
+  e->segptr->seglen += run_len;
+  top(e)->msglen += run_len;
+  e->runbegin = e->ptr;
+}
+
+/* Call to indicate the start of delimited region for which the full length is
+ * not yet known.  All data will be buffered until the length is known.
+ * Delimited regions may be nested; their lengths will all be tracked properly. */
+static bool start_delim(upb_pb_encoder *e) {
+  if (e->top) {
+    /* We are already buffering, advance to the next segment and push it on the
+     * stack. */
+    accumulate(e);
+
+    if (++e->top == e->stacklimit) {
+      /* TODO(haberman): grow stack? */
+      return false;
+    }
+
+    if (++e->segptr == e->seglimit) {
+      /* Grow segment buffer. */
+      size_t old_size =
+          (e->seglimit - e->segbuf) * sizeof(upb_pb_encoder_segment);
+      size_t new_size = old_size * 2;
+      upb_pb_encoder_segment *new_buf =
+          upb_env_realloc(e->env, e->segbuf, old_size, new_size);
+
+      if (new_buf == NULL) {
+        return false;
+      }
+
+      e->segptr = new_buf + (e->segptr - e->segbuf);
+      e->seglimit = new_buf + (new_size / sizeof(upb_pb_encoder_segment));
+      e->segbuf = new_buf;
+    }
+  } else {
+    /* We were previously at the top level, start buffering. */
+    e->segptr = e->segbuf;
+    e->top = e->stack;
+    e->runbegin = e->ptr;
+  }
+
+  *e->top = e->segptr - e->segbuf;
+  e->segptr->seglen = 0;
+  e->segptr->msglen = 0;
+
+  return true;
+}
+
+/* Call to indicate the end of a delimited region.  We now know the length of
+ * the delimited region.  If we are not nested inside any other delimited
+ * regions, we can now emit all of the buffered data we accumulated. */
+static bool end_delim(upb_pb_encoder *e) {
+  size_t msglen;
+  accumulate(e);
+  msglen = top(e)->msglen;
+
+  if (e->top == e->stack) {
+    /* All lengths are now available, emit all buffered data. */
+    char buf[UPB_PB_VARINT_MAX_LEN];
+    upb_pb_encoder_segment *s;
+    const char *ptr = e->buf;
+    for (s = e->segbuf; s <= e->segptr; s++) {
+      size_t lenbytes = upb_vencode64(s->msglen, buf);
+      putbuf(e, buf, lenbytes);
+      putbuf(e, ptr, s->seglen);
+      ptr += s->seglen;
+    }
+
+    e->ptr = e->buf;
+    e->top = NULL;
+  } else {
+    /* Need to keep buffering; propagate length info into enclosing
+     * submessages. */
+    --e->top;
+    top(e)->msglen += msglen + upb_varint_size(msglen);
+  }
+
+  return true;
+}
+
+
+/* tag_t **********************************************************************/
+
+/* A precomputed (pre-encoded) tag and length. */
+
+typedef struct {
+  uint8_t bytes;
+  char tag[7];
+} tag_t;
+
+/* Allocates a new tag for this field, and sets it in these handlerattr. */
+static void new_tag(upb_handlers *h, const upb_fielddef *f, upb_wiretype_t wt,
+                    upb_handlerattr *attr) {
+  uint32_t n = upb_fielddef_number(f);
+
+  tag_t *tag = upb_gmalloc(sizeof(tag_t));
+  tag->bytes = upb_vencode64((n << 3) | wt, tag->tag);
+
+  upb_handlerattr_init(attr);
+  upb_handlerattr_sethandlerdata(attr, tag);
+  upb_handlers_addcleanup(h, tag, upb_gfree);
+}
+
+static bool encode_tag(upb_pb_encoder *e, const tag_t *tag) {
+  return encode_bytes(e, tag->tag, tag->bytes);
+}
+
+
+/* encoding of wire types *****************************************************/
+
+static bool encode_fixed64(upb_pb_encoder *e, uint64_t val) {
+  /* TODO(haberman): byte-swap for big endian. */
+  return encode_bytes(e, &val, sizeof(uint64_t));
+}
+
+static bool encode_fixed32(upb_pb_encoder *e, uint32_t val) {
+  /* TODO(haberman): byte-swap for big endian. */
+  return encode_bytes(e, &val, sizeof(uint32_t));
+}
+
+static bool encode_varint(upb_pb_encoder *e, uint64_t val) {
+  if (!reserve(e, UPB_PB_VARINT_MAX_LEN)) {
+    return false;
+  }
+
+  encoder_advance(e, upb_vencode64(val, e->ptr));
+  return true;
+}
+
+static uint64_t dbl2uint64(double d) {
+  uint64_t ret;
+  memcpy(&ret, &d, sizeof(uint64_t));
+  return ret;
+}
+
+static uint32_t flt2uint32(float d) {
+  uint32_t ret;
+  memcpy(&ret, &d, sizeof(uint32_t));
+  return ret;
+}
+
+
+/* encoding of proto types ****************************************************/
+
+static bool startmsg(void *c, const void *hd) {
+  upb_pb_encoder *e = c;
+  UPB_UNUSED(hd);
+  if (e->depth++ == 0) {
+    upb_bytessink_start(e->output_, 0, &e->subc);
+  }
+  return true;
+}
+
+static bool endmsg(void *c, const void *hd, upb_status *status) {
+  upb_pb_encoder *e = c;
+  UPB_UNUSED(hd);
+  UPB_UNUSED(status);
+  if (--e->depth == 0) {
+    upb_bytessink_end(e->output_);
+  }
+  return true;
+}
+
+static void *encode_startdelimfield(void *c, const void *hd) {
+  bool ok = encode_tag(c, hd) && commit(c) && start_delim(c);
+  return ok ? c : UPB_BREAK;
+}
+
+static bool encode_unknown(void *c, const void *hd, const char *buf,
+                           size_t len) {
+  UPB_UNUSED(hd);
+  return encode_bytes(c, buf, len) && commit(c);
+}
+
+static bool encode_enddelimfield(void *c, const void *hd) {
+  UPB_UNUSED(hd);
+  return end_delim(c);
+}
+
+static void *encode_startgroup(void *c, const void *hd) {
+  return (encode_tag(c, hd) && commit(c)) ? c : UPB_BREAK;
+}
+
+static bool encode_endgroup(void *c, const void *hd) {
+  return encode_tag(c, hd) && commit(c);
+}
+
+static void *encode_startstr(void *c, const void *hd, size_t size_hint) {
+  UPB_UNUSED(size_hint);
+  return encode_startdelimfield(c, hd);
+}
+
+static size_t encode_strbuf(void *c, const void *hd, const char *buf,
+                            size_t len, const upb_bufhandle *h) {
+  UPB_UNUSED(hd);
+  UPB_UNUSED(h);
+  return encode_bytes(c, buf, len) ? len : 0;
+}
+
+#define T(type, ctype, convert, encode)                                  \
+  static bool encode_scalar_##type(void *e, const void *hd, ctype val) { \
+    return encode_tag(e, hd) && encode(e, (convert)(val)) && commit(e);  \
+  }                                                                      \
+  static bool encode_packed_##type(void *e, const void *hd, ctype val) { \
+    UPB_UNUSED(hd);                                                      \
+    return encode(e, (convert)(val));                                    \
+  }
+
+T(double,   double,   dbl2uint64,   encode_fixed64)
+T(float,    float,    flt2uint32,   encode_fixed32)
+T(int64,    int64_t,  uint64_t,     encode_varint)
+T(int32,    int32_t,  int64_t,      encode_varint)
+T(fixed64,  uint64_t, uint64_t,     encode_fixed64)
+T(fixed32,  uint32_t, uint32_t,     encode_fixed32)
+T(bool,     bool,     bool,         encode_varint)
+T(uint32,   uint32_t, uint32_t,     encode_varint)
+T(uint64,   uint64_t, uint64_t,     encode_varint)
+T(enum,     int32_t,  uint32_t,     encode_varint)
+T(sfixed32, int32_t,  uint32_t,     encode_fixed32)
+T(sfixed64, int64_t,  uint64_t,     encode_fixed64)
+T(sint32,   int32_t,  upb_zzenc_32, encode_varint)
+T(sint64,   int64_t,  upb_zzenc_64, encode_varint)
+
+#undef T
+
+
+/* code to build the handlers *************************************************/
+
+static void newhandlers_callback(const void *closure, upb_handlers *h) {
+  const upb_msgdef *m;
+  upb_msg_field_iter i;
+
+  UPB_UNUSED(closure);
+
+  upb_handlers_setstartmsg(h, startmsg, NULL);
+  upb_handlers_setendmsg(h, endmsg, NULL);
+  upb_handlers_setunknown(h, encode_unknown, NULL);
+
+  m = upb_handlers_msgdef(h);
+  for(upb_msg_field_begin(&i, m);
+      !upb_msg_field_done(&i);
+      upb_msg_field_next(&i)) {
+    const upb_fielddef *f = upb_msg_iter_field(&i);
+    bool packed = upb_fielddef_isseq(f) && upb_fielddef_isprimitive(f) &&
+                  upb_fielddef_packed(f);
+    upb_handlerattr attr;
+    upb_wiretype_t wt =
+        packed ? UPB_WIRE_TYPE_DELIMITED
+               : upb_pb_native_wire_types[upb_fielddef_descriptortype(f)];
+
+    /* Pre-encode the tag for this field. */
+    new_tag(h, f, wt, &attr);
+
+    if (packed) {
+      upb_handlers_setstartseq(h, f, encode_startdelimfield, &attr);
+      upb_handlers_setendseq(h, f, encode_enddelimfield, &attr);
+    }
+
+#define T(upper, lower, upbtype)                                     \
+  case UPB_DESCRIPTOR_TYPE_##upper:                                  \
+    if (packed) {                                                    \
+      upb_handlers_set##upbtype(h, f, encode_packed_##lower, &attr); \
+    } else {                                                         \
+      upb_handlers_set##upbtype(h, f, encode_scalar_##lower, &attr); \
+    }                                                                \
+    break;
+
+    switch (upb_fielddef_descriptortype(f)) {
+      T(DOUBLE,   double,   double);
+      T(FLOAT,    float,    float);
+      T(INT64,    int64,    int64);
+      T(INT32,    int32,    int32);
+      T(FIXED64,  fixed64,  uint64);
+      T(FIXED32,  fixed32,  uint32);
+      T(BOOL,     bool,     bool);
+      T(UINT32,   uint32,   uint32);
+      T(UINT64,   uint64,   uint64);
+      T(ENUM,     enum,     int32);
+      T(SFIXED32, sfixed32, int32);
+      T(SFIXED64, sfixed64, int64);
+      T(SINT32,   sint32,   int32);
+      T(SINT64,   sint64,   int64);
+      case UPB_DESCRIPTOR_TYPE_STRING:
+      case UPB_DESCRIPTOR_TYPE_BYTES:
+        upb_handlers_setstartstr(h, f, encode_startstr, &attr);
+        upb_handlers_setendstr(h, f, encode_enddelimfield, &attr);
+        upb_handlers_setstring(h, f, encode_strbuf, &attr);
+        break;
+      case UPB_DESCRIPTOR_TYPE_MESSAGE:
+        upb_handlers_setstartsubmsg(h, f, encode_startdelimfield, &attr);
+        upb_handlers_setendsubmsg(h, f, encode_enddelimfield, &attr);
+        break;
+      case UPB_DESCRIPTOR_TYPE_GROUP: {
+        /* Endgroup takes a different tag (wire_type = END_GROUP). */
+        upb_handlerattr attr2;
+        new_tag(h, f, UPB_WIRE_TYPE_END_GROUP, &attr2);
+
+        upb_handlers_setstartsubmsg(h, f, encode_startgroup, &attr);
+        upb_handlers_setendsubmsg(h, f, encode_endgroup, &attr2);
+
+        upb_handlerattr_uninit(&attr2);
+        break;
+      }
+    }
+
+#undef T
+
+    upb_handlerattr_uninit(&attr);
+  }
+}
+
+void upb_pb_encoder_reset(upb_pb_encoder *e) {
+  e->segptr = NULL;
+  e->top = NULL;
+  e->depth = 0;
+}
+
+
+/* public API *****************************************************************/
+
+const upb_handlers *upb_pb_encoder_newhandlers(const upb_msgdef *m,
+                                               const void *owner) {
+  return upb_handlers_newfrozen(m, owner, newhandlers_callback, NULL);
+}
+
+upb_pb_encoder *upb_pb_encoder_create(upb_env *env, const upb_handlers *h,
+                                      upb_bytessink *output) {
+  const size_t initial_bufsize = 256;
+  const size_t initial_segbufsize = 16;
+  /* TODO(haberman): make this configurable. */
+  const size_t stack_size = 64;
+#ifndef NDEBUG
+  const size_t size_before = upb_env_bytesallocated(env);
+#endif
+
+  upb_pb_encoder *e = upb_env_malloc(env, sizeof(upb_pb_encoder));
+  if (!e) return NULL;
+
+  e->buf = upb_env_malloc(env, initial_bufsize);
+  e->segbuf = upb_env_malloc(env, initial_segbufsize * sizeof(*e->segbuf));
+  e->stack = upb_env_malloc(env, stack_size * sizeof(*e->stack));
+
+  if (!e->buf || !e->segbuf || !e->stack) {
+    return NULL;
+  }
+
+  e->limit = e->buf + initial_bufsize;
+  e->seglimit = e->segbuf + initial_segbufsize;
+  e->stacklimit = e->stack + stack_size;
+
+  upb_pb_encoder_reset(e);
+  upb_sink_reset(&e->input_, h, e);
+
+  e->env = env;
+  e->output_ = output;
+  e->subc = output->closure;
+  e->ptr = e->buf;
+
+  /* If this fails, increase the value in encoder.h. */
+  UPB_ASSERT_DEBUGVAR(upb_env_bytesallocated(env) - size_before <=
+                      UPB_PB_ENCODER_SIZE);
+  return e;
+}
+
+upb_sink *upb_pb_encoder_input(upb_pb_encoder *e) { return &e->input_; }
+
+
+
+upb_filedef **upb_loaddescriptor(const char *buf, size_t n, const void *owner,
+                                 upb_status *status) {
+  /* Create handlers. */
+  const upb_pbdecodermethod *decoder_m;
+  const upb_handlers *reader_h = upb_descreader_newhandlers(&reader_h);
+  upb_env env;
+  upb_pbdecodermethodopts opts;
+  upb_pbdecoder *decoder;
+  upb_descreader *reader;
+  bool ok;
+  size_t i;
+  upb_filedef **ret = NULL;
+
+  upb_pbdecodermethodopts_init(&opts, reader_h);
+  decoder_m = upb_pbdecodermethod_new(&opts, &decoder_m);
+
+  upb_env_init(&env);
+  upb_env_reporterrorsto(&env, status);
+
+  reader = upb_descreader_create(&env, reader_h);
+  decoder = upb_pbdecoder_create(&env, decoder_m, upb_descreader_input(reader));
+
+  /* Push input data. */
+  ok = upb_bufsrc_putbuf(buf, n, upb_pbdecoder_input(decoder));
+
+  if (!ok) {
+    goto cleanup;
+  }
+
+  ret = upb_gmalloc(sizeof (*ret) * (upb_descreader_filecount(reader) + 1));
+
+  if (!ret) {
+    goto cleanup;
+  }
+
+  for (i = 0; i < upb_descreader_filecount(reader); i++) {
+    ret[i] = upb_descreader_file(reader, i);
+    upb_filedef_ref(ret[i], owner);
+  }
+
+  ret[i] = NULL;
+
+cleanup:
+  upb_env_uninit(&env);
+  upb_handlers_unref(reader_h, &reader_h);
+  upb_pbdecodermethod_unref(decoder_m, &decoder_m);
+  return ret;
+}
+/*
+ * upb::pb::TextPrinter
+ *
+ * OPT: This is not optimized at all.  It uses printf() which parses the format
+ * string every time, and it allocates memory for every put.
+ */
+
+
+#include <ctype.h>
+#include <float.h>
+#include <inttypes.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <string.h>
+
+
+struct upb_textprinter {
+  upb_sink input_;
+  upb_bytessink *output_;
+  int indent_depth_;
+  bool single_line_;
+  void *subc;
+};
+
+#define CHECK(x) if ((x) < 0) goto err;
+
+static const char *shortname(const char *longname) {
+  const char *last = strrchr(longname, '.');
+  return last ? last + 1 : longname;
+}
+
+static int indent(upb_textprinter *p) {
+  int i;
+  if (!p->single_line_)
+    for (i = 0; i < p->indent_depth_; i++)
+      upb_bytessink_putbuf(p->output_, p->subc, "  ", 2, NULL);
+  return 0;
+}
+
+static int endfield(upb_textprinter *p) {
+  const char ch = (p->single_line_ ? ' ' : '\n');
+  upb_bytessink_putbuf(p->output_, p->subc, &ch, 1, NULL);
+  return 0;
+}
+
+static int putescaped(upb_textprinter *p, const char *buf, size_t len,
+                      bool preserve_utf8) {
+  /* Based on CEscapeInternal() from Google's protobuf release. */
+  char dstbuf[4096], *dst = dstbuf, *dstend = dstbuf + sizeof(dstbuf);
+  const char *end = buf + len;
+
+  /* I think hex is prettier and more useful, but proto2 uses octal; should
+   * investigate whether it can parse hex also. */
+  const bool use_hex = false;
+  bool last_hex_escape = false; /* true if last output char was \xNN */
+
+  for (; buf < end; buf++) {
+    bool is_hex_escape;
+
+    if (dstend - dst < 4) {
+      upb_bytessink_putbuf(p->output_, p->subc, dstbuf, dst - dstbuf, NULL);
+      dst = dstbuf;
+    }
+
+    is_hex_escape = false;
+    switch (*buf) {
+      case '\n': *(dst++) = '\\'; *(dst++) = 'n';  break;
+      case '\r': *(dst++) = '\\'; *(dst++) = 'r';  break;
+      case '\t': *(dst++) = '\\'; *(dst++) = 't';  break;
+      case '\"': *(dst++) = '\\'; *(dst++) = '\"'; break;
+      case '\'': *(dst++) = '\\'; *(dst++) = '\''; break;
+      case '\\': *(dst++) = '\\'; *(dst++) = '\\'; break;
+      default:
+        /* Note that if we emit \xNN and the buf character after that is a hex
+         * digit then that digit must be escaped too to prevent it being
+         * interpreted as part of the character code by C. */
+        if ((!preserve_utf8 || (uint8_t)*buf < 0x80) &&
+            (!isprint(*buf) || (last_hex_escape && isxdigit(*buf)))) {
+          sprintf(dst, (use_hex ? "\\x%02x" : "\\%03o"), (uint8_t)*buf);
+          is_hex_escape = use_hex;
+          dst += 4;
+        } else {
+          *(dst++) = *buf; break;
+        }
+    }
+    last_hex_escape = is_hex_escape;
+  }
+  /* Flush remaining data. */
+  upb_bytessink_putbuf(p->output_, p->subc, dstbuf, dst - dstbuf, NULL);
+  return 0;
+}
+
+bool putf(upb_textprinter *p, const char *fmt, ...) {
+  va_list args;
+  va_list args_copy;
+  char *str;
+  int written;
+  int len;
+  bool ok;
+
+  va_start(args, fmt);
+
+  /* Run once to get the length of the string. */
+  _upb_va_copy(args_copy, args);
+  len = _upb_vsnprintf(NULL, 0, fmt, args_copy);
+  va_end(args_copy);
+
+  /* + 1 for NULL terminator (vsprintf() requires it even if we don't). */
+  str = upb_gmalloc(len + 1);
+  if (!str) return false;
+  written = vsprintf(str, fmt, args);
+  va_end(args);
+  UPB_ASSERT(written == len);
+
+  ok = upb_bytessink_putbuf(p->output_, p->subc, str, len, NULL);
+  upb_gfree(str);
+  return ok;
+}
+
+
+/* handlers *******************************************************************/
+
+static bool textprinter_startmsg(void *c, const void *hd) {
+  upb_textprinter *p = c;
+  UPB_UNUSED(hd);
+  if (p->indent_depth_ == 0) {
+    upb_bytessink_start(p->output_, 0, &p->subc);
+  }
+  return true;
+}
+
+static bool textprinter_endmsg(void *c, const void *hd, upb_status *s) {
+  upb_textprinter *p = c;
+  UPB_UNUSED(hd);
+  UPB_UNUSED(s);
+  if (p->indent_depth_ == 0) {
+    upb_bytessink_end(p->output_);
+  }
+  return true;
+}
+
+#define TYPE(name, ctype, fmt) \
+  static bool textprinter_put ## name(void *closure, const void *handler_data, \
+                                      ctype val) {                             \
+    upb_textprinter *p = closure;                                              \
+    const upb_fielddef *f = handler_data;                                      \
+    CHECK(indent(p));                                                          \
+    putf(p, "%s: " fmt, upb_fielddef_name(f), val);                            \
+    CHECK(endfield(p));                                                        \
+    return true;                                                               \
+  err:                                                                         \
+    return false;                                                              \
+}
+
+static bool textprinter_putbool(void *closure, const void *handler_data,
+                                bool val) {
+  upb_textprinter *p = closure;
+  const upb_fielddef *f = handler_data;
+  CHECK(indent(p));
+  putf(p, "%s: %s", upb_fielddef_name(f), val ? "true" : "false");
+  CHECK(endfield(p));
+  return true;
+err:
+  return false;
+}
+
+#define STRINGIFY_HELPER(x) #x
+#define STRINGIFY_MACROVAL(x) STRINGIFY_HELPER(x)
+
+TYPE(int32,  int32_t,  "%" PRId32)
+TYPE(int64,  int64_t,  "%" PRId64)
+TYPE(uint32, uint32_t, "%" PRIu32)
+TYPE(uint64, uint64_t, "%" PRIu64)
+TYPE(float,  float,    "%." STRINGIFY_MACROVAL(FLT_DIG) "g")
+TYPE(double, double,   "%." STRINGIFY_MACROVAL(DBL_DIG) "g")
+
+#undef TYPE
+
+/* Output a symbolic value from the enum if found, else just print as int32. */
+static bool textprinter_putenum(void *closure, const void *handler_data,
+                                int32_t val) {
+  upb_textprinter *p = closure;
+  const upb_fielddef *f = handler_data;
+  const upb_enumdef *enum_def = upb_downcast_enumdef(upb_fielddef_subdef(f));
+  const char *label = upb_enumdef_iton(enum_def, val);
+  if (label) {
+    indent(p);
+    putf(p, "%s: %s", upb_fielddef_name(f), label);
+    endfield(p);
+  } else {
+    if (!textprinter_putint32(closure, handler_data, val))
+      return false;
+  }
+  return true;
+}
+
+static void *textprinter_startstr(void *closure, const void *handler_data,
+                      size_t size_hint) {
+  upb_textprinter *p = closure;
+  const upb_fielddef *f = handler_data;
+  UPB_UNUSED(size_hint);
+  indent(p);
+  putf(p, "%s: \"", upb_fielddef_name(f));
+  return p;
+}
+
+static bool textprinter_endstr(void *closure, const void *handler_data) {
+  upb_textprinter *p = closure;
+  UPB_UNUSED(handler_data);
+  putf(p, "\"");
+  endfield(p);
+  return true;
+}
+
+static size_t textprinter_putstr(void *closure, const void *hd, const char *buf,
+                                 size_t len, const upb_bufhandle *handle) {
+  upb_textprinter *p = closure;
+  const upb_fielddef *f = hd;
+  UPB_UNUSED(handle);
+  CHECK(putescaped(p, buf, len, upb_fielddef_type(f) == UPB_TYPE_STRING));
+  return len;
+err:
+  return 0;
+}
+
+static void *textprinter_startsubmsg(void *closure, const void *handler_data) {
+  upb_textprinter *p = closure;
+  const char *name = handler_data;
+  CHECK(indent(p));
+  putf(p, "%s {%c", name, p->single_line_ ? ' ' : '\n');
+  p->indent_depth_++;
+  return p;
+err:
+  return UPB_BREAK;
+}
+
+static bool textprinter_endsubmsg(void *closure, const void *handler_data) {
+  upb_textprinter *p = closure;
+  UPB_UNUSED(handler_data);
+  p->indent_depth_--;
+  CHECK(indent(p));
+  upb_bytessink_putbuf(p->output_, p->subc, "}", 1, NULL);
+  CHECK(endfield(p));
+  return true;
+err:
+  return false;
+}
+
+static void onmreg(const void *c, upb_handlers *h) {
+  const upb_msgdef *m = upb_handlers_msgdef(h);
+  upb_msg_field_iter i;
+  UPB_UNUSED(c);
+
+  upb_handlers_setstartmsg(h, textprinter_startmsg, NULL);
+  upb_handlers_setendmsg(h, textprinter_endmsg, NULL);
+
+  for(upb_msg_field_begin(&i, m);
+      !upb_msg_field_done(&i);
+      upb_msg_field_next(&i)) {
+    upb_fielddef *f = upb_msg_iter_field(&i);
+    upb_handlerattr attr = UPB_HANDLERATTR_INITIALIZER;
+    upb_handlerattr_sethandlerdata(&attr, f);
+    switch (upb_fielddef_type(f)) {
+      case UPB_TYPE_INT32:
+        upb_handlers_setint32(h, f, textprinter_putint32, &attr);
+        break;
+      case UPB_TYPE_INT64:
+        upb_handlers_setint64(h, f, textprinter_putint64, &attr);
+        break;
+      case UPB_TYPE_UINT32:
+        upb_handlers_setuint32(h, f, textprinter_putuint32, &attr);
+        break;
+      case UPB_TYPE_UINT64:
+        upb_handlers_setuint64(h, f, textprinter_putuint64, &attr);
+        break;
+      case UPB_TYPE_FLOAT:
+        upb_handlers_setfloat(h, f, textprinter_putfloat, &attr);
+        break;
+      case UPB_TYPE_DOUBLE:
+        upb_handlers_setdouble(h, f, textprinter_putdouble, &attr);
+        break;
+      case UPB_TYPE_BOOL:
+        upb_handlers_setbool(h, f, textprinter_putbool, &attr);
+        break;
+      case UPB_TYPE_STRING:
+      case UPB_TYPE_BYTES:
+        upb_handlers_setstartstr(h, f, textprinter_startstr, &attr);
+        upb_handlers_setstring(h, f, textprinter_putstr, &attr);
+        upb_handlers_setendstr(h, f, textprinter_endstr, &attr);
+        break;
+      case UPB_TYPE_MESSAGE: {
+        const char *name =
+            upb_fielddef_istagdelim(f)
+                ? shortname(upb_msgdef_fullname(upb_fielddef_msgsubdef(f)))
+                : upb_fielddef_name(f);
+        upb_handlerattr_sethandlerdata(&attr, name);
+        upb_handlers_setstartsubmsg(h, f, textprinter_startsubmsg, &attr);
+        upb_handlers_setendsubmsg(h, f, textprinter_endsubmsg, &attr);
+        break;
+      }
+      case UPB_TYPE_ENUM:
+        upb_handlers_setint32(h, f, textprinter_putenum, &attr);
+        break;
+    }
+  }
+}
+
+static void textprinter_reset(upb_textprinter *p, bool single_line) {
+  p->single_line_ = single_line;
+  p->indent_depth_ = 0;
+}
+
+
+/* Public API *****************************************************************/
+
+upb_textprinter *upb_textprinter_create(upb_env *env, const upb_handlers *h,
+                                        upb_bytessink *output) {
+  upb_textprinter *p = upb_env_malloc(env, sizeof(upb_textprinter));
+  if (!p) return NULL;
+
+  p->output_ = output;
+  upb_sink_reset(&p->input_, h, p);
+  textprinter_reset(p, false);
+
+  return p;
+}
+
+const upb_handlers *upb_textprinter_newhandlers(const upb_msgdef *m,
+                                                const void *owner) {
+  return upb_handlers_newfrozen(m, owner, &onmreg, NULL);
+}
+
+upb_sink *upb_textprinter_input(upb_textprinter *p) { return &p->input_; }
+
+void upb_textprinter_setsingleline(upb_textprinter *p, bool single_line) {
+  p->single_line_ = single_line;
+}
+
+
+/* Index is descriptor type. */
+const uint8_t upb_pb_native_wire_types[] = {
+  UPB_WIRE_TYPE_END_GROUP,     /* ENDGROUP */
+  UPB_WIRE_TYPE_64BIT,         /* DOUBLE */
+  UPB_WIRE_TYPE_32BIT,         /* FLOAT */
+  UPB_WIRE_TYPE_VARINT,        /* INT64 */
+  UPB_WIRE_TYPE_VARINT,        /* UINT64 */
+  UPB_WIRE_TYPE_VARINT,        /* INT32 */
+  UPB_WIRE_TYPE_64BIT,         /* FIXED64 */
+  UPB_WIRE_TYPE_32BIT,         /* FIXED32 */
+  UPB_WIRE_TYPE_VARINT,        /* BOOL */
+  UPB_WIRE_TYPE_DELIMITED,     /* STRING */
+  UPB_WIRE_TYPE_START_GROUP,   /* GROUP */
+  UPB_WIRE_TYPE_DELIMITED,     /* MESSAGE */
+  UPB_WIRE_TYPE_DELIMITED,     /* BYTES */
+  UPB_WIRE_TYPE_VARINT,        /* UINT32 */
+  UPB_WIRE_TYPE_VARINT,        /* ENUM */
+  UPB_WIRE_TYPE_32BIT,         /* SFIXED32 */
+  UPB_WIRE_TYPE_64BIT,         /* SFIXED64 */
+  UPB_WIRE_TYPE_VARINT,        /* SINT32 */
+  UPB_WIRE_TYPE_VARINT,        /* SINT64 */
+};
+
+/* A basic branch-based decoder, uses 32-bit values to get good performance
+ * on 32-bit architectures (but performs well on 64-bits also).
+ * This scheme comes from the original Google Protobuf implementation
+ * (proto2). */
+upb_decoderet upb_vdecode_max8_branch32(upb_decoderet r) {
+  upb_decoderet err = {NULL, 0};
+  const char *p = r.p;
+  uint32_t low = (uint32_t)r.val;
+  uint32_t high = 0;
+  uint32_t b;
+  b = *(p++); low  |= (b & 0x7fU) << 14; if (!(b & 0x80)) goto done;
+  b = *(p++); low  |= (b & 0x7fU) << 21; if (!(b & 0x80)) goto done;
+  b = *(p++); low  |= (b & 0x7fU) << 28;
+              high  = (b & 0x7fU) >>  4; if (!(b & 0x80)) goto done;
+  b = *(p++); high |= (b & 0x7fU) <<  3; if (!(b & 0x80)) goto done;
+  b = *(p++); high |= (b & 0x7fU) << 10; if (!(b & 0x80)) goto done;
+  b = *(p++); high |= (b & 0x7fU) << 17; if (!(b & 0x80)) goto done;
+  b = *(p++); high |= (b & 0x7fU) << 24; if (!(b & 0x80)) goto done;
+  b = *(p++); high |= (b & 0x7fU) << 31; if (!(b & 0x80)) goto done;
+  return err;
+
+done:
+  r.val = ((uint64_t)high << 32) | low;
+  r.p = p;
+  return r;
+}
+
+/* Like the previous, but uses 64-bit values. */
+upb_decoderet upb_vdecode_max8_branch64(upb_decoderet r) {
+  const char *p = r.p;
+  uint64_t val = r.val;
+  uint64_t b;
+  upb_decoderet err = {NULL, 0};
+  b = *(p++); val |= (b & 0x7fU) << 14; if (!(b & 0x80)) goto done;
+  b = *(p++); val |= (b & 0x7fU) << 21; if (!(b & 0x80)) goto done;
+  b = *(p++); val |= (b & 0x7fU) << 28; if (!(b & 0x80)) goto done;
+  b = *(p++); val |= (b & 0x7fU) << 35; if (!(b & 0x80)) goto done;
+  b = *(p++); val |= (b & 0x7fU) << 42; if (!(b & 0x80)) goto done;
+  b = *(p++); val |= (b & 0x7fU) << 49; if (!(b & 0x80)) goto done;
+  b = *(p++); val |= (b & 0x7fU) << 56; if (!(b & 0x80)) goto done;
+  b = *(p++); val |= (b & 0x7fU) << 63; if (!(b & 0x80)) goto done;
+  return err;
+
+done:
+  r.val = val;
+  r.p = p;
+  return r;
+}
+
+#line 1 "upb/json/parser.rl"
+/*
+** upb::json::Parser (upb_json_parser)
+**
+** A parser that uses the Ragel State Machine Compiler to generate
+** the finite automata.
+**
+** Ragel only natively handles regular languages, but we can manually
+** program it a bit to handle context-free languages like JSON, by using
+** the "fcall" and "fret" constructs.
+**
+** This parser can handle the basics, but needs several things to be fleshed
+** out:
+**
+** - handling of unicode escape sequences (including high surrogate pairs).
+** - properly check and report errors for unknown fields, stack overflow,
+**   improper array nesting (or lack of nesting).
+** - handling of base64 sequences with padding characters.
+** - handling of push-back (non-success returns from sink functions).
+** - handling of keys/escape-sequences/etc that span input buffers.
+*/
+
+#include <errno.h>
+#include <float.h>
+#include <math.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+
+
+#define UPB_JSON_MAX_DEPTH 64
+
+typedef struct {
+  upb_sink sink;
+
+  /* The current message in which we're parsing, and the field whose value we're
+   * expecting next. */
+  const upb_msgdef *m;
+  const upb_fielddef *f;
+
+  /* The table mapping json name to fielddef for this message. */
+  upb_strtable *name_table;
+
+  /* We are in a repeated-field context, ready to emit mapentries as
+   * submessages. This flag alters the start-of-object (open-brace) behavior to
+   * begin a sequence of mapentry messages rather than a single submessage. */
+  bool is_map;
+
+  /* We are in a map-entry message context. This flag is set when parsing the
+   * value field of a single map entry and indicates to all value-field parsers
+   * (subobjects, strings, numbers, and bools) that the map-entry submessage
+   * should end as soon as the value is parsed. */
+  bool is_mapentry;
+
+  /* If |is_map| or |is_mapentry| is true, |mapfield| refers to the parent
+   * message's map field that we're currently parsing. This differs from |f|
+   * because |f| is the field in the *current* message (i.e., the map-entry
+   * message itself), not the parent's field that leads to this map. */
+  const upb_fielddef *mapfield;
+} upb_jsonparser_frame;
+
+struct upb_json_parser {
+  upb_env *env;
+  const upb_json_parsermethod *method;
+  upb_bytessink input_;
+
+  /* Stack to track the JSON scopes we are in. */
+  upb_jsonparser_frame stack[UPB_JSON_MAX_DEPTH];
+  upb_jsonparser_frame *top;
+  upb_jsonparser_frame *limit;
+
+  upb_status status;
+
+  /* Ragel's internal parsing stack for the parsing state machine. */
+  int current_state;
+  int parser_stack[UPB_JSON_MAX_DEPTH];
+  int parser_top;
+
+  /* The handle for the current buffer. */
+  const upb_bufhandle *handle;
+
+  /* Accumulate buffer.  See details in parser.rl. */
+  const char *accumulated;
+  size_t accumulated_len;
+  char *accumulate_buf;
+  size_t accumulate_buf_size;
+
+  /* Multi-part text data.  See details in parser.rl. */
+  int multipart_state;
+  upb_selector_t string_selector;
+
+  /* Input capture.  See details in parser.rl. */
+  const char *capture;
+
+  /* Intermediate result of parsing a unicode escape sequence. */
+  uint32_t digit;
+};
+
+struct upb_json_parsermethod {
+  upb_refcounted base;
+
+  upb_byteshandler input_handler_;
+
+  /* Mainly for the purposes of refcounting, so all the fielddefs we point
+   * to stay alive. */
+  const upb_msgdef *msg;
+
+  /* Keys are upb_msgdef*, values are upb_strtable (json_name -> fielddef) */
+  upb_inttable name_tables;
+};
+
+#define PARSER_CHECK_RETURN(x) if (!(x)) return false
+
+/* Used to signal that a capture has been suspended. */
+static char suspend_capture;
+
+static upb_selector_t getsel_for_handlertype(upb_json_parser *p,
+                                             upb_handlertype_t type) {
+  upb_selector_t sel;
+  bool ok = upb_handlers_getselector(p->top->f, type, &sel);
+  UPB_ASSERT(ok);
+  return sel;
+}
+
+static upb_selector_t parser_getsel(upb_json_parser *p) {
+  return getsel_for_handlertype(
+      p, upb_handlers_getprimitivehandlertype(p->top->f));
+}
+
+static bool check_stack(upb_json_parser *p) {
+  if ((p->top + 1) == p->limit) {
+    upb_status_seterrmsg(&p->status, "Nesting too deep");
+    upb_env_reporterror(p->env, &p->status);
+    return false;
+  }
+
+  return true;
+}
+
+static void set_name_table(upb_json_parser *p, upb_jsonparser_frame *frame) {
+  upb_value v;
+  bool ok = upb_inttable_lookupptr(&p->method->name_tables, frame->m, &v);
+  UPB_ASSERT(ok);
+  frame->name_table = upb_value_getptr(v);
+}
+
+/* There are GCC/Clang built-ins for overflow checking which we could start
+ * using if there was any performance benefit to it. */
+
+static bool checked_add(size_t a, size_t b, size_t *c) {
+  if (SIZE_MAX - a < b) return false;
+  *c = a + b;
+  return true;
+}
+
+static size_t saturating_multiply(size_t a, size_t b) {
+  /* size_t is unsigned, so this is defined behavior even on overflow. */
+  size_t ret = a * b;
+  if (b != 0 && ret / b != a) {
+    ret = SIZE_MAX;
+  }
+  return ret;
+}
+
+
+/* Base64 decoding ************************************************************/
+
+/* TODO(haberman): make this streaming. */
+
+static const signed char b64table[] = {
+  -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,
+  -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,
+  -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,
+  -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,
+  -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,
+  -1,      -1,      -1,      62/*+*/, -1,      -1,      -1,      63/*/ */,
+  52/*0*/, 53/*1*/, 54/*2*/, 55/*3*/, 56/*4*/, 57/*5*/, 58/*6*/, 59/*7*/,
+  60/*8*/, 61/*9*/, -1,      -1,      -1,      -1,      -1,      -1,
+  -1,       0/*A*/,  1/*B*/,  2/*C*/,  3/*D*/,  4/*E*/,  5/*F*/,  6/*G*/,
+  07/*H*/,  8/*I*/,  9/*J*/, 10/*K*/, 11/*L*/, 12/*M*/, 13/*N*/, 14/*O*/,
+  15/*P*/, 16/*Q*/, 17/*R*/, 18/*S*/, 19/*T*/, 20/*U*/, 21/*V*/, 22/*W*/,
+  23/*X*/, 24/*Y*/, 25/*Z*/, -1,      -1,      -1,      -1,      -1,
+  -1,      26/*a*/, 27/*b*/, 28/*c*/, 29/*d*/, 30/*e*/, 31/*f*/, 32/*g*/,
+  33/*h*/, 34/*i*/, 35/*j*/, 36/*k*/, 37/*l*/, 38/*m*/, 39/*n*/, 40/*o*/,
+  41/*p*/, 42/*q*/, 43/*r*/, 44/*s*/, 45/*t*/, 46/*u*/, 47/*v*/, 48/*w*/,
+  49/*x*/, 50/*y*/, 51/*z*/, -1,      -1,      -1,      -1,      -1,
+  -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,
+  -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,
+  -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,
+  -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,
+  -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,
+  -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,
+  -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,
+  -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,
+  -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,
+  -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,
+  -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,
+  -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,
+  -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,
+  -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,
+  -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1,
+  -1,      -1,      -1,      -1,      -1,      -1,      -1,      -1
+};
+
+/* Returns the table value sign-extended to 32 bits.  Knowing that the upper
+ * bits will be 1 for unrecognized characters makes it easier to check for
+ * this error condition later (see below). */
+int32_t b64lookup(unsigned char ch) { return b64table[ch]; }
+
+/* Returns true if the given character is not a valid base64 character or
+ * padding. */
+bool nonbase64(unsigned char ch) { return b64lookup(ch) == -1 && ch != '='; }
+
+static bool base64_push(upb_json_parser *p, upb_selector_t sel, const char *ptr,
+                        size_t len) {
+  const char *limit = ptr + len;
+  for (; ptr < limit; ptr += 4) {
+    uint32_t val;
+    char output[3];
+
+    if (limit - ptr < 4) {
+      upb_status_seterrf(&p->status,
+                         "Base64 input for bytes field not a multiple of 4: %s",
+                         upb_fielddef_name(p->top->f));
+      upb_env_reporterror(p->env, &p->status);
+      return false;
+    }
+
+    val = b64lookup(ptr[0]) << 18 |
+          b64lookup(ptr[1]) << 12 |
+          b64lookup(ptr[2]) << 6  |
+          b64lookup(ptr[3]);
+
+    /* Test the upper bit; returns true if any of the characters returned -1. */
+    if (val & 0x80000000) {
+      goto otherchar;
+    }
+
+    output[0] = val >> 16;
+    output[1] = (val >> 8) & 0xff;
+    output[2] = val & 0xff;
+    upb_sink_putstring(&p->top->sink, sel, output, 3, NULL);
+  }
+  return true;
+
+otherchar:
+  if (nonbase64(ptr[0]) || nonbase64(ptr[1]) || nonbase64(ptr[2]) ||
+      nonbase64(ptr[3]) ) {
+    upb_status_seterrf(&p->status,
+                       "Non-base64 characters in bytes field: %s",
+                       upb_fielddef_name(p->top->f));
+    upb_env_reporterror(p->env, &p->status);
+    return false;
+  } if (ptr[2] == '=') {
+    uint32_t val;
+    char output;
+
+    /* Last group contains only two input bytes, one output byte. */
+    if (ptr[0] == '=' || ptr[1] == '=' || ptr[3] != '=') {
+      goto badpadding;
+    }
+
+    val = b64lookup(ptr[0]) << 18 |
+          b64lookup(ptr[1]) << 12;
+
+    UPB_ASSERT(!(val & 0x80000000));
+    output = val >> 16;
+    upb_sink_putstring(&p->top->sink, sel, &output, 1, NULL);
+    return true;
+  } else {
+    uint32_t val;
+    char output[2];
+
+    /* Last group contains only three input bytes, two output bytes. */
+    if (ptr[0] == '=' || ptr[1] == '=' || ptr[2] == '=') {
+      goto badpadding;
+    }
+
+    val = b64lookup(ptr[0]) << 18 |
+          b64lookup(ptr[1]) << 12 |
+          b64lookup(ptr[2]) << 6;
+
+    output[0] = val >> 16;
+    output[1] = (val >> 8) & 0xff;
+    upb_sink_putstring(&p->top->sink, sel, output, 2, NULL);
+    return true;
+  }
+
+badpadding:
+  upb_status_seterrf(&p->status,
+                     "Incorrect base64 padding for field: %s (%.*s)",
+                     upb_fielddef_name(p->top->f),
+                     4, ptr);
+  upb_env_reporterror(p->env, &p->status);
+  return false;
+}
+
+
+/* Accumulate buffer **********************************************************/
+
+/* Functionality for accumulating a buffer.
+ *
+ * Some parts of the parser need an entire value as a contiguous string.  For
+ * example, to look up a member name in a hash table, or to turn a string into
+ * a number, the relevant library routines need the input string to be in
+ * contiguous memory, even if the value spanned two or more buffers in the
+ * input.  These routines handle that.
+ *
+ * In the common case we can just point to the input buffer to get this
+ * contiguous string and avoid any actual copy.  So we optimistically begin
+ * this way.  But there are a few cases where we must instead copy into a
+ * separate buffer:
+ *
+ *   1. The string was not contiguous in the input (it spanned buffers).
+ *
+ *   2. The string included escape sequences that need to be interpreted to get
+ *      the true value in a contiguous buffer. */
+
+static void assert_accumulate_empty(upb_json_parser *p) {
+  UPB_ASSERT(p->accumulated == NULL);
+  UPB_ASSERT(p->accumulated_len == 0);
+}
+
+static void accumulate_clear(upb_json_parser *p) {
+  p->accumulated = NULL;
+  p->accumulated_len = 0;
+}
+
+/* Used internally by accumulate_append(). */
+static bool accumulate_realloc(upb_json_parser *p, size_t need) {
+  void *mem;
+  size_t old_size = p->accumulate_buf_size;
+  size_t new_size = UPB_MAX(old_size, 128);
+  while (new_size < need) {
+    new_size = saturating_multiply(new_size, 2);
+  }
+
+  mem = upb_env_realloc(p->env, p->accumulate_buf, old_size, new_size);
+  if (!mem) {
+    upb_status_seterrmsg(&p->status, "Out of memory allocating buffer.");
+    upb_env_reporterror(p->env, &p->status);
+    return false;
+  }
+
+  p->accumulate_buf = mem;
+  p->accumulate_buf_size = new_size;
+  return true;
+}
+
+/* Logically appends the given data to the append buffer.
+ * If "can_alias" is true, we will try to avoid actually copying, but the buffer
+ * must be valid until the next accumulate_append() call (if any). */
+static bool accumulate_append(upb_json_parser *p, const char *buf, size_t len,
+                              bool can_alias) {
+  size_t need;
+
+  if (!p->accumulated && can_alias) {
+    p->accumulated = buf;
+    p->accumulated_len = len;
+    return true;
+  }
+
+  if (!checked_add(p->accumulated_len, len, &need)) {
+    upb_status_seterrmsg(&p->status, "Integer overflow.");
+    upb_env_reporterror(p->env, &p->status);
+    return false;
+  }
+
+  if (need > p->accumulate_buf_size && !accumulate_realloc(p, need)) {
+    return false;
+  }
+
+  if (p->accumulated != p->accumulate_buf) {
+    memcpy(p->accumulate_buf, p->accumulated, p->accumulated_len);
+    p->accumulated = p->accumulate_buf;
+  }
+
+  memcpy(p->accumulate_buf + p->accumulated_len, buf, len);
+  p->accumulated_len += len;
+  return true;
+}
+
+/* Returns a pointer to the data accumulated since the last accumulate_clear()
+ * call, and writes the length to *len.  This with point either to the input
+ * buffer or a temporary accumulate buffer. */
+static const char *accumulate_getptr(upb_json_parser *p, size_t *len) {
+  UPB_ASSERT(p->accumulated);
+  *len = p->accumulated_len;
+  return p->accumulated;
+}
+
+
+/* Mult-part text data ********************************************************/
+
+/* When we have text data in the input, it can often come in multiple segments.
+ * For example, there may be some raw string data followed by an escape
+ * sequence.  The two segments are processed with different logic.  Also buffer
+ * seams in the input can cause multiple segments.
+ *
+ * As we see segments, there are two main cases for how we want to process them:
+ *
+ *  1. we want to push the captured input directly to string handlers.
+ *
+ *  2. we need to accumulate all the parts into a contiguous buffer for further
+ *     processing (field name lookup, string->number conversion, etc). */
+
+/* This is the set of states for p->multipart_state. */
+enum {
+  /* We are not currently processing multipart data. */
+  MULTIPART_INACTIVE = 0,
+
+  /* We are processing multipart data by accumulating it into a contiguous
+   * buffer. */
+  MULTIPART_ACCUMULATE = 1,
+
+  /* We are processing multipart data by pushing each part directly to the
+   * current string handlers. */
+  MULTIPART_PUSHEAGERLY = 2
+};
+
+/* Start a multi-part text value where we accumulate the data for processing at
+ * the end. */
+static void multipart_startaccum(upb_json_parser *p) {
+  assert_accumulate_empty(p);
+  UPB_ASSERT(p->multipart_state == MULTIPART_INACTIVE);
+  p->multipart_state = MULTIPART_ACCUMULATE;
+}
+
+/* Start a multi-part text value where we immediately push text data to a string
+ * value with the given selector. */
+static void multipart_start(upb_json_parser *p, upb_selector_t sel) {
+  assert_accumulate_empty(p);
+  UPB_ASSERT(p->multipart_state == MULTIPART_INACTIVE);
+  p->multipart_state = MULTIPART_PUSHEAGERLY;
+  p->string_selector = sel;
+}
+
+static bool multipart_text(upb_json_parser *p, const char *buf, size_t len,
+                           bool can_alias) {
+  switch (p->multipart_state) {
+    case MULTIPART_INACTIVE:
+      upb_status_seterrmsg(
+          &p->status, "Internal error: unexpected state MULTIPART_INACTIVE");
+      upb_env_reporterror(p->env, &p->status);
+      return false;
+
+    case MULTIPART_ACCUMULATE:
+      if (!accumulate_append(p, buf, len, can_alias)) {
+        return false;
+      }
+      break;
+
+    case MULTIPART_PUSHEAGERLY: {
+      const upb_bufhandle *handle = can_alias ? p->handle : NULL;
+      upb_sink_putstring(&p->top->sink, p->string_selector, buf, len, handle);
+      break;
+    }
+  }
+
+  return true;
+}
+
+/* Note: this invalidates the accumulate buffer!  Call only after reading its
+ * contents. */
+static void multipart_end(upb_json_parser *p) {
+  UPB_ASSERT(p->multipart_state != MULTIPART_INACTIVE);
+  p->multipart_state = MULTIPART_INACTIVE;
+  accumulate_clear(p);
+}
+
+
+/* Input capture **************************************************************/
+
+/* Functionality for capturing a region of the input as text.  Gracefully
+ * handles the case where a buffer seam occurs in the middle of the captured
+ * region. */
+
+static void capture_begin(upb_json_parser *p, const char *ptr) {
+  UPB_ASSERT(p->multipart_state != MULTIPART_INACTIVE);
+  UPB_ASSERT(p->capture == NULL);
+  p->capture = ptr;
+}
+
+static bool capture_end(upb_json_parser *p, const char *ptr) {
+  UPB_ASSERT(p->capture);
+  if (multipart_text(p, p->capture, ptr - p->capture, true)) {
+    p->capture = NULL;
+    return true;
+  } else {
+    return false;
+  }
+}
+
+/* This is called at the end of each input buffer (ie. when we have hit a
+ * buffer seam).  If we are in the middle of capturing the input, this
+ * processes the unprocessed capture region. */
+static void capture_suspend(upb_json_parser *p, const char **ptr) {
+  if (!p->capture) return;
+
+  if (multipart_text(p, p->capture, *ptr - p->capture, false)) {
+    /* We use this as a signal that we were in the middle of capturing, and
+     * that capturing should resume at the beginning of the next buffer.
+     * 
+     * We can't use *ptr here, because we have no guarantee that this pointer
+     * will be valid when we resume (if the underlying memory is freed, then
+     * using the pointer at all, even to compare to NULL, is likely undefined
+     * behavior). */
+    p->capture = &suspend_capture;
+  } else {
+    /* Need to back up the pointer to the beginning of the capture, since
+     * we were not able to actually preserve it. */
+    *ptr = p->capture;
+  }
+}
+
+static void capture_resume(upb_json_parser *p, const char *ptr) {
+  if (p->capture) {
+    UPB_ASSERT(p->capture == &suspend_capture);
+    p->capture = ptr;
+  }
+}
+
+
+/* Callbacks from the parser **************************************************/
+
+/* These are the functions called directly from the parser itself.
+ * We define these in the same order as their declarations in the parser. */
+
+static char escape_char(char in) {
+  switch (in) {
+    case 'r': return '\r';
+    case 't': return '\t';
+    case 'n': return '\n';
+    case 'f': return '\f';
+    case 'b': return '\b';
+    case '/': return '/';
+    case '"': return '"';
+    case '\\': return '\\';
+    default:
+      UPB_ASSERT(0);
+      return 'x';
+  }
+}
+
+static bool escape(upb_json_parser *p, const char *ptr) {
+  char ch = escape_char(*ptr);
+  return multipart_text(p, &ch, 1, false);
+}
+
+static void start_hex(upb_json_parser *p) {
+  p->digit = 0;
+}
+
+static void hexdigit(upb_json_parser *p, const char *ptr) {
+  char ch = *ptr;
+
+  p->digit <<= 4;
+
+  if (ch >= '0' && ch <= '9') {
+    p->digit += (ch - '0');
+  } else if (ch >= 'a' && ch <= 'f') {
+    p->digit += ((ch - 'a') + 10);
+  } else {
+    UPB_ASSERT(ch >= 'A' && ch <= 'F');
+    p->digit += ((ch - 'A') + 10);
+  }
+}
+
+static bool end_hex(upb_json_parser *p) {
+  uint32_t codepoint = p->digit;
+
+  /* emit the codepoint as UTF-8. */
+  char utf8[3]; /* support \u0000 -- \uFFFF -- need only three bytes. */
+  int length = 0;
+  if (codepoint <= 0x7F) {
+    utf8[0] = codepoint;
+    length = 1;
+  } else if (codepoint <= 0x07FF) {
+    utf8[1] = (codepoint & 0x3F) | 0x80;
+    codepoint >>= 6;
+    utf8[0] = (codepoint & 0x1F) | 0xC0;
+    length = 2;
+  } else /* codepoint <= 0xFFFF */ {
+    utf8[2] = (codepoint & 0x3F) | 0x80;
+    codepoint >>= 6;
+    utf8[1] = (codepoint & 0x3F) | 0x80;
+    codepoint >>= 6;
+    utf8[0] = (codepoint & 0x0F) | 0xE0;
+    length = 3;
+  }
+  /* TODO(haberman): Handle high surrogates: if codepoint is a high surrogate
+   * we have to wait for the next escape to get the full code point). */
+
+  return multipart_text(p, utf8, length, false);
+}
+
+static void start_text(upb_json_parser *p, const char *ptr) {
+  capture_begin(p, ptr);
+}
+
+static bool end_text(upb_json_parser *p, const char *ptr) {
+  return capture_end(p, ptr);
+}
+
+static void start_number(upb_json_parser *p, const char *ptr) {
+  multipart_startaccum(p);
+  capture_begin(p, ptr);
+}
+
+static bool parse_number(upb_json_parser *p, bool is_quoted);
+
+static bool end_number(upb_json_parser *p, const char *ptr) {
+  if (!capture_end(p, ptr)) {
+    return false;
+  }
+
+  return parse_number(p, false);
+}
+
+/* |buf| is NULL-terminated. |buf| itself will never include quotes;
+ * |is_quoted| tells us whether this text originally appeared inside quotes. */
+static bool parse_number_from_buffer(upb_json_parser *p, const char *buf,
+                                     bool is_quoted) {
+  size_t len = strlen(buf);
+  const char *bufend = buf + len;
+  char *end;
+  upb_fieldtype_t type = upb_fielddef_type(p->top->f);
+  double val;
+  double dummy;
+  double inf = 1.0 / 0.0;  /* C89 does not have an INFINITY macro. */
+
+  errno = 0;
+
+  if (len == 0 || buf[0] == ' ') {
+    return false;
+  }
+
+  /* For integer types, first try parsing with integer-specific routines.
+   * If these succeed, they will be more accurate for int64/uint64 than
+   * strtod().
+   */
+  switch (type) {
+    case UPB_TYPE_ENUM:
+    case UPB_TYPE_INT32: {
+      long val = strtol(buf, &end, 0);
+      if (errno == ERANGE || end != bufend) {
+        break;
+      } else if (val > INT32_MAX || val < INT32_MIN) {
+        return false;
+      } else {
+        upb_sink_putint32(&p->top->sink, parser_getsel(p), val);
+        return true;
+      }
+    }
+    case UPB_TYPE_UINT32: {
+      unsigned long val = strtoul(buf, &end, 0);
+      if (end != bufend) {
+        break;
+      } else if (val > UINT32_MAX || errno == ERANGE) {
+        return false;
+      } else {
+        upb_sink_putuint32(&p->top->sink, parser_getsel(p), val);
+        return true;
+      }
+    }
+    /* XXX: We can't handle [u]int64 properly on 32-bit machines because
+     * strto[u]ll isn't in C89. */
+    case UPB_TYPE_INT64: {
+      long val = strtol(buf, &end, 0);
+      if (errno == ERANGE || end != bufend) {
+        break;
+      } else {
+        upb_sink_putint64(&p->top->sink, parser_getsel(p), val);
+        return true;
+      }
+    }
+    case UPB_TYPE_UINT64: {
+      unsigned long val = strtoul(p->accumulated, &end, 0);
+      if (end != bufend) {
+        break;
+      } else if (errno == ERANGE) {
+        return false;
+      } else {
+        upb_sink_putuint64(&p->top->sink, parser_getsel(p), val);
+        return true;
+      }
+    }
+    default:
+      break;
+  }
+
+  if (type != UPB_TYPE_DOUBLE && type != UPB_TYPE_FLOAT && is_quoted) {
+    /* Quoted numbers for integer types are not allowed to be in double form. */
+    return false;
+  }
+
+  if (len == strlen("Infinity") && strcmp(buf, "Infinity") == 0) {
+    /* C89 does not have an INFINITY macro. */
+    val = inf;
+  } else if (len == strlen("-Infinity") && strcmp(buf, "-Infinity") == 0) {
+    val = -inf;
+  } else {
+    val = strtod(buf, &end);
+    if (errno == ERANGE || end != bufend) {
+      return false;
+    }
+  }
+
+  switch (type) {
+#define CASE(capitaltype, smalltype, ctype, min, max)                     \
+    case UPB_TYPE_ ## capitaltype: {                                      \
+      if (modf(val, &dummy) != 0 || val > max || val < min) {             \
+        return false;                                                     \
+      } else {                                                            \
+        upb_sink_put ## smalltype(&p->top->sink, parser_getsel(p),        \
+                                  (ctype)val);                            \
+        return true;                                                      \
+      }                                                                   \
+      break;                                                              \
+    }
+    case UPB_TYPE_ENUM:
+    CASE(INT32, int32, int32_t, INT32_MIN, INT32_MAX);
+    CASE(INT64, int64, int64_t, INT64_MIN, INT64_MAX);
+    CASE(UINT32, uint32, uint32_t, 0, UINT32_MAX);
+    CASE(UINT64, uint64, uint64_t, 0, UINT64_MAX);
+#undef CASE
+
+    case UPB_TYPE_DOUBLE:
+      upb_sink_putdouble(&p->top->sink, parser_getsel(p), val);
+      return true;
+    case UPB_TYPE_FLOAT:
+      if ((val > FLT_MAX || val < -FLT_MAX) && val != inf && val != -inf) {
+        return false;
+      } else {
+        upb_sink_putfloat(&p->top->sink, parser_getsel(p), val);
+        return true;
+      }
+    default:
+      return false;
+  }
+}
+
+static bool parse_number(upb_json_parser *p, bool is_quoted) {
+  size_t len;
+  const char *buf;
+
+  /* strtol() and friends unfortunately do not support specifying the length of
+   * the input string, so we need to force a copy into a NULL-terminated buffer. */
+  if (!multipart_text(p, "\0", 1, false)) {
+    return false;
+  }
+
+  buf = accumulate_getptr(p, &len);
+
+  if (parse_number_from_buffer(p, buf, is_quoted)) {
+    multipart_end(p);
+    return true;
+  } else {
+    upb_status_seterrf(&p->status, "error parsing number: %s", buf);
+    upb_env_reporterror(p->env, &p->status);
+    multipart_end(p);
+    return false;
+  }
+}
+
+static bool parser_putbool(upb_json_parser *p, bool val) {
+  bool ok;
+
+  if (upb_fielddef_type(p->top->f) != UPB_TYPE_BOOL) {
+    upb_status_seterrf(&p->status,
+                       "Boolean value specified for non-bool field: %s",
+                       upb_fielddef_name(p->top->f));
+    upb_env_reporterror(p->env, &p->status);
+    return false;
+  }
+
+  ok = upb_sink_putbool(&p->top->sink, parser_getsel(p), val);
+  UPB_ASSERT(ok);
+
+  return true;
+}
+
+static bool start_stringval(upb_json_parser *p) {
+  UPB_ASSERT(p->top->f);
+
+  if (upb_fielddef_isstring(p->top->f)) {
+    upb_jsonparser_frame *inner;
+    upb_selector_t sel;
+
+    if (!check_stack(p)) return false;
+
+    /* Start a new parser frame: parser frames correspond one-to-one with
+     * handler frames, and string events occur in a sub-frame. */
+    inner = p->top + 1;
+    sel = getsel_for_handlertype(p, UPB_HANDLER_STARTSTR);
+    upb_sink_startstr(&p->top->sink, sel, 0, &inner->sink);
+    inner->m = p->top->m;
+    inner->f = p->top->f;
+    inner->name_table = NULL;
+    inner->is_map = false;
+    inner->is_mapentry = false;
+    p->top = inner;
+
+    if (upb_fielddef_type(p->top->f) == UPB_TYPE_STRING) {
+      /* For STRING fields we push data directly to the handlers as it is
+       * parsed.  We don't do this yet for BYTES fields, because our base64
+       * decoder is not streaming.
+       *
+       * TODO(haberman): make base64 decoding streaming also. */
+      multipart_start(p, getsel_for_handlertype(p, UPB_HANDLER_STRING));
+      return true;
+    } else {
+      multipart_startaccum(p);
+      return true;
+    }
+  } else if (upb_fielddef_type(p->top->f) != UPB_TYPE_BOOL &&
+             upb_fielddef_type(p->top->f) != UPB_TYPE_MESSAGE) {
+    /* No need to push a frame -- numeric values in quotes remain in the
+     * current parser frame.  These values must accmulate so we can convert
+     * them all at once at the end. */
+    multipart_startaccum(p);
+    return true;
+  } else {
+    upb_status_seterrf(&p->status,
+                       "String specified for bool or submessage field: %s",
+                       upb_fielddef_name(p->top->f));
+    upb_env_reporterror(p->env, &p->status);
+    return false;
+  }
+}
+
+static bool end_stringval(upb_json_parser *p) {
+  bool ok = true;
+
+  switch (upb_fielddef_type(p->top->f)) {
+    case UPB_TYPE_BYTES:
+      if (!base64_push(p, getsel_for_handlertype(p, UPB_HANDLER_STRING),
+                       p->accumulated, p->accumulated_len)) {
+        return false;
+      }
+      /* Fall through. */
+
+    case UPB_TYPE_STRING: {
+      upb_selector_t sel = getsel_for_handlertype(p, UPB_HANDLER_ENDSTR);
+      p->top--;
+      upb_sink_endstr(&p->top->sink, sel);
+      break;
+    }
+
+    case UPB_TYPE_ENUM: {
+      /* Resolve enum symbolic name to integer value. */
+      const upb_enumdef *enumdef =
+          (const upb_enumdef*)upb_fielddef_subdef(p->top->f);
+
+      size_t len;
+      const char *buf = accumulate_getptr(p, &len);
+
+      int32_t int_val = 0;
+      ok = upb_enumdef_ntoi(enumdef, buf, len, &int_val);
+
+      if (ok) {
+        upb_selector_t sel = parser_getsel(p);
+        upb_sink_putint32(&p->top->sink, sel, int_val);
+      } else {
+        upb_status_seterrf(&p->status, "Enum value unknown: '%.*s'", len, buf);
+        upb_env_reporterror(p->env, &p->status);
+      }
+
+      break;
+    }
+
+    case UPB_TYPE_INT32:
+    case UPB_TYPE_INT64:
+    case UPB_TYPE_UINT32:
+    case UPB_TYPE_UINT64:
+    case UPB_TYPE_DOUBLE:
+    case UPB_TYPE_FLOAT:
+      ok = parse_number(p, true);
+      break;
+
+    default:
+      UPB_ASSERT(false);
+      upb_status_seterrmsg(&p->status, "Internal error in JSON decoder");
+      upb_env_reporterror(p->env, &p->status);
+      ok = false;
+      break;
+  }
+
+  multipart_end(p);
+
+  return ok;
+}
+
+static void start_member(upb_json_parser *p) {
+  UPB_ASSERT(!p->top->f);
+  multipart_startaccum(p);
+}
+
+/* Helper: invoked during parse_mapentry() to emit the mapentry message's key
+ * field based on the current contents of the accumulate buffer. */
+static bool parse_mapentry_key(upb_json_parser *p) {
+
+  size_t len;
+  const char *buf = accumulate_getptr(p, &len);
+
+  /* Emit the key field. We do a bit of ad-hoc parsing here because the
+   * parser state machine has already decided that this is a string field
+   * name, and we are reinterpreting it as some arbitrary key type. In
+   * particular, integer and bool keys are quoted, so we need to parse the
+   * quoted string contents here. */
+
+  p->top->f = upb_msgdef_itof(p->top->m, UPB_MAPENTRY_KEY);
+  if (p->top->f == NULL) {
+    upb_status_seterrmsg(&p->status, "mapentry message has no key");
+    upb_env_reporterror(p->env, &p->status);
+    return false;
+  }
+  switch (upb_fielddef_type(p->top->f)) {
+    case UPB_TYPE_INT32:
+    case UPB_TYPE_INT64:
+    case UPB_TYPE_UINT32:
+    case UPB_TYPE_UINT64:
+      /* Invoke end_number. The accum buffer has the number's text already. */
+      if (!parse_number(p, true)) {
+        return false;
+      }
+      break;
+    case UPB_TYPE_BOOL:
+      if (len == 4 && !strncmp(buf, "true", 4)) {
+        if (!parser_putbool(p, true)) {
+          return false;
+        }
+      } else if (len == 5 && !strncmp(buf, "false", 5)) {
+        if (!parser_putbool(p, false)) {
+          return false;
+        }
+      } else {
+        upb_status_seterrmsg(&p->status,
+                             "Map bool key not 'true' or 'false'");
+        upb_env_reporterror(p->env, &p->status);
+        return false;
+      }
+      multipart_end(p);
+      break;
+    case UPB_TYPE_STRING:
+    case UPB_TYPE_BYTES: {
+      upb_sink subsink;
+      upb_selector_t sel = getsel_for_handlertype(p, UPB_HANDLER_STARTSTR);
+      upb_sink_startstr(&p->top->sink, sel, len, &subsink);
+      sel = getsel_for_handlertype(p, UPB_HANDLER_STRING);
+      upb_sink_putstring(&subsink, sel, buf, len, NULL);
+      sel = getsel_for_handlertype(p, UPB_HANDLER_ENDSTR);
+      upb_sink_endstr(&p->top->sink, sel);
+      multipart_end(p);
+      break;
+    }
+    default:
+      upb_status_seterrmsg(&p->status, "Invalid field type for map key");
+      upb_env_reporterror(p->env, &p->status);
+      return false;
+  }
+
+  return true;
+}
+
+/* Helper: emit one map entry (as a submessage in the map field sequence). This
+ * is invoked from end_membername(), at the end of the map entry's key string,
+ * with the map key in the accumulate buffer. It parses the key from that
+ * buffer, emits the handler calls to start the mapentry submessage (setting up
+ * its subframe in the process), and sets up state in the subframe so that the
+ * value parser (invoked next) will emit the mapentry's value field and then
+ * end the mapentry message. */
+
+static bool handle_mapentry(upb_json_parser *p) {
+  const upb_fielddef *mapfield;
+  const upb_msgdef *mapentrymsg;
+  upb_jsonparser_frame *inner;
+  upb_selector_t sel;
+
+  /* Map entry: p->top->sink is the seq frame, so we need to start a frame
+   * for the mapentry itself, and then set |f| in that frame so that the map
+   * value field is parsed, and also set a flag to end the frame after the
+   * map-entry value is parsed. */
+  if (!check_stack(p)) return false;
+
+  mapfield = p->top->mapfield;
+  mapentrymsg = upb_fielddef_msgsubdef(mapfield);
+
+  inner = p->top + 1;
+  p->top->f = mapfield;
+  sel = getsel_for_handlertype(p, UPB_HANDLER_STARTSUBMSG);
+  upb_sink_startsubmsg(&p->top->sink, sel, &inner->sink);
+  inner->m = mapentrymsg;
+  inner->name_table = NULL;
+  inner->mapfield = mapfield;
+  inner->is_map = false;
+
+  /* Don't set this to true *yet* -- we reuse parsing handlers below to push
+   * the key field value to the sink, and these handlers will pop the frame
+   * if they see is_mapentry (when invoked by the parser state machine, they
+   * would have just seen the map-entry value, not key). */
+  inner->is_mapentry = false;
+  p->top = inner;
+
+  /* send STARTMSG in submsg frame. */
+  upb_sink_startmsg(&p->top->sink);
+
+  parse_mapentry_key(p);
+
+  /* Set up the value field to receive the map-entry value. */
+  p->top->f = upb_msgdef_itof(p->top->m, UPB_MAPENTRY_VALUE);
+  p->top->is_mapentry = true;  /* set up to pop frame after value is parsed. */
+  p->top->mapfield = mapfield;
+  if (p->top->f == NULL) {
+    upb_status_seterrmsg(&p->status, "mapentry message has no value");
+    upb_env_reporterror(p->env, &p->status);
+    return false;
+  }
+
+  return true;
+}
+
+static bool end_membername(upb_json_parser *p) {
+  UPB_ASSERT(!p->top->f);
+
+  if (p->top->is_map) {
+    return handle_mapentry(p);
+  } else {
+    size_t len;
+    const char *buf = accumulate_getptr(p, &len);
+    upb_value v;
+
+    if (upb_strtable_lookup2(p->top->name_table, buf, len, &v)) {
+      p->top->f = upb_value_getconstptr(v);
+      multipart_end(p);
+
+      return true;
+    } else {
+      /* TODO(haberman): Ignore unknown fields if requested/configured to do
+       * so. */
+      upb_status_seterrf(&p->status, "No such field: %.*s\n", (int)len, buf);
+      upb_env_reporterror(p->env, &p->status);
+      return false;
+    }
+  }
+}
+
+static void end_member(upb_json_parser *p) {
+  /* If we just parsed a map-entry value, end that frame too. */
+  if (p->top->is_mapentry) {
+    upb_status s = UPB_STATUS_INIT;
+    upb_selector_t sel;
+    bool ok;
+    const upb_fielddef *mapfield;
+
+    UPB_ASSERT(p->top > p->stack);
+    /* send ENDMSG on submsg. */
+    upb_sink_endmsg(&p->top->sink, &s);
+    mapfield = p->top->mapfield;
+
+    /* send ENDSUBMSG in repeated-field-of-mapentries frame. */
+    p->top--;
+    ok = upb_handlers_getselector(mapfield, UPB_HANDLER_ENDSUBMSG, &sel);
+    UPB_ASSERT(ok);
+    upb_sink_endsubmsg(&p->top->sink, sel);
+  }
+
+  p->top->f = NULL;
+}
+
+static bool start_subobject(upb_json_parser *p) {
+  UPB_ASSERT(p->top->f);
+
+  if (upb_fielddef_ismap(p->top->f)) {
+    upb_jsonparser_frame *inner;
+    upb_selector_t sel;
+
+    /* Beginning of a map. Start a new parser frame in a repeated-field
+     * context. */
+    if (!check_stack(p)) return false;
+
+    inner = p->top + 1;
+    sel = getsel_for_handlertype(p, UPB_HANDLER_STARTSEQ);
+    upb_sink_startseq(&p->top->sink, sel, &inner->sink);
+    inner->m = upb_fielddef_msgsubdef(p->top->f);
+    inner->name_table = NULL;
+    inner->mapfield = p->top->f;
+    inner->f = NULL;
+    inner->is_map = true;
+    inner->is_mapentry = false;
+    p->top = inner;
+
+    return true;
+  } else if (upb_fielddef_issubmsg(p->top->f)) {
+    upb_jsonparser_frame *inner;
+    upb_selector_t sel;
+
+    /* Beginning of a subobject. Start a new parser frame in the submsg
+     * context. */
+    if (!check_stack(p)) return false;
+
+    inner = p->top + 1;
+
+    sel = getsel_for_handlertype(p, UPB_HANDLER_STARTSUBMSG);
+    upb_sink_startsubmsg(&p->top->sink, sel, &inner->sink);
+    inner->m = upb_fielddef_msgsubdef(p->top->f);
+    set_name_table(p, inner);
+    inner->f = NULL;
+    inner->is_map = false;
+    inner->is_mapentry = false;
+    p->top = inner;
+
+    return true;
+  } else {
+    upb_status_seterrf(&p->status,
+                       "Object specified for non-message/group field: %s",
+                       upb_fielddef_name(p->top->f));
+    upb_env_reporterror(p->env, &p->status);
+    return false;
+  }
+}
+
+static void end_subobject(upb_json_parser *p) {
+  if (p->top->is_map) {
+    upb_selector_t sel;
+    p->top--;
+    sel = getsel_for_handlertype(p, UPB_HANDLER_ENDSEQ);
+    upb_sink_endseq(&p->top->sink, sel);
+  } else {
+    upb_selector_t sel;
+    p->top--;
+    sel = getsel_for_handlertype(p, UPB_HANDLER_ENDSUBMSG);
+    upb_sink_endsubmsg(&p->top->sink, sel);
+  }
+}
+
+static bool start_array(upb_json_parser *p) {
+  upb_jsonparser_frame *inner;
+  upb_selector_t sel;
+
+  UPB_ASSERT(p->top->f);
+
+  if (!upb_fielddef_isseq(p->top->f)) {
+    upb_status_seterrf(&p->status,
+                       "Array specified for non-repeated field: %s",
+                       upb_fielddef_name(p->top->f));
+    upb_env_reporterror(p->env, &p->status);
+    return false;
+  }
+
+  if (!check_stack(p)) return false;
+
+  inner = p->top + 1;
+  sel = getsel_for_handlertype(p, UPB_HANDLER_STARTSEQ);
+  upb_sink_startseq(&p->top->sink, sel, &inner->sink);
+  inner->m = p->top->m;
+  inner->name_table = NULL;
+  inner->f = p->top->f;
+  inner->is_map = false;
+  inner->is_mapentry = false;
+  p->top = inner;
+
+  return true;
+}
+
+static void end_array(upb_json_parser *p) {
+  upb_selector_t sel;
+
+  UPB_ASSERT(p->top > p->stack);
+
+  p->top--;
+  sel = getsel_for_handlertype(p, UPB_HANDLER_ENDSEQ);
+  upb_sink_endseq(&p->top->sink, sel);
+}
+
+static void start_object(upb_json_parser *p) {
+  if (!p->top->is_map) {
+    upb_sink_startmsg(&p->top->sink);
+  }
+}
+
+static void end_object(upb_json_parser *p) {
+  if (!p->top->is_map) {
+    upb_status status;
+    upb_status_clear(&status);
+    upb_sink_endmsg(&p->top->sink, &status);
+    if (!upb_ok(&status)) {
+      upb_env_reporterror(p->env, &status);
+    }
+  }
+}
+
+
+#define CHECK_RETURN_TOP(x) if (!(x)) goto error
+
+
+/* The actual parser **********************************************************/
+
+/* What follows is the Ragel parser itself.  The language is specified in Ragel
+ * and the actions call our C functions above.
+ *
+ * Ragel has an extensive set of functionality, and we use only a small part of
+ * it.  There are many action types but we only use a few:
+ *
+ *   ">" -- transition into a machine
+ *   "%" -- transition out of a machine
+ *   "@" -- transition into a final state of a machine.
+ *
+ * "@" transitions are tricky because a machine can transition into a final
+ * state repeatedly.  But in some cases we know this can't happen, for example
+ * a string which is delimited by a final '"' can only transition into its
+ * final state once, when the closing '"' is seen. */
+
+
+#line 1310 "upb/json/parser.rl"
+
+
+
+#line 1222 "upb/json/parser.c"
+static const char _json_actions[] = {
+	0, 1, 0, 1, 2, 1, 3, 1, 
+	5, 1, 6, 1, 7, 1, 8, 1, 
+	10, 1, 12, 1, 13, 1, 14, 1, 
+	15, 1, 16, 1, 17, 1, 21, 1, 
+	25, 1, 27, 2, 3, 8, 2, 4, 
+	5, 2, 6, 2, 2, 6, 8, 2, 
+	11, 9, 2, 13, 15, 2, 14, 15, 
+	2, 18, 1, 2, 19, 27, 2, 20, 
+	9, 2, 22, 27, 2, 23, 27, 2, 
+	24, 27, 2, 26, 27, 3, 14, 11, 
+	9
+};
+
+static const unsigned char _json_key_offsets[] = {
+	0, 0, 4, 9, 14, 15, 19, 24, 
+	29, 34, 38, 42, 45, 48, 50, 54, 
+	58, 60, 62, 67, 69, 71, 80, 86, 
+	92, 98, 104, 106, 115, 116, 116, 116, 
+	121, 126, 131, 132, 133, 134, 135, 135, 
+	136, 137, 138, 138, 139, 140, 141, 141, 
+	146, 151, 152, 156, 161, 166, 171, 175, 
+	175, 178, 178, 178
+};
+
+static const char _json_trans_keys[] = {
+	32, 123, 9, 13, 32, 34, 125, 9, 
+	13, 32, 34, 125, 9, 13, 34, 32, 
+	58, 9, 13, 32, 93, 125, 9, 13, 
+	32, 44, 125, 9, 13, 32, 44, 125, 
+	9, 13, 32, 34, 9, 13, 45, 48, 
+	49, 57, 48, 49, 57, 46, 69, 101, 
+	48, 57, 69, 101, 48, 57, 43, 45, 
+	48, 57, 48, 57, 48, 57, 46, 69, 
+	101, 48, 57, 34, 92, 34, 92, 34, 
+	47, 92, 98, 102, 110, 114, 116, 117, 
+	48, 57, 65, 70, 97, 102, 48, 57, 
+	65, 70, 97, 102, 48, 57, 65, 70, 
+	97, 102, 48, 57, 65, 70, 97, 102, 
+	34, 92, 34, 45, 91, 102, 110, 116, 
+	123, 48, 57, 34, 32, 93, 125, 9, 
+	13, 32, 44, 93, 9, 13, 32, 93, 
+	125, 9, 13, 97, 108, 115, 101, 117, 
+	108, 108, 114, 117, 101, 32, 34, 125, 
+	9, 13, 32, 34, 125, 9, 13, 34, 
+	32, 58, 9, 13, 32, 93, 125, 9, 
+	13, 32, 44, 125, 9, 13, 32, 44, 
+	125, 9, 13, 32, 34, 9, 13, 32, 
+	9, 13, 0
+};
+
+static const char _json_single_lengths[] = {
+	0, 2, 3, 3, 1, 2, 3, 3, 
+	3, 2, 2, 1, 3, 0, 2, 2, 
+	0, 0, 3, 2, 2, 9, 0, 0, 
+	0, 0, 2, 7, 1, 0, 0, 3, 
+	3, 3, 1, 1, 1, 1, 0, 1, 
+	1, 1, 0, 1, 1, 1, 0, 3, 
+	3, 1, 2, 3, 3, 3, 2, 0, 
+	1, 0, 0, 0
+};
+
+static const char _json_range_lengths[] = {
+	0, 1, 1, 1, 0, 1, 1, 1, 
+	1, 1, 1, 1, 0, 1, 1, 1, 
+	1, 1, 1, 0, 0, 0, 3, 3, 
+	3, 3, 0, 1, 0, 0, 0, 1, 
+	1, 1, 0, 0, 0, 0, 0, 0, 
+	0, 0, 0, 0, 0, 0, 0, 1, 
+	1, 0, 1, 1, 1, 1, 1, 0, 
+	1, 0, 0, 0
+};
+
+static const short _json_index_offsets[] = {
+	0, 0, 4, 9, 14, 16, 20, 25, 
+	30, 35, 39, 43, 46, 50, 52, 56, 
+	60, 62, 64, 69, 72, 75, 85, 89, 
+	93, 97, 101, 104, 113, 115, 116, 117, 
+	122, 127, 132, 134, 136, 138, 140, 141, 
+	143, 145, 147, 148, 150, 152, 154, 155, 
+	160, 165, 167, 171, 176, 181, 186, 190, 
+	191, 194, 195, 196
+};
+
+static const char _json_indicies[] = {
+	0, 2, 0, 1, 3, 4, 5, 3, 
+	1, 6, 7, 8, 6, 1, 9, 1, 
+	10, 11, 10, 1, 11, 1, 1, 11, 
+	12, 13, 14, 15, 13, 1, 16, 17, 
+	8, 16, 1, 17, 7, 17, 1, 18, 
+	19, 20, 1, 19, 20, 1, 22, 23, 
+	23, 21, 24, 1, 23, 23, 24, 21, 
+	25, 25, 26, 1, 26, 1, 26, 21, 
+	22, 23, 23, 20, 21, 28, 29, 27, 
+	31, 32, 30, 33, 33, 33, 33, 33, 
+	33, 33, 33, 34, 1, 35, 35, 35, 
+	1, 36, 36, 36, 1, 37, 37, 37, 
+	1, 38, 38, 38, 1, 40, 41, 39, 
+	42, 43, 44, 45, 46, 47, 48, 43, 
+	1, 49, 1, 50, 51, 53, 54, 1, 
+	53, 52, 55, 56, 54, 55, 1, 56, 
+	1, 1, 56, 52, 57, 1, 58, 1, 
+	59, 1, 60, 1, 61, 62, 1, 63, 
+	1, 64, 1, 65, 66, 1, 67, 1, 
+	68, 1, 69, 70, 71, 72, 70, 1, 
+	73, 74, 75, 73, 1, 76, 1, 77, 
+	78, 77, 1, 78, 1, 1, 78, 79, 
+	80, 81, 82, 80, 1, 83, 84, 75, 
+	83, 1, 84, 74, 84, 1, 85, 86, 
+	86, 1, 1, 1, 1, 0
+};
+
+static const char _json_trans_targs[] = {
+	1, 0, 2, 3, 4, 56, 3, 4, 
+	56, 5, 5, 6, 7, 8, 9, 56, 
+	8, 9, 11, 12, 18, 57, 13, 15, 
+	14, 16, 17, 20, 58, 21, 20, 58, 
+	21, 19, 22, 23, 24, 25, 26, 20, 
+	58, 21, 28, 30, 31, 34, 39, 43, 
+	47, 29, 59, 59, 32, 31, 29, 32, 
+	33, 35, 36, 37, 38, 59, 40, 41, 
+	42, 59, 44, 45, 46, 59, 48, 49, 
+	55, 48, 49, 55, 50, 50, 51, 52, 
+	53, 54, 55, 53, 54, 59, 56
+};
+
+static const char _json_trans_actions[] = {
+	0, 0, 0, 21, 77, 53, 0, 47, 
+	23, 17, 0, 0, 15, 19, 19, 50, 
+	0, 0, 0, 0, 0, 1, 0, 0, 
+	0, 0, 0, 3, 13, 0, 0, 35, 
+	5, 11, 0, 38, 7, 7, 7, 41, 
+	44, 9, 62, 56, 25, 0, 0, 0, 
+	31, 29, 33, 59, 15, 0, 27, 0, 
+	0, 0, 0, 0, 0, 68, 0, 0, 
+	0, 71, 0, 0, 0, 65, 21, 77, 
+	53, 0, 47, 23, 17, 0, 0, 15, 
+	19, 19, 50, 0, 0, 74, 0
+};
+
+static const int json_start = 1;
+
+static const int json_en_number_machine = 10;
+static const int json_en_string_machine = 19;
+static const int json_en_value_machine = 27;
+static const int json_en_main = 1;
+
+
+#line 1313 "upb/json/parser.rl"
+
+size_t parse(void *closure, const void *hd, const char *buf, size_t size,
+             const upb_bufhandle *handle) {
+  upb_json_parser *parser = closure;
+
+  /* Variables used by Ragel's generated code. */
+  int cs = parser->current_state;
+  int *stack = parser->parser_stack;
+  int top = parser->parser_top;
+
+  const char *p = buf;
+  const char *pe = buf + size;
+
+  parser->handle = handle;
+
+  UPB_UNUSED(hd);
+  UPB_UNUSED(handle);
+
+  capture_resume(parser, buf);
+
+  
+#line 1393 "upb/json/parser.c"
+	{
+	int _klen;
+	unsigned int _trans;
+	const char *_acts;
+	unsigned int _nacts;
+	const char *_keys;
+
+	if ( p == pe )
+		goto _test_eof;
+	if ( cs == 0 )
+		goto _out;
+_resume:
+	_keys = _json_trans_keys + _json_key_offsets[cs];
+	_trans = _json_index_offsets[cs];
+
+	_klen = _json_single_lengths[cs];
+	if ( _klen > 0 ) {
+		const char *_lower = _keys;
+		const char *_mid;
+		const char *_upper = _keys + _klen - 1;
+		while (1) {
+			if ( _upper < _lower )
+				break;
+
+			_mid = _lower + ((_upper-_lower) >> 1);
+			if ( (*p) < *_mid )
+				_upper = _mid - 1;
+			else if ( (*p) > *_mid )
+				_lower = _mid + 1;
+			else {
+				_trans += (unsigned int)(_mid - _keys);
+				goto _match;
+			}
+		}
+		_keys += _klen;
+		_trans += _klen;
+	}
+
+	_klen = _json_range_lengths[cs];
+	if ( _klen > 0 ) {
+		const char *_lower = _keys;
+		const char *_mid;
+		const char *_upper = _keys + (_klen<<1) - 2;
+		while (1) {
+			if ( _upper < _lower )
+				break;
+
+			_mid = _lower + (((_upper-_lower) >> 1) & ~1);
+			if ( (*p) < _mid[0] )
+				_upper = _mid - 2;
+			else if ( (*p) > _mid[1] )
+				_lower = _mid + 2;
+			else {
+				_trans += (unsigned int)((_mid - _keys)>>1);
+				goto _match;
+			}
+		}
+		_trans += _klen;
+	}
+
+_match:
+	_trans = _json_indicies[_trans];
+	cs = _json_trans_targs[_trans];
+
+	if ( _json_trans_actions[_trans] == 0 )
+		goto _again;
+
+	_acts = _json_actions + _json_trans_actions[_trans];
+	_nacts = (unsigned int) *_acts++;
+	while ( _nacts-- > 0 )
+	{
+		switch ( *_acts++ )
+		{
+	case 0:
+#line 1225 "upb/json/parser.rl"
+	{ p--; {cs = stack[--top]; goto _again;} }
+	break;
+	case 1:
+#line 1226 "upb/json/parser.rl"
+	{ p--; {stack[top++] = cs; cs = 10; goto _again;} }
+	break;
+	case 2:
+#line 1230 "upb/json/parser.rl"
+	{ start_text(parser, p); }
+	break;
+	case 3:
+#line 1231 "upb/json/parser.rl"
+	{ CHECK_RETURN_TOP(end_text(parser, p)); }
+	break;
+	case 4:
+#line 1237 "upb/json/parser.rl"
+	{ start_hex(parser); }
+	break;
+	case 5:
+#line 1238 "upb/json/parser.rl"
+	{ hexdigit(parser, p); }
+	break;
+	case 6:
+#line 1239 "upb/json/parser.rl"
+	{ CHECK_RETURN_TOP(end_hex(parser)); }
+	break;
+	case 7:
+#line 1245 "upb/json/parser.rl"
+	{ CHECK_RETURN_TOP(escape(parser, p)); }
+	break;
+	case 8:
+#line 1251 "upb/json/parser.rl"
+	{ p--; {cs = stack[--top]; goto _again;} }
+	break;
+	case 9:
+#line 1254 "upb/json/parser.rl"
+	{ {stack[top++] = cs; cs = 19; goto _again;} }
+	break;
+	case 10:
+#line 1256 "upb/json/parser.rl"
+	{ p--; {stack[top++] = cs; cs = 27; goto _again;} }
+	break;
+	case 11:
+#line 1261 "upb/json/parser.rl"
+	{ start_member(parser); }
+	break;
+	case 12:
+#line 1262 "upb/json/parser.rl"
+	{ CHECK_RETURN_TOP(end_membername(parser)); }
+	break;
+	case 13:
+#line 1265 "upb/json/parser.rl"
+	{ end_member(parser); }
+	break;
+	case 14:
+#line 1271 "upb/json/parser.rl"
+	{ start_object(parser); }
+	break;
+	case 15:
+#line 1274 "upb/json/parser.rl"
+	{ end_object(parser); }
+	break;
+	case 16:
+#line 1280 "upb/json/parser.rl"
+	{ CHECK_RETURN_TOP(start_array(parser)); }
+	break;
+	case 17:
+#line 1284 "upb/json/parser.rl"
+	{ end_array(parser); }
+	break;
+	case 18:
+#line 1289 "upb/json/parser.rl"
+	{ start_number(parser, p); }
+	break;
+	case 19:
+#line 1290 "upb/json/parser.rl"
+	{ CHECK_RETURN_TOP(end_number(parser, p)); }
+	break;
+	case 20:
+#line 1292 "upb/json/parser.rl"
+	{ CHECK_RETURN_TOP(start_stringval(parser)); }
+	break;
+	case 21:
+#line 1293 "upb/json/parser.rl"
+	{ CHECK_RETURN_TOP(end_stringval(parser)); }
+	break;
+	case 22:
+#line 1295 "upb/json/parser.rl"
+	{ CHECK_RETURN_TOP(parser_putbool(parser, true)); }
+	break;
+	case 23:
+#line 1297 "upb/json/parser.rl"
+	{ CHECK_RETURN_TOP(parser_putbool(parser, false)); }
+	break;
+	case 24:
+#line 1299 "upb/json/parser.rl"
+	{ /* null value */ }
+	break;
+	case 25:
+#line 1301 "upb/json/parser.rl"
+	{ CHECK_RETURN_TOP(start_subobject(parser)); }
+	break;
+	case 26:
+#line 1302 "upb/json/parser.rl"
+	{ end_subobject(parser); }
+	break;
+	case 27:
+#line 1307 "upb/json/parser.rl"
+	{ p--; {cs = stack[--top]; goto _again;} }
+	break;
+#line 1579 "upb/json/parser.c"
+		}
+	}
+
+_again:
+	if ( cs == 0 )
+		goto _out;
+	if ( ++p != pe )
+		goto _resume;
+	_test_eof: {}
+	_out: {}
+	}
+
+#line 1334 "upb/json/parser.rl"
+
+  if (p != pe) {
+    upb_status_seterrf(&parser->status, "Parse error at '%.*s'\n", pe - p, p);
+    upb_env_reporterror(parser->env, &parser->status);
+  } else {
+    capture_suspend(parser, &p);
+  }
+
+error:
+  /* Save parsing state back to parser. */
+  parser->current_state = cs;
+  parser->parser_top = top;
+
+  return p - buf;
+}
+
+bool end(void *closure, const void *hd) {
+  UPB_UNUSED(closure);
+  UPB_UNUSED(hd);
+
+  /* Prevent compile warning on unused static constants. */
+  UPB_UNUSED(json_start);
+  UPB_UNUSED(json_en_number_machine);
+  UPB_UNUSED(json_en_string_machine);
+  UPB_UNUSED(json_en_value_machine);
+  UPB_UNUSED(json_en_main);
+  return true;
+}
+
+static void json_parser_reset(upb_json_parser *p) {
+  int cs;
+  int top;
+
+  p->top = p->stack;
+  p->top->f = NULL;
+  p->top->is_map = false;
+  p->top->is_mapentry = false;
+
+  /* Emit Ragel initialization of the parser. */
+  
+#line 1633 "upb/json/parser.c"
+	{
+	cs = json_start;
+	top = 0;
+	}
+
+#line 1374 "upb/json/parser.rl"
+  p->current_state = cs;
+  p->parser_top = top;
+  accumulate_clear(p);
+  p->multipart_state = MULTIPART_INACTIVE;
+  p->capture = NULL;
+  p->accumulated = NULL;
+  upb_status_clear(&p->status);
+}
+
+static void visit_json_parsermethod(const upb_refcounted *r,
+                                    upb_refcounted_visit *visit,
+                                    void *closure) {
+  const upb_json_parsermethod *method = (upb_json_parsermethod*)r;
+  visit(r, upb_msgdef_upcast2(method->msg), closure);
+}
+
+static void free_json_parsermethod(upb_refcounted *r) {
+  upb_json_parsermethod *method = (upb_json_parsermethod*)r;
+
+  upb_inttable_iter i;
+  upb_inttable_begin(&i, &method->name_tables);
+  for(; !upb_inttable_done(&i); upb_inttable_next(&i)) {
+    upb_value val = upb_inttable_iter_value(&i);
+    upb_strtable *t = upb_value_getptr(val);
+    upb_strtable_uninit(t);
+    upb_gfree(t);
+  }
+
+  upb_inttable_uninit(&method->name_tables);
+
+  upb_gfree(r);
+}
+
+static void add_jsonname_table(upb_json_parsermethod *m, const upb_msgdef* md) {
+  upb_msg_field_iter i;
+  upb_strtable *t;
+
+  /* It would be nice to stack-allocate this, but protobufs do not limit the
+   * length of fields to any reasonable limit. */
+  char *buf = NULL;
+  size_t len = 0;
+
+  if (upb_inttable_lookupptr(&m->name_tables, md, NULL)) {
+    return;
+  }
+
+  /* TODO(haberman): handle malloc failure. */
+  t = upb_gmalloc(sizeof(*t));
+  upb_strtable_init(t, UPB_CTYPE_CONSTPTR);
+  upb_inttable_insertptr(&m->name_tables, md, upb_value_ptr(t));
+
+  for(upb_msg_field_begin(&i, md);
+      !upb_msg_field_done(&i);
+      upb_msg_field_next(&i)) {
+    const upb_fielddef *f = upb_msg_iter_field(&i);
+
+    /* Add an entry for the JSON name. */
+    size_t field_len = upb_fielddef_getjsonname(f, buf, len);
+    if (field_len > len) {
+      size_t len2;
+      buf = upb_grealloc(buf, 0, field_len);
+      len = field_len;
+      len2 = upb_fielddef_getjsonname(f, buf, len);
+      UPB_ASSERT(len == len2);
+    }
+    upb_strtable_insert(t, buf, upb_value_constptr(f));
+
+    if (strcmp(buf, upb_fielddef_name(f)) != 0) {
+      /* Since the JSON name is different from the regular field name, add an
+       * entry for the raw name (compliant proto3 JSON parsers must accept
+       * both). */
+      upb_strtable_insert(t, upb_fielddef_name(f), upb_value_constptr(f));
+    }
+
+    if (upb_fielddef_issubmsg(f)) {
+      add_jsonname_table(m, upb_fielddef_msgsubdef(f));
+    }
+  }
+
+  upb_gfree(buf);
+}
+
+/* Public API *****************************************************************/
+
+upb_json_parser *upb_json_parser_create(upb_env *env,
+                                        const upb_json_parsermethod *method,
+                                        upb_sink *output) {
+#ifndef NDEBUG
+  const size_t size_before = upb_env_bytesallocated(env);
+#endif
+  upb_json_parser *p = upb_env_malloc(env, sizeof(upb_json_parser));
+  if (!p) return false;
+
+  p->env = env;
+  p->method = method;
+  p->limit = p->stack + UPB_JSON_MAX_DEPTH;
+  p->accumulate_buf = NULL;
+  p->accumulate_buf_size = 0;
+  upb_bytessink_reset(&p->input_, &method->input_handler_, p);
+
+  json_parser_reset(p);
+  upb_sink_reset(&p->top->sink, output->handlers, output->closure);
+  p->top->m = upb_handlers_msgdef(output->handlers);
+  set_name_table(p, p->top);
+
+  /* If this fails, uncomment and increase the value in parser.h. */
+  /* fprintf(stderr, "%zd\n", upb_env_bytesallocated(env) - size_before); */
+  UPB_ASSERT_DEBUGVAR(upb_env_bytesallocated(env) - size_before <=
+                      UPB_JSON_PARSER_SIZE);
+  return p;
+}
+
+upb_bytessink *upb_json_parser_input(upb_json_parser *p) {
+  return &p->input_;
+}
+
+upb_json_parsermethod *upb_json_parsermethod_new(const upb_msgdef* md,
+                                                 const void* owner) {
+  static const struct upb_refcounted_vtbl vtbl = {visit_json_parsermethod,
+                                                  free_json_parsermethod};
+  upb_json_parsermethod *ret = upb_gmalloc(sizeof(*ret));
+  upb_refcounted_init(upb_json_parsermethod_upcast_mutable(ret), &vtbl, owner);
+
+  ret->msg = md;
+  upb_ref2(md, ret);
+
+  upb_byteshandler_init(&ret->input_handler_);
+  upb_byteshandler_setstring(&ret->input_handler_, parse, ret);
+  upb_byteshandler_setendstr(&ret->input_handler_, end, ret);
+
+  upb_inttable_init(&ret->name_tables, UPB_CTYPE_PTR);
+
+  add_jsonname_table(ret, md);
+
+  return ret;
+}
+
+const upb_byteshandler *upb_json_parsermethod_inputhandler(
+    const upb_json_parsermethod *m) {
+  return &m->input_handler_;
+}
+/*
+** This currently uses snprintf() to format primitives, and could be optimized
+** further.
+*/
+
+
+#include <string.h>
+#include <stdint.h>
+
+struct upb_json_printer {
+  upb_sink input_;
+  /* BytesSink closure. */
+  void *subc_;
+  upb_bytessink *output_;
+
+  /* We track the depth so that we know when to emit startstr/endstr on the
+   * output. */
+  int depth_;
+
+  /* Have we emitted the first element? This state is necessary to emit commas
+   * without leaving a trailing comma in arrays/maps. We keep this state per
+   * frame depth.
+   *
+   * Why max_depth * 2? UPB_MAX_HANDLER_DEPTH counts depth as nested messages.
+   * We count frames (contexts in which we separate elements by commas) as both
+   * repeated fields and messages (maps), and the worst case is a
+   * message->repeated field->submessage->repeated field->... nesting. */
+  bool first_elem_[UPB_MAX_HANDLER_DEPTH * 2];
+};
+
+/* StringPiece; a pointer plus a length. */
+typedef struct {
+  char *ptr;
+  size_t len;
+} strpc;
+
+void freestrpc(void *ptr) {
+  strpc *pc = ptr;
+  upb_gfree(pc->ptr);
+  upb_gfree(pc);
+}
+
+/* Convert fielddef name to JSON name and return as a string piece. */
+strpc *newstrpc(upb_handlers *h, const upb_fielddef *f,
+                bool preserve_fieldnames) {
+  /* TODO(haberman): handle malloc failure. */
+  strpc *ret = upb_gmalloc(sizeof(*ret));
+  if (preserve_fieldnames) {
+    ret->ptr = upb_gstrdup(upb_fielddef_name(f));
+    ret->len = strlen(ret->ptr);
+  } else {
+    size_t len;
+    ret->len = upb_fielddef_getjsonname(f, NULL, 0);
+    ret->ptr = upb_gmalloc(ret->len);
+    len = upb_fielddef_getjsonname(f, ret->ptr, ret->len);
+    UPB_ASSERT(len == ret->len);
+    ret->len--;  /* NULL */
+  }
+
+  upb_handlers_addcleanup(h, ret, freestrpc);
+  return ret;
+}
+
+/* ------------ JSON string printing: values, maps, arrays ------------------ */
+
+static void print_data(
+    upb_json_printer *p, const char *buf, unsigned int len) {
+  /* TODO: Will need to change if we support pushback from the sink. */
+  size_t n = upb_bytessink_putbuf(p->output_, p->subc_, buf, len, NULL);
+  UPB_ASSERT(n == len);
+}
+
+static void print_comma(upb_json_printer *p) {
+  if (!p->first_elem_[p->depth_]) {
+    print_data(p, ",", 1);
+  }
+  p->first_elem_[p->depth_] = false;
+}
+
+/* Helpers that print properly formatted elements to the JSON output stream. */
+
+/* Used for escaping control chars in strings. */
+static const char kControlCharLimit = 0x20;
+
+UPB_INLINE bool is_json_escaped(char c) {
+  /* See RFC 4627. */
+  unsigned char uc = (unsigned char)c;
+  return uc < kControlCharLimit || uc == '"' || uc == '\\';
+}
+
+UPB_INLINE const char* json_nice_escape(char c) {
+  switch (c) {
+    case '"':  return "\\\"";
+    case '\\': return "\\\\";
+    case '\b': return "\\b";
+    case '\f': return "\\f";
+    case '\n': return "\\n";
+    case '\r': return "\\r";
+    case '\t': return "\\t";
+    default:   return NULL;
+  }
+}
+
+/* Write a properly escaped string chunk. The surrounding quotes are *not*
+ * printed; this is so that the caller has the option of emitting the string
+ * content in chunks. */
+static void putstring(upb_json_printer *p, const char *buf, unsigned int len) {
+  const char* unescaped_run = NULL;
+  unsigned int i;
+  for (i = 0; i < len; i++) {
+    char c = buf[i];
+    /* Handle escaping. */
+    if (is_json_escaped(c)) {
+      /* Use a "nice" escape, like \n, if one exists for this character. */
+      const char* escape = json_nice_escape(c);
+      /* If we don't have a specific 'nice' escape code, use a \uXXXX-style
+       * escape. */
+      char escape_buf[8];
+      if (!escape) {
+        unsigned char byte = (unsigned char)c;
+        _upb_snprintf(escape_buf, sizeof(escape_buf), "\\u%04x", (int)byte);
+        escape = escape_buf;
+      }
+
+      /* N.B. that we assume that the input encoding is equal to the output
+       * encoding (both UTF-8 for  now), so for chars >= 0x20 and != \, ", we
+       * can simply pass the bytes through. */
+
+      /* If there's a current run of unescaped chars, print that run first. */
+      if (unescaped_run) {
+        print_data(p, unescaped_run, &buf[i] - unescaped_run);
+        unescaped_run = NULL;
+      }
+      /* Then print the escape code. */
+      print_data(p, escape, strlen(escape));
+    } else {
+      /* Add to the current unescaped run of characters. */
+      if (unescaped_run == NULL) {
+        unescaped_run = &buf[i];
+      }
+    }
+  }
+
+  /* If the string ended in a run of unescaped characters, print that last run. */
+  if (unescaped_run) {
+    print_data(p, unescaped_run, &buf[len] - unescaped_run);
+  }
+}
+
+#define CHKLENGTH(x) if (!(x)) return -1;
+
+/* Helpers that format floating point values according to our custom formats.
+ * Right now we use %.8g and %.17g for float/double, respectively, to match
+ * proto2::util::JsonFormat's defaults.  May want to change this later. */
+
+const char neginf[] = "\"-Infinity\"";
+const char inf[] = "\"Infinity\"";
+
+static size_t fmt_double(double val, char* buf, size_t length) {
+  if (val == (1.0 / 0.0)) {
+    CHKLENGTH(length >= strlen(inf));
+    strcpy(buf, inf);
+    return strlen(inf);
+  } else if (val == (-1.0 / 0.0)) {
+    CHKLENGTH(length >= strlen(neginf));
+    strcpy(buf, neginf);
+    return strlen(neginf);
+  } else {
+    size_t n = _upb_snprintf(buf, length, "%.17g", val);
+    CHKLENGTH(n > 0 && n < length);
+    return n;
+  }
+}
+
+static size_t fmt_float(float val, char* buf, size_t length) {
+  size_t n = _upb_snprintf(buf, length, "%.8g", val);
+  CHKLENGTH(n > 0 && n < length);
+  return n;
+}
+
+static size_t fmt_bool(bool val, char* buf, size_t length) {
+  size_t n = _upb_snprintf(buf, length, "%s", (val ? "true" : "false"));
+  CHKLENGTH(n > 0 && n < length);
+  return n;
+}
+
+static size_t fmt_int64(long val, char* buf, size_t length) {
+  size_t n = _upb_snprintf(buf, length, "%ld", val);
+  CHKLENGTH(n > 0 && n < length);
+  return n;
+}
+
+static size_t fmt_uint64(unsigned long long val, char* buf, size_t length) {
+  size_t n = _upb_snprintf(buf, length, "%llu", val);
+  CHKLENGTH(n > 0 && n < length);
+  return n;
+}
+
+/* Print a map key given a field name. Called by scalar field handlers and by
+ * startseq for repeated fields. */
+static bool putkey(void *closure, const void *handler_data) {
+  upb_json_printer *p = closure;
+  const strpc *key = handler_data;
+  print_comma(p);
+  print_data(p, "\"", 1);
+  putstring(p, key->ptr, key->len);
+  print_data(p, "\":", 2);
+  return true;
+}
+
+#define CHKFMT(val) if ((val) == (size_t)-1) return false;
+#define CHK(val)    if (!(val)) return false;
+
+#define TYPE_HANDLERS(type, fmt_func)                                        \
+  static bool put##type(void *closure, const void *handler_data, type val) { \
+    upb_json_printer *p = closure;                                           \
+    char data[64];                                                           \
+    size_t length = fmt_func(val, data, sizeof(data));                       \
+    UPB_UNUSED(handler_data);                                                \
+    CHKFMT(length);                                                          \
+    print_data(p, data, length);                                             \
+    return true;                                                             \
+  }                                                                          \
+  static bool scalar_##type(void *closure, const void *handler_data,         \
+                            type val) {                                      \
+    CHK(putkey(closure, handler_data));                                      \
+    CHK(put##type(closure, handler_data, val));                              \
+    return true;                                                             \
+  }                                                                          \
+  static bool repeated_##type(void *closure, const void *handler_data,       \
+                              type val) {                                    \
+    upb_json_printer *p = closure;                                           \
+    print_comma(p);                                                          \
+    CHK(put##type(closure, handler_data, val));                              \
+    return true;                                                             \
+  }
+
+#define TYPE_HANDLERS_MAPKEY(type, fmt_func)                                 \
+  static bool putmapkey_##type(void *closure, const void *handler_data,      \
+                            type val) {                                      \
+    upb_json_printer *p = closure;                                           \
+    print_data(p, "\"", 1);                                                  \
+    CHK(put##type(closure, handler_data, val));                              \
+    print_data(p, "\":", 2);                                                 \
+    return true;                                                             \
+  }
+
+TYPE_HANDLERS(double,   fmt_double)
+TYPE_HANDLERS(float,    fmt_float)
+TYPE_HANDLERS(bool,     fmt_bool)
+TYPE_HANDLERS(int32_t,  fmt_int64)
+TYPE_HANDLERS(uint32_t, fmt_int64)
+TYPE_HANDLERS(int64_t,  fmt_int64)
+TYPE_HANDLERS(uint64_t, fmt_uint64)
+
+/* double and float are not allowed to be map keys. */
+TYPE_HANDLERS_MAPKEY(bool,     fmt_bool)
+TYPE_HANDLERS_MAPKEY(int32_t,  fmt_int64)
+TYPE_HANDLERS_MAPKEY(uint32_t, fmt_int64)
+TYPE_HANDLERS_MAPKEY(int64_t,  fmt_int64)
+TYPE_HANDLERS_MAPKEY(uint64_t, fmt_uint64)
+
+#undef TYPE_HANDLERS
+#undef TYPE_HANDLERS_MAPKEY
+
+typedef struct {
+  void *keyname;
+  const upb_enumdef *enumdef;
+} EnumHandlerData;
+
+static bool scalar_enum(void *closure, const void *handler_data,
+                        int32_t val) {
+  const EnumHandlerData *hd = handler_data;
+  upb_json_printer *p = closure;
+  const char *symbolic_name;
+
+  CHK(putkey(closure, hd->keyname));
+
+  symbolic_name = upb_enumdef_iton(hd->enumdef, val);
+  if (symbolic_name) {
+    print_data(p, "\"", 1);
+    putstring(p, symbolic_name, strlen(symbolic_name));
+    print_data(p, "\"", 1);
+  } else {
+    putint32_t(closure, NULL, val);
+  }
+
+  return true;
+}
+
+static void print_enum_symbolic_name(upb_json_printer *p,
+                                     const upb_enumdef *def,
+                                     int32_t val) {
+  const char *symbolic_name = upb_enumdef_iton(def, val);
+  if (symbolic_name) {
+    print_data(p, "\"", 1);
+    putstring(p, symbolic_name, strlen(symbolic_name));
+    print_data(p, "\"", 1);
+  } else {
+    putint32_t(p, NULL, val);
+  }
+}
+
+static bool repeated_enum(void *closure, const void *handler_data,
+                          int32_t val) {
+  const EnumHandlerData *hd = handler_data;
+  upb_json_printer *p = closure;
+  print_comma(p);
+
+  print_enum_symbolic_name(p, hd->enumdef, val);
+
+  return true;
+}
+
+static bool mapvalue_enum(void *closure, const void *handler_data,
+                          int32_t val) {
+  const EnumHandlerData *hd = handler_data;
+  upb_json_printer *p = closure;
+
+  print_enum_symbolic_name(p, hd->enumdef, val);
+
+  return true;
+}
+
+static void *scalar_startsubmsg(void *closure, const void *handler_data) {
+  return putkey(closure, handler_data) ? closure : UPB_BREAK;
+}
+
+static void *repeated_startsubmsg(void *closure, const void *handler_data) {
+  upb_json_printer *p = closure;
+  UPB_UNUSED(handler_data);
+  print_comma(p);
+  return closure;
+}
+
+static void start_frame(upb_json_printer *p) {
+  p->depth_++;
+  p->first_elem_[p->depth_] = true;
+  print_data(p, "{", 1);
+}
+
+static void end_frame(upb_json_printer *p) {
+  print_data(p, "}", 1);
+  p->depth_--;
+}
+
+static bool printer_startmsg(void *closure, const void *handler_data) {
+  upb_json_printer *p = closure;
+  UPB_UNUSED(handler_data);
+  if (p->depth_ == 0) {
+    upb_bytessink_start(p->output_, 0, &p->subc_);
+  }
+  start_frame(p);
+  return true;
+}
+
+static bool printer_endmsg(void *closure, const void *handler_data, upb_status *s) {
+  upb_json_printer *p = closure;
+  UPB_UNUSED(handler_data);
+  UPB_UNUSED(s);
+  end_frame(p);
+  if (p->depth_ == 0) {
+    upb_bytessink_end(p->output_);
+  }
+  return true;
+}
+
+static void *startseq(void *closure, const void *handler_data) {
+  upb_json_printer *p = closure;
+  CHK(putkey(closure, handler_data));
+  p->depth_++;
+  p->first_elem_[p->depth_] = true;
+  print_data(p, "[", 1);
+  return closure;
+}
+
+static bool endseq(void *closure, const void *handler_data) {
+  upb_json_printer *p = closure;
+  UPB_UNUSED(handler_data);
+  print_data(p, "]", 1);
+  p->depth_--;
+  return true;
+}
+
+static void *startmap(void *closure, const void *handler_data) {
+  upb_json_printer *p = closure;
+  CHK(putkey(closure, handler_data));
+  p->depth_++;
+  p->first_elem_[p->depth_] = true;
+  print_data(p, "{", 1);
+  return closure;
+}
+
+static bool endmap(void *closure, const void *handler_data) {
+  upb_json_printer *p = closure;
+  UPB_UNUSED(handler_data);
+  print_data(p, "}", 1);
+  p->depth_--;
+  return true;
+}
+
+static size_t putstr(void *closure, const void *handler_data, const char *str,
+                     size_t len, const upb_bufhandle *handle) {
+  upb_json_printer *p = closure;
+  UPB_UNUSED(handler_data);
+  UPB_UNUSED(handle);
+  putstring(p, str, len);
+  return len;
+}
+
+/* This has to Base64 encode the bytes, because JSON has no "bytes" type. */
+static size_t putbytes(void *closure, const void *handler_data, const char *str,
+                       size_t len, const upb_bufhandle *handle) {
+  upb_json_printer *p = closure;
+
+  /* This is the regular base64, not the "web-safe" version. */
+  static const char base64[] =
+      "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+
+  /* Base64-encode. */
+  char data[16000];
+  const char *limit = data + sizeof(data);
+  const unsigned char *from = (const unsigned char*)str;
+  char *to = data;
+  size_t remaining = len;
+  size_t bytes;
+
+  UPB_UNUSED(handler_data);
+  UPB_UNUSED(handle);
+
+  while (remaining > 2) {
+    /* TODO(haberman): handle encoded lengths > sizeof(data) */
+    UPB_ASSERT((limit - to) >= 4);
+
+    to[0] = base64[from[0] >> 2];
+    to[1] = base64[((from[0] & 0x3) << 4) | (from[1] >> 4)];
+    to[2] = base64[((from[1] & 0xf) << 2) | (from[2] >> 6)];
+    to[3] = base64[from[2] & 0x3f];
+
+    remaining -= 3;
+    to += 4;
+    from += 3;
+  }
+
+  switch (remaining) {
+    case 2:
+      to[0] = base64[from[0] >> 2];
+      to[1] = base64[((from[0] & 0x3) << 4) | (from[1] >> 4)];
+      to[2] = base64[(from[1] & 0xf) << 2];
+      to[3] = '=';
+      to += 4;
+      from += 2;
+      break;
+    case 1:
+      to[0] = base64[from[0] >> 2];
+      to[1] = base64[((from[0] & 0x3) << 4)];
+      to[2] = '=';
+      to[3] = '=';
+      to += 4;
+      from += 1;
+      break;
+  }
+
+  bytes = to - data;
+  print_data(p, "\"", 1);
+  putstring(p, data, bytes);
+  print_data(p, "\"", 1);
+  return len;
+}
+
+static void *scalar_startstr(void *closure, const void *handler_data,
+                             size_t size_hint) {
+  upb_json_printer *p = closure;
+  UPB_UNUSED(handler_data);
+  UPB_UNUSED(size_hint);
+  CHK(putkey(closure, handler_data));
+  print_data(p, "\"", 1);
+  return p;
+}
+
+static size_t scalar_str(void *closure, const void *handler_data,
+                         const char *str, size_t len,
+                         const upb_bufhandle *handle) {
+  CHK(putstr(closure, handler_data, str, len, handle));
+  return len;
+}
+
+static bool scalar_endstr(void *closure, const void *handler_data) {
+  upb_json_printer *p = closure;
+  UPB_UNUSED(handler_data);
+  print_data(p, "\"", 1);
+  return true;
+}
+
+static void *repeated_startstr(void *closure, const void *handler_data,
+                               size_t size_hint) {
+  upb_json_printer *p = closure;
+  UPB_UNUSED(handler_data);
+  UPB_UNUSED(size_hint);
+  print_comma(p);
+  print_data(p, "\"", 1);
+  return p;
+}
+
+static size_t repeated_str(void *closure, const void *handler_data,
+                           const char *str, size_t len,
+                           const upb_bufhandle *handle) {
+  CHK(putstr(closure, handler_data, str, len, handle));
+  return len;
+}
+
+static bool repeated_endstr(void *closure, const void *handler_data) {
+  upb_json_printer *p = closure;
+  UPB_UNUSED(handler_data);
+  print_data(p, "\"", 1);
+  return true;
+}
+
+static void *mapkeyval_startstr(void *closure, const void *handler_data,
+                                size_t size_hint) {
+  upb_json_printer *p = closure;
+  UPB_UNUSED(handler_data);
+  UPB_UNUSED(size_hint);
+  print_data(p, "\"", 1);
+  return p;
+}
+
+static size_t mapkey_str(void *closure, const void *handler_data,
+                         const char *str, size_t len,
+                         const upb_bufhandle *handle) {
+  CHK(putstr(closure, handler_data, str, len, handle));
+  return len;
+}
+
+static bool mapkey_endstr(void *closure, const void *handler_data) {
+  upb_json_printer *p = closure;
+  UPB_UNUSED(handler_data);
+  print_data(p, "\":", 2);
+  return true;
+}
+
+static bool mapvalue_endstr(void *closure, const void *handler_data) {
+  upb_json_printer *p = closure;
+  UPB_UNUSED(handler_data);
+  print_data(p, "\"", 1);
+  return true;
+}
+
+static size_t scalar_bytes(void *closure, const void *handler_data,
+                           const char *str, size_t len,
+                           const upb_bufhandle *handle) {
+  CHK(putkey(closure, handler_data));
+  CHK(putbytes(closure, handler_data, str, len, handle));
+  return len;
+}
+
+static size_t repeated_bytes(void *closure, const void *handler_data,
+                             const char *str, size_t len,
+                             const upb_bufhandle *handle) {
+  upb_json_printer *p = closure;
+  print_comma(p);
+  CHK(putbytes(closure, handler_data, str, len, handle));
+  return len;
+}
+
+static size_t mapkey_bytes(void *closure, const void *handler_data,
+                           const char *str, size_t len,
+                           const upb_bufhandle *handle) {
+  upb_json_printer *p = closure;
+  CHK(putbytes(closure, handler_data, str, len, handle));
+  print_data(p, ":", 1);
+  return len;
+}
+
+static void set_enum_hd(upb_handlers *h,
+                        const upb_fielddef *f,
+                        bool preserve_fieldnames,
+                        upb_handlerattr *attr) {
+  EnumHandlerData *hd = upb_gmalloc(sizeof(EnumHandlerData));
+  hd->enumdef = (const upb_enumdef *)upb_fielddef_subdef(f);
+  hd->keyname = newstrpc(h, f, preserve_fieldnames);
+  upb_handlers_addcleanup(h, hd, upb_gfree);
+  upb_handlerattr_sethandlerdata(attr, hd);
+}
+
+/* Set up handlers for a mapentry submessage (i.e., an individual key/value pair
+ * in a map).
+ *
+ * TODO: Handle missing key, missing value, out-of-order key/value, or repeated
+ * key or value cases properly. The right way to do this is to allocate a
+ * temporary structure at the start of a mapentry submessage, store key and
+ * value data in it as key and value handlers are called, and then print the
+ * key/value pair once at the end of the submessage. If we don't do this, we
+ * should at least detect the case and throw an error. However, so far all of
+ * our sources that emit mapentry messages do so canonically (with one key
+ * field, and then one value field), so this is not a pressing concern at the
+ * moment. */
+void printer_sethandlers_mapentry(const void *closure, bool preserve_fieldnames,
+                                  upb_handlers *h) {
+  const upb_msgdef *md = upb_handlers_msgdef(h);
+
+  /* A mapentry message is printed simply as '"key": value'. Rather than
+   * special-case key and value for every type below, we just handle both
+   * fields explicitly here. */
+  const upb_fielddef* key_field = upb_msgdef_itof(md, UPB_MAPENTRY_KEY);
+  const upb_fielddef* value_field = upb_msgdef_itof(md, UPB_MAPENTRY_VALUE);
+
+  upb_handlerattr empty_attr = UPB_HANDLERATTR_INITIALIZER;
+
+  UPB_UNUSED(closure);
+
+  switch (upb_fielddef_type(key_field)) {
+    case UPB_TYPE_INT32:
+      upb_handlers_setint32(h, key_field, putmapkey_int32_t, &empty_attr);
+      break;
+    case UPB_TYPE_INT64:
+      upb_handlers_setint64(h, key_field, putmapkey_int64_t, &empty_attr);
+      break;
+    case UPB_TYPE_UINT32:
+      upb_handlers_setuint32(h, key_field, putmapkey_uint32_t, &empty_attr);
+      break;
+    case UPB_TYPE_UINT64:
+      upb_handlers_setuint64(h, key_field, putmapkey_uint64_t, &empty_attr);
+      break;
+    case UPB_TYPE_BOOL:
+      upb_handlers_setbool(h, key_field, putmapkey_bool, &empty_attr);
+      break;
+    case UPB_TYPE_STRING:
+      upb_handlers_setstartstr(h, key_field, mapkeyval_startstr, &empty_attr);
+      upb_handlers_setstring(h, key_field, mapkey_str, &empty_attr);
+      upb_handlers_setendstr(h, key_field, mapkey_endstr, &empty_attr);
+      break;
+    case UPB_TYPE_BYTES:
+      upb_handlers_setstring(h, key_field, mapkey_bytes, &empty_attr);
+      break;
+    default:
+      UPB_ASSERT(false);
+      break;
+  }
+
+  switch (upb_fielddef_type(value_field)) {
+    case UPB_TYPE_INT32:
+      upb_handlers_setint32(h, value_field, putint32_t, &empty_attr);
+      break;
+    case UPB_TYPE_INT64:
+      upb_handlers_setint64(h, value_field, putint64_t, &empty_attr);
+      break;
+    case UPB_TYPE_UINT32:
+      upb_handlers_setuint32(h, value_field, putuint32_t, &empty_attr);
+      break;
+    case UPB_TYPE_UINT64:
+      upb_handlers_setuint64(h, value_field, putuint64_t, &empty_attr);
+      break;
+    case UPB_TYPE_BOOL:
+      upb_handlers_setbool(h, value_field, putbool, &empty_attr);
+      break;
+    case UPB_TYPE_FLOAT:
+      upb_handlers_setfloat(h, value_field, putfloat, &empty_attr);
+      break;
+    case UPB_TYPE_DOUBLE:
+      upb_handlers_setdouble(h, value_field, putdouble, &empty_attr);
+      break;
+    case UPB_TYPE_STRING:
+      upb_handlers_setstartstr(h, value_field, mapkeyval_startstr, &empty_attr);
+      upb_handlers_setstring(h, value_field, putstr, &empty_attr);
+      upb_handlers_setendstr(h, value_field, mapvalue_endstr, &empty_attr);
+      break;
+    case UPB_TYPE_BYTES:
+      upb_handlers_setstring(h, value_field, putbytes, &empty_attr);
+      break;
+    case UPB_TYPE_ENUM: {
+      upb_handlerattr enum_attr = UPB_HANDLERATTR_INITIALIZER;
+      set_enum_hd(h, value_field, preserve_fieldnames, &enum_attr);
+      upb_handlers_setint32(h, value_field, mapvalue_enum, &enum_attr);
+      upb_handlerattr_uninit(&enum_attr);
+      break;
+    }
+    case UPB_TYPE_MESSAGE:
+      /* No handler necessary -- the submsg handlers will print the message
+       * as appropriate. */
+      break;
+  }
+
+  upb_handlerattr_uninit(&empty_attr);
+}
+
+void printer_sethandlers(const void *closure, upb_handlers *h) {
+  const upb_msgdef *md = upb_handlers_msgdef(h);
+  bool is_mapentry = upb_msgdef_mapentry(md);
+  upb_handlerattr empty_attr = UPB_HANDLERATTR_INITIALIZER;
+  upb_msg_field_iter i;
+  const bool *preserve_fieldnames_ptr = closure;
+  const bool preserve_fieldnames = *preserve_fieldnames_ptr;
+
+  if (is_mapentry) {
+    /* mapentry messages are sufficiently different that we handle them
+     * separately. */
+    printer_sethandlers_mapentry(closure, preserve_fieldnames, h);
+    return;
+  }
+
+  upb_handlers_setstartmsg(h, printer_startmsg, &empty_attr);
+  upb_handlers_setendmsg(h, printer_endmsg, &empty_attr);
+
+#define TYPE(type, name, ctype)                                               \
+  case type:                                                                  \
+    if (upb_fielddef_isseq(f)) {                                              \
+      upb_handlers_set##name(h, f, repeated_##ctype, &empty_attr);            \
+    } else {                                                                  \
+      upb_handlers_set##name(h, f, scalar_##ctype, &name_attr);               \
+    }                                                                         \
+    break;
+
+  upb_msg_field_begin(&i, md);
+  for(; !upb_msg_field_done(&i); upb_msg_field_next(&i)) {
+    const upb_fielddef *f = upb_msg_iter_field(&i);
+
+    upb_handlerattr name_attr = UPB_HANDLERATTR_INITIALIZER;
+    upb_handlerattr_sethandlerdata(&name_attr,
+                                   newstrpc(h, f, preserve_fieldnames));
+
+    if (upb_fielddef_ismap(f)) {
+      upb_handlers_setstartseq(h, f, startmap, &name_attr);
+      upb_handlers_setendseq(h, f, endmap, &name_attr);
+    } else if (upb_fielddef_isseq(f)) {
+      upb_handlers_setstartseq(h, f, startseq, &name_attr);
+      upb_handlers_setendseq(h, f, endseq, &empty_attr);
+    }
+
+    switch (upb_fielddef_type(f)) {
+      TYPE(UPB_TYPE_FLOAT,  float,  float);
+      TYPE(UPB_TYPE_DOUBLE, double, double);
+      TYPE(UPB_TYPE_BOOL,   bool,   bool);
+      TYPE(UPB_TYPE_INT32,  int32,  int32_t);
+      TYPE(UPB_TYPE_UINT32, uint32, uint32_t);
+      TYPE(UPB_TYPE_INT64,  int64,  int64_t);
+      TYPE(UPB_TYPE_UINT64, uint64, uint64_t);
+      case UPB_TYPE_ENUM: {
+        /* For now, we always emit symbolic names for enums. We may want an
+         * option later to control this behavior, but we will wait for a real
+         * need first. */
+        upb_handlerattr enum_attr = UPB_HANDLERATTR_INITIALIZER;
+        set_enum_hd(h, f, preserve_fieldnames, &enum_attr);
+
+        if (upb_fielddef_isseq(f)) {
+          upb_handlers_setint32(h, f, repeated_enum, &enum_attr);
+        } else {
+          upb_handlers_setint32(h, f, scalar_enum, &enum_attr);
+        }
+
+        upb_handlerattr_uninit(&enum_attr);
+        break;
+      }
+      case UPB_TYPE_STRING:
+        if (upb_fielddef_isseq(f)) {
+          upb_handlers_setstartstr(h, f, repeated_startstr, &empty_attr);
+          upb_handlers_setstring(h, f, repeated_str, &empty_attr);
+          upb_handlers_setendstr(h, f, repeated_endstr, &empty_attr);
+        } else {
+          upb_handlers_setstartstr(h, f, scalar_startstr, &name_attr);
+          upb_handlers_setstring(h, f, scalar_str, &empty_attr);
+          upb_handlers_setendstr(h, f, scalar_endstr, &empty_attr);
+        }
+        break;
+      case UPB_TYPE_BYTES:
+        /* XXX: this doesn't support strings that span buffers yet. The base64
+         * encoder will need to be made resumable for this to work properly. */
+        if (upb_fielddef_isseq(f)) {
+          upb_handlers_setstring(h, f, repeated_bytes, &empty_attr);
+        } else {
+          upb_handlers_setstring(h, f, scalar_bytes, &name_attr);
+        }
+        break;
+      case UPB_TYPE_MESSAGE:
+        if (upb_fielddef_isseq(f)) {
+          upb_handlers_setstartsubmsg(h, f, repeated_startsubmsg, &name_attr);
+        } else {
+          upb_handlers_setstartsubmsg(h, f, scalar_startsubmsg, &name_attr);
+        }
+        break;
+    }
+
+    upb_handlerattr_uninit(&name_attr);
+  }
+
+  upb_handlerattr_uninit(&empty_attr);
+#undef TYPE
+}
+
+static void json_printer_reset(upb_json_printer *p) {
+  p->depth_ = 0;
+}
+
+
+/* Public API *****************************************************************/
+
+upb_json_printer *upb_json_printer_create(upb_env *e, const upb_handlers *h,
+                                          upb_bytessink *output) {
+#ifndef NDEBUG
+  size_t size_before = upb_env_bytesallocated(e);
+#endif
+
+  upb_json_printer *p = upb_env_malloc(e, sizeof(upb_json_printer));
+  if (!p) return NULL;
+
+  p->output_ = output;
+  json_printer_reset(p);
+  upb_sink_reset(&p->input_, h, p);
+
+  /* If this fails, increase the value in printer.h. */
+  UPB_ASSERT_DEBUGVAR(upb_env_bytesallocated(e) - size_before <=
+                      UPB_JSON_PRINTER_SIZE);
+  return p;
+}
+
+upb_sink *upb_json_printer_input(upb_json_printer *p) {
+  return &p->input_;
+}
+
+const upb_handlers *upb_json_printer_newhandlers(const upb_msgdef *md,
+                                                 bool preserve_fieldnames,
+                                                 const void *owner) {
+  return upb_handlers_newfrozen(
+      md, owner, printer_sethandlers, &preserve_fieldnames);
+}
diff --git a/php/ext/google/protobuf/upb.h b/php/ext/google/protobuf/upb.h
new file mode 100644
index 0000000..a263db3
--- /dev/null
+++ b/php/ext/google/protobuf/upb.h
@@ -0,0 +1,9624 @@
+// Amalgamated source file
+
+// php.h intentionally defined NDEBUG. We have to define this macro in order to
+// be used together with php.h
+#ifndef NDEBUG
+#define NDEBUG
+#endif
+
+/*
+** upb_decode: parsing into a upb_msg using a upb_msglayout.
+*/
+
+#ifndef UPB_DECODE_H_
+#define UPB_DECODE_H_
+
+/*
+** upb::Message is a representation for protobuf messages.
+**
+** However it differs from other common representations like
+** google::protobuf::Message in one key way: it does not prescribe any
+** ownership between messages and submessages, and it relies on the
+** client to delete each message/submessage/array/map at the appropriate
+** time.
+**
+** A client can access a upb::Message without knowing anything about
+** ownership semantics, but to create or mutate a message a user needs
+** to implement the memory management themselves.
+**
+** Currently all messages, arrays, and maps store a upb_alloc* internally.
+** Mutating operations use this when they require dynamically-allocated
+** memory.  We could potentially eliminate this size overhead later by
+** letting the user flip a bit on the factory that prevents this from
+** being stored.  The user would then need to use separate functions where
+** the upb_alloc* is passed explicitly.  However for handlers to populate
+** such structures, they would need a place to store this upb_alloc* during
+** parsing; upb_handlers don't currently have a good way to accommodate this.
+**
+** TODO: UTF-8 checking?
+**/
+
+#ifndef UPB_MSG_H_
+#define UPB_MSG_H_
+
+/*
+** Defs are upb's internal representation of the constructs that can appear
+** in a .proto file:
+**
+** - upb::MessageDef (upb_msgdef): describes a "message" construct.
+** - upb::FieldDef (upb_fielddef): describes a message field.
+** - upb::FileDef (upb_filedef): describes a .proto file and its defs.
+** - upb::EnumDef (upb_enumdef): describes an enum.
+** - upb::OneofDef (upb_oneofdef): describes a oneof.
+** - upb::Def (upb_def): base class of all the others.
+**
+** TODO: definitions of services.
+**
+** Like upb_refcounted objects, defs are mutable only until frozen, and are
+** only thread-safe once frozen.
+**
+** This is a mixed C/C++ interface that offers a full API to both languages.
+** See the top-level README for more information.
+*/
+
+#ifndef UPB_DEF_H_
+#define UPB_DEF_H_
+
+/*
+** upb::RefCounted (upb_refcounted)
+**
+** A refcounting scheme that supports circular refs.  It accomplishes this by
+** partitioning the set of objects into groups such that no cycle spans groups;
+** we can then reference-count the group as a whole and ignore refs within the
+** group.  When objects are mutable, these groups are computed very
+** conservatively; we group any objects that have ever had a link between them.
+** When objects are frozen, we compute strongly-connected components which
+** allows us to be precise and only group objects that are actually cyclic.
+**
+** This is a mixed C/C++ interface that offers a full API to both languages.
+** See the top-level README for more information.
+*/
+
+#ifndef UPB_REFCOUNTED_H_
+#define UPB_REFCOUNTED_H_
+
+/*
+** upb_table
+**
+** This header is INTERNAL-ONLY!  Its interfaces are not public or stable!
+** This file defines very fast int->upb_value (inttable) and string->upb_value
+** (strtable) hash tables.
+**
+** The table uses chained scatter with Brent's variation (inspired by the Lua
+** implementation of hash tables).  The hash function for strings is Austin
+** Appleby's "MurmurHash."
+**
+** The inttable uses uintptr_t as its key, which guarantees it can be used to
+** store pointers or integers of at least 32 bits (upb isn't really useful on
+** systems where sizeof(void*) < 4).
+**
+** The table must be homogenous (all values of the same type).  In debug
+** mode, we check this on insert and lookup.
+*/
+
+#ifndef UPB_TABLE_H_
+#define UPB_TABLE_H_
+
+#include <stdint.h>
+#include <string.h>
+/*
+** This file contains shared definitions that are widely used across upb.
+**
+** This is a mixed C/C++ interface that offers a full API to both languages.
+** See the top-level README for more information.
+*/
+
+#ifndef UPB_H_
+#define UPB_H_
+
+#include <assert.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stddef.h>
+
+#ifdef __cplusplus
+namespace upb {
+class Allocator;
+class Arena;
+class Environment;
+class ErrorSpace;
+class Status;
+template <int N> class InlinedArena;
+template <int N> class InlinedEnvironment;
+}
+#endif
+
+/* UPB_INLINE: inline if possible, emit standalone code if required. */
+#ifdef __cplusplus
+#define UPB_INLINE inline
+#elif defined (__GNUC__)
+#define UPB_INLINE static __inline__
+#else
+#define UPB_INLINE static
+#endif
+
+/* Hints to the compiler about likely/unlikely branches. */
+#define UPB_LIKELY(x) __builtin_expect((x),1)
+
+/* Define UPB_BIG_ENDIAN manually if you're on big endian and your compiler
+ * doesn't provide these preprocessor symbols. */
+#if defined(__BYTE_ORDER__) && (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)
+#define UPB_BIG_ENDIAN
+#endif
+
+/* Macros for function attributes on compilers that support them. */
+#ifdef __GNUC__
+#define UPB_FORCEINLINE __inline__ __attribute__((always_inline))
+#define UPB_NOINLINE __attribute__((noinline))
+#define UPB_NORETURN __attribute__((__noreturn__))
+#else  /* !defined(__GNUC__) */
+#define UPB_FORCEINLINE
+#define UPB_NOINLINE
+#define UPB_NORETURN
+#endif
+
+#if __STDC_VERSION__ >= 199901L || __cplusplus >= 201103L
+/* C99/C++11 versions. */
+#include <stdio.h>
+#define _upb_snprintf snprintf
+#define _upb_vsnprintf vsnprintf
+#define _upb_va_copy(a, b) va_copy(a, b)
+#elif defined __GNUC__
+/* A few hacky workarounds for functions not in C89.
+ * For internal use only!
+ * TODO(haberman): fix these by including our own implementations, or finding
+ * another workaround.
+ */
+#define _upb_snprintf __builtin_snprintf
+#define _upb_vsnprintf __builtin_vsnprintf
+#define _upb_va_copy(a, b) __va_copy(a, b)
+#else
+#error Need implementations of [v]snprintf and va_copy
+#endif
+
+
+#if ((defined(__cplusplus) && __cplusplus >= 201103L) || \
+      defined(__GXX_EXPERIMENTAL_CXX0X__)) && !defined(UPB_NO_CXX11)
+#define UPB_CXX11
+#endif
+
+/* UPB_DISALLOW_COPY_AND_ASSIGN()
+ * UPB_DISALLOW_POD_OPS()
+ *
+ * Declare these in the "private" section of a C++ class to forbid copy/assign
+ * or all POD ops (construct, destruct, copy, assign) on that class. */
+#ifdef UPB_CXX11
+#include <type_traits>
+#define UPB_DISALLOW_COPY_AND_ASSIGN(class_name) \
+  class_name(const class_name&) = delete; \
+  void operator=(const class_name&) = delete;
+#define UPB_DISALLOW_POD_OPS(class_name, full_class_name) \
+  class_name() = delete; \
+  ~class_name() = delete; \
+  UPB_DISALLOW_COPY_AND_ASSIGN(class_name)
+#define UPB_ASSERT_STDLAYOUT(type) \
+  static_assert(std::is_standard_layout<type>::value, \
+                #type " must be standard layout");
+#define UPB_FINAL final
+#else  /* !defined(UPB_CXX11) */
+#define UPB_DISALLOW_COPY_AND_ASSIGN(class_name) \
+  class_name(const class_name&); \
+  void operator=(const class_name&);
+#define UPB_DISALLOW_POD_OPS(class_name, full_class_name) \
+  class_name(); \
+  ~class_name(); \
+  UPB_DISALLOW_COPY_AND_ASSIGN(class_name)
+#define UPB_ASSERT_STDLAYOUT(type)
+#define UPB_FINAL
+#endif
+
+/* UPB_DECLARE_TYPE()
+ * UPB_DECLARE_DERIVED_TYPE()
+ * UPB_DECLARE_DERIVED_TYPE2()
+ *
+ * Macros for declaring C and C++ types both, including inheritance.
+ * The inheritance doesn't use real C++ inheritance, to stay compatible with C.
+ *
+ * These macros also provide upcasts:
+ *  - in C: types-specific functions (ie. upb_foo_upcast(foo))
+ *  - in C++: upb::upcast(foo) along with implicit conversions
+ *
+ * Downcasts are not provided, but upb/def.h defines downcasts for upb::Def. */
+
+#define UPB_C_UPCASTS(ty, base)                                      \
+  UPB_INLINE base *ty ## _upcast_mutable(ty *p) { return (base*)p; } \
+  UPB_INLINE const base *ty ## _upcast(const ty *p) { return (const base*)p; }
+
+#define UPB_C_UPCASTS2(ty, base, base2)                                 \
+  UPB_C_UPCASTS(ty, base)                                               \
+  UPB_INLINE base2 *ty ## _upcast2_mutable(ty *p) { return (base2*)p; } \
+  UPB_INLINE const base2 *ty ## _upcast2(const ty *p) { return (const base2*)p; }
+
+#ifdef __cplusplus
+
+#define UPB_BEGIN_EXTERN_C extern "C" {
+#define UPB_END_EXTERN_C }
+#define UPB_PRIVATE_FOR_CPP private:
+#define UPB_DECLARE_TYPE(cppname, cname) typedef cppname cname;
+
+#define UPB_DECLARE_DERIVED_TYPE(cppname, cppbase, cname, cbase)  \
+  UPB_DECLARE_TYPE(cppname, cname)                                \
+  UPB_C_UPCASTS(cname, cbase)                                     \
+  namespace upb {                                                 \
+  template <>                                                     \
+  class Pointer<cppname> : public PointerBase<cppname, cppbase> { \
+   public:                                                        \
+    explicit Pointer(cppname* ptr)                                \
+        : PointerBase<cppname, cppbase>(ptr) {}                   \
+  };                                                              \
+  template <>                                                     \
+  class Pointer<const cppname>                                    \
+      : public PointerBase<const cppname, const cppbase> {        \
+   public:                                                        \
+    explicit Pointer(const cppname* ptr)                          \
+        : PointerBase<const cppname, const cppbase>(ptr) {}       \
+  };                                                              \
+  }
+
+#define UPB_DECLARE_DERIVED_TYPE2(cppname, cppbase, cppbase2, cname, cbase,  \
+                                  cbase2)                                    \
+  UPB_DECLARE_TYPE(cppname, cname)                                           \
+  UPB_C_UPCASTS2(cname, cbase, cbase2)                                       \
+  namespace upb {                                                            \
+  template <>                                                                \
+  class Pointer<cppname> : public PointerBase2<cppname, cppbase, cppbase2> { \
+   public:                                                                   \
+    explicit Pointer(cppname* ptr)                                           \
+        : PointerBase2<cppname, cppbase, cppbase2>(ptr) {}                   \
+  };                                                                         \
+  template <>                                                                \
+  class Pointer<const cppname>                                               \
+      : public PointerBase2<const cppname, const cppbase, const cppbase2> {  \
+   public:                                                                   \
+    explicit Pointer(const cppname* ptr)                                     \
+        : PointerBase2<const cppname, const cppbase, const cppbase2>(ptr) {} \
+  };                                                                         \
+  }
+
+#else  /* !defined(__cplusplus) */
+
+#define UPB_BEGIN_EXTERN_C
+#define UPB_END_EXTERN_C
+#define UPB_PRIVATE_FOR_CPP
+#define UPB_DECLARE_TYPE(cppname, cname) \
+  struct cname;                          \
+  typedef struct cname cname;
+#define UPB_DECLARE_DERIVED_TYPE(cppname, cppbase, cname, cbase) \
+  UPB_DECLARE_TYPE(cppname, cname)                               \
+  UPB_C_UPCASTS(cname, cbase)
+#define UPB_DECLARE_DERIVED_TYPE2(cppname, cppbase, cppbase2,    \
+                                  cname, cbase, cbase2)          \
+  UPB_DECLARE_TYPE(cppname, cname)                               \
+  UPB_C_UPCASTS2(cname, cbase, cbase2)
+
+#endif  /* defined(__cplusplus) */
+
+#define UPB_MAX(x, y) ((x) > (y) ? (x) : (y))
+#define UPB_MIN(x, y) ((x) < (y) ? (x) : (y))
+
+#define UPB_UNUSED(var) (void)var
+
+/* UPB_ASSERT(): in release mode, we use the expression without letting it be
+ * evaluated.  This prevents "unused variable" warnings. */
+#ifdef NDEBUG
+#define UPB_ASSERT(expr) do {} while (false && (expr))
+#else
+#define UPB_ASSERT(expr) assert(expr)
+#endif
+
+/* UPB_ASSERT_DEBUGVAR(): assert that uses functions or variables that only
+ * exist in debug mode.  This turns into regular assert. */
+#define UPB_ASSERT_DEBUGVAR(expr) assert(expr)
+
+#ifdef __GNUC__
+#define UPB_UNREACHABLE() do { assert(0); __builtin_unreachable(); } while(0)
+#else
+#define UPB_UNREACHABLE() do { assert(0); } while(0)
+#endif
+
+/* Generic function type. */
+typedef void upb_func();
+
+
+/* C++ Casts ******************************************************************/
+
+#ifdef __cplusplus
+
+namespace upb {
+
+template <class T> class Pointer;
+
+/* Casts to a subclass.  The caller must know that cast is correct; an
+ * incorrect cast will throw an assertion failure in debug mode.
+ *
+ * Example:
+ *   upb::Def* def = GetDef();
+ *   // Assert-fails if this was not actually a MessageDef.
+ *   upb::MessgeDef* md = upb::down_cast<upb::MessageDef>(def);
+ *
+ * Note that downcasts are only defined for some types (at the moment you can
+ * only downcast from a upb::Def to a specific Def type). */
+template<class To, class From> To down_cast(From* f);
+
+/* Casts to a subclass.  If the class does not actually match the given To type,
+ * returns NULL.
+ *
+ * Example:
+ *   upb::Def* def = GetDef();
+ *   // md will be NULL if this was not actually a MessageDef.
+ *   upb::MessgeDef* md = upb::down_cast<upb::MessageDef>(def);
+ *
+ * Note that dynamic casts are only defined for some types (at the moment you
+ * can only downcast from a upb::Def to a specific Def type).. */
+template<class To, class From> To dyn_cast(From* f);
+
+/* Casts to any base class, or the type itself (ie. can be a no-op).
+ *
+ * Example:
+ *   upb::MessageDef* md = GetDef();
+ *   // This will fail to compile if this wasn't actually a base class.
+ *   upb::Def* def = upb::upcast(md);
+ */
+template <class T> inline Pointer<T> upcast(T *f) { return Pointer<T>(f); }
+
+/* Attempt upcast to specific base class.
+ *
+ * Example:
+ *   upb::MessageDef* md = GetDef();
+ *   upb::upcast_to<upb::Def>(md)->MethodOnDef();
+ */
+template <class T, class F> inline T* upcast_to(F *f) {
+  return static_cast<T*>(upcast(f));
+}
+
+/* PointerBase<T>: implementation detail of upb::upcast().
+ * It is implicitly convertable to pointers to the Base class(es).
+ */
+template <class T, class Base>
+class PointerBase {
+ public:
+  explicit PointerBase(T* ptr) : ptr_(ptr) {}
+  operator T*() { return ptr_; }
+  operator Base*() { return (Base*)ptr_; }
+
+ private:
+  T* ptr_;
+};
+
+template <class T, class Base, class Base2>
+class PointerBase2 : public PointerBase<T, Base> {
+ public:
+  explicit PointerBase2(T* ptr) : PointerBase<T, Base>(ptr) {}
+  operator Base2*() { return Pointer<Base>(*this); }
+};
+
+}
+
+#endif
+
+/* A list of types as they are encoded on-the-wire. */
+typedef enum {
+  UPB_WIRE_TYPE_VARINT      = 0,
+  UPB_WIRE_TYPE_64BIT       = 1,
+  UPB_WIRE_TYPE_DELIMITED   = 2,
+  UPB_WIRE_TYPE_START_GROUP = 3,
+  UPB_WIRE_TYPE_END_GROUP   = 4,
+  UPB_WIRE_TYPE_32BIT       = 5
+} upb_wiretype_t;
+
+
+/* upb::ErrorSpace ************************************************************/
+
+/* A upb::ErrorSpace represents some domain of possible error values.  This lets
+ * upb::Status attach specific error codes to operations, like POSIX/C errno,
+ * Win32 error codes, etc.  Clients who want to know the very specific error
+ * code can check the error space and then know the type of the integer code.
+ *
+ * NOTE: upb::ErrorSpace is currently not used and should be considered
+ * experimental.  It is important primarily in cases where upb is performing
+ * I/O, but upb doesn't currently have any components that do this. */
+
+UPB_DECLARE_TYPE(upb::ErrorSpace, upb_errorspace)
+
+#ifdef __cplusplus
+class upb::ErrorSpace {
+#else
+struct upb_errorspace {
+#endif
+  const char *name;
+};
+
+
+/* upb::Status ****************************************************************/
+
+/* upb::Status represents a success or failure status and error message.
+ * It owns no resources and allocates no memory, so it should work
+ * even in OOM situations. */
+UPB_DECLARE_TYPE(upb::Status, upb_status)
+
+/* The maximum length of an error message before it will get truncated. */
+#define UPB_STATUS_MAX_MESSAGE 128
+
+UPB_BEGIN_EXTERN_C
+
+const char *upb_status_errmsg(const upb_status *status);
+bool upb_ok(const upb_status *status);
+upb_errorspace *upb_status_errspace(const upb_status *status);
+int upb_status_errcode(const upb_status *status);
+
+/* Any of the functions that write to a status object allow status to be NULL,
+ * to support use cases where the function's caller does not care about the
+ * status message. */
+void upb_status_clear(upb_status *status);
+void upb_status_seterrmsg(upb_status *status, const char *msg);
+void upb_status_seterrf(upb_status *status, const char *fmt, ...);
+void upb_status_vseterrf(upb_status *status, const char *fmt, va_list args);
+void upb_status_copy(upb_status *to, const upb_status *from);
+
+UPB_END_EXTERN_C
+
+#ifdef __cplusplus
+
+class upb::Status {
+ public:
+  Status() { upb_status_clear(this); }
+
+  /* Returns true if there is no error. */
+  bool ok() const { return upb_ok(this); }
+
+  /* Optional error space and code, useful if the caller wants to
+   * programmatically check the specific kind of error. */
+  ErrorSpace* error_space() { return upb_status_errspace(this); }
+  int error_code() const { return upb_status_errcode(this); }
+
+  /* The returned string is invalidated by any other call into the status. */
+  const char *error_message() const { return upb_status_errmsg(this); }
+
+  /* The error message will be truncated if it is longer than
+   * UPB_STATUS_MAX_MESSAGE-4. */
+  void SetErrorMessage(const char* msg) { upb_status_seterrmsg(this, msg); }
+  void SetFormattedErrorMessage(const char* fmt, ...) {
+    va_list args;
+    va_start(args, fmt);
+    upb_status_vseterrf(this, fmt, args);
+    va_end(args);
+  }
+
+  /* Resets the status to a successful state with no message. */
+  void Clear() { upb_status_clear(this); }
+
+  void CopyFrom(const Status& other) { upb_status_copy(this, &other); }
+
+ private:
+  UPB_DISALLOW_COPY_AND_ASSIGN(Status)
+#else
+struct upb_status {
+#endif
+  bool ok_;
+
+  /* Specific status code defined by some error space (optional). */
+  int code_;
+  upb_errorspace *error_space_;
+
+  /* TODO(haberman): add file/line of error? */
+
+  /* Error message; NULL-terminated. */
+  char msg[UPB_STATUS_MAX_MESSAGE];
+};
+
+#define UPB_STATUS_INIT {true, 0, NULL, {0}}
+
+
+/** Built-in error spaces. ****************************************************/
+
+/* Errors raised by upb that we want to be able to detect programmatically. */
+typedef enum {
+  UPB_NOMEM   /* Can't reuse ENOMEM because it is POSIX, not ISO C. */
+} upb_errcode_t;
+
+extern upb_errorspace upb_upberr;
+
+void upb_upberr_setoom(upb_status *s);
+
+/* Since errno is defined by standard C, we define an error space for it in
+ * core upb.  Other error spaces should be defined in other, platform-specific
+ * modules. */
+
+extern upb_errorspace upb_errnoerr;
+
+
+/** upb::Allocator ************************************************************/
+
+/* A upb::Allocator is a possibly-stateful allocator object.
+ *
+ * It could either be an arena allocator (which doesn't require individual
+ * free() calls) or a regular malloc() (which does).  The client must therefore
+ * free memory unless it knows that the allocator is an arena allocator. */
+UPB_DECLARE_TYPE(upb::Allocator, upb_alloc)
+
+/* A malloc()/free() function.
+ * If "size" is 0 then the function acts like free(), otherwise it acts like
+ * realloc().  Only "oldsize" bytes from a previous allocation are preserved. */
+typedef void *upb_alloc_func(upb_alloc *alloc, void *ptr, size_t oldsize,
+                             size_t size);
+
+#ifdef __cplusplus
+
+class upb::Allocator UPB_FINAL {
+ public:
+  Allocator() {}
+
+ private:
+  UPB_DISALLOW_COPY_AND_ASSIGN(Allocator)
+
+ public:
+#else
+struct upb_alloc {
+#endif  /* __cplusplus */
+  upb_alloc_func *func;
+};
+
+UPB_INLINE void *upb_malloc(upb_alloc *alloc, size_t size) {
+  UPB_ASSERT(alloc);
+  return alloc->func(alloc, NULL, 0, size);
+}
+
+UPB_INLINE void *upb_realloc(upb_alloc *alloc, void *ptr, size_t oldsize,
+                             size_t size) {
+  UPB_ASSERT(alloc);
+  return alloc->func(alloc, ptr, oldsize, size);
+}
+
+UPB_INLINE void upb_free(upb_alloc *alloc, void *ptr) {
+  assert(alloc);
+  alloc->func(alloc, ptr, 0, 0);
+}
+
+/* The global allocator used by upb.  Uses the standard malloc()/free(). */
+
+extern upb_alloc upb_alloc_global;
+
+/* Functions that hard-code the global malloc.
+ *
+ * We still get benefit because we can put custom logic into our global
+ * allocator, like injecting out-of-memory faults in debug/testing builds. */
+
+UPB_INLINE void *upb_gmalloc(size_t size) {
+  return upb_malloc(&upb_alloc_global, size);
+}
+
+UPB_INLINE void *upb_grealloc(void *ptr, size_t oldsize, size_t size) {
+  return upb_realloc(&upb_alloc_global, ptr, oldsize, size);
+}
+
+UPB_INLINE void upb_gfree(void *ptr) {
+  upb_free(&upb_alloc_global, ptr);
+}
+
+/* upb::Arena *****************************************************************/
+
+/* upb::Arena is a specific allocator implementation that uses arena allocation.
+ * The user provides an allocator that will be used to allocate the underlying
+ * arena blocks.  Arenas by nature do not require the individual allocations
+ * to be freed.  However the Arena does allow users to register cleanup
+ * functions that will run when the arena is destroyed.
+ *
+ * A upb::Arena is *not* thread-safe.
+ *
+ * You could write a thread-safe arena allocator that satisfies the
+ * upb::Allocator interface, but it would not be as efficient for the
+ * single-threaded case. */
+UPB_DECLARE_TYPE(upb::Arena, upb_arena)
+
+typedef void upb_cleanup_func(void *ud);
+
+#define UPB_ARENA_BLOCK_OVERHEAD (sizeof(size_t)*4)
+
+UPB_BEGIN_EXTERN_C
+
+void upb_arena_init(upb_arena *a);
+void upb_arena_init2(upb_arena *a, void *mem, size_t n, upb_alloc *alloc);
+void upb_arena_uninit(upb_arena *a);
+bool upb_arena_addcleanup(upb_arena *a, upb_cleanup_func *func, void *ud);
+size_t upb_arena_bytesallocated(const upb_arena *a);
+void upb_arena_setnextblocksize(upb_arena *a, size_t size);
+void upb_arena_setmaxblocksize(upb_arena *a, size_t size);
+UPB_INLINE upb_alloc *upb_arena_alloc(upb_arena *a) { return (upb_alloc*)a; }
+
+UPB_END_EXTERN_C
+
+#ifdef __cplusplus
+
+class upb::Arena {
+ public:
+  /* A simple arena with no initial memory block and the default allocator. */
+  Arena() { upb_arena_init(this); }
+
+  /* Constructs an arena with the given initial block which allocates blocks
+   * with the given allocator.  The given allocator must outlive the Arena.
+   *
+   * If you pass NULL for the allocator it will default to the global allocator
+   * upb_alloc_global, and NULL/0 for the initial block will cause there to be
+   * no initial block. */
+  Arena(void *mem, size_t len, Allocator* a) {
+    upb_arena_init2(this, mem, len, a);
+  }
+
+  ~Arena() { upb_arena_uninit(this); }
+
+  /* Sets the size of the next block the Arena will request (unless the
+   * requested allocation is larger).  Each block will double in size until the
+   * max limit is reached. */
+  void SetNextBlockSize(size_t size) { upb_arena_setnextblocksize(this, size); }
+
+  /* Sets the maximum block size.  No blocks larger than this will be requested
+   * from the underlying allocator unless individual arena allocations are
+   * larger. */
+  void SetMaxBlockSize(size_t size) { upb_arena_setmaxblocksize(this, size); }
+
+  /* Allows this arena to be used as a generic allocator.
+   *
+   * The arena does not need free() calls so when using Arena as an allocator
+   * it is safe to skip them.  However they are no-ops so there is no harm in
+   * calling free() either. */
+  Allocator* allocator() { return upb_arena_alloc(this); }
+
+  /* Add a cleanup function to run when the arena is destroyed.
+   * Returns false on out-of-memory. */
+  bool AddCleanup(upb_cleanup_func* func, void* ud) {
+    return upb_arena_addcleanup(this, func, ud);
+  }
+
+  /* Total number of bytes that have been allocated.  It is undefined what
+   * Realloc() does to this counter. */
+  size_t BytesAllocated() const {
+    return upb_arena_bytesallocated(this);
+  }
+
+ private:
+  UPB_DISALLOW_COPY_AND_ASSIGN(Arena)
+
+#else
+struct upb_arena {
+#endif  /* __cplusplus */
+  /* We implement the allocator interface.
+   * This must be the first member of upb_arena! */
+  upb_alloc alloc;
+
+  /* Allocator to allocate arena blocks.  We are responsible for freeing these
+   * when we are destroyed. */
+  upb_alloc *block_alloc;
+
+  size_t bytes_allocated;
+  size_t next_block_size;
+  size_t max_block_size;
+
+  /* Linked list of blocks.  Points to an arena_block, defined in env.c */
+  void *block_head;
+
+  /* Cleanup entries.  Pointer to a cleanup_ent, defined in env.c */
+  void *cleanup_head;
+
+  /* For future expansion, since the size of this struct is exposed to users. */
+  void *future1;
+  void *future2;
+};
+
+
+/* upb::Environment ***********************************************************/
+
+/* A upb::Environment provides a means for injecting malloc and an
+ * error-reporting callback into encoders/decoders.  This allows them to be
+ * independent of nearly all assumptions about their actual environment.
+ *
+ * It is also a container for allocating the encoders/decoders themselves that
+ * insulates clients from knowing their actual size.  This provides ABI
+ * compatibility even if the size of the objects change.  And this allows the
+ * structure definitions to be in the .c files instead of the .h files, making
+ * the .h files smaller and more readable.
+ *
+ * We might want to consider renaming this to "Pipeline" if/when the concept of
+ * a pipeline element becomes more formalized. */
+UPB_DECLARE_TYPE(upb::Environment, upb_env)
+
+/* A function that receives an error report from an encoder or decoder.  The
+ * callback can return true to request that the error should be recovered, but
+ * if the error is not recoverable this has no effect. */
+typedef bool upb_error_func(void *ud, const upb_status *status);
+
+UPB_BEGIN_EXTERN_C
+
+void upb_env_init(upb_env *e);
+void upb_env_init2(upb_env *e, void *mem, size_t n, upb_alloc *alloc);
+void upb_env_uninit(upb_env *e);
+
+void upb_env_initonly(upb_env *e);
+
+UPB_INLINE upb_arena *upb_env_arena(upb_env *e) { return (upb_arena*)e; }
+bool upb_env_ok(const upb_env *e);
+void upb_env_seterrorfunc(upb_env *e, upb_error_func *func, void *ud);
+
+/* Convenience wrappers around the methods of the contained arena. */
+void upb_env_reporterrorsto(upb_env *e, upb_status *s);
+bool upb_env_reporterror(upb_env *e, const upb_status *s);
+void *upb_env_malloc(upb_env *e, size_t size);
+void *upb_env_realloc(upb_env *e, void *ptr, size_t oldsize, size_t size);
+void upb_env_free(upb_env *e, void *ptr);
+bool upb_env_addcleanup(upb_env *e, upb_cleanup_func *func, void *ud);
+size_t upb_env_bytesallocated(const upb_env *e);
+
+UPB_END_EXTERN_C
+
+#ifdef __cplusplus
+
+class upb::Environment {
+ public:
+  /* The given Arena must outlive this environment. */
+  Environment() { upb_env_initonly(this); }
+
+  Environment(void *mem, size_t len, Allocator *a) : arena_(mem, len, a) {
+    upb_env_initonly(this);
+  }
+
+  Arena* arena() { return upb_env_arena(this); }
+
+  /* Set a custom error reporting function. */
+  void SetErrorFunction(upb_error_func* func, void* ud) {
+    upb_env_seterrorfunc(this, func, ud);
+  }
+
+  /* Set the error reporting function to simply copy the status to the given
+   * status and abort. */
+  void ReportErrorsTo(Status* status) { upb_env_reporterrorsto(this, status); }
+
+  /* Returns true if all allocations and AddCleanup() calls have succeeded,
+   * and no errors were reported with ReportError() (except ones that recovered
+   * successfully). */
+  bool ok() const { return upb_env_ok(this); }
+
+  /* Reports an error to this environment's callback, returning true if
+   * the caller should try to recover. */
+  bool ReportError(const Status* status) {
+    return upb_env_reporterror(this, status);
+  }
+
+ private:
+  UPB_DISALLOW_COPY_AND_ASSIGN(Environment)
+
+#else
+struct upb_env {
+#endif  /* __cplusplus */
+  upb_arena arena_;
+  upb_error_func *error_func_;
+  void *error_ud_;
+  bool ok_;
+};
+
+
+/* upb::InlinedArena **********************************************************/
+/* upb::InlinedEnvironment ****************************************************/
+
+/* upb::InlinedArena and upb::InlinedEnvironment seed their arenas with a
+ * predefined amount of memory.  No heap memory will be allocated until the
+ * initial block is exceeded.
+ *
+ * These types only exist in C++ */
+
+#ifdef __cplusplus
+
+template <int N> class upb::InlinedArena : public upb::Arena {
+ public:
+  InlinedArena() : Arena(initial_block_, N, NULL) {}
+  explicit InlinedArena(Allocator* a) : Arena(initial_block_, N, a) {}
+
+ private:
+  UPB_DISALLOW_COPY_AND_ASSIGN(InlinedArena)
+
+  char initial_block_[N + UPB_ARENA_BLOCK_OVERHEAD];
+};
+
+template <int N> class upb::InlinedEnvironment : public upb::Environment {
+ public:
+  InlinedEnvironment() : Environment(initial_block_, N, NULL) {}
+  explicit InlinedEnvironment(Allocator *a)
+      : Environment(initial_block_, N, a) {}
+
+ private:
+  UPB_DISALLOW_COPY_AND_ASSIGN(InlinedEnvironment)
+
+  char initial_block_[N + UPB_ARENA_BLOCK_OVERHEAD];
+};
+
+#endif  /* __cplusplus */
+
+
+
+#endif  /* UPB_H_ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/* upb_value ******************************************************************/
+
+/* A tagged union (stored untagged inside the table) so that we can check that
+ * clients calling table accessors are correctly typed without having to have
+ * an explosion of accessors. */
+typedef enum {
+  UPB_CTYPE_INT32    = 1,
+  UPB_CTYPE_INT64    = 2,
+  UPB_CTYPE_UINT32   = 3,
+  UPB_CTYPE_UINT64   = 4,
+  UPB_CTYPE_BOOL     = 5,
+  UPB_CTYPE_CSTR     = 6,
+  UPB_CTYPE_PTR      = 7,
+  UPB_CTYPE_CONSTPTR = 8,
+  UPB_CTYPE_FPTR     = 9,
+  UPB_CTYPE_FLOAT    = 10,
+  UPB_CTYPE_DOUBLE   = 11
+} upb_ctype_t;
+
+typedef struct {
+  uint64_t val;
+#ifndef NDEBUG
+  /* In debug mode we carry the value type around also so we can check accesses
+   * to be sure the right member is being read. */
+  upb_ctype_t ctype;
+#endif
+} upb_value;
+
+#ifdef NDEBUG
+#define SET_TYPE(dest, val)      UPB_UNUSED(val)
+#else
+#define SET_TYPE(dest, val) dest = val
+#endif
+
+/* Like strdup(), which isn't always available since it's not ANSI C. */
+char *upb_strdup(const char *s, upb_alloc *a);
+/* Variant that works with a length-delimited rather than NULL-delimited string,
+ * as supported by strtable. */
+char *upb_strdup2(const char *s, size_t len, upb_alloc *a);
+
+UPB_INLINE char *upb_gstrdup(const char *s) {
+  return upb_strdup(s, &upb_alloc_global);
+}
+
+UPB_INLINE void _upb_value_setval(upb_value *v, uint64_t val,
+                                  upb_ctype_t ctype) {
+  v->val = val;
+  SET_TYPE(v->ctype, ctype);
+}
+
+UPB_INLINE upb_value _upb_value_val(uint64_t val, upb_ctype_t ctype) {
+  upb_value ret;
+  _upb_value_setval(&ret, val, ctype);
+  return ret;
+}
+
+/* For each value ctype, define the following set of functions:
+ *
+ * // Get/set an int32 from a upb_value.
+ * int32_t upb_value_getint32(upb_value val);
+ * void upb_value_setint32(upb_value *val, int32_t cval);
+ *
+ * // Construct a new upb_value from an int32.
+ * upb_value upb_value_int32(int32_t val); */
+#define FUNCS(name, membername, type_t, converter, proto_type) \
+  UPB_INLINE void upb_value_set ## name(upb_value *val, type_t cval) { \
+    val->val = (converter)cval; \
+    SET_TYPE(val->ctype, proto_type); \
+  } \
+  UPB_INLINE upb_value upb_value_ ## name(type_t val) { \
+    upb_value ret; \
+    upb_value_set ## name(&ret, val); \
+    return ret; \
+  } \
+  UPB_INLINE type_t upb_value_get ## name(upb_value val) { \
+    UPB_ASSERT_DEBUGVAR(val.ctype == proto_type); \
+    return (type_t)(converter)val.val; \
+  }
+
+FUNCS(int32,    int32,        int32_t,      int32_t,    UPB_CTYPE_INT32)
+FUNCS(int64,    int64,        int64_t,      int64_t,    UPB_CTYPE_INT64)
+FUNCS(uint32,   uint32,       uint32_t,     uint32_t,   UPB_CTYPE_UINT32)
+FUNCS(uint64,   uint64,       uint64_t,     uint64_t,   UPB_CTYPE_UINT64)
+FUNCS(bool,     _bool,        bool,         bool,       UPB_CTYPE_BOOL)
+FUNCS(cstr,     cstr,         char*,        uintptr_t,  UPB_CTYPE_CSTR)
+FUNCS(ptr,      ptr,          void*,        uintptr_t,  UPB_CTYPE_PTR)
+FUNCS(constptr, constptr,     const void*,  uintptr_t,  UPB_CTYPE_CONSTPTR)
+FUNCS(fptr,     fptr,         upb_func*,    uintptr_t,  UPB_CTYPE_FPTR)
+
+#undef FUNCS
+
+UPB_INLINE void upb_value_setfloat(upb_value *val, float cval) {
+  memcpy(&val->val, &cval, sizeof(cval));
+  SET_TYPE(val->ctype, UPB_CTYPE_FLOAT);
+}
+
+UPB_INLINE void upb_value_setdouble(upb_value *val, double cval) {
+  memcpy(&val->val, &cval, sizeof(cval));
+  SET_TYPE(val->ctype, UPB_CTYPE_DOUBLE);
+}
+
+UPB_INLINE upb_value upb_value_float(float cval) {
+  upb_value ret;
+  upb_value_setfloat(&ret, cval);
+  return ret;
+}
+
+UPB_INLINE upb_value upb_value_double(double cval) {
+  upb_value ret;
+  upb_value_setdouble(&ret, cval);
+  return ret;
+}
+
+#undef SET_TYPE
+
+
+/* upb_tabkey *****************************************************************/
+
+/* Either:
+ *   1. an actual integer key, or
+ *   2. a pointer to a string prefixed by its uint32_t length, owned by us.
+ *
+ * ...depending on whether this is a string table or an int table.  We would
+ * make this a union of those two types, but C89 doesn't support statically
+ * initializing a non-first union member. */
+typedef uintptr_t upb_tabkey;
+
+#define UPB_TABKEY_NUM(n) n
+#define UPB_TABKEY_NONE 0
+/* The preprocessor isn't quite powerful enough to turn the compile-time string
+ * length into a byte-wise string representation, so code generation needs to
+ * help it along.
+ *
+ * "len1" is the low byte and len4 is the high byte. */
+#ifdef UPB_BIG_ENDIAN
+#define UPB_TABKEY_STR(len1, len2, len3, len4, strval) \
+    (uintptr_t)(len4 len3 len2 len1 strval)
+#else
+#define UPB_TABKEY_STR(len1, len2, len3, len4, strval) \
+    (uintptr_t)(len1 len2 len3 len4 strval)
+#endif
+
+UPB_INLINE char *upb_tabstr(upb_tabkey key, uint32_t *len) {
+  char* mem = (char*)key;
+  if (len) memcpy(len, mem, sizeof(*len));
+  return mem + sizeof(*len);
+}
+
+
+/* upb_tabval *****************************************************************/
+
+#ifdef __cplusplus
+
+/* Status initialization not supported.
+ *
+ * This separate definition is necessary because in C++, UINTPTR_MAX isn't
+ * reliably available. */
+typedef struct {
+  uint64_t val;
+} upb_tabval;
+
+#else
+
+/* C -- supports static initialization, but to support static initialization of
+ * both integers and points for both 32 and 64 bit targets, it takes a little
+ * bit of doing. */
+
+#if UINTPTR_MAX == 0xffffffffffffffffULL
+#define UPB_PTR_IS_64BITS
+#elif UINTPTR_MAX != 0xffffffff
+#error Could not determine how many bits pointers are.
+#endif
+
+typedef union {
+  /* For static initialization.
+   *
+   * Unfortunately this ugliness is necessary -- it is the only way that we can,
+   * with -std=c89 -pedantic, statically initialize this to either a pointer or
+   * an integer on 32-bit platforms. */
+  struct {
+#ifdef UPB_PTR_IS_64BITS
+    uintptr_t val;
+#else
+    uintptr_t val1;
+    uintptr_t val2;
+#endif
+  } staticinit;
+
+  /* The normal accessor that we use for everything at runtime. */
+  uint64_t val;
+} upb_tabval;
+
+#ifdef UPB_PTR_IS_64BITS
+#define UPB_TABVALUE_INT_INIT(v) {{v}}
+#define UPB_TABVALUE_EMPTY_INIT  {{-1}}
+#else
+
+/* 32-bit pointers */
+
+#ifdef UPB_BIG_ENDIAN
+#define UPB_TABVALUE_INT_INIT(v) {{0, v}}
+#define UPB_TABVALUE_EMPTY_INIT  {{-1, -1}}
+#else
+#define UPB_TABVALUE_INT_INIT(v) {{v, 0}}
+#define UPB_TABVALUE_EMPTY_INIT  {{-1, -1}}
+#endif
+
+#endif
+
+#define UPB_TABVALUE_PTR_INIT(v) UPB_TABVALUE_INT_INIT((uintptr_t)v)
+
+#undef UPB_PTR_IS_64BITS
+
+#endif  /* __cplusplus */
+
+
+/* upb_table ******************************************************************/
+
+typedef struct _upb_tabent {
+  upb_tabkey key;
+  upb_tabval val;
+
+  /* Internal chaining.  This is const so we can create static initializers for
+   * tables.  We cast away const sometimes, but *only* when the containing
+   * upb_table is known to be non-const.  This requires a bit of care, but
+   * the subtlety is confined to table.c. */
+  const struct _upb_tabent *next;
+} upb_tabent;
+
+typedef struct {
+  size_t count;          /* Number of entries in the hash part. */
+  size_t mask;           /* Mask to turn hash value -> bucket. */
+  upb_ctype_t ctype;     /* Type of all values. */
+  uint8_t size_lg2;      /* Size of the hashtable part is 2^size_lg2 entries. */
+
+  /* Hash table entries.
+   * Making this const isn't entirely accurate; what we really want is for it to
+   * have the same const-ness as the table it's inside.  But there's no way to
+   * declare that in C.  So we have to make it const so that we can statically
+   * initialize const hash tables.  Then we cast away const when we have to.
+   */
+  const upb_tabent *entries;
+
+#ifndef NDEBUG
+  /* This table's allocator.  We make the user pass it in to every relevant
+   * function and only use this to check it in debug mode.  We do this solely
+   * to keep upb_table as small as possible.  This might seem slightly paranoid
+   * but the plan is to use upb_table for all map fields and extension sets in
+   * a forthcoming message representation, so there could be a lot of these.
+   * If this turns out to be too annoying later, we can change it (since this
+   * is an internal-only header file). */
+  upb_alloc *alloc;
+#endif
+} upb_table;
+
+#ifdef NDEBUG
+#  define UPB_TABLE_INIT(count, mask, ctype, size_lg2, entries) \
+     {count, mask, ctype, size_lg2, entries}
+#else
+#  ifdef UPB_DEBUG_REFS
+/* At the moment the only mutable tables we statically initialize are debug
+ * ref tables. */
+#    define UPB_TABLE_INIT(count, mask, ctype, size_lg2, entries) \
+       {count, mask, ctype, size_lg2, entries, &upb_alloc_debugrefs}
+#  else
+#    define UPB_TABLE_INIT(count, mask, ctype, size_lg2, entries) \
+       {count, mask, ctype, size_lg2, entries, NULL}
+#  endif
+#endif
+
+typedef struct {
+  upb_table t;
+} upb_strtable;
+
+#define UPB_STRTABLE_INIT(count, mask, ctype, size_lg2, entries) \
+  {UPB_TABLE_INIT(count, mask, ctype, size_lg2, entries)}
+
+#define UPB_EMPTY_STRTABLE_INIT(ctype)                           \
+  UPB_STRTABLE_INIT(0, 0, ctype, 0, NULL)
+
+typedef struct {
+  upb_table t;              /* For entries that don't fit in the array part. */
+  const upb_tabval *array;  /* Array part of the table. See const note above. */
+  size_t array_size;        /* Array part size. */
+  size_t array_count;       /* Array part number of elements. */
+} upb_inttable;
+
+#define UPB_INTTABLE_INIT(count, mask, ctype, size_lg2, ent, a, asize, acount) \
+  {UPB_TABLE_INIT(count, mask, ctype, size_lg2, ent), a, asize, acount}
+
+#define UPB_EMPTY_INTTABLE_INIT(ctype) \
+  UPB_INTTABLE_INIT(0, 0, ctype, 0, NULL, NULL, 0, 0)
+
+#define UPB_ARRAY_EMPTYENT -1
+
+UPB_INLINE size_t upb_table_size(const upb_table *t) {
+  if (t->size_lg2 == 0)
+    return 0;
+  else
+    return 1 << t->size_lg2;
+}
+
+/* Internal-only functions, in .h file only out of necessity. */
+UPB_INLINE bool upb_tabent_isempty(const upb_tabent *e) {
+  return e->key == 0;
+}
+
+/* Used by some of the unit tests for generic hashing functionality. */
+uint32_t MurmurHash2(const void * key, size_t len, uint32_t seed);
+
+UPB_INLINE uintptr_t upb_intkey(uintptr_t key) {
+  return key;
+}
+
+UPB_INLINE uint32_t upb_inthash(uintptr_t key) {
+  return (uint32_t)key;
+}
+
+static const upb_tabent *upb_getentry(const upb_table *t, uint32_t hash) {
+  return t->entries + (hash & t->mask);
+}
+
+UPB_INLINE bool upb_arrhas(upb_tabval key) {
+  return key.val != (uint64_t)-1;
+}
+
+/* Initialize and uninitialize a table, respectively.  If memory allocation
+ * failed, false is returned that the table is uninitialized. */
+bool upb_inttable_init2(upb_inttable *table, upb_ctype_t ctype, upb_alloc *a);
+bool upb_strtable_init2(upb_strtable *table, upb_ctype_t ctype, upb_alloc *a);
+void upb_inttable_uninit2(upb_inttable *table, upb_alloc *a);
+void upb_strtable_uninit2(upb_strtable *table, upb_alloc *a);
+
+UPB_INLINE bool upb_inttable_init(upb_inttable *table, upb_ctype_t ctype) {
+  return upb_inttable_init2(table, ctype, &upb_alloc_global);
+}
+
+UPB_INLINE bool upb_strtable_init(upb_strtable *table, upb_ctype_t ctype) {
+  return upb_strtable_init2(table, ctype, &upb_alloc_global);
+}
+
+UPB_INLINE void upb_inttable_uninit(upb_inttable *table) {
+  upb_inttable_uninit2(table, &upb_alloc_global);
+}
+
+UPB_INLINE void upb_strtable_uninit(upb_strtable *table) {
+  upb_strtable_uninit2(table, &upb_alloc_global);
+}
+
+/* Returns the number of values in the table. */
+size_t upb_inttable_count(const upb_inttable *t);
+UPB_INLINE size_t upb_strtable_count(const upb_strtable *t) {
+  return t->t.count;
+}
+
+void upb_inttable_packedsize(const upb_inttable *t, size_t *size);
+void upb_strtable_packedsize(const upb_strtable *t, size_t *size);
+upb_inttable *upb_inttable_pack(const upb_inttable *t, void *p, size_t *ofs,
+                                size_t size);
+upb_strtable *upb_strtable_pack(const upb_strtable *t, void *p, size_t *ofs,
+                                size_t size);
+
+/* Inserts the given key into the hashtable with the given value.  The key must
+ * not already exist in the hash table.  For string tables, the key must be
+ * NULL-terminated, and the table will make an internal copy of the key.
+ * Inttables must not insert a value of UINTPTR_MAX.
+ *
+ * If a table resize was required but memory allocation failed, false is
+ * returned and the table is unchanged. */
+bool upb_inttable_insert2(upb_inttable *t, uintptr_t key, upb_value val,
+                          upb_alloc *a);
+bool upb_strtable_insert3(upb_strtable *t, const char *key, size_t len,
+                          upb_value val, upb_alloc *a);
+
+UPB_INLINE bool upb_inttable_insert(upb_inttable *t, uintptr_t key,
+                                    upb_value val) {
+  return upb_inttable_insert2(t, key, val, &upb_alloc_global);
+}
+
+UPB_INLINE bool upb_strtable_insert2(upb_strtable *t, const char *key,
+                                     size_t len, upb_value val) {
+  return upb_strtable_insert3(t, key, len, val, &upb_alloc_global);
+}
+
+/* For NULL-terminated strings. */
+UPB_INLINE bool upb_strtable_insert(upb_strtable *t, const char *key,
+                                    upb_value val) {
+  return upb_strtable_insert2(t, key, strlen(key), val);
+}
+
+/* Looks up key in this table, returning "true" if the key was found.
+ * If v is non-NULL, copies the value for this key into *v. */
+bool upb_inttable_lookup(const upb_inttable *t, uintptr_t key, upb_value *v);
+bool upb_strtable_lookup2(const upb_strtable *t, const char *key, size_t len,
+                          upb_value *v);
+
+/* For NULL-terminated strings. */
+UPB_INLINE bool upb_strtable_lookup(const upb_strtable *t, const char *key,
+                                    upb_value *v) {
+  return upb_strtable_lookup2(t, key, strlen(key), v);
+}
+
+/* Removes an item from the table.  Returns true if the remove was successful,
+ * and stores the removed item in *val if non-NULL. */
+bool upb_inttable_remove(upb_inttable *t, uintptr_t key, upb_value *val);
+bool upb_strtable_remove3(upb_strtable *t, const char *key, size_t len,
+                          upb_value *val, upb_alloc *alloc);
+
+UPB_INLINE bool upb_strtable_remove2(upb_strtable *t, const char *key,
+                                     size_t len, upb_value *val) {
+  return upb_strtable_remove3(t, key, len, val, &upb_alloc_global);
+}
+
+/* For NULL-terminated strings. */
+UPB_INLINE bool upb_strtable_remove(upb_strtable *t, const char *key,
+                                    upb_value *v) {
+  return upb_strtable_remove2(t, key, strlen(key), v);
+}
+
+/* Updates an existing entry in an inttable.  If the entry does not exist,
+ * returns false and does nothing.  Unlike insert/remove, this does not
+ * invalidate iterators. */
+bool upb_inttable_replace(upb_inttable *t, uintptr_t key, upb_value val);
+
+/* Handy routines for treating an inttable like a stack.  May not be mixed with
+ * other insert/remove calls. */
+bool upb_inttable_push2(upb_inttable *t, upb_value val, upb_alloc *a);
+upb_value upb_inttable_pop(upb_inttable *t);
+
+UPB_INLINE bool upb_inttable_push(upb_inttable *t, upb_value val) {
+  return upb_inttable_push2(t, val, &upb_alloc_global);
+}
+
+/* Convenience routines for inttables with pointer keys. */
+bool upb_inttable_insertptr2(upb_inttable *t, const void *key, upb_value val,
+                             upb_alloc *a);
+bool upb_inttable_removeptr(upb_inttable *t, const void *key, upb_value *val);
+bool upb_inttable_lookupptr(
+    const upb_inttable *t, const void *key, upb_value *val);
+
+UPB_INLINE bool upb_inttable_insertptr(upb_inttable *t, const void *key,
+                                       upb_value val) {
+  return upb_inttable_insertptr2(t, key, val, &upb_alloc_global);
+}
+
+/* Optimizes the table for the current set of entries, for both memory use and
+ * lookup time.  Client should call this after all entries have been inserted;
+ * inserting more entries is legal, but will likely require a table resize. */
+void upb_inttable_compact2(upb_inttable *t, upb_alloc *a);
+
+UPB_INLINE void upb_inttable_compact(upb_inttable *t) {
+  upb_inttable_compact2(t, &upb_alloc_global);
+}
+
+/* A special-case inlinable version of the lookup routine for 32-bit
+ * integers. */
+UPB_INLINE bool upb_inttable_lookup32(const upb_inttable *t, uint32_t key,
+                                      upb_value *v) {
+  *v = upb_value_int32(0);  /* Silence compiler warnings. */
+  if (key < t->array_size) {
+    upb_tabval arrval = t->array[key];
+    if (upb_arrhas(arrval)) {
+      _upb_value_setval(v, arrval.val, t->t.ctype);
+      return true;
+    } else {
+      return false;
+    }
+  } else {
+    const upb_tabent *e;
+    if (t->t.entries == NULL) return false;
+    for (e = upb_getentry(&t->t, upb_inthash(key)); true; e = e->next) {
+      if ((uint32_t)e->key == key) {
+        _upb_value_setval(v, e->val.val, t->t.ctype);
+        return true;
+      }
+      if (e->next == NULL) return false;
+    }
+  }
+}
+
+/* Exposed for testing only. */
+bool upb_strtable_resize(upb_strtable *t, size_t size_lg2, upb_alloc *a);
+
+/* Iterators ******************************************************************/
+
+/* Iterators for int and string tables.  We are subject to some kind of unusual
+ * design constraints:
+ *
+ * For high-level languages:
+ *  - we must be able to guarantee that we don't crash or corrupt memory even if
+ *    the program accesses an invalidated iterator.
+ *
+ * For C++11 range-based for:
+ *  - iterators must be copyable
+ *  - iterators must be comparable
+ *  - it must be possible to construct an "end" value.
+ *
+ * Iteration order is undefined.
+ *
+ * Modifying the table invalidates iterators.  upb_{str,int}table_done() is
+ * guaranteed to work even on an invalidated iterator, as long as the table it
+ * is iterating over has not been freed.  Calling next() or accessing data from
+ * an invalidated iterator yields unspecified elements from the table, but it is
+ * guaranteed not to crash and to return real table elements (except when done()
+ * is true). */
+
+
+/* upb_strtable_iter **********************************************************/
+
+/*   upb_strtable_iter i;
+ *   upb_strtable_begin(&i, t);
+ *   for(; !upb_strtable_done(&i); upb_strtable_next(&i)) {
+ *     const char *key = upb_strtable_iter_key(&i);
+ *     const upb_value val = upb_strtable_iter_value(&i);
+ *     // ...
+ *   }
+ */
+
+typedef struct {
+  const upb_strtable *t;
+  size_t index;
+} upb_strtable_iter;
+
+void upb_strtable_begin(upb_strtable_iter *i, const upb_strtable *t);
+void upb_strtable_next(upb_strtable_iter *i);
+bool upb_strtable_done(const upb_strtable_iter *i);
+const char *upb_strtable_iter_key(const upb_strtable_iter *i);
+size_t upb_strtable_iter_keylength(const upb_strtable_iter *i);
+upb_value upb_strtable_iter_value(const upb_strtable_iter *i);
+void upb_strtable_iter_setdone(upb_strtable_iter *i);
+bool upb_strtable_iter_isequal(const upb_strtable_iter *i1,
+                               const upb_strtable_iter *i2);
+
+
+/* upb_inttable_iter **********************************************************/
+
+/*   upb_inttable_iter i;
+ *   upb_inttable_begin(&i, t);
+ *   for(; !upb_inttable_done(&i); upb_inttable_next(&i)) {
+ *     uintptr_t key = upb_inttable_iter_key(&i);
+ *     upb_value val = upb_inttable_iter_value(&i);
+ *     // ...
+ *   }
+ */
+
+typedef struct {
+  const upb_inttable *t;
+  size_t index;
+  bool array_part;
+} upb_inttable_iter;
+
+void upb_inttable_begin(upb_inttable_iter *i, const upb_inttable *t);
+void upb_inttable_next(upb_inttable_iter *i);
+bool upb_inttable_done(const upb_inttable_iter *i);
+uintptr_t upb_inttable_iter_key(const upb_inttable_iter *i);
+upb_value upb_inttable_iter_value(const upb_inttable_iter *i);
+void upb_inttable_iter_setdone(upb_inttable_iter *i);
+bool upb_inttable_iter_isequal(const upb_inttable_iter *i1,
+                               const upb_inttable_iter *i2);
+
+
+#ifdef __cplusplus
+}  /* extern "C" */
+#endif
+
+#endif  /* UPB_TABLE_H_ */
+
+/* Reference tracking will check ref()/unref() operations to make sure the
+ * ref ownership is correct.  Where possible it will also make tools like
+ * Valgrind attribute ref leaks to the code that took the leaked ref, not
+ * the code that originally created the object.
+ *
+ * Enabling this requires the application to define upb_lock()/upb_unlock()
+ * functions that acquire/release a global mutex (or #define UPB_THREAD_UNSAFE).
+ * For this reason we don't enable it by default, even in debug builds.
+ */
+
+/* #define UPB_DEBUG_REFS */
+
+#ifdef __cplusplus
+namespace upb {
+class RefCounted;
+template <class T> class reffed_ptr;
+}
+#endif
+
+UPB_DECLARE_TYPE(upb::RefCounted, upb_refcounted)
+
+struct upb_refcounted_vtbl;
+
+#ifdef __cplusplus
+
+class upb::RefCounted {
+ public:
+  /* Returns true if the given object is frozen. */
+  bool IsFrozen() const;
+
+  /* Increases the ref count, the new ref is owned by "owner" which must not
+   * already own a ref (and should not itself be a refcounted object if the ref
+   * could possibly be circular; see below).
+   * Thread-safe iff "this" is frozen. */
+  void Ref(const void *owner) const;
+
+  /* Release a ref that was acquired from upb_refcounted_ref() and collects any
+   * objects it can. */
+  void Unref(const void *owner) const;
+
+  /* Moves an existing ref from "from" to "to", without changing the overall
+   * ref count.  DonateRef(foo, NULL, owner) is the same as Ref(foo, owner),
+   * but "to" may not be NULL. */
+  void DonateRef(const void *from, const void *to) const;
+
+  /* Verifies that a ref to the given object is currently held by the given
+   * owner.  Only effective in UPB_DEBUG_REFS builds. */
+  void CheckRef(const void *owner) const;
+
+ private:
+  UPB_DISALLOW_POD_OPS(RefCounted, upb::RefCounted)
+#else
+struct upb_refcounted {
+#endif
+  /* TODO(haberman): move the actual structure definition to structdefs.int.h.
+   * The only reason they are here is because inline functions need to see the
+   * definition of upb_handlers, which needs to see this definition.  But we
+   * can change the upb_handlers inline functions to deal in raw offsets
+   * instead.
+   */
+
+  /* A single reference count shared by all objects in the group. */
+  uint32_t *group;
+
+  /* A singly-linked list of all objects in the group. */
+  upb_refcounted *next;
+
+  /* Table of function pointers for this type. */
+  const struct upb_refcounted_vtbl *vtbl;
+
+  /* Maintained only when mutable, this tracks the number of refs (but not
+   * ref2's) to this object.  *group should be the sum of all individual_count
+   * in the group. */
+  uint32_t individual_count;
+
+  bool is_frozen;
+
+#ifdef UPB_DEBUG_REFS
+  upb_inttable *refs;  /* Maps owner -> trackedref for incoming refs. */
+  upb_inttable *ref2s; /* Set of targets for outgoing ref2s. */
+#endif
+};
+
+#ifdef UPB_DEBUG_REFS
+extern upb_alloc upb_alloc_debugrefs;
+#define UPB_REFCOUNT_INIT(vtbl, refs, ref2s) \
+    {&static_refcount, NULL, vtbl, 0, true, refs, ref2s}
+#else
+#define UPB_REFCOUNT_INIT(vtbl, refs, ref2s) \
+    {&static_refcount, NULL, vtbl, 0, true}
+#endif
+
+UPB_BEGIN_EXTERN_C
+
+/* It is better to use tracked refs when possible, for the extra debugging
+ * capability.  But if this is not possible (because you don't have easy access
+ * to a stable pointer value that is associated with the ref), you can pass
+ * UPB_UNTRACKED_REF instead.  */
+extern const void *UPB_UNTRACKED_REF;
+
+/* Native C API. */
+bool upb_refcounted_isfrozen(const upb_refcounted *r);
+void upb_refcounted_ref(const upb_refcounted *r, const void *owner);
+void upb_refcounted_unref(const upb_refcounted *r, const void *owner);
+void upb_refcounted_donateref(
+    const upb_refcounted *r, const void *from, const void *to);
+void upb_refcounted_checkref(const upb_refcounted *r, const void *owner);
+
+#define UPB_REFCOUNTED_CMETHODS(type, upcastfunc) \
+  UPB_INLINE bool type ## _isfrozen(const type *v) { \
+    return upb_refcounted_isfrozen(upcastfunc(v)); \
+  } \
+  UPB_INLINE void type ## _ref(const type *v, const void *owner) { \
+    upb_refcounted_ref(upcastfunc(v), owner); \
+  } \
+  UPB_INLINE void type ## _unref(const type *v, const void *owner) { \
+    upb_refcounted_unref(upcastfunc(v), owner); \
+  } \
+  UPB_INLINE void type ## _donateref(const type *v, const void *from, const void *to) { \
+    upb_refcounted_donateref(upcastfunc(v), from, to); \
+  } \
+  UPB_INLINE void type ## _checkref(const type *v, const void *owner) { \
+    upb_refcounted_checkref(upcastfunc(v), owner); \
+  }
+
+#define UPB_REFCOUNTED_CPPMETHODS \
+  bool IsFrozen() const { \
+    return upb::upcast_to<const upb::RefCounted>(this)->IsFrozen(); \
+  } \
+  void Ref(const void *owner) const { \
+    return upb::upcast_to<const upb::RefCounted>(this)->Ref(owner); \
+  } \
+  void Unref(const void *owner) const { \
+    return upb::upcast_to<const upb::RefCounted>(this)->Unref(owner); \
+  } \
+  void DonateRef(const void *from, const void *to) const { \
+    return upb::upcast_to<const upb::RefCounted>(this)->DonateRef(from, to); \
+  } \
+  void CheckRef(const void *owner) const { \
+    return upb::upcast_to<const upb::RefCounted>(this)->CheckRef(owner); \
+  }
+
+/* Internal-to-upb Interface **************************************************/
+
+typedef void upb_refcounted_visit(const upb_refcounted *r,
+                                  const upb_refcounted *subobj,
+                                  void *closure);
+
+struct upb_refcounted_vtbl {
+  /* Must visit all subobjects that are currently ref'd via upb_refcounted_ref2.
+   * Must be longjmp()-safe. */
+  void (*visit)(const upb_refcounted *r, upb_refcounted_visit *visit, void *c);
+
+  /* Must free the object and release all references to other objects. */
+  void (*free)(upb_refcounted *r);
+};
+
+/* Initializes the refcounted with a single ref for the given owner.  Returns
+ * false if memory could not be allocated. */
+bool upb_refcounted_init(upb_refcounted *r,
+                         const struct upb_refcounted_vtbl *vtbl,
+                         const void *owner);
+
+/* Adds a ref from one refcounted object to another ("from" must not already
+ * own a ref).  These refs may be circular; cycles will be collected correctly
+ * (if conservatively).  These refs do not need to be freed in from's free()
+ * function. */
+void upb_refcounted_ref2(const upb_refcounted *r, upb_refcounted *from);
+
+/* Removes a ref that was acquired from upb_refcounted_ref2(), and collects any
+ * object it can.  This is only necessary when "from" no longer points to "r",
+ * and not from from's "free" function. */
+void upb_refcounted_unref2(const upb_refcounted *r, upb_refcounted *from);
+
+#define upb_ref2(r, from) \
+    upb_refcounted_ref2((const upb_refcounted*)r, (upb_refcounted*)from)
+#define upb_unref2(r, from) \
+    upb_refcounted_unref2((const upb_refcounted*)r, (upb_refcounted*)from)
+
+/* Freezes all mutable object reachable by ref2() refs from the given roots.
+ * This will split refcounting groups into precise SCC groups, so that
+ * refcounting of frozen objects can be more aggressive.  If memory allocation
+ * fails, or if more than 2**31 mutable objects are reachable from "roots", or
+ * if the maximum depth of the graph exceeds "maxdepth", false is returned and
+ * the objects are unchanged.
+ *
+ * After this operation succeeds, the objects are frozen/const, and may not be
+ * used through non-const pointers.  In particular, they may not be passed as
+ * the second parameter of upb_refcounted_{ref,unref}2().  On the upside, all
+ * operations on frozen refcounteds are threadsafe, and objects will be freed
+ * at the precise moment that they become unreachable.
+ *
+ * Caller must own refs on each object in the "roots" list. */
+bool upb_refcounted_freeze(upb_refcounted *const*roots, int n, upb_status *s,
+                           int maxdepth);
+
+/* Shared by all compiled-in refcounted objects. */
+extern uint32_t static_refcount;
+
+UPB_END_EXTERN_C
+
+#ifdef __cplusplus
+/* C++ Wrappers. */
+namespace upb {
+inline bool RefCounted::IsFrozen() const {
+  return upb_refcounted_isfrozen(this);
+}
+inline void RefCounted::Ref(const void *owner) const {
+  upb_refcounted_ref(this, owner);
+}
+inline void RefCounted::Unref(const void *owner) const {
+  upb_refcounted_unref(this, owner);
+}
+inline void RefCounted::DonateRef(const void *from, const void *to) const {
+  upb_refcounted_donateref(this, from, to);
+}
+inline void RefCounted::CheckRef(const void *owner) const {
+  upb_refcounted_checkref(this, owner);
+}
+}  /* namespace upb */
+#endif
+
+
+/* upb::reffed_ptr ************************************************************/
+
+#ifdef __cplusplus
+
+#include <algorithm>  /* For std::swap(). */
+
+/* Provides RAII semantics for upb refcounted objects.  Each reffed_ptr owns a
+ * ref on whatever object it points to (if any). */
+template <class T> class upb::reffed_ptr {
+ public:
+  reffed_ptr() : ptr_(NULL) {}
+
+  /* If ref_donor is NULL, takes a new ref, otherwise adopts from ref_donor. */
+  template <class U>
+  reffed_ptr(U* val, const void* ref_donor = NULL)
+      : ptr_(upb::upcast(val)) {
+    if (ref_donor) {
+      UPB_ASSERT(ptr_);
+      ptr_->DonateRef(ref_donor, this);
+    } else if (ptr_) {
+      ptr_->Ref(this);
+    }
+  }
+
+  template <class U>
+  reffed_ptr(const reffed_ptr<U>& other)
+      : ptr_(upb::upcast(other.get())) {
+    if (ptr_) ptr_->Ref(this);
+  }
+
+  reffed_ptr(const reffed_ptr& other)
+      : ptr_(upb::upcast(other.get())) {
+    if (ptr_) ptr_->Ref(this);
+  }
+
+  ~reffed_ptr() { if (ptr_) ptr_->Unref(this); }
+
+  template <class U>
+  reffed_ptr& operator=(const reffed_ptr<U>& other) {
+    reset(other.get());
+    return *this;
+  }
+
+  reffed_ptr& operator=(const reffed_ptr& other) {
+    reset(other.get());
+    return *this;
+  }
+
+  /* TODO(haberman): add C++11 move construction/assignment for greater
+   * efficiency. */
+
+  void swap(reffed_ptr& other) {
+    if (ptr_ == other.ptr_) {
+      return;
+    }
+
+    if (ptr_) ptr_->DonateRef(this, &other);
+    if (other.ptr_) other.ptr_->DonateRef(&other, this);
+    std::swap(ptr_, other.ptr_);
+  }
+
+  T& operator*() const {
+    UPB_ASSERT(ptr_);
+    return *ptr_;
+  }
+
+  T* operator->() const {
+    UPB_ASSERT(ptr_);
+    return ptr_;
+  }
+
+  T* get() const { return ptr_; }
+
+  /* If ref_donor is NULL, takes a new ref, otherwise adopts from ref_donor. */
+  template <class U>
+  void reset(U* ptr = NULL, const void* ref_donor = NULL) {
+    reffed_ptr(ptr, ref_donor).swap(*this);
+  }
+
+  template <class U>
+  reffed_ptr<U> down_cast() {
+    return reffed_ptr<U>(upb::down_cast<U*>(get()));
+  }
+
+  template <class U>
+  reffed_ptr<U> dyn_cast() {
+    return reffed_ptr<U>(upb::dyn_cast<U*>(get()));
+  }
+
+  /* Plain release() is unsafe; if we were the only owner, it would leak the
+   * object.  Instead we provide this: */
+  T* ReleaseTo(const void* new_owner) {
+    T* ret = NULL;
+    ptr_->DonateRef(this, new_owner);
+    std::swap(ret, ptr_);
+    return ret;
+  }
+
+ private:
+  T* ptr_;
+};
+
+#endif  /* __cplusplus */
+
+#endif  /* UPB_REFCOUNT_H_ */
+
+#ifdef __cplusplus
+#include <cstring>
+#include <string>
+#include <vector>
+
+namespace upb {
+class Def;
+class EnumDef;
+class FieldDef;
+class FileDef;
+class MessageDef;
+class OneofDef;
+class SymbolTable;
+}
+#endif
+
+UPB_DECLARE_DERIVED_TYPE(upb::Def, upb::RefCounted, upb_def, upb_refcounted)
+UPB_DECLARE_DERIVED_TYPE(upb::OneofDef, upb::RefCounted, upb_oneofdef,
+                         upb_refcounted)
+UPB_DECLARE_DERIVED_TYPE(upb::FileDef, upb::RefCounted, upb_filedef,
+                         upb_refcounted)
+UPB_DECLARE_TYPE(upb::SymbolTable, upb_symtab)
+
+
+/* The maximum message depth that the type graph can have.  This is a resource
+ * limit for the C stack since we sometimes need to recursively traverse the
+ * graph.  Cycles are ok; the traversal will stop when it detects a cycle, but
+ * we must hit the cycle before the maximum depth is reached.
+ *
+ * If having a single static limit is too inflexible, we can add another variant
+ * of Def::Freeze that allows specifying this as a parameter. */
+#define UPB_MAX_MESSAGE_DEPTH 64
+
+
+/* upb::Def: base class for top-level defs  ***********************************/
+
+/* All the different kind of defs that can be defined at the top-level and put
+ * in a SymbolTable or appear in a FileDef::defs() list.  This excludes some
+ * defs (like oneofs and files).  It only includes fields because they can be
+ * defined as extensions. */
+typedef enum {
+  UPB_DEF_MSG,
+  UPB_DEF_FIELD,
+  UPB_DEF_ENUM,
+  UPB_DEF_SERVICE,   /* Not yet implemented. */
+  UPB_DEF_ANY = -1   /* Wildcard for upb_symtab_get*() */
+} upb_deftype_t;
+
+#ifdef __cplusplus
+
+/* The base class of all defs.  Its base is upb::RefCounted (use upb::upcast()
+ * to convert). */
+class upb::Def {
+ public:
+  typedef upb_deftype_t Type;
+
+  /* upb::RefCounted methods like Ref()/Unref(). */
+  UPB_REFCOUNTED_CPPMETHODS
+
+  Type def_type() const;
+
+  /* "fullname" is the def's fully-qualified name (eg. foo.bar.Message). */
+  const char *full_name() const;
+
+  /* The final part of a def's name (eg. Message). */
+  const char *name() const;
+
+  /* The def must be mutable.  Caller retains ownership of fullname.  Defs are
+   * not required to have a name; if a def has no name when it is frozen, it
+   * will remain an anonymous def.  On failure, returns false and details in "s"
+   * if non-NULL. */
+  bool set_full_name(const char* fullname, upb::Status* s);
+  bool set_full_name(const std::string &fullname, upb::Status* s);
+
+  /* The file in which this def appears.  It is not necessary to add a def to a
+   * file (and consequently the accessor may return NULL).  Set this by calling
+   * file->Add(def). */
+  FileDef* file() const;
+
+  /* Freezes the given defs; this validates all constraints and marks the defs
+   * as frozen (read-only).  "defs" may not contain any fielddefs, but fields
+   * of any msgdefs will be frozen.
+   *
+   * Symbolic references to sub-types and enum defaults must have already been
+   * resolved.  Any mutable defs reachable from any of "defs" must also be in
+   * the list; more formally, "defs" must be a transitive closure of mutable
+   * defs.
+   *
+   * After this operation succeeds, the finalized defs must only be accessed
+   * through a const pointer! */
+  static bool Freeze(Def* const* defs, size_t n, Status* status);
+  static bool Freeze(const std::vector<Def*>& defs, Status* status);
+
+ private:
+  UPB_DISALLOW_POD_OPS(Def, upb::Def)
+};
+
+#endif  /* __cplusplus */
+
+UPB_BEGIN_EXTERN_C
+
+/* Include upb_refcounted methods like upb_def_ref()/upb_def_unref(). */
+UPB_REFCOUNTED_CMETHODS(upb_def, upb_def_upcast)
+
+upb_deftype_t upb_def_type(const upb_def *d);
+const char *upb_def_fullname(const upb_def *d);
+const char *upb_def_name(const upb_def *d);
+const upb_filedef *upb_def_file(const upb_def *d);
+bool upb_def_setfullname(upb_def *def, const char *fullname, upb_status *s);
+bool upb_def_freeze(upb_def *const *defs, size_t n, upb_status *s);
+
+/* Temporary API: for internal use only. */
+bool _upb_def_validate(upb_def *const*defs, size_t n, upb_status *s);
+
+UPB_END_EXTERN_C
+
+
+/* upb::Def casts *************************************************************/
+
+#ifdef __cplusplus
+#define UPB_CPP_CASTS(cname, cpptype)                                          \
+  namespace upb {                                                              \
+  template <>                                                                  \
+  inline cpptype *down_cast<cpptype *, Def>(Def * def) {                       \
+    return upb_downcast_##cname##_mutable(def);                                \
+  }                                                                            \
+  template <>                                                                  \
+  inline cpptype *dyn_cast<cpptype *, Def>(Def * def) {                        \
+    return upb_dyncast_##cname##_mutable(def);                                 \
+  }                                                                            \
+  template <>                                                                  \
+  inline const cpptype *down_cast<const cpptype *, const Def>(                 \
+      const Def *def) {                                                        \
+    return upb_downcast_##cname(def);                                          \
+  }                                                                            \
+  template <>                                                                  \
+  inline const cpptype *dyn_cast<const cpptype *, const Def>(const Def *def) { \
+    return upb_dyncast_##cname(def);                                           \
+  }                                                                            \
+  template <>                                                                  \
+  inline const cpptype *down_cast<const cpptype *, Def>(Def * def) {           \
+    return upb_downcast_##cname(def);                                          \
+  }                                                                            \
+  template <>                                                                  \
+  inline const cpptype *dyn_cast<const cpptype *, Def>(Def * def) {            \
+    return upb_dyncast_##cname(def);                                           \
+  }                                                                            \
+  }  /* namespace upb */
+#else
+#define UPB_CPP_CASTS(cname, cpptype)
+#endif  /* __cplusplus */
+
+/* Dynamic casts, for determining if a def is of a particular type at runtime.
+ * Downcasts, for when some wants to assert that a def is of a particular type.
+ * These are only checked if we are building debug. */
+#define UPB_DEF_CASTS(lower, upper, cpptype)                               \
+  UPB_INLINE const upb_##lower *upb_dyncast_##lower(const upb_def *def) {  \
+    if (upb_def_type(def) != UPB_DEF_##upper) return NULL;                 \
+    return (upb_##lower *)def;                                             \
+  }                                                                        \
+  UPB_INLINE const upb_##lower *upb_downcast_##lower(const upb_def *def) { \
+    UPB_ASSERT(upb_def_type(def) == UPB_DEF_##upper);                          \
+    return (const upb_##lower *)def;                                       \
+  }                                                                        \
+  UPB_INLINE upb_##lower *upb_dyncast_##lower##_mutable(upb_def *def) {    \
+    return (upb_##lower *)upb_dyncast_##lower(def);                        \
+  }                                                                        \
+  UPB_INLINE upb_##lower *upb_downcast_##lower##_mutable(upb_def *def) {   \
+    return (upb_##lower *)upb_downcast_##lower(def);                       \
+  }                                                                        \
+  UPB_CPP_CASTS(lower, cpptype)
+
+#define UPB_DEFINE_DEF(cppname, lower, upper, cppmethods, members)             \
+  UPB_DEFINE_CLASS2(cppname, upb::Def, upb::RefCounted, cppmethods,            \
+                   members)                                                    \
+  UPB_DEF_CASTS(lower, upper, cppname)
+
+#define UPB_DECLARE_DEF_TYPE(cppname, lower, upper) \
+  UPB_DECLARE_DERIVED_TYPE2(cppname, upb::Def, upb::RefCounted, \
+                            upb_ ## lower, upb_def, upb_refcounted) \
+  UPB_DEF_CASTS(lower, upper, cppname)
+
+UPB_DECLARE_DEF_TYPE(upb::FieldDef, fielddef, FIELD)
+UPB_DECLARE_DEF_TYPE(upb::MessageDef, msgdef, MSG)
+UPB_DECLARE_DEF_TYPE(upb::EnumDef, enumdef, ENUM)
+
+#undef UPB_DECLARE_DEF_TYPE
+#undef UPB_DEF_CASTS
+#undef UPB_CPP_CASTS
+
+
+/* upb::FieldDef **************************************************************/
+
+/* The types a field can have.  Note that this list is not identical to the
+ * types defined in descriptor.proto, which gives INT32 and SINT32 separate
+ * types (we distinguish the two with the "integer encoding" enum below). */
+typedef enum {
+  /* Types stored in 1 byte. */
+  UPB_TYPE_BOOL     = 1,
+  /* Types stored in 4 bytes. */
+  UPB_TYPE_FLOAT    = 2,
+  UPB_TYPE_INT32    = 3,
+  UPB_TYPE_UINT32   = 4,
+  UPB_TYPE_ENUM     = 5,  /* Enum values are int32. */
+  /* Types stored as pointers (probably 4 or 8 bytes). */
+  UPB_TYPE_STRING   = 6,
+  UPB_TYPE_BYTES    = 7,
+  UPB_TYPE_MESSAGE  = 8,
+  /* Types stored as 8 bytes. */
+  UPB_TYPE_DOUBLE   = 9,
+  UPB_TYPE_INT64    = 10,
+  UPB_TYPE_UINT64   = 11
+} upb_fieldtype_t;
+
+/* The repeated-ness of each field; this matches descriptor.proto. */
+typedef enum {
+  UPB_LABEL_OPTIONAL = 1,
+  UPB_LABEL_REQUIRED = 2,
+  UPB_LABEL_REPEATED = 3
+} upb_label_t;
+
+/* How integers should be encoded in serializations that offer multiple
+ * integer encoding methods. */
+typedef enum {
+  UPB_INTFMT_VARIABLE = 1,
+  UPB_INTFMT_FIXED = 2,
+  UPB_INTFMT_ZIGZAG = 3   /* Only for signed types (INT32/INT64). */
+} upb_intfmt_t;
+
+/* Descriptor types, as defined in descriptor.proto. */
+typedef enum {
+  UPB_DESCRIPTOR_TYPE_DOUBLE   = 1,
+  UPB_DESCRIPTOR_TYPE_FLOAT    = 2,
+  UPB_DESCRIPTOR_TYPE_INT64    = 3,
+  UPB_DESCRIPTOR_TYPE_UINT64   = 4,
+  UPB_DESCRIPTOR_TYPE_INT32    = 5,
+  UPB_DESCRIPTOR_TYPE_FIXED64  = 6,
+  UPB_DESCRIPTOR_TYPE_FIXED32  = 7,
+  UPB_DESCRIPTOR_TYPE_BOOL     = 8,
+  UPB_DESCRIPTOR_TYPE_STRING   = 9,
+  UPB_DESCRIPTOR_TYPE_GROUP    = 10,
+  UPB_DESCRIPTOR_TYPE_MESSAGE  = 11,
+  UPB_DESCRIPTOR_TYPE_BYTES    = 12,
+  UPB_DESCRIPTOR_TYPE_UINT32   = 13,
+  UPB_DESCRIPTOR_TYPE_ENUM     = 14,
+  UPB_DESCRIPTOR_TYPE_SFIXED32 = 15,
+  UPB_DESCRIPTOR_TYPE_SFIXED64 = 16,
+  UPB_DESCRIPTOR_TYPE_SINT32   = 17,
+  UPB_DESCRIPTOR_TYPE_SINT64   = 18
+} upb_descriptortype_t;
+
+typedef enum {
+  UPB_SYNTAX_PROTO2 = 2,
+  UPB_SYNTAX_PROTO3 = 3
+} upb_syntax_t;
+
+/* Maps descriptor type -> upb field type.  */
+extern const uint8_t upb_desctype_to_fieldtype[];
+
+/* Maximum field number allowed for FieldDefs.  This is an inherent limit of the
+ * protobuf wire format. */
+#define UPB_MAX_FIELDNUMBER ((1 << 29) - 1)
+
+#ifdef __cplusplus
+
+/* A upb_fielddef describes a single field in a message.  It is most often
+ * found as a part of a upb_msgdef, but can also stand alone to represent
+ * an extension.
+ *
+ * Its base class is upb::Def (use upb::upcast() to convert). */
+class upb::FieldDef {
+ public:
+  typedef upb_fieldtype_t Type;
+  typedef upb_label_t Label;
+  typedef upb_intfmt_t IntegerFormat;
+  typedef upb_descriptortype_t DescriptorType;
+
+  /* These return true if the given value is a valid member of the enumeration. */
+  static bool CheckType(int32_t val);
+  static bool CheckLabel(int32_t val);
+  static bool CheckDescriptorType(int32_t val);
+  static bool CheckIntegerFormat(int32_t val);
+
+  /* These convert to the given enumeration; they require that the value is
+   * valid. */
+  static Type ConvertType(int32_t val);
+  static Label ConvertLabel(int32_t val);
+  static DescriptorType ConvertDescriptorType(int32_t val);
+  static IntegerFormat ConvertIntegerFormat(int32_t val);
+
+  /* Returns NULL if memory allocation failed. */
+  static reffed_ptr<FieldDef> New();
+
+  /* upb::RefCounted methods like Ref()/Unref(). */
+  UPB_REFCOUNTED_CPPMETHODS
+
+  /* Functionality from upb::Def. */
+  const char* full_name() const;
+
+  bool type_is_set() const;  /* set_[descriptor_]type() has been called? */
+  Type type() const;         /* Requires that type_is_set() == true. */
+  Label label() const;       /* Defaults to UPB_LABEL_OPTIONAL. */
+  const char* name() const;  /* NULL if uninitialized. */
+  uint32_t number() const;   /* Returns 0 if uninitialized. */
+  bool is_extension() const;
+
+  /* Copies the JSON name for this field into the given buffer.  Returns the
+   * actual size of the JSON name, including the NULL terminator.  If the
+   * return value is 0, the JSON name is unset.  If the return value is
+   * greater than len, the JSON name was truncated.  The buffer is always
+   * NULL-terminated if len > 0.
+   *
+   * The JSON name always defaults to a camelCased version of the regular
+   * name.  However if the regular name is unset, the JSON name will be unset
+   * also.
+   */
+  size_t GetJsonName(char* buf, size_t len) const;
+
+  /* Convenience version of the above function which copies the JSON name
+   * into the given string, returning false if the name is not set. */
+  template <class T>
+  bool GetJsonName(T* str) {
+    str->resize(GetJsonName(NULL, 0));
+    GetJsonName(&(*str)[0], str->size());
+    return str->size() > 0;
+  }
+
+  /* For UPB_TYPE_MESSAGE fields only where is_tag_delimited() == false,
+   * indicates whether this field should have lazy parsing handlers that yield
+   * the unparsed string for the submessage.
+   *
+   * TODO(haberman): I think we want to move this into a FieldOptions container
+   * when we add support for custom options (the FieldOptions struct will
+   * contain both regular FieldOptions like "lazy" *and* custom options). */
+  bool lazy() const;
+
+  /* For non-string, non-submessage fields, this indicates whether binary
+   * protobufs are encoded in packed or non-packed format.
+   *
+   * TODO(haberman): see note above about putting options like this into a
+   * FieldOptions container. */
+  bool packed() const;
+
+  /* An integer that can be used as an index into an array of fields for
+   * whatever message this field belongs to.  Guaranteed to be less than
+   * f->containing_type()->field_count().  May only be accessed once the def has
+   * been finalized. */
+  uint32_t index() const;
+
+  /* The MessageDef to which this field belongs.
+   *
+   * If this field has been added to a MessageDef, that message can be retrieved
+   * directly (this is always the case for frozen FieldDefs).
+   *
+   * If the field has not yet been added to a MessageDef, you can set the name
+   * of the containing type symbolically instead.  This is mostly useful for
+   * extensions, where the extension is declared separately from the message. */
+  const MessageDef* containing_type() const;
+  const char* containing_type_name();
+
+  /* The OneofDef to which this field belongs, or NULL if this field is not part
+   * of a oneof. */
+  const OneofDef* containing_oneof() const;
+
+  /* The field's type according to the enum in descriptor.proto.  This is not
+   * the same as UPB_TYPE_*, because it distinguishes between (for example)
+   * INT32 and SINT32, whereas our "type" enum does not.  This return of
+   * descriptor_type() is a function of type(), integer_format(), and
+   * is_tag_delimited().  Likewise set_descriptor_type() sets all three
+   * appropriately. */
+  DescriptorType descriptor_type() const;
+
+  /* Convenient field type tests. */
+  bool IsSubMessage() const;
+  bool IsString() const;
+  bool IsSequence() const;
+  bool IsPrimitive() const;
+  bool IsMap() const;
+
+  /* Returns whether this field explicitly represents presence.
+   *
+   * For proto2 messages: Returns true for any scalar (non-repeated) field.
+   * For proto3 messages: Returns true for scalar submessage or oneof fields. */
+  bool HasPresence() const;
+
+  /* How integers are encoded.  Only meaningful for integer types.
+   * Defaults to UPB_INTFMT_VARIABLE, and is reset when "type" changes. */
+  IntegerFormat integer_format() const;
+
+  /* Whether a submessage field is tag-delimited or not (if false, then
+   * length-delimited).  May only be set when type() == UPB_TYPE_MESSAGE. */
+  bool is_tag_delimited() const;
+
+  /* Returns the non-string default value for this fielddef, which may either
+   * be something the client set explicitly or the "default default" (0 for
+   * numbers, empty for strings).  The field's type indicates the type of the
+   * returned value, except for enum fields that are still mutable.
+   *
+   * Requires that the given function matches the field's current type. */
+  int64_t default_int64() const;
+  int32_t default_int32() const;
+  uint64_t default_uint64() const;
+  uint32_t default_uint32() const;
+  bool default_bool() const;
+  float default_float() const;
+  double default_double() const;
+
+  /* The resulting string is always NULL-terminated.  If non-NULL, the length
+   * will be stored in *len. */
+  const char *default_string(size_t* len) const;
+
+  /* For frozen UPB_TYPE_ENUM fields, enum defaults can always be read as either
+   * string or int32, and both of these methods will always return true.
+   *
+   * For mutable UPB_TYPE_ENUM fields, the story is a bit more complicated.
+   * Enum defaults are unusual. They can be specified either as string or int32,
+   * but to be valid the enum must have that value as a member.  And if no
+   * default is specified, the "default default" comes from the EnumDef.
+   *
+   * We allow reading the default as either an int32 or a string, but only if
+   * we have a meaningful value to report.  We have a meaningful value if it was
+   * set explicitly, or if we could get the "default default" from the EnumDef.
+   * Also if you explicitly set the name and we find the number in the EnumDef */
+  bool EnumHasStringDefault() const;
+  bool EnumHasInt32Default() const;
+
+  /* Submessage and enum fields must reference a "subdef", which is the
+   * upb::MessageDef or upb::EnumDef that defines their type.  Note that when
+   * the FieldDef is mutable it may not have a subdef *yet*, but this function
+   * still returns true to indicate that the field's type requires a subdef. */
+  bool HasSubDef() const;
+
+  /* Returns the enum or submessage def for this field, if any.  The field's
+   * type must match (ie. you may only call enum_subdef() for fields where
+   * type() == UPB_TYPE_ENUM).  Returns NULL if the subdef has not been set or
+   * is currently set symbolically. */
+  const EnumDef* enum_subdef() const;
+  const MessageDef* message_subdef() const;
+
+  /* Returns the generic subdef for this field.  Requires that HasSubDef() (ie.
+   * only works for UPB_TYPE_ENUM and UPB_TYPE_MESSAGE fields). */
+  const Def* subdef() const;
+
+  /* Returns the symbolic name of the subdef.  If the subdef is currently set
+   * unresolved (ie. set symbolically) returns the symbolic name.  If it has
+   * been resolved to a specific subdef, returns the name from that subdef. */
+  const char* subdef_name() const;
+
+  /* Setters (non-const methods), only valid for mutable FieldDefs! ***********/
+
+  bool set_full_name(const char* fullname, upb::Status* s);
+  bool set_full_name(const std::string& fullname, upb::Status* s);
+
+  /* This may only be called if containing_type() == NULL (ie. the field has not
+   * been added to a message yet). */
+  bool set_containing_type_name(const char *name, Status* status);
+  bool set_containing_type_name(const std::string& name, Status* status);
+
+  /* Defaults to false.  When we freeze, we ensure that this can only be true
+   * for length-delimited message fields.  Prior to freezing this can be true or
+   * false with no restrictions. */
+  void set_lazy(bool lazy);
+
+  /* Defaults to true.  Sets whether this field is encoded in packed format. */
+  void set_packed(bool packed);
+
+  /* "type" or "descriptor_type" MUST be set explicitly before the fielddef is
+   * finalized.  These setters require that the enum value is valid; if the
+   * value did not come directly from an enum constant, the caller should
+   * validate it first with the functions above (CheckFieldType(), etc). */
+  void set_type(Type type);
+  void set_label(Label label);
+  void set_descriptor_type(DescriptorType type);
+  void set_is_extension(bool is_extension);
+
+  /* "number" and "name" must be set before the FieldDef is added to a
+   * MessageDef, and may not be set after that.
+   *
+   * "name" is the same as full_name()/set_full_name(), but since fielddefs
+   * most often use simple, non-qualified names, we provide this accessor
+   * also.  Generally only extensions will want to think of this name as
+   * fully-qualified. */
+  bool set_number(uint32_t number, upb::Status* s);
+  bool set_name(const char* name, upb::Status* s);
+  bool set_name(const std::string& name, upb::Status* s);
+
+  /* Sets the JSON name to the given string. */
+  /* TODO(haberman): implement.  Right now only default json_name (camelCase)
+   * is supported. */
+  bool set_json_name(const char* json_name, upb::Status* s);
+  bool set_json_name(const std::string& name, upb::Status* s);
+
+  /* Clears the JSON name. This will make it revert to its default, which is
+   * a camelCased version of the regular field name. */
+  void clear_json_name();
+
+  void set_integer_format(IntegerFormat format);
+  bool set_tag_delimited(bool tag_delimited, upb::Status* s);
+
+  /* Sets default value for the field.  The call must exactly match the type
+   * of the field.  Enum fields may use either setint32 or setstring to set
+   * the default numerically or symbolically, respectively, but symbolic
+   * defaults must be resolved before finalizing (see ResolveEnumDefault()).
+   *
+   * Changing the type of a field will reset its default. */
+  void set_default_int64(int64_t val);
+  void set_default_int32(int32_t val);
+  void set_default_uint64(uint64_t val);
+  void set_default_uint32(uint32_t val);
+  void set_default_bool(bool val);
+  void set_default_float(float val);
+  void set_default_double(double val);
+  bool set_default_string(const void *str, size_t len, Status *s);
+  bool set_default_string(const std::string &str, Status *s);
+  void set_default_cstr(const char *str, Status *s);
+
+  /* Before a fielddef is frozen, its subdef may be set either directly (with a
+   * upb::Def*) or symbolically.  Symbolic refs must be resolved before the
+   * containing msgdef can be frozen (see upb_resolve() above).  upb always
+   * guarantees that any def reachable from a live def will also be kept alive.
+   *
+   * Both methods require that upb_hassubdef(f) (so the type must be set prior
+   * to calling these methods).  Returns false if this is not the case, or if
+   * the given subdef is not of the correct type.  The subdef is reset if the
+   * field's type is changed.  The subdef can be set to NULL to clear it. */
+  bool set_subdef(const Def* subdef, Status* s);
+  bool set_enum_subdef(const EnumDef* subdef, Status* s);
+  bool set_message_subdef(const MessageDef* subdef, Status* s);
+  bool set_subdef_name(const char* name, Status* s);
+  bool set_subdef_name(const std::string &name, Status* s);
+
+ private:
+  UPB_DISALLOW_POD_OPS(FieldDef, upb::FieldDef)
+};
+
+# endif  /* defined(__cplusplus) */
+
+UPB_BEGIN_EXTERN_C
+
+/* Native C API. */
+upb_fielddef *upb_fielddef_new(const void *owner);
+
+/* Include upb_refcounted methods like upb_fielddef_ref(). */
+UPB_REFCOUNTED_CMETHODS(upb_fielddef, upb_fielddef_upcast2)
+
+/* Methods from upb_def. */
+const char *upb_fielddef_fullname(const upb_fielddef *f);
+bool upb_fielddef_setfullname(upb_fielddef *f, const char *fullname,
+                              upb_status *s);
+
+bool upb_fielddef_typeisset(const upb_fielddef *f);
+upb_fieldtype_t upb_fielddef_type(const upb_fielddef *f);
+upb_descriptortype_t upb_fielddef_descriptortype(const upb_fielddef *f);
+upb_label_t upb_fielddef_label(const upb_fielddef *f);
+uint32_t upb_fielddef_number(const upb_fielddef *f);
+const char *upb_fielddef_name(const upb_fielddef *f);
+bool upb_fielddef_isextension(const upb_fielddef *f);
+bool upb_fielddef_lazy(const upb_fielddef *f);
+bool upb_fielddef_packed(const upb_fielddef *f);
+size_t upb_fielddef_getjsonname(const upb_fielddef *f, char *buf, size_t len);
+const upb_msgdef *upb_fielddef_containingtype(const upb_fielddef *f);
+const upb_oneofdef *upb_fielddef_containingoneof(const upb_fielddef *f);
+upb_msgdef *upb_fielddef_containingtype_mutable(upb_fielddef *f);
+const char *upb_fielddef_containingtypename(upb_fielddef *f);
+upb_intfmt_t upb_fielddef_intfmt(const upb_fielddef *f);
+uint32_t upb_fielddef_index(const upb_fielddef *f);
+bool upb_fielddef_istagdelim(const upb_fielddef *f);
+bool upb_fielddef_issubmsg(const upb_fielddef *f);
+bool upb_fielddef_isstring(const upb_fielddef *f);
+bool upb_fielddef_isseq(const upb_fielddef *f);
+bool upb_fielddef_isprimitive(const upb_fielddef *f);
+bool upb_fielddef_ismap(const upb_fielddef *f);
+bool upb_fielddef_haspresence(const upb_fielddef *f);
+int64_t upb_fielddef_defaultint64(const upb_fielddef *f);
+int32_t upb_fielddef_defaultint32(const upb_fielddef *f);
+uint64_t upb_fielddef_defaultuint64(const upb_fielddef *f);
+uint32_t upb_fielddef_defaultuint32(const upb_fielddef *f);
+bool upb_fielddef_defaultbool(const upb_fielddef *f);
+float upb_fielddef_defaultfloat(const upb_fielddef *f);
+double upb_fielddef_defaultdouble(const upb_fielddef *f);
+const char *upb_fielddef_defaultstr(const upb_fielddef *f, size_t *len);
+bool upb_fielddef_enumhasdefaultint32(const upb_fielddef *f);
+bool upb_fielddef_enumhasdefaultstr(const upb_fielddef *f);
+bool upb_fielddef_hassubdef(const upb_fielddef *f);
+const upb_def *upb_fielddef_subdef(const upb_fielddef *f);
+const upb_msgdef *upb_fielddef_msgsubdef(const upb_fielddef *f);
+const upb_enumdef *upb_fielddef_enumsubdef(const upb_fielddef *f);
+const char *upb_fielddef_subdefname(const upb_fielddef *f);
+
+void upb_fielddef_settype(upb_fielddef *f, upb_fieldtype_t type);
+void upb_fielddef_setdescriptortype(upb_fielddef *f, int type);
+void upb_fielddef_setlabel(upb_fielddef *f, upb_label_t label);
+bool upb_fielddef_setnumber(upb_fielddef *f, uint32_t number, upb_status *s);
+bool upb_fielddef_setname(upb_fielddef *f, const char *name, upb_status *s);
+bool upb_fielddef_setjsonname(upb_fielddef *f, const char *name, upb_status *s);
+bool upb_fielddef_clearjsonname(upb_fielddef *f);
+bool upb_fielddef_setcontainingtypename(upb_fielddef *f, const char *name,
+                                        upb_status *s);
+void upb_fielddef_setisextension(upb_fielddef *f, bool is_extension);
+void upb_fielddef_setlazy(upb_fielddef *f, bool lazy);
+void upb_fielddef_setpacked(upb_fielddef *f, bool packed);
+void upb_fielddef_setintfmt(upb_fielddef *f, upb_intfmt_t fmt);
+void upb_fielddef_settagdelim(upb_fielddef *f, bool tag_delim);
+void upb_fielddef_setdefaultint64(upb_fielddef *f, int64_t val);
+void upb_fielddef_setdefaultint32(upb_fielddef *f, int32_t val);
+void upb_fielddef_setdefaultuint64(upb_fielddef *f, uint64_t val);
+void upb_fielddef_setdefaultuint32(upb_fielddef *f, uint32_t val);
+void upb_fielddef_setdefaultbool(upb_fielddef *f, bool val);
+void upb_fielddef_setdefaultfloat(upb_fielddef *f, float val);
+void upb_fielddef_setdefaultdouble(upb_fielddef *f, double val);
+bool upb_fielddef_setdefaultstr(upb_fielddef *f, const void *str, size_t len,
+                                upb_status *s);
+void upb_fielddef_setdefaultcstr(upb_fielddef *f, const char *str,
+                                 upb_status *s);
+bool upb_fielddef_setsubdef(upb_fielddef *f, const upb_def *subdef,
+                            upb_status *s);
+bool upb_fielddef_setmsgsubdef(upb_fielddef *f, const upb_msgdef *subdef,
+                               upb_status *s);
+bool upb_fielddef_setenumsubdef(upb_fielddef *f, const upb_enumdef *subdef,
+                                upb_status *s);
+bool upb_fielddef_setsubdefname(upb_fielddef *f, const char *name,
+                                upb_status *s);
+
+bool upb_fielddef_checklabel(int32_t label);
+bool upb_fielddef_checktype(int32_t type);
+bool upb_fielddef_checkdescriptortype(int32_t type);
+bool upb_fielddef_checkintfmt(int32_t fmt);
+
+UPB_END_EXTERN_C
+
+
+/* upb::MessageDef ************************************************************/
+
+typedef upb_inttable_iter upb_msg_field_iter;
+typedef upb_strtable_iter upb_msg_oneof_iter;
+
+/* Well-known field tag numbers for map-entry messages. */
+#define UPB_MAPENTRY_KEY   1
+#define UPB_MAPENTRY_VALUE 2
+
+#ifdef __cplusplus
+
+/* Structure that describes a single .proto message type.
+ *
+ * Its base class is upb::Def (use upb::upcast() to convert). */
+class upb::MessageDef {
+ public:
+  /* Returns NULL if memory allocation failed. */
+  static reffed_ptr<MessageDef> New();
+
+  /* upb::RefCounted methods like Ref()/Unref(). */
+  UPB_REFCOUNTED_CPPMETHODS
+
+  /* Functionality from upb::Def. */
+  const char* full_name() const;
+  const char* name() const;
+  bool set_full_name(const char* fullname, Status* s);
+  bool set_full_name(const std::string& fullname, Status* s);
+
+  /* Call to freeze this MessageDef.
+   * WARNING: this will fail if this message has any unfrozen submessages!
+   * Messages with cycles must be frozen as a batch using upb::Def::Freeze(). */
+  bool Freeze(Status* s);
+
+  /* The number of fields that belong to the MessageDef. */
+  int field_count() const;
+
+  /* The number of oneofs that belong to the MessageDef. */
+  int oneof_count() const;
+
+  /* Adds a field (upb_fielddef object) to a msgdef.  Requires that the msgdef
+   * and the fielddefs are mutable.  The fielddef's name and number must be
+   * set, and the message may not already contain any field with this name or
+   * number, and this fielddef may not be part of another message.  In error
+   * cases false is returned and the msgdef is unchanged.
+   *
+   * If the given field is part of a oneof, this call succeeds if and only if
+   * that oneof is already part of this msgdef. (Note that adding a oneof to a
+   * msgdef automatically adds all of its fields to the msgdef at the time that
+   * the oneof is added, so it is usually more idiomatic to add the oneof's
+   * fields first then add the oneof to the msgdef. This case is supported for
+   * convenience.)
+   *
+   * If |f| is already part of this MessageDef, this method performs no action
+   * and returns true (success). Thus, this method is idempotent. */
+  bool AddField(FieldDef* f, Status* s);
+  bool AddField(const reffed_ptr<FieldDef>& f, Status* s);
+
+  /* Adds a oneof (upb_oneofdef object) to a msgdef. Requires that the msgdef,
+   * oneof, and any fielddefs are mutable, that the fielddefs contained in the
+   * oneof do not have any name or number conflicts with existing fields in the
+   * msgdef, and that the oneof's name is unique among all oneofs in the msgdef.
+   * If the oneof is added successfully, all of its fields will be added
+   * directly to the msgdef as well. In error cases, false is returned and the
+   * msgdef is unchanged. */
+  bool AddOneof(OneofDef* o, Status* s);
+  bool AddOneof(const reffed_ptr<OneofDef>& o, Status* s);
+
+  upb_syntax_t syntax() const;
+
+  /* Returns false if we don't support this syntax value. */
+  bool set_syntax(upb_syntax_t syntax);
+
+  /* Set this to false to indicate that primitive fields should not have
+   * explicit presence information associated with them.  This will affect all
+   * fields added to this message.  Defaults to true. */
+  void SetPrimitivesHavePresence(bool have_presence);
+
+  /* These return NULL if the field is not found. */
+  FieldDef* FindFieldByNumber(uint32_t number);
+  FieldDef* FindFieldByName(const char *name, size_t len);
+  const FieldDef* FindFieldByNumber(uint32_t number) const;
+  const FieldDef* FindFieldByName(const char* name, size_t len) const;
+
+
+  FieldDef* FindFieldByName(const char *name) {
+    return FindFieldByName(name, strlen(name));
+  }
+  const FieldDef* FindFieldByName(const char *name) const {
+    return FindFieldByName(name, strlen(name));
+  }
+
+  template <class T>
+  FieldDef* FindFieldByName(const T& str) {
+    return FindFieldByName(str.c_str(), str.size());
+  }
+  template <class T>
+  const FieldDef* FindFieldByName(const T& str) const {
+    return FindFieldByName(str.c_str(), str.size());
+  }
+
+  OneofDef* FindOneofByName(const char* name, size_t len);
+  const OneofDef* FindOneofByName(const char* name, size_t len) const;
+
+  OneofDef* FindOneofByName(const char* name) {
+    return FindOneofByName(name, strlen(name));
+  }
+  const OneofDef* FindOneofByName(const char* name) const {
+    return FindOneofByName(name, strlen(name));
+  }
+
+  template<class T>
+  OneofDef* FindOneofByName(const T& str) {
+    return FindOneofByName(str.c_str(), str.size());
+  }
+  template<class T>
+  const OneofDef* FindOneofByName(const T& str) const {
+    return FindOneofByName(str.c_str(), str.size());
+  }
+
+  /* Is this message a map entry? */
+  void setmapentry(bool map_entry);
+  bool mapentry() const;
+
+  /* Iteration over fields.  The order is undefined. */
+  class field_iterator
+      : public std::iterator<std::forward_iterator_tag, FieldDef*> {
+   public:
+    explicit field_iterator(MessageDef* md);
+    static field_iterator end(MessageDef* md);
+
+    void operator++();
+    FieldDef* operator*() const;
+    bool operator!=(const field_iterator& other) const;
+    bool operator==(const field_iterator& other) const;
+
+   private:
+    upb_msg_field_iter iter_;
+  };
+
+  class const_field_iterator
+      : public std::iterator<std::forward_iterator_tag, const FieldDef*> {
+   public:
+    explicit const_field_iterator(const MessageDef* md);
+    static const_field_iterator end(const MessageDef* md);
+
+    void operator++();
+    const FieldDef* operator*() const;
+    bool operator!=(const const_field_iterator& other) const;
+    bool operator==(const const_field_iterator& other) const;
+
+   private:
+    upb_msg_field_iter iter_;
+  };
+
+  /* Iteration over oneofs. The order is undefined. */
+  class oneof_iterator
+      : public std::iterator<std::forward_iterator_tag, FieldDef*> {
+   public:
+    explicit oneof_iterator(MessageDef* md);
+    static oneof_iterator end(MessageDef* md);
+
+    void operator++();
+    OneofDef* operator*() const;
+    bool operator!=(const oneof_iterator& other) const;
+    bool operator==(const oneof_iterator& other) const;
+
+   private:
+    upb_msg_oneof_iter iter_;
+  };
+
+  class const_oneof_iterator
+      : public std::iterator<std::forward_iterator_tag, const FieldDef*> {
+   public:
+    explicit const_oneof_iterator(const MessageDef* md);
+    static const_oneof_iterator end(const MessageDef* md);
+
+    void operator++();
+    const OneofDef* operator*() const;
+    bool operator!=(const const_oneof_iterator& other) const;
+    bool operator==(const const_oneof_iterator& other) const;
+
+   private:
+    upb_msg_oneof_iter iter_;
+  };
+
+  class FieldAccessor {
+   public:
+    explicit FieldAccessor(MessageDef* msg) : msg_(msg) {}
+    field_iterator begin() { return msg_->field_begin(); }
+    field_iterator end() { return msg_->field_end(); }
+   private:
+    MessageDef* msg_;
+  };
+
+  class ConstFieldAccessor {
+   public:
+    explicit ConstFieldAccessor(const MessageDef* msg) : msg_(msg) {}
+    const_field_iterator begin() { return msg_->field_begin(); }
+    const_field_iterator end() { return msg_->field_end(); }
+   private:
+    const MessageDef* msg_;
+  };
+
+  class OneofAccessor {
+   public:
+    explicit OneofAccessor(MessageDef* msg) : msg_(msg) {}
+    oneof_iterator begin() { return msg_->oneof_begin(); }
+    oneof_iterator end() { return msg_->oneof_end(); }
+   private:
+    MessageDef* msg_;
+  };
+
+  class ConstOneofAccessor {
+   public:
+    explicit ConstOneofAccessor(const MessageDef* msg) : msg_(msg) {}
+    const_oneof_iterator begin() { return msg_->oneof_begin(); }
+    const_oneof_iterator end() { return msg_->oneof_end(); }
+   private:
+    const MessageDef* msg_;
+  };
+
+  field_iterator field_begin();
+  field_iterator field_end();
+  const_field_iterator field_begin() const;
+  const_field_iterator field_end() const;
+
+  oneof_iterator oneof_begin();
+  oneof_iterator oneof_end();
+  const_oneof_iterator oneof_begin() const;
+  const_oneof_iterator oneof_end() const;
+
+  FieldAccessor fields() { return FieldAccessor(this); }
+  ConstFieldAccessor fields() const { return ConstFieldAccessor(this); }
+  OneofAccessor oneofs() { return OneofAccessor(this); }
+  ConstOneofAccessor oneofs() const { return ConstOneofAccessor(this); }
+
+ private:
+  UPB_DISALLOW_POD_OPS(MessageDef, upb::MessageDef)
+};
+
+#endif  /* __cplusplus */
+
+UPB_BEGIN_EXTERN_C
+
+/* Returns NULL if memory allocation failed. */
+upb_msgdef *upb_msgdef_new(const void *owner);
+
+/* Include upb_refcounted methods like upb_msgdef_ref(). */
+UPB_REFCOUNTED_CMETHODS(upb_msgdef, upb_msgdef_upcast2)
+
+bool upb_msgdef_freeze(upb_msgdef *m, upb_status *status);
+
+const char *upb_msgdef_fullname(const upb_msgdef *m);
+const char *upb_msgdef_name(const upb_msgdef *m);
+int upb_msgdef_numoneofs(const upb_msgdef *m);
+upb_syntax_t upb_msgdef_syntax(const upb_msgdef *m);
+
+bool upb_msgdef_addfield(upb_msgdef *m, upb_fielddef *f, const void *ref_donor,
+                         upb_status *s);
+bool upb_msgdef_addoneof(upb_msgdef *m, upb_oneofdef *o, const void *ref_donor,
+                         upb_status *s);
+bool upb_msgdef_setfullname(upb_msgdef *m, const char *fullname, upb_status *s);
+void upb_msgdef_setmapentry(upb_msgdef *m, bool map_entry);
+bool upb_msgdef_mapentry(const upb_msgdef *m);
+bool upb_msgdef_setsyntax(upb_msgdef *m, upb_syntax_t syntax);
+
+/* Field lookup in a couple of different variations:
+ *   - itof = int to field
+ *   - ntof = name to field
+ *   - ntofz = name to field, null-terminated string. */
+const upb_fielddef *upb_msgdef_itof(const upb_msgdef *m, uint32_t i);
+const upb_fielddef *upb_msgdef_ntof(const upb_msgdef *m, const char *name,
+                                    size_t len);
+int upb_msgdef_numfields(const upb_msgdef *m);
+
+UPB_INLINE const upb_fielddef *upb_msgdef_ntofz(const upb_msgdef *m,
+                                                const char *name) {
+  return upb_msgdef_ntof(m, name, strlen(name));
+}
+
+UPB_INLINE upb_fielddef *upb_msgdef_itof_mutable(upb_msgdef *m, uint32_t i) {
+  return (upb_fielddef*)upb_msgdef_itof(m, i);
+}
+
+UPB_INLINE upb_fielddef *upb_msgdef_ntof_mutable(upb_msgdef *m,
+                                                 const char *name, size_t len) {
+  return (upb_fielddef *)upb_msgdef_ntof(m, name, len);
+}
+
+/* Oneof lookup:
+ *   - ntoo = name to oneof
+ *   - ntooz = name to oneof, null-terminated string. */
+const upb_oneofdef *upb_msgdef_ntoo(const upb_msgdef *m, const char *name,
+                                    size_t len);
+int upb_msgdef_numoneofs(const upb_msgdef *m);
+
+UPB_INLINE const upb_oneofdef *upb_msgdef_ntooz(const upb_msgdef *m,
+                                               const char *name) {
+  return upb_msgdef_ntoo(m, name, strlen(name));
+}
+
+UPB_INLINE upb_oneofdef *upb_msgdef_ntoo_mutable(upb_msgdef *m,
+                                                 const char *name, size_t len) {
+  return (upb_oneofdef *)upb_msgdef_ntoo(m, name, len);
+}
+
+/* Lookup of either field or oneof by name.  Returns whether either was found.
+ * If the return is true, then the found def will be set, and the non-found
+ * one set to NULL. */
+bool upb_msgdef_lookupname(const upb_msgdef *m, const char *name, size_t len,
+                           const upb_fielddef **f, const upb_oneofdef **o);
+
+UPB_INLINE bool upb_msgdef_lookupnamez(const upb_msgdef *m, const char *name,
+                                       const upb_fielddef **f,
+                                       const upb_oneofdef **o) {
+  return upb_msgdef_lookupname(m, name, strlen(name), f, o);
+}
+
+/* Iteration over fields and oneofs.  For example:
+ *
+ * upb_msg_field_iter i;
+ * for(upb_msg_field_begin(&i, m);
+ *     !upb_msg_field_done(&i);
+ *     upb_msg_field_next(&i)) {
+ *   upb_fielddef *f = upb_msg_iter_field(&i);
+ *   // ...
+ * }
+ *
+ * For C we don't have separate iterators for const and non-const.
+ * It is the caller's responsibility to cast the upb_fielddef* to
+ * const if the upb_msgdef* is const. */
+void upb_msg_field_begin(upb_msg_field_iter *iter, const upb_msgdef *m);
+void upb_msg_field_next(upb_msg_field_iter *iter);
+bool upb_msg_field_done(const upb_msg_field_iter *iter);
+upb_fielddef *upb_msg_iter_field(const upb_msg_field_iter *iter);
+void upb_msg_field_iter_setdone(upb_msg_field_iter *iter);
+
+/* Similar to above, we also support iterating through the oneofs in a
+ * msgdef. */
+void upb_msg_oneof_begin(upb_msg_oneof_iter *iter, const upb_msgdef *m);
+void upb_msg_oneof_next(upb_msg_oneof_iter *iter);
+bool upb_msg_oneof_done(const upb_msg_oneof_iter *iter);
+upb_oneofdef *upb_msg_iter_oneof(const upb_msg_oneof_iter *iter);
+void upb_msg_oneof_iter_setdone(upb_msg_oneof_iter *iter);
+
+UPB_END_EXTERN_C
+
+
+/* upb::EnumDef ***************************************************************/
+
+typedef upb_strtable_iter upb_enum_iter;
+
+#ifdef __cplusplus
+
+/* Class that represents an enum.  Its base class is upb::Def (convert with
+ * upb::upcast()). */
+class upb::EnumDef {
+ public:
+  /* Returns NULL if memory allocation failed. */
+  static reffed_ptr<EnumDef> New();
+
+  /* upb::RefCounted methods like Ref()/Unref(). */
+  UPB_REFCOUNTED_CPPMETHODS
+
+  /* Functionality from upb::Def. */
+  const char* full_name() const;
+  const char* name() const;
+  bool set_full_name(const char* fullname, Status* s);
+  bool set_full_name(const std::string& fullname, Status* s);
+
+  /* Call to freeze this EnumDef. */
+  bool Freeze(Status* s);
+
+  /* The value that is used as the default when no field default is specified.
+   * If not set explicitly, the first value that was added will be used.
+   * The default value must be a member of the enum.
+   * Requires that value_count() > 0. */
+  int32_t default_value() const;
+
+  /* Sets the default value.  If this value is not valid, returns false and an
+   * error message in status. */
+  bool set_default_value(int32_t val, Status* status);
+
+  /* Returns the number of values currently defined in the enum.  Note that
+   * multiple names can refer to the same number, so this may be greater than
+   * the total number of unique numbers. */
+  int value_count() const;
+
+  /* Adds a single name/number pair to the enum.  Fails if this name has
+   * already been used by another value. */
+  bool AddValue(const char* name, int32_t num, Status* status);
+  bool AddValue(const std::string& name, int32_t num, Status* status);
+
+  /* Lookups from name to integer, returning true if found. */
+  bool FindValueByName(const char* name, int32_t* num) const;
+
+  /* Finds the name corresponding to the given number, or NULL if none was
+   * found.  If more than one name corresponds to this number, returns the
+   * first one that was added. */
+  const char* FindValueByNumber(int32_t num) const;
+
+  /* Iteration over name/value pairs.  The order is undefined.
+   * Adding an enum val invalidates any iterators.
+   *
+   * TODO: make compatible with range-for, with elements as pairs? */
+  class Iterator {
+   public:
+    explicit Iterator(const EnumDef*);
+
+    int32_t number();
+    const char *name();
+    bool Done();
+    void Next();
+
+   private:
+    upb_enum_iter iter_;
+  };
+
+ private:
+  UPB_DISALLOW_POD_OPS(EnumDef, upb::EnumDef)
+};
+
+#endif  /* __cplusplus */
+
+UPB_BEGIN_EXTERN_C
+
+/* Native C API. */
+upb_enumdef *upb_enumdef_new(const void *owner);
+
+/* Include upb_refcounted methods like upb_enumdef_ref(). */
+UPB_REFCOUNTED_CMETHODS(upb_enumdef, upb_enumdef_upcast2)
+
+bool upb_enumdef_freeze(upb_enumdef *e, upb_status *status);
+
+/* From upb_def. */
+const char *upb_enumdef_fullname(const upb_enumdef *e);
+const char *upb_enumdef_name(const upb_enumdef *e);
+bool upb_enumdef_setfullname(upb_enumdef *e, const char *fullname,
+                             upb_status *s);
+
+int32_t upb_enumdef_default(const upb_enumdef *e);
+bool upb_enumdef_setdefault(upb_enumdef *e, int32_t val, upb_status *s);
+int upb_enumdef_numvals(const upb_enumdef *e);
+bool upb_enumdef_addval(upb_enumdef *e, const char *name, int32_t num,
+                        upb_status *status);
+
+/* Enum lookups:
+ * - ntoi:  look up a name with specified length.
+ * - ntoiz: look up a name provided as a null-terminated string.
+ * - iton:  look up an integer, returning the name as a null-terminated
+ *          string. */
+bool upb_enumdef_ntoi(const upb_enumdef *e, const char *name, size_t len,
+                      int32_t *num);
+UPB_INLINE bool upb_enumdef_ntoiz(const upb_enumdef *e,
+                                  const char *name, int32_t *num) {
+  return upb_enumdef_ntoi(e, name, strlen(name), num);
+}
+const char *upb_enumdef_iton(const upb_enumdef *e, int32_t num);
+
+/*  upb_enum_iter i;
+ *  for(upb_enum_begin(&i, e); !upb_enum_done(&i); upb_enum_next(&i)) {
+ *    // ...
+ *  }
+ */
+void upb_enum_begin(upb_enum_iter *iter, const upb_enumdef *e);
+void upb_enum_next(upb_enum_iter *iter);
+bool upb_enum_done(upb_enum_iter *iter);
+const char *upb_enum_iter_name(upb_enum_iter *iter);
+int32_t upb_enum_iter_number(upb_enum_iter *iter);
+
+UPB_END_EXTERN_C
+
+
+/* upb::OneofDef **************************************************************/
+
+typedef upb_inttable_iter upb_oneof_iter;
+
+#ifdef __cplusplus
+
+/* Class that represents a oneof. */
+class upb::OneofDef {
+ public:
+  /* Returns NULL if memory allocation failed. */
+  static reffed_ptr<OneofDef> New();
+
+  /* upb::RefCounted methods like Ref()/Unref(). */
+  UPB_REFCOUNTED_CPPMETHODS
+
+  /* Returns the MessageDef that owns this OneofDef. */
+  const MessageDef* containing_type() const;
+
+  /* Returns the name of this oneof. This is the name used to look up the oneof
+   * by name once added to a message def. */
+  const char* name() const;
+  bool set_name(const char* name, Status* s);
+  bool set_name(const std::string& name, Status* s);
+
+  /* Returns the number of fields currently defined in the oneof. */
+  int field_count() const;
+
+  /* Adds a field to the oneof. The field must not have been added to any other
+   * oneof or msgdef. If the oneof is not yet part of a msgdef, then when the
+   * oneof is eventually added to a msgdef, all fields added to the oneof will
+   * also be added to the msgdef at that time. If the oneof is already part of a
+   * msgdef, the field must either be a part of that msgdef already, or must not
+   * be a part of any msgdef; in the latter case, the field is added to the
+   * msgdef as a part of this operation.
+   *
+   * The field may only have an OPTIONAL label, never REQUIRED or REPEATED.
+   *
+   * If |f| is already part of this MessageDef, this method performs no action
+   * and returns true (success). Thus, this method is idempotent. */
+  bool AddField(FieldDef* field, Status* s);
+  bool AddField(const reffed_ptr<FieldDef>& field, Status* s);
+
+  /* Looks up by name. */
+  const FieldDef* FindFieldByName(const char* name, size_t len) const;
+  FieldDef* FindFieldByName(const char* name, size_t len);
+  const FieldDef* FindFieldByName(const char* name) const {
+    return FindFieldByName(name, strlen(name));
+  }
+  FieldDef* FindFieldByName(const char* name) {
+    return FindFieldByName(name, strlen(name));
+  }
+
+  template <class T>
+  FieldDef* FindFieldByName(const T& str) {
+    return FindFieldByName(str.c_str(), str.size());
+  }
+  template <class T>
+  const FieldDef* FindFieldByName(const T& str) const {
+    return FindFieldByName(str.c_str(), str.size());
+  }
+
+  /* Looks up by tag number. */
+  const FieldDef* FindFieldByNumber(uint32_t num) const;
+
+  /* Iteration over fields.  The order is undefined. */
+  class iterator : public std::iterator<std::forward_iterator_tag, FieldDef*> {
+   public:
+    explicit iterator(OneofDef* md);
+    static iterator end(OneofDef* md);
+
+    void operator++();
+    FieldDef* operator*() const;
+    bool operator!=(const iterator& other) const;
+    bool operator==(const iterator& other) const;
+
+   private:
+    upb_oneof_iter iter_;
+  };
+
+  class const_iterator
+      : public std::iterator<std::forward_iterator_tag, const FieldDef*> {
+   public:
+    explicit const_iterator(const OneofDef* md);
+    static const_iterator end(const OneofDef* md);
+
+    void operator++();
+    const FieldDef* operator*() const;
+    bool operator!=(const const_iterator& other) const;
+    bool operator==(const const_iterator& other) const;
+
+   private:
+    upb_oneof_iter iter_;
+  };
+
+  iterator begin();
+  iterator end();
+  const_iterator begin() const;
+  const_iterator end() const;
+
+ private:
+  UPB_DISALLOW_POD_OPS(OneofDef, upb::OneofDef)
+};
+
+#endif  /* __cplusplus */
+
+UPB_BEGIN_EXTERN_C
+
+/* Native C API. */
+upb_oneofdef *upb_oneofdef_new(const void *owner);
+
+/* Include upb_refcounted methods like upb_oneofdef_ref(). */
+UPB_REFCOUNTED_CMETHODS(upb_oneofdef, upb_oneofdef_upcast)
+
+const char *upb_oneofdef_name(const upb_oneofdef *o);
+const upb_msgdef *upb_oneofdef_containingtype(const upb_oneofdef *o);
+int upb_oneofdef_numfields(const upb_oneofdef *o);
+uint32_t upb_oneofdef_index(const upb_oneofdef *o);
+
+bool upb_oneofdef_setname(upb_oneofdef *o, const char *name, upb_status *s);
+bool upb_oneofdef_addfield(upb_oneofdef *o, upb_fielddef *f,
+                           const void *ref_donor,
+                           upb_status *s);
+
+/* Oneof lookups:
+ * - ntof:  look up a field by name.
+ * - ntofz: look up a field by name (as a null-terminated string).
+ * - itof:  look up a field by number. */
+const upb_fielddef *upb_oneofdef_ntof(const upb_oneofdef *o,
+                                      const char *name, size_t length);
+UPB_INLINE const upb_fielddef *upb_oneofdef_ntofz(const upb_oneofdef *o,
+                                                  const char *name) {
+  return upb_oneofdef_ntof(o, name, strlen(name));
+}
+const upb_fielddef *upb_oneofdef_itof(const upb_oneofdef *o, uint32_t num);
+
+/*  upb_oneof_iter i;
+ *  for(upb_oneof_begin(&i, e); !upb_oneof_done(&i); upb_oneof_next(&i)) {
+ *    // ...
+ *  }
+ */
+void upb_oneof_begin(upb_oneof_iter *iter, const upb_oneofdef *o);
+void upb_oneof_next(upb_oneof_iter *iter);
+bool upb_oneof_done(upb_oneof_iter *iter);
+upb_fielddef *upb_oneof_iter_field(const upb_oneof_iter *iter);
+void upb_oneof_iter_setdone(upb_oneof_iter *iter);
+
+UPB_END_EXTERN_C
+
+
+/* upb::FileDef ***************************************************************/
+
+#ifdef __cplusplus
+
+/* Class that represents a .proto file with some things defined in it.
+ *
+ * Many users won't care about FileDefs, but they are necessary if you want to
+ * read the values of file-level options. */
+class upb::FileDef {
+ public:
+  /* Returns NULL if memory allocation failed. */
+  static reffed_ptr<FileDef> New();
+
+  /* upb::RefCounted methods like Ref()/Unref(). */
+  UPB_REFCOUNTED_CPPMETHODS
+
+  /* Get/set name of the file (eg. "foo/bar.proto"). */
+  const char* name() const;
+  bool set_name(const char* name, Status* s);
+  bool set_name(const std::string& name, Status* s);
+
+  /* Package name for definitions inside the file (eg. "foo.bar"). */
+  const char* package() const;
+  bool set_package(const char* package, Status* s);
+
+  /* Sets the php class prefix which is prepended to all php generated classes
+   * from this .proto. Default is empty. */
+  const char* phpprefix() const;
+  bool set_phpprefix(const char* phpprefix, Status* s);
+
+  /* Use this option to change the namespace of php generated classes. Default
+   * is empty. When this option is empty, the package name will be used for
+   * determining the namespace. */
+  const char* phpnamespace() const;
+  bool set_phpnamespace(const char* phpnamespace, Status* s);
+
+  /* Syntax for the file.  Defaults to proto2. */
+  upb_syntax_t syntax() const;
+  void set_syntax(upb_syntax_t syntax);
+
+  /* Get the list of defs from the file.  These are returned in the order that
+   * they were added to the FileDef. */
+  int def_count() const;
+  const Def* def(int index) const;
+  Def* def(int index);
+
+  /* Get the list of dependencies from the file.  These are returned in the
+   * order that they were added to the FileDef. */
+  int dependency_count() const;
+  const FileDef* dependency(int index) const;
+
+  /* Adds defs to this file.  The def must not already belong to another
+   * file.
+   *
+   * Note: this does *not* ensure that this def's name is unique in this file!
+   * Use a SymbolTable if you want to check this property.  Especially since
+   * properly checking uniqueness would require a check across *all* files
+   * (including dependencies). */
+  bool AddDef(Def* def, Status* s);
+  bool AddMessage(MessageDef* m, Status* s);
+  bool AddEnum(EnumDef* e, Status* s);
+  bool AddExtension(FieldDef* f, Status* s);
+
+  /* Adds a dependency of this file. */
+  bool AddDependency(const FileDef* file);
+
+  /* Freezes this FileDef and all messages/enums under it.  All subdefs must be
+   * resolved and all messages/enums must validate.  Returns true if this
+   * succeeded.
+   *
+   * TODO(haberman): should we care whether the file's dependencies are frozen
+   * already? */
+  bool Freeze(Status* s);
+
+ private:
+  UPB_DISALLOW_POD_OPS(FileDef, upb::FileDef)
+};
+
+#endif
+
+UPB_BEGIN_EXTERN_C
+
+upb_filedef *upb_filedef_new(const void *owner);
+
+/* Include upb_refcounted methods like upb_msgdef_ref(). */
+UPB_REFCOUNTED_CMETHODS(upb_filedef, upb_filedef_upcast)
+
+const char *upb_filedef_name(const upb_filedef *f);
+const char *upb_filedef_package(const upb_filedef *f);
+const char *upb_filedef_phpprefix(const upb_filedef *f);
+const char *upb_filedef_phpnamespace(const upb_filedef *f);
+upb_syntax_t upb_filedef_syntax(const upb_filedef *f);
+size_t upb_filedef_defcount(const upb_filedef *f);
+size_t upb_filedef_depcount(const upb_filedef *f);
+const upb_def *upb_filedef_def(const upb_filedef *f, size_t i);
+const upb_filedef *upb_filedef_dep(const upb_filedef *f, size_t i);
+
+bool upb_filedef_freeze(upb_filedef *f, upb_status *s);
+bool upb_filedef_setname(upb_filedef *f, const char *name, upb_status *s);
+bool upb_filedef_setpackage(upb_filedef *f, const char *package, upb_status *s);
+bool upb_filedef_setphpprefix(upb_filedef *f, const char *phpprefix,
+                              upb_status *s);
+bool upb_filedef_setphpnamespace(upb_filedef *f, const char *phpnamespace,
+                                 upb_status *s);
+bool upb_filedef_setsyntax(upb_filedef *f, upb_syntax_t syntax, upb_status *s);
+
+bool upb_filedef_adddef(upb_filedef *f, upb_def *def, const void *ref_donor,
+                        upb_status *s);
+bool upb_filedef_adddep(upb_filedef *f, const upb_filedef *dep);
+
+UPB_INLINE bool upb_filedef_addmsg(upb_filedef *f, upb_msgdef *m,
+                                   const void *ref_donor, upb_status *s) {
+  return upb_filedef_adddef(f, upb_msgdef_upcast_mutable(m), ref_donor, s);
+}
+
+UPB_INLINE bool upb_filedef_addenum(upb_filedef *f, upb_enumdef *e,
+                                    const void *ref_donor, upb_status *s) {
+  return upb_filedef_adddef(f, upb_enumdef_upcast_mutable(e), ref_donor, s);
+}
+
+UPB_INLINE bool upb_filedef_addext(upb_filedef *file, upb_fielddef *f,
+                                   const void *ref_donor, upb_status *s) {
+  return upb_filedef_adddef(file, upb_fielddef_upcast_mutable(f), ref_donor, s);
+}
+UPB_INLINE upb_def *upb_filedef_mutabledef(upb_filedef *f, int i) {
+  return (upb_def*)upb_filedef_def(f, i);
+}
+
+UPB_END_EXTERN_C
+
+typedef struct {
+ UPB_PRIVATE_FOR_CPP
+  upb_strtable_iter iter;
+  upb_deftype_t type;
+} upb_symtab_iter;
+
+#ifdef __cplusplus
+
+/* Non-const methods in upb::SymbolTable are NOT thread-safe. */
+class upb::SymbolTable {
+ public:
+  /* Returns a new symbol table with a single ref owned by "owner."
+   * Returns NULL if memory allocation failed. */
+  static SymbolTable* New();
+  static void Free(upb::SymbolTable* table);
+
+  /* For all lookup functions, the returned pointer is not owned by the
+   * caller; it may be invalidated by any non-const call or unref of the
+   * SymbolTable!  To protect against this, take a ref if desired. */
+
+  /* Freezes the symbol table: prevents further modification of it.
+   * After the Freeze() operation is successful, the SymbolTable must only be
+   * accessed via a const pointer.
+   *
+   * Unlike with upb::MessageDef/upb::EnumDef/etc, freezing a SymbolTable is not
+   * a necessary step in using a SymbolTable.  If you have no need for it to be
+   * immutable, there is no need to freeze it ever.  However sometimes it is
+   * useful, and SymbolTables that are statically compiled into the binary are
+   * always frozen by nature. */
+  void Freeze();
+
+  /* Resolves the given symbol using the rules described in descriptor.proto,
+   * namely:
+   *
+   *    If the name starts with a '.', it is fully-qualified.  Otherwise,
+   *    C++-like scoping rules are used to find the type (i.e. first the nested
+   *    types within this message are searched, then within the parent, on up
+   *    to the root namespace).
+   *
+   * If not found, returns NULL. */
+  const Def* Resolve(const char* base, const char* sym) const;
+
+  /* Finds an entry in the symbol table with this exact name.  If not found,
+   * returns NULL. */
+  const Def* Lookup(const char *sym) const;
+  const MessageDef* LookupMessage(const char *sym) const;
+  const EnumDef* LookupEnum(const char *sym) const;
+
+  /* TODO: introduce a C++ iterator, but make it nice and templated so that if
+   * you ask for an iterator of MessageDef the iterated elements are strongly
+   * typed as MessageDef*. */
+
+  /* Adds the given mutable defs to the symtab, resolving all symbols (including
+   * enum default values) and finalizing the defs.  Only one def per name may be
+   * in the list, and the defs may not duplicate any name already in the symtab.
+   * All defs must have a name -- anonymous defs are not allowed.  Anonymous
+   * defs can still be frozen by calling upb_def_freeze() directly.
+   *
+   * The entire operation either succeeds or fails.  If the operation fails,
+   * the symtab is unchanged, false is returned, and status indicates the
+   * error.  The caller passes a ref on all defs to the symtab (even if the
+   * operation fails).
+   *
+   * TODO(haberman): currently failure will leave the symtab unchanged, but may
+   * leave the defs themselves partially resolved.  Does this matter?  If so we
+   * could do a prepass that ensures that all symbols are resolvable and bail
+   * if not, so we don't mutate anything until we know the operation will
+   * succeed. */
+  bool Add(Def*const* defs, size_t n, void* ref_donor, Status* status);
+
+  bool Add(const std::vector<Def*>& defs, void *owner, Status* status) {
+    return Add((Def*const*)&defs[0], defs.size(), owner, status);
+  }
+
+  /* Resolves all subdefs for messages in this file and attempts to freeze the
+   * file.  If this succeeds, adds all the symbols to this SymbolTable
+   * (replacing any existing ones with the same names). */
+  bool AddFile(FileDef* file, Status* s);
+
+ private:
+  UPB_DISALLOW_POD_OPS(SymbolTable, upb::SymbolTable)
+};
+
+#endif  /* __cplusplus */
+
+UPB_BEGIN_EXTERN_C
+
+/* Native C API. */
+
+upb_symtab *upb_symtab_new();
+void upb_symtab_free(upb_symtab* s);
+const upb_def *upb_symtab_resolve(const upb_symtab *s, const char *base,
+                                  const char *sym);
+const upb_def *upb_symtab_lookup(const upb_symtab *s, const char *sym);
+const upb_msgdef *upb_symtab_lookupmsg(const upb_symtab *s, const char *sym);
+const upb_enumdef *upb_symtab_lookupenum(const upb_symtab *s, const char *sym);
+bool upb_symtab_add(upb_symtab *s, upb_def *const*defs, size_t n,
+                    void *ref_donor, upb_status *status);
+bool upb_symtab_addfile(upb_symtab *s, upb_filedef *file, upb_status* status);
+
+/* upb_symtab_iter i;
+ * for(upb_symtab_begin(&i, s, type); !upb_symtab_done(&i);
+ *     upb_symtab_next(&i)) {
+ *   const upb_def *def = upb_symtab_iter_def(&i);
+ *    // ...
+ * }
+ *
+ * For C we don't have separate iterators for const and non-const.
+ * It is the caller's responsibility to cast the upb_fielddef* to
+ * const if the upb_msgdef* is const. */
+void upb_symtab_begin(upb_symtab_iter *iter, const upb_symtab *s,
+                      upb_deftype_t type);
+void upb_symtab_next(upb_symtab_iter *iter);
+bool upb_symtab_done(const upb_symtab_iter *iter);
+const upb_def *upb_symtab_iter_def(const upb_symtab_iter *iter);
+
+UPB_END_EXTERN_C
+
+#ifdef __cplusplus
+/* C++ inline wrappers. */
+namespace upb {
+inline SymbolTable* SymbolTable::New() {
+  return upb_symtab_new();
+}
+inline void SymbolTable::Free(SymbolTable* s) {
+  upb_symtab_free(s);
+}
+inline const Def *SymbolTable::Resolve(const char *base,
+                                       const char *sym) const {
+  return upb_symtab_resolve(this, base, sym);
+}
+inline const Def* SymbolTable::Lookup(const char *sym) const {
+  return upb_symtab_lookup(this, sym);
+}
+inline const MessageDef *SymbolTable::LookupMessage(const char *sym) const {
+  return upb_symtab_lookupmsg(this, sym);
+}
+inline bool SymbolTable::Add(
+    Def*const* defs, size_t n, void* ref_donor, Status* status) {
+  return upb_symtab_add(this, (upb_def*const*)defs, n, ref_donor, status);
+}
+inline bool SymbolTable::AddFile(FileDef* file, Status* s) {
+  return upb_symtab_addfile(this, file, s);
+}
+}  /* namespace upb */
+#endif
+
+#ifdef __cplusplus
+
+UPB_INLINE const char* upb_safecstr(const std::string& str) {
+  UPB_ASSERT(str.size() == std::strlen(str.c_str()));
+  return str.c_str();
+}
+
+/* Inline C++ wrappers. */
+namespace upb {
+
+inline Def::Type Def::def_type() const { return upb_def_type(this); }
+inline const char* Def::full_name() const { return upb_def_fullname(this); }
+inline const char* Def::name() const { return upb_def_name(this); }
+inline bool Def::set_full_name(const char* fullname, Status* s) {
+  return upb_def_setfullname(this, fullname, s);
+}
+inline bool Def::set_full_name(const std::string& fullname, Status* s) {
+  return upb_def_setfullname(this, upb_safecstr(fullname), s);
+}
+inline bool Def::Freeze(Def* const* defs, size_t n, Status* status) {
+  return upb_def_freeze(defs, n, status);
+}
+inline bool Def::Freeze(const std::vector<Def*>& defs, Status* status) {
+  return upb_def_freeze((Def* const*)&defs[0], defs.size(), status);
+}
+
+inline bool FieldDef::CheckType(int32_t val) {
+  return upb_fielddef_checktype(val);
+}
+inline bool FieldDef::CheckLabel(int32_t val) {
+  return upb_fielddef_checklabel(val);
+}
+inline bool FieldDef::CheckDescriptorType(int32_t val) {
+  return upb_fielddef_checkdescriptortype(val);
+}
+inline bool FieldDef::CheckIntegerFormat(int32_t val) {
+  return upb_fielddef_checkintfmt(val);
+}
+inline FieldDef::Type FieldDef::ConvertType(int32_t val) {
+  UPB_ASSERT(CheckType(val));
+  return static_cast<FieldDef::Type>(val);
+}
+inline FieldDef::Label FieldDef::ConvertLabel(int32_t val) {
+  UPB_ASSERT(CheckLabel(val));
+  return static_cast<FieldDef::Label>(val);
+}
+inline FieldDef::DescriptorType FieldDef::ConvertDescriptorType(int32_t val) {
+  UPB_ASSERT(CheckDescriptorType(val));
+  return static_cast<FieldDef::DescriptorType>(val);
+}
+inline FieldDef::IntegerFormat FieldDef::ConvertIntegerFormat(int32_t val) {
+  UPB_ASSERT(CheckIntegerFormat(val));
+  return static_cast<FieldDef::IntegerFormat>(val);
+}
+
+inline reffed_ptr<FieldDef> FieldDef::New() {
+  upb_fielddef *f = upb_fielddef_new(&f);
+  return reffed_ptr<FieldDef>(f, &f);
+}
+inline const char* FieldDef::full_name() const {
+  return upb_fielddef_fullname(this);
+}
+inline bool FieldDef::set_full_name(const char* fullname, Status* s) {
+  return upb_fielddef_setfullname(this, fullname, s);
+}
+inline bool FieldDef::set_full_name(const std::string& fullname, Status* s) {
+  return upb_fielddef_setfullname(this, upb_safecstr(fullname), s);
+}
+inline bool FieldDef::type_is_set() const {
+  return upb_fielddef_typeisset(this);
+}
+inline FieldDef::Type FieldDef::type() const { return upb_fielddef_type(this); }
+inline FieldDef::DescriptorType FieldDef::descriptor_type() const {
+  return upb_fielddef_descriptortype(this);
+}
+inline FieldDef::Label FieldDef::label() const {
+  return upb_fielddef_label(this);
+}
+inline uint32_t FieldDef::number() const { return upb_fielddef_number(this); }
+inline const char* FieldDef::name() const { return upb_fielddef_name(this); }
+inline bool FieldDef::is_extension() const {
+  return upb_fielddef_isextension(this);
+}
+inline size_t FieldDef::GetJsonName(char* buf, size_t len) const {
+  return upb_fielddef_getjsonname(this, buf, len);
+}
+inline bool FieldDef::lazy() const {
+  return upb_fielddef_lazy(this);
+}
+inline void FieldDef::set_lazy(bool lazy) {
+  upb_fielddef_setlazy(this, lazy);
+}
+inline bool FieldDef::packed() const {
+  return upb_fielddef_packed(this);
+}
+inline uint32_t FieldDef::index() const {
+  return upb_fielddef_index(this);
+}
+inline void FieldDef::set_packed(bool packed) {
+  upb_fielddef_setpacked(this, packed);
+}
+inline const MessageDef* FieldDef::containing_type() const {
+  return upb_fielddef_containingtype(this);
+}
+inline const OneofDef* FieldDef::containing_oneof() const {
+  return upb_fielddef_containingoneof(this);
+}
+inline const char* FieldDef::containing_type_name() {
+  return upb_fielddef_containingtypename(this);
+}
+inline bool FieldDef::set_number(uint32_t number, Status* s) {
+  return upb_fielddef_setnumber(this, number, s);
+}
+inline bool FieldDef::set_name(const char *name, Status* s) {
+  return upb_fielddef_setname(this, name, s);
+}
+inline bool FieldDef::set_name(const std::string& name, Status* s) {
+  return upb_fielddef_setname(this, upb_safecstr(name), s);
+}
+inline bool FieldDef::set_json_name(const char *name, Status* s) {
+  return upb_fielddef_setjsonname(this, name, s);
+}
+inline bool FieldDef::set_json_name(const std::string& name, Status* s) {
+  return upb_fielddef_setjsonname(this, upb_safecstr(name), s);
+}
+inline void FieldDef::clear_json_name() {
+  upb_fielddef_clearjsonname(this);
+}
+inline bool FieldDef::set_containing_type_name(const char *name, Status* s) {
+  return upb_fielddef_setcontainingtypename(this, name, s);
+}
+inline bool FieldDef::set_containing_type_name(const std::string &name,
+                                               Status *s) {
+  return upb_fielddef_setcontainingtypename(this, upb_safecstr(name), s);
+}
+inline void FieldDef::set_type(upb_fieldtype_t type) {
+  upb_fielddef_settype(this, type);
+}
+inline void FieldDef::set_is_extension(bool is_extension) {
+  upb_fielddef_setisextension(this, is_extension);
+}
+inline void FieldDef::set_descriptor_type(FieldDef::DescriptorType type) {
+  upb_fielddef_setdescriptortype(this, type);
+}
+inline void FieldDef::set_label(upb_label_t label) {
+  upb_fielddef_setlabel(this, label);
+}
+inline bool FieldDef::IsSubMessage() const {
+  return upb_fielddef_issubmsg(this);
+}
+inline bool FieldDef::IsString() const { return upb_fielddef_isstring(this); }
+inline bool FieldDef::IsSequence() const { return upb_fielddef_isseq(this); }
+inline bool FieldDef::IsMap() const { return upb_fielddef_ismap(this); }
+inline int64_t FieldDef::default_int64() const {
+  return upb_fielddef_defaultint64(this);
+}
+inline int32_t FieldDef::default_int32() const {
+  return upb_fielddef_defaultint32(this);
+}
+inline uint64_t FieldDef::default_uint64() const {
+  return upb_fielddef_defaultuint64(this);
+}
+inline uint32_t FieldDef::default_uint32() const {
+  return upb_fielddef_defaultuint32(this);
+}
+inline bool FieldDef::default_bool() const {
+  return upb_fielddef_defaultbool(this);
+}
+inline float FieldDef::default_float() const {
+  return upb_fielddef_defaultfloat(this);
+}
+inline double FieldDef::default_double() const {
+  return upb_fielddef_defaultdouble(this);
+}
+inline const char* FieldDef::default_string(size_t* len) const {
+  return upb_fielddef_defaultstr(this, len);
+}
+inline void FieldDef::set_default_int64(int64_t value) {
+  upb_fielddef_setdefaultint64(this, value);
+}
+inline void FieldDef::set_default_int32(int32_t value) {
+  upb_fielddef_setdefaultint32(this, value);
+}
+inline void FieldDef::set_default_uint64(uint64_t value) {
+  upb_fielddef_setdefaultuint64(this, value);
+}
+inline void FieldDef::set_default_uint32(uint32_t value) {
+  upb_fielddef_setdefaultuint32(this, value);
+}
+inline void FieldDef::set_default_bool(bool value) {
+  upb_fielddef_setdefaultbool(this, value);
+}
+inline void FieldDef::set_default_float(float value) {
+  upb_fielddef_setdefaultfloat(this, value);
+}
+inline void FieldDef::set_default_double(double value) {
+  upb_fielddef_setdefaultdouble(this, value);
+}
+inline bool FieldDef::set_default_string(const void *str, size_t len,
+                                         Status *s) {
+  return upb_fielddef_setdefaultstr(this, str, len, s);
+}
+inline bool FieldDef::set_default_string(const std::string& str, Status* s) {
+  return upb_fielddef_setdefaultstr(this, str.c_str(), str.size(), s);
+}
+inline void FieldDef::set_default_cstr(const char* str, Status* s) {
+  return upb_fielddef_setdefaultcstr(this, str, s);
+}
+inline bool FieldDef::HasSubDef() const { return upb_fielddef_hassubdef(this); }
+inline const Def* FieldDef::subdef() const { return upb_fielddef_subdef(this); }
+inline const MessageDef *FieldDef::message_subdef() const {
+  return upb_fielddef_msgsubdef(this);
+}
+inline const EnumDef *FieldDef::enum_subdef() const {
+  return upb_fielddef_enumsubdef(this);
+}
+inline const char* FieldDef::subdef_name() const {
+  return upb_fielddef_subdefname(this);
+}
+inline bool FieldDef::set_subdef(const Def* subdef, Status* s) {
+  return upb_fielddef_setsubdef(this, subdef, s);
+}
+inline bool FieldDef::set_enum_subdef(const EnumDef* subdef, Status* s) {
+  return upb_fielddef_setenumsubdef(this, subdef, s);
+}
+inline bool FieldDef::set_message_subdef(const MessageDef* subdef, Status* s) {
+  return upb_fielddef_setmsgsubdef(this, subdef, s);
+}
+inline bool FieldDef::set_subdef_name(const char* name, Status* s) {
+  return upb_fielddef_setsubdefname(this, name, s);
+}
+inline bool FieldDef::set_subdef_name(const std::string& name, Status* s) {
+  return upb_fielddef_setsubdefname(this, upb_safecstr(name), s);
+}
+
+inline reffed_ptr<MessageDef> MessageDef::New() {
+  upb_msgdef *m = upb_msgdef_new(&m);
+  return reffed_ptr<MessageDef>(m, &m);
+}
+inline const char *MessageDef::full_name() const {
+  return upb_msgdef_fullname(this);
+}
+inline const char *MessageDef::name() const {
+  return upb_msgdef_name(this);
+}
+inline upb_syntax_t MessageDef::syntax() const {
+  return upb_msgdef_syntax(this);
+}
+inline bool MessageDef::set_full_name(const char* fullname, Status* s) {
+  return upb_msgdef_setfullname(this, fullname, s);
+}
+inline bool MessageDef::set_full_name(const std::string& fullname, Status* s) {
+  return upb_msgdef_setfullname(this, upb_safecstr(fullname), s);
+}
+inline bool MessageDef::set_syntax(upb_syntax_t syntax) {
+  return upb_msgdef_setsyntax(this, syntax);
+}
+inline bool MessageDef::Freeze(Status* status) {
+  return upb_msgdef_freeze(this, status);
+}
+inline int MessageDef::field_count() const {
+  return upb_msgdef_numfields(this);
+}
+inline int MessageDef::oneof_count() const {
+  return upb_msgdef_numoneofs(this);
+}
+inline bool MessageDef::AddField(upb_fielddef* f, Status* s) {
+  return upb_msgdef_addfield(this, f, NULL, s);
+}
+inline bool MessageDef::AddField(const reffed_ptr<FieldDef>& f, Status* s) {
+  return upb_msgdef_addfield(this, f.get(), NULL, s);
+}
+inline bool MessageDef::AddOneof(upb_oneofdef* o, Status* s) {
+  return upb_msgdef_addoneof(this, o, NULL, s);
+}
+inline bool MessageDef::AddOneof(const reffed_ptr<OneofDef>& o, Status* s) {
+  return upb_msgdef_addoneof(this, o.get(), NULL, s);
+}
+inline FieldDef* MessageDef::FindFieldByNumber(uint32_t number) {
+  return upb_msgdef_itof_mutable(this, number);
+}
+inline FieldDef* MessageDef::FindFieldByName(const char* name, size_t len) {
+  return upb_msgdef_ntof_mutable(this, name, len);
+}
+inline const FieldDef* MessageDef::FindFieldByNumber(uint32_t number) const {
+  return upb_msgdef_itof(this, number);
+}
+inline const FieldDef *MessageDef::FindFieldByName(const char *name,
+                                                   size_t len) const {
+  return upb_msgdef_ntof(this, name, len);
+}
+inline OneofDef* MessageDef::FindOneofByName(const char* name, size_t len) {
+  return upb_msgdef_ntoo_mutable(this, name, len);
+}
+inline const OneofDef* MessageDef::FindOneofByName(const char* name,
+                                                   size_t len) const {
+  return upb_msgdef_ntoo(this, name, len);
+}
+inline void MessageDef::setmapentry(bool map_entry) {
+  upb_msgdef_setmapentry(this, map_entry);
+}
+inline bool MessageDef::mapentry() const {
+  return upb_msgdef_mapentry(this);
+}
+inline MessageDef::field_iterator MessageDef::field_begin() {
+  return field_iterator(this);
+}
+inline MessageDef::field_iterator MessageDef::field_end() {
+  return field_iterator::end(this);
+}
+inline MessageDef::const_field_iterator MessageDef::field_begin() const {
+  return const_field_iterator(this);
+}
+inline MessageDef::const_field_iterator MessageDef::field_end() const {
+  return const_field_iterator::end(this);
+}
+
+inline MessageDef::oneof_iterator MessageDef::oneof_begin() {
+  return oneof_iterator(this);
+}
+inline MessageDef::oneof_iterator MessageDef::oneof_end() {
+  return oneof_iterator::end(this);
+}
+inline MessageDef::const_oneof_iterator MessageDef::oneof_begin() const {
+  return const_oneof_iterator(this);
+}
+inline MessageDef::const_oneof_iterator MessageDef::oneof_end() const {
+  return const_oneof_iterator::end(this);
+}
+
+inline MessageDef::field_iterator::field_iterator(MessageDef* md) {
+  upb_msg_field_begin(&iter_, md);
+}
+inline MessageDef::field_iterator MessageDef::field_iterator::end(
+    MessageDef* md) {
+  MessageDef::field_iterator iter(md);
+  upb_msg_field_iter_setdone(&iter.iter_);
+  return iter;
+}
+inline FieldDef* MessageDef::field_iterator::operator*() const {
+  return upb_msg_iter_field(&iter_);
+}
+inline void MessageDef::field_iterator::operator++() {
+  return upb_msg_field_next(&iter_);
+}
+inline bool MessageDef::field_iterator::operator==(
+    const field_iterator &other) const {
+  return upb_inttable_iter_isequal(&iter_, &other.iter_);
+}
+inline bool MessageDef::field_iterator::operator!=(
+    const field_iterator &other) const {
+  return !(*this == other);
+}
+
+inline MessageDef::const_field_iterator::const_field_iterator(
+    const MessageDef* md) {
+  upb_msg_field_begin(&iter_, md);
+}
+inline MessageDef::const_field_iterator MessageDef::const_field_iterator::end(
+    const MessageDef *md) {
+  MessageDef::const_field_iterator iter(md);
+  upb_msg_field_iter_setdone(&iter.iter_);
+  return iter;
+}
+inline const FieldDef* MessageDef::const_field_iterator::operator*() const {
+  return upb_msg_iter_field(&iter_);
+}
+inline void MessageDef::const_field_iterator::operator++() {
+  return upb_msg_field_next(&iter_);
+}
+inline bool MessageDef::const_field_iterator::operator==(
+    const const_field_iterator &other) const {
+  return upb_inttable_iter_isequal(&iter_, &other.iter_);
+}
+inline bool MessageDef::const_field_iterator::operator!=(
+    const const_field_iterator &other) const {
+  return !(*this == other);
+}
+
+inline MessageDef::oneof_iterator::oneof_iterator(MessageDef* md) {
+  upb_msg_oneof_begin(&iter_, md);
+}
+inline MessageDef::oneof_iterator MessageDef::oneof_iterator::end(
+    MessageDef* md) {
+  MessageDef::oneof_iterator iter(md);
+  upb_msg_oneof_iter_setdone(&iter.iter_);
+  return iter;
+}
+inline OneofDef* MessageDef::oneof_iterator::operator*() const {
+  return upb_msg_iter_oneof(&iter_);
+}
+inline void MessageDef::oneof_iterator::operator++() {
+  return upb_msg_oneof_next(&iter_);
+}
+inline bool MessageDef::oneof_iterator::operator==(
+    const oneof_iterator &other) const {
+  return upb_strtable_iter_isequal(&iter_, &other.iter_);
+}
+inline bool MessageDef::oneof_iterator::operator!=(
+    const oneof_iterator &other) const {
+  return !(*this == other);
+}
+
+inline MessageDef::const_oneof_iterator::const_oneof_iterator(
+    const MessageDef* md) {
+  upb_msg_oneof_begin(&iter_, md);
+}
+inline MessageDef::const_oneof_iterator MessageDef::const_oneof_iterator::end(
+    const MessageDef *md) {
+  MessageDef::const_oneof_iterator iter(md);
+  upb_msg_oneof_iter_setdone(&iter.iter_);
+  return iter;
+}
+inline const OneofDef* MessageDef::const_oneof_iterator::operator*() const {
+  return upb_msg_iter_oneof(&iter_);
+}
+inline void MessageDef::const_oneof_iterator::operator++() {
+  return upb_msg_oneof_next(&iter_);
+}
+inline bool MessageDef::const_oneof_iterator::operator==(
+    const const_oneof_iterator &other) const {
+  return upb_strtable_iter_isequal(&iter_, &other.iter_);
+}
+inline bool MessageDef::const_oneof_iterator::operator!=(
+    const const_oneof_iterator &other) const {
+  return !(*this == other);
+}
+
+inline reffed_ptr<EnumDef> EnumDef::New() {
+  upb_enumdef *e = upb_enumdef_new(&e);
+  return reffed_ptr<EnumDef>(e, &e);
+}
+inline const char* EnumDef::full_name() const {
+  return upb_enumdef_fullname(this);
+}
+inline const char* EnumDef::name() const {
+  return upb_enumdef_name(this);
+}
+inline bool EnumDef::set_full_name(const char* fullname, Status* s) {
+  return upb_enumdef_setfullname(this, fullname, s);
+}
+inline bool EnumDef::set_full_name(const std::string& fullname, Status* s) {
+  return upb_enumdef_setfullname(this, upb_safecstr(fullname), s);
+}
+inline bool EnumDef::Freeze(Status* status) {
+  return upb_enumdef_freeze(this, status);
+}
+inline int32_t EnumDef::default_value() const {
+  return upb_enumdef_default(this);
+}
+inline bool EnumDef::set_default_value(int32_t val, Status* status) {
+  return upb_enumdef_setdefault(this, val, status);
+}
+inline int EnumDef::value_count() const { return upb_enumdef_numvals(this); }
+inline bool EnumDef::AddValue(const char* name, int32_t num, Status* status) {
+  return upb_enumdef_addval(this, name, num, status);
+}
+inline bool EnumDef::AddValue(const std::string& name, int32_t num,
+                              Status* status) {
+  return upb_enumdef_addval(this, upb_safecstr(name), num, status);
+}
+inline bool EnumDef::FindValueByName(const char* name, int32_t *num) const {
+  return upb_enumdef_ntoiz(this, name, num);
+}
+inline const char* EnumDef::FindValueByNumber(int32_t num) const {
+  return upb_enumdef_iton(this, num);
+}
+
+inline EnumDef::Iterator::Iterator(const EnumDef* e) {
+  upb_enum_begin(&iter_, e);
+}
+inline int32_t EnumDef::Iterator::number() {
+  return upb_enum_iter_number(&iter_);
+}
+inline const char* EnumDef::Iterator::name() {
+  return upb_enum_iter_name(&iter_);
+}
+inline bool EnumDef::Iterator::Done() { return upb_enum_done(&iter_); }
+inline void EnumDef::Iterator::Next() { return upb_enum_next(&iter_); }
+
+inline reffed_ptr<OneofDef> OneofDef::New() {
+  upb_oneofdef *o = upb_oneofdef_new(&o);
+  return reffed_ptr<OneofDef>(o, &o);
+}
+
+inline const MessageDef* OneofDef::containing_type() const {
+  return upb_oneofdef_containingtype(this);
+}
+inline const char* OneofDef::name() const {
+  return upb_oneofdef_name(this);
+}
+inline bool OneofDef::set_name(const char* name, Status* s) {
+  return upb_oneofdef_setname(this, name, s);
+}
+inline bool OneofDef::set_name(const std::string& name, Status* s) {
+  return upb_oneofdef_setname(this, upb_safecstr(name), s);
+}
+inline int OneofDef::field_count() const {
+  return upb_oneofdef_numfields(this);
+}
+inline bool OneofDef::AddField(FieldDef* field, Status* s) {
+  return upb_oneofdef_addfield(this, field, NULL, s);
+}
+inline bool OneofDef::AddField(const reffed_ptr<FieldDef>& field, Status* s) {
+  return upb_oneofdef_addfield(this, field.get(), NULL, s);
+}
+inline const FieldDef* OneofDef::FindFieldByName(const char* name,
+                                                 size_t len) const {
+  return upb_oneofdef_ntof(this, name, len);
+}
+inline const FieldDef* OneofDef::FindFieldByNumber(uint32_t num) const {
+  return upb_oneofdef_itof(this, num);
+}
+inline OneofDef::iterator OneofDef::begin() { return iterator(this); }
+inline OneofDef::iterator OneofDef::end() { return iterator::end(this); }
+inline OneofDef::const_iterator OneofDef::begin() const {
+  return const_iterator(this);
+}
+inline OneofDef::const_iterator OneofDef::end() const {
+  return const_iterator::end(this);
+}
+
+inline OneofDef::iterator::iterator(OneofDef* o) {
+  upb_oneof_begin(&iter_, o);
+}
+inline OneofDef::iterator OneofDef::iterator::end(OneofDef* o) {
+  OneofDef::iterator iter(o);
+  upb_oneof_iter_setdone(&iter.iter_);
+  return iter;
+}
+inline FieldDef* OneofDef::iterator::operator*() const {
+  return upb_oneof_iter_field(&iter_);
+}
+inline void OneofDef::iterator::operator++() { return upb_oneof_next(&iter_); }
+inline bool OneofDef::iterator::operator==(const iterator &other) const {
+  return upb_inttable_iter_isequal(&iter_, &other.iter_);
+}
+inline bool OneofDef::iterator::operator!=(const iterator &other) const {
+  return !(*this == other);
+}
+
+inline OneofDef::const_iterator::const_iterator(const OneofDef* md) {
+  upb_oneof_begin(&iter_, md);
+}
+inline OneofDef::const_iterator OneofDef::const_iterator::end(
+    const OneofDef *md) {
+  OneofDef::const_iterator iter(md);
+  upb_oneof_iter_setdone(&iter.iter_);
+  return iter;
+}
+inline const FieldDef* OneofDef::const_iterator::operator*() const {
+  return upb_msg_iter_field(&iter_);
+}
+inline void OneofDef::const_iterator::operator++() {
+  return upb_oneof_next(&iter_);
+}
+inline bool OneofDef::const_iterator::operator==(
+    const const_iterator &other) const {
+  return upb_inttable_iter_isequal(&iter_, &other.iter_);
+}
+inline bool OneofDef::const_iterator::operator!=(
+    const const_iterator &other) const {
+  return !(*this == other);
+}
+
+inline reffed_ptr<FileDef> FileDef::New() {
+  upb_filedef *f = upb_filedef_new(&f);
+  return reffed_ptr<FileDef>(f, &f);
+}
+
+inline const char* FileDef::name() const {
+  return upb_filedef_name(this);
+}
+inline bool FileDef::set_name(const char* name, Status* s) {
+  return upb_filedef_setname(this, name, s);
+}
+inline bool FileDef::set_name(const std::string& name, Status* s) {
+  return upb_filedef_setname(this, upb_safecstr(name), s);
+}
+inline const char* FileDef::package() const {
+  return upb_filedef_package(this);
+}
+inline bool FileDef::set_package(const char* package, Status* s) {
+  return upb_filedef_setpackage(this, package, s);
+}
+inline const char* FileDef::phpprefix() const {
+  return upb_filedef_phpprefix(this);
+}
+inline bool FileDef::set_phpprefix(const char* phpprefix, Status* s) {
+  return upb_filedef_setphpprefix(this, phpprefix, s);
+}
+inline const char* FileDef::phpnamespace() const {
+  return upb_filedef_phpnamespace(this);
+}
+inline bool FileDef::set_phpnamespace(const char* phpnamespace, Status* s) {
+  return upb_filedef_setphpnamespace(this, phpnamespace, s);
+}
+inline int FileDef::def_count() const {
+  return upb_filedef_defcount(this);
+}
+inline const Def* FileDef::def(int index) const {
+  return upb_filedef_def(this, index);
+}
+inline Def* FileDef::def(int index) {
+  return const_cast<Def*>(upb_filedef_def(this, index));
+}
+inline int FileDef::dependency_count() const {
+  return upb_filedef_depcount(this);
+}
+inline const FileDef* FileDef::dependency(int index) const {
+  return upb_filedef_dep(this, index);
+}
+inline bool FileDef::AddDef(Def* def, Status* s) {
+  return upb_filedef_adddef(this, def, NULL, s);
+}
+inline bool FileDef::AddMessage(MessageDef* m, Status* s) {
+  return upb_filedef_addmsg(this, m, NULL, s);
+}
+inline bool FileDef::AddEnum(EnumDef* e, Status* s) {
+  return upb_filedef_addenum(this, e, NULL, s);
+}
+inline bool FileDef::AddExtension(FieldDef* f, Status* s) {
+  return upb_filedef_addext(this, f, NULL, s);
+}
+inline bool FileDef::AddDependency(const FileDef* file) {
+  return upb_filedef_adddep(this, file);
+}
+
+}  /* namespace upb */
+#endif
+
+#endif /* UPB_DEF_H_ */
+/*
+** upb::Handlers (upb_handlers)
+**
+** A upb_handlers is like a virtual table for a upb_msgdef.  Each field of the
+** message can have associated functions that will be called when we are
+** parsing or visiting a stream of data.  This is similar to how handlers work
+** in SAX (the Simple API for XML).
+**
+** The handlers have no idea where the data is coming from, so a single set of
+** handlers could be used with two completely different data sources (for
+** example, a parser and a visitor over in-memory objects).  This decoupling is
+** the most important feature of upb, because it allows parsers and serializers
+** to be highly reusable.
+**
+** This is a mixed C/C++ interface that offers a full API to both languages.
+** See the top-level README for more information.
+*/
+
+#ifndef UPB_HANDLERS_H
+#define UPB_HANDLERS_H
+
+
+#ifdef __cplusplus
+namespace upb {
+class BufferHandle;
+class BytesHandler;
+class HandlerAttributes;
+class Handlers;
+template <class T> class Handler;
+template <class T> struct CanonicalType;
+}  /* namespace upb */
+#endif
+
+UPB_DECLARE_TYPE(upb::BufferHandle, upb_bufhandle)
+UPB_DECLARE_TYPE(upb::BytesHandler, upb_byteshandler)
+UPB_DECLARE_TYPE(upb::HandlerAttributes, upb_handlerattr)
+UPB_DECLARE_DERIVED_TYPE(upb::Handlers, upb::RefCounted,
+                         upb_handlers, upb_refcounted)
+
+/* The maximum depth that the handler graph can have.  This is a resource limit
+ * for the C stack since we sometimes need to recursively traverse the graph.
+ * Cycles are ok; the traversal will stop when it detects a cycle, but we must
+ * hit the cycle before the maximum depth is reached.
+ *
+ * If having a single static limit is too inflexible, we can add another variant
+ * of Handlers::Freeze that allows specifying this as a parameter. */
+#define UPB_MAX_HANDLER_DEPTH 64
+
+/* All the different types of handlers that can be registered.
+ * Only needed for the advanced functions in upb::Handlers. */
+typedef enum {
+  UPB_HANDLER_INT32,
+  UPB_HANDLER_INT64,
+  UPB_HANDLER_UINT32,
+  UPB_HANDLER_UINT64,
+  UPB_HANDLER_FLOAT,
+  UPB_HANDLER_DOUBLE,
+  UPB_HANDLER_BOOL,
+  UPB_HANDLER_STARTSTR,
+  UPB_HANDLER_STRING,
+  UPB_HANDLER_ENDSTR,
+  UPB_HANDLER_STARTSUBMSG,
+  UPB_HANDLER_ENDSUBMSG,
+  UPB_HANDLER_STARTSEQ,
+  UPB_HANDLER_ENDSEQ
+} upb_handlertype_t;
+
+#define UPB_HANDLER_MAX (UPB_HANDLER_ENDSEQ+1)
+
+#define UPB_BREAK NULL
+
+/* A convenient definition for when no closure is needed. */
+extern char _upb_noclosure;
+#define UPB_NO_CLOSURE &_upb_noclosure
+
+/* A selector refers to a specific field handler in the Handlers object
+ * (for example: the STARTSUBMSG handler for field "field15"). */
+typedef int32_t upb_selector_t;
+
+UPB_BEGIN_EXTERN_C
+
+/* Forward-declares for C inline accessors.  We need to declare these here
+ * so we can "friend" them in the class declarations in C++. */
+UPB_INLINE upb_func *upb_handlers_gethandler(const upb_handlers *h,
+                                             upb_selector_t s);
+UPB_INLINE const void *upb_handlerattr_handlerdata(const upb_handlerattr *attr);
+UPB_INLINE const void *upb_handlers_gethandlerdata(const upb_handlers *h,
+                                                   upb_selector_t s);
+
+UPB_INLINE void upb_bufhandle_init(upb_bufhandle *h);
+UPB_INLINE void upb_bufhandle_setobj(upb_bufhandle *h, const void *obj,
+                                     const void *type);
+UPB_INLINE void upb_bufhandle_setbuf(upb_bufhandle *h, const char *buf,
+                                     size_t ofs);
+UPB_INLINE const void *upb_bufhandle_obj(const upb_bufhandle *h);
+UPB_INLINE const void *upb_bufhandle_objtype(const upb_bufhandle *h);
+UPB_INLINE const char *upb_bufhandle_buf(const upb_bufhandle *h);
+
+UPB_END_EXTERN_C
+
+
+/* Static selectors for upb::Handlers. */
+#define UPB_STARTMSG_SELECTOR 0
+#define UPB_ENDMSG_SELECTOR 1
+#define UPB_UNKNOWN_SELECTOR 2
+#define UPB_STATIC_SELECTOR_COUNT 3
+
+/* Static selectors for upb::BytesHandler. */
+#define UPB_STARTSTR_SELECTOR 0
+#define UPB_STRING_SELECTOR 1
+#define UPB_ENDSTR_SELECTOR 2
+
+typedef void upb_handlerfree(void *d);
+
+#ifdef __cplusplus
+
+/* A set of attributes that accompanies a handler's function pointer. */
+class upb::HandlerAttributes {
+ public:
+  HandlerAttributes();
+  ~HandlerAttributes();
+
+  /* Sets the handler data that will be passed as the second parameter of the
+   * handler.  To free this pointer when the handlers are freed, call
+   * Handlers::AddCleanup(). */
+  bool SetHandlerData(const void *handler_data);
+  const void* handler_data() const;
+
+  /* Use this to specify the type of the closure.  This will be checked against
+   * all other closure types for handler that use the same closure.
+   * Registration will fail if this does not match all other non-NULL closure
+   * types. */
+  bool SetClosureType(const void *closure_type);
+  const void* closure_type() const;
+
+  /* Use this to specify the type of the returned closure.  Only used for
+   * Start*{String,SubMessage,Sequence} handlers.  This must match the closure
+   * type of any handlers that use it (for example, the StringBuf handler must
+   * match the closure returned from StartString). */
+  bool SetReturnClosureType(const void *return_closure_type);
+  const void* return_closure_type() const;
+
+  /* Set to indicate that the handler always returns "ok" (either "true" or a
+   * non-NULL closure).  This is a hint that can allow code generators to
+   * generate more efficient code. */
+  bool SetAlwaysOk(bool always_ok);
+  bool always_ok() const;
+
+ private:
+  friend UPB_INLINE const void * ::upb_handlerattr_handlerdata(
+      const upb_handlerattr *attr);
+#else
+struct upb_handlerattr {
+#endif
+  const void *handler_data_;
+  const void *closure_type_;
+  const void *return_closure_type_;
+  bool alwaysok_;
+};
+
+#define UPB_HANDLERATTR_INITIALIZER {NULL, NULL, NULL, false}
+
+typedef struct {
+  upb_func *func;
+
+  /* It is wasteful to include the entire attributes here:
+   *
+   * * Some of the information is redundant (like storing the closure type
+   *   separately for each handler that must match).
+   * * Some of the info is only needed prior to freeze() (like closure types).
+   * * alignment padding wastes a lot of space for alwaysok_.
+   *
+   * If/when the size and locality of handlers is an issue, we can optimize this
+   * not to store the entire attr like this.  We do not expose the table's
+   * layout to allow this optimization in the future. */
+  upb_handlerattr attr;
+} upb_handlers_tabent;
+
+#ifdef __cplusplus
+
+/* Extra information about a buffer that is passed to a StringBuf handler.
+ * TODO(haberman): allow the handle to be pinned so that it will outlive
+ * the handler invocation. */
+class upb::BufferHandle {
+ public:
+  BufferHandle();
+  ~BufferHandle();
+
+  /* The beginning of the buffer.  This may be different than the pointer
+   * passed to a StringBuf handler because the handler may receive data
+   * that is from the middle or end of a larger buffer. */
+  const char* buffer() const;
+
+  /* The offset within the attached object where this buffer begins.  Only
+   * meaningful if there is an attached object. */
+  size_t object_offset() const;
+
+  /* Note that object_offset is the offset of "buf" within the attached
+   * object. */
+  void SetBuffer(const char* buf, size_t object_offset);
+
+  /* The BufferHandle can have an "attached object", which can be used to
+   * tunnel through a pointer to the buffer's underlying representation. */
+  template <class T>
+  void SetAttachedObject(const T* obj);
+
+  /* Returns NULL if the attached object is not of this type. */
+  template <class T>
+  const T* GetAttachedObject() const;
+
+ private:
+  friend UPB_INLINE void ::upb_bufhandle_init(upb_bufhandle *h);
+  friend UPB_INLINE void ::upb_bufhandle_setobj(upb_bufhandle *h,
+                                                const void *obj,
+                                                const void *type);
+  friend UPB_INLINE void ::upb_bufhandle_setbuf(upb_bufhandle *h,
+                                                const char *buf, size_t ofs);
+  friend UPB_INLINE const void* ::upb_bufhandle_obj(const upb_bufhandle *h);
+  friend UPB_INLINE const void* ::upb_bufhandle_objtype(
+      const upb_bufhandle *h);
+  friend UPB_INLINE const char* ::upb_bufhandle_buf(const upb_bufhandle *h);
+#else
+struct upb_bufhandle {
+#endif
+  const char *buf_;
+  const void *obj_;
+  const void *objtype_;
+  size_t objofs_;
+};
+
+#ifdef __cplusplus
+
+/* A upb::Handlers object represents the set of handlers associated with a
+ * message in the graph of messages.  You can think of it as a big virtual
+ * table with functions corresponding to all the events that can fire while
+ * parsing or visiting a message of a specific type.
+ *
+ * Any handlers that are not set behave as if they had successfully consumed
+ * the value.  Any unset Start* handlers will propagate their closure to the
+ * inner frame.
+ *
+ * The easiest way to create the *Handler objects needed by the Set* methods is
+ * with the UpbBind() and UpbMakeHandler() macros; see below. */
+class upb::Handlers {
+ public:
+  typedef upb_selector_t Selector;
+  typedef upb_handlertype_t Type;
+
+  typedef Handler<void *(*)(void *, const void *)> StartFieldHandler;
+  typedef Handler<bool (*)(void *, const void *)> EndFieldHandler;
+  typedef Handler<bool (*)(void *, const void *)> StartMessageHandler;
+  typedef Handler<bool (*)(void *, const void *, Status*)> EndMessageHandler;
+  typedef Handler<void *(*)(void *, const void *, size_t)> StartStringHandler;
+  typedef Handler<size_t (*)(void *, const void *, const char *, size_t,
+                             const BufferHandle *)> StringHandler;
+
+  template <class T> struct ValueHandler {
+    typedef Handler<bool(*)(void *, const void *, T)> H;
+  };
+
+  typedef ValueHandler<int32_t>::H     Int32Handler;
+  typedef ValueHandler<int64_t>::H     Int64Handler;
+  typedef ValueHandler<uint32_t>::H    UInt32Handler;
+  typedef ValueHandler<uint64_t>::H    UInt64Handler;
+  typedef ValueHandler<float>::H       FloatHandler;
+  typedef ValueHandler<double>::H      DoubleHandler;
+  typedef ValueHandler<bool>::H        BoolHandler;
+
+  /* Any function pointer can be converted to this and converted back to its
+   * correct type. */
+  typedef void GenericFunction();
+
+  typedef void HandlersCallback(const void *closure, upb_handlers *h);
+
+  /* Returns a new handlers object for the given frozen msgdef.
+   * Returns NULL if memory allocation failed. */
+  static reffed_ptr<Handlers> New(const MessageDef *m);
+
+  /* Convenience function for registering a graph of handlers that mirrors the
+   * graph of msgdefs for some message.  For "m" and all its children a new set
+   * of handlers will be created and the given callback will be invoked,
+   * allowing the client to register handlers for this message.  Note that any
+   * subhandlers set by the callback will be overwritten. */
+  static reffed_ptr<const Handlers> NewFrozen(const MessageDef *m,
+                                              HandlersCallback *callback,
+                                              const void *closure);
+
+  /* Functionality from upb::RefCounted. */
+  UPB_REFCOUNTED_CPPMETHODS
+
+  /* All handler registration functions return bool to indicate success or
+   * failure; details about failures are stored in this status object.  If a
+   * failure does occur, it must be cleared before the Handlers are frozen,
+   * otherwise the freeze() operation will fail.  The functions may *only* be
+   * used while the Handlers are mutable. */
+  const Status* status();
+  void ClearError();
+
+  /* Call to freeze these Handlers.  Requires that any SubHandlers are already
+   * frozen.  For cycles, you must use the static version below and freeze the
+   * whole graph at once. */
+  bool Freeze(Status* s);
+
+  /* Freezes the given set of handlers.  You may not freeze a handler without
+   * also freezing any handlers they point to. */
+  static bool Freeze(Handlers*const* handlers, int n, Status* s);
+  static bool Freeze(const std::vector<Handlers*>& handlers, Status* s);
+
+  /* Returns the msgdef associated with this handlers object. */
+  const MessageDef* message_def() const;
+
+  /* Adds the given pointer and function to the list of cleanup functions that
+   * will be run when these handlers are freed.  If this pointer has previously
+   * been registered, the function returns false and does nothing. */
+  bool AddCleanup(void *ptr, upb_handlerfree *cleanup);
+
+  /* Sets the startmsg handler for the message, which is defined as follows:
+   *
+   *   bool startmsg(MyType* closure) {
+   *     // Called when the message begins.  Returns true if processing should
+   *     // continue.
+   *     return true;
+   *   }
+   */
+  bool SetStartMessageHandler(const StartMessageHandler& handler);
+
+  /* Sets the endmsg handler for the message, which is defined as follows:
+   *
+   *   bool endmsg(MyType* closure, upb_status *status) {
+   *     // Called when processing of this message ends, whether in success or
+   *     // failure.  "status" indicates the final status of processing, and
+   *     // can also be modified in-place to update the final status.
+   *   }
+   */
+  bool SetEndMessageHandler(const EndMessageHandler& handler);
+
+  /* Sets the value handler for the given field, which is defined as follows
+   * (this is for an int32 field; other field types will pass their native
+   * C/C++ type for "val"):
+   *
+   *   bool OnValue(MyClosure* c, const MyHandlerData* d, int32_t val) {
+   *     // Called when the field's value is encountered.  "d" contains
+   *     // whatever data was bound to this field when it was registered.
+   *     // Returns true if processing should continue.
+   *     return true;
+   *   }
+   *
+   *   handers->SetInt32Handler(f, UpbBind(OnValue, new MyHandlerData(...)));
+   *
+   * The value type must exactly match f->type().
+   * For example, a handler that takes an int32_t parameter may only be used for
+   * fields of type UPB_TYPE_INT32 and UPB_TYPE_ENUM.
+   *
+   * Returns false if the handler failed to register; in this case the cleanup
+   * handler (if any) will be called immediately.
+   */
+  bool SetInt32Handler (const FieldDef* f,  const Int32Handler& h);
+  bool SetInt64Handler (const FieldDef* f,  const Int64Handler& h);
+  bool SetUInt32Handler(const FieldDef* f, const UInt32Handler& h);
+  bool SetUInt64Handler(const FieldDef* f, const UInt64Handler& h);
+  bool SetFloatHandler (const FieldDef* f,  const FloatHandler& h);
+  bool SetDoubleHandler(const FieldDef* f, const DoubleHandler& h);
+  bool SetBoolHandler  (const FieldDef* f,   const BoolHandler& h);
+
+  /* Like the previous, but templated on the type on the value (ie. int32).
+   * This is mostly useful to call from other templates.  To call this you must
+   * specify the template parameter explicitly, ie:
+   *   h->SetValueHandler<T>(f, UpbBind(MyHandler<T>, MyData)); */
+  template <class T>
+  bool SetValueHandler(
+      const FieldDef *f,
+      const typename ValueHandler<typename CanonicalType<T>::Type>::H& handler);
+
+  /* Sets handlers for a string field, which are defined as follows:
+   *
+   *   MySubClosure* startstr(MyClosure* c, const MyHandlerData* d,
+   *                          size_t size_hint) {
+   *     // Called when a string value begins.  The return value indicates the
+   *     // closure for the string.  "size_hint" indicates the size of the
+   *     // string if it is known, however if the string is length-delimited
+   *     // and the end-of-string is not available size_hint will be zero.
+   *     // This case is indistinguishable from the case where the size is
+   *     // known to be zero.
+   *     //
+   *     // TODO(haberman): is it important to distinguish these cases?
+   *     // If we had ssize_t as a type we could make -1 "unknown", but
+   *     // ssize_t is POSIX (not ANSI) and therefore less portable.
+   *     // In practice I suspect it won't be important to distinguish.
+   *     return closure;
+   *   }
+   *
+   *   size_t str(MyClosure* closure, const MyHandlerData* d,
+   *              const char *str, size_t len) {
+   *     // Called for each buffer of string data; the multiple physical buffers
+   *     // are all part of the same logical string.  The return value indicates
+   *     // how many bytes were consumed.  If this number is less than "len",
+   *     // this will also indicate that processing should be halted for now,
+   *     // like returning false or UPB_BREAK from any other callback.  If
+   *     // number is greater than "len", the excess bytes will be skipped over
+   *     // and not passed to the callback.
+   *     return len;
+   *   }
+   *
+   *   bool endstr(MyClosure* c, const MyHandlerData* d) {
+   *     // Called when a string value ends.  Return value indicates whether
+   *     // processing should continue.
+   *     return true;
+   *   }
+   */
+  bool SetStartStringHandler(const FieldDef* f, const StartStringHandler& h);
+  bool SetStringHandler(const FieldDef* f, const StringHandler& h);
+  bool SetEndStringHandler(const FieldDef* f, const EndFieldHandler& h);
+
+  /* Sets the startseq handler, which is defined as follows:
+   *
+   *   MySubClosure *startseq(MyClosure* c, const MyHandlerData* d) {
+   *     // Called when a sequence (repeated field) begins.  The returned
+   *     // pointer indicates the closure for the sequence (or UPB_BREAK
+   *     // to interrupt processing).
+   *     return closure;
+   *   }
+   *
+   *   h->SetStartSequenceHandler(f, UpbBind(startseq, new MyHandlerData(...)));
+   *
+   * Returns "false" if "f" does not belong to this message or is not a
+   * repeated field.
+   */
+  bool SetStartSequenceHandler(const FieldDef* f, const StartFieldHandler& h);
+
+  /* Sets the startsubmsg handler for the given field, which is defined as
+   * follows:
+   *
+   *   MySubClosure* startsubmsg(MyClosure* c, const MyHandlerData* d) {
+   *     // Called when a submessage begins.  The returned pointer indicates the
+   *     // closure for the sequence (or UPB_BREAK to interrupt processing).
+   *     return closure;
+   *   }
+   *
+   *   h->SetStartSubMessageHandler(f, UpbBind(startsubmsg,
+   *                                           new MyHandlerData(...)));
+   *
+   * Returns "false" if "f" does not belong to this message or is not a
+   * submessage/group field.
+   */
+  bool SetStartSubMessageHandler(const FieldDef* f, const StartFieldHandler& h);
+
+  /* Sets the endsubmsg handler for the given field, which is defined as
+   * follows:
+   *
+   *   bool endsubmsg(MyClosure* c, const MyHandlerData* d) {
+   *     // Called when a submessage ends.  Returns true to continue processing.
+   *     return true;
+   *   }
+   *
+   * Returns "false" if "f" does not belong to this message or is not a
+   * submessage/group field.
+   */
+  bool SetEndSubMessageHandler(const FieldDef *f, const EndFieldHandler &h);
+
+  /* Starts the endsubseq handler for the given field, which is defined as
+   * follows:
+   *
+   *   bool endseq(MyClosure* c, const MyHandlerData* d) {
+   *     // Called when a sequence ends.  Returns true continue processing.
+   *     return true;
+   *   }
+   *
+   * Returns "false" if "f" does not belong to this message or is not a
+   * repeated field.
+   */
+  bool SetEndSequenceHandler(const FieldDef* f, const EndFieldHandler& h);
+
+  /* Sets or gets the object that specifies handlers for the given field, which
+   * must be a submessage or group.  Returns NULL if no handlers are set. */
+  bool SetSubHandlers(const FieldDef* f, const Handlers* sub);
+  const Handlers* GetSubHandlers(const FieldDef* f) const;
+
+  /* Equivalent to GetSubHandlers, but takes the STARTSUBMSG selector for the
+   * field. */
+  const Handlers* GetSubHandlers(Selector startsubmsg) const;
+
+  /* A selector refers to a specific field handler in the Handlers object
+   * (for example: the STARTSUBMSG handler for field "field15").
+   * On success, returns true and stores the selector in "s".
+   * If the FieldDef or Type are invalid, returns false.
+   * The returned selector is ONLY valid for Handlers whose MessageDef
+   * contains this FieldDef. */
+  static bool GetSelector(const FieldDef* f, Type type, Selector* s);
+
+  /* Given a START selector of any kind, returns the corresponding END selector. */
+  static Selector GetEndSelector(Selector start_selector);
+
+  /* Returns the function pointer for this handler.  It is the client's
+   * responsibility to cast to the correct function type before calling it. */
+  GenericFunction* GetHandler(Selector selector);
+
+  /* Sets the given attributes to the attributes for this selector. */
+  bool GetAttributes(Selector selector, HandlerAttributes* attr);
+
+  /* Returns the handler data that was registered with this handler. */
+  const void* GetHandlerData(Selector selector);
+
+  /* Could add any of the following functions as-needed, with some minor
+   * implementation changes:
+   *
+   * const FieldDef* GetFieldDef(Selector selector);
+   * static bool IsSequence(Selector selector); */
+
+ private:
+  UPB_DISALLOW_POD_OPS(Handlers, upb::Handlers)
+
+  friend UPB_INLINE GenericFunction *::upb_handlers_gethandler(
+      const upb_handlers *h, upb_selector_t s);
+  friend UPB_INLINE const void *::upb_handlers_gethandlerdata(
+      const upb_handlers *h, upb_selector_t s);
+#else
+struct upb_handlers {
+#endif
+  upb_refcounted base;
+
+  const upb_msgdef *msg;
+  const upb_handlers **sub;
+  const void *top_closure_type;
+  upb_inttable cleanup_;
+  upb_status status_;  /* Used only when mutable. */
+  upb_handlers_tabent table[1];  /* Dynamically-sized field handler array. */
+};
+
+#ifdef __cplusplus
+
+namespace upb {
+
+/* Convenience macros for creating a Handler object that is wrapped with a
+ * type-safe wrapper function that converts the "void*" parameters/returns
+ * of the underlying C API into nice C++ function.
+ *
+ * Sample usage:
+ *   void OnValue1(MyClosure* c, const MyHandlerData* d, int32_t val) {
+ *     // do stuff ...
+ *   }
+ *
+ *   // Handler that doesn't need any data bound to it.
+ *   void OnValue2(MyClosure* c, int32_t val) {
+ *     // do stuff ...
+ *   }
+ *
+ *   // Handler that returns bool so it can return failure if necessary.
+ *   bool OnValue3(MyClosure* c, int32_t val) {
+ *     // do stuff ...
+ *     return ok;
+ *   }
+ *
+ *   // Member function handler.
+ *   class MyClosure {
+ *    public:
+ *     void OnValue(int32_t val) {
+ *       // do stuff ...
+ *     }
+ *   };
+ *
+ *   // Takes ownership of the MyHandlerData.
+ *   handlers->SetInt32Handler(f1, UpbBind(OnValue1, new MyHandlerData(...)));
+ *   handlers->SetInt32Handler(f2, UpbMakeHandler(OnValue2));
+ *   handlers->SetInt32Handler(f1, UpbMakeHandler(OnValue3));
+ *   handlers->SetInt32Handler(f2, UpbMakeHandler(&MyClosure::OnValue));
+ */
+
+#ifdef UPB_CXX11
+
+/* In C++11, the "template" disambiguator can appear even outside templates,
+ * so all calls can safely use this pair of macros. */
+
+#define UpbMakeHandler(f) upb::MatchFunc(f).template GetFunc<f>()
+
+/* We have to be careful to only evaluate "d" once. */
+#define UpbBind(f, d) upb::MatchFunc(f).template GetFunc<f>((d))
+
+#else
+
+/* Prior to C++11, the "template" disambiguator may only appear inside a
+ * template, so the regular macro must not use "template" */
+
+#define UpbMakeHandler(f) upb::MatchFunc(f).GetFunc<f>()
+
+#define UpbBind(f, d) upb::MatchFunc(f).GetFunc<f>((d))
+
+#endif  /* UPB_CXX11 */
+
+/* This macro must be used in C++98 for calls from inside a template.  But we
+ * define this variant in all cases; code that wants to be compatible with both
+ * C++98 and C++11 should always use this macro when calling from a template. */
+#define UpbMakeHandlerT(f) upb::MatchFunc(f).template GetFunc<f>()
+
+/* We have to be careful to only evaluate "d" once. */
+#define UpbBindT(f, d) upb::MatchFunc(f).template GetFunc<f>((d))
+
+/* Handler: a struct that contains the (handler, data, deleter) tuple that is
+ * used to register all handlers.  Users can Make() these directly but it's
+ * more convenient to use the UpbMakeHandler/UpbBind macros above. */
+template <class T> class Handler {
+ public:
+  /* The underlying, handler function signature that upb uses internally. */
+  typedef T FuncPtr;
+
+  /* Intentionally implicit. */
+  template <class F> Handler(F func);
+  ~Handler();
+
+ private:
+  void AddCleanup(Handlers* h) const {
+    if (cleanup_func_) {
+      bool ok = h->AddCleanup(cleanup_data_, cleanup_func_);
+      UPB_ASSERT(ok);
+    }
+  }
+
+  UPB_DISALLOW_COPY_AND_ASSIGN(Handler)
+  friend class Handlers;
+  FuncPtr handler_;
+  mutable HandlerAttributes attr_;
+  mutable bool registered_;
+  void *cleanup_data_;
+  upb_handlerfree *cleanup_func_;
+};
+
+}  /* namespace upb */
+
+#endif  /* __cplusplus */
+
+UPB_BEGIN_EXTERN_C
+
+/* Native C API. */
+
+/* Handler function typedefs. */
+typedef bool upb_unknown_handlerfunc(void *c, const void *hd, const char *buf,
+                                     size_t n);
+typedef bool upb_startmsg_handlerfunc(void *c, const void*);
+typedef bool upb_endmsg_handlerfunc(void *c, const void *, upb_status *status);
+typedef void* upb_startfield_handlerfunc(void *c, const void *hd);
+typedef bool upb_endfield_handlerfunc(void *c, const void *hd);
+typedef bool upb_int32_handlerfunc(void *c, const void *hd, int32_t val);
+typedef bool upb_int64_handlerfunc(void *c, const void *hd, int64_t val);
+typedef bool upb_uint32_handlerfunc(void *c, const void *hd, uint32_t val);
+typedef bool upb_uint64_handlerfunc(void *c, const void *hd, uint64_t val);
+typedef bool upb_float_handlerfunc(void *c, const void *hd, float val);
+typedef bool upb_double_handlerfunc(void *c, const void *hd, double val);
+typedef bool upb_bool_handlerfunc(void *c, const void *hd, bool val);
+typedef void *upb_startstr_handlerfunc(void *c, const void *hd,
+                                       size_t size_hint);
+typedef size_t upb_string_handlerfunc(void *c, const void *hd, const char *buf,
+                                      size_t n, const upb_bufhandle* handle);
+
+/* upb_bufhandle */
+size_t upb_bufhandle_objofs(const upb_bufhandle *h);
+
+/* upb_handlerattr */
+void upb_handlerattr_init(upb_handlerattr *attr);
+void upb_handlerattr_uninit(upb_handlerattr *attr);
+
+bool upb_handlerattr_sethandlerdata(upb_handlerattr *attr, const void *hd);
+bool upb_handlerattr_setclosuretype(upb_handlerattr *attr, const void *type);
+const void *upb_handlerattr_closuretype(const upb_handlerattr *attr);
+bool upb_handlerattr_setreturnclosuretype(upb_handlerattr *attr,
+                                          const void *type);
+const void *upb_handlerattr_returnclosuretype(const upb_handlerattr *attr);
+bool upb_handlerattr_setalwaysok(upb_handlerattr *attr, bool alwaysok);
+bool upb_handlerattr_alwaysok(const upb_handlerattr *attr);
+
+UPB_INLINE const void *upb_handlerattr_handlerdata(
+    const upb_handlerattr *attr) {
+  return attr->handler_data_;
+}
+
+/* upb_handlers */
+typedef void upb_handlers_callback(const void *closure, upb_handlers *h);
+upb_handlers *upb_handlers_new(const upb_msgdef *m,
+                               const void *owner);
+const upb_handlers *upb_handlers_newfrozen(const upb_msgdef *m,
+                                           const void *owner,
+                                           upb_handlers_callback *callback,
+                                           const void *closure);
+
+/* Include refcounted methods like upb_handlers_ref(). */
+UPB_REFCOUNTED_CMETHODS(upb_handlers, upb_handlers_upcast)
+
+const upb_status *upb_handlers_status(upb_handlers *h);
+void upb_handlers_clearerr(upb_handlers *h);
+const upb_msgdef *upb_handlers_msgdef(const upb_handlers *h);
+bool upb_handlers_addcleanup(upb_handlers *h, void *p, upb_handlerfree *hfree);
+bool upb_handlers_setunknown(upb_handlers *h, upb_unknown_handlerfunc *func,
+                             upb_handlerattr *attr);
+
+bool upb_handlers_setstartmsg(upb_handlers *h, upb_startmsg_handlerfunc *func,
+                              upb_handlerattr *attr);
+bool upb_handlers_setendmsg(upb_handlers *h, upb_endmsg_handlerfunc *func,
+                            upb_handlerattr *attr);
+bool upb_handlers_setint32(upb_handlers *h, const upb_fielddef *f,
+                           upb_int32_handlerfunc *func, upb_handlerattr *attr);
+bool upb_handlers_setint64(upb_handlers *h, const upb_fielddef *f,
+                           upb_int64_handlerfunc *func, upb_handlerattr *attr);
+bool upb_handlers_setuint32(upb_handlers *h, const upb_fielddef *f,
+                            upb_uint32_handlerfunc *func,
+                            upb_handlerattr *attr);
+bool upb_handlers_setuint64(upb_handlers *h, const upb_fielddef *f,
+                            upb_uint64_handlerfunc *func,
+                            upb_handlerattr *attr);
+bool upb_handlers_setfloat(upb_handlers *h, const upb_fielddef *f,
+                           upb_float_handlerfunc *func, upb_handlerattr *attr);
+bool upb_handlers_setdouble(upb_handlers *h, const upb_fielddef *f,
+                            upb_double_handlerfunc *func,
+                            upb_handlerattr *attr);
+bool upb_handlers_setbool(upb_handlers *h, const upb_fielddef *f,
+                          upb_bool_handlerfunc *func,
+                          upb_handlerattr *attr);
+bool upb_handlers_setstartstr(upb_handlers *h, const upb_fielddef *f,
+                              upb_startstr_handlerfunc *func,
+                              upb_handlerattr *attr);
+bool upb_handlers_setstring(upb_handlers *h, const upb_fielddef *f,
+                            upb_string_handlerfunc *func,
+                            upb_handlerattr *attr);
+bool upb_handlers_setendstr(upb_handlers *h, const upb_fielddef *f,
+                            upb_endfield_handlerfunc *func,
+                            upb_handlerattr *attr);
+bool upb_handlers_setstartseq(upb_handlers *h, const upb_fielddef *f,
+                              upb_startfield_handlerfunc *func,
+                              upb_handlerattr *attr);
+bool upb_handlers_setstartsubmsg(upb_handlers *h, const upb_fielddef *f,
+                                 upb_startfield_handlerfunc *func,
+                                 upb_handlerattr *attr);
+bool upb_handlers_setendsubmsg(upb_handlers *h, const upb_fielddef *f,
+                               upb_endfield_handlerfunc *func,
+                               upb_handlerattr *attr);
+bool upb_handlers_setendseq(upb_handlers *h, const upb_fielddef *f,
+                            upb_endfield_handlerfunc *func,
+                            upb_handlerattr *attr);
+
+bool upb_handlers_setsubhandlers(upb_handlers *h, const upb_fielddef *f,
+                                 const upb_handlers *sub);
+const upb_handlers *upb_handlers_getsubhandlers(const upb_handlers *h,
+                                                const upb_fielddef *f);
+const upb_handlers *upb_handlers_getsubhandlers_sel(const upb_handlers *h,
+                                                    upb_selector_t sel);
+
+UPB_INLINE upb_func *upb_handlers_gethandler(const upb_handlers *h,
+                                             upb_selector_t s) {
+  return (upb_func *)h->table[s].func;
+}
+
+bool upb_handlers_getattr(const upb_handlers *h, upb_selector_t s,
+                          upb_handlerattr *attr);
+
+UPB_INLINE const void *upb_handlers_gethandlerdata(const upb_handlers *h,
+                                                   upb_selector_t s) {
+  return upb_handlerattr_handlerdata(&h->table[s].attr);
+}
+
+#ifdef __cplusplus
+
+/* Handler types for single fields.
+ * Right now we only have one for TYPE_BYTES but ones for other types
+ * should follow.
+ *
+ * These follow the same handlers protocol for fields of a message. */
+class upb::BytesHandler {
+ public:
+  BytesHandler();
+  ~BytesHandler();
+#else
+struct upb_byteshandler {
+#endif
+  upb_handlers_tabent table[3];
+};
+
+void upb_byteshandler_init(upb_byteshandler *h);
+
+/* Caller must ensure that "d" outlives the handlers.
+ * TODO(haberman): should this have a "freeze" operation?  It's not necessary
+ * for memory management, but could be useful to force immutability and provide
+ * a convenient moment to verify that all registration succeeded. */
+bool upb_byteshandler_setstartstr(upb_byteshandler *h,
+                                  upb_startstr_handlerfunc *func, void *d);
+bool upb_byteshandler_setstring(upb_byteshandler *h,
+                                upb_string_handlerfunc *func, void *d);
+bool upb_byteshandler_setendstr(upb_byteshandler *h,
+                                upb_endfield_handlerfunc *func, void *d);
+
+/* "Static" methods */
+bool upb_handlers_freeze(upb_handlers *const *handlers, int n, upb_status *s);
+upb_handlertype_t upb_handlers_getprimitivehandlertype(const upb_fielddef *f);
+bool upb_handlers_getselector(const upb_fielddef *f, upb_handlertype_t type,
+                              upb_selector_t *s);
+UPB_INLINE upb_selector_t upb_handlers_getendselector(upb_selector_t start) {
+  return start + 1;
+}
+
+/* Internal-only. */
+uint32_t upb_handlers_selectorbaseoffset(const upb_fielddef *f);
+uint32_t upb_handlers_selectorcount(const upb_fielddef *f);
+
+UPB_END_EXTERN_C
+
+/*
+** Inline definitions for handlers.h, which are particularly long and a bit
+** tricky.
+*/
+
+#ifndef UPB_HANDLERS_INL_H_
+#define UPB_HANDLERS_INL_H_
+
+#include <limits.h>
+
+/* C inline methods. */
+
+/* upb_bufhandle */
+UPB_INLINE void upb_bufhandle_init(upb_bufhandle *h) {
+  h->obj_ = NULL;
+  h->objtype_ = NULL;
+  h->buf_ = NULL;
+  h->objofs_ = 0;
+}
+UPB_INLINE void upb_bufhandle_uninit(upb_bufhandle *h) {
+  UPB_UNUSED(h);
+}
+UPB_INLINE void upb_bufhandle_setobj(upb_bufhandle *h, const void *obj,
+                                     const void *type) {
+  h->obj_ = obj;
+  h->objtype_ = type;
+}
+UPB_INLINE void upb_bufhandle_setbuf(upb_bufhandle *h, const char *buf,
+                                     size_t ofs) {
+  h->buf_ = buf;
+  h->objofs_ = ofs;
+}
+UPB_INLINE const void *upb_bufhandle_obj(const upb_bufhandle *h) {
+  return h->obj_;
+}
+UPB_INLINE const void *upb_bufhandle_objtype(const upb_bufhandle *h) {
+  return h->objtype_;
+}
+UPB_INLINE const char *upb_bufhandle_buf(const upb_bufhandle *h) {
+  return h->buf_;
+}
+
+
+#ifdef __cplusplus
+
+/* Type detection and typedefs for integer types.
+ * For platforms where there are multiple 32-bit or 64-bit types, we need to be
+ * able to enumerate them so we can properly create overloads for all variants.
+ *
+ * If any platform existed where there were three integer types with the same
+ * size, this would have to become more complicated.  For example, short, int,
+ * and long could all be 32-bits.  Even more diabolically, short, int, long,
+ * and long long could all be 64 bits and still be standard-compliant.
+ * However, few platforms are this strange, and it's unlikely that upb will be
+ * used on the strangest ones. */
+
+/* Can't count on stdint.h limits like INT32_MAX, because in C++ these are
+ * only defined when __STDC_LIMIT_MACROS are defined before the *first* include
+ * of stdint.h.  We can't guarantee that someone else didn't include these first
+ * without defining __STDC_LIMIT_MACROS. */
+#define UPB_INT32_MAX 0x7fffffffLL
+#define UPB_INT32_MIN (-UPB_INT32_MAX - 1)
+#define UPB_INT64_MAX 0x7fffffffffffffffLL
+#define UPB_INT64_MIN (-UPB_INT64_MAX - 1)
+
+#if INT_MAX == UPB_INT32_MAX && INT_MIN == UPB_INT32_MIN
+#define UPB_INT_IS_32BITS 1
+#endif
+
+#if LONG_MAX == UPB_INT32_MAX && LONG_MIN == UPB_INT32_MIN
+#define UPB_LONG_IS_32BITS 1
+#endif
+
+#if LONG_MAX == UPB_INT64_MAX && LONG_MIN == UPB_INT64_MIN
+#define UPB_LONG_IS_64BITS 1
+#endif
+
+#if LLONG_MAX == UPB_INT64_MAX && LLONG_MIN == UPB_INT64_MIN
+#define UPB_LLONG_IS_64BITS 1
+#endif
+
+/* We use macros instead of typedefs so we can undefine them later and avoid
+ * leaking them outside this header file. */
+#if UPB_INT_IS_32BITS
+#define UPB_INT32_T int
+#define UPB_UINT32_T unsigned int
+
+#if UPB_LONG_IS_32BITS
+#define UPB_TWO_32BIT_TYPES 1
+#define UPB_INT32ALT_T long
+#define UPB_UINT32ALT_T unsigned long
+#endif  /* UPB_LONG_IS_32BITS */
+
+#elif UPB_LONG_IS_32BITS  /* && !UPB_INT_IS_32BITS */
+#define UPB_INT32_T long
+#define UPB_UINT32_T unsigned long
+#endif  /* UPB_INT_IS_32BITS */
+
+
+#if UPB_LONG_IS_64BITS
+#define UPB_INT64_T long
+#define UPB_UINT64_T unsigned long
+
+#if UPB_LLONG_IS_64BITS
+#define UPB_TWO_64BIT_TYPES 1
+#define UPB_INT64ALT_T long long
+#define UPB_UINT64ALT_T unsigned long long
+#endif  /* UPB_LLONG_IS_64BITS */
+
+#elif UPB_LLONG_IS_64BITS  /* && !UPB_LONG_IS_64BITS */
+#define UPB_INT64_T long long
+#define UPB_UINT64_T unsigned long long
+#endif  /* UPB_LONG_IS_64BITS */
+
+#undef UPB_INT32_MAX
+#undef UPB_INT32_MIN
+#undef UPB_INT64_MAX
+#undef UPB_INT64_MIN
+#undef UPB_INT_IS_32BITS
+#undef UPB_LONG_IS_32BITS
+#undef UPB_LONG_IS_64BITS
+#undef UPB_LLONG_IS_64BITS
+
+
+namespace upb {
+
+typedef void CleanupFunc(void *ptr);
+
+/* Template to remove "const" from "const T*" and just return "T*".
+ *
+ * We define a nonsense default because otherwise it will fail to instantiate as
+ * a function parameter type even in cases where we don't expect any caller to
+ * actually match the overload. */
+class CouldntRemoveConst {};
+template <class T> struct remove_constptr { typedef CouldntRemoveConst type; };
+template <class T> struct remove_constptr<const T *> { typedef T *type; };
+
+/* Template that we use below to remove a template specialization from
+ * consideration if it matches a specific type. */
+template <class T, class U> struct disable_if_same { typedef void Type; };
+template <class T> struct disable_if_same<T, T> {};
+
+template <class T> void DeletePointer(void *p) { delete static_cast<T>(p); }
+
+template <class T1, class T2>
+struct FirstUnlessVoidOrBool {
+  typedef T1 value;
+};
+
+template <class T2>
+struct FirstUnlessVoidOrBool<void, T2> {
+  typedef T2 value;
+};
+
+template <class T2>
+struct FirstUnlessVoidOrBool<bool, T2> {
+  typedef T2 value;
+};
+
+template<class T, class U>
+struct is_same {
+  static bool value;
+};
+
+template<class T>
+struct is_same<T, T> {
+  static bool value;
+};
+
+template<class T, class U>
+bool is_same<T, U>::value = false;
+
+template<class T>
+bool is_same<T, T>::value = true;
+
+/* FuncInfo *******************************************************************/
+
+/* Info about the user's original, pre-wrapped function. */
+template <class C, class R = void>
+struct FuncInfo {
+  /* The type of the closure that the function takes (its first param). */
+  typedef C Closure;
+
+  /* The return type. */
+  typedef R Return;
+};
+
+/* Func ***********************************************************************/
+
+/* Func1, Func2, Func3: Template classes representing a function and its
+ * signature.
+ *
+ * Since the function is a template parameter, calling the function can be
+ * inlined at compile-time and does not require a function pointer at runtime.
+ * These functions are not bound to a handler data so have no data or cleanup
+ * handler. */
+struct UnboundFunc {
+  CleanupFunc *GetCleanup() { return NULL; }
+  void *GetData() { return NULL; }
+};
+
+template <class R, class P1, R F(P1), class I>
+struct Func1 : public UnboundFunc {
+  typedef R Return;
+  typedef I FuncInfo;
+  static R Call(P1 p1) { return F(p1); }
+};
+
+template <class R, class P1, class P2, R F(P1, P2), class I>
+struct Func2 : public UnboundFunc {
+  typedef R Return;
+  typedef I FuncInfo;
+  static R Call(P1 p1, P2 p2) { return F(p1, p2); }
+};
+
+template <class R, class P1, class P2, class P3, R F(P1, P2, P3), class I>
+struct Func3 : public UnboundFunc {
+  typedef R Return;
+  typedef I FuncInfo;
+  static R Call(P1 p1, P2 p2, P3 p3) { return F(p1, p2, p3); }
+};
+
+template <class R, class P1, class P2, class P3, class P4, R F(P1, P2, P3, P4),
+          class I>
+struct Func4 : public UnboundFunc {
+  typedef R Return;
+  typedef I FuncInfo;
+  static R Call(P1 p1, P2 p2, P3 p3, P4 p4) { return F(p1, p2, p3, p4); }
+};
+
+template <class R, class P1, class P2, class P3, class P4, class P5,
+          R F(P1, P2, P3, P4, P5), class I>
+struct Func5 : public UnboundFunc {
+  typedef R Return;
+  typedef I FuncInfo;
+  static R Call(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5) {
+    return F(p1, p2, p3, p4, p5);
+  }
+};
+
+/* BoundFunc ******************************************************************/
+
+/* BoundFunc2, BoundFunc3: Like Func2/Func3 except also contains a value that
+ * shall be bound to the function's second parameter.
+ * 
+ * Note that the second parameter is a const pointer, but our stored bound value
+ * is non-const so we can free it when the handlers are destroyed. */
+template <class T>
+struct BoundFunc {
+  typedef typename remove_constptr<T>::type MutableP2;
+  explicit BoundFunc(MutableP2 data_) : data(data_) {}
+  CleanupFunc *GetCleanup() { return &DeletePointer<MutableP2>; }
+  MutableP2 GetData() { return data; }
+  MutableP2 data;
+};
+
+template <class R, class P1, class P2, R F(P1, P2), class I>
+struct BoundFunc2 : public BoundFunc<P2> {
+  typedef BoundFunc<P2> Base;
+  typedef I FuncInfo;
+  explicit BoundFunc2(typename Base::MutableP2 arg) : Base(arg) {}
+};
+
+template <class R, class P1, class P2, class P3, R F(P1, P2, P3), class I>
+struct BoundFunc3 : public BoundFunc<P2> {
+  typedef BoundFunc<P2> Base;
+  typedef I FuncInfo;
+  explicit BoundFunc3(typename Base::MutableP2 arg) : Base(arg) {}
+};
+
+template <class R, class P1, class P2, class P3, class P4, R F(P1, P2, P3, P4),
+          class I>
+struct BoundFunc4 : public BoundFunc<P2> {
+  typedef BoundFunc<P2> Base;
+  typedef I FuncInfo;
+  explicit BoundFunc4(typename Base::MutableP2 arg) : Base(arg) {}
+};
+
+template <class R, class P1, class P2, class P3, class P4, class P5,
+          R F(P1, P2, P3, P4, P5), class I>
+struct BoundFunc5 : public BoundFunc<P2> {
+  typedef BoundFunc<P2> Base;
+  typedef I FuncInfo;
+  explicit BoundFunc5(typename Base::MutableP2 arg) : Base(arg) {}
+};
+
+/* FuncSig ********************************************************************/
+
+/* FuncSig1, FuncSig2, FuncSig3: template classes reflecting a function
+ * *signature*, but without a specific function attached.
+ *
+ * These classes contain member functions that can be invoked with a
+ * specific function to return a Func/BoundFunc class. */
+template <class R, class P1>
+struct FuncSig1 {
+  template <R F(P1)>
+  Func1<R, P1, F, FuncInfo<P1, R> > GetFunc() {
+    return Func1<R, P1, F, FuncInfo<P1, R> >();
+  }
+};
+
+template <class R, class P1, class P2>
+struct FuncSig2 {
+  template <R F(P1, P2)>
+  Func2<R, P1, P2, F, FuncInfo<P1, R> > GetFunc() {
+    return Func2<R, P1, P2, F, FuncInfo<P1, R> >();
+  }
+
+  template <R F(P1, P2)>
+  BoundFunc2<R, P1, P2, F, FuncInfo<P1, R> > GetFunc(
+      typename remove_constptr<P2>::type param2) {
+    return BoundFunc2<R, P1, P2, F, FuncInfo<P1, R> >(param2);
+  }
+};
+
+template <class R, class P1, class P2, class P3>
+struct FuncSig3 {
+  template <R F(P1, P2, P3)>
+  Func3<R, P1, P2, P3, F, FuncInfo<P1, R> > GetFunc() {
+    return Func3<R, P1, P2, P3, F, FuncInfo<P1, R> >();
+  }
+
+  template <R F(P1, P2, P3)>
+  BoundFunc3<R, P1, P2, P3, F, FuncInfo<P1, R> > GetFunc(
+      typename remove_constptr<P2>::type param2) {
+    return BoundFunc3<R, P1, P2, P3, F, FuncInfo<P1, R> >(param2);
+  }
+};
+
+template <class R, class P1, class P2, class P3, class P4>
+struct FuncSig4 {
+  template <R F(P1, P2, P3, P4)>
+  Func4<R, P1, P2, P3, P4, F, FuncInfo<P1, R> > GetFunc() {
+    return Func4<R, P1, P2, P3, P4, F, FuncInfo<P1, R> >();
+  }
+
+  template <R F(P1, P2, P3, P4)>
+  BoundFunc4<R, P1, P2, P3, P4, F, FuncInfo<P1, R> > GetFunc(
+      typename remove_constptr<P2>::type param2) {
+    return BoundFunc4<R, P1, P2, P3, P4, F, FuncInfo<P1, R> >(param2);
+  }
+};
+
+template <class R, class P1, class P2, class P3, class P4, class P5>
+struct FuncSig5 {
+  template <R F(P1, P2, P3, P4, P5)>
+  Func5<R, P1, P2, P3, P4, P5, F, FuncInfo<P1, R> > GetFunc() {
+    return Func5<R, P1, P2, P3, P4, P5, F, FuncInfo<P1, R> >();
+  }
+
+  template <R F(P1, P2, P3, P4, P5)>
+  BoundFunc5<R, P1, P2, P3, P4, P5, F, FuncInfo<P1, R> > GetFunc(
+      typename remove_constptr<P2>::type param2) {
+    return BoundFunc5<R, P1, P2, P3, P4, P5, F, FuncInfo<P1, R> >(param2);
+  }
+};
+
+/* Overloaded template function that can construct the appropriate FuncSig*
+ * class given a function pointer by deducing the template parameters. */
+template <class R, class P1>
+inline FuncSig1<R, P1> MatchFunc(R (*f)(P1)) {
+  UPB_UNUSED(f);  /* Only used for template parameter deduction. */
+  return FuncSig1<R, P1>();
+}
+
+template <class R, class P1, class P2>
+inline FuncSig2<R, P1, P2> MatchFunc(R (*f)(P1, P2)) {
+  UPB_UNUSED(f);  /* Only used for template parameter deduction. */
+  return FuncSig2<R, P1, P2>();
+}
+
+template <class R, class P1, class P2, class P3>
+inline FuncSig3<R, P1, P2, P3> MatchFunc(R (*f)(P1, P2, P3)) {
+  UPB_UNUSED(f);  /* Only used for template parameter deduction. */
+  return FuncSig3<R, P1, P2, P3>();
+}
+
+template <class R, class P1, class P2, class P3, class P4>
+inline FuncSig4<R, P1, P2, P3, P4> MatchFunc(R (*f)(P1, P2, P3, P4)) {
+  UPB_UNUSED(f);  /* Only used for template parameter deduction. */
+  return FuncSig4<R, P1, P2, P3, P4>();
+}
+
+template <class R, class P1, class P2, class P3, class P4, class P5>
+inline FuncSig5<R, P1, P2, P3, P4, P5> MatchFunc(R (*f)(P1, P2, P3, P4, P5)) {
+  UPB_UNUSED(f);  /* Only used for template parameter deduction. */
+  return FuncSig5<R, P1, P2, P3, P4, P5>();
+}
+
+/* MethodSig ******************************************************************/
+
+/* CallMethod*: a function template that calls a given method. */
+template <class R, class C, R (C::*F)()>
+R CallMethod0(C *obj) {
+  return ((*obj).*F)();
+}
+
+template <class R, class C, class P1, R (C::*F)(P1)>
+R CallMethod1(C *obj, P1 arg1) {
+  return ((*obj).*F)(arg1);
+}
+
+template <class R, class C, class P1, class P2, R (C::*F)(P1, P2)>
+R CallMethod2(C *obj, P1 arg1, P2 arg2) {
+  return ((*obj).*F)(arg1, arg2);
+}
+
+template <class R, class C, class P1, class P2, class P3, R (C::*F)(P1, P2, P3)>
+R CallMethod3(C *obj, P1 arg1, P2 arg2, P3 arg3) {
+  return ((*obj).*F)(arg1, arg2, arg3);
+}
+
+template <class R, class C, class P1, class P2, class P3, class P4,
+          R (C::*F)(P1, P2, P3, P4)>
+R CallMethod4(C *obj, P1 arg1, P2 arg2, P3 arg3, P4 arg4) {
+  return ((*obj).*F)(arg1, arg2, arg3, arg4);
+}
+
+/* MethodSig: like FuncSig, but for member functions.
+ *
+ * GetFunc() returns a normal FuncN object, so after calling GetFunc() no
+ * more logic is required to special-case methods. */
+template <class R, class C>
+struct MethodSig0 {
+  template <R (C::*F)()>
+  Func1<R, C *, CallMethod0<R, C, F>, FuncInfo<C *, R> > GetFunc() {
+    return Func1<R, C *, CallMethod0<R, C, F>, FuncInfo<C *, R> >();
+  }
+};
+
+template <class R, class C, class P1>
+struct MethodSig1 {
+  template <R (C::*F)(P1)>
+  Func2<R, C *, P1, CallMethod1<R, C, P1, F>, FuncInfo<C *, R> > GetFunc() {
+    return Func2<R, C *, P1, CallMethod1<R, C, P1, F>, FuncInfo<C *, R> >();
+  }
+
+  template <R (C::*F)(P1)>
+  BoundFunc2<R, C *, P1, CallMethod1<R, C, P1, F>, FuncInfo<C *, R> > GetFunc(
+      typename remove_constptr<P1>::type param1) {
+    return BoundFunc2<R, C *, P1, CallMethod1<R, C, P1, F>, FuncInfo<C *, R> >(
+        param1);
+  }
+};
+
+template <class R, class C, class P1, class P2>
+struct MethodSig2 {
+  template <R (C::*F)(P1, P2)>
+  Func3<R, C *, P1, P2, CallMethod2<R, C, P1, P2, F>, FuncInfo<C *, R> >
+  GetFunc() {
+    return Func3<R, C *, P1, P2, CallMethod2<R, C, P1, P2, F>,
+                 FuncInfo<C *, R> >();
+  }
+
+  template <R (C::*F)(P1, P2)>
+  BoundFunc3<R, C *, P1, P2, CallMethod2<R, C, P1, P2, F>, FuncInfo<C *, R> >
+  GetFunc(typename remove_constptr<P1>::type param1) {
+    return BoundFunc3<R, C *, P1, P2, CallMethod2<R, C, P1, P2, F>,
+                      FuncInfo<C *, R> >(param1);
+  }
+};
+
+template <class R, class C, class P1, class P2, class P3>
+struct MethodSig3 {
+  template <R (C::*F)(P1, P2, P3)>
+  Func4<R, C *, P1, P2, P3, CallMethod3<R, C, P1, P2, P3, F>, FuncInfo<C *, R> >
+  GetFunc() {
+    return Func4<R, C *, P1, P2, P3, CallMethod3<R, C, P1, P2, P3, F>,
+                 FuncInfo<C *, R> >();
+  }
+
+  template <R (C::*F)(P1, P2, P3)>
+  BoundFunc4<R, C *, P1, P2, P3, CallMethod3<R, C, P1, P2, P3, F>,
+             FuncInfo<C *, R> >
+  GetFunc(typename remove_constptr<P1>::type param1) {
+    return BoundFunc4<R, C *, P1, P2, P3, CallMethod3<R, C, P1, P2, P3, F>,
+                      FuncInfo<C *, R> >(param1);
+  }
+};
+
+template <class R, class C, class P1, class P2, class P3, class P4>
+struct MethodSig4 {
+  template <R (C::*F)(P1, P2, P3, P4)>
+  Func5<R, C *, P1, P2, P3, P4, CallMethod4<R, C, P1, P2, P3, P4, F>,
+        FuncInfo<C *, R> >
+  GetFunc() {
+    return Func5<R, C *, P1, P2, P3, P4, CallMethod4<R, C, P1, P2, P3, P4, F>,
+                 FuncInfo<C *, R> >();
+  }
+
+  template <R (C::*F)(P1, P2, P3, P4)>
+  BoundFunc5<R, C *, P1, P2, P3, P4, CallMethod4<R, C, P1, P2, P3, P4, F>,
+             FuncInfo<C *, R> >
+  GetFunc(typename remove_constptr<P1>::type param1) {
+    return BoundFunc5<R, C *, P1, P2, P3, P4,
+                      CallMethod4<R, C, P1, P2, P3, P4, F>, FuncInfo<C *, R> >(
+        param1);
+  }
+};
+
+template <class R, class C>
+inline MethodSig0<R, C> MatchFunc(R (C::*f)()) {
+  UPB_UNUSED(f);  /* Only used for template parameter deduction. */
+  return MethodSig0<R, C>();
+}
+
+template <class R, class C, class P1>
+inline MethodSig1<R, C, P1> MatchFunc(R (C::*f)(P1)) {
+  UPB_UNUSED(f);  /* Only used for template parameter deduction. */
+  return MethodSig1<R, C, P1>();
+}
+
+template <class R, class C, class P1, class P2>
+inline MethodSig2<R, C, P1, P2> MatchFunc(R (C::*f)(P1, P2)) {
+  UPB_UNUSED(f);  /* Only used for template parameter deduction. */
+  return MethodSig2<R, C, P1, P2>();
+}
+
+template <class R, class C, class P1, class P2, class P3>
+inline MethodSig3<R, C, P1, P2, P3> MatchFunc(R (C::*f)(P1, P2, P3)) {
+  UPB_UNUSED(f);  /* Only used for template parameter deduction. */
+  return MethodSig3<R, C, P1, P2, P3>();
+}
+
+template <class R, class C, class P1, class P2, class P3, class P4>
+inline MethodSig4<R, C, P1, P2, P3, P4> MatchFunc(R (C::*f)(P1, P2, P3, P4)) {
+  UPB_UNUSED(f);  /* Only used for template parameter deduction. */
+  return MethodSig4<R, C, P1, P2, P3, P4>();
+}
+
+/* MaybeWrapReturn ************************************************************/
+
+/* Template class that attempts to wrap the return value of the function so it
+ * matches the expected type.  There are two main adjustments it may make:
+ *
+ *   1. If the function returns void, make it return the expected type and with
+ *      a value that always indicates success.
+ *   2. If the function returns bool, make it return the expected type with a
+ *      value that indicates success or failure.
+ *
+ * The "expected type" for return is:
+ *   1. void* for start handlers.  If the closure parameter has a different type
+ *      we will cast it to void* for the return in the success case.
+ *   2. size_t for string buffer handlers.
+ *   3. bool for everything else. */
+
+/* Template parameters are FuncN type and desired return type. */
+template <class F, class R, class Enable = void>
+struct MaybeWrapReturn;
+
+/* If the return type matches, return the given function unwrapped. */
+template <class F>
+struct MaybeWrapReturn<F, typename F::Return> {
+  typedef F Func;
+};
+
+/* Function wrapper that munges the return value from void to (bool)true. */
+template <class P1, class P2, void F(P1, P2)>
+bool ReturnTrue2(P1 p1, P2 p2) {
+  F(p1, p2);
+  return true;
+}
+
+template <class P1, class P2, class P3, void F(P1, P2, P3)>
+bool ReturnTrue3(P1 p1, P2 p2, P3 p3) {
+  F(p1, p2, p3);
+  return true;
+}
+
+/* Function wrapper that munges the return value from void to (void*)arg1  */
+template <class P1, class P2, void F(P1, P2)>
+void *ReturnClosure2(P1 p1, P2 p2) {
+  F(p1, p2);
+  return p1;
+}
+
+template <class P1, class P2, class P3, void F(P1, P2, P3)>
+void *ReturnClosure3(P1 p1, P2 p2, P3 p3) {
+  F(p1, p2, p3);
+  return p1;
+}
+
+/* Function wrapper that munges the return value from R to void*. */
+template <class R, class P1, class P2, R F(P1, P2)>
+void *CastReturnToVoidPtr2(P1 p1, P2 p2) {
+  return F(p1, p2);
+}
+
+template <class R, class P1, class P2, class P3, R F(P1, P2, P3)>
+void *CastReturnToVoidPtr3(P1 p1, P2 p2, P3 p3) {
+  return F(p1, p2, p3);
+}
+
+/* Function wrapper that munges the return value from bool to void*. */
+template <class P1, class P2, bool F(P1, P2)>
+void *ReturnClosureOrBreak2(P1 p1, P2 p2) {
+  return F(p1, p2) ? p1 : UPB_BREAK;
+}
+
+template <class P1, class P2, class P3, bool F(P1, P2, P3)>
+void *ReturnClosureOrBreak3(P1 p1, P2 p2, P3 p3) {
+  return F(p1, p2, p3) ? p1 : UPB_BREAK;
+}
+
+/* For the string callback, which takes five params, returns the size param. */
+template <class P1, class P2,
+          void F(P1, P2, const char *, size_t, const BufferHandle *)>
+size_t ReturnStringLen(P1 p1, P2 p2, const char *p3, size_t p4,
+                       const BufferHandle *p5) {
+  F(p1, p2, p3, p4, p5);
+  return p4;
+}
+
+/* For the string callback, which takes five params, returns the size param or
+ * zero. */
+template <class P1, class P2,
+          bool F(P1, P2, const char *, size_t, const BufferHandle *)>
+size_t ReturnNOr0(P1 p1, P2 p2, const char *p3, size_t p4,
+                  const BufferHandle *p5) {
+  return F(p1, p2, p3, p4, p5) ? p4 : 0;
+}
+
+/* If we have a function returning void but want a function returning bool, wrap
+ * it in a function that returns true. */
+template <class P1, class P2, void F(P1, P2), class I>
+struct MaybeWrapReturn<Func2<void, P1, P2, F, I>, bool> {
+  typedef Func2<bool, P1, P2, ReturnTrue2<P1, P2, F>, I> Func;
+};
+
+template <class P1, class P2, class P3, void F(P1, P2, P3), class I>
+struct MaybeWrapReturn<Func3<void, P1, P2, P3, F, I>, bool> {
+  typedef Func3<bool, P1, P2, P3, ReturnTrue3<P1, P2, P3, F>, I> Func;
+};
+
+/* If our function returns void but we want one returning void*, wrap it in a
+ * function that returns the first argument. */
+template <class P1, class P2, void F(P1, P2), class I>
+struct MaybeWrapReturn<Func2<void, P1, P2, F, I>, void *> {
+  typedef Func2<void *, P1, P2, ReturnClosure2<P1, P2, F>, I> Func;
+};
+
+template <class P1, class P2, class P3, void F(P1, P2, P3), class I>
+struct MaybeWrapReturn<Func3<void, P1, P2, P3, F, I>, void *> {
+  typedef Func3<void *, P1, P2, P3, ReturnClosure3<P1, P2, P3, F>, I> Func;
+};
+
+/* If our function returns R* but we want one returning void*, wrap it in a
+ * function that casts to void*. */
+template <class R, class P1, class P2, R *F(P1, P2), class I>
+struct MaybeWrapReturn<Func2<R *, P1, P2, F, I>, void *,
+                       typename disable_if_same<R *, void *>::Type> {
+  typedef Func2<void *, P1, P2, CastReturnToVoidPtr2<R *, P1, P2, F>, I> Func;
+};
+
+template <class R, class P1, class P2, class P3, R *F(P1, P2, P3), class I>
+struct MaybeWrapReturn<Func3<R *, P1, P2, P3, F, I>, void *,
+                       typename disable_if_same<R *, void *>::Type> {
+  typedef Func3<void *, P1, P2, P3, CastReturnToVoidPtr3<R *, P1, P2, P3, F>, I>
+      Func;
+};
+
+/* If our function returns bool but we want one returning void*, wrap it in a
+ * function that returns either the first param or UPB_BREAK. */
+template <class P1, class P2, bool F(P1, P2), class I>
+struct MaybeWrapReturn<Func2<bool, P1, P2, F, I>, void *> {
+  typedef Func2<void *, P1, P2, ReturnClosureOrBreak2<P1, P2, F>, I> Func;
+};
+
+template <class P1, class P2, class P3, bool F(P1, P2, P3), class I>
+struct MaybeWrapReturn<Func3<bool, P1, P2, P3, F, I>, void *> {
+  typedef Func3<void *, P1, P2, P3, ReturnClosureOrBreak3<P1, P2, P3, F>, I>
+      Func;
+};
+
+/* If our function returns void but we want one returning size_t, wrap it in a
+ * function that returns the size argument. */
+template <class P1, class P2,
+          void F(P1, P2, const char *, size_t, const BufferHandle *), class I>
+struct MaybeWrapReturn<
+    Func5<void, P1, P2, const char *, size_t, const BufferHandle *, F, I>,
+          size_t> {
+  typedef Func5<size_t, P1, P2, const char *, size_t, const BufferHandle *,
+                ReturnStringLen<P1, P2, F>, I> Func;
+};
+
+/* If our function returns bool but we want one returning size_t, wrap it in a
+ * function that returns either 0 or the buf size. */
+template <class P1, class P2,
+          bool F(P1, P2, const char *, size_t, const BufferHandle *), class I>
+struct MaybeWrapReturn<
+    Func5<bool, P1, P2, const char *, size_t, const BufferHandle *, F, I>,
+    size_t> {
+  typedef Func5<size_t, P1, P2, const char *, size_t, const BufferHandle *,
+                ReturnNOr0<P1, P2, F>, I> Func;
+};
+
+/* ConvertParams **************************************************************/
+
+/* Template class that converts the function parameters if necessary, and
+ * ignores the HandlerData parameter if appropriate.
+ *
+ * Template parameter is the are FuncN function type. */
+template <class F, class T>
+struct ConvertParams;
+
+/* Function that discards the handler data parameter. */
+template <class R, class P1, R F(P1)>
+R IgnoreHandlerData2(void *p1, const void *hd) {
+  UPB_UNUSED(hd);
+  return F(static_cast<P1>(p1));
+}
+
+template <class R, class P1, class P2Wrapper, class P2Wrapped,
+          R F(P1, P2Wrapped)>
+R IgnoreHandlerData3(void *p1, const void *hd, P2Wrapper p2) {
+  UPB_UNUSED(hd);
+  return F(static_cast<P1>(p1), p2);
+}
+
+template <class R, class P1, class P2, class P3, R F(P1, P2, P3)>
+R IgnoreHandlerData4(void *p1, const void *hd, P2 p2, P3 p3) {
+  UPB_UNUSED(hd);
+  return F(static_cast<P1>(p1), p2, p3);
+}
+
+template <class R, class P1, class P2, class P3, class P4, R F(P1, P2, P3, P4)>
+R IgnoreHandlerData5(void *p1, const void *hd, P2 p2, P3 p3, P4 p4) {
+  UPB_UNUSED(hd);
+  return F(static_cast<P1>(p1), p2, p3, p4);
+}
+
+template <class R, class P1, R F(P1, const char*, size_t)>
+R IgnoreHandlerDataIgnoreHandle(void *p1, const void *hd, const char *p2,
+                                size_t p3, const BufferHandle *handle) {
+  UPB_UNUSED(hd);
+  UPB_UNUSED(handle);
+  return F(static_cast<P1>(p1), p2, p3);
+}
+
+/* Function that casts the handler data parameter. */
+template <class R, class P1, class P2, R F(P1, P2)>
+R CastHandlerData2(void *c, const void *hd) {
+  return F(static_cast<P1>(c), static_cast<P2>(hd));
+}
+
+template <class R, class P1, class P2, class P3Wrapper, class P3Wrapped,
+          R F(P1, P2, P3Wrapped)>
+R CastHandlerData3(void *c, const void *hd, P3Wrapper p3) {
+  return F(static_cast<P1>(c), static_cast<P2>(hd), p3);
+}
+
+template <class R, class P1, class P2, class P3, class P4, class P5,
+          R F(P1, P2, P3, P4, P5)>
+R CastHandlerData5(void *c, const void *hd, P3 p3, P4 p4, P5 p5) {
+  return F(static_cast<P1>(c), static_cast<P2>(hd), p3, p4, p5);
+}
+
+template <class R, class P1, class P2, R F(P1, P2, const char *, size_t)>
+R CastHandlerDataIgnoreHandle(void *c, const void *hd, const char *p3,
+                              size_t p4, const BufferHandle *handle) {
+  UPB_UNUSED(handle);
+  return F(static_cast<P1>(c), static_cast<P2>(hd), p3, p4);
+}
+
+/* For unbound functions, ignore the handler data. */
+template <class R, class P1, R F(P1), class I, class T>
+struct ConvertParams<Func1<R, P1, F, I>, T> {
+  typedef Func2<R, void *, const void *, IgnoreHandlerData2<R, P1, F>, I> Func;
+};
+
+template <class R, class P1, class P2, R F(P1, P2), class I,
+          class R2, class P1_2, class P2_2, class P3_2>
+struct ConvertParams<Func2<R, P1, P2, F, I>,
+                     R2 (*)(P1_2, P2_2, P3_2)> {
+  typedef Func3<R, void *, const void *, P3_2,
+                IgnoreHandlerData3<R, P1, P3_2, P2, F>, I> Func;
+};
+
+/* For StringBuffer only; this ignores both the handler data and the
+ * BufferHandle. */
+template <class R, class P1, R F(P1, const char *, size_t), class I, class T>
+struct ConvertParams<Func3<R, P1, const char *, size_t, F, I>, T> {
+  typedef Func5<R, void *, const void *, const char *, size_t,
+                const BufferHandle *, IgnoreHandlerDataIgnoreHandle<R, P1, F>,
+                I> Func;
+};
+
+template <class R, class P1, class P2, class P3, class P4, R F(P1, P2, P3, P4),
+          class I, class T>
+struct ConvertParams<Func4<R, P1, P2, P3, P4, F, I>, T> {
+  typedef Func5<R, void *, const void *, P2, P3, P4,
+                IgnoreHandlerData5<R, P1, P2, P3, P4, F>, I> Func;
+};
+
+/* For bound functions, cast the handler data. */
+template <class R, class P1, class P2, R F(P1, P2), class I, class T>
+struct ConvertParams<BoundFunc2<R, P1, P2, F, I>, T> {
+  typedef Func2<R, void *, const void *, CastHandlerData2<R, P1, P2, F>, I>
+      Func;
+};
+
+template <class R, class P1, class P2, class P3, R F(P1, P2, P3), class I,
+          class R2, class P1_2, class P2_2, class P3_2>
+struct ConvertParams<BoundFunc3<R, P1, P2, P3, F, I>,
+                     R2 (*)(P1_2, P2_2, P3_2)> {
+  typedef Func3<R, void *, const void *, P3_2,
+                CastHandlerData3<R, P1, P2, P3_2, P3, F>, I> Func;
+};
+
+/* For StringBuffer only; this ignores the BufferHandle. */
+template <class R, class P1, class P2, R F(P1, P2, const char *, size_t),
+          class I, class T>
+struct ConvertParams<BoundFunc4<R, P1, P2, const char *, size_t, F, I>, T> {
+  typedef Func5<R, void *, const void *, const char *, size_t,
+                const BufferHandle *, CastHandlerDataIgnoreHandle<R, P1, P2, F>,
+                I> Func;
+};
+
+template <class R, class P1, class P2, class P3, class P4, class P5,
+          R F(P1, P2, P3, P4, P5), class I, class T>
+struct ConvertParams<BoundFunc5<R, P1, P2, P3, P4, P5, F, I>, T> {
+  typedef Func5<R, void *, const void *, P3, P4, P5,
+                CastHandlerData5<R, P1, P2, P3, P4, P5, F>, I> Func;
+};
+
+/* utype/ltype are upper/lower-case, ctype is canonical C type, vtype is
+ * variant C type. */
+#define TYPE_METHODS(utype, ltype, ctype, vtype)                               \
+  template <> struct CanonicalType<vtype> {                                    \
+    typedef ctype Type;                                                        \
+  };                                                                           \
+  template <>                                                                  \
+  inline bool Handlers::SetValueHandler<vtype>(                                \
+      const FieldDef *f,                                                       \
+      const Handlers::utype ## Handler& handler) {                             \
+    UPB_ASSERT(!handler.registered_);                                              \
+    handler.AddCleanup(this);                                                  \
+    handler.registered_ = true;                                                \
+    return upb_handlers_set##ltype(this, f, handler.handler_, &handler.attr_); \
+  }                                                                            \
+
+TYPE_METHODS(Double, double, double,   double)
+TYPE_METHODS(Float,  float,  float,    float)
+TYPE_METHODS(UInt64, uint64, uint64_t, UPB_UINT64_T)
+TYPE_METHODS(UInt32, uint32, uint32_t, UPB_UINT32_T)
+TYPE_METHODS(Int64,  int64,  int64_t,  UPB_INT64_T)
+TYPE_METHODS(Int32,  int32,  int32_t,  UPB_INT32_T)
+TYPE_METHODS(Bool,   bool,   bool,     bool)
+
+#ifdef UPB_TWO_32BIT_TYPES
+TYPE_METHODS(Int32,  int32,  int32_t,  UPB_INT32ALT_T)
+TYPE_METHODS(UInt32, uint32, uint32_t, UPB_UINT32ALT_T)
+#endif
+
+#ifdef UPB_TWO_64BIT_TYPES
+TYPE_METHODS(Int64,  int64,  int64_t,  UPB_INT64ALT_T)
+TYPE_METHODS(UInt64, uint64, uint64_t, UPB_UINT64ALT_T)
+#endif
+#undef TYPE_METHODS
+
+template <> struct CanonicalType<Status*> {
+  typedef Status* Type;
+};
+
+/* Type methods that are only one-per-canonical-type and not
+ * one-per-cvariant. */
+
+#define TYPE_METHODS(utype, ctype) \
+    inline bool Handlers::Set##utype##Handler(const FieldDef *f, \
+                                              const utype##Handler &h) { \
+      return SetValueHandler<ctype>(f, h); \
+    } \
+
+TYPE_METHODS(Double, double)
+TYPE_METHODS(Float,  float)
+TYPE_METHODS(UInt64, uint64_t)
+TYPE_METHODS(UInt32, uint32_t)
+TYPE_METHODS(Int64,  int64_t)
+TYPE_METHODS(Int32,  int32_t)
+TYPE_METHODS(Bool,   bool)
+#undef TYPE_METHODS
+
+template <class F> struct ReturnOf;
+
+template <class R, class P1, class P2>
+struct ReturnOf<R (*)(P1, P2)> {
+  typedef R Return;
+};
+
+template <class R, class P1, class P2, class P3>
+struct ReturnOf<R (*)(P1, P2, P3)> {
+  typedef R Return;
+};
+
+template <class R, class P1, class P2, class P3, class P4>
+struct ReturnOf<R (*)(P1, P2, P3, P4)> {
+  typedef R Return;
+};
+
+template <class R, class P1, class P2, class P3, class P4, class P5>
+struct ReturnOf<R (*)(P1, P2, P3, P4, P5)> {
+  typedef R Return;
+};
+
+template<class T> const void *UniquePtrForType() {
+  static const char ch = 0;
+  return &ch;
+}
+
+template <class T>
+template <class F>
+inline Handler<T>::Handler(F func)
+    : registered_(false),
+      cleanup_data_(func.GetData()),
+      cleanup_func_(func.GetCleanup()) {
+  upb_handlerattr_sethandlerdata(&attr_, func.GetData());
+  typedef typename ReturnOf<T>::Return Return;
+  typedef typename ConvertParams<F, T>::Func ConvertedParamsFunc;
+  typedef typename MaybeWrapReturn<ConvertedParamsFunc, Return>::Func
+      ReturnWrappedFunc;
+  handler_ = ReturnWrappedFunc().Call;
+
+  /* Set attributes based on what templates can statically tell us about the
+   * user's function. */
+
+  /* If the original function returns void, then we know that we wrapped it to
+   * always return ok. */
+  bool always_ok = is_same<typename F::FuncInfo::Return, void>::value;
+  attr_.SetAlwaysOk(always_ok);
+
+  /* Closure parameter and return type. */
+  attr_.SetClosureType(UniquePtrForType<typename F::FuncInfo::Closure>());
+
+  /* We use the closure type (from the first parameter) if the return type is
+   * void or bool, since these are the two cases we wrap to return the closure's
+   * type anyway.
+   *
+   * This is all nonsense for non START* handlers, but it doesn't matter because
+   * in that case the value will be ignored. */
+  typedef typename FirstUnlessVoidOrBool<typename F::FuncInfo::Return,
+                                         typename F::FuncInfo::Closure>::value
+      EffectiveReturn;
+  attr_.SetReturnClosureType(UniquePtrForType<EffectiveReturn>());
+}
+
+template <class T>
+inline Handler<T>::~Handler() {
+  UPB_ASSERT(registered_);
+}
+
+inline HandlerAttributes::HandlerAttributes() { upb_handlerattr_init(this); }
+inline HandlerAttributes::~HandlerAttributes() { upb_handlerattr_uninit(this); }
+inline bool HandlerAttributes::SetHandlerData(const void *hd) {
+  return upb_handlerattr_sethandlerdata(this, hd);
+}
+inline const void* HandlerAttributes::handler_data() const {
+  return upb_handlerattr_handlerdata(this);
+}
+inline bool HandlerAttributes::SetClosureType(const void *type) {
+  return upb_handlerattr_setclosuretype(this, type);
+}
+inline const void* HandlerAttributes::closure_type() const {
+  return upb_handlerattr_closuretype(this);
+}
+inline bool HandlerAttributes::SetReturnClosureType(const void *type) {
+  return upb_handlerattr_setreturnclosuretype(this, type);
+}
+inline const void* HandlerAttributes::return_closure_type() const {
+  return upb_handlerattr_returnclosuretype(this);
+}
+inline bool HandlerAttributes::SetAlwaysOk(bool always_ok) {
+  return upb_handlerattr_setalwaysok(this, always_ok);
+}
+inline bool HandlerAttributes::always_ok() const {
+  return upb_handlerattr_alwaysok(this);
+}
+
+inline BufferHandle::BufferHandle() { upb_bufhandle_init(this); }
+inline BufferHandle::~BufferHandle() { upb_bufhandle_uninit(this); }
+inline const char* BufferHandle::buffer() const {
+  return upb_bufhandle_buf(this);
+}
+inline size_t BufferHandle::object_offset() const {
+  return upb_bufhandle_objofs(this);
+}
+inline void BufferHandle::SetBuffer(const char* buf, size_t ofs) {
+  upb_bufhandle_setbuf(this, buf, ofs);
+}
+template <class T>
+void BufferHandle::SetAttachedObject(const T* obj) {
+  upb_bufhandle_setobj(this, obj, UniquePtrForType<T>());
+}
+template <class T>
+const T* BufferHandle::GetAttachedObject() const {
+  return upb_bufhandle_objtype(this) == UniquePtrForType<T>()
+      ? static_cast<const T *>(upb_bufhandle_obj(this))
+                               : NULL;
+}
+
+inline reffed_ptr<Handlers> Handlers::New(const MessageDef *m) {
+  upb_handlers *h = upb_handlers_new(m, &h);
+  return reffed_ptr<Handlers>(h, &h);
+}
+inline reffed_ptr<const Handlers> Handlers::NewFrozen(
+    const MessageDef *m, upb_handlers_callback *callback,
+    const void *closure) {
+  const upb_handlers *h = upb_handlers_newfrozen(m, &h, callback, closure);
+  return reffed_ptr<const Handlers>(h, &h);
+}
+inline const Status* Handlers::status() {
+  return upb_handlers_status(this);
+}
+inline void Handlers::ClearError() {
+  return upb_handlers_clearerr(this);
+}
+inline bool Handlers::Freeze(Status *s) {
+  upb::Handlers* h = this;
+  return upb_handlers_freeze(&h, 1, s);
+}
+inline bool Handlers::Freeze(Handlers *const *handlers, int n, Status *s) {
+  return upb_handlers_freeze(handlers, n, s);
+}
+inline bool Handlers::Freeze(const std::vector<Handlers*>& h, Status* status) {
+  return upb_handlers_freeze((Handlers* const*)&h[0], h.size(), status);
+}
+inline const MessageDef *Handlers::message_def() const {
+  return upb_handlers_msgdef(this);
+}
+inline bool Handlers::AddCleanup(void *p, upb_handlerfree *func) {
+  return upb_handlers_addcleanup(this, p, func);
+}
+inline bool Handlers::SetStartMessageHandler(
+    const Handlers::StartMessageHandler &handler) {
+  UPB_ASSERT(!handler.registered_);
+  handler.registered_ = true;
+  handler.AddCleanup(this);
+  return upb_handlers_setstartmsg(this, handler.handler_, &handler.attr_);
+}
+inline bool Handlers::SetEndMessageHandler(
+    const Handlers::EndMessageHandler &handler) {
+  UPB_ASSERT(!handler.registered_);
+  handler.registered_ = true;
+  handler.AddCleanup(this);
+  return upb_handlers_setendmsg(this, handler.handler_, &handler.attr_);
+}
+inline bool Handlers::SetStartStringHandler(const FieldDef *f,
+                                            const StartStringHandler &handler) {
+  UPB_ASSERT(!handler.registered_);
+  handler.registered_ = true;
+  handler.AddCleanup(this);
+  return upb_handlers_setstartstr(this, f, handler.handler_, &handler.attr_);
+}
+inline bool Handlers::SetEndStringHandler(const FieldDef *f,
+                                          const EndFieldHandler &handler) {
+  UPB_ASSERT(!handler.registered_);
+  handler.registered_ = true;
+  handler.AddCleanup(this);
+  return upb_handlers_setendstr(this, f, handler.handler_, &handler.attr_);
+}
+inline bool Handlers::SetStringHandler(const FieldDef *f,
+                                       const StringHandler& handler) {
+  UPB_ASSERT(!handler.registered_);
+  handler.registered_ = true;
+  handler.AddCleanup(this);
+  return upb_handlers_setstring(this, f, handler.handler_, &handler.attr_);
+}
+inline bool Handlers::SetStartSequenceHandler(
+    const FieldDef *f, const StartFieldHandler &handler) {
+  UPB_ASSERT(!handler.registered_);
+  handler.registered_ = true;
+  handler.AddCleanup(this);
+  return upb_handlers_setstartseq(this, f, handler.handler_, &handler.attr_);
+}
+inline bool Handlers::SetStartSubMessageHandler(
+    const FieldDef *f, const StartFieldHandler &handler) {
+  UPB_ASSERT(!handler.registered_);
+  handler.registered_ = true;
+  handler.AddCleanup(this);
+  return upb_handlers_setstartsubmsg(this, f, handler.handler_, &handler.attr_);
+}
+inline bool Handlers::SetEndSubMessageHandler(const FieldDef *f,
+                                              const EndFieldHandler &handler) {
+  UPB_ASSERT(!handler.registered_);
+  handler.registered_ = true;
+  handler.AddCleanup(this);
+  return upb_handlers_setendsubmsg(this, f, handler.handler_, &handler.attr_);
+}
+inline bool Handlers::SetEndSequenceHandler(const FieldDef *f,
+                                            const EndFieldHandler &handler) {
+  UPB_ASSERT(!handler.registered_);
+  handler.registered_ = true;
+  handler.AddCleanup(this);
+  return upb_handlers_setendseq(this, f, handler.handler_, &handler.attr_);
+}
+inline bool Handlers::SetSubHandlers(const FieldDef *f, const Handlers *sub) {
+  return upb_handlers_setsubhandlers(this, f, sub);
+}
+inline const Handlers *Handlers::GetSubHandlers(const FieldDef *f) const {
+  return upb_handlers_getsubhandlers(this, f);
+}
+inline const Handlers *Handlers::GetSubHandlers(Handlers::Selector sel) const {
+  return upb_handlers_getsubhandlers_sel(this, sel);
+}
+inline bool Handlers::GetSelector(const FieldDef *f, Handlers::Type type,
+                                  Handlers::Selector *s) {
+  return upb_handlers_getselector(f, type, s);
+}
+inline Handlers::Selector Handlers::GetEndSelector(Handlers::Selector start) {
+  return upb_handlers_getendselector(start);
+}
+inline Handlers::GenericFunction *Handlers::GetHandler(
+    Handlers::Selector selector) {
+  return upb_handlers_gethandler(this, selector);
+}
+inline const void *Handlers::GetHandlerData(Handlers::Selector selector) {
+  return upb_handlers_gethandlerdata(this, selector);
+}
+
+inline BytesHandler::BytesHandler() {
+  upb_byteshandler_init(this);
+}
+
+inline BytesHandler::~BytesHandler() {}
+
+}  /* namespace upb */
+
+#endif  /* __cplusplus */
+
+
+#undef UPB_TWO_32BIT_TYPES
+#undef UPB_TWO_64BIT_TYPES
+#undef UPB_INT32_T
+#undef UPB_UINT32_T
+#undef UPB_INT32ALT_T
+#undef UPB_UINT32ALT_T
+#undef UPB_INT64_T
+#undef UPB_UINT64_T
+#undef UPB_INT64ALT_T
+#undef UPB_UINT64ALT_T
+
+#endif  /* UPB_HANDLERS_INL_H_ */
+
+#endif  /* UPB_HANDLERS_H */
+/*
+** upb::Sink (upb_sink)
+** upb::BytesSink (upb_bytessink)
+**
+** A upb_sink is an object that binds a upb_handlers object to some runtime
+** state.  It is the object that can actually receive data via the upb_handlers
+** interface.
+**
+** Unlike upb_def and upb_handlers, upb_sink is never frozen, immutable, or
+** thread-safe.  You can create as many of them as you want, but each one may
+** only be used in a single thread at a time.
+**
+** If we compare with class-based OOP, a you can think of a upb_def as an
+** abstract base class, a upb_handlers as a concrete derived class, and a
+** upb_sink as an object (class instance).
+*/
+
+#ifndef UPB_SINK_H
+#define UPB_SINK_H
+
+
+#ifdef __cplusplus
+namespace upb {
+class BufferSink;
+class BufferSource;
+class BytesSink;
+class Sink;
+}
+#endif
+
+UPB_DECLARE_TYPE(upb::BufferSink, upb_bufsink)
+UPB_DECLARE_TYPE(upb::BufferSource, upb_bufsrc)
+UPB_DECLARE_TYPE(upb::BytesSink, upb_bytessink)
+UPB_DECLARE_TYPE(upb::Sink, upb_sink)
+
+#ifdef __cplusplus
+
+/* A upb::Sink is an object that binds a upb::Handlers object to some runtime
+ * state.  It represents an endpoint to which data can be sent.
+ *
+ * TODO(haberman): right now all of these functions take selectors.  Should they
+ * take selectorbase instead?
+ *
+ * ie. instead of calling:
+ *   sink->StartString(FOO_FIELD_START_STRING, ...)
+ * a selector base would let you say:
+ *   sink->StartString(FOO_FIELD, ...)
+ *
+ * This would make call sites a little nicer and require emitting fewer selector
+ * definitions in .h files.
+ *
+ * But the current scheme has the benefit that you can retrieve a function
+ * pointer for any handler with handlers->GetHandler(selector), without having
+ * to have a separate GetHandler() function for each handler type.  The JIT
+ * compiler uses this.  To accommodate we'd have to expose a separate
+ * GetHandler() for every handler type.
+ *
+ * Also to ponder: selectors right now are independent of a specific Handlers
+ * instance.  In other words, they allocate a number to every possible handler
+ * that *could* be registered, without knowing anything about what handlers
+ * *are* registered.  That means that using selectors as table offsets prohibits
+ * us from compacting the handler table at Freeze() time.  If the table is very
+ * sparse, this could be wasteful.
+ *
+ * Having another selector-like thing that is specific to a Handlers instance
+ * would allow this compacting, but then it would be impossible to write code
+ * ahead-of-time that can be bound to any Handlers instance at runtime.  For
+ * example, a .proto file parser written as straight C will not know what
+ * Handlers it will be bound to, so when it calls sink->StartString() what
+ * selector will it pass?  It needs a selector like we have today, that is
+ * independent of any particular upb::Handlers.
+ *
+ * Is there a way then to allow Handlers table compaction? */
+class upb::Sink {
+ public:
+  /* Constructor with no initialization; must be Reset() before use. */
+  Sink() {}
+
+  /* Constructs a new sink for the given frozen handlers and closure.
+   *
+   * TODO: once the Handlers know the expected closure type, verify that T
+   * matches it. */
+  template <class T> Sink(const Handlers* handlers, T* closure);
+
+  /* Resets the value of the sink. */
+  template <class T> void Reset(const Handlers* handlers, T* closure);
+
+  /* Returns the top-level object that is bound to this sink.
+   *
+   * TODO: once the Handlers know the expected closure type, verify that T
+   * matches it. */
+  template <class T> T* GetObject() const;
+
+  /* Functions for pushing data into the sink.
+   *
+   * These return false if processing should stop (either due to error or just
+   * to suspend).
+   *
+   * These may not be called from within one of the same sink's handlers (in
+   * other words, handlers are not re-entrant). */
+
+  /* Should be called at the start and end of every message; both the top-level
+   * message and submessages.  This means that submessages should use the
+   * following sequence:
+   *   sink->StartSubMessage(startsubmsg_selector);
+   *   sink->StartMessage();
+   *   // ...
+   *   sink->EndMessage(&status);
+   *   sink->EndSubMessage(endsubmsg_selector); */
+  bool StartMessage();
+  bool EndMessage(Status* status);
+
+  /* Putting of individual values.  These work for both repeated and
+   * non-repeated fields, but for repeated fields you must wrap them in
+   * calls to StartSequence()/EndSequence(). */
+  bool PutInt32(Handlers::Selector s, int32_t val);
+  bool PutInt64(Handlers::Selector s, int64_t val);
+  bool PutUInt32(Handlers::Selector s, uint32_t val);
+  bool PutUInt64(Handlers::Selector s, uint64_t val);
+  bool PutFloat(Handlers::Selector s, float val);
+  bool PutDouble(Handlers::Selector s, double val);
+  bool PutBool(Handlers::Selector s, bool val);
+
+  /* Putting of string/bytes values.  Each string can consist of zero or more
+   * non-contiguous buffers of data.
+   *
+   * For StartString(), the function will write a sink for the string to "sub."
+   * The sub-sink must be used for any/all PutStringBuffer() calls. */
+  bool StartString(Handlers::Selector s, size_t size_hint, Sink* sub);
+  size_t PutStringBuffer(Handlers::Selector s, const char *buf, size_t len,
+                         const BufferHandle *handle);
+  bool EndString(Handlers::Selector s);
+
+  /* For submessage fields.
+   *
+   * For StartSubMessage(), the function will write a sink for the string to
+   * "sub." The sub-sink must be used for any/all handlers called within the
+   * submessage. */
+  bool StartSubMessage(Handlers::Selector s, Sink* sub);
+  bool EndSubMessage(Handlers::Selector s);
+
+  /* For repeated fields of any type, the sequence of values must be wrapped in
+   * these calls.
+   *
+   * For StartSequence(), the function will write a sink for the string to
+   * "sub." The sub-sink must be used for any/all handlers called within the
+   * sequence. */
+  bool StartSequence(Handlers::Selector s, Sink* sub);
+  bool EndSequence(Handlers::Selector s);
+
+  /* Copy and assign specifically allowed.
+   * We don't even bother making these members private because so many
+   * functions need them and this is mainly just a dumb data container anyway.
+   */
+#else
+struct upb_sink {
+#endif
+  const upb_handlers *handlers;
+  void *closure;
+};
+
+#ifdef __cplusplus
+class upb::BytesSink {
+ public:
+  BytesSink() {}
+
+  /* Constructs a new sink for the given frozen handlers and closure.
+   *
+   * TODO(haberman): once the Handlers know the expected closure type, verify
+   * that T matches it. */
+  template <class T> BytesSink(const BytesHandler* handler, T* closure);
+
+  /* Resets the value of the sink. */
+  template <class T> void Reset(const BytesHandler* handler, T* closure);
+
+  bool Start(size_t size_hint, void **subc);
+  size_t PutBuffer(void *subc, const char *buf, size_t len,
+                   const BufferHandle *handle);
+  bool End();
+#else
+struct upb_bytessink {
+#endif
+  const upb_byteshandler *handler;
+  void *closure;
+};
+
+#ifdef __cplusplus
+
+/* A class for pushing a flat buffer of data to a BytesSink.
+ * You can construct an instance of this to get a resumable source,
+ * or just call the static PutBuffer() to do a non-resumable push all in one
+ * go. */
+class upb::BufferSource {
+ public:
+  BufferSource();
+  BufferSource(const char* buf, size_t len, BytesSink* sink);
+
+  /* Returns true if the entire buffer was pushed successfully.  Otherwise the
+   * next call to PutNext() will resume where the previous one left off.
+   * TODO(haberman): implement this. */
+  bool PutNext();
+
+  /* A static version; with this version is it not possible to resume in the
+   * case of failure or a partially-consumed buffer. */
+  static bool PutBuffer(const char* buf, size_t len, BytesSink* sink);
+
+  template <class T> static bool PutBuffer(const T& str, BytesSink* sink) {
+    return PutBuffer(str.c_str(), str.size(), sink);
+  }
+#else
+struct upb_bufsrc {
+  char dummy;
+#endif
+};
+
+UPB_BEGIN_EXTERN_C
+
+/* A class for accumulating output string data in a flat buffer. */
+
+upb_bufsink *upb_bufsink_new(upb_env *env);
+void upb_bufsink_free(upb_bufsink *sink);
+upb_bytessink *upb_bufsink_sink(upb_bufsink *sink);
+const char *upb_bufsink_getdata(const upb_bufsink *sink, size_t *len);
+
+/* Inline definitions. */
+
+UPB_INLINE void upb_bytessink_reset(upb_bytessink *s, const upb_byteshandler *h,
+                                    void *closure) {
+  s->handler = h;
+  s->closure = closure;
+}
+
+UPB_INLINE bool upb_bytessink_start(upb_bytessink *s, size_t size_hint,
+                                    void **subc) {
+  typedef upb_startstr_handlerfunc func;
+  func *start;
+  *subc = s->closure;
+  if (!s->handler) return true;
+  start = (func *)s->handler->table[UPB_STARTSTR_SELECTOR].func;
+
+  if (!start) return true;
+  *subc = start(s->closure, upb_handlerattr_handlerdata(
+                                &s->handler->table[UPB_STARTSTR_SELECTOR].attr),
+                size_hint);
+  return *subc != NULL;
+}
+
+UPB_INLINE size_t upb_bytessink_putbuf(upb_bytessink *s, void *subc,
+                                       const char *buf, size_t size,
+                                       const upb_bufhandle* handle) {
+  typedef upb_string_handlerfunc func;
+  func *putbuf;
+  if (!s->handler) return true;
+  putbuf = (func *)s->handler->table[UPB_STRING_SELECTOR].func;
+
+  if (!putbuf) return true;
+  return putbuf(subc, upb_handlerattr_handlerdata(
+                          &s->handler->table[UPB_STRING_SELECTOR].attr),
+                buf, size, handle);
+}
+
+UPB_INLINE bool upb_bytessink_end(upb_bytessink *s) {
+  typedef upb_endfield_handlerfunc func;
+  func *end;
+  if (!s->handler) return true;
+  end = (func *)s->handler->table[UPB_ENDSTR_SELECTOR].func;
+
+  if (!end) return true;
+  return end(s->closure,
+             upb_handlerattr_handlerdata(
+                 &s->handler->table[UPB_ENDSTR_SELECTOR].attr));
+}
+
+bool upb_bufsrc_putbuf(const char *buf, size_t len, upb_bytessink *sink);
+
+#define PUTVAL(type, ctype)                                                    \
+  UPB_INLINE bool upb_sink_put##type(upb_sink *s, upb_selector_t sel,          \
+                                     ctype val) {                              \
+    typedef upb_##type##_handlerfunc functype;                                 \
+    functype *func;                                                            \
+    const void *hd;                                                            \
+    if (!s->handlers) return true;                                             \
+    func = (functype *)upb_handlers_gethandler(s->handlers, sel);              \
+    if (!func) return true;                                                    \
+    hd = upb_handlers_gethandlerdata(s->handlers, sel);                        \
+    return func(s->closure, hd, val);                                          \
+  }
+
+PUTVAL(int32,  int32_t)
+PUTVAL(int64,  int64_t)
+PUTVAL(uint32, uint32_t)
+PUTVAL(uint64, uint64_t)
+PUTVAL(float,  float)
+PUTVAL(double, double)
+PUTVAL(bool,   bool)
+#undef PUTVAL
+
+UPB_INLINE void upb_sink_reset(upb_sink *s, const upb_handlers *h, void *c) {
+  s->handlers = h;
+  s->closure = c;
+}
+
+UPB_INLINE size_t upb_sink_putstring(upb_sink *s, upb_selector_t sel,
+                                     const char *buf, size_t n,
+                                     const upb_bufhandle *handle) {
+  typedef upb_string_handlerfunc func;
+  func *handler;
+  const void *hd;
+  if (!s->handlers) return n;
+  handler = (func *)upb_handlers_gethandler(s->handlers, sel);
+
+  if (!handler) return n;
+  hd = upb_handlers_gethandlerdata(s->handlers, sel);
+  return handler(s->closure, hd, buf, n, handle);
+}
+
+UPB_INLINE bool upb_sink_putunknown(upb_sink *s, const char *buf, size_t n) {
+  typedef upb_unknown_handlerfunc func;
+  func *handler;
+  const void *hd;
+  if (!s->handlers) return true;
+  handler = (func *)upb_handlers_gethandler(s->handlers, UPB_UNKNOWN_SELECTOR);
+
+  if (!handler) return n;
+  hd = upb_handlers_gethandlerdata(s->handlers, UPB_UNKNOWN_SELECTOR);
+  return handler(s->closure, hd, buf, n);
+}
+
+UPB_INLINE bool upb_sink_startmsg(upb_sink *s) {
+  typedef upb_startmsg_handlerfunc func;
+  func *startmsg;
+  const void *hd;
+  if (!s->handlers) return true;
+  startmsg = (func*)upb_handlers_gethandler(s->handlers, UPB_STARTMSG_SELECTOR);
+
+  if (!startmsg) return true;
+  hd = upb_handlers_gethandlerdata(s->handlers, UPB_STARTMSG_SELECTOR);
+  return startmsg(s->closure, hd);
+}
+
+UPB_INLINE bool upb_sink_endmsg(upb_sink *s, upb_status *status) {
+  typedef upb_endmsg_handlerfunc func;
+  func *endmsg;
+  const void *hd;
+  if (!s->handlers) return true;
+  endmsg = (func *)upb_handlers_gethandler(s->handlers, UPB_ENDMSG_SELECTOR);
+
+  if (!endmsg) return true;
+  hd = upb_handlers_gethandlerdata(s->handlers, UPB_ENDMSG_SELECTOR);
+  return endmsg(s->closure, hd, status);
+}
+
+UPB_INLINE bool upb_sink_startseq(upb_sink *s, upb_selector_t sel,
+                                  upb_sink *sub) {
+  typedef upb_startfield_handlerfunc func;
+  func *startseq;
+  const void *hd;
+  sub->closure = s->closure;
+  sub->handlers = s->handlers;
+  if (!s->handlers) return true;
+  startseq = (func*)upb_handlers_gethandler(s->handlers, sel);
+
+  if (!startseq) return true;
+  hd = upb_handlers_gethandlerdata(s->handlers, sel);
+  sub->closure = startseq(s->closure, hd);
+  return sub->closure ? true : false;
+}
+
+UPB_INLINE bool upb_sink_endseq(upb_sink *s, upb_selector_t sel) {
+  typedef upb_endfield_handlerfunc func;
+  func *endseq;
+  const void *hd;
+  if (!s->handlers) return true;
+  endseq = (func*)upb_handlers_gethandler(s->handlers, sel);
+
+  if (!endseq) return true;
+  hd = upb_handlers_gethandlerdata(s->handlers, sel);
+  return endseq(s->closure, hd);
+}
+
+UPB_INLINE bool upb_sink_startstr(upb_sink *s, upb_selector_t sel,
+                                  size_t size_hint, upb_sink *sub) {
+  typedef upb_startstr_handlerfunc func;
+  func *startstr;
+  const void *hd;
+  sub->closure = s->closure;
+  sub->handlers = s->handlers;
+  if (!s->handlers) return true;
+  startstr = (func*)upb_handlers_gethandler(s->handlers, sel);
+
+  if (!startstr) return true;
+  hd = upb_handlers_gethandlerdata(s->handlers, sel);
+  sub->closure = startstr(s->closure, hd, size_hint);
+  return sub->closure ? true : false;
+}
+
+UPB_INLINE bool upb_sink_endstr(upb_sink *s, upb_selector_t sel) {
+  typedef upb_endfield_handlerfunc func;
+  func *endstr;
+  const void *hd;
+  if (!s->handlers) return true;
+  endstr = (func*)upb_handlers_gethandler(s->handlers, sel);
+
+  if (!endstr) return true;
+  hd = upb_handlers_gethandlerdata(s->handlers, sel);
+  return endstr(s->closure, hd);
+}
+
+UPB_INLINE bool upb_sink_startsubmsg(upb_sink *s, upb_selector_t sel,
+                                     upb_sink *sub) {
+  typedef upb_startfield_handlerfunc func;
+  func *startsubmsg;
+  const void *hd;
+  sub->closure = s->closure;
+  if (!s->handlers) {
+    sub->handlers = NULL;
+    return true;
+  }
+  sub->handlers = upb_handlers_getsubhandlers_sel(s->handlers, sel);
+  startsubmsg = (func*)upb_handlers_gethandler(s->handlers, sel);
+
+  if (!startsubmsg) return true;
+  hd = upb_handlers_gethandlerdata(s->handlers, sel);
+  sub->closure = startsubmsg(s->closure, hd);
+  return sub->closure ? true : false;
+}
+
+UPB_INLINE bool upb_sink_endsubmsg(upb_sink *s, upb_selector_t sel) {
+  typedef upb_endfield_handlerfunc func;
+  func *endsubmsg;
+  const void *hd;
+  if (!s->handlers) return true;
+  endsubmsg = (func*)upb_handlers_gethandler(s->handlers, sel);
+
+  if (!endsubmsg) return s->closure;
+  hd = upb_handlers_gethandlerdata(s->handlers, sel);
+  return endsubmsg(s->closure, hd);
+}
+
+UPB_END_EXTERN_C
+
+#ifdef __cplusplus
+
+namespace upb {
+
+template <class T> Sink::Sink(const Handlers* handlers, T* closure) {
+  upb_sink_reset(this, handlers, closure);
+}
+template <class T>
+inline void Sink::Reset(const Handlers* handlers, T* closure) {
+  upb_sink_reset(this, handlers, closure);
+}
+inline bool Sink::StartMessage() {
+  return upb_sink_startmsg(this);
+}
+inline bool Sink::EndMessage(Status* status) {
+  return upb_sink_endmsg(this, status);
+}
+inline bool Sink::PutInt32(Handlers::Selector sel, int32_t val) {
+  return upb_sink_putint32(this, sel, val);
+}
+inline bool Sink::PutInt64(Handlers::Selector sel, int64_t val) {
+  return upb_sink_putint64(this, sel, val);
+}
+inline bool Sink::PutUInt32(Handlers::Selector sel, uint32_t val) {
+  return upb_sink_putuint32(this, sel, val);
+}
+inline bool Sink::PutUInt64(Handlers::Selector sel, uint64_t val) {
+  return upb_sink_putuint64(this, sel, val);
+}
+inline bool Sink::PutFloat(Handlers::Selector sel, float val) {
+  return upb_sink_putfloat(this, sel, val);
+}
+inline bool Sink::PutDouble(Handlers::Selector sel, double val) {
+  return upb_sink_putdouble(this, sel, val);
+}
+inline bool Sink::PutBool(Handlers::Selector sel, bool val) {
+  return upb_sink_putbool(this, sel, val);
+}
+inline bool Sink::StartString(Handlers::Selector sel, size_t size_hint,
+                              Sink *sub) {
+  return upb_sink_startstr(this, sel, size_hint, sub);
+}
+inline size_t Sink::PutStringBuffer(Handlers::Selector sel, const char *buf,
+                                    size_t len, const BufferHandle* handle) {
+  return upb_sink_putstring(this, sel, buf, len, handle);
+}
+inline bool Sink::EndString(Handlers::Selector sel) {
+  return upb_sink_endstr(this, sel);
+}
+inline bool Sink::StartSubMessage(Handlers::Selector sel, Sink* sub) {
+  return upb_sink_startsubmsg(this, sel, sub);
+}
+inline bool Sink::EndSubMessage(Handlers::Selector sel) {
+  return upb_sink_endsubmsg(this, sel);
+}
+inline bool Sink::StartSequence(Handlers::Selector sel, Sink* sub) {
+  return upb_sink_startseq(this, sel, sub);
+}
+inline bool Sink::EndSequence(Handlers::Selector sel) {
+  return upb_sink_endseq(this, sel);
+}
+
+template <class T>
+BytesSink::BytesSink(const BytesHandler* handler, T* closure) {
+  Reset(handler, closure);
+}
+
+template <class T>
+void BytesSink::Reset(const BytesHandler *handler, T *closure) {
+  upb_bytessink_reset(this, handler, closure);
+}
+inline bool BytesSink::Start(size_t size_hint, void **subc) {
+  return upb_bytessink_start(this, size_hint, subc);
+}
+inline size_t BytesSink::PutBuffer(void *subc, const char *buf, size_t len,
+                                   const BufferHandle *handle) {
+  return upb_bytessink_putbuf(this, subc, buf, len, handle);
+}
+inline bool BytesSink::End() {
+  return upb_bytessink_end(this);
+}
+
+inline bool BufferSource::PutBuffer(const char *buf, size_t len,
+                                    BytesSink *sink) {
+  return upb_bufsrc_putbuf(buf, len, sink);
+}
+
+}  /* namespace upb */
+#endif
+
+#endif
+
+#ifdef __cplusplus
+
+namespace upb {
+class Array;
+class Map;
+class MapIterator;
+class MessageFactory;
+class MessageLayout;
+class Visitor;
+class VisitorPlan;
+}
+
+#endif
+
+UPB_DECLARE_TYPE(upb::MessageFactory, upb_msgfactory)
+UPB_DECLARE_TYPE(upb::MessageLayout, upb_msglayout)
+UPB_DECLARE_TYPE(upb::Array, upb_array)
+UPB_DECLARE_TYPE(upb::Map, upb_map)
+UPB_DECLARE_TYPE(upb::MapIterator, upb_mapiter)
+UPB_DECLARE_TYPE(upb::Visitor, upb_visitor)
+UPB_DECLARE_TYPE(upb::VisitorPlan, upb_visitorplan)
+
+/* TODO(haberman): C++ accessors */
+
+UPB_BEGIN_EXTERN_C
+
+typedef void upb_msg;
+
+
+/** upb_msglayout *************************************************************/
+
+/* upb_msglayout represents the memory layout of a given upb_msgdef.  You get
+ * instances of this from a upb_msgfactory, and the factory always owns the
+ * msglayout. */
+
+
+/** upb_visitor ***************************************************************/
+
+/* upb_visitor will visit all the fields of a message and its submessages.  It
+ * uses a upb_visitorplan which you can obtain from a upb_msgfactory. */
+
+upb_visitor *upb_visitor_create(upb_env *e, const upb_visitorplan *vp,
+                                upb_sink *output);
+bool upb_visitor_visitmsg(upb_visitor *v, const upb_msg *msg);
+
+
+/** upb_msgfactory ************************************************************/
+
+/* A upb_msgfactory contains a cache of upb_msglayout, upb_handlers, and
+ * upb_visitorplan objects.  These are the objects necessary to represent,
+ * populate, and and visit upb_msg objects.
+ *
+ * These caches are all populated by upb_msgdef, and lazily created on demand.
+ */
+
+/* Creates and destroys a msgfactory, respectively.  The messages for this
+ * msgfactory must come from |symtab| (which should outlive the msgfactory). */
+upb_msgfactory *upb_msgfactory_new(const upb_symtab *symtab);
+void upb_msgfactory_free(upb_msgfactory *f);
+
+const upb_symtab *upb_msgfactory_symtab(const upb_msgfactory *f);
+
+/* The functions to get cached objects, lazily creating them on demand.  These
+ * all require:
+ *
+ * - m is in upb_msgfactory_symtab(f)
+ * - upb_msgdef_mapentry(m) == false (since map messages can't have layouts).
+ *
+ * The returned objects will live for as long as the msgfactory does.
+ *
+ * TODO(haberman): consider making this thread-safe and take a const
+ * upb_msgfactory. */
+const upb_msglayout *upb_msgfactory_getlayout(upb_msgfactory *f,
+                                              const upb_msgdef *m);
+const upb_handlers *upb_msgfactory_getmergehandlers(upb_msgfactory *f,
+                                                    const upb_msgdef *m);
+const upb_visitorplan *upb_msgfactory_getvisitorplan(upb_msgfactory *f,
+                                                     const upb_handlers *h);
+
+
+/** upb_stringview ************************************************************/
+
+typedef struct {
+  const char *data;
+  size_t size;
+} upb_stringview;
+
+UPB_INLINE upb_stringview upb_stringview_make(const char *data, size_t size) {
+  upb_stringview ret;
+  ret.data = data;
+  ret.size = size;
+  return ret;
+}
+
+#define UPB_STRINGVIEW_INIT(ptr, len) {ptr, len}
+
+
+/** upb_msgval ****************************************************************/
+
+/* A union representing all possible protobuf values.  Used for generic get/set
+ * operations. */
+
+typedef union {
+  bool b;
+  float flt;
+  double dbl;
+  int32_t i32;
+  int64_t i64;
+  uint32_t u32;
+  uint64_t u64;
+  const upb_map* map;
+  const upb_msg* msg;
+  const upb_array* arr;
+  const void* ptr;
+  upb_stringview str;
+} upb_msgval;
+
+#define ACCESSORS(name, membername, ctype) \
+  UPB_INLINE ctype upb_msgval_get ## name(upb_msgval v) { \
+    return v.membername; \
+  } \
+  UPB_INLINE void upb_msgval_set ## name(upb_msgval *v, ctype cval) { \
+    v->membername = cval; \
+  } \
+  UPB_INLINE upb_msgval upb_msgval_ ## name(ctype v) { \
+    upb_msgval ret; \
+    ret.membername = v; \
+    return ret; \
+  }
+
+ACCESSORS(bool,   b,   bool)
+ACCESSORS(float,  flt, float)
+ACCESSORS(double, dbl, double)
+ACCESSORS(int32,  i32, int32_t)
+ACCESSORS(int64,  i64, int64_t)
+ACCESSORS(uint32, u32, uint32_t)
+ACCESSORS(uint64, u64, uint64_t)
+ACCESSORS(map,    map, const upb_map*)
+ACCESSORS(msg,    msg, const upb_msg*)
+ACCESSORS(ptr,    ptr, const void*)
+ACCESSORS(arr,    arr, const upb_array*)
+ACCESSORS(str,    str, upb_stringview)
+
+#undef ACCESSORS
+
+UPB_INLINE upb_msgval upb_msgval_makestr(const char *data, size_t size) {
+  return upb_msgval_str(upb_stringview_make(data, size));
+}
+
+
+/** upb_msg *******************************************************************/
+
+/* A upb_msg represents a protobuf message.  It always corresponds to a specific
+ * upb_msglayout, which describes how it is laid out in memory.
+ *
+ * The message will have a fixed size, as returned by upb_msg_sizeof(), which
+ * will be used to store fixed-length fields.  The upb_msg may also allocate
+ * dynamic memory internally to store data such as:
+ *
+ * - extensions
+ * - unknown fields
+ */
+
+/* Returns the size of a message given this layout. */
+size_t upb_msg_sizeof(const upb_msglayout *l);
+
+/* upb_msg_init() / upb_msg_uninit() allow the user to use a pre-allocated
+ * block of memory as a message.  The block's size should be upb_msg_sizeof().
+ * upb_msg_uninit() must be called to release internally-allocated memory
+ * unless the allocator is an arena that does not require freeing.
+ *
+ * Please note that upb_msg_init() may return a value that is different than
+ * |msg|, so you must assign the return value and not cast your memory block
+ * to upb_msg* directly!
+ *
+ * Please note that upb_msg_uninit() does *not* free any submessages, maps,
+ * or arrays referred to by this message's fields.  You must free them manually
+ * yourself.
+ *
+ * upb_msg_uninit returns the original memory block, which may be useful if
+ * you dynamically allocated it (though upb_msg_new() would normally be more
+ * appropriate in this case). */
+upb_msg *upb_msg_init(void *msg, const upb_msglayout *l, upb_alloc *a);
+void *upb_msg_uninit(upb_msg *msg, const upb_msglayout *l);
+
+/* Like upb_msg_init() / upb_msg_uninit(), except the message's memory is
+ * allocated / freed from the given upb_alloc. */
+upb_msg *upb_msg_new(const upb_msglayout *l, upb_alloc *a);
+void upb_msg_free(upb_msg *msg, const upb_msglayout *l);
+
+/* Returns the upb_alloc for the given message.
+ * TODO(haberman): get rid of this?  Not sure we want to be storing this
+ * for every message. */
+upb_alloc *upb_msg_alloc(const upb_msg *msg);
+
+/* Packs the tree of messages rooted at "msg" into a single hunk of memory,
+ * allocated from the given allocator. */
+void *upb_msg_pack(const upb_msg *msg, const upb_msglayout *l,
+                   void *p, size_t *ofs, size_t size);
+
+/* Read-only message API.  Can be safely called by anyone. */
+
+/* Returns the value associated with this field:
+ *   - for scalar fields (including strings), the value directly.
+ *   - return upb_msg*, or upb_map* for msg/map.
+ *     If the field is unset for these field types, returns NULL.
+ *
+ * TODO(haberman): should we let users store cached array/map/msg
+ * pointers here for fields that are unset?  Could be useful for the
+ * strongly-owned submessage model (ie. generated C API that doesn't use
+ * arenas).
+ */
+upb_msgval upb_msg_get(const upb_msg *msg,
+                       int field_index,
+                       const upb_msglayout *l);
+
+/* May only be called for fields where upb_fielddef_haspresence(f) == true. */
+bool upb_msg_has(const upb_msg *msg,
+                 int field_index,
+                 const upb_msglayout *l);
+
+/* Mutable message API.  May only be called by the owner of the message who
+ * knows its ownership scheme and how to keep it consistent. */
+
+/* Sets the given field to the given value.  Does not perform any memory
+ * management: if you overwrite a pointer to a msg/array/map/string without
+ * cleaning it up (or using an arena) it will leak.
+ */
+void upb_msg_set(upb_msg *msg,
+                 int field_index,
+                 upb_msgval val,
+                 const upb_msglayout *l);
+
+/* For a primitive field, set it back to its default. For repeated, string, and
+ * submessage fields set it back to NULL.  This could involve releasing some
+ * internal memory (for example, from an extension dictionary), but it is not
+ * recursive in any way and will not recover any memory that may be used by
+ * arrays/maps/strings/msgs that this field may have pointed to.
+ */
+bool upb_msg_clearfield(upb_msg *msg,
+                        int field_index,
+                        const upb_msglayout *l);
+
+/* TODO(haberman): copyfrom()/mergefrom()? */
+
+
+/** upb_array *****************************************************************/
+
+/* A upb_array stores data for a repeated field.  The memory management
+ * semantics are the same as upb_msg.  A upb_array allocates dynamic
+ * memory internally for the array elements. */
+
+size_t upb_array_sizeof(upb_fieldtype_t type);
+void upb_array_init(upb_array *arr, upb_fieldtype_t type, upb_alloc *a);
+void upb_array_uninit(upb_array *arr);
+upb_array *upb_array_new(upb_fieldtype_t type, upb_alloc *a);
+void upb_array_free(upb_array *arr);
+
+/* Read-only interface.  Safe for anyone to call. */
+
+size_t upb_array_size(const upb_array *arr);
+upb_fieldtype_t upb_array_type(const upb_array *arr);
+upb_msgval upb_array_get(const upb_array *arr, size_t i);
+
+/* Write interface.  May only be called by the message's owner who can enforce
+ * its memory management invariants. */
+
+bool upb_array_set(upb_array *arr, size_t i, upb_msgval val);
+
+
+/** upb_map *******************************************************************/
+
+/* A upb_map stores data for a map field.  The memory management semantics are
+ * the same as upb_msg, with one notable exception.  upb_map will internally
+ * store a copy of all string keys, but *not* any string values or submessages.
+ * So you must ensure that any string or message values outlive the map, and you
+ * must delete them manually when they are no longer required. */
+
+size_t upb_map_sizeof(upb_fieldtype_t ktype, upb_fieldtype_t vtype);
+bool upb_map_init(upb_map *map, upb_fieldtype_t ktype, upb_fieldtype_t vtype,
+                  upb_alloc *a);
+void upb_map_uninit(upb_map *map);
+upb_map *upb_map_new(upb_fieldtype_t ktype, upb_fieldtype_t vtype, upb_alloc *a);
+void upb_map_free(upb_map *map);
+
+/* Read-only interface.  Safe for anyone to call. */
+
+size_t upb_map_size(const upb_map *map);
+upb_fieldtype_t upb_map_keytype(const upb_map *map);
+upb_fieldtype_t upb_map_valuetype(const upb_map *map);
+bool upb_map_get(const upb_map *map, upb_msgval key, upb_msgval *val);
+
+/* Write interface.  May only be called by the message's owner who can enforce
+ * its memory management invariants. */
+
+/* Sets or overwrites an entry in the map.  Return value indicates whether
+ * the operation succeeded or failed with OOM, and also whether an existing
+ * key was replaced or not. */
+bool upb_map_set(upb_map *map,
+                 upb_msgval key, upb_msgval val,
+                 upb_msgval *valremoved);
+
+/* Deletes an entry in the map.  Returns true if the key was present. */
+bool upb_map_del(upb_map *map, upb_msgval key);
+
+
+/** upb_mapiter ***************************************************************/
+
+/* For iterating over a map.  Map iterators are invalidated by mutations to the
+ * map, but an invalidated iterator will never return junk or crash the process.
+ * An invalidated iterator may return entries that were already returned though,
+ * and if you keep invalidating the iterator during iteration, the program may
+ * enter an infinite loop. */
+
+size_t upb_mapiter_sizeof();
+
+void upb_mapiter_begin(upb_mapiter *i, const upb_map *t);
+upb_mapiter *upb_mapiter_new(const upb_map *t, upb_alloc *a);
+void upb_mapiter_free(upb_mapiter *i, upb_alloc *a);
+void upb_mapiter_next(upb_mapiter *i);
+bool upb_mapiter_done(const upb_mapiter *i);
+
+upb_msgval upb_mapiter_key(const upb_mapiter *i);
+upb_msgval upb_mapiter_value(const upb_mapiter *i);
+void upb_mapiter_setdone(upb_mapiter *i);
+bool upb_mapiter_isequal(const upb_mapiter *i1, const upb_mapiter *i2);
+
+
+/** Handlers ******************************************************************/
+
+/* These are the handlers used internally by upb_msgfactory_getmergehandlers().
+ * They write scalar data to a known offset from the message pointer.
+ *
+ * These would be trivial for anyone to implement themselves, but it's better
+ * to use these because some JITs will recognize and specialize these instead
+ * of actually calling the function. */
+
+/* Sets a handler for the given primitive field that will write the data at the
+ * given offset.  If hasbit > 0, also sets a hasbit at the given bit offset
+ * (addressing each byte low to high). */
+bool upb_msg_setscalarhandler(upb_handlers *h,
+                              const upb_fielddef *f,
+                              size_t offset,
+                              int32_t hasbit);
+
+/* If the given handler is a msghandlers_primitive field, returns true and sets
+ * *type, *offset and *hasbit.  Otherwise returns false. */
+bool upb_msg_getscalarhandlerdata(const upb_handlers *h,
+                                  upb_selector_t s,
+                                  upb_fieldtype_t *type,
+                                  size_t *offset,
+                                  int32_t *hasbit);
+
+
+/** Interfaces for generated code *********************************************/
+
+#define UPB_NOT_IN_ONEOF UINT16_MAX
+#define UPB_NO_HASBIT UINT16_MAX
+#define UPB_NO_SUBMSG UINT16_MAX
+
+typedef struct {
+  uint32_t number;
+  uint32_t offset;  /* If in a oneof, offset of default in default_msg below. */
+  uint16_t hasbit;        /* UPB_NO_HASBIT if no hasbit. */
+  uint16_t oneof_index;   /* UPB_NOT_IN_ONEOF if not in a oneof. */
+  uint16_t submsg_index;  /* UPB_NO_SUBMSG if no submsg. */
+  uint8_t descriptortype;
+  uint8_t label;
+} upb_msglayout_fieldinit_v1;
+
+typedef struct {
+  uint32_t data_offset;
+  uint32_t case_offset;
+} upb_msglayout_oneofinit_v1;
+
+typedef struct upb_msglayout_msginit_v1 {
+  const struct upb_msglayout_msginit_v1 *const* submsgs;
+  const upb_msglayout_fieldinit_v1 *fields;
+  const upb_msglayout_oneofinit_v1 *oneofs;
+  void *default_msg;
+  /* Must be aligned to sizeof(void*).  Doesn't include internal members like
+   * unknown fields, extension dict, pointer to msglayout, etc. */
+  uint32_t size;
+  uint16_t field_count;
+  uint16_t oneof_count;
+  bool extendable;
+  bool is_proto2;
+} upb_msglayout_msginit_v1;
+
+#define UPB_ALIGN_UP_TO(val, align) ((val + (align - 1)) & -align)
+#define UPB_ALIGNED_SIZEOF(type) UPB_ALIGN_UP_TO(sizeof(type), sizeof(void*))
+
+/* Initialize/uninitialize a msglayout from a msginit.  If upb uses v1
+ * internally, this will not allocate any memory.  Should only be used by
+ * generated code. */
+upb_msglayout *upb_msglayout_frominit_v1(
+    const upb_msglayout_msginit_v1 *init, upb_alloc *a);
+void upb_msglayout_uninit_v1(upb_msglayout *layout, upb_alloc *a);
+
+UPB_END_EXTERN_C
+
+#endif /* UPB_MSG_H_ */
+
+UPB_BEGIN_EXTERN_C
+
+bool upb_decode(upb_stringview buf, void *msg,
+                const upb_msglayout_msginit_v1 *l, upb_env *env);
+
+UPB_END_EXTERN_C
+
+#endif  /* UPB_DECODE_H_ */
+/*
+** upb_encode: parsing into a upb_msg using a upb_msglayout.
+*/
+
+#ifndef UPB_ENCODE_H_
+#define UPB_ENCODE_H_
+
+
+UPB_BEGIN_EXTERN_C
+
+char *upb_encode(const void *msg, const upb_msglayout_msginit_v1 *l,
+                 upb_env *env, size_t *size);
+
+UPB_END_EXTERN_C
+
+#endif  /* UPB_ENCODE_H_ */
+/* This file was generated by upbc (the upb compiler) from the input
+ * file:
+ *
+ *     google/protobuf/descriptor.proto
+ *
+ * Do not edit -- your changes will be discarded when the file is
+ * regenerated. */
+
+#ifndef GOOGLE_PROTOBUF_DESCRIPTOR_PROTO_UPB_H_
+#define GOOGLE_PROTOBUF_DESCRIPTOR_PROTO_UPB_H_
+
+
+UPB_BEGIN_EXTERN_C
+
+struct google_protobuf_FileDescriptorSet;
+typedef struct google_protobuf_FileDescriptorSet google_protobuf_FileDescriptorSet;
+struct google_protobuf_FileDescriptorProto;
+typedef struct google_protobuf_FileDescriptorProto google_protobuf_FileDescriptorProto;
+struct google_protobuf_DescriptorProto;
+typedef struct google_protobuf_DescriptorProto google_protobuf_DescriptorProto;
+struct google_protobuf_DescriptorProto_ExtensionRange;
+typedef struct google_protobuf_DescriptorProto_ExtensionRange google_protobuf_DescriptorProto_ExtensionRange;
+struct google_protobuf_DescriptorProto_ReservedRange;
+typedef struct google_protobuf_DescriptorProto_ReservedRange google_protobuf_DescriptorProto_ReservedRange;
+struct google_protobuf_ExtensionRangeOptions;
+typedef struct google_protobuf_ExtensionRangeOptions google_protobuf_ExtensionRangeOptions;
+struct google_protobuf_FieldDescriptorProto;
+typedef struct google_protobuf_FieldDescriptorProto google_protobuf_FieldDescriptorProto;
+struct google_protobuf_OneofDescriptorProto;
+typedef struct google_protobuf_OneofDescriptorProto google_protobuf_OneofDescriptorProto;
+struct google_protobuf_EnumDescriptorProto;
+typedef struct google_protobuf_EnumDescriptorProto google_protobuf_EnumDescriptorProto;
+struct google_protobuf_EnumDescriptorProto_EnumReservedRange;
+typedef struct google_protobuf_EnumDescriptorProto_EnumReservedRange google_protobuf_EnumDescriptorProto_EnumReservedRange;
+struct google_protobuf_EnumValueDescriptorProto;
+typedef struct google_protobuf_EnumValueDescriptorProto google_protobuf_EnumValueDescriptorProto;
+struct google_protobuf_ServiceDescriptorProto;
+typedef struct google_protobuf_ServiceDescriptorProto google_protobuf_ServiceDescriptorProto;
+struct google_protobuf_MethodDescriptorProto;
+typedef struct google_protobuf_MethodDescriptorProto google_protobuf_MethodDescriptorProto;
+struct google_protobuf_FileOptions;
+typedef struct google_protobuf_FileOptions google_protobuf_FileOptions;
+struct google_protobuf_MessageOptions;
+typedef struct google_protobuf_MessageOptions google_protobuf_MessageOptions;
+struct google_protobuf_FieldOptions;
+typedef struct google_protobuf_FieldOptions google_protobuf_FieldOptions;
+struct google_protobuf_OneofOptions;
+typedef struct google_protobuf_OneofOptions google_protobuf_OneofOptions;
+struct google_protobuf_EnumOptions;
+typedef struct google_protobuf_EnumOptions google_protobuf_EnumOptions;
+struct google_protobuf_EnumValueOptions;
+typedef struct google_protobuf_EnumValueOptions google_protobuf_EnumValueOptions;
+struct google_protobuf_ServiceOptions;
+typedef struct google_protobuf_ServiceOptions google_protobuf_ServiceOptions;
+struct google_protobuf_MethodOptions;
+typedef struct google_protobuf_MethodOptions google_protobuf_MethodOptions;
+struct google_protobuf_UninterpretedOption;
+typedef struct google_protobuf_UninterpretedOption google_protobuf_UninterpretedOption;
+struct google_protobuf_UninterpretedOption_NamePart;
+typedef struct google_protobuf_UninterpretedOption_NamePart google_protobuf_UninterpretedOption_NamePart;
+struct google_protobuf_SourceCodeInfo;
+typedef struct google_protobuf_SourceCodeInfo google_protobuf_SourceCodeInfo;
+struct google_protobuf_SourceCodeInfo_Location;
+typedef struct google_protobuf_SourceCodeInfo_Location google_protobuf_SourceCodeInfo_Location;
+struct google_protobuf_GeneratedCodeInfo;
+typedef struct google_protobuf_GeneratedCodeInfo google_protobuf_GeneratedCodeInfo;
+struct google_protobuf_GeneratedCodeInfo_Annotation;
+typedef struct google_protobuf_GeneratedCodeInfo_Annotation google_protobuf_GeneratedCodeInfo_Annotation;
+/* Enums */
+
+typedef enum {
+  google_protobuf_FieldDescriptorProto_LABEL_OPTIONAL = 1,
+  google_protobuf_FieldDescriptorProto_LABEL_REQUIRED = 2,
+  google_protobuf_FieldDescriptorProto_LABEL_REPEATED = 3
+} google_protobuf_FieldDescriptorProto_Label;
+
+typedef enum {
+  google_protobuf_FieldDescriptorProto_TYPE_DOUBLE = 1,
+  google_protobuf_FieldDescriptorProto_TYPE_FLOAT = 2,
+  google_protobuf_FieldDescriptorProto_TYPE_INT64 = 3,
+  google_protobuf_FieldDescriptorProto_TYPE_UINT64 = 4,
+  google_protobuf_FieldDescriptorProto_TYPE_INT32 = 5,
+  google_protobuf_FieldDescriptorProto_TYPE_FIXED64 = 6,
+  google_protobuf_FieldDescriptorProto_TYPE_FIXED32 = 7,
+  google_protobuf_FieldDescriptorProto_TYPE_BOOL = 8,
+  google_protobuf_FieldDescriptorProto_TYPE_STRING = 9,
+  google_protobuf_FieldDescriptorProto_TYPE_GROUP = 10,
+  google_protobuf_FieldDescriptorProto_TYPE_MESSAGE = 11,
+  google_protobuf_FieldDescriptorProto_TYPE_BYTES = 12,
+  google_protobuf_FieldDescriptorProto_TYPE_UINT32 = 13,
+  google_protobuf_FieldDescriptorProto_TYPE_ENUM = 14,
+  google_protobuf_FieldDescriptorProto_TYPE_SFIXED32 = 15,
+  google_protobuf_FieldDescriptorProto_TYPE_SFIXED64 = 16,
+  google_protobuf_FieldDescriptorProto_TYPE_SINT32 = 17,
+  google_protobuf_FieldDescriptorProto_TYPE_SINT64 = 18
+} google_protobuf_FieldDescriptorProto_Type;
+
+typedef enum {
+  google_protobuf_FieldOptions_STRING = 0,
+  google_protobuf_FieldOptions_CORD = 1,
+  google_protobuf_FieldOptions_STRING_PIECE = 2
+} google_protobuf_FieldOptions_CType;
+
+typedef enum {
+  google_protobuf_FieldOptions_JS_NORMAL = 0,
+  google_protobuf_FieldOptions_JS_STRING = 1,
+  google_protobuf_FieldOptions_JS_NUMBER = 2
+} google_protobuf_FieldOptions_JSType;
+
+typedef enum {
+  google_protobuf_FileOptions_SPEED = 1,
+  google_protobuf_FileOptions_CODE_SIZE = 2,
+  google_protobuf_FileOptions_LITE_RUNTIME = 3
+} google_protobuf_FileOptions_OptimizeMode;
+
+typedef enum {
+  google_protobuf_MethodOptions_IDEMPOTENCY_UNKNOWN = 0,
+  google_protobuf_MethodOptions_NO_SIDE_EFFECTS = 1,
+  google_protobuf_MethodOptions_IDEMPOTENT = 2
+} google_protobuf_MethodOptions_IdempotencyLevel;
+
+/* google_protobuf_FileDescriptorSet */
+extern const upb_msglayout_msginit_v1 google_protobuf_FileDescriptorSet_msginit;
+google_protobuf_FileDescriptorSet *google_protobuf_FileDescriptorSet_new(upb_env *env);
+google_protobuf_FileDescriptorSet *google_protobuf_FileDescriptorSet_parsenew(upb_stringview buf, upb_env *env);
+char *google_protobuf_FileDescriptorSet_serialize(google_protobuf_FileDescriptorSet *msg, upb_env *env, size_t *len);
+void google_protobuf_FileDescriptorSet_free(google_protobuf_FileDescriptorSet *msg, upb_env *env);
+
+/* getters. */
+const upb_array* google_protobuf_FileDescriptorSet_file(const google_protobuf_FileDescriptorSet *msg);
+
+/* setters. */
+void google_protobuf_FileDescriptorSet_set_file(google_protobuf_FileDescriptorSet *msg, upb_array* value);
+
+
+/* google_protobuf_FileDescriptorProto */
+extern const upb_msglayout_msginit_v1 google_protobuf_FileDescriptorProto_msginit;
+google_protobuf_FileDescriptorProto *google_protobuf_FileDescriptorProto_new(upb_env *env);
+google_protobuf_FileDescriptorProto *google_protobuf_FileDescriptorProto_parsenew(upb_stringview buf, upb_env *env);
+char *google_protobuf_FileDescriptorProto_serialize(google_protobuf_FileDescriptorProto *msg, upb_env *env, size_t *len);
+void google_protobuf_FileDescriptorProto_free(google_protobuf_FileDescriptorProto *msg, upb_env *env);
+
+/* getters. */
+upb_stringview google_protobuf_FileDescriptorProto_name(const google_protobuf_FileDescriptorProto *msg);
+upb_stringview google_protobuf_FileDescriptorProto_package(const google_protobuf_FileDescriptorProto *msg);
+const upb_array* google_protobuf_FileDescriptorProto_dependency(const google_protobuf_FileDescriptorProto *msg);
+const upb_array* google_protobuf_FileDescriptorProto_message_type(const google_protobuf_FileDescriptorProto *msg);
+const upb_array* google_protobuf_FileDescriptorProto_enum_type(const google_protobuf_FileDescriptorProto *msg);
+const upb_array* google_protobuf_FileDescriptorProto_service(const google_protobuf_FileDescriptorProto *msg);
+const upb_array* google_protobuf_FileDescriptorProto_extension(const google_protobuf_FileDescriptorProto *msg);
+const google_protobuf_FileOptions* google_protobuf_FileDescriptorProto_options(const google_protobuf_FileDescriptorProto *msg);
+const google_protobuf_SourceCodeInfo* google_protobuf_FileDescriptorProto_source_code_info(const google_protobuf_FileDescriptorProto *msg);
+const upb_array* google_protobuf_FileDescriptorProto_public_dependency(const google_protobuf_FileDescriptorProto *msg);
+const upb_array* google_protobuf_FileDescriptorProto_weak_dependency(const google_protobuf_FileDescriptorProto *msg);
+upb_stringview google_protobuf_FileDescriptorProto_syntax(const google_protobuf_FileDescriptorProto *msg);
+
+/* setters. */
+void google_protobuf_FileDescriptorProto_set_name(google_protobuf_FileDescriptorProto *msg, upb_stringview value);
+void google_protobuf_FileDescriptorProto_set_package(google_protobuf_FileDescriptorProto *msg, upb_stringview value);
+void google_protobuf_FileDescriptorProto_set_dependency(google_protobuf_FileDescriptorProto *msg, upb_array* value);
+void google_protobuf_FileDescriptorProto_set_message_type(google_protobuf_FileDescriptorProto *msg, upb_array* value);
+void google_protobuf_FileDescriptorProto_set_enum_type(google_protobuf_FileDescriptorProto *msg, upb_array* value);
+void google_protobuf_FileDescriptorProto_set_service(google_protobuf_FileDescriptorProto *msg, upb_array* value);
+void google_protobuf_FileDescriptorProto_set_extension(google_protobuf_FileDescriptorProto *msg, upb_array* value);
+void google_protobuf_FileDescriptorProto_set_options(google_protobuf_FileDescriptorProto *msg, google_protobuf_FileOptions* value);
+void google_protobuf_FileDescriptorProto_set_source_code_info(google_protobuf_FileDescriptorProto *msg, google_protobuf_SourceCodeInfo* value);
+void google_protobuf_FileDescriptorProto_set_public_dependency(google_protobuf_FileDescriptorProto *msg, upb_array* value);
+void google_protobuf_FileDescriptorProto_set_weak_dependency(google_protobuf_FileDescriptorProto *msg, upb_array* value);
+void google_protobuf_FileDescriptorProto_set_syntax(google_protobuf_FileDescriptorProto *msg, upb_stringview value);
+
+
+/* google_protobuf_DescriptorProto */
+extern const upb_msglayout_msginit_v1 google_protobuf_DescriptorProto_msginit;
+google_protobuf_DescriptorProto *google_protobuf_DescriptorProto_new(upb_env *env);
+google_protobuf_DescriptorProto *google_protobuf_DescriptorProto_parsenew(upb_stringview buf, upb_env *env);
+char *google_protobuf_DescriptorProto_serialize(google_protobuf_DescriptorProto *msg, upb_env *env, size_t *len);
+void google_protobuf_DescriptorProto_free(google_protobuf_DescriptorProto *msg, upb_env *env);
+
+/* getters. */
+upb_stringview google_protobuf_DescriptorProto_name(const google_protobuf_DescriptorProto *msg);
+const upb_array* google_protobuf_DescriptorProto_field(const google_protobuf_DescriptorProto *msg);
+const upb_array* google_protobuf_DescriptorProto_nested_type(const google_protobuf_DescriptorProto *msg);
+const upb_array* google_protobuf_DescriptorProto_enum_type(const google_protobuf_DescriptorProto *msg);
+const upb_array* google_protobuf_DescriptorProto_extension_range(const google_protobuf_DescriptorProto *msg);
+const upb_array* google_protobuf_DescriptorProto_extension(const google_protobuf_DescriptorProto *msg);
+const google_protobuf_MessageOptions* google_protobuf_DescriptorProto_options(const google_protobuf_DescriptorProto *msg);
+const upb_array* google_protobuf_DescriptorProto_oneof_decl(const google_protobuf_DescriptorProto *msg);
+const upb_array* google_protobuf_DescriptorProto_reserved_range(const google_protobuf_DescriptorProto *msg);
+const upb_array* google_protobuf_DescriptorProto_reserved_name(const google_protobuf_DescriptorProto *msg);
+
+/* setters. */
+void google_protobuf_DescriptorProto_set_name(google_protobuf_DescriptorProto *msg, upb_stringview value);
+void google_protobuf_DescriptorProto_set_field(google_protobuf_DescriptorProto *msg, upb_array* value);
+void google_protobuf_DescriptorProto_set_nested_type(google_protobuf_DescriptorProto *msg, upb_array* value);
+void google_protobuf_DescriptorProto_set_enum_type(google_protobuf_DescriptorProto *msg, upb_array* value);
+void google_protobuf_DescriptorProto_set_extension_range(google_protobuf_DescriptorProto *msg, upb_array* value);
+void google_protobuf_DescriptorProto_set_extension(google_protobuf_DescriptorProto *msg, upb_array* value);
+void google_protobuf_DescriptorProto_set_options(google_protobuf_DescriptorProto *msg, google_protobuf_MessageOptions* value);
+void google_protobuf_DescriptorProto_set_oneof_decl(google_protobuf_DescriptorProto *msg, upb_array* value);
+void google_protobuf_DescriptorProto_set_reserved_range(google_protobuf_DescriptorProto *msg, upb_array* value);
+void google_protobuf_DescriptorProto_set_reserved_name(google_protobuf_DescriptorProto *msg, upb_array* value);
+
+
+/* google_protobuf_DescriptorProto_ExtensionRange */
+extern const upb_msglayout_msginit_v1 google_protobuf_DescriptorProto_ExtensionRange_msginit;
+google_protobuf_DescriptorProto_ExtensionRange *google_protobuf_DescriptorProto_ExtensionRange_new(upb_env *env);
+google_protobuf_DescriptorProto_ExtensionRange *google_protobuf_DescriptorProto_ExtensionRange_parsenew(upb_stringview buf, upb_env *env);
+char *google_protobuf_DescriptorProto_ExtensionRange_serialize(google_protobuf_DescriptorProto_ExtensionRange *msg, upb_env *env, size_t *len);
+void google_protobuf_DescriptorProto_ExtensionRange_free(google_protobuf_DescriptorProto_ExtensionRange *msg, upb_env *env);
+
+/* getters. */
+int32_t google_protobuf_DescriptorProto_ExtensionRange_start(const google_protobuf_DescriptorProto_ExtensionRange *msg);
+int32_t google_protobuf_DescriptorProto_ExtensionRange_end(const google_protobuf_DescriptorProto_ExtensionRange *msg);
+const google_protobuf_ExtensionRangeOptions* google_protobuf_DescriptorProto_ExtensionRange_options(const google_protobuf_DescriptorProto_ExtensionRange *msg);
+
+/* setters. */
+void google_protobuf_DescriptorProto_ExtensionRange_set_start(google_protobuf_DescriptorProto_ExtensionRange *msg, int32_t value);
+void google_protobuf_DescriptorProto_ExtensionRange_set_end(google_protobuf_DescriptorProto_ExtensionRange *msg, int32_t value);
+void google_protobuf_DescriptorProto_ExtensionRange_set_options(google_protobuf_DescriptorProto_ExtensionRange *msg, google_protobuf_ExtensionRangeOptions* value);
+
+
+/* google_protobuf_DescriptorProto_ReservedRange */
+extern const upb_msglayout_msginit_v1 google_protobuf_DescriptorProto_ReservedRange_msginit;
+google_protobuf_DescriptorProto_ReservedRange *google_protobuf_DescriptorProto_ReservedRange_new(upb_env *env);
+google_protobuf_DescriptorProto_ReservedRange *google_protobuf_DescriptorProto_ReservedRange_parsenew(upb_stringview buf, upb_env *env);
+char *google_protobuf_DescriptorProto_ReservedRange_serialize(google_protobuf_DescriptorProto_ReservedRange *msg, upb_env *env, size_t *len);
+void google_protobuf_DescriptorProto_ReservedRange_free(google_protobuf_DescriptorProto_ReservedRange *msg, upb_env *env);
+
+/* getters. */
+int32_t google_protobuf_DescriptorProto_ReservedRange_start(const google_protobuf_DescriptorProto_ReservedRange *msg);
+int32_t google_protobuf_DescriptorProto_ReservedRange_end(const google_protobuf_DescriptorProto_ReservedRange *msg);
+
+/* setters. */
+void google_protobuf_DescriptorProto_ReservedRange_set_start(google_protobuf_DescriptorProto_ReservedRange *msg, int32_t value);
+void google_protobuf_DescriptorProto_ReservedRange_set_end(google_protobuf_DescriptorProto_ReservedRange *msg, int32_t value);
+
+
+/* google_protobuf_ExtensionRangeOptions */
+extern const upb_msglayout_msginit_v1 google_protobuf_ExtensionRangeOptions_msginit;
+google_protobuf_ExtensionRangeOptions *google_protobuf_ExtensionRangeOptions_new(upb_env *env);
+google_protobuf_ExtensionRangeOptions *google_protobuf_ExtensionRangeOptions_parsenew(upb_stringview buf, upb_env *env);
+char *google_protobuf_ExtensionRangeOptions_serialize(google_protobuf_ExtensionRangeOptions *msg, upb_env *env, size_t *len);
+void google_protobuf_ExtensionRangeOptions_free(google_protobuf_ExtensionRangeOptions *msg, upb_env *env);
+
+/* getters. */
+const upb_array* google_protobuf_ExtensionRangeOptions_uninterpreted_option(const google_protobuf_ExtensionRangeOptions *msg);
+
+/* setters. */
+void google_protobuf_ExtensionRangeOptions_set_uninterpreted_option(google_protobuf_ExtensionRangeOptions *msg, upb_array* value);
+
+
+/* google_protobuf_FieldDescriptorProto */
+extern const upb_msglayout_msginit_v1 google_protobuf_FieldDescriptorProto_msginit;
+google_protobuf_FieldDescriptorProto *google_protobuf_FieldDescriptorProto_new(upb_env *env);
+google_protobuf_FieldDescriptorProto *google_protobuf_FieldDescriptorProto_parsenew(upb_stringview buf, upb_env *env);
+char *google_protobuf_FieldDescriptorProto_serialize(google_protobuf_FieldDescriptorProto *msg, upb_env *env, size_t *len);
+void google_protobuf_FieldDescriptorProto_free(google_protobuf_FieldDescriptorProto *msg, upb_env *env);
+
+/* getters. */
+upb_stringview google_protobuf_FieldDescriptorProto_name(const google_protobuf_FieldDescriptorProto *msg);
+upb_stringview google_protobuf_FieldDescriptorProto_extendee(const google_protobuf_FieldDescriptorProto *msg);
+int32_t google_protobuf_FieldDescriptorProto_number(const google_protobuf_FieldDescriptorProto *msg);
+google_protobuf_FieldDescriptorProto_Label google_protobuf_FieldDescriptorProto_label(const google_protobuf_FieldDescriptorProto *msg);
+google_protobuf_FieldDescriptorProto_Type google_protobuf_FieldDescriptorProto_type(const google_protobuf_FieldDescriptorProto *msg);
+upb_stringview google_protobuf_FieldDescriptorProto_type_name(const google_protobuf_FieldDescriptorProto *msg);
+upb_stringview google_protobuf_FieldDescriptorProto_default_value(const google_protobuf_FieldDescriptorProto *msg);
+const google_protobuf_FieldOptions* google_protobuf_FieldDescriptorProto_options(const google_protobuf_FieldDescriptorProto *msg);
+int32_t google_protobuf_FieldDescriptorProto_oneof_index(const google_protobuf_FieldDescriptorProto *msg);
+upb_stringview google_protobuf_FieldDescriptorProto_json_name(const google_protobuf_FieldDescriptorProto *msg);
+
+/* setters. */
+void google_protobuf_FieldDescriptorProto_set_name(google_protobuf_FieldDescriptorProto *msg, upb_stringview value);
+void google_protobuf_FieldDescriptorProto_set_extendee(google_protobuf_FieldDescriptorProto *msg, upb_stringview value);
+void google_protobuf_FieldDescriptorProto_set_number(google_protobuf_FieldDescriptorProto *msg, int32_t value);
+void google_protobuf_FieldDescriptorProto_set_label(google_protobuf_FieldDescriptorProto *msg, google_protobuf_FieldDescriptorProto_Label value);
+void google_protobuf_FieldDescriptorProto_set_type(google_protobuf_FieldDescriptorProto *msg, google_protobuf_FieldDescriptorProto_Type value);
+void google_protobuf_FieldDescriptorProto_set_type_name(google_protobuf_FieldDescriptorProto *msg, upb_stringview value);
+void google_protobuf_FieldDescriptorProto_set_default_value(google_protobuf_FieldDescriptorProto *msg, upb_stringview value);
+void google_protobuf_FieldDescriptorProto_set_options(google_protobuf_FieldDescriptorProto *msg, google_protobuf_FieldOptions* value);
+void google_protobuf_FieldDescriptorProto_set_oneof_index(google_protobuf_FieldDescriptorProto *msg, int32_t value);
+void google_protobuf_FieldDescriptorProto_set_json_name(google_protobuf_FieldDescriptorProto *msg, upb_stringview value);
+
+
+/* google_protobuf_OneofDescriptorProto */
+extern const upb_msglayout_msginit_v1 google_protobuf_OneofDescriptorProto_msginit;
+google_protobuf_OneofDescriptorProto *google_protobuf_OneofDescriptorProto_new(upb_env *env);
+google_protobuf_OneofDescriptorProto *google_protobuf_OneofDescriptorProto_parsenew(upb_stringview buf, upb_env *env);
+char *google_protobuf_OneofDescriptorProto_serialize(google_protobuf_OneofDescriptorProto *msg, upb_env *env, size_t *len);
+void google_protobuf_OneofDescriptorProto_free(google_protobuf_OneofDescriptorProto *msg, upb_env *env);
+
+/* getters. */
+upb_stringview google_protobuf_OneofDescriptorProto_name(const google_protobuf_OneofDescriptorProto *msg);
+const google_protobuf_OneofOptions* google_protobuf_OneofDescriptorProto_options(const google_protobuf_OneofDescriptorProto *msg);
+
+/* setters. */
+void google_protobuf_OneofDescriptorProto_set_name(google_protobuf_OneofDescriptorProto *msg, upb_stringview value);
+void google_protobuf_OneofDescriptorProto_set_options(google_protobuf_OneofDescriptorProto *msg, google_protobuf_OneofOptions* value);
+
+
+/* google_protobuf_EnumDescriptorProto */
+extern const upb_msglayout_msginit_v1 google_protobuf_EnumDescriptorProto_msginit;
+google_protobuf_EnumDescriptorProto *google_protobuf_EnumDescriptorProto_new(upb_env *env);
+google_protobuf_EnumDescriptorProto *google_protobuf_EnumDescriptorProto_parsenew(upb_stringview buf, upb_env *env);
+char *google_protobuf_EnumDescriptorProto_serialize(google_protobuf_EnumDescriptorProto *msg, upb_env *env, size_t *len);
+void google_protobuf_EnumDescriptorProto_free(google_protobuf_EnumDescriptorProto *msg, upb_env *env);
+
+/* getters. */
+upb_stringview google_protobuf_EnumDescriptorProto_name(const google_protobuf_EnumDescriptorProto *msg);
+const upb_array* google_protobuf_EnumDescriptorProto_value(const google_protobuf_EnumDescriptorProto *msg);
+const google_protobuf_EnumOptions* google_protobuf_EnumDescriptorProto_options(const google_protobuf_EnumDescriptorProto *msg);
+const upb_array* google_protobuf_EnumDescriptorProto_reserved_range(const google_protobuf_EnumDescriptorProto *msg);
+const upb_array* google_protobuf_EnumDescriptorProto_reserved_name(const google_protobuf_EnumDescriptorProto *msg);
+
+/* setters. */
+void google_protobuf_EnumDescriptorProto_set_name(google_protobuf_EnumDescriptorProto *msg, upb_stringview value);
+void google_protobuf_EnumDescriptorProto_set_value(google_protobuf_EnumDescriptorProto *msg, upb_array* value);
+void google_protobuf_EnumDescriptorProto_set_options(google_protobuf_EnumDescriptorProto *msg, google_protobuf_EnumOptions* value);
+void google_protobuf_EnumDescriptorProto_set_reserved_range(google_protobuf_EnumDescriptorProto *msg, upb_array* value);
+void google_protobuf_EnumDescriptorProto_set_reserved_name(google_protobuf_EnumDescriptorProto *msg, upb_array* value);
+
+
+/* google_protobuf_EnumDescriptorProto_EnumReservedRange */
+extern const upb_msglayout_msginit_v1 google_protobuf_EnumDescriptorProto_EnumReservedRange_msginit;
+google_protobuf_EnumDescriptorProto_EnumReservedRange *google_protobuf_EnumDescriptorProto_EnumReservedRange_new(upb_env *env);
+google_protobuf_EnumDescriptorProto_EnumReservedRange *google_protobuf_EnumDescriptorProto_EnumReservedRange_parsenew(upb_stringview buf, upb_env *env);
+char *google_protobuf_EnumDescriptorProto_EnumReservedRange_serialize(google_protobuf_EnumDescriptorProto_EnumReservedRange *msg, upb_env *env, size_t *len);
+void google_protobuf_EnumDescriptorProto_EnumReservedRange_free(google_protobuf_EnumDescriptorProto_EnumReservedRange *msg, upb_env *env);
+
+/* getters. */
+int32_t google_protobuf_EnumDescriptorProto_EnumReservedRange_start(const google_protobuf_EnumDescriptorProto_EnumReservedRange *msg);
+int32_t google_protobuf_EnumDescriptorProto_EnumReservedRange_end(const google_protobuf_EnumDescriptorProto_EnumReservedRange *msg);
+
+/* setters. */
+void google_protobuf_EnumDescriptorProto_EnumReservedRange_set_start(google_protobuf_EnumDescriptorProto_EnumReservedRange *msg, int32_t value);
+void google_protobuf_EnumDescriptorProto_EnumReservedRange_set_end(google_protobuf_EnumDescriptorProto_EnumReservedRange *msg, int32_t value);
+
+
+/* google_protobuf_EnumValueDescriptorProto */
+extern const upb_msglayout_msginit_v1 google_protobuf_EnumValueDescriptorProto_msginit;
+google_protobuf_EnumValueDescriptorProto *google_protobuf_EnumValueDescriptorProto_new(upb_env *env);
+google_protobuf_EnumValueDescriptorProto *google_protobuf_EnumValueDescriptorProto_parsenew(upb_stringview buf, upb_env *env);
+char *google_protobuf_EnumValueDescriptorProto_serialize(google_protobuf_EnumValueDescriptorProto *msg, upb_env *env, size_t *len);
+void google_protobuf_EnumValueDescriptorProto_free(google_protobuf_EnumValueDescriptorProto *msg, upb_env *env);
+
+/* getters. */
+upb_stringview google_protobuf_EnumValueDescriptorProto_name(const google_protobuf_EnumValueDescriptorProto *msg);
+int32_t google_protobuf_EnumValueDescriptorProto_number(const google_protobuf_EnumValueDescriptorProto *msg);
+const google_protobuf_EnumValueOptions* google_protobuf_EnumValueDescriptorProto_options(const google_protobuf_EnumValueDescriptorProto *msg);
+
+/* setters. */
+void google_protobuf_EnumValueDescriptorProto_set_name(google_protobuf_EnumValueDescriptorProto *msg, upb_stringview value);
+void google_protobuf_EnumValueDescriptorProto_set_number(google_protobuf_EnumValueDescriptorProto *msg, int32_t value);
+void google_protobuf_EnumValueDescriptorProto_set_options(google_protobuf_EnumValueDescriptorProto *msg, google_protobuf_EnumValueOptions* value);
+
+
+/* google_protobuf_ServiceDescriptorProto */
+extern const upb_msglayout_msginit_v1 google_protobuf_ServiceDescriptorProto_msginit;
+google_protobuf_ServiceDescriptorProto *google_protobuf_ServiceDescriptorProto_new(upb_env *env);
+google_protobuf_ServiceDescriptorProto *google_protobuf_ServiceDescriptorProto_parsenew(upb_stringview buf, upb_env *env);
+char *google_protobuf_ServiceDescriptorProto_serialize(google_protobuf_ServiceDescriptorProto *msg, upb_env *env, size_t *len);
+void google_protobuf_ServiceDescriptorProto_free(google_protobuf_ServiceDescriptorProto *msg, upb_env *env);
+
+/* getters. */
+upb_stringview google_protobuf_ServiceDescriptorProto_name(const google_protobuf_ServiceDescriptorProto *msg);
+const upb_array* google_protobuf_ServiceDescriptorProto_method(const google_protobuf_ServiceDescriptorProto *msg);
+const google_protobuf_ServiceOptions* google_protobuf_ServiceDescriptorProto_options(const google_protobuf_ServiceDescriptorProto *msg);
+
+/* setters. */
+void google_protobuf_ServiceDescriptorProto_set_name(google_protobuf_ServiceDescriptorProto *msg, upb_stringview value);
+void google_protobuf_ServiceDescriptorProto_set_method(google_protobuf_ServiceDescriptorProto *msg, upb_array* value);
+void google_protobuf_ServiceDescriptorProto_set_options(google_protobuf_ServiceDescriptorProto *msg, google_protobuf_ServiceOptions* value);
+
+
+/* google_protobuf_MethodDescriptorProto */
+extern const upb_msglayout_msginit_v1 google_protobuf_MethodDescriptorProto_msginit;
+google_protobuf_MethodDescriptorProto *google_protobuf_MethodDescriptorProto_new(upb_env *env);
+google_protobuf_MethodDescriptorProto *google_protobuf_MethodDescriptorProto_parsenew(upb_stringview buf, upb_env *env);
+char *google_protobuf_MethodDescriptorProto_serialize(google_protobuf_MethodDescriptorProto *msg, upb_env *env, size_t *len);
+void google_protobuf_MethodDescriptorProto_free(google_protobuf_MethodDescriptorProto *msg, upb_env *env);
+
+/* getters. */
+upb_stringview google_protobuf_MethodDescriptorProto_name(const google_protobuf_MethodDescriptorProto *msg);
+upb_stringview google_protobuf_MethodDescriptorProto_input_type(const google_protobuf_MethodDescriptorProto *msg);
+upb_stringview google_protobuf_MethodDescriptorProto_output_type(const google_protobuf_MethodDescriptorProto *msg);
+const google_protobuf_MethodOptions* google_protobuf_MethodDescriptorProto_options(const google_protobuf_MethodDescriptorProto *msg);
+bool google_protobuf_MethodDescriptorProto_client_streaming(const google_protobuf_MethodDescriptorProto *msg);
+bool google_protobuf_MethodDescriptorProto_server_streaming(const google_protobuf_MethodDescriptorProto *msg);
+
+/* setters. */
+void google_protobuf_MethodDescriptorProto_set_name(google_protobuf_MethodDescriptorProto *msg, upb_stringview value);
+void google_protobuf_MethodDescriptorProto_set_input_type(google_protobuf_MethodDescriptorProto *msg, upb_stringview value);
+void google_protobuf_MethodDescriptorProto_set_output_type(google_protobuf_MethodDescriptorProto *msg, upb_stringview value);
+void google_protobuf_MethodDescriptorProto_set_options(google_protobuf_MethodDescriptorProto *msg, google_protobuf_MethodOptions* value);
+void google_protobuf_MethodDescriptorProto_set_client_streaming(google_protobuf_MethodDescriptorProto *msg, bool value);
+void google_protobuf_MethodDescriptorProto_set_server_streaming(google_protobuf_MethodDescriptorProto *msg, bool value);
+
+
+/* google_protobuf_FileOptions */
+extern const upb_msglayout_msginit_v1 google_protobuf_FileOptions_msginit;
+google_protobuf_FileOptions *google_protobuf_FileOptions_new(upb_env *env);
+google_protobuf_FileOptions *google_protobuf_FileOptions_parsenew(upb_stringview buf, upb_env *env);
+char *google_protobuf_FileOptions_serialize(google_protobuf_FileOptions *msg, upb_env *env, size_t *len);
+void google_protobuf_FileOptions_free(google_protobuf_FileOptions *msg, upb_env *env);
+
+/* getters. */
+upb_stringview google_protobuf_FileOptions_java_package(const google_protobuf_FileOptions *msg);
+upb_stringview google_protobuf_FileOptions_java_outer_classname(const google_protobuf_FileOptions *msg);
+google_protobuf_FileOptions_OptimizeMode google_protobuf_FileOptions_optimize_for(const google_protobuf_FileOptions *msg);
+bool google_protobuf_FileOptions_java_multiple_files(const google_protobuf_FileOptions *msg);
+upb_stringview google_protobuf_FileOptions_go_package(const google_protobuf_FileOptions *msg);
+bool google_protobuf_FileOptions_cc_generic_services(const google_protobuf_FileOptions *msg);
+bool google_protobuf_FileOptions_java_generic_services(const google_protobuf_FileOptions *msg);
+bool google_protobuf_FileOptions_py_generic_services(const google_protobuf_FileOptions *msg);
+bool google_protobuf_FileOptions_java_generate_equals_and_hash(const google_protobuf_FileOptions *msg);
+bool google_protobuf_FileOptions_deprecated(const google_protobuf_FileOptions *msg);
+bool google_protobuf_FileOptions_java_string_check_utf8(const google_protobuf_FileOptions *msg);
+bool google_protobuf_FileOptions_cc_enable_arenas(const google_protobuf_FileOptions *msg);
+upb_stringview google_protobuf_FileOptions_objc_class_prefix(const google_protobuf_FileOptions *msg);
+upb_stringview google_protobuf_FileOptions_csharp_namespace(const google_protobuf_FileOptions *msg);
+upb_stringview google_protobuf_FileOptions_swift_prefix(const google_protobuf_FileOptions *msg);
+upb_stringview google_protobuf_FileOptions_php_class_prefix(const google_protobuf_FileOptions *msg);
+upb_stringview google_protobuf_FileOptions_php_namespace(const google_protobuf_FileOptions *msg);
+bool google_protobuf_FileOptions_php_generic_services(const google_protobuf_FileOptions *msg);
+const upb_array* google_protobuf_FileOptions_uninterpreted_option(const google_protobuf_FileOptions *msg);
+
+/* setters. */
+void google_protobuf_FileOptions_set_java_package(google_protobuf_FileOptions *msg, upb_stringview value);
+void google_protobuf_FileOptions_set_java_outer_classname(google_protobuf_FileOptions *msg, upb_stringview value);
+void google_protobuf_FileOptions_set_optimize_for(google_protobuf_FileOptions *msg, google_protobuf_FileOptions_OptimizeMode value);
+void google_protobuf_FileOptions_set_java_multiple_files(google_protobuf_FileOptions *msg, bool value);
+void google_protobuf_FileOptions_set_go_package(google_protobuf_FileOptions *msg, upb_stringview value);
+void google_protobuf_FileOptions_set_cc_generic_services(google_protobuf_FileOptions *msg, bool value);
+void google_protobuf_FileOptions_set_java_generic_services(google_protobuf_FileOptions *msg, bool value);
+void google_protobuf_FileOptions_set_py_generic_services(google_protobuf_FileOptions *msg, bool value);
+void google_protobuf_FileOptions_set_java_generate_equals_and_hash(google_protobuf_FileOptions *msg, bool value);
+void google_protobuf_FileOptions_set_deprecated(google_protobuf_FileOptions *msg, bool value);
+void google_protobuf_FileOptions_set_java_string_check_utf8(google_protobuf_FileOptions *msg, bool value);
+void google_protobuf_FileOptions_set_cc_enable_arenas(google_protobuf_FileOptions *msg, bool value);
+void google_protobuf_FileOptions_set_objc_class_prefix(google_protobuf_FileOptions *msg, upb_stringview value);
+void google_protobuf_FileOptions_set_csharp_namespace(google_protobuf_FileOptions *msg, upb_stringview value);
+void google_protobuf_FileOptions_set_swift_prefix(google_protobuf_FileOptions *msg, upb_stringview value);
+void google_protobuf_FileOptions_set_php_class_prefix(google_protobuf_FileOptions *msg, upb_stringview value);
+void google_protobuf_FileOptions_set_php_namespace(google_protobuf_FileOptions *msg, upb_stringview value);
+void google_protobuf_FileOptions_set_php_generic_services(google_protobuf_FileOptions *msg, bool value);
+void google_protobuf_FileOptions_set_uninterpreted_option(google_protobuf_FileOptions *msg, upb_array* value);
+
+
+/* google_protobuf_MessageOptions */
+extern const upb_msglayout_msginit_v1 google_protobuf_MessageOptions_msginit;
+google_protobuf_MessageOptions *google_protobuf_MessageOptions_new(upb_env *env);
+google_protobuf_MessageOptions *google_protobuf_MessageOptions_parsenew(upb_stringview buf, upb_env *env);
+char *google_protobuf_MessageOptions_serialize(google_protobuf_MessageOptions *msg, upb_env *env, size_t *len);
+void google_protobuf_MessageOptions_free(google_protobuf_MessageOptions *msg, upb_env *env);
+
+/* getters. */
+bool google_protobuf_MessageOptions_message_set_wire_format(const google_protobuf_MessageOptions *msg);
+bool google_protobuf_MessageOptions_no_standard_descriptor_accessor(const google_protobuf_MessageOptions *msg);
+bool google_protobuf_MessageOptions_deprecated(const google_protobuf_MessageOptions *msg);
+bool google_protobuf_MessageOptions_map_entry(const google_protobuf_MessageOptions *msg);
+const upb_array* google_protobuf_MessageOptions_uninterpreted_option(const google_protobuf_MessageOptions *msg);
+
+/* setters. */
+void google_protobuf_MessageOptions_set_message_set_wire_format(google_protobuf_MessageOptions *msg, bool value);
+void google_protobuf_MessageOptions_set_no_standard_descriptor_accessor(google_protobuf_MessageOptions *msg, bool value);
+void google_protobuf_MessageOptions_set_deprecated(google_protobuf_MessageOptions *msg, bool value);
+void google_protobuf_MessageOptions_set_map_entry(google_protobuf_MessageOptions *msg, bool value);
+void google_protobuf_MessageOptions_set_uninterpreted_option(google_protobuf_MessageOptions *msg, upb_array* value);
+
+
+/* google_protobuf_FieldOptions */
+extern const upb_msglayout_msginit_v1 google_protobuf_FieldOptions_msginit;
+google_protobuf_FieldOptions *google_protobuf_FieldOptions_new(upb_env *env);
+google_protobuf_FieldOptions *google_protobuf_FieldOptions_parsenew(upb_stringview buf, upb_env *env);
+char *google_protobuf_FieldOptions_serialize(google_protobuf_FieldOptions *msg, upb_env *env, size_t *len);
+void google_protobuf_FieldOptions_free(google_protobuf_FieldOptions *msg, upb_env *env);
+
+/* getters. */
+google_protobuf_FieldOptions_CType google_protobuf_FieldOptions_ctype(const google_protobuf_FieldOptions *msg);
+bool google_protobuf_FieldOptions_packed(const google_protobuf_FieldOptions *msg);
+bool google_protobuf_FieldOptions_deprecated(const google_protobuf_FieldOptions *msg);
+bool google_protobuf_FieldOptions_lazy(const google_protobuf_FieldOptions *msg);
+google_protobuf_FieldOptions_JSType google_protobuf_FieldOptions_jstype(const google_protobuf_FieldOptions *msg);
+bool google_protobuf_FieldOptions_weak(const google_protobuf_FieldOptions *msg);
+const upb_array* google_protobuf_FieldOptions_uninterpreted_option(const google_protobuf_FieldOptions *msg);
+
+/* setters. */
+void google_protobuf_FieldOptions_set_ctype(google_protobuf_FieldOptions *msg, google_protobuf_FieldOptions_CType value);
+void google_protobuf_FieldOptions_set_packed(google_protobuf_FieldOptions *msg, bool value);
+void google_protobuf_FieldOptions_set_deprecated(google_protobuf_FieldOptions *msg, bool value);
+void google_protobuf_FieldOptions_set_lazy(google_protobuf_FieldOptions *msg, bool value);
+void google_protobuf_FieldOptions_set_jstype(google_protobuf_FieldOptions *msg, google_protobuf_FieldOptions_JSType value);
+void google_protobuf_FieldOptions_set_weak(google_protobuf_FieldOptions *msg, bool value);
+void google_protobuf_FieldOptions_set_uninterpreted_option(google_protobuf_FieldOptions *msg, upb_array* value);
+
+
+/* google_protobuf_OneofOptions */
+extern const upb_msglayout_msginit_v1 google_protobuf_OneofOptions_msginit;
+google_protobuf_OneofOptions *google_protobuf_OneofOptions_new(upb_env *env);
+google_protobuf_OneofOptions *google_protobuf_OneofOptions_parsenew(upb_stringview buf, upb_env *env);
+char *google_protobuf_OneofOptions_serialize(google_protobuf_OneofOptions *msg, upb_env *env, size_t *len);
+void google_protobuf_OneofOptions_free(google_protobuf_OneofOptions *msg, upb_env *env);
+
+/* getters. */
+const upb_array* google_protobuf_OneofOptions_uninterpreted_option(const google_protobuf_OneofOptions *msg);
+
+/* setters. */
+void google_protobuf_OneofOptions_set_uninterpreted_option(google_protobuf_OneofOptions *msg, upb_array* value);
+
+
+/* google_protobuf_EnumOptions */
+extern const upb_msglayout_msginit_v1 google_protobuf_EnumOptions_msginit;
+google_protobuf_EnumOptions *google_protobuf_EnumOptions_new(upb_env *env);
+google_protobuf_EnumOptions *google_protobuf_EnumOptions_parsenew(upb_stringview buf, upb_env *env);
+char *google_protobuf_EnumOptions_serialize(google_protobuf_EnumOptions *msg, upb_env *env, size_t *len);
+void google_protobuf_EnumOptions_free(google_protobuf_EnumOptions *msg, upb_env *env);
+
+/* getters. */
+bool google_protobuf_EnumOptions_allow_alias(const google_protobuf_EnumOptions *msg);
+bool google_protobuf_EnumOptions_deprecated(const google_protobuf_EnumOptions *msg);
+const upb_array* google_protobuf_EnumOptions_uninterpreted_option(const google_protobuf_EnumOptions *msg);
+
+/* setters. */
+void google_protobuf_EnumOptions_set_allow_alias(google_protobuf_EnumOptions *msg, bool value);
+void google_protobuf_EnumOptions_set_deprecated(google_protobuf_EnumOptions *msg, bool value);
+void google_protobuf_EnumOptions_set_uninterpreted_option(google_protobuf_EnumOptions *msg, upb_array* value);
+
+
+/* google_protobuf_EnumValueOptions */
+extern const upb_msglayout_msginit_v1 google_protobuf_EnumValueOptions_msginit;
+google_protobuf_EnumValueOptions *google_protobuf_EnumValueOptions_new(upb_env *env);
+google_protobuf_EnumValueOptions *google_protobuf_EnumValueOptions_parsenew(upb_stringview buf, upb_env *env);
+char *google_protobuf_EnumValueOptions_serialize(google_protobuf_EnumValueOptions *msg, upb_env *env, size_t *len);
+void google_protobuf_EnumValueOptions_free(google_protobuf_EnumValueOptions *msg, upb_env *env);
+
+/* getters. */
+bool google_protobuf_EnumValueOptions_deprecated(const google_protobuf_EnumValueOptions *msg);
+const upb_array* google_protobuf_EnumValueOptions_uninterpreted_option(const google_protobuf_EnumValueOptions *msg);
+
+/* setters. */
+void google_protobuf_EnumValueOptions_set_deprecated(google_protobuf_EnumValueOptions *msg, bool value);
+void google_protobuf_EnumValueOptions_set_uninterpreted_option(google_protobuf_EnumValueOptions *msg, upb_array* value);
+
+
+/* google_protobuf_ServiceOptions */
+extern const upb_msglayout_msginit_v1 google_protobuf_ServiceOptions_msginit;
+google_protobuf_ServiceOptions *google_protobuf_ServiceOptions_new(upb_env *env);
+google_protobuf_ServiceOptions *google_protobuf_ServiceOptions_parsenew(upb_stringview buf, upb_env *env);
+char *google_protobuf_ServiceOptions_serialize(google_protobuf_ServiceOptions *msg, upb_env *env, size_t *len);
+void google_protobuf_ServiceOptions_free(google_protobuf_ServiceOptions *msg, upb_env *env);
+
+/* getters. */
+bool google_protobuf_ServiceOptions_deprecated(const google_protobuf_ServiceOptions *msg);
+const upb_array* google_protobuf_ServiceOptions_uninterpreted_option(const google_protobuf_ServiceOptions *msg);
+
+/* setters. */
+void google_protobuf_ServiceOptions_set_deprecated(google_protobuf_ServiceOptions *msg, bool value);
+void google_protobuf_ServiceOptions_set_uninterpreted_option(google_protobuf_ServiceOptions *msg, upb_array* value);
+
+
+/* google_protobuf_MethodOptions */
+extern const upb_msglayout_msginit_v1 google_protobuf_MethodOptions_msginit;
+google_protobuf_MethodOptions *google_protobuf_MethodOptions_new(upb_env *env);
+google_protobuf_MethodOptions *google_protobuf_MethodOptions_parsenew(upb_stringview buf, upb_env *env);
+char *google_protobuf_MethodOptions_serialize(google_protobuf_MethodOptions *msg, upb_env *env, size_t *len);
+void google_protobuf_MethodOptions_free(google_protobuf_MethodOptions *msg, upb_env *env);
+
+/* getters. */
+bool google_protobuf_MethodOptions_deprecated(const google_protobuf_MethodOptions *msg);
+google_protobuf_MethodOptions_IdempotencyLevel google_protobuf_MethodOptions_idempotency_level(const google_protobuf_MethodOptions *msg);
+const upb_array* google_protobuf_MethodOptions_uninterpreted_option(const google_protobuf_MethodOptions *msg);
+
+/* setters. */
+void google_protobuf_MethodOptions_set_deprecated(google_protobuf_MethodOptions *msg, bool value);
+void google_protobuf_MethodOptions_set_idempotency_level(google_protobuf_MethodOptions *msg, google_protobuf_MethodOptions_IdempotencyLevel value);
+void google_protobuf_MethodOptions_set_uninterpreted_option(google_protobuf_MethodOptions *msg, upb_array* value);
+
+
+/* google_protobuf_UninterpretedOption */
+extern const upb_msglayout_msginit_v1 google_protobuf_UninterpretedOption_msginit;
+google_protobuf_UninterpretedOption *google_protobuf_UninterpretedOption_new(upb_env *env);
+google_protobuf_UninterpretedOption *google_protobuf_UninterpretedOption_parsenew(upb_stringview buf, upb_env *env);
+char *google_protobuf_UninterpretedOption_serialize(google_protobuf_UninterpretedOption *msg, upb_env *env, size_t *len);
+void google_protobuf_UninterpretedOption_free(google_protobuf_UninterpretedOption *msg, upb_env *env);
+
+/* getters. */
+const upb_array* google_protobuf_UninterpretedOption_name(const google_protobuf_UninterpretedOption *msg);
+upb_stringview google_protobuf_UninterpretedOption_identifier_value(const google_protobuf_UninterpretedOption *msg);
+uint64_t google_protobuf_UninterpretedOption_positive_int_value(const google_protobuf_UninterpretedOption *msg);
+int64_t google_protobuf_UninterpretedOption_negative_int_value(const google_protobuf_UninterpretedOption *msg);
+double google_protobuf_UninterpretedOption_double_value(const google_protobuf_UninterpretedOption *msg);
+upb_stringview google_protobuf_UninterpretedOption_string_value(const google_protobuf_UninterpretedOption *msg);
+upb_stringview google_protobuf_UninterpretedOption_aggregate_value(const google_protobuf_UninterpretedOption *msg);
+
+/* setters. */
+void google_protobuf_UninterpretedOption_set_name(google_protobuf_UninterpretedOption *msg, upb_array* value);
+void google_protobuf_UninterpretedOption_set_identifier_value(google_protobuf_UninterpretedOption *msg, upb_stringview value);
+void google_protobuf_UninterpretedOption_set_positive_int_value(google_protobuf_UninterpretedOption *msg, uint64_t value);
+void google_protobuf_UninterpretedOption_set_negative_int_value(google_protobuf_UninterpretedOption *msg, int64_t value);
+void google_protobuf_UninterpretedOption_set_double_value(google_protobuf_UninterpretedOption *msg, double value);
+void google_protobuf_UninterpretedOption_set_string_value(google_protobuf_UninterpretedOption *msg, upb_stringview value);
+void google_protobuf_UninterpretedOption_set_aggregate_value(google_protobuf_UninterpretedOption *msg, upb_stringview value);
+
+
+/* google_protobuf_UninterpretedOption_NamePart */
+extern const upb_msglayout_msginit_v1 google_protobuf_UninterpretedOption_NamePart_msginit;
+google_protobuf_UninterpretedOption_NamePart *google_protobuf_UninterpretedOption_NamePart_new(upb_env *env);
+google_protobuf_UninterpretedOption_NamePart *google_protobuf_UninterpretedOption_NamePart_parsenew(upb_stringview buf, upb_env *env);
+char *google_protobuf_UninterpretedOption_NamePart_serialize(google_protobuf_UninterpretedOption_NamePart *msg, upb_env *env, size_t *len);
+void google_protobuf_UninterpretedOption_NamePart_free(google_protobuf_UninterpretedOption_NamePart *msg, upb_env *env);
+
+/* getters. */
+upb_stringview google_protobuf_UninterpretedOption_NamePart_name_part(const google_protobuf_UninterpretedOption_NamePart *msg);
+bool google_protobuf_UninterpretedOption_NamePart_is_extension(const google_protobuf_UninterpretedOption_NamePart *msg);
+
+/* setters. */
+void google_protobuf_UninterpretedOption_NamePart_set_name_part(google_protobuf_UninterpretedOption_NamePart *msg, upb_stringview value);
+void google_protobuf_UninterpretedOption_NamePart_set_is_extension(google_protobuf_UninterpretedOption_NamePart *msg, bool value);
+
+
+/* google_protobuf_SourceCodeInfo */
+extern const upb_msglayout_msginit_v1 google_protobuf_SourceCodeInfo_msginit;
+google_protobuf_SourceCodeInfo *google_protobuf_SourceCodeInfo_new(upb_env *env);
+google_protobuf_SourceCodeInfo *google_protobuf_SourceCodeInfo_parsenew(upb_stringview buf, upb_env *env);
+char *google_protobuf_SourceCodeInfo_serialize(google_protobuf_SourceCodeInfo *msg, upb_env *env, size_t *len);
+void google_protobuf_SourceCodeInfo_free(google_protobuf_SourceCodeInfo *msg, upb_env *env);
+
+/* getters. */
+const upb_array* google_protobuf_SourceCodeInfo_location(const google_protobuf_SourceCodeInfo *msg);
+
+/* setters. */
+void google_protobuf_SourceCodeInfo_set_location(google_protobuf_SourceCodeInfo *msg, upb_array* value);
+
+
+/* google_protobuf_SourceCodeInfo_Location */
+extern const upb_msglayout_msginit_v1 google_protobuf_SourceCodeInfo_Location_msginit;
+google_protobuf_SourceCodeInfo_Location *google_protobuf_SourceCodeInfo_Location_new(upb_env *env);
+google_protobuf_SourceCodeInfo_Location *google_protobuf_SourceCodeInfo_Location_parsenew(upb_stringview buf, upb_env *env);
+char *google_protobuf_SourceCodeInfo_Location_serialize(google_protobuf_SourceCodeInfo_Location *msg, upb_env *env, size_t *len);
+void google_protobuf_SourceCodeInfo_Location_free(google_protobuf_SourceCodeInfo_Location *msg, upb_env *env);
+
+/* getters. */
+const upb_array* google_protobuf_SourceCodeInfo_Location_path(const google_protobuf_SourceCodeInfo_Location *msg);
+const upb_array* google_protobuf_SourceCodeInfo_Location_span(const google_protobuf_SourceCodeInfo_Location *msg);
+upb_stringview google_protobuf_SourceCodeInfo_Location_leading_comments(const google_protobuf_SourceCodeInfo_Location *msg);
+upb_stringview google_protobuf_SourceCodeInfo_Location_trailing_comments(const google_protobuf_SourceCodeInfo_Location *msg);
+const upb_array* google_protobuf_SourceCodeInfo_Location_leading_detached_comments(const google_protobuf_SourceCodeInfo_Location *msg);
+
+/* setters. */
+void google_protobuf_SourceCodeInfo_Location_set_path(google_protobuf_SourceCodeInfo_Location *msg, upb_array* value);
+void google_protobuf_SourceCodeInfo_Location_set_span(google_protobuf_SourceCodeInfo_Location *msg, upb_array* value);
+void google_protobuf_SourceCodeInfo_Location_set_leading_comments(google_protobuf_SourceCodeInfo_Location *msg, upb_stringview value);
+void google_protobuf_SourceCodeInfo_Location_set_trailing_comments(google_protobuf_SourceCodeInfo_Location *msg, upb_stringview value);
+void google_protobuf_SourceCodeInfo_Location_set_leading_detached_comments(google_protobuf_SourceCodeInfo_Location *msg, upb_array* value);
+
+
+/* google_protobuf_GeneratedCodeInfo */
+extern const upb_msglayout_msginit_v1 google_protobuf_GeneratedCodeInfo_msginit;
+google_protobuf_GeneratedCodeInfo *google_protobuf_GeneratedCodeInfo_new(upb_env *env);
+google_protobuf_GeneratedCodeInfo *google_protobuf_GeneratedCodeInfo_parsenew(upb_stringview buf, upb_env *env);
+char *google_protobuf_GeneratedCodeInfo_serialize(google_protobuf_GeneratedCodeInfo *msg, upb_env *env, size_t *len);
+void google_protobuf_GeneratedCodeInfo_free(google_protobuf_GeneratedCodeInfo *msg, upb_env *env);
+
+/* getters. */
+const upb_array* google_protobuf_GeneratedCodeInfo_annotation(const google_protobuf_GeneratedCodeInfo *msg);
+
+/* setters. */
+void google_protobuf_GeneratedCodeInfo_set_annotation(google_protobuf_GeneratedCodeInfo *msg, upb_array* value);
+
+
+/* google_protobuf_GeneratedCodeInfo_Annotation */
+extern const upb_msglayout_msginit_v1 google_protobuf_GeneratedCodeInfo_Annotation_msginit;
+google_protobuf_GeneratedCodeInfo_Annotation *google_protobuf_GeneratedCodeInfo_Annotation_new(upb_env *env);
+google_protobuf_GeneratedCodeInfo_Annotation *google_protobuf_GeneratedCodeInfo_Annotation_parsenew(upb_stringview buf, upb_env *env);
+char *google_protobuf_GeneratedCodeInfo_Annotation_serialize(google_protobuf_GeneratedCodeInfo_Annotation *msg, upb_env *env, size_t *len);
+void google_protobuf_GeneratedCodeInfo_Annotation_free(google_protobuf_GeneratedCodeInfo_Annotation *msg, upb_env *env);
+
+/* getters. */
+const upb_array* google_protobuf_GeneratedCodeInfo_Annotation_path(const google_protobuf_GeneratedCodeInfo_Annotation *msg);
+upb_stringview google_protobuf_GeneratedCodeInfo_Annotation_source_file(const google_protobuf_GeneratedCodeInfo_Annotation *msg);
+int32_t google_protobuf_GeneratedCodeInfo_Annotation_begin(const google_protobuf_GeneratedCodeInfo_Annotation *msg);
+int32_t google_protobuf_GeneratedCodeInfo_Annotation_end(const google_protobuf_GeneratedCodeInfo_Annotation *msg);
+
+/* setters. */
+void google_protobuf_GeneratedCodeInfo_Annotation_set_path(google_protobuf_GeneratedCodeInfo_Annotation *msg, upb_array* value);
+void google_protobuf_GeneratedCodeInfo_Annotation_set_source_file(google_protobuf_GeneratedCodeInfo_Annotation *msg, upb_stringview value);
+void google_protobuf_GeneratedCodeInfo_Annotation_set_begin(google_protobuf_GeneratedCodeInfo_Annotation *msg, int32_t value);
+void google_protobuf_GeneratedCodeInfo_Annotation_set_end(google_protobuf_GeneratedCodeInfo_Annotation *msg, int32_t value);
+
+
+UPB_END_EXTERN_C
+
+#endif  /* GOOGLE_PROTOBUF_DESCRIPTOR_PROTO_UPB_H_ */
+/*
+** structs.int.h: structures definitions that are internal to upb.
+*/
+
+#ifndef UPB_STRUCTS_H_
+#define UPB_STRUCTS_H_
+
+struct upb_array {
+  upb_fieldtype_t type;
+  uint8_t element_size;
+  void *data;   /* Each element is element_size. */
+  size_t len;   /* Measured in elements. */
+  size_t size;  /* Measured in elements. */
+  upb_alloc *alloc;
+};
+
+#endif  /* UPB_STRUCTS_H_ */
+
+/*
+** This file contains definitions of structs that should be considered private
+** and NOT stable across versions of upb.
+**
+** The only reason they are declared here and not in .c files is to allow upb
+** and the application (if desired) to embed statically-initialized instances
+** of structures like defs.
+**
+** If you include this file, all guarantees of ABI compatibility go out the
+** window!  Any code that includes this file needs to recompile against the
+** exact same version of upb that they are linking against.
+**
+** You also need to recompile if you change the value of the UPB_DEBUG_REFS
+** flag.
+*/
+
+
+#ifndef UPB_STATICINIT_H_
+#define UPB_STATICINIT_H_
+
+#ifdef __cplusplus
+/* Because of how we do our typedefs, this header can't be included from C++. */
+#error This file cannot be included from C++
+#endif
+
+/* upb_refcounted *************************************************************/
+
+
+/* upb_def ********************************************************************/
+
+struct upb_def {
+  upb_refcounted base;
+
+  const char *fullname;
+  const upb_filedef* file;
+  char type;  /* A upb_deftype_t (char to save space) */
+
+  /* Used as a flag during the def's mutable stage.  Must be false unless
+   * it is currently being used by a function on the stack.  This allows
+   * us to easily determine which defs were passed into the function's
+   * current invocation. */
+  bool came_from_user;
+};
+
+#define UPB_DEF_INIT(name, type, vtbl, refs, ref2s) \
+    { UPB_REFCOUNT_INIT(vtbl, refs, ref2s), name, NULL, type, false }
+
+
+/* upb_fielddef ***************************************************************/
+
+struct upb_fielddef {
+  upb_def base;
+
+  union {
+    int64_t sint;
+    uint64_t uint;
+    double dbl;
+    float flt;
+    void *bytes;
+  } defaultval;
+  union {
+    const upb_msgdef *def;  /* If !msg_is_symbolic. */
+    char *name;             /* If msg_is_symbolic. */
+  } msg;
+  union {
+    const upb_def *def;  /* If !subdef_is_symbolic. */
+    char *name;          /* If subdef_is_symbolic. */
+  } sub;  /* The msgdef or enumdef for this field, if upb_hassubdef(f). */
+  bool subdef_is_symbolic;
+  bool msg_is_symbolic;
+  const upb_oneofdef *oneof;
+  bool default_is_string;
+  bool type_is_set_;     /* False until type is explicitly set. */
+  bool is_extension_;
+  bool lazy_;
+  bool packed_;
+  upb_intfmt_t intfmt;
+  bool tagdelim;
+  upb_fieldtype_t type_;
+  upb_label_t label_;
+  uint32_t number_;
+  uint32_t selector_base;  /* Used to index into a upb::Handlers table. */
+  uint32_t index_;
+};
+
+extern const struct upb_refcounted_vtbl upb_fielddef_vtbl;
+
+#define UPB_FIELDDEF_INIT(label, type, intfmt, tagdelim, is_extension, lazy,   \
+                          packed, name, num, msgdef, subdef, selector_base,    \
+                          index, defaultval, refs, ref2s)                      \
+  {                                                                            \
+    UPB_DEF_INIT(name, UPB_DEF_FIELD, &upb_fielddef_vtbl, refs, ref2s),        \
+        defaultval, {msgdef}, {subdef}, NULL, false, false,                    \
+        type == UPB_TYPE_STRING || type == UPB_TYPE_BYTES, true, is_extension, \
+        lazy, packed, intfmt, tagdelim, type, label, num, selector_base, index \
+  }
+
+
+/* upb_msgdef *****************************************************************/
+
+struct upb_msgdef {
+  upb_def base;
+
+  size_t selector_count;
+  uint32_t submsg_field_count;
+
+  /* Tables for looking up fields by number and name. */
+  upb_inttable itof;  /* int to field */
+  upb_strtable ntof;  /* name to field/oneof */
+
+  /* Is this a map-entry message? */
+  bool map_entry;
+
+  /* Whether this message has proto2 or proto3 semantics. */
+  upb_syntax_t syntax;
+
+  /* TODO(haberman): proper extension ranges (there can be multiple). */
+};
+
+extern const struct upb_refcounted_vtbl upb_msgdef_vtbl;
+
+/* TODO: also support static initialization of the oneofs table. This will be
+ * needed if we compile in descriptors that contain oneofs. */
+#define UPB_MSGDEF_INIT(name, selector_count, submsg_field_count, itof, ntof, \
+                        map_entry, syntax, refs, ref2s)                       \
+  {                                                                           \
+    UPB_DEF_INIT(name, UPB_DEF_MSG, &upb_fielddef_vtbl, refs, ref2s),         \
+        selector_count, submsg_field_count, itof, ntof, map_entry, syntax     \
+  }
+
+
+/* upb_enumdef ****************************************************************/
+
+struct upb_enumdef {
+  upb_def base;
+
+  upb_strtable ntoi;
+  upb_inttable iton;
+  int32_t defaultval;
+};
+
+extern const struct upb_refcounted_vtbl upb_enumdef_vtbl;
+
+#define UPB_ENUMDEF_INIT(name, ntoi, iton, defaultval, refs, ref2s) \
+  { UPB_DEF_INIT(name, UPB_DEF_ENUM, &upb_enumdef_vtbl, refs, ref2s), ntoi,    \
+    iton, defaultval }
+
+
+/* upb_oneofdef ***************************************************************/
+
+struct upb_oneofdef {
+  upb_refcounted base;
+
+  uint32_t index;  /* Index within oneofs. */
+  const char *name;
+  upb_strtable ntof;
+  upb_inttable itof;
+  const upb_msgdef *parent;
+};
+
+extern const struct upb_refcounted_vtbl upb_oneofdef_vtbl;
+
+#define UPB_ONEOFDEF_INIT(name, ntof, itof, refs, ref2s) \
+  { UPB_REFCOUNT_INIT(&upb_oneofdef_vtbl, refs, ref2s), 0, name, ntof, itof }
+
+
+/* upb_symtab *****************************************************************/
+
+struct upb_symtab {
+  upb_refcounted base;
+
+  upb_strtable symtab;
+};
+
+struct upb_filedef {
+  upb_refcounted base;
+
+  const char *name;
+  const char *package;
+  const char *phpprefix;
+  const char *phpnamespace;
+  upb_syntax_t syntax;
+
+  upb_inttable defs;
+  upb_inttable deps;
+};
+
+extern const struct upb_refcounted_vtbl upb_filedef_vtbl;
+
+#endif  /* UPB_STATICINIT_H_ */
+/*
+** upb::descriptor::Reader (upb_descreader)
+**
+** Provides a way of building upb::Defs from data in descriptor.proto format.
+*/
+
+#ifndef UPB_DESCRIPTOR_H
+#define UPB_DESCRIPTOR_H
+
+
+#ifdef __cplusplus
+namespace upb {
+namespace descriptor {
+class Reader;
+}  /* namespace descriptor */
+}  /* namespace upb */
+#endif
+
+UPB_DECLARE_TYPE(upb::descriptor::Reader, upb_descreader)
+
+#ifdef __cplusplus
+
+/* Class that receives descriptor data according to the descriptor.proto schema
+ * and use it to build upb::Defs corresponding to that schema. */
+class upb::descriptor::Reader {
+ public:
+  /* These handlers must have come from NewHandlers() and must outlive the
+   * Reader.
+   *
+   * TODO: generate the handlers statically (like we do with the
+   * descriptor.proto defs) so that there is no need to pass this parameter (or
+   * to build/memory-manage the handlers at runtime at all).  Unfortunately this
+   * is a bit tricky to implement for Handlers, but necessary to simplify this
+   * interface. */
+  static Reader* Create(Environment* env, const Handlers* handlers);
+
+  /* The reader's input; this is where descriptor.proto data should be sent. */
+  Sink* input();
+
+  /* Use to get the FileDefs that have been parsed. */
+  size_t file_count() const;
+  FileDef* file(size_t i) const;
+
+  /* Builds and returns handlers for the reader, owned by "owner." */
+  static Handlers* NewHandlers(const void* owner);
+
+ private:
+  UPB_DISALLOW_POD_OPS(Reader, upb::descriptor::Reader)
+};
+
+#endif
+
+UPB_BEGIN_EXTERN_C
+
+/* C API. */
+upb_descreader *upb_descreader_create(upb_env *e, const upb_handlers *h);
+upb_sink *upb_descreader_input(upb_descreader *r);
+size_t upb_descreader_filecount(const upb_descreader *r);
+upb_filedef *upb_descreader_file(const upb_descreader *r, size_t i);
+const upb_handlers *upb_descreader_newhandlers(const void *owner);
+
+UPB_END_EXTERN_C
+
+#ifdef __cplusplus
+/* C++ implementation details. ************************************************/
+namespace upb {
+namespace descriptor {
+inline Reader* Reader::Create(Environment* e, const Handlers *h) {
+  return upb_descreader_create(e, h);
+}
+inline Sink* Reader::input() { return upb_descreader_input(this); }
+inline size_t Reader::file_count() const {
+  return upb_descreader_filecount(this);
+}
+inline FileDef* Reader::file(size_t i) const {
+  return upb_descreader_file(this, i);
+}
+}  /* namespace descriptor */
+}  /* namespace upb */
+#endif
+
+#endif  /* UPB_DESCRIPTOR_H */
+/* This file contains accessors for a set of compiled-in defs.
+ * Note that unlike Google's protobuf, it does *not* define
+ * generated classes or any other kind of data structure for
+ * actually storing protobufs.  It only contains *defs* which
+ * let you reflect over a protobuf *schema*.
+ */
+/* This file was generated by upbc (the upb compiler) from the input
+ * file:
+ *
+ *     upb/descriptor/descriptor.proto
+ *
+ * Do not edit -- your changes will be discarded when the file is
+ * regenerated. */
+
+#ifndef UPB_DESCRIPTOR_DESCRIPTOR_PROTO_UPB_H_
+#define UPB_DESCRIPTOR_DESCRIPTOR_PROTO_UPB_H_
+
+
+UPB_BEGIN_EXTERN_C
+
+/* MessageDefs: call these functions to get a ref to a msgdef. */
+const upb_msgdef *upbdefs_google_protobuf_DescriptorProto_get(const void *owner);
+const upb_msgdef *upbdefs_google_protobuf_DescriptorProto_ExtensionRange_get(const void *owner);
+const upb_msgdef *upbdefs_google_protobuf_DescriptorProto_ReservedRange_get(const void *owner);
+const upb_msgdef *upbdefs_google_protobuf_EnumDescriptorProto_get(const void *owner);
+const upb_msgdef *upbdefs_google_protobuf_EnumOptions_get(const void *owner);
+const upb_msgdef *upbdefs_google_protobuf_EnumValueDescriptorProto_get(const void *owner);
+const upb_msgdef *upbdefs_google_protobuf_EnumValueOptions_get(const void *owner);
+const upb_msgdef *upbdefs_google_protobuf_FieldDescriptorProto_get(const void *owner);
+const upb_msgdef *upbdefs_google_protobuf_FieldOptions_get(const void *owner);
+const upb_msgdef *upbdefs_google_protobuf_FileDescriptorProto_get(const void *owner);
+const upb_msgdef *upbdefs_google_protobuf_FileDescriptorSet_get(const void *owner);
+const upb_msgdef *upbdefs_google_protobuf_FileOptions_get(const void *owner);
+const upb_msgdef *upbdefs_google_protobuf_MessageOptions_get(const void *owner);
+const upb_msgdef *upbdefs_google_protobuf_MethodDescriptorProto_get(const void *owner);
+const upb_msgdef *upbdefs_google_protobuf_MethodOptions_get(const void *owner);
+const upb_msgdef *upbdefs_google_protobuf_OneofDescriptorProto_get(const void *owner);
+const upb_msgdef *upbdefs_google_protobuf_ServiceDescriptorProto_get(const void *owner);
+const upb_msgdef *upbdefs_google_protobuf_ServiceOptions_get(const void *owner);
+const upb_msgdef *upbdefs_google_protobuf_SourceCodeInfo_get(const void *owner);
+const upb_msgdef *upbdefs_google_protobuf_SourceCodeInfo_Location_get(const void *owner);
+const upb_msgdef *upbdefs_google_protobuf_UninterpretedOption_get(const void *owner);
+const upb_msgdef *upbdefs_google_protobuf_UninterpretedOption_NamePart_get(const void *owner);
+
+/* EnumDefs: call these functions to get a ref to an enumdef. */
+const upb_enumdef *upbdefs_google_protobuf_FieldDescriptorProto_Label_get(const void *owner);
+const upb_enumdef *upbdefs_google_protobuf_FieldDescriptorProto_Type_get(const void *owner);
+const upb_enumdef *upbdefs_google_protobuf_FieldOptions_CType_get(const void *owner);
+const upb_enumdef *upbdefs_google_protobuf_FieldOptions_JSType_get(const void *owner);
+const upb_enumdef *upbdefs_google_protobuf_FileOptions_OptimizeMode_get(const void *owner);
+
+/* Functions to test whether this message is of a certain type. */
+UPB_INLINE bool upbdefs_google_protobuf_DescriptorProto_is(const upb_msgdef *m) {
+  return strcmp(upb_msgdef_fullname(m), "google.protobuf.DescriptorProto") == 0;
+}
+UPB_INLINE bool upbdefs_google_protobuf_DescriptorProto_ExtensionRange_is(const upb_msgdef *m) {
+  return strcmp(upb_msgdef_fullname(m), "google.protobuf.DescriptorProto.ExtensionRange") == 0;
+}
+UPB_INLINE bool upbdefs_google_protobuf_DescriptorProto_ReservedRange_is(const upb_msgdef *m) {
+  return strcmp(upb_msgdef_fullname(m), "google.protobuf.DescriptorProto.ReservedRange") == 0;
+}
+UPB_INLINE bool upbdefs_google_protobuf_EnumDescriptorProto_is(const upb_msgdef *m) {
+  return strcmp(upb_msgdef_fullname(m), "google.protobuf.EnumDescriptorProto") == 0;
+}
+UPB_INLINE bool upbdefs_google_protobuf_EnumOptions_is(const upb_msgdef *m) {
+  return strcmp(upb_msgdef_fullname(m), "google.protobuf.EnumOptions") == 0;
+}
+UPB_INLINE bool upbdefs_google_protobuf_EnumValueDescriptorProto_is(const upb_msgdef *m) {
+  return strcmp(upb_msgdef_fullname(m), "google.protobuf.EnumValueDescriptorProto") == 0;
+}
+UPB_INLINE bool upbdefs_google_protobuf_EnumValueOptions_is(const upb_msgdef *m) {
+  return strcmp(upb_msgdef_fullname(m), "google.protobuf.EnumValueOptions") == 0;
+}
+UPB_INLINE bool upbdefs_google_protobuf_FieldDescriptorProto_is(const upb_msgdef *m) {
+  return strcmp(upb_msgdef_fullname(m), "google.protobuf.FieldDescriptorProto") == 0;
+}
+UPB_INLINE bool upbdefs_google_protobuf_FieldOptions_is(const upb_msgdef *m) {
+  return strcmp(upb_msgdef_fullname(m), "google.protobuf.FieldOptions") == 0;
+}
+UPB_INLINE bool upbdefs_google_protobuf_FileDescriptorProto_is(const upb_msgdef *m) {
+  return strcmp(upb_msgdef_fullname(m), "google.protobuf.FileDescriptorProto") == 0;
+}
+UPB_INLINE bool upbdefs_google_protobuf_FileDescriptorSet_is(const upb_msgdef *m) {
+  return strcmp(upb_msgdef_fullname(m), "google.protobuf.FileDescriptorSet") == 0;
+}
+UPB_INLINE bool upbdefs_google_protobuf_FileOptions_is(const upb_msgdef *m) {
+  return strcmp(upb_msgdef_fullname(m), "google.protobuf.FileOptions") == 0;
+}
+UPB_INLINE bool upbdefs_google_protobuf_MessageOptions_is(const upb_msgdef *m) {
+  return strcmp(upb_msgdef_fullname(m), "google.protobuf.MessageOptions") == 0;
+}
+UPB_INLINE bool upbdefs_google_protobuf_MethodDescriptorProto_is(const upb_msgdef *m) {
+  return strcmp(upb_msgdef_fullname(m), "google.protobuf.MethodDescriptorProto") == 0;
+}
+UPB_INLINE bool upbdefs_google_protobuf_MethodOptions_is(const upb_msgdef *m) {
+  return strcmp(upb_msgdef_fullname(m), "google.protobuf.MethodOptions") == 0;
+}
+UPB_INLINE bool upbdefs_google_protobuf_OneofDescriptorProto_is(const upb_msgdef *m) {
+  return strcmp(upb_msgdef_fullname(m), "google.protobuf.OneofDescriptorProto") == 0;
+}
+UPB_INLINE bool upbdefs_google_protobuf_ServiceDescriptorProto_is(const upb_msgdef *m) {
+  return strcmp(upb_msgdef_fullname(m), "google.protobuf.ServiceDescriptorProto") == 0;
+}
+UPB_INLINE bool upbdefs_google_protobuf_ServiceOptions_is(const upb_msgdef *m) {
+  return strcmp(upb_msgdef_fullname(m), "google.protobuf.ServiceOptions") == 0;
+}
+UPB_INLINE bool upbdefs_google_protobuf_SourceCodeInfo_is(const upb_msgdef *m) {
+  return strcmp(upb_msgdef_fullname(m), "google.protobuf.SourceCodeInfo") == 0;
+}
+UPB_INLINE bool upbdefs_google_protobuf_SourceCodeInfo_Location_is(const upb_msgdef *m) {
+  return strcmp(upb_msgdef_fullname(m), "google.protobuf.SourceCodeInfo.Location") == 0;
+}
+UPB_INLINE bool upbdefs_google_protobuf_UninterpretedOption_is(const upb_msgdef *m) {
+  return strcmp(upb_msgdef_fullname(m), "google.protobuf.UninterpretedOption") == 0;
+}
+UPB_INLINE bool upbdefs_google_protobuf_UninterpretedOption_NamePart_is(const upb_msgdef *m) {
+  return strcmp(upb_msgdef_fullname(m), "google.protobuf.UninterpretedOption.NamePart") == 0;
+}
+
+/* Functions to test whether this enum is of a certain type. */
+UPB_INLINE bool upbdefs_google_protobuf_FieldDescriptorProto_Label_is(const upb_enumdef *e) {
+  return strcmp(upb_enumdef_fullname(e), "google.protobuf.FieldDescriptorProto.Label") == 0;
+}
+UPB_INLINE bool upbdefs_google_protobuf_FieldDescriptorProto_Type_is(const upb_enumdef *e) {
+  return strcmp(upb_enumdef_fullname(e), "google.protobuf.FieldDescriptorProto.Type") == 0;
+}
+UPB_INLINE bool upbdefs_google_protobuf_FieldOptions_CType_is(const upb_enumdef *e) {
+  return strcmp(upb_enumdef_fullname(e), "google.protobuf.FieldOptions.CType") == 0;
+}
+UPB_INLINE bool upbdefs_google_protobuf_FieldOptions_JSType_is(const upb_enumdef *e) {
+  return strcmp(upb_enumdef_fullname(e), "google.protobuf.FieldOptions.JSType") == 0;
+}
+UPB_INLINE bool upbdefs_google_protobuf_FileOptions_OptimizeMode_is(const upb_enumdef *e) {
+  return strcmp(upb_enumdef_fullname(e), "google.protobuf.FileOptions.OptimizeMode") == 0;
+}
+
+
+/* Functions to get a fielddef from a msgdef reference. */
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_DescriptorProto_ExtensionRange_f_end(const upb_msgdef *m) { UPB_ASSERT(upbdefs_google_protobuf_DescriptorProto_ExtensionRange_is(m)); return upb_msgdef_itof(m, 2); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_DescriptorProto_ExtensionRange_f_start(const upb_msgdef *m) { UPB_ASSERT(upbdefs_google_protobuf_DescriptorProto_ExtensionRange_is(m)); return upb_msgdef_itof(m, 1); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_DescriptorProto_ReservedRange_f_end(const upb_msgdef *m) { UPB_ASSERT(upbdefs_google_protobuf_DescriptorProto_ReservedRange_is(m)); return upb_msgdef_itof(m, 2); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_DescriptorProto_ReservedRange_f_start(const upb_msgdef *m) { UPB_ASSERT(upbdefs_google_protobuf_DescriptorProto_ReservedRange_is(m)); return upb_msgdef_itof(m, 1); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_DescriptorProto_f_enum_type(const upb_msgdef *m) { UPB_ASSERT(upbdefs_google_protobuf_DescriptorProto_is(m)); return upb_msgdef_itof(m, 4); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_DescriptorProto_f_extension(const upb_msgdef *m) { UPB_ASSERT(upbdefs_google_protobuf_DescriptorProto_is(m)); return upb_msgdef_itof(m, 6); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_DescriptorProto_f_extension_range(const upb_msgdef *m) { UPB_ASSERT(upbdefs_google_protobuf_DescriptorProto_is(m)); return upb_msgdef_itof(m, 5); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_DescriptorProto_f_field(const upb_msgdef *m) { UPB_ASSERT(upbdefs_google_protobuf_DescriptorProto_is(m)); return upb_msgdef_itof(m, 2); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_DescriptorProto_f_name(const upb_msgdef *m) { UPB_ASSERT(upbdefs_google_protobuf_DescriptorProto_is(m)); return upb_msgdef_itof(m, 1); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_DescriptorProto_f_nested_type(const upb_msgdef *m) { UPB_ASSERT(upbdefs_google_protobuf_DescriptorProto_is(m)); return upb_msgdef_itof(m, 3); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_DescriptorProto_f_oneof_decl(const upb_msgdef *m) { UPB_ASSERT(upbdefs_google_protobuf_DescriptorProto_is(m)); return upb_msgdef_itof(m, 8); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_DescriptorProto_f_options(const upb_msgdef *m) { UPB_ASSERT(upbdefs_google_protobuf_DescriptorProto_is(m)); return upb_msgdef_itof(m, 7); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_DescriptorProto_f_reserved_name(const upb_msgdef *m) { UPB_ASSERT(upbdefs_google_protobuf_DescriptorProto_is(m)); return upb_msgdef_itof(m, 10); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_DescriptorProto_f_reserved_range(const upb_msgdef *m) { UPB_ASSERT(upbdefs_google_protobuf_DescriptorProto_is(m)); return upb_msgdef_itof(m, 9); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_EnumDescriptorProto_f_name(const upb_msgdef *m) { UPB_ASSERT(upbdefs_google_protobuf_EnumDescriptorProto_is(m)); return upb_msgdef_itof(m, 1); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_EnumDescriptorProto_f_options(const upb_msgdef *m) { UPB_ASSERT(upbdefs_google_protobuf_EnumDescriptorProto_is(m)); return upb_msgdef_itof(m, 3); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_EnumDescriptorProto_f_value(const upb_msgdef *m) { UPB_ASSERT(upbdefs_google_protobuf_EnumDescriptorProto_is(m)); return upb_msgdef_itof(m, 2); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_EnumOptions_f_allow_alias(const upb_msgdef *m) { UPB_ASSERT(upbdefs_google_protobuf_EnumOptions_is(m)); return upb_msgdef_itof(m, 2); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_EnumOptions_f_deprecated(const upb_msgdef *m) { UPB_ASSERT(upbdefs_google_protobuf_EnumOptions_is(m)); return upb_msgdef_itof(m, 3); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_EnumOptions_f_uninterpreted_option(const upb_msgdef *m) { UPB_ASSERT(upbdefs_google_protobuf_EnumOptions_is(m)); return upb_msgdef_itof(m, 999); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_EnumValueDescriptorProto_f_name(const upb_msgdef *m) { UPB_ASSERT(upbdefs_google_protobuf_EnumValueDescriptorProto_is(m)); return upb_msgdef_itof(m, 1); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_EnumValueDescriptorProto_f_number(const upb_msgdef *m) { UPB_ASSERT(upbdefs_google_protobuf_EnumValueDescriptorProto_is(m)); return upb_msgdef_itof(m, 2); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_EnumValueDescriptorProto_f_options(const upb_msgdef *m) { UPB_ASSERT(upbdefs_google_protobuf_EnumValueDescriptorProto_is(m)); return upb_msgdef_itof(m, 3); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_EnumValueOptions_f_deprecated(const upb_msgdef *m) { UPB_ASSERT(upbdefs_google_protobuf_EnumValueOptions_is(m)); return upb_msgdef_itof(m, 1); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_EnumValueOptions_f_uninterpreted_option(const upb_msgdef *m) { UPB_ASSERT(upbdefs_google_protobuf_EnumValueOptions_is(m)); return upb_msgdef_itof(m, 999); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FieldDescriptorProto_f_default_value(const upb_msgdef *m) { UPB_ASSERT(upbdefs_google_protobuf_FieldDescriptorProto_is(m)); return upb_msgdef_itof(m, 7); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FieldDescriptorProto_f_extendee(const upb_msgdef *m) { UPB_ASSERT(upbdefs_google_protobuf_FieldDescriptorProto_is(m)); return upb_msgdef_itof(m, 2); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FieldDescriptorProto_f_json_name(const upb_msgdef *m) { UPB_ASSERT(upbdefs_google_protobuf_FieldDescriptorProto_is(m)); return upb_msgdef_itof(m, 10); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FieldDescriptorProto_f_label(const upb_msgdef *m) { UPB_ASSERT(upbdefs_google_protobuf_FieldDescriptorProto_is(m)); return upb_msgdef_itof(m, 4); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FieldDescriptorProto_f_name(const upb_msgdef *m) { UPB_ASSERT(upbdefs_google_protobuf_FieldDescriptorProto_is(m)); return upb_msgdef_itof(m, 1); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FieldDescriptorProto_f_number(const upb_msgdef *m) { UPB_ASSERT(upbdefs_google_protobuf_FieldDescriptorProto_is(m)); return upb_msgdef_itof(m, 3); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FieldDescriptorProto_f_oneof_index(const upb_msgdef *m) { UPB_ASSERT(upbdefs_google_protobuf_FieldDescriptorProto_is(m)); return upb_msgdef_itof(m, 9); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FieldDescriptorProto_f_options(const upb_msgdef *m) { UPB_ASSERT(upbdefs_google_protobuf_FieldDescriptorProto_is(m)); return upb_msgdef_itof(m, 8); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FieldDescriptorProto_f_type(const upb_msgdef *m) { UPB_ASSERT(upbdefs_google_protobuf_FieldDescriptorProto_is(m)); return upb_msgdef_itof(m, 5); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FieldDescriptorProto_f_type_name(const upb_msgdef *m) { UPB_ASSERT(upbdefs_google_protobuf_FieldDescriptorProto_is(m)); return upb_msgdef_itof(m, 6); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FieldOptions_f_ctype(const upb_msgdef *m) { UPB_ASSERT(upbdefs_google_protobuf_FieldOptions_is(m)); return upb_msgdef_itof(m, 1); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FieldOptions_f_deprecated(const upb_msgdef *m) { UPB_ASSERT(upbdefs_google_protobuf_FieldOptions_is(m)); return upb_msgdef_itof(m, 3); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FieldOptions_f_jstype(const upb_msgdef *m) { UPB_ASSERT(upbdefs_google_protobuf_FieldOptions_is(m)); return upb_msgdef_itof(m, 6); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FieldOptions_f_lazy(const upb_msgdef *m) { UPB_ASSERT(upbdefs_google_protobuf_FieldOptions_is(m)); return upb_msgdef_itof(m, 5); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FieldOptions_f_packed(const upb_msgdef *m) { UPB_ASSERT(upbdefs_google_protobuf_FieldOptions_is(m)); return upb_msgdef_itof(m, 2); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FieldOptions_f_uninterpreted_option(const upb_msgdef *m) { UPB_ASSERT(upbdefs_google_protobuf_FieldOptions_is(m)); return upb_msgdef_itof(m, 999); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FieldOptions_f_weak(const upb_msgdef *m) { UPB_ASSERT(upbdefs_google_protobuf_FieldOptions_is(m)); return upb_msgdef_itof(m, 10); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FileDescriptorProto_f_dependency(const upb_msgdef *m) { UPB_ASSERT(upbdefs_google_protobuf_FileDescriptorProto_is(m)); return upb_msgdef_itof(m, 3); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FileDescriptorProto_f_enum_type(const upb_msgdef *m) { UPB_ASSERT(upbdefs_google_protobuf_FileDescriptorProto_is(m)); return upb_msgdef_itof(m, 5); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FileDescriptorProto_f_extension(const upb_msgdef *m) { UPB_ASSERT(upbdefs_google_protobuf_FileDescriptorProto_is(m)); return upb_msgdef_itof(m, 7); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FileDescriptorProto_f_message_type(const upb_msgdef *m) { UPB_ASSERT(upbdefs_google_protobuf_FileDescriptorProto_is(m)); return upb_msgdef_itof(m, 4); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FileDescriptorProto_f_name(const upb_msgdef *m) { UPB_ASSERT(upbdefs_google_protobuf_FileDescriptorProto_is(m)); return upb_msgdef_itof(m, 1); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FileDescriptorProto_f_options(const upb_msgdef *m) { UPB_ASSERT(upbdefs_google_protobuf_FileDescriptorProto_is(m)); return upb_msgdef_itof(m, 8); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FileDescriptorProto_f_package(const upb_msgdef *m) { UPB_ASSERT(upbdefs_google_protobuf_FileDescriptorProto_is(m)); return upb_msgdef_itof(m, 2); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FileDescriptorProto_f_public_dependency(const upb_msgdef *m) { UPB_ASSERT(upbdefs_google_protobuf_FileDescriptorProto_is(m)); return upb_msgdef_itof(m, 10); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FileDescriptorProto_f_service(const upb_msgdef *m) { UPB_ASSERT(upbdefs_google_protobuf_FileDescriptorProto_is(m)); return upb_msgdef_itof(m, 6); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FileDescriptorProto_f_source_code_info(const upb_msgdef *m) { UPB_ASSERT(upbdefs_google_protobuf_FileDescriptorProto_is(m)); return upb_msgdef_itof(m, 9); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FileDescriptorProto_f_syntax(const upb_msgdef *m) { UPB_ASSERT(upbdefs_google_protobuf_FileDescriptorProto_is(m)); return upb_msgdef_itof(m, 12); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FileDescriptorProto_f_weak_dependency(const upb_msgdef *m) { UPB_ASSERT(upbdefs_google_protobuf_FileDescriptorProto_is(m)); return upb_msgdef_itof(m, 11); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FileDescriptorSet_f_file(const upb_msgdef *m) { UPB_ASSERT(upbdefs_google_protobuf_FileDescriptorSet_is(m)); return upb_msgdef_itof(m, 1); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FileOptions_f_cc_enable_arenas(const upb_msgdef *m) { UPB_ASSERT(upbdefs_google_protobuf_FileOptions_is(m)); return upb_msgdef_itof(m, 31); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FileOptions_f_cc_generic_services(const upb_msgdef *m) { UPB_ASSERT(upbdefs_google_protobuf_FileOptions_is(m)); return upb_msgdef_itof(m, 16); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FileOptions_f_csharp_namespace(const upb_msgdef *m) { UPB_ASSERT(upbdefs_google_protobuf_FileOptions_is(m)); return upb_msgdef_itof(m, 37); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FileOptions_f_deprecated(const upb_msgdef *m) { UPB_ASSERT(upbdefs_google_protobuf_FileOptions_is(m)); return upb_msgdef_itof(m, 23); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FileOptions_f_go_package(const upb_msgdef *m) { UPB_ASSERT(upbdefs_google_protobuf_FileOptions_is(m)); return upb_msgdef_itof(m, 11); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FileOptions_f_java_generate_equals_and_hash(const upb_msgdef *m) { UPB_ASSERT(upbdefs_google_protobuf_FileOptions_is(m)); return upb_msgdef_itof(m, 20); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FileOptions_f_java_generic_services(const upb_msgdef *m) { UPB_ASSERT(upbdefs_google_protobuf_FileOptions_is(m)); return upb_msgdef_itof(m, 17); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FileOptions_f_java_multiple_files(const upb_msgdef *m) { UPB_ASSERT(upbdefs_google_protobuf_FileOptions_is(m)); return upb_msgdef_itof(m, 10); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FileOptions_f_java_outer_classname(const upb_msgdef *m) { UPB_ASSERT(upbdefs_google_protobuf_FileOptions_is(m)); return upb_msgdef_itof(m, 8); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FileOptions_f_java_package(const upb_msgdef *m) { UPB_ASSERT(upbdefs_google_protobuf_FileOptions_is(m)); return upb_msgdef_itof(m, 1); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FileOptions_f_java_string_check_utf8(const upb_msgdef *m) { UPB_ASSERT(upbdefs_google_protobuf_FileOptions_is(m)); return upb_msgdef_itof(m, 27); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FileOptions_f_javanano_use_deprecated_package(const upb_msgdef *m) { UPB_ASSERT(upbdefs_google_protobuf_FileOptions_is(m)); return upb_msgdef_itof(m, 38); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FileOptions_f_objc_class_prefix(const upb_msgdef *m) { UPB_ASSERT(upbdefs_google_protobuf_FileOptions_is(m)); return upb_msgdef_itof(m, 36); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FileOptions_f_optimize_for(const upb_msgdef *m) { UPB_ASSERT(upbdefs_google_protobuf_FileOptions_is(m)); return upb_msgdef_itof(m, 9); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FileOptions_f_php_class_prefix(const upb_msgdef *m) { UPB_ASSERT(upbdefs_google_protobuf_FileOptions_is(m)); return upb_msgdef_itof(m, 40); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FileOptions_f_php_namespace(const upb_msgdef *m) { UPB_ASSERT(upbdefs_google_protobuf_FileOptions_is(m)); return upb_msgdef_itof(m, 41); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FileOptions_f_py_generic_services(const upb_msgdef *m) { UPB_ASSERT(upbdefs_google_protobuf_FileOptions_is(m)); return upb_msgdef_itof(m, 18); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FileOptions_f_uninterpreted_option(const upb_msgdef *m) { UPB_ASSERT(upbdefs_google_protobuf_FileOptions_is(m)); return upb_msgdef_itof(m, 999); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_MessageOptions_f_deprecated(const upb_msgdef *m) { UPB_ASSERT(upbdefs_google_protobuf_MessageOptions_is(m)); return upb_msgdef_itof(m, 3); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_MessageOptions_f_map_entry(const upb_msgdef *m) { UPB_ASSERT(upbdefs_google_protobuf_MessageOptions_is(m)); return upb_msgdef_itof(m, 7); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_MessageOptions_f_message_set_wire_format(const upb_msgdef *m) { UPB_ASSERT(upbdefs_google_protobuf_MessageOptions_is(m)); return upb_msgdef_itof(m, 1); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_MessageOptions_f_no_standard_descriptor_accessor(const upb_msgdef *m) { UPB_ASSERT(upbdefs_google_protobuf_MessageOptions_is(m)); return upb_msgdef_itof(m, 2); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_MessageOptions_f_uninterpreted_option(const upb_msgdef *m) { UPB_ASSERT(upbdefs_google_protobuf_MessageOptions_is(m)); return upb_msgdef_itof(m, 999); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_MethodDescriptorProto_f_client_streaming(const upb_msgdef *m) { UPB_ASSERT(upbdefs_google_protobuf_MethodDescriptorProto_is(m)); return upb_msgdef_itof(m, 5); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_MethodDescriptorProto_f_input_type(const upb_msgdef *m) { UPB_ASSERT(upbdefs_google_protobuf_MethodDescriptorProto_is(m)); return upb_msgdef_itof(m, 2); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_MethodDescriptorProto_f_name(const upb_msgdef *m) { UPB_ASSERT(upbdefs_google_protobuf_MethodDescriptorProto_is(m)); return upb_msgdef_itof(m, 1); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_MethodDescriptorProto_f_options(const upb_msgdef *m) { UPB_ASSERT(upbdefs_google_protobuf_MethodDescriptorProto_is(m)); return upb_msgdef_itof(m, 4); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_MethodDescriptorProto_f_output_type(const upb_msgdef *m) { UPB_ASSERT(upbdefs_google_protobuf_MethodDescriptorProto_is(m)); return upb_msgdef_itof(m, 3); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_MethodDescriptorProto_f_server_streaming(const upb_msgdef *m) { UPB_ASSERT(upbdefs_google_protobuf_MethodDescriptorProto_is(m)); return upb_msgdef_itof(m, 6); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_MethodOptions_f_deprecated(const upb_msgdef *m) { UPB_ASSERT(upbdefs_google_protobuf_MethodOptions_is(m)); return upb_msgdef_itof(m, 33); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_MethodOptions_f_uninterpreted_option(const upb_msgdef *m) { UPB_ASSERT(upbdefs_google_protobuf_MethodOptions_is(m)); return upb_msgdef_itof(m, 999); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_OneofDescriptorProto_f_name(const upb_msgdef *m) { UPB_ASSERT(upbdefs_google_protobuf_OneofDescriptorProto_is(m)); return upb_msgdef_itof(m, 1); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_ServiceDescriptorProto_f_method(const upb_msgdef *m) { UPB_ASSERT(upbdefs_google_protobuf_ServiceDescriptorProto_is(m)); return upb_msgdef_itof(m, 2); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_ServiceDescriptorProto_f_name(const upb_msgdef *m) { UPB_ASSERT(upbdefs_google_protobuf_ServiceDescriptorProto_is(m)); return upb_msgdef_itof(m, 1); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_ServiceDescriptorProto_f_options(const upb_msgdef *m) { UPB_ASSERT(upbdefs_google_protobuf_ServiceDescriptorProto_is(m)); return upb_msgdef_itof(m, 3); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_ServiceOptions_f_deprecated(const upb_msgdef *m) { UPB_ASSERT(upbdefs_google_protobuf_ServiceOptions_is(m)); return upb_msgdef_itof(m, 33); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_ServiceOptions_f_uninterpreted_option(const upb_msgdef *m) { UPB_ASSERT(upbdefs_google_protobuf_ServiceOptions_is(m)); return upb_msgdef_itof(m, 999); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_SourceCodeInfo_Location_f_leading_comments(const upb_msgdef *m) { UPB_ASSERT(upbdefs_google_protobuf_SourceCodeInfo_Location_is(m)); return upb_msgdef_itof(m, 3); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_SourceCodeInfo_Location_f_leading_detached_comments(const upb_msgdef *m) { UPB_ASSERT(upbdefs_google_protobuf_SourceCodeInfo_Location_is(m)); return upb_msgdef_itof(m, 6); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_SourceCodeInfo_Location_f_path(const upb_msgdef *m) { UPB_ASSERT(upbdefs_google_protobuf_SourceCodeInfo_Location_is(m)); return upb_msgdef_itof(m, 1); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_SourceCodeInfo_Location_f_span(const upb_msgdef *m) { UPB_ASSERT(upbdefs_google_protobuf_SourceCodeInfo_Location_is(m)); return upb_msgdef_itof(m, 2); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_SourceCodeInfo_Location_f_trailing_comments(const upb_msgdef *m) { UPB_ASSERT(upbdefs_google_protobuf_SourceCodeInfo_Location_is(m)); return upb_msgdef_itof(m, 4); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_SourceCodeInfo_f_location(const upb_msgdef *m) { UPB_ASSERT(upbdefs_google_protobuf_SourceCodeInfo_is(m)); return upb_msgdef_itof(m, 1); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_UninterpretedOption_NamePart_f_is_extension(const upb_msgdef *m) { UPB_ASSERT(upbdefs_google_protobuf_UninterpretedOption_NamePart_is(m)); return upb_msgdef_itof(m, 2); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_UninterpretedOption_NamePart_f_name_part(const upb_msgdef *m) { UPB_ASSERT(upbdefs_google_protobuf_UninterpretedOption_NamePart_is(m)); return upb_msgdef_itof(m, 1); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_UninterpretedOption_f_aggregate_value(const upb_msgdef *m) { UPB_ASSERT(upbdefs_google_protobuf_UninterpretedOption_is(m)); return upb_msgdef_itof(m, 8); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_UninterpretedOption_f_double_value(const upb_msgdef *m) { UPB_ASSERT(upbdefs_google_protobuf_UninterpretedOption_is(m)); return upb_msgdef_itof(m, 6); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_UninterpretedOption_f_identifier_value(const upb_msgdef *m) { UPB_ASSERT(upbdefs_google_protobuf_UninterpretedOption_is(m)); return upb_msgdef_itof(m, 3); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_UninterpretedOption_f_name(const upb_msgdef *m) { UPB_ASSERT(upbdefs_google_protobuf_UninterpretedOption_is(m)); return upb_msgdef_itof(m, 2); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_UninterpretedOption_f_negative_int_value(const upb_msgdef *m) { UPB_ASSERT(upbdefs_google_protobuf_UninterpretedOption_is(m)); return upb_msgdef_itof(m, 5); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_UninterpretedOption_f_positive_int_value(const upb_msgdef *m) { UPB_ASSERT(upbdefs_google_protobuf_UninterpretedOption_is(m)); return upb_msgdef_itof(m, 4); }
+UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_UninterpretedOption_f_string_value(const upb_msgdef *m) { UPB_ASSERT(upbdefs_google_protobuf_UninterpretedOption_is(m)); return upb_msgdef_itof(m, 7); }
+
+UPB_END_EXTERN_C
+
+#ifdef __cplusplus
+
+namespace upbdefs {
+namespace google {
+namespace protobuf {
+
+class DescriptorProto : public ::upb::reffed_ptr<const ::upb::MessageDef> {
+ public:
+  DescriptorProto(const ::upb::MessageDef* m, const void *ref_donor = NULL)
+      : reffed_ptr(m, ref_donor) {
+    UPB_ASSERT(upbdefs_google_protobuf_DescriptorProto_is(m));
+  }
+
+  static DescriptorProto get() {
+    const ::upb::MessageDef* m = upbdefs_google_protobuf_DescriptorProto_get(&m);
+    return DescriptorProto(m, &m);
+  }
+
+  class ExtensionRange : public ::upb::reffed_ptr<const ::upb::MessageDef> {
+   public:
+    ExtensionRange(const ::upb::MessageDef* m, const void *ref_donor = NULL)
+        : reffed_ptr(m, ref_donor) {
+      UPB_ASSERT(upbdefs_google_protobuf_DescriptorProto_ExtensionRange_is(m));
+    }
+
+    static ExtensionRange get() {
+      const ::upb::MessageDef* m = upbdefs_google_protobuf_DescriptorProto_ExtensionRange_get(&m);
+      return ExtensionRange(m, &m);
+    }
+  };
+
+  class ReservedRange : public ::upb::reffed_ptr<const ::upb::MessageDef> {
+   public:
+    ReservedRange(const ::upb::MessageDef* m, const void *ref_donor = NULL)
+        : reffed_ptr(m, ref_donor) {
+      UPB_ASSERT(upbdefs_google_protobuf_DescriptorProto_ReservedRange_is(m));
+    }
+
+    static ReservedRange get() {
+      const ::upb::MessageDef* m = upbdefs_google_protobuf_DescriptorProto_ReservedRange_get(&m);
+      return ReservedRange(m, &m);
+    }
+  };
+};
+
+class EnumDescriptorProto : public ::upb::reffed_ptr<const ::upb::MessageDef> {
+ public:
+  EnumDescriptorProto(const ::upb::MessageDef* m, const void *ref_donor = NULL)
+      : reffed_ptr(m, ref_donor) {
+    UPB_ASSERT(upbdefs_google_protobuf_EnumDescriptorProto_is(m));
+  }
+
+  static EnumDescriptorProto get() {
+    const ::upb::MessageDef* m = upbdefs_google_protobuf_EnumDescriptorProto_get(&m);
+    return EnumDescriptorProto(m, &m);
+  }
+};
+
+class EnumOptions : public ::upb::reffed_ptr<const ::upb::MessageDef> {
+ public:
+  EnumOptions(const ::upb::MessageDef* m, const void *ref_donor = NULL)
+      : reffed_ptr(m, ref_donor) {
+    UPB_ASSERT(upbdefs_google_protobuf_EnumOptions_is(m));
+  }
+
+  static EnumOptions get() {
+    const ::upb::MessageDef* m = upbdefs_google_protobuf_EnumOptions_get(&m);
+    return EnumOptions(m, &m);
+  }
+};
+
+class EnumValueDescriptorProto : public ::upb::reffed_ptr<const ::upb::MessageDef> {
+ public:
+  EnumValueDescriptorProto(const ::upb::MessageDef* m, const void *ref_donor = NULL)
+      : reffed_ptr(m, ref_donor) {
+    UPB_ASSERT(upbdefs_google_protobuf_EnumValueDescriptorProto_is(m));
+  }
+
+  static EnumValueDescriptorProto get() {
+    const ::upb::MessageDef* m = upbdefs_google_protobuf_EnumValueDescriptorProto_get(&m);
+    return EnumValueDescriptorProto(m, &m);
+  }
+};
+
+class EnumValueOptions : public ::upb::reffed_ptr<const ::upb::MessageDef> {
+ public:
+  EnumValueOptions(const ::upb::MessageDef* m, const void *ref_donor = NULL)
+      : reffed_ptr(m, ref_donor) {
+    UPB_ASSERT(upbdefs_google_protobuf_EnumValueOptions_is(m));
+  }
+
+  static EnumValueOptions get() {
+    const ::upb::MessageDef* m = upbdefs_google_protobuf_EnumValueOptions_get(&m);
+    return EnumValueOptions(m, &m);
+  }
+};
+
+class FieldDescriptorProto : public ::upb::reffed_ptr<const ::upb::MessageDef> {
+ public:
+  FieldDescriptorProto(const ::upb::MessageDef* m, const void *ref_donor = NULL)
+      : reffed_ptr(m, ref_donor) {
+    UPB_ASSERT(upbdefs_google_protobuf_FieldDescriptorProto_is(m));
+  }
+
+  static FieldDescriptorProto get() {
+    const ::upb::MessageDef* m = upbdefs_google_protobuf_FieldDescriptorProto_get(&m);
+    return FieldDescriptorProto(m, &m);
+  }
+
+  class Label : public ::upb::reffed_ptr<const ::upb::EnumDef> {
+   public:
+    Label(const ::upb::EnumDef* e, const void *ref_donor = NULL)
+        : reffed_ptr(e, ref_donor) {
+      UPB_ASSERT(upbdefs_google_protobuf_FieldDescriptorProto_Label_is(e));
+    }
+    static Label get() {
+      const ::upb::EnumDef* e = upbdefs_google_protobuf_FieldDescriptorProto_Label_get(&e);
+      return Label(e, &e);
+    }
+  };
+
+  class Type : public ::upb::reffed_ptr<const ::upb::EnumDef> {
+   public:
+    Type(const ::upb::EnumDef* e, const void *ref_donor = NULL)
+        : reffed_ptr(e, ref_donor) {
+      UPB_ASSERT(upbdefs_google_protobuf_FieldDescriptorProto_Type_is(e));
+    }
+    static Type get() {
+      const ::upb::EnumDef* e = upbdefs_google_protobuf_FieldDescriptorProto_Type_get(&e);
+      return Type(e, &e);
+    }
+  };
+};
+
+class FieldOptions : public ::upb::reffed_ptr<const ::upb::MessageDef> {
+ public:
+  FieldOptions(const ::upb::MessageDef* m, const void *ref_donor = NULL)
+      : reffed_ptr(m, ref_donor) {
+    UPB_ASSERT(upbdefs_google_protobuf_FieldOptions_is(m));
+  }
+
+  static FieldOptions get() {
+    const ::upb::MessageDef* m = upbdefs_google_protobuf_FieldOptions_get(&m);
+    return FieldOptions(m, &m);
+  }
+
+  class CType : public ::upb::reffed_ptr<const ::upb::EnumDef> {
+   public:
+    CType(const ::upb::EnumDef* e, const void *ref_donor = NULL)
+        : reffed_ptr(e, ref_donor) {
+      UPB_ASSERT(upbdefs_google_protobuf_FieldOptions_CType_is(e));
+    }
+    static CType get() {
+      const ::upb::EnumDef* e = upbdefs_google_protobuf_FieldOptions_CType_get(&e);
+      return CType(e, &e);
+    }
+  };
+
+  class JSType : public ::upb::reffed_ptr<const ::upb::EnumDef> {
+   public:
+    JSType(const ::upb::EnumDef* e, const void *ref_donor = NULL)
+        : reffed_ptr(e, ref_donor) {
+      UPB_ASSERT(upbdefs_google_protobuf_FieldOptions_JSType_is(e));
+    }
+    static JSType get() {
+      const ::upb::EnumDef* e = upbdefs_google_protobuf_FieldOptions_JSType_get(&e);
+      return JSType(e, &e);
+    }
+  };
+};
+
+class FileDescriptorProto : public ::upb::reffed_ptr<const ::upb::MessageDef> {
+ public:
+  FileDescriptorProto(const ::upb::MessageDef* m, const void *ref_donor = NULL)
+      : reffed_ptr(m, ref_donor) {
+    UPB_ASSERT(upbdefs_google_protobuf_FileDescriptorProto_is(m));
+  }
+
+  static FileDescriptorProto get() {
+    const ::upb::MessageDef* m = upbdefs_google_protobuf_FileDescriptorProto_get(&m);
+    return FileDescriptorProto(m, &m);
+  }
+};
+
+class FileDescriptorSet : public ::upb::reffed_ptr<const ::upb::MessageDef> {
+ public:
+  FileDescriptorSet(const ::upb::MessageDef* m, const void *ref_donor = NULL)
+      : reffed_ptr(m, ref_donor) {
+    UPB_ASSERT(upbdefs_google_protobuf_FileDescriptorSet_is(m));
+  }
+
+  static FileDescriptorSet get() {
+    const ::upb::MessageDef* m = upbdefs_google_protobuf_FileDescriptorSet_get(&m);
+    return FileDescriptorSet(m, &m);
+  }
+};
+
+class FileOptions : public ::upb::reffed_ptr<const ::upb::MessageDef> {
+ public:
+  FileOptions(const ::upb::MessageDef* m, const void *ref_donor = NULL)
+      : reffed_ptr(m, ref_donor) {
+    UPB_ASSERT(upbdefs_google_protobuf_FileOptions_is(m));
+  }
+
+  static FileOptions get() {
+    const ::upb::MessageDef* m = upbdefs_google_protobuf_FileOptions_get(&m);
+    return FileOptions(m, &m);
+  }
+
+  class OptimizeMode : public ::upb::reffed_ptr<const ::upb::EnumDef> {
+   public:
+    OptimizeMode(const ::upb::EnumDef* e, const void *ref_donor = NULL)
+        : reffed_ptr(e, ref_donor) {
+      UPB_ASSERT(upbdefs_google_protobuf_FileOptions_OptimizeMode_is(e));
+    }
+    static OptimizeMode get() {
+      const ::upb::EnumDef* e = upbdefs_google_protobuf_FileOptions_OptimizeMode_get(&e);
+      return OptimizeMode(e, &e);
+    }
+  };
+};
+
+class MessageOptions : public ::upb::reffed_ptr<const ::upb::MessageDef> {
+ public:
+  MessageOptions(const ::upb::MessageDef* m, const void *ref_donor = NULL)
+      : reffed_ptr(m, ref_donor) {
+    UPB_ASSERT(upbdefs_google_protobuf_MessageOptions_is(m));
+  }
+
+  static MessageOptions get() {
+    const ::upb::MessageDef* m = upbdefs_google_protobuf_MessageOptions_get(&m);
+    return MessageOptions(m, &m);
+  }
+};
+
+class MethodDescriptorProto : public ::upb::reffed_ptr<const ::upb::MessageDef> {
+ public:
+  MethodDescriptorProto(const ::upb::MessageDef* m, const void *ref_donor = NULL)
+      : reffed_ptr(m, ref_donor) {
+    UPB_ASSERT(upbdefs_google_protobuf_MethodDescriptorProto_is(m));
+  }
+
+  static MethodDescriptorProto get() {
+    const ::upb::MessageDef* m = upbdefs_google_protobuf_MethodDescriptorProto_get(&m);
+    return MethodDescriptorProto(m, &m);
+  }
+};
+
+class MethodOptions : public ::upb::reffed_ptr<const ::upb::MessageDef> {
+ public:
+  MethodOptions(const ::upb::MessageDef* m, const void *ref_donor = NULL)
+      : reffed_ptr(m, ref_donor) {
+    UPB_ASSERT(upbdefs_google_protobuf_MethodOptions_is(m));
+  }
+
+  static MethodOptions get() {
+    const ::upb::MessageDef* m = upbdefs_google_protobuf_MethodOptions_get(&m);
+    return MethodOptions(m, &m);
+  }
+};
+
+class OneofDescriptorProto : public ::upb::reffed_ptr<const ::upb::MessageDef> {
+ public:
+  OneofDescriptorProto(const ::upb::MessageDef* m, const void *ref_donor = NULL)
+      : reffed_ptr(m, ref_donor) {
+    UPB_ASSERT(upbdefs_google_protobuf_OneofDescriptorProto_is(m));
+  }
+
+  static OneofDescriptorProto get() {
+    const ::upb::MessageDef* m = upbdefs_google_protobuf_OneofDescriptorProto_get(&m);
+    return OneofDescriptorProto(m, &m);
+  }
+};
+
+class ServiceDescriptorProto : public ::upb::reffed_ptr<const ::upb::MessageDef> {
+ public:
+  ServiceDescriptorProto(const ::upb::MessageDef* m, const void *ref_donor = NULL)
+      : reffed_ptr(m, ref_donor) {
+    UPB_ASSERT(upbdefs_google_protobuf_ServiceDescriptorProto_is(m));
+  }
+
+  static ServiceDescriptorProto get() {
+    const ::upb::MessageDef* m = upbdefs_google_protobuf_ServiceDescriptorProto_get(&m);
+    return ServiceDescriptorProto(m, &m);
+  }
+};
+
+class ServiceOptions : public ::upb::reffed_ptr<const ::upb::MessageDef> {
+ public:
+  ServiceOptions(const ::upb::MessageDef* m, const void *ref_donor = NULL)
+      : reffed_ptr(m, ref_donor) {
+    UPB_ASSERT(upbdefs_google_protobuf_ServiceOptions_is(m));
+  }
+
+  static ServiceOptions get() {
+    const ::upb::MessageDef* m = upbdefs_google_protobuf_ServiceOptions_get(&m);
+    return ServiceOptions(m, &m);
+  }
+};
+
+class SourceCodeInfo : public ::upb::reffed_ptr<const ::upb::MessageDef> {
+ public:
+  SourceCodeInfo(const ::upb::MessageDef* m, const void *ref_donor = NULL)
+      : reffed_ptr(m, ref_donor) {
+    UPB_ASSERT(upbdefs_google_protobuf_SourceCodeInfo_is(m));
+  }
+
+  static SourceCodeInfo get() {
+    const ::upb::MessageDef* m = upbdefs_google_protobuf_SourceCodeInfo_get(&m);
+    return SourceCodeInfo(m, &m);
+  }
+
+  class Location : public ::upb::reffed_ptr<const ::upb::MessageDef> {
+   public:
+    Location(const ::upb::MessageDef* m, const void *ref_donor = NULL)
+        : reffed_ptr(m, ref_donor) {
+      UPB_ASSERT(upbdefs_google_protobuf_SourceCodeInfo_Location_is(m));
+    }
+
+    static Location get() {
+      const ::upb::MessageDef* m = upbdefs_google_protobuf_SourceCodeInfo_Location_get(&m);
+      return Location(m, &m);
+    }
+  };
+};
+
+class UninterpretedOption : public ::upb::reffed_ptr<const ::upb::MessageDef> {
+ public:
+  UninterpretedOption(const ::upb::MessageDef* m, const void *ref_donor = NULL)
+      : reffed_ptr(m, ref_donor) {
+    UPB_ASSERT(upbdefs_google_protobuf_UninterpretedOption_is(m));
+  }
+
+  static UninterpretedOption get() {
+    const ::upb::MessageDef* m = upbdefs_google_protobuf_UninterpretedOption_get(&m);
+    return UninterpretedOption(m, &m);
+  }
+
+  class NamePart : public ::upb::reffed_ptr<const ::upb::MessageDef> {
+   public:
+    NamePart(const ::upb::MessageDef* m, const void *ref_donor = NULL)
+        : reffed_ptr(m, ref_donor) {
+      UPB_ASSERT(upbdefs_google_protobuf_UninterpretedOption_NamePart_is(m));
+    }
+
+    static NamePart get() {
+      const ::upb::MessageDef* m = upbdefs_google_protobuf_UninterpretedOption_NamePart_get(&m);
+      return NamePart(m, &m);
+    }
+  };
+};
+
+}  /* namespace protobuf */
+}  /* namespace google */
+}  /* namespace upbdefs */
+
+#endif  /* __cplusplus */
+
+#endif  /* UPB_DESCRIPTOR_DESCRIPTOR_PROTO_UPB_H_ */
+/*
+** Internal-only definitions for the decoder.
+*/
+
+#ifndef UPB_DECODER_INT_H_
+#define UPB_DECODER_INT_H_
+
+/*
+** upb::pb::Decoder
+**
+** A high performance, streaming, resumable decoder for the binary protobuf
+** format.
+**
+** This interface works the same regardless of what decoder backend is being
+** used.  A client of this class does not need to know whether decoding is using
+** a JITted decoder (DynASM, LLVM, etc) or an interpreted decoder.  By default,
+** it will always use the fastest available decoder.  However, you can call
+** set_allow_jit(false) to disable any JIT decoder that might be available.
+** This is primarily useful for testing purposes.
+*/
+
+#ifndef UPB_DECODER_H_
+#define UPB_DECODER_H_
+
+
+#ifdef __cplusplus
+namespace upb {
+namespace pb {
+class CodeCache;
+class Decoder;
+class DecoderMethod;
+class DecoderMethodOptions;
+}  /* namespace pb */
+}  /* namespace upb */
+#endif
+
+UPB_DECLARE_TYPE(upb::pb::CodeCache, upb_pbcodecache)
+UPB_DECLARE_TYPE(upb::pb::Decoder, upb_pbdecoder)
+UPB_DECLARE_TYPE(upb::pb::DecoderMethodOptions, upb_pbdecodermethodopts)
+
+UPB_DECLARE_DERIVED_TYPE(upb::pb::DecoderMethod, upb::RefCounted,
+                         upb_pbdecodermethod, upb_refcounted)
+
+/* The maximum number of bytes we are required to buffer internally between
+ * calls to the decoder.  The value is 14: a 5 byte unknown tag plus ten-byte
+ * varint, less one because we are buffering an incomplete value.
+ *
+ * Should only be used by unit tests. */
+#define UPB_DECODER_MAX_RESIDUAL_BYTES 14
+
+#ifdef __cplusplus
+
+/* The parameters one uses to construct a DecoderMethod.
+ * TODO(haberman): move allowjit here?  Seems more convenient for users.
+ * TODO(haberman): move this to be heap allocated for ABI stability. */
+class upb::pb::DecoderMethodOptions {
+ public:
+  /* Parameter represents the destination handlers that this method will push
+   * to. */
+  explicit DecoderMethodOptions(const Handlers* dest_handlers);
+
+  /* Should the decoder push submessages to lazy handlers for fields that have
+   * them?  The caller should set this iff the lazy handlers expect data that is
+   * in protobuf binary format and the caller wishes to lazy parse it. */
+  void set_lazy(bool lazy);
+#else
+struct upb_pbdecodermethodopts {
+#endif
+  const upb_handlers *handlers;
+  bool lazy;
+};
+
+#ifdef __cplusplus
+
+/* Represents the code to parse a protobuf according to a destination
+ * Handlers. */
+class upb::pb::DecoderMethod {
+ public:
+  /* Include base methods from upb::ReferenceCounted. */
+  UPB_REFCOUNTED_CPPMETHODS
+
+  /* The destination handlers that are statically bound to this method.
+   * This method is only capable of outputting to a sink that uses these
+   * handlers. */
+  const Handlers* dest_handlers() const;
+
+  /* The input handlers for this decoder method. */
+  const BytesHandler* input_handler() const;
+
+  /* Whether this method is native. */
+  bool is_native() const;
+
+  /* Convenience method for generating a DecoderMethod without explicitly
+   * creating a CodeCache. */
+  static reffed_ptr<const DecoderMethod> New(const DecoderMethodOptions& opts);
+
+ private:
+  UPB_DISALLOW_POD_OPS(DecoderMethod, upb::pb::DecoderMethod)
+};
+
+#endif
+
+/* Preallocation hint: decoder won't allocate more bytes than this when first
+ * constructed.  This hint may be an overestimate for some build configurations.
+ * But if the decoder library is upgraded without recompiling the application,
+ * it may be an underestimate. */
+#define UPB_PB_DECODER_SIZE 4416
+
+#ifdef __cplusplus
+
+/* A Decoder receives binary protobuf data on its input sink and pushes the
+ * decoded data to its output sink. */
+class upb::pb::Decoder {
+ public:
+  /* Constructs a decoder instance for the given method, which must outlive this
+   * decoder.  Any errors during parsing will be set on the given status, which
+   * must also outlive this decoder.
+   *
+   * The sink must match the given method. */
+  static Decoder* Create(Environment* env, const DecoderMethod* method,
+                         Sink* output);
+
+  /* Returns the DecoderMethod this decoder is parsing from. */
+  const DecoderMethod* method() const;
+
+  /* The sink on which this decoder receives input. */
+  BytesSink* input();
+
+  /* Returns number of bytes successfully parsed.
+   *
+   * This can be useful for determining the stream position where an error
+   * occurred.
+   *
+   * This value may not be up-to-date when called from inside a parsing
+   * callback. */
+  uint64_t BytesParsed() const;
+
+  /* Gets/sets the parsing nexting limit.  If the total number of nested
+   * submessages and repeated fields hits this limit, parsing will fail.  This
+   * is a resource limit that controls the amount of memory used by the parsing
+   * stack.
+   *
+   * Setting the limit will fail if the parser is currently suspended at a depth
+   * greater than this, or if memory allocation of the stack fails. */
+  size_t max_nesting() const;
+  bool set_max_nesting(size_t max);
+
+  void Reset();
+
+  static const size_t kSize = UPB_PB_DECODER_SIZE;
+
+ private:
+  UPB_DISALLOW_POD_OPS(Decoder, upb::pb::Decoder)
+};
+
+#endif  /* __cplusplus */
+
+#ifdef __cplusplus
+
+/* A class for caching protobuf processing code, whether bytecode for the
+ * interpreted decoder or machine code for the JIT.
+ *
+ * This class is not thread-safe.
+ *
+ * TODO(haberman): move this to be heap allocated for ABI stability. */
+class upb::pb::CodeCache {
+ public:
+  CodeCache();
+  ~CodeCache();
+
+  /* Whether the cache is allowed to generate machine code.  Defaults to true.
+   * There is no real reason to turn it off except for testing or if you are
+   * having a specific problem with the JIT.
+   *
+   * Note that allow_jit = true does not *guarantee* that the code will be JIT
+   * compiled.  If this platform is not supported or the JIT was not compiled
+   * in, the code may still be interpreted. */
+  bool allow_jit() const;
+
+  /* This may only be called when the object is first constructed, and prior to
+   * any code generation, otherwise returns false and does nothing. */
+  bool set_allow_jit(bool allow);
+
+  /* Returns a DecoderMethod that can push data to the given handlers.
+   * If a suitable method already exists, it will be returned from the cache.
+   *
+   * Specifying the destination handlers here allows the DecoderMethod to be
+   * statically bound to the destination handlers if possible, which can allow
+   * more efficient decoding.  However the returned method may or may not
+   * actually be statically bound.  But in all cases, the returned method can
+   * push data to the given handlers. */
+  const DecoderMethod *GetDecoderMethod(const DecoderMethodOptions& opts);
+
+  /* If/when someone needs to explicitly create a dynamically-bound
+   * DecoderMethod*, we can add a method to get it here. */
+
+ private:
+  UPB_DISALLOW_COPY_AND_ASSIGN(CodeCache)
+#else
+struct upb_pbcodecache {
+#endif
+  bool allow_jit_;
+
+  /* Array of mgroups. */
+  upb_inttable groups;
+};
+
+UPB_BEGIN_EXTERN_C
+
+upb_pbdecoder *upb_pbdecoder_create(upb_env *e,
+                                    const upb_pbdecodermethod *method,
+                                    upb_sink *output);
+const upb_pbdecodermethod *upb_pbdecoder_method(const upb_pbdecoder *d);
+upb_bytessink *upb_pbdecoder_input(upb_pbdecoder *d);
+uint64_t upb_pbdecoder_bytesparsed(const upb_pbdecoder *d);
+size_t upb_pbdecoder_maxnesting(const upb_pbdecoder *d);
+bool upb_pbdecoder_setmaxnesting(upb_pbdecoder *d, size_t max);
+void upb_pbdecoder_reset(upb_pbdecoder *d);
+
+void upb_pbdecodermethodopts_init(upb_pbdecodermethodopts *opts,
+                                  const upb_handlers *h);
+void upb_pbdecodermethodopts_setlazy(upb_pbdecodermethodopts *opts, bool lazy);
+
+
+/* Include refcounted methods like upb_pbdecodermethod_ref(). */
+UPB_REFCOUNTED_CMETHODS(upb_pbdecodermethod, upb_pbdecodermethod_upcast)
+
+const upb_handlers *upb_pbdecodermethod_desthandlers(
+    const upb_pbdecodermethod *m);
+const upb_byteshandler *upb_pbdecodermethod_inputhandler(
+    const upb_pbdecodermethod *m);
+bool upb_pbdecodermethod_isnative(const upb_pbdecodermethod *m);
+const upb_pbdecodermethod *upb_pbdecodermethod_new(
+    const upb_pbdecodermethodopts *opts, const void *owner);
+
+void upb_pbcodecache_init(upb_pbcodecache *c);
+void upb_pbcodecache_uninit(upb_pbcodecache *c);
+bool upb_pbcodecache_allowjit(const upb_pbcodecache *c);
+bool upb_pbcodecache_setallowjit(upb_pbcodecache *c, bool allow);
+const upb_pbdecodermethod *upb_pbcodecache_getdecodermethod(
+    upb_pbcodecache *c, const upb_pbdecodermethodopts *opts);
+
+UPB_END_EXTERN_C
+
+#ifdef __cplusplus
+
+namespace upb {
+
+namespace pb {
+
+/* static */
+inline Decoder* Decoder::Create(Environment* env, const DecoderMethod* m,
+                                Sink* sink) {
+  return upb_pbdecoder_create(env, m, sink);
+}
+inline const DecoderMethod* Decoder::method() const {
+  return upb_pbdecoder_method(this);
+}
+inline BytesSink* Decoder::input() {
+  return upb_pbdecoder_input(this);
+}
+inline uint64_t Decoder::BytesParsed() const {
+  return upb_pbdecoder_bytesparsed(this);
+}
+inline size_t Decoder::max_nesting() const {
+  return upb_pbdecoder_maxnesting(this);
+}
+inline bool Decoder::set_max_nesting(size_t max) {
+  return upb_pbdecoder_setmaxnesting(this, max);
+}
+inline void Decoder::Reset() { upb_pbdecoder_reset(this); }
+
+inline DecoderMethodOptions::DecoderMethodOptions(const Handlers* h) {
+  upb_pbdecodermethodopts_init(this, h);
+}
+inline void DecoderMethodOptions::set_lazy(bool lazy) {
+  upb_pbdecodermethodopts_setlazy(this, lazy);
+}
+
+inline const Handlers* DecoderMethod::dest_handlers() const {
+  return upb_pbdecodermethod_desthandlers(this);
+}
+inline const BytesHandler* DecoderMethod::input_handler() const {
+  return upb_pbdecodermethod_inputhandler(this);
+}
+inline bool DecoderMethod::is_native() const {
+  return upb_pbdecodermethod_isnative(this);
+}
+/* static */
+inline reffed_ptr<const DecoderMethod> DecoderMethod::New(
+    const DecoderMethodOptions &opts) {
+  const upb_pbdecodermethod *m = upb_pbdecodermethod_new(&opts, &m);
+  return reffed_ptr<const DecoderMethod>(m, &m);
+}
+
+inline CodeCache::CodeCache() {
+  upb_pbcodecache_init(this);
+}
+inline CodeCache::~CodeCache() {
+  upb_pbcodecache_uninit(this);
+}
+inline bool CodeCache::allow_jit() const {
+  return upb_pbcodecache_allowjit(this);
+}
+inline bool CodeCache::set_allow_jit(bool allow) {
+  return upb_pbcodecache_setallowjit(this, allow);
+}
+inline const DecoderMethod *CodeCache::GetDecoderMethod(
+    const DecoderMethodOptions& opts) {
+  return upb_pbcodecache_getdecodermethod(this, &opts);
+}
+
+}  /* namespace pb */
+}  /* namespace upb */
+
+#endif  /* __cplusplus */
+
+#endif  /* UPB_DECODER_H_ */
+
+/* C++ names are not actually used since this type isn't exposed to users. */
+#ifdef __cplusplus
+namespace upb {
+namespace pb {
+class MessageGroup;
+}  /* namespace pb */
+}  /* namespace upb */
+#endif
+UPB_DECLARE_DERIVED_TYPE(upb::pb::MessageGroup, upb::RefCounted,
+                         mgroup, upb_refcounted)
+
+/* Opcode definitions.  The canonical meaning of each opcode is its
+ * implementation in the interpreter (the JIT is written to match this).
+ *
+ * All instructions have the opcode in the low byte.
+ * Instruction format for most instructions is:
+ *
+ * +-------------------+--------+
+ * |     arg (24)      | op (8) |
+ * +-------------------+--------+
+ *
+ * Exceptions are indicated below.  A few opcodes are multi-word. */
+typedef enum {
+  /* Opcodes 1-8, 13, 15-18 parse their respective descriptor types.
+   * Arg for all of these is the upb selector for this field. */
+#define T(type) OP_PARSE_ ## type = UPB_DESCRIPTOR_TYPE_ ## type
+  T(DOUBLE), T(FLOAT), T(INT64), T(UINT64), T(INT32), T(FIXED64), T(FIXED32),
+  T(BOOL), T(UINT32), T(SFIXED32), T(SFIXED64), T(SINT32), T(SINT64),
+#undef T
+  OP_STARTMSG       = 9,   /* No arg. */
+  OP_ENDMSG         = 10,  /* No arg. */
+  OP_STARTSEQ       = 11,
+  OP_ENDSEQ         = 12,
+  OP_STARTSUBMSG    = 14,
+  OP_ENDSUBMSG      = 19,
+  OP_STARTSTR       = 20,
+  OP_STRING         = 21,
+  OP_ENDSTR         = 22,
+
+  OP_PUSHTAGDELIM   = 23,  /* No arg. */
+  OP_PUSHLENDELIM   = 24,  /* No arg. */
+  OP_POP            = 25,  /* No arg. */
+  OP_SETDELIM       = 26,  /* No arg. */
+  OP_SETBIGGROUPNUM = 27,  /* two words:
+                            *   | unused (24)     | opc (8) |
+                            *   |        groupnum (32)      | */
+  OP_CHECKDELIM     = 28,
+  OP_CALL           = 29,
+  OP_RET            = 30,
+  OP_BRANCH         = 31,
+
+  /* Different opcodes depending on how many bytes expected. */
+  OP_TAG1           = 32,  /* | match tag (16) | jump target (8) | opc (8) | */
+  OP_TAG2           = 33,  /* | match tag (16) | jump target (8) | opc (8) | */
+  OP_TAGN           = 34,  /* three words: */
+                           /*   | unused (16) | jump target(8) | opc (8) | */
+                           /*   |           match tag 1 (32)             | */
+                           /*   |           match tag 2 (32)             | */
+
+  OP_SETDISPATCH    = 35,  /* N words: */
+                           /*   | unused (24)         | opc | */
+                           /*   | upb_inttable* (32 or 64)  | */
+
+  OP_DISPATCH       = 36,  /* No arg. */
+
+  OP_HALT           = 37   /* No arg. */
+} opcode;
+
+#define OP_MAX OP_HALT
+
+UPB_INLINE opcode getop(uint32_t instr) { return instr & 0xff; }
+
+/* Method group; represents a set of decoder methods that had their code
+ * emitted together, and must therefore be freed together.  Immutable once
+ * created.  It is possible we may want to expose this to users at some point.
+ *
+ * Overall ownership of Decoder objects looks like this:
+ *
+ *                +----------+
+ *                |          | <---> DecoderMethod
+ *                | method   |
+ * CodeCache ---> |  group   | <---> DecoderMethod
+ *                |          |
+ *                | (mgroup) | <---> DecoderMethod
+ *                +----------+
+ */
+struct mgroup {
+  upb_refcounted base;
+
+  /* Maps upb_msgdef/upb_handlers -> upb_pbdecodermethod.  We own refs on the
+   * methods. */
+  upb_inttable methods;
+
+  /* When we add the ability to link to previously existing mgroups, we'll
+   * need an array of mgroups we reference here, and own refs on them. */
+
+  /* The bytecode for our methods, if any exists.  Owned by us. */
+  uint32_t *bytecode;
+  uint32_t *bytecode_end;
+
+#ifdef UPB_USE_JIT_X64
+  /* JIT-generated machine code, if any. */
+  upb_string_handlerfunc *jit_code;
+  /* The size of the jit_code (required to munmap()). */
+  size_t jit_size;
+  char *debug_info;
+  void *dl;
+#endif
+};
+
+/* The maximum that any submessages can be nested.  Matches proto2's limit.
+ * This specifies the size of the decoder's statically-sized array and therefore
+ * setting it high will cause the upb::pb::Decoder object to be larger.
+ *
+ * If necessary we can add a runtime-settable property to Decoder that allow
+ * this to be larger than the compile-time setting, but this would add
+ * complexity, particularly since we would have to decide how/if to give users
+ * the ability to set a custom memory allocation function. */
+#define UPB_DECODER_MAX_NESTING 64
+
+/* Internal-only struct used by the decoder. */
+typedef struct {
+  /* Space optimization note: we store two pointers here that the JIT
+   * doesn't need at all; the upb_handlers* inside the sink and
+   * the dispatch table pointer.  We can optimze so that the JIT uses
+   * smaller stack frames than the interpreter.  The only thing we need
+   * to guarantee is that the fallback routines can find end_ofs. */
+  upb_sink sink;
+
+  /* The absolute stream offset of the end-of-frame delimiter.
+   * Non-delimited frames (groups and non-packed repeated fields) reuse the
+   * delimiter of their parent, even though the frame may not end there.
+   *
+   * NOTE: the JIT stores a slightly different value here for non-top frames.
+   * It stores the value relative to the end of the enclosed message.  But the
+   * top frame is still stored the same way, which is important for ensuring
+   * that calls from the JIT into C work correctly. */
+  uint64_t end_ofs;
+  const uint32_t *base;
+
+  /* 0 indicates a length-delimited field.
+   * A positive number indicates a known group.
+   * A negative number indicates an unknown group. */
+  int32_t groupnum;
+  upb_inttable *dispatch;  /* Not used by the JIT. */
+} upb_pbdecoder_frame;
+
+struct upb_pbdecodermethod {
+  upb_refcounted base;
+
+  /* While compiling, the base is relative in "ofs", after compiling it is
+   * absolute in "ptr". */
+  union {
+    uint32_t ofs;     /* PC offset of method. */
+    void *ptr;        /* Pointer to bytecode or machine code for this method. */
+  } code_base;
+
+  /* The decoder method group to which this method belongs.  We own a ref.
+   * Owning a ref on the entire group is more coarse-grained than is strictly
+   * necessary; all we truly require is that methods we directly reference
+   * outlive us, while the group could contain many other messages we don't
+   * require.  But the group represents the messages that were
+   * allocated+compiled together, so it makes the most sense to free them
+   * together also. */
+  const upb_refcounted *group;
+
+  /* Whether this method is native code or bytecode. */
+  bool is_native_;
+
+  /* The handler one calls to invoke this method. */
+  upb_byteshandler input_handler_;
+
+  /* The destination handlers this method is bound to.  We own a ref. */
+  const upb_handlers *dest_handlers_;
+
+  /* Dispatch table -- used by both bytecode decoder and JIT when encountering a
+   * field number that wasn't the one we were expecting to see.  See
+   * decoder.int.h for the layout of this table. */
+  upb_inttable dispatch;
+};
+
+struct upb_pbdecoder {
+  upb_env *env;
+
+  /* Our input sink. */
+  upb_bytessink input_;
+
+  /* The decoder method we are parsing with (owned). */
+  const upb_pbdecodermethod *method_;
+
+  size_t call_len;
+  const uint32_t *pc, *last;
+
+  /* Current input buffer and its stream offset. */
+  const char *buf, *ptr, *end, *checkpoint;
+
+  /* End of the delimited region, relative to ptr, NULL if not in this buf. */
+  const char *delim_end;
+
+  /* End of the delimited region, relative to ptr, end if not in this buf. */
+  const char *data_end;
+
+  /* Overall stream offset of "buf." */
+  uint64_t bufstart_ofs;
+
+  /* Buffer for residual bytes not parsed from the previous buffer. */
+  char residual[UPB_DECODER_MAX_RESIDUAL_BYTES];
+  char *residual_end;
+
+  /* Bytes of data that should be discarded from the input beore we start
+   * parsing again.  We set this when we internally determine that we can
+   * safely skip the next N bytes, but this region extends past the current
+   * user buffer. */
+  size_t skip;
+
+  /* Stores the user buffer passed to our decode function. */
+  const char *buf_param;
+  size_t size_param;
+  const upb_bufhandle *handle;
+
+  /* Our internal stack. */
+  upb_pbdecoder_frame *stack, *top, *limit;
+  const uint32_t **callstack;
+  size_t stack_size;
+
+  upb_status *status;
+
+#ifdef UPB_USE_JIT_X64
+  /* Used momentarily by the generated code to store a value while a user
+   * function is called. */
+  uint32_t tmp_len;
+
+  const void *saved_rsp;
+#endif
+};
+
+/* Decoder entry points; used as handlers. */
+void *upb_pbdecoder_startbc(void *closure, const void *pc, size_t size_hint);
+void *upb_pbdecoder_startjit(void *closure, const void *hd, size_t size_hint);
+size_t upb_pbdecoder_decode(void *closure, const void *hd, const char *buf,
+                            size_t size, const upb_bufhandle *handle);
+bool upb_pbdecoder_end(void *closure, const void *handler_data);
+
+/* Decoder-internal functions that the JIT calls to handle fallback paths. */
+int32_t upb_pbdecoder_resume(upb_pbdecoder *d, void *p, const char *buf,
+                             size_t size, const upb_bufhandle *handle);
+size_t upb_pbdecoder_suspend(upb_pbdecoder *d);
+int32_t upb_pbdecoder_skipunknown(upb_pbdecoder *d, int32_t fieldnum,
+                                  uint8_t wire_type);
+int32_t upb_pbdecoder_checktag_slow(upb_pbdecoder *d, uint64_t expected);
+int32_t upb_pbdecoder_decode_varint_slow(upb_pbdecoder *d, uint64_t *u64);
+int32_t upb_pbdecoder_decode_f32(upb_pbdecoder *d, uint32_t *u32);
+int32_t upb_pbdecoder_decode_f64(upb_pbdecoder *d, uint64_t *u64);
+void upb_pbdecoder_seterr(upb_pbdecoder *d, const char *msg);
+
+/* Error messages that are shared between the bytecode and JIT decoders. */
+extern const char *kPbDecoderStackOverflow;
+extern const char *kPbDecoderSubmessageTooLong;
+
+/* Access to decoderplan members needed by the decoder. */
+const char *upb_pbdecoder_getopname(unsigned int op);
+
+/* JIT codegen entry point. */
+void upb_pbdecoder_jit(mgroup *group);
+void upb_pbdecoder_freejit(mgroup *group);
+UPB_REFCOUNTED_CMETHODS(mgroup, mgroup_upcast)
+
+/* A special label that means "do field dispatch for this message and branch to
+ * wherever that takes you." */
+#define LABEL_DISPATCH 0
+
+/* A special slot in the dispatch table that stores the epilogue (ENDMSG and/or
+ * RET) for branching to when we find an appropriate ENDGROUP tag. */
+#define DISPATCH_ENDMSG 0
+
+/* It's important to use this invalid wire type instead of 0 (which is a valid
+ * wire type). */
+#define NO_WIRE_TYPE 0xff
+
+/* The dispatch table layout is:
+ *   [field number] -> [ 48-bit offset ][ 8-bit wt2 ][ 8-bit wt1 ]
+ *
+ * If wt1 matches, jump to the 48-bit offset.  If wt2 matches, lookup
+ * (UPB_MAX_FIELDNUMBER + fieldnum) and jump there.
+ *
+ * We need two wire types because of packed/non-packed compatibility.  A
+ * primitive repeated field can use either wire type and be valid.  While we
+ * could key the table on fieldnum+wiretype, the table would be 8x sparser.
+ *
+ * Storing two wire types in the primary value allows us to quickly rule out
+ * the second wire type without needing to do a separate lookup (this case is
+ * less common than an unknown field). */
+UPB_INLINE uint64_t upb_pbdecoder_packdispatch(uint64_t ofs, uint8_t wt1,
+                                               uint8_t wt2) {
+  return (ofs << 16) | (wt2 << 8) | wt1;
+}
+
+UPB_INLINE void upb_pbdecoder_unpackdispatch(uint64_t dispatch, uint64_t *ofs,
+                                             uint8_t *wt1, uint8_t *wt2) {
+  *wt1 = (uint8_t)dispatch;
+  *wt2 = (uint8_t)(dispatch >> 8);
+  *ofs = dispatch >> 16;
+}
+
+/* All of the functions in decoder.c that return int32_t return values according
+ * to the following scheme:
+ *   1. negative values indicate a return code from the following list.
+ *   2. positive values indicate that error or end of buffer was hit, and
+ *      that the decode function should immediately return the given value
+ *      (the decoder state has already been suspended and is ready to be
+ *      resumed). */
+#define DECODE_OK -1
+#define DECODE_MISMATCH -2  /* Used only from checktag_slow(). */
+#define DECODE_ENDGROUP -3  /* Used only from checkunknown(). */
+
+#define CHECK_RETURN(x) { int32_t ret = x; if (ret >= 0) return ret; }
+
+#endif  /* UPB_DECODER_INT_H_ */
+/*
+** A number of routines for varint manipulation (we keep them all around to
+** have multiple approaches available for benchmarking).
+*/
+
+#ifndef UPB_VARINT_DECODER_H_
+#define UPB_VARINT_DECODER_H_
+
+#include <assert.h>
+#include <stdint.h>
+#include <string.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define UPB_MAX_WIRE_TYPE 5
+
+/* The maximum number of bytes that it takes to encode a 64-bit varint. */
+#define UPB_PB_VARINT_MAX_LEN 10
+
+/* Array of the "native" (ie. non-packed-repeated) wire type for the given a
+ * descriptor type (upb_descriptortype_t). */
+extern const uint8_t upb_pb_native_wire_types[];
+
+/* Zig-zag encoding/decoding **************************************************/
+
+UPB_INLINE int32_t upb_zzdec_32(uint32_t n) {
+  return (n >> 1) ^ -(int32_t)(n & 1);
+}
+UPB_INLINE int64_t upb_zzdec_64(uint64_t n) {
+  return (n >> 1) ^ -(int64_t)(n & 1);
+}
+UPB_INLINE uint32_t upb_zzenc_32(int32_t n) { return (n << 1) ^ (n >> 31); }
+UPB_INLINE uint64_t upb_zzenc_64(int64_t n) { return (n << 1) ^ (n >> 63); }
+
+/* Decoding *******************************************************************/
+
+/* All decoding functions return this struct by value. */
+typedef struct {
+  const char *p;  /* NULL if the varint was unterminated. */
+  uint64_t val;
+} upb_decoderet;
+
+UPB_INLINE upb_decoderet upb_decoderet_make(const char *p, uint64_t val) {
+  upb_decoderet ret;
+  ret.p = p;
+  ret.val = val;
+  return ret;
+}
+
+upb_decoderet upb_vdecode_max8_branch32(upb_decoderet r);
+upb_decoderet upb_vdecode_max8_branch64(upb_decoderet r);
+
+/* Template for a function that checks the first two bytes with branching
+ * and dispatches 2-10 bytes with a separate function.  Note that this may read
+ * up to 10 bytes, so it must not be used unless there are at least ten bytes
+ * left in the buffer! */
+#define UPB_VARINT_DECODER_CHECK2(name, decode_max8_function)                  \
+UPB_INLINE upb_decoderet upb_vdecode_check2_ ## name(const char *_p) {         \
+  uint8_t *p = (uint8_t*)_p;                                                   \
+  upb_decoderet r;                                                             \
+  if ((*p & 0x80) == 0) {                                                      \
+  /* Common case: one-byte varint. */                                          \
+    return upb_decoderet_make(_p + 1, *p & 0x7fU);                             \
+  }                                                                            \
+  r = upb_decoderet_make(_p + 2, (*p & 0x7fU) | ((*(p + 1) & 0x7fU) << 7));    \
+  if ((*(p + 1) & 0x80) == 0) {                                                \
+    /* Two-byte varint. */                                                     \
+    return r;                                                                  \
+  }                                                                            \
+  /* Longer varint, fallback to out-of-line function. */                       \
+  return decode_max8_function(r);                                              \
+}
+
+UPB_VARINT_DECODER_CHECK2(branch32, upb_vdecode_max8_branch32)
+UPB_VARINT_DECODER_CHECK2(branch64, upb_vdecode_max8_branch64)
+#undef UPB_VARINT_DECODER_CHECK2
+
+/* Our canonical functions for decoding varints, based on the currently
+ * favored best-performing implementations. */
+UPB_INLINE upb_decoderet upb_vdecode_fast(const char *p) {
+  if (sizeof(long) == 8)
+    return upb_vdecode_check2_branch64(p);
+  else
+    return upb_vdecode_check2_branch32(p);
+}
+
+
+/* Encoding *******************************************************************/
+
+UPB_INLINE int upb_value_size(uint64_t val) {
+#ifdef __GNUC__
+  int high_bit = 63 - __builtin_clzll(val);  /* 0-based, undef if val == 0. */
+#else
+  int high_bit = 0;
+  uint64_t tmp = val;
+  while(tmp >>= 1) high_bit++;
+#endif
+  return val == 0 ? 1 : high_bit / 8 + 1;
+}
+
+/* Encodes a 64-bit varint into buf (which must be >=UPB_PB_VARINT_MAX_LEN
+ * bytes long), returning how many bytes were used.
+ *
+ * TODO: benchmark and optimize if necessary. */
+UPB_INLINE size_t upb_vencode64(uint64_t val, char *buf) {
+  size_t i;
+  if (val == 0) { buf[0] = 0; return 1; }
+  i = 0;
+  while (val) {
+    uint8_t byte = val & 0x7fU;
+    val >>= 7;
+    if (val) byte |= 0x80U;
+    buf[i++] = byte;
+  }
+  return i;
+}
+
+UPB_INLINE size_t upb_varint_size(uint64_t val) {
+  char buf[UPB_PB_VARINT_MAX_LEN];
+  return upb_vencode64(val, buf);
+}
+
+/* Encodes a 32-bit varint, *not* sign-extended. */
+UPB_INLINE uint64_t upb_vencode32(uint32_t val) {
+  char buf[UPB_PB_VARINT_MAX_LEN];
+  size_t bytes = upb_vencode64(val, buf);
+  uint64_t ret = 0;
+  UPB_ASSERT(bytes <= 5);
+  memcpy(&ret, buf, bytes);
+  UPB_ASSERT(ret <= 0xffffffffffU);
+  return ret;
+}
+
+#ifdef __cplusplus
+}  /* extern "C" */
+#endif
+
+#endif  /* UPB_VARINT_DECODER_H_ */
+/*
+** upb::pb::Encoder (upb_pb_encoder)
+**
+** Implements a set of upb_handlers that write protobuf data to the binary wire
+** format.
+**
+** This encoder implementation does not have any access to any out-of-band or
+** precomputed lengths for submessages, so it must buffer submessages internally
+** before it can emit the first byte.
+*/
+
+#ifndef UPB_ENCODER_H_
+#define UPB_ENCODER_H_
+
+
+#ifdef __cplusplus
+namespace upb {
+namespace pb {
+class Encoder;
+}  /* namespace pb */
+}  /* namespace upb */
+#endif
+
+UPB_DECLARE_TYPE(upb::pb::Encoder, upb_pb_encoder)
+
+#define UPB_PBENCODER_MAX_NESTING 100
+
+/* upb::pb::Encoder ***********************************************************/
+
+/* Preallocation hint: decoder won't allocate more bytes than this when first
+ * constructed.  This hint may be an overestimate for some build configurations.
+ * But if the decoder library is upgraded without recompiling the application,
+ * it may be an underestimate. */
+#define UPB_PB_ENCODER_SIZE 768
+
+#ifdef __cplusplus
+
+class upb::pb::Encoder {
+ public:
+  /* Creates a new encoder in the given environment.  The Handlers must have
+   * come from NewHandlers() below. */
+  static Encoder* Create(Environment* env, const Handlers* handlers,
+                         BytesSink* output);
+
+  /* The input to the encoder. */
+  Sink* input();
+
+  /* Creates a new set of handlers for this MessageDef. */
+  static reffed_ptr<const Handlers> NewHandlers(const MessageDef* msg);
+
+  static const size_t kSize = UPB_PB_ENCODER_SIZE;
+
+ private:
+  UPB_DISALLOW_POD_OPS(Encoder, upb::pb::Encoder)
+};
+
+#endif
+
+UPB_BEGIN_EXTERN_C
+
+const upb_handlers *upb_pb_encoder_newhandlers(const upb_msgdef *m,
+                                               const void *owner);
+upb_sink *upb_pb_encoder_input(upb_pb_encoder *p);
+upb_pb_encoder* upb_pb_encoder_create(upb_env* e, const upb_handlers* h,
+                                      upb_bytessink* output);
+
+UPB_END_EXTERN_C
+
+#ifdef __cplusplus
+
+namespace upb {
+namespace pb {
+inline Encoder* Encoder::Create(Environment* env, const Handlers* handlers,
+                                BytesSink* output) {
+  return upb_pb_encoder_create(env, handlers, output);
+}
+inline Sink* Encoder::input() {
+  return upb_pb_encoder_input(this);
+}
+inline reffed_ptr<const Handlers> Encoder::NewHandlers(
+    const upb::MessageDef *md) {
+  const Handlers* h = upb_pb_encoder_newhandlers(md, &h);
+  return reffed_ptr<const Handlers>(h, &h);
+}
+}  /* namespace pb */
+}  /* namespace upb */
+
+#endif
+
+#endif  /* UPB_ENCODER_H_ */
+/*
+** upb's core components like upb_decoder and upb_msg are carefully designed to
+** avoid depending on each other for maximum orthogonality.  In other words,
+** you can use a upb_decoder to decode into *any* kind of structure; upb_msg is
+** just one such structure.  A upb_msg can be serialized/deserialized into any
+** format, protobuf binary format is just one such format.
+**
+** However, for convenience we provide functions here for doing common
+** operations like deserializing protobuf binary format into a upb_msg.  The
+** compromise is that this file drags in almost all of upb as a dependency,
+** which could be undesirable if you're trying to use a trimmed-down build of
+** upb.
+**
+** While these routines are convenient, they do not reuse any encoding/decoding
+** state.  For example, if a decoder is JIT-based, it will be re-JITted every
+** time these functions are called.  For this reason, if you are parsing lots
+** of data and efficiency is an issue, these may not be the best functions to
+** use (though they are useful for prototyping, before optimizing).
+*/
+
+#ifndef UPB_GLUE_H
+#define UPB_GLUE_H
+
+#include <stdbool.h>
+
+#ifdef __cplusplus
+#include <vector>
+
+extern "C" {
+#endif
+
+/* Loads a binary descriptor and returns a NULL-terminated array of unfrozen
+ * filedefs.  The caller owns the returned array, which must be freed with
+ * upb_gfree(). */
+upb_filedef **upb_loaddescriptor(const char *buf, size_t n, const void *owner,
+                                 upb_status *status);
+
+#ifdef __cplusplus
+}  /* extern "C" */
+
+namespace upb {
+
+inline bool LoadDescriptor(const char* buf, size_t n, Status* status,
+                           std::vector<reffed_ptr<FileDef> >* files) {
+  FileDef** parsed_files = upb_loaddescriptor(buf, n, &parsed_files, status);
+
+  if (parsed_files) {
+    FileDef** p = parsed_files;
+    while (*p) {
+      files->push_back(reffed_ptr<FileDef>(*p, &parsed_files));
+      ++p;
+    }
+    free(parsed_files);
+    return true;
+  } else {
+    return false;
+  }
+}
+
+/* Templated so it can accept both string and std::string. */
+template <typename T>
+bool LoadDescriptor(const T& desc, Status* status,
+                    std::vector<reffed_ptr<FileDef> >* files) {
+  return LoadDescriptor(desc.c_str(), desc.size(), status, files);
+}
+
+}  /* namespace upb */
+
+#endif
+
+#endif  /* UPB_GLUE_H */
+/*
+** upb::pb::TextPrinter (upb_textprinter)
+**
+** Handlers for writing to protobuf text format.
+*/
+
+#ifndef UPB_TEXT_H_
+#define UPB_TEXT_H_
+
+
+#ifdef __cplusplus
+namespace upb {
+namespace pb {
+class TextPrinter;
+}  /* namespace pb */
+}  /* namespace upb */
+#endif
+
+UPB_DECLARE_TYPE(upb::pb::TextPrinter, upb_textprinter)
+
+#ifdef __cplusplus
+
+class upb::pb::TextPrinter {
+ public:
+  /* The given handlers must have come from NewHandlers().  It must outlive the
+   * TextPrinter. */
+  static TextPrinter *Create(Environment *env, const upb::Handlers *handlers,
+                             BytesSink *output);
+
+  void SetSingleLineMode(bool single_line);
+
+  Sink* input();
+
+  /* If handler caching becomes a requirement we can add a code cache as in
+   * decoder.h */
+  static reffed_ptr<const Handlers> NewHandlers(const MessageDef* md);
+};
+
+#endif
+
+UPB_BEGIN_EXTERN_C
+
+/* C API. */
+upb_textprinter *upb_textprinter_create(upb_env *env, const upb_handlers *h,
+                                        upb_bytessink *output);
+void upb_textprinter_setsingleline(upb_textprinter *p, bool single_line);
+upb_sink *upb_textprinter_input(upb_textprinter *p);
+
+const upb_handlers *upb_textprinter_newhandlers(const upb_msgdef *m,
+                                                const void *owner);
+
+UPB_END_EXTERN_C
+
+#ifdef __cplusplus
+
+namespace upb {
+namespace pb {
+inline TextPrinter *TextPrinter::Create(Environment *env,
+                                        const upb::Handlers *handlers,
+                                        BytesSink *output) {
+  return upb_textprinter_create(env, handlers, output);
+}
+inline void TextPrinter::SetSingleLineMode(bool single_line) {
+  upb_textprinter_setsingleline(this, single_line);
+}
+inline Sink* TextPrinter::input() {
+  return upb_textprinter_input(this);
+}
+inline reffed_ptr<const Handlers> TextPrinter::NewHandlers(
+    const MessageDef *md) {
+  const Handlers* h = upb_textprinter_newhandlers(md, &h);
+  return reffed_ptr<const Handlers>(h, &h);
+}
+}  /* namespace pb */
+}  /* namespace upb */
+
+#endif
+
+#endif  /* UPB_TEXT_H_ */
+/*
+** upb::json::Parser (upb_json_parser)
+**
+** Parses JSON according to a specific schema.
+** Support for parsing arbitrary JSON (schema-less) will be added later.
+*/
+
+#ifndef UPB_JSON_PARSER_H_
+#define UPB_JSON_PARSER_H_
+
+
+#ifdef __cplusplus
+namespace upb {
+namespace json {
+class Parser;
+class ParserMethod;
+}  /* namespace json */
+}  /* namespace upb */
+#endif
+
+UPB_DECLARE_TYPE(upb::json::Parser, upb_json_parser)
+UPB_DECLARE_DERIVED_TYPE(upb::json::ParserMethod, upb::RefCounted,
+                         upb_json_parsermethod, upb_refcounted)
+
+/* upb::json::Parser **********************************************************/
+
+/* Preallocation hint: parser won't allocate more bytes than this when first
+ * constructed.  This hint may be an overestimate for some build configurations.
+ * But if the parser library is upgraded without recompiling the application,
+ * it may be an underestimate. */
+#define UPB_JSON_PARSER_SIZE 4112
+
+#ifdef __cplusplus
+
+/* Parses an incoming BytesStream, pushing the results to the destination
+ * sink. */
+class upb::json::Parser {
+ public:
+  static Parser* Create(Environment* env, const ParserMethod* method,
+                        Sink* output);
+
+  BytesSink* input();
+
+ private:
+  UPB_DISALLOW_POD_OPS(Parser, upb::json::Parser)
+};
+
+class upb::json::ParserMethod {
+ public:
+  /* Include base methods from upb::ReferenceCounted. */
+  UPB_REFCOUNTED_CPPMETHODS
+
+  /* Returns handlers for parsing according to the specified schema. */
+  static reffed_ptr<const ParserMethod> New(const upb::MessageDef* md);
+
+  /* The destination handlers that are statically bound to this method.
+   * This method is only capable of outputting to a sink that uses these
+   * handlers. */
+  const Handlers* dest_handlers() const;
+
+  /* The input handlers for this decoder method. */
+  const BytesHandler* input_handler() const;
+
+ private:
+  UPB_DISALLOW_POD_OPS(ParserMethod, upb::json::ParserMethod)
+};
+
+#endif
+
+UPB_BEGIN_EXTERN_C
+
+upb_json_parser* upb_json_parser_create(upb_env* e,
+                                        const upb_json_parsermethod* m,
+                                        upb_sink* output);
+upb_bytessink *upb_json_parser_input(upb_json_parser *p);
+
+upb_json_parsermethod* upb_json_parsermethod_new(const upb_msgdef* md,
+                                                 const void* owner);
+const upb_handlers *upb_json_parsermethod_desthandlers(
+    const upb_json_parsermethod *m);
+const upb_byteshandler *upb_json_parsermethod_inputhandler(
+    const upb_json_parsermethod *m);
+
+/* Include refcounted methods like upb_json_parsermethod_ref(). */
+UPB_REFCOUNTED_CMETHODS(upb_json_parsermethod, upb_json_parsermethod_upcast)
+
+UPB_END_EXTERN_C
+
+#ifdef __cplusplus
+
+namespace upb {
+namespace json {
+inline Parser* Parser::Create(Environment* env, const ParserMethod* method,
+                              Sink* output) {
+  return upb_json_parser_create(env, method, output);
+}
+inline BytesSink* Parser::input() {
+  return upb_json_parser_input(this);
+}
+
+inline const Handlers* ParserMethod::dest_handlers() const {
+  return upb_json_parsermethod_desthandlers(this);
+}
+inline const BytesHandler* ParserMethod::input_handler() const {
+  return upb_json_parsermethod_inputhandler(this);
+}
+/* static */
+inline reffed_ptr<const ParserMethod> ParserMethod::New(
+    const MessageDef* md) {
+  const upb_json_parsermethod *m = upb_json_parsermethod_new(md, &m);
+  return reffed_ptr<const ParserMethod>(m, &m);
+}
+
+}  /* namespace json */
+}  /* namespace upb */
+
+#endif
+
+
+#endif  /* UPB_JSON_PARSER_H_ */
+/*
+** upb::json::Printer
+**
+** Handlers that emit JSON according to a specific protobuf schema.
+*/
+
+#ifndef UPB_JSON_TYPED_PRINTER_H_
+#define UPB_JSON_TYPED_PRINTER_H_
+
+
+#ifdef __cplusplus
+namespace upb {
+namespace json {
+class Printer;
+}  /* namespace json */
+}  /* namespace upb */
+#endif
+
+UPB_DECLARE_TYPE(upb::json::Printer, upb_json_printer)
+
+
+/* upb::json::Printer *********************************************************/
+
+#define UPB_JSON_PRINTER_SIZE 176
+
+#ifdef __cplusplus
+
+/* Prints an incoming stream of data to a BytesSink in JSON format. */
+class upb::json::Printer {
+ public:
+  static Printer* Create(Environment* env, const upb::Handlers* handlers,
+                         BytesSink* output);
+
+  /* The input to the printer. */
+  Sink* input();
+
+  /* Returns handlers for printing according to the specified schema.
+   * If preserve_proto_fieldnames is true, the output JSON will use the
+   * original .proto field names (ie. {"my_field":3}) instead of using
+   * camelCased names, which is the default: (eg. {"myField":3}). */
+  static reffed_ptr<const Handlers> NewHandlers(const upb::MessageDef* md,
+                                                bool preserve_proto_fieldnames);
+
+  static const size_t kSize = UPB_JSON_PRINTER_SIZE;
+
+ private:
+  UPB_DISALLOW_POD_OPS(Printer, upb::json::Printer)
+};
+
+#endif
+
+UPB_BEGIN_EXTERN_C
+
+/* Native C API. */
+upb_json_printer *upb_json_printer_create(upb_env *e, const upb_handlers *h,
+                                          upb_bytessink *output);
+upb_sink *upb_json_printer_input(upb_json_printer *p);
+const upb_handlers *upb_json_printer_newhandlers(const upb_msgdef *md,
+                                                 bool preserve_fieldnames,
+                                                 const void *owner);
+
+UPB_END_EXTERN_C
+
+#ifdef __cplusplus
+
+namespace upb {
+namespace json {
+inline Printer* Printer::Create(Environment* env, const upb::Handlers* handlers,
+                                BytesSink* output) {
+  return upb_json_printer_create(env, handlers, output);
+}
+inline Sink* Printer::input() { return upb_json_printer_input(this); }
+inline reffed_ptr<const Handlers> Printer::NewHandlers(
+    const upb::MessageDef *md, bool preserve_proto_fieldnames) {
+  const Handlers* h = upb_json_printer_newhandlers(
+      md, preserve_proto_fieldnames, &h);
+  return reffed_ptr<const Handlers>(h, &h);
+}
+}  /* namespace json */
+}  /* namespace upb */
+
+#endif
+
+#endif  /* UPB_JSON_TYPED_PRINTER_H_ */
diff --git a/php/ext/google/protobuf/utf8.c b/php/ext/google/protobuf/utf8.c
new file mode 100644
index 0000000..2752a08
--- /dev/null
+++ b/php/ext/google/protobuf/utf8.c
@@ -0,0 +1,68 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// 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.
+
+#include <stdbool.h>
+#include <stdint.h>
+
+#include "utf8.h"
+
+static const uint8_t utf8_offset[] = {
+    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+    1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+    2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+    4, 4, 4, 4, 4, 4, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0,
+};
+
+bool is_structurally_valid_utf8(const char* buf, int len) {
+  int i, j;
+  uint8_t offset;
+
+  i = 0;
+  while (i < len) {
+    offset = utf8_offset[(uint8_t)buf[i]];
+    if (offset == 0 || i + offset > len) {
+      return false;
+    }
+    for (j = i + 1; j < i + offset; j++) {
+      if ((buf[j] & 0xc0) != 0x80) {
+        return false;
+      }
+    }
+    i += offset;
+  }
+  return i == len;
+}
diff --git a/php/ext/google/protobuf/utf8.h b/php/ext/google/protobuf/utf8.h
new file mode 100644
index 0000000..28b8d87
--- /dev/null
+++ b/php/ext/google/protobuf/utf8.h
@@ -0,0 +1,36 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// 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 GOOGLE_PROTOBUF_UTF8_H_
+#define GOOGLE_PROTOBUF_UTF8_H_
+
+bool is_structurally_valid_utf8(const char* buf, int len);
+
+#endif  // GOOGLE_PROTOBUF_UTF8_H_