Added TryCatch::ReThrow method.
authorchristian.plesner.hansen@gmail.com <christian.plesner.hansen@gmail.com@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Tue, 3 Nov 2009 08:53:34 +0000 (08:53 +0000)
committerchristian.plesner.hansen@gmail.com <christian.plesner.hansen@gmail.com@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Tue, 3 Nov 2009 08:53:34 +0000 (08:53 +0000)
Review URL: http://codereview.chromium.org/342078

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@3201 ce2b1a6d-e550-0410-aec6-3dcde31c8c00

include/v8.h
src/api.cc
test/cctest/test-api.cc

index 5f3b68b..c372d0c 100644 (file)
@@ -2473,6 +2473,15 @@ class V8EXPORT TryCatch {
   bool CanContinue() const;
 
   /**
+   * Throws the exception caught by this TryCatch in a way that avoids
+   * it being caught again by this same TryCatch.  As with ThrowException
+   * it is illegal to execute any JavaScript operations after calling
+   * ReThrow; the caller must return immediately to where the exception
+   * is caught.
+   */
+  Handle<Value> ReThrow();
+
+  /**
    * Returns the exception caught by this try/catch block.  If no exception has
    * been caught an empty handle is returned.
    *
@@ -2527,9 +2536,10 @@ class V8EXPORT TryCatch {
   TryCatch* next_;
   void* exception_;
   void* message_;
-  bool is_verbose_;
-  bool can_continue_;
-  bool capture_message_;
+  bool is_verbose_ : 1;
+  bool can_continue_ : 1;
+  bool capture_message_ : 1;
+  bool rethrow_ : 1;
   void* js_handler_;
 };
 
index bde5fdc..20edbc5 100644 (file)
@@ -1197,13 +1197,21 @@ v8::TryCatch::TryCatch()
       is_verbose_(false),
       can_continue_(true),
       capture_message_(true),
+      rethrow_(false),
       js_handler_(NULL) {
   i::Top::RegisterTryCatchHandler(this);
 }
 
 
 v8::TryCatch::~TryCatch() {
-  i::Top::UnregisterTryCatchHandler(this);
+  if (rethrow_) {
+    v8::HandleScope scope;
+    v8::Local<v8::Value> exc = v8::Local<v8::Value>::New(Exception());
+    i::Top::UnregisterTryCatchHandler(this);
+    v8::ThrowException(exc);
+  } else {
+    i::Top::UnregisterTryCatchHandler(this);
+  }
 }
 
 
@@ -1217,6 +1225,13 @@ bool v8::TryCatch::CanContinue() const {
 }
 
 
+v8::Handle<v8::Value> v8::TryCatch::ReThrow() {
+  if (!HasCaught()) return v8::Local<v8::Value>();
+  rethrow_ = true;
+  return v8::Undefined();
+}
+
+
 v8::Local<Value> v8::TryCatch::Exception() const {
   if (HasCaught()) {
     // Check for out of memory exception.
index b3c8515..514a22f 100644 (file)
@@ -8662,3 +8662,29 @@ THREADED_TEST(QuietSignalingNaNs) {
     }
   }
 }
+
+
+static v8::Handle<Value> SpaghettiIncident(const v8::Arguments& args) {
+  v8::HandleScope scope;
+  v8::TryCatch tc;
+  v8::Handle<v8::String> str = args[0]->ToString();
+  if (tc.HasCaught())
+    return tc.ReThrow();
+  return v8::Undefined();
+}
+
+
+// Test that a stack overflow can be propagated down through a spaghetti
+// stack using ReThrow.
+THREADED_TEST(SpaghettiStackOverflow) {
+  v8::HandleScope scope;
+  LocalContext context;
+  context->Global()->Set(
+      v8::String::New("s"),
+      v8::FunctionTemplate::New(SpaghettiIncident)->GetFunction());
+  v8::TryCatch try_catch;
+  CompileRun("var o = {toString: function () {return s(o);}}; s(o);");
+  CHECK(try_catch.HasCaught());
+  v8::String::Utf8Value value(try_catch.Exception());
+  CHECK_NE(0, strstr(*value, "RangeError"));
+}