static uint64_t LookupFieldBitOffset(CodeGen::CodeGenModule &CGM, const ObjCInterfaceDecl *OID, const ObjCImplementationDecl *ID, const ObjCIvarDecl *Ivar) { const ObjCInterfaceDecl *Container = Ivar->getContainingInterface(); // FIXME: We should eliminate the need to have ObjCImplementationDecl passed // in here; it should never be necessary because that should be the lexical // decl context for the ivar. // If we know have an implementation (and the ivar is in it) then // look up in the implementation layout. const ASTRecordLayout *RL; if (ID && ID->getClassInterface() == Container) RL = &CGM.getContext().getASTObjCImplementationLayout(ID); else RL = &CGM.getContext().getASTObjCInterfaceLayout(Container); // Compute field index. // // FIXME: The index here is closely tied to how ASTContext::getObjCLayout is // implemented. This should be fixed to get the information from the layout // directly. unsigned Index = 0; for (const ObjCIvarDecl *IVD = Container->all_declared_ivar_begin(); IVD; IVD = IVD->getNextIvar()) { if (Ivar == IVD) break; ++Index; } assert(Index < RL->getFieldCount() && "Ivar is not inside record layout!"); return RL->getFieldOffset(Index); }
uint64_t CGObjCRuntime::ComputeIvarBaseOffset(CodeGen::CodeGenModule &CGM, const ObjCImplementationDecl *OID, const ObjCIvarDecl *Ivar) { return LookupFieldBitOffset(CGM, OID->getClassInterface(), OID, Ivar) / CGM.getContext().getCharWidth(); }
CGObjCJit::CGObjCJit(CodeGen::CodeGenModule &cgm) : CGObjCRuntime(cgm), isUsable(false), CGM(cgm), VMContext(cgm.getLLVMContext()), ObjCTypes(cgm), JitInitFunction(0) { //puts("Constructing CGObjCJit (host runtime proxy)"); llvm::PointerType *PtrToInt8Ty = llvm::Type::getInt8Ty(VMContext)->getPointerTo(); NULLPtr = llvm::ConstantPointerNull::get(PtrToInt8Ty); // TODO: For now, just searching for pre-loaded objc runtime LOAD_FN(_objc_getClass, "objc_getClass"); // Don't bother to try the rest if the first one wasn't available if (_objc_getClass) { isUsable = true; LOAD_FN(_objc_allocateClassPair, "objc_allocateClassPair"); LOAD_FN(_objc_registerClassPair, "objc_registerClassPair"); LOAD_FN(_objc_getProtocol, "objc_getProtocol"); LOAD_FN(_object_getClass, "object_getClass"); LOAD_FN(_sel_registerName, "sel_registerName"); LOAD_FN(_class_getClassVariable, "class_getClassVariable"); LOAD_FN(_class_addIvar, "class_addIvar"); LOAD_FN(_class_addProtocol, "class_addProtocol"); LOAD_FN(_class_getMethodImplementation, "class_getMethodImplementation"); LOAD_FN(_ivar_getOffset, "ivar_getOffset"); LOAD_FN(_NSGetSizeAndAlignment, "NSGetSizeAndAlignment"); //puts("Creating .objc_jit_init()"); llvm::FunctionType *initFuncType = llvm::FunctionType::get(llvm::Type::getVoidTy(VMContext), false); JitInitFunction = cast<llvm::Function>(CGM.getModule().getOrInsertFunction( llvm::StringRef(".objc_jit_init"), initFuncType)); JitInitFunction->setLinkage(llvm::Function::PrivateLinkage); JitInitFunction->setCallingConv(llvm::CallingConv::C); JitInitBlock = llvm::BasicBlock::Create(VMContext, "entry", JitInitFunction); // Define VM objc_getClass function fn_objc_getClass.init(&CGM, "objc_getClass", ObjCTypes.ClassPtrTy, ObjCTypes.Int8PtrTy, NULL); fn_objc_getMetaClass.init(&CGM, "objc_getMetaClass", ObjCTypes.ClassPtrTy, ObjCTypes.Int8PtrTy, NULL); fn_objc_getProtocol.init(&CGM, "objc_getProtocol", ObjCTypes.ProtocolPtrTy, ObjCTypes.Int8PtrTy, NULL); fn_object_getClass.init(&CGM, "object_getClass", ObjCTypes.ClassPtrTy, ObjCTypes.ObjectPtrTy, NULL); // Define VM class_addMethod and class_replaceMethod function calls for // the init function llvm::Type *ImpParams[] = {ObjCTypes.ObjectPtrTy, ObjCTypes.SelectorPtrTy}; ImpPtrTy = llvm::FunctionType::get(ObjCTypes.ObjectPtrTy, ImpParams, false)->getPointerTo(); fn_class_addMethod.init(&CGM, "class_addMethod", llvm::Type::getInt8Ty(VMContext), ObjCTypes.ClassPtrTy, ObjCTypes.SelectorPtrTy, ImpPtrTy, ObjCTypes.Int8PtrTy, NULL); fn_class_replaceMethod.init(&CGM, "class_replaceMethod", llvm::Type::getInt8Ty(VMContext), ObjCTypes.ClassTy, ObjCTypes.SelectorPtrTy, ImpPtrTy, ObjCTypes.Int8PtrTy, NULL); fn_class_getMethodImplementation.init(&CGM, "class_getMethodImplementation", ImpPtrTy, ObjCTypes.ClassPtrTy, ObjCTypes.SelectorPtrTy, NULL); // Unfortunately, even though class_getMethodImplementation is provided by // the GNU runtime, it doesn't work on a class unless objc_msg_lookup was // called first. // LOAD_FN(_objc_msg_lookup, "objc_msg_lookup"); if (_objc_msg_lookup) { fn_objc_msg_lookup.init(&CGM, "objc_msg_lookup", ImpPtrTy, ObjCTypes.ClassPtrTy, ObjCTypes.SelectorPtrTy, NULL); } // Save 'isa' pointer value used for locally-stored prototypes void *sampleProtocol = _objc_getProtocol("NSObject"); ProtocolIsaPointer = *((void**)sampleProtocol); InitConstantStringGenerator(); } }
uint64_t CGObjCRuntime::ComputeIvarBaseOffset(CodeGen::CodeGenModule &CGM, const ObjCInterfaceDecl *OID, const ObjCIvarDecl *Ivar) { return LookupFieldBitOffset(CGM, OID, nullptr, Ivar) / CGM.getContext().getCharWidth(); }