Merge.
authorBrendan Eich <brendan@mozilla.org>
Thu, 05 Jun 2008 14:55:05 -0700
changeset 15280 c1dd1852b4ae66a565b3bcce84c8fe96ae4ed4d5
parent 15279 ddfa674923bd855e5cb66746ad8184bdb91d4683 (current diff)
parent 15265 3878b860a6dc477a40fe47e5d71163c373459ae9 (diff)
child 15281 aba6549b72d1b4d4543d58aef21e2ae32100279d
push idunknown
push userunknown
push dateunknown
milestone1.9.1a1pre
Merge.
--- a/accessible/src/base/nsDocAccessible.cpp
+++ b/accessible/src/base/nsDocAccessible.cpp
@@ -80,17 +80,18 @@
 PRUint32 nsDocAccessible::gLastFocusedAccessiblesState = 0;
 nsIAtom *nsDocAccessible::gLastFocusedFrameType = nsnull;
 
 //-----------------------------------------------------
 // construction
 //-----------------------------------------------------
 nsDocAccessible::nsDocAccessible(nsIDOMNode *aDOMNode, nsIWeakReference* aShell):
   nsHyperTextAccessibleWrap(aDOMNode, aShell), mWnd(nsnull),
-  mScrollPositionChangedTicks(0), mIsContentLoaded(PR_FALSE), mIsLoadCompleteFired(PR_FALSE)
+  mScrollPositionChangedTicks(0), mIsContentLoaded(PR_FALSE),
+  mIsLoadCompleteFired(PR_FALSE), mInFlushPendingEvents(PR_FALSE)
 {
   // For GTK+ native window, we do nothing here.
   if (!mDOMNode)
     return;
 
   // Because of the way document loading happens, the new nsIWidget is created before
   // the old one is removed. Since it creates the nsDocAccessible, for a brief moment
   // there can be 2 nsDocAccessible's for the content area, although for 2 different
@@ -584,17 +585,20 @@ NS_IMETHODIMP nsDocAccessible::Shutdown(
   if (mFireEventTimer) {
     // Doc being shut down before events fired,
     mFireEventTimer->Cancel();
     mFireEventTimer = nsnull;
     if (mEventsToFire.Count() > 0 ) {
       mEventsToFire.Clear();
       // Make sure we release the kung fu death grip which is always
       // there when there are still events left to be fired
-      NS_RELEASE_THIS();
+      // If FlushPendingEvents() is in call stack,
+      // kung fu death grip will be released there.
+      if (!mInFlushPendingEvents)
+        NS_RELEASE_THIS();
     }
   }
 
   // Remove from the cache after other parts of Shutdown(), so that Shutdown() procedures
   // can find the doc or root accessible in the cache if they need it.
   // We don't do this during ShutdownAccessibility() because that is already clearing the cache
   if (!gIsShuttingDownApp)
     gGlobalDocAccessibleCache.Remove(static_cast<void*>(kungFuDeathGripDoc));
@@ -1500,16 +1504,17 @@ nsDocAccessible::FireDelayedAccessibleEv
                                           0, nsITimer::TYPE_ONE_SHOT);
   }
 
   return NS_OK;
 }
 
 NS_IMETHODIMP nsDocAccessible::FlushPendingEvents()
 {
+  mInFlushPendingEvents = PR_TRUE;
   PRUint32 length = mEventsToFire.Count();
   NS_ASSERTION(length, "How did we get here without events to fire?");
   nsCOMPtr<nsIPresShell> presShell = GetPresShell();
   if (!presShell)
     length = 0; // The doc is now shut down, don't fire events in it anymore
   else
     nsAccEvent::ApplyEventRules(mEventsToFire);
   
@@ -1620,17 +1625,18 @@ NS_IMETHODIMP nsDocAccessible::FlushPend
           // Test caret line # -- fire an EVENT_ALERT on the focused node so we can watch the
           // line-number object attribute on it
           nsCOMPtr<nsIAccessible> accForFocus;
           GetAccService()->GetAccessibleFor(gLastFocusedNode, getter_AddRefs(accForFocus));
           nsAccUtils::FireAccEvent(nsIAccessibleEvent::EVENT_ALERT, accForFocus);
 #endif
           nsCOMPtr<nsIAccessibleCaretMoveEvent> caretMoveEvent =
             new nsAccCaretMoveEvent(accessible, caretOffset);
-          NS_ENSURE_TRUE(caretMoveEvent, NS_ERROR_OUT_OF_MEMORY);
+          if (!caretMoveEvent)
+            break; // Out of memory, break out to release kung fu death grip
 
           FireAccessibleEvent(caretMoveEvent);
 
           PRInt32 selectionCount;
           accessibleText->GetSelectionCount(&selectionCount);
           if (selectionCount) {  // There's a selection so fire selection change as well
             nsAccUtils::FireAccEvent(nsIAccessibleEvent::EVENT_TEXT_SELECTION_CHANGED,
                                      accessible, PR_TRUE);
@@ -1656,16 +1662,17 @@ NS_IMETHODIMP nsDocAccessible::FlushPend
     }
   }
   mEventsToFire.Clear(); // Clear out array
   NS_RELEASE_THIS(); // Release kung fu death grip
 
   // After a flood of events, reset so that user input flag is off
   nsAccEvent::ResetLastInputState();
 
