Merge m-i to m-c
authorPhil Ringnalda <philringnalda@gmail.com>
Sun, 22 Sep 2013 09:13:14 -0700
changeset 148216 f97307cb4c957a69271657a3c3c6ef3797814768
parent 148190 314f6d5d53f5a527fe915504b05a92a8948ac6e3 (current diff)
parent 148215 07a7fefec7cb8fc9b429df879e322c54371338bc (diff)
child 148217 879cf32d8a6f59a895a05372a6df0f8bbb5601fd
child 148261 41047800c65ce71666af17a284b9fb62f9a60432
child 148266 6f76fe060186af7fa4919029565f867b19ed5413
push id25330
push userphilringnalda@gmail.com
push dateSun, 22 Sep 2013 16:14:09 +0000
treeherdermozilla-central@f97307cb4c95 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone27.0a1
first release with
nightly linux32
f97307cb4c95 / 27.0a1 / 20130923030204 / files
nightly linux64
f97307cb4c95 / 27.0a1 / 20130923030204 / files
nightly mac
f97307cb4c95 / 27.0a1 / 20130923030204 / files
nightly win32
f97307cb4c95 / 27.0a1 / 20130923030204 / files
nightly win64
f97307cb4c95 / 27.0a1 / 20130923030204 / files
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
releases
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge m-i to m-c
build/virtualenv/packages.txt
build/virtualenv/populate_virtualenv.py
python/mozbuild/README.rst
python/mozbuild/dumbmake/README.rst
python/mozbuild/mozbuild/frontend/README.rst
--- a/browser/installer/package-manifest.in
+++ b/browser/installer/package-manifest.in
@@ -793,8 +793,12 @@ bin/libfreebl_32int64_3.so
 @BINPATH@/metro/chrome/@AB_CD@@JAREXT@
 @BINPATH@/metro/chrome/@AB_CD@.manifest
 @BINPATH@/metro/chrome/pdfjs.manifest
 @BINPATH@/metro/chrome/pdfjs/*
 @BINPATH@/metro/components
 @BINPATH@/metro/defaults
 @BINPATH@/metro/modules
 #endif
+
+#ifdef MOZ_ASAN
+@BINPATH@/llvm-symbolizer
+#endif
--- a/build/autoconf/python-virtualenv.m4
+++ b/build/autoconf/python-virtualenv.m4
@@ -19,17 +19,17 @@ fi
 
 _virtualenv_topsrcdir=
 _virtualenv_populate_path=
 
 dnl If this is a mozilla-central, we'll find the virtualenv in the top
 dnl source directory. If this is a SpiderMonkey build, we assume we're at
 dnl js/src and try to find the virtualenv from the mozilla-central root.
 for base in $MOZILLA_CENTRAL_PATH $_topsrcdir $_topsrcdir/../..; do
-  possible=$base/build/virtualenv/populate_virtualenv.py
+  possible=$base/python/mozbuild/mozbuild/virtualenv.py
 
   if test -e $possible; then
     _virtualenv_topsrcdir=$base
     _virtualenv_populate_path=$possible
     break
   fi
 done
 
@@ -48,17 +48,18 @@ mozilla-central and relaunch configure.]
 fi
 
 if test -z $DONT_POPULATE_VIRTUALENV; then
   AC_MSG_RESULT([Creating Python environment])
   dnl This verifies our Python version is sane and ensures the Python
   dnl virtualenv is present and up to date. It sanitizes the environment
   dnl for us, so we don't need to clean anything out.
   $PYTHON $_virtualenv_populate_path \
-    $_virtualenv_topsrcdir $MOZ_BUILD_ROOT $MOZ_BUILD_ROOT/_virtualenv || exit 1
+    $_virtualenv_topsrcdir $MOZ_BUILD_ROOT $MOZ_BUILD_ROOT/_virtualenv \
+    $_virtualenv_topsrcdir/build/virtualenv_packages.txt || exit 1
 
   case "$host_os" in
   mingw*)
     PYTHON=`cd $MOZ_BUILD_ROOT && pwd -W`/_virtualenv/Scripts/python.exe
     ;;
   *)
     PYTHON=$MOZ_BUILD_ROOT/_virtualenv/bin/python
     ;;
--- a/build/automation.py.in
+++ b/build/automation.py.in
@@ -507,16 +507,22 @@ class Automation(object):
     if 'NSPR_LOG_MODULES' not in env:
       env['NSPR_LOG_MODULES'] = 'signaling:5,mtransport:3'
     env['R_LOG_LEVEL'] = '5'
     env['R_LOG_DESTINATION'] = 'stderr'
     env['R_LOG_VERBOSE'] = '1'
 
     # ASan specific environment stuff
     if self.IS_ASAN and (self.IS_LINUX or self.IS_MAC):
+      # Symbolizer support
+      llvmsym = os.path.join(xrePath, "llvm-symbolizer")
+      if os.path.isfile(llvmsym):
+        env["ASAN_SYMBOLIZER_PATH"] = llvmsym
+        self.log.info("INFO | automation.py | ASan using symbolizer at %s", llvmsym)
+
       try:
         totalMemory = int(os.popen("free").readlines()[1].split()[1])
 
         # Only 2 GB RAM or less available? Use custom ASan options to reduce
         # the amount of resources required to do the tests. Standard options 
         # will otherwise lead to OOM conditions on the current test slaves.
         # 
         # If we have more than 2 GB or RAM but still less than 4 GB, we need
new file mode 100644
--- /dev/null
+++ b/build/docs/conf.py
@@ -0,0 +1,49 @@
+# 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
+
+import os
+import re
+
+from datetime import datetime
+
+
+here = os.path.abspath(os.path.dirname(__file__))
+mozilla_dir = os.path.normpath(os.path.join(here, '..', '..'))
+
+import mdn_theme
+
+extensions = [
+    'sphinx.ext.autodoc',
+]
+
+templates_path = ['_templates']
+source_suffix = '.rst'
+master_doc = 'index'
+project = u'Mozilla Build System'
+year = datetime.now().year
+copyright = u'%s, Mozilla Foundation, CC BY-SA 3.0' % year
+
+# Grab the version from the source tree's milestone.
+with open(os.path.join(mozilla_dir, 'config', 'milestone.txt'), 'rt') as fh:
+    for line in fh:
+        line = line.strip()
+
+        if not line or line.startswith('#'):
+            continue
+
+        release = line
+        break
+
+version = re.sub(r'[ab]\d+$', '', release)
+
+exclude_patterns = ['_build']
+pygments_style = 'sphinx'
+
+html_theme_path = [mdn_theme.get_theme_dir()]
+html_theme = 'mdn'
+
+html_static_path = ['_static']
+htmlhelp_basename = 'MozillaBuildSystemdoc'
new file mode 100644
--- /dev/null
+++ b/build/docs/glossary.rst
@@ -0,0 +1,28 @@
+========
+Glossary
+========
+
+.. glossary::
+   :sorted:
+
+   object directory
+       A directory holding the output of the build system. The build
+       system attempts to isolate all file modifications to this
+       directory. By convention, object directories are commonly
+       directories under the source directory prefixed with **obj-**.
+       e.g. **obj-firefox**.
+
+   mozconfig
+       A shell script used to configure the build system.
+
+   configure
+       A generated shell script which detects the current system
+       environment, applies a requested set of build configuration
+       options, and writes out metadata to be consumed by the build
+       system.
+
+   config.status
+       An executable file produced by **configure** that takes the
+       generated build config and writes out files used to build the
+       tree. Traditionally, config.status writes out a bunch of
+       Makefiles.
new file mode 100644
--- /dev/null
+++ b/build/docs/index.rst
@@ -0,0 +1,41 @@
+==================================
+Mozilla Build System Documentation
+==================================
+
+Overview
+========
+
+.. toctree::
+   :maxdepth: 1
+
+   glossary
+
+Important Concepts
+==================
+.. toctree::
+   :maxdepth: 1
+
+   Mozconfig Files <mozconfigs>
+   Profile Guided Optimization <pgo>
+
+mozbuild
+========
+
+mozbuild is a Python package containing a lot of the code for the
+Mozilla build system.
+
+.. toctree::
+   :maxdepth: 1
+
+   mozbuild/index
+   mozbuild/frontend
+   mozbuild/dumbmake
+
+
+Indices and tables
+==================
+
+* :ref:`genindex`
+* :ref:`modindex`
+* :ref:`search`
+
rename from python/mozbuild/dumbmake/README.rst
rename to build/docs/mozbuild/dumbmake.rst
rename from python/mozbuild/mozbuild/frontend/README.rst
rename to build/docs/mozbuild/frontend.rst
rename from python/mozbuild/README.rst
rename to build/docs/mozbuild/index.rst
new file mode 100644
--- /dev/null
+++ b/build/docs/mozconfigs.rst
@@ -0,0 +1,68 @@
+===============
+mozconfig Files
+===============
+
+mozconfig files are used to configure how a build works.
+
+mozconfig files are actually shell scripts. They are executed in a
+special context with specific variables and functions exposed to them.
+
+API
+===
+
+Functions
+---------
+
+The following special functions are available to a mozconfig script.
+
+ac_add_options
+^^^^^^^^^^^^^^
+
+This function is used to declare extra options/arguments to pass into
+configure.
+
+e.g.::
+
+    ac_add_options --disable-tests
+    ac_add_options --enable-optimize
+
+mk_add_options
+^^^^^^^^^^^^^^
+
+This function is used to inject statements into client.mk for execution.
+It is typically used to define variables, notably the object directory.
+
+e.g.::
+
+    mk_add_options AUTOCLOBBER=1
+
+ac_add_options
+^^^^^^^^^^^^^^
+
+This is a variant of ac_add_options() which only adds configure options
+for a specified application. This is only used when building multiple
+applications through client.mk. This function is typically not needed.
+
+Special mk_add_options Variables
+--------------------------------
+
+For historical reasons, the method for communicating certain
+well-defined variables is via mk_add_options(). In this section, we
+document what those special variables are.
+
+MOZ_OBJDIR
+^^^^^^^^^^
+
+This variable is used to define the :term:`object directory` for the current
+build.
+
+Finding the active mozconfig
+============================
+
+Multiple mozconfig files can exist to provide different configuration
+options for different tasks. The rules for finding the active mozconfig
+are defined in the
+:py:func:`mozbuild.mozconfig.MozconfigLoader.find_mozconfig` method:
+
+.. autoclass:: mozbuild.mozconfig.MozconfigLoader
+   :members: find_mozconfig
new file mode 100644
--- /dev/null
+++ b/build/docs/pgo.rst
@@ -0,0 +1,40 @@
+.. _pgo:
+
+===========================
+Profile Guided Optimization
+===========================
+
+:abbr:`PGO (Profile Guided Optimization)` is the process of adding
+probes to a compiled binary, running said binary, then using the
+run-time information to *recompile* the binary to (hopefully) make it
+faster.
+
+How PGO Builds Work
+===================
+
+The supported interface for invoking a PGO build is to evaluate the
+*build* target of client.mk with *MOZ_PGO* defined. e.g.::
+
+    $ make -f client.mk MOZ_PGO=1
+
+This is equivalent to::
+
+    $ make -f client.mk profiledbuild
+
+Which is roughly equivalent to:
+
+#. Perform a build with *MOZ_PROFILE_GENERATE=1* and *MOZ_PGO_INSTRUMENTED=1*
+#. Package with *MOZ_PGO_INSTRUMENTED=1*
+#. Performing a run of the instrumented binaries
+#. $ make maybe_clobber_profiledbuild
+#. Perform a build with *MOZ_PROFILE_USE=1*
+
+Differences between toolchains
+==============================
+
+There are some implementation differences depending on the compiler
+toolchain being used.
+
+The *maybe_clobber_profiledbuild* step gets its name because of a
+difference. On Windows, this step merely moves some *.pgc* files around.
+Using GCC or Clang, it is equivalent to a *make clean*.
--- a/build/unix/Makefile.in
+++ b/build/unix/Makefile.in
@@ -1,14 +1,22 @@
 # -*- makefile -*-
 #
 # 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/.
 
 SDK_BINARY = run-mozilla.sh
 
+ifneq ($(LLVM_SYMBOLIZER),)
+# Install a copy of the llvm-symbolizer binary to dist/bin, so it can
+# be used for symbolizing traces for e.g. AddressSanitizer
+LLVMSYM_EXECUTABLES=$(LLVM_SYMBOLIZER)
+LLVMSYM_DEST=$(FINAL_TARGET)
+INSTALL_TARGETS += LLVMSYM
+endif
+
 include $(topsrcdir)/config/rules.mk
 
 libs:: $(srcdir)/run-mozilla.sh
 	$(INSTALL) $< $(DIST)/bin
 
 # EOF
--- a/build/unix/mozconfig.asan
+++ b/build/unix/mozconfig.asan
@@ -1,13 +1,14 @@
 . "$topsrcdir/build/mozconfig.common"
 
 # Use Clang as specified in manifest
 export CC="$topsrcdir/clang/bin/clang -fgnu89-inline"
 export CXX="$topsrcdir/clang/bin/clang++"
+export LLVM_SYMBOLIZER="$topsrcdir/clang/bin/llvm-symbolizer"
 
 # Mandatory flags for ASan
 export ASANFLAGS="-fsanitize=address -Dxmalloc=myxmalloc -fPIC"
 export CFLAGS="$ASANFLAGS"
 export CXXFLAGS="$ASANFLAGS"
 export LDFLAGS="-fsanitize=address"
 
 # Enable ASan specific code and build workarounds
rename from build/virtualenv/packages.txt
rename to build/virtualenv_packages.txt
--- a/client.mk
+++ b/client.mk
@@ -320,18 +320,18 @@ EXTRA_CONFIG_DEPS := \
 CONFIG_STATUS_DEPS := \
   $(wildcard $(TOPSRCDIR)/*/confvars.sh) \
   $(CONFIGURES) \
   $(TOPSRCDIR)/CLOBBER \
   $(TOPSRCDIR)/nsprpub/configure \
   $(TOPSRCDIR)/config/milestone.txt \
   $(TOPSRCDIR)/js/src/config/milestone.txt \
   $(TOPSRCDIR)/browser/config/version.txt \
-  $(TOPSRCDIR)/build/virtualenv/packages.txt \
-  $(TOPSRCDIR)/build/virtualenv/populate_virtualenv.py \
+  $(TOPSRCDIR)/build/virtualenv_packages.txt \
+  $(TOPSRCDIR)/python/mozbuild/mozbuild/virtualenv.py \
   $(TOPSRCDIR)/testing/mozbase/packages.txt \
   $(NULL)
 
 CONFIGURE_ENV_ARGS += \
   MAKE="$(MAKE)" \
   $(NULL)
 
 # configure uses the program name to determine @srcdir@. Calling it without
--- a/configure.in
+++ b/configure.in
@@ -1207,18 +1207,20 @@ dnl = Use Address Sanitizer
 dnl ========================================================
 MOZ_ARG_ENABLE_BOOL(address-sanitizer,
 [  --enable-address-sanitizer       Enable Address Sanitizer (default=no)],
     MOZ_ASAN=1,
     MOZ_ASAN= )
 if test -n "$MOZ_ASAN"; then
     MOZ_LLVM_HACKS=1
     AC_DEFINE(MOZ_ASAN)
+    MOZ_PATH_PROG(LLVM_SYMBOLIZER, llvm-symbolizer)
 fi
 AC_SUBST(MOZ_ASAN)
+AC_SUBST(LLVM_SYMBOLIZER)
 
 dnl ========================================================
 dnl = Enable hacks required for LLVM instrumentations
 dnl ========================================================
 MOZ_ARG_ENABLE_BOOL(llvm-hacks,
 [  --enable-llvm-hacks       Enable workarounds required for several LLVM instrumentations (default=no)],
     MOZ_LLVM_HACKS=1,
     MOZ_LLVM_HACKS= )
@@ -1230,17 +1232,22 @@ AC_SUBST(MOZ_NO_WLZDEFS)
 AC_SUBST(MOZ_CFLAGS_NSS)
 
 dnl ========================================================
 dnl GNU specific defaults
 dnl ========================================================
 if test "$GNU_CC"; then
     # Per bug 719659 comment 2, some of the headers on ancient build machines
     # may require gnu89 inline semantics.  But otherwise, we use C99.
-    CFLAGS="$CFLAGS -std=gnu99 -fgnu89-inline"
+    # But on OS X we just use C99 plus GNU extensions, in order to fix
+    # bug 917526.
+    CFLAGS="$CFLAGS -std=gnu99"
+    if test "${OS_ARCH}" != Darwin; then
+        CFLAGS="$CFLAGS -fgnu89-inline"
+    fi
     # FIXME: Let us build with strict aliasing. bug 414641.
     CFLAGS="$CFLAGS -fno-strict-aliasing"
     MKSHLIB='$(CXX) $(CXXFLAGS) $(DSO_PIC_CFLAGS) $(DSO_LDOPTS) -Wl,-h,$(notdir $@) -o $@'
     MKCSHLIB='$(CC) $(CFLAGS) $(DSO_PIC_CFLAGS) $(DSO_LDOPTS) -Wl,-h,$(notdir $@) -o $@'
     DSO_LDOPTS='-shared'
     if test "$GCC_USE_GNU_LD"; then
         # Some tools like ASan use a runtime library that is only
         # linked against executables, so we must allow undefined
--- a/dom/ipc/CrashReporterParent.h
+++ b/dom/ipc/CrashReporterParent.h
@@ -4,16 +4,17 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 #include "mozilla/dom/PCrashReporterParent.h"
 #include "mozilla/dom/TabMessageUtils.h"
 #include "nsXULAppAPI.h"
 #include "nsIFile.h"
 #ifdef MOZ_CRASHREPORTER
 #include "nsExceptionHandler.h"
+#include "nsDataHashtable.h"
 #endif
 
 namespace mozilla {
 namespace dom {
 class ProcessReporter;
 
 class CrashReporterParent :
     public PCrashReporterParent
--- a/js/src/Makefile.in
+++ b/js/src/Makefile.in
@@ -293,21 +293,28 @@ ifeq ($(MOZ_DEBUG),1)
 endif
 
 ifdef MOZ_VALGRIND
 ifndef MOZ_ASAN
 JITTEST_VALGRIND_FLAG = --valgrind
 endif
 endif
 
+ifdef MOZ_ASAN
+ifneq ($(LLVM_SYMBOLIZER),)
+# Use the LLVM symbolizer when running jit-tests under ASan, if available
+JITTEST_ASAN_ENV=ASAN_SYMBOLIZER_PATH='$(LLVM_SYMBOLIZER)'
+endif
+endif
+
 check-style::
 	(cd $(srcdir) && $(PYTHON) config/check_spidermonkey_style.py);
 
 check-jit-test::
-	$(wildcard $(RUN_TEST_PROGRAM)) $(PYTHON) -u $(srcdir)/jit-test/jit_test.py \
+	$(JITTEST_ASAN_ENV) $(wildcard $(RUN_TEST_PROGRAM)) $(PYTHON) -u $(srcdir)/jit-test/jit_test.py \
 	        --no-slow --no-progress --tinderbox --tbpl $(JITTEST_VALGRIND_FLAG) \
 	        $(DIST)/bin/$(JS_SHELL_NAME)$(BIN_SUFFIX)
 
 check:: check-style check-jit-test
 
 # jstests doesn't have a --jitflags option, so we need to loop, updating the
 # exit code (RC) after each invocation.
 # FIXME: MethodJIT doesn't work for 1 test case (bug 644393), so
--- a/js/src/build/autoconf/python-virtualenv.m4
+++ b/js/src/build/autoconf/python-virtualenv.m4
@@ -19,17 +19,17 @@ fi
 
 _virtualenv_topsrcdir=
 _virtualenv_populate_path=
 
 dnl If this is a mozilla-central, we'll find the virtualenv in the top
 dnl source directory. If this is a SpiderMonkey build, we assume we're at
 dnl js/src and try to find the virtualenv from the mozilla-central root.
 for base in $MOZILLA_CENTRAL_PATH $_topsrcdir $_topsrcdir/../..; do
-  possible=$base/build/virtualenv/populate_virtualenv.py
+  possible=$base/python/mozbuild/mozbuild/virtualenv.py
 
   if test -e $possible; then
     _virtualenv_topsrcdir=$base
     _virtualenv_populate_path=$possible
     break
   fi
 done
 
@@ -48,17 +48,18 @@ mozilla-central and relaunch configure.]
 fi
 
 if test -z $DONT_POPULATE_VIRTUALENV; then
   AC_MSG_RESULT([Creating Python environment])
   dnl This verifies our Python version is sane and ensures the Python
   dnl virtualenv is present and up to date. It sanitizes the environment
   dnl for us, so we don't need to clean anything out.
   $PYTHON $_virtualenv_populate_path \
-    $_virtualenv_topsrcdir $MOZ_BUILD_ROOT $MOZ_BUILD_ROOT/_virtualenv || exit 1
+    $_virtualenv_topsrcdir $MOZ_BUILD_ROOT $MOZ_BUILD_ROOT/_virtualenv \
+    $_virtualenv_topsrcdir/build/virtualenv_packages.txt || exit 1
 
   case "$host_os" in
   mingw*)
     PYTHON=`cd $MOZ_BUILD_ROOT && pwd -W`/_virtualenv/Scripts/python.exe
     ;;
   *)
     PYTHON=$MOZ_BUILD_ROOT/_virtualenv/bin/python
     ;;
--- a/js/src/builtin/TypeRepresentation.cpp
+++ b/js/src/builtin/TypeRepresentation.cpp
@@ -255,17 +255,17 @@ StructTypeRepresentation::init(JSContext
     return true;
 }
 
 ///////////////////////////////////////////////////////////////////////////
 // Interning
 
 JSObject *
 TypeRepresentation::addToTableOrFree(JSContext *cx,
-                                     TypeRepresentationSet::AddPtr &p)
+                                     TypeRepresentationHash::AddPtr &p)
 {
     JS_ASSERT(!ownerObject_);
 
     JSCompartment *comp = cx->compartment();
 
     if (!comp->typeReprs.add(p, this)) {
         js_ReportOutOfMemory(cx);
         js_free(this); // do not finalize, not present in the table
@@ -293,17 +293,17 @@ TypeRepresentation::addToTableOrFree(JSC
 /*static*/
 JSObject *
 ScalarTypeRepresentation::Create(JSContext *cx,
                                  ScalarTypeRepresentation::Type type)
 {
     JSCompartment *comp = cx->compartment();
 
     ScalarTypeRepresentation sample(type);
-    TypeRepresentationSet::AddPtr p = comp->typeReprs.lookupForAdd(&sample);
+    TypeRepresentationHash::AddPtr p = comp->typeReprs.lookupForAdd(&sample);
     if (p)
         return (*p)->ownerObject();
 
     // Note: cannot use cx->new_ because constructor is private.
     ScalarTypeRepresentation *ptr =
         (ScalarTypeRepresentation *) cx->malloc_(
             sizeof(ScalarTypeRepresentation));
     if (!ptr)
@@ -327,17 +327,17 @@ ArrayTypeRepresentation::Create(JSContex
     int32_t temp;
     if (!SafeMul(element->size(), length, &temp)) {
         JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
                              JSMSG_TYPEDOBJECT_TOO_BIG);
         return NULL;
     }
 
     ArrayTypeRepresentation sample(element, length);
-    TypeRepresentationSet::AddPtr p = comp->typeReprs.lookupForAdd(&sample);
+    TypeRepresentationHash::AddPtr p = comp->typeReprs.lookupForAdd(&sample);
     if (p)
         return (*p)->ownerObject();
 
     // Note: cannot use cx->new_ because constructor is private.
     ArrayTypeRepresentation *ptr =
         (ArrayTypeRepresentation *) cx->malloc_(
             sizeof(ArrayTypeRepresentation));
     if (!ptr)
@@ -359,17 +359,17 @@ StructTypeRepresentation::Create(JSConte
     // Note: cannot use cx->new_ because constructor is private.
     size_t size = sizeof(StructTypeRepresentation) + count * sizeof(StructField);
     StructTypeRepresentation *ptr =
         (StructTypeRepresentation *) cx->malloc_(size);
     new(ptr) StructTypeRepresentation();
     if (!ptr->init(cx, ids, typeReprOwners))
         return NULL;
 
-    TypeRepresentationSet::AddPtr p = comp->typeReprs.lookupForAdd(ptr);
+    TypeRepresentationHash::AddPtr p = comp->typeReprs.lookupForAdd(ptr);
     if (p) {
         js_free(ptr); // do not finalize, not present in the table
         return (*p)->ownerObject();
     }
 
     return ptr->addToTableOrFree(cx, p);
 }
 
@@ -535,20 +535,20 @@ StructTypeRepresentation::appendStringSt
 
     return true;
 }
 
 ///////////////////////////////////////////////////////////////////////////
 // Misc
 
 const StructField *
-StructTypeRepresentation::fieldNamed(HandleId id) const
+StructTypeRepresentation::fieldNamed(jsid id) const
 {
     for (size_t i = 0; i < fieldCount(); i++) {
-        if (field(i).id.get() == id.get())
+        if (field(i).id.get() == id)
             return &field(i);
     }
     return NULL;
 }
 
 /*static*/ bool
 TypeRepresentation::isTypeRepresentationOwnerObject(JSObject *obj)
 {
--- a/js/src/builtin/TypeRepresentation.h
+++ b/js/src/builtin/TypeRepresentation.h
@@ -80,34 +80,34 @@ struct TypeRepresentationHasher
     static bool matchStructs(StructTypeRepresentation *key1,
                              StructTypeRepresentation *key2);
     static bool matchArrays(ArrayTypeRepresentation *key1,
                             ArrayTypeRepresentation *key2);
 };
 
 typedef js::HashSet<TypeRepresentation *,
                     TypeRepresentationHasher,
-                    RuntimeAllocPolicy> TypeRepresentationSet;
+                    RuntimeAllocPolicy> TypeRepresentationHash;
 
 class TypeRepresentation {
   public:
     enum Kind {
         Scalar,
         Struct,
         Array
     };
 
   protected:
     TypeRepresentation(Kind kind, size_t size, size_t align);
 
     size_t size_;
     size_t alignment_;
     Kind kind_;
 
-    JSObject *addToTableOrFree(JSContext *cx, TypeRepresentationSet::AddPtr &p);
+    JSObject *addToTableOrFree(JSContext *cx, TypeRepresentationHash::AddPtr &p);
 
   private:
     static const Class class_;
     static void obj_trace(JSTracer *trace, JSObject *object);
     static void obj_finalize(js::FreeOp *fop, JSObject *object);
 
     js::HeapPtrObject ownerObject_;
     void traceFields(JSTracer *tracer);
@@ -285,17 +285,17 @@ class StructTypeRepresentation : public 
         return fieldCount_;
     }
 
     const StructField &field(size_t i) const {
         JS_ASSERT(i < fieldCount());
         return fields()[i];
     }
 
-    const StructField *fieldNamed(HandleId id) const;
+    const StructField *fieldNamed(jsid id) const;
 
     static JSObject *Create(JSContext *cx,
                             AutoIdVector &ids,
                             AutoObjectVector &typeReprOwners);
 };
 
 } // namespace js
 
--- a/js/src/builtin/TypedObject.cpp
+++ b/js/src/builtin/TypedObject.cpp
@@ -2361,8 +2361,15 @@ BinaryBlock::obj_enumerate(JSContext *cx
             statep.setNull();
             break;
         }
         break;
     }
 
     return true;
 }
