Merge last PGO-green changeset of mozilla-inbound to mozilla-central
authorEd Morley <emorley@mozilla.com>
Wed, 01 Aug 2012 10:48:01 +0100
changeset 101072 bcfaabb6bac8b4fea120206de9ca70496b96b43a
parent 101027 e5000bb5fa0380000530ef64cc42f32aae7b5e7a (current diff)
parent 101071 f94b5c54e94e5ed7c286b2bdfcbcd497bf7b2733 (diff)
child 101073 f6daa7cc4dd93c1a6d7e7847f2df86371ede6383
child 101084 a26c651ff5cf17aad200823fa48d8ea94ccc5595
push id23208
push useremorley@mozilla.com
push dateWed, 01 Aug 2012 09:49:50 +0000
treeherdermozilla-central@bcfaabb6bac8 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone17.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge last PGO-green changeset of mozilla-inbound to mozilla-central
--- a/browser/base/content/test/browser_alltabslistener.js
+++ b/browser/base/content/test/browser_alltabslistener.js
@@ -126,16 +126,17 @@ function startTest1() {
 }
 
 function startTest2() {
   info("\nTest 2");
   gAllNotifications = [
     "onStateChange",
     "onLocationChange",
     "onSecurityChange",
+    "onSecurityChange",
     "onStateChange"
   ];
   gFrontNotifications = gAllNotifications;
   runTest(gForegroundBrowser, "https://example.com" + gTestPage, startTest3);
 }
 
 function startTest3() {
   info("\nTest 3");
@@ -150,16 +151,17 @@ function startTest3() {
 }
 
 function startTest4() {
   info("\nTest 4");
   gAllNotifications = [
     "onStateChange",
     "onLocationChange",
     "onSecurityChange",
+    "onSecurityChange",
     "onStateChange"
   ];
   gFrontNotifications = [];
   runTest(gBackgroundBrowser, "https://example.com" + gTestPage, startTest5);
 }
 
 function startTest5() {
   info("\nTest 5");
--- a/build/mobile/sutagent/android/RunCmdThread.java
+++ b/build/mobile/sutagent/android/RunCmdThread.java
@@ -42,40 +42,28 @@ public class RunCmdThread extends Thread
 
     public void StopListening()
         {
         bListening = false;
         }
 
     public void run() {
         try {
-            int    nIterations = 0;
-
             SvrSocket.setSoTimeout(5000);
             while (bListening)
                 {
                 try
                     {
                     socket = SvrSocket.accept();
                     CmdWorkerThread theWorker = new CmdWorkerThread(this, socket);
                     theWorker.start();
                     theWorkers.add(theWorker);
                     }
                 catch (SocketTimeoutException toe)
                     {
-                    if (++nIterations > 60)
-                        {
-                        nIterations = 0;
-                        String sRet = SendPing("www.mozilla.org");
-                        if (sRet.contains("3 received"))
-                            handler.post(new doCancelNotification());
-                        else
-                            handler.post(new doSendNotification("SUTAgent - Network Connectivity Error", sRet));
-                        sRet = null;
-                        }
                     continue;
                     }
                 catch (IOException e)
                     {
                     e.printStackTrace();
                     continue;
                     }
                 }
new file mode 100755
--- /dev/null
+++ b/build/unix/build-clang/create-manifest.py
@@ -0,0 +1,55 @@
+#!/bin/python
+
+import os
+import simplejson
+import sys
+import subprocess
+import urllib
+import glob
+
+def check_run(args):
+    r = subprocess.call(args)
+    assert r == 0
+
+old_files = glob.glob('*.manifest') + ['tooltool.py', 'setup.sh']
+for f in old_files:
+    try:
+        os.unlink(f)
+    except:
+        pass
+
+urllib.urlretrieve('https://raw.github.com/jhford/tooltool/master/tooltool.py',
+                   'tooltool.py')
+urllib.urlretrieve('https://hg.mozilla.org/mozilla-central/raw-file/tip/build/unix/build-clang/setup.sh',
+                   'setup.sh')
+
+check_run(['python', 'tooltool.py', '-m', 'linux32.manifest', 'add',
+           'clang-linux32.tar.bz2', 'setup.sh'])
+check_run(['python', 'tooltool.py', '-m', 'linux64.manifest', 'add',
+           'clang-linux64.tar.bz2', 'setup.sh'])
+check_run(['python', 'tooltool.py', '-m', 'darwin.manifest', 'add',
+           'clang-darwin.tar.bz2', 'setup.sh'])
+
+def key_sort(item):
+    item = item[0]
+    if item == 'size':
+        return 0
+    if item == 'digest':
+        return 1
+    if item == 'algorithm':
+        return 3
+    return 4
+
+rev = os.path.basename(os.getcwd()).split('-')[1]
+
+for platform in ['darwin', 'linux32', 'linux64']:
+    old_name = 'clang-' + platform + '.tar.bz2'
+    manifest = platform + '.manifest'
+    data = eval(file(manifest).read())
+    new_name = data[1]['digest']
+    data[1]['filename'] = 'clang.tar.bz2'
+    data = [{'clang_version' : 'r%s' % rev }] + data
+    out = file(manifest,'w')
+    simplejson.dump(data, out, indent=0, item_sort_key=key_sort)
+    out.write('\n')
+    os.rename(old_name, new_name)
--- a/content/base/src/nsXMLHttpRequest.cpp
+++ b/content/base/src/nsXMLHttpRequest.cpp
@@ -2598,18 +2598,18 @@ GetRequestBody(nsIXHRSendable* aSendable
 
 static nsresult
 GetRequestBody(ArrayBuffer* aArrayBuffer, nsIInputStream** aResult,
                nsACString& aContentType, nsACString& aCharset)
 {
   aContentType.SetIsVoid(true);
   aCharset.Truncate();
 
-  PRInt32 length = aArrayBuffer->mLength;
-  char* data = reinterpret_cast<char*>(aArrayBuffer->mData);
+  PRInt32 length = aArrayBuffer->Length();
+  char* data = reinterpret_cast<char*>(aArrayBuffer->Data());
 
   nsCOMPtr<nsIInputStream> stream;
   nsresult rv = NS_NewByteInputStream(getter_AddRefs(stream), data, length,
                                       NS_ASSIGNMENT_COPY);
   NS_ENSURE_SUCCESS(rv, rv);
 
   stream.forget(aResult);
 
--- a/content/canvas/src/WebGLContext.h
+++ b/content/canvas/src/WebGLContext.h
@@ -887,129 +887,129 @@ public:
     void Uniform1f(WebGLUniformLocation* location, WebGLfloat x);
     void Uniform2f(WebGLUniformLocation* location, WebGLfloat x, WebGLfloat y);
     void Uniform3f(WebGLUniformLocation* location, WebGLfloat x, WebGLfloat y,
                    WebGLfloat z);
     void Uniform4f(WebGLUniformLocation* location, WebGLfloat x, WebGLfloat y,
                    WebGLfloat z, WebGLfloat w);
     
     void Uniform1iv(WebGLUniformLocation* location, dom::Int32Array& arr) {
-        Uniform1iv_base(location, arr.mLength, arr.mData);
+        Uniform1iv_base(location, arr.Length(), arr.Data());
     }
     void Uniform1iv(WebGLUniformLocation* location,
                     const dom::Sequence<WebGLint>& arr) {
         Uniform1iv_base(location, arr.Length(), arr.Elements());
     }
     void Uniform1iv_base(WebGLUniformLocation* location, uint32_t arrayLength,
                          const WebGLint* data);
 
     void Uniform2iv(WebGLUniformLocation* location, dom::Int32Array& arr) {
-        Uniform2iv_base(location, arr.mLength, arr.mData);
+        Uniform2iv_base(location, arr.Length(), arr.Data());
     }
     void Uniform2iv(WebGLUniformLocation* location,
                     const dom::Sequence<WebGLint>& arr) {
         Uniform2iv_base(location, arr.Length(), arr.Elements());
     }
     void Uniform2iv_base(WebGLUniformLocation* location, uint32_t arrayLength,
                          const WebGLint* data);
 
     void Uniform3iv(WebGLUniformLocation* location, dom::Int32Array& arr) {
-        Uniform3iv_base(location, arr.mLength, arr.mData);
+        Uniform3iv_base(location, arr.Length(), arr.Data());
     }
     void Uniform3iv(WebGLUniformLocation* location,
                     const dom::Sequence<WebGLint>& arr) {
         Uniform3iv_base(location, arr.Length(), arr.Elements());
     }
     void Uniform3iv_base(WebGLUniformLocation* location, uint32_t arrayLength,
                          const WebGLint* data);
     
     void Uniform4iv(WebGLUniformLocation* location, dom::Int32Array& arr) {
-        Uniform4iv_base(location, arr.mLength, arr.mData);
+        Uniform4iv_base(location, arr.Length(), arr.Data());
     }
     void Uniform4iv(WebGLUniformLocation* location,
                     const dom::Sequence<WebGLint>& arr) {
         Uniform4iv_base(location, arr.Length(), arr.Elements());
     }
     void Uniform4iv_base(WebGLUniformLocation* location, uint32_t arrayLength,
                          const WebGLint* data);
 
     void Uniform1fv(WebGLUniformLocation* location, dom::Float32Array& arr) {
-        Uniform1fv_base(location, arr.mLength, arr.mData);
+        Uniform1fv_base(location, arr.Length(), arr.Data());
     }
     void Uniform1fv(WebGLUniformLocation* location,
                     const dom::Sequence<WebGLfloat>& arr) {
         Uniform1fv_base(location, arr.Length(), arr.Elements());
     }
     void Uniform1fv_base(WebGLUniformLocation* location, uint32_t arrayLength,
                          const WebGLfloat* data);
 
     void Uniform2fv(WebGLUniformLocation* location, dom::Float32Array& arr) {
-        Uniform2fv_base(location, arr.mLength, arr.mData);
+        Uniform2fv_base(location, arr.Length(), arr.Data());
     }
     void Uniform2fv(WebGLUniformLocation* location,
                     const dom::Sequence<WebGLfloat>& arr) {
         Uniform2fv_base(location, arr.Length(), arr.Elements());
     }
     void Uniform2fv_base(WebGLUniformLocation* location, uint32_t arrayLength,
                          const WebGLfloat* data);
 
     void Uniform3fv(WebGLUniformLocation* location, dom::Float32Array& arr) {
-        Uniform3fv_base(location, arr.mLength, arr.mData);
+        Uniform3fv_base(location, arr.Length(), arr.Data());
     }
     void Uniform3fv(WebGLUniformLocation* location,
                     const dom::Sequence<WebGLfloat>& arr) {
         Uniform3fv_base(location, arr.Length(), arr.Elements());
     }
     void Uniform3fv_base(WebGLUniformLocation* location, uint32_t arrayLength,
                          const WebGLfloat* data);
     
     void Uniform4fv(WebGLUniformLocation* location, dom::Float32Array& arr) {
-        Uniform4fv_base(location, arr.mLength, arr.mData);
+        Uniform4fv_base(location, arr.Length(), arr.Data());
     }
     void Uniform4fv(WebGLUniformLocation* location,
                     const dom::Sequence<WebGLfloat>& arr) {
         Uniform4fv_base(location, arr.Length(), arr.Elements());
     }
     void Uniform4fv_base(WebGLUniformLocation* location, uint32_t arrayLength,
                          const WebGLfloat* data);
 
     void UniformMatrix2fv(WebGLUniformLocation* location,
                           WebGLboolean transpose,
                           dom::Float32Array &value) {
-        UniformMatrix2fv_base(location, transpose, value.mLength, value.mData);
+        UniformMatrix2fv_base(location, transpose, value.Length(), value.Data());
     }
     void UniformMatrix2fv(WebGLUniformLocation* location,
                           WebGLboolean transpose,
                           const dom::Sequence<float> &value) {
         UniformMatrix2fv_base(location, transpose, value.Length(),
                               value.Elements());
     }
     void UniformMatrix2fv_base(WebGLUniformLocation* location,
                                WebGLboolean transpose, uint32_t arrayLength,
                                const float* data);
 
     void UniformMatrix3fv(WebGLUniformLocation* location,
                           WebGLboolean transpose,
                           dom::Float32Array &value) {
-        UniformMatrix3fv_base(location, transpose, value.mLength, value.mData);
+        UniformMatrix3fv_base(location, transpose, value.Length(), value.Data());
     }
     void UniformMatrix3fv(WebGLUniformLocation* location,
                           WebGLboolean transpose,
                           const dom::Sequence<float> &value) {
         UniformMatrix3fv_base(location, transpose, value.Length(),
                               value.Elements());
     }
     void UniformMatrix3fv_base(WebGLUniformLocation* location,
                                WebGLboolean transpose, uint32_t arrayLength,
                                const float* data);
 
     void UniformMatrix4fv(WebGLUniformLocation* location,
                           WebGLboolean transpose,
                           dom::Float32Array &value) {
-        UniformMatrix4fv_base(location, transpose, value.mLength, value.mData);
+        UniformMatrix4fv_base(location, transpose, value.Length(), value.Data());
     }
     void UniformMatrix4fv(WebGLUniformLocation* location,
                           WebGLboolean transpose,
                           const dom::Sequence<float> &value) {
         UniformMatrix4fv_base(location, transpose, value.Length(),
                               value.Elements());
     }
     void UniformMatrix4fv_base(WebGLUniformLocation* location,
@@ -1022,44 +1022,44 @@ public:
     void VertexAttrib1f(WebGLuint index, WebGLfloat x0);
     void VertexAttrib2f(WebGLuint index, WebGLfloat x0, WebGLfloat x1);
     void VertexAttrib3f(WebGLuint index, WebGLfloat x0, WebGLfloat x1,
                         WebGLfloat x2);
     void VertexAttrib4f(WebGLuint index, WebGLfloat x0, WebGLfloat x1,
                         WebGLfloat x2, WebGLfloat x3);
 
     void VertexAttrib1fv(WebGLuint idx, dom::Float32Array &arr) {
-        VertexAttrib1fv_base(idx, arr.mLength, arr.mData);
+        VertexAttrib1fv_base(idx, arr.Length(), arr.Data());
     }
     void VertexAttrib1fv(WebGLuint idx, const dom::Sequence<WebGLfloat>& arr) {
         VertexAttrib1fv_base(idx, arr.Length(), arr.Elements());
     }
     void VertexAttrib1fv_base(WebGLuint idx, uint32_t arrayLength,
                               const WebGLfloat* ptr);
 
     void VertexAttrib2fv(WebGLuint idx, dom::Float32Array &arr) {
-        VertexAttrib2fv_base(idx, arr.mLength, arr.mData);
+        VertexAttrib2fv_base(idx, arr.Length(), arr.Data());
     }
     void VertexAttrib2fv(WebGLuint idx, const dom::Sequence<WebGLfloat>& arr) {
         VertexAttrib2fv_base(idx, arr.Length(), arr.Elements());
     }
     void VertexAttrib2fv_base(WebGLuint idx, uint32_t arrayLength,
                               const WebGLfloat* ptr);
 
     void VertexAttrib3fv(WebGLuint idx, dom::Float32Array &arr) {
-        VertexAttrib3fv_base(idx, arr.mLength, arr.mData);
+        VertexAttrib3fv_base(idx, arr.Length(), arr.Data());
     }
     void VertexAttrib3fv(WebGLuint idx, const dom::Sequence<WebGLfloat>& arr) {
         VertexAttrib3fv_base(idx, arr.Length(), arr.Elements());
     }
     void VertexAttrib3fv_base(WebGLuint idx, uint32_t arrayLength,
                               const WebGLfloat* ptr);
 
     void VertexAttrib4fv(WebGLuint idx, dom::Float32Array &arr) {
-        VertexAttrib4fv_base(idx, arr.mLength, arr.mData);
+        VertexAttrib4fv_base(idx, arr.Length(), arr.Data());
     }
     void VertexAttrib4fv(WebGLuint idx, const dom::Sequence<WebGLfloat>& arr) {
         VertexAttrib4fv_base(idx, arr.Length(), arr.Elements());
     }
     void VertexAttrib4fv_base(WebGLuint idx, uint32_t arrayLength,
                               const WebGLfloat* ptr);
     
     void VertexAttribPointer(WebGLuint index, WebGLint size, WebGLenum type,
--- a/content/canvas/src/WebGLContextGL.cpp
+++ b/content/canvas/src/WebGLContextGL.cpp
@@ -541,26 +541,26 @@ WebGLContext::BufferData(WebGLenum targe
     if (!ValidateBufferUsageEnum(usage, "bufferData: usage"))
         return;
 
     if (!boundBuffer)
         return ErrorInvalidOperation("bufferData: no buffer bound!");
 
     MakeContextCurrent();
 
-    GLenum error = CheckedBufferData(target, data->mLength, data->mData, usage);
+    GLenum error = CheckedBufferData(target, data->Length(), data->Data(), usage);
 
     if (error) {
         GenerateWarning("bufferData generated error %s", ErrorName(error));
         return;
     }
 
-    boundBuffer->SetByteLength(data->mLength);
+    boundBuffer->SetByteLength(data->Length());
     boundBuffer->InvalidateCachedMaxElements();
-    if (!boundBuffer->CopyDataIfElementArray(data->mData))
+    if (!boundBuffer->CopyDataIfElementArray(data->Data()))
         return ErrorOutOfMemory("bufferData: out of memory");
 }
 
 void
 WebGLContext::BufferData(WebGLenum target, ArrayBufferView& data, WebGLenum usage)
 {
     if (!IsContextStable())
         return;
@@ -578,25 +578,25 @@ WebGLContext::BufferData(WebGLenum targe
     if (!ValidateBufferUsageEnum(usage, "bufferData: usage"))
         return;
 
     if (!boundBuffer)
         return ErrorInvalidOperation("bufferData: no buffer bound!");
 
     MakeContextCurrent();
 
-    GLenum error = CheckedBufferData(target, data.mLength, data.mData, usage);
+    GLenum error = CheckedBufferData(target, data.Length(), data.Data(), usage);
     if (error) {
         GenerateWarning("bufferData generated error %s", ErrorName(error));
         return;
     }
 
-    boundBuffer->SetByteLength(data.mLength);
+    boundBuffer->SetByteLength(data.Length());
     boundBuffer->InvalidateCachedMaxElements();
-    if (!boundBuffer->CopyDataIfElementArray(data.mData))
+    if (!boundBuffer->CopyDataIfElementArray(data.Data()))
         return ErrorOutOfMemory("bufferData: out of memory");
 }
 
 NS_IMETHODIMP
 WebGLContext::BufferSubData(WebGLenum target, WebGLintptr offset, const JS::Value& data, JSContext *cx)
 {
     if (!IsContextStable())
         return NS_OK;
@@ -649,30 +649,30 @@ WebGLContext::BufferSubData(GLenum targe
     }
 
     if (byteOffset < 0)
         return ErrorInvalidValue("bufferSubData: negative offset");
 
     if (!boundBuffer)
         return ErrorInvalidOperation("bufferData: no buffer bound!");
 
-    CheckedUint32 checked_neededByteLength = CheckedUint32(byteOffset) + data->mLength;
+    CheckedUint32 checked_neededByteLength = CheckedUint32(byteOffset) + data->Length();
     if (!checked_neededByteLength.isValid())
         return ErrorInvalidOperation("bufferSubData: integer overflow computing the needed byte length");
 
     if (checked_neededByteLength.value() > boundBuffer->ByteLength())
         return ErrorInvalidOperation("bufferSubData: not enough data - operation requires %d bytes, but buffer only has %d bytes",
                                      checked_neededByteLength.value(), boundBuffer->ByteLength());
 
     MakeContextCurrent();
 
-    boundBuffer->CopySubDataIfElementArray(byteOffset, data->mLength, data->mData);
+    boundBuffer->CopySubDataIfElementArray(byteOffset, data->Length(), data->Data());
     boundBuffer->InvalidateCachedMaxElements();
 
-    gl->fBufferSubData(target, byteOffset, data->mLength, data->mData);
+    gl->fBufferSubData(target, byteOffset, data->Length(), data->Data());
 }
 
 void
 WebGLContext::BufferSubData(WebGLenum target, WebGLsizeiptr byteOffset,
                             ArrayBufferView& data)
 {
     if (!IsContextStable())
         return;
@@ -688,30 +688,30 @@ WebGLContext::BufferSubData(WebGLenum ta
     }
 
     if (byteOffset < 0)
         return ErrorInvalidValue("bufferSubData: negative offset");
 
     if (!boundBuffer)
         return ErrorInvalidOperation("bufferSubData: no buffer bound!");
 
-    CheckedUint32 checked_neededByteLength = CheckedUint32(byteOffset) + data.mLength;
+    CheckedUint32 checked_neededByteLength = CheckedUint32(byteOffset) + data.Length();
     if (!checked_neededByteLength.isValid())
         return ErrorInvalidOperation("bufferSubData: integer overflow computing the needed byte length");
 
     if (checked_neededByteLength.value() > boundBuffer->ByteLength())
         return ErrorInvalidOperation("bufferSubData: not enough data -- operation requires %d bytes, but buffer only has %d bytes",
                                      checked_neededByteLength.value(), boundBuffer->ByteLength());
 
     MakeContextCurrent();
 
-    boundBuffer->CopySubDataIfElementArray(byteOffset, data.mLength, data.mData);
+    boundBuffer->CopySubDataIfElementArray(byteOffset, data.Length(), data.Data());
     boundBuffer->InvalidateCachedMaxElements();
 
-    gl->fBufferSubData(target, byteOffset, data.mLength, data.mData);
+    gl->fBufferSubData(target, byteOffset, data.Length(), data.Data());
 }
 
 NS_IMETHODIMP
 WebGLContext::CheckFramebufferStatus(WebGLenum target, WebGLenum *retval)
 {
     *retval = CheckFramebufferStatus(target);
     return NS_OK;
 }
@@ -3871,19 +3871,19 @@ WebGLContext::ReadPixels(WebGLint x, Web
 
     if (!pixels)
         return ErrorInvalidValue("readPixels: null destination buffer");
 
     const WebGLRectangleObject *framebufferRect = FramebufferRectangleObject();
     WebGLsizei framebufferWidth = framebufferRect ? framebufferRect->Width() : 0;
     WebGLsizei framebufferHeight = framebufferRect ? framebufferRect->Height() : 0;
 
-    void* data = pixels->mData;
-    uint32_t dataByteLen = JS_GetTypedArrayByteLength(pixels->mObj, NULL);
-    int dataType = JS_GetTypedArrayType(pixels->mObj, NULL);
+    void* data = pixels->Data();
+    uint32_t dataByteLen = JS_GetTypedArrayByteLength(pixels->Obj(), NULL);
+    int dataType = JS_GetTypedArrayType(pixels->Obj(), NULL);
 
     uint32_t channels = 0;
 
     // Check the format param
     switch (format) {
         case LOCAL_GL_ALPHA:
             channels = 1;
             break;
@@ -5141,22 +5141,22 @@ WebGLContext::CompressedTexImage2D(WebGL
         return;
     }
 
     if (border) {
         ErrorInvalidValue("compressedTexImage2D: border is not 0");
         return;
     }
 
-    uint32_t byteLength = view.mLength;
+    uint32_t byteLength = view.Length();
     if (!ValidateCompressedTextureSize(level, internalformat, width, height, byteLength, "compressedTexImage2D")) {
         return;
     }
 
-    gl->fCompressedTexImage2D(target, level, internalformat, width, height, border, byteLength, view.mData);
+    gl->fCompressedTexImage2D(target, level, internalformat, width, height, border, byteLength, view.Data());
     tex->SetImageInfo(target, level, width, height, internalformat, LOCAL_GL_UNSIGNED_BYTE);
 }
 
 NS_IMETHODIMP
 WebGLContext::CompressedTexSubImage2D(WebGLenum target, WebGLint level, WebGLint xoffset,
                                       WebGLint yoffset, WebGLsizei width, WebGLsizei height,
                                       WebGLenum format, const JS::Value& pixels, JSContext *cx)
 {
@@ -5202,17 +5202,17 @@ WebGLContext::CompressedTexSubImage2D(We
         ErrorInvalidEnum("compressedTexSubImage2D: compressed texture format 0x%x is not supported", format);
         return;
     }
 
     if (!ValidateLevelWidthHeightForTarget(target, level, width, height, "compressedTexSubImage2D")) {
         return;
     }
 
-    uint32_t byteLength = view.mLength;
+    uint32_t byteLength = view.Length();
     if (!ValidateCompressedTextureSize(level, format, width, height, byteLength, "compressedTexSubImage2D")) {
         return;
     }
 
     size_t face = WebGLTexture::FaceForTarget(target);
 
     if (!tex->HasImageInfoAt(level, face)) {
         ErrorInvalidOperation("compressedTexSubImage2D: no texture image previously defined for this level and face");
@@ -5247,17 +5247,17 @@ WebGLContext::CompressedTexSubImage2D(We
             if (height % 4 != 0 && height != imageInfo.Height()) {
                 ErrorInvalidOperation("compressedTexSubImage2D: height is not a multiple of 4 or equal to texture height");
                 return;
             }
             break;
         }
     }
 
-    gl->fCompressedTexSubImage2D(target, level, xoffset, yoffset, width, height, format, byteLength, view.mData);
+    gl->fCompressedTexSubImage2D(target, level, xoffset, yoffset, width, height, format, byteLength, view.Data());
 
     return;
 }
 
 NS_IMETHODIMP
 WebGLContext::GetShaderParameter(nsIWebGLShader *sobj, WebGLenum pname, JS::Value *retval)
 {
     *retval = GetShaderParameter(static_cast<WebGLShader*>(sobj), pname);
@@ -5737,19 +5737,19 @@ WebGLContext::TexImage2D(JSContext* cx, 
                          WebGLenum internalformat, WebGLsizei width,
                          WebGLsizei height, WebGLint border, WebGLenum format,
                          WebGLenum type, ArrayBufferView *pixels, ErrorResult& rv)
 {
     if (!IsContextStable())
         return;
 
     return TexImage2D_base(target, level, internalformat, width, height, 0, border, format, type,
-                           pixels ? pixels->mData : 0,
-                           pixels ? pixels->mLength : 0,
-                           pixels ? (int)JS_GetTypedArrayType(pixels->mObj, cx) : -1,
+                           pixels ? pixels->Data() : 0,
+                           pixels ? pixels->Length() : 0,
+                           pixels ? (int)JS_GetTypedArrayType(pixels->Obj(), cx) : -1,
                            WebGLTexelConversions::Auto, false);
 }
 
 NS_IMETHODIMP
 WebGLContext::TexImage2D_imageData(WebGLenum target, WebGLint level, WebGLenum internalformat,
                                    WebGLsizei width, WebGLsizei height, WebGLint border,
                                    WebGLenum format, WebGLenum type,
                                    JSObject *pixels, JSContext *cx)
@@ -5778,17 +5778,17 @@ WebGLContext::TexImage2D(JSContext* cx, 
     if (!pixels) {
         // Spec says to generate an INVALID_VALUE error
         return ErrorInvalidValue("texImage2D: null ImageData");
     }
     
     Uint8ClampedArray arr(cx, pixels->GetDataObject());
     return TexImage2D_base(target, level, internalformat, pixels->GetWidth(),
                            pixels->GetHeight(), 4*pixels->GetWidth(), 0,
-                           format, type, arr.mData, arr.mLength, -1,
+                           format, type, arr.Data(), arr.Length(), -1,
                            WebGLTexelConversions::RGBA8, false);
 }
 
 
 NS_IMETHODIMP
 WebGLContext::TexImage2D_dom(WebGLenum target, WebGLint level, WebGLenum internalformat,
                              WebGLenum format, GLenum type, Element* elt)
 {
@@ -5943,18 +5943,18 @@ WebGLContext::TexSubImage2D(JSContext* c
     if (!IsContextStable())
         return;
 
     if (!pixels)
         return ErrorInvalidValue("texSubImage2D: pixels must not be null!");
 
     return TexSubImage2D_base(target, level, xoffset, yoffset,
                               width, height, 0, format, type,
-                              pixels->mData, pixels->mLength,
-                              JS_GetTypedArrayType(pixels->mObj, cx),
+                              pixels->Data(), pixels->Length(),
+                              JS_GetTypedArrayType(pixels->Obj(), cx),
                               WebGLTexelConversions::Auto, false);
 }
 
 NS_IMETHODIMP
 WebGLContext::TexSubImage2D_imageData(WebGLenum target, WebGLint level,
                                       WebGLint xoffset, WebGLint yoffset,
                                       WebGLsizei width, WebGLsizei height,
                                       WebGLenum format, WebGLenum type,
@@ -5989,17 +5989,17 @@ WebGLContext::TexSubImage2D(JSContext* c
 
     if (!pixels)
         return ErrorInvalidValue("texSubImage2D: pixels must not be null!");
 
     Uint8ClampedArray arr(cx, pixels->GetDataObject());
     return TexSubImage2D_base(target, level, xoffset, yoffset,
                               pixels->GetWidth(), pixels->GetHeight(),
                               4*pixels->GetWidth(), format, type,
-                              arr.mData, arr.mLength,
+                              arr.Data(), arr.Length(),
                               -1,
                               WebGLTexelConversions::RGBA8, false);
 }
 
 NS_IMETHODIMP
 WebGLContext::TexSubImage2D_dom(WebGLenum target, WebGLint level,
                                 WebGLint xoffset, WebGLint yoffset,
                                 WebGLenum format, WebGLenum type,
--- a/content/canvas/src/nsCanvasRenderingContext2DAzure.cpp
+++ b/content/canvas/src/nsCanvasRenderingContext2DAzure.cpp
@@ -4347,17 +4347,17 @@ nsCanvasRenderingContext2DAzure::PutImag
     error.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
     return;
   }
 
   dom::Uint8ClampedArray arr(cx, imageData->GetDataObject());
 
   error = PutImageData_explicit(JS_DoubleToInt32(dx), JS_DoubleToInt32(dy),
                                 imageData->GetWidth(), imageData->GetHeight(),
-                                arr.mData, arr.mLength, false, 0, 0, 0, 0);
+                                arr.Data(), arr.Length(), false, 0, 0, 0, 0);
 }
 
 void
 nsCanvasRenderingContext2DAzure::PutImageData(JSContext* cx,
                                               ImageData* imageData, double dx,
                                               double dy, double dirtyX,
                                               double dirtyY, double dirtyWidth,
                                               double dirtyHeight,
@@ -4367,17 +4367,17 @@ nsCanvasRenderingContext2DAzure::PutImag
     error.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
     return;
   }
 
   dom::Uint8ClampedArray arr(cx, imageData->GetDataObject());
 
   error = PutImageData_explicit(JS_DoubleToInt32(dx), JS_DoubleToInt32(dy),
                                 imageData->GetWidth(), imageData->GetHeight(),
-                                arr.mData, arr.mLength, true,
+                                arr.Data(), arr.Length(), true,
                                 JS_DoubleToInt32(dirtyX),
                                 JS_DoubleToInt32(dirtyY),
                                 JS_DoubleToInt32(dirtyWidth),
                                 JS_DoubleToInt32(dirtyHeight));
 }
 
 // void putImageData (in ImageData d, in float x, in float y);
 // void putImageData (in ImageData d, in double x, in double y, in double dirtyX, in double dirtyY, in double dirtyWidth, in double dirtyHeight);
--- a/content/html/content/src/nsHTMLAudioElement.cpp
+++ b/content/html/content/src/nsHTMLAudioElement.cpp
@@ -184,17 +184,17 @@ nsHTMLAudioElement::MozCurrentSampleOffs
   if (!mAudioStream) {
     return NS_ERROR_DOM_INVALID_STATE_ERR;
   }
 
   PRInt64 position = mAudioStream->GetPositionInFrames();
   if (position < 0) {
     *aRetVal = 0;
   } else {
-    *aRetVal = mAudioStream->GetPositionInFrames() * mChannels;
+    *aRetVal = position * mChannels;
   }
   return NS_OK;
 }
 
 nsresult nsHTMLAudioElement::SetAcceptHeader(nsIHttpChannel* aChannel)
 {
     nsCAutoString value(
 #ifdef MOZ_WEBM
--- a/content/media/ogg/nsOggReader.cpp
+++ b/content/media/ogg/nsOggReader.cpp
@@ -1648,21 +1648,20 @@ nsresult nsOggReader::GetBuffered(nsTime
       else if (IsKnownStream(serial)) {
         // Stream is not the theora or vorbis stream we're playing,
         // but is one that we have header data for.
         startOffset += page.header_len + page.body_len;
         continue;
       }
       else {
         // Page is for a stream we don't know about (possibly a chained
-        // ogg), return an error.
-        //
-        // XXX Invalid cast of PageSyncResult to nsresult -- this has numeric
-        // value 1 and will pass an NS_SUCCEEDED() check (bug 778105)
-        return (nsresult)PAGE_SYNC_ERROR;
+        // ogg), return OK to abort the finding any further ranges. This
+        // prevents us searching through the rest of the media when we
+        // may not be able to extract timestamps from it.
+        return NS_OK;
       }
     }
 
     if (startTime != -1) {
       // We were able to find a start time for that range, see if we can
       // find an end time.
       PRInt64 endTime = RangeEndTime(startOffset, endOffset, true);
       if (endTime != -1) {
--- a/dom/base/nsDOMClassInfo.cpp
+++ b/dom/base/nsDOMClassInfo.cpp
@@ -511,16 +511,17 @@ using mozilla::dom::indexedDB::IDBWrappe
 #include "nsIDOMVoicemailEvent.h"
 #endif
 
 #ifdef MOZ_B2G_BT
 #include "BluetoothManager.h"
 #include "BluetoothAdapter.h"
 #include "BluetoothDevice.h"
 #include "BluetoothDeviceEvent.h"
+#include "BluetoothPropertyEvent.h"
 #endif
 
 #include "nsIDOMNavigatorSystemMessages.h"
 
 #include "mozilla/dom/Activity.h"
 
 #include "DOMCameraManager.h"
 #include "CameraControl.h"
@@ -1665,16 +1666,18 @@ static nsDOMClassInfoData sClassInfoData
   NS_DEFINE_CLASSINFO_DATA(BluetoothManager, nsEventTargetSH,
                            EVENTTARGET_SCRIPTABLE_FLAGS)
   NS_DEFINE_CLASSINFO_DATA(BluetoothAdapter, nsEventTargetSH,
                            EVENTTARGET_SCRIPTABLE_FLAGS)  
   NS_DEFINE_CLASSINFO_DATA(BluetoothDevice, nsEventTargetSH,
                            EVENTTARGET_SCRIPTABLE_FLAGS)
   NS_DEFINE_CLASSINFO_DATA(BluetoothDeviceEvent, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
+  NS_DEFINE_CLASSINFO_DATA(BluetoothPropertyEvent, nsDOMGenericSH,
+                           DOM_DEFAULT_SCRIPTABLE_FLAGS)
 #endif
 
   NS_DEFINE_CLASSINFO_DATA(CameraManager, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
   NS_DEFINE_CLASSINFO_DATA(CameraControl, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
   NS_DEFINE_CLASSINFO_DATA(CameraCapabilities, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
@@ -4462,16 +4465,21 @@ nsDOMClassInfo::Init()
   DOM_CLASSINFO_MAP_BEGIN(BluetoothDevice, nsIDOMBluetoothDevice)
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMBluetoothDevice)
   DOM_CLASSINFO_MAP_END
 
   DOM_CLASSINFO_MAP_BEGIN(BluetoothDeviceEvent, nsIDOMBluetoothDeviceEvent)
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMBluetoothDeviceEvent)
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMEvent)
   DOM_CLASSINFO_MAP_END
+
+  DOM_CLASSINFO_MAP_BEGIN(BluetoothPropertyEvent, nsIDOMBluetoothPropertyEvent)
+    DOM_CLASSINFO_MAP_ENTRY(nsIDOMBluetoothPropertyEvent)
+    DOM_CLASSINFO_MAP_ENTRY(nsIDOMEvent)
+  DOM_CLASSINFO_MAP_END
 #endif
 
   DOM_CLASSINFO_MAP_BEGIN(CameraManager, nsIDOMCameraManager)
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMCameraManager)
   DOM_CLASSINFO_MAP_END
 
   DOM_CLASSINFO_MAP_BEGIN(CameraControl, nsICameraControl)
     DOM_CLASSINFO_MAP_ENTRY(nsICameraControl)
--- a/dom/base/nsDOMClassInfoClasses.h
+++ b/dom/base/nsDOMClassInfoClasses.h
@@ -519,16 +519,17 @@ DOMCI_CLASS(MozVoicemail)
 DOMCI_CLASS(MozVoicemailEvent)
 #endif
 
 #ifdef MOZ_B2G_BT
 DOMCI_CLASS(BluetoothManager)
 DOMCI_CLASS(BluetoothAdapter)
 DOMCI_CLASS(BluetoothDevice)
 DOMCI_CLASS(BluetoothDeviceEvent)
+DOMCI_CLASS(BluetoothPropertyEvent)
 #endif
 
 DOMCI_CLASS(CameraManager)
 DOMCI_CLASS(CameraControl)
 DOMCI_CLASS(CameraCapabilities)
 
 DOMCI_CLASS(DOMError)
 DOMCI_CLASS(DOMRequest)
--- a/dom/base/nsJSEnvironment.cpp
+++ b/dom/base/nsJSEnvironment.cpp
@@ -105,16 +105,19 @@ static PRLogModuleInfo* gJSDiagnostics;
 
 #define NS_FULL_GC_DELAY            60000 // ms
 
 #define NS_MAX_COMPARTMENT_GC_COUNT 20
 
 // Maximum amount of time that should elapse between incremental GC slices
 #define NS_INTERSLICE_GC_DELAY      100 // ms
 
+// If we haven't painted in 100ms, we allow for a longer GC budget
+#define NS_INTERSLICE_GC_BUDGET     40 // ms
+
 // The amount of time we wait between a request to CC (after GC ran)
 // and doing the actual CC.
 #define NS_CC_DELAY                 6000 // ms
 
 #define NS_CC_SKIPPABLE_DELAY       400 // ms
 
 // Force a CC after this long if there's more than NS_CC_FORCED_PURPLE_LIMIT
 // objects in the purple buffer.
@@ -2904,21 +2907,24 @@ FullGCTimerFired(nsITimer* aTimer, void*
                                  nsJSContext::IncrementalGC);
 }
 
 //static
 void
 nsJSContext::GarbageCollectNow(js::gcreason::Reason aReason,
                                IsIncremental aIncremental,
                                IsCompartment aCompartment,
-                               IsShrinking aShrinking)
+                               IsShrinking aShrinking,
+                               int64_t aSliceMillis)
 {
   NS_TIME_FUNCTION_MIN(1.0);
   SAMPLE_LABEL("GC", "GarbageCollectNow");
 
+  MOZ_ASSERT_IF(aSliceMillis, aIncremental == IncrementalGC);
+
   KillGCTimer();
   KillShrinkGCBuffersTimer();
 
   // Reset sPendingLoadCount in case the timer that fired was a
   // timer we scheduled due to a normal GC timer firing while
   // documents were loading. If this happens we're waiting for a
   // document that is taking a long time to load, and we effectively
   // ignore the fact that the currently loading documents are still
@@ -2928,17 +2934,17 @@ nsJSContext::GarbageCollectNow(js::gcrea
 
   if (!nsContentUtils::XPConnect() || !nsJSRuntime::sRuntime) {
     return;
   }
 
   if (sCCLockedOut && aIncremental == IncrementalGC) {
     // We're in the middle of incremental GC. Do another slice.
     js::PrepareForIncrementalGC(nsJSRuntime::sRuntime);
-    js::IncrementalGC(nsJSRuntime::sRuntime, aReason);
+    js::IncrementalGC(nsJSRuntime::sRuntime, aReason, aSliceMillis);
     return;
   }
 
   // Use compartment GC when we're not asked to do a shrinking GC nor
   // global GC and compartment GC has been called less than
   // NS_MAX_COMPARTMENT_GC_COUNT times after the previous global GC.
   if (!sDisableExplicitCompartmentGC &&
       aShrinking != ShrinkingGC && aCompartment != NonCompartmentGC &&
@@ -2949,30 +2955,30 @@ nsJSContext::GarbageCollectNow(js::gcrea
         if (JSObject* global = cx->GetNativeGlobal()) {
           js::SkipCompartmentForGC(js::GetObjectCompartment(global));
         }
       }
       cx->mActive = false;
     }
     if (js::IsGCScheduled(nsJSRuntime::sRuntime)) {
       if (aIncremental == IncrementalGC) {
-        js::IncrementalGC(nsJSRuntime::sRuntime, aReason);
+        js::IncrementalGC(nsJSRuntime::sRuntime, aReason, aSliceMillis);
       } else {
         js::GCForReason(nsJSRuntime::sRuntime, aReason);
       }
     }
     return;
   }
 
   for (nsJSContext* cx = sContextList; cx; cx = cx->mNext) {
     cx->mActive = false;
   }
   js::PrepareForFullGC(nsJSRuntime::sRuntime);
   if (aIncremental == IncrementalGC) {
-    js::IncrementalGC(nsJSRuntime::sRuntime, aReason);
+    js::IncrementalGC(nsJSRuntime::sRuntime, aReason, aSliceMillis);
   } else {
     js::GCForReason(nsJSRuntime::sRuntime, aReason);
   }
 }
 
 //static
 void
 nsJSContext::ShrinkGCBuffersNow()
@@ -3212,23 +3218,31 @@ nsJSContext::CycleCollectNow(nsICycleCol
   sTotalForgetSkippableTime = 0;
   sRemovedPurples = 0;
   sForgetSkippableBeforeCC = 0;
   sNeedsFullCC = false;
 }
 
 // static
 void
+InterSliceGCTimerFired(nsITimer *aTimer, void *aClosure)
+{
+  NS_RELEASE(sInterSliceGCTimer);
+  nsJSContext::GarbageCollectNow(js::gcreason::INTER_SLICE_GC,
+                                 nsJSContext::IncrementalGC,
+                                 nsJSContext::CompartmentGC,
+                                 nsJSContext::NonShrinkingGC,
+                                 NS_INTERSLICE_GC_BUDGET);
+}
+
+// static
+void
 GCTimerFired(nsITimer *aTimer, void *aClosure)
 {
-  if (aTimer == sGCTimer) {
-    NS_RELEASE(sGCTimer);
-  } else {
-    NS_RELEASE(sInterSliceGCTimer);
-  }
+  NS_RELEASE(sGCTimer);
 
   uintptr_t reason = reinterpret_cast<uintptr_t>(aClosure);
   nsJSContext::GarbageCollectNow(static_cast<js::gcreason::Reason>(reason),
                                  nsJSContext::IncrementalGC,
                                  nsJSContext::CompartmentGC);
 }
 
 void
@@ -3541,19 +3555,18 @@ DOMGCSliceCallback(JSRuntime *aRt, js::G
   } else if (aProgress == js::GC_CYCLE_END) {
     sCCLockedOut = false;
   }
 
   // The GC has more work to do, so schedule another GC slice.
   if (aProgress == js::GC_SLICE_END) {
     nsJSContext::KillInterSliceGCTimer();
     CallCreateInstance("@mozilla.org/timer;1", &sInterSliceGCTimer);
-    js::gcreason::Reason reason = js::gcreason::INTER_SLICE_GC;
-    sInterSliceGCTimer->InitWithFuncCallback(GCTimerFired,
-                                             reinterpret_cast<void *>(reason),
+    sInterSliceGCTimer->InitWithFuncCallback(InterSliceGCTimerFired,
+                                             NULL,
                                              NS_INTERSLICE_GC_DELAY,
                                              nsITimer::TYPE_ONE_SHOT);
   }
 
   if (aProgress == js::GC_CYCLE_END) {
     // May need to kill the inter-slice GC timer
     nsJSContext::KillInterSliceGCTimer();
 
--- a/dom/base/nsJSEnvironment.h
+++ b/dom/base/nsJSEnvironment.h
@@ -159,17 +159,18 @@ public:
   enum IsIncremental {
     IncrementalGC,
     NonIncrementalGC
   };
 
   static void GarbageCollectNow(js::gcreason::Reason reason,
                                 IsIncremental aIncremental = NonIncrementalGC,
                                 IsCompartment aCompartment = NonCompartmentGC,
-                                IsShrinking aShrinking = NonShrinkingGC);
+                                IsShrinking aShrinking = NonShrinkingGC,
+                                int64_t aSliceMillis = 0);
   static void ShrinkGCBuffersNow();
   // If aExtraForgetSkippableCalls is -1, forgetSkippable won't be
   // called even if the previous collection was GC.
   static void CycleCollectNow(nsICycleCollectorListener *aListener = nullptr,
                               PRInt32 aExtraForgetSkippableCalls = 0,
                               bool aForced = true);
 
   static void PokeGC(js::gcreason::Reason aReason, int aDelay = 0);
--- a/dom/bindings/Codegen.py
+++ b/dom/bindings/Codegen.py
@@ -1967,50 +1967,45 @@ for (uint32_t i = 0; i < length; ++i) {
         return (templateBody, declType, holderType, isOptional)
 
     if type.isSpiderMonkeyInterface():
         if isMember:
             raise TypeError("Can't handle member arraybuffers or "
                             "arraybuffer views because making sure all the "
                             "objects are properly rooted is hard")
         name = type.name
-        if type.isArrayBuffer():
-            jsname = "ArrayBufferObject"
-        elif type.isArrayBufferView():
-            jsname = "ArrayBufferViewObject"
-        else:
-            jsname = type.name
-
         # By default, we use a Maybe<> to hold our typed array.  And in the optional
         # non-nullable case we want to pass Optional<TypedArray> to consumers, not
         # Optional<NonNull<TypedArray> >, so jump though some hoops to do that.
         holderType = "Maybe<%s>" % name
         constructLoc = "${holderName}"
         constructMethod = "construct"
+        constructInternal = "ref"
         if type.nullable():
             if isOptional:
                 declType = "const Optional<" + name + "*>"
             else:
                 declType = name + "*"
         else:
             if isOptional:
                 declType = "const Optional<" + name + ">"
                 # We don't need a holder in this case
                 holderType = None
                 constructLoc = "(const_cast<Optional<" + name + ">& >(${declName}))"
                 constructMethod = "Construct"
+                constructInternal = "Value"
             else:
                 declType = "NonNull<" + name + ">"
         template = (
-            "if (!JS_Is%s(&${val}.toObject(), cx)) {\n"
+            "%s.%s(cx, &${val}.toObject());\n"
+            "if (!%s.%s().inited()) {\n"
             "%s" # No newline here because onFailure() handles that
-            "}\n"
-            "%s.%s(cx, &${val}.toObject());\n" %
-            (jsname, CGIndenter(onFailure(failureCode, descriptorProvider.workers)).define(),
-             constructLoc, constructMethod))
+            "}\n" %
+            (constructLoc, constructMethod, constructLoc, constructInternal,
+             CGIndenter(onFailure(failureCode, descriptorProvider.workers)).define()))
         nullableTarget = ""
         if type.nullable():
             if isOptional:
                 mutableDecl = "(const_cast<Optional<" + name + "*>& >(${declName}))"
                 template += "%s.Construct();\n" % mutableDecl
                 nullableTarget = "%s.Value()" % mutableDecl
             else:
                 nullableTarget = "${declName}"
--- a/dom/bindings/TypedArray.h
+++ b/dom/bindings/TypedArray.h
@@ -13,41 +13,60 @@ namespace mozilla {
 namespace dom {
 
 /*
  * Various typed array classes for argument conversion.  We have a base class
  * that has a way of initializing a TypedArray from an existing typed array, and
  * a subclass of the base class that supports creation of a relevant typed array
  * or array buffer object.
  */
-template<typename T, typename U,
-         U* GetData(JSObject*, JSContext*),
-         uint32_t GetLength(JSObject*, JSContext*)>
+template<typename T,
+         JSObject* UnboxArray(JSContext*, JSObject*, uint32_t*, T**)>
 struct TypedArray_base {
-  TypedArray_base(JSContext* cx, JSObject* obj) :
-    mData(static_cast<T*>(GetData(obj, cx))),
-    mLength(GetLength(obj, cx)),
-    mObj(obj)
-  {}
+  TypedArray_base(JSContext* cx, JSObject* obj)
+  {
+    mObj = UnboxArray(cx, obj, &mLength, &mData);
+  }
+
+private:
+  T* mData;
+  uint32_t mLength;
+  JSObject* mObj;
+
+public:
+  inline bool inited() const {
+    return !!mObj;
+  }
 
-  T* const mData;
-  const uint32_t mLength;
-  JSObject* const mObj;
+  inline T *Data() const {
+    MOZ_ASSERT(inited());
+    return mData;
+  }
+
+  inline uint32_t Length() const {
+    MOZ_ASSERT(inited());
+    return mLength;
+  }
+
+  inline JSObject *Obj() const {
+    MOZ_ASSERT(inited());
+    return mObj;
+  }
 };
 
 
-template<typename T, typename U,
-         U* GetData(JSObject*, JSContext*),
-         uint32_t GetLength(JSObject*, JSContext*),
+template<typename T,
+         T* GetData(JSObject*, JSContext*),
+         JSObject* UnboxArray(JSContext*, JSObject*, uint32_t*, T**),
          JSObject* CreateNew(JSContext*, uint32_t)>
-struct TypedArray : public TypedArray_base<T,U,GetData,GetLength> {
+struct TypedArray : public TypedArray_base<T,UnboxArray> {
   TypedArray(JSContext* cx, JSObject* obj) :
-    TypedArray_base<T,U,GetData,GetLength>(cx, obj)
+    TypedArray_base<T,UnboxArray>(cx, obj)
   {}
-  
+
   static inline JSObject*
   Create(JSContext* cx, nsWrapperCache* creator, uint32_t length,
          T* data = NULL) {
     JSObject* creatorWrapper;
     JSAutoEnterCompartment ac;
     if (creator && (creatorWrapper = creator->GetWrapperPreserveColor())) {
       if (!ac.enter(cx, creatorWrapper)) {
         return NULL;
@@ -60,46 +79,45 @@ struct TypedArray : public TypedArray_ba
     if (data) {
       T* buf = static_cast<T*>(GetData(obj, cx));
       memcpy(buf, data, length*sizeof(T));
     }
     return obj;
   }
 };
 
-typedef TypedArray<int8_t, int8_t, JS_GetInt8ArrayData, JS_GetTypedArrayLength,
+typedef TypedArray<int8_t, JS_GetInt8ArrayData, JS_GetObjectAsInt8Array,
                    JS_NewInt8Array>
         Int8Array;
-typedef TypedArray<uint8_t, uint8_t, JS_GetUint8ArrayData,
-                   JS_GetTypedArrayLength, JS_NewUint8Array>
+typedef TypedArray<uint8_t, JS_GetUint8ArrayData,
+                   JS_GetObjectAsUint8Array, JS_NewUint8Array>
         Uint8Array;
-typedef TypedArray<uint8_t, uint8_t, JS_GetUint8ClampedArrayData,
-                   JS_GetTypedArrayLength, JS_NewUint8ClampedArray>
+typedef TypedArray<uint8_t, JS_GetUint8ClampedArrayData,
+                   JS_GetObjectAsUint8ClampedArray, JS_NewUint8ClampedArray>
         Uint8ClampedArray;
-typedef TypedArray<int16_t, int16_t, JS_GetInt16ArrayData,
-                   JS_GetTypedArrayLength, JS_NewInt16Array>
+typedef TypedArray<int16_t, JS_GetInt16ArrayData,
+                   JS_GetObjectAsInt16Array, JS_NewInt16Array>
         Int16Array;
-typedef TypedArray<uint16_t, uint16_t, JS_GetUint16ArrayData,
-                   JS_GetTypedArrayLength, JS_NewUint16Array>
+typedef TypedArray<uint16_t, JS_GetUint16ArrayData,
+                   JS_GetObjectAsUint16Array, JS_NewUint16Array>
         Uint16Array;
-typedef TypedArray<int32_t, int32_t, JS_GetInt32ArrayData,
-                   JS_GetTypedArrayLength, JS_NewInt32Array>
+typedef TypedArray<int32_t, JS_GetInt32ArrayData,
+                   JS_GetObjectAsInt32Array, JS_NewInt32Array>
         Int32Array;
-typedef TypedArray<uint32_t, uint32_t, JS_GetUint32ArrayData,
-                   JS_GetTypedArrayLength, JS_NewUint32Array>
+typedef TypedArray<uint32_t, JS_GetUint32ArrayData,
+                   JS_GetObjectAsUint32Array, JS_NewUint32Array>
         Uint32Array;
-typedef TypedArray<float, float, JS_GetFloat32ArrayData, JS_GetTypedArrayLength,
-                   JS_NewFloat32Array>
+typedef TypedArray<float, JS_GetFloat32ArrayData,
+                   JS_GetObjectAsFloat32Array, JS_NewFloat32Array>
         Float32Array;
-typedef TypedArray<double, double, JS_GetFloat64ArrayData,
-                   JS_GetTypedArrayLength, JS_NewFloat64Array>
+typedef TypedArray<double, JS_GetFloat64ArrayData,
+                   JS_GetObjectAsFloat64Array, JS_NewFloat64Array>
         Float64Array;
-typedef TypedArray_base<uint8_t, void, JS_GetArrayBufferViewData,
-                        JS_GetArrayBufferViewByteLength>
+typedef TypedArray_base<uint8_t, JS_GetObjectAsArrayBufferView>
         ArrayBufferView;
-typedef TypedArray<uint8_t, uint8_t, JS_GetArrayBufferData,
-                   JS_GetArrayBufferByteLength, JS_NewArrayBuffer>
+typedef TypedArray<uint8_t, JS_GetArrayBufferData,
+                   JS_GetObjectAsArrayBuffer, JS_NewArrayBuffer>
         ArrayBuffer;
 
 } // namespace dom
 } // namespace mozilla
 
 #endif /* mozilla_dom_TypedArray_h */
--- a/dom/bluetooth/BluetoothAdapter.cpp
+++ b/dom/bluetooth/BluetoothAdapter.cpp
@@ -3,126 +3,171 @@
 /* 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 "base/basictypes.h"
 #include "BluetoothAdapter.h"
 #include "BluetoothDevice.h"
 #include "BluetoothDeviceEvent.h"
+#include "BluetoothPropertyEvent.h"
 #include "BluetoothService.h"
 #include "BluetoothTypes.h"
 #include "BluetoothReplyRunnable.h"
+#include "BluetoothUtils.h"
 
 #include "nsDOMClassInfo.h"
 #include "nsDOMEvent.h"
 #include "nsThreadUtils.h"
 #include "nsXPCOMCIDInternal.h"
 #include "nsIDOMDOMRequest.h"
+#include "nsContentUtils.h"
 
 #include "mozilla/LazyIdleThread.h"
 #include "mozilla/Util.h"
 
 using namespace mozilla;
 
 USING_BLUETOOTH_NAMESPACE
 
 DOMCI_DATA(BluetoothAdapter, BluetoothAdapter)
 
 NS_IMPL_CYCLE_COLLECTION_CLASS(BluetoothAdapter)
 
+NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN_INHERITED(BluetoothAdapter,
+                                               nsDOMEventTargetHelper)
+  NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mJsUuids)
+  NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mJsDeviceAddresses)
+NS_IMPL_CYCLE_COLLECTION_TRACE_END
+
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(BluetoothAdapter, 
                                                   nsDOMEventTargetHelper)
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
   NS_CYCLE_COLLECTION_TRAVERSE_EVENT_HANDLER(devicefound)
   NS_CYCLE_COLLECTION_TRAVERSE_EVENT_HANDLER(devicedisappeared)
   NS_CYCLE_COLLECTION_TRAVERSE_EVENT_HANDLER(propertychanged)  
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 
 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(BluetoothAdapter, 
                                                 nsDOMEventTargetHelper)
+  tmp->Unroot();
   NS_CYCLE_COLLECTION_UNLINK_EVENT_HANDLER(devicefound)
   NS_CYCLE_COLLECTION_UNLINK_EVENT_HANDLER(devicedisappeared)
   NS_CYCLE_COLLECTION_UNLINK_EVENT_HANDLER(propertychanged)  
 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
 
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(BluetoothAdapter)
   NS_INTERFACE_MAP_ENTRY(nsIDOMBluetoothAdapter)
   NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(BluetoothAdapter)
 NS_INTERFACE_MAP_END_INHERITING(nsDOMEventTargetHelper)
 
 NS_IMPL_ADDREF_INHERITED(BluetoothAdapter, nsDOMEventTargetHelper)
 NS_IMPL_RELEASE_INHERITED(BluetoothAdapter, nsDOMEventTargetHelper)
 
-class GetPropertiesTask : public BluetoothReplyRunnable
+BluetoothAdapter::BluetoothAdapter(nsPIDOMWindow* aOwner, const nsAString& aPath)
+    : BluetoothPropertyContainer(BluetoothObjectType::TYPE_ADAPTER)
+    , mJsUuids(nullptr)
+    , mJsDeviceAddresses(nullptr)
+    , mIsRooted(false)
 {
-public:
-  GetPropertiesTask(BluetoothAdapter* aAdapter, nsIDOMDOMRequest* aReq) :
-    BluetoothReplyRunnable(aReq),
-    mAdapterPtr(aAdapter)
-  {
-  }
-
-  bool
-  ParseSuccessfulReply(jsval* aValue)
-  {
-    const InfallibleTArray<BluetoothNamedValue>& values =
-      mReply->get_BluetoothReplySuccess().value().get_ArrayOfBluetoothNamedValue();
-    for (uint32_t i = 0; i < values.Length(); ++i) {
-      mAdapterPtr->SetPropertyByValue(values[i]);
-    }
-    *aValue = JSVAL_VOID;
-    return true;
-  }
-
-  void
-  ReleaseMembers()
-  {
-    BluetoothReplyRunnable::ReleaseMembers();
-    mAdapterPtr = nullptr;
-  }
-private:
-  nsRefPtr<BluetoothAdapter> mAdapterPtr;
-};
+  BindToOwner(aOwner);
+  mPath = aPath;
+}
 
 BluetoothAdapter::~BluetoothAdapter()
 {
   BluetoothService* bs = BluetoothService::Get();
   // We can be null on shutdown, where this might happen
   if (bs) {
     if (NS_FAILED(bs->UnregisterBluetoothSignalHandler(mPath, this))) {
       NS_WARNING("Failed to unregister object with observer!");
     }
   }
+  Unroot();
+}
+
+void
+BluetoothAdapter::Unroot()
+{
+  if (!mIsRooted) {
+    return;
+  }
+  NS_DROP_JS_OBJECTS(this, BluetoothAdapter);
+  mIsRooted = false;
+}
+
+void
+BluetoothAdapter::Root()
+{
+  if (mIsRooted) {
+    return;
+  }
+  NS_HOLD_JS_OBJECTS(this, BluetoothAdapter);
+  mIsRooted = true;
 }
 
 void
 BluetoothAdapter::SetPropertyByValue(const BluetoothNamedValue& aValue)
 {
   const nsString& name = aValue.name();
   const BluetoothValue& value = aValue.value();
   if (name.EqualsLiteral("Name")) {
     mName = value.get_nsString();
   } else if (name.EqualsLiteral("Address")) {
     mAddress = value.get_nsString();
+  } else if (name.EqualsLiteral("Path")) {
+    mPath = value.get_nsString();
   } else if (name.EqualsLiteral("Enabled")) {
     mEnabled = value.get_bool();
   } else if (name.EqualsLiteral("Discoverable")) {
     mDiscoverable = value.get_bool();
+  } else if (name.EqualsLiteral("Discovering")) {
+    mDiscovering = value.get_bool();
   } else if (name.EqualsLiteral("Pairable")) {
     mPairable = value.get_bool();
   } else if (name.EqualsLiteral("Powered")) {
     mPowered = value.get_bool();
   } else if (name.EqualsLiteral("PairableTimeout")) {
     mPairableTimeout = value.get_uint32_t();
   } else if (name.EqualsLiteral("DiscoverableTimeout")) {
     mDiscoverableTimeout = value.get_uint32_t();
   } else if (name.EqualsLiteral("Class")) {
     mClass = value.get_uint32_t();
   } else if (name.EqualsLiteral("UUIDs")) {
     mUuids = value.get_ArrayOfnsString();
+    nsresult rv;
+    nsIScriptContext* sc = GetContextForEventHandlers(&rv);
+    if (sc) {
+      rv =
+        StringArrayToJSArray(sc->GetNativeContext(),
+                             sc->GetNativeGlobal(), mUuids, &mJsUuids);
+      if (NS_FAILED(rv)) {
+        NS_WARNING("Cannot set JS UUIDs object!");
+        return;
+      }
+      Root();
+    } else {
+      NS_WARNING("Could not get context!");
+    }
+  } else if (name.EqualsLiteral("Devices")) {
+    mDeviceAddresses = value.get_ArrayOfnsString();
+    nsresult rv;
+    nsIScriptContext* sc = GetContextForEventHandlers(&rv);
+    if (sc) {
+      rv =
+        StringArrayToJSArray(sc->GetNativeContext(),
+                             sc->GetNativeGlobal(), mUuids, &mJsDeviceAddresses);
+      if (NS_FAILED(rv)) {
+        NS_WARNING("Cannot set JS Devices Addresses object!");
+        return;
+      }
+      Root();
+    } else {
+      NS_WARNING("Could not get context!");
+    }
   } else {
 #ifdef DEBUG
     nsCString warningMsg;
     warningMsg.AssignLiteral("Not handling adapter property: ");
     warningMsg.Append(NS_ConvertUTF16toUTF8(name));
     NS_WARNING(warningMsg.get());
 #endif
   }
@@ -131,52 +176,70 @@ BluetoothAdapter::SetPropertyByValue(con
 // static
 already_AddRefed<BluetoothAdapter>
 BluetoothAdapter::Create(nsPIDOMWindow* aOwner, const nsAString& aPath)
 {
   // Make sure we at least have a path
   NS_ASSERTION(!aPath.IsEmpty(), "Adapter created with empty path!");
     
   BluetoothService* bs = BluetoothService::Get();
-  MOZ_ASSERT(bs);
+  if (!bs) {
+    NS_WARNING("BluetoothService not available!");
+    return nullptr;
+  }
 
-  nsRefPtr<BluetoothAdapter> adapter = new BluetoothAdapter(aPath);
-  adapter->BindToOwner(aOwner);
-  if (NS_FAILED(bs->RegisterBluetoothSignalHandler(aPath, adapter))) {
+  nsRefPtr<BluetoothAdapter> adapter = new BluetoothAdapter(aOwner, aPath);
+  nsString path;
+  path = adapter->GetPath();
+  if (NS_FAILED(bs->RegisterBluetoothSignalHandler(path, adapter))) {
     NS_WARNING("Failed to register object with observer!");
     return nullptr;
   }
   return adapter.forget();
 }
 
 void
 BluetoothAdapter::Notify(const BluetoothSignal& aData)
 {
   if (aData.name().EqualsLiteral("DeviceFound")) {
-    nsRefPtr<BluetoothDevice> d = BluetoothDevice::Create(GetOwner(), aData);
+    nsRefPtr<BluetoothDevice> d = BluetoothDevice::Create(GetOwner(), mPath, aData.value());
     nsRefPtr<BluetoothDeviceEvent> e = BluetoothDeviceEvent::Create(d);
     e->Dispatch(ToIDOMEventTarget(), NS_LITERAL_STRING("devicefound"));
+  } else if (aData.name().EqualsLiteral("PropertyChanged")) {
+    // Get BluetoothNamedValue, make sure array length is 1
+    InfallibleTArray<BluetoothNamedValue> arr = aData.value().get_ArrayOfBluetoothNamedValue();
+    if (arr.Length() != 1) {
+      // This really should not happen
+      NS_ERROR("Got more than one property in a change message!");
+      return;
+    }
+    BluetoothNamedValue v = arr[0];
+    SetPropertyByValue(v);
+    nsRefPtr<BluetoothPropertyEvent> e = BluetoothPropertyEvent::Create(v.name());
+    e->Dispatch(ToIDOMEventTarget(), NS_LITERAL_STRING("propertychanged"));
   } else {
 #ifdef DEBUG
     nsCString warningMsg;
     warningMsg.AssignLiteral("Not handling manager signal: ");
     warningMsg.Append(NS_ConvertUTF16toUTF8(aData.name()));
     NS_WARNING(warningMsg.get());
 #endif
   }
 }
 
 nsresult
 BluetoothAdapter::StartStopDiscovery(bool aStart, nsIDOMDOMRequest** aRequest)
 {
   BluetoothService* bs = BluetoothService::Get();
-  MOZ_ASSERT(bs);
+  if (!bs) {
+    NS_WARNING("BluetoothService not available!");
+    return NS_ERROR_FAILURE;
+  }
 
-  nsCOMPtr<nsIDOMRequestService> rs = do_GetService("@mozilla.org/dom/dom-request-service;1");
-    
+  nsCOMPtr<nsIDOMRequestService> rs = do_GetService("@mozilla.org/dom/dom-request-service;1");    
   if (!rs) {
     NS_WARNING("No DOMRequest Service!");
     return NS_ERROR_FAILURE;
   }
 
   nsCOMPtr<nsIDOMDOMRequest> req;
   nsresult rv = rs->CreateRequest(GetOwner(), getter_AddRefs(req));
   if (NS_FAILED(rv)) {
@@ -263,15 +326,71 @@ BluetoothAdapter::GetDiscoverableTimeout
 {
   *aDiscoverableTimeout = mDiscoverableTimeout;
   return NS_OK;
 }
 
 NS_IMETHODIMP
 BluetoothAdapter::GetDevices(JSContext* aCx, jsval* aDevices)
 {
-  NS_WARNING("GetDevices not yet implemented.");
+  if (mJsDeviceAddresses) {
+    aDevices->setObject(*mJsDeviceAddresses);
+  }
+  else {
+    NS_WARNING("UUIDs not yet set!\n");
+    return NS_ERROR_FAILURE;
+  }    
+  return NS_OK;
+}
+
+nsresult
+BluetoothAdapter::GetUuids(JSContext* aCx, jsval* aValue)
+{
+  if (mJsUuids) {
+    aValue->setObject(*mJsUuids);
+  }
+  else {
+    NS_WARNING("UUIDs not yet set!\n");
+    return NS_ERROR_FAILURE;
+  }    
   return NS_OK;
 }
 
+NS_IMETHODIMP
+BluetoothAdapter::SetName(const nsAString& aName,
+                          nsIDOMDOMRequest** aRequest)
+{
+  if (mName.Equals(aName)) {
+    return NS_OK;
+  }
+  nsString name(aName);
+  BluetoothValue value(name);
+  BluetoothNamedValue property(NS_LITERAL_STRING("Name"), value);
+  return SetProperty(GetOwner(), property, aRequest);
+}
+ 
+NS_IMETHODIMP
+BluetoothAdapter::SetDiscoverable(const bool aDiscoverable,
+                                  nsIDOMDOMRequest** aRequest)
+{
+  if (aDiscoverable == mDiscoverable) {
+    return NS_OK;
+  }
+  BluetoothValue value(aDiscoverable);
+  BluetoothNamedValue property(NS_LITERAL_STRING("Discoverable"), value);
+  return SetProperty(GetOwner(), property, aRequest);
+}
+ 
+NS_IMETHODIMP
+BluetoothAdapter::SetDiscoverableTimeout(const PRUint32 aDiscoverableTimeout,
+                                         nsIDOMDOMRequest** aRequest)
+{
+  if (aDiscoverableTimeout == mDiscoverableTimeout) {
+    return NS_OK;
+  }
+  BluetoothValue value(aDiscoverableTimeout);
+  BluetoothNamedValue property(NS_LITERAL_STRING("DiscoverableTimeout"), value);
+  return SetProperty(GetOwner(), property, aRequest);
+}
+
 NS_IMPL_EVENT_HANDLER(BluetoothAdapter, propertychanged)
 NS_IMPL_EVENT_HANDLER(BluetoothAdapter, devicefound)
 NS_IMPL_EVENT_HANDLER(BluetoothAdapter, devicedisappeared)
--- a/dom/bluetooth/BluetoothAdapter.h
+++ b/dom/bluetooth/BluetoothAdapter.h
@@ -3,40 +3,43 @@
 /* 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 mozilla_dom_bluetooth_bluetoothadapter_h__
 #define mozilla_dom_bluetooth_bluetoothadapter_h__
 
 #include "BluetoothCommon.h"
+#include "BluetoothPropertyContainer.h"
 #include "nsCOMPtr.h"
 #include "nsDOMEventTargetHelper.h"
 #include "nsIDOMBluetoothAdapter.h"
 
 class nsIEventTarget;
 class nsIDOMDOMRequest;
 
 BEGIN_BLUETOOTH_NAMESPACE
 
 class BluetoothSignal;
 class BluetoothNamedValue;
 
 class BluetoothAdapter : public nsDOMEventTargetHelper
                        , public nsIDOMBluetoothAdapter
                        , public BluetoothSignalObserver
+                       , public BluetoothPropertyContainer
 {
 public:
   NS_DECL_ISUPPORTS_INHERITED
   NS_DECL_NSIDOMBLUETOOTHADAPTER
 
   NS_FORWARD_NSIDOMEVENTTARGET(nsDOMEventTargetHelper::)
 
-  NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(BluetoothAdapter,
-                                           nsDOMEventTargetHelper)
+  NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_INHERITED(BluetoothAdapter,
+                                                         nsDOMEventTargetHelper)
+
   static already_AddRefed<BluetoothAdapter>
   Create(nsPIDOMWindow* aOwner, const nsAString& name);
 
   void Notify(const BluetoothSignal& aParam);
 
   nsIDOMEventTarget*
   ToIDOMEventTarget() const
   {
@@ -45,44 +48,42 @@ public:
   }
 
   nsISupports*
   ToISupports() const
   {
     return ToIDOMEventTarget();
   }
 
-  nsresult GetProperties();
-  void SetPropertyByValue(const BluetoothNamedValue& aValue);  
+  void Unroot();
+  virtual void SetPropertyByValue(const BluetoothNamedValue& aValue);  
 private:
   
-  BluetoothAdapter(const nsAString& aPath) : mPath(aPath)
-  {
-  }
-
+  BluetoothAdapter(nsPIDOMWindow* aOwner, const nsAString& aPath);
   ~BluetoothAdapter();
 
-  nsresult SetProperty(const BluetoothNamedValue& aValue,
-                       nsIDOMDOMRequest** aRequest);
+  void Root();
   nsresult StartStopDiscovery(bool aStart, nsIDOMDOMRequest** aRequest);
   
   nsString mAddress;
   nsString mName;
-  nsString mPath;
   bool mEnabled;
   bool mDiscoverable;
   bool mDiscovering;
   bool mPairable;
   bool mPowered;
   PRUint32 mPairableTimeout;
   PRUint32 mDiscoverableTimeout;
   PRUint32 mClass;
   nsTArray<nsString> mDeviceAddresses;
   nsTArray<nsString> mUuids;
-
+  JSObject* mJsUuids;
+  JSObject* mJsDeviceAddresses;
+  bool mIsRooted;
+  
   NS_DECL_EVENT_HANDLER(propertychanged)
   NS_DECL_EVENT_HANDLER(devicefound)
   NS_DECL_EVENT_HANDLER(devicedisappeared)
 };
 
 END_BLUETOOTH_NAMESPACE
 
 #endif
--- a/dom/bluetooth/BluetoothCommon.h
+++ b/dom/bluetooth/BluetoothCommon.h
@@ -20,11 +20,20 @@
 
 class nsCString;
 
 BEGIN_BLUETOOTH_NAMESPACE
 
 class BluetoothSignal;
 typedef mozilla::Observer<BluetoothSignal> BluetoothSignalObserver;
 
+// Enums for object types, currently used for shared function lookups
+// (get/setproperty, etc...). Possibly discernable via dbus paths, but this
+// method is future-proofed for platform independence.
+enum BluetoothObjectType {
+  TYPE_MANAGER = 0,
+  TYPE_ADAPTER = 1,
+  TYPE_DEVICE = 2 
+};
+
 END_BLUETOOTH_NAMESPACE
 
 #endif // mozilla_dom_bluetooth_bluetoothcommon_h__
--- a/dom/bluetooth/BluetoothDevice.cpp
+++ b/dom/bluetooth/BluetoothDevice.cpp
@@ -1,89 +1,193 @@
 /* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
 /* vim: set ts=2 et sw=2 tw=40: */
 /* 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 "base/basictypes.h"
 #include "BluetoothDevice.h"
+#include "BluetoothPropertyEvent.h"
 #include "BluetoothTypes.h"
+#include "BluetoothReplyRunnable.h"
+#include "BluetoothService.h"
+#include "BluetoothUtils.h"
 
+#include "nsIDOMDOMRequest.h"
 #include "nsDOMClassInfo.h"
+#include "nsContentUtils.h"
 
 USING_BLUETOOTH_NAMESPACE
 
 DOMCI_DATA(BluetoothDevice, BluetoothDevice)
 
 NS_IMPL_CYCLE_COLLECTION_CLASS(BluetoothDevice)
 
+NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN_INHERITED(BluetoothDevice,
+                                               nsDOMEventTargetHelper)
+  NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mJsUuids)
+NS_IMPL_CYCLE_COLLECTION_TRACE_END
+
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(BluetoothDevice, 
                                                   nsDOMEventTargetHelper)
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
   NS_CYCLE_COLLECTION_TRAVERSE_EVENT_HANDLER(propertychanged)  
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 
 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(BluetoothDevice, 
                                                 nsDOMEventTargetHelper)
+  tmp->Unroot();
   NS_CYCLE_COLLECTION_UNLINK_EVENT_HANDLER(propertychanged)  
 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
 
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(BluetoothDevice)
   NS_INTERFACE_MAP_ENTRY(nsIDOMBluetoothDevice)
   NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(BluetoothDevice)
 NS_INTERFACE_MAP_END_INHERITING(nsDOMEventTargetHelper)
 
 NS_IMPL_ADDREF_INHERITED(BluetoothDevice, nsDOMEventTargetHelper)
 NS_IMPL_RELEASE_INHERITED(BluetoothDevice, nsDOMEventTargetHelper)
 
-BluetoothDevice::BluetoothDevice(const BluetoothSignal& aSignal)
+BluetoothDevice::BluetoothDevice(nsPIDOMWindow* aOwner,
+                                 const nsAString& aAdapterPath,
+                                 const BluetoothValue& aValue) :
+  BluetoothPropertyContainer(BluetoothObjectType::TYPE_DEVICE),
+  mJsUuids(nullptr),
+  mAdapterPath(aAdapterPath),
+  mIsRooted(false)
 {
+  BindToOwner(aOwner);
   const InfallibleTArray<BluetoothNamedValue>& values =
-    aSignal.value().get_ArrayOfBluetoothNamedValue();
+    aValue.get_ArrayOfBluetoothNamedValue();
   for (uint32_t i = 0; i < values.Length(); ++i) {
     SetPropertyByValue(values[i]);
   }
 }
 
+BluetoothDevice::~BluetoothDevice()
+{
+  BluetoothService* bs = BluetoothService::Get();
+  // bs can be null on shutdown, where destruction might happen.
+  if (bs) {
+    if (NS_FAILED(bs->UnregisterBluetoothSignalHandler(mPath, this))) {
+      NS_WARNING("Failed to unregister object with observer!");
+    }
+  }
+  Unroot();
+}
+
+void
+BluetoothDevice::Root()
+{
+  if (!mIsRooted) {
+    NS_HOLD_JS_OBJECTS(this, BluetoothDevice);
+    mIsRooted = true;
+  }
+}
+
+void
+BluetoothDevice::Unroot()
+{
+  if (mIsRooted) {
+    NS_DROP_JS_OBJECTS(this, BluetoothDevice);
+    mIsRooted = false;
+  }
+}
+  
 void
 BluetoothDevice::SetPropertyByValue(const BluetoothNamedValue& aValue)
 {
   const nsString& name = aValue.name();
   const BluetoothValue& value = aValue.value();
   if (name.EqualsLiteral("Name")) {
     mName = value.get_nsString();
   } else if (name.EqualsLiteral("Address")) {
     mAddress = value.get_nsString();
+    BluetoothService* bs = BluetoothService::Get();
+    if (!bs) {
+      NS_WARNING("BluetoothService not available!");
+      return;
+    }
+    // We can't actually set up our path until we know our address
+    bs->GetDevicePath(mAdapterPath, mAddress, mPath);
   } else if (name.EqualsLiteral("Class")) {
     mClass = value.get_uint32_t();
   } else if (name.EqualsLiteral("Connected")) {
     mConnected = value.get_bool();
   } else if (name.EqualsLiteral("Paired")) {
     mPaired = value.get_bool();
   } else if (name.EqualsLiteral("UUIDs")) {
     mUuids = value.get_ArrayOfnsString();
+    nsresult rv;
+    nsIScriptContext* sc = GetContextForEventHandlers(&rv);
+    if (sc) {
+      rv =
+        StringArrayToJSArray(sc->GetNativeContext(),
+                             sc->GetNativeGlobal(), mUuids, &mJsUuids);
+      if (NS_FAILED(rv)) {
+        NS_WARNING("Cannot set JS UUIDs object!");
+        return;
+      }
+      Root();
+    } else {
+      NS_WARNING("Could not get context!");
+    }
+#ifdef DEBUG
   } else {
-#ifdef DEBUG
     nsCString warningMsg;
     warningMsg.AssignLiteral("Not handling device property: ");
     warningMsg.Append(NS_ConvertUTF16toUTF8(name));
     NS_WARNING(warningMsg.get());
 #endif
   }
 }
 
 // static
 already_AddRefed<BluetoothDevice>
-BluetoothDevice::Create(nsPIDOMWindow* aOwner, const BluetoothSignal& aSignal)
+BluetoothDevice::Create(nsPIDOMWindow* aOwner,
+                        const nsAString& aAdapterPath,
+                        const BluetoothValue& aValue)
 {
-  nsRefPtr<BluetoothDevice> device = new BluetoothDevice(aSignal);
-  device->BindToOwner(device);
+  // Make sure we at least have a service
+  BluetoothService* bs = BluetoothService::Get();
+  if (!bs) {
+    NS_WARNING("BluetoothService not available!");
+    return nullptr;
+  }
+
+  nsRefPtr<BluetoothDevice> device = new BluetoothDevice(aOwner, aAdapterPath,
+                                                         aValue);
+  if (NS_FAILED(bs->RegisterBluetoothSignalHandler(device->mPath, device))) {
+    NS_WARNING("Failed to register object with observer!");
+    return nullptr;
+  }
   return device.forget();
 }
 
+void
+BluetoothDevice::Notify(const BluetoothSignal& aData)
+{
+  if (aData.name().EqualsLiteral("PropertyChanged")) {
+    // Get BluetoothNamedValue, make sure array length is 1
+    BluetoothNamedValue v = aData.value().get_ArrayOfBluetoothNamedValue()[0];
+    nsString name = v.name();
+    SetPropertyByValue(v);
+    nsRefPtr<BluetoothPropertyEvent> e = BluetoothPropertyEvent::Create(name);
+    e->Dispatch(ToIDOMEventTarget(), NS_LITERAL_STRING("propertychanged"));
+  } else {
+#ifdef DEBUG
+    nsCString warningMsg;
+    warningMsg.AssignLiteral("Not handling device signal: ");
+    warningMsg.Append(NS_ConvertUTF16toUTF8(aData.name()));
+    NS_WARNING(warningMsg.get());
+#endif
+  }
+}
+
 NS_IMETHODIMP
 BluetoothDevice::GetAddress(nsAString& aAddress)
 {
   aAddress = mAddress;
   return NS_OK;
 }
 
 NS_IMETHODIMP
@@ -109,9 +213,21 @@ BluetoothDevice::GetPaired(bool* aPaired
 
 NS_IMETHODIMP
 BluetoothDevice::GetConnected(bool* aConnected)
 {
   *aConnected = mConnected;
   return NS_OK;
 }
 
+NS_IMETHODIMP
+BluetoothDevice::GetUuids(JSContext* aCx, jsval* aUuids)
+{
+  if (mJsUuids) {
+    aUuids->setObject(*mJsUuids);
+  } else {
+    NS_WARNING("UUIDs not yet set!\n");
+    return NS_ERROR_FAILURE;
+  }    
+  return NS_OK;
+}
+
 NS_IMPL_EVENT_HANDLER(BluetoothDevice, propertychanged)
--- a/dom/bluetooth/BluetoothDevice.h
+++ b/dom/bluetooth/BluetoothDevice.h
@@ -3,63 +3,80 @@
 /* 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 mozilla_dom_bluetooth_bluetoothdevice_h__
 #define mozilla_dom_bluetooth_bluetoothdevice_h__
 
 #include "BluetoothCommon.h"
+#include "BluetoothPropertyContainer.h"
 #include "nsDOMEventTargetHelper.h"
 #include "nsIDOMBluetoothDevice.h"
 #include "nsString.h"
 
+class nsIDOMDOMRequest;
+
 BEGIN_BLUETOOTH_NAMESPACE
 
 class BluetoothNamedValue;
+class BluetoothValue;
 class BluetoothSignal;
 
 class BluetoothDevice : public nsDOMEventTargetHelper
                       , public nsIDOMBluetoothDevice
+                      , public BluetoothSignalObserver
+                      , public BluetoothPropertyContainer
 {
 public:
   NS_DECL_ISUPPORTS_INHERITED
   NS_DECL_NSIDOMBLUETOOTHDEVICE
 
   NS_FORWARD_NSIDOMEVENTTARGET(nsDOMEventTargetHelper::)
 
-  NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(BluetoothDevice,
-                                           nsDOMEventTargetHelper)
+  NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_INHERITED(BluetoothDevice,
+                                                         nsDOMEventTargetHelper)
 
   static already_AddRefed<BluetoothDevice>
-  Create(nsPIDOMWindow* aOwner, const BluetoothSignal& aSignal);
+  Create(nsPIDOMWindow* aOwner, const nsAString& aAdapterPath,
+         const BluetoothValue& aValue);
+
+  void Notify(const BluetoothSignal& aParam);
 
   nsIDOMEventTarget*
   ToIDOMEventTarget() const
   {
     return static_cast<nsDOMEventTargetHelper*>(
       const_cast<BluetoothDevice*>(this));
   }
 
   nsISupports*
   ToISupports() const
   {
     return ToIDOMEventTarget();
   }
-  
+
+  void SetPropertyByValue(const BluetoothNamedValue& aValue);
+
+  void Unroot();
 private:
-  BluetoothDevice(const BluetoothSignal& aSignal);
-  ~BluetoothDevice() {}  
-  void SetPropertyByValue(const BluetoothNamedValue& aValue);
+  BluetoothDevice(nsPIDOMWindow* aOwner, const nsAString& aAdapterPath,
+                  const BluetoothValue& aValue);
+  ~BluetoothDevice();
+  void Root();
   
+  JSObject* mJsUuids;
+
+  nsString mAdapterPath;
   nsString mAddress;
   nsString mName;
   PRUint32 mClass;
   bool mConnected;
   bool mPaired;
+  bool mIsRooted;
   nsTArray<nsString> mUuids;
 
   NS_DECL_EVENT_HANDLER(propertychanged)
 };
 
 END_BLUETOOTH_NAMESPACE
 
 #endif
--- a/dom/bluetooth/BluetoothDeviceEvent.cpp
+++ b/dom/bluetooth/BluetoothDeviceEvent.cpp
@@ -3,16 +3,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/. */
 
 #include "base/basictypes.h"
 #include "BluetoothDeviceEvent.h"
 #include "BluetoothTypes.h"
 #include "BluetoothDevice.h"
+#include "nsIDOMDOMRequest.h"
 
 #include "nsDOMClassInfo.h"
 
 USING_BLUETOOTH_NAMESPACE
 
 // static
 already_AddRefed<BluetoothDeviceEvent>
 BluetoothDeviceEvent::Create(BluetoothDevice* aDevice)
--- a/dom/bluetooth/BluetoothManager.cpp
+++ b/dom/bluetooth/BluetoothManager.cpp
@@ -139,41 +139,56 @@ public:
   }
   
 private:
   nsRefPtr<BluetoothManager> mManagerPtr;
   bool mEnabled;
 };
 
 BluetoothManager::BluetoothManager(nsPIDOMWindow *aWindow) :
+  BluetoothPropertyContainer(BluetoothObjectType::TYPE_MANAGER),
   mEnabled(false)
 {
   BindToOwner(aWindow);
-  mName.AssignLiteral("/");
+  mPath.AssignLiteral("/");
 }
 
 BluetoothManager::~BluetoothManager()
 {
   BluetoothService* bs = BluetoothService::Get();
   // We can be null on shutdown, where this might happen
   if (bs) {
-    if (NS_FAILED(bs->UnregisterBluetoothSignalHandler(mName, this))) {
+    if (NS_FAILED(bs->UnregisterBluetoothSignalHandler(mPath, this))) {
       NS_WARNING("Failed to unregister object with observer!");
     }
   }
 }
 
+void
+BluetoothManager::SetPropertyByValue(const BluetoothNamedValue& aValue)
+{
+#ifdef DEBUG
+    const nsString& name = aValue.name();
+    nsCString warningMsg;
+    warningMsg.AssignLiteral("Not handling manager property: ");
+    warningMsg.Append(NS_ConvertUTF16toUTF8(name));
+    NS_WARNING(warningMsg.get());
+#endif
+}
+
 NS_IMETHODIMP
 BluetoothManager::SetEnabled(bool aEnabled, nsIDOMDOMRequest** aDomRequest)
 {
   BluetoothService* bs = BluetoothService::Get();
-  MOZ_ASSERT(bs);
+  if (!bs) {
+    NS_WARNING("BluetoothService not available!");
+    return NS_ERROR_FAILURE;
+  }
 
   nsCOMPtr<nsIDOMRequestService> rs = do_GetService("@mozilla.org/dom/dom-request-service;1");
-
   if (!rs) {
     NS_WARNING("No DOMRequest Service!");
     return NS_ERROR_FAILURE;
   }
 
   nsCOMPtr<nsIDOMDOMRequest> request;
   nsresult rv = rs->CreateRequest(GetOwner(), getter_AddRefs(request));
   if (NS_FAILED(rv)) {
@@ -203,17 +218,20 @@ BluetoothManager::GetEnabled(bool* aEnab
   *aEnabled = mEnabled;
   return NS_OK;
 }
 
 NS_IMETHODIMP
 BluetoothManager::GetDefaultAdapter(nsIDOMDOMRequest** aAdapter)
 {
   BluetoothService* bs = BluetoothService::Get();
-  MOZ_ASSERT(bs);
+  if (!bs) {
+    NS_WARNING("BluetoothService not available!");
+    return NS_ERROR_FAILURE;
+  }
   
   nsCOMPtr<nsIDOMRequestService> rs = do_GetService("@mozilla.org/dom/dom-request-service;1");
 
   if (!rs) {
     NS_WARNING("No DOMRequest Service!");
     return NS_ERROR_FAILURE;
   }
 
@@ -234,17 +252,20 @@ BluetoothManager::GetDefaultAdapter(nsID
 }
 
 // static
 already_AddRefed<BluetoothManager>
 BluetoothManager::Create(nsPIDOMWindow* aWindow) {
 
   nsRefPtr<BluetoothManager> manager = new BluetoothManager(aWindow);
   BluetoothService* bs = BluetoothService::Get();
-  MOZ_ASSERT(bs);
+  if (!bs) {
+    NS_WARNING("BluetoothService not available!");
+    return nullptr;
+  }
   
   if (NS_FAILED(bs->RegisterBluetoothSignalHandler(NS_LITERAL_STRING("/"), manager))) {
     NS_ERROR("Failed to register object with observer!");
     return nullptr;
   }
   
   return manager.forget();
 }
--- a/dom/bluetooth/BluetoothManager.h
+++ b/dom/bluetooth/BluetoothManager.h
@@ -3,48 +3,51 @@
 /* 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 mozilla_dom_bluetooth_bluetoothmanager_h__
 #define mozilla_dom_bluetooth_bluetoothmanager_h__
 
 #include "BluetoothCommon.h"
+#include "BluetoothPropertyContainer.h"
 #include "nsDOMEventTargetHelper.h"
 #include "nsIDOMBluetoothManager.h"
 #include "mozilla/Observer.h"
 #include "nsIEventTarget.h"
 
 BEGIN_BLUETOOTH_NAMESPACE
 
+class BluetoothNamedValue;
+
 class BluetoothManager : public nsDOMEventTargetHelper
                        , public nsIDOMBluetoothManager
                        , public BluetoothSignalObserver
+                       , public BluetoothPropertyContainer
 {
 public:
   NS_DECL_ISUPPORTS_INHERITED
   NS_DECL_NSIDOMBLUETOOTHMANAGER
 
   NS_FORWARD_NSIDOMEVENTTARGET(nsDOMEventTargetHelper::)
 
   NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(BluetoothManager,
                                            nsDOMEventTargetHelper)
 
 
   inline void SetEnabledInternal(bool aEnabled) {mEnabled = aEnabled;}
 
   static already_AddRefed<BluetoothManager>
   Create(nsPIDOMWindow* aWindow);
   void Notify(const BluetoothSignal& aData);
+  virtual void SetPropertyByValue(const BluetoothNamedValue& aValue);
 private:
-  BluetoothManager() {}
   BluetoothManager(nsPIDOMWindow* aWindow);
   ~BluetoothManager();
   bool mEnabled;
-  nsString mName;
 
   NS_DECL_EVENT_HANDLER(enabled)
 };
 
 END_BLUETOOTH_NAMESPACE
 
 nsresult NS_NewBluetoothManager(nsPIDOMWindow* aWindow,
                                 nsIDOMBluetoothManager** aBluetoothManager);
new file mode 100644
--- /dev/null
+++ b/dom/bluetooth/BluetoothPropertyContainer.cpp
@@ -0,0 +1,76 @@
+/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
+/* vim: set ts=2 et sw=2 tw=40: */
+/* 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 "base/basictypes.h"
+#include "BluetoothPropertyContainer.h"
+#include "BluetoothService.h"
+#include "BluetoothTypes.h"
+#include "nsIDOMDOMRequest.h"
+
+USING_BLUETOOTH_NAMESPACE
+
+nsresult
+BluetoothPropertyContainer::GetProperties()
+{
+  BluetoothService* bs = BluetoothService::Get();
+  if (!bs) {
+    NS_WARNING("Bluetooth service not available!");
+    return NS_ERROR_FAILURE;
+  }
+  nsRefPtr<BluetoothReplyRunnable> task = new GetPropertiesTask(this, NULL);
+  return bs->GetProperties(mObjectType, mPath, task);
+}
+
+nsresult
+BluetoothPropertyContainer::SetProperty(nsIDOMWindow* aOwner,
+                                        const BluetoothNamedValue& aProperty,
+                                        nsIDOMDOMRequest** aRequest)
+{
+  BluetoothService* bs = BluetoothService::Get();
+  if (!bs) {
+    NS_WARNING("Bluetooth service not available!");
+    return NS_ERROR_FAILURE;
+  }
+  nsCOMPtr<nsIDOMRequestService> rs = do_GetService("@mozilla.org/dom/dom-request-service;1");
+    
+  if (!rs) {
+    NS_WARNING("No DOMRequest Service!");
+    return NS_ERROR_FAILURE;
+  }
+
+  nsCOMPtr<nsIDOMDOMRequest> req;
+  nsresult rv = rs->CreateRequest(aOwner, getter_AddRefs(req));
+  if (NS_FAILED(rv)) {
+    NS_WARNING("Can't create DOMRequest!");
+    return NS_ERROR_FAILURE;
+  }
+
+  nsRefPtr<BluetoothReplyRunnable> task = new BluetoothVoidReplyRunnable(req);
+  
+  rv = bs->SetProperty(mObjectType, mPath, aProperty, task);
+  NS_ENSURE_SUCCESS(rv, rv);
+  
+  req.forget(aRequest);
+  return NS_OK;
+}
+
+
+bool
+BluetoothPropertyContainer::GetPropertiesTask::ParseSuccessfulReply(jsval* aValue)
+{
+  *aValue = JSVAL_VOID;
+  BluetoothValue& v = mReply->get_BluetoothReplySuccess().value();
+  if (v.type() != BluetoothValue::TArrayOfBluetoothNamedValue) {
+    NS_WARNING("Not a BluetoothNamedValue array!");
+    return false;
+  }
+  const InfallibleTArray<BluetoothNamedValue>& values =
+    mReply->get_BluetoothReplySuccess().value().get_ArrayOfBluetoothNamedValue();
+  for (uint32_t i = 0; i < values.Length(); ++i) {
+    mPropObjPtr->SetPropertyByValue(values[i]);
+  }
+  return true;
+}
new file mode 100644
--- /dev/null
+++ b/dom/bluetooth/BluetoothPropertyContainer.h
@@ -0,0 +1,75 @@
+/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
+/* vim: set ts=2 et sw=2 tw=40: */
+/* 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 mozilla_dom_bluetooth_bluetoothpropertyobject_h__
+#define mozilla_dom_bluetooth_bluetoothpropertyobject_h__
+
+#include "BluetoothCommon.h"
+#include "BluetoothReplyRunnable.h"
+
+class nsIDOMDOMRequest;
+class nsIDOMWindow;
+
+BEGIN_BLUETOOTH_NAMESPACE
+
+class BluetoothNamedValue;
+
+class BluetoothPropertyContainer
+{
+public:
+  nsresult GetProperties();
+  nsresult SetProperty(nsIDOMWindow* aOwner,
+                       const BluetoothNamedValue& aProperty,
+                       nsIDOMDOMRequest** aRequest);
+  virtual void SetPropertyByValue(const BluetoothNamedValue& aValue) = 0;
+  nsString GetPath()
+  {
+    return mPath;
+  }
+
+  // Compatibility with nsRefPtr to make sure we don't hold a weakptr to
+  // ourselves
+  virtual nsrefcnt AddRef() = 0;
+  virtual nsrefcnt Release() = 0;
+
+protected:
+  BluetoothPropertyContainer(BluetoothObjectType aType) :
+    mObjectType(aType)
+  {}
+
+  ~BluetoothPropertyContainer()
+  {}
+  
+  class GetPropertiesTask : public BluetoothReplyRunnable
+  {
+  public:
+    GetPropertiesTask(BluetoothPropertyContainer* aPropObj, nsIDOMDOMRequest* aReq) :
+      BluetoothReplyRunnable(aReq),
+      mPropObjPtr(aPropObj)
+    {
+      MOZ_ASSERT(aReq && aPropObj);
+    }
+
+    virtual bool ParseSuccessfulReply(jsval* aValue);
+    
+    void
+    ReleaseMembers()
+    {
+      BluetoothReplyRunnable::ReleaseMembers();
+      mPropObjPtr = nullptr;
+    }
+    
+  private:
+    BluetoothPropertyContainer* mPropObjPtr;    
+  };
+
+  nsString mPath;
+  BluetoothObjectType mObjectType;
+};
+
+END_BLUETOOTH_NAMESPACE
+
+#endif
new file mode 100644
--- /dev/null
+++ b/dom/bluetooth/BluetoothPropertyEvent.cpp
@@ -0,0 +1,53 @@
+/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
+/* vim: set ts=2 et sw=2 tw=40: */
+/* 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 "base/basictypes.h"
+#include "BluetoothPropertyEvent.h"
+#include "BluetoothTypes.h"
+
+#include "nsDOMClassInfo.h"
+
+USING_BLUETOOTH_NAMESPACE
+
+// static
+already_AddRefed<BluetoothPropertyEvent>
+BluetoothPropertyEvent::Create(const nsAString& aPropertyName)
+{
+  NS_ASSERTION(!aPropertyName.IsEmpty(), "Empty Property String!");
+
+  nsRefPtr<BluetoothPropertyEvent> event = new BluetoothPropertyEvent();
+
+  event->mPropertyName = aPropertyName;
+
+  return event.forget();
+}
+
+NS_IMPL_CYCLE_COLLECTION_CLASS(BluetoothPropertyEvent)
+
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(BluetoothPropertyEvent,
+                                                  nsDOMEvent)
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
+
+NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(BluetoothPropertyEvent,
+                                                nsDOMEvent)
+NS_IMPL_CYCLE_COLLECTION_UNLINK_END
+
+NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(BluetoothPropertyEvent)
+  NS_INTERFACE_MAP_ENTRY(nsIDOMBluetoothPropertyEvent)
+  NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(BluetoothPropertyEvent)
+NS_INTERFACE_MAP_END_INHERITING(nsDOMEvent)
+
+NS_IMPL_ADDREF_INHERITED(BluetoothPropertyEvent, nsDOMEvent)
+NS_IMPL_RELEASE_INHERITED(BluetoothPropertyEvent, nsDOMEvent)
+
+DOMCI_DATA(BluetoothPropertyEvent, BluetoothPropertyEvent)
+
+NS_IMETHODIMP
+BluetoothPropertyEvent::GetProperty(nsAString& aPropertyName)
+{
+  aPropertyName = mPropertyName;
+  return NS_OK;
+}
new file mode 100644
--- /dev/null
+++ b/dom/bluetooth/BluetoothPropertyEvent.h
@@ -0,0 +1,66 @@
+/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
+/* vim: set ts=2 et sw=2 tw=40: */
+/* 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 mozilla_dom_bluetooth_propertyevent_h__
+#define mozilla_dom_bluetooth_propertyevent_h__
+
+#include "BluetoothCommon.h"
+
+#include "nsIDOMBluetoothPropertyEvent.h"
+#include "nsIDOMEventTarget.h"
+
+#include "nsDOMEvent.h"
+
+BEGIN_BLUETOOTH_NAMESPACE
+
+class BluetoothPropertyEvent : public nsDOMEvent
+                             , public nsIDOMBluetoothPropertyEvent
+{
+public:
+  NS_DECL_ISUPPORTS_INHERITED
+  NS_FORWARD_TO_NSDOMEVENT
+  NS_DECL_NSIDOMBLUETOOTHPROPERTYEVENT
+  NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(BluetoothPropertyEvent, nsDOMEvent)
+
+  static already_AddRefed<BluetoothPropertyEvent>
+  Create(const nsAString& aPropertyName);
+
+  nsresult
+  Dispatch(nsIDOMEventTarget* aTarget, const nsAString& aEventType)
+  {
+    NS_ASSERTION(aTarget, "Null pointer!");
+    NS_ASSERTION(!aEventType.IsEmpty(), "Empty event type!");
+
+    nsresult rv = InitEvent(aEventType, false, false);
+    NS_ENSURE_SUCCESS(rv, rv);
+
+    rv = SetTrusted(true);
+    NS_ENSURE_SUCCESS(rv, rv);
+
+    nsIDOMEvent* thisEvent =
+      static_cast<nsDOMEvent*>(const_cast<BluetoothPropertyEvent*>(this));
+
+    bool dummy;
+    rv = aTarget->DispatchEvent(thisEvent, &dummy);
+    NS_ENSURE_SUCCESS(rv, rv);
+
+    return NS_OK;
+  }
+
+private:
+  BluetoothPropertyEvent()
+    : nsDOMEvent(nullptr, nullptr)
+  { }
+
+  ~BluetoothPropertyEvent()
+  { }
+
+  nsString mPropertyName;
+};
+
+END_BLUETOOTH_NAMESPACE
+
+#endif
--- a/dom/bluetooth/BluetoothReplyRunnable.cpp
+++ b/dom/bluetooth/BluetoothReplyRunnable.cpp
@@ -2,18 +2,16 @@
 /* vim: set ts=2 et sw=2 tw=40: */
 /* 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 "base/basictypes.h"
 #include "BluetoothTypes.h"
 #include "BluetoothReplyRunnable.h"
-#include "nsIDOMDOMRequest.h"
-#include "jsapi.h"
 
 USING_BLUETOOTH_NAMESPACE
 
 nsresult
 BluetoothReplyRunnable::FireReply(const jsval& aVal)
 {
   nsCOMPtr<nsIDOMRequestService> rs =
     do_GetService("@mozilla.org/dom/dom-request-service;1");
--- a/dom/bluetooth/BluetoothReplyRunnable.h
+++ b/dom/bluetooth/BluetoothReplyRunnable.h
@@ -4,20 +4,19 @@
  * 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 mozilla_dom_bluetooth_bluetoothreplyrunnable_h__
 #define mozilla_dom_bluetooth_bluetoothreplyrunnable_h__
 
 #include "BluetoothCommon.h"
 #include "nsThreadUtils.h"
+#include "nsIDOMDOMRequest.h"
 #include "jsapi.h"
 
-class nsIDOMDOMRequest;
-
 BEGIN_BLUETOOTH_NAMESPACE
 
 class BluetoothReply;
 
 class BluetoothReplyRunnable : public nsRunnable
 {
 public:
   NS_DECL_NSIRUNNABLE
--- a/dom/bluetooth/BluetoothService.h
+++ b/dom/bluetooth/BluetoothService.h
@@ -138,16 +138,60 @@ public:
   /** 
    * Platform specific startup functions go here. Usually deals with member
    * variables, so not static. Guaranteed to be called outside of main thread.
    *
    * @return NS_OK on correct startup, NS_ERROR_FAILURE otherwise
    */
   virtual nsresult StopInternal() = 0;
 
+  /** 
+   * Fetches the propertes for the specified object
+   *
+   * @param aType Type of the object (see BluetoothObjectType in BluetoothCommon.h)
+   * @param aPath Path of the object
+   * @param aRunnable Runnable to return to after receiving callback
+   *
+   * @return NS_OK on function run, NS_ERROR_FAILURE otherwise
+   */
+  virtual nsresult
+  GetProperties(BluetoothObjectType aType,
+                const nsAString& aPath,
+                BluetoothReplyRunnable* aRunnable) = 0;
+
+  /** 
+   * Set a property for the specified object
+   *
+   * @param aPath Path to the object
+   * @param aPropName Name of the property
+   * @param aValue Boolean value
+   * @param aRunnable Runnable to run on async reply
+   *
+   * @return NS_OK if property is set correctly, NS_ERROR_FAILURE otherwise
+   */
+  virtual nsresult
+  SetProperty(BluetoothObjectType aType,
+              const nsAString& aPath,
+              const BluetoothNamedValue& aValue,
+              BluetoothReplyRunnable* aRunnable) = 0;
+
+  /** 
+   * Get the path of a device
+   *
+   * @param aAdapterPath Path to the Adapter that's communicating with the device
+   * @param aDeviceAddress Device address (XX:XX:XX:XX:XX:XX format)
+   * @param aDevicePath Return value of path
+   *
+   * @return True if path set correctly, false otherwise
+   */
+  virtual bool
+  GetDevicePath(const nsAString& aAdapterPath,
+                const nsAString& aDeviceAddress,
+                nsAString& aDevicePath) = 0;
+
 protected:
   BluetoothService()
   {
     mBluetoothSignalObserverTable.Init();
   }
 
   virtual ~BluetoothService()
   {
new file mode 100644
--- /dev/null
+++ b/dom/bluetooth/BluetoothUtils.cpp
@@ -0,0 +1,61 @@
+/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
+/* vim: set ts=2 et sw=2 tw=40: */
+/* 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 "BluetoothUtils.h"
+#include "jsapi.h"
+#include "nsTArray.h"
+#include "nsString.h"
+#include "mozilla/Scoped.h"
+
+nsresult
+mozilla::dom::bluetooth::StringArrayToJSArray(JSContext* aCx, JSObject* aGlobal,
+                                              const nsTArray<nsString>& aSourceArray,
+                                              JSObject** aResultArray)
+{
+  NS_ASSERTION(aCx, "Null context!");
+  NS_ASSERTION(aGlobal, "Null global!");
+
+  JSAutoRequest ar(aCx);
+  JSAutoEnterCompartment ac;
+  if (!ac.enter(aCx, aGlobal)) {
+    NS_WARNING("Failed to enter compartment!");
+    return NS_ERROR_FAILURE;
+  }
+
+  JSObject* arrayObj;
+
+  if (aSourceArray.IsEmpty()) {
+    arrayObj = JS_NewArrayObject(aCx, 0, nullptr);
+  } else {
+    uint32_t valLength = aSourceArray.Length();
+    mozilla::ScopedDeleteArray<jsval> valArray(new jsval[valLength]);
+    JS::AutoArrayRooter tvr(aCx, valLength, valArray);
+    for (PRUint32 index = 0; index < valLength; index++) {
+      JSString* s = JS_NewUCStringCopyN(aCx, aSourceArray[index].BeginReading(),
+                                        aSourceArray[index].Length());
+      if(!s) {
+        NS_WARNING("Memory allocation error!");
+        return NS_ERROR_OUT_OF_MEMORY;
+      }
+      valArray[index] = STRING_TO_JSVAL(s);
+    }
+    arrayObj = JS_NewArrayObject(aCx, valLength, valArray);
+  }
+
+  if (!arrayObj) {
+    return NS_ERROR_OUT_OF_MEMORY;
+  }
+
+  // XXX This is not what Jonas wants. He wants it to be live.
+  // Followup at bug 717414
+  if (!JS_FreezeObject(aCx, arrayObj)) {
+    return NS_ERROR_FAILURE;
+  }
+
+  *aResultArray = arrayObj;
+  return NS_OK;
+}
+
new file mode 100644
--- /dev/null
+++ b/dom/bluetooth/BluetoothUtils.h
@@ -0,0 +1,24 @@
+/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
+/* vim: set ts=2 et sw=2 tw=40: */
+/* 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 mozilla_dom_bluetooth_bluetoothutils_h__
+#define mozilla_dom_bluetooth_bluetoothutils_h__
+
+#include "BluetoothCommon.h"
+
+class JSContext;
+class JSObject;
+
+BEGIN_BLUETOOTH_NAMESPACE
+
+nsresult
+StringArrayToJSArray(JSContext* aCx, JSObject* aGlobal,
+                     const nsTArray<nsString>& aSourceArray,
+                     JSObject** aResultArray);
+
+END_BLUETOOTH_NAMESPACE
+
+#endif
--- a/dom/bluetooth/Makefile.in
+++ b/dom/bluetooth/Makefile.in
@@ -28,25 +28,29 @@ FORCE_STATIC_LIB = 1
 include $(topsrcdir)/dom/dom-config.mk
 
 CPPSRCS += \
   BluetoothService.cpp \
   BluetoothManager.cpp \
   BluetoothAdapter.cpp \
   BluetoothDevice.cpp \
   BluetoothDeviceEvent.cpp \
+  BluetoothPropertyEvent.cpp \
   BluetoothReplyRunnable.cpp \
+  BluetoothPropertyContainer.cpp \
+  BluetoothUtils.cpp \
   $(NULL)
 
 XPIDLSRCS = \
   nsIDOMNavigatorBluetooth.idl \
   nsIDOMBluetoothManager.idl \
   nsIDOMBluetoothAdapter.idl \
   nsIDOMBluetoothDevice.idl \
   nsIDOMBluetoothDeviceEvent.idl \
+  nsIDOMBluetoothPropertyEvent.idl \
   $(NULL)
 
 ifeq (gonk,$(MOZ_WIDGET_TOOLKIT))
 VPATH += \
 	$(srcdir)/linux \
 	$(srcdir)/gonk \
 	$(NULL)
 LOCAL_INCLUDES += $(MOZ_DBUS_CFLAGS)
--- a/dom/bluetooth/linux/BluetoothDBusService.cpp
+++ b/dom/bluetooth/linux/BluetoothDBusService.cpp
@@ -52,28 +52,29 @@ USING_BLUETOOTH_NAMESPACE
 #if defined(MOZ_WIDGET_GONK)
 #include <android/log.h>
 #define LOG(args...)  __android_log_print(ANDROID_LOG_INFO, "GonkDBus", args);
 #else
 #define BTDEBUG true
 #define LOG(args...) if (BTDEBUG) printf(args);
 #endif
 
+#define DBUS_MANAGER_IFACE BLUEZ_DBUS_BASE_IFC ".Manager"
 #define DBUS_ADAPTER_IFACE BLUEZ_DBUS_BASE_IFC ".Adapter"
 #define DBUS_DEVICE_IFACE BLUEZ_DBUS_BASE_IFC ".Device"
 #define BLUEZ_DBUS_BASE_PATH      "/org/bluez"
 #define BLUEZ_DBUS_BASE_IFC       "org.bluez"
 #define BLUEZ_ERROR_IFC           "org.bluez.Error"
 
 typedef struct {
   const char* name;
   int type;
 } Properties;
 
-static Properties remote_device_properties[] = {
+static Properties sDeviceProperties[] = {
   {"Address", DBUS_TYPE_STRING},
   {"Name", DBUS_TYPE_STRING},
   {"Icon", DBUS_TYPE_STRING},
   {"Class", DBUS_TYPE_UINT32},
   {"UUIDs", DBUS_TYPE_ARRAY},
   {"Services", DBUS_TYPE_ARRAY},
   {"Paired", DBUS_TYPE_BOOLEAN},
   {"Connected", DBUS_TYPE_BOOLEAN},
@@ -83,31 +84,42 @@ static Properties remote_device_properti
   {"Nodes", DBUS_TYPE_ARRAY},
   {"Adapter", DBUS_TYPE_OBJECT_PATH},
   {"LegacyPairing", DBUS_TYPE_BOOLEAN},
   {"RSSI", DBUS_TYPE_INT16},
   {"TX", DBUS_TYPE_UINT32},
   {"Broadcaster", DBUS_TYPE_BOOLEAN}
 };
 
-static Properties adapter_properties[] = {
+static Properties sAdapterProperties[] = {
   {"Address", DBUS_TYPE_STRING},
   {"Name", DBUS_TYPE_STRING},
   {"Class", DBUS_TYPE_UINT32},
   {"Powered", DBUS_TYPE_BOOLEAN},
   {"Discoverable", DBUS_TYPE_BOOLEAN},
   {"DiscoverableTimeout", DBUS_TYPE_UINT32},
   {"Pairable", DBUS_TYPE_BOOLEAN},
   {"PairableTimeout", DBUS_TYPE_UINT32},
   {"Discovering", DBUS_TYPE_BOOLEAN},
   {"Devices", DBUS_TYPE_ARRAY},
   {"UUIDs", DBUS_TYPE_ARRAY},
 };
 
-static const char* BLUETOOTH_DBUS_SIGNALS[] =
+static Properties sManagerProperties[] = {
+  {"Adapters", DBUS_TYPE_ARRAY},
+};
+
+static const char* sBluetoothDBusIfaces[] =
+{
+  DBUS_MANAGER_IFACE,
+  DBUS_ADAPTER_IFACE,
+  DBUS_DEVICE_IFACE
+};
+
+static const char* sBluetoothDBusSignals[] =
 {
   "type='signal',interface='org.freedesktop.DBus'",
   "type='signal',interface='org.bluez.Adapter'",
   "type='signal',interface='org.bluez.Manager'",
   "type='signal',interface='org.bluez.Device'",
   "type='signal',interface='org.bluez.Input'",
   "type='signal',interface='org.bluez.Network'",
   "type='signal',interface='org.bluez.NetworkServer'",
@@ -123,22 +135,24 @@ public:
   {
   }
 
   NS_IMETHOD
   Run()
   {
     MOZ_ASSERT(NS_IsMainThread());
     BluetoothService* bs = BluetoothService::Get();
-    MOZ_ASSERT(bs);
+    if (!bs) {
+      NS_WARNING("BluetoothService not available!");
+      return NS_ERROR_FAILURE;
+    }    
     return bs->DistributeSignal(mSignal);
   }  
 };
 
-
 bool
 IsDBusMessageError(DBusMessage* aMsg, nsAString& aError)
 {
   DBusError err;
   dbus_error_init(&err);
   if (dbus_message_get_type(aMsg) == DBUS_MESSAGE_TYPE_ERROR) {
     const char* error_msg;
     if (!dbus_message_get_args(aMsg, &err, DBUS_TYPE_STRING,
@@ -171,78 +185,89 @@ DispatchBluetoothReply(BluetoothReplyRun
     reply = new BluetoothReply(BluetoothReplySuccess(aValue));
   }
   
   aRunnable->SetReply(reply);
   if (NS_FAILED(NS_DispatchToMainThread(aRunnable))) {
     NS_WARNING("Failed to dispatch to main thread!");
   }
 }
-  
+
 void
-GetObjectPathCallback(DBusMessage* aMsg, void* aBluetoothReplyRunnable)
+UnpackObjectPathMessage(DBusMessage* aMsg, BluetoothValue& aValue,
+                        nsAString& aErrorStr)
 {
-  MOZ_ASSERT(!NS_IsMainThread());
   DBusError err;
   dbus_error_init(&err);
-  nsRefPtr<BluetoothReplyRunnable> replyRunnable =
-    dont_AddRef(static_cast< BluetoothReplyRunnable* >(aBluetoothReplyRunnable));
-
-  NS_ASSERTION(replyRunnable, "Callback reply runnable is null!");
-
-  nsString replyError;
-  nsString replyPath;
-
-  nsTArray<BluetoothNamedValue> replyValues;
-  BluetoothValue v;
-  if (!IsDBusMessageError(aMsg, replyError)) {
+  if (!IsDBusMessageError(aMsg, aErrorStr)) {
     NS_ASSERTION(dbus_message_get_type(aMsg) == DBUS_MESSAGE_TYPE_METHOD_RETURN,
                  "Got dbus callback that's not a METHOD_RETURN!");
     const char* object_path;
     if (!dbus_message_get_args(aMsg, &err, DBUS_TYPE_OBJECT_PATH,
                                &object_path, DBUS_TYPE_INVALID) ||
         !object_path) {
       if (dbus_error_is_set(&err)) {
-        replyError = NS_ConvertUTF8toUTF16(err.message);
+        aErrorStr = NS_ConvertUTF8toUTF16(err.message);
         LOG_AND_FREE_DBUS_ERROR(&err);
       }
     } else {
-      v = NS_ConvertUTF8toUTF16(object_path);
+      aValue = NS_ConvertUTF8toUTF16(object_path);
     }
   }
-  DispatchBluetoothReply(replyRunnable, v, replyError);
 }
 
+typedef void (*UnpackFunc)(DBusMessage*, BluetoothValue&, nsAString&);
+
 void
-GetVoidCallback(DBusMessage* aMsg, void* aBluetoothReplyRunnable)
+RunDBusCallback(DBusMessage* aMsg, void* aBluetoothReplyRunnable,
+                UnpackFunc aFunc)
 {
   MOZ_ASSERT(!NS_IsMainThread());
-  DBusError err;
-  dbus_error_init(&err);
   nsRefPtr<BluetoothReplyRunnable> replyRunnable =
     dont_AddRef(static_cast< BluetoothReplyRunnable* >(aBluetoothReplyRunnable));
 
   NS_ASSERTION(replyRunnable, "Callback reply runnable is null!");
 
   nsString replyError;
   BluetoothValue v;
-  if (!IsDBusMessageError(aMsg, replyError) &&
+  aFunc(aMsg, v, replyError);
+  DispatchBluetoothReply(replyRunnable, v, replyError);  
+}
+
+void
+GetObjectPathCallback(DBusMessage* aMsg, void* aBluetoothReplyRunnable)
+{
+  RunDBusCallback(aMsg, aBluetoothReplyRunnable, UnpackObjectPathMessage);
+}
+
+void
+UnpackVoidMessage(DBusMessage* aMsg, BluetoothValue& aValue,
+                  nsAString& aErrorStr)
+{
+  DBusError err;
+  dbus_error_init(&err);
+  if (!IsDBusMessageError(aMsg, aErrorStr) &&
       dbus_message_get_type(aMsg) == DBUS_MESSAGE_TYPE_METHOD_RETURN &&
       !dbus_message_get_args(aMsg, &err, DBUS_TYPE_INVALID)) {
     if (dbus_error_is_set(&err)) {
-      replyError = NS_ConvertUTF8toUTF16(err.message);
+      aErrorStr = NS_ConvertUTF8toUTF16(err.message);
       LOG_AND_FREE_DBUS_ERROR(&err);
     }
   }
-  DispatchBluetoothReply(replyRunnable, v, replyError);  
+}
+
+void
+GetVoidCallback(DBusMessage* aMsg, void* aBluetoothReplyRunnable)
+{
+  RunDBusCallback(aMsg, aBluetoothReplyRunnable, UnpackVoidMessage);
 }
 
 bool
 GetProperty(DBusMessageIter aIter, Properties* aPropertyTypes,
-            int aPropertiesTypeLen, int* aPropIndex,
+            int aPropertyTypeLen, int* aPropIndex,
             InfallibleTArray<BluetoothNamedValue>& aProperties)
 {
   DBusMessageIter prop_val, array_val_iter;
   char* property = NULL;
   uint32_t array_type;
   int i, type;
 
   if (dbus_message_iter_get_arg_type(&aIter) != DBUS_TYPE_STRING) {    
@@ -251,23 +276,23 @@ GetProperty(DBusMessageIter aIter, Prope
 
   dbus_message_iter_get_basic(&aIter, &property);
 
   if (!dbus_message_iter_next(&aIter) ||
       dbus_message_iter_get_arg_type(&aIter) != DBUS_TYPE_VARIANT) {
     return false;
   }
 
-  for (i = 0; i <  aPropertiesTypeLen; i++) {
+  for (i = 0; i < aPropertyTypeLen; i++) {
     if (!strncmp(property, aPropertyTypes[i].name, strlen(property))) {      
       break;
     }
   }
 
-  if (i == aPropertiesTypeLen) {
+  if (i == aPropertyTypeLen) {
     return false;
   }
 
   nsString propertyName;
   propertyName.AssignASCII(aPropertyTypes[i].name);
   *aPropIndex = i;
 
   dbus_message_iter_recurse(&aIter, &prop_val);
@@ -305,72 +330,151 @@ GetProperty(DBusMessageIter aIter, Prope
           const char* tmp;
           dbus_message_iter_get_basic(&array_val_iter, &tmp);
           nsString s;
           s = NS_ConvertUTF8toUTF16(tmp);
           arr.AppendElement(s);
         } while (dbus_message_iter_next(&array_val_iter));
         propertyValue = arr;
       } else {
+        // This happens when the array is 0-length. Apparently we get a
+        // DBUS_TYPE_INVALID type.
+        propertyValue = InfallibleTArray<nsString>();
         NS_WARNING("Received array type that's not a string array!");
       }
       break;
     default:
       NS_NOTREACHED("Cannot find dbus message type!");
   }
   aProperties.AppendElement(BluetoothNamedValue(propertyName, propertyValue));
   return true;
 }
 
 void 
-ParseProperties(DBusMessageIter* aIter, 
+ParseProperties(DBusMessageIter* aIter,
+                BluetoothValue& aValue,
+                nsAString& aErrorStr,
                 Properties* aPropertyTypes,
-                const int aPropertiesTypeLen,
-                InfallibleTArray<BluetoothNamedValue>& aProperties)
+                const int aPropertyTypeLen)
 {
   DBusMessageIter dict_entry, dict;
   int prop_index = -1;
 
   NS_ASSERTION(dbus_message_iter_get_arg_type(aIter) == DBUS_TYPE_ARRAY,
                "Trying to parse a property from something that's not an array!");
 
   dbus_message_iter_recurse(aIter, &dict);
-
+  InfallibleTArray<BluetoothNamedValue> props;
   do {
     NS_ASSERTION(dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_DICT_ENTRY,
                  "Trying to parse a property from something that's not an dict!");
     dbus_message_iter_recurse(&dict, &dict_entry);
 
-    if (!GetProperty(dict_entry, aPropertyTypes, aPropertiesTypeLen, &prop_index,
-                     aProperties)) {
+    if (!GetProperty(dict_entry, aPropertyTypes, aPropertyTypeLen, &prop_index,
+                     props)) {
+      aErrorStr.AssignLiteral("Can't Create Property!");
       NS_WARNING("Can't create property!");
       return;
     }
   } while (dbus_message_iter_next(&dict));
+
+  aValue = props;
+}
+
+void UnpackPropertiesMessage(DBusMessage* aMsg, BluetoothValue& aValue,
+                             nsAString& aErrorStr, Properties* aPropertyTypes,
+                             const int aPropertyTypeLen)
+{
+  if (!IsDBusMessageError(aMsg, aErrorStr) &&
+      dbus_message_get_type(aMsg) == DBUS_MESSAGE_TYPE_METHOD_RETURN) {
+    DBusMessageIter iter;
+    if (!dbus_message_iter_init(aMsg, &iter)) {
+      aErrorStr.AssignLiteral("Cannot create dbus message iter!");
+    } else {
+      ParseProperties(&iter, aValue, aErrorStr, aPropertyTypes,
+                      aPropertyTypeLen);
+    }
+  }
+}
+
+void UnpackAdapterPropertiesMessage(DBusMessage* aMsg, BluetoothValue& aValue,
+                                    nsAString& aErrorStr)
+{
+  UnpackPropertiesMessage(aMsg, aValue, aErrorStr,
+                          sAdapterProperties,
+                          ArrayLength(sAdapterProperties));
+}
+
+void UnpackDevicePropertiesMessage(DBusMessage* aMsg, BluetoothValue& aValue,
+                                    nsAString& aErrorStr)
+{
+  UnpackPropertiesMessage(aMsg, aValue, aErrorStr,
+                          sDeviceProperties,
+                          ArrayLength(sDeviceProperties));
+}
+
+void UnpackManagerPropertiesMessage(DBusMessage* aMsg, BluetoothValue& aValue,
+                                    nsAString& aErrorStr)
+{
+  UnpackPropertiesMessage(aMsg, aValue, aErrorStr,
+                          sManagerProperties,
+                          ArrayLength(sManagerProperties));
 }
 
 void
-ParsePropertyChange(DBusMessage* aMsg, Properties* aPropertyTypes,
-                    const int aPropertiesTypeLen,
-                    InfallibleTArray<BluetoothNamedValue>& aProperties)
+GetManagerPropertiesCallback(DBusMessage* aMsg, void* aBluetoothReplyRunnable)
+{
+  RunDBusCallback(aMsg, aBluetoothReplyRunnable, UnpackManagerPropertiesMessage);
+}
+
+void
+GetAdapterPropertiesCallback(DBusMessage* aMsg, void* aBluetoothReplyRunnable)
+{
+  RunDBusCallback(aMsg, aBluetoothReplyRunnable, UnpackAdapterPropertiesMessage);
+}
+
+void
+GetDevicePropertiesCallback(DBusMessage* aMsg, void* aBluetoothReplyRunnable)
+{
+  RunDBusCallback(aMsg, aBluetoothReplyRunnable, UnpackDevicePropertiesMessage);
+}
+
+static DBusCallback sBluetoothDBusPropCallbacks[] =
+{
+  GetManagerPropertiesCallback,
+  GetAdapterPropertiesCallback,
+  GetDevicePropertiesCallback
+};
+
+MOZ_STATIC_ASSERT(sizeof(sBluetoothDBusPropCallbacks) == sizeof(sBluetoothDBusIfaces),
+  "DBus Property callback array and DBus interface array must be same size");
+
+void
+ParsePropertyChange(DBusMessage* aMsg, BluetoothValue& aValue,
+                    nsAString& aErrorStr, Properties* aPropertyTypes,
+                    const int aPropertyTypeLen)
 {
   DBusMessageIter iter;
   DBusError err;
   int prop_index = -1;
+  InfallibleTArray<BluetoothNamedValue> props;
   
   dbus_error_init(&err);
   if (!dbus_message_iter_init(aMsg, &iter)) {
     LOG_AND_FREE_DBUS_ERROR_WITH_MSG(&err, aMsg);
     return;
   }
     
-  if (!GetProperty(iter, aPropertyTypes, aPropertiesTypeLen,
-                   &prop_index, aProperties)) {
+  if (!GetProperty(iter, aPropertyTypes, aPropertyTypeLen,
+                   &prop_index, props)) {
     NS_WARNING("Can't get property!");
+    aErrorStr.AssignLiteral("Can't get property!");
+    return;
   }
+  aValue = props;
 }
 
 // Called by dbus during WaitForAndDispatchEventNative()
 // This function is called on the IOThread
 static
 DBusHandlerResult
 EventFilter(DBusConnection* aConn, DBusMessage* aMsg, void* aData)
 {
@@ -387,72 +491,100 @@ EventFilter(DBusConnection* aConn, DBusM
     return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
   }
 
   DBusError err;
   nsString signalPath;
   nsString signalName;
   dbus_error_init(&err);
   signalPath = NS_ConvertUTF8toUTF16(dbus_message_get_path(aMsg));
-  LOG("%s: Received signal %s:%s from %s\n", __FUNCTION__,
-      dbus_message_get_interface(aMsg), dbus_message_get_member(aMsg),
-      dbus_message_get_path(aMsg));
-
   signalName = NS_ConvertUTF8toUTF16(dbus_message_get_member(aMsg));
+  nsString errorStr;
   BluetoothValue v;
   
   if (dbus_message_is_signal(aMsg, DBUS_ADAPTER_IFACE, "DeviceFound")) {
 
     DBusMessageIter iter;
 
     if (!dbus_message_iter_init(aMsg, &iter)) {
       NS_WARNING("Can't create iterator!");
       return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
     }
 
-    InfallibleTArray<BluetoothNamedValue> value;
     const char* addr;
     dbus_message_iter_get_basic(&iter, &addr);
-    value.AppendElement(BluetoothNamedValue(NS_LITERAL_STRING("Address"),
-                                            NS_ConvertUTF8toUTF16(addr)));
     
     if (dbus_message_iter_next(&iter)) {
       ParseProperties(&iter,
-                      remote_device_properties,
-                      ArrayLength(remote_device_properties),
-                      value);
-      NS_ASSERTION(value.Length() != 0, "Properties returned empty!");
-      v = value;
+                      v,
+                      errorStr,
+                      sDeviceProperties,
+                      ArrayLength(sDeviceProperties));
+      if (v.type() == BluetoothValue::TArrayOfBluetoothNamedValue)
+      {
+        // The DBus DeviceFound message actually passes back a key value object
+        // with the address as the key and the rest of the device properties as
+        // a dict value. After we parse out the properties, we need to go back
+        // and add the address to the ipdl dict we've created to make sure we
+        // have all of the information to correctly build the device.
+        v.get_ArrayOfBluetoothNamedValue()
+          .AppendElement(BluetoothNamedValue(NS_LITERAL_STRING("Address"),
+                                             NS_ConvertUTF8toUTF16(addr)));
+      }
     } else {
-      NS_WARNING("DBus iterator not as long as expected!");
+      errorStr.AssignLiteral("DBus device found message structure not as expected!");
     }
   } else if (dbus_message_is_signal(aMsg, DBUS_ADAPTER_IFACE, "DeviceDisappeared")) {
     const char* str;
     if (!dbus_message_get_args(aMsg, &err,
                                DBUS_TYPE_STRING, &str,
                                DBUS_TYPE_INVALID)) {
       LOG_AND_FREE_DBUS_ERROR_WITH_MSG(&err, aMsg);
+      errorStr.AssignLiteral("Cannot parse device address!");
     }
     v = NS_ConvertUTF8toUTF16(str);
   } else if (dbus_message_is_signal(aMsg, DBUS_ADAPTER_IFACE, "DeviceCreated")) {
     const char* str;
     if (!dbus_message_get_args(aMsg, &err,
                                DBUS_TYPE_OBJECT_PATH, &str,
                                DBUS_TYPE_INVALID)) {
       LOG_AND_FREE_DBUS_ERROR_WITH_MSG(&err, aMsg);
+      errorStr.AssignLiteral("Cannot parse device path!");
     }
     v = NS_ConvertUTF8toUTF16(str);
   } else if (dbus_message_is_signal(aMsg, DBUS_ADAPTER_IFACE, "PropertyChanged")) {
-    InfallibleTArray<BluetoothNamedValue> value;
+    ParsePropertyChange(aMsg,
+                        v,
+                        errorStr,
+                        sAdapterProperties,
+                        ArrayLength(sAdapterProperties));
+  } else if (dbus_message_is_signal(aMsg, DBUS_DEVICE_IFACE, "PropertyChanged")) {
+    ParsePropertyChange(aMsg,
+                        v,
+                        errorStr,
+                        sDeviceProperties,
+                        ArrayLength(sDeviceProperties));
+  } else if (dbus_message_is_signal(aMsg, DBUS_MANAGER_IFACE, "PropertyChanged")) {
     ParsePropertyChange(aMsg,
-                        (Properties*)&adapter_properties,
-                        ArrayLength(adapter_properties),
-                        value);
-    NS_ASSERTION(value.Length() != 0, "Properties returned empty!");
-    v = value;
+                        v,
+                        errorStr,
+                        sManagerProperties,
+                        ArrayLength(sManagerProperties));
+  } else {
+#ifdef DEBUG
+    nsCAutoString signalStr;
+    signalStr += dbus_message_get_member(aMsg);
+    signalStr += " Signal not handled!";
+    NS_WARNING(signalStr.get());
+#endif
+  }
+
+  if (!errorStr.IsEmpty()) {
+    NS_WARNING(NS_ConvertUTF16toUTF8(errorStr).get());
+    return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
   }
 
   BluetoothSignal signal(signalName, signalPath, v);
   
   nsRefPtr<DistributeBluetoothSignalTask>
     t = new DistributeBluetoothSignalTask(signal);
   if (NS_FAILED(NS_DispatchToMainThread(t))) {
     NS_WARNING("Failed to dispatch to main thread!");
@@ -572,8 +704,136 @@ BluetoothDBusService::StopDiscoveryInter
 }
  
 nsresult
 BluetoothDBusService::StartDiscoveryInternal(const nsAString& aAdapterPath,
                                              BluetoothReplyRunnable* aRunnable)
 {
   return SendDiscoveryMessage(aAdapterPath, "StartDiscovery", aRunnable);
 }
+
+nsresult
+BluetoothDBusService::GetProperties(BluetoothObjectType aType,
+                                    const nsAString& aPath,
+                                    BluetoothReplyRunnable* aRunnable)
+{
+  NS_ASSERTION(NS_IsMainThread(), "Must be called from main thread!");
+
+  MOZ_ASSERT(aType < ArrayLength(sBluetoothDBusIfaces));
+  MOZ_ASSERT(aType < ArrayLength(sBluetoothDBusPropCallbacks));
+  
+  const char* interface = sBluetoothDBusIfaces[aType];
+  DBusCallback callback = sBluetoothDBusPropCallbacks[aType];
+  
+  nsRefPtr<BluetoothReplyRunnable> runnable = aRunnable;
+
+  if (!dbus_func_args_async(mConnection,
+                            1000,
+                            callback,
+                            (void*)aRunnable,
+                            NS_ConvertUTF16toUTF8(aPath).get(),
+                            interface,
+                            "GetProperties",
+                            DBUS_TYPE_INVALID)) {
+    NS_WARNING("Could not start async function!");
+    return NS_ERROR_FAILURE;
+  }
+  runnable.forget();
+  return NS_OK;
+}
+
+nsresult
+BluetoothDBusService::SetProperty(BluetoothObjectType aType,
+                                  const nsAString& aPath,
+                                  const BluetoothNamedValue& aValue,
+                                  BluetoothReplyRunnable* aRunnable)
+{
+  NS_ASSERTION(NS_IsMainThread(), "Must be called from main thread!");
+
+  MOZ_ASSERT(aType < ArrayLength(sBluetoothDBusIfaces));
+  const char* interface = sBluetoothDBusIfaces[aType];
+
+  /* Compose the command */
+  DBusMessage* msg = dbus_message_new_method_call("org.bluez",
+                                                  NS_ConvertUTF16toUTF8(aPath).get(),
+                                                  interface,
+                                                  "SetProperty");
+
+  if (!msg) {
+    NS_WARNING("Could not allocate D-Bus message object!");
+    return NS_ERROR_FAILURE;
+  }
+
+  const char* propName = NS_ConvertUTF16toUTF8(aValue.name()).get();
+  if (!dbus_message_append_args(msg, DBUS_TYPE_STRING, &propName, DBUS_TYPE_INVALID)) {
+    NS_WARNING("Couldn't append arguments to dbus message!");
+    return NS_ERROR_FAILURE;
+  }
+  
+  int type;
+  int tmp_int;
+  void* val;
+  nsCString str;
+  if (aValue.value().type() == BluetoothValue::Tuint32_t) {
+    tmp_int = aValue.value().get_uint32_t();
+    val = &tmp_int;
+    type = DBUS_TYPE_UINT32;
+  } else if (aValue.value().type() == BluetoothValue::TnsString) {
+    str = NS_ConvertUTF16toUTF8(aValue.value().get_nsString());
+    val = (void*)str.get();
+    type = DBUS_TYPE_STRING;
+  } else if (aValue.value().type() == BluetoothValue::Tbool) {
+    tmp_int = aValue.value().get_bool() ? 1 : 0;
+    val = &(tmp_int);
+    type = DBUS_TYPE_BOOLEAN;
+  } else {
+    NS_WARNING("Property type not handled!");
+    dbus_message_unref(msg);
+    return NS_ERROR_FAILURE;
+  }
+  
+  DBusMessageIter value_iter, iter;
+  dbus_message_iter_init_append(msg, &iter);
+  char var_type[2] = {(char)type, '\0'};
+  if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_VARIANT, var_type, &value_iter) ||
+      !dbus_message_iter_append_basic(&value_iter, type, val) ||
+      !dbus_message_iter_close_container(&iter, &value_iter)) {
+    NS_WARNING("Could not append argument to method call!");
+    dbus_message_unref(msg);
+    return NS_ERROR_FAILURE;
+  }
+  nsRefPtr<BluetoothReplyRunnable> runnable = aRunnable;
+
+  // msg is unref'd as part of dbus_func_send_async 
+  if (!dbus_func_send_async(mConnection,
+                            msg,
+                            1000,
+                            GetVoidCallback,
+                            (void*)aRunnable)) {
+    NS_WARNING("Could not start async function!");
+    return NS_ERROR_FAILURE;
+  }
+  runnable.forget();
+  return NS_OK;
+}
+
+nsString
+GetObjectPathFromAddress(const nsAString& aAdapterPath,
+                         const nsAString& aDeviceAddress)
+{
+  // The object path would be like /org/bluez/2906/hci0/dev_00_23_7F_CB_B4_F1,
+  // and the adapter path would be the first part of the object path, accoring
+  // to the example above, it's /org/bluez/2906/hci0.
+  nsString devicePath(aAdapterPath);
+  devicePath.AppendLiteral("/dev_");
+  devicePath.Append(aDeviceAddress);
+  devicePath.ReplaceChar(':', '_');
+  return devicePath;
+}
+
+bool
+BluetoothDBusService::GetDevicePath(const nsAString& aAdapterPath,
+                                    const nsAString& aDeviceAddress,
+                                    nsAString& aDevicePath)
+{
+  aDevicePath = GetObjectPathFromAddress(aAdapterPath, aDeviceAddress);
+  return true;
+}
--- a/dom/bluetooth/linux/BluetoothDBusService.h
+++ b/dom/bluetooth/linux/BluetoothDBusService.h
@@ -11,74 +11,53 @@
 #include "mozilla/ipc/RawDBusConnection.h"
 #include "BluetoothService.h"
 
 class DBusMessage;
 
 BEGIN_BLUETOOTH_NAMESPACE
 
 /**
- * BluetoothService functions are used to dispatch messages to Bluetooth DOM
- * objects on the main thread, as well as provide platform independent access
- * to BT functionality. Tasks for polling for outside messages will usually
- * happen on the IO Thread (see ipc/dbus for instance), and these messages will
- * be encased in runnables that will then be distributed via observers managed
- * here.
+ * BluetoothDBusService is the implementation of BluetoothService for DBus on
+ * linux/android/B2G. Function comments are in BluetoothService.h
  */
 
 class BluetoothDBusService : public BluetoothService
                            , private mozilla::ipc::RawDBusConnection
 {
 public:
-  /** 
-   * Set up variables and start the platform specific connection. Must
-   * be called from outside main thread.
-   *
-   * @return NS_OK if connection starts successfully, NS_ERROR_FAILURE
-   * otherwise
-   */
   virtual nsresult StartInternal();
-
-  /** 
-   * Stop the platform specific connection. Must be called from outside main
-   * thread.
-   *
-   * @return NS_OK if connection starts successfully, NS_ERROR_FAILURE
-   * otherwise
-   */
   virtual nsresult StopInternal();
-
-  /** 
-   * Returns the path of the default adapter, implemented via a platform
-   * specific method.
-   *
-   * @return Default adapter path/name on success, NULL otherwise
-   */
   virtual nsresult GetDefaultAdapterPathInternal(BluetoothReplyRunnable* aRunnable);
-
-  /** 
-   * Start device discovery (platform specific implementation)
-   *
-   * @param aAdapterPath Adapter to start discovery on
-   *
-   * @return NS_OK if discovery stopped correctly, NS_ERROR_FAILURE otherwise
-   */
   virtual nsresult StartDiscoveryInternal(const nsAString& aAdapterPath,
                                           BluetoothReplyRunnable* aRunnable);
-  /** 
-   * Stop device discovery (platform specific implementation)
-   *
-   * @param aAdapterPath Adapter to stop discovery on
-   *
-   * @return NS_OK if discovery stopped correctly, NS_ERROR_FAILURE otherwise
-   */
   virtual nsresult StopDiscoveryInternal(const nsAString& aAdapterPath,
                                          BluetoothReplyRunnable* aRunnable);
+  virtual nsresult
+  GetProperties(BluetoothObjectType aType,
+                const nsAString& aPath,
+                BluetoothReplyRunnable* aRunnable);
+  virtual nsresult
+  SetProperty(BluetoothObjectType aType,
+              const nsAString& aPath,
+              const BluetoothNamedValue& aValue,
+              BluetoothReplyRunnable* aRunnable);
+  virtual bool
+  GetDevicePath(const nsAString& aAdapterPath,
+                const nsAString& aDeviceAddress,
+                nsAString& aDevicePath);
 
 private:
+  nsresult SendGetPropertyMessage(const nsAString& aPath,
+                                  const char* aInterface,
+                                  void (*aCB)(DBusMessage *, void *),
+                                  BluetoothReplyRunnable* aRunnable);
   nsresult SendDiscoveryMessage(const nsAString& aAdapterPath,
                                 const char* aMessageName,
                                 BluetoothReplyRunnable* aRunnable);
+  nsresult SendSetPropertyMessage(const nsString& aPath, const char* aInterface,
+                                  const BluetoothNamedValue& aValue,
+                                  BluetoothReplyRunnable* aRunnable);
 };
 
 END_BLUETOOTH_NAMESPACE
 
 #endif
--- a/dom/bluetooth/linux/BluetoothDBusUtils.cpp
+++ b/dom/bluetooth/linux/BluetoothDBusUtils.cpp
@@ -165,17 +165,17 @@ EventFilter(DBusConnection *aConn, DBusM
   }
 
   return DBUS_HANDLER_RESULT_HANDLED;
 }
 
 nsresult
 StartBluetoothConnection()
 {
-  if(sDBusConnection) {
+  if (sDBusConnection) {
     NS_WARNING("DBusConnection already established, skipping");
     return NS_OK;    
   }
   sBluetoothEventObserverTable = new BluetoothEventObserverTable();
   sBluetoothEventObserverTable->Init(100);
 
   sDBusConnection = new RawDBusConnection();
   sDBusConnection->EstablishDBusConnection();
@@ -188,17 +188,17 @@ StartBluetoothConnection()
   }
 
   return NS_OK;
 }
 
 nsresult
 StopBluetoothConnection()
 {
-  if(!sDBusConnection) {
+  if (!sDBusConnection) {
     NS_WARNING("DBusConnection does not exist, nothing to stop, skipping.");
     return NS_OK;
   }
   dbus_connection_remove_filter(sDBusConnection->mConnection, EventFilter, NULL);
   sDBusConnection = NULL;
   sBluetoothEventObserverTable->Clear();
   sBluetoothEventObserverTable = NULL;
   return NS_OK;
--- a/dom/bluetooth/nsIDOMBluetoothAdapter.idl
+++ b/dom/bluetooth/nsIDOMBluetoothAdapter.idl
@@ -4,32 +4,38 @@
  * 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 "nsIDOMEventTarget.idl"
 
 interface nsIDOMDOMRequest;
 interface nsIDOMBluetoothDevice;
 
-[scriptable, builtinclass, uuid(48df7f05-2bbc-4ac8-aa88-9fecd4c24028)]
+[scriptable, builtinclass, uuid(86e9fe78-ce64-476e-a357-333f7d3c8980)]
 interface nsIDOMBluetoothAdapter : nsIDOMEventTarget
 {
   readonly attribute DOMString address;
   [binaryname(AdapterClass)] readonly attribute unsigned long class;
   readonly attribute bool enabled;
   readonly attribute bool discovering;
 
   [implicit_jscontext]
   readonly attribute jsval devices;
 
+  [implicit_jscontext]
+  readonly attribute jsval uuids;
+  
   readonly attribute DOMString name;
   readonly attribute bool discoverable;
   // Unit: sec
   readonly attribute unsigned long discoverableTimeout;
 
+  nsIDOMDOMRequest setName(in DOMString name);
+  nsIDOMDOMRequest setDiscoverable(in bool discoverable);
+  nsIDOMDOMRequest setDiscoverableTimeout(in unsigned long timeout);
   nsIDOMDOMRequest startDiscovery();
   nsIDOMDOMRequest stopDiscovery();
   // Fired when discoverying and any device is discovered.
   attribute nsIDOMEventListener ondevicefound;
   // Fired when any device is out of discoverable range.
   attribute nsIDOMEventListener ondevicedisappeared;
   // Fired when a property of the adapter is changed
   attribute nsIDOMEventListener onpropertychanged;
--- a/dom/bluetooth/nsIDOMBluetoothDevice.idl
+++ b/dom/bluetooth/nsIDOMBluetoothDevice.idl
@@ -1,19 +1,19 @@
 /* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
 /* vim: set ts=2 et sw=2 tw=40: */
 /* 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 "nsIDOMEventTarget.idl"
 
-[scriptable, builtinclass, uuid(2c446123-b5dd-4631-80f6-eda91befd8c9)]
+[scriptable, builtinclass, uuid(24c64513-9587-46c6-b718-bb9b9a754b0d)]
 interface nsIDOMBluetoothDevice : nsIDOMEventTarget
 {
   readonly attribute DOMString address;
   readonly attribute DOMString name;
-
   [binaryname(DeviceClass)] readonly attribute unsigned long class;
+  [implicit_jscontext] readonly attribute jsval uuids;
   readonly attribute bool connected;
   readonly attribute bool paired;
   attribute nsIDOMEventListener onpropertychanged;
 };
new file mode 100644
--- /dev/null
+++ b/dom/bluetooth/nsIDOMBluetoothPropertyEvent.idl
@@ -0,0 +1,13 @@
+/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
+/* vim: set ts=2 et sw=2 tw=40: */
+/* 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 "nsIDOMEvent.idl"
+
+[scriptable, builtinclass, uuid(2604ce78-abaa-4af4-b456-daa4c6386a11)]
+interface nsIDOMBluetoothPropertyEvent : nsIDOMEvent
+{
+  readonly attribute DOMString property;
+};
--- a/dom/browser-element/BrowserElementParent.cpp
+++ b/dom/browser-element/BrowserElementParent.cpp
@@ -188,17 +188,19 @@ BrowserElementParent::OpenWindowInProces
   nsCOMPtr<Element> openerFrameElement =
     do_QueryInterface(openerFrameDOMElement);
 
   nsRefPtr<nsHTMLIFrameElement> popupFrameElement =
     CreateIframe(openerFrameElement);
   NS_ENSURE_TRUE(popupFrameElement, false);
 
   nsCAutoString spec;
-  aURI->GetSpec(spec);
+  if (aURI) {
+    aURI->GetSpec(spec);
+  }
   bool dispatchSucceeded =
     DispatchOpenWindowEvent(openerFrameElement, popupFrameElement,
                             NS_ConvertUTF8toUTF16(spec),
                             aName,
                             NS_ConvertUTF8toUTF16(aFeatures));
   if (!dispatchSucceeded) {
     return false;
   }
--- a/dom/browser-element/BrowserElementParent.h
+++ b/dom/browser-element/BrowserElementParent.h
@@ -48,16 +48,18 @@ public:
    * 2) The embedder (the document which contains the opener iframe) can accept
    *    the window.open request by inserting event.detail.frameElement (an iframe
    *    element) into the DOM somewhere.
    *
    * 3) If the embedder accepted the window.open request, we return true and
    *    set aPopupTabParent's frame element to event.detail.frameElement.
    *    Otherwise, we return false.
    *
+   * @param aURL the URL the new window should load.  The empty string is
+   *             allowed.
    * @param aOpenerTabParent the TabParent whose TabChild called window.open.
    * @param aPopupTabParent the TabParent inside which the opened window will
    *                        live.
    * @return true on success, false otherwise.  Failure is not (necessarily)
    *         an error; it may indicate that the embedder simply rejected the
    *         window.open request.
    */
   static bool
@@ -70,16 +72,18 @@ public:
   /**
    * Handle a window.open call from an in-process <iframe mozbrowser>.
    *
    * As with OpenWindowOOP, we return true if the window.open request
    * succeeded, and return false if the embedder denied the request.
    *
    * (These parameter types are silly, but they match what our caller has in
    * hand.  Feel free to add an override, if they are inconvenient to you.)
+   *
+   * @param aURI the URI the new window should load.  May be null.
    */
   static bool
   OpenWindowInProcess(nsIDOMWindow* aOpenerWindow,
                       nsIURI* aURI,
                       const nsAString& aName,
                       const nsACString& aFeatures,
                       nsIDOMWindow** aReturnWindow);
 };
--- a/dom/camera/CameraCapabilities.h
+++ b/dom/camera/CameraCapabilities.h
@@ -2,22 +2,23 @@
  * 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 DOM_CAMERA_NSCAMERACAPABILITIES_H
 #define DOM_CAMERA_NSCAMERACAPABILITIES_H
 
 #include "CameraControl.h"
 #include "nsAutoPtr.h"
+#include "mozilla/Attributes.h"
 
 namespace mozilla {
 
 typedef nsresult (*ParseItemAndAddFunc)(JSContext* aCx, JSObject* aArray, PRUint32 aIndex, const char* aStart, char** aEnd);
 
-class nsCameraCapabilities : public nsICameraCapabilities
+class nsCameraCapabilities MOZ_FINAL : public nsICameraCapabilities
 {
 public:
   NS_DECL_ISUPPORTS
   NS_DECL_NSICAMERACAPABILITIES
 
   nsCameraCapabilities(nsCameraControl* aCamera);
 
   nsresult ParameterListToNewArray(
--- a/dom/camera/CameraControl.cpp
+++ b/dom/camera/CameraControl.cpp
@@ -20,18 +20,18 @@ using namespace dom;
 DOMCI_DATA(CameraControl, nsICameraControl)
 
 NS_INTERFACE_MAP_BEGIN(nsCameraControl)
   NS_INTERFACE_MAP_ENTRY(nsISupports)
   NS_INTERFACE_MAP_ENTRY(nsICameraControl)
   NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(CameraControl)
 NS_INTERFACE_MAP_END
 
-NS_IMPL_ADDREF(nsCameraControl)
-NS_IMPL_RELEASE(nsCameraControl)
+NS_IMPL_THREADSAFE_ADDREF(nsCameraControl)
+NS_IMPL_THREADSAFE_RELEASE(nsCameraControl)
 
 // Helpers for string properties.
 nsresult
 nsCameraControl::SetHelper(PRUint32 aKey, const nsAString& aValue)
 {
   SetParameter(aKey, NS_ConvertUTF16toUTF8(aValue).get());
   return NS_OK;
 }
--- a/dom/camera/CameraPreview.cpp
+++ b/dom/camera/CameraPreview.cpp
@@ -4,17 +4,17 @@
 
 #include "CameraPreview.h"
 
 #define DOM_CAMERA_LOG_LEVEL  3
 #include "CameraCommon.h"
 
 using namespace mozilla;
 
-NS_IMPL_ISUPPORTS1(CameraPreview, CameraPreview)
+NS_IMPL_THREADSAFE_ISUPPORTS1(CameraPreview, CameraPreview)
 
 class CameraPreviewListener : public MediaStreamListener
 {
 public:
   CameraPreviewListener(CameraPreview* aPreview) :
     mPreview(aPreview)
   {
     DOM_CAMERA_LOGI("%s:%d : this=%p\n", __func__, __LINE__, this);
--- a/dom/camera/DOMCameraManager.h
+++ b/dom/camera/DOMCameraManager.h
@@ -7,18 +7,19 @@
 #ifndef DOM_CAMERA_DOMCAMERAMANAGER_H
 #define DOM_CAMERA_DOMCAMERAMANAGER_H
 
 #include "nsCOMPtr.h"
 #include "nsAutoPtr.h"
 #include "nsIThread.h"
 #include "nsThreadUtils.h"
 #include "nsIDOMCameraManager.h"
+#include "mozilla/Attributes.h"
 
-class nsDOMCameraManager : public nsIDOMCameraManager
+class nsDOMCameraManager MOZ_FINAL : public nsIDOMCameraManager
 {
 public:
   NS_DECL_ISUPPORTS
   NS_DECL_NSIDOMCAMERAMANAGER
 
   static already_AddRefed<nsDOMCameraManager> Create(PRUint64 aWindowId);
 
   void OnNavigation(PRUint64 aWindowId);
--- a/dom/camera/GonkCameraPreview.cpp
+++ b/dom/camera/GonkCameraPreview.cpp
@@ -67,26 +67,26 @@ GonkCameraPreview::ReceiveFrame(PRUint8 
 
   switch (mFormat) {
     case GonkCameraHardware::PREVIEW_FORMAT_YUV420SP:
       {
         // de-interlace the u and v planes
         uint8_t* y = aData;
         uint32_t yN = mWidth * mHeight;
 
-        NS_ASSERTION(yN & 0x3 == 0, "Invalid image dimensions!");
+        NS_ASSERTION((yN & 0x3) == 0, "Invalid image dimensions!");
 
         uint32_t uvN = yN / 4;
         uint32_t* src = (uint32_t*)( y + yN );
         uint32_t* d = new uint32_t[ uvN / 2 ];
         uint32_t* u = d;
         uint32_t* v = u + uvN / 4;
 
         // we're handling pairs of 32-bit words, so divide by 8
-        NS_ASSERTION(uvN & 0x7 == 0, "Invalid image dimensions!");
+        NS_ASSERTION((uvN & 0x7) == 0, "Invalid image dimensions!");
         uvN /= 8;
 
         while (uvN--) {
           uint32_t src0 = *src++;
           uint32_t src1 = *src++;
 
           uint32_t u0;
           uint32_t v0;
@@ -131,21 +131,21 @@ GonkCameraPreview::ReceiveFrame(PRUint8 
    */
   const PRUint8 lumaBpp = 8;
   const PRUint8 chromaBpp = 4;
   PlanarYCbCrImage::Data data;
   data.mYChannel = aData;
   data.mYSize = gfxIntSize(mWidth, mHeight);
 
   data.mYStride = mWidth * lumaBpp;
-  NS_ASSERTION(data.mYStride & 0x7 == 0, "Invalid image dimensions!");
+  NS_ASSERTION((data.mYStride & 0x7) == 0, "Invalid image dimensions!");
   data.mYStride /= 8;
 
   data.mCbCrStride = mWidth * chromaBpp;
-  NS_ASSERTION(data.mCbCrStride & 0x7 == 0, "Invalid image dimensions!");
+  NS_ASSERTION((data.mCbCrStride & 0x7) == 0, "Invalid image dimensions!");
   data.mCbCrStride /= 8;
 
   data.mCbChannel = aData + mHeight * data.mYStride;
   data.mCrChannel = data.mCbChannel + mHeight * data.mCbCrStride / 2;
   data.mCbCrSize = gfxIntSize(mWidth / 2, mHeight / 2);
   data.mPicX = 0;
   data.mPicY = 0;
   data.mPicSize = gfxIntSize(mWidth, mHeight);
--- a/dom/ipc/TabChild.cpp
+++ b/dom/ipc/TabChild.cpp
@@ -380,17 +380,19 @@ TabChild::BrowserFrameProvideWindow(nsID
 {
   *aReturn = nullptr;
 
   nsRefPtr<TabChild> newChild =
     static_cast<TabChild*>(Manager()->SendPBrowserConstructor(
       /* aChromeFlags = */ 0, mIsBrowserElement, mAppId));
 
   nsCAutoString spec;
-  aURI->GetSpec(spec);
+  if (aURI) {
+    aURI->GetSpec(spec);
+  }
 
   NS_ConvertUTF8toUTF16 url(spec);
   nsString name(aName);
   NS_ConvertUTF8toUTF16 features(aFeatures);
   newChild->SendBrowserFrameOpenWindow(this, url, name,
                                        features, aWindowIsNew);
   if (!*aWindowIsNew) {
     PBrowserChild::Send__delete__(newChild);
--- a/dom/plugins/base/nsPluginNativeWindowGtk2.cpp
+++ b/dom/plugins/base/nsPluginNativeWindowGtk2.cpp
@@ -13,16 +13,17 @@
 #include "nsPluginNativeWindow.h"
 #include "npapi.h"
 #include <gtk/gtk.h>
 #include <gdk/gdkx.h>
 #include <gdk/gdk.h>
 
 #include "gtk2compat.h"
 #include "gtk2xtbin.h"
+#include "mozilla/X11Util.h"
 
 class nsPluginNativeWindowGtk2 : public nsPluginNativeWindow {
 public: 
   nsPluginNativeWindowGtk2();
   virtual ~nsPluginNativeWindowGtk2();
 
   virtual nsresult CallSetWindow(nsRefPtr<nsNPAPIPluginInstance> &aPluginInstance);
 private:
@@ -302,11 +303,11 @@ socket_unrealize_cb(GtkWidget *widget, g
       // This window is not known to GDK.
       XUnmapWindow(display, child);
       XReparentWindow(display, child, DefaultRootWindow(display), 0, 0);
     }
   }
 
   if (children) XFree(children);
 
-  XSync(display, False);
+  mozilla::FinishX(display);
   gdk_error_trap_pop();
 }
--- a/dom/plugins/ipc/PluginInstanceParent.cpp
+++ b/dom/plugins/ipc/PluginInstanceParent.cpp
@@ -128,17 +128,17 @@ PluginInstanceParent::ActorDestroy(Actor
     // memory backing this surface may no longer be valid. The right
     // way to inform the nsObjectFrame that the surface is no longer
     // valid is with an invalidate call.
     if (mFrontSurface) {
         mFrontSurface = NULL;
         const NPRect rect = {0, 0, 0, 0};
         RecvNPN_InvalidateRect(rect);
 #ifdef MOZ_X11
-        XSync(DefaultXDisplay(), False);
+        FinishX(DefaultXDisplay());
 #endif
     }
 }
 
 NPError
 PluginInstanceParent::Destroy()
 {
     NPError retval;
@@ -629,17 +629,17 @@ PluginInstanceParent::RecvShow(const NPR
 #ifdef MOZ_X11
     if (mFrontSurface &&
         mFrontSurface->GetType() == gfxASurface::SurfaceTypeXlib)
         // This is the "old front buffer" we're about to hand back to
         // the plugin.  We might still have drawing operations
         // referencing it, so we XSync here to let them finish before
         // the plugin starts scribbling on it again, or worse,
         // destroys it.
-        XSync(DefaultXDisplay(), False);
+        FinishX(DefaultXDisplay());
 #endif
 
     if (mFrontSurface && gfxSharedImageSurface::IsSharedImage(mFrontSurface))
         *prevSurface = static_cast<gfxSharedImageSurface*>(mFrontSurface.get())->GetShmem();
     else
         *prevSurface = null_t();
 
     if (surface) {
@@ -1255,17 +1255,17 @@ PluginInstanceParent::NPP_HandleEvent(vo
                           npevent->xgraphicsexpose.drawable));
         // Make sure the X server has created the Drawable and completes any
         // drawing before the plugin draws on top.
         //
         // XSync() waits for the X server to complete.  Really this parent
         // process does not need to wait; the child is the process that needs
         // to wait.  A possibly-slightly-better alternative would be to send
         // an X event to the child that the child would wait for.
-        XSync(DefaultXDisplay(), False);
+        FinishX(DefaultXDisplay());
 
         return CallPaint(npremoteevent, &handled) ? handled : 0;
 
     case ButtonPress:
         // Release any active pointer grab so that the plugin X client can
         // grab the pointer if it wishes.
         Display *dpy = DefaultXDisplay();
 #  ifdef MOZ_WIDGET_GTK
--- a/dom/workers/XMLHttpRequest.h
+++ b/dom/workers/XMLHttpRequest.h
@@ -157,17 +157,17 @@ public:
   void
   Send(const nsAString& aBody, ErrorResult& aRv);
 
   void
   Send(JSObject* aBody, ErrorResult& aRv);
 
   void
   Send(ArrayBuffer& aBody, ErrorResult& aRv) {
-    return Send(aBody.mObj, aRv);
+    return Send(aBody.Obj(), aRv);
   }
 
   void
   SendAsBinary(const nsAString& aBody, ErrorResult& aRv);
 
   void
   Abort(ErrorResult& aRv);
 
--- a/gfx/2d/DrawTargetCG.h
+++ b/gfx/2d/DrawTargetCG.h
@@ -158,15 +158,13 @@ private:
    * NULL otherwise).
    * The data is not considered owned by DrawTargetCG if the DrawTarget was 
    * created for a pre-existing buffer or if the buffer's lifetime is managed
    * by CoreGraphics.
    * Data owned by DrawTargetCG will be deallocated in the destructor. 
    */
   void *mData;
 
-  SurfaceFormat mFormat;
-
   RefPtr<SourceSurfaceCGContext> mSnapshot;
 };
 
 }
 }
--- a/gfx/gl/GLContextProviderEGL.cpp
+++ b/gfx/gl/GLContextProviderEGL.cpp
@@ -1410,17 +1410,17 @@ public:
             mTextureState = Valid;
             mUpdateSurface = nullptr;
             return;
         }
 
         if (mBackingSurface && mUpdateSurface == mBackingSurface) {
 #ifdef MOZ_X11
             if (mBackingSurface->GetType() == gfxASurface::SurfaceTypeXlib) {
-                XSync(DefaultXDisplay(), False);
+                FinishX(DefaultXDisplay());
             }
 #endif
 
             mBackingSurface->SetDeviceOffset(gfxPoint(0, 0));
             mTextureState = Valid;
             mUpdateSurface = nullptr;
             return;
         }
--- a/gfx/gl/GLContextProviderGLX.cpp
+++ b/gfx/gl/GLContextProviderGLX.cpp
@@ -35,17 +35,17 @@
 #ifdef MOZ_WIDGET_GTK
 #include "gfxPlatformGtk.h"
 #endif
 
 namespace mozilla {
 namespace gl {
 
 static bool gIsATI = false;
-static bool gIsChromium = false;
+static bool gClientIsMesa = false;
 static int gGLXMajorVersion = 0, gGLXMinorVersion = 0;
 
 // Check that we have at least version aMajor.aMinor .
 static inline bool
 GLXVersionCheck(int aMajor, int aMinor)
 {
     return aMajor < gGLXMajorVersion ||
            (aMajor == gGLXMajorVersion && aMinor <= gGLXMinorVersion);
@@ -165,36 +165,31 @@ GLXLibrary::EnsureInitialized()
     };
 
     if (!GLLibraryLoader::LoadSymbols(mOGLLibrary, &symbols[0])) {
         NS_WARNING("Couldn't find required entry point in OpenGL shared library");
         return false;
     }
 
     Display *display = DefaultXDisplay();
-
     int screen = DefaultScreen(display);
-    const char *serverVendor = NULL;
-    const char *serverVersionStr = NULL;
-    const char *extensionsStr = NULL;
 
     if (!xQueryVersion(display, &gGLXMajorVersion, &gGLXMinorVersion)) {
         gGLXMajorVersion = 0;
         gGLXMinorVersion = 0;
         return false;
     }
 
-    serverVendor = xQueryServerString(display, screen, GLX_VENDOR);
-    serverVersionStr = xQueryServerString(display, screen, GLX_VERSION);
-
     if (!GLXVersionCheck(1, 1))
         // Not possible to query for extensions.
         return false;
 
-    extensionsStr = xQueryExtensionsString(display, screen);
+    const char *clientVendor = xGetClientString(display, GLX_VENDOR);
+    const char *serverVendor = xQueryServerString(display, screen, GLX_VENDOR);
+    const char *extensionsStr = xQueryExtensionsString(display, screen);
 
     GLLibraryLoader::SymLoadStruct *sym13;
     if (!GLXVersionCheck(1, 3)) {
         // Even if we don't have 1.3, we might have equivalent extensions
         // (as on the Intel X server).
         if (!HasExtension(extensionsStr, "GLX_SGIX_fbconfig")) {
             return false;
         }
@@ -238,20 +233,17 @@ GLXLibrary::EnsureInitialized()
     }
 
     if (HasExtension(extensionsStr, "GLX_ARB_create_context_robustness") &&
         GLLibraryLoader::LoadSymbols(mOGLLibrary, symbols_robustness)) {
         mHasRobustness = true;
     }
 
     gIsATI = serverVendor && DoesStringMatch(serverVendor, "ATI");
-    gIsChromium = (serverVendor &&
-                   DoesStringMatch(serverVendor, "Chromium")) ||
-        (serverVersionStr &&
-         DoesStringMatch(serverVersionStr, "Chromium"));
+    gClientIsMesa = clientVendor && DoesStringMatch(clientVendor, "Mesa");
 
     mInitialized = true;
     return true;
 }
 
 bool
 GLXLibrary::SupportsTextureFromPixmap(gfxASurface* aSurface)
 {
@@ -265,46 +257,87 @@ GLXLibrary::SupportsTextureFromPixmap(gf
 
     return true;
 }
 
 GLXPixmap 
 GLXLibrary::CreatePixmap(gfxASurface* aSurface)
 {
     if (!SupportsTextureFromPixmap(aSurface)) {
-        return 0;
+        return None;
     }
 
+    gfxXlibSurface *xs = static_cast<gfxXlibSurface*>(aSurface);
+    const XRenderPictFormat *format = xs->XRenderFormat();
+    if (!format || format->type != PictTypeDirect) {
+        return None;
+    }
+
+    bool withAlpha =
+        aSurface->GetContentType() == gfxASurface::CONTENT_COLOR_ALPHA;
+
     int attribs[] = { GLX_DOUBLEBUFFER, False,
                       GLX_DRAWABLE_TYPE, GLX_PIXMAP_BIT,
-                      GLX_BIND_TO_TEXTURE_RGBA_EXT, True,
+                      (withAlpha ? GLX_BIND_TO_TEXTURE_RGBA_EXT
+                       : GLX_BIND_TO_TEXTURE_RGB_EXT), True,
                       None };
 
-    int numFormats;
-    Display *display = DefaultXDisplay();
+    int numConfigs = 0;
+    Display *display = xs->XDisplay();
     int xscreen = DefaultScreen(display);
 
-    ScopedXFree<GLXFBConfig> cfg(xChooseFBConfig(display,
-                                                 xscreen,
-                                                 attribs,
-                                                 &numFormats));
-    if (!cfg) {
-        return 0;
+    ScopedXFree<GLXFBConfig> cfgs(xChooseFBConfig(display,
+                                                  xscreen,
+                                                  attribs,
+                                                  &numConfigs));
+
+    int matchIndex = -1;
+    const XRenderDirectFormat& direct = format->direct;
+    unsigned long redMask =
+        static_cast<unsigned long>(direct.redMask) << direct.red;
+    unsigned long greenMask =
+        static_cast<unsigned long>(direct.greenMask) << direct.green;
+    unsigned long blueMask =
+        static_cast<unsigned long>(direct.blueMask) << direct.blue;
+    ScopedXFree<XVisualInfo> vinfo;
+
+    for (int i = 0; i < numConfigs; i++) {
+        int size;
+        // The visual depth won't necessarily match as it may not include the
+        // alpha buffer, so check buffer size.
+        if (sGLXLibrary.xGetFBConfigAttrib(display, cfgs[i],
+                                           GLX_BUFFER_SIZE, &size) != Success ||
+            size != format->depth) {
+            continue;
+        }
+
+        vinfo = sGLXLibrary.xGetVisualFromFBConfig(display, cfgs[i]);
+        if (!vinfo ||
+            vinfo->c_class != TrueColor ||
+            vinfo->red_mask != redMask ||
+            vinfo->green_mask != greenMask ||
+            vinfo->blue_mask != blueMask ) {
+            continue;
+        }
+
+        matchIndex = i;
     }
-    NS_ABORT_IF_FALSE(numFormats > 0,
-                 "glXChooseFBConfig() failed to match our requested format and violated its spec (!)");
-
-    gfxXlibSurface *xs = static_cast<gfxXlibSurface*>(aSurface);
+    if (matchIndex == -1) {
+        NS_WARNING("[GLX] Couldn't find a FBConfig matching Pixmap format");
+        return None;
+    }
 
     int pixmapAttribs[] = { GLX_TEXTURE_TARGET_EXT, GLX_TEXTURE_2D_EXT,
-                            GLX_TEXTURE_FORMAT_EXT, GLX_TEXTURE_FORMAT_RGBA_EXT,
+                            GLX_TEXTURE_FORMAT_EXT,
+                            (withAlpha ? GLX_TEXTURE_FORMAT_RGBA_EXT
+                             : GLX_TEXTURE_FORMAT_RGB_EXT),
                             None};
 
     GLXPixmap glxpixmap = xCreatePixmap(display,
-                                        cfg[0],
+                                        cfgs[matchIndex],
                                         xs->XDrawable(),
                                         pixmapAttribs);
 
     return glxpixmap;
 }
 
 void
 GLXLibrary::DestroyPixmap(GLXPixmap aPixmap)
@@ -321,17 +354,24 @@ void
 GLXLibrary::BindTexImage(GLXPixmap aPixmap)
 {    
     if (!mUseTextureFromPixmap) {
         return;
     }
 
     Display *display = DefaultXDisplay();
     // Make sure all X drawing to the surface has finished before binding to a texture.
-    xWaitX();
+    if (gClientIsMesa) {
+        // Using XSync instead of Mesa's glXWaitX, because its glxWaitX is a
+        // noop when direct rendering unless the current drawable is a
+        // single-buffer window.
+        FinishX(display);
+    } else {
+        xWaitX();
+    }
     xBindTexImage(display, aPixmap, GLX_FRONT_LEFT_EXT, NULL);
 }
 
 void
 GLXLibrary::ReleaseTexImage(GLXPixmap aPixmap)
 {
     if (!mUseTextureFromPixmap) {
         return;
@@ -360,17 +400,17 @@ GLXLibrary::BeforeGLXCall()
         sOldErrorHandler = XSetErrorHandler(GLXErrorHandler);
     }
 }
 
 void
 GLXLibrary::AfterGLXCall()
 {
     if (mDebug) {
-        XSync(DefaultXDisplay(), False);
+        FinishX(DefaultXDisplay());
         if (sErrorEvent.mError.error_code) {
             char buffer[2048];
             XGetErrorText(DefaultXDisplay(), sErrorEvent.mError.error_code, buffer, sizeof(buffer));
             printf_stderr("X ERROR: %s (%i) - Request: %i.%i, Serial: %i",
                           buffer,
                           sErrorEvent.mError.error_code,
                           sErrorEvent.mError.request_code,
                           sErrorEvent.mError.minor_code,
--- a/gfx/layers/basic/BasicLayerManager.cpp
+++ b/gfx/layers/basic/BasicLayerManager.cpp
@@ -919,17 +919,18 @@ already_AddRefed<ReadbackLayer>
 BasicLayerManager::CreateReadbackLayer()
 {
   NS_ASSERTION(InConstruction(), "Only allowed in construction phase");
   nsRefPtr<ReadbackLayer> layer = new BasicReadbackLayer(this);
   return layer.forget();
 }
 
 BasicShadowLayerManager::BasicShadowLayerManager(nsIWidget* aWidget) :
-  BasicLayerManager(aWidget), mTargetRotation(ROTATION_0)
+  BasicLayerManager(aWidget), mTargetRotation(ROTATION_0),
+  mRepeatTransaction(false)
 {
   MOZ_COUNT_CTOR(BasicShadowLayerManager);
 }
 
 BasicShadowLayerManager::~BasicShadowLayerManager()
 {
   MOZ_COUNT_DTOR(BasicShadowLayerManager);
 }
--- a/gfx/layers/ipc/AsyncPanZoomController.cpp
+++ b/gfx/layers/ipc/AsyncPanZoomController.cpp
@@ -8,16 +8,17 @@
 #include "mozilla/gfx/2D.h"
 #include "mozilla/Util.h"
 #include "mozilla/XPCOM.h"
 #include "mozilla/Monitor.h"
 #include "AsyncPanZoomController.h"
 #include "GestureEventListener.h"
 #include "nsIThreadManager.h"
 #include "nsThreadUtils.h"
+#include "Layers.h"
 
 namespace mozilla {
 namespace layers {
 
 #ifndef M_PI
 #define M_PI 3.14159265358979323846
 #endif
 
@@ -692,28 +693,30 @@ void AsyncPanZoomController::RequestCont
     mGeckoContentController->RequestContentRepaint(mFrameMetrics);
   } else {
     mContentPainterStatus = CONTENT_PAINTING_AND_PAINT_PENDING;
   }
 }
 
 bool AsyncPanZoomController::SampleContentTransformForFrame(const TimeStamp& aSampleTime,
                                                             const FrameMetrics& aFrame,
-                                                            const gfx3DMatrix& aCurrentTransform,
+                                                            Layer* aLayer,
                                                             gfx3DMatrix* aNewTransform) {
   // The eventual return value of this function. The compositor needs to know
   // whether or not to advance by a frame as soon as it can. For example, if a
   // fling is happening, it has to keep compositing so that the animation is
   // smooth. If an animation frame is requested, it is the compositor's
   // responsibility to schedule a composite.
   bool requestAnimationFrame = false;
 
+  const gfx3DMatrix& currentTransform = aLayer->GetTransform();
+
   // Scales on the root layer, on what's currently painted.
-  float rootScaleX = aCurrentTransform.GetXScale(),
-        rootScaleY = aCurrentTransform.GetYScale();
+  float rootScaleX = currentTransform.GetXScale(),
+        rootScaleY = currentTransform.GetYScale();
 
   nsIntPoint metricsScrollOffset(0, 0);
   nsIntPoint scrollOffset;
   float localScaleX, localScaleY;
 
   {
     MonitorAutoLock mon(mMonitor);
 
@@ -735,17 +738,24 @@ bool AsyncPanZoomController::SampleConte
     scrollOffset = mFrameMetrics.mViewportScrollOffset;
   }
 
   nsIntPoint scrollCompensation(
     (scrollOffset.x / rootScaleX - metricsScrollOffset.x) * localScaleX,
     (scrollOffset.y / rootScaleY - metricsScrollOffset.y) * localScaleY);
 
   ViewTransform treeTransform(-scrollCompensation, localScaleX, localScaleY);
-  *aNewTransform = gfx3DMatrix(treeTransform) * aCurrentTransform;
+  *aNewTransform = gfx3DMatrix(treeTransform) * currentTransform;
+
+  // The transform already takes the resolution scale into account.  Since we
+  // will apply the resolution scale again when computing the effective
+  // transform, we must apply the inverse resolution scale here.
+  aNewTransform->Scale(1.0f/aLayer->GetXScale(),
+                       1.0f/aLayer->GetYScale(),
+                       1);
 
   mLastSampleTime = aSampleTime;
 
   return requestAnimationFrame;
 }
 
 void AsyncPanZoomController::NotifyLayersUpdated(const FrameMetrics& aViewportFrame, bool aIsFirstPaint) {
   MonitorAutoLock monitor(mMonitor);
--- a/gfx/layers/ipc/AsyncPanZoomController.h
+++ b/gfx/layers/ipc/AsyncPanZoomController.h
@@ -105,25 +105,25 @@ public:
   /**
    * The compositor calls this when it's about to draw pannable/zoomable content
    * and is setting up transforms for compositing the layer tree. This is not
    * idempotent. For example, a fling transform can be applied each time this is
    * called (though not necessarily). |aSampleTime| is the time that this is
    * sampled at; this is used for interpolating animations. Calling this sets a
    * new transform in |aNewTransform| which should be applied directly to the
    * shadow layer of the frame (do not multiply it in as the code already does
-   * this internally with |aCurrentTransform|.
+   * this internally with |aLayer|'s transform).
    *
    * Return value indicates whether or not any currently running animation
    * should continue. That is, if true, the compositor should schedule another
    * composite.
    */
   bool SampleContentTransformForFrame(const TimeStamp& aSampleTime,
                                       const FrameMetrics& aFrame,
-                                      const gfx3DMatrix& aCurrentTransform,
+                                      Layer* aLayer,
                                       gfx3DMatrix* aNewTransform);
 
   /**
    * A shadow layer update has arrived. |aViewportFrame| is the new FrameMetrics
    * for the top-level frame. |aIsFirstPaint| is a flag passed from the shadow
    * layers code indicating that the frame metrics being sent with this call are
    * the initial metrics and the initial paint of the frame has just happened.
    */
--- a/gfx/layers/ipc/CompositorParent.cpp
+++ b/gfx/layers/ipc/CompositorParent.cpp
@@ -687,17 +687,17 @@ CompositorParent::ApplyAsyncContentTrans
   if (LayerUserData* data = aLayer->GetUserData(&sPanZoomUserDataKey)) {
     AsyncPanZoomController* controller = static_cast<PanZoomUserData*>(data)->mController;
     ShadowLayer* shadow = aLayer->AsShadowLayer();
 
     gfx3DMatrix newTransform;
     *aWantNextFrame |=
       controller->SampleContentTransformForFrame(aCurrentFrame,
                                                  container->GetFrameMetrics(),
-                                                 aLayer->GetTransform(),
+                                                 aLayer,
                                                  &newTransform);
 
     shadow->SetShadowTransform(newTransform);
 
     appliedTransform = true;
   }
 
   return appliedTransform;
--- a/gfx/layers/ipc/ShadowLayerUtilsX11.cpp
+++ b/gfx/layers/ipc/ShadowLayerUtilsX11.cpp
@@ -182,17 +182,17 @@ ShadowLayerForwarder::PlatformSyncBefore
 ShadowLayerManager::PlatformSyncBeforeReplyUpdate()
 {
   if (UsingXCompositing()) {
     // If we're using X surfaces, we need to finish all pending
     // operations on the *front buffers* before handing them back to
     // the child, even though they will be read operations.
     // Otherwise, the child might start scribbling on new back buffers
     // that are still participating in requests as old front buffers.
-    XSync(DefaultXDisplay(), False);
+    FinishX(DefaultXDisplay());
   }
 }
 
 /*static*/ already_AddRefed<TextureImage>
 ShadowLayerManager::OpenDescriptorForDirectTexturing(GLContext*,
                                                      const SurfaceDescriptor&,
                                                      GLenum)
 {
--- a/gfx/src/X11Util.cpp
+++ b/gfx/src/X11Util.cpp
@@ -32,16 +32,26 @@ XVisualIDToInfo(Display* aDisplay, Visua
             }
         }
     }
 
     NS_ERROR("VisualID not on Screen.");
     return false;
 }
 
+void
+FinishX(Display* aDisplay)
+{
+  unsigned long lastRequest = NextRequest(aDisplay) - 1;
+  if (lastRequest == LastKnownRequestProcessed(aDisplay))
+    return;
+
+  XSync(aDisplay, False);
+}
+
 ScopedXErrorHandler::ErrorEvent* ScopedXErrorHandler::sXErrorPtr;
 
 int
 ScopedXErrorHandler::ErrorHandler(Display *, XErrorEvent *ev)
 {
     // only record the error if no error was previously recorded.
     // this means that in case of multiple errors, it's the first error that we report.
     if (!sXErrorPtr->mError.error_code)
@@ -62,23 +72,18 @@ ScopedXErrorHandler::~ScopedXErrorHandle
 {
     sXErrorPtr = mOldXErrorPtr;
     XSetErrorHandler(mOldErrorHandler);
 }
 
 bool
 ScopedXErrorHandler::SyncAndGetError(Display *dpy, XErrorEvent *ev)
 {
-    XSync(dpy, False);
-    return GetError(ev);
-}
+    FinishX(dpy);
 
-bool
-ScopedXErrorHandler::GetError(XErrorEvent *ev)
-{
     bool retval = mXError.mError.error_code != 0;
     if (ev)
         *ev = mXError.mError;
     mXError = ErrorEvent(); // reset
     return retval;
 }
 
 } // namespace mozilla
--- a/gfx/src/X11Util.h
+++ b/gfx/src/X11Util.h
@@ -47,16 +47,29 @@ DefaultXDisplay()
  * to NULL and 0 respectively.  Both out-parameter pointers are assumed
  * non-NULL.  Returns true in both of these situations, but false if aVisualID
  * is not None and not found on the Display.
  */
 bool
 XVisualIDToInfo(Display* aDisplay, VisualID aVisualID,
                 Visual** aVisual, unsigned int* aDepth);
 
+
+/**
+ * Ensure that all X requests have been processed.
+ *
+ * This is similar to XSync, but doesn't need a round trip if the previous
+ * request was synchronous or if events have been received since the last
+ * request.  Subsequent FinishX calls will be noops if there have been no
+ * intermediate requests.
+ */
+
+void
+FinishX(Display* aDisplay);
+
 /**
  * Invoke XFree() on a pointer to memory allocated by Xlib (if the
  * pointer is nonnull) when this class goes out of scope.
  */
 template <typename T>
 struct ScopedXFreePtrTraits
 {
   typedef T *type;
@@ -119,20 +132,13 @@ public:
 
     /** \returns true if a X error occurred since the last time this method was called on this ScopedXErrorHandler object,
      *           or since the creation of this ScopedXErrorHandler object if this method was never called on it.
      *
      * \param ev this optional parameter, if set, will be filled with the XErrorEvent object. If multiple errors occurred,
      *           the first one will be returned.
      */
     bool SyncAndGetError(Display *dpy, XErrorEvent *ev = nullptr);
-
-    /** Like SyncAndGetError, but does not sync. Faster, but only reliably catches errors in synchronous calls.
-     *
-     * \param ev this optional parameter, if set, will be filled with the XErrorEvent object. If multiple errors occurred,
-     *           the first one will be returned.
-     */
-    bool GetError(XErrorEvent *ev = nullptr);
 };
 
 } // namespace mozilla
 
 #endif  // mozilla_X11Util_h
--- a/ipc/dbus/DBusThread.cpp
+++ b/ipc/dbus/DBusThread.cpp
@@ -77,17 +77,16 @@ enum {
   DBUS_EVENT_LOOP_REMOVE = 3,
 } DBusEventTypes;
 
 // Signals that the DBus thread should listen for. Needs to include
 // all signals any DBus observer object may need.
 
 static const char* DBUS_SIGNALS[] =
 {
-  "type='signal',interface='org.freedesktop.DBus'",
   "type='signal',interface='org.bluez.Adapter'",
   "type='signal',interface='org.bluez.Manager'",
   "type='signal',interface='org.bluez.Device'",
   "type='signal',interface='org.bluez.Input'",
   "type='signal',interface='org.bluez.Network'",
   "type='signal',interface='org.bluez.NetworkServer'",
   "type='signal',interface='org.bluez.HealthDevice'",
   "type='signal',interface='org.bluez.AudioSink'"
--- a/ipc/dbus/DBusThread.h
+++ b/ipc/dbus/DBusThread.h
@@ -7,18 +7,16 @@
 #ifndef mozilla_ipc_dbus_gonk_dbusthread_h__
 #define mozilla_ipc_dbus_gonk_dbusthread_h__
 
 struct DBusMessage;
 
 namespace mozilla {
 namespace ipc {
 
-class nsCString;
-
 /** 
  * Starts the DBus thread, which handles returning signals to objects
  * that call asynchronous functions. This should be called from the
  * main thread at startup.
  *
  * @return True on thread starting correctly, false otherwise
  */
 bool StartDBus();
--- a/js/src/frontend/BytecodeCompiler.cpp
+++ b/js/src/frontend/BytecodeCompiler.cpp
@@ -18,20 +18,20 @@
 
 #include "frontend/TreeContext-inl.h"
 
 using namespace js;
 using namespace js::frontend;
 
 class AutoAttachToRuntime {
     JSRuntime *rt;
+    ScriptSource *ss;
   public:
-    ScriptSource *ss;
-    AutoAttachToRuntime(JSRuntime *rt)
-      : rt(rt), ss(NULL) {}
+    AutoAttachToRuntime(JSRuntime *rt, ScriptSource *ss)
+      : rt(rt), ss(ss) {}
     ~AutoAttachToRuntime() {
         // This makes the source visible to the GC. If compilation fails, and no
         // script refers to it, it will be collected.
         if (ss)
             ss->attachToRuntime(rt);
     }
 };
 
@@ -74,24 +74,24 @@ frontend::CompileScript(JSContext *cx, H
      * The scripted callerFrame can only be given for compile-and-go scripts
      * and non-zero static level requires callerFrame.
      */
     JS_ASSERT_IF(callerFrame, options.compileAndGo);
     JS_ASSERT_IF(staticLevel != 0, callerFrame);
 
     if (!CheckLength(cx, length))
         return NULL;
-    AutoAttachToRuntime attacher(cx->runtime);
+    ScriptSource *ss = cx->new_<ScriptSource>();
+    if (!ss)
+        return NULL;
+    AutoAttachToRuntime attacher(cx->runtime, ss);
     SourceCompressionToken sct(cx);
-    ScriptSource *ss = NULL;
     if (!cx->hasRunOption(JSOPTION_ONLY_CNG_SOURCE) || options.compileAndGo) {
-        ss = ScriptSource::createFromSource(cx, chars, length, false, &sct);
-        if (!ss)
+        if (!ss->setSource(cx, chars, length, false, &sct))
             return NULL;
-        attacher.ss = ss;
     }
 
     Parser parser(cx, options, chars, length, /* foldConstants = */ true);
     if (!parser.init())
         return NULL;
     parser.sct = &sct;
 
     SharedContext sc(cx, scopeChain, /* fun = */ NULL, /* funbox = */ NULL, StrictModeFromContext(cx));
@@ -239,23 +239,24 @@ frontend::CompileScript(JSContext *cx, H
 
 // 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, HandleFunction fun, CompileOptions options,
                               Bindings *bindings, const jschar *chars, size_t length)
 {
     if (!CheckLength(cx, length))
-        return false;
-    AutoAttachToRuntime attacher(cx->runtime);
-    SourceCompressionToken sct(cx);
-    ScriptSource *ss = ScriptSource::createFromSource(cx, chars, length, true, &sct);
+        return NULL;
+    ScriptSource *ss = cx->new_<ScriptSource>();
     if (!ss)
         return NULL;
-    attacher.ss = ss;
+    AutoAttachToRuntime attacher(cx->runtime, ss);
+    SourceCompressionToken sct(cx);
+    if (!ss->setSource(cx, chars, length, true, &sct))
+        return NULL;
 
     options.setCompileAndGo(false);
     Parser parser(cx, options, chars, length, /* foldConstants = */ true);
     if (!parser.init())
         return false;
     parser.sct = &sct;
 
     JS_ASSERT(fun);
--- a/js/src/frontend/BytecodeEmitter.cpp
+++ b/js/src/frontend/BytecodeEmitter.cpp
@@ -1204,17 +1204,17 @@ TryConvertToGname(BytecodeEmitter *bce, 
  *
  * NB: if you add more opcodes specialized from JSOP_NAME, etc., don't forget
  * to update the special cases in EmitFor (for-in) and EmitAssignment (= and
  * op=, e.g. +=).
  */
 static bool
 BindNameToSlot(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn)
 {
-    JS_ASSERT(pn->isKind(PNK_NAME));
+    JS_ASSERT(pn->isKind(PNK_NAME) || pn->isKind(PNK_INTRINSICNAME));
 
     /* Don't attempt if 'pn' is already bound or deoptimized or a nop. */
     JSOp op = pn->getOp();
     if (pn->isBound() || pn->isDeoptimized() || op == JSOP_NOP)
         return true;
 
     /* JSOP_CALLEE is pre-bound by definition. */
     JS_ASSERT(op != JSOP_CALLEE);
@@ -1741,16 +1741,19 @@ EmitNameOp(JSContext *cx, BytecodeEmitte
         return false;
     op = pn->getOp();
 
     if (callContext) {
         switch (op) {
           case JSOP_NAME:
             op = JSOP_CALLNAME;
             break;
+          case JSOP_INTRINSICNAME:
+            op = JSOP_CALLINTRINSIC;
+            break;
           case JSOP_GETGNAME:
             op = JSOP_CALLGNAME;
             break;
           case JSOP_GETARG:
             op = JSOP_CALLARG;
             break;
           case JSOP_GETLOCAL:
             op = JSOP_CALLLOCAL;
@@ -5327,22 +5330,64 @@ EmitCallOrNew(JSContext *cx, BytecodeEmi
      * interpose the lambda-initialized method read barrier -- see the code
      * in jsinterp.cpp for JSOP_LAMBDA followed by JSOP_{SET,INIT}PROP.
      *
      * Then (or in a call case that has no explicit reference-base
      * object) we emit JSOP_UNDEFINED to produce the undefined |this|
      * value required for calls (which non-strict mode functions
      * will box into the global object).
      */
+    uint32_t argc = pn->pn_count - 1;
+    bool emitArgs = true;
     ParseNode *pn2 = pn->pn_head;
     switch (pn2->getKind()) {
       case PNK_NAME:
         if (!EmitNameOp(cx, bce, pn2, callop))
             return false;
         break;
+      case PNK_INTRINSICNAME:
+        if (pn2->atom() == cx->runtime->atomState._CallFunctionAtom)
+        {
+            /*
+             * Special-casing of %_CallFunction to emit bytecode that directly
+             * invokes the callee with the correct |this| object and arguments.
+             * The call %_CallFunction(receiver, ...args, fun) thus becomes:
+             * - emit lookup for fun
+             * - emit lookup for receiver
+             * - emit lookups for ...args
+             *
+             * argc is set to the amount of actually emitted args and the
+             * emitting of args below is disabled by setting emitArgs to false.
+             */
+            if (pn->pn_count < 3) {
+                bce->reportError(pn, JSMSG_MORE_ARGS_NEEDED, "%_CallFunction", "1", "s");
+                return false;
+            }
+            ParseNode *funNode = pn2->pn_next;
+            while (funNode->pn_next)
+                funNode = funNode->pn_next;
+            if (!EmitTree(cx, bce, funNode))
+                return false;
+            ParseNode *receiver = pn2->pn_next;
+            if (!EmitTree(cx, bce, receiver))
+                return false;
+            bool oldInForInit = bce->inForInit;
+            bce->inForInit = false;
+            for (ParseNode *argpn = receiver->pn_next; argpn != funNode; argpn = argpn->pn_next) {
+                if (!EmitTree(cx, bce, argpn))
+                    return false;
+            }
+            bce->inForInit = oldInForInit;
+            argc -= 2;
+            emitArgs = false;
+            break;
+        }
+        if (!EmitNameOp(cx, bce, pn2, callop))
+            return false;
+        break;
       case PNK_DOT:
         if (!EmitPropOp(cx, pn2, pn2->getOp(), bce, callop))
             return false;
         break;
       case PNK_LB:
         JS_ASSERT(pn2->isOp(JSOP_GETELEM));
         if (!EmitElemOp(cx, pn2, callop ? JSOP_CALLELEM : JSOP_GETELEM, bce))
             return false;
@@ -5359,35 +5404,33 @@ EmitCallOrNew(JSContext *cx, BytecodeEmi
         if (!EmitTree(cx, bce, pn2))
             return false;
         callop = false;             /* trigger JSOP_UNDEFINED after */
         break;
     }
     if (!callop && Emit1(cx, bce, JSOP_UNDEFINED) < 0)
         return false;
 
-    /* Remember start of callable-object bytecode for decompilation hint. */
-    ptrdiff_t off = top;
-
-    /*
-     * Emit code for each argument in order, then emit the JSOP_*CALL or
-     * JSOP_NEW bytecode with a two-byte immediate telling how many args
-     * were pushed on the operand stack.
-     */
-    bool oldInForInit = bce->inForInit;
-    bce->inForInit = false;
-    for (ParseNode *pn3 = pn2->pn_next; pn3; pn3 = pn3->pn_next) {
-        if (!EmitTree(cx, bce, pn3))
-            return false;
-    }
-    bce->inForInit = oldInForInit;
-    if (NewSrcNote2(cx, bce, SRC_PCBASE, bce->offset() - off) < 0)
-        return false;
-
-    uint32_t argc = pn->pn_count - 1;
+    if (emitArgs) {
+        /*
+         * Emit code for each argument in order, then emit the JSOP_*CALL or
+         * JSOP_NEW bytecode with a two-byte immediate telling how many args
+         * were pushed on the operand stack.
+         */
+        bool oldInForInit = bce->inForInit;
+        bce->inForInit = false;
+        for (ParseNode *pn3 = pn2->pn_next; pn3; pn3 = pn3->pn_next) {
+            if (!EmitTree(cx, bce, pn3))
+                return false;
+        }
+        bce->inForInit = oldInForInit;
+    }
+    if (NewSrcNote2(cx, bce, SRC_PCBASE, bce->offset() - top) < 0)
+        return false;
+
     if (Emit3(cx, bce, pn->getOp(), ARGC_HI(argc), ARGC_LO(argc)) < 0)
         return false;
     CheckTypeSet(cx, bce, pn->getOp());
     if (pn->isOp(JSOP_EVAL))
         EMIT_UINT16_IMM_OP(JSOP_LINENO, pn->pn_pos.begin.lineno);
     if (pn->pn_xflags & PNX_SETCALL) {
         if (Emit1(cx, bce, JSOP_SETCALL) < 0)
             return false;
--- a/js/src/frontend/ParseNode-inl.h
+++ b/js/src/frontend/ParseNode-inl.h
@@ -30,17 +30,17 @@ UpvarCookie::set(JSContext *cx, unsigned
     level_ = newLevel;
     slot_ = newSlot;
     return true;
 }
 
 inline PropertyName *
 ParseNode::atom() const
 {
-    JS_ASSERT(isKind(PNK_FUNCTION) || isKind(PNK_NAME));
+    JS_ASSERT(isKind(PNK_FUNCTION) || isKind(PNK_NAME) || isKind(PNK_INTRINSICNAME));
     JSAtom *atom = isKind(PNK_FUNCTION) ? pn_funbox->function()->atom : pn_atom;
     return atom->asPropertyName();
 }
 
 inline bool
 ParseNode::isConstant()
 {
     switch (pn_type) {
--- a/js/src/frontend/ParseNode.h
+++ b/js/src/frontend/ParseNode.h
@@ -93,16 +93,17 @@ enum ParseNodeKind {
     PNK_LB,
     PNK_RB,
     PNK_STATEMENTLIST,
     PNK_XMLCURLYEXPR,
     PNK_RC,
     PNK_LP,
     PNK_RP,
     PNK_NAME,
+    PNK_INTRINSICNAME,
     PNK_NUMBER,
     PNK_STRING,
     PNK_REGEXP,
     PNK_TRUE,
     PNK_FALSE,
     PNK_NULL,
     PNK_THIS,
     PNK_FUNCTION,
--- a/js/src/frontend/Parser.cpp
+++ b/js/src/frontend/Parser.cpp
@@ -112,17 +112,18 @@ Parser::Parser(JSContext *cx, const Comp
     tokenStream(cx, options, chars, length, &strictModeGetter),
     tempPoolMark(NULL),
     allocator(cx),
     traceListHead(NULL),
     tc(NULL),
     sct(NULL),
     keepAtoms(cx->runtime),
     foldConstants(foldConstants),
-    compileAndGo(options.compileAndGo)
+    compileAndGo(options.compileAndGo),
+    allowIntrinsicsCalls(options.allowIntrinsicsCalls)
 {
     cx->activeCompilations++;
 }
 
 bool
 Parser::init()
 {
     if (!context->ensureParseMapPool())
@@ -6492,16 +6493,40 @@ Parser::identifierName(bool afterDoubleD
         if (!node)
             return NULL;
     }
 #endif
 
     return node;
 }
 
+ParseNode *
+Parser::intrinsicName()
+{
+    JS_ASSERT(tokenStream.isCurrentTokenType(TOK_MOD));
+    if (tokenStream.getToken() != TOK_NAME) {
+        reportError(NULL, JSMSG_SYNTAX_ERROR);
+        return NULL;
+    }
+
+    PropertyName *name = tokenStream.currentToken().name();
+    if (!(name == context->runtime->atomState._CallFunctionAtom ||
+          context->global()->hasIntrinsicFunction(context, name)))
+    {
+        reportError(NULL, JSMSG_INTRINSIC_NOT_DEFINED, JS_EncodeString(context, name));
+        return NULL;
+    }
+    ParseNode *node = NameNode::create(PNK_INTRINSICNAME, name, this, this->tc);
+    if (!node)
+        return NULL;
+    JS_ASSERT(tokenStream.currentToken().t_op == JSOP_NAME);
+    node->setOp(JSOP_INTRINSICNAME);
+    return node;
+}
+
 #if JS_HAS_XML_SUPPORT
 ParseNode *
 Parser::starOrAtPropertyIdentifier(TokenKind tt)
 {
     JS_ASSERT(tt == TOK_AT || tt == TOK_STAR);
     if (allowsXML())
         return (tt == TOK_AT) ? attributeIdentifier() : qualifiedIdentifier();
     reportError(NULL, JSMSG_SYNTAX_ERROR);
@@ -7049,16 +7074,22 @@ Parser::primaryExpr(TokenKind tt, bool a
         return new_<BooleanLiteral>(true, tokenStream.currentToken().pos);
       case TOK_FALSE:
         return new_<BooleanLiteral>(false, tokenStream.currentToken().pos);
       case TOK_THIS:
         return new_<ThisLiteral>(tokenStream.currentToken().pos);
       case TOK_NULL:
         return new_<NullLiteral>(tokenStream.currentToken().pos);
 
+      case TOK_MOD:
+        if (allowIntrinsicsCalls)
+            return intrinsicName();
+        else
+            goto syntaxerror;
+
       case TOK_ERROR:
         /* The scanner or one of its subroutines reported the error. */
         return NULL;
 
     syntaxerror:
       default:
         reportError(NULL, JSMSG_SYNTAX_ERROR);
         return NULL;
--- a/js/src/frontend/Parser.h
+++ b/js/src/frontend/Parser.h
@@ -49,16 +49,22 @@ struct Parser : private AutoGCRooter
 
     /* Perform constant-folding; must be true when interfacing with the emitter. */
     const bool          foldConstants:1;
 
   private:
     /* Script can optimize name references based on scope chain. */
     const bool          compileAndGo:1;
 
+    /*
+     * Self-hosted scripts can use the special syntax %funName(..args) to call
+     * internal functions.
+     */
+    const bool          allowIntrinsicsCalls:1;
+
   public:
     Parser(JSContext *cx, const CompileOptions &options,
            const jschar *chars, size_t length, bool foldConstants);
     ~Parser();
 
     friend void AutoGCRooter::trace(JSTracer *trc);
 
     /*
@@ -225,16 +231,17 @@ struct Parser : private AutoGCRooter
     ParseNode *bracketedExpr();
     ParseNode *letBlock(LetContext letContext);
     ParseNode *returnOrYield(bool useAssignExpr);
     ParseNode *destructuringExpr(BindData *data, TokenKind tt);
 
     bool checkForFunctionNode(PropertyName *name, ParseNode *node);
 
     ParseNode *identifierName(bool afterDoubleDot);
+    ParseNode *intrinsicName();
 
 #if JS_HAS_XML_SUPPORT
     // True if E4X syntax is allowed in the current syntactic context. Note this
     // function may be false while TokenStream::allowsXML() is true!
     // Specifically, when strictModeState is not STRICT, Parser::allowsXML()
     // will be false, where TokenStream::allowsXML() is only false when
     // strictModeState is STRICT. The reason for this is when we are parsing the
     // directive prologue, the tokenizer looks ahead into the body of the
--- a/js/src/gc/Statistics.cpp
+++ b/js/src/gc/Statistics.cpp
@@ -20,18 +20,18 @@
 #include "gc/Memory.h"
 #include "gc/Statistics.h"
 
 #include "gc/Barrier-inl.h"
 
 namespace js {
 namespace gcstats {
 
-/* Except for the first and last, slices of less than 12ms are not reported. */
-static const int64_t SLICE_MIN_REPORT_TIME = 12 * PRMJ_USEC_PER_MSEC;
+/* Except for the first and last, slices of less than 42ms are not reported. */
+static const int64_t SLICE_MIN_REPORT_TIME = 42 * PRMJ_USEC_PER_MSEC;
 
 class StatisticsSerializer
 {
     typedef Vector<char, 128, SystemAllocPolicy> CharBuffer;
     CharBuffer buf_;
     bool asJSON_;
     bool needComma_;
     bool oom_;
--- a/js/src/js.msg
+++ b/js/src/js.msg
@@ -347,8 +347,9 @@ MSG_DEF(JSMSG_QUERY_INNERMOST_WITHOUT_LI
 MSG_DEF(JSMSG_DEBUG_VARIABLE_NOT_FOUND, 294, 0, JSEXN_TYPEERR, "variable not found in environment")
 MSG_DEF(JSMSG_PARAMETER_AFTER_REST,   295, 0, JSEXN_SYNTAXERR, "parameter after rest parameter")
 MSG_DEF(JSMSG_NO_REST_NAME,           296, 0, JSEXN_SYNTAXERR, "no parameter name after ...")
 MSG_DEF(JSMSG_ARGUMENTS_AND_REST,     297, 0, JSEXN_SYNTAXERR, "'arguments' object may not be used in conjunction with a rest parameter")
 MSG_DEF(JSMSG_FUNCTION_ARGUMENTS_AND_REST, 298, 0, JSEXN_ERR, "the 'arguments' property of a function with a rest parameter may not be used")
 MSG_DEF(JSMSG_REST_WITH_DEFAULT,      299, 0, JSEXN_SYNTAXERR, "rest parameter may not have a default")
 MSG_DEF(JSMSG_NONDEFAULT_FORMAL_AFTER_DEFAULT, 300, 0, JSEXN_SYNTAXERR, "parameter(s) with default followed by parameter without default")
 MSG_DEF(JSMSG_YIELD_IN_DEFAULT,       301, 0, JSEXN_SYNTAXERR, "yield in default expression")
+MSG_DEF(JSMSG_INTRINSIC_NOT_DEFINED,  302, 1, JSEXN_REFERENCEERR, "no intrinsic function {0}")
--- a/js/src/jsanalyze.cpp
+++ b/js/src/jsanalyze.cpp
@@ -565,16 +565,18 @@ ScriptAnalysis::analyzeBytecode(JSContex
           case JSOP_INSTANCEOF:
           case JSOP_LINENO:
           case JSOP_ENUMELEM:
           case JSOP_CONDSWITCH:
           case JSOP_LABEL:
           case JSOP_RETRVAL:
           case JSOP_GETGNAME:
           case JSOP_CALLGNAME:
+          case JSOP_INTRINSICNAME:
+          case JSOP_CALLINTRINSIC:
           case JSOP_SETGNAME:
           case JSOP_REGEXP:
           case JSOP_OBJECT:
           case JSOP_UINT24:
           case JSOP_GETXPROP:
           case JSOP_INT8:
           case JSOP_INT32:
           case JSOP_HOLE:
--- a/js/src/jsapi.cpp
+++ b/js/src/jsapi.cpp
@@ -5053,26 +5053,69 @@ ReadCompleteFile(JSContext *cx, FILE *fp
             break;
         if (!buffer.append(c))
             return false;
     }
 
     return true;
 }
 
+class AutoFile
+{
+    FILE *fp_;
+  public:
+    AutoFile()
+      : fp_(NULL)
+    {}
+    ~AutoFile()
+    {
+        if (fp_ && fp_ != stdin)
+            fclose(fp_);
+    }
+    FILE *fp() const { return fp_; }
+    bool open(JSContext *cx, const char *filename);
+    bool readAll(JSContext *cx, FileContents &buffer)
+    {
+        JS_ASSERT(fp_);
+        return ReadCompleteFile(cx, fp_, buffer);
+    }
+};
+
+/*
+ * Open a source file for reading. Supports "-" and NULL to mean stdin. The
+ * return value must be fclosed unless it is stdin.
+ */
+bool
+AutoFile::open(JSContext *cx, const char *filename)
+{
+    if (!filename || strcmp(filename, "-") == 0) {
+        fp_ = stdin;
+    } else {
+        fp_ = fopen(filename, "r");
+        if (!fp_) {
+            JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_CANT_OPEN,
+                                 filename, "No such file or directory");
+            return false;
+        }
+    }
+    return true;
+}
+
+
 JS::CompileOptions::CompileOptions(JSContext *cx)
     : principals(NULL),
       originPrincipals(NULL),
       version(cx->findVersion()),
       versionSet(false),
       utf8(false),
       filename(NULL),
       lineno(1),
       compileAndGo(cx->hasRunOption(JSOPTION_COMPILE_N_GO)),
-      noScriptRval(cx->hasRunOption(JSOPTION_NO_SCRIPT_RVAL))
+      noScriptRval(cx->hasRunOption(JSOPTION_NO_SCRIPT_RVAL)),
+      allowIntrinsicsCalls(false)
 {
 }
 
 JSScript *
 JS::Compile(JSContext *cx, HandleObject obj, CompileOptions options,
             const jschar *chars, size_t length)
 {
     Maybe<AutoVersionAPI> mava;
@@ -5117,31 +5160,21 @@ JS::Compile(JSContext *cx, HandleObject 
 
     JSScript *script = Compile(cx, obj, options, buffer.begin(), buffer.length());
     return script;
 }
 
 JSScript *
 JS::Compile(JSContext *cx, HandleObject obj, CompileOptions options, const char *filename)
 {
-    FILE *fp;
-    if (!filename || strcmp(filename, "-") == 0) {
-        fp = stdin;
-    } else {
-        fp = fopen(filename, "r");
-        if (!fp) {
-            JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_CANT_OPEN,
-                                 filename, "No such file or directory");
-            return NULL;
-        }
-    }
-
-    JSScript *script = Compile(cx, obj, options, fp);
-    if (fp != stdin)
-        fclose(fp);
+    AutoFile file;
+    if (!file.open(cx, filename))
+        return NULL;
+    options = options.setFileAndLine(filename, 1);
+    JSScript *script = Compile(cx, obj, options, file.fp());
     return script;
 }
 
 extern JS_PUBLIC_API(JSScript *)
 JS_CompileUCScriptForPrincipalsVersion(JSContext *cx, JSObject *obj_,
                                        JSPrincipals *principals,
                                        const jschar *chars, size_t length,
                                        const char *filename, unsigned lineno,
@@ -5619,16 +5652,31 @@ JS::Evaluate(JSContext *cx, HandleObject
     if (!chars)
         return NULL;
 
     bool ok = Evaluate(cx, obj, options, chars, length, rval);
     cx->free_(chars);
     return ok;
 }
 
+extern JS_PUBLIC_API(bool)
+JS::Evaluate(JSContext *cx, HandleObject obj, CompileOptions options,
+             const char *filename, jsval *rval)
+{
+    FileContents buffer(cx);
+    {
+        AutoFile file;
+        if (!file.open(cx, filename) || !file.readAll(cx, buffer))
+            return NULL;
+    }
+
+    options = options.setFileAndLine(filename, 1);
+    return Evaluate(cx, obj, options, buffer.begin(), buffer.length(), rval);
+}
+
 JS_PUBLIC_API(JSBool)
 JS_EvaluateUCScriptForPrincipals(JSContext *cx, JSObject *obj_,
                                  JSPrincipals *principals,
                                  const jschar *chars, unsigned length,
                                  const char *filename, unsigned lineno,
                                  jsval *rval)
 {
     RootedObject obj(cx, obj_);
@@ -5951,19 +5999,25 @@ JS_InternJSString(JSContext *cx, JSStrin
     JSAtom *atom = js_AtomizeString(cx, str, InternAtom);
     JS_ASSERT_IF(atom, JS_StringHasBeenInterned(cx, atom));
     return atom;
 }
 
 JS_PUBLIC_API(JSString *)
 JS_InternString(JSContext *cx, const char *s)
 {
-    AssertHeapIsIdle(cx);
-    CHECK_REQUEST(cx);
-    JSAtom *atom = js_Atomize(cx, s, strlen(s), InternAtom);
+    return JS_InternStringN(cx, s, strlen(s));
+}
+
+JS_PUBLIC_API(JSString *)
+JS_InternStringN(JSContext *cx, const char *s, size_t length)
+{
+    AssertHeapIsIdle(cx);
+    CHECK_REQUEST(cx);
+    JSAtom *atom = js_Atomize(cx, s, length, InternAtom);
     JS_ASSERT_IF(atom, JS_StringHasBeenInterned(cx, atom));
     return atom;
 }
 
 JS_PUBLIC_API(JSString *)
 JS_NewUCString(JSContext *cx, jschar *chars, size_t length)
 {
     AssertHeapIsIdle(cx);
--- a/js/src/jsapi.h
+++ b/js/src/jsapi.h
@@ -4085,17 +4085,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 + 23)
+#define JSCLASS_GLOBAL_SLOT_COUNT      (JSProto_LIMIT * 3 + 24)
 #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)
 
@@ -4957,27 +4957,29 @@ struct CompileOptions {
     JSPrincipals *originPrincipals;
     JSVersion version;
     bool versionSet;
     bool utf8;
     const char *filename;
     unsigned lineno;
     bool compileAndGo;
     bool noScriptRval;
+    bool allowIntrinsicsCalls;
 
     CompileOptions(JSContext *cx);
     CompileOptions &setPrincipals(JSPrincipals *p) { principals = p; return *this; }
     CompileOptions &setOriginPrincipals(JSPrincipals *p) { originPrincipals = p; return *this; }
     CompileOptions &setVersion(JSVersion v) { version = v; versionSet = true; return *this; }
     CompileOptions &setUTF8(bool u) { utf8 = u; return *this; }
     CompileOptions &setFileAndLine(const char *f, unsigned l) {
         filename = f; lineno = l; return *this;
     }
     CompileOptions &setCompileAndGo(bool cng) { compileAndGo = cng; return *this; }
     CompileOptions &setNoScriptRval(bool nsr) { noScriptRval = nsr; return *this; }
+    CompileOptions &setAllowIntrinsicsCalls(bool aic) { allowIntrinsicsCalls = aic; return *this; }
 };
 
 extern JS_PUBLIC_API(JSScript *)
 Compile(JSContext *cx, JSHandleObject obj, CompileOptions options,
         const char *bytes, size_t length);
 
 extern JS_PUBLIC_API(JSScript *)
 Compile(JSContext *cx, JSHandleObject obj, CompileOptions options,
@@ -5131,16 +5133,20 @@ namespace JS {
 extern JS_PUBLIC_API(bool)
 Evaluate(JSContext *cx, JSHandleObject obj, CompileOptions options,
          const jschar *chars, size_t length, jsval *rval);
 
 extern JS_PUBLIC_API(bool)
 Evaluate(JSContext *cx, JSHandleObject obj, CompileOptions options,
          const char *bytes, size_t length, jsval *rval);
 
+extern JS_PUBLIC_API(bool)
+Evaluate(JSContext *cx, JSHandleObject obj, CompileOptions options,
+         const char *filename, jsval *rval);
+
 } /* namespace JS */
 
 JS_BEGIN_EXTERN_C
 #endif
 
 extern JS_PUBLIC_API(JSBool)
 JS_CallFunction(JSContext *cx, JSObject *obj, JSFunction *fun, unsigned argc,
                 jsval *argv, jsval *rval);
@@ -5261,16 +5267,19 @@ JS_NewStringCopyN(JSContext *cx, const c
 
 extern JS_PUBLIC_API(JSString *)
 JS_NewStringCopyZ(JSContext *cx, const char *s);
 
 extern JS_PUBLIC_API(JSString *)
 JS_InternJSString(JSContext *cx, JSString *str);
 
 extern JS_PUBLIC_API(JSString *)
+JS_InternStringN(JSContext *cx, const char *s, size_t length);
+
+extern JS_PUBLIC_API(JSString *)
 JS_InternString(JSContext *cx, const char *s);
 
 extern JS_PUBLIC_API(JSString *)
 JS_NewUCString(JSContext *cx, jschar *chars, size_t length);
 
 extern JS_PUBLIC_API(JSString *)
 JS_NewUCStringCopyN(JSContext *cx, const jschar *s, size_t n);
 
--- a/js/src/jsatom.tbl
+++ b/js/src/jsatom.tbl
@@ -144,8 +144,9 @@ DEFINE_ATOM(lookupGetter, "__lookupGette
 DEFINE_ATOM(lookupSetter, "__lookupSetter__")
 DEFINE_ATOM(parseFloat, "parseFloat")
 DEFINE_ATOM(parseInt, "parseInt")
 DEFINE_ATOM(propertyIsEnumerable, "propertyIsEnumerable")
 DEFINE_ATOM(unescape, "unescape")
 DEFINE_ATOM(uneval, "uneval")
 DEFINE_ATOM(unwatch, "unwatch")
 DEFINE_ATOM(watch, "watch")
+DEFINE_ATOM(_CallFunction, "_CallFunction")
--- a/js/src/jscntxt.cpp
+++ b/js/src/jscntxt.cpp
@@ -1156,24 +1156,25 @@ JSRuntime::setGCMaxMallocBytes(size_t va
     gcMaxMallocBytes = (ptrdiff_t(value) >= 0) ? value : size_t(-1) >> 1;
     for (CompartmentsIter c(this); !c.done(); c.next())
         c->setGCMaxMallocBytes(value);
 }
 
 void
 JSRuntime::updateMallocCounter(JSContext *cx, size_t nbytes)
 {
-    /* We tolerate any thread races when updating gcMallocBytes. */
-    ptrdiff_t oldCount = gcMallocBytes;
-    ptrdiff_t newCount = oldCount - ptrdiff_t(nbytes);
-    gcMallocBytes = newCount;
-    if (JS_UNLIKELY(newCount <= 0 && oldCount > 0))
-        onTooMuchMalloc();
-    else if (cx && cx->compartment)
+    if (cx && cx->compartment) {
         cx->compartment->updateMallocCounter(nbytes);
+    } else {
+        ptrdiff_t oldCount = gcMallocBytes;
+        ptrdiff_t newCount = oldCount - ptrdiff_t(nbytes);
+        gcMallocBytes = newCount;
+        if (JS_UNLIKELY(newCount <= 0 && oldCount > 0))
+            onTooMuchMalloc();
+    }
 }
 
 JS_FRIEND_API(void)
 JSRuntime::onTooMuchMalloc()
 {
     TriggerGC(this, gcreason::TOO_MUCH_MALLOC);
 }
 
--- a/js/src/jscompartment.cpp
+++ b/js/src/jscompartment.cpp
@@ -65,17 +65,17 @@ JSCompartment::JSCompartment(JSRuntime *
     gcTriggerMallocAndFreeBytes(0),
     gcMallocBytes(0),
     debugModeBits(rt->debugMode ? DebugFromC : 0),
     watchpointMap(NULL),
     scriptCountsMap(NULL),
     sourceMapMap(NULL),
     debugScriptMap(NULL)
 {
-    setGCMaxMallocBytes(rt->gcMaxMallocBytes * 0.9);
+    setGCMaxMallocBytes(rt->gcMaxMallocBytes);
 }
 
 JSCompartment::~JSCompartment()
 {
     Foreground::delete_(watchpointMap);
     Foreground::delete_(scriptCountsMap);
     Foreground::delete_(sourceMapMap);
     Foreground::delete_(debugScriptMap);
--- a/js/src/jsfriendapi.cpp
+++ b/js/src/jsfriendapi.cpp
@@ -157,19 +157,19 @@ js::GCForReason(JSRuntime *rt, gcreason:
 
 JS_FRIEND_API(void)
 js::ShrinkingGC(JSRuntime *rt, gcreason::Reason reason)
 {
     GC(rt, GC_SHRINK, reason);
 }
 
 JS_FRIEND_API(void)
-js::IncrementalGC(JSRuntime *rt, gcreason::Reason reason)
+js::IncrementalGC(JSRuntime *rt, gcreason::Reason reason, int64_t millis)
 {
-    GCSlice(rt, GC_NORMAL, reason);
+    GCSlice(rt, GC_NORMAL, reason, millis);
 }
 
 JS_FRIEND_API(void)
 js::FinishIncrementalGC(JSRuntime *rt, gcreason::Reason reason)
 {
     GCFinalSlice(rt, GC_NORMAL, reason);
 }
 
--- a/js/src/jsfriendapi.h
+++ b/js/src/jsfriendapi.h
@@ -702,17 +702,17 @@ SkipCompartmentForGC(JSCompartment *comp
 
 extern JS_FRIEND_API(void)
 GCForReason(JSRuntime *rt, gcreason::Reason reason);
 
 extern JS_FRIEND_API(void)
 ShrinkingGC(JSRuntime *rt, gcreason::Reason reason);
 
 extern JS_FRIEND_API(void)
-IncrementalGC(JSRuntime *rt, gcreason::Reason reason);
+IncrementalGC(JSRuntime *rt, gcreason::Reason reason, int64_t millis = 0);
 
 extern JS_FRIEND_API(void)
 FinishIncrementalGC(JSRuntime *rt, gcreason::Reason reason);
 
 enum GCProgress {
     /*
      * During non-incremental GC, the GC is bracketed by JSGC_CYCLE_BEGIN/END
      * callbacks. During an incremental GC, the sequence of callbacks is as
@@ -1088,16 +1088,45 @@ extern JS_FRIEND_API(JSBool)
 JS_IsInt32Array(JSObject *obj, JSContext *cx);
 extern JS_FRIEND_API(JSBool)
 JS_IsUint32Array(JSObject *obj, JSContext *cx);
 extern JS_FRIEND_API(JSBool)
 JS_IsFloat32Array(JSObject *obj, JSContext *cx);
 extern JS_FRIEND_API(JSBool)
 JS_IsFloat64Array(JSObject *obj, JSContext *cx);
 
+
+/*
+ * Unwrap Typed arrays all at once. Return NULL without throwing if the object
+ * cannot be viewed as the correct typed array, or the typed array object on
+ * success, filling both outparameters.
+ */
+extern JS_FRIEND_API(JSObject *)
+JS_GetObjectAsInt8Array(JSContext *cx, JSObject *obj, uint32_t *length, int8_t **data);
+extern JS_FRIEND_API(JSObject *)
+JS_GetObjectAsUint8Array(JSContext *cx, JSObject *obj, uint32_t *length, uint8_t **data);
+extern JS_FRIEND_API(JSObject *)
+JS_GetObjectAsUint8ClampedArray(JSContext *cx, JSObject *obj, uint32_t *length, uint8_t **data);
+extern JS_FRIEND_API(JSObject *)
+JS_GetObjectAsInt16Array(JSContext *cx, JSObject *obj, uint32_t *length, int16_t **data);
+extern JS_FRIEND_API(JSObject *)
+JS_GetObjectAsUint16Array(JSContext *cx, JSObject *obj, uint32_t *length, uint16_t **data);
+extern JS_FRIEND_API(JSObject *)
+JS_GetObjectAsInt32Array(JSContext *cx, JSObject *obj, uint32_t *length, int32_t **data);
+extern JS_FRIEND_API(JSObject *)
+JS_GetObjectAsUint32Array(JSContext *cx, JSObject *obj, uint32_t *length, uint32_t **data);
+extern JS_FRIEND_API(JSObject *)
+JS_GetObjectAsFloat32Array(JSContext *cx, JSObject *obj, uint32_t *length, float **data);
+extern JS_FRIEND_API(JSObject *)
+JS_GetObjectAsFloat64Array(JSContext *cx, JSObject *obj, uint32_t *length, double **data);
+extern JS_FRIEND_API(JSObject *)
+JS_GetObjectAsArrayBufferView(JSContext *cx, JSObject *obj, uint32_t *length, uint8_t **data);
+extern JS_FRIEND_API(JSObject *)
+JS_GetObjectAsArrayBuffer(JSContext *cx, JSObject *obj, uint32_t *length, uint8_t **data);
+
 /*
  * Get the type of elements in a typed array.
  *
  * |obj| must have passed a JS_IsTypedArrayObject/JS_Is*Array test, or somehow
  * be known that it would pass such a test: it is a typed array or a wrapper of
  * a typed array, and the unwrapping will succeed. If cx is NULL, then DEBUG
  * builds may be unable to assert when unwrapping should be disallowed.
  */
--- a/js/src/jsfun.cpp
+++ b/js/src/jsfun.cpp
@@ -601,18 +601,21 @@ js::FunctionToString(JSContext *cx, Hand
         if (!out.append("function "))
             return NULL;
         if (fun->atom) {
             if (!out.append(fun->atom))
                 return NULL;
         }
     }
     bool haveSource = fun->isInterpreted();
-    if (haveSource && !fun->script()->scriptSource() && !fun->script()->loadSource(cx, &haveSource))
-            return NULL;
+    if (haveSource && !fun->script()->scriptSource()->hasSourceData() &&
+        !fun->script()->loadSource(cx, &haveSource))
+    {
+        return NULL;
+    }
     if (haveSource) {
         RootedScript script(cx, fun->script());
         RootedString src(cx, fun->script()->sourceData(cx));
         if (!src)
             return NULL;
         const jschar *chars = src->getChars(cx);
         if (!chars)
             return NULL;
--- a/js/src/jsgc.cpp
+++ b/js/src/jsgc.cpp
@@ -2626,18 +2626,18 @@ MaybeGC(JSContext *cx)
         GC(rt, GC_NORMAL, gcreason::MAYBEGC);
         return;
     }
 
     if (rt->gcIsNeeded) {
         GCSlice(rt, GC_NORMAL, gcreason::MAYBEGC);
         return;
     }
+
     double factor = rt->gcHighFrequencyGC ? 0.75 : 0.9;
-
     JSCompartment *comp = cx->compartment;
     if (comp->gcBytes > 1024 * 1024 &&
         comp->gcBytes >= factor * comp->gcTriggerBytes &&
         rt->gcIncrementalState == NO_INCREMENTAL &&
         !rt->gcHelperThread.sweeping())
     {
         PrepareCompartmentForGC(comp);
         GCSlice(rt, GC_NORMAL, gcreason::MAYBEGC);
@@ -4246,31 +4246,35 @@ namespace js {
 
 void
 GC(JSRuntime *rt, JSGCInvocationKind gckind, gcreason::Reason reason)
 {
     Collect(rt, false, SliceBudget::Unlimited, gckind, reason);
 }
 
 void
-GCSlice(JSRuntime *rt, JSGCInvocationKind gckind, gcreason::Reason reason)
-{
-    int sliceBudget = rt->gcHighFrequencyGC && rt->gcDynamicMarkSlice
-                      ? rt->gcSliceBudget * IGC_MARK_SLICE_MULTIPLIER
-                      : rt->gcSliceBudget;
+GCSlice(JSRuntime *rt, JSGCInvocationKind gckind, gcreason::Reason reason, int64_t millis)
+{
+    int64_t sliceBudget;
+    if (millis)
+        sliceBudget = SliceBudget::TimeBudget(millis);
+    else if (rt->gcHighFrequencyGC && rt->gcDynamicMarkSlice)
+        sliceBudget = rt->gcSliceBudget * IGC_MARK_SLICE_MULTIPLIER;
+    else
+        sliceBudget = rt->gcSliceBudget;
+
     Collect(rt, true, sliceBudget, gckind, reason);
 }
 
 void
 GCFinalSlice(JSRuntime *rt, JSGCInvocationKind gckind, gcreason::Reason reason)
 {
     Collect(rt, true, SliceBudget::Unlimited, gckind, reason);
 }
 
-
 void
 GCDebugSlice(JSRuntime *rt, bool limit, int64_t objCount)
 {
     int64_t budget = limit ? SliceBudget::WorkBudget(objCount) : SliceBudget::Unlimited;
     PrepareForDebugGC(rt);
     Collect(rt, true, budget, GC_NORMAL, gcreason::API);
 }
 
--- a/js/src/jsgc.h
+++ b/js/src/jsgc.h
@@ -520,17 +520,17 @@ typedef enum JSGCInvocationKind {
     /* Minimize GC triggers and release empty GC chunks right away. */
     GC_SHRINK             = 1
 } JSGCInvocationKind;
 
 extern void
 GC(JSRuntime *rt, JSGCInvocationKind gckind, js::gcreason::Reason reason);
 
 extern void
-GCSlice(JSRuntime *rt, JSGCInvocationKind gckind, js::gcreason::Reason reason);
+GCSlice(JSRuntime *rt, JSGCInvocationKind gckind, js::gcreason::Reason reason, int64_t millis = 0);
 
 extern void
 GCFinalSlice(JSRuntime *rt, JSGCInvocationKind gckind, js::gcreason::Reason reason);
 
 extern void
 GCDebugSlice(JSRuntime *rt, bool limit, int64_t objCount);
 
 extern void
--- a/js/src/jsinfer.cpp
+++ b/js/src/jsinfer.cpp
@@ -3389,21 +3389,23 @@ ScriptAnalysis::analyzeTypesBytecode(JSC
             pushed[0].addPropagateThis(cx, script, pc, Type::UnknownType());
 
         if (CheckNextTest(pc))
             pushed[0].addType(cx, Type::UndefinedType());
         break;
       }
 
       case JSOP_NAME:
-      case JSOP_CALLNAME: {
+      case JSOP_INTRINSICNAME:
+      case JSOP_CALLNAME:
+      case JSOP_CALLINTRINSIC: {
         TypeSet *seen = bytecodeTypes(pc);
         addTypeBarrier(cx, pc, seen, Type::UnknownType());
         seen->addSubset(cx, &pushed[0]);
-        if (op == JSOP_CALLNAME)
+        if (op == JSOP_CALLNAME || op == JSOP_CALLINTRINSIC)
             pushed[0].addPropagateThis(cx, script, pc, Type::UnknownType());
         break;
       }
 
       case JSOP_BINDGNAME:
       case JSOP_BINDNAME:
         break;
 
--- a/js/src/jsinterp.cpp
+++ b/js/src/jsinterp.cpp
@@ -1413,18 +1413,16 @@ js::Interpret(JSContext *cx, StackFrame 
 #endif
     }
 
 /* No-ops for ease of decompilation. */
 ADD_EMPTY_CASE(JSOP_NOP)
 ADD_EMPTY_CASE(JSOP_UNUSED1)
 ADD_EMPTY_CASE(JSOP_UNUSED2)
 ADD_EMPTY_CASE(JSOP_UNUSED3)
-ADD_EMPTY_CASE(JSOP_UNUSED8)
-ADD_EMPTY_CASE(JSOP_UNUSED9)
 ADD_EMPTY_CASE(JSOP_UNUSED10)
 ADD_EMPTY_CASE(JSOP_UNUSED11)
 ADD_EMPTY_CASE(JSOP_UNUSED12)
 ADD_EMPTY_CASE(JSOP_UNUSED13)
 ADD_EMPTY_CASE(JSOP_UNUSED15)
 ADD_EMPTY_CASE(JSOP_UNUSED17)
 ADD_EMPTY_CASE(JSOP_UNUSED18)
 ADD_EMPTY_CASE(JSOP_UNUSED19)
@@ -2519,16 +2517,29 @@ BEGIN_CASE(JSOP_CALLNAME)
     if (!NameOperation(cx, script, regs.pc, rval.address()))
         goto error;
 
     PUSH_COPY(rval);
     TypeScript::Monitor(cx, script, regs.pc, rval);
 }
 END_CASE(JSOP_NAME)
 
+BEGIN_CASE(JSOP_INTRINSICNAME)
+BEGIN_CASE(JSOP_CALLINTRINSIC)
+{
+    RootedValue &rval = rootValue0;
+
+    if (!IntrinsicNameOperation(cx, script, regs.pc, rval.address()))
+        goto error;
+
+    PUSH_COPY(rval);
+    TypeScript::Monitor(cx, script, regs.pc, rval);
+}
+END_CASE(JSOP_INTRINSICNAME)
+
 BEGIN_CASE(JSOP_UINT16)
     PUSH_INT32((int32_t) GET_UINT16(regs.pc));
 END_CASE(JSOP_UINT16)
 
 BEGIN_CASE(JSOP_UINT24)
     PUSH_INT32((int32_t) GET_UINT24(regs.pc));
 END_CASE(JSOP_UINT24)
 
--- a/js/src/jsinterpinlines.h
+++ b/js/src/jsinterpinlines.h
@@ -16,16 +16,17 @@
 #include "jslibmath.h"
 #include "jsnum.h"
 #include "jsprobes.h"
 #include "jsstr.h"
 #include "methodjit/MethodJIT.h"
 
 #include "jsfuninlines.h"
 #include "jsinferinlines.h"
+#include "jsopcodeinlines.h"
 #include "jspropertycacheinlines.h"
 #include "jstypedarrayinlines.h"
 
 #include "vm/Stack-inl.h"
 
 namespace js {
 
 /*
@@ -355,16 +356,27 @@ SetPropertyOperation(JSContext *cx, jsby
         if (!obj->setGeneric(cx, obj, id, &rref, strict))
             return false;
     }
 
     return true;
 }
 
 inline bool
+IntrinsicNameOperation(JSContext *cx, JSScript *script, jsbytecode *pc, Value *vp)
+{
+    JSOp op = JSOp(*pc);
+    RootedPropertyName name(cx);
+    name = GetNameFromBytecode(cx, script, pc, op);
+    JSFunction *fun = cx->global()->getIntrinsicFunction(cx, name);
+    vp->setObject(*fun);
+    return true;
+}
+
+inline bool
 NameOperation(JSContext *cx, JSScript *script, jsbytecode *pc, Value *vp)
 {
     RootedObject obj(cx, cx->stack.currentScriptedScopeChain());
 
     /*
      * Skip along the scope chain to the enclosing global object. This is
      * used for GNAME opcodes where the bytecode emitter has determined a
      * name access must be on the global. It also insulates us from bugs
--- a/js/src/jsopcode.tbl
+++ b/js/src/jsopcode.tbl
@@ -345,19 +345,27 @@ OPDEF(JSOP_FINALLY,     135,"finally",  
 OPDEF(JSOP_GETALIASEDVAR, 136,"getaliasedvar",NULL,   9,  0,  1, 19,  JOF_SCOPECOORD|JOF_NAME|JOF_TYPESET)
 OPDEF(JSOP_CALLALIASEDVAR,137,"callaliasedvar",NULL,  9,  0,  1, 19,  JOF_SCOPECOORD|JOF_NAME|JOF_TYPESET)
 OPDEF(JSOP_SETALIASEDVAR, 138,"setaliasedvar",NULL,   9,  1,  1,  3,  JOF_SCOPECOORD|JOF_NAME|JOF_SET|JOF_DETECTING)
 OPDEF(JSOP_INCALIASEDVAR, 139,"incaliasedvar",NULL,   10, 0,  1, 15,  JOF_SCOPECOORD|JOF_NAME|JOF_INC|JOF_TMPSLOT3|JOF_DECOMPOSE)
 OPDEF(JSOP_DECALIASEDVAR, 140,"decaliasedvar",NULL,   10, 0,  1, 15,  JOF_SCOPECOORD|JOF_NAME|JOF_DEC|JOF_TMPSLOT3|JOF_DECOMPOSE)
 OPDEF(JSOP_ALIASEDVARINC, 141,"aliasedvarinc",NULL,   10, 0,  1, 15,  JOF_SCOPECOORD|JOF_NAME|JOF_INC|JOF_POST|JOF_TMPSLOT3|JOF_DECOMPOSE)
 OPDEF(JSOP_ALIASEDVARDEC, 142,"aliasedvardec",NULL,   10, 0,  1, 15,  JOF_SCOPECOORD|JOF_NAME|JOF_DEC|JOF_POST|JOF_TMPSLOT3|JOF_DECOMPOSE)
 
+/*
+ * Intrinsic names have the syntax %name and can only be used when the 
+ * CompileOptions flag "allowIntrinsicsCalls" is set.
+ *
+ * They are used to access intrinsic functions the runtime doesn't give 
+ * client JS code access to from self-hosted code.
+ */
+OPDEF(JSOP_INTRINSICNAME, 143, "intrinsicname", NULL, 5,  0,  1, 19,  JOF_ATOM|JOF_NAME|JOF_TYPESET)
+OPDEF(JSOP_CALLINTRINSIC, 144, "callintrinsic", NULL, 5,  0,  1, 19,  JOF_ATOM|JOF_NAME|JOF_TYPESET)
+
 /* Unused. */
-OPDEF(JSOP_UNUSED8,       143,"unused8",  NULL,       1,  0,  0,  0,  JOF_BYTE)
-OPDEF(JSOP_UNUSED9,       144,"unused9",  NULL,       1,  0,  0,  0,  JOF_BYTE)
 OPDEF(JSOP_UNUSED10,      145,"unused10", NULL,       1,  0,  0,  0,  JOF_BYTE)
 OPDEF(JSOP_UNUSED11,      146,"unused11", NULL,       1,  0,  0,  0,  JOF_BYTE)
 OPDEF(JSOP_UNUSED12,      147,"unused12", NULL,       1,  0,  0,  0,  JOF_BYTE)
 OPDEF(JSOP_UNUSED13,      148,"unused13", NULL,       1,  0,  0,  0,  JOF_BYTE)
 
 /* Placeholders for a real jump opcode set during backpatch chain fixup. */
 OPDEF(JSOP_BACKPATCH,     149,"backpatch",NULL,       5,  0,  0,  0,  JOF_JUMP|JOF_BACKPATCH)
 OPDEF(JSOP_BACKPATCH_POP, 150,"backpatch_pop",NULL,   5,  1,  0,  0,  JOF_JUMP|JOF_BACKPATCH)
--- a/js/src/jsopcodeinlines.h
+++ b/js/src/jsopcodeinlines.h
@@ -1,14 +1,17 @@
 /* -*- Mode: C; tab-width: 8; 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 jsopcodeinlines_h__
+#define jsopcodeinlines_h__
+
 #include "jsautooplen.h"
 
 #include "frontend/BytecodeEmitter.h"
 
 namespace js {
 
 static inline PropertyName *
 GetNameFromBytecode(JSContext *cx, JSScript *script, jsbytecode *pc, JSOp op)
@@ -113,8 +116,10 @@ public:
     bool isLineHeader() const {
         return lineHeader;
     }
 
     uint32_t getLine() const { return lineno; }
 };
 
 }
+
+#endif /* jsopcodeinlines_h__ */
--- a/js/src/jsscript.cpp
+++ b/js/src/jsscript.cpp
@@ -353,18 +353,18 @@ js::XDRScript(XDRState<mode> *xdr, Handl
         ContainsDynamicNameAccess,
         FunHasExtensibleScope,
         ArgumentsHasVarBinding,
         NeedsArgsObj,
         OwnFilename,
         ParentFilename,
         IsGenerator,
         IsGeneratorExp,
-        HaveSource,
         OwnSource,
+        HasSourceData,
         ExplicitUseStrict
     };
 
     uint32_t length, lineno, nslots;
     uint32_t natoms, nsrcnotes, ntrynotes, nobjects, nregexps, nconsts, nClosedArgs, nClosedVars, i;
     uint32_t prologLength, version;
     uint32_t nTypeSets = 0;
     uint32_t scriptBits = 0;
@@ -514,20 +514,20 @@ js::XDRScript(XDRState<mode> *xdr, Handl
             scriptBits |= (1 << ArgumentsHasVarBinding);
         if (script->analyzedArgsUsage() && script->needsArgsObj())
             scriptBits |= (1 << NeedsArgsObj);
         if (script->filename) {
             scriptBits |= (enclosingScript && enclosingScript->filename == script->filename)
                           ? (1 << ParentFilename)
                           : (1 << OwnFilename);
         }
-        if (script->scriptSource()) {
-            scriptBits |= (1 << HaveSource);
-            if (!enclosingScript || enclosingScript->scriptSource() != script->scriptSource())
-                scriptBits |= (1 << OwnSource);
+        if (!enclosingScript || enclosingScript->scriptSource() != script->scriptSource()) {
+            scriptBits |= (1 << OwnSource);
+            if (script->scriptSource()->hasSourceData())
+                scriptBits |= (1 << HasSourceData);
         }
         if (script->isGenerator)
             scriptBits |= (1 << IsGenerator);
         if (script->isGeneratorExp)
             scriptBits |= (1 << IsGeneratorExp);
 
         JS_ASSERT(!script->compileAndGo);
         JS_ASSERT(!script->hasSingletons);
@@ -568,18 +568,29 @@ js::XDRScript(XDRState<mode> *xdr, Handl
         JSVersion version_ = JSVersion(version & JS_BITMASK(16));
         JS_ASSERT((version_ & VersionFlags::FULL_MASK) == unsigned(version_));
 
         // principals and originPrincipals are set with xdr->initScriptPrincipals(script) below.
         // staticLevel is set below.
         CompileOptions options(cx);
         options.setVersion(version_)
                .setNoScriptRval(!!(scriptBits & (1 << NoScriptRval)));
+        ScriptSource *ss;
+        if (scriptBits & (1 << OwnSource)) {
+            ss = cx->new_<ScriptSource>();
+            if (!ss)
+                return NULL;
+        } else {
+            JS_ASSERT(enclosingScript);
+            ss = enclosingScript->scriptSource();
+        }
         script = JSScript::Create(cx, enclosingScope, !!(scriptBits & (1 << SavedCallerFun)),
-                                  options, /* staticLevel = */ 0, NULL, 0, 0);
+                                  options, /* staticLevel = */ 0, ss, 0, 0);
+        if (scriptBits & (1 << OwnSource))
+            ss->attachToRuntime(cx->runtime);
         if (!script || !JSScript::partiallyInit(cx, script,
                                                 length, nsrcnotes, natoms, nobjects,
                                                 nregexps, ntrynotes, nconsts, nClosedArgs,
                                                 nClosedVars, nTypeSets))
             return JS_FALSE;
 
         script->bindings.transfer(&bindings);
         JS_ASSERT(!script->mainOffset);
@@ -629,30 +640,20 @@ js::XDRScript(XDRState<mode> *xdr, Handl
                 return false;
         }
     } else if (scriptBits & (1 << ParentFilename)) {
         JS_ASSERT(enclosingScript);
         if (mode == XDR_DECODE)
             script->filename = enclosingScript->filename;
     }
 
-    if (scriptBits & (1 << HaveSource)) {
-        ScriptSource *ss = script->scriptSource();
-        if (scriptBits & (1 << OwnSource)) {
-            if (!ScriptSource::performXDR<mode>(xdr, &ss))
-                return false;
-        } else {
-            JS_ASSERT(enclosingScript);
-            ss = enclosingScript->scriptSource();
-        }
-        if (mode == XDR_DECODE)
-            script->setScriptSource(cx, ss);
-    } else if (mode == XDR_DECODE) {
-        script->setScriptSource(cx, NULL);
-        JS_ASSERT_IF(enclosingScript, !enclosingScript->scriptSource());
+    if (scriptBits & (1 << HasSourceData)) {
+        JS_ASSERT(scriptBits & (1 << OwnSource));
+        if (!script->scriptSource()->performXDR<mode>(xdr))
+            return false;
     }
     if (!xdr->codeUint32(&script->sourceStart))
         return false;
     if (!xdr->codeUint32(&script->sourceEnd))
         return false;
 
     if (mode == XDR_DECODE) {
         script->lineno = lineno;
@@ -1122,52 +1123,48 @@ SourceCompressorThread::abort(SourceComp
     JS_ASSERT(userTok == tok);
     stop = true;
 }
 #endif /* JS_THREADSAFE */
 
 void
 JSScript::setScriptSource(JSContext *cx, ScriptSource *ss)
 {
+    JS_ASSERT(ss);
 #ifdef JSGC_INCREMENTAL
     // During IGC, we need to barrier writing to scriptSource_.
-    if (ss && cx->runtime->gcIncrementalState != NO_INCREMENTAL && cx->runtime->gcIsFull)
+    if (cx->runtime->gcIncrementalState != NO_INCREMENTAL && cx->runtime->gcIsFull)
         ss->mark();
 #endif
     scriptSource_ = ss;
 }
 
 bool
 JSScript::loadSource(JSContext *cx, bool *worked)
 {
-    JS_ASSERT(!scriptSource_);
+    JS_ASSERT(!scriptSource_->hasSourceData());
     *worked = false;
     if (!cx->runtime->sourceHook)
         return true;
     jschar *src = NULL;
     uint32_t length;
     if (!cx->runtime->sourceHook(cx, this, &src, &length))
         return false;
     if (!src)
         return true;
-    ScriptSource *ss = ScriptSource::createFromSource(cx, src, length, false, NULL, true);
-    if (!ss) {
-        cx->free_(src);
-        return false;
-    }
-    setScriptSource(cx, ss);
-    ss->attachToRuntime(cx->runtime);
+    ScriptSource *ss = scriptSource();
+    JS_ALWAYS_TRUE(ss->setSource(cx, src, length, false, NULL, true));
     *worked = true;
     return true;
 }
 
 JSFixedString *
 JSScript::sourceData(JSContext *cx)
 {
-    JS_ASSERT(scriptSource_);
+    JS_ASSERT(scriptSource_->hasSourceData());
     return scriptSource_->substring(cx, sourceStart, sourceEnd);
 }
 
 JSFixedString *
 SourceDataCache::lookup(ScriptSource *ss)
 {
     if (!map_)
         return NULL;
@@ -1233,61 +1230,54 @@ ScriptSource::substring(JSContext *cx, u
         chars = data.source;
     }
 #else
     chars = data.source;
 #endif
     return js_NewStringCopyN(cx, chars + start, stop - start);
 }
 
-ScriptSource *
-ScriptSource::createFromSource(JSContext *cx, const jschar *src, uint32_t length,
-                               bool argumentsNotIncluded, SourceCompressionToken *tok,
-                               bool ownSource)
+bool
+ScriptSource::setSource(JSContext *cx, const jschar *src, uint32_t length,
+                        bool argumentsNotIncluded, SourceCompressionToken *tok,
+                        bool ownSource)
 {
-    ScriptSource *ss = static_cast<ScriptSource *>(cx->runtime->malloc_(sizeof(*ss)));
-    if (!ss)
-        return NULL;
+    JS_ASSERT(!hasSourceData());
     if (!ownSource) {
         const size_t nbytes = length * sizeof(jschar);
-        ss->data.compressed = static_cast<unsigned char *>(cx->runtime->malloc_(nbytes));
-        if (!ss->data.compressed) {
-            cx->free_(ss);
-            return NULL;
-        }
+        data.compressed = static_cast<unsigned char *>(cx->malloc_(nbytes));
+        if (!data.compressed)
+            return false;
     }
-    ss->next = NULL;
-    ss->length_ = length;
-    ss->compressedLength_ = 0;
-    ss->marked = ss->onRuntime_ = false;
-    ss->argumentsNotIncluded_ = argumentsNotIncluded;
-#ifdef DEBUG
-    ss->ready_ = false;
-#endif
+    length_ = length;
+    argumentsNotIncluded_ = argumentsNotIncluded;
 
     JS_ASSERT_IF(ownSource, !tok);
 
 #ifdef JS_THREADSAFE
     if (tok && !ownSource) {
-        tok->ss = ss;
+#ifdef DEBUG
+        ready_ = false;  
+#endif
+        tok->ss = this;
         tok->chars = src;
         cx->runtime->sourceCompressorThread.compress(tok);
     } else
 #endif
     {
         if (ownSource)
-            ss->data.source = const_cast<jschar *>(src);
+            data.source = const_cast<jschar *>(src);
         else
-            PodCopy(ss->data.source, src, ss->length_);
+            PodCopy(data.source, src, length_);
 #ifdef DEBUG
-        ss->ready_ = true;
+        ready_ = true;
 #endif
     }
 
-    return ss;
+    return true;
 }
 
 void
 SourceCompressionToken::ensureReady()
 {
 #ifdef JS_THREADSAFE
     cx->runtime->sourceCompressorThread.waitOnCompression(this);
 #endif
@@ -1350,79 +1340,60 @@ ScriptSource::sweep(JSRuntime *rt)
             *prev = next;
             cur->destroy(rt);
         }
     }
 }
 
 template<XDRMode mode>
 bool
-ScriptSource::performXDR(XDRState<mode> *xdr, ScriptSource **ssp)
+ScriptSource::performXDR(XDRState<mode> *xdr)
 {
-    class Cleanup {
-        JSContext *cx;
-        ScriptSource *ss;
-      public:
-        explicit Cleanup(JSContext *cx)
-            : cx(cx), ss(NULL) {}
-        ~Cleanup()
-        {
-            if (ss) {
-                if (ss->data.compressed)
-                    cx->free_(ss->data.compressed);
-                cx->free_(ss);
-            }
-        }
-        void protect(ScriptSource *source) { ss = source; }
-        void release() { ss = NULL; }
-    } cleanup(xdr->cx());
-    ScriptSource *ss = *ssp;
-    if (mode == XDR_DECODE) {
-        *ssp = static_cast<ScriptSource *>(xdr->cx()->malloc_(sizeof(ScriptSource)));
-        ss = *ssp;
-        if (!ss)
-            return false;
-        ss->marked = ss->onRuntime_ = ss->argumentsNotIncluded_ = false;
-#ifdef DEBUG
-        ss->ready_ = false;
-#endif
-        ss->data.compressed = NULL;
-        cleanup.protect(ss);
-#ifdef JSGC_INCREMENTAL
-        // See comment in ScriptSource::createFromSource.
-        if (xdr->cx()->runtime->gcIncrementalState != NO_INCREMENTAL &&
-            xdr->cx()->runtime->gcIsFull)
-            ss->marked = true;
-#endif
-    }
-    if (!xdr->codeUint32(&ss->length_))
-        return false;
-    if (!xdr->codeUint32(&ss->compressedLength_))
+    uint8_t hasSource = hasSourceData();
+    if (!xdr->codeUint8(&hasSource))
         return false;
 
-    uint8_t argumentsNotIncluded = ss->argumentsNotIncluded_;
-    if (!xdr->codeUint8(&argumentsNotIncluded))
-        return false;
-    ss->argumentsNotIncluded_ = argumentsNotIncluded;
+    if (hasSource) {
+        // Only set members when we know decoding cannot fail. This prevents the
+        // script source from being partially initialized.
+        uint32_t length = length_;
+        if (!xdr->codeUint32(&length))
+            return false;
 
-    size_t byteLen = ss->compressed() ? ss->compressedLength_ : (ss->length_ * sizeof(jschar));
-    if (mode == XDR_DECODE) {
-        ss->data.compressed = static_cast<unsigned char *>(xdr->cx()->malloc_(byteLen));
-        if (!ss->data.compressed)
+        uint32_t compressedLength = compressedLength_;
+        if (!xdr->codeUint32(&compressedLength))
+            return false;
+
+        uint8_t argumentsNotIncluded = argumentsNotIncluded_;
+        if (!xdr->codeUint8(&argumentsNotIncluded))
             return false;
+
+        size_t byteLen = compressedLength ? compressedLength : (length * sizeof(jschar));
+        if (mode == XDR_DECODE) {
+            data.compressed = static_cast<unsigned char *>(xdr->cx()->malloc_(byteLen));
+            if (!data.compressed)
+                return false;
+        }
+        if (!xdr->codeBytes(data.compressed, byteLen)) {
+            if (mode == XDR_DECODE) {
+                xdr->cx()->free_(data.compressed);
+                data.compressed = NULL;
+            }
+            return false;
+        }
+        length_ = length;
+        compressedLength_ = compressedLength;
+        argumentsNotIncluded_ = argumentsNotIncluded;
     }
-    if (!xdr->codeBytes(ss->data.compressed, byteLen))
-        return false;
-    if (mode == XDR_DECODE) {
+
 #ifdef DEBUG
-        ss->ready_ = true;
+    if (mode == XDR_DECODE)
+        ready_ = true;
 #endif
-        ss->attachToRuntime(xdr->cx()->runtime);
-        cleanup.release();
-    }
+
     return true;
 }
 
 /*
  * Shared script filename management.
  */
 
 const char *
@@ -2632,17 +2603,17 @@ JSScript::markChildren(JSTracer *trc)
 
     if (enclosingScope_)
         MarkObject(trc, &enclosingScope_, "enclosing");
 
     if (IS_GC_MARKING_TRACER(trc)) {
         if (filename)
             MarkScriptFilename(trc->runtime, filename);
 
-        if (trc->runtime->gcIsFull && scriptSource_)
+        if (trc->runtime->gcIsFull)
             scriptSource_->mark();
     }
 
     bindings.trace(trc);
 
 #ifdef JS_METHODJIT
     for (int constructing = 0; constructing <= 1; constructing++) {
         for (int barriers = 0; barriers <= 1; barriers++) {
--- a/js/src/jsscript.h
+++ b/js/src/jsscript.h
@@ -992,42 +992,62 @@ struct ScriptSource
     bool marked:1;
     bool onRuntime_:1;
     bool argumentsNotIncluded_:1;
 #ifdef DEBUG
     bool ready_:1;
 #endif
 
   public:
-    static ScriptSource *createFromSource(JSContext *cx,
-                                          const jschar *src,
-                                          uint32_t length,
-                                          bool argumentsNotIncluded = false,
-                                          SourceCompressionToken *tok = NULL,
-                                          bool ownSource = false);
+    ScriptSource()
+      : next(NULL),
+        length_(0),
+        compressedLength_(0),
+        marked(false),
+        onRuntime_(false),
+        argumentsNotIncluded_(false)
+#ifdef DEBUG
+       ,ready_(true)
+#endif
+    {
+        data.source = NULL;
+    }
+    bool setSource(JSContext *cx,
+                   const jschar *src,
+                   uint32_t length,
+                   bool argumentsNotIncluded = false,
+                   SourceCompressionToken *tok = NULL,
+                   bool ownSource = false);
     void attachToRuntime(JSRuntime *rt);
     void mark() { marked = true; }
-    void destroy(JSRuntime *rt);
-    uint32_t length() const { return length_; }
     bool onRuntime() const { return onRuntime_; }
-    bool argumentsNotIncluded() const { return argumentsNotIncluded_; }
 #ifdef DEBUG
     bool ready() const { return ready_; }
 #endif
+    bool hasSourceData() const { return !!data.source; }
+    uint32_t length() const {
+        JS_ASSERT(hasSourceData());
+        return length_;
+    }
+    bool argumentsNotIncluded() const {
+        JS_ASSERT(hasSourceData());
+        return argumentsNotIncluded_;
+    }
     JSFixedString *substring(JSContext *cx, uint32_t start, uint32_t stop);
     size_t sizeOfIncludingThis(JSMallocSizeOfFun mallocSizeOf);
 
     // For the GC.
     static void sweep(JSRuntime *rt);
 
     // XDR handling
     template <XDRMode mode>
-    static bool performXDR(XDRState<mode> *xdr, ScriptSource **ss);
+    bool performXDR(XDRState<mode> *xdr);
 
   private:
+    void destroy(JSRuntime *rt);
     bool compressed() { return compressedLength_ != 0; }
 };
 
 #ifdef JS_THREADSAFE
 /*
  * Background thread to compress JS source code. This happens only while parsing
  * and bytecode generation is happening in the main thread. If needed, the
  * compiler waits for compression to complete before returning.
--- a/js/src/jstypedarray.cpp
+++ b/js/src/jstypedarray.cpp
@@ -2915,32 +2915,69 @@ JSFunctionSpec _typedArray::jsfuncs[] = 
       MOZ_ASSERT(byteoffset <= INT32_MAX);                                                   \
       Rooted<JSObject*> arrayBuffer(cx, arrayBuffer_);                                       \
       Rooted<JSObject*> proto(cx, NULL);                                                     \
       return TypedArrayTemplate<NativeType>::fromBuffer(cx, arrayBuffer, byteoffset, length, \
                                                         proto);                              \
   }                                                                                          \
   JS_FRIEND_API(JSBool) JS_Is ## Name ## Array(JSObject *obj, JSContext *cx)                 \
   {                                                                                          \
-      if (!(obj = UnwrapObjectChecked(cx, obj)))                                             \
+      MOZ_ASSERT(!cx->isExceptionPending());                                                 \
+      if (!(obj = UnwrapObjectChecked(cx, obj))) {                                           \
+          cx->clearPendingException();                                                       \
           return false;                                                                      \
+      }                                                                                      \
       Class *clasp = obj->getClass();                                                        \
       return (clasp == &TypedArray::classes[TypedArrayTemplate<NativeType>::ArrayTypeID()]); \
   }
 
 IMPL_TYPED_ARRAY_JSAPI_CONSTRUCTORS(Int8, int8_t)
 IMPL_TYPED_ARRAY_JSAPI_CONSTRUCTORS(Uint8, uint8_t)
 IMPL_TYPED_ARRAY_JSAPI_CONSTRUCTORS(Uint8Clamped, uint8_clamped)
 IMPL_TYPED_ARRAY_JSAPI_CONSTRUCTORS(Int16, int16_t)
 IMPL_TYPED_ARRAY_JSAPI_CONSTRUCTORS(Uint16, uint16_t)
 IMPL_TYPED_ARRAY_JSAPI_CONSTRUCTORS(Int32, int32_t)
 IMPL_TYPED_ARRAY_JSAPI_CONSTRUCTORS(Uint32, uint32_t)
 IMPL_TYPED_ARRAY_JSAPI_CONSTRUCTORS(Float32, float)
 IMPL_TYPED_ARRAY_JSAPI_CONSTRUCTORS(Float64, double)
 
+#define IMPL_TYPED_ARRAY_COMBINED_UNWRAPPERS(Name, ExternalType, InternalType)              \
+  JS_FRIEND_API(JSObject *) JS_GetObjectAs ## Name ## Array(JSContext *cx,                  \
+                                                            JSObject *obj,                  \
+                                                            uint32_t *length,               \
+                                                            ExternalType **data)            \
+  {                                                                                         \
+      if (obj->isWrapper()) {                                                               \
+          MOZ_ASSERT(!cx->isExceptionPending());                                            \
+          if (!(obj = UnwrapObjectChecked(cx, obj))) {                                      \
+              cx->clearPendingException();                                                  \
+              return NULL;                                                                  \
+          }                                                                                 \
+      }                                                                                     \
+                                                                                            \
+      Class *clasp = obj->getClass();                                                       \
+      if (clasp != &TypedArray::classes[TypedArrayTemplate<InternalType>::ArrayTypeID()])   \
+          return NULL;                                                                      \
+                                                                                            \
+      *length = obj->getSlot(TypedArray::FIELD_LENGTH).toInt32();                           \
+      *data = static_cast<ExternalType *>(TypedArray::viewData(obj));                       \
+                                                                                            \
+      return obj;                                                                           \
+  }
+
+IMPL_TYPED_ARRAY_COMBINED_UNWRAPPERS(Int8, int8_t, int8_t)
+IMPL_TYPED_ARRAY_COMBINED_UNWRAPPERS(Uint8, uint8_t, uint8_t)
+IMPL_TYPED_ARRAY_COMBINED_UNWRAPPERS(Uint8Clamped, uint8_t, uint8_clamped)
+IMPL_TYPED_ARRAY_COMBINED_UNWRAPPERS(Int16, int16_t, int16_t)
+IMPL_TYPED_ARRAY_COMBINED_UNWRAPPERS(Uint16, uint16_t, uint16_t)
+IMPL_TYPED_ARRAY_COMBINED_UNWRAPPERS(Int32, int32_t, int32_t)
+IMPL_TYPED_ARRAY_COMBINED_UNWRAPPERS(Uint32, uint32_t, uint32_t)
+IMPL_TYPED_ARRAY_COMBINED_UNWRAPPERS(Float32, float, float)
+IMPL_TYPED_ARRAY_COMBINED_UNWRAPPERS(Float64, double, double)
+
 #define IMPL_TYPED_ARRAY_PROTO_CLASS(_typedArray)                               \
 {                                                                              \
     #_typedArray "Prototype",                                                  \
     JSCLASS_HAS_RESERVED_SLOTS(TypedArray::FIELD_MAX) |                        \
     JSCLASS_HAS_PRIVATE |                                                      \
     JSCLASS_HAS_CACHED_PROTO(JSProto_##_typedArray),                           \
     JS_PropertyStub,         /* addProperty */                                 \
     JS_PropertyStub,         /* delProperty */                                 \
@@ -3553,8 +3590,47 @@ JS_GetArrayBufferViewByteLength(JSObject
 {
     if (!(obj = CheckedUnwrap(cx, obj)))
         return 0;
     JS_ASSERT(obj->isTypedArray() || obj->isDataView());
     return obj->isDataView()
            ? obj->asDataView().byteLength()
            : TypedArray::byteLengthValue(obj).toInt32();
 }
+
+JS_FRIEND_API(JSObject *)
+JS_GetObjectAsArrayBufferView(JSContext *cx, JSObject *obj,
+                              uint32_t *length, uint8_t **data)
+{
+    if (obj->isWrapper()) {
+        if (!(obj = UnwrapObjectChecked(cx, obj))) {
+            cx->clearPendingException();
+            return NULL;
+        }
+    }
+    if (!(obj->isTypedArray() || obj->isDataView()))
+        return NULL;
+
+    *length = obj->isDataView() ? obj->asDataView().byteLength()
+                                : TypedArray::byteLengthValue(obj).toInt32();
+
+    *data = static_cast<uint8_t *>(obj->isDataView() ? obj->asDataView().dataPointer()
+                                                     : TypedArray::viewData(obj));
+    return obj;
+}
+
+JS_FRIEND_API(JSObject *)
+JS_GetObjectAsArrayBuffer(JSContext *cx, JSObject *obj, uint32_t *length, uint8_t **data)
+{
+    if (obj->isWrapper()) {
+        if (!(obj = UnwrapObjectChecked(cx, obj))) {
+            cx->clearPendingException();
+            return NULL;
+        }
+    }
+    if (!obj->isArrayBuffer())
+        return NULL;
+
+    *length = obj->asArrayBuffer().byteLength();
+    *data = obj->asArrayBuffer().dataPointer();
+
+    return obj;
+}
--- a/js/src/methodjit/Compiler.cpp
+++ b/js/src/methodjit/Compiler.cpp
@@ -2640,16 +2640,25 @@ mjit::Compiler::generateMethod()
           BEGIN_CASE(JSOP_CALLNAME)
           {
             PropertyName *name = script->getName(GET_UINT32_INDEX(PC));
             jsop_name(name, knownPushedType(0));
             frame.extra(frame.peek(-1)).name = name;
           }
           END_CASE(JSOP_NAME)
 
+          BEGIN_CASE(JSOP_INTRINSICNAME)
+          BEGIN_CASE(JSOP_CALLINTRINSIC)
+          {
+            PropertyName *name = script->getName(GET_UINT32_INDEX(PC));
+            jsop_intrinsicname(name, knownPushedType(0));
+            frame.extra(frame.peek(-1)).name = name;
+          }
+          END_CASE(JSOP_INTRINSICNAME)
+
           BEGIN_CASE(JSOP_IMPLICITTHIS)
           {
             prepareStubCall(Uses(0));
             masm.move(ImmPtr(script->getName(GET_UINT32_INDEX(PC))), Registers::ArgReg1);
             INLINE_STUBCALL(stubs::ImplicitThis, REJOIN_FALLTHROUGH);
             frame.pushSynced(JSVAL_TYPE_UNKNOWN);
           }
           END_CASE(JSOP_IMPLICITTHIS)
@@ -5548,16 +5557,23 @@ mjit::Compiler::jsop_setprop(PropertyNam
     labels.setInlineValueStore(masm, pic.fastPathRejoin, inlineValueStore);
     labels.setInlineShapeJump(masm, pic.shapeGuard, afterInlineShapeJump);
 
     pics.append(pic);
     return true;
 }
 
 void
+mjit::Compiler::jsop_intrinsicname(PropertyName *name, JSValueType type)
+{
+    JSFunction *fun = cx->global().get()->getIntrinsicFunction(cx, name);
+    frame.push(ObjectValue(*fun));
+}
+
+void
 mjit::Compiler::jsop_name(PropertyName *name, JSValueType type)
 {
     PICGenInfo pic(ic::PICInfo::NAME, PC);
 
     RESERVE_IC_SPACE(masm);
 
     pic.shapeReg = frame.allocReg();
     pic.objReg = frame.allocReg();
--- a/js/src/methodjit/Compiler.h
+++ b/js/src/methodjit/Compiler.h
@@ -648,16 +648,17 @@ private:
     void jsop_setelem_slow();
     void jsop_getelem_slow();
     bool jsop_getprop(PropertyName *name, JSValueType type,
                       bool typeCheck = true, bool forPrototype = false);
     bool jsop_getprop_dispatch(PropertyName *name);
     bool jsop_setprop(PropertyName *name, bool popGuaranteed);
     void jsop_setprop_slow(PropertyName *name);
     bool jsop_instanceof();
+    void jsop_intrinsicname(PropertyName *name, JSValueType type);
     void jsop_name(PropertyName *name, JSValueType type);
     bool jsop_xname(PropertyName *name);
     void enterBlock(StaticBlockObject *block);
     void leaveBlock();
     void emitEval(uint32_t argc);
     bool jsop_tableswitch(jsbytecode *pc);
     Jump getNewObject(JSContext *cx, RegisterID result, JSObject *templateObject);
 
--- a/js/src/shell/js.cpp
+++ b/js/src/shell/js.cpp
@@ -708,25 +708,23 @@ Load(JSContext *cx, unsigned argc, jsval
         JSString *str = JS_ValueToString(cx, argv[i]);
         if (!str)
             return false;
         argv[i] = STRING_TO_JSVAL(str);
         JSAutoByteString filename(cx, str);
         if (!filename)
             return false;
         errno = 0;
-        uint32_t oldopts = JS_GetOptions(cx);
-        JS_SetOptions(cx, oldopts | JSOPTION_COMPILE_N_GO | JSOPTION_NO_SCRIPT_RVAL);
-        JSScript *script = JS_CompileUTF8File(cx, thisobj, filename.ptr());
-        JS_SetOptions(cx, oldopts);
-        if (!script)
+        CompileOptions opts(cx);
+        opts.setCompileAndGo(true).setNoScriptRval(true);
+        if ((compileOnly && !Compile(cx, thisobj, opts, filename.ptr())) ||
+            !Evaluate(cx, thisobj, opts, filename.ptr(), NULL))
+        {
             return false;
-
-        if (!compileOnly && !JS_ExecuteScript(cx, thisobj, script, NULL))
-            return false;
+        }
     }
 
     JS_SET_RVAL(cx, vp, JSVAL_VOID);
     return true;
 }
 
 class AutoNewContext
 {
--- a/js/src/vm/GlobalObject-inl.h
+++ b/js/src/vm/GlobalObject-inl.h
@@ -208,11 +208,18 @@ GlobalObject::createArrayFromBuffer<uint
 
 void
 GlobalObject::setProtoGetter(JSFunction *protoGetter)
 {
     JS_ASSERT(getSlotRef(PROTO_GETTER).isUndefined());
     setSlot(PROTO_GETTER, ObjectValue(*protoGetter));
 }
 
+void
+GlobalObject::setIntrinsicsHolder(JSObject *obj)
+{
+    JS_ASSERT(getSlotRef(INTRINSICS).isUndefined());
+    setSlot(INTRINSICS, ObjectValue(*obj));
+}
+
 } // namespace js
 
 #endif
--- a/js/src/vm/GlobalObject.cpp
+++ b/js/src/vm/GlobalObject.cpp
@@ -168,16 +168,20 @@ ProtoSetterImpl(JSContext *cx, CallArgs 
 
 static JSBool
 ProtoSetter(JSContext *cx, unsigned argc, Value *vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
     return CallNonGenericMethod(cx, TestProtoSetterThis, ProtoSetterImpl, args);
 }
 
+JSFunctionSpec intrinsic_functions[] = {
+    JS_FN("ThrowTypeError",      ThrowTypeError,     0,0),
+    JS_FS_END
+};
 JSObject *
 GlobalObject::initFunctionAndObjectClasses(JSContext *cx)
 {
     Rooted<GlobalObject*> self(cx, this);
 
     JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->atomsCompartment);
     JS_ASSERT(isNative());
 
@@ -229,20 +233,22 @@ GlobalObject::initFunctionAndObjectClass
         JS_ASSERT(proto == functionProto);
         functionProto->flags |= JSFUN_PROTOTYPE;
 
         const char *rawSource = "() {\n}";
         size_t sourceLen = strlen(rawSource);
         jschar *source = InflateString(cx, rawSource, &sourceLen);
         if (!source)
             return NULL;
-        ScriptSource *ss = ScriptSource::createFromSource(cx, source, sourceLen);
-        cx->free_(source);
-        if (!ss)
+        ScriptSource *ss = cx->new_<ScriptSource>();
+        if (!ss) {
+            cx->free_(source);
             return NULL;
+        }
+        JS_ALWAYS_TRUE(ss->setSource(cx, source, sourceLen, false, NULL, true));
 
         CompileOptions options(cx);
         options.setNoScriptRval(true)
                .setVersion(JSVERSION_DEFAULT);
         Rooted<JSScript*> script(cx, JSScript::Create(cx,
                                                       /* enclosingScope = */ NullPtr(),
                                                       /* savedCallerFun = */ false,
                                                       options,
@@ -364,24 +370,30 @@ GlobalObject::initFunctionAndObjectClass
     /* ES5 15.1.2.1. */
     RootedId id(cx, NameToId(cx->runtime->atomState.evalAtom));
     JSObject *evalobj = js_DefineFunction(cx, self, id, IndirectEval, 1, JSFUN_STUB_GSOPS);
     if (!evalobj)
         return NULL;
     self->setOriginalEval(evalobj);
 
     /* ES5 13.2.3: Construct the unique [[ThrowTypeError]] function object. */
-    RootedFunction throwTypeError(cx);
-    throwTypeError = js_NewFunction(cx, NULL, ThrowTypeError, 0, 0, self, NULL);
+    RootedFunction throwTypeError(cx, js_NewFunction(cx, NULL, ThrowTypeError, 0, 0, self, NULL));
     if (!throwTypeError)
         return NULL;
     if (!throwTypeError->preventExtensions(cx))
         return NULL;
     self->setThrowTypeError(throwTypeError);
 
+    RootedObject intrinsicsHolder(cx, JS_NewObject(cx, NULL, NULL, self));
+    if (!intrinsicsHolder)
+        return NULL;
+    self->setIntrinsicsHolder(intrinsicsHolder);
+    if (!JS_DefineFunctions(cx, intrinsicsHolder, intrinsic_functions))
+        return NULL;
+
     /*
      * The global object should have |Object.prototype| as its [[Prototype]].
      * Eventually we'd like to have standard classes be there from the start,
      * and thus we would know we were always setting what had previously been a
      * null [[Prototype]], but right now some code assumes it can set the
      * [[Prototype]] before standard classes have been initialized.  For now,
      * only set the [[Prototype]] if it hasn't already been set.
      */
@@ -477,16 +489,17 @@ GlobalObject::clear(JSContext *cx)
      * Clear all slots storing values in case throwing trying to execute a
      * script for this global must reinitialize standard classes.  See
      * bug 470150.
      */
     setSlot(BOOLEAN_VALUEOF, UndefinedValue());
     setSlot(EVAL, UndefinedValue());
     setSlot(CREATE_DATAVIEW_FOR_THIS, UndefinedValue());
     setSlot(THROWTYPEERROR, UndefinedValue());
+    setSlot(INTRINSICS, UndefinedValue());
     setSlot(PROTO_GETTER, UndefinedValue());
 
     /*
      * Mark global as cleared. If we try to execute any compile-and-go
      * scripts from here on, we will throw.
      */
     int32_t flags = getSlot(FLAGS).toInt32();
     flags |= FLAGS_CLEARED;
--- a/js/src/vm/GlobalObject.h
+++ b/js/src/vm/GlobalObject.h
@@ -95,19 +95,20 @@ class GlobalObject : public JSObject
     static const unsigned GENERATOR_PROTO         = ELEMENT_ITERATOR_PROTO + 1;
     static const unsigned MAP_ITERATOR_PROTO      = GENERATOR_PROTO + 1;
     static const unsigned SET_ITERATOR_PROTO      = MAP_ITERATOR_PROTO + 1;
     static const unsigned REGEXP_STATICS          = SET_ITERATOR_PROTO + 1;
     static const unsigned FUNCTION_NS             = REGEXP_STATICS + 1;
     static const unsigned RUNTIME_CODEGEN_ENABLED = FUNCTION_NS + 1;
     static const unsigned FLAGS                   = RUNTIME_CODEGEN_ENABLED + 1;
     static const unsigned DEBUGGERS               = FLAGS + 1;
+    static const unsigned INTRINSICS              = DEBUGGERS + 1;
 
     /* Total reserved-slot count for global objects. */
-    static const unsigned RESERVED_SLOTS = DEBUGGERS + 1;
+    static const unsigned RESERVED_SLOTS = INTRINSICS + 1;
 
     void staticAsserts() {
         /*
          * The slot count must be in the public API for JSCLASS_GLOBAL_FLAGS,
          * and we aren't going to expose GlobalObject, so just assert that the
          * two values are synchronized.
          */
         JS_STATIC_ASSERT(JSCLASS_GLOBAL_SLOT_COUNT == RESERVED_SLOTS);
@@ -130,16 +131,18 @@ class GlobalObject : public JSObject
     inline void setDetailsForKey(JSProtoKey key, JSObject *ctor, JSObject *proto);
     inline void setObjectClassDetails(JSFunction *ctor, JSObject *proto);
     inline void setFunctionClassDetails(JSFunction *ctor, JSObject *proto);
 
     inline void setThrowTypeError(JSFunction *fun);
     inline void setOriginalEval(JSObject *evalobj);
     inline void setProtoGetter(JSFunction *protoGetter);
 
+    inline void setIntrinsicsHolder(JSObject *obj);
+
     Value getConstructor(JSProtoKey key) const {
         JS_ASSERT(key <= JSProto_LIMIT);
         return getSlot(key);
     }
 
     Value getPrototype(JSProtoKey key) const {
         JS_ASSERT(key <= JSProto_LIMIT);
         return getSlot(JSProto_LIMIT + key);
@@ -355,16 +358,30 @@ class GlobalObject : public JSObject
         if (dataViewClassInitialized())
             return &getPrototype(JSProto_DataView).toObject();
         Rooted<GlobalObject*> self(cx, this);
         if (!js_InitTypedArrayClasses(cx, this))
             return NULL;
         return &self->getPrototype(JSProto_DataView).toObject();
     }
 
+    bool hasIntrinsicFunction(JSContext *cx, PropertyName *name) {
+        RootedObject holder(cx, &getSlotRef(INTRINSICS).toObject());
+        Value fun = NullValue();
+        return HasDataProperty(cx, holder, NameToId(name), &fun);
+    }
+
+    JSFunction *getIntrinsicFunction(JSContext *cx, PropertyName *name) {
+        RootedObject holder(cx, &getSlotRef(INTRINSICS).toObject());
+        Value fun = NullValue();
+        DebugOnly<bool> ok = HasDataProperty(cx, holder, NameToId(name), &fun);
+        JS_ASSERT(ok);
+        return fun.toObject().toFunction();
+    }
+
     inline RegExpStatics *getRegExpStatics() const;
 
     JSObject *getThrowTypeError() const {
         JS_ASSERT(functionObjectClassesInitialized());
         return &getSlot(THROWTYPEERROR).toObject();
     }
 
     Value booleanValueOf() const {
--- a/js/src/vm/Xdr.h
+++ b/js/src/vm/Xdr.h
@@ -20,17 +20,17 @@ namespace js {
  * Bytecode version number. Increment the subtrahend whenever JS bytecode
  * changes incompatibly.
  *
  * This version number is XDR'd near the front of xdr bytecode and
  * aborts deserialization if there is a mismatch between the current
  * and saved versions. If deserialization fails, the data should be
  * invalidated if possible.
  */
-static const uint32_t XDR_BYTECODE_VERSION = uint32_t(0xb973c0de - 124);
+static const uint32_t XDR_BYTECODE_VERSION = uint32_t(0xb973c0de - 126);
 
 class XDRBuffer {
   public:
     XDRBuffer(JSContext *cx)
       : context(cx), base(NULL), cursor(NULL), limit(NULL) { }
 
     JSContext *cx() const {
         return context;
--- a/mobile/android/base/GeckoApp.java
+++ b/mobile/android/base/GeckoApp.java
@@ -1377,18 +1377,18 @@ abstract public class GeckoApp
         view.setWillNotDraw(false);
         if (view instanceof SurfaceView) {
             ((SurfaceView) view).setZOrderOnTop(true);
         }
 
         mFullScreenPluginContainer = new FullScreenHolder(this);
 
         FrameLayout.LayoutParams layoutParams = new FrameLayout.LayoutParams(
-                            ViewGroup.LayoutParams.MATCH_PARENT,
-                            ViewGroup.LayoutParams.MATCH_PARENT,
+                            ViewGroup.LayoutParams.FILL_PARENT,
+                            ViewGroup.LayoutParams.FILL_PARENT,
                             Gravity.CENTER);
         mFullScreenPluginContainer.addView(view, layoutParams);
 
 
         FrameLayout decor = (FrameLayout)getWindow().getDecorView();
         decor.addView(mFullScreenPluginContainer, layoutParams);
 
         mFullScreenPluginView = view;
--- a/mobile/android/base/resources/layout/abouthome_last_tabs_row.xml
+++ b/mobile/android/base/resources/layout/abouthome_last_tabs_row.xml
@@ -16,16 +16,17 @@
                android:layout_centerVertical="true"
                android:layout_marginLeft="12dip"
                android:src="@drawable/favicon"/>
 
     <TextView android:id="@+id/last_tab_title"
               android:layout_width="wrap_content"
               android:layout_height="wrap_content"
               android:layout_toRightOf="@id/last_tab_favicon"
+              android:layout_marginTop="2dip"
               android:layout_marginLeft="12dip"
               android:layout_marginRight="12dip"
               android:textSize="15sp"
               android:singleLine="true"
               android:textColor="#222222"/>
 
     <TextView android:id="@+id/last_tab_url"
               android:layout_width="wrap_content"
--- a/mobile/android/base/resources/layout/font_size_preference.xml
+++ b/mobile/android/base/resources/layout/font_size_preference.xml
@@ -1,46 +1,46 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <!-- 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/.  -->
 
 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-              android:layout_width="match_parent"
-              android:layout_height="match_parent"
+              android:layout_width="fill_parent"
+              android:layout_height="fill_parent"
               android:orientation="vertical"> 
 
     <TextView android:id="@+id/preview"
-              android:layout_width="match_parent"
+              android:layout_width="fill_parent"
               android:layout_height="wrap_content"
               android:layout_weight="1"
               android:background="#ffffffff"
               android:paddingTop="2dp"
               android:paddingBottom="2dp"
               android:paddingLeft="3dp"
               android:paddingRight="3dp"
               android:text="@string/pref_font_size_preview_text"
               android:textColor="#ff000000"
               android:scrollbars="vertical"
               android:fadeScrollbars="true"/>
 
     <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-                  android:layout_width="match_parent"
+                  android:layout_width="fill_parent"
                   android:layout_height="wrap_content"
                   android:orientation="horizontal">
 
         <Button android:id="@+id/decrease_preview_font_button"
                 android:layout_width="0dp"
-                android:layout_height="match_parent"
+                android:layout_height="fill_parent"
                 android:layout_weight="1"
                 android:text="@string/pref_font_size_adjust_char"
                 android:textSize="8sp"/>
 
         <Button android:id="@+id/increase_preview_font_button"
                 android:layout_width="0dp"
-                android:layout_height="match_parent"
+                android:layout_height="fill_parent"
                 android:layout_weight="1"
                 android:text="@string/pref_font_size_adjust_char"
                 android:textSize="16sp"/>
 
     </LinearLayout>
 
 </LinearLayout>
--- a/mobile/android/base/resources/layout/sync_send_tab.xml
+++ b/mobile/android/base/resources/layout/sync_send_tab.xml
@@ -3,26 +3,26 @@
   style="@style/SyncLayout.Vertical" >
   <TextView
       style="@style/SyncTop"
       android:id="@+id/sendtab_top"
       android:text="@string/sync_title_send_tab" />
 
   <ListView
     android:id="@+id/device_list"
-    android:layout_width="match_parent"
+    android:layout_width="fill_parent"
     android:layout_height="wrap_content"
     android:layout_below="@id/sendtab_top"
     android:layout_above="@+id/sendtab_bottom" >
   </ListView>
 
   <LinearLayout
     android:id="@id/sendtab_bottom"
     style="@style/SyncBottom" >
     <Button
       style="@style/SyncButton"
       android:id="@+id/send_button"
       android:onClick="sendClickHandler"
       android:clickable="false"
       android:enabled="false"
       android:text="@string/sync_button_send" />
   </LinearLayout>
-</RelativeLayout>
\ No newline at end of file
+</RelativeLayout>
--- a/mobile/android/chrome/content/Readability.js
+++ b/mobile/android/chrome/content/Readability.js
@@ -106,44 +106,41 @@ Readability.prototype = {
   /**
    * Converts each <a> and <img> uri in the given element to an absolute URI.
    *
    * @param Element
    * @return void
    */
   _fixRelativeUris: function(articleContent) {
     let baseUri = this._uri;
-    let ioService = Cc["@mozilla.org/network/io-service;1"]
-        .getService(Components.interfaces.nsIIOService);
 
     // Fix links.
     let links = articleContent.getElementsByTagName('a');
     for (let i = links.length - 1; i >= 0; i--) {
-      links[i].href = this._newURIErrorWrapper(links[i].href, baseUri, ioService);
+      links[i].href = this._newURIErrorWrapper(links[i].href, baseUri);
     }
 
     // Fix images.
     let images = articleContent.getElementsByTagName('img');
     for (let i = images.length - 1; i >= 0; i--) {
-      images[i].src = this._newURIErrorWrapper(images[i].src, baseUri, ioService);
+      images[i].src = this._newURIErrorWrapper(images[i].src, baseUri);
     }
   },
 
   /**
    * Converts the given parameters into a new nsIURI object and returns the "spec" attribute of it.
    * Catches errors of the newURI method and returns an appropriate value.
    *
    * @param string
    * @param nsIURI
-   * @param nsIIOService
    * @return string
    */
-  _newURIErrorWrapper: function(aSpec, aBaseURI, ioService) {
+  _newURIErrorWrapper: function(aSpec, aBaseURI) {
     try {
-      return ioService.newURI(aSpec, null, aBaseURI).spec;
+      return Services.io.newURI(aSpec, null, aBaseURI).spec;
     } catch (err) {
       dump("_newURIErrorWrapper: " + err.message);
       return "";
     }
   },
 
   /**
    * Get the article title as an H1.
--- a/security/manager/boot/src/nsSecureBrowserUIImpl.cpp
+++ b/security/manager/boot/src/nsSecureBrowserUIImpl.cpp
@@ -127,16 +127,17 @@ nsSecureBrowserUIImpl::nsSecureBrowserUI
   , mNewToplevelIsEV(false)
   , mNewToplevelSecurityStateKnown(true)
   , mIsViewSource(false)
   , mSubRequestsHighSecurity(0)
   , mSubRequestsLowSecurity(0)
   , mSubRequestsBrokenSecurity(0)
   , mSubRequestsNoSecurity(0)
   , mRestoreSubrequests(false)
+  , mOnLocationChangeSeen(false)
 #ifdef DEBUG
   , mOnStateLocationChangeReentranceDetection(0)
 #endif
 {
   mTransferringRequests.ops = nullptr;
   ResetStateTracking();
   
 #if defined(PR_LOGGING)
@@ -1212,19 +1213,20 @@ nsSecureBrowserUIImpl::OnStateChange(nsI
       // Data has been transferred for the single toplevel
       // request. Evaluate the security state.
 
       // Do this only when the sink has changed.  We update and notify
       // the state from OnLacationChange, this is actually redundant.
       // But when the target sink changes between OnLocationChange and
       // OnStateChange, we have to fire the notification here (again).
 
-      if (sinkChanged)
+      if (sinkChanged || mOnLocationChangeSeen)
         return EvaluateAndUpdateSecurityState(aRequest, securityInfo, false);
     }
+    mOnLocationChangeSeen = false;
 
     if (mRestoreSubrequests && !inProgress)
     {
       // We get here when there were no OnLocationChange between 
       // OnStateChange(START) and OnStateChange(STOP).  Then the load has not
       // been rendered but has been retargeted in some other way then by external
       // app handler.  Restore mSubRequests* members to what the current security 
       // state info holds (it was reset to all zero in OnStateChange(START) 
@@ -1605,16 +1607,17 @@ nsSecureBrowserUIImpl::OnLocationChange(
 
   nsCOMPtr<nsIDOMWindow> windowForProgress;
   aWebProgress->GetDOMWindow(getter_AddRefs(windowForProgress));
 
   nsCOMPtr<nsISupports> securityInfo(ExtractSecurityInfo(aRequest));
 
   if (windowForProgress.get() == window.get()) {
     // For toplevel channels, update the security state right away.
+    mOnLocationChangeSeen = true;
     return EvaluateAndUpdateSecurityState(aRequest, securityInfo, true);
   }
 
   // For channels in subdocuments we only update our subrequest state members.
   UpdateSubrequestMembers(securityInfo);
 
   // Care for the following scenario:
 
--- a/security/manager/boot/src/nsSecureBrowserUIImpl.h
+++ b/security/manager/boot/src/nsSecureBrowserUIImpl.h
@@ -90,16 +90,17 @@ protected:
 
   nsXPIDLString mInfoTooltip;
   PRInt32 mDocumentRequestsInProgress;
   PRInt32 mSubRequestsHighSecurity;
   PRInt32 mSubRequestsLowSecurity;
   PRInt32 mSubRequestsBrokenSecurity;
   PRInt32 mSubRequestsNoSecurity;
   bool mRestoreSubrequests;
+  bool mOnLocationChangeSeen;
 #ifdef DEBUG
   /* related to mReentrantMonitor */
   PRInt32 mOnStateLocationChangeReentranceDetection;
 #endif
 
   static already_AddRefed<nsISupports> ExtractSecurityInfo(nsIRequest* aRequest);
   static nsresult MapInternalToExternalState(PRUint32* aState, lockIconState lock, bool ev);
   nsresult UpdateSecurityState(nsIRequest* aRequest, bool withNewLocation,
--- a/testing/mochitest/android.json
+++ b/testing/mochitest/android.json
@@ -136,17 +136,17 @@
  "dom/imptests/webapps/DOMCore/tests/approved/test_Range-cloneContents.html": "bug 775227", 
  "dom/imptests/webapps/DOMCore/tests/approved/test_Range-compareBoundaryPoints.html": "bug 775227",
  "dom/imptests/webapps/DOMCore/tests/approved/test_Range-deleteContents.html": "bug 775227",
  "dom/imptests/webapps/DOMCore/tests/approved/test_Range-extractContents.html": "bug 775227",
  "dom/imptests/webapps/DOMCore/tests/approved/test_Range-insertNode.html": "bug 775227",
  "dom/imptests/webapps/DOMCore/tests/approved/test_Range-mutations.html": "bug 775227",
  "dom/imptests/webapps/DOMCore/tests/approved/test_Range-set.html": "bug 775227",
  "dom/imptests/webapps/DOMCore/tests/approved/test_Range-surroundContents.html": "bug 775227",
-
+ "dom/imptests/webapps/WebStorage/tests/submissions/Infraware/test_event_session_key.html": "bug 775227",
  "dom/indexedDB/test/test_third_party.html": "TIMED_OUT",
  "dom/network/tests/test_network_basics.html": "",
  "dom/settings/tests/test_settings_events.html": "",
  "dom/settings/tests/test_settings_basics.html": "",
  "dom/contacts/tests/test_contacts_basics.html": "",
  "dom/contacts/tests/test_contacts_events.html": "",
  "dom/sms/tests/test_sms_basics.html": "",
  "dom/tests/mochitest/ajax/jquery/test_jQuery.html": "bug 775227",
--- a/uriloader/base/nsDocLoader.cpp
+++ b/uriloader/base/nsDocLoader.cpp
@@ -1382,16 +1382,17 @@ nsDocLoader::FireOnLocationChange(nsIWeb
     listener = do_QueryReferent(info->mWeakListener);
     if (!listener) {
       // the listener went away. gracefully pull it out of the list.
       mListenerInfoList.RemoveElementAt(count);
       delete info;
       continue;
     }
 
+    PR_LOG(gDocLoaderLog, PR_LOG_DEBUG, ("DocLoader [%p] calling %p->OnLocationChange", this, listener.get()));
     listener->OnLocationChange(aWebProgress, aRequest, aUri, aFlags);
   }
 
   mListenerInfoList.Compact();
 
   // Pass the notification up to the parent...
   if (mParent) {
     mParent->FireOnLocationChange(aWebProgress, aRequest, aUri, aFlags);
--- a/uriloader/prefetch/nsPrefetchService.cpp
+++ b/uriloader/prefetch/nsPrefetchService.cpp
@@ -215,22 +215,23 @@ nsPrefetchNode::CancelChannel(nsresult e
 
     return NS_OK;
 }
 
 //-----------------------------------------------------------------------------
 // nsPrefetchNode::nsISupports
 //-----------------------------------------------------------------------------
 
-NS_IMPL_ISUPPORTS5(nsPrefetchNode,
+NS_IMPL_ISUPPORTS6(nsPrefetchNode,
                    nsIDOMLoadStatus,
                    nsIRequestObserver,
                    nsIStreamListener,
                    nsIInterfaceRequestor,
-                   nsIChannelEventSink)
+                   nsIChannelEventSink,
+                   nsIRedirectResultListener)
 
 //-----------------------------------------------------------------------------
 // nsPrefetchNode::nsIStreamListener
 //-----------------------------------------------------------------------------
 
 NS_IMETHODIMP
 nsPrefetchNode::OnStartRequest(nsIRequest *aRequest,
                                nsISupports *aContext)
@@ -320,16 +321,22 @@ NS_IMETHODIMP
 nsPrefetchNode::GetInterface(const nsIID &aIID, void **aResult)
 {
     if (aIID.Equals(NS_GET_IID(nsIChannelEventSink))) {
         NS_ADDREF_THIS();
         *aResult = static_cast<nsIChannelEventSink *>(this);
         return NS_OK;
     }
 
+    if (aIID.Equals(NS_GET_IID(nsIRedirectResultListener))) {
+        NS_ADDREF_THIS();
+        *aResult = static_cast<nsIRedirectResultListener *>(this);
+        return NS_OK;
+    }
+
     return NS_ERROR_NO_INTERFACE;
 }
 
 //-----------------------------------------------------------------------------
 // nsPrefetchNode::nsIChannelEventSink
 //-----------------------------------------------------------------------------
 
 NS_IMETHODIMP
@@ -356,22 +363,38 @@ nsPrefetchNode::AsyncOnChannelRedirect(n
     // HTTP request headers are not automatically forwarded to the new channel.
     nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(aNewChannel);
     NS_ENSURE_STATE(httpChannel);
 
     httpChannel->SetRequestHeader(NS_LITERAL_CSTRING("X-Moz"),
                                   NS_LITERAL_CSTRING("prefetch"),
                                   false);
 
-    mChannel = aNewChannel;
+    // Assign to mChannel after we get notification about success of the
+    // redirect in OnRedirectResult.
+    mRedirectChannel = aNewChannel;
 
     callback->OnRedirectVerifyCallback(NS_OK);
     return NS_OK;
 }
 
+//-----------------------------------------------------------------------------
+// nsPrefetchNode::nsIRedirectResultListener
+//-----------------------------------------------------------------------------
+
+NS_IMETHODIMP
+nsPrefetchNode::OnRedirectResult(bool proceeding)
+{
+    if (proceeding && mRedirectChannel)
+        mChannel = mRedirectChannel;
+
+    mRedirectChannel = nsnull;
+
+    return NS_OK;
+}
 
 //-----------------------------------------------------------------------------
 // nsPrefetchService <public>
 //-----------------------------------------------------------------------------
 
 nsPrefetchService::nsPrefetchService()
     : mQueueHead(nullptr)
     , mQueueTail(nullptr)
--- a/uriloader/prefetch/nsPrefetchService.h
+++ b/uriloader/prefetch/nsPrefetchService.h
@@ -4,16 +4,17 @@
 
 #ifndef nsPrefetchService_h__
 #define nsPrefetchService_h__
 
 #include "nsCPrefetchService.h"
 #include "nsIObserver.h"
 #include "nsIInterfaceRequestor.h"
 #include "nsIChannelEventSink.h"
+#include "nsIRedirectResultListener.h"
 #include "nsIWebProgressListener.h"
 #include "nsIStreamListener.h"
 #include "nsIChannel.h"
 #include "nsIURI.h"
 #include "nsIDOMLoadStatus.h"
 #include "nsWeakReference.h"
 #include "nsCOMPtr.h"
 #include "nsAutoPtr.h"
@@ -80,24 +81,26 @@ private:
 //-----------------------------------------------------------------------------
 // nsPrefetchNode
 //-----------------------------------------------------------------------------
 
 class nsPrefetchNode MOZ_FINAL : public nsIDOMLoadStatus
                                , public nsIStreamListener
                                , public nsIInterfaceRequestor
                                , public nsIChannelEventSink
+                               , public nsIRedirectResultListener
 {
 public:
     NS_DECL_ISUPPORTS
     NS_DECL_NSIDOMLOADSTATUS
     NS_DECL_NSIREQUESTOBSERVER
     NS_DECL_NSISTREAMLISTENER
     NS_DECL_NSIINTERFACEREQUESTOR
     NS_DECL_NSICHANNELEVENTSINK
+    NS_DECL_NSIREDIRECTRESULTLISTENER
 
     nsPrefetchNode(nsPrefetchService *aPrefetchService,
                    nsIURI *aURI,
                    nsIURI *aReferrerURI,
                    nsIDOMNode *aSource);
 
     ~nsPrefetchNode() {}
 
@@ -107,13 +110,14 @@ public:
     nsPrefetchNode             *mNext;
     nsCOMPtr<nsIURI>            mURI;
     nsCOMPtr<nsIURI>            mReferrerURI;
     nsCOMPtr<nsIWeakReference>  mSource;
 
 private:
     nsRefPtr<nsPrefetchService> mService;
     nsCOMPtr<nsIChannel>        mChannel;
+    nsCOMPtr<nsIChannel>        mRedirectChannel;
     PRUint16                    mState;
     PRInt32                     mBytesRead;
 };
 
 #endif // !nsPrefetchService_h__
--- a/widget/android/AndroidBridge.cpp
+++ b/widget/android/AndroidBridge.cpp
@@ -54,36 +54,35 @@ static void JavaThreadDetachFunc(void *a
 class AndroidRefable {
     void incStrong(void* thing) { }
     void decStrong(void* thing) { }
 };
 
 // This isn't in AndroidBridge.h because including StrongPointer.h there is gross
 static android::sp<AndroidRefable> (*android_SurfaceTexture_getNativeWindow)(JNIEnv* env, jobject surfaceTexture) = nullptr;
 
-AndroidBridge *
+void
 AndroidBridge::ConstructBridge(JNIEnv *jEnv,
                                jclass jGeckoAppShellClass)
 {
     /* NSS hack -- bionic doesn't handle recursive unloads correctly,
      * because library finalizer functions are called with the dynamic
      * linker lock still held.  This results in a deadlock when trying
      * to call dlclose() while we're already inside dlclose().
      * Conveniently, NSS has an env var that can prevent it from unloading.
      */
     putenv("NSS_DISABLE_UNLOAD=1");
 
     PR_NewThreadPrivateIndex(&sJavaEnvThreadIndex, JavaThreadDetachFunc);
 
-    sBridge = new AndroidBridge();
-    if (!sBridge->Init(jEnv, jGeckoAppShellClass)) {
-        delete sBridge;
-        sBridge = 0;
+    AndroidBridge *bridge = new AndroidBridge();
+    if (!bridge->Init(jEnv, jGeckoAppShellClass)) {
+        delete bridge;
     }
-    return sBridge;
+    sBridge = bridge;
 }
 
 bool
 AndroidBridge::Init(JNIEnv *jEnv,
                     jclass jGeckoAppShellClass)
 {
     ALOG_BRIDGE("AndroidBridge::Init");
     jEnv->GetJavaVM(&mJavaVM);
--- a/widget/android/AndroidBridge.h
+++ b/widget/android/AndroidBridge.h
@@ -96,18 +96,17 @@ public:
         NOTIFY_IME_FOCUSCHANGE = 3
     };
 
     enum {
         LAYER_CLIENT_TYPE_NONE = 0,
         LAYER_CLIENT_TYPE_GL = 2            // AndroidGeckoGLLayerClient
     };
 
-    static AndroidBridge *ConstructBridge(JNIEnv *jEnv,
-                                          jclass jGeckoAppShellClass);
+    static void ConstructBridge(JNIEnv *jEnv, jclass jGeckoAppShellClass);
 
     static AndroidBridge *Bridge() {
         return sBridge;
     }
 
     static JavaVM *GetVM() {
         if (NS_LIKELY(sBridge))
             return sBridge->mJavaVM;
--- a/widget/gonk/nsAppShell.cpp
+++ b/widget/gonk/nsAppShell.cpp
@@ -44,16 +44,18 @@
 #include "nsWindow.h"
 #include "OrientationObserver.h"
 
 #include "android/log.h"
 #include "libui/EventHub.h"
 #include "libui/InputReader.h"
 #include "libui/InputDispatcher.h"
 
+#include "sampler.h"
+
 #define LOG(args...)                                            \
     __android_log_print(ANDROID_LOG_INFO, "Gonk" , ## args)
 #ifdef VERBOSE_LOG_ENABLED
 # define VERBOSE_LOG(args...)                           \
     __android_log_print(ANDROID_LOG_INFO, "Gonk" , ## args)
 #else
 # define VERBOSE_LOG(args...)                   \
     (void)0
@@ -566,21 +568,25 @@ nsAppShell::ScheduleNativeEventCallback(
 {
     mNativeCallbackRequest = true;
     NotifyEvent();
 }
 
 bool
 nsAppShell::ProcessNextNativeEvent(bool mayWait)
 {
+    SAMPLE_LABEL("nsAppShell", "ProcessNextNativeEvent");
     epoll_event events[16] = {{ 0 }};
 
     int event_count;
-    if ((event_count = epoll_wait(epollfd, events, 16,  mayWait ? -1 : 0)) <= 0)
-        return true;
+    {
+        SAMPLE_LABEL("nsAppShell", "ProcessNextNativeEvent::Wait");
+        if ((event_count = epoll_wait(epollfd, events, 16,  mayWait ? -1 : 0)) <= 0)
+            return true;
+    }
 
     for (int i = 0; i < event_count; i++)
         mHandlers[events[i].data.u32].run();
 
     if (mDispatcher.get())
         mDispatcher->dispatchOnce();
 
     // NativeEventCallback always schedules more if it needs it
--- a/widget/shared/nsShmImage.h
+++ b/widget/shared/nsShmImage.h
@@ -1,9 +1,9 @@
-/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+/* -*- Mode: C++; tab-width: 4; 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 __mozilla_widget_nsShmImage_h__
 #define __mozilla_widget_nsShmImage_h__
 
@@ -44,17 +44,17 @@ public:
     static already_AddRefed<nsShmImage>
         Create(const gfxIntSize& aSize, Visual* aVisual, unsigned int aDepth);
     static already_AddRefed<gfxASurface>
         EnsureShmImage(const gfxIntSize& aSize, Visual* aVisual, unsigned int aDepth,
                        nsRefPtr<nsShmImage>& aImage);
 
     ~nsShmImage() {
         if (mImage) {
-            XSync(DISPLAY(), False);
+            mozilla::FinishX(DISPLAY());
             if (mXAttached) {
                 XShmDetach(DISPLAY(), &mInfo);
             }
             XDestroyImage(mImage);
         }
     }
 
     already_AddRefed<gfxASurface> AsSurface();
--- a/xpcom/threads/nsProcess.h
+++ b/xpcom/threads/nsProcess.h
@@ -54,16 +54,17 @@ private:
                                   bool holdWeak);
   // The 'args' array is null-terminated.
   nsresult RunProcess(bool blocking, char **args, nsIObserver* observer,
                       bool holdWeak, bool argsUTF8);
 
   PRThread* mThread;
   mozilla::Mutex mLock;
   bool mShutdown;
+  bool mBlocking;
 
   nsCOMPtr<nsIFile> mExecutable;
   nsString mTargetPath;
   PRInt32 mPid;
   nsCOMPtr<nsIObserver> mObserver;
   nsWeakPtr mWeakObserver;
 
   // These members are modified by multiple threads, any accesses should be
--- a/xpcom/threads/nsProcessCommon.cpp
+++ b/xpcom/threads/nsProcessCommon.cpp
@@ -62,16 +62,17 @@ cpu_type_t pref_cpu_types[2] = {
 NS_IMPL_THREADSAFE_ISUPPORTS2(nsProcess, nsIProcess,
                                          nsIObserver)
 
 //Constructor
 nsProcess::nsProcess()
     : mThread(nullptr)
     , mLock("nsProcess.mLock")
     , mShutdown(false)
+    , mBlocking(false)
     , mPid(-1)
     , mObserver(nullptr)
     , mWeakObserver(nullptr)
     , mExitValue(-1)
 #if !defined(XP_MACOSX)
     , mProcess(nullptr)
 #endif
 {
@@ -217,19 +218,21 @@ static int assembleCmdLine(char *const *
     MultiByteToWideChar(codePage, 0, cmdLine, -1, *wideCmdLine, numChars); 
     PR_Free(cmdLine);
     return 0;
 }
 #endif
 
 void PR_CALLBACK nsProcess::Monitor(void *arg)
 {
-    PR_SetCurrentThreadName("RunProcess");
+    nsRefPtr<nsProcess> process = dont_AddRef(static_cast<nsProcess*>(arg));
 
-    nsRefPtr<nsProcess> process = dont_AddRef(static_cast<nsProcess*>(arg));
+    if (!process->mBlocking)
+        PR_SetCurrentThreadName("RunProcess");
+
 #if defined(PROCESSMODEL_WINAPI)
     DWORD dwRetVal;
     unsigned long exitCode = -1;
 
     dwRetVal = WaitForSingleObject(process->mProcess, INFINITE);
     if (dwRetVal != WAIT_FAILED) {
         if (GetExitCodeProcess(process->mProcess, &exitCode) == FALSE)
             exitCode = -1;
@@ -502,16 +505,17 @@ nsProcess::RunProcess(bool blocking, cha
     struct MYProcess {
         PRUint32 pid;
     };
     MYProcess* ptrProc = (MYProcess *) mProcess;
     mPid = ptrProc->pid;
 #endif
 
     NS_ADDREF_THIS();
+    mBlocking = blocking;
     if (blocking) {
         Monitor(this);
         if (mExitValue < 0)
             return NS_ERROR_FILE_EXECUTION_FAILED;
     }
     else {
         mThread = PR_CreateThread(PR_SYSTEM_THREAD, Monitor, this,
                                   PR_PRIORITY_NORMAL, PR_LOCAL_THREAD,