blob: 73a343fc1b9cdfaf4ce4eb563fd9c5298286b700 [file] [log] [blame]
//===--- SILOpenedArchetypesTracker.cpp - Track opened archetypes ---------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See http://swift.org/LICENSE.txt for license information
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
#include "swift/SIL/SILOpenedArchetypesTracker.h"
using namespace swift;
void SILOpenedArchetypesTracker::addOpenedArchetypeDef(Type archetype,
SILValue Def) {
archetype = archetype->getDesugaredType();
assert(archetype->is<ArchetypeType>() && "The type should be an archetype");
auto OldDef = getOpenedArchetypeDef(archetype);
if (OldDef && isa<GlobalAddrInst>(OldDef)) {
// It is a forward definition created during deserialization.
// Replace it with the real definition now.
OldDef->replaceAllUsesWith(Def);
OldDef = SILValue();
}
assert(!OldDef &&
"There can be only one definition of an opened archetype");
OpenedArchetypeDefs[archetype] = Def;
}
/// Check if there are any unresolved forward definitions of opened
/// archetypes.
bool SILOpenedArchetypesTracker::hasUnresolvedOpenedArchetypeDefinitions() {
for (auto &KV : getOpenedArchetypeDefs()) {
assert(KV.getFirst()->is<ArchetypeType>() && "The type should be an archetype");
if (!KV.getSecond() || isa<GlobalAddrInst>(KV.getSecond()))
return true;
}
return false;
}
void SILOpenedArchetypesTracker::registerUsedOpenedArchetypes(Type Ty) {
// Nothing else to be done if the type does not contain an opened archetype.
if (!Ty || !Ty->hasOpenedExistential())
return;
// Find all opened existentials used by this type and check if their
// definitions are known.
Ty.visit([&](Type ty) {
if (!ty->isOpenedExistential())
return;
ty = ty->getDesugaredType();
// Nothing to do if a definition was seen already.
if (getOpenedArchetypeDef(ty))
return;
auto &SILMod = this->getFunction().getModule();
// Create a placeholder representing a forward definition.
auto Placeholder = new (SILMod)
GlobalAddrInst(SILDebugLocation(), SILMod.Types.getLoweredType(ty));
// Make it available to SILBuilder, so that instructions using this
// archetype can be constructed.
addOpenedArchetypeDef(ty, Placeholder);
});
}
// Register archetypes opened by a given instruction.
// Can be used to incrementally populate the mapping, e.g.
// if it is done when performing a scan of all instructions
// inside a function.
void SILOpenedArchetypesTracker::registerOpenedArchetypes(
const SILInstruction *I) {
assert((!I->getParent() || I->getFunction() == &F) &&
"Instruction does not belong to a proper SILFunction");
auto Archetype = getOpenedArchetypeOf(I);
if (Archetype)
addOpenedArchetypeDef(Archetype, I);
}
// Register opened archetypes whose definitions are referenced by
// the typedef operands of this instruction.
void SILOpenedArchetypesTracker::registerUsedOpenedArchetypes(
const SILInstruction *I) {
assert((!I->getParent() || I->getFunction() == &F) &&
"Instruction does not belong to a proper SILFunction");
for (auto &Op : I->getOpenedArchetypeOperands()) {
auto OpenedArchetypeDef = Op.get();
assert(isa<SILInstruction>(OpenedArchetypeDef) &&
"typedef operand should refer to a SILInstruction");
addOpenedArchetypeDef(
getOpenedArchetypeOf(cast<SILInstruction>(OpenedArchetypeDef)),
OpenedArchetypeDef);
}
}
// Unregister archetypes opened by a given instruction.
// Should be only called when this instruction is to be removed.
void SILOpenedArchetypesTracker::unregisterOpenedArchetypes(
const SILInstruction *I) {
assert(I->getFunction() == &F &&
"Instruction does not belong to a proper SILFunction");
auto Archetype = getOpenedArchetypeOf(I);
if (Archetype)
removeOpenedArchetypeDef(Archetype, I);
}
void SILOpenedArchetypesTracker::handleDeleteNotification(
swift::ValueBase *Value) {
if (auto I = dyn_cast<SILInstruction>(Value))
if (I->getFunction() == &F)
unregisterOpenedArchetypes(I);
}
/// Find an opened archetype defined by an instruction.
/// \returns The found archetype or empty type otherwise.
CanType swift::getOpenedArchetypeOf(const SILInstruction *I) {
if (isa<OpenExistentialAddrInst>(I) || isa<OpenExistentialRefInst>(I) ||
isa<OpenExistentialBoxInst>(I) || isa<OpenExistentialMetatypeInst>(I)) {
auto Ty = getOpenedArchetypeOf(I->getType().getSwiftRValueType());
assert(Ty->isOpenedExistential() && "Type should be an opened archetype");
return Ty;
}
return CanType();
}
bool hasAtMostOneOpenedArchetype(CanType Ty) {
int NumOpenedArchetypes = 0;
Ty.visit([&](Type t) {
if (t->isOpenedExistential()) {
NumOpenedArchetypes++;
}
return;
});
return NumOpenedArchetypes <= 1;
}
/// Find an opened archetype represented by this type.
/// It is assumed by this method that the type contains
/// at most one opened archetype.
/// Typically, it would be called from a type visitor.
/// It checks only the type itself, but does not try to
/// recursively check any children of this type, because
/// this is the task of the type visitor invoking it.
/// \returns The found archetype or empty type otherwise.
CanType swift::getOpenedArchetypeOf(CanType Ty) {
if (!Ty)
return CanType();
assert(hasAtMostOneOpenedArchetype(Ty) &&
"Type should contain at most one opened archetype");
while (auto MetaTy = dyn_cast<AnyMetatypeType>(Ty)) {
Ty = MetaTy->getInstanceType().getCanonicalTypeOrNull();
}
if (Ty->isOpenedExistential())
return Ty;
return CanType();
}
SILValue SILOpenedArchetypesState::getOpenedArchetypeDef(Type Ty) const {
if (!Ty)
return SILValue();
auto CanTy = Ty.getCanonicalTypeOrNull();
// First perform a quick check.
for (auto &Op : OpenedArchetypeOperands) {
auto Def = Op.get();
if (getOpenedArchetypeOf(cast<SILInstruction>(Def)) == CanTy)
return Def;
}
// Then use a regular lookup.
if (OpenedArchetypesTracker)
return OpenedArchetypesTracker->getOpenedArchetypeDef(Ty);
return SILValue();
}