Bug 891177 - Implement Move.h to define a move-construction interface. r=terrence
authorJeff Walden <jwalden@mit.edu>
Tue, 02 Jul 2013 17:25:13 -0700
changeset 138047 2e8e8ebef9285fc9d18186b11666f19f546fc6df
parent 138046 272dce99bdd9943c8b1bf22c844e951c34d95935
child 138048 8a88e4fd3a398797d43b8f8563ba08dd3f220bda
push id24941
push useremorley@mozilla.com
push dateThu, 11 Jul 2013 09:11:18 +0000
treeherderautoland@c89e5b9fe935 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersterrence
bugs891177
milestone25.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 891177 - Implement Move.h to define a move-construction interface. r=terrence
js/public/HashTable.h
js/public/Utility.h
js/public/Vector.h
js/src/builtin/MapObject.cpp
js/src/ion/AsmJS.cpp
js/src/ion/AsmJSModule.h
js/src/shell/jsheaptools.cpp
mfbt/Move.h
mfbt/exported_headers.mk
--- a/js/public/HashTable.h
+++ b/js/public/HashTable.h
@@ -7,16 +7,17 @@
 #ifndef js_HashTable_h
 #define js_HashTable_h
 
 #include "mozilla/Assertions.h"
 #include "mozilla/Attributes.h"
 #include "mozilla/Casting.h"
 #include "mozilla/DebugOnly.h"
 #include "mozilla/MemoryReporting.h"
+#include "mozilla/Move.h"
 #include "mozilla/PodOperations.h"
 #include "mozilla/TypeTraits.h"
 #include "mozilla/Util.h"
 
 #include "js/TemplateLib.h"
 #include "js/Utility.h"
 
 namespace js {
@@ -131,28 +132,28 @@ class HashMap
     typedef typename Impl::AddPtr AddPtr;
     AddPtr lookupForAdd(const Lookup &l) const {
         return impl.lookupForAdd(l);
     }
 
     template<typename KeyInput, typename ValueInput>
     bool add(AddPtr &p, const KeyInput &k, const ValueInput &v) {
         Entry e(k, v);
-        return impl.add(p, Move(e));
+        return impl.add(p, mozilla::Move(e));
     }
 
     bool add(AddPtr &p, const Key &k) {
         Entry e(k, Value());
-        return impl.add(p, Move(e));
+        return impl.add(p, mozilla::Move(e));
     }
 
     template<typename KeyInput, typename ValueInput>
     bool relookupOrAdd(AddPtr &p, const KeyInput &k, const ValueInput &v) {
         Entry e(k, v);
-        return impl.relookupOrAdd(p, k, Move(e));
+        return impl.relookupOrAdd(p, k, mozilla::Move(e));
     }
 
     // |all()| returns a Range containing |count()| elements. E.g.:
     //
     //   typedef HashMap<int,char> HM;
     //   HM h;
     //   for (HM::Range r = h.all(); !r.empty(); r.popFront())
     //     char c = r.front().value;
@@ -224,17 +225,17 @@ class HashMap
         }
         return add(p, k, v);
     }
 
     // Like put, but assert that the given key is not already present.
     template<typename KeyInput, typename ValueInput>
     bool putNew(const KeyInput &k, const ValueInput &v) {
         Entry e(k, v);
-        return impl.putNew(k, Move(e));
+        return impl.putNew(k, mozilla::Move(e));
     }
 
     // Add (k,defaultValue) if |k| is not found. Return a false-y Ptr on oom.
     Ptr lookupWithDefault(const Key &k, const Value &defaultValue) {
         AddPtr p = lookupForAdd(k);
         if (p)
             return p;
         (void)add(p, k, defaultValue);  // p is left false-y on oom.
@@ -251,18 +252,18 @@ class HashMap
     void rekey(const Lookup &old_key, const Key &new_key) {
         if (old_key != new_key) {
             if (Ptr p = lookup(old_key))
                 impl.rekey(p, new_key, new_key);
         }
     }
 
     // HashMap is movable
-    HashMap(MoveRef<HashMap> rhs) : impl(Move(rhs->impl)) {}
-    void operator=(MoveRef<HashMap> rhs) { impl = Move(rhs->impl); }
+    HashMap(mozilla::MoveRef<HashMap> rhs) : impl(mozilla::Move(rhs->impl)) {}
+    void operator=(mozilla::MoveRef<HashMap> rhs) { impl = mozilla::Move(rhs->impl); }
 
   private:
     // HashMap is not copyable or assignable
     HashMap(const HashMap &hm) MOZ_DELETE;
     HashMap &operator=(const HashMap &hm) MOZ_DELETE;
 
     friend class Impl::Enum;
 };
