Created
February 10, 2012 20:04
-
-
Save jorendorff/1792357 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* This is for writing C++ code that does the equivalent of JS try/finally. | |
* Normal infallible C++ cleanup code should just go in a C++ destructor. | |
* This is for cleanup that should be *skipped* in the unusual case that | |
* the try block exits with an uncatchable error (OOM or timeout). | |
* | |
* Use it like this: | |
* | |
* bool ok; | |
* ... YOUR TRY-BLOCK CODE HERE ... | |
* if (AutoFinallyBlock afb(cx, ok)) { | |
* bool cleanupOK; | |
* ... YOUR CLEANUP CODE HERE ... | |
* ok = afb.leave(closedOK); | |
* } | |
* return ok; | |
* | |
*/ | |
class AutoFinallyBlock { | |
private: | |
JSContext *cx; | |
Value exception; | |
enum { OK = JS_GENERIC_MAGIC, DONE = JS_THIS_POISON }; | |
public: | |
AutoFinallyBlock(JSContext *cx, bool ok) : cx(cx), ok(ok) { | |
if (ok) { | |
/* Case 1: try-block exited successfully. */ | |
JS_ASSERT(!cx->isExceptionPending()); | |
exception.setMagic(OK); | |
} else if (cx->isExceptionPending()) { | |
/* Case 2: try-block threw an exception. */ | |
exception = cx->getPendingException(); | |
cx->clearPendingException(); | |
} else { | |
/* | |
* Case 3: try-block died with an uncatchable error. We're done | |
* here; the caller will skip the finally block. | |
*/ | |
exception.setMagic(DONE); | |
} | |
} | |
operator bool() const { | |
return !exception.isParticularMagic(DONE); | |
} | |
void debugSetDone() { | |
#ifdef DEBUG | |
exception.setMagic(DONE); | |
#endif | |
} | |
void leave(bool cleanupOK) { | |
/* | |
* There are four possible cases: | |
* was ok and now cleanupOK - do nothing, return true | |
* was ok but now !cleanupOK - do nothing, return false | |
* had exception and now cleanupOK - restore exception, return false | |
* had exception and now !cleanupOK - do nothing, return false | |
* | |
* This method MUST NOT be called if we had an uncatchable error. | |
* The isMagic call here enforces that with an assertion. | |
*/ | |
if (exception.isMagic(JS_EVERYTHING_IS_FINE)) { | |
debugSetDone(); | |
return cleanupOK; | |
} | |
if (cleanupOK) | |
cx->setPendingException(exception); | |
debugSetDone(); | |
return false; | |
} | |
~AutoFinallyBlock() { | |
JS_ASSERT(exception.isParticularMagic(DONE)); | |
} | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment