Path: utzoo!attcan!uunet!husc6!uwvax!oddjob!mimsy!chris From: chris@mimsy.UUCP (Chris Torek) Newsgroups: comp.lang.fortran Subject: Re: Exception handling Message-ID: <13598@mimsy.UUCP> Date: 17 Sep 88 15:26:29 GMT References: <401@quintus.UUCP> <44400022@hcx2> Organization: U of Maryland, Dept. of Computer Science, Coll. Pk., MD 20742 Lines: 127 The original proposal from Richard O'Keefe (ok@quintus.UUCP): >>HANDLE ('exception name, ..., exception name') IN >>statements to be protected >>CANNOT HANDLE >>statements to execute if any of the exceptions cannot be trapped >>HANDLER >>statements to execute if any of the exceptions occurs >>END HANDLER He goes on to note that >>... A compiler would be entitled to generate code for *just* the >>CANNOT HANDLE branch, though it would be good manners to print a >>warning message. The precise location of an exception does not >>matter, but any pending exceptions must be signalled before control >>leaves the protected code. In article <44400022@hcx2> bill@hcx2.SSD.HARRIS.COM writes: >Oh, but it does. Without a precise location, how can the generated >code (or the runtime, or whoever) figure out whether the exception >occurred _inside_ the HANDLE section or _outside_. It does not need to `figure it out': Consider three kinds of machines. Primus: machines on which trapping some exception is in fact impossible (the hardware explodes, turning the computer into shrapnel :-) ). On such a machine, the compiler must treat HANDLE exception-list IN primary-block CANNOT HANDLE cannot-handle-block HANDLER handler-block END as the simpler statement-list cannot-handle-block This is not particularly useful (all the working code in primary-block vanishes) but at least the user need not wear battle-armour. Secundus: machines on which trapping some exception is trivial and cost-free. These are not interesting either. Tertius: machines on which trapping some exception is possible but non-trivial. This is most interesting if the machine has `imprecise faults'. By Richard O'Keefe's definitions, a compiler writer is free to pretend this machine is like the first, and merely generate the cannot-handle-block (along with a civil apology at compilation time). This is not interesting, so we will consider the other case. >This single fact causes us headaches in Ada, because it is VERY >expensive on our hardware to determine exactly where the exception >occurred. (I believe this is almost universally true in cases >where floating-point operations are done by an independent co-processor.) In the presence of pipelining, yes. In its absence, no. Morever, one can simulate the absence of pipelining (or multi-operations) by simply delaying until the exception is sure to have occurred. Hence the compiler could, instead of trying to pinpoint the error after it occurs, generate code more like the following: procedure delay past exception: for int i in [1..100] do skip; rof; # on some machines this might even be a system call. # on others it might be a single (rather slow) instruction. erudecorp ... delay past exception; # make sure we are not hit by an old one enable trap exceptions (exception-list) at HANDLER; primary-block; # do the usual computation delay past exception; # wait for any exceptions we generated disable trap exceptions (exception-list); goto DONE; # made it! HANDLER: # where this disable is placed depends on the language definition # (I myself would prefer stacked exception handler semantics). disable trap exceptions (exception-list); handler-block; DONE: [ok@quintus:] >>On which machines must this be inefficient (but how _can_ just >>compiling the CANNOT HANDLE branch be inefficient?) and what are the >>reasons for this inefficiency? [bill@hcx2.SSD.HARRIS.COM:] >Again, in order to know that the CANNOT HANDLE branch should be >executed requires knowing where the exception occurred. Not at all. The CANNOT HANDLE branch turns into no code whatsoever when catching exceptions. It is irrelevant when discussing exception catching efficiency, as it exists only for the case when exception catching is not done at all. The important thing is that a compiler that generates only the cannot-handle statements is likely to be viewed as deficient (unless we have one of those machines on which trapping exceptions is indeed impossible). And, if `delay past exception' is as slow as is the one shown above, obviously detailed exception catching will be slow (since at least one delay must be generated for each HANDLE statement). Well, so it goes. If you really *need* detailed exception catching, and you have a machine on which it is slow, let it be slow. If you do not *need* it, you can either leave it out of your code, or compile with a switch that tells the compiler, `For all HANDLE statements, generate only the primary-block, as if the HANDLE statement and the CANNOT HANDLE and HANDLER branches did not appear.' To me, this seems the best situation possible: If you *can* catch exceptions, the language permits you; if you cannot, it will tell you so; and if you can, but it is inefficient, you have the option of not bothering to catch exceptions (by leaving out the HANDLE statements). Thus, the price of this feature when not used is whatever code is required in the compiler and support libraries to implement it---i.e., there is no execution speed penalty, although there may be a compile and link time penalty---and the price of this feature when it *is* used is, well, the price of the feature. -- In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 7163) Domain: chris@mimsy.umd.edu Path: uunet!mimsy!chris