Bug 1206822 - Handle JS exceptions in NativeJSContainer; r=snorp
authorJim Chen <nchen@mozilla.com>
Mon, 18 Apr 2016 08:46:31 -0400
changeset 331470 317bc3f69953ab30354ae88bfe30061cabb29bb2
parent 331469 ca4c37c89034e5750d74b72817f8b701b5e56c5e
child 331471 755eb5d58f6f3ee4e41f9844e4491aa2bbd8e9a1
push id6048
push userkmoir@mozilla.com
push dateMon, 06 Jun 2016 19:02:08 +0000
treeherdermozilla-beta@46d72a56c57d [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssnorp
bugs1206822
milestone48.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1206822 - Handle JS exceptions in NativeJSContainer; r=snorp Clear any JS exceptions in appropriate places in NativeJSContainer, so the exceptions don't affect subsequent JS API calls. We don't actually "handle" the exceptions because we throw a Java exception instead or it is safe to ignore the JS exception.
widget/android/NativeJSContainer.cpp
--- a/widget/android/NativeJSContainer.cpp
+++ b/widget/android/NativeJSContainer.cpp
@@ -34,26 +34,16 @@ bool CheckThread()
     if (!NS_IsMainThread()) {
         jni::ThrowException("java/lang/IllegalThreadStateException",
                             "Not on Gecko thread");
         return false;
     }
     return true;
 }
 
-bool
-CheckJSCall(bool result)
-{
-    if (!result) {
-        jni::ThrowException("java/lang/UnsupportedOperationException",
-                            "JSAPI call failed");
-    }
-    return result;
-}
-
 template<class C, typename T> bool
 CheckJNIArgument(const jni::Ref<C, T>& arg)
 {
     if (!arg) {
         jni::ThrowException("java/lang/IllegalArgumentException",
                             "Null argument");
     }
     return !!arg;
@@ -124,16 +114,26 @@ class NativeJSContainerImpl final
     {
         if (!mJSObject) {
             jni::ThrowException("java/lang/NullPointerException",
                                 "Null JSObject");
         }
         return !!mJSObject;
     }
 
+    bool CheckJSCall(bool result) const
+    {
+        if (!result) {
+            JS_ClearPendingException(mJSContext);
+            jni::ThrowException("java/lang/UnsupportedOperationException",
+                                "JSAPI call failed");
+        }
+        return result;
+    }
+
     // Check that a JS Value contains a particular property type as indicaed by
     // the property's InValue method (e.g. StringProperty::InValue).
     bool CheckProperty(bool (Self::*InValue)(JS::HandleValue) const,
                        JS::HandleValue val) const
     {
         if (!(this->*InValue)(val)) {
             // XXX this can happen when converting a double array inside a
             // Bundle, because double arrays can be misidentified as an int
@@ -430,27 +430,31 @@ class NativeJSContainerImpl final
             return false;
         }
         JS::RootedObject obj(mJSContext, &val.toObject());
         bool isArray;
         uint32_t length = 0;
         if (!JS_IsArrayObject(mJSContext, obj, &isArray) ||
             !isArray ||
             !JS_GetArrayLength(mJSContext, obj, &length)) {
+            JS_ClearPendingException(mJSContext);
             return false;
         }
         if (!length) {
             // Empty arrays are always okay.
             return true;
         }
         // We only check to see the first element is the target type. If the
         // array has mixed types, we'll throw an error during actual conversion.
         JS::RootedValue element(mJSContext);
-        return JS_GetElement(mJSContext, obj, 0, &element) &&
-               (this->*Prop::InValue)(element);
+        if (!JS_GetElement(mJSContext, obj, 0, &element)) {
+            JS_ClearPendingException(mJSContext);
+            return false;
+        }
+        return (this->*Prop::InValue)(element);
     }
 
     template<class Prop> typename Prop::NativeArray
     ArrayFromValue(JS::HandleValue val)
     {
         JS::RootedObject obj(mJSContext, &val.toObject());
         uint32_t length = 0;
         if (!CheckJSCall(JS_GetArrayLength(mJSContext, obj, &length))) {