Skip to content

Commit

Permalink
Only store the minimal requirements in generic metadata, where
Browse files Browse the repository at this point in the history
"minimal" is defined as the set of requirements that would be
passed to a function with the type's generic signature that
takes the thick metadata of the parent type as its only argument.
  • Loading branch information
rjmccall committed Feb 25, 2016
1 parent 66b0b57 commit 3ce1ba3
Show file tree
Hide file tree
Showing 26 changed files with 1,121 additions and 737 deletions.
57 changes: 57 additions & 0 deletions include/swift/ABI/MetadataValues.h
Original file line number Diff line number Diff line change
Expand Up @@ -237,6 +237,63 @@ enum class ProtocolDispatchStrategy: uint8_t {
Empty = 2,
};

/// Flags in a generic nominal type descriptor.
class GenericParameterDescriptorFlags {
typedef uint32_t int_type;
enum : int_type {
HasParent = 0x01,
HasGenericParent = 0x02,
};
int_type Data;

constexpr GenericParameterDescriptorFlags(int_type data) : Data(data) {}
public:
constexpr GenericParameterDescriptorFlags() : Data(0) {}

constexpr GenericParameterDescriptorFlags withHasParent(bool b) const {
return GenericParameterDescriptorFlags(b ? (Data | HasParent)
: (Data & ~HasParent));
}

constexpr GenericParameterDescriptorFlags withHasGenericParent(bool b) const {
return GenericParameterDescriptorFlags(b ? (Data | HasGenericParent)
: (Data & ~HasGenericParent));
}

/// Does this type have a lexical parent type?
///
/// For class metadata, if this is true, the storage for the parent type
/// appears immediately prior to the first generic argument. Other
/// metadata always have a slot for their parent type.
bool hasParent() const {
return Data & HasParent;
}

/// Given that this type has a parent type, is that type generic? If so,
/// it forms part of the key distinguishing this metadata from other
/// metadata, and the parent metadata will be the first argument to
/// the generic metadata access function.
bool hasGenericParent() const {
return Data & HasGenericParent;
}

int_type getIntValue() const {
return Data;
}

static GenericParameterDescriptorFlags fromIntValue(int_type Data) {
return GenericParameterDescriptorFlags(Data);
}

bool operator==(GenericParameterDescriptorFlags other) const {
return Data == other.Data;
}
bool operator!=(GenericParameterDescriptorFlags other) const {
return Data != other.Data;
}
};


