//===--- 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 "swift/AST/Attr.h" #include "swift/AST/Decl.h" #include "swift/AST/Types.h" #include "swift/SIL/TypeLowering.h" namespace swift { /// 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 /// template class SILVTableVisitor { Lowering::TypeConverter &Types; T &asDerived() { return *static_cast(this); } void maybeAddMethod(FuncDecl *fd) { assert(!fd->hasClangNode()); // Observing accessors and addressors don't get vtable entries. if (fd->isObservingAccessor() || fd->getAddressorKind() != AddressorKind::NotAddressor) return; maybeAddEntry(SILDeclRef(fd, SILDeclRef::Kind::Func)); } void maybeAddConstructor(ConstructorDecl *cd) { assert(!cd->hasClangNode()); SILDeclRef initRef(cd, SILDeclRef::Kind::Initializer); // Stub constructors don't get a vtable entry unless they were synthesized // to override a base class initializer. if (cd->hasStubImplementation() && !initRef.getNextOverriddenVTableEntry()) return; // Required constructors (or overrides thereof) have their allocating entry // point in the vtable. if (cd->isRequired()) maybeAddEntry(SILDeclRef(cd, SILDeclRef::Kind::Allocator)); // All constructors have their initializing constructor in the // vtable, which can be used by a convenience initializer. maybeAddEntry(SILDeclRef(cd, SILDeclRef::Kind::Initializer)); } void maybeAddEntry(SILDeclRef declRef) { // Introduce a new entry if required. if (Types.requiresNewVTableEntry(declRef)) asDerived().addMethod(declRef); // Update any existing entries that it overrides. auto nextRef = declRef; while ((nextRef = nextRef.getNextOverriddenVTableEntry())) { auto baseRef = Types.getOverriddenVTableEntry(nextRef); asDerived().addMethodOverride(baseRef, declRef); nextRef = baseRef; } } protected: SILVTableVisitor(Lowering::TypeConverter &Types) : Types(Types) {} void addVTableEntries(ClassDecl *theClass) { // Imported classes do not have a vtable. if (!theClass->hasKnownSwiftImplementation()) return; for (auto member : theClass->getMembers()) { if (auto *fd = dyn_cast(member)) maybeAddMethod(fd); else if (auto *cd = dyn_cast(member)) maybeAddConstructor(cd); } } }; } #endif