@@ -450,18 +451,18 @@ class HashSet
     void rekey(const Lookup &old_key, const T &new_key) {
         if (old_key != new_key) {
             if (Ptr p = lookup(old_key))
                 impl.rekey(p, new_key, new_key);
         }
     }
 
     // HashSet is movable
-    HashSet(MoveRef<HashSet> rhs) : impl(Move(rhs->impl)) {}
-    void operator=(MoveRef<HashSet> rhs) { impl = Move(rhs->impl); }
+    HashSet(mozilla::MoveRef<HashSet> rhs) : impl(mozilla::Move(rhs->impl)) {}
+    void operator=(mozilla::MoveRef<HashSet> rhs) { impl = mozilla::Move(rhs->impl); }
 
   private:
     // HashSet is not copyable or assignable
     HashSet(const HashSet &hs) MOZ_DELETE;
     HashSet &operator=(const HashSet &hs) MOZ_DELETE;
 
     friend class Impl::Enum;
 };
@@ -571,18 +572,18 @@ class HashMapEntry
 
     HashMapEntry(const HashMapEntry &) MOZ_DELETE;
     void operator=(const HashMapEntry &) MOZ_DELETE;
 
   public:
     template<typename KeyInput, typename ValueInput>
     HashMapEntry(const KeyInput &k, const ValueInput &v) : key(k), value(v) {}
 
-    HashMapEntry(MoveRef<HashMapEntry> rhs)
-      : key(Move(rhs->key)), value(Move(rhs->value)) { }
+    HashMapEntry(mozilla::MoveRef<HashMapEntry> rhs)
+      : key(mozilla::Move(rhs->key)), value(mozilla::Move(rhs->value)) { }
 
     typedef Key KeyType;
     typedef Value ValueType;
 
     const Key key;
     Value value;
 };
 
@@ -823,23 +824,23 @@ class HashTable : private AllocPolicy
             }
 
             if (removed)
                 table.compactIfUnderloaded();
         }
     };
 
     // HashTable is movable
-    HashTable(MoveRef<HashTable> rhs)
+    HashTable(mozilla::MoveRef<HashTable> rhs)
       : AllocPolicy(*rhs)
     {
         mozilla::PodAssign(this, &*rhs);
         rhs->table = NULL;
     }
-    void operator=(MoveRef<HashTable> rhs) {
+    void operator=(mozilla::MoveRef<HashTable> rhs) {
         if (table)
             destroyTable(*this, table, capacity());
         mozilla::PodAssign(this, &*rhs);
         rhs->table = NULL;
     }
 
   private:
     // HashTable is not copyable or assignable
@@ -1156,17 +1157,17 @@ class HashTable : private AllocPolicy
         removedCount = 0;
         gen++;
         table = newTable;
 
         // Copy only live entries, leaving removed ones behind.
         for (Entry *src = oldTable, *end = src + oldCap; src < end; ++src) {
             if (src->isLive()) {
                 HashNumber hn = src->getKeyHash();
-                findFreeEntry(hn).setLive(hn, Move(src->get()));
+                findFreeEntry(hn).setLive(hn, mozilla::Move(src->get()));
                 src->destroy();
             }
         }
 
         // All entries have been destroyed, no need to destroyTable.
         this->free_(oldTable);
         return Rehashed;
     }
@@ -1454,20 +1455,20 @@ class HashTable : private AllocPolicy
         checkUnderloaded();
     }
 
     void rekey(Ptr p, const Lookup &l, const Key &k)
     {
         JS_ASSERT(table);
         ReentrancyGuard g(*this);
         JS_ASSERT(p.found());
-        typename HashTableEntry<T>::NonConstT t(Move(*p));
+        typename HashTableEntry<T>::NonConstT t(mozilla::Move(*p));
         HashPolicy::setKey(t, const_cast<Key &>(k));
         remove(*p.entry_);
-        putNewInfallible(l, Move(t));
+        putNewInfallible(l, mozilla::Move(t));
     }
 
 #undef METER
 };
 
 }  // namespace detail
 }  // namespace js
 
