Merge inbound to m-c. a=merge
authorRyan VanderMeulen <ryanvm@gmail.com>
Thu, 14 Aug 2014 22:15:29 -0400
changeset 221288 c9f8cc9ce89c95a173a8116a934a0689f5452aea
parent 221251 9827d3cf6f69c33dd7321fc9ecb4e8529de7ae8e (current diff)
parent 221287 150d3813133c7b30a5c8cd5f9b4afd630d3d0f36 (diff)
child 221296 eac6befe2416927871f6c100ffd9801bd2e06df5
child 221331 1135f262b3cab90b553c602e7f5be2c772d4d5c3
child 221374 ea86f30734114b5a4f906073ae3463a4c5c801dc
push id3979
push userraliiev@mozilla.com
push dateMon, 13 Oct 2014 16:35:44 +0000
treeherdermozilla-beta@30f2cc610691 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone34.0a1
first release with
nightly linux32
c9f8cc9ce89c / 34.0a1 / 20140815030202 / files
nightly linux64
c9f8cc9ce89c / 34.0a1 / 20140815030202 / files
nightly mac
c9f8cc9ce89c / 34.0a1 / 20140815030202 / files
nightly win32
c9f8cc9ce89c / 34.0a1 / 20140815030202 / files
nightly win64
c9f8cc9ce89c / 34.0a1 / 20140815030202 / files
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
releases
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge inbound to m-c. a=merge
intl/uconv/ucvcn/moz.build
intl/uconv/ucvibm/moz.build
intl/uconv/ucvja/moz.build
intl/uconv/ucvko/moz.build
intl/uconv/ucvlatin/moz.build
intl/uconv/ucvtw/moz.build
js/xpconnect/src/nsCxPusher.cpp
js/xpconnect/src/nsCxPusher.h
--- a/accessible/base/nsAccessibilityService.cpp
+++ b/accessible/base/nsAccessibilityService.cpp
@@ -1284,17 +1284,17 @@ nsAccessibilityService::CreateAccessible
                               nsGkAtoms::_true, eCaseMatters))
       accessible = new XULAlertAccessible(aContent, aDoc);
     else
       accessible = new EnumRoleAccessible(aContent, aDoc, roles::PANE);
 
   } else if (role.EqualsLiteral("xul:progressmeter")) {
     accessible = new XULProgressMeterAccessible(aContent, aDoc);
 
-  } else if (role.EqualsLiteral("xulstatusbar")) {
+  } else if (role.EqualsLiteral("xul:statusbar")) {
     accessible = new XULStatusBarAccessible(aContent, aDoc);
 
   } else if (role.EqualsLiteral("xul:scale")) {
     accessible = new XULSliderAccessible(aContent, aDoc);
 
   } else if (role.EqualsLiteral("xul:radiobutton")) {
     accessible = new XULRadioButtonAccessible(aContent, aDoc);
 
--- a/accessible/tests/mochitest/role/test_general.xul
+++ b/accessible/tests/mochitest/role/test_general.xul
@@ -17,16 +17,17 @@
   <script type="application/javascript">
   <![CDATA[
     function doTest()
     {
       ok(!isAccessible("statusbarpanel"),
                       "statusbarpanel shouldn't be accessible.");
       testRole("statusbarpanel-iconic", ROLE_PUSHBUTTON);
       testRole("statusbarpanel-iconic-text", ROLE_PUSHBUTTON);
+      testRole("statusbar", ROLE_STATUSBAR);
 
       SimpleTest.finish();
     }
 
     SimpleTest.waitForExplicitFinish();
     addA11yLoadEvent(doTest);
   ]]>
   </script>
@@ -44,12 +45,13 @@
     </div>
     <pre id="test">
     </pre>
   </body>
 
   <statusbarpanel id="statusbarpanel"></statusbarpanel>
   <statusbarpanel id="statusbarpanel-iconic" class="statusbarpanel-iconic"></statusbarpanel>
   <statusbarpanel id="statusbarpanel-iconic-text" class="statusbarpanel-iconic-text"></statusbarpanel>
+  <statusbar id="statusbar"></statusbar>
 
   </hbox>
 </window>
 
--- a/build/automation.py.in
+++ b/build/automation.py.in
@@ -212,17 +212,16 @@ class Automation(object):
                  preexec_fn=None,
                  close_fds=False,
                  shell=False,
                  cwd=None,
                  env=None,
                  universal_newlines=False,
                  startupinfo=None,
                  creationflags=0):
-      args = automationutils.wrapCommand(args)
       _log.info("INFO | automation.py | Launching: %s", subprocess.list2cmdline(args))
       subprocess.Popen.__init__(self, args, bufsize, executable,
                                 stdin, stdout, stderr,
                                 preexec_fn, close_fds,
                                 shell, cwd, env,
                                 universal_newlines, startupinfo, creationflags)
       self.log = _log
 
--- a/build/automationutils.py
+++ b/build/automationutils.py
@@ -21,17 +21,16 @@ import mozinfo
   "ZipFileReader",
   "addCommonOptions",
   "dumpLeakLog",
   "isURL",
   "processLeakLog",
   "getDebuggerInfo",
   "DEBUGGER_INFO",
   "replaceBackSlashes",
-  "wrapCommand",
   'KeyValueParseError',
   'parseKeyValue',
   'systemMemory',
   'environment',
   'dumpScreen',
   "ShutdownLeaks"
   ]
 
