-
Notifications
You must be signed in to change notification settings - Fork 10.4k
/
Copy pathCleanup.cpp
154 lines (126 loc) · 4.89 KB
/
Cleanup.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
146
147
148
149
150
151
152
153
154
//===--- Cleanup.cpp - Implements the Cleanup mechanics --------------------==//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See http://swift.org/LICENSE.txt for license information
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
#include "Cleanup.h"
#include "SILGenFunction.h"
using namespace swift;
using namespace Lowering;
/// Are there any active cleanups in the given range?
static bool hasAnyActiveCleanups(DiverseStackImpl<Cleanup>::iterator begin,
DiverseStackImpl<Cleanup>::iterator end) {
for (; begin != end; ++begin)
if (begin->isActive())
return true;
return false;
}
namespace {
/// A CleanupBuffer is a location to which to temporarily copy a
/// cleanup.
class CleanupBuffer {
SmallVector<char, sizeof(Cleanup) + 10 * sizeof(void*)> Data;
public:
CleanupBuffer(const Cleanup &cleanup) {
size_t size = cleanup.allocated_size();
Data.set_size(size);
memcpy(Data.data(), reinterpret_cast<const void*>(&cleanup), size);
}
Cleanup &getCopy() { return *reinterpret_cast<Cleanup*>(Data.data()); }
};
}
void CleanupManager::popAndEmitTopCleanup(CleanupLocation *l) {
Cleanup &stackCleanup = *Stack.begin();
// Copy it off the cleanups stack.
CleanupBuffer buffer(stackCleanup);
Cleanup &cleanup = buffer.getCopy();
// Pop now.
Stack.pop();
if (cleanup.isActive() && Gen.B.hasValidInsertionPoint()) {
assert(l && "Location should be provided for active cleanups.");
cleanup.emit(Gen, *l);
}
}
void CleanupManager::popTopDeadCleanups(CleanupsDepth end) {
Stack.checkIterator(end);
while (Stack.stable_begin() != end && Stack.begin()->isDead()) {
assert(!Stack.empty());
popAndEmitTopCleanup(0);
Stack.checkIterator(end);
}
}
/// Leave a scope, with all its cleanups.
void CleanupManager::endScope(CleanupsDepth depth, CleanupLocation l) {
Stack.checkIterator(depth);
// FIXME: Thread a branch through the cleanups if there are any active
// cleanups and we have a valid insertion point.
if (!::hasAnyActiveCleanups(Stack.begin(), Stack.find(depth))) {
return;
}
// Iteratively mark cleanups dead and pop them.
// Maybe we'd get better results if we marked them all dead in one shot?
while (Stack.stable_begin() != depth) {
popAndEmitTopCleanup(&l);
}
}
bool CleanupManager::hasAnyActiveCleanups(CleanupsDepth from,
CleanupsDepth to) {
return ::hasAnyActiveCleanups(Stack.find(from), Stack.find(to));
}
/// emitBranchAndCleanups - Emit a branch to the given jump destination,
/// threading out through any cleanups we might need to run. This does not
/// pop the cleanup stack.
void CleanupManager::emitBranchAndCleanups(JumpDest Dest,
SILLocation BranchLoc,
ArrayRef<SILValue> Args) {
SILBuilder &B = Gen.getBuilder();
assert(B.hasValidInsertionPoint() && "Inserting branch in invalid spot");
auto depth = Dest.getDepth();
auto end = Stack.find(depth);
for (auto cleanup = Stack.begin();
cleanup != end;
++cleanup) {
if (cleanup->isActive()) {
cleanup->emit(Gen, Dest.getCleanupLocation());
}
}
B.createBranch(BranchLoc, Dest.getBlock(), Args);
}
void CleanupManager::emitCleanupsForReturn(CleanupLocation Loc) {
for (auto &cleanup : Stack)
if (cleanup.isActive())
cleanup.emit(Gen, Loc);
}
Cleanup &CleanupManager::initCleanup(Cleanup &cleanup,
size_t allocSize,
CleanupState state) {
cleanup.allocatedSize = allocSize;
cleanup.state = state;
return cleanup;
}
void CleanupManager::setCleanupState(CleanupsDepth depth, CleanupState state) {
auto iter = Stack.find(depth);
assert(iter != Stack.end() && "can't change end of cleanups stack");
setCleanupState(*iter, state);
if (state == CleanupState::Dead && iter == Stack.begin())
popTopDeadCleanups(InnermostScope);
}
void CleanupManager::setCleanupState(Cleanup &cleanup, CleanupState state) {
assert(Gen.B.hasValidInsertionPoint() &&
"changing cleanup state at invalid IP");
// Do the transition now to avoid doing it in N places below.
CleanupState oldState = cleanup.getState();
(void)oldState;
cleanup.setState(state);
assert(state != oldState && "trivial cleanup state change");
assert(oldState != CleanupState::Dead && "changing state of dead cleanup");
// Our current cleanup emission logic, where we don't try to re-use
// cleanup emissions between various branches, doesn't require any
// code to be emitted at transition points.
}