Bug 801487 - Implement ErrorResult::ThrowTypeError. r=bz
authorMasatoshi Kimura <VYV03354@nifty.ne.jp>
Tue, 06 Nov 2012 18:23:14 -0500
changeset 121139 71c0fa0964c3a7a667357bb82d4a7d3f9986f807
parent 121138 c083bb05e3fd3fed4cac5f6bd59418dd7ad66515
child 121140 4aeebb3cacfa9bd7093cd4580ea40037e58af7ea
push id273
push userlsblakk@mozilla.com
push dateThu, 14 Feb 2013 23:19:38 +0000
treeherdermozilla-release@c5e807a3f8b8 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbz
bugs801487
milestone19.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 801487 - Implement ErrorResult::ThrowTypeError. r=bz
dom/bindings/BindingUtils.cpp
dom/bindings/BindingUtils.h
dom/bindings/Bindings.conf
dom/bindings/ErrorResult.h
dom/bindings/Errors.msg
--- a/dom/bindings/BindingUtils.cpp
+++ b/dom/bindings/BindingUtils.cpp
@@ -1,14 +1,15 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-*/
 /* vim: set ts=2 sw=2 et tw=79: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
+#include <algorithm>
 #include <stdarg.h>
 
 #include "BindingUtils.h"
 
 #include "AccessCheck.h"
 #include "WrapperFactory.h"
 #include "xpcprivate.h"
 #include "nsContentUtils.h"
@@ -39,16 +40,68 @@ ThrowErrorMessage(JSContext* aCx, const 
   va_list ap;
   va_start(ap, aErrorNumber);
   JS_ReportErrorNumberVA(aCx, GetErrorMessage, NULL,
                          static_cast<const unsigned>(aErrorNumber), ap);
   va_end(ap);
   return false;
 }
 
+} // namespace dom
+
+struct ErrorResult::Message {
+  nsTArray<nsString> mArgs;
+  dom::ErrNum mErrorNumber;
+};
+
+void
+ErrorResult::ThrowTypeError(const dom::ErrNum errorNumber, ...)
+{
+  va_list ap;
+  va_start(ap, errorNumber);
+  if (IsTypeError()) {
+    delete mMessage;
+  }
+  mResult = NS_ERROR_TYPE_ERR;
+  Message* message = new Message();
+  message->mErrorNumber = errorNumber;
+  uint16_t argCount =
+    dom::GetErrorMessage(nullptr, nullptr, errorNumber)->argCount;
+  MOZ_ASSERT(argCount <= 10);
+  argCount = std::min<uint16_t>(argCount, 10);
+  while (argCount--) {
+    message->mArgs.AppendElement(*va_arg(ap, nsString*));
+  }
+  mMessage = message;
+  va_end(ap);
+}
+
+void
+ErrorResult::ReportTypeError(JSContext* aCx)
+{
+  MOZ_ASSERT(mMessage, "ReportTypeError() can be called only once");
+
+  Message* message = mMessage;
+  const uint32_t argCount = message->mArgs.Length();
+  const jschar* args[11];
+  for (uint32_t i = 0; i < argCount; ++i) {
+    args[i] = message->mArgs.ElementAt(i).get();
+  }
+  args[argCount] = nullptr;
+
+  JS_ReportErrorNumberUCArray(aCx, dom::GetErrorMessage, nullptr,
+                              static_cast<const unsigned>(message->mErrorNumber),
+                              argCount > 0 ? args : nullptr);
+
+  delete message;
+  mMessage = nullptr;
+}
+
+namespace dom {
+
 bool
 DefineConstants(JSContext* cx, JSObject* obj, ConstantSpec* cs)
 {
   for (; cs->name; ++cs) {
     JSBool ok =
       JS_DefineProperty(cx, obj, cs->name, cs->value, NULL, NULL,
                         JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT);
     if (!ok) {
--- a/dom/bindings/BindingUtils.h
+++ b/dom/bindings/BindingUtils.h
@@ -26,24 +26,16 @@
 
 // nsGlobalWindow implements nsWrapperCache, but doesn't always use it. Don't
 // try to use it without fixing that first.
 class nsGlobalWindow;
 
 namespace mozilla {
 namespace dom {
 
-enum ErrNum {
-#define MSG_DEF(_name, _argc, _str) \
-  _name,
-#include "mozilla/dom/Errors.msg"
-#undef MSG_DEF
-  Err_Limit
-};
-
 bool
 ThrowErrorMessage(JSContext* aCx, const ErrNum aErrorNumber, ...);
 
 template<bool mainThread>
 inline bool
 Throw(JSContext* cx, nsresult rv)
 {
   using mozilla::dom::workers::exceptions::ThrowDOMExceptionForNSResult;
@@ -56,20 +48,24 @@ Throw(JSContext* cx, nsresult rv)
       ThrowDOMExceptionForNSResult(cx, rv);
     }
   }
   return false;
 }
 
 template<bool mainThread>
 inline bool
-ThrowMethodFailedWithDetails(JSContext* cx, const ErrorResult& rv,
+ThrowMethodFailedWithDetails(JSContext* cx, ErrorResult& rv,
                              const char* /* ifaceName */,
                              const char* /* memberName */)
 {
+  if (rv.IsTypeError()) {
+    rv.ReportTypeError(cx);
+    return false;
+  }
   return Throw<mainThread>(cx, rv.ErrorCode());
 }
 
 // Returns true if the JSClass is used for DOM objects.
 inline bool
 IsDOMClass(const JSClass* clasp)
 {
   return clasp->flags & JSCLASS_IS_DOMJSCLASS;
--- a/dom/bindings/Bindings.conf
+++ b/dom/bindings/Bindings.conf
@@ -348,24 +348,19 @@ DOMInterfaces = {
 
 'SVGTransformList': {
     'nativeType': 'mozilla::DOMSVGTransformList',
     'headerFile': 'DOMSVGTransformList.h',
     'resultNotAddRefed': [ 'getItem' ]
 },
 
 'TextEncoder': {
-    'headerFile': 'mozilla/dom/TextEncoder.h',
     'implicitJSContext': [ 'encode' ],
 },
 
-'TextDecoder': {
-    'headerFile': 'mozilla/dom/TextDecoder.h',
-},
-
 'WebGLActiveInfo': {
    'nativeType': 'mozilla::WebGLActiveInfo',
    'headerFile': 'WebGLContext.h',
    'wrapperCache': False
 },
 
 'WebGLBuffer': {
    'nativeType': 'mozilla::WebGLBuffer',
--- a/dom/bindings/ErrorResult.h
+++ b/dom/bindings/ErrorResult.h
@@ -6,53 +6,84 @@
 
 /**
  * A struct for tracking exceptions that need to be thrown to JS.
  */
 
 #ifndef mozilla_ErrorResult_h
 #define mozilla_ErrorResult_h
 
+#include <stdarg.h>
+
+#include "jsapi.h"
 #include "nscore.h"
 #include "mozilla/Assertions.h"
 
 namespace mozilla {
 
+namespace dom {
+
+enum ErrNum {
+#define MSG_DEF(_name, _argc, _str) \
+  _name,
+#include "mozilla/dom/Errors.msg"
+#undef MSG_DEF
+  Err_Limit
+};
+
+} // namespace dom
+
 class ErrorResult {
 public:
   ErrorResult() {
     mResult = NS_OK;
   }
+#ifdef DEBUG
+  ~ErrorResult() {
+    MOZ_ASSERT_IF(IsTypeError(), !mMessage);
+  }
+#endif
 
   void Throw(nsresult rv) {
     MOZ_ASSERT(NS_FAILED(rv), "Please don't try throwing success");
+    MOZ_ASSERT(rv != NS_ERROR_TYPE_ERR, "Use ThrowTypeError()");
+    MOZ_ASSERT(!IsTypeError(), "Don't overwite TypeError");
     mResult = rv;
   }
 
+  void ThrowTypeError(const dom::ErrNum errorNumber, ...);
+  void ReportTypeError(JSContext* cx);
+  bool IsTypeError() const { return ErrorCode() == NS_ERROR_TYPE_ERR; }
+
   // In the future, we can add overloads of Throw that take more
   // interesting things, like strings or DOM exception types or
   // something if desired.
 
   // Backwards-compat to make conversion simpler.  We don't call
   // Throw() here because people can easily pass success codes to
   // this.
   void operator=(nsresult rv) {
+    MOZ_ASSERT(rv != NS_ERROR_TYPE_ERR, "Use ThrowTypeError()");
+    MOZ_ASSERT(!IsTypeError(), "Don't overwite TypeError");
     mResult = rv;
   }
 
   bool Failed() const {
     return NS_FAILED(mResult);
   }
 
   nsresult ErrorCode() const {
     return mResult;
   }
 
 private:
   nsresult mResult;
+  struct Message;
+  // Do not use nsAutoPtr to avoid extra initalizatoin and check.
+  Message* mMessage;
 
   // Not to be implemented, to make sure people always pass this by
   // reference, not by value.
   ErrorResult(const ErrorResult&) MOZ_DELETE;
 };
 
 } // namespace mozilla
 
--- a/dom/bindings/Errors.msg
+++ b/dom/bindings/Errors.msg
@@ -27,8 +27,10 @@ MSG_DEF(MSG_DOES_NOT_IMPLEMENT_INTERFACE
 MSG_DEF(MSG_NOT_IN_UNION, 1, "Value could not be converted to any of: {0}.")
 MSG_DEF(MSG_ILLEGAL_CONSTRUCTOR, 0, "Illegal constructor.")
 MSG_DEF(MSG_NO_PROPERTY_SETTER, 1, "{0} doesn't have an indexed property setter.")
 MSG_DEF(MSG_ENFORCE_RANGE_NON_FINITE, 1, "Non-finite value is out of range for {0}.")
 MSG_DEF(MSG_ENFORCE_RANGE_OUT_OF_RANGE, 1, "Value is out of range for {0}.")
 MSG_DEF(MSG_NOT_SEQUENCE, 0, "object can not be converted to a sequence")
 MSG_DEF(MSG_INVALID_ARG, 2, "argument {0} is not valid for any of the {1}-argument overloads")
 MSG_DEF(MSG_GLOBAL_NOT_NATIVE, 0, "global is not a native object")
+MSG_DEF(MSG_ENCODING_NOT_SUPPORTED, 1, "The given encoding '{0}' is not supported.")
+MSG_DEF(MSG_DOM_ENCODING_NOT_UTF, 0, "The encoding must be utf-8, utf-16, or utf-16be.")