@@ -397,29 +396,16 @@ def processLeakLog(leakLogFile, leakThre
       m = fileNameRegExp.search(fileName)
       if m:
         processType = m.group(1)
       processSingleLeakFile(thisFile, processType, leakThreshold)
 
 def replaceBackSlashes(input):
   return input.replace('\\', '/')
 
-def wrapCommand(cmd):
-  """
-  If running on OS X 10.5 or older, wrap |cmd| so that it will
-  be executed as an i386 binary, in case it's a 32-bit/64-bit universal
-  binary.
-  """
-  if platform.system() == "Darwin" and \
-     hasattr(platform, 'mac_ver') and \
-     platform.mac_ver()[0][:4] < '10.6':
-    return ["arch", "-arch", "i386"] + cmd
-  # otherwise just execute the command normally
-  return cmd
-
 class KeyValueParseError(Exception):
   """error when parsing strings of serialized key-values"""
   def __init__(self, msg, errors=()):
     self.errors = errors
     Exception.__init__(self, msg)
 
 def parseKeyValue(strings, separator='=', context='key, value: '):
   """
--- a/content/media/webaudio/AudioContext.cpp
+++ b/content/media/webaudio/AudioContext.cpp
@@ -535,18 +535,18 @@ AudioContext::DestinationStream() const
   }
   return nullptr;
 }
 
 double
 AudioContext::CurrentTime() const
 {
   MediaStream* stream = Destination()->Stream();
-  return stream->StreamTimeToSeconds(stream->GetCurrentTime()) +
-      ExtraCurrentTime();
+  return StreamTimeToDOMTime(stream->
+                             StreamTimeToSeconds(stream->GetCurrentTime()));
 }
 
 void
 AudioContext::Shutdown()
 {
   mIsShutDown = true;
 
   // We mute rather than suspending, because the delay between the ::Shutdown
--- a/content/media/webaudio/AudioContext.h
+++ b/content/media/webaudio/AudioContext.h
@@ -228,16 +228,21 @@ public:
 
   void UpdateNodeCount(int32_t aDelta);
 
   double DOMTimeToStreamTime(double aTime) const
   {
     return aTime - ExtraCurrentTime();
   }
 
+  double StreamTimeToDOMTime(double aTime) const
+  {
+    return aTime + ExtraCurrentTime();
+  }
+
   IMPL_EVENT_HANDLER(mozinterruptbegin)
   IMPL_EVENT_HANDLER(mozinterruptend)
 
 private:
   /**
    * Returns the amount of extra time added to the current time of the
    * AudioDestinationNode's MediaStream to get this AudioContext's currentTime.
    * Must be subtracted from all DOM API parameter times that are on the same
--- a/content/media/webaudio/ScriptProcessorNode.cpp
+++ b/content/media/webaudio/ScriptProcessorNode.cpp
@@ -353,17 +353,16 @@ private:
 
     // we now have a full input buffer ready to be sent to the main thread.
     TrackTicks playbackTick = mSource->GetCurrentPosition();
     // Add the duration of the current sample
     playbackTick += WEBAUDIO_BLOCK_SIZE;
     // Add the delay caused by the main thread
     playbackTick += mSharedBuffers->DelaySoFar();
     // Compute the playback time in the coordinate system of the destination
-    // FIXME: bug 970773
     double playbackTime =
       mSource->DestinationTimeFromTicks(mDestination, playbackTick);
 
     class Command : public nsRunnable
     {
     public:
       Command(AudioNodeStream* aStream,
               InputChannels& aInputChannels,
@@ -378,49 +377,40 @@ private:
           for (uint32_t i = 0; i < mInputChannels.Length(); ++i) {
             mInputChannels[i] = aInputChannels[i].forget();
           }
         }
       }
 
       NS_IMETHODIMP Run()
       {
-        // If it's not safe to run scripts right now, schedule this to run later
-        if (!nsContentUtils::IsSafeToRunScript()) {
-          nsContentUtils::AddScriptRunner(this);
+        nsRefPtr<ScriptProcessorNode> node = static_cast<ScriptProcessorNode*>
+          (mStream->Engine()->NodeMainThread());
+        if (!node) {
           return NS_OK;
         }
-
-        nsRefPtr<ScriptProcessorNode> node;
-        {
-          // No need to keep holding the lock for the whole duration of this
-          // function, since we're holding a strong reference to it, so if
-          // we can obtain the reference, we will hold the node alive in
-          // this function.
-          MutexAutoLock lock(mStream->Engine()->NodeMutex());
-          node = static_cast<ScriptProcessorNode*>(mStream->Engine()->Node());
-        }
-        if (!node || !node->Context()) {
+        AudioContext* context = node->Context();
+        if (!context) {
           return NS_OK;
         }
 
         AutoJSAPI jsapi;
         if (NS_WARN_IF(!jsapi.Init(node->GetOwner()))) {
           return NS_OK;
         }
         JSContext* cx = jsapi.cx();
 
         // Create the input buffer
         nsRefPtr<AudioBuffer> inputBuffer;
         if (!mNullInput) {
           ErrorResult rv;
           inputBuffer =
-            AudioBuffer::Create(node->Context(), mInputChannels.Length(),
+            AudioBuffer::Create(context, mInputChannels.Length(),
                                 node->BufferSize(),
-                                node->Context()->SampleRate(), cx, rv);
+                                context->SampleRate(), cx, rv);
           if (rv.Failed()) {
             return NS_OK;
           }
           // Put the channel data inside it
           for (uint32_t i = 0; i < mInputChannels.Length(); ++i) {
             inputBuffer->SetRawChannelContents(i, mInputChannels[i]);
           }
         }
@@ -428,17 +418,17 @@ private:
         // Ask content to produce data in the output buffer
         // Note that we always avoid creating the output buffer here, and we try to
         // avoid creating the input buffer as well.  The AudioProcessingEvent class
         // knows how to lazily create them if needed once the script tries to access
         // them.  Otherwise, we may be able to get away without creating them!
         nsRefPtr<AudioProcessingEvent> event = new AudioProcessingEvent(node, nullptr, nullptr);
         event->InitEvent(inputBuffer,
                          mInputChannels.Length(),
-                         mPlaybackTime);
+                         context->StreamTimeToDOMTime(mPlaybackTime));
         node->DispatchTrustedEvent(event);
 
         // Steal the output buffers if they have been set.
         // Don't create a buffer if it hasn't been used to return output;
         // FinishProducingOutputBuffer() will optimize output = null.
         // GetThreadSharedChannelsForRate() may also return null after OOM.
         nsRefPtr<ThreadSharedFloatArrayBufferList> output;
         if (event->HasOutputBuffer()) {
--- a/content/media/webaudio/test/mochitest.ini
+++ b/content/media/webaudio/test/mochitest.ini
@@ -112,16 +112,17 @@ skip-if = (toolkit == 'gonk' && !debug)
 [test_pannerNode_equalPower.html]
 [test_pannerNodeAbove.html]
 [test_pannerNodeChannelCount.html]
 [test_pannerNodeHRTFSymmetry.html]
 [test_pannerNodeTail.html]
 [test_periodicWave.html]
 [test_scriptProcessorNode.html]
 [test_scriptProcessorNodeChannelCount.html]
+[test_scriptProcessorNode_playbackTime1.html]
 [test_scriptProcessorNodeZeroInputOutput.html]
 [test_scriptProcessorNodeNotConnected.html]
 [test_singleSourceDest.html]
 [test_stereoPanningWithGain.html]
 [test_waveDecoder.html]
 [test_waveShaper.html]
 [test_waveShaperNoCurve.html]
 [test_waveShaperZeroLengthCurve.html]
--- a/content/media/webaudio/test/test_scriptProcessorNode.html
+++ b/content/media/webaudio/test/test_scriptProcessorNode.html
@@ -59,81 +59,68 @@ addLoadEvent(function() {
     }
     return buffer.length;
   }
 
   var sp = context.createScriptProcessor(2048);
   sourceSP.connect(sp);
   sp.connect(context.destination);
   var lastPlaybackTime = 0;
-  sp.onaudioprocess = function(e) {
-    isnot(buffer, null, "The audioprocess handler for sourceSP must be run at this point");
+
+  var emptyBuffer = context.createBuffer(1, 2048, context.sampleRate);
+
+  function checkAudioProcessingEvent(e) {
     is(e.target, sp, "Correct event target");
     ok(e.playbackTime > lastPlaybackTime, "playbackTime correctly set");
     lastPlaybackTime = e.playbackTime;
     is(e.inputBuffer.numberOfChannels, 2, "Correct number of channels for the input buffer");
     is(e.inputBuffer.length, 2048, "Correct length for the input buffer");
     is(e.inputBuffer.sampleRate, context.sampleRate, "Correct sample rate for the input buffer");
     is(e.outputBuffer.numberOfChannels, 2, "Correct number of channels for the output buffer");
     is(e.outputBuffer.length, 2048, "Correct length for the output buffer");
     is(e.outputBuffer.sampleRate, context.sampleRate, "Correct sample rate for the output buffer");
 
+    compareChannels(e.outputBuffer.getChannelData(0), emptyBuffer.getChannelData(0));
+    compareChannels(e.outputBuffer.getChannelData(1), emptyBuffer.getChannelData(0));
+  }
+
+  sp.onaudioprocess = function(e) {
+    isnot(buffer, null, "The audioprocess handler for sourceSP must be run at this point");
+    checkAudioProcessingEvent(e);
+
     // Because of the initial latency added by the second script processor node,
     // we will never see any generated audio frames in the first callback.
-    var emptyBuffer = context.createBuffer(1, 2048, context.sampleRate);
     compareChannels(e.inputBuffer.getChannelData(0), emptyBuffer.getChannelData(0));
     compareChannels(e.inputBuffer.getChannelData(1), emptyBuffer.getChannelData(0));
-    compareChannels(e.outputBuffer.getChannelData(0), emptyBuffer.getChannelData(0));
-    compareChannels(e.outputBuffer.getChannelData(1), emptyBuffer.getChannelData(0));
 
     sp.onaudioprocess = function(e) {
-      is(e.target, sp, "Correct event target");
-      ok(e.playbackTime > lastPlaybackTime, "playbackTime correctly set");
-      lastPlaybackTime = e.playbackTime;
-      is(e.inputBuffer.numberOfChannels, 2, "Correct number of channels for the input buffer");
-      is(e.inputBuffer.length, 2048, "Correct length for the input buffer");
-      is(e.inputBuffer.sampleRate, context.sampleRate, "Correct sample rate for the input buffer");
-      is(e.outputBuffer.numberOfChannels, 2, "Correct number of channels for the output buffer");
-      is(e.outputBuffer.length, 2048, "Correct length for the output buffer");
-      is(e.outputBuffer.sampleRate, context.sampleRate, "Correct sample rate for the output buffer");
+      checkAudioProcessingEvent(e);
 
       var firstNonZero = findFirstNonZeroSample(e.inputBuffer);
       ok(firstNonZero <= 2048, "First non-zero sample within range");
 
       compareChannels(e.inputBuffer.getChannelData(0), emptyBuffer.getChannelData(0), firstNonZero);
       compareChannels(e.inputBuffer.getChannelData(1), emptyBuffer.getChannelData(0), firstNonZero);
       compareChannels(e.inputBuffer.getChannelData(0), buffer.getChannelData(0), 2048 - firstNonZero, firstNonZero, 0);
       compareChannels(e.inputBuffer.getChannelData(1), buffer.getChannelData(1), 2048 - firstNonZero, firstNonZero, 0);
-      compareChannels(e.outputBuffer.getChannelData(0), emptyBuffer.getChannelData(0));
-      compareChannels(e.outputBuffer.getChannelData(1), emptyBuffer.getChannelData(0));
 
       if (firstNonZero == 0) {
         // If we did not experience any delays, the test is done!
         sp.onaudioprocess = null;
 
         SimpleTest.finish();
       } else if (firstNonZero != 2048) {
         // In case we just saw a zero buffer this time, wait one more round
         sp.onaudioprocess = function(e) {
-          is(e.target, sp, "Correct event target");
-          ok(e.playbackTime > lastPlaybackTime, "playbackTime correctly set");
-          lastPlaybackTime = e.playbackTime;
-          is(e.inputBuffer.numberOfChannels, 2, "Correct number of channels for the input buffer");
-          is(e.inputBuffer.length, 2048, "Correct length for the input buffer");
-          is(e.inputBuffer.sampleRate, context.sampleRate, "Correct sample rate for the input buffer");
-          is(e.outputBuffer.numberOfChannels, 2, "Correct number of channels for the output buffer");
-          is(e.outputBuffer.length, 2048, "Correct length for the output buffer");
-          is(e.outputBuffer.sampleRate, context.sampleRate, "Correct sample rate for the output buffer");
+          checkAudioProcessingEvent(e);
 
           compareChannels(e.inputBuffer.getChannelData(0), buffer.getChannelData(0), firstNonZero, 0, 2048 - firstNonZero);
           compareChannels(e.inputBuffer.getChannelData(1), buffer.getChannelData(1), firstNonZero, 0, 2048 - firstNonZero);
           compareChannels(e.inputBuffer.getChannelData(0), emptyBuffer.getChannelData(0), undefined, firstNonZero);
           compareChannels(e.inputBuffer.getChannelData(1), emptyBuffer.getChannelData(0), undefined, firstNonZero);
-          compareChannels(e.outputBuffer.getChannelData(0), emptyBuffer.getChannelData(0));
-          compareChannels(e.outputBuffer.getChannelData(1), emptyBuffer.getChannelData(0));
 
           sp.onaudioprocess = null;
 
           SimpleTest.finish();
         };
       }
     };
   };
new file mode 100644
--- /dev/null
+++ b/content/media/webaudio/test/test_scriptProcessorNode_playbackTime1.html
@@ -0,0 +1,41 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+  <title>Test ScriptProcessorNode playbackTime for bug 970773</title>
+  <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+
+SimpleTest.waitForExplicitFinish();
+addLoadEvent(
+  function() {
+    const delay = 0.1;
+    var context = new AudioContext();
+    SimpleTest.executeSoon( // to ensure that AudioContext has started
+      function() {
+        setTimeout( // wait for |delay|
+          function() {
+            var sp = context.createScriptProcessor(256);
+            sp.connect(context.destination);
+            sp.onaudioprocess =
+              function(e) {
+                var minimum =
+                  (delay + e.inputBuffer.length/context.sampleRate) *
+                  (1.0 - 1.0/Math.pow(2.0,52.0)); // double precision
+                ok(e.playbackTime >= minimum,
+                   "playbackTime " + e.playbackTime +
+                   " beyond expected minimum " + minimum);
+                sp.onaudioprocess = null;
+                SimpleTest.finish();
+              };
+          }, 1000 * delay);
+      });
+  });
+
+</script>
+</pre>
+</body>
+</html>
--- a/dom/base/ScriptSettings.h
+++ b/dom/base/ScriptSettings.h
@@ -66,22 +66,23 @@ inline JSObject& IncumbentJSGlobal()
   return *GetIncumbentGlobal()->GetGlobalJSObject();
 }
 
 class ScriptSettingsStack;
 class ScriptSettingsStackEntry {
   friend class ScriptSettingsStack;
 
 public:
-  ScriptSettingsStackEntry(nsIGlobalObject *aGlobal, bool aCandidate);
   ~ScriptSettingsStackEntry();
 
   bool NoJSAPI() { return !mGlobalObject; }
 
 protected:
+  ScriptSettingsStackEntry(nsIGlobalObject *aGlobal, bool aCandidate);
+
   nsCOMPtr<nsIGlobalObject> mGlobalObject;
   bool mIsCandidateEntryPoint;
 
 private:
   // This constructor is only for use by AutoNoJSAPI.
   friend class AutoNoJSAPI;
   ScriptSettingsStackEntry();
 
--- a/intl/uconv/moz.build
+++ b/intl/uconv/moz.build
@@ -1,23 +1,14 @@
 # -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
 # vim: set filetype=python:
 # 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/.
 
-DIRS += [
-    'ucvja',
-    'ucvcn',
-    'ucvlatin',
-    'ucvtw',
-    'ucvko',
-    'ucvibm',
-]
-
 TEST_DIRS += ['tests']
 
 XPIDL_SOURCES += [
     'nsICurrentCharsetListener.idl',
     'nsIScriptableUConv.idl',
     'nsITextToSubURI.idl',
     'nsIUTF8ConverterService.idl',
 ]
@@ -26,16 +17,23 @@ XPIDL_MODULE = 'uconv'
 
 EXPORTS += [
     'nsEncoderDecoderUtils.h',
     'nsIUnicodeDecoder.h',
     'nsIUnicodeEncoder.h',
     'nsUConvCID.h',
     'nsUCSupport.h',
     'uconvutil.h',
+    'ucvcn/nsUCvCnCID.h',
+    'ucvibm/nsUCvIBMCID.h',
+    'ucvja/nsUCVJA2CID.h',
+    'ucvja/nsUCVJACID.h',
+    'ucvko/nsUCvKOCID.h',
+    'ucvlatin/nsUCvLatinCID.h',
+    'ucvtw/nsUCvTWCID.h',
 ]
 
 UNIFIED_SOURCES += [
     'nsConverterInputStream.cpp',
     'nsConverterOutputStream.cpp',
     'nsCP1252ToUnicode.cpp',
     'nsISO88591ToUnicode.cpp',
     'nsMacRomanToUnicode.cpp',
deleted file mode 100644
--- a/intl/uconv/ucvcn/moz.build
+++ /dev/null
@@ -1,9 +0,0 @@
-# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
-# vim: set filetype=python:
-# 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/.
-
-EXPORTS += [
-    'nsUCvCnCID.h',
-]
deleted file mode 100644
--- a/intl/uconv/ucvibm/moz.build
+++ /dev/null
@@ -1,9 +0,0 @@
-# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
-# vim: set filetype=python:
-# 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/.
-
-EXPORTS += [
-    'nsUCvIBMCID.h',
-]
deleted file mode 100644
--- a/intl/uconv/ucvja/moz.build
+++ /dev/null
@@ -1,10 +0,0 @@
-# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
-# vim: set filetype=python:
-# 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/.
-
-EXPORTS += [
-    'nsUCVJA2CID.h',
-    'nsUCVJACID.h',
-]
deleted file mode 100644
--- a/intl/uconv/ucvko/moz.build
+++ /dev/null
@@ -1,9 +0,0 @@
-# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
-# vim: set filetype=python:
-# 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/.
-
-EXPORTS += [
-    'nsUCvKOCID.h',
-]
deleted file mode 100644
--- a/intl/uconv/ucvlatin/moz.build
+++ /dev/null
@@ -1,9 +0,0 @@
-# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
-# vim: set filetype=python:
-# 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/.
-
-EXPORTS += [
-    'nsUCvLatinCID.h',
-]
deleted file mode 100644
--- a/intl/uconv/ucvtw/moz.build
+++ /dev/null
@@ -1,9 +0,0 @@
-# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
-# vim: set filetype=python:
-# 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/.
-
-EXPORTS += [
-    'nsUCvTWCID.h',
-]
new file mode 100644
--- /dev/null
+++ b/js/public/DebugAPI.h
@@ -0,0 +1,256 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sts=4 et sw=4 tw=99:
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+// Interfaces by which the embedding can interact with the Debugger API.
+
+#ifndef js_DebugAPI_h
+#define js_DebugAPI_h
+
+#include "mozilla/Assertions.h"
+#include "mozilla/Attributes.h"
+#include "mozilla/Move.h"
+
+#include "jspubtd.h"
+
+#include "js/RootingAPI.h"
+#include "js/TypeDecls.h"
+
+namespace js {
+class Debugger;
+}
+
+namespace JS {
+namespace dbg {
+
+// Helping embedding code build objects for Debugger
+// -------------------------------------------------
+//
+// Some Debugger API features lean on the embedding application to construct
+// their result values. For example, Debugger.Frame.prototype.scriptEntryReason
+// calls hooks provided by the embedding to construct values explaining why it
+// invoked JavaScript; if F is a frame called from a mouse click event handler,
+// F.scriptEntryReason would return an object of the form:
+//
+//   { eventType: "mousedown", event: <object> }
+//
+// where <object> is a Debugger.Object whose referent is the event being
+// dispatched.
+//
+// However, Debugger implements a trust boundary. Debuggee code may be
+// considered untrusted; debugger code needs to be protected from debuggee
+// getters, setters, proxies, Object.watch watchpoints, and any other feature
+// that might accidentally cause debugger code to set the debuggee running. The
+// Debugger API tries to make it easy to write safe debugger code by only
+// offering access to debuggee objects via Debugger.Object instances, which
+// ensure that only those operations whose explicit purpose is to invoke
+// debuggee code do so. But this protective membrane is only helpful if we
+// interpose Debugger.Object instances in all the necessary spots.
+//
+// SpiderMonkey's compartment system also implements a trust boundary. The
+// debuggee and debugger are always in different compartments. Inter-compartment
+// work requires carefully tracking which compartment each JSObject or JS::Value
+// belongs to, and ensuring that is is correctly wrapped for each operation.
+//
+// It seems precarious to expect the embedding's hooks to implement these trust
+// boundaries. Instead, the JS::dbg::Builder API segregates the code which
+// constructs trusted objects from that which deals with untrusted objects.
+// Trusted objects have an entirely different C++ type, so code that improperly
+// mixes trusted and untrusted objects is caught at compile time.
+//
+// In the structure shown above, there are two trusted objects, and one
+// untrusted object:
+//
+// - The overall object, with the 'eventType' and 'event' properties, is a
+//   trusted object. We're going to return it to D.F.p.scriptEntryReason's
+//   caller, which will handle it directly.
+//
+// - The Debugger.Object instance appearing as the value of the 'event' property
+//   is a trusted object. It belongs to the same Debugger instance as the
+//   Debugger.Frame instance whose scriptEntryReason accessor was called, and
+//   presents a safe reflection-oriented API for inspecting its referent, which
+//   is:
+//
+// - The actual event object, an untrusted object, and the referent of the
+//   Debugger.Object above. (Content can do things like replacing accessors on
+//   Event.prototype.)
+//
+// Using JS::dbg::Builder, all objects and values the embedding deals with
+// directly are considered untrusted, and are assumed to be debuggee values. The
+// only way to construct trusted objects is to use Builder's own methods, which
+// return a separate Object type. The only way to set a property on a trusted
+// object is through that Object type. The actual trusted object is never
+// exposed to the embedding.
+//
+// So, for example, the embedding might use code like the following to construct
+// the object shown above, given a Builder passed to it by Debugger:
+//
+//    bool
+//    MyScriptEntryReason::explain(JSContext *cx,
+//                                 Builder &builder,
+//                                 Builder::Object &result)
+//    {
+//        JSObject *eventObject = ... obtain debuggee event object somehow ...;
+//        if (!eventObject)
+//            return false;
+//        result = builder.newObject(cx);
+//        return result &&
+//               result.defineProperty(cx, "eventType", SafelyFetchType(eventObject)) &&
+//               result.defineProperty(cx, "event", eventObject);
+//    }
+//
+//
+// Object::defineProperty also accepts an Object as the value to store on the
+// property. By its type, we know that the value is trusted, so we set it
+// directly as the property's value, without interposing a Debugger.Object
+// wrapper. This allows the embedding to builted nested structures of trusted
+// objects.
+//
+// The Builder and Builder::Object methods take care of doing whatever
+// compartment switching and wrapping are necessary to construct the trusted
+// values in the Debugger's compartment.
+//
+// The Object type is self-rooting. Construction, assignment, and destruction
+// all properly root the referent object.
+
+class BuilderOrigin;
+
+class Builder {
+    // The Debugger instance whose client we are building a value for. We build
+    // objects in this object's compartment.
+    PersistentRootedObject debuggerObject;
+
+    // debuggerObject's Debugger structure, for convenience.
+    js::Debugger *debugger;
+
+    // Check that |thing| is in the same compartment as our debuggerObject. Used
+    // for assertions when constructing BuiltThings. We can overload this as we
+    // add more instantiations of BuiltThing.
+#if DEBUG
+    void assertBuilt(JSObject *obj);
+#else
+    void assertBuilt(JSObject *obj) { }
+#endif
+
+  protected:
+    // A reference to a trusted object or value. At the moment, we only use it
+    // with JSObject *.
+    template<typename T>
+    class BuiltThing {
+        friend class BuilderOrigin;
+
+        void nonNull() {}
+
+      protected:
+        // The Builder to which this trusted thing belongs.
+        Builder &owner;
+
+        // A rooted reference to our value.
+        PersistentRooted<T> value;
+
+        BuiltThing(JSContext *cx, Builder &owner_, T value_ = js::GCMethods<T>::initial())
+          : owner(owner_), value(cx, value_)
+        {
+            owner.assertBuilt(value_);
+        }
+
+        // Forward some things from our owner, for convenience.
+        js::Debugger *debugger() const { return owner.debugger; }
+        JSObject *debuggerObject() const { return owner.debuggerObject; }
+
+      public:
+        BuiltThing(const BuiltThing &rhs) : owner(rhs.owner), value(rhs.value) { }
+        BuiltThing &operator=(const BuiltThing &rhs) {
+            MOZ_ASSERT(&owner == &rhs.owner);
+            owner.assertBuilt(rhs.value);
+            value = rhs.value;
+            return *this;
+        }
+
+        typedef void (BuiltThing::* ConvertibleToBool)();
+        operator ConvertibleToBool() const {
+            // If we ever instantiate BuiltThink<Value>, this might not suffice.
+            return value ? &BuiltThing::nonNull : 0;
+        }
+
+      private:
+        BuiltThing() MOZ_DELETE;
+    };
+
+  public:
+    // A reference to a trusted object, possibly null. Instances of Object are
+    // always properly rooted. They can be copied and assigned, as if they were
+    // pointers.
+    class Object: private BuiltThing<JSObject *> {
+        friend class Builder;           // for construction
+        friend class BuilderOrigin;     // for unwrapping
+
+        typedef BuiltThing<JSObject *> Base;
+
+        // This is private, because only Builders can create Objects that
+        // actually point to something (hence the 'friend' declaration).
+        Object(JSContext *cx, Builder &owner_, HandleObject obj) : Base(cx, owner_, obj.get()) { }
+
+        bool definePropertyToTrusted(JSContext *cx, const char *name,
+                                     JS::MutableHandleValue value);
+
+      public:
+        Object(JSContext *cx, Builder &owner_) : Base(cx, owner_, nullptr) { }
+        Object(const Object &rhs) : Base(rhs) { }
+
+        // Our automatically-generated assignment operator can see our base
+        // class's assignment operator, so we don't need to write one out here.
+
+        // Set the property named |name| on this object to |value|.
+        //
+        // If |value| is a string or primitive, re-wrap it for the debugger's
+        // compartment.
+        //
+        // If |value| is an object, assume it is a debuggee object and make a
+        // Debugger.Object instance referring to it. Set that as the propery's
+        // value.
+        //
+        // If |value| is another trusted object, store it directly as the
+        // property's value.
+        //
+        // On error, report the problem on cx and return false.
+        bool defineProperty(JSContext *cx, const char *name, JS::HandleValue value);
+        bool defineProperty(JSContext *cx, const char *name, JS::HandleObject value);
+        bool defineProperty(JSContext *cx, const char *name, Object &value);
+
+        using Base::ConvertibleToBool;
+        using Base::operator ConvertibleToBool;
+    };
+
+    // Build an empty object for direct use by debugger code, owned by this
+    // Builder. If an error occurs, report it on cx and return a false Object.
+    Object newObject(JSContext *cx);
+
+  protected:
+    Builder(JSContext *cx, js::Debugger *debugger);
+};
+
+// Debugger itself instantiates this subclass of Builder, which can unwrap
+// BuiltThings that belong to it.
+class BuilderOrigin : public Builder {
+    template<typename T>
+    T unwrapAny(const BuiltThing<T> &thing) {
+        MOZ_ASSERT(&thing.owner == this);
+        return thing.value.get();
+    }
+
+  public:
+    BuilderOrigin(JSContext *cx, js::Debugger *debugger_)
+      : Builder(cx, debugger_)
+    { }
+
+    JSObject *unwrap(Object &object) { return unwrapAny(object); }
+};
+
+} // namespace dbg
+} // namespace JS
+
+
+#endif /* js_DebugAPI_h */
--- a/js/public/UbiNode.h
+++ b/js/public/UbiNode.h
@@ -193,17 +193,20 @@ class Base {
     // Return the size of this node, in bytes. Include any structures that this
     // node owns exclusively that are not exposed as their own ubi::Nodes.
     virtual size_t size() const = 0;
 
     // Return an EdgeRange that initially contains all the referent's outgoing
     // edges. The EdgeRange should be freed with 'js_delete'. (You could use
     // ScopedDJSeletePtr<EdgeRange> to manage it.) On OOM, report an exception
     // on |cx| and return nullptr.
-    virtual EdgeRange *edges(JSContext *cx) const = 0;
+    //
+    // If wantNames is true, compute names for edges. Doing so can be expensive
+    // in time and memory.
+    virtual EdgeRange *edges(JSContext *cx, bool wantNames) const = 0;
 
     // Return the Zone to which this node's referent belongs, or nullptr if the
     // referent is not of a type allocated in SpiderMonkey Zones.
     virtual JS::Zone *zone() const = 0;
 
     // Return the compartment for this node. Some ubi::Node referents are not
     // associated with JSCompartments, such as JSStrings (which are associated
     // with Zones). When the referent is not associated with a compartment,
@@ -328,19 +331,21 @@ class Node {
     // If this node refers to something that can be represented as a JavaScript
     // value that is safe to expose to JavaScript code, return that value.
     // Otherwise return UndefinedValue(). JSStrings, JS::Symbols, and some (but
     // not all!) JSObjects can be exposed.
     JS::Value exposeToJS() const;
 
     const jschar *typeName()        const { return base()->typeName(); }
     size_t size()                   const { return base()->size(); }
-    EdgeRange *edges(JSContext *cx) const { return base()->edges(cx); }
     JS::Zone *zone()                const { return base()->zone(); }
     JSCompartment *compartment()    const { return base()->compartment(); }
+    EdgeRange *edges(JSContext *cx, bool wantNames = true) const {
+        return base()->edges(cx, wantNames);
+    }
 
     // A hash policy for ubi::Nodes.
     // This simply uses the stock PointerHasher on the ubi::Node's pointer.
     // We specialize DefaultHasher below to make this the default.
     class HashPolicy {
         typedef js::PointerHasher<void *, mozilla::tl::FloorLog2<sizeof(void *)>::value> PtrHash;
 
       public:
@@ -360,17 +365,18 @@ class Node {
 // Each Edge class should inherit from this base class, overriding as
 // appropriate.
 class Edge {
   protected:
     Edge() : name(nullptr), referent() { }
     virtual ~Edge() { }
 
   public:
-    // This edge's name.
+    // This edge's name. This may be nullptr, if Node::edges was called with
+    // false as the wantNames parameter.
     //
     // The storage is owned by this Edge, and will be freed when this Edge is
     // destructed.
     //
     // (In real life we'll want a better representation for names, to avoid
     // creating tons of strings when the names follow a pattern; and we'll need
     // to think about lifetimes carefully to ensure traversal stays cheap.)
     const jschar *name;
@@ -423,17 +429,17 @@ class EdgeRange {
 // Concrete classes for ubi::Node referent types.
 
 // A reusable ubi::Concrete specialization base class for types supported by
 // JS_TraceChildren.
 template<typename Referent>
 class TracerConcrete : public Base {
     const jschar *typeName() const MOZ_OVERRIDE { return concreteTypeName; }
     size_t size() const MOZ_OVERRIDE { return 0; } // not implemented yet; bug 1011300
-    EdgeRange *edges(JSContext *) const MOZ_OVERRIDE;
+    EdgeRange *edges(JSContext *, bool wantNames) const MOZ_OVERRIDE;
     JS::Zone *zone() const MOZ_OVERRIDE { return get().zone(); }
     JSCompartment *compartment() const MOZ_OVERRIDE { return nullptr; }
 
   protected:
     explicit TracerConcrete(Referent *ptr) : Base(ptr) { }
     Referent &get() const { return *static_cast<Referent *>(ptr); }
 
   public:
@@ -467,17 +473,17 @@ template<> struct Concrete<js::Shape> : 
 template<> struct Concrete<js::BaseShape> : TracerConcreteWithCompartment<js::BaseShape> { };
 template<> struct Concrete<js::types::TypeObject> : TracerConcrete<js::types::TypeObject> { };
 
 // The ubi::Node null pointer. Any attempt to operate on a null ubi::Node asserts.
 template<>
 class Concrete<void> : public Base {
     const jschar *typeName() const MOZ_OVERRIDE;
     size_t size() const MOZ_OVERRIDE;
-    EdgeRange *edges(JSContext *cx) const MOZ_OVERRIDE;
+    EdgeRange *edges(JSContext *cx, bool wantNames) const MOZ_OVERRIDE;
     JS::Zone *zone() const MOZ_OVERRIDE;
     JSCompartment *compartment() const MOZ_OVERRIDE;
 
     explicit Concrete(void *ptr) : Base(ptr) { }
 
   public:
     static void construct(void *storage, void *ptr) { new (storage) Concrete(ptr); }
     static const jschar concreteTypeName[];
--- a/js/public/UbiNodeTraverse.h
+++ b/js/public/UbiNodeTraverse.h
@@ -79,27 +79,31 @@ struct BreadthFirst {
 
     // Construct a breadth-first traversal object that reports the nodes it
     // reaches to |handler|. The traversal object reports OOM on |cx|, and
     // asserts that no GC happens in |cx|'s runtime during its lifetime.
     //
     // We do nothing with noGC, other than require it to exist, with a lifetime
     // that encloses our own.
     BreadthFirst(JSContext *cx, Handler &handler, const JS::AutoCheckCannotGC &noGC)
-      : cx(cx), visited(cx), handler(handler), pending(cx),
+      : wantNames(true), cx(cx), visited(cx), handler(handler), pending(cx),
         traversalBegun(false), stopRequested(false), abandonRequested(false)
     { }
 
     // Initialize this traversal object. Return false on OOM.
     bool init() { return visited.init(); }
 
     // Add |node| as a starting point for the traversal. You may add
     // as many starting points as you like. Return false on OOM.
     bool addStart(Node node) { return pending.append(node); }
 
+    // True if the handler wants us to compute edge names; doing so can be
+    // expensive in time and memory. True by default.
+    bool wantNames;
+
     // Traverse the graph in breadth-first order, starting at the given
     // start nodes, applying |handler::operator()| for each edge traversed
     // as described above.
     //
     // This should be called only once per instance of this class.
     //
     // Return false on OOM or error return from |handler::operator()|.
     bool traverse()
@@ -108,17 +112,17 @@ struct BreadthFirst {
         traversalBegun = true;
 
         // While there are pending nodes, visit them, until we've found a path to the target.
         while (!pending.empty()) {
             Node origin = pending.front();
             pending.popFront();
 
             // Get a range containing all origin's outgoing edges.
-            js::ScopedJSDeletePtr<EdgeRange> range(origin.edges(cx));
+            js::ScopedJSDeletePtr<EdgeRange> range(origin.edges(cx, wantNames));
             if (!range)
                 return false;
 
             // Traverse each edge.
             for (; !range->empty(); range->popFront()) {
                 MOZ_ASSERT(!stopRequested);
 
                 const Edge &edge = range->front();
--- a/js/src/asmjs/AsmJSLink.cpp
+++ b/js/src/asmjs/AsmJSLink.cpp
@@ -118,19 +118,16 @@ ValidateGlobalVariable(JSContext *cx, co
         break;
       }
       case AsmJSModule::Global::InitImport: {
         RootedPropertyName field(cx, global.varImportField());
         RootedValue v(cx);
         if (!GetDataProperty(cx, importVal, field, &v))
             return false;
 
-        if (!v.isPrimitive())
-            return LinkFail(cx, "Imported values must be primitives");
-
         switch (global.varInitCoercion()) {
           case AsmJS_ToInt32:
             if (!ToInt32(cx, v, (int32_t *)datum))
                 return false;
             break;
           case AsmJS_ToNumber:
             if (!ToNumber(cx, v, (double *)datum))
                 return false;
@@ -179,17 +176,16 @@ ValidateArrayView(JSContext *cx, AsmJSMo
 }
 
 static bool
 ValidateMathBuiltinFunction(JSContext *cx, AsmJSModule::Global &global, HandleValue globalVal)
 {
     RootedValue v(cx);
     if (!GetDataProperty(cx, globalVal, cx->names().Math, &v))
         return false;
-
     RootedPropertyName field(cx, global.mathName());
     if (!GetDataProperty(cx, v, field, &v))
         return false;
 
     Native native = nullptr;
     switch (global.mathBuiltinFunction()) {
       case AsmJSMathBuiltin_sin: native = math_sin; break;
       case AsmJSMathBuiltin_cos: native = math_cos; break;
@@ -225,17 +221,16 @@ ValidateConstant(JSContext *cx, AsmJSMod
 
     if (global.constantKind() == AsmJSModule::Global::MathConstant) {
         if (!GetDataProperty(cx, v, cx->names().Math, &v))
             return false;
     }
 
     if (!GetDataProperty(cx, v, field, &v))
         return false;
-
     if (!v.isNumber())
         return LinkFail(cx, "math / global constant value needs to be a number");
 
     // NaN != NaN
     if (IsNaN(global.constantValue())) {
         if (!IsNaN(v.toNumber()))
             return LinkFail(cx, "global constant value needs to be NaN");
     } else {
--- a/js/src/jit-test/tests/asm.js/testGlobals.js
+++ b/js/src/jit-test/tests/asm.js/testGlobals.js
@@ -1,10 +1,9 @@
 load(libdir + "asm.js");
-load(libdir + "asserts.js");
 
 assertAsmTypeFail(USE_ASM + "var i; function f(){} return f");
 assertAsmTypeFail(USE_ASM + "const i; function f(){} return f");
 assertEq(asmLink(asmCompile(USE_ASM + "var i=0; function f(){} return f"))(), undefined);
 assertEq(asmLink(asmCompile(USE_ASM + "const i=0; function f(){} return f"))(), undefined);
 assertEq(asmLink(asmCompile(USE_ASM + "var i=42; function f(){ return i|0 } return f"))(), 42);
 assertEq(asmLink(asmCompile(USE_ASM + "const i=42; function f(){ return i|0 } return f"))(), 42);
 assertEq(asmLink(asmCompile(USE_ASM + "var i=4.2; function f(){ return +i } return f"))(), 4.2);
@@ -113,24 +112,16 @@ assertEq(asmLink(asmCompile('global', 'i
 assertEq(asmLink(asmCompile('global', 'imp', USE_ASM + "const i=imp.i|0; function f() { return i|0 } return f")(null, {i:42})), 42);
 assertEq(asmLink(asmCompile('global', 'imp', USE_ASM + "var i=imp.i|0; function f() { return i|0 } return f")(null, {i:1.4})), 1);
 assertEq(asmLink(asmCompile('global', 'imp', USE_ASM + "const i=imp.i|0; function f() { return i|0 } return f")(null, {i:1.4})), 1);
 assertEq(asmLink(asmCompile('global', 'imp', USE_ASM + "var i=+imp.i; function f() { return +i } return f")(null, {i:42})), 42);
 assertEq(asmLink(asmCompile('global', 'imp', USE_ASM + "const i=+imp.i; function f() { return +i } return f")(null, {i:42})), 42);
 assertEq(asmLink(asmCompile('global', 'imp', USE_ASM + "var i=+imp.i; function f() { return +i } return f")(this, {i:1.4})), 1.4);
 assertEq(asmLink(asmCompile('global', 'imp', USE_ASM + "const i=+imp.i; function f() { return +i } return f")(this, {i:1.4})), 1.4);
 assertEq(asmLink(asmCompile(USE_ASM + "var g=0; function f() { var i=42; while (1) { break; } g = i; return g|0 } return f"))(), 42);
-assertAsmLinkFail(asmCompile('glob','foreign', USE_ASM + 'var i = +foreign.x; function f() {} return f'), null, {x:{valueOf:function() { return 42 }}});
-assertAsmLinkFail(asmCompile('glob','foreign', USE_ASM + 'var i = foreign.x|0; function f() {} return f'), null, {x:{valueOf:function() { return 42 }}});
-assertEq(asmLink(asmCompile('glob','foreign', USE_ASM + 'var i = foreign.x|0; function f() { return i|0} return f'), null, {x:"blah"})(), 0);
-assertEq(asmLink(asmCompile('glob','foreign', USE_ASM + 'var i = +foreign.x; function f() { return +i} return f'), null, {x:"blah"})(), NaN);
-assertEq(asmLink(asmCompile('glob','foreign', USE_ASM + 'var tof = glob.Math.fround; var i = tof(foreign.x); function f() { return +i} return f'), this, {x:"blah"})(), NaN);
-assertThrowsInstanceOf(() => asmCompile('glob','foreign',USE_ASM + 'var i = foreign.x|0; function f() { return i|0} return f')(null, {x:Symbol("blah")}), TypeError);
-assertThrowsInstanceOf(() => asmCompile('glob','foreign',USE_ASM + 'var i = +foreign.x; function f() { return +i} return f')(null, {x:Symbol("blah")}), TypeError);
-assertThrowsInstanceOf(() => asmCompile('glob','foreign',USE_ASM + 'var tof = glob.Math.fround; var i = tof(foreign.x); function f() { return +i} return f')(this, {x:Symbol("blah")}), TypeError);
 
 var f1 = asmCompile('global', 'foreign', 'heap', USE_ASM + 'var i32 = new global.Int32Array(heap); function g() { return i32[4]|0 } return g');
 var global = this;
 var ab = new ArrayBuffer(4096);
 var p = new Proxy(global,
                   {has:function(name) { f1(global, null, ab); return true},
                    getOwnPropertyDescriptor:function(name) { return {configurable:true, value:Int32Array}}});
 new Int32Array(ab)[4] = 42;
--- a/js/src/jit/MIR.h
+++ b/js/src/jit/MIR.h
@@ -681,22 +681,37 @@ class MDefinition : public MNode
     }
     uint32_t virtualRegister() const {
         JS_ASSERT(isLowered());
         return virtualRegister_;
     }
 
   public:
     // Opcode testing and casts.
+    template<typename MIRType> bool is() const {
+        return op() == MIRType::classOpcode;
+    }
+    template<typename MIRType> MIRType *to() {
+        JS_ASSERT(is<MIRType>());
+        return static_cast<MIRType *>(this);
+    }
+    template<typename MIRType> const MIRType *to() const {
+        JS_ASSERT(is<MIRType>());
+        return static_cast<const MIRType *>(this);
+    }
 #   define OPCODE_CASTS(opcode)                                             \
     bool is##opcode() const {                                               \
-        return op() == Op_##opcode;                                         \
+        return is<M##opcode>();                                             \
     }                                                                       \
-    inline M##opcode *to##opcode();                                         \
-    inline const M##opcode *to##opcode() const;
+    M##opcode *to##opcode() {                                               \
+        return to<M##opcode>();                                             \
+    }                                                                       \
+    const M##opcode *to##opcode() const {                                   \
+        return to<M##opcode>();                                             \
+    }
     MIR_OPCODE_LIST(OPCODE_CASTS)
 #   undef OPCODE_CASTS
 
     inline MInstruction *toInstruction();
     inline const MInstruction *toInstruction() const;
     bool isInstruction() const {
         return !isPhi();
     }
@@ -827,18 +842,19 @@ class MInstruction
         return false;
     }
     virtual MInstruction *clone(TempAllocator &alloc, const MDefinitionVector &inputs) const {
         MOZ_CRASH();
     }
 };
 
 #define INSTRUCTION_HEADER(opcode)                                          \
+    static const Opcode classOpcode = MDefinition::Op_##opcode;             \
     Opcode op() const {                                                     \
-        return MDefinition::Op_##opcode;                                    \
+        return classOpcode;                                                 \
     }                                                                       \
     const char *opName() const {                                            \
         return #opcode;                                                     \
     }                                                                       \
     bool accept(MDefinitionVisitor *visitor) {                              \
         return visitor->visit##opcode(this);                                \
     }
 
@@ -6627,17 +6643,18 @@ class MTypedArrayElements
         return AliasSet::Load(AliasSet::ObjectFields);
     }
 
     ALLOW_CLONE(MTypedArrayElements)
 };
 
 // Checks whether a typed object is neutered.
 class MNeuterCheck
-  : public MUnaryInstruction
+  : public MUnaryInstruction,
+    public SingleObjectPolicy
 {
   private:
     explicit MNeuterCheck(MDefinition *object)
       : MUnaryInstruction(object)
     {
         JS_ASSERT(object->type() == MIRType_Object);
         setResultType(MIRType_Object);
         setResultTypeSet(object->resultTypeSet());
@@ -6658,16 +6675,20 @@ class MNeuterCheck
 
     bool congruentTo(const MDefinition *ins) const {
         return congruentIfOperandsEqual(ins);
     }
 
     AliasSet getAliasSet() const {
         return AliasSet::Load(AliasSet::ObjectFields);
     }
+
+    TypePolicy *typePolicy() {
+        return this;
+    }
 };
 
 // Load a binary data object's "elements", which is just its opaque
 // binary data space. Eventually this should probably be
 // unified with `MTypedArrayElements`.
 class MTypedObjectElements
   : public MUnaryInstruction,
     public SingleObjectPolicy
@@ -11242,16 +11263,18 @@ class MAsmJSCall MOZ_FINAL : public MVar
         return spIncrement_;
     }
 
     bool possiblyCalls() const {
         return true;
     }
 };
 
+#undef INSTRUCTION_HEADER
+
 void MUse::init(MDefinition *producer, MNode *consumer)
 {
     MOZ_ASSERT(!consumer_, "Initializing MUse that already has a consumer");
     MOZ_ASSERT(!producer_, "Initializing MUse that already has a producer");
     initUnchecked(producer, consumer);
 }
 
 void MUse::initUnchecked(MDefinition *producer, MNode *consumer)
@@ -11279,32 +11302,17 @@ void MUse::replaceProducer(MDefinition *
 
 void MUse::discardProducer()
 {
     MOZ_ASSERT(consumer_, "Clearing MUse without a consumer");
     producer_->removeUse(this);
     producer_ = nullptr;
 }
 
-#undef INSTRUCTION_HEADER
-
-// Implement opcode casts now that the compiler can see the inheritance.
-#define OPCODE_CASTS(opcode)                                                \
-    M##opcode *MDefinition::to##opcode()                                    \
-    {                                                                       \
-        JS_ASSERT(is##opcode());                                            \
-        return static_cast<M##opcode *>(this);                              \
-    }                                                                       \
-    const M##opcode *MDefinition::to##opcode() const                        \
-    {                                                                       \
-        JS_ASSERT(is##opcode());                                            \
-        return static_cast<const M##opcode *>(this);                        \
-    }
-MIR_OPCODE_LIST(OPCODE_CASTS)
-#undef OPCODE_CASTS
+// Implement cast functions now that the compiler can see the inheritance.
 
 MDefinition *MNode::toDefinition()
 {
     JS_ASSERT(isDefinition());
     return (MDefinition *)this;
 }
 
 MResumePoint *MNode::toResumePoint()
--- a/js/src/jsapi-tests/testIntTypesABI.cpp
+++ b/js/src/jsapi-tests/testIntTypesABI.cpp
@@ -14,16 +14,17 @@
 #include "jstypes.h"
 
 #include "js/Anchor.h"
 #include "js/CallArgs.h"
 #include "js/CallNonGenericMethod.h"
 #include "js/CharacterEncoding.h"
 #include "js/Class.h"
 #include "js/Date.h"
+#include "js/DebugAPI.h"
 #include "js/GCAPI.h"
 #include "js/HashTable.h"
 #include "js/HeapAPI.h"
 #include "js/Id.h"
 /* LegacyIntTypes.h is deliberately exempted from this requirement */
 #include "js/MemoryMetrics.h"
 #include "js/OldDebugAPI.h"
 #include "js/ProfilingStack.h"
--- a/js/src/moz.build
+++ b/js/src/moz.build
@@ -66,16 +66,17 @@ EXPORTS += [
 # LegacyIntTypes.h below is deliberately exempted from this requirement.
 EXPORTS.js += [
     '../public/Anchor.h',
     '../public/CallArgs.h',
     '../public/CallNonGenericMethod.h',
     '../public/CharacterEncoding.h',
     '../public/Class.h',
     '../public/Date.h',
+    '../public/DebugAPI.h',
     '../public/GCAPI.h',
     '../public/HashTable.h',
     '../public/HeapAPI.h',
     '../public/Id.h',
     '../public/LegacyIntTypes.h',
     '../public/MemoryMetrics.h',
     '../public/OldDebugAPI.h',
     '../public/Principals.h',
--- a/js/src/vm/Debugger.cpp
+++ b/js/src/vm/Debugger.cpp
@@ -13,16 +13,17 @@
 #include "jshashutil.h"
 #include "jsnum.h"
 #include "jsobj.h"
 #include "jswrapper.h"
 
 #include "frontend/BytecodeCompiler.h"
 #include "gc/Marking.h"
 #include "jit/BaselineJIT.h"
+#include "js/DebugAPI.h"
 #include "js/GCAPI.h"
 #include "js/Vector.h"
 #include "vm/ArgumentsObject.h"
 #include "vm/DebuggerMemory.h"
 #include "vm/SPSProfiler.h"
 #include "vm/WrapperObject.h"
 
 #include "jsgcinlines.h"
@@ -30,16 +31,17 @@
 #include "jsopcodeinlines.h"
 #include "jsscriptinlines.h"
 
 #include "vm/ObjectImpl-inl.h"
 #include "vm/Stack-inl.h"
 
 using namespace js;
 
+using JS::dbg::Builder;
 using js::frontend::IsIdentifier;
 using mozilla::ArrayLength;
 using mozilla::Maybe;
 
 
 /*** Forward declarations ************************************************************************/
 
 extern const Class DebuggerFrame_class;
@@ -6272,16 +6274,91 @@ static const JSFunctionSpec DebuggerEnv_
     JS_FN("find", DebuggerEnv_find, 1, 0),
     JS_FN("getVariable", DebuggerEnv_getVariable, 1, 0),
     JS_FN("setVariable", DebuggerEnv_setVariable, 2, 0),
     JS_FS_END
 };
 
 
 
+/*** JS::dbg::Builder ****************************************************************************/
+
+Builder::Builder(JSContext *cx, js::Debugger *debugger)
+  : debuggerObject(cx, debugger->toJSObject().get()),
+    debugger(debugger)
+{ }
+
+
+#if DEBUG
+void
+Builder::assertBuilt(JSObject *obj)
+{
+    // We can't use assertSameCompartment here, because that is always keyed to
+    // some JSContext's current compartment, whereas BuiltThings can be
+    // constructed and assigned to without respect to any particular context;
+    // the only constraint is that they should be in their debugger's compartment.
+    MOZ_ASSERT_IF(obj, debuggerObject->compartment() == obj->compartment());
+}
+#endif
+
+bool
+Builder::Object::definePropertyToTrusted(JSContext *cx, const char *name,
+                                         JS::MutableHandleValue trusted)
+{
+    // We should have checked for false Objects before calling this.
+    MOZ_ASSERT(value);
+
+    JSAtom *atom = Atomize(cx, name, strlen(name));
+    if (!atom)
+        return false;
+    RootedId id(cx, AtomToId(atom));
+
+    return JSObject::defineGeneric(cx, value, id, trusted);
+}
+
+bool
+Builder::Object::defineProperty(JSContext *cx, const char *name, JS::HandleValue propval_)
+{
+    AutoCompartment ac(cx, debuggerObject());
+
+    RootedValue propval(cx, propval_);
+    if (!debugger()->wrapDebuggeeValue(cx, &propval))
+        return false;
+
+    return definePropertyToTrusted(cx, name, &propval);
+}
+
+bool
+Builder::Object::defineProperty(JSContext *cx, const char *name, JS::HandleObject propval_)
+{
+    RootedValue propval(cx, ObjectOrNullValue(propval_));
+    return defineProperty(cx, name, propval);
+}
+
+bool
+Builder::Object::defineProperty(JSContext *cx, const char *name, Builder::Object &propval_)
+{
+    AutoCompartment ac(cx, debuggerObject());
+
+    RootedValue propval(cx, ObjectOrNullValue(propval_.value));
+    return definePropertyToTrusted(cx, name, &propval);
+}
+
+Builder::Object
+Builder::newObject(JSContext *cx)
+{
+    AutoCompartment ac(cx, debuggerObject);
+
+    RootedObject obj(cx, NewBuiltinClassInstance(cx, &JSObject::class_));
+
+    // If the allocation failed, this will return a false Object, as the spec promises.
+    return Object(cx, *this, obj);
+}
+
+
 /*** Glue ****************************************************************************************/
 
 extern JS_PUBLIC_API(bool)
 JS_DefineDebuggerObject(JSContext *cx, HandleObject obj)
 {
     RootedObject
         objProto(cx),
         debugCtor(cx),
--- a/js/src/vm/DebuggerMemory.cpp
+++ b/js/src/vm/DebuggerMemory.cpp
@@ -638,16 +638,17 @@ DebuggerMemory::takeCensus(JSContext *cx
         return false;
 
     {
         JS::AutoCheckCannotGC noGC;
 
         dbg::DefaultCensusTraversal traversal(cx, handler, noGC);
         if (!traversal.init())
             return false;
+        traversal.wantNames = false;
 
         // Walk the debuggee compartments, using it to set the starting points
         // (the debuggee globals) for the traversal, and to populate
         // census.debuggeeZones.
         for (GlobalObjectSet::Range r = debugger->debuggees.all(); !r.empty(); r.popFront()) {
             if (!census.debuggeeZones.put(r.front()->zone()) ||
                 !traversal.addStart(static_cast<JSObject *>(r.front())))
                 return false;
--- a/js/src/vm/UbiNode.cpp
+++ b/js/src/vm/UbiNode.cpp
@@ -23,21 +23,21 @@
 using JS::Value;
 using JS::ubi::Concrete;
 using JS::ubi::Edge;
 using JS::ubi::EdgeRange;
 using JS::ubi::Node;
 using JS::ubi::TracerConcrete;
 
 // All operations on null ubi::Nodes crash.
-const jschar *Concrete<void>::typeName() const      { MOZ_CRASH("null ubi::Node"); }
-size_t Concrete<void>::size() const                 { MOZ_CRASH("null ubi::Node"); }
-EdgeRange *Concrete<void>::edges(JSContext *) const { MOZ_CRASH("null ubi::Node"); }
-JS::Zone *Concrete<void>::zone() const              { MOZ_CRASH("null ubi::Node"); }
-JSCompartment *Concrete<void>::compartment() const  { MOZ_CRASH("null ubi::Node"); }
+const jschar *Concrete<void>::typeName() const            { MOZ_CRASH("null ubi::Node"); }
+size_t Concrete<void>::size() const                       { MOZ_CRASH("null ubi::Node"); }
+EdgeRange *Concrete<void>::edges(JSContext *, bool) const { MOZ_CRASH("null ubi::Node"); }
+JS::Zone *Concrete<void>::zone() const                    { MOZ_CRASH("null ubi::Node"); }
+JSCompartment *Concrete<void>::compartment() const        { MOZ_CRASH("null ubi::Node"); }
 
 Node::Node(JSGCTraceKind kind, void *ptr)
 {
     switch (kind) {
       case JSTRACE_OBJECT:      construct(static_cast<JSObject *>(ptr));              break;
       case JSTRACE_STRING:      construct(static_cast<JSString *>(ptr));              break;
       case JSTRACE_SYMBOL:      construct(static_cast<JS::Symbol *>(ptr));            break;
       case JSTRACE_SCRIPT:      construct(static_cast<JSScript *>(ptr));              break;
@@ -127,92 +127,101 @@ typedef mozilla::Vector<SimpleEdge, 8, j
 
 
 // A JSTracer subclass that adds a SimpleEdge to a Vector for each edge on
 // which it is invoked.
 class SimpleEdgeVectorTracer : public JSTracer {
     // The vector to which we add SimpleEdges.
     SimpleEdgeVector *vec;
 
+    // True if we should populate the edge's names.
+    bool wantNames;
+
     static void staticCallback(JSTracer *trc, void **thingp, JSGCTraceKind kind) {
         static_cast<SimpleEdgeVectorTracer *>(trc)->callback(thingp, kind);
     }
 
     void callback(void **thingp, JSGCTraceKind kind) {
         if (!okay)
             return;
 
-        // Ask the tracer to compute an edge name for us.
-        char buffer[1024];
-        const char *name = getTracingEdgeName(buffer, sizeof(buffer));
+        jschar *jsname = nullptr;
+        if (wantNames) {
+            // Ask the tracer to compute an edge name for us.
+            char buffer[1024];
+            const char *name = getTracingEdgeName(buffer, sizeof(buffer));
 
-        // Convert the name to jschars.
-        jschar *jsname = js_pod_malloc<jschar>(strlen(name) + 1);
-        if (!jsname) {
-            okay = false;
-            return;
+            // Convert the name to jschars.
+            jsname = js_pod_malloc<jschar>(strlen(name) + 1);
+            if (!jsname) {
+                okay = false;
+                return;
+            }
+
+            size_t i;
+            for (i = 0; name[i]; i++)
+                jsname[i] = name[i];
+            jsname[i] = '\0';
         }
 
-        size_t i;
-        for (i = 0; name[i]; i++)
-            jsname[i] = name[i];
-        jsname[i] = '\0';
-
         // The simplest code is correct! The temporary SimpleEdge takes
         // ownership of name; if the append succeeds, the vector element
         // then takes ownership; if the append fails, then the temporary
         // retains it, and its destructor will free it.
         if (!vec->append(mozilla::Move(SimpleEdge(jsname, Node(kind, *thingp))))) {
             okay = false;
             return;
         }
     }
 
   public:
     // True if no errors (OOM, say) have yet occurred.
     bool okay;
 
-    SimpleEdgeVectorTracer(JSContext *cx, SimpleEdgeVector *vec)
-        : JSTracer(JS_GetRuntime(cx), staticCallback), vec(vec), okay(true) {
-    }
+    SimpleEdgeVectorTracer(JSContext *cx, SimpleEdgeVector *vec, bool wantNames)
+      : JSTracer(JS_GetRuntime(cx), staticCallback),
+        vec(vec),
+        wantNames(wantNames),
+        okay(true)
+    { }
 };
 
 
 // An EdgeRange concrete class that simply holds a vector of SimpleEdges,
 // populated by the init method.
 class SimpleEdgeRange : public EdgeRange {
     SimpleEdgeVector edges;
     size_t i;
 
     void settle() {
         front_ = i < edges.length() ? &edges[i] : nullptr;
     }
 
   public:
     explicit SimpleEdgeRange(JSContext *cx) : edges(cx), i(0) { }
 
-    bool init(JSContext *cx, void *thing, JSGCTraceKind kind) {
-        SimpleEdgeVectorTracer tracer(cx, &edges);
+    bool init(JSContext *cx, void *thing, JSGCTraceKind kind, bool wantNames = true) {
+        SimpleEdgeVectorTracer tracer(cx, &edges, wantNames);
         JS_TraceChildren(&tracer, thing, kind);
         settle();
         return tracer.okay;
     }
 
     void popFront() MOZ_OVERRIDE { i++; settle(); }
 };
 
 
 template<typename Referent>
 EdgeRange *
-TracerConcrete<Referent>::edges(JSContext *cx) const {
+TracerConcrete<Referent>::edges(JSContext *cx, bool wantNames) const {
     js::ScopedJSDeletePtr<SimpleEdgeRange> r(js_new<SimpleEdgeRange>(cx));
     if (!r)
         return nullptr;
 
-    if (!r->init(cx, ptr, ::js::gc::MapTypeToTraceKind<Referent>::kind))
+    if (!r->init(cx, ptr, ::js::gc::MapTypeToTraceKind<Referent>::kind, wantNames))
         return nullptr;
 
     return r.forget();
 }
 
 template<> const jschar TracerConcrete<JSObject>::concreteTypeName[] =
     MOZ_UTF16("JSObject");
 template<> const jschar TracerConcrete<JSString>::concreteTypeName[] =
new file mode 100644
--- /dev/null
+++ b/layout/reftests/svg/filters/css-filters/drop-shadow-default-color-ref.html
@@ -0,0 +1,28 @@
+<!--
+     Any copyright is dedicated to the Public Domain.
+     http://creativecommons.org/publicdomain/zero/1.0/
+-->
+<!DOCTYPE html>
+<html>
+<head>
+  <title>CSS Filters: Drop Shadow Default Color</title>
+  <link rel="author" title="Max Vujovic" href="mailto:mvujovic@adobe.com">
+  <style type="text/css">
+    #target {
+      filter: url(#drop-shadow);
+      background-color: #00f;
+      width: 100px;
+      height: 100px;
+    }
+  </style>
+</head>
+<body>
+  <p>You should see a blue square with a green drop shadow.</p>
+  <div id="target"></div>
+  <svg width="0" height="0">
+    <filter id="drop-shadow" x="-50" y="-50" width="200" height="200" filterUnits="userSpaceOnUse">
+      <feDropShadow dx="10" dy="10" stdDeviation="3" flood-color="#0f0" color-interpolation-filters="sRGB"/>
+    </filter>
+  </svg>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/svg/filters/css-filters/drop-shadow-default-color.html
@@ -0,0 +1,31 @@
+<!--
+     Any copyright is dedicated to the Public Domain.
+     http://creativecommons.org/publicdomain/zero/1.0/
+-->
+<!DOCTYPE html>
+<html>
+<head>
+  <title>CSS Filters: Drop Shadow Default Color</title>
+  <link rel="author" title="Max Vujovic" href="mailto:mvujovic@adobe.com">
+  <link rel="help" href="http://www.w3.org/TR/filter-effects-1/#funcdef-drop-shadow">
+  <link rel="help" href="http://www.w3.org/TR/css3-background/#the-box-shadow">
+  <link rel="match" href="drop-shadow-default-color-ref.html">
+  <meta name="assert"
+        content="If the color is unspecified in a CSS drop-shadow filter
+                 function, it should default to the value of the CSS color
+                 property.">
+  <style type="text/css">
+    #target {
+      filter: drop-shadow(10px 10px 3px);
+      color: #0f0;
+      background-color: #00f;
+      width: 100px;
+      height: 100px;
+    }
+  </style>
+</head>
+<body>
+  <p>You should see a blue square with a green drop shadow.</p>
+  <div id="target"></div>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/svg/filters/css-filters/drop-shadow-negative-offset-ref.html
@@ -0,0 +1,31 @@
+<!--
+     Any copyright is dedicated to the Public Domain.
+     http://creativecommons.org/publicdomain/zero/1.0/
+-->
+<!DOCTYPE html>
+<html>
+<head>
+<title>CSS Filters: Negative Drop Shadow Offset</title>
+  <link rel="author" title="Max Vujovic" href="mailto:mvujovic@adobe.com">
+  <style type="text/css">
+    #target {
+      filter: url(#drop-shadow);
+      background-color: #00f;
+      position: relative;
+      top: 20px;
+      left: 20px;
+      width: 100px;
+      height: 100px;
+    }
+  </style>
+</head>
+<body>
+  <p>You should see a blue square with a green drop shadow in its top left corner.</p>
+  <div id="target"></div>
+  <svg width="0" height="0">
+    <filter id="drop-shadow" x="-50" y="-50" width="200" height="200" filterUnits="userSpaceOnUse">
+      <feDropShadow dx="-10" dy="-10" stdDeviation="3" flood-color="#0f0" color-interpolation-filters="sRGB"/>
+    </filter>
+  </svg>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/svg/filters/css-filters/drop-shadow-negative-offset.html
@@ -0,0 +1,32 @@
+<!--
+     Any copyright is dedicated to the Public Domain.
+     http://creativecommons.org/publicdomain/zero/1.0/
+-->
+<!DOCTYPE html>
+<html>
+<head>
+  <title>CSS Filters: Negative Drop Shadow Offset</title>
+  <link rel="author" title="Max Vujovic" href="mailto:mvujovic@adobe.com">
+  <link rel="help" href="http://www.w3.org/TR/filter-effects-1/#funcdef-drop-shadow">
+  <link rel="match" href="drop-shadow-negative-offset-ref.html">
+  <meta name="assert"
+        content="Given negative shadow offsets, the CSS drop-shadow filter
+                 function should add a drop shadow extending from the top left
+                 corner of an HTML element.">
+  <style type="text/css">
+    #target {
+      filter: drop-shadow(-10px -10px 3px #0f0);
+      background-color: #00f;
+      position: relative;
+      top: 20px;
+      left: 20px;
+      width: 100px;
+      height: 100px;
+    }
+  </style>
+</head>
+<body>
+  <p>You should see a blue square with a green drop shadow in its top left corner.</p>
+  <div id="target"></div>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/svg/filters/css-filters/drop-shadow-ref.html
@@ -0,0 +1,28 @@
+<!--
+     Any copyright is dedicated to the Public Domain.
+     http://creativecommons.org/publicdomain/zero/1.0/
+-->
+<!DOCTYPE html>
+<html>
+<head>
+  <title>CSS Filters: Drop Shadow on HTML Element</title>
+  <link rel="author" title="Max Vujovic" href="mailto:mvujovic@adobe.com">
+  <style type="text/css">
+    #target {
+      filter: url(#drop-shadow);
+      background-color: #00f;
+      width: 100px;
+      height: 100px;
+    }
+  </style>
+</head>
+<body>
+  <p>You should see a blue square with a green drop shadow.</p>
+  <div id="target"></div>
+  <svg width="0" height="0">
+    <filter id="drop-shadow" x="-50" y="-50" width="200" height="200" filterUnits="userSpaceOnUse">
+      <feDropShadow dx="10" dy="10" stdDeviation="3" flood-color="#0f0" color-interpolation-filters="sRGB"/>
+    </filter>
+  </svg>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/svg/filters/css-filters/drop-shadow.html
@@ -0,0 +1,28 @@
+<!--
+     Any copyright is dedicated to the Public Domain.
+     http://creativecommons.org/publicdomain/zero/1.0/
+-->
+<!DOCTYPE html>
+<html>
+<head>
+  <title>CSS Filters: Drop Shadow on HTML Element</title>
+  <link rel="author" title="Max Vujovic" href="mailto:mvujovic@adobe.com">
+  <link rel="help" href="http://www.w3.org/TR/filter-effects-1/#funcdef-drop-shadow">
+  <link rel="match" href="drop-shadow-ref.html">
+  <meta name="assert"
+        content="The CSS drop-shadow filter function should add a drop shadow to
+                 an HTML element.">
+  <style type="text/css">
+    #target {
+      filter: drop-shadow(10px 10px 3px #0f0);
+      background-color: #00f;
+      width: 100px;
+      height: 100px;
+    }
+  </style>
+</head>
+<body>
+  <p>You should see a blue square with a green drop shadow.</p>
+  <div id="target"></div>
+</body>
+</html>
--- a/layout/reftests/svg/filters/css-filters/reftest.list
+++ b/layout/reftests/svg/filters/css-filters/reftest.list
@@ -2,8 +2,11 @@
 # e.g. filter: blur(3px)
 
 default-preferences pref(layout.css.filters.enabled,true)
 
 == blur.html blur-ref.html
 == blur.svg blur-ref.svg
 == blur-zero-radius.html blur-zero-radius-ref.html
 == blur-zoomed-page.html blur-zoomed-page-ref.html
+== drop-shadow.html drop-shadow-ref.html
+== drop-shadow-default-color.html drop-shadow-default-color-ref.html
+== drop-shadow-negative-offset.html drop-shadow-negative-offset-ref.html
--- a/layout/reftests/svg/smil/transform/reftest.list
+++ b/layout/reftests/svg/smil/transform/reftest.list
@@ -1,14 +1,14 @@
 # Tests related to SVG Animation (using SMIL), focusing on the animateTransform
 # element.
 
 fuzzy(110,1802) == additive-1.svg additive-1-ref.svg # bug 981344
 == animate-width-1.svg lime.svg
-fuzzy-if(cocoaWidget,1,32) fuzzy-if(winWidget,1,1) == paced-1.svg paced-1-ref.svg # bug 981640
+fuzzy-if(cocoaWidget,1,32) fuzzy-if(winWidget,15,4) == paced-1.svg paced-1-ref.svg # bug 981640
 == rotate-angle-1.svg rotate-angle-ref.svg
 == rotate-angle-2.svg rotate-angle-ref.svg
 == rotate-angle-3.svg rotate-angle-ref.svg
 == rotate-angle-4.svg rotate-angle-ref.svg
 == rotate-angle-5.svg rotate-angle-ref.svg
 fuzzy(12,27) == scale-1.svg scale-1-ref.svg  # bug 981004
 == set-transform-1.svg lime.svg
 fuzzy-if(winWidget,1,3) == skew-1.svg skew-1-ref.svg # bug 983671
--- a/layout/svg/nsCSSFilterInstance.cpp
+++ b/layout/svg/nsCSSFilterInstance.cpp
@@ -4,26 +4,29 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 // Main header first:
 #include "nsCSSFilterInstance.h"
 
 // Keep others in (case-insensitive) order:
 #include "gfx2DGlue.h"
 #include "gfxUtils.h"
+#include "nsIFrame.h"
 #include "nsStyleStruct.h"
 #include "nsTArray.h"
 
 using namespace mozilla;
 using namespace mozilla::gfx;
 
 nsCSSFilterInstance::nsCSSFilterInstance(const nsStyleFilter& aFilter,
+                                         nsIFrame *aTargetFrame,
                                          const nsIntRect& aTargetBBoxInFilterSpace,
                                          const gfxMatrix& aFrameSpaceInCSSPxToFilterSpaceTransform)
   : mFilter(aFilter)
+  , mTargetFrame(aTargetFrame)
   , mTargetBBoxInFilterSpace(aTargetBBoxInFilterSpace)
   , mFrameSpaceInCSSPxToFilterSpaceTransform(aFrameSpaceInCSSPxToFilterSpaceTransform)
 {
 }
 
 nsresult
 nsCSSFilterInstance::BuildPrimitives(nsTArray<FilterPrimitiveDescription>& aPrimitiveDescrs)
 {
@@ -33,16 +36,19 @@ nsCSSFilterInstance::BuildPrimitives(nsT
   switch(mFilter.GetType()) {
     case NS_STYLE_FILTER_BLUR:
       descr = CreatePrimitiveDescription(PrimitiveType::GaussianBlur, aPrimitiveDescrs);
       result = SetAttributesForBlur(descr);
       break;
     case NS_STYLE_FILTER_BRIGHTNESS:
     case NS_STYLE_FILTER_CONTRAST:
     case NS_STYLE_FILTER_DROP_SHADOW:
+      descr = CreatePrimitiveDescription(PrimitiveType::DropShadow, aPrimitiveDescrs);
+      result = SetAttributesForDropShadow(descr);
+      break;
     case NS_STYLE_FILTER_GRAYSCALE:
     case NS_STYLE_FILTER_HUE_ROTATE:
     case NS_STYLE_FILTER_INVERT:
     case NS_STYLE_FILTER_OPACITY:
     case NS_STYLE_FILTER_SATURATE:
     case NS_STYLE_FILTER_SEPIA:
       return NS_ERROR_NOT_IMPLEMENTED;
     default:
@@ -73,48 +79,105 @@ nsCSSFilterInstance::CreatePrimitiveDesc
   descr.SetInputColorSpace(0, ColorSpace::SRGB);
   descr.SetOutputColorSpace(ColorSpace::SRGB);
   return descr;
 }
 
 nsresult
 nsCSSFilterInstance::SetAttributesForBlur(FilterPrimitiveDescription& aDescr)
 {
-  // Get the radius from the style.
-  nsStyleCoord radiusStyleCoord = mFilter.GetFilterParameter();
-  if (radiusStyleCoord.GetUnit() != eStyleUnit_Coord) {
+  const nsStyleCoord& radiusInFrameSpace = mFilter.GetFilterParameter();
+  if (radiusInFrameSpace.GetUnit() != eStyleUnit_Coord) {
     NS_NOTREACHED("unexpected unit");
     return NS_ERROR_FAILURE;
   }
 
-  // Get the radius in frame space.
-  nscoord radiusInFrameSpace = radiusStyleCoord.GetCoordValue();
+  Size radiusInFilterSpace = BlurRadiusToFilterSpace(radiusInFrameSpace.GetCoordValue());
+  aDescr.Attributes().Set(eGaussianBlurStdDeviation, radiusInFilterSpace);
+  return NS_OK;
+}
+
+nsresult
+nsCSSFilterInstance::SetAttributesForDropShadow(FilterPrimitiveDescription& aDescr)
+{
+  nsCSSShadowArray* shadows = mFilter.GetDropShadow();
+  if (!shadows || shadows->Length() != 1) {
+    NS_NOTREACHED("Exactly one drop shadow should have been parsed.");
+    return NS_ERROR_FAILURE;
+  }
+
+  nsCSSShadowItem* shadow = shadows->ShadowAt(0);
+
+  // Set drop shadow blur radius.
+  Size radiusInFilterSpace = BlurRadiusToFilterSpace(shadow->mRadius);
+  aDescr.Attributes().Set(eDropShadowStdDeviation, radiusInFilterSpace);
+
+  // Set offset.
+  IntPoint offsetInFilterSpace = OffsetToFilterSpace(shadow->mXOffset, shadow->mYOffset);
+  aDescr.Attributes().Set(eDropShadowOffset, offsetInFilterSpace);
+
+  // Set color. If unspecified, use the CSS color property.
+  nscolor shadowColor = shadow->mHasColor ?
+    shadow->mColor : mTargetFrame->StyleColor()->mColor;
+  aDescr.Attributes().Set(eDropShadowColor, ToAttributeColor(shadowColor));
+
+  return NS_OK;
+}
+
+Size
+nsCSSFilterInstance::BlurRadiusToFilterSpace(nscoord aRadiusInFrameSpace)
+{
   float radiusInFrameSpaceInCSSPx =
-    nsPresContext::AppUnitsToFloatCSSPixels(radiusInFrameSpace);
+    nsPresContext::AppUnitsToFloatCSSPixels(aRadiusInFrameSpace);
 
   // Convert the radius to filter space.
   gfxSize radiusInFilterSpace(radiusInFrameSpaceInCSSPx,
                               radiusInFrameSpaceInCSSPx);
   gfxSize frameSpaceInCSSPxToFilterSpaceScale =
     mFrameSpaceInCSSPxToFilterSpaceTransform.ScaleFactors(true);
   radiusInFilterSpace.Scale(frameSpaceInCSSPxToFilterSpaceScale.width,
                             frameSpaceInCSSPxToFilterSpaceScale.height);
 
   // Check the radius limits.
   if (radiusInFilterSpace.width < 0 || radiusInFilterSpace.height < 0) {
     NS_NOTREACHED("we shouldn't have parsed a negative radius in the style");
-    return NS_ERROR_FAILURE;
+    return Size();
   }
   gfxFloat maxStdDeviation = (gfxFloat)kMaxStdDeviation;
   radiusInFilterSpace.width = std::min(radiusInFilterSpace.width, maxStdDeviation);
   radiusInFilterSpace.height = std::min(radiusInFilterSpace.height, maxStdDeviation);
 
-  // Set the radius parameter.
-  aDescr.Attributes().Set(eGaussianBlurStdDeviation, ToSize(radiusInFilterSpace));
-  return NS_OK;
+  return ToSize(radiusInFilterSpace);
+}
+
+IntPoint
+nsCSSFilterInstance::OffsetToFilterSpace(nscoord aXOffsetInFrameSpace,
+                                         nscoord aYOffsetInFrameSpace)
+{
+  gfxPoint offsetInFilterSpace(nsPresContext::AppUnitsToFloatCSSPixels(aXOffsetInFrameSpace),
+                               nsPresContext::AppUnitsToFloatCSSPixels(aYOffsetInFrameSpace));
+
+  // Convert the radius to filter space.
+  gfxSize frameSpaceInCSSPxToFilterSpaceScale =
+    mFrameSpaceInCSSPxToFilterSpaceTransform.ScaleFactors(true);
+  offsetInFilterSpace.x *= frameSpaceInCSSPxToFilterSpaceScale.width;
+  offsetInFilterSpace.y *= frameSpaceInCSSPxToFilterSpaceScale.height;
+
+  return IntPoint(int32_t(offsetInFilterSpace.x), int32_t(offsetInFilterSpace.y));
+}
+
+Color
+nsCSSFilterInstance::ToAttributeColor(nscolor aColor)
+{
+  return Color(
+    NS_GET_R(aColor) / 255.0,
+    NS_GET_G(aColor) / 255.0,
+    NS_GET_B(aColor) / 255.0,
+    NS_GET_A(aColor) / 255.0
+  );
 }
 
 int32_t
 nsCSSFilterInstance::GetLastResultIndex(const nsTArray<FilterPrimitiveDescription>& aPrimitiveDescrs)
 {
   uint32_t numPrimitiveDescrs = aPrimitiveDescrs.Length();
   return !numPrimitiveDescrs ?
     FilterPrimitiveDescription::kPrimitiveIndexSourceGraphic :
--- a/layout/svg/nsCSSFilterInstance.h
+++ b/layout/svg/nsCSSFilterInstance.h
@@ -4,41 +4,49 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef __NS_CSSFILTERINSTANCE_H__
 #define __NS_CSSFILTERINSTANCE_H__
 
 #include "FilterSupport.h"
 #include "gfxMatrix.h"
 #include "gfxRect.h"
+#include "mozilla/gfx/Point.h"
+#include "mozilla/gfx/Types.h"
+#include "nsColor.h"
 
+class nsIFrame;
 struct nsStyleFilter;
 template<class T> class nsTArray;
 
 /**
  * This class helps nsFilterInstance build its filter graph. It turns a CSS
  * filter function (e.g. blur(3px)) from the style system into a
  * FilterPrimitiveDescription connected to the filter graph.
  */
 class nsCSSFilterInstance
 {
+  typedef mozilla::gfx::Color Color;
   typedef mozilla::gfx::FilterPrimitiveDescription FilterPrimitiveDescription;
+  typedef mozilla::gfx::IntPoint IntPoint;
   typedef mozilla::gfx::PrimitiveType PrimitiveType;
+  typedef mozilla::gfx::Size Size;
 
 public:
   /**
    * @param aFilter The CSS filter from the style system. This class stores
    *   aFilter by reference, so callers should avoid modifying or deleting
    *   aFilter during the lifetime of nsCSSFilterInstance.
    * @param mTargetBBoxInFilterSpace The frame of element being filtered, in
    *   filter space.
    * @param aFrameSpaceInCSSPxToFilterSpaceTransform The transformation from
    *   the filtered element's frame space in CSS pixels to filter space.
    */
   nsCSSFilterInstance(const nsStyleFilter& aFilter,
+                      nsIFrame *aTargetFrame,
                       const nsIntRect& mTargetBBoxInFilterSpace,
                       const gfxMatrix& aFrameSpaceInCSSPxToFilterSpaceTransform);
 
   /**
    * Creates at least one new FilterPrimitiveDescription based on the filter
    * from the style system. Appends the new FilterPrimitiveDescription(s) to the
    * aPrimitiveDescrs list.
    */
@@ -50,16 +58,17 @@ private:
    */
   FilterPrimitiveDescription CreatePrimitiveDescription(PrimitiveType aType,
                                                         const nsTArray<FilterPrimitiveDescription>& aPrimitiveDescrs);
 
   /**
    * Sets aDescr's attributes using the style info in mFilter.
    */
   nsresult SetAttributesForBlur(FilterPrimitiveDescription& aDescr);
+  nsresult SetAttributesForDropShadow(FilterPrimitiveDescription& aDescr);
 
   /**
    * Returns the index of the last result in the aPrimitiveDescrs, which we'll
    * use as the input to this CSS filter.
    */
   int32_t GetLastResultIndex(const nsTArray<FilterPrimitiveDescription>& aPrimitiveDescrs);
 
   /**
@@ -67,21 +76,44 @@ private:
    * based on this CSS filter's input and its attributes. For example, a CSS
    * blur filter will have bounds equal to its input bounds, inflated by the
    * blur extents.
    */
   void SetBounds(FilterPrimitiveDescription& aDescr,
                  const nsTArray<FilterPrimitiveDescription>& aPrimitiveDescrs);
 
   /**
+   * Converts an nscolor to a Color, suitable for use as a
+   * FilterPrimitiveDescription attribute.
+   */
+  Color ToAttributeColor(nscolor aColor);
+
+  /**
+   * Converts a blur radius in frame space to filter space.
+   */
+  Size BlurRadiusToFilterSpace(nscoord aRadiusInFrameSpace);
+
+  /**
+   * Converts a point defined by a pair of nscoord x, y coordinates from frame
+   * space to filter space.
+   */
+  IntPoint OffsetToFilterSpace(nscoord aXOffsetInFrameSpace,
+                               nscoord aYOffsetInFrameSpace);
+
+  /**
    * The CSS filter originally from the style system.
    */
   const nsStyleFilter& mFilter;
 
   /**
+   * The frame for the element that is currently being filtered.
+   */
+  nsIFrame*               mTargetFrame;
+
+  /**
    * The bounding box of the element being filtered, in filter space. Used for
    * input bounds if this CSS filter is the first in the filter chain.
    */
   nsIntRect mTargetBBoxInFilterSpace;
 
   /**
    * The transformation from the filtered element's frame space in CSS pixels to
    * filter space. Used to transform style values to filter space.
--- a/layout/svg/nsFilterInstance.cpp
+++ b/layout/svg/nsFilterInstance.cpp
@@ -255,17 +255,18 @@ nsFilterInstance::BuildPrimitivesForFilt
     if (!svgFilterInstance.IsInitialized()) {
       return NS_ERROR_FAILURE;
     }
 
     return svgFilterInstance.BuildPrimitives(mPrimitiveDescriptions, mInputImages);
   }
 
   // Build primitives for a CSS filter.
-  nsCSSFilterInstance cssFilterInstance(aFilter, mTargetBBoxInFilterSpace,
+  nsCSSFilterInstance cssFilterInstance(aFilter, mTargetFrame,
+                                        mTargetBBoxInFilterSpace,
                                         mFrameSpaceInCSSPxToFilterSpaceTransform);
   return cssFilterInstance.BuildPrimitives(mPrimitiveDescriptions);
 }
 
 void
 nsFilterInstance::ComputeNeededBoxes()
 {
   if (mPrimitiveDescriptions.IsEmpty())
--- a/media/mtransport/third_party/nICEr/src/stun/stun_codec.c
+++ b/media/mtransport/third_party/nICEr/src/stun/stun_codec.c
@@ -114,17 +114,17 @@ nr_stun_encode_htonl(UINT4 data, int buf
    *offset += sizeof(d);
 
    return 0;
 }
 
 int
 nr_stun_encode_htonll(UINT8 data, int buflen, UCHAR *buf, int *offset)
 {
-   UINT8 d = htonll(data);
+   UINT8 d = nr_htonll(data);
 
    if (*offset + sizeof(d) > buflen) {
       r_log(NR_LOG_STUN, LOG_WARNING, "Attempted buffer overrun: %d + %zd > %d", *offset, sizeof(d), buflen);
       return R_BAD_DATA;
    }
 
    memcpy(&buf[*offset], &d, sizeof(d));
    *offset += sizeof(d);
@@ -188,17 +188,17 @@ nr_stun_decode_htonll(UCHAR *buf, int bu
 
    if (*offset + sizeof(d) > buflen) {
       r_log(NR_LOG_STUN, LOG_WARNING, "Attempted buffer overrun: %d + %zd > %d", *offset, sizeof(d), buflen);
       return R_BAD_DATA;
    }
 
    memcpy(&d, &buf[*offset], sizeof(d));
    *offset += sizeof(d);
-   *data = htonll(d);
+   *data = nr_htonll(d);
 
    return 0;
 }
 
 int
 nr_stun_decode(int length, UCHAR *buf, int buflen, int *offset, UCHAR *data)
 {
    if (*offset + length > buflen) {
--- a/media/mtransport/third_party/nrappkit/src/util/byteorder.c
+++ b/media/mtransport/third_party/nrappkit/src/util/byteorder.c
@@ -48,29 +48,29 @@ static char *RCSSTRING __UNUSED__ ="$Id:
 #define IS_BIG_ENDIAN (htonl(0x1) == 0x1)
 
 #define BYTE(n,i)   (((UCHAR*)&(n))[(i)])
 #define SWAP(n,x,y) tmp=BYTE((n),(x)), \
                     BYTE((n),(x))=BYTE((n),(y)), \
                     BYTE((n),(y))=tmp
 
 UINT8
-htonll(UINT8 hostlonglong)
+nr_htonll(UINT8 hostlonglong)
 {
     UINT8 netlonglong = hostlonglong;
     UCHAR tmp;
 
     if (!IS_BIG_ENDIAN) {
         SWAP(netlonglong, 0, 7);
         SWAP(netlonglong, 1, 6);
         SWAP(netlonglong, 2, 5);
         SWAP(netlonglong, 3, 4);
     }
 
     return netlonglong;
 }
 
 UINT8
-ntohll(UINT8 netlonglong)
+nr_ntohll(UINT8 netlonglong)
 {
-    return htonll(netlonglong);
+    return nr_htonll(netlonglong);
 }
 
--- a/media/mtransport/third_party/nrappkit/src/util/byteorder.h
+++ b/media/mtransport/third_party/nrappkit/src/util/byteorder.h
@@ -34,14 +34,14 @@
 
    briank@networkresonance.com  Wed May 16 16:46:00 PDT 2007
  */
 
 
 #ifndef _byteorder_h
 #define _byteorder_h
 
-UINT8 htonll(UINT8 hostlonglong);
+UINT8 nr_htonll(UINT8 hostlonglong);
 
-UINT8 ntohll(UINT8 netlonglong);
+UINT8 nr_ntohll(UINT8 netlonglong);
 
 #endif
 
--- a/media/mtransport/transportlayerdtls.cpp
+++ b/media/mtransport/transportlayerdtls.cpp
@@ -587,17 +587,19 @@ bool TransportLayerDtls::Setup() {
 // builds, but can be disabled with prefs and they aren't on in our unit tests
 // since that uses NSS default configuration.
 // Only override prefs to comply with MUST statements in the security-arch.
 static const uint32_t EnabledCiphers[] = {
   TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
   TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA
 };
 
-// Disalbe all NSS suites modes without PFS or with old and rusty ciphersuites.
+// Don't remove suites; TODO(mt@mozilla.com) restore; bug 1052610
+#if 0
+// Disable all NSS suites modes without PFS or with old and rusty ciphersuites.
 // Anything outside this list is governed by the usual combination of policy
 // and user preferences.
 static const uint32_t DisabledCiphers[] = {
   TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA,
   TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA,
   TLS_ECDHE_ECDSA_WITH_RC4_128_SHA,
   TLS_ECDHE_RSA_WITH_RC4_128_SHA,
 
@@ -642,16 +644,17 @@ static const uint32_t DisabledCiphers[] 
   TLS_ECDHE_RSA_WITH_NULL_SHA,
   TLS_ECDH_ECDSA_WITH_NULL_SHA,
   TLS_ECDH_RSA_WITH_NULL_SHA,
 
   TLS_RSA_WITH_NULL_SHA,
   TLS_RSA_WITH_NULL_SHA256,
   TLS_RSA_WITH_NULL_MD5,
 };
+#endif // bug 1052610
 
 bool TransportLayerDtls::SetupCipherSuites(PRFileDesc* ssl_fd) const {
   SECStatus rv;
 
   // Set the SRTP ciphers
   if (!srtp_ciphers_.empty()) {
     // Note: std::vector is guaranteed to contiguous
     rv = SSL_SetSRTPCiphers(ssl_fd, &srtp_ciphers_[0], srtp_ciphers_.size());
--- a/modules/libpref/init/all.js
+++ b/modules/libpref/init/all.js
@@ -453,18 +453,18 @@ pref("apz.x_stationary_size_multiplier",
 pref("apz.y_stationary_size_multiplier", "3.5");
 pref("apz.zoom_animation_duration_ms", 250);
 
 #ifdef XP_MACOSX
 // Layerize scrollable subframes to allow async panning
 pref("apz.subframe.enabled", true);
 pref("apz.fling_repaint_interval", 16);
 pref("apz.pan_repaint_interval", 16);
-pref("apz.apz.x_skate_size_multiplier", "2.5");
-pref("apz.apz.y_skate_size_multiplier", "3.5");
+pref("apz.x_skate_size_multiplier", "2.5");
+pref("apz.y_skate_size_multiplier", "3.5");
 #else
 pref("apz.subframe.enabled", false);
 pref("apz.fling_repaint_interval", 75);
 pref("apz.pan_repaint_interval", 250);
 pref("apz.x_skate_size_multiplier", "1.5");
 pref("apz.y_skate_size_multiplier", "2.5");
 #endif
 
--- a/security/sandbox/linux/Sandbox.cpp
+++ b/security/sandbox/linux/Sandbox.cpp
@@ -42,17 +42,17 @@
 
 // See definition of SandboxDie, below.
 #include "sandbox/linux/seccomp-bpf/die.h"
 
 namespace mozilla {
 #if defined(ANDROID)
 #define LOG_ERROR(args...) __android_log_print(ANDROID_LOG_ERROR, "Sandbox", ## args)
 #else
-#define LOG_ERROR(fmt, args...) fprintf(stderr, "Sandbox: " fmt, ## args)
+#define LOG_ERROR(fmt, args...) fprintf(stderr, "Sandbox: " fmt "\n", ## args)
 #endif
 
 #ifdef MOZ_GMP_SANDBOX
 // For media plugins, we can start the sandbox before we dlopen the
 // module, so we have to pre-open the file and simulate the sandboxed
 // open().
 static int gMediaPluginFileDesc = -1;
 static const char *gMediaPluginFilePath;
--- a/testing/mozbase/mozrunner/mozrunner/base/browser.py
+++ b/testing/mozbase/mozrunner/mozrunner/base/browser.py
@@ -49,23 +49,16 @@ class GeckoRuntimeRunner(BaseRunner):
         if mozinfo.isMac and '-foreground' not in self.cmdargs:
             # runner should specify '-foreground' on Mac; see
             # https://bugzilla.mozilla.org/show_bug.cgi?id=916512
             self.cmdargs.append('-foreground')
 
         # Bug 775416 - Ensure that binary options are passed in first
         command[1:1] = self.cmdargs
 
-        # If running on OS X 10.5 or older, wrap |cmd| so that it will
-        # be executed as an i386 binary, in case it's a 32-bit/64-bit universal
-        # binary.
-        if mozinfo.isMac and hasattr(platform, 'mac_ver') and \
-                platform.mac_ver()[0][:4] < '10.6':
-            command = ["arch", "-arch", "i386"] + command
-
         if hasattr(self.app_ctx, 'wrap_command'):
             command = self.app_ctx.wrap_command(command)
         return command
 
     def start(self, *args, **kwargs):
         # ensure the profile exists
         if not self.profile.exists():
             self.profile.reset()
--- a/xpcom/glue/BlockingResourceBase.cpp
+++ b/xpcom/glue/BlockingResourceBase.cpp
@@ -6,16 +6,23 @@
 
 #include "mozilla/BlockingResourceBase.h"
 
 #ifdef DEBUG
 #include "prthread.h"
 
 #include "nsAutoPtr.h"
 
+#ifndef MOZ_CALLSTACK_DISABLED
+#include "CodeAddressService.h"
+#include "nsHashKeys.h"
+#include "nsStackWalk.h"
+#include "nsTHashtable.h"
+#endif
+
 #include "mozilla/CondVar.h"
 #include "mozilla/DeadlockDetector.h"
 #include "mozilla/ReentrantMonitor.h"
 #include "mozilla/Mutex.h"
 
 #ifdef MOZILLA_INTERNAL_API
 #include "GeckoProfiler.h"
 #endif //MOZILLA_INTERNAL_API
@@ -36,16 +43,41 @@ const char* const BlockingResourceBase::
 
 #ifdef DEBUG
 
 PRCallOnceType BlockingResourceBase::sCallOnce;
 unsigned BlockingResourceBase::sResourceAcqnChainFrontTPI = (unsigned)-1;
 BlockingResourceBase::DDT* BlockingResourceBase::sDeadlockDetector;
 
 
+void
+BlockingResourceBase::StackWalkCallback(void* aPc, void* aSp, void* aClosure)
+{
+#ifndef MOZ_CALLSTACK_DISABLED
+  AcquisitionState* state = (AcquisitionState*)aClosure;
+  state->AppendElement(aPc);
+#endif
+}
+
+void
+BlockingResourceBase::GetStackTrace(AcquisitionState& aState)
+{
+#ifndef MOZ_CALLSTACK_DISABLED
+  // Skip this function and the calling function.
+  const uint32_t kSkipFrames = 2;
+
+  aState.Clear();
+
+  // NB: Ignore the return value, there's nothing useful we can do if this
+  //     this fails.
+  NS_StackWalk(StackWalkCallback, kSkipFrames,
+               24, &aState, 0, nullptr);
+#endif
+}
+
 /**
  * PrintCycle
  * Append to |aOut| detailed information about the circular
  * dependency in |aCycle|.  Returns true if it *appears* that this
  * cycle may represent an imminent deadlock, but this is merely a
  * heuristic; the value returned may be a false positive or false
  * negative.
  *
@@ -80,44 +112,125 @@ PrintCycle(const BlockingResourceBase::D
 
   fputs("\n=== Cycle completed at\n", stderr);
   aOut += "Cycle completed at\n";
   (*it)->Print(aOut);
 
   return maybeImminent;
 }
 
+#ifndef MOZ_CALLSTACK_DISABLED
+class CodeAddressServiceWriter MOZ_FINAL
+{
+public:
+  explicit CodeAddressServiceWriter(nsACString& aOut) : mOut(aOut) {}
+
+  void Write(const char* aFmt, ...) const
+  {
+    va_list ap;
+    va_start(ap, aFmt);
+
+    const size_t kMaxLength = 4096;
+    char buffer[kMaxLength];
+
+    vsnprintf(buffer, kMaxLength, aFmt, ap);
+    mOut += buffer;
+    fprintf(stderr, "%s", buffer);
+
+    va_end(ap);
+  }
+
+private:
+  nsACString& mOut;
+};
+
+struct CodeAddressServiceLock MOZ_FINAL
+{
+  static void Unlock() { }
+  static void Lock() { }
+  static bool IsLocked() { return true; }
+};
+
+struct CodeAddressServiceStringAlloc MOZ_FINAL
+{
+  static char* copy(const char* aString) { return ::strdup(aString); }
+  static void free(char* aString) { ::free(aString); }
+};
+
+class CodeAddressServiceStringTable MOZ_FINAL
+{
+public:
+  CodeAddressServiceStringTable() : mSet(32) {}
+
+  const char* Intern(const char* aString)
+  {
+    nsCharPtrHashKey* e = mSet.PutEntry(aString);
+    return e->GetKey();
+  }
+
+  size_t SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) const
+  {
+    return mSet.SizeOfExcludingThis(aMallocSizeOf);
+  }
+
+private:
+  typedef nsTHashtable<nsCharPtrHashKey> StringSet;
+  StringSet mSet;
+};
+
+typedef CodeAddressService<CodeAddressServiceStringTable,
+                           CodeAddressServiceStringAlloc,
+                           CodeAddressServiceWriter,
+                           CodeAddressServiceLock> WalkTheStackCodeAddressService;
+#endif
 
 bool
 BlockingResourceBase::Print(nsACString& aOut) const
 {
   fprintf(stderr, "--- %s : %s",
           kResourceTypeName[mType], mName);
   aOut += BlockingResourceBase::kResourceTypeName[mType];
   aOut += " : ";
   aOut += mName;
 
-  if (mAcquired) {
+  bool acquired = IsAcquired();
+
+  if (acquired) {
     fputs(" (currently acquired)\n", stderr);
     aOut += " (currently acquired)\n";
   }
 
   fputs(" calling context\n", stderr);
+#ifdef MOZ_CALLSTACK_DISABLED
   fputs("  [stack trace unavailable]\n", stderr);
+#else
+  const AcquisitionState& state = acquired ? mAcquired : mFirstSeen;
 
-  return mAcquired;
+  WalkTheStackCodeAddressService addressService;
+  CodeAddressServiceWriter writer(aOut);
+  for (uint32_t i = 0; i < state.Length(); i++) {
+    addressService.WriteLocation(writer, state[i]);
+  }
+
+#endif
+
+  return acquired;
 }
 
 
 BlockingResourceBase::BlockingResourceBase(
     const char* aName,
     BlockingResourceBase::BlockingResourceType aType)
   : mName(aName)
   , mType(aType)
+#ifdef MOZ_CALLSTACK_DISABLED
   , mAcquired(false)
+#else
+  , mAcquired()
+#endif
 {
   NS_ABORT_IF_FALSE(mName, "Name must be nonnull");
   // PR_CallOnce guaranatees that InitStatics is called in a
   // thread-safe way
   if (PR_SUCCESS != PR_CallOnce(&sCallOnce, InitStatics)) {
     NS_RUNTIMEABORT("can't initialize blocking resource static members");
   }
 
@@ -177,16 +290,21 @@ BlockingResourceBase::CheckAcquire()
   BlockingResourceBase* chainFront = ResourceChainFront();
   nsAutoPtr<DDT::ResourceAcquisitionArray> cycle(
     sDeadlockDetector->CheckAcquisition(
       chainFront ? chainFront : 0, this));
   if (!cycle) {
     return;
   }
 
+#ifndef MOZ_CALLSTACK_DISABLED
+  // Update the current stack before printing.
+  GetStackTrace(mAcquired);
+#endif
+
   fputs("###!!! ERROR: Potential deadlock detected:\n", stderr);
   nsAutoCString out("Potential deadlock detected:\n");
   bool maybeImminent = PrintCycle(cycle, out);
 
   if (maybeImminent) {
     fputs("\n###!!! Deadlock may happen NOW!\n\n", stderr);
     out.AppendLiteral("\n###!!! Deadlock may happen NOW!\n\n");
   } else {
@@ -206,35 +324,44 @@ BlockingResourceBase::CheckAcquire()
 void
 BlockingResourceBase::Acquire()
 {
   if (mType == eCondVar) {
     NS_NOTYETIMPLEMENTED(
       "FIXME bug 456272: annots. to allow Acquire()ing condvars");
     return;
   }
-  NS_ASSERTION(!mAcquired,
+  NS_ASSERTION(!IsAcquired(),
                "reacquiring already acquired resource");
 
   ResourceChainAppend(ResourceChainFront());
+
+#ifdef MOZ_CALLSTACK_DISABLED
   mAcquired = true;
+#else
+  // Take a stack snapshot.
+  GetStackTrace(mAcquired);
+  if (mFirstSeen.IsEmpty()) {
+    mFirstSeen = mAcquired;
+  }
+#endif
 }
 
 
 void
 BlockingResourceBase::Release()
 {
   if (mType == eCondVar) {
     NS_NOTYETIMPLEMENTED(
       "FIXME bug 456272: annots. to allow Release()ing condvars");
     return;
   }
 
   BlockingResourceBase* chainFront = ResourceChainFront();
-  NS_ASSERTION(chainFront && mAcquired,
+  NS_ASSERTION(chainFront && IsAcquired(),
                "Release()ing something that hasn't been Acquire()ed");
 
   if (chainFront == this) {
     ResourceChainRemove();
   } else {
     // not an error, but makes code hard to reason about.
     NS_WARNING("Resource acquired at calling context\n");
     NS_WARNING("  [stack trace unavailable]\n");
@@ -250,17 +377,17 @@ BlockingResourceBase::Release()
     while (curr && (prev = curr->mChainPrev) && (prev != this)) {
       curr = prev;
     }
     if (prev == this) {
       curr->mChainPrev = prev->mChainPrev;
     }
   }
 
-  mAcquired = false;
+  ClearAcquisitionState();
 }
 
 
 //
 // Debug implementation of (OffTheBooks)Mutex
 void
 OffTheBooksMutex::Lock()
 {
@@ -335,20 +462,20 @@ ReentrantMonitor::Exit()
 
 nsresult
 ReentrantMonitor::Wait(PRIntervalTime aInterval)
 {
   AssertCurrentThreadIn();
 
   // save monitor state and reset it to empty
   int32_t savedEntryCount = mEntryCount;
-  bool savedAcquisitionState = GetAcquisitionState();
+  AcquisitionState savedAcquisitionState = GetAcquisitionState();
   BlockingResourceBase* savedChainPrev = mChainPrev;
   mEntryCount = 0;
-  SetAcquisitionState(false);
+  ClearAcquisitionState();
   mChainPrev = 0;
 
   nsresult rv;
 #ifdef MOZILLA_INTERNAL_API
   {
     GeckoProfilerSleepRAII profiler_sleep;
 #endif //MOZILLA_INTERNAL_API
 
@@ -372,19 +499,19 @@ ReentrantMonitor::Wait(PRIntervalTime aI
 //
 // Debug implementation of CondVar
 nsresult
 CondVar::Wait(PRIntervalTime aInterval)
 {
   AssertCurrentThreadOwnsMutex();
 
   // save mutex state and reset to empty
-  bool savedAcquisitionState = mLock->GetAcquisitionState();
+  AcquisitionState savedAcquisitionState = mLock->GetAcquisitionState();
   BlockingResourceBase* savedChainPrev = mLock->mChainPrev;
-  mLock->SetAcquisitionState(false);
+  mLock->ClearAcquisitionState();
   mLock->mChainPrev = 0;
 
   // give up mutex until we're back from Wait()
   nsresult rv =
     PR_WaitCondVar(mCvar, aInterval) == PR_SUCCESS ? NS_OK : NS_ERROR_FAILURE;
 
   // restore saved state
   mLock->SetAcquisitionState(savedAcquisitionState);
--- a/xpcom/glue/BlockingResourceBase.h
+++ b/xpcom/glue/BlockingResourceBase.h
@@ -11,19 +11,28 @@
 #include "prlog.h"
 
 #include "nscore.h"
 #include "nsDebug.h"
 #include "nsError.h"
 #include "nsISupportsImpl.h"
 
 #ifdef DEBUG
+
+// NB: Comment this out to enable callstack tracking.
+#define MOZ_CALLSTACK_DISABLED
+
 #include "prinit.h"
 
 #include "nsStringGlue.h"
+
+#ifndef MOZ_CALLSTACK_DISABLED
+#include "nsTArray.h"
+#endif
+
 #include "nsXPCOM.h"
 #endif
 
 //
 // This header is not meant to be included by client code.
 //
 
 namespace mozilla {
@@ -83,16 +92,22 @@ public:
     size_t n = aMallocSizeOf(this);
     return n;
   }
 
   // ``DDT'' = ``Deadlock Detector Type''
   typedef DeadlockDetector<BlockingResourceBase> DDT;
 
 protected:
+#ifdef MOZ_CALLSTACK_DISABLED
+  typedef bool AcquisitionState;
+#else
+  typedef nsAutoTArray<void*, 24> AcquisitionState;
+#endif
+
   /**
    * BlockingResourceBase
    * Initialize this blocking resource.  Also hooks the resource into
    * instrumentation code.
    *
    * Thread safe.
    *
    * @param aName A meaningful, unique name that can be used in
@@ -179,33 +194,63 @@ protected:
   } //NS_NEEDS_RESOURCE(this)
 
   /**
    * GetAcquisitionState
    * Return whether or not this resource was acquired.
    *
    * *NOT* thread safe.  Requires ownership of underlying resource.
    */
-  bool GetAcquisitionState()
+  AcquisitionState GetAcquisitionState()
   {
     return mAcquired;
   }
 
   /**
    * SetAcquisitionState
    * Set whether or not this resource was acquired.
    *
    * *NOT* thread safe.  Requires ownership of underlying resource.
    */
-  void SetAcquisitionState(bool aAcquisitionState)
+  void SetAcquisitionState(const AcquisitionState& aAcquisitionState)
   {
     mAcquired = aAcquisitionState;
   }
 
   /**
+   * ClearAcquisitionState
+   * Indicate this resource is not acquired.
+   *
+   * *NOT* thread safe.  Requires ownership of underlying resource.
+   */
+  void ClearAcquisitionState()
+  {
+#ifdef MOZ_CALLSTACK_DISABLED
+    mAcquired = false;
+#else
+    mAcquired.Clear();
+#endif
+  }
+
+  /**
+   * IsAcquired
+   * Indicates if this resource is acquired.
+   *
+   * *NOT* thread safe.  Requires ownership of underlying resource.
+   */
+  bool IsAcquired() const
+  {
+#ifdef MOZ_CALLSTACK_DISABLED
+    return mAcquired;
+#else
+    return !mAcquired.IsEmpty();
+#endif
+  }
+
+  /**
    * mChainPrev
    * A series of resource acquisitions creates a chain of orders.  This
    * chain is implemented as a linked list; |mChainPrev| points to the
    * resource most recently Acquire()'d before this one.
    **/
   BlockingResourceBase* mChainPrev;
 
 private:
@@ -222,17 +267,25 @@ private:
    * special semantics (e.g., reentrancy of monitors).
    **/
   BlockingResourceType mType;
 
   /**
    * mAcquired
    * Indicates if this resource is currently acquired.
    */
-  bool mAcquired;
+  AcquisitionState mAcquired;
+
+#ifndef MOZ_CALLSTACK_DISABLED
+  /**
+   * mFirstSeen
+   * Inidicates where this resource was first acquired.
+   */
+  AcquisitionState mFirstSeen;
+#endif
 
   /**
    * sCallOnce
    * Ensures static members are initialized only once, and in a
    * thread-safe way.
    */
   static PRCallOnceType sCallOnce;
 
@@ -261,16 +314,19 @@ private:
   /**
    * Shutdown
    * Free static members.
    *
    * *NOT* thread safe.
    */
   static void Shutdown();
 
+  static void StackWalkCallback(void* aPc, void* aSp, void* aClosure);
+  static void GetStackTrace(AcquisitionState& aState);
+
 #  ifdef MOZILLA_INTERNAL_API
   // so it can call BlockingResourceBase::Shutdown()
   friend void LogTerm();
 #  endif  // ifdef MOZILLA_INTERNAL_API
 
 #else  // non-DEBUG implementation
 
   BlockingResourceBase(const char* aName, BlockingResourceType aType) {}
--- a/xpcom/threads/ThreadStackHelper.cpp
+++ b/xpcom/threads/ThreadStackHelper.cpp
@@ -600,17 +600,20 @@ ThreadStackHelper::FillStackBuffer()
       continue;
     }
 #ifdef MOZ_THREADSTACKHELPER_NATIVE
     if (mContextToFill) {
       mContextToFill->mStackEnd = entry->stackAddress();
     }
 #endif
     const char* const label = entry->label();
-    if (mStackToFill->IsSameAsEntry(prevLabel, label)) {
+    if (mStackToFill->IsSameAsEntry(prevLabel, label) ||
+        !strcmp(label, "js::RunScript")) {
+      // Avoid duplicate labels to save space in the stack.
+      // Avoid js::RunScript labels because we save actual JS frames above.
       continue;
     }
     mStackToFill->infallibleAppend(label);
     prevLabel = label;
   }
 
   // end != entry if we exited early due to not enough reserved frames.
   // Expand the number of reserved frames for next time.