@@ -70,45 +70,101 @@ void EHScopeStack::deallocate(size_t size) {
7070}
7171
7272void *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;
7476
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 ());
7978
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 ());
81103}
82104
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?" );
88111}
89112
90113// / Pops a cleanup block. If the block includes a normal cleanup, the
91114// / current insertion point is threaded through the cleanup, as are
92115// / any branch fixups on the cleanup.
93116void CIRGenFunction::popCleanupBlock () {
94117 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 ());
95125
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;
100129
101- // The eventual implementation here will use the EHCleanupScope helper class.
102- assert (!cir::MissingFeatures::ehCleanupScope ());
130+ bool requiresNormalCleanup = scope.isNormalCleanup () && hasFallthrough;
103131
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+ }
105162
106163 assert (!cir::MissingFeatures::ehCleanupFlags ());
107- mlir::Block *cleanupEntry = getCurCleanupBlock (*this );
108- builder.setInsertionPointToEnd (cleanupEntry);
109- cleanup.emit (*this );
110164
111- ehStack.deallocate (cleanup.getSize ());
165+ ehStack.popCleanup ();
166+ scope.markEmitted ();
167+ emitCleanup (*this , cleanup);
112168}
113169
114170// / Pops cleanup blocks until the given savepoint is reached.
0 commit comments