Skip to content

Commit

Permalink
DI: Add non-working code for handling value_metatype when used on an …
Browse files Browse the repository at this point in the history
…address-only type
  • Loading branch information
slavapestov committed Oct 24, 2020
1 parent 7f2b01c commit 37f2bc1
Show file tree
Hide file tree
Showing 3 changed files with 56 additions and 26 deletions.
4 changes: 4 additions & 0 deletions lib/SILOptimizer/Mandatory/DIMemoryUseCollector.cpp
Expand Up @@ -1409,6 +1409,10 @@ collectDelegatingInitUses(const DIMemoryObjectInfo &TheMemory,
Kind = DIUseKind::LoadForTypeOfSelf;
}
}
// value_metatype may also use the 'self' value directly, if it has an
// address-only type.
if (isa<ValueMetatypeInst>(User))
Kind = DIUseKind::TypeOfSelf;

// We can safely handle anything else as an escape. They should all happen
// after self.init is invoked.
Expand Down
3 changes: 3 additions & 0 deletions lib/SILOptimizer/Mandatory/DIMemoryUseCollector.h
Expand Up @@ -281,6 +281,9 @@ enum DIUseKind {
/// This instruction is a load that's only used to answer a `type(of: self)`
/// question.
LoadForTypeOfSelf,

/// This instruction is a value_metatype on the address of 'self'.
TypeOfSelf
};

/// This struct represents a single classified access to the memory object
Expand Down
75 changes: 49 additions & 26 deletions lib/SILOptimizer/Mandatory/DefiniteInitialization.cpp
Expand Up @@ -460,6 +460,7 @@ namespace {
void handleStoreUse(unsigned UseID);
void handleLoadUse(const DIMemoryUse &Use);
void handleLoadForTypeOfSelfUse(DIMemoryUse &Use);
void handleTypeOfSelfUse(DIMemoryUse &Use);
void handleInOutUse(const DIMemoryUse &Use);
void handleEscapeUse(const DIMemoryUse &Use);

Expand Down Expand Up @@ -530,6 +531,7 @@ LifetimeChecker::LifetimeChecker(const DIMemoryObjectInfo &TheMemory,
switch (Use.Kind) {
case DIUseKind::Load:
case DIUseKind::LoadForTypeOfSelf:
case DIUseKind::TypeOfSelf:
case DIUseKind::Escape:
continue;
case DIUseKind::Assign:
Expand Down Expand Up @@ -787,6 +789,9 @@ void LifetimeChecker::doIt() {
case DIUseKind::LoadForTypeOfSelf:
handleLoadForTypeOfSelfUse(Use);
break;
case DIUseKind::TypeOfSelf:
handleTypeOfSelfUse(Use);
break;
}
}

Expand Down Expand Up @@ -835,6 +840,35 @@ void LifetimeChecker::handleLoadUse(const DIMemoryUse &Use) {
return handleLoadUseFailure(Use, IsSuperInitComplete, FailedSelfUse);
}

static void replaceValueMetatypeInstWithMetatypeArgument(
ValueMetatypeInst *valueMetatype) {
SILValue metatypeArgument = valueMetatype->getFunction()->getSelfArgument();

// SILFunction parameter types never have a DynamicSelfType, since it only
// makes sense in the context of a given method's body. Since the
// value_metatype instruction might produce a DynamicSelfType we have to
// cast the metatype argument.
//
// FIXME: Semantically, we're "opening" the class metatype here to produce
// the "opened" DynamicSelfType. Ideally it would be modeled as an opened
// archetype associated with the original metatype or class instance value,
// instead of as a "global" type.
auto metatypeSelfType = metatypeArgument->getType()
.castTo<MetatypeType>().getInstanceType();
auto valueSelfType = valueMetatype->getType()
.castTo<MetatypeType>().getInstanceType();
if (metatypeSelfType != valueSelfType) {
assert(metatypeSelfType ==
cast<DynamicSelfType>(valueSelfType).getSelfType());

SILBuilderWithScope B(valueMetatype);
metatypeArgument = B.createUncheckedTrivialBitCast(
valueMetatype->getLoc(), metatypeArgument,
valueMetatype->getType());
}
replaceAllSimplifiedUsesAndErase(valueMetatype, metatypeArgument);
}

void LifetimeChecker::handleLoadForTypeOfSelfUse(DIMemoryUse &Use) {
bool IsSuperInitComplete, FailedSelfUse;
// If the value is not definitively initialized, replace the
Expand All @@ -849,32 +883,7 @@ void LifetimeChecker::handleLoadForTypeOfSelfUse(DIMemoryUse &Use) {
if (valueMetatype)
break;
}
assert(valueMetatype);
SILValue metatypeArgument = load->getFunction()->getSelfArgument();

// SILFunction parameter types never have a DynamicSelfType, since it only
// makes sense in the context of a given method's body. Since the
// value_metatype instruction might produce a DynamicSelfType we have to
// cast the metatype argument.
//
// FIXME: Semantically, we're "opening" the class metatype here to produce
// the "opened" DynamicSelfType. Ideally it would be modeled as an opened
// archetype associated with the original metatype or class instance value,
// instead of as a "global" type.
auto metatypeSelfType = metatypeArgument->getType()
.castTo<MetatypeType>().getInstanceType();
auto valueSelfType = valueMetatype->getType()
.castTo<MetatypeType>().getInstanceType();
if (metatypeSelfType != valueSelfType) {
assert(metatypeSelfType ==
cast<DynamicSelfType>(valueSelfType).getSelfType());

SILBuilderWithScope B(valueMetatype);
metatypeArgument = B.createUncheckedTrivialBitCast(
valueMetatype->getLoc(), metatypeArgument,
valueMetatype->getType());
}
replaceAllSimplifiedUsesAndErase(valueMetatype, metatypeArgument);
replaceValueMetatypeInstWithMetatypeArgument(valueMetatype);

// Dead loads for type-of-self must be removed.
// Otherwise it's a violation of memory lifetime.
Expand All @@ -889,6 +898,20 @@ void LifetimeChecker::handleLoadForTypeOfSelfUse(DIMemoryUse &Use) {
}
}

void LifetimeChecker::handleTypeOfSelfUse(DIMemoryUse &Use) {
bool IsSuperInitComplete, FailedSelfUse;
// If the value is not definitively initialized, replace the
// value_metatype instruction with the metatype argument that was passed into
// the initializer.
if (!isInitializedAtUse(Use, &IsSuperInitComplete, &FailedSelfUse)) {
auto *valueMetatype = cast<ValueMetatypeInst>(Use.Inst);
replaceValueMetatypeInstWithMetatypeArgument(valueMetatype);

// Clear the Inst pointer just to be sure to avoid use-after-free.
Use.Inst = nullptr;
}
}

void LifetimeChecker::emitSelfConsumedDiagnostic(SILInstruction *Inst) {
if (!shouldEmitError(Inst))
return;
Expand Down

0 comments on commit 37f2bc1

Please sign in to comment.