-
Notifications
You must be signed in to change notification settings - Fork 10.4k
/
Copy pathScope.cpp
145 lines (127 loc) · 5.8 KB
/
Scope.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
//===--- 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);
}