std::tuple<ManagedValue, SILType> SILGenFunction::emitSiblingMethodRef(SILLocation loc, SILValue selfValue, SILDeclRef methodConstant, const SubstitutionMap &subMap) { SILValue methodValue; // If the method is dynamic, access it through runtime-hookable virtual // dispatch (viz. objc_msgSend for now). if (methodConstant.hasDecl() && methodConstant.getDecl()->isDynamic()) { methodValue = emitDynamicMethodRef(loc, methodConstant, SGM.Types.getConstantInfo(methodConstant).SILFnType); } else { methodValue = emitGlobalFunctionRef(loc, methodConstant); } SILType methodTy = methodValue->getType(); // Specialize the generic method. methodTy = methodTy.substGenericArgs(SGM.M, subMap); return std::make_tuple(ManagedValue::forUnmanaged(methodValue), methodTy); }
std::tuple<ManagedValue, SILType, ArrayRef<Substitution>> SILGenFunction::emitSiblingMethodRef(SILLocation loc, SILValue selfValue, SILDeclRef methodConstant, ArrayRef<Substitution> subs) { SILValue methodValue; // If the method is dynamic, access it through runtime-hookable virtual // dispatch (viz. objc_msgSend for now). if (methodConstant.hasDecl() && methodConstant.getDecl()->getAttrs().hasAttribute<DynamicAttr>()) methodValue = emitDynamicMethodRef(loc, methodConstant, SGM.Types.getConstantInfo(methodConstant)); else methodValue = emitGlobalFunctionRef(loc, methodConstant); SILType methodTy = methodValue->getType(); if (!subs.empty()) { // Specialize the generic method. methodTy = getLoweredLoadableType( methodTy.castTo<SILFunctionType>() ->substGenericArgs(SGM.M, SGM.SwiftModule, subs)); } return std::make_tuple(ManagedValue::forUnmanaged(methodValue), methodTy, subs); }
SILValue SILGenFunction::emitGlobalFunctionRef(SILLocation loc, SILDeclRef constant, SILConstantInfo constantInfo) { assert(constantInfo == getConstantInfo(constant)); // Builtins must be fully applied at the point of reference. if (constant.hasDecl() && isa<BuiltinUnit>(constant.getDecl()->getDeclContext())) { SGM.diagnose(loc.getSourceLoc(), diag::not_implemented, "delayed application of builtin"); return SILUndef::get(constantInfo.getSILType(), SGM.M); } // If the constant is a thunk we haven't emitted yet, emit it. if (!SGM.hasFunction(constant)) { if (constant.isCurried) { SGM.emitCurryThunk(constant); } else if (constant.isForeignToNativeThunk()) { SGM.emitForeignToNativeThunk(constant); } else if (constant.isNativeToForeignThunk()) { SGM.emitNativeToForeignThunk(constant); } else if (constant.kind == SILDeclRef::Kind::EnumElement) { SGM.emitEnumConstructor(cast<EnumElementDecl>(constant.getDecl())); } } auto f = SGM.getFunction(constant, NotForDefinition); assert(f->getLoweredFunctionType() == constantInfo.SILFnType); return B.createFunctionRef(loc, f); }
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_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?"); // 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"); }
static SILValue getNextUncurryLevelRef(SILGenFunction &gen, SILLocation loc, SILDeclRef next, bool direct, ArrayRef<SILValue> curriedArgs, ArrayRef<Substitution> curriedSubs) { // For a foreign function, reference the native thunk. if (next.isForeign) return gen.emitGlobalFunctionRef(loc, next.asForeign(false)); // If the fully-uncurried reference is to a native dynamic class method, emit // the dynamic dispatch. auto fullyAppliedMethod = !next.isCurried && !next.isForeign && !direct && next.hasDecl(); auto constantInfo = gen.SGM.Types.getConstantInfo(next); SILValue thisArg; if (!curriedArgs.empty()) thisArg = curriedArgs.back(); if (fullyAppliedMethod && isa<AbstractFunctionDecl>(next.getDecl()) && gen.getMethodDispatch(cast<AbstractFunctionDecl>(next.getDecl())) == MethodDispatch::Class) { SILValue thisArg = curriedArgs.back(); // Use the dynamic thunk if dynamic. if (next.getDecl()->isDynamic()) { auto dynamicThunk = gen.SGM.getDynamicThunk(next, constantInfo); return gen.B.createFunctionRef(loc, dynamicThunk); } return gen.B.createClassMethod(loc, thisArg, next); } // If the fully-uncurried reference is to a generic method, look up the // witness. if (fullyAppliedMethod && constantInfo.SILFnType->getRepresentation() == SILFunctionTypeRepresentation::WitnessMethod) { auto thisType = curriedSubs[0].getReplacement()->getCanonicalType(); assert(isa<ArchetypeType>(thisType) && "no archetype for witness?!"); SILValue OpenedExistential; if (!cast<ArchetypeType>(thisType)->getOpenedExistentialType().isNull()) OpenedExistential = thisArg; return gen.B.createWitnessMethod(loc, thisType, nullptr, next, constantInfo.getSILType(), OpenedExistential); } // Otherwise, emit a direct call. return gen.emitGlobalFunctionRef(loc, next); }
SILValue SILGenFunction::emitGlobalFunctionRef(SILLocation loc, SILDeclRef constant, SILConstantInfo constantInfo) { assert(constantInfo == getConstantInfo(constant)); // Builtins must be fully applied at the point of reference. if (constant.hasDecl() && isa<BuiltinUnit>(constant.getDecl()->getDeclContext())) { SGM.diagnose(loc.getSourceLoc(), diag::not_implemented, "delayed application of builtin"); return SILUndef::get(constantInfo.getSILType(), SGM.M); } // If the constant is a thunk we haven't emitted yet, emit it. if (!SGM.hasFunction(constant)) { if (constant.isCurried) { auto vd = constant.getDecl(); // Reference the next uncurrying level of the function. SILDeclRef next = SILDeclRef(vd, constant.kind, SILDeclRef::ConstructAtBestResilienceExpansion, constant.uncurryLevel + 1); // If the function is fully uncurried and natively foreign, reference its // foreign entry point. if (!next.isCurried) { if (requiresForeignToNativeThunk(vd)) next = next.asForeign(); } // Preserve whether the curry thunks lead to a direct reference to the // method implementation. next = next.asDirectReference(constant.isDirectReference); SGM.emitCurryThunk(vd, constant, next); } // Otherwise, if this is a calling convention thunk we haven't emitted yet, // emit it. else if (constant.isForeignToNativeThunk()) { SGM.emitForeignToNativeThunk(constant); } else if (constant.isNativeToForeignThunk()) { SGM.emitNativeToForeignThunk(constant); } else if (constant.kind == SILDeclRef::Kind::EnumElement) { SGM.emitEnumConstructor(cast<EnumElementDecl>(constant.getDecl())); } } auto f = SGM.getFunction(constant, NotForDefinition); assert(f->getLoweredFunctionType() == constantInfo.SILFnType); return B.createFunctionRef(loc, f); }
void SILGenModule::emitNativeToForeignThunk(SILDeclRef thunk) { // Thunks are always emitted by need, so don't need delayed emission. assert(thunk.isForeign && "native-to-foreign thunks only"); SILFunction *f = getFunction(thunk, ForDefinition); if (thunk.hasDecl()) preEmitFunction(thunk, thunk.getDecl(), f, thunk.getDecl()); else preEmitFunction(thunk, thunk.getAbstractClosureExpr(), f, thunk.getAbstractClosureExpr()); PrettyStackTraceSILFunction X("silgen emitNativeToForeignThunk", f); f->setBare(IsBare); f->setThunk(IsThunk); SILGenFunction(*this, *f).emitNativeToForeignThunk(thunk); postEmitFunction(thunk, f); }
static SILFunction::ClassVisibility_t getClassVisibility(SILDeclRef constant) { if (!constant.hasDecl()) return SILFunction::NotRelevant; // If this declaration is a function which goes into a vtable, then it's // symbol must be as visible as its class. Derived classes even have to put // all less visible methods of the base class into their vtables. auto *FD = dyn_cast<AbstractFunctionDecl>(constant.getDecl()); if (!FD) return SILFunction::NotRelevant; DeclContext *context = FD->getDeclContext(); // Methods from extensions don't go into vtables (yet). if (context->isExtensionContext()) return SILFunction::NotRelevant; auto *classType = context->getAsClassOrClassExtensionContext(); if (!classType || classType->isFinal()) return SILFunction::NotRelevant; if (FD->isFinal() && !FD->getOverriddenDecl()) return SILFunction::NotRelevant; assert(FD->getEffectiveAccess() <= classType->getEffectiveAccess() && "class must be as visible as its members"); switch (classType->getEffectiveAccess()) { case Accessibility::Private: case Accessibility::FilePrivate: return SILFunction::NotRelevant; case Accessibility::Internal: return SILFunction::InternalClass; case Accessibility::Public: case Accessibility::Open: return SILFunction::PublicClass; } llvm_unreachable("Unhandled Accessibility in switch."); }
static std::string mangleConstant(SILDeclRef c, SILDeclRef::ManglingKind Kind) { 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"; switch (Kind) { case SILDeclRef::ManglingKind::Default: if (c.isForeign) { introducer = "_TTo"; } else if (c.isDirectReference) { introducer = "_TTd"; } else if (c.isForeignToNativeThunk()) { introducer = "_TTO"; } break; case SILDeclRef::ManglingKind::VTableMethod: introducer = "_TTV"; break; case SILDeclRef::ManglingKind::DynamicThunk: introducer = "_TTD"; break; } // 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(); // entity ::= 'I' declaration 'i' // stored property initializer case SILDeclRef::Kind::StoredPropertyInitializer: mangler.append(introducer); mangler.mangleInitializerEntity(cast<VarDecl>(c.getDecl())); return mangler.finalize(); } llvm_unreachable("bad entity kind!"); }
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!"); }