11use std:: {
22 convert:: { TryFrom , TryInto } ,
33 iter,
4+ collections:: hash_map:: Entry ,
45} ;
56
67use log:: trace;
@@ -34,7 +35,7 @@ pub enum EmulateByNameResult<'mir, 'tcx> {
3435 /// Jumping has already been taken care of.
3536 AlreadyJumped ,
3637 /// A MIR body has been found for the function
37- MirBody ( & ' mir mir:: Body < ' tcx > ) ,
38+ MirBody ( & ' mir mir:: Body < ' tcx > , ty :: Instance < ' tcx > ) ,
3839 /// The item is not supported.
3940 NotSupported ,
4041}
@@ -135,68 +136,74 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
135136 fn lookup_exported_symbol (
136137 & mut self ,
137138 link_name : Symbol ,
138- ) -> InterpResult < ' tcx , Option < & ' mir mir:: Body < ' tcx > > > {
139+ ) -> InterpResult < ' tcx , Option < ( & ' mir mir:: Body < ' tcx > , ty :: Instance < ' tcx > ) > > {
139140 let this = self . eval_context_mut ( ) ;
140141 let tcx = this. tcx . tcx ;
141142
142143 // If the result was cached, just return it.
143- if let Some ( instance) = this. machine . exported_symbols_cache . get ( & link_name) {
144- return instance. map ( |instance| this. load_mir ( instance. def , None ) ) . transpose ( ) ;
145- }
146-
147- // Find it if it was not cached.
148- let mut instance_and_crate: Option < ( ty:: Instance < ' _ > , CrateNum ) > = None ;
149- // `dependency_formats` includes all the transitive informations needed to link a crate,
150- // which is what we need here since we need to dig out `exported_symbols` from all transitive
151- // dependencies.
152- let dependency_formats = tcx. dependency_formats ( ( ) ) ;
153- let dependency_format = dependency_formats
154- . iter ( )
155- . find ( |( crate_type, _) | * crate_type == CrateType :: Executable )
156- . expect ( "interpreting a non-executable crate" ) ;
157- for cnum in
158- iter:: once ( LOCAL_CRATE ) . chain ( dependency_format. 1 . iter ( ) . enumerate ( ) . filter_map (
159- |( num, & linkage) | ( linkage != Linkage :: NotLinked ) . then_some ( CrateNum :: new ( num + 1 ) ) ,
160- ) )
161- {
162- // We can ignore `_export_level` here: we are a Rust crate, and everything is exported
163- // from a Rust crate.
164- for & ( symbol, _export_level) in tcx. exported_symbols ( cnum) {
165- if let ExportedSymbol :: NonGeneric ( def_id) = symbol {
166- let attrs = tcx. codegen_fn_attrs ( def_id) ;
167- let symbol_name = if let Some ( export_name) = attrs. export_name {
168- export_name
169- } else if attrs. flags . contains ( CodegenFnAttrFlags :: NO_MANGLE ) {
170- tcx. item_name ( def_id)
171- } else {
172- // Skip over items without an explicitly defined symbol name.
173- continue ;
174- } ;
175- if symbol_name == link_name {
176- if let Some ( ( instance, original_cnum) ) = instance_and_crate {
177- throw_machine_stop ! ( TerminationInfo :: MultipleSymbolDefinitions {
178- link_name,
179- first: tcx. def_span( instance. def_id( ) ) . data( ) ,
180- first_crate: tcx. crate_name( original_cnum) ,
181- second: tcx. def_span( def_id) . data( ) ,
182- second_crate: tcx. crate_name( cnum) ,
183- } ) ;
184- }
185- if !matches ! ( tcx. def_kind( def_id) , DefKind :: Fn | DefKind :: AssocFn ) {
186- throw_ub_format ! (
187- "attempt to call an exported symbol that is not defined as a function"
188- ) ;
144+ // (Cannot use `or_insert` since the code below might have to throw an error.)
145+ let entry = this. machine . exported_symbols_cache . entry ( link_name) ;
146+ let instance = * match entry {
147+ Entry :: Occupied ( e) => e. into_mut ( ) ,
148+ Entry :: Vacant ( e) => {
149+ // Find it if it was not cached.
150+ let mut instance_and_crate: Option < ( ty:: Instance < ' _ > , CrateNum ) > = None ;
151+ // `dependency_formats` includes all the transitive informations needed to link a crate,
152+ // which is what we need here since we need to dig out `exported_symbols` from all transitive
153+ // dependencies.
154+ let dependency_formats = tcx. dependency_formats ( ( ) ) ;
155+ let dependency_format = dependency_formats
156+ . iter ( )
157+ . find ( |( crate_type, _) | * crate_type == CrateType :: Executable )
158+ . expect ( "interpreting a non-executable crate" ) ;
159+ for cnum in
160+ iter:: once ( LOCAL_CRATE ) . chain ( dependency_format. 1 . iter ( ) . enumerate ( ) . filter_map (
161+ |( num, & linkage) | ( linkage != Linkage :: NotLinked ) . then_some ( CrateNum :: new ( num + 1 ) ) ,
162+ ) )
163+ {
164+ // We can ignore `_export_level` here: we are a Rust crate, and everything is exported
165+ // from a Rust crate.
166+ for & ( symbol, _export_level) in tcx. exported_symbols ( cnum) {
167+ if let ExportedSymbol :: NonGeneric ( def_id) = symbol {
168+ let attrs = tcx. codegen_fn_attrs ( def_id) ;
169+ let symbol_name = if let Some ( export_name) = attrs. export_name {
170+ export_name
171+ } else if attrs. flags . contains ( CodegenFnAttrFlags :: NO_MANGLE ) {
172+ tcx. item_name ( def_id)
173+ } else {
174+ // Skip over items without an explicitly defined symbol name.
175+ continue ;
176+ } ;
177+ if symbol_name == link_name {
178+ if let Some ( ( instance, original_cnum) ) = instance_and_crate {
179+ throw_machine_stop ! ( TerminationInfo :: MultipleSymbolDefinitions {
180+ link_name,
181+ first: tcx. def_span( instance. def_id( ) ) . data( ) ,
182+ first_crate: tcx. crate_name( original_cnum) ,
183+ second: tcx. def_span( def_id) . data( ) ,
184+ second_crate: tcx. crate_name( cnum) ,
185+ } ) ;
186+ }
187+ if !matches ! ( tcx. def_kind( def_id) , DefKind :: Fn | DefKind :: AssocFn ) {
188+ throw_ub_format ! (
189+ "attempt to call an exported symbol that is not defined as a function"
190+ ) ;
191+ }
192+ instance_and_crate = Some ( ( ty:: Instance :: mono ( tcx, def_id) , cnum) ) ;
193+ }
189194 }
190- instance_and_crate = Some ( ( ty:: Instance :: mono ( tcx, def_id) , cnum) ) ;
191195 }
192196 }
197+
198+ e. insert ( instance_and_crate. map ( |ic| ic. 0 ) )
199+ }
200+ } ;
201+ match instance {
202+ None => Ok ( None ) , // no symbol with this name
203+ Some ( instance) => {
204+ Ok ( Some ( ( this. load_mir ( instance. def , None ) ?, instance) ) )
193205 }
194206 }
195-
196- let instance = instance_and_crate. map ( |ic| ic. 0 ) ;
197- // Cache it and load its MIR, if found.
198- this. machine . exported_symbols_cache . try_insert ( link_name, instance) . unwrap ( ) ;
199- instance. map ( |instance| this. load_mir ( instance. def , None ) ) . transpose ( )
200207 }
201208
202209 /// Emulates calling a foreign item, failing if the item is not supported.
@@ -212,7 +219,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
212219 args : & [ OpTy < ' tcx , Tag > ] ,
213220 ret : Option < ( & PlaceTy < ' tcx , Tag > , mir:: BasicBlock ) > ,
214221 unwind : StackPopUnwind ,
215- ) -> InterpResult < ' tcx , Option < & ' mir mir:: Body < ' tcx > > > {
222+ ) -> InterpResult < ' tcx , Option < ( & ' mir mir:: Body < ' tcx > , ty :: Instance < ' tcx > ) > > {
216223 let this = self . eval_context_mut ( ) ;
217224 let attrs = this. tcx . get_attrs ( def_id) ;
218225 let link_name = this
@@ -240,7 +247,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
240247 this. check_abi_and_shim_symbol_clash ( abi, Abi :: Rust , link_name) ?;
241248 let panic_impl_id = tcx. lang_items ( ) . panic_impl ( ) . unwrap ( ) ;
242249 let panic_impl_instance = ty:: Instance :: mono ( tcx, panic_impl_id) ;
243- return Ok ( Some ( & * this. load_mir ( panic_impl_instance. def , None ) ?) ) ;
250+ return Ok ( Some ( ( & * this. load_mir ( panic_impl_instance. def , None ) ?, panic_impl_instance ) ) ) ;
244251 }
245252 #[ rustfmt:: skip]
246253 | "exit"
@@ -284,7 +291,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
284291 this. go_to_block ( ret) ;
285292 }
286293 EmulateByNameResult :: AlreadyJumped => ( ) ,
287- EmulateByNameResult :: MirBody ( mir) => return Ok ( Some ( mir) ) ,
294+ EmulateByNameResult :: MirBody ( mir, instance ) => return Ok ( Some ( ( mir, instance ) ) ) ,
288295 EmulateByNameResult :: NotSupported => {
289296 if let Some ( body) = this. lookup_exported_symbol ( link_name) ? {
290297 return Ok ( Some ( body) ) ;
@@ -315,11 +322,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
315322
316323 match allocator_kind {
317324 AllocatorKind :: Global => {
318- let body = this
325+ let ( body, instance ) = this
319326 . lookup_exported_symbol ( symbol) ?
320327 . expect ( "symbol should be present if there is a global allocator" ) ;
321328
322- Ok ( EmulateByNameResult :: MirBody ( body) )
329+ Ok ( EmulateByNameResult :: MirBody ( body, instance ) )
323330 }
324331 AllocatorKind :: Default => {
325332 default ( this) ?;
0 commit comments