Bug 662001 - Move js::RangeCheckedPointer<T> to mozilla::RangedPtr<T>, make it no longer implicitly convert to T*, and adjust users accordingly. r=cjones
authorJeff Walden <jwalden@mit.edu>
Mon, 06 Jun 2011 11:02:34 -0700
changeset 71218 739c0fd21cccb1eae3de374b6d39616048be2e28
parent 71217 955cb37c90b581fcf4ff0a9c7228abf27413c03a
child 71219 21ab818fcdf6816654c2abe64e774b5a6529db2a
push idunknown
push userunknown
push dateunknown
reviewerscjones
bugs662001
milestone7.0a1
Bug 662001 - Move js::RangeCheckedPointer<T> to mozilla::RangedPtr<T>, make it no longer implicitly convert to T*, and adjust users accordingly. r=cjones
js/src/Makefile.in
js/src/jsonparser.cpp
js/src/jsonparser.h
js/src/jstl.h
mfbt/RangedPtr.h
mfbt/Types.h
mfbt/Util.h
--- a/js/src/Makefile.in
+++ b/js/src/Makefile.in
@@ -291,16 +291,17 @@ EXPORTS_vm = \
 #
 VPATH		+= \
 		$(srcdir)/../../mfbt \
 		$(NULL)
 
 EXPORTS_NAMESPACES += mozilla
 
 EXPORTS_mozilla = \
+		RangedPtr.h \
 		Types.h		\
 		Util.h          \
 		$(NULL)
 
 ifdef ENABLE_TRACEJIT
 VPATH		+= \
 		$(srcdir)/tracejit \
 		$(srcdir)/nanojit \
--- a/js/src/jsonparser.cpp
+++ b/js/src/jsonparser.cpp
@@ -76,24 +76,24 @@ JSONParser::readString()
         error("unterminated string literal");
         return token(Error);
     }
 
     /*
      * Optimization: if the source contains no escaped characters, create the
      * string directly from the source text.
      */