+
+/* static */ size_t
+BinaryBlock::dataOffset()
+{
+    return JSObject::getPrivateDataOffset(BLOCK_RESERVED_SLOTS + 1);
+}
+
--- a/js/src/builtin/TypedObject.h
+++ b/js/src/builtin/TypedObject.h
@@ -192,16 +192,20 @@ class BinaryBlock
                                     bool *succeeded);
 
     static bool obj_enumerate(JSContext *cx, HandleObject obj, JSIterateOp enum_op,
                                 MutableHandleValue statep, MutableHandleId idp);
 
   public:
     static const Class class_;
 
+    // Returns the offset in bytes within the object where the `void*`
+    // pointer can be found.
+    static size_t dataOffset();
+
     static bool isBlock(HandleObject val);
     static uint8_t *mem(HandleObject val);
 
     // creates zeroed memory of size of type
     static JSObject *createZeroed(JSContext *cx, HandleObject type);
 
     // creates a block that aliases the memory owned by `owner` at the
     // given offset
--- a/js/src/configure.in
+++ b/js/src/configure.in
@@ -1056,17 +1056,22 @@ if test -n "$MOZ_LLVM_HACKS"; then
 fi
 
 dnl ========================================================
 dnl GNU specific defaults
 dnl ========================================================
 if test "$GNU_CC"; then
     # Per bug 719659 comment 2, some of the headers on ancient build machines
     # may require gnu89 inline semantics.  But otherwise, we use C99.
-    CFLAGS="$CFLAGS -std=gnu99 -fgnu89-inline"
+    # But on OS X we just use C99 plus GNU extensions, in order to fix
+    # bug 917526.
+    CFLAGS="$CFLAGS -std=gnu99"
+    if test "${OS_ARCH}" != Darwin; then
+        CFLAGS="$CFLAGS -fgnu89-inline"
+    fi
     MKSHLIB='$(CXX) $(CXXFLAGS) $(DSO_PIC_CFLAGS) $(DSO_LDOPTS) -Wl,-h,$(notdir $@) -o $@'
     MKCSHLIB='$(CC) $(CFLAGS) $(DSO_PIC_CFLAGS) $(DSO_LDOPTS) -Wl,-h,$(notdir $@) -o $@'
     DSO_LDOPTS='-shared'
     if test "$GCC_USE_GNU_LD"; then
         # Some tools like ASan use a runtime library that is only
         # linked against executables, so we must allow undefined
         # symbols for shared objects in some cases.
         if test -z "$MOZ_NO_WLZDEFS"; then
--- a/js/src/gc/Statistics.cpp
+++ b/js/src/gc/Statistics.cpp
@@ -129,26 +129,20 @@ class gcstats::StatisticsSerializer
         size_t nchars = strlen(buf);
         jschar *out = js_pod_malloc<jschar>(nchars + 1);
         if (!out) {
             oom_ = true;
             js_free(buf);
             return NULL;
         }
 
-        size_t outlen = nchars;
-        bool ok = InflateStringToBuffer(NULL, buf, nchars, out, &outlen);
+        InflateStringToBuffer(buf, nchars, out);
         js_free(buf);
-        if (!ok) {
-            oom_ = true;
-            js_free(out);
-            return NULL;
-        }
+
         out[nchars] = 0;
