Merge from mozilla-central.
authorDavid Anderson <danderson@mozilla.com>
Tue, 15 May 2012 10:22:19 -0700
changeset 95389 c83c77b4ed05534bfae3ea4ab386365d93fb602c
parent 95268 38e41331c9ee3f4259aa5a1702332ac01a333315 (current diff)
parent 95388 00c7a320165bb5cbf9f5c195d042d83b615e56c4 (diff)
child 95390 06338317eaba9190894a1b60b9ea3d1a8137eb18
push idunknown
push userunknown
push dateunknown
milestone15.0a1
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->