/// Flags for protocol descriptors.
class ProtocolDescriptorFlags {
typedef uint32_t int_type;
Expand Down
68 changes: 40 additions & 28 deletions include/swift/Runtime/Metadata.h
Original file line number Diff line number Diff line change
Expand Up @@ -1208,34 +1208,37 @@ struct HeapMetadata : Metadata {
/// structure that describes how to find and parse a generic parameter vector
/// within the type metadata for an instance of a nominal type.
struct GenericParameterDescriptor {
/// The offset of the descriptor in the metadata record. If NumParams is zero,
/// this value is meaningless.
/// The offset of the descriptor in the metadata record. This is
/// meaningful if either NumGenericRequirements is nonzero or
/// (for classes) if Flags.hasParent() is true.
uint32_t Offset;
/// The number of type parameters. A value of zero means there is no generic
/// parameter vector. This includes associated types of the primary type
/// parameters.
uint32_t NumParams;

/// The amount of generic requirement data in the metadata record, in
/// words, excluding the lexical parent type. A value of zero means
/// there is no generic requirement data.
///
/// This may include protocol witness tables for type parameters or
/// their associated types.
uint32_t NumGenericRequirements;

/// The number of primary type parameters. This is always less than or equal
/// to NumParams; it counts only the primary type parameters and not their
/// associated types.
/// to NumGenericRequirements; it counts only the type parameters
/// and not any required witness tables.
uint32_t NumPrimaryParams;

/// True if the nominal type has generic parameters.
bool hasGenericParams() const { return NumParams > 0; }

/// A type parameter.
struct Parameter {
/// The number of protocol witness tables required by this type parameter.
uint32_t NumWitnessTables;

// TODO: This is the bare minimum to be able to parse an opaque generic
// parameter vector. Should we include additional info, such as the
// required protocols?
};

/// The parameter descriptors are in a tail-emplaced array of NumParams
/// elements.
Parameter Parameters[1];
/// Flags for this generic parameter descriptor.
GenericParameterDescriptorFlags Flags;

/// True if the nominal type has generic requirements other than its
/// parent metadata.
bool hasGenericRequirements() const { return NumGenericRequirements > 0; }

/// True if the nominal type is generic in any way.
bool isGeneric() const {
return hasGenericRequirements() || Flags.hasGenericParent();
}

// TODO: add meaningful descriptions of the generic requirements.
};

struct ClassTypeDescriptor;
Expand Down Expand Up @@ -1566,6 +1569,16 @@ struct ClassMetadata : public HeapMetadata {
return getter(this);
}

/// Return the parent type for a given level in the class hierarchy, or
/// null if that level does not have a parent type.
const Metadata *getParentType(const NominalTypeDescriptor *theClass) const {
if (!theClass->GenericParams.Flags.hasParent())
return nullptr;

auto metadataAsWords = reinterpret_cast<const Metadata * const *>(this);
return metadataAsWords[theClass->GenericParams.Offset - 1];
}

static bool classof(const Metadata *metadata) {
return metadata->getKind() == MetadataKind::Class;
}
Expand Down Expand Up @@ -1739,12 +1752,11 @@ struct ValueMetadata : public Metadata {

/// Retrieve the generic arguments of this type.
const Metadata * const *getGenericArgs() const {
if (Description->GenericParams.NumParams == 0)
if (!Description->GenericParams.hasGenericRequirements())
return nullptr;

const void* const *asWords = reinterpret_cast<const void * const *>(this);
asWords += Description->GenericParams.Offset;
return reinterpret_cast<const Metadata * const *>(asWords);
auto asWords = reinterpret_cast<const Metadata * const *>(this);
return (asWords + Description->GenericParams.Offset);
}
};

Expand Down
26 changes: 7 additions & 19 deletions lib/IRGen/ClassMetadataLayout.h
Original file line number Diff line number Diff line change
Expand Up @@ -73,23 +73,23 @@ template <class Impl> class ClassMetadataLayout : public MetadataLayout<Impl> {
asImpl().addIVarDestroyer();

// Class members.
addClassMembers(Target);
addClassMembers(Target, Target->getDeclaredTypeInContext());
}

private:
/// Add fields associated with the given class and its bases.
void addClassMembers(ClassDecl *theClass) {
void addClassMembers(ClassDecl *theClass, Type type) {
// Add any fields associated with the superclass.
// NB: We don't apply superclass substitutions to members because we want
// consistent metadata layout between generic superclasses and concrete
// subclasses.
if (Type superclass = theClass->getSuperclass()) {
if (Type superclass = type->getSuperclass(nullptr)) {
ClassDecl *superclassDecl = superclass->getClassOrBoundGenericClass();
// Skip superclass fields if superclass is resilient.
// FIXME: Needs runtime support to ensure the field offset vector is
// populated correctly.
if (!IGM.isResilient(superclassDecl, ResilienceExpansion::Maximal)) {
addClassMembers(superclass->getClassOrBoundGenericClass());
addClassMembers(superclassDecl, superclass);
}
}

Expand All @@ -101,9 +101,7 @@ template <class Impl> class ClassMetadataLayout : public MetadataLayout<Impl> {
// Add space for the generic parameters, if applicable.
// Note that we only add references for the immediate parameters;
// parameters for the parent context are handled by the parent.
if (auto generics = theClass->getGenericParams()) {
addGenericClassFields(theClass, *generics);
}
asImpl().addGenericFields(theClass, type, theClass);

// Add entries for the methods.
for (auto member : theClass->getMembers()) {
Expand Down Expand Up @@ -177,15 +175,6 @@ template <class Impl> class ClassMetadataLayout : public MetadataLayout<Impl> {
void noteEndOfFieldOffsets(ClassDecl *whichClass) {}

private:
/// Add fields related to the generics of this class declaration.
/// TODO: don't add new fields that are implied by the superclass.
/// fields. e.g., if B<T> extends A<T>, the witness for T in A's
/// section should be enough.
void addGenericClassFields(ClassDecl *theClass,
const GenericParamList &generics) {
asImpl().addGenericFields(generics, theClass);
}

void addFieldEntries(VarDecl *field) {
asImpl().addFieldOffset(field);
}
Expand Down Expand Up @@ -258,11 +247,10 @@ class ClassMetadataScanner : public ClassMetadataLayout<Impl> {
addPointer();
}
void addFieldOffset(VarDecl *var) { addPointer(); }
void addGenericArgument(ArchetypeType *argument, ClassDecl *forClass) {
void addGenericArgument(CanType argument, ClassDecl *forClass) {
addPointer();
}
void addGenericWitnessTable(ArchetypeType *argument,
ProtocolDecl *protocol,
void addGenericWitnessTable(CanType argument, ProtocolConformanceRef conf,
ClassDecl *forClass) {
addPointer();
}
Expand Down
8 changes: 3 additions & 5 deletions lib/IRGen/EnumMetadataLayout.h
Original file line number Diff line number Diff line change
Expand Up @@ -60,8 +60,7 @@ template <class Impl> class EnumMetadataLayout : public MetadataLayout<Impl> {
asImpl().addPayloadSize();

// Add fields for generic cases.
if (auto generics = Target->getGenericParamsOfContext())
asImpl().addGenericFields(*generics);
asImpl().addGenericFields(Target, Target->getDeclaredTypeInContext());
}
};

Expand All @@ -82,9 +81,8 @@ class EnumMetadataScanner : public EnumMetadataLayout<Impl> {
void addValueWitnessTable() { addPointer(); }
void addNominalTypeDescriptor() { addPointer(); }
void addParentMetadataRef() { addPointer(); }
void addGenericArgument(ArchetypeType *argument) { addPointer(); }
void addGenericWitnessTable(ArchetypeType *argument,
ProtocolDecl *protocol) {
void addGenericArgument(CanType argument) { addPointer(); }
void addGenericWitnessTable(CanType argument, ProtocolConformanceRef conf) {
addPointer();
}
void addPayloadSize() { addPointer(); }
Expand Down
Loading

0 comments on commit 3ce1ba3

Please sign in to comment.