@@ -10,14 +10,30 @@ use anyhow::Context;
1010use indexmap:: map:: Entry ;
1111use std:: ptr:: NonNull ;
1212
13+ /// Translates IDs from a [`ProfilesDictionary`] into the IDs used by the
14+ /// current Profile's internal collections.
15+ ///
16+ /// # Safety
17+ ///
18+ /// All IDs passed to the translate methods (translate_function,
19+ /// translate_mapping, translate_string) MUST have been created by the same
20+ /// ProfilesDictionary that this translator wraps.
1321pub struct ProfilesDictionaryTranslator {
1422 pub profiles_dictionary : crate :: profiles:: collections:: Arc < ProfilesDictionary > ,
1523 pub mappings : FxIndexMap < SetId < dt:: Mapping > , MappingId > ,
1624 pub functions : FxIndexMap < Option < SetId < dt:: Function > > , FunctionId > ,
1725 pub strings : FxIndexMap < StringRef , StringId > ,
1826}
1927
20- // SAFETY: the profiles_dictionary keeps the storage for Ids alive.
28+ // SAFETY: ProfilesDictionaryTranslator is Send because:
29+ // 1. The profiles_dictionary Arc ensures the underlying storage remains alive and valid for the
30+ // lifetime of this translator, and Arc<T> is Send when T is Send + Sync. ProfilesDictionary is
31+ // Send + Sync.
32+ // 2. SetId<T> and StringRef are non-owning handles (thin pointers) to immutable data in the
33+ // ProfilesDictionary's concurrent collections, which use arena allocation with stable addresses.
34+ // The Arc protects this data, making the pointers safe to send across threads.
35+ // 3. FxIndexMap<K, V> is Send when K and V are Send. The keys (SetId, StringRef) and values
36+ // (MappingId, FunctionId, StringId) are all Copy types that are Send.
2137unsafe impl Send for ProfilesDictionaryTranslator { }
2238
2339impl ProfilesDictionaryTranslator {
@@ -32,7 +48,14 @@ impl ProfilesDictionaryTranslator {
3248 }
3349 }
3450
35- pub fn translate_function (
51+ /// Translates a FunctionId2 from the ProfilesDictionary into a FunctionId
52+ /// for this profile's StringTable.
53+ ///
54+ /// # Safety
55+ ///
56+ /// The `id2` must have been created by `self.profiles_dictionary`, and
57+ /// the strings must also live in the same dictionary.
58+ pub unsafe fn translate_function (
3659 & mut self ,
3760 functions : & mut impl Dedup < Function > ,
3861 string_table : & mut StringTable ,
@@ -55,12 +78,19 @@ impl ProfilesDictionaryTranslator {
5578 return Ok ( * internal) ;
5679 }
5780
58- // SAFETY: todo
81+ // SAFETY: This is safe if `id2` (the FunctionId2) was created by
82+ // `self.profiles_dictionary`, which is a precondition of calling
83+ // this method.
5984 let function = unsafe { * self . profiles_dictionary . functions ( ) . get ( set_id) } ;
60- let function = Function {
61- name : self . translate_string ( string_table, function. name ) ?,
62- system_name : self . translate_string ( string_table, function. system_name ) ?,
63- filename : self . translate_string ( string_table, function. file_name ) ?,
85+ // SAFETY: safe if the strings were made by
86+ // `self.profiles_dictionary`, which is a precondition of
87+ // calling this method.
88+ let function = unsafe {
89+ Function {
90+ name : self . translate_string ( string_table, function. name ) ?,
91+ system_name : self . translate_string ( string_table, function. system_name ) ?,
92+ filename : self . translate_string ( string_table, function. file_name ) ?,
93+ }
6494 } ;
6595 ( Some ( set_id) , function)
6696 }
@@ -76,7 +106,14 @@ impl ProfilesDictionaryTranslator {
76106 Ok ( internal_id)
77107 }
78108
79- pub fn translate_mapping (
109+ /// Translates a MappingId2 from the ProfilesDictionary into a MappingId
110+ /// for this profile's internal collections.
111+ ///
112+ /// # Safety
113+ ///
114+ /// The `id2` must have been created by `self.profiles_dictionary`, and
115+ /// the strings must also live in the same dictionary.
116+ pub unsafe fn translate_mapping (
80117 & mut self ,
81118 mappings : & mut impl Dedup < Mapping > ,
82119 string_table : & mut StringTable ,
@@ -93,7 +130,9 @@ impl ProfilesDictionaryTranslator {
93130 return Ok ( Some ( * internal) ) ;
94131 }
95132
96- // SAFETY: todo
133+ // SAFETY: This is safe if `id2` (the MappingId2) was created by
134+ // `self.profiles_dictionary`, which is a precondition of calling
135+ // this method.
97136 let mapping = unsafe { * self . profiles_dictionary . mappings ( ) . get ( set_id) } ;
98137 let internal = Mapping {
99138 memory_start : mapping. memory_start ,
@@ -112,7 +151,14 @@ impl ProfilesDictionaryTranslator {
112151 Ok ( Some ( internal_id) )
113152 }
114153
115- pub fn translate_string (
154+ /// Translates a StringRef from the ProfilesDictionary into a StringId
155+ /// for this profile's internal string table.
156+ ///
157+ /// # Safety
158+ ///
159+ /// The `str_ref` must have been created by `self.profiles_dictionary`.
160+ /// Violating this precondition results in undefined behavior.
161+ pub unsafe fn translate_string (
116162 & mut self ,
117163 string_table : & mut StringTable ,
118164 str_ref : StringRef ,
@@ -121,12 +167,11 @@ impl ProfilesDictionaryTranslator {
121167 match self . strings . entry ( str_ref) {
122168 Entry :: Occupied ( o) => Ok ( * o. get ( ) ) ,
123169 Entry :: Vacant ( v) => {
170+ // SAFETY: This is safe if `str_ref` was created by
171+ // `self.profiles_dictionary`, which is a precondition of calling
172+ // this method.
124173 let str = unsafe { self . profiles_dictionary . strings ( ) . get ( str_ref) } ;
125- // SAFETY: we're keeping these lifetimes in sync. I think.
126- // TODO: BUT longer-term we want to avoid copying them
127- // entirely, so this should go away.
128- let decouple_str = unsafe { core:: mem:: transmute :: < & str , & str > ( str) } ;
129- let internal_id = string_table. try_intern ( decouple_str) ?;
174+ let internal_id = string_table. try_intern ( str) ?;
130175 v. insert ( internal_id) ;
131176 Ok ( internal_id)
132177 }
0 commit comments