--- a/js/public/Utility.h
+++ b/js/public/Utility.h
@@ -5,16 +5,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef js_Utility_h
 #define js_Utility_h
 
 #include "mozilla/Assertions.h"
 #include "mozilla/Attributes.h"
 #include "mozilla/Compiler.h"
+#include "mozilla/Move.h"
 #include "mozilla/Scoped.h"
 
 #include <stdlib.h>
 #include <string.h>
 
 #ifdef JS_OOM_DO_BACKTRACES
 #include <stdio.h>
 #include <execinfo.h>
@@ -558,134 +559,16 @@ struct ScopedReleasePtrTraits : public S
     static void release(T *ptr) { if (ptr) ptr->release(); }
 };
 SCOPED_TEMPLATE(ScopedReleasePtr, ScopedReleasePtrTraits)
 
 } /* namespace js */
 
 namespace js {
 
-/*
- * "Move" References
- *
- * Some types can be copied much more efficiently if we know the original's
- * value need not be preserved --- that is, if we are doing a "move", not a
- * "copy". For example, if we have:
- *
- *   Vector<T> u;
- *   Vector<T> v(u);
- *
- * the constructor for v must apply a copy constructor to each element of u ---
- * taking time linear in the length of u. However, if we know we will not need u
- * any more once v has been initialized, then we could initialize v very
- * efficiently simply by stealing u's dynamically allocated buffer and giving it
- * to v --- a constant-time operation, regardless of the size of u.
- *
- * Moves often appear in container implementations. For example, when we append
- * to a vector, we may need to resize its buffer. This entails moving each of
- * its extant elements from the old, smaller buffer to the new, larger buffer.
- * But once the elements have been migrated, we're just going to throw away the
- * old buffer; we don't care if they still have their values. So if the vector's
- * element type can implement "move" more efficiently than "copy", the vector
- * resizing should by all means use a "move" operation. Hash tables also need to
- * be resized.
- *
- * The details of the optimization, and whether it's worth applying, vary from
- * one type to the next. And while some constructor calls are moves, many really
- * are copies, and can't be optimized this way. So we need:
- *
- * 1) a way for a particular invocation of a copy constructor to say that it's
- *    really a move, and that the value of the original isn't important
- *    afterwards (althought it must still be safe to destroy); and
- *
- * 2) a way for a type (like Vector) to announce that it can be moved more
- *    efficiently than it can be copied, and provide an implementation of that
- *    move operation.
- *
- * The Move(T &) function takes a reference to a T, and returns an MoveRef<T>
- * referring to the same value; that's 1). An MoveRef<T> is simply a reference
- * to a T, annotated to say that a copy constructor applied to it may move that
- * T, instead of copying it. Finally, a constructor that accepts an MoveRef<T>
- * should perform a more efficient move, instead of a copy, providing 2).
- *
- * So, where we might define a copy constructor for a class C like this:
- *
- *   C(const C &rhs) { ... copy rhs to this ... }
- *
- * we would declare a move constructor like this:
- *
- *   C(MoveRef<C> rhs) { ... move rhs to this ... }
- *
- * And where we might perform a copy like this:
- *
- *   C c2(c1);
- *
- * we would perform a move like this:
- *
- *   C c2(Move(c1))
- *
- * Note that MoveRef<T> implicitly converts to T &, so you can pass an
- * MoveRef<T> to an ordinary copy constructor for a type that doesn't support a
- * special move constructor, and you'll just get a copy. This means that
- * templates can use Move whenever they know they won't use the original value
- * any more, even if they're not sure whether the type at hand has a specialized
- * move constructor. If it doesn't, the MoveRef<T> will just convert to a T &,
- * and the ordinary copy constructor will apply.
- *
- * A class with a move constructor can also provide a move assignment operator,
- * which runs this's destructor, and then applies the move constructor to
- * *this's memory. A typical definition:
- *
- *   C &operator=(MoveRef<C> rhs) {
- *     this->~C();
- *     new(this) C(rhs);
- *     return *this;
- *   }
- *
- * With that in place, one can write move assignments like this:
- *
- *   c2 = Move(c1);
- *
- * This destroys c1, moves c1's value to c2, and leaves c1 in an undefined but
- * destructible state.
- *
- * This header file defines MoveRef and Move in the js namespace. It's up to
- * individual containers to annotate moves as such, by calling Move; and it's up
- * to individual types to define move constructors.
- *
- * One hint: if you're writing a move constructor where the type has members
- * that should be moved themselves, it's much nicer to write this:
- *
- *   C(MoveRef<C> c) : x(c->x), y(c->y) { }
- *
- * than the equivalent:
- *
- *   C(MoveRef<C> c) { new(&x) X(c->x); new(&y) Y(c->y); }
- *
- * especially since GNU C++ fails to notice that this does indeed initialize x
- * and y, which may matter if they're const.
- */
-template<typename T>
-class MoveRef {
-  public:
-    typedef T Referent;
-    explicit MoveRef(T &t) : pointer(&t) { }
-    T &operator*()  const { return *pointer; }
-    T *operator->() const { return  pointer; }
-    operator T& ()   const { return *pointer; }
-  private:
-    T *pointer;
-};
-
-template<typename T>
-MoveRef<T> Move(T &t) { return MoveRef<T>(t); }
-
-template<typename T>
-MoveRef<T> Move(const T &t) { return MoveRef<T>(const_cast<T &>(t)); }
-
 /* Useful for implementing containers that assert non-reentrancy */
 class ReentrancyGuard
 {
     /* ReentrancyGuard is not copyable. */
     ReentrancyGuard(const ReentrancyGuard &);
     void operator=(const ReentrancyGuard &);
 
 #ifdef DEBUG
@@ -712,19 +595,19 @@ class ReentrancyGuard
 #endif
     }
 };
 
 template <class T>
 JS_ALWAYS_INLINE static void
 Swap(T &t, T &u)
 {
-    T tmp(Move(t));
-    t = Move(u);
-    u = Move(tmp);
+    T tmp(mozilla::Move(t));
+    t = mozilla::Move(u);
+    u = mozilla::Move(tmp);
 }
 
 /*
  * Round x up to the nearest power of 2.  This function assumes that the most
  * significant bit of x is not set, which would lead to overflow.
  */
 JS_ALWAYS_INLINE size_t
 RoundUpPow2(size_t x)
