//===--- 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/ADT/StringExtras.h" #include "llvm/IR/DerivedTypes.h" #include "llvm/IR/Module.h" #include "llvm/IR/InlineAsm.h" #include "clang/AST/ASTContext.h" #include "swift/AST/Attr.h" #include "swift/AST/Decl.h" #include "swift/AST/IRGenOptions.h" #include "swift/ClangImporter/ClangImporter.h" #include "swift/AST/Types.h" #include "swift/SIL/SILModule.h" #include "clang/AST/Attr.h" #include "clang/AST/DeclObjC.h" #include "CallEmission.h" #include "Explosion.h" #include "FormalType.h" #include "GenClangType.h" #include "GenClass.h" #include "GenFunc.h" #include "GenHeap.h" #include "GenMeta.h" #include "GenProto.h" #include "GenType.h" #include "HeapTypeInfo.h" #include "IRGenFunction.h" #include "IRGenModule.h" #include "Linking.h" #include "ScalarTypeInfo.h" #include "StructLayout.h" #include "GenObjC.h" using namespace swift; using namespace irgen; void IRGenFunction::emitObjCRelease(llvm::Value *value) { // Get an appropriately-cast 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) || valueTy == IGM.IntPtrTy); // happens with optional types #endif if (valueTy == IGM.ObjCPtrTy) return fn; auto fnTy = llvm::FunctionType::get(valueTy, valueTy, false); return llvm::ConstantExpr::getBitCast(fn, fnTy->getPointerTo(0)); } void IRGenFunction::emitObjCRetain(llvm::Value *v, Explosion &explosion) { explosion.add(emitObjCRetainCall(v)); } llvm::Value *IRGenFunction::emitObjCRetainCall(llvm::Value *value) { // Get an appropriately cast function pointer. auto fn = IGM.getObjCRetainFn(); fn = getCastOfRetainFn(IGM, fn, value->getType()); auto call = Builder.CreateCall(fn, value); call->setDoesNotThrow(); return call; } llvm::Value *IRGenFunction::emitObjCAutoreleaseCall(llvm::Value *val) { if (val->getType()->isPointerTy()) val = Builder.CreateBitCast(val, IGM.ObjCPtrTy); else val = Builder.CreateIntToPtr(val, IGM.ObjCPtrTy); auto call = Builder.CreateCall(IGM.getObjCAutoreleaseFn(), val); call->setDoesNotThrow(); return call; } llvm::Value *IRGenModule::getObjCRetainAutoreleasedReturnValueMarker() { // Check to see if we've already computed the market. Note that we // might have cached a null marker, and that's fine. auto &cache = ObjCRetainAutoreleasedReturnValueMarker; if (cache.hasValue()) return cache.getValue(); // Ask the target for the string. StringRef asmString = TargetInfo.ObjCRetainAutoreleasedReturnValueMarker; // If the string is empty, just leave, remembering that we did all this. if (asmString.empty()) { cache = nullptr; return nullptr; } // If we're emitting optimized code, record the string in the module // and let the late ARC pass insert it, but don't generate any calls // right now. if (Opts.OptLevel) { llvm::NamedMDNode *metadata = Module.getOrInsertNamedMetadata( "clang.arc.retainAutoreleasedReturnValueMarker"); assert(metadata->getNumOperands() <= 1); if (metadata->getNumOperands() == 0) { llvm::Value *string = llvm::MDString::get(LLVMContext, asmString); metadata->addOperand(llvm::MDNode::get(LLVMContext, string)); } cache = nullptr; // Otherwise, create the module } else { llvm::FunctionType *type = llvm::FunctionType::get(VoidTy, /*variadic*/false); cache = llvm::InlineAsm::get(type, asmString, "", /*sideeffects*/ true); } return cache.getValue(); } /// Reclaim an autoreleased return value. llvm::Value *irgen::emitObjCRetainAutoreleasedReturnValue(IRGenFunction &IGF, llvm::Value *value) { // Call the inline-assembly marker if we need one. if (auto marker = IGF.IGM.getObjCRetainAutoreleasedReturnValueMarker()) { IGF.Builder.CreateCall(marker); } 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. llvm::Value *irgen::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 { /// A type-info implementation suitable for an ObjC pointer type. class ObjCTypeInfo : public HeapTypeInfo { public: ObjCTypeInfo(llvm::PointerType *storageType, Size size, llvm::BitVector spareBits, Alignment align) : HeapTypeInfo(storageType, size, spareBits, align) { } /// Builtin.UnknownObject requires ObjC reference-counting. ReferenceCounting getReferenceCounting() const { return ReferenceCounting::ObjC; } }; } const TypeInfo *TypeConverter::convertBuiltinUnknownObject() { return new ObjCTypeInfo(IGM.ObjCPtrTy, IGM.getPointerSize(), IGM.getHeapObjectSpareBits(), IGM.getPointerAlignment()); } const TypeInfo &IRGenModule::getObjCClassPtrTypeInfo() { return Types.getObjCClassPtrTypeInfo(); } const TypeInfo &TypeConverter::getObjCClassPtrTypeInfo() { if (ObjCClassPtrTI) return *ObjCClassPtrTI; // ObjC class objects are guaranteed to be pointer-aligned. ObjCClassPtrTI = createPrimitiveForAlignedPointer(IGM.ObjCClassPtrTy, IGM.getPointerSize(), IGM.getPointerAlignment(), IGM.getPointerAlignment()); ObjCClassPtrTI->NextConverted = FirstType; FirstType = ObjCClassPtrTI; return *ObjCClassPtrTI; } /// 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; } /// Get or create an ObjC protocol record. Always returns an i8*. We lazily /// create ObjC protocol_t records for protocols, storing references to the /// record into the __objc_protolist and and __objc_protorefs sections to be /// fixed up by the runtime. /// /// It is not correct to use this value as a Protocol* reference directly. The /// ObjC runtime requires protocol references to be loaded from an /// indirect variable, the address of which is given by /// getAddrOfObjCProtocolRef. llvm::Constant *IRGenModule::getAddrOfObjCProtocolRecord(ProtocolDecl *proto, ForDefinition_t forDefinition) { return const_cast (cast(getObjCProtocolGlobalVars(proto).record)); } /// Get or create an ObjC protocol reference. Always returns an i8**. We lazily /// create ObjC protocol_t records for protocols, storing references to the /// record into the __objc_protolist and and __objc_protorefs sections to be /// fixed up by the runtime. llvm::Constant *IRGenModule::getAddrOfObjCProtocolRef(ProtocolDecl *proto, ForDefinition_t forDefinition) { return const_cast (cast(getObjCProtocolGlobalVars(proto).ref)); } IRGenModule::ObjCProtocolPair IRGenModule::getObjCProtocolGlobalVars(ProtocolDecl *proto) { // See whether we already emitted this protocol reference. auto found = ObjCProtocols.find(proto); if (found != ObjCProtocols.end()) { return found->second; } // Emit the protocol record. llvm::Constant *protocolRecord = emitObjCProtocolData(*this, proto); protocolRecord = llvm::ConstantExpr::getBitCast(protocolRecord, Int8PtrTy); // Introduce a variable to label the protocol. llvm::SmallString<64> nameBuffer; StringRef protocolName = proto->getObjCRuntimeName(nameBuffer); auto *protocolLabel = new llvm::GlobalVariable(Module, protocolRecord->getType(), /*constant*/ false, llvm::GlobalValue::WeakAnyLinkage, protocolRecord, llvm::Twine("\01l_OBJC_LABEL_PROTOCOL_$_") + protocolName); protocolLabel->setAlignment(getPointerAlignment().getValue()); protocolLabel->setVisibility(llvm::GlobalValue::HiddenVisibility); protocolLabel->setSection("__DATA,__objc_protolist,coalesced,no_dead_strip"); // Introduce a variable to reference the protocol. auto *protocolRef = new llvm::GlobalVariable(Module, protocolRecord->getType(), /*constant*/ false, llvm::GlobalValue::WeakAnyLinkage, protocolRecord, llvm::Twine("\01l_OBJC_PROTOCOL_REFERENCE_$_") + protocolName); protocolRef->setAlignment(getPointerAlignment().getValue()); protocolRef->setVisibility(llvm::GlobalValue::HiddenVisibility); protocolRef->setSection("__DATA,__objc_protorefs,coalesced,no_dead_strip"); ObjCProtocolPair pair{protocolRecord, protocolRef}; ObjCProtocols.insert({proto, pair}); return pair; } namespace { class Selector { llvm::SmallString<80> Buffer; StringRef 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) { Text = method->getObjCSelector().getString(Buffer); } Selector(ConstructorDecl *ctor) { Text = ctor->getObjCSelector().getString(Buffer); } Selector(ValueDecl *methodOrCtorOrDtor) { if (auto *method = dyn_cast(methodOrCtorOrDtor)) { Text = method->getObjCSelector().getString(Buffer); } else if (auto *ctor = dyn_cast(methodOrCtorOrDtor)) { Text = ctor->getObjCSelector().getString(Buffer); } else if (isa(methodOrCtorOrDtor)) { Text = "dealloc"; } else { llvm_unreachable("property or subscript selector should be generated " "using ForGetter or ForSetter constructors"); } } Selector(AbstractStorageDecl *asd, ForGetter_t) { Text = asd->getObjCGetterSelector().getString(Buffer); } Selector(AbstractStorageDecl *asd, ForSetter_t) { Text = asd->getObjCSetterSelector().getString(Buffer); } Selector(SILDeclRef ref) { switch (ref.kind) { case SILDeclRef::Kind::DefaultArgGenerator: case SILDeclRef::Kind::EnumElement: case SILDeclRef::Kind::GlobalAccessor: llvm_unreachable("Method does not have a selector"); case SILDeclRef::Kind::Destroyer: case SILDeclRef::Kind::Deallocator: Text = "dealloc"; break; case SILDeclRef::Kind::Func: Text = cast(ref.getDecl())->getObjCSelector() .getString(Buffer); break; case SILDeclRef::Kind::Allocator: case SILDeclRef::Kind::Initializer: Text = cast(ref.getDecl())->getObjCSelector() .getString(Buffer); break; case SILDeclRef::Kind::IVarInitializer: Text = ".cxx_construct"; break; case SILDeclRef::Kind::IVarDestroyer: Text = ".cxx_destruct"; break; } } 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 }; } static void emitSuperArgument(IRGenFunction &IGF, bool isInstanceMethod, llvm::Value *selfValue, Explosion &selfValues, SILType 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, IGF.IGM.ObjCPtrTy); // Generate the search class object reference. llvm::Value *searchValue; if (isInstanceMethod) { searchValue = emitClassHeapMetadataRef(IGF, searchClass); } else { ClassDecl *searchClassDecl = searchClass.castTo().getInstanceType() .getClassOrBoundGenericClass(); searchValue = IGF.IGM.getAddrOfMetaclassObject(searchClassDecl, NotForDefinition); } 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()); } static llvm::FunctionType *getMsgSendSuperTy(IRGenModule &IGM, llvm::FunctionType *fnTy, bool indirectResult) { SmallVector args(fnTy->param_begin(), fnTy->param_end()); if (indirectResult) args[1] = IGM.ObjCSuperPtrTy; else args[0] = IGM.ObjCSuperPtrTy; return llvm::FunctionType::get(fnTy->getReturnType(), args, fnTy->isVarArg()); } /// Prepare a call using ObjC method dispatch without applying the 'self' and /// '_cmd' arguments. CallEmission irgen::prepareObjCMethodRootCall(IRGenFunction &IGF, SILDeclRef method, CanSILFunctionType origFnType, CanSILFunctionType substFnType, ArrayRef subs, ResilienceExpansion maxExplosion, ObjCMessageKind kind) { assert((method.kind == SILDeclRef::Kind::Initializer || method.kind == SILDeclRef::Kind::Allocator || method.kind == SILDeclRef::Kind::Func || method.kind == SILDeclRef::Kind::Destroyer || method.kind == SILDeclRef::Kind::Deallocator) && "objc method call must be to a func/initializer/getter/setter/dtor"); ResilienceExpansion explosionLevel = ResilienceExpansion::Minimal; llvm::AttributeSet attrs; auto fnTy = IGF.IGM.getFunctionType(origFnType, explosionLevel, ExtraData::None, attrs); bool indirectResult = requiresExternalIndirectResult(IGF.IGM, origFnType); if (kind != ObjCMessageKind::Normal) fnTy = getMsgSendSuperTy(IGF.IGM, fnTy, indirectResult); // Create the appropriate messenger function. // FIXME: this needs to be target-specific. llvm::Constant *messenger; if (indirectResult && IGF.IGM.TargetInfo.ObjCUseStret) { switch (kind) { case ObjCMessageKind::Normal: messenger = IGF.IGM.getObjCMsgSendStretFn(); break; case ObjCMessageKind::Peer: messenger = IGF.IGM.getObjCMsgSendSuperStretFn(); break; case ObjCMessageKind::Super: messenger = IGF.IGM.getObjCMsgSendSuperStret2Fn(); break; } } else { switch (kind) { case ObjCMessageKind::Normal: messenger = IGF.IGM.getObjCMsgSendFn(); break; case ObjCMessageKind::Peer: messenger = IGF.IGM.getObjCMsgSendSuperFn(); break; case ObjCMessageKind::Super: messenger = IGF.IGM.getObjCMsgSendSuper2Fn(); break; } } // Cast the messenger to the right type. messenger = llvm::ConstantExpr::getBitCast(messenger, fnTy->getPointerTo()); CallEmission emission(IGF, Callee::forKnownFunction(origFnType, substFnType, subs, messenger, nullptr, explosionLevel)); return emission; } /// Emit the 'self'/'super' and '_cmd' arguments for an ObjC method dispatch. void irgen::addObjCMethodCallImplicitArguments(IRGenFunction &IGF, Explosion &args, SILDeclRef method, llvm::Value *self, SILType searchType) { // Compute the selector. Selector selector(method); // super.constructor references an instance method (even though the // decl is really a 'static' member). Similarly, destructors refer // to the instance method -dealloc. bool isInstanceMethod = method.kind == SILDeclRef::Kind::Initializer || method.kind == SILDeclRef::Kind::Deallocator || method.getDecl()->isInstanceMember(); if (searchType) { emitSuperArgument(IGF, isInstanceMethod, self, args, searchType); } else { args.add(self); } assert(args.size() == 1); // Add the selector value. args.add(IGF.emitObjCSelectorRefLoad(selector.str())); } /// Return the formal type that we would use for +allocWithZone:. static CanSILFunctionType getAllocObjectFormalType(ASTContext &ctx, CanType classType) { SILParameterInfo inputs[] = { SILParameterInfo(CanType(ctx.TheRawPointerType), /* (NSZone*), kindof */ ParameterConvention::Direct_Unowned), SILParameterInfo(CanType(MetatypeType::get(classType, MetatypeRepresentation::Thick)), ParameterConvention::Direct_Unowned) }; auto result = SILResultInfo(classType, ResultConvention::Owned); auto extInfo = SILFunctionType::ExtInfo(AbstractCC::ObjCMethod, FunctionType::Representation::Thin, /*noreturn*/ false); return SILFunctionType::get(nullptr, extInfo, /*callee*/ ParameterConvention::Direct_Unowned, inputs, result, ctx); } /// Call [self allocWithZone: nil]. llvm::Value *irgen::emitObjCAllocObjectCall(IRGenFunction &IGF, llvm::Value *self, CanType classType) { // Compute the formal type that we expect +allocWithZone: to have. auto formalType = getAllocObjectFormalType(IGF.IGM.Context, classType); auto explosionLevel = ResilienceExpansion::Minimal; unsigned uncurryLevel = 0; // Compute the appropriate LLVM type for the function. llvm::AttributeSet attrs; auto fnTy = IGF.IGM.getFunctionType(formalType, explosionLevel, ExtraData::None, attrs); // Get the messenger function. llvm::Constant *messenger = IGF.IGM.getObjCMsgSendFn(); messenger = llvm::ConstantExpr::getBitCast(messenger, fnTy->getPointerTo()); // Prepare the call. CallEmission emission(IGF, Callee::forKnownFunction(formalType, formalType, {}, messenger, nullptr, explosionLevel, uncurryLevel)); // Emit the arguments. { Explosion args(emission.getCurExplosionLevel()); args.add(self); args.add(IGF.emitObjCSelectorRefLoad("allocWithZone:")); args.add(llvm::ConstantPointerNull::get(IGF.IGM.Int8PtrTy)); emission.addArg(args); } // Emit the call. Explosion out(explosionLevel); emission.emitToExplosion(out); return out.claimNext(); } static llvm::Function *emitObjCPartialApplicationForwarder(IRGenModule &IGM, SILDeclRef method, CanSILFunctionType origMethodType, CanSILFunctionType resultType, const HeapLayout &layout, SILType selfType) { auto &selfTI = IGM.getTypeInfo(selfType); llvm::AttributeSet attrs; llvm::FunctionType *fwdTy = IGM.getFunctionType(resultType, ResilienceExpansion::Minimal, ExtraData::Retainable, attrs); // FIXME: Give the thunk a real name. // FIXME: Maybe cache the thunk by function and closure types? llvm::Function *fwd = llvm::Function::Create(fwdTy, llvm::Function::InternalLinkage, "_TPAo", &IGM.Module); fwd->setAttributes(attrs); IRGenFunction subIGF(IGM, fwd); // Do we need to lifetime-extend self? bool lifetimeExtendsSelf; switch (origMethodType->getInterfaceResult().getConvention()) { case ResultConvention::UnownedInnerPointer: lifetimeExtendsSelf = true; break; case ResultConvention::Unowned: case ResultConvention::Owned: case ResultConvention::Autoreleased: lifetimeExtendsSelf = false; break; } // Do we need to retain self before calling, and/or release it after? bool retainsSelf; switch (origMethodType->getInterfaceParameters().back().getConvention()) { case ParameterConvention::Direct_Unowned: retainsSelf = false; break; case ParameterConvention::Direct_Guaranteed: case ParameterConvention::Direct_Owned: retainsSelf = true; break; case ParameterConvention::Indirect_In: case ParameterConvention::Indirect_Out: case ParameterConvention::Indirect_Inout: llvm_unreachable("self passed indirectly?!"); } // Recover 'self' from the context. Explosion params = subIGF.collectParameters(ResilienceExpansion::Minimal); llvm::Value *context = params.takeLast(); Address dataAddr = layout.emitCastTo(subIGF, context); auto &fieldLayout = layout.getElements()[0]; Address selfAddr = fieldLayout.project(subIGF, dataAddr, Nothing); Explosion selfParams(ResilienceExpansion::Minimal); if (retainsSelf) cast(selfTI).loadAsCopy(subIGF, selfAddr, selfParams); else cast(selfTI).loadAsTake(subIGF, selfAddr, selfParams); llvm::Value *self = selfParams.claimNext(); // Save off the forwarded indirect return address if we have one. llvm::Value *indirectReturn = nullptr; SILType appliedResultTy = origMethodType->getSemanticInterfaceResultSILType(); auto &appliedResultTI = IGM.getTypeInfo(appliedResultTy); if (appliedResultTI.getSchema(ResilienceExpansion::Minimal) .requiresIndirectResult(IGM)) { indirectReturn = params.claimNext(); } // Prepare the call to the underlying method. CallEmission emission = prepareObjCMethodRootCall(subIGF, method, origMethodType, origMethodType, ArrayRef{}, ResilienceExpansion::Minimal, ObjCMessageKind::Normal); Explosion args(params.getKind()); addObjCMethodCallImplicitArguments(subIGF, args, method, self, SILType()); args.add(params.claimAll()); emission.addArg(args); // Cleanup that always has to occur after the function call. auto cleanup = [&]{ // Lifetime-extend 'self' by sending it to the autorelease pool if need be. if (lifetimeExtendsSelf) { subIGF.emitObjCRetainCall(self); subIGF.emitObjCAutoreleaseCall(self); } // Release the context. subIGF.emitRelease(context); }; // Emit the call and produce the return value. if (indirectReturn) { emission.emitToMemory(appliedResultTI.getAddressForPointer(indirectReturn), appliedResultTI); cleanup(); subIGF.Builder.CreateRetVoid(); } else { Explosion result(ResilienceExpansion::Minimal); emission.emitToExplosion(result); cleanup(); auto &callee = emission.getCallee(); auto resultType = callee.getOrigFunctionType()->getSILInterfaceResult(); subIGF.emitScalarReturn(resultType, result); } return fwd; } void irgen::emitObjCPartialApplication(IRGenFunction &IGF, SILDeclRef method, CanSILFunctionType origMethodType, CanSILFunctionType resultType, llvm::Value *self, SILType selfType, Explosion &out) { // Create a heap object to contain the self argument. // TODO: If function context arguments were given objc retain counts, // we wouldn't need to create a separate heap object here. auto *selfTypeInfo = &IGF.getTypeInfo(selfType); HeapLayout layout(IGF.IGM, LayoutStrategy::Optimal, selfType.getSwiftRValueType(), selfTypeInfo); llvm::Value *data = IGF.emitUnmanagedAlloc(layout, "closure"); // FIXME: non-fixed offsets NonFixedOffsets offsets = Nothing; Address dataAddr = layout.emitCastTo(IGF, data); auto &fieldLayout = layout.getElements()[0]; auto &fieldType = layout.getElementTypes()[0]; Address fieldAddr = fieldLayout.project(IGF, dataAddr, offsets); Explosion selfParams(ResilienceExpansion::Minimal); selfParams.add(self); fieldLayout.getType().initializeFromParams(IGF, selfParams, fieldAddr, fieldType); // Create the forwarding stub. llvm::Function *forwarder = emitObjCPartialApplicationForwarder(IGF.IGM, method, origMethodType, resultType, layout, selfType); llvm::Value *forwarderValue = IGF.Builder.CreateBitCast(forwarder, IGF.IGM.Int8PtrTy); // Emit the result explosion. out.add(forwarderValue); out.add(data); } /// Create the LLVM function declaration for a thunk that acts like /// an Objective-C method for a Swift method implementation. static llvm::Constant *findSwiftAsObjCThunk(IRGenModule &IGM, SILDeclRef ref) { auto fn = IGM.getAddrOfSILFunction(ref, NotForDefinition); assert(fn && "no IR function for swift-as-objc thunk"); // FIXME: Should set the linkage of the SILFunction to 'internal'. fn->setLinkage(llvm::GlobalValue::InternalLinkage); fn->setUnnamedAddr(true); return llvm::ConstantExpr::getBitCast(fn, 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, AbstractStorageDecl *property) { // Protocol properties have no impl. if (isa(property->getDeclContext())) return llvm::ConstantPointerNull::get(IGM.Int8PtrTy); // FIXME: Explosion level ResilienceExpansion expansion = ResilienceExpansion::Minimal; SILDeclRef getter = SILDeclRef(property->getGetter(), SILDeclRef::Kind::Func, expansion, SILDeclRef::ConstructAtNaturalUncurryLevel, /*foreign*/ true); return findSwiftAsObjCThunk(IGM, getter); } /// 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, AbstractStorageDecl *property) { // Protocol properties have no impl. if (isa(property->getDeclContext())) return llvm::ConstantPointerNull::get(IGM.Int8PtrTy); assert(property->isSettable(property->getDeclContext()) && "property is not settable?!"); ResilienceExpansion expansion = ResilienceExpansion::Minimal; SILDeclRef setter = SILDeclRef(property->getSetter(), SILDeclRef::Kind::Func, expansion, SILDeclRef::ConstructAtNaturalUncurryLevel, /*foreign*/ true); return findSwiftAsObjCThunk(IGM, setter); } /// 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, FuncDecl *method) { // Protocol methods have no impl. if (isa(method->getDeclContext())) return llvm::ConstantPointerNull::get(IGM.Int8PtrTy); ResilienceExpansion expansion = ResilienceExpansion::Minimal; SILDeclRef declRef = SILDeclRef(method, SILDeclRef::Kind::Func, expansion, SILDeclRef::ConstructAtNaturalUncurryLevel, /*foreign*/ true); return findSwiftAsObjCThunk(IGM, declRef); } /// Produce a function pointer, suitable for invocation by /// objc_msgSend, for the given constructor implementation. /// /// Returns a value of type i8*. static llvm::Constant *getObjCMethodPointer(IRGenModule &IGM, ConstructorDecl *constructor) { // Protocol methods have no impl. if (isa(constructor->getDeclContext())) return llvm::ConstantPointerNull::get(IGM.Int8PtrTy); ResilienceExpansion expansion = ResilienceExpansion::Minimal; SILDeclRef declRef = SILDeclRef(constructor, SILDeclRef::Kind::Initializer, expansion, SILDeclRef::ConstructAtNaturalUncurryLevel, /*foreign*/ true); return findSwiftAsObjCThunk(IGM, declRef); } /// Produce a function pointer, suitable for invocation by /// objc_msgSend, for the given destructor implementation. /// /// Returns a value of type i8*. static llvm::Constant *getObjCMethodPointer(IRGenModule &IGM, DestructorDecl *destructor) { ResilienceExpansion expansion = ResilienceExpansion::Minimal; SILDeclRef declRef = SILDeclRef(destructor, SILDeclRef::Kind::Deallocator, expansion, SILDeclRef::ConstructAtNaturalUncurryLevel, /*foreign*/ true); return findSwiftAsObjCThunk(IGM, declRef); } /// True if the value is of class type, or of a type that is bridged to class /// type. bool irgen::hasObjCClassRepresentation(IRGenModule &IGM, Type t) { return IGM.SILMod->Types.getLoweredBridgedType(t, AbstractCC::ObjCMethod) ->getClassOrBoundGenericClass(); } static llvm::Constant * GetObjCEncodingForType(IRGenModule &IGM, Type T) { ASTContext &Context = IGM.Context; auto CI = static_cast(&*Context.getClangModuleLoader()); assert(CI && "no clang module loader"); auto &clangASTContext = CI->getClangASTContext(); // TODO. encode types 'T'. GenClangType CTG(Context); auto clangType = CTG.visit(T->getCanonicalType()); if (!clangType.isNull()) { std::string TypeStr; clangASTContext.getObjCEncodingForType(clangType, TypeStr); return IGM.getAddrOfGlobalString(TypeStr.c_str()); } return llvm::ConstantPointerNull::get(IGM.Int8PtrTy); } static void HelperGetObjCEncodingForType(clang::ASTContext &Context, clang::CanQualType T, std::string &S, bool Extended) { Context.getObjCEncodingForMethodParameter(clang::Decl::OBJC_TQ_None, T, S, Extended); } static llvm::Constant *GetObjCEncodingForTypes(IRGenModule &IGM, CanType Result, ArrayRef Args, StringRef FixedArgs, Size::int_type ParmOffset, bool Extended) { ASTContext &Context = IGM.Context; auto CI = static_cast(&*Context.getClangModuleLoader()); assert(CI && "no clang module loader"); auto &clangASTContext = CI->getClangASTContext(); GenClangType CTG(Context); llvm::Constant *cnull = llvm::ConstantPointerNull::get(IGM.Int8PtrTy); // TODO. Encode type qualifer, 'in', 'inout', etc. for the parameter. std::string EncodeStr; auto clangType = CTG.visit(Result->getCanonicalType()); if (clangType.isNull()) return cnull; HelperGetObjCEncodingForType(clangASTContext, clangType, EncodeStr, Extended); std::string ArgsStr; // Argument types. for (auto ArgType : Args) { auto PType = CTG.visit(ArgType->getCanonicalType()); if (PType.isNull()) return cnull; // TODO. Some stuff related to Array and Function type is missing. // TODO. Encode type qualifer, 'in', 'inout', etc. for the parameter. HelperGetObjCEncodingForType(clangASTContext, PType, ArgsStr, Extended); ArgsStr += llvm::itostr(ParmOffset); clang::CharUnits sz = clangASTContext.getObjCEncodingTypeSize(PType); ParmOffset += sz.getQuantity(); } EncodeStr += llvm::itostr(ParmOffset); EncodeStr += FixedArgs; EncodeStr += ArgsStr; return IGM.getAddrOfGlobalString(StringRef(EncodeStr)); } static llvm::Constant * GetObjCEncodingForMethodType(IRGenModule &IGM, CanAnyFunctionType T, bool Extended) { CanType Result = T.getResult(); CanType Input = T.getInput(); SmallVector Inputs; // Unravel one level of tuple. if (auto tuple = dyn_cast(Input)) { for (unsigned i = 0, e = tuple->getNumElements(); i < e; ++i) Inputs.push_back(tuple.getElementType(i)); } else { Inputs.push_back(Input); } // Include the encoding for 'self' and '_cmd'. llvm::SmallString<8> specialParams; specialParams += "@0:"; auto ptrSize = IGM.getPointerSize().getValue(); specialParams += llvm::itostr(ptrSize); return GetObjCEncodingForTypes(IGM, Result, Inputs, specialParams, ptrSize * 2, Extended); } /// Emit the components of an Objective-C method descriptor: its selector, /// type encoding, and IMP pointer. void irgen::emitObjCMethodDescriptorParts(IRGenModule &IGM, AbstractFunctionDecl *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. CanAnyFunctionType methodType = cast(method->getType()->getCanonicalType()); if (!isa(method)) { // Account for the 'self' pointer being curried. methodType = cast(methodType.getResult()); } atEncoding = GetObjCEncodingForMethodType(IGM, methodType, false); /// The third element is the method implementation pointer. if (auto func = dyn_cast(method)) impl = getObjCMethodPointer(IGM, func); else if (auto ctor = dyn_cast(method)) impl = getObjCMethodPointer(IGM, ctor); else impl = getObjCMethodPointer(IGM, cast(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) { Selector getterSel(property, Selector::ForGetter); selectorRef = IGM.getAddrOfObjCMethodName(getterSel.str()); ASTContext &Context = IGM.Context; auto CI = static_cast(&*Context.getClangModuleLoader()); assert(CI && "no clang module loader"); GenClangType CTG(Context); auto &clangASTContext = CI->getClangASTContext(); std::string TypeStr; auto clangType = CTG.visit(property->getType()->getCanonicalType()); if (clangType.isNull()) { atEncoding = llvm::ConstantPointerNull::get(IGM.Int8PtrTy); return; } clangASTContext.getObjCEncodingForType(clangType, TypeStr); Size PtrSize = IGM.getPointerSize(); Size::int_type ParmOffset = 2 * PtrSize.getValue(); TypeStr += llvm::itostr(ParmOffset); TypeStr += "@0:"; TypeStr += llvm::itostr(PtrSize.getValue()); atEncoding = IGM.getAddrOfGlobalString(TypeStr.c_str()); impl = getObjCGetterPointer(IGM, property); } /// Emit the components of an Objective-C method descriptor for a /// subscript getter method. void irgen::emitObjCGetterDescriptorParts(IRGenModule &IGM, SubscriptDecl *subscript, llvm::Constant *&selectorRef, llvm::Constant *&atEncoding, llvm::Constant *&impl) { Selector getterSel(subscript, Selector::ForGetter); selectorRef = IGM.getAddrOfObjCMethodName(getterSel.str()); atEncoding = llvm::ConstantPointerNull::get(IGM.Int8PtrTy); impl = getObjCGetterPointer(IGM, subscript); } /// 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(property->getDeclContext()) && "not a settable property?!"); Selector setterSel(property, Selector::ForSetter); selectorRef = IGM.getAddrOfObjCMethodName(setterSel.str()); ASTContext &Context = IGM.Context; auto CI = static_cast(&*Context.getClangModuleLoader()); assert(CI && "no clang module loader"); GenClangType CTG(Context); auto &clangASTContext = CI->getClangASTContext(); std::string TypeStr; auto clangType = clangASTContext.VoidTy; clangASTContext.getObjCEncodingForType(clangType, TypeStr); Size PtrSize = IGM.getPointerSize(); Size::int_type ParmOffset = 2 * PtrSize.getValue(); Type ArgType = property->getType(); clangType = CTG.visit(ArgType->getCanonicalType()); if (clangType.isNull()) { atEncoding = llvm::ConstantPointerNull::get(IGM.Int8PtrTy); return; } clang::CharUnits sz = clangASTContext.getObjCEncodingTypeSize(clangType); if (!sz.isZero()) ParmOffset += sz.getQuantity(); TypeStr += llvm::itostr(ParmOffset); TypeStr += "@0:"; TypeStr += llvm::itostr(PtrSize.getValue()); ParmOffset = 2 * PtrSize.getValue(); clangASTContext.getObjCEncodingForType(clangType, TypeStr); TypeStr += llvm::itostr(ParmOffset); atEncoding = IGM.getAddrOfGlobalString(TypeStr.c_str()); impl = getObjCSetterPointer(IGM, property); } /// Emit the components of an Objective-C method descriptor for a /// subscript getter method. void irgen::emitObjCSetterDescriptorParts(IRGenModule &IGM, SubscriptDecl *subscript, llvm::Constant *&selectorRef, llvm::Constant *&atEncoding, llvm::Constant *&impl) { assert(subscript->isSettable() && "not a settable subscript?!"); Selector setterSel(subscript, Selector::ForSetter); selectorRef = IGM.getAddrOfObjCMethodName(setterSel.str()); atEncoding = llvm::ConstantPointerNull::get(IGM.Int8PtrTy); impl = getObjCSetterPointer(IGM, subscript); } /// 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, AbstractFunctionDecl *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); } Optional irgen::emitObjCIVarInitDestroyDescriptor(IRGenModule &IGM, ClassDecl *cd, bool isDestroyer) { // Check whether we have an implementation. Optional objcImpl = IGM.getAddrOfObjCIVarInitDestroy(cd, isDestroyer, NotForDefinition); if (!objcImpl) return Nothing; /// The first element is the selector. SILDeclRef declRef = SILDeclRef(cd, isDestroyer? SILDeclRef::Kind::IVarDestroyer : SILDeclRef::Kind::IVarInitializer, ResilienceExpansion::Minimal, 1, /*foreign*/ true); Selector selector(declRef); llvm::Constant *selectorRef = IGM.getAddrOfObjCMethodName(selector.str()); /// The second element is the type @encoding. llvm::Constant *atEncoding = GetObjCEncodingForType(IGM, cd->getDestructor()->getType()); /// The third element is the method implementation pointer. llvm::Constant *impl = llvm::ConstantExpr::getBitCast(*objcImpl, IGM.Int8PtrTy); // Form the method_t instance. llvm::Constant *fields[] = { selectorRef, atEncoding, impl }; return llvm::ConstantStruct::getAnon(IGM.getLLVMContext(), fields); } llvm::Constant * irgen::getMethodTypeExtendedEncoding(IRGenModule &IGM, AbstractFunctionDecl *method) { CanAnyFunctionType methodType = cast(method->getType()->getCanonicalType()); if (!isa(method)) { // Account for the 'self' pointer being curried. methodType = cast(methodType.getResult()); } return GetObjCEncodingForMethodType(IGM, methodType, true/*Extended*/); } llvm::Constant * irgen::getBlockTypeExtendedEncoding(IRGenModule &IGM, CanSILFunctionType invokeTy) { CanType resultType = invokeTy->getInterfaceResult().getType(); SmallVector paramTypes; // Skip the storage pointer, which is encoded as '@?' to avoid the infinite // recursion of the usual '@?<...>' rule for blocks. for (auto param : invokeTy->getInterfaceParameters().slice(1)) { assert(!param.isIndirect() && "indirect C arguments not supported"); paramTypes.push_back(param.getType()); } return GetObjCEncodingForTypes(IGM, resultType, paramTypes, "@?", IGM.getPointerSize().getValue(), /*extended*/ true); } /// 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(property->getDeclContext())) { emitObjCSetterDescriptorParts(IGM, property, selectorRef, atEncoding, impl); llvm::Constant *setterFields[] = {selectorRef, atEncoding, impl}; setter = llvm::ConstantStruct::getAnon(IGM.getLLVMContext(), setterFields); } return {getter, setter}; } std::pair irgen::emitObjCSubscriptMethodDescriptors(IRGenModule &IGM, SubscriptDecl *subscript) { llvm::Constant *selectorRef, *atEncoding, *impl; emitObjCGetterDescriptorParts(IGM, subscript, selectorRef, atEncoding, impl); llvm::Constant *getterFields[] = {selectorRef, atEncoding, impl}; llvm::Constant *getter = llvm::ConstantStruct::getAnon(IGM.getLLVMContext(), getterFields); llvm::Constant *setter = nullptr; if (subscript->isSettable()) { emitObjCSetterDescriptorParts(IGM, subscript, 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->isAccessor()) return false; // We don't export generic methods or subclasses to IRGen yet. if (method->getType()->is() || method->getType()->getAs() ->getResult()->is() || method->getDeclContext()->getDeclaredTypeInContext() ->is()) return false; if (method->isObjC() || method->getAttrs().hasAttribute()) return true; if (auto override = method->getOverriddenDecl()) return requiresObjCMethodDescriptor(override); return false; } bool irgen::requiresObjCMethodDescriptor(ConstructorDecl *constructor) { // We don't export generic methods or subclasses to IRGen yet. // FIXME: Total hack. Sema should filter these out. if (constructor->getType()->is() || constructor->getType()->getAs() ->getResult()->is() || constructor->getDeclContext()->getDeclaredTypeInContext() ->is()) return false; return constructor->isObjC(); } bool irgen::requiresObjCPropertyDescriptor(IRGenModule &IGM, VarDecl *property) { // We don't export generic methods or subclasses to IRGen yet. if (property->getDeclContext()->getDeclaredTypeInContext() ->is()) return false; if (auto override = property->getOverriddenDecl()) return requiresObjCPropertyDescriptor(IGM, override); if (!property->isObjC()) return false; // Don't expose objc properties for function types we can't bridge. if (auto ft = property->getType()->getAs()) switch (ft->getRepresentation()) { case FunctionType::Representation::Thin: // We can't bridge thin types at all. return false; case FunctionType::Representation::Thick: case FunctionType::Representation::Block: return true; } return true; } bool irgen::requiresObjCSubscriptDescriptor(IRGenModule &IGM, SubscriptDecl *subscript) { // We don't export generic methods or subclasses to IRGen yet. if (subscript->getDeclContext()->getDeclaredTypeInContext() ->is()) return false; if (auto override = subscript->getOverriddenDecl()) return requiresObjCSubscriptDescriptor(IGM, override); if (!subscript->isObjC()) return false; // Don't expose objc properties for function types we can't bridge. if (auto ft = subscript->getElementType()->getAs()) switch (ft->getRepresentation()) { case FunctionType::Representation::Thin: // We can't bridge thin types at all. return false; case FunctionType::Representation::Thick: case FunctionType::Representation::Block: return true; } return true; } llvm::Value *IRGenFunction::emitBlockCopyCall(llvm::Value *value) { // Get an appropriately-cast function pointer. auto fn = IGM.getBlockCopyFn(); if (value->getType() != IGM.ObjCBlockPtrTy) { auto fnTy = llvm::FunctionType::get(value->getType(), value->getType(), false)->getPointerTo(); fn = llvm::ConstantExpr::getBitCast(fn, fnTy); } auto call = Builder.CreateCall(fn, value); return call; } void IRGenFunction::emitBlockRelease(llvm::Value *value) { // Get an appropriately-cast function pointer. auto fn = IGM.getBlockReleaseFn(); if (value->getType() != IGM.ObjCBlockPtrTy) { 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(); }