mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
Although I don't plan to bring over new assertions wholesale into the current qualification branch, it's entirely possible that various minor changes in main will use the new assertions; having this basic support in the release branch will simplify that. (This is why I'm adding the includes as a separate pass from rewriting the individual assertions)
146 lines
5.8 KiB
C++
146 lines
5.8 KiB
C++
//===--- Scope.cpp --------------------------------------------------------===//
|
|
//
|
|
// 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
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "Scope.h"
|
|
#include "swift/Basic/Assertions.h"
|
|
#include "swift/Basic/Range.h"
|
|
|
|
using namespace swift;
|
|
using namespace Lowering;
|
|
|
|
ManagedValue Scope::popPreservingValue(ManagedValue mv) {
|
|
// If we have a value, make sure that it is an object. The reason why is
|
|
// that we want to make sure that we are not forwarding a cleanup for a
|
|
// stack location that will be destroyed by this scope.
|
|
assert(mv && mv.getType().isObject() &&
|
|
(mv.getType().isTrivial(cleanups.SGF.F) ||
|
|
mv.getOwnershipKind() == OwnershipKind::None || mv.hasCleanup()));
|
|
CleanupCloner cloner(cleanups.SGF, mv);
|
|
SILValue value = mv.forward(cleanups.SGF);
|
|
pop();
|
|
return cloner.clone(value);
|
|
}
|
|
|
|
// Since we have an RValue, we know that RValue invariants imply that all
|
|
// subvalues that are addresses must be address only types. Such address only
|
|
// types if they are +1 rvalues should be independent of any values from outside
|
|
// the +1 rvalue emission (that is if someone else has a reference to the
|
|
// address only type, we should have produced a copy). This means that it is
|
|
// safe to move the value into new memory that is guaranteed to live through the
|
|
// scope being pushed. As an additional complication due to SIL enforcing stack
|
|
// ordering, we can not use a temporary stack location since any stack locations
|
|
// that are inside the scope will be cleaned up while such a scope jumping stack
|
|
// is still alive (violating stack ordering). Instead we use an alloc_box to
|
|
// store the new value. allocbox-to-stack will then reorder/expand the stack
|
|
// lifetimes to resolve the issues.
|
|
static void lifetimeExtendAddressOnlyRValueSubValues(
|
|
SILGenFunction &SGF, SILLocation loc,
|
|
llvm::SmallVectorImpl<SILValue> &values,
|
|
llvm::SmallVectorImpl<SILValue> &lifetimeExtendingBoxes) {
|
|
for (SILValue &v : values) {
|
|
// If v is not an address, it isn't interesting, continue.
|
|
if (!v->getType().isAddress()) {
|
|
continue;
|
|
}
|
|
|
|
// Otherwise, create the box and move the address only value into the box.
|
|
assert(v->getType().isAddressOnly(SGF.F) &&
|
|
"RValue invariants imply that all RValue subtypes that are "
|
|
"addresses must be address only.");
|
|
auto boxTy = SILBoxType::get(v->getType().getASTType());
|
|
SILValue box = SGF.B.createAllocBox(loc, boxTy);
|
|
// TODO: Should these boxes that extend lifetimes for rvalue subobjects ever
|
|
// be lexical?
|
|
if (SGF.getASTContext().SILOpts.supportsLexicalLifetimes(SGF.getModule())) {
|
|
if (v->getType().getLifetime(SGF.F).isLexical()) {
|
|
box = SGF.B.createBeginBorrow(loc, box, IsLexical);
|
|
}
|
|
}
|
|
SILValue addr = SGF.B.createProjectBox(loc, box, 0);
|
|
SGF.B.createCopyAddr(loc, v, addr, IsTake, IsInitialization);
|
|
|
|
// Then save the box so we create the box destroy in the caller and
|
|
// overwrite v with the project box since that is where the value is now.
|
|
lifetimeExtendingBoxes.emplace_back(box);
|
|
v = addr;
|
|
}
|
|
}
|
|
|
|
RValue Scope::popPreservingValue(RValue &&rv) {
|
|
auto &SGF = cleanups.SGF;
|
|
assert(rv.isPlusOneOrTrivial(SGF) &&
|
|
"Can only push plus one rvalues through a scope");
|
|
|
|
// Perform a quick check if we have an incontext value. If so, just pop and
|
|
// return rv.
|
|
if (rv.isInContext()) {
|
|
pop();
|
|
return std::move(rv);
|
|
}
|
|
|
|
// After this point, we should have /no/ special states.
|
|
assert(!rv.isInSpecialState());
|
|
|
|
// Ok, we have a normal RValue. Gather all of the data that we need to
|
|
// recreate the RValue in the outer scope.
|
|
CanType type = rv.type;
|
|
unsigned numEltsRemaining = rv.elementsToBeAdded;
|
|
SmallVector<CleanupCloner, 4> cloners;
|
|
CleanupCloner::getClonersForRValue(SGF, rv, cloners);
|
|
|
|
SmallVector<SILValue, 4> values;
|
|
std::move(rv).forwardAll(SGF, values);
|
|
|
|
// Lifetime any address only values that we may have.
|
|
SmallVector<SILValue, 4> lifetimeExtendingBoxes;
|
|
lifetimeExtendAddressOnlyRValueSubValues(SGF, loc, values,
|
|
lifetimeExtendingBoxes);
|
|
|
|
// Then pop the cleanups.
|
|
pop();
|
|
|
|
// Then create cleanups for any lifetime extending boxes that we may have to
|
|
// ensure that the boxes are cleaned up /after/ the value stored in the
|
|
// box. We assume that our values will be destroyed via a destroy_addr or the
|
|
// like /before/ the end of our box's lifetime, implying that the value inside
|
|
// the box should be uninitialized when the box is destroyed, so it is
|
|
// important that we use a dealloc_box.
|
|
for (auto v : lifetimeExtendingBoxes) {
|
|
SGF.enterDeallocBoxCleanup(v);
|
|
}
|
|
|
|
// Reconstruct the managed values from the underlying sil values in the outer
|
|
// scope. Since the RValue wants a std::vector value, we use that instead.
|
|
std::vector<ManagedValue> managedValues;
|
|
for (unsigned i : indices(values)) {
|
|
managedValues.push_back(cloners[i].clone(values[i]));
|
|
}
|
|
|
|
// And then assemble the managed values into a rvalue.
|
|
return RValue(SGF, std::move(managedValues), type, numEltsRemaining);
|
|
}
|
|
|
|
void Scope::popImpl() {
|
|
verify();
|
|
cleanups.innermostScope = savedInnermostScope;
|
|
cleanups.endScope(depth, loc);
|
|
if (cleanups.innermostScope)
|
|
cleanups.stack.checkIterator(cleanups.innermostScope->depth);
|
|
cleanups.popTopDeadCleanups();
|
|
}
|
|
|
|
void Scope::verify() {
|
|
assert(cleanups.innermostScope == this && "popping scopes out of order");
|
|
assert(depth.isValid());
|
|
cleanups.stack.checkIterator(depth);
|
|
}
|