--- a/js/public/Vector.h
+++ b/js/public/Vector.h
@@ -4,16 +4,17 @@
  * 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 js_Vector_h
 #define js_Vector_h
 
 #include "mozilla/Attributes.h"
 #include "mozilla/MemoryReporting.h"
+#include "mozilla/Move.h"
 #include "mozilla/TypeTraits.h"
 
 #include "js/TemplateLib.h"
 #include "js/Utility.h"
 
 /* Silence dire "bugs in previous versions of MSVC have been fixed" warnings */
 #ifdef _MSC_VER
 #pragma warning(push)
@@ -73,17 +74,17 @@ struct VectorImpl
 
     /*
      * Move-constructs objects in the uninitialized range
      * [dst, dst+(srcend-srcbeg)) from the range [srcbeg, srcend).
      */
     template <class U>
     static inline void moveConstruct(T *dst, const U *srcbeg, const U *srcend) {
         for (const U *p = srcbeg; p != srcend; ++p, ++dst)
-            new(dst) T(Move(*p));
+            new(dst) T(mozilla::Move(*p));
     }
 
     /*
      * Copy-constructs objects in the uninitialized range [dst, dst+n) from the
      * same object u.
      */
     template <class U>
     static inline void copyConstructN(T *dst, size_t n, const U &u) {
@@ -99,17 +100,17 @@ struct VectorImpl
      */
     static inline bool growTo(Vector<T,N,AP> &v, size_t newCap) {
         JS_ASSERT(!v.usingInlineStorage());
         JS_ASSERT(!CapacityHasExcessSpace<T>(newCap));
         T *newbuf = reinterpret_cast<T *>(v.malloc_(newCap * sizeof(T)));
         if (!newbuf)
             return false;
         for (T *dst = newbuf, *src = v.beginNoCheck(); src != v.endNoCheck(); ++dst, ++src)
-            new(dst) T(Move(*src));
+            new(dst) T(mozilla::Move(*src));
         VectorImpl::destroy(v.beginNoCheck(), v.endNoCheck());
         v.free_(v.mBegin);
         v.mBegin = newbuf;
         /* v.mLength is unchanged. */
         v.mCapacity = newCap;
         return true;
     }
 };
