blob: 7072d9af9baa4d878af1480ea664e70adff0dbca [file] [log] [blame]
//===--- 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 <string>
#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<std::string, AbstractFunctionDecl *>;
SmallVector<Entry, 2> elts;
bool sorted = false;
void add(AbstractFunctionDecl *afd) {
Mangle::ASTMangler mangler;
std::string mangledName;
if (auto *cd = dyn_cast<ConstructorDecl>(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 T> class SILVTableVisitor {
T &asDerived() { return *static_cast<T*>(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<FuncDecl>(member))
maybeAddMethod(fd);
else if (auto *cd = dyn_cast<ConstructorDecl>(member))
maybeAddConstructor(cd);
else if (auto *placeholder = dyn_cast<MissingMemberDecl>(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<AbstractFunctionDecl>(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