LValue CGObjCRuntime::EmitValueForIvarAtOffset(CodeGen::CodeGenFunction &CGF, const ObjCInterfaceDecl *OID, llvm::Value *BaseValue, const ObjCIvarDecl *Ivar, unsigned CVRQualifiers, llvm::Value *Offset) { // Compute (type*) ( (char *) BaseValue + Offset) QualType IvarTy = Ivar->getType(); llvm::Type *LTy = CGF.CGM.getTypes().ConvertTypeForMem(IvarTy); llvm::Value *V = CGF.Builder.CreateBitCast(BaseValue, CGF.Int8PtrTy); V = CGF.Builder.CreateInBoundsGEP(V, Offset, "add.ptr"); if (!Ivar->isBitField()) { V = CGF.Builder.CreateBitCast(V, llvm::PointerType::getUnqual(LTy)); LValue LV = CGF.MakeNaturalAlignAddrLValue(V, IvarTy); LV.getQuals().addCVRQualifiers(CVRQualifiers); return LV; } // We need to compute an access strategy for this bit-field. We are given the // offset to the first byte in the bit-field, the sub-byte offset is taken // from the original layout. We reuse the normal bit-field access strategy by // treating this as an access to a struct where the bit-field is in byte 0, // and adjust the containing type size as appropriate. // // FIXME: Note that currently we make a very conservative estimate of the // alignment of the bit-field, because (a) it is not clear what guarantees the // runtime makes us, and (b) we don't have a way to specify that the struct is // at an alignment plus offset. // // Note, there is a subtle invariant here: we can only call this routine on // non-synthesized ivars but we may be called for synthesized ivars. However, // a synthesized ivar can never be a bit-field, so this is safe. uint64_t FieldBitOffset = LookupFieldBitOffset(CGF.CGM, OID, nullptr, Ivar); uint64_t BitOffset = FieldBitOffset % CGF.CGM.getContext().getCharWidth(); uint64_t AlignmentBits = CGF.CGM.getTarget().getCharAlign(); uint64_t BitFieldSize = Ivar->getBitWidthValue(CGF.getContext()); CharUnits StorageSize = CGF.CGM.getContext().toCharUnitsFromBits( llvm::RoundUpToAlignment(BitOffset + BitFieldSize, AlignmentBits)); CharUnits Alignment = CGF.CGM.getContext().toCharUnitsFromBits(AlignmentBits); // Allocate a new CGBitFieldInfo object to describe this access. // // FIXME: This is incredibly wasteful, these should be uniqued or part of some // layout object. However, this is blocked on other cleanups to the // Objective-C code, so for now we just live with allocating a bunch of these // objects. CGBitFieldInfo *Info = new (CGF.CGM.getContext()) CGBitFieldInfo( CGBitFieldInfo::MakeInfo(CGF.CGM.getTypes(), Ivar, BitOffset, BitFieldSize, CGF.CGM.getContext().toBits(StorageSize), CharUnits::fromQuantity(0))); V = CGF.Builder.CreateBitCast(V, llvm::Type::getIntNPtrTy(CGF.getLLVMContext(), Info->StorageSize)); return LValue::MakeBitfield(V, *Info, IvarTy.withCVRQualifiers(CVRQualifiers), Alignment); }
CodeGen::RValue CGObjCJit::EmitMessageSend(CodeGen::CodeGenFunction &CGF, ReturnValueSlot Return, QualType ResultType, Selector Sel, llvm::Value *Arg0, llvm::Value *Arg0Class, const CallArgList &CallArgs, const ObjCMethodDecl *Method) { llvm::Value *Arg1 = GetSelector(CGF, Sel); CallArgList ActualArgs; ActualArgs.add(RValue::get(Arg0), CGF.getContext().getObjCIdType()); ActualArgs.add(RValue::get(Arg1), CGF.getContext().getObjCSelType()); ActualArgs.addFrom(CallArgs); if (Method) assert(CGM.getContext().getCanonicalType(Method->getResultType()) == CGM.getContext().getCanonicalType(ResultType) && "Result type mismatch!"); // Perform the following: // imp = class_getMethodImplementation( Arg0Class, Arg1 ); // (*imp)( Arg0, Arg1, CallArgs ); llvm::CallInst *getImp; // Unfortunately, using the GNU runtime version of // class_getMethodImplementation and then calling the resulting // IMP doesn't work unless objc_msg_lookup was already // called first. TODO: avoid doing this every time // if (fn_objc_msg_lookup.isValid()) { getImp = CGF.Builder.CreateCall2(fn_objc_msg_lookup, Arg0, Arg1); } else { // use the universal way getImp = CGF.Builder.CreateCall2(fn_class_getMethodImplementation, Arg0Class, Arg1); } MessageSendInfo MSI = getMessageSendInfo(Method, ResultType, ActualArgs); llvm::Value *theImp = CGF.Builder.CreateBitCast(getImp, MSI.MessengerType); return CGF.EmitCall(MSI.CallInfo, theImp, Return, ActualArgs); }