@@ -303,18 +304,18 @@ class Vector : private AllocPolicy
     template <class U, size_t O, class BP> void internalAppend(const Vector<U,O,BP> &other);
 
   public:
     static const size_t sMaxInlineStorage = N;
 
     typedef T ElementType;
 
     Vector(AllocPolicy = AllocPolicy());
-    Vector(MoveRef<Vector>); /* Move constructor. */
-    Vector &operator=(MoveRef<Vector>); /* Move assignment. */
+    Vector(mozilla::MoveRef<Vector>); /* Move constructor. */
+    Vector &operator=(mozilla::MoveRef<Vector>); /* Move assignment. */
     ~Vector();
 
     /* accessors */
 
     const AllocPolicy &allocPolicy() const {
         return *this;
     }
 
@@ -534,17 +535,17 @@ Vector<T,N,AllocPolicy>::Vector(AllocPol
 #ifdef DEBUG
   , mReserved(sInlineCapacity), entered(false)
 #endif
 {}
 
 /* Move constructor. */
 template <class T, size_t N, class AllocPolicy>
 JS_ALWAYS_INLINE
-Vector<T, N, AllocPolicy>::Vector(MoveRef<Vector> rhs)
+Vector<T, N, AllocPolicy>::Vector(mozilla::MoveRef<Vector> rhs)
     : AllocPolicy(rhs)
 #ifdef DEBUG
     , entered(false)
 #endif
 {
     mLength = rhs->mLength;
     mCapacity = rhs->mCapacity;
 #ifdef DEBUG
@@ -573,17 +574,17 @@ Vector<T, N, AllocPolicy>::Vector(MoveRe
 #endif
     }
 }
 
 /* Move assignment. */
 template <class T, size_t N, class AP>
 JS_ALWAYS_INLINE
 Vector<T, N, AP> &
-Vector<T, N, AP>::operator=(MoveRef<Vector> rhs)
+Vector<T, N, AP>::operator=(mozilla::MoveRef<Vector> rhs)
 {
     this->~Vector();
     new(this) Vector(rhs);
     return *this;
 }
 
 template <class T, size_t N, class AP>
 JS_ALWAYS_INLINE
--- a/js/src/builtin/MapObject.cpp
+++ b/js/src/builtin/MapObject.cpp
@@ -1,16 +1,18 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
  * vim: set ts=8 sts=4 et sw=4 tw=99:
  * 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 "builtin/MapObject.h"
 
+#include "mozilla/Move.h"
+
 #include "jscntxt.h"
 #include "jsiter.h"
 #include "jsobj.h"
 
 #include "gc/Marking.h"
 #include "js/Utility.h"
 #include "vm/GlobalObject.h"
 #include "vm/Interpreter.h"
@@ -18,16 +20,18 @@
 #include "jsobjinlines.h"
 
 #include "gc/Barrier-inl.h"
 
 using namespace js;
 
 using mozilla::DoubleIsInt32;
 using mozilla::IsNaN;
+using mozilla::Move;
+using mozilla::MoveRef;
 
 
 /*** OrderedHashTable ****************************************************************************/
 
 /*
  * Define two collection templates, js::OrderedHashMap and js::OrderedHashSet.
  * They are like js::HashMap and js::HashSet except that:
  *
--- a/js/src/ion/AsmJS.cpp
+++ b/js/src/ion/AsmJS.cpp
@@ -1,14 +1,16 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
  * vim: set ts=8 sts=4 et sw=4 tw=99:
  * 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 "mozilla/Move.h"
+
 #include "jsmath.h"
 #include "jsworkers.h"
 #include "prmjtime.h"
 
 #include "frontend/ParseNode.h"
 #include "ion/AsmJS.h"
 #include "ion/AsmJSModule.h"
 #include "ion/PerfSpewer.h"
--- a/js/src/ion/AsmJSModule.h
+++ b/js/src/ion/AsmJSModule.h
@@ -215,17 +215,17 @@ class AsmJSModule
             unsigned codeOffset_;
             CodePtr code_;
         } u;
 
         friend class AsmJSModule;
 
         ExportedFunction(JSFunction *fun,
                          PropertyName *maybeFieldName,
-                         MoveRef<ArgCoercionVector> argCoercions,
+                         mozilla::MoveRef<ArgCoercionVector> argCoercions,
                          ReturnType returnType)
           : fun_(fun),
             maybeFieldName_(maybeFieldName),
             argCoercions_(argCoercions),
             returnType_(returnType),
             hasCodePtr_(false)
         {
             u.codeOffset_ = 0;
@@ -233,20 +233,20 @@ class AsmJSModule
 
         void trace(JSTracer *trc) {
             MarkObject(trc, &fun_, "asm.js export name");
             if (maybeFieldName_)
                 MarkString(trc, &maybeFieldName_, "asm.js export field");
         }
 
       public:
-        ExportedFunction(MoveRef<ExportedFunction> rhs)
+        ExportedFunction(mozilla::MoveRef<ExportedFunction> rhs)
           : fun_(rhs->fun_),
             maybeFieldName_(rhs->maybeFieldName_),
-            argCoercions_(Move(rhs->argCoercions_)),
+            argCoercions_(mozilla::Move(rhs->argCoercions_)),
             returnType_(rhs->returnType_),
             hasCodePtr_(rhs->hasCodePtr_),
             u(rhs->u)
         {}
 
         void initCodeOffset(unsigned off) {
             JS_ASSERT(!hasCodePtr_);
             JS_ASSERT(!u.codeOffset_);
@@ -496,20 +496,21 @@ class AsmJSModule
         *exitIndex = unsigned(exits_.length());
         return exits_.append(Exit(ffiIndex));
     }
     bool addFunctionCounts(ion::IonScriptCounts *counts) {
         return functionCounts_.append(counts);
     }
 
     bool addExportedFunction(JSFunction *fun, PropertyName *maybeFieldName,
-                             MoveRef<ArgCoercionVector> argCoercions, ReturnType returnType)
+                             mozilla::MoveRef<ArgCoercionVector> argCoercions,
+                             ReturnType returnType)
     {
         ExportedFunction func(fun, maybeFieldName, argCoercions, returnType);
-        return exports_.append(Move(func));
+        return exports_.append(mozilla::Move(func));
     }
     unsigned numExportedFunctions() const {
         return exports_.length();
     }
     const ExportedFunction &exportedFunction(unsigned i) const {
         return exports_[i];
     }
     ExportedFunction &exportedFunction(unsigned i) {
--- a/js/src/shell/jsheaptools.cpp
+++ b/js/src/shell/jsheaptools.cpp
@@ -1,30 +1,35 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
  * vim: set ts=8 sts=4 et sw=4 tw=99:
  * 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 <string.h>
 
+#include "mozilla/Move.h"
+
 #include "jsapi.h"
 
 #include "jsalloc.h"
 #include "jscntxt.h"
 #include "jscompartment.h"
 #include "jsfun.h"
 #include "jsobj.h"
 #include "jsprf.h"
 #include "jsutil.h"
 
 #include "jsobjinlines.h"
 
 using namespace js;
 
+using mozilla::Move;
+using mozilla::MoveRef;
+
 #ifdef DEBUG
 
 
 /*** class HeapReverser **************************************************************************/
 
 /*
  * A class for constructing a map of the JavaScript heap, with all
  * reference edges reversed.
new file mode 100644
--- /dev/null
+++ b/mfbt/Move.h
@@ -0,0 +1,141 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* 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/. */
+
+/* C++11-style, but C++98-usable, "move references" implementation. */
+
+#ifndef mozilla_Move_h_
+#define mozilla_Move_h_
+
+namespace mozilla {
+
+/*
+ * "Move" References
+ *
+ * Some types can be copied much more efficiently if we know the original's
+ * value need not be preserved --- that is, if we are doing a "move", not a
+ * "copy". For example, if we have:
+ *
+ *   Vector<T> u;
+ *   Vector<T> v(u);
+ *
+ * the constructor for v must apply a copy constructor to each element of u ---
+ * taking time linear in the length of u. However, if we know we will not need u
+ * any more once v has been initialized, then we could initialize v very
+ * efficiently simply by stealing u's dynamically allocated buffer and giving it
+ * to v --- a constant-time operation, regardless of the size of u.
+ *
+ * Moves often appear in container implementations. For example, when we append
+ * to a vector, we may need to resize its buffer. This entails moving each of
+ * its extant elements from the old, smaller buffer to the new, larger buffer.
+ * But once the elements have been migrated, we're just going to throw away the
+ * old buffer; we don't care if they still have their values. So if the vector's
+ * element type can implement "move" more efficiently than "copy", the vector
+ * resizing should by all means use a "move" operation. Hash tables also need to
+ * be resized.
+ *
+ * The details of the optimization, and whether it's worth applying, vary from
+ * one type to the next. And while some constructor calls are moves, many really
+ * are copies, and can't be optimized this way. So we need:
+ *
+ * 1) a way for a particular invocation of a copy constructor to say that it's
+ *    really a move, and that the value of the original isn't important
+ *    afterwards (although it must still be safe to destroy); and
+ *
+ * 2) a way for a type (like Vector) to announce that it can be moved more
+ *    efficiently than it can be copied, and provide an implementation of that
+ *    move operation.
+ *
+ * The Move(T&) function takes a reference to a T, and returns a MoveRef<T>
+ * referring to the same value; that's 1). A MoveRef<T> is simply a reference
+ * to a T, annotated to say that a copy constructor applied to it may move that
+ * T, instead of copying it. Finally, a constructor that accepts an MoveRef<T>
+ * should perform a more efficient move, instead of a copy, providing 2).
+ *
+ * So, where we might define a copy constructor for a class C like this:
+ *
+ *   C(const C& rhs) { ... copy rhs to this ... }
+ *
+ * we would declare a move constructor like this:
+ *
+ *   C(MoveRef<C> rhs) { ... move rhs to this ... }
+ *
+ * And where we might perform a copy like this:
+ *
+ *   C c2(c1);
+ *
+ * we would perform a move like this:
+ *
+ *   C c2(Move(c1))
+ *
+ * Note that MoveRef<T> implicitly converts to T&, so you can pass a MoveRef<T>
+ * to an ordinary copy constructor for a type that doesn't support a special
+ * move constructor, and you'll just get a copy.  This means that templates can
+ * use Move whenever they know they won't use the original value any more, even
+ * if they're not sure whether the type at hand has a specialized move
+ * constructor.  If it doesn't, the MoveRef<T> will just convert to a T&, and
+ * the ordinary copy constructor will apply.
+ *
+ * A class with a move constructor can also provide a move assignment operator,
+ * which runs this's destructor, and then applies the move constructor to
+ * *this's memory. A typical definition:
+ *
+ *   C& operator=(MoveRef<C> rhs) {
+ *     this->~C();
+ *     new(this) C(rhs);
+ *     return *this;
+ *   }
+ *
+ * With that in place, one can write move assignments like this:
+ *
+ *   c2 = Move(c1);
+ *
+ * This destroys c1, moves c1's value to c2, and leaves c1 in an undefined but
+ * destructible state.
+ *
+ * This header file defines MoveRef and Move in the mozilla namespace.  It's up
+ * to individual containers to annotate moves as such, by calling Move; and it's
+ * up to individual types to define move constructors.
+ *
+ * One hint: if you're writing a move constructor where the type has members
+ * that should be moved themselves, it's much nicer to write this:
+ *
+ *   C(MoveRef<C> c) : x(c->x), y(c->y) { }
+ *
+ * than the equivalent:
+ *
+ *   C(MoveRef<C> c) { new(&x) X(c->x); new(&y) Y(c->y); }
+ *
+ * especially since GNU C++ fails to notice that this does indeed initialize x
+ * and y, which may matter if they're const.
+ */
+template<typename T>
+class MoveRef
+{
+    T* pointer;
+
+  public:
+    explicit MoveRef(T& t) : pointer(&t) { }
+    T& operator*() const { return *pointer; }
+    T* operator->() const { return pointer; }
+    operator T& () const { return *pointer; }
+};
+
+template<typename T>
+inline MoveRef<T>
+Move(T& t)
+{
+  return MoveRef<T>(t);
+}
+
+template<typename T>
+inline MoveRef<T>
+Move(const T& t)
+{
+  return MoveRef<T>(const_cast<T&>(t));
+}
+
+} // namespace mozilla
+
+#endif // mozilla_Move_h_
--- a/mfbt/exported_headers.mk
+++ b/mfbt/exported_headers.mk
@@ -27,16 +27,17 @@ EXPORTS_mozilla += \
   GuardObjects.h \
   HashFunctions.h \
   Likely.h \
   LinkedList.h \
   MathAlgorithms.h \
   MemoryChecking.h \
   MemoryReporting.h \
   MSStdInt.h \
+  Move.h \
   NullPtr.h \
   PodOperations.h \
   Poison.h \
   Range.h \
   RangedPtr.h \
   RefPtr.h \
   Scoped.h \
   SHA1.h \