瀏覽代碼

Merge branch 'master' into layout_clear

Joshua Haberman 6 年之前
父節點
當前提交
78378dab22

+ 1 - 1
Makefile.am

@@ -1236,7 +1236,7 @@ EXTRA_DIST = $(@DIST_LANG@_EXTRA_DIST)   \
   python/release/wheel/Dockerfile                \
   python/release/wheel/protobuf_optimized_pip.sh \
   python/release/wheel/README.md         \
-  six.BUILD                              \
+  third_party/six.BUILD                  \
   third_party/zlib.BUILD                 \
   util/python/BUILD
 

+ 0 - 7
WORKSPACE

@@ -16,13 +16,6 @@ load("//:protobuf_deps.bzl", "protobuf_deps")
 # Load common dependencies.
 protobuf_deps()
 
-http_archive(
-    name = "six",
-    build_file = "@//:six.BUILD",
-    sha256 = "105f8d68616f8248e24bf0e9372ef04d3cc10104f1980f54d57b2ce73a5ad56a",
-    urls = ["https://pypi.python.org/packages/source/s/six/six-1.10.0.tar.gz#md5=34eed507548117b2ab523ab14b2f8b55"],
-)
-
 bind(
     name = "python_headers",
     actual = "//util/python:python_headers",

+ 0 - 2
conformance/failure_list_php_c.txt

@@ -58,8 +58,6 @@ Required.Proto3.JsonInput.FloatFieldInfinity.JsonOutput
 Required.Proto3.JsonInput.FloatFieldNan.JsonOutput
 Required.Proto3.JsonInput.FloatFieldNegativeInfinity.JsonOutput
 Required.Proto3.JsonInput.OneofFieldDuplicate
-Required.Proto3.JsonInput.OptionalWrapperTypesWithNonDefaultValue.JsonOutput
-Required.Proto3.JsonInput.OptionalWrapperTypesWithNonDefaultValue.ProtobufOutput
 Required.Proto3.JsonInput.RejectTopLevelNull
 Required.Proto3.JsonInput.StringFieldSurrogatePair.JsonOutput
 Required.Proto3.JsonInput.StringFieldSurrogatePair.ProtobufOutput

+ 6 - 3
php/ext/google/protobuf/upb.c

@@ -9964,7 +9964,8 @@ static bool start_any_stringval(upb_json_parser *p) {
 
 static bool start_stringval(upb_json_parser *p) {
   if (is_top_level(p)) {
-    if (is_string_wrapper_object(p)) {
+    if (is_string_wrapper_object(p) ||
+        is_number_wrapper_object(p)) {
       start_wrapper_object(p);
     } else if (is_wellknown_msg(p, UPB_WELLKNOWN_FIELDMASK)) {
       start_fieldmask_object(p);
@@ -9977,7 +9978,8 @@ static bool start_stringval(upb_json_parser *p) {
     } else {
       return false;
     }
-  } else if (does_string_wrapper_start(p)) {
+  } else if (does_string_wrapper_start(p) ||
+             does_number_wrapper_start(p)) {
     if (!start_subobject(p)) {
       return false;
     }
@@ -10183,7 +10185,8 @@ static bool end_stringval(upb_json_parser *p) {
     return false;
   }
 
-  if (does_string_wrapper_end(p)) {
+  if (does_string_wrapper_end(p) ||
+      does_number_wrapper_end(p)) {
     end_wrapper_object(p);
     if (!is_top_level(p)) {
       end_subobject(p);

+ 26 - 12
php/tests/encode_decode_test.php

@@ -118,12 +118,19 @@ class EncodeDecodeTest extends TestBase
         $this->assertEquals(1, $m->getValue());
     }
 
-    # public function testEncodeTopLevelInt64Value()
-    # {
-    #     $m = new Int64Value();
-    #     $m->setValue(1);
-    #     $this->assertSame("\"1\"", $m->serializeToJsonString());
-    # }
+    public function testDecodeTopLevelInt64ValueAsString()
+    {
+        $m = new Int64Value();
+        $m->mergeFromJsonString("\"1\"");
+        $this->assertEquals(1, $m->getValue());
+    }
+
+    public function testEncodeTopLevelInt64Value()
+    {
+        $m = new Int64Value();
+        $m->setValue(1);
+        $this->assertSame("\"1\"", $m->serializeToJsonString());
+    }
 
     public function testDecodeTopLevelUInt64Value()
     {
@@ -132,12 +139,19 @@ class EncodeDecodeTest extends TestBase
         $this->assertEquals(1, $m->getValue());
     }
 
-    # public function testEncodeTopLevelUInt64Value()
-    # {
-    #     $m = new UInt64Value();
-    #     $m->setValue(1);
-    #     $this->assertSame("\"1\"", $m->serializeToJsonString());
-    # }
+    public function testDecodeTopLevelUInt64ValueAsString()
+    {
+        $m = new UInt64Value();
+        $m->mergeFromJsonString("\"1\"");
+        $this->assertEquals(1, $m->getValue());
+    }
+
+    public function testEncodeTopLevelUInt64Value()
+    {
+        $m = new UInt64Value();
+        $m->setValue(1);
+        $this->assertSame("\"1\"", $m->serializeToJsonString());
+    }
 
     public function testDecodeTopLevelStringValue()
     {

+ 3 - 3
protobuf_deps.bzl

@@ -25,9 +25,9 @@ def protobuf_deps():
     if not native.existing_rule("six"):
         http_archive(
             name = "six",
-            build_file = "@//:six.BUILD",
-            sha256 = "105f8d68616f8248e24bf0e9372ef04d3cc10104f1980f54d57b2ce73a5ad56a",
-            urls = ["https://pypi.python.org/packages/source/s/six/six-1.10.0.tar.gz#md5=34eed507548117b2ab523ab14b2f8b55"],
+            build_file = "@com_google_protobuf//:third_party/six.BUILD",
+            sha256 = "d16a0141ec1a18405cd4ce8b4613101da75da0e9a7aec5bdd4fa804d0e0eba73",
+            urls = ["https://pypi.python.org/packages/source/s/six/six-1.12.0.tar.gz"],
         )
 
     if not native.existing_rule("rules_cc"):

+ 21 - 0
ruby/ext/google/protobuf_c/defs.c

@@ -2231,6 +2231,27 @@ static VALUE get_def_obj(VALUE _descriptor_pool, const void* ptr, VALUE klass) {
     VALUE args[3] = { c_only_cookie, _descriptor_pool, key };
     def = rb_class_new_instance(3, args, klass);
     rb_hash_aset(descriptor_pool->def_to_descriptor, key, def);
+
+    // For message defs, we now eagerly get/create descriptors for all
+    // submessages.  We will need these anyway to parse or serialize this
+    // message type.  But more importantly, we must do this now so that
+    // add_handlers_for_message() (which calls get_msgdef_obj()) does *not*
+    // need to create a Ruby object or insert into a Ruby Hash.  We need to
+    // avoid triggering GC, which can switch Ruby threads and re-enter our
+    // C extension from a different thread.  This wreaks havoc on our state
+    // if we were in the middle of building handlers.
+    if (klass == cDescriptor) {
+      const upb_msgdef *m = ptr;
+      upb_msg_field_iter it;
+      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)) {
+          get_msgdef_obj(_descriptor_pool, upb_fielddef_msgsubdef(f));
+        }
+      }
+    }
   }
 
   return def;

+ 16 - 14
ruby/ext/google/protobuf_c/encode_decode.c

@@ -155,6 +155,9 @@ static const void *newoneofhandlerdata(upb_handlers *h,
   // 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 (is_value_field(f)) {
+    hd->oneof_case_num |= ONEOF_CASE_MASK;
+  }
   hd->subklass = field_type_class(desc->layout, f);
   upb_handlers_addcleanup(h, hd, xfree);
   return hd;
@@ -706,12 +709,13 @@ void add_handlers_for_message(const void *closure, upb_handlers *h) {
        !upb_msg_field_done(&i);
        upb_msg_field_next(&i)) {
     const upb_fielddef *f = upb_msg_iter_field(&i);
+    const upb_oneofdef *oneof = upb_fielddef_containingoneof(f);
     size_t offset = desc->layout->fields[upb_fielddef_index(f)].offset +
         sizeof(MessageHeader);
 
-    if (upb_fielddef_containingoneof(f)) {
+    if (oneof) {
       size_t oneof_case_offset =
-          desc->layout->fields[upb_fielddef_index(f)].case_offset +
+          desc->layout->oneofs[upb_oneofdef_index(oneof)].case_offset +
           sizeof(MessageHeader);
       add_handlers_for_oneof_field(h, f, offset, oneof_case_offset, desc);
     } else if (is_map_field(f)) {
@@ -1256,19 +1260,18 @@ static void putmsg(VALUE msg_rb, const Descriptor* desc,
        !upb_msg_field_done(&i);
        upb_msg_field_next(&i)) {
     upb_fielddef *f = upb_msg_iter_field(&i);
+    const upb_oneofdef *oneof = upb_fielddef_containingoneof(f);
     bool is_matching_oneof = false;
     uint32_t offset =
         desc->layout->fields[upb_fielddef_index(f)].offset +
         sizeof(MessageHeader);
 
-    if (upb_fielddef_containingoneof(f)) {
-      uint32_t oneof_case_offset =
-          desc->layout->fields[upb_fielddef_index(f)].case_offset +
-          sizeof(MessageHeader);
+    if (oneof) {
+      uint32_t oneof_case =
+          slot_read_oneof_case(desc->layout, Message_data(msg), oneof);
       // For a oneof, check that this field is actually present -- skip all the
       // below if not.
-      if (DEREF(msg, oneof_case_offset, uint32_t) !=
-          upb_fielddef_number(f)) {
+      if (oneof_case != upb_fielddef_number(f)) {
         continue;
       }
       // Otherwise, fall through to the appropriate singular-field handler
@@ -1464,18 +1467,17 @@ static void discard_unknown(VALUE msg_rb, const Descriptor* desc) {
        !upb_msg_field_done(&it);
        upb_msg_field_next(&it)) {
     upb_fielddef *f = upb_msg_iter_field(&it);
+    const upb_oneofdef *oneof = upb_fielddef_containingoneof(f);
     uint32_t offset =
         desc->layout->fields[upb_fielddef_index(f)].offset +
         sizeof(MessageHeader);
 
-    if (upb_fielddef_containingoneof(f)) {
-      uint32_t oneof_case_offset =
-          desc->layout->fields[upb_fielddef_index(f)].case_offset +
-          sizeof(MessageHeader);
+    if (oneof) {
+      uint32_t oneof_case =
+          slot_read_oneof_case(desc->layout, Message_data(msg), oneof);
       // For a oneof, check that this field is actually present -- skip all the
       // below if not.
-      if (DEREF(msg, oneof_case_offset, uint32_t) !=
-          upb_fielddef_number(f)) {
+      if (oneof_case != upb_fielddef_number(f)) {
         continue;
       }
       // Otherwise, fall through to the appropriate singular-field handler

+ 2 - 18
ruby/ext/google/protobuf_c/message.c

@@ -86,27 +86,11 @@ VALUE Message_alloc(VALUE klass) {
 }
 
 static const upb_fielddef* which_oneof_field(MessageHeader* self, const upb_oneofdef* o) {
-  upb_oneof_iter it;
-  size_t case_ofs;
   uint32_t oneof_case;
-  const upb_fielddef* first_field;
   const upb_fielddef* f;
 
-  // If no fields in the oneof, always nil.
-  if (upb_oneofdef_numfields(o) == 0) {
-    return NULL;
-  }
-  // Grab the first field in the oneof so we can get its layout info to find the
-  // oneof_case field.
-  upb_oneof_begin(&it, o);
-  assert(!upb_oneof_done(&it));
-  first_field = upb_oneof_iter_field(&it);
-  assert(upb_fielddef_containingoneof(first_field) != NULL);
-
-  case_ofs =
-      self->descriptor->layout->
-      fields[upb_fielddef_index(first_field)].case_offset;
-  oneof_case = *((uint32_t*)((char*)Message_data(self) + case_ofs));
+  oneof_case =
+      slot_read_oneof_case(self->descriptor->layout, Message_data(self), o);
 
   if (oneof_case == ONEOF_CASE_NONE) {
     return NULL;

+ 19 - 7
ruby/ext/google/protobuf_c/protobuf.h

@@ -59,6 +59,7 @@ typedef struct OneofDescriptor OneofDescriptor;
 typedef struct EnumDescriptor EnumDescriptor;
 typedef struct MessageLayout MessageLayout;
 typedef struct MessageField MessageField;
+typedef struct MessageOneof MessageOneof;
 typedef struct MessageHeader MessageHeader;
 typedef struct MessageBuilderContext MessageBuilderContext;
 typedef struct OneofBuilderContext OneofBuilderContext;
@@ -367,6 +368,9 @@ bool native_slot_eq(upb_fieldtype_t type, void* mem1, void* mem2);
 
 VALUE native_slot_encode_and_freeze_string(upb_fieldtype_t type, VALUE value);
 void native_slot_check_int_range_precision(const char* name, upb_fieldtype_t type, VALUE value);
+uint32_t slot_read_oneof_case(MessageLayout* layout, const void* storage,
+                              const upb_oneofdef* oneof);
+bool is_value_field(const upb_fielddef* f);
 
 extern rb_encoding* kRubyStringUtf8Encoding;
 extern rb_encoding* kRubyStringASCIIEncoding;
@@ -496,13 +500,16 @@ VALUE Map_iter_value(Map_iter* iter);
 // Message layout / storage.
 // -----------------------------------------------------------------------------
 
-#define MESSAGE_FIELD_NO_CASE ((size_t)-1)
-#define MESSAGE_FIELD_NO_HASBIT ((size_t)-1)
+#define MESSAGE_FIELD_NO_HASBIT ((uint32_t)-1)
 
 struct MessageField {
-  size_t offset;
-  size_t case_offset;  // for oneofs, a uint32. Else, MESSAGE_FIELD_NO_CASE.
-  size_t hasbit;
+  uint32_t offset;
+  uint32_t hasbit;
+};
+
+struct MessageOneof {
+  uint32_t offset;
+  uint32_t case_offset;
 };
 
 // MessageLayout is owned by the enclosing Descriptor, which must outlive us.
@@ -511,10 +518,15 @@ struct MessageLayout {
   const upb_msgdef* msgdef;
   void* empty_template;  // Can memcpy() onto a layout to clear it.
   MessageField* fields;
-  size_t size;
+  MessageOneof* oneofs;
+  uint32_t size;
+  uint32_t value_offset;
+  int value_count;
 };
 
-void create_layout(Descriptor* desc);
+#define ONEOF_CASE_MASK 0x80000000
+
+MessageLayout* create_layout(Descriptor* desc);
 void free_layout(MessageLayout* layout);
 bool field_contains_hasbit(MessageLayout* layout,
                  const upb_fielddef* field);

+ 96 - 67
ruby/ext/google/protobuf_c/storage.c

@@ -473,10 +473,16 @@ static size_t align_up_to(size_t offset, size_t granularity) {
   return (offset + granularity - 1) & ~(granularity - 1);
 }
 
-void create_layout(Descriptor* desc) {
+bool is_value_field(const upb_fielddef* f) {
+  return upb_fielddef_isseq(f) || upb_fielddef_issubmsg(f) ||
+         upb_fielddef_isstring(f);
+}
+
+MessageLayout* create_layout(Descriptor* desc) {
   const upb_msgdef *msgdef = desc->msgdef;
   MessageLayout* layout = ALLOC(MessageLayout);
   int nfields = upb_msgdef_numfields(msgdef);
+  int noneofs = upb_msgdef_numoneofs(msgdef);
   upb_msg_field_iter it;
   upb_msg_oneof_iter oit;
   size_t off = 0;
@@ -487,6 +493,11 @@ void create_layout(Descriptor* desc) {
   desc->layout = layout;
 
   layout->fields = ALLOC_N(MessageField, nfields);
+  layout->oneofs = NULL;
+
+  if (noneofs > 0) {
+    layout->oneofs = ALLOC_N(MessageOneof, noneofs);
+  }
 
   for (upb_msg_field_begin(&it, msgdef);
        !upb_msg_field_done(&it);
@@ -504,29 +515,41 @@ void create_layout(Descriptor* desc) {
     off += (hasbit + 8 - 1) / 8;
   }
 
+  off = align_up_to(off, sizeof(VALUE));
+  layout->value_offset = off;
+  layout->value_count = 0;
+
+  // Place all (non-oneof) VALUE fields first.
+  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_containingoneof(field) || !is_value_field(field)) {
+      continue;
+    }
+
+    layout->fields[upb_fielddef_index(field)].offset = off;
+    off += sizeof(VALUE);
+    layout->value_count++;
+  }
+
+  // Now place all other (non-oneof) fields.
   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.
+    if (upb_fielddef_containingoneof(field) || is_value_field(field)) {
       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(VALUE);
-    } else {
-      field_size = native_slot_size(upb_fielddef_type(field));
-    }
+    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;
     off += field_size;
   }
 
@@ -560,6 +583,7 @@ void create_layout(Descriptor* desc) {
          upb_oneof_next(&fit)) {
       const upb_fielddef* field = upb_oneof_iter_field(&fit);
       layout->fields[upb_fielddef_index(field)].offset = off;
+      layout->oneofs[upb_oneofdef_index(oneof)].offset = off;
     }
     off += field_size;
   }
@@ -569,18 +593,10 @@ void create_layout(Descriptor* desc) {
        !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;
-    }
+    layout->oneofs[upb_oneofdef_index(oneof)].case_offset = off;
     off += field_size;
   }
 
@@ -601,6 +617,7 @@ void create_layout(Descriptor* desc) {
 void free_layout(MessageLayout* layout) {
   xfree(layout->empty_template);
   xfree(layout->fields);
+  xfree(layout->oneofs);
   xfree(layout);
 }
 
@@ -627,9 +644,15 @@ static void* slot_memory(MessageLayout* layout,
 
 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);
+                                 const upb_oneofdef* oneof) {
+  return (uint32_t*)(((uint8_t*)storage) +
+                     layout->oneofs[upb_oneofdef_index(oneof)].case_offset);
+}
+
+uint32_t slot_read_oneof_case(MessageLayout* layout, const void* storage,
+                              const upb_oneofdef* oneof) {
+  uint32_t* ptr = slot_oneof_case(layout, storage, oneof);
+  return *ptr & ~ONEOF_CASE_MASK;
 }
 
 static void slot_set_hasbit(MessageLayout* layout,
@@ -672,13 +695,14 @@ void layout_clear(MessageLayout* layout,
                  const void* storage,
                  const upb_fielddef* field) {
   void* memory = slot_memory(layout, storage, field);
-  uint32_t* oneof_case = slot_oneof_case(layout, storage, field);
+  const upb_oneofdef* oneof = upb_fielddef_containingoneof(field);
 
   if (field_contains_hasbit(layout, field)) {
     slot_clear_hasbit(layout, storage, field);
   }
 
-  if (upb_fielddef_containingoneof(field)) {
+  if (oneof) {
+    uint32_t* oneof_case = slot_oneof_case(layout, storage, oneof);
     memset(memory, 0, NATIVE_SLOT_MAX_SIZE);
     *oneof_case = ONEOF_CASE_NONE;
   } else if (is_map_field(field)) {
@@ -764,8 +788,7 @@ VALUE layout_get(MessageLayout* layout,
                  const void* storage,
                  const upb_fielddef* field) {
   void* memory = slot_memory(layout, storage, field);
-  uint32_t* oneof_case = slot_oneof_case(layout, storage, field);
-
+  const upb_oneofdef* oneof = upb_fielddef_containingoneof(field);
   bool field_set;
   if (field_contains_hasbit(layout, field)) {
     field_set = slot_is_hasbit_set(layout, storage, field);
@@ -773,8 +796,9 @@ VALUE layout_get(MessageLayout* layout,
     field_set = true;
   }
 
-  if (upb_fielddef_containingoneof(field)) {
-    if (*oneof_case != upb_fielddef_number(field)) {
+  if (oneof) {
+    uint32_t oneof_case = slot_read_oneof_case(layout, storage, oneof);
+    if (oneof_case != upb_fielddef_number(field)) {
       return layout_get_default(field);
     }
     return native_slot_get(upb_fielddef_type(field),
@@ -837,9 +861,10 @@ void layout_set(MessageLayout* layout,
                 const upb_fielddef* field,
                 VALUE val) {
   void* memory = slot_memory(layout, storage, field);
-  uint32_t* oneof_case = slot_oneof_case(layout, storage, field);
+  const upb_oneofdef* oneof = upb_fielddef_containingoneof(field);
 
-  if (upb_fielddef_containingoneof(field)) {
+  if (oneof) {
+    uint32_t* oneof_case = slot_oneof_case(layout, storage, oneof);
     if (val == Qnil) {
       // Assigning nil to a oneof field clears the oneof completely.
       *oneof_case = ONEOF_CASE_NONE;
@@ -857,11 +882,14 @@ void layout_set(MessageLayout* layout,
       // sync with the value slot whenever the Ruby VM has been called. Thus, we
       // use native_slot_set_value_and_case(), which ensures that both the value
       // and case number are altered atomically (w.r.t. the Ruby VM).
+      uint32_t case_value = upb_fielddef_number(field);
+      if (upb_fielddef_issubmsg(field) || upb_fielddef_isstring(field)) {
+        case_value |= ONEOF_CASE_MASK;
+      }
+
       native_slot_set_value_and_case(
-          upb_fielddef_name(field),
-          upb_fielddef_type(field), field_type_class(layout, field),
-          memory, val,
-          oneof_case, upb_fielddef_number(field));
+          upb_fielddef_name(field), upb_fielddef_type(field),
+          field_type_class(layout, field), memory, val, oneof_case, case_value);
     }
   } else if (is_map_field(field)) {
     check_map_field_type(layout, val, field);
@@ -893,22 +921,19 @@ void layout_init(MessageLayout* layout, void* storage) {
 }
 
 void layout_mark(MessageLayout* layout, void* storage) {
-  upb_msg_field_iter it;
-  for (upb_msg_field_begin(&it, layout->msgdef);
-       !upb_msg_field_done(&it);
-       upb_msg_field_next(&it)) {
-    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);
+  VALUE* values = (VALUE*)CHARPTR_AT(storage, layout->value_offset);
+  int noneofs = upb_msgdef_numoneofs(layout->msgdef);
+  int i;
 
-    if (upb_fielddef_containingoneof(field)) {
-      if (*oneof_case == upb_fielddef_number(field)) {
-        native_slot_mark(upb_fielddef_type(field), memory);
-      }
-    } else if (upb_fielddef_label(field) == UPB_LABEL_REPEATED) {
-      rb_gc_mark(DEREF(memory, VALUE));
-    } else {
-      native_slot_mark(upb_fielddef_type(field), memory);
+  for (i = 0; i < layout->value_count; i++) {
+    rb_gc_mark(values[i]);
+  }
+
+  for (i = 0; i < noneofs; i++) {
+    MessageOneof* oneof = &layout->oneofs[i];
+    uint32_t* case_ptr = (uint32_t*)CHARPTR_AT(storage, oneof->case_offset);
+    if (*case_ptr & ONEOF_CASE_MASK) {
+      rb_gc_mark(DEREF_OFFSET(storage, oneof->offset, VALUE));
     }
   }
 }
@@ -919,14 +944,16 @@ void layout_dup(MessageLayout* layout, void* to, void* from) {
        !upb_msg_field_done(&it);
        upb_msg_field_next(&it)) {
     const upb_fielddef* field = upb_msg_iter_field(&it);
+    const upb_oneofdef* oneof = upb_fielddef_containingoneof(field);
 
     void* to_memory = slot_memory(layout, to, field);
-    uint32_t* to_oneof_case = slot_oneof_case(layout, to, field);
     void* from_memory = slot_memory(layout, from, field);
-    uint32_t* from_oneof_case = slot_oneof_case(layout, from, field);
 
-    if (upb_fielddef_containingoneof(field)) {
-      if (*from_oneof_case == upb_fielddef_number(field)) {
+    if (oneof) {
+      uint32_t* to_oneof_case = slot_oneof_case(layout, to, oneof);
+      uint32_t* from_oneof_case = slot_oneof_case(layout, from, oneof);
+      if (slot_read_oneof_case(layout, from, oneof) ==
+          upb_fielddef_number(field)) {
         *to_oneof_case = *from_oneof_case;
         native_slot_dup(upb_fielddef_type(field), to_memory, from_memory);
       }
@@ -951,14 +978,16 @@ void layout_deep_copy(MessageLayout* layout, void* to, void* from) {
        !upb_msg_field_done(&it);
        upb_msg_field_next(&it)) {
     const upb_fielddef* field = upb_msg_iter_field(&it);
+    const upb_oneofdef* oneof = upb_fielddef_containingoneof(field);
 
     void* to_memory = slot_memory(layout, to, field);
-    uint32_t* to_oneof_case = slot_oneof_case(layout, to, field);
     void* from_memory = slot_memory(layout, from, field);
-    uint32_t* from_oneof_case = slot_oneof_case(layout, from, field);
 
-    if (upb_fielddef_containingoneof(field)) {
-      if (*from_oneof_case == upb_fielddef_number(field)) {
+    if (oneof) {
+      uint32_t* to_oneof_case = slot_oneof_case(layout, to, oneof);
+      uint32_t* from_oneof_case = slot_oneof_case(layout, from, oneof);
+      if (slot_read_oneof_case(layout, from, oneof) ==
+          upb_fielddef_number(field)) {
         *to_oneof_case = *from_oneof_case;
         native_slot_deep_copy(upb_fielddef_type(field), to_memory, from_memory);
       }
@@ -985,17 +1014,18 @@ VALUE layout_eq(MessageLayout* layout, void* msg1, void* msg2) {
        !upb_msg_field_done(&it);
        upb_msg_field_next(&it)) {
     const upb_fielddef* field = upb_msg_iter_field(&it);
+    const upb_oneofdef* oneof = upb_fielddef_containingoneof(field);
 
     void* msg1_memory = slot_memory(layout, msg1, field);
-    uint32_t* msg1_oneof_case = slot_oneof_case(layout, msg1, field);
     void* msg2_memory = slot_memory(layout, msg2, field);
-    uint32_t* msg2_oneof_case = slot_oneof_case(layout, msg2, field);
 
-    if (upb_fielddef_containingoneof(field)) {
+    if (oneof) {
+      uint32_t* msg1_oneof_case = slot_oneof_case(layout, msg1, oneof);
+      uint32_t* msg2_oneof_case = slot_oneof_case(layout, msg2, oneof);
       if (*msg1_oneof_case != *msg2_oneof_case ||
-          (*msg1_oneof_case == upb_fielddef_number(field) &&
-           !native_slot_eq(upb_fielddef_type(field),
-                           msg1_memory,
+          (slot_read_oneof_case(layout, msg1, oneof) ==
+               upb_fielddef_number(field) &&
+           !native_slot_eq(upb_fielddef_type(field), msg1_memory,
                            msg2_memory))) {
         return Qfalse;
       }
@@ -1011,9 +1041,8 @@ VALUE layout_eq(MessageLayout* layout, void* msg1, void* msg2) {
       }
     } else {
       if (slot_is_hasbit_set(layout, msg1, field) !=
-	  slot_is_hasbit_set(layout, msg2, field) ||
-          !native_slot_eq(upb_fielddef_type(field),
-			  msg1_memory, msg2_memory)) {
+              slot_is_hasbit_set(layout, msg2, field) ||
+          !native_slot_eq(upb_fielddef_type(field), msg1_memory, msg2_memory)) {
         return Qfalse;
       }
     }

+ 2 - 0
src/google/protobuf/arena.h

@@ -75,6 +75,8 @@ namespace protobuf {
 class Arena;    // defined below
 class Message;  // defined in message.h
 class MessageLite;
+template <typename Key, typename T>
+class Map;
 
 namespace arena_metrics {
 

+ 1 - 1
src/google/protobuf/compiler/csharp/csharp_helpers.cc

@@ -297,7 +297,7 @@ uint GetGroupEndTag(const Descriptor* descriptor) {
 
 std::string ToCSharpName(const std::string& name, const FileDescriptor* file) {
   std::string result = GetFileNamespace(file);
-  if (result != "") {
+  if (!result.empty()) {
     result += '.';
   }
   string classname;

+ 3 - 0
src/google/protobuf/compiler/csharp/csharp_reflection_class.cc

@@ -261,6 +261,7 @@ void ReflectionClassGenerator::WriteGeneratedCodeInfo(const Descriptor* descript
   // Fields
   if (descriptor->field_count() > 0) {
       std::vector<std::string> fields;
+      fields.reserve(descriptor->field_count());
       for (int i = 0; i < descriptor->field_count(); i++) {
           fields.push_back(GetPropertyName(descriptor->field(i)));
       }
@@ -273,6 +274,7 @@ void ReflectionClassGenerator::WriteGeneratedCodeInfo(const Descriptor* descript
   // Oneofs
   if (descriptor->oneof_decl_count() > 0) {
       std::vector<std::string> oneofs;
+      oneofs.reserve(descriptor->oneof_decl_count());
       for (int i = 0; i < descriptor->oneof_decl_count(); i++) {
           oneofs.push_back(UnderscoresToCamelCase(descriptor->oneof_decl(i)->name(), true));
       }
@@ -285,6 +287,7 @@ void ReflectionClassGenerator::WriteGeneratedCodeInfo(const Descriptor* descript
   // Nested enums
   if (descriptor->enum_type_count() > 0) {
       std::vector<std::string> enums;
+      enums.reserve(descriptor->enum_type_count());
       for (int i = 0; i < descriptor->enum_type_count(); i++) {
           enums.push_back(GetClassName(descriptor->enum_type(i)));
       }

+ 23 - 28
src/google/protobuf/compiler/php/php_generator.cc

@@ -88,7 +88,6 @@ std::string GeneratedMetadataFileName(const FileDescriptor* file,
 std::string LabelForField(FieldDescriptor* field);
 std::string TypeName(FieldDescriptor* field);
 std::string UnderscoresToCamelCase(const string& name, bool cap_first_letter);
-std::string EscapeDollor(const string& to_escape);
 std::string BinaryToHex(const string& binary);
 void Indent(io::Printer* printer);
 void Outdent(io::Printer* printer);
@@ -153,7 +152,7 @@ template <typename DescriptorType>
 std::string ClassNamePrefix(const string& classname,
                             const DescriptorType* desc) {
   const string& prefix = (desc->file()->options()).php_class_prefix();
-  if (prefix != "") {
+  if (!prefix.empty()) {
     return prefix;
   }
 
@@ -244,13 +243,13 @@ template <typename DescriptorType>
 std::string RootPhpNamespace(const DescriptorType* desc, bool is_descriptor) {
   if (desc->file()->options().has_php_namespace()) {
     const string& php_namespace = desc->file()->options().php_namespace();
-    if (php_namespace != "") {
+    if (!php_namespace.empty()) {
       return php_namespace;
     }
     return "";
   }
 
-  if (desc->file()->package() != "") {
+  if (!desc->file()->package().empty()) {
     return PhpName(desc->file()->package(), is_descriptor);
   }
   return "";
@@ -260,7 +259,7 @@ template <typename DescriptorType>
 std::string FullClassName(const DescriptorType* desc, bool is_descriptor) {
   string classname = GeneratedClassNameImpl(desc);
   string php_namespace = RootPhpNamespace(desc, is_descriptor);
-  if (php_namespace != "") {
+  if (!php_namespace.empty()) {
     return php_namespace + "\\" + classname;
   }
   return classname;
@@ -270,7 +269,7 @@ template <typename DescriptorType>
 std::string LegacyFullClassName(const DescriptorType* desc, bool is_descriptor) {
   string classname = LegacyGeneratedClassName(desc);
   string php_namespace = RootPhpNamespace(desc, is_descriptor);
-  if (php_namespace != "") {
+  if (!php_namespace.empty()) {
     return php_namespace + "\\" + classname;
   }
   return classname;
@@ -352,7 +351,7 @@ std::string GeneratedMetadataFileName(const FileDescriptor* file,
   if (file->options().has_php_metadata_namespace()) {
     const string& php_metadata_namespace =
         file->options().php_metadata_namespace();
-    if (php_metadata_namespace != "" && php_metadata_namespace != "\\") {
+    if (!php_metadata_namespace.empty() && php_metadata_namespace != "\\") {
       result += php_metadata_namespace;
       std::replace(result.begin(), result.end(), '\\', '/');
       if (result.at(result.size() - 1) != '/') {
@@ -552,45 +551,41 @@ std::string EnumOrMessageSuffix(
 
 // Converts a name to camel-case. If cap_first_letter is true, capitalize the
 // first letter.
-std::string UnderscoresToCamelCase(const string& input, bool cap_first_letter) {
+std::string UnderscoresToCamelCase(const string& name, bool cap_first_letter) {
   std::string result;
-  for (int i = 0; i < input.size(); i++) {
-    if ('a' <= input[i] && input[i] <= 'z') {
+  for (int i = 0; i < name.size(); i++) {
+    if ('a' <= name[i] && name[i] <= 'z') {
       if (cap_first_letter) {
-        result += input[i] + ('A' - 'a');
+        result += name[i] + ('A' - 'a');
       } else {
-        result += input[i];
+        result += name[i];
       }
       cap_first_letter = false;
-    } else if ('A' <= input[i] && input[i] <= 'Z') {
+    } else if ('A' <= name[i] && name[i] <= 'Z') {
       if (i == 0 && !cap_first_letter) {
         // Force first letter to lower-case unless explicitly told to
         // capitalize it.
-        result += input[i] + ('a' - 'A');
+        result += name[i] + ('a' - 'A');
       } else {
         // Capital letters after the first are left as-is.
-        result += input[i];
+        result += name[i];
       }
       cap_first_letter = false;
-    } else if ('0' <= input[i] && input[i] <= '9') {
-      result += input[i];
+    } else if ('0' <= name[i] && name[i] <= '9') {
+      result += name[i];
       cap_first_letter = true;
     } else {
       cap_first_letter = true;
     }
   }
   // Add a trailing "_" if the name should be altered.
-  if (input[input.size() - 1] == '#') {
+  if (name[name.size() - 1] == '#') {
     result += '_';
   }
   return result;
 }
 
-std::string EscapeDollor(const string& to_escape) {
-  return StringReplace(to_escape, "$", "\\$", true);
-}
-
-std::string BinaryToHex(const string& src) {
+std::string BinaryToHex(const string& binary) {
   string dest;
   size_t i;
   unsigned char symbol[16] = {
@@ -600,12 +595,12 @@ std::string BinaryToHex(const string& src) {
     'c', 'd', 'e', 'f',
   };
 
-  dest.resize(src.size() * 2);
+  dest.resize(binary.size() * 2);
   char* append_ptr = &dest[0];
 
-  for (i = 0; i < src.size(); i++) {
-    *append_ptr++ = symbol[(src[i] & 0xf0) >> 4];
-    *append_ptr++ = symbol[src[i] & 0x0f];
+  for (i = 0; i < binary.size(); i++) {
+    *append_ptr++ = symbol[(binary[i] & 0xf0) >> 4];
+    *append_ptr++ = symbol[binary[i] & 0x0f];
   }
 
   return dest;
@@ -1103,7 +1098,7 @@ void LegacyGenerateClassFile(const FileDescriptor* file, const DescriptorType* d
   GenerateHead(file, &printer);
 
   std::string php_namespace = RootPhpNamespace(desc, is_descriptor);
-  if (php_namespace != "") {
+  if (!php_namespace.empty()) {
     printer.Print(
         "namespace ^name^;\n\n",
         "name", php_namespace);

+ 3 - 3
six.BUILD → third_party/six.BUILD

@@ -1,13 +1,13 @@
 genrule(
   name = "copy_six",
-  srcs = ["six-1.10.0/six.py"],
-  outs = ["six.py"],
+  srcs = ["six-1.12.0/six.py"],
+  outs = ["__init__.py"],
   cmd = "cp $< $(@)",
 )
 
 py_library(
   name = "six",
-  srcs = ["six.py"],
+  srcs = ["__init__.py"],
   srcs_version = "PY2AND3",
   visibility = ["//visibility:public"],
 )