mirror of
				https://gitlab.gnome.org/GNOME/glib.git
				synced 2025-11-04 01:58:54 +01:00 
			
		
		
		
	GDBusMessage: fast-path decoding of fixed arrays
Instead of creating a separate GVariant for each of the 'y's in an 'ay', use g_variant_new_fixed_array(). https://bugzilla.gnome.org/show_bug.cgi?id=732754
This commit is contained in:
		@@ -1205,6 +1205,27 @@ g_dbus_message_set_unix_fd_list (GDBusMessage  *message,
 | 
			
		||||
 | 
			
		||||
/* ---------------------------------------------------------------------------------------------------- */
 | 
			
		||||
 | 
			
		||||
static guint
 | 
			
		||||
get_type_fixed_size (const GVariantType *type)
 | 
			
		||||
{
 | 
			
		||||
  /* NB: we do not treat 'b' as fixed-size here because GVariant and
 | 
			
		||||
   * D-Bus disagree about the size.
 | 
			
		||||
   */
 | 
			
		||||
  switch (*g_variant_type_peek_string (type))
 | 
			
		||||
    {
 | 
			
		||||
    case 'y':
 | 
			
		||||
      return 1;
 | 
			
		||||
    case 'n': case 'q':
 | 
			
		||||
      return 2;
 | 
			
		||||
    case 'i': case 'u': case 'h':
 | 
			
		||||
      return 4;
 | 
			
		||||
    case 'x': case 't': case 'd':
 | 
			
		||||
      return 8;
 | 
			
		||||
    default:
 | 
			
		||||
      return 0;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static gboolean
 | 
			
		||||
validate_headers (GDBusMessage  *message,
 | 
			
		||||
                  GError       **error)
 | 
			
		||||
@@ -1378,6 +1399,35 @@ read_string (GMemoryBuffer  *mbuf,
 | 
			
		||||
  return str;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static gconstpointer
 | 
			
		||||
read_bytes (GMemoryBuffer  *mbuf,
 | 
			
		||||
            gsize           len,
 | 
			
		||||
            GError        **error)
 | 
			
		||||
{
 | 
			
		||||
  gconstpointer result;
 | 
			
		||||
 | 
			
		||||
  if (mbuf->pos + len > mbuf->valid_len || mbuf->pos + len < mbuf->pos)
 | 
			
		||||
    {
 | 
			
		||||
      mbuf->pos = mbuf->valid_len;
 | 
			
		||||
      /* G_GSIZE_FORMAT doesn't work with gettext, so we use %lu */
 | 
			
		||||
      g_set_error (error,
 | 
			
		||||
                   G_IO_ERROR,
 | 
			
		||||
                   G_IO_ERROR_INVALID_ARGUMENT,
 | 
			
		||||
                   g_dngettext (GETTEXT_PACKAGE,
 | 
			
		||||
                                "Wanted to read %lu byte but only got %lu",
 | 
			
		||||
                                "Wanted to read %lu bytes but only got %lu",
 | 
			
		||||
                                (gulong)len),
 | 
			
		||||
                                (gulong)len,
 | 
			
		||||
                   (gulong)(mbuf->valid_len - mbuf->pos));
 | 
			
		||||
      return NULL;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  result = mbuf->data + mbuf->pos;
 | 
			
		||||
  mbuf->pos += len;
 | 
			
		||||
 | 
			
		||||
  return result;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* if just_align==TRUE, don't read a value, just align the input stream wrt padding */
 | 
			
		||||
 | 
			
		||||
/* returns a non-floating GVariant! */
 | 
			
		||||
@@ -1588,10 +1638,8 @@ parse_value_from_blob (GMemoryBuffer       *buf,
 | 
			
		||||
      if (!just_align)
 | 
			
		||||
        {
 | 
			
		||||
          guint32 array_len;
 | 
			
		||||
          goffset offset;
 | 
			
		||||
          goffset target;
 | 
			
		||||
          const GVariantType *element_type;
 | 
			
		||||
          GVariantBuilder builder;
 | 
			
		||||
          guint fixed_size;
 | 
			
		||||
 | 
			
		||||
          array_len = g_memory_buffer_read_uint32 (buf);
 | 
			
		||||
 | 
			
		||||
@@ -1614,8 +1662,46 @@ parse_value_from_blob (GMemoryBuffer       *buf,
 | 
			
		||||
              goto fail;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
          g_variant_builder_init (&builder, type);
 | 
			
		||||
          element_type = g_variant_type_element (type);
 | 
			
		||||
          fixed_size = get_type_fixed_size (element_type);
 | 
			
		||||
 | 
			
		||||
          /* Fast-path the cases like 'ay', etc. */
 | 
			
		||||
          if (fixed_size != 0)
 | 
			
		||||
            {
 | 
			
		||||
              gconstpointer array_data;
 | 
			
		||||
 | 
			
		||||
              if (array_len % fixed_size != 0)
 | 
			
		||||
                {
 | 
			
		||||
                  g_set_error (&local_error,
 | 
			
		||||
                               G_IO_ERROR,
 | 
			
		||||
                               G_IO_ERROR_INVALID_ARGUMENT,
 | 
			
		||||
                               _("Encountered array of type 'a%c', expected to have a length a multiple "
 | 
			
		||||
                                 "of %u bytes, but found to be %u bytes in length"),
 | 
			
		||||
                               g_variant_type_peek_string (element_type)[0], fixed_size, array_len);
 | 
			
		||||
                  goto fail;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
              ensure_input_padding (buf, fixed_size);
 | 
			
		||||
              array_data = read_bytes (buf, array_len, &local_error);
 | 
			
		||||
              if (array_data == NULL)
 | 
			
		||||
                goto fail;
 | 
			
		||||
 | 
			
		||||
              ret = g_variant_new_fixed_array (element_type, array_data, array_len / fixed_size, fixed_size);
 | 
			
		||||
 | 
			
		||||
              if (g_memory_buffer_is_byteswapped (buf))
 | 
			
		||||
                {
 | 
			
		||||
                  GVariant *tmp = g_variant_ref_sink (ret);
 | 
			
		||||
                  ret = g_variant_byteswap (tmp);
 | 
			
		||||
                  g_variant_unref (tmp);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
          else
 | 
			
		||||
            {
 | 
			
		||||
              GVariantBuilder builder;
 | 
			
		||||
              goffset offset;
 | 
			
		||||
              goffset target;
 | 
			
		||||
 | 
			
		||||
              g_variant_builder_init (&builder, type);
 | 
			
		||||
 | 
			
		||||
              if (array_len == 0)
 | 
			
		||||
                {
 | 
			
		||||
@@ -1629,7 +1715,6 @@ parse_value_from_blob (GMemoryBuffer       *buf,
 | 
			
		||||
                }
 | 
			
		||||
              else
 | 
			
		||||
                {
 | 
			
		||||
              /* TODO: optimize array of primitive types */
 | 
			
		||||
                  offset = buf->pos;
 | 
			
		||||
                  target = offset + array_len;
 | 
			
		||||
                  while (offset < target)
 | 
			
		||||
@@ -1653,6 +1738,7 @@ parse_value_from_blob (GMemoryBuffer       *buf,
 | 
			
		||||
 | 
			
		||||
              ret = g_variant_builder_end (&builder);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
      break;
 | 
			
		||||
 | 
			
		||||
    default:
 | 
			
		||||
@@ -1812,12 +1898,9 @@ parse_value_from_blob (GMemoryBuffer       *buf,
 | 
			
		||||
  is_leaf = is_leaf; /* To avoid -Wunused-but-set-variable */
 | 
			
		||||
#endif /* DEBUG_SERIALIZER */
 | 
			
		||||
 | 
			
		||||
  /* sink the reference */
 | 
			
		||||
  /* sink the reference, if floating */
 | 
			
		||||
  if (ret != NULL)
 | 
			
		||||
    {
 | 
			
		||||
      g_assert (g_variant_is_floating (ret));
 | 
			
		||||
      g_variant_ref_sink (ret);
 | 
			
		||||
    }
 | 
			
		||||
    g_variant_take_ref (ret);
 | 
			
		||||
  return ret;
 | 
			
		||||
 | 
			
		||||
 fail:
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user