Bug 1330536 part 3. Add a subclass of FastErrorResult that can be used only to throw OOM. r=smaug
authorBoris Zbarsky <bzbarsky@mit.edu>
Tue, 17 Jan 2017 23:52:13 -0500
changeset 374788 ec1b482c8b7efdfaddab0378cef686b68edd85ca
parent 374787 555c3c62d3c0bb1e06ae053da5e918e068dbfc06
child 374789 c9b845082a916520ab66e164ba5987de18c07e40
push id6996
push userjlorenzo@mozilla.com
push dateMon, 06 Mar 2017 20:48:21 +0000
treeherdermozilla-beta@d89512dab048 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssmaug
bugs1330536
milestone53.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 1330536 part 3. Add a subclass of FastErrorResult that can be used only to throw OOM. r=smaug
dom/bindings/BindingUtils.h
dom/bindings/ErrorResult.h
--- a/dom/bindings/BindingUtils.h
+++ b/dom/bindings/BindingUtils.h
@@ -1847,26 +1847,16 @@ HasPropertyOnPrototype(JSContext* cx, JS
 // shadowPrototypeProperties is false then skip properties that are also
 // present on the proto chain of proxy.  If shadowPrototypeProperties is true,
 // then the "proxy" argument is ignored.
 bool
 AppendNamedPropertyIds(JSContext* cx, JS::Handle<JSObject*> proxy,
                        nsTArray<nsString>& names,
                        bool shadowPrototypeProperties, JS::AutoIdVector& props);
 
-namespace binding_detail {
-
-class FastErrorResult :
-    public mozilla::binding_danger::TErrorResult<
-      mozilla::binding_danger::JustAssertCleanupPolicy>
-{
-};
-
-} // namespace binding_detail
-
 enum StringificationBehavior {
   eStringify,
   eEmpty,
   eNull
 };
 
 template<typename T>
 static inline bool
--- a/dom/bindings/ErrorResult.h
+++ b/dom/bindings/ErrorResult.h
@@ -97,16 +97,17 @@ struct StringArrayAppender
     aArgs.AppendElement(aFirst);
     Append(aArgs, aCount - 1, Forward<Ts>(aOtherArgs)...);
   }
 };
 
 } // namespace dom
 
 class ErrorResult;
+class OOMReporter;
 
 namespace binding_danger {
 
 /**
  * Templated implementation class for various ErrorResult-like things.  The
  * instantiations differ only in terms of their cleanup policies (used in the
  * destructor), which they can specify via the template argument.  Note that
  * this means it's safe to reinterpret_cast between the instantiations unless
@@ -157,16 +158,17 @@ public:
 
   explicit TErrorResult(nsresult aRv)
     : TErrorResult()
   {
     AssignErrorCode(aRv);
   }
 
   operator ErrorResult&();
+  operator OOMReporter&();
 
   void Throw(nsresult rv) {
     MOZ_ASSERT(NS_FAILED(rv), "Please don't try throwing success");
     AssignErrorCode(rv);
   }
 
   // Duplicate our current state on the given TErrorResult object.  Any
   // existing errors or messages on the target will be suppressed before
@@ -532,16 +534,92 @@ binding_danger::TErrorResult<CleanupPoli
 // A class for use when an ErrorResult should just automatically be ignored.
 // This doesn't inherit from ErrorResult so we don't make two separate calls to
 // SuppressException.
 class IgnoredErrorResult :
     public binding_danger::TErrorResult<binding_danger::JustSuppressCleanupPolicy>
 {
 };
 
+namespace dom {
+namespace binding_detail {
+class FastErrorResult :
+    public mozilla::binding_danger::TErrorResult<
+      mozilla::binding_danger::JustAssertCleanupPolicy>
+{
+};
+} // namespace binding_detail
+} // namespace dom
+
+// This part is a bit annoying.  We want an OOMReporter class that has the
+// following properties:
+//
+// 1) Can be cast to from any ErrorResult-like type.
+// 2) Has a fast destructor (because we want to use it from bindings).
+// 3) Won't be randomly instantiated by non-binding code (because the fast
+//    destructor is not so safe.
+// 4) Doesn't look ugly on the callee side (e.g. isn't in the binding_detail or
+//    binding_danger namespace).
+//
+// We do this by having two classes: The class callees should use, which has the
+// things we want and a private constructor, and a friend subclass in the
+// binding_danger namespace that can be used to construct it.
+namespace binding_danger {
+class OOMReporterInstantiator;
+} // namespace binding_danger
+
+class OOMReporter : private dom::binding_detail::FastErrorResult
+{
+public:
+  void ReportOOM()
+  {
+    Throw(NS_ERROR_OUT_OF_MEMORY);
+  }
+
+private:
+  // OOMReporterInstantiator is a friend so it can call our constructor and
+  // MaybeSetPendingException.
+  friend class binding_danger::OOMReporterInstantiator;
+
+  // TErrorResult is a friend so its |operator OOMReporter&()| can work.
+  template<typename CleanupPolicy>
+  friend class binding_danger::TErrorResult;
+
+  OOMReporter()
+    : dom::binding_detail::FastErrorResult()
+  {
+  }
+};
+
+namespace binding_danger {
+class OOMReporterInstantiator : public OOMReporter
+{
+public:
+  OOMReporterInstantiator()
+    : OOMReporter()
+  {
+  }
+
+  // We want to be able to call MaybeSetPendingException from codegen.  The one
+  // on OOMReporter is not callable directly, because it comes from a private
+  // superclass.  But we're a friend, so _we_ can call it.
+  bool MaybeSetPendingException(JSContext* cx)
+  {
+    return OOMReporter::MaybeSetPendingException(cx);
+  }
+};
+} // namespace binding_danger
+
+template<typename CleanupPolicy>
+binding_danger::TErrorResult<CleanupPolicy>::operator OOMReporter&()
+{
+  return *static_cast<OOMReporter*>(
+     reinterpret_cast<TErrorResult<JustAssertCleanupPolicy>*>(this));
+}
+
 /******************************************************************************
  ** Macros for checking results
  ******************************************************************************/
 
 #define ENSURE_SUCCESS(res, ret)                                          \
   do {                                                                    \
     if (res.Failed()) {                                                   \
       nsCString msg;                                                      \