@@ -499,6 +499,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
499499 & mut self ,
500500 helper : TerminatorCodegenHelper < ' tcx > ,
501501 bx : & mut Bx ,
502+ source_info : & mir:: SourceInfo ,
502503 location : mir:: Place < ' tcx > ,
503504 target : mir:: BasicBlock ,
504505 unwind : mir:: UnwindAction ,
@@ -522,90 +523,109 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
522523 args1 = [ place. val . llval ] ;
523524 & args1[ ..]
524525 } ;
525- let ( drop_fn, fn_abi, drop_instance) =
526- match ty. kind ( ) {
527- // FIXME(eddyb) perhaps move some of this logic into
528- // `Instance::resolve_drop_in_place`?
529- ty:: Dynamic ( _, _, ty:: Dyn ) => {
530- // IN THIS ARM, WE HAVE:
531- // ty = *mut (dyn Trait)
532- // which is: exists<T> ( *mut T, Vtable<T: Trait> )
533- // args[0] args[1]
534- //
535- // args = ( Data, Vtable )
536- // |
537- // v
538- // /-------\
539- // | ... |
540- // \-------/
541- //
542- let virtual_drop = Instance {
543- def : ty:: InstanceDef :: Virtual ( drop_fn. def_id ( ) , 0 ) , // idx 0: the drop function
544- args : drop_fn. args ,
545- } ;
546- debug ! ( "ty = {:?}" , ty) ;
547- debug ! ( "drop_fn = {:?}" , drop_fn) ;
548- debug ! ( "args = {:?}" , args) ;
549- let fn_abi = bx. fn_abi_of_instance ( virtual_drop, ty:: List :: empty ( ) ) ;
550- let vtable = args[ 1 ] ;
551- // Truncate vtable off of args list
552- args = & args[ ..1 ] ;
553- (
554- meth:: VirtualIndex :: from_index ( ty:: COMMON_VTABLE_ENTRIES_DROPINPLACE )
555- . get_fn ( bx, vtable, ty, fn_abi) ,
556- fn_abi,
557- virtual_drop,
558- )
559- }
560- ty:: Dynamic ( _, _, ty:: DynStar ) => {
561- // IN THIS ARM, WE HAVE:
562- // ty = *mut (dyn* Trait)
563- // which is: *mut exists<T: sizeof(T) == sizeof(usize)> (T, Vtable<T: Trait>)
564- //
565- // args = [ * ]
566- // |
567- // v
568- // ( Data, Vtable )
569- // |
570- // v
571- // /-------\
572- // | ... |
573- // \-------/
574- //
575- //
576- // WE CAN CONVERT THIS INTO THE ABOVE LOGIC BY DOING
577- //
578- // data = &(*args[0]).0 // gives a pointer to Data above (really the same pointer)
579- // vtable = (*args[0]).1 // loads the vtable out
580- // (data, vtable) // an equivalent Rust `*mut dyn Trait`
581- //
582- // SO THEN WE CAN USE THE ABOVE CODE.
583- let virtual_drop = Instance {
584- def : ty:: InstanceDef :: Virtual ( drop_fn. def_id ( ) , 0 ) , // idx 0: the drop function
585- args : drop_fn. args ,
586- } ;
587- debug ! ( "ty = {:?}" , ty) ;
588- debug ! ( "drop_fn = {:?}" , drop_fn) ;
589- debug ! ( "args = {:?}" , args) ;
590- let fn_abi = bx. fn_abi_of_instance ( virtual_drop, ty:: List :: empty ( ) ) ;
591- let meta_ptr = place. project_field ( bx, 1 ) ;
592- let meta = bx. load_operand ( meta_ptr) ;
593- // Truncate vtable off of args list
594- args = & args[ ..1 ] ;
595- debug ! ( "args' = {:?}" , args) ;
596- (
597- meth:: VirtualIndex :: from_index ( ty:: COMMON_VTABLE_ENTRIES_DROPINPLACE )
598- . get_fn ( bx, meta. immediate ( ) , ty, fn_abi) ,
599- fn_abi,
600- virtual_drop,
601- )
602- }
603- _ => (
604- bx. get_fn_addr ( drop_fn) ,
605- bx. fn_abi_of_instance ( drop_fn, ty:: List :: empty ( ) ) ,
606- drop_fn,
607- ) ,
608- } ;
526+ let ( maybe_null, drop_fn, fn_abi, drop_instance) = match ty. kind ( ) {
527+ // FIXME(eddyb) perhaps move some of this logic into
528+ // `Instance::resolve_drop_in_place`?
529+ ty:: Dynamic ( _, _, ty:: Dyn ) => {
530+ // IN THIS ARM, WE HAVE:
531+ // ty = *mut (dyn Trait)
532+ // which is: exists<T> ( *mut T, Vtable<T: Trait> )
533+ // args[0] args[1]
534+ //
535+ // args = ( Data, Vtable )
536+ // |
537+ // v
538+ // /-------\
539+ // | ... |
540+ // \-------/
541+ //
542+ let virtual_drop = Instance {
543+ def : ty:: InstanceDef :: Virtual ( drop_fn. def_id ( ) , 0 ) , // idx 0: the drop function
544+ args : drop_fn. args ,
545+ } ;
546+ debug ! ( "ty = {:?}" , ty) ;
547+ debug ! ( "drop_fn = {:?}" , drop_fn) ;
548+ debug ! ( "args = {:?}" , args) ;
549+ let fn_abi = bx. fn_abi_of_instance ( virtual_drop, ty:: List :: empty ( ) ) ;
550+ let vtable = args[ 1 ] ;
551+ // Truncate vtable off of args list
552+ args = & args[ ..1 ] ;
553+ (
554+ true ,
555+ meth:: VirtualIndex :: from_index ( ty:: COMMON_VTABLE_ENTRIES_DROPINPLACE )
556+ . get_optional_fn ( bx, vtable, ty, fn_abi) ,
557+ fn_abi,
558+ virtual_drop,
559+ )
560+ }
561+ ty:: Dynamic ( _, _, ty:: DynStar ) => {
562+ // IN THIS ARM, WE HAVE:
563+ // ty = *mut (dyn* Trait)
564+ // which is: *mut exists<T: sizeof(T) == sizeof(usize)> (T, Vtable<T: Trait>)
565+ //
566+ // args = [ * ]
567+ // |
568+ // v
569+ // ( Data, Vtable )
570+ // |
571+ // v
572+ // /-------\
573+ // | ... |
574+ // \-------/
575+ //
576+ //
577+ // WE CAN CONVERT THIS INTO THE ABOVE LOGIC BY DOING
578+ //
579+ // data = &(*args[0]).0 // gives a pointer to Data above (really the same pointer)
580+ // vtable = (*args[0]).1 // loads the vtable out
581+ // (data, vtable) // an equivalent Rust `*mut dyn Trait`
582+ //
583+ // SO THEN WE CAN USE THE ABOVE CODE.
584+ let virtual_drop = Instance {
585+ def : ty:: InstanceDef :: Virtual ( drop_fn. def_id ( ) , 0 ) , // idx 0: the drop function
586+ args : drop_fn. args ,
587+ } ;
588+ debug ! ( "ty = {:?}" , ty) ;
589+ debug ! ( "drop_fn = {:?}" , drop_fn) ;
590+ debug ! ( "args = {:?}" , args) ;
591+ let fn_abi = bx. fn_abi_of_instance ( virtual_drop, ty:: List :: empty ( ) ) ;
592+ let meta_ptr = place. project_field ( bx, 1 ) ;
593+ let meta = bx. load_operand ( meta_ptr) ;
594+ // Truncate vtable off of args list
595+ args = & args[ ..1 ] ;
596+ debug ! ( "args' = {:?}" , args) ;
597+ (
598+ true ,
599+ meth:: VirtualIndex :: from_index ( ty:: COMMON_VTABLE_ENTRIES_DROPINPLACE )
600+ . get_optional_fn ( bx, meta. immediate ( ) , ty, fn_abi) ,
601+ fn_abi,
602+ virtual_drop,
603+ )
604+ }
605+ _ => (
606+ false ,
607+ bx. get_fn_addr ( drop_fn) ,
608+ bx. fn_abi_of_instance ( drop_fn, ty:: List :: empty ( ) ) ,
609+ drop_fn,
610+ ) ,
611+ } ;
612+
613+ // We generate a null check for the drop_fn. This saves a bunch of relocations being
614+ // generated for no-op drops.
615+ if maybe_null {
616+ let is_not_null = bx. append_sibling_block ( "is_not_null" ) ;
617+ let llty = bx. fn_ptr_backend_type ( fn_abi) ;
618+ let null = bx. const_null ( llty) ;
619+ let non_null = bx. icmp (
620+ base:: bin_op_to_icmp_predicate ( mir:: BinOp :: Ne . to_hir_binop ( ) , false ) ,
621+ drop_fn,
622+ null,
623+ ) ;
624+ bx. cond_br ( non_null, is_not_null, self . llbb ( target) ) ;
625+ bx. switch_to_block ( is_not_null) ;
626+ self . set_debug_loc ( bx, * source_info) ;
627+ }
628+
609629 helper. do_call (
610630 self ,
611631 bx,
@@ -616,7 +636,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
616636 unwind,
617637 & [ ] ,
618638 Some ( drop_instance) ,
619- mergeable_succ,
639+ !maybe_null && mergeable_succ,
620640 )
621641 }
622642
@@ -1345,9 +1365,16 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
13451365 MergingSucc :: False
13461366 }
13471367
1348- mir:: TerminatorKind :: Drop { place, target, unwind, replace : _ } => {
1349- self . codegen_drop_terminator ( helper, bx, place, target, unwind, mergeable_succ ( ) )
1350- }
1368+ mir:: TerminatorKind :: Drop { place, target, unwind, replace : _ } => self
1369+ . codegen_drop_terminator (
1370+ helper,
1371+ bx,
1372+ & terminator. source_info ,
1373+ place,
1374+ target,
1375+ unwind,
1376+ mergeable_succ ( ) ,
1377+ ) ,
13511378
13521379 mir:: TerminatorKind :: Assert { ref cond, expected, ref msg, target, unwind } => self
13531380 . codegen_assert_terminator (
0 commit comments