//===--- GenObjC.cpp - Objective-C interaction ----------------------------===// // // This source file is part of the Swift.org open source project // // Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information // See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors // //===----------------------------------------------------------------------===// // // This file implements bridging to Objective-C. // //===----------------------------------------------------------------------===// #include "llvm/ADT/SmallString.h" #include "llvm/IR/DerivedTypes.h" #include "llvm/IR/Module.h" #include "swift/IRGen/Options.h" #include "swift/AST/Attr.h" #include "swift/AST/Decl.h" #include "swift/AST/Types.h" #include "clang/AST/Attr.h" #include "clang/AST/DeclObjC.h" #include "ASTVisitor.h" #include "CallEmission.h" #include "Cleanup.h" #include "Explosion.h" #include "FixedTypeInfo.h" #include "FormalType.h" #include "FunctionRef.h" #include "GenClass.h" #include "GenFunc.h" #include "GenMeta.h" #include "GenType.h" #include "HeapTypeInfo.h" #include "IRGenFunction.h" #include "IRGenModule.h" #include "Linking.h" #include "ScalarTypeInfo.h" #include "TypeVisitor.h" #include "GenObjC.h" using namespace swift; using namespace irgen; /// Create an Objective-C runtime function. The ObjC runtime uses the /// standard C conventions. static llvm::Constant *createObjCRuntimeFunction(IRGenModule &IGM, StringRef name, llvm::FunctionType *fnType) { llvm::Constant *addr = IGM.Module.getOrInsertFunction(name, fnType); return addr; } namespace { template llvm::Constant *getObjCSendFn(IRGenModule &IGM) { if (IGM.*FIELD) return IGM.*FIELD; // We use a totally bogus signature to make sure we *always* cast. llvm::FunctionType *fnType = llvm::FunctionType::get(IGM.VoidTy, ArrayRef(), false); IGM.*FIELD = createObjCRuntimeFunction(IGM, NAME, fnType); return IGM.*FIELD; } // T objc_msgSend(id, SEL*, U...); static const char objc_msgSend_name[] = "objc_msgSend"; // void objc_msgSend_stret([[sret]] T *, id, SEL, U...); static const char objc_msgSend_stret_name[] = "objc_msgSend_stret"; // T objc_msgSendSuper2(struct objc_super *, SEL, U...); static const char objc_msgSendSuper_name[] = "objc_msgSendSuper2"; // void objc_msgSendSuper2_stret([[sret]] T *, struct objc_super *, SEL, U...); static const char objc_msgSendSuper_stret_name[] = "objc_msgSendSuper2_stret"; } // end anonymous namespace llvm::Constant *IRGenModule::getObjCMsgSendFn() { return getObjCSendFn<&IRGenModule::ObjCMsgSendFn, objc_msgSend_name>(*this); } llvm::Constant *IRGenModule::getObjCMsgSendStretFn() { return getObjCSendFn<&IRGenModule::ObjCMsgSendStretFn, objc_msgSend_stret_name>(*this); } llvm::Constant *IRGenModule::getObjCMsgSendSuperFn() { return getObjCSendFn<&IRGenModule::ObjCMsgSendSuperFn, objc_msgSendSuper_name>(*this); } llvm::Constant *IRGenModule::getObjCMsgSendSuperStretFn() { return getObjCSendFn<&IRGenModule::ObjCMsgSendSuperStretFn, objc_msgSendSuper_stret_name>(*this); } llvm::Constant *IRGenModule::getObjCSelRegisterNameFn() { if (ObjCSelRegisterNameFn) return ObjCSelRegisterNameFn; // SEL sel_registerName(const char *str); llvm::Type *argTypes[1] = { Int8PtrTy }; auto fnType = llvm::FunctionType::get(ObjCSELTy, argTypes, false); ObjCSelRegisterNameFn = createObjCRuntimeFunction(*this, "sel_registerName", fnType); return ObjCSelRegisterNameFn; } #define DEFINE_OBJC_RUNTIME_FUNCTION(LABEL, NAME, RETTY) \ llvm::Constant *IRGenModule::getObjC##LABEL##Fn() { \ if (ObjC##LABEL##Fn) return ObjC##LABEL##Fn; \ \ llvm::FunctionType *fnType = \ llvm::FunctionType::get(RETTY, ObjCPtrTy, false); \ ObjC##LABEL##Fn = createObjCRuntimeFunction(*this, NAME, fnType); \ return ObjC##LABEL##Fn; \ } DEFINE_OBJC_RUNTIME_FUNCTION(Retain, "objc_retain", ObjCPtrTy) DEFINE_OBJC_RUNTIME_FUNCTION(RetainAutoreleasedReturnValue, "objc_retainAutoreleasedReturnValue", ObjCPtrTy) DEFINE_OBJC_RUNTIME_FUNCTION(Release, "objc_release", VoidTy) DEFINE_OBJC_RUNTIME_FUNCTION(AutoreleaseReturnValue, "objc_autoreleaseReturnValue", ObjCPtrTy); void IRGenFunction::emitObjCRelease(llvm::Value *value) { // Get an appropriately-casted function pointer. auto fn = IGM.getObjCReleaseFn(); if (value->getType() != IGM.ObjCPtrTy) { auto fnTy = llvm::FunctionType::get(IGM.VoidTy, value->getType(), false)->getPointerTo(); fn = llvm::ConstantExpr::getBitCast(fn, fnTy); } auto call = Builder.CreateCall(fn, value); call->setDoesNotThrow(); } /// Given a function of type %objc* (%objc*)*, cast it as appropriate /// to be used with values of type T. static llvm::Constant *getCastOfRetainFn(IRGenModule &IGM, llvm::Constant *fn, llvm::Type *valueTy) { #ifndef NDEBUG auto origFnTy = cast(fn->getType()->getPointerElementType()); assert(origFnTy->getReturnType() == IGM.ObjCPtrTy); assert(origFnTy->getNumParams() == 1); assert(origFnTy->getParamType(0) == IGM.ObjCPtrTy); assert(isa(valueTy)); #endif if (valueTy == IGM.ObjCPtrTy) return fn; auto fnTy = llvm::FunctionType::get(valueTy, valueTy, false); return llvm::ConstantExpr::getBitCast(fn, fnTy->getPointerTo(0)); } llvm::Value *IRGenFunction::emitObjCRetainCall(llvm::Value *value) { // Get an appropriately-casted function pointer. auto fn = IGM.getObjCRetainFn(); fn = getCastOfRetainFn(IGM, fn, value->getType()); auto call = Builder.CreateCall(fn, value); call->setDoesNotThrow(); return call; } /// Reclaim an autoreleased return value. llvm::Value *irgen::emitObjCRetainAutoreleasedReturnValue(IRGenFunction &IGF, llvm::Value *value) { auto fn = IGF.IGM.getObjCRetainAutoreleasedReturnValueFn(); fn = getCastOfRetainFn(IGF.IGM, fn, value->getType()); auto call = IGF.Builder.CreateCall(fn, value); call->setDoesNotThrow(); return call; } /// Autorelease a return value. static llvm::Value *emitObjCAutoreleaseReturnValue(IRGenFunction &IGF, llvm::Value *value) { auto fn = IGF.IGM.getObjCAutoreleaseReturnValueFn(); fn = getCastOfRetainFn(IGF.IGM, fn, value->getType()); auto call = IGF.Builder.CreateCall(fn, value); call->setDoesNotThrow(); call->setTailCall(); // force tail calls at -O0 return call; } namespace { struct CallObjCRelease : Cleanup { llvm::Value *Value; CallObjCRelease(llvm::Value *value) : Value(value) {} void emit(IRGenFunction &IGF) const { IGF.emitObjCRelease(Value); } }; } ManagedValue IRGenFunction::enterObjCReleaseCleanup(llvm::Value *value) { pushFullExprCleanup(value); return ManagedValue(value, getCleanupsDepth()); } namespace { /// A type-info implementation suitable for an ObjC pointer type. class ObjCTypeInfo : public HeapTypeInfo { public: ObjCTypeInfo(llvm::PointerType *storageType, Size size, Alignment align) : HeapTypeInfo(storageType, size, align) { } /// Builtin.ObjCPointer requires ObjC reference-counting. bool hasSwiftRefcount() const { return false; } }; } const TypeInfo *TypeConverter::convertBuiltinObjCPointer() { return new ObjCTypeInfo(IGM.ObjCPtrTy, IGM.getPointerSize(), IGM.getPointerAlignment()); } /// Get or create a global Objective-C method name. Always returns an i8*. llvm::Constant *IRGenModule::getAddrOfObjCMethodName(StringRef selector) { // Check whether this selector already exists. auto &entry = ObjCMethodNames[selector]; if (entry) return entry; // If not, create it. This implicitly adds a trailing null. auto init = llvm::ConstantDataArray::getString(LLVMContext, selector); auto global = new llvm::GlobalVariable(Module, init->getType(), true, llvm::GlobalValue::InternalLinkage, init, llvm::Twine("\01L_selector_data(") + selector + ")"); global->setSection("__TEXT,__objc_methname,cstring_literals"); global->setAlignment(1); // Drill down to make an i8*. auto zero = llvm::ConstantInt::get(SizeTy, 0); llvm::Constant *indices[] = { zero, zero }; auto address = llvm::ConstantExpr::getInBoundsGetElementPtr(global, indices); // Cache and return. entry = address; return address; } /// Get or create an Objective-C selector reference. Always returns /// an i8**. The design is that the compiler will emit a load of this /// pointer, and the linker will ensure that that pointer is unique. llvm::Constant *IRGenModule::getAddrOfObjCSelectorRef(StringRef selector) { // Check whether a reference for this selector already exists. auto &entry = ObjCSelectorRefs[selector]; if (entry) return entry; // If not, create it. The initializer is just a pointer to the // method name. Note that the label here is unimportant, so we // choose something descriptive to make the IR readable. auto init = getAddrOfObjCMethodName(selector); auto global = new llvm::GlobalVariable(Module, init->getType(), false, llvm::GlobalValue::InternalLinkage, init, llvm::Twine("\01L_selector(") + selector + ")"); global->setAlignment(getPointerAlignment().getValue()); // This section name is magical for the Darwin static and dynamic linkers. global->setSection("__DATA,__objc_selrefs,literal_pointers,no_dead_strip"); // Make sure that this reference does not get optimized away. addUsedGlobal(global); // Cache and return. entry = global; return global; } /// Determine the natural limits on how we can call the given method /// using Objective-C method dispatch. AbstractCallee irgen::getAbstractObjCMethodCallee(IRGenFunction &IGF, ValueDecl *fn) { return AbstractCallee(AbstractCC::C, ExplosionKind::Minimal, /*minUncurry*/ 1, /*maxUncurry*/ 1, ExtraData::None); } namespace { struct ObjCMethodSignature { bool IsIndirectReturn; llvm::FunctionType *FnTy; CanType ResultType; llvm::AttributeSet Attrs; void addFormalArg(IRGenModule &IGM, CanType inputTy, SmallVectorImpl &argTys) { // This is a totally wrong and shameful hack, but it lets us pass // NSRect correctly. if (requiresExternalByvalArgument(IGM, inputTy)) { const TypeInfo &ti = IGM.getFragileTypeInfo(inputTy); llvm::Constant *alignConstant = ti.getStaticAlignment(IGM); unsigned alignValue = alignConstant ? alignConstant->getUniqueInteger().getZExtValue() : 1; addByvalArgumentAttributes(IGM, Attrs, argTys.size(), Alignment(alignValue)); argTys.push_back(ti.getStorageType()->getPointerTo()); } else { auto argSchema = IGM.getSchema(inputTy, ExplosionKind::Minimal); argSchema.addToArgTypes(IGM, argTys); } } ObjCMethodSignature(IRGenModule &IGM, CanType formalType, bool isSuper) { auto selfFnType = cast(formalType); auto formalFnType = cast(CanType(selfFnType->getResult())); llvm::Type *resultTy; SmallVector argTys; // Consider the result type first. ResultType = CanType(formalFnType->getResult()); if (auto ptrTy = requiresExternalIndirectResult(IGM, ResultType)) { IsIndirectReturn = true; resultTy = IGM.VoidTy; argTys.push_back(ptrTy); addIndirectReturnAttributes(IGM, Attrs); } else { IsIndirectReturn = false; auto resultSchema = IGM.getSchema(ResultType, ExplosionKind::Minimal); assert(!resultSchema.containsAggregate()); resultTy = resultSchema.getScalarResultType(IGM); } // Add the 'self' or 'super' argument. if (isSuper) argTys.push_back(IGM.ObjCSuperPtrTy); else argTys.push_back(IGM.getFragileType(CanType(selfFnType->getInput()))); // Add the _cmd argument. argTys.push_back(IGM.ObjCSELTy); // Add the formal arguments. CanType inputs(formalFnType->getInput()); if (TupleType *tuple = dyn_cast(inputs)) { for (const TupleTypeElt &field : tuple->getFields()) addFormalArg(IGM, CanType(field.getType()), argTys); } else addFormalArg(IGM, inputs, argTys); FnTy = llvm::FunctionType::get(resultTy, argTys, /*variadic*/ false); } }; class Selector { llvm::SmallString<80> Text; public: static constexpr struct ForGetter_t { } ForGetter{}; static constexpr struct ForSetter_t { } ForSetter{}; #define FOREACH_FAMILY(FAMILY) \ FAMILY(Alloc, "alloc") \ FAMILY(Copy, "copy") \ FAMILY(Init, "init") \ FAMILY(MutableCopy, "mutableCopy") \ FAMILY(New, "new") // Note that these are in parallel with 'prefixes', below. enum class Family { None, #define GET_LABEL(LABEL, PREFIX) LABEL, FOREACH_FAMILY(GET_LABEL) #undef GET_LABEL }; Selector() = default; Selector(FuncDecl *method) { method->getObjCSelector(Text); } Selector(ConstructorDecl *ctor) { ctor->getObjCSelector(Text); } Selector(ValueDecl *methodOrCtor) { if (auto *method = dyn_cast(methodOrCtor)) { method->getObjCSelector(Text); } else if (auto *ctor = dyn_cast(methodOrCtor)) { ctor->getObjCSelector(Text); } else { llvm_unreachable("property selector should be generated using ForGetter" " or ForSetter constructors"); } } Selector(VarDecl *property, ForGetter_t) { property->getObjCGetterSelector(Text); } Selector(VarDecl *property, ForSetter_t) { property->getObjCSetterSelector(Text); } StringRef str() const { return Text; } /// Return the family string of this selector. Family getFamily() const { StringRef text = str(); while (!text.empty() && text[0] == '_') text = text.substr(1); #define CHECK_PREFIX(LABEL, PREFIX) \ if (hasPrefix(text, PREFIX)) return Family::LABEL; FOREACH_FAMILY(CHECK_PREFIX) #undef CHECK_PREFIX return Family::None; } private: /// Does the given selector start with the given string as a /// prefix, in the sense of the selector naming conventions? static bool hasPrefix(StringRef text, StringRef prefix) { if (!text.startswith(prefix)) return false; if (text.size() == prefix.size()) return true; assert(text.size() > prefix.size()); return !islower(text[prefix.size()]); } #undef FOREACH_FAMILY }; /// A CRTP class for emitting an expression as an ObjC class /// reference. class ObjCClassEmitter : public irgen::ExprVisitor { IRGenFunction &IGF; typedef irgen::ExprVisitor super; public: ObjCClassEmitter(IRGenFunction &IGF) : IGF(IGF) {} llvm::Value *visit(Expr *E) { assert(E->getType()->is()); assert(E->getType()->castTo()->getInstanceType() ->getClassOrBoundGenericClass() != nullptr); return super::visit(E); } /// Look through metatype conversions. llvm::Value *visitMetatypeConversionExpr(MetatypeConversionExpr *E) { return visit(E->getSubExpr()); } llvm::Value *emitGetMetatype(Expr *base) { Explosion temp(ExplosionKind::Maximal); IGF.emitRValue(base, temp); auto value = temp.claimNext().getValue(); // let the cleanup happen auto baseType = base->getType()->getCanonicalType(); return emitHeapMetadataRefForHeapObject(IGF, value, baseType); } /// Special-case explicit .metatype expressions. llvm::Value *visitMetatypeExpr(MetatypeExpr *E) { // If there's a base, we need to evaluate it and then grab the // ObjC class for that. if (Expr *base = E->getBase()) { return emitGetMetatype(base); } // Otherwise, we need to emit a class reference. return emitClassHeapMetadataRef(IGF, getInstanceType(E)); } /// Special-case direct type references. llvm::Value *visitDeclRefExpr(DeclRefExpr *E) { assert(isa(E->getDecl())); auto typeDecl = cast(E->getDecl()); auto type = typeDecl->getDeclaredType()->getCanonicalType(); return emitClassHeapMetadataRef(IGF, type); } /// In the fallback case, emit as a swift metatype and remap it to /// an ObjC class type. llvm::Value *visitExpr(Expr *E) { Explosion temp(ExplosionKind::Maximal); IGF.emitRValue(E, temp); assert(temp.size() == 1); llvm::Value *metatype = temp.claimUnmanagedNext(); return emitClassHeapMetadataRefForMetatype(IGF, metatype, getInstanceType(E)); } /// Given an expression of metatype type, return the instance /// type of the metatype. static CanType getInstanceType(Expr *E) { auto type = E->getType()->getCanonicalType(); return CanType(cast(type)->getInstanceType()); } }; /// Ownership conventions derived from a Clang method declaration. class ObjCMethodConventions : public OwnershipConventions { clang::ObjCMethodDecl *Method; public: ObjCMethodConventions(clang::ObjCMethodDecl *method) : Method(method) {} bool isResultAutoreleased(IRGenModule &IGM, const Callee &callee) const override { return (Method->getResultType()->isObjCRetainableType() && !Method->hasAttr()); } void getConsumedArgs(IRGenModule &IGM, const Callee &callee, SmallVectorImpl &set) const override { // 'self' if (Method->hasAttr()) set.push_back(0); // Formal parameters. unsigned nextArgIndex = 2; unsigned methodParamIndex = 0; auto type = cast(callee.getOrigFormalType()); type = cast(CanType(type->getResult())); addConsumedArgs(IGM, callee, set, CanType(type->getInput()), nextArgIndex, methodParamIndex); } void addConsumedArgs(IRGenModule &IGM, const Callee &callee, SmallVectorImpl &set, CanType argType, unsigned &nextArgIndex, unsigned &methodParamIndex) const { if (auto tuple = dyn_cast(argType)) { for (auto &elt : tuple->getFields()) { addConsumedArgs(IGM, callee, set, CanType(elt.getType()), nextArgIndex, methodParamIndex); } return; } assert(methodParamIndex < Method->param_size()); auto param = *(Method->param_begin() + methodParamIndex); assert(param); if (param->hasAttr()) { set.push_back(nextArgIndex++); } else { nextArgIndex += IGM.getExplosionSize(argType, callee.getExplosionLevel()); } methodParamIndex++; } }; /// Ownership conventions derived from a selector family. class ObjCSelectorConventions : public OwnershipConventions { CanType SubstResultType; Selector::Family Family; public: ObjCSelectorConventions(CanType substResultType, Selector::Family family) : SubstResultType(substResultType), Family(family) {} bool isResultAutoreleased(IRGenModule &IGM, const Callee &callee) const override { // If the result type isn't a retainable object pointer, this // isn't applicable. if (!SubstResultType->getClassOrBoundGenericClass()) return false; switch (Family) { case Selector::Family::Alloc: case Selector::Family::Init: case Selector::Family::Copy: case Selector::Family::MutableCopy: case Selector::Family::New: return false; case Selector::Family::None: return true; } llvm_unreachable("bad selector family!"); } void getConsumedArgs(IRGenModule &IGM, const Callee &callee, SmallVectorImpl &set) const override { // The only conventionally-consumed argument is an init method's self. if (Family == Selector::Family::Init) set.push_back(0); } }; } /// Emit the given expression (of class-metatype type) as an /// Objective-C class reference. static void emitObjCClassRValue(IRGenFunction &IGF, Expr *E, Explosion &out) { out.addUnmanaged(ObjCClassEmitter(IGF).visit(E)); } /// Try to find a clang method declaration for the given function. static clang::ObjCMethodDecl *findClangMethod(ValueDecl *method) { if (FuncDecl *methodFn = dyn_cast(method)) { if (auto decl = methodFn->getClangDecl()) return cast(decl); if (auto overridden = methodFn->getOverriddenDecl()) return findClangMethod(overridden); } return nullptr; } /// Set the appropriate ownership conventions for an Objective-C /// method on the given callee. static const OwnershipConventions &setOwnershipConventions(Callee &callee, ValueDecl *method, const Selector &selector) { if (auto clangDecl = findClangMethod(method)) { callee.setOwnershipConventions(clangDecl); } else { auto substResultType = callee.getSubstResultType(); auto selectorFamily = selector.getFamily(); callee.setOwnershipConventions(substResultType, selectorFamily); } return callee.getOwnershipConventions(); } static void emitSelfArgument(IRGenFunction &IGF, bool isInstanceMethod, Expr *self, Explosion &selfValues) { if (isInstanceMethod) { IGF.emitRValue(self, selfValues); } else { emitObjCClassRValue(IGF, self, selfValues); } } static void emitSuperArgument(IRGenFunction &IGF, bool isInstanceMethod, ManagedValue selfValue, Explosion &selfValues, CanType searchClass) { // Allocate an objc_super struct. Address super = IGF.createAlloca(IGF.IGM.ObjCSuperStructTy, IGF.IGM.getPointerAlignment(), "objc_super"); llvm::Value *self = IGF.Builder.CreateBitCast(selfValue.getValue(), IGF.IGM.ObjCPtrTy); // Generate the search class object reference. llvm::Value *searchValue; if (isInstanceMethod) { searchValue = emitClassHeapMetadataRef(IGF, searchClass); } else { ClassDecl *searchClassDecl = searchClass->getClassOrBoundGenericClass(); searchValue = IGF.IGM.getAddrOfMetaclassObject(searchClassDecl); } searchValue = IGF.Builder.CreateBitCast(searchValue, IGF.IGM.ObjCClassPtrTy); // Store the receiver and class to the struct. llvm::Value *selfIndices[2] = { IGF.Builder.getInt32(0), IGF.Builder.getInt32(0) }; llvm::Value *selfAddr = IGF.Builder.CreateGEP(super.getAddress(), selfIndices); IGF.Builder.CreateStore(self, selfAddr, super.getAlignment()); llvm::Value *searchIndices[2] = { IGF.Builder.getInt32(0), IGF.Builder.getInt32(1) }; llvm::Value *searchAddr = IGF.Builder.CreateGEP(super.getAddress(), searchIndices); IGF.Builder.CreateStore(searchValue, searchAddr, super.getAlignment()); // Pass a pointer to the objc_super struct to the messenger. // Project the ownership semantics of 'self' to the super argument. selfValues.add({super.getAddress(), selfValue.getCleanup()}); } static void emitSuperArgument(IRGenFunction &IGF, bool isInstanceMethod, Expr *self, Explosion &selfValues, CanType searchClass) { // Generate the 'self' receiver. Explosion selfValueTmp(ExplosionKind::Minimal); emitSelfArgument(IGF, isInstanceMethod, self, selfValueTmp); ManagedValue selfValue = selfValueTmp.claimNext(); emitSuperArgument(IGF, isInstanceMethod, selfValue, selfValues, searchClass); } /// Prepare a call using ObjC method dispatch without applying the 'self' and /// '_cmd' arguments. CallEmission irgen::prepareObjCMethodRootCall(IRGenFunction &IGF, ValueDecl *method, CanType substResultType, ArrayRef subs, ExplosionKind maxExplosion, unsigned maxUncurry, bool isSuper) { assert((isa(method) || isa(method)) && "objc method call must be to a func or constructor decl"); Type formalType; if (auto *ctor = dyn_cast(method)) { formalType = ctor->getInitializerType(); } else { formalType = method->getType(); } CanType origFormalType = formalType->getCanonicalType(); ObjCMethodSignature sig(IGF.IGM, origFormalType, isSuper); // Create the appropriate messenger function. // FIXME: this needs to be target-specific. llvm::Constant *messenger; if (sig.IsIndirectReturn) { messenger = isSuper ? IGF.IGM.getObjCMsgSendSuperStretFn() : IGF.IGM.getObjCMsgSendStretFn(); } else { messenger = isSuper ? IGF.IGM.getObjCMsgSendSuperFn() : IGF.IGM.getObjCMsgSendFn(); } // Cast the messenger to the right type. messenger = llvm::ConstantExpr::getBitCast(messenger, sig.FnTy->getPointerTo()); CallEmission emission(IGF, Callee::forKnownFunction(AbstractCC::C, origFormalType, substResultType, subs, messenger, ManagedValue(nullptr), ExplosionKind::Minimal, /*uncurry*/ 1)); // Compute the selector. Selector selector(method); // Respect conventions. Callee &callee = emission.getMutableCallee(); setOwnershipConventions(callee, method, selector); return emission; } /// Emit the 'self'/'super' and '_cmd' arguments for an ObjC method dispatch. void irgen::addObjCMethodCallImplicitArguments(IRGenFunction &IGF, CallEmission &emission, ValueDecl *method, ManagedValue self, CanType selfType, CanType searchType) { // Compute the selector. Selector selector(method); Explosion args(ExplosionKind::Minimal); // super.constructor references an instance method (even though the // decl is really a 'static' member). bool isInstanceMethod = isa(method) || method->isInstanceMember(); // Map a class parameter back to an ObjC Class value (the heap metadata). if (!isInstanceMethod) { CanType selfInstanceType(selfType->castTo()->getInstanceType()); self = ManagedValue(emitClassHeapMetadataRefForMetatype(IGF, self.getValue(), selfInstanceType)); } if (searchType) { emitSuperArgument(IGF, isInstanceMethod, self, args, searchType); } else { args.add(self); } assert(args.size() == 1); // Add the selector value. auto selectorRef = IGF.IGM.getAddrOfObjCSelectorRef(selector.str()); llvm::Value *selectorV; if (IGF.IGM.Opts.UseJIT) { // When generating JIT'd code, we need to call sel_registerName() to force // the runtime to unique the selector. selectorV = IGF.Builder.CreateLoad(Address(selectorRef, IGF.IGM.getPointerAlignment())); selectorV = IGF.Builder.CreateCall(IGF.IGM.getObjCSelRegisterNameFn(), selectorV); } else { // When generating statically-compiled code, just build a reference to // the selector. selectorV = IGF.Builder.CreateLoad(Address(selectorRef, IGF.IGM.getPointerAlignment())); } args.addUnmanaged(selectorV); // Add that to the emission. emission.addArg(args); } /// Prepare a call using ObjC method dispatch. CallEmission irgen::prepareObjCMethodCall(IRGenFunction &IGF, ValueDecl *method, Expr *self, CanType substResultType, ArrayRef subs, ExplosionKind maxExplosion, unsigned maxUncurry, CanType searchType) { CallEmission emission = prepareObjCMethodRootCall(IGF, method, substResultType, subs, maxExplosion, maxUncurry, bool(searchType)); // Compute the selector. Selector selector(method); // Emit the self or super argument. Explosion selfValues(ExplosionKind::Minimal); // super.constructor references an instance method (even though the // decl is really a 'static' member). bool isInstanceMethod = isa(method) || method->isInstanceMember(); if (searchType) { emitSuperArgument(IGF, isInstanceMethod, self, selfValues, searchType); } else { emitSelfArgument(IGF, isInstanceMethod, self, selfValues); } assert(selfValues.size() == 1); // Add the selector value. auto selectorRef = IGF.IGM.getAddrOfObjCSelectorRef(selector.str()); llvm::Value *selectorV; if (IGF.IGM.Opts.UseJIT) { // When generating JIT'd code, we need to call sel_registerName() to force // the runtime to unique the selector. selectorV = IGF.Builder.CreateLoad(Address(selectorRef, IGF.IGM.getPointerAlignment())); selectorV = IGF.Builder.CreateCall(IGF.IGM.getObjCSelRegisterNameFn(), selectorV); } else { // When generating statically-compiled code, just build a reference to // the selector. selectorV = IGF.Builder.CreateLoad(Address(selectorRef, IGF.IGM.getPointerAlignment())); } selfValues.addUnmanaged(selectorV); // Add that to the emission. emission.addArg(selfValues); return emission; } /// Can we use the given method directly as the IMPL of an Objective-C /// function? /// /// It is okay for this to conservatively return false. static bool canUseSwiftFunctionAsObjCFunction(IRGenModule &IGM, const ObjCMethodSignature &signature, const OwnershipConventions &ownership, CanType origFormalType) { // TODO: nullary functions that return compatibly should be okay. return false; } /// Create the LLVM function declaration for a thunk that acts like /// an Objective-C method for a Swift method implementation. static llvm::Function *createSwiftAsObjCThunk(IRGenModule &IGM, const ObjCMethodSignature &sig, llvm::StringRef name) { // Construct the thunk name. llvm::SmallString<128> buffer; buffer.reserve(name.size() + 2); buffer.append("_TTo"); assert(name.startswith("_T")); buffer.append(name.substr(2)); auto fn = llvm::Function::Create(sig.FnTy, llvm::Function::InternalLinkage, buffer.str(), &IGM.Module); fn->setAttributes(sig.Attrs); fn->setUnnamedAddr(true ); return fn; } namespace { class TranslateParameters : public irgen::TypeVisitor { IRGenFunction &IGF; Explosion &Params; SmallVectorImpl &Args; SmallVectorImpl &ConsumedArgs; SmallVectorImpl::const_iterator NextConsumedArg; unsigned NextParamIndex = 0; public: TranslateParameters(IRGenFunction &IGF, Explosion ¶ms, SmallVectorImpl &args, SmallVectorImpl &consumedArgs) : IGF(IGF), Params(params), Args(args), ConsumedArgs(consumedArgs), NextConsumedArg(consumedArgs.begin()) { } void ignoreNext(unsigned count) { Params.claim(count); NextParamIndex += count; } /// Break apart tuple types and treat the fields separately and in order. void visitTupleType(TupleType *type) { for (auto &field : type->getFields()) { visit(CanType(field.getType())); } } /// Retain class pointers if necessary. void visitClassType(ClassType *type) { visitAnyClassType(type->getDecl()); } void visitBoundGenericClassType(BoundGenericClassType *type) { visitAnyClassType(type->getDecl()); } void visitAnyClassType(ClassDecl *theClass) { auto param = Params.claimUnmanagedNext(); if (shouldRetainNextParam()) { Args.push_back(IGF.emitBestRetainCall(param, theClass)); } else { Args.push_back(param); } } // Everything else gets copied to raise the component retain counts to +1. // FIXME: blocks could potentially be ns_consumed. void visitType(TypeBase *type) { const TypeInfo &ti = IGF.getFragileTypeInfo(type); if (requiresExternalByvalArgument(IGF.IGM, CanType(type))) { // If the argument was passed byval in the C calling convention, // reexplode it. llvm::Value *addrValue = Params.claimUnmanagedNext(); llvm::Constant *alignConstant = ti.getStaticAlignment(IGF.IGM); unsigned align = alignConstant ? alignConstant->getUniqueInteger().getZExtValue() : 1; Address addr(addrValue, Alignment(align)); Explosion loaded(IGF.CurExplosionLevel); ti.load(IGF, addr, loaded); unsigned width = ti.getExplosionSize(IGF.CurExplosionLevel); loaded.forward(IGF, width, Args); NextParamIndex += 1; } else { unsigned width = ti.getExplosionSize(IGF.CurExplosionLevel); Explosion copied(IGF.CurExplosionLevel); ti.copy(IGF, Params, copied); copied.forward(IGF, width, Args); NextParamIndex += width; } } private: /// Given that the next parameter is a retainable type, check /// whether its index is in the consumed-arguments set. /// If not, we need to retain it. Regardless, advance the /// next-parameter-index counter. bool shouldRetainNextParam() { auto paramIndex = NextParamIndex++; // Note that the consumed-arguments set is just a sorted list. // If the remaining set is empty, we're done. if (NextConsumedArg == ConsumedArgs.end()) return true; if (*NextConsumedArg != paramIndex) return true; NextConsumedArg++; return false; } }; } /// Produce a pointer to the objc_msgSend-compatible thunk wrapping the /// given Swift implementation, at the given explosion and uncurry levels. static llvm::Constant *getObjCMethodPointerForSwiftImpl(IRGenModule &IGM, const Selector &selector, FuncDecl *method, llvm::Function *swiftImpl, ExplosionKind explosionLevel, unsigned uncurryLevel) { // Construct a callee and derive its ownership conventions. CanType origFormalType = method->getType()->getCanonicalType(); ObjCMethodSignature sig(IGM, origFormalType, /*isSuper*/ false); auto callee = Callee::forMethod(origFormalType, sig.ResultType, ArrayRef(), swiftImpl, explosionLevel, uncurryLevel); auto &conventions = setOwnershipConventions(callee, method, selector); // Build the Objective-C function. llvm::Function *objcImpl; // As a special case, consider whether we really need a thunk. if (canUseSwiftFunctionAsObjCFunction(IGM, sig, conventions, origFormalType)) { objcImpl = swiftImpl; // Otherwise, build a function. } else { objcImpl = createSwiftAsObjCThunk(IGM, sig, swiftImpl->getName()); IRGenFunction IGF(IGM, origFormalType, ArrayRef(), explosionLevel, uncurryLevel, objcImpl, Prologue::Bare); Explosion params = IGF.collectParameters(); SmallVector args; // Remember the out-pointer. if (sig.IsIndirectReturn) { // TODO: remap return values? args.push_back(params.claimUnmanagedNext()); } auto fnType = cast(origFormalType); auto selfType = CanType(fnType->getInput()); fnType = cast(CanType(fnType->getResult())); auto formalArgType = CanType(fnType->getInput()); SmallVector consumedArgs; conventions.getConsumedArgs(IGM, callee, consumedArgs); TranslateParameters translate(IGF, params, args, consumedArgs); // Pull off and translate 'self'. translate.visit(selfType); params.getLastClaimed()->setName(method->isStatic() ? "This" : "this"); // 'self' just got pushed on, but we need it to come later. auto self = args.back(); args.pop_back(); // Ignore '_cmd'. translate.ignoreNext(1); // Translate the formal parameters. translate.visit(formalArgType); assert(params.empty()); // Put 'self' in its proper place. args.push_back(self); // Perform the call. // FIXME: other fn attributes? auto call = IGF.Builder.CreateCall(swiftImpl, args); if (sig.IsIndirectReturn) { call->addAttribute(1, llvm::Attribute::StructRet); } if (call->getType()->isVoidTy()) { IGF.Builder.CreateRetVoid(); } else { llvm::Value *result = call; if (conventions.isResultAutoreleased(IGM, callee)) { result = emitObjCAutoreleaseReturnValue(IGF, result); } IGF.Builder.CreateRet(result); } } return llvm::ConstantExpr::getBitCast(objcImpl, IGM.Int8PtrTy); } /// Produce a function pointer, suitable for invocation by /// objc_msgSend, for the given property's getter method implementation. /// /// Returns a value of type i8*. static llvm::Constant *getObjCGetterPointer(IRGenModule &IGM, const Selector &selector, VarDecl *property) { // FIXME: Explosion level ExplosionKind explosionLevel = ExplosionKind::Minimal; // Thunk the getter method, if there is one. if (FuncDecl *getter = property->getGetter()) { llvm::Function *swiftImpl = IGM.getAddrOfGetter(property, explosionLevel); return getObjCMethodPointerForSwiftImpl(IGM, selector, getter, swiftImpl, explosionLevel, /*uncurryLevel=*/ 2); } else { assert(!property->isProperty() && "property without getter?!"); // Synthesize a getter. FormalType getterType = IGM.getTypeOfGetter(property); CanType origFormalType = getterType.getType(); ObjCMethodSignature sig(IGM, origFormalType, /*isSuper*/ false); llvm::SmallString<32> swiftName; // Generate the mangled name of the Swift getter (without actually creating // a Function for it). CodeRef getterCode = CodeRef::forGetter(property, explosionLevel, getterType.getNaturalUncurryLevel()); LinkEntity getterEntity = LinkEntity::forFunction(getterCode); getterEntity.mangle(swiftName); llvm::Function *objcImpl = createSwiftAsObjCThunk(IGM, sig, swiftName); // Emit the ObjC method. IRGenFunction IGF(IGM, origFormalType, ArrayRef(), explosionLevel, getterType.getNaturalUncurryLevel(), objcImpl, Prologue::Bare); Explosion params = IGF.collectParameters(); CanType propTy = property->getType()->getCanonicalType(); CanType classTy = property->getDeclContext()->getDeclaredTypeInContext() ->getCanonicalType(); TypeInfo const &ti = IGM.getFragileTypeInfo(propTy); llvm::Constant *alignConstant = ti.getStaticAlignment(IGF.IGM); Alignment align(alignConstant ? alignConstant->getUniqueInteger().getZExtValue() : 1); // Pick out the arguments: // - indirect return (if any) Address indirectReturn; if (requiresExternalIndirectResult(IGM, propTy)) { indirectReturn = Address(params.claimUnmanagedNext(), align); } // - self (passed in at +0) llvm::Value *thisValue = params.forwardNext(IGF); // - _cmd params.claimUnmanagedNext(); // Load the physical ivar. OwnedAddress ivar = projectPhysicalClassMemberAddress(IGF, thisValue, classTy, property); // Return it at +0. if (indirectReturn.isValid()) { // "initializeWithTake" because ObjC getter convention is to return at // +0. ti.initializeWithTake(IGF, indirectReturn, ivar.getAddress()); IGF.Builder.CreateRetVoid(); } else { Explosion value(explosionLevel); // "loadAsTake" because ObjC getter convention is to return at +0. ti.loadAsTake(IGF, ivar.getAddress(), value); IGF.emitScalarReturn(value); } // Cast the method pointer to i8* and return it. return llvm::ConstantExpr::getBitCast(objcImpl, IGM.Int8PtrTy); } } /// Produce a function pointer, suitable for invocation by /// objc_msgSend, for the given property's setter method implementation. /// /// Returns a value of type i8*. static llvm::Constant *getObjCSetterPointer(IRGenModule &IGM, const Selector &selector, VarDecl *property) { assert(property->isSettable() && "property is not settable?!"); // FIXME: Explosion level ExplosionKind explosionLevel = ExplosionKind::Minimal; // Thunk the setter method, if there is one. if (FuncDecl *setter = property->getSetter()) { llvm::Function *swiftImpl = IGM.getAddrOfSetter(property, explosionLevel); return getObjCMethodPointerForSwiftImpl(IGM, selector, setter, swiftImpl, explosionLevel, /*uncurryLevel=*/ 2); } else { assert(!property->isProperty() && "settable property w/o setter?!"); // Synthesize a setter. FormalType setterType = IGM.getTypeOfSetter(property); CanType origFormalType = setterType.getType(); ObjCMethodSignature sig(IGM, origFormalType, /*isSuper*/ false); llvm::SmallString<32> swiftName; // Generate the mangled name of the Swift setter (without actually creating // a Function for it). CodeRef setterCode = CodeRef::forSetter(property, explosionLevel, setterType.getNaturalUncurryLevel()); LinkEntity setterEntity = LinkEntity::forFunction(setterCode); setterEntity.mangle(swiftName); llvm::Function *objcImpl = createSwiftAsObjCThunk(IGM, sig, swiftName); // Emit the ObjC method. IRGenFunction IGF(IGM, origFormalType, ArrayRef(), explosionLevel, setterType.getNaturalUncurryLevel(), objcImpl, Prologue::Bare); Explosion params = IGF.collectParameters(); CanType propTy = property->getType()->getCanonicalType(); CanType classTy = property->getDeclContext()->getDeclaredTypeInContext() ->getCanonicalType(); TypeInfo const &ti = IGM.getFragileTypeInfo(propTy); llvm::Constant *alignConstant = ti.getStaticAlignment(IGF.IGM); Alignment align(alignConstant ? alignConstant->getUniqueInteger().getZExtValue() : 1); // Pick out the arguments: // - self (passed in at +0) llvm::Value *thisValue = params.forwardNext(IGF); // - _cmd params.claimUnmanagedNext(); // - value (passed in at +0) -- we'll deal with that below. // Project the physical ivar. OwnedAddress ivar = projectPhysicalClassMemberAddress(IGF, thisValue, classTy, property); if (requiresExternalByvalArgument(IGM, propTy)) { // If the argument was passed byval in the C calling convention, // assign it (with copy so that we retain it) into the ivar. llvm::Value *value = params.claimUnmanagedNext(); Address valueAddr(value, align); ti.assignWithCopy(IGF, ivar.getAddress(), valueAddr); } else { Explosion copy(explosionLevel); // Copy the argument values so they get retained. ti.copy(IGF, params, copy); // Assign the exploded value to the ivar. ti.assign(IGF, copy, ivar.getAddress()); } IGF.Builder.CreateRetVoid(); // Cast the method pointer to i8* and return it. return llvm::ConstantExpr::getBitCast(objcImpl, IGM.Int8PtrTy); } } /// Produce a function pointer, suitable for invocation by /// objc_msgSend, for the given method implementation. /// /// Returns a value of type i8*. static llvm::Constant *getObjCMethodPointer(IRGenModule &IGM, const Selector &selector, FuncDecl *method) { auto absCallee = AbstractCallee::forDirectGlobalFunction(IGM, method); auto fnRef = FunctionRef(method, absCallee.getBestExplosionLevel(), absCallee.getMaxUncurryLevel()); llvm::Function *swiftImpl = IGM.getAddrOfFunction(fnRef, ExtraData::None); ExplosionKind explosionLevel = fnRef.getExplosionLevel(); unsigned uncurryLevel = fnRef.getUncurryLevel(); return getObjCMethodPointerForSwiftImpl(IGM, selector, method, swiftImpl, explosionLevel, uncurryLevel); } static bool isObjCGetterSignature(IRGenModule &IGM, AnyFunctionType *methodType) { return methodType->getResult()->getClassOrBoundGenericClass() && methodType->getInput()->isEqual(TupleType::getEmpty(IGM.Context)); } static bool isObjCSetterSignature(IRGenModule &IGM, AnyFunctionType *methodType) { if (!methodType->getResult()->isEqual(TupleType::getEmpty(IGM.Context))) return false; if (methodType->getInput()->getClassOrBoundGenericClass()) return true; if (TupleType *inputTuple = methodType->getInput()->getAs()) { return inputTuple->getFields().size() == 1 && inputTuple->getFields()[0].getType()->getClassOrBoundGenericClass(); } return false; } /// ObjC method encoding for a property getter of class type. /// - (SomeClass*)foo; static const char * const GetterMethodSignature = "@@:"; /// ObjC method encoding for a property setter of class type. /// - (void)setFoo:(SomeClass*); static const char * const SetterMethodSignature = "v@:@"; /// Emit the components of an Objective-C method descriptor: its selector, /// type encoding, and IMP pointer. void irgen::emitObjCMethodDescriptorParts(IRGenModule &IGM, FuncDecl *method, llvm::Constant *&selectorRef, llvm::Constant *&atEncoding, llvm::Constant *&impl) { Selector selector(method); /// The first element is the selector. selectorRef = IGM.getAddrOfObjCMethodName(selector.str()); /// The second element is the type @encoding. Handle some simple cases, and /// leave the rest as null for now. AnyFunctionType *methodType = method->getType()->castTo(); // Account for the 'this' pointer being curried. methodType = methodType->getResult()->castTo(); if (isObjCGetterSignature(IGM, methodType)) atEncoding = IGM.getAddrOfGlobalString(GetterMethodSignature); else if (isObjCSetterSignature(IGM, methodType)) atEncoding = IGM.getAddrOfGlobalString(SetterMethodSignature); else atEncoding = llvm::ConstantPointerNull::get(IGM.Int8PtrTy); /// The third element is the method implementation pointer. impl = getObjCMethodPointer(IGM, selector, method); } /// Emit the components of an Objective-C method descriptor for a /// property getter method. void irgen::emitObjCGetterDescriptorParts(IRGenModule &IGM, VarDecl *property, llvm::Constant *&selectorRef, llvm::Constant *&atEncoding, llvm::Constant *&impl) { bool isClassProperty = property->getType()->getClassOrBoundGenericClass(); Selector getterSel(property, Selector::ForGetter); selectorRef = IGM.getAddrOfObjCMethodName(getterSel.str()); atEncoding = isClassProperty ? IGM.getAddrOfGlobalString(GetterMethodSignature) : llvm::ConstantPointerNull::get(IGM.Int8PtrTy); impl = getObjCGetterPointer(IGM, getterSel, property); } /// Emit the components of an Objective-C method descriptor for a /// property getter method. void irgen::emitObjCSetterDescriptorParts(IRGenModule &IGM, VarDecl *property, llvm::Constant *&selectorRef, llvm::Constant *&atEncoding, llvm::Constant *&impl) { assert(property->isSettable() && "not a settable property?!"); bool isClassProperty = property->getType()->getClassOrBoundGenericClass(); Selector setterSel(property, Selector::ForSetter); selectorRef = IGM.getAddrOfObjCMethodName(setterSel.str()); atEncoding = isClassProperty ? IGM.getAddrOfGlobalString(SetterMethodSignature) : llvm::ConstantPointerNull::get(IGM.Int8PtrTy); impl = getObjCSetterPointer(IGM, setterSel, property); } /// Emit an Objective-C method descriptor for the given method. /// struct method_t { /// SEL name; /// const char *types; /// IMP imp; /// }; llvm::Constant *irgen::emitObjCMethodDescriptor(IRGenModule &IGM, FuncDecl *method) { llvm::Constant *selectorRef, *atEncoding, *impl; emitObjCMethodDescriptorParts(IGM, method, selectorRef, atEncoding, impl); llvm::Constant *fields[] = { selectorRef, atEncoding, impl }; return llvm::ConstantStruct::getAnon(IGM.getLLVMContext(), fields); } /// Emit Objective-C method descriptors for the property accessors of the given /// property. Returns a pair of Constants consisting of the getter and setter /// function pointers, in that order. The setter llvm::Constant* will be null if /// the property is not settable. std::pair irgen::emitObjCPropertyMethodDescriptors(IRGenModule &IGM, VarDecl *property) { llvm::Constant *selectorRef, *atEncoding, *impl; emitObjCGetterDescriptorParts(IGM, property, selectorRef, atEncoding, impl); llvm::Constant *getterFields[] = {selectorRef, atEncoding, impl}; llvm::Constant *getter = llvm::ConstantStruct::getAnon(IGM.getLLVMContext(), getterFields); llvm::Constant *setter = nullptr; if (property->isSettable()) { emitObjCSetterDescriptorParts(IGM, property, selectorRef, atEncoding, impl); llvm::Constant *setterFields[] = {selectorRef, atEncoding, impl}; setter = llvm::ConstantStruct::getAnon(IGM.getLLVMContext(), setterFields); } return {getter, setter}; } bool irgen::requiresObjCMethodDescriptor(FuncDecl *method) { // Property accessors should be generated alongside the property. if (method->isGetterOrSetter()) return false; if (method->isObjC() || method->getAttrs().isIBAction()) return true; if (auto override = method->getOverriddenDecl()) return requiresObjCMethodDescriptor(override); return false; } bool irgen::requiresObjCPropertyDescriptor(VarDecl *property) { if (property->isObjC()) return true; if (auto override = property->getOverriddenDecl()) return requiresObjCPropertyDescriptor(override); return false; }