js/src/ds/Nestable.h
author Nika Layzell <nika@thelayzells.com>
Wed, 16 Sep 2020 20:47:55 +0000
changeset 549331 ab7d302fd3186b10ada9264528c80f6840e44571
parent 449035 66eb1f485c1a3ea81372758bc92292c9428b17cd
permissions -rw-r--r--
Bug 1659696 - Check PendingInitialization before targeting in window.open, r=kmag This requires adding the flag as a synced field on the BrowsingContext, and checking it in a few more places. Attempts to open a new window in this racy manner will now raise an exception. This should avoid the issue from bug 1658854 by blocking the buggy attempts to load before the nested event loop has been exited. Differential Revision: https://phabricator.services.mozilla.com/D87927

/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
 * vim: set ts=8 sts=2 et sw=2 tw=80:
 * 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/. */

#ifndef ds_Nestable_h
#define ds_Nestable_h

#include "mozilla/Assertions.h"
#include "mozilla/Attributes.h"

namespace js {

// A base class for nestable structures.
template <typename Concrete>
class MOZ_STACK_CLASS Nestable {
  Concrete** stack_;
  Concrete* enclosing_;

 protected:
  explicit Nestable(Concrete** stack) : stack_(stack), enclosing_(*stack) {
    *stack_ = static_cast<Concrete*>(this);
  }

  // These method are protected. Some derived classes, such as ParseContext,
  // do not expose the ability to walk the stack.
  Concrete* enclosing() const { return enclosing_; }

  template <typename Predicate /* (Concrete*) -> bool */>
  static Concrete* findNearest(Concrete* it, Predicate predicate) {
    while (it && !predicate(it)) {
      it = it->enclosing();
    }
    return it;
  }

  template <typename T>
  static T* findNearest(Concrete* it) {
    while (it && !it->template is<T>()) {
      it = it->enclosing();
    }
    return it ? &it->template as<T>() : nullptr;
  }

  template <typename T, typename Predicate /* (T*) -> bool */>
  static T* findNearest(Concrete* it, Predicate predicate) {
    while (it && (!it->template is<T>() || !predicate(&it->template as<T>()))) {
      it = it->enclosing();
    }
    return it ? &it->template as<T>() : nullptr;
  }

 public:
  ~Nestable() {
    MOZ_ASSERT(*stack_ == static_cast<Concrete*>(this));
    *stack_ = enclosing_;
  }
};

}  // namespace js

#endif /* ds_Nestable_h */