@@ -70,45 +70,101 @@ void EHScopeStack::deallocate(size_t size) {
70
70
}
71
71
72
72
void *EHScopeStack::pushCleanup (CleanupKind kind, size_t size) {
73
- char *buffer = allocate (size);
73
+ char *buffer = allocate (EHCleanupScope::getSizeForCleanupSize (size));
74
+ bool isEHCleanup = kind & EHCleanup;
75
+ bool isLifetimeMarker = kind & LifetimeMarker;
74
76
75
- // When the full implementation is upstreamed, this will allocate
76
- // extra memory for and construct a wrapper object that is used to
77
- // manage the cleanup generation.
78
- assert (!cir::MissingFeatures::ehCleanupScope ());
77
+ assert (!cir::MissingFeatures::innermostEHScope ());
79
78
80
- return buffer;
79
+ EHCleanupScope *scope = new (buffer) EHCleanupScope (size);
80
+
81
+ if (isLifetimeMarker)
82
+ cgf->cgm .errorNYI (" push lifetime marker cleanup" );
83
+
84
+ // With Windows -EHa, Invoke llvm.seh.scope.begin() for EHCleanup
85
+ if (cgf->getLangOpts ().EHAsynch && isEHCleanup && !isLifetimeMarker &&
86
+ cgf->getTarget ().getCXXABI ().isMicrosoft ())
87
+ cgf->cgm .errorNYI (" push seh cleanup" );
88
+
89
+ return scope->getCleanupBuffer ();
90
+ }
91
+
92
+ void EHScopeStack::popCleanup () {
93
+ assert (!empty () && " popping exception stack when not empty" );
94
+
95
+ assert (isa<EHCleanupScope>(*begin ()));
96
+ EHCleanupScope &cleanup = cast<EHCleanupScope>(*begin ());
97
+ deallocate (cleanup.getAllocatedSize ());
98
+
99
+ // Destroy the cleanup.
100
+ cleanup.destroy ();
101
+
102
+ assert (!cir::MissingFeatures::ehCleanupBranchFixups ());
81
103
}
82
104
83
- static mlir::Block *getCurCleanupBlock (CIRGenFunction &cgf) {
84
- mlir::OpBuilder::InsertionGuard guard (cgf.getBuilder ());
85
- mlir::Block *cleanup =
86
- cgf.curLexScope ->getOrCreateCleanupBlock (cgf.getBuilder ());
87
- return cleanup;
105
+ static void emitCleanup (CIRGenFunction &cgf, EHScopeStack::Cleanup *cleanup) {
106
+ // Ask the cleanup to emit itself.
107
+ assert (cgf.haveInsertPoint () && " expected insertion point" );
108
+ assert (!cir::MissingFeatures::ehCleanupFlags ());
109
+ cleanup->emit (cgf);
110
+ assert (cgf.haveInsertPoint () && " cleanup ended with no insertion point?" );
88
111
}
89
112
90
113
// / Pops a cleanup block. If the block includes a normal cleanup, the
91
114
// / current insertion point is threaded through the cleanup, as are
92
115
// / any branch fixups on the cleanup.
93
116
void CIRGenFunction::popCleanupBlock () {
94
117
assert (!ehStack.empty () && " cleanup stack is empty!" );
118
+ assert (isa<EHCleanupScope>(*ehStack.begin ()) && " top not a cleanup!" );
119
+ EHCleanupScope &scope = cast<EHCleanupScope>(*ehStack.begin ());
120
+
121
+ // Remember activation information.
122
+ bool isActive = scope.isActive ();
123
+
124
+ assert (!cir::MissingFeatures::ehCleanupBranchFixups ());
95
125
96
- // The memory for the cleanup continues to be owned by the EHScopeStack
97
- // allocator, so we just destroy the object rather than attempting to
98
- // free it.
99
- EHScopeStack::Cleanup &cleanup = *ehStack.begin ();
126
+ // - whether there's a fallthrough
127
+ mlir::Block *fallthroughSource = builder.getInsertionBlock ();
128
+ bool hasFallthrough = fallthroughSource != nullptr && isActive;
100
129
101
- // The eventual implementation here will use the EHCleanupScope helper class.
102
- assert (!cir::MissingFeatures::ehCleanupScope ());
130
+ bool requiresNormalCleanup = scope.isNormalCleanup () && hasFallthrough;
103
131
104
- mlir::OpBuilder::InsertionGuard guard (builder);
132
+ // If we don't need the cleanup at all, we're done.
133
+ assert (!cir::MissingFeatures::ehCleanupScopeRequiresEHCleanup ());
134
+ if (!requiresNormalCleanup) {
135
+ ehStack.popCleanup ();
136
+ return ;
137
+ }
138
+
139
+ // Copy the cleanup emission data out. This uses either a stack
140
+ // array or malloc'd memory, depending on the size, which is
141
+ // behavior that SmallVector would provide, if we could use it
142
+ // here. Unfortunately, if you ask for a SmallVector<char>, the
143
+ // alignment isn't sufficient.
144
+ auto *cleanupSource = reinterpret_cast <char *>(scope.getCleanupBuffer ());
145
+ alignas (EHScopeStack::ScopeStackAlignment) char
146
+ cleanupBufferStack[8 * sizeof (void *)];
147
+ std::unique_ptr<char []> cleanupBufferHeap;
148
+ size_t cleanupSize = scope.getCleanupSize ();
149
+ EHScopeStack::Cleanup *cleanup;
150
+
151
+ // This is necessary because we are going to deallocate the cleanup
152
+ // (in popCleanup) before we emit it.
153
+ if (cleanupSize <= sizeof (cleanupBufferStack)) {
154
+ memcpy (cleanupBufferStack, cleanupSource, cleanupSize);
155
+ cleanup = reinterpret_cast <EHScopeStack::Cleanup *>(cleanupBufferStack);
156
+ } else {
157
+ cleanupBufferHeap.reset (new char [cleanupSize]);
158
+ memcpy (cleanupBufferHeap.get (), cleanupSource, cleanupSize);
159
+ cleanup =
160
+ reinterpret_cast <EHScopeStack::Cleanup *>(cleanupBufferHeap.get ());
161
+ }
105
162
106
163
assert (!cir::MissingFeatures::ehCleanupFlags ());
107
- mlir::Block *cleanupEntry = getCurCleanupBlock (*this );
108
- builder.setInsertionPointToEnd (cleanupEntry);
109
- cleanup.emit (*this );
110
164
111
- ehStack.deallocate (cleanup.getSize ());
165
+ ehStack.popCleanup ();
166
+ scope.markEmitted ();
167
+ emitCleanup (*this , cleanup);
112
168
}
113
169
114
170
// / Pops cleanup blocks until the given savepoint is reached.
0 commit comments