Skip to content

Commit 016fd7c

Browse files
stepanchegfacebook-github-bot
authored andcommitted
Use StringValue in dict key in ParametersSpec::collect
Summary: Before this diff `kwargs` were collected into `Dict` which is `SmallMap<Hashed<Value>, Value>`. Now `kwargs` are collected into `SmallMap<Hashed<StringValue>, Value>` and that `SmallMap` is "coerced" into a map with `Value` key. When inserting keys we lookup previous keys (this should be partially addressed by [this PR in indexmap](indexmap-rs/indexmap#200)), and equality operation on `StringValue` is cheaper that equality on `Value` because there's no dynamic casts. We don't do real equality often (because hash collisions are rare), but having `StringValue` instead of `Value` may generate more efficient machine code. Also this makes code a little more type-safe. Reviewed By: ndmitchell Differential Revision: D30921794 fbshipit-source-id: cf2b4fa72eeef150e6308d2fe2d7c16f59166586
1 parent 1f85103 commit 016fd7c

File tree

2 files changed

+40
-16
lines changed

2 files changed

+40
-16
lines changed

starlark/src/eval/runtime/arguments.rs

+26-16
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,11 @@ use crate::{
3030
},
3131
};
3232
use either::Either;
33-
use gazebo::{cell::ARef, coerce::Coerce, prelude::*};
33+
use gazebo::{
34+
cell::ARef,
35+
coerce::{coerce, Coerce},
36+
prelude::*,
37+
};
3438
use itertools::Itertools;
3539
use std::{cell::Cell, cmp, convert::TryInto, intrinsics::unlikely, iter};
3640
use thiserror::Error;
@@ -371,18 +375,18 @@ impl<'v, V: ValueLike<'v>> ParametersSpec<V> {
371375
// Return true if the value is a duplicate
372376
#[inline(always)]
373377
fn add_kwargs<'v>(
374-
kwargs: &mut Option<Box<Dict<'v>>>,
375-
key: Hashed<Value<'v>>,
378+
kwargs: &mut Option<Box<SmallMap<StringValue<'v>, Value<'v>>>>,
379+
key: Hashed<StringValue<'v>>,
376380
val: Value<'v>,
377381
) -> bool {
378382
match kwargs {
379383
None => {
380384
let mut mp = SmallMap::with_capacity_largest_vec();
381385
mp.insert_hashed(key, val);
382-
*kwargs = Some(box Dict::new(mp));
386+
*kwargs = Some(box mp);
383387
false
384388
}
385-
Some(mp) => mp.content.insert_hashed(key, val).is_some(),
389+
Some(mp) => mp.insert_hashed(key, val).is_some(),
386390
}
387391
}
388392

@@ -425,7 +429,7 @@ impl<'v, V: ValueLike<'v>> ParametersSpec<V> {
425429
None => {
426430
add_kwargs(
427431
&mut kwargs,
428-
Hashed::new_unchecked(name.small_hash(), name_value.to_value()),
432+
Hashed::new_unchecked(name.small_hash(), *name_value),
429433
*v,
430434
);
431435
}
@@ -466,14 +470,17 @@ impl<'v, V: ValueLike<'v>> ParametersSpec<V> {
466470
match Dict::from_value(param_kwargs) {
467471
Some(y) => {
468472
for (k, v) in y.iter_hashed() {
469-
match k.key().unpack_str() {
473+
match StringValue::new(*k.key()) {
470474
None => return Err(FunctionError::ArgsValueIsNotString.into()),
471475
Some(s) => {
472-
let repeat = match self
473-
.names
474-
.get_hashed_str(BorrowHashed::new_unchecked(k.hash(), s))
475-
{
476-
None => add_kwargs(&mut kwargs, k, v),
476+
let repeat = match self.names.get_hashed_str(
477+
BorrowHashed::new_unchecked(k.hash(), s.as_str()),
478+
) {
479+
None => add_kwargs(
480+
&mut kwargs,
481+
Hashed::new_unchecked(k.hash(), s),
482+
v,
483+
),
477484
Some(i) => {
478485
let this_slot = &slots[*i];
479486
let repeat = this_slot.get().is_some();
@@ -483,7 +490,7 @@ impl<'v, V: ValueLike<'v>> ParametersSpec<V> {
483490
};
484491
if unlikely(repeat) {
485492
return Err(FunctionError::RepeatedParameter {
486-
name: s.to_owned(),
493+
name: s.as_str().to_owned(),
487494
}
488495
.into());
489496
}
@@ -538,11 +545,14 @@ impl<'v, V: ValueLike<'v>> ParametersSpec<V> {
538545
}
539546

540547
if let Some(kwargs_pos) = self.kwargs {
541-
let kwargs = kwargs.take().unwrap_or_default();
542-
slots[kwargs_pos].set(Some(heap.alloc(*kwargs)));
548+
let kwargs = match kwargs.take() {
549+
Some(kwargs) => Dict::new(coerce(*kwargs)),
550+
None => Dict::default(),
551+
};
552+
slots[kwargs_pos].set(Some(heap.alloc(kwargs)));
543553
} else if let Some(kwargs) = kwargs {
544554
return Err(FunctionError::ExtraNamedParameters {
545-
names: kwargs.content.keys().map(|x| x.to_str()).collect(),
555+
names: kwargs.keys().map(|x| x.as_str().to_owned()).collect(),
546556
function: self.signature(),
547557
}
548558
.into());

starlark/src/values/layout/constant.rs

+14
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,8 @@ unsafe impl<'v> Coerce<StringValue<'v>> for FrozenStringValue {}
100100
unsafe impl<'v> CoerceKey<StringValue<'v>> for FrozenStringValue {}
101101
unsafe impl<'v> Coerce<StringValue<'v>> for StringValue<'v> {}
102102
unsafe impl<'v> CoerceKey<StringValue<'v>> for StringValue<'v> {}
103+
unsafe impl<'v> Coerce<Value<'v>> for StringValue<'v> {}
104+
unsafe impl<'v> CoerceKey<Value<'v>> for StringValue<'v> {}
103105

104106
impl PartialEq for FrozenStringValue {
105107
fn eq(&self, other: &Self) -> bool {
@@ -138,6 +140,14 @@ impl FrozenStringValue {
138140
}
139141
}
140142

143+
impl<'v> PartialEq for StringValue<'v> {
144+
fn eq(&self, other: &Self) -> bool {
145+
self.0.ptr_eq(other.0) || self.as_str() == other.as_str()
146+
}
147+
}
148+
149+
impl<'v> Eq for StringValue<'v> {}
150+
141151
impl<'v> StringValue<'v> {
142152
/// Construct without a check that the value contains a string.
143153
///
@@ -161,6 +171,10 @@ impl<'v> StringValue<'v> {
161171
unsafe { &self.0.0.unpack_ptr_no_int_unchecked().as_repr().payload }
162172
}
163173

174+
pub(crate) fn as_str(self) -> &'v str {
175+
self.unpack_starlark_str().unpack()
176+
}
177+
164178
pub(crate) fn to_value(self) -> Value<'v> {
165179
self.0
166180
}

0 commit comments

Comments
 (0)