@@ -2651,35 +2651,6 @@ CGObjCGNU::GenerateMessageSend(CodeGenFunction &CGF,
2651
2651
}
2652
2652
}
2653
2653
2654
- // If the return type is something that goes in an integer register, the
2655
- // runtime will handle 0 returns. For other cases, we fill in the 0 value
2656
- // ourselves.
2657
- //
2658
- // The language spec says the result of this kind of message send is
2659
- // undefined, but lots of people seem to have forgotten to read that
2660
- // paragraph and insist on sending messages to nil that have structure
2661
- // returns. With GCC, this generates a random return value (whatever happens
2662
- // to be on the stack / in those registers at the time) on most platforms,
2663
- // and generates an illegal instruction trap on SPARC. With LLVM it corrupts
2664
- // the stack.
2665
- bool isPointerSizedReturn = (ResultType->isAnyPointerType () ||
2666
- ResultType->isIntegralOrEnumerationType () || ResultType->isVoidType ());
2667
-
2668
- llvm::BasicBlock *startBB = nullptr ;
2669
- llvm::BasicBlock *messageBB = nullptr ;
2670
- llvm::BasicBlock *continueBB = nullptr ;
2671
-
2672
- if (!isPointerSizedReturn) {
2673
- startBB = Builder.GetInsertBlock ();
2674
- messageBB = CGF.createBasicBlock (" msgSend" );
2675
- continueBB = CGF.createBasicBlock (" continue" );
2676
-
2677
- llvm::Value *isNil = Builder.CreateICmpEQ (Receiver,
2678
- llvm::Constant::getNullValue (Receiver->getType ()));
2679
- Builder.CreateCondBr (isNil, continueBB, messageBB);
2680
- CGF.EmitBlock (messageBB);
2681
- }
2682
-
2683
2654
IdTy = cast<llvm::PointerType>(CGM.getTypes ().ConvertType (ASTIdTy));
2684
2655
llvm::Value *cmd;
2685
2656
if (Method)
@@ -2703,6 +2674,96 @@ CGObjCGNU::GenerateMessageSend(CodeGenFunction &CGF,
2703
2674
2704
2675
MessageSendInfo MSI = getMessageSendInfo (Method, ResultType, ActualArgs);
2705
2676
2677
+ // Message sends are expected to return a zero value when the
2678
+ // receiver is nil. At one point, this was only guaranteed for
2679
+ // simple integer and pointer types, but expectations have grown
2680
+ // over time.
2681
+ //
2682
+ // Given a nil receiver, the GNU runtime's message lookup will
2683
+ // return a stub function that simply sets various return-value
2684
+ // registers to zero and then returns. That's good enough for us
2685
+ // if and only if (1) the calling conventions of that stub are
2686
+ // compatible with the signature we're using and (2) the registers
2687
+ // it sets are sufficient to produce a zero value of the return type.
2688
+ // Rather than doing a whole target-specific analysis, we assume it
2689
+ // only works for void, integer, and pointer types, and in all
2690
+ // other cases we do an explicit nil check is emitted code. In
2691
+ // addition to ensuring we produe a zero value for other types, this
2692
+ // sidesteps the few outright CC incompatibilities we know about that
2693
+ // could otherwise lead to crashes, like when a method is expected to
2694
+ // return on the x87 floating point stack or adjust the stack pointer
2695
+ // because of an indirect return.
2696
+ bool hasParamDestroyedInCallee = false ;
2697
+ bool requiresExplicitZeroResult = false ;
2698
+ bool requiresNilReceiverCheck = [&] {
2699
+ // We never need a check if we statically know the receiver isn't nil.
2700
+ if (!canMessageReceiverBeNull (CGF, Method, /* IsSuper*/ false ,
2701
+ Class, Receiver))
2702
+ return false ;
2703
+
2704
+ // If there's a consumed argument, we need a nil check.
2705
+ if (Method && Method->hasParamDestroyedInCallee ()) {
2706
+ hasParamDestroyedInCallee = true ;
2707
+ }
2708
+
2709
+ // If the return value isn't flagged as unused, and the result
2710
+ // type isn't in our narrow set where we assume compatibility,
2711
+ // we need a nil check to ensure a nil value.
2712
+ if (!Return.isUnused ()) {
2713
+ if (ResultType->isVoidType ()) {
2714
+ // void results are definitely okay.
2715
+ } else if (ResultType->hasPointerRepresentation () &&
2716
+ CGM.getTypes ().isZeroInitializable (ResultType)) {
2717
+ // Pointer types should be fine as long as they have
2718
+ // bitwise-zero null pointers. But do we need to worry
2719
+ // about unusual address spaces?
2720
+ } else if (ResultType->isIntegralOrEnumerationType ()) {
2721
+ // Bitwise zero should always be zero for integral types.
2722
+ // FIXME: we probably need a size limit here, but we've
2723
+ // never imposed one before
2724
+ } else {
2725
+ // Otherwise, use an explicit check just to be sure.
2726
+ requiresExplicitZeroResult = true ;
2727
+ }
2728
+ }
2729
+
2730
+ return hasParamDestroyedInCallee || requiresExplicitZeroResult;
2731
+ }();
2732
+
2733
+ // We will need to explicitly zero-initialize an aggregate result slot
2734
+ // if we generally require explicit zeroing and we have an aggregate
2735
+ // result.
2736
+ bool requiresExplicitAggZeroing =
2737
+ requiresExplicitZeroResult && CGF.hasAggregateEvaluationKind (ResultType);
2738
+
2739
+ // The block we're going to end up in after any message send or nil path.
2740
+ llvm::BasicBlock *continueBB = nullptr ;
2741
+ // The block that eventually branched to continueBB along the nil path.
2742
+ llvm::BasicBlock *nilPathBB = nullptr ;
2743
+ // The block to do explicit work in along the nil path, if necessary.
2744
+ llvm::BasicBlock *nilCleanupBB = nullptr ;
2745
+
2746
+ // Emit the nil-receiver check.
2747
+ if (requiresNilReceiverCheck) {
2748
+ llvm::BasicBlock *messageBB = CGF.createBasicBlock (" msgSend" );
2749
+ continueBB = CGF.createBasicBlock (" continue" );
2750
+
2751
+ // If we need to zero-initialize an aggregate result or destroy
2752
+ // consumed arguments, we'll need a separate cleanup block.
2753
+ // Otherwise we can just branch directly to the continuation block.
2754
+ if (requiresExplicitAggZeroing || hasParamDestroyedInCallee) {
2755
+ nilCleanupBB = CGF.createBasicBlock (" nilReceiverCleanup" );
2756
+ } else {
2757
+ nilPathBB = Builder.GetInsertBlock ();
2758
+ }
2759
+
2760
+ llvm::Value *isNil = Builder.CreateICmpEQ (Receiver,
2761
+ llvm::Constant::getNullValue (Receiver->getType ()));
2762
+ Builder.CreateCondBr (isNil, nilCleanupBB ? nilCleanupBB : continueBB,
2763
+ messageBB);
2764
+ CGF.EmitBlock (messageBB);
2765
+ }
2766
+
2706
2767
// Get the IMP to call
2707
2768
llvm::Value *imp;
2708
2769
@@ -2744,36 +2805,48 @@ CGObjCGNU::GenerateMessageSend(CodeGenFunction &CGF,
2744
2805
RValue msgRet = CGF.EmitCall (MSI.CallInfo , callee, Return, ActualArgs, &call);
2745
2806
call->setMetadata (msgSendMDKind, node);
2746
2807
2747
-
2748
- if (!isPointerSizedReturn) {
2749
- messageBB = CGF.Builder .GetInsertBlock ();
2808
+ if (requiresNilReceiverCheck) {
2809
+ llvm::BasicBlock *nonNilPathBB = CGF.Builder .GetInsertBlock ();
2750
2810
CGF.Builder .CreateBr (continueBB);
2811
+
2812
+ // Emit the nil path if we decided it was necessary above.
2813
+ if (nilCleanupBB) {
2814
+ CGF.EmitBlock (nilCleanupBB);
2815
+
2816
+ if (hasParamDestroyedInCallee) {
2817
+ destroyCalleeDestroyedArguments (CGF, Method, CallArgs);
2818
+ }
2819
+
2820
+ if (requiresExplicitAggZeroing) {
2821
+ assert (msgRet.isAggregate ());
2822
+ Address addr = msgRet.getAggregateAddress ();
2823
+ CGF.EmitNullInitialization (addr, ResultType);
2824
+ }
2825
+
2826
+ nilPathBB = CGF.Builder .GetInsertBlock ();
2827
+ CGF.Builder .CreateBr (continueBB);
2828
+ }
2829
+
2830
+ // Enter the continuation block and emit a phi if required.
2751
2831
CGF.EmitBlock (continueBB);
2752
2832
if (msgRet.isScalar ()) {
2753
2833
llvm::Value *v = msgRet.getScalarVal ();
2754
2834
llvm::PHINode *phi = Builder.CreatePHI (v->getType (), 2 );
2755
- phi->addIncoming (v, messageBB );
2756
- phi->addIncoming (llvm::Constant::getNullValue (v-> getType ()), startBB );
2835
+ phi->addIncoming (v, nonNilPathBB );
2836
+ phi->addIncoming (CGM. EmitNullConstant (ResultType), nilPathBB );
2757
2837
msgRet = RValue::get (phi);
2758
2838
} else if (msgRet.isAggregate ()) {
2759
- Address v = msgRet.getAggregateAddress ();
2760
- llvm::PHINode *phi = Builder.CreatePHI (v.getType (), 2 );
2761
- llvm::Type *RetTy = v.getElementType ();
2762
- Address NullVal = CGF.CreateTempAlloca (RetTy, v.getAlignment (), " null" );
2763
- CGF.InitTempAlloca (NullVal, llvm::Constant::getNullValue (RetTy));
2764
- phi->addIncoming (v.getPointer (), messageBB);
2765
- phi->addIncoming (NullVal.getPointer (), startBB);
2766
- msgRet = RValue::getAggregate (Address (phi, v.getAlignment ()));
2839
+ // Aggregate zeroing is handled in nilCleanupBB when it's required.
2767
2840
} else /* isComplex() */ {
2768
2841
std::pair<llvm::Value*,llvm::Value*> v = msgRet.getComplexVal ();
2769
2842
llvm::PHINode *phi = Builder.CreatePHI (v.first ->getType (), 2 );
2770
- phi->addIncoming (v.first , messageBB );
2843
+ phi->addIncoming (v.first , nonNilPathBB );
2771
2844
phi->addIncoming (llvm::Constant::getNullValue (v.first ->getType ()),
2772
- startBB );
2845
+ nilPathBB );
2773
2846
llvm::PHINode *phi2 = Builder.CreatePHI (v.second ->getType (), 2 );
2774
- phi2->addIncoming (v.second , messageBB );
2847
+ phi2->addIncoming (v.second , nonNilPathBB );
2775
2848
phi2->addIncoming (llvm::Constant::getNullValue (v.second ->getType ()),
2776
- startBB );
2849
+ nilPathBB );
2777
2850
msgRet = RValue::getComplex (phi, phi2);
2778
2851
}
2779
2852
}
0 commit comments