Merge inbound to m-c.
authorRyan VanderMeulen <ryanvm@gmail.com>
Fri, 23 Aug 2013 17:49:37 -0400
changeset 157045 17143a9a0d838ced69fa159d8b12c7ecfcc5d8c4
parent 157001 ce881259e2d0a10897c9ca1ecf116a1cba1a8e56 (current diff)
parent 157044 76a5ca209147c633797bfdb0c3ea3fc0e7ff7c9a (diff)
child 157046 01576441bdc683d3256696b618e5f02bcfe1de9a
child 157055 96741a4ad796c7323acf4fc48bc70f9c1ea85651
child 157079 d0fda982e6a5beacdbdb6f59dab6b01ed214c13a
child 157161 5f6957ab016cf28b31d6690a4ec1f36191c2fd78
push id2961
push userlsblakk@mozilla.com
push dateMon, 28 Oct 2013 21:59:28 +0000
treeherdermozilla-beta@73ef4f13486f [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone26.0a1
first release with
nightly linux32
17143a9a0d83 / 26.0a1 / 20130823151250 / files
nightly linux64
17143a9a0d83 / 26.0a1 / 20130823151250 / files
nightly mac
17143a9a0d83 / 26.0a1 / 20130823151250 / files
nightly win32
17143a9a0d83 / 26.0a1 / 20130823151250 / files
nightly win64
17143a9a0d83 / 26.0a1 / 20130823151250 / files
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
releases
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge inbound to m-c.
--- a/build/automation.py.in
+++ b/build/automation.py.in
@@ -213,17 +213,17 @@ class Automation(object):
                  close_fds=False,
                  shell=False,
                  cwd=None,
                  env=None,
                  universal_newlines=False,
                  startupinfo=None,
                  creationflags=0):
       args = automationutils.wrapCommand(args)
-      print "args: %s" % args
+      _log.info("INFO | automation.py | Launching: %s", subprocess.list2cmdline(args))
       subprocess.Popen.__init__(self, args, bufsize, executable,
                                 stdin, stdout, stderr,
                                 preexec_fn, close_fds,
                                 shell, cwd, env,
                                 universal_newlines, startupinfo, creationflags)
       self.log = _log
 
     def kill(self):
--- a/build/mobile/robocop/Actions.java.in
+++ b/build/mobile/robocop/Actions.java.in
@@ -44,16 +44,32 @@ public interface Actions {
     /**
      * Sends an event to Gecko.
      * 
      * @param geckoEvent The geckoEvent JSONObject's type
      */
     void sendGeckoEvent(String geckoEvent, String data);
 
     /**
+     * Sends a preferences get event to Gecko.
+     *
+     * @param requestId The id of this request.
+     * @param prefNames The preferences being requested.
+     */
+    void sendPreferencesGetEvent(int requestId, String[] prefNames);
+
+    /**
+     * Sends a preferences observe event to Gecko.
+     *
+     * @param requestId The id of this request.
+     * @param prefNames The preferences being requested.
+     */
+    void sendPreferencesObserveEvent(int requestId, String[] prefNames);
+
+    /**
      * Listens for a gecko event to be sent from the Gecko instance.
      * The returned object can be used to test if the event has been
      * received. Note that only one event is listened for.
      * 
      * @param geckoEvent The geckoEvent JSONObject's type
      */
     RepeatedEventExpecter expectGeckoEvent(String geckoEvent);
 
--- a/build/mobile/robocop/FennecMochitestAssert.java.in
+++ b/build/mobile/robocop/FennecMochitestAssert.java.in
@@ -66,21 +66,23 @@ public class FennecMochitestAssert imple
         dumpLog(Integer.toString(mLineNumber++) + " INFO TEST-START | " + mLogTestName);
     }
 
     class testInfo {
         public boolean mResult;
         public String mName;
         public String mDiag;
         public boolean mTodo;
-        public testInfo(boolean r, String n, String d, boolean t) {
+        public boolean mInfo;
+        public testInfo(boolean r, String n, String d, boolean t, boolean i) {
             mResult = r;
             mName = n;
             mDiag = d;
             mTodo = t;
+            mInfo = i;
         }
 
     }
 
     private void _logMochitestResult(testInfo test, String passString, String failString) {
         boolean isError = true;
         String resultString = failString;
         if (test.mResult || test.mTodo) {
@@ -91,17 +93,19 @@ public class FennecMochitestAssert imple
             resultString = passString;
         }
         String diag = test.mName;
         if (test.mDiag != null) diag += " - " + test.mDiag;
 
         String message = Integer.toString(mLineNumber++) + " INFO " + resultString + " | " + mLogTestName + " | " + diag;
         dumpLog(message);
 
-        if (test.mTodo) {
+        if (test.mInfo) {
+            // do not count TEST-INFO messages
+        } else if (test.mTodo) {
             mTodo++;
         } else if (isError) {
             mFailed++;
         } else {
             mPassed++;
         }
         if (isError) {
             junit.framework.Assert.fail(message);
@@ -127,17 +131,17 @@ public class FennecMochitestAssert imple
         dumpLog(message);
         message = Integer.toString(mLineNumber++) + " INFO Todo: " + Integer.toString(mTodo);
         dumpLog(message);
         message = Integer.toString(mLineNumber++) + " INFO SimpleTest FINISHED";
         dumpLog(message);
     }
 
     public void ok(boolean condition, String name, String diag) {
-        testInfo test = new testInfo(condition, name, diag, false);
+        testInfo test = new testInfo(condition, name, diag, false, false);
         _logMochitestResult(test, "TEST-PASS", "TEST-UNEXPECTED-FAIL");
         mTestList.add(test);
     }
 
     public void is(Object a, Object b, String name) {
         boolean pass = checkObjectsEqual(a,b);
         ok(pass, name, getEqualString(a,b, pass));
     }
@@ -184,17 +188,17 @@ public class FennecMochitestAssert imple
         if (pass) {
             return true;
         } else {
             return false;
         }
     }
 
     public void todo(boolean condition, String name, String diag) {
-        testInfo test = new testInfo(condition, name, diag, true);
+        testInfo test = new testInfo(condition, name, diag, true, false);
         _logMochitestResult(test, "TEST-UNEXPECTED-PASS", "TEST-KNOWN-FAIL");
         mTestList.add(test);
     }
 
     public void todo_is(Object a, Object b, String name) {
         boolean pass = checkObjectsEqual(a,b);
         todo(pass, name, getEqualString(a,b,pass));
     }
@@ -237,12 +241,12 @@ public class FennecMochitestAssert imple
     private String getNotEqualString(Object a, Object b, boolean pass) {
         if(pass) {
             return a + " should not equal " + b;
         }
         return "didn't expect " + a + ", but got it";
     }
 
     public void info(String name, String message) {
-        testInfo test = new testInfo(true, name, message, false);
+        testInfo test = new testInfo(true, name, message, false, true);
         _logMochitestResult(test, "TEST-INFO", "INFO FAILED?");
     }
 }
--- a/build/mobile/robocop/FennecNativeActions.java.in
+++ b/build/mobile/robocop/FennecNativeActions.java.in
@@ -39,16 +39,18 @@ public class FennecNativeActions impleme
     // Objects for reflexive access of fennec classes.
     private ClassLoader mClassLoader;
     private Class mApiClass;
     private Class mEventListenerClass;
     private Class mDrawListenerClass;
     private Method mRegisterEventListener;
     private Method mUnregisterEventListener;
     private Method mBroadcastEvent;
+    private Method mPreferencesGetEvent;
+    private Method mPreferencesObserveEvent;
     private Method mSetDrawListener;
     private Method mQuerySql;
     private Object mRobocopApi;
 
     private static final String LOGTAG = "FennecNativeActions";
 
     public FennecNativeActions(Activity activity, Solo robocop, Instrumentation instrumentation, Assert asserter) {
         mSolo = robocop;
@@ -61,16 +63,18 @@ public class FennecNativeActions impleme
 
             mApiClass = mClassLoader.loadClass("org.mozilla.gecko.RobocopAPI");
             mEventListenerClass = mClassLoader.loadClass("org.mozilla.gecko.util.GeckoEventListener");
             mDrawListenerClass = mClassLoader.loadClass("org.mozilla.gecko.gfx.GeckoLayerClient$DrawListener");
 
             mRegisterEventListener = mApiClass.getMethod("registerEventListener", String.class, mEventListenerClass);
             mUnregisterEventListener = mApiClass.getMethod("unregisterEventListener", String.class, mEventListenerClass);
             mBroadcastEvent = mApiClass.getMethod("broadcastEvent", String.class, String.class);
+            mPreferencesGetEvent = mApiClass.getMethod("preferencesGetEvent", Integer.TYPE, String[].class);
+            mPreferencesObserveEvent = mApiClass.getMethod("preferencesObserveEvent", Integer.TYPE, String[].class);
             mSetDrawListener = mApiClass.getMethod("setDrawListener", mDrawListenerClass);
             mQuerySql = mApiClass.getMethod("querySql", String.class, String.class);
 
             mRobocopApi = mApiClass.getConstructor(Activity.class).newInstance(activity);
         } catch (Exception e) {
             FennecNativeDriver.log(LogLevel.ERROR, e);
         }
     }
@@ -260,16 +264,34 @@ public class FennecNativeActions impleme
             mBroadcastEvent.invoke(mRobocopApi, geckoEvent, data);
         } catch (IllegalAccessException e) {
             FennecNativeDriver.log(LogLevel.ERROR, e);
         } catch (InvocationTargetException e) {
             FennecNativeDriver.log(LogLevel.ERROR, e);
         }
     }
 