-
         return out;
     }
 
     char *finishCString() {
         if (oom_)
             return NULL;
 
         buf_.append('\0');
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/TypedObject/jit-complex.js
@@ -0,0 +1,30 @@
+// Test that we can optimize stuff like line.target.x without
+// creating an intermediate object.
+
+if (!this.hasOwnProperty("Type"))
+  quit();
+
+var PointType = new StructType({x: float64,
+                                y: float64});
+var LineType = new StructType({source: PointType,
+                               target: PointType});
+
+function manhattenDistance(line) {
+  return (Math.abs(line.target.x - line.source.x) +
+          Math.abs(line.target.y - line.source.y));
+}
+
+function foo() {
+  var N = 30000;
+  var points = [];
+  var obj;
+  var s;
+
+  var fromAToB = new LineType({source: {x: 22, y: 44},
+                               target: {x: 66, y: 88}});
+
+  for (var i = 0; i < N; i++)
+    assertEq(manhattenDistance(fromAToB), 88);
+}
+
+foo();
--- a/js/src/jit-test/tests/TypedObject/jit-prefix.js
+++ b/js/src/jit-test/tests/TypedObject/jit-prefix.js
@@ -7,22 +7,31 @@ var PointType2 = new StructType({x: floa
 var PointType3 = new StructType({x: float64,
                                  y: float64,
                                  z: float64});
 
 function xPlusY(p) {
   return p.x + p.y;
 }
 
+function xPlusYTweak(p) {
+  p.x = 22;
+  return xPlusY(p);
+}
+
 function foo() {
   var N = 30000;
   var points = [];
+  var obj;
+  var s;
+
   for (var i = 0; i < N; i++) {
-    var s;
     if ((i % 2) == 0 || true)
-      s = xPlusY(new PointType2({x: i, y: i+1}));
+      obj = new PointType2({x: i, y: i+1});
     else
-      s = xPlusY(new PointType3({x: i, y: i+1, z: i+2}));
-    assertEq(s, i + i + 1);
+      obj = new PointType3({x: i, y: i+1, z: i+2});
+
+    assertEq(xPlusY(obj), i + i + 1);
+    assertEq(xPlusYTweak(obj), 22 + i + 1);
   }
 }
 
 foo();
--- a/js/src/jit/CodeGenerator.cpp
+++ b/js/src/jit/CodeGenerator.cpp
@@ -11,16 +11,17 @@
 #include "mozilla/DebugOnly.h"
 #include "mozilla/Util.h"
 
 #include "jslibmath.h"
 #include "jsmath.h"
 #include "jsnum.h"
 
 #include "builtin/Eval.h"
+#include "builtin/TypedObject.h"
 #include "gc/Nursery.h"
 #include "jit/ExecutionModeInlines.h"
 #include "jit/IonLinker.h"
 #include "jit/IonSpewer.h"
 #include "jit/Lowering.h"
 #include "jit/MIRGenerator.h"
 #include "jit/MoveEmitter.h"
 #include "jit/ParallelFunctions.h"
@@ -2856,16 +2857,35 @@ CodeGenerator::visitNewArrayCallVM(LNewA
     if (ReturnReg != objReg)
         masm.movePtr(ReturnReg, objReg);
 
     restoreLive(lir);
 
     return true;
 }
 
+typedef JSObject *(*NewDerivedTypedObjectFn)(JSContext *,
+                                             HandleObject type,
+                                             HandleObject owner,
+                                             int32_t offset);
+static const VMFunction CreateDerivedTypedObjInfo =
+    FunctionInfo<NewDerivedTypedObjectFn>(CreateDerivedTypedObj);
+
+bool
+CodeGenerator::visitNewDerivedTypedObject(LNewDerivedTypedObject *lir)
+{
+    // Not yet made safe for par exec:
+    JS_ASSERT(gen->info().executionMode() == SequentialExecution);
+
+    pushArg(ToRegister(lir->offset()));
+    pushArg(ToRegister(lir->owner()));
+    pushArg(ToRegister(lir->type()));
+    return callVM(CreateDerivedTypedObjInfo, lir);
+}
+
 bool
 CodeGenerator::visitNewSlots(LNewSlots *lir)
 {
     Register temp1 = ToRegister(lir->temp1());
     Register temp2 = ToRegister(lir->temp2());
     Register temp3 = ToRegister(lir->temp3());
     Register output = ToRegister(lir->output());
 
@@ -3573,16 +3593,25 @@ CodeGenerator::visitTypedArrayElements(L
 {
     Register obj = ToRegister(lir->object());
     Register out = ToRegister(lir->output());
     masm.loadPtr(Address(obj, TypedArrayObject::dataOffset()), out);
     return true;
 }
 
 bool
+CodeGenerator::visitTypedObjectElements(LTypedObjectElements *lir)
+{
+    Register obj = ToRegister(lir->object());
+    Register out = ToRegister(lir->output());
+    masm.loadPtr(Address(obj, BinaryBlock::dataOffset()), out);
+    return true;
+}
+
+bool
 CodeGenerator::visitStringLength(LStringLength *lir)
 {
     Register input = ToRegister(lir->string());
     Register output = ToRegister(lir->output());
 
     masm.loadStringLength(input, output);
     return true;
 }
--- a/js/src/jit/CodeGenerator.h
+++ b/js/src/jit/CodeGenerator.h
@@ -127,32 +127,34 @@ class CodeGenerator : public CodeGenerat
     bool visitNewObject(LNewObject *lir);
     bool visitOutOfLineNewObject(OutOfLineNewObject *ool);
     bool visitNewDeclEnvObject(LNewDeclEnvObject *lir);
     bool visitNewCallObject(LNewCallObject *lir);
     bool visitNewCallObjectPar(LNewCallObjectPar *lir);
     bool visitNewStringObject(LNewStringObject *lir);
     bool visitNewPar(LNewPar *lir);
     bool visitNewDenseArrayPar(LNewDenseArrayPar *lir);
+    bool visitNewDerivedTypedObject(LNewDerivedTypedObject *lir);
     bool visitAbortPar(LAbortPar *lir);
     bool visitInitElem(LInitElem *lir);
     bool visitInitElemGetterSetter(LInitElemGetterSetter *lir);
     bool visitInitProp(LInitProp *lir);
     bool visitInitPropGetterSetter(LInitPropGetterSetter *lir);
     bool visitCreateThis(LCreateThis *lir);
     bool visitCreateThisWithProto(LCreateThisWithProto *lir);
     bool visitCreateThisWithTemplate(LCreateThisWithTemplate *lir);
     bool visitCreateArgumentsObject(LCreateArgumentsObject *lir);
     bool visitGetArgumentsObjectArg(LGetArgumentsObjectArg *lir);
     bool visitSetArgumentsObjectArg(LSetArgumentsObjectArg *lir);
     bool visitReturnFromCtor(LReturnFromCtor *lir);
     bool visitComputeThis(LComputeThis *lir);
     bool visitArrayLength(LArrayLength *lir);
     bool visitTypedArrayLength(LTypedArrayLength *lir);
     bool visitTypedArrayElements(LTypedArrayElements *lir);
+    bool visitTypedObjectElements(LTypedObjectElements *lir);
     bool visitStringLength(LStringLength *lir);
     bool visitInitializedLength(LInitializedLength *lir);
     bool visitSetInitializedLength(LSetInitializedLength *lir);
     bool visitNotO(LNotO *ins);
     bool visitNotV(LNotV *ins);
     bool visitBoundsCheck(LBoundsCheck *lir);
     bool visitBoundsCheckRange(LBoundsCheckRange *lir);
     bool visitBoundsCheckLower(LBoundsCheckLower *lir);
--- a/js/src/jit/IonBuilder.cpp
+++ b/js/src/jit/IonBuilder.cpp
@@ -6,16 +6,17 @@
 
 #include "jit/IonBuilder.h"
 
 #include "mozilla/DebugOnly.h"
 
 #include "jsautooplen.h"
 
 #include "builtin/Eval.h"
+#include "builtin/TypedObject.h"
 #include "builtin/TypeRepresentation.h"
 #include "frontend/SourceNotes.h"
 #include "jit/BaselineFrame.h"
 #include "jit/BaselineInspector.h"
 #include "jit/ExecutionModeInlines.h"
 #include "jit/Ion.h"
 #include "jit/IonAnalysis.h"
 #include "jit/IonSpewer.h"
@@ -1181,17 +1182,25 @@ IonBuilder::traverseBytecode()
                 // we may replace it with |undefined|, but the difference is
                 // not observable.
                 JS_ASSERT(i == 0);
                 if (current->peek(-1) == popped[0])
                     break;
                 // FALL THROUGH
 
               default:
-                JS_ASSERT(popped[i]->isFolded() || popped[i]->defUseCount() > poppedUses[i]);
+                JS_ASSERT(popped[i]->isFolded() ||
+
+                          // MNewDerivedTypedObject instances are
+                          // often dead unless they escape from the
+                          // fn. See IonBuilder::loadTypedObjectData()
+                          // for more details.
+                          popped[i]->isNewDerivedTypedObject() ||
+
+                          popped[i]->defUseCount() > poppedUses[i]);
                 break;
             }
         }
 #endif
 
         pc += js_CodeSpec[op].length;
         current->updateTrackedPc(pc);
     }
@@ -6996,16 +7005,38 @@ IonBuilder::convertShiftToMaskForStaticT
     JS_ASSERT(!ptr->isEffectful());
 
     current->add(mask);
     current->add(ptr);
 
     return ptr;
 }
 
+static MIRType
+MIRTypeForTypedArrayRead(ScalarTypeRepresentation::Type arrayType,
+                         bool observedDouble)
+{
+    switch (arrayType) {
+      case ScalarTypeRepresentation::TYPE_INT8:
+      case ScalarTypeRepresentation::TYPE_UINT8:
+      case ScalarTypeRepresentation::TYPE_UINT8_CLAMPED:
+      case ScalarTypeRepresentation::TYPE_INT16:
+      case ScalarTypeRepresentation::TYPE_UINT16:
+      case ScalarTypeRepresentation::TYPE_INT32:
+        return MIRType_Int32;
+      case ScalarTypeRepresentation::TYPE_UINT32:
+        return observedDouble ? MIRType_Double : MIRType_Int32;
+      case ScalarTypeRepresentation::TYPE_FLOAT32:
+        return (LIRGenerator::allowFloat32Optimizations()) ? MIRType_Float32 : MIRType_Double;
+      case ScalarTypeRepresentation::TYPE_FLOAT64:
+        return MIRType_Double;
+    }
+    MOZ_ASSUME_UNREACHABLE("Unknown typed array type");
+}
+
 bool
 IonBuilder::jsop_getelem_typed(MDefinition *obj, MDefinition *index,
                                ScalarTypeRepresentation::Type arrayType)
 {
     types::TemporaryTypeSet *types = bytecodeTypes(pc);
 
     bool maybeUndefined = types->hasType(types::Type::UndefinedType());
 
@@ -7022,38 +7053,17 @@ IonBuilder::jsop_getelem_typed(MDefiniti
     if (!maybeUndefined) {
         // Assume the index is in range, so that we can hoist the length,
         // elements vector and bounds check.
 
         // If we are reading in-bounds elements, we can use knowledge about
         // the array type to determine the result type, even if the opcode has
         // never executed. The known pushed type is only used to distinguish
         // uint32 reads that may produce either doubles or integers.
-        MIRType knownType;
-        switch (arrayType) {
-          case ScalarTypeRepresentation::TYPE_INT8:
-          case ScalarTypeRepresentation::TYPE_UINT8:
-          case ScalarTypeRepresentation::TYPE_UINT8_CLAMPED:
-          case ScalarTypeRepresentation::TYPE_INT16:
-          case ScalarTypeRepresentation::TYPE_UINT16:
-          case ScalarTypeRepresentation::TYPE_INT32:
-            knownType = MIRType_Int32;
-            break;
-          case ScalarTypeRepresentation::TYPE_UINT32:
-            knownType = allowDouble ? MIRType_Double : MIRType_Int32;
-            break;
-          case ScalarTypeRepresentation::TYPE_FLOAT32:
-            knownType = (LIRGenerator::allowFloat32Optimizations()) ? MIRType_Float32 : MIRType_Double;
-            break;
-          case ScalarTypeRepresentation::TYPE_FLOAT64:
-            knownType = MIRType_Double;
-            break;
-          default:
-            MOZ_ASSUME_UNREACHABLE("Unknown typed array type");
-        }
+        MIRType knownType = MIRTypeForTypedArrayRead(arrayType, allowDouble);
 
         // Get the length.
         MInstruction *length = getTypedArrayLength(obj);
         current->add(length);
 
         // Bounds check.
         index = addBoundsCheck(index, length);
 
@@ -8145,16 +8155,20 @@ IonBuilder::jsop_getprop(PropertyName *n
     if (info().executionMode() == DefinitePropertiesAnalysis) {
         MDefinition *obj = current->pop();
         MCallGetProperty *call = MCallGetProperty::New(obj, name);
         current->add(call);
         current->push(call);
         return resumeAfter(call);
     }
 
+    // Try to emit loads from known binary data blocks
+    if (!getPropTryTypedObject(&emitted, id, types) || emitted)
+        return emitted;
+
     // Try to emit loads from definite slots.
     if (!getPropTryDefiniteSlot(&emitted, name, barrier, types) || emitted)
         return emitted;
 
     // Try to inline a common property getter, or make a call.
     if (!getPropTryCommonGetter(&emitted, id, barrier, types) || emitted)
         return emitted;
 
@@ -8227,16 +8241,131 @@ IonBuilder::getPropTryConstant(bool *emi
     current->add(known);
     current->push(known);
 
     *emitted = true;
     return true;
 }
 
 bool
+IonBuilder::getPropTryTypedObject(bool *emitted,
+                                  jsid id,
+                                  types::TemporaryTypeSet *resultTypes)
+{
+    TypeRepresentationSet fieldTypeReprs;
+    int32_t fieldOffset;
+    size_t fieldIndex;
+    if (!lookupTypedObjectField(current->peek(-1), id, &fieldOffset,
+                                &fieldTypeReprs, &fieldIndex))
+        return false;
+    if (fieldTypeReprs.empty())
+        return true;
+
+    switch (fieldTypeReprs.kind()) {
+      case TypeRepresentation::Struct:
+      case TypeRepresentation::Array:
+        return getPropTryComplexPropOfTypedObject(emitted,
+                                                  fieldOffset,
+                                                  fieldTypeReprs,
+                                                  fieldIndex,
+                                                  resultTypes);
+
+      case TypeRepresentation::Scalar:
+        return getPropTryScalarPropOfTypedObject(emitted,
+                                                 fieldOffset,
+                                                 fieldTypeReprs,
+                                                 resultTypes);
+    }
+
+    MOZ_ASSUME_UNREACHABLE("Bad kind");
+}
+
+bool
+IonBuilder::getPropTryScalarPropOfTypedObject(bool *emitted,
+                                              int32_t fieldOffset,
+                                              TypeRepresentationSet fieldTypeReprs,
+                                              types::TemporaryTypeSet *resultTypes)
+{
+    // Must always be loading the same scalar type
+    if (fieldTypeReprs.length() != 1)
+        return true;
+    ScalarTypeRepresentation *fieldTypeRepr = fieldTypeReprs.get(0)->asScalar();
+
+    // OK!
+    *emitted = true;
+
+    MDefinition *typedObj = current->pop();
+
+    // Find location within the owner object.
+    MDefinition *owner, *ownerOffset;
+    loadTypedObjectData(typedObj, fieldOffset, &owner, &ownerOffset);
+
+    // Load the element data.
+    MTypedObjectElements *elements = MTypedObjectElements::New(owner);
+    current->add(elements);
+
+    // Reading from an Uint32Array will result in a double for values
+    // that don't fit in an int32. We have to bailout if this happens
+    // and the instruction is not known to return a double.
+    bool allowDouble = resultTypes->hasType(types::Type::DoubleType());
+    MIRType knownType = MIRTypeForTypedArrayRead(fieldTypeRepr->type(), allowDouble);
+
+    // Typed array offsets are expressed in units of the alignment,
+    // and the binary data API guarantees all offsets are properly
+    // aligned. So just do the divide.
+    MConstant *alignment = MConstant::New(Int32Value(fieldTypeRepr->alignment()));
+    current->add(alignment);
+    MDiv *scaledOffset = MDiv::NewAsmJS(ownerOffset, alignment, MIRType_Int32);
+    current->add(scaledOffset);
+
+    MLoadTypedArrayElement *load =
+        MLoadTypedArrayElement::New(elements, scaledOffset,
+                                    fieldTypeRepr->type());
+    load->setResultType(knownType);
+    load->setResultTypeSet(resultTypes);
+    current->add(load);
+    current->push(load);
+    return true;
+}
+
+bool
+IonBuilder::getPropTryComplexPropOfTypedObject(bool *emitted,
+                                               int32_t fieldOffset,
+                                               TypeRepresentationSet fieldTypeReprs,
+                                               size_t fieldIndex,
+                                               types::TemporaryTypeSet *resultTypes)
+{
+    // Must know the field index so that we can load the new type
+    // object for the derived value
+    if (fieldIndex == SIZE_MAX)
+        return true;
+
+    *emitted = true;
+    MDefinition *typedObj = current->pop();
+
+    // Identify the type object for the field.
+    MDefinition *type = loadTypedObjectType(typedObj);
+    MDefinition *fieldType = typeObjectForFieldFromStructType(type, fieldIndex);
+
+    // Find location within the owner object.
+    MDefinition *owner, *ownerOffset;
+    loadTypedObjectData(typedObj, fieldOffset, &owner, &ownerOffset);
+
+    // Create the derived type object.
+    MInstruction *derived = new MNewDerivedTypedObject(fieldTypeReprs,
+                                                       fieldType,
+                                                       owner,
+                                                       ownerOffset);
+    derived->setResultTypeSet(resultTypes);
+    current->add(derived);
+    current->push(derived);
+    return true;
+}
+
+bool
 IonBuilder::getPropTryDefiniteSlot(bool *emitted, PropertyName *name,
                                    bool barrier, types::TemporaryTypeSet *types)
 {
     JS_ASSERT(*emitted == false);
     types::TypeSet *propTypes = GetDefiniteSlot(cx, current->peek(-1)->resultTypeSet(), name);
     if (!propTypes)
         return true;
 
@@ -8516,16 +8645,20 @@ IonBuilder::jsop_setprop(PropertyName *n
     types::TemporaryTypeSet *objTypes = obj->resultTypeSet();
     bool barrier;
     if (!PropertyWriteNeedsTypeBarrier(cx, current, &obj, name, &value,
                                        /* canModify = */ true, &barrier))
     {
         return false;
     }
 
+    // Try to emit stores to known binary data blocks
+    if (!setPropTryTypedObject(&emitted, obj, id, value) || emitted)
+        return emitted;
+
     // Try to emit store from definite slots.
     if (!setPropTryDefiniteSlot(&emitted, obj, name, value, barrier, objTypes) || emitted)
         return emitted;
 
     // Try to emit a monomorphic/polymorphic store based on baseline caches.
     if (!setPropTryInlineAccess(&emitted, obj, name, id, value, barrier, objTypes) || emitted)
         return emitted;
 
@@ -8649,16 +8782,76 @@ IonBuilder::setPropTryCommonDOMSetter(bo
     if (!resumeAfter(set))
         return false;
 
     *emitted = true;
     return true;
 }
 
 bool
+IonBuilder::setPropTryTypedObject(bool *emitted, MDefinition *obj,
+                                  jsid id, MDefinition *value)
+{
+    TypeRepresentationSet fieldTypeReprs;
+    int32_t fieldOffset;
+    size_t fieldIndex;
+    if (!lookupTypedObjectField(obj, id, &fieldOffset, &fieldTypeReprs,
+                                &fieldIndex))
+        return false;
+    if (fieldTypeReprs.empty())
+        return true;
+
+    switch (fieldTypeReprs.kind()) {
+      case TypeRepresentation::Struct:
+      case TypeRepresentation::Array:
+        // For now, only optimize storing scalars.
+        return true;
+
+      case TypeRepresentation::Scalar:
+        break;
+    }
+
+    // Must always be storing the same scalar type
+    if (fieldTypeReprs.length() != 1)
+        return true;
+    ScalarTypeRepresentation *fieldTypeRepr = fieldTypeReprs.get(0)->asScalar();
+
+    // OK!
+    *emitted = true;
+
+    MTypedObjectElements *elements = MTypedObjectElements::New(obj);
+    current->add(elements);
+
+    // Typed array offsets are expressed in units of the alignment,
+    // and the binary data API guarantees all offsets are properly
+    // aligned.
+    JS_ASSERT(fieldOffset % fieldTypeRepr->alignment() == 0);
+    int32_t scaledFieldOffset = fieldOffset / fieldTypeRepr->alignment();
+
+    MConstant *offset = MConstant::New(Int32Value(scaledFieldOffset));
+    current->add(offset);
+
+    // Clamp value to [0, 255] for Uint8ClampedArray.
+    MDefinition *toWrite = value;
+    if (fieldTypeRepr->type() == ScalarTypeRepresentation::TYPE_UINT8_CLAMPED) {
+        toWrite = MClampToUint8::New(value);
+        current->add(toWrite->toInstruction());
+    }
+
+    MStoreTypedArrayElement *store =
+        MStoreTypedArrayElement::New(elements, offset, toWrite,
+                                     fieldTypeRepr->type());
+    current->add(store);
+
+    current->push(value);
+
+    return true;
+}
+
+bool
 IonBuilder::setPropTryDefiniteSlot(bool *emitted, MDefinition *obj,
                                    PropertyName *name, MDefinition *value,
                                    bool barrier, types::TemporaryTypeSet *objTypes)
 {
     JS_ASSERT(*emitted == false);
 
     if (barrier)
         return true;
@@ -9320,8 +9513,177 @@ types::TemporaryTypeSet *
 IonBuilder::cloneTypeSet(types::StackTypeSet *types)
 {
     // Clone a type set so that it can be stored into the MIR and accessed
     // during off thread compilation. This is necessary because main thread
     // updates to type sets can race with reads in the compiler backend, and
     // after bug 804676 this code can be removed.
     return types->clone(GetIonContext()->temp->lifoAlloc());
 }
+
+TypeRepresentationSetHash *
+IonBuilder::getOrCreateReprSetHash()
+{
+    if (!reprSetHash_) {
+        TypeRepresentationSetHash* hash =
+            cx->new_<TypeRepresentationSetHash>();
+        if (!hash || !hash->init()) {
+            js_delete(hash);
+            return NULL;
+        }
+
+        reprSetHash_ = hash;
+    }
+    return reprSetHash_.get();
+}
+
+bool
+IonBuilder::lookupTypeRepresentationSet(MDefinition *typedObj,
+                                        TypeRepresentationSet *out)
+{
+    *out = TypeRepresentationSet(); // default to unknown
+
+    // Extract TypeRepresentationSet directly if we can
+    if (typedObj->isNewDerivedTypedObject()) {
+        *out = typedObj->toNewDerivedTypedObject()->set();
+        return true;
+    }
+
+    // Extract TypeRepresentationSet directly if we can
+    types::TemporaryTypeSet *types = typedObj->resultTypeSet();
+    if (!types || types->getKnownTypeTag() != JSVAL_TYPE_OBJECT)
+        return true;
+
+    // And only known objects.
+    if (types->unknownObject())
+        return true;
+
+    TypeRepresentationSetBuilder set;
+    for (uint32_t i = 0; i < types->getObjectCount(); i++) {
+        types::TypeObject *type = types->getTypeObject(0);
+        if (!type || type->unknownProperties())
+            return true;
+
+        if (!type->hasTypedObject())
+            return true;
+
+        TypeRepresentation *typeRepr = type->typedObject()->typeRepr;
+        if (!set.insert(typeRepr))
+            return false;
+    }
+
+    return set.build(*this, out);
+}
+
+MDefinition *
+IonBuilder::loadTypedObjectType(MDefinition *typedObj)
+{
+    // Shortcircuit derived type objects, meaning the intermediate
+    // objects created to represent `a.b` in an expression like
+    // `a.b.c`. In that case, the type object can be simply pulled
+    // from the operands of that instruction.
+    if (typedObj->isNewDerivedTypedObject())
+        return typedObj->toNewDerivedTypedObject()->type();
+
+    MInstruction *load = MLoadFixedSlot::New(typedObj, js::SLOT_DATATYPE);
+    current->add(load);
+    return load;
+}
+
+// Given a typed object `typedObj` and an offset `offset` into that
+// object's data, returns another typed object and adusted offset
+// where the data can be found. Often, these returned values are the
+// same as the inputs, but in cases where intermediate derived type
+// objects have been created, the return values will remove
+// intermediate layers (often rendering those derived type objects
+// into dead code).
+void
+IonBuilder::loadTypedObjectData(MDefinition *typedObj,
+                                int32_t offset,
+                                MDefinition **owner,
+                                MDefinition **ownerOffset)
+{
+    MConstant *offsetDef = MConstant::New(Int32Value(offset));
+    current->add(offsetDef);
+
+    // Shortcircuit derived type objects, meaning the intermediate
+    // objects created to represent `a.b` in an expression like
+    // `a.b.c`. In that case, the owned and a base offset can be
+    // pulled from the operands of the instruction and combined with
+    // `offset`.
+    if (typedObj->isNewDerivedTypedObject()) {
+        // If we see that the
+        MNewDerivedTypedObject *ins = typedObj->toNewDerivedTypedObject();
+
+        MAdd *offsetAdd = MAdd::NewAsmJS(ins->offset(), offsetDef,
+                                         MIRType_Int32);
+        current->add(offsetAdd);
+
+        *owner = ins->owner();
+        *ownerOffset = offsetAdd;
+        return;
+    }
+
+    *owner = typedObj;
+    *ownerOffset = offsetDef;
+}
+
+// Looks up the offset/type-repr-set of the field `id`, given the type
+// set `objTypes` of the field owner. Note that even when true is
+// returned, `*fieldTypeReprs` might be empty if no useful type/offset
+// pair could be determined.
+bool
+IonBuilder::lookupTypedObjectField(MDefinition *typedObj,
+                                   jsid id,
+                                   int32_t *fieldOffset,
+                                   TypeRepresentationSet *fieldTypeReprs,
+                                   size_t *fieldIndex)
+{
+    TypeRepresentationSet objTypeReprs;
+    if (!lookupTypeRepresentationSet(typedObj, &objTypeReprs))
+        return false;
+
+    // Must be accessing a struct.
+    if (!objTypeReprs.allOfKind(TypeRepresentation::Struct))
+        return true;
+
+    // Determine the type/offset of the field `id`, if any.
+    size_t offset;
+    if (!objTypeReprs.fieldNamed(*this, id, &offset,
+                                 fieldTypeReprs, fieldIndex))
+        return false;
+    if (fieldTypeReprs->empty())
+        return false;
+
+    // Field offset must be representable as signed integer.
+    if (offset >= size_t(INT_MAX)) {
+        *fieldTypeReprs = TypeRepresentationSet();
+        return true;
+    }
+
+    *fieldOffset = int32_t(offset);
+    JS_ASSERT(*fieldOffset >= 0);
+
+    return true;
+}
+
+MDefinition *
+IonBuilder::typeObjectForFieldFromStructType(MDefinition *typeObj,
+                                             size_t fieldIndex)
+{
+    // Load list of field type objects.
+
+    MInstruction *fieldTypes = MLoadFixedSlot::New(typeObj, SLOT_STRUCT_FIELD_TYPES);
+    current->add(fieldTypes);
+
+    // Index into list with index of field.
+
+    MInstruction *fieldTypesElements = MElements::New(fieldTypes);
+    current->add(fieldTypesElements);
+
+    MConstant *fieldIndexDef = MConstant::New(Int32Value(fieldIndex));
+    current->add(fieldIndexDef);
+
+    MInstruction *fieldType = MLoadElement::New(fieldTypesElements, fieldIndexDef, false, false);
+    current->add(fieldType);
+
+    return fieldType;
+}
--- a/js/src/jit/IonBuilder.h
+++ b/js/src/jit/IonBuilder.h
@@ -10,16 +10,17 @@
 #ifdef JS_ION
 
 // This file declares the data structures for building a MIRGraph from a
 // JSScript.
 
 #include "jit/BytecodeAnalysis.h"
 #include "jit/MIR.h"
 #include "jit/MIRGraph.h"
+#include "jit/TypeRepresentationSet.h"
 
 namespace js {
 namespace jit {
 
 class CodeGenerator;
 class CallInfo;
 class BaselineInspector;
 
@@ -358,16 +359,27 @@ class IonBuilder : public MIRGenerator
     bool getPropTryArgumentsLength(bool *emitted);
     bool getPropTryConstant(bool *emitted, jsid id, types::TemporaryTypeSet *types);
     bool getPropTryDefiniteSlot(bool *emitted, PropertyName *name,
                                 bool barrier, types::TemporaryTypeSet *types);
     bool getPropTryCommonGetter(bool *emitted, jsid id,
                                 bool barrier, types::TemporaryTypeSet *types);
     bool getPropTryInlineAccess(bool *emitted, PropertyName *name, jsid id,
                                 bool barrier, types::TemporaryTypeSet *types);
+    bool getPropTryTypedObject(bool *emitted, jsid id,
+                               types::TemporaryTypeSet *resultTypes);
+    bool getPropTryScalarPropOfTypedObject(bool *emitted,
+                                           int32_t fieldOffset,
+                                           TypeRepresentationSet fieldTypeReprs,
+                                           types::TemporaryTypeSet *resultTypes);
+    bool getPropTryComplexPropOfTypedObject(bool *emitted,
+                                            int32_t fieldOffset,
+                                            TypeRepresentationSet fieldTypeReprs,
+                                            size_t fieldIndex,
+                                            types::TemporaryTypeSet *resultTypes);
     bool getPropTryCache(bool *emitted, PropertyName *name, jsid id,
                          bool barrier, types::TemporaryTypeSet *types);
     bool needsToMonitorMissingProperties(types::TemporaryTypeSet *types);
 
     // jsop_setprop() helpers.
     bool setPropTryCommonSetter(bool *emitted, MDefinition *obj,
                                 PropertyName *name, jsid id,
                                 MDefinition *value);
@@ -376,20 +388,38 @@ class IonBuilder : public MIRGenerator
                                    bool isDOM);
     bool setPropTryDefiniteSlot(bool *emitted, MDefinition *obj,
                                 PropertyName *name, MDefinition *value,
                                 bool barrier, types::TemporaryTypeSet *objTypes);
     bool setPropTryInlineAccess(bool *emitted, MDefinition *obj,
                                 PropertyName *name, jsid id,
                                 MDefinition *value, bool barrier,
                                 types::TemporaryTypeSet *objTypes);
+    bool setPropTryTypedObject(bool *emitted, MDefinition *obj,
+                               jsid id, MDefinition *value);
     bool setPropTryCache(bool *emitted, MDefinition *obj,
                          PropertyName *name, MDefinition *value,
                          bool barrier, types::TemporaryTypeSet *objTypes);
 
+    // binary data lookup helpers.
+    bool lookupTypeRepresentationSet(MDefinition *typedObj,
+                                     TypeRepresentationSet *out);
+    bool lookupTypedObjectField(MDefinition *typedObj,
+                                jsid id,
+                                int32_t *fieldOffset,
+                                TypeRepresentationSet *fieldTypeReprs,
+                                size_t *fieldIndex);
+    MDefinition *loadTypedObjectType(MDefinition *value);
+    void loadTypedObjectData(MDefinition *inOwner,
+                             int32_t inOffset,
+                             MDefinition **outOwner,
+                             MDefinition **outOffset);
+    MDefinition *typeObjectForFieldFromStructType(MDefinition *type,
+                                                  size_t fieldIndex);
+
     // jsop_setelem() helpers.
     bool setElemTryTyped(bool *emitted, MDefinition *object,
                          MDefinition *index, MDefinition *value);
     bool setElemTryTypedStatic(bool *emitted, MDefinition *object,
                                MDefinition *index, MDefinition *value);
     bool setElemTryDense(bool *emitted, MDefinition *object,
                          MDefinition *index, MDefinition *value);
     bool setElemTryArguments(bool *emitted, MDefinition *object,
@@ -636,22 +666,25 @@ class IonBuilder : public MIRGenerator
 
     JSScript *script() const { return script_.get(); }
 
     CodeGenerator *backgroundCodegen() const { return backgroundCodegen_; }
     void setBackgroundCodegen(CodeGenerator *codegen) { backgroundCodegen_ = codegen; }
 
     AbortReason abortReason() { return abortReason_; }
 
+    TypeRepresentationSetHash *getOrCreateReprSetHash(); // fallible
+
   private:
     bool init();
 
     JSContext *cx;
     BaselineFrame *baselineFrame_;
     AbortReason abortReason_;
+    ScopedJSDeletePtr<TypeRepresentationSetHash> reprSetHash_;
 
     // Basic analysis information about the script.
     BytecodeAnalysis analysis_;
     BytecodeAnalysis &analysis() {
         return analysis_;
     }
 
     GSNCache gsn;
--- a/js/src/jit/LIR-Common.h
+++ b/js/src/jit/LIR-Common.h
@@ -496,16 +496,42 @@ public:
         return getTemp(0)->output();
     }
 
     const LAllocation *getTemp1() {
         return getTemp(1)->output();
     }
 };
 
+class LNewDerivedTypedObject : public LCallInstructionHelper<1, 3, 0>
+{
+  public:
+    LIR_HEADER(NewDerivedTypedObject);
+
+    LNewDerivedTypedObject(const LAllocation &type,
+                           const LAllocation &owner,
+                           const LAllocation &offset) {
+        setOperand(0, type);
+        setOperand(1, owner);
+        setOperand(2, offset);
+    }
+
+    const LAllocation *type() {
+        return getOperand(0);
+    }
+
+    const LAllocation *owner() {
+        return getOperand(1);
+    }
+
+    const LAllocation *offset() {
+        return getOperand(2);
+    }
+};
+
 class LNewStringObject : public LInstructionHelper<1, 1, 1>
 {
   public:
     LIR_HEADER(NewStringObject)
 
     LNewStringObject(const LAllocation &input, const LDefinition &temp) {
         setOperand(0, input);
         setTemp(0, temp);
@@ -3037,16 +3063,30 @@ class LTypedArrayElements : public LInst
     LTypedArrayElements(const LAllocation &object) {
         setOperand(0, object);
     }
     const LAllocation *object() {
         return getOperand(0);
     }
 };
 
+// Load a typed array's elements vector.
+class LTypedObjectElements : public LInstructionHelper<1, 1, 0>
+{
+  public:
+    LIR_HEADER(TypedObjectElements)
+
+    LTypedObjectElements(const LAllocation &object) {
+        setOperand(0, object);
+    }
+    const LAllocation *object() {
+        return getOperand(0);
+    }
+};
+
 // Bailout if index >= length.
 class LBoundsCheck : public LInstructionHelper<0, 2, 0>
 {
   public:
     LIR_HEADER(BoundsCheck)
 
     LBoundsCheck(const LAllocation &index, const LAllocation &length) {
         setOperand(0, index);
--- a/js/src/jit/LOpcodes.h
+++ b/js/src/jit/LOpcodes.h
@@ -27,16 +27,17 @@
     _(NewObject)                    \
     _(NewSlots)                     \
     _(NewDeclEnvObject)             \
     _(NewCallObject)                \
     _(NewStringObject)              \
     _(NewPar)                       \
     _(NewDenseArrayPar)             \
     _(NewCallObjectPar)             \
+    _(NewDerivedTypedObject)        \
     _(AbortPar)                     \
     _(InitElem)                     \
     _(InitElemGetterSetter)         \
     _(InitProp)                     \
     _(InitPropGetterSetter)         \
     _(CheckOverRecursed)            \
     _(CheckOverRecursedPar)         \
     _(DefVar)                       \
@@ -216,16 +217,17 @@
     _(CallIteratorStart)            \
     _(IteratorStart)                \
     _(IteratorNext)                 \
     _(IteratorMore)                 \
     _(IteratorEnd)                  \
     _(ArrayLength)                  \
     _(TypedArrayLength)             \
     _(TypedArrayElements)           \
+    _(TypedObjectElements)          \
     _(StringLength)                 \
     _(ArgumentsLength)              \
     _(GetArgument)                  \
     _(RunOncePrologue)              \
     _(Rest)                         \
     _(RestPar)                      \
     _(TypeOfV)                      \
     _(ToIdV)                        \
--- a/js/src/jit/Lowering.cpp
+++ b/js/src/jit/Lowering.cpp
@@ -203,16 +203,26 @@ LIRGenerator::visitNewCallObject(MNewCal
 
     if (!assignSafepoint(lir, ins))
         return false;
 
     return true;
 }
 
 bool
+LIRGenerator::visitNewDerivedTypedObject(MNewDerivedTypedObject *ins)
+{
+    LNewDerivedTypedObject *lir =
+        new LNewDerivedTypedObject(useRegisterAtStart(ins->type()),
+                                   useRegisterAtStart(ins->owner()),
+                                   useRegisterAtStart(ins->offset()));
+    return defineReturn(lir, ins) && assignSafepoint(lir, ins);
+}
+
+bool
 LIRGenerator::visitNewCallObjectPar(MNewCallObjectPar *ins)
 {
     const LAllocation &parThreadContext = useRegister(ins->forkJoinSlice());
     const LDefinition &temp1 = temp();
     const LDefinition &temp2 = temp();
 
     LNewCallObjectPar *lir;
     if (ins->slots()->type() == MIRType_Slots) {
@@ -2064,16 +2074,23 @@ LIRGenerator::visitTypedArrayLength(MTyp
 bool
 LIRGenerator::visitTypedArrayElements(MTypedArrayElements *ins)
 {
     JS_ASSERT(ins->type() == MIRType_Elements);
     return define(new LTypedArrayElements(useRegisterAtStart(ins->object())), ins);
 }
 
 bool
+LIRGenerator::visitTypedObjectElements(MTypedObjectElements *ins)
+{
+    JS_ASSERT(ins->type() == MIRType_Elements);
+    return define(new LTypedObjectElements(useRegisterAtStart(ins->object())), ins);
+}
+
+bool
 LIRGenerator::visitInitializedLength(MInitializedLength *ins)
 {
     JS_ASSERT(ins->elements()->type() == MIRType_Elements);
     return define(new LInitializedLength(useRegisterAtStart(ins->elements())), ins);
 }
 
 bool
 LIRGenerator::visitSetInitializedLength(MSetInitializedLength *ins)
--- a/js/src/jit/Lowering.h
+++ b/js/src/jit/Lowering.h
@@ -84,16 +84,17 @@ class LIRGenerator : public LIRGenerator
     bool visitTableSwitch(MTableSwitch *tableswitch);
     bool visitNewSlots(MNewSlots *ins);
     bool visitNewParallelArray(MNewParallelArray *ins);
     bool visitNewArray(MNewArray *ins);
     bool visitNewObject(MNewObject *ins);
     bool visitNewDeclEnvObject(MNewDeclEnvObject *ins);
     bool visitNewCallObject(MNewCallObject *ins);
     bool visitNewStringObject(MNewStringObject *ins);
+    bool visitNewDerivedTypedObject(MNewDerivedTypedObject *ins);
     bool visitNewPar(MNewPar *ins);
     bool visitNewCallObjectPar(MNewCallObjectPar *ins);
     bool visitNewDenseArrayPar(MNewDenseArrayPar *ins);
     bool visitAbortPar(MAbortPar *ins);
     bool visitInitElem(MInitElem *ins);
     bool visitInitElemGetterSetter(MInitElemGetterSetter *ins);
     bool visitInitProp(MInitProp *ins);
     bool visitInitPropGetterSetter(MInitPropGetterSetter *ins);
@@ -177,16 +178,17 @@ class LIRGenerator : public LIRGenerator
     bool visitCheckInterruptPar(MCheckInterruptPar *ins);
     bool visitStoreSlot(MStoreSlot *ins);
     bool visitTypeBarrier(MTypeBarrier *ins);
     bool visitMonitorTypes(MMonitorTypes *ins);
     bool visitPostWriteBarrier(MPostWriteBarrier *ins);
     bool visitArrayLength(MArrayLength *ins);
     bool visitTypedArrayLength(MTypedArrayLength *ins);
     bool visitTypedArrayElements(MTypedArrayElements *ins);
+    bool visitTypedObjectElements(MTypedObjectElements *ins);
     bool visitInitializedLength(MInitializedLength *ins);
     bool visitSetInitializedLength(MSetInitializedLength *ins);
     bool visitNot(MNot *ins);
     bool visitBoundsCheck(MBoundsCheck *ins);
     bool visitBoundsCheckLower(MBoundsCheckLower *ins);
     bool visitLoadElement(MLoadElement *ins);
     bool visitLoadElementHole(MLoadElementHole *ins);
     bool visitStoreElement(MStoreElement *ins);
--- a/js/src/jit/MIR.cpp
+++ b/js/src/jit/MIR.cpp
@@ -534,16 +534,23 @@ MCompare::printOpcode(FILE *fp) const
 
 void
 MConstantElements::printOpcode(FILE *fp) const
 {
     PrintOpcodeName(fp, op());
     fprintf(fp, " %p", value());
 }
 
+void
+MLoadTypedArrayElement::printOpcode(FILE *fp) const
+{
+    MDefinition::printOpcode(fp);
+    fprintf(fp, " %s", ScalarTypeRepresentation::typeName(arrayType()));
+}
+
 MParameter *
 MParameter::New(int32_t index, types::TemporaryTypeSet *types)
 {
     return new MParameter(index, types);
 }
 
 void
 MParameter::printOpcode(FILE *fp) const
--- a/js/src/jit/MIR.h
+++ b/js/src/jit/MIR.h
@@ -19,16 +19,17 @@
 #include "jit/Bailouts.h"
 #include "jit/CompilerRoot.h"
 #include "jit/FixedList.h"
 #include "jit/InlineList.h"
 #include "jit/IonAllocPolicy.h"
 #include "jit/IonMacroAssembler.h"
 #include "jit/MOpcodes.h"
 #include "jit/TypePolicy.h"
+#include "jit/TypeRepresentationSet.h"
 #include "vm/ScopeObject.h"
 
 namespace js {
 
 class StringObject;
 
 namespace jit {
 
@@ -1482,16 +1483,76 @@ class MNewPar : public MUnaryInstruction
         return getOperand(0);
     }
 
     JSObject *templateObject() const {
         return templateObject_;
     }
 };
 
+// Creates a new derived type object. At runtime, this is just a call
+// to `BinaryBlock::createDerived()`. That is, the MIR itself does not
+// compile to particularly optimized code. However, using a distinct
+// MIR for creating derived type objects allows the compiler to
+// optimize ephemeral typed objects as would be created for a
+// reference like `a.b.c` -- here, the `a.b` will create an ephemeral
+// derived type object that aliases the memory of `a` itself. The
+// specific nature of `a.b` is revealed by using
+// `MNewDerivedTypedObject` rather than `MGetProperty` or what have
+// you. Moreover, the compiler knows that there are no side-effects,
+// so `MNewDerivedTypedObject` instructions can be reordered or pruned
+// as dead code.
+class MNewDerivedTypedObject
+  : public MTernaryInstruction,
+    public Mix3Policy<ObjectPolicy<0>,
+                      ObjectPolicy<1>,
+                      IntPolicy<2> >
+{
+  private:
+    TypeRepresentationSet set_;
+
+  public:
+    INSTRUCTION_HEADER(NewDerivedTypedObject);
+
+    MNewDerivedTypedObject(TypeRepresentationSet set,
+                           MDefinition *type,
+                           MDefinition *owner,
+                           MDefinition *offset)
+      : MTernaryInstruction(type, owner, offset),
+        set_(set)
+    {
+        setMovable();
+        setResultType(MIRType_Object);
+    }
+
+    TypeRepresentationSet set() const {
+        return set_;
+    }
+
+    MDefinition *type() const {
+        return getOperand(0);
+    }
+
+    MDefinition *owner() const {
+        return getOperand(1);
+    }
+
+    MDefinition *offset() const {
+        return getOperand(2);
+    }
+
+    TypePolicy *typePolicy() {
+        return this;
+    }
+
+    virtual AliasSet getAliasSet() const {
+        return AliasSet::None();
+    }
+};
+
 // Abort parallel execution.
 class MAbortPar : public MAryControlInstruction<0, 0>
 {
   public:
     INSTRUCTION_HEADER(AbortPar);
 
     MAbortPar()
       : MAryControlInstruction<0, 0>()
@@ -4877,16 +4938,52 @@ class MTypedArrayElements
     bool congruentTo(MDefinition *ins) const {
         return congruentIfOperandsEqual(ins);
     }
     AliasSet getAliasSet() const {
         return AliasSet::Load(AliasSet::ObjectFields);
     }
 };
 
+// Load a binary data object's "elements", which is just its opaque
+// binary data space. Eventually this should probably be
+// unified with `MTypedArrayElements`.
+class MTypedObjectElements
+  : public MUnaryInstruction,
+    public SingleObjectPolicy
+{
+  private:
+    MTypedObjectElements(MDefinition *object)
+      : MUnaryInstruction(object)
+    {
+        setResultType(MIRType_Elements);
+        setMovable();
+    }
+
+  public:
+    INSTRUCTION_HEADER(TypedObjectElements)
+
+    static MTypedObjectElements *New(MDefinition *object) {
+        return new MTypedObjectElements(object);
+    }
+
+    TypePolicy *typePolicy() {
+        return this;
+    }
+    MDefinition *object() const {
+        return getOperand(0);
+    }
+    bool congruentTo(MDefinition *ins) const {
+        return congruentIfOperandsEqual(ins);
+    }
+    AliasSet getAliasSet() const {
+        return AliasSet::Load(AliasSet::ObjectFields);
+    }
+};
+
 // Perform !-operation
 class MNot
   : public MUnaryInstruction,
     public TestPolicy
 {
     bool operandMightEmulateUndefined_;
 
   public:
@@ -5418,16 +5515,18 @@ class MLoadTypedArrayElement
     }
     MDefinition *index() const {
         return getOperand(1);
     }
     AliasSet getAliasSet() const {
         return AliasSet::Load(AliasSet::TypedArrayElement);
     }
 
+    void printOpcode(FILE *fp) const;
+
     void computeRange();
 
     bool canProduceFloat32() const { return arrayType_ == ScalarTypeRepresentation::TYPE_FLOAT32; }
 };
 
 // Load a value from a typed array. Out-of-bounds accesses are handled using
 // a VM call.
 class MLoadTypedArrayElementHole
--- a/js/src/jit/MOpcodes.h
+++ b/js/src/jit/MOpcodes.h
@@ -118,16 +118,17 @@ namespace jit {
     _(SetElementCache)                                                      \
     _(BindNameCache)                                                        \
     _(GuardShape)                                                           \
     _(GuardObjectType)                                                      \
     _(GuardClass)                                                           \
     _(ArrayLength)                                                          \
     _(TypedArrayLength)                                                     \
     _(TypedArrayElements)                                                   \
+    _(TypedObjectElements)                                                  \
     _(InitializedLength)                                                    \
     _(SetInitializedLength)                                                 \
     _(Not)                                                                  \
     _(BoundsCheck)                                                          \
     _(BoundsCheckLower)                                                     \
     _(InArray)                                                              \
     _(LoadElement)                                                          \
     _(LoadElementHole)                                                      \
@@ -192,16 +193,17 @@ namespace jit {
     _(AsmJSVoidReturn)                                                      \
     _(AsmJSPassStackArg)                                                    \
     _(AsmJSCall)                                                            \
     _(AsmJSCheckOverRecursed)                                               \
     _(CheckOverRecursedPar)                                                 \
     _(NewCallObjectPar)                                                     \
     _(NewPar)                                                               \
     _(NewDenseArrayPar)                                                     \
+    _(NewDerivedTypedObject)                                                \
     _(AbortPar)                                                             \
     _(LambdaPar)                                                            \
     _(RestPar)                                                              \
     _(ForkJoinSlice)                                                        \
     _(GuardThreadLocalObject)                                               \
     _(CheckInterruptPar)
 
 // Forward declarations of MIR types.
--- a/js/src/jit/ParallelSafetyAnalysis.cpp
+++ b/js/src/jit/ParallelSafetyAnalysis.cpp
@@ -170,16 +170,17 @@ class ParallelSafetyVisitor : public MIn
     SAFE_OP(TruncateToInt32)
     SAFE_OP(MaybeToDoubleElement)
     CUSTOM_OP(ToString)
     SAFE_OP(NewSlots)
     CUSTOM_OP(NewArray)
     CUSTOM_OP(NewObject)
     CUSTOM_OP(NewCallObject)
     CUSTOM_OP(NewParallelArray)
+    UNSAFE_OP(NewDerivedTypedObject)
     UNSAFE_OP(InitElem)
     UNSAFE_OP(InitElemGetterSetter)
     UNSAFE_OP(InitProp)
     UNSAFE_OP(InitPropGetterSetter)
     SAFE_OP(Start)
     UNSAFE_OP(OsrEntry)
     SAFE_OP(Nop)
     UNSAFE_OP(RegExp)
@@ -202,16 +203,17 @@ class ParallelSafetyVisitor : public MIn
     UNSAFE_OP(BindNameCache)
     SAFE_OP(GuardShape)
     SAFE_OP(GuardObjectType)
     SAFE_OP(GuardClass)
     SAFE_OP(AssertRange)
     SAFE_OP(ArrayLength)
     SAFE_OP(TypedArrayLength)
     SAFE_OP(TypedArrayElements)
+    SAFE_OP(TypedObjectElements)
     SAFE_OP(InitializedLength)
     WRITE_GUARDED_OP(SetInitializedLength, elements)
     SAFE_OP(Not)
     SAFE_OP(BoundsCheck)
     SAFE_OP(BoundsCheckLower)
     SAFE_OP(LoadElement)
     SAFE_OP(LoadElementHole)
     MAYBE_WRITE_GUARDED_OP(StoreElement, elements)
--- a/js/src/jit/TypePolicy.cpp
+++ b/js/src/jit/TypePolicy.cpp
@@ -411,16 +411,17 @@ IntPolicy<Op>::staticAdjustInputs(MInstr
     MUnbox *replace = MUnbox::New(in, MIRType_Int32, MUnbox::Fallible);
     def->block()->insertBefore(def, replace);
     def->replaceOperand(Op, replace);
     return true;
 }
 
 template bool IntPolicy<0>::staticAdjustInputs(MInstruction *def);
 template bool IntPolicy<1>::staticAdjustInputs(MInstruction *def);
+template bool IntPolicy<2>::staticAdjustInputs(MInstruction *def);
 
 template <unsigned Op>
 bool
 DoublePolicy<Op>::staticAdjustInputs(MInstruction *def)
 {
     MDefinition *in = def->getOperand(Op);
     if (in->type() == MIRType_Double)
         return true;
new file mode 100644
--- /dev/null
+++ b/js/src/jit/TypeRepresentationSet.cpp
@@ -0,0 +1,278 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sts=4 et sw=4 tw=99:
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "jit/TypeRepresentationSet.h"
+
+#include "mozilla/HashFunctions.h"
+
+#include "jit/IonBuilder.h"
+
+#include "jsinferinlines.h"
+
+using namespace js;
+using namespace jit;
+
+///////////////////////////////////////////////////////////////////////////
+// TypeRepresentationSet hasher
+
+HashNumber
+TypeRepresentationSetHasher::hash(TypeRepresentationSet key)
+{
+    HashNumber hn = mozilla::HashGeneric(key.length());
+    for (size_t i = 0; i < key.length(); i++)
+        hn = mozilla::AddToHash(hn, uintptr_t(key.get(i)));
+    return hn;
+}
+
+bool
+TypeRepresentationSetHasher::match(TypeRepresentationSet key1,
+                                   TypeRepresentationSet key2)
+{
+    if (key1.length() != key2.length())
+        return false;
+
+    // Note: entries are always sorted
+    for (size_t i = 0; i < key1.length(); i++) {
+        if (key1.get(i) != key2.get(i))
+            return false;
+    }
+
+    return true;
+}
+
+///////////////////////////////////////////////////////////////////////////
+// TypeRepresentationSetBuilder
+
+TypeRepresentationSetBuilder::TypeRepresentationSetBuilder()
+  : invalid_(false)
+{}
+
+bool
+TypeRepresentationSetBuilder::insert(TypeRepresentation *typeRepr)
+{
+    if (invalid_)
+        return true;
+
+    if (entries_.length() == 0)
+        return entries_.append(typeRepr);
+
+    // Check that this new type repr is of the same basic kind as the
+    // ones we have seen thus far. If not, for example if we have an
+    // `int` and a `struct`, then convert this set to the invalid set.
+    TypeRepresentation *entry0 = entries_[0];
+    if (typeRepr->kind() != entry0->kind()) {
+        invalid_ = true;
+        entries_.clear();
+        return true;
+    }
+
+    // Otherwise, use binary search to find the right place to insert
+    // the type descriptor. We keep list sorted by the *address* of
+    // the type representations within.
+    uintptr_t typeReprAddr = (uintptr_t) typeRepr;
+    size_t min = 0;
+    size_t max = entries_.length();
+    while (min != max) {
+        size_t i = min + ((max - min) >> 1); // average w/o fear of overflow
+
+        uintptr_t entryiaddr = (uintptr_t) entries_[i];
+        if (entryiaddr == typeReprAddr)
+            return true; // typeRepr already present in the set
+
+        if (entryiaddr < typeReprAddr) {
+            // typeRepr lies to the right of entry i
+            min = i;
+        } else {
+            // typeRepr lies to the left of entry i
+            max = i;
+        }
+    }
+
+    // As a sanity check, give up if the TypeRepresentationSet grows too large.
+    if (entries_.length() >= 512) {
+        invalid_ = true;
+        entries_.clear();
+        return true;
+    }
+
+    // Not present. Insert at position `min`.
+    if (min == entries_.length())
+        return entries_.append(typeRepr);
+    TypeRepresentation **insertLoc = &entries_[min];
+    return entries_.insert(insertLoc, typeRepr) != NULL;
+}
+
+bool
+TypeRepresentationSetBuilder::build(IonBuilder &builder,
+                                    TypeRepresentationSet *out)
+{
+    if (invalid_) {
+        *out = TypeRepresentationSet();
+        return true;
+    }
+
+    TypeRepresentationSetHash *table = builder.getOrCreateReprSetHash();
+    if (!table)
+        return false;
+
+    // Check if there is already a copy in the hashtable.
+    size_t length = entries_.length();
+    TypeRepresentationSet tempSet(length, entries_.begin());
+    TypeRepresentationSetHash::AddPtr p = table->lookupForAdd(tempSet);
+    if (p) {
+        *out = *p;
+        return true;
+    }
+
+    // If not, allocate a permanent copy in Ion temp memory and add it.
+    size_t space = sizeof(TypeRepresentation*) * length;
+    TypeRepresentation **array = (TypeRepresentation**)
+        GetIonContext()->temp->allocate(space);
+    if (!array)
+        return false;
+    memcpy(array, entries_.begin(), space);
+    TypeRepresentationSet permSet(length, array);
+    if (!table->add(p, permSet))
+        return false;
+
+    *out = permSet;
+    return true;
+}
+
+///////////////////////////////////////////////////////////////////////////
+// TypeRepresentationSet
+
+TypeRepresentationSet::TypeRepresentationSet(const TypeRepresentationSet &c)
+  : length_(c.length_),
+    entries_(c.entries_)
+{}
+
+TypeRepresentationSet::TypeRepresentationSet(size_t length,
+                                             TypeRepresentation **entries)
+  : length_(length),
+    entries_(entries)
+{}
+
+TypeRepresentationSet::TypeRepresentationSet()
+  : length_(0),
+    entries_(NULL)
+{}
+
+bool
+TypeRepresentationSet::empty()
+{
+    return length() == 0;
+}
+
+size_t
+TypeRepresentationSet::length()
+{
+    return length_;
+}
+
+TypeRepresentation *
+TypeRepresentationSet::get(size_t i)
+{
+    JS_ASSERT(i < length());
+    return entries_[i];
+}
+
+bool
+TypeRepresentationSet::allOfKind(TypeRepresentation::Kind aKind)
+{
+    if (empty())
+        return false;
+
+    return kind() == aKind;
+}
+
+TypeRepresentation::Kind
+TypeRepresentationSet::kind()
+{
+    JS_ASSERT(!empty());
+    return get(0)->kind();
+}
+
+size_t
+TypeRepresentationSet::arrayLength()
+{
+    JS_ASSERT(kind() == TypeRepresentation::Array);
+    const size_t result = get(0)->asArray()->length();
+    for (size_t i = 1; i < length(); i++) {
+        if (get(i)->asArray()->length() != result)
+            return SIZE_MAX;
+    }
+    return result;
+}
+
+bool
+TypeRepresentationSet::arrayElementType(IonBuilder &builder,
+                                        TypeRepresentationSet *out)
+{
+    JS_ASSERT(kind() == TypeRepresentation::Array);
+
+    TypeRepresentationSetBuilder elementTypes;
+    for (size_t i = 0; i < length(); i++) {
+        if (!elementTypes.insert(get(i)->asArray()->element()))
+            return false;
+    }
+    return elementTypes.build(builder, out);
+}
+
+bool
+TypeRepresentationSet::fieldNamed(IonBuilder &builder,
+                                  jsid id,
+                                  size_t *offset,
+                                  TypeRepresentationSet *out,
+                                  size_t *index)
+{
+    JS_ASSERT(kind() == TypeRepresentation::Struct);
+
+    // Initialize `*offset` and `*out` for the case where incompatible
+    // or absent fields are found.
+    *offset = SIZE_MAX;
+    *index = SIZE_MAX;
+    *out = TypeRepresentationSet();
+
+    // Remember offset of the first field.
+    size_t offset0;
+    size_t index0;
+    TypeRepresentationSetBuilder fieldTypes;
+    {
+        const StructField *field = get(0)->asStruct()->fieldNamed(id);
+        if (!field)
+            return true;
+
+        offset0 = field->offset;
+        index0 = field->index;
+        if (!fieldTypes.insert(field->typeRepr))
+            return false;
+    }
+
+    // Check that all subsequent fields are at the same offset
+    // and compute the union of their types.
+    for (size_t i = 1; i < length(); i++) {
+        const StructField *field = get(i)->asStruct()->fieldNamed(id);
+        if (!field)
+            return true;
+
+        if (field->offset != offset0)
+            return true;
+
+        if (field->index != index0)
+            index0 = SIZE_MAX;
+
+        if (!fieldTypes.insert(field->typeRepr))
+            return false;
+    }
+
+    // All struct types had a field named `id` at the same offset
+    // (though it's still possible that the types are incompatible and
+    // that the indices disagree).
+    *offset = offset0;
+    *index = index0;
+    return fieldTypes.build(builder, out);
+}
new file mode 100644
--- /dev/null
+++ b/js/src/jit/TypeRepresentationSet.h
@@ -0,0 +1,146 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sts=4 et sw=4 tw=99:
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef jit_TypeRepresentationSet_h
+#define jit_TypeRepresentationSet_h
+
+#include "builtin/TypeRepresentation.h"
+#include "jit/IonAllocPolicy.h"
+#include "js/HashTable.h"
+
+// TypeRepresentationSet stores a set of TypeRepresentation* objects,
+// representing the possible types of the binary data associated with
+// a typed object value.  Often TypeRepresentationSets will be
+// singleton sets, but it is also possible to have cases where many
+// type representations flow into a single point. In such cases, the
+// various type representations may differ in their details but often
+// have a common prefix. We try to optimize this case as well.
+//
+// So, for example, consider some code like:
+//
+//     var Point2Type = new StructType({x: uint8, y: uint8});
+//     var Point3Type = new StructType({x: uint8, y: uint8, z: uint8});
+//
+//     function distance2d(pnt) {
+//         return Math.sqrt(pnt.x * pnt.x + pnt.y * pnt.y);
+//     }
+//
+// Even if the function `distance2d()` were used with instances of
+// both Point2Type and Point3Type, we can still generate optimal code,
+// because both of those types contain fields named `x` and `y` with
+// the same types at the same offset.
+
+namespace js {
+namespace jit {
+
+class IonBuilder;
+class TypeRepresentationSet;
+
+class TypeRepresentationSetBuilder {
+  private:
+    Vector<TypeRepresentation *, 4, SystemAllocPolicy> entries_;
+    bool invalid_;
+
+    bool overlaps(TypeRepresentation *a, TypeRepresentation *b);
+
+  public:
+    TypeRepresentationSetBuilder();
+
+    bool insert(TypeRepresentation *typeRepr);
+    bool build(IonBuilder &builder, TypeRepresentationSet *out);
+};
+
+class TypeRepresentationSet {
+  private:
+    friend class TypeRepresentationSetBuilder;
+
+    size_t length_;
+    TypeRepresentation **entries_; // Allocated using temp policy
+
+    TypeRepresentationSet(size_t length, TypeRepresentation **entries);
+
+  public:
+    //////////////////////////////////////////////////////////////////////
+    // Constructors
+    //
+    // For more flexible constructors, see
+    // TypeRepresentationSetBuilder above.
+
+    TypeRepresentationSet(const TypeRepresentationSet &c);
+    TypeRepresentationSet(); // empty set
+
+    //////////////////////////////////////////////////////////////////////
+    // Query the set
+
+    bool empty();
+    size_t length();
+    TypeRepresentation *get(size_t i);
+    bool allOfKind(TypeRepresentation::Kind kind);
+
+    //////////////////////////////////////////////////////////////////////
+    // The following operations are only valid on a non-empty set:
+
+    TypeRepresentation::Kind kind();
+
+    //////////////////////////////////////////////////////////////////////
+    // Array operations
+    //
+    // Only valid when `kind() == TypeRepresentation::Array`
+
+    // Returns the length of the arrays in this set, or SIZE_MAX
+    // if they are not all the same.
+    size_t arrayLength();
+
+    // Returns a `TypeRepresentationSet` representing the element
+    // types of the various array types in this set. The returned set
+    // may be the empty set.
+    bool arrayElementType(IonBuilder &builder, TypeRepresentationSet *out);
+
+    //////////////////////////////////////////////////////////////////////
+    // Struct operations
+    //
+    // Only valid when `kind() == TypeRepresentation::Struct`
+
+    // Searches the type in the set for a field named `id`. All
+    // possible types must agree on the offset of the field within the
+    // structure and the possible types of the field must be
+    // compatible. If any pair of types disagree on the offset or have
+    // incompatible types for the field, then `*out` will be set to
+    // the empty set.
+    //
+    // Upon success, `out` will be set to the set of possible types of
+    // the field and `offset` will be set to the field's offset within
+    // the struct (measured in bytes).
+    //
+    // The parameter `*index` is special. If all types agree on the
+    // index of the field, then `*index` is set to the field index.
+    // Otherwise, it is set to SIZE_MAX. Note that two types may agree
+    // on the type and offset of a field but disagree about its index,
+    // e.g. the field `c` in `new StructType({a: uint8, b: uint8, c:
+    // uint16})` and `new StructType({a: uint16, c: uint16})`.
+    bool fieldNamed(IonBuilder &builder,
+                    jsid id,
+                    size_t *offset,
+                    TypeRepresentationSet *out,
+                    size_t *index);
+};
+
+struct TypeRepresentationSetHasher
+{
+    typedef TypeRepresentationSet Lookup;
+    static HashNumber hash(TypeRepresentationSet key);
+    static bool match(TypeRepresentationSet key1,
+                      TypeRepresentationSet key2);
+};
+
+typedef js::HashSet<TypeRepresentationSet,
+                    TypeRepresentationSetHasher,
+                    IonAllocPolicy> TypeRepresentationSetHash;
+
+} // namespace jit
+} // namespace js
+
+#endif
--- a/js/src/jit/VMFunctions.cpp
+++ b/js/src/jit/VMFunctions.cpp
@@ -2,16 +2,17 @@
  * vim: set ts=8 sts=4 et sw=4 tw=99:
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "jit/VMFunctions.h"
 
 #include "builtin/ParallelArray.h"
+#include "builtin/TypedObject.h"
 #include "frontend/BytecodeCompiler.h"
 #include "jit/BaselineIC.h"
 #include "jit/Ion.h"
 #include "jit/IonCompartment.h"
 #include "jit/IonFrames.h"
 #include "vm/ArrayObject.h"
 #include "vm/Debugger.h"
 #include "vm/Interpreter.h"
@@ -867,10 +868,17 @@ LeaveBlock(JSContext *cx, BaselineFrame 
 }
 
 bool
 InitBaselineFrameForOsr(BaselineFrame *frame, StackFrame *interpFrame, uint32_t numStackValues)
 {
     return frame->initForOsr(interpFrame, numStackValues);
 }
 
+JSObject *CreateDerivedTypedObj(JSContext *cx, HandleObject type,
+                                HandleObject owner, int32_t offset)
+{
+    return BinaryBlock::createDerived(cx, type, owner, offset);
+}
+
+
 } // namespace jit
 } // namespace js
--- a/js/src/jit/VMFunctions.h
+++ b/js/src/jit/VMFunctions.h
@@ -660,12 +660,15 @@ bool HandleDebugTrap(JSContext *cx, Base
 bool OnDebuggerStatement(JSContext *cx, BaselineFrame *frame, jsbytecode *pc, bool *mustReturn);
 
 bool EnterBlock(JSContext *cx, BaselineFrame *frame, Handle<StaticBlockObject *> block);
 bool LeaveBlock(JSContext *cx, BaselineFrame *frame);
 
 bool InitBaselineFrameForOsr(BaselineFrame *frame, StackFrame *interpFrame,
                              uint32_t numStackValues);
 
+JSObject *CreateDerivedTypedObj(JSContext *cx, HandleObject type,
+                                HandleObject owner, int32_t offset);
+
 } // namespace jit
 } // namespace js
 
 #endif /* jit_VMFunctions_h */
--- a/js/src/jsapi.cpp
+++ b/js/src/jsapi.cpp
@@ -5458,17 +5458,35 @@ JS_ConcatStrings(JSContext *cx, HandleSt
     return ConcatStrings<CanGC>(cx, left, right);
 }
 
 JS_PUBLIC_API(bool)
 JS_DecodeBytes(JSContext *cx, const char *src, size_t srclen, jschar *dst, size_t *dstlenp)
 {
     AssertHeapIsIdle(cx);
     CHECK_REQUEST(cx);
-    return InflateStringToBuffer(cx, src, srclen, dst, dstlenp);
+
+    if (!dst) {
+        *dstlenp = srclen;
+        return true;
+    }
+
+    size_t dstlen = *dstlenp;
+
+    if (srclen > dstlen) {
+        InflateStringToBuffer(src, dstlen, dst);
+
+        AutoSuppressGC suppress(cx);
+        JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_BUFFER_TOO_SMALL);
+        return false;
+    }
+
+    InflateStringToBuffer(src, srclen, dst);
+    *dstlenp = srclen;
+    return true;
 }
 
 JS_PUBLIC_API(char *)
 JS_EncodeString(JSContext *cx, JSString *str)
 {
     AssertHeapIsIdle(cx);
     CHECK_REQUEST(cx);
 
--- a/js/src/jsatom.cpp
+++ b/js/src/jsatom.cpp
@@ -383,23 +383,18 @@ js::AtomizeMaybeGC(ExclusiveContext *cx,
         /*
          * Avoiding the malloc in InflateString on shorter strings saves us
          * over 20,000 malloc calls on mozilla browser startup. This compares to
          * only 131 calls where the string is longer than a 31 char (net) buffer.
          * The vast majority of atomized strings are already in the hashtable. So
          * js::AtomizeString rarely has to copy the temp string we make.
          */
         jschar inflated[ATOMIZE_BUF_MAX];
-        size_t inflatedLength = ATOMIZE_BUF_MAX - 1;
-        if (!InflateStringToBuffer(cx->maybeJSContext(),
-                                   bytes, length, inflated, &inflatedLength))
-        {
-            return NULL;
-        }
-        return AtomizeAndCopyChars<allowGC>(cx, inflated, inflatedLength, ib);
+        InflateStringToBuffer(bytes, length, inflated);
+        return AtomizeAndCopyChars<allowGC>(cx, inflated, length, ib);
     }
 
     jschar *tbcharsZ = InflateString(cx, bytes, &length);
     if (!tbcharsZ)
         return NULL;
     return AtomizeAndTakeOwnership<allowGC>(cx, tbcharsZ, length, ib);
 }
 
--- a/js/src/jscompartment.h
+++ b/js/src/jscompartment.h
@@ -199,17 +199,17 @@ struct JSCompartment
 
   public:
     /* Last time at which an animation was played for a global in this compartment. */
     int64_t                      lastAnimationTime;
 
     js::RegExpCompartment        regExps;
 
     /* Set of all currently living type representations. */
-    js::TypeRepresentationSet    typeReprs;
+    js::TypeRepresentationHash   typeReprs;
 
   private:
     void sizeOfTypeInferenceData(JS::TypeInferenceSizes *stats, mozilla::MallocSizeOf mallocSizeOf);
 
   public:
     void sizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf, size_t *compartmentObject,
                              JS::TypeInferenceSizes *tiSizes,
                              size_t *shapesCompartmentTables, size_t *crossCompartmentWrappers,
--- a/js/src/jsfriendapi.cpp
+++ b/js/src/jsfriendapi.cpp
@@ -41,17 +41,17 @@ PerThreadDataFriendFields::PerThreadData
     PodArrayZero(thingGCRooters);
 #endif
 #if defined(DEBUG) && defined(JS_GC_ZEAL) && defined(JSGC_ROOT_ANALYSIS) && !defined(JS_THREADSAFE)
     skipGCRooters = NULL;
 #endif
 }
 
 JS_FRIEND_API(void)
-JS_SetSourceHook(JSRuntime *rt, JS_SourceHook hook)
+js::SetSourceHook(JSRuntime *rt, SourceHook *hook)
 {
     rt->sourceHook = hook;
 }
 
 JS_FRIEND_API(void)
 JS_SetGrayGCRootsTracer(JSRuntime *rt, JSTraceDataOp traceOp, void *data)
 {
     rt->gcGrayRootTracer.op = traceOp;
--- a/js/src/jsfriendapi.h
+++ b/js/src/jsfriendapi.h
@@ -198,23 +198,43 @@ struct JSFunctionSpecWithHelp {
 #define JS_FN_HELP(name,call,nargs,flags,usage,help)                          \
     {name, call, nargs, (flags) | JSPROP_ENUMERATE | JSFUN_STUB_GSOPS, usage, help}
 #define JS_FS_HELP_END                                                        \
     {NULL, NULL, 0, 0, NULL, NULL}
 
 extern JS_FRIEND_API(bool)
 JS_DefineFunctionsWithHelp(JSContext *cx, JSObject *obj, const JSFunctionSpecWithHelp *fs);
 
-typedef bool (* JS_SourceHook)(JSContext *cx, const char *filename,
-                               jschar **src, uint32_t *length);
+namespace js {
 
+/*
+ * A class of objects that return source code on demand.
+ *
+ * When code is compiled with CompileOptions::LAZY_SOURCE, SpiderMonkey
+ * doesn't retain the source code (and doesn't do lazy bytecode
+ * generation). If we ever need the source code, say, in response to a call
+ * to Function.prototype.toSource or Debugger.Source.prototype.text, then
+ * we call the 'load' member function of the instance of this class that
+ * has hopefully been registered with the runtime, passing the code's URL,
+ * and hope that it will be able to find the source.
+ */
+class SourceHook {
+  public:
+    virtual ~SourceHook() { }
+
+    /* Set |*src| and |*length| to refer to the source code for |filename|. */
+    virtual bool load(JSContext *cx, const char *filename, jschar **src, size_t *length) = 0;
+};
+
+/*
+ * Have |rt| use |hook| to retrieve LAZY_SOURCE source code.
+ * See the comments for SourceHook.
+ */
 extern JS_FRIEND_API(void)
-JS_SetSourceHook(JSRuntime *rt, JS_SourceHook hook);
-
-namespace js {
+SetSourceHook(JSRuntime *rt, SourceHook *hook);
 
 inline JSRuntime *
 GetRuntime(const JSContext *cx)
 {
     return ContextFriendFields::get(cx)->runtime_;
 }
 
 inline JSCompartment *
--- a/js/src/jsnum.cpp
+++ b/js/src/jsnum.cpp
@@ -645,21 +645,22 @@ js::Int32ToAtom(ExclusiveContext *cx, in
 template JSAtom *
 js::Int32ToAtom<CanGC>(ExclusiveContext *cx, int32_t si);
 
 template JSAtom *
 js::Int32ToAtom<NoGC>(ExclusiveContext *cx, int32_t si);
 
 /* Returns a non-NULL pointer to inside cbuf.  */
 static char *
-IntToCString(ToCStringBuf *cbuf, int i, int base = 10)
+IntToCString(ToCStringBuf *cbuf, int i, size_t *len, int base = 10)
 {
     unsigned u = (i < 0) ? -i : i;
 
-    RangedPtr<char> cp(cbuf->sbuf + cbuf->sbufSize - 1, cbuf->sbuf, cbuf->sbufSize);
+    RangedPtr<char> cp(cbuf->sbuf + ToCStringBuf::sbufSize - 1, cbuf->sbuf, ToCStringBuf::sbufSize);
+    char *end = cp.get();
     *cp = '\0';
 
     /* Build the string from behind. */
     switch (base) {
     case 10:
       cp = BackfillIndexInCharBuffer(u, cp);
       break;
     case 16:
@@ -676,16 +677,17 @@ IntToCString(ToCStringBuf *cbuf, int i, 
           *--cp = "0123456789abcdefghijklmnopqrstuvwxyz"[u - newu * base];
           u = newu;
       } while (u != 0);
       break;
     }
     if (i < 0)
         *--cp = '-';
 
+    *len = end - cp.get();
     return cp.get();
 }
 
 template <AllowGC allowGC>
 static JSString * JS_FASTCALL
 js_NumberToStringWithBase(ThreadSafeContext *cx, double d, int base);
 
 JS_ALWAYS_INLINE bool
@@ -1304,18 +1306,19 @@ FracNumberToCString(ThreadSafeContext *c
     }
     return numStr;
 }
 
 char *
 js::NumberToCString(JSContext *cx, ToCStringBuf *cbuf, double d, int base/* = 10*/)
 {
     int32_t i;
+    size_t len;
     return mozilla::DoubleIsInt32(d, &i)
-           ? IntToCString(cbuf, i, base)
+           ? IntToCString(cbuf, i, &len, base)
            : FracNumberToCString(cx, cbuf, d, base);
 }
 
 template <AllowGC allowGC>
 static JSString * JS_FASTCALL
 js_NumberToStringWithBase(ThreadSafeContext *cx, double d, int base)
 {
     ToCStringBuf cbuf;
@@ -1345,17 +1348,18 @@ js_NumberToStringWithBase(ThreadSafeCont
             return cx->staticStrings().getUnit(c);
         }
 
         if (comp) {
             if (JSFlatString *str = comp->dtoaCache.lookup(base, d))
                 return str;
         }
 
-        numStr = IntToCString(&cbuf, i, base);
+        size_t len;
+        numStr = IntToCString(&cbuf, i, &len, base);
         JS_ASSERT(!cbuf.dbuf && numStr >= cbuf.sbuf && numStr < cbuf.sbuf + cbuf.sbufSize);
     } else {
         if (comp) {
             if (JSFlatString *str = comp->dtoaCache.lookup(base, d))
                 return str;
         }
 
         numStr = FracNumberToCString(cx, &cbuf, d, base);
@@ -1461,31 +1465,33 @@ js::IndexToString(JSContext *cx, uint32_
 }
 
 bool JS_FASTCALL
 js::NumberValueToStringBuffer(JSContext *cx, const Value &v, StringBuffer &sb)
 {
     /* Convert to C-string. */
     ToCStringBuf cbuf;
     const char *cstr;
+    size_t cstrlen;
     if (v.isInt32()) {
-        cstr = IntToCString(&cbuf, v.toInt32());
+        cstr = IntToCString(&cbuf, v.toInt32(), &cstrlen);
+        JS_ASSERT(cstrlen == strlen(cstr));
     } else {
         cstr = NumberToCString(cx, &cbuf, v.toDouble());
         if (!cstr) {
             JS_ReportOutOfMemory(cx);
             return false;
         }
+        cstrlen = strlen(cstr);
     }
 
     /*
      * Inflate to jschar string.  The input C-string characters are < 127, so
      * even if jschars are UTF-8, all chars should map to one jschar.
      */
-    size_t cstrlen = strlen(cstr);
     JS_ASSERT(!cbuf.dbuf && cstrlen < cbuf.sbufSize);
     return sb.appendInflated(cstr, cstrlen);
 }
 
 static void
 CharsToNumber(ThreadSafeContext *cx, const jschar *chars, size_t length, double *result)
 {
     if (length == 1) {
--- a/js/src/jsscript.cpp
+++ b/js/src/jsscript.cpp
@@ -993,18 +993,18 @@ ScriptSource::adjustDataSize(size_t nbyt
 /* static */ bool
 JSScript::loadSource(JSContext *cx, ScriptSource *ss, bool *worked)
 {
     JS_ASSERT(!ss->hasSourceData());
     *worked = false;
     if (!cx->runtime()->sourceHook || !ss->sourceRetrievable())
         return true;
     jschar *src = NULL;
-    uint32_t length;
-    if (!cx->runtime()->sourceHook(cx, ss->filename(), &src, &length))
+    size_t length;
+    if (!cx->runtime()->sourceHook->load(cx, ss->filename(), &src, &length))
         return false;
     if (!src)
         return true;
     ss->setSource(src, length);
     *worked = true;
     return true;
 }
 
@@ -1119,17 +1119,17 @@ ScriptSource::setSourceCopy(ExclusiveCon
             return false;
         PodCopy(data.source, src, length_);
     }
 
     return true;
 }
 
 void
-ScriptSource::setSource(const jschar *src, uint32_t length)
+ScriptSource::setSource(const jschar *src, size_t length)
 {
     JS_ASSERT(!hasSourceData());
     length_ = length;
     JS_ASSERT(!argumentsNotIncluded_);
     data.source = const_cast<jschar *>(src);
 }
 
 bool
--- a/js/src/jsscript.h
+++ b/js/src/jsscript.h
@@ -336,17 +336,17 @@ class ScriptSource
         if (--refs == 0)
             destroy();
     }
     bool setSourceCopy(ExclusiveContext *cx,
                        const jschar *src,
                        uint32_t length,
                        bool argumentsNotIncluded,
                        SourceCompressionTask *tok);
-    void setSource(const jschar *src, uint32_t length);
+    void setSource(const jschar *src, size_t length);
     bool ready() const { return ready_; }
     void setSourceRetrievable() { sourceRetrievable_ = true; }
     bool sourceRetrievable() const { return sourceRetrievable_; }
     bool hasSourceData() const { return !!data.source || !ready(); }
     uint32_t length() const {
         JS_ASSERT(hasSourceData());
         return length_;
     }
--- a/js/src/jsstr.cpp
+++ b/js/src/jsstr.cpp
@@ -4159,39 +4159,16 @@ js::DeflateStringToBuffer(JSContext *may
         return false;
     }
     for (size_t i = 0; i < srclen; i++)
         dst[i] = (char) src[i];
     *dstlenp = srclen;
     return true;
 }
 
-bool
-js::InflateStringToBuffer(JSContext *maybecx, const char *src, size_t srclen,
-                          jschar *dst, size_t *dstlenp)
-{
-    if (dst) {
-        size_t dstlen = *dstlenp;
-        if (srclen > dstlen) {
-            for (size_t i = 0; i < dstlen; i++)
-                dst[i] = (unsigned char) src[i];
-            if (maybecx) {
-                AutoSuppressGC suppress(maybecx);
-                JS_ReportErrorNumber(maybecx, js_GetErrorMessage, NULL,
-                                     JSMSG_BUFFER_TOO_SMALL);
-            }
-            return false;
-        }
-        for (size_t i = 0; i < srclen; i++)
-            dst[i] = (unsigned char) src[i];
-    }
-    *dstlenp = srclen;
-    return true;
-}
-
 #define ____ false
 
 /*
  * Identifier start chars:
  * -      36:    $
  * -  65..90: A..Z
  * -      95:    _
  * - 97..122: a..z
--- a/js/src/jsstr.h
+++ b/js/src/jsstr.h
@@ -244,25 +244,25 @@ namespace js {
  * return the jschar that was malloc'ed. length is updated to the length of the
  * new string (in jschars). A null char is appended, but it is not included in
  * the length.
  */
 extern jschar *
 InflateString(ThreadSafeContext *cx, const char *bytes, size_t *length);
 
 /*
- * Inflate bytes to JS chars in an existing buffer. 'chars' must be large
- * enough for 'length' jschars. The buffer is NOT null-terminated.
- *
- * charsLength must be be initialized with the destination buffer size and, on
- * return, will contain on return the number of copied chars.
+ * Inflate bytes to JS chars in an existing buffer. 'dst' must be large
+ * enough for 'srclen' jschars. The buffer is NOT null-terminated.
  */
-extern bool
-InflateStringToBuffer(JSContext *maybecx, const char *bytes, size_t length,
-                      jschar *chars, size_t *charsLength);
+inline void
+InflateStringToBuffer(const char *src, size_t srclen, jschar *dst)
+{
+    for (size_t i = 0; i < srclen; i++)
+        dst[i] = (unsigned char) src[i];
+}
 
 /*
  * Deflate JS chars to bytes into a buffer. 'bytes' must be large enough for
  * 'length chars. The buffer is NOT null-terminated. The destination length
  * must to be initialized with the buffer size and will contain on return the
  * number of copied bytes.
  */
 extern bool
--- a/js/src/moz.build
+++ b/js/src/moz.build
@@ -243,16 +243,17 @@ if CONFIG['ENABLE_ION']:
         'ParallelSafetyAnalysis.cpp',
         'ParallelFunctions.cpp',
         'RangeAnalysis.cpp',
         'RegisterAllocator.cpp',
         'Safepoints.cpp',
         'Snapshots.cpp',
         'StupidAllocator.cpp',
         'TypePolicy.cpp',
+        'TypeRepresentationSet.cpp',
         'UnreachableCodeElimination.cpp',
         'VMFunctions.cpp',
         'ValueNumbering.cpp',
     ]
     if CONFIG['TARGET_CPU'].find('86') != -1:
         CPP_SOURCES += [
             'Assembler-x86-shared.cpp',
             'BaselineCompiler-x86-shared.cpp',
--- a/js/src/vm/Runtime.cpp
+++ b/js/src/vm/Runtime.cpp
@@ -229,17 +229,16 @@ JSRuntime::JSRuntime(JSUseHelperThreads 
     gcSliceCallback(NULL),
     gcFinalizeCallback(NULL),
     gcMallocBytes(0),
     scriptAndCountsVector(NULL),
     NaNValue(DoubleNaNValue()),
     negativeInfinityValue(DoubleValue(NegativeInfinity())),
     positiveInfinityValue(DoubleValue(PositiveInfinity())),
     emptyString(NULL),
-    sourceHook(NULL),
     debugMode(false),
     spsProfiler(thisFromCtor()),
     profilingScripts(false),
     alwaysPreserveCode(false),
     hadOutOfMemory(false),
     haveCreatedContext(false),
     data(NULL),
     gcLock(NULL),
@@ -394,16 +393,19 @@ JSRuntime::init(uint32_t maxbytes)
 #endif
     return true;
 }
 
 JSRuntime::~JSRuntime()
 {
     JS_ASSERT(!isHeapBusy());
 
+    /* Free source hook early, as its destructor may want to delete roots. */
+    sourceHook = NULL;
+
     /* Off thread compilation and parsing depend on atoms still existing. */
     for (CompartmentsIter comp(this); !comp.done(); comp.next())
         CancelOffThreadIonCompile(comp, NULL);
     WaitForOffThreadParsingToFinish(this);
 
 #ifdef JS_WORKER_THREADS
     if (workerThreadState)
         workerThreadState->cleanup(this);
--- a/js/src/vm/Runtime.h
+++ b/js/src/vm/Runtime.h
@@ -6,16 +6,17 @@
 
 #ifndef vm_Runtime_h
 #define vm_Runtime_h
 
 #include "mozilla/Atomics.h"
 #include "mozilla/LinkedList.h"
 #include "mozilla/MemoryReporting.h"
 #include "mozilla/PodOperations.h"
+#include "mozilla/Scoped.h"
 #include "mozilla/ThreadLocal.h"
 
 #include <setjmp.h>
 
 #include "jsatom.h"
 #include "jsclist.h"
 #include "jsgc.h"
 #include "jsproxy.h"
@@ -1270,17 +1271,17 @@ struct JSRuntime : public JS::shadow::Ru
 
     /* List of active contexts sharing this runtime. */
     mozilla::LinkedList<JSContext> contextList;
 
     bool hasContexts() const {
         return !contextList.isEmpty();
     }
 
-    JS_SourceHook       sourceHook;
+    mozilla::ScopedDeletePtr<js::SourceHook> sourceHook;
 
     /* Per runtime debug hooks -- see js/OldDebugAPI.h. */
     JSDebugHooks        debugHooks;
 
     /* If true, new compartments are initially in debug mode. */
     bool                debugMode;
 
     /* SPS profiling metadata */
--- a/js/src/vm/StringBuffer.h
+++ b/js/src/vm/StringBuffer.h
@@ -117,20 +117,17 @@ StringBuffer::append(JSString *str)
 }
 
 inline bool
 StringBuffer::appendInflated(const char *cstr, size_t cstrlen)
 {
     size_t lengthBefore = length();
     if (!cb.growByUninitialized(cstrlen))
         return false;
-    mozilla::DebugOnly<size_t> oldcstrlen = cstrlen;
-    mozilla::DebugOnly<bool> ok = InflateStringToBuffer(NULL, cstr, cstrlen,
-                                                        begin() + lengthBefore, &cstrlen);
-    JS_ASSERT(ok && oldcstrlen == cstrlen);
+    InflateStringToBuffer(cstr, cstrlen, begin() + lengthBefore);
     return true;
 }
 
 /* ES5 9.8 ToString, appending the result to the string buffer. */
 extern bool
 ValueToStringBufferSlow(JSContext *cx, const Value &v, StringBuffer &sb);
 
 inline bool
--- a/js/xpconnect/src/XPCJSRuntime.cpp
+++ b/js/xpconnect/src/XPCJSRuntime.cpp
@@ -2769,110 +2769,113 @@ PreserveWrapper(JSContext *cx, JSObject 
     MOZ_ASSERT(cx);
     MOZ_ASSERT(obj);
     MOZ_ASSERT(IS_WN_REFLECTOR(obj) || mozilla::dom::IsDOMObject(obj));
 
     return mozilla::dom::IsDOMObject(obj) && mozilla::dom::TryPreserveWrapper(obj);
 }
 
 static nsresult
-ReadSourceFromFilename(JSContext *cx, const char *filename, jschar **src, uint32_t *len)
+ReadSourceFromFilename(JSContext *cx, const char *filename, jschar **src, size_t *len)
 {
-  nsresult rv;
-
-  // mozJSSubScriptLoader prefixes the filenames of the scripts it loads with
-  // the filename of its caller. Axe that if present.
-  const char *arrow;
-  while ((arrow = strstr(filename, " -> ")))
-    filename = arrow + strlen(" -> ");
-
-  // Get the URI.
-  nsCOMPtr<nsIURI> uri;
-  rv = NS_NewURI(getter_AddRefs(uri), filename);
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  nsCOMPtr<nsIChannel> scriptChannel;
-  rv = NS_NewChannel(getter_AddRefs(scriptChannel), uri);
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  // Only allow local reading.
-  nsCOMPtr<nsIURI> actualUri;
-  rv = scriptChannel->GetURI(getter_AddRefs(actualUri));
-  NS_ENSURE_SUCCESS(rv, rv);
-  nsCString scheme;
-  rv = actualUri->GetScheme(scheme);
-  NS_ENSURE_SUCCESS(rv, rv);
-  if (!scheme.EqualsLiteral("file") && !scheme.EqualsLiteral("jar"))
+    nsresult rv;
+
+    // mozJSSubScriptLoader prefixes the filenames of the scripts it loads with
+    // the filename of its caller. Axe that if present.
+    const char *arrow;
+    while ((arrow = strstr(filename, " -> ")))
+        filename = arrow + strlen(" -> ");
+
+    // Get the URI.
+    nsCOMPtr<nsIURI> uri;
+    rv = NS_NewURI(getter_AddRefs(uri), filename);
+    NS_ENSURE_SUCCESS(rv, rv);
+
+    nsCOMPtr<nsIChannel> scriptChannel;
+    rv = NS_NewChannel(getter_AddRefs(scriptChannel), uri);
+    NS_ENSURE_SUCCESS(rv, rv);
+
+    // Only allow local reading.
+    nsCOMPtr<nsIURI> actualUri;
+    rv = scriptChannel->GetURI(getter_AddRefs(actualUri));
+    NS_ENSURE_SUCCESS(rv, rv);
+    nsCString scheme;
+    rv = actualUri->GetScheme(scheme);
+    NS_ENSURE_SUCCESS(rv, rv);
+    if (!scheme.EqualsLiteral("file") && !scheme.EqualsLiteral("jar"))
+        return NS_OK;
+
+    nsCOMPtr<nsIInputStream> scriptStream;
+    rv = scriptChannel->Open(getter_AddRefs(scriptStream));
+    NS_ENSURE_SUCCESS(rv, rv);
+
+    uint64_t rawLen;
+    rv = scriptStream->Available(&rawLen);
+    NS_ENSURE_SUCCESS(rv, rv);
+    if (!rawLen)
+        return NS_ERROR_FAILURE;
+
+    // Technically, this should be SIZE_MAX, but we don't run on machines
+    // where that would be less than UINT32_MAX, and the latter is already
+    // well beyond a reasonable limit.
+    if (rawLen > UINT32_MAX)
+        return NS_ERROR_FILE_TOO_BIG;
+
+    // Allocate an internal buf the size of the file.
+    nsAutoArrayPtr<unsigned char> buf(new unsigned char[rawLen]);
+    if (!buf)
+        return NS_ERROR_OUT_OF_MEMORY;
+
+    unsigned char *ptr = buf, *end = ptr + rawLen;
+    while (ptr < end) {
+        uint32_t bytesRead;
+        rv = scriptStream->Read(reinterpret_cast<char *>(ptr), end - ptr, &bytesRead);
+        if (NS_FAILED(rv))
+            return rv;
+        MOZ_ASSERT(bytesRead > 0, "stream promised more bytes before EOF");
+        ptr += bytesRead;
+    }
+
+    nsString decoded;
+    rv = nsScriptLoader::ConvertToUTF16(scriptChannel, buf, rawLen, EmptyString(), NULL, decoded);
+    NS_ENSURE_SUCCESS(rv, rv);
+
+    // Copy to JS engine.
+    *len = decoded.Length();
+    *src = static_cast<jschar *>(JS_malloc(cx, decoded.Length()*sizeof(jschar)));
+    if (!*src)
+        return NS_ERROR_FAILURE;
+    memcpy(*src, decoded.get(), decoded.Length()*sizeof(jschar));
+
     return NS_OK;
-
-  nsCOMPtr<nsIInputStream> scriptStream;
-  rv = scriptChannel->Open(getter_AddRefs(scriptStream));
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  uint64_t rawLen;
-  rv = scriptStream->Available(&rawLen);
-  NS_ENSURE_SUCCESS(rv, rv);
-  if (!rawLen)
-    return NS_ERROR_FAILURE;
-  if (rawLen > UINT32_MAX)
-    return NS_ERROR_FILE_TOO_BIG;
-
-  // Allocate an internal buf the size of the file.
-  nsAutoArrayPtr<unsigned char> buf(new unsigned char[rawLen]);
-  if (!buf)
-    return NS_ERROR_OUT_OF_MEMORY;
-
-  unsigned char *ptr = buf, *end = ptr + rawLen;
-  while (ptr < end) {
-    uint32_t bytesRead;
-    rv = scriptStream->Read(reinterpret_cast<char *>(ptr), end - ptr, &bytesRead);
-    if (NS_FAILED(rv))
-      return rv;
-    MOZ_ASSERT(bytesRead > 0, "stream promised more bytes before EOF");
-    ptr += bytesRead;
-  }
-
-  nsString decoded;
-  rv = nsScriptLoader::ConvertToUTF16(scriptChannel, buf, rawLen, EmptyString(), NULL, decoded);
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  // Copy to JS engine.
-  *len = decoded.Length();
-  *src = static_cast<jschar *>(JS_malloc(cx, decoded.Length()*sizeof(jschar)));
-  if (!*src)
-    return NS_ERROR_FAILURE;
-  memcpy(*src, decoded.get(), decoded.Length()*sizeof(jschar));
-
-  return NS_OK;
 }
 
-/*
-  The JS engine calls this function when it needs the source for a chrome JS
-  function. See the comment in the XPCJSRuntime constructor.
-*/
-static bool
-SourceHook(JSContext *cx, const char *filename, jschar **src, uint32_t *length)
-{
-  *src = NULL;
-  *length = 0;
-
-  if (!nsContentUtils::IsCallerChrome())
-    return true;
-
-  if (!filename)
-    return true;
-
-  nsresult rv = ReadSourceFromFilename(cx, filename, src, length);
-  if (NS_FAILED(rv)) {
-    xpc::Throw(cx, rv);
-    return false;
-  }
-
-  return true;
-}
+// The JS engine calls this object's 'load' member function when it needs
+// the source for a chrome JS function. See the comment in the XPCJSRuntime
+// constructor.
+class XPCJSSourceHook: public js::SourceHook {
+    bool load(JSContext *cx, const char *filename, jschar **src, size_t *length) {
+        *src = NULL;
+        *length = 0;
+
+        if (!nsContentUtils::IsCallerChrome())
+            return true;
+
+        if (!filename)
+            return true;
+
+        nsresult rv = ReadSourceFromFilename(cx, filename, src, length);
+        if (NS_FAILED(rv)) {
+            xpc::Throw(cx, rv);
+            return false;
+        }
+
+        return true;
+    }
+};
 
 XPCJSRuntime::XPCJSRuntime(nsXPConnect* aXPConnect)
    : CycleCollectedJSRuntime(32L * 1024L * 1024L, JS_USE_HELPER_THREADS),
    mJSContextStack(new XPCJSContextStack()),
    mCallContext(nullptr),
    mAutoRoots(nullptr),
    mResolveName(JSID_VOID),
    mResolvingWrapper(nullptr),
@@ -3031,17 +3034,17 @@ XPCJSRuntime::XPCJSRuntime(nsXPConnect* 
     // compiling some chrome code. This causes the JS engine not save the source
     // code in memory. When the JS engine is asked to provide the source for a
     // function compiled with LAZY_SOURCE, it calls SourceHook to load it.
     ///
     // Note we do have to retain the source code in memory for scripts compiled in
     // compileAndGo mode and compiled function bodies (from
     // JS_CompileFunction*). In practice, this means content scripts and event
     // handlers.
-    JS_SetSourceHook(runtime, SourceHook);
+    js::SetSourceHook(runtime, new XPCJSSourceHook);
 
     // Set up locale information and callbacks for the newly-created runtime so
     // that the various toLocaleString() methods, localeCompare(), and other
     // internationalization APIs work as desired.
     if (!xpc_LocalizeRuntime(runtime))
         NS_RUNTIMEABORT("xpc_LocalizeRuntime failed.");
 
     NS_RegisterMemoryReporter(new JSMainRuntimeGCHeapReporter());
--- a/layout/base/nsLayoutUtils.cpp
+++ b/layout/base/nsLayoutUtils.cpp
@@ -5489,17 +5489,34 @@ nsLayoutUtils::UpdateImageVisibilityForF
     nsIScrollableFrame* sf = do_QueryFrame(f);
     if (sf) {
       nsRect transformedRect =
         nsLayoutUtils::TransformFrameRectToAncestor(rectFrame, rect, f);
       if (!sf->IsRectNearlyVisible(transformedRect)) {
         visible = false;
         break;
       }
-      rect = sf->GetScrollPortRect();
+      // Move transformedRect to be contained in the scrollport as best we can
+      // (it might not fit) to pretend that it was scrolled into view.
+      nsRect scrollPort = sf->GetScrollPortRect();
+      if (transformedRect.XMost() > scrollPort.XMost()) {
+        transformedRect.x -= transformedRect.XMost() - scrollPort.XMost();
+      }
+      if (transformedRect.x < scrollPort.x) {
+        transformedRect.x = scrollPort.x;
+      }
+      if (transformedRect.YMost() > scrollPort.YMost()) {
+        transformedRect.y -= transformedRect.YMost() - scrollPort.YMost();
+      }
+      if (transformedRect.y < scrollPort.y) {
+        transformedRect.y = scrollPort.y;
+      }
+      transformedRect.width = std::min(transformedRect.width, scrollPort.width);
+      transformedRect.height = std::min(transformedRect.height, scrollPort.height);
+      rect = transformedRect;
       rectFrame = f;
     }
     nsIFrame* parent = f->GetParent();
     if (!parent) {
       parent = nsLayoutUtils::GetCrossDocParentFrame(f);
       if (parent && parent->PresContext()->IsChrome()) {
         break;
       }
--- a/netwerk/base/src/ArrayBufferInputStream.h
+++ b/netwerk/base/src/ArrayBufferInputStream.h
@@ -2,17 +2,16 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef ArrayBufferInputStream_h
 #define ArrayBufferInputStream_h
 
 #include "nsIArrayBufferInputStream.h"
-#include "mozilla/Util.h"
 #include "js/Value.h"
 
 #define NS_ARRAYBUFFERINPUTSTREAM_CONTRACTID "@mozilla.org/io/arraybuffer-input-stream;1"
 #define NS_ARRAYBUFFERINPUTSTREAM_CID                \
 { /* 3014dde6-aa1c-41db-87d0-48764a3710f6 */       \
     0x3014dde6,                                      \
     0xaa1c,                                          \
     0x41db,                                          \
--- a/netwerk/base/src/BackgroundFileSaver.cpp
+++ b/netwerk/base/src/BackgroundFileSaver.cpp
@@ -1,24 +1,22 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set ts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
-#include "mozilla/RefPtr.h"
 #include "pk11pub.h"
 #include "ScopedNSSTypes.h"
 #include "secoidt.h"
 
 #include "nsIFile.h"
 #include "nsIPipe.h"
 #include "nsNetUtil.h"
 #include "nsThreadUtils.h"
-#include "nsXPCOMStrings.h"
 
 #include "BackgroundFileSaver.h"
 #include "mozilla/Telemetry.h"
 
 namespace mozilla {
 namespace net {
 
 ////////////////////////////////////////////////////////////////////////////////
--- a/netwerk/base/src/Dashboard.cpp
+++ b/netwerk/base/src/Dashboard.cpp
@@ -2,19 +2,23 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http:mozilla.org/MPL/2.0/. */
 
 #include "mozilla/dom/NetDashboardBinding.h"
 #include "mozilla/net/Dashboard.h"
 #include "mozilla/net/HttpInfo.h"
 #include "nsCxPusher.h"
 #include "nsHttp.h"
+#include "nsICancelable.h"
 #include "nsIDNSService.h"
+#include "nsIDNSRecord.h"
+#include "nsIInputStream.h"
+#include "nsISocketTransport.h"
 #include "nsIThread.h"
-#include "nsSocketTransport2.h"
+#include "nsSocketTransportService2.h"
 #include "nsThreadUtils.h"
 
 using mozilla::AutoSafeJSContext;
 namespace mozilla {
 namespace net {
 
 NS_IMPL_ISUPPORTS5(Dashboard, nsIDashboard, nsIDashboardEventNotifier,
                               nsITransportEventSink, nsITimerCallback,
--- a/netwerk/base/src/EventTokenBucket.cpp
+++ b/netwerk/base/src/EventTokenBucket.cpp
@@ -1,19 +1,23 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim:set ts=2 sw=2 sts=2 et cindent: */
 /* 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 "EventTokenBucket.h"
 
+#include "nsICancelable.h"
 #include "nsNetUtil.h"
 #include "nsSocketTransportService2.h"
-#include "nsThreadUtils.h"
+
+#ifdef DEBUG
+#include "MainThreadUtils.h"
+#endif
 
 #ifdef XP_WIN
 #include <windows.h>
 #include <mmsystem.h>
 #endif
 
 extern PRThread *gSocketThread;
 
--- a/netwerk/base/src/EventTokenBucket.h
+++ b/netwerk/base/src/EventTokenBucket.h
@@ -4,21 +4,22 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef NetEventTokenBucket_h__
 #define NetEventTokenBucket_h__
 
 #include "nsCOMPtr.h"
 #include "nsDeque.h"
-#include "nsICancelable.h"
 #include "nsITimer.h"
 
 #include "mozilla/TimeStamp.h"
 
+class nsICancelable;
+
 namespace mozilla {
 namespace net {
 
 /* A token bucket is used to govern the maximum rate a series of events
    can be executed at. For instance if your event was "eat a piece of cake"
    then a token bucket configured to allow "1 piece per day" would spread
    the eating of a 8 piece cake over 8 days even if you tried to eat the
    whole thing up front. In a practical sense it 'costs' 1 token to execute
--- a/netwerk/base/src/ProxyAutoConfig.cpp
+++ b/netwerk/base/src/ProxyAutoConfig.cpp
@@ -4,24 +4,25 @@
  * 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 "ProxyAutoConfig.h"
 #include "nsICancelable.h"
 #include "nsIDNSListener.h"
 #include "nsIDNSRecord.h"
 #include "nsIDNSService.h"
-#include "nsNetUtil.h"
 #include "nsThreadUtils.h"
 #include "nsIConsoleService.h"
 #include "nsJSUtils.h"
 #include "jsfriendapi.h"
 #include "prnetdb.h"
 #include "nsITimer.h"
 #include "mozilla/net/DNS.h"
+#include "nsServiceManagerUtils.h"
+#include "nsNetCID.h"
 
 namespace mozilla {
 namespace net {
 
 // These are some global helper symbols the PAC format requires that we provide that
 // are initialized as part of the global javascript context used for PAC evaluations.
 // Additionally dnsResolve(host) and myIpAddress() are supplied in the same context
 // but are implemented as c++ helpers. alert(msg) is similarly defined.
@@ -321,16 +322,24 @@ bool PACResolve(const nsCString &aHostNa
   if (!sRunning) {
     NS_WARNING("PACResolve without a running ProxyAutoConfig object");
     return false;
   }
 
   return sRunning->ResolveAddress(aHostName, aNetAddr, aTimeout);
 }
 
+ProxyAutoConfig::ProxyAutoConfig()
+  : mJSRuntime(nullptr)
+  , mJSNeedsSetup(false)
+  , mShutdown(false)
+{
+  MOZ_COUNT_CTOR(ProxyAutoConfig);
+}
+
 bool
 ProxyAutoConfig::ResolveAddress(const nsCString &aHostName,
                                 NetAddr *aNetAddr,
                                 unsigned int aTimeout)
 {
   nsCOMPtr<nsIDNSService> dns = do_GetService(NS_DNSSERVICE_CONTRACTID);
   if (!dns)
     return false;
--- a/netwerk/base/src/ProxyAutoConfig.h
+++ b/netwerk/base/src/ProxyAutoConfig.h
@@ -3,39 +3,35 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef ProxyAutoConfig_h__
 #define ProxyAutoConfig_h__
 
 #include "nsString.h"
-#include "prio.h"
-#include "nsITimer.h"
-#include "nsAutoPtr.h"
-#include "mozilla/net/DNS.h"
-#include "js/TypeDecls.h"
+#include "nsCOMPtr.h"
+
+class nsITimer;
+namespace JS {
+class Value;
+}
 
 namespace mozilla { namespace net {
 
 class JSRuntimeWrapper;
+union NetAddr;
 
 // The ProxyAutoConfig class is meant to be created and run on a
 // non main thread. It synchronously resolves PAC files by blocking that
 // thread and running nested event loops. GetProxyForURI is not re-entrant.
 
 class ProxyAutoConfig  {
 public:
-  ProxyAutoConfig()
-    : mJSRuntime(nullptr)
-    , mJSNeedsSetup(false)
-    , mShutdown(false)
-  {
-    MOZ_COUNT_CTOR(ProxyAutoConfig);
-  }
+  ProxyAutoConfig();
   ~ProxyAutoConfig();
 
   nsresult Init(const nsCString &aPACURI,
                 const nsCString &aPACScript);
   void     Shutdown();
   void     GC();
   bool     MyIPAddress(JS::Value *vp);
   bool     ResolveAddress(const nsCString &aHostName,
--- a/netwerk/base/src/Tickler.cpp
+++ b/netwerk/base/src/Tickler.cpp
@@ -1,22 +1,22 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
+#include "Tickler.h"
+
+#ifdef MOZ_USE_WIFI_TICKLER
 #include "nsComponentManagerUtils.h"
 #include "nsIPrefBranch.h"
 #include "nsIPrefService.h"
 #include "nsServiceManagerUtils.h"
+#include "nsThreadUtils.h"
 #include "prnetdb.h"
-#include "Tickler.h"
-#include "nsThreadUtils.h"
-
-#ifdef MOZ_USE_WIFI_TICKLER
 
 #include "AndroidBridge.h"
 
 namespace mozilla {
 namespace net {
 
 NS_IMPL_ISUPPORTS1(Tickler, nsISupportsWeakReference)
 
--- a/netwerk/base/src/Tickler.h
+++ b/netwerk/base/src/Tickler.h
@@ -22,33 +22,40 @@
 // complete quickly when on wifi - ARP, DNS, TCP handshake, SSL
 // handshake, HTTP headers, and the TCP slow start phase. The
 // transaction is given up to 400 miliseconds by default to get
 // through those phases before the tickler is disabled.
 //
 // The tickler only applies to wifi on mobile right now. Hopefully it
 // can also be restricted to particular handset models in the future.
 
+#if defined(ANDROID) && !defined(MOZ_B2G)
+#define MOZ_USE_WIFI_TICKLER
+#endif
+
+#include "mozilla/Attributes.h"
+#include "nsISupports.h"
+#include <stdint.h>
+
+#ifdef MOZ_USE_WIFI_TICKLER
 #include "mozilla/Mutex.h"
 #include "mozilla/TimeStamp.h"
 #include "nsAutoPtr.h"
 #include "nsISupports.h"
 #include "nsIThread.h"
 #include "nsITimer.h"
 #include "nsWeakReference.h"
+#include "prio.h"
 
 class nsIPrefBranch;
+#endif
 
 namespace mozilla {
 namespace net {
 
-#if defined(ANDROID) && !defined(MOZ_B2G)
-#define MOZ_USE_WIFI_TICKLER
-#endif
-
 #ifdef MOZ_USE_WIFI_TICKLER
 
 class Tickler MOZ_FINAL : public nsSupportsWeakReference
 {
 public:
   NS_DECL_THREADSAFE_ISUPPORTS
 
   // These methods are main thread only
--- a/netwerk/base/src/nsAsyncStreamCopier.cpp
+++ b/netwerk/base/src/nsAsyncStreamCopier.cpp
@@ -1,17 +1,16 @@
 /* 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 "nsAsyncStreamCopier.h"
 #include "nsIOService.h"
-#include "nsAsyncStreamCopier.h"
 #include "nsIEventTarget.h"
 #include "nsStreamUtils.h"
-#include "nsNetSegmentUtils.h"
 #include "nsNetUtil.h"
 #include "prlog.h"
 
 using namespace mozilla;
 
 #if defined(PR_LOGGING)
 //
 // NSPR_LOG_MODULES=nsStreamCopier:5
--- a/netwerk/base/src/nsAsyncStreamCopier.h
+++ b/netwerk/base/src/nsAsyncStreamCopier.h
@@ -1,23 +1,22 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef nsAsyncStreamCopier_h__
 #define nsAsyncStreamCopier_h__
 
 #include "nsIAsyncStreamCopier.h"
-#include "nsIAsyncInputStream.h"
-#include "nsIAsyncOutputStream.h"
-#include "nsIRequestObserver.h"
 #include "mozilla/Mutex.h"
 #include "nsStreamUtils.h"
 #include "nsCOMPtr.h"
 
+class nsIRequestObserver;
+
 //-----------------------------------------------------------------------------
 
 class nsAsyncStreamCopier : public nsIAsyncStreamCopier
 {
 public:
     NS_DECL_THREADSAFE_ISUPPORTS
     NS_DECL_NSIREQUEST
     NS_DECL_NSIASYNCSTREAMCOPIER
--- a/netwerk/base/src/nsBaseChannel.cpp
+++ b/netwerk/base/src/nsBaseChannel.cpp
@@ -1,19 +1,17 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
 /* 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 "nsBaseChannel.h"
-#include "nsChannelProperties.h"
 #include "nsURLHelper.h"
 #include "nsNetUtil.h"
 #include "nsMimeTypes.h"
-#include "nsIOService.h"
 #include "nsIHttpEventSink.h"
 #include "nsIHttpChannel.h"
 #include "nsIChannelEventSink.h"
 #include "nsIStreamConverterService.h"
 #include "nsChannelClassifier.h"
 #include "nsAsyncRedirectVerifyHelper.h"
 
 static PLDHashOperator
--- a/netwerk/base/src/nsBaseChannel.h
+++ b/netwerk/base/src/nsBaseChannel.h
@@ -8,28 +8,29 @@
 
 #include "nsString.h"
 #include "nsAutoPtr.h"
 #include "nsCOMPtr.h"
 #include "nsHashPropertyBag.h"
 #include "nsInputStreamPump.h"
 
 #include "nsIChannel.h"
-#include "nsIInputStream.h"
 #include "nsIURI.h"
 #include "nsILoadGroup.h"
 #include "nsIStreamListener.h"
 #include "nsIInterfaceRequestor.h"
 #include "nsIProgressEventSink.h"
 #include "nsITransport.h"
 #include "nsIAsyncVerifyRedirectCallback.h"
 #include "PrivateBrowsingChannel.h"
 #include "nsThreadUtils.h"
 #include "nsNetUtil.h"
 
+class nsIInputStream;
+
 //-----------------------------------------------------------------------------
 // nsBaseChannel is designed to be subclassed.  The subclass is responsible for
 // implementing the OpenContentStream method, which will be called by the
 // nsIChannel::AsyncOpen and nsIChannel::Open implementations.
 //
 // nsBaseChannel implements nsIInterfaceRequestor to provide a convenient way
 // for subclasses to query both the nsIChannel::notificationCallbacks and
 // nsILoadGroup::notificationCallbacks for supported interfaces.
--- a/netwerk/base/src/nsBufferedStreams.cpp
+++ b/netwerk/base/src/nsBufferedStreams.cpp
@@ -1,19 +1,17 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
 /* 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 "ipc/IPCMessageUtils.h"
 
-#include "nsAlgorithm.h"
 #include "nsBufferedStreams.h"
 #include "nsStreamUtils.h"
-#include "nsCRT.h"
 #include "nsNetCID.h"
 #include "nsIClassInfoImpl.h"
 #include "mozilla/ipc/InputStreamUtils.h"
 #include <algorithm>
 
 #ifdef DEBUG_brendan
 # define METERING
 #endif
--- a/netwerk/base/src/nsChannelClassifier.h
+++ b/netwerk/base/src/nsChannelClassifier.h
@@ -1,17 +1,16 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef nsChannelClassifier_h__
 #define nsChannelClassifier_h__
 
 #include "nsIURIClassifier.h"
-#include "nsIRunnable.h"
 #include "nsCOMPtr.h"
 #include "mozilla/Attributes.h"
 
 class nsIChannel;
 
 
 class nsChannelClassifier MOZ_FINAL : public nsIURIClassifierCallback
 {
--- a/netwerk/base/src/nsDNSPrefetch.cpp
+++ b/netwerk/base/src/nsDNSPrefetch.cpp
@@ -2,22 +2,20 @@
 /* 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 "nsDNSPrefetch.h"
 #include "nsCOMPtr.h"
 #include "nsString.h"
 
-#include "nsNetUtil.h"
-
 #include "nsIDNSListener.h"
-#include "nsIDNSRecord.h"
 #include "nsIDNSService.h"
 #include "nsICancelable.h"
+#include "nsIURI.h"
 
 static nsIDNSService *sDNSService = nullptr;
 
 nsresult
 nsDNSPrefetch::Initialize(nsIDNSService *aDNSService)
 {
     NS_IF_RELEASE(sDNSService);
     sDNSService =  aDNSService;
--- a/netwerk/base/src/nsDNSPrefetch.h
+++ b/netwerk/base/src/nsDNSPrefetch.h
@@ -1,17 +1,16 @@
 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef nsDNSPrefetch_h___
 #define nsDNSPrefetch_h___
 
-#include "nsCOMPtr.h"
 #include "nsString.h"
 #include "mozilla/TimeStamp.h"
 #include "mozilla/Attributes.h"
 
 #include "nsIDNSListener.h"
 
 class nsIURI;
 class nsIDNSService;
--- a/netwerk/base/src/nsDirectoryIndexStream.cpp
+++ b/netwerk/base/src/nsDirectoryIndexStream.cpp
@@ -11,33 +11,30 @@
   Lou Montulli's original spec:
 
   http://www.mozilla.org/projects/netlib/dirindexformat.html
 
  */
 
 #include "nsEscape.h"
 #include "nsDirectoryIndexStream.h"
-#include "nsXPIDLString.h"
-#include "prio.h"
 #include "prlog.h"
 #ifdef PR_LOGGING
 static PRLogModuleInfo* gLog;
 #endif
 
 #include "nsISimpleEnumerator.h"
+#ifdef THREADSAFE_I18N
+#include "nsCollationCID.h"
 #include "nsICollation.h"
 #include "nsILocale.h"
 #include "nsILocaleService.h"
-#include "nsCollationCID.h"
-#include "nsIPlatformCharset.h"
-#include "nsReadableUtils.h"
+#endif
+#include "nsIFile.h"
 #include "nsURLHelper.h"
-#include "nsNetUtil.h"
-#include "nsCRT.h"
 #include "nsNativeCharsetUtils.h"
 
 // NOTE: This runs on the _file transport_ thread.
 // The problem is that now that we're actually doing something with the data,
 // we want to do stuff like i18n sorting. However, none of the collation stuff
 // is threadsafe.
 // So THIS CODE IS ASCII ONLY!!!!!!!! This is no worse than the current
 // behaviour, though. See bug 99382.
--- a/netwerk/base/src/nsDirectoryIndexStream.h
+++ b/netwerk/base/src/nsDirectoryIndexStream.h
@@ -3,22 +3,21 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef nsDirectoryIndexStream_h__
 #define nsDirectoryIndexStream_h__
 
 #include "mozilla/Attributes.h"
 
-#include "nsIFile.h"
 #include "nsString.h"
 #include "nsIInputStream.h"
-#include "nsCOMPtr.h"
 #include "nsCOMArray.h"
-#include "nsITextToSubURI.h"
+
+class nsIFile;
 
 class nsDirectoryIndexStream MOZ_FINAL : public nsIInputStream
 {
 private:
     nsCString mBuf;
     int32_t mOffset;
     nsresult mStatus;
 
--- a/netwerk/base/src/nsDownloader.h
+++ b/netwerk/base/src/nsDownloader.h
@@ -1,20 +1,21 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef nsDownloader_h__
 #define nsDownloader_h__
 
 #include "nsIDownloader.h"
-#include "nsIOutputStream.h"
-#include "nsIFile.h"
 #include "nsCOMPtr.h"
 
+class nsIFile;
+class nsIOutputStream;
+
 class nsDownloader : public nsIDownloader
 {
 public:
     NS_DECL_ISUPPORTS
     NS_DECL_NSIDOWNLOADER
     NS_DECL_NSIREQUESTOBSERVER
     NS_DECL_NSISTREAMLISTENER
 
--- a/netwerk/base/src/nsFileStreams.cpp
+++ b/netwerk/base/src/nsFileStreams.cpp
@@ -14,26 +14,21 @@
 #include <os2.h>
 #else
 // XXX add necessary include file for ftruncate (or equivalent)
 #endif
 
 #include "private/pprio.h"
 
 #include "nsFileStreams.h"
-#include "nsXPIDLString.h"
-#include "prerror.h"
-#include "nsCRT.h"
 #include "nsIFile.h"
-#include "nsDirectoryIndexStream.h"
-#include "nsMimeTypes.h"
 #include "nsReadLine.h"
-#include "nsNetUtil.h"
 #include "nsIClassInfoImpl.h"
 #include "mozilla/ipc/InputStreamUtils.h"
+#include "nsNetCID.h"
 
 #define NS_NO_INPUT_BUFFERING 1 // see http://bugzilla.mozilla.org/show_bug.cgi?id=41067
 
 typedef mozilla::ipc::FileDescriptor::PlatformHandleType FileHandleType;
 
 using namespace mozilla::ipc;
 
 ////////////////////////////////////////////////////////////////////////////////
--- a/netwerk/base/src/nsFileStreams.h
+++ b/netwerk/base/src/nsFileStreams.h
@@ -1,28 +1,25 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef nsFileStreams_h__
 #define nsFileStreams_h__
 
-#include "nsAlgorithm.h"
 #include "nsAutoPtr.h"
 #include "nsIFileStreams.h"
 #include "nsIFile.h"
 #include "nsIInputStream.h"
 #include "nsIOutputStream.h"
 #include "nsISafeOutputStream.h"
 #include "nsISeekableStream.h"
 #include "nsILineInputStream.h"
 #include "nsCOMPtr.h"
-#include "prlog.h"
-#include "prio.h"
 #include "nsIIPCSerializableInputStream.h"
 #include "nsReadLine.h"
 #include <algorithm>
 
 
 ////////////////////////////////////////////////////////////////////////////////
 
 class nsFileStreamBase : public nsISeekableStream,
--- a/netwerk/base/src/nsIOService.cpp
+++ b/netwerk/base/src/nsIOService.cpp
@@ -5,50 +5,43 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "mozilla/DebugOnly.h"
 
 #include "nsIOService.h"
 #include "nsIProtocolHandler.h"
 #include "nsIFileProtocolHandler.h"
 #include "nscore.h"
-#include "nsIServiceManager.h"
 #include "nsIURI.h"
-#include "nsIStreamListener.h"
 #include "prprf.h"
-#include "prlog.h"
-#include "nsLoadGroup.h"
-#include "nsInputStreamChannel.h"
-#include "nsXPIDLString.h" 
-#include "nsReadableUtils.h"
-#include "nsIErrorService.h" 
+#include "nsIErrorService.h"
 #include "netCore.h"
 #include "nsIObserverService.h"
 #include "nsIPrefService.h"
-#include "nsIPrefLocalizedString.h"
-#include "nsICategoryManager.h"
 #include "nsXPCOM.h"
-#include "nsISupportsPrimitives.h"
 #include "nsIProxiedProtocolHandler.h"
 #include "nsIProxyInfo.h"
 #include "nsEscape.h"
 #include "nsNetCID.h"
-#include "nsISocketTransport.h"
 #include "nsCRT.h"
 #include "nsSimpleNestedURI.h"
 #include "nsNetUtil.h"
-#include "nsThreadUtils.h"
-#include "nsIPermissionManager.h"
 #include "nsTArray.h"
 #include "nsIConsoleService.h"
 #include "nsIUploadChannel2.h"
 #include "nsXULAppAPI.h"
-#include "nsIProxiedChannel.h"
 #include "nsIProtocolProxyCallback.h"
 #include "nsICancelable.h"
+#include "nsINetworkLinkService.h"
+#include "nsPISocketTransportService.h"
+#include "nsAsyncRedirectVerifyHelper.h"
+#include "nsURLHelper.h"
+#include "nsPIDNSService.h"
+#include "nsIProtocolProxyService2.h"
+#include "MainThreadUtils.h"
 
 #if defined(XP_WIN)
 #include "nsNativeConnectionHelper.h"
 #endif
 
 using namespace mozilla;
 
 #define PORT_PREF_PREFIX           "network.security.ports."
--- a/netwerk/base/src/nsIOService.h
+++ b/netwerk/base/src/nsIOService.h
@@ -1,50 +1,46 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef nsIOService_h__
 #define nsIOService_h__
 
-#include "necko-config.h"
-
-#include "nsString.h"
+#include "nsStringFwd.h"
 #include "nsIIOService2.h"
 #include "nsTArray.h"
-#include "nsPISocketTransportService.h" 
-#include "nsPIDNSService.h" 
-#include "nsIProtocolProxyService2.h"
 #include "nsCOMPtr.h"
-#include "nsURLHelper.h"
 #include "nsWeakPtr.h"
-#include "nsIURLParser.h"
 #include "nsIObserver.h"
 #include "nsWeakReference.h"
 #include "nsINetUtil.h"
 #include "nsIChannelEventSink.h"
-#include "nsIContentSniffer.h"
 #include "nsCategoryCache.h"
-#include "nsINetworkLinkService.h"
-#include "nsAsyncRedirectVerifyHelper.h"
 #include "nsISpeculativeConnect.h"
 #include "mozilla/Attributes.h"
 
 #define NS_N(x) (sizeof(x)/sizeof(*x))
 
 // We don't want to expose this observer topic.
 // Intended internal use only for remoting offline/inline events.
 // See Bug 552829
 #define NS_IPC_IOSERVICE_SET_OFFLINE_TOPIC "ipc:network:set-offline"
 
 static const char gScheme[][sizeof("resource")] =
     {"chrome", "file", "http", "jar", "resource"};
 
+class nsAsyncRedirectVerifyHelper;
+class nsINetworkLinkService;
 class nsIPrefBranch;
+class nsIProtocolProxyService2;
+class nsIProxyInfo;
+class nsPIDNSService;
+class nsPISocketTransportService;
 
 class nsIOService MOZ_FINAL : public nsIIOService2
                             , public nsIObserver
                             , public nsINetUtil
                             , public nsISpeculativeConnect
                             , public nsSupportsWeakReference
 {
 public:
--- a/netwerk/base/src/nsIncrementalDownload.cpp
+++ b/netwerk/base/src/nsIncrementalDownload.cpp
@@ -9,24 +9,21 @@
 #include "nsIIncrementalDownload.h"
 #include "nsIRequestObserver.h"
 #include "nsIProgressEventSink.h"
 #include "nsIChannelEventSink.h"
 #include "nsIAsyncVerifyRedirectCallback.h"
 #include "nsIInterfaceRequestor.h"
 #include "nsIObserverService.h"
 #include "nsIObserver.h"
-#include "nsIPropertyBag2.h"
-#include "nsIServiceManager.h"
 #include "nsIFile.h"
 #include "nsITimer.h"
 #include "nsNetUtil.h"
 #include "nsAutoPtr.h"
 #include "nsWeakReference.h"
-#include "nsChannelProperties.h"
 #include "prio.h"
 #include "prprf.h"
 #include <algorithm>
 
 // Default values used to initialize a nsIncrementalDownload object.
 #define DEFAULT_CHUNK_SIZE (4096 * 16)  // bytes
 #define DEFAULT_INTERVAL    60          // seconds
 
--- a/netwerk/base/src/nsInputStreamPump.cpp
+++ b/netwerk/base/src/nsInputStreamPump.cpp
@@ -1,30 +1,27 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
 /* vim:set ts=4 sts=4 sw=4 et cin: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
-#include "mozilla/DebugOnly.h"
 #include "nsIOService.h"
 #include "nsInputStreamPump.h"
-#include "nsIServiceManager.h"
 #include "nsIStreamTransportService.h"
-#include "nsIInterfaceRequestorUtils.h"
 #include "nsISeekableStream.h"
 #include "nsITransport.h"
 #include "nsIThreadRetargetableStreamListener.h"
-#include "nsStreamUtils.h"
-#include "nsNetUtil.h"
 #include "nsThreadUtils.h"
 #include "nsCOMPtr.h"
 #include "prlog.h"
-#include "nsPrintfCString.h"
 #include "GeckoProfiler.h"
+#include "nsIStreamListener.h"
+#include "nsILoadGroup.h"
+#include "nsNetCID.h"
 #include <algorithm>
 
 static NS_DEFINE_CID(kStreamTransportServiceCID, NS_STREAMTRANSPORTSERVICE_CID);
 
 #if defined(PR_LOGGING)
 //
 // NSPR_LOG_MODULES=nsStreamPump:5
 //
--- a/netwerk/base/src/nsInputStreamPump.h
+++ b/netwerk/base/src/nsInputStreamPump.h
@@ -2,28 +2,25 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef nsInputStreamPump_h__
 #define nsInputStreamPump_h__
 
 #include "nsIInputStreamPump.h"
-#include "nsIInputStream.h"
-#include "nsIURI.h"
-#include "nsILoadGroup.h"
-#include "nsIStreamListener.h"
-#include "nsIInterfaceRequestor.h"
-#include "nsIProgressEventSink.h"
 #include "nsIAsyncInputStream.h"
-#include "nsIThread.h"
 #include "nsIThreadRetargetableRequest.h"
 #include "nsCOMPtr.h"
 #include "mozilla/Attributes.h"
 
+class nsIInputStream;
+class nsILoadGroup;
+class nsIStreamListener;
+
 class nsInputStreamPump MOZ_FINAL : public nsIInputStreamPump
                                   , public nsIInputStreamCallback
                                   , public nsIThreadRetargetableRequest
 {
 public:
     NS_DECL_THREADSAFE_ISUPPORTS
     NS_DECL_NSIREQUEST
     NS_DECL_NSIINPUTSTREAMPUMP
--- a/netwerk/base/src/nsLoadGroup.cpp
+++ b/netwerk/base/src/nsLoadGroup.cpp
@@ -5,32 +5,27 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "mozilla/DebugOnly.h"
 
 #include "nsLoadGroup.h"
 
 #include "nsArrayEnumerator.h"
 #include "nsCOMArray.h"
-#include "nsEnumeratorUtils.h"
-#include "nsIServiceManager.h"
 #include "nsCOMPtr.h"
-#include "nsIURI.h"
 #include "prlog.h"
-#include "nsCRT.h"
-#include "netCore.h"
-#include "nsXPIDLString.h"
-#include "nsReadableUtils.h"
 #include "nsString.h"
 #include "nsTArray.h"
-#include "nsIHttpChannelInternal.h"
 #include "mozilla/Atomics.h"
 #include "mozilla/Telemetry.h"
 #include "nsAutoPtr.h"
 #include "mozilla/net/PSpdyPush3.h"
+#include "nsITimedChannel.h"
+#include "nsIInterfaceRequestor.h"
+#include "nsIRequestObserver.h"
 
 using namespace mozilla;
 
 #if defined(PR_LOGGING)
 //
 // Log module for nsILoadGroup logging...
 //
 // To enable logging (see prlog.h for full details):
--- a/netwerk/base/src/nsLoadGroup.h
+++ b/netwerk/base/src/nsLoadGroup.h
@@ -4,30 +4,26 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef nsLoadGroup_h__
 #define nsLoadGroup_h__
 
 #include "nsILoadGroup.h"
 #include "nsILoadGroupChild.h"
 #include "nsPILoadGroupInternal.h"
-#include "nsIChannel.h"
-#include "nsIStreamListener.h"
 #include "nsAgg.h"
 #include "nsCOMPtr.h"
 #include "nsWeakPtr.h"
 #include "nsWeakReference.h"
-#include "nsIInterfaceRequestor.h"
-#include "nsIInterfaceRequestorUtils.h"
 #include "nsISupportsPriority.h"
-#include "nsITimedChannel.h"
 #include "pldhash.h"
 #include "mozilla/TimeStamp.h"
 
-class  nsILoadGroupConnectionInfo;
+class nsILoadGroupConnectionInfo;
+class nsITimedChannel;
 
 class nsLoadGroup : public nsILoadGroup,
                     public nsILoadGroupChild,
                     public nsISupportsPriority,
                     public nsSupportsWeakReference,
                     public nsPILoadGroupInternal
 {
 public:
--- a/netwerk/base/src/nsMediaFragmentURIParser.cpp
+++ b/netwerk/base/src/nsMediaFragmentURIParser.cpp
@@ -2,16 +2,17 @@
 /* vim:set ts=2 sw=2 sts=2 et cindent: */
 /* 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 "nsTArray.h"
 #include "nsCharSeparatedTokenizer.h"
 #include "nsEscape.h"
+#include "nsIURI.h"
 #include <utility>
 
 #include "nsMediaFragmentURIParser.h"
 
 using std::pair;
 using std::make_pair;
 
 namespace mozilla { namespace net {
--- a/netwerk/base/src/nsMediaFragmentURIParser.h
+++ b/netwerk/base/src/nsMediaFragmentURIParser.h
@@ -2,20 +2,21 @@
 /* vim:set ts=2 sw=2 sts=2 et cindent: */
 /* 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/. */
 #if !defined(nsMediaFragmentURIParser_h__)
 #define nsMediaFragmentURIParser_h__
 
 #include "mozilla/Maybe.h"
-#include "nsIURI.h"
-#include "nsString.h"
+#include "nsStringFwd.h"
 #include "nsRect.h"
 
+class nsIURI;
+
 // Class to handle parsing of a W3C media fragment URI as per
 // spec at: http://www.w3.org/TR/media-frags/
 // Only the temporaral URI portion of the spec is implemented.
 // To use:
 // a) Construct an instance with the URI containing the fragment
 // b) Check for the validity of the values you are interested in
 //    using e.g. HasStartTime().
 // c) If the values are valid, obtain them using e.g. GetStartTime().
--- a/netwerk/base/src/nsNetAddr.cpp
+++ b/netwerk/base/src/nsNetAddr.cpp
@@ -1,17 +1,16 @@
 /* vim: et ts=2 sw=2 tw=80 
  */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "nsNetAddr.h"
 #include "nsString.h"
-#include "prnetdb.h"
 #include "mozilla/net/DNS.h"
 
 using namespace mozilla::net;
 
 NS_IMPL_ISUPPORTS1(nsNetAddr, nsINetAddr)
 
 /* Makes a copy of |addr| */
 nsNetAddr::nsNetAddr(NetAddr* addr)
--- a/netwerk/base/src/nsPACMan.cpp
+++ b/netwerk/base/src/nsPACMan.cpp
@@ -7,20 +7,18 @@
 #include "nsPACMan.h"
 #include "nsThreadUtils.h"
 #include "nsIAuthPrompt.h"
 #include "nsIPromptFactory.h"
 #include "nsIHttpChannel.h"
 #include "nsIPrefService.h"
 #include "nsIPrefBranch.h"
 #include "nsNetUtil.h"
-#include "nsCRT.h"
-#include "prmon.h"
 #include "nsIAsyncVerifyRedirectCallback.h"
-#include "nsProxyRelease.h"
+#include "nsISystemProxySettings.h"
 
 //-----------------------------------------------------------------------------
 using namespace mozilla;
 using namespace mozilla::net;
 
 #include "prlog.h"
 #if defined(PR_LOGGING)
 static PRLogModuleInfo *
--- a/netwerk/base/src/nsPACMan.h
+++ b/netwerk/base/src/nsPACMan.h
@@ -6,29 +6,28 @@
 
 #ifndef nsPACMan_h__
 #define nsPACMan_h__
 
 #include "nsIStreamLoader.h"
 #include "nsIInterfaceRequestor.h"
 #include "nsIChannelEventSink.h"
 #include "ProxyAutoConfig.h"
-#include "nsICancelable.h"
 #include "nsThreadUtils.h"
 #include "nsIURI.h"
 #include "nsCOMPtr.h"
 #include "nsString.h"
 #include "mozilla/Attributes.h"
 #include "mozilla/LinkedList.h"
-#include "nsIThread.h"
 #include "nsAutoPtr.h"
-#include "nsISystemProxySettings.h"
 #include "mozilla/TimeStamp.h"
 
 class nsPACMan;
+class nsISystemProxySettings;
+class nsIThread;
 
 /**
  * This class defines a callback interface used by AsyncGetProxyForURI.
  */
 class NS_NO_VTABLE nsPACManCallback : public nsISupports
 {
 public:
   /**
--- a/netwerk/base/src/nsPreloadedStream.cpp
+++ b/netwerk/base/src/nsPreloadedStream.cpp
@@ -2,17 +2,16 @@
 /* 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 "nsPreloadedStream.h"
 #include "nsIRunnable.h"
 
 #include "nsThreadUtils.h"
-#include "nsAlgorithm.h"
 #include <algorithm>
    
 namespace mozilla {
 namespace net {
 
 NS_IMPL_ISUPPORTS2(nsPreloadedStream,
                    nsIInputStream,
                    nsIAsyncInputStream)
--- a/netwerk/base/src/nsProtocolProxyService.cpp
+++ b/netwerk/base/src/nsProtocolProxyService.cpp
@@ -5,38 +5,35 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "mozilla/Attributes.h"
 #include "mozilla/Util.h"
 
 #include "nsProtocolProxyService.h"
 #include "nsProxyInfo.h"
 #include "nsIClassInfoImpl.h"
-#include "nsIServiceManager.h"
-#include "nsXPIDLString.h"
 #include "nsIIOService.h"
 #include "nsIObserverService.h"
 #include "nsIProtocolHandler.h"
 #include "nsIProtocolProxyCallback.h"
 #include "nsICancelable.h"
 #include "nsIDNSService.h"
 #include "nsPIDNSService.h"
 #include "nsIPrefService.h"
 #include "nsIPrefBranch.h"
-#include "nsReadableUtils.h"
 #include "nsThreadUtils.h"
 #include "nsString.h"
 #include "nsNetUtil.h"
 #include "nsNetCID.h"
-#include "nsCRT.h"
 #include "prnetdb.h"
 #include "nsPACMan.h"
 #include "nsProxyRelease.h"
 #include "mozilla/Mutex.h"
 #include "mozilla/CondVar.h"
+#include "nsISystemProxySettings.h"
 
 //----------------------------------------------------------------------------
 
 using namespace mozilla;
 
 #include "prlog.h"
 #if defined(PR_LOGGING)
 static PRLogModuleInfo *
--- a/netwerk/base/src/nsProtocolProxyService.h
+++ b/netwerk/base/src/nsProtocolProxyService.h
@@ -5,33 +5,32 @@
  
 #ifndef nsProtocolProxyService_h__
 #define nsProtocolProxyService_h__
 
 #include "nsString.h"
 #include "nsCOMPtr.h"
 #include "nsAutoPtr.h"
 #include "nsTArray.h"
-#include "nsIPrefBranch.h"
 #include "nsIProtocolProxyService2.h"
 #include "nsIProtocolProxyFilter.h"
-#include "nsISystemProxySettings.h"
 #include "nsIProxyInfo.h"
 #include "nsIObserver.h"
 #include "nsDataHashtable.h"
 #include "nsHashKeys.h"
-#include "nsPACMan.h"
-#include "prtime.h"
 #include "prio.h"
 #include "mozilla/Attributes.h"
 
 typedef nsDataHashtable<nsCStringHashKey, uint32_t> nsFailedProxyTable;
 
 class nsProxyInfo;
 struct nsProtocolInfo;
+class nsIPrefBranch;
+class nsISystemProxySettings;
+class nsPACMan;
 
 class nsProtocolProxyService MOZ_FINAL : public nsIProtocolProxyService2
                                        , public nsIObserver
 {
 public:
     NS_DECL_ISUPPORTS
     NS_DECL_NSIPROTOCOLPROXYSERVICE2
     NS_DECL_NSIPROTOCOLPROXYSERVICE
--- a/netwerk/base/src/nsRequestObserverProxy.cpp
+++ b/netwerk/base/src/nsRequestObserverProxy.cpp
@@ -3,19 +3,17 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "mozilla/DebugOnly.h"
 
 #include "nscore.h"
 #include "nsRequestObserverProxy.h"
 #include "nsIRequest.h"
-#include "nsIServiceManager.h"
 #include "nsAutoPtr.h"
-#include "nsString.h"
 #include "prlog.h"
 
 using namespace mozilla;
 
 #if defined(PR_LOGGING)
 static PRLogModuleInfo *gRequestObserverProxyLog;
 #endif
 
--- a/netwerk/base/src/nsSerializationHelper.h
+++ b/netwerk/base/src/nsSerializationHelper.h
@@ -9,17 +9,16 @@
 #ifndef NSSERIALIZATIONHELPER_H_
 #define NSSERIALIZATIONHELPER_H_
 
 #include "nsStringFwd.h"
 #include "nsISerializationHelper.h"
 #include "mozilla/Attributes.h"
 
 class nsISerializable;
-class nsISupports;
 
 /**
  * Serialize an object to an ASCII string.
  */
 nsresult NS_SerializeToString(nsISerializable* obj,
                               nsCSubstring& str);
 
 /**
--- a/netwerk/base/src/nsServerSocket.cpp
+++ b/netwerk/base/src/nsServerSocket.cpp
@@ -1,14 +1,13 @@
 /* vim:set ts=2 sw=2 et cindent: */
 /* 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 "nsIServiceManager.h"
 #include "nsSocketTransport2.h"
 #include "nsServerSocket.h"
 #include "nsProxyRelease.h"
 #include "nsAutoPtr.h"
 #include "nsError.h"
 #include "nsNetCID.h"
 #include "prnetdb.h"
 #include "prio.h"
--- a/netwerk/base/src/nsServerSocket.h
+++ b/netwerk/base/src/nsServerSocket.h
@@ -1,18 +1,18 @@
 /* vim:set ts=2 sw=2 et cindent: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef nsServerSocket_h__
 #define nsServerSocket_h__
 
+#include "nsASocketHandler.h"
 #include "nsIServerSocket.h"
-#include "nsSocketTransportService2.h"
 #include "mozilla/Mutex.h"
 
 //-----------------------------------------------------------------------------
 
 class nsServerSocket : public nsASocketHandler
                      , public nsIServerSocket
 {
 public:
--- a/netwerk/base/src/nsSimpleURI.cpp
+++ b/netwerk/base/src/nsSimpleURI.cpp
@@ -4,20 +4,18 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "mozilla/DebugOnly.h"
 
 #include "IPCMessageUtils.h"
 
 #include "nsSimpleURI.h"
 #include "nscore.h"
-#include "nsCRT.h"
 #include "nsString.h"
-#include "nsReadableUtils.h"
-#include "prprf.h"
+#include "plstr.h"
 #include "nsURLHelper.h"
 #include "nsNetCID.h"
 #include "nsIObjectInputStream.h"
 #include "nsIObjectOutputStream.h"
 #include "nsEscape.h"
 #include "nsError.h"
 #include "nsIProgrammingLanguage.h"
 #include "nsIIPCSerializableURI.h"
--- a/netwerk/base/src/nsSimpleURI.h
+++ b/netwerk/base/src/nsSimpleURI.h
@@ -2,18 +2,17 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef nsSimpleURI_h__
 #define nsSimpleURI_h__
 
 #include "mozilla/MemoryReporting.h"
-#include "nsIURL.h"
-#include "nsAgg.h"
+#include "nsIURI.h"
 #include "nsISerializable.h"
 #include "nsString.h"
 #include "nsIClassInfo.h"
 #include "nsIMutable.h"
 #include "nsISizeOf.h"
 #include "nsIIPCSerializableURI.h"
 
 #define NS_THIS_SIMPLEURI_IMPLEMENTATION_CID         \
--- a/netwerk/base/src/nsSocketTransport2.cpp
+++ b/netwerk/base/src/nsSocketTransport2.cpp
@@ -15,31 +15,32 @@
 #include "nsNetSegmentUtils.h"
 #include "nsNetAddr.h"
 #include "nsTransportUtils.h"
 #include "nsProxyInfo.h"
 #include "nsNetCID.h"
 #include "nsNetUtil.h"
 #include "nsAutoPtr.h"
 #include "nsCOMPtr.h"
-#include "netCore.h"
 #include "plstr.h"
-#include "prnetdb.h"
 #include "prerr.h"
 #include "NetworkActivityMonitor.h"
 #include "mozilla/VisualEventTracer.h"
 #include "nsThreadUtils.h"
-#include "nsIServiceManager.h"
 #include "nsISocketProviderService.h"
 #include "nsISocketProvider.h"
 #include "nsISSLSocketControl.h"
 #include "nsINSSErrorsService.h"
 #include "nsIPipe.h"
 #include "nsIProgrammingLanguage.h"
 #include "nsIClassInfoImpl.h"
+#include "nsURLHelper.h"
+#include "nsIDNSService.h"
+#include "nsIDNSRecord.h"
+#include "nsICancelable.h"
 #include <algorithm>
 
 #if defined(XP_WIN)
 #include "nsNativeConnectionHelper.h"
 #endif
 
 using namespace mozilla;
 using namespace mozilla::net;
--- a/netwerk/base/src/nsSocketTransport2.h
+++ b/netwerk/base/src/nsSocketTransport2.h
@@ -10,28 +10,29 @@
 #endif
 
 #include "mozilla/Mutex.h"
 #include "nsSocketTransportService2.h"
 #include "nsString.h"
 #include "nsCOMPtr.h"
 
 #include "nsISocketTransport.h"
-#include "nsIInterfaceRequestor.h"
 #include "nsIAsyncInputStream.h"
 #include "nsIAsyncOutputStream.h"
 #include "nsIDNSListener.h"
-#include "nsIDNSRecord.h"
-#include "nsICancelable.h"
 #include "nsIClassInfo.h"
 #include "mozilla/net/DNS.h"
+#include "nsASocketHandler.h"
 
 #include "prerror.h"
 
 class nsSocketTransport;
+class nsICancelable;
+class nsIDNSRecord;
+class nsIInterfaceRequestor;
 
 nsresult
 ErrorAccordingToNSPR(PRErrorCode errorCode);
 
 //-----------------------------------------------------------------------------
 
 // after this short interval, we will return to PR_Poll
 #define NS_SOCKET_CONNECT_TIMEOUT PR_MillisecondsToInterval(20)
--- a/netwerk/base/src/nsSocketTransportService2.cpp
+++ b/netwerk/base/src/nsSocketTransportService2.cpp
@@ -4,25 +4,22 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifdef MOZ_LOGGING
 #define FORCE_PR_LOG
 #endif
 
 #include "nsSocketTransportService2.h"
 #include "nsSocketTransport2.h"
-#include "nsReadableUtils.h"
 #include "nsError.h"
 #include "prnetdb.h"
 #include "prerror.h"
-#include "plstr.h"
 #include "nsIPrefService.h"
 #include "nsIPrefBranch.h"
 #include "nsServiceManagerUtils.h"
-#include "nsIOService.h"
 #include "NetworkActivityMonitor.h"
 #include "nsIObserverService.h"
 #include "mozilla/Services.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/Likely.h"
 #include "mozilla/PublicSSL.h"
 #include "nsThreadUtils.h"
 
--- a/netwerk/base/src/nsSocketTransportService2.h
+++ b/netwerk/base/src/nsSocketTransportService2.h
@@ -6,26 +6,25 @@
 #ifndef nsSocketTransportService2_h__
 #define nsSocketTransportService2_h__
 
 #include "nsPISocketTransportService.h"
 #include "nsIThreadInternal.h"
 #include "nsIRunnable.h"
 #include "nsEventQueue.h"
 #include "nsCOMPtr.h"
-#include "pldhash.h"
 #include "prinrval.h"
 #include "prlog.h"
 #include "prinit.h"
-#include "prio.h"
-#include "nsASocketHandler.h"
 #include "nsIObserver.h"
 #include "mozilla/Mutex.h"
 #include "mozilla/net/DashboardTypes.h"
 
+class nsASocketHandler;
+
 //-----------------------------------------------------------------------------
 
 #if defined(PR_LOGGING)
 //
 // set NSPR_LOG_MODULES=nsSocketTransport:5
 //
 extern PRLogModuleInfo *gSocketTransportLog;
 #endif
--- a/netwerk/base/src/nsStandardURL.cpp
+++ b/netwerk/base/src/nsStandardURL.cpp
@@ -2,32 +2,30 @@
 /* vim:set ts=4 sw=4 sts=4 et cindent: */
 /* 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 "IPCMessageUtils.h"
 
 #include "nsStandardURL.h"
-#include "nsDependentSubstring.h"
-#include "nsReadableUtils.h"
 #include "nsCRT.h"
 #include "nsEscape.h"
 #include "nsIFile.h"
 #include "nsIObjectInputStream.h"
 #include "nsIObjectOutputStream.h"
 #include "nsICharsetConverterManager.h"
 #include "nsIPrefService.h"
 #include "nsIPrefBranch.h"
 #include "nsIIDNService.h"
-#include "nsNetUtil.h"
 #include "prlog.h"
 #include "nsAutoPtr.h"
 #include "nsIProgrammingLanguage.h"
-#include "nsVoidArray.h"
+#include "nsIURLParser.h"
+#include "nsNetCID.h"
 #include "mozilla/MemoryReporting.h"
 #include "mozilla/ipc/URIUtils.h"
 #include <algorithm>
 
 using namespace mozilla::ipc;
 
 static NS_DEFINE_CID(kThisImplCID, NS_THIS_STANDARDURL_IMPL_CID);
 static NS_DEFINE_CID(kStandardURLCID, NS_STANDARDURL_CID);
--- a/netwerk/base/src/nsStandardURL.h
+++ b/netwerk/base/src/nsStandardURL.h
@@ -2,26 +2,21 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef nsStandardURL_h__
 #define nsStandardURL_h__
 
 #include "nsString.h"
-#include "nsDependentString.h"
-#include "nsDependentSubstring.h"
 #include "nsISerializable.h"
 #include "nsIFileURL.h"
 #include "nsIStandardURL.h"
-#include "nsIFile.h"
-#include "nsIURLParser.h"
 #include "nsIUnicodeEncoder.h"
 #include "nsIObserver.h"
-#include "nsIIOService.h"
 #include "nsCOMPtr.h"
 #include "nsURLHelper.h"
 #include "nsIClassInfo.h"
 #include "nsISizeOf.h"
 #include "prclist.h"
 #include "mozilla/Attributes.h"
 #include "mozilla/MemoryReporting.h"
 #include "nsIIPCSerializableURI.h"
@@ -30,16 +25,18 @@
 #define DEBUG_DUMP_URLS_AT_SHUTDOWN
 #endif
 
 class nsIBinaryInputStream;
 class nsIBinaryOutputStream;
 class nsIIDNService;
 class nsICharsetConverterManager;
 class nsIPrefBranch;
+class nsIFile;
+class nsIURLParser;
 
 //-----------------------------------------------------------------------------
 // standard URL implementation
 //-----------------------------------------------------------------------------
 
 class nsStandardURL : public nsIFileURL
                     , public nsIStandardURL
                     , public nsISerializable
--- a/netwerk/base/src/nsStreamListenerWrapper.cpp
+++ b/netwerk/base/src/nsStreamListenerWrapper.cpp
@@ -1,14 +1,16 @@
 /* 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 "nsStreamListenerWrapper.h"
-#include "nsThreadUtils.h"
+#ifdef DEBUG
+#include "MainThreadUtils.h"
+#endif
 
 NS_IMPL_ISUPPORTS3(nsStreamListenerWrapper,
                    nsIStreamListener,
                    nsIRequestObserver,
                    nsIThreadRetargetableStreamListener)
 
 NS_IMETHODIMP
 nsStreamListenerWrapper::CheckListenerChain()
--- a/netwerk/base/src/nsStreamLoader.h
+++ b/netwerk/base/src/nsStreamLoader.h
@@ -1,22 +1,22 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef nsStreamLoader_h__
 #define nsStreamLoader_h__
 
-#include "nsIRequest.h"
 #include "nsIStreamLoader.h"
 #include "nsCOMPtr.h"
-#include "nsString.h"
 #include "mozilla/Attributes.h"
 
+class nsIRequest;
+
 class nsStreamLoader MOZ_FINAL : public nsIStreamLoader
 {
 public:
   NS_DECL_ISUPPORTS
   NS_DECL_NSISTREAMLOADER
   NS_DECL_NSIREQUESTOBSERVER
   NS_DECL_NSISTREAMLISTENER
 
--- a/netwerk/base/src/nsStreamTransportService.cpp
+++ b/netwerk/base/src/nsStreamTransportService.cpp
@@ -5,24 +5,23 @@
 #include "nsStreamTransportService.h"
 #include "nsXPCOMCIDInternal.h"
 #include "nsNetSegmentUtils.h"
 #include "nsTransportUtils.h"
 #include "nsStreamUtils.h"
 #include "nsError.h"
 #include "nsNetCID.h"
 
-#include "nsIServiceManager.h"
 #include "nsIAsyncInputStream.h"
 #include "nsIAsyncOutputStream.h"
 #include "nsISeekableStream.h"
 #include "nsIPipe.h"
 #include "nsITransport.h"
-#include "nsIRunnable.h"
 #include "nsIObserverService.h"
+#include "nsIThreadPool.h"
 #include "mozilla/Services.h"
 
 //-----------------------------------------------------------------------------
 // nsInputStreamTransport
 //
 // Implements nsIInputStream as a wrapper around the real input stream.  This
 // allows the transport to support seeking, range-limiting, progress reporting,
 // and close-when-done semantics while utilizing NS_AsyncCopy.
--- a/netwerk/base/src/nsStreamTransportService.h
+++ b/netwerk/base/src/nsStreamTransportService.h
@@ -1,19 +1,20 @@
 /* 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 "nsIStreamTransportService.h"
 #include "nsIEventTarget.h"
-#include "nsIThreadPool.h"
 #include "nsIObserver.h"
 #include "nsCOMPtr.h"
 #include "mozilla/Attributes.h"
 
+class nsIThreadPool;
+
 class nsStreamTransportService MOZ_FINAL : public nsIStreamTransportService
                                          , public nsIEventTarget
                                          , public nsIObserver
 {
 public:
     NS_DECL_THREADSAFE_ISUPPORTS
     NS_DECL_NSISTREAMTRANSPORTSERVICE
     NS_DECL_NSIEVENTTARGET
--- a/netwerk/base/src/nsSyncStreamListener.cpp
+++ b/netwerk/base/src/nsSyncStreamListener.cpp
@@ -1,15 +1,16 @@
 /* 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 "nsIOService.h"
 #include "nsSyncStreamListener.h"
 #include "nsIPipe.h"
+#include "nsThreadUtils.h"
 #include <algorithm>
 
 nsresult
 nsSyncStreamListener::Init()
 {
     return NS_NewPipe(getter_AddRefs(mPipeIn),
                       getter_AddRefs(mPipeOut),
                       nsIOService::gDefaultSegmentSize,
--- a/netwerk/base/src/nsSyncStreamListener.h
+++ b/netwerk/base/src/nsSyncStreamListener.h
@@ -3,17 +3,16 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef nsSyncStreamListener_h__
 #define nsSyncStreamListener_h__
 
 #include "nsISyncStreamListener.h"
 #include "nsIInputStream.h"
 #include "nsIOutputStream.h"
-#include "nsThreadUtils.h"
 #include "nsCOMPtr.h"
 #include "mozilla/Attributes.h"
 
 //-----------------------------------------------------------------------------
 
 class nsSyncStreamListener MOZ_FINAL : public nsISyncStreamListener
                                      , public nsIInputStream
 {
--- a/netwerk/base/src/nsTemporaryFileInputStream.cpp
+++ b/netwerk/base/src/nsTemporaryFileInputStream.cpp
@@ -1,15 +1,16 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
 /* 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 "nsTemporaryFileInputStream.h"
 #include "nsStreamUtils.h"
+#include <algorithm>
 
 NS_IMPL_ISUPPORTS1(nsTemporaryFileInputStream, nsIInputStream)
 
 nsTemporaryFileInputStream::nsTemporaryFileInputStream(FileDescOwner* aFileDescOwner, uint64_t aStartPos, uint64_t aEndPos)
   : mFileDescOwner(aFileDescOwner),
     mStartPos(aStartPos),
     mEndPos(aEndPos),
     mClosed(false)
--- a/netwerk/base/src/nsTemporaryFileInputStream.h
+++ b/netwerk/base/src/nsTemporaryFileInputStream.h
@@ -1,18 +1,20 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef nsTemporaryFileInputStream_h__
 #define nsTemporaryFileInputStream_h__
 
-#include "nsFileStreams.h"
 #include "mozilla/Mutex.h"
+#include "nsIInputStream.h"
+#include "nsAutoPtr.h"
+#include "prio.h"
 
 class nsTemporaryFileInputStream : public nsIInputStream
 {
 public:
   //used to release a PRFileDesc
   class FileDescOwner
   {
     friend class nsTemporaryFileInputStream;
--- a/netwerk/base/src/nsUDPServerSocket.cpp
+++ b/netwerk/base/src/nsUDPServerSocket.cpp
@@ -1,30 +1,28 @@
 /* vim:set ts=2 sw=2 et cindent: */
 /* 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 "nsIServiceManager.h"
 #include "nsSocketTransport2.h"
 #include "nsUDPServerSocket.h"
 #include "nsProxyRelease.h"
 #include "nsAutoPtr.h"
 #include "nsError.h"
 #include "nsNetCID.h"
 #include "prnetdb.h"
 #include "prio.h"
 #include "mozilla/Attributes.h"
 #include "nsNetAddr.h"
 #include "nsNetSegmentUtils.h"
 #include "NetworkActivityMonitor.h"
 #include "nsStreamUtils.h"
 #include "nsIPipe.h"
 #include "prerror.h"
-#include "nsINSSErrorsService.h"
 #include "nsThreadUtils.h"
 
 using namespace mozilla::net;
 using namespace mozilla;
 
 static NS_DEFINE_CID(kSocketTransportServiceCID, NS_SOCKETTRANSPORTSERVICE_CID);
 
 //-----------------------------------------------------------------------------
--- a/netwerk/base/src/nsUDPServerSocket.h
+++ b/netwerk/base/src/nsUDPServerSocket.h
@@ -2,17 +2,16 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef nsUDPServerSocket_h__
 #define nsUDPServerSocket_h__
 
 #include "nsIUDPServerSocket.h"
-#include "nsSocketTransportService2.h"
 #include "mozilla/Mutex.h"
 #include "nsIOutputStream.h"
 #include "nsAutoPtr.h"
 
 //-----------------------------------------------------------------------------
 
 class nsUDPServerSocket : public nsASocketHandler
                         , public nsIUDPServerSocket
--- a/netwerk/base/src/nsURIChecker.cpp
+++ b/netwerk/base/src/nsURIChecker.cpp
@@ -1,15 +1,14 @@
 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
 /* 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 "nsURIChecker.h"
-#include "nsIServiceManager.h"
 #include "nsIAuthPrompt.h"
 #include "nsIHttpChannel.h"
 #include "nsNetUtil.h"
 #include "nsString.h"
 #include "nsIAsyncVerifyRedirectCallback.h"
 
 //-----------------------------------------------------------------------------
 
--- a/netwerk/base/src/nsURIChecker.h
+++ b/netwerk/base/src/nsURIChecker.h
@@ -6,18 +6,16 @@
 #ifndef nsURIChecker_h__
 #define nsURIChecker_h__
 
 #include "nsIURIChecker.h"
 #include "nsIChannel.h"
 #include "nsIStreamListener.h"
 #include "nsIChannelEventSink.h"
 #include "nsIInterfaceRequestor.h"
-#include "nsIIOService.h"
-#include "nsIURI.h"
 #include "nsCOMPtr.h"
 
 //-----------------------------------------------------------------------------
 
 class nsURIChecker : public nsIURIChecker,
                      public nsIStreamListener,
                      public nsIChannelEventSink,
                      public nsIInterfaceRequestor
--- a/netwerk/base/src/nsURLHelper.cpp
+++ b/netwerk/base/src/nsURLHelper.cpp
@@ -2,29 +2,21 @@
 /* vim:set ts=4 sw=4 sts=4 et cindent: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "mozilla/RangedPtr.h"
 
 #include "nsURLHelper.h"
-#include "nsReadableUtils.h"
-#include "nsIServiceManager.h"
-#include "nsIIOService.h"
 #include "nsIFile.h"
 #include "nsIURLParser.h"
-#include "nsIURI.h"
-#include "nsMemory.h"
-#include "nsEscape.h"
 #include "nsCOMPtr.h"
 #include "nsCRT.h"
 #include "nsNetCID.h"
-#include "netCore.h"
-#include "prprf.h"
 #include "prnetdb.h"
 
 using namespace mozilla;
 
 //----------------------------------------------------------------------------
 // Init/Shutdown
 //----------------------------------------------------------------------------
 
--- a/netwerk/base/src/nsURLParsers.cpp
+++ b/netwerk/base/src/nsURLParsers.cpp
@@ -4,21 +4,19 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include <string.h>
 
 #include "mozilla/RangedPtr.h"
 
 #include "nsURLParsers.h"
 #include "nsURLHelper.h"
-#include "nsIURI.h"
 #include "prtypes.h"
 #include "nsString.h"
 #include "nsCRT.h"
-#include "netCore.h"
 
 using namespace mozilla;
 
 //----------------------------------------------------------------------------
 
 static uint32_t
 CountConsecutiveSlashes(const char *str, int32_t len)
 {
--- a/netwerk/base/src/nsUnicharStreamLoader.cpp
+++ b/netwerk/base/src/nsUnicharStreamLoader.cpp
@@ -3,17 +3,17 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "mozilla/DebugOnly.h"
 
 #include "nsUnicharStreamLoader.h"
 #include "nsIInputStream.h"
 #include "nsICharsetConverterManager.h"
-#include "nsIServiceManager.h"
+#include "nsServiceManagerUtils.h"
 #include <algorithm>
 
 // 1024 bytes is specified in
 // http://www.whatwg.org/specs/web-apps/current-work/#charset for HTML; for
 // other resource types (e.g. CSS) typically fewer bytes are fine too, since
 // they only look at things right at the beginning of the data.
 #define SNIFFING_BUFFER_SIZE 1024
 
--- a/netwerk/build/nsNetModule.cpp
+++ b/netwerk/build/nsNetModule.cpp
@@ -32,16 +32,17 @@
 #include "nsMimeTypes.h"
 #include "nsNetStrings.h"
 #include "nsDNSPrefetch.h"
 #include "nsAboutProtocolHandler.h"
 #include "nsXULAppAPI.h"
 #include "nsCategoryCache.h"
 #include "nsIContentSniffer.h"
 #include "nsNetUtil.h"
+#include "nsIThreadPool.h"
 #include "mozilla/net/NeckoChild.h"
 
 #include "nsNetCID.h"
 
 #if defined(XP_MACOSX)
 #if !defined(__LP64__)
 #define BUILD_APPLEFILE_DECODER 1
 #endif
--- a/netwerk/protocol/http/nsHttpTransaction.cpp
+++ b/netwerk/protocol/http/nsHttpTransaction.cpp
@@ -26,16 +26,17 @@
 #include "nsMultiplexInputStream.h"
 #include "nsStringStream.h"
 #include "mozilla/VisualEventTracer.h"
 
 #include "nsComponentManagerUtils.h" // do_CreateInstance
 #include "nsServiceManagerUtils.h"   // do_GetService
 #include "nsIHttpActivityObserver.h"
 #include "nsSocketTransportService2.h"
+#include "nsICancelable.h"
 #include <algorithm>
 
 
 using namespace mozilla;
 
 //-----------------------------------------------------------------------------
 
 #ifdef DEBUG
--- a/python/mozbuild/mozbuild/base.py
+++ b/python/mozbuild/mozbuild/base.py
@@ -20,16 +20,18 @@ from mozfile.mozfile import rmtree
 
 from .backend.configenvironment import ConfigEnvironment
 from .config import BuildConfig
 from .mozconfig import (
     MozconfigFindException,
     MozconfigLoadException,
     MozconfigLoader,
 )
+from .virtualenv import VirtualenvManager
+
 
 def ancestors(path):
     """Emit the parent directories of a path."""
     while path:
         yield path
         newpath = os.path.dirname(path)
         if newpath == path:
             break
@@ -81,16 +83,17 @@ class MozbuildObject(ProcessExecutionMix
         self.populate_logger()
         self.log_manager = log_manager
 
         self._make = None
         self._topobjdir = topobjdir
         self._mozconfig = None
         self._config_guess_output = None
         self._config_environment = None
+        self._virtualenv_manager = None
 
     @classmethod
     def from_environment(cls, cwd=None, detect_virtualenv_mozinfo=True):
         """Create a MozbuildObject by detecting the proper one from the env.
 
         This examines environment state like the current working directory and
         creates a MozbuildObject from the found source directory, mozconfig, etc.
 
@@ -202,16 +205,26 @@ class MozbuildObject(ProcessExecutionMix
     def topobjdir(self):
         if self._topobjdir is None:
             self._topobjdir = MozbuildObject.resolve_mozconfig_topobjdir(
                 self.topsrcdir, self.mozconfig, default='obj-@CONFIG_GUESS@')
 
         return self._topobjdir
 
     @property
+    def virtualenv_manager(self):
+        if self._virtualenv_manager is None:
+            self._virtualenv_manager = VirtualenvManager(self.topsrcdir,
+                self.topobjdir, os.path.join(self.topobjdir, '_virtualenv'),
+                sys.stdout, os.path.join(self.topsrcdir, 'build',
+                'virtualenv_packages.txt'))
+
+        return self._virtualenv_manager
+
+    @property
     def mozconfig(self):
         """Returns information about the current mozconfig file.
 
         This a dict as returned by MozconfigLoader.read_mozconfig()
         """
         if self._mozconfig is None:
             loader = MozconfigLoader(self.topsrcdir)
             self._mozconfig = loader.read_mozconfig()
@@ -470,16 +483,20 @@ class MozbuildObject(ProcessExecutionMix
         This is used as a convenience method to create other
         MozbuildObject-derived class instances. It can only be used on
         classes that have the same constructor arguments as us.
         """
 
         return cls(self.topsrcdir, self.settings, self.log_manager,
             topobjdir=self.topobjdir)
 
+    def _activate_virtualenv(self):
+        self.virtualenv_manager.ensure()
+        self.virtualenv_manager.activate()
+
 
 class MachCommandBase(MozbuildObject):
     """Base class for mach command providers that wish to be MozbuildObjects.
 
     This provides a level of indirection so MozbuildObject can be refactored
     without having to change everything that inherits from it.
     """
 
--- a/python/mozbuild/mozbuild/mach_commands.py
+++ b/python/mozbuild/mozbuild/mach_commands.py
@@ -908,8 +908,42 @@ class MachDebug(object):
             if verbose:
                 print('config substitutions:')
                 for k in sorted(config.substs):
                     print('\t%s: %s' % (k, config.substs[k]))
 
                 print('config defines:')
                 for k in sorted(config.defines):
                     print('\t%s' % k)
+
+
+@CommandProvider
+class Documentation(MachCommandBase):
+    """Helps manage in-tree documentation."""
+
+    @Command('build-docs', category='build-dev',
+        description='Generate documentation for the tree.')
+    @CommandArgument('--format', default='html',
+        help='Documentation format to write.')
+    @CommandArgument('outdir', default='<DEFAULT>', nargs='?',
+        help='Where to write output.')
+    def build_docs(self, format=None, outdir=None):
+        self._activate_virtualenv()
+
+        self.virtualenv_manager.install_pip_package('mdn-sphinx-theme==0.3')
+
+        import sphinx
+
+        if outdir == '<DEFAULT>':
+            outdir = os.path.join(self.topobjdir, 'docs', format)
+
+        args = [
+            sys.argv[0],
+            '-b', format,
+            os.path.join(self.topsrcdir, 'build', 'docs'),
+            outdir,
+        ]
+
+        result = sphinx.main(args)
+
+        print('Docs written to %s.' % outdir)
+
+        return result
rename from build/virtualenv/populate_virtualenv.py
rename to python/mozbuild/mozbuild/virtualenv.py
--- a/build/virtualenv/populate_virtualenv.py
+++ b/python/mozbuild/mozbuild/virtualenv.py
@@ -55,29 +55,37 @@ class VirtualenvManager(object):
 
     @property
     def virtualenv_script_path(self):
         """Path to virtualenv's own populator script."""
         return os.path.join(self.topsrcdir, 'python', 'virtualenv',
             'virtualenv.py')
 
     @property
-    def python_path(self):
+    def bin_path(self):
+        # virtualenv.py provides a similar API via path_locations(). However,
+        # we have a bit of a chicken-and-egg problem and can't reliably
+        # import virtualenv. The functionality is trivial, so just implement
+        # it here.
         if sys.platform in ('win32', 'cygwin'):
-            return os.path.join(self.virtualenv_root, 'Scripts', 'python.exe')
+            return os.path.join(self.virtualenv_root, 'Scripts')
+
+        return os.path.join(self.virtualenv_root, 'bin')
 
-        return os.path.join(self.virtualenv_root, 'bin', 'python')
+    @property
+    def python_path(self):
+        binary = 'python'
+        if sys.platform in ('win32', 'cygwin'):
+            binary += '.exe'
+
+        return os.path.join(self.bin_path, binary)
 
     @property
     def activate_path(self):
-        if sys.platform in ('win32', 'cygwin'):
-            return os.path.join(self.virtualenv_root, 'Scripts',
-                'activate_this.py')
-
-        return os.path.join(self.virtualenv_root, 'bin', 'activate_this.py')
+        return os.path.join(self.bin_path, 'activate_this.py')
 
     def up_to_date(self):
         """Returns whether the virtualenv is present and up to date."""
 
         deps = [self.manifest_path, __file__]
 
         # check if virtualenv exists
         if not os.path.exists(self.virtualenv_root) or \
@@ -361,17 +369,17 @@ class VirtualenvManager(object):
         """
 
         self.create()
 
         # We need to populate the virtualenv using the Python executable in
         # the virtualenv for paths to be proper.
 
         args = [self.python_path, __file__, 'populate', self.topsrcdir,
-            self.topobjdir, self.virtualenv_root]
+            self.topobjdir, self.virtualenv_root, self.manifest_path]
 
         result = subprocess.call(args, stdout=self.log_handle,
             stderr=subprocess.STDOUT, cwd=self.topsrcdir)
 
         if result != 0:
             raise Exception('Error populating virtualenv.')
 
         os.utime(self.activate_path, None)
@@ -383,16 +391,49 @@ class VirtualenvManager(object):
 
         If you run a random Python script and wish to "activate" the
         virtualenv, you can simply instantiate an instance of this class
         and call .ensure() and .activate() to make the virtualenv active.
         """
 
         execfile(self.activate_path, dict(__file__=self.activate_path))
 
+    def install_pip_package(self, package):
+        """Install a package via pip.
+
+        The supplied package is specified using a pip requirement specifier.
+        e.g. 'foo' or 'foo==1.0'.
+
+        If the package is already installed, this is a no-op.
+        """
+        from pip.req import InstallRequirement
+
+        req = InstallRequirement.from_line(package)
+        if req.check_if_exists():
+            return
+
+        args = [
+            'install',
+            '--use-wheel',
+            package,
+        ]
+
+        return self._run_pip(args)
+
+    def _run_pip(self, args):
+        # It's tempting to call pip natively via pip.main(). However,
+        # the current Python interpreter may not be the virtualenv python.
+        # This will confuse pip and cause the package to attempt to install
+        # against the executing interpreter. By creating a new process, we
+        # force the virtualenv's interpreter to be used and all is well.
+        # It /might/ be possible to cheat and set sys.executable to
+        # self.python_path. However, this seems more risk than it's worth.
+        subprocess.check_call([os.path.join(self.bin_path, 'pip')] + args,
+            stderr=subprocess.STDOUT)
+
 
 def verify_python_version(log_handle):
     """Ensure the current version of Python is sufficient."""
     major, minor, micro = sys.version_info[:3]
 
     our = StrictVersion('%d.%d.%d' % (major, minor, micro))
 
     if major != MINIMUM_PYTHON_MAJOR or our < MINIMUM_PYTHON_VERSION:
@@ -404,36 +445,29 @@ def verify_python_version(log_handle):
             log_handle.write(UPGRADE_WINDOWS)
         else:
             log_handle.write(UPGRADE_OTHER)
 
         sys.exit(1)
 
 
 if __name__ == '__main__':
-    if len(sys.argv) < 4:
-        print('Usage: populate_virtualenv.py /path/to/topsrcdir /path/to/topobjdir /path/to/virtualenv')
+    if len(sys.argv) < 5:
+        print('Usage: populate_virtualenv.py /path/to/topsrcdir /path/to/topobjdir /path/to/virtualenv /path/to/virtualenv_manifest')
         sys.exit(1)
 
     verify_python_version(sys.stdout)
 
-    topsrcdir = sys.argv[1]
-    topobjdir = sys.argv[2]
-    virtualenv_path = sys.argv[3]
+    topsrcdir, topobjdir, virtualenv_path, manifest_path = sys.argv[1:5]
     populate = False
 
     # This should only be called internally.
     if sys.argv[1] == 'populate':
         populate = True
-        topsrcdir = sys.argv[2]
-        topobjdir = sys.argv[3]
-        virtualenv_path = sys.argv[4]
-
-    # path to default packages.txt
-    manifest_path = os.path.join(topsrcdir, 'build', 'virtualenv', 'packages.txt')
+        topsrcdir, topobjdir, virtualenv_path, manifest_path = sys.argv[2:]
 
     manager = VirtualenvManager(topsrcdir, topobjdir, virtualenv_path,
         sys.stdout, manifest_path)
 
     if populate:
         manager.populate()
     else:
         manager.ensure()
--- a/testing/runcppunittests.py
+++ b/testing/runcppunittests.py
@@ -84,16 +84,22 @@ class CPPUnitTests(object):
             pathvar = "DYLD_LIBRARY_PATH"
         elif mozinfo.os == "win":
             pathvar = "PATH"
         if pathvar:
             if pathvar in env:
                 env[pathvar] = "%s%s%s" % (self.xre_path, os.pathsep, env[pathvar])
             else:
                 env[pathvar] = self.xre_path
+
+        # Use llvm-symbolizer for ASan if available/required
+        llvmsym = os.path.join(self.xre_path, "llvm-symbolizer")
+        if os.path.isfile(llvmsym):
+          env["ASAN_SYMBOLIZER_PATH"] = llvmsym
+
         return env
 
     def run_tests(self, programs, xre_path, symbols_path=None):
         """
         Run a set of C++ unit test programs.
 
         Arguments:
         * programs: An iterable containing paths to test programs.
--- a/toolkit/crashreporter/nsExceptionHandler.cpp
+++ b/toolkit/crashreporter/nsExceptionHandler.cpp
@@ -1,28 +1,29 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
+#include "nsExceptionHandler.h"
+#include "nsDataHashtable.h"
 #include "mozilla/dom/CrashReporterChild.h"
 #include "mozilla/Services.h"
 #include "nsIObserverService.h"
 #include "mozilla/Util.h"
 
-#include "nsXULAppAPI.h"
-
-#include "nsExceptionHandler.h"
 #include "nsThreadUtils.h"
 
 #if defined(XP_WIN32)
 #ifdef WIN32_LEAN_AND_MEAN
 #undef WIN32_LEAN_AND_MEAN
 #endif
 
+#include "nsXULAppAPI.h"
+#include "nsIXULAppInfo.h"
 #include "nsIWindowsRegKey.h"
 #include "client/windows/crash_generation/client_info.h"
 #include "client/windows/crash_generation/crash_generation_server.h"
 #include "client/windows/handler/exception_handler.h"
 #include <dbghelp.h>
 #include <string.h>
 #include "nsDirectoryServiceUtils.h"
 
@@ -37,25 +38,22 @@
 #include <crt_externs.h>
 #include <fcntl.h>
 #include <mach/mach.h>
 #include <sys/types.h>
 #include <spawn.h>
 #include <unistd.h>
 #include "mac_utils.h"
 #elif defined(XP_LINUX)
-#include "nsDirectoryServiceDefs.h"
 #include "nsIINIParser.h"
 #include "common/linux/linux_libc_support.h"
 #include "third_party/lss/linux_syscall_support.h"
 #include "client/linux/crash_generation/client_info.h"
 #include "client/linux/crash_generation/crash_generation_server.h"
 #include "client/linux/handler/exception_handler.h"
-#include "client/linux/minidump_writer/linux_dumper.h"
-#include "client/linux/minidump_writer/minidump_writer.h"
 #include <fcntl.h>
 #include <sys/types.h>
 #include <unistd.h>
 #elif defined(XP_SOLARIS)
 #include "client/solaris/handler/exception_handler.h"
 #include <fcntl.h>
 #include <sys/types.h>
 #include <unistd.h>
@@ -72,35 +70,30 @@ using mozilla::InjectCrashRunnable;
 #include <time.h>
 #include <prenv.h>
 #include <prio.h>
 #include <prmem.h>
 #include "mozilla/Mutex.h"
 #include "nsDebug.h"
 #include "nsCRT.h"
 #include "nsIFile.h"
-#include "nsIFileStreams.h"
-#include "nsInterfaceHashtable.h"
 #include "prprf.h"
-#include "nsIXULAppInfo.h"
 #include <map>
 #include <vector>
 
 #include "mozilla/mozalloc_oom.h"
 #include "mozilla/mozPoisonWrite.h"
 
 #if defined(XP_MACOSX)
 CFStringRef reporterClientAppID = CFSTR("org.mozilla.crashreporter");
 #endif
 #if defined(MOZ_WIDGET_ANDROID)
 #include "common/linux/file_id.h"
 #endif
 
-#include "nsIUUIDGenerator.h"
-
 using google_breakpad::CrashGenerationServer;
 using google_breakpad::ClientInfo;
 #ifdef XP_LINUX
 using google_breakpad::MinidumpDescriptor;
 #endif
 using namespace mozilla;
 using mozilla::dom::CrashReporterChild;
 using mozilla::dom::PCrashReporterChild;
--- a/toolkit/crashreporter/nsExceptionHandler.h
+++ b/toolkit/crashreporter/nsExceptionHandler.h
@@ -1,34 +1,36 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef nsExceptionHandler_h__
 #define nsExceptionHandler_h__
 
-#include "nscore.h"
-#include "nsDataHashtable.h"
-#include "nsXPCOM.h"
+#include <stddef.h>
+#include <stdint.h>
+#include "nsError.h"
 #include "nsStringGlue.h"
 
-#include "nsIFile.h"
-
 #if defined(XP_WIN32)
 #ifdef WIN32_LEAN_AND_MEAN
 #undef WIN32_LEAN_AND_MEAN
 #endif
 #include <windows.h>
 #endif
 
 #if defined(XP_MACOSX)
 #include <mach/mach.h>
 #endif
 
+class nsIFile;
+template<class KeyClass, class DataType> class nsDataHashtable;
+class nsCStringHashKey;
+
 namespace CrashReporter {
 nsresult SetExceptionHandler(nsIFile* aXREDirectory, bool force=false);
 nsresult UnsetExceptionHandler();
 bool     GetEnabled();
 bool     GetServerURL(nsACString& aServerURL);
 nsresult SetServerURL(const nsACString& aServerURL);
 bool     GetMinidumpPath(nsAString& aPath);
 nsresult SetMinidumpPath(const nsAString& aPath);