-    RangeCheckedPointer<const jschar> start = current;
+    RangedPtr<const jschar> start = current;
     for (; current < end; current++) {
         if (*current == '"') {
             size_t length = current - start;
             current++;
             JSFlatString *str = (ST == JSONParser::PropertyName)
-                                ? js_AtomizeChars(cx, start, length)
-                                : js_NewStringCopyN(cx, start, length);
+                                ? js_AtomizeChars(cx, start.get(), length)
+                                : js_NewStringCopyN(cx, start.get(), length);
             if (!str)
                 return token(OOM);
             return stringToken(str);
         }
 
         if (*current == '\\')
             break;
 
@@ -105,17 +105,17 @@ JSONParser::readString()
 
     /*
      * Slow case: string contains escaped characters.  Copy a maximal sequence
      * of unescaped characters into a temporary buffer, then an escaped
      * character, and repeat until the entire string is consumed.
      */
     StringBuffer buffer(cx);
     do {
-        if (start < current && !buffer.append(start, current))
+        if (start < current && !buffer.append(start.get(), current.get()))
             return token(OOM);
 
         if (current >= end)
             break;
 
         jschar c = *current++;
         if (c == '"') {
             JSFlatString *str = (ST == JSONParser::PropertyName)
@@ -195,17 +195,17 @@ JSONParser::readNumber()
     bool negative = *current == '-';
 
     /* -? */
     if (negative && ++current == end) {
         error("no number after minus sign");
         return token(Error);
     }
 
-    const RangeCheckedPointer<const jschar> digitStart = current;
+    const RangedPtr<const jschar> digitStart = current;
 
     /* 0|[1-9][0-9]+ */
     if (!JS7_ISDEC(*current)) {
         error("unexpected non-digit");
         return token(Error);
     }
     if (*current++ != '0') {
         for (; current < end; current++) {
@@ -213,17 +213,17 @@ JSONParser::readNumber()
                 break;
         }
     }
 
     /* Fast path: no fractional or exponent part. */
     if (current == end || (*current != '.' && *current != 'e' && *current != 'E')) {
         const jschar *dummy;
         jsdouble d;
-        if (!GetPrefixInteger(cx, digitStart, current, 10, &dummy, &d))
+        if (!GetPrefixInteger(cx, digitStart.get(), current.get(), 10, &dummy, &d))
             return token(OOM);
         JS_ASSERT(current == dummy);
         return numberToken(negative ? -d : d);
     }
 
     /* (\.[0-9]+)? */
     if (current < end && *current == '.') {
         if (++current == end) {
@@ -259,17 +259,17 @@ JSONParser::readNumber()
         while (++current < end) {
             if (!JS7_ISDEC(*current))
                 break;
         }
     }
 
     jsdouble d;
     const jschar *finish;
-    if (!js_strtod(cx, digitStart, current, &finish, &d))
+    if (!js_strtod(cx, digitStart.get(), current.get(), &finish, &d))
         return token(OOM);
     JS_ASSERT(current == finish);
     return numberToken(negative ? -d : d);
 }
 
 static inline bool
 IsJSONWhitespace(jschar c)
 {
@@ -377,17 +377,17 @@ JSONParser::advanceAfterObjectOpen()
         return token(ObjectClose);
     }
 
     error("expected property name or '}'");
     return token(Error);
 }
 
 static inline void
-AssertPastValue(const RangeCheckedPointer<const jschar> current)
+AssertPastValue(const RangedPtr<const jschar> current)
 {
     /*
      * We're past an arbitrary JSON value, so the previous character is
      * *somewhat* constrained, even if this assertion is pretty broad.  Don't
      * knock it till you tried it: this assertion *did* catch a bug once.
      */
     JS_ASSERT((current[-1] == 'l' &&
                current[-2] == 'l' &&
--- a/js/src/jsonparser.h
+++ b/js/src/jsonparser.h
@@ -36,36 +36,37 @@
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 #ifndef jsonparser_h___
 #define jsonparser_h___
 
+#include "mozilla/RangedPtr.h"
+
 #include "jscntxt.h"
 #include "jsstr.h"
-#include "jstl.h"
 #include "jsvalue.h"
 
 /*
  * NB: This class must only be used on the stack as it contains a js::Value.
  */
 class JSONParser
 {
   public:
     enum ErrorHandling { RaiseError, NoError };
     enum ParsingMode { StrictJSON, LegacyJSON };
 
   private:
     /* Data members */
 
     JSContext * const cx;
-    js::RangeCheckedPointer<const jschar> current;
-    const js::RangeCheckedPointer<const jschar> end;
+    mozilla::RangedPtr<const jschar> current;
+    const mozilla::RangedPtr<const jschar> end;
 
     js::Value v;
 
     const ParsingMode parsingMode;
     const ErrorHandling errorHandling;
 
     enum Token { String, Number, True, False, Null,
                  ArrayOpen, ArrayClose,
@@ -84,17 +85,17 @@ class JSONParser
      * certain legacy, non-JSON syntax if decodingMode is LegacyJSON.
      * Description of this syntax is deliberately omitted: new code should only
      * use strict JSON parsing.
      */
     JSONParser(JSContext *cx, const jschar *data, size_t length,
                ParsingMode parsingMode = StrictJSON,
                ErrorHandling errorHandling = RaiseError)
       : cx(cx),
-        current(data, data, length),
+        current(data, length),
         end(data + length, data, length),
         parsingMode(parsingMode),
         errorHandling(errorHandling)
 #ifdef DEBUG
       , lastToken(Error)
 #endif
     {
         JS_ASSERT(current <= end);
--- a/js/src/jstl.h
+++ b/js/src/jstl.h
@@ -216,29 +216,16 @@ JS_ALWAYS_INLINE size_t
 RoundUpPow2(size_t x)
 {
     size_t log2 = JS_CEILING_LOG2W(x);
     JS_ASSERT(log2 < tl::BitSize<size_t>::result);
     size_t result = size_t(1) << log2;
     return result;
 }
 
-/*
- * Safely subtract two pointers when it is known that end > begin.  This avoids
- * the common compiler bug that if (size_t(end) - size_t(begin)) has the MSB
- * set, the unsigned subtraction followed by right shift will produce -1, or
- * size_t(-1), instead of the real difference.
- */
-template <class T>
-JS_ALWAYS_INLINE size_t
-PointerRangeSize(T *begin, T *end)
-{
-    return (size_t(end) - size_t(begin)) / sizeof(T);
-}
-
 template <class T>
 class AlignedPtrAndFlag
 {
     uintptr_t bits;
 
   public:
     AlignedPtrAndFlag(T *t, bool flag) {
         JS_ASSERT((uintptr_t(t) & 1) == 0);
@@ -329,177 +316,16 @@ Max(T t1, T t2)
 /* Allows a const variable to be initialized after its declaration. */
 template <class T>
 static T&
 InitConst(const T &t)
 {
     return const_cast<T &>(t);
 }
 
-/* Smart pointer, restricted to a range defined at construction. */
-template <class T>
-class RangeCheckedPointer
-{
-    T *ptr;
-
-#ifdef DEBUG
-    T * const rangeStart;
-    T * const rangeEnd;
-#endif
-
-    void sanityChecks() {
-        JS_ASSERT(rangeStart <= ptr);
-        JS_ASSERT(ptr <= rangeEnd);
-    }
-
-    /* Creates a new pointer for |ptr|, restricted to this pointer's range. */
-    RangeCheckedPointer<T> create(T *ptr) const {
-#ifdef DEBUG
-        return RangeCheckedPointer<T>(ptr, rangeStart, rangeEnd);
-#else
-        return RangeCheckedPointer<T>(ptr, NULL, size_t(0));
-#endif
-    }
-
-  public:
-    RangeCheckedPointer(T *p, T *start, T *end)
-      : ptr(p)
-#ifdef DEBUG
-      , rangeStart(start), rangeEnd(end)
-#endif
-    {
-        JS_ASSERT(rangeStart <= rangeEnd);
-        sanityChecks();
-    }
-    RangeCheckedPointer(T *p, T *start, size_t length)
-      : ptr(p)
-#ifdef DEBUG
-      , rangeStart(start), rangeEnd(start + length)
-#endif
-    {
-        JS_ASSERT(length <= size_t(-1) / sizeof(T));
-        JS_ASSERT(uintptr_t(rangeStart) + length * sizeof(T) >= uintptr_t(rangeStart));
-        sanityChecks();
-    }
-
-    RangeCheckedPointer<T> &operator=(const RangeCheckedPointer<T> &other) {
-        JS_ASSERT(rangeStart == other.rangeStart);
-        JS_ASSERT(rangeEnd == other.rangeEnd);
-        ptr = other.ptr;
-        sanityChecks();
-        return *this;
-    }
-
-    RangeCheckedPointer<T> operator+(size_t inc) {
-        JS_ASSERT(inc <= size_t(-1) / sizeof(T));
-        JS_ASSERT(ptr + inc > ptr);
-        return create(ptr + inc);
-    }
-
-    RangeCheckedPointer<T> operator-(size_t dec) {
-        JS_ASSERT(dec <= size_t(-1) / sizeof(T));
-        JS_ASSERT(ptr - dec < ptr);
-        return create(ptr - dec);
-    }
-
-    template <class U>
-    RangeCheckedPointer<T> &operator=(U *p) {
-        *this = create(p);
-        return *this;
-    }
-
-    template <class U>
-    RangeCheckedPointer<T> &operator=(const RangeCheckedPointer<U> &p) {
-        JS_ASSERT(rangeStart <= p.ptr);
-        JS_ASSERT(p.ptr <= rangeEnd);
-        ptr = p.ptr;
-        sanityChecks();
-        return *this;
-    }
-
-    RangeCheckedPointer<T> &operator++() {
-        return (*this += 1);
-    }
-
-    RangeCheckedPointer<T> operator++(int) {
-        RangeCheckedPointer<T> rcp = *this;
-        ++*this;
-        return rcp;
-    }
-
-    RangeCheckedPointer<T> &operator--() {
-        return (*this -= 1);
-    }
-
-    RangeCheckedPointer<T> operator--(int) {
-        RangeCheckedPointer<T> rcp = *this;
-        --*this;
-        return rcp;
-    }
-
-    RangeCheckedPointer<T> &operator+=(size_t inc) {
-        this->operator=<T>(*this + inc);
-        return *this;
-    }
-
-    RangeCheckedPointer<T> &operator-=(size_t dec) {
-        this->operator=<T>(*this - dec);
-        return *this;
-    }
-
-    T &operator[](int index) const {
-        JS_ASSERT(size_t(index > 0 ? index : -index) <= size_t(-1) / sizeof(T));
-        return *create(ptr + index);
-    }
-
-    T &operator*() const {
-        return *ptr;
-    }
-
-    operator T*() const {
-        return ptr;
-    }
-
-    template <class U>
-    bool operator==(const RangeCheckedPointer<U> &other) const {
-        return ptr == other.ptr;
-    }
-    template <class U>
-    bool operator!=(const RangeCheckedPointer<U> &other) const {
-        return !(*this == other);
-    }
-
-    template <class U>
-    bool operator<(const RangeCheckedPointer<U> &other) const {
-        return ptr < other.ptr;
-    }
-    template <class U>
-    bool operator<=(const RangeCheckedPointer<U> &other) const {
-        return ptr <= other.ptr;
-    }
-
-    template <class U>
-    bool operator>(const RangeCheckedPointer<U> &other) const {
-        return ptr > other.ptr;
-    }
-    template <class U>
-    bool operator>=(const RangeCheckedPointer<U> &other) const {
-        return ptr >= other.ptr;
-    }
-
-    size_t operator-(const RangeCheckedPointer<T> &other) const {
-        JS_ASSERT(ptr >= other.ptr);
-        return PointerRangeSize(other.ptr, ptr);
-    }
-
-  private:
-    RangeCheckedPointer();
-    T *operator&();
-};
-
 template <class T, class U>
 JS_ALWAYS_INLINE T &
 ImplicitCast(U &u)
 {
     T &t = u;
     return t;
 }
 
new file mode 100644
--- /dev/null
+++ b/mfbt/RangedPtr.h
@@ -0,0 +1,269 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sw=4 et tw=99 ft=cpp:
+ *
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at:
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Code.
+ *
+ * The Initial Developer of the Original Code is
+ *   The Mozilla Foundation
+ * Portions created by the Initial Developer are Copyright (C) 2011
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Jeff Walden <jwalden+code@mit.edu> (original author)
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#ifndef mozilla_RangedPtr_h_
+#define mozilla_RangedPtr_h_
+
+#include "mozilla/Util.h"
+
+#ifdef __cplusplus
+
+namespace mozilla {
+
+/*
+ * RangedPtr is a smart pointer restricted to an address range specified at
+ * creation.  The pointer (and any smart pointers derived from it) must remain
+ * within the range [start, end] (inclusive of end to facilitate use as
+ * sentinels).  Dereferencing or indexing into the pointer (or pointers derived
+ * from it) must remain within the range [start, end).  All the standard pointer
+ * operators are defined on it; in debug builds these operations assert that the
+ * range specified at construction is respected.
+ *
+ * In theory passing a smart pointer instance as an argument can be slightly
+ * slower than passing a T* (due to ABI requirements for passing structs versus
+ * passing pointers), if the method being called isn't inlined.  If you are in
+ * extremely performance-critical code, you may want to be careful using this
+ * smart pointer as an argument type.
+ *
+ * RangedPtr<T> intentionally does not implicitly convert to T*.  Use get() to
+ * explicitly convert to T*.  Keep in mind that the raw pointer of course won't
+ * implement bounds checking in debug builds.
+ */
+template <typename T>
+class RangedPtr
+{
+    T* ptr;
+
+#ifdef DEBUG
+    T* const rangeStart;
+    T* const rangeEnd;
+#endif
+
+    void checkSanity() {
+        MOZ_ASSERT(rangeStart <= ptr);
+        MOZ_ASSERT(ptr <= rangeEnd);
+    }
+
+    /* Creates a new pointer for |ptr|, restricted to this pointer's range. */
+    RangedPtr<T> create(T *ptr) const {
+#ifdef DEBUG
+        return RangedPtr<T>(ptr, rangeStart, rangeEnd);
+#else
+        return RangedPtr<T>(ptr, NULL, size_t(0));
+#endif
+    }
+
+  public:
+    RangedPtr(T* p, T* start, T* end)
+      : ptr(p)
+#ifdef DEBUG
+      , rangeStart(start), rangeEnd(end)
+#endif
+    {
+        MOZ_ASSERT(rangeStart <= rangeEnd);
+        checkSanity();
+    }
+    RangedPtr(T* p, T* start, size_t length)
+      : ptr(p)
+#ifdef DEBUG
+      , rangeStart(start), rangeEnd(start + length)
+#endif
+    {
+        MOZ_ASSERT(length <= size_t(-1) / sizeof(T));
+        MOZ_ASSERT(uintptr_t(rangeStart) + length * sizeof(T) >= uintptr_t(rangeStart));
+        checkSanity();
+    }
+
+    /* Equivalent to RangedPtr(p, p, length). */
+    RangedPtr(T* p, size_t length)
+      : ptr(p)
+#ifdef DEBUG
+      , rangeStart(p), rangeEnd(p + length)
+#endif
+    {
+        MOZ_ASSERT(length <= size_t(-1) / sizeof(T));
+        MOZ_ASSERT(uintptr_t(rangeStart) + length * sizeof(T) >= uintptr_t(rangeStart));
+        checkSanity();
+    }
+
+    T* get() const {
+        return ptr;
+    }
+
+    /*
+     * You can only assign one RangedPtr into another if the two pointers have
+     * the same valid range:
+     *
+     *   char arr1[] = "hi";
+     *   char arr2[] = "bye";
+     *   RangedPtr<char> p1(arr1, 2);
+     *   p1 = RangedPtr<char>(arr1 + 1, arr1, arr1 + 2); // works
+     *   p1 = RangedPtr<char>(arr2, 3);                  // asserts
+     */
+    RangedPtr<T>& operator=(const RangedPtr<T>& other) {
+        MOZ_ASSERT(rangeStart == other.rangeStart);
+        MOZ_ASSERT(rangeEnd == other.rangeEnd);
+        ptr = other.ptr;
+        checkSanity();
+        return *this;
+    }
+
+    RangedPtr<T> operator+(size_t inc) {
+        MOZ_ASSERT(inc <= size_t(-1) / sizeof(T));
+        MOZ_ASSERT(ptr + inc > ptr);
+        return create(ptr + inc);
+    }
+
+    RangedPtr<T> operator-(size_t dec) {
+        MOZ_ASSERT(dec <= size_t(-1) / sizeof(T));
+        MOZ_ASSERT(ptr - dec < ptr);
+        return create(ptr - dec);
+    }
+
+    /*
+     * You can assign a raw pointer into a RangedPtr if the raw pointer is
+     * within the range specified at creation.
+     */
+    template <typename U>
+    RangedPtr<T>& operator=(U* p) {
+        *this = create(p);
+        return *this;
+    }
+
+    template <typename U>
+    RangedPtr<T>& operator=(const RangedPtr<U>& p) {
+        MOZ_ASSERT(rangeStart <= p.ptr);
+        MOZ_ASSERT(p.ptr <= rangeEnd);
+        ptr = p.ptr;
+        checkSanity();
+        return *this;
+    }
+
+    RangedPtr<T>& operator++() {
+        return (*this += 1);
+    }
+
+    RangedPtr<T> operator++(int) {
+        RangedPtr<T> rcp = *this;
+        ++*this;
+        return rcp;
+    }
+
+    RangedPtr<T>& operator--() {
+        return (*this -= 1);
+    }
+
+    RangedPtr<T> operator--(int) {
+        RangedPtr<T> rcp = *this;
+        --*this;
+        return rcp;
+    }
+
+    RangedPtr<T>& operator+=(size_t inc) {
+        this->operator=<T>(*this + inc);
+        return *this;
+    }
+
+    RangedPtr<T>& operator-=(size_t dec) {
+        this->operator=<T>(*this - dec);
+        return *this;
+    }
+
+    T& operator[](int index) const {
+        MOZ_ASSERT(size_t(index > 0 ? index : -index) <= size_t(-1) / sizeof(T));
+        return *create(ptr + index);
+    }
+
+    T& operator*() const {
+        return *ptr;
+    }
+
+    template <typename U>
+    bool operator==(const RangedPtr<U>& other) const {
+        return ptr == other.ptr;
+    }
+    template <typename U>
+    bool operator!=(const RangedPtr<U>& other) const {
+        return !(*this == other);
+    }
+
+    template<typename U>
+    bool operator==(const U* u) const {
+        return ptr == u;
+    }
+    template<typename U>
+    bool operator!=(const U* u) const {
+        return !(*this == u);
+    }
+
+    template <typename U>
+    bool operator<(const RangedPtr<U>& other) const {
+        return ptr < other.ptr;
+    }
+    template <typename U>
+    bool operator<=(const RangedPtr<U>& other) const {
+        return ptr <= other.ptr;
+    }
+
+    template <typename U>
+    bool operator>(const RangedPtr<U>& other) const {
+        return ptr > other.ptr;
+    }
+    template <typename U>
+    bool operator>=(const RangedPtr<U>& other) const {
+        return ptr >= other.ptr;
+    }
+
+    size_t operator-(const RangedPtr<T>& other) const {
+        MOZ_ASSERT(ptr >= other.ptr);
+        return PointerRangeSize(other.ptr, ptr);
+    }
+
+  private:
+    RangedPtr();
+    T* operator&();
+    operator T*() const;
+};
+
+} /* namespace mozilla */
+
+#endif /* __cplusplus */
+
+#endif  /* mozilla_RangedPtr_h_ */
--- a/mfbt/Types.h
+++ b/mfbt/Types.h
@@ -13,17 +13,17 @@
  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
  * for the specific language governing rights and limitations under the
  * License.
  *
  * The Original Code is Mozilla Code.
  *
  * The Initial Developer of the Original Code is
  *   The Mozilla Foundation
- * Portions created by the Initial Developer are Copyrigght (C) 2011
+ * Portions created by the Initial Developer are Copyright (C) 2011
  * the Initial Developer. All Rights Reserved.
  *
  * Contributor(s):
  *
  * Alternatively, the contents of this file may be used under the terms of
  * either the GNU General Public License Version 2 or later (the "GPL"), or
  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
  * in which case the provisions of the GPL or the LGPL are applicable instead
--- a/mfbt/Util.h
+++ b/mfbt/Util.h
@@ -13,17 +13,17 @@
  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
  * for the specific language governing rights and limitations under the
  * License.
  *
  * The Original Code is Mozilla Code.
  *
  * The Initial Developer of the Original Code is
  *   The Mozilla Foundation
- * Portions created by the Initial Developer are Copyrigght (C) 2011
+ * Portions created by the Initial Developer are Copyright (C) 2011
  * the Initial Developer. All Rights Reserved.
  *
  * Contributor(s):
  *
  * Alternatively, the contents of this file may be used under the terms of
  * either the GNU General Public License Version 2 or later (the "GPL"), or
  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
  * in which case the provisions of the GPL or the LGPL are applicable instead
@@ -74,16 +74,69 @@ MOZ_END_EXTERN_C
     ((expr_) ? (void)0 : JS_Assert(#expr_, __FILE__, __LINE__))
 
 #else
 
 # define MOZ_ASSERT(expr_) ((void)0)
 
 #endif  /* DEBUG */
 
+/*
+ * MOZ_INLINE is a macro which expands to tell the compiler that the method
+ * decorated with it should be inlined.  This macro is usable from C and C++
+ * code, even though C89 does not support the |inline| keyword.  The compiler
+ * may ignore this directive if it chooses.
+ */
+#ifndef MOZ_INLINE
+# if defined __cplusplus
+#  define MOZ_INLINE          inline
+# elif defined _MSC_VER
+#  define MOZ_INLINE          __inline
+# elif defined __GNUC__
+#  define MOZ_INLINE          __inline__
+# else
+#  define MOZ_INLINE          inline
+# endif
+#endif
+
+/*
+ * MOZ_ALWAYS_INLINE is a macro which expands to tell the compiler that the
+ * method decorated with it must be inlined, even if the compiler thinks
+ * otherwise.  This is only a (much) stronger version of the MOZ_INLINE hint:
+ * compilers are not guaranteed to respect it (although they're much more likely
+ * to do so).
+ */
+#ifndef MOZ_ALWAYS_INLINE
+# if defined DEBUG
+#  define MOZ_ALWAYS_INLINE   MOZ_INLINE
+# elif defined _MSC_VER
+#  define MOZ_ALWAYS_INLINE   __forceinline
+# elif defined __GNUC__
+#  define MOZ_ALWAYS_INLINE   __attribute__((always_inline)) MOZ_INLINE
+# else
+#  define MOZ_ALWAYS_INLINE   MOZ_INLINE
+# endif
+#endif
+
+/*
+ * MOZ_NEVER_INLINE is a macro which expands to tell the compiler that the
+ * method decorated with it must never be inlined, even if the compiler would
+ * otherwise choose to inline the method.  Compilers aren't absolutely
+ * guaranteed to support this, but most do.
+ */
+#ifndef MOZ_NEVER_INLINE
+# if defined _MSC_VER
+#  define MOZ_NEVER_INLINE __declspec(noinline)
+# elif defined __GNUC__
+#  define MOZ_NEVER_INLINE __attribute__((noinline))
+# else
+#  define MOZ_NEVER_INLINE
+# endif
+#endif
+
 #ifdef __cplusplus
 
 namespace mozilla {
 
 /**
  * DebugOnly contains a value of type T, but only in debug builds.  In
  * release builds, it does not contain a value.  This helper is
  * intended to be used along with ASSERT()-style macros, allowing one
@@ -245,13 +298,27 @@ class Maybe
     }
 
     void destroyIfConstructed() {
         if (!empty())
             destroy();
     }
 };
 
+/*
+ * Safely subtract two pointers when it is known that end >= begin.  This avoids
+ * the common compiler bug that if (size_t(end) - size_t(begin)) has the MSB
+ * set, the unsigned subtraction followed by right shift will produce -1, or
+ * size_t(-1), instead of the real difference.
+ */
+template <class T>
+MOZ_ALWAYS_INLINE size_t
+PointerRangeSize(T* begin, T* end)
+{
+    MOZ_ASSERT(end >= begin);
+    return (size_t(end) - size_t(begin)) / sizeof(T);
+}
+
 } /* namespace mozilla */
 
 #endif /* __cplusplus */
 
 #endif  /* mozilla_Util_h_ */