+  mInFlushPendingEvents = PR_FALSE;
   return NS_OK;
 }
 
 void nsDocAccessible::FlushEventsCallback(nsITimer *aTimer, void *aClosure)
 {
   nsPIAccessibleDocument *accessibleDoc = static_cast<nsPIAccessibleDocument*>(aClosure);
   NS_ASSERTION(accessibleDoc, "How did we get here without an accessible document?");
   if (accessibleDoc) {
--- a/accessible/src/base/nsDocAccessible.h
+++ b/accessible/src/base/nsDocAccessible.h
@@ -216,13 +216,14 @@ class nsDocAccessible : public nsHyperTe
     PRUint16 mScrollPositionChangedTicks; // Used for tracking scroll events
     PRPackedBool mIsContentLoaded;
     PRPackedBool mIsLoadCompleteFired;
     nsCOMArray<nsIAccessibleEvent> mEventsToFire;
 
 protected:
     PRBool mIsAnchor;
     PRBool mIsAnchorJumped;
+    PRBool mInFlushPendingEvents;
     static PRUint32 gLastFocusedAccessiblesState;
     static nsIAtom *gLastFocusedFrameType;
 };
 
 #endif  
--- a/configure.in
+++ b/configure.in
@@ -4251,16 +4251,28 @@ MOZ_ARG_WITH_STRING(java-include-path,
     JAVA_INCLUDE_PATH=$withval)
 
 JAVA_BIN_PATH=
 MOZ_ARG_WITH_STRING(java-bin-path,
 [  --with-java-bin-path=dir   Location of Java binaries (java, javac, jar)],
     JAVA_BIN_PATH=$withval)
 
 dnl ========================================================
+dnl Use ARM userspace kernel helpers; tell NSPR to enable
+dnl their usage and use them in spidermonkey.
+dnl ========================================================
+MOZ_ARG_WITH_BOOL(arm-kuser,
+[  --with-arm-kuser         Use kuser helpers (Linux/ARM only -- requires kernel 2.6.13 or later)],
+    USE_ARM_KUSER=1,
+    USE_ARM_KUSER=)
+if test -n "$USE_ARM_KUSER"; then
+   AC_DEFINE(USE_ARM_KUSER)
+fi
+
+dnl ========================================================
 dnl =
 dnl = Application
 dnl =
 dnl ========================================================
 
 MOZ_ARG_HEADER(Application)
 
 BUILD_STATIC_LIBS=
@@ -8259,16 +8271,19 @@ if test -z "$MOZ_NATIVE_NSPR" || test "$
         ac_configure_args="$ac_configure_args --enable-optimize"
     fi
     if test "$OS_ARCH" = "WINNT" && test "$NS_TRACE_MALLOC"; then
        ac_configure_args="$ac_configure_args --enable-debug --disable-optimize"
     fi
     if test -n "$HAVE_64BIT_OS"; then
         ac_configure_args="$ac_configure_args --enable-64bit"
     fi
+    if test -n "$USE_ARM_KUSER"; then
+        ac_configure_args="$ac_configure_args --with-arm-kuser"
+    fi
     AC_OUTPUT_SUBDIRS(nsprpub)
     ac_configure_args="$_SUBDIR_CONFIG_ARGS"
 fi
 
 if test -z "$MOZ_NATIVE_NSPR"; then
     # Hack to deal with the fact that we use NSPR_CFLAGS everywhere
     AC_MSG_WARN([Recreating autoconf.mk with updated nspr-config output])
     if test ! "$VACPP" && test "$OS_ARCH" != "WINNT" && test "$OS_ARCH" != "WINCE"; then
--- a/content/base/src/nsGkAtomList.h
+++ b/content/base/src/nsGkAtomList.h
@@ -392,16 +392,17 @@ GK_ATOM(hspace, "hspace")
 GK_ATOM(html, "html")
 GK_ATOM(htmlBaseHref, "html-base-href")
 GK_ATOM(htmlBaseTarget, "html-base-target")
 GK_ATOM(httpEquiv, "http-equiv")
 GK_ATOM(i, "i")
 GK_ATOM(id, "id")
 GK_ATOM(_if, "if")
 GK_ATOM(iframe, "iframe")
+GK_ATOM(ignore, "ignore")
 GK_ATOM(ignorecase, "ignorecase")
 GK_ATOM(ignorekeys, "ignorekeys")
 GK_ATOM(ilayer, "ilayer")
 GK_ATOM(image, "image")
 GK_ATOM(imageClickedPoint, "image-clicked-point")
 GK_ATOM(img, "img")
 GK_ATOM(implementation, "implementation")
 GK_ATOM(implements, "implements")
@@ -797,16 +798,17 @@ GK_ATOM(start_after, "start_after")
 GK_ATOM(start_before, "start_before")
 GK_ATOM(startsWith, "starts-with")
 GK_ATOM(state, "state")
 GK_ATOM(statedatasource, "statedatasource")
 GK_ATOM(staticHint, "staticHint")
 GK_ATOM(statustext, "statustext")
 GK_ATOM(stop, "stop")
 GK_ATOM(stretch, "stretch")
+GK_ATOM(stretch_to_fit, "stretch-to-fit")
 GK_ATOM(strike, "strike")
 GK_ATOM(string, "string")
 GK_ATOM(stringLength, "string-length")
 GK_ATOM(stripSpace, "strip-space")
 GK_ATOM(strong, "strong")
 GK_ATOM(style, "style")
 GK_ATOM(stylesheet, "stylesheet")
 GK_ATOM(stylesheetPrefix, "stylesheet-prefix")
--- a/content/html/document/src/nsHTMLDocument.cpp
+++ b/content/html/document/src/nsHTMLDocument.cpp
@@ -3872,29 +3872,31 @@ nsHTMLDocument::GetDocumentAllResult(con
   }
 
   if (!entry->mDocAllList) {
     entry->mDocAllList = new nsContentList(root, DocAllResultMatch,
                                            nsnull, nsnull, PR_TRUE, id);
     NS_ENSURE_TRUE(entry->mDocAllList, NS_ERROR_OUT_OF_MEMORY);
   }
 
+  nsRefPtr<nsContentList> docAllList = entry->mDocAllList;
+
   // Check if there are more than 1 entries. Do this by getting the second one
   // rather than the length since getting the length always requires walking
   // the entire document.
 
-  nsIContent* cont = entry->mDocAllList->Item(1, PR_TRUE);
+  nsIContent* cont = docAllList->Item(1, PR_TRUE);
   if (cont) {
-    NS_ADDREF(*aResult = static_cast<nsIDOMNodeList*>(entry->mDocAllList));
+    NS_ADDREF(*aResult = static_cast<nsIDOMNodeList*>(docAllList));
 
     return NS_OK;
   }
 
   // There's only 0 or 1 items. Return the first one or null.
-  NS_IF_ADDREF(*aResult = entry->mDocAllList->Item(0, PR_TRUE));
+  NS_IF_ADDREF(*aResult = docAllList->Item(0, PR_TRUE));
 
   return NS_OK;
 }
 
 static void
 NotifyEditableStateChange(nsINode *aNode, nsIDocument *aDocument,
                           PRBool aEditable)
 {
--- a/content/xul/content/src/nsXULElement.cpp
+++ b/content/xul/content/src/nsXULElement.cpp
@@ -147,16 +147,18 @@
 #include "nsReadableUtils.h"
 #include "nsITimelineService.h"
 #include "nsIFrame.h"
 #include "nsNodeInfoManager.h"
 #include "nsXBLBinding.h"
 #include "nsEventDispatcher.h"
 #include "nsPresShellIterator.h"
 #include "mozAutoDocUpdate.h"
+#include "nsIDOMXULCommandEvent.h"
+#include "nsIDOMNSEvent.h"
 
 /**
  * Three bits are used for XUL Element's lazy state.
  */
 #define XUL_ELEMENT_CHILDREN_MUST_BE_REBUILT \
   (nsXULElement::eChildrenMustBeRebuilt << XUL_ELEMENT_LAZY_STATE_OFFSET)
 
 #define XUL_ELEMENT_TEMPLATE_CONTENTS_BUILT \
@@ -1643,16 +1645,32 @@ nsXULElement::PreHandleEvent(nsEventChai
 
                 if (!aVisitor.mDOMEvent) {
                     // We need to create a new DOMEvent for the original event
                     nsEventDispatcher::CreateEvent(aVisitor.mPresContext,
                                                    aVisitor.mEvent,
                                                    EmptyString(),
                                                    &aVisitor.mDOMEvent);
                 }
+
+                nsCOMPtr<nsIDOMNSEvent> nsevent =
+                    do_QueryInterface(aVisitor.mDOMEvent);
+                while (nsevent) {
+                    nsCOMPtr<nsIDOMEventTarget> oTarget;
+                    nsevent->GetOriginalTarget(getter_AddRefs(oTarget));
+                    NS_ENSURE_STATE(!SameCOMIdentity(oTarget, commandContent));
+                    nsCOMPtr<nsIDOMEvent> tmp;
+                    nsCOMPtr<nsIDOMXULCommandEvent> commandEvent =
+                        do_QueryInterface(nsevent);
+                    if (commandEvent) {
+                        commandEvent->GetSourceEvent(getter_AddRefs(tmp));
+                    }
+                    nsevent = do_QueryInterface(tmp);
+                }
+
                 event.sourceEvent = aVisitor.mDOMEvent;
 
                 nsEventStatus status = nsEventStatus_eIgnore;
                 nsEventDispatcher::Dispatch(commandContent,
                                             aVisitor.mPresContext,
                                             &event, nsnull, &status);
             } else {
                 NS_WARNING("A XUL element is attached to a command that doesn't exist!\n");
--- a/dom/public/idl/css/nsIDOMCSS2Properties.idl
+++ b/dom/public/idl/css/nsIDOMCSS2Properties.idl
@@ -401,17 +401,17 @@ interface nsIDOMCSS2Properties : nsISupp
 
            attribute DOMString        wordSpacing;
                                         // raises(DOMException) on setting
 
            attribute DOMString        zIndex;
                                         // raises(DOMException) on setting
 };
 
-[scriptable, uuid(c9339b8c-9bdd-4d2a-a61a-55ca609b92bd)]
+[scriptable, uuid(8a5b178d-c805-4f8e-8992-fa7c5c11d08e)]
 interface nsIDOMNSCSS2Properties : nsIDOMCSS2Properties
 {
            /* Non-DOM 2 extensions */
 
            /* Mozilla extension CSS properties */
            attribute DOMString        MozAppearance;
                                         // raises(DOMException) on setting
 
@@ -586,9 +586,11 @@ interface nsIDOMNSCSS2Properties : nsIDO
                                         // raises(DOMException) on setting
 
            attribute DOMString        MozBorderStartStyle;
                                         // raises(DOMException) on setting
 
            attribute DOMString        MozBorderStartWidth;
                                         // raises(DOMException) on setting
 
+           attribute DOMString        MozStackSizing;
+                                        // raises(DOMException) on setting
 };
new file mode 100644
--- /dev/null
+++ b/intl/uconv/tests/unit/test_bug396637.js
@@ -0,0 +1,22 @@
+// Tests conversion of a single byte from UTF-16 to Unicode
+	
+const inString = "A";
+    
+const expectedString = "\ufffd";
+
+const charset = "UTF-16BE";
+
+function run_test() {
+    var ScriptableUnicodeConverter =
+	Components.Constructor("@mozilla.org/intl/scriptableunicodeconverter",
+			       "nsIScriptableUnicodeConverter");
+
+    var converter = new ScriptableUnicodeConverter();
+    converter.charset = charset;
+    try {
+      var outString = converter.ConvertToUnicode(inString) + converter.Finish();
+    } catch(e) {
+      outString = "\ufffd";
+    }
+    do_check_eq(outString, expectedString);
+}
new file mode 100644
--- /dev/null
+++ b/intl/uconv/tests/unit/test_bug399257.js
@@ -0,0 +1,53 @@
+// Tests encoding of characters below U+0020
+const Ci = Components.interfaces;
+const Cc = Components.classes;
+const inString = "Hello\u000aWorld";
+const expectedString = "Hello\nWorld";
+
+
+function run_test() {
+    var failures = false;
+    var ccManager = Cc["@mozilla.org/charset-converter-manager;1"]
+        .getService(Ci.nsICharsetConverterManager);
+    var encodingConverter = Cc["@mozilla.org/intl/scriptableunicodeconverter"]
+        .createInstance(Ci.nsIScriptableUnicodeConverter);
+
+    var charsetList = ccManager.getDecoderList();
+    var counter = 0;
+    while (charsetList.hasMore()) {
+	++counter;
+	var charset = charsetList.getNext();
+
+	// exclude known non-ASCII compatible charsets
+	if (charset.substr(0, "UTF-16".length) == "UTF-16" ||
+	    charset.substr(0, "UTF-32".length) == "UTF-32" ||
+	    charset == "x-imap4-modified-utf7") {
+	    dump("skipping " + counter + " " + charset + "\n");
+	    continue;
+	}
+        dump("testing " + counter + " " + charset + "\n");
+
+        try {
+            encodingConverter.charset = charset;
+        } catch(e) {
+            dump("Warning: couldn't set encoder charset to " + charset + "\n");
+            continue;
+        }
+        var codepageString = encodingConverter.ConvertFromUnicode(inString) +
+            encodingConverter.Finish();
+	if (codepageString != expectedString) {
+	    dump(charset + " encoding failed\n");
+	    for (var i = 0; i < expectedString.length; ++i) {
+		if (codepageString.charAt(i) != expectedString.charAt(i)) {
+		    dump(i.toString(16) + ": 0x" +
+			 codepageString.charCodeAt(i).toString(16) + " != " +
+			 expectedString.charCodeAt(i).toString(16) + "\n");
+		}
+	    }
+	    failures = true;
+	}
+    }
+    if (failures) {
+	do_throw("test failed\n");
+    }
+}
--- a/intl/uconv/ucvlatin/nsUCS2BEToUnicode.cpp
+++ b/intl/uconv/ucvlatin/nsUCS2BEToUnicode.cpp
@@ -54,21 +54,23 @@ UTF16ConvertToUnicode(PRUint8& aState, P
 {
   const char* src = aSrc;
   const char* srcEnd = aSrc + *aSrcLength;
   PRUnichar* dest = aDest;
   PRUnichar* destEnd = aDest + *aDestLength;
 
   if(STATE_FOUND_BOM == aState) // caller found a BOM
   {
-    NS_ASSERTION(*aSrcLength >= 2, "Too few bytes in input");
+    if (*aSrcLength < 2)
+      return NS_ERROR_ILLEGAL_INPUT;
     src+=2;
     aState = STATE_NORMAL;
   } else if(STATE_FIRST_CALL == aState) { // first time called
-    NS_ASSERTION(*aSrcLength >= 2, "Too few bytes in input");
+    if (*aSrcLength < 2)
+      return NS_ERROR_ILLEGAL_INPUT;
 
     // Eliminate BOM (0xFEFF). Note that different endian case is taken care of
     // in |Convert| of LE and BE converters. Here, we only have to
     // deal with the same endian case. That is, 0xFFFE (byte-swapped BOM) is
     // illegal.
     if(0xFEFF == *((PRUnichar*)src)) {
       src+=2;
     } else if(0xFFFE == *((PRUnichar*)src)) {
@@ -154,17 +156,18 @@ nsUTF16BEToUnicode::Convert(const char *
                             PRUnichar * aDest, PRInt32 * aDestLength)
 {
 #ifdef IS_LITTLE_ENDIAN
     // Remove the BOM if we're little-endian. The 'same endian' case with the
     // leading BOM will be taken care of by |UTF16ConvertToUnicode|.
     if(STATE_FIRST_CALL == mState) // Called for the first time.
     {
       mState = STATE_NORMAL;
-      NS_ASSERTION(*aSrcLength >= 2, "Too few bytes in input");
+      if (*aSrcLength < 2)
+        return NS_ERROR_ILLEGAL_INPUT;
       if(0xFFFE == *((PRUnichar*)aSrc)) {
         // eliminate BOM (on LE machines, BE BOM is 0xFFFE)
         mState = STATE_FOUND_BOM;
       } else if(0xFEFF == *((PRUnichar*)aSrc)) {
         *aSrcLength=0;
         *aDestLength=0;
         return NS_ERROR_ILLEGAL_INPUT;
       }
@@ -185,17 +188,18 @@ nsUTF16LEToUnicode::Convert(const char *
                             PRUnichar * aDest, PRInt32 * aDestLength)
 {
 #ifdef IS_BIG_ENDIAN
     // Remove the BOM if we're big-endian. The 'same endian' case with the
     // leading BOM will be taken care of by |UTF16ConvertToUnicode|.
     if(STATE_FIRST_CALL == mState) // first time called
     {
       mState = STATE_NORMAL;
-      NS_ASSERTION(*aSrcLength >= 2, "Too few bytes in input");
+      if (*aSrcLength < 2)
+        return NS_ERROR_ILLEGAL_INPUT;
       if(0xFFFE == *((PRUnichar*)aSrc)) {
         // eliminate BOM (on BE machines, LE BOM is 0xFFFE)
         mState = STATE_FOUND_BOM;
       } else if(0xFEFF == *((PRUnichar*)aSrc)) {
         *aSrcLength=0;
         *aDestLength=0;
         return NS_ERROR_ILLEGAL_INPUT;
       }
@@ -221,17 +225,18 @@ nsUTF16ToUnicode::Reset()
 
 NS_IMETHODIMP
 nsUTF16ToUnicode::Convert(const char * aSrc, PRInt32 * aSrcLength,
                           PRUnichar * aDest, PRInt32 * aDestLength)
 {
     if(STATE_FIRST_CALL == mState) // first time called
     {
       mState = STATE_NORMAL;
-      NS_ASSERTION(*aSrcLength >= 2, "Too few bytes in input");
+      if (*aSrcLength < 2)
+        return NS_ERROR_ILLEGAL_INPUT;
 
       // check if BOM (0xFEFF) is at the beginning, remove it if found, and
       // set mEndian accordingly.
       if(0xFF == PRUint8(aSrc[0]) && 0xFE == PRUint8(aSrc[1])) {
         mState = STATE_FOUND_BOM;
         mEndian = kLittleEndian;
         mFoundBOM = PR_TRUE;
       }
--- a/intl/uconv/util/nsUnicodeEncodeHelper.cpp
+++ b/intl/uconv/util/nsUnicodeEncodeHelper.cpp
@@ -57,18 +57,23 @@ nsresult nsUnicodeEncodeHelper::ConvertB
   PRInt32 destLen = *aDestLength;
 
   PRUnichar med;
   PRInt32 bcw; // byte count for write;
   nsresult res = NS_OK;
 
   while (src < srcEnd) {
     if (!uMapCode((uTable*) aMappingTable, static_cast<PRUnichar>(*(src++)), reinterpret_cast<PRUint16*>(&med))) {
-      res = NS_ERROR_UENC_NOMAPPING;
-      break;
+      if (*(src - 1) < 0x20) {
+        // some tables are missing the 0x00 - 0x20 part
+        med = *(src - 1);
+      } else {
+        res = NS_ERROR_UENC_NOMAPPING;
+        break;
+      }
     }
 
     PRBool charFound;
     if (aScanClass == uMultibytesCharset) {
       NS_ASSERTION(aShiftOutTable, "shift table missing");
       charFound = uGenerateShift(aShiftOutTable, 0, med,
                                  (PRUint8 *)dest, destLen, 
                                  (PRUint32 *)&bcw);
--- a/js/src/jslock.cpp
+++ b/js/src/jslock.cpp
@@ -173,16 +173,34 @@ 1:"
 #include <sys/atomic_op.h>
 
 static JS_INLINE int
 js_CompareAndSwap(jsword *w, jsword ov, jsword nv)
 {
     return !_check_lock((atomic_p)w, ov, nv);
 }
 
+#elif defined(USE_ARM_KUSER)
+
+/* See https://bugzilla.mozilla.org/show_bug.cgi?id=429387 for a
+ * description of this ABI; this is a function provided at a fixed
+ * location by the kernel in the memory space of each process.
+ */
+typedef int (__kernel_cmpxchg_t)(int oldval, int newval, volatile int *ptr);
+#define __kernel_cmpxchg (*(__kernel_cmpxchg_t *)0xffff0fc0)
+
+JS_STATIC_ASSERT(sizeof(jsword) == sizeof(int));
+
+static JS_INLINE int
+js_CompareAndSwap(jsword *w, jsword ov, jsword nv)
+{
+    volatile int *vp = (volatile int*)w;
+    return !__kernel_cmpxchg(ov, nv, vp);
+}
+
 #else
 
 #error "Define NSPR_LOCK if your platform lacks a compare-and-swap instruction."
 
 #endif /* arch-tests */
 
 #endif /* !NSPR_LOCK */
 
--- a/js/src/jslock.h
+++ b/js/src/jslock.h
@@ -221,17 +221,17 @@ extern void js_SetScopeInfo(JSScope *sco
         JSRuntime *_rt = (cx)->runtime;                                       \
         JS_LOCK_RUNTIME_VOID(_rt, e);                                         \
     JS_END_MACRO
 
 #if defined(JS_USE_ONLY_NSPR_LOCKS) ||                                        \
     !( (defined(_WIN32) && defined(_M_IX86)) ||                               \
        (defined(__GNUC__) && defined(__i386__)) ||                            \
        (defined(SOLARIS) && defined(sparc) && defined(ULTRA_SPARC)) ||        \
-       defined(AIX) )
+       defined(AIX) || defined(USE_ARM_KUSER))
 
 #define NSPR_LOCK 1
 
 #undef JS_LOCK0
 #undef JS_UNLOCK0
 #define JS_LOCK0(P,M)   (JS_ACQUIRE_LOCK(((JSLock*)(P)->fat)), (P)->owner = (M))
 #define JS_UNLOCK0(P,M) ((P)->owner = 0, JS_RELEASE_LOCK(((JSLock*)(P)->fat)))
 
--- a/layout/base/nsStyleConsts.h
+++ b/layout/base/nsStyleConsts.h
@@ -123,16 +123,20 @@
 // box-direction
 #define NS_STYLE_BOX_DIRECTION_NORMAL    0
 #define NS_STYLE_BOX_DIRECTION_REVERSE   1
 
 // box-orient
 #define NS_STYLE_BOX_ORIENT_HORIZONTAL 0
 #define NS_STYLE_BOX_ORIENT_VERTICAL   1
 
+// stack-sizing
+#define NS_STYLE_STACK_SIZING_IGNORE         0
+#define NS_STYLE_STACK_SIZING_STRETCH_TO_FIT 1
+
 // Azimuth - See nsStyleAural
 #define NS_STYLE_AZIMUTH_LEFT_SIDE        0x00
 #define NS_STYLE_AZIMUTH_FAR_LEFT         0x01
 #define NS_STYLE_AZIMUTH_LEFT             0x02
 #define NS_STYLE_AZIMUTH_CENTER_LEFT      0x03
 #define NS_STYLE_AZIMUTH_CENTER           0x04
 #define NS_STYLE_AZIMUTH_CENTER_RIGHT     0x05
 #define NS_STYLE_AZIMUTH_RIGHT            0x06
new file mode 100644
--- /dev/null
+++ b/layout/reftests/bugs/346189-1-ref.xul
@@ -0,0 +1,56 @@
+<?xml version="1.0"?>
+
+<?xml-stylesheet href="chrome://global/skin/" type="text/css"?>
+
+<window
+  xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
+  xmlns:html="http://www.w3c.org/1999/xhtml"
+  width="400"
+  height="600">
+
+<vbox>
+  <hbox style="height: 20px;">
+    <spacer style="width: 100px; background: yellow;"/>
+    <spacer style="width: 100px; background: blue;"/>
+    <spacer style="width: 50px; background: yellow;"/>
+    <spacer style="width: 150px; background: green;"/>
+  </hbox>
+
+  <hbox style="height: 20px;">
+    <spacer style="width: 100px; background: yellow;"/>
+    <spacer style="width: 100px; background: blue;"/>
+    <spacer style="width: 50px; background: yellow;"/>
+    <spacer style="width: 150px; background: green;"/>
+  </hbox>
+
+  <hbox style="height: 20px;">
+    <spacer style="width: 100px; background: yellow;"/>
+    <spacer style="width: 100px; background: blue;"/>
+    <spacer style="width: 50px; background: yellow;"/>
+    <spacer style="width: 150px; background: green;"/>
+  </hbox>
+
+  <hbox style="height: 20px;">
+    <spacer style="width: 100px; background: yellow;"/>
+    <spacer style="width: 100px; background: blue;"/>
+    <spacer style="width: 200px; background: green;"/>
+  </hbox>
+
+  <hbox style="height: 20px;">
+    <spacer style="width: 100px; background: yellow;"/>
+    <spacer style="width: 300px; background: green;"/>
+  </hbox>
+
+  <hbox style="height: 20px;">
+    <spacer style="width: 200px; background: yellow;"/>
+    <spacer style="width: 200px; background: green;"/>
+  </hbox>
+
+  <hbox style="height: 20px;">
+    <spacer style="width: 100px; background: yellow;"/>
+    <spacer style="width: 300px; background: green;"/>
+  </hbox>
+
+</vbox>
+
+</window>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/bugs/346189-1.xul
@@ -0,0 +1,71 @@
+<?xml version="1.0"?>
+
+<?xml-stylesheet href="chrome://global/skin/" type="text/css"?>
+
+<window
+  xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
+  xmlns:html="http://www.w3c.org/1999/xhtml"
+  width="400"
+  height="600">
+
+<vbox style="max-width: 400px;">
+  <!-- default: the inner hbox should expand the stack. -->
+  <hbox style="height: 20px;">
+    <stack flex="1" style="background: yellow;">
+      <hbox style="width: 100px; height: 20px; background: blue;" top="0" left="100"/>
+    </stack>
+    <spacer flex="3" style="background: green;"/>
+  </hbox>
+
+  <!-- same as above, with explicit -moz-stack-sizing: stretch-to-fit -->
+  <hbox style="height: 20px;">
+    <stack flex="1" style="background: yellow;">
+      <hbox style="-moz-stack-sizing: stretch-to-fit; width: 100px; height: 20px; background: blue;" top="0" left="100"/>
+    </stack>
+    <spacer flex="3" style="background: green;"/>
+  </hbox>
+
+  <!-- same as above, but with overflow: hidden -->
+  <hbox style="height: 20px;">
+    <stack flex="1" style="overflow: hidden; background: yellow;">
+      <hbox style="-moz-stack-sizing: stretch-to-fit; width: 100px; height: 20px; background: blue;" top="0" left="100"/>
+    </stack>
+    <spacer flex="3" style="background: green; height: 20px;"/>
+  </hbox>
+
+  <!-- inner hbox has stack-sizing: ignore, but the stack doesn't have overflow: hidden set; the stack will stretch
+       just enough to include the child, but no more -->
+  <hbox style="height: 20px;">
+    <stack flex="1" style="background: yellow;">
+      <hbox style="-moz-stack-sizing: ignore; width: 100px; height: 20px; background: blue;" top="0" left="100"/>
+    </stack>
+    <spacer flex="3" style="background: green; height: 20px;"/>
+  </hbox>
+
+  <!-- same as above, except stack has overflow: hidden set, so the blue shouldn't be visible -->
+  <hbox style="height: 20px;">
+    <stack flex="1" style="overflow: hidden; background: yellow;">
+      <hbox style="-moz-stack-sizing: ignore; width: 100px; height: 20px; background: blue;" top="0" left="100"/>
+    </stack>
+    <spacer flex="3" style="background: green; height: 20px;"/>
+  </hbox>
+
+  <!-- no flex on the stack, but an explicit size; the child will cause us to resize the stack during Layout -->
+  <hbox style="height: 20px;">
+    <stack style="width: 100px; background: yellow;">
+      <hbox style="width: 100px; height: 20px; background: transparent;" top="0" left="100"/>
+    </stack>
+    <spacer flex="1" style="background: green;"/>
+  </hbox>
+
+  <!-- same as above, but with stack-sizing: ignore; the stack should not be resized -->
+  <hbox style="height: 20px;">
+    <stack style="width: 100px; background: yellow;">
+      <hbox style="-moz-stack-sizing: ignore; width: 100px; height: 20px; background: transparent;" top="0" left="100"/>
+    </stack>
+    <spacer flex="1" style="background: green;"/>
+  </hbox>
+
+</vbox>
+
+</window>
--- a/layout/reftests/bugs/reftest.list
+++ b/layout/reftests/bugs/reftest.list
@@ -296,16 +296,17 @@ random-if(MOZ_WIDGET_TOOLKIT=="gtk2") ==
 == 341043-1a.html 341043-1-ref.html
 != 341043-1b.html 341043-1-ref.html
 == 343540-1.html 343540-1-ref.html
 == 345267-1a.html 345267-1-ref.html
 == 345267-1b.html 345267-1-ref.html
 == 345267-1c.html 345267-1-ref.html
 == 345267-1d.html 345267-1-ref.html
 != 345563-sub.xhtml 345563-sup.xhtml 
+== 346189-1.xul 346189-1-ref.xul
 == 346774-1a.html 346774-1-ref.html
 == 346774-1b.html 346774-1-ref.html
 == 346774-1c.html 346774-1-ref.html
 == 347348-1.xhtml 347348-1-ref.xhtml
 skip-if(MOZ_WIDGET_TOOLKIT=="windows") == 347496-1.xhtml 347496-1-ref.xhtml # Bug 409150
 == 347912-1.html 347912-1-ref.html
 == 348049-1.xhtml 348049-1-ref.xhtml
 == 348516-1.html 348516-1-ref.html
new file mode 100644
--- /dev/null
+++ b/layout/reftests/first-letter/229764-1.html
@@ -0,0 +1,14 @@
+<!DOCTYPE html>
+<html>
+ <head>
+  <style type="text/css">
+   p:first-letter {
+    float: left;
+   }
+  </style>
+  <title>a first-letter testcase</title>
+ </head>
+ <body>
+  <p>Lorem ipsum dolor sit amet.</p>
+ </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/first-letter/229764-2.html
@@ -0,0 +1,19 @@
+<!DOCTYPE html>
+<html>
+ <head>
+  <style type="text/css">
+   p:first-letter {
+    float: left;
+   }
+  </style>
+  <title>a first-letter testcase</title>
+  <script type="text/javascript">
+  window.onload = function() {
+   document.getElementsByTagName("style")[0].disabled = true;
+  }
+  </script>
+ </head>
+ <body>
+  <p>Lorem ipsum dolor sit amet.</p>
+ </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/first-letter/229764-ref.html
@@ -0,0 +1,9 @@
+<!DOCTYPE html>
+<html>
+ <head>
+  <title>a first-letter testcase</title>
+ </head>
+ <body>
+  <p>Lorem ipsum dolor sit amet.</p>
+ </body>
+</html>
--- a/layout/reftests/first-letter/reftest.list
+++ b/layout/reftests/first-letter/reftest.list
@@ -24,10 +24,12 @@ fails == dynamic-1.html dynamic-1-ref.ht
 random == dynamic-3b.html dynamic-3-ref.html
 == 23605-1.html 23605-1-ref.html
 == 23605-2.html 23605-2-ref.html
 == 23605-3.html 23605-3-ref.html
 == 23605-4.html 23605-4-ref.html
 == 23605-5.html 23605-5-ref.html
 == 23605-6.html 23605-6-ref.html
 random-if(MOZ_WIDGET_TOOLKIT=="gtk2") == 329069-1.html 329069-1-ref.html # failure is font-dependent, may be related to bug 404848
+!= 229764-1.html 229764-ref.html
+== 229764-2.html 229764-ref.html
 == 342120-1.xhtml 342120-1-ref.xhtml
 == 379799-1.html 379799-1-ref.html
--- a/layout/style/nsCSSKeywordList.h
+++ b/layout/style/nsCSSKeywordList.h
@@ -413,16 +413,17 @@ CSS_KEY(smaller, smaller)
 CSS_KEY(soft, soft)
 CSS_KEY(solid, solid)
 CSS_KEY(spell-out, spell_out)
 CSS_KEY(square, square)
 CSS_KEY(start, start)
 CSS_KEY(static, static)
 CSS_KEY(status-bar, status_bar)
 CSS_KEY(stretch, stretch)
+CSS_KEY(stretch-to-fit, stretch_to_fit)
 CSS_KEY(sub, sub)
 CSS_KEY(super, super)
 CSS_KEY(sw-resize, sw_resize)
 CSS_KEY(table, table)
 CSS_KEY(table-caption, table_caption)
 CSS_KEY(table-cell, table_cell)
 CSS_KEY(table-column, table_column)
 CSS_KEY(table-column-group, table_column_group)
--- a/layout/style/nsCSSParser.cpp
+++ b/layout/style/nsCSSParser.cpp
@@ -5065,16 +5065,19 @@ PRBool CSSParserImpl::ParseSingleValuePr
     return ParseVariant(aErrorCode, aValue, VARIANT_HK,
                         nsCSSProps::kSpeakNumeralKTable);
   case eCSSProperty_speak_punctuation:
     return ParseVariant(aErrorCode, aValue, VARIANT_HOK,
                         nsCSSProps::kSpeakPunctuationKTable);
   case eCSSProperty_speech_rate:
     return ParseVariant(aErrorCode, aValue, VARIANT_HN | VARIANT_KEYWORD,
                         nsCSSProps::kSpeechRateKTable);
+  case eCSSProperty_stack_sizing:
+    return ParseVariant(aErrorCode, aValue, VARIANT_HK,
+                        nsCSSProps::kStackSizingKTable);
   case eCSSProperty_stress:
     return ParseVariant(aErrorCode, aValue, VARIANT_HN, nsnull);
   case eCSSProperty_table_layout:
     return ParseVariant(aErrorCode, aValue, VARIANT_AHK,
                         nsCSSProps::kTableLayoutKTable);
   case eCSSProperty_text_align:
     // When we support aligning on a string, we can parse text-align
     // as a string....
--- a/layout/style/nsCSSPropList.h
+++ b/layout/style/nsCSSPropList.h
@@ -511,16 +511,17 @@ CSS_PROP_TEXT(word-spacing, word_spacing
 CSS_PROP_POSITION(z-index, z_index, ZIndex, Position, mZIndex, eCSSType_Value, nsnull)
 
 CSS_PROP_XUL(-moz-box-align, box_align, MozBoxAlign, XUL, mBoxAlign, eCSSType_Value, kBoxAlignKTable) // XXX bug 3935
 CSS_PROP_XUL(-moz-box-direction, box_direction, MozBoxDirection, XUL, mBoxDirection, eCSSType_Value, kBoxDirectionKTable) // XXX bug 3935
 CSS_PROP_XUL(-moz-box-flex, box_flex, MozBoxFlex, XUL, mBoxFlex, eCSSType_Value, nsnull) // XXX bug 3935
 CSS_PROP_XUL(-moz-box-orient, box_orient, MozBoxOrient, XUL, mBoxOrient, eCSSType_Value, kBoxOrientKTable) // XXX bug 3935
 CSS_PROP_XUL(-moz-box-pack, box_pack, MozBoxPack, XUL, mBoxPack, eCSSType_Value, kBoxPackKTable) // XXX bug 3935
 CSS_PROP_XUL(-moz-box-ordinal-group, box_ordinal_group, MozBoxOrdinalGroup, XUL, mBoxOrdinal, eCSSType_Value, nsnull)
+CSS_PROP_XUL(-moz-stack-sizing, stack_sizing, MozStackSizing, XUL, mStackSizing, eCSSType_Value, kStackSizingKTable)
 
 #ifdef MOZ_MATHML
 #ifndef CSS_PROP_LIST_EXCLUDE_INTERNAL
 CSS_PROP_FONT(-moz-script-level, script_level, ScriptLevel, Font, mScriptLevel, eCSSType_Value, nsnull)
 CSS_PROP_FONT(-moz-script-size-multiplier, script_size_multiplier, ScriptSizeMultiplier, Font, mScriptSizeMultiplier, eCSSType_Value, nsnull)
 CSS_PROP_FONT(-moz-script-min-size, script_min_size, ScriptMinSize, Font, mScriptMinSize, eCSSType_Value, nsnull)
 #endif
 #endif
--- a/layout/style/nsCSSProps.cpp
+++ b/layout/style/nsCSSProps.cpp
@@ -855,16 +855,22 @@ const PRInt32 nsCSSProps::kSpeechRateKTa
   eCSSKeyword_medium, NS_STYLE_SPEECH_RATE_MEDIUM,
   eCSSKeyword_fast, NS_STYLE_SPEECH_RATE_FAST,
   eCSSKeyword_x_fast, NS_STYLE_SPEECH_RATE_X_FAST,
   eCSSKeyword_faster, NS_STYLE_SPEECH_RATE_FASTER,
   eCSSKeyword_slower, NS_STYLE_SPEECH_RATE_SLOWER,
   eCSSKeyword_UNKNOWN,-1
 };
 
+const PRInt32 nsCSSProps::kStackSizingKTable[] = {
+  eCSSKeyword_ignore, NS_STYLE_STACK_SIZING_IGNORE,
+  eCSSKeyword_stretch_to_fit, NS_STYLE_STACK_SIZING_STRETCH_TO_FIT,
+  eCSSKeyword_UNKNOWN,-1
+};
+
 const PRInt32 nsCSSProps::kTableLayoutKTable[] = {
   eCSSKeyword_fixed, NS_STYLE_TABLE_LAYOUT_FIXED,
   eCSSKeyword_UNKNOWN,-1
 };
 
 const PRInt32 nsCSSProps::kTextAlignKTable[] = {
   eCSSKeyword_left, NS_STYLE_TEXT_ALIGN_LEFT,
   eCSSKeyword_right, NS_STYLE_TEXT_ALIGN_RIGHT,
--- a/layout/style/nsCSSProps.h
+++ b/layout/style/nsCSSProps.h
@@ -172,16 +172,17 @@ public:
   static const PRInt32 kPageSizeKTable[];
   static const PRInt32 kPitchKTable[];
   static const PRInt32 kPositionKTable[];
   static const PRInt32 kSpeakKTable[];
   static const PRInt32 kSpeakHeaderKTable[];
   static const PRInt32 kSpeakNumeralKTable[];
   static const PRInt32 kSpeakPunctuationKTable[];
   static const PRInt32 kSpeechRateKTable[];
+  static const PRInt32 kStackSizingKTable[];
   static const PRInt32 kTableLayoutKTable[];
   static const PRInt32 kTextAlignKTable[];
   static const PRInt32 kTextDecorationKTable[];
   static const PRInt32 kTextTransformKTable[];
   static const PRInt32 kUnicodeBidiKTable[];
   static const PRInt32 kUserFocusKTable[];
   static const PRInt32 kUserInputKTable[];
   static const PRInt32 kUserModifyKTable[];
--- a/layout/style/nsCSSStruct.h
+++ b/layout/style/nsCSSStruct.h
@@ -543,16 +543,17 @@ struct nsCSSXUL : public nsCSSStruct  {
   ~nsCSSXUL(void);
 
   nsCSSValue  mBoxAlign;
   nsCSSValue  mBoxDirection;
   nsCSSValue  mBoxFlex;
   nsCSSValue  mBoxOrient;
   nsCSSValue  mBoxPack;
   nsCSSValue  mBoxOrdinal;
+  nsCSSValue  mStackSizing;
 private:
   nsCSSXUL(const nsCSSXUL& aOther); // NOT IMPLEMENTED
 };
 
 struct nsRuleDataXUL : public nsCSSXUL {
   nsRuleDataXUL() {}
 private:
   nsRuleDataXUL(const nsRuleDataXUL& aOther); // NOT IMPLEMENTED
--- a/layout/style/nsComputedDOMStyle.cpp
+++ b/layout/style/nsComputedDOMStyle.cpp
@@ -482,16 +482,28 @@ nsComputedDOMStyle::GetCssFloat(nsIDOMCS
 
 nsresult
 nsComputedDOMStyle::GetBottom(nsIDOMCSSValue** aValue)
 {
   return GetOffsetWidthFor(NS_SIDE_BOTTOM, aValue);
 }
 
 nsresult
+nsComputedDOMStyle::GetStackSizing(nsIDOMCSSValue** aValue)
+{
+  nsROCSSPrimitiveValue *val = GetROCSSPrimitiveValue();
+  NS_ENSURE_TRUE(val, NS_ERROR_OUT_OF_MEMORY);
+
+  val->SetIdent(GetStyleXUL()->mStretchStack ? nsGkAtoms::stretch_to_fit :
+                nsGkAtoms::ignore);
+
+  return CallQueryInterface(val, aValue);
+}
+
+nsresult
 nsComputedDOMStyle::SetToRGBAColor(nsROCSSPrimitiveValue* aValue,
                                    nscolor aColor)
 {
   if (NS_GET_A(aColor) == 0) {
     aValue->SetIdent(nsGkAtoms::transparent);
     return NS_OK;
   }
 
@@ -3801,16 +3813,17 @@ nsComputedDOMStyle::GetQueryableProperty
     COMPUTED_STYLE_MAP_ENTRY(_moz_column_gap,               ColumnGap),
     COMPUTED_STYLE_MAP_ENTRY(float_edge,                    FloatEdge),
     COMPUTED_STYLE_MAP_ENTRY(force_broken_image_icon,  ForceBrokenImageIcon),
     COMPUTED_STYLE_MAP_ENTRY(image_region,                  ImageRegion),
     COMPUTED_STYLE_MAP_ENTRY(_moz_outline_radius_bottomLeft, OutlineRadiusBottomLeft),
     COMPUTED_STYLE_MAP_ENTRY(_moz_outline_radius_bottomRight,OutlineRadiusBottomRight),
     COMPUTED_STYLE_MAP_ENTRY(_moz_outline_radius_topLeft,    OutlineRadiusTopLeft),
     COMPUTED_STYLE_MAP_ENTRY(_moz_outline_radius_topRight,   OutlineRadiusTopRight),
+    COMPUTED_STYLE_MAP_ENTRY(stack_sizing,                  StackSizing),
     COMPUTED_STYLE_MAP_ENTRY(user_focus,                    UserFocus),
     COMPUTED_STYLE_MAP_ENTRY(user_input,                    UserInput),
     COMPUTED_STYLE_MAP_ENTRY(user_modify,                   UserModify),
     COMPUTED_STYLE_MAP_ENTRY(user_select,                   UserSelect)
 
 #ifdef MOZ_SVG
     ,
     COMPUTED_STYLE_MAP_ENTRY(clip_path,                     ClipPath),
--- a/layout/style/nsComputedDOMStyle.h
+++ b/layout/style/nsComputedDOMStyle.h
@@ -128,16 +128,17 @@ private:
   nsresult GetMaxHeight(nsIDOMCSSValue** aValue);
   nsresult GetMaxWidth(nsIDOMCSSValue** aValue);
   nsresult GetMinHeight(nsIDOMCSSValue** aValue);
   nsresult GetMinWidth(nsIDOMCSSValue** aValue);
   nsresult GetLeft(nsIDOMCSSValue** aValue);
   nsresult GetTop(nsIDOMCSSValue** aValue);
   nsresult GetRight(nsIDOMCSSValue** aValue);
   nsresult GetBottom(nsIDOMCSSValue** aValue);
+  nsresult GetStackSizing(nsIDOMCSSValue** aValue);
 
   /* Font properties */
   nsresult GetColor(nsIDOMCSSValue** aValue);
   nsresult GetFontFamily(nsIDOMCSSValue** aValue);
   nsresult GetFontStyle(nsIDOMCSSValue** aValue);
   nsresult GetFontSize(nsIDOMCSSValue** aValue);
   nsresult GetFontSizeAdjust(nsIDOMCSSValue** aValue);
   nsresult GetFontWeight(nsIDOMCSSValue** aValue);
--- a/layout/style/nsRuleNode.cpp
+++ b/layout/style/nsRuleNode.cpp
@@ -4520,16 +4520,26 @@ nsRuleNode::ComputeXULData(void* aStartS
     xul->mBoxOrdinal = xulData.mBoxOrdinal.GetIntValue();
   } else if (eCSSUnit_Inherit == xulData.mBoxOrdinal.GetUnit()) {
     inherited = PR_TRUE;
     xul->mBoxOrdinal = parentXUL->mBoxOrdinal;
   } else if (eCSSUnit_Initial == xulData.mBoxOrdinal.GetUnit()) {
     xul->mBoxOrdinal = 1;
   }
 
+  if (eCSSUnit_Inherit == xulData.mStackSizing.GetUnit()) {
+    inherited = PR_TRUE;
+    xul->mStretchStack = parentXUL->mStretchStack;
+  } else if (eCSSUnit_Initial == xulData.mStackSizing.GetUnit()) {
+    xul->mStretchStack = PR_TRUE;
+  } else if (eCSSUnit_Enumerated == xulData.mStackSizing.GetUnit()) {
+    xul->mStretchStack = xulData.mStackSizing.GetIntValue() ==
+      NS_STYLE_STACK_SIZING_STRETCH_TO_FIT;
+  }
+
   COMPUTE_END_RESET(XUL, xul)
 }
 
 const void* 
 nsRuleNode::ComputeColumnData(void* aStartStruct,
                               const nsRuleDataStruct& aData, 
                               nsStyleContext* aContext, 
                               nsRuleNode* aHighestNode,
--- a/layout/style/nsStyleStruct.cpp
+++ b/layout/style/nsStyleStruct.cpp
@@ -568,16 +568,17 @@ nsChangeHint nsStyleList::MaxDifference(
 nsStyleXUL::nsStyleXUL() 
 { 
   mBoxAlign  = NS_STYLE_BOX_ALIGN_STRETCH;
   mBoxDirection = NS_STYLE_BOX_DIRECTION_NORMAL;
   mBoxFlex = 0.0f;
   mBoxOrient = NS_STYLE_BOX_ORIENT_HORIZONTAL;
   mBoxPack   = NS_STYLE_BOX_PACK_START;
   mBoxOrdinal = 1;
+  mStretchStack = PR_TRUE;
 }
 
 nsStyleXUL::~nsStyleXUL() 
 {
 }
 
 nsStyleXUL::nsStyleXUL(const nsStyleXUL& aSource)
 {
--- a/layout/style/nsStyleStruct.h
+++ b/layout/style/nsStyleStruct.h
@@ -1182,16 +1182,17 @@ struct nsStyleXUL {
 #endif
   
   float         mBoxFlex;               // [reset] see nsStyleConsts.h
   PRUint32      mBoxOrdinal;            // [reset] see nsStyleConsts.h
   PRUint8       mBoxAlign;              // [reset] see nsStyleConsts.h
   PRUint8       mBoxDirection;          // [reset] see nsStyleConsts.h
   PRUint8       mBoxOrient;             // [reset] see nsStyleConsts.h
   PRUint8       mBoxPack;               // [reset] see nsStyleConsts.h
+  PRPackedBool  mStretchStack;          // [reset] see nsStyleConsts.h
 };
 
 struct nsStyleColumn {
   nsStyleColumn();
   nsStyleColumn(const nsStyleColumn& aSource);
   ~nsStyleColumn();
 
   void* operator new(size_t sz, nsPresContext* aContext) CPP_THROW_NEW {
--- a/layout/style/test/property_database.js
+++ b/layout/style/test/property_database.js
@@ -437,16 +437,24 @@ var gCSSProperties = {
 		inherited: false,
 		type: CSS_TYPE_SHORTHAND_AND_LONGHAND,
 		get_computed: logical_box_prop_get_computed,
 		/* no subproperties */
 		initial_values: [ "0", "0px", "0%", "0em", "0ex" ],
 		other_values: [ "1px", "3em" ],
 		invalid_values: []
 	},
+	"-moz-stack-sizing": {
+		domProp: "MozStackSizing",
+		inherited: false,
+		type: CSS_TYPE_LONGHAND,
+		initial_values: [ "stretch-to-fit" ],
+		other_values: [ "ignore" ],
+		invalid_values: []
+	},
 	"-moz-user-focus": {
 		domProp: "MozUserFocus",
 		inherited: true,
 		type: CSS_TYPE_LONGHAND,
 		initial_values: [ "none" ],
 		other_values: [ "normal", "ignore", "select-all", "select-before", "select-after", "select-same", "select-menu" ],
 		invalid_values: []
 	},
--- a/layout/xul/base/src/nsStackLayout.cpp
+++ b/layout/xul/base/src/nsStackLayout.cpp
@@ -71,84 +71,91 @@ nsStackLayout::Shutdown()
 {
   NS_IF_RELEASE(gInstance);
 }
 
 nsStackLayout::nsStackLayout()
 {
 }
 
+/*
+ * Sizing: we are as wide as the widest child plus its left offset
+ * we are tall as the tallest child plus its top offset.
+ *
+ * Only children which have -moz-stack-sizing set to stretch-to-fit
+ * (the default) will be included in the size computations.
+ */
+
 nsSize
 nsStackLayout::GetPrefSize(nsIBox* aBox, nsBoxLayoutState& aState)
 {
-  nsSize rpref (0, 0);
-
-  // we are as wide as the widest child plus its left offset
-  // we are tall as the tallest child plus its top offset
+  nsSize prefSize (0, 0);
 
   nsIBox* child = aBox->GetChildBox();
-  while (child) {  
-    nsSize pref = child->GetPrefSize(aState);
+  while (child) {
+    if (child->GetStyleXUL()->mStretchStack) {
+      nsSize pref = child->GetPrefSize(aState);
 
-    AddMargin(child, pref);
-    AddOffset(aState, child, pref);
-    AddLargestSize(rpref, pref);
+      AddMargin(child, pref);
+      AddOffset(aState, child, pref);
+      AddLargestSize(prefSize, pref);
+    }
 
     child = child->GetNextBox();
   }
 
-  // now add our border and padding
-  AddBorderAndPadding(aBox, rpref);
+  AddBorderAndPadding(aBox, prefSize);
 
-  return rpref;
+  return prefSize;
 }
 
 nsSize
 nsStackLayout::GetMinSize(nsIBox* aBox, nsBoxLayoutState& aState)
 {
   nsSize minSize (0, 0);
 
-  // run through all the children and get their min, max, and preferred sizes
+  nsIBox* child = aBox->GetChildBox();
+  while (child) {
+    if (child->GetStyleXUL()->mStretchStack) {
+      nsSize min = child->GetMinSize(aState);
 
-  nsIBox* child = aBox->GetChildBox();
-  while (child) {  
-    nsSize min = child->GetMinSize(aState);
-    AddMargin(child, min);
-    AddOffset(aState, child, min);
-    AddLargestSize(minSize, min);
+      AddMargin(child, min);
+      AddOffset(aState, child, min);
+      AddLargestSize(minSize, min);
+    }
 
     child = child->GetNextBox();
   }
 
-  // now add our border and padding
   AddBorderAndPadding(aBox, minSize);
 
   return minSize;
 }
 
 nsSize
 nsStackLayout::GetMaxSize(nsIBox* aBox, nsBoxLayoutState& aState)
 {
   nsSize maxSize (NS_INTRINSICSIZE, NS_INTRINSICSIZE);
 
-  // run through all the children and get their min, max, and preferred sizes
+  nsIBox* child = aBox->GetChildBox();
+  while (child) {
+    if (child->GetStyleXUL()->mStretchStack) {
+      nsSize min = child->GetMinSize(aState);
+      nsSize max = child->GetMaxSize(aState);
 
-  nsIBox* child = aBox->GetChildBox();
-  while (child) {  
-    nsSize min = child->GetMinSize(aState);
-    nsSize max = nsBox::BoundsCheckMinMax(min, child->GetMaxSize(aState));
+      max = nsBox::BoundsCheckMinMax(min, max);
 
-    AddMargin(child, max);
-    AddOffset(aState, child, max);
-    AddSmallestSize(maxSize, max);
+      AddMargin(child, max);
+      AddOffset(aState, child, max);
+      AddSmallestSize(maxSize, max);
+    }
 
     child = child->GetNextBox();
   }
 
-  // now add our border and padding
   AddBorderAndPadding(aBox, maxSize);
 
   return maxSize;
 }
 
 
 nscoord
 nsStackLayout::GetAscent(nsIBox* aBox, nsBoxLayoutState& aState)
@@ -287,25 +294,27 @@ nsStackLayout::Layout(nsIBox* aBox, nsBo
           // Flow the child.
           child->Layout(aState);
 
           // Get the child's new rect.
           nsRect childRectNoMargin;
           childRectNoMargin = childRect = child->GetRect();
           childRect.Inflate(margin);
 
-          // Did the child push back on us and get bigger?
-          if (offset.width + childRect.width > clientRect.width) {
-            clientRect.width = childRect.width + offset.width;
-            grow = PR_TRUE;
-          }
+          if (child->GetStyleXUL()->mStretchStack) {
+            // Did the child push back on us and get bigger?
+            if (offset.width + childRect.width > clientRect.width) {
+              clientRect.width = childRect.width + offset.width;
+              grow = PR_TRUE;
+            }
 
-          if (offset.height + childRect.height > clientRect.height) {
-            clientRect.height = childRect.height + offset.height;
-            grow = PR_TRUE;
+            if (offset.height + childRect.height > clientRect.height) {
+              clientRect.height = childRect.height + offset.height;
+              grow = PR_TRUE;
+            }
           }
 
           if (childRectNoMargin != oldRect)
           {
             // redraw the new and old positions if the 
             // child moved or resized.
             // if the new and old rect intersect meaning we just moved a little
             // then just redraw the union. If they don't intersect (meaning
--- a/netwerk/dns/src/effective_tld_names.dat
+++ b/netwerk/dns/src/effective_tld_names.dat
@@ -1,8 +1,47 @@
+// ***** BEGIN LICENSE BLOCK *****
+// Version: MPL 1.1/GPL 2.0/LGPL 2.1
+// 
+// The contents of this file are subject to the Mozilla Public License Version 
+// 1.1 (the "License"); you may not use this file except in compliance with 
+// the License. You may obtain a copy of the License at 
+// http://www.mozilla.org/MPL/
+// 
+// Software distributed under the License is distributed on an "AS IS" basis,
+// WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+// for the specific language governing rights and limitations under the
+// License.
+// 
+// The Original Code is the Public Suffix List.
+// 
+// The Initial Developer of the Original Code is
+// Jo Hermans <jo.hermans@gmail.com>.
+// Portions created by the Initial Developer are Copyright (C) 2007
+// the Initial Developer. All Rights Reserved.
+// 
+// Contributor(s):
+//   Ruben Arakelyan <ruben@wackomenace.co.uk>
+// 
+// Alternatively, the contents of this file may be used under the terms of
+// either the GNU General Public License Version 2 or later (the "GPL"), or
+// the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+// in which case the provisions of the GPL or the LGPL are applicable instead
+// of those above. If you wish to allow use of your version of this file only
+// under the terms of either the GPL or the LGPL, and not to allow others to
+// use your version of this file under the terms of the MPL, indicate your
+// 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 *****
+
+// $Id$
+
 // ac : http://en.wikipedia.org/wiki/.ac
 ac
 com.ac
 edu.ac
 gov.ac
 net.ac
 mil.ac
 org.ac
--- a/xpcom/analysis/outparams.js
+++ b/xpcom/analysis/outparams.js
@@ -5,16 +5,18 @@ include('treehydra.js');
 
 include('util.js');
 include('gcc_util.js');
 include('gcc_print.js');
 include('unstable/adts.js');
 include('unstable/analysis.js');
 include('unstable/esp.js');
 include('unstable/liveness.js');
+let Zero_NonZero = {};
+include('unstable/zero_nonzero.js', Zero_NonZero);
 
 include('mayreturn.js');
 
 MapFactory.use_injective = true;
 
 // Print a trace for each function analyzed
 let TRACE_FUNCTIONS = 0;
 // Trace operation of the ESP analysis, use 2 or 3 for more detail
@@ -143,342 +145,217 @@ function OutparamCheck(cfg, psem_list, o
     this.psvar_list.push(v);
   }
   if (trace) {
     print("PS vars");
     for each (let v in this.psvar_list) {
       print("    " + expr_display(v));
     }
   }
-  ESP.Analysis.call(this, cfg, this.psvar_list, av.BOTTOM, av.meet, trace);
+  this.zeroNonzero = new Zero_NonZero.Zero_NonZero();
+  ESP.Analysis.call(this, cfg, this.psvar_list, av.meet, trace);
 }
 
 // Abstract values for outparam check
 function AbstractValue(name, ch) {
   this.name = name;
   this.ch = ch;
 }
 
 AbstractValue.prototype.equals = function(v) {
   return this === v;
 }
 
 AbstractValue.prototype.toString = function() {
   return this.name + ' (' + this.ch + ')';
 }
 
+AbstractValue.prototype.toShortString = function() {
+  return this.ch;
+}
+
 let avspec = [
-  // General-purpose abstract values
-  [ 'BOTTOM',        '.' ],   // any value, also used for dead vars
-
   // Abstract values for outparam contents write status
   [ 'NULL',          'x' ],   // is a null pointer
   [ 'NOT_WRITTEN',   '-' ],   // not written
   [ 'WROTE_NULL',    '/' ],   // had NULL written to
   [ 'WRITTEN',       '+' ],   // had anything written to
   // MAYBE_WRITTEN is special. "Officially", it means the same thing as
   // NOT_WRITTEN. What it really means is that an outparam was passed
   // to another function as a possible outparam (outparam type, but not
   // in last position), so if there is an error with it not being written,
   // we can give a hint about the possible outparam in the warning.
   [ 'MAYBE_WRITTEN', '?' ],   // written if possible outparam is one
-  
-  // Abstract values for rvs
-  [ 'ZERO',          '0' ],   // zero value
-  [ 'NONZERO',       '1' ]    // nonzero value
 ];
 
 let av = {};
 for each (let [name, ch] in avspec) {
   av[name] = new AbstractValue(name, ch);
 }
 
+av.ZERO = Zero_NonZero.Lattice.ZERO;
+av.NONZERO = Zero_NonZero.Lattice.NONZERO;
+
+/*
 av.ZERO.negation = av.NONZERO;
 av.NONZERO.negation = av.ZERO;
 
-let cachedAVs = {};
-
 // Abstract values for int constants. We use these to figure out feasible
 // paths in the presence of GCC finally_tmp-controlled switches.
 function makeIntAV(v) {
   let key = 'int_' + v;
   if (cachedAVs.hasOwnProperty(key)) return cachedAVs[key];
 
   let s = "" + v;
   let ans = cachedAVs[key] = new AbstractValue(s, s);
   ans.int_val = v;
   return ans;
 }
+*/
+
+let cachedAVs = {};
 
 // Abstract values for pointers that contain a copy of an outparam 
 // pointer. We use these to figure out writes to a casted copy of 
 // an outparam passed to another method.
 function makeOutparamAV(v) {
   let key = 'outparam_' + DECL_UID(v);
-  if (cachedAVs.hasOwnProperty(key)) return cachedAVs[key];
+  if (key in cachedAVs) return cachedAVs[key];
 
   let ans = cachedAVs[key] = 
     new AbstractValue('OUTPARAM:' + expr_display(v), 'P');
   ans.outparam = v;
   return ans;
 }
 
 /** Return the integer value if this is an integer av, otherwise undefined. */
 av.intVal = function(v) {
   if (v.hasOwnProperty('int_val'))
     return v.int_val;
   return undefined;
 }
 
 /** Meet function for our abstract values. */
 av.meet = function(v1, v2) {
-  // Important for following cases -- as output, undefined means top here.
-  if (v1 == undefined) v1 = av.BOTTOM;
-  if (v2 == undefined) v2 = av.BOTTOM;
-
-  // These cases apply for any lattice.
-  if (v1 == av.BOTTOM) return v2;
-  if (v2 == av.BOTTOM) return v1;
-  if (v1 == v2) return v1;
+  // At this point we know v1 != v2.
+  let values = [v1,v2]
+  if (values.indexOf(av.LOCKED) != -1
+      || values.indexOf(av.UNLOCKED) != -1)
+    return ESP.NOT_REACHED;
 
-  // At this point we know v1 != v2.
-  switch (v1) {
-  case av.ZERO:
-    return av.intVal(v2) == 0 ? v2 : undefined;
-  case av.NONZERO:
-    // Return a nonempty meet only if the other value is an integer
-    // and is nonzero.
-    let iv2 = av.intVal(v2);
-    return iv2 != undefined && iv2 != 0 ? v2 : undefined;
-  default:
-    let iv = av.intVal(v1);
-    if (iv == 0) return v2 == av.ZERO ? v1 : undefined;
-    if (iv != undefined) return v2 == av.NONZERO ? v1 : undefined;
-    return undefined;
-  }
-}     
+  return Zero_NonZero.meet(v1, v2)
+};
 
 // Outparam check analysis
 OutparamCheck.prototype = new ESP.Analysis;
 
 OutparamCheck.prototype.startValues = function() {
   let ans = create_decl_map();
   for each (let p in this.psvar_list) {
-    ans.put(p, this.outparams.has(p) ? av.NOT_WRITTEN : av.BOTTOM);
+    ans.put(p, this.outparams.has(p) ? av.NOT_WRITTEN : ESP.TOP);
   }
   return ans;
 }
 
+OutparamCheck.prototype.split = function(vbl, v) {
+  // Can't happen for current version of ESP, but could change
+  if (v != ESP.TOP) throw new Error("not implemented");
+  return [ av.ZERO, av.NONZERO ];
+}
+
 OutparamCheck.prototype.updateEdgeState = function(e) {
   e.state.keepOnly(e.dest.keepVars);
 }
 
 OutparamCheck.prototype.flowState = function(isn, state) {
   switch (TREE_CODE(isn)) {
   case GIMPLE_MODIFY_STMT:
     this.processAssign(isn, state);
     break;
   case CALL_EXPR:
     this.processCall(undefined, isn, isn, state);
     break;
   case SWITCH_EXPR:
   case COND_EXPR:
     // This gets handled by flowStateCond instead, has no exec effect
     break;
-  case RETURN_EXPR:
-    let op = isn.operands()[0];
-    if (op) this.processAssign(isn.operands()[0], state);
-    break;
-  case LABEL_EXPR:
-  case RESX_EXPR:
-  case ASM_EXPR:
-    // NOPs for us
-    break;
   default:
-    print(TREE_CODE(isn));
-    throw new Error("ni");
+    this.zeroNonzero.flowState(isn, state);
   }
 }
 
 OutparamCheck.prototype.flowStateCond = function(isn, truth, state) {
-  switch (TREE_CODE(isn)) {
-  case COND_EXPR:
-    this.flowStateIf(isn, truth, state);
-    break;
-  case SWITCH_EXPR:
-    this.flowStateSwitch(isn, truth, state);
-    break;
-  default:
-    throw new Error("ni " + TREE_CODE(isn));
-  }
+  this.zeroNonzero.flowStateCond(isn, truth, state);
 }
 
-OutparamCheck.prototype.flowStateIf = function(isn, truth, state) {
-  let exp = TREE_OPERAND(isn, 0);
-
-  if (DECL_P(exp)) {
-    this.filter(state, exp, av.NONZERO, truth, isn);
-    return;
-  }
-
-  switch (TREE_CODE(exp)) {
-  case EQ_EXPR:
-  case NE_EXPR:
-    // Handle 'x op <int lit>' pattern only
-    let op1 = TREE_OPERAND(exp, 0);
-    let op2 = TREE_OPERAND(exp, 1);
-    if (expr_literal_int(op1) != undefined) {
-      [op1,op2] = [op2,op1];
-    }
-    if (!DECL_P(op1)) break;
-    if (expr_literal_int(op2) != 0) break;
-    let val = TREE_CODE(exp) == EQ_EXPR ? av.ZERO : av.NONZERO;
-
-    this.filter(state, op1, val, truth, isn);
-    break;
-  default:
-    // Don't care about anything else.
-  }
-
-};
-
-OutparamCheck.prototype.flowStateSwitch = function(isn, truth, state) {
-  let exp = TREE_OPERAND(isn, 0);
-
-  if (DECL_P(exp)) {
-    if (truth != null) {
-      this.filter(state, exp, makeIntAV(truth), true, isn);
-    }
-    return;
-  }
-  throw new Error("ni");
-}
-
-// Apply a filter to the state. We need to special case it for this analysis
-// because outparams only care about being a NULL pointer.
-OutparamCheck.prototype.filter = function(state, vbl, val, truth, blame) {
-  if (truth != true && truth != false) throw new Error("ni " + truth);
-  if (this.outparams.has(vbl)) {
-    // We do need to check for true and false here because other values
-    // could get passed in from switches.
-    if (truth == true && val == av.ZERO || truth == false && val == av.NONZERO) {
-      state.assignValue(vbl, av.NULL, blame);
-    }
-  } else {
-    if (truth == false) {
-      val = val.negation;
-    }
-    state.filter(vbl, val, blame);
-  }
-};
-
+// For any outparams-specific semantics, we handle it here and then
+// return. Otherwise we delegate to the zero-nonzero analysis.
 OutparamCheck.prototype.processAssign = function(isn, state) {
   let lhs = isn.operands()[0];
   let rhs = isn.operands()[1];
 
   if (DECL_P(lhs)) {
     // Unwrap NOP_EXPR, which is semantically a copy.
     if (TREE_CODE(rhs) == NOP_EXPR) {
       rhs = rhs.operands()[0];
     }
 
-    if (DECL_P(rhs)) {
-      if (this.outparams.has(rhs)) {
+    if (DECL_P(rhs) && this.outparams.has(rhs)) {
         // Copying an outparam pointer. We have to remember this so that
         // if it is assigned thru later, we pick up the write.
         state.assignValue(lhs, makeOutparamAV(rhs), isn);
-      } else {
-        state.assign(lhs, rhs, isn);
-      }
-      return
+        return;
     }
     
     switch (TREE_CODE(rhs)) {
     case INTEGER_CST:
       if (this.outparams.has(lhs)) {
         warning("assigning to outparam pointer");
-      } else {
-        // Need to know the exact int value for finally_tmp.
-        if (is_finally_tmp(lhs)) {
-          let v = TREE_INT_CST_LOW(rhs);
-          state.assignValue(lhs, makeIntAV(v), isn);
-        } else {
-          let value = expr_literal_int(rhs) == 0 ? av.ZERO : av.NONZERO;
-          state.assignValue(lhs, value, isn);
-        }
+        return;
       }
       break;
-    case NE_EXPR: {
-      // We only care about gcc-generated x != 0 for conversions and such.
-      let [op1, op2] = rhs.operands();
-      if (DECL_P(op1) && expr_literal_int(op2) == 0) {
-        state.assign(lhs, op1, isn);
-      }
-    }
-      break;
     case EQ_EXPR: {
       // We only care about testing outparams for NULL (and then not writing)
       let [op1, op2] = rhs.operands();
       if (DECL_P(op1) && this.outparams.has(op1) && expr_literal_int(op2) == 0) {
         state.update(function(ss) {
           let [s1, s2] = [ss, ss.copy()]; // s1 true, s2 false
           s1.assignValue(lhs, av.NONZERO, isn);
           s1.assignValue(op1, av.NULL, isn);
           s2.assignValue(lhs, av.ZERO, isn);
           return [s1, s2];
         });
+        return;
       }
     }
       break;
     case CALL_EXPR:
       let fname = call_function_name(rhs);
       if (fname == 'NS_FAILED') {
         this.processTest(lhs, rhs, av.NONZERO, isn, state);
       } else if (fname == 'NS_SUCCEEDED') {
         this.processTest(lhs, rhs, av.ZERO, isn, state);
       } else if (fname == '__builtin_expect') {
         // Same as an assign from arg 0 to lhs
         state.assign(lhs, call_args(rhs)[0], isn);
       } else {
         this.processCall(lhs, rhs, isn, state);
       }
-      break;
-    // Stuff we don't analyze -- just kill the LHS info
-    case ADDR_EXPR:
-    case POINTER_PLUS_EXPR:
-    case ARRAY_REF:
-    case COMPONENT_REF:
-    case INDIRECT_REF:
-    case FILTER_EXPR:
-    case EXC_PTR_EXPR:
-    case CONSTRUCTOR:
-
-    case REAL_CST:
-    case STRING_CST:
+      return;
+    }
 
-    case CONVERT_EXPR:
-    case TRUTH_NOT_EXPR:
-    case TRUTH_XOR_EXPR:
-    case BIT_FIELD_REF:
-      state.remove(lhs);
-      break;
-    default:
-      if (UNARY_CLASS_P(rhs) || BINARY_CLASS_P(rhs) || COMPARISON_CLASS_P(rhs)) {
-        state.remove(lhs);
-        break;
-      }
-      print(TREE_CODE(rhs));
-      throw new Error("ni");
-    }
+    // Nothing special -- delegate
+    this.zeroNonzero.processAssign(isn, state);
     return;
   }
 
   switch (TREE_CODE(lhs)) {
   case INDIRECT_REF:
-    // Writing to an outparam. We want to try to figure out if we're writing NULL.
+    // Writing to an outparam. We want to try to figure out if we're 
+    // writing NULL.
     let e = TREE_OPERAND(lhs, 0);
     if (this.outparams.has(e)) {
       if (expr_literal_int(rhs) == 0) {
         state.assignValue(e, av.WROTE_NULL, isn);
       } else if (DECL_P(rhs)) {
         state.update(function(ss) {
           let [s1, s2] = [ss.copy(), ss]; // s1 NULL, s2 non-NULL
           s1.assignValue(e, av.WROTE_NULL, isn);
@@ -504,19 +381,19 @@ OutparamCheck.prototype.processAssign = 
     throw new Error("ni");
   }
 }
 
 // Handle an assignment x := test(foo) where test is a simple predicate
 OutparamCheck.prototype.processTest = function(lhs, call, val, blame, state) {
   let arg = call_arg(call, 0);
   if (DECL_P(arg)) {
-    state.predicate(lhs, val, arg, blame);
+    this.zeroNonzero.predicate(state, lhs, val, arg, blame);
   } else {
-    state.assignValue(lhs, av.BOTTOM, blame);
+    state.assignValue(lhs, ESP.TOP, blame);
   }
 };
 
 // The big one: outparam semantics of function calls.
 OutparamCheck.prototype.processCall = function(dest, expr, blame, state) {
   let args = call_args(expr);
   let callable = callable_arg_function_decl(TREE_OPERAND(expr, 1));
   let psem = this.func_param_semantics(callable);
@@ -645,24 +522,23 @@ OutparamCheck.prototype.check = function
 }
 
 OutparamCheck.prototype.checkSubstate = function(isvoid, fndecl, ss) {
   if (isvoid) {
     this.checkSubstateSuccess(ss);
   } else {
     let [succ, fail] = ret_coding(fndecl);
     let rv = ss.get(this.retvar);
-    switch (rv) {
-    case succ:
+    // We want to check if the abstract value of the rv is entirely
+    // contained in the success or failure condition.
+    if (av.meet(rv, succ) == rv) {
       this.checkSubstateSuccess(ss);
-      break;
-    case fail:
+    } else if (av.meet(rv, fail) == rv) {
       this.checkSubstateFailure(ss);
-      break;
-    default:
+    } else {
       // This condition indicates a bug in outparams.js. We'll just
       // warn so we don't break static analysis builds.
       warning("Outparams checker cannot determine rv success/failure",
               location_of(fndecl));
       this.checkSubstateSuccess(ss);
       this.checkSubstateFailure(ss);
     }
   }
--- a/xpcom/glue/nsDebug.h
+++ b/xpcom/glue/nsDebug.h
@@ -69,17 +69,17 @@
  *      NS_ABORT_IF_FALSE(0 == foo++, "yikes foo should be zero");
  *
  * Note also that the non-debug version of this macro does <b>not</b>
  * evaluate the message argument.
  */
 #define NS_ABORT_IF_FALSE(_expr, _msg)                        \
   PR_BEGIN_MACRO                                              \
     if (!(_expr)) {                                           \
-      NS_DebugBreak(NS_DEBUG_ASSERTION, _msg, #_expr, __FILE__, __LINE__); \
+      NS_DebugBreak(NS_DEBUG_ABORT, _msg, #_expr, __FILE__, __LINE__); \
     }                                                         \
   PR_END_MACRO
 
 /**
  * Warn if a given condition is false.
  *
  * Program execution continues past the usage of this macro.
  *