Merge inbound to m-c.
authorRyan VanderMeulen <ryanvm@gmail.com>
Fri, 10 Jan 2014 14:46:40 -0500
changeset 162970 e89afc241513ce0202c82f6848c699fa91fa0d2c
parent 162896 a4d843cc48a669995593c01c0bc2951d9e2e5016 (current diff)
parent 162969 8945b2a33ba9a619ee50dff6e10e5b6458022bd2 (diff)
child 162971 171857e7e3348e71ecef3fb22c6a8c0750261c2a
child 162972 eacc67be800176ea59e1a83ca15fada676400c53
child 162987 a2774d4a7b7d9c32c66e059ac5fba276110f7606
child 163008 18884bc505096ea53b63aed66afcea952e1bdc66
child 163089 be17ee97a197c7f0703cc3de981b3f6c2a976ef9
push id25975
push userryanvm@gmail.com
push dateFri, 10 Jan 2014 19:46:47 +0000
treeherdermozilla-central@e89afc241513 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone29.0a1
first release with
nightly linux32
e89afc241513 / 29.0a1 / 20140111030200 / files
nightly linux64
e89afc241513 / 29.0a1 / 20140111030200 / files
nightly mac
e89afc241513 / 29.0a1 / 20140111030200 / files
nightly win32
e89afc241513 / 29.0a1 / 20140111030200 / files
nightly win64
e89afc241513 / 29.0a1 / 20140111030200 / files
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
releases
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge inbound to m-c.
intl/uconv/util/ubase.h
toolkit/mozapps/extensions/XPIProvider.jsm
xpcom/reflect/xptcall/src/md/unix/xptcinvoke_asm_ppc_openbsd.s
xpcom/reflect/xptcall/src/md/unix/xptcstubs_asm_ppc_openbsd.s
--- a/browser/base/content/test/general/browser_save_link-perwindowpb.js
+++ b/browser/base/content/test/general/browser_save_link-perwindowpb.js
@@ -11,20 +11,23 @@ let NetUtil = tempScope.NetUtil;
 // Trigger a save of a link in public mode, then trigger an identical save
 // in private mode and ensure that the second request is differentiated from
 // the first by checking that cookies set by the first response are not sent
 // during the second request.
 function triggerSave(aWindow, aCallback) {
   var fileName;
   let testBrowser = aWindow.gBrowser.selectedBrowser;
   // This page sets a cookie if and only if a cookie does not exist yet
-  testBrowser.loadURI("http://mochi.test:8888/browser/browser/base/content/test/general/bug792517-2.html");
+  let testURI = "http://mochi.test:8888/browser/browser/base/content/test/general/bug792517-2.html";
+  testBrowser.loadURI(testURI);
   testBrowser.addEventListener("pageshow", function pageShown(event) {
-    if (event.target.location == "about:blank")
+    if (event.target.location != testURI) {
+      testBrowser.loadURI(testURI);
       return;
+    }
     testBrowser.removeEventListener("pageshow", pageShown, false);
 
     executeSoon(function () {
       aWindow.document.addEventListener("popupshown", function(e) contextMenuOpened(aWindow, e), false);
 
       var link = testBrowser.contentDocument.getElementById("fff");
       EventUtils.synthesizeMouseAtCenter(link,
                                          { type: "contextmenu", button: 2 },
--- a/build/automation.py.in
+++ b/build/automation.py.in
@@ -843,17 +843,17 @@ class Automation(object):
   def checkForCrashes(self, minidumpDir, symbolsPath):
     return mozcrash.check_for_crashes(minidumpDir, symbolsPath, test_name=self.lastTestSeen)
 
   def runApp(self, testURL, env, app, profileDir, extraArgs,
              runSSLTunnel = False, utilityPath = None,
              xrePath = None, certPath = None,
              debuggerInfo = None, symbolsPath = None,
              timeout = -1, maxTime = None, onLaunch = None,
-             webapprtChrome = False):
+             webapprtChrome = False, hide_subtests=None):
     """
     Run the app, log the duration it took to execute, return the status code.
     Kills the app if it runs for longer than |maxTime| seconds, or outputs nothing for |timeout| seconds.
     """
 
     if utilityPath == None:
       utilityPath = self.DIST_BIN
     if xrePath == None:
--- a/config/rules.mk
+++ b/config/rules.mk
@@ -119,19 +119,16 @@ SIMPLE_PROGRAMS += $(CPP_UNIT_TEST_BINS)
 INCLUDES += -I$(DIST)/include/testing
 LIBS += $(XPCOM_GLUE_LDOPTS) $(NSPR_LIBS)
 
 ifndef MOZ_PROFILE_GENERATE
 libs:: $(CPP_UNIT_TEST_BINS) $(call mkdir_deps,$(DIST)/cppunittests)
 	$(NSINSTALL) $(CPP_UNIT_TEST_BINS) $(DIST)/cppunittests
 endif
 
-check::
-	@$(PYTHON) $(topsrcdir)/testing/runcppunittests.py --xre-path=$(DIST)/bin --symbols-path=$(DIST)/crashreporter-symbols $(subst .cpp,$(BIN_SUFFIX),$(CPP_UNIT_TESTS))
-
 cppunittests-remote: DM_TRANS?=adb
 cppunittests-remote:
 	@if [ '${TEST_DEVICE}' != '' -o '$(DM_TRANS)' = 'adb' ]; then \
 		$(PYTHON) -u $(topsrcdir)/testing/remotecppunittests.py \
 			--xre-path=$(DEPTH)/dist/bin \
 			--localLib=$(DEPTH)/dist/$(MOZ_APP_NAME) \
 			--dm_trans=$(DM_TRANS) \
 			--deviceIP=${TEST_DEVICE} \
--- a/content/base/src/nsDocument.cpp
+++ b/content/base/src/nsDocument.cpp
@@ -8813,16 +8813,20 @@ nsDocument::SetScrollToRef(nsIURI *aDocu
     mScrollToRef = Substring(start, end);
   }
 }
 
 void
 nsDocument::ScrollToRef()
 {
   if (mScrolledToRefAlready) {
+    nsCOMPtr<nsIPresShell> shell = GetShell();
+    if (shell) {
+      shell->ScrollToAnchor();
+    }
     return;
   }
 
   if (mScrollToRef.IsEmpty()) {
     return;
   }
 
   char* tmpstr = ToNewCString(mScrollToRef);
--- a/content/base/src/nsXMLHttpRequest.cpp
+++ b/content/base/src/nsXMLHttpRequest.cpp
@@ -1894,17 +1894,21 @@ nsXMLHttpRequest::OnStartRequest(nsIRequ
   mErrorLoad = mErrorLoad || NS_FAILED(status);
 
   if (mUpload && !mUploadComplete && !mErrorLoad &&
       (mState & XML_HTTP_REQUEST_ASYNC)) {
     if (mProgressTimerIsActive) {
       mProgressTimerIsActive = false;
       mProgressNotifier->Cancel();
     }
-    MaybeDispatchProgressEvents(true);
+    if (mUploadTransferred < mUploadTotal) {
+      mUploadTransferred = mUploadTotal;
+      mProgressSinceLastProgressEvent = true;
+      MaybeDispatchProgressEvents(true);
+    }
     mUploadComplete = true;
     DispatchProgressEvent(mUpload, NS_LITERAL_STRING(LOAD_STR),
                           true, mUploadTotal, mUploadTotal);
   }
 
   mContext = ctxt;
   mState |= XML_HTTP_REQUEST_PARSEBODY;
   ChangeState(XML_HTTP_REQUEST_HEADERS_RECEIVED);
@@ -3405,19 +3409,16 @@ nsXMLHttpRequest::MaybeDispatchProgressE
 
   if (!aFinalProgress) {
     StartProgressEventTimer();
   }
 
   // We're uploading if our state is XML_HTTP_REQUEST_OPENED or
   // XML_HTTP_REQUEST_SENT
   if ((XML_HTTP_REQUEST_OPENED | XML_HTTP_REQUEST_SENT) & mState) {
-    if (aFinalProgress) {
-      mUploadTotal = mUploadTransferred;
-    }
     if (mUpload && !mUploadComplete) {
       DispatchProgressEvent(mUpload, NS_LITERAL_STRING(PROGRESS_STR),
                             mUploadLengthComputable, mUploadTransferred,
                             mUploadTotal);
     }
   } else {
     if (aFinalProgress) {
       mLoadTotal = mLoadTransferred;
--- a/content/base/test/test_bug435425.html
+++ b/content/base/test/test_bug435425.html
@@ -18,25 +18,33 @@ https://bugzilla.mozilla.org/show_bug.cg
 <script class="testbody" type="text/javascript">
 
 /** Test for Bug 435425 **/
 
 var xhr = null;
 var upload = null;
 var currentEvents = null;
 var expectedResponseText = null;
+var uploadTotal = 0;
 
 function logEvent(evt) {
   var i = 0;
   while ((currentEvents.length != i) &&
          currentEvents[i].optional &&
          ((currentEvents[i].type != evt.type) ||
           !(evt.target instanceof currentEvents[i].target))) {
     ++i;
   }
+  if (evt.target instanceof XMLHttpRequestUpload) {
+    if (evt.type == "loadstart") {
+      uploadTotal = evt.total
+    } else {
+      is(evt.total, uploadTotal, "event(" + evt.type +  ").total should not change during upload.");
+    }
+  }
   ok(i != currentEvents.length, "Extra or wrong event?");
   is(evt.type, currentEvents[i].type, "Wrong event!")
   ok(evt.target instanceof currentEvents[i].target,
      "Wrong event target [" + evt.target + "," + evt.type + "]!");
   // If we handled non-optional event, remove all optional events before the 
   // handled event and then the non-optional event from the list.
   if (!currentEvents[i].optional) {
     for (;i != -1; --i) {
--- a/content/canvas/src/CanvasRenderingContext2D.cpp
+++ b/content/canvas/src/CanvasRenderingContext2D.cpp
@@ -1785,33 +1785,16 @@ bool CanvasRenderingContext2D::DrawCusto
   }
 
   nsIFocusManager* fm = nsFocusManager::GetFocusManager();
   if (fm) {
     // check that the element i focused
     nsCOMPtr<nsIDOMElement> focusedElement;
     fm->GetFocusedElement(getter_AddRefs(focusedElement));
     if (SameCOMIdentity(aElement.AsDOMNode(), focusedElement)) {
-      // get the bounds of the current path
-      mgfx::Rect bounds;
-      bounds = mPath->GetBounds(mTarget->GetTransform());
-
-      // and set them as the accessible area
-      nsRect rect(canvas->ClientLeft() + bounds.x, canvas->ClientTop() + bounds.y,
-               bounds.width, bounds.height);
-      rect.x *= AppUnitsPerCSSPixel();
-      rect.y *= AppUnitsPerCSSPixel();
-      rect.width *= AppUnitsPerCSSPixel();
-      rect.height *= AppUnitsPerCSSPixel();
-
-      nsIFrame* frame = aElement.GetPrimaryFrame();
-      if(frame) {
-        frame->SetRect(rect);
-      }
-
       return true;
     }
   }
 
   return false;
 }
 
 void
--- a/content/canvas/src/WebGLContext.cpp
+++ b/content/canvas/src/WebGLContext.cpp
@@ -151,16 +151,21 @@ WebGLContext::WebGLContext()
     mStencilClearValue = 0;
     mStencilRefFront = 0;
     mStencilRefBack = 0;
     mStencilValueMaskFront = 0xffffffff;
     mStencilValueMaskBack  = 0xffffffff;
     mStencilWriteMaskFront = 0xffffffff;
     mStencilWriteMaskBack  = 0xffffffff;
 
+    mViewportX = 0;
+    mViewportY = 0;
+    mViewportWidth = 0;
+    mViewportHeight = 0;
+
     mScissorTestEnabled = 0;
     mDitherEnabled = 1;
     mRasterizerDiscardEnabled = 0; // OpenGL ES 3.0 spec p244
 
     // initialize some GL values: we're going to get them from the GL and use them as the sizes of arrays,
     // so in case glGetIntegerv leaves them uninitialized because of a GL bug, we would have very weird crashes.
     mGLMaxVertexAttribs = 0;
     mGLMaxTextureUnits = 0;
@@ -188,16 +193,17 @@ WebGLContext::WebGLContext()
     mContextRestorer = do_CreateInstance("@mozilla.org/timer;1");
     mContextStatus = ContextNotLost;
     mContextLostErrorSet = false;
     mLoseContextOnHeapMinimize = false;
     mCanLoseContextInForeground = true;
 
     mAlreadyGeneratedWarnings = 0;
     mAlreadyWarnedAboutFakeVertexAttrib0 = false;
+    mAlreadyWarnedAboutViewportLargerThanDest = false;
     mMaxWarnings = Preferences::GetInt("webgl.max-warnings-per-context", 32);
     if (mMaxWarnings < -1)
     {
         GenerateWarning("webgl.max-warnings-per-context size is too large (seems like a negative value wrapped)");
         mMaxWarnings = 0;
     }
 
     mLastUseIndex = 0;
@@ -568,16 +574,18 @@ WebGLContext::SetDimensions(int32_t widt
 #ifdef DEBUG
     if (gl->DebugMode()) {
         printf_stderr("--- WebGL context created: %p\n", gl.get());
     }
 #endif
 
     mWidth = width;
     mHeight = height;
+    mViewportWidth = width;
+    mViewportHeight = height;
     mResetLayer = true;
     mOptionsFrozen = true;
 
     mHasRobustness = gl->HasRobustness();
 
     // increment the generation number
     ++mGeneration;
 
--- a/content/canvas/src/WebGLContext.h
+++ b/content/canvas/src/WebGLContext.h
@@ -1131,16 +1131,22 @@ protected:
     GLuint mStencilValueMaskFront, mStencilValueMaskBack,
               mStencilWriteMaskFront, mStencilWriteMaskBack;
     realGLboolean mColorWriteMask[4];
     realGLboolean mDepthWriteMask;
     GLfloat mColorClearValue[4];
     GLint mStencilClearValue;
     GLfloat mDepthClearValue;
 
+    GLint mViewportX;
+    GLint mViewportY;
+    GLsizei mViewportWidth;
+    GLsizei mViewportHeight;
+    bool mAlreadyWarnedAboutViewportLargerThanDest;
+
     nsCOMPtr<nsITimer> mContextRestorer;
     bool mAllowRestore;
     bool mContextLossTimerRunning;
     bool mDrawSinceContextLossTimerSet;
     ContextStatus mContextStatus;
     bool mContextLostErrorSet;
 
     // Used for some hardware (particularly Tegra 2 and 4) that likes to
--- a/content/canvas/src/WebGLContextGL.cpp
+++ b/content/canvas/src/WebGLContextGL.cpp
@@ -48,17 +48,17 @@
 using namespace mozilla;
 using namespace mozilla::dom;
 using namespace mozilla::gl;
 using namespace mozilla::gfx;
 
 static bool BaseTypeAndSizeFromUniformType(GLenum uType, GLenum *baseType, GLint *unitSize);
 static GLenum InternalFormatForFormatAndType(GLenum format, GLenum type, bool isGLES2);
 
-inline const WebGLRectangleObject *WebGLContext::FramebufferRectangleObject() const {
+const WebGLRectangleObject *WebGLContext::FramebufferRectangleObject() const {
     return mBoundFramebuffer ? mBoundFramebuffer->RectangleObject()
                              : static_cast<const WebGLRectangleObject*>(this);
 }
 
 WebGLContext::FakeBlackTexture::FakeBlackTexture(GLContext *gl, GLenum target, GLenum format)
     : mGL(gl)
     , mGLName(0)
 {
@@ -3062,16 +3062,21 @@ WebGLContext::Viewport(GLint x, GLint y,
     if (IsContextLost())
         return;
 
     if (width < 0 || height < 0)
         return ErrorInvalidValue("viewport: negative size");
 
     MakeContextCurrent();
     gl->fViewport(x, y, width, height);
+
+    mViewportX = x;
+    mViewportY = y;
+    mViewportWidth = width;
+    mViewportHeight = height;
 }
 
 void
 WebGLContext::CompileShader(WebGLShader *shader)
 {
     if (IsContextLost())
         return;
 
--- a/content/canvas/src/WebGLContextValidate.cpp
+++ b/content/canvas/src/WebGLContextValidate.cpp
@@ -485,19 +485,21 @@ uint32_t WebGLContext::GetBitsPerTexel(G
         int multiplier = type == LOCAL_GL_FLOAT ? 32 : 8;
         switch (format) {
             case LOCAL_GL_ALPHA:
             case LOCAL_GL_LUMINANCE:
                 return 1 * multiplier;
             case LOCAL_GL_LUMINANCE_ALPHA:
                 return 2 * multiplier;
             case LOCAL_GL_RGB:
+            case LOCAL_GL_RGB32F:
             case LOCAL_GL_SRGB_EXT:
                 return 3 * multiplier;
             case LOCAL_GL_RGBA:
+            case LOCAL_GL_RGBA32F:
             case LOCAL_GL_SRGB_ALPHA_EXT:
                 return 4 * multiplier;
             case LOCAL_GL_COMPRESSED_RGB_PVRTC_2BPPV1:
             case LOCAL_GL_COMPRESSED_RGBA_PVRTC_2BPPV1:
                 return 2;
             case LOCAL_GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
             case LOCAL_GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
             case LOCAL_GL_ATC_RGB:
@@ -514,17 +516,17 @@ uint32_t WebGLContext::GetBitsPerTexel(G
         }
     } else if (type == LOCAL_GL_UNSIGNED_SHORT_4_4_4_4 ||
                type == LOCAL_GL_UNSIGNED_SHORT_5_5_5_1 ||
                type == LOCAL_GL_UNSIGNED_SHORT_5_6_5)
     {
         return 16;
     }
 
-    MOZ_ASSERT(false);
+    MOZ_ASSERT(false, "Unhandled format+type combo.");
     return 0;
 }
 
 bool WebGLContext::ValidateTexFormatAndType(GLenum format, GLenum type, int jsArrayType,
                                               uint32_t *texelSize, const char *info)
 {
     if (IsExtensionEnabled(WEBGL_depth_texture)) {
         if (format == LOCAL_GL_DEPTH_COMPONENT) {
--- a/content/canvas/src/WebGLContextVertices.cpp
+++ b/content/canvas/src/WebGLContextVertices.cpp
@@ -728,16 +728,30 @@ void WebGLContext::Draw_cleanup()
             mDrawCallsSinceLastFlush++;
 
             if (mDrawCallsSinceLastFlush >= MAX_DRAW_CALLS_SINCE_FLUSH) {
                 gl->fFlush();
                 mDrawCallsSinceLastFlush = 0;
             }
         }
     }
+
+    // Let's check the viewport
+    const WebGLRectangleObject* rect = FramebufferRectangleObject();
+    if (rect) {
+        if (mViewportWidth > rect->Width() ||
+            mViewportHeight > rect->Height())
+        {
+            if (!mAlreadyWarnedAboutViewportLargerThanDest) {
+                GenerateWarning("Drawing to a destination rect smaller than the viewport rect. "
+                                "(This warning will only be given once)");
+                mAlreadyWarnedAboutViewportLargerThanDest = true;
+            }
+        }
+    }
 }
 
 /*
  * Verify that state is consistent for drawing, and compute max number of elements (maxAllowedCount)
  * that will be legal to be read from bound VBOs.
  */
 
 bool
--- a/content/media/TextTrackCue.cpp
+++ b/content/media/TextTrackCue.cpp
@@ -31,16 +31,17 @@ NS_INTERFACE_MAP_END_INHERITING(nsDOMEve
 StaticRefPtr<nsIWebVTTParserWrapper> TextTrackCue::sParserWrapper;
 
 // Set cue setting defaults based on step 19 & seq.
 // in http://dev.w3.org/html5/webvtt/#parsing
 void
 TextTrackCue::SetDefaultCueSettings()
 {
   mPosition = 50;
+  mPositionAlign = AlignSetting::Middle;
   mSize = 100;
   mPauseOnExit = false;
   mSnapToLines = true;
   mLine = WEBVTT_AUTO;
   mAlign = AlignSetting::Middle;
   mLineAlign = AlignSetting::Start;
   mVertical = DirectionSetting::_empty;
 }
--- a/content/media/TextTrackCue.h
+++ b/content/media/TextTrackCue.h
@@ -215,16 +215,36 @@ public:
       return;
     }
 
     mReset = true;
     mPosition = aPosition;
     CueChanged();
   }
 
+  AlignSetting PositionAlign() const
+  {
+    return mPositionAlign;
+  }
+
+  void SetPositionAlign(AlignSetting aPositionAlign, ErrorResult& aRv)
+  {
+    if (mPositionAlign == aPositionAlign)
+      return;
+
+    if (aPositionAlign == AlignSetting::Left ||
+        aPositionAlign == AlignSetting::Right) {
+      return aRv.Throw(NS_ERROR_DOM_SYNTAX_ERR);
+    }
+
+    mReset = true;
+    mPositionAlign = aPositionAlign;
+    CueChanged();
+  }
+
   int32_t Size() const
   {
     return mSize;
   }
 
   void SetSize(int32_t aSize, ErrorResult& aRv)
   {
     if (mSize == aSize) {
@@ -339,16 +359,17 @@ private:
   nsString mText;
   double mStartTime;
   double mEndTime;
 
   nsRefPtr<TextTrack> mTrack;
   nsRefPtr<HTMLTrackElement> mTrackElement;
   nsString mId;
   int32_t mPosition;
+  AlignSetting mPositionAlign;
   int32_t mSize;
   bool mPauseOnExit;
   bool mSnapToLines;
   nsString mRegionId;
   DirectionSetting mVertical;
   int mLine;
   AlignSetting mAlign;
   AlignSetting mLineAlign;
--- a/content/media/test/mochitest.ini
+++ b/content/media/test/mochitest.ini
@@ -234,16 +234,17 @@ support-files =
 [test_source.html]
 [test_source_write.html]
 [test_source_null.html]
 [test_standalone.html]
 [test_volume.html]
 [test_video_to_canvas.html]
 [test_audiowrite.html]
 [test_mediarecorder_creation.html]
+[test_mediarecorder_creation_fail.html]
 [test_mediarecorder_avoid_recursion.html]
 [test_mediarecorder_record_timeslice.html]
 [test_mediarecorder_record_audiocontext.html]
 [test_mediarecorder_record_4ch_audiocontext.html]
 [test_mediarecorder_record_stopms.html]
 [test_mediarecorder_record_nosrc.html]
 [test_mozHasAudio.html]
 [test_source_media.html]
new file mode 100644
--- /dev/null
+++ b/content/media/test/test_mediarecorder_creation_fail.html
@@ -0,0 +1,74 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+  <title>Test MediaRecorder Record with media.ogg.enabled = false</title>
+  <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+  <script type="text/javascript" src="manifest.js"></script>
+</head>
+<body>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+
+function startTest() {
+  var element = document.createElement('audio');
+
+  element.src = 'detodos.opus';
+  element.stream = element.mozCaptureStream();
+  // the expect sequence should be
+  // 1. onerror
+  // 2. ondataavailable
+  // 3. onstop
+  var callbackStep = 0;
+  var mediaRecorder = new MediaRecorder(element.stream);
+
+  mediaRecorder.onerror = function (e) {
+    is(callbackStep, 0, 'should fired onstop callback');
+    is(e.name, 'GenericError', 'error name should be GenericError');
+    is(mediaRecorder.mimeType, '', 'mimetype should be empty');
+    is(mediaRecorder.state, 'recording', 'state is recording');
+    info('onerror callback fired');
+    SpecialPowers.setBoolPref('media.ogg.enabled', true);
+    callbackStep = 1;
+  };
+
+  mediaRecorder.onwarning = function () {
+    ok(false, 'Unexpected onwarning callback fired');
+  };
+
+  mediaRecorder.onstop = function () {
+    info('onstop callback fired');
+    is(mediaRecorder.state, 'inactive', 'state should be inactive');
+    is(callbackStep, 2, 'should fired onstop callback');
+    SimpleTest.finish();
+  };
+
+  // This handler fires every 250ms to generate a blob.
+  mediaRecorder.ondataavailable = function (evt) {
+    info('ondataavailable callback fired');
+    is(callbackStep, 1, 'should fired ondataavailable callback');
+    is(evt.data.size, 0, 'data size should be zero');
+    ok(evt instanceof BlobEvent,
+       'Events fired from ondataavailable should be BlobEvent');
+    is(evt.data.type, '', 'encoder start fail, blob miemType should be empty');
+    callbackStep = 2;
+  };
+
+  // Start recording once canplaythrough fires
+  element.oncanplaythrough = function() {
+    SpecialPowers.setBoolPref("media.ogg.enabled", false);
+    mediaRecorder.start(250);
+    is(mediaRecorder.state, 'recording', 'Media recorder should be recording');
+    is(mediaRecorder.stream, element.stream,
+       'Media recorder stream = element stream at the start of recording');
+  };
+
+  element.play();
+}
+
+startTest();
+SimpleTest.waitForExplicitFinish();
+</script>
+</pre>
+</body>
+</html>
--- a/content/media/test/test_texttrackcue.html
+++ b/content/media/test/test_texttrackcue.html
@@ -99,16 +99,42 @@ SpecialPowers.pushPrefEnv({"set": [["med
 
       cue.lineAlign = "middle";
       is(cue.lineAlign, "middle", "Cue's line align should be middle.");
       cue.lineAlign = "START";
       is(cue.lineAlign, "middle", "Cue's line align should be middle.");
       cue.lineAlign = "end";
       is(cue.lineAlign, "end", "Cue's line align should be end.");
 
+      // Check that cue position align works properly
+      is(cue.positionAlign, "middle", "Cue's default position alignment should be middle.");
+
+      var exceptionHappened = false;
+      try {
+        cue.positionAlign = "left";
+      } catch(e) {
+        exceptionHappened = true;
+        is(e.name, "SyntaxError", "Should have thrown SyntaxError.");
+      }
+      ok(exceptionHappened, "Exception should have happened.");
+
+      exceptionHappened = false;
+      try {
+        cue.positionAlign = "right";
+      } catch(e) {
+        exceptionHappened = true;
+        is(e.name, "SyntaxError", "Should have thrown SyntaxError.");
+      }
+      ok(exceptionHappened, "Exception should have happened.");
+
+      cue.positionAlign = "start";
+      is(cue.positionAlign, "start", "Cue's position align should be start.");
+      cue.positionAlign = "end";
+      is(cue.positionAlign, "end", "Cue's position align should be end.");
+
       // Check that we can create and add new VTTCues
       var vttCue = new VTTCue(3.999, 4, "foo");
       trackElement.track.addCue(vttCue);
       is(cueList.length, 7, "Cue list length should now be 7.");
 
       // Check that new VTTCue was added correctly
       cue = cueList[6];
       is(cue.startTime, 3.999, "Cue's start time should be 3.999.");
--- a/content/media/webaudio/OscillatorNode.cpp
+++ b/content/media/webaudio/OscillatorNode.cpp
@@ -18,17 +18,18 @@ NS_IMPL_CYCLE_COLLECTION_INHERITED_3(Osc
                                      mPeriodicWave, mFrequency, mDetune)
 
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(OscillatorNode)
 NS_INTERFACE_MAP_END_INHERITING(AudioNode)
 
 NS_IMPL_ADDREF_INHERITED(OscillatorNode, AudioNode)
 NS_IMPL_RELEASE_INHERITED(OscillatorNode, AudioNode)
 
-static const float sLeak = 0.995f;
+static const float sLeakTriangle = 0.995f;
+static const float sLeak = 0.999f;
 
 class DCBlocker
 {
 public:
   // These are sane defauts when the initial mPhase is zero
   DCBlocker(float aLastInput = 0.0f,
             float aLastOutput = 0.0f,
             float aPole = 0.995)
@@ -315,34 +316,34 @@ public:
   }
 
   void ComputeSquare(float * aOutput, TrackTicks ticks, uint32_t aStart, uint32_t aEnd)
   {
     for (uint32_t i = aStart; i < aEnd; ++i) {
       UpdateParametersIfNeeded(ticks, i);
       // Integration to get us a square. It turns out we can have a
       // pure integrator here.
-      mSquare += BipolarBLIT();
+      mSquare = mSquare * sLeak + BipolarBLIT();
       aOutput[i] = mSquare;
       // maybe we want to apply a gain, the wg has not decided yet
       aOutput[i] *= 1.5;
       IncrementPhase();
     }
   }
 
   void ComputeSawtooth(float * aOutput, TrackTicks ticks, uint32_t aStart, uint32_t aEnd)
   {
     float dcoffset;
     for (uint32_t i = aStart; i < aEnd; ++i) {
       UpdateParametersIfNeeded(ticks, i);
       // DC offset so the Saw does not ramp up to infinity when integrating.
       dcoffset = mFinalFrequency / mSource->SampleRate();
       // Integrate and offset so we get mAmplitudeAtZero sawtooth. We have a
       // very low frequency component somewhere here, but I'm not sure where.
-      mSaw += UnipolarBLIT() - dcoffset;
+      mSaw = mSaw * sLeak + (UnipolarBLIT() - dcoffset);
       // reverse the saw so we are spec compliant
       aOutput[i] = -mSaw * 1.5;
 
       IncrementPhase();
     }
   }
 
   void ComputeTriangle(float * aOutput, TrackTicks ticks, uint32_t aStart, uint32_t aEnd)
@@ -351,17 +352,17 @@ public:
       UpdateParametersIfNeeded(ticks, i);
       // Integrate to get a square
       mSquare += BipolarBLIT();
       // Leaky integrate to get a triangle. We get too much dc offset if we don't
       // leaky integrate here.
       // C6 = k0 / period
       // (period is samplingrate / frequency, k0 = (PI/2)/(2*PI)) = 0.25
       float C6 = 0.25 / (mSource->SampleRate() / mFinalFrequency);
-      mTriangle = mTriangle * sLeak + mSquare + C6;
+      mTriangle = mTriangle * sLeakTriangle + mSquare + C6;
       // DC Block, and scale back to [-1.0; 1.0]
       aOutput[i] = mDCBlocker.Process(mTriangle) / (mSignalPeriod/2) * 1.5;
 
       IncrementPhase();
     }
   }
 
   void ComputeCustom(float* aOutput,
--- a/dom/system/gonk/OpenFileFinder.cpp
+++ b/dom/system/gonk/OpenFileFinder.cpp
@@ -5,16 +5,29 @@
 #include "OpenFileFinder.h"
 
 #include "mozilla/FileUtils.h"
 #include "nsPrintfCString.h"
 
 #include <sys/stat.h>
 #include <errno.h>
 
+#define USE_DEBUG 0
+
+#undef LOG
+#define LOG(args...)  __android_log_print(ANDROID_LOG_INFO,  "OpenFileFinder", ## args)
+#define LOGW(args...) __android_log_print(ANDROID_LOG_WARN,  "OpenFileFinder", ## args)
+#define ERR(args...)  __android_log_print(ANDROID_LOG_ERROR, "OpenFileFinder", ## args)
+
+#if USE_DEBUG
+#define DBG(args...)  __android_log_print(ANDROID_LOG_DEBUG, "OpenFileFinder" , ## args)
+#else
+#define DBG(args...)
+#endif
+
 namespace mozilla {
 namespace system {
 
 OpenFileFinder::OpenFileFinder(const nsACString& aPath,
                                bool aCheckIsB2gOrDescendant /* = true */)
   : mPath(aPath),
     mProcDir(nullptr),
     mFdDir(nullptr),
--- a/dom/system/gonk/OpenFileFinder.h
+++ b/dom/system/gonk/OpenFileFinder.h
@@ -4,29 +4,16 @@
 
 #ifndef mozilla_system_openfilefinder_h__
 #define mozilla_system_openfilefinder_h__
 
 #include "nsString.h"
 
 #include <dirent.h>
 
-#define USE_DEBUG 0
-
-#undef LOG
-#define LOG(args...)  __android_log_print(ANDROID_LOG_INFO,  "OpenFileFinder", ## args)
-#define LOGW(args...) __android_log_print(ANDROID_LOG_WARN,  "OpenFileFinder", ## args)
-#define ERR(args...)  __android_log_print(ANDROID_LOG_ERROR, "OpenFileFinder", ## args)
-
-#if USE_DEBUG
-#define DBG(args...)  __android_log_print(ANDROID_LOG_DEBUG, "OpenFileFinder" , ## args)
-#else
-#define DBG(args...)
-#endif
-
 namespace mozilla {
 namespace system {
 
 class OpenFileFinder
 {
 public:
   enum State
   {
--- a/dom/webidl/VTTCue.webidl
+++ b/dom/webidl/VTTCue.webidl
@@ -37,16 +37,18 @@ interface VTTCue : EventTarget {
   attribute boolean snapToLines;
   // XXXhumph: https://www.w3.org/Bugs/Public/show_bug.cgi?id=20651
   // attribute (long or AutoKeyword) line;
   [SetterThrows]
   attribute AlignSetting lineAlign;
   [SetterThrows]
   attribute long position;
   [SetterThrows]
+  attribute AlignSetting positionAlign;
+  [SetterThrows]
   attribute long size;
   attribute AlignSetting align;
   attribute DOMString text;
   DocumentFragment getCueAsHTML();
 
   attribute EventHandler onenter;
 
   attribute EventHandler onexit;
--- a/gfx/gl/GLReadTexImageHelper.cpp
+++ b/gfx/gl/GLReadTexImageHelper.cpp
@@ -8,16 +8,18 @@
 #include "GLContext.h"
 #include "OGLShaderProgram.h"
 #include "gfxTypes.h"
 #include "gfxContext.h"
 #include "ScopedGLHelpers.h"
 #include "mozilla/gfx/2D.h"
 #include "gfx2DGlue.h"
 
+using namespace mozilla::gfx;
+
 namespace mozilla {
 namespace gl {
 
 GLReadTexImageHelper::GLReadTexImageHelper(GLContext* gl)
     : mGL(gl)
 {
     mPrograms[0] = 0;
     mPrograms[1] = 0;
@@ -199,24 +201,24 @@ GetActualReadFormats(GLContext* gl, GLen
         return false;
     } else {
         readFormat = destFormat;
         readType = destType;
         return true;
     }
 }
 
-static void SwapRAndBComponents(gfxImageSurface* surf)
+static void SwapRAndBComponents(DataSourceSurface* surf)
 {
-  uint8_t *row = surf->Data();
+  uint8_t *row = surf->GetData();
 
-  size_t rowBytes = surf->Width()*4;
+  size_t rowBytes = surf->GetSize().width*4;
   size_t rowHole = surf->Stride() - rowBytes;
 
-  size_t rows = surf->Height();
+  size_t rows = surf->GetSize().height;
 
   while (rows) {
 
     const uint8_t *rowEnd = row + rowBytes;
 
     while (row != rowEnd) {
       row[0] ^= row[2];
       row[2] ^= row[0];
@@ -277,29 +279,29 @@ ReadPixelsIntoImageSurface(GLContext* gl
 
     nsAutoPtr<gfxImageSurface> tempSurf;
     gfxImageSurface* readSurf = nullptr;
     int readPixelSize = 0;
     if (needsTempSurf) {
         if (gl->DebugMode()) {
             NS_WARNING("Needing intermediary surface for ReadPixels. This will be slow!");
         }
-        gfx::SurfaceFormat readFormatGFX;
+        SurfaceFormat readFormatGFX;
 
         switch (readFormat) {
             case LOCAL_GL_RGBA:
             case LOCAL_GL_BGRA: {
-                readFormatGFX = hasAlpha ? gfx::FORMAT_B8G8R8A8
-                                         : gfx::FORMAT_B8G8R8X8;
+                readFormatGFX = hasAlpha ? FORMAT_B8G8R8A8
+                                         : FORMAT_B8G8R8X8;
                 break;
             }
             case LOCAL_GL_RGB: {
                 MOZ_ASSERT(readPixelSize == 2);
                 MOZ_ASSERT(readType == LOCAL_GL_UNSIGNED_SHORT_5_6_5_REV);
-                readFormatGFX = gfx::FORMAT_R5G6B5;
+                readFormatGFX = FORMAT_R5G6B5;
                 break;
             }
             default: {
                 MOZ_CRASH("Bad read format.");
             }
         }
 
         switch (readType) {
@@ -353,17 +355,22 @@ ReadPixelsIntoImageSurface(GLContext* gl
         gl->fPixelStorei(LOCAL_GL_PACK_ALIGNMENT, currentPackAlignment);
 
     if (readSurf != dest) {
         MOZ_ASSERT(readFormat == LOCAL_GL_RGBA);
         MOZ_ASSERT(readType == LOCAL_GL_UNSIGNED_BYTE);
         // So we just copied in RGBA in big endian, or le: 0xAABBGGRR.
         // We want 0xAARRGGBB, so swap R and B:
         dest->Flush();
-        SwapRAndBComponents(readSurf);
+        RefPtr<DataSourceSurface> readDSurf =
+            Factory::CreateWrappingDataSourceSurface(readSurf->Data(),
+                                                     readSurf->Stride(),
+                                                     ToIntSize(readSurf->GetSize()),
+                                                     ImageFormatToSurfaceFormat(readSurf->Format()));
+        SwapRAndBComponents(readDSurf);
         dest->MarkDirty();
 
         gfxContext ctx(dest);
         ctx.SetOperator(gfxContext::OPERATOR_SOURCE);
         ctx.SetSource(readSurf);
         ctx.Paint();
     }
 
@@ -392,76 +399,80 @@ ReadPixelsIntoImageSurface(GLContext* gl
                 }
             }
             dest->MarkDirty();
         }
     }
 #endif
 }
 
-static already_AddRefed<gfxImageSurface> YInvertImageSurface(gfxImageSurface* aSurf)
+static TemporaryRef<DataSourceSurface> YInvertImageSurface(DataSourceSurface* aSurf)
 {
-  gfxIntSize size = aSurf->GetSize();
-  nsRefPtr<gfxImageSurface> temp = new gfxImageSurface(size, aSurf->Format());
-  nsRefPtr<gfxContext> ctx = new gfxContext(temp);
+  RefPtr<DataSourceSurface> temp =
+    Factory::CreateDataSourceSurfaceWithStride(aSurf->GetSize(),
+                                               aSurf->GetFormat(),
+                                               aSurf->Stride());
+  RefPtr<DrawTarget> dt =
+    Factory::CreateDrawTargetForData(BACKEND_CAIRO,
+                                     temp->GetData(),
+                                     temp->GetSize(),
+                                     temp->Stride(),
+                                     temp->GetFormat());
+  nsRefPtr<gfxContext> ctx = new gfxContext(dt);
   ctx->SetOperator(gfxContext::OPERATOR_SOURCE);
   ctx->Scale(1.0, -1.0);
-  ctx->Translate(-gfxPoint(0.0, size.height));
-  ctx->SetSource(aSurf);
+  ctx->Translate(-gfxPoint(0.0, aSurf->GetSize().height));
+
+  nsRefPtr<gfxImageSurface> thebesSurf =
+    new gfxImageSurface(aSurf->GetData(),
+                        ThebesIntSize(aSurf->GetSize()),
+                        aSurf->Stride(),
+                        SurfaceFormatToImageFormat(aSurf->GetFormat()));
+  ctx->SetSource(thebesSurf);
   ctx->Paint();
   return temp.forget();
 }
 
-already_AddRefed<gfxImageSurface>
-GetTexImage(GLContext* gl, GLuint aTexture, bool aYInvert, gfx::SurfaceFormat aFormat)
+TemporaryRef<DataSourceSurface>
+ReadBackSurface(GLContext* gl, GLuint aTexture, bool aYInvert, SurfaceFormat aFormat)
 {
     gl->MakeCurrent();
     gl->GuaranteeResolve();
     gl->fActiveTexture(LOCAL_GL_TEXTURE0);
     gl->fBindTexture(LOCAL_GL_TEXTURE_2D, aTexture);
 
-    gfxIntSize size;
+    IntSize size;
     gl->fGetTexLevelParameteriv(LOCAL_GL_TEXTURE_2D, 0, LOCAL_GL_TEXTURE_WIDTH, &size.width);
     gl->fGetTexLevelParameteriv(LOCAL_GL_TEXTURE_2D, 0, LOCAL_GL_TEXTURE_HEIGHT, &size.height);
 
-    nsRefPtr<gfxImageSurface> surf = new gfxImageSurface(size, gfxImageFormatARGB32);
-    if (!surf || surf->CairoStatus()) {
+    RefPtr<DataSourceSurface> surf =
+      Factory::CreateDataSourceSurfaceWithStride(size, FORMAT_B8G8R8A8,
+                                                 GetAlignedStride<4>(size.width * BytesPerPixel(FORMAT_B8G8R8A8)));
+
+    if (!surf) {
         return nullptr;
     }
 
     uint32_t currentPackAlignment = 0;
     gl->fGetIntegerv(LOCAL_GL_PACK_ALIGNMENT, (GLint*)&currentPackAlignment);
     if (currentPackAlignment != 4) {
         gl->fPixelStorei(LOCAL_GL_PACK_ALIGNMENT, 4);
     }
-    gl->fGetTexImage(LOCAL_GL_TEXTURE_2D, 0, LOCAL_GL_RGBA, LOCAL_GL_UNSIGNED_BYTE, surf->Data());
+    gl->fGetTexImage(LOCAL_GL_TEXTURE_2D, 0, LOCAL_GL_RGBA, LOCAL_GL_UNSIGNED_BYTE, surf->GetData());
     if (currentPackAlignment != 4) {
         gl->fPixelStorei(LOCAL_GL_PACK_ALIGNMENT, currentPackAlignment);
     }
 
-    if (aFormat == gfx::FORMAT_R8G8B8A8 || aFormat == gfx::FORMAT_R8G8B8X8) {
+    if (aFormat == FORMAT_R8G8B8A8 || aFormat == FORMAT_R8G8B8X8) {
       SwapRAndBComponents(surf);
     }
 
     if (aYInvert) {
       surf = YInvertImageSurface(surf);
     }
-    return surf.forget();
-}
-
-TemporaryRef<gfx::DataSourceSurface>
-ReadBackSurface(GLContext* gl, GLuint aTexture, bool aYInvert, gfx::SurfaceFormat aFormat)
-{
-    nsRefPtr<gfxImageSurface> image = GetTexImage(gl, aTexture, aYInvert, aFormat);
-    RefPtr<gfx::DataSourceSurface> surf =
-        gfx::Factory::CreateDataSourceSurface(gfx::ToIntSize(image->GetSize()), aFormat);
-
-    if (!image->CopyTo(surf)) {
-        return nullptr;
-    }
 
     return surf.forget();
 }
 
 void
 ReadScreenIntoImageSurface(GLContext* gl, gfxImageSurface* dest)
 {
     ScopedBindFramebuffer autoFB(gl, 0);
--- a/gfx/gl/GLReadTexImageHelper.h
+++ b/gfx/gl/GLReadTexImageHelper.h
@@ -22,19 +22,16 @@ namespace gfx {
 class DataSourceSurface;
 }
 
 namespace gl {
 
 void ReadPixelsIntoImageSurface(GLContext* aGL, gfxImageSurface* aSurface);
 void ReadScreenIntoImageSurface(GLContext* aGL, gfxImageSurface* aSurface);
 
-already_AddRefed<gfxImageSurface>
-GetTexImage(GLContext* gl, GLuint aTexture, bool aYInvert, gfx::SurfaceFormat aFormat);
-
 TemporaryRef<gfx::DataSourceSurface>
 ReadBackSurface(GLContext* gl, GLuint aTexture, bool aYInvert, gfx::SurfaceFormat aFormat);
 
 class GLReadTexImageHelper MOZ_FINAL
 {
     // The GLContext is the sole owner of the GLBlitHelper.
     GLContext* mGL;
 
--- a/gfx/gl/SharedSurfaceGralloc.cpp
+++ b/gfx/gl/SharedSurfaceGralloc.cpp
@@ -6,22 +6,24 @@
 #include "mozilla/Preferences.h"
 
 #include "SharedSurfaceGralloc.h"
 
 #include "GLContext.h"
 #include "SharedSurfaceGL.h"
 #include "SurfaceFactory.h"
 #include "GLLibraryEGL.h"
+#include "mozilla/layers/GrallocTextureClient.h"
 #include "mozilla/layers/ShadowLayers.h"
 
 #include "ui/GraphicBuffer.h"
 #include "../layers/ipc/ShadowLayers.h"
 #include "ScopedGLHelpers.h"
 
+#include "gfxPlatform.h"
 #include "gfx2DGlue.h"
 
 #define DEBUG_GRALLOC
 #ifdef DEBUG_GRALLOC
 #define DEBUG_PRINT(...) do { printf_stderr(__VA_ARGS__); } while (0)
 #else
 #define DEBUG_PRINT(...) do { } while (0)
 #endif
@@ -67,44 +69,45 @@ SharedSurface_Gralloc::Create(GLContext*
     GLLibraryEGL* egl = &sEGLLibrary;
     MOZ_ASSERT(egl);
 
     DEBUG_PRINT("SharedSurface_Gralloc::Create -------\n");
 
     if (!HasExtensions(egl, prodGL))
         return nullptr;
 
-    SurfaceDescriptor baseDesc;
-    SurfaceDescriptorGralloc desc;
+    gfxContentType type = hasAlpha ? GFX_CONTENT_COLOR_ALPHA
+                                   : GFX_CONTENT_COLOR;
+
+    gfxImageFormat format
+      = gfxPlatform::GetPlatform()->OptimalFormatForContent(type);
 
-    gfxContentType type = hasAlpha ? GFX_CONTENT_COLOR_ALPHA
-                                                : GFX_CONTENT_COLOR;
-    if (!allocator->AllocSurfaceDescriptorWithCaps(size, type, USING_GL_RENDERING_ONLY, &baseDesc))
-        return false;
+    GrallocTextureClientOGL* grallocTC =
+      new GrallocTextureClientOGL(
+          allocator,
+          gfx::ImageFormatToSurfaceFormat(format),
+          TEXTURE_FLAGS_DEFAULT);
 
-    if (baseDesc.type() != SurfaceDescriptor::TSurfaceDescriptorGralloc) {
-        allocator->DestroySharedSurface(&baseDesc);
-        return false;
+    if (!grallocTC->AllocateForGLRendering(size)) {
+      return nullptr;
     }
 
-    desc = baseDesc.get_SurfaceDescriptorGralloc();
-
-    sp<GraphicBuffer> buffer = GrallocBufferActor::GetFrom(desc);
+    sp<GraphicBuffer> buffer = grallocTC->GetGraphicBuffer();
 
     EGLDisplay display = egl->Display();
     EGLClientBuffer clientBuffer = buffer->getNativeBuffer();
     EGLint attrs[] = {
         LOCAL_EGL_NONE, LOCAL_EGL_NONE
     };
     EGLImage image = egl->fCreateImage(display,
                                        EGL_NO_CONTEXT,
                                        LOCAL_EGL_NATIVE_BUFFER_ANDROID,
                                        clientBuffer, attrs);
     if (!image) {
-        allocator->DestroySharedSurface(&baseDesc);
+        grallocTC->DropTextureData()->DeallocateSharedData(allocator);
         return nullptr;
     }
 
     prodGL->MakeCurrent();
     GLuint prodTex = 0;
     prodGL->fGenTextures(1, &prodTex);
     ScopedBindTexture autoTex(prodGL, prodTex);
 
@@ -112,17 +115,17 @@ SharedSurface_Gralloc::Create(GLContext*
     prodGL->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_MAG_FILTER, LOCAL_GL_LINEAR);
     prodGL->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_WRAP_S, LOCAL_GL_CLAMP_TO_EDGE);
     prodGL->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_WRAP_T, LOCAL_GL_CLAMP_TO_EDGE);
 
     prodGL->fEGLImageTargetTexture2D(LOCAL_GL_TEXTURE_2D, image);
 
     egl->fDestroyImage(display, image);
 
-    SharedSurface_Gralloc *surf = new SharedSurface_Gralloc(prodGL, size, hasAlpha, egl, allocator, desc, prodTex);
+    SharedSurface_Gralloc *surf = new SharedSurface_Gralloc(prodGL, size, hasAlpha, egl, allocator, grallocTC, prodTex);
 
     DEBUG_PRINT("SharedSurface_Gralloc::Create: success -- surface %p, GraphicBuffer %p.\n", surf, buffer.get());
 
     return surf;
 }
 
 
 bool
@@ -134,22 +137,16 @@ SharedSurface_Gralloc::HasExtensions(GLL
 
 SharedSurface_Gralloc::~SharedSurface_Gralloc()
 {
 
     DEBUG_PRINT("[SharedSurface_Gralloc %p] destroyed\n", this);
 
     mGL->MakeCurrent();
     mGL->fDeleteTextures(1, (GLuint*)&mProdTex);
-
-    SurfaceDescriptor desc(mDesc);
-
-    if (mAllocator) {
-        mAllocator->DestroySharedSurface(&desc);
-    }
 }
 
 void
 SharedSurface_Gralloc::Fence()
 {
     // We should be able to rely on genlock write locks/read locks.
     // But they're broken on some configs, and even a glFinish doesn't
     // work.  glReadPixels seems to, though.
--- a/gfx/gl/SharedSurfaceGralloc.h
+++ b/gfx/gl/SharedSurfaceGralloc.h
@@ -2,23 +2,23 @@
 /* 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 SHARED_SURFACE_GRALLOC_H_
 #define SHARED_SURFACE_GRALLOC_H_
 
 #include "SharedSurfaceGL.h"
+#include "mozilla/layers/ISurfaceAllocator.h"
 #include "mozilla/layers/LayersSurfaces.h"
-#include "mozilla/layers/ISurfaceAllocator.h"
+#include "mozilla/layers/TextureClient.h"
 
 namespace mozilla {
 namespace layers {
 class ISurfaceAllocator;
-class SurfaceDescriptorGralloc;
 }
 
 namespace gl {
 class GLContext;
 class GLLibraryEGL;
 
 class SharedSurface_Gralloc
     : public SharedSurface_GL
@@ -34,43 +34,34 @@ public:
         MOZ_ASSERT(surf->Type() == SharedSurfaceType::Gralloc);
 
         return (SharedSurface_Gralloc*)surf;
     }
 
 protected:
     GLLibraryEGL* const mEGL;
     RefPtr<layers::ISurfaceAllocator> mAllocator;
-    // We keep the SurfaceDescriptor around, because we'll end up
-    // using it often and it's handy to do so.  The actual
-    // GraphicBuffer is kept alive by the sp<GraphicBuffer> in
-    // GrallocBufferActor; the actor will stay alive until we
-    // explicitly destroy this descriptor (and thus deallocate the
-    // actor) it in the destructor of this class.  This is okay to do
-    // on the client, but is very bad to do on the server (because on
-    // the client, the actor has no chance of going away unless the
-    // whole app died).
-    layers::SurfaceDescriptorGralloc mDesc;
+    RefPtr<layers::TextureClient> mTextureClient;
     const GLuint mProdTex;
 
     SharedSurface_Gralloc(GLContext* prodGL,
                           const gfx::IntSize& size,
                           bool hasAlpha,
                           GLLibraryEGL* egl,
                           layers::ISurfaceAllocator* allocator,
-                          layers::SurfaceDescriptorGralloc& desc,
+                          layers::TextureClient* textureClient,
                           GLuint prodTex)
         : SharedSurface_GL(SharedSurfaceType::Gralloc,
                            AttachmentType::GLTexture,
                            prodGL,
                            size,
                            hasAlpha)
         , mEGL(egl)
         , mAllocator(allocator)
-        , mDesc(desc)
+        , mTextureClient(textureClient)
         , mProdTex(prodTex)
     {}
 
     static bool HasExtensions(GLLibraryEGL* egl, GLContext* gl);
 
 public:
     virtual ~SharedSurface_Gralloc();
 
@@ -79,18 +70,18 @@ public:
 
     virtual void LockProdImpl();
     virtual void UnlockProdImpl();
 
     virtual GLuint Texture() const {
         return mProdTex;
     }
 
-    layers::SurfaceDescriptorGralloc& GetDescriptor() {
-        return mDesc;
+    layers::TextureClient* GetTextureClient() {
+        return mTextureClient;
     }
 };
 
 class SurfaceFactory_Gralloc
     : public SurfaceFactory_GL
 {
 protected:
     RefPtr<layers::ISurfaceAllocator> mAllocator;
--- a/gfx/layers/Layers.cpp
+++ b/gfx/layers/Layers.cpp
@@ -1110,44 +1110,50 @@ void WriteSnapshotLinkToDumpFile(T* aObj
   }
   nsCString string(aObj->Name());
   string.Append("-");
   string.AppendInt((uint64_t)aObj);
   fprintf_stderr(aFile, "href=\"javascript:ViewImage('%s')\"", string.BeginReading());
 }
 
 template <typename T>
-void WriteSnapshotToDumpFile_internal(T* aObj, gfxASurface* aSurf)
+void WriteSnapshotToDumpFile_internal(T* aObj, DataSourceSurface* aSurf)
 {
+  nsRefPtr<gfxImageSurface> deprecatedSurf =
+    new gfxImageSurface(aSurf->GetData(),
+                        ThebesIntSize(aSurf->GetSize()),
+                        aSurf->Stride(),
+                        SurfaceFormatToImageFormat(aSurf->GetFormat()));
   nsCString string(aObj->Name());
   string.Append("-");
   string.AppendInt((uint64_t)aObj);
   if (gfxUtils::sDumpPaintFile) {
     fprintf_stderr(gfxUtils::sDumpPaintFile, "array[\"%s\"]=\"", string.BeginReading());
   }
-  aSurf->DumpAsDataURL(gfxUtils::sDumpPaintFile);
+  deprecatedSurf->DumpAsDataURL(gfxUtils::sDumpPaintFile);
   if (gfxUtils::sDumpPaintFile) {
     fprintf_stderr(gfxUtils::sDumpPaintFile, "\";");
   }
 }
 
-void WriteSnapshotToDumpFile(Layer* aLayer, gfxASurface* aSurf)
+void WriteSnapshotToDumpFile(Layer* aLayer, DataSourceSurface* aSurf)
 {
   WriteSnapshotToDumpFile_internal(aLayer, aSurf);
 }
 
-void WriteSnapshotToDumpFile(LayerManager* aManager, gfxASurface* aSurf)
+void WriteSnapshotToDumpFile(LayerManager* aManager, DataSourceSurface* aSurf)
 {
   WriteSnapshotToDumpFile_internal(aManager, aSurf);
 }
 
 void WriteSnapshotToDumpFile(Compositor* aCompositor, DrawTarget* aTarget)
 {
-  nsRefPtr<gfxASurface> surf = gfxPlatform::GetPlatform()->GetThebesSurfaceForDrawTarget(aTarget);
-  WriteSnapshotToDumpFile_internal(aCompositor, surf);
+  RefPtr<SourceSurface> surf = aTarget->Snapshot();
+  RefPtr<DataSourceSurface> dSurf = surf->GetDataSurface();
+  WriteSnapshotToDumpFile_internal(aCompositor, dSurf);
 }
 #endif
 
 void
 Layer::Dump(FILE* aFile, const char* aPrefix, bool aDumpHtml)
 {
   if (aDumpHtml) {
     fprintf_stderr(aFile, "<li><a id=\"%p\" ", this);
--- a/gfx/layers/Layers.h
+++ b/gfx/layers/Layers.h
@@ -2041,17 +2041,17 @@ protected:
   // 0 is a special value that means "no ID".
   uint64_t mId;
 };
 
 void SetAntialiasingFlags(Layer* aLayer, gfxContext* aTarget);
 void SetAntialiasingFlags(Layer* aLayer, gfx::DrawTarget* aTarget);
 
 #ifdef MOZ_DUMP_PAINTING
-void WriteSnapshotToDumpFile(Layer* aLayer, gfxASurface* aSurf);
-void WriteSnapshotToDumpFile(LayerManager* aManager, gfxASurface* aSurf);
+void WriteSnapshotToDumpFile(Layer* aLayer, gfx::DataSourceSurface* aSurf);
+void WriteSnapshotToDumpFile(LayerManager* aManager, gfx::DataSourceSurface* aSurf);
 void WriteSnapshotToDumpFile(Compositor* aCompositor, gfx::DrawTarget* aTarget);
 #endif
 
 }
 }
 
 #endif /* GFX_LAYERS_H */
--- a/gfx/layers/client/CanvasClient.cpp
+++ b/gfx/layers/client/CanvasClient.cpp
@@ -10,46 +10,42 @@
 #include "Layers.h"                     // for Layer, etc
 #include "SurfaceStream.h"              // for SurfaceStream
 #include "SurfaceTypes.h"               // for SurfaceStreamHandle
 #include "gfx2DGlue.h"                  // for ImageFormatToSurfaceFormat
 #include "gfxASurface.h"                // for gfxASurface, etc
 #include "gfxPlatform.h"                // for gfxPlatform
 #include "mozilla/gfx/BaseSize.h"       // for BaseSize
 #include "mozilla/layers/CompositableForwarder.h"
+#include "mozilla/layers/GrallocTextureClient.h"
 #include "mozilla/layers/LayersTypes.h"
 #include "mozilla/layers/TextureClient.h"  // for TextureClient, etc
+#include "mozilla/layers/TextureClientOGL.h"
 #include "nsAutoPtr.h"                  // for nsRefPtr
 #include "nsDebug.h"                    // for printf_stderr, NS_ASSERTION
 #include "nsXULAppAPI.h"                // for XRE_GetProcessType, etc
 #ifdef MOZ_WIDGET_GONK
 #include "SharedSurfaceGralloc.h"
 #endif
 
 using namespace mozilla::gfx;
 using namespace mozilla::gl;
 
 namespace mozilla {
-namespace gfx {
-class SharedSurface;
-}
-}
-
-namespace mozilla {
 namespace layers {
 
 /* static */ TemporaryRef<CanvasClient>
 CanvasClient::CreateCanvasClient(CanvasClientType aType,
                                  CompositableForwarder* aForwarder,
                                  TextureFlags aFlags)
 {
   if (aType == CanvasClientGLContext &&
       aForwarder->GetCompositorBackendType() == LAYERS_OPENGL) {
     aFlags |= TEXTURE_DEALLOCATE_CLIENT;
-    return new DeprecatedCanvasClientSurfaceStream(aForwarder, aFlags);
+    return new CanvasClientSurfaceStream(aForwarder, aFlags);
   }
   if (gfxPlatform::GetPlatform()->UseDeprecatedTextures()) {
     aFlags |= TEXTURE_DEALLOCATE_CLIENT;
     return new DeprecatedCanvasClient2D(aForwarder, aFlags);
   }
   return new CanvasClient2D(aForwarder, aFlags);
 }
 
@@ -101,16 +97,83 @@ CanvasClient2D::Update(gfx::IntSize aSiz
 
 TemporaryRef<BufferTextureClient>
 CanvasClient2D::CreateBufferTextureClient(gfx::SurfaceFormat aFormat, TextureFlags aFlags)
 {
   return CompositableClient::CreateBufferTextureClient(aFormat,
                                                        mTextureInfo.mTextureFlags | aFlags);
 }
 
+CanvasClientSurfaceStream::CanvasClientSurfaceStream(CompositableForwarder* aLayerForwarder,
+                                                     TextureFlags aFlags)
+  : CanvasClient(aLayerForwarder, aFlags)
+{
+}
+
+void
+CanvasClientSurfaceStream::Update(gfx::IntSize aSize, ClientCanvasLayer* aLayer)
+{
+  GLScreenBuffer* screen = aLayer->mGLContext->Screen();
+  SurfaceStream* stream = screen->Stream();
+
+  bool isCrossProcess = !(XRE_GetProcessType() == GeckoProcessType_Default);
+  bool bufferCreated = false;
+  if (isCrossProcess) {
+#ifdef MOZ_WIDGET_GONK
+    SharedSurface* surf = stream->SwapConsumer();
+    if (!surf) {
+      printf_stderr("surf is null post-SwapConsumer!\n");
+      return;
+    }
+
+    if (surf->Type() != SharedSurfaceType::Gralloc) {
+      printf_stderr("Unexpected non-Gralloc SharedSurface in IPC path!");
+      MOZ_ASSERT(false);
+      return;
+    }
+
+    SharedSurface_Gralloc* grallocSurf = SharedSurface_Gralloc::Cast(surf);
+
+    GrallocTextureClientOGL* grallocTextureClient =
+      static_cast<GrallocTextureClientOGL*>(grallocSurf->GetTextureClient());
+
+    // If IPDLActor is null means this TextureClient didn't AddTextureClient yet
+    if (!grallocTextureClient->GetIPDLActor()) {
+      grallocTextureClient->SetTextureFlags(mTextureInfo.mTextureFlags);
+      AddTextureClient(grallocTextureClient);
+    }
+
+    if (grallocTextureClient->GetIPDLActor()) {
+      GetForwarder()->UseTexture(this, grallocTextureClient);
+    }
+#else
+    printf_stderr("isCrossProcess, but not MOZ_WIDGET_GONK! Someone needs to write some code!");
+    MOZ_ASSERT(false);
+#endif
+  } else {
+    if (!mBuffer) {
+      StreamTextureClientOGL* textureClient =
+        new StreamTextureClientOGL(mTextureInfo.mTextureFlags);
+      textureClient->InitWith(stream);
+      mBuffer = textureClient;
+      bufferCreated = true;
+    }
+
+    if (bufferCreated && !AddTextureClient(mBuffer)) {
+      mBuffer = nullptr;
+    }
+
+    if (mBuffer) {
+      GetForwarder()->UseTexture(this, mBuffer);
+    }
+  }
+
+  aLayer->Painted();
+}
+
 void
 DeprecatedCanvasClient2D::Updated()
 {
   mForwarder->UpdateTexture(this, 1, mDeprecatedTextureClient->LockSurfaceDescriptor());
 }
 
 
 DeprecatedCanvasClient2D::DeprecatedCanvasClient2D(CompositableForwarder* aFwd,
@@ -201,17 +264,18 @@ DeprecatedCanvasClientSurfaceStream::Upd
 
 #ifdef MOZ_WIDGET_GONK
     if (surf->Type() != SharedSurfaceType::Gralloc) {
       printf_stderr("Unexpected non-Gralloc SharedSurface in IPC path!");
       return;
     }
 
     SharedSurface_Gralloc* grallocSurf = SharedSurface_Gralloc::Cast(surf);
-    mDeprecatedTextureClient->SetDescriptor(grallocSurf->GetDescriptor());
+    //XXX todo
+    //mDeprecatedTextureClient->SetDescriptor(grallocSurf->GetDescriptor());
 #else
     printf_stderr("isCrossProcess, but not MOZ_WIDGET_GONK! Someone needs to write some code!");
     MOZ_ASSERT(false);
 #endif
   } else {
     SurfaceStreamHandle handle = stream->GetShareHandle();
     mDeprecatedTextureClient->SetDescriptor(SurfaceStreamDescriptor(handle, false));
 
--- a/gfx/layers/client/CanvasClient.h
+++ b/gfx/layers/client/CanvasClient.h
@@ -14,16 +14,22 @@
 #include "mozilla/layers/LayersSurfaces.h"  // for SurfaceDescriptor
 #include "mozilla/layers/TextureClient.h"  // for TextureClient, etc
 #include "mozilla/mozalloc.h"           // for operator delete
 
 #include "mozilla/gfx/Point.h"          // for IntSize
 #include "mozilla/gfx/Types.h"          // for SurfaceFormat
 
 namespace mozilla {
+namespace gfx {
+class SharedSurface;
+}
+}
+
+namespace mozilla {
 namespace layers {
 
 class ClientCanvasLayer;
 class CompositableForwarder;
 
 /**
  * Compositable client for 2d and webgl canvas.
  */
@@ -90,16 +96,39 @@ public:
   {
     mBuffer = nullptr;
   }
 
 private:
   RefPtr<TextureClient> mBuffer;
 };
 
+// Used for GL canvases where we don't need to do any readback, i.e., with a
+// GL backend.
+class CanvasClientSurfaceStream : public CanvasClient
+{
+public:
+  CanvasClientSurfaceStream(CompositableForwarder* aLayerForwarder, TextureFlags aFlags);
+
+  TextureInfo GetTextureInfo() const
+  {
+    return TextureInfo(COMPOSITABLE_IMAGE);
+  }
+
+  virtual void Update(gfx::IntSize aSize, ClientCanvasLayer* aLayer) MOZ_OVERRIDE;
+
+  virtual void OnDetach() MOZ_OVERRIDE
+  {
+    mBuffer = nullptr;
+  }
+
+private:
+  RefPtr<TextureClient> mBuffer;
+};
+
 class DeprecatedCanvasClient2D : public CanvasClient
 {
 public:
   DeprecatedCanvasClient2D(CompositableForwarder* aLayerForwarder,
                            TextureFlags aFlags);
 
   TextureInfo GetTextureInfo() const MOZ_OVERRIDE
   {
--- a/gfx/layers/client/ClientCanvasLayer.h
+++ b/gfx/layers/client/ClientCanvasLayer.h
@@ -46,55 +46,56 @@ public:
   }
 
   virtual void SetVisibleRegion(const nsIntRegion& aRegion)
   {
     NS_ASSERTION(ClientManager()->InConstruction(),
                  "Can only set properties in construction phase");
     CanvasLayer::SetVisibleRegion(aRegion);
   }
-  
+
   virtual void Initialize(const Data& aData);
 
   virtual void RenderLayer();
-  
+
   virtual void FillSpecificAttributes(SpecificLayerAttributes& aAttrs)
   {
     aAttrs = CanvasLayerAttributes(mFilter, mBounds);
   }
 
   virtual Layer* AsLayer() { return this; }
   virtual ShadowableLayer* AsShadowableLayer() { return this; }
-  
+
   virtual void Disconnect()
   {
     mCanvasClient = nullptr;
     ClientLayer::Disconnect();
   }
 
   virtual CompositableClient* GetCompositableClient() MOZ_OVERRIDE
   {
     return mCanvasClient;
   }
 protected:
   ClientLayerManager* ClientManager()
   {
     return static_cast<ClientLayerManager*>(mManager);
   }
-  
+
   CanvasClientType GetCanvasClientType()
   {
     if (mGLContext) {
       return CanvasClient::CanvasClientGLContext;
     }
     return CanvasClient::CanvasClientSurface;
   }
 
   RefPtr<CanvasClient> mCanvasClient;
 
   friend class DeprecatedCanvasClient2D;
   friend class CanvasClient2D;
   friend class DeprecatedCanvasClientSurfaceStream;
+  friend class CanvasClientSurfaceStream;
 };
 }
 }
 
 #endif
--- a/gfx/layers/client/TextureClient.cpp
+++ b/gfx/layers/client/TextureClient.cpp
@@ -517,18 +517,18 @@ BufferTextureClient::AllocateForSurface(
   mSize = aSize;
   return true;
 }
 
 TemporaryRef<gfx::DrawTarget>
 BufferTextureClient::GetAsDrawTarget()
 {
   MOZ_ASSERT(IsValid());
-  // XXX - uncomment when ContentClient's locking is fixed
-  // MOZ_ASSERT(mLocked);
+  // XXX - Turn this into a fatal assertion as soon as Bug 952507 is fixed
+  NS_WARN_IF_FALSE(mLocked, "GetAsDrawTarget should be called on locked textures only");
 
   if (mDrawTarget) {
     return mDrawTarget;
   }
 
   ImageDataSerializer serializer(GetBuffer());
   if (!serializer.IsValid()) {
     return nullptr;
@@ -555,26 +555,28 @@ BufferTextureClient::GetAsDrawTarget()
     mDrawTarget->CopySurface(surface, rect, IntPoint(0,0));
   }
   return mDrawTarget;
 }
 
 bool
 BufferTextureClient::Lock(OpenMode aMode)
 {
-  MOZ_ASSERT(!mLocked);
+  // XXX - Turn this into a fatal assertion as soon as Bug 952507 is fixed
+  NS_WARN_IF_FALSE(!mLocked, "The TextureClient is already Locked!");
   mOpenMode = aMode;
   mLocked = true;
   return true;
 }
 
 void
 BufferTextureClient::Unlock()
 {
-  MOZ_ASSERT(mLocked);
+  // XXX - Turn this into a fatal assertion as soon as Bug 952507 is fixed
+  NS_WARN_IF_FALSE(mLocked, "The TextureClient is already Unlocked!");
   mLocked = false;
   if (!mDrawTarget) {
     mUsingFallbackDrawTarget = false;
     return;
   }
 
   mDrawTarget->Flush();
   if (mUsingFallbackDrawTarget && (mOpenMode & OPEN_WRITE)) {
--- a/gfx/layers/composite/CanvasLayerComposite.cpp
+++ b/gfx/layers/composite/CanvasLayerComposite.cpp
@@ -65,23 +65,17 @@ CanvasLayerComposite::RenderLayer(const 
   if (!mImageHost || !mImageHost->IsAttached()) {
     return;
   }
 
   mCompositor->MakeCurrent();
 
 #ifdef MOZ_DUMP_PAINTING
   if (gfxUtils::sDumpPainting) {
-    RefPtr<gfx::DataSourceSurface> dSurf = mImageHost->GetAsSurface();
-    gfxPlatform *platform = gfxPlatform::GetPlatform();
-    RefPtr<gfx::DrawTarget> dt = platform->CreateDrawTargetForData(dSurf->GetData(),
-                                                                   dSurf->GetSize(),
-                                                                   dSurf->Stride(),
-                                                                   dSurf->GetFormat());
-    nsRefPtr<gfxASurface> surf = platform->GetThebesSurfaceForDrawTarget(dt);
+    RefPtr<gfx::DataSourceSurface> surf = mImageHost->GetAsSurface();
     WriteSnapshotToDumpFile(this, surf);
   }
 #endif
 
   GraphicsFilter filter = mFilter;
 #ifdef ANDROID
   // Bug 691354
   // Using the LINEAR filter we get unexplained artifacts.
--- a/gfx/layers/composite/ContainerLayerComposite.cpp
+++ b/gfx/layers/composite/ContainerLayerComposite.cpp
@@ -328,17 +328,17 @@ ContainerRender(ContainerT* aContainer,
     // invariant: our GL context should be current here, I don't think we can
     // assert it though
   }
 
   if (needsSurface) {
     // Unbind the current surface and rebind the previous one.
 #ifdef MOZ_DUMP_PAINTING
     if (gfxUtils::sDumpPainting) {
-      nsRefPtr<gfxImageSurface> surf = surface->Dump(aManager->GetCompositor());
+      RefPtr<gfx::DataSourceSurface> surf = surface->Dump(aManager->GetCompositor());
       WriteSnapshotToDumpFile(aContainer, surf);
     }
 #endif
 
     compositor->SetRenderTarget(previousTarget);
     EffectChain effectChain;
     LayerManagerComposite::AutoAddMaskEffect autoMaskEffect(aContainer->GetMaskLayer(),
                                                             effectChain,
--- a/gfx/layers/composite/ImageLayerComposite.cpp
+++ b/gfx/layers/composite/ImageLayerComposite.cpp
@@ -79,23 +79,17 @@ void
 ImageLayerComposite::RenderLayer(const nsIntRect& aClipRect)
 {
   if (!mImageHost || !mImageHost->IsAttached()) {
     return;
   }
 
 #ifdef MOZ_DUMP_PAINTING
   if (gfxUtils::sDumpPainting) {
-    RefPtr<gfx::DataSourceSurface> dSurf = mImageHost->GetAsSurface();
-    gfxPlatform *platform = gfxPlatform::GetPlatform();
-    RefPtr<gfx::DrawTarget> dt = platform->CreateDrawTargetForData(dSurf->GetData(),
-                                                                   dSurf->GetSize(),
-                                                                   dSurf->Stride(),
-                                                                   dSurf->GetFormat());
-    nsRefPtr<gfxASurface> surf = platform->GetThebesSurfaceForDrawTarget(dt);
+    RefPtr<gfx::DataSourceSurface> surf = mImageHost->GetAsSurface();
     WriteSnapshotToDumpFile(this, surf);
   }
 #endif
 
   mCompositor->MakeCurrent();
 
   EffectChain effectChain;
   LayerManagerComposite::AutoAddMaskEffect autoMaskEffect(mMaskLayer, effectChain);
--- a/gfx/layers/composite/TextureHost.h
+++ b/gfx/layers/composite/TextureHost.h
@@ -838,17 +838,17 @@ class CompositingRenderTarget : public T
 {
 public:
   CompositingRenderTarget(const gfx::IntPoint& aOrigin)
     : mOrigin(aOrigin)
   {}
   virtual ~CompositingRenderTarget() {}
 
 #ifdef MOZ_DUMP_PAINTING
-  virtual already_AddRefed<gfxImageSurface> Dump(Compositor* aCompositor) { return nullptr; }
+  virtual TemporaryRef<gfx::DataSourceSurface> Dump(Compositor* aCompositor) { return nullptr; }
 #endif
 
   const gfx::IntPoint& GetOrigin() { return mOrigin; }
 
 private:
   gfx::IntPoint mOrigin;
 };
 
--- a/gfx/layers/composite/ThebesLayerComposite.cpp
+++ b/gfx/layers/composite/ThebesLayerComposite.cpp
@@ -106,24 +106,18 @@ ThebesLayerComposite::RenderLayer(const 
              "buffer is corrupted");
 
   gfx::Matrix4x4 transform;
   ToMatrix4x4(GetEffectiveTransform(), transform);
   gfx::Rect clipRect(aClipRect.x, aClipRect.y, aClipRect.width, aClipRect.height);
 
 #ifdef MOZ_DUMP_PAINTING
   if (gfxUtils::sDumpPainting) {
-    RefPtr<gfx::DataSourceSurface> dSurf = mBuffer->GetAsSurface();
-    if (dSurf) {
-      gfxPlatform *platform = gfxPlatform::GetPlatform();
-      RefPtr<gfx::DrawTarget> dt = platform->CreateDrawTargetForData(dSurf->GetData(),
-                                                                     dSurf->GetSize(),
-                                                                     dSurf->Stride(),
-                                                                     dSurf->GetFormat());
-      nsRefPtr<gfxASurface> surf = platform->GetThebesSurfaceForDrawTarget(dt);
+    RefPtr<gfx::DataSourceSurface> surf = mBuffer->GetAsSurface();
+    if (surf) {
       WriteSnapshotToDumpFile(this, surf);
     }
   }
 #endif
 
   EffectChain effectChain;
   LayerManagerComposite::AutoAddMaskEffect autoMaskEffect(mMaskLayer, effectChain);
 
--- a/gfx/layers/ipc/AsyncPanZoomController.cpp
+++ b/gfx/layers/ipc/AsyncPanZoomController.cpp
@@ -128,17 +128,17 @@ namespace mozilla {
 namespace layers {
 
 /**
  * Constant describing the tolerance in distance we use, multiplied by the
  * device DPI, before we start panning the screen. This is to prevent us from
  * accidentally processing taps as touch moves, and from very short/accidental
  * touches moving the screen.
  */
-static float gTouchStartTolerance = 1.0f/16.0f;
+static float gTouchStartTolerance = 1.0f/2.0f;
 
 /**
  * Angle from axis within which we stay axis-locked
  */
 static const double AXIS_LOCK_ANGLE = M_PI / 6.0; // 30 degrees
 
 /**
  * The distance in inches the user must pan before axis lock can be broken
--- a/gfx/layers/opengl/CompositingRenderTargetOGL.cpp
+++ b/gfx/layers/opengl/CompositingRenderTargetOGL.cpp
@@ -1,18 +1,21 @@
 /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "CompositingRenderTargetOGL.h"
 #include "GLContext.h"
 #include "GLReadTexImageHelper.h"
+#include "mozilla/gfx/2D.h"
 
 using namespace mozilla;
+using namespace mozilla::gfx;
+using namespace mozilla::gl;
 using namespace mozilla::layers;
 
 CompositingRenderTargetOGL::~CompositingRenderTargetOGL()
 {
   mGL->fDeleteTextures(1, &mTextureHandle);
   mGL->fDeleteFramebuffers(1, &mFBO);
 }
 
@@ -52,22 +55,22 @@ CompositingRenderTargetOGL::BindRenderTa
       }
     }
 
     mCompositor->PrepareViewport(mInitParams.mSize, mTransform);
   }
 }
 
 #ifdef MOZ_DUMP_PAINTING
-already_AddRefed<gfxImageSurface>
+TemporaryRef<DataSourceSurface>
 CompositingRenderTargetOGL::Dump(Compositor* aCompositor)
 {
   MOZ_ASSERT(mInitParams.mStatus == InitParams::INITIALIZED);
   CompositorOGL* compositorOGL = static_cast<CompositorOGL*>(aCompositor);
-  return GetTexImage(mGL, mTextureHandle, true, compositorOGL->GetFBOFormat());
+  return ReadBackSurface(mGL, mTextureHandle, true, compositorOGL->GetFBOFormat());
 }
 #endif
 
 void
 CompositingRenderTargetOGL::InitializeImpl()
 {
   MOZ_ASSERT(mInitParams.mStatus == InitParams::READY);
 
--- a/gfx/layers/opengl/CompositingRenderTargetOGL.h
+++ b/gfx/layers/opengl/CompositingRenderTargetOGL.h
@@ -24,16 +24,19 @@
 #include "nsString.h"                   // for nsAutoCString
 
 class gfxImageSurface;
 
 namespace mozilla {
 namespace gl {
   class BindableTexture;
 }
+namespace gfx {
+  class DataSourceSurface;
+}
 
 namespace layers {
 
 class TextureSource;
 
 class CompositingRenderTargetOGL : public CompositingRenderTarget
 {
   typedef mozilla::gl::GLContext GLContext;
@@ -147,17 +150,17 @@ public:
     return gfx::FORMAT_UNKNOWN;
   }
 
   const gfxMatrix& GetTransform() {
     return mTransform;
   }
 
 #ifdef MOZ_DUMP_PAINTING
-  virtual already_AddRefed<gfxImageSurface> Dump(Compositor* aCompositor);
+  virtual TemporaryRef<gfx::DataSourceSurface> Dump(Compositor* aCompositor);
 #endif
 
 private:
   /**
    * Actually do the initialisation. Note that we leave our FBO bound, and so
    * calling this method is only suitable when about to use this render target.
    */
   void InitializeImpl();
--- a/gfx/layers/opengl/GrallocTextureClient.cpp
+++ b/gfx/layers/opengl/GrallocTextureClient.cpp
@@ -88,49 +88,63 @@ GrallocTextureClientOGL::DropTextureData
     return result;
   }
 }
 
 GrallocTextureClientOGL::GrallocTextureClientOGL(GrallocBufferActor* aActor,
                                                  gfx::IntSize aSize,
                                                  TextureFlags aFlags)
 : BufferTextureClient(nullptr, gfx::FORMAT_UNKNOWN, aFlags)
+, mAllocator(nullptr)
 , mGrallocFlags(android::GraphicBuffer::USAGE_SW_READ_OFTEN)
 , mMappedBuffer(nullptr)
 {
   InitWith(aActor, aSize);
   MOZ_COUNT_CTOR(GrallocTextureClientOGL);
 }
 
 GrallocTextureClientOGL::GrallocTextureClientOGL(CompositableClient* aCompositable,
                                                  gfx::SurfaceFormat aFormat,
                                                  TextureFlags aFlags)
 : BufferTextureClient(aCompositable, aFormat, aFlags)
+, mAllocator(nullptr)
+, mGrallocFlags(android::GraphicBuffer::USAGE_SW_READ_OFTEN)
+, mMappedBuffer(nullptr)
+{
+  MOZ_COUNT_CTOR(GrallocTextureClientOGL);
+}
+
+GrallocTextureClientOGL::GrallocTextureClientOGL(ISurfaceAllocator* aAllocator,
+                                                 gfx::SurfaceFormat aFormat,
+                                                 TextureFlags aFlags)
+: BufferTextureClient(nullptr, aFormat, aFlags)
+, mAllocator(aAllocator)
 , mGrallocFlags(android::GraphicBuffer::USAGE_SW_READ_OFTEN)
 , mMappedBuffer(nullptr)
 {
   MOZ_COUNT_CTOR(GrallocTextureClientOGL);
 }
 
 GrallocTextureClientOGL::~GrallocTextureClientOGL()
 {
   MOZ_COUNT_DTOR(GrallocTextureClientOGL);
     if (ShouldDeallocateInDestructor()) {
     // If the buffer has never been shared we must deallocate it or it would
     // leak.
     if (mBufferLocked) {
       mBufferLocked->Unlock();
     } else {
-      MOZ_ASSERT(mCompositable);
       // We just need to wrap the actor in a SurfaceDescriptor because that's what
       // ISurfaceAllocator uses as input, we don't care about the other parameters.
       SurfaceDescriptor sd = SurfaceDescriptorGralloc(nullptr, mGrallocActor,
                                                       IntSize(0, 0),
                                                       false, false);
-      mCompositable->GetForwarder()->DestroySharedSurface(&sd);
+
+      ISurfaceAllocator* allocator = GetAllocator();
+      allocator->DestroySharedSurface(&sd);
     }
   }
 }
 
 void
 GrallocTextureClientOGL::InitWith(GrallocBufferActor* aActor, gfx::IntSize aSize)
 {
   MOZ_ASSERT(aActor);
@@ -190,18 +204,16 @@ GrallocTextureClientOGL::GetBuffer() con
   return mMappedBuffer;
 }
 
 bool
 GrallocTextureClientOGL::AllocateForSurface(gfx::IntSize aSize,
                                             TextureAllocationFlags)
 {
   MOZ_ASSERT(IsValid());
-  MOZ_ASSERT(mCompositable);
-  ISurfaceAllocator* allocator = mCompositable->GetForwarder();
 
   uint32_t format;
   uint32_t usage = android::GraphicBuffer::USAGE_SW_READ_OFTEN;
   bool swapRB = GetFlags() & TEXTURE_RB_SWAPPED;
 
   switch (mFormat) {
   case gfx::FORMAT_R8G8B8A8:
     format = swapRB ? android::PIXEL_FORMAT_BGRA_8888 : android::PIXEL_FORMAT_RGBA_8888;
@@ -233,23 +245,55 @@ GrallocTextureClientOGL::AllocateForYCbC
 {
   MOZ_ASSERT(IsValid());
   return AllocateGralloc(aYSize,
                          HAL_PIXEL_FORMAT_YV12,
                          android::GraphicBuffer::USAGE_SW_READ_OFTEN);
 }
 
 bool
+GrallocTextureClientOGL::AllocateForGLRendering(gfx::IntSize aSize)
+{
+  MOZ_ASSERT(IsValid());
+
+  uint32_t format;
+  uint32_t usage = android::GraphicBuffer::USAGE_HW_RENDER |
+                   android::GraphicBuffer::USAGE_HW_TEXTURE;
+
+  switch (mFormat) {
+  case gfx::FORMAT_R8G8B8A8:
+  case gfx::FORMAT_B8G8R8A8:
+    format = android::PIXEL_FORMAT_RGBA_8888;
+    break;
+  case gfx::FORMAT_R8G8B8X8:
+  case gfx::FORMAT_B8G8R8X8:
+    // there is no android BGRX format?
+    format = android::PIXEL_FORMAT_RGBX_8888;
+    break;
+  case gfx::FORMAT_R5G6B5:
+    format = android::PIXEL_FORMAT_RGB_565;
+    break;
+  case gfx::FORMAT_A8:
+    format = android::PIXEL_FORMAT_A_8;
+    break;
+  default:
+    NS_WARNING("Unsupported surface format");
+    return false;
+  }
+
+  return AllocateGralloc(aSize, format, usage);
+}
+
+bool
 GrallocTextureClientOGL::AllocateGralloc(gfx::IntSize aSize,
                                          uint32_t aAndroidFormat,
                                          uint32_t aUsage)
 {
   MOZ_ASSERT(IsValid());
-  MOZ_ASSERT(mCompositable);
-  ISurfaceAllocator* allocator = mCompositable->GetForwarder();
+  ISurfaceAllocator* allocator = GetAllocator();
 
   MaybeMagicGrallocBufferHandle handle;
   PGrallocBufferChild* actor =
     allocator->AllocGrallocBuffer(aSize,
                                   aAndroidFormat,
                                   aUsage,
                                   &handle);
   if (!actor) {
@@ -290,12 +334,21 @@ GrallocTextureClientOGL::Allocate(uint32
 size_t
 GrallocTextureClientOGL::GetBufferSize() const
 {
   // see Bug 908196
   MOZ_CRASH("This method should never be called.");
   return 0;
 }
 
+ISurfaceAllocator*
+GrallocTextureClientOGL::GetAllocator()
+{
+  MOZ_ASSERT(mCompositable || mAllocator);
+  return mCompositable ?
+         mCompositable->GetForwarder() :
+         mAllocator;
+}
+
 } // namesapace layers
 } // namesapace mozilla
 
 #endif // MOZ_WIDGET_GONK
--- a/gfx/layers/opengl/GrallocTextureClient.h
+++ b/gfx/layers/opengl/GrallocTextureClient.h
@@ -34,16 +34,19 @@ class GrallocTextureClientOGL : public B
 {
 public:
   GrallocTextureClientOGL(GrallocBufferActor* aActor,
                           gfx::IntSize aSize,
                           TextureFlags aFlags = TEXTURE_FLAGS_DEFAULT);
   GrallocTextureClientOGL(CompositableClient* aCompositable,
                           gfx::SurfaceFormat aFormat,
                           TextureFlags aFlags = TEXTURE_FLAGS_DEFAULT);
+  GrallocTextureClientOGL(ISurfaceAllocator* aAllocator,
+                          gfx::SurfaceFormat aFormat,
+                          TextureFlags aFlags = TEXTURE_FLAGS_DEFAULT);
 
   ~GrallocTextureClientOGL();
 
   virtual bool Lock(OpenMode aMode) MOZ_OVERRIDE;
 
   virtual void Unlock() MOZ_OVERRIDE;
 
   virtual bool ImplementsLocking() const MOZ_OVERRIDE { return true; }
@@ -51,16 +54,18 @@ public:
   virtual bool IsAllocated() const MOZ_OVERRIDE;
 
   virtual bool ToSurfaceDescriptor(SurfaceDescriptor& aOutDescriptor) MOZ_OVERRIDE;
 
   virtual TextureClientData* DropTextureData() MOZ_OVERRIDE;
 
   void InitWith(GrallocBufferActor* aActor, gfx::IntSize aSize);
 
+  void SetTextureFlags(TextureFlags aFlags) { AddFlags(aFlags); }
+
   gfx::IntSize GetSize() const MOZ_OVERRIDE { return mSize; }
 
   android::GraphicBuffer* GetGraphicBuffer()
   {
     return mGraphicBuffer.get();
   }
 
   android::PixelFormat GetPixelFormat()
@@ -82,35 +87,40 @@ public:
 
   virtual bool AllocateForSurface(gfx::IntSize aSize,
                                   TextureAllocationFlags aFlags = ALLOC_DEFAULT) MOZ_OVERRIDE;
 
   virtual bool AllocateForYCbCr(gfx::IntSize aYSize,
                                 gfx::IntSize aCbCrSize,
                                 StereoMode aStereoMode) MOZ_OVERRIDE;
 
+  bool AllocateForGLRendering(gfx::IntSize aSize);
+
   bool AllocateGralloc(gfx::IntSize aYSize, uint32_t aAndroidFormat, uint32_t aUsage);
 
   virtual bool Allocate(uint32_t aSize) MOZ_OVERRIDE;
 
   virtual size_t GetBufferSize() const MOZ_OVERRIDE;
 
   void SetGraphicBufferLocked(GraphicBufferLocked* aBufferLocked);
 
 protected:
+  ISurfaceAllocator* GetAllocator();
 
   /**
    * Unfortunately, until bug 879681 is fixed we need to use a GrallocBufferActor.
    */
   GrallocBufferActor* mGrallocActor;
 
   RefPtr<GraphicBufferLocked> mBufferLocked;
 
   android::sp<android::GraphicBuffer> mGraphicBuffer;
 
+  RefPtr<ISurfaceAllocator> mAllocator;
+
   /**
    * Flags that are used when locking the gralloc buffer
    */
   uint32_t mGrallocFlags;
   /**
    * Points to a mapped gralloc buffer between calls to lock and unlock.
    * Should be null outside of the lock-unlock pair.
    */
--- a/gfx/layers/opengl/TextureClientOGL.cpp
+++ b/gfx/layers/opengl/TextureClientOGL.cpp
@@ -1,17 +1,18 @@
 /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
-#include "mozilla/layers/TextureClientOGL.h"
 #include "GLContext.h"                  // for GLContext, etc
+#include "SurfaceStream.h"
 #include "mozilla/Assertions.h"         // for MOZ_ASSERT, etc
 #include "mozilla/layers/ISurfaceAllocator.h"
+#include "mozilla/layers/TextureClientOGL.h"
 #include "nsSize.h"                     // for nsIntSize
 
 using namespace mozilla::gl;
 
 namespace mozilla {
 namespace layers {
 
 class CompositableForwarder;
@@ -60,16 +61,52 @@ SharedTextureClientOGL::InitWith(gl::Sha
 }
 
 bool
 SharedTextureClientOGL::IsAllocated() const
 {
   return mHandle != 0;
 }
 
+StreamTextureClientOGL::StreamTextureClientOGL(TextureFlags aFlags)
+  : TextureClient(aFlags)
+  , mStream(0)
+{
+}
+
+StreamTextureClientOGL::~StreamTextureClientOGL()
+{
+  // the data is owned externally.
+}
+
+bool
+StreamTextureClientOGL::ToSurfaceDescriptor(SurfaceDescriptor& aOutDescriptor)
+{
+  if (!IsAllocated()) {
+    return false;
+  }
+
+  gfx::SurfaceStreamHandle handle = mStream->GetShareHandle();
+  aOutDescriptor = SurfaceStreamDescriptor(handle, false);
+  return true;
+}
+
+void
+StreamTextureClientOGL::InitWith(gfx::SurfaceStream* aStream)
+{
+  MOZ_ASSERT(!IsAllocated());
+  mStream = aStream;
+}
+
+bool
+StreamTextureClientOGL::IsAllocated() const
+{
+  return mStream != 0;
+}
+
 DeprecatedTextureClientSharedOGL::DeprecatedTextureClientSharedOGL(CompositableForwarder* aForwarder,
                                                const TextureInfo& aTextureInfo)
   : DeprecatedTextureClient(aForwarder, aTextureInfo)
   , mGL(nullptr)
 {
 }
 
 void
--- a/gfx/layers/opengl/TextureClientOGL.h
+++ b/gfx/layers/opengl/TextureClientOGL.h
@@ -10,16 +10,22 @@
 #include "gfxTypes.h"
 #include "mozilla/Attributes.h"         // for MOZ_OVERRIDE
 #include "mozilla/gfx/Point.h"          // for IntSize
 #include "mozilla/layers/CompositorTypes.h"
 #include "mozilla/layers/LayersSurfaces.h"  // for SurfaceDescriptor
 #include "mozilla/layers/TextureClient.h"  // for DeprecatedTextureClient, etc
 
 namespace mozilla {
+namespace gfx {
+class SurfaceStream;
+}
+}
+
+namespace mozilla {
 namespace layers {
 
 class CompositableForwarder;
 
 /**
  * A TextureClient implementation to share TextureMemory that is already
  * on the GPU, for the OpenGL backend.
  */
@@ -52,16 +58,40 @@ public:
 
 protected:
   gl::SharedTextureHandle mHandle;
   gfx::IntSize mSize;
   gl::SharedTextureShareType mShareType;
   bool mInverted;
 };
 
+/**
+ * A TextureClient implementation to share SurfaceStream.
+ */
+class StreamTextureClientOGL : public TextureClient
+{
+public:
+  StreamTextureClientOGL(TextureFlags aFlags);
+
+  ~StreamTextureClientOGL();
+
+  virtual bool IsAllocated() const MOZ_OVERRIDE;
+
+  virtual bool ToSurfaceDescriptor(SurfaceDescriptor& aOutDescriptor) MOZ_OVERRIDE;
+
+  virtual TextureClientData* DropTextureData() MOZ_OVERRIDE { return nullptr; }
+
+  void InitWith(gfx::SurfaceStream* aStream);
+
+  virtual gfx::IntSize GetSize() const { return gfx::IntSize(); }
+
+protected:
+  gfx::SurfaceStream* mStream;
+};
+
 class DeprecatedTextureClientSharedOGL : public DeprecatedTextureClient
 {
 public:
   DeprecatedTextureClientSharedOGL(CompositableForwarder* aForwarder, const TextureInfo& aTextureInfo);
   ~DeprecatedTextureClientSharedOGL() { ReleaseResources(); }
 
   virtual bool SupportsType(DeprecatedTextureClientType aType) MOZ_OVERRIDE { return aType == TEXTURE_SHARED_GL; }
   virtual bool EnsureAllocated(gfx::IntSize aSize, gfxContentType aType);
--- a/gfx/layers/opengl/TextureHostOGL.cpp
+++ b/gfx/layers/opengl/TextureHostOGL.cpp
@@ -103,16 +103,21 @@ CreateTextureHostOGL(const SurfaceDescri
       const SharedTextureDescriptor& desc = aDesc.get_SharedTextureDescriptor();
       result = new SharedTextureHostOGL(aFlags,
                                         desc.shareType(),
                                         desc.handle(),
                                         desc.size(),
                                         desc.inverted());
       break;
     }
+    case SurfaceDescriptor::TSurfaceStreamDescriptor: {
+      const SurfaceStreamDescriptor& desc = aDesc.get_SurfaceStreamDescriptor();
+      result = new StreamTextureHostOGL(aFlags, desc);
+      break;
+    }
 #ifdef XP_MACOSX
     case SurfaceDescriptor::TSurfaceDescriptorMacIOSurface: {
       const SurfaceDescriptorMacIOSurface& desc =
         aDesc.get_SurfaceDescriptorMacIOSurface();
       result = new MacIOSurfaceTextureHostOGL(aFlags, desc);
       break;
     }
 #endif
@@ -458,16 +463,194 @@ SharedTextureHostOGL::SetCompositor(Comp
 
 gfx::SurfaceFormat
 SharedTextureHostOGL::GetFormat() const
 {
   MOZ_ASSERT(mTextureSource);
   return mTextureSource->GetFormat();
 }
 
+void
+StreamTextureSourceOGL::BindTexture(GLenum activetex)
+{
+  MOZ_ASSERT(gl());
+  gl()->fActiveTexture(activetex);
+  gl()->fBindTexture(mTextureTarget, mTextureHandle);
+}
+
+bool
+StreamTextureSourceOGL::RetrieveTextureFromStream()
+{
+  gl()->MakeCurrent();
+
+  SharedSurface* sharedSurf = mStream->SwapConsumer();
+  if (!sharedSurf) {
+    // We don't have a valid surf to show yet.
+    return false;
+  }
+
+  gl()->MakeCurrent();
+
+  mSize = IntSize(sharedSurf->Size().width, sharedSurf->Size().height);
+
+  DataSourceSurface* toUpload = nullptr;
+  switch (sharedSurf->Type()) {
+    case SharedSurfaceType::GLTextureShare: {
+      SharedSurface_GLTexture* glTexSurf = SharedSurface_GLTexture::Cast(sharedSurf);
+      glTexSurf->SetConsumerGL(gl());
+      mTextureHandle = glTexSurf->Texture();
+      mTextureTarget = glTexSurf->TextureTarget();
+      MOZ_ASSERT(mTextureHandle);
+      mFormat = sharedSurf->HasAlpha() ? FORMAT_R8G8B8A8
+                                       : FORMAT_R8G8B8X8;
+      break;
+    }
+    case SharedSurfaceType::EGLImageShare: {
+      SharedSurface_EGLImage* eglImageSurf =
+          SharedSurface_EGLImage::Cast(sharedSurf);
+
+      mTextureHandle = eglImageSurf->AcquireConsumerTexture(gl());
+      mTextureTarget = eglImageSurf->TextureTarget();
+      if (!mTextureHandle) {
+        toUpload = eglImageSurf->GetPixels();
+        MOZ_ASSERT(toUpload);
+      } else {
+        mFormat = sharedSurf->HasAlpha() ? FORMAT_R8G8B8A8
+                                         : FORMAT_R8G8B8X8;
+      }
+      break;
+    }
+#ifdef XP_MACOSX
+    case SharedSurfaceType::IOSurface: {
+      SharedSurface_IOSurface* glTexSurf = SharedSurface_IOSurface::Cast(sharedSurf);
+      mTextureHandle = glTexSurf->Texture();
+      mTextureTarget = glTexSurf->TextureTarget();
+      MOZ_ASSERT(mTextureHandle);
+      mFormat = sharedSurf->HasAlpha() ? FORMAT_R8G8B8A8
+                                       : FORMAT_R8G8B8X8;
+      break;
+    }
+#endif
+    case SharedSurfaceType::Basic: {
+      toUpload = SharedSurface_Basic::Cast(sharedSurf)->GetData();
+      MOZ_ASSERT(toUpload);
+      break;
+    }
+    default:
+      MOZ_CRASH("Invalid SharedSurface type.");
+  }
+
+  if (toUpload) {
+    // mBounds seems to end up as (0,0,0,0) a lot, so don't use it?
+    nsIntSize size(ThebesIntSize(toUpload->GetSize()));
+    nsIntRect rect(nsIntPoint(0,0), size);
+    nsIntRegion bounds(rect);
+    mFormat = UploadSurfaceToTexture(gl(),
+                                     toUpload,
+                                     bounds,
+                                     mUploadTexture,
+                                     true);
+    mTextureHandle = mUploadTexture;
+    mTextureTarget = LOCAL_GL_TEXTURE_2D;
+  }
+
+  MOZ_ASSERT(mTextureHandle);
+  gl()->fBindTexture(mTextureTarget, mTextureHandle);
+  gl()->fTexParameteri(mTextureTarget,
+                      LOCAL_GL_TEXTURE_WRAP_S,
+                      LOCAL_GL_CLAMP_TO_EDGE);
+  gl()->fTexParameteri(mTextureTarget,
+                      LOCAL_GL_TEXTURE_WRAP_T,
+                      LOCAL_GL_CLAMP_TO_EDGE);
+
+  return true;
+}
+
+void
+StreamTextureSourceOGL::DeallocateDeviceData()
+{
+  if (mUploadTexture) {
+    MOZ_ASSERT(gl());
+    gl()->MakeCurrent();
+    gl()->fDeleteTextures(1, &mUploadTexture);
+    mUploadTexture = 0;
+    mTextureHandle = 0;
+  }
+}
+
+gl::GLContext*
+StreamTextureSourceOGL::gl() const
+{
+  return mCompositor ? mCompositor->gl() : nullptr;
+}
+
+void
+StreamTextureSourceOGL::SetCompositor(Compositor* aCompositor)
+{
+  mCompositor = static_cast<CompositorOGL*>(aCompositor);
+}
+
+StreamTextureHostOGL::StreamTextureHostOGL(TextureFlags aFlags,
+                                           const SurfaceStreamDescriptor& aDesc)
+  : TextureHost(aFlags)
+{
+  mStream = SurfaceStream::FromHandle(aDesc.handle());
+  MOZ_ASSERT(mStream);
+}
+
+StreamTextureHostOGL::~StreamTextureHostOGL()
+{
+  // If need to deallocate textures, call DeallocateSharedData() before
+  // the destructor
+}
+
+bool
+StreamTextureHostOGL::Lock()
+{
+  if (!mCompositor) {
+    return false;
+  }
+
+  if (!mTextureSource) {
+    mTextureSource = new StreamTextureSourceOGL(mCompositor,
+                                                mStream);
+  }
+
+  return mTextureSource->RetrieveTextureFromStream();
+}
+
+void
+StreamTextureHostOGL::Unlock()
+{
+}
+
+void
+StreamTextureHostOGL::SetCompositor(Compositor* aCompositor)
+{
+  CompositorOGL* glCompositor = static_cast<CompositorOGL*>(aCompositor);
+  mCompositor = glCompositor;
+  if (mTextureSource) {
+    mTextureSource->SetCompositor(glCompositor);
+  }
+}
+
+gfx::SurfaceFormat
+StreamTextureHostOGL::GetFormat() const
+{
+  MOZ_ASSERT(mTextureSource);
+  return mTextureSource->GetFormat();
+}
+
+gfx::IntSize
+StreamTextureHostOGL::GetSize() const
+{
+  MOZ_ASSERT(mTextureSource);
+  return mTextureSource->GetSize();
+}
+
 TextureImageDeprecatedTextureHostOGL::~TextureImageDeprecatedTextureHostOGL()
 {
   MOZ_COUNT_DTOR(TextureImageDeprecatedTextureHostOGL);
   if (mTexture && mTexture->InUpdate()) {
     mTexture->EndUpdate();
   }
 }
 
--- a/gfx/layers/opengl/TextureHostOGL.h
+++ b/gfx/layers/opengl/TextureHostOGL.h
@@ -331,16 +331,118 @@ protected:
   CompositorOGL* mCompositor;
   gl::SharedTextureHandle mSharedHandle;
   gl::SharedTextureShareType mShareType;
 
   RefPtr<SharedTextureSourceOGL> mTextureSource;
 };
 
 /**
+ * A texture source meant for use with StreamTextureHostOGL.
+ *
+ * It does not own any texture, we get texture from SurfaceStream.
+ */
+class StreamTextureSourceOGL : public NewTextureSource
+                             , public TextureSourceOGL
+{
+public:
+  StreamTextureSourceOGL(CompositorOGL* aCompositor,
+                         gfx::SurfaceStream* aStream)
+    : mCompositor(aCompositor)
+    , mStream(aStream)
+    , mTextureHandle(0)
+    , mTextureTarget(LOCAL_GL_TEXTURE_2D)
+    , mUploadTexture(0)
+    , mFormat(gfx::FORMAT_UNKNOWN)
+  {
+    MOZ_COUNT_CTOR(StreamTextureSourceOGL);
+  }
+
+  ~StreamTextureSourceOGL()
+  {
+    MOZ_COUNT_DTOR(StreamTextureSourceOGL);
+  }
+
+  virtual TextureSourceOGL* AsSourceOGL() { return this; }
+
+  virtual void BindTexture(GLenum activetex) MOZ_OVERRIDE;
+
+  virtual bool IsValid() const MOZ_OVERRIDE { return !!gl(); }
+
+  virtual gfx::IntSize GetSize() const MOZ_OVERRIDE { return mSize; }
+
+  virtual gfx::SurfaceFormat GetFormat() const MOZ_OVERRIDE { return mFormat; }
+
+  virtual GLenum GetTextureTarget() const { return mTextureTarget; }
+
+  virtual GLenum GetWrapMode() const MOZ_OVERRIDE { return LOCAL_GL_CLAMP_TO_EDGE; }
+
+  virtual void DeallocateDeviceData();
+
+  bool RetrieveTextureFromStream();
+
+  virtual void SetCompositor(Compositor* aCompositor) MOZ_OVERRIDE;
+
+protected:
+  gl::GLContext* gl() const;
+
+  CompositorOGL* mCompositor;
+  gfx::SurfaceStream* mStream;
+  GLuint mTextureHandle;
+  GLenum mTextureTarget;
+  GLuint mUploadTexture;
+  gfx::IntSize mSize;
+  gfx::SurfaceFormat mFormat;
+};
+
+/**
+ * A TextureHost for shared SurfaceStream
+ */
+class StreamTextureHostOGL : public TextureHost
+{
+public:
+  StreamTextureHostOGL(TextureFlags aFlags,
+                       const SurfaceStreamDescriptor& aDesc);
+
+  virtual ~StreamTextureHostOGL();
+
+  // SharedTextureHostOGL doesn't own any GL texture
+  virtual void DeallocateDeviceData() MOZ_OVERRIDE {}
+
+  virtual void SetCompositor(Compositor* aCompositor) MOZ_OVERRIDE;
+
+  virtual bool Lock() MOZ_OVERRIDE;
+
+  virtual void Unlock() MOZ_OVERRIDE;
+
+  virtual gfx::SurfaceFormat GetFormat() const MOZ_OVERRIDE;
+
+  virtual NewTextureSource* GetTextureSources() MOZ_OVERRIDE
+  {
+    return mTextureSource;
+  }
+
+  virtual TemporaryRef<gfx::DataSourceSurface> GetAsSurface() MOZ_OVERRIDE
+  {
+    return nullptr; // XXX - implement this (for MOZ_DUMP_PAINTING)
+  }
+
+  virtual gfx::IntSize GetSize() const MOZ_OVERRIDE;
+
+#ifdef MOZ_LAYERS_HAVE_LOG
+  virtual const char* Name() { return "StreamTextureHostOGL"; }
+#endif
+
+protected:
+  CompositorOGL* mCompositor;
+  gfx::SurfaceStream* mStream;
+  RefPtr<StreamTextureSourceOGL> mTextureSource;
+};
+
+/**
  * DeprecatedTextureHost implementation using a TextureImage as the underlying texture.
  */
 class TextureImageDeprecatedTextureHostOGL : public DeprecatedTextureHost
                                            , public TextureSourceOGL
                                            , public TileIterator
 {
 public:
   TextureImageDeprecatedTextureHostOGL(gl::TextureImage* aTexImage = nullptr)
new file mode 100644
--- /dev/null
+++ b/gfx/tests/gtest/TestSkipChars.cpp
@@ -0,0 +1,135 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "gtest/gtest.h"
+
+#include "gfxSkipChars.h"
+#include "mozilla/ArrayUtils.h"
+
+static bool
+TestConstructor()
+{
+  gfxSkipChars skipChars;
+
+  EXPECT_TRUE(skipChars.GetOriginalCharCount() == 0) <<
+    "[1] Make sure the gfxSkipChars was properly initialized with constructor";
+
+  return true;
+}
+
+static bool
+TestLength()
+{
+  gfxSkipChars skipChars;
+
+  skipChars.KeepChars(100);
+
+  EXPECT_TRUE(skipChars.GetOriginalCharCount() == 100) <<
+    "[1] Check length after keeping chars";
+
+  skipChars.SkipChars(50);
+
+  EXPECT_TRUE(skipChars.GetOriginalCharCount() == 150) <<
+    "[2] Check length after skipping chars";
+
+  skipChars.SkipChars(50);
+
+  EXPECT_TRUE(skipChars.GetOriginalCharCount() == 200) <<
+    "[3] Check length after skipping more chars";
+
+  skipChars.KeepChar();
+
+  EXPECT_TRUE(skipChars.GetOriginalCharCount() == 201) <<
+    "[4] Check length after keeping a final char";
+
+  return true;
+}
+
+static bool
+TestIterator()
+{
+  // Test a gfxSkipChars that starts with kept chars
+  gfxSkipChars skipChars1;
+
+  skipChars1.KeepChars(9);
+  skipChars1.SkipChar();
+  skipChars1.KeepChars(9);
+  skipChars1.SkipChar();
+  skipChars1.KeepChars(9);
+
+  EXPECT_TRUE(skipChars1.GetOriginalCharCount() == 29) <<
+    "[1] Check length";
+
+  gfxSkipCharsIterator iter1(skipChars1);
+
+  EXPECT_TRUE(iter1.GetOriginalOffset() == 0) <<
+    "[2] Check initial original offset";
+  EXPECT_TRUE(iter1.GetSkippedOffset() == 0) <<
+    "[3] Check initial skipped offset";
+
+  uint32_t expectSkipped1[] =
+  {  0,  1,  2,  3,  4,  5,  6,  7,  8,  9,
+     9, 10, 11, 12, 13, 14, 15, 16, 17, 18,
+    18, 19, 20, 21, 22, 23, 24, 25, 26, 27 };
+
+  for (uint32_t i = 0; i < mozilla::ArrayLength(expectSkipped1); i++) {
+    EXPECT_TRUE(iter1.ConvertOriginalToSkipped(i) == expectSkipped1[i]) <<
+      "[4] Check mapping of original to skipped for " << i;
+  }
+
+  uint32_t expectOriginal1[] =
+  {  0,  1,  2,  3,  4,  5,  6,  7,  8,
+    10, 11, 12, 13, 14, 15, 16, 17, 18,
+    20, 21, 22, 23, 24, 25, 26, 27, 28 };
+
+  for (uint32_t i = 0; i < mozilla::ArrayLength(expectOriginal1); i++) {
+    EXPECT_TRUE(iter1.ConvertSkippedToOriginal(i) == expectOriginal1[i]) <<
+      "[5] Check mapping of skipped to original for " << i;
+  }
+
+  // Test a gfxSkipChars that starts with skipped chars
+  gfxSkipChars skipChars2;
+
+  skipChars2.SkipChars(9);
+  skipChars2.KeepChar();
+  skipChars2.SkipChars(9);
+  skipChars2.KeepChar();
+  skipChars2.SkipChars(9);
+
+  EXPECT_TRUE(skipChars2.GetOriginalCharCount() == 29) <<
+    "[6] Check length";
+
+  gfxSkipCharsIterator iter2(skipChars2);
+
+  EXPECT_TRUE(iter2.GetOriginalOffset() == 0) <<
+    "[7] Check initial original offset";
+  EXPECT_TRUE(iter2.GetSkippedOffset() == 0) <<
+    "[8] Check initial skipped offset";
+
+  uint32_t expectSkipped2[] =
+  {  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+     1,  1,  1,  1,  1,  1,  1,  1,  1,  1,
+     2,  2,  2,  2,  2,  2,  2,  2,  2,  2 };
+
+  for (uint32_t i = 0; i < mozilla::ArrayLength(expectSkipped2); i++) {
+    EXPECT_TRUE(iter2.ConvertOriginalToSkipped(i) == expectSkipped2[i]) <<
+      "[9] Check mapping of original to skipped for " << i;
+  }
+
+  uint32_t expectOriginal2[] = { 9, 19, 29 };
+
+  for (uint32_t i = 0; i < mozilla::ArrayLength(expectOriginal2); i++) {
+    EXPECT_TRUE(iter2.ConvertSkippedToOriginal(i) == expectOriginal2[i]) <<
+      "[10] Check mapping of skipped to original for " << i;
+  }
+
+  return true;
+}
+
+TEST(Gfx, gfxSkipChars) {
+  TestConstructor();
+  TestLength();
+  TestIterator();
+}
--- a/gfx/tests/gtest/moz.build
+++ b/gfx/tests/gtest/moz.build
@@ -10,16 +10,17 @@ UNIFIED_SOURCES += [
     'gfxSurfaceRefCountTest.cpp',
     # Disabled on suspicion of causing bug 904227
     #'gfxWordCacheTest.cpp',
     'TestAsyncPanZoomController.cpp',
     'TestBufferRotation.cpp',
     'TestColorNames.cpp',
     'TestLayers.cpp',
     'TestRegion.cpp',
+    'TestSkipChars.cpp',
     # Hangs on linux in ApplyGdkScreenFontOptions
     #'gfxFontSelectionTest.cpp',
     'TestTextures.cpp',
     # Test works but it doesn't assert anything
     #'gfxTextRunPerfTest.cpp',
     'TestTiledLayerBuffer.cpp',
 ]
 
--- a/gfx/thebes/gfxPattern.cpp
+++ b/gfx/thebes/gfxPattern.cpp
@@ -174,18 +174,21 @@ Pattern*
 gfxPattern::GetPattern(DrawTarget *aTarget, Matrix *aPatternTransform)
 {
   if (mGfxPattern) {
     mGfxPattern->~Pattern();
     mGfxPattern = nullptr;
   }
 
   if (!mPattern) {
+    Matrix adjustedMatrix = mTransform;
+    if (aPatternTransform)
+      AdjustTransformForPattern(adjustedMatrix, aTarget->GetTransform(), aPatternTransform);
     mGfxPattern = new (mSurfacePattern.addr())
-      SurfacePattern(mSourceSurface, ToExtendMode(mExtend), mTransform, mFilter);
+      SurfacePattern(mSourceSurface, ToExtendMode(mExtend), adjustedMatrix, mFilter);
     return mGfxPattern;
   }
 
   GraphicsExtend extend = (GraphicsExtend)cairo_pattern_get_extend(mPattern);
 
   switch (cairo_pattern_get_type(mPattern)) {
   case CAIRO_PATTERN_TYPE_SOLID:
     {
--- a/gfx/thebes/gfxSkipChars.cpp
+++ b/gfx/thebes/gfxSkipChars.cpp
@@ -1,231 +1,140 @@
 /* -*- Mode: C++; tab-width: 20; 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/. */
 
 #include "gfxSkipChars.h"
 
-#include <stdlib.h>
-#include <algorithm>
-
-#define SHORTCUT_FREQUENCY 256
-
-// Even numbered list entries are "keep" entries
-static bool
-IsKeepEntry(uint32_t aEntry)
+void
+gfxSkipCharsIterator::SetOriginalOffset(int32_t aOffset)
 {
-    return !(aEntry & 1);
-}
+    aOffset += mOriginalStringToSkipCharsOffset;
+    NS_ASSERTION(uint32_t(aOffset) <= mSkipChars->mCharCount,
+                 "Invalid offset");
 
-void
-gfxSkipChars::BuildShortcuts()
-{
-    if (!mList || mCharCount < SHORTCUT_FREQUENCY)
-        return;
-  
-    mShortcuts = new Shortcut[mCharCount/SHORTCUT_FREQUENCY];
-    if (!mShortcuts)
+    mOriginalStringOffset = aOffset;
+
+    uint32_t rangeCount = mSkipChars->mRanges.Length();
+    if (rangeCount == 0) {
+        mSkippedStringOffset = aOffset;
         return;
-  
-    uint32_t i;
-    uint32_t nextShortcutIndex = 0;
-    uint32_t originalCharOffset = 0;
-    uint32_t skippedCharOffset = 0;
-    for (i = 0; i < mListLength; ++i) {
-        uint8_t len = mList[i];
-    
-        // We use >= here to ensure that when mCharCount is a multiple of
-        // SHORTCUT_FREQUENCY, we fill in the final shortcut with a reference
-        // to the last element of mList. This means that in general when a list
-        // element ends on an offset that's a multiple of SHORTCUT_FREQUENCY,
-        // that list element is the shortcut for that offset, which is
-        // slightly suboptimal (the *next* element is the one we really want),
-        // but it's all correct and simpler this way.
-        while (originalCharOffset + len >= (nextShortcutIndex + 1)*SHORTCUT_FREQUENCY) {
-            mShortcuts[nextShortcutIndex] =
-                Shortcut(i, originalCharOffset, skippedCharOffset);
-            ++nextShortcutIndex;
-        }
-    
-        originalCharOffset += len;
-        if (IsKeepEntry(i)) {
-            skippedCharOffset += len;
+    }
+
+    // at start of string?
+    if (aOffset == 0) {
+        mSkippedStringOffset = 0;
+        mCurrentRangeIndex =
+            rangeCount && mSkipChars->mRanges[0].Start() == 0 ? 0 : -1;
+        return;
+    }
+
+    // find the range that includes or precedes aOffset
+    uint32_t lo = 0, hi = rangeCount;
+    const gfxSkipChars::SkippedRange* ranges = mSkipChars->mRanges.Elements();
+    while (lo < hi) {
+        uint32_t mid = (lo + hi) / 2;
+        if (uint32_t(aOffset) < ranges[mid].Start()) {
+            hi = mid;
+        } else {
+            lo = mid + 1;
         }
     }
+
+    if (lo == rangeCount) {
+        mCurrentRangeIndex = rangeCount - 1;
+    } else if (uint32_t(aOffset) < ranges[lo].Start()) {
+        mCurrentRangeIndex = lo - 1;
+        if (mCurrentRangeIndex == -1) {
+            mSkippedStringOffset = aOffset;
+            return;
+        }
+    } else {
+        mCurrentRangeIndex = lo;
+    }
+
+    const gfxSkipChars::SkippedRange& r = ranges[mCurrentRangeIndex];
+    if (uint32_t(aOffset) < r.End()) {
+        mSkippedStringOffset = r.SkippedOffset();
+        return;
+    }
+
+    mSkippedStringOffset = aOffset - r.NextDelta();
 }
 
 void
-gfxSkipCharsIterator::SetOffsets(uint32_t aOffset, bool aInOriginalString)
+gfxSkipCharsIterator::SetSkippedOffset(uint32_t aOffset)
 {
-    NS_ASSERTION(aOffset <= mSkipChars->mCharCount,
-                 "Invalid offset");
+    NS_ASSERTION((mSkipChars->mRanges.IsEmpty() &&
+                  aOffset <= mSkipChars->mCharCount) ||
+                 (aOffset <= mSkipChars->LastRange().SkippedOffset() +
+                                 mSkipChars->mCharCount -
+                                 mSkipChars->LastRange().End()),
+                 "Invalid skipped offset");
+    mSkippedStringOffset = aOffset;
 
-    if (mSkipChars->mListLength == 0) {
-        mOriginalStringOffset = mSkippedStringOffset = aOffset;
+    uint32_t rangeCount = mSkipChars->mRanges.Length();
+    if (rangeCount == 0) {
+        mOriginalStringOffset = aOffset;
         return;
     }
-  
-    if (aOffset == 0) {
-        // Start from the beginning of the string.
-        mSkippedStringOffset = 0;
-        mOriginalStringOffset = 0;
-        mListPrefixLength = 0;
-        mListPrefixKeepCharCount = 0;
-        mListPrefixCharCount = 0;
-        if (aInOriginalString) {
-            // Nothing more to do!
-            return;
-        }
-    }
-  
-    if (aInOriginalString && mSkipChars->mShortcuts &&
-        abs(int32_t(aOffset) - int32_t(mListPrefixCharCount)) > SHORTCUT_FREQUENCY) {
-        // Take a shortcut. This makes SetOffsets(..., true) O(1) by bounding
-        // the iterations in the loop below to at most SHORTCUT_FREQUENCY iterations
-        uint32_t shortcutIndex = aOffset/SHORTCUT_FREQUENCY;
-        if (shortcutIndex == 0) {
-            mListPrefixLength = 0;
-            mListPrefixKeepCharCount = 0;
-            mListPrefixCharCount = 0;
+
+    uint32_t lo = 0, hi = rangeCount;
+    const gfxSkipChars::SkippedRange* ranges = mSkipChars->mRanges.Elements();
+    while (lo < hi) {
+        uint32_t mid = (lo + hi) / 2;
+        if (aOffset < ranges[mid].SkippedOffset()) {
+            hi = mid;
         } else {
-            const gfxSkipChars::Shortcut& shortcut = mSkipChars->mShortcuts[shortcutIndex - 1];
-            mListPrefixLength = shortcut.mListPrefixLength;
-            mListPrefixKeepCharCount = shortcut.mListPrefixKeepCharCount;
-            mListPrefixCharCount = shortcut.mListPrefixCharCount;
+            lo = mid + 1;
         }
     }
-  
-    int32_t currentRunLength = mSkipChars->mList[mListPrefixLength];
-    for (;;) {
-        // See if aOffset is in the string segment described by
-        // mSkipChars->mList[mListPrefixLength]
-        uint32_t segmentOffset = aInOriginalString ? mListPrefixCharCount : mListPrefixKeepCharCount;
-        if ((aInOriginalString || IsKeepEntry(mListPrefixLength)) &&
-            aOffset >= segmentOffset && aOffset < segmentOffset + currentRunLength) {
-            int32_t offsetInSegment = aOffset - segmentOffset;
-            mOriginalStringOffset = mListPrefixCharCount + offsetInSegment;
-            mSkippedStringOffset = mListPrefixKeepCharCount;
-            if (IsKeepEntry(mListPrefixLength)) {
-                mSkippedStringOffset += offsetInSegment;
-            }
+
+    if (lo == rangeCount) {
+        mCurrentRangeIndex = rangeCount - 1;
+    } else if (aOffset < ranges[lo].SkippedOffset()) {
+        mCurrentRangeIndex = lo - 1;
+        if (mCurrentRangeIndex == -1) {
+            mOriginalStringOffset = aOffset;
             return;
         }
-        
-        if (aOffset < segmentOffset) {
-            // We need to move backwards
-            if (mListPrefixLength <= 0) {
-                // nowhere to go backwards
-                mOriginalStringOffset = mSkippedStringOffset = 0;
-                return;
-            }
-            // Go backwards one segment and restore invariants
-            --mListPrefixLength;
-            currentRunLength = mSkipChars->mList[mListPrefixLength];
-            mListPrefixCharCount -= currentRunLength;
-            if (IsKeepEntry(mListPrefixLength)) {
-                mListPrefixKeepCharCount -= currentRunLength;
-            }
-        } else {
-            // We need to move forwards
-            if (mListPrefixLength >= mSkipChars->mListLength - 1) {
-                // nowhere to go forwards
-                mOriginalStringOffset = mListPrefixCharCount + currentRunLength;
-                mSkippedStringOffset = mListPrefixKeepCharCount;
-                if (IsKeepEntry(mListPrefixLength)) {
-                    mSkippedStringOffset += currentRunLength;
-                }
-                return;
-            }
-            // Go forwards one segment and restore invariants
-            mListPrefixCharCount += currentRunLength;
-            if (IsKeepEntry(mListPrefixLength)) {
-                mListPrefixKeepCharCount += currentRunLength;
-            }
-            ++mListPrefixLength;
-            currentRunLength = mSkipChars->mList[mListPrefixLength];
-        }
+    } else {
+        mCurrentRangeIndex = lo;
     }
+
+    const gfxSkipChars::SkippedRange& r = ranges[mCurrentRangeIndex];
+    mOriginalStringOffset = r.End() + aOffset - r.SkippedOffset();
 }
 
 bool
 gfxSkipCharsIterator::IsOriginalCharSkipped(int32_t* aRunLength) const
 {
-    if (mSkipChars->mListLength == 0) {
+    if (mCurrentRangeIndex == -1) {
+        // we're before the first skipped range (if any)
         if (aRunLength) {
-            *aRunLength = mSkipChars->mCharCount - mOriginalStringOffset;
+            uint32_t end = mSkipChars->mRanges.IsEmpty() ?
+                mSkipChars->mCharCount : mSkipChars->mRanges[0].Start();
+            *aRunLength = end - mOriginalStringOffset;
         }
         return mSkipChars->mCharCount == uint32_t(mOriginalStringOffset);
     }
-  
-    uint32_t listPrefixLength = mListPrefixLength;
-    // figure out which segment we're in
-    uint32_t currentRunLength = mSkipChars->mList[listPrefixLength];
-    // Zero-length list entries are possible. Advance until mListPrefixLength
-    // is pointing to a run with real characters (or we're at the end of the
-    // string).
-    while (currentRunLength == 0 && listPrefixLength < mSkipChars->mListLength - 1) {
-        ++listPrefixLength;
-        // This does not break the iterator's invariant because no skipped
-        // or kept characters are being added
-        currentRunLength = mSkipChars->mList[listPrefixLength];
-    }
-    NS_ASSERTION(uint32_t(mOriginalStringOffset) >= mListPrefixCharCount,
-                 "Invariant violation");
-    uint32_t offsetIntoCurrentRun =
-      uint32_t(mOriginalStringOffset) - mListPrefixCharCount;
-    if (listPrefixLength >= mSkipChars->mListLength - 1 &&
-        offsetIntoCurrentRun >= currentRunLength) {
-        NS_ASSERTION(listPrefixLength == mSkipChars->mListLength - 1 &&
-                     offsetIntoCurrentRun == currentRunLength,
-                     "Overran end of string");
-        // We're at the end of the string
+
+    const gfxSkipChars::SkippedRange& range =
+        mSkipChars->mRanges[mCurrentRangeIndex];
+
+    if (uint32_t(mOriginalStringOffset) < range.End()) {
         if (aRunLength) {
-            *aRunLength = 0;
+            *aRunLength = range.End() - mOriginalStringOffset;
         }
         return true;
     }
-  
-    bool isSkipped = !IsKeepEntry(listPrefixLength);
-    if (aRunLength) {
-        // Long runs of all-skipped or all-kept characters will be encoded as
-        // sequences of 255, 0, 255, 0 etc. Compute the maximum run length by skipping
-        // over zero entries.
-        uint32_t runLength = currentRunLength - offsetIntoCurrentRun;
-        for (uint32_t i = listPrefixLength + 2; i < mSkipChars->mListLength; i += 2) {
-            if (mSkipChars->mList[i - 1] != 0)
-                break;
-            runLength += mSkipChars->mList[i];
-        }
-        *aRunLength = runLength;
-    }
-    return isSkipped;
-}
 
-void
-gfxSkipCharsBuilder::FlushRun()
-{
-    NS_ASSERTION((mBuffer.Length() & 1) == mRunSkipped,
-                 "out of sync?");
-    // Fill in buffer entries starting at mBufferLength, as many as necessary
-    uint32_t charCount = mRunCharCount;
-    for (;;) {
-        uint32_t chars = std::min<uint32_t>(255, charCount);
-        if (!mBuffer.AppendElement(chars)) {
-            mInErrorState = true;
-            return;
-        }
-        charCount -= chars;
-        if (charCount == 0)
-            break;
-        if (!mBuffer.AppendElement(0)) {
-            mInErrorState = true;
-            return;
-        }
+    if (aRunLength) {
+        uint32_t end =
+            uint32_t(mCurrentRangeIndex) + 1 < mSkipChars->mRanges.Length() ?
+                mSkipChars->mRanges[mCurrentRangeIndex + 1].Start() :
+                mSkipChars->mCharCount;
+        *aRunLength = end - mOriginalStringOffset;
     }
-  
-    NS_ASSERTION(mCharCount + mRunCharCount >= mCharCount,
-                 "String length overflow");
-    mCharCount += mRunCharCount;
-    mRunCharCount = 0;
-    mRunSkipped = !mRunSkipped;
+
+    return mSkipChars->mCharCount == uint32_t(mOriginalStringOffset);
 }
--- a/gfx/thebes/gfxSkipChars.h
+++ b/gfx/thebes/gfxSkipChars.h
@@ -1,316 +1,302 @@
 /* -*- Mode: C++; tab-width: 20; 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 GFX_SKIP_CHARS_H
 #define GFX_SKIP_CHARS_H
 
-#include "nsAutoPtr.h"
 #include "nsTArray.h"
 
 /*
  * gfxSkipChars is a data structure representing a list of characters that
  * have been skipped. The initial string is called the "original string"
  * and after skipping some characters, the result is called the "skipped string".
  * gfxSkipChars provides efficient ways to translate between offsets in the
  * original string and the skipped string. It is used by textrun code to keep
  * track of offsets before and after text transformations such as whitespace
  * compression and control code deletion.
  */
 
 /**
- * gfxSkipCharsBuilder is a helper class that accumulates a list of (skip, keep)
- * commands and can eventually be used to construct a real gfxSkipChars.
- * gfxSkipCharsBuilder objects are quite large so don't keep these around.
- * On the positive side, the Skip/KeepChar(s) methods are very efficient,
- * especially when you have runs of all-kept or all-skipped characters.
- * 
- * mBuffer is an array of bytes; even numbered bytes represent characters kept,
- * odd numbered bytes represent characters skipped. After those characters
- * are accounted for, we have mRunCharCount characters which are kept or
- * skipped depending on the value of mRunSkipped.
- * 
- * mCharCount is the sum of counts of all skipped and kept characters, i.e.,
- * the length of the original string.
+ * The gfxSkipChars is represented as a sorted array of skipped ranges.
+ *
+ * A freshly-created gfxSkipChars means "all chars kept".
  */
-class gfxSkipCharsBuilder {
+class gfxSkipChars
+{
+private:
+    class SkippedRange
+    {
+    public:
+        SkippedRange(uint32_t aOffset, uint32_t aLength, uint32_t aDelta)
+            : mOffset(aOffset), mLength(aLength), mDelta(aDelta)
+        { }
+
+        uint32_t Start() const
+        {
+            return mOffset;
+        }
+
+        uint32_t End() const
+        {
+            return mOffset + mLength;
+        }
+
+        uint32_t Length() const
+        {
+            return mLength;
+        }
+
+        uint32_t SkippedOffset() const
+        {
+            return mOffset - mDelta;
+        }
+
+        uint32_t Delta() const
+        {
+            return mDelta;
+        }
+
+        uint32_t NextDelta() const
+        {
+            return mDelta + mLength;
+        }
+
+        void Extend(uint32_t aChars)
+        {
+            mLength += aChars;
+        }
+
+    private:
+        uint32_t mOffset; // original-string offset at which we want to skip
+        uint32_t mLength; // number of skipped chars at this offset
+        uint32_t mDelta;  // sum of lengths of preceding skipped-ranges
+    };
+
 public:
-    gfxSkipCharsBuilder() :
-        mCharCount(0), mRunCharCount(0), mRunSkipped(false), mInErrorState(false)
-    {}
-  
-    void SkipChars(uint32_t aChars) {
-        DoChars(aChars, true);
-    }
-    void KeepChars(uint32_t aChars) {
-        DoChars(aChars, false);
-    }
-    void SkipChar() {
-        SkipChars(1);
-    }
-    void KeepChar() {
-        KeepChars(1);
-    }
-    void DoChars(uint32_t aChars, bool aSkipped) {
-        if (aSkipped != mRunSkipped && aChars > 0) {
-            FlushRun();
+    gfxSkipChars()
+        : mCharCount(0)
+    { }
+
+    void SkipChars(uint32_t aChars)
+    {
+        NS_ASSERTION(mCharCount + aChars > mCharCount,
+                     "Character count overflow");
+        uint32_t rangeCount = mRanges.Length();
+        uint32_t delta = 0;
+        if (rangeCount > 0) {
+            SkippedRange& lastRange = mRanges[rangeCount - 1];
+            if (lastRange.End() == mCharCount) {
+                lastRange.Extend(aChars);
+                mCharCount += aChars;
+                return;
+            }
+            delta = lastRange.NextDelta();
         }
-        NS_ASSERTION(mRunCharCount + aChars > mRunCharCount,
-                     "Character count overflow");
-        mRunCharCount += aChars;
+        mRanges.AppendElement(SkippedRange(mCharCount, aChars, delta));
+        mCharCount += aChars;
     }
 
-    bool IsOK() { return !mInErrorState; }
-
-    uint32_t GetCharCount() { return mCharCount + mRunCharCount; }
-    bool GetAllCharsKept() { return mBuffer.Length() == 0; }
-
-    friend class gfxSkipChars;
-
-private:
-    typedef AutoFallibleTArray<uint8_t,256> Buffer;
+    void KeepChars(uint32_t aChars)
+    {
+        NS_ASSERTION(mCharCount + aChars > mCharCount,
+                     "Character count overflow");
+        mCharCount += aChars;
+    }
 
-    /**
-     * Moves mRunCharCount/mRunSkipped to the buffer (updating mCharCount),
-     * sets mRunCharCount to zero and toggles mRunSkipped.
-     */
-    void FlushRun();
-  
-    Buffer       mBuffer;
-    uint32_t     mCharCount;
-    uint32_t     mRunCharCount;
-    bool mRunSkipped; // == mBuffer.Length()&1
-    bool mInErrorState;
-};
+    void SkipChar()
+    {
+        SkipChars(1);
+    }
 
-/**
- * The gfxSkipChars list is represented as a list of bytes of the form
- * [chars to keep, chars to skip, chars to keep, chars to skip, ...]
- * In the special case where all chars are to be kept, the list is length
- * zero.
- * 
- * A freshly-created gfxSkipChars means "all chars kept".
- */
-class gfxSkipChars {
-public:
-    gfxSkipChars() : mListLength(0), mCharCount(0) {}
-  
-    void TakeFrom(gfxSkipChars* aSkipChars) {
-        mList = aSkipChars->mList.forget();
-        mListLength = aSkipChars->mListLength;
+    void KeepChar()
+    {
+        KeepChars(1);
+    }
+
+    void TakeFrom(gfxSkipChars* aSkipChars)
+    {
+        mRanges.SwapElements(aSkipChars->mRanges);
         mCharCount = aSkipChars->mCharCount;
         aSkipChars->mCharCount = 0;
-        aSkipChars->mListLength = 0;
-        BuildShortcuts();
+    }
+
+    int32_t GetOriginalCharCount() const
+    {
+        return mCharCount;
     }
-  
-    void TakeFrom(gfxSkipCharsBuilder* aSkipCharsBuilder) {
-        if (!aSkipCharsBuilder->mBuffer.Length()) {
-            NS_ASSERTION(!aSkipCharsBuilder->mRunSkipped, "out of sync");
-            // all characters kept
-            mCharCount = aSkipCharsBuilder->mRunCharCount;
-            mList = nullptr;
-            mListLength = 0;
-        } else {
-            aSkipCharsBuilder->FlushRun();
-            mCharCount = aSkipCharsBuilder->mCharCount;
-            mList = new uint8_t[aSkipCharsBuilder->mBuffer.Length()];
-            if (!mList) {
-                mListLength = 0;
-            } else {
-                mListLength = aSkipCharsBuilder->mBuffer.Length();
-                memcpy(mList, aSkipCharsBuilder->mBuffer.Elements(), mListLength);
-            }
-        }
-        aSkipCharsBuilder->mBuffer.Clear();
-        aSkipCharsBuilder->mCharCount = 0;
-        aSkipCharsBuilder->mRunCharCount = 0;    
-        aSkipCharsBuilder->mRunSkipped = false;
-        BuildShortcuts();
+
+    const SkippedRange& LastRange() const
+    {
+        // this is only valid if mRanges is non-empty; no assertion here
+        // because nsTArray will already assert if we abuse it
+        return mRanges[mRanges.Length() - 1];
     }
-  
-    void SetAllKeep(uint32_t aLength) {
-        mCharCount = aLength;
-        mList = nullptr;
-        mListLength = 0;
-    }
-  
-    int32_t GetOriginalCharCount() const { return mCharCount; }
 
     friend class gfxSkipCharsIterator;
 
 private:
-    struct Shortcut {
-        uint32_t mListPrefixLength;
-        uint32_t mListPrefixCharCount;
-        uint32_t mListPrefixKeepCharCount;
-    
-        Shortcut() {}
-        Shortcut(uint32_t aListPrefixLength, uint32_t aListPrefixCharCount,
-                 uint32_t aListPrefixKeepCharCount) :
-            mListPrefixLength(aListPrefixLength),
-            mListPrefixCharCount(aListPrefixCharCount),
-            mListPrefixKeepCharCount(aListPrefixKeepCharCount) {}
-    };
-  
-    void BuildShortcuts();
-
-    nsAutoArrayPtr<uint8_t>  mList;
-    nsAutoArrayPtr<Shortcut> mShortcuts;
-    uint32_t                 mListLength;
-    uint32_t                 mCharCount;
+    nsTArray<SkippedRange> mRanges;
+    uint32_t               mCharCount;
 };
 
 /**
  * A gfxSkipCharsIterator represents a position in the original string. It lets you
  * map efficiently to and from positions in the string after skipped characters
  * have been removed. You can also specify an offset that is added to all
  * incoming original string offsets and subtracted from all outgoing original
  * string offsets --- useful when the gfxSkipChars corresponds to something
  * offset from the original DOM coordinates, which it often does for gfxTextRuns.
- * 
+ *
  * The current positions (in both the original and skipped strings) are
  * always constrained to be >= 0 and <= the string length. When the position
  * is equal to the string length, it is at the end of the string. The current
  * positions do not include any aOriginalStringToSkipCharsOffset.
- * 
+ *
  * When the position in the original string corresponds to a skipped character,
  * the skipped-characters offset is the offset of the next unskipped character,
  * or the skipped-characters string length if there is no next unskipped character.
  */
-class gfxSkipCharsIterator {
+class gfxSkipCharsIterator
+{
 public:
     /**
      * @param aOriginalStringToSkipCharsOffset add this to all incoming and
      * outgoing original string offsets
      */
     gfxSkipCharsIterator(const gfxSkipChars& aSkipChars,
                          int32_t aOriginalStringToSkipCharsOffset,
                          int32_t aOriginalStringOffset)
         : mSkipChars(&aSkipChars),
-          mOriginalStringToSkipCharsOffset(aOriginalStringToSkipCharsOffset),
-          mListPrefixLength(0), mListPrefixCharCount(0), mListPrefixKeepCharCount(0) {
+          mOriginalStringOffset(0),
+          mSkippedStringOffset(0),
+          mCurrentRangeIndex(-1),
+          mOriginalStringToSkipCharsOffset(aOriginalStringToSkipCharsOffset)
+    {
           SetOriginalOffset(aOriginalStringOffset);
     }
 
     gfxSkipCharsIterator(const gfxSkipChars& aSkipChars,
                          int32_t aOriginalStringToSkipCharsOffset = 0)
         : mSkipChars(&aSkipChars),
-          mOriginalStringOffset(0), mSkippedStringOffset(0),
-          mOriginalStringToSkipCharsOffset(aOriginalStringToSkipCharsOffset),
-          mListPrefixLength(0), mListPrefixCharCount(0), mListPrefixKeepCharCount(0) {
-    }
+          mOriginalStringOffset(0),
+          mSkippedStringOffset(0),
+          mCurrentRangeIndex(-1),
+          mOriginalStringToSkipCharsOffset(aOriginalStringToSkipCharsOffset)
+    { }
 
     gfxSkipCharsIterator(const gfxSkipCharsIterator& aIterator)
         : mSkipChars(aIterator.mSkipChars),
           mOriginalStringOffset(aIterator.mOriginalStringOffset),
           mSkippedStringOffset(aIterator.mSkippedStringOffset),
-          mOriginalStringToSkipCharsOffset(aIterator.mOriginalStringToSkipCharsOffset),
-          mListPrefixLength(aIterator.mListPrefixLength),
-          mListPrefixCharCount(aIterator.mListPrefixCharCount),
-          mListPrefixKeepCharCount(aIterator.mListPrefixKeepCharCount)
-    {}
-  
+          mCurrentRangeIndex(aIterator.mCurrentRangeIndex),
+          mOriginalStringToSkipCharsOffset(aIterator.mOriginalStringToSkipCharsOffset)
+    { }
+
     /**
      * The empty constructor creates an object that is useless until it is assigned.
      */
-    gfxSkipCharsIterator() : mSkipChars(nullptr) {}
+    gfxSkipCharsIterator()
+        : mSkipChars(nullptr)
+    { }
 
     /**
      * Return true if this iterator is properly initialized and usable.
-     */  
-    bool IsInitialized() { return mSkipChars != nullptr; }
+     */
+    bool IsInitialized()
+    {
+        return mSkipChars != nullptr;
+    }
 
     /**
      * Set the iterator to aOriginalStringOffset in the original string.
      * This can efficiently move forward or backward from the current position.
      * aOriginalStringOffset is clamped to [0,originalStringLength].
      */
-    void SetOriginalOffset(int32_t aOriginalStringOffset) {
-        SetOffsets(aOriginalStringOffset + mOriginalStringToSkipCharsOffset, true);
-    }
-    
+    void SetOriginalOffset(int32_t aOriginalStringOffset);
+
     /**
      * Set the iterator to aSkippedStringOffset in the skipped string.
      * This can efficiently move forward or backward from the current position.
      * aSkippedStringOffset is clamped to [0,skippedStringLength].
      */
-    void SetSkippedOffset(uint32_t aSkippedStringOffset) {
-        SetOffsets(aSkippedStringOffset, false);
-    }
-    
-    uint32_t ConvertOriginalToSkipped(int32_t aOriginalStringOffset) {
+    void SetSkippedOffset(uint32_t aSkippedStringOffset);
+
+    uint32_t ConvertOriginalToSkipped(int32_t aOriginalStringOffset)
+    {
         SetOriginalOffset(aOriginalStringOffset);
         return GetSkippedOffset();
     }
-    uint32_t ConvertSkippedToOriginal(int32_t aSkippedStringOffset) {
+
+    uint32_t ConvertSkippedToOriginal(int32_t aSkippedStringOffset)
+    {
         SetSkippedOffset(aSkippedStringOffset);
         return GetOriginalOffset();
     }
-  
+
     /**
      * Test if the character at the current position in the original string
      * is skipped or not. If aRunLength is non-null, then *aRunLength is set
      * to a number of characters all of which are either skipped or not, starting
      * at this character. When the current position is at the end of the original
      * string, we return true and *aRunLength is set to zero.
      */
     bool IsOriginalCharSkipped(int32_t* aRunLength = nullptr) const;
-    
-    void AdvanceOriginal(int32_t aDelta) {
-        SetOffsets(mOriginalStringOffset + aDelta, true);
+
+    void AdvanceOriginal(int32_t aDelta)
+    {
+        SetOriginalOffset(GetOriginalOffset() + aDelta);
     }
-    void AdvanceSkipped(int32_t aDelta) {
-        SetOffsets(mSkippedStringOffset + aDelta, false);
+
+    void AdvanceSkipped(int32_t aDelta)
+    {
+        SetSkippedOffset(GetSkippedOffset() + aDelta);
     }
-  
+
     /**
      * @return the offset within the original string
      */
-    int32_t GetOriginalOffset() const {
+    int32_t GetOriginalOffset() const
+    {
         return mOriginalStringOffset - mOriginalStringToSkipCharsOffset;
     }
+
     /**
      * @return the offset within the skipped string corresponding to the
      * current position in the original string. If the current position
      * in the original string is a character that is skipped, then we return
      * the position corresponding to the first non-skipped character in the
      * original string after the current position, or the length of the skipped
      * string if there is no such character.
      */
-    uint32_t GetSkippedOffset() const { return mSkippedStringOffset; }
+    uint32_t GetSkippedOffset() const
+    {
+        return mSkippedStringOffset;
+    }
 
-    int32_t GetOriginalEnd() const {
+    int32_t GetOriginalEnd() const
+    {
         return mSkipChars->GetOriginalCharCount() -
             mOriginalStringToSkipCharsOffset;
     }
 
 private:
-    void SetOffsets(uint32_t aOffset, bool aInOriginalString);
-  
     const gfxSkipChars* mSkipChars;
+
+    // Current position
     int32_t mOriginalStringOffset;
     uint32_t mSkippedStringOffset;
 
+    // Index of the last skippedRange that precedes or contains the current
+    // position in the original string.
+    // If index == -1 then we are before the first skipped char.
+    int32_t mCurrentRangeIndex;
+
     // This offset is added to map from "skipped+unskipped characters in
     // the original DOM string" character space to "skipped+unskipped
     // characters in the textrun's gfxSkipChars" character space
     int32_t mOriginalStringToSkipCharsOffset;
-
-    /*
-     * This is used to speed up cursor-style traversal. The invariant is that
-     * the first mListPrefixLength bytes of mSkipChars.mList sum to
-     * mListPrefixCharCount, and the even-indexed bytes in that prefix sum to
-     * mListPrefixKeepCharCount.
-     * Also, 0 <= mListPrefixLength < mSkipChars.mListLength, or else
-     * mSkipChars.mListLength is zero.
-     * Also, mListPrefixCharCount <= mOriginalStringOffset (and therefore
-     * mListPrefixKeepCharCount < mSkippedStringOffset).
-     */
-    uint32_t mListPrefixLength;
-    uint32_t mListPrefixCharCount;
-    uint32_t mListPrefixKeepCharCount;
 };
 
 #endif /*GFX_SKIP_CHARS_H*/
deleted file mode 100644
--- a/intl/uconv/util/ubase.h
+++ /dev/null
@@ -1,14 +0,0 @@
-/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-#ifndef ubase_h__
-#define ubase_h__
-
-#include "prtypes.h"
-#include <stdint.h>
-
-#define PRIVATE 
-#define MODULE_PRIVATE
-
-#endif
--- a/intl/uconv/util/ugen.c
+++ b/intl/uconv/util/ugen.c
@@ -1,176 +1,176 @@
 /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 #include "unicpriv.h"
 /*=================================================================================
 
 =================================================================================*/
-typedef  PRBool (*uSubGeneratorFunc) (uint16_t in, unsigned char* out);
+typedef  int (*uSubGeneratorFunc) (uint16_t in, unsigned char* out);
 /*=================================================================================
 
 =================================================================================*/
 
-typedef PRBool (*uGeneratorFunc) (
-                                  int32_t*    state,
-                                  uint16_t    in,
-                                  unsigned char*  out,
-                                  uint32_t     outbuflen,
-                                  uint32_t*    outlen
-                                  );
+typedef int (*uGeneratorFunc) (
+                               int32_t*    state,
+                               uint16_t    in,
+                               unsigned char*  out,
+                               uint32_t     outbuflen,
+                               uint32_t*    outlen
+                               );
 
-MODULE_PRIVATE PRBool uGenerate(  
-                                uScanClassID scanClass,
-                                int32_t*    state,
-                                uint16_t    in,
-                                unsigned char*  out,
-                                uint32_t     outbuflen,
-                                uint32_t*    outlen
-                                );
+int uGenerate(
+              uScanClassID scanClass,
+              int32_t*    state,
+              uint16_t    in,
+              unsigned char*  out,
+              uint32_t     outbuflen,
+              uint32_t*    outlen
+              );
 
 #define uSubGenerator(sub,in,out) (* m_subgenerator[sub])((in),(out))
 
-PRIVATE PRBool uCheckAndGenAlways1Byte(
-                                       int32_t*   state,
-                                       uint16_t   in,
-                                       unsigned char* out,
-                                       uint32_t    outbuflen,
-                                       uint32_t*   outlen
-                                       );
-PRIVATE PRBool uCheckAndGenAlways2Byte(
-                                       int32_t*   state,
-                                       uint16_t   in,
-                                       unsigned char* out,
-                                       uint32_t    outbuflen,
-                                       uint32_t*   outlen
-                                       );
-PRIVATE PRBool uCheckAndGenAlways2ByteShiftGR(
-                                              int32_t*    state,
-                                              uint16_t    in,
-                                              unsigned char*  out,
-                                              uint32_t     outbuflen,
-                                              uint32_t*    outlen
-                                              );
-MODULE_PRIVATE PRBool uGenerateShift(
-                                     uShiftOutTable   *shift,
-                                     int32_t*   state,
-                                     uint16_t   in,
-                                     unsigned char* out,
-                                     uint32_t    outbuflen,
-                                     uint32_t*   outlen
-                                     );
-PRIVATE PRBool uCheckAndGen2ByteGRPrefix8F(
-                                           int32_t*   state,
-                                           uint16_t   in,
-                                           unsigned char* out,
-                                           uint32_t    outbuflen,
-                                           uint32_t*   outlen
-                                           );
-PRIVATE PRBool uCheckAndGen2ByteGRPrefix8EA2(
-                                             int32_t*   state,
-                                             uint16_t   in,
-                                             unsigned char* out,
-                                             uint32_t    outbuflen,
-                                             uint32_t*   outlen
-                                             );
+int uCheckAndGenAlways1Byte(
+                               int32_t*   state,
+                               uint16_t   in,
+                               unsigned char* out,
+                               uint32_t    outbuflen,
+                               uint32_t*   outlen
+                               );
+int uCheckAndGenAlways2Byte(
+                            int32_t*   state,
+                            uint16_t   in,
+                            unsigned char* out,
+                            uint32_t    outbuflen,
+                            uint32_t*   outlen
+                            );
+int uCheckAndGenAlways2ByteShiftGR(
+                                   int32_t*    state,
+                                   uint16_t    in,
+                                   unsigned char*  out,
+                                   uint32_t     outbuflen,
+                                   uint32_t*    outlen
+                                   );
+int uGenerateShift(
+                   uShiftOutTable   *shift,
+                   int32_t*   state,
+                   uint16_t   in,
+                   unsigned char* out,
+                   uint32_t    outbuflen,
+                   uint32_t*   outlen
+                   );
+int uCheckAndGen2ByteGRPrefix8F(
+                                int32_t*   state,
+                                uint16_t   in,
+                                unsigned char* out,
+                                uint32_t    outbuflen,
+                                uint32_t*   outlen
+                                );
+int uCheckAndGen2ByteGRPrefix8EA2(
+                                  int32_t*   state,
+                                  uint16_t   in,
+                                  unsigned char* out,
+                                  uint32_t    outbuflen,
+                                  uint32_t*   outlen
+                                  );
 
-PRIVATE PRBool uCheckAndGen2ByteGRPrefix8EA3(
-                                             int32_t*   state,
-                                             uint16_t   in,
-                                             unsigned char* out,
-                                             uint32_t    outbuflen,
-                                             uint32_t*   outlen
-                                             );
+int uCheckAndGen2ByteGRPrefix8EA3(
+                                  int32_t*   state,
+                                  uint16_t   in,
+                                  unsigned char* out,
+                                  uint32_t    outbuflen,
+                                  uint32_t*   outlen
+                                  );
 
-PRIVATE PRBool uCheckAndGen2ByteGRPrefix8EA4(
-                                             int32_t*   state,
-                                             uint16_t   in,
-                                             unsigned char* out,
-                                             uint32_t    outbuflen,
-                                             uint32_t*   outlen
-                                             );
+int uCheckAndGen2ByteGRPrefix8EA4(
+                                  int32_t*   state,
+                                  uint16_t   in,
+                                  unsigned char* out,
+                                  uint32_t    outbuflen,
+                                  uint32_t*   outlen
+                                  );
 
-PRIVATE PRBool uCheckAndGen2ByteGRPrefix8EA5(
-                                             int32_t*   state,
-                                             uint16_t   in,
-                                             unsigned char* out,
-                                             uint32_t    outbuflen,
-                                             uint32_t*   outlen
-                                             );
+int uCheckAndGen2ByteGRPrefix8EA5(
+                                  int32_t*   state,
+                                  uint16_t   in,
+                                  unsigned char* out,
+                                  uint32_t    outbuflen,
+                                  uint32_t*   outlen
+                                  );
 
-PRIVATE PRBool uCheckAndGen2ByteGRPrefix8EA6(
-                                             int32_t*   state,
-                                             uint16_t   in,
-                                             unsigned char* out,
-                                             uint32_t    outbuflen,
-                                             uint32_t*   outlen
-                                             );
+int uCheckAndGen2ByteGRPrefix8EA6(
+                                  int32_t*   state,
+                                  uint16_t   in,
+                                  unsigned char* out,
+                                  uint32_t    outbuflen,
+                                  uint32_t*   outlen
+                                  );
 
-PRIVATE PRBool uCheckAndGen2ByteGRPrefix8EA7(
-                                             int32_t*   state,
-                                             uint16_t   in,
-                                             unsigned char* out,
-                                             uint32_t    outbuflen,
-                                             uint32_t*   outlen
-                                             );
-PRIVATE PRBool uCnGAlways8BytesDecomposedHangul(
-                                              int32_t*    state,
-                                              uint16_t    in,
-                                              unsigned char*  out,
-                                              uint32_t     outbuflen,
-                                              uint32_t*    outlen
-                                              );
+int uCheckAndGen2ByteGRPrefix8EA7(
+                                  int32_t*   state,
+                                  uint16_t   in,
+                                  unsigned char* out,
+                                  uint32_t    outbuflen,
+                                  uint32_t*   outlen
+                                  );
+int uCnGAlways8BytesDecomposedHangul(
+                                     int32_t*    state,
+                                     uint16_t    in,
+                                     unsigned char*  out,
+                                     uint32_t     outbuflen,
+                                     uint32_t*    outlen
+                                     );
 
-PRIVATE PRBool uCheckAndGenJohabHangul(
-                                       int32_t*   state,
-                                       uint16_t   in,
-                                       unsigned char* out,
-                                       uint32_t    outbuflen,
-                                       uint32_t*   outlen
-                                       );
+int uCheckAndGenJohabHangul(
+                            int32_t*   state,
+                            uint16_t   in,
+                            unsigned char* out,
+                            uint32_t    outbuflen,
+                            uint32_t*   outlen
+                            );
 
-PRIVATE PRBool uCheckAndGenJohabSymbol(
-                                       int32_t*   state,
-                                       uint16_t   in,
-                                       unsigned char* out,
-                                       uint32_t    outbuflen,
-                                       uint32_t*   outlen
-                                       );
+int uCheckAndGenJohabSymbol(
+                            int32_t*   state,
+                            uint16_t   in,
+                            unsigned char* out,
+                            uint32_t    outbuflen,
+                            uint32_t*   outlen
+                            );
 
 
-PRIVATE PRBool uCheckAndGen4BytesGB18030(
-                                         int32_t*   state,
-                                         uint16_t   in,
-                                         unsigned char* out,
-                                         uint32_t    outbuflen,
-                                         uint32_t*   outlen
-                                         );
+int uCheckAndGen4BytesGB18030(
+                              int32_t*   state,
+                              uint16_t   in,
+                              unsigned char* out,
+                              uint32_t    outbuflen,
+                              uint32_t*   outlen
+                              );
 
-PRIVATE PRBool uGenAlways2Byte(
-                               uint16_t    in,
-                               unsigned char* out
-                               );
-PRIVATE PRBool uGenAlways2ByteShiftGR(
-                                      uint16_t     in,
-                                      unsigned char*  out
-                                      );
-PRIVATE PRBool uGenAlways1Byte(
-                               uint16_t    in,
-                               unsigned char* out
-                               );
-PRIVATE PRBool uGenAlways1BytePrefix8E(
-                                       uint16_t    in,
-                                       unsigned char* out
-                                       );
-                                   /*=================================================================================
-                                   
+int uGenAlways2Byte(
+                    uint16_t    in,
+                    unsigned char* out
+                    );
+int uGenAlways2ByteShiftGR(
+                           uint16_t     in,
+                           unsigned char*  out
+                           );
+int uGenAlways1Byte(
+                    uint16_t    in,
+                    unsigned char* out
+                    );
+int uGenAlways1BytePrefix8E(
+                            uint16_t    in,
+                            unsigned char* out
+                            );
+/*=================================================================================
+
 =================================================================================*/
-PRIVATE const uGeneratorFunc m_generator[uNumOfCharsetType] =
+const uGeneratorFunc m_generator[uNumOfCharsetType] =
 {
     uCheckAndGenAlways1Byte,
     uCheckAndGenAlways2Byte,
     uCheckAndGenAlways2ByteShiftGR,
     uCheckAndGen2ByteGRPrefix8F,
     uCheckAndGen2ByteGRPrefix8EA2,
     uCheckAndGen2ByteGRPrefix8EA3,
     uCheckAndGen2ByteGRPrefix8EA4,
@@ -183,378 +183,377 @@ PRIVATE const uGeneratorFunc m_generator
     uCheckAndGen4BytesGB18030,
     uCheckAndGenAlways2Byte   /* place-holder for GR128 */
 };
 
 /*=================================================================================
 
 =================================================================================*/
 
-PRIVATE const uSubGeneratorFunc m_subgenerator[uNumOfCharType] =
+const uSubGeneratorFunc m_subgenerator[uNumOfCharType] =
 {
     uGenAlways1Byte,
     uGenAlways2Byte,
     uGenAlways2ByteShiftGR,
     uGenAlways1BytePrefix8E
-        
 };
 /*=================================================================================
 
 =================================================================================*/
-MODULE_PRIVATE PRBool uGenerate(  
-                                uScanClassID scanClass,
-                                int32_t*    state,
-                                uint16_t    in,
-                                unsigned char*  out,
-                                uint32_t     outbuflen,
-                                uint32_t*    outlen
-                                )
+int uGenerate(
+              uScanClassID scanClass,
+              int32_t*    state,
+              uint16_t    in,
+              unsigned char*  out,
+              uint32_t     outbuflen,
+              uint32_t*    outlen
+              )
 {
     return (* m_generator[scanClass]) (state,in,out,outbuflen,outlen);
 }
 /*=================================================================================
 
 =================================================================================*/
-PRIVATE PRBool uGenAlways1Byte(
-                               uint16_t    in,
-                               unsigned char* out
-                               )
+int uGenAlways1Byte(
+                    uint16_t    in,
+                    unsigned char* out
+                    )
 {
     out[0] = (unsigned char)in;
-    return PR_TRUE;
+    return 1;
 }
 
 /*=================================================================================
 
 =================================================================================*/
-PRIVATE PRBool uGenAlways2Byte(
-                               uint16_t    in,
-                               unsigned char* out
-                               )
+int uGenAlways2Byte(
+                    uint16_t    in,
+                    unsigned char* out
+                    )
 {
     out[0] = (unsigned char)((in >> 8) & 0xff);
     out[1] = (unsigned char)(in & 0xff);
-    return PR_TRUE;
+    return 1;
 }
 /*=================================================================================
 
 =================================================================================*/
-PRIVATE PRBool uGenAlways2ByteShiftGR(
-                                      uint16_t     in,
-                                      unsigned char*  out
-                                      )
+int uGenAlways2ByteShiftGR(
+                           uint16_t     in,
+                           unsigned char*  out
+                           )
 {
     out[0] = (unsigned char)(((in >> 8) & 0xff) | 0x80);
     out[1] = (unsigned char)((in & 0xff) | 0x80);
-    return PR_TRUE;
+    return 1;
 }
 /*=================================================================================
 
 =================================================================================*/
-PRIVATE PRBool uGenAlways1BytePrefix8E(
-                                       uint16_t    in,
-                                       unsigned char* out
-                                       )
+int uGenAlways1BytePrefix8E(
+                            uint16_t    in,
+                            unsigned char* out
+                            )
 {
     out[0] = 0x8E;
     out[1] = (unsigned char)(in  & 0xff);
-    return PR_TRUE;
+    return 1;
 }
 /*=================================================================================
 
 =================================================================================*/
-PRIVATE PRBool uCheckAndGenAlways1Byte(
-                                       int32_t*   state,
-                                       uint16_t   in,
-                                       unsigned char* out,
-                                       uint32_t    outbuflen,
-                                       uint32_t*   outlen
-                                       )
+int uCheckAndGenAlways1Byte(
+                            int32_t*   state,
+                            uint16_t   in,
+                            unsigned char* out,
+                            uint32_t    outbuflen,
+                            uint32_t*   outlen
+                            )
 {
     /* Don't check inlen. The caller should ensure it is larger than 0 */
     /*  Oops, I don't agree. Code changed to check every time. [CATA] */
     if(outbuflen < 1)
-        return PR_FALSE;
+        return 0;
     else
     {
         *outlen = 1;
         out[0] = in & 0xff;
-        return PR_TRUE;
+        return 1;
     }
 }
 
 /*=================================================================================
 
 =================================================================================*/
-PRIVATE PRBool uCheckAndGenAlways2Byte(
-                                       int32_t*   state,
-                                       uint16_t   in,
-                                       unsigned char* out,
-                                       uint32_t    outbuflen,
-                                       uint32_t*   outlen
-                                       )
+int uCheckAndGenAlways2Byte(
+                            int32_t*   state,
+                            uint16_t   in,
+                            unsigned char* out,
+                            uint32_t    outbuflen,
+                            uint32_t*   outlen
+                            )
 {
     if(outbuflen < 2)
-        return PR_FALSE;
+        return 0;
     else
     {
         *outlen = 2;
         out[0] = ((in >> 8 ) & 0xff);
         out[1] = in  & 0xff;
-        return PR_TRUE;
+        return 1;
     }
 }
 /*=================================================================================
 
 =================================================================================*/
-PRIVATE PRBool uCheckAndGenAlways2ByteShiftGR(
-                                              int32_t*    state,
-                                              uint16_t    in,
-                                              unsigned char*  out,
-                                              uint32_t     outbuflen,
-                                              uint32_t*    outlen
-                                              )
+int uCheckAndGenAlways2ByteShiftGR(
+                                   int32_t*    state,
+                                   uint16_t    in,
+                                   unsigned char*  out,
+                                   uint32_t     outbuflen,
+                                   uint32_t*    outlen
+                                   )
 {
     if(outbuflen < 2)
-        return PR_FALSE;
+        return 0;
     else
     {
         *outlen = 2;
         out[0] = ((in >> 8 ) & 0xff) | 0x80;
         out[1] = (in  & 0xff)  | 0x80;
-        return PR_TRUE;
+        return 1;
     }
 }
 /*=================================================================================
 
 =================================================================================*/
-MODULE_PRIVATE PRBool uGenerateShift(
-                                   uShiftOutTable   *shift,
-                                   int32_t*   state,
-                                   uint16_t   in,
-                                   unsigned char* out,
-                                   uint32_t    outbuflen,
-                                   uint32_t*   outlen
-                                   )
+int uGenerateShift(
+                   uShiftOutTable   *shift,
+                   int32_t*   state,
+                   uint16_t   in,
+                   unsigned char* out,
+                   uint32_t    outbuflen,
+                   uint32_t*   outlen
+                   )
 {
     int16_t i;
     const uShiftOutCell* cell = &(shift->shiftcell[0]);
     int16_t itemnum = shift->numOfItem;
     unsigned char inH, inL;
     inH = (in >> 8) & 0xff;
     inL = (in & 0xff );
     for(i=0;i<itemnum;i++)
     {
         if( ( inL >=  cell[i].shiftout_MinLB) &&
             ( inL <=  cell[i].shiftout_MaxLB) &&
             ( inH >=  cell[i].shiftout_MinHB) &&
             ( inH <=  cell[i].shiftout_MaxHB) )
         {
             if(outbuflen < cell[i].reserveLen)
               {
-                return PR_FALSE;
+                return 0;
               }
             else
             {
                 *outlen = cell[i].reserveLen;
                 return (uSubGenerator(cell[i].classID,in,out));
             }
         }
     }
-    return PR_FALSE;
+    return 0;
 }
 /*=================================================================================
 
 =================================================================================*/
-PRIVATE PRBool uCheckAndGen2ByteGRPrefix8F( int32_t*   state,
-                                           uint16_t   in,
-                                           unsigned char* out,
-                                           uint32_t    outbuflen,
-                                           uint32_t*   outlen
-                                           )
+int uCheckAndGen2ByteGRPrefix8F(int32_t*   state,
+                                uint16_t   in,
+                                unsigned char* out,
+                                uint32_t    outbuflen,
+                                uint32_t*   outlen
+                                )
 {
     if(outbuflen < 3)
-        return PR_FALSE;
+        return 0;
     else
     {
         *outlen = 3;
         out[0] = 0x8F;
         out[1] = ((in >> 8 ) & 0xff) | 0x80;
         out[2] = (in  & 0xff)  | 0x80;
-        return PR_TRUE;
+        return 1;
     }
 }
 /*=================================================================================
 
 =================================================================================*/
-PRIVATE PRBool uCheckAndGen2ByteGRPrefix8EA2( int32_t*   state,
-                                             uint16_t   in,
-                                             unsigned char* out,
-                                             uint32_t    outbuflen,
-                                             uint32_t*   outlen
-                                             )
+int uCheckAndGen2ByteGRPrefix8EA2(int32_t*   state,
+                                  uint16_t   in,
+                                  unsigned char* out,
+                                  uint32_t    outbuflen,
+                                  uint32_t*   outlen
+                                  )
 {
     if(outbuflen < 4)
-        return PR_FALSE;
+        return 0;
     else
     {
         *outlen = 4;
         out[0] = 0x8E;
         out[1] = 0xA2;
         out[2] = ((in >> 8 ) & 0xff) | 0x80;
         out[3] = (in  & 0xff)  | 0x80;
-        return PR_TRUE;
+        return 1;
     }
 }
 
 
 /*=================================================================================
 
 =================================================================================*/
-PRIVATE PRBool uCheckAndGen2ByteGRPrefix8EA3( int32_t*   state,
-                                             uint16_t   in,
-                                             unsigned char* out,
-                                             uint32_t    outbuflen,
-                                             uint32_t*   outlen
-                                             )
+int uCheckAndGen2ByteGRPrefix8EA3(int32_t*   state,
+                                  uint16_t   in,
+                                  unsigned char* out,
+                                  uint32_t    outbuflen,
+                                  uint32_t*   outlen
+                                  )
 {
     if(outbuflen < 4)
-        return PR_FALSE;
+        return 0;
     else
     {
         *outlen = 4;
         out[0] = 0x8E;
         out[1] = 0xA3;
         out[2] = ((in >> 8 ) & 0xff) | 0x80;
         out[3] = (in  & 0xff)  | 0x80;
-        return PR_TRUE;
+        return 1;
     }
 }
 /*=================================================================================
 
 =================================================================================*/
-PRIVATE PRBool uCheckAndGen2ByteGRPrefix8EA4( int32_t*   state,
-                                             uint16_t   in,
-                                             unsigned char* out,
-                                             uint32_t    outbuflen,
-                                             uint32_t*   outlen
-                                             )
+int uCheckAndGen2ByteGRPrefix8EA4(int32_t*   state,
+                                  uint16_t   in,
+                                  unsigned char* out,
+                                  uint32_t    outbuflen,
+                                  uint32_t*   outlen
+                                  )
 {
     if(outbuflen < 4)
-        return PR_FALSE;
+        return 0;
     else
     {
         *outlen = 4;
         out[0] = 0x8E;
         out[1] = 0xA4;
         out[2] = ((in >> 8 ) & 0xff) | 0x80;
         out[3] = (in  & 0xff)  | 0x80;
-        return PR_TRUE;
+        return 1;
     }
 }
 /*=================================================================================
 
 =================================================================================*/
-PRIVATE PRBool uCheckAndGen2ByteGRPrefix8EA5( int32_t*   state,
-                                             uint16_t   in,
-                                             unsigned char* out,
-                                             uint32_t    outbuflen,
-                                             uint32_t*   outlen
-                                             )
+int uCheckAndGen2ByteGRPrefix8EA5(int32_t*   state,
+                                  uint16_t   in,
+                                  unsigned char* out,
+                                  uint32_t    outbuflen,
+                                  uint32_t*   outlen
+                                  )
 {
     if(outbuflen < 4)
-        return PR_FALSE;
+        return 0;
     else
     {
         *outlen = 4;
         out[0] = 0x8E;
         out[1] = 0xA5;
         out[2] = ((in >> 8 ) & 0xff) | 0x80;
         out[3] = (in  & 0xff)  | 0x80;
-        return PR_TRUE;
+        return 1;
     }
 }
 /*=================================================================================
 
 =================================================================================*/
-PRIVATE PRBool uCheckAndGen2ByteGRPrefix8EA6( int32_t*   state,
-                                             uint16_t   in,
-                                             unsigned char* out,
-                                             uint32_t    outbuflen,
-                                             uint32_t*   outlen
-                                             )
+int uCheckAndGen2ByteGRPrefix8EA6(int32_t*   state,
+                                  uint16_t   in,
+                                  unsigned char* out,
+                                  uint32_t    outbuflen,
+                                  uint32_t*   outlen
+                                  )
 {
     if(outbuflen < 4)
-        return PR_FALSE;
+        return 0;
     else
     {
         *outlen = 4;
         out[0] = 0x8E;
         out[1] = 0xA6;
         out[2] = ((in >> 8 ) & 0xff) | 0x80;
         out[3] = (in  & 0xff)  | 0x80;
-        return PR_TRUE;
+        return 1;
     }
 }
 /*=================================================================================
 
 =================================================================================*/
-PRIVATE PRBool uCheckAndGen2ByteGRPrefix8EA7( int32_t*   state,
-                                             uint16_t   in,
-                                             unsigned char* out,
-                                             uint32_t    outbuflen,
-                                             uint32_t*   outlen
-                                             )
+int uCheckAndGen2ByteGRPrefix8EA7(int32_t*   state,
+                                  uint16_t   in,
+                                  unsigned char* out,
+                                  uint32_t    outbuflen,
+                                  uint32_t*   outlen
+                                  )
 {
     if(outbuflen < 4)
-        return PR_FALSE;
+        return 0;
     else
     {
         *outlen = 4;
         out[0] = 0x8E;
         out[1] = 0xA7;
         out[2] = ((in >> 8 ) & 0xff) | 0x80;
         out[3] = (in  & 0xff)  | 0x80;
-        return PR_TRUE;
+        return 1;
     }
 }
 /*=================================================================================
 
 =================================================================================*/
 #define SBase 0xAC00
 #define LCount 19
 #define VCount 21
 #define TCount 28
 #define NCount (VCount * TCount)
 /*=================================================================================
 
 =================================================================================*/
-PRIVATE PRBool uCnGAlways8BytesDecomposedHangul(
-                                              int32_t*    state,
-                                              uint16_t    in,
-                                              unsigned char*  out,
-                                              uint32_t     outbuflen,
-                                              uint32_t*    outlen
-                                              )
+int uCnGAlways8BytesDecomposedHangul(
+                                     int32_t*    state,
+                                     uint16_t    in,
+                                     unsigned char*  out,
+                                     uint32_t     outbuflen,
+                                     uint32_t*    outlen
+                                     )
 {
     static const uint8_t lMap[LCount] = {
         0xa1, 0xa2, 0xa4, 0xa7, 0xa8, 0xa9, 0xb1, 0xb2, 0xb3, 0xb5,
             0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe
     };
     
     static const uint8_t tMap[TCount] = {
         0xd4, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa9, 0xaa, 
             0xab, 0xac, 0xad, 0xae, 0xaf, 0xb0, 0xb1, 0xb2, 0xb4, 0xb5, 
             0xb6, 0xb7, 0xb8, 0xba, 0xbb, 0xbc, 0xbd, 0xbe
     };
 
     uint16_t SIndex, LIndex, VIndex, TIndex;
 
     if(outbuflen < 8)
-        return PR_FALSE;
+        return 0;
 
     /* the following line are copy from Unicode 2.0 page 3-13 */
     /* item 1 of Hangul Syllabel Decomposition */
     SIndex =  in - SBase;
     
     /* the following lines are copy from Unicode 2.0 page 3-14 */
     /* item 2 of Hangul Syllabel Decomposition w/ modification */
     LIndex = SIndex / NCount;
@@ -570,29 +569,29 @@ PRIVATE PRBool uCnGAlways8BytesDecompose
      */
     *outlen = 8;
     out[0] = out[2] = out[4] = out[6] = 0xa4;
     out[1] = 0xd4;
     out[3] = lMap[LIndex] ;
     out[5] = (VIndex + 0xbf);
     out[7] = tMap[TIndex];
 
-    return PR_TRUE;
+    return 1;
 }
 
-PRIVATE PRBool uCheckAndGenJohabHangul(
-                                       int32_t*   state,
-                                       uint16_t   in,
-                                       unsigned char* out,
-                                       uint32_t    outbuflen,
-                                       uint32_t*   outlen
-                                       )
+int uCheckAndGenJohabHangul(
+                            int32_t*   state,
+                            uint16_t   in,
+                            unsigned char* out,
+                            uint32_t    outbuflen,
+                            uint32_t*   outlen
+                            )
 {
     if(outbuflen < 2)
-        return PR_FALSE;
+        return 0;
     else
     {
     /*
     See Table 4-45 (page 183) of CJKV Information Processing
     for detail explanation of the following table.
         */
         /*
         static const uint8_t lMap[LCount] = {
@@ -628,29 +627,29 @@ PRIVATE PRBool uCheckAndGenJohabHangul(
             ((LIndex+2)<<10) | 
             (vMap[VIndex]<<5)| 
             tMap[TIndex];
         out[0] = (ch >> 8);
         out[1] = ch & 0x00FF;
 #if 0
         printf("Johab Hangul %x %x in=%x L=%d V=%d T=%d\n", out[0], out[1], in, LIndex, VIndex, TIndex); 
 #endif 
-        return PR_TRUE;
+        return 1;
     }
 }
-PRIVATE PRBool uCheckAndGenJohabSymbol(
-                                       int32_t*   state,
-                                       uint16_t   in,
-                                       unsigned char* out,
-                                       uint32_t    outbuflen,
-                                       uint32_t*   outlen
-                                       )
+int uCheckAndGenJohabSymbol(
+                            int32_t*   state,
+                            uint16_t   in,
+                            unsigned char* out,
+                            uint32_t    outbuflen,
+                            uint32_t*   outlen
+                            )
 {
     if(outbuflen < 2)
-        return PR_FALSE;
+        return 0;
     else
     {
     /* The following code are based on the Perl code listed under
     * "ISO-2022-KR or EUC-KR to Johab Conversion" (page 1013)
     * in the book "CJKV Information Processing" by 
     * Ken Lunde <lunde@adobe.com>
     *
     * sub convert2johab($) { # Convert ISO-2022-KR or EUC-KR to Johab
@@ -684,30 +683,30 @@ PRIVATE PRBool uCheckAndGenJohabSymbol(
         }
         *outlen = 2;
         out[0] =  ((hi+hi_off) >> 1) + ((hi<74) ? 200 : 187 ) - fe_off;
         out[1] =  lo + (((hi+lo_off) & 1) ? ((lo > 110) ? 34 : 16) : 
         128);
 #if 0
         printf("Johab Symbol %x %x in=%x\n", out[0], out[1], in); 
 #endif
-        return PR_TRUE;
+        return 1;
     }
 }
-PRIVATE PRBool uCheckAndGen4BytesGB18030(
-                                         int32_t*   state,
-                                         uint16_t   in,
-                                         unsigned char* out,
-                                         uint32_t    outbuflen,
-                                         uint32_t*   outlen
-                                         )
+int uCheckAndGen4BytesGB18030(
+                              int32_t*   state,
+                              uint16_t   in,
+                              unsigned char* out,
+                              uint32_t    outbuflen,
+                              uint32_t*   outlen
+                              )
 {
     if(outbuflen < 4)
-        return PR_FALSE;
+        return 0;
     out[0] = (in / (10*126*10)) + 0x81;
     in %= (10*126*10);
     out[1] = (in / (10*126)) + 0x30;
     in %= (10*126);
     out[2] = (in / (10)) + 0x81;
     out[3] = (in % 10) + 0x30;
     *outlen = 4;
-    return PR_TRUE;
+    return 1;
 }
--- a/intl/uconv/util/umap.c
+++ b/intl/uconv/util/umap.c
@@ -2,140 +2,140 @@
 /* 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 "PRIntlpriv.h" */
 #include "unicpriv.h" 
 
 
 typedef uint16_t (* MapFormatFunc)(uint16_t in,const uTable *uT,const uMapCell *cell);
-typedef PRBool (* HitFormateFunc)(uint16_t in,const uMapCell *cell);
+typedef int (* HitFormateFunc)(uint16_t in,const uMapCell *cell);
 typedef void (* FillInfoFormateFunc)(const uTable *uT, const uMapCell *cell, uint32_t* info);
 
 
-PRIVATE PRBool uHitFormate0(uint16_t in,const uMapCell *cell);
-PRIVATE PRBool uHitFormate2(uint16_t in,const uMapCell *cell);
-PRIVATE uint16_t uMapFormate0(uint16_t in,const uTable *uT,const uMapCell *cell);
-PRIVATE uint16_t uMapFormate1(uint16_t in,const uTable *uT,const uMapCell *cell);
-PRIVATE uint16_t uMapFormate2(uint16_t in,const uTable *uT,const uMapCell *cell);
-PRIVATE void uFillInfoFormate0(const uTable *uT,const uMapCell *cell,uint32_t* aInfo);
-PRIVATE void uFillInfoFormate1(const uTable *uT,const uMapCell *cell,uint32_t* aInfo);
-PRIVATE void uFillInfoFormate2(const uTable *uT,const uMapCell *cell,uint32_t* aInfo);
+int uHitFormate0(uint16_t in,const uMapCell *cell);
+int uHitFormate2(uint16_t in,const uMapCell *cell);
+uint16_t uMapFormate0(uint16_t in,const uTable *uT,const uMapCell *cell);
+uint16_t uMapFormate1(uint16_t in,const uTable *uT,const uMapCell *cell);
+uint16_t uMapFormate2(uint16_t in,const uTable *uT,const uMapCell *cell);
+void uFillInfoFormate0(const uTable *uT,const uMapCell *cell,uint32_t* aInfo);
+void uFillInfoFormate1(const uTable *uT,const uMapCell *cell,uint32_t* aInfo);
+void uFillInfoFormate2(const uTable *uT,const uMapCell *cell,uint32_t* aInfo);
 
 
-PRIVATE const uMapCell *uGetMapCell(const uTable *uT, int16_t item);
-PRIVATE char uGetFormat(const uTable *uT, int16_t item);
+const uMapCell *uGetMapCell(const uTable *uT, int16_t item);
+char uGetFormat(const uTable *uT, int16_t item);
 
 
 /*=================================================================================
 
 =================================================================================*/
-PRIVATE const MapFormatFunc m_map[uNumFormatTag] =
+const MapFormatFunc m_map[uNumFormatTag] =
 {
     uMapFormate0,
     uMapFormate1,
     uMapFormate2,
 };
 
 /*=================================================================================
 
 =================================================================================*/
-PRIVATE const FillInfoFormateFunc m_fillinfo[uNumFormatTag] =
+const FillInfoFormateFunc m_fillinfo[uNumFormatTag] =
 {
     uFillInfoFormate0,
     uFillInfoFormate1,
     uFillInfoFormate2,
 };
 
 /*=================================================================================
 
 =================================================================================*/
-PRIVATE const HitFormateFunc m_hit[uNumFormatTag] =
+const HitFormateFunc m_hit[uNumFormatTag] =
 {
     uHitFormate0,
     uHitFormate0,
     uHitFormate2,
 };
 
 #define uHit(format,in,cell)   (* m_hit[(format)])((in),(cell))
 #define uMap(format,in,uT,cell)  (* m_map[(format)])((in),(uT),(cell))
 #define uGetMapCell(uT, item) ((uMapCell *)(((uint16_t *)uT) + (uT)->offsetToMapCellArray + (item)*(UMAPCELL_SIZE/sizeof(uint16_t))))
 #define uGetFormat(uT, item) (((((uint16_t *)uT) + (uT)->offsetToFormatArray)[(item)>> 2 ] >> (((item)% 4 ) << 2)) & 0x0f)
 
 /*=================================================================================
 
 =================================================================================*/
-MODULE_PRIVATE PRBool uMapCode(const uTable *uT, uint16_t in, uint16_t* out)
+int uMapCode(const uTable *uT, uint16_t in, uint16_t* out)
 {
-  PRBool done = PR_FALSE;
+  int done = 0;
   uint16_t itemOfList = uT->itemOfList;
   uint16_t i;
   *out = NOMAPPING;
   for(i=0;i<itemOfList;i++)
   {
     const uMapCell* uCell;
     int8_t format = uGetFormat(uT,i);
     uCell = uGetMapCell(uT,i);
     if(uHit(format, in, uCell))
     {
       *out = uMap(format, in, uT,uCell);
-      done = PR_TRUE;
+      done = 1;
       break;
     }
   }
   return ( done && (*out != NOMAPPING));
 }
 
 
 /*
 member function
 */
 /*=================================================================================
 
 =================================================================================*/
-PRIVATE PRBool uHitFormate0(uint16_t in,const uMapCell *cell)
+int uHitFormate0(uint16_t in,const uMapCell *cell)
 {
   return ( (in >= cell->fmt.format0.srcBegin) &&
     (in <= cell->fmt.format0.srcEnd) ) ;
 }
 /*=================================================================================
 
 =================================================================================*/
-PRIVATE PRBool uHitFormate2(uint16_t in,const uMapCell *cell)
+int uHitFormate2(uint16_t in,const uMapCell *cell)
 {
   return (in == cell->fmt.format2.srcBegin);
 }
 /*=================================================================================
 
 =================================================================================*/
-PRIVATE uint16_t uMapFormate0(uint16_t in,const uTable *uT,const uMapCell *cell)
+uint16_t uMapFormate0(uint16_t in,const uTable *uT,const uMapCell *cell)
 {
   return ((in - cell->fmt.format0.srcBegin) + cell->fmt.format0.destBegin);
 }
 /*=================================================================================
 
 =================================================================================*/
-PRIVATE uint16_t uMapFormate1(uint16_t in,const uTable *uT,const uMapCell *cell)
+uint16_t uMapFormate1(uint16_t in,const uTable *uT,const uMapCell *cell)
 {
   return (*(((uint16_t *)uT) + uT->offsetToMappingTable
     + cell->fmt.format1.mappingOffset + in - cell->fmt.format1.srcBegin));
 }
 /*=================================================================================
 
 =================================================================================*/
-PRIVATE uint16_t uMapFormate2(uint16_t in,const uTable *uT,const uMapCell *cell)
+uint16_t uMapFormate2(uint16_t in,const uTable *uT,const uMapCell *cell)
 {
   return (cell->fmt.format2.destBegin);
 }
 
 #define SET_REPRESENTABLE(info, c)  (info)[(c) >> 5] |= (1L << ((c) & 0x1f))
 /*=================================================================================
 
 =================================================================================*/
-PRIVATE void uFillInfoFormate0(const uTable *uT,const uMapCell *cell,uint32_t* info)
+void uFillInfoFormate0(const uTable *uT,const uMapCell *cell,uint32_t* info)
 {
   uint16_t begin, end, i;
   begin = cell->fmt.format0.srcBegin;
   end = cell->fmt.format0.srcEnd;
   if( (begin >> 5) == (end >> 5)) /* High 17 bits are the same */
   {
     for(i = begin; i <= end; i++)
       SET_REPRESENTABLE(info, i);
@@ -147,29 +147,29 @@ PRIVATE void uFillInfoFormate0(const uTa
     info[ e ] |= (0xFFFFFFFFL >> (31 - ((end) & 0x1f)));
     for(b++ ; b < e ; b++)
       info[b] |= 0xFFFFFFFFL;
   }
 }
 /*=================================================================================
 
 =================================================================================*/
-PRIVATE void uFillInfoFormate1(const uTable *uT,const uMapCell *cell,uint32_t* info)
+void uFillInfoFormate1(const uTable *uT,const uMapCell *cell,uint32_t* info)
 {
   uint16_t begin, end, i;
   uint16_t *base;
   begin = cell->fmt.format0.srcBegin;
   end = cell->fmt.format0.srcEnd;
   base = (((uint16_t *)uT) + uT->offsetToMappingTable + cell->fmt.format1.mappingOffset);
   for(i = begin; i <= end; i++) 
   {
     if(0xFFFD != base[i - begin])  /* check every item */
       SET_REPRESENTABLE(info, i);
   }
 }
 /*=================================================================================
 
 =================================================================================*/
-PRIVATE void uFillInfoFormate2(const uTable *uT,const uMapCell *cell,uint32_t* info)
+void uFillInfoFormate2(const uTable *uT,const uMapCell *cell,uint32_t* info)
 {
   SET_REPRESENTABLE(info, cell->fmt.format2.srcBegin);
 }
 
--- a/intl/uconv/util/unicpriv.h
+++ b/intl/uconv/util/unicpriv.h
@@ -1,52 +1,52 @@
 /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 #ifndef __UNIPRIV__
 #define __UNIPRIV__
 
-#include "ubase.h"
+#include <stdint.h>
 #include "umap.h"
 #include "uconvutil.h"
 
 #ifdef __cplusplus
 extern "C" {
 #endif
 
-PRBool	uMapCode(const uTable *uT, 
-                    uint16_t in, 
-                    uint16_t* out);
+int uMapCode(const uTable *uT,
+             uint16_t in,
+             uint16_t* out);
 
-PRBool 	uGenerate(uScanClassID scanClass,
-                  int32_t* state, 
-                  uint16_t in, 
-                  unsigned char* out, 
-                  uint32_t outbuflen, 
-                  uint32_t* outlen);
+int uGenerate(uScanClassID scanClass,
+              int32_t* state,
+              uint16_t in,
+              unsigned char* out,
+              uint32_t outbuflen,
+              uint32_t* outlen);
 
-PRBool 	uScan(uScanClassID scanClass,
-              int32_t *state, 
-              unsigned char *in,
-              uint16_t *out, 
-              uint32_t inbuflen, 
-              uint32_t* inscanlen);
+int uScan(uScanClassID scanClass,
+          int32_t *state,
+          unsigned char *in,
+          uint16_t *out,
+          uint32_t inbuflen,
+          uint32_t* inscanlen);
 
-PRBool 	uGenerateShift(uShiftOutTable *shift,
-                       int32_t* state, 
-                       uint16_t in, 
-                       unsigned char* out, 
-                       uint32_t outbuflen, 
-                       uint32_t* outlen);
+int uGenerateShift(uShiftOutTable *shift,
+                   int32_t* state,
+                   uint16_t in,
+                   unsigned char* out,
+                   uint32_t outbuflen,
+                   uint32_t* outlen);
 
-PRBool 	uScanShift(uShiftInTable *shift, 
-                   int32_t *state, 
-                   unsigned char *in,
-                   uint16_t *out, 
-                   uint32_t inbuflen, 
-                   uint32_t* inscanlen);
+int uScanShift(uShiftInTable *shift,
+               int32_t *state,
+               unsigned char *in,
+               uint16_t *out,
+               uint32_t inbuflen,
+               uint32_t* inscanlen);
 
 #ifdef __cplusplus
 }
 #endif
 
 #endif /* __UNIPRIV__ */
--- a/intl/uconv/util/uscan.c
+++ b/intl/uconv/util/uscan.c
@@ -3,176 +3,176 @@
  * 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 "unicpriv.h"
 #define CHK_GR94(b) ( (uint8_t) 0xa0 < (uint8_t) (b) && (uint8_t) (b) < (uint8_t) 0xff )
 #define CHK_GR94_2Byte(b1,b2) (CHK_GR94(b1) && CHK_GR94(b2))
 /*=================================================================================
 
 =================================================================================*/
-typedef  PRBool (*uSubScannerFunc) (unsigned char* in, uint16_t* out);
+typedef  int (*uSubScannerFunc) (unsigned char* in, uint16_t* out);
 /*=================================================================================
 
 =================================================================================*/
 
-typedef PRBool (*uScannerFunc) (
-                                int32_t*    state,
-                                unsigned char  *in,
-                                uint16_t    *out,
-                                uint32_t     inbuflen,
-                                uint32_t*    inscanlen
-                                );
+typedef int (*uScannerFunc) (
+                             int32_t*    state,
+                             unsigned char  *in,
+                             uint16_t    *out,
+                             uint32_t     inbuflen,
+                             uint32_t*    inscanlen
+                             );
 
-MODULE_PRIVATE PRBool uScan(  
-                            uScanClassID scanClass,
+int uScan(
+          uScanClassID scanClass,
+          int32_t*    state,
+          unsigned char  *in,
+          uint16_t    *out,
+          uint32_t     inbuflen,
+          uint32_t*    inscanlen
+          );
+
+#define uSubScanner(sub,in,out) (* m_subscanner[sub])((in),(out))
+
+int uCheckAndScanAlways1Byte(
                             int32_t*    state,
                             unsigned char  *in,
                             uint16_t    *out,
                             uint32_t     inbuflen,
                             uint32_t*    inscanlen
                             );
-
-#define uSubScanner(sub,in,out) (* m_subscanner[sub])((in),(out))
+int uCheckAndScanAlways2Byte(
+                             int32_t*    state,
+                             unsigned char  *in,
+                             uint16_t    *out,
+                             uint32_t     inbuflen,
+                             uint32_t*    inscanlen
+                             );
+int uCheckAndScanAlways2ByteShiftGR(
+                                    int32_t*    state,
+                                    unsigned char  *in,
+                                    uint16_t    *out,
+                                    uint32_t     inbuflen,
+                                    uint32_t*    inscanlen
+                                    );
+int uCheckAndScanAlways2ByteGR128(
+                                  int32_t*    state,
+                                  unsigned char  *in,
+                                  uint16_t    *out,
+                                  uint32_t     inbuflen,
+                                  uint32_t*    inscanlen
+                                          );
+int uScanShift(
+               uShiftInTable    *shift,
+               int32_t*    state,
+               unsigned char  *in,
+               uint16_t    *out,
+               uint32_t     inbuflen,
+               uint32_t*    inscanlen
+               );
 
-PRIVATE PRBool uCheckAndScanAlways1Byte(
-                                        int32_t*    state,
-                                        unsigned char  *in,
-                                        uint16_t    *out,
-                                        uint32_t     inbuflen,
-                                        uint32_t*    inscanlen
-                                        );
-PRIVATE PRBool uCheckAndScanAlways2Byte(
-                                        int32_t*    state,
-                                        unsigned char  *in,
-                                        uint16_t    *out,
-                                        uint32_t     inbuflen,
-                                        uint32_t*    inscanlen
-                                        );
-PRIVATE PRBool uCheckAndScanAlways2ByteShiftGR(
-                                               int32_t*    state,
-                                               unsigned char  *in,
-                                               uint16_t    *out,
-                                               uint32_t     inbuflen,
-                                               uint32_t*    inscanlen
-                                               );
-PRIVATE PRBool uCheckAndScanAlways2ByteGR128(
-                                               int32_t*    state,
-                                               unsigned char  *in,
-                                               uint16_t    *out,
-                                               uint32_t     inbuflen,
-                                               uint32_t*    inscanlen
-                                               );
-MODULE_PRIVATE PRBool uScanShift(  
-                                 uShiftInTable    *shift,
+int uCheckAndScan2ByteGRPrefix8F(
                                  int32_t*    state,
                                  unsigned char  *in,
                                  uint16_t    *out,
                                  uint32_t     inbuflen,
                                  uint32_t*    inscanlen
                                  );
+int uCheckAndScan2ByteGRPrefix8EA2(
+                                   int32_t*    state,
+                                   unsigned char  *in,
+                                   uint16_t    *out,
+                                   uint32_t     inbuflen,
+                                   uint32_t*    inscanlen
+                                   );
+int uCheckAndScan2ByteGRPrefix8EA3(
+                                   int32_t*    state,
+                                   unsigned char  *in,
+                                   uint16_t    *out,
+                                   uint32_t     inbuflen,
+                                   uint32_t*    inscanlen
+                                   );
+int uCheckAndScan2ByteGRPrefix8EA4(
+                                   int32_t*    state,
+                                   unsigned char  *in,
+                                   uint16_t    *out,
+                                   uint32_t     inbuflen,
+                                   uint32_t*    inscanlen
+                                   );
+int uCheckAndScan2ByteGRPrefix8EA5(
+                                   int32_t*    state,
+                                   unsigned char  *in,
+                                   uint16_t    *out,
+                                   uint32_t     inbuflen,
+                                   uint32_t*    inscanlen
+                                   );
+int uCheckAndScan2ByteGRPrefix8EA6(
+                                   int32_t*    state,
+                                   unsigned char  *in,
+                                   uint16_t    *out,
+                                   uint32_t     inbuflen,
+                                   uint32_t*    inscanlen
+                                   );
+int uCheckAndScan2ByteGRPrefix8EA7(
+                                   int32_t*    state,
+                                   unsigned char  *in,
+                                   uint16_t    *out,
+                                   uint32_t     inbuflen,
+                                   uint32_t*    inscanlen
+                                   );
+int uCnSAlways8BytesDecomposedHangul(
+                                     int32_t*    state,
+                                     unsigned char  *in,
+                                     uint16_t    *out,
+                                     uint32_t     inbuflen,
+                                     uint32_t*    inscanlen
+                                     );
+int uCheckAndScanJohabHangul(
+                             int32_t*    state,
+                             unsigned char  *in,
+                             uint16_t    *out,
+                             uint32_t     inbuflen,
+                             uint32_t*    inscanlen
+                             );
+int uCheckAndScanJohabSymbol(
+                             int32_t*    state,
+                             unsigned char  *in,
+                             uint16_t    *out,
+                             uint32_t     inbuflen,
+                             uint32_t*    inscanlen
+                             );
 
-PRIVATE PRBool uCheckAndScan2ByteGRPrefix8F(
-                                            int32_t*    state,
-                                            unsigned char  *in,
-                                            uint16_t    *out,
-                                            uint32_t     inbuflen,
-                                            uint32_t*    inscanlen
-                                            );
-PRIVATE PRBool uCheckAndScan2ByteGRPrefix8EA2(
-                                              int32_t*    state,
-                                              unsigned char  *in,
-                                              uint16_t    *out,
-                                              uint32_t     inbuflen,
-                                              uint32_t*    inscanlen
-                                              );
-PRIVATE PRBool uCheckAndScan2ByteGRPrefix8EA3(
-                                              int32_t*    state,
-                                              unsigned char  *in,
-                                              uint16_t    *out,
-                                              uint32_t     inbuflen,
-                                              uint32_t*    inscanlen
-                                              );
-PRIVATE PRBool uCheckAndScan2ByteGRPrefix8EA4(
-                                              int32_t*    state,
-                                              unsigned char  *in,
-                                              uint16_t    *out,
-                                              uint32_t     inbuflen,
-                                              uint32_t*    inscanlen
-                                              );
-PRIVATE PRBool uCheckAndScan2ByteGRPrefix8EA5(
-                                              int32_t*    state,
-                                              unsigned char  *in,
-                                              uint16_t    *out,
-                                              uint32_t     inbuflen,
-                                              uint32_t*    inscanlen
-                                              );
-PRIVATE PRBool uCheckAndScan2ByteGRPrefix8EA6(
-                                              int32_t*    state,
-                                              unsigned char  *in,
-                                              uint16_t    *out,
-                                              uint32_t     inbuflen,
-                                              uint32_t*    inscanlen
-                                              );
-PRIVATE PRBool uCheckAndScan2ByteGRPrefix8EA7(
-                                              int32_t*    state,
-                                              unsigned char  *in,
-                                              uint16_t    *out,
-                                              uint32_t     inbuflen,
-                                              uint32_t*    inscanlen
-                                              );
-PRIVATE PRBool uCnSAlways8BytesDecomposedHangul(
-                                              int32_t*    state,
-                                              unsigned char  *in,
-                                              uint16_t    *out,
-                                              uint32_t     inbuflen,
-                                              uint32_t*    inscanlen
-                                              );
-PRIVATE PRBool uCheckAndScanJohabHangul(
-                                        int32_t*    state,
-                                        unsigned char  *in,
-                                        uint16_t    *out,
-                                        uint32_t     inbuflen,
-                                        uint32_t*    inscanlen
-                                        );
-PRIVATE PRBool uCheckAndScanJohabSymbol(
-                                        int32_t*    state,
-                                        unsigned char  *in,
-                                        uint16_t    *out,
-                                        uint32_t     inbuflen,
-                                        uint32_t*    inscanlen
-                                        );
+int uCheckAndScan4BytesGB18030(
+                               int32_t*    state,
+                               unsigned char  *in,
+                               uint16_t    *out,
+                               uint32_t     inbuflen,
+                               uint32_t*    inscanlen
+                               );
 
-PRIVATE PRBool uCheckAndScan4BytesGB18030(
-                                          int32_t*    state,
-                                          unsigned char  *in,
-                                          uint16_t    *out,
-                                          uint32_t     inbuflen,
-                                          uint32_t*    inscanlen
-                                          );
+int uScanAlways2Byte(
+                     unsigned char*  in,
+                     uint16_t*    out
+                     );
+int uScanAlways2ByteShiftGR(
+                            unsigned char*  in,
+                            uint16_t*    out
+                            );
+int uScanAlways1Byte(
+                     unsigned char*  in,
+                     uint16_t*    out
+                     );
+int uScanAlways1BytePrefix8E(
+                             unsigned char*  in,
+                             uint16_t*    out
+                             );
+/*=================================================================================
 
-PRIVATE PRBool uScanAlways2Byte(
-                                unsigned char*  in,
-                                uint16_t*    out
-                                );
-PRIVATE PRBool uScanAlways2ByteShiftGR(
-                                       unsigned char*  in,
-                                       uint16_t*    out
-                                       );
-PRIVATE PRBool uScanAlways1Byte(
-                                unsigned char*  in,
-                                uint16_t*    out
-                                );
-PRIVATE PRBool uScanAlways1BytePrefix8E(
-                                        unsigned char*  in,
-                                        uint16_t*    out
-                                        );
-                                    /*=================================================================================
-                                    
 =================================================================================*/
-PRIVATE const uScannerFunc m_scanner[uNumOfCharsetType] =
+const uScannerFunc m_scanner[uNumOfCharsetType] =
 {
     uCheckAndScanAlways1Byte,
     uCheckAndScanAlways2Byte,
     uCheckAndScanAlways2ByteShiftGR,
     uCheckAndScan2ByteGRPrefix8F,
     uCheckAndScan2ByteGRPrefix8EA2,
     uCheckAndScan2ByteGRPrefix8EA3,
     uCheckAndScan2ByteGRPrefix8EA4,
@@ -185,460 +185,460 @@ PRIVATE const uScannerFunc m_scanner[uNu
     uCheckAndScan4BytesGB18030,
     uCheckAndScanAlways2ByteGR128
 };
 
 /*=================================================================================
 
 =================================================================================*/
 
-PRIVATE const uSubScannerFunc m_subscanner[uNumOfCharType] =
+const uSubScannerFunc m_subscanner[uNumOfCharType] =
 {
     uScanAlways1Byte,
     uScanAlways2Byte,
     uScanAlways2ByteShiftGR,
     uScanAlways1BytePrefix8E
 };
 /*=================================================================================
 
 =================================================================================*/
-MODULE_PRIVATE PRBool uScan(  
-                            uScanClassID scanClass,
-                            int32_t*    state,
-                            unsigned char  *in,
-                            uint16_t    *out,
-                            uint32_t     inbuflen,
-                            uint32_t*    inscanlen
-                            )
+int uScan(
+          uScanClassID scanClass,
+          int32_t*    state,
+          unsigned char  *in,
+          uint16_t    *out,
+          uint32_t     inbuflen,
+          uint32_t*    inscanlen
+          )
 {
   return (* m_scanner[scanClass]) (state,in,out,inbuflen,inscanlen);
 }
 /*=================================================================================
 
 =================================================================================*/
-PRIVATE PRBool uScanAlways1Byte(
-                                unsigned char*  in,
-                                uint16_t*    out
-                                )
+int uScanAlways1Byte(
+                     unsigned char*  in,
+                     uint16_t*    out
+                     )
 {
   *out = (uint16_t) in[0];
-  return PR_TRUE;
+  return 1;
 }
 
 /*=================================================================================
 
 =================================================================================*/
-PRIVATE PRBool uScanAlways2Byte(
-                                unsigned char*  in,
-                                uint16_t*    out
-                                )
+int uScanAlways2Byte(
+                     unsigned char*  in,
+                     uint16_t*    out
+                     )
 {
   *out = (uint16_t) (( in[0] << 8) | (in[1]));
-  return PR_TRUE;
+  return 1;
 }
 /*=================================================================================
 
 =================================================================================*/
-PRIVATE PRBool uScanAlways2ByteShiftGR(
-                                       unsigned char*  in,
-                                       uint16_t*    out
-                                       )
+int uScanAlways2ByteShiftGR(
+                            unsigned char*  in,
+                            uint16_t*    out
+                            )
 {
   *out = (uint16_t) ((( in[0] << 8) | (in[1])) &  0x7F7F);
-  return PR_TRUE;
+  return 1;
 }
 
 /*=================================================================================
 
 =================================================================================*/
-PRIVATE PRBool uScanAlways1BytePrefix8E(
-                                        unsigned char*  in,
-                                        uint16_t*    out
-                                        )
+int uScanAlways1BytePrefix8E(
+                             unsigned char*  in,
+                             uint16_t*    out
+                             )
 {
   *out = (uint16_t) in[1];
-  return PR_TRUE;
+  return 1;
 }
 /*=================================================================================
 
 =================================================================================*/
-PRIVATE PRBool uCheckAndScanAlways1Byte(
-                                        int32_t*    state,
-                                        unsigned char  *in,
-                                        uint16_t    *out,
-                                        uint32_t     inbuflen,
-                                        uint32_t*    inscanlen
-                                        )
+int uCheckAndScanAlways1Byte(
+                             int32_t*    state,
+                             unsigned char  *in,
+                             uint16_t    *out,
+                             uint32_t     inbuflen,
+                             uint32_t*    inscanlen
+                             )
 {
   /* Don't check inlen. The caller should ensure it is larger than 0 */
   *inscanlen = 1;
   *out = (uint16_t) in[0];
   
-  return PR_TRUE;
+  return 1;
 }
 
 /*=================================================================================
 
 =================================================================================*/
-PRIVATE PRBool uCheckAndScanAlways2Byte(
-                                        int32_t*    state,
-                                        unsigned char  *in,
-                                        uint16_t    *out,
-                                        uint32_t     inbuflen,
-                                        uint32_t*    inscanlen
-                                        )
+int uCheckAndScanAlways2Byte(
+                             int32_t*    state,
+                             unsigned char  *in,
+                             uint16_t    *out,
+                             uint32_t     inbuflen,
+                             uint32_t*    inscanlen
+                             )
 {
   if(inbuflen < 2)
-    return PR_FALSE;
+    return 0;
   else
   {
     *inscanlen = 2;
     *out = ((in[0] << 8) | ( in[1])) ;
-    return PR_TRUE;
+    return 1;
   }
 }
 /*=================================================================================
 
 =================================================================================*/
-PRIVATE PRBool uCheckAndScanAlways2ByteShiftGR(
-                                               int32_t*    state,
-                                               unsigned char  *in,
-                                               uint16_t    *out,
-                                               uint32_t     inbuflen,
-                                               uint32_t*    inscanlen
-                                               )
+int uCheckAndScanAlways2ByteShiftGR(
+                                    int32_t*    state,
+                                    unsigned char  *in,
+                                    uint16_t    *out,
+                                    uint32_t     inbuflen,
+                                    uint32_t*    inscanlen
+                                    )
 {
   /*
    * Both bytes should be in the range of [0xa1,0xfe] for 94x94 character sets
    * invoked on GR. No encoding implemented in Mozilla uses 96x96 char. sets.
    * Only 2nd byte range needs to be checked because 
    * 1st byte is checked before calling this in nsUnicodeDecoerHelper.cpp 
    */
   if(inbuflen < 2)    /* will lead to NS_OK_UDEC_MOREINPUT */
-    return PR_FALSE;
+    return 0;
   else if (! CHK_GR94(in[1]))  
   {
     *inscanlen = 2; 
     *out = 0xFF;  /* for 2-byte table, uMap() is guaranteed to fail for 0xFF. */
-    return PR_TRUE;
+    return 1;
   }
   else
   {
     *inscanlen = 2;
     *out = (((in[0] << 8) | ( in[1]))  & 0x7F7F);
-    return PR_TRUE;
+    return 1;
   }
 }
 /*=================================================================================
 
 =================================================================================*/
-PRIVATE PRBool uCheckAndScanAlways2ByteGR128(
-                                               int32_t*    state,
-                                               unsigned char  *in,
-                                               uint16_t    *out,
-                                               uint32_t     inbuflen,
-                                               uint32_t*    inscanlen
-                                               )
+int uCheckAndScanAlways2ByteGR128(
+                                  int32_t*    state,
+                                  unsigned char  *in,
+                                  uint16_t    *out,
+                                  uint32_t     inbuflen,
+                                  uint32_t*    inscanlen
+                                  )
 {
   /*
    * The first byte should be in  [0xa1,0xfe] 
    * and the second byte in [0x41,0xfe]
    * Used by CP949 -> Unicode converter.
    * Only 2nd byte range needs to be checked because 
    * 1st byte is checked before calling this in nsUnicodeDecoderHelper.cpp 
    */
   if(inbuflen < 2)    /* will lead to NS_OK_UDEC_MOREINPUT */
-    return PR_FALSE;
+    return 0;
   else if (in[1] < 0x41)     /* 2nd byte range check */
   {
     *inscanlen = 2; 
     *out = 0xFF;  /* for 2-byte table, uMap() is guaranteed to fail for 0xFF. */
-    return PR_TRUE;
+    return 1;
   }
   else
   {
     *inscanlen = 2;
     *out = (in[0] << 8) |  in[1];
-    return PR_TRUE;
+    return 1;
   }
 }
 /*=================================================================================
 
 =================================================================================*/
-PRIVATE PRBool uScanShift(
-                                    uShiftInTable    *shift,
-                                    int32_t*    state,
-                                    unsigned char  *in,
-                                    uint16_t    *out,
-                                    uint32_t     inbuflen,
-                                    uint32_t*    inscanlen
-                                    )
+int uScanShift(
+               uShiftInTable    *shift,
+               int32_t*    state,
+               unsigned char  *in,
+               uint16_t    *out,
+               uint32_t     inbuflen,
+               uint32_t*    inscanlen
+               )
 {
   int16_t i;
   const uShiftInCell* cell = &(shift->shiftcell[0]);
   int16_t itemnum = shift->numOfItem;
   for(i=0;i<itemnum;i++)
   {
     if( ( in[0] >=  cell[i].shiftin_Min) &&
       ( in[0] <=  cell[i].shiftin_Max))
     {
       if(inbuflen < cell[i].reserveLen)
-        return PR_FALSE;
+        return 0;
       else
       {
         *inscanlen = cell[i].reserveLen;
         return (uSubScanner(cell[i].classID,in,out));
       }
     }
   }
-  return PR_FALSE;
+  return 0;
 }
 /*=================================================================================
 
 =================================================================================*/
-PRIVATE PRBool uCheckAndScan2ByteGRPrefix8F(
-                                            int32_t*    state,
-                                            unsigned char  *in,
-                                            uint16_t    *out,
-                                            uint32_t     inbuflen,
-                                            uint32_t*    inscanlen
-                                            )
+int uCheckAndScan2ByteGRPrefix8F(
+                                 int32_t*    state,
+                                 unsigned char  *in,
+                                 uint16_t    *out,
+                                 uint32_t     inbuflen,
+                                 uint32_t*    inscanlen
+                                 )
 {
   if((inbuflen < 3) ||(in[0] != 0x8F)) 
-    return PR_FALSE;
+    return 0;
   else if (! CHK_GR94(in[1]))  /* 2nd byte range check */
   {
     *inscanlen = 2; 
     *out = 0xFF;  /* for 2-byte table, uMap() is guaranteed to fail for 0xFF. */
-    return PR_TRUE;
+    return 1;
   }
   else if (! CHK_GR94(in[2]))  /* 3rd byte range check */
   {
     *inscanlen = 3; 
     *out = 0xFF;  /* for 2-byte table, uMap() is guaranteed to fail for 0xFF. */
-    return PR_TRUE;
+    return 1;
   }
   else
   {
     *inscanlen = 3;
     *out = (((in[1] << 8) | ( in[2]))  & 0x7F7F);
-    return PR_TRUE;
+    return 1;
   }
 }
 /*=================================================================================
 
 =================================================================================*/
 
 /* Macro definition to use for uCheckAndScan2ByteGRPrefix8EAX()
  * where X is 2,3,4,5,6,7 
  */
 #define CNS_8EAX_4BYTE(PREFIX)                    \
   if((inbuflen < 4) || (in[0] != 0x8E))           \
-    return PR_FALSE;                              \
+    return 0;                                     \
   else if((in[1] != (PREFIX)))                    \
   {                                               \
     *inscanlen = 2;                               \
     *out = 0xFF;                                  \
-    return PR_TRUE;                               \
+    return 1;                                     \
   }                                               \
   else if(! CHK_GR94(in[2]))                      \
   {                                               \
     *inscanlen = 3;                               \
     *out = 0xFF;                                  \
-    return PR_TRUE;                               \
+    return 1;                                     \
   }                                               \
   else if(! CHK_GR94(in[3]))                      \
   {                                               \
     *inscanlen = 4;                               \
     *out = 0xFF;                                  \
-    return PR_TRUE;                               \
+    return 1;                                     \
   }                                               \
   else                                            \
   {                                               \
     *inscanlen = 4;                               \
     *out = (((in[2] << 8) | ( in[3]))  & 0x7F7F); \
-    return PR_TRUE;                               \
+    return 1;                                     \
   }    
 
-PRIVATE PRBool uCheckAndScan2ByteGRPrefix8EA2(
-                                              int32_t*    state,
-                                              unsigned char  *in,
-                                              uint16_t    *out,
-                                              uint32_t     inbuflen,
-                                              uint32_t*    inscanlen
-                                              )
+int uCheckAndScan2ByteGRPrefix8EA2(
+                                   int32_t*    state,
+                                   unsigned char  *in,
+                                   uint16_t    *out,
+                                   uint32_t     inbuflen,
+                                   uint32_t*    inscanlen
+                                   )
 {
   CNS_8EAX_4BYTE(0xA2)
 }
 
 /*=================================================================================
 
 =================================================================================*/
-PRIVATE PRBool uCheckAndScan2ByteGRPrefix8EA3(
-                                              int32_t*    state,
-                                              unsigned char  *in,
-                                              uint16_t    *out,
-                                              uint32_t     inbuflen,
-                                              uint32_t*    inscanlen
-                                              )
+int uCheckAndScan2ByteGRPrefix8EA3(
+                                   int32_t*    state,
+                                   unsigned char  *in,
+                                   uint16_t    *out,
+                                   uint32_t     inbuflen,
+                                   uint32_t*    inscanlen
+                                   )
 {
   CNS_8EAX_4BYTE(0xA3)
 }
 /*=================================================================================
 
 =================================================================================*/
-PRIVATE PRBool uCheckAndScan2ByteGRPrefix8EA4(
-                                              int32_t*    state,
-                                              unsigned char  *in,
-                                              uint16_t    *out,
-                                              uint32_t     inbuflen,
-                                              uint32_t*    inscanlen
-                                              )
+int uCheckAndScan2ByteGRPrefix8EA4(
+                                   int32_t*    state,
+                                   unsigned char  *in,
+                                   uint16_t    *out,
+                                   uint32_t     inbuflen,
+                                   uint32_t*    inscanlen
+                                   )
 {
   CNS_8EAX_4BYTE(0xA4)
 }
 /*=================================================================================
 
 =================================================================================*/
-PRIVATE PRBool uCheckAndScan2ByteGRPrefix8EA5(
-                                              int32_t*    state,
-                                              unsigned char  *in,
-                                              uint16_t    *out,
-                                              uint32_t     inbuflen,
-                                              uint32_t*    inscanlen
-                                              )
+int uCheckAndScan2ByteGRPrefix8EA5(
+                                   int32_t*    state,
+                                   unsigned char  *in,
+                                   uint16_t    *out,
+                                   uint32_t     inbuflen,
+                                   uint32_t*    inscanlen
+                                   )
 {
   CNS_8EAX_4BYTE(0xA5)
 }
 /*=================================================================================
 
 =================================================================================*/
-PRIVATE PRBool uCheckAndScan2ByteGRPrefix8EA6(
-                                              int32_t*    state,
-                                              unsigned char  *in,
-                                              uint16_t    *out,
-                                              uint32_t     inbuflen,
-                                              uint32_t*    inscanlen
-                                              )
+int uCheckAndScan2ByteGRPrefix8EA6(
+                                   int32_t*    state,
+                                   unsigned char  *in,
+                                   uint16_t    *out,
+                                   uint32_t     inbuflen,
+                                   uint32_t*    inscanlen
+                                   )
 {
   CNS_8EAX_4BYTE(0xA6)
 }
 /*=================================================================================
 
 =================================================================================*/
-PRIVATE PRBool uCheckAndScan2ByteGRPrefix8EA7(
-                                              int32_t*    state,
-                                              unsigned char  *in,
-                                              uint16_t    *out,
-                                              uint32_t     inbuflen,
-                                              uint32_t*    inscanlen
-                                              )
+int uCheckAndScan2ByteGRPrefix8EA7(
+                                   int32_t*    state,
+                                   unsigned char  *in,
+                                   uint16_t    *out,
+                                   uint32_t     inbuflen,
+                                   uint32_t*    inscanlen
+                                   )
 {
   CNS_8EAX_4BYTE(0xA7)
 }
 /*=================================================================================
 
 =================================================================================*/
 #define SBase 0xAC00
 #define SCount 11172
 #define LCount 19
 #define VCount 21
 #define TCount 28
 #define NCount (VCount * TCount)
 
-PRIVATE PRBool uCnSAlways8BytesDecomposedHangul(
-                                              int32_t*    state,
-                                              unsigned char  *in,
-                                              uint16_t    *out,
-                                              uint32_t     inbuflen,
-                                              uint32_t*    inscanlen
-                                              )
+int uCnSAlways8BytesDecomposedHangul(
+                                     int32_t*    state,
+                                     unsigned char  *in,
+                                     uint16_t    *out,
+                                     uint32_t     inbuflen,
+                                     uint32_t*    inscanlen
+                                     )
 {
   
   uint16_t LIndex, VIndex, TIndex;
   /* no 8 bytes, not in a4 range, or the first 2 byte are not a4d4 */
   if((inbuflen < 8) || (0xa4 != in[0]) || (0xd4 != in[1]) ||
     (0xa4 != in[2] ) || (0xa4 != in[4]) || (0xa4 != in[6]))
-    return PR_FALSE;
+    return 0;
   
   /* Compute LIndex  */
   if((in[3] < 0xa1) || (in[3] > 0xbe)) { /* illegal leading consonant */
-    return PR_FALSE;
+    return 0;
   } 
   else {
     static const uint8_t lMap[] = {
       /*        A1   A2   A3   A4   A5   A6   A7  */
       0,   1,0xff,   2,0xff,0xff,   3,
         /*   A8   A9   AA   AB   AC   AD   AE   AF  */
         4,   5,0xff,0xff,0xff,0xff,0xff,0xff,
         /*   B0   B1   B2   B3   B4   B5   B6   B7  */
         0xff,   6,   7,   8,0xff,   9,  10,  11,
         /*   B8   B9   BA   BB   BC   BD   BE       */
         12,  13,  14,  15,  16,  17,  18     
     };
     
     LIndex = lMap[in[3] - 0xa1];
     if(0xff == (0xff & LIndex))
-      return PR_FALSE;
+      return 0;
   }
   
   /* Compute VIndex  */
   if((in[5] < 0xbf) || (in[5] > 0xd3)) { /* illegal medial vowel */
-    return PR_FALSE;
+    return 0;
   } 
   else {
     VIndex = in[5] - 0xbf;
   }
   
   /* Compute TIndex  */
   if(0xd4 == in[7])  
   {
     TIndex = 0;
   } 
   else if((in[7] < 0xa1) || (in[7] > 0xbe)) {/* illegal trailing consonant */
-    return PR_FALSE;
+    return 0;
   } 
   else {
     static const uint8_t tMap[] = {
       /*        A1   A2   A3   A4   A5   A6   A7  */
       1,   2,   3,   4,   5,   6,   7,
         /*   A8   A9   AA   AB   AC   AD   AE   AF  */
         0xff,   8,   9,  10,  11,  12,  13,  14,
         /*   B0   B1   B2   B3   B4   B5   B6   B7  */
         15,  16,  17,0xff,  18,  19,  20,  21,
         /*   B8   B9   BA   BB   BC   BD   BE       */
         22,0xff,  23,  24,  25,  26,  27     
     };
     TIndex = tMap[in[7] - 0xa1];
     if(0xff == (0xff & TIndex))
-      return PR_FALSE;
+      return 0;
   }
   
   *inscanlen = 8;
   /* the following line is from Unicode 2.0 page 3-13 item 5 */
   *out = ( LIndex * VCount + VIndex) * TCount + TIndex + SBase;
   
-  return PR_TRUE;
+  return 1;
 }
 /*=================================================================================
 
 =================================================================================*/
 
-PRIVATE PRBool uCheckAndScanJohabHangul(
-                                        int32_t*    state,
-                                        unsigned char  *in,
-                                        uint16_t    *out,
-                                        uint32_t     inbuflen,
-                                        uint32_t*    inscanlen
-                                        )
+int uCheckAndScanJohabHangul(
+                             int32_t*    state,
+                             unsigned char  *in,
+                             uint16_t    *out,
+                             uint32_t     inbuflen,
+                             uint32_t*    inscanlen
+                             )
 {
 /* since we don't have code to convert Johab to Unicode right now     *
   * make this part of code #if 0 to save space until we fully test it */
   if(inbuflen < 2)
-    return PR_FALSE;
+    return 0;
   else {
   /*
   * See Table 4-45 Johab Encoding's Five-Bit Binary Patterns in page 183
   * of "CJKV Information Processing" for details
     */
     static const uint8_t lMap[32]={ /* totaly 19  */
       0xff,0xff,0,   1,   2,   3,   4,   5,    /* 0-7    */
         6,   7,   8,   9,   10,  11,  12,  13,   /* 8-15   */
@@ -655,40 +655,40 @@ PRIVATE PRBool uCheckAndScanJohabHangul(
       0xff,0,   1,   2,   3,   4,   5,   6,    /* 0-7   */
         7,   8,   9,   10,  11,  12,  13,  14,   /* 8-15  */
         15,  16,  0xff,17,  18,  19,  20,  21,   /* 16-23 */
         22,  23,  24,  25,  26,  27,  0xff,0xff  /* 24-31 */
     };
     uint16_t ch = (in[0] << 8) | in[1];
     uint16_t LIndex, VIndex, TIndex;
     if(0 == (0x8000 & ch))
-      return PR_FALSE;
+      return 0;
     LIndex=lMap[(ch>>10)& 0x1F];
     VIndex=vMap[(ch>>5) & 0x1F];
     TIndex=tMap[(ch>>0) & 0x1F];
     if((0xff==(LIndex)) || 
       (0xff==(VIndex)) || 
       (0xff==(TIndex)))
-      return PR_FALSE;
+      return 0;
     /* the following line is from Unicode 2.0 page 3-13 item 5 */
     *out = ( LIndex * VCount + VIndex) * TCount + TIndex + SBase;
     *inscanlen = 2;
-    return PR_TRUE;
+    return 1;
   }
 }
-PRIVATE PRBool uCheckAndScanJohabSymbol(
-                                        int32_t*    state,
-                                        unsigned char  *in,
-                                        uint16_t    *out,
-                                        uint32_t     inbuflen,
-                                        uint32_t*    inscanlen
-                                        )
+int uCheckAndScanJohabSymbol(
+                             int32_t*    state,
+                             unsigned char  *in,
+                             uint16_t    *out,
+                             uint32_t     inbuflen,
+                             uint32_t*    inscanlen
+                             )
 {
   if(inbuflen < 2)
-    return PR_FALSE;
+    return 0;
   else {
   /*
   * The following code are based on the Perl code lised under
   * "Johab to ISO-2022-KR or EUC-KR Conversion" in page 1014 of
   * "CJKV Information Processing" by Ken Lunde <lunde@adobe.com>
   *
   * sub johab2ks ($) { # Convert Johab to ISO-2022-KR
   *   my @johab = unpack("C*", $_[0]);
@@ -721,39 +721,39 @@ PRIVATE PRBool uCheckAndScanJohabSymbol(
         d8_off = 42;
     }
     
     *out = (((((hi - ((hi < 223) ? 200 : 187)) << 1) -
       (lo < 161 ? 1 : 0) + offset) + d8_off) << 8 ) |
       (lo - ((lo < 161) ? ((lo > 126) ? 34 : 16) : 
     128));
     *inscanlen = 2;
-    return PR_TRUE;
+    return 1;
   }
 }
-PRIVATE PRBool uCheckAndScan4BytesGB18030(
-                                          int32_t*    state,
-                                          unsigned char  *in,
-                                          uint16_t    *out,
-                                          uint32_t     inbuflen,
-                                          uint32_t*    inscanlen
-                                          )
+int uCheckAndScan4BytesGB18030(
+                               int32_t*    state,
+                               unsigned char  *in,
+                               uint16_t    *out,
+                               uint32_t     inbuflen,
+                               uint32_t*    inscanlen
+                               )
 {
   uint32_t  data;
   if(inbuflen < 4) 
-    return PR_FALSE;
+    return 0;
   
   if((in[0] < 0x81 ) || (0xfe < in[0])) 
-    return PR_FALSE;
+    return 0;
   if((in[1] < 0x30 ) || (0x39 < in[1])) 
-    return PR_FALSE;
+    return 0;
   if((in[2] < 0x81 ) || (0xfe < in[2])) 
-    return PR_FALSE;
+    return 0;
   if((in[3] < 0x30 ) || (0x39 < in[3])) 
-    return PR_FALSE;
+    return 0;
   
   data = (((((in[0] - 0x81) * 10 + (in[1] - 0x30)) * 126) + 
     (in[2] - 0x81)) * 10 ) + (in[3] - 0x30);
   
   *inscanlen = 4;
   *out = (data < 0x00010000) ? data : 0xFFFD;
-  return PR_TRUE;
+  return 1;
 }
--- a/intl/unicharutil/util/nsSpecialCasingData.h
+++ b/intl/unicharutil/util/nsSpecialCasingData.h
@@ -1,13 +1,12 @@
 /* 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 "prtypes.h"
 #include <stdint.h>
 
 namespace mozilla {
 namespace unicode {
 
 // Multi-character mappings (from SpecialCasing.txt) map a single Unicode
 // value to a sequence of 2 or 3 Unicode characters. There are currently none
 // defined outside the BMP, so we can use char16_t here. Unused trailing
--- a/ipc/glue/MessageChannel.cpp
+++ b/ipc/glue/MessageChannel.cpp
@@ -1280,16 +1280,19 @@ MessageChannel::ReportMessageRouteError(
 {
     PrintErrorMessage(mSide, channelName, "Need a route");
     mListener->OnProcessingError(MsgRouteError);
 }
 
 void
 MessageChannel::ReportConnectionError(const char* aChannelName) const
 {
+    AssertWorkerThread();
+    mMonitor->AssertCurrentThreadOwns();
+
     const char* errorMsg = nullptr;
     switch (mChannelState) {
       case ChannelClosed:
         errorMsg = "Closed channel: cannot send/recv";
         break;
       case ChannelOpening:
         errorMsg = "Opening channel: not yet ready for send/recv";
         break;
@@ -1303,16 +1306,18 @@ MessageChannel::ReportConnectionError(co
         errorMsg = "Channel error: cannot send/recv";
         break;
 
       default:
         NS_RUNTIMEABORT("unreached");
     }
 
     PrintErrorMessage(mSide, aChannelName, errorMsg);
+
+    MonitorAutoUnlock unlock(*mMonitor);
     mListener->OnProcessingError(MsgDropped);
 }
 
 bool
 MessageChannel::MaybeHandleError(Result code, const char* channelName)
 {
     if (MsgProcessed == code)
         return true;
--- a/js/jsd/jsd_scpt.cpp
+++ b/js/jsd/jsd_scpt.cpp
@@ -355,17 +355,17 @@ JSScript *
 jsd_GetJSScript (JSDContext *jsdc, JSDScript *script)
 {
     return script->script;
 }
 
 JSFunction *
 jsd_GetJSFunction (JSDContext *jsdc, JSDScript *script)
 {
-    AutoSafeJSContext cx; // NB: Actually unused.
+    AutoSafeJSContext cx;
     return JS_GetScriptFunction(cx, script->script);
 }
 
 JSDScript*
 jsd_IterateScripts(JSDContext* jsdc, JSDScript **iterp)
 {
     JSDScript *jsdscript = *iterp;
     
--- a/js/src/builtin/Array.js
+++ b/js/src/builtin/Array.js
@@ -603,16 +603,32 @@ function ArrayKeys() {
  */
 function ComputeNumChunks(length) {
   var chunks = length >>> CHUNK_SHIFT;
   if (chunks << CHUNK_SHIFT === length)
     return chunks;
   return chunks + 1;
 }
 
+#define SLICES_PER_WORKER 8
+
+/**
+ * Compute the number of slices given an array length and the number of
+ * chunks. Used in tandem with the workstealing scheduler.
+ */
+function ComputeNumSlices(workers, length, chunks) {
+  if (length !== 0) {
+    var slices = workers * SLICES_PER_WORKER;
+    if (chunks < slices)
+      return workers;
+    return slices;
+  }
+  return workers;
+}
+
 /**
  * Computes the bounds for slice |sliceIndex| of |numItems| items,
  * assuming |numSlices| total slices. If numItems is not evenly
  * divisible by numSlices, then the final thread may have a bit of
  * extra work.
  */
 function ComputeSliceBounds(numItems, sliceIndex, numSlices) {
   var sliceWidth = (numItems / numSlices) | 0;
@@ -671,32 +687,33 @@ function ArrayMapPar(func, mode) {
     // - Breaking out of named blocks does not currently work (bug 684384);
     // - Unreachable Code Elim. can't properly handle if (a && b) (bug 669796)
     if (ShouldForceSequential())
       break parallel;
     if (!TRY_PARALLEL(mode))
       break parallel;
 
     var chunks = ComputeNumChunks(length);
-    var numSlices = ForkJoinSlices();
+    var numWorkers = ForkJoinNumWorkers();
+    var numSlices = ComputeNumSlices(numWorkers, length, chunks);
     var info = ComputeAllSliceBounds(chunks, numSlices);
-    ForkJoin(mapSlice, ForkJoinMode(mode));
+    ForkJoin(mapSlice, ForkJoinMode(mode), numSlices);
     return buffer;
   }
 
   // Sequential fallback:
   ASSERT_SEQUENTIAL_IS_OK(mode);
   for (var i = 0; i < length; i++) {
     // Note: Unlike JS arrays, parallel arrays cannot have holes.
     var v = func(self[i], i, self);
     UnsafePutElements(buffer, i, v);
   }
   return buffer;
 
-  function mapSlice(sliceId, numSlices, warmup) {
+  function mapSlice(sliceId, warmup) {
     var chunkPos = info[SLICE_POS(sliceId)];
     var chunkEnd = info[SLICE_END(sliceId)];
 
     if (warmup && chunkEnd > chunkPos + 1)
       chunkEnd = chunkPos + 1;
 
     while (chunkPos < chunkEnd) {
       var indexStart = chunkPos << CHUNK_SHIFT;
@@ -730,37 +747,38 @@ function ArrayReducePar(func, mode) {
 
   parallel: for (;;) { // see ArrayMapPar() to explain why for(;;) etc
     if (ShouldForceSequential())
       break parallel;
     if (!TRY_PARALLEL(mode))
       break parallel;
 
     var chunks = ComputeNumChunks(length);
-    var numSlices = ForkJoinSlices();
-    if (chunks < numSlices)
+    var numWorkers = ForkJoinNumWorkers();
+    if (chunks < numWorkers)
       break parallel;
 
+    var numSlices = ComputeNumSlices(numWorkers, length, chunks);
     var info = ComputeAllSliceBounds(chunks, numSlices);
     var subreductions = NewDenseArray(numSlices);
-    ForkJoin(reduceSlice, ForkJoinMode(mode));
+    ForkJoin(reduceSlice, ForkJoinMode(mode), numSlices);
     var accumulator = subreductions[0];
     for (var i = 1; i < numSlices; i++)
       accumulator = func(accumulator, subreductions[i]);
     return accumulator;
   }
 
   // Sequential fallback:
   ASSERT_SEQUENTIAL_IS_OK(mode);
   var accumulator = self[0];
   for (var i = 1; i < length; i++)
     accumulator = func(accumulator, self[i]);
   return accumulator;
 
-  function reduceSlice(sliceId, numSlices, warmup) {
+  function reduceSlice(sliceId, warmup) {
     var chunkStart = info[SLICE_START(sliceId)];
     var chunkPos = info[SLICE_POS(sliceId)];
     var chunkEnd = info[SLICE_END(sliceId)];
 
     // (*) This function is carefully designed so that the warmup
     // (which executes with chunkStart === chunkPos) will execute all
     // potential loads and stores. In particular, the warmup run
     // processes two chunks rather than one. Moreover, it stores
@@ -819,23 +837,25 @@ function ArrayScanPar(func, mode) {
 
   parallel: for (;;) { // see ArrayMapPar() to explain why for(;;) etc
     if (ShouldForceSequential())
       break parallel;
     if (!TRY_PARALLEL(mode))
       break parallel;
 
     var chunks = ComputeNumChunks(length);
-    var numSlices = ForkJoinSlices();
-    if (chunks < numSlices)
+    var numWorkers = ForkJoinNumWorkers();
+    if (chunks < numWorkers)
       break parallel;
+
+    var numSlices = ComputeNumSlices(numWorkers, length, chunks);
     var info = ComputeAllSliceBounds(chunks, numSlices);
 
     // Scan slices individually (see comment on phase1()).
-    ForkJoin(phase1, ForkJoinMode(mode));
+    ForkJoin(phase1, ForkJoinMode(mode), numSlices);
 
     // Compute intermediates array (see comment on phase2()).
     var intermediates = [];
     var accumulator = buffer[finalElement(0)];
     ARRAY_PUSH(intermediates, accumulator);
     for (var i = 1; i < numSlices - 1; i++) {
       accumulator = func(accumulator, buffer[finalElement(i)]);
       ARRAY_PUSH(intermediates, accumulator);
@@ -845,17 +865,17 @@ function ArrayScanPar(func, mode) {
     // convert from chunks to indices (see comment on phase2()).
     for (var i = 0; i < numSlices; i++) {
       info[SLICE_POS(i)] = info[SLICE_START(i)] << CHUNK_SHIFT;
       info[SLICE_END(i)] = info[SLICE_END(i)] << CHUNK_SHIFT;
     }
     info[SLICE_END(numSlices - 1)] = std_Math_min(info[SLICE_END(numSlices - 1)], length);
 
     // Complete each slice using intermediates array (see comment on phase2()).
-    ForkJoin(phase2, ForkJoinMode(mode));
+    ForkJoin(phase2, ForkJoinMode(mode), numSlices);
     return buffer;
   }
 
   // Sequential fallback:
   ASSERT_SEQUENTIAL_IS_OK(mode);
   scan(self[0], 0, length);
   return buffer;
 
@@ -879,17 +899,17 @@ function ArrayScanPar(func, mode) {
    * result array like:
    *
    *     [A, A+B, A+B+C, D, D+E, D+E+F, G, G+H, G+H+I]
    *      ^~~~~~~~~~~~^  ^~~~~~~~~~~~^  ^~~~~~~~~~~~~^
    *      Slice 0        Slice 1        Slice 2
    *
    * Read on in phase2 to see what we do next!
    */
-  function phase1(sliceId, numSlices, warmup) {
+  function phase1(sliceId, warmup) {
     var chunkStart = info[SLICE_START(sliceId)];
     var chunkPos = info[SLICE_POS(sliceId)];
     var chunkEnd = info[SLICE_END(sliceId)];
 
     if (warmup && chunkEnd > chunkPos + 2)
       chunkEnd = chunkPos + 2;
 
     if (chunkPos === chunkStart) {
@@ -962,17 +982,17 @@ function ArrayScanPar(func, mode) {
    * SUBTLE: Because we are mutating |buffer| in place, we have to
    * be very careful about bailouts!  We cannot checkpoint a chunk
    * at a time as we do elsewhere because that assumes it is safe to
    * replay the portion of a chunk which was already processed.
    * Therefore, in this phase, we track the current position at an
    * index granularity, although this requires two memory writes per
    * index.
    */
-  function phase2(sliceId, numSlices, warmup) {
+  function phase2(sliceId, warmup) {
     if (sliceId === 0)
       return true; // No work to do for the 0th slice.
 
     var indexPos = info[SLICE_POS(sliceId)];
     var indexEnd = info[SLICE_END(sliceId)];
 
     if (warmup)
       indexEnd = std_Math_min(indexEnd, indexPos + CHUNK_SIZE);
@@ -1097,33 +1117,33 @@ function ArrayScatterPar(targets, defaul
       ThrowError(JSMSG_PAR_ARRAY_SCATTER_CONFLICT);
 
     return conflictFunc(elem1, elem2);
   }
 
 
   function parDivideOutputRange() {
     var chunks = ComputeNumChunks(targetsLength);
-    var numSlices = ForkJoinSlices();
+    var numSlices = ComputeNumSlices(ForkJoinNumWorkers(), length, chunks);
     var checkpoints = NewDenseArray(numSlices);
     for (var i = 0; i < numSlices; i++)
       UnsafePutElements(checkpoints, i, 0);
 
     var buffer = NewDenseArray(length);
     var conflicts = NewDenseArray(length);
 
     for (var i = 0; i < length; i++) {
       UnsafePutElements(buffer, i, defaultValue);
       UnsafePutElements(conflicts, i, false);
     }
 
-    ForkJoin(fill, ForkJoinMode(mode));
+    ForkJoin(fill, ForkJoinMode(mode), numSlices);
     return buffer;
 
-    function fill(sliceId, numSlices, warmup) {
+    function fill(sliceId, warmup) {
       var indexPos = checkpoints[sliceId];
       var indexEnd = targetsLength;
       if (warmup)
         indexEnd = std_Math_min(indexEnd, indexPos + CHUNK_SIZE);
 
       // Range in the output for which we are responsible:
       var [outputStart, outputEnd] = ComputeSliceBounds(length, sliceId, numSlices);
 
@@ -1144,17 +1164,17 @@ function ArrayScatterPar(targets, defaul
   }
 
   function parDivideScatterVector() {
     // Subtle: because we will be mutating the localBuffers and
     // conflict arrays in place, we can never replay an entry in the
     // target array for fear of inducing a conflict where none existed
     // before. Therefore, we must proceed not by chunks but rather by
     // individual indices.
-    var numSlices = ForkJoinSlices();
+    var numSlices = ComputeNumSlices(ForkJoinNumWorkers(), length, ComputeNumChunks(length));
     var info = ComputeAllSliceBounds(targetsLength, numSlices);
 
     // FIXME(bug 844890): Use typed arrays here.
     var localBuffers = NewDenseArray(numSlices);
     for (var i = 0; i < numSlices; i++)
       UnsafePutElements(localBuffers, i, NewDenseArray(length));
     var localConflicts = NewDenseArray(numSlices);
     for (var i = 0; i < numSlices; i++) {
@@ -1167,21 +1187,21 @@ function ArrayScatterPar(targets, defaul
     // Initialize the 0th buffer, which will become the output. For
     // the other buffers, we track which parts have been written to
     // using the conflict buffer so they do not need to be
     // initialized.
     var outputBuffer = localBuffers[0];
     for (var i = 0; i < length; i++)
       UnsafePutElements(outputBuffer, i, defaultValue);
 
-    ForkJoin(fill, ForkJoinMode(mode));
+    ForkJoin(fill, ForkJoinMode(mode), numSlices);
     mergeBuffers();
     return outputBuffer;
 
-    function fill(sliceId, numSlices, warmup) {
+    function fill(sliceId, warmup) {
       var indexPos = info[SLICE_POS(sliceId)];
       var indexEnd = info[SLICE_END(sliceId)];
       if (warmup)
         indexEnd = std_Math_min(indexEnd, indexPos + CHUNK_SIZE);
 
       var localbuffer = localBuffers[sliceId];
       var conflicts = localConflicts[sliceId];
       while (indexPos < indexEnd) {
@@ -1270,43 +1290,44 @@ function ArrayFilterPar(func, mode) {
 
   parallel: for (;;) { // see ArrayMapPar() to explain why for(;;) etc
     if (ShouldForceSequential())
       break parallel;
     if (!TRY_PARALLEL(mode))
       break parallel;
 
     var chunks = ComputeNumChunks(length);
-    var numSlices = ForkJoinSlices();
-    if (chunks < numSlices * 2)
+    var numWorkers = ForkJoinNumWorkers();
+    if (chunks < numWorkers * 2)
       break parallel;
 
+    var numSlices = ComputeNumSlices(numWorkers, length, chunks);
     var info = ComputeAllSliceBounds(chunks, numSlices);
 
     // Step 1. Compute which items from each slice of the result
     // buffer should be preserved. When we're done, we have an array
     // |survivors| containing a bitset for each chunk, indicating
     // which members of the chunk survived. We also keep an array
     // |counts| containing the total number of items that are being
     // preserved from within one slice.
     //
     // FIXME(bug 844890): Use typed arrays here.
     var counts = NewDenseArray(numSlices);
     for (var i = 0; i < numSlices; i++)
       UnsafePutElements(counts, i, 0);
     var survivors = NewDenseArray(chunks);
-    ForkJoin(findSurvivorsInSlice, ForkJoinMode(mode));
+    ForkJoin(findSurvivorsInSlice, ForkJoinMode(mode), numSlices);
 
     // Step 2. Compress the slices into one contiguous set.
     var count = 0;
     for (var i = 0; i < numSlices; i++)
       count += counts[i];
     var buffer = NewDenseArray(count);
     if (count > 0)
-      ForkJoin(copySurvivorsInSlice, ForkJoinMode(mode));
+      ForkJoin(copySurvivorsInSlice, ForkJoinMode(mode), numSlices);
 
     return buffer;
   }
 
   // Sequential fallback:
   ASSERT_SEQUENTIAL_IS_OK(mode);
   var buffer = [];
   for (var i = 0; i < length; i++) {
@@ -1317,17 +1338,17 @@ function ArrayFilterPar(func, mode) {
   return buffer;
 
   /**
    * As described above, our goal is to determine which items we
    * will preserve from a given slice. We do this one chunk at a
    * time. When we finish a chunk, we record our current count and
    * the next chunk sliceId, lest we should bail.
    */
-  function findSurvivorsInSlice(sliceId, numSlices, warmup) {
+  function findSurvivorsInSlice(sliceId, warmup) {
     var chunkPos = info[SLICE_POS(sliceId)];
     var chunkEnd = info[SLICE_END(sliceId)];
 
     if (warmup && chunkEnd > chunkPos)
       chunkEnd = chunkPos + 1;
 
     var count = counts[sliceId];
     while (chunkPos < chunkEnd) {
@@ -1344,17 +1365,17 @@ function ArrayFilterPar(func, mode) {
       UnsafePutElements(survivors, chunkPos, chunkBits,
                         counts, sliceId, count,
                         info, SLICE_POS(sliceId), ++chunkPos);
     }
 
     return chunkEnd === info[SLICE_END(sliceId)];
   }
 
-  function copySurvivorsInSlice(sliceId, numSlices, warmup) {
+  function copySurvivorsInSlice(sliceId, warmup) {
     // Copies the survivors from this slice into the correct position.
     // Note that this is an idempotent operation that does not invoke
     // user code. Therefore, we don't expect bailouts and make an
     // effort to proceed chunk by chunk or avoid duplicating work.
 
     // Total up the items preserved by previous slices.
     var count = 0;
     if (sliceId > 0) { // FIXME(#819219)---work around a bug in Ion's range checks
@@ -1427,28 +1448,29 @@ function ArrayStaticBuildPar(length, fun
 
   parallel: for (;;) {
     if (ShouldForceSequential())
       break parallel;
     if (!TRY_PARALLEL(mode))
       break parallel;
 
     var chunks = ComputeNumChunks(length);
-    var numSlices = ForkJoinSlices();
+    var numWorkers = ForkJoinNumWorkers();
+    var numSlices = ComputeNumSlices(numWorkers, length, chunks);
     var info = ComputeAllSliceBounds(chunks, numSlices);
-    ForkJoin(constructSlice, ForkJoinMode(mode));
+    ForkJoin(constructSlice, ForkJoinMode(mode), numSlices);
     return buffer;
   }
 
   // Sequential fallback:
   ASSERT_SEQUENTIAL_IS_OK(mode);
   fill(0, length);
   return buffer;
 
-  function constructSlice(sliceId, numSlices, warmup) {
+  function constructSlice(sliceId, warmup) {
     var chunkPos = info[SLICE_POS(sliceId)];
     var chunkEnd = info[SLICE_END(sliceId)];
 
     if (warmup && chunkEnd > chunkPos)
       chunkEnd = chunkPos + 1;
 
     while (chunkPos < chunkEnd) {
       var indexStart = chunkPos << CHUNK_SHIFT;
--- a/js/src/config/rules.mk
+++ b/js/src/config/rules.mk
@@ -119,19 +119,16 @@ SIMPLE_PROGRAMS += $(CPP_UNIT_TEST_BINS)
 INCLUDES += -I$(DIST)/include/testing
 LIBS += $(XPCOM_GLUE_LDOPTS) $(NSPR_LIBS)
 
 ifndef MOZ_PROFILE_GENERATE
 libs:: $(CPP_UNIT_TEST_BINS) $(call mkdir_deps,$(DIST)/cppunittests)
 	$(NSINSTALL) $(CPP_UNIT_TEST_BINS) $(DIST)/cppunittests
 endif
 
-check::
-	@$(PYTHON) $(topsrcdir)/testing/runcppunittests.py --xre-path=$(DIST)/bin --symbols-path=$(DIST)/crashreporter-symbols $(subst .cpp,$(BIN_SUFFIX),$(CPP_UNIT_TESTS))
-
 cppunittests-remote: DM_TRANS?=adb
 cppunittests-remote:
 	@if [ '${TEST_DEVICE}' != '' -o '$(DM_TRANS)' = 'adb' ]; then \
 		$(PYTHON) -u $(topsrcdir)/testing/remotecppunittests.py \
 			--xre-path=$(DEPTH)/dist/bin \
 			--localLib=$(DEPTH)/dist/$(MOZ_APP_NAME) \
 			--dm_trans=$(DM_TRANS) \
 			--deviceIP=${TEST_DEVICE} \
--- a/js/src/frontend/BytecodeCompiler.cpp
+++ b/js/src/frontend/BytecodeCompiler.cpp
@@ -67,17 +67,19 @@ CheckArgumentsWithinEval(JSContext *cx, 
         // It's an error to use |arguments| in a function that has a rest
         // parameter.
         parser.report(ParseError, false, nullptr, JSMSG_ARGUMENTS_AND_REST);
         return false;
     }
 
     // Force construction of arguments objects for functions that use
     // |arguments| within an eval.
-    RootedScript script(cx, fun->nonLazyScript());
+    RootedScript script(cx, fun->getOrCreateScript(cx));
+    if (!script)
+        return false;
     if (script->argumentsHasVarBinding()) {
         if (!JSScript::argumentsOptimizationFailed(cx, script))
             return false;
     }
 
     // It's an error to use |arguments| in a legacy generator expression.
     if (script->isGeneratorExp() && script->isLegacyGenerator()) {
         parser.report(ParseError, false, nullptr, JSMSG_BAD_GENEXP_BODY, js_arguments_str);
@@ -118,17 +120,19 @@ MaybeCheckEvalFreeVariables(ExclusiveCon
     // If the eval'ed script contains any debugger statement, force construction
     // of arguments objects for the caller script and any other scripts it is
     // transitively nested inside. The debugger can access any variable on the
     // scope chain.
     if (pc.sc->hasDebuggerStatement()) {
         RootedObject scope(cx, scopeChain);
         while (scope->is<ScopeObject>() || scope->is<DebugScopeObject>()) {
             if (scope->is<CallObject>() && !scope->as<CallObject>().isForEval()) {
-                RootedScript script(cx, scope->as<CallObject>().callee().nonLazyScript());
+                RootedScript script(cx, scope->as<CallObject>().callee().getOrCreateScript(cx));
+                if (!script)
+                    return false;
                 if (script->argumentsHasVarBinding()) {
                     if (!JSScript::argumentsOptimizationFailed(cx, script))
                         return false;
                 }
             }
             scope = scope->enclosingScope();
         }
     }
@@ -230,20 +234,18 @@ frontend::CompileScript(ExclusiveContext
     Parser<FullParseHandler> parser(cx, alloc, options, chars, length, /* foldConstants = */ true,
                                     canLazilyParse ? &syntaxParser.ref() : nullptr, nullptr);
     parser.sct = sct;
     parser.ss = ss;
 
     Directives directives(options.strictOption);
     GlobalSharedContext globalsc(cx, scopeChain, directives, options.extraWarningsOption);
 
-    bool savedCallerFun =
-        options.compileAndGo &&
-        evalCaller &&
-        (evalCaller->function() || evalCaller->savedCallerFun());
+    bool savedCallerFun = options.compileAndGo &&
+                          evalCaller && evalCaller->functionOrCallerFunction();
     Rooted<JSScript*> script(cx, JSScript::Create(cx, NullPtr(), savedCallerFun,
                                                   options, staticLevel, sourceObject, 0, length));
     if (!script)
         return nullptr;
 
     // Global/eval script bindings are always empty (all names are added to the
     // scope dynamically via JSOP_DEFFUN/VAR).
     InternalHandle<Bindings*> bindings(script, &script->bindings);
@@ -399,17 +401,17 @@ frontend::CompileScript(ExclusiveContext
         return nullptr;
 
     return script;
 }
 
 bool
 frontend::CompileLazyFunction(JSContext *cx, Handle<LazyScript*> lazy, const jschar *chars, size_t length)
 {
-    JS_ASSERT(cx->compartment() == lazy->function()->compartment());
+    JS_ASSERT(cx->compartment() == lazy->functionNonDelazifying()->compartment());
 
     CompileOptions options(cx, lazy->version());
     options.setPrincipals(cx->compartment()->principals)
            .setOriginPrincipals(lazy->originPrincipals())
            .setFileAndLine(lazy->source()->filename(), lazy->lineno())
            .setColumn(lazy->column())
            .setCompileAndGo(true)
            .setNoScriptRval(false)
@@ -422,17 +424,17 @@ frontend::CompileLazyFunction(JSContext 
                                 options);
 #endif
 
     Parser<FullParseHandler> parser(cx, &cx->tempLifoAlloc(), options, chars, length,
                                     /* foldConstants = */ true, nullptr, lazy);
 
     uint32_t staticLevel = lazy->staticLevel(cx);
 
-    Rooted<JSFunction*> fun(cx, lazy->function());
+    Rooted<JSFunction*> fun(cx, lazy->functionNonDelazifying());
     JS_ASSERT(!lazy->isLegacyGenerator());
     ParseNode *pn = parser.standaloneLazyFunction(fun, staticLevel, lazy->strict(),
                                                   lazy->generatorKind());
     if (!pn)
         return false;
 
     if (!NameFunctions(cx, pn))
         return false;
--- a/js/src/frontend/BytecodeEmitter.cpp
+++ b/js/src/frontend/BytecodeEmitter.cpp
@@ -1280,17 +1280,17 @@ TryConvertFreeName(BytecodeEmitter *bce,
                     // Use generic ops if a catch block is encountered.
                     return false;
                 }
                 if (ssi.hasDynamicScopeObject())
                     hops++;
                 continue;
             }
             RootedScript script(bce->sc->context, ssi.funScript());
-            if (script->function()->atom() == pn->pn_atom)
+            if (script->functionNonDelazifying()->atom() == pn->pn_atom)
                 return false;
             if (ssi.hasDynamicScopeObject()) {
                 uint16_t slot;
                 if (LookupAliasedName(script, pn->pn_atom->asPropertyName(), &slot)) {
                     JSOp op;
                     switch (pn->getOp()) {
                       case JSOP_NAME:     op = JSOP_GETALIASEDVAR; break;
                       case JSOP_SETNAME:  op = JSOP_SETALIASEDVAR; break;
@@ -1862,17 +1862,17 @@ BytecodeEmitter::needsImplicitThis()
 void
 BytecodeEmitter::tellDebuggerAboutCompiledScript(ExclusiveContext *cx)
 {
     // Note: when parsing off thread the resulting scripts need to be handed to
     // the debugger after rejoining to the main thread.
     if (!cx->isJSContext())
         return;
 
-    RootedFunction function(cx, script->function());
+    RootedFunction function(cx, script->functionNonDelazifying());
     CallNewScriptHook(cx->asJSContext(), script, function);
     // Lazy scripts are never top level (despite always being invoked with a
     // nullptr parent), and so the hook should never be fired.
     if (emitterMode != LazyFunction && !parent) {
         GlobalObject *compileAndGoGlobal = nullptr;
         if (script->compileAndGo())
             compileAndGoGlobal = &script->global();
         Debugger::onNewScript(cx->asJSContext(), script, compileAndGoGlobal);
@@ -2790,17 +2790,17 @@ frontend::EmitFunctionScript(ExclusiveCo
      * initializers created within it may be given more precise types.
      */
     if (runOnce) {
         bce->script->setTreatAsRunOnce();
         JS_ASSERT(!bce->script->hasRunOnce());
     }
 
     /* Initialize fun->script() so that the debugger has a valid fun->script(). */
-    RootedFunction fun(cx, bce->script->function());
+    RootedFunction fun(cx, bce->script->functionNonDelazifying());
     JS_ASSERT(fun->isInterpreted());
 
     if (fun->isInterpretedLazy()) {
         AutoLockForCompilation lock(cx);
         fun->setUnlazifiedScript(bce->script);
     } else {
         fun->setScript(bce->script);
     }
--- a/js/src/gc/Nursery.cpp
+++ b/js/src/gc/Nursery.cpp
@@ -98,18 +98,20 @@ js::Nursery::disable()
     numActiveChunks_ = 0;
     currentEnd_ = 0;
 }
 
 bool
 js::Nursery::isEmpty() const
 {
     JS_ASSERT(runtime_);
+    if (!isEnabled())
+        return true;
     JS_ASSERT_IF(runtime_->gcZeal_ != ZealGenerationalGCValue, currentStart_ == start());
-    return !isEnabled() || position() == currentStart_;
+    return position() == currentStart_;
 }
 
 void *
 js::Nursery::allocate(size_t size)
 {
     JS_ASSERT(isEnabled());
     JS_ASSERT(!runtime()->isHeapBusy());
 
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/basic/regexp-match-limit.js
@@ -0,0 +1,9 @@
+// See bug 953013
+
+load(libdir + "asserts.js");
+
+function test() {
+    var input = Array(999999+1).join('a');
+    var result = /^([\w])+$/.test(input);
+}
+assertThrowsInstanceOf(test, InternalError);
--- a/js/src/jit-test/tests/basic/string-endswith.js
+++ b/js/src/jit-test/tests/basic/string-endswith.js
@@ -1,39 +1,262 @@
-assertEq("abc".endsWith("abc"), true);
-assertEq("abcd".endsWith("bcd"), true);
-assertEq("abc".endsWith("c"), true);
-assertEq("abc".endsWith("abcd"), false);
-assertEq("abc".endsWith("bbc"), false);
-assertEq("abc".endsWith("b"), false);
-assertEq("abc".endsWith("abc", 3), true);
-assertEq("abc".endsWith("bc", 3), true);
-assertEq("abc".endsWith("a", 3), false);
-assertEq("abc".endsWith("bc", 3), true);
-assertEq("abc".endsWith("a", 1), true);
-assertEq("abc".endsWith("abc", 1), false);
-assertEq("abc".endsWith("b", 2), true);
-assertEq("abc".endsWith("d", 2), false);
-assertEq("abc".endsWith("dcd", 2), false);
-assertEq("abc".endsWith("a", 42), false);
-assertEq("abc".endsWith("bc", Infinity), true);
-assertEq("abc".endsWith("a", Infinity), false);
-assertEq("abc".endsWith("bc", undefined), true);
-assertEq("abc".endsWith("bc", -43), false);
-assertEq("abc".endsWith("bc", -Infinity), false);
-assertEq("abc".endsWith("bc", NaN), false);
-var myobj = {toString : (function () "abc"), endsWith : String.prototype.endsWith};
-assertEq(myobj.endsWith("abc"), true);
-assertEq(myobj.endsWith("ab"), false);
-var gotStr = false, gotPos = false;
-myobj = {toString : (function () {
-    assertEq(gotPos, false);
-    gotStr = true;
-    return "xyz";
-}),
-endsWith : String.prototype.endsWith};
-var idx = {valueOf : (function () {
-    assertEq(gotStr, true);
-    gotPos = true;
-    return 42;
-})};
-myobj.endsWith("elephant", idx);
-assertEq(gotPos, true);
+/*
+* Copyright (c) 2013 Mathias Bynens. All rights reserved.
+*
+* Permission is hereby granted, free of charge, to any person obtaining a
+* copy of this software and associated documentation files (the "Software"),
+* to deal in the Software without restriction, including without limitation
+* the rights to use, copy, modify, merge, publish, distribute, sublicense,
+* and/or sell copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following conditions:
+*
+* The above copyright notice and this permission notice shall be included in
+* all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+* DEALINGS IN THE SOFTWARE.
+*/
+
+function assertThrows(fun, errorType) {
+  try {
+    fun();
+    assertEq(true, false, "Expected error, but none was thrown");
+  } catch (e) {
+    assertEq(e instanceof errorType, true, "Wrong error type thrown");
+  }
+}
+assertEq(String.prototype.endsWith.length, 1);
+assertEq(String.prototype.propertyIsEnumerable('endsWith'), false);
+
+assertEq('undefined'.endsWith(), true);
+assertEq('undefined'.endsWith(undefined), true);
+assertEq('undefined'.endsWith(null), false);
+assertEq('null'.endsWith(), false);
+assertEq('null'.endsWith(undefined), false);
+assertEq('null'.endsWith(null), true);
+
+assertEq('abc'.endsWith(), false);
+assertEq('abc'.endsWith(''), true);
+assertEq('abc'.endsWith('\0'), false);
+assertEq('abc'.endsWith('c'), true);
+assertEq('abc'.endsWith('b'), false);
+assertEq('abc'.endsWith('a'), false);
+assertEq('abc'.endsWith('ab'), false);
+assertEq('abc'.endsWith('bc'), true);
+assertEq('abc'.endsWith('abc'), true);
+assertEq('abc'.endsWith('bcd'), false);
+assertEq('abc'.endsWith('abcd'), false);
+assertEq('abc'.endsWith('bcde'), false);
+
+assertEq('abc'.endsWith('', NaN), true);
+assertEq('abc'.endsWith('\0', NaN), false);
+assertEq('abc'.endsWith('c', NaN), false);
+assertEq('abc'.endsWith('b', NaN), false);
+assertEq('abc'.endsWith('a', NaN), false);
+assertEq('abc'.endsWith('ab', NaN), false);
+assertEq('abc'.endsWith('bc', NaN), false);
+assertEq('abc'.endsWith('abc', NaN), false);
+assertEq('abc'.endsWith('bcd', NaN), false);
+assertEq('abc'.endsWith('abcd', NaN), false);
+assertEq('abc'.endsWith('bcde', NaN), false);
+
+assertEq('abc'.endsWith('', false), true);
+assertEq('abc'.endsWith('\0', false), false);
+assertEq('abc'.endsWith('c', false), false);
+assertEq('abc'.endsWith('b', false), false);
+assertEq('abc'.endsWith('a', false), false);
+assertEq('abc'.endsWith('ab', false), false);
+assertEq('abc'.endsWith('bc', false), false);
+assertEq('abc'.endsWith('abc', false), false);
+assertEq('abc'.endsWith('bcd', false), false);
+assertEq('abc'.endsWith('abcd', false), false);
+assertEq('abc'.endsWith('bcde', false), false);
+
+assertEq('abc'.endsWith('', undefined), true);
+assertEq('abc'.endsWith('\0', undefined), false);
+assertEq('abc'.endsWith('c', undefined), true);
+assertEq('abc'.endsWith('b', undefined), false);
+assertEq('abc'.endsWith('a', undefined), false);
+assertEq('abc'.endsWith('ab', undefined), false);
+assertEq('abc'.endsWith('bc', undefined), true);
+assertEq('abc'.endsWith('abc', undefined), true);
+assertEq('abc'.endsWith('bcd', undefined), false);
+assertEq('abc'.endsWith('abcd', undefined), false);
+assertEq('abc'.endsWith('bcde', undefined), false);
+
+assertEq('abc'.endsWith('', null), true);
+assertEq('abc'.endsWith('\0', null), false);
+assertEq('abc'.endsWith('c', null), false);
+assertEq('abc'.endsWith('b', null), false);
+assertEq('abc'.endsWith('a', null), false);
+assertEq('abc'.endsWith('ab', null), false);
+assertEq('abc'.endsWith('bc', null), false);
+assertEq('abc'.endsWith('abc', null), false);
+assertEq('abc'.endsWith('bcd', null), false);
+assertEq('abc'.endsWith('abcd', null), false);
+assertEq('abc'.endsWith('bcde', null), false);
+
+assertEq('abc'.endsWith('', -Infinity), true);
+assertEq('abc'.endsWith('\0', -Infinity), false);
+assertEq('abc'.endsWith('c', -Infinity), false);
+assertEq('abc'.endsWith('b', -Infinity), false);
+assertEq('abc'.endsWith('a', -Infinity), false);
+assertEq('abc'.endsWith('ab', -Infinity), false);
+assertEq('abc'.endsWith('bc', -Infinity), false);
+assertEq('abc'.endsWith('abc', -Infinity), false);
+assertEq('abc'.endsWith('bcd', -Infinity), false);
+assertEq('abc'.endsWith('abcd', -Infinity), false);
+assertEq('abc'.endsWith('bcde', -Infinity), false);
+
+assertEq('abc'.endsWith('', -1), true);
+assertEq('abc'.endsWith('\0', -1), false);
+assertEq('abc'.endsWith('c', -1), false);
+assertEq('abc'.endsWith('b', -1), false);
+assertEq('abc'.endsWith('a', -1), false);
+assertEq('abc'.endsWith('ab', -1), false);
+assertEq('abc'.endsWith('bc', -1), false);
+assertEq('abc'.endsWith('abc', -1), false);
+assertEq('abc'.endsWith('bcd', -1), false);
+assertEq('abc'.endsWith('abcd', -1), false);
+assertEq('abc'.endsWith('bcde', -1), false);
+
+assertEq('abc'.endsWith('', -0), true);
+assertEq('abc'.endsWith('\0', -0), false);
+assertEq('abc'.endsWith('c', -0), false);
+assertEq('abc'.endsWith('b', -0), false);
+assertEq('abc'.endsWith('a', -0), false);
+assertEq('abc'.endsWith('ab', -0), false);
+assertEq('abc'.endsWith('bc', -0), false);
+assertEq('abc'.endsWith('abc', -0), false);
+assertEq('abc'.endsWith('bcd', -0), false);
+assertEq('abc'.endsWith('abcd', -0), false);
+assertEq('abc'.endsWith('bcde', -0), false);
+
+assertEq('abc'.endsWith('', +0), true);
+assertEq('abc'.endsWith('\0', +0), false);
+assertEq('abc'.endsWith('c', +0), false);
+assertEq('abc'.endsWith('b', +0), false);
+assertEq('abc'.endsWith('a', +0), false);
+assertEq('abc'.endsWith('ab', +0), false);
+assertEq('abc'.endsWith('bc', +0), false);
+assertEq('abc'.endsWith('abc', +0), false);
+assertEq('abc'.endsWith('bcd', +0), false);
+assertEq('abc'.endsWith('abcd', +0), false);
+assertEq('abc'.endsWith('bcde', +0), false);
+
+assertEq('abc'.endsWith('', 1), true);
+assertEq('abc'.endsWith('\0', 1), false);
+assertEq('abc'.endsWith('c', 1), false);
+assertEq('abc'.endsWith('b', 1), false);
+assertEq('abc'.endsWith('ab', 1), false);
+assertEq('abc'.endsWith('bc', 1), false);
+assertEq('abc'.endsWith('abc', 1), false);
+assertEq('abc'.endsWith('bcd', 1), false);
+assertEq('abc'.endsWith('abcd', 1), false);
+assertEq('abc'.endsWith('bcde', 1), false);
+
+assertEq('abc'.endsWith('', 2), true);
+assertEq('abc'.endsWith('\0', 2), false);
+assertEq('abc'.endsWith('c', 2), false);
+assertEq('abc'.endsWith('b', 2), true);
+assertEq('abc'.endsWith('ab', 2), true);
+assertEq('abc'.endsWith('bc', 2), false);
+assertEq('abc'.endsWith('abc', 2), false);
+assertEq('abc'.endsWith('bcd', 2), false);
+assertEq('abc'.endsWith('abcd', 2), false);
+assertEq('abc'.endsWith('bcde', 2), false);
+
+assertEq('abc'.endsWith('', +Infinity), true);
+assertEq('abc'.endsWith('\0', +Infinity), false);
+assertEq('abc'.endsWith('c', +Infinity), true);
+assertEq('abc'.endsWith('b', +Infinity), false);
+assertEq('abc'.endsWith('a', +Infinity), false);
+assertEq('abc'.endsWith('ab', +Infinity), false);
+assertEq('abc'.endsWith('bc', +Infinity), true);
+assertEq('abc'.endsWith('abc', +Infinity), true);
+assertEq('abc'.endsWith('bcd', +Infinity), false);
+assertEq('abc'.endsWith('abcd', +Infinity), false);
+assertEq('abc'.endsWith('bcde', +Infinity), false);
+
+assertEq('abc'.endsWith('', true), true);
+assertEq('abc'.endsWith('\0', true), false);
+assertEq('abc'.endsWith('c', true), false);
+assertEq('abc'.endsWith('b', true), false);
+assertEq('abc'.endsWith('ab', true), false);
+assertEq('abc'.endsWith('bc', true), false);
+assertEq('abc'.endsWith('abc', true), false);
+assertEq('abc'.endsWith('bcd', true), false);
+assertEq('abc'.endsWith('abcd', true), false);
+assertEq('abc'.endsWith('bcde', true), false);
+
+assertEq('abc'.endsWith('', 'x'), true);
+assertEq('abc'.endsWith('\0', 'x'), false);
+assertEq('abc'.endsWith('c', 'x'), false);
+assertEq('abc'.endsWith('b', 'x'), false);
+assertEq('abc'.endsWith('a', 'x'), false);
+assertEq('abc'.endsWith('ab', 'x'), false);
+assertEq('abc'.endsWith('bc', 'x'), false);
+assertEq('abc'.endsWith('abc', 'x'), false);
+assertEq('abc'.endsWith('bcd', 'x'), false);
+assertEq('abc'.endsWith('abcd', 'x'), false);
+assertEq('abc'.endsWith('bcde', 'x'), false);
+
+assertEq('[a-z]+(bar)?'.endsWith('(bar)?'), true);
+assertThrows(function() { '[a-z]+(bar)?'.endsWith(/(bar)?/); }, TypeError);
+assertEq('[a-z]+(bar)?'.endsWith('[a-z]+', 6), true);
+assertThrows(function() { '[a-z]+(bar)?'.endsWith(/(bar)?/); }, TypeError);
+assertThrows(function() { '[a-z]+/(bar)?/'.endsWith(/(bar)?/); }, TypeError);
+var global = newGlobal();
+global.eval('this.re = /(bar)?/');
+assertThrows(function() { '[a-z]+/(bar)?/'.endsWith(global.re); }, TypeError);
+
+// http://mathiasbynens.be/notes/javascript-unicode#poo-test
+var string = 'I\xF1t\xEBrn\xE2ti\xF4n\xE0liz\xE6ti\xF8n\u2603\uD83D\uDCA9';
+assertEq(string.endsWith(''), true);
+assertEq(string.endsWith('\xF1t\xEBr'), false);
+assertEq(string.endsWith('\xF1t\xEBr', 5), true);
+assertEq(string.endsWith('\xE0liz\xE6'), false);
+assertEq(string.endsWith('\xE0liz\xE6', 16), true);
+assertEq(string.endsWith('\xF8n\u2603\uD83D\uDCA9'), true);
+assertEq(string.endsWith('\xF8n\u2603\uD83D\uDCA9', 23), true);
+assertEq(string.endsWith('\u2603'), false);
+assertEq(string.endsWith('\u2603', 21), true);
+assertEq(string.endsWith('\uD83D\uDCA9'), true);
+assertEq(string.endsWith('\uD83D\uDCA9', 23), true);
+
+assertThrows(function() { String.prototype.endsWith.call(undefined); }, TypeError);
+assertThrows(function() { String.prototype.endsWith.call(undefined, 'b'); }, TypeError);
+assertThrows(function() { String.prototype.endsWith.call(undefined, 'b', 4); }, TypeError);
+assertThrows(function() { String.prototype.endsWith.call(null); }, TypeError);
+assertThrows(function() { String.prototype.endsWith.call(null, 'b'); }, TypeError);
+assertThrows(function() { String.prototype.endsWith.call(null, 'b', 4); }, TypeError);
+assertEq(String.prototype.endsWith.call(42, '2'), true);
+assertEq(String.prototype.endsWith.call(42, '4'), false);
+assertEq(String.prototype.endsWith.call(42, 'b', 4), false);
+assertEq(String.prototype.endsWith.call(42, '2', 1), false);
+assertEq(String.prototype.endsWith.call(42, '2', 4), true);
+assertEq(String.prototype.endsWith.call({ 'toString': function() { return 'abc'; } }, 'b', 0), false);
+assertEq(String.prototype.endsWith.call({ 'toString': function() { return 'abc'; } }, 'b', 1), false);
+assertEq(String.prototype.endsWith.call({ 'toString': function() { return 'abc'; } }, 'b', 2), true);
+assertThrows(function() { String.prototype.endsWith.call({ 'toString': function() { throw RangeError(); } }, /./); }, RangeError);
+assertThrows(function() { String.prototype.endsWith.call({ 'toString': function() { return 'abc' } }, /./); }, TypeError);
+
+assertThrows(function() { String.prototype.endsWith.apply(undefined); }, TypeError);
+assertThrows(function() { String.prototype.endsWith.apply(undefined, ['b']); }, TypeError);
+assertThrows(function() { String.prototype.endsWith.apply(undefined, ['b', 4]); }, TypeError);
+assertThrows(function() { String.prototype.endsWith.apply(null); }, TypeError);
+assertThrows(function() { String.prototype.endsWith.apply(null, ['b']); }, TypeError);
+assertThrows(function() { String.prototype.endsWith.apply(null, ['b', 4]); }, TypeError);
+assertEq(String.prototype.endsWith.apply(42, ['2']), true);
+assertEq(String.prototype.endsWith.apply(42, ['4']), false);
+assertEq(String.prototype.endsWith.apply(42, ['b', 4]), false);
+assertEq(String.prototype.endsWith.apply(42, ['2', 1]), false);
+assertEq(String.prototype.endsWith.apply(42, ['2', 4]), true);
+assertEq(String.prototype.endsWith.apply({ 'toString': function() { return 'abc'; } }, ['b', 0]), false);
+assertEq(String.prototype.endsWith.apply({ 'toString': function() { return 'abc'; } }, ['b', 1]), false);
+assertEq(String.prototype.endsWith.apply({ 'toString': function() { return 'abc'; } }, ['b', 2]), true);
+assertThrows(function() { String.prototype.endsWith.apply({ 'toString': function() { throw RangeError(); } }, [/./]); }, RangeError);
+assertThrows(function() { String.prototype.endsWith.apply({ 'toString': function() { return 'abc' } }, [/./]); }, TypeError);
--- a/js/src/jit-test/tests/basic/string-startswith.js
+++ b/js/src/jit-test/tests/basic/string-startswith.js
@@ -1,39 +1,243 @@
-assertEq("abc".startsWith("abc"), true);
-assertEq("abcd".startsWith("abc"), true);
-assertEq("abc".startsWith("a"), true);
-assertEq("abc".startsWith("abcd"), false);
-assertEq("abc".startsWith("bcde"), false);
-assertEq("abc".startsWith("b"), false);
-assertEq("abc".startsWith("abc", 0), true);
-assertEq("abc".startsWith("bc", 0), false);
-assertEq("abc".startsWith("bc", 1), true);
-assertEq("abc".startsWith("c", 1), false);
-assertEq("abc".startsWith("abc", 1), false);
-assertEq("abc".startsWith("c", 2), true);
-assertEq("abc".startsWith("d", 2), false);
-assertEq("abc".startsWith("dcd", 2), false);
-assertEq("abc".startsWith("a", 42), false);
-assertEq("abc".startsWith("a", Infinity), false);
-assertEq("abc".startsWith("a", NaN), true);
-assertEq("abc".startsWith("b", NaN), false);
-assertEq("abc".startsWith("ab", -43), true);
-assertEq("abc".startsWith("ab", -Infinity), true);
-assertEq("abc".startsWith("bc", -42), false);
-assertEq("abc".startsWith("bc", -Infinity), false);
-var myobj = {toString : (function () "abc"), startsWith : String.prototype.startsWith};
-assertEq(myobj.startsWith("abc"), true);
-assertEq(myobj.startsWith("bc"), false);
-var gotStr = false, gotPos = false;
-myobj = {toString : (function () {
-    assertEq(gotPos, false);
-    gotStr = true;
-    return "xyz";
-}),
-startsWith : String.prototype.startsWith};
-var idx = {valueOf : (function () {
-    assertEq(gotStr, true);
-    gotPos = true;
-    return 42;
-})};
-myobj.startsWith("elephant", idx);
-assertEq(gotPos, true);
+/*
+* Copyright (c) 2013 Mathias Bynens. All rights reserved.
+*
+* Permission is hereby granted, free of charge, to any person obtaining a
+* copy of this software and associated documentation files (the "Software"),
+* to deal in the Software without restriction, including without limitation
+* the rights to use, copy, modify, merge, publish, distribute, sublicense,
+* and/or sell copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following conditions:
+*
+* The above copyright notice and this permission notice shall be included in
+* all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+* DEALINGS IN THE SOFTWARE.
+*/
+
+function assertThrows(fun, errorType) {
+  try {
+    fun();
+    assertEq(true, false, "Expected error, but none was thrown");
+  } catch (e) {
+    assertEq(e instanceof errorType, true, "Wrong error type thrown");
+  }
+}
+
+Object.prototype[1] = 2; // try to break `arguments[1]`
+
+assertEq(String.prototype.startsWith.length, 1);
+assertEq(String.prototype.propertyIsEnumerable('startsWith'), false);
+
+assertEq('undefined'.startsWith(), true);
+assertEq('undefined'.startsWith(undefined), true);
+assertEq('undefined'.startsWith(null), false);
+assertEq('null'.startsWith(), false);
+assertEq('null'.startsWith(undefined), false);
+assertEq('null'.startsWith(null), true);
+
+assertEq('abc'.startsWith(), false);
+assertEq('abc'.startsWith(''), true);
+assertEq('abc'.startsWith('\0'), false);
+assertEq('abc'.startsWith('a'), true);
+assertEq('abc'.startsWith('b'), false);
+assertEq('abc'.startsWith('ab'), true);
+assertEq('abc'.startsWith('bc'), false);
+assertEq('abc'.startsWith('abc'), true);
+assertEq('abc'.startsWith('bcd'), false);
+assertEq('abc'.startsWith('abcd'), false);
+assertEq('abc'.startsWith('bcde'), false);
+
+assertEq('abc'.startsWith('', NaN), true);
+assertEq('abc'.startsWith('\0', NaN), false);
+assertEq('abc'.startsWith('a', NaN), true);
+assertEq('abc'.startsWith('b', NaN), false);
+assertEq('abc'.startsWith('ab', NaN), true);
+assertEq('abc'.startsWith('bc', NaN), false);
+assertEq('abc'.startsWith('abc', NaN), true);
+assertEq('abc'.startsWith('bcd', NaN), false);
+assertEq('abc'.startsWith('abcd', NaN), false);
+assertEq('abc'.startsWith('bcde', NaN), false);
+
+assertEq('abc'.startsWith('', false), true);
+assertEq('abc'.startsWith('\0', false), false);
+assertEq('abc'.startsWith('a', false), true);
+assertEq('abc'.startsWith('b', false), false);
+assertEq('abc'.startsWith('ab', false), true);
+assertEq('abc'.startsWith('bc', false), false);
+assertEq('abc'.startsWith('abc', false), true);
+assertEq('abc'.startsWith('bcd', false), false);
+assertEq('abc'.startsWith('abcd', false), false);
+assertEq('abc'.startsWith('bcde', false), false);
+
+assertEq('abc'.startsWith('', undefined), true);
+assertEq('abc'.startsWith('\0', undefined), false);
+assertEq('abc'.startsWith('a', undefined), true);
+assertEq('abc'.startsWith('b', undefined), false);
+assertEq('abc'.startsWith('ab', undefined), true);
+assertEq('abc'.startsWith('bc', undefined), false);
+assertEq('abc'.startsWith('abc', undefined), true);
+assertEq('abc'.startsWith('bcd', undefined), false);
+assertEq('abc'.startsWith('abcd', undefined), false);
+assertEq('abc'.startsWith('bcde', undefined), false);
+
+assertEq('abc'.startsWith('', null), true);
+assertEq('abc'.startsWith('\0', null), false);
+assertEq('abc'.startsWith('a', null), true);
+assertEq('abc'.startsWith('b', null), false);
+assertEq('abc'.startsWith('ab', null), true);
+assertEq('abc'.startsWith('bc', null), false);
+assertEq('abc'.startsWith('abc', null), true);
+assertEq('abc'.startsWith('bcd', null), false);
+assertEq('abc'.startsWith('abcd', null), false);
+assertEq('abc'.startsWith('bcde', null), false);
+
+assertEq('abc'.startsWith('', -Infinity), true);
+assertEq('abc'.startsWith('\0', -Infinity), false);
+assertEq('abc'.startsWith('a', -Infinity), true);
+assertEq('abc'.startsWith('b', -Infinity), false);
+assertEq('abc'.startsWith('ab', -Infinity), true);
+assertEq('abc'.startsWith('bc', -Infinity), false);
+assertEq('abc'.startsWith('abc', -Infinity), true);
+assertEq('abc'.startsWith('bcd', -Infinity), false);
+assertEq('abc'.startsWith('abcd', -Infinity), false);
+assertEq('abc'.startsWith('bcde', -Infinity), false);
+
+assertEq('abc'.startsWith('', -1), true);
+assertEq('abc'.startsWith('\0', -1), false);
+assertEq('abc'.startsWith('a', -1), true);
+assertEq('abc'.startsWith('b', -1), false);
+assertEq('abc'.startsWith('ab', -1), true);
+assertEq('abc'.startsWith('bc', -1), false);
+assertEq('abc'.startsWith('abc', -1), true);
+assertEq('abc'.startsWith('bcd', -1), false);
+assertEq('abc'.startsWith('abcd', -1), false);
+assertEq('abc'.startsWith('bcde', -1), false);
+
+assertEq('abc'.startsWith('', -0), true);
+assertEq('abc'.startsWith('\0', -0), false);
+assertEq('abc'.startsWith('a', -0), true);
+assertEq('abc'.startsWith('b', -0), false);
+assertEq('abc'.startsWith('ab', -0), true);
+assertEq('abc'.startsWith('bc', -0), false);
+assertEq('abc'.startsWith('abc', -0), true);
+assertEq('abc'.startsWith('bcd', -0), false);
+assertEq('abc'.startsWith('abcd', -0), false);
+assertEq('abc'.startsWith('bcde', -0), false);
+
+assertEq('abc'.startsWith('', +0), true);
+assertEq('abc'.startsWith('\0', +0), false);
+assertEq('abc'.startsWith('a', +0), true);
+assertEq('abc'.startsWith('b', +0), false);
+assertEq('abc'.startsWith('ab', +0), true);
+assertEq('abc'.startsWith('bc', +0), false);
+assertEq('abc'.startsWith('abc', +0), true);
+assertEq('abc'.startsWith('bcd', +0), false);
+assertEq('abc'.startsWith('abcd', +0), false);
+assertEq('abc'.startsWith('bcde', +0), false);
+
+assertEq('abc'.startsWith('', 1), true);
+assertEq('abc'.startsWith('\0', 1), false);
+assertEq('abc'.startsWith('a', 1), false);
+assertEq('abc'.startsWith('b', 1), true);
+assertEq('abc'.startsWith('ab', 1), false);
+assertEq('abc'.startsWith('bc', 1), true);
+assertEq('abc'.startsWith('abc', 1), false);
+assertEq('abc'.startsWith('bcd', 1), false);
+assertEq('abc'.startsWith('abcd', 1), false);
+assertEq('abc'.startsWith('bcde', 1), false);
+
+assertEq('abc'.startsWith('', +Infinity), true);
+assertEq('abc'.startsWith('\0', +Infinity), false);
+assertEq('abc'.startsWith('a', +Infinity), false);
+assertEq('abc'.startsWith('b', +Infinity), false);
+assertEq('abc'.startsWith('ab', +Infinity), false);
+assertEq('abc'.startsWith('bc', +Infinity), false);
+assertEq('abc'.startsWith('abc', +Infinity), false);
+assertEq('abc'.startsWith('bcd', +Infinity), false);
+assertEq('abc'.startsWith('abcd', +Infinity), false);
+assertEq('abc'.startsWith('bcde', +Infinity), false);
+
+assertEq('abc'.startsWith('', true), true);
+assertEq('abc'.startsWith('\0', true), false);
+assertEq('abc'.startsWith('a', true), false);
+assertEq('abc'.startsWith('b', true), true);
+assertEq('abc'.startsWith('ab', true), false);
+assertEq('abc'.startsWith('bc', true), true);
+assertEq('abc'.startsWith('abc', true), false);
+assertEq('abc'.startsWith('bcd', true), false);
+assertEq('abc'.startsWith('abcd', true), false);
+assertEq('abc'.startsWith('bcde', true), false);
+
+assertEq('abc'.startsWith('', 'x'), true);
+assertEq('abc'.startsWith('\0', 'x'), false);
+assertEq('abc'.startsWith('a', 'x'), true);
+assertEq('abc'.startsWith('b', 'x'), false);
+assertEq('abc'.startsWith('ab', 'x'), true);
+assertEq('abc'.startsWith('bc', 'x'), false);
+assertEq('abc'.startsWith('abc', 'x'), true);
+assertEq('abc'.startsWith('bcd', 'x'), false);
+assertEq('abc'.startsWith('abcd', 'x'), false);
+assertEq('abc'.startsWith('bcde', 'x'), false);
+
+assertEq('[a-z]+(bar)?'.startsWith('[a-z]+'), true);
+assertThrows(function() { '[a-z]+(bar)?'.startsWith(/[a-z]+/); }, TypeError);
+assertEq('[a-z]+(bar)?'.startsWith('(bar)?', 6), true);
+assertThrows(function() { '[a-z]+(bar)?'.startsWith(/(bar)?/); }, TypeError);
+assertThrows(function() { '[a-z]+/(bar)?/'.startsWith(/(bar)?/); }, TypeError);
+var global = newGlobal();
+global.eval('this.re = /(bar)?/');
+assertThrows(function() { '[a-z]+/(bar)?/'.startsWith(global.re); }, TypeError);
+
+// http://mathiasbynens.be/notes/javascript-unicode#poo-test
+var string = 'I\xF1t\xEBrn\xE2ti\xF4n\xE0liz\xE6ti\xF8n\u2603\uD83D\uDCA9';
+assertEq(string.startsWith(''), true);
+assertEq(string.startsWith('\xF1t\xEBr'), false);
+assertEq(string.startsWith('\xF1t\xEBr', 1), true);
+assertEq(string.startsWith('\xE0liz\xE6'), false);
+assertEq(string.startsWith('\xE0liz\xE6', 11), true);
+assertEq(string.startsWith('\xF8n\u2603\uD83D\uDCA9'), false);
+assertEq(string.startsWith('\xF8n\u2603\uD83D\uDCA9', 18), true);
+assertEq(string.startsWith('\u2603'), false);
+assertEq(string.startsWith('\u2603', 20), true);
+assertEq(string.startsWith('\uD83D\uDCA9'), false);
+assertEq(string.startsWith('\uD83D\uDCA9', 21), true);
+
+assertThrows(function() { String.prototype.startsWith.call(undefined); }, TypeError);
+assertThrows(function() { String.prototype.startsWith.call(undefined, 'b'); }, TypeError);
+assertThrows(function() { String.prototype.startsWith.call(undefined, 'b', 4); }, TypeError);
+assertThrows(function() { String.prototype.startsWith.call(null); }, TypeError);
+assertThrows(function() { String.prototype.startsWith.call(null, 'b'); }, TypeError);
+assertThrows(function() { String.prototype.startsWith.call(null, 'b', 4); }, TypeError);
+assertEq(String.prototype.startsWith.call(42, '2'), false);
+assertEq(String.prototype.startsWith.call(42, '4'), true);
+assertEq(String.prototype.startsWith.call(42, 'b', 4), false);
+assertEq(String.prototype.startsWith.call(42, '2', 1), true);
+assertEq(String.prototype.startsWith.call(42, '2', 4), false);
+assertEq(String.prototype.startsWith.call({ 'toString': function() { return 'abc'; } }, 'b', 0), false);
+assertEq(String.prototype.startsWith.call({ 'toString': function() { return 'abc'; } }, 'b', 1), true);
+assertEq(String.prototype.startsWith.call({ 'toString': function() { return 'abc'; } }, 'b', 2), false);
+assertThrows(function() { String.prototype.startsWith.call({ 'toString': function() { throw RangeError(); } }, /./); }, RangeError);
+assertThrows(function() { String.prototype.startsWith.call({ 'toString': function() { return 'abc'; } }, /./); }, TypeError);
+
+assertThrows(function() { String.prototype.startsWith.apply(undefined); }, TypeError);
+assertThrows(function() { String.prototype.startsWith.apply(undefined, ['b']); }, TypeError);
+assertThrows(function() { String.prototype.startsWith.apply(undefined, ['b', 4]); }, TypeError);
+assertThrows(function() { String.prototype.startsWith.apply(null); }, TypeError);
+assertThrows(function() { String.prototype.startsWith.apply(null, ['b']); }, TypeError);
+assertThrows(function() { String.prototype.startsWith.apply(null, ['b', 4]); }, TypeError);
+assertEq(String.prototype.startsWith.apply(42, ['2']), false);
+assertEq(String.prototype.startsWith.apply(42, ['4']), true);
+assertEq(String.prototype.startsWith.apply(42, ['b', 4]), false);
+assertEq(String.prototype.startsWith.apply(42, ['2', 1]), true);
+assertEq(String.prototype.startsWith.apply(42, ['2', 4]), false);
+assertEq(String.prototype.startsWith.apply({ 'toString': function() { return 'abc'; } }, ['b', 0]), false);
+assertEq(String.prototype.startsWith.apply({ 'toString': function() { return 'abc'; } }, ['b', 1]), true);
+assertEq(String.prototype.startsWith.apply({ 'toString': function() { return 'abc'; } }, ['b', 2]), false);
+assertThrows(function() { String.prototype.startsWith.apply({ 'toString': function() { throw RangeError(); } }, [/./]); }, RangeError);
+assertThrows(function() { String.prototype.startsWith.apply({ 'toString': function() { return 'abc'; } }, [/./]); }, TypeError);
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/gc/bug-945275.js
@@ -0,0 +1,11 @@
+function TestCase(n) {
+  this.name = undefined;
+  this.description = undefined;
+}
+gczeal(7,1);
+eval("\
+function reportCompare() new TestCase;\
+reportCompare();\
+Object.defineProperty(Object.prototype, 'name', {});\
+reportCompare();\
+");
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/gc/bug-957110.js
@@ -0,0 +1,6 @@
+gczeal(7,1);
+try {
+gcparam("maxBytes", gcparam("gcBytes") + 4*1024);
+newGlobal("same-compartment");
+} catch(exc1) {}
+gczeal(1);
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/gc/bug-957114.js
@@ -0,0 +1,13 @@
+gczeal(7,1);
+function TestCase(n) {
+  this.name = '';
+  this.description = '';
+  this.expect = '';
+  this.actual = '';
+  this.reason = '';
+  this.passed = '';
+}
+function test() new TestCase;
+test();
+Object.defineProperty(Object.prototype, "name", {});
+test();
--- a/js/src/jit-test/tests/parallel/Array-reducePar-bail.js
+++ b/js/src/jit-test/tests/parallel/Array-reducePar-bail.js
@@ -10,17 +10,18 @@ function testReduce() {
   var aCounter = 0;
   function sum(a, b) {
     var r = a + b;
     if (r == 234) // occurs once per slice
       aCounter++;
     return r;
   }
 
-  var array = build(4096, function() { return 1; });
+  // We use a big array, to make sure that the test runs with 64 slices.
+  var array = build(8 * 4096, function() { return 1; });
   var seqResult = array.reduce(sum);
   var seqCounter = aCounter;
 
   aCounter = 0;
   var parResult = array.reducePar(sum);
   var parCounter = aCounter;
 
   assertEq(true, parCounter >= seqCounter);
--- a/js/src/jit-test/tests/parallel/bailout-executed.js
+++ b/js/src/jit-test/tests/parallel/bailout-executed.js
@@ -1,14 +1,14 @@
 load(libdir + "parallelarray-helpers.js");
 
 function makeObject(e, i, c) {
   var v = {element: e, index: i, collection: c};
 
-  if (e == 512) // note: happens once
+  if (e == 0) // note: happens once
     delete v.index;
 
   return v;
 }
 
 function test() {
   var array = range(0, 768);
   var array1 = array.map(makeObject);
--- a/js/src/jit/BaselineCompiler.cpp
+++ b/js/src/jit/BaselineCompiler.cpp
@@ -108,18 +108,18 @@ BaselineCompiler::compile()
         return Method_Error;
 
     Linker linker(masm);
     JitCode *code = linker.newCode<CanGC>(cx, JSC::BASELINE_CODE);
     if (!code)
         return Method_Error;
 
     JSObject *templateScope = nullptr;
-    if (script->function()) {
-        RootedFunction fun(cx, script->function());
+    if (script->functionNonDelazifying()) {
+        RootedFunction fun(cx, script->functionNonDelazifying());
         if (fun->isHeavyweight()) {
             templateScope = CallObject::createTemplateObject(cx, script, gc::TenuredHeap);
             if (!templateScope)
                 return Method_Error;
 
             if (fun->isNamedLambda()) {
                 RootedObject declEnvObject(cx, DeclEnvObject::createTemplateObject(cx, fun, gc::TenuredHeap));
                 if (!declEnvObject)
--- a/js/src/jit/BaselineFrame.h
+++ b/js/src/jit/BaselineFrame.h
@@ -177,17 +177,17 @@ class BaselineFrame
     }
 
     unsigned numActualArgs() const {
         return *(size_t *)(reinterpret_cast<const uint8_t *>(this) +
                              BaselineFrame::Size() +
                              offsetOfNumActualArgs());
     }
     unsigned numFormalArgs() const {
-        return script()->function()->nargs();
+        return script()->functionNonDelazifying()->nargs();
     }
     Value &thisValue() const {
         return *(Value *)(reinterpret_cast<const uint8_t *>(this) +
                          BaselineFrame::Size() +
                          offsetOfThis());
     }
     Value *argv() const {
         return (Value *)(reinterpret_cast<const uint8_t *>(this) +
--- a/js/src/jit/BaselineFrameInfo.h
+++ b/js/src/jit/BaselineFrameInfo.h
@@ -177,17 +177,17 @@ class FrameInfo
     { }
 
     bool init(TempAllocator &alloc);
 
     uint32_t nlocals() const {
         return script->nfixed();
     }
     uint32_t nargs() const {
-        return script->function()->nargs();
+        return script->functionNonDelazifying()->nargs();
     }
 
   private:
     inline StackValue *rawPush() {
         StackValue *val = &stack[spIndex++];
         val->reset();
         return val;
     }
--- a/js/src/jit/BaselineJIT.cpp
+++ b/js/src/jit/BaselineJIT.cpp
@@ -215,16 +215,18 @@ jit::EnterBaselineAtBranch(JSContext *cx
 MethodStatus
 jit::BaselineCompile(JSContext *cx, HandleScript script)
 {
     JS_ASSERT(!script->hasBaselineScript());
     JS_ASSERT(script->canBaselineCompile());
 
     LifoAlloc alloc(BASELINE_LIFO_ALLOC_PRIMARY_CHUNK_SIZE);
 
+    script->ensureNonLazyCanonicalFunction(cx);
+
     TempAllocator *temp = alloc.new_<TempAllocator>(&alloc);
     if (!temp)
         return Method_Error;
 
     IonContext ictx(cx, temp);
 
     BaselineCompiler compiler(cx, *temp, script);
     if (!compiler.init())
--- a/js/src/jit/CodeGenerator.cpp
+++ b/js/src/jit/CodeGenerator.cpp
@@ -3396,17 +3396,18 @@ bool
 CodeGenerator::visitNewDeclEnvObject(LNewDeclEnvObject *lir)
 {
     Register obj = ToRegister(lir->output());
     JSObject *templateObj = lir->mir()->templateObj();
     CompileInfo &info = lir->mir()->block()->info();
 
     // If we have a template object, we can inline call object creation.
     OutOfLineCode *ool = oolCallVM(NewDeclEnvObjectInfo, lir,
-                                   (ArgList(), ImmGCPtr(info.fun()), Imm32(gc::DefaultHeap)),
+                                   (ArgList(), ImmGCPtr(info.funMaybeLazy()),
+                                    Imm32(gc::DefaultHeap)),
                                    StoreRegisterTo(obj));
     if (!ool)
         return false;
 
     masm.newGCThing(obj, templateObj, ool->entry(), gc::DefaultHeap);
     masm.initGCThing(obj, templateObj);
     masm.bind(ool->rejoin());
     return true;
--- a/js/src/jit/CompileInfo.h
+++ b/js/src/jit/CompileInfo.h
@@ -46,20 +46,22 @@ class CompileInfo
   public:
     CompileInfo(JSScript *script, JSFunction *fun, jsbytecode *osrPc, bool constructing,
                 ExecutionMode executionMode, bool scriptNeedsArgsObj)
       : script_(script), fun_(fun), osrPc_(osrPc), constructing_(constructing),
         executionMode_(executionMode), scriptNeedsArgsObj_(scriptNeedsArgsObj)
     {
         JS_ASSERT_IF(osrPc, JSOp(*osrPc) == JSOP_LOOPENTRY);
 
-        // The function here can flow in from anywhere so look up the canonical function to ensure that
-        // we do not try to embed a nursery pointer in jit-code.
+        // The function here can flow in from anywhere so look up the canonical
+        // function to ensure that we do not try to embed a nursery pointer in
+        // jit-code. Precisely because it can flow in from anywhere, it's not
+        // guaranteed to be non-lazy. Hence, don't access its script!
         if (fun_) {
-            fun_ = fun_->nonLazyScript()->function();
+            fun_ = fun_->nonLazyScript()->functionNonDelazifying();
             JS_ASSERT(fun_->isTenured());
         }
 
         nimplicit_ = StartArgSlot(script)                   /* scope chain and argument obj */
                    + (fun ? 1 : 0);                         /* this */
         nargs_ = fun ? fun->nargs() : 0;
         nlocals_ = script->nfixed();
         nstack_ = script->nslots() - script->nfixed();
@@ -75,17 +77,17 @@ class CompileInfo
         nlocals_ = nlocals;
         nstack_ = 1;  /* For FunctionCompiler::pushPhiInput/popPhiOutput */
         nslots_ = nlocals_ + nstack_;
     }
 
     JSScript *script() const {
         return script_;
     }
-    JSFunction *fun() const {
+    JSFunction *funMaybeLazy() const {
         return fun_;
     }
     bool constructing() const {
         return constructing_;
     }
     jsbytecode *osrPc() {
         return osrPc_;
     }
@@ -169,17 +171,17 @@ class CompileInfo
         JS_ASSERT(script());
         return 1;
     }
     uint32_t argsObjSlot() const {
         JS_ASSERT(hasArguments());
         return 2;
     }
     uint32_t thisSlot() const {
-        JS_ASSERT(fun());
+        JS_ASSERT(funMaybeLazy());
         JS_ASSERT(nimplicit_ > 0);
         return nimplicit_ - 1;
     }
     uint32_t firstArgSlot() const {
         return nimplicit_;
     }
     uint32_t argSlotUnchecked(uint32_t i) const {
         // During initialization, some routines need to get at arg
@@ -208,26 +210,26 @@ class CompileInfo
     }
 
     uint32_t startArgSlot() const {
         JS_ASSERT(script());
         return StartArgSlot(script());
     }
     uint32_t endArgSlot() const {
         JS_ASSERT(script());
-        return CountArgSlots(script(), fun());
+        return CountArgSlots(script(), funMaybeLazy());
     }
 
     uint32_t totalSlots() const {
-        JS_ASSERT(script() && fun());
+        JS_ASSERT(script() && funMaybeLazy());
         return nimplicit() + nargs() + nlocals();
     }
 
     bool isSlotAliased(uint32_t index) const {
-        if (fun() && index == thisSlot())
+        if (funMaybeLazy() && index == thisSlot())
             return false;
 
         uint32_t arg = index - firstArgSlot();
         if (arg < nargs()) {
             if (script()->formalIsAliased(arg))
                 return true;
             return false;
         }
--- a/js/src/jit/Ion.cpp
+++ b/js/src/jit/Ion.cpp
@@ -1617,17 +1617,19 @@ TrackAllProperties(JSContext *cx, JSObje
 
 static void
 TrackPropertiesForSingletonScopes(JSContext *cx, JSScript *script, BaselineFrame *baselineFrame)
 {
     // Ensure that all properties of singleton call objects which the script
     // could access are tracked. These are generally accessed through
     // ALIASEDVAR operations in baseline and will not be tracked even if they
     // have been accessed in baseline code.
-    JSObject *environment = script->function() ? script->function()->environment() : nullptr;
+    JSObject *environment = script->functionNonDelazifying()
+                            ? script->functionNonDelazifying()->environment()
+                            : nullptr;
 
     while (environment && !environment->is<GlobalObject>()) {
         if (environment->is<CallObject>() && environment->hasSingletonType())
             TrackAllProperties(cx, environment);
         environment = environment->enclosingScope();
     }
 
     if (baselineFrame) {
@@ -1646,16 +1648,20 @@ IonCompile(JSContext *cx, JSScript *scri
 #if JS_TRACE_LOGGING
     AutoTraceLog logger(TraceLogging::defaultLogger(),
                         TraceLogging::ION_COMPILE_START,
                         TraceLogging::ION_COMPILE_STOP,
                         script);
 #endif
     JS_ASSERT(optimizationLevel > Optimization_DontCompile);
 
+    // Make sure the script's canonical function isn't lazy. We can't de-lazify
+    // it in a worker thread.
+    script->ensureNonLazyCanonicalFunction(cx);
+
     TrackPropertiesForSingletonScopes(cx, script, baselineFrame);
 
     LifoAlloc *alloc = cx->new_<LifoAlloc>(BUILDER_LIFO_ALLOC_PRIMARY_CHUNK_SIZE);
     if (!alloc)
         return AbortReason_Alloc;
 
     ScopedJSDeletePtr<LifoAlloc> autoDelete(alloc);
 
@@ -1672,18 +1678,19 @@ IonCompile(JSContext *cx, JSScript *scri
 
     if (!cx->compartment()->jitCompartment()->ensureIonStubsExist(cx))
         return AbortReason_Alloc;
 
     MIRGraph *graph = alloc->new_<MIRGraph>(temp);
     if (!graph)
         return AbortReason_Alloc;
 
-    CompileInfo *info = alloc->new_<CompileInfo>(script, script->function(), osrPc, constructing,
-                                                 executionMode, script->needsArgsObj());
+    CompileInfo *info = alloc->new_<CompileInfo>(script, script->functionNonDelazifying(), osrPc,
+                                                 constructing, executionMode,
+                                                 script->needsArgsObj());
     if (!info)
         return AbortReason_Alloc;
 
     BaselineInspector *inspector = alloc->new_<BaselineInspector>(script);
     if (!inspector)
         return AbortReason_Alloc;
 
     BaselineFrameInspector *baselineFrameInspector = nullptr;
@@ -2213,17 +2220,17 @@ jit::CanEnterUsingFastInvoke(JSContext *
     JS_ASSERT(jit::IsIonEnabled(cx));
 
     // Skip if the code is expected to result in a bailout.
     if (!script->hasIonScript() || script->ionScript()->bailoutExpected())
         return Method_Skipped;
 
     // Don't handle arguments underflow, to make this work we would have to pad
     // missing arguments with |undefined|.
-    if (numActualArgs < script->function()->nargs())
+    if (numActualArgs < script->functionNonDelazifying()->nargs())
         return Method_Skipped;
 
     if (!cx->compartment()->ensureJitCompartmentExists(cx))
         return Method_Error;
 
     // This can GC, so afterward, script->ion is not guaranteed to be valid.
     if (!cx->runtime()->jitRuntime()->enterIon())
         return Method_Error;
@@ -2274,17 +2281,17 @@ EnterIon(JSContext *cx, EnterJitData &da
 
 bool
 jit::SetEnterJitData(JSContext *cx, EnterJitData &data, RunState &state, AutoValueVector &vals)
 {
     data.osrFrame = nullptr;
 
     if (state.isInvoke()) {
         CallArgs &args = state.asInvoke()->args();
-        unsigned numFormals = state.script()->function()->nargs();
+        unsigned numFormals = state.script()->functionNonDelazifying()->nargs();
         data.constructing = state.asInvoke()->constructing();
         data.numActualArgs = args.length();
         data.maxArgc = Max(args.length(), numFormals) + 1;
         data.scopeChain = nullptr;
         data.calleeToken = CalleeToToken(&args.callee().as<JSFunction>());
 
         if (data.numActualArgs >= numFormals) {
             data.maxArgv = args.base() + 1;
--- a/js/src/jit/IonAnalysis.cpp
+++ b/js/src/jit/IonAnalysis.cpp
@@ -211,17 +211,17 @@ IsPhiObservable(MPhi *phi, Observability
                 !iter->consumer()->toDefinition()->isPhi())
                 return true;
         }
         break;
     }
 
     uint32_t slot = phi->slot();
     CompileInfo &info = phi->block()->info();
-    JSFunction *fun = info.fun();
+    JSFunction *fun = info.funMaybeLazy();
 
     // If the Phi is of the |this| value, it must always be observable.
     if (fun && slot == info.thisSlot())
         return true;
 
     // If the function may need an arguments object, then make sure to preserve
     // the scope chain, because it may be needed to construct the arguments
     // object during bailout.
@@ -2138,21 +2138,20 @@ jit::AnalyzeNewScriptProperties(JSContex
                                 Vector<types::TypeNewScript::Initializer> *initializerList)
 {
     JS_ASSERT(cx->compartment()->activeAnalysis);
 
     // When invoking 'new' on the specified script, try to find some properties
     // which will definitely be added to the created object before it has a
     // chance to escape and be accessed elsewhere.
 
-    if (fun->isInterpretedLazy() && !fun->getOrCreateScript(cx))
+    RootedScript script(cx, fun->getOrCreateScript(cx));
+    if (!script)
         return false;
 
-    RootedScript script(cx, fun->nonLazyScript());
-
     if (!script->compileAndGo() || !script->canBaselineCompile())
         return true;
 
     Vector<PropertyName *> accessedProperties(cx);
 
     LifoAlloc alloc(types::TypeZone::TYPE_LIFO_ALLOC_PRIMARY_CHUNK_SIZE);
 
     TempAllocator temp(&alloc);
--- a/js/src/jit/IonBuilder.cpp
+++ b/js/src/jit/IonBuilder.cpp
@@ -70,17 +70,17 @@ jit::NewBaselineFrameInspector(TempAlloc
 
     inspector->thisType = types::GetValueType(frame->thisValue());
 
     if (frame->scopeChain()->hasSingletonType())
         inspector->singletonScopeChain = frame->scopeChain();
 
     JSScript *script = frame->script();
 
-    if (script->function()) {
+    if (script->functionNonDelazifying()) {
         if (!inspector->argTypes.reserve(frame->numFormalArgs()))
             return nullptr;
         for (size_t i = 0; i < frame->numFormalArgs(); i++) {
             if (script->formalIsAliased(i))
                 inspector->argTypes.infallibleAppend(types::Type::UndefinedType());
             else if (!script->argsObjAliasesFormals())
                 inspector->argTypes.infallibleAppend(types::GetValueType(frame->unaliasedFormal(i)));
             else if (frame->hasArgsObj())
@@ -344,20 +344,20 @@ IonBuilder::canInlineTarget(JSFunction *
         return InliningDecision_DontInline;
 
     if (!target->isInterpreted())
         return DontInline(nullptr, "Non-interpreted target");
 
     // Allow constructing lazy scripts when performing the definite properties
     // analysis, as baseline has not been used to warm the caller up yet.
     if (target->isInterpreted() && info().executionMode() == DefinitePropertiesAnalysis) {
-        if (!target->getOrCreateScript(analysisContext))
+        RootedScript script(analysisContext, target->getOrCreateScript(analysisContext));
+        if (!script)
             return InliningDecision_Error;
 
-        RootedScript script(analysisContext, target->nonLazyScript());
         if (!script->hasBaselineScript() && script->canBaselineCompile()) {
             MethodStatus status = BaselineCompile(analysisContext, script);
             if (status == Method_Error)
                 return InliningDecision_Error;
             if (status != Method_Compiled)
                 return InliningDecision_DontInline;
         }
     }
@@ -682,17 +682,17 @@ IonBuilder::build()
     // It's safe to start emitting actual IR, so now build the scope chain.
     if (!initScopeChain())
         return false;
 
     if (info().needsArgsObj() && !initArgumentsObject())
         return false;
 
     // Prevent |this| from being DCE'd: necessary for constructors.
-    if (info().fun())
+    if (info().funMaybeLazy())
         current->getSlot(info().thisSlot())->setGuard();
 
     // The type analysis phase attempts to insert unbox operations near
     // definitions of values. It also attempts to replace uses in resume points
     // with the narrower, unboxed variants. However, we must prevent this
     // replacement from happening on values in the entry snapshot. Otherwise we
     // could get this:
     //
@@ -914,29 +914,29 @@ IonBuilder::rewriteParameter(uint32_t sl
 // Apply Type Inference information to parameters early on, unboxing them if
 // they have a definitive type. The actual guards will be emitted by the code
 // generator, explicitly, as part of the function prologue.
 void
 IonBuilder::rewriteParameters()
 {
     JS_ASSERT(info().scopeChainSlot() == 0);
 
-    if (!info().fun())
+    if (!info().funMaybeLazy())
         return;
 
     for (uint32_t i = info().startArgSlot(); i < info().endArgSlot(); i++) {
         MDefinition *param = current->getSlot(i);
         rewriteParameter(i, param, param->toParameter()->index());
     }
 }
 
 bool
 IonBuilder::initParameters()
 {
-    if (!info().fun())
+    if (!info().funMaybeLazy())
         return true;
 
     // If we are doing OSR on a frame which initially executed in the
     // interpreter and didn't accumulate type information, try to use that OSR
     // frame to determine possible initial types for 'this' and parameters.
 
     // For unknownProperties() tests under addType.
     lock();
@@ -985,17 +985,17 @@ IonBuilder::initScopeChain(MDefinition *
     // will try to access the scope. For other scripts, the scope instructions
     // will be held live by resume points and code will still be generated for
     // them, so just use a constant undefined value.
     if (!script()->compileAndGo())
         return abort("non-CNG global scripts are not supported");
 
     lock();
 
-    if (JSFunction *fun = info().fun()) {
+    if (JSFunction *fun = info().funMaybeLazy()) {
         if (!callee) {
             MCallee *calleeIns = MCallee::New(alloc());
             current->add(calleeIns);
             callee = calleeIns;
         }
         scope = MFunctionEnvironment::New(alloc(), callee);
         current->add(scope);
 
@@ -3825,17 +3825,17 @@ class AutoAccumulateReturns
     ~AutoAccumulateReturns() {
         graph_.setReturnAccumulator(prev_);
     }
 };
 
 bool
 IonBuilder::inlineScriptedCall(CallInfo &callInfo, JSFunction *target)
 {
-    JS_ASSERT(target->isInterpreted());
+    JS_ASSERT(target->hasScript());
     JS_ASSERT(IsIonInlinablePC(pc));
 
     callInfo.setImplicitlyUsedUnchecked();
 
     // Ensure sufficient space in the slots: needed for inlining from FUNAPPLY.
     uint32_t depth = current->stackDepth() + callInfo.numFormals();
     if (depth > current->nslots()) {
         if (!current->increaseSlots(depth - current->nslots()))
@@ -5293,17 +5293,17 @@ IonBuilder::jsop_eval(uint32_t argc)
     JSFunction *singleton = getSingleCallTarget(calleeTypes);
     if (!singleton)
         return abort("No singleton callee for eval()");
 
     if (script()->global().valueIsEval(ObjectValue(*singleton))) {
         if (argc != 1)
             return abort("Direct eval with more than one argument");
 
-        if (!info().fun())
+        if (!info().funMaybeLazy())
             return abort("Direct eval in global code");
 
         // The 'this' value for the outer and eval scripts must be the
         // same. This is not guaranteed if a primitive string/number/etc.
         // is passed through to the eval invoke as the primitive may be
         // boxed into different objects if accessed via 'this'.
         JSValueType type = thisTypes->getKnownTypeTag();
         if (type != JSVAL_TYPE_OBJECT && type != JSVAL_TYPE_NULL && type != JSVAL_TYPE_UNDEFINED)
@@ -5715,17 +5715,17 @@ IonBuilder::newOsrPreheader(MBasicBlock 
         if (needsArgsObj)
             argsObj = MOsrArgumentsObject::New(alloc(), entry);
         else
             argsObj = MConstant::New(alloc(), UndefinedValue());
         osrBlock->add(argsObj);
         osrBlock->initSlot(info().argsObjSlot(), argsObj);
     }
 
-    if (info().fun()) {
+    if (info().funMaybeLazy()) {
         // Initialize |this| parameter.
         MParameter *thisv = MParameter::New(alloc(), MParameter::THIS_SLOT, nullptr);
         osrBlock->add(thisv);
         osrBlock->initSlot(info().thisSlot(), thisv);
 
         // Initialize arguments.
         for (uint32_t i = 0; i < info().nargs(); i++) {
             uint32_t slot = needsArgsObj ? info().argSlotUnchecked(i) : info().argSlot(i);
@@ -5820,17 +5820,17 @@ IonBuilder::newOsrPreheader(MBasicBlock 
 
     // Finish the osrBlock.
     osrBlock->end(MGoto::New(alloc(), preheader));
     preheader->addPredecessor(alloc(), osrBlock);
     graph().setOsrBlock(osrBlock);
 
     // Wrap |this| with a guaranteed use, to prevent instruction elimination.
     // Prevent |this| from being DCE'd: necessary for constructors.
-    if (info().fun())
+    if (info().funMaybeLazy())
         preheader->getSlot(info().thisSlot())->setGuard();
 
     return preheader;
 }
 
 MBasicBlock *
 IonBuilder::newPendingLoopHeader(MBasicBlock *predecessor, jsbytecode *pc, bool osr)
 {
@@ -5860,17 +5860,17 @@ IonBuilder::newPendingLoopHeader(MBasicB
                 continue;
 
             MPhi *phi = block->getSlot(i)->toPhi();
 
             // Get the type from the baseline frame.
             types::Type existingType = types::Type::UndefinedType();
             uint32_t arg = i - info().firstArgSlot();
             uint32_t var = i - info().firstLocalSlot();
-            if (info().fun() && i == info().thisSlot())
+            if (info().funMaybeLazy() && i == info().thisSlot())
                 existingType = baselineFrame_->thisType;
             else if (arg < info().nargs())
                 existingType = baselineFrame_->argTypes[arg];
             else
                 existingType = baselineFrame_->varTypes[var];
 
             // Extract typeset from value.
             types::TemporaryTypeSet *typeSet =
@@ -9235,20 +9235,20 @@ IonBuilder::jsop_deffun(uint32_t index)
     current->add(deffun);
 
     return resumeAfter(deffun);
 }
 
 bool
 IonBuilder::jsop_this()
 {
-    if (!info().fun())
+    if (!info().funMaybeLazy())
         return abort("JSOP_THIS outside of a JSFunction.");
 
-    if (script()->strict() || info().fun()->isSelfHostedBuiltin()) {
+    if (script()->strict() || info().funMaybeLazy()->isSelfHostedBuiltin()) {
         // No need to wrap primitive |this| in strict mode or self-hosted code.
         current->pushSlot(info().thisSlot());
         return true;
     }
 
     if (thisTypes->getKnownTypeTag() == JSVAL_TYPE_OBJECT ||
         (thisTypes->empty() && baselineFrame_ && baselineFrame_->thisType.isSomeObject()))
     {
@@ -9394,33 +9394,34 @@ IonBuilder::walkScopeChain(unsigned hops
 
 bool
 IonBuilder::hasStaticScopeObject(ScopeCoordinate sc, JSObject **pcall)
 {
     JSScript *outerScript = ScopeCoordinateFunctionScript(script(), pc);
     if (!outerScript || !outerScript->treatAsRunOnce())
         return false;
 
-    types::TypeObjectKey *funType = types::TypeObjectKey::get(outerScript->function());
+    types::TypeObjectKey *funType =
+            types::TypeObjectKey::get(outerScript->functionNonDelazifying());
     if (funType->hasFlags(constraints(), types::OBJECT_FLAG_RUNONCE_INVALIDATED))
         return false;
 
     // The script this aliased var operation is accessing will run only once,
     // so there will be only one call object and the aliased var access can be
     // compiled in the same manner as a global access. We still need to find
     // the call object though.
 
     // Look for the call object on the current script's function's scope chain.
     // If the current script is inner to the outer script and the function has
     // singleton type then it should show up here.
 
     MDefinition *scope = current->getSlot(info().scopeChainSlot());
     scope->setImplicitlyUsedUnchecked();
 
-    JSObject *environment = script()->function()->environment();
+    JSObject *environment = script()->functionNonDelazifying()->environment();
     while (environment && !environment->is<GlobalObject>()) {
         if (environment->is<CallObject>() &&
             !environment->as<CallObject>().isForEval() &&
             environment->as<CallObject>().callee().nonLazyScript() == outerScript)
         {
             JS_ASSERT(environment->hasSingletonType());
             *pcall = environment;
             return true;
--- a/js/src/jit/IonFrames.cpp
+++ b/js/src/jit/IonFrames.cpp
@@ -614,17 +614,17 @@ HandleException(ResumeFromException *rfe
                 bool popSPSFrame = cx->runtime()->spsProfiler.enabled();
                 if (invalidated)
                     popSPSFrame = ionScript->hasSPSInstrumentation();
 
                 // When profiling, each frame popped needs a notification that
                 // the function has exited, so invoke the probe that a function
                 // is exiting.
                 JSScript *script = frames.script();
-                probes::ExitScript(cx, script, script->function(), popSPSFrame);
+                probes::ExitScript(cx, script, script->functionNonDelazifying(), popSPSFrame);
                 if (!frames.more())
                     break;
                 ++frames;
             }
 
             if (invalidated)
                 ionScript->decref(cx->runtime()->defaultFreeOp());
 
@@ -633,17 +633,17 @@ HandleException(ResumeFromException *rfe
             bool calledDebugEpilogue = false;
 
             HandleExceptionBaseline(cx, iter, rfe, &calledDebugEpilogue);
             if (rfe->kind != ResumeFromException::RESUME_ENTRY_FRAME)
                 return;
 
             // Unwind profiler pseudo-stack
             JSScript *script = iter.script();
-            probes::ExitScript(cx, script, script->function(),
+            probes::ExitScript(cx, script, script->functionNonDelazifying(),
                                iter.baselineFrame()->hasPushedSPSFrame());
             // After this point, any pushed SPS frame would have been popped if it needed
             // to be.  Unset the flag here so that if we call DebugEpilogue below,
             // it doesn't try to pop the SPS frame again.
             iter.baselineFrame()->unsetPushedSPSFrame();
  
             if (cx->compartment()->debugMode() && !calledDebugEpilogue) {
                 // If DebugEpilogue returns |true|, we have to perform a forced
@@ -1098,16 +1098,27 @@ MarkJitExitFrame(JSTracer *trc, const Io
           case VMFunction::RootCell:
             gc::MarkGCThingRoot(trc, footer->outParam<void *>(), "ion-vm-out");
             break;
         }
     }
 }
 
 static void
+MarkRectifierFrame(JSTracer *trc, const IonFrameIterator &frame)
+{
+    // Mark thisv.
+    //
+    // Baseline JIT code generated as part of the ICCall_Fallback stub may use
+    // it if we're calling a constructor that returns a primitive value.
+    IonRectifierFrameLayout *layout = (IonRectifierFrameLayout *)frame.fp();
+    gc::MarkValueRoot(trc, &layout->argv()[0], "ion-thisv");
+}
+
+static void
 MarkJitActivation(JSTracer *trc, const JitActivationIterator &activations)
 {
 #ifdef CHECK_OSIPOINT_REGISTERS
     if (js_JitOptions.checkOsiPointRegisters) {
         // GC can modify spilled registers, breaking our register checks.
         // To handle this, we disable these checks for the current VM call
         // when a GC happens.
         JitActivation *activation = activations.activation()->asJit();
@@ -1127,16 +1138,18 @@ MarkJitActivation(JSTracer *trc, const J
             MarkBaselineStubFrame(trc, frames);
             break;
           case IonFrame_OptimizedJS:
             MarkIonJSFrame(trc, frames);
             break;
           case IonFrame_Unwound_OptimizedJS:
             MOZ_ASSUME_UNREACHABLE("invalid");
           case IonFrame_Rectifier:
+            MarkRectifierFrame(trc, frames);
+            break;
           case IonFrame_Unwound_Rectifier:
             break;
           case IonFrame_Osr:
             // The callee token will be marked by the callee JS frame;
             // otherwise, it does not need to be marked, since the frame is
             // dead.
             break;
           default:
--- a/js/src/jit/VMFunctions.cpp
+++ b/js/src/jit/VMFunctions.cpp
@@ -511,23 +511,23 @@ JSObject *
 NewStringObject(JSContext *cx, HandleString str)
 {
     return StringObject::create(cx, str);
 }
 
 bool
 SPSEnter(JSContext *cx, HandleScript script)
 {
-    return cx->runtime()->spsProfiler.enter(cx, script, script->function());
+    return cx->runtime()->spsProfiler.enter(cx, script, script->functionNonDelazifying());
 }
 
 bool
 SPSExit(JSContext *cx, HandleScript script)
 {
-    cx->runtime()->spsProfiler.exit(cx, script, script->function());
+    cx->runtime()->spsProfiler.exit(cx, script, script->functionNonDelazifying());
     return true;
 }
 
 bool
 OperatorIn(JSContext *cx, HandleValue key, HandleObject obj, bool *out)
 {
     RootedId id(cx);
     if (!ValueToId<CanGC>(cx, key, &id))
--- a/js/src/jit/shared/BaselineCompiler-shared.h
+++ b/js/src/jit/shared/BaselineCompiler-shared.h
@@ -91,17 +91,19 @@ class BaselineCompilerShared
         JS_ASSERT(!icEntries_.empty());
         ICLoadLabel loadLabel;
         loadLabel.label = label;
         loadLabel.icEntry = icEntries_.length() - 1;
         return icLoadLabels_.append(loadLabel);
     }
 
     JSFunction *function() const {
-        return script->function();
+        // Not delazifying here is ok as the function is guaranteed to have
+        // been delazified before compilation started.
+        return script->functionNonDelazifying();
     }
 
     PCMappingSlotInfo getStackTopSlotInfo() {
         JS_ASSERT(frame.numUnsyncedSlots() <= 2);
         switch (frame.numUnsyncedSlots()) {
           case 0:
             return PCMappingSlotInfo::MakeSlotInfo();
           case 1:
--- a/js/src/jit/shared/CodeGenerator-shared.cpp
+++ b/js/src/jit/shared/CodeGenerator-shared.cpp
@@ -256,17 +256,17 @@ CodeGeneratorShared::encode(LSnapshot *s
 
     uint32_t startIndex = 0;
     for (MResumePoint **it = mirOperandIter.begin(), **end = mirOperandIter.end();
          it != end;
          ++it)
     {
         MResumePoint *mir = *it;
         MBasicBlock *block = mir->block();
-        JSFunction *fun = block->info().fun();
+        JSFunction *fun = block->info().funMaybeLazy();
         JSScript *script = block->info().script();
         jsbytecode *pc = mir->pc();
         uint32_t exprStack = mir->stackDepth() - block->info().ninvoke();
         snapshots_.startFrame(fun, script, pc, exprStack);
 
         // Ensure that all snapshot which are encoded can safely be used for
         // bailouts.
         DebugOnly<jsbytecode *> bailPC = pc;
--- a/js/src/js.msg
+++ b/js/src/js.msg
@@ -350,17 +350,17 @@ MSG_DEF(JSMSG_NO_REST_NAME,           29
 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}")
 MSG_DEF(JSMSG_ALREADY_HAS_PRAGMA, 303, 2, JSEXN_ERR,      "{0} is being assigned a {1}, but already has one")
 MSG_DEF(JSMSG_PAR_ARRAY_BAD_ARG,      304, 0, JSEXN_RANGEERR, "invalid parallel method argument")
-MSG_DEF(JSMSG_UNUSED305,              305, 0, JSEXN_NONE, "")
+MSG_DEF(JSMSG_REGEXP_RUNTIME_ERROR,   305, 0, JSEXN_INTERNALERR, "an error occurred while executing regular expression")
 MSG_DEF(JSMSG_UNUSED306,              306, 0, JSEXN_NONE, "")
 MSG_DEF(JSMSG_UNUSED307,              307, 0, JSEXN_NONE, "")
 MSG_DEF(JSMSG_PAR_ARRAY_SCATTER_CONFLICT, 308, 0, JSEXN_ERR, "no conflict resolution function provided")
 MSG_DEF(JSMSG_PAR_ARRAY_SCATTER_BOUNDS, 309, 0, JSEXN_ERR, "index in scatter vector out of bounds")
 MSG_DEF(JSMSG_CANT_REPORT_NC_AS_NE,   310, 0, JSEXN_TYPEERR, "proxy can't report a non-configurable own property as non-existent")
 MSG_DEF(JSMSG_CANT_REPORT_E_AS_NE,    311, 0, JSEXN_TYPEERR, "proxy can't report an existing own property as non-existent on a non-extensible object")
 MSG_DEF(JSMSG_CANT_REPORT_NEW,        312, 0, JSEXN_TYPEERR, "proxy can't report a new property on a non-extensible object")
 MSG_DEF(JSMSG_CANT_REPORT_INVALID,    313, 0, JSEXN_TYPEERR, "proxy can't report an incompatible property descriptor")
@@ -429,8 +429,9 @@ MSG_DEF(JSMSG_MODULE_SPEC_AFTER_FROM,   
 MSG_DEF(JSMSG_MODULES_NOT_IMPLEMENTED,  375, 0, JSEXN_SYNTAXERR, "modules are not implemented yet")
 MSG_DEF(JSMSG_EXPORT_DECL_AT_TOP_LEVEL, 376, 0, JSEXN_SYNTAXERR, "export declarations may only appear at top level")
 MSG_DEF(JSMSG_RC_AFTER_EXPORT_SPEC_LIST, 377, 0, JSEXN_SYNTAXERR, "missing '}' after export specifier list")
 MSG_DEF(JSMSG_NO_EXPORT_NAME,           378, 0, JSEXN_SYNTAXERR, "missing export name")
 MSG_DEF(JSMSG_DECLARATION_AFTER_EXPORT, 379, 0, JSEXN_SYNTAXERR, "missing declaration after 'export' keyword")
 MSG_DEF(JSMSG_INVALID_PROTOTYPE,        380, 0, JSEXN_TYPEERR, "prototype field is not an object")
 MSG_DEF(JSMSG_TYPEDOBJECT_HANDLE_TO_UNSIZED, 381, 0, JSEXN_TYPEERR, "cannot create a handle to an unsized type")
 MSG_DEF(JSMSG_SETPROTOTYPEOF_FAIL,      382, 0, JSEXN_TYPEERR, "[[SetPrototypeOf]] failed")
+MSG_DEF(JSMSG_INVALID_ARG_TYPE,         383, 3, JSEXN_TYPEERR, "Invalid type: {0} can't be a{1} {2}")
--- a/js/src/jsanalyze.h
+++ b/js/src/jsanalyze.h
@@ -220,17 +220,18 @@ FollowBranch(JSContext *cx, JSScript *sc
 /* Common representation of slots throughout analyses and the compiler. */
 static inline uint32_t ThisSlot() {
     return 0;
 }
 static inline uint32_t ArgSlot(uint32_t arg) {
     return 1 + arg;
 }
 static inline uint32_t LocalSlot(JSScript *script, uint32_t local) {
-    return 1 + (script->function() ? script->function()->nargs() : 0) + local;
+    return 1 + local +
+           (script->functionNonDelazifying() ? script->functionNonDelazifying()->nargs() : 0);
 }
 static inline uint32_t TotalSlots(JSScript *script) {
     return LocalSlot(script, 0) + script->nfixed();
 }
 
 static inline uint32_t StackSlot(JSScript *script, uint32_t index) {
     return TotalSlots(script) + index;
 }
--- a/js/src/jsapi.cpp
+++ b/js/src/jsapi.cpp
@@ -3979,26 +3979,26 @@ JS_CloneFunctionObject(JSContext *cx, JS
         parent = cx->global();
 
     if (!funobj->is<JSFunction>()) {
         AutoCompartment ac(cx, funobj);
         ReportIsNotFunction(cx, ObjectValue(*funobj));
         return nullptr;
     }
 
-    /*
-     * If a function was compiled to be lexically nested inside some other
-     * script, we cannot clone it without breaking the compiler's assumptions.
-     */
     RootedFunction fun(cx, &funobj->as<JSFunction>());
     if (fun->isInterpretedLazy()) {
         AutoCompartment ac(cx, funobj);
         if (!fun->getOrCreateScript(cx))
             return nullptr;
     }
+    /*
+     * If a function was compiled to be lexically nested inside some other
+     * script, we cannot clone it without breaking the compiler's assumptions.
+     */
     if (fun->isInterpreted() && (fun->nonLazyScript()->enclosingStaticScope() ||
         (fun->nonLazyScript()->compileAndGo() && !parent->is<GlobalObject>())))
     {
         JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_BAD_CLONE_FUNOBJ_SCOPE);
         return nullptr;
     }
 
     if (fun->isBoundFunction()) {
@@ -4686,17 +4686,18 @@ JS_CompileFunction(JSContext *cx, JS::Ha
 JS_PUBLIC_API(JSString *)
 JS_DecompileScript(JSContext *cx, JSScript *scriptArg, const char *name, unsigned indent)
 {
     JS_ASSERT(!cx->runtime()->isAtomsCompartment(cx->compartment()));
 
     AssertHeapIsIdle(cx);
     CHECK_REQUEST(cx);
     RootedScript script(cx, scriptArg);
-    RootedFunction fun(cx, script->function());
+    script->ensureNonLazyCanonicalFunction(cx);
+    RootedFunction fun(cx, script->functionNonDelazifying());
     if (fun)
         return JS_DecompileFunction(cx, fun, indent);
     bool haveSource = script->scriptSource()->hasSourceData();
     if (!haveSource && !JSScript::loadSource(cx, script->scriptSource(), &haveSource))
         return nullptr;
     return haveSource ? script->sourceData(cx) : js_NewStringCopyZ<CanGC>(cx, "[no source]");
 }
 
--- a/js/src/jscompartment.cpp
+++ b/js/src/jscompartment.cpp
@@ -38,16 +38,17 @@ using namespace js::gc;
 using mozilla::DebugOnly;
 
 JSCompartment::JSCompartment(Zone *zone, const JS::CompartmentOptions &options = JS::CompartmentOptions())
   : options_(options),
     zone_(zone),
     runtime_(zone->runtimeFromMainThread()),
     principals(nullptr),
     isSystem(false),
+    isSelfHosting(false),
     marked(true),
 #ifdef DEBUG
     firedOnNewGlobalObject(false),
 #endif
     global_(nullptr),
     enterCompartmentDepth(0),
     data(nullptr),
     objectMetadataCallback(nullptr),
@@ -719,17 +720,17 @@ CreateLazyScriptsForCompartment(JSContex
     AutoObjectVector lazyFunctions(cx);
 
     // Find all live lazy scripts in the compartment, and via them all root
     // lazy functions in the compartment: those which have not been compiled
     // and which have a source object, indicating that their parent has been
     // compiled.
     for (gc::CellIter i(cx->zone(), gc::FINALIZE_LAZY_SCRIPT); !i.done(); i.next()) {
         LazyScript *lazy = i.get<LazyScript>();
-        JSFunction *fun = lazy->function();
+        JSFunction *fun = lazy->functionNonDelazifying();
         if (fun->compartment() == cx->compartment() &&
             lazy->sourceObject() && !lazy->maybeScript())
         {
             MOZ_ASSERT(fun->isInterpretedLazy());
             MOZ_ASSERT(lazy == fun->lazyScriptOrNull());
             if (!lazyFunctions.append(fun))
                 return false;
         }
--- a/js/src/jscompartment.h
+++ b/js/src/jscompartment.h
@@ -122,16 +122,17 @@ struct JSCompartment
 
   private:
     JS::Zone                     *zone_;
     JSRuntime                    *runtime_;
 
   public:
     JSPrincipals                 *principals;
     bool                         isSystem;
+    bool                         isSelfHosting;
     bool                         marked;
 
 #ifdef DEBUG
     bool                         firedOnNewGlobalObject;
 #endif
 
     void mark() { marked = true; }
 
--- a/js/src/jsfun.cpp
+++ b/js/src/jsfun.cpp
@@ -450,17 +450,19 @@ js::CloneFunctionAndScript(JSContext *cx
     }
     RootedFunction clone(cx, NewFunctionWithProto(cx, NullPtr(), nullptr, 0,
                                                   JSFunction::INTERPRETED, NullPtr(), NullPtr(),
                                                   cloneProto, JSFunction::FinalizeKind,
                                                   TenuredObject));
     if (!clone)
         return nullptr;
 
-    RootedScript srcScript(cx, srcFun->nonLazyScript());
+    RootedScript srcScript(cx, srcFun->getOrCreateScript(cx));
+    if (!srcScript)
+        return nullptr;
     RootedScript clonedScript(cx, CloneScript(cx, enclosingScope, clone, srcScript));
     if (!clonedScript)
         return nullptr;
 
     clone->setArgCount(srcFun->nargs());
     clone->setFlags(srcFun->flags());
     clone->initAtom(srcFun->displayAtom());
     clone->initScript(clonedScript);
@@ -517,21 +519,40 @@ JSFunction::trace(JSTracer *trc)
     }
 
     if (atom_)
         MarkString(trc, &atom_, "atom");
 
     if (isInterpreted()) {
         // Functions can be be marked as interpreted despite having no script
         // yet at some points when parsing, and can be lazy with no lazy script
-        // for self hosted code.
-        if (hasScript() && u.i.s.script_)
-            MarkScriptUnbarriered(trc, &u.i.s.script_, "script");
-        else if (isInterpretedLazy() && u.i.s.lazy_)
+        // for self-hosted code.
+        if (hasScript() && u.i.s.script_) {
+            // Functions can be relazified under the following conditions:
+            // - their compartment isn't currently executing scripts or being
+            //   debugged
+            // - they are not in the self-hosting compartment
+            // - they aren't generators
+            // - they don't have JIT code attached
+            // - they don't have child functions
+            // - they have information for un-lazifying them again later
+            // This information can either be a LazyScript, or the name of a
+            // self-hosted function which can be cloned over again. The latter
+            // is stored in the first extended slot.
+            if (IS_GC_MARKING_TRACER(trc) && !compartment()->hasBeenEntered() &&
+                !compartment()->debugMode() && !compartment()->isSelfHosting &&
+                u.i.s.script_->isRelazifiable() && (!isSelfHostedBuiltin() || isExtended()))
+            {
+                relazify(trc);
+            } else {
+                MarkScriptUnbarriered(trc, &u.i.s.script_, "script");
+            }
+        } else if (isInterpretedLazy() && u.i.s.lazy_) {
             MarkLazyScriptUnbarriered(trc, &u.i.s.lazy_, "lazyScript");
+        }
         if (u.i.env_)
             MarkObjectUnbarriered(trc, &u.i.env_, "fun_callscope");
     }
 }
 
 static void
 fun_trace(JSTracer *trc, JSObject *obj)
 {
@@ -1121,21 +1142,28 @@ JSFunction::createScriptForLazilyInterpr
         // THING_ROOT_LAZY_SCRIPT).
         AutoSuppressGC suppressGC(cx);
 
         RootedScript script(cx, lazy->maybeScript());
 
         if (script) {
             AutoLockForCompilation lock(cx);
             fun->setUnlazifiedScript(script);
+            // Remember the lazy script on the compiled script, so it can be
+            // stored on the function again in case of re-lazification.
+            // Only functions without inner functions are re-lazified.
+            if (!lazy->numInnerFunctions())
+                script->setLazyScript(lazy);
             return true;
         }
 
-        if (fun != lazy->function()) {
-            script = lazy->function()->getOrCreateScript(cx);
+        if (fun != lazy->functionNonDelazifying()) {
+            if (!lazy->functionDelazifying(cx))
+                return false;
+            script = lazy->functionNonDelazifying()->nonLazyScript();
             if (!script)
                 return false;
 
             AutoLockForCompilation lock(cx);
             fun->setUnlazifiedScript(script);
             return true;
         }
 
@@ -1155,27 +1183,28 @@ JSFunction::createScriptForLazilyInterpr
         if (script) {
             RootedObject enclosingScope(cx, lazy->enclosingScope());
             RootedScript clonedScript(cx, CloneScript(cx, enclosingScope, fun, script));
             if (!clonedScript)
                 return false;
 
             clonedScript->setSourceObject(lazy->sourceObject());
 
-            fun->initAtom(script->function()->displayAtom());
+            fun->initAtom(script->functionNonDelazifying()->displayAtom());
             clonedScript->setFunction(fun);
 
             {
                 AutoLockForCompilation lock(cx);
                 fun->setUnlazifiedScript(clonedScript);
             }
 
             CallNewScriptHook(cx, clonedScript, fun);
 
-            lazy->initScript(clonedScript);
+            if (!lazy->maybeScript())
+                lazy->initScript(clonedScript);
             return true;
         }
 
         JS_ASSERT(lazy->source()->hasSourceData());
 
         // Parse and compile the script from source.
         SourceDataCache::AutoSuppressPurge asp(cx);
         const jschar *chars = lazy->source()->chars(cx, asp);
@@ -1185,41 +1214,87 @@ JSFunction::createScriptForLazilyInterpr
         const jschar *lazyStart = chars + lazy->begin();
         size_t lazyLength = lazy->end() - lazy->begin();
 
         if (!frontend::CompileLazyFunction(cx, lazy, lazyStart, lazyLength))
             return false;
 
         script = fun->nonLazyScript();
 
+        // Remember the compiled script on the lazy script itself, in case
+        // there are clones of the function still pointing to the lazy script.
+        if (!lazy->maybeScript())
+            lazy->initScript(script);
+
         // Try to insert the newly compiled script into the lazy script cache.
         if (!lazy->numInnerFunctions()) {
             // A script's starting column isn't set by the bytecode emitter, so
             // specify this from the lazy script so that if an identical lazy
             // script is encountered later a match can be determined.
             script->setColumn(lazy->column());
 
             LazyScriptCache::Lookup lookup(cx, lazy);
             cx->runtime()->lazyScriptCache.insert(lookup, script);
+
+            // Remember the lazy script on the compiled script, so it can be
+            // stored on the function again in case of re-lazification.
+            // Only functions without inner functions are re-lazified.
+            script->setLazyScript(lazy);
         }
-
-        // Remember the compiled script on the lazy script itself, in case
-        // there are clones of the function still pointing to the lazy script.
-        lazy->initScript(script);
         return true;
     }
 
-    /* Lazily cloned self hosted script. */
+    /* Lazily cloned self-hosted script. */
+    JS_ASSERT(fun->isSelfHostedBuiltin());
     RootedAtom funAtom(cx, &fun->getExtendedSlot(0).toString()->asAtom());
     if (!funAtom)
         return false;
     Rooted<PropertyName *> funName(cx, funAtom->asPropertyName());
     return cx->runtime()->cloneSelfHostedFunctionScript(cx, funName, fun);
 }
 
+void
+JSFunction::relazify(JSTracer *trc)
+{
+    JSScript *script = nonLazyScript();
+    JS_ASSERT(script->isRelazifiable());
+    JS_ASSERT(!compartment()->hasBeenEntered());
+    JS_ASSERT(!compartment()->debugMode());
+
+    // If the script's canonical function isn't lazy, we have to mark the
+    // script. Otherwise, the following scenario would leave it unmarked
+    // and cause it to be swept while a function is still expecting it to be
+    // valid:
+    // 1. an incremental GC slice causes the canonical function to relazify
+    // 2. a clone is used and delazifies the canonical function
+    // 3. another GC slice causes the clone to relazify
+    // The result is that no function marks the script, but the canonical
+    // function expects it to be valid.
+    if (script->functionNonDelazifying()->hasScript())
+        MarkScriptUnbarriered(trc, &u.i.s.script_, "script");
+
+    flags_ &= ~INTERPRETED;
+    flags_ |= INTERPRETED_LAZY;
+    LazyScript *lazy = script->maybeLazyScript();
+    u.i.s.lazy_ = lazy;
+    if (lazy) {
+        JS_ASSERT(!isSelfHostedBuiltin());
+        // If this is the script stored in the lazy script to be cloned
+        // for un-lazifying other functions, reset it so the script can
+        // be freed.
+        if (lazy->maybeScript() == script)
+            lazy->resetScript();
+        MarkLazyScriptUnbarriered(trc, &u.i.s.lazy_, "lazyScript");
+    } else {
+        JS_ASSERT(isSelfHostedBuiltin());
+        JS_ASSERT(isExtended());
+        JS_ASSERT(getExtendedSlot(0).toString()->isAtom());
+    }
+}
+
 /* ES5 15.3.4.5.1 and 15.3.4.5.2. */
 bool
 js::CallOrConstructBoundFunction(JSContext *cx, unsigned argc, Value *vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
     RootedFunction fun(cx, &args.callee().as<JSFunction>());
     JS_ASSERT(fun->isBoundFunction());
 
--- a/js/src/jsfun.h
+++ b/js/src/jsfun.h
@@ -274,16 +274,17 @@ class JSFunction : public JSObject
     }
 
     static inline size_t offsetOfNargs() { return offsetof(JSFunction, nargs_); }
     static inline size_t offsetOfFlags() { return offsetof(JSFunction, flags_); }
     static inline size_t offsetOfEnvironment() { return offsetof(JSFunction, u.i.env_); }
     static inline size_t offsetOfAtom() { return offsetof(JSFunction, atom_); }
 
     static bool createScriptForLazilyInterpretedFunction(JSContext *cx, js::HandleFunction fun);
+    void relazify(JSTracer *trc);
 
     // Function Scripts
     //
     // Interpreted functions may either have an explicit JSScript (hasScript())
     // or be lazy with sufficient information to construct the JSScript if
     // necessary (isInterpretedLazy()).
     //
     // A lazy function will have a LazyScript if the function came from parsed
@@ -303,45 +304,43 @@ class JSFunction : public JSObject
 
     JSScript *getOrCreateScript(JSContext *cx) {
         JS_ASSERT(isInterpreted());
         JS_ASSERT(cx);
         if (isInterpretedLazy()) {
             JS::RootedFunction self(cx, this);
             if (!createScriptForLazilyInterpretedFunction(cx, self))
                 return nullptr;
-            JS_ASSERT(self->hasScript());
-            return self->u.i.s.script_;
+            return self->nonLazyScript();
         }
-        JS_ASSERT(hasScript());
-        return u.i.s.script_;
+        return nonLazyScript();
     }
 
     JSScript *existingScript() {
         JS_ASSERT(isInterpreted());
         if (isInterpretedLazy()) {
             js::LazyScript *lazy = lazyScript();
             JSScript *script = lazy->maybeScript();
             JS_ASSERT(script);
 
             if (shadowZone()->needsBarrier())
                 js::LazyScript::writeBarrierPre(lazy);
 
             flags_ &= ~INTERPRETED_LAZY;
             flags_ |= INTERPRETED;
             initScript(script);
         }
-        JS_ASSERT(hasScript());
-        return u.i.s.script_;
+        return nonLazyScript();
     }
 
     JSScript *nonLazyScript() const {
         js::AutoThreadSafeAccess ts(this);
+        JS_ASSERT(js::CurrentThreadCanReadCompilationData());
         JS_ASSERT(hasScript());
-        JS_ASSERT(js::CurrentThreadCanReadCompilationData());
+        JS_ASSERT(u.i.s.script_);
         return u.i.s.script_;
     }
 
     js::HeapPtrScript &mutableScript() {
         JS_ASSERT(isInterpreted());
         return *(js::HeapPtrScript *)&u.i.s.script_;
     }
 
@@ -386,16 +385,18 @@ class JSFunction : public JSObject
         mutableScript().init(script_);
     }
 
     void setUnlazifiedScript(JSScript *script) {
         // Note: createScriptForLazilyInterpretedFunction triggers a barrier on
         // lazy script before it is overwritten here.
         JS_ASSERT(js::CurrentThreadCanWriteCompilationData());
         JS_ASSERT(isInterpretedLazy());
+        if (!lazyScript()->maybeScript())
+            lazyScript()->initScript(script);
         flags_ &= ~INTERPRETED_LAZY;
         flags_ |= INTERPRETED;
         initScript(script);
     }
 
     void initLazyScript(js::LazyScript *lazy) {
         JS_ASSERT(isInterpreted());
         flags_ &= ~INTERPRETED;
--- a/js/src/jsinfer.cpp
+++ b/js/src/jsinfer.cpp
@@ -701,17 +701,17 @@ TypeScript::FreezeTypeSets(CompilerConst
     PodZero(types, count);
 
     for (size_t i = 0; i < count; i++) {
         if (!existing[i].clone(alloc, &types[i]))
             return false;
     }
 
     *pThisTypes = types + (ThisTypes(script) - existing);
-    *pArgTypes = (script->function() && script->function()->nargs())
+    *pArgTypes = (script->functionNonDelazifying() && script->functionNonDelazifying()->nargs())
                  ? (types + (ArgTypes(script, 0) - existing))
                  : nullptr;
     *pBytecodeTypes = types;
 
     constraints->freezeScript(script, *pThisTypes, *pArgTypes, *pBytecodeTypes);
     return true;
 }
 
@@ -996,17 +996,19 @@ types::FinishCompilation(JSContext *cx, 
     }
 
     for (size_t i = 0; i < constraints->numFrozenScripts(); i++) {
         const CompilerConstraintList::FrozenScript &entry = constraints->frozenScript(i);
         JS_ASSERT(entry.script->types);
 
         if (!CheckFrozenTypeSet(cx, entry.thisTypes, types::TypeScript::ThisTypes(entry.script)))
             succeeded = false;
-        unsigned nargs = entry.script->function() ? entry.script->function()->nargs() : 0;
+        unsigned nargs = entry.script->functionNonDelazifying()
+                         ? entry.script->functionNonDelazifying()->nargs()
+                         : 0;
         for (size_t i = 0; i < nargs; i++) {
             if (!CheckFrozenTypeSet(cx, &entry.argTypes[i], types::TypeScript::ArgTypes(entry.script, i)))
                 succeeded = false;
         }
         for (size_t i = 0; i < entry.script->nTypeSets(); i++) {
             if (!CheckFrozenTypeSet(cx, &entry.bytecodeTypes[i], &entry.script->types->typeArray()[i]))
                 succeeded = false;
         }
@@ -1060,33 +1062,37 @@ types::FinishDefinitePropertiesAnalysis(
     // than once. See also CheckDefinitePropertiesTypeSet.
     for (size_t i = 0; i < constraints->numFrozenScripts(); i++) {
         const CompilerConstraintList::FrozenScript &entry = constraints->frozenScript(i);
         JSScript *script = entry.script;
         JS_ASSERT(script->types);
 
         JS_ASSERT(TypeScript::ThisTypes(script)->isSubset(entry.thisTypes));
 
-        unsigned nargs = script->function() ? script->function()->nargs() : 0;
+        unsigned nargs = entry.script->functionNonDelazifying()
+                         ? entry.script->functionNonDelazifying()->nargs()
+                         : 0;
         for (size_t j = 0; j < nargs; j++)
             JS_ASSERT(TypeScript::ArgTypes(script, j)->isSubset(&entry.argTypes[j]));
 
         for (size_t j = 0; j < script->nTypeSets(); j++)
             JS_ASSERT(script->types->typeArray()[j].isSubset(&entry.bytecodeTypes[j]));
     }
 #endif
 
     for (size_t i = 0; i < constraints->numFrozenScripts(); i++) {
         const CompilerConstraintList::FrozenScript &entry = constraints->frozenScript(i);
         JSScript *script = entry.script;
         JS_ASSERT(script->types);
 
         CheckDefinitePropertiesTypeSet(cx, entry.thisTypes, TypeScript::ThisTypes(script));
 
-        unsigned nargs = script->function() ? script->function()->nargs() : 0;
+        unsigned nargs = script->functionNonDelazifying()
+                         ? script->functionNonDelazifying()->nargs()
+                         : 0;
         for (size_t j = 0; j < nargs; j++)
             CheckDefinitePropertiesTypeSet(cx, &entry.argTypes[j], TypeScript::ArgTypes(script, j));
 
         for (size_t j = 0; j < script->nTypeSets(); j++)
             CheckDefinitePropertiesTypeSet(cx, &entry.bytecodeTypes[j], &script->types->typeArray()[j]);
     }
 }
 
@@ -2058,17 +2064,17 @@ NewObjectKind
 types::UseNewTypeForInitializer(JSScript *script, jsbytecode *pc, JSProtoKey key)
 {
     /*
      * Objects created outside loops in global and eval scripts should have
      * singleton types. For now this is only done for plain objects and typed
      * arrays, but not normal arrays.
      */
 
-    if (script->function() && !script->treatAsRunOnce())
+    if (script->functionNonDelazifying() && !script->treatAsRunOnce())
         return GenericObject;
 
     if (key != JSProto_Object && !(key >= JSProto_Int8Array && key <= JSProto_Uint8ClampedArray))
         return GenericObject;
 
     /*
      * All loops in the script will have a JSTRY_ITER or JSTRY_LOOP try note
      * indicating their boundary.
@@ -2274,18 +2280,18 @@ TypeZone::addPendingRecompile(JSContext 
 
     if (script->hasParallelIonScript())
         addPendingRecompile(cx, script->parallelIonScript()->recompileInfo());
 #endif
 
     // When one script is inlined into another the caller listens to state
     // changes on the callee's script, so trigger these to force recompilation
     // of any such callers.
-    if (script->function() && !script->function()->hasLazyType())
-        ObjectStateChange(cx, script->function()->type(), false);
+    if (script->functionNonDelazifying() && !script->functionNonDelazifying()->hasLazyType())
+        ObjectStateChange(cx, script->functionNonDelazifying()->type(), false);
 }
 
 void
 TypeCompartment::markSetsUnknown(JSContext *cx, TypeObject *target)
 {
     JS_ASSERT(this == &cx->compartment()->types);
     JS_ASSERT(!(target->flags() & OBJECT_FLAG_SETS_MARKED_UNKNOWN));
     JS_ASSERT(!target->singleton());
@@ -3397,17 +3403,17 @@ types::AddClearDefiniteFunctionUsesInScr
                                             JSScript *script, JSScript *calleeScript)
 {
     // Look for any uses of the specified calleeScript in type sets for
     // |script|, and add constraints to ensure that if the type sets' contents
     // change then the definite properties are cleared from the type.
     // This ensures that the inlining performed when the definite properties
     // analysis was done is stable.
 
-    TypeObjectKey *calleeKey = Type::ObjectType(calleeScript->function()).objectKey();
+    TypeObjectKey *calleeKey = Type::ObjectType(calleeScript->functionNonDelazifying()).objectKey();
 
     unsigned count = TypeScript::NumTypeSets(script);
     StackTypeSet *typeArray = script->types->typeArray();
 
     for (unsigned i = 0; i < count; i++) {
         StackTypeSet *types = &typeArray[i];
         if (!types->unknownObject() && types->getObjectCount() == 1) {
             if (calleeKey != types->getObject(0)) {
@@ -3691,17 +3697,17 @@ JSScript::makeTypes(JSContext *cx)
     for (unsigned i = 0; i < nTypeSets(); i++)
         InferSpew(ISpewOps, "typeSet: %sT%p%s bytecode%u #%u",
                   InferSpewColor(&typeArray[i]), &typeArray[i], InferSpewColorReset(),
                   i, id());
     TypeSet *thisTypes = TypeScript::ThisTypes(this);
     InferSpew(ISpewOps, "typeSet: %sT%p%s this #%u",
               InferSpewColor(thisTypes), thisTypes, InferSpewColorReset(),
               id());
-    unsigned nargs = function() ? function()->nargs() : 0;
+    unsigned nargs = functionNonDelazifying() ? functionNonDelazifying()->nargs() : 0;
     for (unsigned i = 0; i < nargs; i++) {
         TypeSet *types = TypeScript::ArgTypes(this, i);
         InferSpew(ISpewOps, "typeSet: %sT%p%s arg%u #%u",
                   InferSpewColor(types), types, InferSpewColorReset(),
                   i, id());
     }
 #endif
 
@@ -3975,19 +3981,19 @@ ExclusiveContext::getNewType(const Class
     TypeObjectWithNewScriptSet &newTypeObjects = compartment()->newTypeObjects;
 
     if (!newTypeObjects.initialized() && !newTypeObjects.init())
         return nullptr;
 
     // Canonicalize new functions to use the original one associated with its script.
     if (fun) {
         if (fun->hasScript())
-            fun = fun->nonLazyScript()->function();
+            fun = fun->nonLazyScript()->functionNonDelazifying();
         else if (fun->isInterpretedLazy())
-            fun = fun->lazyScript()->function();
+            fun = fun->lazyScript()->functionNonDelazifying();
         else
             fun = nullptr;
     }
 
     TypeObjectWithNewScriptSet::AddPtr p =
         newTypeObjects.lookupForAdd(TypeObjectWithNewScriptSet::Lookup(clasp, proto, fun));
     if (p) {
         TypeObject *type = p->object;
@@ -4565,35 +4571,38 @@ TypeScript::printTypes(JSContext *cx, Ha
 {
     JS_ASSERT(script->types == this);
 
     if (!script->hasBaselineScript())
         return;
 
     AutoEnterAnalysis enter(nullptr, script->compartment());
 
-    if (script->function())
+    if (script->functionNonDelazifying())
         fprintf(stderr, "Function");
     else if (script->isForEval())
         fprintf(stderr, "Eval");
     else
         fprintf(stderr, "Main");
     fprintf(stderr, " #%u %s:%d ", script->id(), script->filename(), (int) script->lineno());
 
-    if (script->function()) {
-        if (js::PropertyName *name = script->function()->name()) {
+    if (script->functionNonDelazifying()) {
+        if (js::PropertyName *name = script->functionNonDelazifying()->name()) {
             const jschar *chars = name->getChars(nullptr);
             JSString::dumpChars(chars, name->length());
         }
     }
 
     fprintf(stderr, "\n    this:");
     TypeScript::ThisTypes(script)->print();
 
-    for (unsigned i = 0; script->function() && i < script->function()->nargs(); i++) {
+    for (unsigned i = 0;
+         script->functionNonDelazifying() && i < script->functionNonDelazifying()->nargs();
+         i++)
+    {
         fprintf(stderr, "\n    arg%u:", i);
         TypeScript::ArgTypes(script, i)->print();
     }
     fprintf(stderr, "\n");
 
     for (jsbytecode *pc = script->code(); pc < script->codeEnd(); pc += GetBytecodeLength(pc)) {
         PrintBytecode(cx, script, pc);
 
--- a/js/src/jsinferinlines.h
+++ b/js/src/jsinferinlines.h
@@ -572,17 +572,17 @@ TypeScript::ThisTypes(JSScript *script)
  * Note: for non-escaping arguments and locals, argTypes/localTypes reflect
  * only the initial type of the variable (e.g. passed values for argTypes,
  * or undefined for localTypes) and not types from subsequent assignments.
  */
 
 /* static */ inline StackTypeSet *
 TypeScript::ArgTypes(JSScript *script, unsigned i)
 {
-    JS_ASSERT(i < script->function()->nargs());
+    JS_ASSERT(i < script->functionNonDelazifying()->nargs());
     JS_ASSERT(CurrentThreadCanReadCompilationData());
     return script->types->typeArray() + script->nTypeSets() + analyze::ArgSlot(i);
 }
 
 template <typename TYPESET>
 /* static */ inline TYPESET *
 TypeScript::BytecodeTypes(JSScript *script, jsbytecode *pc, uint32_t *hint, TYPESET *typeArray)
 {
--- a/js/src/jsopcode.cpp
+++ b/js/src/jsopcode.cpp
@@ -405,17 +405,18 @@ class BytecodeParser
     }
 
     void reportOOM() {
         allocScope_.releaseEarly();
         js_ReportOutOfMemory(cx_);
     }
 
     uint32_t numSlots() {
-        return 1 + (script_->function() ? script_->function()->nargs() : 0) + script_->nfixed();
+        return 1 + script_->nfixed() +
+               (script_->functionNonDelazifying() ? script_->functionNonDelazifying()->nargs() : 0);
     }
 
     uint32_t maximumStackDepth() {
         return script_->nslots() - script_->nfixed();
     }
 
     Bytecode& getCode(uint32_t offset) {
         JS_ASSERT(offset < script_->length());
@@ -1507,16 +1508,18 @@ ExpressionDecompiler::decompilePC(jsbyte
         }
     }
 
     switch (op) {
       case JSOP_GETGNAME:
       case JSOP_CALLGNAME:
       case JSOP_NAME:
       case JSOP_CALLNAME:
+      case JSOP_GETINTRINSIC:
+      case JSOP_CALLINTRINSIC:
         return write(loadAtom(pc));
       case JSOP_GETARG:
       case JSOP_CALLARG: {
         unsigned slot = GET_ARGNO(pc);
         JSAtom *atom = getArg(slot);
         return write(atom);
       }
       case JSOP_GETLOCAL:
@@ -2031,18 +2034,18 @@ js::GetPCCountScriptSummary(JSContext *c
     JSString *str = JS_NewStringCopyZ(cx, script->filename());
     if (!str || !(str = StringToSource(cx, str)))
         return nullptr;
     buf.append(str);
 
     AppendJSONProperty(buf, "line");
     NumberValueToStringBuffer(cx, Int32Value(script->lineno()), buf);
 
-    if (script->function()) {
-        JSAtom *atom = script->function()->displayAtom();
+    if (script->functionNonDelazifying()) {
+        JSAtom *atom = script->functionNonDelazifying()->displayAtom();
         if (atom) {
             AppendJSONProperty(buf, "name");
             if (!(str = StringToSource(cx, atom)))
                 return nullptr;
             buf.append(str);
         }
     }
 
@@ -2164,17 +2167,17 @@ GetPCCountJSON(JSContext *cx, const Scri
             const char *name = js_CodeName[op];
             AppendJSONProperty(buf, "name");
             buf.append('\"');
             buf.appendInflated(name, strlen(name));
             buf.append('\"');
         }
 
         {
-            ExpressionDecompiler ed(cx, script, script->function());
+            ExpressionDecompiler ed(cx, script, script->functionDelazifying());
             if (!ed.init())
                 return false;
             if (!ed.decompilePC(pc))
                 return false;
             char *text;
             if (!ed.getOutput(&text))
                 return false;
             AppendJSONProperty(buf, "text");
@@ -2275,17 +2278,17 @@ js::GetPCCountScriptContents(JSContext *
         return nullptr;
     }
 
     const ScriptAndCounts &sac = (*rt->scriptAndCountsVector)[index];
     JSScript *script = sac.script;
 
     StringBuffer buf(cx);
 
-    if (!script->function() && !script->compileAndGo())
+    if (!script->functionNonDelazifying() && !script->compileAndGo())
         return buf.finishString();
 
     {
         AutoCompartment ac(cx, &script->global());
         if (!GetPCCountJSON(cx, sac, buf))
             return nullptr;
     }
 
--- a/js/src/jsscript.cpp
+++ b/js/src/jsscript.cpp
@@ -2855,22 +2855,25 @@ JSScript::markChildren(JSTracer *trc)
         MarkValueRange(trc, constarray->length, constarray->vector, "consts");
     }
 
     if (sourceObject()) {
         JS_ASSERT(sourceObject()->compartment() == compartment());
         MarkObject(trc, &sourceObject_, "sourceObject");
     }
 
-    if (function())
+    if (functionNonDelazifying())
         MarkObject(trc, &function_, "function");
 
     if (enclosingScopeOrOriginalFunction_)
         MarkObject(trc, &enclosingScopeOrOriginalFunction_, "enclosing");
 
+    if (maybeLazyScript())
+        MarkLazyScriptUnbarriered(trc, &lazyScript, "lazyScript");
+
     if (IS_GC_MARKING_TRACER(trc)) {
         compartment()->mark();
 
         if (code())
             MarkScriptData(trc->runtime, code());
     }
 
     bindings.trace(trc);
@@ -3019,17 +3022,17 @@ js::SetFrameArgumentsObject(JSContext *c
         if (frame.unaliasedLocal(var).isMagic(JS_OPTIMIZED_ARGUMENTS))
             frame.unaliasedLocal(var) = ObjectValue(*argsobj);
     }
 }
 
 /* static */ bool
 JSScript::argumentsOptimizationFailed(JSContext *cx, HandleScript script)
 {
-    JS_ASSERT(script->function());
+    JS_ASSERT(script->functionNonDelazifying());
     JS_ASSERT(script->analyzedArgsUsage());
     JS_ASSERT(script->argumentsHasVarBinding());
 
     /*
      * It is possible that the arguments optimization has already failed,
      * everything has been fixed up, but there was an outstanding magic value
      * on the stack that has just now flowed into an apply. In this case, there
      * is nothing to do; GuardFunApplySpeculation will patch in the real
@@ -3150,16 +3153,23 @@ LazyScript::LazyScript(JSFunction *fun, 
 void
 LazyScript::initScript(JSScript *script)
 {
     JS_ASSERT(script && !script_);
     script_ = script;
 }
 
 void
+LazyScript::resetScript()
+{
+    JS_ASSERT(script_);
+    script_ = nullptr;
+}
+
+void
 LazyScript::setParent(JSObject *enclosingScope, ScriptSourceObject *sourceObject)
 {
     JS_ASSERT(!sourceObject_ && !enclosingScope_);
     JS_ASSERT_IF(enclosingScope, function_->compartment() == enclosingScope->compartment());
     JS_ASSERT(function_->compartment() == sourceObject->compartment());
 
     enclosingScope_ = enclosingScope;
     sourceObject_ = sourceObject;
--- a/js/src/jsscript.h
+++ b/js/src/jsscript.h
@@ -34,16 +34,17 @@ namespace jit {
 
 # define ION_DISABLED_SCRIPT ((js::jit::IonScript *)0x1)
 # define ION_COMPILING_SCRIPT ((js::jit::IonScript *)0x2)
 
 # define BASELINE_DISABLED_SCRIPT ((js::jit::BaselineScript *)0x1)
 
 class BreakpointSite;
 class BindingIter;
+class LazyScript;
 class RegExpObject;
 struct SourceCompressionTask;
 class Shape;
 class WatchpointMap;
 class StaticBlockObject;
 
 namespace analyze {
     class ScriptAnalysis;
@@ -619,16 +620,23 @@ class JSScript : public js::gc::Barriere
 
     /* Information attached by Baseline/Ion for sequential mode execution. */
     js::jit::IonScript *ion;
     js::jit::BaselineScript *baseline;
 
     /* Information attached by Ion for parallel mode execution */
     js::jit::IonScript *parallelIon;
 
+    /* Information used to re-lazify a lazily-parsed interpreted function. */
+    js::LazyScript *lazyScript;
+
+#if JS_BITS_PER_WORD == 32
+    uint32_t padding0;
+#endif
+
     /*
      * Pointer to either baseline->method()->raw() or ion->method()->raw(), or
      * nullptr if there's no Baseline or Ion script.
      */
     uint8_t *baselineOrIonRaw;
     uint8_t *baselineOrIonSkipArgCheck;
 
     // 32-bit fields.
@@ -1178,25 +1186,47 @@ class JSScript : public js::gc::Barriere
     }
     static size_t offsetOfBaselineOrIonRaw() {
         return offsetof(JSScript, baselineOrIonRaw);
     }
     static size_t offsetOfBaselineOrIonSkipArgCheck() {
         return offsetof(JSScript, baselineOrIonSkipArgCheck);
     }
 
+    bool isRelazifiable() const {
+        return (selfHosted() || lazyScript) &&
+               !isGenerator() && !hasBaselineScript() && !hasAnyIonScript();
+    }
+    void setLazyScript(js::LazyScript *lazy) {
+        lazyScript = lazy;
+    }
+    js::LazyScript *maybeLazyScript() {
+        return lazyScript;
+    }
+
     /*
      * Original compiled function for the script, if it has a function.
      * nullptr for global and eval scripts.
+     * The delazifying variant ensures that the function isn't lazy, but can
+     * only be used under a compilation lock. The non-delazifying variant
+     * can be used off-thread and without the lock, but must only be used
+     * after earlier code has called ensureNonLazyCanonicalFunction and
+     * while the function can't have been relazified.
      */
-    JSFunction *function() const {
+    inline JSFunction *functionDelazifying() const;
+    JSFunction *functionNonDelazifying() const {
         js::AutoThreadSafeAccess ts(this);
         return function_;
     }
     inline void setFunction(JSFunction *fun);
+    /*
+     * Takes a compilation lock and de-lazifies the canonical function. Must
+     * be called before entering code that expects the function to be non-lazy.
+     */
+    inline void ensureNonLazyCanonicalFunction(JSContext *cx);
 
     JSFunction *originalFunction() const;
     void setIsCallsiteClone(JSObject *fun);
 
     JSFlatString *sourceData(JSContext *cx);
 
     static bool loadSource(JSContext *cx, js::ScriptSource *ss, bool *worked);
 
@@ -1610,21 +1640,23 @@ class LazyScript : public gc::BarrieredC
                uint32_t begin, uint32_t end, uint32_t lineno, uint32_t column);
 
   public:
     static LazyScript *Create(ExclusiveContext *cx, HandleFunction fun,
                               uint32_t numFreeVariables, uint32_t numInnerFunctions,
                               JSVersion version, uint32_t begin, uint32_t end,
                               uint32_t lineno, uint32_t column);
 
-    JSFunction *function() const {
+    inline JSFunction *functionDelazifying(JSContext *cx) const;
+    JSFunction *functionNonDelazifying() const {
         return function_;
     }
 
     void initScript(JSScript *script);
+    void resetScript();
     JSScript *maybeScript() {
         return script_;
     }
 
     JSObject *enclosingScope() const {
         return enclosingScope_;
     }
     ScriptSourceObject *sourceObject() const;
--- a/js/src/jsscriptinlines.h
+++ b/js/src/jsscriptinlines.h
@@ -40,25 +40,53 @@ ScriptCounts::destroy(FreeOp *fop)
     fop->free_(pcCountsVector);
     fop->delete_(ionCounts);
 }
 
 void
 SetFrameArgumentsObject(JSContext *cx, AbstractFramePtr frame,
                         HandleScript script, JSObject *argsobj);
 
+inline JSFunction *
+LazyScript::functionDelazifying(JSContext *cx) const
+{
+    if (function_ && !function_->getOrCreateScript(cx))
+        return nullptr;
+    return function_;
+}
+
 } // namespace js
 
+inline JSFunction *
+JSScript::functionDelazifying() const
+{
+    js::AutoThreadSafeAccess ts(this);
+    JS_ASSERT(js::CurrentThreadCanWriteCompilationData());
+    if (function_ && function_->isInterpretedLazy())
+        function_->setUnlazifiedScript(const_cast<JSScript *>(this));
+    return function_;
+}
+
 inline void
 JSScript::setFunction(JSFunction *fun)
 {
     JS_ASSERT(fun->isTenured());
     function_ = fun;
 }
 
+inline void
+JSScript::ensureNonLazyCanonicalFunction(JSContext *cx)
+{
+    // Infallibly delazify the canonical script.
+    if (function_ && function_->isInterpretedLazy()) {
+        js::AutoLockForCompilation lock(cx);
+        functionDelazifying();
+    }
+}
+
 inline JSFunction *
 JSScript::getFunction(size_t index)
 {
     JSFunction *fun = &getObject(index)->as<JSFunction>();
 #ifdef DEBUG
     JS_ASSERT_IF(fun->isNative(), IsAsmJSModuleNative(fun->native()));
 #endif
     return fun;
@@ -69,18 +97,18 @@ JSScript::getCallerFunction()
 {
     JS_ASSERT(savedCallerFun());
     return getFunction(0);
 }
 
 inline JSFunction *
 JSScript::functionOrCallerFunction()
 {
-    if (function())
-        return function();
+    if (functionNonDelazifying())
+        return functionNonDelazifying();
     if (savedCallerFun())
         return getCallerFunction();
     return nullptr;
 }
 
 inline js::RegExpObject *
 JSScript::getRegExp(size_t index)
 {
--- a/js/src/jsstr.cpp
+++ b/js/src/jsstr.cpp
@@ -1417,125 +1417,137 @@ str_lastIndexOf(JSContext *cx, unsigned 
         }
       break_continue:;
     }
 
     args.rval().setInt32(-1);
     return true;
 }
 
-/* ES6 20120927 draft 15.5.4.22. */
+/* ES6 20131108 draft 21.1.3.18. */
 static bool
 str_startsWith(JSContext *cx, unsigned argc, Value *vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
 
     // Steps 1, 2, and 3
     RootedString str(cx, ThisToStringForStringProto(cx, args));
     if (!str)
         return false;
 
-    // Steps 4 and 5
+    // Step 4
+    if (args.get(0).isObject() && IsObjectWithClass(args[0], ESClass_RegExp, cx)) {
+        JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_INVALID_ARG_TYPE,
+                             "first", "", "Regular Expression");
+        return false;
+    }
+
+    // Steps 5 and 6
     Rooted<JSLinearString*> searchStr(cx, ArgToRootedString(cx, args, 0));
     if (!searchStr)
         return false;
 
-    // Steps 6 and 7
+    // Steps 7 and 8
     uint32_t pos = 0;
     if (args.hasDefined(1)) {
         if (args[1].isInt32()) {
             int i = args[1].toInt32();
             pos = (i < 0) ? 0U : uint32_t(i);
         } else {
             double d;
             if (!ToInteger(cx, args[1], &d))
                 return false;
             pos = uint32_t(Min(Max(d, 0.0), double(UINT32_MAX)));
         }
     }
 
-    // Step 8
+    // Step 9
     uint32_t textLen = str->length();
     const jschar *textChars = str->getChars(cx);
     if (!textChars)
         return false;
 
-    // Step 9
+    // Step 10
     uint32_t start = Min(Max(pos, 0U), textLen);
 
-    // Step 10
+    // Step 11
     uint32_t searchLen = searchStr->length();
     const jschar *searchChars = searchStr->chars();
 
-    // Step 11
+    // Step 12
     if (searchLen + start < searchLen || searchLen + start > textLen) {
         args.rval().setBoolean(false);
         return true;
     }
 
-    // Steps 12 and 13
+    // Steps 13 and 14
     args.rval().setBoolean(PodEqual(textChars + start, searchChars, searchLen));
     return true;
 }
 
-/* ES6 20120708 draft 15.5.4.23. */
+/* ES6 20131108 draft 21.1.3.7. */
 static bool
 str_endsWith(JSContext *cx, unsigned argc, Value *vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
 
     // Steps 1, 2, and 3
     RootedString str(cx, ThisToStringForStringProto(cx, args));
     if (!str)
         return false;
 
-    // Steps 4 and 5
+    // Step 4
+    if (args.get(0).isObject() && IsObjectWithClass(args[0], ESClass_RegExp, cx)) {
+        JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_INVALID_ARG_TYPE,
+                             "first", "", "Regular Expression");
+        return false;
+    }
+
+    // Steps 5 and 6
     Rooted<JSLinearString *> searchStr(cx, ArgToRootedString(cx, args, 0));
     if (!searchStr)
         return false;
 
-    // Step 6
+    // Step 7
     uint32_t textLen = str->length();
-
-    // Steps 7 and 8
+    const jschar *textChars = str->getChars(cx);
+    if (!textChars)
+        return false;
+
+    // Steps 8 and 9
     uint32_t pos = textLen;
     if (args.hasDefined(1)) {
         if (args[1].isInt32()) {
             int i = args[1].toInt32();
             pos = (i < 0) ? 0U : uint32_t(i);
         } else {
             double d;
             if (!ToInteger(cx, args[1], &d))
                 return false;
             pos = uint32_t(Min(Max(d, 0.0), double(UINT32_MAX)));
         }
     }
 
-    // Step 6
-    const jschar *textChars = str->getChars(cx);
-    if (!textChars)
-        return false;
-
-    // Step 9
+    // Step 10
     uint32_t end = Min(Max(pos, 0U), textLen);
 
-    // Step 10
+    // Step 11
     uint32_t searchLen = searchStr->length();
     const jschar *searchChars = searchStr->chars();
 
-    // Step 12
+    // Step 13 (reordered)
     if (searchLen > end) {
         args.rval().setBoolean(false);
         return true;
     }
 
-    // Step 11
+    // Step 12
     uint32_t start = end - searchLen;
 
-    // Steps 13 and 14
+    // Steps 14 and 15
     args.rval().setBoolean(PodEqual(textChars + start, searchChars, searchLen));
     return true;
 }
 
 static bool
 js_TrimString(JSContext *cx, Value *vp, bool trimLeft, bool trimRight)
 {
     CallReceiver call = CallReceiverFromVp(vp);
--- a/js/src/jsworkers.cpp
+++ b/js/src/jsworkers.cpp
@@ -585,17 +585,17 @@ CallNewScriptHookForAllScripts(JSContext
                     RootedScript nested(cx, fun->nonLazyScript());
                     CallNewScriptHookForAllScripts(cx, nested);
                 }
             }
         }
     }
 
     // The global new script hook is called on every script that was compiled.
-    RootedFunction function(cx, script->function());
+    RootedFunction function(cx, script->functionNonDelazifying());
     CallNewScriptHook(cx, script, function);
 }
 
 JSScript *
 WorkerThreadState::finishParseTask(JSContext *maybecx, JSRuntime *rt, void *token)
 {
     ParseTask *parseTask = nullptr;
 
new file mode 100644
--- /dev/null
+++ b/js/src/tests/ecma_6/TypedObject/arraybuffer_isview.js
@@ -0,0 +1,25 @@
+var BUGNUMBER = 896105;
+var summary = 'ArrayBuffer.isView';
+
+/*
+ * Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/licenses/publicdomain/
+ */
+
+function runTests() {
+  assertEq(ArrayBuffer.isView(), false);
+  assertEq(ArrayBuffer.isView(undefined), false);
+  assertEq(ArrayBuffer.isView(null), false);
+  assertEq(ArrayBuffer.isView("primitive"), false);
+  assertEq(ArrayBuffer.isView({}), false);
+  assertEq(ArrayBuffer.isView([]), false);
+  assertEq(ArrayBuffer.isView(new ArrayBuffer(10)), false);
+  assertEq(ArrayBuffer.isView(new Int8Array(10)), true);
+  assertEq(ArrayBuffer.isView(new Int8Array(10).subarray(0, 3)), true);
+
+  if (typeof reportCompare !== 'undefined')
+    reportCompare(true, true);
+  print("Tests complete");
+}
+
+runTests();
--- a/js/src/vm/ArgumentsObject.cpp
+++ b/js/src/vm/ArgumentsObject.cpp
@@ -336,17 +336,17 @@ ArgSetter(JSContext *cx, HandleObject ob
 
     NormalArgumentsObject &argsobj = obj->as<NormalArgumentsObject>();
     RootedScript script(cx, argsobj.containingScript());
 
     if (JSID_IS_INT(id)) {
         unsigned arg = unsigned(JSID_TO_INT(id));
         if (arg < argsobj.initialLength() && !argsobj.isElementDeleted(arg)) {
             argsobj.setElement(cx, arg, vp);
-            if (arg < script->function()->nargs())
+            if (arg < script->functionNonDelazifying()->nargs())
                 types::TypeScript::SetArgument(cx, script, arg, vp);
             return true;
         }
     } else {
         JS_ASSERT(JSID_IS_ATOM(id, cx->names().length) || JSID_IS_ATOM(id, cx->names().callee));
     }
 
     /*
--- a/js/src/vm/ForkJoin.cpp
+++ b/js/src/vm/ForkJoin.cpp
@@ -1,14 +1,20 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
  * vim: set ts=8 sts=4 et sw=4 tw=99:
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
+#if defined(XP_OS2) || defined(XP_WIN)
+# include <io.h>     // for isatty()
+#else
+# include <unistd.h> // for isatty()
+#endif
+
 #include "vm/ForkJoin.h"
 
 #include "mozilla/ThreadLocal.h"
 
 #include "jscntxt.h"
 #include "jslock.h"
 #include "jsprf.h"
 
@@ -35,33 +41,28 @@ using mozilla::ThreadLocal;
 ///////////////////////////////////////////////////////////////////////////
 // Degenerate configurations
 //
 // When JS_THREADSAFE or JS_ION is not defined, we simply run the
 // |func| callback sequentially.  We also forego the feedback
 // altogether.
 
 static bool
-ExecuteSequentially(JSContext *cx_, HandleValue funVal, bool *complete);
+ExecuteSequentially(JSContext *cx_, HandleValue funVal, bool *complete,
+                    uint16_t sliceStart, uint16_t numSlices);
 
 #if !defined(JS_THREADSAFE) || !defined(JS_ION)
 bool
 js::ForkJoin(JSContext *cx, CallArgs &args)
 {
     RootedValue argZero(cx, args[0]);
     bool complete = false; // since warmup is false, will always complete
     return ExecuteSequentially(cx, argZero, &complete);
 }
 
-uint32_t
-js::ForkJoinSlices(JSContext *cx)
-{
-    return 1; // just the main thread
-}
-
 JSContext *
 ForkJoinSlice::acquireContext()
 {
     return nullptr;
 }
 
 void
 ForkJoinSlice::releaseContext()
@@ -145,30 +146,29 @@ js::ParallelTestsShouldPass(JSContext *c
 #endif // !JS_THREADSAFE || !JS_ION
 
 ///////////////////////////////////////////////////////////////////////////
 // All configurations
 //
 // Some code that is shared between degenerate and parallel configurations.
 
 static bool
-ExecuteSequentially(JSContext *cx, HandleValue funVal, bool *complete)
+ExecuteSequentially(JSContext *cx, HandleValue funVal, bool *complete,
+                    uint16_t sliceStart, uint16_t numSlices)
 {
-    uint32_t numSlices = ForkJoinSlices(cx);
     bool allComplete = true;
-    for (uint32_t i = 0; i < numSlices; i++) {
+    for (uint16_t i = sliceStart; i < numSlices; i++) {
         FastInvokeGuard fig(cx, funVal);
         InvokeArgs &args = fig.args();
-        if (!args.init(3))
+        if (!args.init(2))
             return false;
         args.setCallee(funVal);
         args.setThis(UndefinedValue());
         args[0].setInt32(i);
-        args[1].setInt32(numSlices);
-        args[2].setBoolean(!!cx->runtime()->parallelWarmup);
+        args[1].setBoolean(!!cx->runtime()->parallelWarmup);
         if (!fig.invoke(cx))
             return false;
         allComplete = allComplete & args.rval().toBoolean();
     }
     *complete = allComplete;
     return true;
 }
 
@@ -225,29 +225,29 @@ enum ForkJoinMode {
 
     // Expects all parallel executions to yield a bailout.  If this is not
     // the case, reports an error.
     ForkJoinModeBailout,
 
     NumForkJoinModes
 };
 
-class ParallelDo
+class ForkJoinOperation
 {
   public:
     // For tests, make sure to keep this in sync with minItemsTestingThreshold.
     static const uint32_t MAX_BAILOUTS = 3;
     uint32_t bailouts;
 
     // Information about the bailout:
     ParallelBailoutCause bailoutCause;
     RootedScript bailoutScript;
     jsbytecode *bailoutBytecode;
 
-    ParallelDo(JSContext *cx, HandleObject fun, ForkJoinMode mode);
+    ForkJoinOperation(JSContext *cx, HandleObject fun, ForkJoinMode mode, uint16_t numSlices);
     ExecutionStatus apply();
 
   private:
     // Most of the functions involved in managing the parallel
     // compilation follow a similar control-flow. They return RedLight
     // if they have either encountered a fatal error or completed the
     // execution, such that no further work is needed. In that event,
     // they take an `ExecutionStatus*` which they use to report
@@ -280,16 +280,18 @@ class ParallelDo
     };
 
     JSContext *cx_;
     HandleObject fun_;
     Vector<ParallelBailoutRecord, 16> bailoutRecords_;
     AutoScriptVector worklist_;
     Vector<WorklistData, 16> worklistData_;
     ForkJoinMode mode_;
+    uint16_t warmupSlice_;
+    uint16_t numSlices_;
 
     TrafficLight enqueueInitialScript(ExecutionStatus *status);
     TrafficLight compileForParallelExecution(ExecutionStatus *status);
     TrafficLight warmupExecution(bool stopIfComplete,
                                  ExecutionStatus *status);
     TrafficLight parallelExecution(ExecutionStatus *status);
     TrafficLight sequentialExecution(bool disqualified, ExecutionStatus *status);
     TrafficLight recoverFromBailout(ExecutionStatus *status);
@@ -299,111 +301,83 @@ class ParallelDo
     ExecutionStatus sequentialExecution(bool disqualified);
 
     TrafficLight appendCallTargetsToWorklist(uint32_t index,
                                              ExecutionStatus *status);
     TrafficLight appendCallTargetToWorklist(HandleScript script,
                                             ExecutionStatus *status);
     bool addToWorklist(HandleScript script);
     inline bool hasScript(Vector<types::RecompileInfo> &scripts, JSScript *script);
-}; // class ParallelDo
+}; // class ForkJoinOperation
 
-class ForkJoinShared : public TaskExecutor, public Monitor
+class ForkJoinShared : public ParallelJob, public Monitor
 {
     /////////////////////////////////////////////////////////////////////////
     // Constant fields
 
     JSContext *const cx_;          // Current context
     ThreadPool *const threadPool_; // The thread pool.
     HandleObject fun_;             // The JavaScript function to execute.
-    const uint32_t numSlices_;     // Total number of threads.
-    PRCondVar *rendezvousEnd_;     // Cond. var used to signal end of rendezvous.
+    uint16_t numSlices_;           // Total number of slices. Dynamically changed
     PRLock *cxLock_;               // Locks cx_ for parallel VM calls.
     ParallelBailoutRecord *const records_; // Bailout records for each slice
 
     /////////////////////////////////////////////////////////////////////////
     // Per-thread arenas
     //
     // Each worker thread gets an arena to use when allocating.
 
     Vector<Allocator *, 16> allocators_;
 
     /////////////////////////////////////////////////////////////////////////
     // Locked Fields
     //
     // Only to be accessed while holding the lock.
 
-    uint32_t uncompleted_;          // Number of uncompleted worker threads
-    uint32_t blocked_;              // Number of threads that have joined rendezvous
-    uint32_t rendezvousIndex_;      // Number of rendezvous attempts
     bool gcRequested_;              // True if a worker requested a GC
     JS::gcreason::Reason gcReason_; // Reason given to request GC
     Zone *gcZone_;                  // Zone for GC, or nullptr for full
 
     /////////////////////////////////////////////////////////////////////////
     // Asynchronous Flags
     //
     // These can be read without the lock (hence the |volatile| declaration).
     // All fields should be *written with the lock*, however.
 
     // Set to true when parallel execution should abort.
     volatile bool abort_;
 
     // Set to true when a worker bails for a fatal reason.
     volatile bool fatal_;
 
-    // The main thread has requested a rendezvous.
-    volatile bool rendezvous_;
-
-    // Invoked only from the main thread:
-    void executeFromMainThread();
-
-    // Executes slice #threadId of the work, either from a worker or
-    // the main thread.
-    void executePortion(PerThreadData *perThread, uint32_t threadId);
-
-    // Rendezvous protocol:
-    //
-    // Use AutoRendezvous rather than invoking initiateRendezvous() and
-    // endRendezvous() directly.
-
-    friend class AutoRendezvous;
-
-    // Requests that the other threads stop.  Must be invoked from the main
-    // thread.
-    void initiateRendezvous(ForkJoinSlice &threadCx);
-
-    // If a rendezvous has been requested, blocks until the main thread says
-    // we may continue.
-    void joinRendezvous(ForkJoinSlice &threadCx);
-
-    // Permits other threads to resume execution.  Must be invoked from the
-    // main thread after a call to initiateRendezvous().
-    void endRendezvous(ForkJoinSlice &threadCx);
-
   public:
     ForkJoinShared(JSContext *cx,
                    ThreadPool *threadPool,
                    HandleObject fun,
-                   uint32_t numSlices,
-                   uint32_t uncompleted,
+                   uint16_t numSlices,
                    ParallelBailoutRecord *records);
     ~ForkJoinShared();
 
     bool init();
 
     ParallelResult execute();
 
     // Invoked from parallel worker threads:
-    virtual void executeFromWorker(uint32_t threadId, uintptr_t stackLimit);
+    virtual bool executeFromWorker(uint16_t sliceId, uint32_t workerId,
+                                   uintptr_t stackLimit) MOZ_OVERRIDE;
+
+    // Invoked only from the main thread:
+    virtual bool executeFromMainThread(uint16_t sliceId) MOZ_OVERRIDE;
 
-    // Moves all the per-thread arenas into the main compartment and
-    // processes any pending requests for a GC.  This can only safely
-    // be invoked on the main thread, either during a rendezvous or
-    // after the workers have completed.
+    // Executes slice |sliceId| either from a worker or the main thread.
+    void executePortion(PerThreadData *perThread, uint16_t sliceId, uint32_t workerId);
+
+    // Moves all the per-thread arenas into the main compartment and processes
+    // any pending requests for a GC. This can only safely be invoked on the
+    // main thread after the workers have completed.
     void transferArenasToCompartmentAndProcessGCRequests();
 
     // Invoked during processing by worker threads to "check in".
     bool check(ForkJoinSlice &threadCx);
 
     // Requests a GC, either full or specific to a zone.
     void requestGC(JS::gcreason::Reason reason);
     void requestZoneGC(JS::Zone *zone, JS::gcreason::Reason reason);
@@ -426,33 +400,16 @@ class AutoEnterWarmup
 {
     JSRuntime *runtime_;
 
   public:
     AutoEnterWarmup(JSRuntime *runtime) : runtime_(runtime) { runtime_->parallelWarmup++; }
     ~AutoEnterWarmup() { runtime_->parallelWarmup--; }
 };
 
-class AutoRendezvous
-{
-  private:
-    ForkJoinSlice &threadCx;
-
-  public:
-    AutoRendezvous(ForkJoinSlice &threadCx)
-        : threadCx(threadCx)
-    {
-        threadCx.shared->initiateRendezvous(threadCx);
-    }
-
-    ~AutoRendezvous() {
-        threadCx.shared->endRendezvous(threadCx);
-    }
-};
-
 class AutoSetForkJoinSlice
 {
   public:
     AutoSetForkJoinSlice(ForkJoinSlice *threadCx) {
         ForkJoinSlice::tlsForkJoinSlice.set(threadCx);
     }
 
     ~AutoSetForkJoinSlice() {
@@ -495,39 +452,40 @@ ForkJoinActivation::ForkJoinActivation(J
 }
 
 ForkJoinActivation::~ForkJoinActivation()
 {
     cx_->mainThread().ionTop = prevIonTop_;
 }
 
 ///////////////////////////////////////////////////////////////////////////
-// js::ForkJoin() and ParallelDo class
+// js::ForkJoin() and ForkJoinOperation class
 //
 // These are the top-level objects that manage the parallel execution.
 // They handle parallel compilation (if necessary), triggering
 // parallel execution, and recovering from bailouts.
 
 static const char *ForkJoinModeString(ForkJoinMode mode);
 
 bool
 js::ForkJoin(JSContext *cx, CallArgs &args)
 {
-    JS_ASSERT(args[0].isObject()); // else the self-hosted code is wrong
+    JS_ASSERT(args.length() == 3); // else the self-hosted code is wrong
+    JS_ASSERT(args[0].isObject());
     JS_ASSERT(args[0].toObject().is<JSFunction>());
-
-    ForkJoinMode mode = ForkJoinModeNormal;
-    if (args.length() > 1) {
-        JS_ASSERT(args[1].isInt32()); // else the self-hosted code is wrong
-        JS_ASSERT(args[1].toInt32() < NumForkJoinModes);
-        mode = (ForkJoinMode) args[1].toInt32();
-    }
+    JS_ASSERT(args[1].isInt32());
+    JS_ASSERT(args[1].toInt32() < NumForkJoinModes);
+    JS_ASSERT(args[2].isInt32());
 
     RootedObject fun(cx, &args[0].toObject());
-    ParallelDo op(cx, fun, mode);
+    ForkJoinMode mode = (ForkJoinMode) args[1].toInt32();
+    uint32_t numSlices = args[2].toInt32();
+    MOZ_ASSERT(uint32_t(uint16_t(numSlices)) == numSlices);
+
+    ForkJoinOperation op(cx, fun, mode, numSlices);
     ExecutionStatus status = op.apply();
     if (status == ExecutionFatal)
         return false;
 
     switch (mode) {
       case ForkJoinModeNormal:
       case ForkJoinModeCompile:
         return true;
@@ -576,33 +534,34 @@ ForkJoinModeString(ForkJoinMode mode) {
       case ForkJoinModeParallel: return "parallel";
       case ForkJoinModeRecover: return "recover";
       case ForkJoinModeBailout: return "bailout";
       case NumForkJoinModes: return "max";
     }
     return "???";
 }
 
-js::ParallelDo::ParallelDo(JSContext *cx,
-                           HandleObject fun,
-                           ForkJoinMode mode)
+js::ForkJoinOperation::ForkJoinOperation(JSContext *cx, HandleObject fun, ForkJoinMode mode,
+                                         uint16_t numSlices)
   : bailouts(0),
     bailoutCause(ParallelBailoutNone),
     bailoutScript(cx),
     bailoutBytecode(nullptr),
     cx_(cx),
     fun_(fun),
     bailoutRecords_(cx),
     worklist_(cx),
     worklistData_(cx),
-    mode_(mode)
+    mode_(mode),
+    warmupSlice_(0),
+    numSlices_(numSlices)
 { }
 
 ExecutionStatus
-js::ParallelDo::apply()
+js::ForkJoinOperation::apply()
 {
     ExecutionStatus status;
 
     // High level outline of the procedure:
     //
     // - As we enter, we check for parallel script without "uncompiled" flag.
     // - If present, skip initial enqueue.
     // - While not too many bailouts:
@@ -622,24 +581,25 @@ js::ParallelDo::apply()
     //       - Invalidate any scripts that may need to be invalidated
     //       - Re-enqueue main script and any uncompiled scripts that were called
     // - Too many bailouts: Fallback to sequential
 
     JS_ASSERT_IF(!jit::IsBaselineEnabled(cx_), !jit::IsIonEnabled(cx_));
     if (!jit::IsBaselineEnabled(cx_) || !jit::IsIonEnabled(cx_))
         return sequentialExecution(true);
 
-    SpewBeginOp(cx_, "ParallelDo");
+    SpewBeginOp(cx_, "ForkJoinOperation");
 
-    uint32_t slices = ForkJoinSlices(cx_);
+    // How many workers do we have, counting the main thread.
+    unsigned numWorkersWithMain = cx_->runtime()->threadPool.numWorkers() + 1;
 
-    if (!bailoutRecords_.resize(slices))
+    if (!bailoutRecords_.resize(numWorkersWithMain))
         return SpewEndOp(ExecutionFatal);
 
-    for (uint32_t i = 0; i < slices; i++)
+    for (uint32_t i = 0; i < numWorkersWithMain; i++)
         bailoutRecords_[i].init(cx_);
 
     if (enqueueInitialScript(&status) == RedLight)
         return SpewEndOp(status);
 
     Spew(SpewOps, "Execution mode: %s", ForkJoinModeString(mode_));
     switch (mode_) {
       case ForkJoinModeNormal:
@@ -659,17 +619,17 @@ js::ParallelDo::apply()
         }
         break;
 
       case NumForkJoinModes:
         MOZ_ASSUME_UNREACHABLE("Invalid mode");
     }
 
     while (bailouts < MAX_BAILOUTS) {
-        for (uint32_t i = 0; i < slices; i++)
+        for (uint32_t i = 0; i < numWorkersWithMain; i++)
             bailoutRecords_[i].reset(cx_);
 
         if (compileForParallelExecution(&status) == RedLight)
             return SpewEndOp(status);
 
         JS_ASSERT(worklist_.length() == 0);
         if (parallelExecution(&status) == RedLight)
             return SpewEndOp(status);
@@ -677,18 +637,18 @@ js::ParallelDo::apply()
         if (recoverFromBailout(&status) == RedLight)
             return SpewEndOp(status);
     }
 
     // After enough tries, just execute sequentially.
     return SpewEndOp(sequentialExecution(true));
 }
 
-js::ParallelDo::TrafficLight
-js::ParallelDo::enqueueInitialScript(ExecutionStatus *status)
+js::ForkJoinOperation::TrafficLight
+js::ForkJoinOperation::enqueueInitialScript(ExecutionStatus *status)
 {
     // GreenLight: script successfully enqueued if necessary
     // RedLight: fatal error or fell back to sequential
 
     // The kernel should be a self-hosted function.
     if (!fun_->is<JSFunction>())
         return sequentialExecution(true, status);
 
@@ -715,18 +675,18 @@ js::ParallelDo::enqueueInitialScript(Exe
     }
 
     // Otherwise, add to the worklist of scripts to process.
     if (addToWorklist(script) == RedLight)
         return fatalError(status);
     return GreenLight;
 }
 
-js::ParallelDo::TrafficLight
-js::ParallelDo::compileForParallelExecution(ExecutionStatus *status)
+js::ForkJoinOperation::TrafficLight
+js::ForkJoinOperation::compileForParallelExecution(ExecutionStatus *status)
 {
     // GreenLight: all scripts compiled
     // RedLight: fatal error or completed work via warmups or fallback
 
     // This routine attempts to do whatever compilation is necessary
     // to execute a single parallel attempt. When it returns, either
     // (1) we have fallen back to sequential; (2) we have run enough
     // warmup runs to complete all the work; or (3) we have compiled
@@ -748,17 +708,18 @@ js::ParallelDo::compileForParallelExecut
     // warmup iterations.
     while (true) {
         bool offMainThreadCompilationsInProgress = false;
         bool gatheringTypeInformation = false;
 
         // Walk over the worklist to check on the status of each entry.
         for (uint32_t i = 0; i < worklist_.length(); i++) {
             script = worklist_[i];
-            fun = script->function();
+            script->ensureNonLazyCanonicalFunction(cx_);
+            fun = script->functionNonDelazifying();
 
             // No baseline script means no type information, hence we
             // will not be able to compile very well.  In such cases,
             // we continue to run baseline iterations until either (1)
             // the potential callee *has* a baseline script or (2) the
             // potential callee's use count stops increasing,
             // indicating that they are not in fact a callee.
             if (!script->hasBaselineScript()) {
@@ -905,19 +866,18 @@ js::ParallelDo::compileForParallelExecut
             JS_ASSERT(worklistData_[i].stallCount >= stallThreshold);
         }
     }
     worklist_.clear();
     worklistData_.clear();
     return GreenLight;
 }
 
-js::ParallelDo::TrafficLight
-js::ParallelDo::appendCallTargetsToWorklist(uint32_t index,
-                                            ExecutionStatus *status)
+js::ForkJoinOperation::TrafficLight
+js::ForkJoinOperation::appendCallTargetsToWorklist(uint32_t index, ExecutionStatus *status)
 {
     // GreenLight: call targets appended
     // RedLight: fatal error or completed work via warmups or fallback
 
     JS_ASSERT(worklist_[index]->hasParallelIonScript());
 
     // Check whether we have already enqueued the targets for
     // this entry and avoid doing it again if so.
@@ -935,19 +895,18 @@ js::ParallelDo::appendCallTargetsToWorkl
                        target->filename(), target->lineno());
         if (appendCallTargetToWorklist(target, status) == RedLight)
             return RedLight;
     }
 
     return GreenLight;
 }
 
-js::ParallelDo::TrafficLight
-js::ParallelDo::appendCallTargetToWorklist(HandleScript script,
-                                           ExecutionStatus *status)
+js::ForkJoinOperation::TrafficLight
+js::ForkJoinOperation::appendCallTargetToWorklist(HandleScript script, ExecutionStatus *status)
 {
     // GreenLight: call target appended if necessary
     // RedLight: fatal error or completed work via warmups or fallback
 
     JS_ASSERT(script);
 
     // Fallback to sequential if disabled.
     if (!script->canParallelIonCompile()) {
@@ -967,17 +926,17 @@ js::ParallelDo::appendCallTargetToWorkli
 
     if (!addToWorklist(script))
         return fatalError(status);
 
     return GreenLight;
 }
 
 bool
-js::ParallelDo::addToWorklist(HandleScript script)
+js::ForkJoinOperation::addToWorklist(HandleScript script)
 {
     for (uint32_t i = 0; i < worklist_.length(); i++) {
         if (worklist_[i] == script) {
             Spew(SpewCompile, "Skipping %p:%s:%u, already in worklist",
                  script.get(), script->filename(), script->lineno());
             return true;
         }
     }
@@ -995,46 +954,46 @@ js::ParallelDo::addToWorklist(HandleScri
     // we have not yet enqueued the callees of this script
     if (!worklistData_.append(WorklistData()))
         return false;
     worklistData_[worklistData_.length() - 1].reset();
 
     return true;
 }
 
-js::ParallelDo::TrafficLight
-js::ParallelDo::sequentialExecution(bool disqualified, ExecutionStatus *status)
+js::ForkJoinOperation::TrafficLight
+js::ForkJoinOperation::sequentialExecution(bool disqualified, ExecutionStatus *status)
 {
     // RedLight: fatal error or completed work
 
     *status = sequentialExecution(disqualified);
     return RedLight;
 }
 
 ExecutionStatus
-js::ParallelDo::sequentialExecution(bool disqualified)
+js::ForkJoinOperation::sequentialExecution(bool disqualified)
 {
     // XXX use disqualified to set parallelIon to ION_DISABLED_SCRIPT?
 
     Spew(SpewOps, "Executing sequential execution (disqualified=%d).",
          disqualified);
 
     bool complete = false;
     RootedValue funVal(cx_, ObjectValue(*fun_));
-    if (!ExecuteSequentially(cx_, funVal, &complete))
+    if (!ExecuteSequentially(cx_, funVal, &complete, 0, numSlices_))
         return ExecutionFatal;
 
     // When invoked without the warmup flag set to true, the kernel
     // function OUGHT to complete successfully, barring an exception.
     JS_ASSERT(complete);
     return ExecutionSequential;
 }
 
-js::ParallelDo::TrafficLight
-js::ParallelDo::fatalError(ExecutionStatus *status)
+js::ForkJoinOperation::TrafficLight
+js::ForkJoinOperation::fatalError(ExecutionStatus *status)
 {
     // RedLight: fatal error
 
     *status = ExecutionFatal;
     return RedLight;
 }
 
 static const char *
@@ -1076,17 +1035,17 @@ BailoutExplanation(ParallelBailoutCause 
       case ParallelBailoutRequestedZoneGC:
         return "requested zone GC";
       default:
         return "no known reason";
     }
 }
 
 void
-js::ParallelDo::determineBailoutCause()
+js::ForkJoinOperation::determineBailoutCause()
 {
     bailoutCause = ParallelBailoutNone;
     for (uint32_t i = 0; i < bailoutRecords_.length(); i++) {
         if (bailoutRecords_[i].cause == ParallelBailoutNone)
             continue;
 
         if (bailoutRecords_[i].cause == ParallelBailoutInterrupt)
             continue;
@@ -1114,17 +1073,17 @@ js::ParallelDo::determineBailoutCause()
             Spew(SpewBailouts, "Bailout from thread %d: cause %d, unknown loc",
                  i,
                  bailoutCause);
         }
     }
 }
 
 bool
-js::ParallelDo::invalidateBailedOutScripts()
+js::ForkJoinOperation::invalidateBailedOutScripts()
 {
     Vector<types::RecompileInfo> invalid(cx_);
     for (uint32_t i = 0; i < bailoutRecords_.length(); i++) {
         RootedScript script(cx_, bailoutRecords_[i].topScript);
 
         // No script to invalidate.
         if (!script || !script->hasParallelIonScript())
             continue;
@@ -1166,61 +1125,73 @@ js::ParallelDo::invalidateBailedOutScrip
             return false;
     }
 
     Invalidate(cx_, invalid);
 
     return true;
 }
 
-js::ParallelDo::TrafficLight
-js::ParallelDo::warmupExecution(bool stopIfComplete,
-                                ExecutionStatus *status)
+js::ForkJoinOperation::TrafficLight
+js::ForkJoinOperation::warmupExecution(bool stopIfComplete, ExecutionStatus *status)
 {
     // GreenLight: warmup succeeded, still more work to do
     // RedLight: fatal error or warmup completed all work (check status)
 
-    Spew(SpewOps, "Executing warmup.");
+    Spew(SpewOps, "Executing warmup of slice %u.", warmupSlice_);
 
     AutoEnterWarmup warmup(cx_->runtime());
     RootedValue funVal(cx_, ObjectValue(*fun_));
     bool complete;
-    if (!ExecuteSequentially(cx_, funVal, &complete)) {
+    uint32_t warmupTo = Min<uint16_t>(warmupSlice_ + 1, numSlices_);
+    if (!ExecuteSequentially(cx_, funVal, &complete, warmupSlice_, warmupTo)) {
         *status = ExecutionFatal;
         return RedLight;
     }
 
-    if (complete && stopIfComplete) {
-        Spew(SpewOps, "Warmup execution finished all the work.");
-        *status = ExecutionWarmup;
-        return RedLight;
+    if (complete) {
+        warmupSlice_ = warmupTo;
+        if (warmupSlice_ == numSlices_) {
+            if (stopIfComplete) {
+                Spew(SpewOps, "Warmup execution finished all the work.");
+                *status = ExecutionWarmup;
+                return RedLight;
+            }
+
+            // If we finished all slices in warmup, be sure check the
+            // interrupt flag. This is because we won't be running more JS
+            // code, and thus no more automatic checking of the interrupt
+            // flag.
+            if (!js_HandleExecutionInterrupt(cx_)) {
+                *status = ExecutionFatal;
+                return RedLight;
+            }
+        }
     }
 
     return GreenLight;
 }
 
-js::ParallelDo::TrafficLight
-js::ParallelDo::parallelExecution(ExecutionStatus *status)
+js::ForkJoinOperation::TrafficLight
+js::ForkJoinOperation::parallelExecution(ExecutionStatus *status)
 {
     // GreenLight: bailout occurred, keep trying
     // RedLight: fatal error or all work completed
 
     // Recursive use of the ThreadPool is not supported.  Right now we
     // cannot get here because parallel code cannot invoke native
     // functions such as ForkJoin().
     JS_ASSERT(ForkJoinSlice::current() == nullptr);
 
     ForkJoinActivation activation(cx_);
 
     ThreadPool *threadPool = &cx_->runtime()->threadPool;
-    uint32_t numSlices = ForkJoinSlices(cx_);
 
     RootedObject rootedFun(cx_, fun_);
-    ForkJoinShared shared(cx_, threadPool, rootedFun, numSlices, numSlices - 1,
-                          &bailoutRecords_[0]);
+    ForkJoinShared shared(cx_, threadPool, rootedFun, numSlices_, &bailoutRecords_[0]);
     if (!shared.init()) {
         *status = ExecutionFatal;
         return RedLight;
     }
 
     switch (shared.execute()) {
       case TP_SUCCESS:
         *status = ExecutionParallel;
@@ -1233,18 +1204,18 @@ js::ParallelDo::parallelExecution(Execut
       case TP_RETRY_SEQUENTIALLY:
       case TP_RETRY_AFTER_GC:
         break; // bailout
     }
 
     return GreenLight;
 }
 
-js::ParallelDo::TrafficLight
-js::ParallelDo::recoverFromBailout(ExecutionStatus *status)
+js::ForkJoinOperation::TrafficLight
+js::ForkJoinOperation::recoverFromBailout(ExecutionStatus *status)
 {
     // GreenLight: bailout recovered, try to compile-and-run again
     // RedLight: fatal error
 
     bailouts += 1;
     determineBailoutCause();
 
     SpewBailout(bailouts, bailoutScript, bailoutBytecode, bailoutCause);
@@ -1262,17 +1233,17 @@ js::ParallelDo::recoverFromBailout(Execu
 
     if (warmupExecution(/*stopIfComplete:*/true, status) == RedLight)
         return RedLight;
 
     return GreenLight;
 }
 
 bool
-js::ParallelDo::hasScript(Vector<types::RecompileInfo> &scripts, JSScript *script)
+js::ForkJoinOperation::hasScript(Vector<types::RecompileInfo> &scripts, JSScript *script)
 {
     for (uint32_t i = 0; i < scripts.length(); i++) {
         if (scripts[i] == script->parallelIonScript()->recompileInfo())
             return true;
     }
     return false;
 }
 
@@ -1319,36 +1290,30 @@ class ParallelIonInvoke
 
 /////////////////////////////////////////////////////////////////////////////
 // ForkJoinShared
 //
 
 ForkJoinShared::ForkJoinShared(JSContext *cx,
                                ThreadPool *threadPool,
                                HandleObject fun,
-                               uint32_t numSlices,
-                               uint32_t uncompleted,
+                               uint16_t numSlices,
                                ParallelBailoutRecord *records)
   : cx_(cx),
     threadPool_(threadPool),
     fun_(fun),
     numSlices_(numSlices),
-    rendezvousEnd_(nullptr),
     cxLock_(nullptr),
     records_(records),
     allocators_(cx),
-    uncompleted_(uncompleted),
-    blocked_(0),
-    rendezvousIndex_(0),
     gcRequested_(false),
     gcReason_(JS::gcreason::NUM_REASONS),
     gcZone_(nullptr),
     abort_(false),
-    fatal_(false),
-    rendezvous_(false)
+    fatal_(false)
 {
 }
 
 bool
 ForkJoinShared::init()
 {
     // Create temporary arenas to hold the data allocated during the
     // parallel code.
@@ -1358,43 +1323,36 @@ ForkJoinShared::init()
     // because when executing parallel code we sometimes check what
     // arena list an object is in to decide if it is writable.  If we
     // used the compartment |Allocator| for the main thread, then the
     // main thread would be permitted to write to any object it wants.
 
     if (!Monitor::init())
         return false;
 
-    rendezvousEnd_ = PR_NewCondVar(lock_);
-    if (!rendezvousEnd_)
-        return false;
-
     cxLock_ = PR_NewLock();
     if (!cxLock_)
         return false;
 
-    for (unsigned i = 0; i < numSlices_; i++) {
+    for (unsigned i = 0; i < (threadPool_->numWorkers() + 1); i++) {
         Allocator *allocator = cx_->new_<Allocator>(cx_->zone());
         if (!allocator)
             return false;
 
         if (!allocators_.append(allocator)) {
             js_delete(allocator);
             return false;
         }
     }
 
     return true;
 }
 
 ForkJoinShared::~ForkJoinShared()
 {
-    if (rendezvousEnd_)
-        PR_DestroyCondVar(rendezvousEnd_);
-
     PR_DestroyLock(cxLock_);
 
     while (allocators_.length() > 0)
         js_delete(allocators_.popCopy());
 }
 
 ParallelResult
 ForkJoinShared::execute()
@@ -1402,111 +1360,114 @@ ForkJoinShared::execute()
     // Sometimes a GC request occurs *just before* we enter into the
     // parallel section.  Rather than enter into the parallel section
     // and then abort, we just check here and abort early.
     if (cx_->runtime()->interrupt)
         return TP_RETRY_SEQUENTIALLY;
 
     AutoLockMonitor lock(*this);
 
-    // Notify workers to start and execute one portion on this thread.
+    ParallelResult jobResult = TP_SUCCESS;
     {
         AutoUnlockMonitor unlock(*this);
-        if (!threadPool_->submitAll(cx_, this))
+
+        // Push parallel tasks and wait until they're all done.
+        jobResult = threadPool_->executeJob(cx_, this, numSlices_);
+        if (jobResult == TP_FATAL)
             return TP_FATAL;
-        executeFromMainThread();
     }
 
-    // Wait for workers to complete.
-    while (uncompleted_ > 0)
-        lock.wait();
-
     transferArenasToCompartmentAndProcessGCRequests();
 
     // Check if any of the workers failed.
     if (abort_) {
         if (fatal_)
             return TP_FATAL;
-        else
-            return TP_RETRY_SEQUENTIALLY;
+        return TP_RETRY_SEQUENTIALLY;
     }
 
+#ifdef DEBUG
+    Spew(SpewOps, "Completed parallel job [slices %d, threads: %d (+1), stolen: %d (work stealing:%s)]",
+         numSlices_,
+         threadPool_->numWorkers(),
+         threadPool_->stolenSlices(),
+         threadPool_->workStealing() ? "ON" : "OFF");
+#endif
+
     // Everything went swimmingly. Give yourself a pat on the back.
-    return TP_SUCCESS;
+    return jobResult;
 }
 
 void
 ForkJoinShared::transferArenasToCompartmentAndProcessGCRequests()
 {
     JSCompartment *comp = cx_->compartment();
-    for (unsigned i = 0; i < numSlices_; i++)
+    for (unsigned i = 0; i < (threadPool_->numWorkers() + 1); i++)
         comp->adoptWorkerAllocator(allocators_[i]);
 
     if (gcRequested_) {
         if (!gcZone_)
             TriggerGC(cx_->runtime(), gcReason_);
         else
             TriggerZoneGC(gcZone_, gcReason_);
         gcRequested_ = false;
         gcZone_ = nullptr;
     }
 }
 
-void
-ForkJoinShared::executeFromWorker(uint32_t workerId, uintptr_t stackLimit)
+bool
+ForkJoinShared::executeFromWorker(uint16_t sliceId, uint32_t workerId, uintptr_t stackLimit)
 {
-    JS_ASSERT(workerId < numSlices_ - 1);
+    JS_ASSERT(sliceId <= numSlices_);
 
     PerThreadData thisThread(cx_->runtime());
     if (!thisThread.init()) {
         setAbortFlag(true);
-        return;
+        return false;
     }
     TlsPerThreadData.set(&thisThread);
 
     // Don't use setIonStackLimit() because that acquires the ionStackLimitLock, and the
     // lock has not been initialized in these cases.
     thisThread.ionStackLimit = stackLimit;
-    executePortion(&thisThread, workerId);
+    executePortion(&thisThread, sliceId, workerId);
     TlsPerThreadData.set(nullptr);
 
-    AutoLockMonitor lock(*this);
-    uncompleted_ -= 1;
-    if (blocked_ == uncompleted_) {
-        // Signal the main thread that we have terminated.  It will be either
-        // working, arranging a rendezvous, or waiting for workers to
-        // complete.
-        lock.notify();
-    }
+    return !abort_;
+}
+
+bool
+ForkJoinShared::executeFromMainThread(uint16_t sliceId)
+{
+    executePortion(&cx_->mainThread(), sliceId, threadPool_->numWorkers());
+    return !abort_;
 }
 
 void
-ForkJoinShared::executeFromMainThread()
-{
-    executePortion(&cx_->mainThread(), numSlices_ - 1);
-}
-
-void
-ForkJoinShared::executePortion(PerThreadData *perThread,
-                               uint32_t threadId)
+ForkJoinShared::executePortion(PerThreadData *perThread, uint16_t sliceId, uint32_t workerId)
 {
     // WARNING: This code runs ON THE PARALLEL WORKER THREAD.
-    // Therefore, it should NOT access `cx_` in any way!
+    // Be careful when accessing cx_.
 
     // ForkJoinSlice already contains an AutoAssertNoGC; however, the analysis
     // does not propagate this type information. We duplicate the assertion
     // here for maximum clarity.
     JS::AutoAssertNoGC nogc(runtime());
 
-    Allocator *allocator = allocators_[threadId];
-    ForkJoinSlice slice(perThread, threadId, numSlices_, allocator,
-                        this, &records_[threadId]);
+    Allocator *allocator = allocators_[workerId];
+    ForkJoinSlice slice(perThread, sliceId, workerId, allocator, this, &records_[workerId]);
     AutoSetForkJoinSlice autoContext(&slice);
 
-    Spew(SpewOps, "Up");
+#ifdef DEBUG
+    // Set the maximum worker and slice number for prettier spewing.
+    slice.maxSliceId = numSlices_ - 1;
+    slice.maxWorkerId = threadPool_->numWorkers();
+#endif
+
+    Spew(SpewOps, "Slice up");
 
     // Make a new IonContext for the slice, which is needed if we need to
     // re-enter the VM.
     IonContext icx(CompileRuntime::get(cx_->runtime()),
                    CompileCompartment::get(cx_->compartment()),
                    nullptr);
 
     JS_ASSERT(slice.bailoutRecord->topScript == nullptr);
@@ -1518,147 +1479,60 @@ ForkJoinShared::executePortion(PerThread
         // Sometimes, particularly with GCZeal, the parallel ion
         // script can be collected between starting the parallel
         // op and reaching this point.  In that case, we just fail
         // and fallback.
         Spew(SpewOps, "Down (Script no longer present)");
         slice.bailoutRecord->setCause(ParallelBailoutMainScriptNotPresent);
         setAbortFlag(false);
     } else {
-        ParallelIonInvoke<3> fii(cx_->runtime(), callee, 3);
+        ParallelIonInvoke<2> fii(cx_->runtime(), callee, 2);
 
         fii.args[0] = Int32Value(slice.sliceId);
-        fii.args[1] = Int32Value(slice.numSlices);
-        fii.args[2] = BooleanValue(false);
+        fii.args[1] = BooleanValue(false);
 
         bool ok = fii.invoke(perThread);
         JS_ASSERT(ok == !slice.bailoutRecord->topScript);
         if (!ok)
             setAbortFlag(false);
     }
 
-    Spew(SpewOps, "Down");
+    Spew(SpewOps, "Slice down");
 }
 
 bool
 ForkJoinShared::check(ForkJoinSlice &slice)
 {
     JS_ASSERT(cx_->runtime()->interrupt);
 
     if (abort_)
         return false;
 
-    if (slice.isMainThread()) {
+    // Note: We must check if the main thread has exited successfully here, as
+    // without a main thread the worker threads which are tripping on the
+    // interrupt flag would never exit.
+    if (slice.isMainThread() || !threadPool_->isMainThreadActive()) {
         JS_ASSERT(!cx_->runtime()->gcIsNeeded);
 
         if (cx_->runtime()->interrupt) {
             // The GC Needed flag should not be set during parallel
             // execution.  Instead, one of the requestGC() or
             // requestZoneGC() methods should be invoked.
             JS_ASSERT(!cx_->runtime()->gcIsNeeded);
 
-            // If interrupt is requested, bring worker threads to a halt,
-            // service the interrupt, then let them start back up again.
-            // AutoRendezvous autoRendezvous(slice);
-            // if (!js_HandleExecutionInterrupt(cx_))
-            //     return setAbortFlag(true);
             slice.bailoutRecord->setCause(ParallelBailoutInterrupt);
             setAbortFlag(false);
             return false;
         }
-    } else if (rendezvous_) {
-        joinRendezvous(slice);
     }
 
     return true;
 }
 
 void
-ForkJoinShared::initiateRendezvous(ForkJoinSlice &slice)
-{
-    // The rendezvous protocol is always initiated by the main thread.  The
-    // main thread sets the rendezvous flag to true.  Seeing this flag, other
-    // threads will invoke |joinRendezvous()|, which causes them to (1) read
-    // |rendezvousIndex| and (2) increment the |blocked| counter.  Once the
-    // |blocked| counter is equal to |uncompleted|, all parallel threads have
-    // joined the rendezvous, and so the main thread is signaled.  That will
-    // cause this function to return.
-    //
-    // Some subtle points:
-    //
-    // - Worker threads may potentially terminate their work before they see
-    //   the rendezvous flag.  In this case, they would decrement
-    //   |uncompleted| rather than incrementing |blocked|.  Either way, if the
-    //   two variables become equal, the main thread will be notified
-    //
-    // - The |rendezvousIndex| counter is used to detect the case where the
-    //   main thread signals the end of the rendezvous and then starts another
-    //   rendezvous before the workers have a chance to exit.  We circumvent
-    //   this by having the workers read the |rendezvousIndex| counter as they
-    //   enter the rendezvous, and then they only block until that counter is
-    //   incremented.  Another alternative would be for the main thread to
-    //   block in |endRendezvous()| until all workers have exited, but that
-    //   would be slower and involve unnecessary synchronization.
-    //
-    //   Note that the main thread cannot ever get more than one rendezvous
-    //   ahead of the workers, because it must wait for all of them to enter
-    //   the rendezvous before it can end it, so the solution of using a
-    //   counter is perfectly general and we need not fear rollover.
-
-    JS_ASSERT(slice.isMainThread());
-    JS_ASSERT(!rendezvous_ && blocked_ == 0);
-    JS_ASSERT(cx_->runtime()->interrupt);
-
-    AutoLockMonitor lock(*this);
-
-    // Signal other threads we want to start a rendezvous.
-    rendezvous_ = true;
-
-    // Wait until all the other threads blocked themselves.
-    while (blocked_ != uncompleted_)
-        lock.wait();
-}
-
-void
-ForkJoinShared::joinRendezvous(ForkJoinSlice &slice)
-{
-    JS_ASSERT(!slice.isMainThread());
-    JS_ASSERT(rendezvous_);
-
-    AutoLockMonitor lock(*this);
-    const uint32_t index = rendezvousIndex_;
-    blocked_ += 1;
-
-    // If we're the last to arrive, let the main thread know about it.
-    if (blocked_ == uncompleted_)
-        lock.notify();
-
-    // Wait until the main thread terminates the rendezvous.  We use a
-    // separate condition variable here to distinguish between workers
-    // notifying the main thread that they have completed and the main
-    // thread notifying the workers to resume.
-    while (rendezvousIndex_ == index)
-        PR_WaitCondVar(rendezvousEnd_, PR_INTERVAL_NO_TIMEOUT);
-}
-
-void
-ForkJoinShared::endRendezvous(ForkJoinSlice &slice)
-{
-    JS_ASSERT(slice.isMainThread());
-
-    AutoLockMonitor lock(*this);
-    rendezvous_ = false;
-    blocked_ = 0;
-    rendezvousIndex_++;
-
-    // Signal other threads that rendezvous is over.
-    PR_NotifyAllCondVar(rendezvousEnd_);
-}
-
-void
 ForkJoinShared::setAbortFlag(bool fatal)
 {
     AutoLockMonitor lock(*this);
 
     abort_ = true;