blob: 79fc99a5d67cfdc1fbb7c9a6d25ac3ee373058af [file] [log] [blame]
//===--- MetadataPath.h - Path for lazily finding type metadata -*- C++ -*-===//
//
// 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
//
//===----------------------------------------------------------------------===//
//
// This file defines the MetadataPath type, which efficiently records the
// path to a metadata object.
//
//===----------------------------------------------------------------------===//
#ifndef SWIFT_IRGEN_METADATAPATH_H
#define SWIFT_IRGEN_METADATAPATH_H
#include "swift/Basic/EncodedSequence.h"
namespace llvm {
class Value;
}
namespace swift {
class ProtocolDecl;
class CanType;
class Decl;
namespace irgen {
class IRGenFunction;
/// A path from one source metadata --- either Swift type metadata or a Swift
/// protocol conformance --- to another.
class MetadataPath {
class Component {
public:
enum class Kind {
// Some components carry indices.
// P means the primary index.
// S means the secondary index.
/// Protocol conformance S of type argument P of a generic nominal type.
NominalTypeArgumentConformance,
LastWithSecondaryIndex = NominalTypeArgumentConformance,
// Everything past this point has at most one index.
/// Base protocol P of a protocol.
InheritedProtocol,
/// Type argument P of a generic nominal type.
NominalTypeArgument,
LastWithPrimaryIndex = NominalTypeArgument,
// Everything past this point has no index.
/// The parent metadata of a nominal type.
NominalParent,
/// An impossible path.
Impossible,
};
private:
unsigned Primary;
unsigned Secondary;
enum {
KindMask = 0xF,
IndexShift = 4,
};
static bool hasPrimaryIndex(Kind kind) {
return kind <= Kind::LastWithPrimaryIndex;
}
static bool hasSecondaryIndex(Kind kind) {
return kind <= Kind::LastWithSecondaryIndex;
}
explicit Component(unsigned primary, unsigned secondary)
: Primary(primary), Secondary(secondary) {}
public:
explicit Component(Kind kind)
: Primary(unsigned(kind)), Secondary(0) {
assert(!hasPrimaryIndex(kind));
}
explicit Component(Kind kind, unsigned primaryIndex)
: Primary(unsigned(kind) | (primaryIndex << IndexShift)),
Secondary(0) {
assert(hasPrimaryIndex(kind));
assert(!hasSecondaryIndex(kind));
}
explicit Component(Kind kind, unsigned primaryIndex,
unsigned secondaryIndex)
: Primary(unsigned(kind) | (primaryIndex << IndexShift)),
Secondary(secondaryIndex) {
assert(hasSecondaryIndex(kind));
}
Kind getKind() const { return Kind(Primary & KindMask); }
unsigned getPrimaryIndex() const {
assert(hasPrimaryIndex(getKind()));
return (Primary >> IndexShift);
}
unsigned getSecondaryIndex() const {
assert(hasSecondaryIndex(getKind()));
return (Secondary);
}
/// Return an abstract measurement of the cost of this component.
unsigned cost() const {
// Right now, all components cost the same: they take one load.
// In the future, maybe some components will be cheaper (no loads,
// like loading from a superclass's metadata) or more expensive
// (multiple loads, or even a call).
return 1;
}
static Component decode(const EncodedSequenceBase::Chunk *&ptr) {
unsigned primary = EncodedSequenceBase::decodeIndex(ptr);
unsigned secondary =
(hasSecondaryIndex(Kind(primary & KindMask))
? EncodedSequenceBase::decodeIndex(ptr) : 0);
return Component(primary, secondary);
}
void encode(EncodedSequenceBase::Chunk *&ptr) const {
EncodedSequenceBase::encodeIndex(Primary, ptr);
if (hasSecondaryIndex(getKind()))
EncodedSequenceBase::encodeIndex(Secondary, ptr);
}
unsigned getEncodedSize() const {
auto size = EncodedSequenceBase::getEncodedIndexSize(Primary);
if (hasSecondaryIndex(getKind()))
size += EncodedSequenceBase::getEncodedIndexSize(Secondary);
return size;
}
};
EncodedSequence<Component> Path;
public:
MetadataPath() {}
using iterator = EncodedSequence<Component>::iterator;
template <class ValueType>
using Map = EncodedSequence<Component>::Map<ValueType>;
/// Add a step to this path which will cause a dynamic assertion if
/// it's followed.
void addImpossibleComponent() {
Path.push_back(Component(Component::Kind::Impossible));
}
/// Add a step to this path which gets the parent metadata.
void addNominalParentComponent() {
Path.push_back(Component(Component::Kind::NominalParent));
}
/// Add a step to this path which gets the nth type argument of a generic
/// type metadata.
void addNominalTypeArgumentComponent(unsigned index) {
Path.push_back(Component(Component::Kind::NominalTypeArgument, index));
}
/// Add a step to this path which gets the kth protocol conformance of
/// the nth type argument of a generic type metadata.
void addNominalTypeArgumentConformanceComponent(unsigned argIndex,
unsigned conformanceIndex) {
Path.push_back(Component(Component::Kind::NominalTypeArgumentConformance,
argIndex, conformanceIndex));
}
/// Add a step to this path which gets the kth inherited protocol from a
/// witness table.
///
/// k is computed including protocols which do not have witness tables.
void addInheritedProtocolComponent(unsigned index) {
Path.push_back(Component(Component::Kind::InheritedProtocol, index));
}
/// Return an abstract measurement of the cost of this path.
unsigned cost() const {
unsigned cost = 0;
for (const Component &component : Path)
cost += component.cost();
return cost;
}
/// Given a pointer to type metadata, follow a path from it.
llvm::Value *followFromTypeMetadata(IRGenFunction &IGF,
CanType sourceType,
llvm::Value *source,
Map<llvm::Value*> *cache) const;
/// Given a pointer to a protocol witness table, follow a path from it.
llvm::Value *followFromWitnessTable(IRGenFunction &IGF,
ProtocolDecl *sourceDecl,
llvm::Value *source,
Map<llvm::Value*> *cache) const;
private:
static llvm::Value *follow(IRGenFunction &IGF,
CanType sourceType,
Decl *sourceDecl,
llvm::Value *source,
MetadataPath::iterator begin,
MetadataPath::iterator end,
Map<llvm::Value*> *cache);
static llvm::Value *followComponent(IRGenFunction &IGF,
CanType &sourceType,
Decl *&sourceDecl,
llvm::Value *source,
Component component);
};
} // end namespace irgen
} // end namespace swift
#endif