comparison gcc/ada/libgnat/a-exexpr.adb @ 145:1830386684a0

gcc-9.2.0
author anatofuz
date Thu, 13 Feb 2020 11:34:05 +0900
parents 84e7813d76e9
children
comparison
equal deleted inserted replaced
131:84e7813d76e9 145:1830386684a0
4 -- -- 4 -- --
5 -- A D A . E X C E P T I O N S . E X C E P T I O N _ P R O P A G A T I O N -- 5 -- A D A . E X C E P T I O N S . E X C E P T I O N _ P R O P A G A T I O N --
6 -- -- 6 -- --
7 -- B o d y -- 7 -- B o d y --
8 -- -- 8 -- --
9 -- Copyright (C) 1992-2018, Free Software Foundation, Inc. -- 9 -- Copyright (C) 1992-2019, Free Software Foundation, Inc. --
10 -- -- 10 -- --
11 -- GNAT is free software; you can redistribute it and/or modify it under -- 11 -- GNAT is free software; you can redistribute it and/or modify it under --
12 -- terms of the GNU General Public License as published by the Free Soft- -- 12 -- terms of the GNU General Public License as published by the Free Soft- --
13 -- ware Foundation; either version 3, or (at your option) any later ver- -- 13 -- ware Foundation; either version 3, or (at your option) any later ver- --
14 -- sion. GNAT is distributed in the hope that it will be useful, but WITH- -- 14 -- sion. GNAT is distributed in the hope that it will be useful, but WITH- --
195 procedure Set_Foreign_Occurrence (Excep : EOA; Mo : System.Address); 195 procedure Set_Foreign_Occurrence (Excep : EOA; Mo : System.Address);
196 -- Utility routine to initialize occurrence Excep from a foreign exception 196 -- Utility routine to initialize occurrence Excep from a foreign exception
197 -- whose machine occurrence is Mo. The message is empty, the backtrace 197 -- whose machine occurrence is Mo. The message is empty, the backtrace
198 -- is empty too and the exception identity is Foreign_Exception. 198 -- is empty too and the exception identity is Foreign_Exception.
199 199
200 -- Hooks called when entering/leaving an exception handler for a given 200 -- Hooks called when entering/leaving an exception handler for a
201 -- occurrence, aimed at handling the stack of active occurrences. The 201 -- given occurrence. The calls are generated by gigi in
202 -- calls are generated by gigi in tree_transform/N_Exception_Handler. 202 -- Exception_Handler_to_gnu_gcc.
203
204 -- Begin_Handler_v1, called when entering an exception handler,
205 -- claims responsibility for the handler to release the
206 -- GCC_Exception occurrence. End_Handler_v1, called when
207 -- leaving the handler, releases the occurrence, unless the
208 -- occurrence is propagating further up, or the handler is
209 -- dynamically nested in the context of another handler that
210 -- claimed responsibility for releasing that occurrence.
211
212 -- Responsibility is claimed by changing the Cleanup field to
213 -- Claimed_Cleanup, which enables claimed exceptions to be
214 -- recognized, and avoids accidental releases even by foreign
215 -- handlers.
216
217 function Begin_Handler_v1
218 (GCC_Exception : not null GCC_Exception_Access)
219 return System.Address;
220 pragma Export (C, Begin_Handler_v1, "__gnat_begin_handler_v1");
221 -- Called when entering an exception handler. Claim
222 -- responsibility for releasing GCC_Exception, by setting the
223 -- cleanup/release function to Claimed_Cleanup, and return the
224 -- address of the previous cleanup/release function.
225
226 procedure End_Handler_v1
227 (GCC_Exception : not null GCC_Exception_Access;
228 Saved_Cleanup : System.Address;
229 Propagating_Exception : GCC_Exception_Access);
230 pragma Export (C, End_Handler_v1, "__gnat_end_handler_v1");
231 -- Called when leaving an exception handler. Restore the
232 -- Saved_Cleanup in the GCC_Exception occurrence, and then release
233 -- it, unless it remains claimed by an enclosing handler, or
234 -- GCC_Exception and Propagating_Exception are the same
235 -- occurrence. Propagating_Exception could be either an
236 -- occurrence (re)raised within the handler of GCC_Exception, when
237 -- we're executing as an exceptional cleanup, or null, if we're
238 -- completing the handler of GCC_Exception normally.
239
240 procedure Claimed_Cleanup
241 (Reason : Unwind_Reason_Code;
242 GCC_Exception : not null GCC_Exception_Access);
243 pragma Export (C, Claimed_Cleanup, "__gnat_claimed_cleanup");
244 -- A do-nothing placeholder installed as GCC_Exception.Cleanup
245 -- while handling GCC_Exception, to claim responsibility for
246 -- releasing it, and to stop it from being accidentally released.
247
248 -- The following are version 0 implementations of the version 1
249 -- hooks above. They remain in place for compatibility with the
250 -- output of compilers that still use version 0, such as those
251 -- used during bootstrap. They are interoperable with the v1
252 -- hooks, except that the older versions may malfunction when
253 -- handling foreign exceptions passed to Reraise_Occurrence.
203 254
204 procedure Begin_Handler (GCC_Exception : not null GCC_Exception_Access); 255 procedure Begin_Handler (GCC_Exception : not null GCC_Exception_Access);
205 pragma Export (C, Begin_Handler, "__gnat_begin_handler"); 256 pragma Export (C, Begin_Handler, "__gnat_begin_handler");
257 -- Called when entering an exception handler translated by an old
258 -- compiler. It does nothing.
206 259
207 procedure End_Handler (GCC_Exception : GCC_Exception_Access); 260 procedure End_Handler (GCC_Exception : GCC_Exception_Access);
208 pragma Export (C, End_Handler, "__gnat_end_handler"); 261 pragma Export (C, End_Handler, "__gnat_end_handler");
262 -- Called when leaving an exception handler translated by an old
263 -- compiler. It releases GCC_Exception, unless it is null. It is
264 -- only ever null when the handler has a 'raise;' translated by a
265 -- v0-using compiler. The artificial handler variable passed to
266 -- End_Handler was set to null to tell End_Handler to refrain from
267 -- releasing the reraised exception. In v1 safer ways are used to
268 -- accomplish that.
209 269
210 -------------------------------------------------------------------- 270 --------------------------------------------------------------------
211 -- Accessors to Basic Components of a GNAT Exception Data Pointer -- 271 -- Accessors to Basic Components of a GNAT Exception Data Pointer --
212 -------------------------------------------------------------------- 272 --------------------------------------------------------------------
213 273
350 410
351 return Excep; 411 return Excep;
352 end if; 412 end if;
353 end Setup_Current_Excep; 413 end Setup_Current_Excep;
354 414
415 ----------------------
416 -- Begin_Handler_v1 --
417 ----------------------
418
419 function Begin_Handler_v1
420 (GCC_Exception : not null GCC_Exception_Access)
421 return System.Address is
422 Saved_Cleanup : constant System.Address := GCC_Exception.Cleanup;
423 begin
424 -- Claim responsibility for releasing this exception, and stop
425 -- others from releasing it.
426 GCC_Exception.Cleanup := Claimed_Cleanup'Address;
427 return Saved_Cleanup;
428 end Begin_Handler_v1;
429
430 --------------------
431 -- End_Handler_v1 --
432 --------------------
433
434 procedure End_Handler_v1
435 (GCC_Exception : not null GCC_Exception_Access;
436 Saved_Cleanup : System.Address;
437 Propagating_Exception : GCC_Exception_Access) is
438 begin
439 GCC_Exception.Cleanup := Saved_Cleanup;
440 -- Restore the Saved_Cleanup, so that it is either used to
441 -- release GCC_Exception below, or transferred to the next
442 -- handler of the Propagating_Exception occurrence. The
443 -- following test ensures that an occurrence is only released
444 -- once, even after reraises.
445 --
446 -- The idea is that the GCC_Exception is not to be released
447 -- unless it had an unclaimed Cleanup when the handler started
448 -- (see Begin_Handler_v1 above), but if we propagate across its
449 -- handler a reraise of the same exception, we transfer to the
450 -- Propagating_Exception the responsibility for running the
451 -- Saved_Cleanup when its handler completes.
452 --
453 -- This ownership transfer mechanism ensures safety, as in
454 -- single release and no dangling pointers, because there is no
455 -- way to hold on to the Machine_Occurrence of an
456 -- Exception_Occurrence: the only situations in which another
457 -- Exception_Occurrence gets the same Machine_Occurrence are
458 -- through Reraise_Occurrence, and plain reraise, and so we
459 -- have the following possibilities:
460 --
461 -- - Reraise_Occurrence is handled within the running handler,
462 -- and so when completing the dynamically nested handler, we
463 -- must NOT release the exception. A Claimed_Cleanup upon
464 -- entry of the nested handler, installed when entering the
465 -- enclosing handler, ensures the exception will not be
466 -- released by the nested handler, but rather by the enclosing
467 -- handler.
468 --
469 -- - Reraise_Occurrence/reraise escapes the running handler,
470 -- and we run as an exceptional cleanup for GCC_Exception. The
471 -- Saved_Cleanup was reinstalled, but since we're propagating
472 -- the same machine occurrence, we do not release it. Instead,
473 -- we transfer responsibility for releasing it to the eventual
474 -- handler of the propagating exception.
475 --
476 -- - An unrelated exception propagates through the running
477 -- handler. We restored GCC_Exception.Saved_Cleanup above.
478 -- Since we're propagating a different exception, we proceed to
479 -- release GCC_Exception, unless Saved_Cleanup was
480 -- Claimed_Cleanup, because then we know we're not in the
481 -- outermost handler for GCC_Exception.
482 --
483 -- - The handler completes normally, so it reinstalls the
484 -- Saved_Cleanup and runs it, unless it was Claimed_Cleanup.
485 -- If Saved_Cleanup is null, Unwind_DeleteException (currently)
486 -- has no effect, so we could skip it, but if it is ever
487 -- changed to do more in this case, we're ready for that,
488 -- calling it exactly once.
489 if Saved_Cleanup /= Claimed_Cleanup'Address
490 and then
491 Propagating_Exception /= GCC_Exception
492 then
493 declare
494 Current : constant EOA := Get_Current_Excep.all;
495 Cur_Occ : constant GCC_Exception_Access
496 := To_GCC_Exception (Current.Machine_Occurrence);
497 begin
498 -- If we are releasing the Machine_Occurrence of the current
499 -- exception, reset the access to it, so that it is no
500 -- longer accessible.
501 if Cur_Occ = GCC_Exception then
502 Current.Machine_Occurrence := System.Null_Address;
503 end if;
504 end;
505 Unwind_DeleteException (GCC_Exception);
506 end if;
507 end End_Handler_v1;
508
509 ---------------------
510 -- Claimed_Cleanup --
511 ---------------------
512
513 procedure Claimed_Cleanup
514 (Reason : Unwind_Reason_Code;
515 GCC_Exception : not null GCC_Exception_Access) is
516 pragma Unreferenced (Reason);
517 pragma Unreferenced (GCC_Exception);
518 begin
519 -- This procedure should never run. If it does, it's either a
520 -- version 0 handler or a foreign handler, attempting to
521 -- release an exception while a version 1 handler that claimed
522 -- responsibility for releasing the exception remains still
523 -- active. This placeholder stops GCC_Exception from being
524 -- released by them.
525
526 -- We could get away with just Null_Address instead, with
527 -- nearly the same effect, but with this placeholder we can
528 -- detect and report unexpected releases, and we can tell apart
529 -- a GCC_Exception without a Cleanup, from one with another
530 -- active handler, so as to still call Unwind_DeleteException
531 -- exactly once: currently, Unwind_DeleteException does nothing
532 -- when the Cleanup is null, but should it ever be changed to
533 -- do more, we'll still be safe.
534 null;
535 end Claimed_Cleanup;
536
355 ------------------- 537 -------------------
356 -- Begin_Handler -- 538 -- Begin_Handler --
357 ------------------- 539 -------------------
358 540
359 procedure Begin_Handler (GCC_Exception : not null GCC_Exception_Access) is 541 procedure Begin_Handler (GCC_Exception : not null GCC_Exception_Access) is