Optional<SILVTable::Entry> SILGenModule::emitVTableMethod(ClassDecl *theClass, SILDeclRef derived, SILDeclRef base) { assert(base.kind == derived.kind); auto *baseDecl = base.getDecl(); auto *derivedDecl = derived.getDecl(); // Note: We intentionally don't support extension members here. // // Once extensions can override or introduce new vtable entries, this will // all likely change anyway. auto *baseClass = cast<ClassDecl>(baseDecl->getDeclContext()); auto *derivedClass = cast<ClassDecl>(derivedDecl->getDeclContext()); // Figure out if the vtable entry comes from the superclass, in which // case we won't emit it if building a resilient module. SILVTable::Entry::Kind implKind; if (baseClass == theClass) { // This is a vtable entry for a method of the immediate class. implKind = SILVTable::Entry::Kind::Normal; } else if (derivedClass == theClass) { // This is a vtable entry for a method of a base class, but it is being // overridden in the immediate class. implKind = SILVTable::Entry::Kind::Override; } else { // This vtable entry is copied from the superclass. implKind = SILVTable::Entry::Kind::Inherited; // If the override is defined in a class from a different resilience // domain, don't emit the vtable entry. if (derivedClass->isResilient(M.getSwiftModule(), ResilienceExpansion::Maximal)) { return None; } } SILFunction *implFn; SILLinkage implLinkage; // If the member is dynamic, reference its dynamic dispatch thunk so that // it will be redispatched, funneling the method call through the runtime // hook point. if (derivedDecl->isDynamic() && derived.kind != SILDeclRef::Kind::Allocator) { implFn = getDynamicThunk(derived, Types.getConstantInfo(derived).SILFnType); implLinkage = SILLinkage::Public; } else { implFn = getFunction(derived, NotForDefinition); implLinkage = stripExternalFromLinkage(implFn->getLinkage()); } // As a fast path, if there is no override, definitely no thunk is necessary. if (derived == base) return SILVTable::Entry(base, implFn, implKind, implLinkage); // Determine the derived thunk type by lowering the derived type against the // abstraction pattern of the base. auto baseInfo = Types.getConstantInfo(base); auto derivedInfo = Types.getConstantInfo(derived); auto basePattern = AbstractionPattern(baseInfo.LoweredType); auto overrideInfo = M.Types.getConstantOverrideInfo(derived, base); // The override member type is semantically a subtype of the base // member type. If the override is ABI compatible, we do not need // a thunk. if (M.Types.checkFunctionForABIDifferences(derivedInfo.SILFnType, overrideInfo.SILFnType) == TypeConverter::ABIDifference::Trivial) return SILVTable::Entry(base, implFn, implKind, implLinkage); // Generate the thunk name. std::string name; { Mangle::ASTMangler mangler; if (isa<FuncDecl>(baseDecl)) { name = mangler.mangleVTableThunk( cast<FuncDecl>(baseDecl), cast<FuncDecl>(derivedDecl)); } else { name = mangler.mangleConstructorVTableThunk( cast<ConstructorDecl>(baseDecl), cast<ConstructorDecl>(derivedDecl), base.kind == SILDeclRef::Kind::Allocator); } } // If we already emitted this thunk, reuse it. if (auto existingThunk = M.lookUpFunction(name)) return SILVTable::Entry(base, existingThunk, implKind, implLinkage); // Emit the thunk. SILLocation loc(derivedDecl); SILGenFunctionBuilder builder(*this); auto thunk = builder.createFunction( SILLinkage::Private, name, overrideInfo.SILFnType, cast<AbstractFunctionDecl>(derivedDecl)->getGenericEnvironment(), loc, IsBare, IsNotTransparent, IsNotSerialized); thunk->setDebugScope(new (M) SILDebugScope(loc, thunk)); SILGenFunction(*this, *thunk, theClass) .emitVTableThunk(derived, implFn, basePattern, overrideInfo.LoweredType, derivedInfo.LoweredType); return SILVTable::Entry(base, thunk, implKind, implLinkage); }