|  | @@ -50,10 +50,6 @@ typedef struct slice_shard {
 | 
	
		
			
				|  |  |    size_t capacity;
 | 
	
		
			
				|  |  |  } slice_shard;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -/* hash seed: decided at initialization time */
 | 
	
		
			
				|  |  | -uint32_t g_hash_seed;
 | 
	
		
			
				|  |  | -static int g_forced_hash_seed = 0;
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  |  static slice_shard g_shards[SHARD_COUNT];
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  typedef struct {
 | 
	
	
		
			
				|  | @@ -68,6 +64,10 @@ uint32_t grpc_static_metadata_hash_values[GRPC_STATIC_MDSTR_COUNT];
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  namespace grpc_core {
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +/* hash seed: decided at initialization time */
 | 
	
		
			
				|  |  | +uint32_t g_hash_seed;
 | 
	
		
			
				|  |  | +static bool g_forced_hash_seed = false;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |  InternedSliceRefcount::~InternedSliceRefcount() {
 | 
	
		
			
				|  |  |    slice_shard* shard = &g_shards[SHARD_IDX(this->hash)];
 | 
	
		
			
				|  |  |    MutexLock lock(&shard->mu);
 | 
	
	
		
			
				|  | @@ -115,7 +115,7 @@ grpc_core::InternedSlice::InternedSlice(InternedSliceRefcount* s) {
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  uint32_t grpc_slice_default_hash_impl(grpc_slice s) {
 | 
	
		
			
				|  |  |    return gpr_murmur_hash3(GRPC_SLICE_START_PTR(s), GRPC_SLICE_LENGTH(s),
 | 
	
		
			
				|  |  | -                          g_hash_seed);
 | 
	
		
			
				|  |  | +                          grpc_core::g_hash_seed);
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  uint32_t grpc_static_slice_hash(grpc_slice s) {
 | 
	
	
		
			
				|  | @@ -159,20 +159,20 @@ grpc_slice grpc_slice_intern(grpc_slice slice) {
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  // Attempt to see if the provided slice or string matches a static slice.
 | 
	
		
			
				|  |  | -// SliceArgs... is either a const grpc_slice& or a string and length. In either
 | 
	
		
			
				|  |  | -// case, hash is the pre-computed hash value.
 | 
	
		
			
				|  |  | +// SliceArgs is either a const grpc_slice& or const pair<const char*, size_t>&.
 | 
	
		
			
				|  |  | +// In either case, hash is the pre-computed hash value.
 | 
	
		
			
				|  |  |  //
 | 
	
		
			
				|  |  |  // Returns: a matching static slice, or null.
 | 
	
		
			
				|  |  | -template <class... SliceArgs>
 | 
	
		
			
				|  |  | +template <typename SliceArgs>
 | 
	
		
			
				|  |  |  static const grpc_core::StaticMetadataSlice* MatchStaticSlice(
 | 
	
		
			
				|  |  | -    uint32_t hash, SliceArgs&&... args) {
 | 
	
		
			
				|  |  | +    uint32_t hash, const SliceArgs& args) {
 | 
	
		
			
				|  |  |    for (uint32_t i = 0; i <= max_static_metadata_hash_probe; i++) {
 | 
	
		
			
				|  |  |      static_metadata_hash_ent ent =
 | 
	
		
			
				|  |  |          static_metadata_hash[(hash + i) % GPR_ARRAY_SIZE(static_metadata_hash)];
 | 
	
		
			
				|  |  |      const grpc_core::StaticMetadataSlice* static_slice_table =
 | 
	
		
			
				|  |  |          grpc_static_slice_table();
 | 
	
		
			
				|  |  |      if (ent.hash == hash && ent.idx < GRPC_STATIC_MDSTR_COUNT &&
 | 
	
		
			
				|  |  | -        static_slice_table[ent.idx].Equals(std::forward<SliceArgs>(args)...)) {
 | 
	
		
			
				|  |  | +        static_slice_table[ent.idx] == args) {
 | 
	
		
			
				|  |  |        return &static_slice_table[ent.idx];
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |    }
 | 
	
	
		
			
				|  | @@ -182,8 +182,12 @@ static const grpc_core::StaticMetadataSlice* MatchStaticSlice(
 | 
	
		
			
				|  |  |  // Helper methods to enable us to select appropriately overloaded slice methods
 | 
	
		
			
				|  |  |  // whether we're dealing with a slice, or a buffer with length, when interning
 | 
	
		
			
				|  |  |  // strings. Helpers for FindOrCreateInternedSlice().
 | 
	
		
			
				|  |  | -static const void* GetBuffer(const void* buf, size_t len) { return buf; }
 | 
	
		
			
				|  |  | -static size_t GetLength(const void* buf, size_t len) { return len; }
 | 
	
		
			
				|  |  | +static const char* GetBuffer(const std::pair<const char*, size_t>& buflen) {
 | 
	
		
			
				|  |  | +  return buflen.first;
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +static size_t GetLength(const std::pair<const char*, size_t>& buflen) {
 | 
	
		
			
				|  |  | +  return buflen.second;
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  |  static const void* GetBuffer(const grpc_slice& slice) {
 | 
	
		
			
				|  |  |    return GRPC_SLICE_START_PTR(slice);
 | 
	
		
			
				|  |  |  }
 | 
	
	
		
			
				|  | @@ -192,19 +196,19 @@ static size_t GetLength(const grpc_slice& slice) {
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  // Creates an interned slice for a string that does not currently exist in the
 | 
	
		
			
				|  |  | -// intern table. SliceArgs... is either a const grpc_slice& or a string and
 | 
	
		
			
				|  |  | -// length. In either case, hash is the pre-computed hash value. We must already
 | 
	
		
			
				|  |  | -// hold the shard lock. Helper for FindOrCreateInternedSlice().
 | 
	
		
			
				|  |  | +// intern table. SliceArgs is either a const grpc_slice& or a const
 | 
	
		
			
				|  |  | +// pair<const char*, size_t>&. Hash is the pre-computed hash value. We must
 | 
	
		
			
				|  |  | +// already hold the shard lock. Helper for FindOrCreateInternedSlice().
 | 
	
		
			
				|  |  |  //
 | 
	
		
			
				|  |  |  // Returns: a newly interned slice.
 | 
	
		
			
				|  |  | -template <class... SliceArgs>
 | 
	
		
			
				|  |  | +template <typename SliceArgs>
 | 
	
		
			
				|  |  |  static InternedSliceRefcount* InternNewStringLocked(slice_shard* shard,
 | 
	
		
			
				|  |  |                                                      size_t shard_idx,
 | 
	
		
			
				|  |  |                                                      uint32_t hash,
 | 
	
		
			
				|  |  | -                                                    SliceArgs&&... args) {
 | 
	
		
			
				|  |  | +                                                    const SliceArgs& args) {
 | 
	
		
			
				|  |  |    /* string data goes after the internal_string header */
 | 
	
		
			
				|  |  | -  size_t len = GetLength(std::forward<SliceArgs>(args)...);
 | 
	
		
			
				|  |  | -  const void* buffer = GetBuffer(std::forward<SliceArgs>(args)...);
 | 
	
		
			
				|  |  | +  size_t len = GetLength(args);
 | 
	
		
			
				|  |  | +  const void* buffer = GetBuffer(args);
 | 
	
		
			
				|  |  |    InternedSliceRefcount* s =
 | 
	
		
			
				|  |  |        static_cast<InternedSliceRefcount*>(gpr_malloc(sizeof(*s) + len));
 | 
	
		
			
				|  |  |    new (s) grpc_core::InternedSliceRefcount(len, hash, shard->strs[shard_idx]);
 | 
	
	
		
			
				|  | @@ -227,16 +231,15 @@ static InternedSliceRefcount* InternNewStringLocked(slice_shard* shard,
 | 
	
		
			
				|  |  |  // shard lock. Helper for FindOrCreateInternedSlice().
 | 
	
		
			
				|  |  |  //
 | 
	
		
			
				|  |  |  // Returns: a pre-existing matching static slice, or null.
 | 
	
		
			
				|  |  | -template <class... SliceArgs>
 | 
	
		
			
				|  |  | +template <typename SliceArgs>
 | 
	
		
			
				|  |  |  static InternedSliceRefcount* MatchInternedSliceLocked(uint32_t hash,
 | 
	
		
			
				|  |  |                                                         size_t idx,
 | 
	
		
			
				|  |  | -                                                       SliceArgs&&... args) {
 | 
	
		
			
				|  |  | +                                                       const SliceArgs& args) {
 | 
	
		
			
				|  |  |    InternedSliceRefcount* s;
 | 
	
		
			
				|  |  |    slice_shard* shard = &g_shards[SHARD_IDX(hash)];
 | 
	
		
			
				|  |  |    /* search for an existing string */
 | 
	
		
			
				|  |  |    for (s = shard->strs[idx]; s; s = s->bucket_next) {
 | 
	
		
			
				|  |  | -    if (s->hash == hash &&
 | 
	
		
			
				|  |  | -        grpc_core::InternedSlice(s).Equals(std::forward<SliceArgs>(args)...)) {
 | 
	
		
			
				|  |  | +    if (s->hash == hash && grpc_core::InternedSlice(s) == args) {
 | 
	
		
			
				|  |  |        if (s->refcnt.RefIfNonZero()) {
 | 
	
		
			
				|  |  |          return s;
 | 
	
		
			
				|  |  |        }
 | 
	
	
		
			
				|  | @@ -248,22 +251,20 @@ static InternedSliceRefcount* MatchInternedSliceLocked(uint32_t hash,
 | 
	
		
			
				|  |  |  // Attempt to see if the provided slice or string matches an existing interned
 | 
	
		
			
				|  |  |  // slice, and failing that, create an interned slice with its contents. Returns
 | 
	
		
			
				|  |  |  // either the existing matching interned slice or the newly created one.
 | 
	
		
			
				|  |  | -// SliceArgs... is either a const grpc_slice& or a string and length. In either
 | 
	
		
			
				|  |  | -// case, hash is the pre-computed hash value. We do not hold the shard lock
 | 
	
		
			
				|  |  | -// here, but do take it.
 | 
	
		
			
				|  |  | +// SliceArgs is either a const grpc_slice& or const pair<const char*, size_t>&.
 | 
	
		
			
				|  |  | +// In either case, hash is the pre-computed hash value. We do not hold the
 | 
	
		
			
				|  |  | +// shard lock here, but do take it.
 | 
	
		
			
				|  |  |  //
 | 
	
		
			
				|  |  |  // Returns: an interned slice, either pre-existing/matched or newly created.
 | 
	
		
			
				|  |  | -template <class... SliceArgs>
 | 
	
		
			
				|  |  | +template <typename SliceArgs>
 | 
	
		
			
				|  |  |  static InternedSliceRefcount* FindOrCreateInternedSlice(uint32_t hash,
 | 
	
		
			
				|  |  | -                                                        SliceArgs&&... args) {
 | 
	
		
			
				|  |  | +                                                        const SliceArgs& args) {
 | 
	
		
			
				|  |  |    slice_shard* shard = &g_shards[SHARD_IDX(hash)];
 | 
	
		
			
				|  |  |    gpr_mu_lock(&shard->mu);
 | 
	
		
			
				|  |  |    const size_t idx = TABLE_IDX(hash, shard->capacity);
 | 
	
		
			
				|  |  | -  InternedSliceRefcount* s =
 | 
	
		
			
				|  |  | -      MatchInternedSliceLocked(hash, idx, std::forward<SliceArgs>(args)...);
 | 
	
		
			
				|  |  | +  InternedSliceRefcount* s = MatchInternedSliceLocked(hash, idx, args);
 | 
	
		
			
				|  |  |    if (s == nullptr) {
 | 
	
		
			
				|  |  | -    s = InternNewStringLocked(shard, idx, hash,
 | 
	
		
			
				|  |  | -                              std::forward<SliceArgs>(args)...);
 | 
	
		
			
				|  |  | +    s = InternNewStringLocked(shard, idx, hash, args);
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |    gpr_mu_unlock(&shard->mu);
 | 
	
		
			
				|  |  |    return s;
 | 
	
	
		
			
				|  | @@ -277,12 +278,13 @@ grpc_core::ManagedMemorySlice::ManagedMemorySlice(const char* string,
 | 
	
		
			
				|  |  |                                                    size_t len) {
 | 
	
		
			
				|  |  |    GPR_TIMER_SCOPE("grpc_slice_intern", 0);
 | 
	
		
			
				|  |  |    const uint32_t hash = gpr_murmur_hash3(string, len, g_hash_seed);
 | 
	
		
			
				|  |  | -  const StaticMetadataSlice* static_slice = MatchStaticSlice(hash, string, len);
 | 
	
		
			
				|  |  | +  const StaticMetadataSlice* static_slice =
 | 
	
		
			
				|  |  | +      MatchStaticSlice(hash, std::pair<const char*, size_t>(string, len));
 | 
	
		
			
				|  |  |    if (static_slice) {
 | 
	
		
			
				|  |  |      *this = *static_slice;
 | 
	
		
			
				|  |  |    } else {
 | 
	
		
			
				|  |  | -    *this =
 | 
	
		
			
				|  |  | -        grpc_core::InternedSlice(FindOrCreateInternedSlice(hash, string, len));
 | 
	
		
			
				|  |  | +    *this = grpc_core::InternedSlice(FindOrCreateInternedSlice(
 | 
	
		
			
				|  |  | +        hash, std::pair<const char*, size_t>(string, len)));
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -303,13 +305,14 @@ grpc_core::ManagedMemorySlice::ManagedMemorySlice(const grpc_slice* slice_ptr) {
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  void grpc_test_only_set_slice_hash_seed(uint32_t seed) {
 | 
	
		
			
				|  |  | -  g_hash_seed = seed;
 | 
	
		
			
				|  |  | -  g_forced_hash_seed = 1;
 | 
	
		
			
				|  |  | +  grpc_core::g_hash_seed = seed;
 | 
	
		
			
				|  |  | +  grpc_core::g_forced_hash_seed = true;
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  void grpc_slice_intern_init(void) {
 | 
	
		
			
				|  |  | -  if (!g_forced_hash_seed) {
 | 
	
		
			
				|  |  | -    g_hash_seed = static_cast<uint32_t>(gpr_now(GPR_CLOCK_REALTIME).tv_nsec);
 | 
	
		
			
				|  |  | +  if (!grpc_core::g_forced_hash_seed) {
 | 
	
		
			
				|  |  | +    grpc_core::g_hash_seed =
 | 
	
		
			
				|  |  | +        static_cast<uint32_t>(gpr_now(GPR_CLOCK_REALTIME).tv_nsec);
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |    for (size_t i = 0; i < SHARD_COUNT; i++) {
 | 
	
		
			
				|  |  |      slice_shard* shard = &g_shards[i];
 |