Skip to content

Class resilience part 3 #13312

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Dec 8, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 4 additions & 9 deletions include/swift/Runtime/Metadata.h
Original file line number Diff line number Diff line change
Expand Up @@ -2869,16 +2869,11 @@ void swift_initStructMetadata_UniversalStrategy(size_t numFields,

/// Initialize the field offset vector for a dependent-layout class, using the
/// "Universal" layout strategy.
///
/// This will relocate the metadata if it doesn't have enough space
/// for its superclass. Note that swift_allocateGenericClassMetadata will
/// never produce a metadata that requires relocation.
SWIFT_RUNTIME_EXPORT
ClassMetadata *
swift_initClassMetadata_UniversalStrategy(ClassMetadata *self,
size_t numFields,
const TypeLayout * const *fieldTypes,
size_t *fieldOffsets);
void swift_initClassMetadata_UniversalStrategy(ClassMetadata *self,
size_t numFields,
const TypeLayout * const *fieldTypes,
size_t *fieldOffsets);

/// \brief Fetch a uniqued metadata for a metatype type.
SWIFT_RUNTIME_EXPORT
Expand Down
10 changes: 5 additions & 5 deletions include/swift/Runtime/RuntimeFunctions.def
Original file line number Diff line number Diff line change
Expand Up @@ -946,13 +946,13 @@ FUNCTION(GetExistentialMetadata,
ATTRS(NoUnwind, ReadOnly))

// struct FieldInfo { size_t Size; size_t AlignMask; };
// Metadata *swift_initClassMetadata_UniversalStrategy(Metadata *self,
// size_t numFields,
// TypeLayout * const *fieldTypes,
// size_t *fieldOffsets);
// void swift_initClassMetadata_UniversalStrategy(Metadata *self,
// size_t numFields,
// TypeLayout * const *fieldTypes,
// size_t *fieldOffsets);
FUNCTION(InitClassMetadataUniversal,
swift_initClassMetadata_UniversalStrategy, DefaultCC,
RETURNS(TypeMetadataPtrTy),
RETURNS(VoidTy),
ARGS(TypeMetadataPtrTy, SizeTy,
Int8PtrPtrTy->getPointerTo(),
SizeTy->getPointerTo()),
Expand Down
66 changes: 23 additions & 43 deletions lib/IRGen/GenMeta.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2758,8 +2758,6 @@ namespace {
struct FillOp {
CanType Type;
Optional<ProtocolConformanceRef> Conformance;
Size ToOffset;
bool IsRelative;
};

SmallVector<FillOp, 8> FillOps;
Expand Down Expand Up @@ -2836,7 +2834,10 @@ namespace {
// fill indexes are word-indexed.
Address metadataWords(IGF.Builder.CreateBitCast(metadataValue, IGM.Int8PtrPtrTy),
IGM.getPointerAlignment());


auto genericReqtOffset = IGM.getMetadataLayout(Target)
.getGenericRequirementsOffset(IGF);

for (auto &fillOp : FillOps) {
llvm::Value *value;
if (fillOp.Conformance) {
Expand All @@ -2846,20 +2847,12 @@ namespace {
}

auto dest = createPointerSizedGEP(IGF, metadataWords,
fillOp.ToOffset - AddressPoint);

// A far relative indirectable pointer.
if (fillOp.IsRelative) {
dest = IGF.Builder.CreateElementBitCast(dest,
IGM.FarRelativeAddressTy);
IGF.emitStoreOfRelativeIndirectablePointer(value, dest,
/*isFar*/ true);
genericReqtOffset.getStatic());
genericReqtOffset = genericReqtOffset.offsetBy(
IGF, IGM.getPointerSize());

// A direct pointer.
} else {
value = IGF.Builder.CreateBitCast(value, IGM.Int8PtrTy);
IGF.Builder.CreateStore(value, dest);
}
value = IGF.Builder.CreateBitCast(value, IGM.Int8PtrTy);
IGF.Builder.CreateStore(value, dest);
}

// Initialize the instantiated dependent value witness table, if we have
Expand Down Expand Up @@ -2894,12 +2887,6 @@ namespace {
return f;
}

void addFillOp(CanType type, Optional<ProtocolConformanceRef> conf,
bool isRelative) {
FillOps.push_back({type, conf, getNextOffsetFromTemplateHeader(),
isRelative });
}

public:
void createMetadataAccessFunction() {
(void) getGenericTypeMetadataAccessFunction(IGM, Target, ForDefinition);
Expand Down Expand Up @@ -2981,14 +2968,14 @@ namespace {

template <class... T>
void addGenericArgument(CanType type, T &&...args) {
addFillOp(type, None, /*relative*/ false);
FillOps.push_back({type, None});
super::addGenericArgument(type, std::forward<T>(args)...);
}

template <class... T>
void addGenericWitnessTable(CanType type, ProtocolConformanceRef conf,
T &&...args) {
addFillOp(type, conf, /*relative*/ false);
FillOps.push_back({type, conf});
super::addGenericWitnessTable(type, conf, std::forward<T>(args)...);
}

Expand Down Expand Up @@ -3021,11 +3008,10 @@ namespace {
};
} // end anonymous namespace

llvm::Value *
irgen::emitInitializeFieldOffsetVector(IRGenFunction &IGF,
SILType T,
llvm::Value *metadata,
llvm::Value *vwtable) {
void irgen::emitInitializeFieldOffsetVector(IRGenFunction &IGF,
SILType T,
llvm::Value *metadata,
llvm::Value *vwtable) {
auto *target = T.getNominalOrBoundGenericNominal();
llvm::Value *fieldVector
= emitAddressOfFieldOffsetVector(IGF, metadata, target)
Expand Down Expand Up @@ -3062,9 +3048,9 @@ irgen::emitInitializeFieldOffsetVector(IRGenFunction &IGF,

if (isa<ClassDecl>(target)) {
assert(vwtable == nullptr);
metadata = IGF.Builder.CreateCall(IGF.IGM.getInitClassMetadataUniversalFn(),
{metadata, numFields,
fields.getAddress(), fieldVector});
IGF.Builder.CreateCall(IGF.IGM.getInitClassMetadataUniversalFn(),
{metadata, numFields,
fields.getAddress(), fieldVector});
} else {
assert(isa<StructDecl>(target));
IGF.Builder.CreateCall(IGF.IGM.getInitStructMetadataUniversalFn(),
Expand All @@ -3074,8 +3060,6 @@ irgen::emitInitializeFieldOffsetVector(IRGenFunction &IGF,

IGF.Builder.CreateLifetimeEnd(fields,
IGF.IGM.getPointerSize() * storedProperties.size());

return metadata;
}

// Classes
Expand Down Expand Up @@ -3489,11 +3473,9 @@ namespace {
}

llvm::Value *emitFinishInitializationOfClassMetadata(IRGenFunction &IGF,
llvm::Value *metadata) {
llvm::Value *metadata) {
// We assume that we've already filled in the class's generic arguments.
// We need to:
// - relocate the metadata to accommodate the superclass,
// if something in our hierarchy is resilient to us;
// - fill out the subclass's field offset vector, if its layout
// wasn't fixed;
// - copy field offsets and generic arguments from higher in the
Expand All @@ -3508,9 +3490,9 @@ namespace {
if (doesClassMetadataRequireDynamicInitialization(IGF.IGM, Target)) {
auto classTy = Target->getDeclaredTypeInContext()->getCanonicalType();
auto loweredClassTy = IGF.IGM.getLoweredType(classTy);
metadata = emitInitializeFieldOffsetVector(IGF, loweredClassTy,
metadata,
/*vwtable=*/nullptr);
emitInitializeFieldOffsetVector(IGF, loweredClassTy,
metadata,
/*vwtable=*/nullptr);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So we're assuming that the superclass has been relocated already. That's a nice simplification. The runtime will do this?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And if so, presumably it can copy field offsets and generic arguments higher in the hierarchy, so we can strike that bit from the comment, too?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The relocation is handled in the next PR ("part 4").

Copying field offsets and generic arguments from higher up in the hierarchy is already implemented by swift_initClassMetadata_UniversalStrategy(), since we already have to do it for generic classes, where the generic arguments and field offsets are always just null in the template.


// Realizing the class with the ObjC runtime will copy back to the
// field offset globals for us; but if ObjC interop is disabled, we
Expand Down Expand Up @@ -3742,9 +3724,7 @@ namespace {
IGF.Builder.CreateStore(superclassMetadata, superField);
}

metadata = emitFinishInitializationOfClassMetadata(IGF, metadata);

return metadata;
return emitFinishInitializationOfClassMetadata(IGF, metadata);
}
};

Expand Down
8 changes: 4 additions & 4 deletions lib/IRGen/GenMeta.h
Original file line number Diff line number Diff line change
Expand Up @@ -255,10 +255,10 @@ namespace irgen {

/// \brief Initialize the field offset vector within the given class or struct
/// metadata.
llvm::Value *emitInitializeFieldOffsetVector(IRGenFunction &IGF,
SILType T,
llvm::Value *metadata,
llvm::Value *vwtable);
void emitInitializeFieldOffsetVector(IRGenFunction &IGF,
SILType T,
llvm::Value *metadata,
llvm::Value *vwtable);

/// Adjustment indices for the address points of various metadata.
/// Size is in words.
Expand Down
2 changes: 1 addition & 1 deletion lib/IRGen/IRGen.h
Original file line number Diff line number Diff line change
Expand Up @@ -484,7 +484,7 @@ class Offset {
}

llvm::Value *getAsValue(IRGenFunction &IGF) const;
Offset offsetBy(IRGenFunction &IGF, Offset other) const;
Offset offsetBy(IRGenFunction &IGF, Size other) const;
};

} // end namespace irgen
Expand Down
9 changes: 5 additions & 4 deletions lib/IRGen/IRGenFunction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -394,11 +394,12 @@ llvm::Value *Offset::getAsValue(IRGenFunction &IGF) const {
}
}

Offset Offset::offsetBy(IRGenFunction &IGF, Offset other) const {
if (isStatic() && other.isStatic()) {
return Offset(getStatic() + other.getStatic());
Offset Offset::offsetBy(IRGenFunction &IGF, Size other) const {
if (isStatic()) {
return Offset(getStatic() + other);
}
return Offset(IGF.Builder.CreateAdd(getDynamic(), other.getDynamic()));
auto otherVal = llvm::ConstantInt::get(IGF.IGM.SizeTy, other.getValue());
return Offset(IGF.Builder.CreateAdd(getDynamic(), otherVal));
}

Address IRGenFunction::emitAddressAtOffset(llvm::Value *base, Offset offset,
Expand Down
35 changes: 31 additions & 4 deletions lib/IRGen/MetadataLayout.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,7 @@ static llvm::Value *emitLoadOfGenericRequirement(IRGenFunction &IGF,
llvm::Type *reqtTy) {
auto offset =
IGF.IGM.getMetadataLayout(decl).getGenericRequirementsOffset(IGF);
offset = offset.offsetBy(IGF, Offset(reqtIndex * IGF.IGM.getPointerSize()));
offset = offset.offsetBy(IGF, Size(reqtIndex * IGF.IGM.getPointerSize()));

auto slot = IGF.emitAddressAtOffset(metadata, offset, reqtTy,
IGF.IGM.getPointerAlignment());
Expand Down Expand Up @@ -203,7 +203,7 @@ Address irgen::emitAddressOfFieldOffsetVector(IRGenFunction &IGF,
/********************************** CLASSES ***********************************/

ClassMetadataLayout::ClassMetadataLayout(IRGenModule &IGM, ClassDecl *decl)
: NominalMetadataLayout(Kind::Class) {
: NominalMetadataLayout(Kind::Class), NumImmediateMembers(0) {

struct Scanner : LayoutScanner<Scanner, ClassMetadataScanner> {
using super = LayoutScanner;
Expand All @@ -228,9 +228,26 @@ ClassMetadataLayout::ClassMetadataLayout(IRGenModule &IGM, ClassDecl *decl)
super::noteStartOfGenericRequirements(forClass);
}

void addGenericWitnessTable(CanType argType, ProtocolConformanceRef conf,
ClassDecl *forClass) {
if (forClass == Target) {
Layout.NumImmediateMembers++;
}
super::addGenericWitnessTable(argType, conf, forClass);
}

void addGenericArgument(CanType argType, ClassDecl *forClass) {
if (forClass == Target) {
Layout.NumImmediateMembers++;
}
super::addGenericArgument(argType, forClass);
}

void addMethod(SILDeclRef fn) {
if (fn.getDecl()->getDeclContext() == Target)
if (fn.getDecl()->getDeclContext() == Target) {
Layout.NumImmediateMembers++;
Layout.MethodInfos.try_emplace(fn, getNextOffset());
}
super::addMethod(fn);
}

Expand All @@ -241,11 +258,21 @@ ClassMetadataLayout::ClassMetadataLayout(IRGenModule &IGM, ClassDecl *decl)
}

void addFieldOffset(VarDecl *field) {
if (field->getDeclContext() == Target)
if (field->getDeclContext() == Target) {
Layout.NumImmediateMembers++;
Layout.FieldOffsets.try_emplace(field, getNextOffset());
}
super::addFieldOffset(field);
}

void addFieldOffsetPlaceholders(MissingMemberDecl *placeholder) {
if (placeholder->getDeclContext() == Target) {
Layout.NumImmediateMembers +=
placeholder->getNumberOfFieldOffsetVectorEntries();
}
super::addFieldOffsetPlaceholders(placeholder);
}

void addVTableEntries(ClassDecl *forClass) {
if (forClass == Target)
Layout.VTableOffset = getNextOffset();
Expand Down
10 changes: 10 additions & 0 deletions lib/IRGen/MetadataLayout.h
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,9 @@ class ClassMetadataLayout : public NominalMetadataLayout {
/// 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());
Expand Down Expand Up @@ -222,6 +225,13 @@ class ClassMetadataLayout : public NominalMetadataLayout {

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;
}
Expand Down
Loading