Merge inbound to m-c
authorWes Kocher <wkocher@mozilla.com>
Tue, 18 Feb 2014 18:49:28 -0800
changeset 169800 f4f3d86162a536c935b048eb85a49d4d60f4ae28
parent 169799 d986cb469f302f526a2756295ddfe696409cdf13 (current diff)
parent 169746 33d272d4ad6c05c565b4d0f0225753a11729f42b (diff)
child 169801 ae3837d89b5e2a554107d5e476de672cb2aaa0d7
child 169833 955ffa2c9620b68a57562e6e9d466474d0c42379
child 169838 187282aafac115b92dc4f3f74abfa014c4f28c46
child 169849 f47f7c3df99115cea2eda95f18407611e717bd56
push id270
push userpvanderbeken@mozilla.com
push dateThu, 06 Mar 2014 09:24:21 +0000
milestone30.0a1
Merge inbound to m-c
browser/config/mozconfigs/hazards
--- a/accessible/src/jsat/Presentation.jsm
+++ b/accessible/src/jsat/Presentation.jsm
@@ -161,24 +161,26 @@ VisualPresenter.prototype = {
         }
       };
     }
 
     return null;
   },
 
   pivotChanged: function VisualPresenter_pivotChanged(aContext, aReason) {
+    if (!aContext.accessible) {
+      // XXX: Don't hide because another vc may be using the highlight.
+      return null;
+    }
+
     this._displayedAccessibles.set(aContext.accessible.document.window,
                                    { accessible: aContext.accessibleForBounds,
                                      startOffset: aContext.startOffset,
                                      endOffset: aContext.endOffset });
 
-    if (!aContext.accessibleForBounds)
-      return {type: this.type, details: {method: 'hideBounds'}};
-
     try {
       aContext.accessibleForBounds.scrollTo(
         Ci.nsIAccessibleScrollType.SCROLL_TYPE_ANYWHERE);
 
       let bounds = (aContext.startOffset === -1 && aContext.endOffset === -1) ?
             aContext.bounds : Utils.getTextBounds(aContext.accessibleForBounds,
                                                   aContext.startOffset,
                                                   aContext.endOffset);
--- a/browser/app/profile/firefox.js
+++ b/browser/app/profile/firefox.js
@@ -1375,8 +1375,12 @@ pref("identity.fxaccounts.remote.signin.
 
 // The URL we take the user to when they opt to "manage" their Firefox Account.
 // Note that this will always need to be in the same TLD as the
 // "identity.fxaccounts.remote.uri" pref.
 pref("identity.fxaccounts.settings.uri", "https://accounts.firefox.com/settings");
 
 // The URL of the Firefox Accounts auth server backend
 pref("identity.fxaccounts.auth.uri", "https://api.accounts.firefox.com/v1");
+
+
+// Temporarily turn the new http cache v2 on for Desktop Firefox only
+pref("browser.cache.use_new_backend_temp", true);
rename from browser/config/mozconfigs/hazards
rename to browser/config/mozconfigs/linux64/hazards
--- a/browser/config/mozconfigs/hazards
+++ b/browser/config/mozconfigs/linux64/hazards
@@ -1,13 +1,24 @@
 # This mozconfig is used when compiling the browser for the SM(Hf) rooting
 # hazard analysis build, see
 # https://wiki.mozilla.org/Javascript:SpiderMonkey:ExactStackRooting
 
-. "$topsrcdir/build/unix/mozconfig.linux"
+# Do NOT include build/unix/mozconfig.linux because it points directly at the
+# tooltool-installed gcc, and the analysis works by wrapping the gcc invocation
+# with a script that invokes the real gcc with -fplugin and its configuration
+# directives. Instead, duplicate the contents of that mozconfig here:
+
+. "$topsrcdir/build/mozconfig.common"
+ac_add_options --enable-elf-hack
+ac_add_options --enable-stdcxx-compat
+
+# The objdir must be at a known location so its path can be stripped from the
+# filenames stored by the analysis
+mk_add_options MOZ_OBJDIR=obj-analyzed
 
 # The configuration options are chosen to compile the most code
 # (--enable-debug, --enable-tests) in the trickiest way possible
 # (--enable-optimize) to maximize the chance of seeing tricky static orderings.
 ac_add_options --enable-debug
 ac_add_options --enable-tests
 ac_add_options --enable-optimize
 
--- a/build/docs/index.rst
+++ b/build/docs/index.rst
@@ -17,16 +17,17 @@ Important Concepts
    slow
    environment-variables
    build-targets
    python
    test_manifests
    mozinfo
    preprocessor
    jar-manifests
+   visualstudio
 
 mozbuild
 ========
 
 mozbuild is a Python package containing a lot of the code for the
 Mozilla build system.
 
 .. toctree::
new file mode 100644
--- /dev/null
+++ b/build/docs/visualstudio.rst
@@ -0,0 +1,100 @@
+.. _build_visualstudio:
+
+======================
+Visual Studio Projects
+======================
+
+The build system contains alpha support for generating Visual Studio
+project files to aid with development.
+
+To generate Visual Studio project files, you'll need to have a configured tree::
+
+   mach configure
+
+(If you have built recently, your tree is already configured.)
+
+Then, simply generate the Visual Studio build backend::
+
+   mach build-backend -b VisualStudio
+
+If all goes well, the path to the generated Solution (``.sln``) file should be
+printed. You should be able to open that solution with Visual Studio 2010 or
+newer.
+
+Currently, output is hard-coded to the Visual Studio 2010 format. If you open
+the solution in a newer Visual Studio release, you will be prompted to upgrade
+projects. Simply click through the wizard to do that.
+
+Structure of Solution
+=====================
+
+The Visual Studio solution consists of hundreds of projects spanning thousands
+of files. To help with organization, the solution is divided into the following
+trees/folders:
+
+Build Targets
+   This folder contains common build targets. The *full* project is used to
+   perform a full build. The *binaries* project is used to build just binaries.
+   The *visual-studio* project can be built to regenerate the Visual Studio
+   project files.
+
+   Performing the *clean* action on any of these targets will clean the
+   *entire* build output.
+
+Binaries
+   This folder contains common binaries that can be executed from within
+   Visual Studio. If you are building the Firefox desktop application,
+   the *firefox* project will launch firefox.exe. You probably want one of
+   these set to your startup project.
+
+Libraries
+   This folder contains entries for each static library that is produced as
+   part of the build. These roughly correspond to each directory in the tree
+   containing C/C++. e.g. code from ``dom/base`` will be contained in the
+   ``dom_base`` project.
+
+   These projects don't do anything when built. If you build a project here,
+   the *binaries* build target project is built.
+
+Updating Project Files
+======================
+
+As you pull and update the source tree, your Visual Studio files may fall out
+of sync with the build configuration. The tree should still build fine from
+within Visual Studio. But source files may be missing and IntelliSense may not
+have the proper build configuration.
+
+To account for this, you'll want to periodically regenerate the Visual Studio
+project files. You can do this within Visual Studio by building the
+``Build Targets :: visual-studio`` project or by running
+``mach build-backend -b VisualStudio`` from the command line.
+
+Currently, regeneration rewrites the original project files. **If you've made
+any customizations to the solution or projects, they will likely get
+overwritten.** We would like to improve this user experience in the
+future.
+
+Moving Project Files Around
+===========================
+
+The produced Visual Studio solution and project files should be portable.
+If you want to move them to a non-default directory, they should continue
+to work from wherever they are. If they don't, please file a bug.
+
+Invoking mach through Visual Studio
+===================================
+
+It's possible to build the tree via Visual Studio. There is some light magic
+involved here.
+
+Alongside the Visual Studio project files is a batch script named ``mach.bat``.
+This batch script sets the environment variables present in your *MozillaBuild*
+development environment at the time of Visual Studio project generation
+and invokes *mach* inside an msys shell with the arguments specified to the
+batch script. This script essentially allows you to invoke mach commands
+inside the MozillaBuild environment without having to load MozillaBuild.
+
+While projects currently only utilize the ``mach build`` command, the batch
+script does not limit it's use: any mach command can be invoked. Developers
+may abuse this fact to add custom projects and commands that invoke other
+mach commands.
--- a/configure.in
+++ b/configure.in
@@ -8613,21 +8613,16 @@ AC_SUBST(LIBJPEG_TURBO_X64_ASM)
 AC_SUBST(LIBJPEG_TURBO_ARM_ASM)
 
 AC_SUBST(MOZ_PACKAGE_JSSHELL)
 AC_SUBST(MOZ_FOLD_LIBS)
 
 AC_SUBST(MOZ_ENABLE_SZIP)
 AC_SUBST(MOZ_SZIP_FLAGS)
 
-if test "$MOZ_DEBUG"; then
-    MOZ_EM_DEBUG=1
-fi
-AC_SUBST(MOZ_EM_DEBUG)
-
 if test -n "$COMPILE_ENVIRONMENT"; then
 AC_MSG_CHECKING([for posix_fallocate])
 AC_TRY_LINK([#define _XOPEN_SOURCE 600
   #include <fcntl.h>],
                  [posix_fallocate(0, 0, 0);],
                  [ac_cv___posix_fallocate=true],
                  [ac_cv___posix_fallocate=false])
 
--- a/content/base/src/nsGkAtomList.h
+++ b/content/base/src/nsGkAtomList.h
@@ -1342,18 +1342,16 @@ GK_ATOM(metadata, "metadata")
 GK_ATOM(missingGlyph, "missing-glyph")
 GK_ATOM(mm, "mm")
 GK_ATOM(mpath, "mpath")
 GK_ATOM(noStitch, "noStitch")
 GK_ATOM(numOctaves, "numOctaves")
 GK_ATOM(multiply, "multiply")
 GK_ATOM(objectBoundingBox, "objectBoundingBox")
 GK_ATOM(offset, "offset")
-GK_ATOM(onSVGAbort, "onSVGAbort")
-GK_ATOM(onSVGError, "onSVGError")
 GK_ATOM(onSVGLoad, "onSVGLoad")
 GK_ATOM(onSVGResize, "onSVGResize")
 GK_ATOM(onSVGScroll, "onSVGScroll")
 GK_ATOM(onSVGUnload, "onSVGUnload")
 GK_ATOM(onSVGZoom, "onSVGZoom")
 GK_ATOM(onzoom, "onzoom")
 GK_ATOM(opacity, "opacity")
 GK_ATOM(_operator, "operator")
--- a/content/svg/content/src/nsSVGElement.cpp
+++ b/content/svg/content/src/nsSVGElement.cpp
@@ -1515,20 +1515,16 @@ nsSVGElement::MaybeSerializeAttrBeforeRe
 
 /* static */
 nsIAtom* nsSVGElement::GetEventNameForAttr(nsIAtom* aAttr)
 {
   if (aAttr == nsGkAtoms::onload)
     return nsGkAtoms::onSVGLoad;
   if (aAttr == nsGkAtoms::onunload)
     return nsGkAtoms::onSVGUnload;
-  if (aAttr == nsGkAtoms::onabort)
-    return nsGkAtoms::onSVGAbort;
-  if (aAttr == nsGkAtoms::onerror)
-    return nsGkAtoms::onSVGError;
   if (aAttr == nsGkAtoms::onresize)
     return nsGkAtoms::onSVGResize;
   if (aAttr == nsGkAtoms::onscroll)
     return nsGkAtoms::onSVGScroll;
   if (aAttr == nsGkAtoms::onzoom)
     return nsGkAtoms::onSVGZoom;
   if (aAttr == nsGkAtoms::onbegin)
     return nsGkAtoms::onbeginEvent;
--- a/content/svg/content/test/mochitest.ini
+++ b/content/svg/content/test/mochitest.ini
@@ -43,16 +43,17 @@ support-files =
 [test_hasFeature.xhtml]
 [test_lang.xhtml]
 skip-if = true # disabled-for-intermittent-failures--bug-701060
 [test_length.xhtml]
 skip-if = true
 [test_lengthParsing.html]
 [test_nonAnimStrings.xhtml]
 [test_non-scaling-stroke.html]
+[test_onerror.xhtml]
 [test_pathAnimInterpolation.xhtml]
 [test_pathSeg.xhtml]
 [test_pointAtLength.xhtml]
 [test_pointer-events-1a.xhtml]
 [test_pointer-events-1b.xhtml]
 [test_pointer-events-2.xhtml]
 [test_pointer-events-3.xhtml]
 [test_pointer-events-4.xhtml]
new file mode 100644
--- /dev/null
+++ b/content/svg/content/test/test_onerror.xhtml
@@ -0,0 +1,36 @@
+<html xmlns="http://www.w3.org/1999/xhtml">
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=500261
+-->
+<head>
+  <title>Test onerror behaviour</title>
+  <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=500261">Mozilla Bug 500261</a>
+<p id="display"></p>
+<div id="content">
+
+  <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="100%" height="1" id="svg">
+    <image width="1" height="1" xlink:href="http://localhost/serverGone.gif" onerror="run()"/>
+  </svg>
+
+</div>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+<![CDATA[
+
+SimpleTest.waitForExplicitFinish();
+
+function run()
+{
+  ok(true, 'onerror method called');
+  SimpleTest.finish();
+}
+
+]]>
+</script>
+</pre>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/dom/apps/src/Makefile.in
@@ -0,0 +1,7 @@
+# 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/.
+
+ifdef MOZ_DEBUG
+  DEFINES += -DMOZ_DEBUG=1
+endif
--- a/dom/apps/src/Webapps.jsm
+++ b/dom/apps/src/Webapps.jsm
@@ -50,17 +50,17 @@ Cu.import("resource://gre/modules/Promis
 #ifdef MOZ_WIDGET_GONK
 XPCOMUtils.defineLazyGetter(this, "libcutils", function() {
   Cu.import("resource://gre/modules/systemlibs.js");
   return libcutils;
 });
 #endif
 
 function debug(aMsg) {
-#ifdef DEBUG
+#ifdef MOZ_DEBUG
   dump("-*- Webapps.jsm : " + aMsg + "\n");
 #endif
 }
 
 function getNSPRErrorCode(err) {
   return -1 * ((err) & 0xffff);
 }
 
--- a/dom/events/nsEventListenerManager.cpp
+++ b/dom/events/nsEventListenerManager.cpp
@@ -828,20 +828,16 @@ nsEventListenerManager::CompileEventHand
     MOZ_ASSERT(element || aBody, "Where will we get our body?");
     nsAutoString handlerBody;
     const nsAString* body = aBody;
     if (!aBody) {
       if (aListenerStruct->mTypeAtom == nsGkAtoms::onSVGLoad)
         attrName = nsGkAtoms::onload;
       else if (aListenerStruct->mTypeAtom == nsGkAtoms::onSVGUnload)
         attrName = nsGkAtoms::onunload;
-      else if (aListenerStruct->mTypeAtom == nsGkAtoms::onSVGAbort)
-        attrName = nsGkAtoms::onabort;
-      else if (aListenerStruct->mTypeAtom == nsGkAtoms::onSVGError)
-        attrName = nsGkAtoms::onerror;
       else if (aListenerStruct->mTypeAtom == nsGkAtoms::onSVGResize)
         attrName = nsGkAtoms::onresize;
       else if (aListenerStruct->mTypeAtom == nsGkAtoms::onSVGScroll)
         attrName = nsGkAtoms::onscroll;
       else if (aListenerStruct->mTypeAtom == nsGkAtoms::onSVGZoom)
         attrName = nsGkAtoms::onzoom;
       else if (aListenerStruct->mTypeAtom == nsGkAtoms::onbeginEvent)
         attrName = nsGkAtoms::onbegin;
--- a/dom/events/nsEventNameList.h
+++ b/dom/events/nsEventNameList.h
@@ -144,17 +144,17 @@
 
 #ifndef BEFOREUNLOAD_EVENT
 #define BEFOREUNLOAD_EVENT WINDOW_EVENT
 #define DEFINED_BEFOREUNLOAD_EVENT
 #endif /* BEFOREUNLOAD_EVENT */
 
 EVENT(abort,
       NS_IMAGE_ABORT,
-      (EventNameType_HTMLXUL | EventNameType_SVGSVG),
+      EventNameType_All,
       NS_EVENT)
 EVENT(canplay,
       NS_CANPLAY,
       EventNameType_HTML,
       NS_EVENT)
 EVENT(canplaythrough,
       NS_CANPLAYTHROUGH,
       EventNameType_HTML,
@@ -428,17 +428,17 @@ EVENT(afterscriptexecute,
       NS_EVENT)
 
 FORWARDED_EVENT(blur,
                 NS_BLUR_CONTENT,
                 EventNameType_HTMLXUL,
                 NS_FOCUS_EVENT)
 ERROR_EVENT(error,
             NS_LOAD_ERROR,
-            (EventNameType_HTMLXUL | EventNameType_SVGSVG),
+            EventNameType_All,
             NS_EVENT)
 FORWARDED_EVENT(focus,
                 NS_FOCUS_CONTENT,
                 EventNameType_HTMLXUL,
                 NS_FOCUS_EVENT)
 FORWARDED_EVENT(load,
                 NS_LOAD,
                 EventNameType_All,
@@ -729,24 +729,16 @@ NON_IDL_EVENT(underflow,
 NON_IDL_EVENT(SVGLoad,
               NS_SVG_LOAD,
               EventNameType_None,
               NS_EVENT)
 NON_IDL_EVENT(SVGUnload,
               NS_SVG_UNLOAD,
               EventNameType_None,
               NS_EVENT)
-NON_IDL_EVENT(SVGAbort,
-              NS_SVG_ABORT,
-              EventNameType_None,
-              NS_EVENT)
-NON_IDL_EVENT(SVGError,
-              NS_SVG_ERROR,
-              EventNameType_None,
-              NS_EVENT)
 NON_IDL_EVENT(SVGResize,
               NS_SVG_RESIZE,
               EventNameType_None,
               NS_EVENT)
 NON_IDL_EVENT(SVGScroll,
               NS_SVG_SCROLL,
               EventNameType_None,
               NS_EVENT)
--- a/gfx/cairo/libpixman/src/Makefile.in
+++ b/gfx/cairo/libpixman/src/Makefile.in
@@ -60,17 +60,39 @@ ifdef HAVE_ARM_NEON
 USE_ARM_NEON_GCC=1
 endif
 endif
 endif
 
 endif
 
 
+ifdef USE_MMX
+CSRCS += pixman-mmx.c
+DEFINES += -DUSE_MMX
+endif
+
+ifdef USE_SSE2
+CSRCS += pixman-sse2.c
+DEFINES += -DUSE_SSE -DUSE_SSE2
+endif
+
+ifdef USE_VMX
+CSRCS += pixman-vmx.c
+DEFINES += -DUSE_VMX
+endif
+
+ifdef USE_ARM_SIMD_GCC
+CSRCS += pixman-arm-simd.c
+DEFINES += -DUSE_ARM_SIMD
+endif
+
 ifdef USE_ARM_NEON_GCC
+CSRCS += pixman-arm-neon.c
+DEFINES += -DUSE_ARM_NEON
 ARM_NEON_CFLAGS = -mfpu=neon
 endif
 
 include $(topsrcdir)/config/rules.mk
 
 # Disable spammy "missing initializer" GCC warning
 ifdef GNU_CC
 CFLAGS += -Wno-missing-field-initializers
--- a/gfx/cairo/libpixman/src/moz.build
+++ b/gfx/cairo/libpixman/src/moz.build
@@ -70,29 +70,8 @@ if CONFIG['MOZ_USE_PTHREADS']:
     DEFINES['HAVE_PTHREAD_SETSPECIFIC'] = True
 
 if CONFIG['_MSC_VER']:
     DEFINES['PIXMAN_USE_XP_DLL_TLS_WORKAROUND'] = True
 
 DEFINES['PACKAGE'] = 'mozpixman'
 
 DEFINES['_USE_MATH_DEFINES'] = True
-
-if CONFIG['USE_MMX']:
-    DEFINES['USE_MMX'] = True
-    SOURCES += ['pixman-mmx.c']
-
-if CONFIG['USE_SSE2']:
-    DEFINES['USE_SSE'] = True
-    DEFINES['USE_SSE2'] = True
-    SOURCES += ['pixman-sse2.c']
-
-if CONFIG['USE_VMX']:
-    DEFINES['USE_VMX'] = True
-    SOURCES += ['pixman-vmx.c']
-
-if CONFIG['USE_ARM_SIMD_GCC']:
-    DEFINES['USE_ARM_SIMD'] = True
-    SOURCES += ['pixman-arm-simd.c']
-
-if CONFIG['USE_ARM_NEON_GCC']:
-    DEFINES['USE_ARM_NEON'] = True
-    SOURCES += ['pixman-arm-neon.c']
new file mode 100644
--- /dev/null
+++ b/ipc/glue/ProcessUtils_bsd.cpp
@@ -0,0 +1,26 @@
+/* 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 "ProcessUtils.h"
+
+#include <pthread.h>
+
+#if !defined(OS_NETBSD)
+#include <pthread_np.h>
+#endif
+
+namespace mozilla {
+namespace ipc {
+
+void SetThisProcessName(const char *aName)
+{
+#if defined(OS_NETBSD)
+  pthread_setname_np(pthread_self(), "%s", (void *)aName);
+#else
+  pthread_set_name_np(pthread_self(), aName);
+#endif
+}
+
+} // namespace ipc
+} // namespace mozilla
--- a/ipc/glue/moz.build
+++ b/ipc/glue/moz.build
@@ -71,16 +71,20 @@ if CONFIG['OS_TARGET'] == 'Android':
     ]
 else:
     EXPORTS.mozilla.ipc += ['SharedMemoryBasic_chromium.h']
 
 if CONFIG['OS_ARCH'] == 'Linux':
     UNIFIED_SOURCES += [
         'ProcessUtils_linux.cpp',
     ]
+elif CONFIG['OS_ARCH'] in ('DragonFly', 'FreeBSD', 'NetBSD', 'OpenBSD'):
+    UNIFIED_SOURCES += [
+        'ProcessUtils_bsd.cpp'
+    ]
 else:
     UNIFIED_SOURCES += [
         'ProcessUtils_none.cpp',
     ]
 
 EXPORTS.ipc += [
     'IPCMessageUtils.h',
 ]
--- a/js/src/Makefile.in
+++ b/js/src/Makefile.in
@@ -198,16 +198,21 @@ DIST_GARBAGE = config.cache config.log c
    backend.mk config/backend.mk devtools/backend.mk editline/backend.mk \
    gdb/backend.mk jsapi-tests/backend.mk shell/backend.mk tests/backend.mk \
    backend.RecursiveMakeBackend backend.RecursiveMakeBackend.pp \
    devtools/rootAnalysis/Makefile
 
 distclean::
 	$(RM) $(DIST_GARBAGE)
 
+ifneq (,$(filter WINNT,$(OS_ARCH)))
+# _CRT_RAND_S must be #defined before #including stdlib.h to get rand_s()
+DEFINES         += -D_CRT_RAND_S
+endif
+
 ifneq ($(findstring -L,$(NSPR_LIBS)),)
 NSPR_STATIC_PATH = $(subst -L,,$(findstring -L,$(NSPR_LIBS)))
 else
 NSPR_STATIC_PATH = $(DIST)/lib
 endif
 
 # HP-UX does not require the extra linking of "-lm"
 ifeq (,$(filter HP-UX WINNT,$(OS_ARCH)))
--- a/js/src/jit-test/lib/bullet.js
+++ b/js/src/jit-test/lib/bullet.js
@@ -54438,17 +54438,22 @@ function b35() {
   ,b39,__ZNK10__cxxabiv120__si_class_type_info27has_unambiguous_public_baseEPNS_19__dynamic_cast_infoEPvi,b39,__ZNK10__cxxabiv121__vmi_class_type_info27has_unambiguous_public_baseEPNS_19__dynamic_cast_infoEPvi,b39,__ZN28btTriangleConvexcastCallback15processTriangleEP9btVector3ii,b39,__ZNK23btPolyhedralConvexShape49batchedUnitVectorGetSupportingVertexWithoutMarginEPK9btVector3PS0_i,b39,__ZN18btConstraintSolver9allSolvedERK19btContactSolverInfoP12btIDebugDrawP12btStackAlloc
   ,b39,__ZN24btConvexTriangleCallback15processTriangleEP9btVector3ii,b39,__ZNK13btSphereShape49batchedUnitVectorGetSupportingVertexWithoutMarginEPK9btVector3PS0_i,b39,__ZZN33btConvexConcaveCollisionAlgorithm21calculateTimeOfImpactEP17btCollisionObjectS1_RK16btDispatcherInfoP16btManifoldResultEN31LocalTriangleSphereCastCallback15processTriangleEP9btVector3ii,b39,__ZNK21btConvexInternalShape11getAabbSlowERK11btTransformR9btVector3S4_,b39,__ZN25btTriangleRaycastCallback15processTriangleEP9btVector3ii
   ,b39,__ZNK10__cxxabiv117__class_type_info27has_unambiguous_public_baseEPNS_19__dynamic_cast_infoEPvi,b39,__ZN21btCollisionDispatcher25dispatchAllCollisionPairsEP22btOverlappingPairCacheRK16btDispatcherInfoP12btDispatcher,b39,__ZNK10btBoxShape49batchedUnitVectorGetSupportingVertexWithoutMarginEPK9btVector3PS0_i,b39,__ZNK10btBoxShape7getAabbERK11btTransformR9btVector3S4_,b39,__ZNK15btTriangleShape49batchedUnitVectorGetSupportingVertexWithoutMarginEPK9btVector3PS0_i
   ,b39,__ZN15btGjkConvexCastC2EPK13btConvexShapeS2_P22btVoronoiSimplexSolver,b39,__ZNK16btDbvtBroadphase7getAabbEP17btBroadphaseProxyR9btVector3S3_,b39,__ZN23btDiscreteDynamicsWorld12addRigidBodyEP11btRigidBodyss,b39,__ZNK21btConvexInternalShape7getAabbERK11btTransformR9btVector3S4_,b39,__ZNK16btCollisionWorld7rayTestERK9btVector3S2_RNS_17RayResultCallbackE
   ,b39,__ZNK10btBoxShape8getPlaneER9btVector3S1_i,b39,__ZNK15btTriangleShape16getPlaneEquationEiR9btVector3S1_,b39,__ZNK15btTriangleShape7getAabbERK11btTransformR9btVector3S4_,b39,__ZN17DebugDrawcallback15processTriangleEP9btVector3ii,b39,__ZN23btDiscreteDynamicsWorld18addCollisionObjectEP17btCollisionObjectss,b39,b39,b39,b39,b39,b39,b39,b39,b39,b39,b39,b39,b39,b39,b39,b39,b39,b39,b39,b39,b39,b39,b39,b39,b39,b39,b39,b39,b39,b39,b39,b39,b39,b39,b39,b39,b39,b39,b39,b39,b39,b39,b39,b39,b39,b39,b39,b39,b39,b39,b39,b39,b39,b39,b39,b39,b39];
   return { _strlen: _strlen, _free: _free, _main: _main, __GLOBAL__I_a: __GLOBAL__I_a, _memset: _memset, _malloc: _malloc, _memcpy: _memcpy, _llvm_uadd_with_overflow_i64: _llvm_uadd_with_overflow_i64, runPostSets: runPostSets, stackAlloc: stackAlloc, stackSave: stackSave, stackRestore: stackRestore, setThrew: setThrew, setTempRet0: setTempRet0, setTempRet1: setTempRet1, setTempRet2: setTempRet2, setTempRet3: setTempRet3, setTempRet4: setTempRet4, setTempRet5: setTempRet5, setTempRet6: setTempRet6, setTempRet7: setTempRet7, setTempRet8: setTempRet8, setTempRet9: setTempRet9, dynCall_iiiiiiii: dynCall_iiiiiiii, dynCall_vif: dynCall_vif, dynCall_viifii: dynCall_viifii, dynCall_viiiii: dynCall_viiiii, dynCall_vi: dynCall_vi, dynCall_vii: dynCall_vii, dynCall_viiifii: dynCall_viiifii, dynCall_vifiii: dynCall_vifiii, dynCall_ii: dynCall_ii, dynCall_viiiiffffiif: dynCall_viiiiffffiif, dynCall_fiii: dynCall_fiii, dynCall_viiif: dynCall_viiif, dynCall_fiiiiiiiiiii: dynCall_fiiiiiiiiiii, dynCall_fiifii: dynCall_fiifii, dynCall_iii: dynCall_iii, dynCall_iiii: dynCall_iiii, dynCall_fif: dynCall_fif, dynCall_viiiiiiii: dynCall_viiiiiiii, dynCall_vifi: dynCall_vifi, dynCall_viiiiii: dynCall_viiiiii, dynCall_iiiiiiiiii: dynCall_iiiiiiiiii, dynCall_viffiii: dynCall_viffiii, dynCall_iiiiiii: dynCall_iiiiiii, dynCall_fiiiiiiiiii: dynCall_fiiiiiiiiii, dynCall_fiiiii: dynCall_fiiiii, dynCall_iiiiiiiiiiii: dynCall_iiiiiiiiiiii, dynCall_vifii: dynCall_vifii, dynCall_fi: dynCall_fi, dynCall_viiiiiiiiii: dynCall_viiiiiiiiii, dynCall_viiiifffffif: dynCall_viiiifffffif, dynCall_viiiiiffii: dynCall_viiiiiffii, dynCall_iifif: dynCall_iifif, dynCall_iiiii: dynCall_iiiii, dynCall_viii: dynCall_viii, dynCall_viifi: dynCall_viifi, dynCall_v: dynCall_v, dynCall_viif: dynCall_viif, dynCall_iiif: dynCall_iiif, dynCall_fiiifii: dynCall_fiiifii, dynCall_viiii: dynCall_viiii };
 };
 
-var asm = asmModule({ "Math": Math, "Int8Array": Int8Array, "Int16Array": Int16Array, "Int32Array": Int32Array, "Uint8Array": Uint8Array, "Uint16Array": Uint16Array, "Uint32Array": Uint32Array, "Float32Array": Float32Array, "Float64Array": Float64Array }, { "abort": abort, "assert": assert, "asmPrintInt": asmPrintInt, "asmPrintFloat": asmPrintFloat, "min": Math_min, "invoke_iiiiiiii": invoke_iiiiiiii, "invoke_vif": invoke_vif, "invoke_viifii": invoke_viifii, "invoke_viiiii": invoke_viiiii, "invoke_vi": invoke_vi, "invoke_vii": invoke_vii, "invoke_viiifii": invoke_viiifii, "invoke_vifiii": invoke_vifiii, "invoke_ii": invoke_ii, "invoke_viiiiffffiif": invoke_viiiiffffiif, "invoke_fiii": invoke_fiii, "invoke_viiif": invoke_viiif, "invoke_fiiiiiiiiiii": invoke_fiiiiiiiiiii, "invoke_fiifii": invoke_fiifii, "invoke_iii": invoke_iii, "invoke_iiii": invoke_iiii, "invoke_fif": invoke_fif, "invoke_viiiiiiii": invoke_viiiiiiii, "invoke_vifi": invoke_vifi, "invoke_viiiiii": invoke_viiiiii, "invoke_iiiiiiiiii": invoke_iiiiiiiiii, "invoke_viffiii": invoke_viffiii, "invoke_iiiiiii": invoke_iiiiiii, "invoke_fiiiiiiiiii": invoke_fiiiiiiiiii, "invoke_fiiiii": invoke_fiiiii, "invoke_iiiiiiiiiiii": invoke_iiiiiiiiiiii, "invoke_vifii": invoke_vifii, "invoke_fi": invoke_fi, "invoke_viiiiiiiiii": invoke_viiiiiiiiii, "invoke_viiiifffffif": invoke_viiiifffffif, "invoke_viiiiiffii": invoke_viiiiiffii, "invoke_iifif": invoke_iifif, "invoke_iiiii": invoke_iiiii, "invoke_viii": invoke_viii, "invoke_viifi": invoke_viifi, "invoke_v": invoke_v, "invoke_viif": invoke_viif, "invoke_iiif": invoke_iiif, "invoke_fiiifii": invoke_fiiifii, "invoke_viiii": invoke_viiii, "_llvm_lifetime_end": _llvm_lifetime_end, "_cosf": _cosf, "_fabsf": _fabsf, "_sysconf": _sysconf, "___cxa_throw": ___cxa_throw, "_atexit": _atexit, "_abort": _abort, "_fprintf": _fprintf, "_llvm_eh_exception": _llvm_eh_exception, "_printf": _printf, "_acosf": _acosf, "_fflush": _fflush, "__reallyNegative": __reallyNegative, "_sqrtf": _sqrtf, "_llvm_pow_f32": _llvm_pow_f32, "___setErrNo": ___setErrNo, "_fwrite": _fwrite, "_send": _send, "_write": _write, "_exit": _exit, "_atan2f": _atan2f, "___cxa_pure_virtual": ___cxa_pure_virtual, "___cxa_is_number_type": ___cxa_is_number_type, "_time": _time, "__formatString": __formatString, "___cxa_does_inherit": ___cxa_does_inherit, "___cxa_guard_acquire": ___cxa_guard_acquire, "__ZSt9terminatev": __ZSt9terminatev, "_gettimeofday": _gettimeofday, "___cxa_find_matching_catch": ___cxa_find_matching_catch, "_sinf": _sinf, "___assert_func": ___assert_func, "__ZSt18uncaught_exceptionv": __ZSt18uncaught_exceptionv, "_pwrite": _pwrite, "___cxa_call_unexpected": ___cxa_call_unexpected, "_sbrk": _sbrk, "___cxa_guard_abort": ___cxa_guard_abort, "___cxa_allocate_exception": ___cxa_allocate_exception, "___errno_location": ___errno_location, "___gxx_personality_v0": ___gxx_personality_v0, "_llvm_lifetime_start": _llvm_lifetime_start, "_fmod": _fmod, "___cxa_guard_release": ___cxa_guard_release, "__exit": __exit, "___resumeException": ___resumeException, "STACKTOP": STACKTOP, "STACK_MAX": STACK_MAX, "tempDoublePtr": tempDoublePtr, "ABORT": ABORT, "cttz_i8": cttz_i8, "ctlz_i8": ctlz_i8, "NaN": NaN, "Infinity": Infinity, "__ZTVN10__cxxabiv117__class_type_infoE": __ZTVN10__cxxabiv117__class_type_infoE, "__ZTVN10__cxxabiv120__si_class_type_infoE": __ZTVN10__cxxabiv120__si_class_type_infoE, "___dso_handle": ___dso_handle }, buffer);
+var ffis = { "abort": abort, "assert": assert, "asmPrintInt": asmPrintInt, "asmPrintFloat": asmPrintFloat, "min": Math_min, "invoke_iiiiiiii": invoke_iiiiiiii, "invoke_vif": invoke_vif, "invoke_viifii": invoke_viifii, "invoke_viiiii": invoke_viiiii, "invoke_vi": invoke_vi, "invoke_vii": invoke_vii, "invoke_viiifii": invoke_viiifii, "invoke_vifiii": invoke_vifiii, "invoke_ii": invoke_ii, "invoke_viiiiffffiif": invoke_viiiiffffiif, "invoke_fiii": invoke_fiii, "invoke_viiif": invoke_viiif, "invoke_fiiiiiiiiiii": invoke_fiiiiiiiiiii, "invoke_fiifii": invoke_fiifii, "invoke_iii": invoke_iii, "invoke_iiii": invoke_iiii, "invoke_fif": invoke_fif, "invoke_viiiiiiii": invoke_viiiiiiii, "invoke_vifi": invoke_vifi, "invoke_viiiiii": invoke_viiiiii, "invoke_iiiiiiiiii": invoke_iiiiiiiiii, "invoke_viffiii": invoke_viffiii, "invoke_iiiiiii": invoke_iiiiiii, "invoke_fiiiiiiiiii": invoke_fiiiiiiiiii, "invoke_fiiiii": invoke_fiiiii, "invoke_iiiiiiiiiiii": invoke_iiiiiiiiiiii, "invoke_vifii": invoke_vifii, "invoke_fi": invoke_fi, "invoke_viiiiiiiiii": invoke_viiiiiiiiii, "invoke_viiiifffffif": invoke_viiiifffffif, "invoke_viiiiiffii": invoke_viiiiiffii, "invoke_iifif": invoke_iifif, "invoke_iiiii": invoke_iiiii, "invoke_viii": invoke_viii, "invoke_viifi": invoke_viifi, "invoke_v": invoke_v, "invoke_viif": invoke_viif, "invoke_iiif": invoke_iiif, "invoke_fiiifii": invoke_fiiifii, "invoke_viiii": invoke_viiii, "_llvm_lifetime_end": _llvm_lifetime_end, "_cosf": _cosf, "_fabsf": _fabsf, "_sysconf": _sysconf, "___cxa_throw": ___cxa_throw, "_atexit": _atexit, "_abort": _abort, "_fprintf": _fprintf, "_llvm_eh_exception": _llvm_eh_exception, "_printf": _printf, "_acosf": _acosf, "_fflush": _fflush, "__reallyNegative": __reallyNegative, "_sqrtf": _sqrtf, "_llvm_pow_f32": _llvm_pow_f32, "___setErrNo": ___setErrNo, "_fwrite": _fwrite, "_send": _send, "_write": _write, "_exit": _exit, "_atan2f": _atan2f, "___cxa_pure_virtual": ___cxa_pure_virtual, "___cxa_is_number_type": ___cxa_is_number_type, "_time": _time, "__formatString": __formatString, "___cxa_does_inherit": ___cxa_does_inherit, "___cxa_guard_acquire": ___cxa_guard_acquire, "__ZSt9terminatev": __ZSt9terminatev, "_gettimeofday": _gettimeofday, "___cxa_find_matching_catch": ___cxa_find_matching_catch, "_sinf": _sinf, "___assert_func": ___assert_func, "__ZSt18uncaught_exceptionv": __ZSt18uncaught_exceptionv, "_pwrite": _pwrite, "___cxa_call_unexpected": ___cxa_call_unexpected, "_sbrk": _sbrk, "___cxa_guard_abort": ___cxa_guard_abort, "___cxa_allocate_exception": ___cxa_allocate_exception, "___errno_location": ___errno_location, "___gxx_personality_v0": ___gxx_personality_v0, "_llvm_lifetime_start": _llvm_lifetime_start, "_fmod": _fmod, "___cxa_guard_release": ___cxa_guard_release, "__exit": __exit, "___resumeException": ___resumeException, "STACKTOP": STACKTOP, "STACK_MAX": STACK_MAX, "tempDoublePtr": tempDoublePtr, "ABORT": ABORT, "cttz_i8": cttz_i8, "ctlz_i8": ctlz_i8, "NaN": NaN, "Infinity": Infinity, "__ZTVN10__cxxabiv117__class_type_infoE": __ZTVN10__cxxabiv117__class_type_infoE, "__ZTVN10__cxxabiv120__si_class_type_infoE": __ZTVN10__cxxabiv120__si_class_type_infoE, "___dso_handle": ___dso_handle };
+
+// Stress-test re-linking by linking once before the "real" one.
+var throwAway = asmModule(this, ffis, new ArrayBuffer(4*4096));
+
+var asm = asmModule(this, ffis, buffer);
 var _strlen = Module["_strlen"] = asm["_strlen"];
 var _free = Module["_free"] = asm["_free"];
 var _main = Module["_main"] = asm["_main"];
 var __GLOBAL__I_a = Module["__GLOBAL__I_a"] = asm["__GLOBAL__I_a"];
 var _memset = Module["_memset"] = asm["_memset"];
 var _malloc = Module["_malloc"] = asm["_malloc"];
 var _memcpy = Module["_memcpy"] = asm["_memcpy"];
 var _llvm_uadd_with_overflow_i64 = Module["_llvm_uadd_with_overflow_i64"] = asm["_llvm_uadd_with_overflow_i64"];
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/asm.js/testCloning.js
@@ -0,0 +1,37 @@
+load(libdir + "asm.js");
+
+var code = asmCompile(USE_ASM + "function g() { return 42 } return g");
+assertEq(asmLink(code)(), 42);
+assertEq(asmLink(code)(), 42);
+
+var code = asmCompile('glob', 'ffis', 'buf', USE_ASM + 'var i32=new glob.Int32Array(buf); function g() { return i32[0]|0 } return g');
+var i32_1 = new Int32Array(4096);
+i32_1[0] = 42;
+var i32_2 = new Int32Array(4096);
+i32_2[0] = 13;
+assertEq(asmLink(code, this, null, i32_1.buffer)(), 42);
+assertEq(asmLink(code, this, null, i32_2.buffer)(), 13);
+var i32_3 = new Int32Array(4097);
+assertAsmLinkFail(code, this, null, i32_3.buffer);
+
+var code = asmCompile('glob', 'ffis', USE_ASM + 'var ffi=ffis.ffi; function g(n) { n=n|0; var i=0; for(; (i|0)<(n|0); i=(i+1)|0) ffi() } return g');
+var calls1 = 0, calls2 = 0;
+function ffi1() { calls1++ }
+function ffi2() { calls2++ }
+asmLink(code, null, {ffi:ffi1})(100000);
+assertEq(calls1, 100000);
+assertEq(calls2, 0);
+calls1 = 0;
+asmLink(code, null, {ffi:ffi2})(50000);
+assertEq(calls1, 0);
+assertEq(calls2, 50000);
+
+var code = asmCompile(USE_ASM + 'var g = 0; function h() { g=(g+1)|0; return g|0 } return h');
+var h1 = code();
+assertEq(h1(), 1);
+assertEq(h1(), 2);
+var h2 = code();
+assertEq(h2(), 1);
+assertEq(h1(), 3);
+assertEq(h2(), 2);
+assertEq(h1(), 4);
--- a/js/src/jit/AsmJS.cpp
+++ b/js/src/jit/AsmJS.cpp
@@ -1576,17 +1576,17 @@ class MOZ_STACK_CLASS ModuleCompiler
         }
         out->reset(JS_smprintf("total compilation time %dms; %s%s",
                                msTotal,
                                storedInCache ? "stored in cache" : "not stored in cache",
                                slowFuns ? slowFuns.get() : ""));
 #endif
     }
 
-    bool extractModule(ScopedJSDeletePtr<AsmJSModule> *module, AsmJSStaticLinkData *linkData)
+    bool finish(ScopedJSDeletePtr<AsmJSModule> *module)
     {
         module_->initCharsEnd(parser_.tokenStream.currentToken().pos.end);
 
         masm_.finish();
         if (masm_.oom())
             return false;
 
 #if defined(JS_CODEGEN_ARM)
@@ -1625,66 +1625,60 @@ class MOZ_STACK_CLASS ModuleCompiler
             for (uint32_t i = 0; i < basicBlocks.length(); i++) {
                 Record &r = basicBlocks[i];
                 r.startOffset = masm_.actualOffset(r.startOffset);
                 r.endOffset = masm_.actualOffset(r.endOffset);
             }
         }
 #endif
 
-        // Some link information does not need to be permanently stored in the
-        // AsmJSModule since it is not needed after staticallyLink (which
-        // occurs during compilation and on cache deserialization). This link
-        // information is collected into AsmJSStaticLinkData which can then be
-        // serialized/deserialized alongside the AsmJSModule.
-
-        linkData->operationCallbackExitOffset = masm_.actualOffset(operationCallbackLabel_.offset());
+        module_->setOperationCallbackOffset(masm_.actualOffset(operationCallbackLabel_.offset()));
 
         // CodeLabels produced during codegen
         for (size_t i = 0; i < masm_.numCodeLabels(); i++) {
             CodeLabel src = masm_.codeLabel(i);
             int32_t labelOffset = src.dest()->offset();
             int32_t targetOffset = masm_.actualOffset(src.src()->offset());
             // The patched uses of a label embed a linked list where the
             // to-be-patched immediate is the offset of the next to-be-patched
             // instruction.
             while (labelOffset != LabelBase::INVALID_OFFSET) {
                 size_t patchAtOffset = masm_.labelOffsetToPatchOffset(labelOffset);
-                AsmJSStaticLinkData::RelativeLink link;
+                AsmJSModule::RelativeLink link;
                 link.patchAtOffset = patchAtOffset;
                 link.targetOffset = targetOffset;
-                if (!linkData->relativeLinks.append(link))
+                if (!module_->addRelativeLink(link))
                     return false;
                 labelOffset = *(uintptr_t *)(module_->codeBase() + patchAtOffset);
             }
         }
 
         // Function-pointer-table entries
         for (unsigned tableIndex = 0; tableIndex < funcPtrTables_.length(); tableIndex++) {
             FuncPtrTable &table = funcPtrTables_[tableIndex];
             unsigned tableBaseOffset = module_->offsetOfGlobalData() + table.globalDataOffset();
             for (unsigned elemIndex = 0; elemIndex < table.numElems(); elemIndex++) {
-                AsmJSStaticLinkData::RelativeLink link;
+                AsmJSModule::RelativeLink link;
                 link.patchAtOffset = tableBaseOffset + elemIndex * sizeof(uint8_t*);
                 link.targetOffset = masm_.actualOffset(table.elem(elemIndex).code()->offset());
-                if (!linkData->relativeLinks.append(link))
+                if (!module_->addRelativeLink(link))
                     return false;
             }
         }
 
 #if defined(JS_CODEGEN_X86)
         // Global data accesses in x86 need to be patched with the absolute
         // address of the global. Globals are allocated sequentially after the
         // code section so we can just use an RelativeLink.
         for (unsigned i = 0; i < globalAccesses_.length(); i++) {
             AsmJSGlobalAccess a = globalAccesses_[i];
-            AsmJSStaticLinkData::RelativeLink link;
+            AsmJSModule::RelativeLink link;
             link.patchAtOffset = masm_.labelOffsetToPatchOffset(a.patchAt.offset());
             link.targetOffset = module_->offsetOfGlobalData() + a.globalDataOffset;
-            if (!linkData->relativeLinks.append(link))
+            if (!module_->addRelativeLink(link))
                 return false;
         }
 #endif
 
 #if defined(JS_CODEGEN_X64)
         // Global data accesses on x64 use rip-relative addressing and thus do
         // not need patching after deserialization.
         uint8_t *code = module_->codeBase();
@@ -1692,20 +1686,20 @@ class MOZ_STACK_CLASS ModuleCompiler
             AsmJSGlobalAccess a = globalAccesses_[i];
             masm_.patchAsmJSGlobalAccess(a.patchAt, code, module_->globalData(), a.globalDataOffset);
         }
 #endif
 
         // Absolute links
         for (size_t i = 0; i < masm_.numAsmJSAbsoluteLinks(); i++) {
             AsmJSAbsoluteLink src = masm_.asmJSAbsoluteLink(i);
-            AsmJSStaticLinkData::AbsoluteLink link;
+            AsmJSModule::AbsoluteLink link;
             link.patchAt = masm_.actualOffset(src.patchAt.offset());
             link.target = src.target;
-            if (!linkData->absoluteLinks.append(link))
+            if (!module_->addAbsoluteLink(link))
                 return false;
         }
 
         *module = module_.forget();
         return true;
     }
 };
 
@@ -6785,29 +6779,28 @@ GenerateStubs(ModuleCompiler &m)
     if (!GenerateThrowExit(m, &throwLabel))
         return false;
 
     return true;
 }
 
 static bool
 FinishModule(ModuleCompiler &m,
-             ScopedJSDeletePtr<AsmJSModule> *module,
-             AsmJSStaticLinkData *linkData)
+             ScopedJSDeletePtr<AsmJSModule> *module)
 {
     LifoAlloc lifo(LIFO_ALLOC_PRIMARY_CHUNK_SIZE);
     TempAllocator alloc(&lifo);
     IonContext ionContext(m.cx(), &alloc);
 
     m.masm().resetForNewCodeGenerator(alloc);
 
     if (!GenerateStubs(m))
         return false;
 
-    return m.extractModule(module, linkData);
+    return m.finish(module);
 }
 
 static bool
 CheckModule(ExclusiveContext *cx, AsmJSParser &parser, ParseNode *stmtList,
             ScopedJSDeletePtr<AsmJSModule> *moduleOut,
             ScopedJSFreePtr<char> *compilationTimeReport)
 {
     if (!LookupAsmJSModuleInCache(cx, parser, moduleOut, compilationTimeReport))
@@ -6853,22 +6846,21 @@ CheckModule(ExclusiveContext *cx, AsmJSP
     if (!CheckModuleReturn(m))
         return false;
 
     TokenKind tk = PeekToken(m.parser());
     if (tk != TOK_EOF && tk != TOK_RC)
         return m.fail(nullptr, "top-level export (return) must be the last statement");
 
     ScopedJSDeletePtr<AsmJSModule> module;
-    AsmJSStaticLinkData linkData(cx);
-    if (!FinishModule(m, &module, &linkData))
-        return false;
-
-    bool storedInCache = StoreAsmJSModuleInCache(parser, *module, linkData, cx);
-    module->staticallyLink(linkData, cx);
+    if (!FinishModule(m, &module))
+        return false;
+
+    bool storedInCache = StoreAsmJSModuleInCache(parser, *module, cx);
+    module->staticallyLink(cx);
 
     m.buildCompilationTimeReport(storedInCache, compilationTimeReport);
     *moduleOut = module.forget();
     return true;
 }
 
 static bool
 Warn(AsmJSParser &parser, int errorNumber, const char *str)
--- a/js/src/jit/AsmJSLink.cpp
+++ b/js/src/jit/AsmJSLink.cpp
@@ -25,17 +25,32 @@
 
 #include "jsobjinlines.h"
 
 using namespace js;
 using namespace js::jit;
 
 using mozilla::IsNaN;
 
-static const unsigned MODULE_FUN_SLOT = 0;
+static bool
+CloneModule(JSContext *cx, MutableHandle<AsmJSModuleObject*> moduleObj)
+{
+    ScopedJSDeletePtr<AsmJSModule> module;
+    if (!moduleObj->module().clone(cx, &module))
+        return false;
+
+    module->staticallyLink(cx);
+
+    AsmJSModuleObject *newModuleObj = AsmJSModuleObject::create(cx, &module);
+    if (!newModuleObj)
+        return false;
+
+    moduleObj.set(newModuleObj);
+    return true;
+}
 
 static bool
 LinkFail(JSContext *cx, const char *str)
 {
     JS_ReportErrorFlagsAndNumber(cx, JSREPORT_WARNING, js_GetErrorMessage,
                                  nullptr, JSMSG_USE_ASM_LINK_FAIL, str);
     return false;
 }
@@ -206,22 +221,17 @@ ValidateConstant(JSContext *cx, AsmJSMod
     }
 
     return true;
 }
 
 static bool
 DynamicallyLinkModule(JSContext *cx, CallArgs args, AsmJSModule &module)
 {
-    if (module.isLinked())
-        return LinkFail(cx, "As a temporary limitation, modules cannot be linked more than "
-                            "once. This limitation should be removed in a future release. To "
-                            "work around this, compile a second module (e.g., using the "
-                            "Function constructor).");
-    module.setIsLinked();
+    module.setIsDynamicallyLinked();
 
     RootedValue globalVal(cx);
     if (args.length() > 0)
         globalVal = args[0];
 
     RootedValue importVal(cx);
     if (args.length() > 1)
         importVal = args[1];
@@ -620,19 +630,19 @@ SendModuleToAttachedProfiler(JSContext *
         return false;
 #endif
 
     return true;
 }
 
 
 static JSObject *
-CreateExportObject(JSContext *cx, HandleObject moduleObj)
+CreateExportObject(JSContext *cx, Handle<AsmJSModuleObject*> moduleObj)
 {
-    AsmJSModule &module = moduleObj->as<AsmJSModuleObject>().module();
+    AsmJSModule &module = moduleObj->module();
 
     if (module.numExportedFunctions() == 1) {
         const AsmJSModule::ExportedFunction &func = module.exportedFunction(0);
         if (!func.maybeFieldName())
             return NewExportedFunction(cx, func, moduleObj, 0);
     }
 
     gc::AllocKind allocKind = gc::GetGCObjectKind(module.numExportedFunctions());
@@ -652,27 +662,38 @@ CreateExportObject(JSContext *cx, Handle
         RootedValue val(cx, ObjectValue(*fun));
         if (!DefineNativeProperty(cx, obj, id, val, nullptr, nullptr, JSPROP_ENUMERATE, 0, 0))
             return nullptr;
     }
 
     return obj;
 }
 
+static const unsigned MODULE_FUN_SLOT = 0;
+
 // Implements the semantics of an asm.js module function that has been successfully validated.
 static bool
 LinkAsmJS(JSContext *cx, unsigned argc, JS::Value *vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
 
     // The LinkAsmJS builtin (created by NewAsmJSModuleFunction) is an extended
     // function and stores its module in an extended slot.
     RootedFunction fun(cx, &args.callee().as<JSFunction>());
-    RootedObject moduleObj(cx,  &fun->getExtendedSlot(MODULE_FUN_SLOT).toObject());
-    AsmJSModule &module = moduleObj->as<AsmJSModuleObject>().module();
+    Rooted<AsmJSModuleObject*> moduleObj(cx,
+        &fun->getExtendedSlot(MODULE_FUN_SLOT).toObject().as<AsmJSModuleObject>());
+
+    // When a module is linked, it is dynamically specialized to the given
+    // arguments (buffer, ffis). Thus, if the module is linked again (it is just
+    // a function so it can be called multiple times), we need to clone a new
+    // module.
+    if (moduleObj->module().isDynamicallyLinked() && !CloneModule(cx, &moduleObj))
+        return false;
+
+    AsmJSModule &module = moduleObj->module();
 
     // Link the module by performing the link-time validation checks in the
     // asm.js spec and then patching the generated module to associate it with
     // the given heap (ArrayBuffer) and a new global data segment (the closure
     // state shared by the inner asm.js functions).
     if (!DynamicallyLinkModule(cx, args, module)) {
         // Linking failed, so reparse the entire asm.js module from scratch to
         // get normal interpreted bytecode which we can simply Invoke. Very slow.
--- a/js/src/jit/AsmJSModule.cpp
+++ b/js/src/jit/AsmJSModule.cpp
@@ -27,28 +27,30 @@
 
 #include "jsobjinlines.h"
 
 #include "frontend/ParseNode-inl.h"
 
 using namespace js;
 using namespace jit;
 using namespace frontend;
+using mozilla::PodCopy;
 using mozilla::PodEqual;
 using mozilla::Compression::LZ4;
 
 void
 AsmJSModule::initHeap(Handle<ArrayBufferObject*> heap, JSContext *cx)
 {
-    JS_ASSERT(linked_);
+    JS_ASSERT(IsValidAsmJSHeapLength(heap->byteLength()));
+    JS_ASSERT(dynamicallyLinked_);
     JS_ASSERT(!maybeHeap_);
+
     maybeHeap_ = heap;
     heapDatum() = heap->dataPointer();
 
-    JS_ASSERT(IsValidAsmJSHeapLength(heap->byteLength()));
 #if defined(JS_CODEGEN_X86)
     uint8_t *heapOffset = heap->dataPointer();
     void *heapLength = (void*)heap->byteLength();
     for (unsigned i = 0; i < heapAccesses_.length(); i++) {
         const jit::AsmJSHeapAccess &access = heapAccesses_[i];
         if (access.hasLengthCheck())
             JSC::X86Assembler::setPointer(access.patchLengthAt(code_), heapLength);
         void *addr = access.patchOffsetAt(code_);
@@ -292,29 +294,58 @@ AddressOf(AsmJSImmKind kind, ExclusiveCo
         break;
     }
 
     MOZ_ASSUME_UNREACHABLE("Bad AsmJSImmKind");
     return nullptr;
 }
 
 void
-AsmJSModule::staticallyLink(const AsmJSStaticLinkData &linkData, ExclusiveContext *cx)
+AsmJSModule::restoreToInitialState(ArrayBufferObject *maybePrevBuffer, ExclusiveContext *cx)
 {
-    // Process AsmJSStaticLinkData:
+#ifdef DEBUG
+    // Put the absolute links back to -1 so patchDataWithValueCheck assertions
+    // in staticallyLink are valid.
+    for (size_t i = 0; i < staticLinkData_.absoluteLinks.length(); i++) {
+        AbsoluteLink link = staticLinkData_.absoluteLinks[i];
+        Assembler::patchDataWithValueCheck(code_ + link.patchAt.offset(),
+                                           PatchedImmPtr((void*)-1),
+                                           PatchedImmPtr(AddressOf(link.target, cx)));
+    }
+#endif
 
-    operationCallbackExit_ = code_ + linkData.operationCallbackExitOffset;
+    if (maybePrevBuffer) {
+#if defined(JS_CODEGEN_X86)
+        // Subtract out the base-pointer added by AsmJSModule::initHeap.
+        uint8_t *ptrBase = maybePrevBuffer->dataPointer();
+        for (unsigned i = 0; i < heapAccesses_.length(); i++) {
+            const jit::AsmJSHeapAccess &access = heapAccesses_[i];
+            void *addr = access.patchOffsetAt(code_);
+            uint8_t *ptr = reinterpret_cast<uint8_t*>(JSC::X86Assembler::getPointer(addr));
+            JS_ASSERT(ptr >= ptrBase);
+            JSC::X86Assembler::setPointer(addr, (void *)(ptr - ptrBase));
+        }
+#endif
+    }
+}
 
-    for (size_t i = 0; i < linkData.relativeLinks.length(); i++) {
-        AsmJSStaticLinkData::RelativeLink link = linkData.relativeLinks[i];
+void
+AsmJSModule::staticallyLink(ExclusiveContext *cx)
+{
+    // Process staticLinkData_
+
+    operationCallbackExit_ = code_ + staticLinkData_.operationCallbackExitOffset;
+
+    for (size_t i = 0; i < staticLinkData_.relativeLinks.length(); i++) {
+        RelativeLink link = staticLinkData_.relativeLinks[i];
         *(void **)(code_ + link.patchAtOffset) = code_ + link.targetOffset;
     }
 
-    for (size_t i = 0; i < linkData.absoluteLinks.length(); i++) {
-        AsmJSStaticLinkData::AbsoluteLink link = linkData.absoluteLinks[i];
+    for (size_t i = 0; i < staticLinkData_.absoluteLinks.length(); i++) {
+        AbsoluteLink link = staticLinkData_.absoluteLinks[i];
         Assembler::patchDataWithValueCheck(code_ + link.patchAt.offset(),
                                            PatchedImmPtr(AddressOf(link.target, cx)),
                                            PatchedImmPtr((void*)-1));
     }
 
     // Initialize global data segment
 
     for (size_t i = 0; i < exits_.length(); i++) {
@@ -324,17 +355,17 @@ AsmJSModule::staticallyLink(const AsmJSS
 }
 
 AsmJSModule::AsmJSModule(ScriptSource *scriptSource, uint32_t charsBegin)
   : globalArgumentName_(nullptr),
     importArgumentName_(nullptr),
     bufferArgumentName_(nullptr),
     code_(nullptr),
     operationCallbackExit_(nullptr),
-    linked_(false),
+    dynamicallyLinked_(false),
     loadedFromCache_(false),
     charsBegin_(charsBegin),
     scriptSource_(scriptSource)
 {
     mozilla::PodZero(&pod);
     scriptSource_->incref();
     pod.minHeapLength_ = AsmJSAllocationGranularity;
 }
@@ -379,17 +410,18 @@ AsmJSModule::addSizeOfMisc(mozilla::Mall
                         heapAccesses_.sizeOfExcludingThis(mallocSizeOf) +
 #if defined(MOZ_VTUNE)
                         profiledFunctions_.sizeOfExcludingThis(mallocSizeOf) +
 #endif
 #if defined(JS_ION_PERF)
                         profiledFunctions_.sizeOfExcludingThis(mallocSizeOf) +
                         perfProfiledBlocksFunctions_.sizeOfExcludingThis(mallocSizeOf) +
 #endif
-                        functionCounts_.sizeOfExcludingThis(mallocSizeOf);
+                        functionCounts_.sizeOfExcludingThis(mallocSizeOf) +
+                        staticLinkData_.sizeOfExcludingThis(mallocSizeOf);
 }
 
 static void
 AsmJSModuleObject_finalize(FreeOp *fop, JSObject *obj)
 {
     fop->delete_(&obj->as<AsmJSModuleObject>().module());
 }
 
@@ -546,16 +578,30 @@ DeserializeVector(ExclusiveContext *cx, 
         return nullptr;
     for (size_t i = 0; i < vec->length(); i++) {
         if (!(cursor = (*vec)[i].deserialize(cx, cursor)))
             return nullptr;
     }
     return cursor;
 }
 
+template <class T>
+bool
+CloneVector(ExclusiveContext *cx, const Vector<T, 0, SystemAllocPolicy> &in,
+            Vector<T, 0, SystemAllocPolicy> *out)
+{
+    if (!out->resize(in.length()))
+        return false;
+    for (size_t i = 0; i < in.length(); i++) {
+        if (!in[i].clone(cx, &(*out)[i]))
+            return false;
+    }
+    return true;
+}
+
 template <class T, class AllocPolicy, class ThisVector>
 size_t
 SerializedPodVectorSize(const mozilla::VectorBase<T, 0, AllocPolicy, ThisVector> &vec)
 {
     return sizeof(uint32_t) +
            vec.length() * sizeof(T);
 }
 
@@ -576,16 +622,27 @@ DeserializePodVector(ExclusiveContext *c
     uint32_t length;
     cursor = ReadScalar<uint32_t>(cursor, &length);
     if (!vec->resize(length))
         return nullptr;
     cursor = ReadBytes(cursor, vec->begin(), length * sizeof(T));
     return cursor;
 }
 
+template <class T>
+bool
+ClonePodVector(ExclusiveContext *cx, const Vector<T, 0, SystemAllocPolicy> &in,
+               Vector<T, 0, SystemAllocPolicy> *out)
+{
+    if (!out->resize(in.length()))
+        return false;
+    PodCopy(out->begin(), in.begin(), in.length());
+    return true;
+}
+
 uint8_t *
 AsmJSModule::Global::serialize(uint8_t *cursor) const
 {
     cursor = WriteBytes(cursor, &pod, sizeof(pod));
     cursor = SerializeName(cursor, name_);
     return cursor;
 }
 
@@ -599,16 +656,23 @@ AsmJSModule::Global::serializedSize() co
 const uint8_t *
 AsmJSModule::Global::deserialize(ExclusiveContext *cx, const uint8_t *cursor)
 {
     (cursor = ReadBytes(cursor, &pod, sizeof(pod))) &&
     (cursor = DeserializeName(cx, cursor, &name_));
     return cursor;
 }
 
+bool
+AsmJSModule::Global::clone(ExclusiveContext *cx, Global *out) const
+{
+    *out = *this;
+    return true;
+}
+
 uint8_t *
 AsmJSModule::Exit::serialize(uint8_t *cursor) const
 {
     cursor = WriteBytes(cursor, this, sizeof(*this));
     return cursor;
 }
 
 size_t
@@ -619,16 +683,23 @@ AsmJSModule::Exit::serializedSize() cons
 
 const uint8_t *
 AsmJSModule::Exit::deserialize(ExclusiveContext *cx, const uint8_t *cursor)
 {
     cursor = ReadBytes(cursor, this, sizeof(*this));
     return cursor;
 }
 
+bool
+AsmJSModule::Exit::clone(ExclusiveContext *cx, Exit *out) const
+{
+    *out = *this;
+    return true;
+}
+
 uint8_t *
 AsmJSModule::ExportedFunction::serialize(uint8_t *cursor) const
 {
     cursor = SerializeName(cursor, name_);
     cursor = SerializeName(cursor, maybeFieldName_);
     cursor = SerializePodVector(cursor, argCoercions_);
     cursor = WriteBytes(cursor, &pod, sizeof(pod));
     return cursor;
@@ -649,42 +720,98 @@ AsmJSModule::ExportedFunction::deseriali
 {
     (cursor = DeserializeName(cx, cursor, &name_)) &&
     (cursor = DeserializeName(cx, cursor, &maybeFieldName_)) &&
     (cursor = DeserializePodVector(cx, cursor, &argCoercions_)) &&
     (cursor = ReadBytes(cursor, &pod, sizeof(pod)));
     return cursor;
 }
 
+bool
+AsmJSModule::ExportedFunction::clone(ExclusiveContext *cx, ExportedFunction *out) const
+{
+    out->name_ = name_;
+    out->maybeFieldName_ = maybeFieldName_;
+
+    if (!ClonePodVector(cx, argCoercions_, &out->argCoercions_))
+        return false;
+
+    out->pod = pod;
+    return true;
+}
+
+size_t
+AsmJSModule::StaticLinkData::serializedSize() const
+{
+    return sizeof(uint32_t) +
+           SerializedPodVectorSize(relativeLinks) +
+           SerializedPodVectorSize(absoluteLinks);
+}
+
+uint8_t *
+AsmJSModule::StaticLinkData::serialize(uint8_t *cursor) const
+{
+    cursor = WriteScalar<uint32_t>(cursor, operationCallbackExitOffset);
+    cursor = SerializePodVector(cursor, relativeLinks);
+    cursor = SerializePodVector(cursor, absoluteLinks);
+    return cursor;
+}
+
+const uint8_t *
+AsmJSModule::StaticLinkData::deserialize(ExclusiveContext *cx, const uint8_t *cursor)
+{
+    (cursor = ReadScalar<uint32_t>(cursor, &operationCallbackExitOffset)) &&
+    (cursor = DeserializePodVector(cx, cursor, &relativeLinks)) &&
+    (cursor = DeserializePodVector(cx, cursor, &absoluteLinks));
+    return cursor;
+}
+
+bool
+AsmJSModule::StaticLinkData::clone(ExclusiveContext *cx, StaticLinkData *out) const
+{
+    out->operationCallbackExitOffset = operationCallbackExitOffset;
+    return ClonePodVector(cx, relativeLinks, &out->relativeLinks) &&
+           ClonePodVector(cx, absoluteLinks, &out->absoluteLinks);
+}
+
+size_t
+AsmJSModule::StaticLinkData::sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const
+{
+    return relativeLinks.sizeOfExcludingThis(mallocSizeOf) +
+           absoluteLinks.sizeOfExcludingThis(mallocSizeOf);
+}
+
 size_t
 AsmJSModule::serializedSize() const
 {
     return sizeof(pod) +
            pod.codeBytes_ +
            SerializedNameSize(globalArgumentName_) +
            SerializedNameSize(importArgumentName_) +
            SerializedNameSize(bufferArgumentName_) +
            SerializedVectorSize(globals_) +
            SerializedVectorSize(exits_) +
            SerializedVectorSize(exports_) +
-           SerializedPodVectorSize(heapAccesses_);
+           SerializedPodVectorSize(heapAccesses_) +
+           staticLinkData_.serializedSize();
 }
 
 uint8_t *
 AsmJSModule::serialize(uint8_t *cursor) const
 {
     cursor = WriteBytes(cursor, &pod, sizeof(pod));
     cursor = WriteBytes(cursor, code_, pod.codeBytes_);
     cursor = SerializeName(cursor, globalArgumentName_);
     cursor = SerializeName(cursor, importArgumentName_);
     cursor = SerializeName(cursor, bufferArgumentName_);
     cursor = SerializeVector(cursor, globals_);
     cursor = SerializeVector(cursor, exits_);
     cursor = SerializeVector(cursor, exports_);
     cursor = SerializePodVector(cursor, heapAccesses_);
+    cursor = staticLinkData_.serialize(cursor);
     return cursor;
 }
 
 const uint8_t *
 AsmJSModule::deserialize(ExclusiveContext *cx, const uint8_t *cursor)
 {
     // To avoid GC-during-deserialization corner cases, prevent atoms from
     // being collected.
@@ -694,46 +821,59 @@ AsmJSModule::deserialize(ExclusiveContex
     (code_ = AllocateExecutableMemory(cx, pod.totalBytes_)) &&
     (cursor = ReadBytes(cursor, code_, pod.codeBytes_)) &&
     (cursor = DeserializeName(cx, cursor, &globalArgumentName_)) &&
     (cursor = DeserializeName(cx, cursor, &importArgumentName_)) &&
     (cursor = DeserializeName(cx, cursor, &bufferArgumentName_)) &&
     (cursor = DeserializeVector(cx, cursor, &globals_)) &&
     (cursor = DeserializeVector(cx, cursor, &exits_)) &&
     (cursor = DeserializeVector(cx, cursor, &exports_)) &&
-    (cursor = DeserializePodVector(cx, cursor, &heapAccesses_));
+    (cursor = DeserializePodVector(cx, cursor, &heapAccesses_)) &&
+    (cursor = staticLinkData_.deserialize(cx, cursor));
 
     loadedFromCache_ = true;
     return cursor;
 }
 
-size_t
-AsmJSStaticLinkData::serializedSize() const
-{
-    return sizeof(uint32_t) +
-           SerializedPodVectorSize(relativeLinks) +
-           SerializedPodVectorSize(absoluteLinks);
-}
-
-uint8_t *
-AsmJSStaticLinkData::serialize(uint8_t *cursor) const
+bool
+AsmJSModule::clone(ExclusiveContext *cx, ScopedJSDeletePtr<AsmJSModule> *moduleOut) const
 {
-    cursor = WriteScalar<uint32_t>(cursor, operationCallbackExitOffset);
-    cursor = SerializePodVector(cursor, relativeLinks);
-    cursor = SerializePodVector(cursor, absoluteLinks);
-    return cursor;
-}
+    *moduleOut = cx->new_<AsmJSModule>(scriptSource_, charsBegin_);
+    if (!*moduleOut)
+        return false;
+
+    AsmJSModule &out = **moduleOut;
+
+    // Mirror the order of serialize/deserialize in cloning:
+
+    out.pod = pod;
+
+    out.code_ = AllocateExecutableMemory(cx, pod.totalBytes_);
+    if (!out.code_)
+        return false;
+
+    memcpy(out.code_, code_, pod.codeBytes_);
 
-const uint8_t *
-AsmJSStaticLinkData::deserialize(ExclusiveContext *cx, const uint8_t *cursor)
-{
-    (cursor = ReadScalar<uint32_t>(cursor, &operationCallbackExitOffset)) &&
-    (cursor = DeserializePodVector(cx, cursor, &relativeLinks)) &&
-    (cursor = DeserializePodVector(cx, cursor, &absoluteLinks));
-    return cursor;
+    out.globalArgumentName_ = globalArgumentName_;
+    out.importArgumentName_ = importArgumentName_;
+    out.bufferArgumentName_ = bufferArgumentName_;
+
+    if (!CloneVector(cx, globals_, &out.globals_) ||
+        !CloneVector(cx, exits_, &out.exits_) ||
+        !CloneVector(cx, exports_, &out.exports_) ||
+        !ClonePodVector(cx, heapAccesses_, &out.heapAccesses_) ||
+        !staticLinkData_.clone(cx, &out.staticLinkData_))
+    {
+        return false;
+    }
+
+    out.loadedFromCache_ = loadedFromCache_;
+
+    out.restoreToInitialState(maybeHeap_, cx);
+    return true;
 }
 
 static bool
 GetCPUID(uint32_t *cpuId)
 {
     enum Arch {
         X86 = 0x1,
         X64 = 0x2,
@@ -985,48 +1125,45 @@ struct ScopedCacheEntryOpenedForWrite
         if (memory)
             cx->asmJSCacheOps().closeEntryForWrite(cx->global(), serializedSize, memory, handle);
     }
 };
 
 bool
 js::StoreAsmJSModuleInCache(AsmJSParser &parser,
                             const AsmJSModule &module,
-                            const AsmJSStaticLinkData &linkData,
                             ExclusiveContext *cx)
 {
     MachineId machineId;
     if (!machineId.extractCurrentState(cx))
         return false;
 
     ModuleCharsForStore moduleChars;
     if (!moduleChars.init(parser, module))
         return false;
 
     size_t serializedSize = machineId.serializedSize() +
                             moduleChars.serializedSize() +
-                            module.serializedSize() +
-                            linkData.serializedSize();
+                            module.serializedSize();
 
     JS::OpenAsmJSCacheEntryForWriteOp open = cx->asmJSCacheOps().openEntryForWrite;
     if (!open)
         return false;
 
     const jschar *begin = parser.tokenStream.rawBase() + ModuleChars::beginOffset(parser);
     const jschar *end = parser.tokenStream.rawBase() + ModuleChars::endOffset(parser);
 
     ScopedCacheEntryOpenedForWrite entry(cx, serializedSize);
     if (!open(cx->global(), begin, end, entry.serializedSize, &entry.memory, &entry.handle))
         return false;
 
     uint8_t *cursor = entry.memory;
     cursor = machineId.serialize(cursor);
     cursor = moduleChars.serialize(cursor);
     cursor = module.serialize(cursor);
-    cursor = linkData.serialize(cursor);
 
     JS_ASSERT(cursor == entry.memory + serializedSize);
     return true;
 }
 
 struct ScopedCacheEntryOpenedForRead
 {
     ExclusiveContext *cx;
@@ -1084,27 +1221,22 @@ js::LookupAsmJSModuleInCache(ExclusiveCo
     ScopedJSDeletePtr<AsmJSModule> module(
         cx->new_<AsmJSModule>(parser.ss, parser.offsetOfCurrentAsmJSModule()));
     if (!module)
         return false;
     cursor = module->deserialize(cx, cursor);
     if (!cursor)
         return false;
 
-    AsmJSStaticLinkData linkData(cx);
-    cursor = linkData.deserialize(cx, cursor);
-    if (!cursor)
-        return false;
-
     bool atEnd = cursor == entry.memory + entry.serializedSize;
     MOZ_ASSERT(atEnd, "Corrupt cache file");
     if (!atEnd)
         return true;
 
-    module->staticallyLink(linkData, cx);
+    module->staticallyLink(cx);
 
     parser.tokenStream.advance(module->charsEnd());
 
     int64_t usecAfter = PRMJ_Now();
     int ms = (usecAfter - usecBefore) / PRMJ_USEC_PER_MSEC;
     *compilationTimeReport = JS_smprintf("loaded from cache in %dms", ms);
     *moduleOut = module.forget();
     return true;
--- a/js/src/jit/AsmJSModule.h
+++ b/js/src/jit/AsmJSModule.h
@@ -39,53 +39,16 @@ enum AsmJSMathBuiltinFunction
     AsmJSMathBuiltin_sin, AsmJSMathBuiltin_cos, AsmJSMathBuiltin_tan,
     AsmJSMathBuiltin_asin, AsmJSMathBuiltin_acos, AsmJSMathBuiltin_atan,
     AsmJSMathBuiltin_ceil, AsmJSMathBuiltin_floor, AsmJSMathBuiltin_exp,
     AsmJSMathBuiltin_log, AsmJSMathBuiltin_pow, AsmJSMathBuiltin_sqrt,
     AsmJSMathBuiltin_abs, AsmJSMathBuiltin_atan2, AsmJSMathBuiltin_imul,
     AsmJSMathBuiltin_fround, AsmJSMathBuiltin_min, AsmJSMathBuiltin_max
 };
 
-// Static-link data is used to patch a module either after it has been
-// compiled or deserialized with various absolute addresses (of code or
-// data in the process) or relative addresses (of code or data in the same
-// AsmJSModule). Since AsmJSStaticLinkData can be serialized alongside the
-// AsmJSModule and isn't needed after compilation/deserialization, it
-// doesn't need to be stored in the AsmJSModule.
-struct AsmJSStaticLinkData
-{
-    struct RelativeLink
-    {
-        uint32_t patchAtOffset;
-        uint32_t targetOffset;
-    };
-
-    typedef Vector<RelativeLink> RelativeLinkVector;
-
-    struct AbsoluteLink
-    {
-        jit::CodeOffsetLabel patchAt;
-        jit::AsmJSImmKind target;
-    };
-
-    typedef Vector<AbsoluteLink> AbsoluteLinkVector;
-
-    uint32_t operationCallbackExitOffset;
-    RelativeLinkVector relativeLinks;
-    AbsoluteLinkVector absoluteLinks;
-
-    AsmJSStaticLinkData(ExclusiveContext *cx)
-      : relativeLinks(cx), absoluteLinks(cx)
-    {}
-
-    size_t serializedSize() const;
-    uint8_t *serialize(uint8_t *cursor) const;
-    const uint8_t *deserialize(ExclusiveContext *cx, const uint8_t *cursor);
-};
-
 // An asm.js module represents the collection of functions nested inside a
 // single outer "use asm" function. For example, this asm.js module:
 //   function() { "use asm"; function f() {} function g() {} return f }
 // contains the functions 'f' and 'g'.
 //
 // An asm.js module contains both the jit-code produced by compiling all the
 // functions in the module as well all the data required to perform the
 // link-time validation step in the asm.js spec.
@@ -201,16 +164,17 @@ class AsmJSModule
         double constantValue() const {
             JS_ASSERT(pod.which_ == Constant);
             return pod.u.constant.value_;
         }
 
         size_t serializedSize() const;
         uint8_t *serialize(uint8_t *cursor) const;
         const uint8_t *deserialize(ExclusiveContext *cx, const uint8_t *cursor);
+        bool clone(ExclusiveContext *cx, Global *out) const;
     };
 
     class Exit
     {
         unsigned ffiIndex_;
         unsigned globalDataOffset_;
         unsigned interpCodeOffset_;
         unsigned ionCodeOffset_;
@@ -236,16 +200,17 @@ class AsmJSModule
         void initIonOffset(unsigned off) {
             JS_ASSERT(!ionCodeOffset_);
             ionCodeOffset_ = off;
         }
 
         size_t serializedSize() const;
         uint8_t *serialize(uint8_t *cursor) const;
         const uint8_t *deserialize(ExclusiveContext *cx, const uint8_t *cursor);
+        bool clone(ExclusiveContext *cx, Exit *out) const;
     };
     typedef int32_t (*CodePtr)(uint64_t *args, uint8_t *global);
 
     typedef Vector<AsmJSCoercion, 0, SystemAllocPolicy> ArgCoercionVector;
 
     enum ReturnType { Return_Int32, Return_Double, Return_Void };
 
     class ExportedFunction
@@ -307,16 +272,17 @@ class AsmJSModule
         }
         ReturnType returnType() const {
             return pod.returnType_;
         }
 
         size_t serializedSize() const;
         uint8_t *serialize(uint8_t *cursor) const;
         const uint8_t *deserialize(ExclusiveContext *cx, const uint8_t *cursor);
+        bool clone(ExclusiveContext *cx, ExportedFunction *out) const;
     };
 
 #if defined(MOZ_VTUNE) || defined(JS_ION_PERF)
     // Function information to add to the VTune JIT profiler following linking.
     struct ProfiledFunction
     {
         JSAtom *name;
         unsigned startCodeOffset;
@@ -357,16 +323,50 @@ class AsmJSModule
 
         ProfiledBlocksFunction(ProfiledBlocksFunction &&copy)
           : ProfiledFunction(copy.name, copy.startCodeOffset, copy.endCodeOffset),
             endInlineCodeOffset(copy.endInlineCodeOffset), blocks(mozilla::Move(copy.blocks))
         { }
     };
 #endif
 
+    struct RelativeLink
+    {
+        uint32_t patchAtOffset;
+        uint32_t targetOffset;
+    };
+
+    typedef Vector<RelativeLink, 0, SystemAllocPolicy> RelativeLinkVector;
+
+    struct AbsoluteLink
+    {
+        jit::CodeOffsetLabel patchAt;
+        jit::AsmJSImmKind target;
+    };
+
+    typedef Vector<AbsoluteLink, 0, SystemAllocPolicy> AbsoluteLinkVector;
+
+    // Static-link data is used to patch a module either after it has been
+    // compiled or deserialized with various absolute addresses (of code or
+    // data in the process) or relative addresses (of code or data in the same
+    // AsmJSModule).
+    struct StaticLinkData
+    {
+        uint32_t operationCallbackExitOffset;
+        RelativeLinkVector relativeLinks;
+        AbsoluteLinkVector absoluteLinks;
+
+        size_t serializedSize() const;
+        uint8_t *serialize(uint8_t *cursor) const;
+        const uint8_t *deserialize(ExclusiveContext *cx, const uint8_t *cursor);
+        bool clone(ExclusiveContext *cx, StaticLinkData *out) const;
+
+        size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const;
+    };
+
   private:
     typedef Vector<ExportedFunction, 0, SystemAllocPolicy> ExportedFunctionVector;
     typedef Vector<Global, 0, SystemAllocPolicy> GlobalVector;
     typedef Vector<Exit, 0, SystemAllocPolicy> ExitVector;
     typedef Vector<jit::AsmJSHeapAccess, 0, SystemAllocPolicy> HeapAccessVector;
     typedef Vector<jit::IonScriptCounts *, 0, SystemAllocPolicy> FunctionCountsVector;
 #if defined(MOZ_VTUNE) || defined(JS_ION_PERF)
     typedef Vector<ProfiledFunction, 0, SystemAllocPolicy> ProfiledFunctionVector;
@@ -401,17 +401,18 @@ class AsmJSModule
         size_t                            codeBytes_;     // function bodies and stubs
         size_t                            totalBytes_;    // function bodies, stubs, and global data
         uint32_t                          minHeapLength_;
     } pod;
 
     uint8_t *                             code_;
     uint8_t *                             operationCallbackExit_;
 
-    bool                                  linked_;
+    StaticLinkData                        staticLinkData_;
+    bool                                  dynamicallyLinked_;
     bool                                  loadedFromCache_;
     HeapPtr<ArrayBufferObject>            maybeHeap_;
 
     uint32_t                              charsBegin_;
     ScriptSource *                        scriptSource_;
 
     FunctionCountsVector                  functionCounts_;
 
@@ -719,45 +720,59 @@ class AsmJSModule
         if (len > pod.minHeapLength_)
             pod.minHeapLength_ = len;
     }
     uint32_t minHeapLength() const {
         return pod.minHeapLength_;
     }
 
     bool allocateAndCopyCode(ExclusiveContext *cx, jit::MacroAssembler &masm);
-    void staticallyLink(const AsmJSStaticLinkData &linkData, ExclusiveContext *cx);
+
+    // StaticLinkData setters (called after finishing compilation, before
+    // staticLink).
+    bool addRelativeLink(RelativeLink link) {
+        return staticLinkData_.relativeLinks.append(link);
+    }
+    bool addAbsoluteLink(AbsoluteLink link) {
+        return staticLinkData_.absoluteLinks.append(link);
+    }
+    void setOperationCallbackOffset(uint32_t offset) {
+        staticLinkData_.operationCallbackExitOffset = offset;
+    }
+
+    void restoreToInitialState(ArrayBufferObject *maybePrevBuffer, ExclusiveContext *cx);
+    void staticallyLink(ExclusiveContext *cx);
 
     uint8_t *codeBase() const {
         JS_ASSERT(code_);
         JS_ASSERT(uintptr_t(code_) % AsmJSPageSize == 0);
         return code_;
     }
 
     uint8_t *operationCallbackExit() const {
         return operationCallbackExit_;
     }
 
-    void setIsLinked() {
-        JS_ASSERT(!linked_);
-        linked_ = true;
+    void setIsDynamicallyLinked() {
+        JS_ASSERT(!dynamicallyLinked_);
+        dynamicallyLinked_ = true;
     }
-    bool isLinked() const {
-        return linked_;
+    bool isDynamicallyLinked() const {
+        return dynamicallyLinked_;
     }
     uint8_t *maybeHeap() const {
-        JS_ASSERT(linked_);
+        JS_ASSERT(dynamicallyLinked_);
         return heapDatum();
     }
     ArrayBufferObject *maybeHeapBufferObject() const {
-        JS_ASSERT(linked_);
+        JS_ASSERT(dynamicallyLinked_);
         return maybeHeap_;
     }
     size_t heapLength() const {
-        JS_ASSERT(linked_);
+        JS_ASSERT(dynamicallyLinked_);
         return maybeHeap_ ? maybeHeap_->byteLength() : 0;
     }
 
     void initGlobalArgumentName(PropertyName *n) {
         JS_ASSERT_IF(n, n->isTenured());
         globalArgumentName_ = n;
     }
     void initImportArgumentName(PropertyName *n) {
@@ -785,23 +800,24 @@ class AsmJSModule
 
     void addSizeOfMisc(mozilla::MallocSizeOf mallocSizeOf, size_t *asmJSModuleCode,
                        size_t *asmJSModuleData);
 
     size_t serializedSize() const;
     uint8_t *serialize(uint8_t *cursor) const;
     const uint8_t *deserialize(ExclusiveContext *cx, const uint8_t *cursor);
     bool loadedFromCache() const { return loadedFromCache_; }
+
+    bool clone(ExclusiveContext *cx, ScopedJSDeletePtr<AsmJSModule> *moduleOut) const;
 };
 
 // Store the just-parsed module in the cache using AsmJSCacheOps.
 extern bool
 StoreAsmJSModuleInCache(AsmJSParser &parser,
                         const AsmJSModule &module,
-                        const AsmJSStaticLinkData &linkData,
                         ExclusiveContext *cx);
 
 // Attempt to load the asm.js module that is about to be parsed from the cache
 // using AsmJSCacheOps. On cache hit, *module will be non-null. Note: the
 // return value indicates whether or not an error was encountered, not whether
 // there was a cache hit.
 extern bool
 LookupAsmJSModuleInCache(ExclusiveContext *cx,
--- a/js/src/moz.build
+++ b/js/src/moz.build
@@ -338,18 +338,16 @@ if CONFIG['ENABLE_ION']:
                 'jit/arm/Simulator-arm.cpp'
             ]
 
 if CONFIG['OS_ARCH'] == 'WINNT':
     SOURCES += [
         'assembler/jit/ExecutableAllocatorWin.cpp',
         'yarr/OSAllocatorWin.cpp',
     ]
-    # _CRT_RAND_S must be #defined before #including stdlib.h to get rand_s()
-    DEFINES['_CRT_RAND_S'] = True
 else:
     SOURCES += [
         'assembler/jit/ExecutableAllocatorPosix.cpp',
         'yarr/OSAllocatorPosix.cpp',
     ]
 
 if CONFIG['ENABLE_ION'] or CONFIG['ENABLE_YARR_JIT']:
     if CONFIG['JS_CODEGEN_X86'] or CONFIG['JS_CODEGEN_X64']:
--- a/netwerk/cache2/CacheObserver.cpp
+++ b/netwerk/cache2/CacheObserver.cpp
@@ -20,16 +20,19 @@ namespace net {
 
 CacheObserver* CacheObserver::sSelf = nullptr;
 
 static uint32_t const kDefaultMemoryLimit = 50 * 1024; // 50 MB
 uint32_t CacheObserver::sMemoryLimit = kDefaultMemoryLimit;
 
 static uint32_t const kDefaultUseNewCache = 0; // Don't use the new cache by default
 uint32_t CacheObserver::sUseNewCache = kDefaultUseNewCache;
+
+static bool sUseNewCacheTemp = false; // Temp trigger to not lose early adopters
+
 static int32_t const kAutoDeleteCacheVersion = -1; // Auto-delete off by default
 static int32_t sAutoDeleteCacheVersion = kAutoDeleteCacheVersion;
 
 static int32_t const kDefaultHalfLifeExperiment = -1; // Disabled
 int32_t CacheObserver::sHalfLifeExperiment = kDefaultHalfLifeExperiment;
 
 static uint32_t const kDefaultHalfLifeHours = 6; // 6 hours
 uint32_t CacheObserver::sHalfLifeHours = kDefaultHalfLifeHours;
@@ -97,16 +100,18 @@ CacheObserver::Shutdown()
 void
 CacheObserver::AttachToPreferences()
 {
   sAutoDeleteCacheVersion = mozilla::Preferences::GetInt(
     "browser.cache.auto_delete_cache_version", kAutoDeleteCacheVersion);
 
   mozilla::Preferences::AddUintVarCache(
     &sUseNewCache, "browser.cache.use_new_backend", kDefaultUseNewCache);
+  mozilla::Preferences::AddBoolVarCache(
+    &sUseNewCacheTemp, "browser.cache.use_new_backend_temp", false);
 
   mozilla::Preferences::AddBoolVarCache(
     &sUseDiskCache, "browser.cache.disk.enable", kDefaultUseDiskCache);
   mozilla::Preferences::AddBoolVarCache(
     &sUseMemoryCache, "browser.cache.memory.enable", kDefaultUseMemoryCache);
 
   mozilla::Preferences::AddUintVarCache(
     &sMemoryLimit, "browser.cache.memory_limit", kDefaultMemoryLimit);
@@ -172,17 +177,22 @@ void CacheObserver::SchduleAutoDelete()
     return;
 
   CacheStorageService::WipeCacheDirectory(sAutoDeleteCacheVersion);
 }
 
 // static
 bool const CacheObserver::UseNewCache()
 {
-  switch (sUseNewCache) {
+  uint32_t useNewCache = sUseNewCache;
+
+  if (sUseNewCacheTemp)
+    useNewCache = 1;
+
+  switch (useNewCache) {
     case 0: // use the old cache backend
       return false;
 
     case 1: // use the new cache backend
       return true;
   }
 
   return true;
new file mode 100644
--- /dev/null
+++ b/python/mozbuild/mozbuild/backend/visualstudio.py
@@ -0,0 +1,552 @@
+# 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/.
+
+# This file contains a build backend for generating Visual Studio project
+# files.
+
+from __future__ import unicode_literals
+
+import errno
+import os
+import re
+import types
+import uuid
+
+from xml.dom import getDOMImplementation
+
+from mozpack.files import FileFinder
+
+from .common import CommonBackend
+from ..frontend.data import (
+    Defines,
+    LibraryDefinition,
+    LocalInclude,
+    VariablePassthru,
+)
+
+
+MSBUILD_NAMESPACE = 'http://schemas.microsoft.com/developer/msbuild/2003'
+
+def get_id(name):
+    return str(uuid.uuid5(uuid.NAMESPACE_URL, name)).upper()
+
+# TODO validate mappings are correct. only 2010 confirmed so far
+def visual_studio_product_to_internal_version(version, solution=False):
+    if solution:
+        if version == '2010':
+            return '11.00'
+        elif version == '2011':
+            return '12.00'
+        elif version == '2012':
+            return '13.00'
+        else:
+            raise Exception('Unknown version seen: %s' % version)
+    else:
+        if version == '2010':
+            return '10.00'
+        elif version == '2011':
+            return '11.00'
+        elif version == '2012':
+            return '12.00'
+        else:
+            raise Exception('Unknown version seen: %s' % version)
+
+class VisualStudioBackend(CommonBackend):
+    """Generate Visual Studio project files.
+
+    This backend is used to produce Visual Studio projects and a solution
+    to foster developing Firefox with Visual Studio.
+
+    This backend is currently considered experimental. There are many things
+    not optimal about how it works.
+
+    It's worth noting that lots of file I/O here is not using
+    self._write_file(). That's because we need Windows line endings preserved
+    and self._write_file() currently opens files in text mode, which behaves
+    oddly under MozillaBuild.
+    """
+
+    def _init(self):
+        CommonBackend._init(self)
+
+        # These should eventually evolve into parameters.
+        self._out_dir = os.path.join(self.environment.topobjdir, 'msvc')
+        # But making this one a parameter requires testing first.
+        self._version = '2010'
+
+        self._paths_to_sources = {}
+        self._paths_to_includes = {}
+        self._paths_to_defines = {}
+        self._paths_to_configs = {}
+        self._libs_to_paths = {}
+
+        def detailed(summary):
+            return 'Generated Visual Studio solution at %s' % (
+                os.path.join(self._out_dir, 'mozilla.sln'))
+
+        self.summary.backend_detailed_summary = types.MethodType(detailed,
+            self.summary)
+
+    def consume_object(self, obj):
+        # Just acknowledge everything.
+        obj.ack()
+
+        reldir = getattr(obj, 'relativedir', None)
+
+        if hasattr(obj, 'config') and reldir not in self._paths_to_configs:
+            self._paths_to_configs[reldir] = obj.config
+
+        if isinstance(obj, VariablePassthru):
+            for k, v in obj.variables.items():
+                if k.endswith('SRCS'):
+                    s = self._paths_to_sources.setdefault(reldir, set())
+                    s.update(v)
+
+        elif isinstance(obj, LibraryDefinition):
+            self._libs_to_paths[obj.basename] = reldir
+
+        elif isinstance(obj, Defines):
+            self._paths_to_defines.setdefault(reldir, {}).update(obj.defines)
+
+        elif isinstance(obj, LocalInclude):
+            p = obj.path
+            includes = self._paths_to_includes.setdefault(reldir, [])
+
+            if p.startswith('/'):
+                includes.append(os.path.join('$(TopSrcDir)', p[1:]))
+            else:
+                includes.append(os.path.join('$(TopSrcDir)', reldir, p))
+
+    def consume_finished(self):
+        out_dir = self._out_dir
+        try:
+            os.makedirs(out_dir)
+        except OSError as e:
+            if e.errno != errno.EEXIST:
+                raise
+
+        projects = {}
+
+        for lib, path in sorted(self._libs_to_paths.items()):
+            config = self._paths_to_configs.get(path, None)
+            sources = self._paths_to_sources.get(path, set())
+            sources = set(os.path.join('$(TopSrcDir)', path, s) for s in sources)
+            sources = set(os.path.normpath(s) for s in sources)
+
+            finder = FileFinder(os.path.join(self.environment.topsrcdir, path),
+                find_executables=False)
+
+            headers = [t[0] for t in finder.find('*.h')]
+            headers = [os.path.normpath(os.path.join('$(TopSrcDir)',
+                path, f)) for f in headers]
+
+            includes = [
+                os.path.join('$(TopSrcDir)', path),
+                os.path.join('$(TopObjDir)', path),
+            ]
+            includes.extend(self._paths_to_includes.get(path, []))
+            includes.append('$(TopObjDir)\\dist\\include\\nss')
+            includes.append('$(TopObjDir)\\dist\\include')
+
+            for v in ('NSPR_CFLAGS', 'NSS_CFLAGS', 'MOZ_JPEG_CFLAGS',
+                    'MOZ_PNG_CFLAGS', 'MOZ_ZLIB_CFLAGS', 'MOZ_PIXMAN_CFLAGS'):
+                if not config:
+                    break
+
+                args = config.substs.get(v, '').split()
+
+                for i, arg in enumerate(args):
+                    if arg.startswith('-I'):
+                        includes.append(os.path.normpath(arg[2:]))
+
+            # Pull in system defaults.
+            includes.append('$(DefaultIncludes)')
+
+            includes = [os.path.normpath(i) for i in includes]
+
+            defines = []
+            for k, v in self._paths_to_defines.get(path, {}).items():
+                if v is True:
+                    defines.append(k)
+                else:
+                    defines.append('%s=%s' % (k, v))
+
+            basename = 'library_%s' % lib
+            project_id = self._write_vs_project(out_dir, basename, lib,
+                includes=includes,
+                forced_includes=['$(TopObjDir)\\dist\\include\\mozilla-config.h'],
+                defines=defines,
+                headers=headers,
+                sources=sources)
+
+            projects[basename] = (project_id, basename, lib)
+
+        # Generate projects that can be used to build common targets.
+        for target in ('export', 'binaries', 'tools', 'full'):
+            basename = 'target_%s' % target
+            command = '$(SolutionDir)\\mach.bat build'
+            if target != 'full':
+                command += ' %s' % target
+
+            project_id = self._write_vs_project(out_dir, basename, target,
+                build_command=command,
+                clean_command='$(SolutionDir)\\mach.bat build clean')
+
+            projects[basename] = (project_id, basename, target)
+
+        # A project that can be used to regenerate the visual studio projects.
+        basename = 'target_vs'
+        project_id = self._write_vs_project(out_dir, basename, 'visual-studio',
+            build_command='$(SolutionDir)\\mach.bat build-backend -b VisualStudio')
+        projects[basename] = (project_id, basename, 'visual-studio')
+
+        # A project to run the main application binary.
+        app_name = self.environment.substs['MOZ_APP_NAME']
+        basename = 'binary_%s' % app_name
+        project_id = self._write_vs_project(out_dir, basename, app_name,
+            debugger=('$(TopObjDir)\\dist\\bin\\%s.exe' % app_name,
+                '-no-remote'))
+        projects[basename] = (project_id, basename, app_name)
+
+        # Projects to run other common binaries.
+        for app in ['js', 'xpcshell']:
+            basename = 'binary_%s' % app
+            project_id = self._write_vs_project(out_dir, basename, app,
+                debugger=('$(TopObjDir)\\dist\\bin\\%s.exe' % app, ''))
+            projects[basename] = (project_id, basename, app)
+
+        # Write out a shared property file with common variables.
+        props_path = os.path.join(out_dir, 'mozilla.props')
+        with open(props_path, 'wb') as fh:
+            self._write_props(fh)
+
+        # Generate some wrapper scripts that allow us to invoke mach inside
+        # a MozillaBuild-like environment. We currently only use the batch
+        # script. We'd like to use the PowerShell script. However, it seems
+        # to buffer output from within Visual Studio (surely this is
+        # configurable) and the default execution policy of PowerShell doesn't
+        # allow custom scripts to be executed.
+        with open(os.path.join(out_dir, 'mach.bat'), 'wb') as fh:
+            self._write_mach_batch(fh)
+
+        with open(os.path.join(out_dir, 'mach.ps1'), 'wb') as fh:
+            self._write_mach_powershell(fh)
+
+        # Write out a solution file to tie it all together.
+        solution_path = os.path.join(out_dir, 'mozilla.sln')
+        with open(solution_path, 'wb') as fh:
+            self._write_solution(fh, projects)
+
+    def _write_solution(self, fh, projects):
+        version = visual_studio_product_to_internal_version(self._version, True)
+        # This is a Visual C++ Project type.
+        project_type = '8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942'
+
+        # Visual Studio seems to require this header.
+        fh.write('Microsoft Visual Studio Solution File, Format Version %s\r\n' %
+            version)
+        fh.write('# Visual Studio %s\r\n' % self._version)
+
+        binaries_id = projects['target_binaries'][0]
+
+        # Write out entries for each project.
+        for key in sorted(projects):
+            project_id, basename, name = projects[key]
+            path = '%s.vcxproj' % basename
+
+            fh.write('Project("{%s}") = "%s", "%s", "{%s}"\r\n' % (
+                project_type, name, path, project_id))
+
+            # Make all libraries depend on the binaries target.
+            if key.startswith('library_'):
+                fh.write('\tProjectSection(ProjectDependencies) = postProject\r\n')
+                fh.write('\t\t{%s} = {%s}\r\n' % (binaries_id, binaries_id))
+                fh.write('\tEndProjectSection\r\n')
+
+            fh.write('EndProject\r\n')
+
+        # Write out solution folders for organizing things.
+
+        # This is the UUID you use for solution folders.
+        container_id = '2150E333-8FDC-42A3-9474-1A3956D46DE8'
+
+        def write_container(desc):
+            cid = get_id(desc.encode('utf-8'))
+            fh.write('Project("{%s}") = "%s", "%s", "{%s}"\r\n' % (
+                container_id, desc, desc, cid))
+            fh.write('EndProject\r\n')
+
+            return cid
+
+        library_id = write_container('Libraries')
+        target_id = write_container('Build Targets')
+        binary_id = write_container('Binaries')
+
+        fh.write('Global\r\n')
+
+        # Make every project a member of our one configuration.
+        fh.write('\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\r\n')
+        fh.write('\t\tBuild|Win32 = Build|Win32\r\n')
+        fh.write('\tEndGlobalSection\r\n')
+
+        # Set every project's active configuration to the one configuration and
+        # set up the default build project.
+        fh.write('\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\r\n')
+        for name, project in sorted(projects.items()):
+            fh.write('\t\t{%s}.Build|Win32.ActiveCfg = Build|Win32\r\n' % project[0])
+
+            # Only build the full build target by default.
+            # It's important we don't write multiple entries here because they
+            # conflict!
+            if name == 'target_full':
+                fh.write('\t\t{%s}.Build|Win32.Build.0 = Build|Win32\r\n' % project[0])
+
+        fh.write('\tEndGlobalSection\r\n')
+
+        fh.write('\tGlobalSection(SolutionProperties) = preSolution\r\n')
+        fh.write('\t\tHideSolutionNode = FALSE\r\n')
+        fh.write('\tEndGlobalSection\r\n')
+
+        # Associate projects with containers.
+        fh.write('\tGlobalSection(NestedProjects) = preSolution\r\n')
+        for key in sorted(projects):
+            project_id = projects[key][0]
+
+            if key.startswith('library_'):
+                container_id = library_id
+            elif key.startswith('target_'):
+                container_id = target_id
+            elif key.startswith('binary_'):
+                container_id = binary_id
+            else:
+                raise Exception('Unknown project type: %s' % key)
+
+            fh.write('\t\t{%s} = {%s}\r\n' % (project_id, container_id))
+        fh.write('\tEndGlobalSection\r\n')
+
+        fh.write('EndGlobal\r\n')
+
+    def _write_props(self, fh):
+        impl = getDOMImplementation()
+        doc = impl.createDocument(MSBUILD_NAMESPACE, 'Project', None)
+
+        project = doc.documentElement
+        project.setAttribute('xmlns', MSBUILD_NAMESPACE)
+        project.setAttribute('ToolsVersion', '4.0')
+
+        ig = project.appendChild(doc.createElement('ImportGroup'))
+        ig.setAttribute('Label', 'PropertySheets')
+
+        pg = project.appendChild(doc.createElement('PropertyGroup'))
+        pg.setAttribute('Label', 'UserMacros')
+
+        ig = project.appendChild(doc.createElement('ItemGroup'))
+
+        def add_var(k, v):
+            e = pg.appendChild(doc.createElement(k))
+            e.appendChild(doc.createTextNode(v))
+
+            e = ig.appendChild(doc.createElement('BuildMacro'))
+            e.setAttribute('Include', k)
+
+            e = e.appendChild(doc.createElement('Value'))
+            e.appendChild(doc.createTextNode('$(%s)' % k))
+
+        add_var('TopObjDir', os.path.normpath(self.environment.topobjdir))
+        add_var('TopSrcDir', os.path.normpath(self.environment.topsrcdir))
+        add_var('PYTHON', '$(TopObjDir)\\_virtualenv\\Scripts\\python.exe')
+        add_var('MACH', '$(TopSrcDir)\\mach')
+
+        # From MozillaBuild.
+        add_var('DefaultIncludes', os.environ.get('INCLUDE', ''))
+
+        fh.write(b'\xef\xbb\xbf')
+        doc.writexml(fh, addindent='  ', newl='\r\n')
+
+    def _relevant_environment_variables(self):
+        # Write out the environment variables, presumably coming from
+        # MozillaBuild.
+        for k, v in sorted(os.environ.items()):
+            if not re.match('^[a-zA-Z0-9_]+$', k):
+                continue
+
+            if k in ('OLDPWD', 'PS1'):
+                continue
+
+            if k.startswith('_'):
+                continue
+
+            yield k, v
+
+        yield 'TOPSRCDIR', self.environment.topsrcdir
+        yield 'TOPOBJDIR', self.environment.topobjdir
+
+    def _write_mach_powershell(self, fh):
+        for k, v in self._relevant_environment_variables():
+            fh.write(b'$env:%s = "%s"\r\n' % (k, v))
+
+        relpath = os.path.relpath(self.environment.topsrcdir,
+            self.environment.topobjdir).replace('\\', '/')
+
+        fh.write(b'$bashargs = "%s/mach", "--log-no-times"\r\n' % relpath)
+        fh.write(b'$bashargs = $bashargs + $args\r\n')
+
+        fh.write(b"$expanded = $bashargs -join ' '\r\n")
+        fh.write(b'$procargs = "-c", $expanded\r\n')
+
+        fh.write(b'Start-Process -WorkingDirectory $env:TOPOBJDIR '
+            b'-FilePath $env:MOZILLABUILD\\msys\\bin\\bash '
+            b'-ArgumentList $procargs '
+            b'-Wait -NoNewWindow\r\n')
+
+    def _write_mach_batch(self, fh):
+        """Write out a batch script that builds the tree.
+
+        The script "bootstraps" into the MozillaBuild environment by setting
+        the environment variables that are active in the current MozillaBuild
+        environment. Then, it builds the tree.
+        """
+        for k, v in self._relevant_environment_variables():
+            fh.write(b'SET "%s=%s"\r\n' % (k, v))
+
+        fh.write(b'cd %TOPOBJDIR%\r\n')
+
+        # We need to convert Windows-native paths to msys paths. Easiest way is
+        # relative paths, since munging c:\ to /c/ is slightly more
+        # complicated.
+        relpath = os.path.relpath(self.environment.topsrcdir,
+            self.environment.topobjdir).replace('\\', '/')
+
+        # We go through mach because it has the logic for choosing the most
+        # appropriate build tool.
+        fh.write(b'"%%MOZILLABUILD%%\\msys\\bin\\bash" '
+            b'-c "%s/mach --log-no-times %%1 %%2 %%3 %%4 %%5 %%6 %%7"' % relpath)
+
+    def _write_vs_project(self, out_dir, basename, name, **kwargs):
+        root = '%s.vcxproj' % basename
+        with open(os.path.join(out_dir, root), 'wb') as fh:
+            project_id, name = VisualStudioBackend.write_vs_project(fh,
+                self._version, name, **kwargs)
+
+        with open(os.path.join(out_dir, '%s.user' % root), 'w') as fh:
+            fh.write('<?xml version="1.0" encoding="utf-8"?>\r\n')
+            fh.write('<Project ToolsVersion="4.0" xmlns="%s">\r\n' %
+                MSBUILD_NAMESPACE)
+            fh.write('</Project>\r\n')
+
+        return project_id
+
+    @staticmethod
+    def write_vs_project(fh, version, name, includes=[],
+        forced_includes=[], defines=[],
+        build_command=None, clean_command=None,
+        debugger=None, headers=[], sources=[]):
+
+        project_id = get_id(name.encode('utf-8'))
+
+        impl = getDOMImplementation()
+        doc = impl.createDocument(MSBUILD_NAMESPACE, 'Project', None)
+
+        project = doc.documentElement
+        project.setAttribute('DefaultTargets', 'Build')
+        project.setAttribute('ToolsVersion', '4.0')
+        project.setAttribute('xmlns', MSBUILD_NAMESPACE)
+
+        ig = project.appendChild(doc.createElement('ItemGroup'))
+        ig.setAttribute('Label', 'ProjectConfigurations')
+
+        pc = ig.appendChild(doc.createElement('ProjectConfiguration'))
+        pc.setAttribute('Include', 'Build|Win32')
+
+        c = pc.appendChild(doc.createElement('Configuration'))
+        c.appendChild(doc.createTextNode('Build'))
+
+        p = pc.appendChild(doc.createElement('Platform'))
+        p.appendChild(doc.createTextNode('Win32'))
+
+        pg = project.appendChild(doc.createElement('PropertyGroup'))
+        pg.setAttribute('Label', 'Globals')
+
+        n = pg.appendChild(doc.createElement('ProjectName'))
+        n.appendChild(doc.createTextNode(name))
+
+        k = pg.appendChild(doc.createElement('Keyword'))
+        k.appendChild(doc.createTextNode('MakeFileProj'))
+
+        g = pg.appendChild(doc.createElement('ProjectGuid'))
+        g.appendChild(doc.createTextNode('{%s}' % project_id))
+
+        rn = pg.appendChild(doc.createElement('RootNamespace'))
+        rn.appendChild(doc.createTextNode('mozilla'))
+
+        i = project.appendChild(doc.createElement('Import'))
+        i.setAttribute('Project', '$(VCTargetsPath)\\Microsoft.Cpp.Default.props')
+
+        ig = project.appendChild(doc.createElement('ImportGroup'))
+        ig.setAttribute('Label', 'ExtensionTargets')
+
+        ig = project.appendChild(doc.createElement('ImportGroup'))
+        ig.setAttribute('Label', 'ExtensionSettings')
+
+        ig = project.appendChild(doc.createElement('ImportGroup'))
+        ig.setAttribute('Label', 'PropertySheets')
+        i = ig.appendChild(doc.createElement('Import'))
+        i.setAttribute('Project', 'mozilla.props')
+
+        pg = project.appendChild(doc.createElement('PropertyGroup'))
+        pg.setAttribute('Label', 'Configuration')
+        ct = pg.appendChild(doc.createElement('ConfigurationType'))
+        ct.appendChild(doc.createTextNode('Makefile'))
+
+        pg = project.appendChild(doc.createElement('PropertyGroup'))
+        pg.setAttribute('Condition', "'$(Configuration)|$(Platform)'=='Build|Win32'")
+
+        if build_command:
+            n = pg.appendChild(doc.createElement('NMakeBuildCommandLine'))
+            n.appendChild(doc.createTextNode(build_command))
+
+        if clean_command:
+            n = pg.appendChild(doc.createElement('NMakeCleanCommandLine'))
+            n.appendChild(doc.createTextNode(clean_command))
+
+        if includes:
+            n = pg.appendChild(doc.createElement('NMakeIncludeSearchPath'))
+            n.appendChild(doc.createTextNode(';'.join(includes)))
+
+        if forced_includes:
+            n = pg.appendChild(doc.createElement('NMakeForcedIncludes'))
+            n.appendChild(doc.createTextNode(';'.join(forced_includes)))
+
+        if defines:
+            n = pg.appendChild(doc.createElement('NMakePreprocessorDefinitions'))
+            n.appendChild(doc.createTextNode(';'.join(defines)))
+
+        if debugger:
+            n = pg.appendChild(doc.createElement('LocalDebuggerCommand'))
+            n.appendChild(doc.createTextNode(debugger[0]))
+
+            n = pg.appendChild(doc.createElement('LocalDebuggerCommandArguments'))
+            n.appendChild(doc.createTextNode(debugger[1]))
+
+        i = project.appendChild(doc.createElement('Import'))
+        i.setAttribute('Project', '$(VCTargetsPath)\\Microsoft.Cpp.props')
+
+        i = project.appendChild(doc.createElement('Import'))
+        i.setAttribute('Project', '$(VCTargetsPath)\\Microsoft.Cpp.targets')
+
+        # Now add files to the project.
+        ig = project.appendChild(doc.createElement('ItemGroup'))
+        for header in sorted(headers or []):
+            n = ig.appendChild(doc.createElement('ClInclude'))
+            n.setAttribute('Include', header)
+
+        ig = project.appendChild(doc.createElement('ItemGroup'))
+        for source in sorted(sources or []):
+            n = ig.appendChild(doc.createElement('ClCompile'))
+            n.setAttribute('Include', source)
+
+        fh.write(b'\xef\xbb\xbf')
+        doc.writexml(fh, addindent='  ', newl='\r\n')
+
+        return project_id, name
--- a/python/mozbuild/mozbuild/config_status.py
+++ b/python/mozbuild/mozbuild/config_status.py
@@ -11,17 +11,16 @@ from __future__ import print_function
 import logging
 import os
 import sys
 
 from optparse import OptionParser
 
 from mach.logging import LoggingManager
 from mozbuild.backend.configenvironment import ConfigEnvironment
-from mozbuild.backend.android_eclipse import AndroidEclipseBackend
 from mozbuild.backend.recursivemake import RecursiveMakeBackend
 from mozbuild.base import MachCommandConditions
 from mozbuild.frontend.emitter import TreeMetadataEmitter
 from mozbuild.frontend.reader import BuildReader
 from mozbuild.mozinfo import write_mozinfo
 
 
 log_manager = LoggingManager()
@@ -35,16 +34,29 @@ You are building Firefox for Android. Yo
 `mach build-backend --backend=AndroidEclipse`
 to generate Eclipse project files.
 
 PLEASE BE AWARE THAT ECLIPSE SUPPORT IS EXPERIMENTAL. You should
 verify any changes using |mach build|.
 =============
 '''.strip()
 
+VISUAL_STUDIO_ADVERTISEMENT = '''
+===============================
+Visual Studio Support Available
+
+You are building Firefox on Windows. Please help us test the experimental
+Visual Studio project files (yes, IntelliSense works) by running the
+following:
+
+   mach build-backend --backend=VisualStudio
+
+===============================
+'''.strip()
+
 
 def config_status(topobjdir='.', topsrcdir='.',
         defines=[], non_global_defines=[], substs=[], source=None):
     '''Main function, providing config.status functionality.
 
     Contrary to config.status, it doesn't use CONFIG_FILES or CONFIG_HEADERS
     variables.
 
@@ -78,17 +90,17 @@ def config_status(topobjdir='.', topsrcd
                       help='update config.status by reconfiguring in the same conditions')
     parser.add_option('-v', '--verbose', dest='verbose', action='store_true',
                       help='display verbose output')
     parser.add_option('-n', dest='not_topobjdir', action='store_true',
                       help='do not consider current directory as top object directory')
     parser.add_option('-d', '--diff', action='store_true',
                       help='print diffs of changed files.')
     parser.add_option('-b', '--backend',
-                      choices=['RecursiveMake', 'AndroidEclipse'],
+                      choices=['RecursiveMake', 'AndroidEclipse', 'VisualStudio'],
                       default='RecursiveMake',
                       help='what backend to build (default: RecursiveMake).')
     options, args = parser.parse_args()
 
     # Without -n, the current directory is meant to be the top object directory
     if not options.not_topobjdir:
         topobjdir = os.path.abspath('.')
 
@@ -98,19 +110,23 @@ def config_status(topobjdir='.', topsrcd
     # mozinfo.json only needs written if configure changes and configure always
     # passes this environment variable.
     if 'WRITE_MOZINFO' in os.environ:
         write_mozinfo(os.path.join(topobjdir, 'mozinfo.json'), env, os.environ)
 
     # Make an appropriate backend instance, defaulting to RecursiveMakeBackend.
     backend_cls = RecursiveMakeBackend
     if options.backend == 'AndroidEclipse':
+        from mozbuild.backend.android_eclipse import AndroidEclipseBackend
         if not MachCommandConditions.is_android(env):
             raise Exception('The Android Eclipse backend is not available with this configuration.')
         backend_cls = AndroidEclipseBackend
+    elif options.backend == 'VisualStudio':
+        from mozbuild.backend.visualstudio import VisualStudioBackend
+        backend_cls = VisualStudioBackend
 
     the_backend = backend_cls(env)
 
     reader = BuildReader(env)
     emitter = TreeMetadataEmitter(env)
     # This won't actually do anything because of the magic of generators.
     definitions = emitter.emit(reader.read_topsrcdir())
 
@@ -128,12 +144,16 @@ def config_status(topobjdir='.', topsrcd
 
     for line in summary.summaries():
         print(line, file=sys.stderr)
 
     if options.diff:
         for path, diff in sorted(summary.file_diffs.items()):
             print(diff)
 
+    # Advertise Visual Studio if appropriate.
+    if os.name == 'nt' and options.backend == 'RecursiveMake':
+        print(VISUAL_STUDIO_ADVERTISEMENT)
+
     # Advertise Eclipse if it is appropriate.
     if MachCommandConditions.is_android(env):
         if options.backend == 'RecursiveMake':
             print(ANDROID_ECLIPSE_ADVERTISEMENT)
--- a/python/mozbuild/mozbuild/frontend/emitter.py
+++ b/python/mozbuild/mozbuild/frontend/emitter.py
@@ -237,16 +237,19 @@ class TreeMetadataEmitter(LoggingMixin):
             'LIBXUL_LIBRARY',
             'MSVC_ENABLE_PGO',
             'NO_DIST_INSTALL',
             'OS_LIBS',
             'RCFILE',
             'RESFILE',
             'DEFFILE',
             'SDK_LIBRARY',
+            'CFLAGS',
+            'CXXFLAGS',
+            'LDFLAGS',
         ]
         for v in varlist:
             if v in sandbox and sandbox[v]:
                 passthru.variables[v] = sandbox[v]
 
         # NO_VISIBILITY_FLAGS is slightly different
         if sandbox['NO_VISIBILITY_FLAGS']:
             passthru.variables['VISIBILITY_FLAGS'] = ''
--- a/python/mozbuild/mozbuild/frontend/sandbox_symbols.py
+++ b/python/mozbuild/mozbuild/frontend/sandbox_symbols.py
@@ -678,16 +678,43 @@ VARIABLES = {
         Keys are relative directories inside the final Sphinx documentation
         tree to install files into. Values are directories (relative to this
         file) whose content to copy into the Sphinx documentation tree.
         """, None),
 
     'SPHINX_PYTHON_PACKAGE_DIRS': (StrictOrderingOnAppendList, list,
         """Directories containing Python packages that Sphinx documents.
         """, None),
+
+    'CFLAGS': (list, list,
+        """Flags passed to the C compiler for all of the C source files
+           declared in this directory.
+
+           Note that the ordering of flags matter here, these flags will be
+           added to the compiler's command line in the same order as they
+           appear in the moz.build file.
+        """, 'binaries'),
+
+    'CXXFLAGS': (list, list,
+        """Flags passed to the C++ compiler for all of the C++ source files
+           declared in this directory.
+
+           Note that the ordering of flags matter here, these flags will be
+           added to the compiler's command line in the same order as they
+           appear in the moz.build file.
+        """, 'binaries'),
+
+    'LDFLAGS': (list, list,
+        """Flags passed to the linker when linking all of the libraries and
+           executables declared in this directory.
+
+           Note that the ordering of flags matter here, these flags will be
+           added to the linker's command line in the same order as they
+           appear in the moz.build file.
+        """, 'libs'),
 }
 
 # The set of functions exposed to the sandbox.
 #
 # Each entry is a tuple of:
 #
 #  (method attribute, (argument types), docs)
 #
--- a/python/mozbuild/mozbuild/mach_commands.py
+++ b/python/mozbuild/mozbuild/mach_commands.py
@@ -526,17 +526,17 @@ class Build(MachCommandBase):
 
     @Command('build-backend', category='build',
         description='Generate a backend used to build the tree.')
     @CommandArgument('-d', '--diff', action='store_true',
         help='Show a diff of changes.')
     # It would be nice to filter the choices below based on
     # conditions, but that is for another day.
     @CommandArgument('-b', '--backend',
-        choices=['RecursiveMake', 'AndroidEclipse'],
+        choices=['RecursiveMake', 'AndroidEclipse', 'VisualStudio'],
         default='RecursiveMake',
         help='Which backend to build (default: RecursiveMake).')
     def build_backend(self, backend='RecursiveMake', diff=False):
         python = self.virtualenv_manager.python_path
         config_status = os.path.join(self.topobjdir, 'config.status')
 
         args = [python, config_status, '--backend=%s' % backend]
         if diff:
--- a/python/mozbuild/mozbuild/test/backend/common.py
+++ b/python/mozbuild/mozbuild/test/backend/common.py
@@ -56,16 +56,23 @@ CONFIGS = DefaultOnReadDict({
             ('foo', 'baz qux'),
             ('baz', 1)
         ],
         'non_global_defines': [],
         'substs': [
             ('foo', 'bar baz'),
         ],
     },
+    'visual-studio': {
+        'defines': [],
+        'non_global_defines': [],
+        'substs': [
+            ('MOZ_APP_NAME', 'my_app'),
+        ],
+    },
 }, global_default={
     'defines': [],
     'non_global_defines': [],
     'substs': [],
 })
 
 
 class BackendTester(unittest.TestCase):
--- a/python/mozbuild/mozbuild/test/backend/data/variable_passthru/moz.build
+++ b/python/mozbuild/mozbuild/test/backend/data/variable_passthru/moz.build
@@ -36,8 +36,12 @@ NO_VISIBILITY_FLAGS = True
 
 DELAYLOAD_DLLS = ['foo.dll', 'bar.dll']
 
 RCFILE = 'foo.rc'
 RESFILE = 'bar.res'
 DEFFILE = 'baz.def'
 
 USE_STATIC_LIBS = True
+
+CFLAGS += ['-fno-exceptions', '-w']
+CXXFLAGS += ['-fcxx-exceptions', '-include foo.h']
+LDFLAGS += ['-framework Foo', '-x']
new file mode 100644
new file mode 100644
new file mode 100644
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/backend/data/visual-studio/dir1/moz.build
@@ -0,0 +1,9 @@
+# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
+# Any copyright is dedicated to the Public Domain.
+# http://creativecommons.org/publicdomain/zero/1.0/
+
+FINAL_LIBRARY = 'test'
+SOURCES += ['bar.cpp', 'foo.cpp']
+LOCAL_INCLUDES += ['/includeA/foo']
+DEFINES['DEFINEFOO'] = True
+DEFINES['DEFINEBAR'] = 'bar'
new file mode 100644
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/backend/data/visual-studio/moz.build
@@ -0,0 +1,7 @@
+# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
+# Any copyright is dedicated to the Public Domain.
+# http://creativecommons.org/publicdomain/zero/1.0/
+
+add_tier_dir('libs', ['dir1'])
+
+LIBRARY_NAME = 'test'
--- a/python/mozbuild/mozbuild/test/backend/test_recursivemake.py
+++ b/python/mozbuild/mozbuild/test/backend/test_recursivemake.py
@@ -335,16 +335,28 @@ class TestRecursiveMakeBackend(BackendTe
                 'RESFILE := bar.res',
             ],
             'DEFFILE': [
                 'DEFFILE := baz.def',
             ],
             'USE_STATIC_LIBS': [
                 'USE_STATIC_LIBS := 1',
             ],
+            'CFLAGS': [
+                'CFLAGS += -fno-exceptions',
+                'CFLAGS += -w',
+            ],
+            'CXXFLAGS': [
+                'CXXFLAGS += -fcxx-exceptions',
+                'CXXFLAGS += -include foo.h',
+            ],
+            'LDFLAGS': [
+                'LDFLAGS += -framework Foo',
+                'LDFLAGS += -x',
+            ]
         }
 
         for var, val in expected.items():
             # print("test_variable_passthru[%s]" % (var))
             found = [str for str in lines if str.startswith(var)]
             self.assertEqual(found, val)
 
     def test_exports(self):
new file mode 100644
--- /dev/null
+++ b/python/mozbuild/mozbuild/test/backend/test_visualstudio.py
@@ -0,0 +1,64 @@
+# 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/.
+
+from __future__ import unicode_literals
+
+from xml.dom.minidom import parse
+import os
+import unittest
+
+from mozbuild.backend.visualstudio import VisualStudioBackend
+from mozbuild.test.backend.common import BackendTester
+
+from mozunit import main
+
+
+class TestVisualStudioBackend(BackendTester):
+    @unittest.skip('Failing inconsistently in automation.')
+    def test_basic(self):
+        """Ensure we can consume our stub project."""
+
+        env = self._consume('visual-studio', VisualStudioBackend)
+
+        msvc = os.path.join(env.topobjdir, 'msvc')
+        self.assertTrue(os.path.isdir(msvc))
+
+        self.assertTrue(os.path.isfile(os.path.join(msvc, 'mozilla.sln')))
+        self.assertTrue(os.path.isfile(os.path.join(msvc, 'mozilla.props')))
+        self.assertTrue(os.path.isfile(os.path.join(msvc, 'mach.bat')))
+        self.assertTrue(os.path.isfile(os.path.join(msvc, 'binary_my_app.vcxproj')))
+        self.assertTrue(os.path.isfile(os.path.join(msvc, 'target_full.vcxproj')))
+        self.assertTrue(os.path.isfile(os.path.join(msvc, 'library_dir1.vcxproj')))
+        self.assertTrue(os.path.isfile(os.path.join(msvc, 'library_dir1.vcxproj.user')))
+
+        d = parse(os.path.join(msvc, 'library_dir1.vcxproj'))
+        self.assertEqual(d.documentElement.tagName, 'Project')
+        els = d.getElementsByTagName('ClCompile')
+        self.assertEqual(len(els), 2)
+
+        # mozilla-config.h should be explicitly listed as an include.
+        els = d.getElementsByTagName('NMakeForcedIncludes')
+        self.assertEqual(len(els), 1)
+        self.assertEqual(els[0].firstChild.nodeValue,
+            '$(TopObjDir)\\dist\\include\\mozilla-config.h')
+
+        # LOCAL_INCLUDES get added to the include search path.
+        els = d.getElementsByTagName('NMakeIncludeSearchPath')
+        self.assertEqual(len(els), 1)
+        includes = els[0].firstChild.nodeValue.split(';')
+        self.assertIn(os.path.normpath('$(TopSrcDir)/includeA/foo'), includes)
+        self.assertIn(os.path.normpath('$(TopSrcDir)/dir1'), includes)
+        self.assertIn(os.path.normpath('$(TopObjDir)/dir1'), includes)
+        self.assertIn(os.path.normpath('$(TopObjDir)\\dist\\include'), includes)
+
+        # DEFINES get added to the project.
+        els = d.getElementsByTagName('NMakePreprocessorDefinitions')
+        self.assertEqual(len(els), 1)
+        defines = els[0].firstChild.nodeValue.split(';')
+        self.assertIn('DEFINEFOO', defines)
+        self.assertIn('DEFINEBAR=bar', defines)
+
+
+if __name__ == '__main__':
+    main()
--- a/python/mozbuild/mozbuild/test/frontend/data/variable-passthru/moz.build
+++ b/python/mozbuild/mozbuild/test/frontend/data/variable-passthru/moz.build
@@ -42,8 +42,12 @@ NO_VISIBILITY_FLAGS = True
 
 DELAYLOAD_DLLS = ['foo.dll', 'bar.dll']
 
 RCFILE = 'foo.rc'
 RESFILE = 'bar.res'
 DEFFILE = 'baz.def'
 
 USE_STATIC_LIBS = True
+
+CFLAGS += ['-fno-exceptions', '-w']
+CXXFLAGS += ['-fcxx-exceptions', '-include foo.h']
+LDFLAGS += ['-framework Foo', '-x']
--- a/python/mozbuild/mozbuild/test/frontend/test_emitter.py
+++ b/python/mozbuild/mozbuild/test/frontend/test_emitter.py
@@ -171,16 +171,19 @@ class TestEmitterBasic(unittest.TestCase
             SSRCS=['bans.S', 'fans.S'],
             VISIBILITY_FLAGS='',
             DELAYLOAD_LDFLAGS=['-DELAYLOAD:foo.dll', '-DELAYLOAD:bar.dll'],
             USE_DELAYIMP=True,
             RCFILE='foo.rc',
             RESFILE='bar.res',
             DEFFILE='baz.def',
             USE_STATIC_LIBS=True,
+            CFLAGS=['-fno-exceptions', '-w'],
+            CXXFLAGS=['-fcxx-exceptions', '-include foo.h'],
+            LDFLAGS=['-framework Foo', '-x'],
         )
 
         variables = objs[0].variables
         maxDiff = self.maxDiff
         self.maxDiff = None
         self.assertEqual(wanted, variables)
         self.maxDiff = maxDiff
 
--- a/testing/profiles/prefs_general.js
+++ b/testing/profiles/prefs_general.js
@@ -154,8 +154,12 @@ user_pref("browser.download.panel.shown"
 // Disable first-tun tab
 user_pref("browser.firstrun.count", 0);
 
 // Enable webapps testing mode, which bypasses native installation.
 user_pref("browser.webapps.testing", true);
 
 // Disable android snippets
 user_pref("browser.snippets.enabled", false);
+
+
+// Do not turn HTTP cache v2 for our infra tests (some tests are failing)
+user_pref("browser.cache.use_new_backend_temp", false);
new file mode 100644
--- /dev/null
+++ b/toolkit/mozapps/extensions/Makefile.in
@@ -0,0 +1,9 @@
+# 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/.
+
+# Additional debugging info is exposed by setting the MOZ_EM_DEBUG
+# environment variable when building.
+ifneq (,$(MOZ_EM_DEBUG))
+DEFINES += -DMOZ_EM_DEBUG=1
+endif
--- a/toolkit/mozapps/extensions/moz.build
+++ b/toolkit/mozapps/extensions/moz.build
@@ -48,12 +48,12 @@ EXTRA_PP_JS_MODULES += [
 if CONFIG['MOZ_UPDATE_CHANNEL'] not in ('aurora', 'beta', 'release', 'esr'):
     DEFINES['MOZ_COMPATIBILITY_NIGHTLY'] = 1
 
 # This is used in multiple places, so is defined here to avoid it getting
 # out of sync.
 DEFINES['MOZ_EXTENSIONS_DB_SCHEMA'] = 16
 
 # Additional debugging info is exposed in debug builds
-if CONFIG['MOZ_EM_DEBUG']:
+if CONFIG['MOZ_DEBUG']:
     DEFINES['MOZ_EM_DEBUG'] = 1
 
-JAR_MANIFESTS += ['jar.mn']
+JAR_MANIFESTS += ['jar.mn']
\ No newline at end of file
--- a/xpcom/reflect/xptcall/src/md/unix/Makefile.in
+++ b/xpcom/reflect/xptcall/src/md/unix/Makefile.in
@@ -10,16 +10,19 @@
 # Linux/ARM
 #
 ifeq ($(OS_ARCH),Linux)
 ifneq (,$(filter arm% sa110,$(OS_TEST)))
 CXXFLAGS += -O2
 endif
 endif
 
+ifeq ($(OS_TEST),aarch64)
+ASFILES := xptcinvoke_asm_aarch64.s xptcstubs_asm_aarch64.s
+endif
 ######################################################################
 # HPPA
 ######################################################################
 #
 # HP-UX/PA32
 #
 # for gas and gcc, check comment in xptcinvoke_asm_pa32.s
 ifeq ($(OS_ARCH),HP-UX)
--- a/xpcom/reflect/xptcall/src/md/unix/moz.build
+++ b/xpcom/reflect/xptcall/src/md/unix/moz.build
@@ -144,16 +144,21 @@ if CONFIG['OS_ARCH'] == 'NetBSD':
     if CONFIG['OS_TEST'] in ('amiga', 'atari', 'hp300', 'mac68k', 'mvme68k',
                              'next68k', 'sun3', 'sun3x', 'x68k'):
         SOURCES += [
             'xptcinvoke_netbsd_m68k.cpp',
             'xptcstubs_netbsd_m68k.cpp'
         ]
 
 if CONFIG['OS_ARCH'] == 'Linux':
+    if CONFIG['OS_TEST'] == 'aarch64':
+        SOURCES += [
+            'xptcinvoke_aarch64.cpp',
+            'xptcstubs_aarch64.cpp',
+        ]
     if CONFIG['OS_TEST'] == 'm68k':
         SOURCES += [
             'xptcinvoke_linux_m68k.cpp',
             'xptcstubs_linux_m68k.cpp',
         ]
     if CONFIG['OS_TEST'].find('mips') != -1:
         if CONFIG['OS_TEST'].find('mips64') != -1:
             SOURCES += [