@@ -13,7 +13,8 @@ use rustc_target::abi::{HasDataLayout, Size};
13
13
use crate :: ty:: { ParamEnv , ScalarInt , Ty , TyCtxt } ;
14
14
15
15
use super :: {
16
- alloc_range, AllocId , InterpResult , Pointer , PointerArithmetic , Provenance , ScalarSizeMismatch ,
16
+ AllocId , ConstAllocation , InterpResult , Pointer , PointerArithmetic , Provenance ,
17
+ ScalarSizeMismatch ,
17
18
} ;
18
19
19
20
/// Represents the result of const evaluation via the `eval_to_allocation` query.
@@ -27,13 +28,13 @@ pub struct ConstAlloc<'tcx> {
27
28
28
29
#[ derive( Copy , Clone , Debug , Eq , PartialEq , Hash ) ]
29
30
#[ derive( HashStable ) ]
30
- pub struct ConstValue < ' tcx > ( pub ( crate ) Interned < ' tcx , ConstValueKind > ) ;
31
+ pub struct ConstValue < ' tcx > ( pub ( crate ) Interned < ' tcx , ConstValueKind < ' tcx > > ) ;
31
32
32
33
/// Represents a constant value in Rust. `Scalar` and `Slice` are optimizations for
33
34
/// array length computations, enum discriminants and the pattern matching logic.
34
35
#[ derive( Copy , Clone , Debug , Eq , PartialEq , TyEncodable , TyDecodable , Hash ) ]
35
- #[ derive( HashStable ) ]
36
- pub enum ConstValueKind {
36
+ #[ derive( HashStable , Lift ) ]
37
+ pub enum ConstValueKind < ' tcx > {
37
38
/// Used for types with `layout::abi::Scalar` ABI.
38
39
///
39
40
/// Not using the enum `Value` to encode that this must not be `Uninit`.
@@ -47,9 +48,16 @@ pub enum ConstValueKind {
47
48
/// Only for ZSTs.
48
49
ZeroSized ,
49
50
51
+ /// Used for `&[u8]` and `&str`.
52
+ ///
53
+ /// This is worth an optimized representation since Rust has literals of these types.
54
+ /// Not having to indirect those through an `AllocId` (or two, if we used `Indirect`) has shown
55
+ /// measurable performance improvements on stress tests.
56
+ Slice { data : ConstAllocation < ' tcx > , start : usize , end : usize } ,
57
+
50
58
/// A value not representable by the other variants; needs to be stored in-memory.
51
59
///
52
- /// Must *not* be used for scalars or ZST, but having `&str` or other slices in this variant is fine .
60
+ /// Must *not* be used for scalars, scalar pairs or ZST .
53
61
Indirect {
54
62
/// The backing memory of the value. May contain more memory than needed for just the value
55
63
/// if this points into some other larger ConstValue.
@@ -68,12 +76,12 @@ static_assert_size!(ConstValue<'_>, 8);
68
76
69
77
impl < ' tcx > ConstValue < ' tcx > {
70
78
#[ inline]
71
- pub fn new ( tcx : TyCtxt < ' tcx > , kind : ConstValueKind ) -> ConstValue < ' tcx > {
79
+ pub fn new ( tcx : TyCtxt < ' tcx > , kind : ConstValueKind < ' tcx > ) -> ConstValue < ' tcx > {
72
80
tcx. intern_const_value ( kind)
73
81
}
74
82
75
83
#[ inline]
76
- pub fn kind ( self ) -> & ' tcx ConstValueKind {
84
+ pub fn kind ( self ) -> & ' tcx ConstValueKind < ' tcx > {
77
85
self . 0 . 0
78
86
}
79
87
@@ -82,6 +90,7 @@ impl<'tcx> ConstValue<'tcx> {
82
90
match self . kind ( ) {
83
91
ConstValueKind :: Indirect { .. }
84
92
| ConstValueKind :: ScalarPair ( ..)
93
+ | ConstValueKind :: Slice { .. }
85
94
| ConstValueKind :: ZeroSized => None ,
86
95
ConstValueKind :: Scalar ( val) => Some ( * val) ,
87
96
}
@@ -162,6 +171,16 @@ impl<'tcx> ConstValue<'tcx> {
162
171
)
163
172
}
164
173
174
+ #[ inline]
175
+ pub fn from_raw_slice (
176
+ tcx : TyCtxt < ' tcx > ,
177
+ data : ConstAllocation < ' tcx > ,
178
+ start : usize ,
179
+ end : usize ,
180
+ ) -> Self {
181
+ Self :: new ( tcx, ConstValueKind :: Slice { data, start, end } )
182
+ }
183
+
165
184
#[ inline]
166
185
pub fn from_memory ( tcx : TyCtxt < ' tcx > , alloc_id : AllocId , offset : Size ) -> Self {
167
186
debug_assert ! ( matches!( tcx. global_alloc( alloc_id) , super :: GlobalAlloc :: Memory ( _) ) ) ;
@@ -178,41 +197,7 @@ impl<'tcx> ConstValue<'tcx> {
178
197
let length = length. try_to_target_usize ( tcx) . unwrap ( ) as usize ;
179
198
( alloc, start, start + length)
180
199
}
181
- & ConstValueKind :: Indirect { alloc_id, offset } => {
182
- // The reference itself is stored behind an indirection.
183
- // Load the reference, and then load the actual slice contents.
184
- let a = tcx. global_alloc ( alloc_id) . unwrap_memory ( ) . inner ( ) ;
185
- let ptr_size = tcx. data_layout . pointer_size ;
186
- if a. size ( ) < offset + 2 * ptr_size {
187
- // (partially) dangling reference
188
- return None ;
189
- }
190
- // Read the wide pointer components.
191
- let ptr = a
192
- . read_scalar (
193
- & tcx,
194
- alloc_range ( offset, ptr_size) ,
195
- /* read_provenance */ true ,
196
- )
197
- . ok ( ) ?;
198
- let ptr = ptr. to_pointer ( & tcx) . ok ( ) ?;
199
- let len = a
200
- . read_scalar (
201
- & tcx,
202
- alloc_range ( offset + ptr_size, ptr_size) ,
203
- /* read_provenance */ false ,
204
- )
205
- . ok ( ) ?;
206
- let len = len. to_target_usize ( & tcx) . ok ( ) ?;
207
- let len: usize = len. try_into ( ) . ok ( ) ?;
208
- if len == 0 {
209
- return Some ( & [ ] ) ;
210
- }
211
- // Non-empty slice, must have memory. We know this is a relative pointer.
212
- let ( inner_alloc_id, offset) = ptr. into_parts ( ) ;
213
- let data = tcx. global_alloc ( inner_alloc_id?) . unwrap_memory ( ) ;
214
- ( data, offset. bytes_usize ( ) , offset. bytes_usize ( ) + len)
215
- }
200
+ & ConstValueKind :: Slice { data, start, end } => ( data, start, end) ,
216
201
_ => {
217
202
bug ! ( "`try_get_slice_bytes` on non-slice constant" )
218
203
}
0 commit comments