/// Generate code to emit a thunk with native conventions that calls a /// function with foreign conventions. void SILGenFunction::emitForeignToNativeThunk(SILDeclRef thunk) { assert(!thunk.isForeign && "foreign-to-native thunks only"); // Wrap the function in its original form. auto fd = cast<AbstractFunctionDecl>(thunk.getDecl()); auto nativeCI = getConstantInfo(thunk); auto nativeFormalResultTy = nativeCI.LoweredInterfaceType.getResult(); auto nativeFnTy = F.getLoweredFunctionType(); assert(nativeFnTy == nativeCI.SILFnType); // Find the foreign error convention and 'self' parameter index. Optional<ForeignErrorConvention> foreignError; if (nativeFnTy->hasErrorResult()) { foreignError = fd->getForeignErrorConvention(); assert(foreignError && "couldn't find foreign error convention!"); } ImportAsMemberStatus memberStatus = fd->getImportAsMemberStatus(); // Forward the arguments. auto forwardedParameters = fd->getParameterLists(); // For allocating constructors, 'self' is a metatype, not the 'self' value // formally present in the constructor body. Type allocatorSelfType; if (thunk.kind == SILDeclRef::Kind::Allocator) { allocatorSelfType = forwardedParameters[0]->getType(getASTContext()) ->getLValueOrInOutObjectType(); forwardedParameters = forwardedParameters.slice(1); } SmallVector<SILValue, 8> params; for (auto *paramList : reversed(forwardedParameters)) bindParametersForForwarding(paramList, params); if (allocatorSelfType) { auto selfMetatype = CanMetatypeType::get(allocatorSelfType->getCanonicalType()); auto selfArg = new (F.getModule()) SILArgument( F.begin(), getLoweredLoadableType(selfMetatype), fd->getImplicitSelfDecl()); params.push_back(selfArg); } // Set up the throw destination if necessary. CleanupLocation cleanupLoc(fd); if (foreignError) { prepareRethrowEpilog(cleanupLoc); } SILValue result; { Scope scope(Cleanups, fd); SILDeclRef foreignDeclRef = thunk.asForeign(true); SILConstantInfo foreignCI = getConstantInfo(foreignDeclRef); auto foreignFnTy = foreignCI.SILFnType; // Bridge all the arguments. SmallVector<ManagedValue, 8> args; unsigned foreignArgIndex = 0; // A helper function to add a function error argument in the // appropriate position. auto maybeAddForeignErrorArg = [&] { if (foreignError && foreignArgIndex == foreignError->getErrorParameterIndex()) { args.push_back(ManagedValue()); foreignArgIndex++; } }; for (unsigned nativeParamIndex : indices(params)) { // Bring the parameter to +1. auto paramValue = params[nativeParamIndex]; auto thunkParam = nativeFnTy->getParameters()[nativeParamIndex]; // TODO: Could avoid a retain if the bridged parameter is also +0 and // doesn't require a bridging conversion. ManagedValue param; switch (thunkParam.getConvention()) { case ParameterConvention::Direct_Owned: param = emitManagedRValueWithCleanup(paramValue); break; case ParameterConvention::Direct_Guaranteed: case ParameterConvention::Direct_Unowned: param = emitManagedRetain(fd, paramValue); break; case ParameterConvention::Direct_Deallocating: param = ManagedValue::forUnmanaged(paramValue); break; case ParameterConvention::Indirect_Inout: case ParameterConvention::Indirect_InoutAliasable: param = ManagedValue::forUnmanaged(paramValue); break; case ParameterConvention::Indirect_In: case ParameterConvention::Indirect_In_Guaranteed: llvm_unreachable("indirect args in foreign thunked method not implemented"); } maybeAddForeignErrorArg(); bool isSelf = nativeParamIndex == params.size() - 1; if (memberStatus.isInstance()) { // Leave space for `self` to be filled in later. if (foreignArgIndex == memberStatus.getSelfIndex()) { args.push_back({}); foreignArgIndex++; } // Use the `self` space we skipped earlier if it's time. if (isSelf) { foreignArgIndex = memberStatus.getSelfIndex(); } } else if (memberStatus.isStatic() && isSelf) { // Lose a static `self` parameter. break; } auto foreignParam = foreignFnTy->getParameters()[foreignArgIndex++]; SILType foreignArgTy = foreignParam.getSILType(); auto bridged = emitNativeToBridgedValue(fd, param, SILFunctionTypeRepresentation::CFunctionPointer, foreignArgTy.getSwiftRValueType()); // Handle C pointer arguments imported as indirect `self` arguments. if (foreignParam.getConvention() == ParameterConvention::Indirect_In) { auto temp = emitTemporaryAllocation(fd, bridged.getType()); bridged.forwardInto(*this, fd, temp); bridged = emitManagedBufferWithCleanup(temp); } if (memberStatus.isInstance() && isSelf) { // Fill in the `self` space. args[memberStatus.getSelfIndex()] = bridged; } else { args.push_back(bridged); } } maybeAddForeignErrorArg(); // Call the original. auto subs = getForwardingSubstitutions(); auto fn = getThunkedForeignFunctionRef(*this, fd, foreignDeclRef, args, subs, foreignCI); auto fnType = fn->getType().castTo<SILFunctionType>(); fnType = fnType->substGenericArgs(SGM.M, SGM.SwiftModule, subs); result = emitApply(fd, ManagedValue::forUnmanaged(fn), subs, args, fnType, AbstractionPattern(nativeFormalResultTy), nativeFormalResultTy, ApplyOptions::None, None, foreignError, SGFContext()) .forwardAsSingleValue(*this, fd); } B.createReturn(ImplicitReturnLocation::getImplicitReturnLoc(fd), result); // Emit the throw destination. emitRethrowEpilog(fd); }
static std::string mangleConstant(SILDeclRef c, StringRef prefix) { using namespace Mangle; Mangler mangler; // Almost everything below gets one of the common prefixes: // mangled-name ::= '_T' global // Native symbol // mangled-name ::= '_TTo' global // ObjC interop thunk // mangled-name ::= '_TTO' global // Foreign function thunk // mangled-name ::= '_TTd' global // Direct StringRef introducer = "_T"; if (!prefix.empty()) { introducer = prefix; } else if (c.isForeign) { assert(prefix.empty() && "can't have custom prefix on thunk"); introducer = "_TTo"; } else if (c.isDirectReference) { introducer = "_TTd"; } else if (c.isForeignToNativeThunk()) { assert(prefix.empty() && "can't have custom prefix on thunk"); introducer = "_TTO"; } // As a special case, Clang functions and globals don't get mangled at all. if (c.hasDecl()) { if (auto clangDecl = c.getDecl()->getClangDecl()) { if (!c.isForeignToNativeThunk() && !c.isNativeToForeignThunk() && !c.isCurried) { if (auto namedClangDecl = dyn_cast<clang::DeclaratorDecl>(clangDecl)) { if (auto asmLabel = namedClangDecl->getAttr<clang::AsmLabelAttr>()) { mangler.append('\01'); mangler.append(asmLabel->getLabel()); } else if (namedClangDecl->hasAttr<clang::OverloadableAttr>()) { std::string storage; llvm::raw_string_ostream SS(storage); // FIXME: When we can import C++, use Clang's mangler all the time. mangleClangDecl(SS, namedClangDecl, c.getDecl()->getASTContext()); mangler.append(SS.str()); } else { mangler.append(namedClangDecl->getName()); } return mangler.finalize(); } } } } switch (c.kind) { // entity ::= declaration // other declaration case SILDeclRef::Kind::Func: if (!c.hasDecl()) { mangler.append(introducer); mangler.mangleClosureEntity(c.getAbstractClosureExpr(), c.uncurryLevel); return mangler.finalize(); } // As a special case, functions can have manually mangled names. // Use the SILGen name only for the original non-thunked, non-curried entry // point. if (auto NameA = c.getDecl()->getAttrs().getAttribute<SILGenNameAttr>()) if (!c.isForeignToNativeThunk() && !c.isNativeToForeignThunk() && !c.isCurried) { mangler.append(NameA->Name); return mangler.finalize(); } // Use a given cdecl name for native-to-foreign thunks. if (auto CDeclA = c.getDecl()->getAttrs().getAttribute<CDeclAttr>()) if (c.isNativeToForeignThunk()) { mangler.append(CDeclA->Name); return mangler.finalize(); } // Otherwise, fall through into the 'other decl' case. SWIFT_FALLTHROUGH; case SILDeclRef::Kind::EnumElement: mangler.append(introducer); mangler.mangleEntity(c.getDecl(), c.uncurryLevel); return mangler.finalize(); // entity ::= context 'D' // deallocating destructor case SILDeclRef::Kind::Deallocator: mangler.append(introducer); mangler.mangleDestructorEntity(cast<DestructorDecl>(c.getDecl()), /*isDeallocating*/ true); return mangler.finalize(); // entity ::= context 'd' // destroying destructor case SILDeclRef::Kind::Destroyer: mangler.append(introducer); mangler.mangleDestructorEntity(cast<DestructorDecl>(c.getDecl()), /*isDeallocating*/ false); return mangler.finalize(); // entity ::= context 'C' type // allocating constructor case SILDeclRef::Kind::Allocator: mangler.append(introducer); mangler.mangleConstructorEntity(cast<ConstructorDecl>(c.getDecl()), /*allocating*/ true, c.uncurryLevel); return mangler.finalize(); // entity ::= context 'c' type // initializing constructor case SILDeclRef::Kind::Initializer: mangler.append(introducer); mangler.mangleConstructorEntity(cast<ConstructorDecl>(c.getDecl()), /*allocating*/ false, c.uncurryLevel); return mangler.finalize(); // entity ::= declaration 'e' // ivar initializer // entity ::= declaration 'E' // ivar destroyer case SILDeclRef::Kind::IVarInitializer: case SILDeclRef::Kind::IVarDestroyer: mangler.append(introducer); mangler.mangleIVarInitDestroyEntity( cast<ClassDecl>(c.getDecl()), c.kind == SILDeclRef::Kind::IVarDestroyer); return mangler.finalize(); // entity ::= declaration 'a' // addressor case SILDeclRef::Kind::GlobalAccessor: mangler.append(introducer); mangler.mangleAddressorEntity(c.getDecl()); return mangler.finalize(); // entity ::= declaration 'G' // getter case SILDeclRef::Kind::GlobalGetter: mangler.append(introducer); mangler.mangleGlobalGetterEntity(c.getDecl()); return mangler.finalize(); // entity ::= context 'e' index // default arg generator case SILDeclRef::Kind::DefaultArgGenerator: mangler.append(introducer); mangler.mangleDefaultArgumentEntity(cast<AbstractFunctionDecl>(c.getDecl()), c.defaultArgIndex); return mangler.finalize(); } llvm_unreachable("bad entity kind!"); }
void SILGenFunction::emitNativeToForeignThunk(SILDeclRef thunk) { assert(thunk.isForeign); SILDeclRef native = thunk.asForeign(false); auto loc = thunk.getAsRegularLocation(); loc.markAutoGenerated(); Scope scope(Cleanups, CleanupLocation::get(loc)); // Bridge the arguments. SmallVector<SILValue, 4> args; Optional<ForeignErrorConvention> foreignError; SILValue foreignErrorSlot; auto objcFnTy = emitObjCThunkArguments(*this, loc, thunk, args, foreignErrorSlot, foreignError); auto nativeInfo = getConstantInfo(native); auto swiftResultTy = F.mapTypeIntoContext(nativeInfo.SILFnType->getSILResult()); auto objcResultTy = F.mapTypeIntoContext(objcFnTy->getSILResult()); // Call the native entry point. SILValue nativeFn = emitGlobalFunctionRef(loc, native, nativeInfo); auto subs = F.getForwardingSubstitutions(); auto substTy = nativeInfo.SILFnType->substGenericArgs( SGM.M, SGM.M.getSwiftModule(), subs); SILType substSILTy = SILType::getPrimitiveObjectType(substTy); CanType bridgedResultType = objcResultTy.getSwiftRValueType(); SILValue result; assert(foreignError.hasValue() == substTy->hasErrorResult()); if (!substTy->hasErrorResult()) { // Create the apply. result = B.createApply(loc, nativeFn, substSILTy, swiftResultTy, subs, args); // Leave the scope immediately. This isn't really necessary; it // just limits lifetimes a little bit more. scope.pop(); // Now bridge the return value. result = emitBridgeReturnValue(*this, loc, result, objcFnTy->getRepresentation(), bridgedResultType); } else { SILBasicBlock *contBB = createBasicBlock(); SILBasicBlock *errorBB = createBasicBlock(); SILBasicBlock *normalBB = createBasicBlock(); B.createTryApply(loc, nativeFn, substSILTy, subs, args, normalBB, errorBB); // Emit the non-error destination. { B.emitBlock(normalBB); SILValue nativeResult = normalBB->createBBArg(swiftResultTy); // In this branch, the eventual return value is mostly created // by bridging the native return value, but we may need to // adjust it slightly. SILValue bridgedResult = emitBridgeReturnValueForForeignError(loc, nativeResult, objcFnTy->getRepresentation(), objcResultTy, foreignErrorSlot, *foreignError); B.createBranch(loc, contBB, bridgedResult); } // Emit the error destination. { B.emitBlock(errorBB); SILValue nativeError = errorBB->createBBArg(substTy->getErrorResult().getSILType()); // In this branch, the eventual return value is mostly invented. // Store the native error in the appropriate location and return. SILValue bridgedResult = emitBridgeErrorForForeignError(loc, nativeError, objcResultTy, foreignErrorSlot, *foreignError); B.createBranch(loc, contBB, bridgedResult); } // Emit the join block. B.emitBlock(contBB); result = contBB->createBBArg(objcResultTy); // Leave the scope now. scope.pop(); } B.createReturn(loc, result); }
ManagedValue SILGenFunction::emitClosureValue(SILLocation loc, SILDeclRef constant, CanType expectedType, SubstitutionList subs) { auto closure = *constant.getAnyFunctionRef(); auto captureInfo = closure.getCaptureInfo(); auto loweredCaptureInfo = SGM.Types.getLoweredLocalCaptures(closure); auto hasCaptures = SGM.Types.hasLoweredLocalCaptures(closure); auto constantInfo = getConstantInfo(constant); SILValue functionRef = emitGlobalFunctionRef(loc, constant, constantInfo); SILType functionTy = functionRef->getType(); // Apply substitutions. auto pft = constantInfo.SILFnType; auto *dc = closure.getAsDeclContext()->getParent(); if (dc->isLocalContext() && !loweredCaptureInfo.hasGenericParamCaptures()) { // If the lowered function type is not polymorphic but we were given // substitutions, we have a closure in a generic context which does not // capture generic parameters. Just drop the substitutions. subs = { }; } else if (closure.getAbstractClosureExpr()) { // If we have a closure expression in generic context, Sema won't give // us substitutions, so we just use the forwarding substitutions from // context. subs = getForwardingSubstitutions(); } bool wasSpecialized = false; if (!subs.empty()) { auto specialized = pft->substGenericArgs(F.getModule(), subs); functionTy = SILType::getPrimitiveObjectType(specialized); wasSpecialized = true; } // If we're in top-level code, we don't need to physically capture script // globals, but we still need to mark them as escaping so that DI can flag // uninitialized uses. if (this == SGM.TopLevelSGF) { SGM.emitMarkFunctionEscapeForTopLevelCodeGlobals( loc, captureInfo); } if (!hasCaptures && !wasSpecialized) { auto result = ManagedValue::forUnmanaged(functionRef); return emitOrigToSubstValue(loc, result, AbstractionPattern(expectedType), expectedType); } SmallVector<ManagedValue, 4> capturedArgs; emitCaptures(loc, closure, CaptureEmission::PartialApplication, capturedArgs); // The partial application takes ownership of the context parameters. SmallVector<SILValue, 4> forwardedArgs; for (auto capture : capturedArgs) forwardedArgs.push_back(capture.forward(*this)); auto calleeConvention = ParameterConvention::Direct_Guaranteed; SILType closureTy = SILGenBuilder::getPartialApplyResultType( functionRef->getType(), capturedArgs.size(), SGM.M, subs, calleeConvention); auto toClosure = B.createPartialApply(loc, functionRef, functionTy, subs, forwardedArgs, closureTy); auto result = emitManagedRValueWithCleanup(toClosure); // Get the lowered AST types: // - the original type auto origFormalType = AbstractionPattern(constantInfo.LoweredType); // - the substituted type auto substFormalType = expectedType; // Generalize if necessary. result = emitOrigToSubstValue(loc, result, origFormalType, substFormalType); return result; }
void SILGenFunction::emitObjCDestructor(SILDeclRef dtor) { auto dd = cast<DestructorDecl>(dtor.getDecl()); auto cd = cast<ClassDecl>(dd->getDeclContext()); MagicFunctionName = DeclName(SGM.M.getASTContext().getIdentifier("deinit")); RegularLocation loc(dd); if (dd->isImplicit()) loc.markAutoGenerated(); SILValue selfValue = emitSelfDecl(dd->getImplicitSelfDecl()); // Create a basic block to jump to for the implicit destruction behavior // of releasing the elements and calling the superclass destructor. // We won't actually emit the block until we finish with the destructor body. prepareEpilog(Type(), false, CleanupLocation::get(loc)); // Emit the destructor body. emitStmt(dd->getBody()); Optional<SILValue> maybeReturnValue; SILLocation returnLoc(loc); std::tie(maybeReturnValue, returnLoc) = emitEpilogBB(loc); if (!maybeReturnValue) return; auto cleanupLoc = CleanupLocation::get(loc); // Note: the ivar destroyer is responsible for destroying the // instance variables before the object is actually deallocated. // Form a reference to the superclass -dealloc. Type superclassTy = dd->mapTypeIntoContext(cd->getSuperclass()); assert(superclassTy && "Emitting Objective-C -dealloc without superclass?"); ClassDecl *superclass = superclassTy->getClassOrBoundGenericClass(); auto superclassDtorDecl = superclass->getDestructor(); SILDeclRef superclassDtor(superclassDtorDecl, SILDeclRef::Kind::Deallocator, SILDeclRef::ConstructAtBestResilienceExpansion, SILDeclRef::ConstructAtNaturalUncurryLevel, /*isForeign=*/true); auto superclassDtorType = SGM.getConstantType(superclassDtor); SILValue superclassDtorValue = B.createSuperMethod( cleanupLoc, selfValue, superclassDtor, superclassDtorType); // Call the superclass's -dealloc. SILType superclassSILTy = getLoweredLoadableType(superclassTy); SILValue superSelf = B.createUpcast(cleanupLoc, selfValue, superclassSILTy); ArrayRef<Substitution> subs = superclassTy->gatherAllSubstitutions(SGM.M.getSwiftModule(), nullptr); auto substDtorType = superclassDtorType.castTo<SILFunctionType>() ->substGenericArgs(SGM.M, subs); B.createApply(cleanupLoc, superclassDtorValue, SILType::getPrimitiveObjectType(substDtorType), substDtorType->getSILResult(), subs, superSelf); // Return. B.createReturn(returnLoc, emitEmptyTuple(cleanupLoc)); }
static std::string mangleConstant(SILDeclRef c, SILDeclRef::ManglingKind Kind) { using namespace NewMangling; ASTMangler mangler; // As a special case, Clang functions and globals don't get mangled at all. if (c.hasDecl()) { if (auto clangDecl = c.getDecl()->getClangDecl()) { if (!c.isForeignToNativeThunk() && !c.isNativeToForeignThunk() && !c.isCurried) { if (auto namedClangDecl = dyn_cast<clang::DeclaratorDecl>(clangDecl)) { if (auto asmLabel = namedClangDecl->getAttr<clang::AsmLabelAttr>()) { std::string s(1, '\01'); s += asmLabel->getLabel(); return s; } else if (namedClangDecl->hasAttr<clang::OverloadableAttr>()) { std::string storage; llvm::raw_string_ostream SS(storage); // FIXME: When we can import C++, use Clang's mangler all the time. mangleClangDecl(SS, namedClangDecl, c.getDecl()->getASTContext()); return SS.str(); } return namedClangDecl->getName(); } } } } ASTMangler::SymbolKind SKind = ASTMangler::SymbolKind::Default; switch (Kind) { case SILDeclRef::ManglingKind::Default: if (c.isForeign) { SKind = ASTMangler::SymbolKind::SwiftAsObjCThunk; } else if (c.isDirectReference) { SKind = ASTMangler::SymbolKind::DirectMethodReferenceThunk; } else if (c.isForeignToNativeThunk()) { SKind = ASTMangler::SymbolKind::ObjCAsSwiftThunk; } break; case SILDeclRef::ManglingKind::VTableMethod: SKind = ASTMangler::SymbolKind::VTableMethod; break; case SILDeclRef::ManglingKind::DynamicThunk: SKind = ASTMangler::SymbolKind::DynamicThunk; break; } switch (c.kind) { case SILDeclRef::Kind::Func: if (!c.hasDecl()) return mangler.mangleClosureEntity(c.getAbstractClosureExpr(), SKind); // As a special case, functions can have manually mangled names. // Use the SILGen name only for the original non-thunked, non-curried entry // point. if (auto NameA = c.getDecl()->getAttrs().getAttribute<SILGenNameAttr>()) if (!c.isForeignToNativeThunk() && !c.isNativeToForeignThunk() && !c.isCurried) { return NameA->Name; } // Use a given cdecl name for native-to-foreign thunks. if (auto CDeclA = c.getDecl()->getAttrs().getAttribute<CDeclAttr>()) if (c.isNativeToForeignThunk()) { return CDeclA->Name; } // Otherwise, fall through into the 'other decl' case. SWIFT_FALLTHROUGH; case SILDeclRef::Kind::EnumElement: return mangler.mangleEntity(c.getDecl(), c.isCurried, SKind); case SILDeclRef::Kind::Deallocator: assert(!c.isCurried); return mangler.mangleDestructorEntity(cast<DestructorDecl>(c.getDecl()), /*isDeallocating*/ true, SKind); case SILDeclRef::Kind::Destroyer: assert(!c.isCurried); return mangler.mangleDestructorEntity(cast<DestructorDecl>(c.getDecl()), /*isDeallocating*/ false, SKind); case SILDeclRef::Kind::Allocator: return mangler.mangleConstructorEntity(cast<ConstructorDecl>(c.getDecl()), /*allocating*/ true, c.isCurried, SKind); case SILDeclRef::Kind::Initializer: return mangler.mangleConstructorEntity(cast<ConstructorDecl>(c.getDecl()), /*allocating*/ false, c.isCurried, SKind); case SILDeclRef::Kind::IVarInitializer: case SILDeclRef::Kind::IVarDestroyer: assert(!c.isCurried); return mangler.mangleIVarInitDestroyEntity(cast<ClassDecl>(c.getDecl()), c.kind == SILDeclRef::Kind::IVarDestroyer, SKind); case SILDeclRef::Kind::GlobalAccessor: assert(!c.isCurried); return mangler.mangleAccessorEntity(AccessorKind::IsMutableAddressor, AddressorKind::Unsafe, c.getDecl(), /*isStatic*/ false, SKind); case SILDeclRef::Kind::GlobalGetter: assert(!c.isCurried); return mangler.mangleGlobalGetterEntity(c.getDecl(), SKind); case SILDeclRef::Kind::DefaultArgGenerator: assert(!c.isCurried); return mangler.mangleDefaultArgumentEntity( cast<AbstractFunctionDecl>(c.getDecl()), c.defaultArgIndex, SKind); case SILDeclRef::Kind::StoredPropertyInitializer: assert(!c.isCurried); return mangler.mangleInitializerEntity(cast<VarDecl>(c.getDecl()), SKind); } llvm_unreachable("bad entity kind!"); }
void SILGenFunction::emitObjCDestructor(SILDeclRef dtor) { auto dd = cast<DestructorDecl>(dtor.getDecl()); auto cd = cast<ClassDecl>(dd->getDeclContext()); MagicFunctionName = DeclName(SGM.M.getASTContext().getIdentifier("deinit")); RegularLocation loc(dd); if (dd->isImplicit()) loc.markAutoGenerated(); SILValue selfValue = emitSelfDecl(dd->getImplicitSelfDecl()); // Create a basic block to jump to for the implicit destruction behavior // of releasing the elements and calling the superclass destructor. // We won't actually emit the block until we finish with the destructor body. prepareEpilog(Type(), false, CleanupLocation::get(loc)); emitProfilerIncrement(dd->getBody()); // Emit the destructor body. emitStmt(dd->getBody()); Optional<SILValue> maybeReturnValue; SILLocation returnLoc(loc); std::tie(maybeReturnValue, returnLoc) = emitEpilogBB(loc); if (!maybeReturnValue) return; auto cleanupLoc = CleanupLocation::get(loc); // Note: the ivar destroyer is responsible for destroying the // instance variables before the object is actually deallocated. // Form a reference to the superclass -dealloc. Type superclassTy = dd->mapTypeIntoContext(cd->getSuperclass()); assert(superclassTy && "Emitting Objective-C -dealloc without superclass?"); ClassDecl *superclass = superclassTy->getClassOrBoundGenericClass(); auto superclassDtorDecl = superclass->getDestructor(); auto superclassDtor = SILDeclRef(superclassDtorDecl, SILDeclRef::Kind::Deallocator) .asForeign(); auto superclassDtorType = SGM.Types.getConstantType(superclassDtor); SILValue superclassDtorValue = B.createObjCSuperMethod( cleanupLoc, selfValue, superclassDtor, superclassDtorType); // Call the superclass's -dealloc. SILType superclassSILTy = getLoweredLoadableType(superclassTy); SILValue superSelf = B.createUpcast(cleanupLoc, selfValue, superclassSILTy); assert(superSelf.getOwnershipKind() == ValueOwnershipKind::Owned); auto subMap = superclassTy->getContextSubstitutionMap(SGM.M.getSwiftModule(), superclass); auto substDtorType = superclassDtorType.substGenericArgs(SGM.M, subMap); CanSILFunctionType substFnType = substDtorType.castTo<SILFunctionType>(); SILFunctionConventions dtorConv(substFnType, SGM.M); assert(substFnType->getSelfParameter().getConvention() == ParameterConvention::Direct_Unowned && "Objective C deinitializing destructor takes self as unowned"); B.createApply(cleanupLoc, superclassDtorValue, substDtorType, dtorConv.getSILResultType(), subMap, superSelf); // We know that the givne value came in at +1, but we pass the relevant value // as unowned to the destructor. Create a fake balance for the verifier to be // happy. B.createEndLifetime(cleanupLoc, superSelf); // Return. B.createReturn(returnLoc, emitEmptyTuple(cleanupLoc)); }
void addMethod(SILDeclRef method) { if (method.getDecl()->getDeclContext() == CD) TBD.addDispatchThunk(method); }
Optional<SpecializedEmitter> SpecializedEmitter::forDecl(SILGenModule &SGM, SILDeclRef function) { // Only consider standalone declarations in the Builtin module. if (function.kind != SILDeclRef::Kind::Func) return None; if (!function.hasDecl()) return None; ValueDecl *decl = function.getDecl(); if (!isa<BuiltinUnit>(decl->getDeclContext())) return None; auto name = decl->getBaseName().getIdentifier(); const BuiltinInfo &builtin = SGM.M.getBuiltinInfo(name); switch (builtin.ID) { // All the non-SIL, non-type-trait builtins should use the // named-builtin logic, which just emits the builtin as a call to a // builtin function. This includes builtins that aren't even declared // in Builtins.def, i.e. all of the LLVM intrinsics. // // We do this in a separate pass over Builtins.def to avoid creating // a bunch of identical cases. #define BUILTIN(Id, Name, Attrs) \ case BuiltinValueKind::Id: #define BUILTIN_SIL_OPERATION(Id, Name, Overload) #define BUILTIN_SANITIZER_OPERATION(Id, Name, Attrs) #define BUILTIN_TYPE_CHECKER_OPERATION(Id, Name) #define BUILTIN_TYPE_TRAIT_OPERATION(Id, Name) #include "swift/AST/Builtins.def" case BuiltinValueKind::None: return SpecializedEmitter(name); // Do a second pass over Builtins.def, ignoring all the cases for // which we emitted something above. #define BUILTIN(Id, Name, Attrs) // Use specialized emitters for SIL builtins. #define BUILTIN_SIL_OPERATION(Id, Name, Overload) \ case BuiltinValueKind::Id: \ return SpecializedEmitter(&emitBuiltin##Id); // Sanitizer builtins should never directly be called; they should only // be inserted as instrumentation by SILGen. #define BUILTIN_SANITIZER_OPERATION(Id, Name, Attrs) \ case BuiltinValueKind::Id: \ llvm_unreachable("Sanitizer builtin called directly?"); #define BUILTIN_TYPE_CHECKER_OPERATION(Id, Name) \ case BuiltinValueKind::Id: \ llvm_unreachable( \ "Compile-time type checker operation should not make it to SIL!"); // Lower away type trait builtins when they're trivially solvable. #define BUILTIN_TYPE_TRAIT_OPERATION(Id, Name) \ case BuiltinValueKind::Id: \ return SpecializedEmitter(&emitBuiltinTypeTrait<&TypeBase::Name, \ BuiltinValueKind::Id>); #include "swift/AST/Builtins.def" } llvm_unreachable("bad builtin kind"); }
void SILGenFunction::emitCurryThunk(SILDeclRef thunk) { assert(thunk.isCurried); auto *vd = thunk.getDecl(); if (auto *fd = dyn_cast<AbstractFunctionDecl>(vd)) { assert(!SGM.M.Types.hasLoweredLocalCaptures(fd) && "methods cannot have captures"); (void) fd; } SILLocation loc(vd); Scope S(*this, vd); auto thunkInfo = SGM.Types.getConstantInfo(thunk); auto thunkFnTy = thunkInfo.SILFnType; SILFunctionConventions fromConv(thunkFnTy, SGM.M); auto selfTy = fromConv.getSILType(thunkFnTy->getSelfParameter()); selfTy = F.mapTypeIntoContext(selfTy); ManagedValue selfArg = B.createInputFunctionArgument(selfTy, loc); // Forward substitutions. auto subs = F.getForwardingSubstitutionMap(); auto toFnAndRef = getNextUncurryLevelRef(*this, loc, thunk, selfArg, subs); ManagedValue toFn = toFnAndRef.first; SILDeclRef calleeRef = toFnAndRef.second; SILType resultTy = fromConv.getSingleSILResultType(); resultTy = F.mapTypeIntoContext(resultTy); // Partially apply the next uncurry level and return the result closure. selfArg = selfArg.ensurePlusOne(*this, loc); auto calleeConvention = ParameterConvention::Direct_Guaranteed; ManagedValue toClosure = B.createPartialApply(loc, toFn, subs, {selfArg}, calleeConvention); if (resultTy != toClosure.getType()) { CanSILFunctionType resultFnTy = resultTy.castTo<SILFunctionType>(); CanSILFunctionType closureFnTy = toClosure.getType().castTo<SILFunctionType>(); if (resultFnTy->isABICompatibleWith(closureFnTy).isCompatible()) { toClosure = B.createConvertFunction(loc, toClosure, resultTy); } else { // Compute the partially-applied abstraction pattern for the callee: // just grab the pattern for the curried fn ref and "call" it. assert(!calleeRef.isCurried); calleeRef.isCurried = true; auto appliedFnPattern = SGM.Types.getConstantInfo(calleeRef).FormalPattern .getFunctionResultType(); auto appliedThunkPattern = thunkInfo.FormalPattern.getFunctionResultType(); // The formal type should be the same for the callee and the thunk. auto formalType = thunkInfo.FormalType; if (auto genericSubstType = dyn_cast<GenericFunctionType>(formalType)) { formalType = genericSubstType.substGenericArgs(subs); } formalType = cast<AnyFunctionType>(formalType.getResult()); toClosure = emitTransformedValue(loc, toClosure, appliedFnPattern, formalType, appliedThunkPattern, formalType); } } toClosure = S.popPreservingValue(toClosure); B.createReturn(ImplicitReturnLocation::getImplicitReturnLoc(loc), toClosure); }