@@ -11,14 +11,14 @@ use rustc_abi::ExternAbi;
1111use rustc_data_structures:: fx:: { FxHashMap , FxHashSet } ;
1212use rustc_hir:: def:: Namespace ;
1313use rustc_hir:: def_id:: DefId ;
14- use rustc_middle:: ty:: layout:: LayoutCx ;
14+ use rustc_middle:: ty:: layout:: { HasTyCtxt , HasTypingEnv , LayoutCx } ;
1515use rustc_middle:: ty:: { self , Ty , TyCtxt } ;
1616use rustc_session:: config:: EntryFnType ;
1717
1818use crate :: concurrency:: GenmcCtx ;
1919use crate :: concurrency:: thread:: TlsAllocAction ;
2020use crate :: diagnostics:: report_leaks;
21- use crate :: shims:: tls;
21+ use crate :: shims:: { global_ctor , tls} ;
2222use crate :: * ;
2323
2424#[ derive( Copy , Clone , Debug ) ]
@@ -216,9 +216,17 @@ impl Default for MiriConfig {
216216}
217217
218218/// The state of the main thread. Implementation detail of `on_main_stack_empty`.
219- #[ derive( Default , Debug ) ]
219+ #[ derive( Debug ) ]
220220enum MainThreadState < ' tcx > {
221- #[ default]
221+ GlobalCtors {
222+ ctor_state : global_ctor:: GlobalCtorState < ' tcx > ,
223+ /// The main function to call.
224+ entry_id : DefId ,
225+ entry_type : MiriEntryFnType ,
226+ /// Arguments passed to `main`.
227+ argc : ImmTy < ' tcx > ,
228+ argv : ImmTy < ' tcx > ,
229+ } ,
222230 Running ,
223231 TlsDtors ( tls:: TlsDtorsState < ' tcx > ) ,
224232 Yield {
@@ -234,6 +242,15 @@ impl<'tcx> MainThreadState<'tcx> {
234242 ) -> InterpResult < ' tcx , Poll < ( ) > > {
235243 use MainThreadState :: * ;
236244 match self {
245+ GlobalCtors { ctor_state, entry_id, entry_type, argc, argv } => {
246+ match ctor_state. on_stack_empty ( this) ? {
247+ Poll :: Pending => { } // just keep going
248+ Poll :: Ready ( ( ) ) => {
249+ call_main ( this, * entry_id, * entry_type, argc. clone ( ) , argv. clone ( ) ) ?;
250+ * self = Running ;
251+ }
252+ }
253+ }
237254 Running => {
238255 * self = TlsDtors ( Default :: default ( ) ) ;
239256 }
@@ -309,13 +326,6 @@ pub fn create_ecx<'tcx>(
309326 MiriMachine :: new ( config, layout_cx, genmc_ctx) ,
310327 ) ;
311328
312- // Some parts of initialization require a full `InterpCx`.
313- MiriMachine :: late_init ( & mut ecx, config, {
314- let mut state = MainThreadState :: default ( ) ;
315- // Cannot capture anything GC-relevant here.
316- Box :: new ( move |m| state. on_main_stack_empty ( m) )
317- } ) ?;
318-
319329 // Make sure we have MIR. We check MIR for some stable monomorphic function in libcore.
320330 let sentinel =
321331 helpers:: try_resolve_path ( tcx, & [ "core" , "ascii" , "escape_default" ] , Namespace :: ValueNS ) ;
@@ -326,15 +336,9 @@ pub fn create_ecx<'tcx>(
326336 ) ;
327337 }
328338
329- // Setup first stack frame.
330- let entry_instance = ty:: Instance :: mono ( tcx, entry_id) ;
331-
332- // First argument is constructed later, because it's skipped for `miri_start.`
333-
334- // Second argument (argc): length of `config.args`.
339+ // Compute argc and argv from `config.args`.
335340 let argc =
336341 ImmTy :: from_int ( i64:: try_from ( config. args . len ( ) ) . unwrap ( ) , ecx. machine . layouts . isize ) ;
337- // Third argument (`argv`): created from `config.args`.
338342 let argv = {
339343 // Put each argument in memory, collect pointers.
340344 let mut argvs = Vec :: < Immediate < Provenance > > :: with_capacity ( config. args . len ( ) ) ;
@@ -359,7 +363,7 @@ pub fn create_ecx<'tcx>(
359363 ecx. write_immediate ( arg, & place) ?;
360364 }
361365 ecx. mark_immutable ( & argvs_place) ;
362- // Store `argc` and `argv` for macOS `_NSGetArg{c,v}`.
366+ // Store `argc` and `argv` for macOS `_NSGetArg{c,v}`, and for the GC to see them .
363367 {
364368 let argc_place =
365369 ecx. allocate ( ecx. machine . layouts . isize , MiriMemoryKind :: Machine . into ( ) ) ?;
@@ -374,7 +378,7 @@ pub fn create_ecx<'tcx>(
374378 ecx. machine . argv = Some ( argv_place. ptr ( ) ) ;
375379 }
376380 // Store command line as UTF-16 for Windows `GetCommandLineW`.
377- {
381+ if tcx . sess . target . os == "windows" {
378382 // Construct a command string with all the arguments.
379383 let cmd_utf16: Vec < u16 > = args_to_utf16_command_string ( config. args . iter ( ) ) ;
380384
@@ -395,11 +399,43 @@ pub fn create_ecx<'tcx>(
395399 ImmTy :: from_immediate ( imm, layout)
396400 } ;
397401
402+ // Some parts of initialization require a full `InterpCx`.
403+ MiriMachine :: late_init ( & mut ecx, config, {
404+ let mut main_thread_state = MainThreadState :: GlobalCtors {
405+ entry_id,
406+ entry_type,
407+ argc,
408+ argv,
409+ ctor_state : global_ctor:: GlobalCtorState :: default ( ) ,
410+ } ;
411+
412+ // Cannot capture anything GC-relevant here.
413+ // `argc` and `argv` *are* GC_relevant, but they also get stored in `machine.argc` and
414+ // `machine.argv` so we are good.
415+ Box :: new ( move |m| main_thread_state. on_main_stack_empty ( m) )
416+ } ) ?;
417+
418+ interp_ok ( ecx)
419+ }
420+
421+ // Call the entry function.
422+ fn call_main < ' tcx > (
423+ ecx : & mut MiriInterpCx < ' tcx > ,
424+ entry_id : DefId ,
425+ entry_type : MiriEntryFnType ,
426+ argc : ImmTy < ' tcx > ,
427+ argv : ImmTy < ' tcx > ,
428+ ) -> InterpResult < ' tcx , ( ) > {
429+ let tcx = ecx. tcx ( ) ;
430+
431+ // Setup first stack frame.
432+ let entry_instance = ty:: Instance :: mono ( tcx, entry_id) ;
433+
398434 // Return place (in static memory so that it does not count as leak).
399435 let ret_place = ecx. allocate ( ecx. machine . layouts . isize , MiriMemoryKind :: Machine . into ( ) ) ?;
400436 ecx. machine . main_fn_ret_place = Some ( ret_place. clone ( ) ) ;
401- // Call start function.
402437
438+ // Call start function.
403439 match entry_type {
404440 MiriEntryFnType :: Rustc ( EntryFnType :: Main { .. } ) => {
405441 let start_id = tcx. lang_items ( ) . start_fn ( ) . unwrap_or_else ( || {
@@ -409,7 +445,7 @@ pub fn create_ecx<'tcx>(
409445 let main_ret_ty = main_ret_ty. no_bound_vars ( ) . unwrap ( ) ;
410446 let start_instance = ty:: Instance :: try_resolve (
411447 tcx,
412- typing_env,
448+ ecx . typing_env ( ) ,
413449 start_id,
414450 tcx. mk_args ( & [ ty:: GenericArg :: from ( main_ret_ty) ] ) ,
415451 )
@@ -427,7 +463,7 @@ pub fn create_ecx<'tcx>(
427463 ExternAbi :: Rust ,
428464 & [
429465 ImmTy :: from_scalar (
430- Scalar :: from_pointer ( main_ptr, & ecx) ,
466+ Scalar :: from_pointer ( main_ptr, ecx) ,
431467 // FIXME use a proper fn ptr type
432468 ecx. machine . layouts . const_raw_ptr ,
433469 ) ,
@@ -450,7 +486,7 @@ pub fn create_ecx<'tcx>(
450486 }
451487 }
452488
453- interp_ok ( ecx )
489+ interp_ok ( ( ) )
454490}
455491
456492/// Evaluates the entry function specified by `entry_id`.
0 commit comments