+    private void sendPreferencesEvent(Method method, int requestId, String[] prefNames) {
+        try {
+            method.invoke(mRobocopApi, requestId, prefNames);
+        } catch (IllegalAccessException e) {
+            FennecNativeDriver.log(LogLevel.ERROR, e);
+        } catch (InvocationTargetException e) {
+            FennecNativeDriver.log(LogLevel.ERROR, e);
+        }
+    }
+
+    public void sendPreferencesGetEvent(int requestId, String[] prefNames) {
+        sendPreferencesEvent(mPreferencesGetEvent, requestId, prefNames);
+    }
+
+    public void sendPreferencesObserveEvent(int requestId, String[] prefNames) {
+        sendPreferencesEvent(mPreferencesObserveEvent, requestId, prefNames);
+    }
+
     class DrawListenerProxy implements InvocationHandler {
         private final PaintExpecter mPaintExpecter;
 
         DrawListenerProxy(PaintExpecter paintExpecter) {
             mPaintExpecter = paintExpecter;
         }
 
         public Object invoke(Object proxy, Method method, Object[] args) {
--- a/content/base/public/nsINodeList.h
+++ b/content/base/public/nsINodeList.h
@@ -3,19 +3,17 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef nsINodeList_h___
 #define nsINodeList_h___
 
 #include "nsIDOMNodeList.h"
 #include "nsWrapperCache.h"
-
-class nsINode;
-class nsIContent;
+#include "nsIContent.h"
 
 // IID for the nsINodeList interface
 #define NS_INODELIST_IID \
 { 0xadb5e54c, 0x6e96, 0x4102, \
  { 0x8d, 0x40, 0xe0, 0x12, 0x3d, 0xcf, 0x48, 0x7a } }
 
 /**
  * An internal interface for a reasonably fast indexOf.
--- a/content/base/src/nsDOMAttributeMap.h
+++ b/content/base/src/nsDOMAttributeMap.h
@@ -18,22 +18,16 @@
 #include "nsRefPtrHashtable.h"
 #include "nsStringGlue.h"
 #include "nsWrapperCache.h"
 
 class nsIAtom;
 class nsINodeInfo;
 class nsIDocument;
 
-namespace mozilla {
-namespace dom {
-class Element;
-} // namespace dom
-} // namespace mozilla
-
 /**
  * Structure used as a key for caching Attrs in nsDOMAttributeMap's mAttributeCache.
  */
 class nsAttrKey
 {
 public:
   /**
    * The namespace of the attribute
@@ -206,10 +200,14 @@ private:
   Attr* GetAttribute(nsINodeInfo* aNodeInfo, bool aNsAware);
 
   /**
    * Remove an attribute, returns the removed node.
    */
   already_AddRefed<Attr> RemoveAttribute(nsINodeInfo* aNodeInfo);
 };
 
+// XXX khuey yes this is crazy.  The bindings code needs to see this include,
+// but if we pull it in at the top of the file we get a circular include
+// problem.
+#include "mozilla/dom/Element.h"
 
 #endif /* nsDOMAttributeMap_h */
--- a/content/base/src/nsXMLHttpRequest.h
+++ b/content/base/src/nsXMLHttpRequest.h
@@ -9,16 +9,17 @@
 
 #include "mozilla/Attributes.h"
 #include "nsIXMLHttpRequest.h"
 #include "nsISupportsUtils.h"
 #include "nsString.h"
 #include "nsIURI.h"
 #include "nsIHttpChannel.h"
 #include "nsIDocument.h"
+#include "nsIContent.h"
 #include "nsIStreamListener.h"
 #include "nsWeakReference.h"
 #include "jsapi.h"
 #include "nsIChannelEventSink.h"
 #include "nsIAsyncVerifyRedirectCallback.h"
 #include "nsIInterfaceRequestor.h"
 #include "nsIHttpHeaderVisitor.h"
 #include "nsIProgressEventSink.h"
--- a/content/html/content/src/HTMLPropertiesCollection.h
+++ b/content/html/content/src/HTMLPropertiesCollection.h
@@ -14,18 +14,18 @@
 #include "nsCOMArray.h"
 #include "nsIMutationObserver.h"
 #include "nsStubMutationObserver.h"
 #include "nsBaseHashtable.h"
 #include "nsINodeList.h"
 #include "nsIHTMLCollection.h"
 #include "nsHashKeys.h"
 #include "nsRefPtrHashtable.h"
+#include "nsGenericHTMLElement.h"
 
-class nsGenericHTMLElement;
 class nsIDocument;
 class nsINode;
 
 namespace mozilla {
 namespace dom {
 
 class HTMLPropertiesCollection;
 class PropertyNodeList;
--- a/content/svg/content/src/SVGAnimatedRect.h
+++ b/content/svg/content/src/SVGAnimatedRect.h
@@ -6,18 +6,18 @@
 #ifndef mozilla_dom_SVGAnimatedRect_h
 #define mozilla_dom_SVGAnimatedRect_h
 
 #include "nsCycleCollectionParticipant.h"
 #include "mozilla/dom/SVGRectBinding.h"
 #include "mozilla/Attributes.h"
 #include "mozilla/ErrorResult.h"
 #include "nsWrapperCache.h"
+#include "nsSVGElement.h"
 
-class nsSVGElement;
 class nsSVGViewBox;
 
 namespace mozilla {
 namespace dom {
 
 class SVGAnimatedRect MOZ_FINAL : public nsWrapperCache
 {
 public:
--- a/content/svg/content/src/SVGPreserveAspectRatio.h
+++ b/content/svg/content/src/SVGPreserveAspectRatio.h
@@ -6,18 +6,17 @@
 #pragma once
 
 #include "mozilla/TypedEnum.h"
 
 #include "nsWrapperCache.h"
 #include "nsAutoPtr.h"
 #include "nsCycleCollectionParticipant.h"
 #include "mozilla/ErrorResult.h"
-
-class nsSVGElement;
+#include "nsSVGElement.h"
 
 namespace mozilla {
 // Alignment Types
 enum SVGAlign MOZ_ENUM_TYPE(uint8_t) {
   SVG_PRESERVEASPECTRATIO_UNKNOWN = 0,
   SVG_PRESERVEASPECTRATIO_NONE = 1,
   SVG_PRESERVEASPECTRATIO_XMINYMIN = 2,
   SVG_PRESERVEASPECTRATIO_XMIDYMIN = 3,
--- a/content/xul/content/src/nsXULElement.cpp
+++ b/content/xul/content/src/nsXULElement.cpp
@@ -544,19 +544,25 @@ nsXULElement::IsFocusable(int32_t *aTabI
    * If aTabIndex is null, then the tabindex is not computed, and
    * true is returned for non-disabled controls and false otherwise.
    */
 
   // elements are not focusable by default
   bool shouldFocus = false;
 
 #ifdef XP_MACOSX
-  // on Mac, mouse interactions only focus the element if it's a list
-  if (aWithMouse && IsNonList(mNodeInfo))
+  // on Mac, mouse interactions only focus the element if it's a list,
+  // or if it's a remote target, since the remote target must handle
+  // the focus.
+  if (aWithMouse &&
+      IsNonList(mNodeInfo) && 
+      !nsEventStateManager::IsRemoteTarget(this))
+  {
     return false;
+  }
 #endif
 
   nsCOMPtr<nsIDOMXULControlElement> xulControl = do_QueryObject(this);
   if (xulControl) {
     // a disabled element cannot be focused and is not part of the tab order
     bool disabled;
     xulControl->GetDisabled(&disabled);
     if (disabled) {
--- a/dom/base/BarProps.h
+++ b/dom/base/BarProps.h
@@ -11,20 +11,20 @@
 
 #ifndef mozilla_dom_BarProps_h
 #define mozilla_dom_BarProps_h
 
 #include "mozilla/Attributes.h"
 #include "nsCycleCollectionParticipant.h"
 #include "nsWrapperCache.h"
 #include "nsAutoPtr.h"
+#include "nsPIDOMWindow.h"
 
 class nsGlobalWindow;
 class nsIWebBrowserChrome;
-class nsPIDOMWindow;
 
 namespace mozilla {
 
 class ErrorResult;
 
 namespace dom {
 
 // Script "BarProp" object
--- a/dom/base/Crypto.h
+++ b/dom/base/Crypto.h
@@ -6,23 +6,23 @@
 
 #ifdef MOZ_DISABLE_CRYPTOLEGACY
 #include "nsIDOMCrypto.h"
 #else
 #include "nsIDOMCryptoLegacy.h"
 class nsIDOMCRMFObject;
 #endif
 
+#include "nsPIDOMWindow.h"
+
 #include "nsWrapperCache.h"
 #include "mozilla/dom/TypedArray.h"
 #define NS_DOMCRYPTO_CID \
   {0x929d9320, 0x251e, 0x11d4, { 0x8a, 0x7c, 0x00, 0x60, 0x08, 0xc8, 0x44, 0xc3} }
 
-class nsPIDOMWindow;
-
 namespace mozilla {
 
 class ErrorResult;
 
 namespace dom {
 
 class Crypto : public nsIDOMCrypto,
                public nsWrapperCache
--- a/dom/base/DOMError.h
+++ b/dom/base/DOMError.h
@@ -6,18 +6,17 @@
 
 #ifndef mozilla_dom_domerror_h__
 #define mozilla_dom_domerror_h__
 
 #include "mozilla/Attributes.h"
 #include "nsWrapperCache.h"
 #include "nsCOMPtr.h"
 #include "nsString.h"
-
-class nsPIDOMWindow;
+#include "nsPIDOMWindow.h"
 
 namespace mozilla {
 
 class ErrorResult;
 
 namespace dom {
 
 class GlobalObject;
--- a/dom/base/nsDOMScriptObjectFactory.cpp
+++ b/dom/base/nsDOMScriptObjectFactory.cpp
@@ -97,19 +97,16 @@ nsDOMScriptObjectFactory::Observe(nsISup
 #ifdef MOZ_XUL
     // Flush the XUL cache since it holds JS roots, and we're about to
     // start the final GC.
     nsXULPrototypeCache* cache = nsXULPrototypeCache::GetInstance();
 
     if (cache)
       cache->Flush();
 #endif
-
-    nsGlobalWindow::ShutDown();
-    nsDOMClassInfo::ShutDown();
   }
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsDOMScriptObjectFactory::RegisterDOMClassInfo(const char *aName,
 					       nsDOMClassInfoExternalConstructorFnc aConstructorFptr,
--- a/dom/base/nsMimeTypeArray.h
+++ b/dom/base/nsMimeTypeArray.h
@@ -7,18 +7,18 @@
 #ifndef nsMimeTypeArray_h___
 #define nsMimeTypeArray_h___
 
 #include "nsString.h"
 #include "nsTArray.h"
 #include "nsWrapperCache.h"
 #include "nsIWeakReferenceUtils.h"
 #include "nsAutoPtr.h"
+#include "nsPIDOMWindow.h"
 
-class nsPIDOMWindow;
 class nsMimeType;
 class nsPluginElement;
 
 class nsMimeTypeArray MOZ_FINAL : public nsISupports,
                                   public nsWrapperCache
 {
 public:
   nsMimeTypeArray(nsWeakPtr aWindow);
--- a/dom/base/nsPerformance.h
+++ b/dom/base/nsPerformance.h
@@ -6,19 +6,19 @@
 #define nsPerformance_h___
 
 #include "nsCOMPtr.h"
 #include "nsAutoPtr.h"
 #include "mozilla/Attributes.h"
 #include "nsWrapperCache.h"
 #include "nsDOMNavigationTiming.h"
 #include "nsContentUtils.h"
+#include "nsIDOMWindow.h"
 
 class nsITimedChannel;
-class nsIDOMWindow;
 class nsPerformance;
 class JSObject;
 struct JSContext;
 
 // Script "performance.timing" object
 class nsPerformanceTiming MOZ_FINAL : public nsWrapperCache
 {
 public:
--- a/dom/bindings/Codegen.py
+++ b/dom/bindings/Codegen.py
@@ -6092,19 +6092,21 @@ class CGUnionStruct(CGThing):
         methods = []
         enumValues = ["eUninitialized"]
         toJSValCases = [CGCase("eUninitialized", CGGeneric("return false;"))]
         destructorCases = [CGCase("eUninitialized", None)]
         unionValues = []
         if self.type.hasNullableType:
             enumValues.append("eNull")
             methods.append(ClassMethod("IsNull", "bool", [], const=True, inline=True,
-                                       body="return mType == eNull;"))
+                                       body="return mType == eNull;",
+                                       bodyInHeader=True))
             methods.append(ClassMethod("SetNull", "void", [], inline=True,
-                                       body="mType = eNull;"))
+                                       body="mType = eNull;",
+                                       bodyInHeader=True))
             destructorCases.append(CGCase("eNull", None))
             toJSValCases.append(CGCase("eNull", CGGeneric("rval.setNull();\n"
                                                           "return true;")))
 
         for t in self.type.flatMemberTypes:
             vars = getUnionTypeTemplateVars(self.type,
                                             t, self.descriptorProvider,
                                             isReturnValue=self.isReturnValue)
@@ -8613,16 +8615,36 @@ class CGBindingRoot(CGThing):
                                             workers=False)
         workerCallbacks = config.getCallbacks(webIDLFile=webIDLFile,
                                               workers=True)
         callbackDescriptors = config.getDescriptors(webIDLFile=webIDLFile,
                                                     isCallback=True)
         jsImplemented = config.getDescriptors(webIDLFile=webIDLFile,
                                               isJSImplemented=True)
 
+        # Python can't modify closed-over variables directly, so sneak
+        # our mutable value in as an entry in a dictionary.
+        needsDOMQS = { "value": any(d.hasXPConnectImpls for d in descriptors) }
+        # Only mainthread things can have hasXPConnectImpls
+        provider = config.getDescriptorProvider(False)
+        def checkForXPConnectImpls(type, descriptor=None, dictionary=None):
+            if needsDOMQS["value"]:
+                return
+            type = type.unroll()
+            if not type.isInterface() or not type.isGeckoInterface():
+                return
+            try:
+                typeDesc = provider.getDescriptor(type.inner.identifier.name)
+            except NoSuchDescriptorError:
+                return
+            needsDOMQS["value"] = typeDesc.hasXPConnectImpls
+
+        callForEachType(descriptors + callbackDescriptors, dictionaries,
+                        mainCallbacks, checkForXPConnectImpls)
+
         descriptorsWithPrototype = filter(lambda d: d.interface.hasInterfacePrototypeObject(),
                                           descriptors)
         traitsClasses = [CGPrototypeTraitsClass(d) for d in descriptorsWithPrototype]
 
         # We must have a 1:1 mapping here, skip for prototypes which
         # share an implementation with other prototypes.
         traitsClasses.extend([CGPrototypeIDMapClass(d) for d in descriptorsWithPrototype
                               if d.unsharedImplementation])
@@ -8698,27 +8720,26 @@ class CGBindingRoot(CGThing):
                          ['mozilla/dom/BindingDeclarations.h',
                           'mozilla/ErrorResult.h',
                           'mozilla/dom/DOMJSClass.h',
                           'mozilla/dom/DOMJSProxyHandler.h'],
                          ['mozilla/dom/BindingUtils.h',
                           'mozilla/dom/Nullable.h',
                           'PrimitiveConversions.h',
                           'WrapperFactory.h',
-                          # Have to include nsDOMQS.h to get fast arg unwrapping
-                          # for old-binding things with castability.
-                          'nsDOMQS.h'
                           ] + (['WorkerPrivate.h',
                                 'nsThreadUtils.h'] if hasWorkerStuff else [])
                             + (['mozilla/Preferences.h'] if requiresPreferences else [])
                             + (['mozilla/dom/NonRefcountedDOMObject.h'] if hasOwnedDescriptors else [])
                             + (['nsContentUtils.h'] if requiresContentUtils else [])
                             + (['nsCxPusher.h'] if dictionaries else [])
                             + (['AccessCheck.h'] if hasChromeOnly else [])
                             + (['xpcprivate.h'] if isEventTarget else [])
+                            + (['nsPIDOMWindow.h'] if len(jsImplemented) != 0 else [])
+                            + (['nsDOMQS.h'] if needsDOMQS["value"] else [])
                             + (['AtomList.h'] if requiresAtoms else []),
                          prefix,
                          curr,
                          config,
                          jsImplemented)
 
         # Add include guards.
         curr = CGIncludeGuard(prefix, curr)
--- a/dom/camera/DOMCameraManager.h
+++ b/dom/camera/DOMCameraManager.h
@@ -15,18 +15,17 @@
 #include "nsThreadUtils.h"
 #include "nsHashKeys.h"
 #include "nsWrapperCache.h"
 #include "nsWeakReference.h"
 #include "nsClassHashtable.h"
 #include "nsIDOMCameraManager.h"
 #include "nsCycleCollectionParticipant.h"
 #include "mozilla/Attributes.h"
-
-class nsPIDOMWindow;
+#include "nsPIDOMWindow.h"
 
 namespace mozilla {
   class ErrorResult;
 class nsDOMCameraControl;
 namespace dom {
 class CameraSelector;
 }
 }
--- a/dom/encoding/TextEncoder.cpp
+++ b/dom/encoding/TextEncoder.cpp
@@ -83,17 +83,18 @@ TextEncoder::Encode(JSContext* aCx,
     if (NS_SUCCEEDED(rv)) {
       dstLen += finishLen;
     }
   }
 
   JSObject* outView = nullptr;
   if (NS_SUCCEEDED(rv)) {
     buf[dstLen] = '\0';
-    outView = CreateUint8Array(aCx, aObj, buf, dstLen);
+    outView = Uint8Array::Create(aCx, aObj, dstLen,
+                                 reinterpret_cast<uint8_t*>(buf.get()));
     if (!outView) {
       aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
       return nullptr;
     }
   }
 
   if (NS_FAILED(rv)) {
     aRv.Throw(rv);
--- a/dom/encoding/TextEncoder.h
+++ b/dom/encoding/TextEncoder.h
@@ -95,25 +95,16 @@ public:
    * @return JSObject* The Uint8Array wrapped in a JS object.
    */
   JSObject* Encode(JSContext* aCx,
                    JS::Handle<JSObject*> aObj,
                    const nsAString& aString,
                    const bool aStream,
                    ErrorResult& aRv);
 
-protected:
-  JSObject*
-  CreateUint8Array(JSContext* aCx, JS::Handle<JSObject*> aObj, 
-                   char* aBuf, uint32_t aLen) const
-  {
-    return Uint8Array::Create(aCx, aObj, aLen,
-                              reinterpret_cast<uint8_t*>(aBuf));
-  }
-
 private:
   nsCString mEncoding;
   nsCOMPtr<nsIUnicodeEncoder> mEncoder;
 };
 
 } // dom
 } // mozilla
 
--- a/dom/media/PeerConnection.js
+++ b/dom/media/PeerConnection.js
@@ -129,17 +129,17 @@ RTCIceCandidate.prototype = {
   QueryInterface: XPCOMUtils.generateQI([Ci.nsISupports,
                                          Ci.nsIDOMGlobalPropertyInitializer]),
 
   init: function(win) { this._win = win; },
 
   __init: function(dict) {
     this.candidate = dict.candidate;
     this.sdpMid = dict.sdpMid;
-    this.sdpMLineIndex = ("sdpMLineIndex" in dict)? dict.sdpMLineIndex+1 : null;
+    this.sdpMLineIndex = ("sdpMLineIndex" in dict)? dict.sdpMLineIndex : null;
   }
 };
 
 function RTCSessionDescription() {
   this.type = this.sdp = null;
 }
 RTCSessionDescription.prototype = {
   classDescription: "mozRTCSessionDescription",
@@ -686,17 +686,18 @@ RTCPeerConnection.prototype = {
     if (!cand.candidate && !cand.sdpMLineIndex) {
       throw new Components.Exception("Invalid candidate passed to addIceCandidate!");
     }
     this._onAddIceCandidateSuccess = onSuccess || null;
     this._onAddIceCandidateError = onError || null;
 
     this._queueOrRun({
       func: this._getPC().addIceCandidate,
-      args: [cand.candidate, cand.sdpMid || "", cand.sdpMLineIndex],
+      args: [cand.candidate, cand.sdpMid || "",
+             (cand.sdpMLineIndex === null)? 0 : cand.sdpMLineIndex + 1],
       wait: true
     });
   },
 
   addStream: function(stream, constraints) {
     if (stream.currentTime === undefined) {
       throw new Components.Exception("Invalid stream passed to addStream!");
     }
--- a/dom/promise/Promise.h
+++ b/dom/promise/Promise.h
@@ -9,19 +9,19 @@
 
 #include "mozilla/Attributes.h"
 #include "mozilla/ErrorResult.h"
 #include "mozilla/dom/BindingDeclarations.h"
 #include "nsCycleCollectionParticipant.h"
 #include "mozilla/dom/PromiseBinding.h"
 #include "nsWrapperCache.h"
 #include "nsAutoPtr.h"
+#include "nsPIDOMWindow.h"
 
 struct JSContext;
-class nsPIDOMWindow;
 
 namespace mozilla {
 namespace dom {
 
 class PromiseInit;
 class PromiseCallback;
 class AnyCallback;
 class PromiseResolver;
--- a/dom/src/geolocation/nsGeolocation.h
+++ b/dom/src/geolocation/nsGeolocation.h
@@ -26,22 +26,22 @@
 #include "nsIDOMGeoPositionCallback.h"
 #include "nsIDOMGeoPositionErrorCallback.h"
 #include "mozilla/dom/GeolocationBinding.h"
 #include "mozilla/dom/PositionErrorBinding.h"
 #include "mozilla/dom/CallbackObject.h"
 
 #include "nsIGeolocationProvider.h"
 #include "nsIContentPermissionPrompt.h"
+#include "nsIDOMWindow.h"
 #include "DictionaryHelpers.h"
 #include "PCOMContentPermissionRequestChild.h"
 #include "mozilla/Attributes.h"
 
 class nsGeolocationService;
-class nsIDOMWindow;
 
 namespace mozilla {
 namespace dom {
 class Geolocation;
 typedef CallbackObjectHolder<PositionCallback, nsIDOMGeoPositionCallback> GeoPositionCallback;
 typedef CallbackObjectHolder<PositionErrorCallback, nsIDOMGeoPositionErrorCallback> GeoPositionErrorCallback;
 }
 }
--- a/gfx/thebes/gfx3DMatrix.h
+++ b/gfx/thebes/gfx3DMatrix.h
@@ -4,19 +4,20 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef GFX_3DMATRIX_H
 #define GFX_3DMATRIX_H
 
 #include <gfxTypes.h>
 #include <gfxPoint3D.h>
 #include <gfxPointH3D.h>
-#include <gfxMatrix.h>
 #include <gfxQuad.h>
 
+class gfxMatrix;
+
 /**
  * This class represents a 3D transformation. The matrix is laid
  * out as follows:
  *
  * _11 _12 _13 _14
  * _21 _22 _23 _24
  * _31 _32 _33 _34
  * _41 _42 _43 _44
--- a/gfx/thebes/gfxQuad.h
+++ b/gfx/thebes/gfxQuad.h
@@ -2,16 +2,17 @@
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef GFX_QUAD_H
 #define GFX_QUAD_H
 
 #include "gfxTypes.h"
+#include "gfxRect.h"
 #include "gfxLineSegment.h"
 #include <algorithm>
 
 struct gfxQuad {
     gfxQuad(const gfxPoint& aOne, const gfxPoint& aTwo, const gfxPoint& aThree, const gfxPoint& aFour)
     {
         mPoints[0] = aOne;
         mPoints[1] = aTwo;
--- a/js/jsd/jsd_val.cpp
+++ b/js/jsd/jsd_val.cpp
@@ -234,18 +234,18 @@ jsd_GetValueFunctionId(JSDContext* jsdc,
 /*
  * Create a new JSD value referring to a jsval. Copy string values into the
  * JSD compartment. Leave all other GCTHINGs in their native compartments
  * and access them through cross-compartment calls.
  */
 JSDValue*
 jsd_NewValue(JSDContext* jsdc, jsval value)
 {
+    JS::RootedValue val(jsdc->jsrt, value);
     AutoSafeJSContext cx;
-    JS::RootedValue val(cx, value);
     JSDValue* jsdval;
 
     if(!(jsdval = (JSDValue*) calloc(1, sizeof(JSDValue))))
         return NULL;
 
     if(JSVAL_IS_GCTHING(val))
     {
         bool ok;
@@ -304,36 +304,37 @@ jsd_GetValueWrappedJSVal(JSDContext* jsd
         }
         else
             val = OBJECT_TO_JSVAL(obj);
     }
     
     return val;
 }
 
-static JSDProperty* _newProperty(JSDContext* jsdc, JSPropertyDesc* pd,
-                                 unsigned additionalFlags)
+static JSDProperty* _newProperty(JSDContext* jsdc, JS::HandleValue propId,
+                                 JS::HandleValue propValue, JS::HandleValue propAlias,
+                                 uint8_t propFlags, unsigned additionalFlags)
 {
     JSDProperty* jsdprop;
 
     if(!(jsdprop = (JSDProperty*) calloc(1, sizeof(JSDProperty))))
         return NULL;
 
     JS_INIT_CLIST(&jsdprop->links);
     jsdprop->nref = 1;
-    jsdprop->flags = pd->flags | additionalFlags;
+    jsdprop->flags = propFlags | additionalFlags;
 
-    if(!(jsdprop->name = jsd_NewValue(jsdc, pd->id)))
+    if(!(jsdprop->name = jsd_NewValue(jsdc, propId)))
         goto new_prop_fail;
 
-    if(!(jsdprop->val = jsd_NewValue(jsdc, pd->value)))
+    if(!(jsdprop->val = jsd_NewValue(jsdc, propValue)))
         goto new_prop_fail;
 
     if((jsdprop->flags & JSDPD_ALIAS) &&
-       !(jsdprop->alias = jsd_NewValue(jsdc, pd->alias)))
+       !(jsdprop->alias = jsd_NewValue(jsdc, propAlias)))
         goto new_prop_fail;
 
     return jsdprop;
 new_prop_fail:
     jsd_DropProperty(jsdc, jsdprop);
     return NULL;
 }
 
@@ -369,19 +370,27 @@ static bool _buildProps(JSDContext* jsdc
 
     JSAutoCompartment ac(cx, obj);
 
     if(!JS_GetPropertyDescArray(cx, obj, &pda))
     {
         return false;
     }
 
+    JS::RootedValue propId(cx);
+    JS::RootedValue propValue(cx);
+    JS::RootedValue propAlias(cx);
+    uint8_t propFlags;
     for(i = 0; i < pda.length; i++)
     {
-        JSDProperty* prop = _newProperty(jsdc, &pda.array[i], 0);
+        propId = pda.array[i].id;
+        propValue = pda.array[i].value;
+        propAlias = pda.array[i].alias;
+        propFlags = pda.array[i].flags;
+        JSDProperty* prop = _newProperty(jsdc, propId, propValue, propAlias, propFlags, 0);
         if(!prop)
         {
             _freeProps(jsdc, jsdval);
             break;
         }
         JS_APPEND_LINK(&prop->links, &jsdval->props);
     }
     JS_PutPropertyDescArray(cx, &pda);
@@ -457,29 +466,32 @@ jsd_IterateProperties(JSDContext* jsdc, 
     JS_ASSERT(jsdprop);
     jsdprop->nref++;
     return jsdprop;
 }
 
 JSDProperty*
 jsd_GetValueProperty(JSDContext* jsdc, JSDValue* jsdval, JSString* nameStr)
 {
+    JS::RootedString name(jsdc->jsrt, nameStr);
     AutoSafeJSContext cx;
     JSAutoCompartment acBase(cx, jsdc->glob);
     JSDProperty* jsdprop;
     JSDProperty* iter = NULL;
     JS::RootedObject obj(cx);
-    JS::RootedString name(cx, nameStr);
     unsigned  attrs = 0;
     bool found;
-    JSPropertyDesc pd;
     const jschar * nameChars;
     size_t nameLen;
     JS::RootedValue val(cx), nameval(cx);
     JS::RootedId nameid(cx);
+    JS::RootedValue propId(cx);
+    JS::RootedValue propValue(cx);
+    JS::RootedValue propAlias(cx);
+    uint8_t propFlags;
 
     if(!jsd_IsValueObject(jsdc, jsdval))
         return NULL;
 
     /* If we already have the prop, then return it */
     while(NULL != (jsdprop = jsd_IterateProperties(jsdc, jsdval, &iter)))
     {
         JSString* propName = jsd_GetValueString(jsdc, jsdprop->name);
@@ -508,47 +520,46 @@ jsd_GetValueProperty(JSDContext* jsdc, J
         }
 
         JS_ClearPendingException(cx);
 
         if(!JS_GetUCProperty(cx, obj, nameChars, nameLen, &val))
         {
             if (JS_IsExceptionPending(cx))
             {
-                if (!JS_GetPendingException(cx, &pd.value))
+                if (!JS_GetPendingException(cx, propValue.address()))
                 {
                     return NULL;
                 }
-                pd.flags = JSPD_EXCEPTION;
+                propFlags = JSPD_EXCEPTION;
             }
             else
             {
-                pd.flags = JSPD_ERROR;
-                pd.value = JSVAL_VOID;
+                propFlags = JSPD_ERROR;
+                propValue = JSVAL_VOID;
             }
         }
         else
         {
-            pd.value = val;
+            propValue = val;
         }
     }
 
     nameval = STRING_TO_JSVAL(name);
     if (!JS_ValueToId(cx, nameval, nameid.address()) ||
-        !JS_IdToValue(cx, nameid, &pd.id)) {
+        !JS_IdToValue(cx, nameid, propId.address())) {
         return NULL;
     }
 
-    pd.spare = 0;
-    pd.alias = JSVAL_NULL;
-    pd.flags |= (attrs & JSPROP_ENUMERATE) ? JSPD_ENUMERATE : 0
+    propAlias = JSVAL_NULL;
+    propFlags |= (attrs & JSPROP_ENUMERATE) ? JSPD_ENUMERATE : 0
         | (attrs & JSPROP_READONLY)  ? JSPD_READONLY  : 0
         | (attrs & JSPROP_PERMANENT) ? JSPD_PERMANENT : 0;
 
-    return _newProperty(jsdc, &pd, JSDPD_HINTED);
+    return _newProperty(jsdc, propId, propValue, propAlias, propFlags, JSDPD_HINTED);
 }
 
 /*
  * Retrieve a JSFunction* from a JSDValue*. This differs from
  * JS_ValueToFunction by fully unwrapping the object first.
  */
 JSFunction*
 jsd_GetValueFunction(JSDContext* jsdc, JSDValue* jsdval)
@@ -650,18 +661,18 @@ jsd_GetValueConstructor(JSDContext* jsdc
 }
 
 const char*
 jsd_GetValueClassName(JSDContext* jsdc, JSDValue* jsdval)
 {
     jsval val = jsdval->val;
     if(!jsdval->className && !JSVAL_IS_PRIMITIVE(val))
     {
+        JS::RootedObject obj(jsdc->jsrt, JSVAL_TO_OBJECT(val));
         AutoSafeJSContext cx;
-        JS::RootedObject obj(cx, JSVAL_TO_OBJECT(val));
         JSAutoCompartment ac(cx, obj);
         jsdval->className = JS_GetDebugClassName(obj);
     }
     return jsdval->className;
 }
 
 JSDScript*
 jsd_GetScriptForValue(JSDContext* jsdc, JSDValue* jsdval)
--- a/js/jsd/jsd_xpc.cpp
+++ b/js/jsd/jsd_xpc.cpp
@@ -892,22 +892,23 @@ jsdProperty::GetValue(jsdIValue **_rval)
     *_rval = jsdValue::FromPtr (mCx, jsdv);
     return NS_OK;
 }
 
 /* Scripts */
 NS_IMPL_ISUPPORTS2(jsdScript, jsdIScript, jsdIEphemeral)
 
 static NS_IMETHODIMP
-AssignToJSString(JSDContext *aCx, nsACString *x, JSString *str)
+AssignToJSString(JSDContext *aCx, nsACString *x, JSString *str_)
 {
-    if (!str) {
+    if (!str_) {
         x->SetLength(0);
         return NS_OK;
     }
+    JS::RootedString str(JSD_GetJSRuntime(aCx), str_);
     AutoSafeJSContext cx;
     JSAutoCompartment ac(cx, JSD_GetDefaultGlobal(aCx)); // Just in case.
     size_t length = JS_GetStringEncodingLength(cx, str);
     if (length == size_t(-1))
         return NS_ERROR_FAILURE;
     x->SetLength(uint32_t(length));
     if (x->Length() != uint32_t(length))
         return NS_ERROR_OUT_OF_MEMORY;
@@ -1256,17 +1257,17 @@ jsdScript::GetParameterNames(uint32_t* c
     *count = nargs;
     *paramNames = ret;
     return NS_OK;
 }
 
 NS_IMETHODIMP
 jsdScript::GetFunctionObject(jsdIValue **_rval)
 {
-    JSFunction *fun = JSD_GetJSFunction(mCx, mScript);
+    JS::RootedFunction fun(JSD_GetJSRuntime(mCx), JSD_GetJSFunction(mCx, mScript));
     if (!fun)
         return NS_ERROR_NOT_AVAILABLE;
 
     AutoSafeJSContext jsContext;
     JS::RootedObject obj(jsContext, JS_GetFunctionObject(fun));
     if (!obj)
         return NS_ERROR_FAILURE;
 
@@ -2109,20 +2110,18 @@ jsdValue::GetIsPrimitive (bool *_rval)
     *_rval = JSD_IsValuePrimitive (mCx, mValue);
     return NS_OK;
 }
 
 NS_IMETHODIMP
 jsdValue::GetJsType (uint32_t *_rval)
 {
     ASSERT_VALID_EPHEMERAL;
-    jsval val;
-
-    val = JSD_GetValueWrappedJSVal (mCx, mValue);
-    
+    JS::RootedValue val(JSD_GetJSRuntime(mCx), JSD_GetValueWrappedJSVal (mCx, mValue));
+
     if (JSVAL_IS_NULL(val))
         *_rval = TYPE_NULL;
     else if (JSVAL_IS_BOOLEAN(val))
         *_rval = TYPE_BOOLEAN;
     else if (JSVAL_IS_DOUBLE(val))
         *_rval = TYPE_DOUBLE;
     else if (JSVAL_IS_INT(val))
         *_rval = TYPE_INT;
--- a/js/src/Makefile.in
+++ b/js/src/Makefile.in
@@ -332,18 +332,22 @@ check-jstests:
 
 ifneq ($(OS_ARCH),WINNT)
 ifndef HAVE_DTRACE
 #check:: check-jstests
 endif
 endif
 
 DIST_GARBAGE = config.cache config.log config.status* \
-   config/autoconf.mk \
-   $(JS_CONFIG_NAME) js-config.h js-confdefs.h
+   config/autoconf.mk config/emptyvars.mk \
+   $(JS_CONFIG_NAME) js-config.h js-confdefs.h \
+   backend.mk config/backend.mk devtools/backend.mk editline/backend.mk \
+   gdb/backend.mk jsapi-tests/backend.mk shell/backend.mk tests/backend.mk \
+   backend.RecursiveMakeBackend.built backend.RecursiveMakeBackend.built.pp \
+   devtools/rootAnalysis/Makefile
 
 distclean::
 	$(RM) $(DIST_GARBAGE)
 
 DEFINES		+= -DEXPORT_JS_API
 
 INCLUDES	+= -I$(srcdir)
 
@@ -660,8 +664,35 @@ CXXFLAGS += -DUSE_SYSTEM_MALLOC=1 -DENAB
 
 ifneq (,$(ENABLE_YARR_JIT))
 CXXFLAGS +=  -DENABLE_JIT=1
 endif
 
 #
 # END kludges for the Nitro assembler
 ###############################################
+
+###############################################
+# Generating source package tarballs
+# (only possible when tar is found)
+ifneq (,$(TAR))
+
+source-package:
+	SRCDIR=$(srcdir) \
+	DIST=$(DIST) \
+	MAKE=$(MAKE) \
+	MKDIR=$(MKDIR) \
+	TAR=$(TAR) \
+	MOZJS_MAJOR_VERSION=$(MOZJS_MAJOR_VERSION) \
+	MOZJS_MINOR_VERSION=$(MOZJS_MINOR_VERSION) \
+	MOZJS_PATCH_VERSION=$(MOZJS_PATCH_VERSION) \
+	MOZJS_ALPHA=$(MOZJS_ALPHA) \
+	$(srcdir)/make-source-package.sh
+
+clean::
+	DIST=$(DIST) \
+	MOZJS_MAJOR_VERSION=$(MOZJS_MAJOR_VERSION) \
+	MOZJS_MINOR_VERSION=$(MOZJS_MINOR_VERSION) \
+	MOZJS_PATCH_VERSION=$(MOZJS_PATCH_VERSION) \
+	MOZJS_ALPHA=$(MOZJS_ALPHA) \
+	$(srcdir)/make-source-package.sh clean
+
+endif
--- a/js/src/builtin/Object.cpp
+++ b/js/src/builtin/Object.cpp
@@ -82,18 +82,18 @@ obj_propertyIsEnumerable(JSContext *cx, 
     if (!JSObject::getGenericAttributes(cx, pobj, id, &attrs))
         return false;
 
     args.rval().setBoolean((attrs & JSPROP_ENUMERATE) != 0);
     return true;
 }
 
 #if JS_HAS_TOSOURCE
-static bool
-obj_toSource(JSContext *cx, unsigned argc, Value *vp)
+bool
+js::obj_toSource(JSContext *cx, unsigned argc, Value *vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
     JS_CHECK_RECURSION(cx, return false);
 
     RootedObject obj(cx, ToObject(cx, args.thisv()));
     if (!obj)
         return false;
 
--- a/js/src/builtin/Object.h
+++ b/js/src/builtin/Object.h
@@ -9,15 +9,19 @@
 
 #include "jsobj.h"
 
 namespace js {
 
 extern const JSFunctionSpec object_methods[];
 extern const JSFunctionSpec object_static_methods[];
 
-/* Object constructor native. Exposed only so the JIT can know its address. */
+// Object constructor native. Exposed only so the JIT can know its address.
 extern bool
 obj_construct(JSContext *cx, unsigned argc, js::Value *vp);
 
+// Object.prototype.toSource. Exposed so that Function.prototype.toSource can chain up.
+extern bool
+obj_toSource(JSContext *cx, unsigned argc, js::Value *vp);
+
 } /* namespace js */
 
 #endif /* builtin_Object_h */
--- a/js/src/configure.in
+++ b/js/src/configure.in
@@ -566,16 +566,24 @@ AC_SUBST(INTEL_CC)
 AC_SUBST(INTEL_CXX)
 
 dnl ========================================================
 dnl Checks for programs.
 dnl ========================================================
 AC_PROG_INSTALL
 AC_PROG_LN_S
 
+AC_MSG_CHECKING([for tar archiver])
+AC_CHECK_PROGS(TAR, gnutar gtar tar, "")
+if test -z "$TAR"; then
+    AC_MSG_WARN([no tar archiver found in \$PATH])
+fi
+AC_MSG_RESULT([$TAR])
+AC_SUBST(TAR)
+
 if test -z "$TINDERBOX_SKIP_PERL_VERSION_CHECK"; then
 AC_MSG_CHECKING([for minimum required perl version >= $PERL_VERSION])
 _perl_version=`PERL_VERSION=$PERL_VERSION $PERL -e 'print "$]"; if ($] >= $ENV{PERL_VERSION}) { exit(0); } else { exit(1); }' 2>&5`
 _perl_res=$?
 AC_MSG_RESULT([$_perl_version])
 
 if test "$_perl_res" != 0; then
     AC_MSG_ERROR([Perl $PERL_VERSION or higher is required.])
--- a/js/src/frontend/BytecodeCompiler.cpp
+++ b/js/src/frontend/BytecodeCompiler.cpp
@@ -446,19 +446,20 @@ frontend::CompileLazyFunction(JSContext 
     if (!bce.init())
         return false;
 
     return EmitFunctionScript(cx, &bce, pn->pn_body);
 }
 
 // Compile a JS function body, which might appear as the value of an event
 // handler attribute in an HTML <INPUT> tag, or in a Function() constructor.
-bool
-frontend::CompileFunctionBody(JSContext *cx, MutableHandleFunction fun, CompileOptions options,
-                              const AutoNameVector &formals, const jschar *chars, size_t length)
+static bool
+CompileFunctionBody(JSContext *cx, MutableHandleFunction fun, CompileOptions options,
+                    const AutoNameVector &formals, const jschar *chars, size_t length,
+                    GeneratorKind generatorKind)
 {
 #if JS_TRACE_LOGGING
         js::AutoTraceLog logger(js::TraceLogging::defaultLogger(),
                                 js::TraceLogging::PARSER_COMPILE_FUNCTION_START,
                                 js::TraceLogging::PARSER_COMPILE_FUNCTION_STOP,
                                 options);
 #endif
 
@@ -515,17 +516,17 @@ frontend::CompileFunctionBody(JSContext 
     Directives directives(options.strictOption);
 
     TokenStream::Position start(parser.keepAtoms);
     parser.tokenStream.tell(&start);
 
     ParseNode *fn;
     while (true) {
         Directives newDirectives = directives;
-        fn = parser.standaloneFunctionBody(fun, formals, NotGenerator, directives, &newDirectives);
+        fn = parser.standaloneFunctionBody(fun, formals, generatorKind, directives, &newDirectives);
         if (fn)
             break;
 
         if (parser.hadAbortedSyntaxParse()) {
             // Hit some unrecoverable ambiguity during an inner syntax parse.
             // Syntax parsing has now been disabled in the parser, so retry
             // the parse.
             parser.clearAbortedSyntaxParse();
@@ -580,8 +581,23 @@ frontend::CompileFunctionBody(JSContext 
     if (!SetSourceMap(cx, parser.tokenStream, ss))
         return false;
 
     if (!sct.complete())
         return false;
 
     return true;
 }
+
+bool
+frontend::CompileFunctionBody(JSContext *cx, MutableHandleFunction fun, CompileOptions options,
+                              const AutoNameVector &formals, const jschar *chars, size_t length)
+{
+    return CompileFunctionBody(cx, fun, options, formals, chars, length, NotGenerator);
+}
+
+bool
+frontend::CompileStarGeneratorBody(JSContext *cx, MutableHandleFunction fun,
+                                   CompileOptions options, const AutoNameVector &formals,
+                                   const jschar *chars, size_t length)
+{
+    return CompileFunctionBody(cx, fun, options, formals, chars, length, StarGenerator);
+}
--- a/js/src/frontend/BytecodeCompiler.h
+++ b/js/src/frontend/BytecodeCompiler.h
@@ -28,16 +28,19 @@ CompileScript(ExclusiveContext *cx, Lifo
               SourceCompressionToken *extraSct = NULL);
 
 bool
 CompileLazyFunction(JSContext *cx, LazyScript *lazy, const jschar *chars, size_t length);
 
 bool
 CompileFunctionBody(JSContext *cx, MutableHandleFunction fun, CompileOptions options,
                     const AutoNameVector &formals, const jschar *chars, size_t length);
+bool
+CompileStarGeneratorBody(JSContext *cx, MutableHandleFunction fun, CompileOptions options,
+                         const AutoNameVector &formals, const jschar *chars, size_t length);
 
 /*
  * This should be called while still on the main thread if compilation will
  * occur on a worker thread.
  */
 void
 MaybeCallSourceHandler(JSContext *cx, const CompileOptions &options,
                        const jschar *chars, size_t length);
--- a/js/src/frontend/Parser.cpp
+++ b/js/src/frontend/Parser.cpp
@@ -1239,17 +1239,17 @@ struct BindData
         this->op = op;
         this->binder = Parser<ParseHandler>::bindVarOrConst;
     }
 };
 
 template <typename ParseHandler>
 JSFunction *
 Parser<ParseHandler>::newFunction(GenericParseContext *pc, HandleAtom atom,
-                                  FunctionSyntaxKind kind)
+                                  FunctionSyntaxKind kind, JSObject *proto)
 {
     JS_ASSERT_IF(kind == Statement, atom != NULL);
 
     /*
      * Find the global compilation context in order to pre-set the newborn
      * function's parent slot to pc->sc->as<GlobalObject>()->scopeChain. If the
      * global context is a compile-and-go one, we leave the pre-set parent
      * intact; otherwise we clear parent and proto.
@@ -1262,18 +1262,18 @@ Parser<ParseHandler>::newFunction(Generi
         parent = pc->sc->asGlobalSharedContext()->scopeChain();
 
     RootedFunction fun(context);
     JSFunction::Flags flags = (kind == Expression)
                               ? JSFunction::INTERPRETED_LAMBDA
                               : (kind == Arrow)
                                 ? JSFunction::INTERPRETED_LAMBDA_ARROW
                                 : JSFunction::INTERPRETED;
-    fun = NewFunction(context, NullPtr(), NULL, 0, flags, parent, atom,
-                      JSFunction::FinalizeKind, MaybeSingletonObject);
+    fun = NewFunctionWithProto(context, NullPtr(), NULL, 0, flags, parent, atom, proto,
+                               JSFunction::FinalizeKind, MaybeSingletonObject);
     if (!fun)
         return NULL;
     if (options().selfHostingMode)
         fun->setIsSelfHostedBuiltin();
     return fun;
 }
 
 static bool
@@ -1994,17 +1994,27 @@ Parser<ParseHandler>::functionDef(Handle
 
     bool bodyProcessed;
     if (!checkFunctionDefinition(funName, &pn, kind, &bodyProcessed))
         return null();
 
     if (bodyProcessed)
         return pn;
 
-    RootedFunction fun(context, newFunction(pc, funName, kind));
+    RootedObject proto(context);
+    if (generatorKind == StarGenerator) {
+        // If we are off the main thread, the generator meta-objects have
+        // already been created by js::StartOffThreadParseScript, so cx will not
+        // be necessary.
+        JSContext *cx = context->maybeJSContext();
+        proto = context->global()->getOrCreateStarGeneratorFunctionPrototype(cx);
+        if (!proto)
+            return null();
+    }
+    RootedFunction fun(context, newFunction(pc, funName, kind, proto));
     if (!fun)
         return null();
 
     // Speculatively parse using the directives of the parent parsing context.
     // If a directive is encountered (e.g., "use strict") that changes how the
     // function should have been parsed, we backup and reparse with the new set
     // of directives.
     Directives directives(pc);
--- a/js/src/frontend/Parser.h
+++ b/js/src/frontend/Parser.h
@@ -402,17 +402,18 @@ class Parser : private AutoGCRooter, pub
     ModuleBox *newModuleBox(Module *module, ParseContext<ParseHandler> *pc);
     FunctionBox *newFunctionBox(Node fn, JSFunction *fun, ParseContext<ParseHandler> *pc,
                                 Directives directives, GeneratorKind generatorKind);
 
     /*
      * Create a new function object given parse context (pc) and a name (which
      * is optional if this is a function expression).
      */
-    JSFunction *newFunction(GenericParseContext *pc, HandleAtom atom, FunctionSyntaxKind kind);
+    JSFunction *newFunction(GenericParseContext *pc, HandleAtom atom, FunctionSyntaxKind kind,
+                            JSObject *proto = NULL);
 
     void trace(JSTracer *trc);
 
     bool hadAbortedSyntaxParse() {
         return abortedSyntaxParse;
     }
     void clearAbortedSyntaxParse() {
         abortedSyntaxParse = false;
--- a/js/src/gc/Zone.h
+++ b/js/src/gc/Zone.h
@@ -190,28 +190,25 @@ struct Zone : private JS::shadow::Zone,
     void setGCState(CompartmentGCState state) {
         JS_ASSERT(runtimeFromMainThread()->isHeapBusy());
         JS_ASSERT_IF(state != NoGC, canCollect());
         gcState = state;
     }
 
     void scheduleGC() {
         JS_ASSERT(!runtimeFromMainThread()->isHeapBusy());
-
-        // Ignore attempts to schedule GCs on zones which can't be collected.
-        if (canCollect())
-            gcScheduled = true;
+        gcScheduled = true;
     }
 
     void unscheduleGC() {
         gcScheduled = false;
     }
 
-    bool isGCScheduled() const {
-        return gcScheduled;
+    bool isGCScheduled() {
+        return gcScheduled && canCollect();
     }
 
     void setPreservingCode(bool preserving) {
         gcPreserveCode = preserving;
     }
 
     bool canCollect() {
         // Zones cannot be collected while in use by other threads.
--- a/js/src/jit/IonTypes.h
+++ b/js/src/jit/IonTypes.h
@@ -202,17 +202,20 @@ IsNullOrUndefined(MIRType type)
 }
 
 #ifdef DEBUG
 // Track the pipeline of opcodes which has produced a snapshot.
 #define TRACK_SNAPSHOTS 1
 
 // Make sure registers are not modified between an instruction and
 // its OsiPoint.
-#  ifdef JS_ION
+//
+// Skip this check in rooting analysis builds, which poison unrooted
+// pointers on the stack.
+#  if defined(JS_ION) && !defined(JSGC_ROOT_ANALYSIS)
 #    define CHECK_OSIPOINT_REGISTERS 1
 #  endif
 #endif
 
 } // namespace ion
 } // namespace js
 
 #endif /* jit_IonTypes_h */
--- a/js/src/jsapi.h
+++ b/js/src/jsapi.h
@@ -2899,17 +2899,17 @@ struct JSClass {
  * member initial value.  The "original ... value" verbiage is there because
  * in ECMA-262, global properties naming class objects are read/write and
  * deleteable, for the most part.
  *
  * Implementing this efficiently requires that global objects have classes
  * with the following flags. Failure to use JSCLASS_GLOBAL_FLAGS was
  * prevously allowed, but is now an ES5 violation and thus unsupported.
  */
-#define JSCLASS_GLOBAL_SLOT_COUNT      (JSProto_LIMIT * 3 + 25)
+#define JSCLASS_GLOBAL_SLOT_COUNT      (JSProto_LIMIT * 3 + 26)
 #define JSCLASS_GLOBAL_FLAGS_WITH_SLOTS(n)                                    \
     (JSCLASS_IS_GLOBAL | JSCLASS_HAS_RESERVED_SLOTS(JSCLASS_GLOBAL_SLOT_COUNT + (n)))
 #define JSCLASS_GLOBAL_FLAGS                                                  \
     JSCLASS_GLOBAL_FLAGS_WITH_SLOTS(0)
 #define JSCLASS_HAS_GLOBAL_FLAG_AND_SLOTS(clasp)                              \
   (((clasp)->flags & JSCLASS_IS_GLOBAL)                                       \
    && JSCLASS_RESERVED_SLOTS(clasp) >= JSCLASS_GLOBAL_SLOT_COUNT)
 
--- a/js/src/jsfun.cpp
+++ b/js/src/jsfun.cpp
@@ -22,16 +22,17 @@
 #include "jsobj.h"
 #include "jsproxy.h"
 #include "jsscript.h"
 #include "jsstr.h"
 #include "jstypes.h"
 #include "jswrapper.h"
 
 #include "builtin/Eval.h"
+#include "builtin/Object.h"
 #include "frontend/BytecodeCompiler.h"
 #include "frontend/TokenStream.h"
 #include "gc/Marking.h"
 #ifdef JS_ION
 #include "jit/Ion.h"
 #include "jit/IonFrameIterator.h"
 #endif
 #include "vm/Interpreter.h"
@@ -190,50 +191,61 @@ static JSObject *
 ResolveInterpretedFunctionPrototype(JSContext *cx, HandleObject obj)
 {
 #ifdef DEBUG
     JSFunction *fun = &obj->as<JSFunction>();
     JS_ASSERT(fun->isInterpreted());
     JS_ASSERT(!fun->isFunctionPrototype());
 #endif
 
-    /*
-     * Assert that fun is not a compiler-created function object, which
-     * must never leak to script or embedding code and then be mutated.
-     * Also assert that obj is not bound, per the ES5 15.3.4.5 ref above.
-     */
+    // Assert that fun is not a compiler-created function object, which
+    // must never leak to script or embedding code and then be mutated.
+    // Also assert that obj is not bound, per the ES5 15.3.4.5 ref above.
     JS_ASSERT(!IsInternalFunctionObject(obj));
     JS_ASSERT(!obj->isBoundFunction());
 
-    /*
-     * Make the prototype object an instance of Object with the same parent
-     * as the function object itself.
-     */
-    JSObject *objProto = obj->global().getOrCreateObjectPrototype(cx);
+    // Make the prototype object an instance of Object with the same parent as
+    // the function object itself, unless the function is an ES6 generator.  In
+    // that case, per the 15 July 2013 ES6 draft, section 15.19.3, its parent is
+    // the GeneratorObjectPrototype singleton.
+    bool isStarGenerator = obj->as<JSFunction>().isStarGenerator();
+    JSObject *objProto;
+    if (isStarGenerator)
+        objProto = obj->global().getOrCreateStarGeneratorObjectPrototype(cx);
+    else
+        objProto = obj->global().getOrCreateObjectPrototype(cx);
     if (!objProto)
         return NULL;
-    RootedObject proto(cx, NewObjectWithGivenProto(cx, &JSObject::class_, objProto, NULL, SingletonObject));
+    Class *clasp = &JSObject::class_;
+
+    RootedObject proto(cx, NewObjectWithGivenProto(cx, clasp, objProto, NULL, SingletonObject));
     if (!proto)
         return NULL;
 
-    /*
-     * Per ES5 15.3.5.2 a user-defined function's .prototype property is
-     * initially non-configurable, non-enumerable, and writable.  Per ES5 13.2
-     * the prototype's .constructor property is configurable, non-enumerable,
-     * and writable.
-     */
+    // Per ES5 15.3.5.2 a user-defined function's .prototype property is
+    // initially non-configurable, non-enumerable, and writable.
     RootedValue protoVal(cx, ObjectValue(*proto));
-    RootedValue objVal(cx, ObjectValue(*obj));
     if (!JSObject::defineProperty(cx, obj, cx->names().classPrototype,
                                   protoVal, JS_PropertyStub, JS_StrictPropertyStub,
-                                  JSPROP_PERMANENT) ||
-        !JSObject::defineProperty(cx, proto, cx->names().constructor,
-                                  objVal, JS_PropertyStub, JS_StrictPropertyStub, 0))
+                                  JSPROP_PERMANENT))
     {
-       return NULL;
+        return NULL;
+    }
+
+    // Per ES5 13.2 the prototype's .constructor property is configurable,
+    // non-enumerable, and writable.  However, per the 15 July 2013 ES6 draft,
+    // section 15.19.3, the .prototype of a generator function does not link
+    // back with a .constructor.
+    if (!isStarGenerator) {
+        RootedValue objVal(cx, ObjectValue(*obj));
+        if (!JSObject::defineProperty(cx, proto, cx->names().constructor,
+                                      objVal, JS_PropertyStub, JS_StrictPropertyStub, 0))
+        {
+            return NULL;
+        }
     }
 
     return proto;
 }
 
 bool
 js::fun_resolve(JSContext *cx, HandleObject obj, HandleId id, unsigned flags,
                 MutableHandleObject objp)
@@ -322,54 +334,71 @@ js::fun_resolve(JSContext *cx, HandleObj
     return true;
 }
 
 template<XDRMode mode>
 bool
 js::XDRInterpretedFunction(XDRState<mode> *xdr, HandleObject enclosingScope, HandleScript enclosingScript,
                            MutableHandleObject objp)
 {
+    enum FirstWordFlag {
+        HasAtom = 0x1,
+        IsStarGenerator = 0x2
+    };
+
     /* NB: Keep this in sync with CloneFunctionAndScript. */
     RootedAtom atom(xdr->cx());
-    uint32_t firstword;           /* flag telling whether fun->atom is non-null,
-                                   plus for fun->u.i.skipmin, fun->u.i.wrapper,
-                                   and 14 bits reserved for future use */
-    uint32_t flagsword;           /* word for argument count and fun->flags */
+    uint32_t firstword = 0;        /* bitmask of FirstWordFlag */
+    uint32_t flagsword = 0;        /* word for argument count and fun->flags */
 
     JSContext *cx = xdr->cx();
     RootedFunction fun(cx);
     RootedScript script(cx);
     if (mode == XDR_ENCODE) {
         fun = &objp->as<JSFunction>();
         if (!fun->isInterpreted()) {
             JSAutoByteString funNameBytes;
             if (const char *name = GetFunctionNameBytes(cx, fun, &funNameBytes)) {
                 JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_NOT_SCRIPTED_FUNCTION,
                                      name);
             }
             return false;
         }
-        firstword = !!fun->atom();
+        if (fun->atom())
+            firstword |= HasAtom;
+        if (fun->isStarGenerator())
+            firstword |= IsStarGenerator;
         script = fun->getOrCreateScript(cx);
         if (!script)
             return false;
         atom = fun->atom();
         flagsword = (fun->nargs << 16) | fun->flags;
+
+        if (!xdr->codeUint32(&firstword))
+            return false;
     } else {
-        fun = NewFunction(cx, NullPtr(), NULL, 0, JSFunction::INTERPRETED, NullPtr(), NullPtr(),
-                          JSFunction::FinalizeKind, TenuredObject);
+        if (!xdr->codeUint32(&firstword))
+            return false;
+
+        JSObject *proto = NULL;
+        if (firstword & IsStarGenerator) {
+            proto = cx->global()->getOrCreateStarGeneratorFunctionPrototype(cx);
+            if (!proto)
+                return false;
+        }
+        fun = NewFunctionWithProto(cx, NullPtr(), NULL, 0, JSFunction::INTERPRETED,
+                                   NullPtr(), NullPtr(), proto,
+                                   JSFunction::FinalizeKind, TenuredObject);
         if (!fun)
             return false;
         atom = NULL;
         script = NULL;
     }
 
-    if (!xdr->codeUint32(&firstword))
-        return false;
-    if ((firstword & 1U) && !XDRAtom(xdr, &atom))
+    if ((firstword & HasAtom) && !XDRAtom(xdr, &atom))
         return false;
     if (!xdr->codeUint32(&flagsword))
         return false;
 
     if (!XDRScript(xdr, enclosingScope, enclosingScript, fun, &script))
         return false;
 
     if (mode == XDR_DECODE) {
@@ -394,20 +423,25 @@ js::XDRInterpretedFunction(XDRState<XDR_
 
 template bool
 js::XDRInterpretedFunction(XDRState<XDR_DECODE> *, HandleObject, HandleScript, MutableHandleObject);
 
 JSObject *
 js::CloneFunctionAndScript(JSContext *cx, HandleObject enclosingScope, HandleFunction srcFun)
 {
     /* NB: Keep this in sync with XDRInterpretedFunction. */
-
-    RootedFunction clone(cx, NewFunction(cx, NullPtr(), NULL, 0,
-                                         JSFunction::INTERPRETED, NullPtr(), NullPtr(),
-                                         JSFunction::FinalizeKind, TenuredObject));
+    JSObject *cloneProto = NULL;
+    if (srcFun->isStarGenerator()) {
+        cloneProto = cx->global()->getOrCreateStarGeneratorFunctionPrototype(cx);
+        if (!cloneProto)
+            return NULL;
+    }
+    RootedFunction clone(cx, NewFunctionWithProto(cx, NullPtr(), NULL, 0, JSFunction::INTERPRETED,
+                                                  NullPtr(), NullPtr(), cloneProto,
+                                                  JSFunction::FinalizeKind, TenuredObject));
     if (!clone)
         return NULL;
 
     RootedScript srcScript(cx, srcFun->nonLazyScript());
     RootedScript clonedScript(cx, CloneScript(cx, enclosingScope, clone, srcScript));
     if (!clonedScript)
         return NULL;
 
@@ -600,17 +634,17 @@ js::FunctionToString(JSContext *cx, Hand
     }
     if (!bodyOnly) {
         // If we're not in pretty mode, put parentheses around lambda functions.
         if (fun->isInterpreted() && !lambdaParen && fun->isLambda() && !fun->isArrow()) {
             if (!out.append("("))
                 return NULL;
         }
         if (!fun->isArrow()) {
-            if (!out.append("function "))
+            if (!(fun->isStarGenerator() ? out.append("function* ") : out.append("function ")))
                 return NULL;
         }
         if (fun->atom()) {
             if (!out.append(fun->atom()))
                 return NULL;
         }
     }
     bool haveSource = fun->isInterpreted() && !fun->isSelfHostedBuiltin();
@@ -790,16 +824,19 @@ fun_toSource(JSContext *cx, unsigned arg
 {
     CallArgs args = CallArgsFromVp(argc, vp);
     JS_ASSERT(IsFunctionObject(args.calleev()));
 
     RootedObject obj(cx, ToObject(cx, args.thisv()));
     if (!obj)
         return false;
 
+    if (!obj->is<JSFunction>() && !obj->is<FunctionProxyObject>())
+        return obj_toSource(cx, argc, vp);
+
     RootedString str(cx, fun_toStringHelper(cx, obj, JS_DONT_PRETTY_PRINT));
     if (!str)
         return false;
 
     args.rval().setString(str);
     return true;
 }
 #endif
@@ -1322,34 +1359,37 @@ const JSFunctionSpec js::function_method
     JS_FN(js_toString_str,   fun_toString,   0,0),
     JS_FN(js_apply_str,      js_fun_apply,   2,0),
     JS_FN(js_call_str,       js_fun_call,    1,0),
     JS_FN("bind",            fun_bind,       1,0),
     JS_FN("isGenerator",     fun_isGenerator,0,0),
     JS_FS_END
 };
 
-bool
-js::Function(JSContext *cx, unsigned argc, Value *vp)
+static bool
+FunctionConstructor(JSContext *cx, unsigned argc, Value *vp, GeneratorKind generatorKind)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
     RootedString arg(cx);   // used multiple times below
 
     /* Block this call if security callbacks forbid it. */
     Rooted<GlobalObject*> global(cx, &args.callee().global());
     if (!GlobalObject::isRuntimeCodeGenEnabled(cx, global)) {
         JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_CSP_BLOCKED_FUNCTION);
         return false;
     }
 
     AutoKeepAtoms keepAtoms(cx->perThreadData);
     AutoNameVector formals(cx);
 
     bool hasRest = false;
 
+    bool isStarGenerator = generatorKind == StarGenerator;
+    JS_ASSERT(generatorKind != LegacyGenerator);
+
     const char *filename;
     unsigned lineno;
     JSPrincipals *originPrincipals;
     CurrentScriptFileLineOrigin(cx, &filename, &lineno, &originPrincipals);
     JSPrincipals *principals = PrincipalsForCompiledCode(args, cx);
 
     CompileOptions options(cx);
     options.setPrincipals(principals)
@@ -1432,38 +1472,39 @@ js::Function(JSContext *cx, unsigned arg
          * Initialize a tokenstream that reads from the given string.  No
          * StrictModeGetter is needed because this TokenStream won't report any
          * strict mode errors.  Any strict mode errors which might be reported
          * here (duplicate argument names, etc.) will be detected when we
          * compile the function body.
          */
         TokenStream ts(cx, options, collected_args.get(), args_length,
                        /* strictModeGetter = */ NULL);
+        bool yieldIsValidName = ts.versionNumber() < JSVERSION_1_7 && !isStarGenerator;
 
         /* The argument string may be empty or contain no tokens. */
         TokenKind tt = ts.getToken();
         if (tt != TOK_EOF) {
             for (;;) {
                 /*
                  * Check that it's a name.  This also implicitly guards against
                  * TOK_ERROR, which was already reported.
                  */
                 if (hasRest) {
                     ts.reportError(JSMSG_PARAMETER_AFTER_REST);
                     return false;
                 }
 
-                if (tt == TOK_YIELD && ts.versionNumber() < JSVERSION_1_7)
+                if (tt == TOK_YIELD && yieldIsValidName)
                     tt = TOK_NAME;
 
                 if (tt != TOK_NAME) {
                     if (tt == TOK_TRIPLEDOT) {
                         hasRest = true;
                         tt = ts.getToken();
-                        if (tt == TOK_YIELD && ts.versionNumber() < JSVERSION_1_7)
+                        if (tt == TOK_YIELD && yieldIsValidName)
                             tt = TOK_NAME;
                         if (tt != TOK_NAME) {
                             if (tt != TOK_ERROR)
                                 ts.reportError(JSMSG_NO_REST_NAME);
                             return false;
                         }
                     } else {
                         return OnBadFormal(cx, tt);
@@ -1514,58 +1555,92 @@ js::Function(JSContext *cx, unsigned arg
 
     /*
      * NB: (new Function) is not lexically closed by its caller, it's just an
      * anonymous function in the top-level scope that its constructor inhabits.
      * Thus 'var x = 42; f = new Function("return x"); print(f())' prints 42,
      * and so would a call to f from another top-level's script or function.
      */
     RootedAtom anonymousAtom(cx, cx->names().anonymous);
-    RootedFunction fun(cx, NewFunction(cx, NullPtr(), NULL, 0, JSFunction::INTERPRETED_LAMBDA,
-                                       global, anonymousAtom, JSFunction::FinalizeKind,
-                                       TenuredObject));
+    JSObject *proto = NULL;
+    if (isStarGenerator) {
+        proto = global->getOrCreateStarGeneratorFunctionPrototype(cx);
+        if (!proto)
+            return false;
+    }
+    RootedFunction fun(cx, NewFunctionWithProto(cx, NullPtr(), NULL, 0,
+                                                JSFunction::INTERPRETED_LAMBDA, global,
+                                                anonymousAtom, proto,
+                                                JSFunction::FinalizeKind, TenuredObject));
     if (!fun)
         return false;
 
     if (hasRest)
         fun->setHasRest();
 
-    bool ok = frontend::CompileFunctionBody(cx, &fun, options, formals, chars, length);
+    bool ok;
+    if (isStarGenerator)
+        ok = frontend::CompileStarGeneratorBody(cx, &fun, options, formals, chars, length);
+    else
+        ok = frontend::CompileFunctionBody(cx, &fun, options, formals, chars, length);
     args.rval().setObject(*fun);
     return ok;
 }
 
 bool
+js::Function(JSContext *cx, unsigned argc, Value *vp)
+{
+    return FunctionConstructor(cx, argc, vp, NotGenerator);
+}
+
+bool
+js::Generator(JSContext *cx, unsigned argc, Value *vp)
+{
+    return FunctionConstructor(cx, argc, vp, StarGenerator);
+}
+
+bool
 JSFunction::isBuiltinFunctionConstructor()
 {
-    return maybeNative() == Function;
+    return maybeNative() == Function || maybeNative() == Generator;
 }
 
 JSFunction *
 js::NewFunction(ExclusiveContext *cx, HandleObject funobjArg, Native native, unsigned nargs,
                 JSFunction::Flags flags, HandleObject parent, HandleAtom atom,
                 gc::AllocKind allocKind /* = JSFunction::FinalizeKind */,
                 NewObjectKind newKind /* = GenericObject */)
 {
+    return NewFunctionWithProto(cx, funobjArg, native, nargs, flags, parent, atom, NULL,
+                                allocKind, newKind);
+}
+
+JSFunction *
+js::NewFunctionWithProto(ExclusiveContext *cx, HandleObject funobjArg, Native native,
+                         unsigned nargs, JSFunction::Flags flags, HandleObject parent,
+                         HandleAtom atom, JSObject *proto,
+                         gc::AllocKind allocKind /* = JSFunction::FinalizeKind */,
+                         NewObjectKind newKind /* = GenericObject */)
+{
     JS_ASSERT(allocKind == JSFunction::FinalizeKind || allocKind == JSFunction::ExtendedFinalizeKind);
     JS_ASSERT(sizeof(JSFunction) <= gc::Arena::thingSize(JSFunction::FinalizeKind));
     JS_ASSERT(sizeof(FunctionExtended) <= gc::Arena::thingSize(JSFunction::ExtendedFinalizeKind));
 
     RootedObject funobj(cx, funobjArg);
     if (funobj) {
         JS_ASSERT(funobj->is<JSFunction>());
         JS_ASSERT(funobj->getParent() == parent);
         JS_ASSERT_IF(native && cx->typeInferenceEnabled(), funobj->hasSingletonType());
     } else {
         // Don't give asm.js module functions a singleton type since they
         // are cloned (via CloneFunctionObjectIfNotSingleton) which assumes
         // that hasSingletonType implies isInterpreted.
         if (native && !IsAsmJSModuleNative(native))
             newKind = SingletonObject;
-        funobj = NewObjectWithClassProto(cx, &JSFunction::class_, NULL,
+        funobj = NewObjectWithClassProto(cx, &JSFunction::class_, proto,
                                          SkipScopeParent(parent), allocKind, newKind);
         if (!funobj)
             return NULL;
     }
     RootedFunction fun(cx, &funobj->as<JSFunction>());
 
     /* Initialize all function members. */
     fun->nargs = uint16_t(nargs);
@@ -1598,17 +1673,23 @@ js::CloneFunctionObject(JSContext *cx, H
     bool useSameScript = cx->compartment() == fun->compartment() &&
                          !fun->hasSingletonType() &&
                          !types::UseNewTypeForClone(fun);
 
     if (!useSameScript && fun->isInterpretedLazy() && !fun->getOrCreateScript(cx))
         return NULL;
 
     NewObjectKind newKind = useSameScript ? newKindArg : SingletonObject;
-    JSObject *cloneobj = NewObjectWithClassProto(cx, &JSFunction::class_, NULL,
+    JSObject *cloneProto = NULL;
+    if (fun->isStarGenerator()) {
+        cloneProto = cx->global()->getOrCreateStarGeneratorFunctionPrototype(cx);
+        if (!cloneProto)
+            return NULL;
+    }
+    JSObject *cloneobj = NewObjectWithClassProto(cx, &JSFunction::class_, cloneProto,
                                                  SkipScopeParent(parent), allocKind, newKind);
     if (!cloneobj)
         return NULL;
     RootedFunction clone(cx, &cloneobj->as<JSFunction>());
 
     clone->nargs = fun->nargs;
     clone->flags = fun->flags & ~JSFunction::EXTENDED;
     if (fun->hasScript()) {
--- a/js/src/jsfun.h
+++ b/js/src/jsfun.h
@@ -405,22 +405,32 @@ JSAPIToJSFunctionFlags(unsigned flags)
            : JSFunction::NATIVE_FUN;
 }
 
 namespace js {
 
 extern bool
 Function(JSContext *cx, unsigned argc, Value *vp);
 
+extern bool
+Generator(JSContext *cx, unsigned argc, Value *vp);
+
 extern JSFunction *
 NewFunction(ExclusiveContext *cx, HandleObject funobj, JSNative native, unsigned nargs,
             JSFunction::Flags flags, HandleObject parent, HandleAtom atom,
             gc::AllocKind allocKind = JSFunction::FinalizeKind,
             NewObjectKind newKind = GenericObject);
 
+// If proto is NULL, Function.prototype is used instead.
+extern JSFunction *
+NewFunctionWithProto(ExclusiveContext *cx, HandleObject funobj, JSNative native, unsigned nargs,
+                     JSFunction::Flags flags, HandleObject parent, HandleAtom atom,
+                     JSObject *proto, gc::AllocKind allocKind = JSFunction::FinalizeKind,
+                     NewObjectKind newKind = GenericObject);
+
 extern JSFunction *
 DefineFunction(JSContext *cx, HandleObject obj, HandleId id, JSNative native,
                unsigned nargs, unsigned flags,
                gc::AllocKind allocKind = JSFunction::FinalizeKind,
                NewObjectKind newKind = GenericObject);
 
 extern bool
 fun_resolve(JSContext *cx, js::HandleObject obj, js::HandleId id,
--- a/js/src/jsgc.cpp
+++ b/js/src/jsgc.cpp
@@ -4440,21 +4440,16 @@ BudgetIncrementalGC(JSRuntime *rt, int64
  * the marking implementation.
  */
 static JS_NEVER_INLINE void
 GCCycle(JSRuntime *rt, bool incremental, int64_t budget, JSGCInvocationKind gckind, JS::gcreason::Reason reason)
 {
     /* If we attempt to invoke the GC while we are running in the GC, assert. */
     JS_ASSERT(!rt->isHeapBusy());
 
-#ifdef DEBUG
-    for (ZonesIter zone(rt); !zone.done(); zone.next())
-        JS_ASSERT_IF(rt->gcMode == JSGC_MODE_GLOBAL, zone->isGCScheduled());
-#endif
-
     AutoGCSession gcsession(rt);
 
     /*
      * As we about to purge caches and clear the mark bits we must wait for
      * any background finalization to finish. We must also wait for the
      * background allocation to finish so we can avoid taking the GC lock
      * when manipulating the chunks during the GC.
      */
--- a/js/src/jsiter.cpp
+++ b/js/src/jsiter.cpp
@@ -953,17 +953,17 @@ Class ElementIteratorObject::class_ = {
 };
 
 const JSFunctionSpec ElementIteratorObject::methods[] = {
     JS_FN("next", next, 0, 0),
     JS_FS_END
 };
 
 static bool
-CloseGenerator(JSContext *cx, HandleObject genobj);
+CloseLegacyGenerator(JSContext *cx, HandleObject genobj);
 
 bool
 js::ValueToIterator(JSContext *cx, unsigned flags, MutableHandleValue vp)
 {
     /* JSITER_KEYVALUE must always come with JSITER_FOREACH */
     JS_ASSERT_IF(flags & JSITER_KEYVALUE, flags & JSITER_FOREACH);
 
     /*
@@ -995,16 +995,40 @@ js::ValueToIterator(JSContext *cx, unsig
                 return false;
         }
     }
 
     return GetIterator(cx, obj, flags, vp);
 }
 
 bool
+IsGenerator(HandleValue v)
+{
+    return v.isObject() && v.toObject().is<GeneratorObject>();
+}
+
+static bool
+IsLegacyGenerator(HandleObject obj)
+{
+    if (!obj->is<GeneratorObject>())
+        return false;
+    JSGenerator *gen = obj->as<GeneratorObject>().getGenerator();
+    return gen->regs.fp()->script()->isLegacyGenerator();
+}
+
+bool
+IsLegacyGenerator(HandleValue v)
+{
+    if (!IsGenerator(v))
+        return false;
+    JSGenerator *gen = v.toObject().as<GeneratorObject>().getGenerator();
+    return gen->regs.fp()->script()->isLegacyGenerator();
+}
+
+bool
 js::CloseIterator(JSContext *cx, HandleObject obj)
 {
     cx->iterValue.setMagic(JS_NO_ITER_VALUE);
 
     if (obj->is<PropertyIteratorObject>()) {
         /* Remove enumerators from the active list, which is a stack. */
         NativeIterator *ni = obj->as<PropertyIteratorObject>().getNativeIterator();
 
@@ -1015,19 +1039,18 @@ js::CloseIterator(JSContext *cx, HandleO
             ni->flags &= ~JSITER_ACTIVE;
 
             /*
              * Reset the enumerator; it may still be in the cached iterators
              * for this thread, and can be reused.
              */
             ni->props_cursor = ni->props_array;
         }
-    } else if (obj->is<GeneratorObject>()) {
-        // FIXME: Only close legacy generators.
-        return CloseGenerator(cx, obj);
+    } else if (IsLegacyGenerator(obj)) {
+        return CloseLegacyGenerator(cx, obj);
     }
     return true;
 }
 
 bool
 js::UnwindIteratorForException(JSContext *cx, HandleObject obj)
 {
     RootedValue v(cx, cx->getPendingException());
@@ -1472,25 +1495,35 @@ Class GeneratorObject::class_ = {
 JSObject *
 js_NewGenerator(JSContext *cx, const FrameRegs &stackRegs)
 {
     JS_ASSERT(stackRegs.stackDepth() == 0);
     StackFrame *stackfp = stackRegs.fp();
 
     JS_ASSERT(stackfp->script()->isGenerator());
 
-    if (stackfp->script()->isStarGenerator()) {
-        JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_ES6_UNIMPLEMENTED);
-        return NULL;
-    }
-
     Rooted<GlobalObject*> global(cx, &stackfp->global());
     RootedObject obj(cx);
-    {
-        JSObject *proto = global->getOrCreateGeneratorPrototype(cx);
+    if (stackfp->script()->isStarGenerator()) {
+        RootedValue pval(cx);
+        RootedObject fun(cx, stackfp->fun());
+        // FIXME: This would be faster if we could avoid doing a lookup to get
+        // the prototype for the instance.  Bug 906600.
+        if (!JSObject::getProperty(cx, fun, fun, cx->names().classPrototype, &pval))
+            return NULL;
+        JSObject *proto = pval.isObject() ? &pval.toObject() : NULL;
+        if (!proto) {
+            proto = global->getOrCreateStarGeneratorObjectPrototype(cx);
+            if (!proto)
+                return NULL;
+        }
+        obj = NewObjectWithGivenProto(cx, &GeneratorObject::class_, proto, global);
+    } else {
+        JS_ASSERT(stackfp->script()->isLegacyGenerator());
+        JSObject *proto = global->getOrCreateLegacyGeneratorObjectPrototype(cx);
         if (!proto)
             return NULL;
         obj = NewObjectWithGivenProto(cx, &GeneratorObject::class_, proto, global);
     }
     if (!obj)
         return NULL;
 
     /* Load and compute stack slot counts. */
@@ -1618,90 +1651,46 @@ SendToGenerator(JSContext *cx, JSGenerat
     /*
      * An error, silent termination by operation callback or an exception.
      * Propagate the condition to the caller.
      */
     return false;
 }
 
 static bool
-CloseGenerator(JSContext *cx, HandleObject obj)
+CloseLegacyGenerator(JSContext *cx, HandleObject obj)
 {
+    JS_ASSERT(IsLegacyGenerator(obj));
+
     JSGenerator *gen = obj->as<GeneratorObject>().getGenerator();
-    if (!gen) {
-        /* Generator prototype object. */
-        return true;
-    }
-
-    // FIXME: Assert that gen is a legacy generator.
-
     if (gen->state == JSGEN_CLOSED)
         return true;
 
     return SendToGenerator(cx, JSGENOP_CLOSE, obj, gen, JS::UndefinedHandleValue);
 }
 
 JS_ALWAYS_INLINE bool
-IsGenerator(HandleValue v)
-{
-    return v.isObject() && v.toObject().is<GeneratorObject>();
-}
-
-JS_ALWAYS_INLINE bool
-generator_send_impl(JSContext *cx, CallArgs args)
-{
-    // FIXME: Change assertion to IsLegacyGenerator().
-    JS_ASSERT(IsGenerator(args.thisv()));
-
-    RootedObject thisObj(cx, &args.thisv().toObject());
-
-    JSGenerator *gen = thisObj->as<GeneratorObject>().getGenerator();
-    if (!gen || gen->state == JSGEN_CLOSED) {
-        /* This happens when obj is the generator prototype. See bug 352885. */
-        return js_ThrowStopIteration(cx);
-    }
-
-    if (gen->state == JSGEN_NEWBORN && args.hasDefined(0)) {
-        RootedValue val(cx, args[0]);
-        js_ReportValueError(cx, JSMSG_BAD_GENERATOR_SEND,
-                            JSDVG_SEARCH_STACK, val, NullPtr());
-        return false;
-    }
-
-    // FIXME: next() takes the send value as an optional argument in ES6
-    // generator objects.
-    if (!SendToGenerator(cx, JSGENOP_SEND, thisObj, gen, args.get(0)))
-        return false;
-
-    args.rval().set(gen->fp->returnValue());
-    return true;
-}
-
-bool
-generator_send(JSContext *cx, unsigned argc, Value *vp)
-{
-    // FIXME: send() is only a method on legacy generator objects.
-    CallArgs args = CallArgsFromVp(argc, vp);
-    return CallNonGenericMethod<IsGenerator, generator_send_impl>(cx, args);
-}
-
-JS_ALWAYS_INLINE bool
 generator_next_impl(JSContext *cx, CallArgs args)
 {
     JS_ASSERT(IsGenerator(args.thisv()));
 
     RootedObject thisObj(cx, &args.thisv().toObject());
 
     JSGenerator *gen = thisObj->as<GeneratorObject>().getGenerator();
-    if (!gen || gen->state == JSGEN_CLOSED) {
-        /* This happens when obj is the generator prototype. See bug 352885. */
+    if (gen->state == JSGEN_CLOSED)
         return js_ThrowStopIteration(cx);
+
+    if (gen->state == JSGEN_NEWBORN && args.hasDefined(0)) {
+        RootedValue val(cx, args[0]);
+        js_ReportValueError(cx, JSMSG_BAD_GENERATOR_SEND,
+                            JSDVG_SEARCH_STACK, val, NullPtr());
+        return false;
     }
 
-    if (!SendToGenerator(cx, JSGENOP_NEXT, thisObj, gen, JS::UndefinedHandleValue))
+    if (!SendToGenerator(cx, JSGENOP_SEND, thisObj, gen, args.get(0)))
         return false;
 
     args.rval().set(gen->fp->returnValue());
     return true;
 }
 
 bool
 generator_next(JSContext *cx, unsigned argc, Value *vp)
@@ -1713,18 +1702,17 @@ generator_next(JSContext *cx, unsigned a
 JS_ALWAYS_INLINE bool
 generator_throw_impl(JSContext *cx, CallArgs args)
 {
     JS_ASSERT(IsGenerator(args.thisv()));
 
     RootedObject thisObj(cx, &args.thisv().toObject());
 
     JSGenerator *gen = thisObj->as<GeneratorObject>().getGenerator();
-    if (!gen || gen->state == JSGEN_CLOSED) {
-        /* This happens when obj is the generator prototype. See bug 352885. */
+    if (gen->state == JSGEN_CLOSED) {
         cx->setPendingException(args.length() >= 1 ? args[0] : UndefinedValue());
         return false;
     }
 
     if (!SendToGenerator(cx, JSGENOP_THROW, thisObj, gen, args.get(0)))
         return false;
 
     args.rval().set(gen->fp->returnValue());
@@ -1736,24 +1724,22 @@ generator_throw(JSContext *cx, unsigned 
 {
     CallArgs args = CallArgsFromVp(argc, vp);
     return CallNonGenericMethod<IsGenerator, generator_throw_impl>(cx, args);
 }
 
 JS_ALWAYS_INLINE bool
 generator_close_impl(JSContext *cx, CallArgs args)
 {
-    // FIXME: Change assertion to IsLegacyGenerator().
-    JS_ASSERT(IsGenerator(args.thisv()));
+    JS_ASSERT(IsLegacyGenerator(args.thisv()));
 
     RootedObject thisObj(cx, &args.thisv().toObject());
 
     JSGenerator *gen = thisObj->as<GeneratorObject>().getGenerator();
-    if (!gen || gen->state == JSGEN_CLOSED) {
-        /* This happens when obj is the generator prototype. See bug 352885. */
+    if (gen->state == JSGEN_CLOSED) {
         args.rval().setUndefined();
         return true;
     }
 
     if (gen->state == JSGEN_NEWBORN) {
         SetGeneratorClosed(cx, gen);
         args.rval().setUndefined();
         return true;
@@ -1764,32 +1750,57 @@ generator_close_impl(JSContext *cx, Call
 
     args.rval().set(gen->fp->returnValue());
     return true;
 }
 
 bool
 generator_close(JSContext *cx, unsigned argc, Value *vp)
 {
-    // FIXME: close() is only a method on legacy generator objects.
     CallArgs args = CallArgsFromVp(argc, vp);
-    return CallNonGenericMethod<IsGenerator, generator_close_impl>(cx, args);
+    return CallNonGenericMethod<IsLegacyGenerator, generator_close_impl>(cx, args);
 }
 
 #define JSPROP_ROPERM   (JSPROP_READONLY | JSPROP_PERMANENT)
 
-static const JSFunctionSpec generator_methods[] = {
+static const JSFunctionSpec legacy_generator_methods[] = {
     JS_FN("iterator",  iterator_iterator,  0, 0),
-    JS_FN("next",      generator_next,     0,JSPROP_ROPERM),
-    JS_FN("send",      generator_send,     1,JSPROP_ROPERM),
+    JS_FN("next",      generator_next,     1,JSPROP_ROPERM),
+    // Send is exactly the same as next.
+    JS_FN("send",      generator_next,     1,JSPROP_ROPERM),
     JS_FN("throw",     generator_throw,    1,JSPROP_ROPERM),
     JS_FN("close",     generator_close,    0,JSPROP_ROPERM),
     JS_FS_END
 };
 
+static const JSFunctionSpec star_generator_methods[] = {
+    JS_FN("iterator",  iterator_iterator,  0, 0),
+    JS_FN("next",      generator_next,     1,JSPROP_ROPERM),
+    JS_FN("throw",     generator_throw,    1,JSPROP_ROPERM),
+    JS_FS_END
+};
+
+static JSObject*
+NewObjectWithObjectPrototype(JSContext *cx, Handle<GlobalObject *> global)
+{
+    JSObject *proto = global->getOrCreateObjectPrototype(cx);
+    if (!proto)
+        return NULL;
+    return NewObjectWithGivenProto(cx, &JSObject::class_, proto, global);
+}
+
+static JSObject*
+NewObjectWithFunctionPrototype(JSContext *cx, Handle<GlobalObject *> global)
+{
+    JSObject *proto = global->getOrCreateFunctionPrototype(cx);
+    if (!proto)
+        return NULL;
+    return NewObjectWithGivenProto(cx, &JSObject::class_, proto, global);
+}
+
 /* static */ bool
 GlobalObject::initIteratorClasses(JSContext *cx, Handle<GlobalObject *> global)
 {
     RootedObject iteratorProto(cx);
     Value iteratorProtoVal = global->getPrototype(JSProto_Iterator);
     if (iteratorProtoVal.isObject()) {
         iteratorProto = &iteratorProtoVal.toObject();
     } else {
@@ -1821,21 +1832,51 @@ GlobalObject::initIteratorClasses(JSCont
     if (global->getSlot(ELEMENT_ITERATOR_PROTO).isUndefined()) {
         Class *cls = &ElementIteratorObject::class_;
         proto = global->createBlankPrototypeInheriting(cx, cls, *iteratorProto);
         if (!proto || !DefinePropertiesAndBrand(cx, proto, NULL, ElementIteratorObject::methods))
             return false;
         global->setReservedSlot(ELEMENT_ITERATOR_PROTO, ObjectValue(*proto));
     }
 
-    if (global->getSlot(GENERATOR_PROTO).isUndefined()) {
-        proto = global->createBlankPrototype(cx, &GeneratorObject::class_);
-        if (!proto || !DefinePropertiesAndBrand(cx, proto, NULL, generator_methods))
+    if (global->getSlot(LEGACY_GENERATOR_OBJECT_PROTO).isUndefined()) {
+        proto = NewObjectWithObjectPrototype(cx, global);
+        if (!proto || !DefinePropertiesAndBrand(cx, proto, NULL, legacy_generator_methods))
+            return false;
+        global->setReservedSlot(LEGACY_GENERATOR_OBJECT_PROTO, ObjectValue(*proto));
+    }
+
+    if (global->getSlot(STAR_GENERATOR_OBJECT_PROTO).isUndefined()) {
+        RootedObject genObjectProto(cx, NewObjectWithObjectPrototype(cx, global));
+        if (!genObjectProto)
+            return false;
+        if (!DefinePropertiesAndBrand(cx, genObjectProto, NULL, star_generator_methods))
+            return false;
+
+        RootedObject genFunctionProto(cx, NewObjectWithFunctionPrototype(cx, global));
+        if (!genFunctionProto)
             return false;
-        global->setReservedSlot(GENERATOR_PROTO, ObjectValue(*proto));
+        if (!LinkConstructorAndPrototype(cx, genFunctionProto, genObjectProto))
+            return false;
+
+        RootedValue function(cx, global->getConstructor(JSProto_Function));
+        if (!function.toObjectOrNull())
+            return false;
+        RootedAtom name(cx, cx->names().GeneratorFunction);
+        RootedObject genFunction(cx, NewFunctionWithProto(cx, NullPtr(), Generator, 1,
+                                                          JSFunction::NATIVE_CTOR, global, name,
+                                                          &function.toObject()));
+        if (!genFunction)
+            return false;
+        if (!LinkConstructorAndPrototype(cx, genFunction, genFunctionProto))
+            return false;
+
+        global->setSlot(STAR_GENERATOR_OBJECT_PROTO, ObjectValue(*genObjectProto));
+        global->setSlot(JSProto_GeneratorFunction, ObjectValue(*genFunction));
+        global->setSlot(JSProto_GeneratorFunction + JSProto_LIMIT, ObjectValue(*genFunctionProto));
     }
 
     if (global->getPrototype(JSProto_StopIteration).isUndefined()) {
         proto = global->createBlankPrototype(cx, &StopIterationObject::class_);
         if (!proto || !JSObject::freeze(cx, proto))
             return false;
 
         /* This should use a non-JSProtoKey'd slot, but this is easier for now. */
--- a/js/src/jsprototypes.h
+++ b/js/src/jsprototypes.h
@@ -64,10 +64,11 @@
     macro(int16,                 45,     js_InitBinaryDataClasses) \
     macro(int32,                 46,     js_InitBinaryDataClasses) \
     macro(int64,                 47,     js_InitBinaryDataClasses) \
     macro(float32,               48,     js_InitBinaryDataClasses) \
     macro(float64,               49,     js_InitBinaryDataClasses) \
     macro(ArrayType,             50,     js_InitBinaryDataClasses) \
     macro(StructType,            51,     js_InitBinaryDataClasses) \
     macro(ArrayTypeObject,       52,     js_InitBinaryDataClasses) \
+    macro(GeneratorFunction,     53,     js_InitIteratorClasses) \
 
 #endif /* jsprototypes_h */
--- a/js/src/jsworkers.cpp
+++ b/js/src/jsworkers.cpp
@@ -231,25 +231,27 @@ js::StartOffThreadParseScript(JSContext 
 
     RootedObject obj(cx);
 
     // Initialize all classes needed for parsing while we are still on the main
     // thread. Do this for both the target and the new global so that prototype
     // pointers can be changed infallibly after parsing finishes.
     if (!js_GetClassObject(cx, cx->global(), JSProto_Function, &obj) ||
         !js_GetClassObject(cx, cx->global(), JSProto_Array, &obj) ||
-        !js_GetClassObject(cx, cx->global(), JSProto_RegExp, &obj))
+        !js_GetClassObject(cx, cx->global(), JSProto_RegExp, &obj) ||
+        !js_GetClassObject(cx, cx->global(), JSProto_GeneratorFunction, &obj))
     {
         return false;
     }
     {
         AutoCompartment ac(cx, global);
         if (!js_GetClassObject(cx, global, JSProto_Function, &obj) ||
             !js_GetClassObject(cx, global, JSProto_Array, &obj) ||
-            !js_GetClassObject(cx, global, JSProto_RegExp, &obj))
+            !js_GetClassObject(cx, global, JSProto_RegExp, &obj) ||
+            !js_GetClassObject(cx, global, JSProto_GeneratorFunction, &obj))
         {
             return false;
         }
     }
 
     cx->runtime()->setUsedByExclusiveThread(global->zone());
 
     ScopedJSDeletePtr<ExclusiveContext> workercx(
new file mode 100755
--- /dev/null
+++ b/js/src/make-source-package.sh
@@ -0,0 +1,123 @@
+#!/bin/sh
+# need these environment vars:
+echo "Environment:"
+echo "    MAKE = $MAKE"
+echo "    MKDIR = $MKDIR"
+echo "    TAR = $TAR"
+echo "    DIST = $DIST"
+echo "    SRCDIR = $SRCDIR"
+echo "    MOZJS_MAJOR_VERSION = $MOZJS_MAJOR_VERSION"
+echo "    MOZJS_MINOR_VERSION = $MOZJS_MINOR_VERSION"
+echo "    MOZJS_PATCH_VERSION = $MOZJS_PATCH_VERSION"
+echo "    MOZJS_ALPHA = $MOZJS_ALPHA"
+
+cmd=${1:-build}
+pkg="mozjs-${MOZJS_MAJOR_VERSION}.${MOZJS_MINOR_VERSION}.${MOZJS_PATCH_VERSION:-${MOZJS_ALPHA:-0}}.tar.bz2"
+pkgpath=${pkg%.tar*}
+tgtpath=${DIST}/${pkgpath}
+taropts="-jcf"
+
+case $cmd in
+"clean")
+	echo "Cleaning ${pkg} and ${tgtpath} ..."
+	rm -rf ${pkg} ${tgtpath}
+	;;
+"build")
+	echo "Packaging source tarball ${pkg}..."
+	if [ -d ${tgtpath} ]; then
+		echo "WARNING - dist tree ${tgtpath} already exists!"
+	fi
+	${MKDIR} -p ${tgtpath}/js/src
+
+	# copy the embedded icu
+	${MKDIR} -p ${tgtpath}/intl
+	cp -t ${tgtpath}/intl -dRp ${SRCDIR}/../../intl/icu
+
+	# put in js itself
+	cp -t ${tgtpath} -dRp ${SRCDIR}/../../mfbt
+	cp -t ${tgtpath}/js -dRp ${SRCDIR}/../jsd ${SRCDIR}/../public
+	find ${SRCDIR} -mindepth 1 -maxdepth 1 -not -path ${DIST} -a -not -name ${pkg} \
+		-exec cp -t ${tgtpath}/js/src -dRp {} +
+
+	# distclean if necessary
+	if [ -e ${tgtpath}/js/src/Makefile ]; then
+		${MAKE} -C ${tgtpath}/js/src distclean
+	fi
+
+	# put in the virtualenv and supporting files if it doesnt already exist
+	if [ ! -e ${SRCDIR}/build/virtualenv ]; then
+		cp -t ${tgtpath}/js/src/build -dRp \
+			${SRCDIR}/../../build/virtualenv \
+			${SRCDIR}/../../build/buildconfig.py
+	fi
+	if [ ! -e ${SRCDIR}/python ]; then
+		cp -t ${tgtpath}/js/src -dRp \
+			${SRCDIR}/../../python
+	fi
+	if [ ! -e ${SRCDIR}/testing ]; then
+		${MKDIR} -p ${tgtpath}/js/src/testing
+		cp -t ${tgtpath}/js/src/testing -dRp \
+			${SRCDIR}/../../testing/mozbase
+	fi
+	# end of virtualenv injection
+
+	# remove *.pyc and *.pyo files if any
+	find ${tgtpath} -type f -name "*.pyc" -o -name "*.pyo" |xargs rm -f
+
+	# copy or create INSTALL
+	if [ -e {DIST}/INSTALL ]; then
+		cp -t ${tgtpath} ${DIST}/INSTALL
+	else
+		cat <<INSTALL_EOF >${tgtpath}/INSTALL
+Full build documentation for SpiderMonkey is hosted on MDN:
+  https://developer.mozilla.org/en-US/docs/SpiderMonkey/Build_Documentation
+
+Note that the libraries produced by the build system include symbols,
+causing the binaries to be extremely large. It is highly suggested that \`strip\`
+be run over the binaries before deploying them.
+
+Building with default options may be performed as follows:
+  cd js/src
+  ./configure
+  make
+INSTALL_EOF
+	fi
+
+	# copy or create README
+	if [ -e ${DIST}/README ]; then
+		cp -t ${tgtpath} ${DIST}/README
+	else
+		cat <<README_EOF >${tgtpath}/README
+This directory contains SpiderMonkey ${MOZJS_MAJOR_VERSION}.
+
+This release is based on a revision of Mozilla ${MOZJS_MAJOR_VERSION}:
+  http://hg.mozilla.org/releases/
+The changes in the patches/ directory were applied.
+
+MDN hosts the latest SpiderMonkey ${MOZJS_MAJOR_VERSION} release notes:
+  https://developer.mozilla.org/en-US/docs/SpiderMonkey/${MOZJS_MAJOR_VERSION}
+README_EOF
+	fi
+
+	# copy LICENSE
+	if [ -e ${SRCDIR}/../../b2g/LICENSE ]; then
+		cp ${SRCDIR}/../../b2g/LICENSE ${tgtpath}/
+	else
+		cp ${SRCDIR}/../../LICENSE ${tgtpath}/
+	fi
+
+	# copy patches dir, if it currently exists in DIST
+	if [ -d ${DIST}/patches ]; then
+		cp -t ${tgtpath} -dRp ${DIST}/patches
+	elif [ -d ${SRCDIR}/../../patches ]; then
+		cp -t ${tgtpath} -dRp ${SRCDIR}/../../patches
+	fi
+
+	# Roll the tarball
+	${TAR} $taropts ${DIST}/../${pkg} -C ${DIST} ${pkgpath}
+	echo "done."
+	;;
+*)
+	echo "Unrecognized command: $cmd"
+	;;
+esac
new file mode 100644
--- /dev/null
+++ b/js/src/tests/ecma_6/Generators/runtime.js
@@ -0,0 +1,150 @@
+// This file was written by Andy Wingo <wingo@igalia.com> and originally
+// contributed to V8 as generators-runtime.js, available here:
+//
+// http://code.google.com/p/v8/source/browse/branches/bleeding_edge/test/mjsunit/harmony/generators-runtime.js
+
+// Test aspects of the generator runtime.
+
+// See http://people.mozilla.org/~jorendorff/es6-draft.html#sec-15.19.3.
+
+function assertSyntaxError(str) {
+    var msg;
+    var evil = eval;
+    try {
+        // Non-direct eval.
+        evil(str);
+    } catch (exc) {
+        if (exc instanceof SyntaxError)
+            return;
+        msg = "Assertion failed: expected SyntaxError, got " + exc;
+    }
+    if (msg === undefined)
+        msg = "Assertion failed: expected SyntaxError, but no exception thrown";
+    throw new Error(msg + " - " + str);
+}
+
+function assertFalse(a) { assertEq(a, false) }
+function assertTrue(a) { assertEq(a, true) }
+function assertNotEq(found, not_expected) { assertFalse(found === expected) }
+function assertArrayEq(found, expected) {
+    assertEq(found.length, expected.length);
+    for (var i = 0; i < expected.length; i++)
+        assertEq(found[i], expected[i]);
+}
+
+
+function f() { }
+function* g() { yield 1; }
+var GeneratorFunctionPrototype = Object.getPrototypeOf(g);
+var GeneratorFunction = GeneratorFunctionPrototype.constructor;
+var GeneratorObjectPrototype = GeneratorFunctionPrototype.prototype;
+
+
+// A generator function should have the same set of properties as any
+// other function.
+function TestGeneratorFunctionInstance() {
+    var f_own_property_names = Object.getOwnPropertyNames(f);
+    var g_own_property_names = Object.getOwnPropertyNames(g);
+
+    f_own_property_names.sort();
+    g_own_property_names.sort();
+
+    assertArrayEq(f_own_property_names, g_own_property_names);
+    var i;
+    for (i = 0; i < f_own_property_names.length; i++) {
+        var prop = f_own_property_names[i];
+        var f_desc = Object.getOwnPropertyDescriptor(f, prop);
+        var g_desc = Object.getOwnPropertyDescriptor(g, prop);
+        assertEq(f_desc.configurable, g_desc.configurable, prop);
+        assertEq(f_desc.writable, g_desc.writable, prop);
+        assertEq(f_desc.enumerable, g_desc.enumerable, prop);
+    }
+}
+TestGeneratorFunctionInstance();
+
+
+// Generators have an additional object interposed in the chain between
+// themselves and Function.prototype.
+function TestGeneratorFunctionPrototype() {
+    // Sanity check.
+    assertEq(Object.getPrototypeOf(f), Function.prototype);
+    assertNotEq(GeneratorFunctionPrototype, Function.prototype);
+    assertEq(Object.getPrototypeOf(GeneratorFunctionPrototype),
+               Function.prototype);
+    assertEq(Object.getPrototypeOf(function* () {}),
+               GeneratorFunctionPrototype);
+}
+TestGeneratorFunctionPrototype();
+
+
+// Functions that we associate with generator objects are actually defined by
+// a common prototype.
+function TestGeneratorObjectPrototype() {
+    assertEq(Object.getPrototypeOf(GeneratorObjectPrototype),
+               Object.prototype);
+    assertEq(Object.getPrototypeOf((function*(){yield 1}).prototype),
+               GeneratorObjectPrototype);
+
+    var expected_property_names = ["iterator", "next", "throw", "constructor"];
+    var found_property_names =
+        Object.getOwnPropertyNames(GeneratorObjectPrototype);
+
+    expected_property_names.sort();
+    found_property_names.sort();
+
+    assertArrayEq(found_property_names, expected_property_names);
+}
+TestGeneratorObjectPrototype();
+
+
+// This tests the object that would be called "GeneratorFunction", if it were
+// like "Function".
+function TestGeneratorFunction() {
+    assertEq(GeneratorFunctionPrototype, GeneratorFunction.prototype);
+    assertTrue(g instanceof GeneratorFunction);
+
+    assertEq(Function, Object.getPrototypeOf(GeneratorFunction));
+    assertTrue(g instanceof Function);
+
+    assertEq("function* g() { yield 1; }", g.toString());
+
+    // Not all functions are generators.
+    assertTrue(f instanceof Function);  // Sanity check.
+    assertFalse(f instanceof GeneratorFunction);
+
+    assertTrue((new GeneratorFunction()) instanceof GeneratorFunction);
+    assertTrue(GeneratorFunction() instanceof GeneratorFunction);
+
+    assertTrue(GeneratorFunction('yield 1') instanceof GeneratorFunction);
+    assertTrue(GeneratorFunction('return 1') instanceof GeneratorFunction);
+    assertTrue(GeneratorFunction('a', 'yield a') instanceof GeneratorFunction);
+    assertTrue(GeneratorFunction('a', 'return a') instanceof GeneratorFunction);
+    assertTrue(GeneratorFunction('a', 'return a') instanceof GeneratorFunction);
+    assertSyntaxError("GeneratorFunction('yield', 'return yield')");
+    assertTrue(GeneratorFunction('with (x) return foo;') instanceof GeneratorFunction);
+    assertSyntaxError("GeneratorFunction('\"use strict\"; with (x) return foo;')");
+
+    // Doesn't matter particularly what string gets serialized, as long
+    // as it contains "function*" and "yield 10".
+    assertEq(GeneratorFunction('yield 10').toString(),
+             "function* anonymous() {\nyield 10\n}");
+}
+TestGeneratorFunction();
+
+
+function TestPerGeneratorPrototype() {
+    assertNotEq((function*(){}).prototype, (function*(){}).prototype);
+    assertNotEq((function*(){}).prototype, g.prototype);
+    assertEq(typeof GeneratorFunctionPrototype, "object");
+    assertEq(g.prototype.__proto__.constructor, GeneratorFunctionPrototype, "object");
+    assertEq(Object.getPrototypeOf(g.prototype), GeneratorObjectPrototype);
+    assertFalse(g.prototype instanceof Function);
+    assertEq(typeof (g.prototype), "object");
+
+    assertArrayEq(Object.getOwnPropertyNames(g.prototype), []);
+}
+TestPerGeneratorPrototype();
+
+
+if (typeof reportCompare == "function")
+    reportCompare(true, true);
--- a/js/src/tests/js1_7/extensions/regress-352885-02.js
+++ b/js/src/tests/js1_7/extensions/regress-352885-02.js
@@ -21,44 +21,45 @@ function test()
   printStatus (summary);
  
   function dotest()
   {
     var proto = (function() { yield 3; })().__proto__;
 
     try {
       proto.next();
-      throw "generatorProto.next() does not throw StopIteration";
+      throw "generatorProto.next() does not throw TypeError";
     } catch (e) {
-      if (!(e instanceof StopIteration))
+      if (!(e instanceof TypeError))
         throw "generatorProto.next() throws unexpected exception: "+uneval(e);
     }
 
     try {
       proto.send();
-      throw "generatorProto.send() does not throw StopIteration";
+      throw "generatorProto.send() does not throw TypeError";
     } catch (e) {
-      if (!(e instanceof StopIteration))
+      if (!(e instanceof TypeError))
         throw "generatorProto.send() throws unexpected exception: "+uneval(e);
     }
 
     var obj = {};
     try {
       proto.throw(obj);
-      throw "generatorProto.throw(obj) does not throw obj";
+      throw "generatorProto.throw(obj) does not throw TypeError";
     } catch (e) {
-      if (e !== obj)
+      if (!(e instanceof TypeError))
         throw "generatorProto.throw() throws unexpected exception: "+uneval(e);
     }
 
-    var obj = {};
     try {
       proto.close();
+      throw "generatorProto.close() does not throw TypeError";
     } catch (e) {
-      throw "generatorProto.throw() throws exception: "+uneval(e);
+      if (!(e instanceof TypeError))
+        throw "generatorProto.close() throws unexpected exception: "+uneval(e);
     }
 
   }
 
   dotest();
 
   reportCompare(expect, actual, summary);
 
--- a/js/src/vm/GlobalObject.h
+++ b/js/src/vm/GlobalObject.h
@@ -85,18 +85,19 @@ class GlobalObject : public JSObject
     static const unsigned FROM_BUFFER_UINT32 = FROM_BUFFER_INT16 + 1;
     static const unsigned FROM_BUFFER_INT32 = FROM_BUFFER_UINT32 + 1;
     static const unsigned FROM_BUFFER_FLOAT32 = FROM_BUFFER_INT32 + 1;
     static const unsigned FROM_BUFFER_FLOAT64 = FROM_BUFFER_FLOAT32 + 1;
     static const unsigned FROM_BUFFER_UINT8CLAMPED = FROM_BUFFER_FLOAT64 + 1;
 
     /* One-off properties stored after slots for built-ins. */
     static const unsigned ELEMENT_ITERATOR_PROTO  = FROM_BUFFER_UINT8CLAMPED + 1;
-    static const unsigned GENERATOR_PROTO         = ELEMENT_ITERATOR_PROTO + 1;
-    static const unsigned MAP_ITERATOR_PROTO      = GENERATOR_PROTO + 1;
+    static const unsigned LEGACY_GENERATOR_OBJECT_PROTO = ELEMENT_ITERATOR_PROTO + 1;
+    static const unsigned STAR_GENERATOR_OBJECT_PROTO = LEGACY_GENERATOR_OBJECT_PROTO + 1;
+    static const unsigned MAP_ITERATOR_PROTO      = STAR_GENERATOR_OBJECT_PROTO + 1;
     static const unsigned SET_ITERATOR_PROTO      = MAP_ITERATOR_PROTO + 1;
     static const unsigned COLLATOR_PROTO          = SET_ITERATOR_PROTO + 1;
     static const unsigned NUMBER_FORMAT_PROTO     = COLLATOR_PROTO + 1;
     static const unsigned DATE_TIME_FORMAT_PROTO  = NUMBER_FORMAT_PROTO + 1;
     static const unsigned REGEXP_STATICS          = DATE_TIME_FORMAT_PROTO + 1;
     static const unsigned FUNCTION_NS             = REGEXP_STATICS + 1;
     static const unsigned RUNTIME_CODEGEN_ENABLED = FUNCTION_NS + 1;
     static const unsigned DEBUGGERS               = RUNTIME_CODEGEN_ENABLED + 1;
@@ -359,18 +360,31 @@ class GlobalObject : public JSObject
     JSObject *getOrCreateIteratorPrototype(JSContext *cx) {
         return getOrCreateObject(cx, JSProto_LIMIT + JSProto_Iterator, initIteratorClasses);
     }
 
     JSObject *getOrCreateElementIteratorPrototype(JSContext *cx) {
         return getOrCreateObject(cx, ELEMENT_ITERATOR_PROTO, initIteratorClasses);
     }
 
-    JSObject *getOrCreateGeneratorPrototype(JSContext *cx) {
-        return getOrCreateObject(cx, GENERATOR_PROTO, initIteratorClasses);
+    JSObject *getOrCreateLegacyGeneratorObjectPrototype(JSContext *cx) {
+        return getOrCreateObject(cx, LEGACY_GENERATOR_OBJECT_PROTO, initIteratorClasses);
+    }
+
+    JSObject *getOrCreateStarGeneratorObjectPrototype(JSContext *cx) {
+        return getOrCreateObject(cx, STAR_GENERATOR_OBJECT_PROTO, initIteratorClasses);
+    }
+
+    JSObject *getOrCreateStarGeneratorFunctionPrototype(JSContext *cx) {
+        return getOrCreateObject(cx, JSProto_LIMIT + JSProto_GeneratorFunction,
+                                 initIteratorClasses);
+    }
+
+    JSObject *getOrCreateStarGeneratorFunction(JSContext *cx) {
+        return getOrCreateObject(cx, JSProto_GeneratorFunction, initIteratorClasses);
     }
 
     JSObject *getOrCreateMapIteratorPrototype(JSContext *cx) {
         return getOrCreateObject(cx, MAP_ITERATOR_PROTO, initMapIteratorProto);
     }
 
     JSObject *getOrCreateSetIteratorPrototype(JSContext *cx) {
         return getOrCreateObject(cx, SET_ITERATOR_PROTO, initSetIteratorProto);
--- a/layout/generic/nsFrame.cpp
+++ b/layout/generic/nsFrame.cpp
@@ -1660,16 +1660,24 @@ WrapPreserve3DListInternal(nsIFrame* aFr
 
     if (childFrame->GetParent() &&
         (childFrame->GetParent()->Preserves3DChildren() || childFrame == aFrame)) {
       switch (item->GetType()) {
         case nsDisplayItem::TYPE_TRANSFORM: {
           if (!aTemp->IsEmpty()) {
             aOutput->AppendToTop(new (aBuilder) nsDisplayTransform(aBuilder, aFrame, aTemp, aIndex++));
           }
+          // Override item's clipping with our current clip state (if any). Since we're
+          // bubbling up a preserve-3d transformed child to a preserve-3d parent,
+          // we can be sure the child doesn't have clip state of its own.
+          NS_ASSERTION(!item->GetClip().HasClip(), "Unexpected clip on item");
+          const DisplayItemClip* clip = aBuilder->ClipState().GetCurrentCombinedClip(aBuilder);
+          if (clip) {
+            item->SetClip(aBuilder, *clip);
+          }
           aOutput->AppendToTop(item);
           break;
         }
         case nsDisplayItem::TYPE_WRAP_LIST: {
           nsDisplayWrapList *list = static_cast<nsDisplayWrapList*>(item);
           rv = WrapPreserve3DListInternal(aFrame, aBuilder,
               list->GetChildren(), aOutput, aIndex, aTemp);
           list->~nsDisplayWrapList();
new file mode 100644
--- /dev/null
+++ b/layout/reftests/bugs/906199-1-ref.html
@@ -0,0 +1,32 @@
+<!DOCTYPE html>
+<html>
+<head>
+<style>
+div {
+  position:relative;
+  width:300px;
+  height:200px;
+  left:50px;
+  top:50px;
+}
+.grandparentdiv {
+  background:yellow;
+  overflow:hidden;
+}
+.childdiv {
+  background:green;
+}
+.grandchilddiv {
+  background:red;
+}
+</style>
+</head>
+<body>
+<div class="grandparentdiv">
+  <div class="childdiv">
+    <div class="grandchilddiv"></div>
+  </div>
+</div>
+</body>
+</html>
+
new file mode 100644
--- /dev/null
+++ b/layout/reftests/bugs/906199-1.html
@@ -0,0 +1,33 @@
+<!DOCTYPE html>
+<html>
+<head>
+<style>
+div {
+  position:relative;
+  width:300px;
+  height:200px;
+  left:50px;
+  top:50px;
+  transform-style:preserve-3d;
+}
+.grandparentdiv {
+  background:yellow;
+  overflow:hidden;
+}
+.childdiv {
+  background:green;
+}
+.grandchilddiv {
+  background:red;
+}
+</style>
+</head>
+<body>
+<div class="grandparentdiv">
+  <div class="childdiv">
+    <div class="grandchilddiv"></div>
+  </div>
+</div>
+</body>
+</html>
+
--- a/layout/reftests/bugs/reftest.list
+++ b/layout/reftests/bugs/reftest.list
@@ -1767,11 +1767,12 @@ test-pref(layout.css.flexbox.enabled,tru
 == 883987-1a.html 883987-1-ref.html
 == 883987-1b.html 883987-1-ref.html
 == 883987-1c.html 883987-1-ref.html
 == 883987-1d.html 883987-1-ref.html
 == 883987-1e.html 883987-1-ref.html
 == 883987-1f.html 883987-1-ref.html
 == 890495-1.html 890495-1-ref.html
 == 894931-1.html 894931-1-ref.html
-fuzzy(1,10000) == 902330-1.html 902330-1-ref.html
 == 897491-1.html 897491-1-ref.html
 == 897491-2.html 897491-2-ref.html
+fuzzy(1,10000) == 902330-1.html 902330-1-ref.html
+fuzzy-if(Android,4,245) == 906199-1.html 906199-1-ref.html
--- a/layout/style/nsICSSDeclaration.h
+++ b/layout/style/nsICSSDeclaration.h
@@ -25,24 +25,23 @@
 #include "CSSValue.h"
 #include "nsWrapperCache.h"
 #include "nsString.h"
 #include "nsIDOMCSSRule.h"
 #include "nsIDOMCSSValue.h"
 #include "mozilla/ErrorResult.h"
 #include "nsAutoPtr.h"
 #include "nsCOMPtr.h"
+#include "nsINode.h"
 
 // dbeabbfa-6cb3-4f5c-aec2-dd558d9d681f
 #define NS_ICSSDECLARATION_IID \
 { 0xdbeabbfa, 0x6cb3, 0x4f5c, \
  { 0xae, 0xc2, 0xdd, 0x55, 0x8d, 0x9d, 0x68, 0x1f } }
 
-class nsINode;
-
 class nsICSSDeclaration : public nsIDOMCSSStyleDeclaration,
                           public nsWrapperCache
 {
 public:
   NS_DECLARE_STATIC_IID_ACCESSOR(NS_ICSSDECLARATION_IID)
 
   /**
    * Method analogous to nsIDOMCSSStyleDeclaration::GetPropertyValue,
--- a/media/webrtc/signaling/src/sipcc/core/gsm/gsm_sdp.c
+++ b/media/webrtc/signaling/src/sipcc/core/gsm/gsm_sdp.c
@@ -1,9 +1,11 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sts=4 et sw=4 tw=99:
+ * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "cpr_in.h"
 #include "cpr_rand.h"
 #include "cpr_stdlib.h"
 #include "lsm.h"
 #include "fsm.h"
@@ -4397,16 +4399,199 @@ fsmdef_media_t* gsmsdp_find_media_by_med
             /* found a match */
             return (media);
         }
     }
     return (NULL);
 }
 
 /*
+ * gsmsdp_add_rtcp_fb
+ *
+ * Description:
+ *  Adds a=rtcp-fb attributes to local SDP for supported video codecs
+ *
+ * Parameters:
+ *   level - SDP media level (between 1 and the # of m-lines)
+ *   sdp_p - pointer to local SDP
+ *   codec - the codec type that the attributes should be added for
+ *   types - a bitmask of rtcp-fb types to add, taken from
+ *           sdp_rtcp_fb_bitmask_e
+ *
+ * returns
+ *  CC_CAUSE_OK - success
+ *  any other code - failure
+ */
+cc_causes_t
+gsmsdp_add_rtcp_fb (int level, sdp_t *sdp_p,
+                    rtp_ptype codec, unsigned int types)
+{
+    int num_pts;
+    int pt_codec;
+    sdp_payload_ind_e indicator;
+
+    int pt_index;
+    unsigned int j;
+    num_pts = sdp_get_media_num_payload_types(sdp_p, level);
+    for (pt_index = 1; pt_index <= num_pts; pt_index++) {
+        pt_codec = sdp_get_media_payload_type (sdp_p, level, pt_index,
+                                               &indicator);
+        if ((pt_codec & 0xFF) == codec) {
+            int pt = GET_DYN_PAYLOAD_TYPE_VALUE(pt_codec);
+
+            /* Add requested a=rtcp-fb:nack attributes */
+            for (j = 0; j < SDP_MAX_RTCP_FB_NACK; j++) {
+                if (types & SDP_RTCP_FB_NACK_TO_BITMAP(j)) {
+                    gsmsdp_set_rtcp_fb_nack_attribute(level, sdp_p, pt, j);
+                }
+            }
+
+            /* Add requested a=rtcp-fb:ack attributes */
+            for (j = 0; j < SDP_MAX_RTCP_FB_ACK; j++) {
+                if (types & SDP_RTCP_FB_ACK_TO_BITMAP(j)) {
+                    gsmsdp_set_rtcp_fb_nack_attribute(level, sdp_p, pt, j);
+                }
+            }
+
+            /* Add requested a=rtcp-fb:ccm attributes */
+            for (j = 0; j < SDP_MAX_RTCP_FB_CCM; j++) {
+                if (types & SDP_RTCP_FB_CCM_TO_BITMAP(j)) {
+                    gsmsdp_set_rtcp_fb_ccm_attribute(level, sdp_p, pt, j);
+                }
+            }
+
+        }
+    }
+    return CC_CAUSE_OK;
+}
+
+
+/*
+ * gsmsdp_negotiate_rtcp_fb
+ *
+ * Description:
+ *  Negotiates a=rtcp-fb attributes to local SDP for supported video codecs
+ *
+ * Parameters:
+ *   cc_sdp_p - local and remote SDP
+ *   media    - The media structure for the current level to be negotiated
+ *   offer    - True if the remote SDP is an offer
+ *
+ * returns
+ *  CC_CAUSE_OK - success
+ *  any other code - failure
+ */
+cc_causes_t
+gsmsdp_negotiate_rtcp_fb (cc_sdp_t *cc_sdp_p,
+                          fsmdef_media_t *media,
+                          boolean offer)
+{
+    int level = media->level;
+    int pt_codec;
+    int remote_pt;
+    sdp_payload_ind_e indicator;
+    int pt_index, i;
+    sdp_rtcp_fb_nack_type_e nack_type;
+    sdp_rtcp_fb_ack_type_e ack_type;
+    sdp_rtcp_fb_ccm_type_e ccm_type;
+    uint32_t fb_types = 0;
+
+    int num_pts = sdp_get_media_num_payload_types(cc_sdp_p->dest_sdp, level);
+
+    /*
+     * Remove any previously negotiated rtcp-fb attributes from the
+     * local SDP
+     */
+    sdp_result_e result = SDP_SUCCESS;
+    while (result == SDP_SUCCESS) {
+        result = sdp_delete_attr (cc_sdp_p->src_sdp, level, 0,
+                                  SDP_ATTR_RTCP_FB, 1);
+    }
+
+    /*
+     * For each remote payload type, determine what feedback types are
+     * requested.
+     */
+    for (pt_index = 1; pt_index <= num_pts; pt_index++) {
+        int pt_codec = sdp_get_media_payload_type (cc_sdp_p->dest_sdp,
+                                                   level, pt_index, &indicator);
+        int codec = pt_codec & 0xFF;
+        remote_pt = GET_DYN_PAYLOAD_TYPE_VALUE(pt_codec);
+        fb_types = 0;
+
+        /* a=rtcp-fb:nack */
+        i = 1;
+        do {
+            nack_type = sdp_attr_get_rtcp_fb_nack(cc_sdp_p->dest_sdp,
+                                                  level, remote_pt, i);
+            if (nack_type >= 0 && nack_type < SDP_MAX_RTCP_FB_NACK) {
+                fb_types |= SDP_RTCP_FB_NACK_TO_BITMAP(nack_type);
+            }
+            i++;
+        } while (nack_type != SDP_RTCP_FB_NACK_NOT_FOUND);
+
+        /* a=rtcp-fb:ack */
+        i = 1;
+        do {
+            ack_type = sdp_attr_get_rtcp_fb_ack(cc_sdp_p->dest_sdp,
+                                                level, remote_pt, i);
+            if (ack_type >= 0 && ack_type < SDP_MAX_RTCP_FB_ACK) {
+                fb_types |= SDP_RTCP_FB_ACK_TO_BITMAP(ack_type);
+            }
+            i++;
+        } while (ack_type != SDP_RTCP_FB_CCM_NOT_FOUND);
+
+        /* a=rtcp-fb:ccm */
+        i = 1;
+        do {
+            ccm_type = sdp_attr_get_rtcp_fb_ccm(cc_sdp_p->dest_sdp,
+                                                level, remote_pt, i);
+            if (ccm_type >= 0 && ccm_type < SDP_MAX_RTCP_FB_CCM) {
+                fb_types |= SDP_RTCP_FB_CCM_TO_BITMAP(ccm_type);
+            }
+            i++;
+        } while (ccm_type != SDP_RTCP_FB_CCM_NOT_FOUND);
+
+        /*
+         * Mask out the types that we do not support
+         */
+        switch (codec) {
+            case RTP_VP8:
+                fb_types &=
+                  SDP_RTCP_FB_NACK_TO_BITMAP(SDP_RTCP_FB_NACK_BASIC) |
+                  SDP_RTCP_FB_NACK_TO_BITMAP(SDP_RTCP_FB_NACK_PLI) |
+                  SDP_RTCP_FB_CCM_TO_BITMAP(SDP_RTCP_FB_CCM_FIR);
+                break;
+            default:
+                fb_types = 0;
+        }
+
+        /*
+         * Now, in our local SDP, set rtcp-fb types that both we and the
+         * remote party support
+         */
+        if (fb_types) {
+            gsmsdp_add_rtcp_fb (level, cc_sdp_p->src_sdp, codec, fb_types);
+        }
+
+        /*
+         * Finally, update the media record for this payload type to
+         * reflect the expected feedback types
+         */
+        for (i = 0; i < media->num_payloads; i++) {
+            if (media->payloads[i].remote_rtp_pt == remote_pt) {
+                media->payloads[i].video.rtcp_fb_types = fb_types;
+            }
+        }
+    }
+
+    return CC_CAUSE_OK;
+}
+
+/*
  * gsmsdp_negotiate_media_lines
  *
  * Description:
  *
  * Walk down the media lines provided in the remote sdp. Compare each
  * media line to the corresponding media line in the local sdp. If
  * the media line does not exist in the local sdp, add it. If the media
  * line exists in the local sdp but is different from the remote sdp,
@@ -4726,16 +4911,21 @@ gsmsdp_negotiate_media_lines (fsm_fcb_t 
             } else {
                 /*
                  * Rejecting multicast because direction is not RECVONLY
                  */
                 unsupported_line = TRUE;
                 update_local_ret_value = TRUE;
             }
 
+            /* Negotiate rtcp feedback mechanisms */
+            if (media && media_type == SDP_MEDIA_VIDEO) {
+                gsmsdp_negotiate_rtcp_fb (dcb_p->sdp, media, offer);
+            }
+
             /*
              * Negotiate rtcp-mux
              */
             if(SDP_MEDIA_APPLICATION != media_type) {
               sdp_res = sdp_attr_get_rtcp_mux_attribute(sdp_p->dest_sdp, i,
                                                         0, SDP_ATTR_RTCP_MUX,
                                                         1, &rtcp_mux);
 
@@ -4810,29 +5000,16 @@ gsmsdp_negotiate_media_lines (fsm_fcb_t 
             break;
 
         default:
             /* Not a support media type stream */
             unsupported_line = TRUE;
             break;
         }
 
-        /* TODO (abr) -- temporarily hardcode rtcb-fb attributes to match our
-           actual behavior. This really needs to be a negotiation, with the
-           results of the negotiation propagating into the codec configuration.
-           See Bug 880067. */
-        if (media && media_type == SDP_MEDIA_VIDEO) {
-            gsmsdp_set_rtcp_fb_nack_attribute(media->level, sdp_p->src_sdp,
-                                              SDP_ALL_PAYLOADS,
-                                              SDP_RTCP_FB_NACK_UNSPECIFIED);
-            gsmsdp_set_rtcp_fb_ccm_attribute(media->level, sdp_p->src_sdp,
-                                             SDP_ALL_PAYLOADS,
-                                             SDP_RTCP_FB_CCM_FIR);
-        }
-
         if (unsupported_line) {
             /* add this line to unsupported line */
             gsmsdp_add_unsupported_stream_to_local_sdp(sdp_p, i);
             gsmsdp_set_mid_attr(sdp_p->src_sdp, i);
             /* Remove the media if one to be removed */
             if (media != NULL) {
                 /* remove this media off the list */
                 gsmsdp_remove_media(dcb_p, media);
@@ -5266,16 +5443,24 @@ gsmsdp_add_media_line (fsmdef_dcb_t *dcb
 
         gsmsdp_update_local_sdp_media(dcb_p, dcb_p->sdp, TRUE, media,
                                           media->transport);
 
         if (media->support_direction != SDP_DIRECTION_INACTIVE) {
 
           gsmsdp_set_local_sdp_direction(dcb_p, media, media->direction);
 
+          /* Add supported rtcp-fb types */
+          if (media_cap->type == SDP_MEDIA_VIDEO) {
+              gsmsdp_add_rtcp_fb (level, dcb_p->sdp->src_sdp, RTP_VP8,
+                  SDP_RTCP_FB_NACK_TO_BITMAP(SDP_RTCP_FB_NACK_BASIC) |
+                  SDP_RTCP_FB_NACK_TO_BITMAP(SDP_RTCP_FB_NACK_PLI) |
+                  SDP_RTCP_FB_CCM_TO_BITMAP(SDP_RTCP_FB_CCM_FIR));
+          }
+
           /*
            * wait until here to set ICE candidates as SDP is now initialized
            */
           for (i=0; i<media->candidate_ct; i++) {
             gsmsdp_set_ice_attribute (SDP_ATTR_ICE_CANDIDATE, level, dcb_p->sdp->src_sdp, media->candidatesp[i]);
           }
 
           config_get_value(CFGID_RTCPMUX, &rtcpmux, sizeof(rtcpmux));
@@ -5392,30 +5577,16 @@ gsmsdp_create_local_sdp (fsmdef_dcb_t *d
                 }
             } else {
                 if (gsmsdp_add_media_line(dcb_p, media_cap, cap_index, level,
                                           CPR_IP_ADDR_IPV4, offer) == NULL) {
                     /* fail to add a media line, go back one level */
                     level = level - 1;
                 }
             }
-
-            /* TODO (abr) -- temporarily hardcode rtcb-fb attributes to match
-               our actual behavior. This really needs to be a negotiation, with
-               the results of the negotiation propagating into the codec
-               configuration.  See Bug 880067. */
-            if (media_cap->type == SDP_MEDIA_VIDEO) {
-                gsmsdp_set_rtcp_fb_nack_attribute(level, dcb_p->sdp->src_sdp,
-                                                  SDP_ALL_PAYLOADS,
-                                                  SDP_RTCP_FB_NACK_UNSPECIFIED);
-                gsmsdp_set_rtcp_fb_ccm_attribute(level, dcb_p->sdp->src_sdp,
-                                                 SDP_ALL_PAYLOADS,
-                                                 SDP_RTCP_FB_CCM_FIR);
-            }
-
         }
         /* next capability */
         media_cap++;
     }
 
     if (level == 0) {
         /*
          * Did not find media line for the SDP and we do not
--- a/media/webrtc/signaling/src/sipcc/core/sdp/sdp.h
+++ b/media/webrtc/signaling/src/sipcc/core/sdp/sdp.h
@@ -483,17 +483,17 @@ typedef enum {
     SDP_RTCP_FB_NACK,
     SDP_RTCP_FB_TRR_INT,
     SDP_MAX_RTCP_FB,
     SDP_RTCP_FB_UNKNOWN
 } sdp_rtcp_fb_type_e;
 
 typedef enum {
     SDP_RTCP_FB_NACK_NOT_FOUND = -1,
-    SDP_RTCP_FB_NACK_UNSPECIFIED = 0,
+    SDP_RTCP_FB_NACK_BASIC = 0,
     SDP_RTCP_FB_NACK_SLI,
     SDP_RTCP_FB_NACK_PLI,
     SDP_RTCP_FB_NACK_RPSI,
     SDP_RTCP_FB_NACK_APP,
     SDP_RTCP_FB_NACK_RAI,
     SDP_RTCP_FB_NACK_TLLEI,
     SDP_RTCP_FB_NACK_PSLEI,
     SDP_RTCP_FB_NACK_ECN,
@@ -514,16 +514,21 @@ typedef enum {
     SDP_RTCP_FB_CCM_FIR = 0,
     SDP_RTCP_FB_CCM_TMMBR,
     SDP_RTCP_FB_CCM_TSTR,
     SDP_RTCP_FB_CCM_VBCM,
     SDP_MAX_RTCP_FB_CCM,
     SDP_RTCP_FB_CCM_UNKNOWN
 } sdp_rtcp_fb_ccm_type_e;
 
+#define SDP_RTCP_FB_NACK_TO_BITMAP(type) (1 << (type))
+#define SDP_RTCP_FB_ACK_TO_BITMAP(type)  (1 << (SDP_MAX_RTCP_FB_NACK + (type)))
+#define SDP_RTCP_FB_CCM_TO_BITMAP(type)  (1 << (SDP_MAX_RTCP_FB_NACK + \
+                                                SDP_MAX_RTCP_FB_ACK + (type)))
+
 /*
  * sdp_srtp_fec_order_t
  *  This type defines the order in which to perform FEC
  *  (Forward Error Correction) and SRTP Encryption/Authentication.
  */
 typedef enum sdp_srtp_fec_order_t_ {
     SDP_SRTP_THEN_FEC, /* upon sending perform SRTP then FEC */
     SDP_FEC_THEN_SRTP, /* upon sending perform FEC then SRTP */
--- a/media/webrtc/signaling/src/sipcc/core/sdp/sdp_attr.c
+++ b/media/webrtc/signaling/src/sipcc/core/sdp/sdp_attr.c
@@ -4779,17 +4779,17 @@ sdp_result_e sdp_build_attr_rtcp_fb(sdp_
         case SDP_RTCP_FB_CCM: /* RFC 5104 */
             if (attr_p->attr.rtcp_fb.param.ccm < SDP_MAX_RTCP_FB_CCM) {
                 flex_string_sprintf(fs, " %s",
                     sdp_rtcp_fb_ccm_type_val[attr_p->attr.rtcp_fb.param.ccm]
                         .name);
             }
             break;
         case SDP_RTCP_FB_NACK:
-            if (attr_p->attr.rtcp_fb.param.nack > SDP_RTCP_FB_NACK_UNSPECIFIED
+            if (attr_p->attr.rtcp_fb.param.nack > SDP_RTCP_FB_NACK_BASIC
                 && attr_p->attr.rtcp_fb.param.nack < SDP_MAX_RTCP_FB_NACK) {
                 flex_string_sprintf(fs, " %s",
                     sdp_rtcp_fb_nack_type_val[attr_p->attr.rtcp_fb.param.nack]
                         .name);
             }
             break;
         case SDP_RTCP_FB_TRR_INT:
             flex_string_sprintf(fs, " %u", attr_p->attr.rtcp_fb.param.trr_int);
@@ -4930,17 +4930,17 @@ sdp_result_e sdp_parse_attr_rtcp_fb (sdp
         case SDP_RTCP_FB_NACK:
             /* Skip any remaining WS -- see
                http://code.google.com/p/webrtc/issues/detail?id=1922 */
             while (*ptr == ' ' || *ptr == '\t') {
                 ptr++;
             }
             /* Check for empty string */
             if (*ptr == '\r') {
-                rtcp_fb_p->param.nack = SDP_RTCP_FB_NACK_UNSPECIFIED;
+                rtcp_fb_p->param.nack = SDP_RTCP_FB_NACK_BASIC;
                 break;
             }
             i = find_token_enum("rtcp-fb nack type", sdp_p, &ptr,
                                 sdp_rtcp_fb_nack_type_val,
                                 SDP_MAX_RTCP_FB_NACK, SDP_RTCP_FB_NACK_UNKNOWN);
             if (i < 0) {
                 sdp_parse_error(sdp_p->peerconnection,
                   "%s Warning: could not parse nack type for rtcp-fb attribute",
--- a/media/webrtc/signaling/src/sipcc/include/vcm.h
+++ b/media/webrtc/signaling/src/sipcc/include/vcm.h
@@ -180,16 +180,17 @@ typedef struct
       int channels;
       int bitrate;     /* Wire bitrate of RTP packet payloads */
     } audio;
 
     struct
     {
       int width;
       int height;
+      uint32_t rtcp_fb_types;
     } video;
   };
 
   /* Codec-specific parameters */
   union
   {
     struct {
         uint16_t mode;
--- a/media/webrtc/signaling/test/sdp_unittests.cpp
+++ b/media/webrtc/signaling/test/sdp_unittests.cpp
@@ -162,17 +162,17 @@ class SdpTest : public ::testing::Test {
       u16 inst_num = 0;
       EXPECT_EQ(sdp_add_new_attr(sdp_ptr_, level, 0, SDP_ATTR_RTCP_FB,
                                  &inst_num), SDP_SUCCESS);
       EXPECT_EQ(sdp_attr_set_rtcp_fb_nack(sdp_ptr_, level, payload, inst_num,
                                           type), SDP_SUCCESS);
       return inst_num;
     }
 
-    u16 AddNewRtcpTrrInt(int level, u32 interval,
+    u16 AddNewRtcpFbTrrInt(int level, u32 interval,
                          u16 payload = SDP_ALL_PAYLOADS) {
       u16 inst_num = 0;
       EXPECT_EQ(sdp_add_new_attr(sdp_ptr_, level, 0, SDP_ATTR_RTCP_FB,
                                  &inst_num), SDP_SUCCESS);
       EXPECT_EQ(sdp_attr_set_rtcp_fb_trr_int(sdp_ptr_, level, payload, inst_num,
                                              interval), SDP_SUCCESS);
       return inst_num;
     }
@@ -228,17 +228,17 @@ TEST_F(SdpTest, parseRtcpFbAckFooBarBaz)
   ParseSdp(kVideoSdp + "a=rtcp-fb:120 ack foo bar baz\r\n");
   ASSERT_EQ(sdp_attr_get_rtcp_fb_ack(sdp_ptr_, 1, 120, 1),
             SDP_RTCP_FB_ACK_UNKNOWN);
 }
 
 TEST_F(SdpTest, parseRtcpFbNack) {
   ParseSdp(kVideoSdp + "a=rtcp-fb:120 nack\r\n");
   ASSERT_EQ(sdp_attr_get_rtcp_fb_nack(sdp_ptr_, 1, 120, 1),
-            SDP_RTCP_FB_NACK_UNSPECIFIED);
+            SDP_RTCP_FB_NACK_BASIC);
 }
 
 TEST_F(SdpTest, parseRtcpFbNackPli) {
   ParseSdp(kVideoSdp + "a=rtcp-fb:120 nack pli\r\n");
 }
 
 TEST_F(SdpTest, parseRtcpFbNackSli) {
   ParseSdp(kVideoSdp + "a=rtcp-fb:120 nack sli\r\n");
@@ -376,17 +376,17 @@ TEST_F(SdpTest, parseRtcpFbKitchenSink) 
   ASSERT_EQ(sdp_attr_get_rtcp_fb_ack(sdp_ptr_, 1, 120, 4),
             SDP_RTCP_FB_ACK_UNKNOWN);
   ASSERT_EQ(sdp_attr_get_rtcp_fb_ack(sdp_ptr_, 1, 120, 5),
             SDP_RTCP_FB_ACK_UNKNOWN);
   ASSERT_EQ(sdp_attr_get_rtcp_fb_ack(sdp_ptr_, 1, 120, 6),
             SDP_RTCP_FB_ACK_NOT_FOUND);
 
   ASSERT_EQ(sdp_attr_get_rtcp_fb_nack(sdp_ptr_, 1, 120, 1),
-            SDP_RTCP_FB_NACK_UNSPECIFIED);
+            SDP_RTCP_FB_NACK_BASIC);
   ASSERT_EQ(sdp_attr_get_rtcp_fb_nack(sdp_ptr_, 1, 120, 2),
             SDP_RTCP_FB_NACK_PLI);
   ASSERT_EQ(sdp_attr_get_rtcp_fb_nack(sdp_ptr_, 1, 120, 3),
             SDP_RTCP_FB_NACK_SLI);
   ASSERT_EQ(sdp_attr_get_rtcp_fb_nack(sdp_ptr_, 1, 120, 4),
             SDP_RTCP_FB_NACK_RPSI);
   ASSERT_EQ(sdp_attr_get_rtcp_fb_nack(sdp_ptr_, 1, 120, 5),
             SDP_RTCP_FB_NACK_APP);
@@ -417,38 +417,207 @@ TEST_F(SdpTest, parseRtcpFbKitchenSink) 
   ASSERT_EQ(sdp_attr_get_rtcp_fb_ccm(sdp_ptr_, 1, 120, 6),
             SDP_RTCP_FB_CCM_UNKNOWN);
   ASSERT_EQ(sdp_attr_get_rtcp_fb_ccm(sdp_ptr_, 1, 120, 7),
             SDP_RTCP_FB_CCM_UNKNOWN);
   ASSERT_EQ(sdp_attr_get_rtcp_fb_ccm(sdp_ptr_, 1, 120, 8),
             SDP_RTCP_FB_CCM_NOT_FOUND);
 }
 
+TEST_F(SdpTest, addRtcpFbAckRpsi) {
+  InitLocalSdp();
+  int level = AddNewMedia(SDP_MEDIA_VIDEO);
+  AddNewRtcpFbAck(level, SDP_RTCP_FB_ACK_RPSI, 120);
+  std::string body = SerializeSdp();
+  ASSERT_NE(body.find("a=rtcp-fb:120 ack rpsi\r\n"), std::string::npos);
+}
 
-/* TODO (abr@mozilla.com) These attribute adding test cases definitely need
-   beefing up; for now, I'm testing the two use cases that we know
-   we need right now.  An exhaustive check of the various permutations
-   will look similar to the parsing tests, above */
+TEST_F(SdpTest, addRtcpFbAckRpsiAllPt) {
+  InitLocalSdp();
+  int level = AddNewMedia(SDP_MEDIA_VIDEO);
+  AddNewRtcpFbAck(level, SDP_RTCP_FB_ACK_RPSI);
+  std::string body = SerializeSdp();
+  ASSERT_NE(body.find("a=rtcp-fb:* ack rpsi\r\n"), std::string::npos);
+}
+
+TEST_F(SdpTest, addRtcpFbAckApp) {
+  InitLocalSdp();
+  int level = AddNewMedia(SDP_MEDIA_VIDEO);
+  AddNewRtcpFbAck(level, SDP_RTCP_FB_ACK_APP, 120);
+  std::string body = SerializeSdp();
+  ASSERT_NE(body.find("a=rtcp-fb:120 ack app\r\n"), std::string::npos);
+}
+
+TEST_F(SdpTest, addRtcpFbAckAppAllPt) {
+  InitLocalSdp();
+  int level = AddNewMedia(SDP_MEDIA_VIDEO);
+  AddNewRtcpFbAck(level, SDP_RTCP_FB_ACK_APP);
+  std::string body = SerializeSdp();
+  ASSERT_NE(body.find("a=rtcp-fb:* ack app\r\n"), std::string::npos);
+}
 
 TEST_F(SdpTest, addRtcpFbNack) {
   InitLocalSdp();
   int level = AddNewMedia(SDP_MEDIA_VIDEO);
-  AddNewRtcpFbNack(level, SDP_RTCP_FB_NACK_UNSPECIFIED, 120);
+  AddNewRtcpFbNack(level, SDP_RTCP_FB_NACK_BASIC, 120);
   std::string body = SerializeSdp();
   ASSERT_NE(body.find("a=rtcp-fb:120 nack\r\n"), std::string::npos);
 }
 
 TEST_F(SdpTest, addRtcpFbNackAllPt) {
   InitLocalSdp();
   int level = AddNewMedia(SDP_MEDIA_VIDEO);
-  AddNewRtcpFbNack(level, SDP_RTCP_FB_NACK_UNSPECIFIED);
+  AddNewRtcpFbNack(level, SDP_RTCP_FB_NACK_BASIC);
   std::string body = SerializeSdp();
   ASSERT_NE(body.find("a=rtcp-fb:* nack\r\n"), std::string::npos);
 }
 
+TEST_F(SdpTest, addRtcpFbNackSli) {
+  InitLocalSdp();
+  int level = AddNewMedia(SDP_MEDIA_VIDEO);
+  AddNewRtcpFbNack(level, SDP_RTCP_FB_NACK_SLI, 120);
+  std::string body = SerializeSdp();
+  ASSERT_NE(body.find("a=rtcp-fb:120 nack sli\r\n"), std::string::npos);
+}
+
+TEST_F(SdpTest, addRtcpFbNackSliAllPt) {
+  InitLocalSdp();
+  int level = AddNewMedia(SDP_MEDIA_VIDEO);
+  AddNewRtcpFbNack(level, SDP_RTCP_FB_NACK_SLI);
+  std::string body = SerializeSdp();
+  ASSERT_NE(body.find("a=rtcp-fb:* nack sli\r\n"), std::string::npos);
+}
+
+TEST_F(SdpTest, addRtcpFbNackPli) {
+  InitLocalSdp();
+  int level = AddNewMedia(SDP_MEDIA_VIDEO);
+  AddNewRtcpFbNack(level, SDP_RTCP_FB_NACK_PLI, 120);
+  std::string body = SerializeSdp();
+  ASSERT_NE(body.find("a=rtcp-fb:120 nack pli\r\n"), std::string::npos);
+}
+
+TEST_F(SdpTest, addRtcpFbNackPliAllPt) {
+  InitLocalSdp();
+  int level = AddNewMedia(SDP_MEDIA_VIDEO);
+  AddNewRtcpFbNack(level, SDP_RTCP_FB_NACK_PLI);
+  std::string body = SerializeSdp();
+  ASSERT_NE(body.find("a=rtcp-fb:* nack pli\r\n"), std::string::npos);
+}
+
+TEST_F(SdpTest, addRtcpFbNackRpsi) {
+  InitLocalSdp();
+  int level = AddNewMedia(SDP_MEDIA_VIDEO);
+  AddNewRtcpFbNack(level, SDP_RTCP_FB_NACK_RPSI, 120);
+  std::string body = SerializeSdp();
+  ASSERT_NE(body.find("a=rtcp-fb:120 nack rpsi\r\n"), std::string::npos);
+}
+
+TEST_F(SdpTest, addRtcpFbNackRpsiAllPt) {
+  InitLocalSdp();
+  int level = AddNewMedia(SDP_MEDIA_VIDEO);
+  AddNewRtcpFbNack(level, SDP_RTCP_FB_NACK_RPSI);
+  std::string body = SerializeSdp();
+  ASSERT_NE(body.find("a=rtcp-fb:* nack rpsi\r\n"), std::string::npos);
+}
+
+TEST_F(SdpTest, addRtcpFbNackApp) {
+  InitLocalSdp();
+  int level = AddNewMedia(SDP_MEDIA_VIDEO);
+  AddNewRtcpFbNack(level, SDP_RTCP_FB_NACK_APP, 120);
+  std::string body = SerializeSdp();
+  ASSERT_NE(body.find("a=rtcp-fb:120 nack app\r\n"), std::string::npos);
+}
+
+TEST_F(SdpTest, addRtcpFbNackAppAllPt) {
+  InitLocalSdp();
+  int level = AddNewMedia(SDP_MEDIA_VIDEO);
+  AddNewRtcpFbNack(level, SDP_RTCP_FB_NACK_APP);
+  std::string body = SerializeSdp();
+  ASSERT_NE(body.find("a=rtcp-fb:* nack app\r\n"), std::string::npos);
+}
+
+TEST_F(SdpTest, addRtcpFbNackRai) {
+  InitLocalSdp();
+  int level = AddNewMedia(SDP_MEDIA_VIDEO);
+  AddNewRtcpFbNack(level, SDP_RTCP_FB_NACK_RAI, 120);
+  std::string body = SerializeSdp();
+  ASSERT_NE(body.find("a=rtcp-fb:120 nack rai\r\n"), std::string::npos);
+}
+
+TEST_F(SdpTest, addRtcpFbNackRaiAllPt) {
+  InitLocalSdp();
+  int level = AddNewMedia(SDP_MEDIA_VIDEO);
+  AddNewRtcpFbNack(level, SDP_RTCP_FB_NACK_RAI);
+  std::string body = SerializeSdp();
+  ASSERT_NE(body.find("a=rtcp-fb:* nack rai\r\n"), std::string::npos);
+}
+
+TEST_F(SdpTest, addRtcpFbNackTllei) {
+  InitLocalSdp();
+  int level = AddNewMedia(SDP_MEDIA_VIDEO);
+  AddNewRtcpFbNack(level, SDP_RTCP_FB_NACK_TLLEI, 120);
+  std::string body = SerializeSdp();
+  ASSERT_NE(body.find("a=rtcp-fb:120 nack tllei\r\n"), std::string::npos);
+}
+
+TEST_F(SdpTest, addRtcpFbNackTlleiAllPt) {
+  InitLocalSdp();
+  int level = AddNewMedia(SDP_MEDIA_VIDEO);
+  AddNewRtcpFbNack(level, SDP_RTCP_FB_NACK_TLLEI);
+  std::string body = SerializeSdp();
+  ASSERT_NE(body.find("a=rtcp-fb:* nack tllei\r\n"), std::string::npos);
+}
+
+TEST_F(SdpTest, addRtcpFbNackPslei) {
+  InitLocalSdp();
+  int level = AddNewMedia(SDP_MEDIA_VIDEO);
+  AddNewRtcpFbNack(level, SDP_RTCP_FB_NACK_PSLEI, 120);
+  std::string body = SerializeSdp();
+  ASSERT_NE(body.find("a=rtcp-fb:120 nack pslei\r\n"), std::string::npos);
+}
+
+TEST_F(SdpTest, addRtcpFbNackPsleiAllPt) {
+  InitLocalSdp();
+  int level = AddNewMedia(SDP_MEDIA_VIDEO);
+  AddNewRtcpFbNack(level, SDP_RTCP_FB_NACK_PSLEI);
+  std::string body = SerializeSdp();
+  ASSERT_NE(body.find("a=rtcp-fb:* nack pslei\r\n"), std::string::npos);
+}
+
+TEST_F(SdpTest, addRtcpFbNackEcn) {
+  InitLocalSdp();
+  int level = AddNewMedia(SDP_MEDIA_VIDEO);
+  AddNewRtcpFbNack(level, SDP_RTCP_FB_NACK_ECN, 120);
+  std::string body = SerializeSdp();
+  ASSERT_NE(body.find("a=rtcp-fb:120 nack ecn\r\n"), std::string::npos);
+}
+
+TEST_F(SdpTest, addRtcpFbNackEcnAllPt) {
+  InitLocalSdp();
+  int level = AddNewMedia(SDP_MEDIA_VIDEO);
+  AddNewRtcpFbNack(level, SDP_RTCP_FB_NACK_ECN);
+  std::string body = SerializeSdp();
+  ASSERT_NE(body.find("a=rtcp-fb:* nack ecn\r\n"), std::string::npos);
+}
+
+TEST_F(SdpTest, addRtcpFbTrrInt) {
+  InitLocalSdp();
+  int level = AddNewMedia(SDP_MEDIA_VIDEO);
+  AddNewRtcpFbTrrInt(level, 12345, 120);
+  std::string body = SerializeSdp();
+  ASSERT_NE(body.find("a=rtcp-fb:120 trr-int 12345\r\n"), std::string::npos);
+}
+
+TEST_F(SdpTest, addRtcpFbNackTrrIntAllPt) {
+  InitLocalSdp();
+  int level = AddNewMedia(SDP_MEDIA_VIDEO);
+  AddNewRtcpFbTrrInt(level, 0);
+  std::string body = SerializeSdp();
+  ASSERT_NE(body.find("a=rtcp-fb:* trr-int 0\r\n"), std::string::npos);
+}
 
 TEST_F(SdpTest, addRtcpFbCcmFir) {
   InitLocalSdp();
   int level = AddNewMedia(SDP_MEDIA_VIDEO);
   AddNewRtcpFbCcm(level, SDP_RTCP_FB_CCM_FIR, 120);
   std::string body = SerializeSdp();
   ASSERT_NE(body.find("a=rtcp-fb:120 ccm fir\r\n"), std::string::npos);
 }
@@ -456,17 +625,71 @@ TEST_F(SdpTest, addRtcpFbCcmFir) {
 TEST_F(SdpTest, addRtcpFbCcmFirAllPt) {
   InitLocalSdp();
   int level = AddNewMedia(SDP_MEDIA_VIDEO);
   AddNewRtcpFbCcm(level, SDP_RTCP_FB_CCM_FIR);
   std::string body = SerializeSdp();
   ASSERT_NE(body.find("a=rtcp-fb:* ccm fir\r\n"), std::string::npos);
 }
 
-/* TODO We need to test the pt=* use cases. */
+TEST_F(SdpTest, addRtcpFbCcmTmmbr) {
+  InitLocalSdp();
+  int level = AddNewMedia(SDP_MEDIA_VIDEO);
+  AddNewRtcpFbCcm(level, SDP_RTCP_FB_CCM_TMMBR, 120);
+  std::string body = SerializeSdp();
+  ASSERT_NE(body.find("a=rtcp-fb:120 ccm tmmbr\r\n"), std::string::npos);
+}
+
+TEST_F(SdpTest, addRtcpFbCcmTmmbrAllPt) {
+  InitLocalSdp();
+  int level = AddNewMedia(SDP_MEDIA_VIDEO);
+  AddNewRtcpFbCcm(level, SDP_RTCP_FB_CCM_TMMBR);
+  std::string body = SerializeSdp();
+  ASSERT_NE(body.find("a=rtcp-fb:* ccm tmmbr\r\n"), std::string::npos);
+}
+
+TEST_F(SdpTest, addRtcpFbCcmTstr) {
+  InitLocalSdp();
+  int level = AddNewMedia(SDP_MEDIA_VIDEO);
+  AddNewRtcpFbCcm(level, SDP_RTCP_FB_CCM_TSTR, 120);
+  std::string body = SerializeSdp();
+  ASSERT_NE(body.find("a=rtcp-fb:120 ccm tstr\r\n"), std::string::npos);
+}
+
+TEST_F(SdpTest, addRtcpFbCcmTstrAllPt) {
+  InitLocalSdp();
+  int level = AddNewMedia(SDP_MEDIA_VIDEO);
+  AddNewRtcpFbCcm(level, SDP_RTCP_FB_CCM_TSTR);
+  std::string body = SerializeSdp();
+  ASSERT_NE(body.find("a=rtcp-fb:* ccm tstr\r\n"), std::string::npos);
+}
+
+TEST_F(SdpTest, addRtcpFbCcmVbcm) {
+  InitLocalSdp();
+  int level = AddNewMedia(SDP_MEDIA_VIDEO);
+  AddNewRtcpFbCcm(level, SDP_RTCP_FB_CCM_VBCM, 120);
+  std::string body = SerializeSdp();
+  ASSERT_NE(body.find("a=rtcp-fb:120 ccm vbcm\r\n"), std::string::npos);
+}
+
+TEST_F(SdpTest, addRtcpFbCcmVbcmAllPt) {
+  InitLocalSdp();
+  int level = AddNewMedia(SDP_MEDIA_VIDEO);
+  AddNewRtcpFbCcm(level, SDP_RTCP_FB_CCM_VBCM);
+  std::string body = SerializeSdp();
+  ASSERT_NE(body.find("a=rtcp-fb:* ccm vbcm\r\n"), std::string::npos);
+}
+
+TEST_F(SdpTest, parseRtcpFbAllPayloads) {
+  ParseSdp(kVideoSdp + "a=rtcp-fb:* ack rpsi\r\n");
+  for (int i = 0; i < 128; i++) {
+    ASSERT_EQ(sdp_attr_get_rtcp_fb_ack(sdp_ptr_, 1, i, 1),
+              SDP_RTCP_FB_ACK_RPSI);
+  }
+}
 
 } // End namespace test.
 
 int main(int argc, char **argv) {
   test_utils = new MtransportTestUtils();
   NSS_NoDB_Init(NULL);
   NSS_SetDomesticPolicy();
 
--- a/media/webrtc/signaling/test/signaling_unittests.cpp
+++ b/media/webrtc/signaling/test/signaling_unittests.cpp
@@ -1880,16 +1880,18 @@ TEST_F(SignalingTest, ChromeOfferAnswer)
     "a=sendrecv\r\n"
     "a=mid:video\r\n"
     "a=rtcp-mux\r\n"
     "a=crypto:1 AES_CM_128_HMAC_SHA1_80 inline:"
       "RzrYlzpkTsvgYFD1hQqNCzQ7y4emNLKI1tODsjim\r\n"
     "a=rtpmap:100 VP8/90000\r\n"
     "a=rtpmap:101 red/90000\r\n"
     "a=rtpmap:102 ulpfec/90000\r\n"
+    "a=rtcp-fb:100 nack\r\n"
+    "a=rtcp-fb:100 ccm fir\r\n"
     "a=ssrc:3012607008 cname:KIXaNxUlU5DP3fVS\r\n"
     "a=ssrc:3012607008 msid:A5UL339RyGxT7zwgyF12BFqesxkmbUsaycp5 v0\r\n"
     "a=ssrc:3012607008 mslabel:A5UL339RyGxT7zwgyF12BFqesxkmbUsaycp5\r\n"
     "a=ssrc:3012607008 label:A5UL339RyGxT7zwgyF12BFqesxkmbUsaycp5v0\r\n";
 
 
   std::cout << "Setting offer to:" << std::endl << indent(offer) << std::endl;
   a2_.SetRemote(TestObserver::OFFER, offer);
--- a/mobile/android/base/GeckoEvent.java
+++ b/mobile/android/base/GeckoEvent.java
@@ -61,17 +61,20 @@ public class GeckoEvent {
         COMPOSITOR_CREATE(28),
         COMPOSITOR_PAUSE(29),
         COMPOSITOR_RESUME(30),
         NATIVE_GESTURE_EVENT(31),
         IME_KEY_EVENT(32),
         CALL_OBSERVER(33),
         REMOVE_OBSERVER(34),
         LOW_MEMORY(35),
-        NETWORK_LINK_CHANGE(36);
+        NETWORK_LINK_CHANGE(36),
+        TELEMETRY_HISTOGRAM_ADD(37),
+        PREFERENCES_OBSERVE(38),
+        PREFERENCES_GET(39);
 
         public final int value;
 
         private NativeGeckoEvent(int value) {
             this.value = value;
          }
     }
 
@@ -180,16 +183,18 @@ public class GeckoEvent {
 
     private short mScreenOrientation;
 
     private ByteBuffer mBuffer;
 
     private int mWidth;
     private int mHeight;
 
+    private String[] mPrefNames;
+
     private GeckoEvent(NativeGeckoEvent event) {
         mType = event.value;
     }
 
     public static GeckoEvent createAppBackgroundingEvent() {
         return new GeckoEvent(NativeGeckoEvent.APP_BACKGROUNDING);
     }
 
@@ -683,24 +688,46 @@ public class GeckoEvent {
     }
 
     public static GeckoEvent createRemoveObserverEvent(String observerKey) {
         GeckoEvent event = new GeckoEvent(NativeGeckoEvent.REMOVE_OBSERVER);
         event.mCharacters = observerKey;
         return event;
     }
 
+    public static GeckoEvent createPreferencesObserveEvent(int requestId, String[] prefNames) {
+        GeckoEvent event = new GeckoEvent(NativeGeckoEvent.PREFERENCES_OBSERVE);
+        event.mCount = requestId;
+        event.mPrefNames = prefNames;
+        return event;
+    }
+
+    public static GeckoEvent createPreferencesGetEvent(int requestId, String[] prefNames) {
+        GeckoEvent event = new GeckoEvent(NativeGeckoEvent.PREFERENCES_GET);
+        event.mCount = requestId;
+        event.mPrefNames = prefNames;
+        return event;
+    }
+
     public static GeckoEvent createLowMemoryEvent(int level) {
         GeckoEvent event = new GeckoEvent(NativeGeckoEvent.LOW_MEMORY);
         event.mMetaState = level;
         return event;
     }
 
     public static GeckoEvent createNetworkLinkChangeEvent(String status) {
         GeckoEvent event = new GeckoEvent(NativeGeckoEvent.NETWORK_LINK_CHANGE);
         event.mCharacters = status;
         return event;
     }
 
+    public static GeckoEvent createTelemetryHistogramAddEvent(String histogram,
+                                                              int value) {
+        GeckoEvent event = new GeckoEvent(NativeGeckoEvent.TELEMETRY_HISTOGRAM_ADD);
+        event.mCharacters = histogram;
+        event.mCount = value;
+        return event;
+    }
+
     public void setAckNeeded(boolean ackNeeded) {
         mAckNeeded = ackNeeded;
     }
 }
--- a/mobile/android/base/GeckoPreferences.java
+++ b/mobile/android/base/GeckoPreferences.java
@@ -659,19 +659,17 @@ public class GeckoPreferences
                 return null;
         }
 
         return dialog;
     }
 
     // Initialize preferences by requesting the preference values from Gecko
     private int getGeckoPreferences(final PreferenceGroup screen, ArrayList<String> prefs) {
-        JSONArray jsonPrefs = new JSONArray(prefs);
-
-        return PrefsHelper.getPrefs(jsonPrefs, new PrefsHelper.PrefHandlerBase() {
+        return PrefsHelper.getPrefs(prefs, new PrefsHelper.PrefHandlerBase() {
             private Preference getField(String prefName) {
                 return screen.findPreference(prefName);
             }
 
             // Handle v14 TwoStatePreference with backwards compatibility.
             class CheckBoxPrefSetter {
                 public void setBooleanPref(Preference preference, boolean value) {
                     if ((preference instanceof CheckBoxPreference) &&
--- a/mobile/android/base/PrefsHelper.java
+++ b/mobile/android/base/PrefsHelper.java
@@ -8,72 +8,58 @@ package org.mozilla.gecko;
 import org.mozilla.gecko.util.GeckoEventListener;
 
 import org.json.JSONArray;
 import org.json.JSONException;
 import org.json.JSONObject;
 
 import android.util.Log;
 
+import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.Map;
 
 /**
  * Helper class to get/set gecko prefs.
  */
 public final class PrefsHelper {
     private static final String LOGTAG = "GeckoPrefsHelper";
 
     private static boolean sRegistered = false;
     private static final Map<Integer, PrefHandler> sCallbacks = new HashMap<Integer, PrefHandler>();
     private static int sUniqueRequestId = 1;
 
     public static int getPref(String prefName, PrefHandler callback) {
-        JSONArray prefs = new JSONArray();
-        prefs.put(prefName);
-        return getPrefs(prefs, callback);
+        return getPrefsInternal(new String[] { prefName }, callback);
     }
 
     public static int getPrefs(String[] prefNames, PrefHandler callback) {
-        JSONArray prefs = new JSONArray();
-        for (String p : prefNames) {
-            prefs.put(p);
-        }
-        return getPrefs(prefs, callback);
+        return getPrefsInternal(prefNames, callback);
     }
 
-    public static int getPrefs(JSONArray prefNames, PrefHandler callback) {
+    public static int getPrefs(ArrayList<String> prefNames, PrefHandler callback) {
+        return getPrefsInternal(prefNames.toArray(new String[prefNames.size()]), callback);
+    }
+
+    private static int getPrefsInternal(String[] prefNames, PrefHandler callback) {
         int requestId;
         synchronized (PrefsHelper.class) {
             ensureRegistered();
 
             requestId = sUniqueRequestId++;
             sCallbacks.put(requestId, callback);
         }
 
         GeckoEvent event;
-        try {
-            JSONObject message = new JSONObject();
-            message.put("requestId", Integer.toString(requestId));
-            message.put("preferences", prefNames);
-            event = GeckoEvent.createBroadcastEvent(callback.isObserver() ?
-                "Preferences:Observe" : "Preferences:Get", message.toString());
-            GeckoAppShell.sendEventToGecko(event);
-        } catch (Exception e) {
-            Log.e(LOGTAG, "Error while composing Preferences:" +
-                  (callback.isObserver() ? "Observe" : "Get") + " message", e);
-
-            // if we failed to send the message, drop our reference to the callback because
-            // otherwise it will leak since we will never get the response
-            synchronized (PrefsHelper.class) {
-                sCallbacks.remove(requestId);
-            }
-
-            return -1;
+        if (callback.isObserver()) {
+            event = GeckoEvent.createPreferencesObserveEvent(requestId, prefNames);
+        } else {
+            event = GeckoEvent.createPreferencesGetEvent(requestId, prefNames);
         }
+        GeckoAppShell.sendEventToGecko(event);
 
         return requestId;
     }
 
     private static void ensureRegistered() {
         if (sRegistered) {
             return;
         }
--- a/mobile/android/base/RobocopAPI.java
+++ b/mobile/android/base/RobocopAPI.java
@@ -30,16 +30,24 @@ public class RobocopAPI {
     public void unregisterEventListener(String event, GeckoEventListener listener) {
         GeckoAppShell.unregisterEventListener(event, listener);
     }
 
     public void broadcastEvent(String subject, String data) {
         GeckoAppShell.sendEventToGecko(GeckoEvent.createBroadcastEvent(subject, data));
     }
 
+    public void preferencesGetEvent(int requestId, String[] prefNames) {
+        GeckoAppShell.sendEventToGecko(GeckoEvent.createPreferencesGetEvent(requestId, prefNames));
+    }
+
+    public void preferencesObserveEvent(int requestId, String[] prefNames) {
+        GeckoAppShell.sendEventToGecko(GeckoEvent.createPreferencesObserveEvent(requestId, prefNames));
+    }
+
     public void setDrawListener(GeckoLayerClient.DrawListener listener) {
         GeckoAppShell.getLayerView().getLayerClient().setDrawListener(listener);
     }
 
     public Cursor querySql(String dbPath, String query) {
         GeckoLoader.loadSQLiteLibs(mGeckoApp, mGeckoApp.getApplication().getPackageResourcePath());
         return new SQLiteBridge(dbPath).rawQuery(query, null);
     }
--- a/mobile/android/base/Telemetry.java
+++ b/mobile/android/base/Telemetry.java
@@ -1,40 +1,28 @@
 /* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 package org.mozilla.gecko;
 
-import org.json.JSONException;
-import org.json.JSONObject;
-
 import android.os.SystemClock;
 import android.util.Log;
 
 public class Telemetry {
     private static final String LOGTAG = "Telemetry";
 
     // Define new histograms in:
     // toolkit/components/telemetry/Histograms.json
     public static void HistogramAdd(String name,
                                     int value) {
-        try {
-            JSONObject jsonData = new JSONObject();
-
-            jsonData.put("name", name);
-            jsonData.put("value", value);
-
-            GeckoEvent event =
-                GeckoEvent.createBroadcastEvent("Telemetry:Add", jsonData.toString());
-            GeckoAppShell.sendEventToGecko(event);
-        } catch (JSONException e) {
-            Log.e(LOGTAG, "JSON exception: ", e);
-        }
+        GeckoEvent event =
+            GeckoEvent.createTelemetryHistogramAddEvent(name, value);
+        GeckoAppShell.sendEventToGecko(event);
     }
 
     public static class Timer {
         private long mStartTime;
         private String mName;
         private boolean mHasFinished;
         private volatile long mElapsed = -1;
 
--- a/mobile/android/base/gfx/Axis.java
+++ b/mobile/android/base/gfx/Axis.java
@@ -59,23 +59,22 @@ abstract class Axis {
     }
 
     private static int getIntPref(Map<String, Integer> prefs, String prefName, int defaultValue) {
         Integer value = (prefs == null ? null : prefs.get(prefName));
         return (value == null || value < 0 ? defaultValue : value);
     }
 
     static void initPrefs() {
-        JSONArray prefs = new JSONArray();
-        prefs.put(PREF_SCROLLING_FRICTION_FAST);
-        prefs.put(PREF_SCROLLING_FRICTION_SLOW);
-        prefs.put(PREF_SCROLLING_MAX_EVENT_ACCELERATION);
-        prefs.put(PREF_SCROLLING_OVERSCROLL_DECEL_RATE);
-        prefs.put(PREF_SCROLLING_OVERSCROLL_SNAP_LIMIT);
-        prefs.put(PREF_SCROLLING_MIN_SCROLLABLE_DISTANCE);
+        final String[] prefs = { PREF_SCROLLING_FRICTION_FAST,
+                                 PREF_SCROLLING_FRICTION_SLOW,
+                                 PREF_SCROLLING_MAX_EVENT_ACCELERATION,
+                                 PREF_SCROLLING_OVERSCROLL_DECEL_RATE,
+                                 PREF_SCROLLING_OVERSCROLL_SNAP_LIMIT,
+                                 PREF_SCROLLING_MIN_SCROLLABLE_DISTANCE };
 
         PrefsHelper.getPrefs(prefs, new PrefsHelper.PrefHandlerBase() {
             Map<String, Integer> mPrefs = new HashMap<String, Integer>();
 
             @Override public void prefValue(String name, int value) {
                 mPrefs.put(name, value);
             }
 
--- a/mobile/android/base/gfx/DisplayPortCalculator.java
+++ b/mobile/android/base/gfx/DisplayPortCalculator.java
@@ -56,29 +56,28 @@ final class DisplayPortCalculator {
         return sStrategy.drawTimeUpdate(millis, pixels);
     }
 
     static void resetPageState() {
         sStrategy.resetPageState();
     }
 
     static void initPrefs() {
-        JSONArray prefs = new JSONArray();
-        prefs.put(PREF_DISPLAYPORT_STRATEGY);
-        prefs.put(PREF_DISPLAYPORT_FM_MULTIPLIER);
-        prefs.put(PREF_DISPLAYPORT_FM_DANGER_X);
-        prefs.put(PREF_DISPLAYPORT_FM_DANGER_Y);
-        prefs.put(PREF_DISPLAYPORT_VB_MULTIPLIER);
-        prefs.put(PREF_DISPLAYPORT_VB_VELOCITY_THRESHOLD);
-        prefs.put(PREF_DISPLAYPORT_VB_REVERSE_BUFFER);
-        prefs.put(PREF_DISPLAYPORT_VB_DANGER_X_BASE);
-        prefs.put(PREF_DISPLAYPORT_VB_DANGER_Y_BASE);
-        prefs.put(PREF_DISPLAYPORT_VB_DANGER_X_INCR);
-        prefs.put(PREF_DISPLAYPORT_VB_DANGER_Y_INCR);
-        prefs.put(PREF_DISPLAYPORT_PB_VELOCITY_THRESHOLD);
+        final String[] prefs = { PREF_DISPLAYPORT_STRATEGY,
+                                 PREF_DISPLAYPORT_FM_MULTIPLIER,
+                                 PREF_DISPLAYPORT_FM_DANGER_X,
+                                 PREF_DISPLAYPORT_FM_DANGER_Y,
+                                 PREF_DISPLAYPORT_VB_MULTIPLIER,
+                                 PREF_DISPLAYPORT_VB_VELOCITY_THRESHOLD,
+                                 PREF_DISPLAYPORT_VB_REVERSE_BUFFER,
+                                 PREF_DISPLAYPORT_VB_DANGER_X_BASE,
+                                 PREF_DISPLAYPORT_VB_DANGER_Y_BASE,
+                                 PREF_DISPLAYPORT_VB_DANGER_X_INCR,
+                                 PREF_DISPLAYPORT_VB_DANGER_Y_INCR,
+                                 PREF_DISPLAYPORT_PB_VELOCITY_THRESHOLD };
 
         PrefsHelper.getPrefs(prefs, new PrefsHelper.PrefHandlerBase() {
             private Map<String, Integer> mValues = new HashMap<String, Integer>();
 
             @Override public void prefValue(String pref, int value) {
                 mValues.put(pref, value);
             }
 
--- a/mobile/android/base/tests/testAddonManager.java.in
+++ b/mobile/android/base/tests/testAddonManager.java.in
@@ -54,31 +54,28 @@ public class testAddonManager extends Pi
         JSONObject jsonPref = new JSONObject();
         try {
             jsonPref.put("name", "extensions.getAddons.browseAddons");
             jsonPref.put("type", "string");
             jsonPref.put("value", getAbsoluteUrl("/robocop/robocop_blank_01.html"));
             mActions.sendGeckoEvent("Preferences:Set", jsonPref.toString());
 
             // Wait for confirmation of the pref change before proceeding with the test.
-            JSONArray getPrefData = new JSONArray();
-            getPrefData.put("extensions.getAddons.browseAddons");
-            JSONObject message = new JSONObject();
-            message.put("requestId", "testAddonManager");
-            message.put("preferences", getPrefData);
+            final String[] prefNames = { "extensions.getAddons.browseAddons" };
+            final int ourRequestId = 0x7357;
             Actions.RepeatedEventExpecter eventExpecter = mActions.expectGeckoEvent("Preferences:Data");
-            mActions.sendGeckoEvent("Preferences:Get", message.toString());
+            mActions.sendPreferencesGetEvent(ourRequestId, prefNames);
 
             JSONObject data = null;
-            String requestId = "";
+            int requestId = -1;
 
             // Wait until we get the correct "Preferences:Data" event
-            while (!requestId.equals("testAddonManager")) {
+            while (requestId != ourRequestId) {
                 data = new JSONObject(eventExpecter.blockForEventData());
-                requestId = data.getString("requestId");
+                requestId = data.getInt("requestId");
             }
             eventExpecter.unregisterListener();
 
         } catch (Exception ex) { 
             mAsserter.ok(false, "exception in testAddonManager", ex.toString());
         }
 
         // Load AMO page by clicking the AMO icon
--- a/mobile/android/base/tests/testDistribution.java.in
+++ b/mobile/android/base/tests/testDistribution.java.in
@@ -24,17 +24,17 @@ import org.json.JSONObject;
  *     preferences.json
  *     bookmarks.json
  *     searchplugins/
  *       common/
  *         engine.xml
  */
 public class testDistribution extends ContentProviderTest {
     private static final String MOCK_PACKAGE = "mock-package.zip";
-    private static final String PREF_REQUEST_ID = "testDistribution";
+    private static final int PREF_REQUEST_ID = 0x7357;
 
     private Activity mActivity;
 
     @Override
     protected int getTestType() {
         return TEST_MOCHITEST;
     }
 
@@ -81,38 +81,33 @@ public class testDistribution extends Co
         String prefID = "distribution.id";
         String prefAbout = "distribution.about";
         String prefVersion = "distribution.version";
         String prefTestBoolean = "distribution.test.boolean";
         String prefTestString = "distribution.test.string";
         String prefTestInt = "distribution.test.int";
 
         try {
-            JSONArray getPrefData = new JSONArray();
-            getPrefData.put(prefID);
-            getPrefData.put(prefAbout);
-            getPrefData.put(prefVersion);
-            getPrefData.put(prefTestBoolean);
-            getPrefData.put(prefTestString);
-            getPrefData.put(prefTestInt);
-
-            JSONObject message = new JSONObject();
-            message.put("requestId", PREF_REQUEST_ID);
-            message.put("preferences", getPrefData);
+            final String[] prefNames = { prefID,
+                                         prefAbout,
+                                         prefVersion,
+                                         prefTestBoolean,
+                                         prefTestString,
+                                         prefTestInt };
 
             Actions.RepeatedEventExpecter eventExpecter = mActions.expectGeckoEvent("Preferences:Data");
-            mActions.sendGeckoEvent("Preferences:Get", message.toString());
+            mActions.sendPreferencesGetEvent(PREF_REQUEST_ID, prefNames);
 
             JSONObject data = null;
-            String requestId = "";
+            int requestId = -1;
 
             // Wait until we get the correct "Preferences:Data" event
-            while (!requestId.equals(PREF_REQUEST_ID)) {
+            while (requestId != PREF_REQUEST_ID) {
                 data = new JSONObject(eventExpecter.blockForEventData());
-                requestId = data.getString("requestId");
+                requestId = data.getInt("requestId");
             }
             eventExpecter.unregisterListener();
 
             JSONArray preferences = data.getJSONArray("preferences");
             for (int i = 0; i < preferences.length(); i++) {
                 JSONObject pref = (JSONObject) preferences.get(i);
                 String name = pref.getString("name");
 
@@ -167,67 +162,55 @@ public class testDistribution extends Co
         try {
             // Request the pref change to the locale.
             jsonPref.put("name", prefUseragentLocale);
             jsonPref.put("type", "string");
             jsonPref.put("value", aLocale);
             mActions.sendGeckoEvent("Preferences:Set", jsonPref.toString());
 
             // Wait for confirmation of the pref change.
-            JSONArray getPrefData = new JSONArray();
-            getPrefData.put(prefUseragentLocale);
-
-            JSONObject message = new JSONObject();
-            message.put("requestId", PREF_REQUEST_ID);
-            message.put("preferences", getPrefData);
+            final String[] prefNames = { prefUseragentLocale };
 
             Actions.RepeatedEventExpecter eventExpecter = mActions.expectGeckoEvent("Preferences:Data");
-            mActions.sendGeckoEvent("Preferences:Get", message.toString());
+            mActions.sendPreferencesGetEvent(PREF_REQUEST_ID, prefNames);
 
             JSONObject data = null;
-            String requestId = "";
+            int requestId = -1;
 
             // Wait until we get the correct "Preferences:Data" event
-            while (!requestId.equals(PREF_REQUEST_ID)) {
+            while (requestId != PREF_REQUEST_ID) {
                 data = new JSONObject(eventExpecter.blockForEventData());
-                requestId = data.getString("requestId");
+                requestId = data.getInt("requestId");
             }
             eventExpecter.unregisterListener();
 
         } catch (Exception e) {
             mAsserter.ok(false, "exception setting test locale", e.toString());
         }
     }
 
     // Test localized distribution and preferences values stored in preferences.json
     private void checkLocalizedPreferences(String aLocale) {
         String prefAbout = "distribution.about";
         String prefLocalizeable = "distribution.test.localizeable";
         String prefLocalizeableOverride = "distribution.test.localizeable-override";
 
         try {
-            JSONArray getPrefData = new JSONArray();
-            getPrefData.put(prefAbout);
-            getPrefData.put(prefLocalizeable);
-            getPrefData.put(prefLocalizeableOverride);
-
-            JSONObject message = new JSONObject();
-            message.put("requestId", PREF_REQUEST_ID);
-            message.put("preferences", getPrefData);
+            final String[] prefNames = { prefAbout, prefLocalizeable, prefLocalizeableOverride };
 
             Actions.RepeatedEventExpecter eventExpecter = mActions.expectGeckoEvent("Preferences:Data");
-            mActions.sendGeckoEvent("Preferences:Get", message.toString());
+            mActions.sendPreferencesGetEvent(PREF_REQUEST_ID, prefNames);
 
             JSONObject data = null;
-            String requestId = "";
+            int requestId = -1;
 
             // Wait until we get the correct "Preferences:Data" event
-            while (!requestId.equals(PREF_REQUEST_ID)) {
+            while (requestId != PREF_REQUEST_ID) {
                 data = new JSONObject(eventExpecter.blockForEventData());
-                requestId = data.getString("requestId");
+                requestId = data.getInt("requestId");
             }
             eventExpecter.unregisterListener();
 
             JSONArray preferences = data.getJSONArray("preferences");
             for (int i = 0; i < preferences.length(); i++) {
                 JSONObject pref = (JSONObject) preferences.get(i);
                 String name = pref.getString("name");
 
--- a/mobile/android/base/tests/testDoorHanger.java.in
+++ b/mobile/android/base/tests/testDoorHanger.java.in
@@ -76,32 +76,29 @@ public class testDoorHanger extends Base
         // Make sure doorhanger is hidden
         mAsserter.is(mSolo.searchText(GEO_MESSAGE), false, "Geolocation doorhanger notification is hidden when opening a new tab");
         */
 
 
         boolean offlineAllowedByDefault = true;
         try {
             // Save offline-allow-by-default preferences first
-            JSONArray getPrefData = new JSONArray();
-            getPrefData.put("offline-apps.allow_by_default");
-            JSONObject message = new JSONObject();
-            message.put("requestId", "testDoorHanger");
-            message.put("preferences", getPrefData);
+            final String[] prefNames = { "offline-apps.allow_by_default" };
+            final int ourRequestId = 0x7357;
 
             Actions.RepeatedEventExpecter eventExpecter = mActions.expectGeckoEvent("Preferences:Data");
-            mActions.sendGeckoEvent("Preferences:Get", message.toString());
+            mActions.sendPreferencesGetEvent(ourRequestId, prefNames);
 
             JSONObject data = null;
-            String requestId = "";
+            int requestId = -1;
 
             // Wait until we get the correct "Preferences:Data" event
-            while (!requestId.equals("testDoorHanger")) {
+            while (requestId != ourRequestId) {
                 data = new JSONObject(eventExpecter.blockForEventData());
-                requestId = data.getString("requestId");
+                requestId = data.getInt("requestId");
             }
             eventExpecter.unregisterListener();
 
             JSONArray preferences = data.getJSONArray("preferences");
             if (preferences.length() > 0) {
                 JSONObject pref = (JSONObject) preferences.get(0);
                 offlineAllowedByDefault = pref.getBoolean("value");
             }
--- a/mobile/android/base/tests/testPasswordEncrypt.java.in
+++ b/mobile/android/base/tests/testPasswordEncrypt.java.in
@@ -121,31 +121,28 @@ public class testPasswordEncrypt extends
         JSONObject jsonPref = new JSONObject();
         try {
             jsonPref.put("name", "privacy.masterpassword.enabled");
             jsonPref.put("type", "string");
             jsonPref.put("value", passwd);
             mActions.sendGeckoEvent("Preferences:Set", jsonPref.toString());
 
             // Wait for confirmation of the pref change before proceeding with the test.
-            JSONArray getPrefData = new JSONArray();
-            getPrefData.put("privacy.masterpassword.enabled");
-            JSONObject message = new JSONObject();
-            message.put("requestId", "testPasswordEncrypt");
-            message.put("preferences", getPrefData);
+            final String[] prefNames = { "privacy.masterpassword.enabled" };
+            final int ourRequestId = 0x73577;
             Actions.RepeatedEventExpecter eventExpecter = mActions.expectGeckoEvent("Preferences:Data");
-            mActions.sendGeckoEvent("Preferences:Get", message.toString());
+            mActions.sendPreferencesGetEvent(ourRequestId, prefNames);
 
             JSONObject data = null;
-            String requestId = "";
+            int requestId = -1;
 
             // Wait until we get the correct "Preferences:Data" event
-            while (!requestId.equals("testPasswordEncrypt")) {
+            while (requestId != ourRequestId) {
                 data = new JSONObject(eventExpecter.blockForEventData());
-                requestId = data.getString("requestId");
+                requestId = data.getInt("requestId");
             }
         } catch (Exception ex) { 
             mAsserter.ok(false, "exception in toggleMasterPassword", ex.toString());
         }
     }
 
     @Override
     public void tearDown() throws Exception {
--- a/mobile/android/base/tests/testPrefsObserver.java.in
+++ b/mobile/android/base/tests/testPrefsObserver.java.in
@@ -11,16 +11,17 @@ import org.json.JSONObject;
 /**
  * Basic test to check bounce-back from overscroll.
  * - Load the page and verify it draws
  * - Drag page downwards by 100 pixels into overscroll, verify it snaps back.
  * - Drag page rightwards by 100 pixels into overscroll, verify it snaps back.
  */
 public class testPrefsObserver extends BaseTest {
     private static final String PREF_TEST_PREF = "robocop.tests.dummy";
+    private static final int PREF_OBSERVE_REQUEST_ID = 0x7357;
     private static final String PREF_REQUEST_ID = "testPrefsObserver";
     private static final long PREF_TIMEOUT = 10000;
 
     private Actions.RepeatedEventExpecter mExpecter;
 
     @Override
     protected int getTestType() {
         return TEST_MOCHITEST;
@@ -35,25 +36,25 @@ public class testPrefsObserver extends B
         jsonPref.put("value", value);
         mActions.sendGeckoEvent("Preferences:Set", jsonPref.toString());
     }
 
     public void waitAndCheckPref(boolean value) throws JSONException {
         mAsserter.dumpLog("Waiting to check pref");
 
         JSONObject data = null;
-        String requestId = "";
+        int requestId = -1;
 
-        while (!requestId.equals(PREF_REQUEST_ID)) {
+        while (requestId != PREF_OBSERVE_REQUEST_ID) {
             data = new JSONObject(mExpecter.blockForEventData());
             if (!mExpecter.eventReceived()) {
                 mAsserter.ok(false, "Checking pref is correct value", "Didn't receive pref");
                 return;
             }
-            requestId = data.getString("requestId");
+            requestId = data.getInt("requestId");
         }
 
         JSONObject pref = data.getJSONArray("preferences").getJSONObject(0);
         mAsserter.is(pref.getString("name"), PREF_TEST_PREF, "Pref name is correct");
         mAsserter.is(pref.getString("type"), "bool", "Pref type is correct");
         mAsserter.is(pref.getBoolean("value"), value, "Pref value is correct");
     }
 
@@ -75,29 +76,24 @@ public class testPrefsObserver extends B
 
         mAsserter.ok(false, "Received unobserved pref change", "");
     }
 
     public void observePref() throws JSONException {
         mAsserter.dumpLog("Setting up pref observer");
 
         // Setup the pref observer
-        JSONArray getPrefData = new JSONArray();
-        getPrefData.put(PREF_TEST_PREF);
-        JSONObject message = new JSONObject();
-        message.put("requestId", PREF_REQUEST_ID);
-        message.put("preferences", getPrefData);
         mExpecter = mActions.expectGeckoEvent("Preferences:Data");
-        mActions.sendGeckoEvent("Preferences:Observe", message.toString());
+        mActions.sendPreferencesObserveEvent(PREF_OBSERVE_REQUEST_ID, new String[] { PREF_TEST_PREF });
     }
 
     public void removePrefObserver() {
         mAsserter.dumpLog("Removing pref observer");
 
-        mActions.sendGeckoEvent("Preferences:RemoveObservers", PREF_REQUEST_ID);
+        mActions.sendGeckoEvent("Preferences:RemoveObservers", Integer.toString(PREF_OBSERVE_REQUEST_ID));
     }
 
     public void testPrefsObserver() {
         blockForGeckoReady();
 
         try {
             setPref(false);
             observePref();
--- a/mobile/android/chrome/content/browser.js
+++ b/mobile/android/chrome/content/browser.js
@@ -273,19 +273,17 @@ var BrowserApp = {
     Services.obs.addObserver(this, "Tab:Closed", false);
     Services.obs.addObserver(this, "Session:Back", false);
     Services.obs.addObserver(this, "Session:ShowHistory", false);
     Services.obs.addObserver(this, "Session:Forward", false);
     Services.obs.addObserver(this, "Session:Reload", false);
     Services.obs.addObserver(this, "Session:Stop", false);
     Services.obs.addObserver(this, "SaveAs:PDF", false);
     Services.obs.addObserver(this, "Browser:Quit", false);
-    Services.obs.addObserver(this, "Preferences:Get", false);
     Services.obs.addObserver(this, "Preferences:Set", false);
-    Services.obs.addObserver(this, "Preferences:Observe", false);
     Services.obs.addObserver(this, "Preferences:RemoveObservers", false);
     Services.obs.addObserver(this, "ScrollTo:FocusedInput", false);
     Services.obs.addObserver(this, "Sanitize:ClearData", false);
     Services.obs.addObserver(this, "FullScreen:Exit", false);
     Services.obs.addObserver(this, "Viewport:Change", false);
     Services.obs.addObserver(this, "Viewport:Flush", false);
     Services.obs.addObserver(this, "Viewport:FixedMarginsChanged", false);
     Services.obs.addObserver(this, "Passwords:Init", false);
@@ -331,19 +329,16 @@ var BrowserApp = {
     WebappsUI.init();
     RemoteDebugger.init();
     Reader.init();
     UserAgentOverrides.init();
     DesktopUserAgent.init();
     ExternalApps.init();
     Distribution.init();
     Tabs.init();
-#ifdef MOZ_TELEMETRY_REPORTING
-    Telemetry.init();
-#endif
 #ifdef ACCESSIBILITY
     AccessFu.attach(window);
 #endif
 
     // Init LoginManager
     Cc["@mozilla.org/login-manager;1"].getService(Ci.nsILoginManager);
 
     let url = null;
@@ -652,19 +647,16 @@ var BrowserApp = {
     WebappsUI.uninit();
     RemoteDebugger.uninit();
     Reader.uninit();
     UserAgentOverrides.uninit();
     DesktopUserAgent.uninit();
     ExternalApps.uninit();
     Distribution.uninit();
     Tabs.uninit();
-#ifdef MOZ_TELEMETRY_REPORTING
-    Telemetry.uninit();
-#endif
   },
 
   // This function returns false during periods where the browser displayed document is
   // different from the browser content document, so user actions and some kinds of viewport
   // updates should be ignored. This period starts when we start loading a new page or
   // switch tabs, and ends when the new browser content document has been drawn and handed
   // off to the compositor.
   isBrowserContentDocumentDisplayed: function() {
@@ -989,37 +981,38 @@ var BrowserApp = {
                                   Services.io.newFileURI(file), "", mimeInfo,
                                   Date.now() * 1000, null, cancelable, isPrivate);
 
     webBrowserPrint.print(printSettings, download);
   },
 
   notifyPrefObservers: function(aPref) {
     this._prefObservers[aPref].forEach(function(aRequestId) {
-      let request = { requestId : aRequestId,
-                      preferences : [aPref] };
-      this.getPreferences(request);
+      this.getPreferences(aRequestId, [aPref], 1);
     }, this);
   },
 
-  getPreferences: function getPreferences(aPrefsRequest, aListen) {
+  handlePreferencesRequest: function handlePreferencesRequest(aRequestId,
+                                                              aPrefNames,
+                                                              aListen) {
+
     let prefs = [];
 
-    for (let prefName of aPrefsRequest.preferences) {
+    for (let prefName of aPrefNames) {
       let pref = {
         name: prefName,
         type: "",
         value: null
       };
 
       if (aListen) {
         if (this._prefObservers[prefName])
-          this._prefObservers[prefName].push(aPrefsRequest.requestId);
+          this._prefObservers[prefName].push(aRequestId);
         else
-          this._prefObservers[prefName] = [ aPrefsRequest.requestId ];
+          this._prefObservers[prefName] = [ aRequestId ];
         Services.prefs.addObserver(prefName, this, false);
       }
 
       // These pref names are not "real" pref names.
       // They are used in the setting menu,
       // and these are passed when initializing the setting menu.
       switch (prefName) {
         // The plugin pref is actually two separate prefs, so
@@ -1116,17 +1109,17 @@ var BrowserApp = {
           break;
       }
 
       prefs.push(pref);
     }
 
     sendMessageToJava({
       type: "Preferences:Data",
-      requestId: aPrefsRequest.requestId,    // opaque request identifier, can be any string/int/whatever
+      requestId: aRequestId,    // opaque request identifier, can be any string/int/whatever
       preferences: prefs
     });
   },
 
   removePreferenceObservers: function removePreferenceObservers(aRequestId) {
     let newPrefObservers = [];
     for (let prefName in this._prefObservers) {
       let requestIds = this._prefObservers[prefName];
@@ -1439,28 +1432,20 @@ var BrowserApp = {
       case "Browser:Quit":
         this.quit();
         break;
 
       case "SaveAs:PDF":
         this.saveAsPDF(browser);
         break;
 
-      case "Preferences:Get":
-        this.getPreferences(JSON.parse(aData));
-        break;
-
       case "Preferences:Set":
         this.setPreferences(aData);
         break;
 
-      case "Preferences:Observe":
-        this.getPreferences(JSON.parse(aData), true);
-        break;
-
       case "Preferences:RemoveObservers":
         this.removePreferenceObservers(aData);
         break;
 
       case "ScrollTo:FocusedInput":
         // these messages come from a change in the viewable area and not user interaction
         // we allow scrolling to the selected input, but not zooming the page
         this.scrollToFocusedInput(browser, false);
@@ -1528,16 +1513,24 @@ var BrowserApp = {
     return this.defaultBrowserWidth = width;
   },
 
   // nsIAndroidBrowserApp
   getBrowserTab: function(tabId) {
     return this.getTabForId(tabId);
   },
 
+  getPreferences: function getPreferences(requestId, prefNames, count) {
+    this.handlePreferencesRequest(requestId, prefNames, false);
+  },
+
+  observePreferences: function observePreferences(requestId, prefNames, count) {
+    this.handlePreferencesRequest(requestId, prefNames, true);
+  },
+
   // This method will print a list from fromIndex to toIndex, optionally
   // selecting selIndex(if fromIndex<=selIndex<=toIndex)
   showHistory: function(fromIndex, toIndex, selIndex) {
     let browser = this.selectedBrowser;
     let hist = browser.sessionHistory;
     let listitems = [];
     for (let i = toIndex; i >= fromIndex; i--) {
       let entry = hist.getEntryAtIndex(i, false);
@@ -7083,36 +7076,20 @@ var RemoteDebugger = {
     DebuggerServer.closeListener();
     dump("Remote debugger stopped");
   }
 };
 
 var Telemetry = {
   SHARED_PREF_TELEMETRY_ENABLED: "datareporting.telemetry.enabled",
 
-  init: function init() {
-    Services.obs.addObserver(this, "Telemetry:Add", false);
-  },
-
-  uninit: function uninit() {
-    Services.obs.removeObserver(this, "Telemetry:Add");
-  },
-
   addData: function addData(aHistogramId, aValue) {
-    let telemetry = Cc["@mozilla.org/base/telemetry;1"].getService(Ci.nsITelemetry);
-    let histogram = telemetry.getHistogramById(aHistogramId);
+    let histogram = Services.telemetry.getHistogramById(aHistogramId);
     histogram.add(aValue);
   },
-
-  observe: function observe(aSubject, aTopic, aData) {
-    if (aTopic == "Telemetry:Add") {
-      let json = JSON.parse(aData);
-      this.addData(json.name, json.value);
-    }
-  },
 };
 
 let Reader = {
   // Version of the cache database schema
   DB_VERSION: 1,
 
   DEBUG: 0,
 
--- a/netwerk/test/httpserver/test/test_load_module.js
+++ b/netwerk/test/httpserver/test/test_load_module.js
@@ -3,14 +3,14 @@
 
 /**
  * Ensure httpd.js can be imported as a module and that a server starts.
  */
 function run_test() {
   Components.utils.import("resource://testing-common/httpd.js");
 
   let server = new HttpServer();
-  server.start(8080);
+  server.start(-1);
 
   do_test_pending();
 
   server.stop(do_test_finished);
 }
--- a/nsprpub/TAG-INFO
+++ b/nsprpub/TAG-INFO
@@ -1,1 +1,1 @@
-NSPR_4_10_1_BETA1
+NSPR_4_10_1_BETA2
--- a/nsprpub/config/prdepend.h
+++ b/nsprpub/config/prdepend.h
@@ -5,9 +5,8 @@
 
 /*
  * A dummy header file that is a dependency for all the object files.
  * Used to force a full recompilation of NSPR in Mozilla's Tinderbox
  * depend builds.  See comments in rules.mk.
  */
 
 #error "Do not include this header file."
-
--- a/nsprpub/pr/src/md/unix/unix_errors.c
+++ b/nsprpub/pr/src/md/unix/unix_errors.c
@@ -523,35 +523,26 @@ void _MD_unix_map_accept_error(int err)
     PR_SetError(prError, err);
 }
 
 void _MD_unix_map_connect_error(int err)
 {
     PRErrorCode prError;
 
     switch (err) {
-        case EACCES:
-            prError = PR_ADDRESS_NOT_SUPPORTED_ERROR;
-            break;
 #if defined(UNIXWARE)
         /*
          * On some platforms, if we connect to a port on the local host 
          * (the loopback address) that no process is listening on, we get 
          * EIO instead of ECONNREFUSED.
          */
         case EIO:
             prError = PR_CONNECT_REFUSED_ERROR;
             break;
 #endif
-        case ELOOP:
-            prError = PR_ADDRESS_NOT_SUPPORTED_ERROR;
-            break;
-        case ENOENT:
-            prError = PR_ADDRESS_NOT_SUPPORTED_ERROR;
-            break;
         case ENXIO:
             prError = PR_IO_ERROR;
             break;
         default:
             _MD_unix_map_default_error(err);
             return;
     }
     PR_SetError(prError, err);
@@ -560,27 +551,16 @@ void _MD_unix_map_connect_error(int err)
 void _MD_unix_map_bind_error(int err)
 {
     PRErrorCode prError;
 
     switch (err) {
         case EINVAL:
             prError = PR_SOCKET_ADDRESS_IS_BOUND_ERROR;
             break;
-        /*
-         * UNIX domain sockets are not supported in NSPR
-         */
-        case EIO:
-        case EISDIR:
-        case ELOOP:
-        case ENOENT:
-        case ENOTDIR:
-        case EROFS:
-            prError = PR_ADDRESS_NOT_SUPPORTED_ERROR;
-            break;
         default:
             _MD_unix_map_default_error(err);
             return;
     }
     PR_SetError(prError, err);
 }
 
 void _MD_unix_map_listen_error(int err)
--- a/parser/html/jArray.h
+++ b/parser/html/jArray.h
@@ -15,18 +15,18 @@
  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
  * DEALINGS IN THE SOFTWARE.
  */
 
-#ifndef jArray_h_
-#define jArray_h_
+#ifndef jArray_h
+#define jArray_h
 
 #include "mozilla/NullPtr.h"
 #include "nsDebug.h"
 
 template<class T, class L>
 struct staticJArray {
   const T* arr;
   const L length;
@@ -119,9 +119,9 @@ class autoJArray {
       // Make assigning null to an array in Java delete the buffer in C++
       // MSVC10 does not allow asserting that zero is null.
       delete[] arr;
       arr = nullptr;
       length = 0;
     }
 };
 
-#endif // jArray_h_
+#endif // jArray_h
--- a/parser/html/nsAHtml5TreeBuilderState.h
+++ b/parser/html/nsAHtml5TreeBuilderState.h
@@ -1,14 +1,14 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
-#ifndef nsAHtml5TreeBuilderState_h___
-#define nsAHtml5TreeBuilderState_h___
+#ifndef nsAHtml5TreeBuilderState_h
+#define nsAHtml5TreeBuilderState_h
 
 /**
  * Interface for exposing the internal state of the HTML5 tree builder.
  * For more documentation, please see
  * http://hg.mozilla.org/projects/htmlparser/file/tip/src/nu/validator/htmlparser/impl/StateSnapshot.java
  */
 class nsAHtml5TreeBuilderState {
   public:
@@ -40,9 +40,9 @@ class nsAHtml5TreeBuilderState {
     virtual bool isNeedToDropLF() = 0;
 
     virtual bool isQuirks() = 0;
     
     virtual ~nsAHtml5TreeBuilderState() {
     }
 };
 
-#endif /* nsAHtml5TreeBuilderState_h___ */
+#endif /* nsAHtml5TreeBuilderState_h */
--- a/parser/html/nsAHtml5TreeOpSink.h
+++ b/parser/html/nsAHtml5TreeOpSink.h
@@ -1,14 +1,14 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
-#ifndef nsAHtml5TreeOpSink_h___
-#define nsAHtml5TreeOpSink_h___
+#ifndef nsAHtml5TreeOpSink_h
+#define nsAHtml5TreeOpSink_h
 
 /**
  * The purpose of this interface is to connect a tree op executor 
  * (main-thread case), a tree op stage (non-speculative off-the-main-thread
  * case) or a speculation (speculative case).
  */
 class nsAHtml5TreeOpSink {
   public:
@@ -16,9 +16,9 @@ class nsAHtml5TreeOpSink {
     /**
      * Flush the operations from the tree operations from the argument
      * queue into this sink unconditionally.
      */
     virtual void MoveOpsFrom(nsTArray<nsHtml5TreeOperation>& aOpQueue) = 0;
     
 };
 
-#endif /* nsAHtml5TreeOpSink_h___ */
+#endif /* nsAHtml5TreeOpSink_h */
--- a/parser/html/nsHtml5ArrayCopy.h
+++ b/parser/html/nsHtml5ArrayCopy.h
@@ -15,18 +15,18 @@
  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
  * DEALINGS IN THE SOFTWARE.
  */
 
-#ifndef nsHtml5ArrayCopy_h__
-#define nsHtml5ArrayCopy_h__
+#ifndef nsHtml5ArrayCopy_h
+#define nsHtml5ArrayCopy_h
 
 #include "prtypes.h"
 
 class nsString;
 class nsHtml5StackNode;
 class nsHtml5AttributeName;
 
 // Unfortunately, these don't work as template functions because the arguments
@@ -71,9 +71,9 @@ class nsHtml5ArrayCopy {
     }
 
     static inline void
     arraycopy(nsHtml5StackNode** arr, int32_t sourceOffset, int32_t targetOffset, int32_t length)
     {
       memmove(&(arr[targetOffset]), &(arr[sourceOffset]), length * sizeof(nsHtml5StackNode*));
     }
 };
-#endif // nsHtml5ArrayCopy_h__
+#endif // nsHtml5ArrayCopy_h
--- a/parser/html/nsHtml5Atom.h
+++ b/parser/html/nsHtml5Atom.h
@@ -1,14 +1,14 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
-#ifndef nsHtml5Atom_h_
-#define nsHtml5Atom_h_
+#ifndef nsHtml5Atom_h
+#define nsHtml5Atom_h
 
 #include "nsIAtom.h"
 #include "mozilla/Attributes.h"
 
 /**
  * A dynamic atom implementation meant for use within the nsHtml5Tokenizer and 
  * nsHtml5TreeBuilder owned by one nsHtml5Parser or nsHtml5StreamParser 
  * instance.
@@ -20,9 +20,9 @@ class nsHtml5Atom MOZ_FINAL : public nsI
   public:
     NS_DECL_ISUPPORTS
     NS_DECL_NSIATOM
 
     nsHtml5Atom(const nsAString& aString);
     ~nsHtml5Atom();
 };
 
-#endif // nsHtml5Atom_h_
+#endif // nsHtml5Atom_h
--- a/parser/html/nsHtml5AtomTable.h
+++ b/parser/html/nsHtml5AtomTable.h
@@ -1,14 +1,14 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
-#ifndef nsHtml5AtomTable_h_
-#define nsHtml5AtomTable_h_
+#ifndef nsHtml5AtomTable_h
+#define nsHtml5AtomTable_h
 
 #include "nsHashKeys.h"
 #include "nsTHashtable.h"
 #include "nsAutoPtr.h"
 #include "nsIAtom.h"
 #include "nsIThread.h"
 
 class nsHtml5Atom;
@@ -103,9 +103,9 @@ class nsHtml5AtomTable
   
   private:
     nsTHashtable<nsHtml5AtomEntry> mTable;
 #ifdef DEBUG
     nsCOMPtr<nsIThread>            mPermittedLookupThread;
 #endif
 };
 
-#endif // nsHtml5AtomTable_h_
+#endif // nsHtml5AtomTable_h
--- a/parser/html/nsHtml5Atoms.h
+++ b/parser/html/nsHtml5Atoms.h
@@ -4,27 +4,27 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
  
 /*
  * This class wraps up the creation (and destruction) of the standard
  * set of atoms used by gklayout; the atoms are created when gklayout
  * is loaded and they are destroyed when gklayout is unloaded.
  */
 
-#ifndef nsHtml5Atoms_h___
-#define nsHtml5Atoms_h___
+#ifndef nsHtml5Atoms_h
+#define nsHtml5Atoms_h
 
 #include "nsIAtom.h"
 
 class nsHtml5Atoms {
   public:
     static void AddRefAtoms();
     /* Declare all atoms
        The atom names and values are stored in nsGkAtomList.h and
        are brought to you by the magic of C preprocessing
        Add new atoms to nsGkAtomList and all support logic will be auto-generated
      */
 #define HTML5_ATOM(_name, _value) static nsIAtom* _name;
 #include "nsHtml5AtomList.h"
 #undef HTML5_ATOM
 };
 
-#endif /* nsHtml5Atoms_h___ */
+#endif /* nsHtml5Atoms_h */
--- a/parser/html/nsHtml5AttributeName.h
+++ b/parser/html/nsHtml5AttributeName.h
@@ -20,18 +20,18 @@
  * DEALINGS IN THE SOFTWARE.
  */
 
 /*
  * THIS IS A GENERATED FILE. PLEASE DO NOT EDIT.
  * Please edit AttributeName.java instead and regenerate.
  */
 
-#ifndef nsHtml5AttributeName_h__
-#define nsHtml5AttributeName_h__
+#ifndef nsHtml5AttributeName_h
+#define nsHtml5AttributeName_h
 
 #include "nsIAtom.h"
 #include "nsHtml5AtomTable.h"
 #include "nsString.h"
 #include "nsINameSpaceManager.h"
 #include "nsIContent.h"
 #include "nsTraceRefcnt.h"
 #include "jArray.h"
--- a/parser/html/nsHtml5ByteReadable.h
+++ b/parser/html/nsHtml5ByteReadable.h
@@ -1,14 +1,14 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
-#ifndef nsHtml5ByteReadable_h__
-#define nsHtml5ByteReadable_h__
+#ifndef nsHtml5ByteReadable_h
+#define nsHtml5ByteReadable_h
 
 /**
  * A weak reference wrapper around a byte array.
  */
 class nsHtml5ByteReadable
 {
   public:
 
--- a/parser/html/nsHtml5DependentUTF16Buffer.h
+++ b/parser/html/nsHtml5DependentUTF16Buffer.h
@@ -1,14 +1,14 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
-#ifndef nsHtml5DependentUTF16Buffer_h_
-#define nsHtml5DependentUTF16Buffer_h_
+#ifndef nsHtml5DependentUTF16Buffer_h
+#define nsHtml5DependentUTF16Buffer_h
 
 #include "nscore.h"
 #include "nsHtml5OwningUTF16Buffer.h"
 
 class MOZ_STACK_CLASS nsHtml5DependentUTF16Buffer : public nsHtml5UTF16Buffer
 {
   public:
     /**
@@ -23,9 +23,9 @@ class MOZ_STACK_CLASS nsHtml5DependentUT
      * Copies the currently unconsumed part of this buffer into a new
      * heap-allocated nsHtml5OwningUTF16Buffer. The new object is allocated
      * with a fallible allocator. If the allocation fails, nullptr is returned.
      * @return heap-allocated copy or nullptr if memory allocation failed
      */
     already_AddRefed<nsHtml5OwningUTF16Buffer> FalliblyCopyAsOwningBuffer();
 };
 
-#endif // nsHtml5DependentUTF16Buffer_h_
+#endif // nsHtml5DependentUTF16Buffer_h
--- a/parser/html/nsHtml5DocumentMode.h
+++ b/parser/html/nsHtml5DocumentMode.h
@@ -1,14 +1,14 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
  
-#ifndef nsHtml5DocumentMode_h__
-#define nsHtml5DocumentMode_h__
+#ifndef nsHtml5DocumentMode_h
+#define nsHtml5DocumentMode_h
 
 enum nsHtml5DocumentMode {
     STANDARDS_MODE,
     ALMOST_STANDARDS_MODE,
     QUIRKS_MODE
 };
 
-#endif // nsHtml5DocumentMode_h__
+#endif // nsHtml5DocumentMode_h
--- a/parser/html/nsHtml5ElementName.h
+++ b/parser/html/nsHtml5ElementName.h
@@ -20,18 +20,18 @@
  * DEALINGS IN THE SOFTWARE.
  */
 
 /*
  * THIS IS A GENERATED FILE. PLEASE DO NOT EDIT.
  * Please edit ElementName.java instead and regenerate.
  */
 
-#ifndef nsHtml5ElementName_h__
-#define nsHtml5ElementName_h__
+#ifndef nsHtml5ElementName_h
+#define nsHtml5ElementName_h
 
 #include "nsIAtom.h"
 #include "nsHtml5AtomTable.h"
 #include "nsString.h"
 #include "nsINameSpaceManager.h"
 #include "nsIContent.h"
 #include "nsTraceRefcnt.h"
 #include "jArray.h"
--- a/parser/html/nsHtml5Highlighter.h
+++ b/parser/html/nsHtml5Highlighter.h
@@ -1,13 +1,13 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-#ifndef nsHtml5Highlighter_h_
-#define nsHtml5Highlighter_h_
+#ifndef nsHtml5Highlighter_h
+#define nsHtml5Highlighter_h
 
 #include "prtypes.h"
 #include "nsCOMPtr.h"
 #include "nsHtml5TreeOperation.h"
 #include "nsHtml5UTF16Buffer.h"
 #include "nsHtml5TreeOperation.h"
 #include "nsAHtml5TreeOpSink.h"
 
@@ -397,9 +397,9 @@ class nsHtml5Highlighter
     static PRUnichar sEntity[];
 
     /**
      * The string "pi"
      */
     static PRUnichar sPi[];
 };
 
-#endif // nsHtml5Highlighter_h_
+#endif // nsHtml5Highlighter_h
--- a/parser/html/nsHtml5HtmlAttributes.h
+++ b/parser/html/nsHtml5HtmlAttributes.h
@@ -21,18 +21,18 @@
  * DEALINGS IN THE SOFTWARE.
  */
 
 /*
  * THIS IS A GENERATED FILE. PLEASE DO NOT EDIT.
  * Please edit HtmlAttributes.java instead and regenerate.
  */
 
-#ifndef nsHtml5HtmlAttributes_h__
-#define nsHtml5HtmlAttributes_h__
+#ifndef nsHtml5HtmlAttributes_h
+#define nsHtml5HtmlAttributes_h
 
 #include "nsIAtom.h"
 #include "nsHtml5AtomTable.h"
 #include "nsString.h"
 #include "nsINameSpaceManager.h"
 #include "nsIContent.h"
 #include "nsTraceRefcnt.h"
 #include "jArray.h"
--- a/parser/html/nsHtml5Macros.h
+++ b/parser/html/nsHtml5Macros.h
@@ -15,18 +15,18 @@
  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
  * DEALINGS IN THE SOFTWARE.
  */
 
-#ifndef nsHtml5Macros_h_
-#define nsHtml5Macros_h_
+#ifndef nsHtml5Macros_h
+#define nsHtml5Macros_h
 
 #define NS_HTML5_CONTINUE(target) \
   goto target
 
 #define NS_HTML5_BREAK(target) \
   goto target ## _end
 
-#endif /* nsHtml5Macros_h_ */
+#endif /* nsHtml5Macros_h */
--- a/parser/html/nsHtml5MetaScanner.h
+++ b/parser/html/nsHtml5MetaScanner.h
@@ -21,18 +21,18 @@
  * DEALINGS IN THE SOFTWARE.
  */
 
 /*
  * THIS IS A GENERATED FILE. PLEASE DO NOT EDIT.
  * Please edit MetaScanner.java instead and regenerate.
  */
 
-#ifndef nsHtml5MetaScanner_h__
-#define nsHtml5MetaScanner_h__
+#ifndef nsHtml5MetaScanner_h
+#define nsHtml5MetaScanner_h
 
 #include "nsIAtom.h"
 #include "nsHtml5AtomTable.h"
 #include "nsString.h"
 #include "nsINameSpaceManager.h"
 #include "nsIContent.h"
 #include "nsTraceRefcnt.h"
 #include "jArray.h"
--- a/parser/html/nsHtml5Module.h
+++ b/parser/html/nsHtml5Module.h
@@ -1,14 +1,14 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
-#ifndef nsHtml5Module_h__
-#define nsHtml5Module_h__
+#ifndef nsHtml5Module_h
+#define nsHtml5Module_h
 
 #include "nsIParser.h"
 #include "nsIThread.h"
 
 class nsHtml5Module
 {
   public:
     static void InitializeStatics();
@@ -20,9 +20,9 @@ class nsHtml5Module
   private:
 #ifdef DEBUG
     static bool sNsHtml5ModuleInitialized;
 #endif
     static nsIThread* sStreamParserThread;
     static nsIThread* sMainThread;
 };
 
-#endif // nsHtml5Module_h__
+#endif // nsHtml5Module_h
--- a/parser/html/nsHtml5NamedCharacters.h
+++ b/parser/html/nsHtml5NamedCharacters.h
@@ -15,18 +15,18 @@
  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 
  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 
  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 
  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 
  * DEALINGS IN THE SOFTWARE.
  */
 
-#ifndef nsHtml5NamedCharacters_h_
-#define nsHtml5NamedCharacters_h_
+#ifndef nsHtml5NamedCharacters_h
+#define nsHtml5NamedCharacters_h
 
 #include "prtypes.h"
 #include "jArray.h"
 #include "nscore.h"
 #include "nsDebug.h"
 #include "prlog.h"
 #include "nsMemory.h"
 
@@ -45,9 +45,9 @@ class nsHtml5NamedCharacters
   public:
     static const nsHtml5CharacterName NAMES[];
     static const PRUnichar VALUES[][2];
     static PRUnichar** WINDOWS_1252;
     static void initializeStatics();
     static void releaseStatics();
 };
 
-#endif // nsHtml5NamedCharacters_h_
+#endif // nsHtml5NamedCharacters_h
--- a/parser/html/nsHtml5NamedCharactersAccel.h
+++ b/parser/html/nsHtml5NamedCharactersAccel.h
@@ -1,25 +1,25 @@
 /*
  * Copyright 2004-2010 Apple Computer, Inc., Mozilla Foundation, and Opera 
  * Software ASA.
  * 
  * You are granted a license to use, reproduce and create derivative works of 
  * this document.
  */
 
-#ifndef nsHtml5NamedCharactersAccel_h_
-#define nsHtml5NamedCharactersAccel_h_
+#ifndef nsHtml5NamedCharactersAccel_h
+#define nsHtml5NamedCharactersAccel_h
 
 #include "prtypes.h"
 #include "jArray.h"
 #include "nscore.h"
 #include "nsDebug.h"
 #include "prlog.h"
 #include "nsMemory.h"
 
 class nsHtml5NamedCharactersAccel
 {
   public:
     static const int32_t* const HILO_ACCEL[];
 };
 
-#endif // nsHtml5NamedCharactersAccel_h_
+#endif // nsHtml5NamedCharactersAccel_h
--- a/parser/html/nsHtml5OwningUTF16Buffer.h
+++ b/parser/html/nsHtml5OwningUTF16Buffer.h
@@ -1,14 +1,14 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
-#ifndef nsHtml5OwningUTF16Buffer_h_
-#define nsHtml5OwningUTF16Buffer_h_
+#ifndef nsHtml5OwningUTF16Buffer_h
+#define nsHtml5OwningUTF16Buffer_h
 
 #include "nsHtml5UTF16Buffer.h"
 
 class nsHtml5OwningUTF16Buffer : public nsHtml5UTF16Buffer
 {
   private:
 
     /**
@@ -48,9 +48,9 @@ class nsHtml5OwningUTF16Buffer : public 
     void Swap(nsHtml5OwningUTF16Buffer* aOther);
 
     nsrefcnt AddRef();
     nsrefcnt Release();
   private:
     nsAutoRefCnt mRefCnt;
 };
 
-#endif // nsHtml5OwningUTF16Buffer_h_
+#endif // nsHtml5OwningUTF16Buffer_h
--- a/parser/html/nsHtml5Parser.h
+++ b/parser/html/nsHtml5Parser.h
@@ -1,15 +1,15 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
-#ifndef NS_HTML5_PARSER__
-#define NS_HTML5_PARSER__
+#ifndef NS_HTML5_PARSER
+#define NS_HTML5_PARSER
 
 #include "nsAutoPtr.h"
 #include "nsIParser.h"
 #include "nsDeque.h"
 #include "nsIURL.h"
 #include "nsParserCIID.h"
 #include "nsITokenizer.h"
 #include "nsThreadUtils.h"
--- a/parser/html/nsHtml5PendingNotification.h
+++ b/parser/html/nsHtml5PendingNotification.h
@@ -1,14 +1,14 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
-#ifndef nsHtml5PendingNotification_h__
-#define nsHtml5PendingNotification_h__
+#ifndef nsHtml5PendingNotification_h
+#define nsHtml5PendingNotification_h
 
 #include "nsNodeUtils.h"
 
 class nsHtml5TreeBuilder;
 
 class nsHtml5PendingNotification {
   public:
 
@@ -43,9 +43,9 @@ class nsHtml5PendingNotification {
     nsIContent* mParent;
 
     /**
      * Child count at start of notification deferring
      */
     uint32_t    mChildCount;
 };
 
-#endif // nsHtml5PendingNotification_h__
+#endif // nsHtml5PendingNotification_h
--- a/parser/html/nsHtml5PlainTextUtils.h
+++ b/parser/html/nsHtml5PlainTextUtils.h
@@ -1,16 +1,16 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
-#ifndef nsHtml5PlainTextUtils_h_
-#define nsHtml5PlainTextUtils_h_
+#ifndef nsHtml5PlainTextUtils_h
+#define nsHtml5PlainTextUtils_h
 
 #include "nsHtml5HtmlAttributes.h"
 
 class nsHtml5PlainTextUtils
 {
   public:
     static nsHtml5HtmlAttributes* NewLinkAttributes();
 };
 
-#endif // nsHtml5PlainTextUtils_h_
+#endif // nsHtml5PlainTextUtils_h
--- a/parser/html/nsHtml5Portability.h
+++ b/parser/html/nsHtml5Portability.h
@@ -20,18 +20,18 @@
  * DEALINGS IN THE SOFTWARE.
  */
 
 /*
  * THIS IS A GENERATED FILE. PLEASE DO NOT EDIT.
  * Please edit Portability.java instead and regenerate.
  */
 
-#ifndef nsHtml5Portability_h__
-#define nsHtml5Portability_h__
+#ifndef nsHtml5Portability_h
+#define nsHtml5Portability_h
 
 #include "nsIAtom.h"
 #include "nsHtml5AtomTable.h"
 #include "nsString.h"
 #include "nsINameSpaceManager.h"
 #include "nsIContent.h"
 #include "nsTraceRefcnt.h"
 #include "jArray.h"
--- a/parser/html/nsHtml5RefPtr.h
+++ b/parser/html/nsHtml5RefPtr.h
@@ -1,15 +1,15 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
-#ifndef nsHtml5RefPtr_h___
-#define nsHtml5RefPtr_h___
+#ifndef nsHtml5RefPtr_h
+#define nsHtml5RefPtr_h
 
 #include "nsIThread.h"
 
 template <class T>
 class nsHtml5RefPtrReleaser : public nsRunnable
   {
     private:
       T* mPtr;
@@ -480,9 +480,9 @@ bool
 operator==( int lhs, const nsHtml5RefPtr<T>& rhs )
     // specifically to allow |0 == smartPtr|
   {
     return reinterpret_cast<const void*>(lhs) == static_cast<const void*>(rhs.get());
   }
 
 #endif // !defined(HAVE_CPP_TROUBLE_COMPARING_TO_ZERO)
 
-#endif // !defined(nsHtml5RefPtr_h___)
+#endif // !defined(nsHtml5RefPtr_h)
--- a/parser/html/nsHtml5ReleasableAttributeName.h
+++ b/parser/html/nsHtml5ReleasableAttributeName.h
@@ -1,21 +1,21 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
-#ifndef nsHtml5ReleasableAttributeName_h__
-#define nsHtml5ReleasableAttributeName_h__
+#ifndef nsHtml5ReleasableAttributeName_h
+#define nsHtml5ReleasableAttributeName_h
 
 #include "nsHtml5AttributeName.h"
 #include "mozilla/Attributes.h"
 
 class nsHtml5AtomTable;
 
 class nsHtml5ReleasableAttributeName MOZ_FINAL : public nsHtml5AttributeName
 {
   public:
     nsHtml5ReleasableAttributeName(int32_t* uri, nsIAtom** local, nsIAtom** prefix);
     virtual nsHtml5AttributeName* cloneAttributeName(nsHtml5AtomTable* aInterner);
     virtual void release();
 };
 
-#endif // nsHtml5ReleasableAttributeName_h__
+#endif // nsHtml5ReleasableAttributeName_h
--- a/parser/html/nsHtml5ReleasableElementName.h
+++ b/parser/html/nsHtml5ReleasableElementName.h
@@ -1,19 +1,19 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
-#ifndef nsHtml5ReleasableElementName_h__
-#define nsHtml5ReleasableElementName_h__
+#ifndef nsHtml5ReleasableElementName_h
+#define nsHtml5ReleasableElementName_h
 
 #include "nsHtml5ElementName.h"
 #include "mozilla/Attributes.h"
 
 class nsHtml5ReleasableElementName MOZ_FINAL : public nsHtml5ElementName
 {
   public:
     nsHtml5ReleasableElementName(nsIAtom* name);
     virtual void release();
     virtual nsHtml5ElementName* cloneElementName(nsHtml5AtomTable* interner);
 };
 
-#endif // nsHtml5ReleasableElementName_h__
+#endif // nsHtml5ReleasableElementName_h
--- a/parser/html/nsHtml5SVGLoadDispatcher.h
+++ b/parser/html/nsHtml5SVGLoadDispatcher.h
@@ -1,21 +1,21 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
-#ifndef nsHtml5SVGLoadDispatcher_h_
-#define nsHtml5SVGLoadDispatcher_h_
+#ifndef nsHtml5SVGLoadDispatcher_h
+#define nsHtml5SVGLoadDispatcher_h
 
 #include "nsThreadUtils.h"
 #include "nsIContent.h"
 
 class nsHtml5SVGLoadDispatcher : public nsRunnable
 {
   private:
     nsCOMPtr<nsIContent> mElement;
     nsCOMPtr<nsIDocument> mDocument;
   public:
     nsHtml5SVGLoadDispatcher(nsIContent* aElement);
     NS_IMETHOD Run();
 };
 
-#endif // nsHtml5SVGLoadDispatcher_h_
+#endif // nsHtml5SVGLoadDispatcher_h
--- a/parser/html/nsHtml5Speculation.h
+++ b/parser/html/nsHtml5Speculation.h
@@ -1,14 +1,14 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
-#ifndef nsHtml5Speculation_h__
-#define nsHtml5Speculation_h__
+#ifndef nsHtml5Speculation_h
+#define nsHtml5Speculation_h
 
 #include "nsHtml5OwningUTF16Buffer.h"
 #include "nsAHtml5TreeBuilderState.h"
 #include "nsHtml5TreeOperation.h"
 #include "nsAHtml5TreeOpSink.h"
 #include "nsTArray.h"
 #include "nsAutoPtr.h"
 #include "mozilla/Attributes.h"
@@ -63,9 +63,9 @@ class nsHtml5Speculation MOZ_FINAL : pub
      */
     int32_t                             mStartLineNumber;
     
     nsAutoPtr<nsAHtml5TreeBuilderState> mSnapshot;
 
     nsTArray<nsHtml5TreeOperation>      mOpQueue;
 };
 
-#endif // nsHtml5Speculation_h__
+#endif // nsHtml5Speculation_h
--- a/parser/html/nsHtml5SpeculativeLoad.h
+++ b/parser/html/nsHtml5SpeculativeLoad.h
@@ -1,14 +1,14 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
  
-#ifndef nsHtml5SpeculativeLoad_h_
-#define nsHtml5SpeculativeLoad_h_
+#ifndef nsHtml5SpeculativeLoad_h
+#define nsHtml5SpeculativeLoad_h
 
 #include "nsString.h"
 
 class nsHtml5TreeOpExecutor;
 
 enum eHtml5SpeculativeLoad {
 #ifdef DEBUG
   eSpeculativeLoadUninitialized,
@@ -127,9 +127,9 @@ class nsHtml5SpeculativeLoad {
     /**
      * If mOpCode is eSpeculativeLoadImage or eSpeculativeLoadScript[FromHead],
      * this is the value of the "crossorigin" attribute.  If the
      * attribute is not set, this will be a void string.
      */
     nsString mCrossOrigin;
 };
 
-#endif // nsHtml5SpeculativeLoad_h_
+#endif // nsHtml5SpeculativeLoad_h
--- a/parser/html/nsHtml5StackNode.h
+++ b/parser/html/nsHtml5StackNode.h
@@ -21,18 +21,18 @@
  * DEALINGS IN THE SOFTWARE.
  */
 
 /*
  * THIS IS A GENERATED FILE. PLEASE DO NOT EDIT.
  * Please edit StackNode.java instead and regenerate.
  */
 
-#ifndef nsHtml5StackNode_h__
-#define nsHtml5StackNode_h__
+#ifndef nsHtml5StackNode_h
+#define nsHtml5StackNode_h
 
 #include "nsIAtom.h"
 #include "nsHtml5AtomTable.h"
 #include "nsString.h"
 #include "nsINameSpaceManager.h"
 #include "nsIContent.h"
 #include "nsTraceRefcnt.h"
 #include "jArray.h"
--- a/parser/html/nsHtml5StateSnapshot.h
+++ b/parser/html/nsHtml5StateSnapshot.h
@@ -20,18 +20,18 @@
  * DEALINGS IN THE SOFTWARE.
  */
 
 /*
  * THIS IS A GENERATED FILE. PLEASE DO NOT EDIT.
  * Please edit StateSnapshot.java instead and regenerate.
  */
 
-#ifndef nsHtml5StateSnapshot_h__
-#define nsHtml5StateSnapshot_h__
+#ifndef nsHtml5StateSnapshot_h
+#define nsHtml5StateSnapshot_h
 
 #include "nsIAtom.h"
 #include "nsHtml5AtomTable.h"
 #include "nsString.h"
 #include "nsINameSpaceManager.h"
 #include "nsIContent.h"
 #include "nsTraceRefcnt.h"
 #include "jArray.h"
--- a/parser/html/nsHtml5StreamParser.h
+++ b/parser/html/nsHtml5StreamParser.h
@@ -1,15 +1,15 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
-#ifndef nsHtml5StreamParser_h__
-#define nsHtml5StreamParser_h__
+#ifndef nsHtml5StreamParser_h
+#define nsHtml5StreamParser_h
 
 #include "nsAutoPtr.h"
 #include "nsCOMPtr.h"
 #include "nsIStreamListener.h"
 #include "nsICharsetDetectionObserver.h"
 #include "nsHtml5MetaScanner.h"
 #include "nsIUnicodeDecoder.h"
 #include "nsHtml5TreeOpExecutor.h"
@@ -556,9 +556,9 @@ class nsHtml5StreamParser : public nsISt
     /**
      * The pref html5.flushtimer.subsequentdelay: Time in milliseconds between
      * the time a network buffer is seen and the timer firing when the
      * timer has already fired previously in this parse.
      */
     static int32_t                sTimerSubsequentDelay;
 };
 
-#endif // nsHtml5StreamParser_h__
+#endif // nsHtml5StreamParser_h
--- a/parser/html/nsHtml5StringParser.h
+++ b/parser/html/nsHtml5StringParser.h
@@ -1,14 +1,14 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
-#ifndef nsHtml5StringParser_h_
-#define nsHtml5StringParser_h_
+#ifndef nsHtml5StringParser_h
+#define nsHtml5StringParser_h
 
 #include "nsHtml5AtomTable.h"
 #include "nsParserBase.h"
 
 class nsHtml5TreeOpExecutor;
 class nsHtml5TreeBuilder;
 class nsHtml5Tokenizer;
 class nsIContent;
@@ -79,9 +79,9 @@ class nsHtml5StringParser : public nsPar
 
     /**
      * The scoped atom table
      */
     nsHtml5AtomTable                    mAtomTable;
 
 };
 
-#endif // nsHtml5StringParser_h_
+#endif // nsHtml5StringParser_h
--- a/parser/html/nsHtml5Tokenizer.h
+++ b/parser/html/nsHtml5Tokenizer.h
@@ -23,18 +23,18 @@
  * DEALINGS IN THE SOFTWARE.
  */
 
 /*
  * THIS IS A GENERATED FILE. PLEASE DO NOT EDIT.
  * Please edit Tokenizer.java instead and regenerate.
  */
 
-#ifndef nsHtml5Tokenizer_h__
-#define nsHtml5Tokenizer_h__
+#ifndef nsHtml5Tokenizer_h
+#define nsHtml5Tokenizer_h
 
 #include "nsIAtom.h"
 #include "nsHtml5AtomTable.h"
 #include "nsString.h"
 #include "nsIContent.h"
 #include "nsTraceRefcnt.h"
 #include "jArray.h"
 #include "nsHtml5DocumentMode.h"
--- a/parser/html/nsHtml5TokenizerLoopPolicies.h
+++ b/parser/html/nsHtml5TokenizerLoopPolicies.h
@@ -1,14 +1,14 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
-#ifndef nsHtml5TokenizerLoopPolicies_h_
-#define nsHtml5TokenizerLoopPolicies_h_
+#ifndef nsHtml5TokenizerLoopPolicies_h
+#define nsHtml5TokenizerLoopPolicies_h
 
 /**
  * This policy does not report tokenizer transitions anywhere. To be used
  * when _not_ viewing source.
  */
 struct nsHtml5SilentPolicy
 {
   static const bool reportErrors = false;
@@ -35,9 +35,9 @@ struct nsHtml5ViewSourcePolicy
                             int32_t aPos) {
     return aHighlighter->Transition(aState, aReconsume, aPos);
   }
   static void completedNamedCharacterReference(nsHtml5Highlighter* aHighlighter) {
     aHighlighter->CompletedNamedCharacterReference();
   }
 };
 
-#endif // nsHtml5TokenizerLoopPolicies_h_
+#endif // nsHtml5TokenizerLoopPolicies_h
--- a/parser/html/nsHtml5TreeBuilder.h
+++ b/parser/html/nsHtml5TreeBuilder.h
@@ -23,18 +23,18 @@
  * DEALINGS IN THE SOFTWARE.
  */
 
 /*
  * THIS IS A GENERATED FILE. PLEASE DO NOT EDIT.
  * Please edit TreeBuilder.java instead and regenerate.
  */
 
-#ifndef nsHtml5TreeBuilder_h__
-#define nsHtml5TreeBuilder_h__
+#ifndef nsHtml5TreeBuilder_h
+#define nsHtml5TreeBuilder_h
 
 #include "nsIAtom.h"
 #include "nsHtml5AtomTable.h"
 #include "nsITimer.h"
 #include "nsString.h"
 #include "nsINameSpaceManager.h"
 #include "nsIContent.h"
 #include "nsTraceRefcnt.h"
--- a/parser/html/nsHtml5TreeOpExecutor.h
+++ b/parser/html/nsHtml5TreeOpExecutor.h
@@ -1,14 +1,14 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
-#ifndef nsHtml5TreeOpExecutor_h__
-#define nsHtml5TreeOpExecutor_h__
+#ifndef nsHtml5TreeOpExecutor_h
+#define nsHtml5TreeOpExecutor_h
 
 #include "nsIAtom.h"
 #include "nsINameSpaceManager.h"
 #include "nsIContent.h"
 #include "nsIDocument.h"
 #include "nsTraceRefcnt.h"
 #include "nsHtml5TreeOperation.h"
 #include "nsHtml5SpeculativeLoad.h"
@@ -410,9 +410,9 @@ class nsHtml5TreeOpExecutor : public nsC
 
     /**
      * Get a nsIURI for an nsString if the URL hasn't been preloaded yet.
      */
     already_AddRefed<nsIURI> ConvertIfNotPreloadedYet(const nsAString& aURL);
 
 };
 
-#endif // nsHtml5TreeOpExecutor_h__
+#endif // nsHtml5TreeOpExecutor_h
--- a/parser/html/nsHtml5TreeOpStage.h
+++ b/parser/html/nsHtml5TreeOpStage.h
@@ -1,14 +1,14 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
-#ifndef nsHtml5TreeOpStage_h___
-#define nsHtml5TreeOpStage_h___
+#ifndef nsHtml5TreeOpStage_h
+#define nsHtml5TreeOpStage_h
 
 #include "mozilla/Mutex.h"
 #include "nsHtml5TreeOperation.h"
 #include "nsTArray.h"
 #include "nsAHtml5TreeOpSink.h"
 #include "nsHtml5SpeculativeLoad.h"
 
 class nsHtml5TreeOpStage : public nsAHtml5TreeOpSink {
@@ -46,9 +46,9 @@ class nsHtml5TreeOpStage : public nsAHtm
 
   private:
     nsTArray<nsHtml5TreeOperation> mOpQueue;
     nsTArray<nsHtml5SpeculativeLoad> mSpeculativeLoadQueue;
     mozilla::Mutex mMutex;
     
 };
 
-#endif /* nsHtml5TreeOpStage_h___ */
+#endif /* nsHtml5TreeOpStage_h */
--- a/parser/html/nsHtml5TreeOperation.h
+++ b/parser/html/nsHtml5TreeOperation.h
@@ -1,14 +1,14 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
  
-#ifndef nsHtml5TreeOperation_h__
-#define nsHtml5TreeOperation_h__
+#ifndef nsHtml5TreeOperation_h
+#define nsHtml5TreeOperation_h
 
 #include "nsHtml5DocumentMode.h"
 #include "nsHtml5HtmlAttributes.h"
 #include "nsXPCOMStrings.h"
 
 class nsIContent;
 class nsHtml5TreeOpExecutor;
 class nsHtml5StateSnapshot;
@@ -389,9 +389,9 @@ class nsHtml5TreeOperation {
       PRUnichar*                      unicharPtr;
       char*                           charPtr;
       nsHtml5TreeOperationStringPair* stringPair;
       nsAHtml5TreeBuilderState*       state;
       int32_t                         integer;
     }                   mOne, mTwo, mThree, mFour;
 };
 
-#endif // nsHtml5TreeOperation_h__
+#endif // nsHtml5TreeOperation_h
--- a/parser/html/nsHtml5UTF16Buffer.h
+++ b/parser/html/nsHtml5UTF16Buffer.h
@@ -20,18 +20,18 @@
  * DEALINGS IN THE SOFTWARE.
  */
 
 /*
  * THIS IS A GENERATED FILE. PLEASE DO NOT EDIT.
  * Please edit UTF16Buffer.java instead and regenerate.
  */
 
-#ifndef nsHtml5UTF16Buffer_h__
-#define nsHtml5UTF16Buffer_h__
+#ifndef nsHtml5UTF16Buffer_h
+#define nsHtml5UTF16Buffer_h
 
 #include "nsIAtom.h"
 #include "nsHtml5AtomTable.h"
 #include "nsString.h"
 #include "nsINameSpaceManager.h"
 #include "nsIContent.h"
 #include "nsTraceRefcnt.h"
 #include "jArray.h"
--- a/parser/html/nsHtml5ViewSourceUtils.h
+++ b/parser/html/nsHtml5ViewSourceUtils.h
@@ -1,17 +1,17 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
-#ifndef nsHtml5ViewSourceUtils_h_
-#define nsHtml5ViewSourceUtils_h_
+#ifndef nsHtml5ViewSourceUtils_h
+#define nsHtml5ViewSourceUtils_h
 
 #include "nsHtml5HtmlAttributes.h"
 
 class nsHtml5ViewSourceUtils
 {
   public:
     static nsHtml5HtmlAttributes* NewBodyAttributes();
     static nsHtml5HtmlAttributes* NewLinkAttributes();
 };
 
-#endif // nsHtml5ViewSourceUtils_h_
+#endif // nsHtml5ViewSourceUtils_h
--- a/parser/html/nsParserUtils.h
+++ b/parser/html/nsParserUtils.h
@@ -1,22 +1,22 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
-#ifndef nsParserUtils_h_
-#define nsParserUtils_h_
+#ifndef nsParserUtils_h
+#define nsParserUtils_h
 
 #include "nsIScriptableUnescapeHTML.h"
 #include "nsIParserUtils.h"
 #include "mozilla/Attributes.h"
 
 class nsParserUtils MOZ_FINAL : public nsIScriptableUnescapeHTML,
                                 public nsIParserUtils
 {
 public:
   NS_DECL_ISUPPORTS
   NS_DECL_NSISCRIPTABLEUNESCAPEHTML
   NS_DECL_NSIPARSERUTILS
 };
 
-#endif // nsParserUtils_h_
+#endif // nsParserUtils_h
--- a/parser/htmlparser/tests/mochitest/test_bug418464.html
+++ b/parser/htmlparser/tests/mochitest/test_bug418464.html
@@ -26,19 +26,18 @@ https://bugzilla.mozilla.org/show_bug.cg
 <p id="display"></p>
 <div id="content" style="display: none">
   
 </div>
 <pre id="test">
 <script class="testbody" type="text/javascript">
 
 /** Test for Bug 418464 **/
-  // Commented out until the HTML5 parser is on by default
-  // is(form1 instanceof HTMLFormElement, true,
-  //    "Should have a form here");
+  is(form1 instanceof HTMLFormElement, true,
+     "Should have a form here");
   is(form2 instanceof HTMLFormElement, true,
      "Should have a form here");
 
 </script>
 </pre>
 </body>
 </html>
 
--- a/python/mozbuild/mozbuild/controller/building.py
+++ b/python/mozbuild/mozbuild/controller/building.py
@@ -11,23 +11,19 @@ import os
 import sys
 import time
 
 from collections import (
     namedtuple,
     OrderedDict,
 )
 
-# keep in sync with psutil os support, see psutil/__init__.py
-if sys.platform.startswith("freebsd") or sys.platform.startswith("darwin") or sys.platform.startswith("win32") or sys.platform.startswith("linux"):
-    try:
-        import psutil
-    except ImportError:
-        psutil = None
-else:
+try:
+    import psutil
+except Exception:
     psutil = None
 
 from mozsystemmonitor.resourcemonitor import SystemResourceMonitor
 
 from ..base import MozbuildObject
 
 from ..compilation.warnings import (
     WarningsCollector,
--- a/testing/mochitest/runtests.py
+++ b/testing/mochitest/runtests.py
@@ -71,18 +71,17 @@ class MochitestServer:
     env["ASAN_OPTIONS"] = "quarantine_size=1:redzone=32"
 
     if mozinfo.isWin:
       env["PATH"] = env["PATH"] + ";" + str(self._xrePath)
 
     args = ["-g", self._xrePath,
             "-v", "170",
             "-f", self._httpdPath + "/httpd.js",
-            "-e", """const _PROFILE_PATH = '%(profile)s';const _SERVER_PORT = '%(port)s'; const _SERVER_ADDR = '%(server)s';
-                     const _TEST_PREFIX = %(testPrefix)s; const _DISPLAY_RESULTS = %(displayResults)s;""" %
+            "-e", """const _PROFILE_PATH = '%(profile)s'; const _SERVER_PORT = '%(port)s'; const _SERVER_ADDR = '%(server)s'; const _TEST_PREFIX = %(testPrefix)s; const _DISPLAY_RESULTS = %(displayResults)s;""" %
                    {"profile" : self._profileDir.replace('\\', '\\\\'), "port" : self.httpPort, "server" : self.webServer,
                     "testPrefix" : self.testPrefix, "displayResults" : str(not self._closeWhenDone).lower() },
             "-f", "./" + "server.js"]
 
     xpcshell = os.path.join(self._utilityPath,
                             "xpcshell" + mozinfo.info['bin_suffix'])
     self._process = self._automation.Process([xpcshell] + args, env = env)
     pid = self._process.pid
--- a/testing/mozbase/mozsystemmonitor/mozsystemmonitor/resourcemonitor.py
+++ b/testing/mozbase/mozsystemmonitor/mozsystemmonitor/resourcemonitor.py
@@ -4,17 +4,17 @@
 
 import multiprocessing
 import sys
 import time
 
 # psutil will raise NotImplementedError if the platform is not supported.
 try:
     import psutil
-except (ImportError, NotImplementedError):
+except Exception:
     psutil = None
 
 from collections import (
     OrderedDict,
     namedtuple,
 )
 
 from contextlib import contextmanager
--- a/testing/runcppunittests.py
+++ b/testing/runcppunittests.py
@@ -101,21 +101,29 @@ class CPPUnitTests(object):
         * symbols_path: A path to a directory containing Breakpad-formatted
                         symbol files for producing stack traces on crash.
 
         Returns True if all test programs exited with a zero status, False
         otherwise.
         """
         self.xre_path = xre_path
         env = self.build_environment()
-        result = True
+        pass_count = 0
+        fail_count = 0
         for prog in programs:
             single_result = self.run_one_test(prog, env, symbols_path)
-            result = result and single_result
-        return result
+            if single_result:
+                pass_count += 1
+            else:
+                fail_count += 1
+
+        log.info("Result summary:")
+        log.info("Passed: %d" % pass_count)
+        log.info("Failed: %d" % fail_count)
+        return fail_count == 0
 
 class CPPUnittestOptions(OptionParser):
     def __init__(self):
         OptionParser.__init__(self)
         self.add_option("--xre-path",
                         action = "store", type = "string", dest = "xre_path",
                         default = None,
                         help = "absolute path to directory containing XRE (probably xulrunner)")
--- a/toolkit/components/telemetry/Telemetry.cpp
+++ b/toolkit/components/telemetry/Telemetry.cpp
@@ -2162,16 +2162,35 @@ Accumulate(ID aHistogram, uint32_t aSamp
   }
   Histogram *h;
   nsresult rv = GetHistogramByEnumId(aHistogram, &h);
   if (NS_SUCCEEDED(rv))
     h->Add(aSample);
 }
 
 void
+Accumulate(const char* name, uint32_t sample)
+{
+  if (!TelemetryImpl::CanRecord()) {
+    return;
+  }
+  ID id;
+  nsresult rv = TelemetryImpl::GetHistogramEnumId(name, &id);
+  if (NS_FAILED(rv)) {
+    return;
+  }
+
+  Histogram *h;
+  rv = GetHistogramByEnumId(id, &h);
+  if (NS_SUCCEEDED(rv)) {
+    h->Add(sample);
+  }
+}
+
+void
 AccumulateTimeDelta(ID aHistogram, TimeStamp start, TimeStamp end)
 {
   Accumulate(aHistogram,
              static_cast<uint32_t>((end - start).ToMilliseconds()));
 }
 
 bool
 CanRecord()
--- a/toolkit/components/telemetry/Telemetry.h
+++ b/toolkit/components/telemetry/Telemetry.h
@@ -35,16 +35,27 @@ void Init();
  * Adds sample to a histogram defined in TelemetryHistograms.h
  *
  * @param id - histogram id
  * @param sample - value to record.
  */
 void Accumulate(ID id, uint32_t sample);
 
 /**
+ * Adds a sample to a histogram defined in TelemetryHistograms.h.
+ * This function is here to support telemetry measurements from Java,
+ * where we have only names and not numeric IDs.  You should almost
+ * certainly be using the by-enum-id version instead of this one.
+ *
+ * @param name - histogram name
+ * @param sample - value to record
+ */
+void Accumulate(const char* name, uint32_t sample);
+
+/**
  * Adds time delta in milliseconds to a histogram defined in TelemetryHistograms.h
  *
  * @param id - histogram id
  * @param start - start time
  * @param end - end time
  */
 void AccumulateTimeDelta(ID id, TimeStamp start, TimeStamp end = TimeStamp::Now());
 
--- a/widget/android/AndroidJavaWrappers.cpp
+++ b/widget/android/AndroidJavaWrappers.cpp
@@ -55,16 +55,17 @@ jfieldID AndroidGeckoEvent::jLocationFie
 jfieldID AndroidGeckoEvent::jBandwidthField = 0;
 jfieldID AndroidGeckoEvent::jCanBeMeteredField = 0;
 jfieldID AndroidGeckoEvent::jIsWifiField = 0;
 jfieldID AndroidGeckoEvent::jDHCPGatewayField = 0;
 jfieldID AndroidGeckoEvent::jScreenOrientationField = 0;
 jfieldID AndroidGeckoEvent::jByteBufferField = 0;
 jfieldID AndroidGeckoEvent::jWidthField = 0;
 jfieldID AndroidGeckoEvent::jHeightField = 0;
+jfieldID AndroidGeckoEvent::jPrefNamesField = 0;
 
 jclass AndroidGeckoEvent::jDomKeyLocationClass = 0;
 jfieldID AndroidGeckoEvent::jDomKeyLocationValueField = 0;
 
 jclass AndroidPoint::jPointClass = 0;
 jfieldID AndroidPoint::jXField = 0;
 jfieldID AndroidPoint::jYField = 0;
 
@@ -261,16 +262,17 @@ AndroidGeckoEvent::InitGeckoEventClass(J
     jBandwidthField = getField("mBandwidth", "D");
     jCanBeMeteredField = getField("mCanBeMetered", "Z");
     jIsWifiField = getField("mIsWifi", "Z");
     jDHCPGatewayField = getField("mDHCPGateway", "I");
     jScreenOrientationField = getField("mScreenOrientation", "S");
     jByteBufferField = getField("mBuffer", "Ljava/nio/ByteBuffer;");
     jWidthField = getField("mWidth", "I");
     jHeightField = getField("mHeight", "I");
+    jPrefNamesField = getField("mPrefNames", "[Ljava/lang/String;");
 
     // Init GeckoEvent.DomKeyLocation enum
     jDomKeyLocationClass = getClassGlobalRef("org/mozilla/gecko/GeckoEvent$DomKeyLocation");
     jDomKeyLocationValueField = getField("value", "I");
 }
 
 void
 AndroidLocation::InitLocationClass(JNIEnv *jEnv)
@@ -471,69 +473,77 @@ AndroidGeckoEvent::ReadFloatArray(nsTArr
     jfloat *vals = jenv->GetFloatArrayElements(jFloatArray, NULL);
     for (int32_t i = 0; i < count; i++) {
         aVals.AppendElement(vals[i]);
     }
     jenv->ReleaseFloatArrayElements(jFloatArray, vals, JNI_ABORT);
 }
 
 void
+AndroidGeckoEvent::ReadStringArray(nsTArray<nsString> &array,
+                                   JNIEnv *jenv,
+                                   jfieldID field)
+{
+    jarray jArray = (jarray)jenv->GetObjectField(wrapped_obj, field);
+    jsize length = jenv->GetArrayLength(jArray);
+    jobjectArray jStringArray = (jobjectArray)jArray;
+    nsString *strings = array.AppendElements(length);
+    for (jsize i = 0; i < length; ++i) {
+        jstring javastring = (jstring) jenv->GetObjectArrayElement(jStringArray, i);
+        ReadStringFromJString(strings[i], jenv, javastring);
+    }
+}
+
+void
 AndroidGeckoEvent::ReadRectField(JNIEnv *jenv)
 {
     AndroidRect r(jenv, jenv->GetObjectField(wrappedObject(), jRectField));
     if (!r.isNull()) {
         mRect.SetRect(r.Left(),
                       r.Top(),
                       r.Width(),
                       r.Height());
     } else {
         mRect.SetEmpty();
     }
 }
 
 void
-AndroidGeckoEvent::ReadCharactersField(JNIEnv *jenv)
+AndroidGeckoEvent::ReadStringFromJString(nsString &aString, JNIEnv *jenv,
+                                         jstring s)
 {
-    jstring s = (jstring) jenv->GetObjectField(wrapped_obj, jCharactersField);
     if (!s) {
-        mCharacters.SetIsVoid(true);
+        aString.SetIsVoid(true);
         return;
     }
 
     int len = jenv->GetStringLength(s);
-    mCharacters.SetLength(len);
-    jenv->GetStringRegion(s, 0, len, mCharacters.BeginWriting());
+    aString.SetLength(len);
+    jenv->GetStringRegion(s, 0, len, aString.BeginWriting());
+}
+
+void
+AndroidGeckoEvent::ReadCharactersField(JNIEnv *jenv)
+{
+    jstring s = (jstring) jenv->GetObjectField(wrapped_obj, jCharactersField);
+    ReadStringFromJString(mCharacters, jenv, s);
 }
 
 void
 AndroidGeckoEvent::ReadCharactersExtraField(JNIEnv *jenv)
 {
     jstring s = (jstring) jenv->GetObjectField(wrapped_obj, jCharactersExtraField);
-    if (!s) {
-        mCharactersExtra.SetIsVoid(true);
-        return;
-    }
-
-    int len = jenv->GetStringLength(s);
-    mCharactersExtra.SetLength(len);
-    jenv->GetStringRegion(s, 0, len, mCharactersExtra.BeginWriting());
+    ReadStringFromJString(mCharactersExtra, jenv, s);
 }
 
 void
 AndroidGeckoEvent::ReadDataField(JNIEnv *jenv)
 {
     jstring s = (jstring) jenv->GetObjectField(wrapped_obj, jDataField);
-    if (!s) {
-        mData.SetIsVoid(true);
-        return;
-    }
-
-    int len = jenv->GetStringLength(s);
-    mData.SetLength(len);
-    jenv->GetStringRegion(s, 0, len, mData.BeginWriting());
+    ReadStringFromJString(mData, jenv, s);
 }
 
 void
 AndroidGeckoEvent::UnionRect(nsIntRect const& aRect)
 {
     mRect = aRect.Union(mRect);
 }
 
@@ -706,16 +716,29 @@ AndroidGeckoEvent::Init(JNIEnv *jenv, jo
             break;
         }
 
         case NETWORK_LINK_CHANGE: {
             ReadCharactersField(jenv);
             break;
         }
 
+        case TELEMETRY_HISTOGRAM_ADD: {
+            ReadCharactersField(jenv);
+            mCount = jenv->GetIntField(jobj, jCountField);
+            break;
+        }
+
+        case PREFERENCES_OBSERVE:
+        case PREFERENCES_GET: {
+            ReadStringArray(mPrefNames, jenv, jPrefNamesField);
+            mCount = jenv->GetIntField(jobj, jCountField);
+            break;
+        }
+
         default:
             break;
     }
 
 #ifdef DEBUG_ANDROID_EVENTS
     ALOG("AndroidGeckoEvent: %p : %d", (void*)jobj, mType);
 #endif
 }
--- a/widget/android/AndroidJavaWrappers.h
+++ b/widget/android/AndroidJavaWrappers.h
@@ -534,16 +534,17 @@ public:
     int Type() { return mType; }
     bool AckNeeded() { return mAckNeeded; }
     int64_t Time() { return mTime; }
     const nsTArray<nsIntPoint>& Points() { return mPoints; }
     const nsTArray<int>& PointIndicies() { return mPointIndicies; }
     const nsTArray<float>& Pressures() { return mPressures; }
     const nsTArray<float>& Orientations() { return mOrientations; }
     const nsTArray<nsIntPoint>& PointRadii() { return mPointRadii; }
+    const nsTArray<nsString>& PrefNames() { return mPrefNames; }
     double X() { return mX; }
     double Y() { return mY; }
     double Z() { return mZ; }
     const nsIntRect& Rect() { return mRect; }
     nsAString& Characters() { return mCharacters; }
     nsAString& CharactersExtra() { return mCharactersExtra; }
     nsAString& Data() { return mData; }
     int KeyCode() { return mKeyCode; }
@@ -572,16 +573,17 @@ public:
     double Bandwidth() { return mBandwidth; }
     bool CanBeMetered() { return mCanBeMetered; }
     bool IsWifi() { return mIsWifi; }
     int DHCPGateway() { return mDHCPGateway; }
     short ScreenOrientation() { return mScreenOrientation; }
     RefCountedJavaObject* ByteBuffer() { return mByteBuffer; }
     int Width() { return mWidth; }
     int Height() { return mHeight; }
+    int RequestId() { return mCount; } // for convenience
     nsTouchEvent MakeTouchEvent(nsIWidget* widget);
     MultiTouchInput MakeMultiTouchInput(nsIWidget* widget);
     void UnionRect(nsIntRect const& aRect);
 
 protected:
     int mAction;
     int mType;
     bool mAckNeeded;
@@ -607,33 +609,38 @@ protected:
     nsRefPtr<nsGeoPosition> mGeoPosition;
     double mBandwidth;
     bool mCanBeMetered;
     bool mIsWifi;
     int mDHCPGateway;
     short mScreenOrientation;
     nsRefPtr<RefCountedJavaObject> mByteBuffer;
     int mWidth, mHeight;
+    nsTArray<nsString> mPrefNames;
 
     void ReadIntArray(nsTArray<int> &aVals,
                       JNIEnv *jenv,
                       jfieldID field,
                       int32_t count);
     void ReadFloatArray(nsTArray<float> &aVals,
                         JNIEnv *jenv,
                         jfieldID field,
                         int32_t count);
     void ReadPointArray(nsTArray<nsIntPoint> &mPoints,
                         JNIEnv *jenv,
                         jfieldID field,
                         int32_t count);
+    void ReadStringArray(nsTArray<nsString> &aStrings,
+                         JNIEnv *jenv,
+                         jfieldID field);
     void ReadRectField(JNIEnv *jenv);
     void ReadCharactersField(JNIEnv *jenv);
     void ReadCharactersExtraField(JNIEnv *jenv);
     void ReadDataField(JNIEnv *jenv);
+    void ReadStringFromJString(nsString &aString, JNIEnv *jenv, jstring s);
 
     uint32_t ReadDomKeyLocation(JNIEnv* jenv, jobject jGeckoEventObj);
 
     static jclass jGeckoEventClass;
     static jfieldID jActionField;
     static jfieldID jTypeField;
     static jfieldID jAckNeededField;
     static jfieldID jTimeField;
@@ -666,16 +673,17 @@ protected:
     static jfieldID jRangeTypeField;
     static jfieldID jRangeStylesField;
     static jfieldID jRangeLineStyleField;
     static jfieldID jRangeBoldLineField;
     static jfieldID jRangeForeColorField;
     static jfieldID jRangeBackColorField;
     static jfieldID jRangeLineColorField;
     static jfieldID jLocationField;
+    static jfieldID jPrefNamesField;
 
     static jfieldID jBandwidthField;
     static jfieldID jCanBeMeteredField;
     static jfieldID jIsWifiField;
     static jfieldID jDHCPGatewayField;
 
     static jfieldID jScreenOrientationField;
     static jfieldID jByteBufferField;
@@ -711,16 +719,19 @@ public:
         COMPOSITOR_PAUSE = 29,
         COMPOSITOR_RESUME = 30,
         NATIVE_GESTURE_EVENT = 31,
         IME_KEY_EVENT = 32,
         CALL_OBSERVER = 33,
         REMOVE_OBSERVER = 34,
         LOW_MEMORY = 35,
         NETWORK_LINK_CHANGE = 36,
+        TELEMETRY_HISTOGRAM_ADD = 37,
+        PREFERENCES_OBSERVE = 38,
+        PREFERENCES_GET = 39,
         dummy_java_enum_list_end
     };
 
     enum {
         // Memory pressue levels, keep in sync with those in MemoryMonitor.java
         MEMORY_PRESSURE_NONE = 0,
         MEMORY_PRESSURE_CLEANUP = 1,
         MEMORY_PRESSURE_LOW = 2,
--- a/widget/android/nsAppShell.cpp
+++ b/widget/android/nsAppShell.cpp
@@ -536,16 +536,32 @@ nsAppShell::ProcessNextNativeEvent(bool 
 
         break;
     }
 
     case AndroidGeckoEvent::REMOVE_OBSERVER:
         mObserversHash.Remove(curEvent->Characters());
         break;
 
+    case AndroidGeckoEvent::PREFERENCES_GET:
+    case AndroidGeckoEvent::PREFERENCES_OBSERVE: {
+        const nsTArray<nsString> &prefNames = curEvent->PrefNames();
+        size_t count = prefNames.Length();
+        nsAutoArrayPtr<const PRUnichar*> prefNamePtrs(new const PRUnichar*[count]);
+        for (size_t i = 0; i < count; ++i) {
+            prefNamePtrs[i] = prefNames[i].get();
+        }
+
+        if (curEvent->Type() == AndroidGeckoEvent::PREFERENCES_GET) {
+            mBrowserApp->GetPreferences(curEvent->RequestId(), prefNamePtrs, count);
+        } else {
+            mBrowserApp->ObservePreferences(curEvent->RequestId(), prefNamePtrs, count);
+        }
+    }
+
     case AndroidGeckoEvent::LOW_MEMORY:
         // TODO hook in memory-reduction stuff for different levels here
         if (curEvent->MetaState() >= AndroidGeckoEvent::MEMORY_PRESSURE_MEDIUM) {
             nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService();
             if (os) {
                 os->NotifyObservers(nullptr,
                                     "memory-pressure",
                                     NS_LITERAL_STRING("low-memory").get());
@@ -559,16 +575,21 @@ nsAppShell::ProcessNextNativeEvent(bool 
         if (os) {
             os->NotifyObservers(nullptr,
                                 NS_NETWORK_LINK_TOPIC,
                                 nsString(curEvent->Characters()).get());
         }
         break;
     }
 
+    case AndroidGeckoEvent::TELEMETRY_HISTOGRAM_ADD:
+        Telemetry::Accumulate(NS_ConvertUTF16toUTF8(curEvent->Characters()).get(),
+                              curEvent->Count());
+        break;
+
     case AndroidGeckoEvent::NOOP:
         break;
 
     default:
         nsWindow::OnGlobalAndroidEvent(curEvent);
         break;
     }
 
--- a/widget/android/nsIAndroidBridge.idl
+++ b/widget/android/nsIAndroidBridge.idl
@@ -6,19 +6,25 @@
 #include "nsIDOMWindow.idl"
 
 [scriptable, uuid(0843f3c1-043e-4c64-9d8c-091370548c05)]
 interface nsIBrowserTab : nsISupports {
   readonly attribute nsIDOMWindow window;
   readonly attribute float scale;
 };
 
-[scriptable, uuid(d10377b4-1c90-493a-a532-63cb3f16ee2b)]
+[scriptable, uuid(6455c49b-7497-4eb6-b137-c9e9b68462ec)]
 interface nsIAndroidBrowserApp : nsISupports {
   nsIBrowserTab getBrowserTab(in int32_t tabId);
+  void getPreferences(in int32_t requestId,
+                      [array, size_is(count)] in wstring prefNames,
+                      in unsigned long count);
+  void observePreferences(in int32_t requestId,
+                          [array, size_is(count)] in wstring prefNames,
+                          in unsigned long count);
 };
 [scriptable, uuid(59cfcb35-69b7-47b2-8155-32b193272666)]
 interface nsIAndroidViewport : nsISupports {
   readonly attribute float x;
   readonly attribute float y;
   readonly attribute float width;
   readonly attribute float height;
   readonly attribute float pageLeft;