Merge from mozilla-central.
authorDavid Anderson <danderson@mozilla.com>
Tue, 15 May 2012 10:22:19 -0700
changeset 106188 c83c77b4ed05534bfae3ea4ab386365d93fb602c
parent 106187 38e41331c9ee3f4259aa5a1702332ac01a333315 (current diff)
parent 93983 00c7a320165bb5cbf9f5c195d042d83b615e56c4 (diff)
child 106189 06338317eaba9190894a1b60b9ea3d1a8137eb18
push id23447
push userdanderson@mozilla.com
push dateTue, 11 Sep 2012 17:34:27 +0000
treeherdermozilla-central@fdfaef738a00 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone15.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge from mozilla-central.
browser/app/macbuild/Contents/Info.plist.in
browser/base/content/browser.js
browser/base/content/browser.xul
browser/base/content/tabbrowser.xml
browser/base/content/test/browser_sanitizeDialog.js
browser/components/tabview/test/browser_tabview_storage_policy.js
browser/locales/en-US/chrome/browser/browser.dtd
config/autoconf.mk.in
config/system-headers
configure.in
content/base/public/nsINode.h
content/base/src/nsDOMFile.cpp
content/base/src/nsDOMTokenList.cpp
content/base/src/nsGenericElement.cpp
content/base/src/nsObjectLoadingContent.cpp
content/canvas/src/CanvasUtils.h
content/canvas/src/CustomQS_Canvas2D.h
content/canvas/src/WebGLContext.cpp
content/canvas/src/WebGLContext.h
content/canvas/src/WebGLContextGL.cpp
content/canvas/src/WebGLContextValidate.cpp
content/canvas/src/nsCanvasRenderingContext2D.cpp
content/canvas/src/nsCanvasRenderingContext2DAzure.cpp
content/html/content/src/nsHTMLCanvasElement.cpp
content/html/content/src/nsHTMLInputElement.cpp
content/media/VideoUtils.h
content/media/nsBuiltinDecoder.cpp
content/media/nsBuiltinDecoder.h
content/media/nsBuiltinDecoderReader.cpp
content/media/nsBuiltinDecoderStateMachine.cpp
content/media/ogg/nsOggCodecState.cpp
content/media/raw/nsRawReader.cpp
content/media/webm/nsWebMReader.cpp
dom/base/nsDOMClassInfo.cpp
dom/base/nsGlobalWindow.cpp
dom/base/nsWrapperCache.h
dom/indexedDB/CheckPermissionsHelper.h
dom/indexedDB/IDBKeyRange.h
dom/indexedDB/IDBObjectStore.h
dom/indexedDB/IndexedDatabaseManager.cpp
embedding/android/AndroidManifest.xml.in
gfx/thebes/gfxASurface.cpp
js/src/Makefile.in
js/src/config/autoconf.mk.in
js/src/config/system-headers
js/src/configure.in
js/src/frontend/BytecodeCompiler.cpp
js/src/frontend/BytecodeCompiler.h
js/src/frontend/BytecodeEmitter.cpp
js/src/frontend/BytecodeEmitter.h
js/src/frontend/FoldConstants.cpp
js/src/frontend/ParseNode.cpp
js/src/frontend/ParseNode.h
js/src/frontend/Parser.cpp
js/src/frontend/Parser.h
js/src/frontend/SemanticAnalysis.cpp
js/src/jsanalyze.cpp
js/src/jsanalyze.h
js/src/jsapi-tests/testBug604087.cpp
js/src/jsapi.cpp
js/src/jsapi.h
js/src/jscntxt.h
js/src/jscompartment.cpp
js/src/jsobj.cpp
js/src/jsopcode.tbl
js/src/jsprvtd.h
js/src/jsscope.cpp
js/src/jsscript.cpp
js/src/jsscript.h
js/src/jswrapper.cpp
js/src/vm/Debugger.cpp
js/src/vm/Stack.cpp
js/xpconnect/src/XPCComponents.cpp
js/xpconnect/src/XPCConvert.cpp
js/xpconnect/src/XPCJSRuntime.cpp
js/xpconnect/src/XPCWrappedNative.cpp
js/xpconnect/wrappers/WrapperFactory.cpp
js/xpconnect/wrappers/WrapperFactory.h
layout/base/FrameLayerBuilder.cpp
layout/base/FrameLayerBuilder.h
layout/base/crashtests/crashtests.list
layout/base/nsCaret.cpp
layout/generic/crashtests/crashtests.list
layout/generic/nsBlockFrame.h
layout/generic/nsGfxScrollFrame.cpp
layout/generic/nsGfxScrollFrame.h
layout/generic/nsIScrollableFrame.h
layout/reftests/scrolling/reftest.list
layout/style/nsCSSScanner.cpp
mobile/android/base/GeckoApp.java
mobile/android/base/GeckoAppShell.java
mobile/xul/app/mobile.js
netwerk/base/public/nsNetUtil.h
netwerk/base/src/nsSocketTransport2.cpp
netwerk/protocol/http/SpdySession.h
netwerk/protocol/http/nsAHttpConnection.h
netwerk/protocol/http/nsHttpConnection.cpp
netwerk/protocol/http/nsHttpConnection.h
netwerk/protocol/http/nsHttpConnectionMgr.h
netwerk/protocol/http/nsHttpHandler.cpp
netwerk/protocol/http/nsHttpPipeline.h
netwerk/protocol/http/nsHttpTransaction.cpp
services/sync/tests/unit/test_utils_json.js
services/sync/tests/unit/xpcshell.ini
toolkit/components/places/nsNavHistory.cpp
toolkit/content/license.html
toolkit/mozapps/extensions/XPIProvider.jsm
toolkit/xre/nsAppRunner.cpp
tools/trace-malloc/Makefile.in
xpcom/ds/CheckedInt.h
xpcom/io/nsLocalFileWin.cpp
xpcom/tests/TestCheckedInt.cpp
--- a/accessible/src/base/nsAccessiblePivot.cpp
+++ b/accessible/src/base/nsAccessiblePivot.cpp
@@ -37,16 +37,17 @@
  *
  * ***** END LICENSE BLOCK ***** */
 
 #include "nsAccessiblePivot.h"
 
 #include "Accessible-inl.h"
 #include "nsAccUtils.h"
 #include "nsHyperTextAccessible.h"
+#include "nsDocAccessible.h"
 #include "States.h"
 
 #include "nsArrayUtils.h"
 #include "nsComponentManagerUtils.h"
 #include "nsISupportsPrimitives.h"
 
 using namespace mozilla::a11y;
 
@@ -212,16 +213,20 @@ nsAccessiblePivot::SetTextRange(nsIAcces
 // Traversal functions
 
 NS_IMETHODIMP
 nsAccessiblePivot::MoveNext(nsIAccessibleTraversalRule* aRule, bool* aResult)
 {
   NS_ENSURE_ARG(aResult);
   NS_ENSURE_ARG(aRule);
 
+  if (mPosition && (mPosition->IsDefunct() ||
+                    !mPosition->Document()->IsInDocument(mPosition)))
+    return NS_ERROR_NOT_IN_TREE;
+
   nsresult rv = NS_OK;
   nsAccessible* accessible = SearchForward(mPosition, aRule, false, &rv);
   NS_ENSURE_SUCCESS(rv, rv);
 
   *aResult = accessible;
   if (*aResult)
     MovePivotInternal(accessible);
 
@@ -229,32 +234,40 @@ nsAccessiblePivot::MoveNext(nsIAccessibl
 }
 
 NS_IMETHODIMP
 nsAccessiblePivot::MovePrevious(nsIAccessibleTraversalRule* aRule, bool* aResult)
 {
   NS_ENSURE_ARG(aResult);
   NS_ENSURE_ARG(aRule);
 
+  if (mPosition && (mPosition->IsDefunct() ||
+                    !mPosition->Document()->IsInDocument(mPosition)))
+    return NS_ERROR_NOT_IN_TREE;
+
   nsresult rv = NS_OK;
   nsAccessible* accessible = SearchBackward(mPosition, aRule, false, &rv);
   NS_ENSURE_SUCCESS(rv, rv);
 
   *aResult = accessible;
   if (*aResult)
     MovePivotInternal(accessible);
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsAccessiblePivot::MoveFirst(nsIAccessibleTraversalRule* aRule, bool* aResult)
 {
   NS_ENSURE_ARG(aResult);
   NS_ENSURE_ARG(aRule);
+
+  if (mRoot && mRoot->IsDefunct())
+    return NS_ERROR_NOT_IN_TREE;
+
   nsresult rv = NS_OK;
   nsAccessible* accessible = SearchForward(mRoot, aRule, true, &rv);
   NS_ENSURE_SUCCESS(rv, rv);
 
   *aResult = accessible;
   if (*aResult)
     MovePivotInternal(accessible);
 
@@ -262,16 +275,19 @@ nsAccessiblePivot::MoveFirst(nsIAccessib
 }
 
 NS_IMETHODIMP
 nsAccessiblePivot::MoveLast(nsIAccessibleTraversalRule* aRule, bool* aResult)
 {
   NS_ENSURE_ARG(aResult);
   NS_ENSURE_ARG(aRule);
 
+  if (mRoot && mRoot->IsDefunct())
+    return NS_ERROR_NOT_IN_TREE;
+
   *aResult = false;
   nsresult rv = NS_OK;
   nsAccessible* lastAccessible = mRoot;
   nsAccessible* accessible = nsnull;
 
   // First got to the last accessible in pre-order
   while (lastAccessible->HasChildren())
     lastAccessible = lastAccessible->LastChild();
@@ -329,16 +345,19 @@ nsAccessiblePivot::RemoveObserver(nsIAcc
   return mObservers.RemoveElement(aObserver) ? NS_OK : NS_ERROR_FAILURE;
 }
 
 // Private utility methods
 
 bool
 nsAccessiblePivot::IsRootDescendant(nsAccessible* aAccessible)
 {
+  if (!mRoot || mRoot->IsDefunct())
+    return false;
+
   nsAccessible* accessible = aAccessible;
   do {
     if (accessible == mRoot)
       return true;
   } while ((accessible = accessible->Parent()));
 
   return false;
 }
--- a/accessible/src/base/nsAccessiblePivot.h
+++ b/accessible/src/base/nsAccessiblePivot.h
@@ -44,16 +44,20 @@
 
 #include "nsAutoPtr.h"
 #include "nsTObserverArray.h"
 #include "nsCycleCollectionParticipant.h"
 
 class nsAccessible;
 class nsIAccessibleTraversalRule;
 
+// raised when current pivot's position is needed but it is not in the tree.
+#define NS_ERROR_NOT_IN_TREE \
+NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_GENERAL, 0x26)
+
 /**
  * Class represents an accessible pivot.
  */
 class nsAccessiblePivot: public nsIAccessiblePivot
 {
 public:
   nsAccessiblePivot(nsAccessible* aRoot);
 
--- a/accessible/src/html/HTMLListAccessible.cpp
+++ b/accessible/src/html/HTMLListAccessible.cpp
@@ -6,16 +6,17 @@
 
 #include "HTMLListAccessible.h"
 
 #include "nsDocAccessible.h"
 #include "Role.h"
 #include "States.h"
 
 #include "nsBlockFrame.h"
+#include "nsBulletFrame.h"
 
 using namespace mozilla;
 using namespace mozilla::a11y;
 
 ////////////////////////////////////////////////////////////////////////////////
 // HTMLListAccessible
 ////////////////////////////////////////////////////////////////////////////////
 
@@ -80,25 +81,25 @@ HTMLLIAccessible::NativeState()
   return nsHyperTextAccessibleWrap::NativeState() | states::READONLY;
 }
 
 NS_IMETHODIMP
 HTMLLIAccessible::GetBounds(PRInt32* aX, PRInt32* aY,
                             PRInt32* aWidth, PRInt32* aHeight)
 {
   nsresult rv = nsAccessibleWrap::GetBounds(aX, aY, aWidth, aHeight);
-  if (NS_FAILED(rv) || !mBullet)
+  if (NS_FAILED(rv) || !mBullet || mBullet->IsInside())
     return rv;
 
   PRInt32 bulletX = 0, bulletY = 0, bulletWidth = 0, bulletHeight = 0;
   rv = mBullet->GetBounds(&bulletX, &bulletY, &bulletWidth, &bulletHeight);
   NS_ENSURE_SUCCESS(rv, rv);
 
+  *aWidth += *aX - bulletX;
   *aX = bulletX; // Move x coordinate of list item over to cover bullet as well
-  *aWidth += bulletWidth;
   return NS_OK;
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 // HTMLLIAccessible: public
 
 void
 HTMLLIAccessible::UpdateBullet(bool aHasBullet)
@@ -139,16 +140,23 @@ HTMLLIAccessible::CacheChildren()
 
 ////////////////////////////////////////////////////////////////////////////////
 // HTMLListBulletAccessible
 ////////////////////////////////////////////////////////////////////////////////
 
 ////////////////////////////////////////////////////////////////////////////////
 // HTMLListBulletAccessible: nsAccessNode
 
+nsIFrame*
+HTMLListBulletAccessible::GetFrame() const
+{
+  nsBlockFrame* blockFrame = do_QueryFrame(mContent->GetPrimaryFrame());
+  return blockFrame ? blockFrame->GetBullet() : nsnull;
+}
+
 bool
 HTMLListBulletAccessible::IsPrimaryForNode() const
 {
   return false;
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 // HTMLListBulletAccessible: nsAccessible
@@ -194,8 +202,18 @@ HTMLListBulletAccessible::AppendTextTo(n
   nsAutoString bulletText;
   nsBlockFrame* blockFrame = do_QueryFrame(mContent->GetPrimaryFrame());
   NS_ASSERTION(blockFrame, "No frame for list item!");
   if (blockFrame)
     blockFrame->GetBulletText(bulletText);
 
   aText.Append(Substring(bulletText, aStartOffset, aLength));
 }
+
+////////////////////////////////////////////////////////////////////////////////
+// HTMLListBulletAccessible: public
+
+bool
+HTMLListBulletAccessible::IsInside() const
+{
+  nsBlockFrame* blockFrame = do_QueryFrame(mContent->GetPrimaryFrame());
+  return blockFrame ? blockFrame->HasInsideBullet() : false;
+}
--- a/accessible/src/html/HTMLListAccessible.h
+++ b/accessible/src/html/HTMLListAccessible.h
@@ -75,24 +75,32 @@ private:
 class HTMLListBulletAccessible : public nsLeafAccessible
 {
 public:
   HTMLListBulletAccessible(nsIContent* aContent, nsDocAccessible* aDoc) :
     nsLeafAccessible(aContent, aDoc) { }
   virtual ~HTMLListBulletAccessible() { }
 
   // nsAccessNode
+  virtual nsIFrame* GetFrame() const;
   virtual bool IsPrimaryForNode() const;
 
   // nsAccessible
   virtual ENameValueFlag Name(nsString& aName);
   virtual a11y::role NativeRole();
   virtual PRUint64 NativeState();
   virtual void AppendTextTo(nsAString& aText, PRUint32 aStartOffset = 0,
                             PRUint32 aLength = PR_UINT32_MAX);
+
+  // HTMLListBulletAccessible
+
+  /**
+   * Return true if the bullet is inside of list item element boundaries.
+   */
+  bool IsInside() const;
 };
 
 } // namespace a11y
 } // namespace mozilla
 
 
 inline mozilla::a11y::HTMLLIAccessible*
 nsAccessible::AsHTMLListItem()
--- a/accessible/src/jsat/AccessFu.jsm
+++ b/accessible/src/jsat/AccessFu.jsm
@@ -43,24 +43,24 @@ var AccessFu = {
     this.prefsBranch.addObserver('accessfu', this, false);
 
     let accessPref = ACCESSFU_DISABLE;
     try {
       accessPref = this.prefsBranch.getIntPref('accessfu');
     } catch (x) {
     }
 
-    this.processPreferences(accessPref);
+    this._processPreferences(accessPref);
   },
 
   /**
    * Start AccessFu mode, this primarily means controlling the virtual cursor
    * with arrow keys.
    */
-  enable: function enable() {
+  _enable: function _enable() {
     if (this._enabled)
       return;
     this._enabled = true;
 
     dump('AccessFu enable');
     this.addPresenter(new VisualPresenter());
 
     // Implicitly add the Android presenter on Android.
@@ -74,17 +74,17 @@ var AccessFu = {
     this.chromeWin.addEventListener('resize', this, true);
     this.chromeWin.addEventListener('scroll', this, true);
     this.chromeWin.addEventListener('TabOpen', this, true);
   },
 
   /**
    * Disable AccessFu and return to default interaction mode.
    */
-  disable: function disable() {
+  _disable: function _disable() {
     if (!this._enabled)
       return;
     this._enabled = false;
 
     dump('AccessFu disable');
 
     this.presenters.forEach(function(p) { p.detach(); });
     this.presenters = [];
@@ -93,17 +93,17 @@ var AccessFu = {
 
     Services.obs.removeObserver(this, 'accessible-event');
     this.chromeWin.removeEventListener('DOMActivate', this, true);
     this.chromeWin.removeEventListener('resize', this, true);
     this.chromeWin.removeEventListener('scroll', this, true);
     this.chromeWin.removeEventListener('TabOpen', this, true);
   },
 
-  processPreferences: function processPreferences(aPref) {
+  _processPreferences: function _processPreferences(aPref) {
     if (Services.appinfo.OS == 'Android') {
       if (aPref == ACCESSFU_AUTO) {
         if (!this._observingSystemSettings) {
           Services.obs.addObserver(this, 'Accessibility:Settings', false);
           this._observingSystemSettings = true;
         }
         Cc['@mozilla.org/android/bridge;1'].
           getService(Ci.nsIAndroidBridge).handleGeckoMessage(
@@ -113,19 +113,19 @@ var AccessFu = {
 
       if (this._observingSystemSettings) {
         Services.obs.removeObserver(this, 'Accessibility:Settings');
         this._observingSystemSettings = false;
       }
     }
 
     if (aPref == ACCESSFU_ENABLE)
-      this.enable();
+      this._enable();
     else
-      this.disable();
+      this._disable();
   },
 
   addPresenter: function addPresenter(presenter) {
     this.presenters.push(presenter);
     presenter.attach(this.chromeWin);
   },
 
   handleEvent: function handleEvent(aEvent) {
@@ -166,37 +166,37 @@ var AccessFu = {
       }
     }
   },
 
   observe: function observe(aSubject, aTopic, aData) {
     switch (aTopic) {
       case 'Accessibility:Settings':
         if (JSON.parse(aData).enabled)
-          this.enable();
+          this._enable();
         else
-          this.disable();
+          this._disable();
         break;
       case 'nsPref:changed':
         if (aData == 'accessfu')
-          this.processPreferences(this.prefsBranch.getIntPref('accessfu'));
+          this._processPreferences(this.prefsBranch.getIntPref('accessfu'));
         break;
       case 'accessible-event':
         let event;
         try {
           event = aSubject.QueryInterface(Ci.nsIAccessibleEvent);
-          this.handleAccEvent(event);
+          this._handleAccEvent(event);
         } catch (ex) {
           dump(ex);
           return;
         }
     }
   },
 
-  handleAccEvent: function handleAccEvent(aEvent) {
+  _handleAccEvent: function _handleAccEvent(aEvent) {
     switch (aEvent.eventType) {
       case Ci.nsIAccessibleEvent.EVENT_VIRTUALCURSOR_CHANGED:
         {
           let pivot = aEvent.accessible.
             QueryInterface(Ci.nsIAccessibleCursorable).virtualCursor;
           let event = aEvent.
             QueryInterface(Ci.nsIAccessibleVirtualCursorChangeEvent);
 
@@ -246,33 +246,33 @@ var AccessFu = {
               // in a BUSY state (i.e. loading), and inform presenters.
               // We need to do this because a state change event will not be
               // fired when an object is created with the BUSY state.
               // If this is not a new tab, don't bother because we sent 'loading'
               // when the previous doc changed its state to BUSY.
               let state = {};
               docAcc.getState(state, {});
               if (state.value & Ci.nsIAccessibleStates.STATE_BUSY &&
-                  this.isNotChromeDoc(docAcc))
+                  this._isNotChromeDoc(docAcc))
                 this.presenters.forEach(
                   function(p) { p.tabStateChanged(docAcc, 'loading'); }
                 );
               delete this._pendingDocuments[aEvent.DOMNode];
             }
-            if (this.isBrowserDoc(docAcc))
+            if (this._isBrowserDoc(docAcc))
               // A new top-level content document has been attached
               this.presenters.forEach(
                 function(p) { p.tabStateChanged(docAcc, 'newdoc'); }
               );
           }
           break;
         }
       case Ci.nsIAccessibleEvent.EVENT_DOCUMENT_LOAD_COMPLETE:
         {
-          if (this.isNotChromeDoc(aEvent.accessible)) {
+          if (this._isNotChromeDoc(aEvent.accessible)) {
             this.presenters.forEach(
               function(p) {
                 p.tabStateChanged(aEvent.accessible, 'loaded');
               }
             );
           }
           break;
         }
@@ -291,17 +291,17 @@ var AccessFu = {
             function(p) {
               p.tabStateChanged(aEvent.accessible, 'reload');
             }
           );
           break;
         }
       case Ci.nsIAccessibleEvent.EVENT_FOCUS:
         {
-          if (this.isBrowserDoc(aEvent.accessible)) {
+          if (this._isBrowserDoc(aEvent.accessible)) {
             // The document recieved focus, call tabSelected to present current tab.
             this.presenters.forEach(
               function(p) { p.tabSelected(aEvent.accessible); });
           }
           break;
         }
       case Ci.nsIAccessibleEvent.EVENT_TEXT_INSERTED:
       case Ci.nsIAccessibleEvent.EVENT_TEXT_REMOVED:
@@ -337,17 +337,17 @@ var AccessFu = {
   },
 
   /**
    * Check if accessible is a top-level content document (i.e. a child of a XUL
    * browser node).
    * @param {nsIAccessible} aDocAcc the accessible to check.
    * @return {boolean} true if this is a top-level content document.
    */
-  isBrowserDoc: function isBrowserDoc(aDocAcc) {
+  _isBrowserDoc: function _isBrowserDoc(aDocAcc) {
     let parent = aDocAcc.parent;
     if (!parent)
       return false;
 
     let domNode = parent.DOMNode;
     if (!domNode)
       return false;
 
@@ -355,17 +355,17 @@ var AccessFu = {
     return (domNode.localName == 'browser' && domNode.namespaceURI == ns);
   },
 
   /**
    * Check if document is not a local "chrome" document, like about:home.
    * @param {nsIDOMDocument} aDocument the document to check.
    * @return {boolean} true if this is not a chrome document.
    */
-  isNotChromeDoc: function isNotChromeDoc(aDocument) {
+  _isNotChromeDoc: function _isNotChromeDoc(aDocument) {
     let location = aDocument.DOMNode.location;
     if (!location)
       return false;
 
     return location.protocol != "about:";
   },
 
   getNewContext: function getNewContext(aOldObject, aNewObject) {
--- a/accessible/src/jsat/Presenters.jsm
+++ b/accessible/src/jsat/Presenters.jsm
@@ -47,17 +47,19 @@ Presenter.prototype = {
    * @param {nsIAccessible} aObject the object that has been invoked.
    * @param {string} aActionName the name of the action.
    */
   actionInvoked: function actionInvoked(aObject, aActionName) {},
 
   /**
    * Text has changed, either by the user or by the system. TODO.
    */
-  textChanged: function textChanged(aIsInserted, aStartOffset, aLength, aText, aModifiedText) {},
+  textChanged: function textChanged(aIsInserted, aStartOffset,
+                                    aLength, aText,
+                                    aModifiedText) {},
 
   /**
    * Text selection has changed. TODO.
    */
   textSelectionChanged: function textSelectionChanged() {},
 
   /**
    * Selection has changed. TODO.
@@ -90,243 +92,253 @@ Presenter.prototype = {
 };
 
 /**
  * Visual presenter. Draws a box around the virtual cursor's position.
  */
 
 function VisualPresenter() {}
 
-VisualPresenter.prototype = new Presenter();
+VisualPresenter.prototype = {
+  __proto__: Presenter.prototype,
 
-/**
- * The padding in pixels between the object and the highlight border.
- */
-VisualPresenter.prototype.BORDER_PADDING = 2;
+  /**
+   * The padding in pixels between the object and the highlight border.
+   */
+  BORDER_PADDING: 2,
 
-VisualPresenter.prototype.attach = function(aWindow) {
-  this.chromeWin = aWindow;
+  attach: function VisualPresenter_attach(aWindow) {
+    this.chromeWin = aWindow;
 
-  // Add stylesheet
-  let stylesheetURL = 'chrome://global/content/accessibility/AccessFu.css';
-  this.stylesheet = aWindow.document.createProcessingInstruction(
-    'xml-stylesheet', 'href="' + stylesheetURL + '" type="text/css"');
-  aWindow.document.insertBefore(this.stylesheet, aWindow.document.firstChild);
+    // Add stylesheet
+    let stylesheetURL = 'chrome://global/content/accessibility/AccessFu.css';
+    this.stylesheet = aWindow.document.createProcessingInstruction(
+      'xml-stylesheet', 'href="' + stylesheetURL + '" type="text/css"');
+    aWindow.document.insertBefore(this.stylesheet, aWindow.document.firstChild);
 
-  // Add highlight box
-  this.highlightBox = this.chromeWin.document.
-    createElementNS('http://www.w3.org/1999/xhtml', 'div');
-  this.chromeWin.document.documentElement.appendChild(this.highlightBox);
-  this.highlightBox.id = 'virtual-cursor-box';
+    // Add highlight box
+    this.highlightBox = this.chromeWin.document.
+      createElementNS('http://www.w3.org/1999/xhtml', 'div');
+    this.chromeWin.document.documentElement.appendChild(this.highlightBox);
+    this.highlightBox.id = 'virtual-cursor-box';
 
-  // Add highlight inset for inner shadow
-  let inset = this.chromeWin.document.
-    createElementNS('http://www.w3.org/1999/xhtml', 'div');
-  inset.id = 'virtual-cursor-inset';
+    // Add highlight inset for inner shadow
+    let inset = this.chromeWin.document.
+      createElementNS('http://www.w3.org/1999/xhtml', 'div');
+    inset.id = 'virtual-cursor-inset';
 
-  this.highlightBox.appendChild(inset);
-};
+    this.highlightBox.appendChild(inset);
+  },
 
-VisualPresenter.prototype.detach = function() {
-  this.chromeWin.document.removeChild(this.stylesheet);
-  this.highlightBox.parentNode.removeChild(this.highlightBox);
-  this.highlightBox = this.stylesheet = null;
-};
+  detach: function VisualPresenter_detach() {
+    this.chromeWin.document.removeChild(this.stylesheet);
+    this.highlightBox.parentNode.removeChild(this.highlightBox);
+    this.highlightBox = this.stylesheet = null;
+  },
 
-VisualPresenter.prototype.viewportChanged = function() {
-  if (this._currentObject)
-    this.highlight(this._currentObject);
-};
+  viewportChanged: function VisualPresenter_viewportChanged() {
+    if (this._currentObject)
+      this._highlight(this._currentObject);
+  },
 
-VisualPresenter.prototype.pivotChanged = function(aObject, aNewContext) {
-  this._currentObject = aObject;
+  pivotChanged: function VisualPresenter_pivotChanged(aObject, aNewContext) {
+    this._currentObject = aObject;
 
-  if (!aObject) {
-    this.hide();
-    return;
-  }
+    if (!aObject) {
+      this._hide();
+      return;
+    }
 
-  try {
-    aObject.scrollTo(Ci.nsIAccessibleScrollType.SCROLL_TYPE_ANYWHERE);
-    this.highlight(aObject);
-  } catch (e) {
-    dump('Error getting bounds: ' + e);
-    return;
-  }
-};
+    try {
+      aObject.scrollTo(Ci.nsIAccessibleScrollType.SCROLL_TYPE_ANYWHERE);
+      this._highlight(aObject);
+    } catch (e) {
+      dump('Error getting bounds: ' + e);
+      return;
+    }
+  },
 
-VisualPresenter.prototype.tabSelected = function(aDocObj) {
-  let vcPos = aDocObj ?
-    aDocObj.QueryInterface(Ci.nsIAccessibleCursorable).virtualCursor.position :
-    null;
+  tabSelected: function VisualPresenter_tabSelected(aDocObj) {
+    let vcPos = aDocObj ? aDocObj.QueryInterface(Ci.nsIAccessibleCursorable).
+      virtualCursor.position : null;
 
-  this.pivotChanged(vcPos);
-};
+    this.pivotChanged(vcPos);
+  },
 
-VisualPresenter.prototype.tabStateChanged = function(aDocObj, aPageState) {
-  if (aPageState == "newdoc")
-    this.pivotChanged(null);
-};
+  tabStateChanged: function VisualPresenter_tabStateChanged(aDocObj,
+                                                            aPageState) {
+    if (aPageState == 'newdoc')
+      this.pivotChanged(null);
+  },
 
-// Internals
+  // Internals
 
-VisualPresenter.prototype.hide = function hide() {
-  this.highlightBox.style.display = 'none';
-};
+  _hide: function _hide() {
+    this.highlightBox.style.display = 'none';
+  },
 
-VisualPresenter.prototype.highlight = function(aObject) {
-  let vp = (Services.appinfo.OS == 'Android') ?
-    this.chromeWin.BrowserApp.selectedTab.getViewport() :
-    { zoom: 1.0, offsetY: 0 };
+  _highlight: function _highlight(aObject) {
+    let vp = (Services.appinfo.OS == 'Android') ?
+      this.chromeWin.BrowserApp.selectedTab.getViewport() :
+      { zoom: 1.0, offsetY: 0 };
 
-  let bounds = this.getBounds(aObject, vp.zoom);
+    let bounds = this._getBounds(aObject, vp.zoom);
 
-  // First hide it to avoid flickering when changing the style.
-  this.highlightBox.style.display = 'none';
-  this.highlightBox.style.top = bounds.top + 'px';
-  this.highlightBox.style.left = bounds.left + 'px';
-  this.highlightBox.style.width = bounds.width + 'px';
-  this.highlightBox.style.height = bounds.height + 'px';
-  this.highlightBox.style.display = 'block';
-};
+    // First hide it to avoid flickering when changing the style.
+    this.highlightBox.style.display = 'none';
+    this.highlightBox.style.top = bounds.top + 'px';
+    this.highlightBox.style.left = bounds.left + 'px';
+    this.highlightBox.style.width = bounds.width + 'px';
+    this.highlightBox.style.height = bounds.height + 'px';
+    this.highlightBox.style.display = 'block';
+  },
+
+  _getBounds: function _getBounds(aObject, aZoom, aStart, aEnd) {
+    let objX = {}, objY = {}, objW = {}, objH = {};
 
-VisualPresenter.prototype.getBounds = function(aObject, aZoom, aStart, aEnd) {
-  let objX = {}, objY = {}, objW = {}, objH = {};
+    if (aEnd >= 0 && aStart >= 0 && aEnd != aStart) {
+      // TODO: Get bounds for text ranges. Leaving this blank until we have
+      // proper text navigation in the virtual cursor.
+    }
+
+    aObject.getBounds(objX, objY, objW, objH);
 
-  if (aEnd >= 0 && aStart >= 0 && aEnd != aStart) {
-    // TODO: Get bounds for text ranges. Leaving this blank until we have
-    // proper text navigation in the virtual cursor.
+    // Can't specify relative coords in nsIAccessible.getBounds, so we do it.
+    let docX = {}, docY = {};
+    let docRoot = aObject.rootDocument.QueryInterface(Ci.nsIAccessible);
+    docRoot.getBounds(docX, docY, {}, {});
+
+    let rv = {
+      left: Math.round((objX.value - docX.value - this.BORDER_PADDING) * aZoom),
+      top: Math.round((objY.value - docY.value - this.BORDER_PADDING) * aZoom),
+      width: Math.round((objW.value + (this.BORDER_PADDING * 2)) * aZoom),
+      height: Math.round((objH.value + (this.BORDER_PADDING * 2)) * aZoom)
+    };
+
+    return rv;
   }
-
-  aObject.getBounds(objX, objY, objW, objH);
-
-  // Can't specify relative coords in nsIAccessible.getBounds, so we do it.
-  let docX = {}, docY = {};
-  let docRoot = aObject.rootDocument.QueryInterface(Ci.nsIAccessible);
-  docRoot.getBounds(docX, docY, {}, {});
-
-  let rv = {
-    left: Math.round((objX.value - docX.value - this.BORDER_PADDING) * aZoom),
-    top: Math.round((objY.value - docY.value - this.BORDER_PADDING) * aZoom),
-    width: Math.round((objW.value + (this.BORDER_PADDING * 2)) * aZoom),
-    height: Math.round((objH.value + (this.BORDER_PADDING * 2)) * aZoom)
-  };
-
-  return rv;
 };
 
 /**
  * Android presenter. Fires Android a11y events.
  */
 
-const ANDROID_TYPE_VIEW_CLICKED = 0x01;
-const ANDROID_TYPE_VIEW_LONG_CLICKED = 0x02;
-const ANDROID_TYPE_VIEW_SELECTED = 0x04;
-const ANDROID_TYPE_VIEW_FOCUSED = 0x08;
-const ANDROID_TYPE_VIEW_TEXT_CHANGED = 0x10;
-const ANDROID_TYPE_WINDOW_STATE_CHANGED = 0x20;
-
 function AndroidPresenter() {}
 
-AndroidPresenter.prototype = new Presenter();
-
-AndroidPresenter.prototype.pivotChanged = function(aObject, aNewContext) {
-  let output = [];
-  for (let i in aNewContext)
-    output.push.apply(output,
-                      UtteranceGenerator.genForObject(aNewContext[i]));
+AndroidPresenter.prototype = {
+  __proto__: Presenter.prototype,
 
-  output.push.apply(output,
-                    UtteranceGenerator.genForObject(aObject, true));
+  // Android AccessibilityEvent type constants.
+  ANDROID_VIEW_CLICKED: 0x01,
+  ANDROID_VIEW_LONG_CLICKED: 0x02,
+  ANDROID_VIEW_SELECTED: 0x04,
+  ANDROID_VIEW_FOCUSED: 0x08,
+  ANDROID_VIEW_TEXT_CHANGED: 0x10,
+  ANDROID_WINDOW_STATE_CHANGED: 0x20,
 
-  this.sendMessageToJava({
-    gecko: {
-      type: 'Accessibility:Event',
-      eventType: ANDROID_TYPE_VIEW_FOCUSED,
-      text: output
-    }
-  });
-};
+  pivotChanged: function AndroidPresenter_pivotChanged(aObject, aNewContext) {
+    let output = [];
+    for (let i in aNewContext)
+      output.push.apply(output,
+                        UtteranceGenerator.genForObject(aNewContext[i]));
+
+    output.push.apply(output,
+                      UtteranceGenerator.genForObject(aObject, true));
 
-AndroidPresenter.prototype.actionInvoked = function(aObject, aActionName) {
-  this.sendMessageToJava({
-    gecko: {
-      type: 'Accessibility:Event',
-      eventType: ANDROID_TYPE_VIEW_CLICKED,
-      text: UtteranceGenerator.genForAction(aObject, aActionName)
-    }
-  });
-};
+    this.sendMessageToJava({
+      gecko: {
+        type: 'Accessibility:Event',
+        eventType: this.ANDROID_VIEW_FOCUSED,
+        text: output
+      }
+    });
+  },
 
-AndroidPresenter.prototype.tabSelected = function(aDocObj) {
-  // Send a pivot change message with the full context utterance for this doc.
-  let vcDoc = aDocObj.QueryInterface(Ci.nsIAccessibleCursorable);
-  let context = [];
+  actionInvoked: function AndroidPresenter_actionInvoked(aObject, aActionName) {
+    this.sendMessageToJava({
+      gecko: {
+        type: 'Accessibility:Event',
+        eventType: this.ANDROID_VIEW_CLICKED,
+        text: UtteranceGenerator.genForAction(aObject, aActionName)
+      }
+    });
+  },
 
-  let parent = vcDoc.virtualCursor.position || aDocObj;
-  while ((parent = parent.parent)) {
-    context.push(parent);
-    if (parent == aDocObj)
-      break;
-  }
+  tabSelected: function AndroidPresenter_tabSelected(aDocObj) {
+    // Send a pivot change message with the full context utterance for this doc.
+    let vcDoc = aDocObj.QueryInterface(Ci.nsIAccessibleCursorable);
+    let context = [];
 
-  context.reverse();
+    let parent = vcDoc.virtualCursor.position || aDocObj;
+    while ((parent = parent.parent)) {
+      context.push(parent);
+      if (parent == aDocObj)
+        break;
+    }
 
-  this.pivotChanged(vcDoc.virtualCursor.position || aDocObj, context);
-};
+    context.reverse();
+
+    this.pivotChanged(vcDoc.virtualCursor.position || aDocObj, context);
+  },
 
-AndroidPresenter.prototype.tabStateChanged = function(aDocObj, aPageState) {
-  let stateUtterance = UtteranceGenerator.
-    genForTabStateChange(aDocObj, aPageState);
-
-  if (!stateUtterance.length)
-    return;
+  tabStateChanged: function AndroidPresenter_tabStateChanged(aDocObj,
+                                                             aPageState) {
+    let stateUtterance = UtteranceGenerator.
+      genForTabStateChange(aDocObj, aPageState);
 
-  this.sendMessageToJava({
-    gecko: {
-      type: 'Accessibility:Event',
-      eventType: ANDROID_TYPE_VIEW_TEXT_CHANGED,
-      text: stateUtterance,
-      addedCount: stateUtterance.join(' ').length,
-      removedCount: 0,
-      fromIndex: 0
-    }
-  });
-};
+    if (!stateUtterance.length)
+      return;
+
+    this.sendMessageToJava({
+      gecko: {
+        type: 'Accessibility:Event',
+        eventType: this.ANDROID_VIEW_TEXT_CHANGED,
+        text: stateUtterance,
+        addedCount: stateUtterance.join(' ').length,
+        removedCount: 0,
+        fromIndex: 0
+      }
+    });
+  },
 
-AndroidPresenter.prototype.textChanged = function(aIsInserted, aStart, aLength, aText, aModifiedText) {
-  let androidEvent = {
-    type: 'Accessibility:Event',
-    eventType: ANDROID_TYPE_VIEW_TEXT_CHANGED,
-    text: [aText],
-    fromIndex: aStart
-  };
+  textChanged: function AndroidPresenter_textChanged(aIsInserted, aStart,
+                                                     aLength, aText,
+                                                     aModifiedText) {
+    let androidEvent = {
+      type: 'Accessibility:Event',
+      eventType: this.ANDROID_VIEW_TEXT_CHANGED,
+      text: [aText],
+      fromIndex: aStart
+    };
 
-  if (aIsInserted) {
-    androidEvent.addedCount = aLength;
-    androidEvent.beforeText =
-      aText.substring(0, aStart) + aText.substring(aStart + aLength);
-  } else {
-    androidEvent.removedCount = aLength;
-    androidEvent.beforeText =
-      aText.substring(0, aStart) + aModifiedText + aText.substring(aStart);
+    if (aIsInserted) {
+      androidEvent.addedCount = aLength;
+      androidEvent.beforeText =
+        aText.substring(0, aStart) + aText.substring(aStart + aLength);
+    } else {
+      androidEvent.removedCount = aLength;
+      androidEvent.beforeText =
+        aText.substring(0, aStart) + aModifiedText + aText.substring(aStart);
+    }
+
+    this.sendMessageToJava({gecko: androidEvent});
+  },
+
+  sendMessageToJava: function AndroidPresenter_sendMessageTojava(aMessage) {
+    return Cc['@mozilla.org/android/bridge;1'].
+      getService(Ci.nsIAndroidBridge).
+      handleGeckoMessage(JSON.stringify(aMessage));
   }
-
-  this.sendMessageToJava({gecko: androidEvent});
-};
-
-AndroidPresenter.prototype.sendMessageToJava = function(aMessage) {
-  return Cc['@mozilla.org/android/bridge;1'].
-    getService(Ci.nsIAndroidBridge).
-    handleGeckoMessage(JSON.stringify(aMessage));
 };
 
 /**
  * A dummy Android presenter for desktop testing
  */
 
 function DummyAndroidPresenter() {}
 
-DummyAndroidPresenter.prototype = new AndroidPresenter();
+DummyAndroidPresenter.prototype = {
+  __proto__: AndroidPresenter.prototype,
 
-DummyAndroidPresenter.prototype.sendMessageToJava = function(aMessage) {
-  dump(JSON.stringify(aMessage, null, 2) + '\n');
+  sendMessageToJava: function DummyAndroidPresenter_sendMessageToJava(aMsg) {
+    dump(JSON.stringify(aMsg, null, 2) + '\n');
+  }
 };
--- a/accessible/src/jsat/UtteranceGenerator.jsm
+++ b/accessible/src/jsat/UtteranceGenerator.jsm
@@ -60,20 +60,20 @@ var UtteranceGenerator = {
    * Generates an utterance for an object.
    * @param {nsIAccessible} aAccessible accessible object to generate utterance
    *    for.
    * @param {boolean} aForceName include the object's name in the utterance
    *    even if this object type does not usually have it's name uttered.
    * @return {Array} Two string array. The first string describes the object
    *    and its states. The second string is the object's name. Some object
    *    types may have the description or name omitted, instead an empty string
-   *    is returned as a placeholder. Whether the object's description or it's role
-   *    is included is determined by {@link verbosityRoleMap}.
+   *    is returned as a placeholder. Whether the object's description or it's
+   *    role is included is determined by {@link verbosityRoleMap}.
    */
-  genForObject: function(aAccessible, aForceName) {
+  genForObject: function genForObject(aAccessible, aForceName) {
     let roleString = gAccRetrieval.getStringRole(aAccessible.role);
 
     let func = this.objectUtteranceFunctions[roleString] ||
       this.objectUtteranceFunctions.defaultFunc;
 
     let flags = this.verbosityRoleMap[roleString] || 0;
 
     if (aForceName)
@@ -86,29 +86,29 @@ var UtteranceGenerator = {
    * Generates an utterance for an action performed.
    * TODO: May become more verbose in the future.
    * @param {nsIAccessible} aAccessible accessible object that the action was
    *    invoked in.
    * @param {string} aActionName the name of the action, one of the keys in
    *    {@link gActionMap}.
    * @return {Array} A one string array with the action.
    */
-  genForAction: function(aObject, aActionName) {
+  genForAction: function genForAction(aObject, aActionName) {
     return [gStringBundle.GetStringFromName(this.gActionMap[aActionName])];
   },
 
   /**
    * Generates an utterance for a tab state change.
    * @param {nsIAccessible} aAccessible accessible object of the tab's attached
    *    document.
    * @param {string} aTabState the tab state name, see
    *    {@link Presenter.tabStateChanged}.
    * @return {Array} The tab state utterace.
    */
-  genForTabStateChange: function (aObject, aTabState) {
+  genForTabStateChange: function genForTabStateChange(aObject, aTabState) {
     switch (aTabState) {
       case 'newtab':
         return [gStringBundle.GetStringFromName('tabNew')];
       case 'loading':
         return [gStringBundle.GetStringFromName('tabLoading')];
       case 'loaded':
         return [aObject.name || '',
                 gStringBundle.GetStringFromName('tabLoaded')];
@@ -172,17 +172,18 @@ var UtteranceGenerator = {
     'combobox option': INCLUDE_ROLE,
     'image map': INCLUDE_ROLE,
     'option': INCLUDE_ROLE,
     'listbox': INCLUDE_ROLE},
 
   objectUtteranceFunctions: {
     defaultFunc: function defaultFunc(aAccessible, aRoleStr, aFlags) {
       let name = (aFlags & INCLUDE_NAME) ? (aAccessible.name || '') : '';
-      let desc = (aFlags & INCLUDE_ROLE) ? this._getLocalizedRole(aRoleStr) : '';
+      let desc = (aFlags & INCLUDE_ROLE) ?
+        this._getLocalizedRole(aRoleStr) : '';
 
       let utterance = [];
 
       if (desc) {
         let state = {};
         let extState = {};
         aAccessible.getState(state, extState);
 
@@ -202,30 +203,30 @@ var UtteranceGenerator = {
       }
 
       if (name)
         utterance.push(name);
 
       return utterance;
     },
 
-    heading: function(aAccessible, aRoleStr, aFlags) {
+    heading: function heading(aAccessible, aRoleStr, aFlags) {
       let name = (aFlags & INCLUDE_NAME) ? (aAccessible.name || '') : '';
       let level = {};
       aAccessible.groupPosition(level, {}, {});
       let utterance =
         [gStringBundle.formatStringFromName('headingLevel', [level.value], 1)];
 
       if (name)
         utterance.push(name);
 
       return utterance;
     },
 
-    listitem: function(aAccessible, aRoleStr, aFlags) {
+    listitem: function listitem(aAccessible, aRoleStr, aFlags) {
       let name = (aFlags & INCLUDE_NAME) ? (aAccessible.name || '') : '';
       let localizedRole = this._getLocalizedRole(aRoleStr);
       let itemno = {};
       let itemof = {};
       aAccessible.groupPosition({}, itemof, itemno);
       let utterance =
         [gStringBundle.formatStringFromName(
            'objItemOf', [localizedRole, itemno.value, itemof.value], 3)];
--- a/accessible/src/jsat/VirtualCursorController.jsm
+++ b/accessible/src/jsat/VirtualCursorController.jsm
@@ -15,34 +15,35 @@ Cu.import('resource://gre/modules/XPCOMU
 Cu.import('resource://gre/modules/Services.jsm');
 
 var gAccRetrieval = Cc['@mozilla.org/accessibleRetrieval;1'].
   getService(Ci.nsIAccessibleRetrieval);
 
 var VirtualCursorController = {
   attach: function attach(aWindow) {
     this.chromeWin = aWindow;
-    this.chromeWin.document.addEventListener('keypress', this.onkeypress, true);
+    this.chromeWin.document.addEventListener('keypress', this._onkeypress, true);
   },
 
   detach: function detach() {
-    this.chromeWin.document.removeEventListener('keypress', this.onkeypress, true);
+    this.chromeWin.document.removeEventListener('keypress', this._onkeypress,
+                                                true);
   },
 
-  getBrowserApp: function getBrowserApp() {
+  _getBrowserApp: function _getBrowserApp() {
     switch (Services.appinfo.OS) {
       case 'Android':
         return this.chromeWin.BrowserApp;
       default:
         return this.chromeWin.gBrowser;
     }
   },
 
-  onkeypress: function onkeypress(aEvent) {
-    let document = VirtualCursorController.getBrowserApp().
+  _onkeypress: function _onkeypress(aEvent) {
+    let document = VirtualCursorController._getBrowserApp().
       selectedBrowser.contentDocument;
 
     dump('keypress ' + aEvent.keyCode + '\n');
 
     switch (aEvent.keyCode) {
       case aEvent.DOM_VK_END:
         VirtualCursorController.moveForward(document, true);
         break;
@@ -52,17 +53,17 @@ var VirtualCursorController = {
       case aEvent.DOM_VK_RIGHT:
         VirtualCursorController.moveForward(document, aEvent.shiftKey);
         break;
       case aEvent.DOM_VK_LEFT:
         VirtualCursorController.moveBackward(document, aEvent.shiftKey);
         break;
       case aEvent.DOM_VK_UP:
         if (Services.appinfo.OS == 'Android')
-          // Return focus to browser chrome, which in Android is a native widget.
+          // Return focus to native Android browser chrome.
           Cc['@mozilla.org/android/bridge;1'].
             getService(Ci.nsIAndroidBridge).handleGeckoMessage(
               JSON.stringify({ gecko: { type: 'ToggleChrome:Focus' } }));
         break;
       case aEvent.DOM_VK_RETURN:
         // XXX: It is true that desktop does not map the keypad enter key to
         // DOM_VK_ENTER. So for desktop we require a ctrl+return instead.
         if (Services.appinfo.OS == 'Android' || !aEvent.ctrlKey)
@@ -105,25 +106,25 @@ var VirtualCursorController = {
   },
 
   getVirtualCursor: function getVirtualCursor(document) {
     return gAccRetrieval.getAccessibleFor(document).
       QueryInterface(Ci.nsIAccessibleCursorable).virtualCursor;
   },
 
   SimpleTraversalRule: {
-    getMatchRoles: function(aRules) {
+    getMatchRoles: function SimpleTraversalRule_getmatchRoles(aRules) {
       aRules.value = this._matchRoles;
       return this._matchRoles.length;
     },
 
     preFilter: Ci.nsIAccessibleTraversalRule.PREFILTER_DEFUNCT |
       Ci.nsIAccessibleTraversalRule.PREFILTER_INVISIBLE,
 
-    match: function(aAccessible) {
+    match: function SimpleTraversalRule_match(aAccessible) {
       switch (aAccessible.role) {
       case Ci.nsIAccessibleRole.ROLE_COMBOBOX:
         // We don't want to ignore the subtree because this is often
         // where the list box hangs out.
         return Ci.nsIAccessibleTraversalRule.FILTER_MATCH;
       case Ci.nsIAccessibleRole.ROLE_TEXT_LEAF:
         {
           // Nameless text leaves are boring, skip them.
--- a/accessible/tests/mochitest/bounds/Makefile.in
+++ b/accessible/tests/mochitest/bounds/Makefile.in
@@ -41,14 +41,15 @@ topsrcdir	= @top_srcdir@
 srcdir		= @srcdir@
 VPATH		= @srcdir@
 relativesrcdir  = accessible/bounds
 
 include $(DEPTH)/config/autoconf.mk
 include $(topsrcdir)/config/rules.mk
 
 _TEST_FILES =\
+		test_list.html \
 		test_select.html \
 		test_zoom.html \
 		$(NULL)
 
 libs:: $(_TEST_FILES)
 	$(INSTALL) $(foreach f,$^,"$f") $(DEPTH)/_tests/testing/mochitest/a11y/$(relativesrcdir)
new file mode 100644
--- /dev/null
+++ b/accessible/tests/mochitest/bounds/test_list.html
@@ -0,0 +1,81 @@
+<!DOCTYPE html>
+<html>
+<head>
+  <title>Accessible boundaries when page is zoomed</title>
+  <link rel="stylesheet" type="text/css"
+        href="chrome://mochikit/content/tests/SimpleTest/test.css" />
+
+  <script type="application/javascript"
+          src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+  <script type="application/javascript"
+          src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"></script>
+
+  <script type="application/javascript"
+          src="../common.js"></script>
+  <script type="application/javascript"
+          src="../role.js"></script>
+  <script type="application/javascript"
+          src="../layout.js"></script>
+
+  <script type="application/javascript">
+    function doTest()
+    {
+      // Inside list
+      var li = getAccessible("insidelist_item");
+      testBounds(li);
+
+      var [xLI, yLI, widthLI, heightLI] = getBounds(li);
+      var bullet = li.firstChild;
+      var [x, y, width, height] = getBounds(bullet);
+      is(x, xLI,
+        "Bullet x should match to list item x");
+      ok(y >= yLI,
+         "Bullet y= " + y + " should be not less than list item y=" + yLI);
+      ok(width < widthLI,
+         "Bullet width should be lesser list item width");
+      ok(height <= heightLI,
+         "Bullet height= " + height + " should be not greater than list item height=" + heightLI);
+
+      // Outside list
+      li = getAccessible("outsidelist_item");
+      var [xLIElm, yLIElm, widthLIElm, heightLIElm] = getBoundsForDOMElm(li);
+      [xLI, yLI, widthLI, heightLI] = getBounds(li);
+
+      ok(xLI < xLIElm,
+         "Outside list item x=" + xLI + " should be lesser than list item element x=" + xLIElm);
+      is(yLI, yLIElm,
+         "Outside list item y should match to list item element y");
+      ok(widthLI > widthLIElm,
+         "Outside list item width=" + widthLI + " should be greater than list item element width=" + widthLIElm);
+      is(heightLI, heightLIElm,
+         "Outside list item height should match to list item element height");
+
+      SimpleTest.finish();
+    }
+
+    SimpleTest.waitForExplicitFinish();
+    addA11yLoadEvent(doTest);
+  </script>
+</head>
+<body>
+
+  <a target="_blank"
+     href="https://bugzilla.mozilla.org/show_bug.cgi?id=754627"
+     title="GetBounds on bullet return wrong values">
+    Mozilla Bug 754627
+  </a>
+  <p id="display"></p>
+  <div id="content" style="display: none"></div>
+  <pre id="test">
+  </pre>
+
+  <ul style="list-style-position: inside;">
+    <li id="insidelist_item">item</li>
+  </ul>
+
+  <ul style="list-style-position: outside;">
+    <li id="outsidelist_item">item</li>
+  </ul>
+
+</body>
+</html>
--- a/accessible/tests/mochitest/pivot.js
+++ b/accessible/tests/mochitest/pivot.js
@@ -3,16 +3,18 @@ Components.utils.import("resource://gre/
 ////////////////////////////////////////////////////////////////////////////////
 // Constants
 
 const PREFILTER_INVISIBLE = nsIAccessibleTraversalRule.PREFILTER_INVISIBLE;
 const FILTER_MATCH = nsIAccessibleTraversalRule.FILTER_MATCH;
 const FILTER_IGNORE = nsIAccessibleTraversalRule.FILTER_IGNORE;
 const FILTER_IGNORE_SUBTREE = nsIAccessibleTraversalRule.FILTER_IGNORE_SUBTREE;
 
+const NS_ERROR_NOT_IN_TREE = 0x80780026;
+
 ////////////////////////////////////////////////////////////////////////////////
 // Traversal rules
 
 /**
  * Rule object to traverse all focusable nodes and text nodes.
  */
 var HeadersTraversalRule =
 {
@@ -63,23 +65,23 @@ var ObjectTraversalRule =
 };
 
 ////////////////////////////////////////////////////////////////////////////////
 // Virtual state invokers and checkers
 
 /**
  * A checker for virtual cursor changed events.
  */
-function virtualCursorChangedChecker(aDocAcc, aIdOrNameOrAcc, aTextOffsets)
+function VCChangedChecker(aDocAcc, aIdOrNameOrAcc, aTextOffsets)
 {
   this.__proto__ = new invokerChecker(EVENT_VIRTUALCURSOR_CHANGED, aDocAcc);
 
-  this.check = function virtualCursorChangedChecker_check(aEvent)
+  this.check = function VCChangedChecker_check(aEvent)
   {
-    SimpleTest.info("virtualCursorChangedChecker_check");
+    SimpleTest.info("VCChangedChecker_check");
 
     var event = null;
     try {
       event = aEvent.QueryInterface(nsIAccessibleVirtualCursorChangeEvent);
     } catch (e) {
       SimpleTest.ok(false, "Does not support correct interface: " + e);
     }
 
@@ -95,157 +97,248 @@ function virtualCursorChangedChecker(aDo
 
     if (aTextOffsets) {
       SimpleTest.is(aDocAcc.virtualCursor.startOffset, aTextOffsets[0],
                     "wrong start offset");
       SimpleTest.is(aDocAcc.virtualCursor.endOffset, aTextOffsets[1],
                     "wrong end offset");
     }
 
-    var prevPosAndOffset = virtualCursorChangedChecker.
+    var prevPosAndOffset = VCChangedChecker.
       getPreviousPosAndOffset(aDocAcc.virtualCursor);
 
     if (prevPosAndOffset) {
       SimpleTest.is(event.oldAccessible, prevPosAndOffset.position,
                     "previous position does not match");
       SimpleTest.is(event.oldStartOffset, prevPosAndOffset.startOffset,
                     "previous start offset does not match");
       SimpleTest.is(event.oldEndOffset, prevPosAndOffset.endOffset,
                     "previous end offset does not match");
     }
   };
 }
 
-virtualCursorChangedChecker.prevPosAndOffset = {};
+VCChangedChecker.prevPosAndOffset = {};
 
-virtualCursorChangedChecker.storePreviousPosAndOffset =
+VCChangedChecker.storePreviousPosAndOffset =
   function storePreviousPosAndOffset(aPivot)
 {
-  virtualCursorChangedChecker.prevPosAndOffset[aPivot] =
+  VCChangedChecker.prevPosAndOffset[aPivot] =
     {position: aPivot.position,
      startOffset: aPivot.startOffset,
      endOffset: aPivot.endOffset};
 };
 
-virtualCursorChangedChecker.getPreviousPosAndOffset =
+VCChangedChecker.getPreviousPosAndOffset =
   function getPreviousPosAndOffset(aPivot)
 {
-  return virtualCursorChangedChecker.prevPosAndOffset[aPivot];
+  return VCChangedChecker.prevPosAndOffset[aPivot];
 };
 
 /**
  * Set a text range in the pivot and wait for virtual cursor change event.
  *
- * @param aDocAcc document that manages the virtual cursor
- * @param aTextAccessible accessible to set to virtual cursor's position
- * @param aTextOffsets start and end offsets of text range to set in virtual
- *   cursor
+ * @param aDocAcc         [in] document that manages the virtual cursor
+ * @param aTextAccessible [in] accessible to set to virtual cursor's position
+ * @param aTextOffsets    [in] start and end offsets of text range to set in
+ *                        virtual cursor.
  */
-function setVirtualCursorRangeInvoker(aDocAcc, aTextAccessible, aTextOffsets)
+function setVCRangeInvoker(aDocAcc, aTextAccessible, aTextOffsets)
 {
   this.invoke = function virtualCursorChangedInvoker_invoke()
   {
-    virtualCursorChangedChecker.
+    VCChangedChecker.
       storePreviousPosAndOffset(aDocAcc.virtualCursor);
     SimpleTest.info(prettyName(aTextAccessible) + " " + aTextOffsets);
     aDocAcc.virtualCursor.setTextRange(aTextAccessible,
                                        aTextOffsets[0],
                                        aTextOffsets[1]);
   };
 
-  this.getID = function setVirtualCursorRangeInvoker_getID()
+  this.getID = function setVCRangeInvoker_getID()
   {
     return "Set offset in " + prettyName(aTextAccessible) +
       " to (" + aTextOffsets[0] + ", " + aTextOffsets[1] + ")";
-  }
+  };
 
   this.eventSeq = [
-    new virtualCursorChangedChecker(aDocAcc, aTextAccessible, aTextOffsets)
+    new VCChangedChecker(aDocAcc, aTextAccessible, aTextOffsets)
   ];
 }
 
 /**
  * Move the pivot and wait for virtual cursor change event.
  *
- * @param aDocAcc document that manages the virtual cursor
- * @param aPivotMoveMethod method to test (ie. "moveNext", "moveFirst", etc.)
- * @param aRule traversal rule object
- * @param aIdOrNameOrAcc id, accessivle or accessible name to expect virtual
- *   cursor to land on after performing move method.
+ * @param aDocAcc          [in] document that manages the virtual cursor
+ * @param aPivotMoveMethod [in] method to test (ie. "moveNext", "moveFirst", etc.)
+ * @param aRule            [in] traversal rule object
+ * @param aIdOrNameOrAcc   [in] id, accessivle or accessible name to expect
+ *                         virtual cursor to land on after performing move method.
  */
-function setVirtualCursorPosInvoker(aDocAcc, aPivotMoveMethod, aRule,
-                                    aIdOrNameOrAcc)
+function setVCPosInvoker(aDocAcc, aPivotMoveMethod, aRule, aIdOrNameOrAcc)
 {
   this.invoke = function virtualCursorChangedInvoker_invoke()
   {
-    virtualCursorChangedChecker.
+    VCChangedChecker.
       storePreviousPosAndOffset(aDocAcc.virtualCursor);
     var moved = aDocAcc.virtualCursor[aPivotMoveMethod](aRule);
     SimpleTest.ok((aIdOrNameOrAcc && moved) || (!aIdOrNameOrAcc && !moved),
                   "moved pivot");
   };
 
-  this.getID = function setVirtualCursorPosInvoker_getID()
+  this.getID = function setVCPosInvoker_getID()
   {
     return "Do " + (aIdOrNameOrAcc ? "" : "no-op ") + aPivotMoveMethod;
-  }
+  };
 
   if (aIdOrNameOrAcc) {
-    this.eventSeq = [ new virtualCursorChangedChecker(aDocAcc, aIdOrNameOrAcc) ];
+    this.eventSeq = [ new VCChangedChecker(aDocAcc, aIdOrNameOrAcc) ];
   } else {
     this.eventSeq = [];
     this.unexpectedEventSeq = [
       new invokerChecker(EVENT_VIRTUALCURSOR_CHANGED, aDocAcc)
     ];
   }
 }
 
 /**
  * Add invokers to a queue to test a rule and an expected sequence of element ids
  * or accessible names for that rule in the given document.
  *
- * @param aQueue event queue in which to push invoker sequence.
- * @param aDocAcc the managing document of the virtual cursor we are testing
- * @param aRule the traversal rule to use in the invokers
- * @param aSequence a sequence of accessible names or elemnt ids to expect with
- *   the given rule in the given document
+ * @param aQueue    [in] event queue in which to push invoker sequence.
+ * @param aDocAcc   [in] the managing document of the virtual cursor we are testing
+ * @param aRule     [in] the traversal rule to use in the invokers
+ * @param aSequence [in] a sequence of accessible names or elemnt ids to expect with
+ *                  the given rule in the given document
  */
 function queueTraversalSequence(aQueue, aDocAcc, aRule, aSequence)
 {
   aDocAcc.virtualCursor.position = null;
 
   for (var i = 0; i < aSequence.length; i++) {
-    var invoker = new setVirtualCursorPosInvoker(aDocAcc, "moveNext",
-                                                 aRule, aSequence[i]);
+    var invoker =
+      new setVCPosInvoker(aDocAcc, "moveNext", aRule, aSequence[i]);
     aQueue.push(invoker);
   }
 
   // No further more matches for given rule, expect no virtual cursor changes.
-  aQueue.push(new setVirtualCursorPosInvoker(aDocAcc, "moveNext", aRule, null));
+  aQueue.push(new setVCPosInvoker(aDocAcc, "moveNext", aRule, null));
 
   for (var i = aSequence.length-2; i >= 0; i--) {
-    var invoker = new setVirtualCursorPosInvoker(aDocAcc, "movePrevious",
-                                                 aRule, aSequence[i])
+    var invoker =
+      new setVCPosInvoker(aDocAcc, "movePrevious", aRule, aSequence[i]);
     aQueue.push(invoker);
   }
 
   // No previous more matches for given rule, expect no virtual cursor changes.
-  aQueue.push(new setVirtualCursorPosInvoker(aDocAcc, "movePrevious", aRule, null));
+  aQueue.push(new setVCPosInvoker(aDocAcc, "movePrevious", aRule, null));
 
-  aQueue.push(new setVirtualCursorPosInvoker(
-    aDocAcc, "moveLast", aRule, aSequence[aSequence.length - 1]));
+  aQueue.push(new setVCPosInvoker(aDocAcc, "moveLast", aRule,
+                                  aSequence[aSequence.length - 1]));
 
   // No further more matches for given rule, expect no virtual cursor changes.
-  aQueue.push(new setVirtualCursorPosInvoker(aDocAcc, "moveNext", aRule, null));
+  aQueue.push(new setVCPosInvoker(aDocAcc, "moveNext", aRule, null));
 
-  aQueue.push(new setVirtualCursorPosInvoker(
-    aDocAcc, "moveFirst", aRule, aSequence[0]));
+  aQueue.push(new setVCPosInvoker(aDocAcc, "moveFirst", aRule, aSequence[0]));
 
   // No previous more matches for given rule, expect no virtual cursor changes.
-  aQueue.push(new setVirtualCursorPosInvoker(aDocAcc, "movePrevious", aRule, null));
+  aQueue.push(new setVCPosInvoker(aDocAcc, "movePrevious", aRule, null));
+}
+
+/**
+ * A checker for removing an accessible while the virtual cursor is on it.
+ */
+function removeVCPositionChecker(aDocAcc, aHiddenParentAcc)
+{
+  this.__proto__ = new invokerChecker(EVENT_REORDER, aHiddenParentAcc);
+
+  this.check = function removeVCPositionChecker_check(aEvent) {
+    var errorResult = 0;
+    try {
+      aDocAcc.virtualCursor.moveNext(ObjectTraversalRule);
+    } catch (x) {
+      errorResult = x.result;
+    }
+    SimpleTest.is(
+      errorResult, NS_ERROR_NOT_IN_TREE,
+      "Expecting NOT_IN_TREE error when moving pivot from invalid position.");
+  };
+}
+
+/**
+ * Put the virtual cursor's position on an object, and then remove it.
+ *
+ * @param aDocAcc     [in] document that manages the virtual cursor
+ * @param aPosNode    [in] DOM node to hide after virtual cursor's position is
+ *                    set to it.
+ */
+function removeVCPositionInvoker(aDocAcc, aPosNode)
+{
+  this.accessible = getAccessible(aPosNode);
+  this.invoke = function removeVCPositionInvoker_invoke()
+  {
+    aDocAcc.virtualCursor.position = this.accessible;
+    aPosNode.parentNode.removeChild(aPosNode);
+  };
+
+  this.getID = function removeVCPositionInvoker_getID()
+  {
+    return "Bring virtual cursor to accessible, and remove its DOM node.";
+  };
+
+  this.eventSeq = [
+    new removeVCPositionChecker(aDocAcc, this.accessible.parent)
+  ];
+}
+
+/**
+ * A checker for removing the pivot root and then calling moveFirst, and
+ * checking that an exception is thrown.
+ */
+function removeVCRootChecker(aPivot)
+{
+  this.__proto__ = new invokerChecker(EVENT_REORDER, aPivot.root.parent);
+
+  this.check = function removeVCRootChecker_check(aEvent) {
+    var errorResult = 0;
+    try {
+      aPivot.moveLast(ObjectTraversalRule);
+    } catch (x) {
+      errorResult = x.result;
+    }
+    SimpleTest.is(
+      errorResult, NS_ERROR_NOT_IN_TREE,
+      "Expecting NOT_IN_TREE error when moving pivot from invalid position.");
+  };
+}
+
+/**
+ * Create a pivot, remove its root, and perform an operation where the root is
+ * needed.
+ *
+ * @param aRootNode [in] DOM node of which accessible will be the root of the
+ *                       pivot. Should have more than one child.
+ */
+function removeVCRootInvoker(aRootNode)
+{
+  this.pivot = gAccRetrieval.createAccessiblePivot(getAccessible(aRootNode));
+  this.invoke = function removeVCRootInvoker_invoke()
+  {
+    this.pivot.position = this.pivot.root.firstChild;
+    aRootNode.parentNode.removeChild(aRootNode);
+  };
+
+  this.getID = function removeVCRootInvoker_getID()
+  {
+    return "Remove root of pivot from tree.";
+  };
+
+  this.eventSeq = [
+    new removeVCRootChecker(this.pivot)
+  ];
 }
 
 /**
  * A debug utility for writing proper sequences for queueTraversalSequence.
  */
 function dumpTraversalSequence(aPivot, aRule)
 {
   var sequence = []
--- a/accessible/tests/mochitest/pivot/doc_virtualcursor.html
+++ b/accessible/tests/mochitest/pivot/doc_virtualcursor.html
@@ -12,15 +12,16 @@
     leo, id <a href="#">semper</a> nulla.
   </p>
   <h2 id="heading-2-2">Second Section Title</h2>
   <p id="paragraph-2">
     Sed accumsan luctus lacus, vitae mollis arcu tristique vulputate.</p>
   <iframe
      src="data:text/html,<html><body>An <i>embedded</i> document.</body></html>">
   </iframe>
-<p>
-  <a href="http://mozilla.org" title="Link 1 title">Link 1</a>
-  <a href="http://mozilla.org" title="Link 2 title">Link 2</a>
-  <a href="http://mozilla.org" title="Link 3 title">Link 3</a>
-</p>
+  <div id="hide-me">Hide me</div>
+  <p id="links">
+    <a href="http://mozilla.org" title="Link 1 title">Link 1</a>
+    <a href="http://mozilla.org" title="Link 2 title">Link 2</a>
+    <a href="http://mozilla.org" title="Link 3 title">Link 3</a>
+  </p>
 </body>
 </html>
--- a/accessible/tests/mochitest/pivot/test_virtualcursor.html
+++ b/accessible/tests/mochitest/pivot/test_virtualcursor.html
@@ -55,25 +55,32 @@
                              ['heading-1-1', 'heading-2-1', 'heading-2-2']);
 
       queueTraversalSequence(
         gQueue, docAcc, ObjectTraversalRule,
         ['Main Title', 'First Section Title', 'Lorem ipsum ',
          'dolor', ' sit amet. Integer vitae urna leo, id ',
          'semper', ' nulla. ', 'Second Section Title',
          'Sed accumsan luctus lacus, vitae mollis arcu tristique vulputate.',
-         'An ', 'embedded', ' document.', 'Link 1', 'Link 2', 'Link 3']);
+         'An ', 'embedded', ' document.', 'Hide me', 'Link 1', 'Link 2',
+         'Link 3']);
 
       // Just a random smoke test to see if our setTextRange works.
       gQueue.push(
-        new setVirtualCursorRangeInvoker(
+        new setVCRangeInvoker(
           docAcc,
           getAccessible(doc.getElementById('paragraph-2'), nsIAccessibleText),
           [2,6]));
 
+      gQueue.push(new removeVCPositionInvoker(
+        docAcc, doc.getElementById('hide-me')));
+
+      gQueue.push(new removeVCRootInvoker(
+        doc.getElementById('links')));
+
       gQueue.invoke();
     }
 
     SimpleTest.waitForExplicitFinish();
     addLoadEvent(function () {
       /* We open a new browser because we need to test with a top-level content
          document. */
       openBrowserWindow(
--- a/browser/app/Makefile.in
+++ b/browser/app/Makefile.in
@@ -181,41 +181,41 @@ libs:: $(srcdir)/blocklist.xml
 ifeq (cocoa,$(MOZ_WIDGET_TOOLKIT))
 
 MAC_APP_NAME = $(MOZ_APP_DISPLAYNAME)
 
 ifdef MOZ_DEBUG
 MAC_APP_NAME := $(MAC_APP_NAME)Debug
 endif
 
-LOWER_MAC_APP_NAME = $(shell echo $(MAC_APP_NAME) | tr '[A-Z]' '[a-z]')
-
 AB_CD = $(MOZ_UI_LOCALE)
 
 AB := $(firstword $(subst -, ,$(AB_CD)))
 
 clean clobber repackage::
 	$(RM) -r $(dist_dest)
 
 ifdef LIBXUL_SDK
 APPFILES = Resources
 else
 APPFILES = MacOS
 endif
 
+MAC_BUNDLE_VERSION = $(shell $(PYTHON) $(srcdir)/macversion.py --version=$(MOZ_APP_VERSION) --buildid=$(DEPTH)/config/buildid)
+
 libs-preqs = \
   $(call mkdir_deps,$(dist_dest)/Contents/MacOS) \
   $(call mkdir_deps,$(dist_dest)/Contents/Resources/$(AB).lproj) \
   $(NULL)
 
 .PHONY: repackage
 libs repackage:: $(PROGRAM) $(libs-preqs)
 	rsync -a --exclude "*.in" $(srcdir)/macbuild/Contents $(dist_dest) --exclude English.lproj
 	rsync -a --exclude "*.in" $(srcdir)/macbuild/Contents/Resources/English.lproj/ $(dist_dest)/Contents/Resources/$(AB).lproj
-	sed -e "s/%APP_VERSION%/$(MOZ_APP_VERSION)/" -e "s/%MAC_APP_NAME%/$(MAC_APP_NAME)/" -e "s/%LOWER_MAC_APP_NAME%/$(LOWER_MAC_APP_NAME)/" $(srcdir)/macbuild/Contents/Info.plist.in > $(dist_dest)/Contents/Info.plist
+	sed -e "s/%APP_VERSION%/$(MOZ_APP_VERSION)/" -e "s/%MAC_APP_NAME%/$(MAC_APP_NAME)/" -e "s/%MOZ_MACBUNDLE_ID%/$(MOZ_MACBUNDLE_ID)/" -e "s/%MAC_BUNDLE_VERSION%/$(MAC_BUNDLE_VERSION)/" $(srcdir)/macbuild/Contents/Info.plist.in > $(dist_dest)/Contents/Info.plist
 	sed -e "s/%MAC_APP_NAME%/$(MAC_APP_NAME)/" $(srcdir)/macbuild/Contents/Resources/English.lproj/InfoPlist.strings.in | iconv -f UTF-8 -t UTF-16 > $(dist_dest)/Contents/Resources/$(AB).lproj/InfoPlist.strings
 	rsync -a $(DIST)/bin/ $(dist_dest)/Contents/$(APPFILES)
 ifdef LIBXUL_SDK
 	cp $(LIBXUL_DIST)/bin/$(XR_STUB_NAME) $(dist_dest)/Contents/MacOS/firefox
 else
 	$(RM) $(dist_dest)/Contents/MacOS/$(PROGRAM)
 	rsync -aL $(PROGRAM) $(dist_dest)/Contents/MacOS
 endif
--- a/browser/app/macbuild/Contents/Info.plist.in
+++ b/browser/app/macbuild/Contents/Info.plist.in
@@ -144,17 +144,17 @@
 	</array>
 	<key>CFBundleExecutable</key>
 	<string>firefox</string>
 	<key>CFBundleGetInfoString</key>
 	<string>%MAC_APP_NAME% %APP_VERSION%</string>
 	<key>CFBundleIconFile</key>
 	<string>firefox</string>
 	<key>CFBundleIdentifier</key>
-	<string>org.mozilla.%LOWER_MAC_APP_NAME%</string>
+	<string>%MOZ_MACBUNDLE_ID%</string>
 	<key>CFBundleInfoDictionaryVersion</key>
 	<string>6.0</string>
 	<key>CFBundleName</key>
 	<string>%MAC_APP_NAME%</string>
 	<key>CFBundlePackageType</key>
 	<string>APPL</string>
 	<key>CFBundleShortVersionString</key>
 	<string>%APP_VERSION%</string>
@@ -195,17 +195,17 @@
 			<string>file URL</string>
 			<key>CFBundleURLSchemes</key>
 			<array>
 				<string>file</string>
 			</array>
 		</dict>
 	</array>
 	<key>CFBundleVersion</key>
-	<string>%APP_VERSION%</string>
+	<string>%MAC_BUNDLE_VERSION%</string>
 	<key>NSAppleScriptEnabled</key>
 	<true/>
 	<key>LSMinimumSystemVersion</key>
 	<string>10.5</string>
 	<key>LSMinimumSystemVersionByArchitecture</key>
 	<dict>
 		<key>i386</key>
 		<string>10.5.0</string>
new file mode 100644
--- /dev/null
+++ b/browser/app/macversion.py
@@ -0,0 +1,40 @@
+#!/usr/bin/python
+
+from optparse import OptionParser
+import sys
+import re
+
+o = OptionParser()
+o.add_option("--buildid", dest="buildid")
+o.add_option("--version", dest="version")
+
+(options, args) = o.parse_args()
+
+if not options.buildid:
+    print >>sys.stderr, "--buildid is required"
+    sys.exit(1)
+
+if not options.version:
+    print >>sys.stderr, "--version is required"
+    sys.exit(1)
+
+# We want to build a version number that matches the format allowed for
+# CFBundleVersion (nnnnn[.nn[.nn]]). We'll incorporate both the version
+# number as well as the date, so that it changes at least daily (for nightly
+# builds), but also so that newly-built older versions (e.g. beta build) aren't
+# considered "newer" than previously-built newer versions (e.g. a trunk nightly)
+
+buildid = open(options.buildid, 'r').read()
+
+# extract only the major version (i.e. "14" from "14.0b1")
+majorVersion = re.match(r'^(\d+)[^\d].*', options.version).group(1)
+# last two digits of the year
+twodigityear = buildid[2:4]
+month = buildid[4:6]
+if month[0] == '0':
+  month = month[1]
+day = buildid[6:8]
+if day[0] == '0':
+  day = day[1]
+
+print '%s.%s.%s' % (majorVersion + twodigityear, month, day)
--- a/browser/base/content/aboutDialog.css
+++ b/browser/base/content/aboutDialog.css
@@ -60,18 +60,13 @@
 }
 
 .bottom-link,
 .bottom-link:focus {
   text-align: center;
   margin: 0 40px;
 }
 
-.text-link:-moz-focusring,
-.bottom-link:-moz-focusring {
-  outline: 1px dotted;
-}
-
 #currentChannel {
   margin: 0;
   padding: 0;
   font-weight: bold;
 }
--- a/browser/base/content/browser-menubar.inc
+++ b/browser/base/content/browser-menubar.inc
@@ -303,22 +303,40 @@
                               oncommand="gPageStyleMenu.switchStyleSheet('');"
                               type="radio"
                               checked="true"/>
                     <menuseparator/>
                   </menupopup>
                 </menu>
 #include browser-charsetmenu.inc
                 <menuseparator/>
+#ifdef XP_MACOSX
+                <menuitem id="enterFullScreenItem"
+                          accesskey="&enterFullScreenCmd.accesskey;"
+                          label="&enterFullScreenCmd.label;"
+                          key="key_fullScreen">
+                  <observes element="View:FullScreen" attribute="oncommand"/>
+                  <observes element="View:FullScreen" attribute="disabled"/>
+                </menuitem>
+                <menuitem id="exitFullScreenItem"
+                          accesskey="&exitFullScreenCmd.accesskey;"
+                          label="&exitFullScreenCmd.label;"
+                          key="key_fullScreen"
+                          hidden="true">
+                  <observes element="View:FullScreen" attribute="oncommand"/>
+                  <observes element="View:FullScreen" attribute="disabled"/>
+                </menuitem>
+#else
                 <menuitem id="fullScreenItem"
                           accesskey="&fullScreenCmd.accesskey;"
                           label="&fullScreenCmd.label;"
                           key="key_fullScreen"
                           type="checkbox"
                           observes="View:FullScreen"/>
+#endif
                 <menuitem id="menu_showAllTabs"
                           hidden="true"
                           accesskey="&showAllTabsCmd.accesskey;"
                           label="&showAllTabsCmd.label;"
                           command="Browser:ShowAllTabs"
                           key="key_showAllTabs"/>
                 <menuseparator hidden="true" id="documentDirection-separator"/>
                 <menuitem id="documentDirection-swap"
--- a/browser/base/content/browser-sets.inc
+++ b/browser/base/content/browser-sets.inc
@@ -336,17 +336,18 @@
     <key keycode="VK_F5" command="Browser:Reload"/>
 #ifndef XP_MACOSX
     <key id="showAllHistoryKb" key="&showAllHistoryCmd.commandkey;" command="Browser:ShowAllHistory" modifiers="accel,shift"/>
     <key keycode="VK_F5" command="Browser:ReloadSkipCache" modifiers="accel"/>
     <key keycode="VK_F6" command="Browser:FocusNextFrame"/>
     <key keycode="VK_F6" command="Browser:FocusNextFrame" modifiers="shift"/>
     <key id="key_fullScreen" keycode="VK_F11" command="View:FullScreen"/>
 #else
-    <key id="key_fullScreen" key="&fullScreenCmd.macCommandKey;" command="View:FullScreen" modifiers="accel,shift"/>
+    <key id="key_fullScreen" key="&fullScreenCmd.macCommandKey;" command="View:FullScreen" modifiers="accel,control"/>
+    <key id="key_fullScreen_old" key="&fullScreenCmd.macCommandKey;" command="View:FullScreen" modifiers="accel,shift"/>
     <key keycode="VK_F11" command="View:FullScreen"/>
 #endif
     <key key="&reloadCmd.commandkey;" command="Browser:Reload" modifiers="accel" id="key_reload"/>
     <key key="&reloadCmd.commandkey;" command="Browser:ReloadSkipCache" modifiers="accel,shift"/>
     <key id="key_viewSource" key="&pageSourceCmd.commandkey;" command="View:PageSource" modifiers="accel"/>
 #ifndef XP_WIN
     <key id="key_viewInfo"   key="&pageInfoCmd.commandkey;"   command="View:PageInfo"   modifiers="accel"/>
 #endif
--- a/browser/base/content/browser.js
+++ b/browser/base/content/browser.js
@@ -3953,16 +3953,22 @@ var FullScreen = {
     // We get the fullscreen event _before_ the window transitions into or out of FS mode.
     if (event && event.type == "fullscreen")
       enterFS = !enterFS;
 
     // Toggle the View:FullScreen command, which controls elements like the
     // fullscreen menuitem, menubars, and the appmenu.
     document.getElementById("View:FullScreen").setAttribute("checked", enterFS);
 
+#ifdef XP_MACOSX
+    // Make sure the menu items are adjusted.
+    document.getElementById("enterFullScreenItem").hidden = enterFS;
+    document.getElementById("exitFullScreenItem").hidden = !enterFS;
+#endif
+
     // On OS X Lion we don't want to hide toolbars when entering fullscreen, unless
     // we're entering DOM fullscreen, in which case we should hide the toolbars.
     // If we're leaving fullscreen, then we'll go through the exit code below to
     // make sure toolbars are made visible in the case of DOM fullscreen.
     if (enterFS && this.useLionFullScreen) {
       if (document.mozFullScreen)
         this.showXULChrome("toolbar", false);
       return;
--- a/browser/base/content/browser.xul
+++ b/browser/base/content/browser.xul
@@ -1121,68 +1121,44 @@
                      tooltiptext="&addonBarCloseButton.tooltip;"
                      oncommand="setToolbarVisibility(this.parentNode, false);"/>
       <statusbar id="status-bar" ordinal="1000"/>
     </toolbar>
   </vbox>
 
 #ifndef XP_UNIX
   <svg:svg height="0">
-    <svg:mask id="winstripe-keyhole-forward-mask" maskContentUnits="objectBoundingBox">
-      <svg:rect x="0" y="0" width="1" height="1" fill="white"/>
-      <svg:circle cx="-0.34" cy="0.5" r="0.61"/>
-    </svg:mask>
-    <svg:mask id="winstripe-urlbar-back-button-mask" maskContentUnits="userSpaceOnUse">
-      <svg:rect x="0" y="0" width="10000" height="50" fill="white"/>
-      <svg:circle cx="-11" cy="18" r="15"/>
-    </svg:mask>
+    <svg:clipPath id="winstripe-keyhole-forward-clip-path" clipPathUnits="objectBoundingBox">
+      <svg:path d="M 0,0 C 0.16,0.11 0.28,0.29 0.28,0.5 0.28,0.71 0.16,0.89 0,1 L 1,1 1,0 0,0 z"/>
+    </svg:clipPath>
+    <svg:clipPath id="winstripe-urlbar-back-button-clip-path" clipPathUnits="userSpaceOnUse">
+      <svg:path d="M 0,0 0,7.8 C 2.5,11 4,14 4,18 4,22 2.5,25 0,28 l 0,22 10000,0 0,-50 L 0,0 z"/>
+    </svg:clipPath>
   </svg:svg>
 #endif
 #ifdef XP_MACOSX
   <svg:svg height="0">
-    <svg:mask id="pinstripe-keyhole-forward-mask" maskContentUnits="objectBoundingBox">
-      <svg:rect x="0" y="0" width="1" height="1" fill="white"/>
-      <svg:circle cx="-0.41" cy="0.5" r="0.65"/>
-    </svg:mask>
-    <svg:mask id="pinstripe-urlbar-back-button-mask" maskContentUnits="userSpaceOnUse">
-      <svg:rect x="0" y="-5" width="10000" height="55" fill="white"/>
-      <svg:circle cx="-9" cy="11" r="15"/>
-    </svg:mask>
-    <svg:mask id="pinstripe-tab-ontop-left-curve-mask" maskContentUnits="userSpaceOnUse">
-      <svg:circle cx="9" cy="3" r="3" fill="white"/>
-      <svg:rect x="9" y="0" width="3" height="3" fill="white"/>
-      <svg:rect x="6" y="3" width="6" height="19" fill="white"/>
-      <svg:rect x="1" y="17" width="5" height="5" fill="white"/>
-      <svg:circle cx="1" cy="17" r="5"/>
-      <svg:rect x="0" y="22" width="12" height="1" fill="white"/>
-    </svg:mask>
-    <svg:mask id="pinstripe-tab-ontop-right-curve-mask" maskContentUnits="userSpaceOnUse">
-      <svg:circle cx="3" cy="3" r="3" fill="white"/>
-      <svg:rect x="0" y="0" width="3" height="3" fill="white"/>
-      <svg:rect x="0" y="3" width="6" height="19" fill="white"/>
-      <svg:rect x="6" y="17" width="5" height="5" fill="white"/>
-      <svg:circle cx="11" cy="17" r="5"/>
-      <svg:rect x="0" y="22" width="12" height="1" fill="white"/>
-    </svg:mask>
-    <svg:mask id="pinstripe-tab-onbottom-left-curve-mask" maskContentUnits="userSpaceOnUse">
-      <svg:circle cx="9" cy="20" r="3" fill="white"/>
-      <svg:rect x="9" y="20" width="3" height="3" fill="white"/>
-      <svg:rect x="6" y="1" width="6" height="19" fill="white"/>
-      <svg:rect x="1" y="1" width="5" height="5" fill="white"/>
-      <svg:circle cx="1" cy="6" r="5"/>
-      <svg:rect x="0" y="0" width="12" height="1" fill="white"/>
-    </svg:mask>
-    <svg:mask id="pinstripe-tab-onbottom-right-curve-mask" maskContentUnits="userSpaceOnUse">
-      <svg:circle cx="3" cy="20" r="3" fill="white"/>
-      <svg:rect x="0" y="20" width="3" height="3" fill="white"/>
-      <svg:rect x="0" y="1" width="6" height="19" fill="white"/>
-      <svg:rect x="6" y="1" width="5" height="5" fill="white"/>
-      <svg:circle cx="11" cy="6" r="5"/>
-      <svg:rect x="0" y="0" width="12" height="1" fill="white"/>
-    </svg:mask>
+    <svg:clipPath id="pinstripe-keyhole-forward-clip-path" clipPathUnits="objectBoundingBox">
+      <svg:path d="M 0,0 C 0.15,0.12 0.25,0.3 0.25,0.5 0.25,0.7 0.15,0.88 0,1 L 1,1 1,0 0,0 z"/>
+    </svg:clipPath>
+    <svg:clipPath id="pinstripe-urlbar-back-button-clip-path" clipPathUnits="userSpaceOnUse">
+      <svg:path d="m 0,-5 0,4.03 C 3.6,1.8 6,6.1 6,11 6,16 3.6,20 0,23 l 0,27 10000,0 0,-55 L 0,-5 z"/>
+    </svg:clipPath>
+    <svg:clipPath id="pinstripe-tab-ontop-left-curve-clip-path" clipPathUnits="userSpaceOnUse">
+      <svg:path d="M 9,0 C 7.3,0 6,1.3 6,3 l 0,14 c 0,3 -2.2,5 -5,5 l -1,0 0,1 12,0 0,-1 0,-19 0,-3 -3,0 z"/>
+    </svg:clipPath>
+    <svg:clipPath id="pinstripe-tab-ontop-right-curve-clip-path" clipPathUnits="userSpaceOnUse">
+      <svg:path d="m 0,0 0,3 0,19 0,1 12,0 0,-1 -1,0 C 8.2,22 6,20 6,17 L 6,3 C 6,1.3 4.7,0 3,0 L 0,0 z"/>
+    </svg:clipPath>
+    <svg:clipPath id="pinstripe-tab-onbottom-left-curve-clip-path" clipPathUnits="userSpaceOnUse">
+      <svg:path d="m 0,0 0,1 1,0 c 2.8,0 5,2.2 5,5 l 0,14 c 0,2 1.3,3 3,3 l 3,0 0,-3 L 12,1 12,0 0,0 z"/>
+    </svg:clipPath>
+    <svg:clipPath id="pinstripe-tab-onbottom-right-curve-clip-path" clipPathUnits="userSpaceOnUse">
+      <svg:path d="m 0,0 0,1 0,19 0,3 3,0 c 1.7,0 3,-1 3,-3 L 6,6 C 6,3.2 8.2,1 11,1 L 12,1 12,0 0,0 z"/>
+    </svg:clipPath>
   </svg:svg>
 #endif
 
 </vbox>
 # <iframe id="tab-view"> is dynamically appended as the 2nd child of #tab-view-deck.
 #     Introducing the iframe dynamically, as needed, was found to be better than
 #     starting with an empty iframe here in browser.xul from a Ts standpoint.
 </deck>
--- a/browser/base/content/tabbrowser.xml
+++ b/browser/base/content/tabbrowser.xml
@@ -625,17 +625,17 @@
                                         aFlags) {
               // OnLocationChange is called for both the top-level content
               // and the subframes.
               let topLevel = aWebProgress.DOMWindow == this.mBrowser.contentWindow;
 
               if (topLevel) {
                 // The document loaded correctly, clear the value if we should
                 if (this.mBrowser.userTypedClear > 0 ||
-                    (aRequest && !Components.isSuccessCode(aRequest.status)))
+                    (aFlags & Ci.nsIWebProgressListener.LOCATION_CHANGE_ERROR_PAGE))
                   this.mBrowser.userTypedValue = null;
 
                 // Clear out the missing plugins list since it's related to the
                 // previous location.
                 this.mBrowser.missingPlugins = null;
 
                 // Don't clear the favicon if this onLocationChange was
                 // triggered by a pushState or a replaceState.  See bug 550565.
--- a/browser/base/content/test/browser_sanitize-timespans.js
+++ b/browser/base/content/test/browser_sanitize-timespans.js
@@ -1,29 +1,34 @@
 // Bug 453440 - Test the timespan-based logic of the sanitizer code
 var now_uSec = Date.now() * 1000;
 
 const dm = Cc["@mozilla.org/download-manager;1"].getService(Ci.nsIDownloadManager);
 const bhist = Cc["@mozilla.org/browser/global-history;2"].getService(Ci.nsIBrowserHistory);
 const formhist = Cc["@mozilla.org/satchel/form-history;1"].getService(Ci.nsIFormHistory2);
 
+const kUsecPerMin = 60 * 1000000;
+
 let tempScope = {};
 Cc["@mozilla.org/moz/jssubscript-loader;1"].getService(Ci.mozIJSSubScriptLoader)
                                            .loadSubScript("chrome://browser/content/sanitize.js", tempScope);
 let Sanitizer = tempScope.Sanitizer;
 
 function test() {
-  
+  waitForExplicitFinish();
+
+  setupDownloads();
+  setupFormHistory();
+  setupHistory(onHistoryReady);
+}
+
+function onHistoryReady() {
   var hoursSinceMidnight = new Date().getHours();
   var minutesSinceMidnight = hoursSinceMidnight * 60 + new Date().getMinutes();
 
-  setupHistory();
-  setupFormHistory();
-  setupDownloads();
-  
   // Should test cookies here, but nsICookieManager/nsICookieService
   // doesn't let us fake creation times.  bug 463127
   
   let s = new Sanitizer();
   s.ignoreTimespan = false;
   s.prefDomain = "privacy.cpd.";
   var itemPrefs = gPrefService.getBranch(s.prefDomain);
   itemPrefs.setBoolPref("history", true);
@@ -266,47 +271,56 @@ function test() {
   s.sanitize();
 
   ok(!bhist.isVisited(makeURI("http://before-today.com")), "Pretend visit to before-today.com should now be deleted");
 
   ok(!formhist.nameExists("b4today"), "b4today form entry should be deleted");
 
   ok(!downloadExists(5555550), "Year old download should now be deleted");
 
+  finish();
 }
 
-function setupHistory() {
-  bhist.addPageWithDetails(makeURI("http://10minutes.com/"), "10 minutes ago", now_uSec - 10*60*1000000);
-  bhist.addPageWithDetails(makeURI("http://1hour.com/"), "Less than 1 hour ago", now_uSec - 45*60*1000000);
-  bhist.addPageWithDetails(makeURI("http://1hour10minutes.com/"), "1 hour 10 minutes ago", now_uSec - 70*60*1000000);
-  bhist.addPageWithDetails(makeURI("http://2hour.com/"), "Less than 2 hours ago", now_uSec - 90*60*1000000);
-  bhist.addPageWithDetails(makeURI("http://2hour10minutes.com/"), "2 hours 10 minutes ago", now_uSec - 130*60*1000000);
-  bhist.addPageWithDetails(makeURI("http://4hour.com/"), "Less than 4 hours ago", now_uSec - 180*60*1000000);
-  bhist.addPageWithDetails(makeURI("http://4hour10minutes.com/"), "4 hours 10 minutesago", now_uSec - 250*60*1000000);
-  
+function setupHistory(aCallback) {
+  let places = [];
+
+  function addPlace(aURI, aTitle, aVisitDate) {
+    places.push({
+      uri: aURI,
+      title: aTitle,
+      visits: [{
+        visitDate: aVisitDate,
+        transitionType: Ci.nsINavHistoryService.TRANSITION_LINK
+      }]
+    });
+  }
+
+  addPlace(makeURI("http://10minutes.com/"), "10 minutes ago", now_uSec - 10 * kUsecPerMin);
+  addPlace(makeURI("http://1hour.com/"), "Less than 1 hour ago", now_uSec - 45 * kUsecPerMin);
+  addPlace(makeURI("http://1hour10minutes.com/"), "1 hour 10 minutes ago", now_uSec - 70 * kUsecPerMin);
+  addPlace(makeURI("http://2hour.com/"), "Less than 2 hours ago", now_uSec - 90 * kUsecPerMin);
+  addPlace(makeURI("http://2hour10minutes.com/"), "2 hours 10 minutes ago", now_uSec - 130 * kUsecPerMin);
+  addPlace(makeURI("http://4hour.com/"), "Less than 4 hours ago", now_uSec - 180 * kUsecPerMin);
+  addPlace(makeURI("http://4hour10minutes.com/"), "4 hours 10 minutesago", now_uSec - 250 * kUsecPerMin);
+
   let today = new Date();
   today.setHours(0);
   today.setMinutes(0);
   today.setSeconds(1);
-  bhist.addPageWithDetails(makeURI("http://today.com/"), "Today", today.valueOf() * 1000);
-  
+  addPlace(makeURI("http://today.com/"), "Today", today.getTime() * 1000);
+
   let lastYear = new Date();
   lastYear.setFullYear(lastYear.getFullYear() - 1);
-  bhist.addPageWithDetails(makeURI("http://before-today.com/"), "Before Today", lastYear.valueOf() * 1000);
-  
-  // Confirm everything worked
-  ok(bhist.isVisited(makeURI("http://10minutes.com/")), "Pretend visit to 10minutes.com should exist");
-  ok(bhist.isVisited(makeURI("http://1hour.com")), "Pretend visit to 1hour.com should exist");
-  ok(bhist.isVisited(makeURI("http://1hour10minutes.com/")), "Pretend visit to 1hour10minutes.com should exist");
-  ok(bhist.isVisited(makeURI("http://2hour.com")), "Pretend visit to 2hour.com should exist");
-  ok(bhist.isVisited(makeURI("http://2hour10minutes.com/")), "Pretend visit to 2hour10minutes.com should exist");
-  ok(bhist.isVisited(makeURI("http://4hour.com")), "Pretend visit to 4hour.com should exist");
-  ok(bhist.isVisited(makeURI("http://4hour10minutes.com/")), "Pretend visit to 4hour10minutes.com should exist");
-  ok(bhist.isVisited(makeURI("http://today.com")), "Pretend visit to today.com should exist");
-  ok(bhist.isVisited(makeURI("http://before-today.com")), "Pretend visit to before-today.com should exist");
+  addPlace(makeURI("http://before-today.com/"), "Before Today", lastYear.getTime() * 1000);
+
+  PlacesUtils.asyncHistory.updatePlaces(places, {
+    handleError: function () ok(false, "Unexpected error in adding visit."),
+    handleResult: function () { },
+    handleCompletion: function () aCallback()
+  });
 }
 
 function setupFormHistory() {
   // Make sure we've got a clean DB to start with.
   formhist.removeAllEntries();
 
   // Add the entries we'll be testing.
   formhist.addEntry("10minutes", "10m");
@@ -316,49 +330,49 @@ function setupFormHistory() {
   formhist.addEntry("2hour10minutes", "2h10m");
   formhist.addEntry("4hour", "4h");
   formhist.addEntry("4hour10minutes", "4h10m");
   formhist.addEntry("today", "1d");
   formhist.addEntry("b4today", "1y");
 
   // Artifically age the entries to the proper vintage.
   let db = formhist.DBConnection;
-  let timestamp = now_uSec - 10*60*1000000;
+  let timestamp = now_uSec - 10 * kUsecPerMin;
   db.executeSimpleSQL("UPDATE moz_formhistory SET firstUsed = " +
                       timestamp +  " WHERE fieldname = '10minutes'");
-  timestamp = now_uSec - 45*60*1000000;
+  timestamp = now_uSec - 45 * kUsecPerMin;
   db.executeSimpleSQL("UPDATE moz_formhistory SET firstUsed = " +
                       timestamp +  " WHERE fieldname = '1hour'");
-  timestamp = now_uSec - 70*60*1000000;
+  timestamp = now_uSec - 70 * kUsecPerMin;
   db.executeSimpleSQL("UPDATE moz_formhistory SET firstUsed = " +
                       timestamp +  " WHERE fieldname = '1hour10minutes'");
-  timestamp = now_uSec - 90*60*1000000;
+  timestamp = now_uSec - 90 * kUsecPerMin;
   db.executeSimpleSQL("UPDATE moz_formhistory SET firstUsed = " +
                       timestamp +  " WHERE fieldname = '2hour'");
-  timestamp = now_uSec - 130*60*1000000;
+  timestamp = now_uSec - 130 * kUsecPerMin;
   db.executeSimpleSQL("UPDATE moz_formhistory SET firstUsed = " +
                       timestamp +  " WHERE fieldname = '2hour10minutes'");
-  timestamp = now_uSec - 180*60*1000000;
+  timestamp = now_uSec - 180 * kUsecPerMin;
   db.executeSimpleSQL("UPDATE moz_formhistory SET firstUsed = " +
                       timestamp +  " WHERE fieldname = '4hour'");
-  timestamp = now_uSec - 250*60*1000000;
+  timestamp = now_uSec - 250 * kUsecPerMin;
   db.executeSimpleSQL("UPDATE moz_formhistory SET firstUsed = " +
                       timestamp +  " WHERE fieldname = '4hour10minutes'");
 
   let today = new Date();
   today.setHours(0);
   today.setMinutes(0);
   today.setSeconds(1);
-  timestamp = today.valueOf() * 1000;
+  timestamp = today.getTime() * 1000;
   db.executeSimpleSQL("UPDATE moz_formhistory SET firstUsed = " +
                       timestamp +  " WHERE fieldname = 'today'");
 
   let lastYear = new Date();
   lastYear.setFullYear(lastYear.getFullYear() - 1);
-  timestamp = lastYear.valueOf() * 1000;
+  timestamp = lastYear.getTime() * 1000;
   db.executeSimpleSQL("UPDATE moz_formhistory SET firstUsed = " +
                       timestamp +  " WHERE fieldname = 'b4today'");
 
   // Sanity check.
   ok(formhist.nameExists("10minutes"), "Checking for 10minutes form history entry creation");
   ok(formhist.nameExists("1hour"), "Checking for 1hour form history entry creation");
   ok(formhist.nameExists("1hour10minutes"), "Checking for 1hour10minutes form history entry creation");
   ok(formhist.nameExists("2hour"), "Checking for 2hour form history entry creation");
@@ -372,18 +386,18 @@ function setupFormHistory() {
 function setupDownloads() {
 
   // Add 10-minutes download to DB
   let data = {
     id:   "5555555",
     name: "fakefile-10-minutes",
     source: "https://bugzilla.mozilla.org/show_bug.cgi?id=480169",
     target: "fakefile-10-minutes",
-    startTime: now_uSec - 10*60*1000000,  // 10 minutes ago, in uSec
-    endTime: now_uSec - 11*60*1000000, // 1 minute later
+    startTime: now_uSec - 10 * kUsecPerMin, // 10 minutes ago, in uSec
+    endTime: now_uSec - 11 * kUsecPerMin, // 1 minute later
     state: Ci.nsIDownloadManager.DOWNLOAD_FINISHED,
     currBytes: 0, maxBytes: -1, preferredAction: 0, autoResume: 0
   };
 
   let db = dm.DBConnection;
   let stmt = db.createStatement(
     "INSERT INTO moz_downloads (id, name, source, target, startTime, endTime, " +
       "state, currBytes, maxBytes, preferredAction, autoResume) " +
@@ -399,18 +413,18 @@ function setupDownloads() {
   }
   
   // Add within-1-hour download to DB
   data = {
     id:   "5555551",
     name: "fakefile-1-hour",
     source: "https://bugzilla.mozilla.org/show_bug.cgi?id=453440",
     target: "fakefile-1-hour",
-    startTime: now_uSec - 45*60*1000000,  // 45 minutes ago, in uSec
-    endTime: now_uSec - 44*60*1000000, // 1 minute later
+    startTime: now_uSec - 45 * kUsecPerMin, // 45 minutes ago, in uSec
+    endTime: now_uSec - 44 * kUsecPerMin, // 1 minute later
     state: Ci.nsIDownloadManager.DOWNLOAD_FINISHED,
     currBytes: 0, maxBytes: -1, preferredAction: 0, autoResume: 0
   };
 
   try {
     for (let prop in data)
       stmt.params[prop] = data[prop];
     stmt.execute();
@@ -420,18 +434,18 @@ function setupDownloads() {
   }
   
   // Add 1-hour-10-minutes download to DB
   data = {
     id:   "5555556",
     name: "fakefile-1-hour-10-minutes",
     source: "https://bugzilla.mozilla.org/show_bug.cgi?id=480169",
     target: "fakefile-1-hour-10-minutes",
-    startTime: now_uSec - 70*60*1000000,  // 70 minutes ago, in uSec
-    endTime: now_uSec - 71*60*1000000, // 1 minute later
+    startTime: now_uSec - 70 * kUsecPerMin, // 70 minutes ago, in uSec
+    endTime: now_uSec - 71 * kUsecPerMin, // 1 minute later
     state: Ci.nsIDownloadManager.DOWNLOAD_FINISHED,
     currBytes: 0, maxBytes: -1, preferredAction: 0, autoResume: 0
   };
 
   try {
     for (let prop in data)
       stmt.params[prop] = data[prop];
     stmt.execute();
@@ -441,18 +455,18 @@ function setupDownloads() {
   }
 
   // Add within-2-hour download  
   data = {
     id:   "5555552",
     name: "fakefile-2-hour",
     source: "https://bugzilla.mozilla.org/show_bug.cgi?id=453440",
     target: "fakefile-2-hour",
-    startTime: now_uSec - 90*60*1000000,  // 90 minutes ago, in uSec
-    endTime: now_uSec - 89*60*1000000, // 1 minute later
+    startTime: now_uSec - 90 * kUsecPerMin, // 90 minutes ago, in uSec
+    endTime: now_uSec - 89 * kUsecPerMin, // 1 minute later
     state: Ci.nsIDownloadManager.DOWNLOAD_FINISHED,
     currBytes: 0, maxBytes: -1, preferredAction: 0, autoResume: 0
   };
 
   try {
     for (let prop in data)
       stmt.params[prop] = data[prop];
     stmt.execute();
@@ -462,18 +476,18 @@ function setupDownloads() {
   }
   
   // Add 2-hour-10-minutes download  
   data = {
     id:   "5555557",
     name: "fakefile-2-hour-10-minutes",
     source: "https://bugzilla.mozilla.org/show_bug.cgi?id=480169",
     target: "fakefile-2-hour-10-minutes",
-    startTime: now_uSec - 130*60*1000000,  // 130 minutes ago, in uSec
-    endTime: now_uSec - 131*60*1000000, // 1 minute later
+    startTime: now_uSec - 130 * kUsecPerMin, // 130 minutes ago, in uSec
+    endTime: now_uSec - 131 * kUsecPerMin, // 1 minute later
     state: Ci.nsIDownloadManager.DOWNLOAD_FINISHED,
     currBytes: 0, maxBytes: -1, preferredAction: 0, autoResume: 0
   };
 
   try {
     for (let prop in data)
       stmt.params[prop] = data[prop];
     stmt.execute();
@@ -483,18 +497,18 @@ function setupDownloads() {
   }
 
   // Add within-4-hour download
   data = {
     id:   "5555553",
     name: "fakefile-4-hour",
     source: "https://bugzilla.mozilla.org/show_bug.cgi?id=453440",
     target: "fakefile-4-hour",
-    startTime: now_uSec - 180*60*1000000,  // 180 minutes ago, in uSec
-    endTime: now_uSec - 179*60*1000000, // 1 minute later
+    startTime: now_uSec - 180 * kUsecPerMin, // 180 minutes ago, in uSec
+    endTime: now_uSec - 179 * kUsecPerMin, // 1 minute later
     state: Ci.nsIDownloadManager.DOWNLOAD_FINISHED,
     currBytes: 0, maxBytes: -1, preferredAction: 0, autoResume: 0
   };
   
   try {
     for (let prop in data)
       stmt.params[prop] = data[prop];
     stmt.execute();
@@ -504,18 +518,18 @@ function setupDownloads() {
   }
   
   // Add 4-hour-10-minutes download
   data = {
     id:   "5555558",
     name: "fakefile-4-hour-10-minutes",
     source: "https://bugzilla.mozilla.org/show_bug.cgi?id=480169",
     target: "fakefile-4-hour-10-minutes",
-    startTime: now_uSec - 250*60*1000000,  // 250 minutes ago, in uSec
-    endTime: now_uSec - 251*60*1000000, // 1 minute later
+    startTime: now_uSec - 250 * kUsecPerMin, // 250 minutes ago, in uSec
+    endTime: now_uSec - 251 * kUsecPerMin, // 1 minute later
     state: Ci.nsIDownloadManager.DOWNLOAD_FINISHED,
     currBytes: 0, maxBytes: -1, preferredAction: 0, autoResume: 0
   };
   
   try {
     for (let prop in data)
       stmt.params[prop] = data[prop];
     stmt.execute();
@@ -530,18 +544,18 @@ function setupDownloads() {
   today.setMinutes(0);
   today.setSeconds(1);
   
   data = {
     id:   "5555554",
     name: "fakefile-today",
     source: "https://bugzilla.mozilla.org/show_bug.cgi?id=453440",
     target: "fakefile-today",
-    startTime: today.valueOf() * 1000,  // 12:00:30am this morning, in uSec
-    endTime: (today.valueOf() + 1000) * 1000, // 1 second later
+    startTime: today.getTime() * 1000,  // 12:00:30am this morning, in uSec
+    endTime: (today.getTime() + 1000) * 1000, // 1 second later
     state: Ci.nsIDownloadManager.DOWNLOAD_FINISHED,
     currBytes: 0, maxBytes: -1, preferredAction: 0, autoResume: 0
   };
   
   try {
     for (let prop in data)
       stmt.params[prop] = data[prop];
     stmt.execute();
@@ -553,18 +567,18 @@ function setupDownloads() {
   // Add "before today" download
   let lastYear = new Date();
   lastYear.setFullYear(lastYear.getFullYear() - 1);
   data = {
     id:   "5555550",
     name: "fakefile-old",
     source: "https://bugzilla.mozilla.org/show_bug.cgi?id=453440",
     target: "fakefile-old",
-    startTime: lastYear.valueOf() * 1000,  // 1 year ago, in uSec
-    endTime: (lastYear.valueOf() + 1000) * 1000, // 1 second later
+    startTime: lastYear.getTime() * 1000, // 1 year ago, in uSec
+    endTime: (lastYear.getTime() + 1000) * 1000, // 1 second later
     state: Ci.nsIDownloadManager.DOWNLOAD_FINISHED,
     currBytes: 0, maxBytes: -1, preferredAction: 0, autoResume: 0
   };
   
   try {
     for (let prop in data)
       stmt.params[prop] = data[prop];
     stmt.execute();
--- a/browser/base/content/test/browser_sanitizeDialog.js
+++ b/browser/base/content/test/browser_sanitizeDialog.js
@@ -55,16 +55,18 @@ Cc["@mozilla.org/moz/jssubscript-loader;
                                            .loadSubScript("chrome://browser/content/sanitize.js", tempScope);
 let Sanitizer = tempScope.Sanitizer;
 
 const dm = Cc["@mozilla.org/download-manager;1"].
            getService(Ci.nsIDownloadManager);
 const formhist = Cc["@mozilla.org/satchel/form-history;1"].
                  getService(Ci.nsIFormHistory2);
 
+const kUsecPerMin = 60 * 1000000;
+
 // Add tests here.  Each is a function that's called by doNextTest().
 var gAllTests = [
 
   /**
    * Initializes the dialog to its default state.
    */
   function () {
     let wh = new WindowHelper();
@@ -826,18 +828,18 @@ WindowHelper.prototype = {
  */
 function addDownloadWithMinutesAgo(aMinutesAgo) {
   let name = "fakefile-" + aMinutesAgo + "-minutes-ago";
   let data = {
     id:        gDownloadId,
     name:      name,
     source:   "https://bugzilla.mozilla.org/show_bug.cgi?id=480169",
     target:    name,
-    startTime: now_uSec - (aMinutesAgo * 60 * 1000000),
-    endTime:   now_uSec - ((aMinutesAgo + 1) *60 * 1000000),
+    startTime: now_uSec - (aMinutesAgo * kUsecPerMin),
+    endTime:   now_uSec - ((aMinutesAgo + 1) * kUsecPerMin),
     state:     Ci.nsIDownloadManager.DOWNLOAD_FINISHED,
     currBytes: 0, maxBytes: -1, preferredAction: 0, autoResume: 0
   };
 
   let db = dm.DBConnection;
   let stmt = db.createStatement(
     "INSERT INTO moz_downloads (id, name, source, target, startTime, endTime, " +
       "state, currBytes, maxBytes, preferredAction, autoResume) " +
@@ -867,37 +869,39 @@ function addDownloadWithMinutesAgo(aMinu
  *        The entry will be added this many minutes ago
  */
 function addFormEntryWithMinutesAgo(aMinutesAgo) {
   let name = aMinutesAgo + "-minutes-ago";
   formhist.addEntry(name, "dummy");
 
   // Artifically age the entry to the proper vintage.
   let db = formhist.DBConnection;
-  let timestamp = now_uSec - (aMinutesAgo * 60 * 1000000);
+  let timestamp = now_uSec - (aMinutesAgo * kUsecPerMin);
   db.executeSimpleSQL("UPDATE moz_formhistory SET firstUsed = " +
                       timestamp +  " WHERE fieldname = '" + name + "'");
 
   is(formhist.nameExists(name), true,
      "Sanity check: form entry " + name + " should exist after creating it");
   return name;
 }
 
 /**
  * Adds a history visit to history.
  *
  * @param aMinutesAgo
  *        The visit will be visited this many minutes ago
  */
 function addHistoryWithMinutesAgo(aMinutesAgo) {
   let pURI = makeURI("http://" + aMinutesAgo + "-minutes-ago.com/");
-  PlacesUtils.bhistory
-             .addPageWithDetails(pURI,
-                                 aMinutesAgo + " minutes ago",
-                                 now_uSec - (aMinutesAgo * 60 * 1000 * 1000));
+  PlacesUtils.history.addVisit(pURI,
+                               now_uSec - aMinutesAgo * kUsecPerMin,
+                               null,
+                               Ci.nsINavHistoryService.TRANSITION_LINK,
+                               false,
+                               0);
   is(PlacesUtils.bhistory.isVisited(pURI), true,
      "Sanity check: history visit " + pURI.spec +
      " should exist after creating it");
   return pURI;
 }
 
 /**
  * Removes all history visits, downloads, and form entries.
--- a/browser/base/content/test/browser_sanitizeDialog_treeView.js
+++ b/browser/base/content/test/browser_sanitizeDialog_treeView.js
@@ -496,20 +496,22 @@ function addFormEntryWithMinutesAgo(aMin
 /**
  * Adds a history visit to history.
  *
  * @param aMinutesAgo
  *        The visit will be visited this many minutes ago
  */
 function addHistoryWithMinutesAgo(aMinutesAgo) {
   let pURI = makeURI("http://" + aMinutesAgo + "-minutes-ago.com/");
-  PlacesUtils.bhistory
-             .addPageWithDetails(pURI,
-                                 aMinutesAgo + " minutes ago",
-                                 now_uSec - (aMinutesAgo * 60 * 1000 * 1000));
+  PlacesUtils.history.addVisit(pURI,
+                               now_uSec - (aMinutesAgo * 60 * 1000 * 1000),
+                               null,
+                               Ci.nsINavHistoryService.TRANSITION_LINK,
+                               false,
+                               0);
   is(PlacesUtils.bhistory.isVisited(pURI), true,
      "Sanity check: history visit " + pURI.spec +
      " should exist after creating it");
   return pURI;
 }
 
 /**
  * Removes all history visits, downloads, and form entries.
--- a/browser/base/content/test/newtab/browser_newtab_bug722273.js
+++ b/browser/base/content/test/newtab/browser_newtab_bug722273.js
@@ -12,31 +12,45 @@ Cc["@mozilla.org/moz/jssubscript-loader;
 
 let {NewTabUtils, Sanitizer} = tmp;
 
 let bhist = Cc["@mozilla.org/browser/global-history;2"]
   .getService(Ci.nsIBrowserHistory);
 
 function runTests() {
   clearHistory();
-  fillHistory();
+  yield fillHistory();
   yield addNewTabPageTab();
 
   is(getCell(0).site.url, URL, "first site is our fake site");
 
   whenPagesUpdated();
   yield clearHistory();
 
   ok(!getCell(0).site, "the fake site is gone");
 }
 
 function fillHistory() {
-  let uri = makeURI(URL);
-  for (let i = 59; i > 0; i--)
-    bhist.addPageWithDetails(uri, "fake site", NOW - i * 60 * 1000000);
+  let visits = [];
+  for (let i = 59; i > 0; i--) {
+    visits.push({
+      visitDate: NOW - i * 60 * 1000000,
+      transitionType: Ci.nsINavHistoryService.TRANSITION_LINK
+    });
+  }
+  let place = {
+    uri: makeURI(URL),
+    title: "fake site",
+    visits: visits
+  };
+  PlacesUtils.asyncHistory.updatePlaces(place, {
+    handleError: function () do_throw("Unexpected error in adding visit."),
+    handleResult: function () { },
+    handleCompletion: function () TestRunner.next()
+  });
 }
 
 function clearHistory() {
   let s = new Sanitizer();
   s.prefDomain = "privacy.cpd.";
 
   let prefs = gPrefService.getBranch(s.prefDomain);
   prefs.setBoolPref("history", true);
--- a/browser/components/privatebrowsing/test/unit/do_test_placesTitleNoUpdate.js
+++ b/browser/components/privatebrowsing/test/unit/do_test_placesTitleNoUpdate.js
@@ -45,40 +45,76 @@ function do_test()
   let pb = Cc[PRIVATEBROWSING_CONTRACT_ID].
            getService(Ci.nsIPrivateBrowsingService);
 
   const TEST_URI = uri("http://mozilla.com/privatebrowsing");
   const TITLE_1 = "Title 1";
   const TITLE_2 = "Title 2";
 
   do_test_pending();
-  waitForClearHistory(function() {
-    PlacesUtils.bhistory.addPageWithDetails(TEST_URI, TITLE_1, Date.now() * 1000);
+  waitForClearHistory(function () {
+    let place = {
+      uri: TEST_URI,
+      title: TITLE_1,
+      visits: [{
+        visitDate: Date.now() * 1000,
+        transitionType: Ci.nsINavHistoryService.TRANSITION_LINK
+      }]
+    };
+    PlacesUtils.asyncHistory.updatePlaces(place, {
+      handleError: function () do_throw("Unexpected error in adding visit."),
+      handleResult: function () { },
+      handleCompletion: function () afterAddFirstVisit()
+    });
+  });
+
+  function afterAddFirstVisit()
+  {
     do_check_eq(PlacesUtils.history.getPageTitle(TEST_URI), TITLE_1);
 
     pb.privateBrowsingEnabled = true;
 
-    PlacesUtils.bhistory.addPageWithDetails(TEST_URI, TITLE_2, Date.now() * 2000);
+    let place = {
+      uri: TEST_URI,
+      title: TITLE_2,
+      visits: [{
+        visitDate: Date.now() * 2000,
+        transitionType: Ci.nsINavHistoryService.TRANSITION_LINK
+      }]
+    };
+
+    PlacesUtils.asyncHistory.updatePlaces(place, {
+      handleError: function (aResultCode) {
+        // We expect this error in Private Browsing mode.
+        do_check_eq(aResultCode, Cr.NS_ERROR_ILLEGAL_VALUE);
+      },
+      handleResult: function () do_throw("Unexpected success adding visit."),
+      handleCompletion: function () afterAddSecondVisit()
+    });
+  }
+
+  function afterAddSecondVisit()
+  {
     do_check_eq(PlacesUtils.history.getPageTitle(TEST_URI), TITLE_1);
 
     pb.privateBrowsingEnabled = false;
 
     do_check_eq(PlacesUtils.history.getPageTitle(TEST_URI), TITLE_1);
 
     pb.privateBrowsingEnabled = true;
 
     PlacesUtils.bhistory.setPageTitle(TEST_URI, TITLE_2);
     do_check_eq(PlacesUtils.history.getPageTitle(TEST_URI), TITLE_1);
 
     pb.privateBrowsingEnabled = false;
 
     do_check_eq(PlacesUtils.history.getPageTitle(TEST_URI), TITLE_1);
 
     waitForClearHistory(do_test_finished);
-  });
+  }
 }
 
 // Support running tests on both the service itself and its wrapper
 function run_test() {
   run_test_on_all_services();
 }
 
 function waitForClearHistory(aCallback) {
--- a/browser/components/privatebrowsing/test/unit/do_test_removeDataFromDomain.js
+++ b/browser/components/privatebrowsing/test/unit/do_test_removeDataFromDomain.js
@@ -38,17 +38,19 @@
  * ***** END LICENSE BLOCK ***** */
 
 /**
  * Test added with bug 460086 to test the behavior of the new API that was added
  * to remove all traces of visiting a site.
  */
 
 ////////////////////////////////////////////////////////////////////////////////
-//// Constants
+//// Globals
+
+Cu.import("resource://gre/modules/PlacesUtils.jsm");
 
 let pb = Cc[PRIVATEBROWSING_CONTRACT_ID].
          getService(Ci.nsIPrivateBrowsingService);
 
 const COOKIE_EXPIRY = Math.round(Date.now() / 1000) + 60;
 const COOKIE_NAME = "testcookie";
 const COOKIE_PATH = "/";
 
@@ -83,36 +85,34 @@ function uri(aURIString)
  * Adds a visit to history.
  *
  * @param aURI
  *        The URI to add.
  */
 function add_visit(aURI)
 {
   check_visited(aURI, false);
-  let bh = Cc["@mozilla.org/browser/global-history;2"].
-           getService(Ci.nsIBrowserHistory);
-  bh.addPageWithDetails(aURI, aURI.spec, Date.now() * 1000);
+  PlacesUtils.history.addVisit(aURI, Date.now() * 1000, null,
+                               Ci.nsINavHistoryService.TRANSITION_LINK, false,
+                               0);
   check_visited(aURI, true);
 }
 
 /**
  * Checks to ensure a URI string is visited or not.
  *
  * @param aURI
  *        The URI to check.
  * @param aIsVisited
  *        True if the URI should be visited, false otherwise.
  */
 function check_visited(aURI, aIsVisited)
 {
-  let gh = Cc["@mozilla.org/browser/global-history;2"].
-           getService(Ci.nsIGlobalHistory2);
   let checker = aIsVisited ? do_check_true : do_check_false;
-  checker(gh.isVisited(aURI));
+  checker(PlacesUtils.ghistory2.isVisited(aURI));
 }
 
 /**
  * Add a cookie to the cookie service.
  *
  * @param aDomain
  */
 function add_cookie(aDomain)
@@ -357,19 +357,17 @@ function test_history_cleared_with_subdo
 function test_history_not_cleared_with_uri_contains_domain()
 {
   const TEST_URI = uri("http://ilovemozilla.org/foo");
   add_visit(TEST_URI);
   pb.removeDataFromDomain("mozilla.org");
   check_visited(TEST_URI, true);
 
   // Clear history since we left something there from this test.
-  let bh = Cc["@mozilla.org/browser/global-history;2"].
-           getService(Ci.nsIBrowserHistory);
-  bh.removeAllPages();
+  PlacesUtils.bhistory.removeAllPages();
 }
 
 // Cookie Service
 function test_cookie_cleared_with_direct_match()
 {
   const TEST_DOMAIN = "mozilla.org";
   add_cookie(TEST_DOMAIN);
   pb.removeDataFromDomain("mozilla.org");
deleted file mode 100644
--- a/browser/components/tabview/test/browser_tabview_storage_policy.js
+++ /dev/null
@@ -1,181 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
-   http://creativecommons.org/publicdomain/zero/1.0/ */
-
-const PREF_DISK_CACHE_SSL = "browser.cache.disk_cache_ssl";
-
-let pb = Cc["@mozilla.org/privatebrowsing;1"].
-         getService(Ci.nsIPrivateBrowsingService);
-
-let contentWindow;
-let newTab;
-
-function test() {
-  waitForExplicitFinish();
-
-  newTab = gBrowser.addTab();
-
-  HttpRequestObserver.register();
-
-  registerCleanupFunction(function () {
-    HttpRequestObserver.unregister();
-    if (gBrowser.tabs[1])
-      gBrowser.removeTab(gBrowser.tabs[1]);
-    hideTabView();
-
-    Services.prefs.clearUserPref(PREF_DISK_CACHE_SSL);
-    pb.privateBrowsingEnabled = false;
-  });
-
-  showTabView(function() {
-    contentWindow = TabView.getContentWindow();
-    test1();
-  });
-}
-
-
-function test1() {
-  // page with cache-control: no-store, should not save thumbnail
-  HttpRequestObserver.cacheControlValue = "no-store";
-
-  whenStorageDenied(newTab, function () {
-    let tabItem = newTab._tabViewTabItem;
-
-    ok(!contentWindow.StoragePolicy.canStoreThumbnailForTab(newTab), 
-       "Should not save the thumbnail for tab");
-
-    whenDeniedToSaveImageData(tabItem, test2);
-    tabItem.saveThumbnail({synchronously: true});
-    HttpRequestObserver.cacheControlValue = null;
-  });
-
-  newTab.linkedBrowser.loadURI("http://www.example.com/browser/browser/components/tabview/test/dummy_page.html");
-}
-
-function test2() {
-  // page with cache-control: private, should save thumbnail
-  HttpRequestObserver.cacheControlValue = "private";
-
-  newTab.linkedBrowser.loadURI("http://www.example.com/");
-  afterAllTabsLoaded(function() {
-    let tabItem = newTab._tabViewTabItem;
-
-    ok(contentWindow.StoragePolicy.canStoreThumbnailForTab(newTab), 
-       "Should save the thumbnail for tab");
-
-    whenSavedCachedImageData(tabItem, test3);
-    tabItem.saveThumbnail({synchronously: true});
-  });
-}
-
-function test3() {
-  // page with cache-control: private with https caching enabled, should save thumbnail
-  HttpRequestObserver.cacheControlValue = "private";
-
-  Services.prefs.setBoolPref(PREF_DISK_CACHE_SSL, true);
-
-  newTab.linkedBrowser.loadURI("https://example.com/browser/browser/components/tabview/test/dummy_page.html");
-  afterAllTabsLoaded(function() {
-    let tabItem = newTab._tabViewTabItem;
-
-    ok(contentWindow.StoragePolicy.canStoreThumbnailForTab(newTab),
-       "Should save the thumbnail for tab");
-
-    whenSavedCachedImageData(tabItem, test4);
-    tabItem.saveThumbnail({synchronously: true});
-  });
-}
-
-function test4() {
-  // page with cache-control: public with https caching disabled, should save thumbnail
-  HttpRequestObserver.cacheControlValue = "public";
-
-  Services.prefs.setBoolPref(PREF_DISK_CACHE_SSL, false);
-
-  newTab.linkedBrowser.loadURI("https://example.com/browser/browser/components/tabview/test/");
-  afterAllTabsLoaded(function() {
-    let tabItem = newTab._tabViewTabItem;
-
-    ok(contentWindow.StoragePolicy.canStoreThumbnailForTab(newTab),
-       "Should save the thumbnail for tab");
-
-    whenSavedCachedImageData(tabItem, test5);
-    tabItem.saveThumbnail({synchronously: true});
-  });
-}
-
-function test5() {
-  // page with cache-control: private with https caching disabled, should not save thumbnail
-  HttpRequestObserver.cacheControlValue = "private";
-
-  whenStorageDenied(newTab, function () {
-    let tabItem = newTab._tabViewTabItem;
-
-    ok(!contentWindow.StoragePolicy.canStoreThumbnailForTab(newTab),
-       "Should not save the thumbnail for tab");
-
-    whenDeniedToSaveImageData(tabItem, function () {
-      gBrowser.removeTab(newTab);
-      test6();
-    });
-
-    tabItem.saveThumbnail({synchronously: true});
-  });
-
-  newTab.linkedBrowser.loadURI("https://example.com/");
-}
-
-// ensure that no thumbnails are saved while in private browsing mode
-function test6() {
-  HttpRequestObserver.cacheControlValue = "public";
-
-  togglePrivateBrowsing(function () {
-    let tab = gBrowser.tabs[0];
-
-    ok(!contentWindow.StoragePolicy.canStoreThumbnailForTab(tab),
-       "Should not save the thumbnail for tab");
-
-    togglePrivateBrowsing(finish);
-  });
-}
-
-let HttpRequestObserver = {
-  cacheControlValue: null,
-
-  observe: function(subject, topic, data) {
-    if (topic == "http-on-examine-response" && this.cacheControlValue) {
-      let httpChannel = subject.QueryInterface(Ci.nsIHttpChannel);
-      httpChannel.setResponseHeader("Cache-Control", this.cacheControlValue, false);
-    }
-  },
-
-  register: function() {
-    Services.obs.addObserver(this, "http-on-examine-response", false);
-  },
-
-  unregister: function() {
-    Services.obs.removeObserver(this, "http-on-examine-response");
-  }
-};
-
-function whenSavedCachedImageData(tabItem, callback) {
-  tabItem.addSubscriber("savedCachedImageData", function onSaved() {
-    tabItem.removeSubscriber("savedCachedImageData", onSaved);
-    callback();
-  });
-}
-
-function whenDeniedToSaveImageData(tabItem, callback) {
-  tabItem.addSubscriber("deniedToSaveImageData", function onDenied() {
-    tabItem.removeSubscriber("deniedToSaveImageData", onDenied);
-    callback();
-  });
-}
-
-function whenStorageDenied(tab, callback) {
-  let mm = tab.linkedBrowser.messageManager;
-
-  mm.addMessageListener("Panorama:StoragePolicy:denied", function onDenied() {
-    mm.removeMessageListener("Panorama:StoragePolicy:denied", onDenied);
-    executeSoon(callback);
-  });
-}
--- a/browser/components/thumbnails/PageThumbs.jsm
+++ b/browser/components/thumbnails/PageThumbs.jsm
@@ -240,24 +240,26 @@ let PageThumbs = {
     }
     catch (e) {
       return true;
     }
   },
 };
 
 let PageThumbsStorage = {
-  getFileForURL: function Storage_getFileForURL(aURL) {
+  getFileForURL: function Storage_getFileForURL(aURL, aOptions) {
     let hash = this._calculateMD5Hash(aURL);
-    let parts = [THUMBNAIL_DIRECTORY, hash[0], hash[1], hash.slice(2) + ".png"];
-    return FileUtils.getFile("ProfD", parts);
+    let parts = [THUMBNAIL_DIRECTORY, hash[0], hash[1]];
+    let file = FileUtils.getDir("ProfD", parts, aOptions && aOptions.createPath);
+    file.append(hash.slice(2) + ".png");
+    return file;
   },
 
   write: function Storage_write(aURL, aDataStream, aCallback) {
-    let file = this.getFileForURL(aURL);
+    let file = this.getFileForURL(aURL, {createPath: true});
     let fos = FileUtils.openSafeFileOutputStream(file);
 
     NetUtil.asyncCopy(aDataStream, fos, function (aResult) {
       FileUtils.closeSafeFileOutputStream(fos);
       aCallback(Components.isSuccessCode(aResult));
     });
   },
 
--- a/browser/components/thumbnails/test/Makefile.in
+++ b/browser/components/thumbnails/test/Makefile.in
@@ -11,15 +11,16 @@ relativesrcdir  = browser/components/thu
 include $(DEPTH)/config/autoconf.mk
 include $(topsrcdir)/config/rules.mk
 
 _BROWSER_FILES = \
 	browser_thumbnails_capture.js \
 	browser_thumbnails_redirect.js \
 	browser_thumbnails_storage.js \
 	browser_thumbnails_bug726727.js \
+	browser_thumbnails_bug753755.js \
 	head.js \
 	background_red.html \
 	background_red_redirect.sjs \
 	$(NULL)
 
 libs::	$(_BROWSER_FILES)
 	$(INSTALL) $(foreach f,$^,"$f") $(DEPTH)/_tests/testing/mochitest/browser/$(relativesrcdir)
new file mode 100644
--- /dev/null
+++ b/browser/components/thumbnails/test/browser_thumbnails_bug753755.js
@@ -0,0 +1,15 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+/**
+ * Make sure that PageThumbsStorage.getFileForURL(url) doesn't implicitly
+ * create the file's parent path.
+ */
+function runTests() {
+  let url = "http://non.existant.url/";
+  let file = PageThumbsStorage.getFileForURL(url);
+  ok(!file.exists() && !file.parent.exists(), "file and path don't exist");
+
+  let file = PageThumbsStorage.getFileForURL(url, {createPath: true});
+  ok(!file.exists() && file.parent.exists(), "path exists, file doesn't");
+}
--- a/browser/components/thumbnails/test/browser_thumbnails_storage.js
+++ b/browser/components/thumbnails/test/browser_thumbnails_storage.js
@@ -13,17 +13,17 @@ XPCOMUtils.defineLazyGetter(this, "Sanit
 });
 
 /**
  * These tests ensure that the thumbnail storage is working as intended.
  * Newly captured thumbnails should be saved as files and they should as well
  * be removed when the user sanitizes their history.
  */
 function runTests() {
-  clearHistory();
+  yield clearHistory();
 
   // create a thumbnail
   yield addTab(URL);
   yield whenFileExists();
   gBrowser.removeTab(gBrowser.selectedTab);
 
   // clear all browser history
   yield clearHistory();
@@ -67,17 +67,17 @@ function clearHistory(aUseRange) {
     s.range = [usec - 10 * 60 * 1000 * 1000, usec];
   }
 
   s.sanitize();
   s.range = null;
 
   executeSoon(function () {
     if (PageThumbsStorage.getFileForURL(URL).exists())
-      clearHistory(aFile, aUseRange);
+      clearHistory(aUseRange);
     else
       next();
   });
 }
 
 function whenFileExists() {
   let callback = whenFileExists;
 
--- a/browser/components/thumbnails/test/head.js
+++ b/browser/components/thumbnails/test/head.js
@@ -24,19 +24,22 @@ function test() {
  * The test runner that controls the execution flow of our tests.
  */
 let TestRunner = {
   /**
    * Starts the test runner.
    */
   run: function () {
     waitForExplicitFinish();
+    this._iter = runTests();
 
-    this._iter = runTests();
-    this.next();
+    if (this._iter)
+      this.next();
+    else
+      finish();
   },
 
   /**
    * Runs the next available test or finishes if there's no test left.
    */
   next: function () {
     try {
       TestRunner._iter.next();
--- a/browser/locales/en-US/chrome/browser/browser.dtd
+++ b/browser/locales/en-US/chrome/browser/browser.dtd
@@ -72,16 +72,22 @@ can reach it easily. -->
 <!ENTITY addonBarCmd.accesskey "A">
 
 <!ENTITY pageSourceCmd.label "Page Source">
 <!ENTITY pageSourceCmd.accesskey "o">
 <!ENTITY pageSourceCmd.commandkey "u">
 <!ENTITY pageInfoCmd.label "Page Info">
 <!ENTITY pageInfoCmd.accesskey "I">
 <!ENTITY pageInfoCmd.commandkey "i">
+<!-- LOCALIZATION NOTE (enterFullScreenCmd.label, exitFullScreenCmd.label):
+These should match what Safari and other Apple applications use on OS X Lion. -->
+<!ENTITY enterFullScreenCmd.label "Enter Full Screen">
+<!ENTITY enterFullScreenCmd.accesskey "F">
+<!ENTITY exitFullScreenCmd.label "Exit Full Screen">
+<!ENTITY exitFullScreenCmd.accesskey "F">
 <!ENTITY fullScreenCmd.label "Full Screen">
 <!ENTITY fullScreenCmd.accesskey "F">
 <!ENTITY fullScreenCmd.macCommandKey "f">
 <!ENTITY showAllTabsCmd.label "Show All Tabs">
 <!ENTITY showAllTabsCmd.accesskey "A">
 
 <!ENTITY fullScreenMinimize.tooltip "Minimize">
 <!ENTITY fullScreenRestore.tooltip "Restore">
--- a/browser/modules/WebappsInstaller.jsm
+++ b/browser/modules/WebappsInstaller.jsm
@@ -583,20 +583,18 @@ MacNativeApp.prototype = {
     <key>CFBundleName</key>\n\
     <string>' + escapeXML(this.appName) + '</string>\n\
     <key>CFBundlePackageType</key>\n\
     <string>APPL</string>\n\
     <key>CFBundleSignature</key>\n\
     <string>MOZB</string>\n\
     <key>CFBundleVersion</key>\n\
     <string>0</string>\n\
-#ifdef DEBUG
     <key>FirefoxBinary</key>\n\
-    <string>org.mozilla.NightlyDebug</string>\n\
-#endif
+#expand     <string>__MOZ_MACBUNDLE_ID__</string>\n\
   </dict>\n\
 </plist>';
 
     let infoPListFile = this.contentsDir.clone();
     infoPListFile.append("Info.plist");
     writeToFile(infoPListFile, infoPListContent, function() {});
   },
 
index 91c5dcb8830e76799d9371f183b4f07a03675dbf..d49be13cb61bf85af510c3c70e9179013859a9ab
GIT binary patch
literal 708
zc$@*m0z3VQP)<h;3K|Lk000e1NJLTq001xm000mO1^@s6P_F#30007uNkl<Zc-pO&
zPe_w-7{}9g7-TyL{n<anSiRe16AKUJrGtmDp|!L;WamnXl7gC`RGPI(B^jaJIz$9X
z&_PJeUYzA@gyE$wUb}{jd3}1m@Z;s>*ZX_l7q-I(o;}a^v+c{+*d8LPnb&^?%``F|
z#>?yjV)o!>%GJfMcY(d)#hRHg69JgT&Wnu5*6OPZ++Nj=GV{z1z>J+kfkyEHhhF~f
zPCfZ?LZABHUIm!3!wngcRr(`KU8zg2j_3n3;VQt4ot6Lpo7Xjs`OA<5cA8BA57YeO
zS9dzU(O$`KB*_eRe9IssvX*{s@l^W4Ot^CXd5Fwlms{*Id}V=KE809m%mU*FVkX>d
z3V4}tp?q9_TuM-(+)<j_?#Tko*x`nZ$Xfb?v#omnbdWC2wwChcR2E>y4mZPB6&POD
zb{Jy(rk!8xDvAOPjE{*;t|zOL>j|3M?(O5p9RM?SeA`6^SvXdH|FclF?`e?ujT=5@
z?D!`676op8(g?WS1M!g_U^*XuO%UMuG;<PQHtjo^gK(_;b5lVAvM=_MFBQ145G^v~
zK+&RrmuZ>!mfU)<)<$+9gDf1`ADC|0$`%4-2Qr2)7r6d0N^Y<y(8L_OzuHD_Ko*Yd
zpM4Y{HyFNL;M#{MIb&JC$Hd3<IJp5?II`b65g<1hzFc7FeUzM07a08#Cuh_Jdd36f
zj7@>7@1o?4y1>Zi7`Z@MAal=8E>IV^@-{{;P<;m?cb8-224vyLerC*1ZZLegz~wiw
zB0~<WDSm|lxs~|loh6Oz;LJ~C;mH1(@z7>^^f1}M8N;vVpE(b+Up#Syi7SX8gDjj{
q{dyK?F#QE?Vtfj4^CAnU9{xYs{QECRKia<l0000<MNUMnLSTXdG*`<2
index 3a22f7e0195088708f3838376551b95a42e87f7e..ffd6694269b3be4859e5ba1dfbcd612a10673c37
GIT binary patch
literal 672
zc$@*C0$=@!P)<h;3K|Lk000e1NJLTq001xm000mO1^@s6P_F#30007KNkl<Zc-pO&
zOKVzD6oqSqN}7SRP>KTs4U|BjqyB;rLjQ;kB!fUe#0TOFQNch!Q4xG0MhK!KaiC6Y
zW=Zo?LaZI{?gg8RoZh1cbntPvd#|M~x94)-5z)>(Jw2`CV4Tc*<`78jl$oX7hkxGz
z4j32XX1*|9Ahla&2cq58uMbeG)xI$U=1mx&w<Ul>KH$@2GC6;Ec$oJ4{S`os9%j&p
zR_pI{I_J4uZkkS~R{%Bl6u%}wrBXR%UKvt&#Y`7KR_q>+#}~a`Z^@9t5;JH-YwK^d
zS{KP=a+ydZXdU!0v;4XMrBZ3Y5Hn^xKx)ElLjV_6eSd#H?RLAw*T?yMehE-ZZwifQ
zZT*={W*U#jiLZ~N(dZJOmY(I;2DrPsdt-?4to1z7`=bfqV2+rtyy{iE-KN=W_LE<q
z0@Ua+f1wer!_FUz#a7X1l!n8h<wuPk&lJB+fZN+!0;YW+EB(lvHJeQWT>oIc1JrB%
zGtoNj{NZqzfa;gN;#UF`3WWtjTUe+8WTl=)qw!L&*J%^bKnsuRk3=Fb!C;U!0gdHX
z17x#VGQlRmA#+@<R>=ft;ZglJH#cO0<yQlwQYkXv{{Zs;Etkt=0<`d`{_E>&GQskz
z0dUd{&;>ZbK{o+fcvSz@)fJflt!)6DbOW>-C>D!kfOZ3cK!6O;Zy*#3kpa3h;LYdr
zWCFDCsD8iSPbOG?H2|OT1w&i-rMU}z<}dfW?FPV_-_XLN`uW#=_W69Y3D#KteLl=N
znGf>DURm*p0(xF(MC;tuzsCU9Bd|;U4o4a=bBWfm5C1>T64|&I!TwYL0000<MNUMn
GLSTYPi#t33
--- a/browser/themes/pinstripe/browser.css
+++ b/browser/themes/pinstripe/browser.css
@@ -539,17 +539,17 @@ toolbar[mode="icons"] #forward-button {
 
 #navigator-toolbox[iconsize="large"][mode="icons"] > #nav-bar #forward-button > .toolbarbutton-icon {
   /* shift the icon away from the back button */
   margin-left: 3px;
   margin-right: -1px;
 }
 
 #navigator-toolbox[iconsize="large"][mode="icons"] > #nav-bar #forward-button {
-  mask: url(chrome://browser/content/browser.xul#pinstripe-keyhole-forward-mask);
+  clip-path: url(chrome://browser/content/browser.xul#pinstripe-keyhole-forward-clip-path);
 }
 
 @conditionalForwardWithUrlbar@ > #forward-button:not(:-moz-lwtheme) {
   -moz-appearance: none;
   -moz-padding-start: 2px;
   background: -moz-linear-gradient(hsl(0,0%,99%), hsl(0,0%,67%)) padding-box;
   border: 1px solid;
   border-color: hsl(0,0%,31%) hsla(0,0%,29%,.6) hsl(0,0%,27%);
@@ -946,17 +946,17 @@ toolbar[mode="icons"] #zoom-in-button {
 }
 
 @conditionalForwardWithUrlbar@ + #urlbar-container > #urlbar:-moz-locale-dir(rtl) {
   border-top-right-radius: 0;
   border-bottom-right-radius: 0;
 }
 
 @conditionalForwardWithUrlbar@[forwarddisabled] + #urlbar-container {
-  mask: url("chrome://browser/content/browser.xul#pinstripe-urlbar-back-button-mask");
+  clip-path: url("chrome://browser/content/browser.xul#pinstripe-urlbar-back-button-clip-path");
 }
 
 @conditionalForwardWithUrlbar@[forwarddisabled] + #urlbar-container > #urlbar {
   margin-left: -@conditionalForwardWithUrlbarWidth@px;
 }
 
 @conditionalForwardWithUrlbar@[forwarddisabled]:hover:not([switchingtabs]) + #urlbar-container > #urlbar {
   /* delay the hiding of the forward button when hovered to avoid accidental clicks on the url bar */
@@ -965,17 +965,17 @@ toolbar[mode="icons"] #zoom-in-button {
 
 @conditionalForwardWithUrlbar@[forwarddisabled]:not(:hover) + #urlbar-container > #urlbar {
   /* when not hovered anymore, trigger a new transition to hide the forward button immediately */
   margin-left: -@conditionalForwardWithUrlbarWidth@.01px;
 }
 
 @conditionalForwardWithUrlbar@ + #urlbar-container:-moz-locale-dir(rtl),
 @conditionalForwardWithUrlbar@ + #urlbar-container > #urlbar:-moz-locale-dir(rtl) {
-  /* let pinstripe-urlbar-back-button-mask clip the urlbar's right side for RTL */
+  /* let pinstripe-urlbar-back-button-clip-path clip the urlbar's right side for RTL */
   -moz-transform: scaleX(-1);
 }
 
 #identity-box {
   -moz-margin-end: 3px;
   padding-top: 1px;
   padding-bottom: 1px;
   -moz-padding-start: 4px;
@@ -1801,32 +1801,32 @@ toolbarbutton.chevron > .toolbarbutton-m
 }
 
 .tab-background-middle {
   -moz-box-flex: 1;
 }
 
 @TABSONTOP_TAB_STACK@ > .tab-background > .tab-background-start:-moz-locale-dir(ltr),
 @TABSONTOP_TAB_STACK@ > .tab-background > .tab-background-end:-moz-locale-dir(rtl) {
-  mask: url(chrome://browser/content/browser.xul#pinstripe-tab-ontop-left-curve-mask);
+  clip-path: url(chrome://browser/content/browser.xul#pinstripe-tab-ontop-left-curve-clip-path);
 }
 
 @TABSONTOP_TAB_STACK@ > .tab-background > .tab-background-end:-moz-locale-dir(ltr),
 @TABSONTOP_TAB_STACK@ > .tab-background > .tab-background-start:-moz-locale-dir(rtl) {
-  mask: url(chrome://browser/content/browser.xul#pinstripe-tab-ontop-right-curve-mask);
+  clip-path: url(chrome://browser/content/browser.xul#pinstripe-tab-ontop-right-curve-clip-path);
 }
 
 @TABSONBOTTOM_TAB_STACK@ > .tab-background > .tab-background-start:-moz-locale-dir(ltr),
 @TABSONBOTTOM_TAB_STACK@ > .tab-background > .tab-background-end:-moz-locale-dir(rtl) {
-  mask: url(chrome://browser/content/browser.xul#pinstripe-tab-onbottom-left-curve-mask);
+  clip-path: url(chrome://browser/content/browser.xul#pinstripe-tab-onbottom-left-curve-clip-path);
 }
 
 @TABSONBOTTOM_TAB_STACK@ > .tab-background > .tab-background-end:-moz-locale-dir(ltr),
 @TABSONBOTTOM_TAB_STACK@ > .tab-background > .tab-background-start:-moz-locale-dir(rtl) {
-  mask: url(chrome://browser/content/browser.xul#pinstripe-tab-onbottom-right-curve-mask);
+  clip-path: url(chrome://browser/content/browser.xul#pinstripe-tab-onbottom-right-curve-clip-path);
 }
 
 .tab-background-start[selected="true"]:not(:-moz-lwtheme),
 .tab-background-middle[selected="true"]:not(:-moz-lwtheme),
 .tab-background-end[selected="true"]:not(:-moz-lwtheme) {
   background-color: -moz-mac-chrome-active;
 }
 
index 997157d6b1f04c7acdbbf2638cab22a88e5e9f72..bb165c579b7d0744ffd627d901700e903dee166d
GIT binary patch
literal 520
zc$@(U0{8uiP)<h;3K|Lk000e1NJLTq001BW000mO1^@s6cL04^0005cNkl<Zc-pPi
z%_{_990zc_=J1rY2jyjEcM>f#>*nBqi=%Ab-wrr?i4Yfx6eSemA~y#~*_6YUm$X?2
z<v{)jS4mudzQ20Z)Xp<AWe=Zv_B-EgziqQSMMU&(C-0+9VbDN8i6mqec6Rx_g&t50
z0?NRIgk;K0aL0GR;)7KOY50`VocRn0gMiBA+t&86<J#=-q4~}D%o$&kov?DiV%D<Y
z1IS5cmd5}M%9d_gI))C-ufc;jIdQgh)0*NAXvzT#_f{GRGN4NtnWa4j2rx&FYO(|S
zF&a6ldD?nz?`3@EjIVJAgmS?Ao%IO>x+BwN_N5pQf+!>h_Tu0DyD`EC_v3XV<1=Tt
z_QM_74Y>}OyS9i0&6)g4%b}@nCq@kCHfWaG9C;H|fR;C4He=_2eB@jP2&f+3uYT*@
zHpmNixC<h0z|56RLAVTvKz+}qK|ydAB6$O*FKzPYIv@%ST^j}k!Ci>v4Vb#H$)9>a
z=ej}uJO)gj+vHC@Aho7b0O|n~XGsb`bq^#`t2zb2UDtbH{4|*Z^6{wn6&T&?@t2O3
zD)NHPD|bN@@?oSwDHxD|289F|va1zxK*;e3jzCl)B0JjOKjAO*o4Y?g^vXv70000<
KMNUMnLSTYH)9Qf$
index 71fe2aefd41a64289c8f7835feaa401e9fec9fb0..d3d9a364bae4464b437072648f8989f377812b28
GIT binary patch
literal 500
zc$@+B0So?#P)<h;3K|Lk000e1NJLTq001BW000mO1^@s6cL04^0005INkl<Zc-pPi
zy=nqM6b0aH792Jfl0Xm(0}4S9QuzcSguI9rVj&13{viG#Vj&2E*onPpWo2j5ndDJ|
ziK%bSg)1!Vjt<1)!}0D}IgX=V5YfMFw_7(0YzTlO0y4AQS-$t&1uj8B2*MB*VVNn;
zoGdVzOzvS0J2B_ki2@cVxS7pnkG)=R-EOz{jMqHlYm%|F1;*oX0=|IUWR^Hmz=qIt
zI(=$3o8OH_gWPz=*Ej>Vw!mmKnghWKB4Q=8`H=z&!ktcMU9Z;(k8jK6@|p2kW^2xX
z(iRvFhdUsMxMmTV{b&kU5QJE*R@+yrRaz_-FL<6{yyh9M{c=XKmT!T<U_i`hE@Vru
zAz3b$iD8|B2a$5klajSP1^WH|2Iz#1PXPsyN~Q8yEEee)&Ttl#r$D#cB@;dc9JnhK
z3S@$_;CKqOS}ii*Eg+wNKA$HOhjZX5z$ev!u0TAO%aIAr`WE1mYCyXK*=&{!=y#x0
zDv<%*8Hi>w88X3H-!p(yx&b=jRr4*l#k+e?r_*!{G9R1;b<RH{8?NMqqY#6*o6Mq|
qk*s~r0+y6e;6PBrk&J!#CHw;+T03{XhaMdO0000<MNUMnLSTYYXVs|y
--- a/browser/themes/winstripe/browser.css
+++ b/browser/themes/winstripe/browser.css
@@ -812,17 +812,17 @@ toolbar[mode=full] .toolbarbutton-1 > .t
 @navbarLargeIcons@ .toolbarbutton-1 > .toolbarbutton-menubutton-button:not([disabled]):hover:active > .toolbarbutton-icon,
 @navbarLargeIcons@ .toolbarbutton-1[open] > .toolbarbutton-menubutton-dropmarker:not([disabled]) > .dropmarker-icon,
 @navbarLargeIcons@ .toolbarbutton-1:not([disabled]):-moz-any([open],[checked],:hover:active) > .toolbarbutton-icon {
   background-image: -moz-linear-gradient(hsla(0,0%,100%,.6), hsla(0,0%,100%,.1));
   background-color: hsla(210,54%,20%,.15);
   border-color: hsla(210,54%,20%,.3) hsla(210,54%,20%,.35) hsla(210,54%,20%,.4);
   box-shadow: 0 1px 1px hsla(210,54%,20%,.1) inset,
               0 0 1px hsla(210,54%,20%,.2) inset,
-              /* allows winstripe-keyhole-forward-mask to be used for non-hover as well as hover: */
+              /* allows winstripe-keyhole-forward-clip-path to be used for non-hover as well as hover: */
               0 1px 0 hsla(210,54%,20%,0),
               0 0 2px hsla(210,54%,20%,0);
   text-shadow: none;
   -moz-transition: none;
 }
 
 @navbarLargeIcons@ .toolbarbutton-1:-moz-any(:hover,[open]) > .toolbarbutton-menubutton-dropmarker:not([disabled]) > .dropmarker-icon {
   -moz-border-start-color: hsla(210,54%,20%,.35);
@@ -891,17 +891,17 @@ toolbar[mode=full] .toolbarbutton-1 > .t
 }
 
 @conditionalForwardWithUrlbar@ > #forward-button > menupopup {
   margin-top: 1px;
 }
 
 @conditionalForwardWithUrlbar@ > #forward-button > .toolbarbutton-icon {
   /*mask: url(keyhole-forward-mask.svg#mask); XXX: this regresses twinopen */
-  mask: url(chrome://browser/content/browser.xul#winstripe-keyhole-forward-mask);
+  clip-path: url(chrome://browser/content/browser.xul#winstripe-keyhole-forward-clip-path);
   -moz-margin-start: -6px !important;
   border-left-style: none;
   border-radius: 0;
   padding-left: 7px;
   padding-right: 3px;
 }
 
 @conditionalForwardWithUrlbar@:not([switchingtabs]) > #forward-button {
@@ -1253,17 +1253,17 @@ toolbar[mode=full] .toolbarbutton-1 > .t
 }
 
 @conditionalForwardWithUrlbar@ + #urlbar-container > #urlbar:-moz-locale-dir(rtl) {
   border-top-right-radius: 0;
   border-bottom-right-radius: 0;
 }
 
 @conditionalForwardWithUrlbar@[forwarddisabled] + #urlbar-container {
-  mask: url("chrome://browser/content/browser.xul#winstripe-urlbar-back-button-mask");
+  clip-path: url("chrome://browser/content/browser.xul#winstripe-urlbar-back-button-clip-path");
 }
 
 @conditionalForwardWithUrlbar@[forwarddisabled] + #urlbar-container > #urlbar {
   margin-left: -@conditionalForwardWithUrlbarWidth@px;
 }
 
 @conditionalForwardWithUrlbar@[forwarddisabled]:hover:not([switchingtabs]) + #urlbar-container > #urlbar {
   /* delay the hiding of the forward button when hovered to avoid accidental clicks on the url bar */
index 91c5dcb8830e76799d9371f183b4f07a03675dbf..d49be13cb61bf85af510c3c70e9179013859a9ab
GIT binary patch
literal 708
zc$@*m0z3VQP)<h;3K|Lk000e1NJLTq001xm000mO1^@s6P_F#30007uNkl<Zc-pO&
zPe_w-7{}9g7-TyL{n<anSiRe16AKUJrGtmDp|!L;WamnXl7gC`RGPI(B^jaJIz$9X
z&_PJeUYzA@gyE$wUb}{jd3}1m@Z;s>*ZX_l7q-I(o;}a^v+c{+*d8LPnb&^?%``F|
z#>?yjV)o!>%GJfMcY(d)#hRHg69JgT&Wnu5*6OPZ++Nj=GV{z1z>J+kfkyEHhhF~f
zPCfZ?LZABHUIm!3!wngcRr(`KU8zg2j_3n3;VQt4ot6Lpo7Xjs`OA<5cA8BA57YeO
zS9dzU(O$`KB*_eRe9IssvX*{s@l^W4Ot^CXd5Fwlms{*Id}V=KE809m%mU*FVkX>d
z3V4}tp?q9_TuM-(+)<j_?#Tko*x`nZ$Xfb?v#omnbdWC2wwChcR2E>y4mZPB6&POD
zb{Jy(rk!8xDvAOPjE{*;t|zOL>j|3M?(O5p9RM?SeA`6^SvXdH|FclF?`e?ujT=5@
z?D!`676op8(g?WS1M!g_U^*XuO%UMuG;<PQHtjo^gK(_;b5lVAvM=_MFBQ145G^v~
zK+&RrmuZ>!mfU)<)<$+9gDf1`ADC|0$`%4-2Qr2)7r6d0N^Y<y(8L_OzuHD_Ko*Yd
zpM4Y{HyFNL;M#{MIb&JC$Hd3<IJp5?II`b65g<1hzFc7FeUzM07a08#Cuh_Jdd36f
zj7@>7@1o?4y1>Zi7`Z@MAal=8E>IV^@-{{;P<;m?cb8-224vyLerC*1ZZLegz~wiw
zB0~<WDSm|lxs~|loh6Oz;LJ~C;mH1(@z7>^^f1}M8N;vVpE(b+Up#Syi7SX8gDjj{
q{dyK?F#QE?Vtfj4^CAnU9{xYs{QECRKia<l0000<MNUMnLSTXdG*`<2
index 3a22f7e0195088708f3838376551b95a42e87f7e..ffd6694269b3be4859e5ba1dfbcd612a10673c37
GIT binary patch
literal 672
zc$@*C0$=@!P)<h;3K|Lk000e1NJLTq001xm000mO1^@s6P_F#30007KNkl<Zc-pO&
zOKVzD6oqSqN}7SRP>KTs4U|BjqyB;rLjQ;kB!fUe#0TOFQNch!Q4xG0MhK!KaiC6Y
zW=Zo?LaZI{?gg8RoZh1cbntPvd#|M~x94)-5z)>(Jw2`CV4Tc*<`78jl$oX7hkxGz
z4j32XX1*|9Ahla&2cq58uMbeG)xI$U=1mx&w<Ul>KH$@2GC6;Ec$oJ4{S`os9%j&p
zR_pI{I_J4uZkkS~R{%Bl6u%}wrBXR%UKvt&#Y`7KR_q>+#}~a`Z^@9t5;JH-YwK^d
zS{KP=a+ydZXdU!0v;4XMrBZ3Y5Hn^xKx)ElLjV_6eSd#H?RLAw*T?yMehE-ZZwifQ
zZT*={W*U#jiLZ~N(dZJOmY(I;2DrPsdt-?4to1z7`=bfqV2+rtyy{iE-KN=W_LE<q
z0@Ua+f1wer!_FUz#a7X1l!n8h<wuPk&lJB+fZN+!0;YW+EB(lvHJeQWT>oIc1JrB%
zGtoNj{NZqzfa;gN;#UF`3WWtjTUe+8WTl=)qw!L&*J%^bKnsuRk3=Fb!C;U!0gdHX
z17x#VGQlRmA#+@<R>=ft;ZglJH#cO0<yQlwQYkXv{{Zs;Etkt=0<`d`{_E>&GQskz
z0dUd{&;>ZbK{o+fcvSz@)fJflt!)6DbOW>-C>D!kfOZ3cK!6O;Zy*#3kpa3h;LYdr
zWCFDCsD8iSPbOG?H2|OT1w&i-rMU}z<}dfW?FPV_-_XLN`uW#=_W69Y3D#KteLl=N
znGf>DURm*p0(xF(MC;tuzsCU9Bd|;U4o4a=bBWfm5C1>T64|&I!TwYL0000<MNUMn
GLSTYPi#t33
--- a/browser/themes/winstripe/jar.mn
+++ b/browser/themes/winstripe/jar.mn
@@ -357,17 +357,17 @@ browser.jar:
         skin/classic/aero/browser/devtools/itemArrow-rtl.png         (devtools/itemArrow-rtl.png)
         skin/classic/aero/browser/devtools/itemArrow-ltr.png         (devtools/itemArrow-ltr.png)
         skin/classic/aero/browser/devtools/inspect-button.png        (devtools/inspect-button.png)
         skin/classic/aero/browser/devtools/dropmarker.png            (devtools/dropmarker.png)
         skin/classic/aero/browser/devtools/treepanel-button.png      (devtools/treepanel-button.png)
         skin/classic/aero/browser/devtools/layout-background.png     (devtools/layout-background.png)
         skin/classic/aero/browser/devtools/layoutview.css            (devtools/layoutview.css)
         skin/classic/aero/browser/devtools/layout-buttons.png        (devtools/layout-buttons.png)
-        skin/classic/aera/browser/devtools/inspector-option-icon.png   (devtools/inspector-option-icon.png)
+        skin/classic/aero/browser/devtools/inspector-option-icon.png   (devtools/inspector-option-icon.png)
 #ifdef MOZ_SERVICES_SYNC
         skin/classic/aero/browser/sync-throbber.png
         skin/classic/aero/browser/sync-16.png
         skin/classic/aero/browser/sync-32.png
         skin/classic/aero/browser/sync-128.png
         skin/classic/aero/browser/sync-bg.png
         skin/classic/aero/browser/sync-desktopIcon.png
         skin/classic/aero/browser/sync-mobileIcon.png
--- a/build/automationutils.py
+++ b/build/automationutils.py
@@ -474,17 +474,17 @@ class ShutdownLeakLogger(object):
       self._logWindow(line)
     elif line[2:10] == "DOCSHELL":
       self._logDocShell(line)
     elif line.startswith("TEST-START"):
       fileName = line.split(" ")[-1].strip().replace("chrome://mochitests/content/browser/", "")
       self.currentTest = {"fileName": fileName, "windows": set(), "docShells": set()}
     elif line.startswith("INFO TEST-END"):
       # don't track a test if no windows or docShells leaked
-      if self.currentTest["windows"] or self.currentTest["docShells"]:
+      if self.currentTest and (self.currentTest["windows"] or self.currentTest["docShells"]):
         self.tests.append(self.currentTest)
       self.currentTest = None
     elif line.startswith("INFO TEST-START | Shutdown"):
       self.seenShutdown = True
 
   def parse(self):
     leakingTests = self._parseLeakingTests()
 
--- a/build/mobile/sutagent/android/SUTAgentAndroid.java
+++ b/build/mobile/sutagent/android/SUTAgentAndroid.java
@@ -35,16 +35,17 @@
  *
  * ***** END LICENSE BLOCK ***** */
 
 package com.mozilla.SUTAgentAndroid;
 
 import java.io.File;
 import java.io.PrintWriter;
 import java.net.InetAddress;
+import org.apache.http.conn.util.InetAddressUtils;
 import java.net.NetworkInterface;
 import java.net.SocketException;
 import java.util.Enumeration;
 import java.util.List;
 import java.util.Timer;
 
 import com.mozilla.SUTAgentAndroid.service.ASMozStub;
 import com.mozilla.SUTAgentAndroid.service.DoCommand;
@@ -660,17 +661,17 @@ public class SUTAgentAndroid extends Act
         try
             {
             for (Enumeration<NetworkInterface> en = NetworkInterface.getNetworkInterfaces(); en.hasMoreElements();)
                 {
                 NetworkInterface intf = en.nextElement();
                 for (Enumeration<InetAddress> enumIpAddr = intf.getInetAddresses(); enumIpAddr.hasMoreElements();)
                     {
                     InetAddress inetAddress = enumIpAddr.nextElement();
-                    if (!inetAddress.isLoopbackAddress())
+                    if (!inetAddress.isLoopbackAddress() && InetAddressUtils.isIPv4Address(inetAddress.getHostAddress()))
                         {
                         return inetAddress.getHostAddress().toString();
                         }
                     }
                 }
             }
         catch (SocketException ex)
             {
--- a/config/autoconf.mk.in
+++ b/config/autoconf.mk.in
@@ -56,16 +56,17 @@ MOZ_APP_ID = @MOZ_APP_ID@
 MAR_CHANNEL_ID = @MAR_CHANNEL_ID@
 ACCEPTED_MAR_CHANNEL_IDS = @ACCEPTED_MAR_CHANNEL_IDS@
 MOZ_PROFILE_MIGRATOR = @MOZ_PROFILE_MIGRATOR@
 MOZ_EXTENSION_MANAGER = @MOZ_EXTENSION_MANAGER@
 MOZ_APP_UA_NAME = @MOZ_APP_UA_NAME@
 MOZ_APP_VERSION = @MOZ_APP_VERSION@
 MOZ_APP_MAXVERSION = @MOZ_APP_MAXVERSION@
 MOZ_MACBUNDLE_NAME = @MOZ_MACBUNDLE_NAME@
+MOZ_MACBUNDLE_ID = @MOZ_MACBUNDLE_ID@
 MOZ_APP_STATIC_INI = @MOZ_APP_STATIC_INI@
 
 MOZ_PKG_SPECIAL = @MOZ_PKG_SPECIAL@
 
 prefix		= @prefix@
 exec_prefix	= @exec_prefix@
 bindir		= @bindir@
 includedir	= @includedir@/$(MOZ_APP_NAME)-$(MOZ_APP_VERSION)
@@ -159,16 +160,17 @@ MOZ_FEEDS = @MOZ_FEEDS@
 MOZ_TOOLKIT_SEARCH = @MOZ_TOOLKIT_SEARCH@
 MOZ_PLACES = @MOZ_PLACES@
 MOZ_SAFE_BROWSING = @MOZ_SAFE_BROWSING@
 MOZ_URL_CLASSIFIER = @MOZ_URL_CLASSIFIER@
 MOZ_ZIPWRITER = @MOZ_ZIPWRITER@
 MOZ_OGG = @MOZ_OGG@
 MOZ_RAW = @MOZ_RAW@
 MOZ_SYDNEYAUDIO = @MOZ_SYDNEYAUDIO@
+MOZ_SPEEX_RESAMPLER = @MOZ_SPEEX_RESAMPLER@
 MOZ_CUBEB = @MOZ_CUBEB@
 MOZ_WAVE = @MOZ_WAVE@
 MOZ_MEDIA = @MOZ_MEDIA@
 MOZ_VORBIS = @MOZ_VORBIS@
 MOZ_TREMOR = @MOZ_TREMOR@
 MOZ_NO_THEORA_ASM = @MOZ_NO_THEORA_ASM@
 MOZ_OPUS = @MOZ_OPUS@
 MOZ_WEBM = @MOZ_WEBM@
--- a/config/rules.mk
+++ b/config/rules.mk
@@ -356,35 +356,35 @@ endif
 ifdef MOZ_PROFILE_GENERATE
 SIMPLE_PROGRAMS :=
 endif
 
 ifndef TARGETS
 TARGETS			= $(LIBRARY) $(SHARED_LIBRARY) $(PROGRAM) $(SIMPLE_PROGRAMS) $(HOST_LIBRARY) $(HOST_PROGRAM) $(HOST_SIMPLE_PROGRAMS) $(JAVA_LIBRARY)
 endif
 
+COBJS = $(CSRCS:.c=.$(OBJ_SUFFIX))
+SOBJS = $(SSRCS:.S=.$(OBJ_SUFFIX))
+CCOBJS = $(patsubst %.cc,%.$(OBJ_SUFFIX),$(filter %.cc,$(CPPSRCS)))
+CPPOBJS = $(patsubst %.cpp,%.$(OBJ_SUFFIX),$(filter %.cpp,$(CPPSRCS)))
+CMOBJS = $(CMSRCS:.m=.$(OBJ_SUFFIX))
+CMMOBJS = $(CMMSRCS:.mm=.$(OBJ_SUFFIX))
+ASOBJS = $(ASFILES:.$(ASM_SUFFIX)=.$(OBJ_SUFFIX))
 ifndef OBJS
-_OBJS			= \
-	$(JRI_STUB_CFILES) \
-	$(addsuffix .$(OBJ_SUFFIX), $(JMC_GEN)) \
-	$(CSRCS:.c=.$(OBJ_SUFFIX)) \
-	$(SSRCS:.S=.$(OBJ_SUFFIX)) \
-	$(patsubst %.cc,%.$(OBJ_SUFFIX),$(CPPSRCS:.cpp=.$(OBJ_SUFFIX))) \
-	$(CMSRCS:.m=.$(OBJ_SUFFIX)) \
-	$(CMMSRCS:.mm=.$(OBJ_SUFFIX)) \
-	$(ASFILES:.$(ASM_SUFFIX)=.$(OBJ_SUFFIX))
-OBJS	= $(strip $(_OBJS))
+_OBJS = $(COBJS) $(SOBJS) $(CCOBJS) $(CPPOBJS) $(CMOBJS) $(CMMOBJS) $(ASOBJS)
+OBJS = $(strip $(_OBJS))
 endif
 
+HOST_COBJS = $(addprefix host_,$(HOST_CSRCS:.c=.$(OBJ_SUFFIX)))
+HOST_CCOBJS = $(addprefix host_,$(patsubst %.cc,%.$(OBJ_SUFFIX),$(filter %.cc,$(HOST_CPPSRCS))))
+HOST_CPPOBJS = $(addprefix host_,$(patsubst %.cpp,%.$(OBJ_SUFFIX),$(filter %.cpp,$(HOST_CPPSRCS))))
+HOST_CMOBJS = $(addprefix host_,$(HOST_CMSRCS:.m=.$(OBJ_SUFFIX)))
+HOST_CMMOBJS = $(addprefix host_,$(HOST_CMMSRCS:.mm=.$(OBJ_SUFFIX)))
 ifndef HOST_OBJS
-_HOST_OBJS		= \
-        $(addprefix host_,$(HOST_CSRCS:.c=.$(OBJ_SUFFIX))) \
-	$(addprefix host_,$(patsubst %.cc,%.$(OBJ_SUFFIX),$(HOST_CPPSRCS:.cpp=.$(OBJ_SUFFIX)))) \
-	$(addprefix host_,$(HOST_CMSRCS:.m=.$(OBJ_SUFFIX))) \
-	$(addprefix host_,$(HOST_CMMSRCS:.mm=.$(OBJ_SUFFIX)))
+_HOST_OBJS = $(HOST_COBJS) $(HOST_CCOBJS) $(HOST_CPPOBJS) $(HOST_CMOBJS) $(HOST_CMMOBJS)
 HOST_OBJS = $(strip $(_HOST_OBJS))
 endif
 
 LIBOBJS			:= $(addprefix \", $(OBJS))
 LIBOBJS			:= $(addsuffix \", $(LIBOBJS))
 
 ifndef MOZ_AUTO_DEPS
 ifneq (,$(OBJS)$(XPIDLSRCS)$(SIMPLE_PROGRAMS))
@@ -1085,42 +1085,37 @@ MAKE_DEPS_AUTO_CXX = $(MAKE_DEPS_AUTO)
 
 endif # COMPILER_DEPEND
 
 endif # MOZ_AUTO_DEPS
 
 $(OBJS) $(HOST_OBJS): $(GLOBAL_DEPS)
 
 # Rules for building native targets must come first because of the host_ prefix
-host_%.$(OBJ_SUFFIX): %.c
+$(HOST_COBJS): host_%.$(OBJ_SUFFIX): %.c
 	$(REPORT_BUILD)
 	$(ELOG) $(HOST_CC) $(HOST_OUTOPTION)$@ -c $(HOST_CFLAGS) $(INCLUDES) $(NSPR_CFLAGS) $(_VPATH_SRCS)
 
-host_%.$(OBJ_SUFFIX): %.cpp
-	$(REPORT_BUILD)
-	$(ELOG) $(HOST_CXX) $(HOST_OUTOPTION)$@ -c $(HOST_CXXFLAGS) $(INCLUDES) $(NSPR_CFLAGS) $(_VPATH_SRCS)
-
-host_%.$(OBJ_SUFFIX): %.cc
+$(HOST_CPPOBJS): host_%.$(OBJ_SUFFIX): %.cpp
 	$(REPORT_BUILD)
 	$(ELOG) $(HOST_CXX) $(HOST_OUTOPTION)$@ -c $(HOST_CXXFLAGS) $(INCLUDES) $(NSPR_CFLAGS) $(_VPATH_SRCS)
 
-host_%.$(OBJ_SUFFIX): %.m
+$(HOST_CCOBJS): host_%.$(OBJ_SUFFIX): %.cc
+	$(REPORT_BUILD)
+	$(ELOG) $(HOST_CXX) $(HOST_OUTOPTION)$@ -c $(HOST_CXXFLAGS) $(INCLUDES) $(NSPR_CFLAGS) $(_VPATH_SRCS)
+
+$(HOST_CMOBJS): host_%.$(OBJ_SUFFIX): %.m
 	$(REPORT_BUILD)
 	$(ELOG) $(HOST_CC) $(HOST_OUTOPTION)$@ -c $(HOST_CFLAGS) $(HOST_CMFLAGS) $(INCLUDES) $(NSPR_CFLAGS) $(_VPATH_SRCS)
 
-host_%.$(OBJ_SUFFIX): %.mm
+$(HOST_CMMOBJS): host_%.$(OBJ_SUFFIX): %.mm
 	$(REPORT_BUILD)
 	$(ELOG) $(HOST_CXX) $(HOST_OUTOPTION)$@ -c $(HOST_CXXFLAGS) $(HOST_CMMFLAGS) $(INCLUDES) $(NSPR_CFLAGS) $(_VPATH_SRCS)
 
-%:: %.c $(GLOBAL_DEPS)
-	$(REPORT_BUILD)
-	@$(MAKE_DEPS_AUTO_CC)
-	$(ELOG) $(CC) $(CFLAGS) $(LDFLAGS) $(OUTOPTION)$@ $(_VPATH_SRCS)
-
-%.$(OBJ_SUFFIX): %.c
+$(COBJS): %.$(OBJ_SUFFIX): %.c
 	$(REPORT_BUILD)
 	@$(MAKE_DEPS_AUTO_CC)
 	$(ELOG) $(CC) $(OUTOPTION)$@ -c $(COMPILE_CFLAGS) $(_VPATH_SRCS)
 
 # DEFINES and ACDEFINES are needed here to enable conditional compilation of Q_OBJECTs:
 # 'moc' only knows about #defines it gets on the command line (-D...), not in
 # included headers like mozilla-config.h
 moc_%.cpp: %.h
@@ -1130,52 +1125,48 @@ moc_%.cc: %.cc
 	$(ELOG) $(MOC) $(DEFINES) $(ACDEFINES) $(_VPATH_SRCS:.cc=.h) $(OUTOPTION)$@
 
 qrc_%.cpp: %.qrc
 	$(ELOG) $(RCC) -name $* $< $(OUTOPTION)$@
 
 ifdef ASFILES
 # The AS_DASH_C_FLAG is needed cause not all assemblers (Solaris) accept
 # a '-c' flag.
-%.$(OBJ_SUFFIX): %.$(ASM_SUFFIX)
+$(ASOBJS): %.$(OBJ_SUFFIX): %.$(ASM_SUFFIX)
 	$(AS) $(ASOUTOPTION)$@ $(ASFLAGS) $(AS_DASH_C_FLAG) $(_VPATH_SRCS)
 endif
 
-%.$(OBJ_SUFFIX): %.S
+$(SOBJS): %.$(OBJ_SUFFIX): %.S
 	$(AS) -o $@ $(ASFLAGS) -c $<
 
-%:: %.cpp $(GLOBAL_DEPS)
-	@$(MAKE_DEPS_AUTO_CXX)
-	$(CCC) $(OUTOPTION)$@ $(CXXFLAGS) $(_VPATH_SRCS) $(LDFLAGS)
-
 #
 # Please keep the next two rules in sync.
 #
-%.$(OBJ_SUFFIX): %.cc
+$(CCOBJS): %.$(OBJ_SUFFIX): %.cc
 	$(REPORT_BUILD)
 	@$(MAKE_DEPS_AUTO_CXX)
 	$(ELOG) $(CCC) $(OUTOPTION)$@ -c $(COMPILE_CXXFLAGS) $(_VPATH_SRCS)
 
-%.$(OBJ_SUFFIX): %.cpp
+$(CPPOBJS): %.$(OBJ_SUFFIX): %.cpp
 	$(REPORT_BUILD)
 	@$(MAKE_DEPS_AUTO_CXX)
 ifdef STRICT_CPLUSPLUS_SUFFIX
 	echo "#line 1 \"$*.cpp\"" | cat - $*.cpp > t_$*.cc
 	$(ELOG) $(CCC) -o $@ -c $(COMPILE_CXXFLAGS) t_$*.cc
 	$(RM) t_$*.cc
 else
 	$(ELOG) $(CCC) $(OUTOPTION)$@ -c $(COMPILE_CXXFLAGS) $(_VPATH_SRCS)
 endif #STRICT_CPLUSPLUS_SUFFIX
 
-$(OBJ_PREFIX)%.$(OBJ_SUFFIX): %.mm
+$(CMMOBJS): $(OBJ_PREFIX)%.$(OBJ_SUFFIX): %.mm
 	$(REPORT_BUILD)
 	@$(MAKE_DEPS_AUTO_CXX)
 	$(ELOG) $(CCC) -o $@ -c $(COMPILE_CXXFLAGS) $(COMPILE_CMMFLAGS) $(_VPATH_SRCS)
 
-$(OBJ_PREFIX)%.$(OBJ_SUFFIX): %.m
+$(CMOBJS): $(OBJ_PREFIX)%.$(OBJ_SUFFIX): %.m
 	$(REPORT_BUILD)
 	@$(MAKE_DEPS_AUTO_CC)
 	$(ELOG) $(CC) -o $@ -c $(COMPILE_CFLAGS) $(COMPILE_CMFLAGS) $(_VPATH_SRCS)
 
 %.s: %.cpp
 	$(CCC) -S $(COMPILE_CXXFLAGS) $(_VPATH_SRCS)
 
 %.s: %.cc
--- a/config/system-headers
+++ b/config/system-headers
@@ -1042,16 +1042,17 @@ vpx/vpx_codec.h
 vpx/vpx_decoder.h
 vpx/vp8dx.h
 #endif
 #ifdef XP_WIN
 vpx/vpx_codec.h
 vpx/vpx_decoder.h
 vpx/vp8dx.h
 sydneyaudio/sydney_audio.h
+speex/speex_resampler.h
 vorbis/codec.h
 theora/theoradec.h
 tremor/ivorbiscodec.h
 ogg/ogg.h
 ogg/os_types.h
 nestegg/nestegg.h
 cubeb/cubeb.h
 #endif
--- a/configure.in
+++ b/configure.in
@@ -4543,16 +4543,17 @@ MOZ_OFFICIAL_BRANDING=
 MOZ_FEEDS=1
 MOZ_FLEXBOX=
 MOZ_WEBAPP_RUNTIME=
 MOZ_JSDEBUGGER=1
 MOZ_AUTH_EXTENSION=1
 MOZ_OGG=1
 MOZ_RAW=
 MOZ_SYDNEYAUDIO=
+MOZ_SPEEX_RESAMPLER=1
 MOZ_CUBEB=
 MOZ_VORBIS=
 MOZ_TREMOR=
 MOZ_WAVE=1
 MOZ_MEDIA=
 MOZ_OPUS=1
 MOZ_WEBM=1
 MOZ_VP8_ERROR_CONCEALMENT=
@@ -5790,16 +5791,20 @@ fi
 dnl ========================================================
 dnl = Handle dependent SYDNEYAUDIO, CUBEB, and MEDIA defines
 dnl ========================================================
 
 if test -n "$MOZ_SYDNEYAUDIO"; then
     AC_DEFINE(MOZ_SYDNEYAUDIO)
 fi
 
+if test -n "$MOZ_SPEEX_RESAMPLER"; then
+    AC_DEFINE(MOZ_SPEEX_RESAMPLER)
+fi
+
 if test -n "$MOZ_CUBEB"; then
     case "$target" in
     *-mingw*)
         AC_DEFINE(MOZ_CUBEB)
         ;;
     *)
         dnl Other targets will be enabled soon.
         ;;
@@ -8008,17 +8013,17 @@ dnl =
 dnl ========================================================
 MOZ_ARG_HEADER(Standalone module options (Not for building Mozilla))
 
 dnl Check for GLib.
 dnl ========================================================
 
 if test -z "$SKIP_PATH_CHECKS"; then
 if test -z "${GLIB_CFLAGS}" -o -z "${GLIB_LIBS}" ; then
-    if test "$MOZ_ENABLE_GTK2" -o "$MOZ_ENABLE_QT" -o "$USE_ELF_DYNSTR_GC" ; then
+    if test "$MOZ_ENABLE_GTK2" -o "$USE_ELF_DYNSTR_GC" ; then
         PKG_CHECK_MODULES(GLIB, glib-2.0 >= 1.3.7 gobject-2.0)
     fi
 fi
 fi
 
 if test -z "${GLIB_GMODULE_LIBS}" \
    -a -n "${GLIB_CONFIG}"\
     -a "${GLIB_CONFIG}" != no\
@@ -8503,16 +8508,26 @@ fi
 
 if test "$MOZ_DEBUG"; then
   MOZ_MACBUNDLE_NAME=${MOZ_MACBUNDLE_NAME}Debug.app
 else
   MOZ_MACBUNDLE_NAME=${MOZ_MACBUNDLE_NAME}.app
 fi
 AC_SUBST(MOZ_MACBUNDLE_NAME)
 
+dnl Mac bundle identifier (based on MOZ_APP_DISPLAYNAME)
+MOZ_MACBUNDLE_ID=`echo $MOZ_APP_DISPLAYNAME | tr '[A-Z]' '[a-z]'`
+MOZ_MACBUNDLE_ID=${MOZ_DISTRIBUTION_ID}.${MOZ_MACBUNDLE_ID}
+if test "$MOZ_DEBUG"; then
+  MOZ_MACBUNDLE_ID=${MOZ_MACBUNDLE_ID}debug
+fi
+
+AC_DEFINE_UNQUOTED(MOZ_MACBUNDLE_ID,$MOZ_MACBUNDLE_ID)
+AC_SUBST(MOZ_MACBUNDLE_ID)
+
 # The following variables are available to branding and application
 # configuration ($BRANDING/configure.sh and $APPLICATION/confvars.sh):
 # - MOZ_APP_VENDOR: Used for application.ini's "Vendor" field, which also
 # impacts profile location and user-visible fields.
 # - MOZ_APP_BASENAME: Typically stays consistent for multiple branded
 # versions of a given application (e.g. Aurora and Firefox both use
 # "Firefox"), but may vary for full rebrandings (e.g. Iceweasel). Used
 # for application.ini's "Name" field, which controls profile location in
@@ -8710,16 +8725,17 @@ AC_SUBST(CXX_VERSION)
 AC_SUBST(MSMANIFEST_TOOL)
 AC_SUBST(NS_ENABLE_TSF)
 AC_SUBST(MOZ_NSS_PATCH)
 AC_SUBST(MOZ_APP_COMPONENT_LIBS)
 AC_SUBST(MOZ_APP_EXTRA_LIBS)
 
 AC_SUBST(MOZ_MEDIA)
 AC_SUBST(MOZ_SYDNEYAUDIO)
+AC_SUBST(MOZ_SPEEX_RESAMPLER)
 AC_SUBST(MOZ_CUBEB)
 AC_SUBST(MOZ_WAVE)
 AC_SUBST(MOZ_VORBIS)
 AC_SUBST(MOZ_TREMOR)
 AC_SUBST(MOZ_OPUS)
 AC_SUBST(MOZ_WEBM)
 AC_SUBST(MOZ_VP8_ERROR_CONCEALMENT)
 AC_SUBST(MOZ_VP8_ENCODER)
--- a/content/base/crashtests/crashtests.list
+++ b/content/base/crashtests/crashtests.list
@@ -102,11 +102,11 @@ load 700090-1.html
 load 700090-2.html
 load 700512.html
 load xhr_html_nullresponse.html
 load 709384.html
 load 713417.html
 load 713417-2.html
 load 715056.html
 load 741163-1.html
-load 752226-1.html
-load 752226-2.html
+asserts(0-1) load 752226-1.html
+asserts(0-1) load 752226-2.html
 HTTP(..) load xhr_abortinprogress.html
--- a/content/base/public/nsINode.h
+++ b/content/base/public/nsINode.h
@@ -1664,16 +1664,9 @@ extern const nsIID kThisPtrOffsetsSID;
     NS_INTERFACE_TABLE_ENTRY(_class, _i8)                                     \
   NS_OFFSET_AND_INTERFACE_TABLE_END                                           \
   NS_OFFSET_AND_INTERFACE_TABLE_TO_MAP_SEGUE
 
 
 NS_DEFINE_STATIC_IID_ACCESSOR(nsINode, NS_INODE_IID)
 
 
-#define NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER \
-  nsContentUtils::TraceWrapper(tmp, aCallback, aClosure);
-
-#define NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER \
-  nsContentUtils::ReleaseWrapper(s, tmp);
-
-
 #endif /* nsINode_h___ */
--- a/content/base/src/nsDOMFile.cpp
+++ b/content/base/src/nsDOMFile.cpp
@@ -602,26 +602,17 @@ nsDOMMemoryFile::GetInternalStream(nsIIn
   return DataOwnerAdapter::Create(mDataOwner, mStart, mLength, aStream);
 }
 
 ////////////////////////////////////////////////////////////////////////////
 // nsDOMFileList implementation
 
 DOMCI_DATA(FileList, nsDOMFileList)
 
-NS_IMPL_CYCLE_COLLECTION_CLASS(nsDOMFileList)
-NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsDOMFileList)
-  NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
-NS_IMPL_CYCLE_COLLECTION_UNLINK_END
-NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsDOMFileList)
-  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
-NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
-NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(nsDOMFileList)
-  NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER
-NS_IMPL_CYCLE_COLLECTION_TRACE_END
+NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_0(nsDOMFileList)
 
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsDOMFileList)
   NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
   NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDOMFileList)
   NS_INTERFACE_MAP_ENTRY(nsIDOMFileList)
   NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(FileList)
 NS_INTERFACE_MAP_END
 
--- a/content/base/src/nsDOMTokenList.cpp
+++ b/content/base/src/nsDOMTokenList.cpp
@@ -53,26 +53,17 @@ nsDOMTokenList::nsDOMTokenList(nsGeneric
 {
   // We don't add a reference to our element. If it goes away,
   // we'll be told to drop our reference
   SetIsDOMBinding();
 }
 
 nsDOMTokenList::~nsDOMTokenList() { }
 
-NS_IMPL_CYCLE_COLLECTION_CLASS(nsDOMTokenList)
-NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsDOMTokenList)
-  NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
-NS_IMPL_CYCLE_COLLECTION_UNLINK_END
-NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsDOMTokenList)
-  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
-NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
-NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(nsDOMTokenList)
-  NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER
-NS_IMPL_CYCLE_COLLECTION_TRACE_END
+NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_0(nsDOMTokenList)
 
 DOMCI_DATA(DOMTokenList, nsDOMTokenList)
 
 NS_INTERFACE_TABLE_HEAD(nsDOMTokenList)
   NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
   NS_INTERFACE_TABLE1(nsDOMTokenList,
                       nsIDOMDOMTokenList)
   NS_INTERFACE_TABLE_TO_MAP_SEGUE_CYCLE_COLLECTION(nsDOMTokenList)
--- a/content/base/src/nsGenericElement.cpp
+++ b/content/base/src/nsGenericElement.cpp
@@ -1712,27 +1712,19 @@ NeedsScriptTraverse(nsWrapperCache* aCac
 }
 
 //----------------------------------------------------------------------
 
 NS_IMPL_CYCLE_COLLECTING_ADDREF(nsChildContentList)
 NS_IMPL_CYCLE_COLLECTING_RELEASE(nsChildContentList)
 
 // If nsChildContentList is changed so that any additional fields are
-// traversed by the cycle collector, then CAN_SKIP must be updated.
-NS_IMPL_CYCLE_COLLECTION_CLASS(nsChildContentList)
-NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsChildContentList)
-  NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
-NS_IMPL_CYCLE_COLLECTION_UNLINK_END
-NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsChildContentList)
-  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
-NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
-NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(nsChildContentList)
-  NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER
-NS_IMPL_CYCLE_COLLECTION_TRACE_END
+// traversed by the cycle collector, then CAN_SKIP must be updated to
+// check that the additional fields are null.
+NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_0(nsChildContentList)
 
 // nsChildContentList only ever has a single child, its wrapper, so if
 // the wrapper is black, the list can't be part of a garbage cycle.
 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_BEGIN(nsChildContentList)
   return !NeedsScriptTraverse(tmp);
 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_END
 
 NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_IN_CC_BEGIN(nsChildContentList)
@@ -2136,21 +2128,18 @@ nsGenericElement::GetScrollTop(PRInt32* 
 }
 
 NS_IMETHODIMP
 nsGenericElement::SetScrollTop(PRInt32 aScrollTop)
 {
   nsIScrollableFrame* sf = GetScrollFrame();
   if (sf) {
     nsPoint pt = sf->GetScrollPosition();
-    pt.y = nsPresContext::CSSPixelsToAppUnits(aScrollTop);
-    nscoord halfPixel = nsPresContext::CSSPixelsToAppUnits(0.5f);
-    // Don't allow pt.y + halfPixel since that would round up to the next CSS pixel.
-    nsRect range(pt.x, pt.y - halfPixel, 0, halfPixel*2 - 1);
-    sf->ScrollTo(pt, nsIScrollableFrame::INSTANT, &range);
+    sf->ScrollToCSSPixels(nsIntPoint(nsPresContext::AppUnitsToIntCSSPixels(pt.x),
+                                     aScrollTop));
   }
   return NS_OK;
 }
 
 PRInt32
 nsGenericElement::GetScrollLeft()
 {
   nsIScrollableFrame* sf = GetScrollFrame();
@@ -2169,21 +2158,18 @@ nsGenericElement::GetScrollLeft(PRInt32*
 }
 
 NS_IMETHODIMP
 nsGenericElement::SetScrollLeft(PRInt32 aScrollLeft)
 {
   nsIScrollableFrame* sf = GetScrollFrame();
   if (sf) {
     nsPoint pt = sf->GetScrollPosition();
-    pt.x = nsPresContext::CSSPixelsToAppUnits(aScrollLeft);
-    nscoord halfPixel = nsPresContext::CSSPixelsToAppUnits(0.5f);
-    // Don't allow pt.x + halfPixel since that would round up to the next CSS pixel.
-    nsRect range(pt.x - halfPixel, pt.y, halfPixel*2 - 1, 0);
-    sf->ScrollTo(pt, nsIScrollableFrame::INSTANT, &range);
+    sf->ScrollToCSSPixels(nsIntPoint(aScrollLeft,
+                                     nsPresContext::AppUnitsToIntCSSPixels(pt.y)));
   }
   return NS_OK;
 }
 
 PRInt32
 nsGenericElement::GetScrollHeight()
 {
   if (IsSVG())
--- a/content/canvas/src/WebGLContext.cpp
+++ b/content/canvas/src/WebGLContext.cpp
@@ -1398,29 +1398,17 @@ NAME_NOT_SUPPORTED(WebGLTexture)
 NAME_NOT_SUPPORTED(WebGLBuffer)
 NAME_NOT_SUPPORTED(WebGLProgram)
 NAME_NOT_SUPPORTED(WebGLShader)
 NAME_NOT_SUPPORTED(WebGLFramebuffer)
 NAME_NOT_SUPPORTED(WebGLRenderbuffer)
 
 // WebGLExtension
 
-NS_IMPL_CYCLE_COLLECTION_CLASS(WebGLExtension)
-
-NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(WebGLExtension)
-  NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER
-NS_IMPL_CYCLE_COLLECTION_TRACE_END
-
-NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(WebGLExtension)
-  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
-NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
-
-NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(WebGLExtension)
-  NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
-NS_IMPL_CYCLE_COLLECTION_UNLINK_END
+NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_0(WebGLExtension)
   
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(WebGLExtension)
   NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
   NS_INTERFACE_MAP_ENTRY(nsISupports)
   NS_INTERFACE_MAP_ENTRY(nsIWebGLExtension)
   NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(WebGLExtension)
 NS_INTERFACE_MAP_END 
 
--- a/content/events/src/nsPaintRequest.cpp
+++ b/content/events/src/nsPaintRequest.cpp
@@ -79,28 +79,17 @@ nsPaintRequest::GetReason(nsAString& aRe
     aResult.Truncate();
     break;
   }
   return NS_OK;
 }
 
 DOMCI_DATA(PaintRequestList, nsPaintRequestList)
 
-NS_IMPL_CYCLE_COLLECTION_CLASS(nsPaintRequestList)
-NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsPaintRequestList)
-  NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
-  NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mParent)
-NS_IMPL_CYCLE_COLLECTION_UNLINK_END
-NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsPaintRequestList)
-  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
-  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mParent)
-NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
-NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(nsPaintRequestList)
-  NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER
-NS_IMPL_CYCLE_COLLECTION_TRACE_END
+NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_1(nsPaintRequestList, mParent)
 
 NS_INTERFACE_TABLE_HEAD(nsPaintRequestList)
   NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
   NS_INTERFACE_TABLE1(nsPaintRequestList, nsIDOMPaintRequestList)
   NS_INTERFACE_TABLE_TO_MAP_SEGUE_CYCLE_COLLECTION(nsPaintRequestList)
   NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(PaintRequestList)
 NS_INTERFACE_MAP_END
 
--- a/content/html/content/src/nsClientRect.cpp
+++ b/content/html/content/src/nsClientRect.cpp
@@ -98,28 +98,17 @@ NS_IMETHODIMP
 nsClientRect::GetHeight(float* aResult)
 {
   *aResult = mHeight;
   return NS_OK;
 }
 
 DOMCI_DATA(ClientRectList, nsClientRectList)
 
-NS_IMPL_CYCLE_COLLECTION_CLASS(nsClientRectList)
-NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsClientRectList)
-  NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mParent)
-  NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
-NS_IMPL_CYCLE_COLLECTION_UNLINK_END
-NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsClientRectList)
-  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mParent)
-  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
-NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
-NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(nsClientRectList)
-  NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER
-NS_IMPL_CYCLE_COLLECTION_TRACE_END
+NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_1(nsClientRectList, mParent)
 
 NS_INTERFACE_TABLE_HEAD(nsClientRectList)
   NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
   NS_INTERFACE_TABLE1(nsClientRectList, nsIDOMClientRectList)
   NS_INTERFACE_TABLE_TO_MAP_SEGUE_CYCLE_COLLECTION(nsClientRectList)
   NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(ClientRectList)
 NS_INTERFACE_MAP_END
 
--- a/content/html/content/src/nsHTMLInputElement.cpp
+++ b/content/html/content/src/nsHTMLInputElement.cpp
@@ -3305,28 +3305,26 @@ nsHTMLInputElement::AllowDrop()
 
 /*
  * Radio group stuff
  */
 
 void
 nsHTMLInputElement::AddedToRadioGroup()
 {
+  // If the element is neither in a form nor a document, there is no group so we
+  // should just stop here.
+  if (!mForm && !IsInDoc()) {
+    return;
+  }
+
   // Make sure not to notify if we're still being created by the parser
   bool notify = !mParserCreating;
 
   //
-  //  If the input element is not in a form and
-  //  not in a document, we just need to return.
-  //
-  if (!mForm && !(IsInDoc() && GetParent())) {
-    return;
-  }
-
-  //
   // If the input element is checked, and we add it to the group, it will
   // deselect whatever is currently selected in that group
   //
   if (mChecked) {
     //
     // If it is checked, call "RadioSetChecked" to perform the selection/
     // deselection ritual.  This has the side effect of repainting the
     // radio button, but as adding a checked radio button into the group
--- a/content/media/nsBuiltinDecoder.cpp
+++ b/content/media/nsBuiltinDecoder.cpp
@@ -441,33 +441,28 @@ void nsBuiltinDecoder::MetadataLoaded(PR
                                       PRUint32 aRate,
                                       bool aHasAudio)
 {
   NS_ASSERTION(NS_IsMainThread(), "Should be on main thread.");
   if (mShuttingDown) {
     return;
   }
 
-  // Only inform the element of MetadataLoaded if not doing a load() in order
-  // to fulfill a seek, otherwise we'll get multiple metadataloaded events.
-  bool notifyElement = true;
   {
     ReentrantMonitorAutoEnter mon(mReentrantMonitor);
     mDuration = mDecoderStateMachine ? mDecoderStateMachine->GetDuration() : -1;
     // Duration has changed so we should recompute playback rate
     UpdatePlaybackRate();
-
-    notifyElement = mNextState != PLAY_STATE_SEEKING;
   }
 
   if (mDuration == -1) {
     SetInfinite(true);
   }
 
-  if (mElement && notifyElement) {
+  if (mElement) {
     // Make sure the element and the frame (if any) are told about
     // our new size.
     Invalidate();
     mElement->MetadataLoaded(aChannels, aRate, aHasAudio);
   }
 
   if (!mResourceLoaded) {
     StartProgress();
@@ -477,17 +472,17 @@ void nsBuiltinDecoder::MetadataLoaded(PR
     mElement->DispatchAsyncEvent(NS_LITERAL_STRING("progress"));
   }
 
   // Only inform the element of FirstFrameLoaded if not doing a load() in order
   // to fulfill a seek, otherwise we'll get multiple loadedfirstframe events.
   ReentrantMonitorAutoEnter mon(mReentrantMonitor);
   bool resourceIsLoaded = !mResourceLoaded && mResource &&
     mResource->IsDataCachedToEndOfResource(mDecoderPosition);
-  if (mElement && notifyElement) {
+  if (mElement) {
     mElement->FirstFrameLoaded(resourceIsLoaded);
   }
 
   // This can run cache callbacks.
   mResource->EnsureCacheUpToDate();
 
   // The element can run javascript via events
   // before reaching here, so only change the
@@ -562,29 +557,32 @@ void nsBuiltinDecoder::DecodeError()
   if (mElement)
     mElement->DecodeError();
 
   Shutdown();
 }
 
 bool nsBuiltinDecoder::IsSeeking() const
 {
-  return mPlayState == PLAY_STATE_SEEKING || mNextState == PLAY_STATE_SEEKING;
+  NS_ASSERTION(NS_IsMainThread(), "Should be on main thread.");
+  return mPlayState == PLAY_STATE_SEEKING;
 }
 
 bool nsBuiltinDecoder::IsEnded() const
 {
+  NS_ASSERTION(NS_IsMainThread(), "Should be on main thread.");
   return mPlayState == PLAY_STATE_ENDED || mPlayState == PLAY_STATE_SHUTDOWN;
 }
 
 void nsBuiltinDecoder::PlaybackEnded()
 {
   if (mShuttingDown || mPlayState == nsBuiltinDecoder::PLAY_STATE_SEEKING)
     return;
 
+  printf("nsBuiltinDecoder::PlaybackEnded mPlayState=%d\n", mPlayState);
   PlaybackPositionChanged();
   ChangeState(PLAY_STATE_ENDED);
 
   if (mElement)  {
     UpdateReadyStateForData();
     mElement->PlaybackEnded();
   }
 
@@ -789,16 +787,17 @@ void nsBuiltinDecoder::SeekingStopped()
 
     // An additional seek was requested while the current seek was
     // in operation.
     if (mRequestedSeekTime >= 0.0) {
       ChangeState(PLAY_STATE_SEEKING);
       seekWasAborted = true;
     } else {
       UnpinForSeek();
+      printf("nsBuiltinDecoder::SeekingStopped, next state=%d\n", mNextState);
       ChangeState(mNextState);
     }
   }
 
   if (mElement) {
     UpdateReadyStateForData();
     if (!seekWasAborted) {
       mElement->SeekCompleted();
@@ -822,16 +821,17 @@ void nsBuiltinDecoder::SeekingStoppedAtE
 
     // An additional seek was requested while the current seek was
     // in operation.
     if (mRequestedSeekTime >= 0.0) {
       ChangeState(PLAY_STATE_SEEKING);
       seekWasAborted = true;
     } else {
       UnpinForSeek();
+      printf("nsBuiltinDecoder::SeekingStoppedAtEnd, next state=PLAY_STATE_ENDED\n");
       fireEnded = true;
       ChangeState(PLAY_STATE_ENDED);
     }
   }
 
   if (mElement) {
     UpdateReadyStateForData();
     if (!seekWasAborted) {
@@ -904,16 +904,19 @@ void nsBuiltinDecoder::PlaybackPositionC
         // Only update the current playback position if we're not seeking.
         // If we are seeking, the update could have been scheduled on the
         // state machine thread while we were playing but after the seek
         // algorithm set the current playback position on the main thread,
         // and we don't want to override the seek algorithm and change the
         // current time after the seek has started but before it has
         // completed.
         mCurrentTime = mDecoderStateMachine->GetCurrentTime();
+      } else {
+        printf("Suppressed timeupdate during seeking: currentTime=%f, new time=%f\n",
+               mCurrentTime, mDecoderStateMachine->GetCurrentTime());
       }
       mDecoderStateMachine->ClearPositionChangeFlag();
     }
   }
 
   // Invalidate the frame so any video data is displayed.
   // Do this before the timeupdate event so that if that
   // event runs JavaScript that queries the media size, the
--- a/content/media/nsBuiltinDecoder.h
+++ b/content/media/nsBuiltinDecoder.h
@@ -465,18 +465,18 @@ public:
   // Called when the video file has completed downloading.
   // Call on the main thread only.
   void ResourceLoaded();
 
   // Called if the media file encounters a network error.
   // Call on the main thread only.
   virtual void NetworkError();
 
-  // Call from any thread safely. Return true if we are currently
-  // seeking in the media resource.
+  // Return true if we are currently seeking in the media resource.
+  // Call on the main thread only.
   virtual bool IsSeeking() const;
 
   // Return true if the decoder has reached the end of playback.
   // Call on the main thread only.
   virtual bool IsEnded() const;
 
   // Set the duration of the media resource in units of seconds.
   // This is called via a channel listener if it can pick up the duration
@@ -737,27 +737,31 @@ public:
   // ReentrantMonitor for detecting when the video play state changes. A call
   // to Wait on this monitor will block the thread until the next
   // state change.
   ReentrantMonitor mReentrantMonitor;
 
   // Data about MediaStreams that are being fed by this decoder.
   nsTArray<OutputMediaStream> mOutputStreams;
 
-  // Set to one of the valid play states. It is protected by the
-  // monitor mReentrantMonitor. This monitor must be acquired when reading or
-  // writing the state. Any change to the state on the main thread
-  // must call NotifyAll on the monitor so the decode thread can wake up.
+  // Set to one of the valid play states.
+  // This can only be changed on the main thread while holding the decoder
+  // monitor. Thus, it can be safely read while holding the decoder monitor
+  // OR on the main thread.
+  // Any change to the state on the main thread must call NotifyAll on the
+  // monitor so the decode thread can wake up.
   PlayState mPlayState;
 
-  // The state to change to after a seek or load operation. It must only
-  // be changed from the main thread. The decoder monitor must be acquired
-  // when writing to the state, or when reading from a non-main thread.
+  // The state to change to after a seek or load operation.
+  // This can only be changed on the main thread while holding the decoder
+  // monitor. Thus, it can be safely read while holding the decoder monitor
+  // OR on the main thread.
   // Any change to the state must call NotifyAll on the monitor.
-  PlayState mNextState;	
+  // This can only be PLAY_STATE_PAUSED or PLAY_STATE_PLAYING.
+  PlayState mNextState;
 
   // True when we have fully loaded the resource and reported that
   // to the element (i.e. reached NETWORK_LOADED state).
   // Accessed on the main thread only.
   bool mResourceLoaded;
 
   // True when seeking or otherwise moving the play position around in
   // such a manner that progress event data is inaccurate. This is set
--- a/content/media/nsBuiltinDecoderStateMachine.cpp
+++ b/content/media/nsBuiltinDecoderStateMachine.cpp
@@ -2193,16 +2193,17 @@ nsresult nsBuiltinDecoderStateMachine::R
         return NS_OK;
       }
  
       StopAudioThread();
       if (mDecoder->GetState() == nsBuiltinDecoder::PLAY_STATE_PLAYING) {
         PRInt64 videoTime = HasVideo() ? mVideoFrameEndTime : 0;
         PRInt64 clockTime = NS_MAX(mEndTime, NS_MAX(videoTime, GetAudioClock()));
         UpdatePlaybackPosition(clockTime);
+        printf("nsBuiltinDecoderStateMachine::RunStateMachine queuing nsBuiltinDecoder::PlaybackEnded\n");
         nsCOMPtr<nsIRunnable> event =
           NS_NewRunnableMethod(mDecoder, &nsBuiltinDecoder::PlaybackEnded);
         NS_DispatchToMainThread(event, NS_DISPATCH_NORMAL);
       }
       return NS_OK;
     }
   }
 
--- a/dom/base/nsDOMClassInfo.cpp
+++ b/dom/base/nsDOMClassInfo.cpp
@@ -5872,17 +5872,17 @@ DefineIDBInterfaceConstants(JSContext *c
                                        JSPROP_ENUMERATE)) {
       return NS_ERROR_UNEXPECTED;
     }
   }
 
   return NS_OK;
 }
 
-class nsDOMConstructor : public nsIDOMDOMConstructor
+class nsDOMConstructor MOZ_FINAL : public nsIDOMDOMConstructor
 {
 protected:
   nsDOMConstructor(const PRUnichar* aName,
                    bool aIsConstructable,
                    nsPIDOMWindow* aOwner)
     : mClassName(aName),
       mConstructable(aIsConstructable),
       mWeakOwner(do_GetWeakReference(aOwner))
--- a/dom/base/nsGlobalWindow.cpp
+++ b/dom/base/nsGlobalWindow.cpp
@@ -1822,23 +1822,21 @@ nsGlobalWindow::SetNewDocument(nsIDocume
                  "We should never be reusing a shared inner window");
     newInnerWindow = currentInner;
 
     if (aDocument != oldDoc) {
       xpc_UnmarkGrayObject(currentInner->mJSObject);
       nsWindowSH::InvalidateGlobalScopePolluter(cx, currentInner->mJSObject);
     }
 
-    // The API we're really looking for here is to go clear all of the
-    // Xray wrappers associated with our outer window. However, we
-    // don't expose that API because the implementation would be
-    // identical to that of JS_TransplantObject, so we just call that
-    // instead.
+    // We're reusing the inner window, but this still counts as a navigation,
+    // so all expandos and such defined on the outer window should go away. Force
+    // all Xray wrappers to be recomputed.
     xpc_UnmarkGrayObject(mJSObject);
-    if (!JS_TransplantObject(cx, mJSObject, mJSObject)) {
+    if (!JS_RefreshCrossCompartmentWrappers(cx, mJSObject)) {
       return NS_ERROR_FAILURE;
     }
   } else {
     if (aState) {
       newInnerWindow = wsh->GetInnerWindow();
       mInnerWindowHolder = wsh->GetInnerWindowHolder();
 
       NS_ASSERTION(newInnerWindow, "Got a state without inner window");
@@ -5325,22 +5323,17 @@ nsGlobalWindow::ScrollTo(PRInt32 aXScrol
 
     if (aXScroll > maxpx) {
       aXScroll = maxpx;
     }
 
     if (aYScroll > maxpx) {
       aYScroll = maxpx;
     }
-    nsPoint pt(nsPresContext::CSSPixelsToAppUnits(aXScroll),
-               nsPresContext::CSSPixelsToAppUnits(aYScroll));
-    nscoord halfPixel = nsPresContext::CSSPixelsToAppUnits(0.5f);
-    // Don't allow pt.x/y + halfPixel since that would round up to the next CSS pixel.
-    nsRect range(pt.x - halfPixel, pt.y - halfPixel, halfPixel*2 - 1, halfPixel*2 - 1);
-    sf->ScrollTo(pt, nsIScrollableFrame::INSTANT, &range);
+    sf->ScrollToCSSPixels(nsIntPoint(aXScroll, aYScroll));
   }
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsGlobalWindow::ScrollBy(PRInt32 aXScrollDif, PRInt32 aYScrollDif)
 {
--- a/dom/base/nsWrapperCache.h
+++ b/dom/base/nsWrapperCache.h
@@ -241,9 +241,45 @@ private:
 NS_DEFINE_STATIC_IID_ACCESSOR(nsWrapperCache, NS_WRAPPERCACHE_IID)
 
 #define NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY                                   \
   if ( aIID.Equals(NS_GET_IID(nsWrapperCache)) ) {                            \
     *aInstancePtr = static_cast<nsWrapperCache*>(this);                       \
     return NS_OK;                                                             \
   }
 
+
+// Cycle collector macros for wrapper caches.
+
+#define NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER \
+  nsContentUtils::TraceWrapper(tmp, aCallback, aClosure);
+
+#define NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER \
+  nsContentUtils::ReleaseWrapper(s, tmp);
+
+#define NS_IMPL_CYCLE_COLLECTION_TRACE_WRAPPERCACHE(_class) \
+  NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(_class)              \
+    NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER        \
+  NS_IMPL_CYCLE_COLLECTION_TRACE_END
+
+#define NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_0(_class) \
+  NS_IMPL_CYCLE_COLLECTION_CLASS(_class)                \
+  NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(_class)         \
+    NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER   \
+  NS_IMPL_CYCLE_COLLECTION_UNLINK_END                   \
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(_class)       \
+    NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS    \
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END                 \
+  NS_IMPL_CYCLE_COLLECTION_TRACE_WRAPPERCACHE(_class)
+
+#define NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_1(_class, _field) \
+  NS_IMPL_CYCLE_COLLECTION_CLASS(_class)                        \
+  NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(_class)                 \
+    NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(_field)            \
+    NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER           \
+  NS_IMPL_CYCLE_COLLECTION_UNLINK_END                           \
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(_class)               \
+    NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(_field)          \
+    NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS            \
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END                         \
+  NS_IMPL_CYCLE_COLLECTION_TRACE_WRAPPERCACHE(_class)
+
 #endif /* nsWrapperCache_h___ */
--- a/dom/contacts/Makefile.in
+++ b/dom/contacts/Makefile.in
@@ -6,30 +6,30 @@ DEPTH		= ../..
 topsrcdir	= @top_srcdir@
 srcdir		= @srcdir@
 VPATH            = \
   $(srcdir)        \
   $(NULL)
 
 include $(DEPTH)/config/autoconf.mk
 
-ifeq ($(MOZ_BUILD_APP),b2g)
+ifeq ($(MOZ_BUILD_APP), $(filter $(MOZ_BUILD_APP),b2g mail))
 VPATH += $(srcdir)/fallback
 endif
 
 MODULE         = dom
 LIBRARY_NAME   = jsdomcontacts_s
 LIBXUL_LIBRARY = 1
 
 EXTRA_COMPONENTS =        \
   ContactManager.js       \
   ContactManager.manifest \
   $(NULL)
 
-ifeq ($(MOZ_BUILD_APP),b2g)
+ifeq ($(MOZ_BUILD_APP), $(filter $(MOZ_BUILD_APP),b2g mail))
 EXTRA_JS_MODULES =   \
   ContactService.jsm \
   ContactDB.jsm      \
   $(NULL)
 endif
 
 ifdef ENABLE_TESTS
 DIRS += tests
--- a/dom/indexedDB/CheckPermissionsHelper.h
+++ b/dom/indexedDB/CheckPermissionsHelper.h
@@ -47,19 +47,19 @@
 #include "nsIObserver.h"
 #include "nsIRunnable.h"
 
 class nsIDOMWindow;
 class nsIThread;
 
 BEGIN_INDEXEDDB_NAMESPACE
 
-class CheckPermissionsHelper : public nsIRunnable,
-                               public nsIInterfaceRequestor,
-                               public nsIObserver
+class CheckPermissionsHelper MOZ_FINAL : public nsIRunnable,
+                                         public nsIInterfaceRequestor,
+                                         public nsIObserver
 {
 public:
   NS_DECL_ISUPPORTS
   NS_DECL_NSIRUNNABLE
   NS_DECL_NSIINTERFACEREQUESTOR
   NS_DECL_NSIOBSERVER
 
   CheckPermissionsHelper(OpenDatabaseHelper* aHelper,
--- a/dom/indexedDB/CheckQuotaHelper.h
+++ b/dom/indexedDB/CheckQuotaHelper.h
@@ -50,19 +50,19 @@
 
 #include "mozilla/Mutex.h"
 #include "mozilla/CondVar.h"
 
 class nsPIDOMWindow;
 
 BEGIN_INDEXEDDB_NAMESPACE
 
-class CheckQuotaHelper : public nsIRunnable,
-                         public nsIInterfaceRequestor,
-                         public nsIObserver
+class CheckQuotaHelper MOZ_FINAL : public nsIRunnable,
+                                   public nsIInterfaceRequestor,
+                                   public nsIObserver
 {
 public:
   NS_DECL_ISUPPORTS
   NS_DECL_NSIRUNNABLE
   NS_DECL_NSIINTERFACEREQUESTOR
   NS_DECL_NSIOBSERVER
 
   CheckQuotaHelper(nsPIDOMWindow* aWindow,
--- a/dom/indexedDB/IDBCursor.h
+++ b/dom/indexedDB/IDBCursor.h
@@ -58,17 +58,17 @@ class IDBIndex;
 class IDBRequest;
 class IDBTransaction;
 
 class ContinueHelper;
 class ContinueObjectStoreHelper;
 class ContinueIndexHelper;
 class ContinueIndexObjectHelper;
 
-class IDBCursor : public nsIIDBCursorWithValue
+class IDBCursor MOZ_FINAL : public nsIIDBCursorWithValue
 {
   friend class ContinueHelper;
   friend class ContinueObjectStoreHelper;
   friend class ContinueIndexHelper;
   friend class ContinueIndexObjectHelper;
 
 public:
   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
--- a/dom/indexedDB/IDBFactory.h
+++ b/dom/indexedDB/IDBFactory.h
@@ -52,17 +52,17 @@ class nsIAtom;
 class nsPIDOMWindow;
 
 BEGIN_INDEXEDDB_NAMESPACE
 
 struct DatabaseInfo;
 class IDBDatabase;
 struct ObjectStoreInfo;
 
-class IDBFactory : public nsIIDBFactory
+class IDBFactory MOZ_FINAL : public nsIIDBFactory
 {
   typedef nsTArray<nsRefPtr<ObjectStoreInfo> > ObjectStoreInfoArray;
 
 public:
   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
   NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(IDBFactory)
   NS_DECL_NSIIDBFACTORY
 
--- a/dom/indexedDB/IDBIndex.h
+++ b/dom/indexedDB/IDBIndex.h
@@ -50,17 +50,17 @@ class nsIScriptContext;
 class nsPIDOMWindow;
 
 BEGIN_INDEXEDDB_NAMESPACE
 
 class AsyncConnectionHelper;
 class IDBObjectStore;
 struct IndexInfo;
 
-class IDBIndex : public nsIIDBIndex
+class IDBIndex MOZ_FINAL : public nsIIDBIndex
 {
 public:
   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
   NS_DECL_NSIIDBINDEX
 
   NS_DECL_CYCLE_COLLECTION_CLASS(IDBIndex)
 
   static already_AddRefed<IDBIndex>
--- a/dom/indexedDB/IDBKeyRange.h
+++ b/dom/indexedDB/IDBKeyRange.h
@@ -46,17 +46,17 @@
 #include "nsIIDBKeyRange.h"
 
 #include "nsCycleCollectionParticipant.h"
 
 class mozIStorageStatement;
 
 BEGIN_INDEXEDDB_NAMESPACE
 
-class IDBKeyRange : public nsIIDBKeyRange
+class IDBKeyRange MOZ_FINAL : public nsIIDBKeyRange
 {
 public:
   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
   NS_DECL_NSIIDBKEYRANGE
   NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(IDBKeyRange)
 
   static JSBool DefineConstructors(JSContext* aCx,
                                    JSObject* aObject);
--- a/dom/indexedDB/IDBObjectStore.h
+++ b/dom/indexedDB/IDBObjectStore.h
@@ -58,17 +58,17 @@ class AsyncConnectionHelper;
 class Key;
 
 struct ObjectStoreInfo;
 struct IndexInfo;
 struct IndexUpdateInfo;
 struct StructuredCloneReadInfo;
 struct StructuredCloneWriteInfo;
 
-class IDBObjectStore : public nsIIDBObjectStore
+class IDBObjectStore MOZ_FINAL : public nsIIDBObjectStore
 {
 public:
   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
   NS_DECL_NSIIDBOBJECTSTORE
 
   NS_DECL_CYCLE_COLLECTION_CLASS(IDBObjectStore)
 
   static already_AddRefed<IDBObjectStore>
--- a/dom/indexedDB/IDBTransaction.h
+++ b/dom/indexedDB/IDBTransaction.h
@@ -214,17 +214,17 @@ private:
 #ifdef DEBUG
   bool mFiredCompleteOrAbort;
 #endif
 
   nsRefPtr<UpdateRefcountFunction> mUpdateFileRefcountFunction;
   nsTArray<nsRefPtr<FileInfo> > mCreatedFileInfos;
 };
 
-class CommitHelper : public nsIRunnable
+class CommitHelper MOZ_FINAL : public nsIRunnable
 {
 public:
   NS_DECL_ISUPPORTS
   NS_DECL_NSIRUNNABLE
 
   CommitHelper(IDBTransaction* aTransaction,
                IDBTransactionListener* aListener,
                const nsTArray<nsRefPtr<IDBObjectStore> >& mUpdatedObjectStores);
@@ -258,17 +258,17 @@ private:
   nsCOMPtr<mozIStorageConnection> mConnection;
   nsRefPtr<UpdateRefcountFunction> mUpdateFileRefcountFunction;
   nsAutoTArray<nsCOMPtr<nsISupports>, 10> mDoomedObjects;
   nsAutoTArray<nsRefPtr<IDBObjectStore>, 10> mAutoIncrementObjectStores;
 
   bool mAborted;
 };
 
-class UpdateRefcountFunction : public mozIStorageFunction
+class UpdateRefcountFunction MOZ_FINAL : public mozIStorageFunction
 {
 public:
   NS_DECL_ISUPPORTS
   NS_DECL_MOZISTORAGEFUNCTION
 
   UpdateRefcountFunction(FileManager* aFileManager)
   : mFileManager(aFileManager)
   { }
--- a/dom/indexedDB/IndexedDatabaseManager.cpp
+++ b/dom/indexedDB/IndexedDatabaseManager.cpp
@@ -120,17 +120,17 @@ GetBaseFilename(const nsAString& aFilena
     return false;
   }
 
   aBaseFilename = Substring(aFilename, 0, filenameLen - sqliteLen);
 
   return true;
 }
 
-class QuotaCallback : public mozIStorageQuotaCallback
+class QuotaCallback MOZ_FINAL : public mozIStorageQuotaCallback
 {
 public:
   NS_DECL_ISUPPORTS
 
   NS_IMETHOD
   QuotaExceeded(const nsACString& aFilename,
                 PRInt64 aCurrentSizeLimit,
                 PRInt64 aCurrentTotalSize,
--- a/dom/indexedDB/IndexedDatabaseManager.h
+++ b/dom/indexedDB/IndexedDatabaseManager.h
@@ -64,18 +64,18 @@ class nsIFile;
 class nsITimer;
 
 BEGIN_INDEXEDDB_NAMESPACE
 
 class AsyncConnectionHelper;
 
 class CheckQuotaHelper;
 
-class IndexedDatabaseManager : public nsIIndexedDatabaseManager,
-                               public nsIObserver
+class IndexedDatabaseManager MOZ_FINAL : public nsIIndexedDatabaseManager,
+                                         public nsIObserver
 {
   friend class IDBDatabase;
 
 public:
   static already_AddRefed<IndexedDatabaseManager> GetOrCreate();
 
   // Returns a non-owning reference.
   static IndexedDatabaseManager* Get();
@@ -238,17 +238,17 @@ private:
   // Responsible for clearing the database files for a particular origin on the
   // IO thread. Created when nsIIDBIndexedDatabaseManager::ClearDatabasesForURI
   // is called. Runs three times, first on the main thread, next on the IO
   // thread, and then finally again on the main thread. While on the IO thread
   // the runnable will actually remove the origin's database files and the
   // directory that contains them before dispatching itself back to the main
   // thread. When back on the main thread the runnable will notify the
   // IndexedDatabaseManager that the job has been completed.
-  class OriginClearRunnable : public nsIRunnable
+  class OriginClearRunnable MOZ_FINAL : public nsIRunnable
   {
   public:
     NS_DECL_ISUPPORTS
     NS_DECL_NSIRUNNABLE
 
     OriginClearRunnable(const nsACString& aOrigin,
                         nsIThread* aThread)
     : mOrigin(aOrigin),
@@ -267,17 +267,17 @@ private:
   // certain origin. Created when nsIIDBIndexedDatabaseManager::GetUsageForURI
   // is called. May be canceled with
   // nsIIDBIndexedDatabaseManager::CancelGetUsageForURI. Runs twice, first on
   // the IO thread, then again on the main thread. While on the IO thread the
   // runnable will calculate the size of all files in the origin's directory
   // before dispatching itself back to the main thread. When on the main thread
   // the runnable will call the callback and then notify the
   // IndexedDatabaseManager that the job has been completed.
-  class AsyncUsageRunnable : public nsIRunnable
+  class AsyncUsageRunnable MOZ_FINAL : public nsIRunnable
   {
   public:
     NS_DECL_ISUPPORTS
     NS_DECL_NSIRUNNABLE
 
     AsyncUsageRunnable(nsIURI* aURI,
                        const nsACString& aOrigin,
                        nsIIndexedDatabaseUsageCallback* aCallback);
@@ -321,17 +321,17 @@ private:
     nsCOMPtr<nsIAtom> mId;
     nsRefPtr<AsyncConnectionHelper> mHelper;
     nsTArray<nsCOMPtr<nsIRunnable> > mDelayedRunnables;
     nsTArray<nsRefPtr<IDBDatabase> > mDatabases;
   };
 
   // A callback runnable used by the TransactionPool when it's safe to proceed
   // with a SetVersion/DeleteDatabase/etc.
-  class WaitForTransactionsToFinishRunnable : public nsIRunnable
+  class WaitForTransactionsToFinishRunnable MOZ_FINAL : public nsIRunnable
   {
   public:
     WaitForTransactionsToFinishRunnable(SynchronizedOp* aOp)
     : mOp(aOp)
     {
       NS_ASSERTION(mOp, "Why don't we have a runnable?");
       NS_ASSERTION(mOp->mDatabases.IsEmpty(), "We're here too early!");
       NS_ASSERTION(mOp->mHelper, "What are we supposed to do when we're done?");
@@ -340,17 +340,17 @@ private:
     NS_DECL_ISUPPORTS
     NS_DECL_NSIRUNNABLE
 
   private:
     // The IndexedDatabaseManager holds this alive.
     SynchronizedOp* mOp;
   };
 
-  class AsyncDeleteFileRunnable : public nsIRunnable
+  class AsyncDeleteFileRunnable MOZ_FINAL : public nsIRunnable
   {
   public:
     NS_DECL_ISUPPORTS
     NS_DECL_NSIRUNNABLE
     AsyncDeleteFileRunnable(const nsAString& aFilePath)
     : mFilePath(aFilePath)
     { }
 
--- a/dom/indexedDB/OpenDatabaseHelper.cpp
+++ b/dom/indexedDB/OpenDatabaseHelper.cpp
@@ -848,17 +848,17 @@ UpgradeSchemaFrom7To8(mozIStorageConnect
   NS_ENSURE_SUCCESS(rv, rv);
 
   rv = aConnection->SetSchemaVersion(8);
   NS_ENSURE_SUCCESS(rv, rv);
 
   return NS_OK;
 }
 
-class CompressDataBlobsFunction : public mozIStorageFunction
+class CompressDataBlobsFunction MOZ_FINAL : public mozIStorageFunction
 {
 public:
   NS_DECL_ISUPPORTS
 
   NS_IMETHOD
   OnFunctionCall(mozIStorageValueArray* aArguments,
                  nsIVariant** aResult)
   {
@@ -1090,17 +1090,17 @@ UpgradeSchemaFrom10_0To11_0(mozIStorageC
   NS_ENSURE_SUCCESS(rv, rv);
 
   rv = aConnection->SetSchemaVersion(MakeSchemaVersion(11, 0));
   NS_ENSURE_SUCCESS(rv, rv);
 
   return NS_OK;
 }
 
-class EncodeKeysFunction : public mozIStorageFunction
+class EncodeKeysFunction MOZ_FINAL : public mozIStorageFunction
 {
 public:
   NS_DECL_ISUPPORTS
 
   NS_IMETHOD
   OnFunctionCall(mozIStorageValueArray* aArguments,
                  nsIVariant** aResult)
   {
--- a/dom/indexedDB/TransactionThreadPool.cpp
+++ b/dom/indexedDB/TransactionThreadPool.cpp
@@ -85,17 +85,17 @@ CheckOverlapAndMergeObjectStores(nsTArra
   *aStoresOverlap = overlap;
   return NS_OK;
 }
 
 } // anonymous namespace
 
 BEGIN_INDEXEDDB_NAMESPACE
 
-class FinishTransactionRunnable : public nsIRunnable
+class FinishTransactionRunnable MOZ_FINAL : public nsIRunnable
 {
 public:
   NS_DECL_ISUPPORTS
   NS_DECL_NSIRUNNABLE
 
   inline FinishTransactionRunnable(IDBTransaction* aTransaction,
                                    nsCOMPtr<nsIRunnable>& aFinishRunnable);
 
--- a/dom/indexedDB/TransactionThreadPool.h
+++ b/dom/indexedDB/TransactionThreadPool.h
@@ -86,17 +86,17 @@ public:
   // Abort all transactions, unless they are already in the process of being
   // committed, for aDatabase.
   void AbortTransactionsForDatabase(IDBDatabase* aDatabase);
 
   // Returns true if there are running or pending transactions for aDatabase.
   bool HasTransactionsForDatabase(IDBDatabase* aDatabase);
 
 protected:
-  class TransactionQueue : public nsIRunnable
+  class TransactionQueue MOZ_FINAL : public nsIRunnable
   {
   public:
     NS_DECL_ISUPPORTS
     NS_DECL_NSIRUNNABLE
 
     inline TransactionQueue(IDBTransaction* aTransaction,
                             nsIRunnable* aRunnable);
 
--- a/dom/system/OSFileConstants.cpp
+++ b/dom/system/OSFileConstants.cpp
@@ -149,32 +149,41 @@ static dom::ConstantSpec gLibcProperties
   INT_CONSTANT(EAGAIN),
   INT_CONSTANT(EBADF),
   INT_CONSTANT(EEXIST),
   INT_CONSTANT(EFAULT),
   INT_CONSTANT(EFBIG),
   INT_CONSTANT(EINVAL),
   INT_CONSTANT(EIO),
   INT_CONSTANT(EISDIR),
+#if defined(ELOOP) // not defined with VC9
   INT_CONSTANT(ELOOP),
+#endif // defined(ELOOP)
   INT_CONSTANT(EMFILE),
   INT_CONSTANT(ENAMETOOLONG),
   INT_CONSTANT(ENFILE),
-  INT_CONSTANT(ELOOP),
   INT_CONSTANT(ENOENT),
   INT_CONSTANT(ENOMEM),
   INT_CONSTANT(ENOSPC),
   INT_CONSTANT(ENOTDIR),
   INT_CONSTANT(ENXIO),
+#if defined(EOPNOTSUPP) // not defined with VC 9
   INT_CONSTANT(EOPNOTSUPP),
+#endif // defined(EOPNOTSUPP)
+#if defined(EOVERFLOW) // not defined with VC 9
   INT_CONSTANT(EOVERFLOW),
+#endif // defined(EOVERFLOW)
   INT_CONSTANT(EPERM),
   INT_CONSTANT(ERANGE),
+#if defined(ETIMEDOUT) // not defined with VC 9
   INT_CONSTANT(ETIMEDOUT),
+#endif // defined(ETIMEDOUT)
+#if defined(EWOULDBLOCK) // not defined with VC 9
   INT_CONSTANT(EWOULDBLOCK),
+#endif // defined(EWOULDBLOCK)
   INT_CONSTANT(EXDEV),
 
   PROP_END
 };
 
 
 #if defined(XP_WIN)
 /**
--- a/dom/system/gonk/AudioManager.cpp
+++ b/dom/system/gonk/AudioManager.cpp
@@ -161,16 +161,18 @@ AudioManager::GetPhoneState(PRInt32* aSt
 }
 
 NS_IMETHODIMP
 AudioManager::SetPhoneState(PRInt32 aState)
 {
   if (AudioSystem::setPhoneState(aState)) {
     return NS_ERROR_FAILURE;
   }
+
+  mPhoneState = aState;
   return NS_OK;
 }
 
 //
 // Kids, don't try this at home.  We want this to link and work on
 // both GB and ICS.  Problem is, the symbol exported by audioflinger
 // is different on the two gonks.
 //
--- a/dom/system/gonk/RILContentHelper.js
+++ b/dom/system/gonk/RILContentHelper.js
@@ -20,16 +20,17 @@ const MOBILECONNECTIONINFO_CID =
   Components.ID("{a35cfd39-2d93-4489-ac7d-396475dacb27}");
 
 const RIL_IPC_MSG_NAMES = [
   "RIL:CardStateChanged",
   "RIL:VoiceInfoChanged",
   "RIL:DataInfoChanged",
   "RIL:EnumerateCalls",
   "RIL:CallStateChanged",
+  "RIL:CallError",
 ];
 
 const kVoiceChangedTopic     = "mobile-connection-voice-changed";
 const kDataChangedTopic      = "mobile-connection-data-changed";
 const kCardStateChangedTopic = "mobile-connection-cardstate-changed";
 
 XPCOMUtils.defineLazyServiceGetter(this, "cpmm",
                                    "@mozilla.org/childprocessmessagemanager;1",
@@ -226,32 +227,36 @@ RILContentHelper.prototype = {
         Services.obs.notifyObservers(null, kDataChangedTopic, null);
         break;
       case "RIL:EnumerateCalls":
         this.handleEnumerateCalls(msg.json);
         break;
       case "RIL:CallStateChanged":
         this._deliverTelephonyCallback("callStateChanged",
                                        [msg.json.callIndex, msg.json.state,
-                                        msg.json.number]);
+                                        msg.json.number, msg.json.isActive]);
+        break;
+      case "RIL:CallError":
+        this._deliverTelephonyCallback("notifyError",
+                                        [msg.json.callIndex, 
+                                         msg.json.error]);    	  
+    	break;
     }
   },
 
-  handleEnumerateCalls: function handleEnumerateCalls(message) {
-    debug("handleEnumerateCalls: " + JSON.stringify(message));
+  handleEnumerateCalls: function handleEnumerateCalls(calls) {
+    debug("handleEnumerateCalls: " + JSON.stringify(calls));
     let callback = this._enumerationTelephonyCallbacks.shift();
-    let calls = message.calls;
-    let activeCallIndex = message.activeCallIndex;
     for (let i in calls) {
       let call = calls[i];
       let keepGoing;
       try {
         keepGoing =
           callback.enumerateCallState(call.callIndex, call.state, call.number,
-                                      call.callIndex == activeCallIndex);
+                                      call.isActive);
       } catch (e) {
         debug("callback handler for 'enumerateCallState' threw an " +
               " exception: " + e);
         keepGoing = true;
       }
       if (!keepGoing) {
         break;
       }
--- a/dom/system/gonk/RadioInterfaceLayer.js
+++ b/dom/system/gonk/RadioInterfaceLayer.js
@@ -283,16 +283,19 @@ RadioInterfaceLayer.prototype = {
       case "callDisconnected":
         // This one will handle its own notifications.
         this.handleCallDisconnected(message.call);
         break;
       case "enumerateCalls":
         // This one will handle its own notifications.
         this.handleEnumerateCalls(message.calls);
         break;
+      case "callError":
+        this.handleCallError(message);
+        break;
       case "voiceregistrationstatechange":
         this.updateVoiceConnection(message);
         break;
       case "dataregistrationstatechange":
         this.updateDataConnection(message);
         break;
       case "signalstrengthchange":
         this.handleSignalStrengthChange(message);
@@ -432,83 +435,90 @@ RadioInterfaceLayer.prototype = {
     if (operator != this.radioState.data.operator) {
       this.radioState.data.operator = operator;
       ppmm.sendAsyncMessage("RIL:DataInfoChanged", this.radioState.data);
     }
   },
 
   /**
    * Track the active call and update the audio system as its state changes.
-   *
-   * XXX Needs some more work to support hold/resume.
    */
   _activeCall: null,
   updateCallAudioState: function updateCallAudioState() {
     if (!this._activeCall) {
       // Disable audio.
       gAudioManager.phoneState = nsIAudioManager.PHONE_STATE_NORMAL;
-      debug("No active call, put audio system into PHONE_STATE_NORMAL.");
+      debug("No active call, put audio system into PHONE_STATE_NORMAL: "
+            + gAudioManager.phoneState);
       return;
     }
     switch (this._activeCall.state) {
       case nsIRadioInterfaceLayer.CALL_STATE_INCOMING:
         gAudioManager.phoneState = nsIAudioManager.PHONE_STATE_RINGTONE;
-        debug("Incoming call, put audio system into PHONE_STATE_RINGTONE.");
+        debug("Incoming call, put audio system into PHONE_STATE_RINGTONE: "
+              + gAudioManager.phoneState);
         break;
       case nsIRadioInterfaceLayer.CALL_STATE_DIALING: // Fall through...
       case nsIRadioInterfaceLayer.CALL_STATE_CONNECTED:
         gAudioManager.phoneState = nsIAudioManager.PHONE_STATE_IN_CALL;
         gAudioManager.setForceForUse(nsIAudioManager.USE_COMMUNICATION,
                                      nsIAudioManager.FORCE_NONE);
-        debug("Active call, put audio system into PHONE_STATE_IN_CALL.");
+        debug("Active call, put audio system into PHONE_STATE_IN_CALL: "
+              + gAudioManager.phoneState);
         break;
     }
   },
 
   /**
    * Handle call state changes by updating our current state and the audio
    * system.
    */
   handleCallStateChange: function handleCallStateChange(call) {
     debug("handleCallStateChange: " + JSON.stringify(call));
     call.state = convertRILCallState(call.state);
-    if (call.state == nsIRadioInterfaceLayer.CALL_STATE_DIALING ||
-        call.state == nsIRadioInterfaceLayer.CALL_STATE_ALERTING ||
-        call.state == nsIRadioInterfaceLayer.CALL_STATE_CONNECTED) {
-      // This is now the active call.
+    if (call.isActive) {
       this._activeCall = call;
+    } else if (this._activeCall &&
+               this._activeCall.callIndex == call.callIndex) {
+      // Previously active call is not active now.
+      this._activeCall = null;
     }
     this.updateCallAudioState();
     ppmm.sendAsyncMessage("RIL:CallStateChanged", call);
   },
 
   /**
    * Handle call disconnects by updating our current state and the audio system.
    */
   handleCallDisconnected: function handleCallDisconnected(call) {
     debug("handleCallDisconnected: " + JSON.stringify(call));
-    if (this._activeCall && this._activeCall.callIndex == call.callIndex) {
+    if (call.isActive) {
       this._activeCall = null;
     }
     this.updateCallAudioState();
     call.state = nsIRadioInterfaceLayer.CALL_STATE_DISCONNECTED;
     ppmm.sendAsyncMessage("RIL:CallStateChanged", call);
   },
 
   /**
    * Handle calls delivered in response to a 'enumerateCalls' request.
    */
   handleEnumerateCalls: function handleEnumerateCalls(calls) {
     debug("handleEnumerateCalls: " + JSON.stringify(calls));
-    let activeCallIndex = this._activeCall ? this._activeCall.callIndex : -1;
     for (let i in calls) {
       calls[i].state = convertRILCallState(calls[i].state);
     }
-    ppmm.sendAsyncMessage("RIL:EnumerateCalls",
-                          {calls: calls, activeCallIndex: activeCallIndex});
+    ppmm.sendAsyncMessage("RIL:EnumerateCalls", calls);
+  },
+
+  /**
+   * Handle call error.
+   */
+  handleCallError: function handleCallError(message) {
+    ppmm.sendAsyncMessage("RIL:CallError", message);   
   },
 
   portAddressedSmsApps: null,
   handleSmsReceived: function handleSmsReceived(message) {
     debug("handleSmsReceived: " + JSON.stringify(message));
 
     // Dispatch to registered handler if application port addressing is
     // available. Note that the destination port can possibly be zero when
@@ -733,30 +743,38 @@ RadioInterfaceLayer.prototype = {
   set microphoneMuted(value) {
     if (value == this.microphoneMuted) {
       return;
     }
     gAudioManager.phoneState = value ?
       nsIAudioManager.PHONE_STATE_IN_COMMUNICATION :
       nsIAudioManager.PHONE_STATE_IN_CALL;  //XXX why is this needed?
     gAudioManager.microphoneMuted = value;
+
+    if (!this._activeCall) {
+      gAudioManager.phoneState = nsIAudioManager.PHONE_STATE_NORMAL;
+    }
   },
 
   get speakerEnabled() {
     return (gAudioManager.getForceForUse(nsIAudioManager.USE_COMMUNICATION) ==
             nsIAudioManager.FORCE_SPEAKER);
   },
   set speakerEnabled(value) {
     if (value == this.speakerEnabled) {
       return;
     }
     gAudioManager.phoneState = nsIAudioManager.PHONE_STATE_IN_CALL; // XXX why is this needed?
     let force = value ? nsIAudioManager.FORCE_SPEAKER :
                         nsIAudioManager.FORCE_NONE;
     gAudioManager.setForceForUse(nsIAudioManager.USE_COMMUNICATION, force);
+
+    if (!this._activeCall) {
+      gAudioManager.phoneState = nsIAudioManager.PHONE_STATE_NORMAL;
+    }
   },
 
   /**
    * List of tuples of national language identifier pairs.
    *
    * TODO: Support static/runtime settings, see bug 733331.
    */
   enabledGsmTableTuples: [
--- a/dom/system/gonk/nsIRadioInterfaceLayer.idl
+++ b/dom/system/gonk/nsIRadioInterfaceLayer.idl
@@ -39,32 +39,35 @@
 
 #include "nsISupports.idl"
 #include "nsIMobileConnectionProvider.idl"
 
 interface nsIDOMMozMobileConnectionInfo;
 interface nsIDOMDOMRequest;
 interface nsIDOMWindow;
 
-[scriptable, uuid(03eafd60-d138-4f09-81b4-90cd4996b3c7)]
+[scriptable, uuid(c14c71b8-afba-403b-8320-94593de9380f)]
 interface nsIRILTelephonyCallback : nsISupports
 {
   /**
    * Notified when a telephony call changes state.
    *
    * @param callIndex
    *        Call identifier assigned by the RIL.
    * @param callState
    *        One of the nsIRadioInterfaceLayer::CALL_STATE_* values.
    * @param number
    *        Number of the other party.
+   * @param isActive
+   *        Indicates whether this call is the currently active one.
    */
   void callStateChanged(in unsigned long callIndex,
                         in unsigned short callState,
-                        in AString number);
+                        in AString number,
+                        in boolean isActive);
 
   /**
    * Called when nsIRILContentHelper is asked to enumerate the current
    * telephony call state (nsIRILContentHelper::enumerateCalls). This is
    * called once per call that is currently managed by the RIL.
    *
    * @param callIndex
    *        Call identifier assigned by the RIL.
@@ -76,16 +79,27 @@ interface nsIRILTelephonyCallback : nsIS
    *        Indicates whether this call is the active one.
    *
    * @return true to continue enumeration or false to cancel.
    */
   boolean enumerateCallState(in unsigned long callIndex,
                              in unsigned short callState,
                              in AString number,
                              in boolean isActive);
+
+  /**
+   * Called when RIL error occurs.
+   *
+   * @param callIndex
+   *        Call identifier assigned by the RIL. -1 if no connection
+   * @param error
+   *        Error from RIL.
+   */
+  void notifyError(in long callIndex,
+                   in AString error);
 };
 
 [scriptable, uuid(66a55943-e63b-4731-aece-9c04bfc14019)]
 interface nsIRILDataCallInfo : nsISupports
 {
   readonly attribute unsigned long callState;
   readonly attribute AString cid;
   readonly attribute AString apn;
--- a/dom/system/gonk/ril_consts.js
+++ b/dom/system/gonk/ril_consts.js
@@ -1347,29 +1347,63 @@ const DATACALL_FAIL_ERROR_UNSPECIFIED = 
 // Keep consistent with nsINetworkManager.NETWORK_STATE_*.
 const GECKO_NETWORK_STATE_UNKNOWN = -1;
 const GECKO_NETWORK_STATE_CONNECTING = 0;
 const GECKO_NETWORK_STATE_CONNECTED = 1;
 const GECKO_NETWORK_STATE_SUSPENDED = 2;
 const GECKO_NETWORK_STATE_DISCONNECTING = 3;
 const GECKO_NETWORK_STATE_DISCONNECTED = 4;
 
+const CALL_FAIL_UNOBTAINABLE_NUMBER = 1;
+const CALL_FAIL_NORMAL = 16;
+const CALL_FAIL_BUSY = 17;
+const CALL_FAIL_CONGESTION = 34;
+const CALL_FAIL_ACM_LIMIT_EXCEEDED = 68;
+const CALL_FAIL_CALL_BARRED = 240;
+const CALL_FAIL_FDN_BLOCKED = 241;
+const CALL_FAIL_IMSI_UNKNOWN_IN_VLR = 242;
+const CALL_FAIL_IMEI_NOT_ACCEPTED = 243;
+const CALL_FAIL_ERROR_UNSPECIFIED = 0xffff;
+
 // Other Gecko-specific constants
 const GECKO_RADIOSTATE_UNAVAILABLE   = null;
 const GECKO_RADIOSTATE_OFF           = "off";
 const GECKO_RADIOSTATE_READY         = "ready";
 
 const GECKO_CARDSTATE_UNAVAILABLE    = null;
 const GECKO_CARDSTATE_ABSENT         = "absent";
 const GECKO_CARDSTATE_PIN_REQUIRED   = "pin_required";
 const GECKO_CARDSTATE_PUK_REQUIRED   = "puk_required";
 const GECKO_CARDSTATE_NETWORK_LOCKED = "network_locked";
 const GECKO_CARDSTATE_NOT_READY      = null;
 const GECKO_CARDSTATE_READY          = "ready";
 
+const GECKO_CALL_ERROR_BAD_NUMBER             = "BadNumberError";
+const GECKO_CALL_ERROR_NORMAL_CALL_CLEARING   = "NormalCallClearingError";
+const GECKO_CALL_ERROR_BUSY                   = "BusyError";
+const GECKO_CALL_ERROR_CONGESTION             = "CongestionError";
+const GECKO_CALL_ERROR_INCOMING_CALL_EXCEEDED = "IncomingCallExceededError";
+const GECKO_CALL_ERROR_BARRED                 = "BarredError";
+const GECKO_CALL_ERROR_FDN_BLOCKED            = "FDNBlockedError";
+const GECKO_CALL_ERROR_SUBSCRIBER_UNKNOWN     = "SubscriberUnknownError";
+const GECKO_CALL_ERROR_DEVICE_NOT_ACCEPTED    = "DeviceNotAcceptedError";
+const GECKO_CALL_ERROR_UNSPECIFIED            = "UnspecifiedError";
+
+const RIL_CALL_FAILCAUSE_TO_GECKO_CALL_ERROR = {};
+RIL_CALL_FAILCAUSE_TO_GECKO_CALL_ERROR[CALL_FAIL_UNOBTAINABLE_NUMBER] = GECKO_CALL_ERROR_BAD_NUMBER;
+RIL_CALL_FAILCAUSE_TO_GECKO_CALL_ERROR[CALL_FAIL_NORMAL]              = GECKO_CALL_ERROR_NORMAL_CALL_CLEARING;
+RIL_CALL_FAILCAUSE_TO_GECKO_CALL_ERROR[CALL_FAIL_BUSY]                = GECKO_CALL_ERROR_BUSY;
+RIL_CALL_FAILCAUSE_TO_GECKO_CALL_ERROR[CALL_FAIL_CONGESTION]          = GECKO_CALL_ERROR_CONGESTION;
+RIL_CALL_FAILCAUSE_TO_GECKO_CALL_ERROR[CALL_FAIL_ACM_LIMIT_EXCEEDED]  = GECKO_CALL_ERROR_INCOMING_CALL_EXCEEDED;
+RIL_CALL_FAILCAUSE_TO_GECKO_CALL_ERROR[CALL_FAIL_CALL_BARRED]         = GECKO_CALL_ERROR_BARRED;
+RIL_CALL_FAILCAUSE_TO_GECKO_CALL_ERROR[CALL_FAIL_FDN_BLOCKED]         = GECKO_CALL_ERROR_FDN_BLOCKED;
+RIL_CALL_FAILCAUSE_TO_GECKO_CALL_ERROR[CALL_FAIL_IMSI_UNKNOWN_IN_VLR] = GECKO_CALL_ERROR_SUBSCRIBER_UNKNOWN;
+RIL_CALL_FAILCAUSE_TO_GECKO_CALL_ERROR[CALL_FAIL_IMEI_NOT_ACCEPTED]   = GECKO_CALL_ERROR_DEVICE_NOT_ACCEPTED;
+RIL_CALL_FAILCAUSE_TO_GECKO_CALL_ERROR[CALL_FAIL_ERROR_UNSPECIFIED]   = GECKO_CALL_ERROR_UNSPECIFIED;
+
 const GECKO_RADIO_TECH = [
   null,
   "gprs",
   "edge",
   "umts",
   "is95a",
   "is95b",
   "1xrtt",
--- a/dom/system/gonk/ril_worker.js
+++ b/dom/system/gonk/ril_worker.js
@@ -294,36 +294,40 @@ let Buf = {
     }
     let s = "";
     for (let i = 0; i < string_len; i++) {
       s += String.fromCharCode(this.readUint16());
     }
     // Strings are \0\0 delimited, but that isn't part of the length. And
     // if the string length is even, the delimiter is two characters wide.
     // It's insane, I know.
-    let delimiter = this.readUint16();
-    if (!(string_len & 1)) {
-      delimiter |= this.readUint16();
-    }
-    if (DEBUG) {
-      if (delimiter != 0) {
-        debug("Something's wrong, found string delimiter: " + delimiter);
-      }
-    }
+    this.readStringDelimiter(string_len);
     return s;
   },
 
   readStringList: function readStringList() {
     let num_strings = this.readUint32();
     let strings = [];
     for (let i = 0; i < num_strings; i++) {
       strings.push(this.readString());
     }
     return strings;
   },
+  
+  readStringDelimiter: function readStringDelimiter(length) {
+    let delimiter = this.readUint16();
+    if (!(length & 1)) {
+      delimiter |= this.readUint16();
+    }
+    if (DEBUG) {
+      if (delimiter != 0) {
+        debug("Something's wrong, found string delimiter: " + delimiter);
+      }
+    }
+  },
 
   readParcelSize: function readParcelSize() {
     return this.readUint8Unchecked() << 24 |
            this.readUint8Unchecked() << 16 |
            this.readUint8Unchecked() <<  8 |
            this.readUint8Unchecked();
   },
 
@@ -358,28 +362,32 @@ let Buf = {
     }
     this.writeUint32(value.length);
     for (let i = 0; i < value.length; i++) {
       this.writeUint16(value.charCodeAt(i));
     }
     // Strings are \0\0 delimited, but that isn't part of the length. And
     // if the string length is even, the delimiter is two characters wide.
     // It's insane, I know.
-    this.writeUint16(0);
-    if (!(value.length & 1)) {
-      this.writeUint16(0);
-    }
+    this.writeStringDelimiter(value.length);
   },
 
   writeStringList: function writeStringList(strings) {
     this.writeUint32(strings.length);
     for (let i = 0; i < strings.length; i++) {
       this.writeString(strings[i]);
     }
   },
+  
+  writeStringDelimiter: function writeStringDelimiter(length) {
+    this.writeUint16(0);
+    if (!(length & 1)) {
+      this.writeUint16(0);
+    }
+  },
 
   writeParcelSize: function writeParcelSize(value) {
     /**
      *  Parcel size will always be the first thing in the parcel byte
      *  array, but the last thing written. Store the current index off
      *  to a temporary to be reset after we write the size.
      */
     let currentIndex = this.outgoingIndex;
@@ -639,21 +647,26 @@ let RIL = {
   basebandVersion: null,
 
   /**
    * Network selection mode. 0 for automatic, 1 for manual selection.
    */
   networkSelectionMode: null,
 
   /**
-   * Active calls
+   * Valid calls.
    */
   currentCalls: {},
 
   /**
+   * Current calls length.
+   */
+  currentCallsLength: null,
+
+  /**
    * Existing data calls.
    */
   currentDataCalls: {},
 
   /**
    * Hash map for received multipart sms fragments. Messages are hashed with
    * its sender address and concatenation reference number. Three additional
    * attributes `segmentMaxSeq`, `receivedSegments`, `segments` are inserted.
@@ -894,25 +907,17 @@ let RIL = {
 
       // Dialling Number/SSC String
       let len = GsmPDUHelper.readHexOctet();
       if (len > MSISDN_MAX_NUMBER_SIZE_BYTES) {
         debug("ICC_EF_MSISDN: invalid length of BCD number/SSC contents - " + len);
         return;
       }
       this.iccInfo.MSISDN = GsmPDUHelper.readAddress(len);
-      let delimiter = Buf.readUint16();
-      if (!(length & 1)) {
-        delimiter |= Buf.readUint16();
-      }
-      if (DEBUG) {
-        if (delimiter != 0) {
-          debug("Something's wrong, found string delimiter: " + delimiter);
-        }
-      }
+      Buf.readStringDelimiter(length);
 
       if (DEBUG) debug("MSISDN: " + this.iccInfo.MSISDN);
       if (this.iccInfo.MSISDN) {
         this._handleICCInfoChange();
       }
     }
 
     this.iccIO({
@@ -933,25 +938,17 @@ let RIL = {
    * Read the AD from the ICC.
    */
   getAD: function getAD() {
     function callback() {
       let length = Buf.readUint32();
       // Each octet is encoded into two chars.
       let len = length / 2;
       this.iccInfo.AD = GsmPDUHelper.readHexOctetArray(len);
-      let delimiter = Buf.readUint16();
-      if (!(length & 1)) {
-        delimiter |= Buf.readUint16();
-      }
-      if (DEBUG) {
-        if (delimiter != 0) {
-          debug("Something's wrong, found string delimiter: " + delimiter);
-        }
-      }
+      Buf.readStringDelimiter(length);
 
       if (DEBUG) {
         let str = "";
         for (let i = 0; i < this.iccInfo.AD.length; i++) {
           str += this.iccInfo.AD[i] + ", ";
         }
         debug("AD: " + str);
       }
@@ -1000,25 +997,17 @@ let RIL = {
    * Read the UST from the ICC.
    */
   getUST: function getUST() {
     function callback() {
       let length = Buf.readUint32();
       // Each octet is encoded into two chars.
       let len = length / 2;
       this.iccInfo.UST = GsmPDUHelper.readHexOctetArray(len);
-      let delimiter = Buf.readUint16();
-      if (!(length & 1)) {
-        delimiter |= Buf.readUint16();
-      }
-      if (DEBUG) {
-        if (delimiter != 0) {
-          debug("Something's wrong, found string delimiter: " + delimiter);
-        }
-      }
+      Buf.readStringDelimiter(length);
       
       if (DEBUG) {
         let str = "";
         for (let i = 0; i < this.iccInfo.UST.length; i++) {
           str += this.iccInfo.UST[i] + ", ";
         }
         debug("UST: " + str);
       }
@@ -1455,18 +1444,18 @@ let RIL = {
    */
   getDataCallList: function getDataCallList() {
     Buf.simpleRequest(REQUEST_DATA_CALL_LIST);
   },
 
   /**
    * Get failure casue code for the most recently failed PDP context.
    */
-  getFailCauseCode: function getFailCauseCode() {
-    Buf.simpleRequest(REQUEST_LAST_CALL_FAIL_CAUSE);
+  getFailCauseCode: function getFailCauseCode(options) {
+    Buf.simpleRequest(REQUEST_LAST_CALL_FAIL_CAUSE, options);
   },
 
   /**
    * Check a given number against the list of emergency numbers provided by the RIL.
    *
    * @param number
    *        The number to look up.
    */
@@ -1600,25 +1589,17 @@ let RIL = {
         debug("Expected EF type " + options.type + " but read " + efType);
       }
       return;
     }
 
     // Length of a record, data[14]
     let recordSize = GsmPDUHelper.readHexOctet();
 
-    let delimiter = Buf.readUint16();
-    if (!(length & 1)) {
-      delimiter |= Buf.readUint16();
-    }
-    if (DEBUG) {
-      if (delimiter != 0) {
-        debug("Something's wrong, found string delimiter: " + delimiter);
-      }
-    }
+    Buf.readStringDelimiter(length);
 
     switch (options.type) {
       case EF_TYPE_LINEAR_FIXED:
         // Reuse the options object and update some properties.
         options.command = ICC_COMMAND_READ_RECORD;
         options.p1 = 1; // Record number, always use the 1st record
         options.p2 = READ_RECORD_ABSOLUTE_MODE;
         options.p3 = recordSize;
@@ -1744,34 +1725,44 @@ let RIL = {
 
     if (stateChanged) {
       rs.type = "dataregistrationstatechange";
       this.sendDOMMessage(rs);
     }
   },
 
   /**
-   * Helpers for processing call state.
+   * Helpers for processing call state and handle the active call.
    */
   _processCalls: function _processCalls(newCalls) {
     // Go through the calls we currently have on file and see if any of them
     // changed state. Remove them from the newCalls map as we deal with them
     // so that only new calls remain in the map after we're done.
+    let lastCallsLength = this.currentCallsLength;
+    if (newCalls) {
+      this.currentCallsLength = newCalls.length;
+    } else {
+      this.currentCallsLength = 0;
+    }
+
     for each (let currentCall in this.currentCalls) {
       let newCall;
       if (newCalls) {
         newCall = newCalls[currentCall.callIndex];
         delete newCalls[currentCall.callIndex];
       }
 
       if (newCall) {
         // Call is still valid.
-        if (newCall.state != currentCall.state) {
-          // State has changed.
+        if (newCall.state != currentCall.state ||
+            this.currentCallsLength != lastCallsLength) {
+          // State has changed. Active call may have changed as valid
+          // calls change.
           currentCall.state = newCall.state;
+          currentCall.isActive = this._isActiveCall(currentCall.state);
           this._handleChangedCallState(currentCall);
         }
       } else {
         // Call is no longer reported by the radio. Remove from our map and
         // send disconnected state change.
         delete this.currentCalls[currentCall.callIndex];
         this._handleDisconnectedCall(currentCall);
       }
@@ -1783,16 +1774,17 @@ let RIL = {
         // Format international numbers appropriately.
         if (newCall.number &&
             newCall.toa == TOA_INTERNATIONAL &&
             newCall.number[0] != "+") {
           newCall.number = "+" + newCall.number;
         }
         // Add to our map.
         this.currentCalls[newCall.callIndex] = newCall;
+        newCall.isActive = this._isActiveCall(newCall.state);
         this._handleChangedCallState(newCall);
       }
     }
 
     // Update our mute status. If there is anything in our currentCalls map then
     // we know it's a voice call and we should leave audio on.
     this.muted = Object.getOwnPropertyNames(this.currentCalls).length == 0;
   },
@@ -1804,16 +1796,34 @@ let RIL = {
   },
 
   _handleDisconnectedCall: function _handleDisconnectedCall(disconnectedCall) {
     let message = {type: "callDisconnected",
                    call: disconnectedCall};
     this.sendDOMMessage(message);
   },
 
+  _isActiveCall: function _isActiveCall(callState) {
+    switch (callState) {
+      case CALL_STATE_INCOMING:
+      case CALL_STATE_DIALING:
+      case CALL_STATE_ALERTING:
+      case CALL_STATE_ACTIVE:
+        return true;
+      case CALL_STATE_HOLDING:
+        return false;
+      case CALL_STATE_WAITING:
+        if (this.currentCallsLength == 1) {
+          return true;
+        } else {
+          return false;
+        }
+    }
+  },
+
   _processDataCallList: function _processDataCallList(datacalls) {
     for each (let currentDataCall in this.currentDataCalls) {
       let updatedDataCall;
       if (datacalls) {
         updatedDataCall = datacalls[currentDataCall.cid];
         delete datacalls[currentDataCall.cid];
       }
 
@@ -1877,25 +1887,17 @@ let RIL = {
     // An SMS is a string, but we won't read it as such, so let's read the
     // string length and then defer to PDU parsing helper.
     let messageStringLength = Buf.readUint32();
     if (DEBUG) debug("Got new SMS, length " + messageStringLength);
     let message = GsmPDUHelper.readMessage();
     if (DEBUG) debug(message);
 
     // Read string delimiters. See Buf.readString().
-    let delimiter = Buf.readUint16();
-    if (!(messageStringLength & 1)) {
-      delimiter |= Buf.readUint16();
-    }
-    if (DEBUG) {
-      if (delimiter != 0) {
-        debug("Something's wrong, found string delimiter: " + delimiter);
-      }
-    }
+    Buf.readStringDelimiter(length);
 
     return message;
   },
 
   /**
    * Helper for processing SMS-DELIVER PDUs.
    *
    * @param length
@@ -2249,21 +2251,31 @@ RIL[REQUEST_GET_CURRENT_CALLS] = functio
     if (uusInfoPresent == 1) {
       call.uusInfo = {
         type:     Buf.readUint32(),
         dcs:      Buf.readUint32(),
         userData: null //XXX TODO byte array?!?
       };
     }
 
+    call.isActive = false;
+
     calls[call.callIndex] = call;
   }
+  calls.length = calls_length;
   this._processCalls(calls);
 };
-RIL[REQUEST_DIAL] = null;
+RIL[REQUEST_DIAL] = function REQUEST_DIAL(length, options) {
+  if (options.rilRequestError) {
+    // The connection is not established yet.
+    options.callIndex = -1;
+    this.getFailCauseCode(options);
+    return;
+  }
+};
 RIL[REQUEST_GET_IMSI] = function REQUEST_GET_IMSI(length, options) {
   if (options.rilRequestError) {
     return;
   }
 
   this.iccInfo.IMSI = Buf.readString();
 };
 RIL[REQUEST_HANGUP] = function REQUEST_HANGUP(length, options) {
@@ -2301,17 +2313,30 @@ RIL[REQUEST_SWITCH_HOLDING_AND_ACTIVE] =
 
   // XXX Normally we should get a UNSOLICITED_RESPONSE_CALL_STATE_CHANGED parcel 
   // notifying us of call state changes, but sometimes we don't (have no idea why).
   // this.getCurrentCalls() helps update the call state actively.
   this.getCurrentCalls();
 };
 RIL[REQUEST_CONFERENCE] = null;
 RIL[REQUEST_UDUB] = null;
-RIL[REQUEST_LAST_CALL_FAIL_CAUSE] = null;
+RIL[REQUEST_LAST_CALL_FAIL_CAUSE] = function REQUEST_LAST_CALL_FAIL_CAUSE(length, options) {
+  let num = 0;
+  if (length) {
+    num = Buf.readUint32();
+  }
+  if (!num) {
+    return;
+  }
+
+  let failCause = Buf.readUint32();
+  options.type = "callError";
+  options.error = RIL_CALL_FAILCAUSE_TO_GECKO_CALL_ERROR[failCause];
+  this.sendDOMMessage(options);
+};
 RIL[REQUEST_SIGNAL_STRENGTH] = function REQUEST_SIGNAL_STRENGTH(length, options) {
   if (options.rilRequestError) {
     return;
   }
 
   let obj = {};
 
   // GSM
@@ -3000,36 +3025,16 @@ let GsmPDUHelper = {
       }
       number *= 100;
       number += this.octetToBCD(octet);
     }
     return number;
   },
 
   /**
-   *  Read a string from Buf and convert it to BCD
-   * 
-   *  @return the decimal as a number.
-   */ 
-  readStringAsBCD: function readStringAsBCD() {
-    let length = Buf.readUint32();
-    let bcd = this.readSwappedNibbleBCD(length / 2);
-    let delimiter = Buf.readUint16();
-    if (!(length & 1)) {
-      delimiter |= Buf.readUint16();
-    }
-    if (DEBUG) {
-      if (delimiter != 0) {
-        debug("Something's wrong, found string delimiter: " + delimiter);
-      }
-    }
-    return bcd;
-  },
-
-  /**
    * Write numerical data as swapped nibble BCD.
    *
    * @param data
    *        Data to write (as a string or a number)
    */
   writeSwappedNibbleBCD: function writeSwappedNibbleBCD(data) {
     data = data.toString();
     if (data.length % 2) {
@@ -3471,17 +3476,17 @@ let GsmPDUHelper = {
         break;
       case 0xC0:
         // bits 7..4 = 11xx
         switch (dcs & 0x30) {
           case 0x20:
             encoding = PDU_DCS_MSG_CODING_16BITS_ALPHABET;
             break;
           case 0x30:
-            if (!dcs & 0x04) {
+            if (dcs & 0x04) {
               encoding = PDU_DCS_MSG_CODING_8BITS_ALPHABET;
             }
             break;
         }
         break;
       default:
         // Falling back to default encoding.
         break;
--- a/dom/telephony/Telephony.cpp
+++ b/dom/telephony/Telephony.cpp
@@ -399,17 +399,17 @@ Telephony::StopTone()
   return NS_OK;
 }
 
 NS_IMPL_EVENT_HANDLER(Telephony, incoming)
 NS_IMPL_EVENT_HANDLER(Telephony, callschanged)
 
 NS_IMETHODIMP
 Telephony::CallStateChanged(PRUint32 aCallIndex, PRUint16 aCallState,
-                            const nsAString& aNumber)
+                            const nsAString& aNumber, bool aIsActive)
 {
   NS_ASSERTION(aCallIndex != kOutgoingPlaceholderCallIndex,
                "This should never happen!");
 
   nsRefPtr<TelephonyCall> modifiedCall;
   nsRefPtr<TelephonyCall> outgoingCall;
 
   for (PRUint32 index = 0; index < mCalls.Length(); index++) {
@@ -440,17 +440,17 @@ Telephony::CallStateChanged(PRUint32 aCa
     modifiedCall.swap(outgoingCall);
   }
 
   if (modifiedCall) {
     // Change state.
     modifiedCall->ChangeState(aCallState);
 
     // See if this should replace our current active call.
-    if (aCallState == nsIRadioInterfaceLayer::CALL_STATE_CONNECTED) {
+    if (aIsActive) {
       mActiveCall = modifiedCall;
     }
 
     return NS_OK;
   }
 
   // Didn't know anything about this call before now, must be incoming.
   NS_ASSERTION(aCallState == nsIRadioInterfaceLayer::CALL_STATE_INCOMING,
@@ -495,16 +495,41 @@ Telephony::EnumerateCallState(PRUint32 a
     NS_ASSERTION(!mActiveCall, "Already have an active call!");
     mActiveCall = call;
   }
 
   *aContinue = true;
   return NS_OK;
 }
 
+NS_IMETHODIMP
+Telephony::NotifyError(PRInt32 aCallIndex,
+                        const nsAString& aError)
+{
+  PRInt32 index = -1;
+  PRInt32 length = mCalls.Length();
+
+  // The connection is not established yet, remove the latest call object
+  if (aCallIndex == -1) {
+    if (length > 0) {
+      index = length - 1;
+    }
+  } else {
+    if (aCallIndex < 0 || aCallIndex >= length) {
+      return NS_ERROR_INVALID_ARG;
+    }
+    index = aCallIndex;
+  }
+  if (index != -1) {
+    mCalls[index]->NotifyError(aError);
+  }
+
+  return NS_OK;
+}
+
 nsresult
 NS_NewTelephony(nsPIDOMWindow* aWindow, nsIDOMTelephony** aTelephony)
 {
   NS_ASSERTION(aWindow, "Null pointer!");
 
   // Make sure we're dealing with an inner window.
   nsPIDOMWindow* innerWindow = aWindow->IsInnerWindow() ?
                                aWindow :
--- a/dom/telephony/TelephonyCall.cpp
+++ b/dom/telephony/TelephonyCall.cpp
@@ -38,16 +38,17 @@
  * ***** END LICENSE BLOCK ***** */
 
 #include "TelephonyCall.h"
 
 #include "nsDOMClassInfo.h"
 
 #include "CallEvent.h"
 #include "Telephony.h"
+#include "DOMError.h"
 
 USING_TELEPHONY_NAMESPACE
 
 // static
 already_AddRefed<TelephonyCall>
 TelephonyCall::Create(Telephony* aTelephony, const nsAString& aNumber,
                       PRUint16 aCallState, PRUint32 aCallIndex)
 {
@@ -57,16 +58,17 @@ TelephonyCall::Create(Telephony* aTeleph
 
   nsRefPtr<TelephonyCall> call = new TelephonyCall();
 
   call->BindToOwner(aTelephony->GetOwner());
 
   call->mTelephony = aTelephony;
   call->mNumber = aNumber;
   call->mCallIndex = aCallIndex;
+  call->mError = nsnull;
 
   call->ChangeStateInternal(aCallState, false);
 
   return call.forget();
 }
 
 void
 TelephonyCall::ChangeStateInternal(PRUint16 aCallState, bool aFireEvents)
@@ -145,16 +147,37 @@ TelephonyCall::ChangeStateInternal(PRUin
 
       if (NS_FAILED(event->Dispatch(ToIDOMEventTarget(), stateString))) {
         NS_WARNING("Failed to dispatch specific event!");
       }
     }
   }
 }
 
+void
+TelephonyCall::NotifyError(const nsAString& aError)
+{
+  // Set the error string
+  NS_ASSERTION(!mError, "Already have an error?");
+
+  mError = DOMError::CreateWithName(aError);
+
+  // Do the state transitions
+  ChangeStateInternal(nsIRadioInterfaceLayer::CALL_STATE_DISCONNECTED, true);
+
+  // Notify the error event
+  nsRefPtr<CallEvent> event = CallEvent::Create(this);
+  NS_ASSERTION(event, "This should never fail!");
+
+  if (NS_FAILED(event->Dispatch(ToIDOMEventTarget(),
+                                NS_LITERAL_STRING("error")))) {
+    NS_WARNING("Failed to dispatch error event!");
+  }
+}
+
 NS_IMPL_CYCLE_COLLECTION_CLASS(TelephonyCall)
 
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(TelephonyCall,
                                                   nsDOMEventTargetHelper)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NATIVE_PTR(tmp->mTelephony->ToISupports(),
                                                Telephony, "mTelephony")
   NS_CYCLE_COLLECTION_TRAVERSE_EVENT_HANDLER(statechange)
   NS_CYCLE_COLLECTION_TRAVERSE_EVENT_HANDLER(dialing)
@@ -162,32 +185,34 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_
   NS_CYCLE_COLLECTION_TRAVERSE_EVENT_HANDLER(busy)
   NS_CYCLE_COLLECTION_TRAVERSE_EVENT_HANDLER(connecting)
   NS_CYCLE_COLLECTION_TRAVERSE_EVENT_HANDLER(connected)
   NS_CYCLE_COLLECTION_TRAVERSE_EVENT_HANDLER(disconnecting)
   NS_CYCLE_COLLECTION_TRAVERSE_EVENT_HANDLER(disconnected)
   NS_CYCLE_COLLECTION_TRAVERSE_EVENT_HANDLER(holding)
   NS_CYCLE_COLLECTION_TRAVERSE_EVENT_HANDLER(held)
   NS_CYCLE_COLLECTION_TRAVERSE_EVENT_HANDLER(resuming)
+  NS_CYCLE_COLLECTION_TRAVERSE_EVENT_HANDLER(error)
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 
 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(TelephonyCall,
                                                 nsDOMEventTargetHelper)
   NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mTelephony)
   NS_CYCLE_COLLECTION_UNLINK_EVENT_HANDLER(statechange)
   NS_CYCLE_COLLECTION_UNLINK_EVENT_HANDLER(dialing)
   NS_CYCLE_COLLECTION_UNLINK_EVENT_HANDLER(alerting)
   NS_CYCLE_COLLECTION_UNLINK_EVENT_HANDLER(busy)
   NS_CYCLE_COLLECTION_UNLINK_EVENT_HANDLER(connecting)
   NS_CYCLE_COLLECTION_UNLINK_EVENT_HANDLER(connected)
   NS_CYCLE_COLLECTION_UNLINK_EVENT_HANDLER(disconnecting)
   NS_CYCLE_COLLECTION_UNLINK_EVENT_HANDLER(disconnected)
   NS_CYCLE_COLLECTION_UNLINK_EVENT_HANDLER(holding)
   NS_CYCLE_COLLECTION_UNLINK_EVENT_HANDLER(held)
   NS_CYCLE_COLLECTION_UNLINK_EVENT_HANDLER(resuming)
+  NS_CYCLE_COLLECTION_UNLINK_EVENT_HANDLER(error)
 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
 
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(TelephonyCall)
   NS_INTERFACE_MAP_ENTRY(nsIDOMTelephonyCall)
   NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(TelephonyCall)
 NS_INTERFACE_MAP_END_INHERITING(nsDOMEventTargetHelper)
 
 NS_IMPL_ADDREF_INHERITED(TelephonyCall, nsDOMEventTargetHelper)
@@ -205,16 +230,23 @@ TelephonyCall::GetNumber(nsAString& aNum
 NS_IMETHODIMP
 TelephonyCall::GetState(nsAString& aState)
 {
   aState.Assign(mState);
   return NS_OK;
 }
 
 NS_IMETHODIMP
+TelephonyCall::GetError(nsIDOMDOMError** aError)
+{
+  NS_IF_ADDREF(*aError = mError);
+  return NS_OK;
+}
+
+NS_IMETHODIMP
 TelephonyCall::Answer()
 {
   if (mCallState != nsIRadioInterfaceLayer::CALL_STATE_INCOMING) {
     NS_WARNING("Answer on non-incoming call ignored!");
     return NS_OK;
   }
 
   nsresult rv = mTelephony->RIL()->AnswerCall(mCallIndex);
@@ -284,8 +316,9 @@ NS_IMPL_EVENT_HANDLER(TelephonyCall, ale
 NS_IMPL_EVENT_HANDLER(TelephonyCall, busy)
 NS_IMPL_EVENT_HANDLER(TelephonyCall, connecting)
 NS_IMPL_EVENT_HANDLER(TelephonyCall, connected)
 NS_IMPL_EVENT_HANDLER(TelephonyCall, disconnecting)
 NS_IMPL_EVENT_HANDLER(TelephonyCall, disconnected)
 NS_IMPL_EVENT_HANDLER(TelephonyCall, holding)
 NS_IMPL_EVENT_HANDLER(TelephonyCall, held)
 NS_IMPL_EVENT_HANDLER(TelephonyCall, resuming)
+NS_IMPL_EVENT_HANDLER(TelephonyCall, error)
--- a/dom/telephony/TelephonyCall.h
+++ b/dom/telephony/TelephonyCall.h
@@ -58,21 +58,23 @@ class TelephonyCall : public nsDOMEventT
   NS_DECL_EVENT_HANDLER(busy)
   NS_DECL_EVENT_HANDLER(connecting)
   NS_DECL_EVENT_HANDLER(connected)
   NS_DECL_EVENT_HANDLER(disconnecting)
   NS_DECL_EVENT_HANDLER(disconnected)
   NS_DECL_EVENT_HANDLER(holding)
   NS_DECL_EVENT_HANDLER(held)
   NS_DECL_EVENT_HANDLER(resuming)
+  NS_DECL_EVENT_HANDLER(error)
 
   nsRefPtr<Telephony> mTelephony;
 
   nsString mNumber;
   nsString mState;
+  nsCOMPtr<nsIDOMDOMError> mError;
 
   PRUint32 mCallIndex;
   PRUint16 mCallState;
   bool mLive;
   bool mOutgoing;
 
 public:
   NS_DECL_ISUPPORTS_INHERITED
@@ -125,16 +127,19 @@ public:
   }
 
   bool
   IsOutgoing() const
   {
     return mOutgoing;
   }
 
+  void
+  NotifyError(const nsAString& aError);
+
 private:
   TelephonyCall()
   : mCallIndex(kOutgoingPlaceholderCallIndex),
     mCallState(nsIRadioInterfaceLayer::CALL_STATE_UNKNOWN), mLive(false), mOutgoing(false)
   { }
 
   ~TelephonyCall()
   { }
--- a/dom/telephony/nsIDOMTelephonyCall.idl
+++ b/dom/telephony/nsIDOMTelephonyCall.idl
@@ -33,26 +33,29 @@
  * decision by deleting the provisions above and replace them with the notice
  * and other provisions required by the GPL or the LGPL. If you do not delete
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 #include "nsIDOMEventTarget.idl"
+#include "nsIDOMDOMError.idl"
 
 interface nsIDOMEventListener;
 
-[scriptable, builtinclass, uuid(2fb9502b-2054-4eda-8db7-3726c39144f7)]
+[scriptable, builtinclass, uuid(d902afb1-2e1d-412e-bfa3-cb6a9453a4db)]
 interface nsIDOMTelephonyCall : nsIDOMEventTarget
 {
   readonly attribute DOMString number;
 
   readonly attribute DOMString state;
 
+  readonly attribute nsIDOMDOMError error;
+
   void answer();
   void hangUp();
   void hold();
   void resume();
 
   attribute nsIDOMEventListener onstatechange;
 
   attribute nsIDOMEventListener ondialing;
@@ -60,9 +63,11 @@ interface nsIDOMTelephonyCall : nsIDOMEv
   attribute nsIDOMEventListener onbusy;
   attribute nsIDOMEventListener onconnecting;
   attribute nsIDOMEventListener onconnected;
   attribute nsIDOMEventListener ondisconnecting;
   attribute nsIDOMEventListener ondisconnected;
   attribute nsIDOMEventListener onholding;
   attribute nsIDOMEventListener onheld;
   attribute nsIDOMEventListener onresuming;
+
+  attribute nsIDOMEventListener onerror;
 };
--- a/embedding/android/AndroidManifest.xml.in
+++ b/embedding/android/AndroidManifest.xml.in
@@ -11,17 +11,17 @@
       >
 
     <uses-sdk android:minSdkVersion="5"
               android:targetSdkVersion="11"/>
 
 #ifdef MOZ_TABLETS_ONLY
     <supports-screens android:smallScreens="false"
                       android:normalScreens="false"
-                      android:largeScreens="true"
+                      android:largeScreens="false"
                       android:xlargeScreens="true" />
 #endif
 
     <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
     <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
     <uses-permission android:name="android.permission.INTERNET"/>
     <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
     <uses-permission android:name="com.android.launcher.permission.INSTALL_SHORTCUT"/>
--- a/gfx/2d/Rect.h
+++ b/gfx/2d/Rect.h
@@ -83,16 +83,17 @@ struct Rect :
     explicit Rect(const IntRect& rect) :
         Super(float(rect.x), float(rect.y),
               float(rect.width), float(rect.height)) {}
 
     bool ToIntRect(IntRect *aOut)
     {
       *aOut = IntRect(int32_t(X()), int32_t(Y()),
                     int32_t(Width()), int32_t(Height()));
-      return Rect(aOut->x, aOut->y, aOut->width, aOut->height).IsEqualEdges(*this);
+      return Rect(Float(aOut->x), Float(aOut->y), 
+                  Float(aOut->width), Float(aOut->height)).IsEqualEdges(*this);
     }
 };
 
 }
 }
 
 #endif /* MOZILLA_GFX_RECT_H_ */
--- a/gfx/cairo/cairo/src/cairo-image-surface.c
+++ b/gfx/cairo/cairo/src/cairo-image-surface.c
@@ -4026,31 +4026,42 @@ static cairo_int_status_t
 			     cairo_clip_t		*clip,
 			     int *num_remaining)
 {
     cairo_image_surface_t *surface = abstract_surface;
     cairo_composite_rectangles_t extents;
     composite_glyphs_info_t glyph_info;
     cairo_clip_t local_clip;
     cairo_bool_t have_clip = FALSE;
+#ifdef MOZ_GFX_OPTIMIZE_MOBILE
+    // For performance reasons we don't want to use two passes for overlapping glyphs
+    // on mobile
+    cairo_bool_t overlap = FALSE;
+#else
     cairo_bool_t overlap;
+#endif
     cairo_status_t status;
 
     cairo_rectangle_int_t rect;
     rect.x = rect.y = 0;
     rect.width = surface->width;
     rect.height = surface->height;
 
     status = _cairo_composite_rectangles_init_for_glyphs (&extents,
 							  &rect,
 							  op, source,
 							  scaled_font,
 							  glyphs, num_glyphs,
 							  clip,
+#ifdef MOZ_GFX_OPTIMIZE_MOBILE
+							  NULL);
+#else
 							  &overlap);
+#endif
+
     if (unlikely (status))
 	return status;
 
     if (_cairo_clip_contains_rectangle (clip, &extents.mask))
 	clip = NULL;
 
     if (clip != NULL && extents.is_bounded) {
 	clip = _cairo_clip_init_copy (&local_clip, clip);
--- a/gfx/cairo/libpixman/src/Makefile.in
+++ b/gfx/cairo/libpixman/src/Makefile.in
@@ -180,22 +180,13 @@ include $(topsrcdir)/config/rules.mk
 CFLAGS += -DPACKAGE="mozpixman" -D_USE_MATH_DEFINES
 
 # Disable spammy "missing initializer" GCC warning
 ifdef GNU_CC
 CFLAGS += -Wno-missing-field-initializers
 endif # GNU_CC
 
 # special rule for pixman-mmx to get the right cflags
-pixman-mmx.$(OBJ_SUFFIX): pixman-mmx.c $(GLOBAL_DEPS)
-	$(REPORT_BUILD)
-	@$(MAKE_DEPS_AUTO_CC)
-	$(ELOG) $(CC) $(OUTOPTION)$@ -c $(COMPILE_CFLAGS) $(MMX_CFLAGS) $(_VPATH_SRCS)
+pixman-mmx.$(OBJ_SUFFIX): COMPILE_CFLAGS += $(MMX_CFLAGS)
 
-pixman-sse2.$(OBJ_SUFFIX): pixman-sse2.c $(GLOBAL_DEPS)
-	$(REPORT_BUILD)
-	@$(MAKE_DEPS_AUTO_CC)
-	$(ELOG) $(CC) $(OUTOPTION)$@ -c $(COMPILE_CFLAGS) $(SSE2_CFLAGS) $(_VPATH_SRCS)
+pixman-sse2.$(OBJ_SUFFIX): COMPILE_CFLAGS += $(SSE2_CFLAGS)
 
-pixman-arm-neon.$(OBJ_SUFFIX): pixman-arm-neon.c $(GLOBAL_DEPS)
-	$(REPORT_BUILD)
-	@$(MAKE_DEPS_AUTO_CC)
-	$(ELOG) $(CC) $(OUTOPTION)$@ -c $(COMPILE_CFLAGS) $(ARM_NEON_CFLAGS) $(_VPATH_SRCS)
+pixman-arm-neon.$(OBJ_SUFFIX): COMPILE_CFLAGS += $(ARM_NEON_CFLAGS)
--- a/gfx/qcms/Makefile.in
+++ b/gfx/qcms/Makefile.in
@@ -96,17 +96,11 @@ include $(topsrcdir)/config/rules.mk
 CFLAGS          += -DMOZ_QCMS
 
 # Disable spammy "missing initializer" GCC warning
 ifdef GNU_CC
 CFLAGS += -Wno-missing-field-initializers
 endif # GNU_CC
 
 # special rules for transform-sse*.c to get the right cflags. (taken from pixman/src/Makefile.in)
-transform-sse1.$(OBJ_SUFFIX): transform-sse1.c $(GLOBAL_DEPS)
-	$(REPORT_BUILD)
-	@$(MAKE_DEPS_AUTO_CC)
-	$(ELOG) $(CC) $(OUTOPTION)$@ -c $(COMPILE_CFLAGS) $(SSE1_FLAGS) $(_VPATH_SRCS)
+transform-sse1.$(OBJ_SUFFIX): COMPILE_CFLAGS += $(SSE1_FLAGS)
 
-transform-sse2.$(OBJ_SUFFIX): transform-sse2.c $(GLOBAL_DEPS)
-	$(REPORT_BUILD)
-	@$(MAKE_DEPS_AUTO_CC)
-	$(ELOG) $(CC) $(OUTOPTION)$@ -c $(COMPILE_CFLAGS) $(SSE2_FLAGS) $(_VPATH_SRCS)
+transform-sse2.$(OBJ_SUFFIX): COMPILE_CFLAGS += $(SSE2_FLAGS)
new file mode 100644
--- /dev/null
+++ b/gfx/skia/arm-fixes.patch
@@ -0,0 +1,191 @@
+diff --git a/gfx/skia/include/core/SkMath.h b/gfx/skia/include/core/SkMath.h
+--- a/gfx/skia/include/core/SkMath.h
++++ b/gfx/skia/include/core/SkMath.h
+@@ -148,20 +148,17 @@ static inline bool SkIsPow2(int value) {
+ }
+ 
+ ///////////////////////////////////////////////////////////////////////////////
+ 
+ /** SkMulS16(a, b) multiplies a * b, but requires that a and b are both int16_t.
+     With this requirement, we can generate faster instructions on some
+     architectures.
+ */
+-#if defined(__arm__) \
+-  && !defined(__thumb__) \
+-  && !defined(__ARM_ARCH_4T__) \
+-  && !defined(__ARM_ARCH_5T__)
++#ifdef SK_ARM_HAS_EDSP
+     static inline int32_t SkMulS16(S16CPU x, S16CPU y) {
+         SkASSERT((int16_t)x == x);
+         SkASSERT((int16_t)y == y);
+         int32_t product;
+         asm("smulbb %0, %1, %2 \n"
+             : "=r"(product)
+             : "r"(x), "r"(y)
+             );
+diff --git a/gfx/skia/include/core/SkPostConfig.h b/gfx/skia/include/core/SkPostConfig.h
+--- a/gfx/skia/include/core/SkPostConfig.h
++++ b/gfx/skia/include/core/SkPostConfig.h
+@@ -300,8 +300,53 @@
+ #endif
+ #endif
+ 
+ //////////////////////////////////////////////////////////////////////
+ 
+ #ifndef SK_ALLOW_STATIC_GLOBAL_INITIALIZERS
+ #define SK_ALLOW_STATIC_GLOBAL_INITIALIZERS 1
+ #endif
++
++//////////////////////////////////////////////////////////////////////
++// ARM defines
++
++#if defined(__GNUC__) && defined(__arm__)
++
++#  define SK_ARM_ARCH 3
++
++#  if defined(__ARM_ARCH_4__) || defined(__ARM_ARCH_4T__) \
++   || defined(_ARM_ARCH_4)
++#    undef SK_ARM_ARCH
++#    define SK_ARM_ARCH 4
++#  endif
++
++#  if defined(__ARM_ARCH_5__) || defined(__ARM_ARCH_5T__) \
++   || defined(__ARM_ARCH_5E__) || defined(__ARM_ARCH_5TE__) \
++   || defined(__ARM_ARCH_5TEJ__) || defined(_ARM_ARCH_5)
++#    undef SK_ARM_ARCH
++#    define SK_ARM_ARCH 5
++#  endif
++ 
++#  if defined(__ARM_ARCH_6__) || defined(__ARM_ARCH_6J__) \
++   || defined(__ARM_ARCH_6K__) || defined(__ARM_ARCH_6Z__) \
++   || defined(__ARM_ARCH_6ZK__) || defined(__ARM_ARCH_6T2__) \
++   || defined(__ARM_ARCH_6M__) || defined(_ARM_ARCH_6)
++#    undef SK_ARM_ARCH
++#    define SK_ARM_ARCH 6
++#  endif
++
++#  if defined(__ARM_ARCH_7__) || defined(__ARM_ARCH_7A__) \
++   || defined(__ARM_ARCH_7R__) || defined(__ARM_ARCH_7M__) \
++   || defined(__ARM_ARCH_7EM__) || defined(_ARM_ARCH_7)
++#    undef SK_ARM_ARCH
++#    define SK_ARM_ARCH 7
++#  endif
++
++#  undef SK_ARM_HAS_EDSP
++#  if defined(__thumb2__) && (SK_ARM_ARCH >= 6) \
++   || !defined(__thumb__) \
++   && ((SK_ARM_ARCH > 5) || defined(__ARM_ARCH_5E__) \
++       || defined(__ARM_ARCH_5TE__) || defined(__ARM_ARCH_5TEJ__))
++#    define SK_ARM_HAS_EDSP 1
++#  endif
++
++#endif
+diff --git a/gfx/skia/src/opts/SkBitmapProcState_opts_arm.cpp b/gfx/skia/src/opts/SkBitmapProcState_opts_arm.cpp
+--- a/gfx/skia/src/opts/SkBitmapProcState_opts_arm.cpp
++++ b/gfx/skia/src/opts/SkBitmapProcState_opts_arm.cpp
+@@ -6,17 +6,17 @@
+  * found in the LICENSE file.
+  */
+ 
+ 
+ #include "SkBitmapProcState.h"
+ #include "SkColorPriv.h"
+ #include "SkUtils.h"
+ 
+-#if __ARM_ARCH__ >= 6 && !defined(SK_CPU_BENDIAN)
++#if SK_ARM_ARCH >= 6 && !defined(SK_CPU_BENDIAN)
+ void SI8_D16_nofilter_DX_arm(
+     const SkBitmapProcState& s,
+     const uint32_t* SK_RESTRICT xy,
+     int count,
+     uint16_t* SK_RESTRICT colors) __attribute__((optimize("O1")));
+ 
+ void SI8_D16_nofilter_DX_arm(const SkBitmapProcState& s,
+                              const uint32_t* SK_RESTRICT xy,
+@@ -177,17 +177,17 @@ void SI8_opaque_D32_nofilter_DX_arm(cons
+                       : [xx] "+r" (xx), [count] "+r" (count), [colors] "+r" (colors)
+                       : [table] "r" (table), [srcAddr] "r" (srcAddr)
+                       : "memory", "cc", "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11"
+                       );
+     }
+ 
+     s.fBitmap->getColorTable()->unlockColors(false);
+ }
+-#endif //__ARM_ARCH__ >= 6 && !defined(SK_CPU_BENDIAN)
++#endif // SK_ARM_ARCH >= 6 && !defined(SK_CPU_BENDIAN)
+ 
+ ///////////////////////////////////////////////////////////////////////////////
+ 
+ /*  If we replace a sampleproc, then we null-out the associated shaderproc,
+     otherwise the shader won't even look at the matrix/sampler
+  */
+ void SkBitmapProcState::platformProcs() {
+     bool doFilter = fDoFilter;
+@@ -195,17 +195,17 @@ void SkBitmapProcState::platformProcs() 
+     bool justDx = false;
+ 
+     if (fInvType <= (SkMatrix::kTranslate_Mask | SkMatrix::kScale_Mask)) {
+         justDx = true;
+     }
+ 
+     switch (fBitmap->config()) {
+         case SkBitmap::kIndex8_Config:
+-#if __ARM_ARCH__ >= 6 && !defined(SK_CPU_BENDIAN)
++#if SK_ARM_ARCH >= 6 && !defined(SK_CPU_BENDIAN)
+             if (justDx && !doFilter) {
+ #if 0   /* crashing on android device */
+                 fSampleProc16 = SI8_D16_nofilter_DX_arm;
+                 fShaderProc16 = NULL;
+ #endif
+                 if (isOpaque) {
+                     // this one is only very slighty faster than the C version
+                     fSampleProc32 = SI8_opaque_D32_nofilter_DX_arm;
+diff --git a/gfx/skia/src/opts/SkBlitRow_opts_arm.cpp b/gfx/skia/src/opts/SkBlitRow_opts_arm.cpp
+--- a/gfx/skia/src/opts/SkBlitRow_opts_arm.cpp
++++ b/gfx/skia/src/opts/SkBlitRow_opts_arm.cpp
+@@ -669,18 +669,23 @@ static void __attribute((noinline,optimi
+                   /* Double Loop */
+                   "1:                                \n\t" /* <double loop> */
+                   "ldm    %[src]!, {r5, r6}          \n\t" /* loading src pointers into r5 and r6 */
+                   "ldm    %[dst], {r7, r8}           \n\t" /* loading dst pointers into r7 and r8 */
+ 
+                   /* dst1_scale and dst2_scale*/
+                   "lsr    r9, r5, #24                \n\t" /* src >> 24 */
+                   "lsr    r10, r6, #24               \n\t" /* src >> 24 */
++#ifdef SK_ARM_HAS_EDSP
+                   "smulbb r9, r9, %[alpha]           \n\t" /* r9 = SkMulS16 r9 with src_scale */
+                   "smulbb r10, r10, %[alpha]         \n\t" /* r10 = SkMulS16 r10 with src_scale */
++#else
++                  "mul    r9, r9, %[alpha]           \n\t" /* r9 = SkMulS16 r9 with src_scale */
++                  "mul    r10, r10, %[alpha]         \n\t" /* r10 = SkMulS16 r10 with src_scale */
++#endif
+                   "lsr    r9, r9, #8                 \n\t" /* r9 >> 8 */
+                   "lsr    r10, r10, #8               \n\t" /* r10 >> 8 */
+                   "rsb    r9, r9, #256               \n\t" /* dst1_scale = r9 = 255 - r9 + 1 */
+                   "rsb    r10, r10, #256             \n\t" /* dst2_scale = r10 = 255 - r10 + 1 */
+ 
+                   /* ---------------------- */
+ 
+                   /* src1, src1_scale */
+@@ -739,17 +744,21 @@ static void __attribute((noinline,optimi
+                                                            /* else get into the single loop */
+                   /* Single Loop */
+                   "2:                                \n\t" /* <single loop> */
+                   "ldr    r5, [%[src]], #4           \n\t" /* loading src pointer into r5: r5=src */
+                   "ldr    r7, [%[dst]]               \n\t" /* loading dst pointer into r7: r7=dst */
+ 
+                   "lsr    r6, r5, #24                \n\t" /* src >> 24 */
+                   "and    r8, r12, r5, lsr #8        \n\t" /* ag = r8 = r5 masked by r12 lsr by #8 */
++#ifdef SK_ARM_HAS_EDSP
+                   "smulbb r6, r6, %[alpha]           \n\t" /* r6 = SkMulS16 with src_scale */
++#else
++                  "mul    r6, r6, %[alpha]           \n\t" /* r6 = SkMulS16 with src_scale */
++#endif
+                   "and    r9, r12, r5                \n\t" /* rb = r9 = r5 masked by r12 */
+                   "lsr    r6, r6, #8                 \n\t" /* r6 >> 8 */
+                   "mul    r8, r8, %[alpha]           \n\t" /* ag = r8 times scale */
+                   "rsb    r6, r6, #256               \n\t" /* r6 = 255 - r6 + 1 */
+ 
+                   /* src, src_scale */
+                   "mul    r9, r9, %[alpha]           \n\t" /* rb = r9 times scale */
+                   "and    r8, r8, r12, lsl #8        \n\t" /* ag masked by reverse mask (r12) */
--- a/gfx/skia/include/core/SkMath.h
+++ b/gfx/skia/include/core/SkMath.h
@@ -148,20 +148,17 @@ static inline bool SkIsPow2(int value) {
 }
 
 ///////////////////////////////////////////////////////////////////////////////
 
 /** SkMulS16(a, b) multiplies a * b, but requires that a and b are both int16_t.
     With this requirement, we can generate faster instructions on some
     architectures.
 */
-#if defined(__arm__) \
-  && !defined(__thumb__) \
-  && !defined(__ARM_ARCH_4T__) \
-  && !defined(__ARM_ARCH_5T__)
+#ifdef SK_ARM_HAS_EDSP
     static inline int32_t SkMulS16(S16CPU x, S16CPU y) {
         SkASSERT((int16_t)x == x);
         SkASSERT((int16_t)y == y);
         int32_t product;
         asm("smulbb %0, %1, %2 \n"
             : "=r"(product)
             : "r"(x), "r"(y)
             );
--- a/gfx/skia/include/core/SkPostConfig.h
+++ b/gfx/skia/include/core/SkPostConfig.h
@@ -300,8 +300,53 @@
 #endif
 #endif
 
 //////////////////////////////////////////////////////////////////////
 
 #ifndef SK_ALLOW_STATIC_GLOBAL_INITIALIZERS
 #define SK_ALLOW_STATIC_GLOBAL_INITIALIZERS 1
 #endif
+
+//////////////////////////////////////////////////////////////////////
+// ARM defines
+
+#if defined(__GNUC__) && defined(__arm__)
+
+#  define SK_ARM_ARCH 3
+
+#  if defined(__ARM_ARCH_4__) || defined(__ARM_ARCH_4T__) \
+   || defined(_ARM_ARCH_4)
+#    undef SK_ARM_ARCH
+#    define SK_ARM_ARCH 4
+#  endif
+
+#  if defined(__ARM_ARCH_5__) || defined(__ARM_ARCH_5T__) \
+   || defined(__ARM_ARCH_5E__) || defined(__ARM_ARCH_5TE__) \
+   || defined(__ARM_ARCH_5TEJ__) || defined(_ARM_ARCH_5)
+#    undef SK_ARM_ARCH
+#    define SK_ARM_ARCH 5
+#  endif
+ 
+#  if defined(__ARM_ARCH_6__) || defined(__ARM_ARCH_6J__) \
+   || defined(__ARM_ARCH_6K__) || defined(__ARM_ARCH_6Z__) \
+   || defined(__ARM_ARCH_6ZK__) || defined(__ARM_ARCH_6T2__) \
+   || defined(__ARM_ARCH_6M__) || defined(_ARM_ARCH_6)
+#    undef SK_ARM_ARCH
+#    define SK_ARM_ARCH 6
+#  endif
+
+#  if defined(__ARM_ARCH_7__) || defined(__ARM_ARCH_7A__) \
+   || defined(__ARM_ARCH_7R__) || defined(__ARM_ARCH_7M__) \
+   || defined(__ARM_ARCH_7EM__) || defined(_ARM_ARCH_7)
+#    undef SK_ARM_ARCH
+#    define SK_ARM_ARCH 7
+#  endif
+
+#  undef SK_ARM_HAS_EDSP
+#  if defined(__thumb2__) && (SK_ARM_ARCH >= 6) \
+   || !defined(__thumb__) \
+   && ((SK_ARM_ARCH > 5) || defined(__ARM_ARCH_5E__) \
+       || defined(__ARM_ARCH_5TE__) || defined(__ARM_ARCH_5TEJ__))
+#    define SK_ARM_HAS_EDSP 1
+#  endif
+
+#endif
--- a/gfx/skia/src/opts/SkBitmapProcState_opts_arm.cpp
+++ b/gfx/skia/src/opts/SkBitmapProcState_opts_arm.cpp
@@ -6,17 +6,17 @@
  * found in the LICENSE file.
  */
 
 
 #include "SkBitmapProcState.h"
 #include "SkColorPriv.h"
 #include "SkUtils.h"
 
-#if __ARM_ARCH__ >= 6 && !defined(SK_CPU_BENDIAN)
+#if SK_ARM_ARCH >= 6 && !defined(SK_CPU_BENDIAN)
 void SI8_D16_nofilter_DX_arm(
     const SkBitmapProcState& s,
     const uint32_t* SK_RESTRICT xy,
     int count,
     uint16_t* SK_RESTRICT colors) __attribute__((optimize("O1")));
 
 void SI8_D16_nofilter_DX_arm(const SkBitmapProcState& s,
                              const uint32_t* SK_RESTRICT xy,
@@ -177,17 +177,17 @@ void SI8_opaque_D32_nofilter_DX_arm(cons
                       : [xx] "+r" (xx), [count] "+r" (count), [colors] "+r" (colors)
                       : [table] "r" (table), [srcAddr] "r" (srcAddr)
                       : "memory", "cc", "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11"
                       );
     }
 
     s.fBitmap->getColorTable()->unlockColors(false);
 }
-#endif //__ARM_ARCH__ >= 6 && !defined(SK_CPU_BENDIAN)
+#endif // SK_ARM_ARCH >= 6 && !defined(SK_CPU_BENDIAN)
 
 ///////////////////////////////////////////////////////////////////////////////
 
 /*  If we replace a sampleproc, then we null-out the associated shaderproc,
     otherwise the shader won't even look at the matrix/sampler
  */
 void SkBitmapProcState::platformProcs() {
     bool doFilter = fDoFilter;
@@ -195,17 +195,17 @@ void SkBitmapProcState::platformProcs() 
     bool justDx = false;
 
     if (fInvType <= (SkMatrix::kTranslate_Mask | SkMatrix::kScale_Mask)) {
         justDx = true;
     }
 
     switch (fBitmap->config()) {
         case SkBitmap::kIndex8_Config:
-#if __ARM_ARCH__ >= 6 && !defined(SK_CPU_BENDIAN)
+#if SK_ARM_ARCH >= 6 && !defined(SK_CPU_BENDIAN)
             if (justDx && !doFilter) {
 #if 0   /* crashing on android device */
                 fSampleProc16 = SI8_D16_nofilter_DX_arm;
                 fShaderProc16 = NULL;
 #endif
                 if (isOpaque) {
                     // this one is only very slighty faster than the C version
                     fSampleProc32 = SI8_opaque_D32_nofilter_DX_arm;
--- a/gfx/skia/src/opts/SkBlitRow_opts_arm.cpp
+++ b/gfx/skia/src/opts/SkBlitRow_opts_arm.cpp
@@ -669,18 +669,23 @@ static void __attribute((noinline,optimi
                   /* Double Loop */
                   "1:                                \n\t" /* <double loop> */
                   "ldm    %[src]!, {r5, r6}          \n\t" /* loading src pointers into r5 and r6 */
                   "ldm    %[dst], {r7, r8}           \n\t" /* loading dst pointers into r7 and r8 */
 
                   /* dst1_scale and dst2_scale*/
                   "lsr    r9, r5, #24                \n\t" /* src >> 24 */
                   "lsr    r10, r6, #24               \n\t" /* src >> 24 */
+#ifdef SK_ARM_HAS_EDSP
                   "smulbb r9, r9, %[alpha]           \n\t" /* r9 = SkMulS16 r9 with src_scale */
                   "smulbb r10, r10, %[alpha]         \n\t" /* r10 = SkMulS16 r10 with src_scale */
+#else
+                  "mul    r9, r9, %[alpha]           \n\t" /* r9 = SkMulS16 r9 with src_scale */
+                  "mul    r10, r10, %[alpha]         \n\t" /* r10 = SkMulS16 r10 with src_scale */
+#endif
                   "lsr    r9, r9, #8                 \n\t" /* r9 >> 8 */
                   "lsr    r10, r10, #8               \n\t" /* r10 >> 8 */
                   "rsb    r9, r9, #256               \n\t" /* dst1_scale = r9 = 255 - r9 + 1 */
                   "rsb    r10, r10, #256             \n\t" /* dst2_scale = r10 = 255 - r10 + 1 */
 
                   /* ---------------------- */
 
                   /* src1, src1_scale */
@@ -739,17 +744,21 @@ static void __attribute((noinline,optimi
                                                            /* else get into the single loop */
                   /* Single Loop */
                   "2:                                \n\t" /* <single loop> */
                   "ldr    r5, [%[src]], #4           \n\t" /* loading src pointer into r5: r5=src */
                   "ldr    r7, [%[dst]]               \n\t" /* loading dst pointer into r7: r7=dst */
 
                   "lsr    r6, r5, #24                \n\t" /* src >> 24 */
                   "and    r8, r12, r5, lsr #8        \n\t" /* ag = r8 = r5 masked by r12 lsr by #8 */
+#ifdef SK_ARM_HAS_EDSP
                   "smulbb r6, r6, %[alpha]           \n\t" /* r6 = SkMulS16 with src_scale */
+#else
+                  "mul    r6, r6, %[alpha]           \n\t" /* r6 = SkMulS16 with src_scale */
+#endif
                   "and    r9, r12, r5                \n\t" /* rb = r9 = r5 masked by r12 */
                   "lsr    r6, r6, #8                 \n\t" /* r6 >> 8 */
                   "mul    r8, r8, %[alpha]           \n\t" /* ag = r8 times scale */
                   "rsb    r6, r6, #256               \n\t" /* r6 = 255 - r6 + 1 */
 
                   /* src, src_scale */
                   "mul    r9, r9, %[alpha]           \n\t" /* rb = r9 times scale */
                   "and    r8, r8, r12, lsl #8        \n\t" /* ag masked by reverse mask (r12) */
--- a/gfx/skia/update.sh
+++ b/gfx/skia/update.sh
@@ -109,8 +109,10 @@ patch -p3 < user-config.patch
 # Bug 715718 - Unitialized variable 'margin' in compute_bounds : SkDraw.cpp
 patch -p3 < uninitialized-margin.patch
 # Bug 722011 - Fix comma at end of enum list
 patch -p3 < fix-comma-end-enum-list.patch
 # Bug 719872 - Fix crash on Android by reverting to older FontHost impl
 patch -p3 < old-android-fonthost.patch
 # Bug 731384 - Fix compile errors on older versions of clang
 patch -p3 < SkPostConfig.patch
+# Bug 751814 - Various Skia fixes for ARM without EDSP and ARMv6+
+patch -p3 < arm-fixes.patch
--- a/gfx/src/nsRect.h
+++ b/gfx/src/nsRect.h
@@ -85,42 +85,56 @@ struct NS_GFX nsRect :
   // x & y is capped at the minimum value nscoord_MIN and
   // width & height is capped at the maximum value nscoord_MAX.
   void SaturatingInflate(const nsMargin& aMargin)
   {
 #ifdef NS_COORD_IS_FLOAT
     Inflate(aMargin);
 #else
     PRInt64 nx = PRInt64(x) - aMargin.left;
-    if (nx < nscoord_MIN) {
+    PRInt64 w = PRInt64(width) + PRInt64(aMargin.left) + aMargin.right;
+    if (NS_UNLIKELY(w > nscoord_MAX)) {
+      NS_WARNING("Overflowed nscoord_MAX in conversion to nscoord width");
+      PRInt64 xdiff = nx - nscoord_MIN / 2;
+      if (xdiff < 0) {
+        // Clamp huge negative x to nscoord_MIN / 2 and try again.
+        nx = nscoord_MIN / 2;
+        w += xdiff;
+      }
+      if (NS_UNLIKELY(w > nscoord_MAX)) {
+        w = nscoord_MAX;
+      }
+    }
+    width = nscoord(w);
+    if (NS_UNLIKELY(nx < nscoord_MIN)) {
       NS_WARNING("Underflowed nscoord_MIN in conversion to nscoord x");
       nx = nscoord_MIN;
     }
     x = nscoord(nx);
 
     PRInt64 ny = PRInt64(y) - aMargin.top;
-    if (ny < nscoord_MIN) {
+    PRInt64 h = PRInt64(height) + PRInt64(aMargin.top) + aMargin.bottom;
+    if (NS_UNLIKELY(h > nscoord_MAX)) {
+      NS_WARNING("Overflowed nscoord_MAX in conversion to nscoord height");
+      PRInt64 ydiff = ny - nscoord_MIN / 2;
+      if (ydiff < 0) {
+        // Clamp huge negative y to nscoord_MIN / 2 and try again.
+        ny = nscoord_MIN / 2;
+        h += ydiff;
+      }
+      if (NS_UNLIKELY(h > nscoord_MAX)) {
+        h = nscoord_MAX;
+      }
+    }
+    height = nscoord(h);
+    if (NS_UNLIKELY(ny < nscoord_MIN)) {
       NS_WARNING("Underflowed nscoord_MIN in conversion to nscoord y");
       ny = nscoord_MIN;
     }
     y = nscoord(ny);
-
-    PRInt64 w = PRInt64(width) + PRInt64(aMargin.left) + aMargin.right;
-    if (w > nscoord_MAX) {
-      NS_WARNING("Overflowed nscoord_MAX in conversion to nscoord width");
-      w = nscoord_MAX;
-    }
-    width = nscoord(w);
-
-    PRInt64 h = PRInt64(height) + PRInt64(aMargin.top) + aMargin.bottom;
-    if (h > nscoord_MAX) {
-      NS_WARNING("Overflowed nscoord_MAX in conversion to nscoord height");
-      h = nscoord_MAX;
-    }
-    height = nscoord(h);
 #endif
   }
 
   // We have saturating versions of all the Union methods. These avoid
   // overflowing nscoord values in the 'width' and 'height' fields by
   // clamping the width and height values to nscoord_MAX if necessary.
 
   nsRect SaturatingUnion(const nsRect& aRect) const
@@ -136,33 +150,64 @@ struct NS_GFX nsRect :
 
   nsRect SaturatingUnionEdges(const nsRect& aRect) const
   {
 #ifdef NS_COORD_IS_FLOAT
     return UnionEdges(aRect);
 #else
     nsRect result;
     result.x = NS_MIN(aRect.x, x);
-    result.y = NS_MIN(aRect.y, y);
     PRInt64 w = NS_MAX(PRInt64(aRect.x) + aRect.width, PRInt64(x) + width) - result.x;
-    PRInt64 h = NS_MAX(PRInt64(aRect.y) + aRect.height, PRInt64(y) + height) - result.y;
-    if (w > nscoord_MAX) {
+    if (NS_UNLIKELY(w > nscoord_MAX)) {
       NS_WARNING("Overflowed nscoord_MAX in conversion to nscoord width");
-      w = nscoord_MAX;
-    }
-    if (h > nscoord_MAX) {
-      NS_WARNING("Overflowed nscoord_MAX in conversion to nscoord height");
-      h = nscoord_MAX;
+      // Clamp huge negative x to nscoord_MIN / 2 and try again.
+      result.x = NS_MAX(result.x, nscoord_MIN / 2);
+      w = NS_MAX(PRInt64(aRect.x) + aRect.width, PRInt64(x) + width) - result.x;
+      if (NS_UNLIKELY(w > nscoord_MAX)) {
+        w = nscoord_MAX;
+      }
     }
     result.width = nscoord(w);
+
+    result.y = NS_MIN(aRect.y, y);
+    PRInt64 h = NS_MAX(PRInt64(aRect.y) + aRect.height, PRInt64(y) + height) - result.y;
+    if (NS_UNLIKELY(h > nscoord_MAX)) {
+      NS_WARNING("Overflowed nscoord_MAX in conversion to nscoord height");
+      // Clamp huge negative y to nscoord_MIN / 2 and try again.
+      result.y = NS_MAX(result.y, nscoord_MIN / 2);
+      h = NS_MAX(PRInt64(aRect.y) + aRect.height, PRInt64(y) + height) - result.y;
+      if (NS_UNLIKELY(h > nscoord_MAX)) {
+        h = nscoord_MAX;
+      }
+    }
     result.height = nscoord(h);
     return result;
 #endif
   }
 
+#ifndef NS_COORD_IS_FLOAT
+  // Make all nsRect Union methods be saturating.
+  nsRect UnionEdges(const nsRect& aRect) const
+  {
+    return SaturatingUnionEdges(aRect);
+  }
+  void UnionRectEdges(const nsRect& aRect1, const nsRect& aRect2)
+  {
+    *this = aRect1.UnionEdges(aRect2);
+  }
+  nsRect Union(const nsRect& aRect) const
+  {
+    return SaturatingUnion(aRect);
+  }
+  void UnionRect(const nsRect& aRect1, const nsRect& aRect2)
+  {
+    *this = aRect1.Union(aRect2);
+  }
+#endif
+
   void SaturatingUnionRect(const nsRect& aRect1, const nsRect& aRect2)
   {
     *this = aRect1.SaturatingUnion(aRect2);
   }
   void SaturatingUnionRectEdges(const nsRect& aRect1, const nsRect& aRect2)
   {
     *this = aRect1.SaturatingUnionEdges(aRect2);
   }
--- a/js/src/Makefile.in
+++ b/js/src/Makefile.in
@@ -406,17 +406,17 @@ VPATH += 	$(srcdir)/assembler \
 
 CPPSRCS += 	ExecutableAllocator.cpp \
 		PageBlock.cpp \
 		YarrInterpreter.cpp \
 		YarrPattern.cpp \
 		YarrSyntaxChecker.cpp \
 		$(NONE)
 
-ifdef MOZ_DEBUG
+ifdef ENABLE_METHODJIT_SPEW
 CPPSRCS += Logging.cpp
 endif
 
 ifneq (,$(filter-out OS2 WINNT,$(OS_ARCH)))
 CPPSRCS += ExecutableAllocatorPosix.cpp \
            OSAllocatorPosix.cpp \
            $(NONE)
 endif
@@ -548,19 +548,21 @@ endif
 EXTRA_DSO_LDOPTS += $(NSPR_LIBS)
 
 ifndef BUILD_OPT
 MOCHAFILE	= 1
 endif
 
 # Define keyword generator before rules.mk, see bug 323979 comment 50
 
+HOST_CPPSRCS += jskwgen.cpp
 HOST_SIMPLE_PROGRAMS += host_jskwgen$(HOST_BIN_SUFFIX)
 GARBAGE += jsautokw.h host_jskwgen$(HOST_BIN_SUFFIX)
 
+HOST_CPPSRCS += jsoplengen.cpp
 HOST_SIMPLE_PROGRAMS += host_jsoplengen$(HOST_BIN_SUFFIX)
 GARBAGE += jsautooplen.h host_jsoplengen$(HOST_BIN_SUFFIX)
 
 USE_HOST_CXX = 1
 
 ifdef HAVE_DTRACE
 ifneq ($(OS_ARCH),Darwin)
 DTRACE_PROBE_OBJ = $(LIBRARY_NAME)-dtrace.$(OBJ_SUFFIX)
--- a/js/src/config/autoconf.mk.in
+++ b/js/src/config/autoconf.mk.in
@@ -324,18 +324,18 @@ GCC_VERSION	= @GCC_VERSION@
 UNIVERSAL_BINARY= @UNIVERSAL_BINARY@
 MOZ_CAN_RUN_PROGRAMS = @MOZ_CAN_RUN_PROGRAMS@
 HAVE_DTRACE= @HAVE_DTRACE@
 
 VISIBILITY_FLAGS = @VISIBILITY_FLAGS@
 WRAP_SYSTEM_INCLUDES = @WRAP_SYSTEM_INCLUDES@
 
 ENABLE_ION = @ENABLE_ION@
-ENABLE_TRACEJIT = @ENABLE_TRACEJIT@
 ENABLE_METHODJIT = @ENABLE_METHODJIT@
+ENABLE_METHODJIT_SPEW = @ENABLE_METHODJIT_SPEW@
 HAVE_ARM_SIMD= @HAVE_ARM_SIMD@
 
 JS_SHARED_LIBRARY = @JS_SHARED_LIBRARY@
 HAVE_LINUX_PERF_EVENT_H = @HAVE_LINUX_PERF_EVENT_H@
 
 MOZ_METRO	= @MOZ_METRO@
 
 MOZ_ASAN = @MOZ_ASAN@
--- a/js/src/config/rules.mk
+++ b/js/src/config/rules.mk
@@ -356,35 +356,35 @@ endif
 ifdef MOZ_PROFILE_GENERATE
 SIMPLE_PROGRAMS :=
 endif
 
 ifndef TARGETS
 TARGETS			= $(LIBRARY) $(SHARED_LIBRARY) $(PROGRAM) $(SIMPLE_PROGRAMS) $(HOST_LIBRARY) $(HOST_PROGRAM) $(HOST_SIMPLE_PROGRAMS) $(JAVA_LIBRARY)
 endif
 
+COBJS = $(CSRCS:.c=.$(OBJ_SUFFIX))
+SOBJS = $(SSRCS:.S=.$(OBJ_SUFFIX))
+CCOBJS = $(patsubst %.cc,%.$(OBJ_SUFFIX),$(filter %.cc,$(CPPSRCS)))
+CPPOBJS = $(patsubst %.cpp,%.$(OBJ_SUFFIX),$(filter %.cpp,$(CPPSRCS)))
+CMOBJS = $(CMSRCS:.m=.$(OBJ_SUFFIX))
+CMMOBJS = $(CMMSRCS:.mm=.$(OBJ_SUFFIX))
+ASOBJS = $(ASFILES:.$(ASM_SUFFIX)=.$(OBJ_SUFFIX))
 ifndef OBJS
-_OBJS			= \
-	$(JRI_STUB_CFILES) \
-	$(addsuffix .$(OBJ_SUFFIX), $(JMC_GEN)) \
-	$(CSRCS:.c=.$(OBJ_SUFFIX)) \
-	$(SSRCS:.S=.$(OBJ_SUFFIX)) \
-	$(patsubst %.cc,%.$(OBJ_SUFFIX),$(CPPSRCS:.cpp=.$(OBJ_SUFFIX))) \
-	$(CMSRCS:.m=.$(OBJ_SUFFIX)) \
-	$(CMMSRCS:.mm=.$(OBJ_SUFFIX)) \
-	$(ASFILES:.$(ASM_SUFFIX)=.$(OBJ_SUFFIX))
-OBJS	= $(strip $(_OBJS))
+_OBJS = $(COBJS) $(SOBJS) $(CCOBJS) $(CPPOBJS) $(CMOBJS) $(CMMOBJS) $(ASOBJS)
+OBJS = $(strip $(_OBJS))
 endif
 
+HOST_COBJS = $(addprefix host_,$(HOST_CSRCS:.c=.$(OBJ_SUFFIX)))
+HOST_CCOBJS = $(addprefix host_,$(patsubst %.cc,%.$(OBJ_SUFFIX),$(filter %.cc,$(HOST_CPPSRCS))))
+HOST_CPPOBJS = $(addprefix host_,$(patsubst %.cpp,%.$(OBJ_SUFFIX),$(filter %.cpp,$(HOST_CPPSRCS))))
+HOST_CMOBJS = $(addprefix host_,$(HOST_CMSRCS:.m=.$(OBJ_SUFFIX)))
+HOST_CMMOBJS = $(addprefix host_,$(HOST_CMMSRCS:.mm=.$(OBJ_SUFFIX)))
 ifndef HOST_OBJS
-_HOST_OBJS		= \
-        $(addprefix host_,$(HOST_CSRCS:.c=.$(OBJ_SUFFIX))) \
-	$(addprefix host_,$(patsubst %.cc,%.$(OBJ_SUFFIX),$(HOST_CPPSRCS:.cpp=.$(OBJ_SUFFIX)))) \
-	$(addprefix host_,$(HOST_CMSRCS:.m=.$(OBJ_SUFFIX))) \
-	$(addprefix host_,$(HOST_CMMSRCS:.mm=.$(OBJ_SUFFIX)))
+_HOST_OBJS = $(HOST_COBJS) $(HOST_CCOBJS) $(HOST_CPPOBJS) $(HOST_CMOBJS) $(HOST_CMMOBJS)
 HOST_OBJS = $(strip $(_HOST_OBJS))
 endif
 
 LIBOBJS			:= $(addprefix \", $(OBJS))
 LIBOBJS			:= $(addsuffix \", $(LIBOBJS))
 
 ifndef MOZ_AUTO_DEPS
 ifneq (,$(OBJS)$(XPIDLSRCS)$(SIMPLE_PROGRAMS))
@@ -1085,42 +1085,37 @@ MAKE_DEPS_AUTO_CXX = $(MAKE_DEPS_AUTO)
 
 endif # COMPILER_DEPEND
 
 endif # MOZ_AUTO_DEPS
 
 $(OBJS) $(HOST_OBJS): $(GLOBAL_DEPS)
 
 # Rules for building native targets must come first because of the host_ prefix
-host_%.$(OBJ_SUFFIX): %.c
+$(HOST_COBJS): host_%.$(OBJ_SUFFIX): %.c
 	$(REPORT_BUILD)
 	$(ELOG) $(HOST_CC) $(HOST_OUTOPTION)$@ -c $(HOST_CFLAGS) $(INCLUDES) $(NSPR_CFLAGS) $(_VPATH_SRCS)
 
-host_%.$(OBJ_SUFFIX): %.cpp
-	$(REPORT_BUILD)
-	$(ELOG) $(HOST_CXX) $(HOST_OUTOPTION)$@ -c $(HOST_CXXFLAGS) $(INCLUDES) $(NSPR_CFLAGS) $(_VPATH_SRCS)
-
-host_%.$(OBJ_SUFFIX): %.cc
+$(HOST_CPPOBJS): host_%.$(OBJ_SUFFIX): %.cpp
 	$(REPORT_BUILD)
 	$(ELOG) $(HOST_CXX) $(HOST_OUTOPTION)$@ -c $(HOST_CXXFLAGS) $(INCLUDES) $(NSPR_CFLAGS) $(_VPATH_SRCS)
 
-host_%.$(OBJ_SUFFIX): %.m
+$(HOST_CCOBJS): host_%.$(OBJ_SUFFIX): %.cc
+	$(REPORT_BUILD)
+	$(ELOG) $(HOST_CXX) $(HOST_OUTOPTION)$@ -c $(HOST_CXXFLAGS) $(INCLUDES) $(NSPR_CFLAGS) $(_VPATH_SRCS)
+
+$(HOST_CMOBJS): host_%.$(OBJ_SUFFIX): %.m
 	$(REPORT_BUILD)
 	$(ELOG) $(HOST_CC) $(HOST_OUTOPTION)$@ -c $(HOST_CFLAGS) $(HOST_CMFLAGS) $(INCLUDES) $(NSPR_CFLAGS) $(_VPATH_SRCS)
 
-host_%.$(OBJ_SUFFIX): %.mm
+$(HOST_CMMOBJS): host_%.$(OBJ_SUFFIX): %.mm
 	$(REPORT_BUILD)
 	$(ELOG) $(HOST_CXX) $(HOST_OUTOPTION)$@ -c $(HOST_CXXFLAGS) $(HOST_CMMFLAGS) $(INCLUDES) $(NSPR_CFLAGS) $(_VPATH_SRCS)
 
-%:: %.c $(GLOBAL_DEPS)
-	$(REPORT_BUILD)
-	@$(MAKE_DEPS_AUTO_CC)
-	$(ELOG) $(CC) $(CFLAGS) $(LDFLAGS) $(OUTOPTION)$@ $(_VPATH_SRCS)
-
-%.$(OBJ_SUFFIX): %.c
+$(COBJS): %.$(OBJ_SUFFIX): %.c
 	$(REPORT_BUILD)
 	@$(MAKE_DEPS_AUTO_CC)
 	$(ELOG) $(CC) $(OUTOPTION)$@ -c $(COMPILE_CFLAGS) $(_VPATH_SRCS)
 
 # DEFINES and ACDEFINES are needed here to enable conditional compilation of Q_OBJECTs:
 # 'moc' only knows about #defines it gets on the command line (-D...), not in
 # included headers like mozilla-config.h
 moc_%.cpp: %.h
@@ -1130,52 +1125,48 @@ moc_%.cc: %.cc
 	$(ELOG) $(MOC) $(DEFINES) $(ACDEFINES) $(_VPATH_SRCS:.cc=.h) $(OUTOPTION)$@
 
 qrc_%.cpp: %.qrc
 	$(ELOG) $(RCC) -name $* $< $(OUTOPTION)$@
 
 ifdef ASFILES
 # The AS_DASH_C_FLAG is needed cause not all assemblers (Solaris) accept
 # a '-c' flag.
-%.$(OBJ_SUFFIX): %.$(ASM_SUFFIX)
+$(ASOBJS): %.$(OBJ_SUFFIX): %.$(ASM_SUFFIX)
 	$(AS) $(ASOUTOPTION)$@ $(ASFLAGS) $(AS_DASH_C_FLAG) $(_VPATH_SRCS)
 endif
 
-%.$(OBJ_SUFFIX): %.S
+$(SOBJS): %.$(OBJ_SUFFIX): %.S
 	$(AS) -o $@ $(ASFLAGS) -c $<
 
-%:: %.cpp $(GLOBAL_DEPS)
-	@$(MAKE_DEPS_AUTO_CXX)
-	$(CCC) $(OUTOPTION)$@ $(CXXFLAGS) $(_VPATH_SRCS) $(LDFLAGS)
-
 #
 # Please keep the next two rules in sync.
 #
-%.$(OBJ_SUFFIX): %.cc
+$(CCOBJS): %.$(OBJ_SUFFIX): %.cc
 	$(REPORT_BUILD)
 	@$(MAKE_DEPS_AUTO_CXX)
 	$(ELOG) $(CCC) $(OUTOPTION)$@ -c $(COMPILE_CXXFLAGS) $(_VPATH_SRCS)
 
-%.$(OBJ_SUFFIX): %.cpp
+$(CPPOBJS): %.$(OBJ_SUFFIX): %.cpp
 	$(REPORT_BUILD)
 	@$(MAKE_DEPS_AUTO_CXX)
 ifdef STRICT_CPLUSPLUS_SUFFIX
 	echo "#line 1 \"$*.cpp\"" | cat - $*.cpp > t_$*.cc
 	$(ELOG) $(CCC) -o $@ -c $(COMPILE_CXXFLAGS) t_$*.cc
 	$(RM) t_$*.cc
 else
 	$(ELOG) $(CCC) $(OUTOPTION)$@ -c $(COMPILE_CXXFLAGS) $(_VPATH_SRCS)
 endif #STRICT_CPLUSPLUS_SUFFIX
 
-$(OBJ_PREFIX)%.$(OBJ_SUFFIX): %.mm
+$(CMMOBJS): $(OBJ_PREFIX)%.$(OBJ_SUFFIX): %.mm
 	$(REPORT_BUILD)
 	@$(MAKE_DEPS_AUTO_CXX)
 	$(ELOG) $(CCC) -o $@ -c $(COMPILE_CXXFLAGS) $(COMPILE_CMMFLAGS) $(_VPATH_SRCS)
 
-$(OBJ_PREFIX)%.$(OBJ_SUFFIX): %.m
+$(CMOBJS): $(OBJ_PREFIX)%.$(OBJ_SUFFIX): %.m
 	$(REPORT_BUILD)
 	@$(MAKE_DEPS_AUTO_CC)
 	$(ELOG) $(CC) -o $@ -c $(COMPILE_CFLAGS) $(COMPILE_CMFLAGS) $(_VPATH_SRCS)
 
 %.s: %.cpp
 	$(CCC) -S $(COMPILE_CXXFLAGS) $(_VPATH_SRCS)
 
 %.s: %.cc
--- a/js/src/config/system-headers
+++ b/js/src/config/system-headers
@@ -1042,16 +1042,17 @@ vpx/vpx_codec.h
 vpx/vpx_decoder.h
 vpx/vp8dx.h
 #endif
 #ifdef XP_WIN
 vpx/vpx_codec.h
 vpx/vpx_decoder.h
 vpx/vp8dx.h
 sydneyaudio/sydney_audio.h
+speex/speex_resampler.h
 vorbis/codec.h
 theora/theoradec.h
 tremor/ivorbiscodec.h
 ogg/ogg.h
 ogg/os_types.h
 nestegg/nestegg.h
 cubeb/cubeb.h
 #endif
--- a/js/src/configure.in
+++ b/js/src/configure.in
@@ -2666,27 +2666,23 @@ MOZ_ARG_DISABLE_BOOL(polyic,
 [  --disable-polyic      Disable use of PICs by JIT compiler],
   ENABLE_POLYIC= )
 
 MOZ_ARG_ENABLE_BOOL(methodjit-spew,
 [  --enable-methodjit-spew      Enable method JIT spew support],
   ENABLE_METHODJIT_SPEW=1,
   ENABLE_METHODJIT_SPEW= )
 
-MOZ_ARG_DISABLE_BOOL(polyic-typed-array,
-[  --disable-polyic-typed-array      Disable use of Typed Array PICs by JIT compiler],
-  ENABLE_POLYIC_TYPED_ARRAY=,
-  ENABLE_POLYIC_TYPED_ARRAY=1 )
-
 MOZ_ARG_DISABLE_BOOL(ion,
 [  --disable-ion      Disable use of IONMonkey compiler],
   ENABLE_ION=,
   ENABLE_ION=1 )
 
 AC_SUBST(ENABLE_METHODJIT)
+AC_SUBST(ENABLE_METHODJIT_SPEW)
 
 if test "$ENABLE_METHODJIT"; then
     AC_DEFINE(JS_METHODJIT)
 else
     ENABLE_ION=
 fi
 
 if test "$ENABLE_MONOIC"; then
@@ -2696,20 +2692,16 @@ fi
 if test "$ENABLE_POLYIC"; then
     AC_DEFINE(JS_POLYIC)
 fi
 
 if test "$ENABLE_METHODJIT_TYPED_ARRAY"; then
     AC_DEFINE(JS_METHODJIT_TYPED_ARRAY)
 fi
 
-if test "$ENABLE_METHODJIT_SPEW"; then
-    AC_DEFINE(JS_METHODJIT_SPEW)
-fi
-
 AC_SUBST(ENABLE_ION)
 
 if test "$ENABLE_ION"; then
     AC_DEFINE(JS_ION)
 fi
 
 if test -z "$SKIP_COMPILER_CHECKS"; then
 dnl Checks for typedefs, structures, and compiler characteristics.
@@ -3899,16 +3891,17 @@ if test -z "$MOZ_DEBUG_FLAGS"; then
   MOZ_DEBUG_FLAGS="-g"
 fi
 
 MOZ_ARG_ENABLE_STRING(debug,
 [  --enable-debug[=DBG]    Enable building with developer debug info
                            (using compiler flags DBG)],
 [ if test "$enableval" != "no"; then
     MOZ_DEBUG=1
+    ENABLE_METHODJIT_SPEW=1
     if test -n "$enableval" -a "$enableval" != "yes"; then
         MOZ_DEBUG_FLAGS=`echo $enableval | sed -e 's|\\\ | |g'`
         _MOZ_DEBUG_FLAGS_SET=1
     fi
   else
     MOZ_DEBUG=
   fi ],
   MOZ_DEBUG=)
@@ -3934,16 +3927,20 @@ if test -n "$MOZ_DEBUG"; then
         _results=no)
     AC_MSG_RESULT([$_results])
     if test "$_results" = "no"; then
         AC_MSG_ERROR([These compiler flags are invalid: $MOZ_DEBUG_FLAGS])
     fi
     CFLAGS=$_SAVE_CFLAGS
 fi
 
+if test "$ENABLE_METHODJIT_SPEW"; then
+    AC_DEFINE(JS_METHODJIT_SPEW)
+fi
+
 dnl ========================================================
 dnl = Enable code optimization. ON by default.
 dnl ========================================================
 if test -z "$MOZ_OPTIMIZE_FLAGS"; then
 	MOZ_OPTIMIZE_FLAGS="-O"
 fi
 
 MOZ_ARG_ENABLE_STRING(optimize,
--- a/js/src/frontend/BytecodeCompiler.cpp
+++ b/js/src/frontend/BytecodeCompiler.cpp
@@ -96,79 +96,82 @@ MarkInnerAndOuterFunctions(JSContext *cx
     }
 
     return true;
 }
 
 JSScript *
 frontend::CompileScript(JSContext *cx, JSObject *scopeChain, StackFrame *callerFrame,
                         JSPrincipals *principals, JSPrincipals *originPrincipals,
-                        uint32_t tcflags,
+                        bool compileAndGo, bool noScriptRval, bool needScriptGlobal,
                         const jschar *chars, size_t length,
                         const char *filename, unsigned lineno, JSVersion version,
                         JSString *source /* = NULL */,
                         unsigned staticLevel /* = 0 */)
 {
     TokenKind tt;
     ParseNode *pn;
     bool inDirectivePrologue;
 
-    JS_ASSERT(!(tcflags & ~(TCF_COMPILE_N_GO | TCF_NO_SCRIPT_RVAL | TCF_COMPILE_FOR_EVAL
-                            | TCF_NEED_SCRIPT_GLOBAL)));
-
     /*
      * The scripted callerFrame can only be given for compile-and-go scripts
      * and non-zero static level requires callerFrame.
      */
-    JS_ASSERT_IF(callerFrame, tcflags & TCF_COMPILE_N_GO);
+    JS_ASSERT_IF(callerFrame, compileAndGo);
     JS_ASSERT_IF(staticLevel != 0, callerFrame);
 
-    Parser parser(cx, principals, originPrincipals, callerFrame);
+    bool foldConstants = true;
+    Parser parser(cx, principals, originPrincipals, callerFrame, foldConstants, compileAndGo);
     if (!parser.init(chars, length, filename, lineno, version))
         return NULL;
 
     TokenStream &tokenStream = parser.tokenStream;
 
-    BytecodeEmitter bce(&parser, tokenStream.getLineno());
-    if (!bce.init(cx, TreeContext::USED_AS_TREE_CONTEXT))
+    SharedContext sc(cx, /* inFunction = */ false);
+
+    TreeContext tc(&parser, &sc);
+    if (!tc.init(cx))
+        return NULL;
+
+    BytecodeEmitter bce(&parser, &sc, tokenStream.getLineno(), noScriptRval, needScriptGlobal);
+    if (!bce.init())
         return NULL;
 
     Probes::compileScriptBegin(cx, filename, lineno);
     MUST_FLOW_THROUGH("out");
 
     // We can specialize a bit for the given scope chain if that scope chain is the global object.
     JSObject *globalObj = scopeChain && scopeChain == &scopeChain->global()
                           ? &scopeChain->global()
                           : NULL;
 
     JS_ASSERT_IF(globalObj, globalObj->isNative());
     JS_ASSERT_IF(globalObj, JSCLASS_HAS_GLOBAL_FLAG_AND_SLOTS(globalObj->getClass()));
 
     RootedVar<JSScript*> script(cx);
 
     GlobalScope globalScope(cx, globalObj);
-    bce.flags |= tcflags;
-    bce.setScopeChain(scopeChain);
+    bce.sc->setScopeChain(scopeChain);
     bce.globalScope = &globalScope;
-    if (!SetStaticLevel(&bce, staticLevel))
+    if (!SetStaticLevel(bce.sc, staticLevel))
         goto out;
 
     /* If this is a direct call to eval, inherit the caller's strictness.  */
     if (callerFrame &&
         callerFrame->isScriptFrame() &&
         callerFrame->script()->strictModeCode) {
-        bce.flags |= TCF_STRICT_MODE_CODE;
+        bce.sc->flags |= TCF_STRICT_MODE_CODE;
         tokenStream.setStrictMode();
     }
 
 #ifdef DEBUG
     bool savedCallerFun;
     savedCallerFun = false;
 #endif
-    if (tcflags & TCF_COMPILE_N_GO) {
+    if (compileAndGo) {
         if (source) {
             /*
              * Save eval program source in script->atoms[0] for the
              * eval cache (see EvalCacheLookup in jsobj.cpp).
              */
             JSAtom *atom = js_AtomizeString(cx, source);
             jsatomid _;
             if (!atom || !bce.makeAtomIndex(atom, &_))
@@ -193,19 +196,19 @@ frontend::CompileScript(JSContext *cx, J
         }
     }
 
     /*
      * Inline this->statements to emit as we go to save AST space. We must
      * generate our script-body blockid since we aren't calling Statements.
      */
     uint32_t bodyid;
-    if (!GenerateBlockId(&bce, bodyid))
+    if (!GenerateBlockId(bce.sc, bodyid))
         goto out;
-    bce.bodyid = bodyid;
+    bce.sc->bodyid = bodyid;
 
 #if JS_HAS_XML_SUPPORT
     pn = NULL;
     bool onlyXML;
     onlyXML = true;
 #endif
 
     inDirectivePrologue = true;
@@ -217,27 +220,26 @@ frontend::CompileScript(JSContext *cx, J
                 break;
             JS_ASSERT(tt == TOK_ERROR);
             goto out;
         }
 
         pn = parser.statement();
         if (!pn)
             goto out;
-        JS_ASSERT(!bce.blockNode);
 
         if (inDirectivePrologue && !parser.recognizeDirectivePrologue(pn, &inDirectivePrologue))
             goto out;
 
         if (!FoldConstants(cx, pn, bce.parser))
             goto out;
 
         if (!AnalyzeFunctions(bce.parser))
             goto out;
-        bce.functionList = NULL;
+        bce.sc->functionList = NULL;
 
         if (!EmitTree(cx, &bce, pn))
             goto out;
 
 #if JS_HAS_XML_SUPPORT
         if (!pn->isKind(PNK_SEMI) || !pn->pn_kid || !pn->pn_kid->isXMLItem())
             onlyXML = false;
 #endif
@@ -291,45 +293,51 @@ frontend::CompileFunctionBody(JSContext 
                               const char *filename, unsigned lineno, JSVersion version)
 {
     Parser parser(cx, principals, originPrincipals);
     if (!parser.init(chars, length, filename, lineno, version))
         return false;
 
     TokenStream &tokenStream = parser.tokenStream;
 
-    BytecodeEmitter funbce(&parser, tokenStream.getLineno());
-    if (!funbce.init(cx, TreeContext::USED_AS_TREE_CONTEXT))
+    SharedContext funsc(cx, /* inFunction = */ true);
+
+    TreeContext funtc(&parser, &funsc);
+    if (!funtc.init(cx))
+        return NULL;
+
+    BytecodeEmitter funbce(&parser, &funsc, tokenStream.getLineno(),
+                           /* noScriptRval = */ false, /* needsScriptGlobal = */ false);
+    if (!funbce.init())
         return false;
 
-    funbce.flags |= TCF_IN_FUNCTION;
-    funbce.setFunction(fun);
-    funbce.bindings.transfer(cx, bindings);
-    fun->setArgCount(funbce.bindings.numArgs());
-    if (!GenerateBlockId(&funbce, funbce.bodyid))
+    funsc.setFunction(fun);
+    funsc.bindings.transfer(cx, bindings);
+    fun->setArgCount(funsc.bindings.numArgs());
+    if (!GenerateBlockId(&funsc, funsc.bodyid))
         return false;
 
     /* FIXME: make Function format the source for a function definition. */
-    ParseNode *fn = FunctionNode::create(PNK_NAME, funbce.parser);
+    ParseNode *fn = FunctionNode::create(PNK_NAME, &parser);
     if (fn) {
         fn->pn_body = NULL;
         fn->pn_cookie.makeFree();
 
         unsigned nargs = fun->nargs;
         if (nargs) {
             /*
              * NB: do not use AutoLocalNameArray because it will release space
              * allocated from cx->tempLifoAlloc by DefineArg.
              */
             BindingNames names(cx);
-            if (!funbce.bindings.getLocalNameArray(cx, &names)) {
+            if (!funsc.bindings.getLocalNameArray(cx, &names)) {
                 fn = NULL;
             } else {
                 for (unsigned i = 0; i < nargs; i++) {
-                    if (!DefineArg(fn, names[i].maybeAtom, i, funbce.parser)) {
+                    if (!DefineArg(fn, names[i].maybeAtom, i, &parser)) {
                         fn = NULL;
                         break;
                     }
                 }
             }
         }
     }
 
@@ -338,20 +346,20 @@ frontend::CompileFunctionBody(JSContext 
      * functions, and generate code for this function, including a stop opcode
      * at the end.
      */
     ParseNode *pn = fn ? parser.functionBody(Parser::StatementListBody) : NULL;
     if (pn) {
         if (!tokenStream.matchToken(TOK_EOF)) {
             parser.reportErrorNumber(NULL, JSREPORT_ERROR, JSMSG_SYNTAX_ERROR);
             pn = NULL;
-        } else if (!FoldConstants(cx, pn, funbce.parser)) {
+        } else if (!FoldConstants(cx, pn, &parser)) {
             /* FoldConstants reported the error already. */
             pn = NULL;
-        } else if (!AnalyzeFunctions(funbce.parser)) {
+        } else if (!AnalyzeFunctions(&parser)) {
             pn = NULL;
         } else {
             if (fn->pn_body) {
                 JS_ASSERT(fn->pn_body->isKind(PNK_ARGSBODY));
                 fn->pn_body->append(pn);
                 fn->pn_body->pn_pos = pn->pn_pos;
                 pn = fn->pn_body;
             }
--- a/js/src/frontend/BytecodeCompiler.h
+++ b/js/src/frontend/BytecodeCompiler.h
@@ -50,16 +50,17 @@ bool
 CompileFunctionBody(JSContext *cx, JSFunction *fun,
                     JSPrincipals *principals, JSPrincipals *originPrincipals,
                     Bindings *bindings, const jschar *chars, size_t length,
                     const char *filename, unsigned lineno, JSVersion version);
 
 JSScript *
 CompileScript(JSContext *cx, JSObject *scopeChain, StackFrame *callerFrame,
               JSPrincipals *principals, JSPrincipals *originPrincipals,
-              uint32_t tcflags, const jschar *chars, size_t length,
+              bool compileAndGo, bool noScriptRval, bool needScriptGlobal,
+              const jschar *chars, size_t length,
               const char *filename, unsigned lineno, JSVersion version,
               JSString *source = NULL, unsigned staticLevel = 0);
 
 } /* namespace frontend */
 } /* namespace js */
 
 #endif /* BytecodeCompiler_h__ */
--- a/js/src/frontend/BytecodeEmitter.cpp
+++ b/js/src/frontend/BytecodeEmitter.cpp
@@ -93,47 +93,52 @@ using namespace js::frontend;
 
 static JSBool
 NewTryNote(JSContext *cx, BytecodeEmitter *bce, JSTryNoteKind kind, unsigned stackDepth,
            size_t start, size_t end);
 
 static JSBool
 SetSrcNoteOffset(JSContext *cx, BytecodeEmitter *bce, unsigned index, unsigned which, ptrdiff_t offset);
 
-BytecodeEmitter::BytecodeEmitter(Parser *parser, unsigned lineno)
-  : TreeContext(parser),
+BytecodeEmitter::BytecodeEmitter(Parser *parser, SharedContext *sc, unsigned lineno,
+                                 bool noScriptRval, bool needScriptGlobal)
+  : sc(sc),
+    parent(NULL),
     parser(parser),
-    atomIndices(parser->context),
+    atomIndices(sc->context),
     stackDepth(0), maxStackDepth(0),
     ntrynotes(0), lastTryNode(NULL),
     arrayCompDepth(0),
     emitLevel(0),
-    constMap(parser->context),
-    constList(parser->context),
+    constMap(sc->context),
+    constList(sc->context),
     globalScope(NULL),
-    closedArgs(parser->context),
-    closedVars(parser->context),
-    typesetCount(0)
+    closedArgs(sc->context),
+    closedVars(sc->context),
+    typesetCount(0),
+    noScriptRval(noScriptRval),
+    needScriptGlobal(needScriptGlobal),
+    hasSingletons(false)
 {
     memset(&prolog, 0, sizeof prolog);
     memset(&main, 0, sizeof main);
     current = &main;
     firstLine = prolog.currentLine = main.currentLine = lineno;
 }
 
 bool
-BytecodeEmitter::init(JSContext *cx, TreeContext::InitBehavior ib)
+BytecodeEmitter::init()
 {
     roLexdeps.init();
-    return TreeContext::init(cx, ib) && constMap.init() && atomIndices.ensureMap(cx);
+    return constMap.init() && atomIndices.ensureMap(sc->context);
 }
 
 BytecodeEmitter::~BytecodeEmitter()
 {
-    JSContext *cx = parser->context;
+    JSContext *cx = sc->context;
 
     cx->free_(prolog.base);
     cx->free_(prolog.notes);
     cx->free_(main.base);
     cx->free_(main.notes);
 }
 
 static ptrdiff_t
@@ -169,21 +174,21 @@ EmitCheck(JSContext *cx, BytecodeEmitter
         bce->current->base = newbase;
         bce->current->limit = newbase + newlength;
         bce->current->next = newbase + offset;
     }
     return offset;
 }
 
 static StaticBlockObject &
-CurrentBlock(BytecodeEmitter *bce)
+CurrentBlock(SharedContext *sc)
 {
-    JS_ASSERT(bce->topStmt->type == STMT_BLOCK || bce->topStmt->type == STMT_SWITCH);
-    JS_ASSERT(bce->topStmt->blockObj->isStaticBlock());
-    return *bce->topStmt->blockObj;
+    JS_ASSERT(sc->topStmt->type == STMT_BLOCK || sc->topStmt->type == STMT_SWITCH);
+    JS_ASSERT(sc->topStmt->blockObj->isStaticBlock());
+    return *sc->topStmt->blockObj;
 }
 
 static void
 UpdateDepth(JSContext *cx, BytecodeEmitter *bce, ptrdiff_t target)
 {
     jsbytecode *pc = bce->code(target);
     JSOp op = (JSOp) *pc;
     const JSCodeSpec *cs = &js_CodeSpec[op];
@@ -203,21 +208,21 @@ UpdateDepth(JSContext *cx, BytecodeEmitt
     /*
      * Specially handle any case that would call js_GetIndexFromBytecode since
      * it requires a well-formed script. This allows us to safely pass NULL as
      * the 'script' parameter.
      */
     int nuses, ndefs;
     if (op == JSOP_ENTERBLOCK) {
         nuses = 0;
-        ndefs = CurrentBlock(bce).slotCount();
+        ndefs = CurrentBlock(bce->sc).slotCount();
     } else if (op == JSOP_ENTERLET0) {
-        nuses = ndefs = CurrentBlock(bce).slotCount();
+        nuses = ndefs = CurrentBlock(bce->sc).slotCount();
     } else if (op == JSOP_ENTERLET1) {
-        nuses = ndefs = CurrentBlock(bce).slotCount() + 1;
+        nuses = ndefs = CurrentBlock(bce->sc).slotCount() + 1;
     } else {
         nuses = StackUses(NULL, pc);
         ndefs = StackDefs(NULL, pc);
     }
 
     bce->stackDepth -= nuses;
     JS_ASSERT(bce->stackDepth >= 0);
     bce->stackDepth += ndefs;
@@ -339,28 +344,28 @@ static const char *statementName[] = {
     "for loop",              /* FOR_LOOP */
     "for/in loop",           /* FOR_IN_LOOP */
     "while loop",            /* WHILE_LOOP */
 };
 
 JS_STATIC_ASSERT(JS_ARRAY_LENGTH(statementName) == STMT_LIMIT);
 
 static const char *
-StatementName(BytecodeEmitter *bce)
+StatementName(SharedContext *sc)
 {
-    if (!bce->topStmt)
+    if (!sc->topStmt)
         return js_script_str;
-    return statementName[bce->topStmt->type];
+    return statementName[sc->topStmt->type];
 }
 
 static void
-ReportStatementTooLarge(JSContext *cx, BytecodeEmitter *bce)
+ReportStatementTooLarge(JSContext *cx, SharedContext *sc)
 {
     JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_NEED_DIET,
-                         StatementName(bce));
+                         StatementName(sc));
 }
 
 /*
  * Emit a backpatch op with offset pointing to the previous jump of this type,
  * so that we can walk back up the chain fixing up the op and jump offset.
  */
 static ptrdiff_t
 EmitBackPatchOp(JSContext *cx, BytecodeEmitter *bce, JSOp op, ptrdiff_t *lastp)
@@ -532,17 +537,17 @@ EmitNonLocalJumpFixup(JSContext *cx, Byt
      * end of a with statement, so we save bce->stackDepth here and restore it
      * just before a successful return.
      */
     int depth = bce->stackDepth;
     int npops = 0;
 
 #define FLUSH_POPS() if (npops && !FlushPops(cx, bce, &npops)) return JS_FALSE
 
-    for (StmtInfo *stmt = bce->topStmt; stmt != toStmt; stmt = stmt->down) {
+    for (StmtInfo *stmt = bce->sc->topStmt; stmt != toStmt; stmt = stmt->down) {
         switch (stmt->type) {
           case STMT_FINALLY:
             FLUSH_POPS();
             if (NewSrcNote(cx, bce, SRC_HIDDEN) < 0)
                 return JS_FALSE;
             if (EmitBackPatchOp(cx, bce, JSOP_BACKPATCH, &GOSUBS(*stmt)) < 0)
                 return JS_FALSE;
             break;
@@ -648,24 +653,24 @@ BackPatch(JSContext *cx, BytecodeEmitter
         pc -= delta;
     }
     return JS_TRUE;
 }
 
 JSBool
 frontend::PopStatementBCE(JSContext *cx, BytecodeEmitter *bce)
 {
-    StmtInfo *stmt = bce->topStmt;
+    StmtInfo *stmt = bce->sc->topStmt;
     if (!STMT_IS_TRYING(stmt) &&
         (!BackPatch(cx, bce, stmt->breaks, bce->next(), JSOP_GOTO) ||
          !BackPatch(cx, bce, stmt->continues, bce->code(stmt->update), JSOP_GOTO)))
     {
         return JS_FALSE;
     }
-    PopStatementTC(bce);
+    PopStatementSC(bce->sc);
     return JS_TRUE;
 }
 
 JSBool
 frontend::DefineCompileTimeConstant(JSContext *cx, BytecodeEmitter *bce, JSAtom *atom, ParseNode *pn)
 {
     /* XXX just do numbers for now */
     if (pn->isKind(PNK_NUMBER)) {
@@ -684,41 +689,41 @@ LookupCompileTimeConstant(JSContext *cx,
 {
     /*
      * Chase down the bce stack, but only until we reach the outermost bce.
      * This enables propagating consts from top-level into switch cases in a
      * function compiled along with the top-level script.
      */
     constp->setMagic(JS_NO_CONSTANT);
     do {
-        if (bce->inFunction() || bce->compileAndGo()) {
+        if (bce->sc->inFunction || bce->parser->compileAndGo) {
             /* XXX this will need revising if 'const' becomes block-scoped. */
-            StmtInfo *stmt = LexicalLookup(bce, atom, NULL);
+            StmtInfo *stmt = LexicalLookup(bce->sc, atom, NULL);
             if (stmt)
                 return JS_TRUE;
 
             if (BytecodeEmitter::ConstMap::Ptr p = bce->constMap.lookup(atom)) {
                 JS_ASSERT(!p->value.isMagic(JS_NO_CONSTANT));
                 *constp = p->value;
                 return JS_TRUE;
             }
 
             /*
              * Try looking in the variable object for a direct property that
              * is readonly and permanent.  We know such a property can't be
              * shadowed by another property on obj's prototype chain, or a
              * with object or catch variable; nor can prop's value be changed,
              * nor can prop be deleted.
              */
-            if (bce->inFunction()) {
-                if (bce->bindings.hasBinding(cx, atom))
+            if (bce->sc->inFunction) {
+                if (bce->sc->bindings.hasBinding(cx, atom))
                     break;
             } else {
-                JS_ASSERT(bce->compileAndGo());
-                JSObject *obj = bce->scopeChain();
+                JS_ASSERT(bce->parser->compileAndGo);
+                JSObject *obj = bce->sc->scopeChain();
 
                 const Shape *shape = obj->nativeLookup(cx, AtomToId(atom));
                 if (shape) {
                     /*
                      * We're compiling code that will be executed immediately,
                      * not re-executed against a different scope chain and/or
                      * variable object.  Therefore we can get constant values
                      * from our variable object here.
@@ -728,17 +733,17 @@ LookupCompileTimeConstant(JSContext *cx,
                         *constp = obj->nativeGetSlot(shape->slot());
                     }
                 }
 
                 if (shape)
                     break;
             }
         }
-        bce = bce->parentBCE();
+        bce = bce->parent;
     } while (bce);
 
     return JS_TRUE;
 }
 
 static bool
 EmitIndex32(JSContext *cx, JSOp op, uint32_t index, BytecodeEmitter *bce)
 {
@@ -891,18 +896,18 @@ EmitAliasedVarOp(JSContext *cx, JSOp op,
     SET_UINT32_INDEX(pc, atomIndex);
     return true;
 }
 
 static bool
 EmitAliasedVarOp(JSContext *cx, JSOp op, ParseNode *pn, BytecodeEmitter *bce)
 {
     uint16_t binding = JOF_OPTYPE(pn->getOp()) == JOF_QARG
-                       ? bce->bindings.argToBinding(pn->pn_cookie.slot())
-                       : bce->bindings.localToBinding(pn->pn_cookie.slot());
+                       ? bce->sc->bindings.argToBinding(pn->pn_cookie.slot())
+                       : bce->sc->bindings.localToBinding(pn->pn_cookie.slot());
     return EmitAliasedVarOp(cx, op, binding, pn->atom(), bce);
 }
 
 static bool
 EmitVarOp(JSContext *cx, ParseNode *pn, JSOp op, BytecodeEmitter *bce)
 {
     JS_ASSERT(pn->isKind(PNK_FUNCTION) || pn->isKind(PNK_NAME));
     JS_ASSERT_IF(pn->isKind(PNK_NAME), JOF_OPTYPE(op) == JOF_QARG || JOF_OPTYPE(op) == JOF_LOCAL);
@@ -969,70 +974,70 @@ EmitVarIncDec(JSContext *cx, ParseNode *
 
     UpdateDecomposeLength(bce, start);
     return true;
 }
 
 bool
 BytecodeEmitter::isAliasedName(ParseNode *pn)
 {
-    return bindingsAccessedDynamically() || shouldNoteClosedName(pn->resolve());
+    return sc->bindingsAccessedDynamically() || shouldNoteClosedName(pn->resolve());
 }
 
 bool
 BytecodeEmitter::shouldNoteClosedName(ParseNode *pn)
 {
-    return !bindingsAccessedDynamically() && pn->isDefn() && pn->isClosed();
+    return !sc->bindingsAccessedDynamically() && pn->isDefn() && pn->isClosed();
 }
 
 bool
 BytecodeEmitter::noteClosedVar(ParseNode *pn)
 {
 #ifdef DEBUG
     JS_ASSERT(shouldNoteClosedName(pn));
     Definition *dn = (Definition *)pn;
     JS_ASSERT(dn->kind() == Definition::VAR || dn->kind() == Definition::CONST ||
               dn->kind() == Definition::FUNCTION);
-    JS_ASSERT(pn->pn_cookie.slot() < bindings.numVars());
+    JS_ASSERT(pn->pn_cookie.slot() < sc->bindings.numVars());
     for (size_t i = 0; i < closedVars.length(); ++i)
         JS_ASSERT(closedVars[i] != pn->pn_cookie.slot());
 #endif
-    flags |= TCF_FUN_HEAVYWEIGHT;
+    sc->flags |= TCF_FUN_HEAVYWEIGHT;
     return closedVars.append(pn->pn_cookie.slot());
 }
 
 bool
 BytecodeEmitter::noteClosedArg(ParseNode *pn)
 {
 #ifdef DEBUG
     JS_ASSERT(shouldNoteClosedName(pn));
     Definition *dn = (Definition *)pn;
     JS_ASSERT(dn->kind() == Definition::ARG);
-    JS_ASSERT(pn->pn_cookie.slot() < bindings.numArgs());
+    JS_ASSERT(pn->pn_cookie.slot() < sc->bindings.numArgs());
     for (size_t i = 0; i < closedArgs.length(); ++i)
         JS_ASSERT(closedArgs[i] != pn->pn_cookie.slot());
 #endif
-    flags |= TCF_FUN_HEAVYWEIGHT;
+    sc->flags |= TCF_FUN_HEAVYWEIGHT;
     return closedArgs.append(pn->pn_cookie.slot());
 }
 
 /*
  * Adjust the slot for a block local to account for the number of variables
  * that share the same index space with locals. Due to the incremental code
  * generation for top-level script, we do the adjustment via code patching in
  * js::frontend::CompileScript; see comments there.
  *
  * The function returns -1 on failures.
  */
 static int
 AdjustBlockSlot(JSContext *cx, BytecodeEmitter *bce, int slot)
 {
     JS_ASSERT((unsigned) slot < bce->maxStackDepth);
-    if (bce->inFunction()) {
-        slot += bce->bindings.numVars();
+    if (bce->sc->inFunction) {
+        slot += bce->sc->bindings.numVars();
         if ((unsigned) slot >= SLOTNO_LIMIT) {
             ReportCompileErrorNumber(cx, bce->tokenStream(), NULL, JSREPORT_ERROR,
                                      JSMSG_TOO_MANY_LOCALS);
             slot = -1;
         }
     }
     return slot;
 }
@@ -1071,27 +1076,27 @@ EmitEnterBlock(JSContext *cx, BytecodeEm
 #ifdef DEBUG
         for (ParseNode *pnu = dn->dn_uses; pnu; pnu = pnu->pn_link) {
             JS_ASSERT(pnu->pn_lexdef == dn);
             JS_ASSERT(!(pnu->pn_dflags & PND_BOUND));
             JS_ASSERT(pnu->pn_cookie.isFree());
         }
 #endif
 
-        bool aliased = bce->bindingsAccessedDynamically() || bce->shouldNoteClosedName(dn);
+        bool aliased = bce->sc->bindingsAccessedDynamically() || bce->shouldNoteClosedName(dn);
         blockObj->setAliased(i, aliased);
     }
 
     /*
      * If clones of this block will have any extensible parents, then the
      * clones must get unique shapes; see the comments for
      * js::Bindings::extensibleParents.
      */
-    if ((bce->flags & TCF_FUN_EXTENSIBLE_SCOPE) ||
-        bce->bindings.extensibleParents()) {
+    if ((bce->sc->flags & TCF_FUN_EXTENSIBLE_SCOPE) ||
+        bce->sc->bindings.extensibleParents()) {
         Shape *newShape = Shape::setExtensibleParents(cx, blockObj->lastProperty());
         if (!newShape)
             return false;
         blockObj->setLastPropertyInfallible(newShape);
     }
 
     return true;
 }
@@ -1115,21 +1120,21 @@ EmitEnterBlock(JSContext *cx, BytecodeEm
  *   {
  *     undeclared = 17; // throws ReferenceError
  *   }
  *   foo();
  */
 static bool
 TryConvertToGname(BytecodeEmitter *bce, ParseNode *pn, JSOp *op)
 {
-    if (bce->compileAndGo() &&
+    if (bce->parser->compileAndGo &&
         bce->globalScope->globalObj &&
-        !bce->mightAliasLocals() &&
+        !bce->sc->mightAliasLocals() &&
         !pn->isDeoptimized() &&
-        !(bce->flags & TCF_STRICT_MODE_CODE)) {
+        !(bce->sc->flags & TCF_STRICT_MODE_CODE)) {
         switch (*op) {
           case JSOP_NAME:     *op = JSOP_GETGNAME; break;
           case JSOP_SETNAME:  *op = JSOP_SETGNAME; break;
           case JSOP_INCNAME:  *op = JSOP_INCGNAME; break;
           case JSOP_NAMEINC:  *op = JSOP_GNAMEINC; break;
           case JSOP_DECNAME:  *op = JSOP_DECGNAME; break;
           case JSOP_NAMEDEC:  *op = JSOP_GNAMEDEC; break;
           case JSOP_SETCONST:
@@ -1213,47 +1218,47 @@ BindNameToSlot(JSContext *cx, BytecodeEm
      */
     switch (op) {
       case JSOP_NAME:
       case JSOP_SETCONST:
         break;
       case JSOP_DELNAME:
         if (dn_kind != Definition::UNKNOWN) {
             if (bce->parser->callerFrame && dn->isTopLevel())
-                JS_ASSERT(bce->compileAndGo());
+                JS_ASSERT(bce->parser->compileAndGo);
             else
                 pn->setOp(JSOP_FALSE);
             pn->pn_dflags |= PND_BOUND;
             return JS_TRUE;
         }
         break;
       default:
         if (pn->isConst()) {
-            if (bce->needStrictChecks()) {
+            if (bce->sc->needStrictChecks()) {
                 JSAutoByteString name;
                 if (!js_AtomToPrintableString(cx, atom, &name) ||
-                    !ReportStrictModeError(cx, bce->tokenStream(), bce, pn, JSMSG_READ_ONLY,
+                    !ReportStrictModeError(cx, bce->tokenStream(), bce->sc, pn, JSMSG_READ_ONLY,
                                            name.ptr())) {
                     return JS_FALSE;
                 }
             }
             pn->setOp(op = JSOP_NAME);
         }
     }
 
     if (cookie.isFree()) {
         StackFrame *caller = bce->parser->callerFrame;
         if (caller) {
-            JS_ASSERT(bce->compileAndGo());
+            JS_ASSERT(bce->parser->compileAndGo);
 
             /*
              * Don't generate upvars on the left side of a for loop. See
              * bug 470758.
              */
-            if (bce->flags & TCF_IN_FOR_INIT)
+            if (bce->sc->inForInit)
                 return JS_TRUE;
 
             JS_ASSERT(caller->isScriptFrame());
 
             /*
              * If this is an eval in the global scope, then unbound variables
              * must be globals, so try to use GNAME ops.
              */
@@ -1276,19 +1281,19 @@ BindNameToSlot(JSContext *cx, BytecodeEm
 
         pn->setOp(op);
         pn->pn_dflags |= PND_BOUND;
 
         return JS_TRUE;
     }
 
     uint16_t level = cookie.level();
-    JS_ASSERT(bce->staticLevel >= level);
-
-    const unsigned skip = bce->staticLevel - level;
+    JS_ASSERT(bce->sc->staticLevel >= level);
+
+    const unsigned skip = bce->sc->staticLevel - level;
     if (skip != 0)
         return JS_TRUE;
 
     /*
      * We are compiling a function body and may be able to optimize name
      * to stack slot. Look for an argument or variable in the function and
      * rewrite pn_op and update pn accordingly.
      */
@@ -1319,17 +1324,17 @@ BindNameToSlot(JSContext *cx, BytecodeEm
           default: JS_NOT_REACHED("arg");
         }
         JS_ASSERT(!pn->isConst());
         break;
 
       case Definition::VAR:
         if (dn->isOp(JSOP_CALLEE)) {
             JS_ASSERT(op != JSOP_CALLEE);
-            JS_ASSERT((bce->fun()->flags & JSFUN_LAMBDA) && atom == bce->fun()->atom);
+            JS_ASSERT((bce->sc->fun()->flags & JSFUN_LAMBDA) && atom == bce->sc->fun()->atom);
 
             /*
              * Leave pn->isOp(JSOP_NAME) if bce->fun is heavyweight to
              * address two cases: a new binding introduced by eval, and
              * assignment to the name in strict mode.
              *
              *   var fun = (function f(s) { eval(s); return f; });
              *   assertEq(fun("var f = 42"), 42);
@@ -1346,17 +1351,17 @@ BindNameToSlot(JSContext *cx, BytecodeEm
              * Outside strict mode, assignment to a function expression's name
              * has no effect.  But in strict mode, this attempt to mutate an
              * immutable binding must throw a TypeError.  We implement this by
              * not optimizing such assignments and by marking such functions as
              * heavyweight, ensuring that the function name is represented in
              * the scope chain so that assignment will throw a TypeError.
              */
             JS_ASSERT(op != JSOP_DELNAME);
-            if (!(bce->flags & TCF_FUN_HEAVYWEIGHT)) {
+            if (!(bce->sc->flags & TCF_FUN_HEAVYWEIGHT)) {
                 op = JSOP_CALLEE;
                 pn->pn_dflags |= PND_CONST;
             }
 
             pn->setOp(op);
             pn->pn_dflags |= PND_BOUND;
             return JS_TRUE;
         }
@@ -1507,17 +1512,17 @@ CheckSideEffects(JSContext *cx, Bytecode
                 if (pn2->isConst()) {
                     *answer = JS_FALSE;
                     break;
                 }
                 /* FALL THROUGH */
               case PNK_DOT:
 #if JS_HAS_XML_SUPPORT
               case PNK_DBLDOT:
-                JS_ASSERT_IF(pn2->getKind() == PNK_DBLDOT, !bce->inStrictMode());
+                JS_ASSERT_IF(pn2->getKind() == PNK_DBLDOT, !bce->sc->inStrictMode());
                 /* FALL THROUGH */
 
 #endif
               case PNK_LP:
               case PNK_LB:
                 /* All these delete addressing modes have effects too. */
                 *answer = JS_TRUE;
                 break;
@@ -1585,31 +1590,31 @@ CheckSideEffects(JSContext *cx, Bytecode
         break;
     }
     return ok;
 }
 
 bool
 BytecodeEmitter::needsImplicitThis()
 {
-    if (!compileAndGo())
+    if (!parser->compileAndGo)
         return true;
-    if (!inFunction()) {
-        JSObject *scope = scopeChain();
+    if (!sc->inFunction) {
+        JSObject *scope = sc->scopeChain();
         while (scope) {
             if (scope->isWith())
                 return true;
             scope = scope->enclosingScope();
         }
     }
-    for (const FunctionBox *funbox = this->funbox; funbox; funbox = funbox->parent) {
-        if (funbox->tcflags & TCF_IN_WITH)
+    for (const FunctionBox *funbox = this->sc->funbox; funbox; funbox = funbox->parent) {
+        if (funbox->inWith)
             return true;
     }
-    for (StmtInfo *stmt = topStmt; stmt; stmt = stmt->down) {
+    for (StmtInfo *stmt = sc->topStmt; stmt; stmt = stmt->down) {
         if (stmt->type == STMT_WITH)
             return true;
     }
     return false;
 }
 
 static JSBool
 EmitNameOp(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn, JSBool callContext)
@@ -1669,27 +1674,27 @@ EmitNameOp(JSContext *cx, BytecodeEmitte
 
     return JS_TRUE;
 }
 
 #if JS_HAS_XML_SUPPORT
 static bool
 EmitXMLName(JSContext *cx, ParseNode *pn, JSOp op, BytecodeEmitter *bce)
 {
-    JS_ASSERT(!bce->inStrictMode());
+    JS_ASSERT(!bce->sc->inStrictMode());
     JS_ASSERT(pn->isKind(PNK_XMLUNARY));
     JS_ASSERT(pn->isOp(JSOP_XMLNAME));
     JS_ASSERT(op == JSOP_XMLNAME || op == JSOP_CALLXMLNAME);
 
     ParseNode *pn2 = pn->pn_kid;
-    unsigned oldflags = bce->flags;
-    bce->flags &= ~TCF_IN_FOR_INIT;
+    bool oldInForInit = bce->sc->inForInit;
+    bce->sc->inForInit = false;
     if (!EmitTree(cx, bce, pn2))
         return false;
-    bce->flags |= oldflags & TCF_IN_FOR_INIT;
+    bce->sc->inForInit = oldInForInit;
     if (NewSrcNote2(cx, bce, SRC_PCBASE, bce->offset() - pn2->pn_offset) < 0)
         return false;
 
     if (Emit1(cx, bce, op) < 0)
         return false;
 
     return true;
 }
@@ -2151,30 +2156,30 @@ EmitSwitch(JSContext *cx, BytecodeEmitte
 #endif
 
     /* Push the discriminant. */
     if (!EmitTree(cx, bce, pn->pn_left))
         return JS_FALSE;
 
 #if JS_HAS_BLOCK_SCOPE
     if (pn2->isKind(PNK_LEXICALSCOPE)) {
-        PushBlockScope(bce, &stmtInfo, pn2->pn_objbox->object->asStaticBlock(), -1);
+        PushBlockScope(bce->sc, &stmtInfo, pn2->pn_objbox->object->asStaticBlock(), -1);
         stmtInfo.type = STMT_SWITCH;
         if (!EmitEnterBlock(cx, bce, pn2, JSOP_ENTERLET1))
             return JS_FALSE;
     }
 #endif
 
     /* Switch bytecodes run from here till end of final case. */
     top = bce->offset();
 #if !JS_HAS_BLOCK_SCOPE
-    PushStatement(bce, &stmtInfo, STMT_SWITCH, top);
+    PushStatement(bce->sc, &stmtInfo, STMT_SWITCH, top);
 #else
     if (pn2->isKind(PNK_STATEMENTLIST)) {
-        PushStatement(bce, &stmtInfo, STMT_SWITCH, top);
+        PushStatement(bce->sc, &stmtInfo, STMT_SWITCH, top);
     } else {
         /*
          * Set the statement info record's idea of top. Reset top too, since
          * repushBlock emits code.
          */
         stmtInfo.update = top = bce->offset();
 
         /* Advance pn2 to refer to the switch case list. */
@@ -2618,36 +2623,36 @@ frontend::EmitFunctionScript(JSContext *
 {
     /*
      * The decompiler has assumptions about what may occur immediately after
      * script->main (e.g., in the case of destructuring params). Thus, put the
      * following ops into the range [script->code, script->main). Note:
      * execution starts from script->code, so this has no semantic effect.
      */
 
-    if (bce->argumentsHasLocalBinding()) {
+    if (bce->sc->argumentsHasLocalBinding()) {
         JS_ASSERT(bce->next() == bce->base());  /* See JSScript::argumentsBytecode. */
         bce->switchToProlog();
         if (Emit1(cx, bce, JSOP_ARGUMENTS) < 0)
             return false;
-        if (bce->bindingsAccessedDynamically()) {
+        if (bce->sc->bindingsAccessedDynamically()) {
             JSAtom *atom = cx->runtime->atomState.argumentsAtom;
-            uint16_t binding = bce->bindings.localToBinding(bce->argumentsLocalSlot());
+            uint16_t binding = bce->sc->bindings.localToBinding(bce->sc->argumentsLocalSlot());
             if (!EmitAliasedVarOp(cx, JSOP_SETALIASEDVAR, binding, atom, bce))
                 return false;
         } else {
-            if (!EmitUnaliasedVarOp(cx, JSOP_SETLOCAL, bce->argumentsLocalSlot(), bce))
+            if (!EmitUnaliasedVarOp(cx, JSOP_SETLOCAL, bce->sc->argumentsLocalSlot(), bce))
                 return false;
         }
         if (Emit1(cx, bce, JSOP_POP) < 0)
             return false;
         bce->switchToMain();
     }
 
-    if (bce->flags & TCF_FUN_IS_GENERATOR) {
+    if (bce->sc->flags & TCF_FUN_IS_GENERATOR) {
         bce->switchToProlog();
         if (Emit1(cx, bce, JSOP_GENERATOR) < 0)
             return false;
         bce->switchToMain();
     }
 
     return EmitTree(cx, bce, body) &&
            Emit1(cx, bce, JSOP_STOP) >= 0 &&
@@ -2663,27 +2668,27 @@ MaybeEmitVarDecl(JSContext *cx, Bytecode
     if (!pn->pn_cookie.isFree()) {
         atomIndex = pn->pn_cookie.slot();
     } else {
         if (!bce->makeAtomIndex(pn->pn_atom, &atomIndex))
             return false;
     }
 
     if (JOF_OPTYPE(pn->getOp()) == JOF_ATOM &&
-        (!bce->inFunction() || (bce->flags & TCF_FUN_HEAVYWEIGHT)))
+        (!bce->sc->inFunction || (bce->sc->flags & TCF_FUN_HEAVYWEIGHT)))
     {
         bce->switchToProlog();
         if (!UpdateLineNumberNotes(cx, bce, pn->pn_pos.begin.lineno))
             return false;
         if (!EmitIndexOp(cx, prologOp, atomIndex, bce))
             return false;
         bce->switchToMain();
     }
 
-    if (bce->inFunction() &&
+    if (bce->sc->inFunction &&
         JOF_OPTYPE(pn->getOp()) == JOF_LOCAL &&
         !pn->isLet() &&
         bce->shouldNoteClosedName(pn))
     {
         if (!bce->noteClosedVar(pn))
             return false;
     }
 
@@ -3376,21 +3381,21 @@ EmitVariables(JSContext *cx, BytecodeEmi
                     return false;
             }
             if (pn->isOp(JSOP_DEFCONST) &&
                 !DefineCompileTimeConstant(cx, bce, pn2->pn_atom, pn3))
             {
                 return JS_FALSE;
             }
 
-            unsigned oldflags = bce->flags;
-            bce->flags &= ~TCF_IN_FOR_INIT;
+            bool oldInForInit = bce->sc->inForInit;
+            bce->sc->inForInit = false;
             if (!EmitTree(cx, bce, pn3))
                 return JS_FALSE;
-            bce->flags |= oldflags & TCF_IN_FOR_INIT;
+            bce->sc->inForInit = oldInForInit;
         } else if (letNotes) {
             /* JSOP_ENTERLETx expects at least 1 slot to have been pushed. */
             if (Emit1(cx, bce, JSOP_UNDEFINED) < 0)
                 return JS_FALSE;
         }
 
         /* If we are not initializing, nothing to pop. */
         if (emitOption != InitializeVars) {
@@ -3493,17 +3498,17 @@ EmitAssignment(JSContext *cx, BytecodeEm
 #endif
       case PNK_LP:
         if (!EmitTree(cx, bce, lhs))
             return false;
         offset++;
         break;
 #if JS_HAS_XML_SUPPORT
       case PNK_XMLUNARY:
-        JS_ASSERT(!bce->inStrictMode());
+        JS_ASSERT(!bce->sc->inStrictMode());
         JS_ASSERT(lhs->isOp(JSOP_SETXMLNAME));
         if (!EmitTree(cx, bce, lhs->pn_kid))
             return false;
         if (Emit1(cx, bce, JSOP_BINDXMLNAME) < 0)
             return false;
         offset++;
         break;
 #endif
@@ -3638,17 +3643,17 @@ EmitAssignment(JSContext *cx, BytecodeEm
       case PNK_RB:
       case PNK_RC:
         if (!EmitDestructuringOps(cx, bce, SRC_DECL_NONE, lhs))
             return false;
         break;
 #endif
 #if JS_HAS_XML_SUPPORT
       case PNK_XMLUNARY:
-        JS_ASSERT(!bce->inStrictMode());
+        JS_ASSERT(!bce->sc->inStrictMode());
         if (Emit1(cx, bce, JSOP_SETXMLNAME) < 0)
             return false;
         break;
 #endif
       default:
         JS_ASSERT(0);
     }
     return true;
@@ -3784,17 +3789,17 @@ ParseNode::getConstantValue(JSContext *c
     }
     return false;
 }
 
 static bool
 EmitSingletonInitialiser(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn)
 {
     Value value;
-    if (!pn->getConstantValue(cx, bce->needStrictChecks(), &value))
+    if (!pn->getConstantValue(cx, bce->sc->needStrictChecks(), &value))
         return false;
 
     JS_ASSERT(value.isObject());
     ObjectBox *objbox = bce->parser->newObjectBox(&value.toObject());
     if (!objbox)
         return false;
 
     return EmitObjectOp(cx, objbox, JSOP_OBJECT, bce);
@@ -3816,17 +3821,17 @@ static bool
 EmitCatch(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn)
 {
     ptrdiff_t catchStart, guardJump;
 
     /*
      * Morph STMT_BLOCK to STMT_CATCH, note the block entry code offset,
      * and save the block object atom.
      */
-    StmtInfo *stmt = bce->topStmt;
+    StmtInfo *stmt = bce->sc->topStmt;
     JS_ASSERT(stmt->type == STMT_BLOCK && (stmt->flags & SIF_SCOPE));
     stmt->type = STMT_CATCH;
     catchStart = stmt->update;
 
     /* Go up one statement info record to the TRY or FINALLY record. */
     stmt = stmt->down;
     JS_ASSERT(stmt->type == STMT_TRY || stmt->type == STMT_FINALLY);
 
@@ -3911,17 +3916,17 @@ EmitTry(JSContext *cx, BytecodeEmitter *
      * Push stmtInfo to track jumps-over-catches and gosubs-to-finally
      * for later fixup.
      *
      * When a finally block is active (STMT_FINALLY in our tree context),
      * non-local jumps (including jumps-over-catches) result in a GOSUB
      * being written into the bytecode stream and fixed-up later (c.f.
      * EmitBackPatchOp and BackPatch).
      */
-    PushStatement(bce, &stmtInfo, pn->pn_kid3 ? STMT_FINALLY : STMT_TRY, bce->offset());
+    PushStatement(bce->sc, &stmtInfo, pn->pn_kid3 ? STMT_FINALLY : STMT_TRY, bce->offset());
 
     /*
      * Since an exception can be thrown at any place inside the try block,
      * we need to restore the stack and the scope chain before we transfer
      * the control to the exception handler.
      *
      * For that we store in a try note associated with the catch or
      * finally block the stack depth upon the try entry. The interpreter
@@ -4145,17 +4150,17 @@ EmitIf(JSContext *cx, BytecodeEmitter *b
     ptrdiff_t noteIndex = -1;
 
   if_again:
     /* Emit code for the condition before pushing stmtInfo. */
     if (!EmitTree(cx, bce, pn->pn_kid1))
         return JS_FALSE;
     ptrdiff_t top = bce->offset();
     if (stmtInfo.type == STMT_IF) {
-        PushStatement(bce, &stmtInfo, STMT_IF, top);
+        PushStatement(bce->sc, &stmtInfo, STMT_IF, top);
     } else {
         /*
          * We came here from the goto further below that detects else-if
          * chains, so we must mutate stmtInfo back into a STMT_IF record.
          * Also (see below for why) we need a note offset for SRC_IF_ELSE
          * to help the decompiler.  Actually, we need two offsets, one for
          * decompiling any else clause and the second for decompiling an
          * else-if chain without bracing, overindenting, or incorrectly
@@ -4289,17 +4294,17 @@ EmitLet(JSContext *cx, BytecodeEmitter *
         /* Tell the decompiler not to print the decl in the let head. */
         if (NewSrcNote(cx, bce, SRC_CONTINUE) < 0)
             return false;
         if (Emit1(cx, bce, JSOP_UNDEFINED) < 0)
             return false;
     }
 
     StmtInfo stmtInfo(cx);
-    PushBlockScope(bce, &stmtInfo, *blockObj, bce->offset());
+    PushBlockScope(bce->sc, &stmtInfo, *blockObj, bce->offset());
 
     if (!letNotes.update(cx, bce, bce->offset()))
         return false;
 
     ptrdiff_t declNote = NewSrcNote(cx, bce, SRC_DECL);
     if (declNote < 0)
         return false;
 
@@ -4331,17 +4336,17 @@ EmitLet(JSContext *cx, BytecodeEmitter *
     return SetSrcNoteOffset(cx, bce, declNote, 0, o);
 }
 #endif
 
 #if JS_HAS_XML_SUPPORT
 static bool
 EmitXMLTag(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn)
 {
-    JS_ASSERT(!bce->inStrictMode());
+    JS_ASSERT(!bce->sc->inStrictMode());
 
     if (Emit1(cx, bce, JSOP_STARTXML) < 0)
         return false;
 
     {
         jsatomid index;
         JSAtom *tagAtom = (pn->isKind(PNK_XMLETAGO))
                           ? cx->runtime->atomState.etagoAtom
@@ -4391,17 +4396,17 @@ EmitXMLTag(JSContext *cx, BytecodeEmitte
         return false;
 
     return true;
 }
 
 static bool
 EmitXMLProcessingInstruction(JSContext *cx, BytecodeEmitter *bce, XMLProcessingInstruction &pi)
 {
-    JS_ASSERT(!bce->inStrictMode());
+    JS_ASSERT(!bce->sc->inStrictMode());
 
     jsatomid index;
     if (!bce->makeAtomIndex(pi.data(), &index))
         return false;
     if (!EmitIndex32(cx, JSOP_QNAMEPART, index, bce))
         return false;
     if (!EmitAtomOp(cx, pi.target(), JSOP_XMLPI, bce))
         return false;
@@ -4418,32 +4423,32 @@ EmitLexicalScope(JSContext *cx, Bytecode
 {
     JS_ASSERT(pn->isKind(PNK_LEXICALSCOPE));
     JS_ASSERT(pn->getOp() == JSOP_LEAVEBLOCK);
 
     StmtInfo stmtInfo(cx);
     ObjectBox *objbox = pn->pn_objbox;
     StaticBlockObject &blockObj = objbox->object->asStaticBlock();
     size_t slots = blockObj.slotCount();
-    PushBlockScope(bce, &stmtInfo, blockObj, bce->offset());
+    PushBlockScope(bce->sc, &stmtInfo, blockObj, bce->offset());
 
     /*
      * For compound statements (i.e. { stmt-list }), the decompiler does not
      * emit curlies by default. However, if this stmt-list contains a let
      * declaration, this is semantically invalid so we need to add a srcnote to
      * enterblock to tell the decompiler to add curlies. This condition
      * shouldn't be so complicated; try to find a simpler condition.
      */
     ptrdiff_t noteIndex = -1;
     if (pn->expr()->getKind() != PNK_FOR &&
         pn->expr()->getKind() != PNK_CATCH &&
         (stmtInfo.down
          ? stmtInfo.down->type == STMT_BLOCK &&
            (!stmtInfo.down->down || stmtInfo.down->down->type != STMT_FOR_IN_LOOP)
-         : !bce->inFunction()))
+         : !bce->sc->inFunction))
     {
         /* There must be no source note already output for the next op. */
         JS_ASSERT(bce->noteCount() == 0 ||
                   bce->lastNoteOffset() != bce->offset() ||
                   !GettableNoteForNextOp(bce));
         noteIndex = NewSrcNote2(cx, bce, SRC_BRACE, 0);
         if (noteIndex < 0)
             return false;
@@ -4467,32 +4472,32 @@ EmitLexicalScope(JSContext *cx, Bytecode
 }
 
 static bool
 EmitWith(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn)
 {
     StmtInfo stmtInfo(cx);
     if (!EmitTree(cx, bce, pn->pn_left))
         return false;
-    PushStatement(bce, &stmtInfo, STMT_WITH, bce->offset());
+    PushStatement(bce->sc, &stmtInfo, STMT_WITH, bce->offset());
     if (Emit1(cx, bce, JSOP_ENTERWITH) < 0)
         return false;
 
     if (!EmitTree(cx, bce, pn->pn_right))
         return false;
     if (Emit1(cx, bce, JSOP_LEAVEWITH) < 0)
         return false;
     return PopStatementBCE(cx, bce);
 }
 
 static bool
 EmitForIn(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn, ptrdiff_t top)
 {
     StmtInfo stmtInfo(cx);
-    PushStatement(bce, &stmtInfo, STMT_FOR_IN_LOOP, top);
+    PushStatement(bce->sc, &stmtInfo, STMT_FOR_IN_LOOP, top);
 
     ParseNode *forHead = pn->pn_left;
     ParseNode *forBody = pn->pn_right;
 
     ParseNode *pn1 = forHead->pn_kid1;
     bool letDecl = pn1 && pn1->isKind(PNK_LEXICALSCOPE);
     JS_ASSERT_IF(letDecl, pn1->isLet());
 
@@ -4527,20 +4532,20 @@ EmitForIn(JSContext *cx, BytecodeEmitter
      * If the left part is 'var x', emit code to define x if necessary
      * using a prolog opcode, but do not emit a pop. If the left part was
      * originally 'var x = i', the parser will have rewritten it; see
      * Parser::forStatement. 'for (let x = i in o)' is mercifully banned.
      */
     if (pn1) {
         ParseNode *decl = letDecl ? pn1->pn_expr : pn1;
         JS_ASSERT(decl->isKind(PNK_VAR) || decl->isKind(PNK_LET));
-        bce->flags |= TCF_IN_FOR_INIT;
+        bce->sc->inForInit = true;
         if (!EmitVariables(cx, bce, decl, DefineVars))
             return false;
-        bce->flags &= ~TCF_IN_FOR_INIT;
+        bce->sc->inForInit = false;
     }
 
     /* Compile the object expression to the right of 'in'. */
     if (!EmitTree(cx, bce, forHead->pn_kid3))
         return JS_FALSE;
 
     /*
      * Emit a bytecode to convert top of stack value to the iterator
@@ -4549,17 +4554,17 @@ EmitForIn(JSContext *cx, BytecodeEmitter
      */
     JS_ASSERT(pn->isOp(JSOP_ITER));
     if (Emit2(cx, bce, JSOP_ITER, (uint8_t) pn->pn_iflags) < 0)
         return false;
 
     /* Enter the block before the loop body, after evaluating the obj. */
     StmtInfo letStmt(cx);
     if (letDecl) {
-        PushBlockScope(bce, &letStmt, *blockObj, bce->offset());
+        PushBlockScope(bce->sc, &letStmt, *blockObj, bce->offset());
         letStmt.flags |= SIF_FOR_BLOCK;
         if (!EmitEnterBlock(cx, bce, pn1, JSOP_ENTERLET1))
             return false;
     }
 
     /* Annotate so the decompiler can find the loop-closing jump. */
     int noteIndex = NewSrcNote(cx, bce, SRC_FOR_IN);
     if (noteIndex < 0)
@@ -4658,29 +4663,29 @@ EmitForIn(JSContext *cx, BytecodeEmitter
 
     return true;
 }
 
 static bool
 EmitNormalFor(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn, ptrdiff_t top)
 {
     StmtInfo stmtInfo(cx);
-    PushStatement(bce, &stmtInfo, STMT_FOR_LOOP, top);
+    PushStatement(bce->sc, &stmtInfo, STMT_FOR_LOOP, top);
 
     ParseNode *forHead = pn->pn_left;
     ParseNode *forBody = pn->pn_right;
 
     /* C-style for (init; cond; update) ... loop. */
     JSOp op = JSOP_POP;
     ParseNode *pn3 = forHead->pn_kid1;
     if (!pn3) {
         /* No initializer: emit an annotated nop for the decompiler. */
         op = JSOP_NOP;
     } else {
-        bce->flags |= TCF_IN_FOR_INIT;
+        bce->sc->inForInit = true;
 #if JS_HAS_DESTRUCTURING
         if (pn3->isKind(PNK_ASSIGN)) {
             JS_ASSERT(pn3->isOp(JSOP_NOP));
             if (!MaybeEmitGroupAssignment(cx, bce, op, pn3, GroupIsNotDecl, &op))
                 return false;
         }
 #endif
         if (op == JSOP_POP) {
@@ -4693,17 +4698,17 @@ EmitNormalFor(JSContext *cx, BytecodeEmi
                  * not need to emit a pop below, so switch to a nop,
                  * just for the decompiler.
                  */
                 JS_ASSERT(pn3->isArity(PN_LIST) || pn3->isArity(PN_BINARY));
                 if (pn3->pn_xflags & PNX_GROUPINIT)
                     op = JSOP_NOP;
             }
         }
-        bce->flags &= ~TCF_IN_FOR_INIT;
+        bce->sc->inForInit = false;
     }
 
     /*
      * NB: the SRC_FOR note has offsetBias 1 (JSOP_{NOP,POP}_LENGTH).
      * Use tmp to hold the biased srcnote "top" offset, which differs
      * from the top local variable by the length of the JSOP_GOTO
      * emitted in between tmp and top if this loop has a condition.
      */
@@ -4823,91 +4828,89 @@ EmitFunc(JSContext *cx, BytecodeEmitter 
     JS_ASSERT(fun->isInterpreted());
     if (fun->script()) {
         /*
          * This second pass is needed to emit JSOP_NOP with a source note
          * for the already-emitted function definition prolog opcode. See
          * comments in EmitStatementList.
          */
         JS_ASSERT(pn->isOp(JSOP_NOP));
-        JS_ASSERT(bce->inFunction());
+        JS_ASSERT(bce->sc->inFunction);
         return EmitFunctionDefNop(cx, bce, pn->pn_index);
     }
 
     JS_ASSERT_IF(pn->pn_funbox->tcflags & TCF_FUN_HEAVYWEIGHT,
                  fun->kind() == JSFUN_INTERPRETED);
 
     {
-        BytecodeEmitter bce2(bce->parser, pn->pn_pos.begin.lineno);
-        if (!bce2.init(cx))
-            return false;
-
-        bce2.flags = pn->pn_funbox->tcflags | TCF_IN_FUNCTION |
-                     (bce->flags & TCF_FUN_MIGHT_ALIAS_LOCALS);
-        bce2.bindings.transfer(cx, &pn->pn_funbox->bindings);
-        bce2.setFunction(fun);
-        bce2.funbox = pn->pn_funbox;
+        SharedContext sc(cx, /* inFunction = */ true);
+        BytecodeEmitter bce2(bce->parser, &sc, pn->pn_pos.begin.lineno,
+                             /* noScriptRval = */ false, /* needsScriptGlobal = */ false);
+        if (!bce2.init())
+            return false;
+
+        bce2.sc->flags = pn->pn_funbox->tcflags | (bce->sc->flags & TCF_FUN_MIGHT_ALIAS_LOCALS);
+        bce2.sc->bindings.transfer(cx, &pn->pn_funbox->bindings);
+        bce2.sc->setFunction(fun);
+        bce2.sc->funbox = pn->pn_funbox;
         bce2.parent = bce;
         bce2.globalScope = bce->globalScope;
 
         /*
          * js::frontend::SetStaticLevel limited static nesting depth to fit in
          * 16 bits and to reserve the all-ones value, thereby reserving the
          * magic FREE_UPVAR_COOKIE value. Note the bce2.staticLevel assignment
          * below.
          */
-        JS_ASSERT(bce->staticLevel < JS_BITMASK(16) - 1);
-        bce2.staticLevel = bce->staticLevel + 1;
+        JS_ASSERT(bce->sc->staticLevel < JS_BITMASK(16) - 1);
+        bce2.sc->staticLevel = bce->sc->staticLevel + 1;
 
         /* We measured the max scope depth when we parsed the function. */
         if (!EmitFunctionScript(cx, &bce2, pn->pn_body))
             return false;
     }
 
     /* Make the function object a literal in the outer script's pool. */
     unsigned index = bce->objectList.index(pn->pn_funbox);
 
     /* Emit a bytecode pointing to the closure object in its immediate. */
     if (pn->getOp() != JSOP_NOP) {
-        if ((pn->pn_funbox->tcflags & TCF_GENEXP_LAMBDA) &&
-            NewSrcNote(cx, bce, SRC_GENEXP) < 0)
-        {
-            return false;
-        }
+        if ((pn->pn_funbox->inGenexpLambda) && NewSrcNote(cx, bce, SRC_GENEXP) < 0)
+            return false;
 
         return EmitFunctionOp(cx, pn->getOp(), index, bce);
     }
 
     /*
      * For a script we emit the code as we parse. Thus the bytecode for
      * top-level functions should go in the prolog to predefine their
      * names in the variable object before the already-generated main code
      * is executed. This extra work for top-level scripts is not necessary
      * when we emit the code for a function. It is fully parsed prior to
      * invocation of the emitter and calls to EmitTree for function
      * definitions can be scheduled before generating the rest of code.
      */
-    if (!bce->inFunction()) {
-        JS_ASSERT(!bce->topStmt);
+    if (!bce->sc->inFunction) {
+        JS_ASSERT(!bce->sc->topStmt);
         JS_ASSERT(pn->pn_cookie.isFree());
         if (pn->pn_cookie.isFree()) {
             bce->switchToProlog();
             if (!EmitFunctionOp(cx, JSOP_DEFFUN, index, bce))
                 return false;
             if (!UpdateLineNumberNotes(cx, bce, pn->pn_pos.begin.lineno))
                 return false;
             bce->switchToMain();
         }
 
         /* Emit NOP for the decompiler. */
         if (!EmitFunctionDefNop(cx, bce, index))
             return false;
     } else {
         unsigned slot;
-        DebugOnly<BindingKind> kind = bce->bindings.lookup(cx, fun->atom, &slot);
+        DebugOnly<BindingKind> kind = bce->sc->bindings.lookup(cx, fun->atom, &slot);
         JS_ASSERT(kind == VARIABLE || kind == CONSTANT);
         JS_ASSERT(index < JS_BIT(20));
         pn->pn_index = index;
         if (bce->shouldNoteClosedName(pn) && !bce->noteClosedVar(pn))
             return false;
 
         if (NewSrcNote(cx, bce, SRC_CONTINUE) < 0)
             return false;
@@ -4937,17 +4940,17 @@ EmitDo(JSContext *cx, BytecodeEmitter *b
     /* Compile the loop body. */
     ptrdiff_t top = EmitLoopHead(cx, bce, pn->pn_left);
     if (top < 0)
         return false;
     if (!EmitLoopEntry(cx, bce, NULL))
         return false;
 
     StmtInfo stmtInfo(cx);
-    PushStatement(bce, &stmtInfo, STMT_DO_LOOP, top);
+    PushStatement(bce->sc, &stmtInfo, STMT_DO_LOOP, top);
     if (!EmitTree(cx, bce, pn->pn_left))
         return false;
 
     /* Set loop and enclosing label update offsets, for continue. */
     ptrdiff_t off = bce->offset();
     StmtInfo *stmt = &stmtInfo;
     do {
         stmt->update = off;
@@ -4990,17 +4993,17 @@ EmitWhile(JSContext *cx, BytecodeEmitter
      *  =    ===============                 ==================
      *  0    ifeq-pass                       goto; ifne-fail
      *  1    ifeq-fail; goto; ifne-pass      goto; ifne-pass; ifne-fail
      *  2    2*(ifeq-fail; goto); ifeq-pass  goto; 2*ifne-pass; ifne-fail
      *  . . .
      *  N    N*(ifeq-fail; goto); ifeq-pass  goto; N*ifne-pass; ifne-fail
      */
     StmtInfo stmtInfo(cx);
-    PushStatement(bce, &stmtInfo, STMT_WHILE_LOOP, top);
+    PushStatement(bce->sc, &stmtInfo, STMT_WHILE_LOOP, top);
 
     ptrdiff_t noteIndex = NewSrcNote(cx, bce, SRC_WHILE);
     if (noteIndex < 0)
         return false;
 
     ptrdiff_t jmp = EmitJump(cx, bce, JSOP_GOTO, 0);
     if (jmp < 0)
         return false;
@@ -5026,17 +5029,17 @@ EmitWhile(JSContext *cx, BytecodeEmitter
         return false;
 
     return PopStatementBCE(cx, bce);
 }
 
 static bool
 EmitBreak(JSContext *cx, BytecodeEmitter *bce, PropertyName *label)
 {
-    StmtInfo *stmt = bce->topStmt;
+    StmtInfo *stmt = bce->sc->topStmt;
     SrcNoteType noteType;
     jsatomid labelIndex;
     if (label) {
         if (!bce->makeAtomIndex(label, &labelIndex))
             return false;
 
         while (stmt->type != STMT_LABEL || stmt->label != label)
             stmt = stmt->down;
@@ -5049,17 +5052,17 @@ EmitBreak(JSContext *cx, BytecodeEmitter
     }
 
     return EmitGoto(cx, bce, stmt, &stmt->breaks, labelIndex, noteType) >= 0;
 }
 
 static bool
 EmitContinue(JSContext *cx, BytecodeEmitter *bce, PropertyName *label)
 {
-    StmtInfo *stmt = bce->topStmt;
+    StmtInfo *stmt = bce->sc->topStmt;
     SrcNoteType noteType;
     jsatomid labelIndex;
     if (label) {
         if (!bce->makeAtomIndex(label, &labelIndex))
             return false;
 
         /* Find the loop statement enclosed by the matching label. */
         StmtInfo *loop = NULL;
@@ -5128,32 +5131,32 @@ EmitStatementList(JSContext *cx, Bytecod
     ptrdiff_t tmp = bce->offset();
     if (pn->pn_xflags & PNX_NEEDBRACES) {
         noteIndex = NewSrcNote2(cx, bce, SRC_BRACE, 0);
         if (noteIndex < 0 || Emit1(cx, bce, JSOP_NOP) < 0)
             return false;
     }
 
     StmtInfo stmtInfo(cx);
-    PushStatement(bce, &stmtInfo, STMT_BLOCK, top);
+    PushStatement(bce->sc, &stmtInfo, STMT_BLOCK, top);
 
     ParseNode *pnchild = pn->pn_head;
     if (pn->pn_xflags & PNX_FUNCDEFS) {
         /*
          * This block contains top-level function definitions. To ensure
          * that we emit the bytecode defining them before the rest of code
          * in the block we use a separate pass over functions. During the
          * main pass later the emitter will add JSOP_NOP with source notes
          * for the function to preserve the original functions position
          * when decompiling.
          *
          * Currently this is used only for functions, as compile-as-we go
          * mode for scripts does not allow separate emitter passes.
          */
-        JS_ASSERT(bce->inFunction());
+        JS_ASSERT(bce->sc->inFunction);
         if (pn->pn_xflags & PNX_DESTRUCT) {
             /*
              * Assign the destructuring arguments before defining any
              * functions, see bug 419662.
              */
             JS_ASSERT(pnchild->isKind(PNK_SEMI));
             JS_ASSERT(pnchild->pn_kid->isKind(PNK_VAR) || pnchild->pn_kid->isKind(PNK_CONST));
             if (!EmitTree(cx, bce, pnchild))
@@ -5203,33 +5206,38 @@ EmitStatement(JSContext *cx, BytecodeEmi
      * Top-level or called-from-a-native JS_Execute/EvaluateScript,
      * debugger, and eval frames may need the value of the ultimate
      * expression statement as the script's result, despite the fact
      * that it appears useless to the compiler.
      *
      * API users may also set the JSOPTION_NO_SCRIPT_RVAL option when
      * calling JS_Compile* to suppress JSOP_POPV.
      */
-    bool wantval;
-    JSBool useful = wantval = !(bce->flags & (TCF_IN_FUNCTION | TCF_NO_SCRIPT_RVAL));
+    bool wantval = false;
+    JSBool useful = JS_FALSE;
+    if (bce->sc->inFunction) {
+        JS_ASSERT(!bce->noScriptRval);
+    } else {
+        useful = wantval = !bce->noScriptRval;
+    }
 
     /* Don't eliminate expressions with side effects. */
     if (!useful) {
         if (!CheckSideEffects(cx, bce, pn2, &useful))
             return false;
 
         /*
          * Don't eliminate apparently useless expressions if they are
          * labeled expression statements.  The tc->topStmt->update test
          * catches the case where we are nesting in EmitTree for a labeled
          * compound statement.
          */
-        if (bce->topStmt &&
-            bce->topStmt->type == STMT_LABEL &&
-            bce->topStmt->update >= bce->offset())
+        if (bce->sc->topStmt &&
+            bce->sc->topStmt->type == STMT_LABEL &&
+            bce->sc->topStmt->update >= bce->offset())
         {
             useful = true;
         }
     }
 
     if (useful) {
         JSOp op = wantval ? JSOP_POPV : JSOP_POP;
         JS_ASSERT_IF(pn2->isKind(PNK_ASSIGN), pn2->isOp(JSOP_NOP));
@@ -5284,17 +5292,17 @@ EmitDelete(JSContext *cx, BytecodeEmitte
         break;
       }
       case PNK_DOT:
         if (!EmitPropOp(cx, pn2, JSOP_DELPROP, bce, false))
             return false;
         break;
 #if JS_HAS_XML_SUPPORT
       case PNK_DBLDOT:
-        JS_ASSERT(!bce->inStrictMode());
+        JS_ASSERT(!bce->sc->inStrictMode());
         if (!EmitElemOp(cx, pn2, JSOP_DELDESC, bce))
             return false;
         break;
 #endif
       case PNK_LB:
         if (!EmitElemOp(cx, pn2, JSOP_DELELEM, bce))
             return false;
         break;
@@ -5393,25 +5401,25 @@ EmitCallOrNew(JSContext *cx, BytecodeEmi
     /* Remember start of callable-object bytecode for decompilation hint. */
     ptrdiff_t off = top;
 
     /*
      * Emit code for each argument in order, then emit the JSOP_*CALL or
      * JSOP_NEW bytecode with a two-byte immediate telling how many args
      * were pushed on the operand stack.
      */
-    unsigned oldflags = bce->flags;
-    bce->flags &= ~TCF_IN_FOR_INIT;
+    bool oldInForInit = bce->sc->inForInit;
+    bce->sc->inForInit = false;
     for (ParseNode *pn3 = pn2->pn_next; pn3; pn3 = pn3->pn_next) {
         if (!EmitTree(cx, bce, pn3))
             return false;
         if (Emit1(cx, bce, JSOP_NOTEARG) < 0)
             return false;
     }
-    bce->flags |= oldflags & TCF_IN_FOR_INIT;
+    bce->sc->inForInit = oldInForInit;
     if (NewSrcNote2(cx, bce, SRC_PCBASE, bce->offset() - off) < 0)
         return false;
 
     uint32_t argc = pn->pn_count - 1;
     if (Emit3(cx, bce, pn->getOp(), ARGC_HI(argc), ARGC_LO(argc)) < 0)
         return false;
     CheckTypeSet(cx, bce, pn->getOp());
     if (pn->isOp(JSOP_EVAL))
@@ -5527,17 +5535,17 @@ EmitIncOrDec(JSContext *cx, BytecodeEmit
         JS_ASSERT(js_CodeSpec[op].format & JOF_ELEM);
         if (Emit1(cx, bce, (JSOp)1) < 0)
             return false;
         if (Emit1(cx, bce, JSOP_POP) < 0)
             return false;
         break;
 #if JS_HAS_XML_SUPPORT
       case PNK_XMLUNARY:
-        JS_ASSERT(!bce->inStrictMode());
+        JS_ASSERT(!bce->sc->inStrictMode());
         JS_ASSERT(pn2->isOp(JSOP_SETXMLNAME));
         if (!EmitTree(cx, bce, pn2->pn_kid))
             return false;
         if (Emit1(cx, bce, JSOP_BINDXMLNAME) < 0)
             return false;
         if (!EmitElemIncDec(cx, NULL, op, bce))
             return false;
         break;
@@ -5615,17 +5623,17 @@ EmitLabel(JSContext *cx, BytecodeEmitter
         return false;
 
     ptrdiff_t top = EmitJump(cx, bce, JSOP_LABEL, 0);
     if (top < 0)
         return false;
 
     /* Emit code for the labeled statement. */
     StmtInfo stmtInfo(cx);
-    PushStatement(bce, &stmtInfo, STMT_LABEL, bce->offset());
+    PushStatement(bce->sc, &stmtInfo, STMT_LABEL, bce->offset());
     stmtInfo.label = atom;
     if (!EmitTree(cx, bce, pn2))
         return false;
     if (!PopStatementBCE(cx, bce))
         return false;
 
     /* Patch the JSOP_LABEL offset. */
     SetJumpOffsetAt(bce, top);
@@ -5639,17 +5647,17 @@ EmitLabel(JSContext *cx, BytecodeEmitter
     return true;
 }
 
 static bool
 EmitSyntheticStatements(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn, ptrdiff_t top)
 {
     JS_ASSERT(pn->isArity(PN_LIST));
     StmtInfo stmtInfo(cx);
-    PushStatement(bce, &stmtInfo, STMT_SEQ, top);
+    PushStatement(bce->sc, &stmtInfo, STMT_SEQ, top);
     for (ParseNode *pn2 = pn->pn_head; pn2; pn2 = pn2->pn_next) {
         if (!EmitTree(cx, bce, pn2))
             return false;
     }
     return PopStatementBCE(cx, bce);
 }
 
 static bool
@@ -5715,17 +5723,17 @@ EmitObject(JSContext *cx, BytecodeEmitte
     if (!EmitNewInit(cx, bce, JSProto_Object, pn))
         return false;
 
     /*
      * Try to construct the shape of the object as we go, so we can emit a
      * JSOP_NEWOBJECT with the final shape instead.
      */
     RootedVarObject obj(cx);
-    if (bce->compileAndGo()) {
+    if (bce->parser->compileAndGo) {
         gc::AllocKind kind = GuessObjectGCKind(pn->pn_count);
         obj = NewBuiltinClassInstance(cx, &ObjectClass, kind);
         if (!obj)
             return false;
     }
 
     for (ParseNode *pn2 = pn->pn_head; pn2; pn2 = pn2->pn_next) {
         /* Emit an index for t[2] for later consumption by JSOP_INITELEM. */
@@ -5881,22 +5889,22 @@ EmitUnary(JSContext *cx, BytecodeEmitter
     /* Unary op, including unary +/-. */
     JSOp op = pn->getOp();
     ParseNode *pn2 = pn->pn_kid;
 
     JS_ASSERT(op != JSOP_XMLNAME);
     if (op == JSOP_TYPEOF && !pn2->isKind(PNK_NAME))
         op = JSOP_TYPEOFEXPR;
 
-    unsigned oldflags = bce->flags;
-    bce->flags &= ~TCF_IN_FOR_INIT;
+    bool oldInForInit = bce->sc->inForInit;
+    bce->sc->inForInit = false;
     if (!EmitTree(cx, bce, pn2))
         return false;
 
-    bce->flags |= oldflags & TCF_IN_FOR_INIT;
+    bce->sc->inForInit = oldInForInit;
     return Emit1(cx, bce, op) >= 0;
 }
 
 JSBool
 frontend::EmitTree(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn)
 {
     JS_CHECK_RECURSION(cx, return JS_FALSE);
 
@@ -5988,17 +5996,17 @@ frontend::EmitTree(JSContext *cx, Byteco
         break;
 
       case PNK_RETURN:
         ok = EmitReturn(cx, bce, pn);
         break;
 
 #if JS_HAS_GENERATORS
       case PNK_YIELD:
-        JS_ASSERT(bce->inFunction());
+        JS_ASSERT(bce->sc->inFunction);
         if (pn->pn_kid) {
             if (!EmitTree(cx, bce, pn->pn_kid))
                 return JS_FALSE;
         } else {
             if (Emit1(cx, bce, JSOP_UNDEFINED) < 0)
                 return JS_FALSE;
         }
         if (pn->pn_hidden && NewSrcNote(cx, bce, SRC_HIDDEN) < 0)
@@ -6117,63 +6125,62 @@ frontend::EmitTree(JSContext *cx, Byteco
             while ((pn2 = pn2->pn_next) != NULL) {
                 if (!EmitTree(cx, bce, pn2))
                     return JS_FALSE;
                 if (Emit1(cx, bce, op) < 0)
                     return JS_FALSE;
             }
         } else {
 #if JS_HAS_XML_SUPPORT
-            unsigned oldflags;
 
       case PNK_DBLCOLON:
             JS_ASSERT(pn->getOp() != JSOP_XMLNAME);
             if (pn->isArity(PN_NAME)) {
                 if (!EmitTree(cx, bce, pn->expr()))
                     return JS_FALSE;
                 if (!EmitAtomOp(cx, pn, pn->getOp(), bce))
                     return JS_FALSE;
                 break;
             }
 
             /*
              * Binary :: has a right operand that brackets arbitrary code,
              * possibly including a let (a = b) ... expression.  We must clear
-             * TCF_IN_FOR_INIT to avoid mis-compiling such beasts.
+             * inForInit to avoid mis-compiling such beasts.
              */
-            oldflags = bce->flags;
-            bce->flags &= ~TCF_IN_FOR_INIT;
+            bool oldInForInit = bce->sc->inForInit;
+            bce->sc->inForInit = false;
 #endif
 
             /* Binary operators that evaluate both operands unconditionally. */
             if (!EmitTree(cx, bce, pn->pn_left))
                 return JS_FALSE;
             if (!EmitTree(cx, bce, pn->pn_right))
                 return JS_FALSE;
 #if JS_HAS_XML_SUPPORT
-            bce->flags |= oldflags & TCF_IN_FOR_INIT;
+            bce->sc->inForInit = oldInForInit;
 #endif
             if (Emit1(cx, bce, pn->getOp()) < 0)
                 return JS_FALSE;
         }
         break;
 
 #if JS_HAS_XML_SUPPORT
       case PNK_XMLUNARY:
         if (pn->getOp() == JSOP_XMLNAME) {
             if (!EmitXMLName(cx, pn, JSOP_XMLNAME, bce))
                 return false;
         } else {
             JSOp op = pn->getOp();
             JS_ASSERT(op == JSOP_BINDXMLNAME || op == JSOP_SETXMLNAME);
-            unsigned oldflags = bce->flags;
-            bce->flags &= ~TCF_IN_FOR_INIT;
+            bool oldInForInit = bce->sc->inForInit;
+            bce->sc->inForInit = false;
             if (!EmitTree(cx, bce, pn->pn_kid))
                 return false;
-            bce->flags |= oldflags & TCF_IN_FOR_INIT;
+            bce->sc->inForInit = oldInForInit;
             if (Emit1(cx, bce, op) < 0)
                 return false;
         }
         break;
 #endif
 
       case PNK_THROW:
 #if JS_HAS_XML_SUPPORT
@@ -6200,17 +6207,17 @@ frontend::EmitTree(JSContext *cx, Byteco
 
       case PNK_DELETE:
         ok = EmitDelete(cx, bce, pn);
         break;
 
 #if JS_HAS_XML_SUPPORT
       case PNK_FILTER:
       {
-        JS_ASSERT(!bce->inStrictMode());
+        JS_ASSERT(!bce->sc->inStrictMode());
 
         if (!EmitTree(cx, bce, pn->pn_left))
             return JS_FALSE;
         ptrdiff_t jmp = EmitJump(cx, bce, JSOP_FILTER, 0);
         if (jmp < 0)
             return JS_FALSE;
         top = EmitLoopHead(cx, bce, pn->pn_right);
         if (top < 0)
@@ -6232,17 +6239,17 @@ frontend::EmitTree(JSContext *cx, Byteco
          * this bytecode's immediate-indexed atom operand, and push its value
          * (not a reference to it).
          */
         ok = EmitPropOp(cx, pn, pn->getOp(), bce, JS_FALSE);
         break;
 
 #if JS_HAS_XML_SUPPORT
       case PNK_DBLDOT:
-        JS_ASSERT(!bce->inStrictMode());
+        JS_ASSERT(!bce->sc->inStrictMode());
         /* FALL THROUGH */
 #endif
       case PNK_LB:
         /*
          * Pop two operands, convert the left one to object and the right one
          * to property name (atom or tagged int), get the named property, and
          * push its value.  Set the "obj" register to the result of ToObject
          * on the left operand.
@@ -6311,17 +6318,17 @@ frontend::EmitTree(JSContext *cx, Byteco
         break;
 
 #if JS_HAS_XML_SUPPORT
       case PNK_XMLATTR:
       case PNK_XMLSPACE:
       case PNK_XMLTEXT:
       case PNK_XMLCDATA:
       case PNK_XMLCOMMENT:
-        JS_ASSERT(!bce->inStrictMode());
+        JS_ASSERT(!bce->sc->inStrictMode());
         /* FALL THROUGH */
 #endif
       case PNK_STRING:
         ok = EmitAtomOp(cx, pn, pn->getOp(), bce);
         break;
 
       case PNK_NUMBER:
         ok = EmitNumberOp(cx, pn->pn_dval, bce);
@@ -6346,17 +6353,17 @@ frontend::EmitTree(JSContext *cx, Byteco
       case PNK_DEBUGGER:
         if (Emit1(cx, bce, JSOP_DEBUGGER) < 0)
             return JS_FALSE;
         break;
 
 #if JS_HAS_XML_SUPPORT
       case PNK_XMLELEM:
       case PNK_XMLLIST:
-        JS_ASSERT(!bce->inStrictMode());
+        JS_ASSERT(!bce->sc->inStrictMode());
         JS_ASSERT(pn->isKind(PNK_XMLLIST) || pn->pn_count != 0);
 
         switch (pn->pn_head ? pn->pn_head->getKind() : PNK_XMLLIST) {
           case PNK_XMLETAGO:
             JS_ASSERT(0);
             /* FALL THROUGH */
           case PNK_XMLPTAGC:
           case PNK_XMLSTAGO:
@@ -6397,17 +6404,17 @@ frontend::EmitTree(JSContext *cx, Byteco
       case PNK_XMLPTAGC:
       case PNK_XMLSTAGO:
       case PNK_XMLETAGO:
         if (!EmitXMLTag(cx, bce, pn))
             return false;
         break;
 
       case PNK_XMLNAME:
-        JS_ASSERT(!bce->inStrictMode());
+        JS_ASSERT(!bce->sc->inStrictMode());
 
         if (pn->isArity(PN_LIST)) {
             JS_ASSERT(pn->pn_count != 0);
             for (ParseNode *pn2 = pn->pn_head; pn2; pn2 = pn2->pn_next) {
                 if (pn2->isKind(PNK_XMLCURLYEXPR) && Emit1(cx, bce, JSOP_STARTXMLEXPR) < 0)
                     return JS_FALSE;
                 if (!EmitTree(cx, bce, pn2))
                     return JS_FALSE;
@@ -6599,17 +6606,17 @@ frontend::AddToSrcNoteDelta(JSContext *c
 
 static JSBool
 SetSrcNoteOffset(JSContext *cx, BytecodeEmitter *bce, unsigned index, unsigned which, ptrdiff_t offset)
 {
     jssrcnote *sn;
     ptrdiff_t diff;
 
     if (size_t(offset) > SN_MAX_OFFSET) {
-        ReportStatementTooLarge(cx, bce);
+        ReportStatementTooLarge(cx, bce->sc);
         return JS_FALSE;
     }
 
     /* Find the offset numbered which (i.e., skip exactly which offsets). */
     sn = &bce->notes()[index];
     JS_ASSERT(SN_TYPE(sn) != SRC_XDELTA);
     JS_ASSERT((int) which < js_SrcNoteSpec[SN_TYPE(sn)].arity);
     for (sn++; which; sn++, which--) {
--- a/js/src/frontend/BytecodeEmitter.h
+++ b/js/src/frontend/BytecodeEmitter.h
@@ -98,18 +98,22 @@ class GCConstList {
 struct GlobalScope {
     GlobalScope(JSContext *cx, JSObject *globalObj)
       : globalObj(cx, globalObj)
     { }
 
     RootedVarObject globalObj;
 };
 
-struct BytecodeEmitter : public TreeContext
+struct BytecodeEmitter
 {
+    SharedContext   *sc;            /* context shared between parsing and bytecode generation */
+
+    BytecodeEmitter *parent;        /* enclosing function or global context */
+
     struct {
         jsbytecode  *base;          /* base of JS bytecode vector */
         jsbytecode  *limit;         /* one byte beyond end of bytecode */
         jsbytecode  *next;          /* pointer to next free bytecode */
         jssrcnote   *notes;         /* source notes, see below */
         unsigned    noteCount;      /* number of source notes so far */
         unsigned    noteLimit;      /* limit number for source notes in notePool */
         ptrdiff_t   lastNoteOffset; /* code offset for last source note */
@@ -145,35 +149,35 @@ struct BytecodeEmitter : public TreeCont
 
     /* Vectors of pn_cookie slot values. */
     typedef Vector<uint32_t, 8> SlotVector;
     SlotVector      closedArgs;
     SlotVector      closedVars;
 
     uint16_t        typesetCount;   /* Number of JOF_TYPESET opcodes generated */
 
-    BytecodeEmitter(Parser *parser, unsigned lineno);
-    bool init(JSContext *cx, TreeContext::InitBehavior ib = USED_AS_CODE_GENERATOR);
+    /* These two should only be true if sc->inFunction() is false. */
+    const bool      noScriptRval:1;     /* The caller is JS_Compile*Script*. */
+    const bool      needScriptGlobal:1; /* API caller does not want result value 
+                                           from global script. */
 
-    // This is a down-cast.  It's necessary and safe -- although
-    // TreeContext::parent is a |TreeContext *|, a BytecodeEmitter's parent is
-    // always itself a BytecodeEmitter.
-    BytecodeEmitter *parentBCE() {
-        return static_cast<BytecodeEmitter *>(parent);
-    }
+    bool            hasSingletons:1;    /* script contains singleton initializer JSOP_OBJECT */
+
+    BytecodeEmitter(Parser *parser, SharedContext *sc, unsigned lineno,
+                    bool noScriptRval, bool needScriptGlobal);
+    bool init();
 
     /*
      * Note that BytecodeEmitters are magic: they own the arena "top-of-stack"
      * space above their tempMark points. This means that you cannot alloc from
      * tempLifoAlloc and save the pointer beyond the next BytecodeEmitter
      * destructor call.
      */
     ~BytecodeEmitter();
 
-    bool compilingForEval() const { return !!(flags & TCF_COMPILE_FOR_EVAL); }
     JSVersion version() const { return parser->versionWithFlags(); }
 
     bool isAliasedName(ParseNode *pn);
     bool shouldNoteClosedName(ParseNode *pn);
     bool noteClosedVar(ParseNode *pn);
     bool noteClosedArg(ParseNode *pn);
 
     JS_ALWAYS_INLINE
@@ -188,23 +192,23 @@ struct BytecodeEmitter : public TreeCont
         if (!atomIndices->add(p, atom, index))
             return false;
 
         *indexp = index;
         return true;
     }
 
     bool checkSingletonContext() {
-        if (!compileAndGo() || inFunction())
+        if (!parser->compileAndGo || sc->inFunction)
             return false;
-        for (StmtInfo *stmt = topStmt; stmt; stmt = stmt->down) {
+        for (StmtInfo *stmt = sc->topStmt; stmt; stmt = stmt->down) {
             if (STMT_IS_LOOP(stmt))
                 return false;
         }
-        flags |= TCF_HAS_SINGLETONS;
+        hasSingletons = true;
         return true;
     }
 
     bool needsImplicitThis();
 
     TokenStream *tokenStream() { return &parser->tokenStream; }
 
     jsbytecode *base() const { return current->base; }
--- a/js/src/frontend/FoldConstants.cpp
+++ b/js/src/frontend/FoldConstants.cpp
@@ -408,17 +408,17 @@ Boolish(ParseNode *pn)
          * simply results in a truthy object reference. This condition folding
          * is needed for the decompiler. See bug 442342 and bug 443074.
          */
         if (pn->pn_count != 1)
             return Unknown;
         ParseNode *pn2 = pn->pn_head;
         if (!pn2->isKind(PNK_FUNCTION))
             return Unknown;
-        if (!(pn2->pn_funbox->tcflags & TCF_GENEXP_LAMBDA))
+        if (!(pn2->pn_funbox->inGenexpLambda))
             return Unknown;
         return Truthy;
       }
 #endif
 
       case JSOP_DEFFUN:
       case JSOP_LAMBDA:
       case JSOP_TRUE:
@@ -429,93 +429,82 @@ Boolish(ParseNode *pn)
         return Falsy;
 
       default:
         return Unknown;
     }
 }
 
 bool
-js::FoldConstants(JSContext *cx, ParseNode *pn, Parser *parser, bool inCond)
+js::FoldConstants(JSContext *cx, ParseNode *pn, Parser *parser, bool inGenexpLambda, bool inCond)
 {
     ParseNode *pn1 = NULL, *pn2 = NULL, *pn3 = NULL;
 
     JS_CHECK_RECURSION(cx, return false);
 
     switch (pn->getArity()) {
       case PN_FUNC:
-      {
-        TreeContext *tc = parser->tc;
-        uint32_t oldflags = tc->flags;
-        FunctionBox *oldlist = tc->functionList;
-
-        tc->flags = pn->pn_funbox->tcflags;
-        tc->functionList = pn->pn_funbox->kids;
-        if (!FoldConstants(cx, pn->pn_body, parser))
+        if (!FoldConstants(cx, pn->pn_body, parser, pn->pn_funbox->inGenexpLambda))
             return false;
-        pn->pn_funbox->kids = tc->functionList;
-        tc->flags = oldflags;
-        tc->functionList = oldlist;
         break;
-      }
 
       case PN_LIST:
       {
         /* Propagate inCond through logical connectives. */
         bool cond = inCond && (pn->isKind(PNK_OR) || pn->isKind(PNK_AND));
 
         /* Don't fold a parenthesized call expression. See bug 537673. */
         pn1 = pn2 = pn->pn_head;
         if ((pn->isKind(PNK_LP) || pn->isKind(PNK_NEW)) && pn2->isInParens())
             pn2 = pn2->pn_next;
 
         /* Save the list head in pn1 for later use. */
         for (; pn2; pn2 = pn2->pn_next) {
-            if (!FoldConstants(cx, pn2, parser, cond))
+            if (!FoldConstants(cx, pn2, parser, inGenexpLambda, cond))
                 return false;
         }
         break;
       }
 
       case PN_TERNARY:
         /* Any kid may be null (e.g. for (;;)). */
         pn1 = pn->pn_kid1;
         pn2 = pn->pn_kid2;
         pn3 = pn->pn_kid3;
-        if (pn1 && !FoldConstants(cx, pn1, parser, pn->isKind(PNK_IF)))
+        if (pn1 && !FoldConstants(cx, pn1, parser, inGenexpLambda, pn->isKind(PNK_IF)))
             return false;
         if (pn2) {
-            if (!FoldConstants(cx, pn2, parser, pn->isKind(PNK_FORHEAD)))
+            if (!FoldConstants(cx, pn2, parser, inGenexpLambda, pn->isKind(PNK_FORHEAD)))
                 return false;
             if (pn->isKind(PNK_FORHEAD) && pn2->isOp(JSOP_TRUE)) {
                 parser->freeTree(pn2);
                 pn->pn_kid2 = NULL;
             }
         }
-        if (pn3 && !FoldConstants(cx, pn3, parser))
+        if (pn3 && !FoldConstants(cx, pn3, parser, inGenexpLambda))
             return false;
         break;
 
       case PN_BINARY:
         pn1 = pn->pn_left;
         pn2 = pn->pn_right;
 
         /* Propagate inCond through logical connectives. */
         if (pn->isKind(PNK_OR) || pn->isKind(PNK_AND)) {
-            if (!FoldConstants(cx, pn1, parser, inCond))
+            if (!FoldConstants(cx, pn1, parser, inGenexpLambda, inCond))
                 return false;
-            if (!FoldConstants(cx, pn2, parser, inCond))
+            if (!FoldConstants(cx, pn2, parser, inGenexpLambda, inCond))
                 return false;
             break;
         }
 
         /* First kid may be null (for default case in switch). */
-        if (pn1 && !FoldConstants(cx, pn1, parser, pn->isKind(PNK_WHILE)))
+        if (pn1 && !FoldConstants(cx, pn1, parser, inGenexpLambda, pn->isKind(PNK_WHILE)))
             return false;
-        if (!FoldConstants(cx, pn2, parser, pn->isKind(PNK_DOWHILE)))
+        if (!FoldConstants(cx, pn2, parser, inGenexpLambda, pn->isKind(PNK_DOWHILE)))
             return false;
         break;
 
       case PN_UNARY:
         pn1 = pn->pn_kid;
 
         /*
          * Kludge to deal with typeof expressions: because constant folding
@@ -524,39 +513,39 @@ js::FoldConstants(JSContext *cx, ParseNo
          *
          * NB: We know that if pn->pn_op is JSOP_TYPEOF, pn1 will not be
          * null. This assumption does not hold true for other unary
          * expressions.
          */
         if (pn->isOp(JSOP_TYPEOF) && !pn1->isKind(PNK_NAME))
             pn->setOp(JSOP_TYPEOFEXPR);
 
-        if (pn1 && !FoldConstants(cx, pn1, parser, pn->isOp(JSOP_NOT)))
+        if (pn1 && !FoldConstants(cx, pn1, parser, inGenexpLambda, pn->isOp(JSOP_NOT)))
             return false;
         break;
 
       case PN_NAME:
         /*
          * Skip pn1 down along a chain of dotted member expressions to avoid
          * excessive recursion.  Our only goal here is to fold constants (if
          * any) in the primary expression operand to the left of the first
          * dot in the chain.
          */
         if (!pn->isUsed()) {
             pn1 = pn->pn_expr;
             while (pn1 && pn1->isArity(PN_NAME) && !pn1->isUsed())
                 pn1 = pn1->pn_expr;
-            if (pn1 && !FoldConstants(cx, pn1, parser))
+            if (pn1 && !FoldConstants(cx, pn1, parser, inGenexpLambda))
                 return false;
         }
         break;
 
       case PN_NAMESET:
         pn1 = pn->pn_tree;
-        if (!FoldConstants(cx, pn1, parser))
+        if (!FoldConstants(cx, pn1, parser, inGenexpLambda))
             return false;
         break;
 
       case PN_NULLARY:
         break;
     }
 
     switch (pn->getKind()) {
@@ -584,17 +573,17 @@ js::FoldConstants(JSContext *cx, ParseNo
             break;
           default:
             /* Early return to dodge common code that copies pn2 to pn. */
             return true;
         }
 
 #if JS_HAS_GENERATOR_EXPRS
         /* Don't fold a trailing |if (0)| in a generator expression. */
-        if (!pn2 && (parser->tc->flags & TCF_GENEXP_LAMBDA))
+        if (!pn2 && inGenexpLambda)
             break;
 #endif
 
         if (pn2 && !pn2->isDefn())
             pn->become(pn2);
         if (!pn2 || (pn->isKind(PNK_SEMI) && !pn->pn_kid)) {
             /*
              * False condition and no else, or an empty then-statement was
--- a/js/src/frontend/FoldConstants.h
+++ b/js/src/frontend/FoldConstants.h
@@ -41,13 +41,14 @@
 #ifndef FoldConstants_h__
 #define FoldConstants_h__
 
 #include "jsprvtd.h"
 
 namespace js {
 
 bool
-FoldConstants(JSContext *cx, ParseNode *pn, Parser *parser, bool inCond = false);
+FoldConstants(JSContext *cx, ParseNode *pn, Parser *parser, bool inGenexpLambda = false,
+              bool inCond = false);
 
 } /* namespace js */
 
 #endif /* FoldConstants_h__ */
--- a/js/src/frontend/ParseNode-inl.h
+++ b/js/src/frontend/ParseNode-inl.h
@@ -195,21 +195,21 @@ NameNode::dump(int indent)
         indent += strlen(name) + 2;
         DumpParseTree(expr(), indent);
         fprintf(stderr, ")");
     }
 }
 #endif
 
 inline void
-NameNode::initCommon(TreeContext *tc)
+NameNode::initCommon(SharedContext *sc)
 {
     pn_expr = NULL;
     pn_cookie.makeFree();
-    pn_dflags = (!tc->topStmt || tc->topStmt->type == STMT_BLOCK)
+    pn_dflags = (!sc->topStmt || sc->topStmt->type == STMT_BLOCK)
                 ? PND_BLOCKCHILD
                 : 0;
-    pn_blockid = tc->blockid();
+    pn_blockid = sc->blockid();
 }
 
 } /* namespace js */
 
 #endif /* ParseNode_inl_h__ */
--- a/js/src/frontend/ParseNode.cpp
+++ b/js/src/frontend/ParseNode.cpp
@@ -107,17 +107,17 @@ ParseNode::clear()
     pn_arity = PN_NULLARY;
     pn_parens = false;
 }
 
 bool
 FunctionBox::inAnyDynamicScope() const
 {
     for (const FunctionBox *funbox = this; funbox; funbox = funbox->parent) {
-        if (funbox->tcflags & (TCF_IN_WITH | TCF_FUN_EXTENSIBLE_SCOPE))
+        if (funbox->inWith || (funbox->tcflags & TCF_FUN_EXTENSIBLE_SCOPE))
             return true;
     }
     return false;
 }
 
 bool
 FunctionBox::scopeIsExtensible() const
 {
@@ -435,25 +435,25 @@ ParseNode::newBinaryOrAppend(ParseNodeKi
         parser->freeTree(right);
         return left;
     }
 
     return parser->new_<BinaryNode>(kind, op, left, right);
 }
 
 // Nb: unlike most functions that are passed a Parser, this one gets a
-// TreeContext passed in separately, because in this case |tc| may not equal
-// |parser->tc|.
+// SharedContext passed in separately, because in this case |sc| may not equal
+// |parser->tc->sc|.
 NameNode *
-NameNode::create(ParseNodeKind kind, JSAtom *atom, Parser *parser, TreeContext *tc)
+NameNode::create(ParseNodeKind kind, JSAtom *atom, Parser *parser, SharedContext *sc)
 {
     ParseNode *pn = ParseNode::create(kind, PN_NAME, parser);
     if (pn) {
         pn->pn_atom = atom;
-        ((NameNode *)pn)->initCommon(tc);
+        ((NameNode *)pn)->initCommon(sc);
     }
     return (NameNode *)pn;
 }
 
 const char js_argument_str[] = "argument";
 const char js_variable_str[] = "variable";
 const char js_unknown_str[]  = "unknown";
 
@@ -475,17 +475,17 @@ Definition::kindString(Kind kind)
  * This function assumes the cloned tree is for use in the same statement and
  * binding context as the original tree.
  */
 static ParseNode *
 CloneParseTree(ParseNode *opn, Parser *parser)
 {
     TreeContext *tc = parser->tc;
 
-    JS_CHECK_RECURSION(tc->context, return NULL);
+    JS_CHECK_RECURSION(tc->sc->context, return NULL);
 
     ParseNode *pn = parser->new_<ParseNode>(opn->getKind(), opn->getOp(), opn->getArity(),
                                             opn->pn_pos);
     if (!pn)
         return NULL;
     pn->setInParens(opn->isInParens());
     pn->setDefn(opn->isDefn());
     pn->setUsed(opn->isUsed());
--- a/js/src/frontend/ParseNode.h
+++ b/js/src/frontend/ParseNode.h
@@ -1060,19 +1060,19 @@ struct FunctionNode : public ParseNode {
     }
 
 #ifdef DEBUG
     inline void dump(int indent);
 #endif
 };
 
 struct NameNode : public ParseNode {
-    static NameNode *create(ParseNodeKind kind, JSAtom *atom, Parser *parser, TreeContext *tc);
+    static NameNode *create(ParseNodeKind kind, JSAtom *atom, Parser *parser, SharedContext *sc);
 
-    inline void initCommon(TreeContext *tc);
+    inline void initCommon(SharedContext *sc);
 
 #ifdef DEBUG
     inline void dump(int indent);
 #endif
 };
 
 struct NameSetNode : public ParseNode {
     static inline NameSetNode *create(ParseNodeKind kind, Parser *parser) {
@@ -1538,16 +1538,19 @@ struct FunctionBox : public ObjectBox
     FunctionBox         *siblings;
     FunctionBox         *kids;
     FunctionBox         *parent;
     Bindings            bindings;               /* bindings for this function */
     uint32_t            queued:1,
                         inLoop:1,               /* in a loop in parent function */
                         level:JSFB_LEVEL_BITS;
     uint32_t            tcflags;
+    bool                inWith:1;               /* some enclosing scope is a with-statement
+                                                   or E4X filter-expression */
+    bool                inGenexpLambda:1;       /* lambda from generator expression */
 
     JSFunction *function() const { return (JSFunction *) object; }
 
     /*
      * True if this function is inside the scope of a with-statement, an E4X
      * filter-expression, or a function that uses direct eval.
      */
     bool inAnyDynamicScope() const;
--- a/js/src/frontend/Parser.cpp
+++ b/js/src/frontend/Parser.cpp
@@ -105,30 +105,31 @@ using namespace js::frontend;
         if (tokenStream.getToken((__flags)) != tt) {                                        \
             reportErrorNumber(NULL, JSREPORT_ERROR, errno);                                 \
             return NULL;                                                                    \
         }                                                                                   \
     JS_END_MACRO
 #define MUST_MATCH_TOKEN(tt, errno) MUST_MATCH_TOKEN_WITH_FLAGS(tt, errno, 0)
 
 Parser::Parser(JSContext *cx, JSPrincipals *prin, JSPrincipals *originPrin,
-               StackFrame *cfp, bool foldConstants)
+               StackFrame *cfp, bool foldConstants, bool compileAndGo)
   : AutoGCRooter(cx, PARSER),
     context(cx),
     tokenStream(cx, prin, originPrin),
     principals(NULL),
     originPrincipals(NULL),
     callerFrame(cfp),
     callerVarObj(cfp ? &cfp->varObj() : NULL),
     allocator(cx),
     functionCount(0),
     traceListHead(NULL),
     tc(NULL),
     keepAtoms(cx->runtime),
-    foldConstants(foldConstants)
+    foldConstants(foldConstants),
+    compileAndGo(compileAndGo)
 {
     cx->activeCompilations++;
     PodArrayZero(tempFreeList);
     setPrincipals(prin, originPrin);
     JS_ASSERT_IF(cfp, cfp->isScriptFrame());
 }
 
 bool
@@ -215,42 +216,42 @@ Parser::newFunctionBox(JSObject *obj, Pa
         return NULL;
     }
     funbox->traceLink = traceListHead;
     traceListHead = funbox;
     funbox->emitLink = NULL;
     funbox->object = obj;
     funbox->isFunctionBox = true;
     funbox->node = fn;
-    funbox->siblings = tc->functionList;
-    tc->functionList = funbox;
+    funbox->siblings = tc->sc->functionList;
+    tc->sc->functionList = funbox;
     ++functionCount;
     funbox->kids = NULL;
-    funbox->parent = tc->funbox;
+    funbox->parent = tc->sc->funbox;
     new (&funbox->bindings) Bindings(context);
     funbox->queued = false;
     funbox->inLoop = false;
-    for (StmtInfo *stmt = tc->topStmt; stmt; stmt = stmt->down) {
+    for (StmtInfo *stmt = tc->sc->topStmt; stmt; stmt = stmt->down) {
         if (STMT_IS_LOOP(stmt)) {
             funbox->inLoop = true;
             break;
         }
     }
-    funbox->level = tc->staticLevel;
-    funbox->tcflags = (TCF_IN_FUNCTION | (tc->flags & (TCF_COMPILE_N_GO | TCF_STRICT_MODE_CODE)));
-    if (tc->innermostWith)
-        funbox->tcflags |= TCF_IN_WITH;
-    if (!tc->inFunction()) {
-        JSObject *scope = tc->scopeChain();
+    funbox->level = tc->sc->staticLevel;
+    funbox->tcflags = tc->sc->flags & TCF_STRICT_MODE_CODE;
+    funbox->inWith = !!tc->innermostWith;
+    if (!tc->sc->inFunction) {
+        JSObject *scope = tc->sc->scopeChain();
         while (scope) {
             if (scope->isWith())
-                funbox->tcflags |= TCF_IN_WITH;
+                funbox->inWith = true;
             scope = scope->enclosingScope();
         }
     }
+    funbox->inGenexpLambda = false;
     return funbox;
 }
 
 void
 Parser::trace(JSTracer *trc)
 {
     ObjectBox *objbox = traceListHead;
     while (objbox) {
@@ -260,24 +261,24 @@ Parser::trace(JSTracer *trc)
         objbox = objbox->traceLink;
     }
 
     for (TreeContext *tc = this->tc; tc; tc = tc->parent)
         tc->trace(trc);
 }
 
 static bool
-GenerateBlockIdForStmtNode(ParseNode *pn, TreeContext *tc)
+GenerateBlockIdForStmtNode(ParseNode *pn, SharedContext *sc)
 {
-    JS_ASSERT(tc->topStmt);
-    JS_ASSERT(STMT_MAYBE_SCOPE(tc->topStmt));
+    JS_ASSERT(sc->topStmt);
+    JS_ASSERT(STMT_MAYBE_SCOPE(sc->topStmt));
     JS_ASSERT(pn->isKind(PNK_STATEMENTLIST) || pn->isKind(PNK_LEXICALSCOPE));
-    if (!GenerateBlockId(tc, tc->topStmt->blockid))
+    if (!GenerateBlockId(sc, sc->topStmt->blockid))
         return false;
-    pn->pn_blockid = tc->topStmt->blockid;
+    pn->pn_blockid = sc->topStmt->blockid;
     return true;
 }
 
 /*
  * Parse a top-level JS script.
  */
 ParseNode *
 Parser::parse(JSObject *chain)
@@ -285,21 +286,22 @@ Parser::parse(JSObject *chain)
     /*
      * Protect atoms from being collected by a GC activation, which might
      * - nest on this thread due to out of memory (the so-called "last ditch"
      *   GC attempted within js_NewGCThing), or
      * - run for any reason on another thread if this thread is suspended on
      *   an object lock before it finishes generating bytecode into a script
      *   protected from the GC by a root or a stack frame reference.
      */
-    TreeContext globaltc(this);
+    SharedContext globalsc(context, /* inFunction = */ false);
+    TreeContext globaltc(this, &globalsc);
     if (!globaltc.init(context))
         return NULL;
-    globaltc.setScopeChain(chain);
-    if (!GenerateBlockId(&globaltc, globaltc.bodyid))
+    globalsc.setScopeChain(chain);
+    if (!GenerateBlockId(&globalsc, globalsc.bodyid))
         return NULL;
 
     ParseNode *pn = statements();
     if (pn) {
         if (!tokenStream.matchToken(TOK_EOF)) {
             reportErrorNumber(NULL, JSREPORT_ERROR, JSMSG_SYNTAX_ERROR);
             pn = NULL;
         } else if (foldConstants) {
@@ -437,48 +439,48 @@ HasFinalReturn(ParseNode *pn)
     }
 }
 
 static JSBool
 ReportBadReturn(JSContext *cx, Parser *parser, ParseNode *pn, unsigned flags, unsigned errnum,
                 unsigned anonerrnum)
 {
     JSAutoByteString name;
-    if (parser->tc->fun()->atom) {
-        if (!js_AtomToPrintableString(cx, parser->tc->fun()->atom, &name))
+    if (parser->tc->sc->fun()->atom) {
+        if (!js_AtomToPrintableString(cx, parser->tc->sc->fun()->atom, &name))
             return false;
     } else {
         errnum = anonerrnum;
     }
     return ReportCompileErrorNumber(cx, TS(parser), pn, flags, errnum, name.ptr());
 }
 
 static JSBool
 CheckFinalReturn(JSContext *cx, Parser *parser, ParseNode *pn)
 {
-    JS_ASSERT(parser->tc->inFunction());
+    JS_ASSERT(parser->tc->sc->inFunction);
     return HasFinalReturn(pn) == ENDS_IN_RETURN ||
            ReportBadReturn(cx, parser, pn, JSREPORT_WARNING | JSREPORT_STRICT,
                            JSMSG_NO_RETURN_VALUE, JSMSG_ANON_NO_RETURN_VALUE);
 }
 
 /*
  * Check that it is permitted to assign to lhs.  Strict mode code may not
  * assign to 'eval' or 'arguments'.
  */
 static bool
 CheckStrictAssignment(JSContext *cx, Parser *parser, ParseNode *lhs)
 {
-    if (parser->tc->needStrictChecks() && lhs->isKind(PNK_NAME)) {
+    if (parser->tc->sc->needStrictChecks() && lhs->isKind(PNK_NAME)) {
         JSAtom *atom = lhs->pn_atom;
         JSAtomState *atomState = &cx->runtime->atomState;
         if (atom == atomState->evalAtom || atom == atomState->argumentsAtom) {
             JSAutoByteString name;
             if (!js_AtomToPrintableString(cx, atom, &name) ||
-                !ReportStrictModeError(cx, TS(parser), parser->tc, lhs, JSMSG_DEPRECATED_ASSIGN,
+                !ReportStrictModeError(cx, TS(parser), parser->tc->sc, lhs, JSMSG_DEPRECATED_ASSIGN,
                                        name.ptr())) {
                 return false;
             }
         }
     }
     return true;
 }
 
@@ -486,80 +488,80 @@ CheckStrictAssignment(JSContext *cx, Par
  * Check that it is permitted to introduce a binding for atom.  Strict mode
  * forbids introducing new definitions for 'eval', 'arguments', or for any
  * strict mode reserved keyword.  Use pn for reporting error locations, or use
  * tc's token stream if pn is NULL.
  */
 bool
 CheckStrictBinding(JSContext *cx, Parser *parser, PropertyName *name, ParseNode *pn)
 {
-    if (!parser->tc->needStrictChecks())
+    if (!parser->tc->sc->needStrictChecks())
         return true;
 
     JSAtomState *atomState = &cx->runtime->atomState;
     if (name == atomState->evalAtom ||
         name == atomState->argumentsAtom ||
         FindKeyword(name->charsZ(), name->length()))
     {
         JSAutoByteString bytes;
         if (!js_AtomToPrintableString(cx, name, &bytes))
             return false;
-        return ReportStrictModeError(cx, TS(parser), parser->tc, pn, JSMSG_BAD_BINDING,
+        return ReportStrictModeError(cx, TS(parser), parser->tc->sc, pn, JSMSG_BAD_BINDING,
                                      bytes.ptr());
     }
 
     return true;
 }
 
 static bool
 ReportBadParameter(JSContext *cx, Parser *parser, JSAtom *name, unsigned errorNumber)
 {
     Definition *dn = parser->tc->decls.lookupFirst(name);
     JSAutoByteString bytes;
     return js_AtomToPrintableString(cx, name, &bytes) &&
-           ReportStrictModeError(cx, TS(parser), parser->tc, dn, errorNumber, bytes.ptr());
+           ReportStrictModeError(cx, TS(parser), parser->tc->sc, dn, errorNumber, bytes.ptr());
 }
 
 /*
  * In strict mode code, all parameter names must be distinct, must not be
  * strict mode reserved keywords, and must not be 'eval' or 'arguments'.  We
  * must perform these checks here, and not eagerly during parsing, because a
  * function's body may turn on strict mode for the function head.
  */
 static bool
 CheckStrictParameters(JSContext *cx, Parser *parser)
 {
-    TreeContext *tc = parser->tc;
-    JS_ASSERT(tc->inFunction());
-
-    if (!tc->needStrictChecks() || tc->bindings.numArgs() == 0)
+    SharedContext *sc = parser->tc->sc;
+    JS_ASSERT(sc->inFunction);
+
+    if (!sc->needStrictChecks() || sc->bindings.numArgs() == 0)
         return true;
 
     JSAtom *argumentsAtom = cx->runtime->atomState.argumentsAtom;
     JSAtom *evalAtom = cx->runtime->atomState.evalAtom;
 
     /* name => whether we've warned about the name already */
     HashMap<JSAtom *, bool> parameters(cx);
-    if (!parameters.init(tc->bindings.numArgs()))
+    if (!parameters.init(sc->bindings.numArgs()))
         return false;
 
     /* Start with lastVariable(), not lastArgument(), for destructuring. */
-    for (Shape::Range r = tc->bindings.lastVariable(); !r.empty(); r.popFront()) {
+    for (Shape::Range r = sc->bindings.lastVariable(); !r.empty(); r.popFront()) {
         jsid id = r.front().propid();
         if (!JSID_IS_ATOM(id))
             continue;
 
         JSAtom *name = JSID_TO_ATOM(id);
 
         if (name == argumentsAtom || name == evalAtom) {
             if (!ReportBadParameter(cx, parser, name, JSMSG_BAD_BINDING))
                 return false;
         }
 
-        if (tc->inStrictMode() && FindKeyword(name->charsZ(), name->length())) {
+        if (sc->inStrictMode() && FindKeyword(name->charsZ(), name->length())) {
             /*
              * JSOPTION_STRICT is supposed to warn about future keywords, too,
              * but we took care of that in the scanner.
              */
             JS_ALWAYS_TRUE(!ReportBadParameter(cx, parser, name, JSMSG_RESERVED_ID));
             return false;
         }
 
@@ -576,73 +578,74 @@ CheckStrictParameters(JSContext *cx, Par
                 return false;
         }
     }
 
     return true;
 }
 
 static bool
-BindLocalVariable(JSContext *cx, TreeContext *tc, ParseNode *pn, BindingKind kind)
+BindLocalVariable(JSContext *cx, SharedContext *sc, ParseNode *pn, BindingKind kind)
 {
     JS_ASSERT(kind == VARIABLE || kind == CONSTANT);
 
-    unsigned index = tc->bindings.numVars();
-    if (!tc->bindings.add(cx, RootedVarAtom(cx, pn->pn_atom), kind))
+    unsigned index = sc->bindings.numVars();
+    if (!sc->bindings.add(cx, RootedVarAtom(cx, pn->pn_atom), kind))
         return false;
 
-    pn->pn_cookie.set(tc->staticLevel, index);
+    pn->pn_cookie.set(sc->staticLevel, index);
     pn->pn_dflags |= PND_BOUND;
     return true;
 }
 
 ParseNode *
 Parser::functionBody(FunctionBodyType type)
 {
-    JS_ASSERT(tc->inFunction());
+    JS_ASSERT(tc->sc->inFunction);
 
     StmtInfo stmtInfo(context);
-    PushStatement(tc, &stmtInfo, STMT_BLOCK, -1);
+    PushStatement(tc->sc, &stmtInfo, STMT_BLOCK, -1);
     stmtInfo.flags = SIF_BODY_BLOCK;
 
-    unsigned oldflags = tc->flags;
-    tc->flags &= ~(TCF_RETURN_EXPR | TCF_RETURN_VOID);
+    unsigned oldflags = tc->sc->flags;
+    JS_ASSERT(!tc->hasReturnExpr && !tc->hasReturnVoid);
 
     ParseNode *pn;
     if (type == StatementListBody) {
         pn = statements();
     } else {
         JS_ASSERT(type == ExpressionBody);
         JS_ASSERT(JS_HAS_EXPR_CLOSURES);
         pn = UnaryNode::create(PNK_RETURN, this);
         if (pn) {
             pn->pn_kid = assignExpr();
             if (!pn->pn_kid) {
                 pn = NULL;
             } else {
-                if (tc->flags & TCF_FUN_IS_GENERATOR) {
+                if (tc->sc->flags & TCF_FUN_IS_GENERATOR) {
                     ReportBadReturn(context, this, pn, JSREPORT_ERROR,
                                     JSMSG_BAD_GENERATOR_RETURN,
                                     JSMSG_BAD_ANON_GENERATOR_RETURN);
                     pn = NULL;
                 } else {
                     pn->setOp(JSOP_RETURN);
                     pn->pn_pos.end = pn->pn_kid->pn_pos.end;
                 }
             }
         }
     }
 
     if (pn) {
-        JS_ASSERT(!(tc->topStmt->flags & SIF_SCOPE));
-        PopStatementTC(tc);
+        JS_ASSERT(!(tc->sc->topStmt->flags & SIF_SCOPE));
+        PopStatementSC(tc->sc);
 
         /* Check for falling off the end of a function that returns a value. */
-        if (context->hasStrictOption() && (tc->flags & TCF_RETURN_EXPR) &&
-            !CheckFinalReturn(context, this, pn)) {
+        if (context->hasStrictOption() && tc->hasReturnExpr &&
+            !CheckFinalReturn(context, this, pn))
+        {
             pn = NULL;
         }
     }
 
     /*
      * Check CheckStrictParameters before arguments logic below adds
      * 'arguments' to bindings.
      */
@@ -658,17 +661,17 @@ Parser::functionBody(FunctionBodyType ty
      * have decls and, even if it did, they will not be noted as closed in the
      * emitter. Thus, in the corner case of function-statement-overridding-
      * arguments, flag the whole scope as dynamic.
      */
     if (FuncStmtSet *set = tc->funcStmts) {
         for (FuncStmtSet::Range r = set->all(); !r.empty(); r.popFront()) {
             PropertyName *name = r.front()->asPropertyName();
             if (name == arguments)
-                tc->noteBindingsAccessedDynamically();
+                tc->sc->noteBindingsAccessedDynamically();
             else if (Definition *dn = tc->decls.lookupFirst(name))
                 dn->pn_dflags |= PND_CLOSED;
         }
     }
 
     /*
      * As explained by the TCF_ARGUMENTS_HAS_LOCAL_BINDING comment, turn uses
      * of 'arguments' into bindings. Use of 'arguments' should never escape a
@@ -678,79 +681,79 @@ Parser::functionBody(FunctionBodyType ty
         JSAtom *atom = r.front().key();
         Definition *dn = r.front().value();
         JS_ASSERT(dn->isPlaceholder());
         if (atom == arguments) {
             /*
              * Turn 'dn' into a proper definition so uses will be bound as
              * GETLOCAL in the emitter.
              */
-            if (!BindLocalVariable(context, tc, dn, VARIABLE))
+            if (!BindLocalVariable(context, tc->sc, dn, VARIABLE))
                 return NULL;
             dn->setOp(JSOP_GETLOCAL);
             dn->pn_dflags &= ~PND_PLACEHOLDER;
 
             /* NB: this leaves r invalid so we must break immediately. */
             tc->lexdeps->remove(arguments);
             break;
         }
     }
 
     /*
      * Even if 'arguments' isn't explicitly mentioned, dynamic name lookup
      * forces an 'arguments' binding.
      */
-    if (tc->bindingsAccessedDynamically() && !tc->bindings.hasBinding(context, arguments)) {
-        if (!tc->bindings.addVariable(context, arguments))
+    if (tc->sc->bindingsAccessedDynamically() && !tc->sc->bindings.hasBinding(context, arguments)) {
+        if (!tc->sc->bindings.addVariable(context, arguments))
             return NULL;
     }
 
     /*
      * Now that all possible 'arguments' bindings have been added, note whether
      * 'arguments' has a local binding and whether it unconditionally needs an
      * arguments object.
      */
-    BindingKind bindKind = tc->bindings.lookup(context, arguments, NULL);
+    BindingKind bindKind = tc->sc->bindings.lookup(context, arguments, NULL);
     if (bindKind == VARIABLE || bindKind == CONSTANT) {
-        tc->noteArgumentsHasLocalBinding();
+        tc->sc->noteArgumentsHasLocalBinding();
 
         /* Dynamic scope access destroys all hope of optimization. */
-        if (tc->bindingsAccessedDynamically())
-            tc->noteDefinitelyNeedsArgsObj();
+        if (tc->sc->bindingsAccessedDynamically())
+