Merge the last PGO-green inbound changeset to m-c.
authorRyan VanderMeulen <ryanvm@gmail.com>
Thu, 23 Aug 2012 22:06:49 -0400
changeset 103225 e509c7472f301a805ee6430dd175daef55b98987
parent 103139 cace7cc25814f222284ade58e875f11c5f32c36c (current diff)
parent 103224 7fb25861ffd9d6b23d10d783f8e68160f3527315 (diff)
child 103226 29ca472bf2d278a27e7d910bf40ece6f501af3c2
push id23332
push userryanvm@gmail.com
push dateFri, 24 Aug 2012 02:06:52 +0000
treeherdermozilla-central@e509c7472f30 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone17.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge the last PGO-green inbound changeset to m-c.
build/automation.py.in
content/base/public/nsBlobProtocolHandler.h
dom/ipc/ContentChild.cpp
dom/ipc/ContentParent.cpp
ipc/glue/IPCSerializableParams.ipdlh
netwerk/base/public/nsIIPCSerializableObsolete.idl
netwerk/ipc/NeckoMessageUtils.h
testing/mochitest/tests/SimpleTest/specialpowersAPI.js
xpcom/tests/unit/test_seek_multiplex.js
--- a/accessible/src/jsat/TouchAdapter.jsm
+++ b/accessible/src/jsat/TouchAdapter.jsm
@@ -80,48 +80,51 @@ var TouchAdapter = {
     if (Utils.OS != 'Android')
       Mouse2Touch.detach(aWindow);
 
     delete this.chromeWin;
   },
 
   handleEvent: function TouchAdapter_handleEvent(aEvent) {
     let touches = aEvent.changedTouches;
+    // XXX: Until bug 77992 is resolved, on desktop we get microseconds
+    // instead of milliseconds.
+    let timeStamp = (Utils.OS == 'Android') ? aEvent.timeStamp : Date.now();
     switch (aEvent.type) {
       case 'touchstart':
         for (var i = 0; i < touches.length; i++) {
           let touch = touches[i];
-          let touchPoint = new TouchPoint(touch, aEvent.timeStamp, this._dpi);
+          let touchPoint = new TouchPoint(touch, timeStamp, this._dpi);
           this._touchPoints[touch.identifier] = touchPoint;
-          this._lastExploreTime = aEvent.timeStamp + this.SWIPE_MAX_DURATION;
+          this._lastExploreTime = timeStamp + this.SWIPE_MAX_DURATION;
         }
         this._dwellTimeout = this.chromeWin.setTimeout(
           (function () {
-             this.compileAndEmit(aEvent.timeStamp + this.DWELL_THRESHOLD);
+             this.compileAndEmit(timeStamp + this.DWELL_THRESHOLD);
            }).bind(this), this.DWELL_THRESHOLD);
         break;
       case 'touchmove':
         for (var i = 0; i < touches.length; i++) {
           let touch = touches[i];
           let touchPoint = this._touchPoints[touch.identifier];
-          touchPoint.update(touch, aEvent.timeStamp);
+          touchPoint.update(touch, timeStamp);
         }
-        if (aEvent.timeStamp - this._lastExploreTime >= EXPLORE_THROTTLE) {
-          this.compileAndEmit(aEvent.timeStamp);
-          this._lastExploreTime = aEvent.timeStamp;
+        if (timeStamp - this._lastExploreTime >= EXPLORE_THROTTLE) {
+          this.compileAndEmit(timeStamp);
+          this._lastExploreTime = timeStamp;
         }
         break;
       case 'touchend':
         for (var i = 0; i < touches.length; i++) {
           let touch = touches[i];
           let touchPoint = this._touchPoints[touch.identifier];
-          touchPoint.update(touch, aEvent.timeStamp);
+          touchPoint.update(touch, timeStamp);
           touchPoint.finish();
         }
-        this.compileAndEmit(aEvent.timeStamp);
+        this.compileAndEmit(timeStamp);
         break;
     }
   },
 
   cleanupTouches: function cleanupTouches() {
     for (var identifier in this._touchPoints) {
       if (!this._touchPoints[identifier].done)
         continue;
--- a/b2g/app/b2g.js
+++ b/b2g/app/b2g.js
@@ -510,16 +510,18 @@ pref("dom.ipc.processPriorityManager.ena
 pref("dom.ipc.processPriorityManager.gracePeriodMS", 1000);
 pref("hal.processPriorityManager.gonk.masterOomAdjust", 0);
 pref("hal.processPriorityManager.gonk.foregroundOomAdjust", 1);
 pref("hal.processPriorityManager.gonk.backgroundOomAdjust", 2);
 pref("hal.processPriorityManager.gonk.masterNice", -1);
 pref("hal.processPriorityManager.gonk.foregroundNice", 0);
 pref("hal.processPriorityManager.gonk.backgroundNice", 10);
 
+#ifndef DEBUG
 // Enable pre-launching content processes for improved startup time
 // (hiding latency).
 pref("dom.ipc.processPrelauch.enabled", true);
 // Wait this long before pre-launching a new subprocess.
 pref("dom.ipc.processPrelauch.delayMs", 1000);
+#endif
 
 // Ignore the "dialog=1" feature in window.open.
 pref("dom.disable_window_open_dialog_feature", true);
--- a/browser/base/content/test/test_contextmenu.html
+++ b/browser/base/content/test/test_contextmenu.html
@@ -47,23 +47,23 @@ function openContextMenuFor(element, shi
 function closeContextMenu() {
     contextMenu.hidePopup();
 }
 
 function executeCopyCommand(command, expectedValue)
 {
   // Just execute the command directly rather than simulating a context menu
   // press to avoid having to deal with its asynchronous nature
-  subwindow.controllers.getControllerForCommand(command).doCommand(command);
+  SpecialPowers.wrap(subwindow).controllers.getControllerForCommand(command).doCommand(command);
 
   // The easiest way to check the clipboard is to paste the contents into a
   // textbox
   input.focus();
   input.value = "";
-  input.controllers.getControllerForCommand("cmd_paste").doCommand("cmd_paste");
+  SpecialPowers.wrap(input).controllers.getControllerForCommand("cmd_paste").doCommand("cmd_paste");
   is(input.value, expectedValue, "paste for command " + command);
 }
 
 function invokeItemAction(generatedItemId)
 {
   var item = contextMenu.getElementsByAttribute("generateditemid",
                                                 generatedItemId)[0];
   ok(item, "Got generated XUL menu item");
@@ -245,17 +245,16 @@ function checkMenu(menu, expectedItems, 
  *
  * Called by a popupshowing event handler. Each test checks for expected menu
  * contents, closes the popup, and finally triggers the popup on a new element
  * (thus kicking off another cycle).
  *
  */
 function runTest(testNum) {
   // Seems we need to enable this again, or sendKeyEvent() complaints.
-  netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
   ok(true, "Starting test #" + testNum);
 
   var inspectItems = [];
   if (SpecialPowers.getBoolPref("devtools.inspector.enabled")) {
     inspectItems = ["---", null,
                     "context-inspect", true];
   }
 
--- a/build/automation.py.in
+++ b/build/automation.py.in
@@ -434,38 +434,23 @@ user_pref("extensions.hotfix.url", "http
 // Make sure opening about:addons won't hit the network
 user_pref("extensions.webservice.discoverURL", "http://%(server)s/extensions-dummy/discoveryURL");
 // Make sure AddonRepository won't hit the network
 user_pref("extensions.getAddons.maxResults", 0);
 user_pref("extensions.getAddons.get.url", "http://%(server)s/extensions-dummy/repositoryGetURL");
 user_pref("extensions.getAddons.getWithPerformance.url", "http://%(server)s/extensions-dummy/repositoryGetWithPerformanceURL");
 user_pref("extensions.getAddons.search.browseURL", "http://%(server)s/extensions-dummy/repositoryBrowseURL");
 user_pref("extensions.getAddons.search.url", "http://%(server)s/extensions-dummy/repositorySearchURL");
+
+// Make enablePrivilege continue to work for test code. :-(
+user_pref("security.enablePrivilege.enable_for_tests", true);
 """ % { "server" : self.webServer + ":" + str(self.httpPort) }
     prefs.append(part)
 
-    if useServerLocations == False:
-      part = """
-user_pref("capability.principal.codebase.p1.granted", "UniversalXPConnect");
-user_pref("capability.principal.codebase.p1.id", "%(origin)s");
-user_pref("capability.principal.codebase.p1.subjectName", "");
-"""  % { "origin": "http://" + self.webServer + ":" + str(self.httpPort) }
-      prefs.append(part)
-    else:
-      # Grant God-power to all the privileged servers on which tests run.
-      privileged = filter(lambda loc: "privileged" in loc.options, locations)
-      for (i, l) in itertools.izip(itertools.count(1), privileged):
-        part = """
-user_pref("capability.principal.codebase.p%(i)d.granted", "UniversalXPConnect");
-user_pref("capability.principal.codebase.p%(i)d.id", "%(origin)s");
-user_pref("capability.principal.codebase.p%(i)d.subjectName", "");
-"""  % { "i": i,
-         "origin": (l.scheme + "://" + l.host + ":" + str(l.port)) }
-        prefs.append(part)
-
+    if useServerLocations:
       # We need to proxy every server but the primary one.
       origins = ["'%s://%s:%s'" % (l.scheme, l.host, l.port)
                 for l in filter(lambda l: "primary" not in l.options, locations)]
       origins = ", ".join(origins)
 
       pacURL = """data:text/plain,
 function FindProxyForURL(url, host)
 {
--- a/build/mobile/b2gemulator.py
+++ b/build/mobile/b2gemulator.py
@@ -24,20 +24,27 @@ class B2GEmulator(Emulator):
 
     def _check_file(self, filePath):
         if not os.path.exists(filePath):
             raise Exception(('File not found: %s; did you pass the B2G home '
                              'directory as the homedir parameter, or set '
                              'B2G_HOME correctly?') % filePath)
 
     def _check_for_adb(self, host_dir):
-        self.adb = os.path.join(self.homedir, 'out', 'host', host_dir, 'bin', 'adb')
-        if not os.path.exists(self.adb):
-            self.adb = os.path.join(self.homedir, 'bin/adb')
-        super(B2GEmulator, self)._check_for_adb()
+        if self._default_adb() == 0:
+            return
+        adb_paths = [os.path.join(self.homedir,'glue','gonk','out','host',
+                      host_dir ,'bin','adb'),os.path.join(self.homedir, 'out',
+                      'host', host_dir,'bin','adb'),os.path.join(self.homedir,
+                      'bin','adb')]
+        for option in adb_paths:
+            if os.path.exists(option):
+                self.adb = option
+                return
+        raise Exception('adb not found!')
 
     def _locate_files(self):
         if self.homedir is None:
             self.homedir = os.getenv('B2G_HOME')
         if self.homedir is None:
             raise Exception('Must define B2G_HOME or pass the homedir parameter')
         self._check_file(self.homedir)
 
--- a/build/mobile/devicemanagerADB.py
+++ b/build/mobile/devicemanagerADB.py
@@ -285,27 +285,24 @@ class DeviceManagerADB(DeviceManager):
               else:
                   out += self.removeFile(remoteDir.strip() + "/" + f.strip())
           out += self.removeSingleDir(remoteDir.strip())
       else:
           out += self.removeFile(remoteDir.strip())
       return out
 
   def isDir(self, remotePath):
-      p = self.runCmd(["shell", "ls", "-a", remotePath])
+      p = self.runCmd(["shell", "ls", "-a", remotePath + '/'])
+
       data = p.stdout.readlines()
-      if (len(data) == 0):
-          return True
-      if (len(data) == 1):
-          if (data[0].rstrip() == remotePath):
+      if len(data) == 1:
+          res = data[0]
+          if "Not a directory" in res or "No such file or directory" in res:
               return False
-          if (data[0].find("No such file or directory") != -1):
-              return False
-          if (data[0].find("Not a directory") != -1):
-              return False
+
       return True
 
   def listFiles(self, rootdir):
       p = self.runCmd(["shell", "ls", "-a", rootdir])
       data = p.stdout.readlines()
       data[:] = [item.rstrip('\r\n') for item in data]
       if (len(data) == 1):
           if (data[0] == rootdir):
--- a/build/mobile/emulator.py
+++ b/build/mobile/emulator.py
@@ -82,27 +82,29 @@ class Emulator(object):
 
     @property
     def is_running(self):
         if self._emulator_launched:
             return self.proc is not None and self.proc.poll() is None
         else:
             return self.port is not None
 
+    def _default_adb(self):
+        adb = subprocess.Popen(['which', 'adb'],
+                               stdout=subprocess.PIPE,
+                               stderr=subprocess.STDOUT)
+        retcode = adb.wait()
+        if retcode == 0:
+            self.adb = adb.stdout.read().strip() # remove trailing newline
+        return retcode
+
     def _check_for_adb(self):
         if not os.path.exists(self.adb):
-            adb = subprocess.Popen(['which', 'adb'],
-                                   stdout=subprocess.PIPE,
-                                   stderr=subprocess.STDOUT)
-            retcode = adb.wait()
-            if retcode:
+            if self._default_adb() != 0:
                 raise Exception('adb not found!')
-            out = adb.stdout.read().strip()
-            if len(out) and out.find('/') > -1:
-                self.adb = out
 
     def _run_adb(self, args):
         args.insert(0, self.adb)
         adb = subprocess.Popen(args, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
         retcode = adb.wait()
         if retcode:
             raise Exception('adb terminated with exit code %d: %s'
             % (retcode, adb.stdout.read()))
--- a/build/unix/build-clang/create-manifest.py
+++ b/build/unix/build-clang/create-manifest.py
@@ -1,39 +1,39 @@
 #!/bin/python
 
 import os
+import os.path
 import simplejson
 import sys
 import subprocess
 import urllib
 import glob
 
 def check_run(args):
     r = subprocess.call(args)
     assert r == 0
 
-old_files = glob.glob('*.manifest') + ['tooltool.py', 'setup.sh']
+old_files = glob.glob('*.manifest')
 for f in old_files:
     try:
         os.unlink(f)
     except:
         pass
 
-urllib.urlretrieve('https://raw.github.com/jhford/tooltool/master/tooltool.py',
-                   'tooltool.py')
-urllib.urlretrieve('https://hg.mozilla.org/mozilla-central/raw-file/tip/build/unix/build-clang/setup.sh',
-                   'setup.sh')
+basedir = os.path.split(os.path.realpath(sys.argv[0]))[0]
+tooltool = basedir + '/tooltool.py'
+setup = basedir + '/setup.sh'
 
-check_run(['python', 'tooltool.py', '-m', 'linux32.manifest', 'add',
-           'clang-linux32.tar.bz2', 'setup.sh'])
-check_run(['python', 'tooltool.py', '-m', 'linux64.manifest', 'add',
-           'clang-linux64.tar.bz2', 'setup.sh'])
-check_run(['python', 'tooltool.py', '-m', 'darwin.manifest', 'add',
-           'clang-darwin.tar.bz2', 'setup.sh'])
+check_run(['python', tooltool, '-m', 'linux32.manifest', 'add',
+           'clang-linux32.tar.bz2', setup])
+check_run(['python', tooltool, '-m', 'linux64.manifest', 'add',
+           'clang-linux64.tar.bz2', setup])
+check_run(['python', tooltool, '-m', 'darwin.manifest', 'add',
+           'clang-darwin.tar.bz2', setup])
 
 def key_sort(item):
     item = item[0]
     if item == 'size':
         return 0
     if item == 'digest':
         return 1
     if item == 'algorithm':
new file mode 100644
--- /dev/null
+++ b/build/unix/build-clang/tooltool.py
@@ -0,0 +1,564 @@
+#!/usr/bin/env python
+
+#tooltool is a lookaside cache implemented in Python
+#Copyright (C) 2011 John H. Ford <john@johnford.info>
+#
+#This program is free software; you can redistribute it and/or
+#modify it under the terms of the GNU General Public License
+#as published by the Free Software Foundation version 2
+#
+#This program is distributed in the hope that it will be useful,
+#but WITHOUT ANY WARRANTY; without even the implied warranty of
+#MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#GNU General Public License for more details.
+#
+#You should have received a copy of the GNU General Public License
+#along with this program; if not, write to the Free Software
+#Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+
+# An manifest file specifies files in that directory that are stored
+# elsewhere.  This file should only contain file in the directory
+# which the manifest file resides in and it should be called 'manifest.manifest'
+
+__version__ = '1'
+
+import os
+import optparse
+import logging
+import hashlib
+import urllib2
+import ConfigParser
+try:
+    import simplejson as json # I hear simplejson is faster
+except ImportError:
+    import json
+
+log = logging.getLogger(__name__)
+
+class FileRecordJSONEncoderException(Exception): pass
+class InvalidManifest(Exception): pass
+class ExceptionWithFilename(Exception):
+    def __init__(self, filename):
+        Exception.__init__(self)
+        self.filename = filename
+
+class DigestMismatchException(ExceptionWithFilename): pass
+class MissingFileException(ExceptionWithFilename): pass
+
+class FileRecord(object):
+    def __init__(self, filename, size, digest, algorithm):
+        object.__init__(self)
+        self.filename = filename
+        self.size = size
+        self.digest = digest
+        self.algorithm = algorithm
+        log.debug("creating %s 0x%x" % (self.__class__.__name__, id(self)))
+
+    def __eq__(self, other):
+        if self is other:
+            return True
+        if self.filename == other.filename and \
+            self.size == other.size and \
+            self.digest == other.digest and \
+            self.algorithm == other.algorithm:
+            return True
+        else:
+            return False
+
+    def __ne__(self, other):
+        return not self.__eq__(other)
+
+    def __str__(self):
+        return repr(self)
+
+    def __repr__(self):
+        return "%s.%s(filename='%s', size='%s', digest='%s', algorithm='%s')" % (__name__,
+                self.__class__.__name__,
+                self.filename, self.size, self.digest, self.algorithm)
+
+    def present(self):
+        # Doesn't check validity
+        return os.path.exists(self.filename)
+
+    def validate_size(self):
+        if self.present():
+            return self.size == os.path.getsize(self.filename)
+        else:
+            log.debug("trying to validate size on a missing file, %s", self.filename)
+            raise MissingFileException(filename=self.filename)
+
+    def validate_digest(self):
+        if self.present():
+            with open(self.filename, 'rb') as f:
+                return self.digest == digest_file(f, self.algorithm)
+        else:
+            log.debug("trying to validate digest on a missing file, %s', self.filename")
+            raise MissingFileException(filename=self.filename)
+
+    def validate(self):
+        if self.validate_size():
+            if self.validate_digest():
+                return True
+        return False
+
+    def describe(self):
+        if self.present() and self.validate():
+            return "'%s' is present and valid" % self.filename
+        elif self.present():
+            return "'%s' is present and invalid" % self.filename
+        else:
+            return "'%s' is absent" % self.filename
+
+
+def create_file_record(filename, algorithm):
+    fo = open(filename, 'rb')
+    stored_filename = os.path.split(filename)[1]
+    fr = FileRecord(stored_filename, os.path.getsize(filename), digest_file(fo, algorithm), algorithm)
+    fo.close()
+    return fr
+
+
+class FileRecordJSONEncoder(json.JSONEncoder):
+    def encode_file_record(self, obj):
+        if not issubclass(type(obj), FileRecord):
+            err = "FileRecordJSONEncoder is only for FileRecord and lists of FileRecords, not %s" % obj.__class__.__name__
+            log.warn(err)
+            raise FileRecordJSONEncoderException(err)
+        else:
+            return {'filename': obj.filename, 'size': obj.size, 'algorithm': obj.algorithm, 'digest': obj.digest}
+
+    def default(self, f):
+        if issubclass(type(f), list):
+            record_list = []
+            for i in f:
+                record_list.append(self.encode_file_record(i))
+            return record_list
+        else:
+            return self.encode_file_record(f)
+
+
+class FileRecordJSONDecoder(json.JSONDecoder):
+    """I help the json module materialize a FileRecord from
+    a JSON file.  I understand FileRecords and lists of
+    FileRecords.  I ignore things that I don't expect for now"""
+    # TODO: make this more explicit in what it's looking for
+    # and error out on unexpected things
+    def process_file_records(self, obj):
+        if isinstance(obj, list):
+            record_list = []
+            for i in obj:
+                record = self.process_file_records(i)
+                if issubclass(type(record), FileRecord):
+                    record_list.append(record)
+            return record_list
+        if isinstance(obj, dict) and \
+           len(obj.keys()) == 4 and \
+           obj.has_key('filename') and \
+           obj.has_key('size') and \
+           obj.has_key('algorithm') and \
+           obj.has_key('digest'):
+            rv = FileRecord(obj['filename'], obj['size'], obj['digest'], obj['algorithm'])
+            log.debug("materialized %s" % rv)
+            return rv
+        return obj
+
+    def decode(self, s):
+        decoded = json.JSONDecoder.decode(self, s)
+        rv = self.process_file_records(decoded)
+        return rv
+
+
+class Manifest(object):
+
+    valid_formats = ('json',)
+
+    def __init__(self, file_records=[]):
+        self.file_records = file_records
+
+    def __eq__(self, other):
+        if self is other:
+            return True
+        if len(self.file_records) != len(other.file_records):
+            log.debug('Manifests differ in number of files')
+            return False
+        #TODO: Lists in a different order should be equal
+        for record in range(0,len(self.file_records)):
+            if self.file_records[record] != other.file_records[record]:
+                log.debug('FileRecords differ, %s vs %s' % (self.file_records[record],
+                                                            other.file_records[record]))
+                return False
+        return True
+
+    def __deepcopy__(self, memo):
+        # This is required for a deep copy
+        return Manifest(self.file_records[:])
+
+    def __copy__(self):
+        return Manifest(self.file_records)
+
+    def copy(self):
+        return Manifest(self.file_records[:])
+
+    def present(self):
+        return all(i.present() for i in self.file_records)
+
+    def validate_sizes(self):
+        return all(i.validate_size() for i in self.file_records)
+
+    def validate_digests(self):
+        return all(i.validate_digest() for i in self.file_records)
+
+    def validate(self):
+        return all(i.validate() for i in self.file_records)
+
+    def sort(self):
+        #TODO: WRITE TESTS
+        self.file_records.sort(key=lambda x: x.size)
+
+    def load(self, data_file, fmt='json'):
+        assert fmt in self.valid_formats
+        if fmt == 'json':
+            try:
+                self.file_records.extend(json.load(data_file, cls=FileRecordJSONDecoder))
+                self.sort()
+            except ValueError:
+                raise InvalidManifest("trying to read invalid manifest file")
+
+    def loads(self, data_string, fmt='json'):
+        assert fmt in self.valid_formats
+        if fmt == 'json':
+            try:
+                self.file_records.extend(json.loads(data_string, cls=FileRecordJSONDecoder))
+                self.sort()
+            except ValueError:
+                raise InvalidManifest("trying to read invalid manifest file")
+
+    def dump(self, output_file, fmt='json'):
+        assert fmt in self.valid_formats
+        self.sort()
+        if fmt == 'json':
+            rv = json.dump(self.file_records, output_file, indent=0, cls=FileRecordJSONEncoder)
+            print >> output_file, ''
+            return rv
+
+    def dumps(self, fmt='json'):
+        assert fmt in self.valid_formats
+        self.sort()
+        if fmt == 'json':
+            return json.dumps(self.file_records, cls=FileRecordJSONEncoder)
+
+
+def digest_file(f, a):
+    """I take a file like object 'f' and return a hex-string containing
+    of the result of the algorithm 'a' applied to 'f'."""
+    h = hashlib.new(a)
+    chunk_size = 1024*10
+    data = f.read(chunk_size)
+    while data:
+        h.update(data)
+        data = f.read(chunk_size)
+    if hasattr(f, 'name'):
+        log.debug('hashed %s with %s to be %s', f.name, a, h.hexdigest())
+    else:
+        log.debug('hashed a file with %s to be %s', a, h.hexdigest())
+    return h.hexdigest()
+
+# TODO: write tests for this function
+def open_manifest(manifest_file):
+    """I know how to take a filename and load it into a Manifest object"""
+    if os.path.exists(manifest_file):
+        manifest = Manifest()
+        with open(manifest_file) as f:
+            manifest.load(f)
+            log.debug("loaded manifest from file '%s'" % manifest_file)
+        return manifest
+    else:
+        log.debug("tried to load absent file '%s' as manifest" % manifest_file)
+        raise InvalidManifest("manifest file '%s' does not exist" % manifest_file)
+
+# TODO: write tests for this function
+def list_manifest(manifest_file):
+    """I know how print all the files in a location"""
+    try:
+        manifest = open_manifest(manifest_file)
+    except InvalidManifest:
+        log.error("failed to load manifest file at '%s'" % manifest_file)
+        return False
+    for f in manifest.file_records:
+        print "%s\t%s\t%s" % ("P" if f.present() else "-",
+                              "V" if f.present() and f.validate() else "-",
+                              f.filename)
+    return True
+
+def validate_manifest(manifest_file):
+    """I validate that all files in a manifest are present and valid but
+    don't fetch or delete them if they aren't"""
+    try:
+        manifest = open_manifest(manifest_file)
+    except InvalidManifest:
+        log.error("failed to load manifest file at '%s'" % manifest_file)
+        return False
+    invalid_files = []
+    absent_files = []
+    for f in manifest.file_records:
+        if not f.present():
+            absent_files.append(f)
+        else:
+            if not f.validate():
+                invalid_files.append(f)
+    if len(invalid_files + absent_files) == 0:
+        return True
+    else:
+        return False
+
+# TODO: write tests for this function
+def add_files(manifest_file, algorithm, filenames):
+    # returns True if all files successfully added, False if not
+    # and doesn't catch library Exceptions.  If any files are already
+    # tracked in the manifest, return will be False because they weren't
+    # added
+    all_files_added = True
+    # Create a old_manifest object to add to
+    if os.path.exists(manifest_file):
+        old_manifest = open_manifest(manifest_file)
+    else:
+        old_manifest = Manifest()
+        log.debug("creating a new manifest file")
+    new_manifest = Manifest() # use a different manifest for the output
+    for filename in filenames:
+        log.debug("adding %s" % filename)
+        path, name = os.path.split(filename)
+        new_fr = create_file_record(filename, algorithm)
+        log.debug("appending a new file record to manifest file")
+        add = True
+        for fr in old_manifest.file_records:
+            log.debug("manifest file has '%s'" % "', ".join([x.filename for x in old_manifest.file_records]))
+            if new_fr == fr and new_fr.validate():
+                # TODO: Decide if this case should really cause a False return
+                log.info("file already in old_manifest file and matches")
+                add = False
+            elif new_fr == fr and not new_fr.validate():
+                log.error("file already in old_manifest file but is invalid")
+                add = False
+            if filename == fr.filename:
+                log.error("manifest already contains file named %s" % filename)
+                add = False
+        if add:
+            new_manifest.file_records.append(new_fr)
+            log.debug("added '%s' to manifest" % filename)
+        else:
+            all_files_added = False
+    with open(manifest_file, 'wb') as output:
+        new_manifest.dump(output, fmt='json')
+    return all_files_added
+
+
+# TODO: write tests for this function
+def fetch_file(base_url, file_record, overwrite=False, grabchunk=1024*4):
+    # A file which is requested to be fetched that exists locally will be hashed.
+    # If the hash matches the requested file's hash, nothing will be done and the
+    # function will return.  If the function is told to overwrite and there is a 
+    # digest mismatch, the exiting file will be overwritten
+    if file_record.present():
+        if file_record.validate():
+            log.info("existing '%s' is valid, not fetching" % file_record.filename)
+            return True
+        if overwrite:
+            log.info("overwriting '%s' as requested" % file_record.filename)
+        else:
+            # All of the following is for a useful error message
+            with open(file_record.filename, 'rb') as f:
+                d = digest_file(f, file_record.algorithm)
+            log.error("digest mismatch between manifest(%s...) and local file(%s...)" % \
+                    (file_record.digest[:8], d[:8]))
+            log.debug("full digests: manifest (%s) local file (%s)" % (file_record.digest, d))
+            # Let's bail!
+            return False
+
+    # Generate the URL for the file on the server side
+    url = "%s/%s/%s" % (base_url, file_record.algorithm, file_record.digest)
+
+    log.debug("fetching from '%s'" % url)
+
+    # TODO: This should be abstracted to make generic retreival protocol handling easy
+    # Well, the file doesn't exist locally.  Lets fetch it.
+    try:
+        f = urllib2.urlopen(url)
+        log.debug("opened %s for reading" % url)
+        with open(file_record.filename, 'wb') as out:
+            k = True
+            size = 0
+            while k:
+                # TODO: print statistics as file transfers happen both for info and to stop
+                # buildbot timeouts
+                indata = f.read(grabchunk)
+                out.write(indata)
+                size += len(indata)
+                if indata == '':
+                    k = False
+            if size != file_record.size:
+                log.error("transfer from %s to %s failed due to a difference of %d bytes" % (url,
+                            file_record.filename, file_record.size - size))
+                return False
+            log.info("fetched %s" % file_record.filename)
+    except (urllib2.URLError, urllib2.HTTPError) as e:
+        log.error("failed to fetch '%s': %s" % (file_record.filename, e),
+                  exc_info=True)
+        return False
+    except IOError:
+        log.error("failed to write to '%s'" % file_record.filename,
+                  exc_info=True)
+        return False
+    return True
+
+
+# TODO: write tests for this function
+def fetch_files(manifest_file, base_url, overwrite, filenames=[]):
+    # Lets load the manifest file
+    try:
+        manifest = open_manifest(manifest_file)
+    except InvalidManifest:
+        log.error("failed to load manifest file at '%s'" % manifest_file)
+        return False
+    # We want to track files that fail to be fetched as well as
+    # files that are fetched
+    failed_files = []
+
+    # Lets go through the manifest and fetch the files that we want
+    fetched_files = []
+    for f in manifest.file_records:
+        if f.filename in filenames or len(filenames) == 0:
+            log.debug("fetching %s" % f.filename)
+            if fetch_file(base_url, f, overwrite):
+                fetched_files.append(f)
+            else:
+                failed_files.append(f.filename)
+        else:
+            log.debug("skipping %s" % f.filename)
+
+    # Even if we get the file, lets ensure that it matches what the
+    # manifest specified
+    for localfile in fetched_files:
+        if not localfile.validate():
+            log.error("'%s'" % localfile.describe())
+
+    # If we failed to fetch or validate a file, we need to fail
+    if len(failed_files) > 0:
+        log.error("The following files failed: '%s'" % "', ".join(failed_files))
+        return False
+    return True
+
+
+# TODO: write tests for this function
+def process_command(options, args):
+    """ I know how to take a list of program arguments and
+    start doing the right thing with them"""
+    cmd = args[0]
+    cmd_args = args[1:]
+    log.debug("processing '%s' command with args '%s'" % (cmd, '", "'.join(cmd_args)))
+    log.debug("using options: %s" % options)
+    if cmd == 'list':
+        return list_manifest(options['manifest'])
+    if cmd == 'validate':
+        return validate_manifest(options['manifest'])
+    elif cmd == 'add':
+        return add_files(options['manifest'], options['algorithm'], cmd_args)
+    elif cmd == 'fetch':
+        if not options.has_key('base_url') or options.get('base_url') is None:
+            log.critical('fetch command requires url option')
+            return False
+        return fetch_files(options['manifest'], options['base_url'], options['overwrite'], cmd_args)
+    else:
+        log.critical('command "%s" is not implemented' % cmd)
+        return False
+
+# fetching api:
+#   http://hostname/algorithm/hash
+#   example: http://people.mozilla.org/sha1/1234567890abcedf
+# This will make it possible to have the server allow clients to
+# use different algorithms than what was uploaded to the server
+
+# TODO: Implement the following features:
+#   -optimization: do small files first, justification is that they are faster
+#    and cause a faster failure if they are invalid
+#   -store permissions
+#   -local renames i.e. call the file one thing on the server and
+#    something different locally
+#   -deal with the cases:
+#     -local data matches file requested with different filename
+#     -two different files with same name, different hash
+#   -?only ever locally to digest as filename, symlink to real name
+#   -?maybe deal with files as a dir of the filename with all files in that dir as the versions of that file
+#      - e.g. ./python-2.6.7.dmg/0123456789abcdef and ./python-2.6.7.dmg/abcdef0123456789
+
+def main():
+    # Set up logging, for now just to the console
+    ch = logging.StreamHandler()
+    cf = logging.Formatter("%(levelname)s - %(message)s")
+    ch.setFormatter(cf)
+
+    # Set up option parsing
+    parser = optparse.OptionParser()
+    # I wish there was a way to say "only allow args to be
+    # sequential and at the end of the argv.
+    # OH! i could step through sys.argv and check for things starting without -/-- before things starting with them
+    parser.add_option('-q', '--quiet', default=False,
+            dest='quiet', action='store_true')
+    parser.add_option('-v', '--verbose', default=False,
+            dest='verbose', action='store_true')
+    parser.add_option('-m', '--manifest', default='manifest.tt',
+            dest='manifest', action='store',
+            help='specify the manifest file to be operated on')
+    parser.add_option('-d', '--algorithm', default='sha512',
+            dest='algorithm', action='store',
+            help='openssl hashing algorithm to use')
+    parser.add_option('-o', '--overwrite', default=False,
+            dest='overwrite', action='store_true',
+            help='if fetching, remote copy will overwrite a local copy that is different. ')
+    parser.add_option('--url', dest='base_url', action='store',
+            help='base url for fetching files')
+    parser.add_option('--ignore-config-files', action='store_true', default=False,
+                     dest='ignore_cfg_files')
+    (options_obj, args) = parser.parse_args()
+    # Dictionaries are easier to work with
+    options = vars(options_obj)
+
+
+    # Use some of the option parser to figure out application
+    # log level
+    if options.get('verbose'):
+        ch.setLevel(logging.DEBUG)
+    elif options.get('quiet'):
+        ch.setLevel(logging.ERROR)
+    else:
+        ch.setLevel(logging.INFO)
+    log.addHandler(ch)
+
+    cfg_file = ConfigParser.SafeConfigParser()
+    if not options.get("ignore_cfg_files"):
+        read_files = cfg_file.read(['/etc/tooltool', os.path.expanduser('~/.tooltool'),
+                   os.path.join(os.getcwd(), '.tooltool')])
+        log.debug("read in the config files '%s'" % '", '.join(read_files))
+    else:
+        log.debug("skipping config files")
+
+    for option in ('base_url', 'algorithm'):
+        if not options.get(option):
+            try:
+                options[option] = cfg_file.get('general', option)
+                log.debug("read '%s' as '%s' from cfg_file" % (option, options[option]))
+            except (ConfigParser.NoSectionError, ConfigParser.NoOptionError) as e:
+                log.debug("%s in config file" % e, exc_info=True)
+
+    if not options.has_key('manifest'):
+        parser.error("no manifest file specified")
+
+    if len(args) < 1:
+        parser.error('You must specify a command')
+    exit(0 if process_command(options, args) else 1)
+
+if __name__ == "__main__":
+    main()
+else:
+    log.addHandler(logging.NullHandler())
+    #log.addHandler(logging.StreamHandler())
--- a/caps/include/nsScriptSecurityManager.h
+++ b/caps/include/nsScriptSecurityManager.h
@@ -388,19 +388,16 @@ private:
     // GetScriptSecurityManager is the only call that can make one
     nsScriptSecurityManager();
     virtual ~nsScriptSecurityManager();
 
     static JSBool
     CheckObjectAccess(JSContext *cx, JSHandleObject obj,
                       JSHandleId id, JSAccessMode mode,
                       jsval *vp);
-
-    static JSPrincipals *
-    ObjectPrincipalFinder(JSObject *obj);
     
     // Decides, based on CSP, whether or not eval() and stuff can be executed.
     static JSBool
     ContentSecurityPolicyPermitsJSAction(JSContext *cx);
 
     // Returns null if a principal cannot be found; generally callers
     // should error out at that point.
     static nsIPrincipal* doGetObjectPrincipal(JSObject *obj);
--- a/caps/src/nsScriptSecurityManager.cpp
+++ b/caps/src/nsScriptSecurityManager.cpp
@@ -462,22 +462,16 @@ NS_IMPL_ISUPPORTS4(nsScriptSecurityManag
                    nsIObserver)
 
 ///////////////////////////////////////////////////
 // Methods implementing nsIScriptSecurityManager //
 ///////////////////////////////////////////////////
 
 ///////////////// Security Checks /////////////////
 
-/* static */ JSPrincipals *
-nsScriptSecurityManager::ObjectPrincipalFinder(JSObject *aObj)
-{
-    return nsJSPrincipals::get(doGetObjectPrincipal(aObj));
-}
-
 JSBool
 nsScriptSecurityManager::ContentSecurityPolicyPermitsJSAction(JSContext *cx)
 {
     // Get the security manager
     nsScriptSecurityManager *ssm =
         nsScriptSecurityManager::GetScriptSecurityManager();
 
     NS_ASSERTION(ssm, "Failed to get security manager service");
@@ -486,23 +480,18 @@ nsScriptSecurityManager::ContentSecurity
 
     nsresult rv;
     nsIPrincipal* subjectPrincipal = ssm->GetSubjectPrincipal(cx, &rv);
 
     NS_ASSERTION(NS_SUCCEEDED(rv), "CSP: Failed to get nsIPrincipal from js context");
     if (NS_FAILED(rv))
         return JS_FALSE; // Not just absence of principal, but failure.
 
-    if (!subjectPrincipal) {
-        // See bug 553448 for discussion of this case.
-        NS_ASSERTION(!JS_GetSecurityCallbacks(js::GetRuntime(cx))->findObjectPrincipals,
-                     "CSP: Should have been able to find subject principal. "
-                     "Reluctantly granting access.");
+    if (!subjectPrincipal)
         return JS_TRUE;
-    }
 
     nsCOMPtr<nsIContentSecurityPolicy> csp;
     rv = subjectPrincipal->GetCsp(getter_AddRefs(csp));
     NS_ASSERTION(NS_SUCCEEDED(rv), "CSP: Failed to get CSP from principal.");
 
     // don't do anything unless there's a CSP
     if (!csp)
         return JS_TRUE;
@@ -2394,20 +2383,17 @@ nsScriptSecurityManager::old_doGetObject
             if (result) {
                 break;
             }
         } else {
             nsISupports *priv;
             if (!(~jsClass->flags & (JSCLASS_HAS_PRIVATE |
                                      JSCLASS_PRIVATE_IS_NSISUPPORTS))) {
                 priv = (nsISupports *) js::GetObjectPrivate(aObj);
-            } else if (IsDOMClass(jsClass) &&
-                       DOMJSClass::FromJSClass(jsClass)->mDOMObjectIsISupports) {
-                priv = UnwrapDOMObject<nsISupports>(aObj);
-            } else {
+            } else if (!UnwrapDOMObjectToISupports(aObj, priv)) {
                 priv = nullptr;
             }
 
             if (aAllowShortCircuit) {
                 nsCOMPtr<nsIXPConnectWrappedNative> xpcWrapper =
                     do_QueryInterface(priv);
 
                 NS_ASSERTION(!xpcWrapper ||
@@ -2450,81 +2436,20 @@ nsScriptSecurityManager::old_doGetObject
 }
 #endif /* DEBUG */
 
 ///////////////// Capabilities API /////////////////////
 NS_IMETHODIMP
 nsScriptSecurityManager::IsCapabilityEnabled(const char *capability,
                                              bool *result)
 {
-    nsresult rv;
-    JSStackFrame *fp = nullptr;
     JSContext *cx = GetCurrentJSContext();
-    fp = cx ? JS_FrameIterator(cx, &fp) : nullptr;
-
-    if (!fp)
-    {
-        // No script code on stack. Allow access if and only if the subject
-        // principal is system.
-        nsresult ignored;
-        nsIPrincipal *subjectPrin = doGetSubjectPrincipal(&ignored);
-        *result = (!subjectPrin || subjectPrin == mSystemPrincipal);
+    if (cx && (*result = xpc::IsUniversalXPConnectEnabled(cx)))
         return NS_OK;
-    }
-
-    *result = false;
-    nsIPrincipal* previousPrincipal = nullptr;
-    do
-    {
-        nsIPrincipal* principal = GetFramePrincipal(cx, fp, &rv);
-        if (NS_FAILED(rv))
-            return rv;
-        if (!principal)
-            continue;
-        // If caller has a different principal, stop looking up the stack.
-        if(previousPrincipal)
-        {
-            bool isEqual = false;
-            if(NS_FAILED(previousPrincipal->Equals(principal, &isEqual)) || !isEqual)
-                break;
-        }
-        else
-            previousPrincipal = principal;
-
-        // First check if the principal is even able to enable the
-        // given capability. If not, don't look any further.
-        int16_t canEnable;
-        rv = principal->CanEnableCapability(capability, &canEnable);
-        if (NS_FAILED(rv)) return rv;
-        if (canEnable != nsIPrincipal::ENABLE_GRANTED &&
-            canEnable != nsIPrincipal::ENABLE_WITH_USER_PERMISSION)
-            return NS_OK;
-
-        // Now see if the capability is enabled.
-        void *annotation = JS_GetFrameAnnotation(cx, fp);
-        rv = principal->IsCapabilityEnabled(capability, annotation, result);
-        if (NS_FAILED(rv)) return rv;
-        if (*result)
-            return NS_OK;
-
-        // Capabilities do not extend to calls into C/C++ and then back into
-        // the JS engine via JS_EvaluateScript or similar APIs.
-        if (JS_IsGlobalFrame(cx, fp))
-            break;
-    } while ((fp = JS_FrameIterator(cx, &fp)) != nullptr);
-
-    if (!previousPrincipal)
-    {
-        // No principals on the stack, all native code.  Allow
-        // execution if the subject principal is the system principal.
-
-        return SubjectPrincipalIsSystem(result);
-    }
-
-    return NS_OK;
+    return SubjectPrincipalIsSystem(result);
 }
 
 void
 nsScriptSecurityManager::FormatCapabilityString(nsAString& aCapability)
 {
     nsAutoString newcaps;
     nsAutoString rawcap;
     NS_NAMED_LITERAL_STRING(capdesc, "capdesc.");
@@ -3046,18 +2971,16 @@ nsresult nsScriptSecurityManager::Init()
         do_QueryInterface(sXPConnect, &rv);
     NS_ENSURE_SUCCESS(rv, rv);
 
     rv = runtimeService->GetRuntime(&sRuntime);
     NS_ENSURE_SUCCESS(rv, rv);
 
     static const JSSecurityCallbacks securityCallbacks = {
         CheckObjectAccess,
-        nsJSPrincipals::Subsume,
-        ObjectPrincipalFinder,
         ContentSecurityPolicyPermitsJSAction
     };
 
     MOZ_ASSERT(!JS_GetSecurityCallbacks(sRuntime));
     JS_SetSecurityCallbacks(sRuntime, &securityCallbacks);
     JS_InitDestroyPrincipalsCallback(sRuntime, nsJSPrincipals::Destroy);
 
     JS_SetTrustedPrincipals(sRuntime, system);
--- a/caps/src/nsSecurityManagerFactory.cpp
+++ b/caps/src/nsSecurityManagerFactory.cpp
@@ -20,94 +20,37 @@
 #include "nsString.h"
 #include "nsNetCID.h"
 #include "nsIClassInfoImpl.h"
 #include "nsJSUtils.h"
 #include "nsPIDOMWindow.h"
 #include "nsIScriptGlobalObject.h"
 #include "nsIDocument.h"
 #include "jsfriendapi.h"
+#include "xpcprivate.h"
+#include "mozilla/Preferences.h"
 
 ///////////////////////
 // nsSecurityNameSet //
 ///////////////////////
 
 nsSecurityNameSet::nsSecurityNameSet()
 {
 }
 
 nsSecurityNameSet::~nsSecurityNameSet()
 {
 }
 
 NS_IMPL_ISUPPORTS1(nsSecurityNameSet, nsIScriptExternalNameSet)
 
-static JSString *
-getStringArgument(JSContext *cx, JSObject *obj, uint16_t argNum, unsigned argc, jsval *argv)
-{
-    if (argc <= argNum || !JSVAL_IS_STRING(argv[argNum])) {
-        JS_ReportError(cx, "String argument expected");
-        return nullptr;
-    }
-
-    /*
-     * We don't want to use JS_ValueToString because we want to be able
-     * to have an object to represent a target in subsequent versions.
-     */
-    return JSVAL_TO_STRING(argv[argNum]);
-}
-
-static bool
-getBytesArgument(JSContext *cx, JSObject *obj, uint16_t argNum, unsigned argc, jsval *argv,
-                 JSAutoByteString *bytes)
-{
-    JSString *str = getStringArgument(cx, obj, argNum, argc, argv);
-    return str && bytes->encode(cx, str);
-}
-
 static JSBool
 netscape_security_enablePrivilege(JSContext *cx, unsigned argc, jsval *vp)
 {
-    JSObject *obj = JS_THIS_OBJECT(cx, vp);
-    if (!obj)
-        return JS_FALSE;
-
-    JSAutoByteString cap;
-    if (!getBytesArgument(cx, obj, 0, argc, JS_ARGV(cx, vp), &cap))
-        return JS_FALSE;
-
-    // Can't use nsContentUtils::GetDocumentFromCaller because that
-    // depends on various XPConnect stuff that's not set up here.
-    {
-        JSAutoEnterCompartment ac;
-        if (ac.enter(cx, obj)) {
-            nsCOMPtr<nsPIDOMWindow> win =
-                do_QueryInterface(nsJSUtils::GetStaticScriptGlobal(cx, obj));
-            if (win) {
-                nsCOMPtr<nsIDocument> doc =
-                    do_QueryInterface(win->GetExtantDocument());
-                if (doc) {
-                    doc->WarnOnceAbout(nsIDocument::eEnablePrivilege);
-                }
-            }
-        }
-    }
-
-    nsresult rv;
-    nsCOMPtr<nsIScriptSecurityManager> securityManager = 
-             do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID, &rv);
-    if (NS_FAILED(rv)) 
-        return JS_FALSE;
-
-    //    NS_ASSERTION(cx == GetCurrentContext(), "unexpected context");
-
-    rv = securityManager->EnableCapability(cap.ptr());
-    if (NS_FAILED(rv))
-        return JS_FALSE;
-    JS_SET_RVAL(cx, vp, JSVAL_VOID);
+    xpc::EnableUniversalXPConnect(cx);
     return JS_TRUE;
 }
 
 static JSFunctionSpec PrivilegeManager_static_methods[] = {
     JS_FS("enablePrivilege", netscape_security_enablePrivilege, 1, 0),
     JS_FS_END
 };
 
@@ -116,16 +59,25 @@ static JSFunctionSpec PrivilegeManager_s
  * et al. so that code that worked with 4.0 can still work.
  */
 NS_IMETHODIMP 
 nsSecurityNameSet::InitializeNameSet(nsIScriptContext* aScriptContext)
 {
     JSContext* cx = aScriptContext->GetNativeContext();
     JSObject *global = JS_ObjectToInnerObject(cx, JS_GetGlobalObject(cx));
 
+    // We hide enablePrivilege behind a pref because it has been altered in a
+    // way that makes it fundamentally insecure to use in production. Mozilla
+    // uses this pref during automated testing to support legacy test code that
+    // uses enablePrivilege. If you're not doing test automation, you _must_ not
+    // flip this pref, or you will be exposing all your users to security
+    // vulnerabilities.
+    if (!mozilla::Preferences::GetBool("security.enablePrivilege.enable_for_tests"))
+        return NS_OK;
+
     /*
      * Find Object.prototype's class by walking up the global object's
      * prototype chain.
      */
     JSObject *obj = global;
     JSObject *proto;
     JSAutoRequest ar(cx);
     while ((proto = JS_GetPrototype(obj)) != nullptr)
--- a/config/rules.mk
+++ b/config/rules.mk
@@ -1582,32 +1582,30 @@ endif # COMPILER_DEPEND
 #   a previous build in the source tree) and thus neglect to create a
 #   dependency directory in the object directory, where we really need
 #   it.
 
 $(CURDIR)/$(MDDEPDIR):
 	$(MKDIR) -p $@
 
 ifneq (,$(filter-out all chrome default export realchrome tools clean clobber clobber_all distclean realclean,$(MAKECMDGOALS)))
-ifneq (,$(OBJS)$(XPIDLSRCS)$(SIMPLE_PROGRAMS))
 MDDEPEND_FILES		:= $(strip $(wildcard $(MDDEPDIR)/*.pp))
 
 ifneq (,$(MDDEPEND_FILES))
 # The script mddepend.pl checks the dependencies and writes to stdout
 # one rule to force out-of-date objects. For example,
 #   foo.o boo.o: FORCE
 # The script has an advantage over including the *.pp files directly
 # because it handles the case when header files are removed from the build.
 # 'make' would complain that there is no way to build missing headers.
 ALL_PP_RESULTS = $(shell $(PERL) $(BUILD_TOOLS)/mddepend.pl - $(MDDEPEND_FILES))
 $(eval $(ALL_PP_RESULTS))
 endif
 
 endif
-endif
 #############################################################################
 
 -include $(topsrcdir)/$(MOZ_BUILD_APP)/app-rules.mk
 -include $(MY_RULES)
 
 #
 # Generate Emacs tags in a file named TAGS if ETAGS was set in $(MY_CONFIG)
 # or in $(MY_RULES)
--- a/content/base/public/Makefile.in
+++ b/content/base/public/Makefile.in
@@ -37,17 +37,16 @@ nsContentCID.h \
 nsCopySupport.h \
 nsContentCreatorFunctions.h \
 nsDOMFile.h \
 nsLineBreaker.h \
 nsReferencedElement.h \
 nsTreeSanitizer.h \
 nsXMLNameSpaceMap.h \
 nsIXFormsUtilityService.h \
-nsBlobProtocolHandler.h \
 $(NULL)
 
 EXPORTS_NAMESPACES = mozilla/dom mozilla
 
 EXPORTS_mozilla/dom = \
 		DirectionalityUtils.h \
 		Element.h \
 		FragmentOrElement.h \
deleted file mode 100644
--- a/content/base/public/nsBlobProtocolHandler.h
+++ /dev/null
@@ -1,51 +0,0 @@
-/* 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 nsBlobProtocolHandler_h
-#define nsBlobProtocolHandler_h
-
-#include "nsIProtocolHandler.h"
-#include "nsIURI.h"
-#include "nsCOMPtr.h"
-
-#define BLOBURI_SCHEME "blob"
-
-class nsIDOMBlob;
-class nsIPrincipal;
-class nsIInputStream;
-
-inline bool IsBlobURI(nsIURI* aUri)
-{
-  bool isBlob;
-  return NS_SUCCEEDED(aUri->SchemeIs(BLOBURI_SCHEME, &isBlob)) && isBlob;
-}
-
-extern nsresult
-NS_GetStreamForBlobURI(nsIURI* aURI, nsIInputStream** aStream);
-
-class nsBlobProtocolHandler : public nsIProtocolHandler
-{
-public:
-  NS_DECL_ISUPPORTS
-
-  // nsIProtocolHandler methods:
-  NS_DECL_NSIPROTOCOLHANDLER
-
-  // nsBlobProtocolHandler methods:
-  nsBlobProtocolHandler() {}
-  virtual ~nsBlobProtocolHandler() {}
-
-  // Methods for managing uri->file mapping
-  static void AddFileDataEntry(nsACString& aUri,
-                               nsIDOMBlob* aFile,
-                               nsIPrincipal* aPrincipal);
-  static void RemoveFileDataEntry(nsACString& aUri);
-  static nsIPrincipal* GetFileDataEntryPrincipal(nsACString& aUri);
-};
-
-#define NS_BLOBPROTOCOLHANDLER_CID \
-{ 0xb43964aa, 0xa078, 0x44b2, \
-  { 0xb0, 0x6b, 0xfd, 0x4d, 0x1b, 0x17, 0x2e, 0x66 } }
-
-#endif /* nsBlobProtocolHandler_h */
--- a/content/base/src/FragmentOrElement.cpp
+++ b/content/base/src/FragmentOrElement.cpp
@@ -386,17 +386,17 @@ NS_INTERFACE_TABLE_HEAD(nsChildContentLi
   NS_INTERFACE_MAP_ENTRIES_CYCLE_COLLECTION(nsChildContentList)
   NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(NodeList)
 NS_INTERFACE_MAP_END
 
 JSObject*
 nsChildContentList::WrapObject(JSContext *cx, JSObject *scope,
                                bool *triedToWrap)
 {
-  return mozilla::dom::binding::NodeList::create(cx, scope, this, triedToWrap);
+  return mozilla::dom::oldproxybindings::NodeList::create(cx, scope, this, triedToWrap);
 }
 
 NS_IMETHODIMP
 nsChildContentList::GetLength(uint32_t* aLength)
 {
   *aLength = mNode ? mNode->GetChildCount() : 0;
 
   return NS_OK;
--- a/content/base/src/nsBlobProtocolHandler.cpp
+++ b/content/base/src/nsBlobProtocolHandler.cpp
@@ -158,18 +158,18 @@ nsBlobProtocolHandler::NewChannel(nsIURI
 #endif
 
   nsCOMPtr<nsIInputStream> stream;
   nsresult rv = info->mFile->GetInternalStream(getter_AddRefs(stream));
   NS_ENSURE_SUCCESS(rv, rv);
 
   nsCOMPtr<nsIChannel> channel;
   rv = NS_NewInputStreamChannel(getter_AddRefs(channel),
-                                uri,
-                                stream);
+				uri,
+				stream);
   NS_ENSURE_SUCCESS(rv, rv);
 
   nsCOMPtr<nsISupports> owner = do_QueryInterface(info->mPrincipal);
 
   nsAutoString type;
   rv = info->mFile->GetType(type);
   NS_ENSURE_SUCCESS(rv, rv);
 
@@ -184,28 +184,8 @@ nsBlobProtocolHandler::NewChannel(nsIURI
 NS_IMETHODIMP 
 nsBlobProtocolHandler::AllowPort(int32_t port, const char *scheme,
                                      bool *_retval)
 {
     // don't override anything.  
     *_retval = false;
     return NS_OK;
 }
-
-nsresult
-NS_GetStreamForBlobURI(nsIURI* aURI, nsIInputStream** aStream)
-{
-  NS_ASSERTION(IsBlobURI(aURI), "Only call this with blob URIs");
-
-  *aStream = nullptr;
-
-  nsCString spec;
-  aURI->GetSpec(spec);
-
-  FileDataInfo* info =
-    GetFileDataInfo(spec);
-
-  if (!info) {
-    return NS_ERROR_DOM_BAD_URI;
-  }
-
-  return info->mFile->GetInternalStream(aStream);
-}
--- a/content/base/src/nsBlobProtocolHandler.h
+++ b/content/base/src/nsBlobProtocolHandler.h
@@ -1,51 +1,40 @@
 /* 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 nsBlobProtocolHandler_h
 #define nsBlobProtocolHandler_h
 
 #include "nsIProtocolHandler.h"
-#include "nsIURI.h"
-#include "nsCOMPtr.h"
 
 #define BLOBURI_SCHEME "blob"
 
 class nsIDOMBlob;
 class nsIPrincipal;
-class nsIInputStream;
-
-inline bool IsBlobURI(nsIURI* aUri)
-{
-  bool isBlob;
-  return NS_SUCCEEDED(aUri->SchemeIs(BLOBURI_SCHEME, &isBlob)) && isBlob;
-}
-
-extern nsresult
-NS_GetStreamForBlobURI(nsIURI* aURI, nsIInputStream** aStream);
 
 class nsBlobProtocolHandler : public nsIProtocolHandler
 {
 public:
   NS_DECL_ISUPPORTS
 
   // nsIProtocolHandler methods:
   NS_DECL_NSIPROTOCOLHANDLER
 
   // nsBlobProtocolHandler methods:
   nsBlobProtocolHandler() {}
   virtual ~nsBlobProtocolHandler() {}
 
   // Methods for managing uri->file mapping
   static void AddFileDataEntry(nsACString& aUri,
-                               nsIDOMBlob* aFile,
+			       nsIDOMBlob* aFile,
                                nsIPrincipal* aPrincipal);
   static void RemoveFileDataEntry(nsACString& aUri);
   static nsIPrincipal* GetFileDataEntryPrincipal(nsACString& aUri);
+  
 };
 
 #define NS_BLOBPROTOCOLHANDLER_CID \
 { 0xb43964aa, 0xa078, 0x44b2, \
   { 0xb0, 0x6b, 0xfd, 0x4d, 0x1b, 0x17, 0x2e, 0x66 } }
 
 #endif /* nsBlobProtocolHandler_h */
--- a/content/base/src/nsContentList.cpp
+++ b/content/base/src/nsContentList.cpp
@@ -157,17 +157,17 @@ NS_INTERFACE_MAP_END_INHERITING(nsBaseCo
 
 NS_IMPL_ADDREF_INHERITED(nsSimpleContentList, nsBaseContentList)
 NS_IMPL_RELEASE_INHERITED(nsSimpleContentList, nsBaseContentList)
 
 JSObject*
 nsSimpleContentList::WrapObject(JSContext *cx, JSObject *scope,
                                 bool *triedToWrap)
 {
-  return mozilla::dom::binding::NodeList::create(cx, scope, this, triedToWrap);
+  return mozilla::dom::oldproxybindings::NodeList::create(cx, scope, this, triedToWrap);
 }
 
 // nsFormContentList
 
 nsFormContentList::nsFormContentList(nsIContent *aForm,
                                      nsBaseContentList& aContentList)
   : nsSimpleContentList(aForm)
 {
@@ -473,17 +473,17 @@ nsContentList::~nsContentList()
     // Clean up mData
     (*mDestroyFunc)(mData);
   }
 }
 
 JSObject*
 nsContentList::WrapObject(JSContext *cx, JSObject *scope, bool *triedToWrap)
 {
-  return mozilla::dom::binding::HTMLCollection::create(cx, scope, this,
+  return mozilla::dom::oldproxybindings::HTMLCollection::create(cx, scope, this,
                                                        triedToWrap);
 }
 
 DOMCI_DATA(ContentList, nsContentList)
 
 // QueryInterface implementation for nsContentList
 NS_INTERFACE_TABLE_HEAD(nsContentList)
   NS_NODELIST_OFFSET_AND_INTERFACE_TABLE_BEGIN(nsContentList)
--- a/content/base/src/nsDOMFile.cpp
+++ b/content/base/src/nsDOMFile.cpp
@@ -13,17 +13,16 @@
 #include "nsICharsetDetector.h"
 #include "nsICharsetConverterManager.h"
 #include "nsIClassInfo.h"
 #include "nsIConverterInputStream.h"
 #include "nsIDocument.h"
 #include "nsIFileStreams.h"
 #include "nsIInputStream.h"
 #include "nsIIPCSerializableInputStream.h"
-#include "nsIIPCSerializableObsolete.h"
 #include "nsIMIMEService.h"
 #include "nsIPlatformCharset.h"
 #include "nsISeekableStream.h"
 #include "nsIUnicharInputStream.h"
 #include "nsIUnicodeDecoder.h"
 #include "nsNetCID.h"
 #include "nsNetUtil.h"
 #include "nsIUUIDGenerator.h"
@@ -43,68 +42,57 @@ using namespace mozilla::dom;
 
 // XXXkhuey the input stream that we pass out of a DOMFile
 // can outlive the actual DOMFile object.  Thus, we must
 // ensure that the buffer underlying the stream we get
 // from NS_NewByteInputStream is held alive as long as the
 // stream is.  We do that by passing back this class instead.
 class DataOwnerAdapter MOZ_FINAL : public nsIInputStream,
                                    public nsISeekableStream,
-                                   public nsIIPCSerializableObsolete,
-                                   public nsIClassInfo,
                                    public nsIIPCSerializableInputStream
 {
   typedef nsDOMMemoryFile::DataOwner DataOwner;
 public:
   static nsresult Create(DataOwner* aDataOwner,
                          uint32_t aStart,
                          uint32_t aLength,
                          nsIInputStream** _retval);
 
   NS_DECL_ISUPPORTS
 
   // These are mandatory.
   NS_FORWARD_NSIINPUTSTREAM(mStream->)
   NS_FORWARD_NSISEEKABLESTREAM(mSeekableStream->)
 
-  // These are optional. We use a conditional QI to keep them from being called
-  // if the underlying stream doesn't QI to either interface.
-  NS_FORWARD_NSIIPCSERIALIZABLEOBSOLETE(mSerializableObsolete->)
-  NS_FORWARD_NSICLASSINFO(mClassInfo->)
+  // This is optional. We use a conditional QI to keep it from being called
+  // if the underlying stream doesn't support it.
   NS_FORWARD_NSIIPCSERIALIZABLEINPUTSTREAM(mSerializableInputStream->)
 
 private:
   DataOwnerAdapter(DataOwner* aDataOwner,
                    nsIInputStream* aStream)
     : mDataOwner(aDataOwner), mStream(aStream),
       mSeekableStream(do_QueryInterface(aStream)),
-      mSerializableObsolete(do_QueryInterface(aStream)),
-      mClassInfo(do_QueryInterface(aStream)),
       mSerializableInputStream(do_QueryInterface(aStream))
   {
     NS_ASSERTION(mSeekableStream, "Somebody gave us the wrong stream!");
   }
 
   nsRefPtr<DataOwner> mDataOwner;
   nsCOMPtr<nsIInputStream> mStream;
   nsCOMPtr<nsISeekableStream> mSeekableStream;
-  nsCOMPtr<nsIIPCSerializableObsolete> mSerializableObsolete;
-  nsCOMPtr<nsIClassInfo> mClassInfo;
   nsCOMPtr<nsIIPCSerializableInputStream> mSerializableInputStream;
 };
 
 NS_IMPL_THREADSAFE_ADDREF(DataOwnerAdapter)
 NS_IMPL_THREADSAFE_RELEASE(DataOwnerAdapter)
 
 NS_INTERFACE_MAP_BEGIN(DataOwnerAdapter)
   NS_INTERFACE_MAP_ENTRY(nsIInputStream)
   NS_INTERFACE_MAP_ENTRY(nsISeekableStream)
-  NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsIIPCSerializableObsolete,
-                                     mSerializableObsolete)
-  NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsIClassInfo, mClassInfo)
   NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsIIPCSerializableInputStream,
                                      mSerializableInputStream)
   NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIInputStream)
 NS_INTERFACE_MAP_END
 
 nsresult DataOwnerAdapter::Create(DataOwner* aDataOwner,
                                   uint32_t aStart,
                                   uint32_t aLength,
@@ -683,17 +671,17 @@ NS_INTERFACE_MAP_END
 
 NS_IMPL_CYCLE_COLLECTING_ADDREF(nsDOMFileList)
 NS_IMPL_CYCLE_COLLECTING_RELEASE(nsDOMFileList)
 
 JSObject*
 nsDOMFileList::WrapObject(JSContext *cx, JSObject *scope,
                           bool *triedToWrap)
 {
-  return mozilla::dom::binding::FileList::create(cx, scope, this, triedToWrap);
+  return mozilla::dom::oldproxybindings::FileList::create(cx, scope, this, triedToWrap);
 }
 
 nsIDOMFile*
 nsDOMFileList::GetItemAt(uint32_t aIndex)
 {
   return mFiles.SafeObjectAt(aIndex);
 }
 
--- a/content/base/src/nsDOMSettableTokenList.cpp
+++ b/content/base/src/nsDOMSettableTokenList.cpp
@@ -46,11 +46,11 @@ nsDOMSettableTokenList::SetValue(const n
 
   return mElement->SetAttr(kNameSpaceID_None, mAttrAtom, aValue, true);
 }
 
 JSObject*
 nsDOMSettableTokenList::WrapObject(JSContext *cx, JSObject *scope,
                                    bool *triedToWrap)
 {
-  return mozilla::dom::binding::DOMSettableTokenList::create(cx, scope, this,
+  return mozilla::dom::oldproxybindings::DOMSettableTokenList::create(cx, scope, this,
                                                              triedToWrap);
 }
--- a/content/base/src/nsDOMTokenList.cpp
+++ b/content/base/src/nsDOMTokenList.cpp
@@ -267,12 +267,12 @@ nsDOMTokenList::ToString(nsAString& aRes
   mElement->GetAttr(kNameSpaceID_None, mAttrAtom, aResult);
 
   return NS_OK;
 }
 
 JSObject*
 nsDOMTokenList::WrapObject(JSContext *cx, JSObject *scope, bool *triedToWrap)
 {
-  return mozilla::dom::binding::DOMTokenList::create(cx, scope, this,
+  return mozilla::dom::oldproxybindings::DOMTokenList::create(cx, scope, this,
                                                      triedToWrap);
 }
 
--- a/content/base/test/test_bug333198.html
+++ b/content/base/test/test_bug333198.html
@@ -25,32 +25,25 @@ var focusTester;
 var focusTester2;
 var focusCount = 0;
 var eventCount = 0;
 function clickHandler() {
   ++eventCount;
 }
 
 function suppressEvents(suppress) {
-  netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
-  window.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
-        .getInterface(Components.interfaces.nsIDOMWindowUtils)
-        .suppressEventHandling(suppress);
+  SpecialPowers.DOMWindowUtils.suppressEventHandling(suppress);
 }
 
 function sendEvents() {
-  netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
-  windowUtils = window.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
-                      .getInterface(Components.interfaces.nsIDOMWindowUtils);
+  windowUtils = SpecialPowers.getDOMWindowUtils(window);
   windowUtils.sendMouseEvent("mousedown", 1, 1, 0, 1, 0);
   windowUtils.sendMouseEvent("mouseup", 1, 1, 0, 1, 0);
 
-  iframeUtils = document.getElementById("ifr").contentWindow
-                        .QueryInterface(Components.interfaces.nsIInterfaceRequestor)
-                        .getInterface(Components.interfaces.nsIDOMWindowUtils);
+  iframeUtils = SpecialPowers.getDOMWindowUtils(document.getElementById("ifr").contentWindow);
   iframeUtils.sendMouseEvent("mousedown", 1, 1, 0, 1, 0);
   iframeUtils.sendMouseEvent("mouseup", 1, 1, 0, 1, 0);
 }
 
 function runTest() {
   window.focus();
   focusTester = document.getElementsByTagName("input")[0];
   focusTester.blur();
--- a/content/events/src/nsPaintRequest.h
+++ b/content/events/src/nsPaintRequest.h
@@ -41,17 +41,17 @@ public:
 
   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
   NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(nsPaintRequestList)
   NS_DECL_NSIDOMPAINTREQUESTLIST
   
   virtual JSObject* WrapObject(JSContext *cx, JSObject *scope,
                                bool *triedToWrap)
   {
-    return mozilla::dom::binding::PaintRequestList::create(cx, scope, this,
+    return mozilla::dom::oldproxybindings::PaintRequestList::create(cx, scope, this,
                                                            triedToWrap);
   }
 
   nsISupports* GetParentObject()
   {
     return mParent;
   }
 
--- a/content/events/test/test_bug226361.xhtml
+++ b/content/events/test/test_bug226361.xhtml
@@ -43,19 +43,17 @@ function setOrRestoreTabFocus(newValue) 
     prefs.setIntPref("tabfocus", newValue);
   }
 }
 
 // =================================
 
 var doc = document;
 function tab_to(id) {
-  netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
-  var wu =  doc.defaultView.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
-                .getInterface(Components.interfaces.nsIDOMWindowUtils);
+  var wu = SpecialPowers.DOMWindowUtils;
   wu.sendKeyEvent('keypress',  9, 0, 0);
   is(doc.activeElement.id, id, "element with id=" + id + " should have focus");
 }
 
 function tab_iframe() {
   doc = document;
   tab_to('iframe');
 
--- a/content/events/test/test_bug493251.html
+++ b/content/events/test/test_bug493251.html
@@ -26,37 +26,31 @@ https://bugzilla.mozilla.org/show_bug.cg
   var mouseUp = 0;
   var mouseClick = 0;
 
   var keyDown = 0;
   var keyPress = 0;
   var keyUp = 0;
 
   function suppressEventHandling(aSuppress) {
-    netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
-    var utils = win.QueryInterface(Components.interfaces.nsIInterfaceRequestor).
-                    getInterface(Components.interfaces.nsIDOMWindowUtils);
+    var utils = SpecialPowers.getDOMWindowUtils(win);
     ok(true, "suppressEventHandling: aSuppress=" + aSuppress);
     utils.suppressEventHandling(aSuppress);
   }
 
   function dispatchKeyEvent(type) {
-    netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
-    var utils = win.QueryInterface(Components.interfaces.nsIInterfaceRequestor).
-                    getInterface(Components.interfaces.nsIDOMWindowUtils);
+    var utils = SpecialPowers.getDOMWindowUtils(win);
     ok(true, "Dipatching key event: type=" + type);
     utils.sendKeyEvent(type, 
                        Components.interfaces.nsIDOMKeyEvent.DOM_VK_A,
                        0, 0);
   }
 
   function dispatchMouseEvent(aType, aX, aY, aButton, aClickCount, aModifiers) {
-    netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
-    var utils = win.QueryInterface(Components.interfaces.nsIInterfaceRequestor).
-                    getInterface(Components.interfaces.nsIDOMWindowUtils);
+    var utils = SpecialPowers.getDOMWindowUtils(win);
     ok(true, "Dipatching mouse event: aType=" + aType + ", aX=" + aX + ", aY" +
                aY + ", aButton=" + aButton + ", aClickCount=" + aClickCount +
                ", aModifiers=" + aModifiers);
     utils.sendMouseEvent(aType, aX, aY, aButton, aClickCount, aModifiers);
   }
 
   function dumpEvent(aEvent) {
     var detail = "target=" + aEvent.target + ", originalTarget=" +
@@ -83,18 +77,17 @@ https://bugzilla.mozilla.org/show_bug.cg
           ", shiftKey=" + (aEvent.shiftKey ? "PRESSED" : "no") +
           ", metaKey=" + (aEvent.metaKey ? "PRESSED" : "no") +
           ", button=" + aEvent.button +
           ", relatedTarget=" + aEvent.relatedTarget;
         break;
     }
     ok(true, aEvent.type + " event is handled: " + detail);
 
-    netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
-    var fm = Components.classes["@mozilla.org/focus-manager;1"].
+    var fm = SpecialPowers.wrap(Components).classes["@mozilla.org/focus-manager;1"].
                         getService(Components.interfaces.nsIFocusManager);
     ok(true, "focused element is \"" + fm.focusedElement +
              "\" and focused window is \"" + fm.focusedWindow +
              "\" (the testing window is \"" + win + "\"");
   }
 
   function doTest() {
     win.document.getElementsByTagName("input")[0].focus();
--- a/content/events/test/test_bug545268.html
+++ b/content/events/test/test_bug545268.html
@@ -29,28 +29,24 @@ https://bugzilla.mozilla.org/show_bug.cg
   var mouseUp = 0;
   var mouseClick = 0;
 
   var keyDown = 0;
   var keyPress = 0;
   var keyUp = 0;
 
   function dispatchKeyEvent(type) {
-    netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
-    var utils = subwin.QueryInterface(Components.interfaces.nsIInterfaceRequestor).
-                    getInterface(Components.interfaces.nsIDOMWindowUtils);
+    var utils = SpecialPowers.getDOMWindowUtils(subwin);
     utils.sendKeyEvent(type, 
                        Components.interfaces.nsIDOMKeyEvent.DOM_VK_A,
                        0, 0);
   }
 
   function doTest() {
-    netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
-    var utils = win.QueryInterface(Components.interfaces.nsIInterfaceRequestor).
-                    getInterface(Components.interfaces.nsIDOMWindowUtils);
+    var utils = SpecialPowers.getDOMWindowUtils(win);
     var f = win.document.getElementById("f");
     subwin = f.contentWindow;
     subwin.document.getElementsByTagName("input")[0].focus();
     subwin.addEventListener("keydown", function(e) { ++keyDown; }, true);
     subwin.addEventListener("keypress", function(e) { ++keyPress; }, true);
     subwin.addEventListener("keyup", function(e) { ++keyUp; }, true);
     subwin.addEventListener("mousedown", function(e) { ++mouseDown; }, true);
     subwin.addEventListener("mouseup", function(e) { ++mouseUp; }, true);
@@ -76,34 +72,30 @@ https://bugzilla.mozilla.org/show_bug.cg
     is(keyDown, 1, "Wrong number events (7)");
     is(keyPress, 1, "Wrong number events (8)");
     is(keyUp, 1, "Wrong number events (9)");
 
     setTimeout(continueTest1, 0);
     }
 
   function continueTest1() {
-    netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
-    var utils = win.QueryInterface(Components.interfaces.nsIInterfaceRequestor).
-                    getInterface(Components.interfaces.nsIDOMWindowUtils);
+    var utils = SpecialPowers.getDOMWindowUtils(win);
     dispatchKeyEvent("keydown");
     utils.suppressEventHandling(true);
     dispatchKeyEvent("keypress");
     dispatchKeyEvent("keyup");
     is(keyDown, 2, "Wrong number events (10)");
     is(keyPress, 1, "Wrong number events (11)");
     is(keyUp, 1, "Wrong number events (12)");
     utils.suppressEventHandling(false);
     setTimeout(continueTest2, 0);
   }
 
   function continueTest2() {
-    netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
-    var utils = win.QueryInterface(Components.interfaces.nsIInterfaceRequestor).
-                    getInterface(Components.interfaces.nsIDOMWindowUtils);
+    var utils = SpecialPowers.getDOMWindowUtils(win);
     is(keyDown, 2, "Wrong number events (13)");
     is(keyPress, 2, "Wrong number events (14)");
     is(keyUp, 2, "Wrong number events (15)");
 
     utils.sendMouseEvent("mousedown", 5, 5, 0, 1, 0);
     utils.sendMouseEvent("mouseup", 5, 5, 0, 1, 0);
     is(mouseDown, 1, "Wrong number events (16)");
     is(mouseUp, 1, "Wrong number events (17)");
@@ -116,19 +108,17 @@ https://bugzilla.mozilla.org/show_bug.cg
     is(mouseDown, 1, "Wrong number events (19)");
     is(mouseUp, 1, "Wrong number events (20)");
     is(mouseClick, 1, "Wrong number events (21)");
 
     setTimeout(continueTest3, 0);
   }
 
   function continueTest3() {
-    netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
-    var utils = win.QueryInterface(Components.interfaces.nsIInterfaceRequestor).
-                    getInterface(Components.interfaces.nsIDOMWindowUtils);
+    var utils = SpecialPowers.getDOMWindowUtils(win);
     utils.sendMouseEvent("mousedown", 5, 5, 0, 1, 0);
     utils.suppressEventHandling(true);
     utils.sendMouseEvent("mouseup", 5, 5, 0, 1, 0);
     utils.suppressEventHandling(false);
     setTimeout(continueTest4, 1000);
   }
 
   function continueTest4() {
--- a/content/events/test/test_bug574663.html
+++ b/content/events/test/test_bug574663.html
@@ -39,19 +39,17 @@ function sendTouchpadScrollMotion(scroll
 
 function runTest() {
   var win = open('data:text/html,<!DOCTYPE html>\n' +
     '<div id="scrollbox" style="height: 100px; overflow: auto;">' +
     '  <div style="height: 1000px;"></div>' +
     '</div>', '_blank', 'width=300,height=300');
   SimpleTest.waitForFocus(function () {
     var scrollbox = win.document.getElementById("scrollbox");
-    netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
-    let winUtils = win.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
-                      .getInterface(Components.interfaces.nsIDOMWindowUtils);
+    let winUtils = SpecialPowers.getDOMWindowUtils(win);
     let outstandingTests = [
       [false, false],
       [false, true],
       [true, false],
       [true, true],
     ];
     function nextTest() {
       netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
--- a/content/events/test/test_bug593959.html
+++ b/content/events/test/test_bug593959.html
@@ -21,30 +21,27 @@ https://bugzilla.mozilla.org/show_bug.cg
   
 </div>
 <pre id="test">
 <script type="application/javascript">
 
 /** Test for Bug 593959 **/
 
   function doTest() {
-    netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
-    var utils = window.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
-                       .getInterface(Components.interfaces.nsIDOMWindowUtils);
+    var utils = SpecialPowers.getDOMWindowUtils(window);
     var e = document.createEvent("MouseEvent");
     e.initEvent("mousedown", false, false, window, 0, 1, 1, 1, 1,
                 false, false, false, false, 0, null);
     utils.dispatchDOMEventViaPresShell(document.body, e, true);
     
     is(document.querySelector("body:active"), document.body, "body should be active!")
     
     var ifrwindow = document.getElementById("ifr").contentWindow;
     
-    var utils2 = ifrwindow.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
-                          .getInterface(Components.interfaces.nsIDOMWindowUtils);
+    var utils2 = SpecialPowers.getDOMWindowUtils(ifrwindow);
    
     var e2 = ifrwindow.document.createEvent("MouseEvent");
     e2.initEvent("mouseup", false, false, ifrwindow, 0, 1, 1, 1, 1,
                  false, false, false, false, 0, null);
     utils2.dispatchDOMEventViaPresShell(ifrwindow.document.body, e2, true);
     
     isnot(document.querySelector("body:active"), document.body, "body shouldn't be active!")
 
--- a/content/html/content/src/HTMLPropertiesCollection.cpp
+++ b/content/html/content/src/HTMLPropertiesCollection.cpp
@@ -103,17 +103,17 @@ HTMLPropertiesCollection::SetDocument(ns
   mNamedItemEntries.EnumerateRead(SetPropertyListDocument, aDocument);
   mIsDirty = true;
 }
 
 JSObject*
 HTMLPropertiesCollection::WrapObject(JSContext* cx, JSObject* scope,
                                      bool* triedToWrap)
 {
-  return mozilla::dom::binding::HTMLPropertiesCollection::create(cx, scope, this,
+  return mozilla::dom::oldproxybindings::HTMLPropertiesCollection::create(cx, scope, this,
                                                                  triedToWrap);
 }
 
 NS_IMETHODIMP
 HTMLPropertiesCollection::GetLength(uint32_t* aLength)
 {
   EnsureFresh();
   *aLength = mProperties.Length();
@@ -421,17 +421,17 @@ PropertyNodeList::GetParentObject()
 {
   return mParent;
 }
 
 JSObject*
 PropertyNodeList::WrapObject(JSContext *cx, JSObject *scope,
                              bool *triedToWrap)
 {
-  return mozilla::dom::binding::PropertyNodeList::create(cx, scope, this,
+  return mozilla::dom::oldproxybindings::PropertyNodeList::create(cx, scope, this,
                                                          triedToWrap);
 }
 
 NS_IMPL_CYCLE_COLLECTION_CLASS(PropertyNodeList)
 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(PropertyNodeList)
   // SetDocument(nullptr) ensures that we remove ourselves as a mutation observer
   tmp->SetDocument(nullptr);
   NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mParent)
--- a/content/html/content/src/nsClientRect.cpp
+++ b/content/html/content/src/nsClientRect.cpp
@@ -101,17 +101,17 @@ nsIDOMClientRect*
 nsClientRectList::GetItemAt(uint32_t aIndex)
 {
   return mArray.SafeObjectAt(aIndex);
 }
 
 JSObject*
 nsClientRectList::WrapObject(JSContext *cx, JSObject *scope, bool *triedToWrap)
 {
-  return mozilla::dom::binding::ClientRectList::create(cx, scope, this,
+  return mozilla::dom::oldproxybindings::ClientRectList::create(cx, scope, this,
                                                        triedToWrap);
 }
 
 static double
 RoundFloat(double aValue)
 {
   return floor(aValue + 0.5);
 }
--- a/content/html/content/src/nsHTMLFormElement.cpp
+++ b/content/html/content/src/nsHTMLFormElement.cpp
@@ -116,17 +116,17 @@ public:
    * @return NS_OK or NS_ERROR_OUT_OF_MEMORY.
    */
   nsresult GetSortedControls(nsTArray<nsGenericHTMLFormElement*>& aControls) const;
 
   // nsWrapperCache
   virtual JSObject* WrapObject(JSContext *cx, JSObject *scope,
                                bool *triedToWrap)
   {
-    return mozilla::dom::binding::HTMLCollection::create(cx, scope, this,
+    return mozilla::dom::oldproxybindings::HTMLCollection::create(cx, scope, this,
                                                          triedToWrap);
   }
 
   nsHTMLFormElement* mForm;  // WEAK - the form owns me
 
   nsTArray<nsGenericHTMLFormElement*> mElements;  // Holds WEAK references - bug 36639
 
   // This array holds on to all form controls that are not contained
--- a/content/html/content/src/nsHTMLMediaElement.cpp
+++ b/content/html/content/src/nsHTMLMediaElement.cpp
@@ -550,22 +550,16 @@ nsHTMLMediaElement::OnChannelRedirect(ns
 }
 
 void nsHTMLMediaElement::ShutdownDecoder()
 {
   RemoveMediaElementFromURITable();
   NS_ASSERTION(mDecoder, "Must have decoder to shut down");
   mDecoder->Shutdown();
   mDecoder = nullptr;
-  // Discard all output streams. mDecoder->Shutdown() will have finished all
-  // its output streams.
-  // XXX For now we ignore mFinishWhenEnded. We'll fix this later. The
-  // immediate goal is to not crash when reloading a media element with
-  // output streams.
-  mOutputStreams.Clear();
 }
 
 void nsHTMLMediaElement::AbortExistingLoads()
 {
   // Abort any already-running instance of the resource selection algorithm.
   mLoadWaitStatus = NOT_WAITING;
 
   // Set a new load ID. This will cause events which were enqueued
@@ -1519,26 +1513,30 @@ NS_IMETHODIMP nsHTMLMediaElement::SetMut
 
   return NS_OK;
 }
 
 already_AddRefed<nsDOMMediaStream>
 nsHTMLMediaElement::CaptureStreamInternal(bool aFinishWhenEnded)
 {
   OutputMediaStream* out = mOutputStreams.AppendElement();
-  out->mStream = nsDOMMediaStream::CreateInputStream();
+  out->mStream = nsDOMMediaStream::CreateTrackUnionStream();
   nsRefPtr<nsIPrincipal> principal = GetCurrentPrincipal();
   out->mStream->CombineWithPrincipal(principal);
   out->mFinishWhenEnded = aFinishWhenEnded;
 
   mAudioCaptured = true;
+  // Block the output stream initially.
+  // Decoders are responsible for removing the block while they are playing
+  // back into the output stream.
+  out->mStream->GetStream()->ChangeExplicitBlockerCount(1);
   if (mDecoder) {
     mDecoder->SetAudioCaptured(true);
     mDecoder->AddOutputStream(
-        out->mStream->GetStream()->AsSourceStream(), aFinishWhenEnded);
+        out->mStream->GetStream()->AsProcessedStream(), aFinishWhenEnded);
   }
   nsRefPtr<nsDOMMediaStream> result = out->mStream;
   return result.forget();
 }
 
 NS_IMETHODIMP nsHTMLMediaElement::MozCaptureStream(nsIDOMMediaStream** aStream)
 {
   *aStream = CaptureStreamInternal(false).get();
@@ -2471,17 +2469,17 @@ nsresult nsHTMLMediaElement::FinishDecod
 
   // The new stream has not been suspended by us.
   mPausedForInactiveDocument = false;
 
   aDecoder->SetAudioCaptured(mAudioCaptured);
   aDecoder->SetVolume(mMuted ? 0.0 : mVolume);
   for (uint32_t i = 0; i < mOutputStreams.Length(); ++i) {
     OutputMediaStream* ms = &mOutputStreams[i];
-    aDecoder->AddOutputStream(ms->mStream->GetStream()->AsSourceStream(),
+    aDecoder->AddOutputStream(ms->mStream->GetStream()->AsProcessedStream(),
         ms->mFinishWhenEnded);
   }
 
   nsresult rv = aDecoder->Load(aStream, aListener, aCloneDonor);
   if (NS_FAILED(rv)) {
     LOG(PR_LOG_DEBUG, ("%p Failed to load for decoder %p", this, aDecoder));
     return rv;
   }
@@ -2823,16 +2821,24 @@ void nsHTMLMediaElement::Error(uint16_t 
 
 void nsHTMLMediaElement::PlaybackEnded()
 {
   // We changed state which can affect AddRemoveSelfReference
   AddRemoveSelfReference();
 
   NS_ASSERTION(!mDecoder || mDecoder->IsEnded(),
                "Decoder fired ended, but not in ended state");
+
+  // Discard all output streams that have finished now.
+  for (int32_t i = mOutputStreams.Length() - 1; i >= 0; --i) {
+    if (mOutputStreams[i].mFinishWhenEnded) {
+      mOutputStreams.RemoveElementAt(i);
+    }
+  }
+
   if (mSrcStream || (mDecoder && mDecoder->IsInfinite())) {
     LOG(PR_LOG_DEBUG, ("%p, got duration by reaching the end of the resource", this));
     DispatchAsyncEvent(NS_LITERAL_STRING("durationchange"));
   }
 
   if (HasAttr(kNameSpaceID_None, nsGkAtoms::loop)) {
     SetCurrentTime(0);
     return;
--- a/content/html/content/src/nsHTMLSelectElement.cpp
+++ b/content/html/content/src/nsHTMLSelectElement.cpp
@@ -2010,17 +2010,17 @@ NS_INTERFACE_MAP_END
 NS_IMPL_CYCLE_COLLECTING_ADDREF(nsHTMLOptionCollection)
 NS_IMPL_CYCLE_COLLECTING_RELEASE(nsHTMLOptionCollection)
 
 
 JSObject*
 nsHTMLOptionCollection::WrapObject(JSContext *cx, JSObject *scope,
                                    bool *triedToWrap)
 {
-  return mozilla::dom::binding::HTMLOptionsCollection::create(cx, scope, this,
+  return mozilla::dom::oldproxybindings::HTMLOptionsCollection::create(cx, scope, this,
                                                               triedToWrap);
 }
 
 NS_IMETHODIMP
 nsHTMLOptionCollection::GetLength(uint32_t* aLength)
 {
   *aLength = mElements.Length();
 
--- a/content/html/content/src/nsHTMLTableElement.cpp
+++ b/content/html/content/src/nsHTMLTableElement.cpp
@@ -51,17 +51,17 @@ public:
   NS_IMETHOD    ParentDestroyed();
 
   NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(TableRowsCollection)
 
   // nsWrapperCache
   virtual JSObject* WrapObject(JSContext *cx, JSObject *scope,
                                bool *triedToWrap)
   {
-    return mozilla::dom::binding::HTMLCollection::create(cx, scope, this,
+    return mozilla::dom::oldproxybindings::HTMLCollection::create(cx, scope, this,
                                                          triedToWrap);
   }
 
 protected:
   // Those rows that are not in table sections
   nsHTMLTableElement* mParent;
   nsRefPtr<nsContentList> mOrphanRows;  
 };
--- a/content/media/MediaResource.cpp
+++ b/content/media/MediaResource.cpp
@@ -23,17 +23,16 @@
 #include "nsCrossSiteListenerProxy.h"
 #include "nsHTMLMediaElement.h"
 #include "nsError.h"
 #include "nsICachingChannel.h"
 #include "nsURILoader.h"
 #include "nsIAsyncVerifyRedirectCallback.h"
 #include "mozilla/Util.h" // for DebugOnly
 #include "nsContentUtils.h"
-#include "nsBlobProtocolHandler.h"
 
 static const uint32_t HTTP_OK_CODE = 200;
 static const uint32_t HTTP_PARTIAL_RESPONSE_CODE = 206;
 
 using namespace mozilla;
 
 ChannelMediaResource::ChannelMediaResource(nsMediaDecoder* aDecoder,
     nsIChannel* aChannel, nsIURI* aURI)
@@ -1034,25 +1033,24 @@ nsresult FileMediaResource::Open(nsIStre
   }
 
   nsresult rv = NS_OK;
   if (aStreamListener) {
     // The channel is already open. We need a synchronous stream that
     // implements nsISeekableStream, so we have to find the underlying
     // file and reopen it
     nsCOMPtr<nsIFileChannel> fc(do_QueryInterface(mChannel));
-    if (fc) {
-      nsCOMPtr<nsIFile> file;
-      rv = fc->GetFile(getter_AddRefs(file));
-      NS_ENSURE_SUCCESS(rv, rv);
+    if (!fc)
+      return NS_ERROR_UNEXPECTED;
 
-      rv = NS_NewLocalFileInputStream(getter_AddRefs(mInput), file);
-    } else if (IsBlobURI(mURI)) {
-      rv = NS_GetStreamForBlobURI(mURI, getter_AddRefs(mInput));
-    }
+    nsCOMPtr<nsIFile> file;
+    rv = fc->GetFile(getter_AddRefs(file));
+    NS_ENSURE_SUCCESS(rv, rv);
+
+    rv = NS_NewLocalFileInputStream(getter_AddRefs(mInput), file);
   } else {
     // Ensure that we never load a local file from some page on a
     // web server.
     nsHTMLMediaElement* element = mDecoder->GetMediaElement();
     NS_ENSURE_TRUE(element, NS_ERROR_FAILURE);
 
     rv = nsContentUtils::GetSecurityManager()->
            CheckLoadURIWithPrincipal(element->NodePrincipal(),
@@ -1198,27 +1196,27 @@ int64_t FileMediaResource::Tell()
   mSeekable->Tell(&offset);
   return offset;
 }
 
 MediaResource*
 MediaResource::Create(nsMediaDecoder* aDecoder, nsIChannel* aChannel)
 {
   NS_ASSERTION(NS_IsMainThread(),
-               "MediaResource::Open called on non-main thread");
+	             "MediaResource::Open called on non-main thread");
 
   // If the channel was redirected, we want the post-redirect URI;
   // but if the URI scheme was expanded, say from chrome: to jar:file:,
   // we want the original URI.
   nsCOMPtr<nsIURI> uri;
   nsresult rv = NS_GetFinalChannelURI(aChannel, getter_AddRefs(uri));
   NS_ENSURE_SUCCESS(rv, nullptr);
 
   nsCOMPtr<nsIFileChannel> fc = do_QueryInterface(aChannel);
-  if (fc || IsBlobURI(uri)) {
+  if (fc) {
     return new FileMediaResource(aDecoder, aChannel, uri);
   }
   return new ChannelMediaResource(aDecoder, aChannel, uri);
 }
 
 void MediaResource::MoveLoadsToBackground() {
   NS_ASSERTION(!mLoadInBackground, "Why are you calling this more than once?");
   mLoadInBackground = true;
--- a/content/media/MediaStreamGraph.cpp
+++ b/content/media/MediaStreamGraph.cpp
@@ -2073,29 +2073,28 @@ SourceMediaStream::Finish()
 
 void
 MediaInputPort::Init()
 {
   LOG(PR_LOG_DEBUG, ("Adding MediaInputPort %p (from %p to %p) to the graph",
       this, mSource, mDest));
   mSource->AddConsumer(this);
   mDest->AddInput(this);
-  // mPortCount decremented in Disconnect()
+  // mPortCount decremented via MediaInputPort::Destroy's message
   ++mDest->GraphImpl()->mPortCount;
 }
 
 void
 MediaInputPort::Disconnect()
 {
   NS_ASSERTION(!mSource == !mDest,
                "mSource must either both be null or both non-null");
   if (!mSource)
     return;
 
-  --mDest->GraphImpl()->mPortCount;
   mSource->RemoveConsumer(this);
   mSource = nullptr;
   mDest->RemoveInput(this);
   mDest = nullptr;
 }
 
 MediaInputPort::InputInterval
 MediaInputPort::GetNextInputInterval(GraphTime aTime)
@@ -2118,32 +2117,45 @@ MediaInputPort::GetNextInputInterval(Gra
 }
 
 void
 MediaInputPort::Destroy()
 {
   class Message : public ControlMessage {
   public:
     Message(MediaInputPort* aPort)
-      : ControlMessage(aPort->GetDestination()), mPort(aPort) {}
+      : ControlMessage(nullptr), mPort(aPort) {}
     virtual void Run()
     {
       mPort->Disconnect();
+      --mPort->GraphImpl()->mPortCount;
       NS_RELEASE(mPort);
     }
     virtual void RunDuringShutdown()
     {
       Run();
     }
     // This does not need to be strongly referenced; the graph is holding
     // a strong reference to the port, which we will remove. This will be the
     // last message for the port.
     MediaInputPort* mPort;
   };
-  mSource->GraphImpl()->AppendMessage(new Message(this));
+  GraphImpl()->AppendMessage(new Message(this));
+}
+
+MediaStreamGraphImpl*
+MediaInputPort::GraphImpl()
+{
+  return gGraph;
+}
+
+MediaStreamGraph*
+MediaInputPort::Graph()
+{
+  return gGraph;
 }
 
 MediaInputPort*
 ProcessedMediaStream::AllocateInputPort(MediaStream* aStream, uint32_t aFlags)
 {
   class Message : public ControlMessage {
   public:
     Message(MediaInputPort* aPort)
--- a/content/media/MediaStreamGraph.h
+++ b/content/media/MediaStreamGraph.h
@@ -680,16 +680,22 @@ public:
     GraphTime mStart;
     GraphTime mEnd;
     bool mInputIsBlocked;
   };
   // Find the next time interval starting at or after aTime during which
   // mDest is not blocked and mSource's blocking status does not change.
   InputInterval GetNextInputInterval(GraphTime aTime);
 
+  /**
+   * Returns the graph that owns this port.
+   */
+  MediaStreamGraphImpl* GraphImpl();
+  MediaStreamGraph* Graph();
+
 protected:
   friend class MediaStreamGraphImpl;
   friend class MediaStream;
   friend class ProcessedMediaStream;
   // Never modified after Init()
   MediaStream* mSource;
   ProcessedMediaStream* mDest;
   uint32_t mFlags;
--- a/content/media/nsBuiltinDecoder.cpp
+++ b/content/media/nsBuiltinDecoder.cpp
@@ -54,24 +54,136 @@ void nsBuiltinDecoder::SetAudioCaptured(
 {
   NS_ASSERTION(NS_IsMainThread(), "Should be on main thread.");
   mInitialAudioCaptured = aCaptured;
   if (mDecoderStateMachine) {
     mDecoderStateMachine->SetAudioCaptured(aCaptured);
   }
 }
 
-void nsBuiltinDecoder::AddOutputStream(SourceMediaStream* aStream, bool aFinishWhenEnded)
+void nsBuiltinDecoder::ConnectDecodedStreamToOutputStream(OutputStreamData* aStream)
+{
+  NS_ASSERTION(!aStream->mPort, "Already connected?");
+
+  // The output stream must stay in sync with the decoded stream, so if
+  // either stream is blocked, we block the other.
+  aStream->mPort = aStream->mStream->AllocateInputPort(mDecodedStream->mStream,
+      MediaInputPort::FLAG_BLOCK_INPUT | MediaInputPort::FLAG_BLOCK_OUTPUT);
+  // Unblock the output stream now. While it's connected to mDecodedStream,
+  // mDecodedStream is responsible for controlling blocking.
+  aStream->mStream->ChangeExplicitBlockerCount(-1);
+}
+
+nsBuiltinDecoder::DecodedStreamData::DecodedStreamData(nsBuiltinDecoder* aDecoder,
+                                                       int64_t aInitialTime,
+                                                       SourceMediaStream* aStream)
+  : mLastAudioPacketTime(-1),
+    mLastAudioPacketEndTime(-1),
+    mAudioFramesWritten(0),
+    mInitialTime(aInitialTime),
+    mNextVideoTime(aInitialTime),
+    mStreamInitialized(false),
+    mHaveSentFinish(false),
+    mHaveSentFinishAudio(false),
+    mHaveSentFinishVideo(false),
+    mStream(aStream),
+    mMainThreadListener(new DecodedStreamMainThreadListener(aDecoder)),
+    mHaveBlockedForPlayState(false)
+{
+  mStream->AddMainThreadListener(mMainThreadListener);
+}
+
+nsBuiltinDecoder::DecodedStreamData::~DecodedStreamData()
+{
+  mStream->RemoveMainThreadListener(mMainThreadListener);
+  mStream->Destroy();
+}
+
+void nsBuiltinDecoder::DestroyDecodedStream()
 {
   NS_ASSERTION(NS_IsMainThread(), "Should be on main thread.");
+  mReentrantMonitor.AssertCurrentThreadIn();
+
+  // All streams are having their SourceMediaStream disconnected, so they
+  // need to be explicitly blocked again.
+  for (uint32_t i = 0; i < mOutputStreams.Length(); ++i) {
+    OutputStreamData& os = mOutputStreams[i];
+    // During cycle collection, nsDOMMediaStream can be destroyed and send
+    // its Destroy message before this decoder is destroyed. So we have to
+    // be careful not to send any messages after the Destroy().
+    if (!os.mStream->IsDestroyed()) {
+      os.mStream->ChangeExplicitBlockerCount(1);
+    }
+    // Explicitly remove all existing ports. This is not strictly necessary but it's
+    // good form.
+    os.mPort->Destroy();
+    os.mPort = nullptr;
+  }
+
+  mDecodedStream = nullptr;
+}
+
+void nsBuiltinDecoder::RecreateDecodedStream(int64_t aStartTimeUSecs)
+{
+  NS_ASSERTION(NS_IsMainThread(), "Should be on main thread.");
+  mReentrantMonitor.AssertCurrentThreadIn();
+  LOG(PR_LOG_DEBUG, ("nsBuiltinDecoder::RecreateDecodedStream this=%p aStartTimeUSecs=%lld!",
+                     this, (long long)aStartTimeUSecs));
+
+  DestroyDecodedStream();
+
+  mDecodedStream = new DecodedStreamData(this, aStartTimeUSecs,
+    MediaStreamGraph::GetInstance()->CreateInputStream(nullptr));
+
+  // Note that the delay between removing ports in DestroyDecodedStream
+  // and adding new ones won't cause a glitch since all graph operations
+  // between main-thread stable states take effect atomically.
+  for (uint32_t i = 0; i < mOutputStreams.Length(); ++i) {
+    ConnectDecodedStreamToOutputStream(&mOutputStreams[i]);
+  }
+
+  mDecodedStream->mHaveBlockedForPlayState = mPlayState != PLAY_STATE_PLAYING;
+  if (mDecodedStream->mHaveBlockedForPlayState) {
+    mDecodedStream->mStream->ChangeExplicitBlockerCount(1);
+  }
+}
+
+void nsBuiltinDecoder::NotifyDecodedStreamMainThreadStateChanged()
+{
+  if (mTriggerPlaybackEndedWhenSourceStreamFinishes && mDecodedStream &&
+      mDecodedStream->mStream->IsFinished()) {
+    mTriggerPlaybackEndedWhenSourceStreamFinishes = false;
+    if (GetState() == PLAY_STATE_PLAYING) {
+      nsCOMPtr<nsIRunnable> event =
+        NS_NewRunnableMethod(this, &nsBuiltinDecoder::PlaybackEnded);
+      NS_DispatchToCurrentThread(event);
+    }
+  }
+}
+
+void nsBuiltinDecoder::AddOutputStream(ProcessedMediaStream* aStream,
+                                       bool aFinishWhenEnded)
+{
+  NS_ASSERTION(NS_IsMainThread(), "Should be on main thread.");
+  LOG(PR_LOG_DEBUG, ("nsBuiltinDecoder::AddOutputStream this=%p aStream=%p!",
+                     this, aStream));
 
   {
     ReentrantMonitorAutoEnter mon(mReentrantMonitor);
-    OutputMediaStream* ms = mOutputStreams.AppendElement();
-    ms->Init(int64_t(mCurrentTime*USECS_PER_S), aStream, aFinishWhenEnded);
+    if (!mDecodedStream) {
+      RecreateDecodedStream(mDecoderStateMachine ?
+          int64_t(mDecoderStateMachine->GetCurrentTime()*USECS_PER_S) : 0);
+    }
+    OutputStreamData* os = mOutputStreams.AppendElement();
+    os->Init(aStream, aFinishWhenEnded);
+    ConnectDecodedStreamToOutputStream(os);
+    if (aFinishWhenEnded) {
+      // Ensure that aStream finishes the moment mDecodedStream does.
+      aStream->SetAutofinish(true);
+    }
   }
 
   // This can be called before Load(), in which case our mDecoderStateMachine
   // won't have been created yet and we can rely on Load() to schedule it
   // once it is created.
   if (mDecoderStateMachine) {
     // Make sure the state machine thread runs so that any buffered data
     // is fed into our stream.
@@ -111,17 +223,18 @@ nsBuiltinDecoder::nsBuiltinDecoder() :
   mRequestedSeekTime(-1.0),
   mDuration(-1),
   mSeekable(true),
   mReentrantMonitor("media.decoder"),
   mPlayState(PLAY_STATE_PAUSED),
   mNextState(PLAY_STATE_PAUSED),
   mResourceLoaded(false),
   mIgnoreProgressData(false),
-  mInfiniteStream(false)
+  mInfiniteStream(false),
+  mTriggerPlaybackEndedWhenSourceStreamFinishes(false)
 {
   MOZ_COUNT_CTOR(nsBuiltinDecoder);
   NS_ASSERTION(NS_IsMainThread(), "Should be on main thread.");
 #ifdef PR_LOGGING
   if (!gBuiltinDecoderLog) {
     gBuiltinDecoderLog = PR_NewLogModule("nsBuiltinDecoder");
   }
 #endif
@@ -141,16 +254,21 @@ void nsBuiltinDecoder::Shutdown()
 {
   NS_ASSERTION(NS_IsMainThread(), "Should be on main thread.");
   
   if (mShuttingDown)
     return;
 
   mShuttingDown = true;
 
+  {
+    ReentrantMonitorAutoEnter mon(GetReentrantMonitor());
+    DestroyDecodedStream();
+  }
+
   // This changes the decoder state to SHUTDOWN and does other things
   // necessary to unblock the state machine thread if it's blocked, so
   // the asynchronous shutdown in nsDestroyStateMachine won't deadlock.
   if (mDecoderStateMachine) {
     mDecoderStateMachine->Shutdown();
   }
 
   // Force any outstanding seek and byterange requests to complete
@@ -538,20 +656,46 @@ bool nsBuiltinDecoder::IsSeeking() const
 bool nsBuiltinDecoder::IsEnded() const
 {
   NS_ASSERTION(NS_IsMainThread(), "Should be on main thread.");
   return mPlayState == PLAY_STATE_ENDED || mPlayState == PLAY_STATE_SHUTDOWN;
 }
 
 void nsBuiltinDecoder::PlaybackEnded()
 {
+  NS_ASSERTION(NS_IsMainThread(), "Should be on main thread.");
+
   if (mShuttingDown || mPlayState == nsBuiltinDecoder::PLAY_STATE_SEEKING)
     return;
 
-  printf("nsBuiltinDecoder::PlaybackEnded mPlayState=%d\n", mPlayState);
+  {
+    ReentrantMonitorAutoEnter mon(mReentrantMonitor);
+
+    if (mDecodedStream && !mDecodedStream->mStream->IsFinished()) {
+      // Wait for it to finish before firing PlaybackEnded()
+      mTriggerPlaybackEndedWhenSourceStreamFinishes = true;
+      return;
+    }
+
+    for (int32_t i = mOutputStreams.Length() - 1; i >= 0; --i) {
+      OutputStreamData& os = mOutputStreams[i];
+      if (os.mFinishWhenEnded) {
+        // Shouldn't really be needed since mDecodedStream should already have
+        // finished, but doesn't hurt.
+        os.mStream->Finish();
+        os.mPort->Destroy();
+        os.mPort = nullptr;
+        // Not really needed but it keeps the invariant that a stream not
+        // connected to mDecodedStream is explicity blocked.
+        os.mStream->ChangeExplicitBlockerCount(1);
+        mOutputStreams.RemoveElementAt(i);
+      }
+    }
+  }
+
   PlaybackPositionChanged();
   ChangeState(PLAY_STATE_ENDED);
 
   if (mElement)  {
     UpdateReadyStateForData();
     mElement->PlaybackEnded();
   }
 
@@ -760,17 +904,16 @@ void nsBuiltinDecoder::SeekingStopped()
 
     // An additional seek was requested while the current seek was
     // in operation.
     if (mRequestedSeekTime >= 0.0) {
       ChangeState(PLAY_STATE_SEEKING);
       seekWasAborted = true;
     } else {
       UnpinForSeek();
-      printf("nsBuiltinDecoder::SeekingStopped, next state=%d\n", mNextState);
       ChangeState(mNextState);
     }
   }
 
   if (mElement) {
     UpdateReadyStateForData();
     if (!seekWasAborted) {
       mElement->SeekCompleted();
@@ -837,16 +980,23 @@ void nsBuiltinDecoder::ChangeState(PlayS
     mNextState = PLAY_STATE_PAUSED;
   }
 
   if (mPlayState == PLAY_STATE_SHUTDOWN) {
     mReentrantMonitor.NotifyAll();
     return;
   }
 
+  if (mDecodedStream) {
+    bool blockForPlayState = aState != PLAY_STATE_PLAYING;
+    if (mDecodedStream->mHaveBlockedForPlayState != blockForPlayState) {
+      mDecodedStream->mStream->ChangeExplicitBlockerCount(blockForPlayState ? 1 : -1);
+      mDecodedStream->mHaveBlockedForPlayState = blockForPlayState;
+    }
+  }
   mPlayState = aState;
   if (mDecoderStateMachine) {
     switch (aState) {
     case PLAY_STATE_PLAYING:
       mDecoderStateMachine->Play();
       break;
     case PLAY_STATE_SEEKING:
       mDecoderStateMachine->Seek(mRequestedSeekTime);
@@ -1043,51 +1193,8 @@ bool nsBuiltinDecoder::OnStateMachineThr
 void nsBuiltinDecoder::NotifyAudioAvailableListener()
 {
   NS_ASSERTION(NS_IsMainThread(), "Should be on main thread.");
   if (mDecoderStateMachine) {
     ReentrantMonitorAutoEnter mon(mReentrantMonitor);
     mDecoderStateMachine->NotifyAudioAvailableListener();
   }
 }
-
-nsBuiltinDecoder::OutputMediaStream::OutputMediaStream()
-{
-
-}
-
-nsBuiltinDecoder::OutputMediaStream::~OutputMediaStream()
-{
-
-}
-    
-
-void nsBuiltinDecoder::OutputMediaStream::Init(int64_t aInitialTime, SourceMediaStream* aStream, bool aFinishWhenEnded)
-{
-  mLastAudioPacketTime = -1;
-  mLastAudioPacketEndTime = -1;
-  mAudioFramesWrittenBaseTime = aInitialTime;
-  mAudioFramesWritten = 0;
-  mNextVideoTime = aInitialTime;
-  mStream = aStream;
-  mStreamInitialized = false;
-  mFinishWhenEnded = aFinishWhenEnded;
-  mHaveSentFinish = false;
-  mHaveSentFinishAudio = false;
-  mHaveSentFinishVideo = false;
-}
-
-nsBuiltinDecoder::OutputMediaStream::OutputMediaStream(const OutputMediaStream& rhs)
-{
-  mLastAudioPacketTime = rhs.mLastAudioPacketTime;
-  mLastAudioPacketEndTime = rhs.mLastAudioPacketEndTime;
-  mAudioFramesWritten = rhs.mAudioFramesWritten;
-  mAudioFramesWrittenBaseTime = rhs.mAudioFramesWrittenBaseTime;
-  mNextVideoTime = rhs.mNextVideoTime;
-  mLastVideoImage = rhs.mLastVideoImage;
-  mStream = rhs.mStream;
-  mLastVideoImageDisplaySize = rhs.mLastVideoImageDisplaySize;
-  mStreamInitialized = rhs.mStreamInitialized;
-  mFinishWhenEnded = rhs.mFinishWhenEnded;
-  mHaveSentFinish = rhs.mHaveSentFinish;
-  mHaveSentFinishAudio = rhs.mHaveSentFinishAudio;
-  mHaveSentFinishVideo = rhs.mHaveSentFinishVideo;
-}
--- a/content/media/nsBuiltinDecoder.h
+++ b/content/media/nsBuiltinDecoder.h
@@ -327,16 +327,17 @@ public:
   // element. Called on the main thread.
   virtual void NotifyAudioAvailableListener() = 0;
 };
 
 class nsBuiltinDecoder : public nsMediaDecoder
 {
 public:
   typedef mozilla::MediaChannelStatistics MediaChannelStatistics;
+  class DecodedStreamMainThreadListener;
 
   NS_DECL_ISUPPORTS
   NS_DECL_NSIOBSERVER
 
   // Enumeration for the valid play states (see mPlayState)
   enum PlayState {
     PLAY_STATE_START,
     PLAY_STATE_LOADING,
@@ -372,53 +373,116 @@ public:
   virtual nsresult Seek(double aTime);
 
   virtual nsresult PlaybackRateChanged();
 
   virtual void Pause();
   virtual void SetVolume(double aVolume);
   virtual void SetAudioCaptured(bool aCaptured);
 
-  virtual void AddOutputStream(SourceMediaStream* aStream, bool aFinishWhenEnded);
-  // Protected by mReentrantMonitor. All decoder output is copied to these streams.
-  struct OutputMediaStream {
-    OutputMediaStream();
-    ~OutputMediaStream();
-    OutputMediaStream(const OutputMediaStream& rhs);
+  // All MediaStream-related data is protected by mReentrantMonitor.
+  // We have at most one DecodedStreamData per nsBuiltinDecoder. Its stream
+  // is used as the input for each ProcessedMediaStream created by calls to
+  // captureStream(UntilEnded). Seeking creates a new source stream, as does
+  // replaying after the input as ended. In the latter case, the new source is
+  // not connected to streams created by captureStreamUntilEnded.
 
-    void Init(int64_t aInitialTime, SourceMediaStream* aStream, bool aFinishWhenEnded);
-    
+  struct DecodedStreamData {
+    DecodedStreamData(nsBuiltinDecoder* aDecoder,
+                      int64_t aInitialTime, SourceMediaStream* aStream);
+    ~DecodedStreamData();
+
+    // The following group of fields are protected by the decoder's monitor
+    // and can be read or written on any thread.    
     int64_t mLastAudioPacketTime; // microseconds
     int64_t mLastAudioPacketEndTime; // microseconds
     // Count of audio frames written to the stream
     int64_t mAudioFramesWritten;
-    // Timestamp of the first audio packet whose frames we wrote.
-    int64_t mAudioFramesWrittenBaseTime; // microseconds
+    // Saved value of aInitialTime. Timestamp of the first audio and/or
+    // video packet written.
+    int64_t mInitialTime; // microseconds
     // mNextVideoTime is the end timestamp for the last packet sent to the stream.
     // Therefore video packets starting at or after this time need to be copied
     // to the output stream.
     int64_t mNextVideoTime; // microseconds
     // The last video image sent to the stream. Useful if we need to replicate
     // the image.
     nsRefPtr<Image> mLastVideoImage;
-    nsRefPtr<SourceMediaStream> mStream;
     gfxIntSize mLastVideoImageDisplaySize;
     // This is set to true when the stream is initialized (audio and
     // video tracks added).
     bool mStreamInitialized;
-    bool mFinishWhenEnded;
     bool mHaveSentFinish;
     bool mHaveSentFinishAudio;
     bool mHaveSentFinishVideo;
+
+    // The decoder is responsible for calling Destroy() on this stream.
+    // Can be read from any thread.
+    const nsRefPtr<SourceMediaStream> mStream;
+    // A listener object that receives notifications when mStream's
+    // main-thread-visible state changes. Used on the main thread only.
+    const nsRefPtr<DecodedStreamMainThreadListener> mMainThreadListener;
+    // True when we've explicitly blocked this stream because we're
+    // not in PLAY_STATE_PLAYING. Used on the main thread only.
+    bool mHaveBlockedForPlayState;
   };
-  nsTArray<OutputMediaStream>& OutputStreams()
+  struct OutputStreamData {
+    void Init(ProcessedMediaStream* aStream, bool aFinishWhenEnded)
+    {
+      mStream = aStream;
+      mFinishWhenEnded = aFinishWhenEnded;
+    }
+    nsRefPtr<ProcessedMediaStream> mStream;
+    // mPort connects mDecodedStream->mStream to our mStream.
+    nsRefPtr<MediaInputPort> mPort;
+    bool mFinishWhenEnded;
+  };
+  /**
+   * Connects mDecodedStream->mStream to aStream->mStream.
+   */
+  void ConnectDecodedStreamToOutputStream(OutputStreamData* aStream);
+  /**
+   * Disconnects mDecodedStream->mStream from all outputs and clears
+   * mDecodedStream.
+   */
+  void DestroyDecodedStream();
+  /**
+   * Recreates mDecodedStream. Call this to create mDecodedStream at first,
+   * and when seeking, to ensure a new stream is set up with fresh buffers.
+   * aStartTimeUSecs is relative to the state machine's mStartTime.
+   */
+  void RecreateDecodedStream(int64_t aStartTimeUSecs);
+  /**
+   * Called when the state of mDecodedStream as visible on the main thread
+   * has changed. In particular we want to know when the stream has finished
+   * so we can call PlaybackEnded.
+   */
+  void NotifyDecodedStreamMainThreadStateChanged();
+  nsTArray<OutputStreamData>& OutputStreams()
   {
     GetReentrantMonitor().AssertCurrentThreadIn();
     return mOutputStreams;
   }
+  DecodedStreamData* GetDecodedStream()
+  {
+    GetReentrantMonitor().AssertCurrentThreadIn();
+    return mDecodedStream;
+  }
+  class DecodedStreamMainThreadListener : public MainThreadMediaStreamListener {
+  public:
+    DecodedStreamMainThreadListener(nsBuiltinDecoder* aDecoder)
+      : mDecoder(aDecoder) {}
+    virtual void NotifyMainThreadStateChanged()
+    {
+      mDecoder->NotifyDecodedStreamMainThreadStateChanged();
+    }
+    nsBuiltinDecoder* mDecoder;
+  };
+
+  virtual void AddOutputStream(ProcessedMediaStream* aStream, bool aFinishWhenEnded);
 
   virtual double GetDuration();
 
   virtual void SetInfinite(bool aInfinite);
   virtual bool IsInfinite();
 
   virtual MediaResource* GetResource() { return mResource; }
   virtual already_AddRefed<nsIPrincipal> GetCurrentPrincipal();
@@ -705,17 +769,23 @@ public:
   nsAutoPtr<MediaResource> mResource;
 
   // ReentrantMonitor for detecting when the video play state changes. A call
   // to Wait on this monitor will block the thread until the next
   // state change.
   ReentrantMonitor mReentrantMonitor;
 
   // Data about MediaStreams that are being fed by this decoder.
-  nsTArray<OutputMediaStream> mOutputStreams;
+  nsTArray<OutputStreamData> mOutputStreams;
+  // The SourceMediaStream we are using to feed the mOutputStreams. This stream
+  // is never exposed outside the decoder.
+  // Only written on the main thread while holding the monitor. Therefore it
+  // can be read on any thread while holding the monitor, or on the main thread
+  // without holding the monitor.
+  nsAutoPtr<DecodedStreamData> mDecodedStream;
 
   // Set to one of the valid play states.
   // This can only be changed on the main thread while holding the decoder
   // monitor. Thus, it can be safely read while holding the decoder monitor
   // OR on the main thread.
   // Any change to the state on the main thread must call NotifyAll on the
   // monitor so the decode thread can wake up.
   PlayState mPlayState;
@@ -737,11 +807,15 @@ public:
   // such a manner that progress event data is inaccurate. This is set
   // during seek and duration operations to prevent the progress indicator
   // from jumping around. Read/Write from any thread. Must have decode monitor
   // locked before accessing.
   bool mIgnoreProgressData;
 
   // True if the stream is infinite (e.g. a webradio).
   bool mInfiniteStream;
+
+  // True if NotifyDecodedStreamMainThreadStateChanged should retrigger
+  // PlaybackEnded when mDecodedStream->mStream finishes.
+  bool mTriggerPlaybackEndedWhenSourceStreamFinishes;
 };
 
 #endif
--- a/content/media/nsBuiltinDecoderStateMachine.cpp
+++ b/content/media/nsBuiltinDecoderStateMachine.cpp
@@ -423,16 +423,18 @@ nsBuiltinDecoderStateMachine::nsBuiltinD
   mBufferingWait = mRealTime ? 0 : BUFFERING_WAIT_S;
   mLowDataThresholdUsecs = mRealTime ? 0 : LOW_DATA_THRESHOLD_USECS;
 }
 
 nsBuiltinDecoderStateMachine::~nsBuiltinDecoderStateMachine()
 {
   NS_ASSERTION(NS_IsMainThread(), "Should be on main thread.");
   MOZ_COUNT_DTOR(nsBuiltinDecoderStateMachine);
+  NS_ASSERTION(!mPendingWakeDecoder.get(),
+               "WakeDecoder should have been revoked already");
   NS_ASSERTION(!StateMachineTracker::Instance().IsQueued(this),
     "Should not have a pending request for a new decode thread");
   NS_ASSERTION(!mRequestedNewDecodeThread,
     "Should not have (or flagged) a pending request for a new decode thread");
   if (mTimer)
     mTimer->Cancel();
   mTimer = nullptr;
   mReader = nullptr;
@@ -491,36 +493,37 @@ void nsBuiltinDecoderStateMachine::Decod
       DecodeSeek();
     }
   }
 
   mDecodeThreadIdle = true;
   LOG(PR_LOG_DEBUG, ("%p Decode thread finished", mDecoder.get()));
 }
 
-void nsBuiltinDecoderStateMachine::SendOutputStreamAudio(AudioData* aAudio,
-                                                         OutputMediaStream* aStream,
-                                                         AudioSegment* aOutput)
+void nsBuiltinDecoderStateMachine::SendStreamAudio(AudioData* aAudio,
+                                                   DecodedStreamData* aStream,
+                                                   AudioSegment* aOutput)
 {
+  NS_ASSERTION(OnDecodeThread(), "Should be on decode thread.");
   mDecoder->GetReentrantMonitor().AssertCurrentThreadIn();
 
   if (aAudio->mTime <= aStream->mLastAudioPacketTime) {
     // ignore packet that we've already processed
     return;
   }
   aStream->mLastAudioPacketTime = aAudio->mTime;
   aStream->mLastAudioPacketEndTime = aAudio->GetEnd();
 
   NS_ASSERTION(aOutput->GetChannels() == int32_t(aAudio->mChannels),
                "Wrong number of channels");
 
   // This logic has to mimic AudioLoop closely to make sure we write
   // the exact same silences
   CheckedInt64 audioWrittenOffset = UsecsToFrames(mInfo.mAudioRate,
-      aStream->mAudioFramesWrittenBaseTime + mStartTime) + aStream->mAudioFramesWritten;
+      aStream->mInitialTime + mStartTime) + aStream->mAudioFramesWritten;
   CheckedInt64 frameOffset = UsecsToFrames(mInfo.mAudioRate, aAudio->mTime);
   if (!audioWrittenOffset.isValid() || !frameOffset.isValid())
     return;
   if (audioWrittenOffset.value() < frameOffset.value()) {
     // Write silence to catch up
     LOG(PR_LOG_DEBUG, ("%p Decoder writing %d frames of silence to MediaStream",
                        mDecoder.get(), int32_t(frameOffset.value() - audioWrittenOffset.value())));
     AudioSegment silence;
@@ -560,121 +563,122 @@ static void WriteVideoToMediaStream(mozi
   nsRefPtr<mozilla::layers::Image> image = aImage;
   aOutput->AppendFrame(image.forget(), aDuration, aIntrinsicSize);
 }
 
 static const TrackID TRACK_AUDIO = 1;
 static const TrackID TRACK_VIDEO = 2;
 static const TrackRate RATE_VIDEO = USECS_PER_S;
 
-void nsBuiltinDecoderStateMachine::SendOutputStreamData()
+void nsBuiltinDecoderStateMachine::SendStreamData()
 {
+  NS_ASSERTION(OnDecodeThread(), "Should be on decode thread.");
   mDecoder->GetReentrantMonitor().AssertCurrentThreadIn();
 
+  DecodedStreamData* stream = mDecoder->GetDecodedStream();
+  if (!stream)
+    return;
+
   if (mState == DECODER_STATE_DECODING_METADATA)
     return;
 
-  nsTArray<OutputMediaStream>& streams = mDecoder->OutputStreams();
   int64_t minLastAudioPacketTime = PR_INT64_MAX;
+  SourceMediaStream* mediaStream = stream->mStream;
+  StreamTime endPosition = 0;
+
+  if (!stream->mStreamInitialized) {
+    if (mInfo.mHasAudio) {
+      AudioSegment* audio = new AudioSegment();
+      audio->Init(mInfo.mAudioChannels);
+      mediaStream->AddTrack(TRACK_AUDIO, mInfo.mAudioRate, 0, audio);
+    }
+    if (mInfo.mHasVideo) {
+      VideoSegment* video = new VideoSegment();
+      mediaStream->AddTrack(TRACK_VIDEO, RATE_VIDEO, 0, video);
+    }
+    stream->mStreamInitialized = true;
+  }
+
+  if (mInfo.mHasAudio) {
+    nsAutoTArray<AudioData*,10> audio;
+    // It's OK to hold references to the AudioData because while audio
+    // is captured, only the decoder thread pops from the queue (see below).
+    mReader->mAudioQueue.GetElementsAfter(stream->mLastAudioPacketTime, &audio);
+    AudioSegment output;
+    output.Init(mInfo.mAudioChannels);
+    for (uint32_t i = 0; i < audio.Length(); ++i) {
+      SendStreamAudio(audio[i], stream, &output);
+    }
+    if (output.GetDuration() > 0) {
+      mediaStream->AppendToTrack(TRACK_AUDIO, &output);
+    }
+    if (mReader->mAudioQueue.IsFinished() && !stream->mHaveSentFinishAudio) {
+      mediaStream->EndTrack(TRACK_AUDIO);
+      stream->mHaveSentFinishAudio = true;
+    }
+    minLastAudioPacketTime = NS_MIN(minLastAudioPacketTime, stream->mLastAudioPacketTime);
+    endPosition = NS_MAX(endPosition,
+        TicksToTimeRoundDown(mInfo.mAudioRate, stream->mAudioFramesWritten));
+  }
+
+  if (mInfo.mHasVideo) {
+    nsAutoTArray<VideoData*,10> video;
+    // It's OK to hold references to the VideoData only the decoder thread
+    // pops from the queue.
+    mReader->mVideoQueue.GetElementsAfter(stream->mNextVideoTime + mStartTime, &video);
+    VideoSegment output;
+    for (uint32_t i = 0; i < video.Length(); ++i) {
+      VideoData* v = video[i];
+      if (stream->mNextVideoTime + mStartTime < v->mTime) {
+        LOG(PR_LOG_DEBUG, ("%p Decoder writing last video to MediaStream %p for %lld ms",
+                           mDecoder.get(), mediaStream,
+                           v->mTime - (stream->mNextVideoTime + mStartTime)));
+        // Write last video frame to catch up. mLastVideoImage can be null here
+        // which is fine, it just means there's no video.
+        WriteVideoToMediaStream(stream->mLastVideoImage,
+          v->mTime - (stream->mNextVideoTime + mStartTime), stream->mLastVideoImageDisplaySize,
+            &output);
+        stream->mNextVideoTime = v->mTime - mStartTime;
+      }
+      if (stream->mNextVideoTime + mStartTime < v->mEndTime) {
+        LOG(PR_LOG_DEBUG, ("%p Decoder writing video frame %lld to MediaStream %p for %lld ms",
+                           mDecoder.get(), v->mTime, mediaStream,
+                           v->mEndTime - (stream->mNextVideoTime + mStartTime)));
+        WriteVideoToMediaStream(v->mImage,
+            v->mEndTime - (stream->mNextVideoTime + mStartTime), v->mDisplay,
+            &output);
+        stream->mNextVideoTime = v->mEndTime - mStartTime;
+        stream->mLastVideoImage = v->mImage;
+        stream->mLastVideoImageDisplaySize = v->mDisplay;
+      } else {
+        LOG(PR_LOG_DEBUG, ("%p Decoder skipping writing video frame %lld to MediaStream",
+                           mDecoder.get(), v->mTime));
+      }
+    }
+    if (output.GetDuration() > 0) {
+      mediaStream->AppendToTrack(TRACK_VIDEO, &output);
+    }
+    if (mReader->mVideoQueue.IsFinished() && !stream->mHaveSentFinishVideo) {
+      mediaStream->EndTrack(TRACK_VIDEO);
+      stream->mHaveSentFinishVideo = true;
+    }
+    endPosition = NS_MAX(endPosition,
+        TicksToTimeRoundDown(RATE_VIDEO, stream->mNextVideoTime - stream->mInitialTime));
+  }
+
+  if (!stream->mHaveSentFinish) {
+    stream->mStream->AdvanceKnownTracksTime(endPosition);
+  }
 
   bool finished =
       (!mInfo.mHasAudio || mReader->mAudioQueue.IsFinished()) &&
       (!mInfo.mHasVideo || mReader->mVideoQueue.IsFinished());
-
-  for (uint32_t i = 0; i < streams.Length(); ++i) {
-    OutputMediaStream* stream = &streams[i];
-    SourceMediaStream* mediaStream = stream->mStream;
-    StreamTime endPosition = 0;
-
-    if (!stream->mStreamInitialized) {
-      if (mInfo.mHasAudio) {
-        AudioSegment* audio = new AudioSegment();
-        audio->Init(mInfo.mAudioChannels);
-        mediaStream->AddTrack(TRACK_AUDIO, mInfo.mAudioRate, 0, audio);
-      }
-      if (mInfo.mHasVideo) {
-        VideoSegment* video = new VideoSegment();
-        mediaStream->AddTrack(TRACK_VIDEO, RATE_VIDEO, 0, video);
-      }
-      stream->mStreamInitialized = true;
-    }
-
-    if (mInfo.mHasAudio) {
-      nsAutoTArray<AudioData*,10> audio;
-      // It's OK to hold references to the AudioData because while audio
-      // is captured, only the decoder thread pops from the queue (see below).
-      mReader->mAudioQueue.GetElementsAfter(stream->mLastAudioPacketTime, &audio);
-      AudioSegment output;
-      output.Init(mInfo.mAudioChannels);
-      for (uint32_t i = 0; i < audio.Length(); ++i) {
-        SendOutputStreamAudio(audio[i], stream, &output);
-      }
-      if (output.GetDuration() > 0) {
-        mediaStream->AppendToTrack(TRACK_AUDIO, &output);
-      }
-      if (mReader->mAudioQueue.IsFinished() && !stream->mHaveSentFinishAudio) {
-        mediaStream->EndTrack(TRACK_AUDIO);
-        stream->mHaveSentFinishAudio = true;
-      }
-      minLastAudioPacketTime = NS_MIN(minLastAudioPacketTime, stream->mLastAudioPacketTime);
-      endPosition = NS_MAX(endPosition,
-          TicksToTimeRoundDown(mInfo.mAudioRate, stream->mAudioFramesWritten));
-    }
-
-    if (mInfo.mHasVideo) {
-      nsAutoTArray<VideoData*,10> video;
-      // It's OK to hold references to the VideoData only the decoder thread
-      // pops from the queue.
-      mReader->mVideoQueue.GetElementsAfter(stream->mNextVideoTime + mStartTime, &video);
-      VideoSegment output;
-      for (uint32_t i = 0; i < video.Length(); ++i) {
-        VideoData* v = video[i];
-        if (stream->mNextVideoTime + mStartTime < v->mTime) {
-          LOG(PR_LOG_DEBUG, ("%p Decoder writing last video to MediaStream for %lld ms",
-                             mDecoder.get(), v->mTime - (stream->mNextVideoTime + mStartTime)));
-          // Write last video frame to catch up. mLastVideoImage can be null here
-          // which is fine, it just means there's no video.
-          WriteVideoToMediaStream(stream->mLastVideoImage,
-              v->mTime - (stream->mNextVideoTime + mStartTime), stream->mLastVideoImageDisplaySize,
-              &output);
-          stream->mNextVideoTime = v->mTime - mStartTime;
-        }
-        if (stream->mNextVideoTime + mStartTime < v->mEndTime) {
-          LOG(PR_LOG_DEBUG, ("%p Decoder writing video frame %lld to MediaStream",
-                             mDecoder.get(), v->mTime));
-          WriteVideoToMediaStream(v->mImage,
-              v->mEndTime - (stream->mNextVideoTime + mStartTime), v->mDisplay,
-              &output);
-          stream->mNextVideoTime = v->mEndTime - mStartTime;
-          stream->mLastVideoImage = v->mImage;
-          stream->mLastVideoImageDisplaySize = v->mDisplay;
-        } else {
-          LOG(PR_LOG_DEBUG, ("%p Decoder skipping writing video frame %lld to MediaStream",
-                             mDecoder.get(), v->mTime));
-        }
-      }
-      if (output.GetDuration() > 0) {
-        mediaStream->AppendToTrack(TRACK_VIDEO, &output);
-      }
-      if (mReader->mVideoQueue.IsFinished() && !stream->mHaveSentFinishVideo) {
-        mediaStream->EndTrack(TRACK_VIDEO);
-        stream->mHaveSentFinishVideo = true;
-      }
-      endPosition = NS_MAX(endPosition,
-          TicksToTimeRoundDown(RATE_VIDEO, stream->mNextVideoTime));
-    }
-
-    if (!stream->mHaveSentFinish) {
-      stream->mStream->AdvanceKnownTracksTime(endPosition);
-    }
-
-    if (finished && !stream->mHaveSentFinish) {
-      stream->mHaveSentFinish = true;
-      stream->mStream->Finish();
-    }
+  if (finished && !stream->mHaveSentFinish) {
+    stream->mHaveSentFinish = true;
+    stream->mStream->Finish();
   }
 
   if (mAudioCaptured) {
     // Discard audio packets that are no longer needed.
     int64_t audioPacketTimeToDiscard =
         NS_MIN(minLastAudioPacketTime, mStartTime + mCurrentFrameTime);
     while (true) {
       nsAutoPtr<AudioData> a(mReader->mAudioQueue.PopFront());
@@ -694,106 +698,68 @@ void nsBuiltinDecoderStateMachine::SendO
 
     if (finished) {
       mAudioCompleted = true;
       UpdateReadyState();
     }
   }
 }
 
-void nsBuiltinDecoderStateMachine::FinishOutputStreams()
+nsBuiltinDecoderStateMachine::WakeDecoderRunnable*
+nsBuiltinDecoderStateMachine::GetWakeDecoderRunnable()
 {
-  // Tell all our output streams that all tracks have ended and we've
-  // finished.
-  nsTArray<OutputMediaStream>& streams = mDecoder->OutputStreams();
-  for (uint32_t i = 0; i < streams.Length(); ++i) {
-    OutputMediaStream* stream = &streams[i];
-    if (!stream->mStreamInitialized) {
-      continue;
-    }
-    SourceMediaStream* mediaStream = stream->mStream;
-    if (mInfo.mHasAudio && !stream->mHaveSentFinishAudio) {
-      mediaStream->EndTrack(TRACK_AUDIO);
-      stream->mHaveSentFinishAudio = true;
-    }
-    if (mInfo.mHasVideo && !stream->mHaveSentFinishVideo) {
-      mediaStream->EndTrack(TRACK_VIDEO);
-      stream->mHaveSentFinishVideo = true;
-    }
-    // XXX ignoring mFinishWhenEnded for now. Immediate goal is to not crash.
-    if (!stream->mHaveSentFinish) {
-      mediaStream->Finish();
-      stream->mHaveSentFinish = true;
-    }
+  mDecoder->GetReentrantMonitor().AssertCurrentThreadIn();
+
+  if (!mPendingWakeDecoder.get()) {
+    mPendingWakeDecoder = new WakeDecoderRunnable(this);
   }
+  return mPendingWakeDecoder.get();
 }
 
 bool nsBuiltinDecoderStateMachine::HaveEnoughDecodedAudio(int64_t aAmpleAudioUSecs)
 {
   mDecoder->GetReentrantMonitor().AssertCurrentThreadIn();
 
   if (mReader->mAudioQueue.GetSize() == 0 ||
       GetDecodedAudioDuration() < aAmpleAudioUSecs) {
     return false;
   }
   if (!mAudioCaptured) {
     return true;
   }
 
-  nsTArray<OutputMediaStream>& streams = mDecoder->OutputStreams();
-  for (uint32_t i = 0; i < streams.Length(); ++i) {
-    OutputMediaStream* stream = &streams[i];
-    if (stream->mStreamInitialized && !stream->mHaveSentFinishAudio &&
-        !stream->mStream->HaveEnoughBuffered(TRACK_AUDIO)) {
+  DecodedStreamData* stream = mDecoder->GetDecodedStream();
+  if (stream && stream->mStreamInitialized && !stream->mHaveSentFinishAudio) {
+    if (!stream->mStream->HaveEnoughBuffered(TRACK_AUDIO)) {
       return false;
     }
+    stream->mStream->DispatchWhenNotEnoughBuffered(TRACK_AUDIO,
+        GetStateMachineThread(), GetWakeDecoderRunnable());
   }
 
-  nsIThread* thread = GetStateMachineThread();
-  nsCOMPtr<nsIRunnable> callback = NS_NewRunnableMethod(this,
-      &nsBuiltinDecoderStateMachine::ScheduleStateMachineWithLockAndWakeDecoder);
-  for (uint32_t i = 0; i < streams.Length(); ++i) {
-    OutputMediaStream* stream = &streams[i];
-    if (stream->mStreamInitialized && !stream->mHaveSentFinishAudio) {
-      stream->mStream->DispatchWhenNotEnoughBuffered(TRACK_AUDIO, thread, callback);
-    }
-  }
   return true;
 }
 
 bool nsBuiltinDecoderStateMachine::HaveEnoughDecodedVideo()
 {
   mDecoder->GetReentrantMonitor().AssertCurrentThreadIn();
 
   if (static_cast<uint32_t>(mReader->mVideoQueue.GetSize()) < AMPLE_VIDEO_FRAMES) {
     return false;
   }
 
-  nsTArray<OutputMediaStream>& streams = mDecoder->OutputStreams();
-  if (streams.IsEmpty()) {
-    return true;
-  }
-
-  for (uint32_t i = 0; i < streams.Length(); ++i) {
-    OutputMediaStream* stream = &streams[i];
-    if (stream->mStreamInitialized && !stream->mHaveSentFinishVideo &&
-        !stream->mStream->HaveEnoughBuffered(TRACK_VIDEO)) {
+  DecodedStreamData* stream = mDecoder->GetDecodedStream();
+  if (stream && stream->mStreamInitialized && !stream->mHaveSentFinishVideo) {
+    if (!stream->mStream->HaveEnoughBuffered(TRACK_VIDEO)) {
       return false;
     }
+    stream->mStream->DispatchWhenNotEnoughBuffered(TRACK_VIDEO,
+        GetStateMachineThread(), GetWakeDecoderRunnable());
   }
 
-  nsIThread* thread = GetStateMachineThread();
-  nsCOMPtr<nsIRunnable> callback = NS_NewRunnableMethod(this,
-      &nsBuiltinDecoderStateMachine::ScheduleStateMachineWithLockAndWakeDecoder);
-  for (uint32_t i = 0; i < streams.Length(); ++i) {
-    OutputMediaStream* stream = &streams[i];
-    if (stream->mStreamInitialized && !stream->mHaveSentFinishVideo) {
-      stream->mStream->DispatchWhenNotEnoughBuffered(TRACK_VIDEO, thread, callback);
-    }
-  }
   return true;
 }
 
 void nsBuiltinDecoderStateMachine::DecodeLoop()
 {
   LOG(PR_LOG_DEBUG, ("%p Start DecodeLoop()", mDecoder.get()));
 
   mDecoder->GetReentrantMonitor().AssertCurrentThreadIn();
@@ -910,17 +876,17 @@ void nsBuiltinDecoderStateMachine::Decod
       audioPump = true;
     }
     mDidThrottleAudioDecoding = throttleAudioDecoding;
     if (!mDidThrottleAudioDecoding) {
       ReentrantMonitorAutoExit exitMon(mDecoder->GetReentrantMonitor());
       audioPlaying = mReader->DecodeAudioData();
     }
 
-    SendOutputStreamData();
+    SendStreamData();
 
     // Notify to ensure that the AudioLoop() is not waiting, in case it was
     // waiting for more audio to be decoded.
     mDecoder->GetReentrantMonitor().NotifyAll();
 
     // The ready state can change when we've decoded data, so update the
     // ready state, so that DOM events can fire.
     UpdateReadyState();
@@ -1520,16 +1486,17 @@ void nsBuiltinDecoderStateMachine::Seek(
 
   // Bound the seek time to be inside the media range.
   NS_ASSERTION(mStartTime != -1, "Should know start time by now");
   NS_ASSERTION(mEndTime != -1, "Should know end time by now");
   mSeekTime = NS_MIN(mSeekTime, mEndTime);
   mSeekTime = NS_MAX(mStartTime, mSeekTime);
   LOG(PR_LOG_DEBUG, ("%p Changed state to SEEKING (to %f)", mDecoder.get(), aTime));
   mState = DECODER_STATE_SEEKING;
+  mDecoder->RecreateDecodedStream(mSeekTime - mStartTime);
   ScheduleStateMachine();
 }
 
 void nsBuiltinDecoderStateMachine::StopDecodeThread()
 {
   NS_ASSERTION(OnStateMachineThread(), "Should be on state machine thread.");
   mDecoder->GetReentrantMonitor().AssertCurrentThreadIn();
   if (mRequestedNewDecodeThread) {
@@ -1996,22 +1963,21 @@ nsresult nsBuiltinDecoderStateMachine::R
 
   switch (mState) {
     case DECODER_STATE_SHUTDOWN: {
       if (IsPlaying()) {
         StopPlayback();
       }
       StopAudioThread();
       StopDecodeThread();
+      // Now that those threads are stopped, there's no possibility of
+      // mPendingWakeDecoder being needed again. Revoke it.
+      mPendingWakeDecoder = nullptr;
       NS_ASSERTION(mState == DECODER_STATE_SHUTDOWN,
                    "How did we escape from the shutdown state?");
-      // Need to call this before dispatching nsDispatchDisposeEvent below, to
-      // ensure that any notifications dispatched by the stream graph
-      // will run before nsDispatchDisposeEvent below.
-      FinishOutputStreams();
       // We must daisy-chain these events to destroy the decoder. We must
       // destroy the decoder on the main thread, but we can't destroy the
       // decoder while this thread holds the decoder monitor. We can't
       // dispatch an event to the main thread to destroy the decoder from
       // here, as the event may run before the dispatch returns, and we
       // hold the decoder monitor here. We also want to guarantee that the
       // state machine is destroyed on the main thread, and so the
       // event runner running this function (which holds a reference to the
--- a/content/media/nsBuiltinDecoderStateMachine.h
+++ b/content/media/nsBuiltinDecoderStateMachine.h
@@ -101,17 +101,17 @@ hardware (via nsAudioStream and libsydne
 */
 class nsBuiltinDecoderStateMachine : public nsDecoderStateMachine
 {
 public:
   typedef mozilla::ReentrantMonitor ReentrantMonitor;
   typedef mozilla::TimeStamp TimeStamp;
   typedef mozilla::TimeDuration TimeDuration;
   typedef mozilla::VideoFrameContainer VideoFrameContainer;
-  typedef nsBuiltinDecoder::OutputMediaStream OutputMediaStream;
+  typedef nsBuiltinDecoder::DecodedStreamData DecodedStreamData;
   typedef mozilla::SourceMediaStream SourceMediaStream;
   typedef mozilla::AudioSegment AudioSegment;
   typedef mozilla::VideoSegment VideoSegment;
 
   nsBuiltinDecoderStateMachine(nsBuiltinDecoder* aDecoder, nsBuiltinDecoderReader* aReader, bool aRealTime = false);
   ~nsBuiltinDecoderStateMachine();
 
   // nsDecoderStateMachine interface
@@ -255,22 +255,56 @@ public:
   void ReleaseDecoder() { mDecoder = nullptr; }
 
    // Called when a "MozAudioAvailable" event listener is added to the media
    // element. Called on the main thread.
    void NotifyAudioAvailableListener();
 
   // Copy queued audio/video data in the reader to any output MediaStreams that
   // need it.
-  void SendOutputStreamData();
-  void FinishOutputStreams();
+  void SendStreamData();
+  void FinishStreamData();
   bool HaveEnoughDecodedAudio(int64_t aAmpleAudioUSecs);
   bool HaveEnoughDecodedVideo();
 
 protected:
+  class WakeDecoderRunnable : public nsRunnable {
+  public:
+    WakeDecoderRunnable(nsBuiltinDecoderStateMachine* aSM)
+      : mMutex("WakeDecoderRunnable"), mStateMachine(aSM) {}
+    NS_IMETHOD Run()
+    {
+      nsRefPtr<nsBuiltinDecoderStateMachine> stateMachine;
+      {
+        // Don't let Run() (called by media stream graph thread) race with
+        // Revoke() (called by decoder state machine thread)
+        MutexAutoLock lock(mMutex);
+        if (!mStateMachine)
+          return NS_OK;
+        stateMachine = mStateMachine;
+      }
+      stateMachine->ScheduleStateMachineWithLockAndWakeDecoder();
+      return NS_OK;
+    }
+    void Revoke()
+    {
+      MutexAutoLock lock(mMutex);
+      mStateMachine = nullptr;
+    }
+
+    Mutex mMutex;
+    // Protected by mMutex.
+    // We don't use an owning pointer here, because keeping mStateMachine alive
+    // would mean in some cases we'd have to destroy mStateMachine from this
+    // object, which would be problematic since nsBuiltinDecoderStateMachine can
+    // only be destroyed on the main thread whereas this object can be destroyed
+    // on the media stream graph thread.
+    nsBuiltinDecoderStateMachine* mStateMachine;
+  };
+  WakeDecoderRunnable* GetWakeDecoderRunnable();
 
   // Returns true if we've got less than aAudioUsecs microseconds of decoded
   // and playable data. The decoder monitor must be held.
   bool HasLowDecodedData(int64_t aAudioUsecs) const;
 
   // Returns true if we're running low on data which is not yet decoded.
   // The decoder monitor must be held.
   bool HasLowUndecodedData() const;
@@ -425,18 +459,18 @@ protected:
   void DecodeLoop();
 
   // Decode thread run function. Determines which of the Decode*() functions
   // to call.
   void DecodeThreadRun();
 
   // Copy audio from an AudioData packet to aOutput. This may require
   // inserting silence depending on the timing of the audio packet.
-  void SendOutputStreamAudio(AudioData* aAudio, OutputMediaStream* aStream,
-                             AudioSegment* aOutput);
+  void SendStreamAudio(AudioData* aAudio, DecodedStreamData* aStream,
+                       AudioSegment* aOutput);
 
   // State machine thread run function. Defers to RunStateMachine().
   nsresult CallRunStateMachine();
 
   // Performs one "cycle" of the state machine. Polls the state, and may send
   // a video frame to be displayed, and generally manages the decode. Called
   // periodically via timer to ensure the video stays in sync.
   nsresult RunStateMachine();
@@ -525,16 +559,23 @@ protected:
   // first acquire the decoder monitor and check that it is non-null.
   nsRefPtr<nsAudioStream> mAudioStream;
 
   // The reader, don't call its methods with the decoder monitor held.
   // This is created in the play state machine's constructor, and destroyed
   // in the play state machine's destructor.
   nsAutoPtr<nsBuiltinDecoderReader> mReader;
 
+  // Accessed only on the state machine thread.
+  // Not an nsRevocableEventPtr since we must Revoke() it well before
+  // this object is destroyed, anyway.
+  // Protected by decoder monitor except during the SHUTDOWN state after the
+  // decoder thread has been stopped.
+  nsRevocableEventPtr<WakeDecoderRunnable> mPendingWakeDecoder;
+
   // The time of the current frame in microseconds. This is referenced from
   // 0 which is the initial playback position. Set by the state machine
   // thread, and read-only from the main thread to get the current
   // time value. Synchronised via decoder monitor.
   int64_t mCurrentFrameTime;
 
   // The presentation time of the first audio frame that was played in
   // microseconds. We can add this to the audio stream position to determine
--- a/content/media/nsDOMMediaStream.cpp
+++ b/content/media/nsDOMMediaStream.cpp
@@ -46,13 +46,22 @@ already_AddRefed<nsDOMMediaStream>
 nsDOMMediaStream::CreateInputStream()
 {
   nsRefPtr<nsDOMMediaStream> stream = new nsDOMMediaStream();
   MediaStreamGraph* gm = MediaStreamGraph::GetInstance();
   stream->mStream = gm->CreateInputStream(stream);
   return stream.forget();
 }
 
+already_AddRefed<nsDOMMediaStream>
+nsDOMMediaStream::CreateTrackUnionStream()
+{
+  nsRefPtr<nsDOMMediaStream> stream = new nsDOMMediaStream();
+  MediaStreamGraph* gm = MediaStreamGraph::GetInstance();
+  stream->mStream = gm->CreateTrackUnionStream(stream);
+  return stream.forget();
+}
+
 bool
 nsDOMMediaStream::CombineWithPrincipal(nsIPrincipal* aPrincipal)
 {
   return nsContentUtils::CombineResourcePrincipals(&mPrincipal, aPrincipal);
 }
--- a/content/media/nsDOMMediaStream.h
+++ b/content/media/nsDOMMediaStream.h
@@ -50,16 +50,21 @@ public:
    */
   bool CombineWithPrincipal(nsIPrincipal* aPrincipal);
 
   /**
    * Create an nsDOMMediaStream whose underlying stream is a SourceMediaStream.
    */
   static already_AddRefed<nsDOMMediaStream> CreateInputStream();
 
+  /**
+   * Create an nsDOMMediaStream whose underlying stream is a TrackUnionStream.
+   */
+  static already_AddRefed<nsDOMMediaStream> CreateTrackUnionStream();
+
 protected:
   // MediaStream is owned by the graph, but we tell it when to die, and it won't
   // die until we let it.
   MediaStream* mStream;
   // Principal identifying who may access the contents of this stream.
   // If null, this stream can be used by anyone because it has no content yet.
   nsCOMPtr<nsIPrincipal> mPrincipal;
 };
--- a/content/media/nsMediaDecoder.h
+++ b/content/media/nsMediaDecoder.h
@@ -36,16 +36,19 @@ static const uint32_t FRAMEBUFFER_LENGTH
 // with the exception of GetVideoFrameContainer and GetStatistics,
 // which can be called from any thread.
 class nsMediaDecoder : public nsIObserver
 {
 public:
   typedef mozilla::MediaResource MediaResource;
   typedef mozilla::ReentrantMonitor ReentrantMonitor;
   typedef mozilla::SourceMediaStream SourceMediaStream;
+  typedef mozilla::ProcessedMediaStream ProcessedMediaStream;
+  typedef mozilla::MediaInputPort MediaInputPort;
+  typedef mozilla::MainThreadMediaStreamListener MainThreadMediaStreamListener;
   typedef mozilla::TimeStamp TimeStamp;
   typedef mozilla::TimeDuration TimeDuration;
   typedef mozilla::VideoFrameContainer VideoFrameContainer;
 
   nsMediaDecoder();
   virtual ~nsMediaDecoder();
 
   // Create a new decoder of the same type as this one.
@@ -97,17 +100,20 @@ public:
   // Set the audio volume. It should be a value from 0 to 1.0.
   virtual void SetVolume(double aVolume) = 0;
 
   // Sets whether audio is being captured. If it is, we won't play any
   // of our audio.
   virtual void SetAudioCaptured(bool aCaptured) = 0;
 
   // Add an output stream. All decoder output will be sent to the stream.
-  virtual void AddOutputStream(SourceMediaStream* aStream, bool aFinishWhenEnded) = 0;
+  // The stream is initially blocked. The decoder is responsible for unblocking
+  // it while it is playing back.
+  virtual void AddOutputStream(ProcessedMediaStream* aStream,
+                               bool aFinishWhenEnded) = 0;
 
   // Start playback of a video. 'Load' must have previously been
   // called.
   virtual nsresult Play() = 0;
 
   // Start downloading the media. Decode the downloaded data up to the
   // point of the first frame of data.
   // aResource is the media stream to use. Ownership of aResource passes to
--- a/content/media/test/test_streams_element_capture_reset.html
+++ b/content/media/test/test_streams_element_capture_reset.html
@@ -4,69 +4,92 @@
   <title>Test that reloading and seeking in a media element that's being captured doesn't crash</title>
   <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
   <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
   <script type="text/javascript" src="manifest.js"></script>
 </head>
 <body>
 <video id="v"></video>
 <video id="vout"></video>
+<video id="vout_untilended"></video>
 <pre id="test">
 <script class="testbody" type="text/javascript">
 SimpleTest.waitForExplicitFinish();
 
 var v = document.getElementById('v');
 var vout = document.getElementById('vout');
-var stream = v.mozCaptureStream();
-vout.src = stream;
+var vout_untilended = document.getElementById('vout_untilended');
+vout.src = v.mozCaptureStream();
+vout_untilended.src = v.mozCaptureStreamUntilEnded();
 
 function dumpEvent(event) {
   dump("GOT EVENT " + event.type + " currentTime=" + event.target.currentTime +
        " paused=" + event.target.paused + " ended=" + event.target.ended +
        " readyState=" + event.target.readyState + "\n");
 }
 var events = ["timeupdate", "seeking", "seeked", "ended", "playing", "pause"];
 for (var i = 0; i < events.length; ++i) {
   v.addEventListener(events[i], dumpEvent, false);
 }
+function isWithinEps(a, b, msg) {
+  ok(Math.abs(a - b) < 0.01,
+     "Got " + a + ", expected " + b + "; " + msg);
+}
 
 function startTest(test) {
   var seekTime = test.duration/2;
 
-  function ended() {
-    ok(true, "Final ended after changing src");
+  function endedAfterReplay() {
+    isWithinEps(v.currentTime, test.duration, "checking v.currentTime at third 'ended' event");
+    isWithinEps(vout.currentTime, (v.currentTime - seekTime) + test.duration*2,
+	            "checking vout.currentTime after seeking, playing through and reloading");
     SimpleTest.finish();
   };
-  function timeupdateAfterSeek() {
-    if (v.currentTime < seekTime + 0.001)
-      return;
-    ok(true, "timeupdate after seek");
-    v.removeEventListener("timeupdate", timeupdateAfterSeek, false);
+  function endedAfterSeek() {
+    isWithinEps(v.currentTime, test.duration, "checking v.currentTime at second 'ended' event");
+    isWithinEps(vout.currentTime, (v.currentTime - seekTime) + test.duration,
+                "checking vout.currentTime after seeking and playing through again");
+    v.removeEventListener("ended", endedAfterSeek, false);
+    v.addEventListener("ended", endedAfterReplay, false);
     v.src = test.name + "?1";
     v.play();
-    v.addEventListener("ended", ended, false);
   };
   function seeked() {
-    ok(true, "Finished seeking");
+    isWithinEps(v.currentTime, seekTime, "Finished seeking");
+    isWithinEps(vout.currentTime, test.duration,
+                "checking vout.currentTime has not changed after seeking");
     v.removeEventListener("seeked", seeked, false);
-    v.addEventListener("timeupdate", timeupdateAfterSeek, false);
+    function dontPlayAgain() {
+      ok(false, "vout_untilended should not play again");
+    }
+    vout_untilended.addEventListener("playing", dontPlayAgain, false);
+    vout_untilended.addEventListener("ended", dontPlayAgain, false);
+    v.addEventListener("ended", endedAfterSeek, false);
+    v.play();
   };
-  function timeupdate() {
-    if (v.currentTime == 0)
-      return;
-    ok(true, "Initial timeupdate");
-    v.removeEventListener("timeupdate", timeupdate, false);
+  function ended() {
+    isWithinEps(vout.currentTime, test.duration, "checking vout.currentTime at first 'ended' event");
+    isWithinEps(v.currentTime, test.duration, "checking v.currentTime at first 'ended' event");
+    is(vout.ended, false, "checking vout has not ended");
+    is(vout_untilended.ended, true, "checking vout_untilended has actually ended");
+    vout_untilended.removeEventListener("ended", ended, false);
+    v.pause();
     v.currentTime = seekTime;
     v.addEventListener("seeked", seeked, false);
   };
-  v.addEventListener("timeupdate", timeupdate, false);
+  vout_untilended.addEventListener("ended", ended, false);
 
   v.src = test.name;
   v.play();
+  function checkNoEnded() {
+    ok(false, "ended event received unexpectedly");
+  };
+  vout.addEventListener("ended", checkNoEnded, false);
   vout.play();
+  vout_untilended.play();
 }
 
 var testVideo = getPlayableVideo(gSmallTests);
 if (testVideo) {
   startTest(testVideo);
 } else {
   todo(false, "No playable video");
 }
--- a/content/svg/content/src/DOMSVGAnimatedLengthList.cpp
+++ b/content/svg/content/src/DOMSVGAnimatedLengthList.cpp
@@ -53,24 +53,23 @@ DOMSVGAnimatedLengthList::GetAnimVal(nsI
 }
 
 /* static */ already_AddRefed<DOMSVGAnimatedLengthList>
 DOMSVGAnimatedLengthList::GetDOMWrapper(SVGAnimatedLengthList *aList,
                                         nsSVGElement *aElement,
                                         uint8_t aAttrEnum,
                                         uint8_t aAxis)
 {
-  DOMSVGAnimatedLengthList *wrapper =
+  nsRefPtr<DOMSVGAnimatedLengthList> wrapper =
     sSVGAnimatedLengthListTearoffTable.GetTearoff(aList);
   if (!wrapper) {
     wrapper = new DOMSVGAnimatedLengthList(aElement, aAttrEnum, aAxis);
     sSVGAnimatedLengthListTearoffTable.AddTearoff(aList, wrapper);
   }
-  NS_ADDREF(wrapper);
-  return wrapper;
+  return wrapper.forget();
 }
 
 /* static */ DOMSVGAnimatedLengthList*
 DOMSVGAnimatedLengthList::GetDOMWrapperIfExists(SVGAnimatedLengthList *aList)
 {
   return sSVGAnimatedLengthListTearoffTable.GetTearoff(aList);
 }
 
--- a/content/svg/content/src/DOMSVGAnimatedNumberList.cpp
+++ b/content/svg/content/src/DOMSVGAnimatedNumberList.cpp
@@ -52,24 +52,23 @@ DOMSVGAnimatedNumberList::GetAnimVal(nsI
   return NS_OK;
 }
 
 /* static */ already_AddRefed<DOMSVGAnimatedNumberList>
 DOMSVGAnimatedNumberList::GetDOMWrapper(SVGAnimatedNumberList *aList,
                                         nsSVGElement *aElement,
                                         uint8_t aAttrEnum)
 {
-  DOMSVGAnimatedNumberList *wrapper =
+  nsRefPtr<DOMSVGAnimatedNumberList> wrapper =
     sSVGAnimatedNumberListTearoffTable.GetTearoff(aList);
   if (!wrapper) {
     wrapper = new DOMSVGAnimatedNumberList(aElement, aAttrEnum);
     sSVGAnimatedNumberListTearoffTable.AddTearoff(aList, wrapper);
   }
-  NS_ADDREF(wrapper);
-  return wrapper;
+  return wrapper.forget();
 }
 
 /* static */ DOMSVGAnimatedNumberList*
 DOMSVGAnimatedNumberList::GetDOMWrapperIfExists(SVGAnimatedNumberList *aList)
 {
   return sSVGAnimatedNumberListTearoffTable.GetTearoff(aList);
 }
 
--- a/content/svg/content/src/DOMSVGAnimatedTransformList.cpp
+++ b/content/svg/content/src/DOMSVGAnimatedTransformList.cpp
@@ -53,24 +53,23 @@ DOMSVGAnimatedTransformList::GetAnimVal(
   NS_ADDREF(*aAnimVal = mAnimVal);
   return NS_OK;
 }
 
 /* static */ already_AddRefed<DOMSVGAnimatedTransformList>
 DOMSVGAnimatedTransformList::GetDOMWrapper(SVGAnimatedTransformList *aList,
                                            nsSVGElement *aElement)
 {
-  DOMSVGAnimatedTransformList *wrapper =
+  nsRefPtr<DOMSVGAnimatedTransformList> wrapper =
     sSVGAnimatedTransformListTearoffTable.GetTearoff(aList);
   if (!wrapper) {
     wrapper = new DOMSVGAnimatedTransformList(aElement);
     sSVGAnimatedTransformListTearoffTable.AddTearoff(aList, wrapper);
   }
-  NS_ADDREF(wrapper);
-  return wrapper;
+  return wrapper.forget();
 }
 
 /* static */ DOMSVGAnimatedTransformList*
 DOMSVGAnimatedTransformList::GetDOMWrapperIfExists(
   SVGAnimatedTransformList *aList)
 {
   return sSVGAnimatedTransformListTearoffTable.GetTearoff(aList);
 }
--- a/content/svg/content/src/DOMSVGLengthList.cpp
+++ b/content/svg/content/src/DOMSVGLengthList.cpp
@@ -71,17 +71,17 @@ NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(
   NS_INTERFACE_MAP_ENTRY(nsIDOMSVGLengthList)
   NS_INTERFACE_MAP_ENTRY(nsISupports)
   NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(SVGLengthList)
 NS_INTERFACE_MAP_END
 
 JSObject*
 DOMSVGLengthList::WrapObject(JSContext *cx, JSObject *scope, bool *triedToWrap)
 {
-  return mozilla::dom::binding::SVGLengthList::create(cx, scope, this,
+  return mozilla::dom::oldproxybindings::SVGLengthList::create(cx, scope, this,
                                                       triedToWrap);
 }
 
 nsIDOMSVGLength*
 DOMSVGLengthList::GetItemAt(uint32_t aIndex)
 {
   if (IsAnimValList()) {
     Element()->FlushAnimations();
--- a/content/svg/content/src/DOMSVGNumberList.cpp
+++ b/content/svg/content/src/DOMSVGNumberList.cpp
@@ -72,17 +72,17 @@ NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(
   NS_INTERFACE_MAP_ENTRY(nsISupports)
   NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(SVGNumberList)
 NS_INTERFACE_MAP_END
 
 
 JSObject*
 DOMSVGNumberList::WrapObject(JSContext *cx, JSObject *scope, bool *triedToWrap)
 {
-  return mozilla::dom::binding::SVGNumberList::create(cx, scope, this,
+  return mozilla::dom::oldproxybindings::SVGNumberList::create(cx, scope, this,
                                                       triedToWrap);
 }
 
 nsIDOMSVGNumber*
 DOMSVGNumberList::GetItemAt(uint32_t aIndex)
 {
   if (IsAnimValList()) {
     Element()->FlushAnimations();
--- a/content/svg/content/src/DOMSVGPathSegList.cpp
+++ b/content/svg/content/src/DOMSVGPathSegList.cpp
@@ -50,24 +50,23 @@ NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(
 NS_INTERFACE_MAP_END
 
 
 /* static */ already_AddRefed<DOMSVGPathSegList>
 DOMSVGPathSegList::GetDOMWrapper(void *aList,
                                  nsSVGElement *aElement,
                                  bool aIsAnimValList)
 {
-  DOMSVGPathSegList *wrapper =
+  nsRefPtr<DOMSVGPathSegList> wrapper =
     sSVGPathSegListTearoffTable.GetTearoff(aList);
   if (!wrapper) {
     wrapper = new DOMSVGPathSegList(aElement, aIsAnimValList);
     sSVGPathSegListTearoffTable.AddTearoff(aList, wrapper);
   }
-  NS_ADDREF(wrapper);
-  return wrapper;
+  return wrapper.forget();
 }
 
 /* static */ DOMSVGPathSegList*
 DOMSVGPathSegList::GetDOMWrapperIfExists(void *aList)
 {
   return sSVGPathSegListTearoffTable.GetTearoff(aList);
 }
 
@@ -79,17 +78,17 @@ DOMSVGPathSegList::~DOMSVGPathSegList()
     InternalAList().GetAnimValKey() :
     InternalAList().GetBaseValKey();
   sSVGPathSegListTearoffTable.RemoveTearoff(key);
 }
 
 JSObject*
 DOMSVGPathSegList::WrapObject(JSContext *cx, JSObject *scope, bool *triedToWrap)
 {
-  return mozilla::dom::binding::SVGPathSegList::create(cx, scope, this,
+  return mozilla::dom::oldproxybindings::SVGPathSegList::create(cx, scope, this,
                                                        triedToWrap);
 }
 
 nsIDOMSVGPathSeg*
 DOMSVGPathSegList::GetItemAt(uint32_t aIndex)
 {
   if (IsAnimValList()) {
     Element()->FlushAnimations();
--- a/content/svg/content/src/DOMSVGPointList.cpp
+++ b/content/svg/content/src/DOMSVGPointList.cpp
@@ -69,24 +69,23 @@ NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(
 NS_INTERFACE_MAP_END
 
 
 /* static */ already_AddRefed<DOMSVGPointList>
 DOMSVGPointList::GetDOMWrapper(void *aList,
                                nsSVGElement *aElement,
                                bool aIsAnimValList)
 {
-  DOMSVGPointList *wrapper =
+  nsRefPtr<DOMSVGPointList> wrapper =
     sSVGPointListTearoffTable.GetTearoff(aList);
   if (!wrapper) {
     wrapper = new DOMSVGPointList(aElement, aIsAnimValList);
     sSVGPointListTearoffTable.AddTearoff(aList, wrapper);
   }
-  NS_ADDREF(wrapper);
-  return wrapper;
+  return wrapper.forget();
 }
 
 /* static */ DOMSVGPointList*
 DOMSVGPointList::GetDOMWrapperIfExists(void *aList)
 {
   return sSVGPointListTearoffTable.GetTearoff(aList);
 }
 
@@ -98,17 +97,17 @@ DOMSVGPointList::~DOMSVGPointList()
     InternalAList().GetAnimValKey() :
     InternalAList().GetBaseValKey();
   sSVGPointListTearoffTable.RemoveTearoff(key);
 }
 
 JSObject*
 DOMSVGPointList::WrapObject(JSContext *cx, JSObject *scope, bool *triedToWrap)
 {
-  return mozilla::dom::binding::SVGPointList::create(cx, scope, this,
+  return mozilla::dom::oldproxybindings::SVGPointList::create(cx, scope, this,
                                                      triedToWrap);
 }
 
 nsIDOMSVGPoint*
 DOMSVGPointList::GetItemAt(uint32_t aIndex)
 {
   if (IsAnimValList()) {
     Element()->FlushAnimations();
--- a/content/svg/content/src/DOMSVGStringList.cpp
+++ b/content/svg/content/src/DOMSVGStringList.cpp
@@ -34,26 +34,25 @@ NS_INTERFACE_MAP_END
 
 
 /* static */ already_AddRefed<DOMSVGStringList>
 DOMSVGStringList::GetDOMWrapper(SVGStringList *aList,
                                 nsSVGElement *aElement,
                                 bool aIsConditionalProcessingAttribute,
                                 uint8_t aAttrEnum)
 {
-  DOMSVGStringList *wrapper =
+  nsRefPtr<DOMSVGStringList> wrapper =
     sSVGStringListTearoffTable.GetTearoff(aList);
   if (!wrapper) {
     wrapper = new DOMSVGStringList(aElement, 
                                    aIsConditionalProcessingAttribute,
                                    aAttrEnum);
     sSVGStringListTearoffTable.AddTearoff(aList, wrapper);
   }
-  NS_ADDREF(wrapper);
-  return wrapper;
+  return wrapper.forget();
 }
 
 DOMSVGStringList::~DOMSVGStringList()
 {
   // Script no longer has any references to us.
   sSVGStringListTearoffTable.RemoveTearoff(&InternalList());
 }
 
--- a/content/svg/content/src/DOMSVGTransformList.cpp
+++ b/content/svg/content/src/DOMSVGTransformList.cpp
@@ -72,17 +72,17 @@ NS_INTERFACE_MAP_END
 
 //----------------------------------------------------------------------
 // DOMSVGTransformList methods:
 
 JSObject*
 DOMSVGTransformList::WrapObject(JSContext *cx, JSObject *scope,
                                 bool *triedToWrap)
 {
-  return mozilla::dom::binding::SVGTransformList::create(cx, scope, this,
+  return mozilla::dom::oldproxybindings::SVGTransformList::create(cx, scope, this,
                                                          triedToWrap);
 }
 
 nsIDOMSVGTransform*
 DOMSVGTransformList::GetItemAt(uint32_t aIndex)
 {
   if (IsAnimValList()) {
     Element()->FlushAnimations();
--- a/content/svg/content/src/nsSVGLength2.cpp
+++ b/content/svg/content/src/nsSVGLength2.cpp
@@ -63,21 +63,21 @@ static nsIAtom** const unitMap[] =
   &nsGkAtoms::px,
   &nsGkAtoms::cm,
   &nsGkAtoms::mm,
   &nsGkAtoms::in,
   &nsGkAtoms::pt,
   &nsGkAtoms::pc
 };
 
-static nsSVGAttrTearoffTable<nsSVGLength2, nsIDOMSVGAnimatedLength>
+static nsSVGAttrTearoffTable<nsSVGLength2, nsSVGLength2::DOMAnimatedLength>
   sSVGAnimatedLengthTearoffTable;
-static nsSVGAttrTearoffTable<nsSVGLength2, nsIDOMSVGLength>
+static nsSVGAttrTearoffTable<nsSVGLength2, nsSVGLength2::DOMBaseVal>
   sBaseSVGLengthTearoffTable;
-static nsSVGAttrTearoffTable<nsSVGLength2, nsIDOMSVGLength>
+static nsSVGAttrTearoffTable<nsSVGLength2, nsSVGLength2::DOMAnimVal>
   sAnimSVGLengthTearoffTable;
 
 /* Helper functions */
 
 static bool
 IsValidUnitType(uint16_t unit)
 {
   if (unit > nsIDOMSVGLength::SVG_LENGTHTYPE_UNKNOWN &&
@@ -354,45 +354,43 @@ nsSVGLength2::NewValueSpecifiedUnits(uin
   }
   aSVGElement->DidChangeLength(mAttrEnum, emptyOrOldValue);
   return NS_OK;
 }
 
 nsresult
 nsSVGLength2::ToDOMBaseVal(nsIDOMSVGLength **aResult, nsSVGElement *aSVGElement)
 {
-  *aResult = sBaseSVGLengthTearoffTable.GetTearoff(this);
-  if (!*aResult) {
-    *aResult = new DOMBaseVal(this, aSVGElement);
-    if (!*aResult)
-      return NS_ERROR_OUT_OF_MEMORY;
-    sBaseSVGLengthTearoffTable.AddTearoff(this, *aResult);
+  nsRefPtr<DOMBaseVal> domBaseVal =
+    sBaseSVGLengthTearoffTable.GetTearoff(this);
+  if (!domBaseVal) {
+    domBaseVal = new DOMBaseVal(this, aSVGElement);
+    sBaseSVGLengthTearoffTable.AddTearoff(this, domBaseVal);
   }
 
-  NS_ADDREF(*aResult);
+  domBaseVal.forget(aResult);
   return NS_OK;
 }
 
 nsSVGLength2::DOMBaseVal::~DOMBaseVal()
 {
   sBaseSVGLengthTearoffTable.RemoveTearoff(mVal);
 }
 
 nsresult
 nsSVGLength2::ToDOMAnimVal(nsIDOMSVGLength **aResult, nsSVGElement *aSVGElement)
 {
-  *aResult = sAnimSVGLengthTearoffTable.GetTearoff(this);
-  if (!*aResult) {
-    *aResult = new DOMAnimVal(this, aSVGElement);
-    if (!*aResult)
-      return NS_ERROR_OUT_OF_MEMORY;
-    sAnimSVGLengthTearoffTable.AddTearoff(this, *aResult);
+  nsRefPtr<DOMAnimVal> domAnimVal =
+    sAnimSVGLengthTearoffTable.GetTearoff(this);
+  if (!domAnimVal) {
+    domAnimVal = new DOMAnimVal(this, aSVGElement);
+    sAnimSVGLengthTearoffTable.AddTearoff(this, domAnimVal);
   }
 
-  NS_ADDREF(*aResult);
+  domAnimVal.forget(aResult);
   return NS_OK;
 }
 
 nsSVGLength2::DOMAnimVal::~DOMAnimVal()
 {
   sAnimSVGLengthTearoffTable.RemoveTearoff(mVal);
 }
 
@@ -476,25 +474,24 @@ nsSVGLength2::SetAnimValue(float aValue,
                                                            mSpecifiedUnitType),
                                aSVGElement);
 }
 
 nsresult
 nsSVGLength2::ToDOMAnimatedLength(nsIDOMSVGAnimatedLength **aResult,
                                   nsSVGElement *aSVGElement)
 {
-  *aResult = sSVGAnimatedLengthTearoffTable.GetTearoff(this);
-  if (!*aResult) {
-    *aResult = new DOMAnimatedLength(this, aSVGElement);
-    if (!*aResult)
-      return NS_ERROR_OUT_OF_MEMORY;
-    sSVGAnimatedLengthTearoffTable.AddTearoff(this, *aResult);
+  nsRefPtr<DOMAnimatedLength> domAnimatedLength =
+    sSVGAnimatedLengthTearoffTable.GetTearoff(this);
+  if (!domAnimatedLength) {
+    domAnimatedLength = new DOMAnimatedLength(this, aSVGElement);
+    sSVGAnimatedLengthTearoffTable.AddTearoff(this, domAnimatedLength);
   }
 
-  NS_ADDREF(*aResult);
+  domAnimatedLength.forget(aResult);
   return NS_OK;
 }
 
 nsSVGLength2::DOMAnimatedLength::~DOMAnimatedLength()
 {
   sSVGAnimatedLengthTearoffTable.RemoveTearoff(mVal);
 }
 
--- a/content/svg/content/src/nsSVGLength2.h
+++ b/content/svg/content/src/nsSVGLength2.h
@@ -122,16 +122,17 @@ private:
   void SetAnimValue(float aValue, nsSVGElement *aSVGElement);
   void SetAnimValueInSpecifiedUnits(float aValue, nsSVGElement *aSVGElement);
   nsresult NewValueSpecifiedUnits(uint16_t aUnitType, float aValue,
                                   nsSVGElement *aSVGElement);
   nsresult ConvertToSpecifiedUnits(uint16_t aUnitType, nsSVGElement *aSVGElement);
   nsresult ToDOMBaseVal(nsIDOMSVGLength **aResult, nsSVGElement* aSVGElement);
   nsresult ToDOMAnimVal(nsIDOMSVGLength **aResult, nsSVGElement* aSVGElement);
 
+public:
   struct DOMBaseVal : public nsIDOMSVGLength
   {
     NS_DECL_CYCLE_COLLECTING_ISUPPORTS
     NS_DECL_CYCLE_COLLECTION_CLASS(DOMBaseVal)
 
     DOMBaseVal(nsSVGLength2* aVal, nsSVGElement *aSVGElement)
       : mVal(aVal), mSVGElement(aSVGElement) {}
     virtual ~DOMBaseVal();
@@ -230,17 +231,16 @@ private:
     NS_IMETHOD NewValueSpecifiedUnits(uint16_t unitType,
                                       float valueInSpecifiedUnits)
       { return NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR; }
 
     NS_IMETHOD ConvertToSpecifiedUnits(uint16_t unitType)
       { return NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR; }
   };
 
-public:
   struct DOMAnimatedLength : public nsIDOMSVGAnimatedLength
   {
     NS_DECL_CYCLE_COLLECTING_ISUPPORTS
     NS_DECL_CYCLE_COLLECTION_CLASS(DOMAnimatedLength)
 
     DOMAnimatedLength(nsSVGLength2* aVal, nsSVGElement *aSVGElement)
       : mVal(aVal), mSVGElement(aSVGElement) {}
     virtual ~DOMAnimatedLength();
--- a/content/xbl/src/nsBindingManager.cpp
+++ b/content/xbl/src/nsBindingManager.cpp
@@ -75,17 +75,17 @@ public:
   int32_t GetInsertionPointCount() { return mElements->Length(); }
 
   nsXBLInsertionPoint* GetInsertionPointAt(int32_t i) { return static_cast<nsXBLInsertionPoint*>(mElements->ElementAt(i)); }
   void RemoveInsertionPointAt(int32_t i) { mElements->RemoveElementAt(i); }
 
   virtual JSObject* WrapObject(JSContext *cx, JSObject *scope,
                                bool *triedToWrap)
   {
-    return mozilla::dom::binding::NodeList::create(cx, scope, this,
+    return mozilla::dom::oldproxybindings::NodeList::create(cx, scope, this,
                                                    triedToWrap);
   }
 
   NS_DECLARE_STATIC_IID_ACCESSOR(NS_ANONYMOUS_CONTENT_LIST_IID)
 private:
   nsCOMPtr<nsIContent> mContent;
   nsInsertionPointList* mElements;
 };
--- a/docshell/test/navigation/NavigationUtils.js
+++ b/docshell/test/navigation/NavigationUtils.js
@@ -53,17 +53,17 @@ function navigateByHyperlink(name) {
 
 ///////////////////////////////////////////////////////////////////////////
 // Functions that call into Mochitest framework
 ///////////////////////////////////////////////////////////////////////////
 
 function isNavigated(wnd, message) {
   var result = null;
   try {
-    result = wnd.document.body.innerHTML;
+    result = SpecialPowers.wrap(wnd).document.body.innerHTML;
   } catch(ex) {
     result = ex;
   }
   is(result, body, message);
 }
 
 function isBlank(wnd, message) {
   var result = null;
@@ -104,26 +104,26 @@ function xpcEnumerateContentWindows(call
                         .classes["@mozilla.org/embedcomp/window-watcher;1"]
                         .getService(Ci.nsIWindowWatcher);
   var enumerator = ww.getWindowEnumerator();
 
   var contentWindows = [];
 
   while (enumerator.hasMoreElements()) {
     var win = enumerator.getNext();
-    if (typeof ChromeWindow != "undefined" && SpecialPowers.call_Instanceof(win, ChromeWindow)) {
+    if (/ChromeWindow/.exec(win)) {
       var docshellTreeNode = win.QueryInterface(Ci.nsIInterfaceRequestor)
                                 .getInterface(Ci.nsIWebNavigation)
                                 .QueryInterface(Ci.nsIDocShellTreeNode);
       var childCount = docshellTreeNode.childCount;
       for (var i = 0; i < childCount; ++i) {
         var childTreeNode = docshellTreeNode.getChildAt(i);
 
         // we're only interested in content docshells
-        if (childTreeNode.itemType != Ci.nsIDocShellTreeItem.typeContent)
+        if (SpecialPowers.unwrap(childTreeNode.itemType) != Ci.nsIDocShellTreeItem.typeContent)
           continue;
 
         var webNav = childTreeNode.QueryInterface(Ci.nsIWebNavigation);
         contentWindows.push(webNav.document.defaultView);
       }
     } else {
       contentWindows.push(win);
     }
--- a/docshell/test/test_bug511449.html
+++ b/docshell/test/test_bug511449.html
@@ -33,19 +33,17 @@ function runTest() {
   SimpleTest.waitForFocus(runNextTest, win);
 }
 
 function runNextTest() {
   var didClose = false;
   win.onunload = function() {
     didClose = true;
   }
-  netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
-  var utils = win.QueryInterface(Components.interfaces.nsIInterfaceRequestor).
-                  getInterface(Components.interfaces.nsIDOMWindowUtils);
+  var utils = SpecialPowers.getDOMWindowUtils(win);
   utils.sendNativeKeyEvent(0, MAC_VK_ANSI_W, 0x4000 /* cmd */, "w", "w");
 
   setTimeout(function () {
     ok(didClose, "Cmd+W should have closed the tab");
     if (!didClose) {
       win.close();
     }
     SimpleTest.finish();
--- a/dom/activities/src/ActivityWrapper.js
+++ b/dom/activities/src/ActivityWrapper.js
@@ -1,26 +1,26 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
- 
+
 const Cc = Components.classes;
 const Ci = Components.interfaces;
 const Cu = Components.utils;
- 
+
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 
 function debug(aMsg) {
   //dump("-- ActivityWrapper.js " + Date.now() + " : " + aMsg + "\n");
 }
 
 /**
-  * nsISystemMessagesWrapper implementation. Will return a 
+  * nsISystemMessagesWrapper implementation. Will return a
   * nsIDOMMozActivityRequestHandler
   */
 function ActivityWrapper() {
   debug("ActivityWrapper");
 }
 
 ActivityWrapper.prototype = {
   wrapMessage: function wrapMessage(aMessage) {
--- a/dom/base/Navigator.cpp
+++ b/dom/base/Navigator.cpp
@@ -34,16 +34,18 @@
 #include "mozilla/Hal.h"
 #include "nsIWebNavigation.h"
 #include "mozilla/ClearOnShutdown.h"
 #include "mozilla/StaticPtr.h"
 #include "Connection.h"
 #include "MobileConnection.h"
 #include "nsIIdleObserver.h"
 #include "nsIPermissionManager.h"
+#include "nsNetUtil.h"
+#include "nsIHttpChannel.h"
 
 #ifdef MOZ_MEDIA_NAVIGATOR
 #include "MediaManager.h"
 #endif
 #ifdef MOZ_B2G_RIL
 #include "TelephonyFactory.h"
 #endif
 #ifdef MOZ_B2G_BT
--- a/dom/base/nsDOMClassInfo.cpp
+++ b/dom/base/nsDOMClassInfo.cpp
@@ -538,16 +538,17 @@ using mozilla::dom::indexedDB::IDBWrappe
 #include "LockedFile.h"
 #include "GeneratedEvents.h"
 #include "mozilla/Likely.h"
 #include "nsDebug.h"
 
 #undef None // something included above defines this preprocessor symbol, maybe Xlib headers
 #include "WebGLContext.h"
 #include "nsICanvasRenderingContextInternal.h"
+#include "mozilla/dom/BindingUtils.h"
 
 using namespace mozilla;
 using namespace mozilla::dom;
 
 static NS_DEFINE_CID(kDOMSOF_CID, NS_DOM_SCRIPT_OBJECT_FACTORY_CID);
 
 static const char kDOMStringBundleURL[] =
   "chrome://global/locale/dom/dom.properties";
@@ -4570,22 +4571,23 @@ nsDOMClassInfo::Init()
   RegisterExternalClasses();
 
   sDisableDocumentAllSupport =
     Preferences::GetBool("browser.dom.document.all.disabled");
 
   sDisableGlobalScopePollutionSupport =
     Preferences::GetBool("browser.dom.global_scope_pollution.disabled");
 
-  // Proxy bindings
-  mozilla::dom::binding::Register(nameSpaceManager);
-
   // Non-proxy bindings
   mozilla::dom::Register(nameSpaceManager);
 
+  // This needs to happen after the call to mozilla::dom::Register, because we
+  // overwrite some values.
+  mozilla::dom::oldproxybindings::Register(nameSpaceManager);
+
   if (!AzureCanvasEnabled()) {
     nameSpaceManager->RegisterDefineDOMInterface(NS_LITERAL_STRING("CanvasRenderingContext2D"), NULL);
   }
 
   sIsInitialized = true;
 
   return NS_OK;
 }
@@ -6741,25 +6743,25 @@ nsWindowSH::GlobalResolve(nsGlobalWindow
     }
   }
 
   if (name_struct->mType == nsGlobalNameStruct::eTypeNewDOMBinding ||
       name_struct->mType == nsGlobalNameStruct::eTypeInterface ||
       name_struct->mType == nsGlobalNameStruct::eTypeClassProto ||
       name_struct->mType == nsGlobalNameStruct::eTypeClassConstructor) {
     // Lookup new DOM bindings.
-    mozilla::dom::binding::DefineInterface define =
+    mozilla::dom::DefineInterface define =
       name_struct->mDefineDOMInterface;
     if (define) {
       if (name_struct->mType == nsGlobalNameStruct::eTypeClassConstructor &&
           !ConstructorEnabled(name_struct, aWin)) {
         return NS_OK;
       }
 
-      if (mozilla::dom::binding::DefineConstructor(cx, obj, define, &rv)) {
+      if (mozilla::dom::DefineConstructor(cx, obj, define, &rv)) {
         *did_resolve = NS_SUCCEEDED(rv);
 
         return rv;
       }
     }
   }
 
   if (name_struct->mType == nsGlobalNameStruct::eTypeInterface) {
@@ -8786,19 +8788,19 @@ nsHTMLDocumentSH::GetDocumentAllNodeList
   // in a reserved slot (0) on the document.all JSObject.
   nsresult rv = NS_OK;
 
   jsval collection = JS_GetReservedSlot(obj, 0);
 
   if (!JSVAL_IS_PRIMITIVE(collection)) {
     // We already have a node list in our reserved slot, use it.
     JSObject *obj = JSVAL_TO_OBJECT(collection);
-    if (mozilla::dom::binding::HTMLCollection::objIsWrapper(obj)) {
+    if (mozilla::dom::oldproxybindings::HTMLCollection::objIsWrapper(obj)) {
       nsIHTMLCollection *native =
-        mozilla::dom::binding::HTMLCollection::getNative(obj);
+        mozilla::dom::oldproxybindings::HTMLCollection::getNative(obj);
       NS_ADDREF(*nodeList = static_cast<nsContentList*>(native));
     }
     else {
       nsISupports *native = sXPConnect->GetNativeOfWrapper(cx, obj);
       if (native) {
         NS_ADDREF(*nodeList = nsContentList::FromSupports(native));
       }
       else {
--- a/dom/base/nsGlobalWindow.cpp
+++ b/dom/base/nsGlobalWindow.cpp
@@ -6125,17 +6125,17 @@ PostMessageReadStructuredClone(JSContext
 
   const JSStructuredCloneCallbacks* runtimeCallbacks =
     js::GetContextStructuredCloneCallbacks(cx);
 
   if (runtimeCallbacks) {
     return runtimeCallbacks->read(cx, reader, tag, data, nullptr);
   }
 
-  return JS_FALSE;
+  return nullptr;
 }
 
 static JSBool
 PostMessageWriteStructuredClone(JSContext* cx,
                                 JSStructuredCloneWriter* writer,
                                 JSObject* obj,
                                 void *closure)
 {
--- a/dom/base/nsScriptNameSpaceManager.cpp
+++ b/dom/base/nsScriptNameSpaceManager.cpp
@@ -776,17 +776,17 @@ nsScriptNameSpaceManager::Observe(nsISup
   // and NS_XPCOM_CATEGORY_CLEARED_OBSERVER_ID but we are safe without it.
   // See bug 600460.
 
   return NS_OK;
 }
 
 void
 nsScriptNameSpaceManager::RegisterDefineDOMInterface(const nsAFlatString& aName,
-    mozilla::dom::binding::DefineInterface aDefineDOMInterface)
+    mozilla::dom::DefineInterface aDefineDOMInterface)
 {
   nsGlobalNameStruct *s = AddToHash(&mGlobalNames, &aName);
   if (s) {
     if (s->mType == nsGlobalNameStruct::eTypeNotInitialized) {
       s->mType = nsGlobalNameStruct::eTypeNewDOMBinding;
     }
     s->mDefineDOMInterface = aDefineDOMInterface;
   }
--- a/dom/base/nsScriptNameSpaceManager.h
+++ b/dom/base/nsScriptNameSpaceManager.h
@@ -62,17 +62,17 @@ struct nsGlobalNameStruct
     int32_t mDOMClassInfoID; // eTypeClassConstructor
     nsIID mIID; // eTypeInterface, eTypeClassProto
     nsExternalDOMClassInfoData* mData; // eTypeExternalClassInfo
     ConstructorAlias* mAlias; // eTypeExternalConstructorAlias
     nsCID mCID; // All other types except eTypeNewDOMBinding
   };
 
   // For new style DOM bindings.
-  mozilla::dom::binding::DefineInterface mDefineDOMInterface;
+  mozilla::dom::DefineInterface mDefineDOMInterface;
 
 private:
 
   // copy constructor
 };
 
 
 class nsIScriptContext;
@@ -134,17 +134,17 @@ public:
                              const nsIID **aInterfaces,
                              uint32_t aScriptableFlags,
                              bool aHasClassInterface,
                              const nsCID *aConstructorCID);
 
   nsGlobalNameStruct* GetConstructorProto(const nsGlobalNameStruct* aStruct);
 
   void RegisterDefineDOMInterface(const nsAFlatString& aName,
-    mozilla::dom::binding::DefineInterface aDefineDOMInterface);
+    mozilla::dom::DefineInterface aDefineDOMInterface);
 
 private:
   // Adds a new entry to the hash and returns the nsGlobalNameStruct
   // that aKey will be mapped to. If mType in the returned
   // nsGlobalNameStruct is != eTypeNotInitialized, an entry for aKey
   // already existed.
   nsGlobalNameStruct *AddToHash(PLDHashTable *aTable, const nsAString *aKey,
                                 const PRUnichar **aClassName = nullptr);
--- a/dom/bindings/BindingUtils.cpp
+++ b/dom/bindings/BindingUtils.cpp
@@ -3,16 +3,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/. */
 
 #include <stdarg.h>
 
 #include "BindingUtils.h"
 
+#include "WrapperFactory.h"
 #include "xpcprivate.h"
 #include "XPCQuickStubs.h"
 
 namespace mozilla {
 namespace dom {
 
 JSErrorFormatString ErrorFormatString[] = {
 #define MSG_DEF(_name, _argc, _str) \
@@ -237,17 +238,17 @@ CreateInterfacePrototypeObject(JSContext
 
   return ourProto;
 }
 
 JSObject*
 CreateInterfaceObjects(JSContext* cx, JSObject* global, JSObject *receiver,
                        JSObject* protoProto, JSClass* protoClass,
                        JSClass* constructorClass, JSNative constructor,
-                       unsigned ctorNargs, JSClass* instanceClass,
+                       unsigned ctorNargs, const DOMClass* domClass,
                        Prefable<JSFunctionSpec>* methods,
                        Prefable<JSPropertySpec>* properties,
                        Prefable<ConstantSpec>* constants,
                        Prefable<JSFunctionSpec>* staticMethods, const char* name)
 {
   MOZ_ASSERT(protoClass || constructorClass || constructor,
              "Need at least one class or a constructor!");
   MOZ_ASSERT(!(methods || properties) || protoClass,
@@ -262,17 +263,17 @@ CreateInterfaceObjects(JSContext* cx, JS
   if (protoClass) {
     proto = CreateInterfacePrototypeObject(cx, global, protoProto, protoClass,
                                            methods, properties, constants);
     if (!proto) {
       return NULL;
     }
 
     js::SetReservedSlot(proto, DOM_PROTO_INSTANCE_CLASS_SLOT,
-                        JS::PrivateValue(instanceClass));
+                        JS::PrivateValue(const_cast<DOMClass*>(domClass)));
   }
   else {
     proto = NULL;
   }
 
   JSObject* interface;
   if (constructorClass || constructor) {
     interface = CreateInterfaceObject(cx, global, receiver, constructorClass,
@@ -328,20 +329,18 @@ DoHandleNewBindingWrappingFailure(JSCont
 }
 
 // Can only be called with the immediate prototype of the instance object. Can
 // only be called on the prototype of an object known to be a DOM instance.
 JSBool
 InstanceClassHasProtoAtDepth(JSHandleObject protoObject, uint32_t protoID,
                              uint32_t depth)
 {
-  JSClass* instanceClass = static_cast<JSClass*>(
+  const DOMClass* domClass = static_cast<DOMClass*>(
     js::GetReservedSlot(protoObject, DOM_PROTO_INSTANCE_CLASS_SLOT).toPrivate());
-  MOZ_ASSERT(IsDOMClass(instanceClass));
-  DOMJSClass* domClass = DOMJSClass::FromJSClass(instanceClass);
   return (uint32_t)domClass->mInterfaceChain[depth] == protoID;
 }
 
 // Only set allowNativeWrapper to false if you really know you need it, if in
 // doubt use true. Setting it to false disables security wrappers.
 bool
 XPCOMObjectToJsval(JSContext* cx, JSObject* scope, xpcObjectHelper &helper,
                    const nsIID* iid, bool allowNativeWrapper, JS::Value* rval)
@@ -372,24 +371,21 @@ QueryInterface(JSContext* cx, unsigned a
 
   // Get the object. It might be a security wrapper, in which case we do a checked
   // unwrap.
   JSObject* origObj = JSVAL_TO_OBJECT(thisv);
   JSObject* obj = js::UnwrapObjectChecked(cx, origObj);
   if (!obj)
       return false;
 
-  JSClass* clasp = js::GetObjectJSClass(obj);
-  if (!IsDOMClass(clasp) ||
-      !DOMJSClass::FromJSClass(clasp)->mDOMObjectIsISupports) {
+  nsISupports* native;
+  if (!UnwrapDOMObjectToISupports(obj, native)) {
     return Throw<true>(cx, NS_ERROR_FAILURE);
   }
 
-  nsISupports* native = UnwrapDOMObject<nsISupports>(obj);
-
   if (argc < 1) {
     return Throw<true>(cx, NS_ERROR_XPC_NOT_ENOUGH_ARGS);
   }
 
   JS::Value* argv = JS_ARGV(cx, vp);
   if (!argv[0].isObject()) {
     return Throw<true>(cx, NS_ERROR_XPC_BAD_CONVERT_JS);
   }
@@ -446,18 +442,19 @@ XrayResolveProperty(JSContext* cx, JSObj
       // Set i to be the index into our full list of ids/specs that we're
       // looking at now.
       size_t i = methods[prefIdx].specs - methodSpecs;
       for ( ; methodIds[i] != JSID_VOID; ++i) {
         if (id == methodIds[i]) {
           JSFunction *fun = JS_NewFunctionById(cx, methodSpecs[i].call.op,
                                                methodSpecs[i].nargs, 0,
                                                wrapper, id);
-          if (!fun)
-              return false;
+          if (!fun) {
+            return false;
+          }
           SET_JITINFO(fun, methodSpecs[i].call.info);
           JSObject *funobj = JS_GetFunctionObject(fun);
           desc->value.setObject(*funobj);
           desc->attrs = methodSpecs[i].flags;
           desc->obj = wrapper;
           desc->setter = nullptr;
           desc->getter = nullptr;
           return true;
@@ -585,10 +582,51 @@ XrayEnumerateProperties(JS::AutoIdVector
         }
       }
     }
   }
 
   return true;
 }
 
+bool
+GetPropertyOnPrototype(JSContext* cx, JSObject* proxy, jsid id, bool* found,
+                       JS::Value* vp)
+{
+  JSObject* proto = js::GetObjectProto(proxy);
+  if (!proto) {
+    *found = false;
+    return true;
+  }
+
+  JSBool hasProp;
+  if (!JS_HasPropertyById(cx, proto, id, &hasProp)) {
+    return false;
+  }
+
+  *found = hasProp;
+  if (!hasProp || !vp) {
+    return true;
+  }
+
+  return JS_ForwardGetPropertyTo(cx, proto, id, proxy, vp);
+}
+
+bool
+HasPropertyOnPrototype(JSContext* cx, JSObject* proxy, DOMProxyHandler* handler,
+                       jsid id)
+{
+  JSAutoEnterCompartment ac;
+  if (xpc::WrapperFactory::IsXrayWrapper(proxy)) {
+    proxy = js::UnwrapObject(proxy);
+    if (!ac.enter(cx, proxy)) {
+      return false;
+    }
+  }
+  MOZ_ASSERT(js::IsProxy(proxy) && js::GetProxyHandler(proxy) == handler);
+
+  bool found;
+  // We ignore an error from GetPropertyOnPrototype.
+  return !GetPropertyOnPrototype(cx, proxy, id, &found, NULL) || found;
+}
+
 } // namespace dom
 } // namespace mozilla
--- a/dom/bindings/BindingUtils.h
+++ b/dom/bindings/BindingUtils.h
@@ -3,16 +3,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 mozilla_dom_BindingUtils_h__
 #define mozilla_dom_BindingUtils_h__
 
 #include "mozilla/dom/DOMJSClass.h"
+#include "mozilla/dom/DOMJSProxyHandler.h"
 #include "mozilla/dom/workers/Workers.h"
 #include "mozilla/ErrorResult.h"
 
 #include "jsapi.h"
 #include "jsfriendapi.h"
 #include "jswrapper.h"
 
 #include "nsIXPConnect.h"
@@ -73,72 +74,147 @@ IsDOMClass(const JSClass* clasp)
 }
 
 inline bool
 IsDOMClass(const js::Class* clasp)
 {
   return IsDOMClass(Jsvalify(clasp));
 }
 
+// It's ok for eRegularDOMObject and eProxyDOMObject to be the same, but
+// eNonDOMObject should always be different from the other two. This enum
+// shouldn't be used to differentiate between non-proxy and proxy bindings.
+enum DOMObjectSlot {
+  eNonDOMObject = -1,
+  eRegularDOMObject = DOM_OBJECT_SLOT,
+  eProxyDOMObject = DOM_PROXY_OBJECT_SLOT
+};
+
 template <class T>
 inline T*
-UnwrapDOMObject(JSObject* obj)
+UnwrapDOMObject(JSObject* obj, DOMObjectSlot slot)
 {
-  MOZ_ASSERT(IsDOMClass(JS_GetClass(obj)));
+  MOZ_ASSERT(slot != eNonDOMObject,
+             "Don't pass non-DOM objects to this function");
 
-  JS::Value val = js::GetReservedSlot(obj, DOM_OBJECT_SLOT);
+#ifdef DEBUG
+  if (IsDOMClass(js::GetObjectClass(obj))) {
+    MOZ_ASSERT(slot == eRegularDOMObject);
+  } else {
+    MOZ_ASSERT(js::IsObjectProxyClass(js::GetObjectClass(obj)) ||
+               js::IsFunctionProxyClass(js::GetObjectClass(obj)));
+    MOZ_ASSERT(js::GetProxyHandler(obj)->family() == ProxyFamily());
+    MOZ_ASSERT(slot == eProxyDOMObject);
+  }
+#endif
+
+  JS::Value val = js::GetReservedSlot(obj, slot);
   // XXXbz/khuey worker code tries to unwrap interface objects (which have
   // nothing here).  That needs to stop.
   // XXX We don't null-check UnwrapObject's result; aren't we going to crash
   // anyway?
   if (val.isUndefined()) {
     return NULL;
   }
   
   return static_cast<T*>(val.toPrivate());
 }
 
+// Only use this with a new DOM binding object (either proxy or regular).
+inline const DOMClass*
+GetDOMClass(JSObject* obj)
+{
+  js::Class* clasp = js::GetObjectClass(obj);
+  if (IsDOMClass(clasp)) {
+    return &DOMJSClass::FromJSClass(clasp)->mClass;
+  }
+
+  js::BaseProxyHandler* handler = js::GetProxyHandler(obj);
+  MOZ_ASSERT(handler->family() == ProxyFamily());
+  return &static_cast<DOMProxyHandler*>(handler)->mClass;
+}
+
+inline DOMObjectSlot
+GetDOMClass(JSObject* obj, const DOMClass*& result)
+{
+  js::Class* clasp = js::GetObjectClass(obj);
+  if (IsDOMClass(clasp)) {
+    result = &DOMJSClass::FromJSClass(clasp)->mClass;
+    return eRegularDOMObject;
+  }
+
+  if (js::IsObjectProxyClass(clasp) || js::IsFunctionProxyClass(clasp)) {
+    js::BaseProxyHandler* handler = js::GetProxyHandler(obj);
+    if (handler->family() == ProxyFamily()) {
+      result = &static_cast<DOMProxyHandler*>(handler)->mClass;
+      return eProxyDOMObject;
+    }
+  }
+
+  return eNonDOMObject;
+}
+
+inline bool
+UnwrapDOMObjectToISupports(JSObject* obj, nsISupports*& result)
+{
+  const DOMClass* clasp;
+  DOMObjectSlot slot = GetDOMClass(obj, clasp);
+  if (slot == eNonDOMObject || !clasp->mDOMObjectIsISupports) {
+    return false;
+  }
+ 
+  result = UnwrapDOMObject<nsISupports>(obj, slot);
+  return true;
+}
+
+inline bool
+IsDOMObject(JSObject* obj)
+{
+  js::Class* clasp = js::GetObjectClass(obj);
+  return IsDOMClass(clasp) ||
+         ((js::IsObjectProxyClass(clasp) || js::IsFunctionProxyClass(clasp)) &&
+          js::GetProxyHandler(obj)->family() == ProxyFamily());
+}
+
 // Some callers don't want to set an exception when unwrappin fails
 // (for example, overload resolution uses unwrapping to tell what sort
 // of thing it's looking at).
 // U must be something that a T* can be assigned to (e.g. T* or an nsRefPtr<T>).
 template <prototypes::ID PrototypeID, class T, typename U>
 inline nsresult
 UnwrapObject(JSContext* cx, JSObject* obj, U& value)
 {
   /* First check to see whether we have a DOM object */
-  JSClass* clasp = js::GetObjectJSClass(obj);
-  if (!IsDOMClass(clasp)) {
+  const DOMClass* domClass;
+  DOMObjectSlot slot = GetDOMClass(obj, domClass);
+  if (slot == eNonDOMObject) {
     /* Maybe we have a security wrapper or outer window? */
     if (!js::IsWrapper(obj)) {
       /* Not a DOM object, not a wrapper, just bail */
       return NS_ERROR_XPC_BAD_CONVERT_JS;
     }
 
     obj = xpc::Unwrap(cx, obj, false);
     if (!obj) {
       return NS_ERROR_XPC_SECURITY_MANAGER_VETO;
     }
     MOZ_ASSERT(!js::IsWrapper(obj));
-    clasp = js::GetObjectJSClass(obj);
-    if (!IsDOMClass(clasp)) {
+    slot = GetDOMClass(obj, domClass);
+    if (slot == eNonDOMObject) {
       /* We don't have a DOM object */
       return NS_ERROR_XPC_BAD_CONVERT_JS;
     }
   }
 
-  MOZ_ASSERT(IsDOMClass(clasp));
-
   /* This object is a DOM object.  Double-check that it is safely
      castable to T by checking whether it claims to inherit from the
      class identified by protoID. */
-  DOMJSClass* domClass = DOMJSClass::FromJSClass(clasp);
   if (domClass->mInterfaceChain[PrototypeTraits<PrototypeID>::Depth] ==
       PrototypeID) {
-    value = UnwrapDOMObject<T>(obj);
+    value = UnwrapDOMObject<T>(obj, slot);
     return NS_OK;
   }
 
   /* It's the wrong sort of DOM object */
   return NS_ERROR_XPC_BAD_CONVERT_JS;
 }
 
 inline bool
@@ -304,17 +380,17 @@ struct Prefable {
  *
  * returns the interface prototype object if protoClass is non-null, else it
  * returns the interface object.
  */
 JSObject*
 CreateInterfaceObjects(JSContext* cx, JSObject* global, JSObject* receiver,
                        JSObject* protoProto, JSClass* protoClass,
                        JSClass* constructorClass, JSNative constructor,
-                       unsigned ctorNargs, JSClass* instanceClass,
+                       unsigned ctorNargs, const DOMClass* domClass,
                        Prefable<JSFunctionSpec>* methods,
                        Prefable<JSPropertySpec>* properties,
                        Prefable<ConstantSpec>* constants,
                        Prefable<JSFunctionSpec>* staticMethods, const char* name);
 
 template <class T>
 inline bool
 WrapNewBindingObject(JSContext* cx, JSObject* scope, T* value, JS::Value* vp)
@@ -550,16 +626,32 @@ GetParentPointer(T* aObject)
 }
 
 inline nsISupports*
 GetParentPointer(const ParentObject& aObject)
 {
   return ToSupports(aObject.mObject);
 }
 
+template<class T>
+inline void
+ClearWrapper(T* p, nsWrapperCache* cache)
+{
+  cache->ClearWrapper();
+}
+
+template<class T>
+inline void
+ClearWrapper(T* p, void*)
+{
+  nsWrapperCache* cache;
+  CallQueryInterface(p, &cache);
+  ClearWrapper(p, cache);
+}
+
 // Can only be called with the immediate prototype of the instance object. Can
 // only be called on the prototype of an object known to be a DOM instance.
 JSBool
 InstanceClassHasProtoAtDepth(JSHandleObject protoObject, uint32_t protoID,
                              uint32_t depth);
 
 // Only set allowNativeWrapper to false if you really know you need it, if in
 // doubt use true. Setting it to false disables security wrappers.
@@ -695,16 +787,24 @@ InitIds(JSContext* cx, Prefable<Spec>* p
   return true;
 }
 
 JSBool
 QueryInterface(JSContext* cx, unsigned argc, JS::Value* vp);
 JSBool
 ThrowingConstructor(JSContext* cx, unsigned argc, JS::Value* vp);
 
+bool
+GetPropertyOnPrototype(JSContext* cx, JSObject* proxy, jsid id, bool* found,
+                       JS::Value* vp);
+
+bool
+HasPropertyOnPrototype(JSContext* cx, JSObject* proxy, DOMProxyHandler* handler,
+                       jsid id);
+
 template<class T>
 class NonNull
 {
 public:
   NonNull()
 #ifdef DEBUG
     : inited(false)
 #endif
--- a/dom/bindings/Bindings.conf
+++ b/dom/bindings/Bindings.conf
@@ -296,16 +296,62 @@ DOMInterfaces = {
         },
 
 'OnlyForUseInConstructor' : {
         'nativeType': 'mozilla::dom::OnlyForUseInConstructor',
         'headerFile': 'TestBindingHeader.h',
         'register': False
         },
 
+
+'TestIndexedGetterInterface' : {
+        'nativeType': 'mozilla::dom::TestIndexedGetterInterface',
+        'headerFile': 'TestBindingHeader.h',
+        'register': False,
+        'infallible': [ 'length' ]
+        },
+
+'TestNamedGetterInterface' : {
+        'nativeType': 'mozilla::dom::TestNamedGetterInterface',
+        'headerFile': 'TestBindingHeader.h',
+        'register': False
+        },
+
+'TestIndexedAndNamedGetterInterface' : {
+        'nativeType': 'mozilla::dom::TestIndexedAndNamedGetterInterface',
+        'headerFile': 'TestBindingHeader.h',
+        'register': False,
+        'infallible': [ 'length' ]
+        },
+
+'TestIndexedSetterInterface' : {
+        'nativeType': 'mozilla::dom::TestIndexedSetterInterface',
+        'headerFile': 'TestBindingHeader.h',
+        'register': False
+        },
+
+'TestNamedSetterInterface' : {
+        'nativeType': 'mozilla::dom::TestNamedSetterInterface',
+        'headerFile': 'TestBindingHeader.h',
+        'register': False
+        },
+
+'TestIndexedAndNamedSetterInterface' : {
+        'nativeType': 'mozilla::dom::TestIndexedAndNamedSetterInterface',
+        'headerFile': 'TestBindingHeader.h',
+        'register': False
+        },
+
+'TestIndexedAndNamedGetterAndSetterInterface' : {
+        'nativeType': 'mozilla::dom::TestIndexedAndNamedGetterAndSetterInterface',
+        'headerFile': 'TestBindingHeader.h',
+        'register': False,
+        'infallible': [ 'length', '__stringifier' ],
+        'binaryNames': { '__stringifier': 'Stringify' }
+        },
 }
 
 # These are temporary, until they've been converted to use new DOM bindings
 def addExternalIface(iface, nativeType=None, headerFile=None):
     if nativeType is None:
         nativeType = 'nsIDOM' + iface
     domInterface = {
         'nativeType': nativeType,
--- a/dom/bindings/Codegen.py
+++ b/dom/bindings/Codegen.py
@@ -63,47 +63,53 @@ class CGNativePropertyHooks(CGThing):
     Generate a NativePropertyHooks for a given descriptor
     """
     def __init__(self, descriptor):
         CGThing.__init__(self)
         self.descriptor = descriptor
     def declare(self):
         if self.descriptor.workers:
             return ""
-        return "  extern const NativePropertyHooks NativeHooks;\n"
+        return "extern const NativePropertyHooks NativeHooks;\n"
     def define(self):
         if self.descriptor.workers:
             return ""
         parent = self.descriptor.interface.parent
         parentHooks = ("&" + toBindingNamespace(parent.identifier.name) + "::NativeHooks"
                        if parent else 'NULL')
         return """
 const NativePropertyHooks NativeHooks = { ResolveProperty, EnumerateProperties, %s };
 """ % parentHooks
 
+def DOMClass(descriptor):
+        protoList = ['prototypes::id::' + proto for proto in descriptor.prototypeChain]
+        # Pad out the list to the right length with _ID_Count so we
+        # guarantee that all the lists are the same length.  _ID_Count
+        # is never the ID of any prototype, so it's safe to use as
+        # padding.
+        protoList.extend(['prototypes::id::_ID_Count'] * (descriptor.config.maxProtoChainLength - len(protoList)))
+        prototypeChainString = ', '.join(protoList)
+        nativeHooks = "NULL" if descriptor.workers else "&NativeHooks"
+        return """{
+  { %s },
+  %s, %s
+}""" % (prototypeChainString, toStringBool(descriptor.nativeIsISupports),
+          nativeHooks)
+
 class CGDOMJSClass(CGThing):
     """
     Generate a DOMJSClass for a given descriptor
     """
     def __init__(self, descriptor):
         CGThing.__init__(self)
         self.descriptor = descriptor
     def declare(self):
-        return "  extern DOMJSClass Class;\n"
+        return "extern DOMJSClass Class;\n"
     def define(self):
         traceHook = TRACE_HOOK_NAME if self.descriptor.customTrace else 'NULL'
-        protoList = ['prototypes::id::' + proto for proto in self.descriptor.prototypeChain]
-        # Pad out the list to the right length with _ID_Count so we
-        # guarantee that all the lists are the same length.  _ID_Count
-        # is never the ID of any prototype, so it's safe to use as
-        # padding.
-        while len(protoList) < self.descriptor.config.maxProtoChainLength:
-            protoList.append('prototypes::id::_ID_Count')
-        prototypeChainString = ', '.join(protoList)
-        nativeHooks = "NULL" if self.descriptor.workers else "&NativeHooks"
         return """
 DOMJSClass Class = {
   { "%s",
     JSCLASS_IS_DOMJSCLASS | JSCLASS_HAS_RESERVED_SLOTS(1),
     %s, /* addProperty */
     JS_PropertyStub,       /* delProperty */
     JS_PropertyStub,       /* getProperty */
     JS_StrictPropertyStub, /* setProperty */
@@ -113,36 +119,33 @@ DOMJSClass Class = {
     %s, /* finalize */
     NULL,                  /* checkAccess */
     NULL,                  /* call */
     NULL,                  /* hasInstance */
     NULL,                  /* construct */
     %s, /* trace */
     JSCLASS_NO_INTERNAL_MEMBERS
   },
-  { %s },
-  -1, %s,
-  %s
+  %s,
+  -1
 };
 """ % (self.descriptor.interface.identifier.name,
        ADDPROPERTY_HOOK_NAME if self.descriptor.concrete and not self.descriptor.workers and self.descriptor.wrapperCache else 'JS_PropertyStub',
-       FINALIZE_HOOK_NAME, traceHook, prototypeChainString,
-       str(self.descriptor.nativeIsISupports).lower(),
-       nativeHooks)
+       FINALIZE_HOOK_NAME, traceHook,
+       CGIndenter(CGGeneric(DOMClass(self.descriptor))).define())
 
 class CGPrototypeJSClass(CGThing):
     def __init__(self, descriptor):
         CGThing.__init__(self)
         self.descriptor = descriptor
     def declare(self):
         # We're purely for internal consumption
         return ""
     def define(self):
-        return """
-static JSClass PrototypeClass = {
+        return """static JSClass PrototypeClass = {
   "%sPrototype",
   JSCLASS_HAS_RESERVED_SLOTS(1),
   JS_PropertyStub,       /* addProperty */
   JS_PropertyStub,       /* delProperty */
   JS_PropertyStub,       /* getProperty */
   JS_StrictPropertyStub, /* setProperty */
   JS_EnumerateStub,
   JS_ResolveStub,
@@ -197,22 +200,22 @@ class CGList(CGThing):
     def __init__(self, children, joiner=""):
         CGThing.__init__(self)
         self.children = children
         self.joiner = joiner
     def append(self, child):
         self.children.append(child)
     def prepend(self, child):
         self.children.insert(0, child)
+    def join(self, generator):
+        return self.joiner.join(filter(lambda s: len(s) > 0, (child for child in generator)))
     def declare(self):
-        return self.joiner.join([child.declare() for child in self.children
-                                 if child is not None])
+        return self.join(child.declare() for child in self.children if child is not None)
     def define(self):
-        return self.joiner.join([child.define() for child in self.children
-                                 if child is not None])
+        return self.join(child.define() for child in self.children if child is not None)
 
 class CGGeneric(CGThing):
     """
     A class that spits out a fixed string into the codegen.  Can spit out a
     separate string for the declaration too.
     """
     def __init__(self, define="", declare=""):
         self.declareText = declare
@@ -226,32 +229,33 @@ class CGGeneric(CGThing):
 # don't want to indent empty lines.  So only indent lines that have a
 # non-newline character on them.
 lineStartDetector = re.compile("^(?=[^\n#])", re.MULTILINE)
 class CGIndenter(CGThing):
     """
     A class that takes another CGThing and generates code that indents that
     CGThing by some number of spaces.  The default indent is two spaces.
     """
-    def __init__(self, child, indentLevel=2):
+    def __init__(self, child, indentLevel=2, declareOnly=False):
         CGThing.__init__(self)
         self.child = child
         self.indent = " " * indentLevel
+        self.declareOnly = declareOnly
     def declare(self):
         decl = self.child.declare()
         if decl is not "":
             return re.sub(lineStartDetector, self.indent, decl)
         else:
             return ""
     def define(self):
         defn = self.child.define()
-        if defn is not "":
+        if defn is not "" and not self.declareOnly:
             return re.sub(lineStartDetector, self.indent, defn)
         else:
-            return ""
+            return defn
 
 class CGWrapper(CGThing):
     """
     Generic CGThing that wraps other CGThings with pre and post text.
     """
     def __init__(self, child, pre="", post="", declarePre=None,
                  declarePost=None, definePre=None, definePost=None,
                  declareOnly=False, defineOnly=False, reindent=False):
@@ -280,16 +284,23 @@ class CGWrapper(CGThing):
         defn = self.child.define()
         if self.reindent:
             # We don't use lineStartDetector because we don't want to
             # insert whitespace at the beginning of our _first_ line.
             defn = stripTrailingWhitespace(
                 defn.replace("\n", "\n" + (" " * len(self.definePre))))
         return self.definePre + defn + self.definePost
 
+class CGIfWrapper(CGWrapper):
+    def __init__(self, child, condition):
+        pre = CGWrapper(CGGeneric(condition), pre="if (", post=") {\n",
+                        reindent=True)
+        CGWrapper.__init__(self, CGIndenter(child), pre=pre.define(),
+                           post="\n}")
+
 class CGNamespace(CGWrapper):
     def __init__(self, namespace, child, declareOnly=False):
         pre = "namespace %s {\n" % namespace
         post = "} // namespace %s\n" % namespace
         CGWrapper.__init__(self, child, pre=pre, post=post,
                            declareOnly=declareOnly)
     @staticmethod
     def build(namespaces, child, declareOnly=False):
@@ -514,49 +525,64 @@ class CGAbstractMethod(CGThing):
 
     returnType is the IDLType of the return value
 
     args is a list of Argument objects
 
     inline should be True to generate an inline method, whose body is
     part of the declaration.
 
+    alwaysInline should be True to generate an inline method annotated with
+    MOZ_ALWAYS_INLINE.
+
     static should be True to generate a static method, which only has
     a definition.
+
+    If templateArgs is not None it should be a list of strings containing
+    template arguments, and the function will be templatized using those
+    arguments.
     """
-    def __init__(self, descriptor, name, returnType, args, inline=False, static=False):
+    def __init__(self, descriptor, name, returnType, args, inline=False, alwaysInline=False, static=False, templateArgs=None):
         CGThing.__init__(self)
         self.descriptor = descriptor
         self.name = name
         self.returnType = returnType
         self.args = args
         self.inline = inline
+        self.alwaysInline = alwaysInline
         self.static = static
+        self.templateArgs = templateArgs
     def _argstring(self):
         return ', '.join([str(a) for a in self.args])
+    def _template(self):
+        if self.templateArgs is None:
+            return ''
+        return 'template <%s>\n' % ', '.join(self.templateArgs)
     def _decorators(self):
         decorators = []
-        if self.inline:
+        if self.alwaysInline:
+            decorators.append('MOZ_ALWAYS_INLINE')
+        elif self.inline:
             decorators.append('inline')
         if self.static:
             decorators.append('static')
         decorators.append(self.returnType)
-        return ' '.join(decorators)
+        maybeNewline = " " if self.inline else "\n"
+        return ' '.join(decorators) + maybeNewline
     def declare(self):
         if self.inline:
             return self._define()
-        return "\n  %s %s(%s);\n" % (self._decorators(), self.name, self._argstring())
+        return "%s%s%s(%s);\n" % (self._template(), self._decorators(), self.name, self._argstring())
     def _define(self):
         return self.definition_prologue() + "\n" + self.definition_body() + self.definition_epilogue()
     def define(self):
         return "" if self.inline else self._define()
     def definition_prologue(self):
-        maybeNewline = " " if self.inline else "\n"
-        return "\n%s%s%s(%s)\n{" % (self._decorators(), maybeNewline,
-                                    self.name, self._argstring())
+        return "%s%s%s(%s)\n{" % (self._template(), self._decorators(),
+                                  self.name, self._argstring())
     def definition_epilogue(self):
         return "\n}\n"
     def definition_body(self):
         assert(False) # Override me!
 
 class CGAbstractStaticMethod(CGAbstractMethod):
     """
     Abstract base class for codegen of implementation-only (no
@@ -575,17 +601,17 @@ class CGAbstractClassHook(CGAbstractStat
     'this' unwrapping as it assumes that the unwrapped type is always known.
     """
     def __init__(self, descriptor, name, returnType, args):
         CGAbstractStaticMethod.__init__(self, descriptor, name, returnType,
                                         args)
 
     def definition_body_prologue(self):
         return """
-  %s* self = UnwrapDOMObject<%s>(obj);
+  %s* self = UnwrapDOMObject<%s>(obj, eRegularDOMObject);
 """ % (self.descriptor.nativeType, self.descriptor.nativeType)
 
     def definition_body(self):
         return self.definition_body_prologue() + self.generate_code()
 
     def generate_code(self):
         # Override me
         assert(False)
@@ -603,43 +629,45 @@ class CGAddPropertyHook(CGAbstractClassH
     def generate_code(self):
         # FIXME https://bugzilla.mozilla.org/show_bug.cgi?id=774279
         # Using a real trace hook might enable us to deal with non-nsISupports
         # wrappercached things here.
         assert self.descriptor.nativeIsISupports
         return """  nsContentUtils::PreserveWrapper(reinterpret_cast<nsISupports*>(self), self);
   return true;"""
 
+def finalizeHook(descriptor, hookName, context):
+    if descriptor.customFinalize:
+        return """if (self) {
+  self->%s(%s);
+}""" % (hookName, context)
+    clearWrapper = "ClearWrapper(self, self);\n" if descriptor.wrapperCache else ""
+    if descriptor.workers:
+        release = "self->Release();"
+    else:
+        assert descriptor.nativeIsISupports
+        release = """XPCJSRuntime *rt = nsXPConnect::GetRuntimeInstance();
+if (rt) {
+  rt->DeferredRelease(reinterpret_cast<nsISupports*>(self));
+} else {
+  NS_RELEASE(self);
+}"""
+    return clearWrapper + release
+
 class CGClassFinalizeHook(CGAbstractClassHook):
     """
     A hook for finalize, used to release our native object.
     """
     def __init__(self, descriptor):
         args = [Argument('JSFreeOp*', 'fop'), Argument('JSObject*', 'obj')]
         CGAbstractClassHook.__init__(self, descriptor, FINALIZE_HOOK_NAME,
                                      'void', args)
 
     def generate_code(self):
-        if self.descriptor.customFinalize:
-            return """  if (self) {
-    self->%s(%s);
-  }""" % (self.name, self.args[0].name)
-        clearWrapper = "self->ClearWrapper();\n  " if self.descriptor.wrapperCache else ""
-        if self.descriptor.workers:
-            release = "self->Release();"
-        else:
-            assert self.descriptor.nativeIsISupports
-            release = """XPCJSRuntime *rt = nsXPConnect::GetRuntimeInstance();
-  if (rt) {
-    rt->DeferredRelease(reinterpret_cast<nsISupports*>(self));
-  } else {
-    NS_RELEASE(self);
-  }"""
-        return """
-  %s%s""" % (clearWrapper, release)
+        return CGIndenter(CGGeneric(finalizeHook(self.descriptor, self.name, self.args[0].name))).define()
 
 class CGClassTraceHook(CGAbstractClassHook):
     """
     A hook to trace through our native object; used for GC and CC
     """
     def __init__(self, descriptor):
         args = [Argument('JSTracer*', 'trc'), Argument('JSObject*', 'obj')]
         CGAbstractClassHook.__init__(self, descriptor, TRACE_HOOK_NAME, 'void',
@@ -889,34 +917,56 @@ def methodLength(method):
 
 class MethodDefiner(PropertyDefiner):
     """
     A class for defining methods on a prototype object.
     """
     def __init__(self, descriptor, name, static):
         PropertyDefiner.__init__(self, descriptor, name)
 
+        # FIXME https://bugzilla.mozilla.org/show_bug.cgi?id=772822
+        #       We should be able to check for special operations without an
+        #       identifier. For now we check if the name starts with __
         methods = [m for m in descriptor.interface.members if
-                   m.isMethod() and m.isStatic() == static]
+                   m.isMethod() and m.isStatic() == static and
+                   not m.isIdentifierLess()]
         self.chrome = [{"name": m.identifier.name,
                         "length": methodLength(m),
                         "flags": "JSPROP_ENUMERATE",
                         "pref": PropertyDefiner.getControllingPref(m) }
                        for m in methods]
         self.regular = [{"name": m.identifier.name,
                          "length": methodLength(m),
                          "flags": "JSPROP_ENUMERATE",
                          "pref": PropertyDefiner.getControllingPref(m) }
                         for m in methods if not isChromeOnly(m)]
+
+        # FIXME Check for an existing iterator on the interface first.
+        if any(m.isGetter() and m.isIndexed() for m in methods):
+            self.chrome.append({"name": 'iterator',
+                                "methodInfo": False,
+                                "nativeName": "JS_ArrayIterator",
+                                "length": 0,
+                                "flags": "JSPROP_ENUMERATE",
+                                "pref": None })
+            self.regular.append({"name": 'iterator',
+                                 "methodInfo": False,
+                                 "nativeName": "JS_ArrayIterator",
+                                 "length": 0,
+                                 "flags": "JSPROP_ENUMERATE",
+                                 "pref": None })
+
         if not descriptor.interface.parent and not static and not descriptor.workers:
             self.chrome.append({"name": 'QueryInterface',
+                                "methodInfo": False,
                                 "length": 1,
                                 "flags": "0",
                                 "pref": None })
             self.regular.append({"name": 'QueryInterface',
+                                 "methodInfo": False,
                                  "length": 1,
                                  "flags": "0",
                                  "pref": None })
 
         if static:
             if not descriptor.interface.hasInterfaceObject():
                 # static methods go on the interface object
                 assert not self.hasChromeOnly() and not self.hasNonChromeOnly()
@@ -928,19 +978,22 @@ class MethodDefiner(PropertyDefiner):
     def generateArray(self, array, name, doIdArrays):
         if len(array) == 0:
             return ""
 
         def pref(m):
             return m["pref"]
 
         def specData(m):
-            isQI = (m["name"] == 'QueryInterface')
-            jitinfo = ("&%s_methodinfo" % m["name"]) if not isQI else "NULL"
-            accessor = "genericMethod" if not isQI else "QueryInterface"
+            if m.get("methodInfo", True):
+                jitinfo = ("&%s_methodinfo" % m["name"])
+                accessor = "genericMethod"
+            else:
+                jitinfo = "nullptr"
+                accessor = m.get("nativeName", m["name"])
             return (m["name"], accessor, jitinfo, m["length"], m["flags"])
 
         return self.generatePrefableArray(
             array, name,
             '  JS_FNINFO("%s", %s, %s, %s, %s)',
             '  JS_FS_END',
             'JSFunctionSpec',
             pref, specData, doIdArrays)
@@ -1101,58 +1154,66 @@ class CGCreateInterfaceObjectsMethod(CGA
             prefCache = CGWrapper(CGIndenter(CGList(prefCacheData, "\n")),
                                   pre=("static bool sPrefCachesInited = false;\n"
                                        "if (!sPrefCachesInited) {\n"
                                        "  sPrefCachesInited = true;\n"),
                                   post="\n}")
         else:
             prefCache = None
             
-        getParentProto = ("JSObject* parentProto = %s;\n"
-                          "if (!parentProto) {\n"
-                          "  return NULL;\n"
-                          "}") % getParentProto
+        getParentProto = ("JSObject* parentProto = %s;\n" +
+                          "if (!parentProto) {\n" +
+                          "  return NULL;\n" +
+                          "}\n") % getParentProto
 
         needInterfaceObjectClass = (needInterfaceObject and
                                     self.descriptor.hasInstanceInterface)
         needConstructor = (needInterfaceObject and
                            not self.descriptor.hasInstanceInterface)
         if self.descriptor.interface.ctor():
             constructHook = CONSTRUCT_HOOK_NAME
             constructArgs = methodLength(self.descriptor.interface.ctor())
         else:
             constructHook = "ThrowingConstructor"
             constructArgs = 0
 
-        call = CGGeneric(("return dom::CreateInterfaceObjects(aCx, aGlobal, aReceiver, parentProto,\n"
-                          "                                   %s, %s, %s, %d,\n"
-                          "                                   %s,\n"
-                          "                                   %%(methods)s, %%(attrs)s, %%(consts)s, %%(staticMethods)s,\n"
-                          "                                   %s);") % (
+        if self.descriptor.concrete:
+            if self.descriptor.proxy:
+                domClass = "&Class"
+            else:
+                domClass = "&Class.mClass"
+        else:
+            domClass = "nullptr"
+
+        call = """return dom::CreateInterfaceObjects(aCx, aGlobal, aReceiver, parentProto,
+                                   %s, %s, %s, %d,
+                                   %s,
+                                   %%(methods)s, %%(attrs)s,
+                                   %%(consts)s, %%(staticMethods)s,
+                                   %s);""" % (
             "&PrototypeClass" if needInterfacePrototypeObject else "NULL",
             "&InterfaceObjectClass" if needInterfaceObjectClass else "NULL",
             constructHook if needConstructor else "NULL",
             constructArgs,
-            "&Class.mBase" if self.descriptor.concrete else "NULL",
-            '"' + self.descriptor.interface.identifier.name + '"' if needInterfaceObject else "NULL"))
-
+            domClass,
+            '"' + self.descriptor.interface.identifier.name + '"' if needInterfaceObject else "NULL")
         if self.properties.hasChromeOnly():
             if self.descriptor.workers:
                 accessCheck = "mozilla::dom::workers::GetWorkerPrivateFromContext(aCx)->IsChromeWorker()"
             else:
                 accessCheck = "xpc::AccessCheck::isChrome(js::GetObjectCompartment(aGlobal))"
-            accessCheck = "if (" + accessCheck + ") {\n"
-            chrome = CGWrapper(CGGeneric((CGIndenter(call).define() % self.properties.variableNames(True))),
-                               pre=accessCheck, post="\n}")
+            chrome = CGIfWrapper(CGGeneric(call % self.properties.variableNames(True)),
+                                 accessCheck)
+            chrome = CGWrapper(chrome, pre="\n\n")
         else:
             chrome = None
 
         functionBody = CGList(
             [CGGeneric(getParentProto), initIds, prefCache, chrome,
-             CGGeneric(call.define() % self.properties.variableNames(False))],
+             CGGeneric(call % self.properties.variableNames(False))],
             "\n\n")
         return CGIndenter(functionBody).define()
 
 class CGGetPerInterfaceObject(CGAbstractMethod):
     """
     A method for getting a per-interface object (a prototype object or interface
     constructor object).
     """
@@ -1267,33 +1328,58 @@ class CGDefineDOMInterfaceMethod(CGAbstr
             getter = "GetConstructorObject"
 
         return ("  JSObject* global = JS_GetGlobalForObject(aCx, aReceiver);\n" +
                 CheckPref(self.descriptor, "global", "*aEnabled", "false") + 
                 """
   *aEnabled = true;
   return !!%s(aCx, global, aReceiver);""" % (getter))
 
-class CGWrapMethod(CGAbstractMethod):
+class CGIsMethod(CGAbstractMethod):
     def __init__(self, descriptor):
-        # XXX can we wrap if we don't have an interface prototype object?
+        args = [Argument('JSObject*', 'obj')]
+        CGAbstractMethod.__init__(self, descriptor, 'Is', 'bool', args)
+
+    def definition_body(self):
+        # Non-proxy implementation would check
+        #   js::GetObjectJSClass(obj) == &Class.mBase
+        return """  return IsProxy(obj);"""
+
+class CGWrapWithCacheMethod(CGAbstractMethod):
+    def __init__(self, descriptor):
         assert descriptor.interface.hasInterfacePrototypeObject()
         args = [Argument('JSContext*', 'aCx'), Argument('JSObject*', 'aScope'),
                 Argument(descriptor.nativeType + '*', 'aObject'),
+                Argument('nsWrapperCache*', 'aCache'),
                 Argument('bool*', 'aTriedToWrap')]
         CGAbstractMethod.__init__(self, descriptor, 'Wrap', 'JSObject*', args)
 
     def definition_body(self):
         if self.descriptor.workers:
-            return """
-  *aTriedToWrap = true;
+            return """  *aTriedToWrap = true;
   return aObject->GetJSObject();"""
 
-        return """
-  *aTriedToWrap = true;
+        if self.descriptor.proxy:
+            create = """  JSObject *obj = NewProxyObject(aCx, &DOMProxyHandler::instance,
+                                 JS::PrivateValue(aObject), proto, parent);
+  if (!obj) {
+    return NULL;
+  }
+
+"""
+        else:
+            create = """  JSObject* obj = JS_NewObject(aCx, &Class.mBase, proto, parent);
+  if (!obj) {
+    return NULL;
+  }
+
+  js::SetReservedSlot(obj, DOM_OBJECT_SLOT, PRIVATE_TO_JSVAL(aObject));
+"""
+
+        return """  *aTriedToWrap = true;
 
   JSObject* parent = WrapNativeParent(aCx, aScope, aObject->GetParentObject());
   if (!parent) {
     return NULL;
   }
 
   JSAutoEnterCompartment ac;
   if (js::GetGlobalForObjectCrossCompartment(parent) != aScope) {
@@ -1304,27 +1390,33 @@ class CGWrapMethod(CGAbstractMethod):
 
   JSObject* global = JS_GetGlobalForObject(aCx, parent);
 %s
   JSObject* proto = GetProtoObject(aCx, global, global);
   if (!proto) {
     return NULL;
   }
 
-  JSObject* obj = JS_NewObject(aCx, &Class.mBase, proto, parent);
-  if (!obj) {
-    return NULL;
-  }
-
-  js::SetReservedSlot(obj, DOM_OBJECT_SLOT, PRIVATE_TO_JSVAL(aObject));
+%s
   NS_ADDREF(aObject);
 
-  aObject->SetWrapper(obj);
-
-  return obj;""" % (CheckPref(self.descriptor, "global", "*aTriedToWrap", "NULL", "aObject"))
+  aCache->SetWrapper(obj);
+
+  return obj;""" % (CheckPref(self.descriptor, "global", "*aTriedToWrap", "NULL", "aCache"), create)
+
+class CGWrapMethod(CGAbstractMethod):
+    def __init__(self, descriptor):
+        # XXX can we wrap if we don't have an interface prototype object?
+        assert descriptor.interface.hasInterfacePrototypeObject()
+        args = [Argument('JSContext*', 'aCx'), Argument('JSObject*', 'aScope'),
+                Argument('T*', 'aObject'), Argument('bool*', 'aTriedToWrap')]
+        CGAbstractMethod.__init__(self, descriptor, 'Wrap', 'JSObject*', args, inline=True, templateArgs=["class T"])
+
+    def definition_body(self):
+        return "  return Wrap(aCx, aScope, aObject, aObject, aTriedToWrap);"
 
 class CGWrapNonWrapperCacheMethod(CGAbstractMethod):
     def __init__(self, descriptor):
         # XXX can we wrap if we don't have an interface prototype object?
         assert descriptor.interface.hasInterfacePrototypeObject()
         args = [Argument('JSContext*', 'aCx'), Argument('JSObject*', 'aScope'),
                 Argument(descriptor.nativeType + '*', 'aObject')]
         CGAbstractMethod.__init__(self, descriptor, 'Wrap', 'JSObject*', args)
@@ -2200,17 +2292,17 @@ for (uint32_t i = 0; i < length; ++i) {
 
         template = ("if (!%s.Init(cx, %s)) {\n"
                     "  return false;\n"
                     "}" % (selfRef, val))
 
         return (template, declType, None, False)
 
     if not type.isPrimitive():
-        raise TypeError("Need conversion for argument type '%s'" % type)
+        raise TypeError("Need conversion for argument type '%s'" % str(type))
 
     # XXXbz need to add support for [EnforceRange] and [Clamp]
     typeName = builtinNames[type.tag()]
     if type.nullable():
         dataLoc = "${declName}.SetValue()"
         nullCondition = "${val}.isNullOrUndefined()"
         if defaultValue is not None and isinstance(defaultValue, IDLNullValue):
             nullCondition = "!(${haveValue}) || " + nullCondition
@@ -2653,131 +2745,132 @@ def infallibleForAttr(attr, descriptorPr
                                   memberIsCreator(attr))[1]
 
 def typeNeedsCx(type):
     return (type is not None and
             (type.isCallback() or type.isAny() or type.isObject() or
              (type.isUnion() and
               any(typeNeedsCx(t) for t in type.unroll().flatMemberTypes))))
 
-# Returns a CGThing containing the type of the return value, or None
-# if there is no need for a return value.
+# Returns a tuple consisting of a CGThing containing the type of the return
+# value, or None if there is no need for a return value, and a boolean signaling
+# whether the return value is passed in an out parameter.
 def getRetvalDeclarationForType(returnType, descriptorProvider,
                                 resultAlreadyAddRefed):
     if returnType is None or returnType.isVoid():
         # Nothing to declare
-        return None
+        return None, False
     if returnType.isPrimitive() and returnType.tag() in builtinNames:
         result = CGGeneric(builtinNames[returnType.tag()])
         if returnType.nullable():
             result = CGWrapper(result, pre="Nullable<", post=">")
-        return result
+        return result, False
     if returnType.isString():
-        return CGGeneric("nsString")
+        return CGGeneric("nsString"), True
     if returnType.isEnum():
         if returnType.nullable():
             raise TypeError("We don't support nullable enum return values")
-        return CGGeneric(returnType.inner.identifier.name)
+        return CGGeneric(returnType.inner.identifier.name), False
     if returnType.isGeckoInterface():
         result = CGGeneric(descriptorProvider.getDescriptor(
             returnType.unroll().inner.identifier.name).nativeType)
         if resultAlreadyAddRefed:
             result = CGWrapper(result, pre="nsRefPtr<", post=">")
         else:
             result = CGWrapper(result, post="*")
-        return result
+        return result, False
     if returnType.isCallback():
         # XXXbz we're going to assume that callback types are always
         # nullable for now.
-        return CGGeneric("JSObject*")
-    if returnType.isAny():
-        return CGGeneric("JS::Value")
+        return CGGeneric("JSObject*"), False
+    if returnType.tag() is IDLType.Tags.any:
+        return CGGeneric("JS::Value"), False
     if returnType.isObject():
-        return CGGeneric("JSObject*")
+        return CGGeneric("JSObject*"), False
     if returnType.isSequence():
         nullable = returnType.nullable()
         if nullable:
             returnType = returnType.inner
         # If our result is already addrefed, use the right type in the
         # sequence argument here.
-        result = getRetvalDeclarationForType(returnType.inner,
-                                             descriptorProvider,
-                                             resultAlreadyAddRefed)
+        (result, _) = getRetvalDeclarationForType(returnType.inner,
+                                                  descriptorProvider,
+                                                  resultAlreadyAddRefed)
         result = CGWrapper(result, pre="nsTArray< ", post=" >")
         if nullable:
             result = CGWrapper(result, pre="Nullable< ", post=" >")
-        return result
+        return result, True
     raise TypeError("Don't know how to declare return value for %s" %
                     returnType)
 
 def isResultAlreadyAddRefed(descriptor, extendedAttributes):
     # Default to already_AddRefed on the main thread, raw pointer in workers
     return not descriptor.workers and not 'resultNotAddRefed' in extendedAttributes
 
 class CGCallGenerator(CGThing):
     """
     A class to generate an actual call to a C++ object.  Assumes that the C++
-    object is stored in a variable named "self".
+    object is stored in a variable whose name is given by the |object| argument.
     """
     def __init__(self, errorReport, arguments, argsPre, returnType,
-                 extendedAttributes, descriptorProvider, nativeMethodName, static):
+                 extendedAttributes, descriptorProvider, nativeMethodName,
+                 static, object="self", declareResult=True):
         CGThing.__init__(self)
 
         isFallible = errorReport is not None
 
+        resultAlreadyAddRefed = isResultAlreadyAddRefed(descriptorProvider,
+                                                        extendedAttributes)
+        (result, resultOutParam) = getRetvalDeclarationForType(returnType,
+                                                               descriptorProvider,
+                                                               resultAlreadyAddRefed)
+
         args = CGList([CGGeneric(arg) for arg in argsPre], ", ")
-        for (i, a) in enumerate(arguments):
-            arg = "arg" + str(i)
+        for (a, name) in arguments:
             # This is a workaround for a bug in Apple's clang.
             if a.type.isObject() and not a.type.nullable() and not a.optional:
-                arg = "(JSObject&)" + arg
-            args.append(CGGeneric(arg))
-        resultOutParam = (returnType is not None and
-                          (returnType.isString() or returnType.isSequence()))
+                name = "(JSObject&)" + name
+            args.append(CGGeneric(name))
+
         # Return values that go in outparams go here
         if resultOutParam:
             args.append(CGGeneric("result"))
         if isFallible:
             args.append(CGGeneric("rv"))
 
-        resultAlreadyAddRefed = isResultAlreadyAddRefed(descriptorProvider,
-                                                        extendedAttributes)
-        result = getRetvalDeclarationForType(returnType,
-                                             descriptorProvider,
-                                             resultAlreadyAddRefed)
         needsCx = (typeNeedsCx(returnType) or
-                   any(typeNeedsCx(a.type) for a in arguments) or
+                   any(typeNeedsCx(a.type) for (a, _) in arguments) or
                    'implicitJSContext' in extendedAttributes)
 
         if not "cx" in argsPre and needsCx:
             args.prepend(CGGeneric("cx"))
 
         # Build up our actual call
         self.cgRoot = CGList([], "\n")
 
         call = CGGeneric(nativeMethodName)
         if static:
-            call = CGWrapper(call, pre="%s::" % (descriptorProvider.getDescriptor(
-                returnType.unroll().inner.identifier.name).nativeType))
+            call = CGWrapper(call, pre="%s::" % descriptorProvider.nativeType)
         else: 
-            call = CGWrapper(call, pre="self->")
+            call = CGWrapper(call, pre="%s->" % object)
         call = CGList([call, CGWrapper(args, pre="(", post=");")])
         if result is not None:
-            result = CGWrapper(result, post=" result;")
-            self.cgRoot.prepend(result)
+            if declareResult:
+                result = CGWrapper(result, post=" result;")
+                self.cgRoot.prepend(result)
             if not resultOutParam:
                 call = CGWrapper(call, pre="result = ")
 
         call = CGWrapper(call)
         self.cgRoot.append(call)
 
         if isFallible:
             self.cgRoot.prepend(CGGeneric("ErrorResult rv;"))
             self.cgRoot.append(CGGeneric("if (rv.Failed()) {"))
-            self.cgRoot.append(CGIndenter(CGGeneric(errorReport)))
+            self.cgRoot.append(CGIndenter(errorReport))
             self.cgRoot.append(CGGeneric("}"))
 
     def define(self):
         return self.cgRoot.define()
 
 class MethodNotCreatorError(Exception):
     def __init__(self, typename):
         self.typename = typename
@@ -2825,27 +2918,29 @@ class CGPerSignatureCall(CGThing):
             cgThings = []
         cgThings.extend([CGArgumentConverter(arguments[i], i, self.getArgv(),
                                              self.getArgc(), self.descriptor,
                                              invalidEnumValueFatal=not setter) for
                          i in range(argConversionStartsAt, self.argCount)])
 
         cgThings.append(CGCallGenerator(
                     self.getErrorReport() if self.isFallible() else None,
-                    self.arguments, self.argsPre, returnType,
+                    self.getArguments(), self.argsPre, returnType,
                     self.extendedAttributes, descriptor, nativeMethodName,
                     static))
         self.cgRoot = CGList(cgThings, "\n")
 
     def getArgv(self):
         return "argv" if self.argCount > 0 else ""
     def getArgvDecl(self):
         return "\nJS::Value* argv = JS_ARGV(cx, vp);\n"
     def getArgc(self):
         return "argc"
+    def getArguments(self):
+        return [(a, "arg" + str(i)) for (i, a) in enumerate(self.arguments)]
 
     def isFallible(self):
         return not 'infallible' in self.extendedAttributes
 
     def wrap_return_value(self):
         isCreator = memberIsCreator(self.idlNode)
         if isCreator:
             # We better be returning addrefed things!
@@ -2860,20 +2955,20 @@ class CGPerSignatureCall(CGThing):
         except MethodNotCreatorError, err:
             assert not isCreator
             raise TypeError("%s being returned from non-creator method or property %s.%s" %
                             (err.typename,
                              self.descriptor.interface.identifier.name,
                              self.idlNode.identifier.name))
 
     def getErrorReport(self):
-        return 'return ThrowMethodFailedWithDetails<%s>(cx, rv, "%s", "%s");'\
-               % (toStringBool(not self.descriptor.workers),
-                  self.descriptor.interface.identifier.name,
-                  self.idlNode.identifier.name)
+        return CGGeneric('return ThrowMethodFailedWithDetails<%s>(cx, rv, "%s", "%s");'
+                         % (toStringBool(not self.descriptor.workers),
+                            self.descriptor.interface.identifier.name,
+                            self.idlNode.identifier.name))
 
     def define(self):
         return (self.cgRoot.define() + "\n" + self.wrap_return_value())
 
 class CGSwitch(CGList):
     """
     A class to generate code for a switch statement.
 
@@ -3841,37 +3936,127 @@ class ClassMethod(ClassItem):
                   'decorators': self.getDecorators(False),
                   'returnType': self.returnType,
                   'className': cgClass.getNameString(),
                   'name': self.name,
                   'args': args,
                   'const': ' const' if self.const else '',
                   'body': body })
 
+class ClassConstructor(ClassItem):
+    """
+    Used for adding a constructor to a CGClass.
+    
+    args is a list of Argument objects that are the arguments taken by the
+    constructor.
+    
+    inline should be True if the constructor should be marked inline.
+
+    bodyInHeader should be True if the body should be placed in the class
+    declaration in the header.
+
+    visibility determines the visibility of the constructor (public,
+    protected, private), defaults to private.
+
+    baseConstructors is a list of strings containing calls to base constructors,
+    defaults to None.
+
+    body contains a string with the code for the constructor, defaults to None.
+    """
+    def __init__(self, args, inline=False, bodyInHeader=False,
+                 visibility="private", baseConstructors=None, body=None):
+        self.args = args
+        self.inline = inline or bodyInHeader
+        self.bodyInHeader = bodyInHeader
+        self.baseConstructors = baseConstructors
+        self.body = body
+        ClassItem.__init__(self, None, visibility)
+
+    def getDecorators(self, declaring):
+        decorators = []
+        if self.inline and declaring:
+            decorators.append('inline')
+        if decorators:
+            return ' '.join(decorators) + ' '
+        return ''
+
+    def getInitializationList(self, cgClass):
+        items = [str(c) for c in self.baseConstructors]
+        for m in cgClass.members:
+            if not m.static:
+                initialize = m.getBody()
+                if initialize:
+                    items.append(m.name + "(" + initialize + ")")
+            
+        if len(items) > 0:
+            return '\n  : ' + ',\n    '.join(items)
+        return ''
+
+    def getBody(self):
+        assert self.body is not None
+        return self.body
+
+    def declare(self, cgClass):
+        args = ', '.join([str(a) for a in self.args])
+        if self.bodyInHeader:
+            body = '  ' + self.getBody();
+            body = stripTrailingWhitespace(body.replace('\n', '\n  '))
+            if len(body) > 0:
+                body += '\n'
+            body = self.getInitializationList(cgClass) + '\n{\n' + body + '}'
+        else:
+            body = ';'
+
+        return string.Template("""${decorators}${className}(${args})${body}
+""").substitute({ 'decorators': self.getDecorators(True),
+                  'className': cgClass.getNameString(),
+                  'args': args,
+                  'body': body })
+
+    def define(self, cgClass):
+        if self.bodyInHeader:
+            return ''
+
+        args = ', '.join([str(a) for a in self.args])
+
+        body = '  ' + self.getBody()
+        body = '\n' + stripTrailingWhitespace(body.replace('\n', '\n  '))
+        if len(body) > 0:
+            body += '\n'
+
+        return string.Template("""${decorators}
+${className}::${className}(${args})${initializationList}
+{${body}}\n
+""").substitute({ 'decorators': self.getDecorators(False),
+                  'className': cgClass.getNameString(),
+                  'args': args,
+                  'initializationList': self.getInitializationList(cgClass),
+                  'body': body })
+
 class ClassMember(ClassItem):
     def __init__(self, name, type, visibility="private", static=False,
                  body=None):
         self.type = type;
         self.static = static
         self.body = body
         ClassItem.__init__(self, name, visibility)
 
-    def getBody(self):
-        assert self.body is not None
-        return self.body
-
     def declare(self, cgClass):
         return '%s%s %s;\n' % ('static ' if self.static else '', self.type,
                                self.name)
 
     def define(self, cgClass):
         if not self.static:
             return ''
-        return '%s %s::%s = %s;\n' % (self.type, cgClass.getNameString(),
-                                      self.name, self.getBody())
+        if self.body:
+            body = " = " + self.body
+        else:
+            body = ""
+        return '%s %s::%s%s;\n' % (self.type, cgClass.getNameString(),
+                                      self.name, body)
 
 class ClassTypedef(ClassItem):
     def __init__(self, name, type, visibility="public"):
         self.type = type
         ClassItem.__init__(self, name, visibility)
 
     def declare(self, cgClass):
         return 'typedef %s %s;\n' % (self.type, self.name)
@@ -3897,23 +4082,24 @@ class ClassEnum(ClassItem):
         name = '' if not self.name else ' ' + self.name
         return 'enum%s\n{\n  %s\n};\n' % (name, ',\n  '.join(entries))
 
     def define(self, cgClass):
         # Only goes in the header
         return ''
 
 class CGClass(CGThing):
-    def __init__(self, name, bases=[], members=[], methods=[], typedefs = [],
-                 enums=[], templateArgs=[], templateSpecialization=[],
-                 isStruct=False, indent=''):
+    def __init__(self, name, bases=[], members=[], constructors=[], methods=[],
+                 typedefs = [], enums=[], templateArgs=[],
+                 templateSpecialization=[], isStruct=False, indent=''):
         CGThing.__init__(self)
         self.name = name
         self.bases = bases
         self.members = members
+        self.constructors = constructors
         self.methods = methods
         self.typedefs = typedefs
         self.enums = enums
         self.templateArgs = templateArgs
         self.templateSpecialization = templateSpecialization
         self.isStruct = isStruct
         self.indent = indent
         self.defaultVisibility ='public' if isStruct else 'private'
@@ -3980,43 +4166,44 @@ class CGClass(CGThing):
                         declaration = member.declare(cgClass)
                         declaration = CGIndenter(CGGeneric(declaration)).define()
                         result = result + declaration
                         itemCount = itemCount + 1
                     lastVisibility = visibility
             return (result, lastVisibility, itemCount)
 
         order = [(self.enums, ''), (self.typedefs, ''), (self.members, ''),
-                 (self.methods, '\n')]
+                 (self.constructors, '\n'), (self.methods, '\n')]
 
         lastVisibility = self.defaultVisibility
         itemCount = 0
         for (memberList, separator) in order:
             (memberString, lastVisibility, itemCount) = \
                 declareMembers(self, memberList, lastVisibility, itemCount,
                                separator)
             if self.indent:
                 memberString = CGIndenter(CGGeneric(memberString),
                                           len(self.indent)).define()
             result = result + memberString
 
-        result = result + self.indent + '};\n\n'
+        result = result + self.indent + '};\n'
         return result
 
     def define(self):
         def defineMembers(cgClass, memberList, itemCount, separator=''):
             result = ''
             for member in memberList:
                 if itemCount != 0:
                     result = result + separator
                 result = result + member.define(cgClass)
                 itemCount = itemCount + 1
             return (result, itemCount)
 
-        order = [(self.members, '\n'), (self.methods, '\n')]
+        order = [(self.members, '\n'), (self.constructors, '\n'),
+                 (self.methods, '\n')]
 
         result = ''
         itemCount = 0
         for (memberList, separator) in order:
             (memberString, itemCount) = defineMembers(self, memberList,
                                                       itemCount, separator)
             result = result + memberString
         return result
@@ -4112,99 +4299,632 @@ class CGClassForwardDeclare(CGThing):
         self.isStruct = isStruct
     def declare(self):
         type = 'struct' if self.isStruct else 'class'
         return '%s %s;\n' % (type, self.name)
     def define(self):
         # Header only
         return ''
 
+class CGProxySpecialOperation(CGPerSignatureCall):
+    """
+    Base class for classes for calling an indexed or named special operation
+    (don't use this directly, use the derived classes below).
+    """
+    def __init__(self, descriptor, operation):
+        nativeName = MakeNativeName(descriptor.binaryNames.get(operation, operation))
+        operation = descriptor.operations[operation]
+        assert len(operation.signatures()) == 1
+        signature = operation.signatures()[0]
+        extendedAttributes = descriptor.getExtendedAttributes(operation)
+
+        (returnType, arguments) = signature
+
+        # We pass len(arguments) as the final argument so that the
+        # CGPerSignatureCall won't do any argument conversion of its own.
+        CGPerSignatureCall.__init__(self, returnType, "", arguments, nativeName,
+                                    False, descriptor, operation,
+                                    len(arguments))
+
+        if operation.isSetter() or operation.isCreator():
+            # arguments[0] is the index or name of the item that we're setting.
+            argument = arguments[1]
+            template = getJSToNativeConversionTemplate(argument.type, descriptor)
+            templateValues = {
+                "declName": argument.identifier.name,
+                "holderName": argument.identifier.name + "_holder",
+                "val": "desc->value",
+                "valPtr": "&desc->value"
+            }
+            self.cgRoot.prepend(instantiateJSToNativeConversionTemplate(template, templateValues))
+        elif operation.isGetter():
+            self.cgRoot.prepend(CGGeneric("bool found;"))
+
+    def getArguments(self):
+        args = [(a, a.identifier.name) for a in self.arguments]
+        if self.idlNode.isGetter():
+            args.append((FakeArgument(BuiltinTypes[IDLBuiltinType.Types.boolean]), "found"))
+        return args
+
+    def wrap_return_value(self):
+        if not self.idlNode.isGetter() or self.templateValues is None:
+            return ""
+
+        wrap = CGGeneric(wrapForType(self.returnType, self.descriptor, self.templateValues))
+        wrap = CGIfWrapper(wrap, "found")
+        return "\n" + wrap.define()
+
+class CGProxyIndexedGetter(CGProxySpecialOperation):
+    """
+    Class to generate a call to an indexed getter. If templateValues is not None
+    the returned value will be wrapped with wrapForType using templateValues.
+    """
+    def __init__(self, descriptor, templateValues=None):
+        self.templateValues = templateValues
+        CGProxySpecialOperation.__init__(self, descriptor, 'IndexedGetter')
+
+class CGProxyIndexedSetter(CGProxySpecialOperation):
+    """
+    Class to generate a call to an indexed setter.
+    """
+    def __init__(self, descriptor):
+        CGProxySpecialOperation.__init__(self, descriptor, 'IndexedSetter')
+
+class CGProxyNamedGetter(CGProxySpecialOperation):
+    """
+    Class to generate a call to an named getter. If templateValues is not None
+    the returned value will be wrapped with wrapForType using templateValues.
+    """
+    def __init__(self, descriptor, templateValues=None):
+        self.templateValues = templateValues
+        CGProxySpecialOperation.__init__(self, descriptor, 'NamedGetter')
+
+class CGProxyNamedSetter(CGProxySpecialOperation):
+    """
+    Class to generate a call to a named setter.
+    """
+    def __init__(self, descriptor):
+        CGProxySpecialOperation.__init__(self, descriptor, 'NamedSetter')
+
+class CGProxyIsProxy(CGAbstractMethod):
+    def __init__(self, descriptor):
+        args = [Argument('JSObject*', 'obj')]
+        CGAbstractMethod.__init__(self, descriptor, "IsProxy", "bool", args, alwaysInline=True)
+    def declare(self):
+        return ""
+    def definition_body(self):
+        return "  return js::IsProxy(obj) && js::GetProxyHandler(obj) == &DOMProxyHandler::instance;"
+
+class CGProxyUnwrap(CGAbstractMethod):
+    def __init__(self, descriptor):
+        args = [Argument('JSObject*', 'obj')]
+        CGAbstractMethod.__init__(self, descriptor, "UnwrapProxy", descriptor.nativeType + '*', args, alwaysInline=True)
+    def declare(self):
+        return ""
+    def definition_body(self):
+        return """  if (xpc::WrapperFactory::IsXrayWrapper(obj)) {
+    obj = js::UnwrapObject(obj);
+  }
+  MOZ_ASSERT(IsProxy(obj));
+  return static_cast<%s*>(js::GetProxyPrivate(obj).toPrivate());""" % (self.descriptor.nativeType)
+
+class CGDOMJSProxyHandlerDOMClass(CGThing):
+    def __init__(self, descriptor):
+        CGThing.__init__(self)
+        self.descriptor = descriptor
+    def declare(self):
+        return "extern const DOMClass Class;\n"
+    def define(self):
+        return """
+const DOMClass Class = """ + DOMClass(self.descriptor) + """;
+
+"""
+
+class CGDOMJSProxyHandler_CGDOMJSProxyHandler(ClassConstructor):
+    def __init__(self):
+        ClassConstructor.__init__(self, [], inline=True, visibility="public",
+                                  baseConstructors=["mozilla::dom::DOMProxyHandler(Class)"],
+                                  body="")
+
+class CGDOMJSProxyHandler_getOwnPropertyDescriptor(ClassMethod):
+    def __init__(self, descriptor):
+        args = [Argument('JSContext*', 'cx'), Argument('JSObject*', 'proxy'),
+                Argument('jsid', 'id'), Argument('bool', 'set'),
+                Argument('JSPropertyDescriptor*', 'desc')]
+        ClassMethod.__init__(self, "getOwnPropertyDescriptor", "bool", args)
+        self.descriptor = descriptor
+    def getBody(self):
+        indexedGetter = self.descriptor.operations['IndexedGetter']
+        indexedSetter = self.descriptor.operations['IndexedSetter']
+
+        setOrIndexedGet = ""
+        if indexedGetter or indexedSetter:
+            setOrIndexedGet += "int32_t index = GetArrayIndexFromId(cx, id);\n"
+
+        if indexedGetter:
+            readonly = toStringBool(self.descriptor.operations['IndexedSetter'] is None)
+            fillDescriptor = "FillPropertyDescriptor(desc, proxy, %s);\nreturn true;" % readonly
+            templateValues = {'jsvalRef': 'desc->value', 'jsvalPtr': '&desc->value',
+                              'obj': 'proxy', 'successCode': fillDescriptor}
+            get = ("if (index >= 0) {\n" +
+                   "  %s* self = UnwrapProxy(proxy);\n" +
+                   CGIndenter(CGProxyIndexedGetter(self.descriptor, templateValues)).define() + "\n" +
+                   "}\n") % (self.descriptor.nativeType)
+
+        if indexedSetter or self.descriptor.operations['NamedSetter']:
+            setOrIndexedGet += "if (set) {\n"
+            if indexedSetter:
+                setOrIndexedGet += ("  if (index >= 0) {\n")
+                if not 'IndexedCreator' in self.descriptor.operations:
+                    # FIXME need to check that this is a 'supported property index'
+                    assert False
+                setOrIndexedGet += ("    FillPropertyDescriptor(desc, proxy, JSVAL_VOID, false);\n" +
+                                    "    return true;\n" +
+                                    "  }\n")
+            if self.descriptor.operations['NamedSetter']:
+                setOrIndexedGet += "  if (JSID_IS_STRING(id)) {\n"
+                if not 'NamedCreator' in self.descriptor.operations:
+                    # FIXME need to check that this is a 'supported property name'
+                    assert False
+                setOrIndexedGet += ("    FillPropertyDescriptor(desc, proxy, JSVAL_VOID, false);\n" +
+                                    "    return true;\n" +
+                                    "  }\n")
+            setOrIndexedGet += "}"
+            if indexedGetter:
+                setOrIndexedGet += (" else {\n" +
+                                    CGIndenter(CGGeneric(get)).define() +
+                                    "}")
+            setOrIndexedGet += "\n\n"
+        elif indexedGetter:
+            setOrIndexedGet += ("if (!set) {\n" +
+                                CGIndenter(CGGeneric(get)).define() +
+                                "}\n\n")
+
+        namedGetter = self.descriptor.operations['NamedGetter']
+        if namedGetter:
+            readonly = toStringBool(self.descriptor.operations['NamedSetter'] is None)
+            fillDescriptor = "FillPropertyDescriptor(desc, proxy, %s);\nreturn true;" % readonly
+            templateValues = {'jsvalRef': 'desc->value', 'jsvalPtr': '&desc->value',
+                              'obj': 'proxy', 'successCode': fillDescriptor}
+            namedGet = ("\n" +
+                        "if (!set && JSID_IS_STRING(id) && !HasPropertyOnPrototype(cx, proxy, this, id)) {\n" +
+                        "  JS::Value nameVal = STRING_TO_JSVAL(JSID_TO_STRING(id));\n" +
+                        "  FakeDependentString name;\n"
+                        "  if (!ConvertJSValueToString(cx, nameVal, &nameVal,\n" +
+                        "                              eStringify, eStringify, name)) {\n" +
+                        "    return false;\n" +
+                        "  }\n" +
+                        "\n" +
+                        "  %s* self = UnwrapProxy(proxy);\n" +
+                        CGIndenter(CGProxyNamedGetter(self.descriptor, templateValues)).define() + "\n" +
+                        "}\n") % (self.descriptor.nativeType)
+        else:
+            namedGet = ""
+
+        return setOrIndexedGet + """JSObject* expando;
+if (!xpc::WrapperFactory::IsXrayWrapper(proxy) && (expando = GetExpandoObject(proxy))) {
+  unsigned flags = (set ? JSRESOLVE_ASSIGNING : 0) | JSRESOLVE_QUALIFIED;
+  if (!JS_GetPropertyDescriptorById(cx, expando, id, flags, desc)) {
+    return false;
+  }
+  if (desc->obj) {
+    // Pretend the property lives on the wrapper.
+    desc->obj = proxy;
+    return true;
+  }
+}
+""" + namedGet + """
+desc->obj = NULL;
+return true;"""
+
+class CGDOMJSProxyHandler_defineProperty(ClassMethod):
+    def __init__(self, descriptor):
+        args = [Argument('JSContext*', 'cx'), Argument('JSObject*', 'proxy'),
+                Argument('jsid', 'id'),
+                Argument('JSPropertyDescriptor*', 'desc')]
+        ClassMethod.__init__(self, "defineProperty", "bool", args)
+        self.descriptor = descriptor
+    def getBody(self):
+        set = ""
+
+        indexedSetter = self.descriptor.operations['IndexedSetter']
+        if indexedSetter:
+            if not (self.descriptor.operations['IndexedCreator'] is indexedSetter):
+                raise TypeError("Can't handle creator that's different from the setter")
+            set += ("int32_t index = GetArrayIndexFromId(cx, id);\n" +
+                    "if (index >= 0) {\n" +
+                    "  %s* self = UnwrapProxy(proxy);\n" +
+                    CGIndenter(CGProxyIndexedSetter(self.descriptor)).define() +
+                    "  return true;\n" +
+                    "}\n") % (self.descriptor.nativeType)
+        elif self.descriptor.operations['IndexedGetter']:
+            set += ("if (GetArrayIndexFromId(cx, id)) {\n" +
+                    "  return ThrowErrorMessage(cx, MSG_NO_PROPERTY_SETTER, \"%s\");\n" +
+                    "}\n") % self.descriptor.name
+        namedSetter = self.descriptor.operations['NamedSetter']
+        if namedSetter:
+            if not self.descriptor.operations['NamedCreator'] is namedSetter:
+                raise TypeError("Can't handle creator that's different from the setter")
+            set += ("if (JSID_IS_STRING(id)) {\n" +
+                    "  JS::Value nameVal = STRING_TO_JSVAL(JSID_TO_STRING(id));\n" +
+                    "  FakeDependentString name;\n"
+                    "  if (!ConvertJSValueToString(cx, nameVal, &nameVal,\n" +
+                    "                              eStringify, eStringify, name)) {\n" +
+                    "    return false;\n" +
+                    "  }\n" +
+                    "\n" +
+                    "  %s* self = UnwrapProxy(proxy);\n" +
+                    CGIndenter(CGProxyNamedSetter(self.descriptor)).define() + "\n" +
+                    "}\n") % (self.descriptor.nativeType)
+        elif self.descriptor.operations['NamedGetter']:
+            set += ("if (JSID_IS_STRING(id)) {\n" +
+                    "  JS::Value nameVal = STRING_TO_JSVAL(JSID_TO_STRING(id));\n" +
+                    "  FakeDependentString name;\n"
+                    "  if (!ConvertJSValueToString(cx, nameVal, &nameVal,\n" +
+                    "                              eStringify, eStringify, name)) {\n" +
+                    "    return false;\n" +
+                    "  }\n" +
+                    "  %s* self = UnwrapProxy(proxy);\n" +
+                    CGIndenter(CGProxyNamedGetter(self.descriptor)).define() +
+                    "  if (found) {\n"
+                    "    return ThrowErrorMessage(cx, MSG_NO_PROPERTY_SETTER, \"%s\");\n" +
+                    "  }\n" +
+                    "}\n") % (self.descriptor.nativeType, self.descriptor.name)
+        return set + """return mozilla::dom::DOMProxyHandler::defineProperty(%s);""" % ", ".join(a.name for a in self.args)
+
+class CGDOMJSProxyHandler_getOwnPropertyNames(ClassMethod):
+    def __init__(self, descriptor):
+        args = [Argument('JSContext*', 'cx'), Argument('JSObject*', 'proxy'),
+                Argument('JS::AutoIdVector&', 'props')]
+        ClassMethod.__init__(self, "getOwnPropertyNames", "bool", args)
+        self.descriptor = descriptor
+    def getBody(self):
+        indexedGetter = self.descriptor.operations['IndexedGetter']
+        if indexedGetter:
+            addIndices = """uint32_t length = UnwrapProxy(proxy)->GetLength();
+MOZ_ASSERT(int32_t(length) >= 0);
+for (int32_t i = 0; i < int32_t(length); ++i) {
+  if (!props.append(INT_TO_JSID(i))) {
+    return false;
+  }
+}
+
+"""
+        else:
+            addIndices = ""
+
+        return addIndices + """JSObject* expando;
+if (!xpc::WrapperFactory::IsXrayWrapper(proxy) && (expando = DOMProxyHandler::GetExpandoObject(proxy)) &&
+    !js::GetPropertyNames(cx, expando, JSITER_OWNONLY | JSITER_HIDDEN, &props)) {
+  return false;
+}
+
+// FIXME: https://bugzilla.mozilla.org/show_bug.cgi?id=772869 Add named items
+return true;"""
+
+class CGDOMJSProxyHandler_hasOwn(ClassMethod):
+    def __init__(self, descriptor):
+        args = [Argument('JSContext*', 'cx'), Argument('JSObject*', 'proxy'),
+                Argument('jsid', 'id'), Argument('bool*', 'bp')]
+        ClassMethod.__init__(self, "hasOwn", "bool", args)
+        self.descriptor = descriptor
+    def getBody(self):
+        indexedGetter = self.descriptor.operations['IndexedGetter']
+        if indexedGetter:
+            indexed = ("int32_t index = GetArrayIndexFromId(cx, id);\n" + 
+                       "if (index >= 0) {\n" +
+                       "  %s* self = UnwrapProxy(proxy);\n" +
+                       CGIndenter(CGProxyIndexedGetter(self.descriptor)).define() + "\n" +
+                       "  *bp = found;\n" +
+                       "  return true;\n" +
+                       "}\n\n") % (self.descriptor.nativeType)
+        else:
+            indexed = ""
+
+        namedGetter = self.descriptor.operations['NamedGetter']
+        if namedGetter:
+            named = ("if (JSID_IS_STRING(id) && !HasPropertyOnPrototype(cx, proxy, this, id)) {\n" +
+                     "  jsval nameVal = STRING_TO_JSVAL(JSID_TO_STRING(id));\n" +
+                     "  FakeDependentString name;\n"
+                     "  if (!ConvertJSValueToString(cx, nameVal, &nameVal,\n" +
+                     "                              eStringify, eStringify, name)) {\n" +
+                     "    return false;\n" +
+                     "  }\n" +
+                     "\n" +
+                     "  %s* self = UnwrapProxy(proxy);\n" +
+                     CGIndenter(CGProxyNamedGetter(self.descriptor)).define() + "\n" +
+                     "  *bp = found;\n"
+                     "  return true;\n"
+                     "}\n" +
+                     "\n") % (self.descriptor.nativeType)
+        else:
+            named = ""
+
+        return indexed + """JSObject* expando = GetExpandoObject(proxy);
+if (expando) {
+  JSBool b = true;
+  JSBool ok = JS_HasPropertyById(cx, expando, id, &b);
+  *bp = !!b;
+  if (!ok || *bp) {
+    return ok;
+  }
+}
+
+""" + named + """*bp = false;
+return true;"""
+
+class CGDOMJSProxyHandler_get(ClassMethod):
+    def __init__(self, descriptor):
+        args = [Argument('JSContext*', 'cx'), Argument('JSObject*', 'proxy'),
+                Argument('JSObject*', 'receiver'), Argument('jsid', 'id'),
+                Argument('JS::Value*', 'vp')]
+        ClassMethod.__init__(self, "get", "bool", args)
+        self.descriptor = descriptor
+    def getBody(self):
+        getFromExpando = """JSObject* expando = DOMProxyHandler::GetExpandoObject(proxy);
+if (expando) {
+  JSBool hasProp;
+  if (!JS_HasPropertyById(cx, expando, id, &hasProp)) {
+    return false;
+  }
+
+  if (hasProp) {
+    return JS_GetPropertyById(cx, expando, id, vp);
+  }
+}"""
+
+        templateValues = {'jsvalRef': '*vp', 'jsvalPtr': 'vp', 'obj': 'proxy'}
+
+        indexedGetter = self.descriptor.operations['IndexedGetter']
+        if indexedGetter:
+            getIndexedOrExpando = ("int32_t index = GetArrayIndexFromId(cx, id);\n" +
+                                   "if (index >= 0) {\n" +
+                                   "  %s* self = UnwrapProxy(proxy);\n" +
+                                   CGIndenter(CGProxyIndexedGetter(self.descriptor, templateValues)).define()) % (self.descriptor.nativeType)
+            getIndexedOrExpando += """
+  // Even if we don't have this index, we don't forward the
+  // get on to our expando object.
+} else {
+  %s
+}
+""" % (stripTrailingWhitespace(getFromExpando.replace('\n', '\n  ')))
+        else:
+            getIndexedOrExpando = getFromExpando + "\n"
+
+        namedGetter = self.descriptor.operations['NamedGetter']
+        if namedGetter:
+            getNamed = ("if (JSID_IS_STRING(id)) {\n" +
+                        "  JS::Value nameVal = STRING_TO_JSVAL(JSID_TO_STRING(id));\n" +
+                        "  FakeDependentString name;\n"
+                        "  if (!ConvertJSValueToString(cx, nameVal, &nameVal,\n" +
+                        "                              eStringify, eStringify, name)) {\n" +
+                        "    return false;\n" +
+                        "  }\n" +
+                        "\n" +
+                        "  %s* self = UnwrapProxy(proxy);\n" +
+                        CGIndenter(CGProxyNamedGetter(self.descriptor, templateValues)).define() +
+                        "}\n") % (self.descriptor.nativeType)
+        else:
+            getNamed = ""
+
+        return """MOZ_ASSERT(!xpc::WrapperFactory::IsXrayWrapper(proxy),
+            "Should not have a XrayWrapper here");
+
+%s
+bool found;
+if (!GetPropertyOnPrototype(cx, proxy, id, &found, vp)) {
+  return false;
+}
+
+if (found) {
+  return true;
+}
+%s
+vp->setUndefined();
+return true;""" % (getIndexedOrExpando, getNamed)
+
+class CGDOMJSProxyHandler_obj_toString(ClassMethod):
+    def __init__(self, descriptor):
+        args = [Argument('JSContext*', 'cx'), Argument('JSObject*', 'proxy')]
+        ClassMethod.__init__(self, "obj_toString", "JSString*", args)
+        self.descriptor = descriptor
+    def getBody(self):
+        stringifier = self.descriptor.operations['Stringifier']
+        if stringifier:
+            name = stringifier.identifier.name
+            nativeName = MakeNativeName(self.descriptor.binaryNames.get(name, name))
+            signature = stringifier.signatures()[0]
+            returnType = signature[0]
+            extendedAttributes = self.descriptor.getExtendedAttributes(stringifier)
+            infallible = 'infallible' in extendedAttributes
+            if not infallible:
+                error = ('ThrowMethodFailedWithDetails(cx, rv, "%s", "toString")\n' +
+                         "return NULL;") % self.descriptor.interface.identifier.name
+            else:
+                error = None
+            call = CGCallGenerator(error, [], "", returnType, extendedAttributes, self.descriptor, nativeName, False, object="UnwrapProxy(proxy)")
+            return call.define() + """
+
+JSString* jsresult;
+return xpc_qsStringToJsstring(cx, result, &jsresult) ? jsresult : NULL;""" 
+
+        return "return mozilla::dom::DOMProxyHandler::obj_toString(cx, \"%s\");" % self.descriptor.name
+
+class CGDOMJSProxyHandler_finalize(ClassMethod):
+    def __init__(self, descriptor):
+        args = [Argument('JSFreeOp*', 'fop'), Argument('JSObject*', 'proxy')]
+        ClassMethod.__init__(self, "finalize", "void", args)
+        self.descriptor = descriptor
+    def getBody(self):
+        return ("%s self = UnwrapProxy(proxy);\n\n" % (self.descriptor.nativeType + "*") +
+                finalizeHook(self.descriptor, FINALIZE_HOOK_NAME, self.args[0].name))
+
+class CGDOMJSProxyHandler_getElementIfPresent(ClassMethod):
+    def __init__(self, descriptor):
+        args = [Argument('JSContext*', 'cx'), Argument('JSObject*', 'proxy'),
+                Argument('JSObject*', 'receiver'),
+                Argument('uint32_t', 'index'),
+                Argument('JS::Value*', 'vp'), Argument('bool*', 'present')]
+        ClassMethod.__init__(self, "getElementIfPresent", "bool", args)
+        self.descriptor = descriptor
+    def getBody(self):
+        indexedGetter = self.descriptor.operations['IndexedGetter']
+        if indexedGetter:
+            successCode = """*present = found;
+return true;"""
+            templateValues = {'jsvalRef': '*vp', 'jsvalPtr': 'vp',
+                              'obj': 'proxy', 'successCode': successCode}
+            get = ("%s* self = UnwrapProxy(proxy);\n" +
+                   CGProxyIndexedGetter(self.descriptor, templateValues).define() + "\n"
+                   "// We skip the expando object if there is an indexed getter.\n" +
+                   "\n") % (self.descriptor.nativeType)
+        else:
+            get = """
+
+JSObject* expando = GetExpandoObject(proxy);
+if (expando) {
+  JSBool isPresent;
+  if (!JS_GetElementIfPresent(cx, expando, index, expando, vp, &isPresent)) {
+    return false;
+  }
+  if (isPresent) {
+    *present = true;
+    return true;
+  }
+}
+"""
+
+        return """MOZ_ASSERT(!xpc::WrapperFactory::IsXrayWrapper(proxy),
+             "Should not have a XrayWrapper here");
+
+""" + get + """
+// No need to worry about name getters here, so just check the proto.
+
+JSObject *proto = js::GetObjectProto(proxy);
+if (proto) {
+  JSBool isPresent;
+  if (!JS_GetElementIfPresent(cx, proto, index, proxy, vp, &isPresent)) {
+    return false;
+  }
+  *present = isPresent;
+  return true;
+}
+
+*present = false;
+// Can't Debug_SetValueRangeToCrashOnTouch because it's not public
+return true;"""
+
+class CGDOMJSProxyHandler(CGClass):
+    def __init__(self, descriptor):
+        constructors = [CGDOMJSProxyHandler_CGDOMJSProxyHandler()]
+        methods = [CGDOMJSProxyHandler_getOwnPropertyDescriptor(descriptor)]
+        if descriptor.operations['IndexedSetter'] or descriptor.operations['NamedSetter']:
+            methods.append(CGDOMJSProxyHandler_defineProperty(descriptor))
+        methods.extend([CGDOMJSProxyHandler_getOwnPropertyNames(descriptor),
+                        CGDOMJSProxyHandler_hasOwn(descriptor),
+                        CGDOMJSProxyHandler_get(descriptor),
+                        CGDOMJSProxyHandler_obj_toString(descriptor),
+                        CGDOMJSProxyHandler_finalize(descriptor),
+                        CGDOMJSProxyHandler_getElementIfPresent(descriptor)])
+        CGClass.__init__(self, 'DOMProxyHandler',
+                         bases=[ClassBase('mozilla::dom::DOMProxyHandler')],
+                         members=[ClassMember('instance', 'DOMProxyHandler', visibility='public', static=True)],
+                         constructors=constructors,
+                         methods=methods)
+
 def stripTrailingWhitespace(text):
     lines = text.splitlines()
     for i in range(len(lines)):
         lines[i] = lines[i].rstrip()
     return '\n'.join(lines)
 
 class CGDescriptor(CGThing):
     def __init__(self, descriptor):
         CGThing.__init__(self)
 
         assert not descriptor.concrete or descriptor.interface.hasInterfacePrototypeObject()
 
         cgThings = []
         if descriptor.interface.hasInterfacePrototypeObject():
             hasMethod, hasGetter, hasSetter = False, False, False
             for m in descriptor.interface.members:
-                if m.isMethod() and not m.isStatic():
+                if m.isMethod() and not m.isStatic() and not m.isIdentifierLess():
                     cgThings.append(CGSpecializedMethod(descriptor, m))
                     cgThings.append(CGMemberJITInfo(descriptor, m))
                     hasMethod = True
                 elif m.isAttr():
                     cgThings.append(CGSpecializedGetter(descriptor, m))
                     hasGetter = True
                     if not m.readonly:
                         cgThings.append(CGSpecializedSetter(descriptor, m))
                         hasSetter = True
                     cgThings.append(CGMemberJITInfo(descriptor, m))
             if hasMethod: cgThings.append(CGGenericMethod(descriptor))
             if hasGetter: cgThings.append(CGGenericGetter(descriptor))
             if hasSetter: cgThings.append(CGGenericSetter(descriptor))
 
-
-        if descriptor.concrete:
+        if descriptor.concrete and not descriptor.proxy:
             if not descriptor.workers and descriptor.wrapperCache:
                 cgThings.append(CGAddPropertyHook(descriptor))
 
             # Always have a finalize hook, regardless of whether the class wants a
             # custom hook.
             cgThings.append(CGClassFinalizeHook(descriptor))
 
             # Only generate a trace hook if the class wants a custom hook.
             if (descriptor.customTrace):
                 cgThings.append(CGClassTraceHook(descriptor))
 
-        if descriptor.interface.hasInterfacePrototypeObject():
-            cgThings.append(CGNativePropertyHooks(descriptor))
-        if descriptor.concrete:
-            cgThings.append(CGDOMJSClass(descriptor))
-
         if descriptor.interface.hasInterfaceObject():
             cgThings.append(CGClassConstructHook(descriptor))
             cgThings.append(CGClassHasInstanceHook(descriptor))
             cgThings.append(CGInterfaceObjectJSClass(descriptor))
 
         if descriptor.interface.hasInterfacePrototypeObject():
             cgThings.append(CGPrototypeJSClass(descriptor))
 
         properties = PropertyArrays(descriptor)
         cgThings.append(CGGeneric(define=str(properties)))
         cgThings.append(CGCreateInterfaceObjectsMethod(descriptor, properties))
         if descriptor.interface.hasInterfacePrototypeObject():
-            cgThings.append(CGIndenter(CGGetProtoObjectMethod(descriptor)))
+            cgThings.append(CGGetProtoObjectMethod(descriptor))
         else:
-            cgThings.append(CGIndenter(CGGetConstructorObjectMethod(descriptor)))
+            cgThings.append(CGGetConstructorObjectMethod(descriptor))
 
         # Set up our Xray callbacks as needed.  Note that we don't need to do
         # it in workers.
         if (descriptor.interface.hasInterfacePrototypeObject() and
             not descriptor.workers):
             cgThings.append(CGResolveProperty(descriptor, properties))
             cgThings.append(CGEnumerateProperties(descriptor, properties))
 
         if descriptor.interface.hasInterfaceObject():
             cgThings.append(CGDefineDOMInterfaceMethod(descriptor))
 
+        if descriptor.interface.hasInterfacePrototypeObject():
+            cgThings.append(CGNativePropertyHooks(descriptor))
+
         if descriptor.concrete:
+            if descriptor.proxy:
+                cgThings.append(CGProxyIsProxy(descriptor))
+                cgThings.append(CGProxyUnwrap(descriptor))
+                cgThings.append(CGDOMJSProxyHandlerDOMClass(descriptor))
+                cgThings.append(CGDOMJSProxyHandler(descriptor))
+                cgThings.append(CGIsMethod(descriptor))
+            else:
+                cgThings.append(CGDOMJSClass(descriptor))
+
             if descriptor.wrapperCache:
+                cgThings.append(CGWrapWithCacheMethod(descriptor))
                 cgThings.append(CGWrapMethod(descriptor))
             else:
                 cgThings.append(CGWrapNonWrapperCacheMethod(descriptor))
 
-        cgThings = CGList(cgThings)
-        cgThings = CGWrapper(cgThings, post='\n')
+        cgThings = CGList((CGIndenter(t, declareOnly=True) for t in cgThings), "\n")
+        cgThings = CGWrapper(cgThings, pre='\n', post='\n')
         self.cgRoot = CGWrapper(CGNamespace(toBindingNamespace(descriptor.name),
                                             cgThings),
                                 post='\n')
 
     def declare(self):
         return self.cgRoot.declare()
     def define(self):
         return self.cgRoot.define()
@@ -4607,17 +5327,18 @@ class CGBindingRoot(CGThing):
                                  defineOnly=True),
                        traitsClasses, curr],
                       "\n")
 
         # Add header includes.
         curr = CGHeaders(descriptors,
                          dictionaries,
                          ['mozilla/dom/BindingUtils.h',
-                          'mozilla/dom/DOMJSClass.h'],
+                          'mozilla/dom/DOMJSClass.h',
+                          'mozilla/dom/DOMJSProxyHandler.h'],
                          ['mozilla/dom/Nullable.h',
                           'PrimitiveConversions.h',
                           'XPCQuickStubs.h',
                           'nsDOMQS.h',
                           'AccessCheck.h',
                           'WorkerPrivate.h',
                           'nsContentUtils.h',
                           'mozilla/Preferences.h',
--- a/dom/bindings/Configuration.py
+++ b/dom/bindings/Configuration.py
@@ -142,23 +142,73 @@ class Descriptor(DescriptorProvider):
         else:
             self.castable = desc.get('castable', True)
 
         self.notflattened = desc.get('notflattened', False)
         self.register = desc.get('register', True)
 
         # If we're concrete, we need to crawl our ancestor interfaces and mark
         # them as having a concrete descendant.
-        self.concrete = desc.get('concrete', True)
+        self.concrete = desc.get('concrete', not self.interface.isExternal())
         if self.concrete:
+            self.proxy = False
+            operations = {
+                'IndexedGetter': None,
+                'IndexedSetter': None,
+                'IndexedCreator': None,
+                'IndexedDeleter': None,
+                'NamedGetter': None,
+                'NamedSetter': None,
+                'NamedCreator': None,
+                'NamedDeleter': None,
+                'Stringifier': None
+            }
             iface = self.interface
             while iface:
+                for m in iface.members:
+                    if not m.isMethod():
+                        continue
+
+                    def addOperation(operation, m):
+                        if not operations[operation]:
+                            operations[operation] = m
+                    def addIndexedOrNamedOperation(operation, m):
+                        self.proxy = True
+                        if m.isIndexed():
+                            operation = 'Indexed' + operation
+                        else:
+                            assert m.isNamed()
+                            operation = 'Named' + operation
+                        addOperation(operation, m)
+                        
+                    if m.isStringifier():
+                        addOperation('Stringifier', m)
+                    else:
+                        if m.isGetter():
+                            addIndexedOrNamedOperation('Getter', m)
+                        if m.isSetter():
+                            addIndexedOrNamedOperation('Setter', m)
+                        if m.isCreator():
+                            addIndexedOrNamedOperation('Creator', m)
+                        if m.isDeleter():
+                            addIndexedOrNamedOperation('Deleter', m)
+                            raise TypeError("deleter specified on %s but we "
+                                            "don't support deleters yet" %
+                                            self.interface.identifier.name)
+
                 iface.setUserData('hasConcreteDescendant', True)
                 iface = iface.parent
 
+            if self.proxy:
+                self.operations = operations
+                iface = self.interface
+                while iface:
+                    iface.setUserData('hasProxyDescendant', True)
+                    iface = iface.parent
+
         if self.interface.isExternal() and 'prefable' in desc:
             raise TypeError("%s is external but has a prefable setting" %
                             self.interface.identifier.name)
         self.prefable = desc.get('prefable', False)
 
         self.nativeIsISupports = not self.workers
         self.customTrace = desc.get('customTrace', self.workers)
         self.customFinalize = desc.get('customFinalize', self.workers)
@@ -183,18 +233,24 @@ class Descriptor(DescriptorProvider):
                     self.extendedAttributes[key].setdefault(member, []).append(attribute)
 
             if isinstance(config, dict):
                 for key in ['all', 'getterOnly', 'setterOnly']:
                     add(key, config.get(key, []), attribute)
             elif isinstance(config, list):
                 add('all', config, attribute)
             else:
-                assert isinstance(config, string)
-                add('all', [config], attribute)
+                assert isinstance(config, str)
+                if config == '*':
+                    iface = self.interface
+                    while iface:
+                        add('all', map(lambda m: m.name, iface.members), attribute)
+                        iface = iface.parent
+                else:
+                    add('all', [config], attribute)
 
         for attribute in ['infallible', 'implicitJSContext', 'resultNotAddRefed']:
             addExtendedAttribute(attribute, desc.get(attribute, {}))
 
         self.binaryNames = desc.get('binaryNames', {})
 
         # Build the prototype chain.
         self.prototypeChain = []
--- a/dom/bindings/DOMJSClass.h
+++ b/dom/bindings/DOMJSClass.h
@@ -40,41 +40,47 @@ typedef bool
 struct NativePropertyHooks
 {
   ResolveProperty mResolveProperty;
   EnumerateProperties mEnumerateProperties;
 
   const NativePropertyHooks *mProtoHooks;
 };
 
+struct DOMClass
+{
+  // A list of interfaces that this object implements, in order of decreasing
+  // derivedness.
+  const prototypes::ID mInterfaceChain[prototypes::id::_ID_Count];
+
+  // We store the DOM object in reserved slot with index DOM_OBJECT_SLOT or in
+  // the proxy private if we use a proxy object.
+  // Sometimes it's an nsISupports and sometimes it's not; this class tells
+  // us which it is.
+  const bool mDOMObjectIsISupports;
+
+  const NativePropertyHooks* mNativeHooks;
+};
+
 // Special JSClass for reflected DOM objects.
 struct DOMJSClass
 {
   // It would be nice to just inherit from JSClass, but that precludes pure
   // compile-time initialization of the form |DOMJSClass = {...};|, since C++
   // only allows brace initialization for aggregate/POD types.
   JSClass mBase;
 
-  // A list of interfaces that this object implements, in order of decreasing
-  // derivedness.
-  const prototypes::ID mInterfaceChain[prototypes::id::_ID_Count];
+  DOMClass mClass;
 
   // We cache the VTable index of GetWrapperCache for objects that support it.
   //
   // -1 indicates that GetWrapperCache is not implemented on the underlying object.
   // XXXkhuey this is unused and needs to die.
   const int16_t mGetWrapperCacheVTableOffset;
 
-  // We store the DOM object in a reserved slot whose index is mNativeSlot.
-  // Sometimes it's an nsISupports and sometimes it's not; this class tells
-  // us which it is.
-  const bool mDOMObjectIsISupports;
-
-  const NativePropertyHooks* mNativeHooks;
-
   static DOMJSClass* FromJSClass(JSClass* base) {
     MOZ_ASSERT(base->flags & JSCLASS_IS_DOMJSCLASS);
     return reinterpret_cast<DOMJSClass*>(base);
   }
   static const DOMJSClass* FromJSClass(const JSClass* base) {
     MOZ_ASSERT(base->flags & JSCLASS_IS_DOMJSCLASS);
     return reinterpret_cast<const DOMJSClass*>(base);
   }
new file mode 100644
--- /dev/null
+++ b/dom/bindings/DOMJSProxyHandler.cpp
@@ -0,0 +1,228 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ * vim: set ts=2 sw=2 et tw=99 ft=cpp: */
+/* 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/Util.h"
+
+#include "DOMJSProxyHandler.h"
+#include "xpcpublic.h"
+#include "xpcprivate.h"
+#include "XPCQuickStubs.h"
+#include "XPCWrapper.h"
+#include "WrapperFactory.h"
+#include "nsDOMClassInfo.h"
+#include "nsGlobalWindow.h"
+#include "nsWrapperCacheInlines.h"
+#include "mozilla/dom/BindingUtils.h"
+
+#include "jsapi.h"
+#include "jsatom.h"
+
+using namespace JS;
+
+namespace mozilla {
+namespace dom {
+
+jsid s_length_id = JSID_VOID;
+
+bool
+DefineStaticJSVals(JSContext* cx)
+{
+  JSAutoRequest ar(cx);
+
+  return InternJSString(cx, s_length_id, "length");
+}
+
+
+int HandlerFamily;
+
+bool
+DefineConstructor(JSContext* cx, JSObject* obj, DefineInterface aDefine, nsresult* aResult)
+{
+  bool enabled;
+  bool defined = aDefine(cx, obj, &enabled);
+  MOZ_ASSERT(!defined || enabled,
+             "We defined a constructor but the new bindings are disabled?");
+  *aResult = defined ? NS_OK : NS_ERROR_FAILURE;
+  return enabled;
+}
+
+// static
+JSObject*
+DOMProxyHandler::EnsureExpandoObject(JSContext* cx, JSObject* obj)
+{
+  NS_ASSERTION(IsDOMProxy(obj), "expected a DOM proxy object");
+  JSObject* expando = GetExpandoObject(obj);
+  if (!expando) {
+    expando = JS_NewObjectWithGivenProto(cx, nullptr, nullptr,
+                                         js::GetObjectParent(obj));
+    if (!expando) {
+      return NULL;
+    }
+
+    xpc::CompartmentPrivate* priv = xpc::GetCompartmentPrivate(obj);
+    if (!priv->RegisterDOMExpandoObject(obj)) {
+      return NULL;
+    }
+
+    nsWrapperCache* cache;
+    CallQueryInterface(UnwrapDOMObject<nsISupports>(obj, eProxyDOMObject), &cache);
+    cache->SetPreservingWrapper(true);
+
+    js::SetProxyExtra(obj, JSPROXYSLOT_EXPANDO, ObjectValue(*expando));
+  }
+  return expando;
+}
+
+bool
+DOMProxyHandler::getPropertyDescriptor(JSContext* cx, JSObject* proxy, jsid id, bool set,
+                                       JSPropertyDescriptor* desc)
+{
+  if (!getOwnPropertyDescriptor(cx, proxy, id, set, desc)) {
+    return false;
+  }
+  if (desc->obj) {
+    return true;
+  }
+
+  JSObject* proto = js::GetObjectProto(proxy);
+  if (!proto) {
+    desc->obj = NULL;
+    return true;
+  }
+
+  return JS_GetPropertyDescriptorById(cx, proto, id, JSRESOLVE_QUALIFIED, desc);
+}
+
+bool
+DOMProxyHandler::defineProperty(JSContext* cx, JSObject* proxy, jsid id,
+                                JSPropertyDescriptor* desc)
+{
+  if ((desc->attrs & JSPROP_GETTER) && desc->setter == JS_StrictPropertyStub) {
+    return JS_ReportErrorFlagsAndNumber(cx,
+                                        JSREPORT_WARNING | JSREPORT_STRICT |
+                                        JSREPORT_STRICT_MODE_ERROR,
+                                        js_GetErrorMessage, NULL,
+                                        JSMSG_GETTER_ONLY);
+  }
+
+  if (xpc::WrapperFactory::IsXrayWrapper(proxy)) {
+    return true;
+  }
+
+  JSObject* expando = EnsureExpandoObject(cx, proxy);
+  if (!expando) {
+    return false;
+  }
+
+  return JS_DefinePropertyById(cx, expando, id, desc->value, desc->getter, desc->setter,
+                               desc->attrs);
+}
+
+bool
+DOMProxyHandler::delete_(JSContext* cx, JSObject* proxy, jsid id, bool* bp)
+{
+  JSBool b = true;
+
+  JSObject* expando;
+  if (!xpc::WrapperFactory::IsXrayWrapper(proxy) && (expando = GetExpandoObject(proxy))) {
+    Value v;
+    if (!JS_DeletePropertyById2(cx, expando, id, &v) || !JS_ValueToBoolean(cx, v, &b)) {
+      return false;
+    }
+  }
+
+  *bp = !!b;
+  return true;
+}
+
+bool
+DOMProxyHandler::enumerate(JSContext* cx, JSObject* proxy, AutoIdVector& props)
+{
+  JSObject* proto = JS_GetPrototype(proxy);
+  return getOwnPropertyNames(cx, proxy, props) &&
+         (!proto || js::GetPropertyNames(cx, proto, 0, &props));
+}
+
+bool
+DOMProxyHandler::fix(JSContext* cx, JSObject* proxy, Value* vp)
+{
+  vp->setUndefined();
+  return true;
+}
+
+bool
+DOMProxyHandler::has(JSContext* cx, JSObject* proxy, jsid id, bool* bp)
+{
+  if (!hasOwn(cx, proxy, id, bp)) {
+    return false;
+  }
+
+  if (*bp) {
+    // We have the property ourselves; no need to worry about our prototype
+    // chain.
+    return true;
+  }
+
+  // OK, now we have to look at the proto
+  JSObject *proto = js::GetObjectProto(proxy);
+  if (!proto) {
+    return true;
+  }
+  JSBool protoHasProp;
+  bool ok = JS_HasPropertyById(cx, proto, id, &protoHasProp);
+  if (ok) {
+    *bp = protoHasProp;
+  }
+  return ok;
+}
+
+// static
+JSString*
+DOMProxyHandler::obj_toString(JSContext* cx, const char* className)
+{
+  size_t nchars = sizeof("[object ]") - 1 + strlen(className);
+  jschar* chars = static_cast<jschar*>(JS_malloc(cx, (nchars + 1) * sizeof(jschar)));
+  if (!chars) {
+    return NULL;
+  }
+
+  const char* prefix = "[object ";
+  nchars = 0;
+  while ((chars[nchars] = (jschar)*prefix) != 0) {
+    nchars++, prefix++;
+  }
+  while ((chars[nchars] = (jschar)*className) != 0) {
+    nchars++, className++;
+  }
+  chars[nchars++] = ']';
+  chars[nchars] = 0;
+
+  JSString* str = JS_NewUCString(cx, chars, nchars);
+  if (!str) {
+    JS_free(cx, chars);
+  }
+  return str;
+}
+
+int32_t
+IdToInt32(JSContext* cx, jsid id)
+{
+  JSAutoRequest ar(cx);
+
+  jsval idval;
+  double array_index;
+  int32_t i;
+  if (!::JS_IdToValue(cx, id, &idval) ||
+      !::JS_ValueToNumber(cx, idval, &array_index) ||
+      !::JS_DoubleIsInt32(array_index, &i)) {
+    return -1;
+  }
+
+  return i;
+}
+
+} // namespace dom
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/dom/bindings/DOMJSProxyHandler.h
@@ -0,0 +1,109 @@
+/* -*- 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 mozilla_dom_DOMJSProxyHandler_h
+#define mozilla_dom_DOMJSProxyHandler_h
+
+#include "jsapi.h"
+#include "jsatom.h"
+#include "jsproxy.h"
+#include "xpcpublic.h"
+#include "nsString.h"
+#include "mozilla/Likely.h"
+
+#define DOM_PROXY_OBJECT_SLOT js::JSSLOT_PROXY_PRIVATE
+
+namespace mozilla {
+namespace dom {
+
+enum {
+  JSPROXYSLOT_EXPANDO = 0
+};
+
+template<typename T> struct Prefable;
+
+class DOMProxyHandler : public js::BaseProxyHandler
+{
+public:
+  DOMProxyHandler(const DOMClass& aClass)
+    : js::BaseProxyHandler(ProxyFamily()),
+      mClass(aClass)
+  {
+  }
+
+  bool getPropertyDescriptor(JSContext* cx, JSObject* proxy, jsid id, bool set,
+                             JSPropertyDescriptor* desc);
+  bool defineProperty(JSContext* cx, JSObject* proxy, jsid id,
+                      JSPropertyDescriptor* desc);
+  bool delete_(JSContext* cx, JSObject* proxy, jsid id, bool* bp);
+  bool enumerate(JSContext* cx, JSObject* proxy, JS::AutoIdVector& props);
+  bool fix(JSContext* cx, JSObject* proxy, JS::Value* vp);
+  bool has(JSContext* cx, JSObject* proxy, jsid id, bool* bp);
+  using js::BaseProxyHandler::obj_toString;
+
+  static JSObject* GetExpandoObject(JSObject* obj)
+  {
+    MOZ_ASSERT(IsDOMProxy(obj), "expected a DOM proxy object");
+    JS::Value v = js::GetProxyExtra(obj, JSPROXYSLOT_EXPANDO);
+    return v.isUndefined() ? NULL : v.toObjectOrNull();
+  }
+  static JSObject* EnsureExpandoObject(JSContext* cx, JSObject* obj);
+
+  const DOMClass& mClass;
+
+protected:
+  static JSString* obj_toString(JSContext* cx, const char* className);
+};
+
+extern jsid s_length_id;
+
+int32_t IdToInt32(JSContext* cx, jsid id);
+
+inline int32_t
+GetArrayIndexFromId(JSContext* cx, jsid id)
+{
+  if (MOZ_LIKELY(JSID_IS_INT(id))) {
+    return JSID_TO_INT(id);
+  }
+  if (MOZ_LIKELY(id == s_length_id)) {
+    return -1;
+  }
+  if (MOZ_LIKELY(JSID_IS_ATOM(id))) {
+    JSAtom* atom = JSID_TO_ATOM(id);
+    jschar s = *js::GetAtomChars(atom);
+    if (MOZ_LIKELY((unsigned)s >= 'a' && (unsigned)s <= 'z'))
+      return -1;
+
+    uint32_t i;
+    JSLinearString* str = js::AtomToLinearString(JSID_TO_ATOM(id));
+    return js::StringIsArrayIndex(str, &i) ? i : -1;
+  }
+  return IdToInt32(cx, id);
+}
+
+inline void
+FillPropertyDescriptor(JSPropertyDescriptor* desc, JSObject* obj, bool readonly)
+{
+  desc->obj = obj;
+  desc->attrs = (readonly ? JSPROP_READONLY : 0) | JSPROP_ENUMERATE;
+  desc->getter = NULL;
+  desc->setter = NULL;
+  desc->shortid = 0;
+}
+
+inline void
+FillPropertyDescriptor(JSPropertyDescriptor* desc, JSObject* obj, jsval v, bool readonly)
+{
+  desc->value = v;
+  FillPropertyDescriptor(desc, obj, readonly);
+}
+
+JSObject* 
+EnsureExpandoObject(JSContext* cx, JSObject* obj);
+
+} // namespace dom
+} // namespace mozilla
+
+#endif /* mozilla_dom_DOMProxyHandler_h */
--- a/dom/bindings/Errors.msg
+++ b/dom/bindings/Errors.msg
@@ -20,8 +20,9 @@
  */
 
 MSG_DEF(MSG_INVALID_ENUM_VALUE, 2, "Value '{0}' is not a valid value for enumeration {1}.")
 MSG_DEF(MSG_MISSING_ARGUMENTS, 1, "Not enough arguments to {0}.")
 MSG_DEF(MSG_NOT_OBJECT, 0, "Value not an object.")
 MSG_DEF(MSG_DOES_NOT_IMPLEMENT_INTERFACE, 1, "Value does not implement interface {0}.")
 MSG_DEF(MSG_NOT_IN_UNION, 1, "Value could not be converted to any of: {0}.")
 MSG_DEF(MSG_ILLEGAL_CONSTRUCTOR, 0, "Illegal constructor.")
+MSG_DEF(MSG_NO_PROPERTY_SETTER, 1, "{0} doesn't have an indexed property setter.")
\ No newline at end of file
--- a/dom/bindings/Makefile.in
+++ b/dom/bindings/Makefile.in
@@ -40,27 +40,29 @@ globalgen_targets := \
   UnionTypes.h \
   UnionConversions.h \
   $(NULL)
 
 CPPSRCS = \
   $(linked_binding_cpp_files) \
   $(filter %.cpp, $(globalgen_targets)) \
   BindingUtils.cpp \
+  DOMJSProxyHandler.cpp \
   $(NULL)
 
 EXPORTS_NAMESPACES = $(binding_include_path) mozilla
 
 EXPORTS_mozilla = \
   ErrorResult.h \
   $(NULL)
 
 EXPORTS_$(binding_include_path) = \
   BindingUtils.h \
   DOMJSClass.h \
+  DOMJSProxyHandler.h \
   Errors.msg \
   Nullable.h \
   PrimitiveConversions.h \
   PrototypeList.h \
   RegisterBindings.h \
   TypedArray.h \
   UnionConversions.h \
   UnionTypes.h \
--- a/dom/bindings/parser/WebIDL.py
+++ b/dom/bindings/parser/WebIDL.py
@@ -2128,16 +2128,19 @@ class IDLMethod(IDLInterfaceMember, IDLS
         return self._legacycaller
 
     def isStringifier(self):
         return self._stringifier
 
     def hasOverloads(self):
         return self._hasOverloads
 
+    def isIdentifierLess(self):
+        return self.identifier.name[:2] == "__"
+
     def resolve(self, parentScope):
         assert isinstance(parentScope, IDLScope)
         IDLObjectWithIdentifier.resolve(self, parentScope)
         IDLScope.__init__(self, self.location, parentScope, self.identifier)
         for (returnType, arguments) in self.signatures():
             for argument in arguments:
                 argument.resolve(self)
 
--- a/dom/bindings/test/TestBindingHeader.h
+++ b/dom/bindings/test/TestBindingHeader.h
@@ -553,12 +553,108 @@ private:
   void PassNullableString(nsAString&, ErrorResult&) MOZ_DELETE;
   void PassOptionalString(Optional<nsAString>&, ErrorResult&) MOZ_DELETE;
   void PassOptionalStringWithDefaultValue(nsAString&, ErrorResult&) MOZ_DELETE;
   void PassOptionalNullableString(Optional<nsAString>&, ErrorResult&) MOZ_DELETE;
   void PassOptionalNullableStringWithDefaultValue(nsAString&, ErrorResult&) MOZ_DELETE;
 
 };
 
+class TestIndexedGetterInterface : public nsISupports,
+                                   public nsWrapperCache
+{
+public:
+  NS_DECL_ISUPPORTS
+
+  // We need a GetParentObject to make binding codegen happy
+  virtual nsISupports* GetParentObject();
+
+  uint32_t IndexedGetter(uint32_t, bool&, ErrorResult&);
+  uint32_t IndexedGetter(uint32_t, ErrorResult&) MOZ_DELETE;
+  uint32_t Item(uint32_t, ErrorResult&);
+  uint32_t Item(uint32_t, bool&, ErrorResult&) MOZ_DELETE;
+  uint32_t GetLength();
+};
+
+class TestNamedGetterInterface : public nsISupports,
+                                 public nsWrapperCache
+{
+public:
+  NS_DECL_ISUPPORTS
+
+  // We need a GetParentObject to make binding codegen happy
+  virtual nsISupports* GetParentObject();
+
+  void NamedGetter(const nsAString&, bool&, nsAString&, ErrorResult&);
+};
+
+class TestIndexedAndNamedGetterInterface : public nsISupports,
+                                           public nsWrapperCache
+{
+public:
+  NS_DECL_ISUPPORTS
+
+  // We need a GetParentObject to make binding codegen happy
+  virtual nsISupports* GetParentObject();
+
+  uint32_t IndexedGetter(uint32_t, bool&, ErrorResult&);
+  void NamedGetter(const nsAString&, bool&, nsAString&, ErrorResult&);
+  void NamedItem(const nsAString&, nsAString&, ErrorResult&);
+  uint32_t GetLength();
+};
+
+class TestIndexedSetterInterface : public nsISupports,
+                                   public nsWrapperCache
+{
+public:
+  NS_DECL_ISUPPORTS
+
+  // We need a GetParentObject to make binding codegen happy
+  virtual nsISupports* GetParentObject();
+
+  void IndexedSetter(uint32_t, const nsAString&, ErrorResult&);
+  void SetItem(uint32_t, const nsAString&, ErrorResult&);
+};
+
+class TestNamedSetterInterface : public nsISupports,
+                                 public nsWrapperCache
+{
+public:
+  NS_DECL_ISUPPORTS
+
+  // We need a GetParentObject to make binding codegen happy
+  virtual nsISupports* GetParentObject();
+
+  void NamedSetter(const nsAString&, TestIndexedSetterInterface&, ErrorResult&);
+};
+
+class TestIndexedAndNamedSetterInterface : public nsISupports,
+                                           public nsWrapperCache
+{
+public:
+  NS_DECL_ISUPPORTS
+
+  // We need a GetParentObject to make binding codegen happy
+  virtual nsISupports* GetParentObject();
+
+  void IndexedSetter(uint32_t, TestIndexedSetterInterface&, ErrorResult&);
+  void NamedSetter(const nsAString&, TestIndexedSetterInterface&, ErrorResult&);
+  void SetNamedItem(const nsAString&, TestIndexedSetterInterface&, ErrorResult&);
+};
+
+class TestIndexedAndNamedGetterAndSetterInterface : public TestIndexedSetterInterface
+{
+public:
+  uint32_t IndexedGetter(uint32_t, bool&, ErrorResult&);
+  uint32_t Item(uint32_t, ErrorResult&);
+  void NamedGetter(const nsAString&, bool&, nsAString&, ErrorResult&);
+  void NamedItem(const nsAString&, nsAString&, ErrorResult&);
+  void IndexedSetter(uint32_t, int32_t&, ErrorResult&);
+  void IndexedSetter(uint32_t, const nsAString&, ErrorResult&) MOZ_DELETE;
+  void NamedSetter(const nsAString&, const nsAString&, ErrorResult&);
+  void Stringify(nsAString&);
+  uint32_t GetLength();
+};
+
 } // namespace dom
 } // namespace mozilla
 
 #endif /* TestBindingHeader_h */
--- a/dom/bindings/test/TestCodeGen.webidl
+++ b/dom/bindings/test/TestCodeGen.webidl
@@ -367,8 +367,45 @@ dictionary ParentDict : GrandparentDict 
   long c = 5;
   TestInterface someInterface;
   TestExternalInterface someExternalInterface;
 };
 
 dictionary DictContainingDict {
   Dict memberDict;
 };
+
+interface TestIndexedGetterInterface {
+  getter long item(unsigned long index);
+  readonly attribute unsigned long length;
+};
+
+interface TestNamedGetterInterface {
+  getter DOMString (DOMString name);
+};
+
+interface TestIndexedAndNamedGetterInterface {
+  getter long (unsigned long index);
+  getter DOMString namedItem(DOMString name);
+  readonly attribute unsigned long length;
+};
+
+interface TestIndexedSetterInterface {
+  setter creator void setItem(unsigned long index, DOMString item);
+};
+
+interface TestNamedSetterInterface {
+  setter creator void (DOMString name, TestIndexedSetterInterface item);
+};
+
+interface TestIndexedAndNamedSetterInterface {
+  setter creator void (unsigned long index, TestIndexedSetterInterface item);
+  setter creator void setNamedItem(DOMString name, TestIndexedSetterInterface item);
+};
+
+interface TestIndexedAndNamedGetterAndSetterInterface : TestIndexedSetterInterface {
+  getter long item(unsigned long index);
+  getter DOMString namedItem(DOMString name);
+  setter creator void (unsigned long index, long item);
+  setter creator void (DOMString name, DOMString item);
+  stringifier DOMString ();
+  readonly attribute unsigned long length;
+};
--- a/dom/bluetooth/BluetoothDevice.cpp
+++ b/dom/bluetooth/BluetoothDevice.cpp
@@ -25,23 +25,27 @@ NS_IMPL_CYCLE_COLLECTION_CLASS(Bluetooth
 NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN_INHERITED(BluetoothDevice,
                                                nsDOMEventTargetHelper)
   NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mJsUuids)
 NS_IMPL_CYCLE_COLLECTION_TRACE_END
 
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(BluetoothDevice, 
                                                   nsDOMEventTargetHelper)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
-  NS_CYCLE_COLLECTION_TRAVERSE_EVENT_HANDLER(propertychanged)  
+  NS_CYCLE_COLLECTION_TRAVERSE_EVENT_HANDLER(propertychanged)
+  NS_CYCLE_COLLECTION_TRAVERSE_EVENT_HANDLER(connected)
+  NS_CYCLE_COLLECTION_TRAVERSE_EVENT_HANDLER(disconnected)
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 
 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(BluetoothDevice, 
                                                 nsDOMEventTargetHelper)
   tmp->Unroot();
-  NS_CYCLE_COLLECTION_UNLINK_EVENT_HANDLER(propertychanged)  
+  NS_CYCLE_COLLECTION_UNLINK_EVENT_HANDLER(propertychanged)
+  NS_CYCLE_COLLECTION_UNLINK_EVENT_HANDLER(connected)
+  NS_CYCLE_COLLECTION_UNLINK_EVENT_HANDLER(disconnected)
 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
 
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(BluetoothDevice)
   NS_INTERFACE_MAP_ENTRY(nsIDOMBluetoothDevice)
   NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(BluetoothDevice)
 NS_INTERFACE_MAP_END_INHERITING(nsDOMEventTargetHelper)
 
 NS_IMPL_ADDREF_INHERITED(BluetoothDevice, nsDOMEventTargetHelper)
@@ -165,19 +169,39 @@ BluetoothDevice::Create(nsPIDOMWindow* a
 
 void
 BluetoothDevice::Notify(const BluetoothSignal& aData)
 {
   if (aData.name().EqualsLiteral("PropertyChanged")) {
     // Get BluetoothNamedValue, make sure array length is 1
     BluetoothNamedValue v = aData.value().get_ArrayOfBluetoothNamedValue()[0];
     nsString name = v.name();
-    SetPropertyByValue(v);
-    nsRefPtr<BluetoothPropertyEvent> e = BluetoothPropertyEvent::Create(name);
-    e->Dispatch(ToIDOMEventTarget(), NS_LITERAL_STRING("propertychanged"));
+
+    if (name.EqualsLiteral("Connected")) {
+      bool isConnected = v.value();
+      nsRefPtr<nsDOMEvent> event = new nsDOMEvent(nullptr, nullptr);
+      nsresult rv;
+      if (isConnected) {
+        rv = event->InitEvent(NS_LITERAL_STRING("connected"), false, false);
+      } else {
+        rv = event->InitEvent(NS_LITERAL_STRING("disconnected"), false, false);
+      }
+      if (NS_FAILED(rv)) {
+        NS_WARNING("Failed to init the connected/disconnected event!!!");
+        return;
+      }
+
+      event->SetTrusted(true);
+      bool dummy;
+      DispatchEvent(event, &dummy);
+    } else {
+      SetPropertyByValue(v);
+      nsRefPtr<BluetoothPropertyEvent> e = BluetoothPropertyEvent::Create(name);
+      e->Dispatch(ToIDOMEventTarget(), NS_LITERAL_STRING("propertychanged"));
+    }
   } else {
 #ifdef DEBUG
     nsCString warningMsg;
     warningMsg.AssignLiteral("Not handling device signal: ");
     warningMsg.Append(NS_ConvertUTF16toUTF8(aData.name()));
     NS_WARNING(warningMsg.get());
 #endif
   }
@@ -226,8 +250,10 @@ BluetoothDevice::GetUuids(JSContext* aCx
   } else {
     NS_WARNING("UUIDs not yet set!\n");
     return NS_ERROR_FAILURE;
   }    
   return NS_OK;
 }
 
 NS_IMPL_EVENT_HANDLER(BluetoothDevice, propertychanged)
+NS_IMPL_EVENT_HANDLER(BluetoothDevice, connected)
+NS_IMPL_EVENT_HANDLER(BluetoothDevice, disconnected)
--- a/dom/bluetooth/BluetoothDevice.h
+++ b/dom/bluetooth/BluetoothDevice.h
@@ -70,13 +70,15 @@ private:
   nsString mName;
   uint32_t mClass;
   bool mConnected;
   bool mPaired;
   bool mIsRooted;
   nsTArray<nsString> mUuids;
 
   NS_DECL_EVENT_HANDLER(propertychanged)
+  NS_DECL_EVENT_HANDLER(connected)
+  NS_DECL_EVENT_HANDLER(disconnected)
 };
 
 END_BLUETOOTH_NAMESPACE
 
 #endif
--- a/dom/bluetooth/nsIDOMBluetoothDevice.idl
+++ b/dom/bluetooth/nsIDOMBluetoothDevice.idl
@@ -1,19 +1,21 @@
 /* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
 /* 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 "nsIDOMEventTarget.idl"
 
-[scriptable, builtinclass, uuid(24c64513-9587-46c6-b718-bb9b9a754b0d)]
+[scriptable, builtinclass, uuid(647bb64c-8d45-4642-b86b-b3b80d4c8c25)]
 interface nsIDOMBluetoothDevice : nsIDOMEventTarget
 {
   readonly attribute DOMString address;
   readonly attribute DOMString name;
   [binaryname(DeviceClass)] readonly attribute unsigned long class;
   [implicit_jscontext] readonly attribute jsval uuids;
   readonly attribute bool connected;
   readonly attribute bool paired;
   attribute nsIDOMEventListener onpropertychanged;
+  attribute nsIDOMEventListener onconnected;
+  attribute nsIDOMEventListener ondisconnected;
 };
--- a/dom/browser-element/BrowserElementParent.cpp
+++ b/dom/browser-element/BrowserElementParent.cpp
@@ -12,16 +12,17 @@
 #undef CreateEvent
 #endif
 
 #include "BrowserElementParent.h"
 #include "nsHTMLIFrameElement.h"
 #include "nsOpenWindowEventDetail.h"
 #include "nsEventDispatcher.h"
 #include "nsIDOMCustomEvent.h"
+#include "nsIInterfaceRequestorUtils.h"
 #include "nsVariant.h"
 
 using mozilla::dom::Element;
 using mozilla::dom::TabParent;
 
 namespace {
 
 /**
--- a/dom/browser-element/BrowserElementScrolling.js
+++ b/dom/browser-element/BrowserElementScrolling.js
@@ -1,16 +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/. */
 
 const ContentPanning = {
   init: function cp_init() {
     ['mousedown', 'mouseup', 'mousemove'].forEach(function(type) {
-      addEventListener(type, ContentPanning, true);
+      addEventListener(type, ContentPanning, false);
     });
 
     addMessageListener("Viewport:Change", this._recvViewportChange.bind(this));
     addMessageListener("Gesture:DoubleTap", this._recvDoubleTap.bind(this));
   },
 
   handleEvent: function cp_handleEvent(evt) {
     switch (evt.type) {
@@ -25,17 +25,17 @@ const ContentPanning = {
         break;
       case 'click':
         evt.stopPropagation();
         evt.preventDefault();
         
         let target = evt.target;
         let view = target.ownerDocument ? target.ownerDocument.defaultView
                                         : target;
-        view.removeEventListener('click', this, true, true);
+        view.removeEventListener('click', this, false, true);
         break;
     }
   },
 
   position: new Point(0 , 0),
 
   onTouchStart: function cp_onTouchStart(evt) {
     this.dragging = true;
@@ -78,17 +78,17 @@ const ContentPanning = {
 
     this.onTouchMove(evt);
 
     let click = evt.detail;
     if (this.target && click && (this.panning || this.preventNextClick)) {
       let target = this.target;
       let view = target.ownerDocument ? target.ownerDocument.defaultView
                                       : target;
-      view.addEventListener('click', this, true, true);
+      view.addEventListener('click', this, false, true);
     }
 
     if (this.panning)
       KineticPanning.start(this);
   },
 
   onTouchMove: function cp_onTouchMove(evt) {
     if (!this.dragging || !this.scrollCallback)
@@ -102,16 +102,18 @@ const ContentPanning = {
     this.scrollCallback(delta.scale(-1));
 
     // If a pan action happens, cancel the active state of the
     // current target.
     if (!this.panning && KineticPanning.isPan()) {
       this.panning = true;
       this._resetActive();
     }
+    evt.stopPropagation();
+    evt.preventDefault();
   },
 
 
   onKineticBegin: function cp_onKineticBegin(evt) {
   },
 
   onKineticPan: function cp_onKineticPan(delta) {
     return !this.scrollCallback(delta);
--- a/dom/contacts/ContactManager.js
+++ b/dom/contacts/ContactManager.js
@@ -543,17 +543,17 @@ ContactManager.prototype = {
     let request;
     request = this.createRequest();
 
     let allowCallback = function() {
       let callback = function(aType, aContacts) {
         if (DEBUG) debug("got SIM contacts: " + aType + " " + JSON.stringify(aContacts));
         let result = aContacts.map(function(c) {
           var contact = new Contact();
-          contact.init( { name: [c.alphaId], tel: [ { number: c.number } ] } );
+          contact.init( { name: [c.alphaId], tel: [ { value: c.number } ] } );
           return contact;
         });
         if (DEBUG) debug("result: " + JSON.stringify(result));
         Services.DOMRequest.fireSuccess(request, result);
       };
       if (DEBUG) debug("getSimContacts " + aType);
 
       mRIL.getICCContacts(aType, callback);
--- a/dom/indexedDB/ipc/IndexedDBChild.cpp
+++ b/dom/indexedDB/ipc/IndexedDBChild.cpp
@@ -2,16 +2,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 "base/basictypes.h"
 
 #include "IndexedDBChild.h"
 
 #include "nsIAtom.h"
+#include "nsIInputStream.h"
 
 #include "mozilla/Assertions.h"
 #include "mozilla/dom/ContentChild.h"
 
 #include "AsyncConnectionHelper.h"
 #include "DatabaseInfo.h"
 #include "IDBEvents.h"
 #include "IDBFactory.h"
--- a/dom/ipc/ContentChild.cpp
+++ b/dom/ipc/ContentChild.cpp
@@ -89,16 +89,17 @@
 
 #include "mozilla/dom/indexedDB/PIndexedDBChild.h"
 #include "mozilla/dom/sms/SmsChild.h"
 #include "mozilla/dom/devicestorage/DeviceStorageRequestChild.h"
 
 #include "nsDOMFile.h"
 #include "nsIRemoteBlob.h"
 #include "StructuredCloneUtils.h"
+#include "URIUtils.h"
 #include "nsIScriptSecurityManager.h"
 #include "nsContentUtils.h"
 #include "nsIPrincipal.h"
 
 using namespace mozilla::docshell;
 using namespace mozilla::dom::devicestorage;
 using namespace mozilla::dom::sms;
 using namespace mozilla::dom::indexedDB;
@@ -223,16 +224,18 @@ ConsoleListener::Observe(nsIConsoleMessa
 ContentChild* ContentChild::sSingleton;
 
 ContentChild::ContentChild()
  :
    mID(uint64_t(-1))
 #ifdef ANDROID
    ,mScreenSize(0, 0)
 #endif
+   , mIsForApp(false)
+   , mIsForBrowser(false)
 {
     // This process is a content process, so it's clearly running in
     // multiprocess mode!
     nsDebugImpl::SetMultiprocessMode("Child");
 }
 
 ContentChild::~ContentChild()
 {
@@ -620,22 +623,22 @@ ContentChild::AllocPNecko()
 bool 
 ContentChild::DeallocPNecko(PNeckoChild* necko)
 {
     delete necko;
     return true;
 }
 
 PExternalHelperAppChild*
-ContentChild::AllocPExternalHelperApp(const IPC::URI& uri,
+ContentChild::AllocPExternalHelperApp(const OptionalURIParams& uri,
                                       const nsCString& aMimeContentType,
                                       const nsCString& aContentDisposition,
                                       const bool& aForceSave,
                                       const int64_t& aContentLength,
-                                      const IPC::URI& aReferrer)
+                                      const OptionalURIParams& aReferrer)
 {
     ExternalHelperAppChild *child = new ExternalHelperAppChild();
     child->AddRef();
     return child;
 }
 
 bool
 ContentChild::DeallocPExternalHelperApp(PExternalHelperAppChild* aService)
@@ -781,19 +784,22 @@ ContentChild::RecvNotifyAlertsObserver(c
             }
         }
         ++i;
     }
     return true;
 }
 
 bool
-ContentChild::RecvNotifyVisited(const IPC::URI& aURI)
+ContentChild::RecvNotifyVisited(const URIParams& aURI)
 {
-    nsCOMPtr<nsIURI> newURI(aURI);
+    nsCOMPtr<nsIURI> newURI = DeserializeURI(aURI);
+    if (!newURI) {
+        return false;
+    }
     History::GetService()->NotifyVisited(newURI);
     return true;
 }
 
 bool
 ContentChild::RecvAsyncMessage(const nsString& aMsg,
                                      const ClonedMessageData& aData)
 {
@@ -931,22 +937,26 @@ ContentChild::RecvAppInfo(const nsCStrin
     mAppInfo.version.Assign(version);
     mAppInfo.buildID.Assign(buildID);
 
     PreloadSlowThings();
     return true;
 }
 
 bool
-ContentChild::RecvSetID(const uint64_t &id)
+ContentChild::RecvSetProcessAttributes(const uint64_t &id,
+                                       const bool& aIsForApp,
+                                       const bool& aIsForBrowser)
 {
     if (mID != uint64_t(-1)) {
         NS_WARNING("Setting content child's ID twice?");
     }
     mID = id;
+    mIsForApp = aIsForApp;
+    mIsForBrowser = aIsForBrowser;
     return true;
 }
 
 bool
 ContentChild::RecvLastPrivateDocShellDestroyed()
 {
     nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
     obs->NotifyObservers(nullptr, "last-pb-context-exited", nullptr);
--- a/dom/ipc/ContentChild.h
+++ b/dom/ipc/ContentChild.h
@@ -17,32 +17,39 @@
 struct ChromePackage;
 class nsIDOMBlob;
 class nsIObserver;
 struct ResourceMapping;
 struct OverrideMapping;
 
 namespace mozilla {
 
+namespace ipc {
+class OptionalURIParams;
+class URIParams;
+}// namespace ipc
+
 namespace layers {
 class PCompositorChild;
-}
+} // namespace layers
 
 namespace dom {
 
 class AlertObserver;
 class PrefObserver;
 class ConsoleListener;
 class PStorageChild;
 class ClonedMessageData;
 
 class ContentChild : public PContentChild
 {
     typedef layers::PCompositorChild PCompositorChild;
     typedef mozilla::dom::ClonedMessageData ClonedMessageData;
+    typedef mozilla::ipc::OptionalURIParams OptionalURIParams;
+    typedef mozilla::ipc::URIParams URIParams;
 
 public:
     ContentChild();
     virtual ~ContentChild();
 
     struct AppInfo
     {
         nsCString version;
@@ -106,38 +113,38 @@ public:
                                      const int32_t&,
                                      const int32_t&);
     virtual bool DeallocPAudio(PAudioChild*);
 
     virtual PNeckoChild* AllocPNecko();
     virtual bool DeallocPNecko(PNeckoChild*);
 
     virtual PExternalHelperAppChild *AllocPExternalHelperApp(
-            const IPC::URI& uri,
+            const OptionalURIParams& uri,
             const nsCString& aMimeContentType,
             const nsCString& aContentDisposition,
             const bool& aForceSave,
             const int64_t& aContentLength,
-            const IPC::URI& aReferrer);
+            const OptionalURIParams& aReferrer);
     virtual bool DeallocPExternalHelperApp(PExternalHelperAppChild *aService);
 
     virtual PSmsChild* AllocPSms();
     virtual bool DeallocPSms(PSmsChild*);
 
     virtual PStorageChild* AllocPStorage(const StorageConstructData& aData);
     virtual bool DeallocPStorage(PStorageChild* aActor);
 
     virtual bool RecvRegisterChrome(const InfallibleTArray<ChromePackage>& packages,
                                     const InfallibleTArray<ResourceMapping>& resources,
                                     const InfallibleTArray<OverrideMapping>& overrides,
                                     const nsCString& locale);
 
     virtual bool RecvSetOffline(const bool& offline);
 
-    virtual bool RecvNotifyVisited(const IPC::URI& aURI);
+    virtual bool RecvNotifyVisited(const URIParams& aURI);
     // auto remove when alertfinished is received.
     nsresult AddRemoteAlertObserver(const nsString& aData, nsIObserver* aObserver);
 
     virtual bool RecvPreferenceUpdate(const PrefSetting& aPref);
 
     virtual bool RecvNotifyAlertsObserver(const nsCString& aType, const nsString& aData);
 
     virtual bool RecvAsyncMessage(const nsString& aMsg,
@@ -152,33 +159,38 @@ public:
     virtual bool RecvFlushMemory(const nsString& reason);
 
     virtual bool RecvActivateA11y();
 
     virtual bool RecvGarbageCollect();
     virtual bool RecvCycleCollect();
 
     virtual bool RecvAppInfo(const nsCString& version, const nsCString& buildID);
-    virtual bool RecvSetID(const uint64_t &id);
+    virtual bool RecvSetProcessAttributes(const uint64_t& id,
+                                          const bool& aIsForApp,
+                                          const bool& aIsForBrowser);
 
     virtual bool RecvLastPrivateDocShellDestroyed();
 
     virtual bool RecvFilePathUpdate(const nsString& path, const nsCString& reason);
     virtual bool RecvFileSystemUpdate(const nsString& aFsName, const nsString& aName, const int32_t& aState);
 
 #ifdef ANDROID
     gfxIntSize GetScreenSize() { return mScreenSize; }
 #endif
 
     // Get the directory for IndexedDB files. We query the parent for this and
     // cache the value
     nsString &GetIndexedDBPath();
 
     uint64_t GetID() { return mID; }
 
+    bool IsForApp() { return mIsForApp; }
+    bool IsForBrowser() { return mIsForBrowser; }
+
     BlobChild* GetOrCreateActorForBlob(nsIDOMBlob* aBlob);
 
 private:
     virtual void ActorDestroy(ActorDestroyReason why) MOZ_OVERRIDE;
 
     virtual void ProcessingError(Result what) MOZ_OVERRIDE;
 
     /**
@@ -200,16 +212,19 @@ private:
     uint64_t mID;
 
     AppInfo mAppInfo;
 
 #ifdef ANDROID
     gfxIntSize mScreenSize;
 #endif
 
+    bool mIsForApp;
+    bool mIsForBrowser;
+
     static ContentChild* sSingleton;
 
     DISALLOW_EVIL_CONSTRUCTORS(ContentChild);
 };
 
 } // namespace dom
 } // namespace mozilla
 
--- a/dom/ipc/ContentParent.cpp
+++ b/dom/ipc/ContentParent.cpp
@@ -71,16 +71,17 @@
 #include "nsServiceManagerUtils.h"
 #include "nsSystemInfo.h"
 #include "nsThreadUtils.h"
 #include "nsToolkitCompsCID.h"
 #include "nsWidgetsCID.h"
 #include "SandboxHal.h"
 #include "StructuredCloneUtils.h"
 #include "TabParent.h"
+#include "URIUtils.h"
 
 #ifdef ANDROID
 # include "gfxAndroidPlatform.h"
 #endif
 
 #ifdef MOZ_CRASHREPORTER
 # include "nsExceptionHandler.h"
 # include "nsICrashReporter.h"
@@ -181,17 +182,18 @@ ContentParent::PreallocateAppProcess()
 
     if (sPreallocateAppProcessTask) {
         // We were called directly while a delayed task was scheduled.
         sPreallocateAppProcessTask->Cancel();
         sPreallocateAppProcessTask = nullptr;
     }
 
     sPreallocatedAppProcess =
-        new ContentParent(MAGIC_PREALLOCATED_APP_MANIFEST_URL);
+        new ContentParent(MAGIC_PREALLOCATED_APP_MANIFEST_URL,
+                          /*isBrowserElement=*/false);
     sPreallocatedAppProcess->Init();
 }
 
 /*static*/ void
 ContentParent::DelayedPreallocateAppProcess()
 {
     sPreallocateAppProcessTask = nullptr;
     if (!sPreallocatedAppProcess) {
@@ -243,44 +245,51 @@ ContentParent::StartUp()
 /*static*/ void
 ContentParent::ShutDown()
 {
     // No-op for now.  We rely on normal process shutdown and
     // ClearOnShutdown() to clean up our state.
 }
 
 /*static*/ ContentParent*
-ContentParent::GetNewOrUsed()
+ContentParent::GetNewOrUsed(bool aForBrowserElement)
 {
     if (!gNonAppContentParents)
         gNonAppContentParents = new nsTArray<ContentParent*>();
 
     int32_t maxContentProcesses = Preferences::GetInt("dom.ipc.processCount", 1);
     if (maxContentProcesses < 1)
         maxContentProcesses = 1;
 
     if (gNonAppContentParents->Length() >= uint32_t(maxContentProcesses)) {
         uint32_t idx = rand() % gNonAppContentParents->Length();
         ContentParent* p = (*gNonAppContentParents)[idx];
         NS_ASSERTION(p->IsAlive(), "Non-alive contentparent in gNonAppContentParents?");
         return p;
     }
 
     nsRefPtr<ContentParent> p =
-        new ContentParent(/* appManifestURL = */ EmptyString());
+        new ContentParent(/* appManifestURL = */ EmptyString(),
+                          aForBrowserElement);
     p->Init();
     gNonAppContentParents->AppendElement(p);
     return p;
 }
 
 /*static*/ TabParent*
 ContentParent::CreateBrowser(mozIApplication* aApp, bool aIsBrowserElement)
 {
+    // We currently don't set the <app> ancestor for <browser> content
+    // correctly.  This assertion is to notify the person who fixes
+    // this code that they need to reevaluate places here where we may
+    // make bad assumptions based on that bug.
+    MOZ_ASSERT(!aApp || !aIsBrowserElement);
+
     if (!aApp) {
-        if (ContentParent* cp = GetNewOrUsed()) {
+        if (ContentParent* cp = GetNewOrUsed(aIsBrowserElement)) {
             nsRefPtr<TabParent> tp(new TabParent(aApp, aIsBrowserElement));
             return static_cast<TabParent*>(
                 cp->SendPBrowserConstructor(
                     // DeallocPBrowserParent() releases the ref we take here
                     tp.forget().get(),
                     /*chromeFlags*/0,
                     aIsBrowserElement, nsIScriptSecurityManager::NO_APP_ID));
         }
@@ -316,17 +325,17 @@ ContentParent::CreateBrowser(mozIApplica
 
     nsRefPtr<ContentParent> p = gAppContentParents->Get(manifestURL);
     if (!p) {
         p = MaybeTakePreallocatedAppProcess();
         if (p) {
             p->SetManifestFromPreallocated(manifestURL);
         } else {
             NS_WARNING("Unable to use pre-allocated app process");
-            p = new ContentParent(manifestURL);
+            p = new ContentParent(manifestURL, aIsBrowserElement);
             p->Init();
         }
         gAppContentParents->Put(manifestURL, p);
     }
 
     nsRefPtr<TabParent> tp(new TabParent(aApp, aIsBrowserElement));
     return static_cast<TabParent*>(
         // DeallocPBrowserParent() releases the ref we take here
@@ -642,17 +651,18 @@ ContentParent::DestroyTestShell(TestShel
 TestShellParent*
 ContentParent::GetTestShellSingleton()
 {
     if (!ManagedPTestShellParent().Length())
         return nullptr;
     return static_cast<TestShellParent*>(ManagedPTestShellParent()[0]);
 }
 
-ContentParent::ContentParent(const nsAString& aAppManifestURL)
+ContentParent::ContentParent(const nsAString& aAppManifestURL,
+                             bool aIsForBrowser)
     : mGeolocationWatchID(-1)
     , mRunToCompletionDepth(0)
     , mShouldCallUnblockChild(false)
     , mIsAlive(true)
     , mSendPermissionUpdates(false)
     , mAppManifestURL(aAppManifestURL)
 {
     // From this point on, NS_WARNING, NS_ASSERTION, etc. should print out the
@@ -666,17 +676,18 @@ ContentParent::ContentParent(const nsASt
     if (useOffMainThreadCompositing) {
         // We need the subprocess's ProcessHandle to create the
         // PCompositor channel below.  Block just until we have that.
         mSubprocess->LaunchAndWaitForProcessHandle();
     } else {
         mSubprocess->AsyncLaunch();
     }
     Open(mSubprocess->GetChannel(), mSubprocess->GetChildProcessHandle());
-    unused << SendSetID(gContentChildID++);
+    unused << SendSetProcessAttributes(gContentChildID++,
+                                       IsForApp(), aIsForBrowser);
 
     // NB: internally, this will send an IPC message to the child
     // process to get it to create the CompositorChild.  This
     // message goes through the regular IPC queue for this
     // channel, so delivery will happen-before any other messages
     // we send.  The CompositorChild must be created before any
     // PBrowsers are created, because they rely on the Compositor
     // already being around.  (Creation is async, so can't happen
@@ -1338,22 +1349,22 @@ ContentParent::AllocPNecko()
 bool 
 ContentParent::DeallocPNecko(PNeckoParent* necko)
 {
     delete necko;
     return true;
 }
 
 PExternalHelperAppParent*
-ContentParent::AllocPExternalHelperApp(const IPC::URI& uri,
+ContentParent::AllocPExternalHelperApp(const OptionalURIParams& uri,
                                        const nsCString& aMimeContentType,
                                        const nsCString& aContentDisposition,
                                        const bool& aForceSave,
                                        const int64_t& aContentLength,
-                                       const IPC::URI& aReferrer)
+                                       const OptionalURIParams& aReferrer)
 {
     ExternalHelperAppParent *parent = new ExternalHelperAppParent(uri, aContentLength);
     parent->AddRef();
     parent->Init(this, aMimeContentType, aContentDisposition, aForceSave, aReferrer);
     return parent;
 }
 
 bool
@@ -1415,53 +1426,62 @@ ContentParent::RequestRunToCompletion()
 #endif
         mRunToCompletionDepth = 1;
         mShouldCallUnblockChild = true;
     }
     return !!mRunToCompletionDepth;
 }
 
 bool
-ContentParent::RecvStartVisitedQuery(const IPC::URI& aURI)
+ContentParent::RecvStartVisitedQuery(const URIParams& aURI)
 {
-    nsCOMPtr<nsIURI> newURI(aURI);
+    nsCOMPtr<nsIURI> newURI = DeserializeURI(aURI);
+    if (!newURI) {
+        return false;
+    }
     nsCOMPtr<IHistory> history = services::GetHistoryService();
     NS_ABORT_IF_FALSE(history, "History must exist at this point.");
     if (history) {
-      history->RegisterVisitedCallback(newURI, nullptr);
+        history->RegisterVisitedCallback(newURI, nullptr);
     }
     return true;
 }
 
 
 bool
-ContentParent::RecvVisitURI(const IPC::URI& uri,
-                                   const IPC::URI& referrer,
-                                   const uint32_t& flags)
+ContentParent::RecvVisitURI(const URIParams& uri,
+                            const OptionalURIParams& referrer,
+                            const uint32_t& flags)
 {
-    nsCOMPtr<nsIURI> ourURI(uri);
-    nsCOMPtr<nsIURI> ourReferrer(referrer);
+    nsCOMPtr<nsIURI> ourURI = DeserializeURI(uri);
+    if (!ourURI) {
+        return false;
+    }
+    nsCOMPtr<nsIURI> ourReferrer = DeserializeURI(referrer);
     nsCOMPtr<IHistory> history = services::GetHistoryService();
     NS_ABORT_IF_FALSE(history, "History must exist at this point");
     if (history) {
-      history->VisitURI(ourURI, ourReferrer, flags);
+        history->VisitURI(ourURI, ourReferrer, flags);
     }
     return true;
 }
 
 
 bool
-ContentParent::RecvSetURITitle(const IPC::URI& uri,
-                                      const nsString& title)
+ContentParent::RecvSetURITitle(const URIParams& uri,
+                               const nsString& title)
 {
-    nsCOMPtr<nsIURI> ourURI(uri);
+    nsCOMPtr<nsIURI> ourURI = DeserializeURI(uri);
+    if (!ourURI) {
+        return false;
+    }
     nsCOMPtr<IHistory> history = services::GetHistoryService();
     NS_ABORT_IF_FALSE(history, "History must exist at this point");
     if (history) {
-      history->SetURITitle(ourURI, title);
+        history->SetURITitle(ourURI, title);
     }
     return true;
 }
 
 bool
 ContentParent::RecvShowFilePicker(const int16_t& mode,
                                   const int16_t& selectedType,
                                   const bool& addToRecentDocs,
@@ -1532,22 +1552,26 @@ ContentParent::RecvShowFilePicker(const 
         file->GetPath(filePath);
         files->AppendElement(filePath);
     }
 
     return true;
 }
 
 bool
-ContentParent::RecvLoadURIExternal(const IPC::URI& uri)
+ContentParent::RecvLoadURIExternal(const URIParams& uri)
 {
     nsCOMPtr<nsIExternalProtocolService> extProtService(do_GetService(NS_EXTERNALPROTOCOLSERVICE_CONTRACTID));
-    if (!extProtService)
+    if (!extProtService) {
         return true;
-    nsCOMPtr<nsIURI> ourURI(uri);
+    }
+    nsCOMPtr<nsIURI> ourURI = DeserializeURI(uri);
+    if (!ourURI) {
+        return false;
+    }
     extProtService->LoadURI(ourURI, nullptr);
     return true;
 }
 
 /* void onDispatchedEvent (in nsIThreadInternal thread); */
 NS_IMETHODIMP
 ContentParent::OnDispatchedEvent(nsIThreadInternal *thread)
 {
--- a/dom/ipc/ContentParent.h
+++ b/dom/ipc/ContentParent.h
@@ -27,50 +27,53 @@
 
 class mozIApplication;
 class nsFrameMessageManager;
 class nsIDOMBlob;
 
 namespace mozilla {
 
 namespace ipc {
+class OptionalURIParams;
+class URIParams;
 class TestShellParent;
-}
+} // namespace ipc
 
 namespace layers {
 class PCompositorParent;
-}
+} // namespace layers
 
 namespace dom {
 
 class TabParent;
 class PStorageParent;
 class ClonedMessageData;
 
 class ContentParent : public PContentParent
                     , public nsIObserver
                     , public nsIThreadObserver
                     , public nsIDOMGeoPositionCallback
 {
-private:
     typedef mozilla::ipc::GeckoChildProcessHost GeckoChildProcessHost;
+    typedef mozilla::ipc::OptionalURIParams OptionalURIParams;
     typedef mozilla::ipc::TestShellParent TestShellParent;
+    typedef mozilla::ipc::URIParams URIParams;
     typedef mozilla::layers::PCompositorParent PCompositorParent;
     typedef mozilla::dom::ClonedMessageData ClonedMessageData;
 
 public:
     /**
      * Start up the content-process machinery.  This might include
      * scheduling pre-launch tasks.
      */
     static void StartUp();
     /** Shut down the content-process machinery. */
     static void ShutDown();
 
-    static ContentParent* GetNewOrUsed();
+    static ContentParent* GetNewOrUsed(bool aForBrowserElement = false);
 
     /**
      * Get or create a content process for the given app descriptor,
      * which may be null.  This function will assign processes to app
      * or non-app browsers by internal heuristics.
      *
      * Currently apps are given their own process, and browser tabs
      * share processes.
@@ -124,17 +127,17 @@ private:
     static void ScheduleDelayedPreallocateAppProcess();
     static already_AddRefed<ContentParent> MaybeTakePreallocatedAppProcess();
 
     // Hide the raw constructor methods since we don't want client code
     // using them.
     using PContentParent::SendPBrowserConstructor;
     using PContentParent::SendPTestShellConstructor;
 
-    ContentParent(const nsAString& aAppManifestURL);
+    ContentParent(const nsAString& aAppManifestURL, bool aIsForBrowser);
     virtual ~ContentParent();
 
     void Init();
 
     // Transform a pre-allocated app process into a "real" app
     // process, for the specified manifest URL.
     void SetManifestFromPreallocated(const nsAString& aAppManifestURL);
 
@@ -193,22 +196,22 @@ private:
                                      const int32_t&,
                                      const int32_t&);
     virtual bool DeallocPAudio(PAudioParent*);
 
     virtual PNeckoParent* AllocPNecko();
     virtual bool DeallocPNecko(PNeckoParent* necko);
 
     virtual PExternalHelperAppParent* AllocPExternalHelperApp(
-            const IPC::URI& uri,
+            const OptionalURIParams& aUri,
             const nsCString& aMimeContentType,
             const nsCString& aContentDisposition,
             const bool& aForceSave,
             const int64_t& aContentLength,
-            const IPC::URI& aReferrer);
+            const OptionalURIParams& aReferrer);
     virtual bool DeallocPExternalHelperApp(PExternalHelperAppParent* aService);
 
     virtual PSmsParent* AllocPSms();
     virtual bool DeallocPSms(PSmsParent*);
 
     virtual PStorageParent* AllocPStorage(const StorageConstructData& aData);
     virtual bool DeallocPStorage(PStorageParent* aActor);
 
@@ -221,23 +224,23 @@ private:
     virtual bool RecvGetClipboardText(const int32_t& whichClipboard, nsString* text);
     virtual bool RecvEmptyClipboard();
     virtual bool RecvClipboardHasText(bool* hasText);
 
     virtual bool RecvGetSystemColors(const uint32_t& colorsCount, InfallibleTArray<uint32_t>* colors);
     virtual bool RecvGetIconForExtension(const nsCString& aFileExt, const uint32_t& aIconSize, InfallibleTArray<uint8_t>* bits);
     virtual bool RecvGetShowPasswordSetting(bool* showPassword);
 
-    virtual bool RecvStartVisitedQuery(const IPC::URI& uri);
+    virtual bool RecvStartVisitedQuery(const URIParams& uri);
 
-    virtual bool RecvVisitURI(const IPC::URI& uri,
-                              const IPC::URI& referrer,
+    virtual bool RecvVisitURI(const URIParams& uri,
+                              const OptionalURIParams& referrer,
                               const uint32_t& flags);
 
-    virtual bool RecvSetURITitle(const IPC::URI& uri,
+    virtual bool RecvSetURITitle(const URIParams& uri,
                                  const nsString& title);
     
     virtual bool RecvShowFilePicker(const int16_t& mode,
                                     const int16_t& selectedType,
                                     const bool& addToRecentDocs,
                                     const nsString& title,
                                     const nsString& defaultFile,
                                     const nsString& defaultExtension,
@@ -246,17 +249,17 @@ private:
                                     InfallibleTArray<nsString>* files,
                                     int16_t* retValue,
                                     nsresult* result);
  
     virtual bool RecvShowAlertNotification(const nsString& aImageUrl, const nsString& aTitle,
                                            const nsString& aText, const bool& aTextClickable,
                                            const nsString& aCookie, const nsString& aName);
 
-    virtual bool RecvLoadURIExternal(const IPC::URI& uri);
+    virtual bool RecvLoadURIExternal(const URIParams& uri);
 
     virtual bool RecvSyncMessage(const nsString& aMsg,
                                  const ClonedMessageData& aData,
                                  InfallibleTArray<nsString>* aRetvals);
     virtual bool RecvAsyncMessage(const nsString& aMsg,
                                   const ClonedMessageData& aData);
 
     virtual bool RecvAddGeolocationListener();
--- a/dom/ipc/PBlobStream.ipdl
+++ b/dom/ipc/PBlobStream.ipdl
@@ -1,14 +1,14 @@
 /* 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 protocol PBlob;
-include IPCSerializableParams;
+include InputStreamParams;
 
 namespace mozilla {
 namespace dom {
 
 protocol PBlobStream
 {
   manager PBlob;
 
--- a/dom/ipc/PBrowser.ipdl
+++ b/dom/ipc/PBrowser.ipdl
@@ -8,28 +8,26 @@
 include protocol PBlob;
 include protocol PContent;
 include protocol PContentDialog;
 include protocol PDocumentRenderer;
 include protocol PContentPermissionRequest;
 include protocol PRenderFrame;
 include protocol POfflineCacheUpdate;
 include protocol PIndexedDB;
+include DOMTypes;
+include URIParams;
 
 include "gfxMatrix.h";
 include "FrameMetrics.h";
 include "IPC/nsGUIEventIPC.h";
 include "mozilla/dom/TabMessageUtils.h";
 include "mozilla/dom/PermissionMessageUtils.h";
 include "mozilla/layout/RenderFrameUtils.h";
-include "mozilla/net/NeckoMessageUtils.h";
 
-include DOMTypes;
-
-using IPC::URI;
 using IPC::Principal;
 using gfxMatrix;
 using gfxRect;
 using gfxSize;
 using mozilla::layers::LayersBackend;
 using mozilla::layers::FrameMetrics;
 using mozilla::layout::ScrollingBehavior;
 using mozilla::WindowsHandle;
@@ -225,18 +223,18 @@ parent:
      *   Why this argument? If the document was not found in an offline cache 
      *   before load and refers a manifest and this manifest itself has not 
      *   been changed since the last fetch, we will not do the application 
      *   cache group update. But we must cache the document (identified by the
      *   documentURI). This argument will ensure that a previously uncached 
      *   document will get cached and that we don't re-cache a document that 
      *   has already been cached (stickDocument=false).
      */
-    POfflineCacheUpdate(URI manifestURI, URI documentURI, nsCString clientID,
-                        bool stickDocument);
+    POfflineCacheUpdate(URIParams manifestURI, URIParams documentURI,
+                        nsCString clientID, bool stickDocument);
 
     sync PIndexedDB(nsCString asciiOrigin)
         returns (bool allowed);
 
     /**
      * window.open from inside <iframe mozbrowser> is special.  When the child
      * process calls window.open, it creates a new PBrowser (in its own
      * process), then calls BrowserFrameOpenWindow on it.
--- a/dom/ipc/PContent.ipdl
+++ b/dom/ipc/PContent.ipdl
@@ -13,32 +13,31 @@ include protocol PExternalHelperApp;
 include protocol PDeviceStorageRequest;
 include protocol PHal;
 include protocol PIndexedDB;
 include protocol PMemoryReportRequest;
 include protocol PNecko;
 include protocol PSms;
 include protocol PStorage;
 include protocol PTestShell;
+include DOMTypes;
+include URIParams;
 
 include "mozilla/chrome/RegistryMessageUtils.h";
 include "mozilla/net/NeckoMessageUtils.h";
 include "mozilla/dom/TabMessageUtils.h";
 
 include "nsGeoPositionIPCSerialiser.h";
 
-include DOMTypes;
-
 using GeoPosition;
 using PrefTuple;
 
 using ChromePackage;
 using ResourceMapping;
 using OverrideMapping;
-using IPC::URI;
 using IPC::Permission;
 using mozilla::null_t;
 using mozilla::void_t;
 using mozilla::dom::NativeThreadId;
 using gfxIntSize;
 
 namespace mozilla {
 namespace dom {
@@ -187,22 +186,33 @@ both:
 
     async PBlob(BlobConstructorParams params);
 
 child:
     PMemoryReportRequest();
 
     PTestShell();
 
+    /**
+     * Tell the content process some attributes of itself.  This is
+     * the first message received by content processes after startup.
+     *
+     * |id| is a unique ID among all subprocesses.  When |isForApp &&
+     * isForBrowser|, we're loading <browser> for an app.  When
+     * |isForBrowser|, we're loading <browser>.  When |!isForApp &&
+     * !isForBrowser|, we're probably loading <xul:browser remote>.
+     */
+    SetProcessAttributes(uint64_t id, bool isForApp, bool isForBrowser);
+
     RegisterChrome(ChromePackage[] packages, ResourceMapping[] resources,
                    OverrideMapping[] overrides, nsCString locale);
 
     async SetOffline(bool offline);
 
-    async NotifyVisited(URI uri);
+    async NotifyVisited(URIParams uri);
 
     PreferenceUpdate(PrefSetting pref);
 
     NotifyAlertsObserver(nsCString topic, nsString data);
 
     GeolocationUpdate(GeoPosition somewhere);
 
     // nsIPermissionManager messages
@@ -217,18 +227,16 @@ child:
     
     /**
      * Start accessibility engine in content process.
      */
     ActivateA11y();
 
     AppInfo(nsCString version, nsCString buildID);
 
-    SetID(uint64_t id);
-
     // Notify child that last-pb-context-exited notification was observed
     LastPrivateDocShellDestroyed();
 
     FilePathUpdate(nsString filepath, nsCString reasons);
 
     FileSystemUpdate(nsString fsName, nsString mountPoint, int32_t fsState);
 
 parent:
@@ -245,47 +253,47 @@ parent:
     PNecko();
 
     PSms();
     
     PStorage(StorageConstructData data);
 
     // Services remoting
 
-    async StartVisitedQuery(URI uri);
-    async VisitURI(URI uri, URI referrer, uint32_t flags);
-    async SetURITitle(URI uri, nsString title);
+    async StartVisitedQuery(URIParams uri);
+    async VisitURI(URIParams uri, OptionalURIParams referrer, uint32_t flags);
+    async SetURITitle(URIParams uri, nsString title);
     
     // filepicker remoting
     sync ShowFilePicker(int16_t mode, int16_t selectedType, bool addToRecentDocs,
                         nsString title, nsString defaultFile, nsString defaultExtension,
                         nsString[] filters, nsString[] filterNames)
         returns (nsString[] files, int16_t retValue, nsresult result);
 
-    async LoadURIExternal(URI uri);
+    async LoadURIExternal(URIParams uri);
 
     // PrefService message
     sync ReadPrefsArray() returns (PrefSetting[] prefs);
 
     sync ReadFontList() returns (FontListEntry[] retValue);
 
     sync SyncMessage(nsString aMessage, ClonedMessageData aData)
       returns (nsString[] retval);
 
     ShowAlertNotification(nsString imageUrl, 
                           nsString title, 
                           nsString text, 
                           bool textClickable,
                           nsString cookie,
                           nsString name);
 
-    PExternalHelperApp(URI uri, nsCString aMimeContentType,
+    PExternalHelperApp(OptionalURIParams uri, nsCString aMimeContentType,
                        nsCString aContentDisposition, bool aForceSave,
-                       int64_t aContentLength, URI aReferrer);
-    
+                       int64_t aContentLength, OptionalURIParams aReferrer);
+
     AddGeolocationListener();
     RemoveGeolocationListener();
 
     ConsoleMessage(nsString message);
     ScriptError(nsString message, nsString sourceName, nsString sourceLine,
                 uint32_t lineNumber, uint32_t colNumber, uint32_t flags,
                 nsCString category); 
 
@@ -313,9 +321,9 @@ parent:
     // Notify the parent of the presence or absence of private docshells
     PrivateDocShellsExist(bool aExist);
 
 both:
      AsyncMessage(nsString aMessage, ClonedMessageData aData);
 };
 
 }
-}
+}
\ No newline at end of file
--- a/dom/ipc/PContentPermissionRequest.ipdl
+++ b/dom/ipc/PContentPermissionRequest.ipdl
@@ -1,16 +1,13 @@
 /* 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 protocol PBrowser;
-include "mozilla/net/NeckoMessageUtils.h";
-
-using IPC::URI;
 
 namespace mozilla {
 namespace dom {
 
 protocol PContentPermissionRequest
 {
   manager PBrowser;
 
--- a/dom/ipc/TabChild.cpp
+++ b/dom/ipc/TabChild.cpp
@@ -1025,18 +1025,18 @@ TabChild::RecvActivateFrameEvent(const n
   NS_ENSURE_TRUE(chromeHandler, true);
   nsRefPtr<ContentListener> listener = new ContentListener(this);
   NS_ENSURE_TRUE(listener, true);
   chromeHandler->AddEventListener(aType, listener, capture);
   return true;
 }
 
 POfflineCacheUpdateChild*
-TabChild::AllocPOfflineCacheUpdate(const URI& manifestURI,
-            const URI& documentURI,
+TabChild::AllocPOfflineCacheUpdate(const URIParams& manifestURI,
+            const URIParams& documentURI,
             const nsCString& clientID,
             const bool& stickDocument)
 {
   NS_RUNTIMEABORT("unused");
   return nullptr;
 }
 
 bool
--- a/dom/ipc/TabChild.h
+++ b/dom/ipc/TabChild.h
@@ -240,18 +240,18 @@ public:
       child->mIPCOpen = true;
       return request;
     }
 #endif /* DEBUG */
 
     virtual PContentPermissionRequestChild* AllocPContentPermissionRequest(const nsCString& aType, const IPC::Principal& aPrincipal);
     virtual bool DeallocPContentPermissionRequest(PContentPermissionRequestChild* actor);
 
-    virtual POfflineCacheUpdateChild* AllocPOfflineCacheUpdate(const URI& manifestURI,
-            const URI& documentURI,
+    virtual POfflineCacheUpdateChild* AllocPOfflineCacheUpdate(const URIParams& manifestURI,
+            const URIParams& documentURI,
             const nsCString& clientID,
             const bool& stickDocument);
     virtual bool DeallocPOfflineCacheUpdate(POfflineCacheUpdateChild* offlineCacheUpdate);
 
     nsIWebNavigation* WebNavigation() { return mWebNav; }
 
     JSContext* GetJSContext() { return mCx; }
 
--- a/dom/ipc/TabParent.cpp
+++ b/dom/ipc/TabParent.cpp
@@ -949,18 +949,18 @@ TabParent::AllocPRenderFrame(ScrollingBe
 bool
 TabParent::DeallocPRenderFrame(PRenderFrameParent* aFrame)
 {
   delete aFrame;
   return true;
 }
 
 mozilla::docshell::POfflineCacheUpdateParent*
-TabParent::AllocPOfflineCacheUpdate(const URI& aManifestURI,
-                                    const URI& aDocumentURI,
+TabParent::AllocPOfflineCacheUpdate(const URIParams& aManifestURI,
+                                    const URIParams& aDocumentURI,
                                     const nsCString& aClientID,
                                     const bool& stickDocument)
 {
   nsRefPtr<mozilla::docshell::OfflineCacheUpdateParent> update =
     new mozilla::docshell::OfflineCacheUpdateParent();
 
   nsresult rv = update->Schedule(aManifestURI, aDocumentURI, aClientID,
                                  stickDocument);
--- a/dom/ipc/TabParent.h
+++ b/dom/ipc/TabParent.h
@@ -154,18 +154,18 @@ public:
                            const nsIntSize& renderSize);
     virtual bool DeallocPDocumentRenderer(PDocumentRendererParent* actor);
 
     virtual PContentPermissionRequestParent*
     AllocPContentPermissionRequest(const nsCString& aType, const IPC::Principal& aPrincipal);
     virtual bool DeallocPContentPermissionRequest(PContentPermissionRequestParent* actor);
 
     virtual POfflineCacheUpdateParent* AllocPOfflineCacheUpdate(
-            const URI& aManifestURI,
-            const URI& aDocumentURI,
+            const URIParams& aManifestURI,
+            const URIParams& aDocumentURI,
             const nsCString& aClientID,
             const bool& stickDocument);
     virtual bool DeallocPOfflineCacheUpdate(POfflineCacheUpdateParent* actor);
 
     JSBool GetGlobalJSObject(JSContext* cx, JSObject** globalp);
 
     NS_DECL_ISUPPORTS
     NS_DECL_NSIAUTHPROMPTPROVIDER
--- a/dom/messages/SystemMessageManager.js
+++ b/dom/messages/SystemMessageManager.js
@@ -23,18 +23,18 @@ XPCOMUtils.defineLazyGetter(this, "cpmm"
 let kMaxPendingMessages;
 try {
   kMaxPendingMessages = Services.prefs.getIntPref("dom.messages.maxPendingMessages");
 } catch(e) {
   // getIntPref throws when the pref is not set.
   kMaxPendingMessages = 5;
 }
 
-function debug(aMsg) { 
-  //dump("-- SystemMessageManager " + Date.now() + " : " + aMsg + "\n"); 
+function debug(aMsg) {
+  //dump("-- SystemMessageManager " + Date.now() + " : " + aMsg + "\n");
 }
 
 // Implementation of the DOM API for system messages
 
 function SystemMessageManager() {
   // Message handlers for this page.
   // We can have only one handler per message type.
   this._handlers = {};
@@ -49,27 +49,29 @@ SystemMessageManager.prototype = {
   _dispatchMessage: function sysMessMgr_dispatchMessage(aType, aHandler, aMessage) {
     // We get a json blob, but in some cases we want another kind of object
     // to be dispatched.
     // To do so, we check if we have a with a contract ID of
     // "@mozilla.org/dom/system-messages/wrapper/TYPE;1" component implementing
     // nsISystemMessageWrapper.
     debug("Dispatching " + JSON.stringify(aMessage) + "\n");
     let contractID = "@mozilla.org/dom/system-messages/wrapper/" + aType + ";1";
+    let wrapped = false;
 
     if (contractID in Cc) {
       debug(contractID + " is registered, creating an instance");
       let wrapper = Cc[contractID].createInstance(Ci.nsISystemMessagesWrapper);
       if (wrapper) {
         aMessage = wrapper.wrapMessage(aMessage);
+        wrapped = true;
         debug("wrapped = " + aMessage);
       }
     }
 
-    aHandler.handleMessage(ObjectWrapper.wrap(aMessage, this._window));
+    aHandler.handleMessage(wrapped ? aMessage : ObjectWrapper.wrap(aMessage, this._window));
   },
 
   mozSetMessageHandler: function sysMessMgr_setMessageHandler(aType, aHandler) {
     debug("setMessage handler for [" + aType + "] " + aHandler);
     if (!aType) {
       // Just bail out if we have no type.
       return;
     }
@@ -107,19 +109,19 @@ SystemMessageManager.prototype = {
 
     // If we have a handler for this type, we can't have any pending message.
     // If called from setMessageHandler, we still want to update the pending
     // queue to deliver existing messages.
     if (aType in this._handlers && !aForceUpdate) {
       return false;
     }
 
-    // Send a sync message to the parent to check if we have a pending message 
+    // Send a sync message to the parent to check if we have a pending message
     // for this type.
-    let messages = cpmm.sendSyncMessage("SystemMessageManager:GetPending", 
+    let messages = cpmm.sendSyncMessage("SystemMessageManager:GetPending",
                                         { type: aType,
                                           uri: this._uri,
                                           manifest: this._manifest })[0];
     if (!messages) {
       // No new pending messages, but the queue may not be empty yet.
       return pendings[aType] && pendings[aType].length != 0;
     }
 
@@ -143,17 +145,17 @@ SystemMessageManager.prototype = {
   },
 
   uninit: function sysMessMgr_uninit()  {
     this._handlers = null;
     this._pendings =  null;
   },
 
   receiveMessage: function sysMessMgr_receiveMessage(aMessage) {
-    debug("receiveMessage " + aMessage.name + " - " + 
+    debug("receiveMessage " + aMessage.name + " - " +
           aMessage.json.type + " for " + aMessage.json.manifest +
           " (" + this._manifest + ")");
 
     let msg = aMessage.json;
     if (msg.manifest != this._manifest)
       return;
 
     // Bail out if we have no handlers registered for this type.
--- a/dom/plugins/base/nsNPAPIPlugin.h
+++ b/dom/plugins/base/nsNPAPIPlugin.h
@@ -15,21 +15,17 @@
 #include "mozilla/PluginLibrary.h"
 
 /*
  * Use this macro before each exported function
  * (between the return address and the function
  * itself), to ensure that the function has the
  * right calling conventions on OS/2.
  */
-#ifdef XP_OS2
-#define NP_CALLBACK _System
-#else
-#define NP_CALLBACK
-#endif
+#define NP_CALLBACK NP_LOADDS
 
 #if defined(XP_WIN)
 #define NS_NPAPIPLUGIN_CALLBACK(_type, _name) _type (__stdcall * _name)
 #elif defined(XP_OS2)
 #define NS_NPAPIPLUGIN_CALLBACK(_type, _name) _type (_System * _name)
 #else
 #define NS_NPAPIPLUGIN_CALLBACK(_type, _name) _type (* _name)
 #endif
--- a/dom/plugins/ipc/PluginModuleChild.h
+++ b/dom/plugins/ipc/PluginModuleChild.h
@@ -35,21 +35,17 @@
 // NOTE: stolen from nsNPAPIPlugin.h
 
 /*
  * Use this macro before each exported function
  * (between the return address and the function
  * itself), to ensure that the function has the
  * right calling conventions on OS/2.
  */
-#ifdef XP_OS2
-#define NP_CALLBACK _System
-#else
-#define NP_CALLBACK
-#endif
+#define NP_CALLBACK NP_LOADDS
 
 #if defined(XP_WIN)
 #define NS_NPAPIPLUGIN_CALLBACK(_type, _name) _type (__stdcall * _name)
 #elif defined(XP_OS2)
 #define NS_NPAPIPLUGIN_CALLBACK(_type, _name) _type (_System * _name)
 #else
 #define NS_NPAPIPLUGIN_CALLBACK(_type, _name) _type (* _name)
 #endif
--- a/dom/sms/src/SmsManager.cpp
+++ b/dom/sms/src/SmsManager.cpp
@@ -82,17 +82,17 @@ SmsManager::CheckPermissionAndCreateInst
 
   nsCOMPtr<nsIPrincipal> principal = document->NodePrincipal();
   NS_ENSURE_TRUE(principal, nullptr);
 
   nsCOMPtr<nsIPermissionManager> permMgr =
     do_GetService(NS_PERMISSIONMANAGER_CONTRACTID);
   NS_ENSURE_TRUE(permMgr, nullptr);
 
-  PRUint32 permission = nsIPermissionManager::DENY_ACTION;
+  uint32_t permission = nsIPermissionManager::DENY_ACTION;
   permMgr->TestPermissionFromPrincipal(principal, "sms", &permission);
 
   if (permission != nsIPermissionManager::ALLOW_ACTION) {
     return nullptr;
   }
 
   nsRefPtr<SmsManager> smsMgr = new SmsManager();
   smsMgr->Init(aWindow);
--- a/dom/workers/Worker.cpp
+++ b/dom/workers/Worker.cpp
@@ -228,27 +228,29 @@ private:
   {
     return ConstructInternal(aCx, aArgc, aVp, false, Class());
   }
 
   static void
   Finalize(JSFreeOp* aFop, JSObject* aObj)
   {
     JS_ASSERT(JS_GetClass(aObj) == Class());
-    WorkerPrivate* worker = UnwrapDOMObject<WorkerPrivate>(aObj);
+    WorkerPrivate* worker =
+      UnwrapDOMObject<WorkerPrivate>(aObj, eRegularDOMObject);
     if (worker) {
       worker->_finalize(aFop);
     }
   }
 
   static void
   Trace(JSTracer* aTrc, JSObject* aObj)
   {
     JS_ASSERT(JS_GetClass(aObj) == Class());
-    WorkerPrivate* worker = UnwrapDOMObject<WorkerPrivate>(aObj);
+    WorkerPrivate* worker =
+      UnwrapDOMObject<WorkerPrivate>(aObj, eRegularDOMObject);
     if (worker) {
       worker->_trace(aTrc);
     }
   }
 
   static JSBool
   Terminate(JSContext* aCx, unsigned aArgc, jsval* aVp)
   {
@@ -298,19 +300,23 @@ DOMJSClass Worker::sClass = {
   {
     "Worker",
     JSCLASS_IS_DOMJSCLASS | JSCLASS_HAS_RESERVED_SLOTS(1) |
     JSCLASS_IMPLEMENTS_BARRIERS,
     JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_StrictPropertyStub,
     JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, Finalize,
     NULL, NULL, NULL, NULL, Trace
   },
-  { prototypes::id::EventTarget_workers, prototypes::id::_ID_Count,
-    prototypes::id::_ID_Count },
-  -1, false, &sNativePropertyHooks
+  {
+    { prototypes::id::EventTarget_workers, prototypes::id::_ID_Count,
+      prototypes::id::_ID_Count },
+    false,
+    &sNativePropertyHooks
+  },
+  -1
 };
 
 JSPropertySpec Worker::sProperties[] = {
   { sEventStrings[STRING_onerror], STRING_onerror, PROPERTY_FLAGS,
     JSOP_WRAPPER(GetEventListener), JSOP_WRAPPER(SetEventListener) },
   { sEventStrings[STRING_onmessage], STRING_onmessage, PROPERTY_FLAGS,
     JSOP_WRAPPER(GetEventListener), JSOP_WRAPPER(SetEventListener) },
   { 0, 0, 0, JSOP_NULLWRAPPER, JSOP_NULLWRAPPER }
@@ -371,44 +377,46 @@ private:
   ~ChromeWorker();
 
   static WorkerPrivate*
   GetInstancePrivate(JSContext* aCx, JSObject* aObj, const char* aFunctionName)
   {
     if (aObj) {
       JSClass* classPtr = JS_GetClass(aObj);
       if (classPtr == Class()) {
-        return UnwrapDOMObject<WorkerPrivate>(aObj);
+        return UnwrapDOMObject<WorkerPrivate>(aObj, eRegularDOMObject);
       }
     }
 
     return Worker::GetInstancePrivate(aCx, aObj, aFunctionName);
   }
 
   static JSBool
   Construct(JSContext* aCx, unsigned aArgc, jsval* aVp)
   {
     return ConstructInternal(aCx, aArgc, aVp, true, Class());
   }
 
   static void
   Finalize(JSFreeOp* aFop, JSObject* aObj)
   {
     JS_ASSERT(JS_GetClass(aObj) == Class());
-    WorkerPrivate* worker = UnwrapDOMObject<WorkerPrivate>(aObj);
+    WorkerPrivate* worker =
+      UnwrapDOMObject<WorkerPrivate>(aObj, eRegularDOMObject);
     if (worker) {
       worker->_finalize(aFop);
     }
   }
 
   static void
   Trace(JSTracer* aTrc, JSObject* aObj)
   {
     JS_ASSERT(JS_GetClass(aObj) == Class());
-    WorkerPrivate* worker = UnwrapDOMObject<WorkerPrivate>(aObj);
+    WorkerPrivate* worker =
+      UnwrapDOMObject<WorkerPrivate>(aObj, eRegularDOMObject);
     if (worker) {
       worker->_trace(aTrc);
     }
   }
 };
 
 MOZ_STATIC_ASSERT(prototypes::MaxProtoChainLength == 3,
                   "The MaxProtoChainLength must match our manual DOMJSClasses");
@@ -418,28 +426,32 @@ MOZ_STATIC_ASSERT(prototypes::MaxProtoCh
 DOMJSClass ChromeWorker::sClass = {
   { "ChromeWorker",
     JSCLASS_IS_DOMJSCLASS | JSCLASS_HAS_RESERVED_SLOTS(1) |
     JSCLASS_IMPLEMENTS_BARRIERS,
     JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_StrictPropertyStub,
     JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, Finalize,
     NULL, NULL, NULL, NULL, Trace,
   },
-  { prototypes::id::EventTarget_workers, prototypes::id::_ID_Count,
-    prototypes::id::_ID_Count },
-  -1, false, &sNativePropertyHooks
+  {
+    { prototypes::id::EventTarget_workers, prototypes::id::_ID_Count,
+      prototypes::id::_ID_Count },
+    false,
+    &sNativePropertyHooks
+  },
+  -1
 };
 
 WorkerPrivate*
 Worker::GetInstancePrivate(JSContext* aCx, JSObject* aObj,
                            const char* aFunctionName)
 {
   JSClass* classPtr = JS_GetClass(aObj);
   if (classPtr == Class() || classPtr == ChromeWorker::Class()) {
-    return UnwrapDOMObject<WorkerPrivate>(aObj);
+    return UnwrapDOMObject<WorkerPrivate>(aObj, eRegularDOMObject);
   }
 
   JS_ReportErrorNumber(aCx, js_GetErrorMessage, NULL, JSMSG_INCOMPATIBLE_PROTO,
                        Class()->name, aFunctionName, classPtr->name);
   return NULL;
 }
 
 } // anonymous namespace
--- a/dom/workers/WorkerScope.cpp
+++ b/dom/workers/WorkerScope.cpp
@@ -763,17 +763,18 @@ private:
     return true;
   }
 
   static DedicatedWorkerGlobalScope*
   GetInstancePrivate(JSContext* aCx, JSObject* aObj, const char* aFunctionName)
   {
     JSClass* classPtr = JS_GetClass(aObj);
     if (classPtr == Class()) {
-      return UnwrapDOMObject<DedicatedWorkerGlobalScope>(aObj);
+      return UnwrapDOMObject<DedicatedWorkerGlobalScope>(aObj,
+                                                         eRegularDOMObject);
     }
 
     JS_ReportErrorNumber(aCx, js_GetErrorMessage, NULL,
                          JSMSG_INCOMPATIBLE_PROTO, Class()->name, aFunctionName,
                          classPtr->name);
     return NULL;
   }
 
@@ -798,29 +799,29 @@ private:
     return true;
   }
 
   static void
   Finalize(JSFreeOp* aFop, JSObject* aObj)
   {
     JS_ASSERT(JS_GetClass(aObj) == Class());
     DedicatedWorkerGlobalScope* scope =
-      UnwrapDOMObject<DedicatedWorkerGlobalScope>(aObj);
+      UnwrapDOMObject<DedicatedWorkerGlobalScope>(aObj, eRegularDOMObject);
     if (scope) {
       DestroyProtoOrIfaceCache(aObj);
       scope->_finalize(aFop);
     }
   }
 
   static void
   Trace(JSTracer* aTrc, JSObject* aObj)
   {
     JS_ASSERT(JS_GetClass(aObj) == Class());
     DedicatedWorkerGlobalScope* scope =
-      UnwrapDOMObject<DedicatedWorkerGlobalScope>(aObj);
+      UnwrapDOMObject<DedicatedWorkerGlobalScope>(aObj, eRegularDOMObject);
     if (scope) {
       mozilla::dom::TraceProtoOrIfaceCache(aTrc, aObj);
       scope->_trace(aTrc);
     }
   }
 
   static JSBool
   PostMessage(JSContext* aCx, unsigned aArgc, jsval* aVp)
@@ -854,19 +855,23 @@ DOMJSClass DedicatedWorkerGlobalScope::s
   {
     "DedicatedWorkerGlobalScope",
     JSCLASS_DOM_GLOBAL | JSCLASS_IS_DOMJSCLASS | JSCLASS_IMPLEMENTS_BARRIERS |
     JSCLASS_GLOBAL_FLAGS_WITH_SLOTS(3) | JSCLASS_NEW_RESOLVE,
     JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_StrictPropertyStub,
     JS_EnumerateStub, reinterpret_cast<JSResolveOp>(Resolve), JS_ConvertStub,
     Finalize, NULL, NULL, NULL, NULL, Trace
   },
-  { prototypes::id::EventTarget_workers, prototypes::id::_ID_Count,
-    prototypes::id::_ID_Count },
-  -1, false, &sNativePropertyHooks
+  {
+    { prototypes::id::EventTarget_workers, prototypes::id::_ID_Count,
+      prototypes::id::_ID_Count },
+    false,
+    &sNativePropertyHooks
+  },
+  -1
 };
 
 JSPropertySpec DedicatedWorkerGlobalScope::sProperties[] = {
   { sEventStrings[STRING_onmessage], STRING_onmessage, PROPERTY_FLAGS,
     JSOP_WRAPPER(GetEventListener), JSOP_WRAPPER(SetEventListener) },
   { 0, 0, 0, JSOP_NULLWRAPPER, JSOP_NULLWRAPPER }
 };
 
@@ -885,17 +890,17 @@ WorkerGlobalScope::GetInstancePrivate(JS
 {
   JSClass* classPtr = JS_GetClass(aObj);
 
   // We can only make DedicatedWorkerGlobalScope, not WorkerGlobalScope, so this
   // should never happen.
   JS_ASSERT(classPtr != Class());
 
   if (classPtr == DedicatedWorkerGlobalScope::Class()) {
-    return UnwrapDOMObject<DedicatedWorkerGlobalScope>(aObj);
+    return UnwrapDOMObject<DedicatedWorkerGlobalScope>(aObj, eRegularDOMObject);
   }
 
   JS_ReportErrorNumber(aCx, js_GetErrorMessage, NULL, JSMSG_INCOMPATIBLE_PROTO,
                        sClass.name, aFunctionName, classPtr->name);
   return NULL;
 }
 
 } /* anonymous namespace */
--- a/gfx/layers/opengl/LayerManagerOGLShaders.h
+++ b/gfx/layers/opengl/LayerManagerOGLShaders.h
@@ -228,42 +228,43 @@ void main()\n\
 vec2 maskCoords = vMaskCoord.xy / vMaskCoord.z;\n\
 float mask = texture2D(uMaskTexture, maskCoords).r;\n\
 \n\
 gl_FragColor = texture2D(uTexture, vTexCoord) * uLayerOpacity * mask;\n\
 }\n\
 ";
 
 static const char sRGBATextureLayerExternalFS[] = "/* sRGBATextureLayerExternalFS */\n\
+#extension GL_OES_EGL_image_external : require\n\
 /* Fragment Shader */\n\
 #ifdef GL_ES\n\
 precision lowp float;\n\
 #endif\n\
 \n\
 #ifndef NO_LAYER_OPACITY\n\
 uniform float uLayerOpacity;\n\
 #endif\n\
 #ifdef GL_ES // for tiling, texcoord can be greater than the lowfp range\n\
 varying mediump vec2 vTexCoord;\n\
 #else\n\
 varying vec2 vTexCoord;\n\
 #endif\n\
 \n\
-#extension GL_OES_EGL_image_external : require\n\
 uniform samplerExternalOES uTexture;\n\
 uniform mat4 uTextureTransform;\n\
 void main()\n\
 {\n\
 float mask = 1.0;\n\
 \n\
 gl_FragColor = texture2D(uTexture, (uTextureTransform * vec4(vTexCoord.x, vTexCoord.y, 0.0, 1.0)).xy) * uLayerOpacity * mask;\n\
 }\n\
 ";
 
 static const char sRGBATextureLayerExternalMaskFS[] = "/* sRGBATextureLayerExternalMaskFS */\n\
+#extension GL_OES_EGL_image_external : require\n\
 /* Fragment Shader */\n\
 #ifdef GL_ES\n\
 precision lowp float;\n\
 #endif\n\
 \n\
 #ifndef NO_LAYER_OPACITY\n\
 uniform float uLayerOpacity;\n\
 #endif\n\
@@ -271,28 +272,28 @@ uniform float uLayerOpacity;\n\
 varying mediump vec2 vTexCoord;\n\
 #else\n\
 varying vec2 vTexCoord;\n\
 #endif\n\
 \n\
 varying vec2 vMaskCoord;\n\
 uniform sampler2D uMaskTexture;\n\
 \n\
-#extension GL_OES_EGL_image_external : require\n\
 uniform samplerExternalOES uTexture;\n\
 uniform mat4 uTextureTransform;\n\
 void main()\n\
 {\n\
 float mask = texture2D(uMaskTexture, vMaskCoord).r;\n\
 \n\
 gl_FragColor = texture2D(uTexture, (uTextureTransform * vec4(vTexCoord.x, vTexCoord.y, 0.0, 1.0)).xy) * uLayerOpacity * mask;\n\
 }\n\
 ";
 
 static const char sRGBATextureLayerExternalMask3DFS[] = "/* sRGBATextureLayerExternalMask3DFS */\n\
+#extension GL_OES_EGL_image_external : require\n\
 /* Fragment Shader */\n\
 #ifdef GL_ES\n\
 precision lowp float;\n\
 #endif\n\
 \n\
 #ifndef NO_LAYER_OPACITY\n\
 uniform float uLayerOpacity;\n\
 #endif\n\
@@ -300,17 +301,16 @@ uniform float uLayerOpacity;\n\
 varying mediump vec2 vTexCoord;\n\
 #else\n\
 varying vec2 vTexCoord;\n\
 #endif\n\
 \n\
 varying vec3 vMaskCoord;\n\
 uniform sampler2D uMaskTexture;\n\
 \n\
-#extension GL_OES_EGL_image_external : require\n\
 uniform samplerExternalOES uTexture;\n\
 uniform mat4 uTextureTransform;\n\
 void main()\n\
 {\n\
 vec2 maskCoords = vMaskCoord.xy / vMaskCoord.z;\n\
 float mask = texture2D(uMaskTexture, maskCoords).r;\n\
 \n\
 gl_FragColor = texture2D(uTexture, (uTextureTransform * vec4(vTexCoord.x, vTexCoord.y, 0.0, 1.0)).xy) * uLayerOpacity * mask;\n\
--- a/gfx/layers/opengl/LayerManagerOGLShaders.txt
+++ b/gfx/layers/opengl/LayerManagerOGLShaders.txt
@@ -208,18 +208,20 @@ void main()
 {
 $FRAGMENT_CALC_MASK<mask>$
   gl_FragColor = texture2D(uTexture, vTexCoord) * uLayerOpacity * mask;
 }
 @end
 
 // Single texture in RGBA format for use with GL_TEXTURE_EXTERNAL_OES
 @shader sRGBATextureLayerExternal<mask:,Mask,Mask3D>FS
+#extension GL_OES_EGL_image_external : require
+
 $LAYER_FRAGMENT<mask>$
-#extension GL_OES_EGL_image_external : require
+
 uniform samplerExternalOES uTexture;
 uniform mat4 uTextureTransform;
 
 void main()
 {
 $FRAGMENT_CALC_MASK<mask>$
   gl_FragColor = texture2D(uTexture, (uTextureTransform * vec4(vTexCoord.x, vTexCoord.y, 0.0, 1.0)).xy) * uLayerOpacity * mask;
 }
--- a/gfx/thebes/gfxAndroidPlatform.cpp
+++ b/gfx/thebes/gfxAndroidPlatform.cpp
@@ -1,27 +1,31 @@
 /* -*- 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 "base/basictypes.h"
+
 #include "gfxAndroidPlatform.h"
 #include "mozilla/gfx/2D.h"
 
 #include "gfxFT2FontList.h"
 #include "gfxImageSurface.h"
+#include "mozilla/dom/ContentChild.h"
 #include "nsXULAppAPI.h"
 #include "nsIScreen.h"
 #include "nsIScreenManager.h"
 
 #include "cairo.h"
 
 #include "ft2build.h"
 #include FT_FREETYPE_H
 using namespace mozilla;
+using namespace mozilla::dom;
 using namespace mozilla::gfx;
 
 static FT_Library gPlatformFTLibrary = NULL;
 
 #define LOG(args...)  __android_log_print(ANDROID_LOG_INFO, "GeckoFonts" , ## args)
 
 gfxAndroidPlatform::gfxAndroidPlatform()
 {
@@ -185,25 +189,21 @@ gfxAndroidPlatform::FontHintingEnabled()
     // On android-java, we currently only use gecko to render web
     // content that can always be be non-reflow-zoomed.  So turn off
     // hinting.
     // 
     // XXX when gecko-android-java is used as an "app runtime", we'll
     // want to re-enable hinting.
     return false;
 #else
-    // Otherwise, if we're in a content process, assume we don't want
-    // hinting.
-    //
-    // XXX when we use content processes to load "apps", we'll want to
-    // configure this dynamically based on whether we're an "app
-    // content process" or a "browser content process".  The former
-    // wants hinting, the latter doesn't since it might be
-    // non-reflow-zoomed.
-    return (XRE_GetProcessType() != GeckoProcessType_Content);
+    // Otherwise, enable hinting unless we're in a content process
+    // that might be used for non-reflowing zoom.
+    return (XRE_GetProcessType() != GeckoProcessType_Content ||
+            (ContentChild::GetSingleton()->IsForApp() &&
+             !ContentChild::GetSingleton()->IsForBrowser()));
 #endif //  MOZ_USING_ANDROID_JAVA_WIDGETS
 }
 
 int
 gfxAndroidPlatform::GetScreenDepth() const
 {
     return mScreenDepth;
 }
--- a/image/decoders/icon/android/nsIconChannel.cpp
+++ b/image/decoders/icon/android/nsIconChannel.cpp
@@ -4,16 +4,18 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include <stdlib.h>
 #include "mozilla/dom/ContentChild.h"
 #include "nsIURL.h"
 #include "nsXULAppAPI.h"
 #include "AndroidBridge.h"
 #include "nsIconChannel.h"
+#include "nsIStringStream.h"
+#include "nsNetUtil.h"
 
 NS_IMPL_ISUPPORTS2(nsIconChannel,
                    nsIRequest,
                    nsIChannel)
 
 using namespace mozilla;
 using mozilla::dom::ContentChild;
 
--- a/image/src/imgLoader.cpp
+++ b/image/src/imgLoader.cpp
@@ -59,54 +59,16 @@
 #include "nsIContentSecurityPolicy.h"
 #include "nsIChannelPolicy.h"
 
 #include "nsContentUtils.h"
 
 using namespace mozilla;
 using namespace mozilla::image;
 
-#if defined(DEBUG_pavlov) || defined(DEBUG_timeless)
-#include "nsISimpleEnumerator.h"
-#include "nsXPCOM.h"
-#include "nsISupportsPrimitives.h"
-#include "nsXPIDLString.h"
-#include "nsComponentManagerUtils.h"
-
-
-static void PrintImageDecoders()
-{
-  nsCOMPtr<nsIComponentRegistrar> compMgr;
-  if (NS_FAILED(NS_GetComponentRegistrar(getter_AddRefs(compMgr))) || !compMgr)
-    return;
-  nsCOMPtr<nsISimpleEnumerator> enumer;
-  if (NS_FAILED(compMgr->EnumerateContractIDs(getter_AddRefs(enumer))) || !enumer)
-    return;
-  
-  nsCString str;
-  nsCOMPtr<nsISupports> s;
-  bool more = false;
-  while (NS_SUCCEEDED(enumer->HasMoreElements(&more)) && more) {
-    enumer->GetNext(getter_AddRefs(s));
-    if (s) {
-      nsCOMPtr<nsISupportsCString> ss(do_QueryInterface(s));
-
-      nsCAutoString xcs;
-      ss->GetData(xcs);
-
-      NS_NAMED_LITERAL_CSTRING(decoderContract, "@mozilla.org/image/decoder;3?type=");
-
-      if (StringBeginsWith(xcs, decoderContract)) {
-        printf("Have decoder for mime type: %s\n", xcs.get()+decoderContract.Length());
-      }
-    }
-  }
-}
-#endif
-
 NS_MEMORY_REPORTER_MALLOC_SIZEOF_FUN(ImagesMallocSizeOf, "images")
 
 class imgMemoryReporter MOZ_FINAL :
   public nsIMemoryMultiReporter
 {
 public:
   imgMemoryReporter()
   {
rename from ipc/glue/IPCSerializableParams.ipdlh
rename to ipc/glue/InputStreamParams.ipdlh
--- a/ipc/glue/IPCSerializableParams.ipdlh
+++ b/ipc/glue/InputStreamParams.ipdlh
@@ -1,12 +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 "IPC/IPCMessageUtils.h";
+
+using mozilla::void_t;
+
 namespace mozilla {
 namespace ipc {
 
 struct StringInputStreamParams
 {
   nsCString data;
 };
 
@@ -32,13 +36,36 @@ struct MultiplexInputStreamParams
   bool startedReadingCurrent;
 };
 
 union InputStreamParams
 {
   StringInputStreamParams;
   FileInputStreamParams;
   PartialFileInputStreamParams;
+  BufferedInputStreamParams;
+  MIMEInputStreamParams;
   MultiplexInputStreamParams;
 };
 
+union OptionalInputStreamParams
+{
+  void_t;
+  InputStreamParams;
+};
+
+struct BufferedInputStreamParams
+{
+  OptionalInputStreamParams optionalStream;
+  uint32_t bufferSize;
+};
+
+struct MIMEInputStreamParams
+{
+  OptionalInputStreamParams optionalStream;
+  nsCString headers;
+  nsCString contentLength;
+  bool startedReading;
+  bool addContentLength;
+};
+
 } // namespace ipc
 } // namespace mozilla
--- a/ipc/glue/InputStreamUtils.cpp
+++ b/ipc/glue/InputStreamUtils.cpp
@@ -5,75 +5,141 @@
 #include "InputStreamUtils.h"
 
 #include "nsIIPCSerializableInputStream.h"
 
 #include "mozilla/Assertions.h"
 #include "nsComponentManagerUtils.h"
 #include "nsDebug.h"
 #include "nsID.h"
+#include "nsMIMEInputStream.h"
 #include "nsMultiplexInputStream.h"
 #include "nsNetCID.h"
 #include "nsStringStream.h"
 #include "nsThreadUtils.h"
 
 using namespace mozilla::ipc;
 
 namespace {
 
 NS_DEFINE_CID(kStringInputStreamCID, NS_STRINGINPUTSTREAM_CID);
 NS_DEFINE_CID(kFileInputStreamCID, NS_LOCALFILEINPUTSTREAM_CID);
 NS_DEFINE_CID(kPartialFileInputStreamCID, NS_PARTIALLOCALFILEINPUTSTREAM_CID);
+NS_DEFINE_CID(kBufferedInputStreamCID, NS_BUFFEREDINPUTSTREAM_CID);
+NS_DEFINE_CID(kMIMEInputStreamCID, NS_MIMEINPUTSTREAM_CID);
 NS_DEFINE_CID(kMultiplexInputStreamCID, NS_MULTIPLEXINPUTSTREAM_CID);
 
 } // anonymous namespace
 
 namespace mozilla {
 namespace ipc {
 
+void
+SerializeInputStream(nsIInputStream* aInputStream,
+                     InputStreamParams& aParams)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+  MOZ_ASSERT(aInputStream);
+
+  nsCOMPtr<nsIIPCSerializableInputStream> serializable =
+    do_QueryInterface(aInputStream);
+  if (!serializable) {
+    MOZ_NOT_REACHED("Input stream is not serializable!");
+  }
+
+  serializable->Serialize(aParams);
+
+  if (aParams.type() == InputStreamParams::T__None) {
+    MOZ_NOT_REACHED("Serialize failed!");
+  }
+}
+
+void
+SerializeInputStream(nsIInputStream* aInputStream,
+                     OptionalInputStreamParams& aParams)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+
+  if (aInputStream) {
+    InputStreamParams params;
+    SerializeInputStream(aInputStream, params);
+    aParams = params;
+  }
+  else {
+    aParams = mozilla::void_t();
+  }
+}
+
 already_AddRefed<nsIInputStream>
 DeserializeInputStream(const InputStreamParams& aParams)
 {
   MOZ_ASSERT(NS_IsMainThread());
 
   nsCOMPtr<nsIIPCSerializableInputStream> serializable;
 
   switch (aParams.type()) {
-    case InputStreamParams::T__None:
-      NS_WARNING("This union has no type!");
-      return nullptr;
-
     case InputStreamParams::TStringInputStreamParams:
       serializable = do_CreateInstance(kStringInputStreamCID);
       break;
 
     case InputStreamParams::TFileInputStreamParams:
       serializable = do_CreateInstance(kFileInputStreamCID);
       break;
 
     case InputStreamParams::TPartialFileInputStreamParams:
       serializable = do_CreateInstance(kPartialFileInputStreamCID);
       break;
 
+    case InputStreamParams::TBufferedInputStreamParams:
+      serializable = do_CreateInstance(kBufferedInputStreamCID);
+      break;
+
+    case InputStreamParams::TMIMEInputStreamParams:
+      serializable = do_CreateInstance(kMIMEInputStreamCID);
+      break;
+
     case InputStreamParams::TMultiplexInputStreamParams:
       serializable = do_CreateInstance(kMultiplexInputStreamCID);
       break;
 
     default:
-      NS_WARNING("Unknown params!");
+      MOZ_ASSERT(false, "Unknown params!");
       return nullptr;
   }
 
   MOZ_ASSERT(serializable);
 
   if (!serializable->Deserialize(aParams)) {
-    NS_WARNING("Deserialize failed!");
+    MOZ_ASSERT(false, "Deserialize failed!");
     return nullptr;
   }
 
   nsCOMPtr<nsIInputStream> stream = do_QueryInterface(serializable);
   MOZ_ASSERT(stream);
 
   return stream.forget();
 }
 
+already_AddRefed<nsIInputStream>
+DeserializeInputStream(const OptionalInputStreamParams& aParams)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+
+  nsCOMPtr<nsIInputStream> stream;
+
+  switch (aParams.type()) {
+    case OptionalInputStreamParams::Tvoid_t:
+      // Leave stream null.
+      break;
+
+    case OptionalInputStreamParams::TInputStreamParams:
+      stream = DeserializeInputStream(aParams.get_InputStreamParams());
+      break;
+
+    default:
+      MOZ_ASSERT(false, "Unknown params!");
+  }
+
+  return stream.forget();
+}
+
 } // namespace ipc
 } // namespace mozilla
--- a/ipc/glue/InputStreamUtils.h
+++ b/ipc/glue/InputStreamUtils.h
@@ -1,21 +1,32 @@
 /* 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 mozilla_ipc_InputStreamUtils_h
 #define mozilla_ipc_InputStreamUtils_h
 
-#include "mozilla/ipc/IPCSerializableParams.h"
+#include "mozilla/ipc/InputStreamParams.h"
 #include "nsCOMPtr.h"
 #include "nsIInputStream.h"
 
 namespace mozilla {
 namespace ipc {
 
+void
+SerializeInputStream(nsIInputStream* aInputStream,
+                     InputStreamParams& aParams);
+
+void
+SerializeInputStream(nsIInputStream* aInputStream,
+                     OptionalInputStreamParams& aParams);
+
 already_AddRefed<nsIInputStream>
 DeserializeInputStream(const InputStreamParams& aParams);
 
+already_AddRefed<nsIInputStream>
+DeserializeInputStream(const OptionalInputStreamParams& aParams);
+
 } // namespace ipc
 } // namespace mozilla
 
 #endif // mozilla_ipc_InputStreamUtils_h
--- a/ipc/glue/Makefile.in
+++ b/ipc/glue/Makefile.in
@@ -35,19 +35,23 @@ EXPORTS_mozilla/ipc = \
   SharedMemory.h \
   SharedMemoryBasic.h \
   SharedMemoryBasic_chromium.h \
   SharedMemorySysV.h \
   Shmem.h \
   SyncChannel.h \
   ScopedXREEmbed.h \
   Transport.h \
+  URIUtils.h \
   $(NULL)
 
-EXPORTS = nsIIPCSerializableInputStream.h
+EXPORTS = \
+  nsIIPCSerializableInputStream.h \
+  nsIIPCSerializableURI.h \
+  $(NULL)
 
 ifeq ($(OS_ARCH),WINNT) #{
 EXPORTS_mozilla/ipc += \
   Transport_win.h \
   $(NULL)
 else
 # POSIX
 EXPORTS_mozilla/ipc += \
@@ -74,16 +78,17 @@ CPPSRCS += \
   ProcessChild.cpp \
   ProtocolUtils.cpp \
   RPCChannel.cpp \
   ScopedXREEmbed.cpp \
   SharedMemory.cpp \
   Shmem.cpp \
   StringUtil.cpp \
   SyncChannel.cpp \
+  URIUtils.cpp \
   $(NULL)
 
 ifeq ($(OS_ARCH),WINNT) #{
 CPPSRCS += \
   SharedMemory_windows.cpp \
   Transport_win.cpp \
   WindowsMessageLoop.cpp \
   CrossProcessMutex_windows.cpp \
new file mode 100644
--- /dev/null
+++ b/ipc/glue/URIParams.ipdlh
@@ -0,0 +1,78 @@
+/* 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";
+
+using mozilla::void_t;
+
+namespace mozilla {
+namespace ipc {
+
+struct SimpleURIParams
+{
+  nsCString scheme;
+  nsCString path;
+  nsCString ref;
+  bool isMutable;
+};
+
+struct StandardURLSegment
+{
+  uint32_t position;
+  int32_t length;
+};
+
+struct StandardURLParams
+{
+  uint32_t urlType;
+  int32_t port;
+  int32_t defaultPort;
+  nsCString spec;
+  StandardURLSegment scheme;
+  StandardURLSegment authority;
+  StandardURLSegment username;
+  StandardURLSegment password;
+  StandardURLSegment host;
+  StandardURLSegment path;
+  StandardURLSegment filePath;
+  StandardURLSegment directory;
+  StandardURLSegment baseName;
+  StandardURLSegment extension;
+  StandardURLSegment query;
+  StandardURLSegment ref;
+  nsCString originCharset;
+  bool isMutable;
+  bool supportsFileURL;
+  uint32_t hostEncoding;
+};
+
+struct JARURIParams
+{
+  URIParams jarFile;
+  URIParams jarEntry;
+  nsCString charset;
+};
+
+struct GenericURIParams
+{
+  nsCString spec;
+  nsCString charset;
+};
+
+union URIParams
+{
+  SimpleURIParams;
+  StandardURLParams;
+  JARURIParams;
+  GenericURIParams;
+};
+
+union OptionalURIParams
+{
+  void_t;
+  URIParams;
+};
+
+} // namespace ipc
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/ipc/glue/URIUtils.cpp
@@ -0,0 +1,207 @@
+/* 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 "URIUtils.h"
+
+#include "nsIIPCSerializableURI.h"
+
+#include "mozilla/Assertions.h"
+#include "mozilla/Util.h"
+#include "nsComponentManagerUtils.h"
+#include "nsDebug.h"
+#include "nsID.h"
+#include "nsJARURI.h"
+#include "nsNetCID.h"
+#include "nsNetUtil.h"
+#include "nsThreadUtils.h"
+
+using namespace mozilla::ipc;
+using mozilla::ArrayLength;
+
+namespace {
+
+NS_DEFINE_CID(kSimpleURICID, NS_SIMPLEURI_CID);
+NS_DEFINE_CID(kStandardURLCID, NS_STANDARDURL_CID);
+NS_DEFINE_CID(kJARURICID, NS_JARURI_CID);
+
+struct StringWithLengh
+{
+  const char* string;
+  size_t length;
+};
+
+#define STRING_WITH_LENGTH(_str) \
+  { _str, ArrayLength(_str) - 1 }
+
+const StringWithLengh kGenericURIAllowedSchemes[] = {
+  STRING_WITH_LENGTH("about:"),
+  STRING_WITH_LENGTH("javascript:"),
+  STRING_WITH_LENGTH("javascript")
+};
+
+#undef STRING_WITH_LENGTH
+
+} // anonymous namespace
+
+namespace mozilla {
+namespace ipc {
+
+void
+SerializeURI(nsIURI* aURI,
+             URIParams& aParams)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+  MOZ_ASSERT(aURI);
+
+  nsCOMPtr<nsIIPCSerializableURI> serializable = do_QueryInterface(aURI);
+  if (serializable) {
+    serializable->Serialize(aParams);
+    if (aParams.type() == URIParams::T__None) {
+      MOZ_NOT_REACHED("Serialize failed!");
+    }
+    return;
+  }
+
+  nsCString scheme;
+  if (NS_FAILED(aURI->GetScheme(scheme))) {
+    MOZ_NOT_REACHED("This must never fail!");
+  }
+
+  bool allowed = false;
+
+  for (size_t i = 0; i < ArrayLength(kGenericURIAllowedSchemes); i++) {
+    const StringWithLengh& entry = kGenericURIAllowedSchemes[i];
+    if (scheme.EqualsASCII(entry.string, entry.length)) {
+      allowed = true;
+      break;
+    }
+  }
+
+  if (!allowed) {
+    MOZ_NOT_REACHED("All IPDL URIs must be serializable or an allowed "
+                    "scheme!");
+  }
+
+  GenericURIParams params;
+  if (NS_FAILED(aURI->GetSpec(params.spec())) ||
+      NS_FAILED(aURI->GetOriginCharset(params.charset()))) {
+    MOZ_NOT_REACHED("This must never fail!");
+  }
+
+  aParams = params;
+}
+
+void
+SerializeURI(nsIURI* aURI,
+             OptionalURIParams& aParams)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+
+  if (aURI) {
+    URIParams params;
+    SerializeURI(aURI, params);
+    aParams = params;
+  }
+  else {
+    aParams = mozilla::void_t();
+  }
+}
+
+already_AddRefed<nsIURI>
+DeserializeURI(const URIParams& aParams)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+
+  nsCOMPtr<nsIURI> uri;
+
+  if (aParams.type() != URIParams::TGenericURIParams) {
+    nsCOMPtr<nsIIPCSerializableURI> serializable;
+
+    switch (aParams.type()) {
+      case URIParams::TSimpleURIParams:
+        serializable = do_CreateInstance(kSimpleURICID);
+        break;
+
+      case URIParams::TStandardURLParams:
+        serializable = do_CreateInstance(kStandardURLCID);
+        break;
+
+      case URIParams::TJARURIParams:
+        serializable = do_CreateInstance(kJARURICID);
+        break;
+
+      default:
+        MOZ_NOT_REACHED("Unknown params!");
+    }
+
+    MOZ_ASSERT(serializable);
+
+    if (!serializable->Deserialize(aParams)) {
+      MOZ_ASSERT(false, "Deserialize failed!");
+      return nullptr;
+    }
+
+    uri = do_QueryInterface(serializable);
+    MOZ_ASSERT(uri);
+
+    return uri.forget();
+  }
+
+  MOZ_ASSERT(aParams.type() == URIParams::TGenericURIParams);
+
+  const GenericURIParams& params = aParams.get_GenericURIParams();
+
+  if (NS_FAILED(NS_NewURI(getter_AddRefs(uri), params.spec(),
+                          params.charset().get()))) {
+    NS_WARNING("Failed to make new URI!");
+    return nullptr;
+  }
+
+  nsCString scheme;
+  if (NS_FAILED(uri->GetScheme(scheme))) {
+    MOZ_NOT_REACHED("This must never fail!");
+  }
+
+  bool allowed = false;
+
+  for (size_t i = 0; i < ArrayLength(kGenericURIAllowedSchemes); i++) {
+    const StringWithLengh& entry = kGenericURIAllowedSchemes[i];
+    if (scheme.EqualsASCII(entry.string, entry.length)) {
+      allowed = true;
+      break;
+    }
+  }
+
+  if (!allowed) {
+    MOZ_ASSERT(false, "This type of URI is not allowed!");
+    return nullptr;
+  }
+
+  return uri.forget();
+}
+
+already_AddRefed<nsIURI>
+DeserializeURI(const OptionalURIParams& aParams)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+
+  nsCOMPtr<nsIURI> uri;
+
+  switch (aParams.type()) {
+    case OptionalURIParams::Tvoid_t:
+      break;
+
+    case OptionalURIParams::TURIParams:
+      uri = DeserializeURI(aParams.get_URIParams());
+      break;
+
+    default:
+      MOZ_NOT_REACHED("Unknown params!");
+  }
+
+  return uri.forget();
+}
+
+} // namespace ipc
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/ipc/glue/URIUtils.h
@@ -0,0 +1,32 @@
+/* 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 mozilla_ipc_URIUtils_h
+#define mozilla_ipc_URIUtils_h
+
+#include "mozilla/ipc/URIParams.h"
+#include "nsCOMPtr.h"
+#include "nsIURI.h"
+
+namespace mozilla {
+namespace ipc {
+
+void
+SerializeURI(nsIURI* aURI,
+             URIParams& aParams);
+
+void
+SerializeURI(nsIURI* aURI,
+             OptionalURIParams& aParams);
+
+already_AddRefed<nsIURI>
+DeserializeURI(const URIParams& aParams);
+
+already_AddRefed<nsIURI>
+DeserializeURI(const OptionalURIParams& aParams);
+
+} // namespace ipc
+} // namespace mozilla
+
+#endif // mozilla_ipc_URIUtils_h
--- a/ipc/glue/ipdl.mk
+++ b/ipc/glue/ipdl.mk
@@ -1,5 +1,8 @@
 # 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/.
 
-IPDLSRCS = IPCSerializableParams.ipdlh
+IPDLSRCS = \
+  InputStreamParams.ipdlh \
+  URIParams.ipdlh \
+  $(NULL)
new file mode 100644
--- /dev/null
+++ b/ipc/glue/nsIIPCSerializableURI.h
@@ -0,0 +1,57 @@
+/* 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 mozilla_ipc_nsIIPCSerializableURI_h
+#define mozilla_ipc_nsIIPCSerializableURI_h
+
+#include "nsISupports.h"
+#include "mozilla/Attributes.h"
+
+namespace mozilla {
+namespace ipc {
+class URIParams;
+}
+}
+
+#define NS_IIPCSERIALIZABLEURI_IID \
+  {0xfee3437d, 0x3daf, 0x411f, {0xb0, 0x1d, 0xdc, 0xd4, 0x88, 0x55, 0xe3, 0xd}}
+
+class NS_NO_VTABLE nsIIPCSerializableURI : public nsISupports
+{
+public:
+  NS_DECLARE_STATIC_IID_ACCESSOR(NS_IIPCSERIALIZABLEURI_IID)
+
+  virtual void
+  Serialize(mozilla::ipc::URIParams& aParams) = 0;
+
+  virtual bool
+  Deserialize(const mozilla::ipc::URIParams& aParams) = 0;
+};
+
+NS_DEFINE_STATIC_IID_ACCESSOR(nsIIPCSerializableURI,
+                              NS_IIPCSERIALIZABLEURI_IID)
+
+#define NS_DECL_NSIIPCSERIALIZABLEURI \
+  virtual void \
+  Serialize(mozilla::ipc::URIParams&) MOZ_OVERRIDE; \
+  virtual bool \
+  Deserialize(const mozilla::ipc::URIParams&) MOZ_OVERRIDE;
+
+#define NS_FORWARD_NSIIPCSERIALIZABLEURI(_to) \
+  virtual void \
+  Serialize(mozilla::ipc::URIParams& aParams) MOZ_OVERRIDE \
+  { _to Serialize(aParams); } \
+  virtual bool \
+  Deserialize(const mozilla::ipc::URIParams& aParams) MOZ_OVERRIDE \
+  { return _to Deserialize(aParams); }
+
+#define NS_FORWARD_SAFE_NSIIPCSERIALIZABLEURI(_to) \
+  virtual void \
+  Serialize(mozilla::ipc::URIParams& aParams) MOZ_OVERRIDE \
+  { if (_to) { _to->Serialize(aParams); } } \
+  virtual bool \
+  Deserialize(const mozilla::ipc::URIParams& aParams) MOZ_OVERRIDE \
+  { if (_to) { return _to->Deserialize(aParams); } return false; }
+
+#endif // mozilla_ipc_nsIIPCSerializableURI_h
--- a/ipc/ipdl/ipdl/lower.py
+++ b/ipc/ipdl/ipdl/lower.py
@@ -1289,20 +1289,21 @@ with some new IPDL/C++ nodes that are tu
         # reference known C++ types by their "short name" rather than
         # fully-qualified name. e.g. |Foo| rather than |a::b::Foo|.
         self.typedefs = [ ]
         self.typedefSet = set([ Typedef(Type('mozilla::ipc::ActorHandle'),
                                         'ActorHandle') ])
         self.protocolName = None
 
     def visitTranslationUnit(self, tu):
-        if not isinstance(tu, TranslationUnit) and tu not in self.visitedTus:
+        if tu not in self.visitedTus:
             self.visitedTus.add(tu)
             ipdl.ast.Visitor.visitTranslationUnit(self, tu)
-            TranslationUnit.upgrade(tu)
+            if not isinstance(tu, TranslationUnit):
+                TranslationUnit.upgrade(tu)
             self.typedefs[:] = sorted(list(self.typedefSet))
 
     def visitInclude(self, inc):
         if inc.tu.filetype == 'header':
             inc.tu.accept(self)
 
     def visitProtocol(self, pro):
         self.protocolName = pro.name
@@ -1312,30 +1313,33 @@ with some new IPDL/C++ nodes that are tu
 
 
     def visitUsingStmt(self, using):
         if using.decl.fullname is not None:
             self.typedefSet.add(Typedef(Type(using.decl.fullname),
                                         using.decl.shortname))
 
     def visitStructDecl(self, sd):
-        sd.decl.special = 0
-        newfields = [ ]
-        for f in sd.fields:
-            ftype = f.decl.type
-            if _hasVisibleActor(ftype):
-                sd.decl.special = 1
-                # if ftype has a visible actor, we need both
-                # |ActorParent| and |ActorChild| fields
-                newfields.append(_StructField(ftype, f.name, sd, side='parent'))
-                newfields.append(_StructField(ftype, f.name, sd, side='child'))
-            else:
-                newfields.append(_StructField(ftype, f.name, sd))
-        sd.fields = newfields
-        StructDecl.upgrade(sd)
+        if not isinstance(sd, StructDecl):
+            sd.decl.special = 0
+            newfields = [ ]
+            for f in sd.fields:
+                ftype = f.decl.type
+                if _hasVisibleActor(ftype):
+                    sd.decl.special = 1
+                    # if ftype has a visible actor, we need both
+                    # |ActorParent| and |ActorChild| fields
+                    newfields.append(_StructField(ftype, f.name, sd,
+                                                  side='parent'))
+                    newfields.append(_StructField(ftype, f.name, sd,
+                                                  side='child'))
+                else:
+                    newfields.append(_StructField(ftype, f.name, sd))
+            sd.fields = newfields
+            StructDecl.upgrade(sd)
 
         if sd.decl.fullname is not None:
             self.typedefSet.add(Typedef(Type(sd.fqClassName()), sd.name))
 
 
     def visitUnionDecl(self, ud):
         ud.decl.special = 0
         newcomponents = [ ]
--- a/ipc/ipdl/ipdl/type.py
+++ b/ipc/ipdl/ipdl/type.py
@@ -799,16 +799,20 @@ class GatherDecls(TcheckVisitor):
         if using.type.basename() == fullname:
             fullname = None
         if fullname == 'mozilla::ipc::Shmem':
             ipdltype = ShmemType(using.type.spec)
         elif fullname == 'mozilla::ipc::FileDescriptor':
             ipdltype = FDType(using.type.spec)
         else:
             ipdltype = ImportedCxxType(using.type.spec)
+            existingType = self.symtab.lookup(ipdltype.fullname())
+            if existingType and existingType.fullname == ipdltype.fullname():
+                using.decl = existingType
+                return
         using.decl = self.declare(
             loc=using.loc,
             type=ipdltype,
             shortname=using.type.basename(),
             fullname=fullname)
 
     def visitProtocol(self, p):
         # protocol scope
new file mode 100644
--- /dev/null
+++ b/ipc/ipdl/test/ipdl/ok/multipleUsingCxxTypes.ipdl
@@ -0,0 +1,7 @@
+using mozilla::void_t;
+using mozilla::void_t;
+
+protocol multipleUsingCxxTypes {
+child:
+    Msg(void_t foo);
+};
--- a/js/src/builtin/Eval.cpp
+++ b/js/src/builtin/Eval.cpp
@@ -361,10 +361,10 @@ js::PrincipalsForCompiledCode(const Call
     // subsume the callee's.
     //
     // In the converse situation, where the callee has lower privileges than the
     // caller, we might initially guess that the caller would want to retain
     // their higher privileges in the generated code. However, since the
     // compiled code will be run with the callee's scope chain, this would make
     // fp->script()->compartment() != fp->compartment().
 
-    return call.callee().principals(cx);
+    return call.callee().compartment()->principals;
 }
--- a/js/src/config/rules.mk
+++ b/js/src/config/rules.mk
@@ -1582,32 +1582,30 @@ endif # COMPILER_DEPEND
 #   a previous build in the source tree) and thus neglect to create a
 #   dependency directory in the object directory, where we really need
 #   it.
 
 $(CURDIR)/$(MDDEPDIR):
 	$(MKDIR) -p $@
 
 ifneq (,$(filter-out all chrome default export realchrome tools clean clobber clobber_all distclean realclean,$(MAKECMDGOALS)))
-ifneq (,$(OBJS)$(XPIDLSRCS)$(SIMPLE_PROGRAMS))
 MDDEPEND_FILES		:= $(strip $(wildcard $(MDDEPDIR)/*.pp))
 
 ifneq (,$(MDDEPEND_FILES))
 # The script mddepend.pl checks the dependencies and writes to stdout
 # one rule to force out-of-date objects. For example,
 #   foo.o boo.o: FORCE
 # The script has an advantage over including the *.pp files directly
 # because it handles the case when header files are removed from the build.
 # 'make' would complain that there is no way to build missing headers.
 ALL_PP_RESULTS = $(shell $(PERL) $(BUILD_TOOLS)/mddepend.pl - $(MDDEPEND_FILES))
 $(eval $(ALL_PP_RESULTS))
 endif
 
 endif
-endif
 #############################################################################
 
 -include $(topsrcdir)/$(MOZ_BUILD_APP)/app-rules.mk
 -include $(MY_RULES)
 
 #
 # Generate Emacs tags in a file named TAGS if ETAGS was set in $(MY_CONFIG)
 # or in $(MY_RULES)
--- a/js/src/frontend/BytecodeEmitter.cpp
+++ b/js/src/frontend/BytecodeEmitter.cpp
@@ -4799,16 +4799,17 @@ EmitNormalFor(JSContext *cx, BytecodeEmi
             return false;
 
         /* Restore the absolute line number for source note readers. */
         ptrdiff_t lineno = pn->pn_pos.end.lineno;
         if (bce->currentLine() != (unsigned) lineno) {
             if (NewSrcNote2(cx, bce, SRC_SETLINE, lineno) < 0)
                 return false;
             bce->current->currentLine = (unsigned) lineno;
+            bce->current->lastColumn = 0;
         }
     }
 
     ptrdiff_t tmp3 = bce->offset();
 
     if (forHead->pn_kid2) {
         /* Fix up the goto from top to target the loop condition. */
         JS_ASSERT(jmp >= 0);
@@ -5257,16 +5258,17 @@ EmitStatement(JSContext *cx, BytecodeEmi
             if (!EmitTree(cx, bce, pn2))
                 return false;
             if (Emit1(cx, bce, op) < 0)
                 return false;
         }
     } else if (!pn->isDirectivePrologueMember()) {
         /* Don't complain about directive prologue members; just don't emit their code. */
         bce->current->currentLine = pn2->pn_pos.begin.lineno;
+        bce->current->lastColumn = 0;
         if (!bce->reportStrictWarning(pn2, JSMSG_USELESS_EXPR))
             return false;
     }
 
     return true;
 }
 
 static bool
--- a/js/src/frontend/NameFunctions.cpp
+++ b/js/src/frontend/NameFunctions.cpp
@@ -96,51 +96,61 @@ class NameResolver
         for (int pos = nparents - 1; pos >= 0; pos--) {
             ParseNode *cur = parents[pos];
             if (cur->isAssignment())
                 return cur;
 
             switch (cur->getKind()) {
                 case PNK_NAME:     return cur;  /* found the initialized declaration */
                 case PNK_FUNCTION: return NULL; /* won't find an assignment or declaration */
-                default:           break;       /* move on, nothing relevant */
 
-                /* These nodes are relevant to the naming process, so append */
+                case PNK_RETURN:
+                    /*
+                     * Normally the relevant parent of a node is its direct parent, but
+                     * sometimes with code like:
+                     *
+                     *    var foo = (function() { return function() {}; })();
+                     *
+                     * the outer function is just a helper to create a scope for the
+                     * returned function. Hence the name of the returned function should
+                     * actually be 'foo'.  This loop sees if the current node is a
+                     * PNK_RETURN, and if there is a direct function call we skip to
+                     * that.
+                     */
+                    for (int tmp = pos - 1; tmp > 0; tmp--) {
+                        if (isDirectCall(tmp, cur)) {
+                            pos = tmp;
+                            break;
+                        } else if (call(cur)) {
+                            /* Don't skip too high in the tree */
+                            break;
+                        }
+                        cur = parents[tmp];
+                    }
+                    break;
+
                 case PNK_COLON:
-                case PNK_LP:
-                case PNK_NEW:
+                    /*
+                     * If this is a PNK_COLON, but our parent is not a PNK_RC,
+                     * then this is a label and we're done naming. Otherwise we
+                     * record the PNK_COLON but skip the PNK_RC so we're not
+                     * flagged as a contributor.
+                     */
+                    if (pos == 0 || !parents[pos - 1]->isKind(PNK_RC))
+                        return NULL;
+                    pos--;
+                    /* fallthrough */
+
+                /* Save any other nodes we encounter on the way up. */
+                default:
                     JS_ASSERT(*size < MaxParents);
                     nameable[(*size)++] = cur;
                     break;
             }
 
-            /*
-             * Normally the relevant parent of a node is its direct parent, but
-             * sometimes with code like:
-             *
-             *    var foo = (function() { return function() {}; })();
-             *
-             * the outer function is just a helper to create a scope for the
-             * returned function. Hence the name of the returned function should
-             * actually be 'foo'.  This loop sees if the current node is a
-             * PNK_RETURN, and if there is a direct function call we skip to
-             * that.
-             */
-            if (cur->isKind(PNK_RETURN)) {
-                for (int tmp = pos - 1; tmp > 0; tmp--) {
-                    if (isDirectCall(tmp, cur)) {
-                        pos = tmp;
-                        break;
-                    } else if (call(cur)) {
-                        /* Don't skip too high in the tree */
-                        break;
-                    }
-                    cur = parents[tmp];
-                }
-            }
         }
 
         return NULL;
     }
 
     /*
      * Resolve the name of a function. If the function already has a name
      * listed, then it is skipped. Otherwise an intelligent name is guessed to
--- a/js/src/gc/Marking.cpp
+++ b/js/src/gc/Marking.cpp
@@ -1157,17 +1157,17 @@ GCMarker::processMarkStackTop(SliceBudge
     JS_ASSERT(vp <= end);
     while (vp != end) {
         const Value &v = *vp++;
         if (v.isString()) {
             JSString *str = v.toString();
             JS_COMPARTMENT_ASSERT_STR(runtime, str);
             JS_ASSERT(str->compartment() == runtime->atomsCompartment ||
                       str->compartment() == obj->compartment());
-    if (str->markIfUnmarked())
+            if (str->markIfUnmarked())
                 ScanString(this, str);
         } else if (v.isObject()) {
             JSObject *obj2 = &v.toObject();
             JS_COMPARTMENT_ASSERT(runtime, obj2);
             JS_ASSERT(obj->compartment() == obj2->compartment());
             if (obj2->markIfUnmarked(getMarkColor())) {
                 pushValueArray(obj, vp, end);
                 obj = obj2;
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/basic/bug785094.js
@@ -0,0 +1,2 @@
+// |jit-test| dump-bytecode
+Function("for(let b; true; x) \nfalse");
--- a/js/src/jit-test/tests/basic/functionnames.js
+++ b/js/src/jit-test/tests/basic/functionnames.js
@@ -112,8 +112,19 @@ function f(g) {
     assertName(g, 'x<');
     return g();
 }
 var x = f(function () { return function() {}; });
 assertName(x, 'x</<');
 
 var a = {'b': function(){}};
 assertName(a.b, 'a.b');
+
+function g(f) {
+  assertName(f, '');
+}
+label: g(function () {});
+
+var z = [function() {}];
+assertName(z[0], 'z<');
+
+/* fuzz bug from 785089 */
+odeURIL:(function(){})
--- a/js/src/js.msg
+++ b/js/src/js.msg
@@ -112,17 +112,17 @@ MSG_DEF(JSMSG_BAD_REGEXP_FLAG,         5
 MSG_DEF(JSMSG_NO_INPUT,                59, 5, JSEXN_SYNTAXERR, "no input for /{0}/{1}{2}{3}{4}")
 MSG_DEF(JSMSG_CANT_OPEN,               60, 2, JSEXN_ERR, "can't open {0}: {1}")
 MSG_DEF(JSMSG_TOO_MANY_FUN_APPLY_ARGS, 61, 0, JSEXN_RANGEERR, "arguments array passed to Function.prototype.apply is too large")
 MSG_DEF(JSMSG_UNMATCHED_RIGHT_PAREN,   62, 0, JSEXN_SYNTAXERR, "unmatched ) in regular expression")
 MSG_DEF(JSMSG_TOO_BIG_TO_ENCODE,       63, 0, JSEXN_INTERNALERR, "data are to big to encode")
 MSG_DEF(JSMSG_ARG_INDEX_OUT_OF_RANGE,  64, 1, JSEXN_RANGEERR, "argument {0} accesses an index that is out of range")
 MSG_DEF(JSMSG_SPREAD_TOO_LARGE,        65, 0, JSEXN_RANGEERR, "array too large due to spread operand(s)")
 MSG_DEF(JSMSG_SOURCE_TOO_LONG,         66, 0, JSEXN_RANGEERR, "source is too long")
-MSG_DEF(JSMSG_UNUSED67,                67, 0, JSEXN_NONE,    "")
+MSG_DEF(JSMSG_BAD_WEAKMAP_KEY,         67, 0, JSEXN_TYPEERR, "cannot use the given object as a weak map key")
 MSG_DEF(JSMSG_BAD_SCRIPT_MAGIC,        68, 0, JSEXN_INTERNALERR, "bad script XDR magic number")
 MSG_DEF(JSMSG_PAREN_BEFORE_FORMAL,     69, 0, JSEXN_SYNTAXERR, "missing ( before formal parameters")
 MSG_DEF(JSMSG_MISSING_FORMAL,          70, 0, JSEXN_SYNTAXERR, "missing formal parameter")
 MSG_DEF(JSMSG_PAREN_AFTER_FORMAL,      71, 0, JSEXN_SYNTAXERR, "missing ) after formal parameters")
 MSG_DEF(JSMSG_CURLY_BEFORE_BODY,       72, 0, JSEXN_SYNTAXERR, "missing { before function body")
 MSG_DEF(JSMSG_CURLY_AFTER_BODY,        73, 0, JSEXN_SYNTAXERR, "missing } after function body")
 MSG_DEF(JSMSG_PAREN_BEFORE_COND,       74, 0, JSEXN_SYNTAXERR, "missing ( before condition")
 MSG_DEF(JSMSG_PAREN_AFTER_COND,        75, 0, JSEXN_SYNTAXERR, "missing ) after condition")
--- a/js/src/jsapi-tests/testOriginPrincipals.cpp
+++ b/js/src/jsapi-tests/testOriginPrincipals.cpp
@@ -1,46 +1,29 @@
 /* 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 "tests.h"
 #include "jsdbgapi.h"
 #include "jsobjinlines.h"
 
-JSPrincipals *sCurrentGlobalPrincipals = NULL;
-
-JSPrincipals *
-ObjectPrincipalsFinder(JSObject *)
-{
-    return sCurrentGlobalPrincipals;
-}
-
-static const JSSecurityCallbacks seccb = {
-    NULL,
-    NULL,
-    ObjectPrincipalsFinder,
-    NULL
-};
-
 JSPrincipals *sOriginPrincipalsInErrorReporter = NULL;
 
 static void
 ErrorReporter(JSContext *cx, const char *message, JSErrorReport *report)
 {
     sOriginPrincipalsInErrorReporter = report->originPrincipals;
 }
 
 JSPrincipals prin1 = { 1 };
 JSPrincipals prin2 = { 1 };
 
 BEGIN_TEST(testOriginPrincipals)
 {
-    JS_SetSecurityCallbacks(rt, &seccb);
-
     /*
      * Currently, the only way to set a non-trivial originPrincipal is to use
      * JS_EvaluateUCScriptForPrincipalsVersionOrigin. This does not expose the
      * compiled script, so we can only test nested scripts.
      */
 
     CHECK(testOuter("function f() {return 1}; f;"));
     CHECK(testOuter("function outer() { return (function () {return 2}); }; outer();"));
@@ -73,17 +56,21 @@ bool
 eval(const char *asciiChars, JSPrincipals *principals, JSPrincipals *originPrincipals, jsval *rval)
 {
     size_t len = strlen(asciiChars);
     jschar *chars = new jschar[len+1];
     for (size_t i = 0; i < len; ++i)
         chars[i] = asciiChars[i];
     chars[len] = 0;
 
-    JS::RootedObject global(cx, JS_GetGlobalObject(cx));
+    JS::RootedObject global(cx, JS_NewGlobalObject(cx, getGlobalClass(), principals));
+    CHECK(global);
+    JSAutoEnterCompartment ac;
+    CHECK(ac.enter(cx, global));
+    CHECK(JS_InitStandardClasses(cx, global));
     bool ok = JS_EvaluateUCScriptForPrincipalsVersionOrigin(cx, global,
                                                             principals,
                                                             originPrincipals,
                                                             chars, len, "", 0, rval,
                                                             JSVERSION_DEFAULT);
     delete[] chars;
     return ok;
 }
@@ -94,18 +81,16 @@ testOuter(const char *asciiChars)
     CHECK(testInner(asciiChars, &prin1, &prin1));
     CHECK(testInner(asciiChars, &prin1, &prin2));
     return true;
 }
 
 bool
 testInner(const char *asciiChars, JSPrincipals *principal, JSPrincipals *originPrincipal)
 {
-    sCurrentGlobalPrincipals = principal;
-
     jsval rval;
     CHECK(eval(asciiChars, principal, originPrincipal, &rval));
 
     JSScript *script = JS_GetFunctionScript(cx, JSVAL_TO_OBJECT(rval)->toFunction());
     CHECK(JS_GetScriptPrincipals(script) == principal);
     CHECK(JS_GetScriptOriginPrincipals(script) == originPrincipal);
 
     return true;
--- a/js/src/jsapi.h
+++ b/js/src/jsapi.h
@@ -1992,30 +1992,16 @@ typedef JSBool
 
 /*
  * Security protocol types.
  */
 
 typedef void
 (* JSDestroyPrincipalsOp)(JSPrincipals *principals);
 
-typedef JSBool
-(* JSSubsumePrincipalsOp)(JSPrincipals *principals1, JSPrincipals *principals2);
-
-/*
- * Return a weak reference to the principals associated with obj, possibly via
- * the immutable parent chain leading from obj to a top-level container (e.g.,
- * a window object in the DOM level 0).  If there are no principals associated
- * with obj, return null.  Therefore null does not mean an error was reported;
- * in no event should an error be reported or an exception be thrown by this
- * callback's implementation.
- */
-typedef JSPrincipals *
-(* JSObjectPrincipalsFinder)(JSObject *obj);
-
 /*
  * Used to check if a CSP instance wants to disable eval() and friends.
  * See js_CheckCSPPermitsJSAction() in jsobj.