//===--- SILVTableVisitor.h - Class vtable visitor --------------*- C++ -*-===// // // This source file is part of the Swift.org open source project // // Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See https://swift.org/LICENSE.txt for license information // See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors // //===----------------------------------------------------------------------===// // // This file defines the SILVTableVisitor class, which is used to generate and // perform lookups in class method vtables. // //===----------------------------------------------------------------------===// #ifndef SWIFT_SIL_SILVTABLEVISITOR_H #define SWIFT_SIL_SILVTABLEVISITOR_H #include #include "swift/AST/Decl.h" #include "swift/AST/Types.h" #include "swift/AST/ASTMangler.h" namespace swift { // Utility class for deterministically ordering vtable entries for // synthesized methods. struct SortedFuncList { using Entry = std::pair; SmallVector elts; bool sorted = false; void add(AbstractFunctionDecl *afd) { Mangle::ASTMangler mangler; std::string mangledName; if (auto *cd = dyn_cast(afd)) mangledName = mangler.mangleConstructorEntity(cd, 0, 0); else mangledName = mangler.mangleEntity(afd, 0); elts.push_back(std::make_pair(mangledName, afd)); } bool empty() { return elts.empty(); } void sort() { assert(!sorted); sorted = true; std::sort(elts.begin(), elts.end(), [](const Entry &lhs, const Entry &rhs) -> bool { return lhs.first < rhs.first; }); } decltype(elts)::const_iterator begin() const { assert(sorted); return elts.begin(); } decltype(elts)::const_iterator end() const { assert(sorted); return elts.end(); } }; /// A CRTP class for visiting virtually-dispatched methods of a class. /// /// You must override these two methods in your subclass: /// /// - addMethod(SILDeclRef): /// introduce a new vtable entry /// /// - addMethodOverride(SILDeclRef baseRef, SILDeclRef derivedRef): /// update vtable entry for baseRef to call derivedRef /// /// - addPlaceholder(MissingMemberDecl *); /// introduce an entry for a method that could not be deserialized /// template class SILVTableVisitor { T &asDerived() { return *static_cast(this); } void maybeAddMethod(FuncDecl *fd) { assert(!fd->hasClangNode()); SILDeclRef constant(fd, SILDeclRef::Kind::Func); maybeAddEntry(constant, constant.requiresNewVTableEntry()); } void maybeAddConstructor(ConstructorDecl *cd) { assert(!cd->hasClangNode()); // The allocating entry point is what is used for dynamic dispatch. // The initializing entry point for designated initializers is only // necessary for super.init chaining, which is sufficiently constrained // to never need dynamic dispatch. SILDeclRef constant(cd, SILDeclRef::Kind::Allocator); maybeAddEntry(constant, constant.requiresNewVTableEntry()); } void maybeAddEntry(SILDeclRef declRef, bool needsNewEntry) { // Introduce a new entry if required. if (needsNewEntry) asDerived().addMethod(declRef); // Update any existing entries that it overrides. auto nextRef = declRef; while ((nextRef = nextRef.getNextOverriddenVTableEntry())) { auto baseRef = nextRef.getOverriddenVTableEntry(); asDerived().addMethodOverride(baseRef, declRef); nextRef = baseRef; } } void maybeAddMember(Decl *member) { if (auto *fd = dyn_cast(member)) maybeAddMethod(fd); else if (auto *cd = dyn_cast(member)) maybeAddConstructor(cd); else if (auto *placeholder = dyn_cast(member)) asDerived().addPlaceholder(placeholder); } protected: void addVTableEntries(ClassDecl *theClass) { // Imported classes do not have a vtable. if (!theClass->hasKnownSwiftImplementation()) return; // Note that while vtable order is not ABI, we still want it to be // consistent between translation units. // // So, sort synthesized members by their mangled name, since they // are added lazily during type checking, with the remaining ones // forced at the end. SortedFuncList synthesizedMembers; for (auto member : theClass->getMembers()) { if (auto *afd = dyn_cast(member)) { if (afd->isSynthesized()) { synthesizedMembers.add(afd); continue; } } maybeAddMember(member); } if (synthesizedMembers.empty()) return; synthesizedMembers.sort(); for (const auto &pair : synthesizedMembers) { maybeAddMember(pair.second); } } }; } #endif