mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
342 lines
9.7 KiB
C++
342 lines
9.7 KiB
C++
//===--- MetadataLayout.h - Type metadata layout ----------------*- 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
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
//
|
|
// Information recording the layout of type metadata objects.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#ifndef SWIFT_IRGEN_METADATALAYOUT_H
|
|
#define SWIFT_IRGEN_METADATALAYOUT_H
|
|
|
|
#include "IRGen.h"
|
|
#include "swift/SIL/SILDeclRef.h"
|
|
|
|
namespace swift {
|
|
class ClassDecl;
|
|
class EnumDecl;
|
|
class StructDecl;
|
|
class VarDecl;
|
|
|
|
namespace irgen {
|
|
class Address;
|
|
class IRGenFunction;
|
|
class IRGenModule;
|
|
|
|
/// The total size and address point of a metadata object.
|
|
struct MetadataSize {
|
|
Size FullSize;
|
|
Size AddressPoint;
|
|
|
|
/// Return the offset from the address point to the end of the
|
|
/// metadata object.
|
|
Size getOffsetToEnd() const {
|
|
return FullSize - AddressPoint;
|
|
}
|
|
};
|
|
|
|
/// A base class for various kinds of metadata layout.
|
|
class MetadataLayout {
|
|
public:
|
|
enum class Kind {
|
|
Class,
|
|
Struct,
|
|
Enum
|
|
// Update NominalMetadataLayout::classof if you add a non-nominal layout.
|
|
};
|
|
|
|
class StoredOffset {
|
|
enum State {
|
|
/// The high bits are an integer displacement.
|
|
Static = 0,
|
|
|
|
/// The high bits are an llvm::Constant* for the displacement,
|
|
/// which may be null if it hasn't been computed yet.
|
|
Dynamic,
|
|
};
|
|
enum : uint64_t {
|
|
KindBits = 1,
|
|
KindMask = (1 << KindBits) - 1,
|
|
PayloadMask = ~uint64_t(KindMask)
|
|
};
|
|
|
|
mutable uintptr_t Data;
|
|
public:
|
|
StoredOffset() : Data(0) {}
|
|
explicit StoredOffset(llvm::Constant *offset)
|
|
: Data(reinterpret_cast<uintptr_t>(offset) | Dynamic) {}
|
|
explicit StoredOffset(Size offset)
|
|
: Data((static_cast<uint64_t>(offset.getValue()) << KindBits) | Static) {
|
|
assert(!offset.isZero() && "cannot store a zero offset");
|
|
assert(getStaticOffset() == offset && "overflow");
|
|
}
|
|
|
|
bool isValid() const { return Data != 0; }
|
|
bool isStatic() const { return isValid() && (Data & KindMask) == Static; }
|
|
bool isDynamic() const { return (Data & KindMask) == Dynamic; }
|
|
Size getStaticOffset() const {
|
|
assert(isStatic());
|
|
return Size(static_cast<int64_t>(Data) >> KindBits);
|
|
}
|
|
llvm::Constant *getDynamicOffsetVariable() const {
|
|
assert(isDynamic());
|
|
return reinterpret_cast<llvm::Constant*>(Data & PayloadMask);
|
|
}
|
|
void setDynamicOffsetVariable(llvm::Constant *pointer) const {
|
|
assert(isDynamic());
|
|
Data = reinterpret_cast<uintptr_t>(pointer) | Dynamic;
|
|
}
|
|
};
|
|
|
|
private:
|
|
Kind TheKind;
|
|
|
|
protected:
|
|
MetadataSize TheSize;
|
|
|
|
MetadataLayout(Kind theKind) : TheKind(theKind) {}
|
|
|
|
MetadataLayout(const MetadataLayout &other) = delete;
|
|
MetadataLayout &operator=(const MetadataLayout &other) = delete;
|
|
|
|
public:
|
|
/// Destruct and deallocate this layout object.
|
|
void destroy() const;
|
|
|
|
Kind getKind() const { return TheKind; }
|
|
|
|
MetadataSize getSize() const { return TheSize; }
|
|
};
|
|
|
|
/// Base class for nominal type metadata layouts.
|
|
class NominalMetadataLayout : public MetadataLayout {
|
|
protected:
|
|
NominalTypeDecl *Nominal;
|
|
StoredOffset GenericRequirements;
|
|
|
|
NominalMetadataLayout(Kind kind, NominalTypeDecl *nominal)
|
|
: MetadataLayout(kind), Nominal(nominal) {}
|
|
|
|
public:
|
|
NominalTypeDecl *getDecl() const {
|
|
return Nominal;
|
|
}
|
|
|
|
bool hasGenericRequirements() const {
|
|
return GenericRequirements.isValid();
|
|
}
|
|
|
|
/// Should only be used when emitting the nominal type descriptor.
|
|
Size getStaticGenericRequirementsOffset() const;
|
|
|
|
Offset getGenericRequirementsOffset(IRGenFunction &IGF) const;
|
|
|
|
static bool classof(const MetadataLayout *layout) {
|
|
return true; // No non-nominal metadata for now.
|
|
}
|
|
};
|
|
|
|
/// Layout for class type metadata.
|
|
class ClassMetadataLayout : public NominalMetadataLayout {
|
|
public:
|
|
class MethodInfo {
|
|
Offset TheOffset;
|
|
public:
|
|
MethodInfo(Offset offset)
|
|
: TheOffset(offset) {}
|
|
Offset getOffset() const { return TheOffset; }
|
|
};
|
|
|
|
private:
|
|
StoredOffset MetadataSize;
|
|
|
|
StoredOffset InstanceSize;
|
|
StoredOffset InstanceAlignMask;
|
|
|
|
struct StoredMethodInfo {
|
|
StoredOffset TheOffset;
|
|
StoredMethodInfo(StoredOffset offset) : TheOffset(offset) {}
|
|
};
|
|
llvm::DenseMap<SILDeclRef, StoredMethodInfo> MethodInfos;
|
|
|
|
/// Field offsets for various fields.
|
|
llvm::DenseMap<VarDecl*, StoredOffset> FieldOffsets;
|
|
|
|
/// The start of the vtable.
|
|
StoredOffset VTableOffset;
|
|
|
|
/// The start of the field-offset vector.
|
|
StoredOffset FieldOffsetVector;
|
|
|
|
/// The number of members to add after superclass metadata.
|
|
unsigned NumImmediateMembers;
|
|
|
|
const StoredMethodInfo &getStoredMethodInfo(SILDeclRef method) const {
|
|
auto it = MethodInfos.find(method);
|
|
assert(it != MethodInfos.end());
|
|
return it->second;
|
|
}
|
|
|
|
const StoredOffset &getStoredFieldOffset(VarDecl *field) const {
|
|
auto it = FieldOffsets.find(field);
|
|
assert(it != FieldOffsets.end());
|
|
return it->second;
|
|
}
|
|
|
|
friend class IRGenModule;
|
|
ClassMetadataLayout(IRGenModule &IGM, ClassDecl *theClass);
|
|
|
|
public:
|
|
ClassDecl *getDecl() const {
|
|
return cast<ClassDecl>(Nominal);
|
|
}
|
|
|
|
Size getMetadataSizeOffset() const;
|
|
|
|
Size getInstanceSizeOffset() const;
|
|
|
|
Size getInstanceAlignMaskOffset() const;
|
|
|
|
/// Should only be used when emitting the nominal type descriptor.
|
|
Size getStaticVTableOffset() const;
|
|
|
|
/// Returns the start of the vtable in the class metadata.
|
|
Offset getVTableOffset(IRGenFunction &IGF) const;
|
|
|
|
/// Returns the size of the vtable, in words.
|
|
unsigned getVTableSize() const {
|
|
return MethodInfos.size();
|
|
}
|
|
|
|
MethodInfo getMethodInfo(IRGenFunction &IGF, SILDeclRef method) const;
|
|
|
|
/// Assuming that the given method is at a static offset in the metadata,
|
|
/// return that static offset.
|
|
///
|
|
/// DEPRECATED: callers should be updated to handle this in a
|
|
/// more arbitrary fashion.
|
|
Size getStaticMethodOffset(SILDeclRef method) const;
|
|
|
|
Offset getFieldOffset(IRGenFunction &IGF, VarDecl *field) const;
|
|
|
|
/// Assuming that the given field offset is at a static offset in
|
|
/// the metadata, return that static offset.
|
|
///
|
|
/// DEPRECATED: callers should be updated to handle this in a
|
|
/// more arbitrary fashion.
|
|
Size getStaticFieldOffset(VarDecl *field) const;
|
|
|
|
/// Should only be used when emitting the nominal type descriptor.
|
|
Size getStaticFieldOffsetVectorOffset() const;
|
|
|
|
Offset getFieldOffsetVectorOffset(IRGenFunction &IGF) const;
|
|
|
|
/// The number of members to add after superclass metadata. The size of
|
|
/// this metadata is the superclass size plus the number of immediate
|
|
/// members in the class itself.
|
|
unsigned getNumImmediateMembers() const {
|
|
return NumImmediateMembers;
|
|
}
|
|
|
|
static bool classof(const MetadataLayout *layout) {
|
|
return layout->getKind() == Kind::Class;
|
|
}
|
|
};
|
|
|
|
/// Layout for enum type metadata.
|
|
class EnumMetadataLayout : public NominalMetadataLayout {
|
|
/// The offset of the payload size field, if there is one.
|
|
StoredOffset PayloadSizeOffset;
|
|
|
|
// TODO: presumably it would be useful to store *something* here
|
|
// for resilience.
|
|
|
|
friend class IRGenModule;
|
|
EnumMetadataLayout(IRGenModule &IGM, EnumDecl *theEnum);
|
|
|
|
public:
|
|
EnumDecl *getDecl() const {
|
|
return cast<EnumDecl>(Nominal);
|
|
}
|
|
|
|
bool hasPayloadSizeOffset() const {
|
|
return PayloadSizeOffset.isValid();
|
|
}
|
|
|
|
Offset getPayloadSizeOffset() const;
|
|
|
|
static bool classof(const MetadataLayout *layout) {
|
|
return layout->getKind() == Kind::Enum;
|
|
}
|
|
};
|
|
|
|
/// Layout for struct type metadata.
|
|
class StructMetadataLayout : public NominalMetadataLayout {
|
|
llvm::DenseMap<VarDecl*, StoredOffset> FieldOffsets;
|
|
|
|
/// The start of the field-offset vector.
|
|
StoredOffset FieldOffsetVector;
|
|
|
|
const StoredOffset &getStoredFieldOffset(VarDecl *field) const {
|
|
auto it = FieldOffsets.find(field);
|
|
assert(it != FieldOffsets.end());
|
|
return it->second;
|
|
}
|
|
|
|
friend class IRGenModule;
|
|
StructMetadataLayout(IRGenModule &IGM, StructDecl *theStruct);
|
|
|
|
public:
|
|
StructDecl *getDecl() const {
|
|
return cast<StructDecl>(Nominal);
|
|
}
|
|
|
|
Offset getFieldOffset(IRGenFunction &IGF, VarDecl *field) const;
|
|
|
|
/// Assuming that the given field offset is at a static offset in
|
|
/// the metadata, return that static offset.
|
|
///
|
|
/// DEPRECATED: callers should be updated to handle this in a
|
|
/// more arbitrary fashion.
|
|
Size getStaticFieldOffset(VarDecl *field) const;
|
|
|
|
Offset getFieldOffsetVectorOffset() const;
|
|
|
|
static bool classof(const MetadataLayout *layout) {
|
|
return layout->getKind() == Kind::Struct;
|
|
}
|
|
};
|
|
|
|
/// Emit the address of the field-offset slot in the given class metadata.
|
|
Address emitAddressOfClassFieldOffset(IRGenFunction &IGF,
|
|
llvm::Value *metadata,
|
|
ClassDecl *theClass,
|
|
VarDecl *field);
|
|
|
|
/// Get the offset to a field offset in the class type metadata.
|
|
///
|
|
/// DEPRECATED: callers should be updated to handle this in a more
|
|
/// arbitrary fashion.
|
|
Size getClassFieldOffsetOffset(IRGenModule &IGM,
|
|
ClassDecl *theClass,
|
|
VarDecl *field);
|
|
|
|
/// Emit the address of the field-offset vector in the given class or struct
|
|
/// metadata.
|
|
Address emitAddressOfFieldOffsetVector(IRGenFunction &IGF,
|
|
llvm::Value *metadata,
|
|
NominalTypeDecl *theDecl);
|
|
|
|
} // end namespace irgen
|
|
} // end namespace swift
|
|
|
|
#endif
|