Merge mozilla-central into services-central
authorGregory Szorc <gps@mozilla.com>
Wed, 12 Sep 2012 17:01:23 -0700
changeset 111076 ce8eea3e3ca6636f09f12d633393663f41df4b58
parent 111075 e0896a31061deb6cae38a9b07f26219029de5cdd (current diff)
parent 106986 7781628da6dda2500ebc4a1a6dc5e3bb36824913 (diff)
child 111077 37a2942f624d3512ce2f78a9820c01578a7d9d69
push id93
push usernmatsakis@mozilla.com
push dateWed, 31 Oct 2012 21:26:57 +0000
milestone18.0a1
Merge mozilla-central into services-central
testing/mozbase/mozdevice/sut_tests/test_unzip.py
--- a/b2g/app/b2g.js
+++ b/b2g/app/b2g.js
@@ -435,17 +435,17 @@ pref("marionette.defaultPrefs.port", 282
 #endif
 
 #ifdef MOZ_UPDATER
 pref("app.update.enabled", true);
 pref("app.update.auto", true);
 pref("app.update.silent", true);
 pref("app.update.mode", 0);
 pref("app.update.incompatible.mode", 0);
-pref("app.update.stage.enabled", true);
+pref("app.update.staging.enabled", true);
 pref("app.update.service.enabled", true);
 
 // The URL hosting the update manifest.
 pref("app.update.url", "http://update.boot2gecko.org/m2.5/updates.xml");
 // Interval at which update manifest is fetched.  In units of seconds.
 pref("app.update.interval", 3600); // 1 hour
 // First interval to elapse before checking for update.  In units of
 // milliseconds.  Capped at 10 seconds.
--- a/b2g/chrome/content/shell.js
+++ b/b2g/chrome/content/shell.js
@@ -240,17 +240,17 @@ var shell = {
         type = type + '-press';
         break;
       case 'keyup':
         type = type + '-release';
         break;
       case 'keypress':
         return;
     }
-  
+
     // On my device, the physical hardware buttons (sleep and volume)
     // send multiple events (press press release release), but the
     // soft home button just sends one.  This hack is to manually
     // "debounce" the keys. If the type of this event is the same as
     // the type of the last one, then don't send it.  We'll never send
     // two presses or two releases in a row.
     // FIXME: https://bugzilla.mozilla.org/show_bug.cgi?id=761067
     if (type !== this.lastHardwareButtonEventType) {
@@ -416,16 +416,20 @@ Services.obs.addObserver(function onSyst
   shell.sendSystemMessage(msg);
 }, 'system-messages-open-app', false);
 
 Services.obs.addObserver(function(aSubject, aTopic, aData) {
   shell.sendChromeEvent({ type: "fullscreenoriginchange",
                           fullscreenorigin: aData });
 }, "fullscreen-origin-change", false);
 
+Services.obs.addObserver(function onWebappsReady(subject, topic, data) {
+  shell.sendChromeEvent({ type: 'webapps-registry-ready' });
+}, 'webapps-registry-ready', false);
+
 (function Repl() {
   if (!Services.prefs.getBoolPref('b2g.remote-js.enabled')) {
     return;
   }
   const prompt = 'JS> ';
   let output;
   let reader = {
     onInputStreamReady : function repl_readInput(input) {
--- a/browser/app/profile/firefox.js
+++ b/browser/app/profile/firefox.js
@@ -142,17 +142,17 @@ pref("app.update.auto", true);
 //
 pref("app.update.mode", 1);
 
 // If set to true, the Update Service will present no UI for any event.
 pref("app.update.silent", false);
 
 // If set to true, the Update Service will apply updates in the background
 // when it finishes downloading them.
-pref("app.update.stage.enabled", true);
+pref("app.update.staging.enabled", true);
 
 // Update service URL:
 pref("app.update.url", "https://aus3.mozilla.org/update/3/%PRODUCT%/%VERSION%/%BUILD_ID%/%BUILD_TARGET%/%LOCALE%/%CHANNEL%/%OS_VERSION%/%DISTRIBUTION%/%DISTRIBUTION_VERSION%/update.xml");
 // app.update.url.manual is in branding section
 // app.update.url.details is in branding section
 
 // User-settable override to app.update.url for testing purposes.
 //pref("app.update.url.override", "");
--- a/browser/base/content/browser.js
+++ b/browser/base/content/browser.js
@@ -214,27 +214,24 @@ XPCOMUtils.defineLazyGetter(this, "PageM
   return new tmp.PageMenu();
 });
 
 /**
 * We can avoid adding multiple load event listeners and save some time by adding
 * one listener that calls all real handlers.
 */
 function pageShowEventHandlers(event) {
-  // Filter out events that are not about the document load we are interested in
-  if (event.target == content.document) {
-    charsetLoadListener();
-    XULBrowserWindow.asyncUpdateUI();
-
-    // The PluginClickToPlay events are not fired when navigating using the
-    // BF cache. |event.persisted| is true when the page is loaded from the
-    // BF cache, so this code reshows the notification if necessary.
-    if (event.persisted)
-      gPluginHandler.reshowClickToPlayNotification();
-  }
+  charsetLoadListener();
+  XULBrowserWindow.asyncUpdateUI();
+
+  // The PluginClickToPlay events are not fired when navigating using the
+  // BF cache. |event.persisted| is true when the page is loaded from the
+  // BF cache, so this code reshows the notification if necessary.
+  if (event.persisted)
+    gPluginHandler.reshowClickToPlayNotification();
 }
 
 function UpdateBackForwardCommands(aWebNavigation) {
   var backBroadcaster = document.getElementById("Browser:Back");
   var forwardBroadcaster = document.getElementById("Browser:Forward");
 
   // Avoid setting attributes on broadcasters if the value hasn't changed!
   // Remember, guys, setting attributes on elements is expensive!  They
@@ -1268,17 +1265,21 @@ var gBrowserInit = {
 
     BrowserOffline.init();
     OfflineApps.init();
     IndexedDBPromptHelper.init();
     gFormSubmitObserver.init();
     SocialUI.init();
     AddonManager.addAddonListener(AddonsMgrListener);
 
-    gBrowser.addEventListener("pageshow", function(evt) { setTimeout(pageShowEventHandlers, 0, evt); }, true);
+    gBrowser.addEventListener("pageshow", function(event) {
+      // Filter out events that are not about the document load we are interested in
+      if (event.target == content.document)
+        setTimeout(pageShowEventHandlers, 0, event);
+    }, true);
 
     // Ensure login manager is up and running.
     Cc["@mozilla.org/login-manager;1"].getService(Ci.nsILoginManager);
 
     if (mustLoadSidebar) {
       let sidebar = document.getElementById("sidebar");
       let sidebarBox = document.getElementById("sidebar-box");
       sidebar.setAttribute("src", sidebarBox.getAttribute("src"));
--- a/build/automation.py.in
+++ b/build/automation.py.in
@@ -391,17 +391,17 @@ user_pref("gfx.color_management.force_sr
 user_pref("network.manage-offline-status", false);
 user_pref("dom.min_background_timeout_value", 1000);
 user_pref("test.mousescroll", true);
 user_pref("security.default_personal_cert", "Select Automatically"); // Need to client auth test be w/o any dialogs
 user_pref("network.http.prompt-temp-redirect", false);
 user_pref("media.cache_size", 100);
 user_pref("security.warn_viewing_mixed", false);
 user_pref("app.update.enabled", false);
-user_pref("app.update.stage.enabled", false);
+user_pref("app.update.staging.enabled", false);
 user_pref("browser.panorama.experienced_first_run", true); // Assume experienced
 user_pref("dom.w3c_touch_events.enabled", true);
 user_pref("toolkit.telemetry.prompted", 2);
 // Existing tests assume there is no font size inflation.
 user_pref("font.size.inflation.emPerLine", 0);
 user_pref("font.size.inflation.minTwips", 0);
 
 // Only load extensions from the application and user profile
--- a/content/media/ogg/nsOggReader.cpp
+++ b/content/media/ogg/nsOggReader.cpp
@@ -155,36 +155,58 @@ void nsOggReader::BuildSerialList(nsTArr
     if (mVorbisState) {
       aTracks.AppendElement(mVorbisState->mSerial);
     } else if(mOpusState) {
       aTracks.AppendElement(mOpusState->mSerial);
     }
   }
 }
 
+static bool IsValidVorbisTagName(nsCString& name)
+{
+  // Tag names must consist of ASCII 0x20 through 0x7D,
+  // excluding 0x3D '=' which is the separator.
+  uint32_t length = name.Length();
+  const char *data = name.Data();
+
+  for (uint32_t i = 0; i < length; i++) {
+    if (data[i] < 0x20 || data[i] > 0x7D || data[i] == '=') {
+      return false;
+    }
+  }
+
+  return true;
+}
+
 static
 nsHTMLMediaElement::MetadataTags* TagsFromVorbisComment(vorbis_comment *vc)
 {
   nsHTMLMediaElement::MetadataTags* tags;
   int i;
 
   tags = new nsHTMLMediaElement::MetadataTags;
   tags->Init();
   for (i = 0; i < vc->comments; i++) {
     char *comment = vc->user_comments[i];
     char *div = (char*)memchr(comment, '=', vc->comment_lengths[i]);
     if (!div) {
-      LOG(PR_LOG_DEBUG, ("Invalid vorbis comment: no separator"));
+      LOG(PR_LOG_DEBUG, ("Skipping vorbis comment: no separator"));
       continue;
     }
-    // This should be ASCII.
     nsCString key = nsCString(comment, div-comment);
+    if (!IsValidVorbisTagName(key)) {
+      LOG(PR_LOG_DEBUG, ("Skipping vorbis comment: invalid tag name"));
+      continue;
+    }
     uint32_t value_length = vc->comment_lengths[i] - (div-comment);
-    // This should be utf-8.
     nsCString value = nsCString(div + 1, value_length);
+    if (!IsUTF8(value)) {
+      LOG(PR_LOG_DEBUG, ("Skipping vorbis comment: invalid UTF-8 in value"));
+      continue;
+    }
     tags->Put(key, value);
   }
 
   return tags;
 }
 
 nsresult nsOggReader::ReadMetadata(nsVideoInfo* aInfo,
                                    nsHTMLMediaElement::MetadataTags** aTags)
--- a/content/media/test/Makefile.in
+++ b/content/media/test/Makefile.in
@@ -163,16 +163,17 @@ endif
 #		test_audioDocumentTitle.html
 
 # sample files
 MOCHITEST_FILES += \
 		320x240.ogv \
 		448636.ogv \
 		audio-overhang.ogg \
 		audio-gaps.ogg \
+		badtags.ogg \
 		beta-phrasebook.ogg \
 		bogus.ogv \
 		bug495129.ogv \
 		bug495794.ogg \
 		bug461281.ogg \
 		bug482461.ogv \
 		bug482461-theora.ogv \
 		bug498380.ogv \
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..12d8358730decd20f0d80d56cc08836d49c74151
GIT binary patch
literal 5033
zc%02weN<Cdwm(6H2-ZeG2~4CnRZ2n=hL1pv1q+l9MI#}}C5H5h5U&^^A(C9C7U@t4
zjE{#bgd`#lnLz?0R_v5QY;~&GR#2%5V#vglVm}ncuF-{6)ULk1a|2k-V*1|v_ij%1
z-RGR&*>~^X+2`DI)ARDgzzxh?#C|N9yt~r~3nhqBTv(K=)RGO9vXcP(0xwWHeLqi0
zCr5&3M^fPZHDT1xv|q}8dG?B)H*M%u*uPP!*%p>wl!p{3b2FW-$XX;aJR&kYGCT@l
zrK{9RO%ble)jIY92uI*wr_>eTackAZIR(lsh@w!Xg1uTqhii4nR%HS10Wr8rquUur
zYH?0A0%|2(M9$jGjDLCgir`JJgs?G$TN*cQM3<9?sB=^}2hkEmnj)oEsm?3d$%BIu
zkS(}YQKZ!9l!a>K4@%uOL|uqzaZOH9j;^o>f&S(=eSp21qQcw)Top#fb^E^#$E{c9
z;{`i8NG_p6a@2@&#^Zc^C&E$}s<}B@g;L25`yGU<3w2(w_a)_)xLMe&Pps+gcb%<q
zx^3`@O07Bsnnb37BnZKwXLu2F8p|bgTe&NrTGHY>2wbhewX2X{{`<*Kl=;*2zm)i9
zCY&M)@Ka>6w;mAH$*Tgi4H0<(imO>w!Fs<$R+~0c{yw{>G3&x7XPdN_jJYCq@&S<$
z;uIpbM}XKzu4F=-XNwkUoo)Zf+RnE$X*-Rg4Qw-AyeI8egJ?aeRi)i((hl-(Hi@g#
zsL{qO@%e}fgM1xZw;|E9Lw`xM?n7N|nrE<1xGJA-^bxZUDl!wdf6~SfU+8Ra&{n@U
zSc{T=_Qul!yS#u909s`WtIADZdDIO=!tA`xs`-{x_cFgu!C&fxzzn7V(5vxVyU%Z6
zh#|Pbxp*a3Y{F$T1+x(t!rQWhv>MOy3^+@t=?z^z)E8v)ohi1P^*L?cEIrhWAm+`M
z)~`$ME-r%FvT~>~yEpMCTFg-UbSkLi?k7`F+n2M6Io?uF;&K@QXAcySICE3Pt%K!G
zT(kC{d>hmbwtk&(yW=X<jP;u$ZXayjRB|`i8k9KEHf`@$(LAGdj(@%VxsK<=G(9lh
z9D2;29sTC1Yb7}iA(hH;Gc<7HaNfdqygqcAvdxT`j+_brQ%@7EVOID-QAy7|$NUpx
zH#M}we5fk)$YD}&TB{>3u<D`UwAQSeIQ;pgL@&1aN}6|Pw?tmZwFc>FiB#r{I5idI
z<gW~X@IJbtI>FhqhTUe!tzx$~xH;)81J2Ebv$md>s*UZ3MI4)|OCpOQX>E6s;K!s4
zUNYL9JbG0C3uYBKdQiCq$7~p8!?6*ZoVlmv_;lznlAPKEj{x#<%nF03Dx#0By~Ljl
zlbq1_9e$}h80Yt`IN!y&ILW!}6D^L47HgxW+GHsqu<1}6DFsqe!K4H_^9UX(ho5<(
zzca)&0Nh$x^WAJ&L1|&W4?qB!EUc<;$+o%`YfWvk#v8IjuWUbbxa!z#Hzy>Xgpe1@
zbco$(RyMZF8rzlsRta<_cr5_J9gKch_Q9wasnhI6lI#i>!bnr=IOpql16@49{iF<?
zz{<mh-JhKRIGmgV!7vZXX(e@-l)qUx16^c+#0JAv2YRzqJtNmbZy@Gtfh~Tmfv<kS
zFbBT=z2T#4kvE&_uZ8AT=QKvP8j1oTX^TM;jJyx&r)kgeLptjH_~VCll0fRRwi;1h
zM|WfHmn>t0=;+?^8c`~@)v%qzF1{+NZnHpV-5BuC(L?v$K?VT&h&61pUv4%3uk@s9
zc0XNL8R4-^Taz%}q!)#bH|T_EU(mHR{KHM<qR0?qxiBr{Ab??e!oPRRVC@o0d=n^3
zsEbXX<YgFm>3+##9hSjEZIiLXKdu*}aYGVRjN*0)Dz(I3=EaF6=w%*im7w-$6fI6h
zt@toXz~0efmEDHPmcE;T;-eBw{u*i<!DJ()Qd4R6WGwn%{V)+Xti!B?N={&ohZ1qI
zz)Il51a2pAnG};9kA}TNC~nhX_F`PRAGP-o!$c_rXG?MEBV1;ykl7A?qr)6hOlm`A
zBYW*80vl0{?T<}INz0dcFi|l_CT1In9yY)%RmosWCLD-LO$6+<>o8dihMG{jm5>$_
zusR08Hi7MdN`8EAwn;Vm8fJTl${v=Y#j5NP;=2aIemo9+P%1W6jOnoK<E5hkTOCU)
zhltW_qbhqNZl5AB{<RZoM(Z7~)1fCn``|=Z*bk>Rd_u_in;bU>ES-#x{^@=Cn0KmU
z%6LrmQ{T~n&m!(vG(YsI7^m;~u12k7fMW)HY(F8Vt1)^Fw2T??F~|m8E%&dKPX)Bz
zdGcB4z^T7o>x%g56nEjta7KT=W0%ZkJa$y!efo-RZ)?6I(Qc{eQb!e!<^9mNfev?@
z>u~qmoEX63ZAk{S5U_dQiVOp1z%O{f2WBmX@&q;`?;<byViYR4zuwA2(HH@0<O-q$
z7l$R{`@CTunvp568qi^$3QnvX_F6FM2w^kg4xT_7gNjWMk4xc%8*#abG<8`lxOg8X
z3o46&QNb#D(N|#eO-50Hv<I~s@qzp6QQv6Wk4a*<uXLkUXF@qh%c#wYOM9>}BcvZz
z1=enuBe=tej`pbJwqVjLX!(AuI2s)$1SkPbNvyufQY&vrhr+5=hhq0(ekEm~(L-7R
zv<x>e41$YMX%9Xufga*He?T2pf!L^m+2@c5<R+Eff0O(HHbe#}aKxaf33ogsq$ZUd
z_QnXL7ILiJqQYSDcY1XdM+pqGV51N@g4rLaP=b(;;A19ibV+gcR4F6}gFc&Zx&Ky2
zu;WChuV9)ca_tx~2Q=-UGHk%DC}HEF_Wdf^aoj#qO8SRl_881+!DSXgw!d`Lh+)M9
zOj^`J?yxz<D%snZV+49rie{FMJ}hnFzJCgys5bXf0Me_E6mC101`zm)53h_EM|fWF
zRH08{k2lrV@jaM&N#r=97mCIidXZ?N2`>J$7K22zoof(@(mLVWK<Lbs^7b#j1r?P?
z-GPV#7S<?a&3TPSj@+qPv9p;4?@vxGmo<k}9ho>`>4Ytf?GqQeeqR7v+HapYcJ$66
zxD6jUag1~46sxMe<4D)51D|P*K=3h+W7T&O`0Bvr7S%U!)tXce3z7W@B@>Axwo+~@
z9rLgJ^WewC=+y1Lp;Q3g-aQWp-+STx<xPHj=PwQH@&V`IA-6i=9HOsHSi>~eir@>>
z9e{-^;fC8F^zb5g(l6jic#klR-F7tt3WErWI?=4=6q4tw|C^X#{U)Tt{C_t^ij3#0
zY5$fl|G$Lsw-Ii@{4xWWgVwX=&88Dj7(`yHZZ*AG9RXj08&>V1YpeO}j&1|rlW8DF
zX)h&E+YE-Rn+$!OXdSohOFp&DY{*)75a#HSj-I7&vfH{PVgc6#4>BDibcKN3b2aNf
zd-|@4@;lGc^N&XNWXh|#eOdVwu=0gP;4hvrM{6`9-qMZEg#mLsB8A=8R8Ct}UMsqk
z;K|f`Fx#87i&ow8Q+x@1(9=TU>1Yu=vTeD<_gtp;Nj%@=tQxL3Pi$!m+RB{=I$;{M
zMK6RO0S2;afceIRV0Mc^lt>NMlj-LNKi{0|>GKI{NV4KRCk60;f#5BbwVbkAMeSP(
zdbuRYY)~vJ=x?geOuAtZZ%9gAhVLnfNVz3}d5us3HJsw^LG?;uQfYlK$(fOFuJFq|
z<5nKIP1E2BUZgGdp~UCzK4h)%9y|-e1}jc7XuA>WZiEw9=C-2uJ>RdcFDSg{{+h;Z
zS@POt?&Q&?%nj@UfZ-RPl%!p<)Sn&@_&dh3Am_pBFYe$a0Qx;?i-+E-I6FV3vd<&+
zPpMD8T4^+z^G<c@&M#Vb@=JI2i<Ue(E&BW7#sGSF7>C2*a!JAAI3@gXd24v%55~^@
zb?qOg;Pg<z<-4Rq|IvI4JegP>>(Bh?gMjen(A5q6o#1bGm4)EBYfV~T_r&AQ<~PVn
zP{A7k{w?o}t?T_bdGF?%-&4w@lTx?m2LvtuYU{_@^JdY^PwxhVtA{pDqeYkt8c2kX
zmOO)9@D$5^9O42k3miP_HjO<%Vkxs&5F9<<1q)J)>EIdcuXe*8zv_zJMf>!==bR3g
zO#a>71$?hxWO>TPnUb-n&0ihLm;s-31#diaJ!#g9=diDzV!3)T;`3J2oY<0kt*%%N
z8oFWb=pJcZ8Gd9DefTe^c$-CW1*5w(;Ma*Jok$7SPJ*)CfAny5;`F($kU3f7vb<fO
zWluWqQC&!j=>78iJn+HwH(c$eee-1goCNz%taG(nGXKy_N}TsUlTTtTRL`i87s0M|
ztLM3ZKW;rE@R*Yb>EuRNCnUny)H$)-$8uM!VR5JRDZ`L8->0nA-3@jHr}Q*a<}@7k
zxZ5>-G|MNrlsTy=nf%Gs@V%|F91^_x_3T*b&_4`u^SqC@5$+Wv8?mp*UxZ!1=G?uy
zjn|nUP2L8e*WDew`0k^hTQ6`}{Xg@(mao21KLBTDK|}rVcL3PUn5Fvd)Tot0b<n3N
fkXK=P*uaqHz@41^cfR?4KF2pckK#Q@8KnFVn!H{f
--- a/content/media/test/manifest.js
+++ b/content/media/test/manifest.js
@@ -341,17 +341,32 @@ var gMetadataTests = [
   { name:"bug516323.indexed.ogv", tags: {
       GENRE:"Open Movie",
       ENCODER:"Audacity",
       TITLE:"Elephants Dream",
       ARTIST:"Silvia Pfeiffer",
       COMMENTS:"Audio Description"
     }
   },
-  { name:"sound.ogg", tags: { } }
+  { name:"sound.ogg", tags: { } },
+  { name:"badtags.ogg", tags: {
+      // We list only the valid tags here, and verify
+      // the invalid ones are filtered out.
+      title:"Invalid comments test file",
+      empty:"",
+      "":"empty",
+      "{- [(`!@\"#$%^&')] -}":"valid tag name, surprisingly"
+      // The file also includes the following invalid tags.
+      // "A description with no separator is a common problem.",
+      // "雨":"Likely, but an invalid key (non-ascii).",
+      // "not\nval\x1fid":"invalid tag name",
+      // "not~valid":"this isn't a valid name either",
+      // "not-utf-8":"invalid sequences: \xff\xfe\xfa\xfb\0eol"
+    }
+  }
 ];
 
 function checkMetadata(msg, e, test) {
   if (test.width) {
     is(e.videoWidth, test.width, msg + " video width");
   }
   if (test.height) {
     is(e.videoHeight, test.height, msg + " video height");
--- a/content/media/test/test_metadata.html
+++ b/content/media/test/test_metadata.html
@@ -23,27 +23,27 @@ function startTest(test, token) {
   a.name = test.name;
 
   // Tags should not be available immediately.
   var exception_fired = false;
   try {
     var m = a.mozGetMetadata();
   } catch (e) {
     is(e.name, 'InvalidStateError',
-       "early mozGetMetadata() threw incorrect exception");
+       "early mozGetMetadata() should throw InvalidStateError");
     exception_fired = true;
   }
   ok(exception_fired,
      "mozGetMetadata() should throw an exception before HAVE_METADATA");
 
   // Wait until metadata has loaded.
   a.addEventListener('loadedmetadata', function() {
     // read decoded tags
     tags = a.mozGetMetadata();
-    ok(tags, "mozGetMetadata() failed");
+    ok(tags, "mozGetMetadata() should return a truthy value");
     // Dump them out.
     var d = document.getElementById('output');
     var html = '<table>\n';
     html += '<caption><p>Called getMozMetadata()'
     html += ' on '+test.name+'</p></caption>\n';
     html += '<tr><th>tag</th>';
     html += '<th>decoded value</th><th>expected value</th></tr>\n';
     for (tag in tags) {
@@ -56,21 +56,21 @@ function startTest(test, token) {
       html += '<tr><td colspan=3 align=center><em>no tags</em></td></tr>\n';
     }
     html += '</table>\n';
     var div = document.createElement('div');
     div.innerHTML = html;
     d.appendChild(div);
     // Verify decoded tag values.
     for (tag in tags) {
-      is(tags[tag], test.tags[tag], "Tag '"+tag+"' doesn't match");
+      is(tags[tag], test.tags[tag], "Tag '"+tag+"' should match");
     }
     // Verify expected tag values
     for (tag in test.tags) {
-      is(tags[tag], test.tags[tag], "Tag '"+tag+"' doesn't match");
+      is(tags[tag], test.tags[tag], "Tag '"+tag+"' should match");
     }
     manager.finished(token);
   }, false);
 }
 
 manager.runTests(gMetadataTests, startTest);
 
 </script>
--- a/dom/apps/src/Webapps.jsm
+++ b/dom/apps/src/Webapps.jsm
@@ -72,54 +72,65 @@ let DOMApplicationRegistry = {
                                       ["webapps", "webapps.json"], true);
 
     let dirList = [DIRECTORY_NAME];
 
 #ifdef MOZ_WIDGET_GONK
     dirList.push("coreAppsDir");
 #endif
     let currentId = 1;
+    this.dirsToLoad = dirList.length;
+    this.dirsLoaded = 0;
     dirList.forEach((function(dir) {
       let curFile;
       try {
         // getFile calls getDir with |shouldCreate = true|, so we have
         // to wrap in a try..catch in case the file does not exist on a
         // read-only partition.
         curFile = FileUtils.getFile(dir, ["webapps", "webapps.json"], false);
       } catch(e) { }
       if (curFile && curFile.exists()) {
         let appDir = FileUtils.getDir(dir, ["webapps"], false);
         this._loadJSONAsync(curFile, (function(aData) {
           if (!aData) {
             return;
           }
+#ifdef MOZ_SYS_MSG
+          let ids = [];
+#endif
           // Add new apps to the merged list.
           for (let id in aData) {
             this.webapps[id] = aData[id];
             this.webapps[id].basePath = appDir.path;
             this.webapps[id].removable = (dir == DIRECTORY_NAME);
 #ifdef MOZ_SYS_MSG
-            this._processManifestForId(id);
+            ids.push({ id: id });
 #endif
             // local ids must be stable between restarts.
             // We partition the ids in two buckets:
             // - 1 to 1000 for the core apps.
             // - 1001 to Inf for installed apps.
             // This way, a gecko update with new core apps will not lead to
             // changes for installed apps ids.
             if (!this.webapps[id].removable) {
               this.webapps[id].localId = currentId++;
             }
 
             // Default to a non privileged status.
             if (this.webapps[id].appStatus === undefined) {
               this.webapps[id].appStatus = Ci.nsIPrincipal.APP_STATUS_INSTALLED;
             }
           };
+#ifdef MOZ_SYS_MSG
+          this._processManifestForIds(ids);
+#endif
         }).bind(this));
+      } else {
+        // The directory we're trying to load from doesn't exist.
+        this.dirsToLoad--;
       }
     }).bind(this));
   },
 
 #ifdef MOZ_SYS_MSG
   _registerSystemMessages: function(aManifest, aApp) {
     if (aManifest.messages && Array.isArray(aManifest.messages) &&
         aManifest.messages.length > 0) {
@@ -170,23 +181,29 @@ let DOMApplicationRegistry = {
       let json = {
         "manifest": aApp.manifestURL,
         "name": activity
       }
       cpmm.sendAsyncMessage("Activities:Unregister", json);
     }
   },
 
-  _processManifestForId: function(aId) {
-    let app = this.webapps[aId];
-    this._readManifests([{ id: aId }], (function registerManifest(aResult) {
-      let manifest = aResult[0].manifest;
-      app.name = manifest.name;
-      this._registerSystemMessages(manifest, app);
-      this._registerActivities(manifest, app);
+  _processManifestForIds: function(aIds) {
+    this._readManifests(aIds, (function registerManifests(aResults) {
+      aResults.forEach(function registerManifest(aResult) {
+        let app = this.webapps[aResult.id];
+        let manifest = aResult.manifest;
+        app.name = manifest.name;
+        this._registerSystemMessages(manifest, app);
+        this._registerActivities(manifest, app);
+      }, this);
+      this.dirsLoaded++;
+      if (this.dirsLoaded == this.dirsToLoad) {
+        Services.obs.notifyObservers(this, "webapps-registry-ready", null);
+      }
     }).bind(this));
   },
 #endif
 
   observe: function(aSubject, aTopic, aData) {
     if (aTopic == "xpcom-shutdown") {
       this.messages.forEach((function(msgName) {
         ppmm.removeMessageListener(msgName, this);
--- a/dom/bluetooth/BluetoothServiceUuid.h
+++ b/dom/bluetooth/BluetoothServiceUuid.h
@@ -11,27 +11,30 @@ namespace mozilla {
 namespace dom {
 namespace bluetooth {
 
 namespace BluetoothServiceUuid {
   static unsigned long long AudioSink    = 0x0000110B00000000;
   static unsigned long long AudioSource  = 0x0000110A00000000;
   static unsigned long long AdvAudioDist = 0x0000110D00000000;
   static unsigned long long Headset      = 0x0000110800000000;
+  static unsigned long long HeadsetAG    = 0x0000111200000000;
+  static unsigned long long Handsfree    = 0x0000111E00000000;
   static unsigned long long HandsfreeAG  = 0x0000111F00000000;
 
   static unsigned long long BaseMSB     = 0x0000000000001000;
   static unsigned long long BaseLSB     = 0x800000805F9B34FB;
 }
 
 namespace BluetoothServiceUuidStr {
   static const char* AudioSink     = "0000110B-0000-1000-8000-00805F9B34FB";
   static const char* AudioSource   = "0000110A-0000-1000-8000-00805F9B34FB";
   static const char* AdvAudioDist  = "0000110D-0000-1000-8000-00805F9B34FB";
   static const char* Headset       = "00001108-0000-1000-8000-00805F9B34FB";
+  static const char* HeadsetAG     = "00001112-0000-1000-8000-00805F9B34FB";
   static const char* Handsfree     = "0000111E-0000-1000-8000-00805F9B34FB";
   static const char* HandsfreeAG   = "0000111F-0000-1000-8000-00805F9B34FB";
 }
 
 }
 }
 }
 
--- a/dom/bluetooth/gonk/BluetoothGonkService.cpp
+++ b/dom/bluetooth/gonk/BluetoothGonkService.cpp
@@ -154,19 +154,20 @@ BluetoothGonkService::StartInternal()
 
   return BluetoothDBusService::StartInternal();
 }
 
 nsresult
 BluetoothGonkService::StopInternal()
 {
   NS_ASSERTION(!NS_IsMainThread(), "This should not run on the main thread!");
+
   nsresult ret;
 
-  ret = StartStopGonkBluetooth(false);
+  ret = BluetoothDBusService::StopInternal();
 
   if (NS_FAILED(ret)) {
     return ret;    
   }
 
-  return BluetoothDBusService::StopInternal();
+  return StartStopGonkBluetooth(false);
 }
 
--- a/dom/bluetooth/linux/BluetoothDBusService.cpp
+++ b/dom/bluetooth/linux/BluetoothDBusService.cpp
@@ -13,16 +13,17 @@
 ** distributed under the License is distributed on an "AS IS" BASIS,
 ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 ** See the License for the specific language governing permissions and
 ** limitations under the License.
 */
 
 #include "base/basictypes.h"
 #include "BluetoothDBusService.h"
+#include "BluetoothServiceUuid.h"
 #include "BluetoothTypes.h"
 #include "BluetoothReplyRunnable.h"
 
 #include <cstdio>
 #include <dbus/dbus.h>
 
 #include "nsIDOMDOMRequest.h"
 #include "nsAutoPtr.h"
@@ -135,16 +136,18 @@ static const char* sBluetoothDBusSignals
 /**
  * DBus Connection held for the BluetoothCommandThread to use. Should never be
  * used by any other thread.
  * 
  */
 static nsAutoPtr<RawDBusConnection> gThreadConnection;
 static nsDataHashtable<nsStringHashKey, DBusMessage* > sPairingReqTable;
 static nsDataHashtable<nsStringHashKey, DBusMessage* > sAuthorizeReqTable;
+static nsString sDefaultAdapterPath;
+static nsTArray<uint32_t> sServiceHandles;
 
 typedef void (*UnpackFunc)(DBusMessage*, DBusError*, BluetoothValue&, nsAString&);
 
 static nsString
 GetObjectPathFromAddress(const nsAString& aAdapterPath,
                          const nsAString& aDeviceAddress)
 {
   // The object path would be like /org/bluez/2906/hci0/dev_00_23_7F_CB_B4_F1,
@@ -549,16 +552,38 @@ RegisterAgent(const nsAString& aAdapterP
         __FUNCTION__, REMOTE_AGENT_PATH);
 
     return false;
   }
 
   return true;
 }
 
+
+
+static void
+AddReservedServices(const nsAString& aAdapterPath)
+{
+  MOZ_ASSERT(!NS_IsMainThread());
+
+  nsTArray<uint32_t> uuids;
+
+  uuids.AppendElement((uint32_t)(BluetoothServiceUuid::HandsfreeAG >> 32));
+  uuids.AppendElement((uint32_t)(BluetoothServiceUuid::HeadsetAG >> 32));
+
+  BluetoothService* bs = BluetoothService::Get();
+  if (!bs) {
+    NS_WARNING("BluetoothService not available!");
+    return ;
+  }
+
+  sServiceHandles.Clear();
+  bs->AddReservedServicesInternal(aAdapterPath, uuids, sServiceHandles);
+}
+
 void
 RunDBusCallback(DBusMessage* aMsg, void* aBluetoothReplyRunnable,
                 UnpackFunc aFunc)
 {
   MOZ_ASSERT(!NS_IsMainThread());
   nsRefPtr<BluetoothReplyRunnable> replyRunnable =
     dont_AddRef(static_cast< BluetoothReplyRunnable* >(aBluetoothReplyRunnable));
 
@@ -937,17 +962,18 @@ EventFilter(DBusConnection* aConn, DBusM
   } else if (dbus_message_is_signal(aMsg, DBUS_MANAGER_IFACE, "AdapterAdded")) {
     const char* str;
     if (!dbus_message_get_args(aMsg, &err,
                                DBUS_TYPE_OBJECT_PATH, &str,
                                DBUS_TYPE_INVALID)) {
       LOG_AND_FREE_DBUS_ERROR_WITH_MSG(&err, aMsg);
       errorStr.AssignLiteral("Cannot parse manager path!");
     } else {
-      v = NS_ConvertUTF8toUTF16(str);
+      sDefaultAdapterPath = NS_ConvertUTF8toUTF16(str);
+      v = sDefaultAdapterPath;
     }
   } else if (dbus_message_is_signal(aMsg, DBUS_MANAGER_IFACE, "PropertyChanged")) {
     ParsePropertyChange(aMsg,
                         v,
                         errorStr,
                         sManagerProperties,
                         ArrayLength(sManagerProperties));
   } else {
@@ -1047,16 +1073,18 @@ BluetoothDBusService::StopInternal()
   // This could block. It should never be run on the main thread.
   MOZ_ASSERT(!NS_IsMainThread());
   
   if (!mConnection) {
     StopDBus();
     return NS_OK;
   }
 
+  RemoveReservedServicesInternal(sDefaultAdapterPath, sServiceHandles);
+
   DBusError err;
   dbus_error_init(&err);
   for (uint32_t i = 0; i < ArrayLength(sBluetoothDBusSignals); ++i) {
     dbus_bus_remove_match(mConnection,
                           sBluetoothDBusSignals[i],
                           &err);
     if (dbus_error_is_set(&err)) {
       LOG_AND_FREE_DBUS_ERROR(&err);
@@ -1143,16 +1171,17 @@ public:
     if (msg) {
       dbus_message_unref(msg);
     }
     // We have to manually attach the path to the rest of the elements
     v.get_ArrayOfBluetoothNamedValue().AppendElement(BluetoothNamedValue(NS_LITERAL_STRING("Path"),
                                                                          path));
 
     RegisterAgent(path);
+    AddReservedServices(path);
 
     DispatchBluetoothReply(mRunnable, v, replyError);
    
     return NS_OK;
   }
 
 private:
   nsRefPtr<BluetoothReplyRunnable> mRunnable;
--- a/gfx/layers/ipc/CompositorParent.cpp
+++ b/gfx/layers/ipc/CompositorParent.cpp
@@ -38,16 +38,19 @@ using namespace std;
 namespace mozilla {
 namespace layers {
 
 // FIXME/bug 774386: we're assuming that there's only one
 // CompositorParent, but that's not always true.  This assumption only
 // affects CrossProcessCompositorParent below.
 static CompositorParent* sCurrentCompositor;
 static Thread* sCompositorThread = nullptr;
+// manual reference count of the compositor thread.
+static int sCompositorThreadRefCount = 0;
+static MessageLoop* sMainLoop = nullptr;
 // When ContentParent::StartUp() is called, we use the Thread global.
 // When StartUpWithExistingThread() is used, we have to use the two
 // duplicated globals, because there's no API to make a Thread from an
 // existing thread.
 static PlatformThreadId sCompositorThreadID = 0;
 static MessageLoop* sCompositorLoop = nullptr;
 
 struct LayerTreeState {
@@ -69,63 +72,86 @@ struct PanZoomUserData : public LayerUse
 
 /**
  * Lookup the indirect shadow tree for |aId| and return it if it
  * exists.  Otherwise null is returned.  This must only be called on
  * the compositor thread.
  */
 static const LayerTreeState* GetIndirectShadowTree(uint64_t aId);
 
+static void DeferredDeleteCompositorParent(CompositorParent* aNowReadyToDie)
+{
+  aNowReadyToDie->Release();
+}
+
+static void DeleteCompositorThread()
+{
+  if (NS_IsMainThread()){
+    delete sCompositorThread;  
+    sCompositorThread = nullptr;
+    sCompositorLoop = nullptr;
+    sCompositorThreadID = 0;
+  } else {
+    sMainLoop->PostTask(FROM_HERE, NewRunnableFunction(&DeleteCompositorThread));
+  }
+}
+
+static void ReleaseCompositorThread()
+{
+  if(--sCompositorThreadRefCount == 0) {
+    DeleteCompositorThread();
+  }
+}
+
 void
 CompositorParent::StartUpWithExistingThread(MessageLoop* aMsgLoop,
                                             PlatformThreadId aThreadID)
 {
   MOZ_ASSERT(!sCompositorThread);
   CreateCompositorMap();
   sCompositorLoop = aMsgLoop;
   sCompositorThreadID = aThreadID;
+  sMainLoop = MessageLoop::current();
+  sCompositorThreadRefCount = 1;
 }
 
 void CompositorParent::StartUp()
 {
   MOZ_ASSERT(!sCompositorLoop);
   CreateCompositorMap();
   CreateThread();
+  sMainLoop = MessageLoop::current();
 }
 
 void CompositorParent::ShutDown()
 {
   DestroyThread();
   DestroyCompositorMap();
 }
 
 bool CompositorParent::CreateThread()
 {
   NS_ASSERTION(NS_IsMainThread(), "Should be on the main Thread!");
   if (sCompositorThread || sCompositorLoop) {
     return true;
   }
+  sCompositorThreadRefCount = 1;
   sCompositorThread = new Thread("Compositor");
   if (!sCompositorThread->Start()) {
     delete sCompositorThread;
     sCompositorThread = nullptr;
     return false;
   }
   return true;
 }
 
 void CompositorParent::DestroyThread()
 {
   NS_ASSERTION(NS_IsMainThread(), "Should be on the main Thread!");
-  if (sCompositorThread) {
-    delete sCompositorThread;
-    sCompositorThread = nullptr;
-  }
-  sCompositorLoop = nullptr;
-  sCompositorThreadID = 0;
+  ReleaseCompositorThread();
 }
 
 MessageLoop* CompositorParent::CompositorLoop()
 {
   return sCompositorThread ? sCompositorThread->message_loop() : sCompositorLoop;
 }
 
 CompositorParent::CompositorParent(nsIWidget* aWidget,
@@ -151,31 +177,33 @@ CompositorParent::CompositorParent(nsIWi
   // can destroy this instance is initialized on the compositor thread after 
   // this task has been processed.
   CompositorLoop()->PostTask(FROM_HERE, NewRunnableFunction(&AddCompositor, 
                                                           this, &mCompositorID));
 
   if (!sCurrentCompositor) {
     sCurrentCompositor = this;
   }
+  ++sCompositorThreadRefCount;
 }
 
 PlatformThreadId
 CompositorParent::CompositorThreadID()
 {
   return sCompositorThread ? sCompositorThread->thread_id() : sCompositorThreadID;
 }
 
 CompositorParent::~CompositorParent()
 {
   MOZ_COUNT_DTOR(CompositorParent);
 
   if (this == sCurrentCompositor) {
     sCurrentCompositor = NULL;
   }
+  ReleaseCompositorThread();
 }
 
 void
 CompositorParent::Destroy()
 {
   NS_ABORT_IF_FALSE(ManagedPLayersParent().Length() == 0,
                     "CompositorParent destroyed before managed PLayersParent");
 
@@ -194,16 +222,25 @@ CompositorParent::RecvWillStop()
 
   return true;
 }
 
 bool
 CompositorParent::RecvStop()
 {
   Destroy();
+  // There are chances that the ref count reaches zero on the main thread shortly
+  // after this function returns while some ipdl code still needs to run on 
+  // this thread.
+  // We must keep the compositor parent alive untill the code handling message 
+  // reception is finished on this thread.
+  this->AddRef(); // Corresponds to DeferredDeleteCompositorParent's Release
+  CompositorLoop()->PostTask(FROM_HERE, 
+                           NewRunnableFunction(&DeferredDeleteCompositorParent,
+                                               this));
   return true;
 }
 
 bool
 CompositorParent::RecvPause()
 {
   PauseComposition();
   return true;
--- a/ipc/chromium/src/base/debug_util_posix.cc
+++ b/ipc/chromium/src/base/debug_util_posix.cc
@@ -28,16 +28,34 @@
 #endif
 
 #include "base/basictypes.h"
 #include "base/eintr_wrapper.h"
 #include "base/logging.h"
 #include "base/scoped_ptr.h"
 #include "base/string_piece.h"
 
+#if defined(OS_NETBSD)
+#undef KERN_PROC
+#define KERN_PROC KERN_PROC2
+#define KINFO_PROC struct kinfo_proc2
+#else
+#define KINFO_PROC struct kinfo_proc
+#endif
+
+#if defined(OS_MACOSX)
+#define KP_FLAGS kp_proc.p_flag
+#elif defined(OS_DRAGONFLY)
+#define KP_FLAGS kp_flags
+#elif defined(OS_FREEBSD)
+#define KP_FLAGS ki_flag
+#else
+#define KP_FLAGS p_flag
+#endif
+
 // static
 bool DebugUtil::SpawnDebuggerOnProcess(unsigned /* process_id */) {
   NOTIMPLEMENTED();
   return false;
 }
 
 #if defined(OS_MACOSX) || defined(OS_BSD)
 
@@ -55,43 +73,39 @@ bool DebugUtil::BeingDebugged() {
   }
 
   // Initialize mib, which tells sysctl what info we want.  In this case,
   // we're looking for information about a specific process ID.
   int mib[] = {
     CTL_KERN,
     KERN_PROC,
     KERN_PROC_PID,
-    getpid()
+    getpid(),
+#if defined(OS_NETBSD) || defined(OS_OPENBSD)
+    sizeof(KINFO_PROC),
+    1,
+#endif
   };
 
   // Caution: struct kinfo_proc is marked __APPLE_API_UNSTABLE.  The source and
   // binary interfaces may change.
-  struct kinfo_proc info;
+  KINFO_PROC info;
   size_t info_size = sizeof(info);
 
   int sysctl_result = sysctl(mib, arraysize(mib), &info, &info_size, NULL, 0);
   DCHECK(sysctl_result == 0);
   if (sysctl_result != 0) {
     is_set = true;
     being_debugged = false;
     return being_debugged;
   }
 
   // This process is being debugged if the P_TRACED flag is set.
   is_set = true;
-#if defined(OS_DRAGONFLY)
-  being_debugged = (info.kp_flags & P_TRACED) != 0;
-#elif defined(OS_FREEBSD)
-  being_debugged = (info.ki_flag & P_TRACED) != 0;
-#elif defined(OS_OPENBSD)
-  being_debugged = (info.p_flag & P_TRACED) != 0;
-#else
-  being_debugged = (info.kp_proc.p_flag & P_TRACED) != 0;
-#endif
+  being_debugged = (info.KP_FLAGS & P_TRACED) != 0;
   return being_debugged;
 }
 
 #elif defined(OS_LINUX)
 
 // We can look in /proc/self/status for TracerPid.  We are likely used in crash
 // handling, so we are careful not to use the heap or have side effects.
 // Another option that is common is to try to ptrace yourself, but then we
--- a/js/src/frontend/BytecodeCompiler.cpp
+++ b/js/src/frontend/BytecodeCompiler.cpp
@@ -95,19 +95,19 @@ frontend::CompileScript(JSContext *cx, H
         break;
     }
 
     Parser parser(cx, options, chars, length, /* foldConstants = */ true);
     if (!parser.init())
         return NULL;
     parser.sct = &sct;
 
-    SharedContext sc(cx, scopeChain, /* funbox = */ NULL, StrictModeFromContext(cx));
+    GlobalSharedContext globalsc(cx, scopeChain, StrictModeFromContext(cx));
 
-    ParseContext pc(&parser, &sc, staticLevel, /* bodyid = */ 0);
+    ParseContext pc(&parser, &globalsc, staticLevel, /* bodyid = */ 0);
     if (!pc.init())
         return NULL;
 
     bool savedCallerFun = options.compileAndGo && callerFrame && callerFrame->isFunctionFrame();
     Rooted<JSScript*> script(cx, JSScript::Create(cx, NullPtr(), savedCallerFun,
                                                   options, staticLevel, ss, 0, length));
     if (!script)
         return NULL;
@@ -118,24 +118,24 @@ frontend::CompileScript(JSContext *cx, H
     if (!Bindings::initWithTemporaryStorage(cx, bindings, 0, 0, NULL))
         return NULL;
 
     // We can specialize a bit for the given scope chain if that scope chain is the global object.
     JSObject *globalScope = scopeChain && scopeChain == &scopeChain->global() ? (JSObject*) scopeChain : NULL;
     JS_ASSERT_IF(globalScope, globalScope->isNative());
     JS_ASSERT_IF(globalScope, JSCLASS_HAS_GLOBAL_FLAG_AND_SLOTS(globalScope->getClass()));
 
-    BytecodeEmitter bce(/* parent = */ NULL, &parser, &sc, script, callerFrame, !!globalScope,
+    BytecodeEmitter bce(/* parent = */ NULL, &parser, &globalsc, script, callerFrame, !!globalScope,
                         options.lineno, options.selfHostingMode);
     if (!bce.init())
         return NULL;
 
     /* If this is a direct call to eval, inherit the caller's strictness.  */
     if (callerFrame && callerFrame->script()->strictModeCode)
-        sc.strictModeState = StrictMode::STRICT;
+        globalsc.strictModeState = StrictMode::STRICT;
 
     if (options.compileAndGo) {
         if (source) {
             /*
              * Save eval program source in script->atoms[0] for the
              * eval cache (see EvalCacheLookup in jsobj.cpp).
              */
             JSAtom *atom = AtomizeString(cx, source);
@@ -170,17 +170,17 @@ frontend::CompileScript(JSContext *cx, H
         if (!stringsAtStart)
             return NULL;
         stringsAtStart->makeEmpty();
         bool ok = parser.processDirectives(stringsAtStart) && EmitTree(cx, &bce, stringsAtStart);
         parser.freeTree(stringsAtStart);
         if (!ok)
             return NULL;
     }
-    JS_ASSERT(sc.strictModeState != StrictMode::UNKNOWN);
+    JS_ASSERT(globalsc.strictModeState != StrictMode::UNKNOWN);
     for (;;) {
         TokenKind tt = tokenStream.peekToken(TSF_OPERAND);
         if (tt <= TOK_EOF) {
             if (tt == TOK_EOF)
                 break;
             JS_ASSERT(tt == TOK_ERROR);
             return NULL;
         }
@@ -272,22 +272,20 @@ frontend::CompileFunctionBody(JSContext 
     if (!parser.init())
         return false;
     parser.sct = &sct;
 
     JS_ASSERT(fun);
 
     StrictMode sms = StrictModeFromContext(cx);
     FunctionBox *funbox = parser.newFunctionBox(fun, /* outerpc = */ NULL, sms);
-
-    SharedContext funsc(cx, /* scopeChain = */ NULL, funbox, sms);
     fun->setArgCount(formals.length());
 
     unsigned staticLevel = 0;
-    ParseContext funpc(&parser, &funsc, staticLevel, /* bodyid = */ 0);
+    ParseContext funpc(&parser, funbox, staticLevel, /* bodyid = */ 0);
     if (!funpc.init())
         return false;
 
     /* FIXME: make Function format the source for a function definition. */
     ParseNode *fn = FunctionNode::create(PNK_NAME, &parser);
     if (!fn)
         return false;
 
@@ -327,17 +325,17 @@ frontend::CompileFunctionBody(JSContext 
                                                   staticLevel, ss, 0, length));
     if (!script)
         return false;
 
     InternalHandle<Bindings*> bindings(script, &script->bindings);
     if (!funpc.generateFunctionBindings(cx, bindings))
         return false;
 
-    BytecodeEmitter funbce(/* parent = */ NULL, &parser, &funsc, script, /* callerFrame = */ NULL,
+    BytecodeEmitter funbce(/* parent = */ NULL, &parser, funbox, script, /* callerFrame = */ NULL,
                            /* hasGlobalScope = */ false, options.lineno);
     if (!funbce.init())
         return false;
 
     if (!NameFunctions(cx, pn))
         return false;
 
     if (fn->pn_body) {
--- a/js/src/frontend/BytecodeEmitter.cpp
+++ b/js/src/frontend/BytecodeEmitter.cpp
@@ -692,22 +692,22 @@ PushStatementBCE(BytecodeEmitter *bce, S
  * block object or compiler created function.
  */
 static JSObject *
 EnclosingStaticScope(BytecodeEmitter *bce)
 {
     if (bce->blockChain)
         return bce->blockChain;
 
-    if (!bce->sc->inFunction()) {
+    if (!bce->sc->isFunction) {
         JS_ASSERT(!bce->parent);
         return NULL;
     }
 
-    return bce->sc->funbox()->fun();
+    return bce->sc->asFunbox()->fun();
 }
 
 // Push a block scope statement and link blockObj into bce->blockChain.
 static void
 PushBlockScopeBCE(BytecodeEmitter *bce, StmtInfoBCE *stmt, StaticBlockObject &blockObj,
                   ptrdiff_t top)
 {
     PushStatementBCE(bce, stmt, STMT_BLOCK, top);
@@ -913,19 +913,20 @@ EmitAliasedVarOp(JSContext *cx, JSOp op,
     if (pn->isUsed()) {
         /*
          * As explained in BindNameToSlot, the 'level' of a use indicates how
          * many function scopes (i.e., BytecodeEmitters) to skip to find the
          * enclosing function scope of the definition being accessed.
          */
         for (unsigned i = pn->pn_cookie.level(); i; i--) {
             skippedScopes += ClonedBlockDepth(bceOfDef);
-            if (bceOfDef->sc->funbox()->fun()->isHeavyweight()) {
+            JSFunction *funOfDef = bceOfDef->sc->asFunbox()->fun();
+            if (funOfDef->isHeavyweight()) {
                 skippedScopes++;
-                if (bceOfDef->sc->funbox()->fun()->isNamedLambda())
+                if (funOfDef->isNamedLambda())
                     skippedScopes++;
             }
             bceOfDef = bceOfDef->parent;
         }
     } else {
         JS_ASSERT(pn->isDefn());
         JS_ASSERT(pn->pn_cookie.level() == bce->script->staticLevel);
     }
@@ -1079,17 +1080,17 @@ BytecodeEmitter::isAliasedName(ParseNode
  * js::frontend::CompileScript; see comments there.
  *
  * The function returns -1 on failures.
  */
 static int
 AdjustBlockSlot(JSContext *cx, BytecodeEmitter *bce, int slot)
 {
     JS_ASSERT((unsigned) slot < bce->maxStackDepth);
-    if (bce->sc->inFunction()) {
+    if (bce->sc->isFunction) {
         slot += bce->script->bindings.numVars();
         if ((unsigned) slot >= SLOTNO_LIMIT) {
             bce->reportError(NULL, JSMSG_TOO_MANY_LOCALS);
             slot = -1;
         }
     }
     return slot;
 }
@@ -1173,17 +1174,17 @@ TryConvertToGname(BytecodeEmitter *bce, 
 {
     if (bce->selfHostingMode) {
         JS_ASSERT(*op == JSOP_NAME);
         *op = JSOP_INTRINSICNAME;
         return true;
     }
     if (bce->script->compileAndGo &&
         bce->hasGlobalScope &&
-        !(bce->sc->inFunction() && bce->sc->funMightAliasLocals()) &&
+        !(bce->sc->isFunction && bce->sc->asFunbox()->mightAliasLocals()) &&
         !pn->isDeoptimized() &&
         !bce->sc->inStrictMode())
     {
         switch (*op) {
           case JSOP_NAME:     *op = JSOP_GETGNAME; break;
           case JSOP_SETNAME:  *op = JSOP_SETGNAME; break;
           case JSOP_INCNAME:  *op = JSOP_INCGNAME; break;
           case JSOP_NAMEINC:  *op = JSOP_GNAMEINC; break;
@@ -1362,29 +1363,30 @@ BindNameToSlot(JSContext *cx, BytecodeEm
           case JSOP_INCNAME:  op = JSOP_INCLOCAL; break;
           case JSOP_NAMEINC:  op = JSOP_LOCALINC; break;
           case JSOP_DECNAME:  op = JSOP_DECLOCAL; break;
           case JSOP_NAMEDEC:  op = JSOP_LOCALDEC; break;
           default: JS_NOT_REACHED("local");
         }
         break;
 
-      case Definition::NAMED_LAMBDA:
+      case Definition::NAMED_LAMBDA: {
         JS_ASSERT(dn->isOp(JSOP_CALLEE));
         JS_ASSERT(op != JSOP_CALLEE);
 
         /*
          * Currently, the ALIASEDVAR ops do not support accessing the
          * callee of a DeclEnvObject, so use NAME.
          */
         if (dn->pn_cookie.level() != bce->script->staticLevel)
             return true;
 
-        JS_ASSERT(bce->sc->funbox()->fun()->flags & JSFUN_LAMBDA);
-        JS_ASSERT(pn->pn_atom == bce->sc->funbox()->fun()->atom());
+        RootedFunction fun(cx, bce->sc->asFunbox()->fun());
+        JS_ASSERT(fun->flags & JSFUN_LAMBDA);
+        JS_ASSERT(pn->pn_atom == fun->atom());
 
         /*
          * Leave pn->isOp(JSOP_NAME) if bce->fun is heavyweight to
          * address two cases: a new binding introduced by eval, and
          * assignment to the name in strict mode.
          *
          *   var fun = (function f(s) { eval(s); return f; });
          *   assertEq(fun("var f = 42"), 42);
@@ -1400,24 +1402,25 @@ BindNameToSlot(JSContext *cx, BytecodeEm
          *
          * Outside strict mode, assignment to a function expression's name
          * has no effect.  But in strict mode, this attempt to mutate an
          * immutable binding must throw a TypeError.  We implement this by
          * not optimizing such assignments and by marking such functions as
          * heavyweight, ensuring that the function name is represented in
          * the scope chain so that assignment will throw a TypeError.
          */
-        if (!bce->sc->funbox()->fun()->isHeavyweight()) {
+        if (!fun->isHeavyweight()) {
             op = JSOP_CALLEE;
             pn->pn_dflags |= PND_CONST;
         }
 
         pn->setOp(op);
         pn->pn_dflags |= PND_BOUND;
         return true;
+      }
 
       case Definition::PLACEHOLDER:
         return true;
     }
 
     /*
      * The difference between the current static level and the static level of
      * the definition is the number of function scopes between the current
@@ -1434,17 +1437,17 @@ BindNameToSlot(JSContext *cx, BytecodeEm
      * bloat where a single live function keeps its whole global script
      * alive.), ScopeCoordinateToTypeSet is not able to find the var/let's
      * associated types::TypeSet.
      */
     if (skip) {
         BytecodeEmitter *bceSkipped = bce;
         for (unsigned i = 0; i < skip; i++)
             bceSkipped = bceSkipped->parent;
-        if (!bceSkipped->sc->inFunction())
+        if (!bceSkipped->sc->isFunction)
             return true;
     }
 
     JS_ASSERT(!pn->isOp(op));
     pn->setOp(op);
     if (!pn->pn_cookie.set(bce->sc->context, skip, dn->pn_cookie.slot()))
         return false;
 
@@ -1646,37 +1649,37 @@ CheckSideEffects(JSContext *cx, Bytecode
         break;
     }
     return ok;
 }
 
 bool
 BytecodeEmitter::checkSingletonContext()
 {
-    if (!script->compileAndGo || sc->inFunction())
+    if (!script->compileAndGo || sc->isFunction)
         return false;
     for (StmtInfoBCE *stmt = topStmt; stmt; stmt = stmt->down) {
         if (stmt->isLoop())
             return false;
     }
     hasSingletons = true;
     return true;
 }
 
 bool
 BytecodeEmitter::needsImplicitThis()
 {
     if (!script->compileAndGo)
         return true;
 
-    if (sc->inFunction()) {
-        if (sc->funbox()->inWith)
+    if (sc->isFunction) {
+        if (sc->asFunbox()->inWith)
             return true;
     } else {
-        JSObject *scope = sc->scopeChain();
+        JSObject *scope = sc->asGlobal()->scopeChain();
         while (scope) {
             if (scope->isWith())
                 return true;
             scope = scope->enclosingScope();
         }
     }
 
     for (StmtInfoBCE *stmt = topStmt; stmt; stmt = stmt->down) {
@@ -2608,17 +2611,18 @@ frontend::EmitFunctionScript(JSContext *
 {
     /*
      * The decompiler has assumptions about what may occur immediately after
      * script->main (e.g., in the case of destructuring params). Thus, put the
      * following ops into the range [script->code, script->main). Note:
      * execution starts from script->code, so this has no semantic effect.
      */
 
-    if (bce->sc->funArgumentsHasLocalBinding()) {
+    FunctionBox *funbox = bce->sc->asFunbox();
+    if (funbox->argumentsHasLocalBinding()) {
         JS_ASSERT(bce->next() == bce->base());  /* See JSScript::argumentsBytecode. */
         bce->switchToProlog();
         if (Emit1(cx, bce, JSOP_ARGUMENTS) < 0)
             return false;
         unsigned varIndex = bce->script->bindings.argumentsVarIndex(cx);
         if (bce->script->varIsAliased(varIndex)) {
             ScopeCoordinate sc;
             sc.hops = 0;
@@ -2629,17 +2633,17 @@ frontend::EmitFunctionScript(JSContext *
             if (!EmitUnaliasedVarOp(cx, JSOP_SETLOCAL, varIndex, bce))
                 return false;
         }
         if (Emit1(cx, bce, JSOP_POP) < 0)
             return false;
         bce->switchToMain();
     }
 
-    if (bce->sc->funIsGenerator()) {
+    if (funbox->isGenerator()) {
         bce->switchToProlog();
         if (Emit1(cx, bce, JSOP_GENERATOR) < 0)
             return false;
         bce->switchToMain();
     }
 
     if (!EmitTree(cx, bce, body))
         return false;
@@ -2683,17 +2687,17 @@ MaybeEmitVarDecl(JSContext *cx, Bytecode
     if (!pn->pn_cookie.isFree()) {
         atomIndex = pn->pn_cookie.slot();
     } else {
         if (!bce->makeAtomIndex(pn->pn_atom, &atomIndex))
             return false;
     }
 
     if (JOF_OPTYPE(pn->getOp()) == JOF_ATOM &&
-        (!bce->sc->inFunction() || bce->sc->funbox()->fun()->isHeavyweight()))
+        (!bce->sc->isFunction || bce->sc->asFunbox()->fun()->isHeavyweight()))
     {
         bce->switchToProlog();
         if (!UpdateSourceCoordNotes(cx, bce, pn->pn_pos.begin))
             return false;
         if (!EmitIndexOp(cx, prologOp, atomIndex, bce))
             return false;
         bce->switchToMain();
     }
@@ -4442,17 +4446,17 @@ EmitLexicalScope(JSContext *cx, Bytecode
      * shouldn't be so complicated; try to find a simpler condition.
      */
     ptrdiff_t noteIndex = -1;
     if (pn->expr()->getKind() != PNK_FOR &&
         pn->expr()->getKind() != PNK_CATCH &&
         (stmtInfo.down
          ? stmtInfo.down->type == STMT_BLOCK &&
            (!stmtInfo.down->down || stmtInfo.down->down->type != STMT_FOR_IN_LOOP)
-         : !bce->sc->inFunction()))
+         : !bce->sc->isFunction))
     {
         /* There must be no source note already output for the next op. */
         JS_ASSERT(bce->noteCount() == 0 ||
                   bce->lastNoteOffset() != bce->offset() ||
                   !GettableNoteForNextOp(bce));
         noteIndex = NewSrcNote2(cx, bce, SRC_BRACE, 0);
         if (noteIndex < 0)
             return false;
@@ -4834,27 +4838,26 @@ EmitFunc(JSContext *cx, BytecodeEmitter 
     JS_ASSERT(fun->isInterpreted());
     if (fun->script()) {
         /*
          * This second pass is needed to emit JSOP_NOP with a source note
          * for the already-emitted function definition prolog opcode. See
          * comments in EmitStatementList.
          */
         JS_ASSERT(pn->functionIsHoisted());
-        JS_ASSERT(bce->sc->inFunction());
+        JS_ASSERT(bce->sc->isFunction);
         return EmitFunctionDefNop(cx, bce, pn->pn_index);
     }
 
     {
+        SharedContext *outersc = bce->sc;
         FunctionBox *funbox = pn->pn_funbox;
-        SharedContext sc(cx, /* scopeChain = */ NULL, funbox, funbox->strictModeState);
-        sc.cxFlags = funbox->cxFlags;
-        if (bce->sc->inFunction() && bce->sc->funMightAliasLocals())
-            sc.setFunMightAliasLocals();  // inherit funMightAliasLocals from parent
-        JS_ASSERT_IF(bce->sc->inStrictMode(), sc.inStrictMode());
+        if (outersc->isFunction && outersc->asFunbox()->mightAliasLocals())
+            funbox->setMightAliasLocals();      // inherit mightAliasLocals from parent
+        JS_ASSERT_IF(outersc->inStrictMode(), funbox->inStrictMode());
 
         // Inherit most things (principals, version, etc) from the parent.
         Rooted<JSScript*> parent(cx, bce->script);
         Rooted<JSObject*> enclosingScope(cx, EnclosingStaticScope(bce));
         CompileOptions options(cx);
         options.setPrincipals(parent->principals)
                .setOriginPrincipals(parent->originPrincipals)
                .setCompileAndGo(parent->compileAndGo)
@@ -4864,28 +4867,28 @@ EmitFunc(JSContext *cx, BytecodeEmitter 
                                                       parent->staticLevel + 1,
                                                       bce->script->scriptSource(),
                                                       funbox->bufStart, funbox->bufEnd));
         if (!script)
             return false;
 
         script->bindings = funbox->bindings;
 
-        BytecodeEmitter bce2(bce, bce->parser, &sc, script, bce->callerFrame, bce->hasGlobalScope,
-                             pn->pn_pos.begin.lineno, bce->selfHostingMode);
+        BytecodeEmitter bce2(bce, bce->parser, funbox, script, bce->callerFrame,
+                             bce->hasGlobalScope, pn->pn_pos.begin.lineno, bce->selfHostingMode);
         if (!bce2.init())
             return false;
 
         /* We measured the max scope depth when we parsed the function. */
         if (!EmitFunctionScript(cx, &bce2, pn->pn_body))
             return false;
     }
 
     /* Make the function object a literal in the outer script's pool. */
-    unsigned index = bce->objectList.add(pn->pn_funbox);
+    unsigned index = bce->objectList.add(&pn->pn_funbox->objbox);
 
     /* Non-hoisted functions simply emit their respective op. */
     if (!pn->functionIsHoisted()) {
         if (pn->pn_funbox->inGenexpLambda && NewSrcNote(cx, bce, SRC_GENEXP) < 0)
             return false;
 
         return EmitIndex32(cx, pn->getOp(), index, bce);
     }
@@ -4894,17 +4897,17 @@ EmitFunc(JSContext *cx, BytecodeEmitter 
      * For a script we emit the code as we parse. Thus the bytecode for
      * top-level functions should go in the prolog to predefine their
      * names in the variable object before the already-generated main code
      * is executed. This extra work for top-level scripts is not necessary
      * when we emit the code for a function. It is fully parsed prior to
      * invocation of the emitter and calls to EmitTree for function
      * definitions can be scheduled before generating the rest of code.
      */
-    if (!bce->sc->inFunction()) {
+    if (!bce->sc->isFunction) {
         JS_ASSERT(pn->pn_cookie.isFree());
         JS_ASSERT(pn->getOp() == JSOP_NOP);
         JS_ASSERT(!bce->topStmt);
         bce->switchToProlog();
         if (!EmitIndex32(cx, JSOP_DEFFUN, index, bce))
             return false;
         if (!UpdateSourceCoordNotes(cx, bce, pn->pn_pos.begin))
             return false;
@@ -5187,17 +5190,17 @@ EmitStatement(JSContext *cx, BytecodeEmi
      * expression statement as the script's result, despite the fact
      * that it appears useless to the compiler.
      *
      * API users may also set the JSOPTION_NO_SCRIPT_RVAL option when
      * calling JS_Compile* to suppress JSOP_POPV.
      */
     bool wantval = false;
     bool useful = false;
-    if (bce->sc->inFunction()) {
+    if (bce->sc->isFunction) {
         JS_ASSERT(!bce->script->noScriptRval);
     } else {
         useful = wantval = !bce->script->noScriptRval;
     }
 
     /* Don't eliminate expressions with side effects. */
     if (!useful) {
         if (!CheckSideEffects(cx, bce, pn2, &useful))
@@ -5953,18 +5956,18 @@ EmitUnary(JSContext *cx, BytecodeEmitter
     bce->emittingForInit = oldEmittingForInit;
     return Emit1(cx, bce, op) >= 0;
 }
 
 static bool
 EmitDefaults(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn)
 {
     JS_ASSERT(pn->isKind(PNK_ARGSBODY));
-    uint16_t ndefaults = bce->sc->funbox()->ndefaults;
-    JSFunction *fun = bce->sc->funbox()->fun();
+    uint16_t ndefaults = bce->sc->asFunbox()->ndefaults;
+    JSFunction *fun = bce->sc->asFunbox()->fun();
     unsigned nformal = fun->nargs - fun->hasRest();
     EMIT_UINT16_IMM_OP(JSOP_ACTUALSFILLED, nformal - ndefaults);
     ptrdiff_t top = bce->offset();
     size_t tableSize = (size_t)(JUMP_OFFSET_LEN * (3 + ndefaults));
     if (EmitN(cx, bce, JSOP_TABLESWITCH, tableSize) < 0)
         return false;
     ptrdiff_t jumpoff = top + JUMP_OFFSET_LEN;
     JS_ASSERT(nformal >= ndefaults);
@@ -6044,17 +6047,17 @@ frontend::EmitTree(JSContext *cx, Byteco
     switch (pn->getKind()) {
       case PNK_FUNCTIONDECL:
       case PNK_FUNCTIONEXPR:
         ok = EmitFunc(cx, bce, pn);
         break;
 
       case PNK_ARGSBODY:
       {
-        RootedFunction fun(cx, bce->sc->funbox()->fun());
+        RootedFunction fun(cx, bce->sc->asFunbox()->fun());
         ParseNode *pnlast = pn->last();
 
         // Carefully emit everything in the right order:
         // 1. Destructuring
         // 2. Functions
         // 3. Defaults
         ParseNode *pnchild = pnlast->pn_head;
         if (pnlast->pn_xflags & PNX_DESTRUCT) {
@@ -6082,17 +6085,17 @@ frontend::EmitTree(JSContext *cx, Byteco
                         return false;
                 }
             }
         }
         if (fun->hasDefaults()) {
             ParseNode *rest = NULL;
             bool restIsDefn = false;
             if (fun->hasRest()) {
-                JS_ASSERT(!bce->sc->funArgumentsHasLocalBinding());
+                JS_ASSERT(!bce->sc->asFunbox()->argumentsHasLocalBinding());
                 // Defaults with a rest parameter need special handling. The
                 // rest parameter needs to be undefined while defaults are being
                 // processed. To do this, we create the rest argument and let it
                 // sit on the stack while processing defaults. The rest
                 // parameter's slot is set to undefined for the course of
                 // default processing.
                 rest = pn->pn_head;
                 while (rest->pn_next != pnlast)
@@ -6127,17 +6130,17 @@ frontend::EmitTree(JSContext *cx, Byteco
             // Only bind the parameter if it's not aliased by a nested function
             // in the body.
             if (!pn2->isDefn())
                 continue;
             if (!BindNameToSlot(cx, bce, pn2))
                 return false;
             if (pn2->pn_next == pnlast && fun->hasRest() && !fun->hasDefaults()) {
                 // Fill rest parameter. We handled the case with defaults above.
-                JS_ASSERT(!bce->sc->funArgumentsHasLocalBinding());
+                JS_ASSERT(!bce->sc->asFunbox()->argumentsHasLocalBinding());
                 bce->switchToProlog();
                 if (Emit1(cx, bce, JSOP_REST) < 0)
                     return false;
                 CheckTypeSet(cx, bce, JSOP_REST);
                 if (!EmitVarOp(cx, pn2, JSOP_SETARG, bce))
                     return false;
                 if (Emit1(cx, bce, JSOP_POP) < 0)
                     return false;
@@ -6197,17 +6200,17 @@ frontend::EmitTree(JSContext *cx, Byteco
         break;
 
       case PNK_RETURN:
         ok = EmitReturn(cx, bce, pn);
         break;
 
 #if JS_HAS_GENERATORS
       case PNK_YIELD:
-        JS_ASSERT(bce->sc->inFunction());
+        JS_ASSERT(bce->sc->isFunction);
         if (pn->pn_kid) {
             if (!EmitTree(cx, bce, pn->pn_kid))
                 return false;
         } else {
             if (Emit1(cx, bce, JSOP_UNDEFINED) < 0)
                 return false;
         }
         if (pn->pn_hidden && NewSrcNote(cx, bce, SRC_HIDDEN) < 0)
--- a/js/src/frontend/ParseNode.cpp
+++ b/js/src/frontend/ParseNode.cpp
@@ -440,17 +440,17 @@ CloneParseTree(ParseNode *opn, Parser *p
     pn->setDefn(opn->isDefn());
     pn->setUsed(opn->isUsed());
 
     switch (pn->getArity()) {
 #define NULLCHECK(e)    JS_BEGIN_MACRO if (!(e)) return NULL; JS_END_MACRO
 
       case PN_FUNC:
         NULLCHECK(pn->pn_funbox =
-                  parser->newFunctionBox(opn->pn_funbox->object, pc, opn->pn_funbox->strictModeState));
+                  parser->newFunctionBox(opn->pn_funbox->fun(), pc, opn->pn_funbox->strictModeState));
         NULLCHECK(pn->pn_body = CloneParseTree(opn->pn_body, parser));
         pn->pn_cookie = opn->pn_cookie;
         pn->pn_dflags = opn->pn_dflags;
         pn->pn_blockid = opn->pn_blockid;
         break;
 
       case PN_LIST:
         pn->makeEmpty();
--- a/js/src/frontend/ParseNode.h
+++ b/js/src/frontend/ParseNode.h
@@ -1460,17 +1460,22 @@ LinkUseToDef(ParseNode *pn, Definition *
     pn->setUsed(true);
     pn->pn_lexdef = dn;
 }
 
 struct ObjectBox {
     ObjectBox           *traceLink;
     ObjectBox           *emitLink;
     JSObject            *object;
-    bool                isFunctionBox;
+
+    // An ObjectBox can hold a JSObject or a JSFunction.  In the latter case,
+    // the ObjectBox will be embedded within a FunctionBox;  |funbox| points to
+    // that FunctionBox.
+    FunctionBox         *const funbox;
 
     ObjectBox(ObjectBox *traceLink, JSObject *obj);
+    ObjectBox(ObjectBox *traceLink, JSFunction *fun, FunctionBox *funbox);
 };
 
 } /* namespace frontend */
 } /* namespace js */
 
 #endif /* ParseNode_h__ */
--- a/js/src/frontend/Parser.cpp
+++ b/js/src/frontend/Parser.cpp
@@ -162,32 +162,32 @@ ParseContext::define(JSContext *cx, Prop
     pn->setDefn(true);
     pn->pn_dflags &= ~PND_PLACEHOLDER;
     if (kind == Definition::CONST)
         pn->pn_dflags |= PND_CONST;
 
     Definition *dn = (Definition *)pn;
     switch (kind) {
       case Definition::ARG:
-        JS_ASSERT(sc->inFunction());
+        JS_ASSERT(sc->isFunction);
         dn->setOp(JSOP_GETARG);
         dn->pn_dflags |= PND_BOUND;
         if (!dn->pn_cookie.set(cx, staticLevel, args_.length()))
             return false;
         if (!args_.append(dn))
             return false;
         if (name == cx->runtime->atomState.emptyAtom)
             break;
         if (!decls_.addUnique(name, dn))
             return false;
         break;
 
       case Definition::CONST:
       case Definition::VAR:
-        if (sc->inFunction()) {
+        if (sc->isFunction) {
             dn->setOp(JSOP_GETLOCAL);
             dn->pn_dflags |= PND_BOUND;
             if (!dn->pn_cookie.set(cx, staticLevel, vars_.length()))
                 return false;
             if (!vars_.append(dn))
                 return false;
         }
         if (!decls_.addUnique(name, dn))
@@ -224,17 +224,17 @@ void
 ParseContext::updateDecl(JSAtom *atom, ParseNode *pn)
 {
     Definition *oldDecl = decls_.lookupFirst(atom);
 
     pn->setDefn(true);
     Definition *newDecl = (Definition *)pn;
     decls_.updateFirst(atom, newDecl);
 
-    if (!sc->inFunction()) {
+    if (!sc->isFunction) {
         JS_ASSERT(newDecl->isFreeVar());
         return;
     }
 
     JS_ASSERT(oldDecl->isBound());
     JS_ASSERT(!oldDecl->pn_cookie.isFree());
     newDecl->pn_cookie = oldDecl->pn_cookie;
     newDecl->pn_dflags |= PND_BOUND;
@@ -293,17 +293,17 @@ AppendPackedBindings(const ParseContext 
 
         *dst = Binding(name, kind, aliased);
     }
 }
 
 bool
 ParseContext::generateFunctionBindings(JSContext *cx, InternalHandle<Bindings*> bindings) const
 {
-    JS_ASSERT(sc->inFunction());
+    JS_ASSERT(sc->isFunction);
 
     unsigned count = args_.length() + vars_.length();
     Binding *packedBindings = cx->tempLifoAlloc().newArrayUninitialized<Binding>(count);
     if (!packedBindings) {
         js_ReportOutOfMemory(cx);
         return false;
     }
 
@@ -311,18 +311,19 @@ ParseContext::generateFunctionBindings(J
     AppendPackedBindings(this, vars_, packedBindings + args_.length());
 
     if (!Bindings::initWithTemporaryStorage(cx, bindings, args_.length(), vars_.length(),
                                             packedBindings))
     {
         return false;
     }
 
-    if (bindings->hasAnyAliasedBindings() || sc->funHasExtensibleScope())
-        sc->funbox()->fun()->flags |= JSFUN_HEAVYWEIGHT;
+    FunctionBox *funbox = sc->asFunbox();
+    if (bindings->hasAnyAliasedBindings() || funbox->hasExtensibleScope())
+        funbox->fun()->flags |= JSFUN_HEAVYWEIGHT;
 
     return true;
 }
 
 Parser::Parser(JSContext *cx, const CompileOptions &options,
                const jschar *chars, size_t length, bool foldConstants)
   : AutoGCRooter(cx, PARSER),
     context(cx),
@@ -357,17 +358,25 @@ Parser::~Parser()
     cx->tempLifoAlloc().release(tempPoolMark);
     cx->activeCompilations--;
 }
 
 ObjectBox::ObjectBox(ObjectBox* traceLink, JSObject *obj)
   : traceLink(traceLink),
     emitLink(NULL),
     object(obj),
-    isFunctionBox(false)
+    funbox(NULL)
+{
+}
+
+ObjectBox::ObjectBox(ObjectBox* traceLink, JSFunction *fun, FunctionBox *funbox)
+  : traceLink(traceLink),
+    emitLink(NULL),
+    object(fun),
+    funbox(funbox)
 {
 }
 
 ObjectBox *
 Parser::newObjectBox(JSObject *obj)
 {
     JS_ASSERT(obj && !IsPoisonedPtr(obj));
 
@@ -385,110 +394,107 @@ Parser::newObjectBox(JSObject *obj)
         return NULL;
     }
 
     traceListHead = objbox;
 
     return objbox;
 }
 
-FunctionBox::FunctionBox(ObjectBox* traceListHead, JSObject *obj, ParseContext *outerpc,
-                         StrictMode sms)
-  : ObjectBox(traceListHead, obj),
+FunctionBox::FunctionBox(JSContext *cx, ObjectBox* traceListHead, JSFunction *fun,
+                         ParseContext *outerpc, StrictMode sms)
+  : SharedContext(cx, /* isFunction = */ true, sms),
+    objbox(traceListHead, fun, this),
     siblings(outerpc ? outerpc->functionList : NULL),
     kids(NULL),
     bindings(),
     bufStart(0),
     bufEnd(0),
     ndefaults(0),
-    strictModeState(sms),
     inWith(false),                  // initialized below
     inGenexpLambda(false),
-    cxFlags()                       // the cxFlags are set in LeaveFunction
+    funCxFlags()
 {
-    isFunctionBox = true;
-
     if (!outerpc) {
         inWith = false;
 
     } else if (outerpc->parsingWith) {
         // This covers cases that don't involve eval().  For example:
         //
         //   with (o) { (function() { g(); })(); }
         //
         // In this case, |outerpc| corresponds to global code, and
         // outerpc->parsingWith is true.
         inWith = true;
 
-    } else if (!outerpc->sc->inFunction()) {
+    } else if (!outerpc->sc->isFunction) {
         // This covers the case where a function is nested within an eval()
         // within a |with| statement.
         //
         //   with (o) { eval("(function() { g(); })();"); }
         //
         // In this case, |outerpc| corresponds to the eval(),
         // outerpc->parsingWith is false because the eval() breaks the
         // ParseContext chain, and |parent| is NULL (again because of the
         // eval(), so we have to look at |outerpc|'s scopeChain.
         //
-        JSObject *scope = outerpc->sc->scopeChain();
+        JSObject *scope = outerpc->sc->asGlobal()->scopeChain();
         while (scope) {
             if (scope->isWith())
                 inWith = true;
             scope = scope->enclosingScope();
         }
     } else {
         // This is like the above case, but for more deeply nested functions.
         // For example:
         //
         //   with (o) { eval("(function() { (function() { g(); })(); })();"); } }
         //
         // In this case, the inner anonymous function needs to inherit the
         // setting of |inWith| from the outer one.
-        FunctionBox *parent = outerpc->sc->funbox();
+        FunctionBox *parent = outerpc->sc->asFunbox();
         if (parent && parent->inWith)
             inWith = true;
     }
 }
 
 FunctionBox *
-Parser::newFunctionBox(JSObject *obj, ParseContext *outerpc, StrictMode sms)
+Parser::newFunctionBox(JSFunction *fun, ParseContext *outerpc, StrictMode sms)
 {
-    JS_ASSERT(obj && !IsPoisonedPtr(obj));
-    JS_ASSERT(obj->isFunction());
+    JS_ASSERT(fun && !IsPoisonedPtr(fun));
 
     /*
      * We use JSContext.tempLifoAlloc to allocate parsed objects and place them
      * on a list in this Parser to ensure GC safety. Thus the tempLifoAlloc
      * arenas containing the entries must be alive until we are done with
      * scanning, parsing and code generation for the whole script or top-level
      * function.
      */
     FunctionBox *funbox =
-        context->tempLifoAlloc().new_<FunctionBox>(traceListHead, obj, outerpc, sms);
+        context->tempLifoAlloc().new_<FunctionBox>(context, traceListHead, fun, outerpc, sms);
     if (!funbox) {
         js_ReportOutOfMemory(context);
         return NULL;
     }
 
     if (outerpc)
         outerpc->functionList = funbox;
-    traceListHead = funbox;
+    traceListHead = &funbox->objbox;
 
     return funbox;
 }
 
 void
 Parser::trace(JSTracer *trc)
 {
     ObjectBox *objbox = traceListHead;
     while (objbox) {
         MarkObjectRoot(trc, &objbox->object, "parser.object");
-        if (objbox->isFunctionBox)
-            static_cast<FunctionBox *>(objbox)->bindings.trace(trc);
+        if (objbox->funbox)
+            objbox->funbox->bindings.trace(trc);
         objbox = objbox->traceLink;
     }
 }
 
 static bool
 GenerateBlockIdForStmtNode(ParseNode *pn, ParseContext *pc)
 {
     JS_ASSERT(pc->topStmt);
@@ -509,17 +515,17 @@ Parser::parse(JSObject *chain)
     /*
      * Protect atoms from being collected by a GC activation, which might
      * - nest on this thread due to out of memory (the so-called "last ditch"
      *   GC attempted within js_NewGCThing), or
      * - run for any reason on another thread if this thread is suspended on
      *   an object lock before it finishes generating bytecode into a script
      *   protected from the GC by a root or a stack frame reference.
      */
-    SharedContext globalsc(context, chain, /* funbox = */ NULL, StrictModeFromContext(context));
+    GlobalSharedContext globalsc(context, chain, StrictModeFromContext(context));
     ParseContext globalpc(this, &globalsc, /* staticLevel = */ 0, /* bodyid = */ 0);
     if (!globalpc.init())
         return NULL;
 
     ParseNode *pn = statements();
     if (pn) {
         if (!tokenStream.matchToken(TOK_EOF)) {
             reportError(NULL, JSMSG_SYNTAX_ERROR);
@@ -657,30 +663,30 @@ HasFinalReturn(ParseNode *pn)
     }
 }
 
 static bool
 ReportBadReturn(JSContext *cx, Parser *parser, ParseNode *pn, Parser::Reporter reporter,
                 unsigned errnum, unsigned anonerrnum)
 {
     JSAutoByteString name;
-    JSAtom *atom = parser->pc->sc->funbox()->fun()->atom();
+    JSAtom *atom = parser->pc->sc->asFunbox()->fun()->atom();
     if (atom) {
         if (!js_AtomToPrintableString(cx, atom, &name))
             return false;
     } else {
         errnum = anonerrnum;
     }
     return (parser->*reporter)(pn, errnum, name.ptr());
 }
 
 static bool
 CheckFinalReturn(JSContext *cx, Parser *parser, ParseNode *pn)
 {
-    JS_ASSERT(parser->pc->sc->inFunction());
+    JS_ASSERT(parser->pc->sc->isFunction);
     return HasFinalReturn(pn) == ENDS_IN_RETURN ||
            ReportBadReturn(cx, parser, pn, &Parser::reportStrictWarning,
                            JSMSG_NO_RETURN_VALUE, JSMSG_ANON_NO_RETURN_VALUE);
 }
 
 /*
  * Check that it is permitted to assign to lhs.  Strict mode code may not
  * assign to 'eval' or 'arguments'.
@@ -727,17 +733,17 @@ CheckStrictBinding(JSContext *cx, Parser
     }
 
     return true;
 }
 
 ParseNode *
 Parser::functionBody(FunctionBodyType type)
 {
-    JS_ASSERT(pc->sc->inFunction());
+    JS_ASSERT(pc->sc->isFunction);
 
     StmtInfoPC stmtInfo(context);
     PushStatementPC(pc, &stmtInfo, STMT_BLOCK);
     stmtInfo.isFunctionBodyBlock = true;
 
     JS_ASSERT(!pc->funHasReturnExpr && !pc->funHasReturnVoid);
 
     ParseNode *pn;
@@ -752,17 +758,17 @@ Parser::functionBody(FunctionBodyType ty
         if (!setStrictMode(false))
             return NULL;
         pn = UnaryNode::create(PNK_RETURN, this);
         if (pn) {
             pn->pn_kid = assignExpr();
             if (!pn->pn_kid) {
                 pn = NULL;
             } else {
-                if (pc->sc->funIsGenerator()) {
+                if (pc->sc->asFunbox()->isGenerator()) {
                     ReportBadReturn(context, this, pn, &Parser::reportError,
                                     JSMSG_BAD_GENERATOR_RETURN,
                                     JSMSG_BAD_ANON_GENERATOR_RETURN);
                     pn = NULL;
                 } else {
                     pn->setOp(JSOP_RETURN);
                     pn->pn_pos.end = pn->pn_kid->pn_pos.end;
                 }
@@ -822,17 +828,17 @@ Parser::functionBody(FunctionBodyType ty
 
     /*
      * Report error if both rest parameters and 'arguments' are used. Do this
      * check before adding artificial 'arguments' below.
      */
     Definition *maybeArgDef = pc->decls().lookupFirst(arguments);
     bool argumentsHasBinding = !!maybeArgDef;
     bool argumentsHasLocalBinding = maybeArgDef && maybeArgDef->kind() != Definition::ARG;
-    bool hasRest = pc->sc->funbox()->fun()->hasRest();
+    bool hasRest = pc->sc->asFunbox()->fun()->hasRest();
     if (hasRest && argumentsHasLocalBinding) {
         reportError(NULL, JSMSG_ARGUMENTS_AND_REST);
         return NULL;
     }
 
     /*
      * Even if 'arguments' isn't explicitly mentioned, dynamic name lookup
      * forces an 'arguments' binding. The exception is that functions with rest
@@ -849,36 +855,37 @@ Parser::functionBody(FunctionBodyType ty
     }
 
     /*
      * Now that all possible 'arguments' bindings have been added, note whether
      * 'arguments' has a local binding and whether it unconditionally needs an
      * arguments object. (Also see the flags' comments in ContextFlags.)
      */
     if (argumentsHasLocalBinding) {
-        pc->sc->setFunArgumentsHasLocalBinding();
+        FunctionBox *funbox = pc->sc->asFunbox();
+        funbox->setArgumentsHasLocalBinding();
 
         /* Dynamic scope access destroys all hope of optimization. */
         if (pc->sc->bindingsAccessedDynamically())
-            pc->sc->setFunDefinitelyNeedsArgsObj();
+            funbox->setDefinitelyNeedsArgsObj();
 
         /*
          * Check whether any parameters have been assigned within this
          * function. In strict mode parameters do not alias arguments[i], and
          * to make the arguments object reflect initial parameter values prior
          * to any mutation we create it eagerly whenever parameters are (or
          * might, in the case of calls to eval) be assigned.
          */
         if (pc->sc->needStrictChecks()) {
             for (AtomDefnListMap::Range r = pc->decls().all(); !r.empty(); r.popFront()) {
                 DefinitionList &dlist = r.front().value();
                 for (DefinitionList::Range dr = dlist.all(); !dr.empty(); dr.popFront()) {
                     Definition *dn = dr.front();
                     if (dn->kind() == Definition::ARG && dn->isAssigned()) {
-                        pc->sc->setFunDefinitelyNeedsArgsObj();
+                        funbox->setDefinitelyNeedsArgsObj();
                         goto exitLoop;
                     }
                 }
             }
           exitLoop: ;
         }
     }
 
@@ -1068,25 +1075,25 @@ struct frontend::BindData {
 
 JSFunction *
 Parser::newFunction(ParseContext *pc, JSAtom *atom, FunctionSyntaxKind kind)
 {
     JS_ASSERT_IF(kind == Statement, atom != NULL);
 
     /*
      * Find the global compilation context in order to pre-set the newborn
-     * function's parent slot to pc->sc->scopeChain. If the global context is a
-     * compile-and-go one, we leave the pre-set parent intact; otherwise we
-     * clear parent and proto.
+     * function's parent slot to pc->sc->asGlobal()->scopeChain. If the global
+     * context is a compile-and-go one, we leave the pre-set parent intact;
+     * otherwise we clear parent and proto.
      */
     while (pc->parent)
         pc = pc->parent;
 
     RootedObject parent(context);
-    parent = pc->sc->inFunction() ? NULL : pc->sc->scopeChain();
+    parent = pc->sc->isFunction ? NULL : pc->sc->asGlobal()->scopeChain();
 
     RootedFunction fun(context);
     uint32_t flags = JSFUN_INTERPRETED | (kind == Expression ? JSFUN_LAMBDA : 0);
     if (selfHostingMode)
         flags |= JSFUN_SELF_HOSTED;
     fun = js_NewFunction(context, NULL, NULL, 0, flags, parent, atom);
     if (fun && !compileAndGo) {
         if (!JSObject::clearParent(context, fun))
@@ -1142,17 +1149,17 @@ LeaveFunction(ParseNode *fn, Parser *par
               FunctionSyntaxKind kind = Expression)
 {
     JSContext *cx = parser->context;
     ParseContext *funpc = parser->pc;
     ParseContext *pc = funpc->parent;
     pc->blockidGen = funpc->blockidGen;
 
     FunctionBox *funbox = fn->pn_funbox;
-    funbox->cxFlags = funpc->sc->cxFlags;   // copy all the flags
+    JS_ASSERT(funbox == funpc->sc->asFunbox());
     funbox->kids = funpc->functionList;
 
     if (!pc->topStmt || pc->topStmt->type == STMT_BLOCK)
         fn->pn_dflags |= PND_BLOCKCHILD;
 
     /* Propagate unresolved lexical names up to pc->lexdeps. */
     if (funpc->lexdeps->count()) {
         for (AtomDefnRange r = funpc->lexdeps->all(); !r.empty(); r.popFront()) {
@@ -1175,28 +1182,28 @@ LeaveFunction(ParseNode *fn, Parser *par
                  * definitions in the ParseContext by generateFunctionBindings).
                  *
                  * If 'dn' has been assigned to, then we also flag the function
                  * scope has needing a dynamic scope so that dynamic scope
                  * setter can either ignore the set (in non-strict mode) or
                  * produce an error (in strict mode).
                  */
                 if (dn->isClosed() || dn->isAssigned())
-                    funpc->sc->funbox()->fun()->flags |= JSFUN_HEAVYWEIGHT;
+                    funbox->fun()->flags |= JSFUN_HEAVYWEIGHT;
                 continue;
             }
 
             Definition *outer_dn = pc->decls().lookupFirst(atom);
 
             /*
              * Make sure to deoptimize lexical dependencies that are polluted
              * by eval and function statements (which both flag the function as
              * having an extensible scope) or any enclosing 'with'.
              */
-            if (funpc->sc->funHasExtensibleScope() || pc->parsingWith)
+            if (funbox->hasExtensibleScope() || pc->parsingWith)
                 DeoptimizeUsesWithin(dn, fn->pn_pos);
 
             if (!outer_dn) {
                 AtomDefnAddPtr p = pc->lexdeps->lookupForAdd(atom);
                 if (p) {
                     outer_dn = p.value();
                 } else {
                     /*
@@ -1330,17 +1337,17 @@ frontend::DefineArg(Parser *parser, Pars
     return parser->pc->define(parser->context, name, argpn, Definition::ARG);
 }
 
 #if JS_HAS_DESTRUCTURING
 static bool
 BindDestructuringArg(JSContext *cx, BindData *data, HandlePropertyName name, Parser *parser)
 {
     ParseContext *pc = parser->pc;
-    JS_ASSERT(pc->sc->inFunction());
+    JS_ASSERT(pc->sc->isFunction);
 
     if (pc->decls().lookupFirst(name)) {
         parser->reportError(NULL, JSMSG_BAD_DUP_ARGS);
         return false;
     }
 
     if (!CheckStrictBinding(cx, parser, name, data->pn))
         return false;
@@ -1352,17 +1359,17 @@ BindDestructuringArg(JSContext *cx, Bind
 bool
 Parser::functionArguments(ParseNode **listp, ParseNode* funcpn, bool &hasRest)
 {
     if (tokenStream.getToken() != TOK_LP) {
         reportError(NULL, JSMSG_PAREN_BEFORE_FORMAL);
         return false;
     }
 
-    FunctionBox *funbox = pc->sc->funbox();
+    FunctionBox *funbox = pc->sc->asFunbox();
     funbox->bufStart = tokenStream.offsetOfToken(tokenStream.currentToken());
 
     hasRest = false;
 
     ParseNode *argsbody = ListNode::create(PNK_ARGSBODY, this);
     if (!argsbody)
         return false;
     argsbody->setOp(JSOP_NOP);
@@ -1582,24 +1589,25 @@ Parser::functionDef(HandlePropertyName f
          * As a SpiderMonkey-specific extension, non-body-level function
          * statements (e.g., functions in an "if" or "while" block) are
          * dynamically bound when control flow reaches the statement. The
          * emitter normally emits functions in two passes (see PNK_ARGSBODY).
          * To distinguish
          */
         if (bodyLevel) {
             JS_ASSERT(pn->functionIsHoisted());
-            JS_ASSERT_IF(pc->sc->inFunction(), !pn->pn_cookie.isFree());
-            JS_ASSERT_IF(!pc->sc->inFunction(), pn->pn_cookie.isFree());
+            JS_ASSERT_IF(pc->sc->isFunction, !pn->pn_cookie.isFree());
+            JS_ASSERT_IF(!pc->sc->isFunction, pn->pn_cookie.isFree());
         } else {
             JS_ASSERT(pc->sc->strictModeState != StrictMode::STRICT);
             JS_ASSERT(pn->pn_cookie.isFree());
-            if (pc->sc->inFunction()) {
-                pc->sc->setFunMightAliasLocals();
-                pc->sc->setFunHasExtensibleScope();
+            if (pc->sc->isFunction) {
+                FunctionBox *funbox = pc->sc->asFunbox();
+                funbox->setMightAliasLocals();
+                funbox->setHasExtensibleScope();
             }
             pn->setOp(JSOP_DEFFUN);
 
             /*
              * Instead of setting bindingsAccessedDynamically, which would be
              * overly conservative, remember the names of all function
              * statements and mark any bindings with the same as aliased at the
              * end of functionBody.
@@ -1631,18 +1639,17 @@ Parser::functionDef(HandlePropertyName f
         StrictMode::STRICT : StrictMode::UNKNOWN;
 
     // Create box for fun->object early to protect against last-ditch GC.
     FunctionBox *funbox = newFunctionBox(fun, outerpc, sms);
     if (!funbox)
         return NULL;
 
     /* Initialize early for possible flags mutation via destructuringExpr. */
-    SharedContext funsc(context, /* scopeChain = */ NULL, funbox, sms);
-    ParseContext funpc(this, &funsc, outerpc->staticLevel + 1, outerpc->blockidGen);
+    ParseContext funpc(this, funbox, outerpc->staticLevel + 1, outerpc->blockidGen);
     if (!funpc.init())
         return NULL;
 
     /* Now parse formal argument list and compute fun->nargs. */
     ParseNode *prelude = NULL;
     bool hasRest;
     if (!functionArguments(&prelude, pn, hasRest))
         return NULL;
@@ -1698,17 +1705,17 @@ Parser::functionDef(HandlePropertyName f
     pn->pn_pos.end = tokenStream.currentToken().pos.end;
 
     /*
      * Fruit of the poisonous tree: if a closure contains a dynamic name access
      * (eval, with, etc), we consider the parent to do the same. The reason is
      * that the deoptimizing effects of dynamic name access apply equally to
      * parents: any local can be read at runtime.
      */
-    if (funsc.bindingsAccessedDynamically())
+    if (funbox->bindingsAccessedDynamically())
         outerpc->sc->setBindingsAccessedDynamically();
 
 #if JS_HAS_DESTRUCTURING
     /*
      * If there were destructuring formal parameters, prepend the initializing
      * comma expression that we synthesized to body. If the body is a return
      * node, we must make a special PNK_SEQ node, to prepend the destructuring
      * code without bracing the decompilation of the function body.
@@ -1740,17 +1747,17 @@ Parser::functionDef(HandlePropertyName f
         body->pn_xflags |= PNX_DESTRUCT;
     }
 #endif
 
     /*
      * If any nested function scope does a dynamic scope access, all enclosing
      * scopes may be accessed dynamically.
      */
-    if (funsc.bindingsAccessedDynamically())
+    if (funbox->bindingsAccessedDynamically())
         outerpc->sc->setBindingsAccessedDynamically();
 
 
     pn->pn_funbox = funbox;
     pn->pn_body->append(body);
     pn->pn_body->pn_pos = body->pn_pos;
     pn->pn_blockid = outerpc->blockid();
 
@@ -1808,18 +1815,17 @@ FunctionBox::recursivelySetStrictMode(St
  * "use strict" directive anymore. Return false on error.
  */
 bool
 Parser::setStrictMode(bool strictMode)
 {
     if (pc->sc->strictModeState != StrictMode::UNKNOWN) {
         // Strict mode was inherited.
         JS_ASSERT(pc->sc->strictModeState == StrictMode::STRICT);
-        if (pc->sc->inFunction()) {
-            JS_ASSERT(pc->sc->funbox()->strictModeState == pc->sc->strictModeState);
+        if (pc->sc->isFunction) {
             JS_ASSERT(pc->parent->sc->strictModeState == StrictMode::STRICT);
         } else {
             JS_ASSERT(StrictModeFromContext(context) == StrictMode::STRICT || pc->staticLevel);
         }
         return true;
     }
     if (strictMode) {
         if (pc->queuedStrictModeError) {
@@ -1835,22 +1841,22 @@ Parser::setStrictMode(bool strictMode)
         pc->sc->strictModeState = StrictMode::NOTSTRICT;
         if (pc->queuedStrictModeError && context->hasStrictOption() &&
             pc->queuedStrictModeError->report.errorNumber != JSMSG_STRICT_CODE_WITH) {
             // Convert queued strict mode error to a warning.
             pc->queuedStrictModeError->report.flags |= JSREPORT_WARNING;
             pc->queuedStrictModeError->throwError();
         }
     }
-    JS_ASSERT_IF(!pc->sc->inFunction(), !pc->functionList);
-    if (pc->sc->strictModeState != StrictMode::UNKNOWN && pc->sc->inFunction()) {
+    JS_ASSERT_IF(!pc->sc->isFunction, !pc->functionList);
+    if (pc->sc->strictModeState != StrictMode::UNKNOWN && pc->sc->isFunction) {
         // We changed the strict mode state. Retroactively recursively set
         // strict mode status on all the function children we've seen so far
         // children (That is, functions in default expressions).
-        pc->sc->funbox()->strictModeState = pc->sc->strictModeState;
+        pc->sc->asFunbox()->strictModeState = pc->sc->strictModeState;
         for (FunctionBox *kid = pc->functionList; kid; kid = kid->siblings)
             kid->recursivelySetStrictMode(pc->sc->strictModeState);
     }
     return true;
 }
 
 /*
  * Return true if this token, known to be an unparenthesized string literal,
@@ -1984,17 +1990,17 @@ Parser::statements(bool *hasFunctionStmt
              */
             if (pc->atBodyLevel()) {
                 pn->pn_xflags |= PNX_FUNCDEFS;
             } else {
                 /*
                  * General deoptimization was done in functionDef, here we just
                  * need to tell TOK_LC in Parser::statement to add braces.
                  */
-                JS_ASSERT_IF(pc->sc->inFunction(), pc->sc->funHasExtensibleScope());
+                JS_ASSERT_IF(pc->sc->isFunction, pc->sc->asFunbox()->hasExtensibleScope());
                 if (hasFunctionStmt)
                     *hasFunctionStmt = true;
             }
         }
         pn->append(next);
     }
 
     /*
@@ -2184,18 +2190,18 @@ BindVarOrConst(JSContext *cx, BindData *
 
     if (!CheckStrictBinding(cx, parser, name, pn))
         return false;
 
     StmtInfoPC *stmt = LexicalLookup(pc, name, NULL, (StmtInfoPC *)NULL);
 
     if (stmt && stmt->type == STMT_WITH) {
         pn->pn_dflags |= PND_DEOPTIMIZED;
-        if (pc->sc->inFunction()) 
-            pc->sc->setFunMightAliasLocals();
+        if (pc->sc->isFunction)
+            pc->sc->asFunbox()->setMightAliasLocals();
         return true;
     }
 
     DefinitionList::Range defs = pc->decls().lookupMulti(name);
     JS_ASSERT_IF(stmt, !defs.empty());
 
     if (defs.empty())
         return pc->define(cx, name, pn, isConstDecl ? Definition::CONST : Definition::VAR);
@@ -2259,17 +2265,17 @@ MakeSetCall(JSContext *cx, ParseNode *pn
         parser->reportError(pn, msg);
         return false;
     }
     pn->pn_xflags |= PNX_SETCALL;
     return true;
 }
 
 static void
-NoteLValue(JSContext *cx, ParseNode *pn, SharedContext *sc)
+NoteLValue(ParseNode *pn)
 {
     if (pn->isUsed())
         pn->pn_lexdef->pn_dflags |= PND_ASSIGNED;
 
     pn->pn_dflags |= PND_ASSIGNED;
 }
 
 static bool
@@ -2332,17 +2338,17 @@ BindDestructuringVar(JSContext *cx, Bind
     else if (data->op == JSOP_DEFCONST)
         pn->setOp(JSOP_SETCONST);
     else
         pn->setOp(JSOP_SETNAME);
 
     if (data->op == JSOP_DEFCONST)
         pn->pn_dflags |= PND_CONST;
 
-    NoteLValue(cx, pn, parser->pc->sc);
+    NoteLValue(pn);
     return true;
 }
 
 /*
  * Here, we are destructuring {... P: Q, ...} = R, where P is any id, Q is any
  * LHS expression except a destructuring initialiser, and R is on the stack.
  * Because R is already evaluated, the usual LHS-specialized bytecodes won't
  * work.  After pushing R[P] we need to evaluate Q's "reference base" QB and
@@ -2359,17 +2365,17 @@ BindDestructuringVar(JSContext *cx, Bind
  * JSOP_ENUMELEM yet, because the LHS may turn out to be an arg or local var,
  * which can be optimized further.  So we select JSOP_SETNAME.
  */
 static bool
 BindDestructuringLHS(JSContext *cx, ParseNode *pn, Parser *parser)
 {
     switch (pn->getKind()) {
       case PNK_NAME:
-        NoteLValue(cx, pn, parser->pc->sc);
+        NoteLValue(pn);
         /* FALL THROUGH */
 
       case PNK_DOT:
       case PNK_ELEM:
         /*
          * We may be called on a name node that has already been specialized,
          * in the very weird and ECMA-262-required "for (var [x] = i in o) ..."
          * case. See bug 558633.
@@ -2555,34 +2561,34 @@ Parser::destructuringExpr(BindData *data
 }
 
 #endif /* JS_HAS_DESTRUCTURING */
 
 ParseNode *
 Parser::returnOrYield(bool useAssignExpr)
 {
     TokenKind tt = tokenStream.currentToken().type;
-    if (!pc->sc->inFunction()) {
+    if (!pc->sc->isFunction) {
         reportError(NULL, JSMSG_BAD_RETURN_OR_YIELD,
                     (tt == TOK_RETURN) ? js_return_str : js_yield_str);
         return NULL;
     }
 
     ParseNode *pn = UnaryNode::create((tt == TOK_RETURN) ? PNK_RETURN : PNK_YIELD, this);
     if (!pn)
         return NULL;
 
 #if JS_HAS_GENERATORS
     if (tt == TOK_YIELD) {
         /*
          * If we're within parens, we won't know if this is a generator expression until we see
          * a |for| token, so we have to delay flagging the current function.
          */
         if (pc->parenDepth == 0) {
-            pc->sc->setFunIsGenerator();
+            pc->sc->asFunbox()->setIsGenerator();
         } else {
             pc->yieldCount++;
             pc->yieldNode = pn;
         }
     }
 #endif
 
     /* This is ugly, but we don't want to require a semicolon. */
@@ -2609,17 +2615,17 @@ Parser::returnOrYield(bool useAssignExpr
         pn->pn_kid = pn2;
     } else {
 #if JS_HAS_GENERATORS
         if (tt == TOK_RETURN)
 #endif
             pc->funHasReturnVoid = true;
     }
 
-    if (pc->funHasReturnExpr && pc->sc->funIsGenerator()) {
+    if (pc->funHasReturnExpr && pc->sc->asFunbox()->isGenerator()) {
         /* As in Python (see PEP-255), disallow return v; in generators. */
         ReportBadReturn(context, this, pn, &Parser::reportError, JSMSG_BAD_GENERATOR_RETURN,
                         JSMSG_BAD_ANON_GENERATOR_RETURN);
         return NULL;
     }
 
     if (context->hasStrictOption() && pc->funHasReturnExpr && pc->funHasReturnVoid &&
         !ReportBadReturn(context, this, pn, &Parser::reportStrictWarning,
@@ -3217,17 +3223,17 @@ Parser::forStatement()
             pn2 = CloneLeftHandSide(pn2, this);
             if (!pn2)
                 return NULL;
         }
 
         switch (pn2->getKind()) {
           case PNK_NAME:
             /* Beware 'for (arguments in ...)' with or without a 'var'. */
-            NoteLValue(context, pn2, pc->sc);
+            NoteLValue(pn2);
             break;
 
 #if JS_HAS_DESTRUCTURING
           case PNK_ASSIGN:
             JS_NOT_REACHED("forStatement TOK_ASSIGN");
             break;
 
           case PNK_ARRAY:
@@ -4174,17 +4180,17 @@ Parser::variables(ParseNodeKind kind, St
             }
 
             pn2->setOp((pn2->pn_dflags & PND_BOUND)
                        ? JSOP_SETLOCAL
                        : (data.op == JSOP_DEFCONST)
                        ? JSOP_SETCONST
                        : JSOP_SETNAME);
 
-            NoteLValue(context, pn2, pc->sc);
+            NoteLValue(pn2);
 
             /* The declarator's position must include the initializer. */
             pn2->pn_pos.end = init->pn_pos.end;
         }
     } while (tokenStream.matchToken(TOK_COMMA));
 
     pn->pn_pos.end = pn->last()->pn_pos.end;
     return pn;
@@ -4457,17 +4463,17 @@ Parser::condExpr1()
 bool
 Parser::setAssignmentLhsOps(ParseNode *pn, JSOp op)
 {
     switch (pn->getKind()) {
       case PNK_NAME:
         if (!CheckStrictAssignment(context, this, pn))
             return false;
         pn->setOp(pn->isOp(JSOP_GETLOCAL) ? JSOP_SETLOCAL : JSOP_SETNAME);
-        NoteLValue(context, pn, pc->sc);
+        NoteLValue(pn);
         break;
       case PNK_DOT:
         pn->setOp(JSOP_SETPROP);
         break;
       case PNK_ELEM:
         pn->setOp(JSOP_SETELEM);
         break;
 #if JS_HAS_DESTRUCTURING
@@ -4576,17 +4582,17 @@ SetIncOpKid(JSContext *cx, Parser *parse
 
     if (!SetLvalKid(cx, parser, pn, kid, incop_name_str[tt == TOK_DEC]))
         return false;
     switch (kid->getKind()) {
       case PNK_NAME:
         op = (tt == TOK_INC)
              ? (preorder ? JSOP_INCNAME : JSOP_NAMEINC)
              : (preorder ? JSOP_DECNAME : JSOP_NAMEDEC);
-        NoteLValue(cx, kid, parser->pc->sc);
+        NoteLValue(kid);
         break;
 
       case PNK_DOT:
         op = (tt == TOK_INC)
              ? (preorder ? JSOP_INCPROP : JSOP_PROPINC)
              : (preorder ? JSOP_DECPROP : JSOP_PROPDEC);
         break;
 
@@ -4845,23 +4851,23 @@ GenexpGuard::checkValidBody(ParseNode *p
  * Call this after endBody() when determining that the body *was not* in a
  * generator expression.
  */
 bool
 GenexpGuard::maybeNoteGenerator(ParseNode *pn)
 {
     ParseContext *pc = parser->pc;
     if (pc->yieldCount > 0) {
-        if (!pc->sc->inFunction()) {
+        if (!pc->sc->isFunction) {
             parser->reportError(NULL, JSMSG_BAD_RETURN_OR_YIELD, js_yield_str);
             return false;
         }
-        pc->sc->setFunIsGenerator();
+        pc->sc->asFunbox()->setIsGenerator();
         if (pc->funHasReturnExpr) {
-            /* At the time we saw the yield, we might not have set funIsGenerator yet. */
+            /* At the time we saw the yield, we might not have set isGenerator yet. */
             ReportBadReturn(pc->sc->context, parser, pn, &Parser::reportError,
                             JSMSG_BAD_GENERATOR_RETURN, JSMSG_BAD_ANON_GENERATOR_RETURN);
             return false;
         }
     }
     return true;
 }
 
@@ -4943,17 +4949,17 @@ CompExprTransplanter::transplant(ParseNo
         /*
          * Only the first level of transplant recursion through functions needs
          * to reparent the funbox, since all descendant functions are correctly
          * linked under the top-most funbox.
          */
         FunctionBox *funbox = pn->pn_funbox;
 
         if (++funcLevel == 1 && genexp) {
-            FunctionBox *parent = pc->sc->funbox();
+            FunctionBox *parent = pc->sc->asFunbox();
 
             FunctionBox **funboxp = &pc->parent->functionList;
             while (*funboxp != funbox)
                 funboxp = &(*funboxp)->siblings;
             *funboxp = funbox->siblings;
 
             funbox->siblings = parent->kids;
             parent->kids = funbox;
@@ -5353,47 +5359,48 @@ Parser::generatorExpr(ParseNode *kid)
     {
         ParseContext *outerpc = pc;
 
         RootedFunction fun(context, newFunction(outerpc, /* atom = */ NULL, Expression));
         if (!fun)
             return NULL;
 
         /* Create box for fun->object early to protect against last-ditch GC. */
-        FunctionBox *funbox = newFunctionBox(fun, outerpc, outerpc->sc->strictModeState);
-        if (!funbox)
+        FunctionBox *genFunbox = newFunctionBox(fun, outerpc, outerpc->sc->strictModeState);
+        if (!genFunbox)
             return NULL;
 
-        SharedContext gensc(context, /* scopeChain = */ NULL, funbox, outerpc->sc->strictModeState);
-        ParseContext genpc(this, &gensc, outerpc->staticLevel + 1, outerpc->blockidGen);
+        ParseContext genpc(this, genFunbox, outerpc->staticLevel + 1, outerpc->blockidGen);
         if (!genpc.init())
             return NULL;
 
         /*
          * We assume conservatively that any deoptimization flags in pc->sc
          * come from the kid. So we propagate these flags into genfn. For code
          * simplicity we also do not detect if the flags were only set in the
          * kid and could be removed from pc->sc.
          */
-        gensc.cxFlags = outerpc->sc->cxFlags;
-        gensc.setFunIsGenerator();
-
-        funbox->inGenexpLambda = true;
-        genfn->pn_funbox = funbox;
+        genFunbox->anyCxFlags = outerpc->sc->anyCxFlags;
+        if (outerpc->sc->isFunction)
+            genFunbox->funCxFlags = outerpc->sc->asFunbox()->funCxFlags;
+
+        genFunbox->setIsGenerator();
+        genFunbox->inGenexpLambda = true;
+        genfn->pn_funbox = genFunbox;
         genfn->pn_blockid = genpc.bodyid;
 
         ParseNode *body = comprehensionTail(pn, outerpc->blockid(), true);
         if (!body)
             return NULL;
         JS_ASSERT(!genfn->pn_body);
         genfn->pn_body = body;
         genfn->pn_pos.begin = body->pn_pos.begin = kid->pn_pos.begin;
         genfn->pn_pos.end = body->pn_pos.end = tokenStream.currentToken().pos.end;
 
-        JSAtom *arguments = gensc.context->runtime->atomState.argumentsAtom;
+        JSAtom *arguments = context->runtime->atomState.argumentsAtom;
         if (AtomDefnPtr p = genpc.lexdeps->lookup(arguments)) {
             Definition *dn = p.value();
             ParseNode *errorNode = dn->dn_uses ? dn->dn_uses : body;
             reportError(errorNode, JSMSG_BAD_GENEXP_BODY, js_arguments_str);
             return NULL;
         }
 
         if (!LeaveFunction(genfn, this))
@@ -5693,18 +5700,18 @@ Parser::memberExpr(bool allowCallSyntax)
                     /* Select JSOP_EVAL and flag pc as heavyweight. */
                     nextMember->setOp(JSOP_EVAL);
                     pc->sc->setBindingsAccessedDynamically();
 
                     /*
                      * In non-strict mode code, direct calls to eval can add
                      * variables to the call object.
                      */
-                    if (pc->sc->inFunction() && pc->sc->strictModeState != StrictMode::STRICT)
-                        pc->sc->setFunHasExtensibleScope();
+                    if (pc->sc->isFunction && pc->sc->strictModeState != StrictMode::STRICT)
+                        pc->sc->asFunbox()->setHasExtensibleScope();
                 }
             } else if (lhs->isOp(JSOP_GETPROP)) {
                 /* Select JSOP_FUNAPPLY given foo.apply(...). */
                 if (lhs->pn_atom == context->runtime->atomState.applyAtom)
                     nextMember->setOp(JSOP_FUNAPPLY);
                 else if (lhs->pn_atom == context->runtime->atomState.callAtom)
                     nextMember->setOp(JSOP_FUNCALL);
             }
@@ -6335,17 +6342,17 @@ Parser::xmlElementOrListRoot(bool allowL
 ParseNode *
 Parser::parseXMLText(JSObject *chain, bool allowList)
 {
     /*
      * Push a compiler frame if we have no frames, or if the top frame is a
      * lightweight function activation, or if its scope chain doesn't match
      * the one passed to us.
      */
-    SharedContext xmlsc(context, chain, /* funbox = */ NULL, StrictMode::NOTSTRICT);
+    GlobalSharedContext xmlsc(context, chain, StrictMode::NOTSTRICT);
     ParseContext xmlpc(this, &xmlsc, /* staticLevel = */ 0, /* bodyid = */ 0);
     if (!xmlpc.init())
         return NULL;
 
     /* Set XML-only mode to turn off special treatment of {expr} in XML. */
     tokenStream.setXMLOnlyMode();
     TokenKind tt = tokenStream.getToken(TSF_OPERAND);
 
--- a/js/src/frontend/Parser.h
+++ b/js/src/frontend/Parser.h
@@ -79,22 +79,22 @@ struct ParseContext                 /* t
     DeclVector      vars_;          /* var/const definitions */
 
   public:
     const AtomDecls &decls() const {
         return decls_;
     }
 
     uint32_t numArgs() const {
-        JS_ASSERT(sc->inFunction());
+        JS_ASSERT(sc->isFunction);
         return args_.length();
     }
 
     uint32_t numVars() const {
-        JS_ASSERT(sc->inFunction());
+        JS_ASSERT(sc->isFunction);
         return vars_.length();
     }
 
     /*
      * This function adds a definition to the lexical scope represented by this
      * ParseContext.
      *
      * Pre-conditions:
@@ -298,17 +298,17 @@ struct Parser : private AutoGCRooter
 #endif
 
     /*
      * Allocate a new parsed object or function container from
      * cx->tempLifoAlloc.
      */
     ObjectBox *newObjectBox(JSObject *obj);
 
-    FunctionBox *newFunctionBox(JSObject *obj, ParseContext *pc, StrictMode sms);
+    FunctionBox *newFunctionBox(JSFunction *fun, ParseContext *pc, StrictMode sms);
 
     /*
      * Create a new function object given parse context (pc) and a name (which
      * is optional if this is a function expression).
      */
     JSFunction *newFunction(ParseContext *pc, JSAtom *atom, FunctionSyntaxKind kind);
 
     void trace(JSTracer *trc);
--- a/js/src/frontend/SharedContext-inl.h
+++ b/js/src/frontend/SharedContext-inl.h
@@ -10,41 +10,57 @@
 
 #include "frontend/Parser.h"
 #include "frontend/SharedContext.h"
 
 namespace js {
 namespace frontend {
 
 inline
-SharedContext::SharedContext(JSContext *cx, JSObject *scopeChain, FunctionBox *funbox,
-                             StrictMode sms)
+SharedContext::SharedContext(JSContext *cx, bool isFun, StrictMode sms)
   : context(cx),
-    funbox_(funbox),
-    scopeChain_(cx, scopeChain),
-    cxFlags(),
+    isFunction(isFun),
+    anyCxFlags(),
     strictModeState(sms)
 {
-    JS_ASSERT((funbox && !scopeChain_) || !funbox);
 }
 
 inline bool
 SharedContext::inStrictMode()
 {
     JS_ASSERT(strictModeState != StrictMode::UNKNOWN);
-    JS_ASSERT_IF(inFunction(), funbox()->strictModeState == strictModeState);
     return strictModeState == StrictMode::STRICT;
 }
 
 inline bool
 SharedContext::needStrictChecks()
 {
     return context->hasStrictOption() || strictModeState != StrictMode::NOTSTRICT;
 }
 
+inline GlobalSharedContext *
+SharedContext::asGlobal()
+{
+    JS_ASSERT(!isFunction);
+    return static_cast<GlobalSharedContext*>(this);
+}
+
+inline FunctionBox *
+SharedContext::asFunbox()
+{
+    JS_ASSERT(isFunction);
+    return static_cast<FunctionBox*>(this);
+}
+
+GlobalSharedContext::GlobalSharedContext(JSContext *cx, JSObject *scopeChain, StrictMode sms)
+  : SharedContext(cx, /* isFunction = */ false, sms),
+    scopeChain_(cx, scopeChain)
+{
+}
+
 } /* namespace frontend */
 
 template <class ContextT>
 void
 frontend::PushStatement(ContextT *ct, typename ContextT::StmtInfo *stmt, StmtType type)
 {
     stmt->type = type;
     stmt->isBlockScope = false;
--- a/js/src/frontend/SharedContext.h
+++ b/js/src/frontend/SharedContext.h
@@ -17,21 +17,21 @@
 
 #include "frontend/ParseMaps.h"
 #include "frontend/ParseNode.h"
 #include "vm/ScopeObject.h"
 
 namespace js {
 namespace frontend {
 
-class ContextFlags {
-
+// These flags apply to both global and function contexts.
+class AnyContextFlags
+{
     // This class's data is all private and so only visible to these friends.
     friend struct SharedContext;
-    friend struct FunctionBox;
 
     // True if "use strict"; appears in the body instead of being inherited.
     bool            hasExplicitUseStrict:1;
 
     // The (static) bindings of this script need to support dynamic name
     // read/write access. Here, 'dynamic' means dynamic dictionary lookup on
     // the scope chain for a dynamic set of keys. The primary examples are:
     //  - direct eval
@@ -49,31 +49,43 @@ class ContextFlags {
     // binding access since it does not go through the normal name lookup
     // mechanism. This is debatable and could be changed (although care must be
     // taken not to turn off the whole 'arguments' optimization). To answer the
     // more general "is this argument aliased" question, script->needsArgsObj
     // should be tested (see JSScript::argIsAlised).
     //
     bool            bindingsAccessedDynamically:1;
 
+  public:
+    AnyContextFlags()
+     :  hasExplicitUseStrict(false),
+        bindingsAccessedDynamically(false)
+    { }
+};
+
+class FunctionContextFlags
+{
+    // This class's data is all private and so only visible to these friends.
+    friend struct FunctionBox;
+
     // We parsed a yield statement in the function.
-    bool            funIsGenerator:1;
+    bool            isGenerator:1;
 
     // The function or a function that encloses it may define new local names
     // at runtime through means other than calling eval.
-    bool            funMightAliasLocals:1;
+    bool            mightAliasLocals:1;
 
     // This function does something that can extend the set of bindings in its
     // call objects --- it does a direct eval in non-strict code, or includes a
     // function statement (as opposed to a function definition).
     //
     // This flag is *not* inherited by enclosed or enclosing functions; it
     // applies only to the function in whose flags it appears.
     //
-    bool            funHasExtensibleScope:1;
+    bool            hasExtensibleScope:1;
 
     // Technically, every function has a binding named 'arguments'. Internally,
     // this binding is only added when 'arguments' is mentioned by the function
     // body. This flag indicates whether 'arguments' has been bound either
     // through implicit use:
     //   function f() { return arguments }
     // or explicit redeclaration:
     //   function f() { var arguments; return arguments }
@@ -86,60 +98,55 @@ class ContextFlags {
     // arguments object (not undefined, like normal locals).
     //
     // Note 2: if 'arguments' is bound as a formal parameter, there will be an
     // 'arguments' in Bindings, but, as the "LOCAL" in the name indicates, this
     // flag will not be set. This is because, as a formal, 'arguments' will
     // have no special semantics: the initial value is unconditionally the
     // actual argument (or undefined if nactual < nformal).
     //
-    bool            funArgumentsHasLocalBinding:1;
+    bool            argumentsHasLocalBinding:1;
 
     // In many cases where 'arguments' has a local binding (as described above)
     // we do not need to actually create an arguments object in the function
     // prologue: instead we can analyze how 'arguments' is used (using the
     // simple dataflow analysis in analyzeSSA) to determine that uses of
     // 'arguments' can just read from the stack frame directly. However, the
     // dataflow analysis only looks at how JSOP_ARGUMENTS is used, so it will
     // be unsound in several cases. The frontend filters out such cases by
     // setting this flag which eagerly sets script->needsArgsObj to true.
     //
-    bool            funDefinitelyNeedsArgsObj:1;
+    bool            definitelyNeedsArgsObj:1;
 
   public:
-    ContextFlags()
-     :  hasExplicitUseStrict(false),
-        bindingsAccessedDynamically(false),
-        funIsGenerator(false),
-        funMightAliasLocals(false),
-        funHasExtensibleScope(false),
-        funArgumentsHasLocalBinding(false),
-        funDefinitelyNeedsArgsObj(false)
+    FunctionContextFlags()
+     :  isGenerator(false),
+        mightAliasLocals(false),
+        hasExtensibleScope(false),
+        argumentsHasLocalBinding(false),
+        definitelyNeedsArgsObj(false)
     { }
 };
 
+class GlobalSharedContext;
+
 /*
  * The struct SharedContext is part of the current parser context (see
  * ParseContext). It stores information that is reused between the parser and
  * the bytecode emitter. Note however, that this information is not shared
  * between the two; they simply reuse the same data structure.
  */
-struct SharedContext {
+class SharedContext
+{
+  public:
     JSContext       *const context;
 
-  private:
-    FunctionBox *const funbox_;     /* null or box for function we're compiling
-                                       (if inFunction() is true) */
-
-    const RootedObject scopeChain_; /* scope chain object for the script
-                                       (if inFunction() is false) */
-
-  public:
-    ContextFlags    cxFlags;
-
+    const bool isFunction;          /* true for function code, false for
+                                       global code */
+    AnyContextFlags anyCxFlags;
 
     // strictModeState tracks the strictness of this context. Normally, it
     // should be STRICT or NOTSTRICT. However, it can be UNKNOWN when parsing
     // code for which the strictness has not yet been determined. This happens
     // when parsing the defaults of a functions and non-"use strict" directive
     // prologue strings.
     //
     // Unless its parent is strict, a context starts out in the UNKNOWN
@@ -153,51 +160,81 @@ struct SharedContext {
     // can have STRICT children but not NOTSTRICT children. NOTSTRICT funboxes
     // can have any kind of children.
     //
     // When parsing is done, no context may be in the UNKNOWN strictness state.
     StrictMode strictModeState;
 
     // If it's function code, funbox must be non-NULL and scopeChain must be NULL.
     // If it's global code, funbox must be NULL.
-    inline SharedContext(JSContext *cx, JSObject *scopeChain, FunctionBox *funbox,
-                         StrictMode sms);
-
-    // The |fun*| flags are only relevant if |inFunction()| is true.
-#define INFUNC JS_ASSERT(inFunction())
+    inline SharedContext(JSContext *cx, bool isFun, StrictMode sms);
 
-    bool hasExplicitUseStrict()        const {         return cxFlags.hasExplicitUseStrict; }
-    bool bindingsAccessedDynamically() const {         return cxFlags.bindingsAccessedDynamically; }
-    bool funIsGenerator()              const { INFUNC; return cxFlags.funIsGenerator; }
-    bool funMightAliasLocals()         const { INFUNC; return cxFlags.funMightAliasLocals; }
-    bool funHasExtensibleScope()       const { INFUNC; return cxFlags.funHasExtensibleScope; }
-    bool funArgumentsHasLocalBinding() const { INFUNC; return cxFlags.funArgumentsHasLocalBinding; }
-    bool funDefinitelyNeedsArgsObj()   const { INFUNC; return cxFlags.funDefinitelyNeedsArgsObj; }
+    inline GlobalSharedContext *asGlobal();
+    inline FunctionBox *asFunbox();
 
-    void setExplicitUseStrict()               {         cxFlags.hasExplicitUseStrict        = true; }
-    void setBindingsAccessedDynamically()     {         cxFlags.bindingsAccessedDynamically = true; }
-    void setFunIsGenerator()                  { INFUNC; cxFlags.funIsGenerator              = true; }
-    void setFunMightAliasLocals()             { INFUNC; cxFlags.funMightAliasLocals         = true; }
-    void setFunHasExtensibleScope()           { INFUNC; cxFlags.funHasExtensibleScope       = true; }
-    void setFunArgumentsHasLocalBinding()     { INFUNC; cxFlags.funArgumentsHasLocalBinding = true; }
-    void setFunDefinitelyNeedsArgsObj()       { JS_ASSERT(cxFlags.funArgumentsHasLocalBinding);
-                                                INFUNC; cxFlags.funDefinitelyNeedsArgsObj   = true; }
+    bool hasExplicitUseStrict()        const { return anyCxFlags.hasExplicitUseStrict; }
+    bool bindingsAccessedDynamically() const { return anyCxFlags.bindingsAccessedDynamically; }
 
-#undef INFUNC
-
-    bool inFunction() const { return !!funbox_; }
-
-    FunctionBox *funbox()  const { JS_ASSERT(inFunction());  return funbox_; }
-    JSObject *scopeChain() const { JS_ASSERT(!inFunction()); return scopeChain_; }
+    void setExplicitUseStrict()           { anyCxFlags.hasExplicitUseStrict        = true; }
+    void setBindingsAccessedDynamically() { anyCxFlags.bindingsAccessedDynamically = true; }
 
     // JSOPTION_STRICT warnings or strict mode errors.
     inline bool needStrictChecks();
     inline bool inStrictMode();
 };
 
+class GlobalSharedContext : public SharedContext
+{
+  private:
+    const RootedObject scopeChain_; /* scope chain object for the script */
+
+  public:
+    inline GlobalSharedContext(JSContext *cx, JSObject *scopeChain, StrictMode sms);
+
+    JSObject *scopeChain() const { return scopeChain_; }
+};
+
+class FunctionBox : public SharedContext
+{
+  public:
+    ObjectBox       objbox;
+    FunctionBox     *siblings;
+    FunctionBox     *kids;
+    Bindings        bindings;               /* bindings for this function */
+    size_t          bufStart;
+    size_t          bufEnd;
+    uint16_t        ndefaults;
+    bool            inWith:1;               /* some enclosing scope is a with-statement
+                                               or E4X filter-expression */
+    bool            inGenexpLambda:1;       /* lambda from generator expression */
+
+    FunctionContextFlags funCxFlags;
+
+    FunctionBox(JSContext *cx, ObjectBox* traceListHead, JSFunction *fun, ParseContext *pc,
+                StrictMode sms);
+
+    JSFunction *fun() const { return objbox.object->toFunction(); }
+
+    void recursivelySetStrictMode(StrictMode strictness);
+
+    bool isGenerator()              const { return funCxFlags.isGenerator; }
+    bool mightAliasLocals()         const { return funCxFlags.mightAliasLocals; }
+    bool hasExtensibleScope()       const { return funCxFlags.hasExtensibleScope; }
+    bool argumentsHasLocalBinding() const { return funCxFlags.argumentsHasLocalBinding; }
+    bool definitelyNeedsArgsObj()   const { return funCxFlags.definitelyNeedsArgsObj; }
+
+    void setIsGenerator()                  { funCxFlags.isGenerator              = true; }
+    void setMightAliasLocals()             { funCxFlags.mightAliasLocals         = true; }
+    void setHasExtensibleScope()           { funCxFlags.hasExtensibleScope       = true; }
+    void setArgumentsHasLocalBinding()     { funCxFlags.argumentsHasLocalBinding = true; }
+    void setDefinitelyNeedsArgsObj()       { JS_ASSERT(funCxFlags.argumentsHasLocalBinding);
+                                             funCxFlags.definitelyNeedsArgsObj   = true; }
+};
+
+
 /*
  * NB: If you add a new type of statement that is a scope, add it between
  * STMT_WITH and STMT_CATCH, or you will break StmtInfoBase::linksScope. If you
  * add a non-looping statement type, add it before STMT_DO_LOOP or you will
  * break StmtInfoBase::isLoop().
  *
  * Also remember to keep the statementName array in BytecodeEmitter.cpp in
  * sync.
@@ -278,41 +315,16 @@ struct StmtInfoBase {
         return type >= STMT_DO_LOOP;
     }
 
     bool isTrying() const {
         return STMT_TRY <= type && type <= STMT_SUBROUTINE;
     }
 };
 
-struct FunctionBox : public ObjectBox
-{
-    FunctionBox     *siblings;
-    FunctionBox     *kids;
-    Bindings        bindings;               /* bindings for this function */
-    size_t          bufStart;
-    size_t          bufEnd;
-    uint16_t        ndefaults;
-    StrictMode      strictModeState;
-    bool            inWith:1;               /* some enclosing scope is a with-statement
-                                               or E4X filter-expression */
-    bool            inGenexpLambda:1;       /* lambda from generator expression */
-
-    ContextFlags    cxFlags;
-
-    FunctionBox(ObjectBox* traceListHead, JSObject *obj, ParseContext *pc,
-                StrictMode sms);
-
-    bool funIsGenerator() const { return cxFlags.funIsGenerator; }
-
-    JSFunction *fun() const { return (JSFunction *) object; }
-
-    void recursivelySetStrictMode(StrictMode strictness);
-};
-
 // Push the C-stack-allocated struct at stmt onto the StmtInfoPC stack.
 template <class ContextT>
 void
 PushStatement(ContextT *ct, typename ContextT::StmtInfo *stmt, StmtType type);
 
 template <class ContextT>
 void
 FinishPushBlockScope(ContextT *ct, typename ContextT::StmtInfo *stmt, StaticBlockObject &blockObj);
--- a/js/src/gc/Heap.h
+++ b/js/src/gc/Heap.h
@@ -99,37 +99,42 @@ struct Cell
     inline JSCompartment *compartment() const;
 
 #ifdef DEBUG
     inline bool isAligned() const;
 #endif
 };
 
 /*
- * Page size is 4096 by default, except for SPARC, where it is 8192.
+ * Page size must be static to support our arena pointer optimizations, so we
+ * are forced to support each platform with non-4096 pages as a special case.
+ * Note: The freelist supports a maximum arena shift of 15.
  * Note: Do not use JS_CPU_SPARC here, this header is used outside JS.
  * Bug 692267: Move page size definition to gc/Memory.h and include it
  *             directly once jsgc.h is no longer an installed header.
  */
 #if (defined(SOLARIS) || defined(__FreeBSD__)) && \
     (defined(__sparc) || defined(__sparcv9) || defined(__ia64))
 const size_t PageShift = 13;
+const size_t ArenaShift = PageShift;
+#elif defined(__powerpc__)
+const size_t PageShift = 16;
+const size_t ArenaShift = 12;
 #else
 const size_t PageShift = 12;
+const size_t ArenaShift = PageShift;
 #endif
 const size_t PageSize = size_t(1) << PageShift;
+const size_t ArenaSize = size_t(1) << ArenaShift;
+const size_t ArenaMask = ArenaSize - 1;
 
 const size_t ChunkShift = 20;
 const size_t ChunkSize = size_t(1) << ChunkShift;
 const size_t ChunkMask = ChunkSize - 1;
 
-const size_t ArenaShift = PageShift;
-const size_t ArenaSize = PageSize;
-const size_t ArenaMask = ArenaSize - 1;
-
 /*
  * This is the maximum number of arenas we allow in the FreeCommitted state
  * before we trigger a GC_SHRINK to release free arenas to the OS.
  */
 const static uint32_t FreeCommittedArenasThreshold = (32 << 20) / ArenaSize;
 
 /*
  * The mark bitmap has one bit per each GC cell. For multi-cell GC things this
--- a/js/src/gc/Memory.cpp
+++ b/js/src/gc/Memory.cpp
@@ -10,16 +10,25 @@
 #include "jstypes.h"
 
 #include "js/Utility.h"
 #include "gc/Memory.h"
 
 namespace js {
 namespace gc {
 
+/* Unused memory decommiting requires the arena size match the page size. */
+extern const size_t PageSize;
+extern const size_t ArenaSize;
+static bool
+DecommitEnabled()
+{
+    return PageSize == ArenaSize;
+}
+
 #if defined(XP_WIN)
 #include "jswin.h"
 #include <psapi.h>
 
 static size_t AllocationGranularity = 0;
 
 void
 InitMemorySubsystem()
@@ -78,16 +87,19 @@ void
 UnmapPages(void *p, size_t size)
 {
     JS_ALWAYS_TRUE(VirtualFree(p, 0, MEM_RELEASE));
 }
 
 bool
 MarkPagesUnused(void *p, size_t size)
 {
+    if (!DecommitEnabled())
+        return false;
+
     JS_ASSERT(uintptr_t(p) % PageSize == 0);
     LPVOID p2 = VirtualAlloc(p, size, MEM_RESET, PAGE_READWRITE);
     return p2 == p;
 }
 
 bool
 MarkPagesInUse(void *p, size_t size)
 {
@@ -347,16 +359,19 @@ void
 UnmapPages(void *p, size_t size)
 {
     JS_ALWAYS_TRUE(0 == munmap(p, size));
 }
 
 bool
 MarkPagesUnused(void *p, size_t size)
 {
+    if (!DecommitEnabled())
+        return false;
+
     JS_ASSERT(uintptr_t(p) % PageSize == 0);
     int result = madvise(p, size, MADV_DONTNEED);
     return result != -1;
 }
 
 bool
 MarkPagesInUse(void *p, size_t size)
 {
--- a/js/src/gc/Root.h
+++ b/js/src/gc/Root.h
@@ -369,24 +369,62 @@ class Rooted : public RootedBase<T>
         this->prev = *stack;
         *stack = this;
 
         JS_ASSERT(!RootMethods<T>::poisoned(ptr));
 #endif
     }
 
   public:
-    Rooted() : ptr(RootMethods<T>::initial()) { init(JS::TlsRuntime); }
-    Rooted(const T &initial) : ptr(initial) { init(JS::TlsRuntime); }
+    Rooted(MOZ_GUARD_OBJECT_NOTIFIER_ONLY_PARAM)
+      : ptr(RootMethods<T>::initial())
+    {
+        MOZ_GUARD_OBJECT_NOTIFIER_INIT;
+        init(JS::TlsRuntime);
+    }
+
+    Rooted(const T &initial
+           MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
+      : ptr(initial)
+    {
+        MOZ_GUARD_OBJECT_NOTIFIER_INIT;
+        init(JS::TlsRuntime);
+    }
+
+    Rooted(JSRuntime *rt
+           MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
+      : ptr(RootMethods<T>::initial())
+    {
+        MOZ_GUARD_OBJECT_NOTIFIER_INIT;
+        init(rt);
+    }
 
-    Rooted(JSRuntime *rt) : ptr(RootMethods<T>::initial()) { init(rt); }
-    Rooted(JSRuntime *rt, T initial) : ptr(initial) { init(rt); }
+    Rooted(JSRuntime *rt, T initial
+           MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
+      : ptr(initial)
+    {
+        MOZ_GUARD_OBJECT_NOTIFIER_INIT;
+        init(rt);
+    }
 
-    Rooted(JSContext *cx) : ptr(RootMethods<T>::initial()) { init(cx); }
-    Rooted(JSContext *cx, T initial) : ptr(initial) { init(cx); }
+    Rooted(JSContext *cx
+           MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
+      : ptr(RootMethods<T>::initial())
+    {
+        MOZ_GUARD_OBJECT_NOTIFIER_INIT;
+        init(cx);
+    }
+
+    Rooted(JSContext *cx, T initial
+           MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
+      : ptr(initial)
+    {
+        MOZ_GUARD_OBJECT_NOTIFIER_INIT;
+        init(cx);
+    }
 
     ~Rooted()
     {
 #if defined(JSGC_ROOT_ANALYSIS) || defined(JSGC_USE_EXACT_ROOTING)
         JS_ASSERT(*stack == this);
         *stack = prev;
 #endif
     }
@@ -415,16 +453,17 @@ class Rooted : public RootedBase<T>
         return ptr;
     }
 
   private:
 #if defined(JSGC_ROOT_ANALYSIS) || defined(JSGC_USE_EXACT_ROOTING)
     Rooted<T> **stack, *prev;
 #endif
     T ptr;
+    MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
 
     Rooted(const Rooted &) MOZ_DELETE;
 };
 
 template<typename T> template <typename S>
 inline
 Handle<T>::Handle(Rooted<S> &root,
                   typename mozilla::EnableIf<mozilla::IsConvertible<S, T>::value, int>::Type dummy)
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/basic/bug787847.js
@@ -0,0 +1,22 @@
+var g = true;
+
+function getown(name)
+{
+    if (g)
+	return { value: 8, enumerable: true, writable: false, configurable: true };
+}
+
+var p = Proxy.create( { getPropertyDescriptor: getown } );
+var o2 = Object.create(p);
+
+function test(x, expected) {
+    for (var i=0; i<3; i++) {
+	var v = x.hello;
+	if (g) assertEq(v, 8);
+    }
+}
+
+g = false
+test(o2);
+g = true;
+test(o2);
--- a/js/src/jsreflect.cpp
+++ b/js/src/jsreflect.cpp
@@ -3095,21 +3095,21 @@ ASTSerializer::identifier(ParseNode *pn,
     LOCAL_ASSERT(pn->pn_atom);
 
     return identifier(pn->pn_atom, &pn->pn_pos, dst);
 }
 
 bool
 ASTSerializer::function(ParseNode *pn, ASTType type, Value *dst)
 {
-    JSFunction *func = (JSFunction *)pn->pn_funbox->object;
+    JSFunction *func = pn->pn_funbox->fun();
 
     bool isGenerator =
 #if JS_HAS_GENERATORS
-        pn->pn_funbox->funIsGenerator();
+        pn->pn_funbox->isGenerator();
 #else
         false;
 #endif
 
     bool isExpression =
 #if JS_HAS_EXPR_CLOSURES
         func->flags & JSFUN_EXPR_CLOSURE;
 #else
--- a/js/src/jsscript.cpp
+++ b/js/src/jsscript.cpp
@@ -1633,17 +1633,17 @@ JSScript::fullyInitFromEmitter(JSContext
                        bce->objectList.length, bce->regexpList.length, bce->tryNoteList.length(),
                        bce->constList.length(), bce->typesetCount))
         return false;
 
     JS_ASSERT(script->mainOffset == 0);
     script->mainOffset = prologLength;
     PodCopy<jsbytecode>(script->code, bce->prologBase(), prologLength);
     PodCopy<jsbytecode>(script->main(), bce->base(), mainLength);
-    uint32_t nfixed = bce->sc->inFunction() ? script->bindings.numVars() : 0;
+    uint32_t nfixed = bce->sc->isFunction ? script->bindings.numVars() : 0;
     JS_ASSERT(nfixed < SLOTNO_LIMIT);
     script->nfixed = uint16_t(nfixed);
     InitAtomMap(cx, bce->atomIndices.getMap(), script->atoms);
 
     const char *filename = bce->parser->tokenStream.getFilename();
     if (filename) {
         script->filename = SaveScriptFilename(cx, filename);
         if (!script->filename)
@@ -1651,54 +1651,55 @@ JSScript::fullyInitFromEmitter(JSContext
     }
     script->lineno = bce->firstLine;
     if (script->nfixed + bce->maxStackDepth >= JS_BIT(16)) {
         bce->reportError(NULL, JSMSG_NEED_DIET, "script");
         return false;
     }
     script->nslots = script->nfixed + bce->maxStackDepth;
 
+    FunctionBox *funbox = bce->sc->isFunction ? bce->sc->asFunbox() : NULL;
+
     if (!FinishTakingSrcNotes(cx, bce, script->notes()))
         return false;
     if (bce->tryNoteList.length() != 0)
         bce->tryNoteList.finish(script->trynotes());
     if (bce->objectList.length != 0)
         bce->objectList.finish(script->objects());
     if (bce->regexpList.length != 0)
         bce->regexpList.finish(script->regexps());
     if (bce->constList.length() != 0)
         bce->constList.finish(script->consts());
     script->strictModeCode = bce->sc->inStrictMode();
     script->explicitUseStrict = bce->sc->hasExplicitUseStrict();
     script->bindingsAccessedDynamically = bce->sc->bindingsAccessedDynamically();
-    script->funHasExtensibleScope =
-        bce->sc->inFunction() ? bce->sc->funHasExtensibleScope() : false;
+    script->funHasExtensibleScope = funbox ? funbox->hasExtensibleScope() : false;
     script->hasSingletons = bce->hasSingletons;
 #ifdef JS_METHODJIT
     if (cx->compartment->debugMode())
         script->debugMode = true;
 #endif
 
-    if (bce->sc->inFunction()) {
-        if (bce->sc->funArgumentsHasLocalBinding()) {
+    if (funbox) {
+        if (funbox->argumentsHasLocalBinding()) {
             // This must precede the script->bindings.transfer() call below
             script->setArgumentsHasVarBinding();
-            if (bce->sc->funDefinitelyNeedsArgsObj())
+            if (funbox->definitelyNeedsArgsObj())
                 script->setNeedsArgsObj(true);
         } else {
-            JS_ASSERT(!bce->sc->funDefinitelyNeedsArgsObj());
+            JS_ASSERT(!funbox->definitelyNeedsArgsObj());
         }
     }
 
     RootedFunction fun(cx, NULL);
-    if (bce->sc->inFunction()) {
+    if (funbox) {
         JS_ASSERT(!bce->script->noScriptRval);
-        script->isGenerator = bce->sc->funIsGenerator();
-        script->isGeneratorExp = bce->sc->funbox()->inGenexpLambda;
-        script->setFunction(bce->sc->funbox()->fun());
+        script->isGenerator = funbox->isGenerator();
+        script->isGeneratorExp = funbox->inGenexpLambda;
+        script->setFunction(funbox->fun());
     }
 
     /*
      * initScriptCounts updates scriptCountsMap if necessary. The other script
      * maps in JSCompartment are populated lazily.
      */
     if (cx->hasRunOption(JSOPTION_PCCOUNT))
         (void) script->initScriptCounts(cx);
--- a/js/src/methodjit/PolyIC.cpp
+++ b/js/src/methodjit/PolyIC.cpp
@@ -697,18 +697,22 @@ struct GetPropHelper {
             if (obj->getClass()->getProperty && obj->getClass()->getProperty != JS_PropertyStub)
                 return Lookup_Uncacheable;
 
             /*
              * Don't generate missing property ICs if we skipped a non-native
              * object, as lookups may extend beyond the prototype chain (e.g.
              * for ListBase proxies).
              */
-            if (!obj->isNative())
-                return Lookup_Uncacheable;
+            JSObject *obj2 = obj;
+            while (obj2) {
+                if (!obj2->isNative())
+                    return Lookup_Uncacheable;
+                obj2 = obj2->getProto();
+            }
 
 #if JS_HAS_NO_SUCH_METHOD
             /*
              * The __noSuchMethod__ hook may substitute in a valid method.
              * Since, if o.m is missing, o.m() will probably be an error,
              * just mark all missing callprops as uncacheable.
              */
             if (*f.pc() == JSOP_CALLPROP)
--- a/layout/base/nsCSSFrameConstructor.cpp
+++ b/layout/base/nsCSSFrameConstructor.cpp
@@ -114,16 +114,17 @@
 #include "nsMathMLParts.h"
 #include "nsIDOMSVGFilters.h"
 #include "DOMSVGTests.h"
 #include "nsSVGEffects.h"
 #include "nsSVGUtils.h"
 
 #include "nsRefreshDriver.h"
 #include "nsRuleProcessorData.h"
+#include "sampler.h"
 
 using namespace mozilla;
 using namespace mozilla::dom;
 
 // An alias for convenience.
 static const nsIFrame::ChildListID kPrincipalList = nsIFrame::kPrincipalList;
 
 nsIFrame*
@@ -8007,16 +8008,18 @@ nsresult
 nsCSSFrameConstructor::ProcessRestyledFrames(nsStyleChangeList& aChangeList)
 {
   NS_ASSERTION(!nsContentUtils::IsSafeToRunScript(),
                "Someone forgot a script blocker");
   int32_t count = aChangeList.Count();
   if (!count)
     return NS_OK;
 
+  SAMPLE_LABEL("CSS", "ProcessRestyledFrames");
+
   // Make sure to not rebuild quote or counter lists while we're
   // processing restyles
   BeginUpdate();
 
   nsPresContext* presContext = mPresShell->GetPresContext();
   FramePropertyTable* propTable = presContext->PropertyTable();
 
   // Mark frames so that we skip frames that die along the way, bug 123049.
--- a/layout/base/nsFrameManager.cpp
+++ b/layout/base/nsFrameManager.cpp
@@ -56,16 +56,17 @@
 #include "nsAutoPtr.h"
 #include "imgIRequest.h"
 #include "nsTransitionManager.h"
 #include "RestyleTracker.h"
 #include "nsAbsoluteContainingBlock.h"
 
 #include "nsFrameManager.h"
 #include "nsRuleProcessorData.h"
+#include "sampler.h"
 
 #ifdef ACCESSIBILITY
 #include "nsAccessibilityService.h"
 #endif
 
   #ifdef DEBUG
     //#define NOISY_DEBUG
     //#define DEBUG_UNDISPLAYED_MAP
@@ -1641,16 +1642,18 @@ nsFrameManager::ReResolveStyleContext(ns
 
 void
 nsFrameManager::ComputeStyleChangeFor(nsIFrame          *aFrame, 
                                       nsStyleChangeList *aChangeList,
                                       nsChangeHint       aMinChange,
                                       RestyleTracker&    aRestyleTracker,
                                       bool               aRestyleDescendants)
 {
+  SAMPLE_LABEL("CSS", "ComputeStyleChangeFor");
+
   nsIContent *content = aFrame->GetContent();
   if (aMinChange) {
     aChangeList->AppendChange(aFrame, content, aMinChange);
   }
 
   nsChangeHint topLevelChange = aMinChange;
 
   nsIFrame* frame = aFrame;
new file mode 100644
--- /dev/null
+++ b/layout/reftests/box-properties/box-sizing-mozbox-minmax-height-ref.html
@@ -0,0 +1,54 @@
+<!DOCTYPE HTML>
+<html><head>
+    <meta charset="utf-8">
+    <title>Testcase for bug 789824</title>
+    <style type="text/css">
+
+        html,body {
+            color:black; background-color:white; font-size:24px; padding:0; margin:0;
+        }
+	
+div { padding:5px; }
+
+hbox {
+  display:-moz-box;
+  border-top:3px solid;
+  border-bottom:2px solid;
+  padding-bottom:4px;
+  background:lime;
+
+  box-sizing:content-box;
+  -moz-box-sizing:content-box;
+}
+
+.cb {
+  background:pink;
+  box-sizing:border-box;
+  -moz-box-sizing:border-box;
+}
+
+.pb {
+  background:cyan;
+}
+
+    </style>
+</head>
+<body>
+
+
+<div><hbox style="height:11px;">border-box 20px</hbox></div>
+<div><hbox style="height:41px;">border-box 50px</hbox></div>
+<div><hbox style="height:11px;">border-box 20px</hbox></div>
+
+<div><hbox class="cb" style="height:29px;">content-box 20px</hbox></div>
+<div><hbox class="cb" style="height:59px;">content-box 50px</hbox></div>
+<div><hbox class="cb" style="height:29px;">content-box 20px</hbox></div>
+
+
+<div><hbox class="pb" style="height:16px;">padding-box 20px</hbox></div>
+<div><hbox class="pb" style="height:46px;">padding-box 50px</hbox></div>
+<div><hbox class="pb" style="height:16px;">padding-box 20px</hbox></div>
+
+
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/box-properties/box-sizing-mozbox-minmax-height.html
@@ -0,0 +1,56 @@
+<!DOCTYPE HTML>
+<html><head>
+    <meta charset="utf-8">
+    <title>Testcase for bug 789824</title>
+    <style type="text/css">
+
+        html,body {
+            color:black; background-color:white; font-size:24px; padding:0; margin:0;
+        }
+	
+div { padding:5px; }
+
+hbox {
+  display:-moz-box;
+  border-top:3px solid;
+  border-bottom:2px solid;
+  padding-bottom:4px;
+  height:auto;
+  box-sizing:border-box;
+  -moz-box-sizing:border-box;
+  background:lime;
+}
+
+.cb {
+  box-sizing:content-box;
+  -moz-box-sizing:content-box;
+  background:pink;
+}
+
+.pb {
+  box-sizing:padding-box;
+  -moz-box-sizing:padding-box;
+  background:cyan;
+}
+
+    </style>
+</head>
+<body>
+
+
+<div><hbox style="height:20px;">border-box 20px</hbox></div>
+<div><hbox style="min-height:50px;">border-box 50px</hbox></div>
+<div><hbox style="max-height:20px;">border-box 20px</hbox></div>
+
+<div><hbox class="cb" style="height:20px;">content-box 20px</hbox></div>
+<div><hbox class="cb" style="min-height:50px;">content-box 50px</hbox></div>
+<div><hbox class="cb" style="max-height:20px;">content-box 20px</hbox></div>
+
+
+<div><hbox class="pb" style="height:20px;">padding-box 20px</hbox></div>
+<div><hbox class="pb" style="min-height:50px;">padding-box 50px</hbox></div>
+<div><hbox class="pb" style="max-height:20px;">padding-box 20px</hbox></div>
+
+
+</body>
+</html>
--- a/layout/reftests/box-properties/reftest.list
+++ b/layout/reftests/box-properties/reftest.list
@@ -13,16 +13,17 @@
 == width-special-values-cell-auto.html width-special-values-cell-auto-ref.html
 == width-special-values-cell-fixed.html width-special-values-cell-fixed-ref.html
 == box-sizing-1.html box-sizing-1-ref.html
 == box-sizing-2.html box-sizing-2-ref.html
 == box-sizing-3.html box-sizing-1-ref.html
 == box-sizing-4.html box-sizing-4-ref.html
 == box-sizing-minmax-height.html box-sizing-minmax-height-ref.html
 == box-sizing-minmax-width.html box-sizing-minmax-width-ref.html
+== box-sizing-mozbox-minmax-height.html box-sizing-mozbox-minmax-height-ref.html
 == abspos-non-replaced-width-offset-margin.html abspos-non-replaced-width-offset-margin-ref.html
 == abspos-replaced-width-offset-margin.html abspos-replaced-width-offset-margin-ref.html
 HTTP(..) == CSS21-t100301.xhtml CSS21-t100301-ref.xhtml
 random-if(bug685516) == CSS21-t100303.xhtml CSS21-t100303-ref.xhtml
 random-if(bug685516) == CSS21-t100303-simple.xhtml CSS21-t100303-ref.xhtml
 random-if(bug685516) == CSS21-t100801-vertical-align.xhtml CSS21-t100801-vertical-align-ref.xhtml
 == clip-auto.html clip-auto-ref.html
 == clip-rect-auto.html clip-rect-auto-ref.html
new file mode 100644
--- /dev/null
+++ b/layout/reftests/table-width/colspan-distribute-to-empty-2-ref.html
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<table width="250" cellpadding="0" border="0" cellspacing="0">
+<tr>
+<td width="50" bgcolor=yellow>50
+<td width="180" bgcolor=aqua>This is a cell with enough text in it to wrap.
+<td width="20" bgcolor=lime><span style="display:inline-block"></span>
+</table>
+<table width="250" cellpadding="0" border="0" cellspacing="0">
+<tr>
+<td width="180" bgcolor=fuchsia>This is a cell with enough text in it to wrap.
+<td width="50" bgcolor=yellow>50
+<td width="20" bgcolor=lime><span style="display:inline-block"></span>
+</table>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/table-width/colspan-distribute-to-empty-2.html
@@ -0,0 +1,11 @@
+<!DOCTYPE html>
+<table width="250" cellpadding="0" border="0" cellspacing="0">
+<tr>
+<td width="50" bgcolor=yellow>50
+<td colspan="2" bgcolor=aqua>This is a cell with enough text in it to wrap.
+<td bgcolor=lime><span style="display:inline-block; width: 20px"></span>
+<tr>
+<td colspan="2" bgcolor=fuchsia>This is a cell with enough text in it to wrap.
+<td width="50" bgcolor=yellow>50
+<td bgcolor=lime><span style="display:inline-block; width: 20px"></span>
+</table>
--- a/layout/reftests/table-width/reftest.list
+++ b/layout/reftests/table-width/reftest.list
@@ -57,8 +57,9 @@ fails == default-box-sizing-collapse-qui
 == colgroup-vs-column-1.html colgroup-vs-column-1-ref.html
 == colgroup-vs-column-2.html colgroup-vs-column-2-ref.html
 == colgroup-vs-column-3.html colgroup-vs-column-3-ref.html
 == colgroup-vs-column-4.html colgroup-vs-column-4-ref.html
 == dynamic-fixed-layout-1.html dynamic-fixed-layout-1-ref.html
 == cell-pref-width-border-box.html cell-pref-width-border-box-ref.html
 == colspan-distribute-to-empty-1a.html colspan-distribute-to-empty-1-ref.html
 == colspan-distribute-to-empty-1b.html colspan-distribute-to-empty-1-ref.html
+== colspan-distribute-to-empty-2.html colspan-distribute-to-empty-2-ref.html
new file mode 100644
--- /dev/null
+++ b/layout/style/crashtests/788836.html
@@ -0,0 +1,3 @@
+<style>@\</style>
+<style>@\
+</style>
--- a/layout/style/crashtests/crashtests.list
+++ b/layout/style/crashtests/crashtests.list
@@ -72,8 +72,9 @@ load 611922-1.html
 load 665209-1.html
 asserts(2) load 671799-1.html
 asserts(2) load 671799-2.html
 load 690990-1.html
 load 696188-1.html
 load 700116.html
 load 729126-1.html
 load 729126-2.html
+load 788836.html
--- a/layout/style/nsCSSScanner.cpp
+++ b/layout/style/nsCSSScanner.cpp
@@ -723,23 +723,17 @@ nsCSSScanner::Next(nsCSSToken& aToken)
       return ParseURange(ch, aToken);
 
     // IDENT
     if (StartsIdent(ch, Peek()))
       return ParseIdent(ch, aToken);
 
     // AT_KEYWORD
     if (ch == '@') {
-      int32_t nextChar = Read();
-      if (nextChar >= 0) {
-        int32_t followingChar = Peek();
-        Pushback(nextChar);
-        if (StartsIdent(nextChar, followingChar))
-          return ParseAtKeyword(ch, aToken);
-      }
+      return ParseAtKeyword(aToken);
     }
 
     // NUMBER or DIM
     if ((ch == '.') || (ch == '+') || (ch == '-')) {
       int32_t nextChar = Peek();
       if (IsDigit(nextChar)) {
         return ParseNumber(ch, aToken);
       }
@@ -1023,18 +1017,18 @@ nsCSSScanner::ParseAndAppendEscape(nsStr
  */
 bool
 nsCSSScanner::GatherIdent(int32_t aChar, nsString& aIdent)
 {
   if (aChar == '\\') {
     if (!ParseAndAppendEscape(aIdent, false)) {
       return false;
     }
-  }
-  else if (0 < aChar) {
+  } else {
+    MOZ_ASSERT(aChar > 0);
     aIdent.Append(aChar);
   }
   for (;;) {
     // If nothing in pushback, first try to get as much as possible in one go
     if (!mPushbackCount && mOffset < mCount) {
       // See how much we can consume and append in one go
       uint32_t n = mOffset;
       // Count number of Ident characters that can be processed
@@ -1060,16 +1054,17 @@ nsCSSScanner::GatherIdent(int32_t aChar,
       }
     } else if (IsIdent(aChar)) {
       aIdent.Append(PRUnichar(aChar));
     } else {
       Pushback(aChar);
       break;
     }
   }
+  MOZ_ASSERT(aIdent.Length() > 0);
   return true;
 }
 
 bool
 nsCSSScanner::ParseRef(int32_t aChar, nsCSSToken& aToken)
 {
   // Fall back for when we don't have name characters following:
   aToken.mType = eCSSToken_Symbol;
@@ -1119,24 +1114,31 @@ nsCSSScanner::ParseIdent(int32_t aChar, 
     }
   }
 
   aToken.mType = tokenType;
   return true;
 }
 
 bool
-nsCSSScanner::ParseAtKeyword(int32_t aChar, nsCSSToken& aToken)
+nsCSSScanner::ParseAtKeyword(nsCSSToken& aToken)
 {
-  aToken.mIdent.SetLength(0);
-  aToken.mType = eCSSToken_AtKeyword;
-  if (!GatherIdent(0, aToken.mIdent)) {
-    aToken.mType = eCSSToken_Symbol;
-    aToken.mSymbol = PRUnichar('@');
+  int32_t ch = Read();
+  if (StartsIdent(ch, Peek())) {
+    aToken.mIdent.SetLength(0);
+    aToken.mType = eCSSToken_AtKeyword;
+    if (GatherIdent(ch, aToken.mIdent)) {
+      return true;
+    }
   }
+  if (ch >= 0) {
+    Pushback(ch);
+  }
+  aToken.mType = eCSSToken_Symbol;
+  aToken.mSymbol = PRUnichar('@');
   return true;
 }
 
 bool
 nsCSSScanner::ParseNumber(int32_t c, nsCSSToken& aToken)
 {
   NS_PRECONDITION(c == '.' || c == '+' || c == '-' || IsDigit(c),
                   "Why did we get called?");
--- a/layout/style/nsCSSScanner.h
+++ b/layout/style/nsCSSScanner.h
@@ -182,17 +182,17 @@ protected:
   int32_t Read();
   int32_t Peek();
   bool LookAhead(PRUnichar aChar);
   bool LookAheadOrEOF(PRUnichar aChar); // expect either aChar or EOF
   void EatWhiteSpace();
 
   bool ParseAndAppendEscape(nsString& aOutput, bool aInString);
   bool ParseIdent(int32_t aChar, nsCSSToken& aResult);
-  bool ParseAtKeyword(int32_t aChar, nsCSSToken& aResult);
+  bool ParseAtKeyword(nsCSSToken& aResult);
   bool ParseNumber(int32_t aChar, nsCSSToken& aResult);
   bool ParseRef(int32_t aChar, nsCSSToken& aResult);
   bool ParseString(int32_t aChar, nsCSSToken& aResult);
   bool ParseURange(int32_t aChar, nsCSSToken& aResult);
   bool SkipCComment();
 
   bool GatherIdent(int32_t aChar, nsString& aIdent);
 
--- a/layout/style/test/flexbox_layout_testcases.js
+++ b/layout/style/test/flexbox_layout_testcases.js
@@ -15,20 +15,25 @@
  *  (a) the property's specified value
  *  ...or...
  *  (b) an array with 2 entries: [specifiedValue, expectedComputedValue] if the
  *      property's computed value is intended to be checked. The first entry
  *      (for the specified value) may be null; this means that no value should
  *      be explicitly specified for this property.
  *
  * To allow these testcases to be re-used in both horizontal and vertical
- * flex containers, we specify "width"/"min-width"/etc. as "_main-size",
- * "_min-main-size", etc.  The test code can map these placeholder names to
- * their corresponding property-names using the maps defined below --
- * gHorizontalPropertyMapping and gVerticalPropertyMapping.
+ * flex containers, we specify "width"/"min-width"/etc. using the aliases
+ * "_main-size", "_min-main-size", etc.  The test code can map these
+ * placeholder names to their corresponding property-names using the maps
+ * defined below -- gRowPropertyMapping, gColumnPropertyMapping, etc.
+ *
+ * If the testcase needs to customize its flex container at all (e.g. by
+ * specifying a custom container-size), it can do so by including a hash
+ * called "container_properties", with propertyName:propertyValue mappings.
+ * (This hash can use aliased property-names like "_main-size" as well.)
  */
 
 // The standard main-size we'll use for our flex container when setting up
 // the testcases defined below:
 var gDefaultFlexContainerSize = "200px";
 
 // Left-to-right versions of placeholder property-names used in
 // testcases below:
@@ -291,16 +296,189 @@ var gFlexboxTestcases =
        },
        {
          "-moz-flex": "99999999999999999999999999999999999",
          "_main-size": [ null,  "50px" ]
        },
      ]
  },
 
+ // And now, some testcases to check that we handle float accumulation error
+ // gracefully.
+
+ // First, a testcase with just a custom-sized huge container, to be sure we'll
+ // be able to handle content on that scale, in the subsequent more-complex
+ // testcases:
+ {
+   container_properties:
+   {
+     "_main-size": "9000000px"
+   },
+   items:
+     [
+       {
+         "-moz-flex": "1",
+         "_main-size": [ null,  "9000000px" ]
+       },
+     ]
+ },
+ // ...and now with two flex items dividing up that container's huge size:
+ {
+   container_properties:
+   {
+     "_main-size": "9000000px"
+   },
+   items:
+     [
+       {
+         "-moz-flex": "2",
+         "_main-size": [ null,  "6000000px" ]
+       },
+       {
+         "-moz-flex": "1",
+         "_main-size": [ null,  "3000000px" ]
+       },
+     ]
+ },
+
+ // OK, now to actually test accumulation error. Below, we have six flex items
+ // splitting up the container's size, with huge differences between flex
+ // weights.  For simplicity, I've set up the weights so that they sum exactly
+ // to the container's size in px. So 1 unit of flex *should* get you 1px.
+ //
+ // NOTE: The expected computed "_main-size" values for the flex items below
+ // appear to add up to more than their container's size, which would suggest
+ // that they overflow their container unnecessarily. But they don't actually
+ // overflow -- this discrepancy is simply because Gecko's code for reporting
+ // computed-sizes rounds to 6 significant figures (in particular, the method
+ // (nsTSubstring_CharT::AppendFloat() does this).  Internally, in app-units,
+ // the child frames' main-sizes add up exactly to the container's main-size,
+ // as you'd hope & expect.
+ {
+   container_properties:
+   {
+     "_main-size": "9000000px"
+   },
+   items:
+     [
+       {
+         "-moz-flex": "3000000",
+         "_main-size": [ null,  "3000000px" ]
+       },
+       {
+         "-moz-flex": "1",
+         "_main-size": [ null,  "1px" ]
+       },
+       {
+         "-moz-flex": "1",
+         "_main-size": [ null,  "1px" ]
+       },
+       {
+         "-moz-flex": "2999999",
+         // NOTE: Expected value is off slightly, from float error when
+         // resolving flexible lengths & when generating computed value string:
+         "_main-size": [ null,  "3000000px" ]
+       },
+       {
+         "-moz-flex": "2999998",
+         // NOTE: Expected value is off slightly, from float error when
+         // resolving flexible lengths & when generating computed value string:
+         "_main-size": [ null,  "3000000px" ]
+       },
+       {
+         "-moz-flex": "1",
+         "_main-size": [ null,  "1px" ]
+       },
+     ]
+ },
+ // Same flex items as previous testcase, but now reordered such that the items
+ // with tiny flex weights are all listed last:
+ {
+   container_properties:
+   {
+     "_main-size": "9000000px"
+   },
+   items:
+     [
+       {
+         "-moz-flex": "3000000",
+         "_main-size": [ null,  "3000000px" ]
+       },
+       {
+         "-moz-flex": "2999999",
+         // NOTE: Expected value is off slightly, from float error when
+         // resolving flexible lengths & when generating computed value string:
+         "_main-size": [ null,  "3000000px" ]
+       },
+       {
+         "-moz-flex": "2999998",
+         // NOTE: Expected value is off slightly, from float error when
+         // resolving flexible lengths & when generating computed value string:
+         "_main-size": [ null,  "3000000px" ]
+       },
+       {
+         "-moz-flex": "1",
+         "_main-size": [ null,  "1px" ]
+       },
+       {
+         "-moz-flex": "1",
+         "_main-size": [ null,  "1px" ]
+       },
+       {
+         "-moz-flex": "1",
+         "_main-size": [ null,  "1px" ]
+       },
+     ]
+ },
+ // Same flex items as previous testcase, but now reordered such that the items
+ // with tiny flex weights are all listed first:
+ {
+   container_properties:
+   {
+     "_main-size": "9000000px"
+   },
+   items:
+     [
+       {
+         "-moz-flex": "1",
+         // NOTE: Expected value is off slightly, from float error when
+         // resolving flexible lengths:
+         "_main-size": [ null,  "0.966667px" ]
+       },
+       {
+         "-moz-flex": "1",
+         // NOTE: Expected value is off slightly, from float error when
+         // resolving flexible lengths:
+         "_main-size": [ null,  "0.983333px" ]
+       },
+       {
+         "-moz-flex": "1",
+         // NOTE: Expected value is off slightly, from float error when
+         // resolving flexible lengths:
+         "_main-size": [ null,  "0.983333px" ]
+       },
+       {
+         "-moz-flex": "3000000",
+         "_main-size": [ null,  "3000000px" ]
+       },
+       {
+         "-moz-flex": "2999999",
+         // NOTE: Expected value is off slightly, from float error when
+         // resolving flexible lengths & when generating computed value string:
+         "_main-size": [ null,  "3000000px" ]
+       },
+       {
+         "-moz-flex": "2999998",
+         // NOTE: Expected value is off slightly, from float error when
+         // resolving flexible lengths & when generating computed value string:
+         "_main-size": [ null,  "3000000px" ]
+       },
+     ]
+ },
+
  // Trying "flex: auto" (== "1 1 auto") w/ a mix of flex-grow/flex-basis values
  {
    items:
      [
        {
          "-moz-flex": "auto",
          "_main-size": [ null, "45px" ]
        },
--- a/layout/style/test/test_flexbox_layout.html
+++ b/layout/style/test/test_flexbox_layout.html
@@ -32,29 +32,51 @@ https://bugzilla.mozilla.org/show_bug.cg
 
 SimpleTest.waitForExplicitFinish();
 
 function getComputedStyleWrapper(elem, prop)
 {
   return window.getComputedStyle(elem, null).getPropertyValue(prop);
 }
 
+function setPossiblyAliasedProperty(aElem, aPropertyName, aPropertyValue,
+                                    aPropertyMapping)
+{
+  let actualPropertyName = (aPropertyName in aPropertyMapping ?
+                            aPropertyMapping[aPropertyName] : aPropertyName);
+
+  if (!gCSSProperties[actualPropertyName]) {
+    ok(false, "Bug in test: property '" + actualPropertyName +
+              "' doesn't exist in gCSSProperties");
+  } else {
+    let domPropertyName = gCSSProperties[actualPropertyName].domProp;
+    aElem.style[domPropertyName] = aPropertyValue;
+  }
+}
+
 // The main test function.
 // aFlexboxTestcase is an entry from the list in flexbox_layout_testcases.js
 function testFlexboxTestcase(aFlexboxTestcase, aFlexDirection, aPropertyMapping)
 {
   let content = document.getElementById("content");
 
   // Create flex container
   let flexContainer = document.createElement("div");
   flexContainer.style.display = "-moz-flex";
+  flexContainer.style.MozFlexDirection = aFlexDirection;
+  setPossiblyAliasedProperty(flexContainer, "_main-size", gDefaultFlexContainerSize, aPropertyMapping);
 
-  flexContainer.style[aPropertyMapping["_main-size"]] = gDefaultFlexContainerSize;
-
-  flexContainer.style.MozFlexDirection = aFlexDirection;
+  // Apply testcase's customizations for flex container (if any).
+  if (aFlexboxTestcase.container_properties) {
+    for (let propName in aFlexboxTestcase.container_properties) {
+      let propValue = aFlexboxTestcase.container_properties[propName];
+      setPossiblyAliasedProperty(flexContainer, propName, propValue,
+                                 aPropertyMapping);
+    }
+  }
 
   // Create & append flex items
   aFlexboxTestcase.items.forEach(function(aChildSpec) {
     // Create an element for our item
     let child = document.createElement("div");
 
     // Set all the specified properties on our item
     for (let propName in aChildSpec) {
@@ -65,24 +87,19 @@ function testFlexboxTestcase(aFlexboxTes
         aChildSpec[propName];
 
       // SANITY CHECK:
       if (Array.isArray(aChildSpec[propName])) {
         is(aChildSpec[propName].length, 2,
            "unexpected number of elements in array within child spec");
       }
 
-      let actualPropName = (propName in aPropertyMapping ?
-                            aPropertyMapping[propName] : propName);
-      if (!gCSSProperties[actualPropName]) {
-        ok(false, "Bug in test: property '" + actualPropName +
-                  "' doesn't exist in gCSSProperties");
-      } else if (specifiedValue !== null) {
-        let domPropName = gCSSProperties[actualPropName].domProp;
-        child.style[domPropName] = specifiedValue;
+      if (specifiedValue !== null) {
+        setPossiblyAliasedProperty(child, propName, specifiedValue,
+                                   aPropertyMapping);
       }
     }
 
     // Append the item to the flex container
     flexContainer.appendChild(child);
   });
 
   // Append the flex container
--- a/layout/xul/base/src/nsBoxFrame.cpp
+++ b/layout/xul/base/src/nsBoxFrame.cpp
@@ -670,32 +670,24 @@ nsBoxFrame::Reflow(nsPresContext*       
     prefSize = BoundsCheck(minSize, prefSize, maxSize);
   }
 
   // get our desiredSize
   computedSize.width += m.left + m.right;
 
   if (aReflowState.ComputedHeight() == NS_INTRINSICSIZE) {
     computedSize.height = prefSize.height;
-    // prefSize is border-box, so we need to figure out the right
-    // length to apply our min/max constraints to.
-    nscoord outsideBoxSizing = 0;
-    switch (GetStylePosition()->mBoxSizing) {
-      case NS_STYLE_BOX_SIZING_CONTENT:
-        outsideBoxSizing = aReflowState.mComputedBorderPadding.TopBottom();
-        // fall through
-      case NS_STYLE_BOX_SIZING_PADDING:
-        outsideBoxSizing -= aReflowState.mComputedPadding.TopBottom();
-        break;
-    }
-    computedSize.height -= outsideBoxSizing;
-    // Note: might be negative now, but that's OK because min-width is
-    // never negative.
-    computedSize.height = aReflowState.ApplyMinMaxHeight(computedSize.height);
-    computedSize.height += outsideBoxSizing;
+    // prefSize is border-box but min/max constraints are content-box.
+    nscoord verticalBorderPadding =
+      aReflowState.mComputedBorderPadding.TopBottom();
+    nscoord contentHeight = computedSize.height - verticalBorderPadding;
+    // Note: contentHeight might be negative, but that's OK because min-height
+    // is never negative.
+    computedSize.height = aReflowState.ApplyMinMaxHeight(contentHeight) +
+                          verticalBorderPadding;
   } else {
     computedSize.height += m.top + m.bottom;
   }
 
   nsRect r(mRect.x, mRect.y, computedSize.width, computedSize.height);
 
   SetBounds(state, r);
  
copy from mobile/android/config/mozconfigs/android/nightly
copy to mobile/android/config/mozconfigs/android-noion/nightly
new file mode 100644
--- /dev/null
+++ b/python/mozboot/README.rst
@@ -0,0 +1,19 @@
+mozboot - Bootstrap your system to build Mozilla projects
+=========================================================
+
+This package contains code used for bootstrapping a system to build
+mozilla-central.
+
+This code is not part of the build system per se. Instead, it is related
+to everything up to invoking the actual build system.
+
+If you have a copy of the source tree, you run:
+
+    python bin/bootstrap.py
+
+If you don't have a copy of the source tree, you can run:
+
+    curl https://hg.mozilla.org/mozilla-central/raw-file/default/python/mozboot/bin/bootstrap.py | python -
+
+The bootstrap script will download everything it needs from hg.mozilla.org
+automatically!
new file mode 100755
--- /dev/null
+++ b/python/mozboot/bin/bootstrap.py
@@ -0,0 +1,134 @@
+#!/usr/bin/env python
+# 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/.
+
+# This script provides one-line bootstrap support to configure systems to build
+# the tree.
+#
+# The role of this script is to load the Python modules containing actual
+# bootstrap support. It does this through various means, including fetching
+# content from the upstream source repository.
+
+from __future__ import print_function, unicode_literals
+
+import os
+import shutil
+import sys
+import tempfile
+import urllib2
+
+from optparse import OptionParser
+
+# The next two variables define where in the repository the Python files
+# reside. This is used to remotely download file content when it isn't
+# available locally.
+REPOSITORY_PATH_PREFIX = 'python/mozboot'
+
+REPOSITORY_PATHS = [
+    'mozboot/__init__.py',
+    'mozboot/base.py',
+    'mozboot/bootstrap.py',
+    'mozboot/centos.py',
+    'mozboot/fedora.py',
+    'mozboot/mint.py',
+    'mozboot/osx.py',
+    'mozboot/ubuntu.py',
+]
+
+TEMPDIR = None
+
+def fetch_files(repo_url, repo_type):
+    repo_url = repo_url.rstrip('/')
+
+    files = {}
+
+    if repo_type == 'hgweb':
+        for path in REPOSITORY_PATHS:
+            url = repo_url + '/raw-file/default/python/mozboot/' + path
+
+            req = urllib2.urlopen(url=url, timeout=30)
+            files[path] = req.read()
+    else:
+        raise NotImplementedError('Not sure how to handle repo type.', repo_type)
+
+    return files
+
+def ensure_environment(repo_url=None, repo_type=None):
+    """Ensure we can load the Python modules necessary to perform bootstrap."""
+
+    try:
+        from mozboot.bootstrap import Bootstrapper
+        return Bootstrapper
+    except ImportError:
+        # The first fallback is to assume we are running from a tree checkout
+        # and have the files in a sibling directory.
+        pardir = os.path.join(os.path.dirname(__file__), os.path.pardir)
+        include = os.path.normpath(pardir)
+
+        sys.path.append(include)
+        try:
+            from mozboot.bootstrap import Bootstrapper
+            return Bootstrapper
+        except ImportError:
+            sys.path.pop()
+
+            # The next fallback is to download the files from the source
+            # repository.
+            files = fetch_files(repo_url, repo_type)
+
+            # Install them into a temporary location. They will be deleted
+            # after this script has finished executing.
+            global TEMPDIR
+            TEMPDIR = tempfile.mkdtemp()
+
+            for relpath in files.keys():
+                destpath = os.path.join(TEMPDIR, relpath)
+                destdir = os.path.dirname(destpath)
+
+                if not os.path.exists(destdir):
+                    os.makedirs(destdir)
+
+                with open(destpath, 'wb') as fh:
+                    fh.write(files[relpath])
+
+            # This should always work.
+            sys.path.append(TEMPDIR)
+            from mozboot.bootstrap import Bootstrapper
+            return Bootstrapper
+
+def main(args):
+    parser = OptionParser()
+    parser.add_option('-r', '--repo-url', dest='repo_url',
+        default='https://hg.mozilla.org/mozilla-central/',
+        help='Base URL of source control repository where bootstrap files can '
+             'be downloaded.')
+
+    parser.add_option('--repo-type', dest='repo_type',
+        default='hgweb',
+        help='The type of the repository. This defines how we fetch file '
+             'content. Like --repo, you should not need to set this.')
+
+    options, leftover = parser.parse_args(args)
+
+    try:
+        try:
+            cls = ensure_environment(options.repo_url, options.repo_type)
+        except Exception as e:
+            print('Could not load the bootstrap Python environment.\n')
+            print('This should never happen. Consider filing a bug.\n')
+            print('\n')
+            print(e)
+            return 1
+
+        dasboot = cls()
+        dasboot.bootstrap()
+
+        return 0
+    finally:
+        if TEMPDIR is not None:
+            shutil.rmtree(TEMPDIR)
+
+
+if __name__ == '__main__':
+    sys.exit(main(sys.argv))
new file mode 100644
new file mode 100644
--- /dev/null
+++ b/python/mozboot/mozboot/base.py
@@ -0,0 +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/.
+
+class BaseBootstrapper(object):
+    """Base class for system bootstrappers."""
+    def __init__(self):
+        pass
+
+    def install_system_packages(self):
+        raise NotImplemented('%s must implement install_system_packages()' %
+            __name__)
new file mode 100644
--- /dev/null
+++ b/python/mozboot/mozboot/bootstrap.py
@@ -0,0 +1,54 @@
+# 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/.
+
+import platform
+import sys
+
+from mozboot.centos import CentOSBootstrapper
+from mozboot.fedora import FedoraBootstrapper
+from mozboot.mint import MintBootstrapper
+from mozboot.osx import OSXBootstrapper
+from mozboot.ubuntu import UbuntuBootstrapper
+
+
+class Bootstrapper(object):
+    """Main class that performs system bootstrap."""
+
+    def bootstrap(self):
+        cls = None
+        args = {}
+
+        if sys.platform.startswith('linux'):
+            distro, version, dist_id = platform.linux_distribution()
+
+            if distro == 'CentOS':
+                cls = CentOSBootstrapper
+            elif distro == 'Fedora':
+                cls = FedoraBootstrapper
+            elif distro == 'Mint':
+                cls = MintBootstrapper
+            elif distro == 'Ubuntu':
+                cls = UbuntuBootstrapper
+            else:
+                raise NotImplementedError('Bootstrap support for this Linux '
+                                          'distro not yet available.')
+
+            args['version'] = version
+            args['dist_id'] = dist_id
+
+        elif sys.platform.startswith('darwin'):
+            # TODO Support Darwin platforms that aren't OS X.
+            major, minor, point = map(int, platform.mac_ver()[0].split('.'))
+
+            cls = OSXBootstrapper
+            args['major'] = major
+            args['minor'] = minor
+            args['point'] = point
+
+        if cls is None:
+            raise NotImplementedError('Bootstrap support is not yet available '
+                                      'for your OS.')
+
+        instance = cls(**args)
+        instance.install_system_packages()
new file mode 100644
--- /dev/null
+++ b/python/mozboot/mozboot/centos.py
@@ -0,0 +1,30 @@
+# 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/.
+
+import os
+import platform
+
+from mozboot.base import BaseBootstrapper
+
+class CentOSBootstrapper(BaseBootstrapper):
+    def __init__(self, version, dist_id):
+        BaseBootstrapper.__init__(self)
+
+        self.version = version
+        self.dist_id = dist_id
+
+    def install_system_packages(self):
+        kern = platform.uname()
+        os.system("sudo yum groupinstall 'Development Tools' 'Development Libraries' 'GNOME Software Development'")
+        os.system("sudo yum install mercurial autoconf213 glibc-static libstdc++-static yasm wireless-tools-devel mesa-libGL-devel alsa-lib-devel libXt-devel")
+        os.system("sudo yum install gtk2-devel")
+        os.system("sudo yum install dbus-glib-devel")
+
+        if ('x86_64' in kern[2]):
+            os.system("sudo rpm -ivh http://pkgs.repoforge.org/yasm/yasm-1.1.0-1.el6.rf.x86_64.rpm")
+        else:
+            os.system("sudo rpm -ivh http://pkgs.repoforge.org/yasm/yasm-1.1.0-1.el6.rf.i686.rpm")
+
+        os.system("sudo yum install curl-devel")
+
new file mode 100644
--- /dev/null
+++ b/python/mozboot/mozboot/fedora.py
@@ -0,0 +1,18 @@
+# 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/.
+
+import os
+
+from mozboot.base import BaseBootstrapper
+
+class FedoraBootstrapper(BaseBootstrapper):
+    def __init__(self, version, dist_id):
+        BaseBootstrapper.__init__(self)
+
+        self.version = version
+        self.dist_id = dist_id
+
+    def install_system_packages(self):
+        os.system("sudo yum groupinstall 'Development Tools' 'Development Libraries' 'GNOME Software Development'")
+        os.system("sudo yum install mercurial autoconf213 glibc-static libstdc++-static yasm wireless-tools-devel mesa-libGL-devel alsa-lib-devel libXt-devel")
new file mode 100644
--- /dev/null
+++ b/python/mozboot/mozboot/mint.py
@@ -0,0 +1,18 @@
+# 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/.
+
+import os
+
+from mozboot.base import BaseBootstrapper
+
+class MintBootstrapper(BaseBootstrapper):
+    def __init__(self, version, dist_id):
+        BaseBootstrapper.__init__(self)
+
+        self.version = version
+        self.dist_id = dist_id
+
+    def install_system_packages(self):
+        os.system("sudo apt-get build-dep firefox")
+        os.system("sudo apt-get install mercurial libasound2-dev libcurl4-openssl-dev libnotify-dev libxt-dev libiw-dev mesa-common-dev autoconf2.13 yasm uuid")
new file mode 100644
--- /dev/null
+++ b/python/mozboot/mozboot/osx.py
@@ -0,0 +1,17 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this file,
+# You can obtain one at http://mozilla.org/MPL/2.0/.
+
+from mozboot.base import BaseBootstrapper
+
+class OSXBootstrapper(BaseBootstrapper):
+    def __init__(self, major, minor, point):
+        BaseBootstrapper.__init__(self)
+
+        if major == 10 and minor < 6:
+            raise Exception('OS X 10.6 or above is required.')
+
+    def install_system_packages(self):
+        raise NotImplementedError('OS X bootstrap not yet implemented.')
+
+
new file mode 100644
--- /dev/null
+++ b/python/mozboot/mozboot/ubuntu.py
@@ -0,0 +1,18 @@
+# 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/.
+
+import os
+
+from mozboot.base import BaseBootstrapper
+
+class UbuntuBootstrapper(BaseBootstrapper):
+    def __init__(self, version, dist_id):
+        BaseBootstrapper.__init__(self)
+
+        self.version = version
+        self.dist_id = dist_id
+
+    def install_system_packages(self):
+        os.system("sudo apt-get build-dep firefox")
+        os.system("sudo apt-get install mercurial libasound2-dev libcurl4-openssl-dev libnotify-dev libxt-dev libiw-dev mesa-common-dev autoconf2.13 yasm uuid")
new file mode 100644
--- /dev/null
+++ b/python/mozboot/setup.py
@@ -0,0 +1,16 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this file,
+# You can obtain one at http://mozilla.org/MPL/2.0/.
+
+from distutils.core import setup
+
+VERSION = '0.1'
+
+setup(
+    name='mozboot',
+    description='System bootstrap for building Mozilla projects.',
+    license='MPL 2.0',
+    packages=['mozboot'],
+    version=VERSION,
+    scripts=['bin/bootstrap.py'],
+)
--- a/testing/mozbase/manifestdestiny/manifestparser/manifestparser.py
+++ b/testing/mozbase/manifestdestiny/manifestparser/manifestparser.py
@@ -3,19 +3,16 @@
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this file,
 # You can obtain one at http://mozilla.org/MPL/2.0/.
 
 """
 Mozilla universal manifest parser
 """
 
-# this file lives at
-# http://hg.mozilla.org/automation/ManifestDestiny/raw-file/tip/manifestparser.py
-
 __all__ = ['read_ini', # .ini reader
            'ManifestParser', 'TestManifest', 'convert', # manifest handling
            'parse', 'ParseError', 'ExpressionParser'] # conditional expression parser
 
 import os
 import re
 import shutil
 import sys
@@ -431,25 +428,25 @@ class ManifestParser(object):
 
             # otherwise an item
             test = data
             test['name'] = section
             test['manifest'] = os.path.abspath(filename)
 
             # determine the path
             path = test.get('path', section)
-            relpath = path
+            _relpath = path
             if '://' not in path: # don't futz with URLs
                 path = normalize_path(path)
                 if not os.path.isabs(path):
                     path = os.path.join(here, path)
-                relpath = os.path.relpath(path, self.rootdir)
+                _relpath = relpath(path, self.rootdir)
 
             test['path'] = path
-            test['relpath'] = relpath
+            test['relpath'] = _relpath
 
             # append the item
             self.tests.append(test)
 
     def read(self, *filenames, **defaults):
 
         # ensure all files exist
         missing = [ filename for filename in filenames
--- a/testing/mozbase/manifestdestiny/setup.py
+++ b/testing/mozbase/manifestdestiny/setup.py
@@ -9,17 +9,17 @@ import os
 here = os.path.dirname(os.path.abspath(__file__))
 try:
     filename = os.path.join(here, 'README.md')
     description = file(filename).read()
 except:
     description = ''
 
 PACKAGE_NAME = "ManifestDestiny"
-PACKAGE_VERSION = '0.5.5'
+PACKAGE_VERSION = '0.5.6'
 
 setup(name=PACKAGE_NAME,
       version=PACKAGE_VERSION,
       description="Universal manifests for Mozilla test harnesses",
       long_description=description,
       classifiers=[], # Get strings from http://pypi.python.org/pypi?%3Aaction=list_classifiers
       keywords='mozilla manifests',
       author='Mozilla Automation and Testing Team',
old mode 100644
new mode 100755
old mode 100644
new mode 100755
deleted file mode 100644
--- a/testing/mozbase/mozdevice/sut_tests/test_unzip.py
+++ /dev/null
@@ -1,60 +0,0 @@
-# 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/.
-
-import os
-import posixpath
-
-from dmunit import DeviceManagerTestCase
-
-
-class UnzipTestCase(DeviceManagerTestCase):
-
-    def runTest(self):
-        """ This tests unzipping a file on the device.
-        """
-        testroot = posixpath.join(self.dm.getDeviceRoot(), 'infratest')
-        self.dm.removeDir(testroot)
-        self.dm.mkDir(testroot)
-        self.assert_(self.dm.pushFile(
-            os.path.join('test-files', 'mybinary.zip'),
-            posixpath.join(testroot, 'mybinary.zip')))
-        self.assertNotEqual(self.dm.unpackFile(
-            posixpath.join(testroot, 'mybinary.zip')), None)
-        # the mybinary.zip file has the zipped up contents of test-files/push2
-        # so we validate it the same as test_push2.
-        self.assert_(self.dm.dirExists(
-            posixpath.join(testroot, 'push2', 'sub1')))
-        self.assert_(self.dm.validateFile(
-            posixpath.join(testroot, 'push2', 'sub1', 'file1.txt'),
-            os.path.join('test-files', 'push2', 'sub1', 'file1.txt')))
-        self.assert_(self.dm.validateFile(
-            posixpath.join(testroot, 'push2', 'sub1', 'sub1.1', 'file2.txt'),
-            os.path.join('test-files', 'push2', 'sub1', 'sub1.1', 'file2.txt')))
-        self.assert_(self.dm.validateFile(
-            posixpath.join(testroot, 'push2', 'sub2', 'file3.txt'),
-            os.path.join('test-files', 'push2', 'sub2', 'file3.txt')))
-        self.assert_(self.dm.validateFile(
-            posixpath.join(testroot, 'push2', 'file4.bin'),
-            os.path.join('test-files', 'push2', 'file4.bin')))
-
-        # test dest_dir param
-        newdir = posixpath.join(testroot, 'newDir')
-        self.dm.mkDir(newdir)
-
-        self.assertNotEqual(self.dm.unpackFile(
-            posixpath.join(testroot, 'mybinary.zip'), newdir), None)
-
-        self.assert_(self.dm.dirExists(posixpath.join(newdir, 'push2', 'sub1')))
-        self.assert_(self.dm.validateFile(
-            posixpath.join(newdir, 'push2', 'sub1', 'file1.txt'),
-            os.path.join('test-files', 'push2', 'sub1', 'file1.txt')))
-        self.assert_(self.dm.validateFile(
-            posixpath.join(newdir, 'push2', 'sub1', 'sub1.1', 'file2.txt'),
-            os.path.join('test-files', 'push2', 'sub1', 'sub1.1', 'file2.txt')))
-        self.assert_(self.dm.validateFile(
-            posixpath.join(newdir, 'push2', 'sub2', 'file3.txt'),
-            os.path.join('test-files', 'push2', 'sub2', 'file3.txt')))
-        self.assert_(self.dm.validateFile(
-            posixpath.join(newdir, 'push2', 'file4.bin'),
-            os.path.join('test-files', 'push2', 'file4.bin')))
old mode 100644
new mode 100755
old mode 100644
new mode 100755
old mode 100644
new mode 100755
old mode 100644
new mode 100755
old mode 100644
new mode 100755
old mode 100644
new mode 100755
old mode 100644
new mode 100755
old mode 100644
new mode 100755
old mode 100644
new mode 100755
new file mode 100644
new file mode 100644
old mode 100644
new mode 100755
--- a/testing/testsuite-targets.mk
+++ b/testing/testsuite-targets.mk
@@ -323,16 +323,17 @@ endif
 package-tests:
 	@rm -f "$(DIST)/$(PKG_PATH)$(TEST_PACKAGE)"
 ifndef UNIVERSAL_BINARY
 	$(NSINSTALL) -D $(DIST)/$(PKG_PATH)
 else
 	#building tests.jar (bug 543800) fails on unify, so we build tests.jar after unify is run
 	$(MAKE) -C $(DEPTH)/testing/mochitest stage-chromejar PKG_STAGE=$(DIST)/universal
 endif
+	find $(PKG_STAGE) -name "*.pyc" -exec rm {} \;
 	cd $(PKG_STAGE) && \
 	  zip -rq9D "$(call core_abspath,$(DIST)/$(PKG_PATH)$(TEST_PACKAGE))" \
 	  * -x \*/.mkdir.done
 
 ifeq (Android, $(OS_TARGET))
 package-tests: stage-android
 endif
 
--- a/toolkit/components/social/FrameWorker.jsm
+++ b/toolkit/components/social/FrameWorker.jsm
@@ -125,16 +125,23 @@ FrameWorker.prototype = {
       appVersion: workerWindow.navigator.appVersion,
       platform: workerWindow.navigator.platform,
       userAgent: workerWindow.navigator.userAgent,
       // interface NavigatorOnLine
       get onLine() workerWindow.navigator.onLine
     };
     sandbox.navigator = navigator;
 
+    // Our importScripts function needs to 'eval' the script code from inside
+    // a function, but using eval() directly means functions in the script
+    // don't end up in the global scope.
+    sandbox._evalInSandbox = function(s) {
+      Cu.evalInSandbox(s, sandbox);
+    };
+
     // and we delegate ononline and onoffline events to the worker.
     // See http://www.whatwg.org/specs/web-apps/current-work/multipage/workers.html#workerglobalscope
     this.frame.addEventListener('offline', function fw_onoffline(event) {
       Cu.evalInSandbox("onoffline();", sandbox);
     }, false);
     this.frame.addEventListener('online', function fw_ononline(event) {
       Cu.evalInSandbox("ononline();", sandbox);
     }, false);
--- a/toolkit/components/social/MessagePortWorker.js
+++ b/toolkit/components/social/MessagePortWorker.js
@@ -27,17 +27,17 @@ function importScripts() {
   for (var i=0; i < arguments.length; i++) {
     // load the url *synchronously*
     var scriptURL = arguments[i];
     var xhr = new XMLHttpRequest();
     xhr.open('GET', scriptURL, false);
     xhr.onreadystatechange = function(aEvt) {
       if (xhr.readyState == 4) {
         if (xhr.status == 200 || xhr.status == 0) {
-          eval(xhr.responseText);
+          _evalInSandbox(xhr.responseText);
         }
         else {
           throw new Error("Unable to importScripts ["+scriptURL+"], status " + xhr.status)
         }
       }
     };
     xhr.send(null);
   }
--- a/toolkit/components/social/test/browser/relative_import.js
+++ b/toolkit/components/social/test/browser/relative_import.js
@@ -1,1 +1,6 @@
 dump("relative_import file\n");
+
+testVar = "oh hai";
+function testFunc() {
+  return "oh hai";
+}
--- a/toolkit/components/social/test/browser/worker_relative.js
+++ b/toolkit/components/social/test/browser/worker_relative.js
@@ -1,13 +1,18 @@
 // Used to test XHR in the worker.
 onconnect = function(e) {
   let port = e.ports[0];
   let req;
   try {
     importScripts("relative_import.js");
-    port.postMessage({topic: "done", result: "ok"});
+    // the import should have exposed "testVar" and "testFunc" from the module.
+    if (testVar == "oh hai" && testFunc() == "oh hai") {
+      port.postMessage({topic: "done", result: "ok"});
+    } else {
+      port.postMessage({topic: "done", result: "import worked but global is not available"});
+    }
   } catch(e) {
     port.postMessage({topic: "done", result: "FAILED to importScripts, " + e.toString() });
     return;
   }
   port.postMessage({topic: "done", result: "FAILED to importScripts, no exception" });
 }
--- a/toolkit/components/startup/nsAppStartup.cpp
+++ b/toolkit/components/startup/nsAppStartup.cpp
@@ -45,28 +45,51 @@
 #include <windows.h>
 // windows.h can go to hell 
 #undef GetStartupInfo
 #elif defined(XP_UNIX)
 #include <unistd.h>
 #include <sys/syscall.h>
 #endif
 
-#ifdef XP_MACOSX
-#include <sys/sysctl.h>
-#endif
-
-#ifdef __OpenBSD__
+#if defined(XP_MACOSX) || defined(__DragonFly__) || defined(__FreeBSD__) \
+  || defined(__NetBSD__) || defined(__OpenBSD__)
 #include <sys/param.h>
 #include <sys/sysctl.h>
 #endif
 
+#if defined(__DragonFly__) || defined(__FreeBSD__)
+#include <sys/user.h>
+#endif
+
 #include "mozilla/Telemetry.h"
 #include "mozilla/StartupTimeline.h"
 
+#if defined(__NetBSD__)
+#undef KERN_PROC
+#define KERN_PROC KERN_PROC2
+#define KINFO_PROC struct kinfo_proc2
+#else
+#define KINFO_PROC struct kinfo_proc
+#endif
+
+#if defined(XP_MACOSX)
+#define KP_START_SEC kp_proc.p_un.__p_starttime.tv_sec
+#define KP_START_USEC kp_proc.p_un.__p_starttime.tv_usec
+#elif defined(__DragonFly__)
+#define KP_START_SEC kp_start.tv_sec
+#define KP_START_USEC kp_start.tv_usec
+#elif defined(__FreeBSD__)
+#define KP_START_SEC ki_start.tv_sec
+#define KP_START_USEC ki_start.tv_usec
+#else
+#define KP_START_SEC p_ustart_sec
+#define KP_START_USEC p_ustart_usec
+#endif
+
 static NS_DEFINE_CID(kAppShellCID, NS_APPSHELL_CID);
 
 #define kPrefLastSuccess "toolkit.startup.last_success"
 #define kPrefMaxResumedCrashes "toolkit.startup.max_resumed_crashes"
 #define kPrefRecentCrashes "toolkit.startup.recent_crashes"
 
 #if defined(XP_WIN)
 #include "mozilla/perfprobe.h"
@@ -831,52 +854,40 @@ CalculateProcessCreationTimestamp()
   CopyMemory(&timestamp, &start, sizeof(PRTime));
 #ifdef __GNUC__
   timestamp = (timestamp - 116444736000000000LL) / 10LL;
 #else
   timestamp = (timestamp - 116444736000000000i64) / 10i64;
 #endif
   return timestamp;
 }
-#elif defined(XP_MACOSX)
+#elif defined(XP_MACOSX) || defined(__DragonFly__) || defined(__FreeBSD__) \
+  || defined(__NetBSD__) || defined(__OpenBSD__)
 static PRTime
 CalculateProcessCreationTimestamp()
 {
-  int mib[4] = { CTL_KERN, KERN_PROC, KERN_PROC_PID, getpid() };
-  size_t buffer_size;
-  if (sysctl(mib, 4, NULL, &buffer_size, NULL, 0))
+  int mib[] = {
+    CTL_KERN,
+    KERN_PROC,
+    KERN_PROC_PID,
+    getpid(),
+#if defined(__NetBSD__) || defined(__OpenBSD__)
+    sizeof(KINFO_PROC),
+    1,
+#endif
+  };
+  u_int miblen = sizeof(mib) / sizeof(mib[0]);
+
+  KINFO_PROC proc;
+  size_t buffer_size = sizeof(proc);
+  if (sysctl(mib, miblen, &proc, &buffer_size, NULL, 0))
     return 0;
 
-  struct kinfo_proc *proc = (kinfo_proc*) malloc(buffer_size);  
-  if (sysctl(mib, 4, proc, &buffer_size, NULL, 0)) {
-    free(proc);
-    return 0;
-  }
-  PRTime starttime = static_cast<PRTime>(proc->kp_proc.p_un.__p_starttime.tv_sec) * PR_USEC_PER_SEC;
-  starttime += proc->kp_proc.p_un.__p_starttime.tv_usec;
-  free(proc);
-  return starttime;
-}
-#elif defined(__OpenBSD__)
-static PRTime
-CalculateProcessCreationTimestamp()
-{
-  int mib[6] = { CTL_KERN, KERN_PROC, KERN_PROC_PID, getpid(), sizeof(struct kinfo_proc), 1 };
-  size_t buffer_size;
-  if (sysctl(mib, 6, NULL, &buffer_size, NULL, 0))
-    return 0;
-
-  struct kinfo_proc *proc = (struct kinfo_proc*) malloc(buffer_size);
-  if (sysctl(mib, 6, proc, &buffer_size, NULL, 0)) {
-    free(proc);
-    return 0;
-  }
-  PRTime starttime = static_cast<PRTime>(proc->p_ustart_sec) * PR_USEC_PER_SEC;
-  starttime += proc->p_ustart_usec;
-  free(proc);
+  PRTime starttime = static_cast<PRTime>(proc.KP_START_SEC) * PR_USEC_PER_SEC;
+  starttime += proc.KP_START_USEC;
   return starttime;
 }
 #else
 static PRTime
 CalculateProcessCreationTimestamp()
 {
   return 0;
 }
--- a/toolkit/mozapps/update/nsUpdateService.js
+++ b/toolkit/mozapps/update/nsUpdateService.js
@@ -37,17 +37,17 @@ const PREF_APP_UPDATE_INCOMPATIBLE_MODE 
 const PREF_APP_UPDATE_INTERVAL            = "app.update.interval";
 const PREF_APP_UPDATE_LOG                 = "app.update.log";
 const PREF_APP_UPDATE_MODE                = "app.update.mode";
 const PREF_APP_UPDATE_NEVER_BRANCH        = "app.update.never.";
 const PREF_APP_UPDATE_POSTUPDATE          = "app.update.postupdate";
 const PREF_APP_UPDATE_PROMPTWAITTIME      = "app.update.promptWaitTime";
 const PREF_APP_UPDATE_SHOW_INSTALLED_UI   = "app.update.showInstalledUI";
 const PREF_APP_UPDATE_SILENT              = "app.update.silent";
-const PREF_APP_UPDATE_STAGE_ENABLED       = "app.update.stage.enabled";
+const PREF_APP_UPDATE_STAGE_ENABLED       = "app.update.staging.enabled";
 const PREF_APP_UPDATE_URL                 = "app.update.url";
 const PREF_APP_UPDATE_URL_DETAILS         = "app.update.url.details";
 const PREF_APP_UPDATE_URL_OVERRIDE        = "app.update.url.override";
 const PREF_APP_UPDATE_SERVICE_ENABLED     = "app.update.service.enabled";
 const PREF_APP_UPDATE_SERVICE_ERRORS      = "app.update.service.errors";
 const PREF_APP_UPDATE_SERVICE_MAX_ERRORS  = "app.update.service.maxErrors";
 
 const PREF_PARTNER_BRANCH                 = "app.partner.";
--- a/toolkit/mozapps/update/test/shared.js
+++ b/toolkit/mozapps/update/test/shared.js
@@ -7,17 +7,17 @@
 // const Cc, Ci, and Cr are defined in netwerk/test/httpserver/httpd.js so we
 // need to define unique ones.
 const AUS_Cc = Components.classes;
 const AUS_Ci = Components.interfaces;
 const AUS_Cr = Components.results;
 const AUS_Cu = Components.utils;
 
 const PREF_APP_UPDATE_AUTO                = "app.update.auto";
-const PREF_APP_UPDATE_STAGE_ENABLED       = "app.update.stage.enabled";
+const PREF_APP_UPDATE_STAGE_ENABLED       = "app.update.staging.enabled";
 const PREF_APP_UPDATE_BACKGROUNDERRORS    = "app.update.backgroundErrors";
 const PREF_APP_UPDATE_BACKGROUNDMAXERRORS = "app.update.backgroundMaxErrors";
 const PREF_APP_UPDATE_CERTS_BRANCH        = "app.update.certs.";
 const PREF_APP_UPDATE_CERT_CHECKATTRS     = "app.update.cert.checkAttributes";
 const PREF_APP_UPDATE_CERT_ERRORS         = "app.update.cert.errors";
 const PREF_APP_UPDATE_CERT_MAXERRORS      = "app.update.cert.maxErrors";
 const PREF_APP_UPDATE_CERT_REQUIREBUILTIN = "app.update.cert.requireBuiltIn";
 const PREF_APP_UPDATE_CHANNEL             = "app.update.channel";
--- a/tools/profiler/TableTicker.cpp
+++ b/tools/profiler/TableTicker.cpp
@@ -1084,18 +1084,19 @@ void mozilla_sampler_start(int aProfileE
   ProfileStack *stack = tlsStack.get();
   if (!stack) {
     ASSERT(false);
     return;
   }
 
   mozilla_sampler_stop();
 
-  TableTicker *t = new TableTicker(aInterval, aProfileEntries, stack,
-                                   aFeatures, aFeatureCount);
+  TableTicker *t = new TableTicker(aInterval ? aInterval : PROFILE_DEFAULT_INTERVAL,
+                                   aProfileEntries ? aProfileEntries : PROFILE_DEFAULT_ENTRY,
+                                   stack, aFeatures, aFeatureCount);
   tlsTicker.set(t);
   t->Start();
   if (t->ProfileJS())
       stack->enableJSSampling();
 }
 
 void mozilla_sampler_stop()
 {
--- a/uriloader/exthandler/nsExternalHelperAppService.cpp
+++ b/uriloader/exthandler/nsExternalHelperAppService.cpp
@@ -471,16 +471,19 @@ static nsExtraMimeTypeEntry extraMimeEnt
   { TEXT_CSS, "css", "Style Sheet" },
   { VIDEO_OGG, "ogv", "Ogg Video" },
   { VIDEO_OGG, "ogg", "Ogg Video" },
   { APPLICATION_OGG, "ogg", "Ogg Video"},
   { AUDIO_OGG, "oga", "Ogg Audio" },
   { AUDIO_OGG, "opus", "Opus Audio" },
   { VIDEO_WEBM, "webm", "Web Media Video" },
   { AUDIO_WEBM, "webm", "Web Media Audio" },
+#ifdef MOZ_MEDIA_PLUGINS
+  { AUDIO_MP3, "mp3", "MPEG Audio" },
+#endif
   { VIDEO_MP4, "mp4", "MPEG-4 Video" },
   { VIDEO_RAW, "yuv", "Raw YUV Video" },
   { AUDIO_WAV, "wav", "Waveform Audio" }
 };
 
 #undef MAC_TYPE
 
 /**
--- a/widget/windows/nsTextStore.cpp
+++ b/widget/windows/nsTextStore.cpp
@@ -1,20 +1,25 @@
 /* -*- 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 <olectl.h>
 
+#ifdef MOZ_LOGGING
+#define FORCE_PR_LOG /* Allow logging in the release build */
+#endif // MOZ_LOGGING
+#include "prlog.h"
+
 #include "nscore.h"
 #include "nsTextStore.h"
 #include "nsWindow.h"
-#include "prlog.h"
 #include "nsPrintfCString.h"
+#include "WinUtils.h"
 #include "mozilla/Preferences.h"
 
 using namespace mozilla;
 using namespace mozilla::widget;
 
 /******************************************************************/
 /* nsTextStore                                                    */
 /******************************************************************/
@@ -23,73 +28,408 @@ ITfThreadMgr*           nsTextStore::sTs
 ITfDisplayAttributeMgr* nsTextStore::sDisplayAttrMgr = NULL;
 ITfCategoryMgr*         nsTextStore::sCategoryMgr    = NULL;
 DWORD         nsTextStore::sTsfClientId  = 0;
 nsTextStore*  nsTextStore::sTsfTextStore = NULL;
 
 UINT nsTextStore::sFlushTIPInputMessage  = 0;
 
 #ifdef PR_LOGGING
+
+/**
+ * TSF related code should log its behavior even on release build especially
+ * in the interface methods.
+ *
+ * In interface methods, use PR_LOG_ALWAYS.
+ * In internal methods, use PR_LOG_DEBUG for logging normal behavior.
+ * For logging error, use PR_LOG_ERROR.
+ *
+ * When an instance method is called, start with following text:
+ *   "TSF: 0x%p nsFoo::Bar(", the 0x%p should be the "this" of the nsFoo.
+ * after that, start with:
+ *   "TSF: 0x%p   nsFoo::Bar("
+ * In an internal method, start with following text:
+ *   "TSF: 0x%p   nsFoo::Bar("
+ * When a static method is called, start with following text:
+ *   "TSF: nsFoo::Bar("
+ */
+
 PRLogModuleInfo* sTextStoreLog = nullptr;
-#endif
+
+static const char*
+GetBoolName(bool aBool)
+{
+  return aBool ? "true" : "false";
+}
+
+static const char*
+GetIMEEnabledName(IMEState::Enabled aIMEEnabled)
+{
+  switch (aIMEEnabled) {
+    case IMEState::DISABLED:
+      return "DISABLED";
+    case IMEState::ENABLED:
+      return "ENABLED";
+    case IMEState::PASSWORD:
+      return "PASSWORD";
+    case IMEState::PLUGIN:
+      return "PLUGIN";
+    default:
+      return "Invalid";
+  }
+}
+
+static nsCString
+GetRIIDNameStr(REFIID aRIID)
+{
+  LPOLESTR str = nullptr;
+  HRESULT hr = ::StringFromIID(aRIID, &str);
+  if (FAILED(hr) || !str || !str[0]) {
+    return EmptyCString();
+  }
+
+  nsAutoString key(L"Interface\\");
+  key += str;
+
+  nsAutoCString result;
+  PRUnichar buf[256];
+  if (WinUtils::GetRegistryKey(HKEY_CLASSES_ROOT, key.get(), nullptr,
+                               buf, sizeof(buf))) {
+    result = NS_ConvertUTF16toUTF8(buf);
+  } else {
+    result = NS_ConvertUTF16toUTF8(str);
+  }
+
+  ::CoTaskMemFree(str);
+  return result;
+}
+
+static const char*
+GetCommonReturnValueName(HRESULT aResult)
+{
+  switch (aResult) {
+    case S_OK:
+      return "S_OK";
+    case E_ABORT:
+      return "E_ABORT";
+    case E_ACCESSDENIED:
+      return "E_ACCESSDENIED";
+    case E_FAIL:
+      return "E_FAIL";
+    case E_HANDLE:
+      return "E_HANDLE";
+    case E_INVALIDARG:
+      return "E_INVALIDARG";
+    case E_NOINTERFACE:
+      return "E_NOINTERFACE";
+    case E_NOTIMPL:
+      return "E_NOTIMPL";
+    case E_OUTOFMEMORY:
+      return "E_OUTOFMEMORY";
+    case E_POINTER:
+      return "E_POINTER";
+    case E_UNEXPECTED:
+      return "E_UNEXPECTED";
+    default:
+      return SUCCEEDED(aResult) ? "Succeeded" : "Failed";
+  }
+}
+
+static const char*
+GetTextStoreReturnValueName(HRESULT aResult)
+{
+  switch (aResult) {
+    case TS_E_FORMAT:
+      return "TS_E_FORMAT";
+    case TS_E_INVALIDPOINT:
+      return "TS_E_INVALIDPOINT";
+    case TS_E_INVALIDPOS:
+      return "TS_E_INVALIDPOS";
+    case TS_E_NOINTERFACE:
+      return "TS_E_NOINTERFACE";
+    case TS_E_NOLAYOUT:
+      return "TS_E_NOLAYOUT";
+    case TS_E_NOLOCK:
+      return "TS_E_NOLOCK";
+    case TS_E_NOOBJECT:
+      return "TS_E_NOOBJECT";
+    case TS_E_NOSELECTION:
+      return "TS_E_NOSELECTION";
+    case TS_E_NOSERVICE:
+      return "TS_E_NOSERVICE";
+    case TS_E_READONLY:
+      return "TS_E_READONLY";
+    case TS_E_SYNCHRONOUS:
+      return "TS_E_SYNCHRONOUS";
+    case TS_S_ASYNC:
+      return "TS_S_ASYNC";
+    default:
+      return GetCommonReturnValueName(aResult);
+  }
+}
+
+static const nsCString
+GetSinkMaskNameStr(DWORD aSinkMask)
+{
+  nsAutoCString description;
+  if (aSinkMask & TS_AS_TEXT_CHANGE) {
+    description.AppendLiteral("TS_AS_TEXT_CHANGE");
+  }
+  if (aSinkMask & TS_AS_SEL_CHANGE) {
+    if (!description.IsEmpty()) {
+      description.AppendLiteral(" | ");
+    }
+    description.AppendLiteral("TS_AS_SEL_CHANGE");
+  }
+  if (aSinkMask & TS_AS_LAYOUT_CHANGE) {
+    if (!description.IsEmpty()) {
+      description.AppendLiteral(" | ");
+    }
+    description.AppendLiteral("TS_AS_LAYOUT_CHANGE");
+  }
+  if (aSinkMask & TS_AS_ATTR_CHANGE) {
+    if (!description.IsEmpty()) {
+      description.AppendLiteral(" | ");
+    }
+    description.AppendLiteral("TS_AS_ATTR_CHANGE");
+  }
+  if (aSinkMask & TS_AS_STATUS_CHANGE) {
+    if (!description.IsEmpty()) {
+      description.AppendLiteral(" | ");
+    }
+    description.AppendLiteral("TS_AS_STATUS_CHANGE");
+  }
+  if (description.IsEmpty()) {
+    description.AppendLiteral("not-specified");
+  }
+  return description;
+}
+
+static const char*
+GetActiveSelEndName(TsActiveSelEnd aSelEnd)
+{
+  return aSelEnd == TS_AE_NONE  ? "TS_AE_NONE" :
+         aSelEnd == TS_AE_START ? "TS_AE_START" :
+         aSelEnd == TS_AE_END   ? "TS_AE_END" : "Unknown";
+}
+
+static const nsCString
+GetLockFlagNameStr(DWORD aLockFlags)
+{
+  nsAutoCString description;
+  if ((aLockFlags & TS_LF_READWRITE) == TS_LF_READWRITE) {
+    description.AppendLiteral("TS_LF_READWRITE");
+  } else if (aLockFlags & TS_LF_READ) {
+    description.AppendLiteral("TS_LF_READ");
+  }
+  if (aLockFlags & TS_LF_SYNC) {
+    if (!description.IsEmpty()) {
+      description.AppendLiteral(" | ");
+    }
+    description.AppendLiteral("TS_LF_SYNC");
+  }
+  if (description.IsEmpty()) {
+    description.AppendLiteral("not-specified");
+  }
+  return description;
+}
+
+static const char*
+GetTextRunTypeName(TsRunType aRunType)
+{
+  switch (aRunType) {
+    case TS_RT_PLAIN:
+      return "TS_RT_PLAIN";
+    case TS_RT_HIDDEN:
+      return "TS_RT_HIDDEN";
+    case  TS_RT_OPAQUE:
+      return "TS_RT_OPAQUE";
+    default:
+      return "Unknown";
+  }
+}
+
+static nsCString
+GetColorName(const TF_DA_COLOR &aColor)
+{
+  switch (aColor.type) {
+    case TF_CT_NONE:
+      return NS_LITERAL_CSTRING("TF_CT_NONE");
+    case TF_CT_SYSCOLOR:
+      return nsPrintfCString("TF_CT_SYSCOLOR, nIndex:0x%08X",
+                             static_cast<int32_t>(aColor.nIndex));
+    case TF_CT_COLORREF:
+      return nsPrintfCString("TF_CT_COLORREF, cr:0x%08X",
+                             static_cast<int32_t>(aColor.cr));
+      break;
+    default:
+      return nsPrintfCString("Unknown(%08X)",
+                             static_cast<int32_t>(aColor.type));
+  }
+}
+
+static nsCString
+GetLineStyleName(TF_DA_LINESTYLE aLineStyle)
+{
+  switch (aLineStyle) {
+    case TF_LS_NONE:
+      return NS_LITERAL_CSTRING("TF_LS_NONE");
+    case TF_LS_SOLID:
+      return NS_LITERAL_CSTRING("TF_LS_SOLID");
+    case TF_LS_DOT:
+      return NS_LITERAL_CSTRING("TF_LS_DOT");
+    case TF_LS_DASH:
+      return NS_LITERAL_CSTRING("TF_LS_DASH");
+    case TF_LS_SQUIGGLE:
+      return NS_LITERAL_CSTRING("TF_LS_SQUIGGLE");
+    default: {
+      return nsPrintfCString("Unknown(%08X)", static_cast<int32_t>(aLineStyle));
+    }
+  }
+}
+
+static nsCString
+GetClauseAttrName(TF_DA_ATTR_INFO aAttr)
+{
+  switch (aAttr) {
+    case TF_ATTR_INPUT:
+      return NS_LITERAL_CSTRING("TF_ATTR_INPUT");
+    case TF_ATTR_TARGET_CONVERTED:
+      return NS_LITERAL_CSTRING("TF_ATTR_TARGET_CONVERTED");
+    case TF_ATTR_CONVERTED:
+      return NS_LITERAL_CSTRING("TF_ATTR_CONVERTED");
+    case TF_ATTR_TARGET_NOTCONVERTED:
+      return NS_LITERAL_CSTRING("TF_ATTR_TARGET_NOTCONVERTED");
+    case TF_ATTR_INPUT_ERROR:
+      return NS_LITERAL_CSTRING("TF_ATTR_INPUT_ERROR");
+    case TF_ATTR_FIXEDCONVERTED:
+      return NS_LITERAL_CSTRING("TF_ATTR_FIXEDCONVERTED");
+    case TF_ATTR_OTHER:
+      return NS_LITERAL_CSTRING("TF_ATTR_OTHER");
+    default: {
+      return nsPrintfCString("Unknown(%08X)", static_cast<int32_t>(aAttr));
+    }
+  }
+}
+
+static nsCString
+GetDisplayAttrStr(const TF_DISPLAYATTRIBUTE &aDispAttr)
+{
+  nsAutoCString str;
+  str = "crText:{ ";
+  str += GetColorName(aDispAttr.crText);
+  str += " }, crBk:{ ";
+  str += GetColorName(aDispAttr.crBk);
+  str += " }, lsStyle: ";
+  str += GetLineStyleName(aDispAttr.lsStyle);
+  str += ", fBoldLine: ";
+  str += GetBoolName(aDispAttr.fBoldLine);
+  str += ", crLine:{ ";
+  str += GetColorName(aDispAttr.crLine);
+  str += " }, bAttr: ";
+  str += GetClauseAttrName(aDispAttr.bAttr);
+  return str;
+}
+
+#endif // #ifdef PR_LOGGING
 
 nsTextStore::nsTextStore()
 {
+  PR_LOG(sTextStoreLog, PR_LOG_ALWAYS,
+    ("TSF: 0x%p nsTextStore::nsTestStore(): instance is created", this));
+
   mRefCnt = 1;
   mEditCookie = 0;
   mSinkMask = 0;
   mWindow = nullptr;
   mLock = 0;
   mLockQueued = 0;
   mTextChange.acpStart = PR_INT32_MAX;
   mTextChange.acpOldEnd = mTextChange.acpNewEnd = 0;
   mLastDispatchedTextEvent = nullptr;
 }
 
 nsTextStore::~nsTextStore()
 {
+  PR_LOG(sTextStoreLog, PR_LOG_ALWAYS,
+    ("TSF: 0x%p nsTextStore instance is destroyed, "
+     "mWindow=0x%p, mDocumentMgr=0x%p, mContext=0x%p",
+     this, mWindow, mDocumentMgr, mContext));
+
   if (mCompositionTimer) {
     mCompositionTimer->Cancel();
     mCompositionTimer = nullptr;
   }
   SaveTextEvent(nullptr);
 }
 
 bool
 nsTextStore::Create(nsWindow* aWindow,
                     IMEState::Enabled aIMEEnabled)
 {
-  if (!mDocumentMgr) {
-    // Create document manager
-    HRESULT hr = sTsfThreadMgr->CreateDocumentMgr(
-                                    getter_AddRefs(mDocumentMgr));
-    NS_ENSURE_TRUE(SUCCEEDED(hr), false);
-    mWindow = aWindow;
-    // Create context and add it to document manager
-    hr = mDocumentMgr->CreateContext(sTsfClientId, 0,
-                                     static_cast<ITextStoreACP*>(this),
-                                     getter_AddRefs(mContext), &mEditCookie);
-    if (SUCCEEDED(hr)) {
-      SetInputContextInternal(aIMEEnabled);
-      hr = mDocumentMgr->Push(mContext);
-    }
-    if (SUCCEEDED(hr)) {
-      PR_LOG(sTextStoreLog, PR_LOG_ALWAYS,
-             ("TSF: Created, window=%08x\n", aWindow));
-      return true;
-    }
+  PR_LOG(sTextStoreLog, PR_LOG_ALWAYS,
+    ("TSF: 0x%p nsTextStore::Create(aWindow=0x%p, aIMEEnabled=%s)",
+     this, aWindow, GetIMEEnabledName(aIMEEnabled)));
+
+  if (mDocumentMgr) {
+    PR_LOG(sTextStoreLog, PR_LOG_ERROR,
+      ("TSF: 0x%p   nsTextStore::Create() FAILED due to already initialized",
+       this));
+    return false;
+  }
+
+  // Create document manager
+  HRESULT hr = sTsfThreadMgr->CreateDocumentMgr(
+                                  getter_AddRefs(mDocumentMgr));
+  if (FAILED(hr)) {
+    PR_LOG(sTextStoreLog, PR_LOG_ERROR,
+      ("TSF: 0x%p   nsTextStore::Create() FAILED to create DocumentMgr "
+       "(0x%08X)", this, hr));
+    return false;
+  }
+  mWindow = aWindow;
+  // Create context and add it to document manager
+  hr = mDocumentMgr->CreateContext(sTsfClientId, 0,
+                                   static_cast<ITextStoreACP*>(this),
+                                   getter_AddRefs(mContext), &mEditCookie);
+  if (FAILED(hr)) {
+    PR_LOG(sTextStoreLog, PR_LOG_ERROR,
+      ("TSF: 0x%p   nsTextStore::Create() FAILED to create the context "
+       "(0x%08X)", this, hr));
+    mDocumentMgr = NULL;
+    return false;
+  }
+
+  SetInputContextInternal(aIMEEnabled);
+
+  hr = mDocumentMgr->Push(mContext);
+  if (FAILED(hr)) {
+    PR_LOG(sTextStoreLog, PR_LOG_ERROR,
+      ("TSF: 0x%p   nsTextStore::Create() FAILED to push the context (0x%08X)",
+       this, hr));
+    // XXX Why don't we use NS_IF_RELEASE() here??
     mContext = NULL;
     mDocumentMgr = NULL;
+    return false;
   }
-  return false;
+
+  PR_LOG(sTextStoreLog, PR_LOG_ALWAYS,
+    ("TSF: 0x%p   nsTextStore::Create() succeeded: "
+     "mDocumentMgr=0x%p, mContext=0x%p, mEditCookie=0x%08X",
+     this, mDocumentMgr, mContext, mEditCookie));
+
+  return true;
 }
 
 bool
 nsTextStore::Destroy(void)
 {
+  PR_LOG(sTextStoreLog, PR_LOG_ALWAYS,
+    ("TSF: 0x%p nsTextStore::Destroy()", this));
+
   if (mWindow) {
     // When blurred, Tablet Input Panel posts "blur" messages
     // and try to insert text when the message is retrieved later.
     // But by that time the text store is already destroyed,
     // so try to get the message early
     MSG msg;
     if (::PeekMessageW(&msg, mWindow->GetWindowHandle(),
                        sFlushTIPInputMessage, sFlushTIPInputMessage,
@@ -98,19 +438,20 @@ nsTextStore::Destroy(void)
     }
   }
   mContext = NULL;
   if (mDocumentMgr) {
     mDocumentMgr->Pop(TF_POPF_ALL);
     mDocumentMgr = NULL;
   }
   mSink = NULL;
+  mWindow = NULL;
+
   PR_LOG(sTextStoreLog, PR_LOG_ALWAYS,
-         ("TSF: Destroyed, window=%08x\n", mWindow));
-  mWindow = NULL;
+    ("TSF: 0x%p   nsTextStore::Destroy() succeeded", this));
   return true;
 }
 
 STDMETHODIMP
 nsTextStore::QueryInterface(REFIID riid,
                             void** ppv)
 {
   *ppv=NULL;
@@ -118,16 +459,20 @@ nsTextStore::QueryInterface(REFIID riid,
     *ppv = static_cast<ITextStoreACP*>(this);
   } else if (IID_ITfContextOwnerCompositionSink == riid) {
     *ppv = static_cast<ITfContextOwnerCompositionSink*>(this);
   }
   if (*ppv) {
     AddRef();
     return S_OK;
   }
+
+  PR_LOG(sTextStoreLog, PR_LOG_ERROR,
+    ("TSF: 0x%p nsTextStore::QueryInterface() FAILED, riid=%s",
+     this, GetRIIDNameStr(riid).get()));
   return E_NOINTERFACE;
 }
 
 STDMETHODIMP_(ULONG) nsTextStore::AddRef()
 {
   return ++mRefCnt;
 }
 
@@ -140,157 +485,313 @@ STDMETHODIMP_(ULONG) nsTextStore::Releas
   return 0;
 }
 
 STDMETHODIMP
 nsTextStore::AdviseSink(REFIID riid,
                         IUnknown *punk,
                         DWORD dwMask)
 {
-  NS_ENSURE_TRUE(punk && IID_ITextStoreACPSink == riid, E_INVALIDARG);
+  PR_LOG(sTextStoreLog, PR_LOG_ALWAYS,
+    ("TSF: 0x%p nsTextStore::AdviseSink(riid=%s, punk=0x%p, dwMask=%s), "
+     "mSink=0x%p, mSinkMask=%s",
+     this, GetRIIDNameStr(riid).get(), punk, GetSinkMaskNameStr(dwMask).get(),
+     mSink, GetSinkMaskNameStr(mSinkMask).get()));
+
+  if (!punk) {
+    PR_LOG(sTextStoreLog, PR_LOG_ERROR,
+      ("TSF: 0x%p   nsTextStore::AdviseSink() FAILED due to the null punk",
+       this));
+    return E_UNEXPECTED;
+  }
+
+  if (IID_ITextStoreACPSink != riid) {
+    PR_LOG(sTextStoreLog, PR_LOG_ERROR,
+      ("TSF: 0x%p   nsTextStore::AdviseSink() FAILED due to "
+       "unsupported interface", this));
+    return E_INVALIDARG; // means unsupported interface.
+  }
+
   if (!mSink) {
     // Install sink
     punk->QueryInterface(IID_ITextStoreACPSink, getter_AddRefs(mSink));
-    NS_ENSURE_TRUE(mSink, E_UNEXPECTED);
+    if (!mSink) {
+      PR_LOG(sTextStoreLog, PR_LOG_ERROR,
+        ("TSF: 0x%p   nsTextStore::AdviseSink() FAILED due to "
+         "punk not having the interface", this));
+      return E_UNEXPECTED;
+    }
   } else {
     // If sink is already installed we check to see if they are the same
     // Get IUnknown from both sides for comparison
     nsRefPtr<IUnknown> comparison1, comparison2;
     punk->QueryInterface(IID_IUnknown, getter_AddRefs(comparison1));
     mSink->QueryInterface(IID_IUnknown, getter_AddRefs(comparison2));
-    if (comparison1 != comparison2)
+    if (comparison1 != comparison2) {
+      PR_LOG(sTextStoreLog, PR_LOG_ERROR,
+        ("TSF: 0x%p   nsTextStore::AdviseSink() FAILED due to "
+         "the sink being different from the stored sink", this));
       return CONNECT_E_ADVISELIMIT;
+    }
   }
   // Update mask either for a new sink or an existing sink
   mSinkMask = dwMask;
-  PR_LOG(sTextStoreLog, PR_LOG_ALWAYS,
-         ("TSF: Sink installed, punk=%08x\n", punk));
   return S_OK;
 }
 
 STDMETHODIMP
 nsTextStore::UnadviseSink(IUnknown *punk)
 {
-  NS_ENSURE_TRUE(punk, E_INVALIDARG);
-  NS_ENSURE_TRUE(mSink, CONNECT_E_NOCONNECTION);
+  PR_LOG(sTextStoreLog, PR_LOG_ALWAYS,
+    ("TSF: 0x%p nsTextStore::UnadviseSink(punk=0x%p), mSink=0x%p",
+     this, punk, mSink));
+
+  if (!punk) {
+    PR_LOG(sTextStoreLog, PR_LOG_ERROR,
+      ("TSF: 0x%p   nsTextStore::UnadviseSink() FAILED due to the null punk",
+       this));
+    return E_INVALIDARG;
+  }
+  if (!mSink) {
+    PR_LOG(sTextStoreLog, PR_LOG_ERROR,
+      ("TSF: 0x%p   nsTextStore::UnadviseSink() FAILED due to "
+       "any sink not stored", this));
+    return CONNECT_E_NOCONNECTION;
+  }
   // Get IUnknown from both sides for comparison
   nsRefPtr<IUnknown> comparison1, comparison2;
   punk->QueryInterface(IID_IUnknown, getter_AddRefs(comparison1));
   mSink->QueryInterface(IID_IUnknown, getter_AddRefs(comparison2));
   // Unadvise only if sinks are the same
-  NS_ENSURE_TRUE(comparison1 == comparison2, CONNECT_E_NOCONNECTION);
+  if (comparison1 != comparison2) {
+    PR_LOG(sTextStoreLog, PR_LOG_ERROR,
+      ("TSF: 0x%p   nsTextStore::UnadviseSink() FAILED due to "
+       "the sink being different from the stored sink", this));
+    return CONNECT_E_NOCONNECTION;
+  }
   mSink = NULL;
   mSinkMask = 0;
-  PR_LOG(sTextStoreLog, PR_LOG_ALWAYS,
-         ("TSF: Sink removed, punk=%08x\n", punk));
   return S_OK;
 }
 
 STDMETHODIMP
 nsTextStore::RequestLock(DWORD dwLockFlags,
                          HRESULT *phrSession)
 {
-  NS_ENSURE_TRUE(mSink, E_FAIL);
-  NS_ENSURE_TRUE(phrSession, E_INVALIDARG);
-  if (mLock) {
-    // only time when reentrant lock is allowed is when caller holds a
-    // read-only lock and is requesting an async write lock
-    if (TS_LF_READ == (mLock & TS_LF_READWRITE) &&
-        TS_LF_READWRITE == (dwLockFlags & TS_LF_READWRITE) &&
-        !(dwLockFlags & TS_LF_SYNC)) {
-      *phrSession = TS_S_ASYNC;
-      mLockQueued = dwLockFlags & (~TS_LF_SYNC);
-    } else {
-      // no more locks allowed
-      *phrSession = TS_E_SYNCHRONOUS;
-      return E_FAIL;
-    }
-  } else {
+  PR_LOG(sTextStoreLog, PR_LOG_ALWAYS,
+    ("TSF: 0x%p nsTextStore::RequestLock(dwLockFlags=%s, phrSession=0x%p), "
+     "mLock=%s", this, GetLockFlagNameStr(dwLockFlags).get(), phrSession,
+     GetLockFlagNameStr(mLock).get()));
+
+  if (!mSink) {
+    PR_LOG(sTextStoreLog, PR_LOG_ERROR,
+      ("TSF: 0x%p   nsTextStore::RequestLock() FAILED due to "
+       "any sink not stored", this));
+    return E_FAIL;
+  }
+  if (!phrSession) {
+    PR_LOG(sTextStoreLog, PR_LOG_ERROR,
+      ("TSF: 0x%p   nsTextStore::RequestLock() FAILED due to "
+       "null phrSession", this));
+    return E_INVALIDARG;
+  }
+
+  if (!mLock) {
     // put on lock
     mLock = dwLockFlags & (~TS_LF_SYNC);
+    PR_LOG(sTextStoreLog, PR_LOG_DEBUG,
+      ("TSF: 0x%p   nsTextStore::RequestLock() notifying OnLockGranted()...",
+       this));
     *phrSession = mSink->OnLockGranted(mLock);
     while (mLockQueued) {
       mLock = mLockQueued;
       mLockQueued = 0;
+      PR_LOG(sTextStoreLog, PR_LOG_DEBUG,
+        ("TSF: 0x%p   nsTextStore::RequestLock() notifying OnLockGranted() "
+         "with mLockQueued (%s)...",
+         this, GetLockFlagNameStr(mLock).get()));
       mSink->OnLockGranted(mLock);
     }
     mLock = 0;
+    PR_LOG(sTextStoreLog, PR_LOG_DEBUG,
+      ("TSF: 0x%p   nsTextStore::RequestLock() succeeded: *phrSession=%s",
+       this, GetTextStoreReturnValueName(*phrSession)));
+    return S_OK;
   }
-  return S_OK;
+
+  // only time when reentrant lock is allowed is when caller holds a
+  // read-only lock and is requesting an async write lock
+  if (IsReadLocked() && !IsReadWriteLocked() && IsReadWriteLock(dwLockFlags) &&
+      !(dwLockFlags & TS_LF_SYNC)) {
+    *phrSession = TS_S_ASYNC;
+    mLockQueued = dwLockFlags & (~TS_LF_SYNC);
+
+    PR_LOG(sTextStoreLog, PR_LOG_ALWAYS,
+      ("TSF: 0x%p   nsTextStore::RequestLock() stores the request in the "
+       "queue, *phrSession=TS_S_ASYNC", this));
+    return S_OK;
+  }
+
+  // no more locks allowed
+  PR_LOG(sTextStoreLog, PR_LOG_ALWAYS,
+    ("TSF: 0x%p   nsTextStore::RequestLock() didn't allow to lock, "
+     "*phrSession=TS_E_SYNCHRONOUS", this));
+  *phrSession = TS_E_SYNCHRONOUS;
+  return E_FAIL;
 }
 
 STDMETHODIMP
 nsTextStore::GetStatus(TS_STATUS *pdcs)
 {
-  NS_ENSURE_TRUE(pdcs, E_INVALIDARG);
+  PR_LOG(sTextStoreLog, PR_LOG_ALWAYS,
+    ("TSF: 0x%p nsTextStore::GetStatus(pdcs=0x%p)", this, pdcs));
+
+  if (!pdcs) {
+    PR_LOG(sTextStoreLog, PR_LOG_ERROR,
+      ("TSF: 0x%p   nsTextStore::GetStatus() FAILED due to null pdcs", this));
+    return E_INVALIDARG;
+  }
   pdcs->dwDynamicFlags = 0;
   // we use a "flat" text model for TSF support so no hidden text
   pdcs->dwStaticFlags = TS_SS_NOHIDDENTEXT;
   return S_OK;
 }
 
 STDMETHODIMP
 nsTextStore::QueryInsert(LONG acpTestStart,
                          LONG acpTestEnd,
                          ULONG cch,
                          LONG *pacpResultStart,
                          LONG *pacpResultEnd)
 {
   PR_LOG(sTextStoreLog, PR_LOG_ALWAYS,
-         ("TSF: QueryInsert, start=%ld end=%ld cch=%lu\n",
-          acpTestStart, acpTestEnd, cch));
-  // We don't test to see if these positions are
-  // after the end of document for performance reasons
-  NS_ENSURE_TRUE(0 <= acpTestStart && acpTestStart <= acpTestEnd &&
-                 pacpResultStart && pacpResultEnd, E_INVALIDARG);
+         ("TSF: 0x%p nsTextStore::QueryInsert(acpTestStart=%ld, "
+          "acpTestEnd=%ld, cch=%lu, pacpResultStart=0x%p, pacpResultEnd=0x%p)",
+          this, acpTestStart, acpTestEnd, cch, acpTestStart, acpTestEnd));
+
+  if (!pacpResultStart || !pacpResultEnd) {
+    PR_LOG(sTextStoreLog, PR_LOG_ERROR,
+           ("TSF: 0x%p   nsTextStore::QueryInsert() FAILED due to "
+            "the null argument", this));
+    return E_INVALIDARG;
+  }
+
+  if (acpTestStart < 0 || acpTestStart > acpTestEnd) {
+    PR_LOG(sTextStoreLog, PR_LOG_ERROR,
+           ("TSF: 0x%p   nsTextStore::QueryInsert() FAILED due to "
+            "wrong argument", this));
+    return E_INVALIDARG;
+  }
 
   // XXX need to adjust to cluster boundary
   // Assume we are given good offsets for now
   *pacpResultStart = acpTestStart;
   *pacpResultEnd = acpTestStart + cch;
 
   PR_LOG(sTextStoreLog, PR_LOG_ALWAYS,
-         ("TSF: QueryInsert SUCCEEDED\n"));
+         ("TSF: 0x%p  nsTextStore::QueryInsert() succeeded: "
+          "*pacpResultStart=%ld, *pacpResultEnd=%ld)",
+          this, *pacpResultStart, *pacpResultEnd));
   return S_OK;
 }
 
 STDMETHODIMP
 nsTextStore::GetSelection(ULONG ulIndex,
                           ULONG ulCount,
                           TS_SELECTION_ACP *pSelection,
                           ULONG *pcFetched)
 {
-  NS_ENSURE_TRUE(TS_LF_READ == (mLock & TS_LF_READ), TS_E_NOLOCK);
-  NS_ENSURE_TRUE(ulCount && pSelection && pcFetched, E_INVALIDARG);
+  PR_LOG(sTextStoreLog, PR_LOG_ALWAYS,
+         ("TSF: 0x%p nsTextStore::GetSelection(ulIndex=%lu, ulCount=%lu, "
+          "pSelection=0x%p, pcFetched=0x%p)",
+          this, ulIndex, ulCount, pSelection, pcFetched));
+
+  if (!IsReadLocked()) {
+    PR_LOG(sTextStoreLog, PR_LOG_ERROR,
+           ("TSF: 0x%p   nsTextStore::GetSelection() FAILED due to not locked",
+            this));
+    return TS_E_NOLOCK;
+  }
+  if (!ulCount || !pSelection || !pcFetched) {
+    PR_LOG(sTextStoreLog, PR_LOG_ERROR,
+           ("TSF: 0x%p   nsTextStore::GetSelection() FAILED due to "
+            "null argument", this));
+    return E_INVALIDARG;
+  }
 
   *pcFetched = 0;
-  NS_ENSURE_TRUE((ULONG)TS_DEFAULT_SELECTION == ulIndex || 0 == ulIndex,
-                 TS_E_NOSELECTION);
+
+  if (ulIndex != static_cast<ULONG>(TS_DEFAULT_SELECTION) &&
+      ulIndex != 0) {
+    PR_LOG(sTextStoreLog, PR_LOG_ERROR,
+           ("TSF: 0x%p   nsTextStore::GetSelection() FAILED due to "
+            "unsupported selection", this));
+    return TS_E_NOSELECTION;
+  }
+
+  if (!GetSelectionInternal(*pSelection)) {
+    PR_LOG(sTextStoreLog, PR_LOG_ERROR,
+           ("TSF: 0x%p   nsTextStore::GetSelection() FAILED to get selection",
+            this));
+    return E_FAIL;
+  }
+
+  *pcFetched = 1;
+  PR_LOG(sTextStoreLog, PR_LOG_ALWAYS,
+         ("TSF: 0x%p   nsTextStore::GetSelection() succeeded", this));
+  return S_OK;
+}
+
+bool
+nsTextStore::GetSelectionInternal(TS_SELECTION_ACP &aSelectionACP)
+{
   if (mCompositionView) {
+    PR_LOG(sTextStoreLog, PR_LOG_DEBUG,
+           ("TSF: 0x%p   nsTextStore::GetSelectionInternal(), "
+            "there is no composition view", this));
+
     // Emulate selection during compositions
-    *pSelection = mCompositionSelection;
+    aSelectionACP = mCompositionSelection;
   } else {
+    PR_LOG(sTextStoreLog, PR_LOG_DEBUG,
+           ("TSF: 0x%p   nsTextStore::GetSelectionInternal(), "
+            "try to get normal selection...", this));
+
     // Construct and initialize an event to get selection info
     nsQueryContentEvent event(true, NS_QUERY_SELECTED_TEXT, mWindow);
     mWindow->InitEvent(event);
     mWindow->DispatchWindowEvent(&event);
-    NS_ENSURE_TRUE(event.mSucceeded, E_FAIL);
+    if (!event.mSucceeded) {
+      PR_LOG(sTextStoreLog, PR_LOG_ERROR,
+             ("TSF: 0x%p   nsTextStore::GetSelectionInternal() FAILED to "
+              "query selected text", this));
+      return false;
+    }
     // Usually the selection anchor (beginning) position corresponds to the
     // TSF start and the selection focus (ending) position corresponds to
     // the TSF end, but if selection is reversed the focus now corresponds
     // to the TSF start and the anchor now corresponds to the TSF end
-    pSelection->acpStart = event.mReply.mOffset;
-    pSelection->acpEnd = pSelection->acpStart + event.mReply.mString.Length();
-    pSelection->style.ase = event.mReply.mString.Length() &&
-        event.mReply.mReversed ? TS_AE_START : TS_AE_END;
+    aSelectionACP.acpStart = event.mReply.mOffset;
+    aSelectionACP.acpEnd =
+      aSelectionACP.acpStart + event.mReply.mString.Length();
+    aSelectionACP.style.ase =
+      event.mReply.mString.Length() && event.mReply.mReversed ? TS_AE_START :
+                                                                TS_AE_END;
     // No support for interim character
-    pSelection->style.fInterimChar = 0;
+    aSelectionACP.style.fInterimChar = FALSE;
   }
-  *pcFetched = 1;
-  return S_OK;
+
+  PR_LOG(sTextStoreLog, PR_LOG_ALWAYS,
+         ("TSF: 0x%p   nsTextStore::GetSelectionInternal() succeeded: "
+          "acpStart=%lu, acpEnd=%lu, style.ase=%s, style.fInterimChar=%s",
+          this, aSelectionACP.acpStart, aSelectionACP.acpEnd,
+          GetActiveSelEndName(aSelectionACP.style.ase),
+          GetBoolName(aSelectionACP.style.fInterimChar)));
+
+  return true;
 }
 
 static HRESULT
 GetRangeExtent(ITfRange* aRange, LONG* aStart, LONG* aLength)
 {
   nsRefPtr<ITfRangeACP> rangeACP;
   aRange->QueryInterface(IID_ITfRangeACP, getter_AddRefs(rangeACP));
   NS_ENSURE_TRUE(rangeACP, E_FAIL);
@@ -313,194 +814,89 @@ GetGeckoSelectionValue(TF_DISPLAYATTRIBU
       break;
     default:
       result = NS_TEXTRANGE_RAWINPUT;
       break;
   }
   return result;
 }
 
-#ifdef PR_LOGGING
-static void
-GetLogTextFor(const TF_DA_COLOR &aColor, nsACString &aText)
-{
-  aText = "type: ";
-  switch (aColor.type) {
-    case TF_CT_NONE:
-      aText += "TF_CT_NONE";
-      break;
-    case TF_CT_SYSCOLOR: {
-      nsPrintfCString tmp("TF_CT_SYSCOLOR, nIndex:0x%08X",
-                          int32_t(aColor.nIndex));
-      aText += tmp;
-      break;
-    }
-    case TF_CT_COLORREF: {
-      nsPrintfCString tmp("TF_CT_COLORREF, cr:0x%08X", int32_t(aColor.cr));
-      aText += tmp;
-      break;
-    }
-    default: {
-      nsPrintfCString tmp("Unknown(%08X)", int32_t(aColor.type));
-      aText += tmp;
-      break;
-    }
-  }
-}
-
-static void
-GetLogTextFor(TF_DA_LINESTYLE aLineStyle, nsACString &aText)
-{
-  switch (aLineStyle) {
-    case TF_LS_NONE:
-      aText = "TF_LS_NONE";
-      break;
-    case TF_LS_SOLID:
-      aText = "TF_LS_SOLID";
-      break;
-    case TF_LS_DOT:
-      aText = "TF_LS_DOT";
-      break;
-    case TF_LS_DASH:
-      aText = "TF_LS_DASH";
-      break;
-    case TF_LS_SQUIGGLE:
-      aText = "TF_LS_SQUIGGLE";
-      break;
-    default: {
-      nsPrintfCString tmp("Unknown(%08X)", int32_t(aLineStyle));
-      aText = tmp;
-      break;
-    }
-  }
-}
-
-static void
-GetLogTextFor(TF_DA_ATTR_INFO aAttr, nsACString &aText)
-{
-  switch (aAttr) {
-    case TF_ATTR_INPUT:
-      aText = "TF_ATTR_INPUT";
-      break;
-    case TF_ATTR_TARGET_CONVERTED:
-      aText = "TF_ATTR_TARGET_CONVERTED";
-      break;
-    case TF_ATTR_CONVERTED:
-      aText = "TF_ATTR_CONVERTED";
-      break;
-    case TF_ATTR_TARGET_NOTCONVERTED:
-      aText = "TF_ATTR_TARGET_NOTCONVERTED";
-      break;
-    case TF_ATTR_INPUT_ERROR:
-      aText = "TF_ATTR_INPUT_ERROR";
-      break;
-    case TF_ATTR_FIXEDCONVERTED:
-      aText = "TF_ATTR_FIXEDCONVERTED";
-      break;
-    case TF_ATTR_OTHER:
-      aText = "TF_ATTR_OTHER";
-      break;
-    default: {
-      nsPrintfCString tmp("Unknown(%08X)", int32_t(aAttr));
-      aText = tmp;
-      break;
-    }
-  }
-}
-
-static nsCString
-GetLogTextFor(const TF_DISPLAYATTRIBUTE &aDispAttr)
-{
-  nsAutoCString str, tmp;
-  str = "crText:{ ";
-  GetLogTextFor(aDispAttr.crText, tmp);
-  str += tmp;
-  str += " }, crBk:{ ";
-  GetLogTextFor(aDispAttr.crBk, tmp);
-  str += tmp;
-  str += " }, lsStyle: ";
-  GetLogTextFor(aDispAttr.lsStyle, tmp);
-  str += tmp;
-  str += ", fBoldLine: ";
-  str += aDispAttr.fBoldLine ? "TRUE" : "FALSE";
-  str += ", crLine:{ ";
-  GetLogTextFor(aDispAttr.crLine, tmp);
-  str += tmp;
-  str += " }, bAttr: ";
-  GetLogTextFor(aDispAttr.bAttr, tmp);
-  str += tmp;
-  return str;
-}
-#endif // PR_LOGGING
-
 HRESULT
 nsTextStore::GetDisplayAttribute(ITfProperty* aAttrProperty,
                                  ITfRange* aRange,
                                  TF_DISPLAYATTRIBUTE* aResult)
 {
   NS_ENSURE_TRUE(aAttrProperty, E_FAIL);
   NS_ENSURE_TRUE(aRange, E_FAIL);
   NS_ENSURE_TRUE(aResult, E_FAIL);
 
   HRESULT hr;
 
 #ifdef PR_LOGGING
-  LONG start = 0, length = 0;
-  hr = GetRangeExtent(aRange, &start, &length);
-  NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
-  PR_LOG(sTextStoreLog, PR_LOG_ALWAYS,
-         ("TSF: GetDisplayAttribute range=%ld-%ld\n",
-          start - mCompositionStart, start - mCompositionStart + length));
+  if (PR_LOG_TEST(sTextStoreLog, PR_LOG_DEBUG)) {
+    LONG start = 0, length = 0;
+    hr = GetRangeExtent(aRange, &start, &length);
+    PR_LOG(sTextStoreLog, PR_LOG_DEBUG,
+           ("TSF: 0x%p   nsTextStore::GetDisplayAttribute(): "
+            "GetDisplayAttribute range=%ld-%ld (hr=%s)",
+            this, start - mCompositionStart, start - mCompositionStart + length,
+            GetCommonReturnValueName(hr)));
+  }
 #endif
 
   VARIANT propValue;
   ::VariantInit(&propValue);
   hr = aAttrProperty->GetValue(TfEditCookie(mEditCookie), aRange, &propValue);
   if (FAILED(hr)) {
-    PR_LOG(sTextStoreLog, PR_LOG_ALWAYS,
-           ("        ITfProperty::GetValue Failed\n"));
+    PR_LOG(sTextStoreLog, PR_LOG_ERROR,
+           ("TSF: 0x%p   nsTextStore::GetDisplayAttribute() FAILED due to "
+            "ITfProperty::GetValue() failed", this));
     return hr;
   }
   if (VT_I4 != propValue.vt) {
-    PR_LOG(sTextStoreLog, PR_LOG_ALWAYS,
-           ("        ITfProperty::GetValue returns non-VT_I4 value\n"));
+    PR_LOG(sTextStoreLog, PR_LOG_ERROR,
+           ("TSF: 0x%p   nsTextStore::GetDisplayAttribute() FAILED due to "
+            "ITfProperty::GetValue() returns non-VT_I4 value", this));
     ::VariantClear(&propValue);
     return E_FAIL;
   }
 
   NS_ENSURE_TRUE(sCategoryMgr, E_FAIL);
   GUID guid;
   hr = sCategoryMgr->GetGUID(DWORD(propValue.lVal), &guid);
   ::VariantClear(&propValue);
   if (FAILED(hr)) {
-    PR_LOG(sTextStoreLog, PR_LOG_ALWAYS,
-           ("        ITfCategoryMgr::GetGUID Failed\n"));
+    PR_LOG(sTextStoreLog, PR_LOG_ERROR,
+           ("TSF: 0x%p   nsTextStore::GetDisplayAttribute() FAILED due to "
+            "ITfCategoryMgr::GetGUID() failed", this));
     return hr;
   }
 
   NS_ENSURE_TRUE(sDisplayAttrMgr, E_FAIL);
   nsRefPtr<ITfDisplayAttributeInfo> info;
   hr = sDisplayAttrMgr->GetDisplayAttributeInfo(guid, getter_AddRefs(info),
                                                 NULL);
   if (FAILED(hr) || !info) {
-    PR_LOG(sTextStoreLog, PR_LOG_ALWAYS,
-           ("        ITfDisplayAttributeMgr::GetDisplayAttributeInfo Failed\n"));
+    PR_LOG(sTextStoreLog, PR_LOG_ERROR,
+           ("TSF: 0x%p   nsTextStore::GetDisplayAttribute() FAILED due to "
+            "ITfDisplayAttributeMgr::GetDisplayAttributeInfo() failed", this));
     return hr;
   }
 
   hr = info->GetAttributeInfo(aResult);
   if (FAILED(hr)) {
-    PR_LOG(sTextStoreLog, PR_LOG_ALWAYS,
-           ("        ITfDisplayAttributeInfo::GetAttributeInfo Failed\n"));
+    PR_LOG(sTextStoreLog, PR_LOG_ERROR,
+           ("TSF: 0x%p   nsTextStore::GetDisplayAttribute() FAILED due to "
+            "ITfDisplayAttributeInfo::GetAttributeInfo() failed", this));
     return hr;
   }
 
-  PR_LOG(sTextStoreLog, PR_LOG_ALWAYS,
-         ("TSF: GetDisplayAttribute Result={ %s }\n",
-          GetLogTextFor(*aResult).get()));
+  PR_LOG(sTextStoreLog, PR_LOG_DEBUG,
+         ("TSF: 0x%p   nsTextStore::GetDisplayAttribute() succeeded: "
+          "Result={ %s }", this, GetDisplayAttrStr(*aResult).get()));
   return S_OK;
 }
 
 HRESULT
 nsTextStore::SaveTextEvent(const nsTextEvent* aEvent)
 {
   if (mLastDispatchedTextEvent) {
     if (mLastDispatchedTextEvent->rangeArray)
@@ -548,50 +944,72 @@ IsSameTextEvent(const nsTextEvent* aEven
            ((aEvent1->rangeArray && aEvent2->rangeArray) &&
            !memcmp(aEvent1->rangeArray, aEvent2->rangeArray,
                    sizeof(nsTextRange) * aEvent1->rangeCount))));
 }
 
 HRESULT
 nsTextStore::UpdateCompositionExtent(ITfRange* aRangeNew)
 {
-  NS_ENSURE_TRUE(mCompositionView, E_FAIL);
+  PR_LOG(sTextStoreLog, PR_LOG_DEBUG,
+         ("TSF: 0x%p   nsTextStore::UpdateCompositionExtent(aRangeNew=0x%p), "
+          "mCompositionView=0x%p", this, aRangeNew, mCompositionView));
+
+  if (!mCompositionView) {
+    PR_LOG(sTextStoreLog, PR_LOG_ERROR,
+           ("TSF: 0x%p   nsTextStore::UpdateCompositionExtent() FAILED due to "
+            "no composition view", this));
+    return E_FAIL;
+  }
 
   HRESULT hr;
   nsRefPtr<ITfCompositionView> pComposition(mCompositionView);
   nsRefPtr<ITfRange> composingRange(aRangeNew);
   if (!composingRange) {
     hr = pComposition->GetRange(getter_AddRefs(composingRange));
-    NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
+    if (FAILED(hr)) {
+      PR_LOG(sTextStoreLog, PR_LOG_ERROR,
+             ("TSF: 0x%p   nsTextStore::UpdateCompositionExtent() FAILED due to "
+              "pComposition->GetRange() failure", this));
+      return hr;
+    }
   }
 
   // Get starting offset of the composition
   LONG compStart = 0, compLength = 0;
   hr = GetRangeExtent(composingRange, &compStart, &compLength);
-  NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
+  if (FAILED(hr)) {
+    PR_LOG(sTextStoreLog, PR_LOG_ERROR,
+           ("TSF: 0x%p   nsTextStore::UpdateCompositionExtent() FAILED due to "
+            "GetRangeExtent() failure", this));
+    return hr;
+  }
+
+  PR_LOG(sTextStoreLog, PR_LOG_DEBUG,
+         ("TSF: 0x%p   nsTextStore::UpdateCompositionExtent(), range=%ld-%ld, "
+          "mCompositionStart=%ld, mCompositionString.Length()=%lu",
+          this, compStart, compStart + compLength, mCompositionStart,
+          mCompositionString.Length()));
+
   if (mCompositionStart != compStart ||
       mCompositionString.Length() != (ULONG)compLength) {
     // If the queried composition length is different from the length
     // of our composition string, OnUpdateComposition is being called
     // because a part of the original composition was committed.
     // Reflect that by committing existing composition and starting
     // a new one. OnEndComposition followed by OnStartComposition
     // will accomplish this automagically.
     OnEndComposition(pComposition);
     OnStartCompositionInternal(pComposition, composingRange, true);
-    PR_LOG(sTextStoreLog, PR_LOG_ALWAYS,
-           ("TSF: UpdateCompositionExtent, (reset) range=%ld-%ld\n",
-            compStart, compStart + compLength));
   } else {
     mCompositionLength = compLength;
-    PR_LOG(sTextStoreLog, PR_LOG_ALWAYS,
-           ("TSF: UpdateCompositionExtent, range=%ld-%ld\n",
-            compStart, compStart + compLength));
   }
 
+  PR_LOG(sTextStoreLog, PR_LOG_DEBUG,
+         ("TSF: 0x%p   nsTextStore::UpdateCompositionExtent() succeeded", this));
   return S_OK;
 }
 
 static bool
 GetColor(const TF_DA_COLOR &aTSFColor, nscolor &aResult)
 {
   switch (aTSFColor.type) {
     case TF_CT_SYSCOLOR: {
@@ -632,46 +1050,69 @@ GetLineStyle(TF_DA_LINESTYLE aTSFLineSty
     default:
       return false;
   }
 }
 
 HRESULT
 nsTextStore::SendTextEventForCompositionString()
 {
-  PR_LOG(sTextStoreLog, PR_LOG_ALWAYS,
-         ("TSF: SendTextEventForCompositionString\n"));
+  PR_LOG(sTextStoreLog, PR_LOG_DEBUG,
+         ("TSF: 0x%p   nsTextStore::SendTextEventForCompositionString(), "
+          "mCompositionView=0x%p, mCompositionString=\"%s\"",
+          this, mCompositionView,
+          NS_ConvertUTF16toUTF8(mCompositionString).get()));
 
-  NS_ENSURE_TRUE(mCompositionView, E_FAIL);
+  if (!mCompositionView) {
+    PR_LOG(sTextStoreLog, PR_LOG_ERROR,
+           ("TSF: 0x%p   nsTextStore::SendTextEventForCompositionString() FAILED "
+            "due to no composition view", this));
+    return E_FAIL;
+  }
 
   // Getting display attributes is *really* complicated!
   // We first get the context and the property objects to query for
   // attributes, but since a big range can have a variety of values for
   // the attribute, we have to find out all the ranges that have distinct
   // attribute values. Then we query for what the value represents through
   // the display attribute manager and translate that to nsTextRange to be
   // sent in NS_TEXT_TEXT
 
   nsRefPtr<ITfProperty> attrPropetry;
   HRESULT hr = mContext->GetProperty(GUID_PROP_ATTRIBUTE,
                                      getter_AddRefs(attrPropetry));
-  NS_ENSURE_TRUE(SUCCEEDED(hr) && attrPropetry, hr);
+  if (FAILED(hr) || !attrPropetry) {
+    PR_LOG(sTextStoreLog, PR_LOG_ERROR,
+           ("TSF: 0x%p   nsTextStore::SendTextEventForCompositionString() FAILED "
+            "due to mContext->GetProperty() failure", this));
+    return FAILED(hr) ? hr : E_FAIL;
+  }
 
   // Use NS_TEXT_TEXT to set composition string
   nsTextEvent event(true, NS_TEXT_TEXT, mWindow);
   mWindow->InitEvent(event);
 
   nsRefPtr<ITfRange> composingRange;
   hr = mCompositionView->GetRange(getter_AddRefs(composingRange));
-  NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
+  if (FAILED(hr)) {
+    PR_LOG(sTextStoreLog, PR_LOG_ERROR,
+           ("TSF: 0x%p   nsTextStore::SendTextEventForCompositionString() FAILED "
+            "due to mCompositionView->GetRange() failure", this));
+    return hr;
+  }
 
   nsRefPtr<IEnumTfRanges> enumRanges;
   hr = attrPropetry->EnumRanges(TfEditCookie(mEditCookie),
                                 getter_AddRefs(enumRanges), composingRange);
-  NS_ENSURE_TRUE(SUCCEEDED(hr) && enumRanges, hr);
+  if (FAILED(hr) || !enumRanges) {
+    PR_LOG(sTextStoreLog, PR_LOG_ERROR,
+           ("TSF: 0x%p   nsTextStore::SendTextEventForCompositionString() FAILED "
+            "due to attrPropetry->EnumRanges() failure", this));
+    return FAILED(hr) ? hr : E_FAIL;
+  }
 
   nsAutoTArray<nsTextRange, 4> textRanges;
   nsTextRange newRange;
   // No matter if we have display attribute info or not,
   // we always pass in at least one range to NS_TEXT_TEXT
   newRange.mStartOffset = 0;
   newRange.mEndOffset = mCompositionString.Length();
   newRange.mRangeType = NS_TEXTRANGE_RAWINPUT;
@@ -762,102 +1203,189 @@ nsTextStore::SendTextEventForComposition
   event.theText = mCompositionString;
   event.rangeArray = textRanges.Elements();
   event.rangeCount = textRanges.Length();
 
   // If we are already send same text event, we should not resend it.  Because
   // it can be a cause of flickering.
   if (IsSameTextEvent(mLastDispatchedTextEvent, &event)) {
     PR_LOG(sTextStoreLog, PR_LOG_ALWAYS,
-           ("TSF: SendTextEventForCompositionString does not dispatch\n"));
+           ("TSF: 0x%p   nsTextStore::SendTextEventForCompositionString() "
+            "succeeded but any DOM events are not dispatched", this));
     return S_OK;
   }
 
   if (mCompositionString != mLastDispatchedCompositionString) {
+    PR_LOG(sTextStoreLog, PR_LOG_ALWAYS,
+           ("TSF: 0x%p   nsTextStore::SendTextEventForCompositionString() "
+            "dispatching compositionupdate event...", this));
     nsCompositionEvent compositionUpdate(true, NS_COMPOSITION_UPDATE,
                                          mWindow);
     mWindow->InitEvent(compositionUpdate);
     compositionUpdate.data = mCompositionString;
     mLastDispatchedCompositionString = mCompositionString;
     mWindow->DispatchWindowEvent(&compositionUpdate);
-    PR_LOG(sTextStoreLog, PR_LOG_ALWAYS,
-           ("TSF: SendTextEventForCompositionString compositionupdate "
-            "DISPATCHED\n"));
   }
 
   if (mWindow && !mWindow->Destroyed()) {
+    PR_LOG(sTextStoreLog, PR_LOG_ALWAYS,
+           ("TSF: 0x%p   nsTextStore::SendTextEventForCompositionString() "
+            "dispatching text event...", this));
     mWindow->DispatchWindowEvent(&event);
-    PR_LOG(sTextStoreLog, PR_LOG_ALWAYS,
-           ("TSF: SendTextEventForCompositionString text event DISPATCHED\n"));
   }
+
+  PR_LOG(sTextStoreLog, PR_LOG_ALWAYS,
+         ("TSF: 0x%p   nsTextStore::SendTextEventForCompositionString() "
+          "succeeded", this));
+
   return SaveTextEvent(&event);
 }
 
 HRESULT
 nsTextStore::SetSelectionInternal(const TS_SELECTION_ACP* pSelection,
                                   bool aDispatchTextEvent)
 {
-  PR_LOG(sTextStoreLog, PR_LOG_ALWAYS,
-         ("TSF: SetSelection, sel=%ld-%ld\n",
-          pSelection->acpStart, pSelection->acpEnd));
+  PR_LOG(sTextStoreLog, PR_LOG_DEBUG,
+         ("TSF: 0x%p   nsTextStore::SetSelectionInternal(pSelection=%ld-%ld, "
+          "aDispatchTextEvent=%s), %s",
+          this, pSelection->acpStart, pSelection->acpEnd,
+          GetBoolName(aDispatchTextEvent),
+          mCompositionView ? "there is composition view" :
+                             "there is no composition view"));
+
   if (mCompositionView) {
     if (aDispatchTextEvent) {
       HRESULT hr = UpdateCompositionExtent(nullptr);
-      NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
+      if (FAILED(hr)) {
+        PR_LOG(sTextStoreLog, PR_LOG_ERROR,
+           ("TSF: 0x%p   nsTextStore::SetSelectionInternal() FAILED due to "
+            "UpdateCompositionExtent() failure", this));
+        return hr;
+      }
+    }
+    if (pSelection->acpStart < mCompositionStart ||
+        pSelection->acpEnd >
+          mCompositionStart + static_cast<LONG>(mCompositionString.Length())) {
+      PR_LOG(sTextStoreLog, PR_LOG_ERROR,
+         ("TSF: 0x%p   nsTextStore::SetSelectionInternal() FAILED due to "
+          "the selection being out of the composition string", this));
+      return TS_E_INVALIDPOS;
     }
     // Emulate selection during compositions
-    NS_ENSURE_TRUE(pSelection->acpStart >= mCompositionStart &&
-                   pSelection->acpEnd <= mCompositionStart +
-                       LONG(mCompositionString.Length()), TS_E_INVALIDPOS);
     mCompositionSelection = *pSelection;
     if (aDispatchTextEvent) {
       HRESULT hr = SendTextEventForCompositionString();
-      NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
+      if (FAILED(hr)) {
+        PR_LOG(sTextStoreLog, PR_LOG_ERROR,
+           ("TSF: 0x%p   nsTextStore::SetSelectionInternal() FAILED due to "
+            "SendTextEventForCompositionString() failure", this));
+        return hr;
+      }
     }
+    return S_OK;
   } else {
     nsSelectionEvent event(true, NS_SELECTION_SET, mWindow);
     event.mOffset = pSelection->acpStart;
     event.mLength = uint32_t(pSelection->acpEnd - pSelection->acpStart);
     event.mReversed = pSelection->style.ase == TS_AE_START;
     mWindow->InitEvent(event);
     mWindow->DispatchWindowEvent(&event);
-    NS_ENSURE_TRUE(event.mSucceeded, E_FAIL);
+    if (!event.mSucceeded) {
+      PR_LOG(sTextStoreLog, PR_LOG_ERROR,
+         ("TSF: 0x%p   nsTextStore::SetSelectionInternal() FAILED due to "
+          "NS_SELECTION_SET failure", this));
+      return E_FAIL;
+    }
   }
-  PR_LOG(sTextStoreLog, PR_LOG_ALWAYS,
-         ("TSF: SetSelection SUCCEEDED\n"));
   return S_OK;
 }
 
 STDMETHODIMP
 nsTextStore::SetSelection(ULONG ulCount,
                           const TS_SELECTION_ACP *pSelection)
 {
-  NS_ENSURE_TRUE(TS_LF_READWRITE == (mLock & TS_LF_READWRITE), TS_E_NOLOCK);
-  NS_ENSURE_TRUE(1 == ulCount && pSelection, E_INVALIDARG);
+  PR_LOG(sTextStoreLog, PR_LOG_ALWAYS,
+         ("TSF: 0x%p nsTextStore::SetSelection(ulCount=%lu)",
+          this, ulCount));
 
-  return SetSelectionInternal(pSelection, true);
+  if (!IsReadWriteLocked()) {
+    PR_LOG(sTextStoreLog, PR_LOG_ERROR,
+           ("TSF: 0x%p   nsTextStore::SetSelection() FAILED due to "
+            "not locked (read-write)", this));
+    return TS_E_NOLOCK;
+  }
+  if (ulCount != 1) {
+    PR_LOG(sTextStoreLog, PR_LOG_ERROR,
+           ("TSF: 0x%p   nsTextStore::SetSelection() FAILED due to "
+            "trying setting multiple selection", this));
+    return E_INVALIDARG;
+  }
+  if (!pSelection) {
+    PR_LOG(sTextStoreLog, PR_LOG_ERROR,
+           ("TSF: 0x%p   nsTextStore::SetSelection() FAILED due to "
+            "null argument", this));
+    return E_INVALIDARG;
+  }
+
+  HRESULT hr = SetSelectionInternal(pSelection, true);
+  if (FAILED(hr)) {
+    PR_LOG(sTextStoreLog, PR_LOG_ERROR,
+           ("TSF: 0x%p   nsTextStore::SetSelection() FAILED due to "
+            "SetSelectionInternal() failure", this));
+  } else {
+    PR_LOG(sTextStoreLog, PR_LOG_ALWAYS,
+           ("TSF: 0x%p   nsTextStore::SetSelection() succeeded", this));
+  }
+  return hr;
 }
 
 STDMETHODIMP
 nsTextStore::GetText(LONG acpStart,
                      LONG acpEnd,
                      WCHAR *pchPlain,
                      ULONG cchPlainReq,
                      ULONG *pcchPlainOut,
                      TS_RUNINFO *prgRunInfo,
                      ULONG ulRunInfoReq,
                      ULONG *pulRunInfoOut,
                      LONG *pacpNext)
 {
-  NS_ENSURE_TRUE(TS_LF_READ == (mLock & TS_LF_READ), TS_E_NOLOCK);
-  NS_ENSURE_TRUE(pcchPlainOut && (pchPlain || prgRunInfo) &&
-                 (!cchPlainReq == !pchPlain) &&
-                 (!ulRunInfoReq == !prgRunInfo), E_INVALIDARG);
-  NS_ENSURE_TRUE(0 <= acpStart && -1 <= acpEnd &&
-                 (-1 == acpEnd || acpStart <= acpEnd), TS_E_INVALIDPOS);
+  PR_LOG(sTextStoreLog, PR_LOG_ALWAYS,
+         ("TSF: 0x%p nsTextStore::GetText(acpStart=%ld, acpEnd=%ld, pchPlain=0x%p, "
+          "cchPlainReq=%lu, pcchPlainOut=0x%p, prgRunInfo=0x%p, ulRunInfoReq=%lu, "
+          "pulRunInfoOut=0x%p, pacpNext=0x%p), %s, mCompositionStart=%ld, "
+          "mCompositionLength=%ld, mCompositionString.Length()=%lu",
+          this, acpStart, acpEnd, pchPlain, cchPlainReq, pcchPlainOut,
+          prgRunInfo, ulRunInfoReq, pulRunInfoOut, pacpNext,
+          mCompositionView ? "there is composition view" :
+                             "there is no composition view",
+          mCompositionStart, mCompositionLength,
+          mCompositionString.Length()));
+
+  if (!IsReadLocked()) {
+    PR_LOG(sTextStoreLog, PR_LOG_ERROR,
+           ("TSF: 0x%p   nsTextStore::GetText() FAILED due to "
+            "not locked (read)", this));
+    return TS_E_NOLOCK;
+  }
+
+  if (!pcchPlainOut || (!pchPlain && !prgRunInfo) ||
+      !cchPlainReq != !pchPlain || !ulRunInfoReq != !prgRunInfo) {
+    PR_LOG(sTextStoreLog, PR_LOG_ERROR,
+           ("TSF: 0x%p   nsTextStore::GetText() FAILED due to "
+            "invalid argument", this));
+    return E_INVALIDARG;
+  }
+
+  if (acpStart < 0 || acpEnd < -1 || (acpEnd != -1 && acpStart > acpEnd)) {
+    PR_LOG(sTextStoreLog, PR_LOG_ERROR,
+           ("TSF: 0x%p   nsTextStore::GetText() FAILED due to "
+            "invalid position", this));
+    return TS_E_INVALIDPOS;
+  }
 
   // Making sure to NULL-terminate string just to be on the safe side
   *pcchPlainOut = 0;
   if (pchPlain && cchPlainReq) *pchPlain = 0;
   if (pulRunInfoOut) *pulRunInfoOut = 0;
   if (pacpNext) *pacpNext = acpStart;
   if (prgRunInfo && ulRunInfoReq) {
     prgRunInfo->uCount = 0;
@@ -886,435 +1414,813 @@ nsTextStore::GetText(LONG acpStart,
         length = uint32_t(LONG(length) + compOldEnd - compNewEnd);
       }
     }
     // Send NS_QUERY_TEXT_CONTENT to get text content
     nsQueryContentEvent event(true, NS_QUERY_TEXT_CONTENT, mWindow);
     mWindow->InitEvent(event);
     event.InitForQueryTextContent(uint32_t(acpStart), length);
     mWindow->DispatchWindowEvent(&event);
-    NS_ENSURE_TRUE(event.mSucceeded, E_FAIL);
+    if (!event.mSucceeded) {
+      PR_LOG(sTextStoreLog, PR_LOG_ERROR,
+             ("TSF: 0x%p   nsTextStore::GetText() FAILED due to "
+              "NS_QUERY_TEXT_CONTENT failure: length=%lu", this, length));
+      return E_FAIL;
+    }
 
     if (compOldEnd > compNewStart || compNewEnd > compNewStart) {
       // Resync composition string
       const PRUnichar* compStrStart = mCompositionString.BeginReading() +
           NS_MAX<LONG>(compNewStart - mCompositionStart, 0);
       event.mReply.mString.Replace(compNewStart - acpStart,
           compOldEnd - mCompositionStart, compStrStart,
           compNewEnd - mCompositionStart);
       length = uint32_t(LONG(length) - compOldEnd + compNewEnd);
     }
-    NS_ENSURE_TRUE(-1 == acpEnd || event.mReply.mString.Length() == length,
-                   TS_E_INVALIDPOS);
+    if (-1 != acpEnd && event.mReply.mString.Length() != length) {
+      PR_LOG(sTextStoreLog, PR_LOG_ERROR,
+             ("TSF: 0x%p   nsTextStore::GetText() FAILED due to "
+              "unexpected length=%lu", this, length));
+      return TS_E_INVALIDPOS;
+    }
     length = NS_MIN(length, event.mReply.mString.Length());
 
     if (pchPlain && cchPlainReq) {
       memcpy(pchPlain, event.mReply.mString.BeginReading(),
              length * sizeof(*pchPlain));
       pchPlain[length] = 0;
       *pcchPlainOut = length;
     }
     if (prgRunInfo && ulRunInfoReq) {
       prgRunInfo->uCount = length;
       prgRunInfo->type = TS_RT_PLAIN;
       if (pulRunInfoOut) *pulRunInfoOut = 1;
     }
     if (pacpNext) *pacpNext = acpStart + length;
   }
+
+  PR_LOG(sTextStoreLog, PR_LOG_ALWAYS,
+         ("TSF: 0x%p   nsTextStore::GetText() succeeded: pcchPlainOut=0x%p, "
+          "*prgRunInfo={ uCount=%lu, type=%s }, *pulRunInfoOut=%lu, "
+          "*pacpNext=%ld)",
+          this, pcchPlainOut, prgRunInfo ? prgRunInfo->uCount : 0,
+          prgRunInfo ? GetTextRunTypeName(prgRunInfo->type) : "N/A",
+          pulRunInfoOut ? pulRunInfoOut : 0, pacpNext ? pacpNext : 0));
   return S_OK;
 }
 
 STDMETHODIMP
 nsTextStore::SetText(DWORD dwFlags,
                      LONG acpStart,
                      LONG acpEnd,
                      const WCHAR *pchText,
                      ULONG cch,
                      TS_TEXTCHANGE *pChange)
 {
+  PR_LOG(sTextStoreLog, PR_LOG_ALWAYS,
+         ("TSF: 0x%p nsTextStore::SetText(dwFlags=%s, acpStart=%ld, acpEnd=%ld, "
+          "pchText=0x%p \"%s\", cch=%lu, pChange=0x%p), %s",
+          this, dwFlags == TS_ST_CORRECTION ? "TS_ST_CORRECTION" :
+                                              "not-specified",
+          acpStart, acpEnd, pchText,
+          pchText && cch ?
+            NS_ConvertUTF16toUTF8(pchText, cch).get() : "",
+          cch, pChange,
+          mCompositionView ? "there is composition view" :
+                             "there is no composition view"));
+
   // Per SDK documentation, and since we don't have better
   // ways to do this, this method acts as a helper to
   // call SetSelection followed by InsertTextAtSelection
-  NS_ENSURE_TRUE(TS_LF_READWRITE == (mLock & TS_LF_READWRITE), TS_E_NOLOCK);
+  if (!IsReadWriteLocked()) {
+    PR_LOG(sTextStoreLog, PR_LOG_ERROR,
+           ("TSF: 0x%p   nsTextStore::SetText() FAILED due to "
+            "not locked (read)", this));
+    return TS_E_NOLOCK;
+  }
+
   TS_SELECTION_ACP selection;
   selection.acpStart = acpStart;
   selection.acpEnd = acpEnd;
   selection.style.ase = TS_AE_END;
   selection.style.fInterimChar = 0;
   // Set selection to desired range
-  NS_ENSURE_TRUE(SUCCEEDED(SetSelectionInternal(&selection)), E_FAIL);
+  HRESULT hr = SetSelectionInternal(&selection);
+  if (FAILED(hr)) {
+    PR_LOG(sTextStoreLog, PR_LOG_ERROR,
+           ("TSF: 0x%p   nsTextStore::SetText() FAILED due to "
+            "SetSelectionInternal() failure", this));
+    return hr;
+  }
   // Replace just selected text
+  // XXX We should make something like InserTextAtSelectionInternal() for
+  //     making the log clearer if InsertTextAtSelection() is called internally.
   return InsertTextAtSelection(TS_IAS_NOQUERY, pchText, cch,
                                NULL, NULL, pChange);
 }
 
 STDMETHODIMP
 nsTextStore::GetFormattedText(LONG acpStart,
                               LONG acpEnd,
                               IDataObject **ppDataObject)
 {
+  PR_LOG(sTextStoreLog, PR_LOG_ALWAYS,
+         ("TSF: 0x%p nsTextStore::GetFormattedText() called "
+          "but not supported (E_NOTIMPL)", this));
+
   // no support for formatted text
   return E_NOTIMPL;
 }
 
 STDMETHODIMP
 nsTextStore::GetEmbedded(LONG acpPos,
                          REFGUID rguidService,
                          REFIID riid,
                          IUnknown **ppunk)
 {
+  PR_LOG(sTextStoreLog, PR_LOG_ALWAYS,
+         ("TSF: 0x%p nsTextStore::GetEmbedded() called "
+          "but not supported (E_NOTIMPL)", this));
+
   // embedded objects are not supported
   return E_NOTIMPL;
 }
 
 STDMETHODIMP
 nsTextStore::QueryInsertEmbedded(const GUID *pguidService,
                                  const FORMATETC *pFormatEtc,
                                  BOOL *pfInsertable)
 {
+  PR_LOG(sTextStoreLog, PR_LOG_ALWAYS,
+         ("TSF: 0x%p nsTextStore::QueryInsertEmbedded() called "
+          "but not supported, *pfInsertable=FALSE (S_OK)", this));
+
   // embedded objects are not supported
   *pfInsertable = FALSE;
   return S_OK;
 }
 
 STDMETHODIMP
 nsTextStore::InsertEmbedded(DWORD dwFlags,
                             LONG acpStart,
                             LONG acpEnd,
                             IDataObject *pDataObject,
                             TS_TEXTCHANGE *pChange)
 {
+  PR_LOG(sTextStoreLog, PR_LOG_ALWAYS,
+         ("TSF: 0x%p nsTextStore::InsertEmbedded() called "
+          "but not supported (E_NOTIMPL)", this));
+
   // embedded objects are not supported
   return E_NOTIMPL;
 }
 
 STDMETHODIMP
 nsTextStore::RequestSupportedAttrs(DWORD dwFlags,
                                    ULONG cFilterAttrs,
                                    const TS_ATTRID *paFilterAttrs)
 {
+  PR_LOG(sTextStoreLog, PR_LOG_ALWAYS,
+         ("TSF: 0x%p nsTextStore::RequestSupportedAttrs() called "
+          "but not supported (S_OK)", this));
+
   // no attributes defined
   return S_OK;
 }
 
 STDMETHODIMP
 nsTextStore::RequestAttrsAtPosition(LONG acpPos,
                                     ULONG cFilterAttrs,
                                     const TS_ATTRID *paFilterAttrs,
                                     DWORD dwFlags)
 {
+  PR_LOG(sTextStoreLog, PR_LOG_ALWAYS,
+         ("TSF: 0x%p nsTextStore::RequestAttrsAtPosition() called "
+          "but not supported (S_OK)", this));
+
   // no per character attributes defined
   return S_OK;
 }
 
 STDMETHODIMP
 nsTextStore::RequestAttrsTransitioningAtPosition(LONG acpPos,
                                                  ULONG cFilterAttrs,
                                                  const TS_ATTRID *paFilterAttr,
                                                  DWORD dwFlags)
 {
+  PR_LOG(sTextStoreLog, PR_LOG_ALWAYS,
+         ("TSF: 0x%p nsTextStore::RequestAttrsTransitioningAtPosition() called "
+          "but not supported (S_OK)", this));
+
   // no per character attributes defined
   return S_OK;
 }
 
 STDMETHODIMP
 nsTextStore::FindNextAttrTransition(LONG acpStart,
                                     LONG acpHalt,
                                     ULONG cFilterAttrs,
                                     const TS_ATTRID *paFilterAttrs,
                                     DWORD dwFlags,
                                     LONG *pacpNext,
                                     BOOL *pfFound,
                                     LONG *plFoundOffset)
 {
-  NS_ENSURE_TRUE(pacpNext && pfFound && plFoundOffset, E_INVALIDARG);
+  if (!pacpNext || !pfFound || !plFoundOffset) {
+    PR_LOG(sTextStoreLog, PR_LOG_ERROR,
+           ("TSF: 0x%p   nsTextStore::FindNextAttrTransition() FAILED due to "
+            "null argument", this));
+    return E_INVALIDARG;
+  }
+
+  PR_LOG(sTextStoreLog, PR_LOG_ALWAYS,
+         ("TSF: 0x%p nsTextStore::FindNextAttrTransition() called "
+          "but not supported (S_OK)", this));
+
   // no per character attributes defined
   *pacpNext = *plFoundOffset = acpHalt;
   *pfFound = FALSE;
   return S_OK;
 }
 
 STDMETHODIMP
 nsTextStore::RetrieveRequestedAttrs(ULONG ulCount,
                                     TS_ATTRVAL *paAttrVals,
                                     ULONG *pcFetched)
 {
-  NS_ENSURE_TRUE(pcFetched && ulCount && paAttrVals, E_INVALIDARG);
+  if (!pcFetched || !ulCount || !paAttrVals) {
+    PR_LOG(sTextStoreLog, PR_LOG_ERROR,
+           ("TSF: 0x%p   nsTextStore::RetrieveRequestedAttrs() FAILED due to "
+            "null argument", this));
+    return E_INVALIDARG;
+  }
+
+  PR_LOG(sTextStoreLog, PR_LOG_ALWAYS,
+         ("TSF: 0x%p nsTextStore::RetrieveRequestedAttrs() called "
+          "but not supported, *pcFetched=0 (S_OK)", this));
+
   // no attributes defined
   *pcFetched = 0;
   return S_OK;
 }
 
 STDMETHODIMP
 nsTextStore::GetEndACP(LONG *pacp)
 {
-  NS_ENSURE_TRUE(TS_LF_READ == (mLock & TS_LF_READ), TS_E_NOLOCK);
-  NS_ENSURE_TRUE(pacp, E_INVALIDARG);
+  PR_LOG(sTextStoreLog, PR_LOG_ALWAYS,
+         ("TSF: 0x%p nsTextStore::GetEndACP(pacp=0x%p)", this, pacp));
+
+  if (!IsReadLocked()) {
+    PR_LOG(sTextStoreLog, PR_LOG_ERROR,
+           ("TSF: 0x%p   nsTextStore::GetEndACP() FAILED due to "
+            "not locked (read)", this));
+    return TS_E_NOLOCK;
+  }
+
+  if (!pacp) {
+    PR_LOG(sTextStoreLog, PR_LOG_ERROR,
+           ("TSF: 0x%p   nsTextStore::GetEndACP() FAILED due to "
+            "null argument", this));
+    return E_INVALIDARG;
+  }
+
   // Flattened text is retrieved and its length returned
   nsQueryContentEvent event(true, NS_QUERY_TEXT_CONTENT, mWindow);
   mWindow->InitEvent(event);
   // Return entire text
   event.InitForQueryTextContent(0, PR_INT32_MAX);
   mWindow->DispatchWindowEvent(&event);
-  NS_ENSURE_TRUE(event.mSucceeded, E_FAIL);
+  if (!event.mSucceeded) {
+    PR_LOG(sTextStoreLog, PR_LOG_ERROR,
+           ("TSF: 0x%p   nsTextStore::GetEndACP() FAILED due to "
+            "NS_QUERY_TEXT_CONTENT failure", this));
+    return E_FAIL;
+  }
   *pacp = LONG(event.mReply.mString.Length());
   return S_OK;
 }
 
 #define TEXTSTORE_DEFAULT_VIEW    (1)
 
 STDMETHODIMP
 nsTextStore::GetActiveView(TsViewCookie *pvcView)
 {
-  NS_ENSURE_TRUE(pvcView, E_INVALIDARG);
+  PR_LOG(sTextStoreLog, PR_LOG_ALWAYS,
+         ("TSF: 0x%p nsTextStore::GetActiveView(pvcView=0x%p)", this, pvcView));
+
+  if (!pvcView) {
+    PR_LOG(sTextStoreLog, PR_LOG_ERROR,
+           ("TSF: 0x%p   nsTextStore::GetActiveView() FAILED due to "
+            "null argument", this));
+    return E_INVALIDARG;
+  }
+
   *pvcView = TEXTSTORE_DEFAULT_VIEW;
+
+  PR_LOG(sTextStoreLog, PR_LOG_ALWAYS,
+         ("TSF: 0x%p   nsTextStore::GetActiveView() succeeded: *pvcView=%ld",
+          this, *pvcView));
   return S_OK;
 }
 
 STDMETHODIMP
 nsTextStore::GetACPFromPoint(TsViewCookie vcView,
                              const POINT *pt,
                              DWORD dwFlags,
                              LONG *pacp)
 {
-  NS_ENSURE_TRUE(TS_LF_READ == (mLock & TS_LF_READ), TS_E_NOLOCK);
-  NS_ENSURE_TRUE(TEXTSTORE_DEFAULT_VIEW == vcView, E_INVALIDARG);
+  if (!IsReadLocked()) {
+    PR_LOG(sTextStoreLog, PR_LOG_ERROR,
+           ("TSF: 0x%p   nsTextStore::GetACPFromPoint() FAILED due to "
+            "not locked (read)", this));
+    return TS_E_NOLOCK;
+  }
+
+  if (vcView != TEXTSTORE_DEFAULT_VIEW) {
+    PR_LOG(sTextStoreLog, PR_LOG_ERROR,
+           ("TSF: 0x%p   nsTextStore::GetACPFromPoint() FAILED due to "
+            "called with invalid view", this));
+    return E_INVALIDARG;
+  }
+
+  PR_LOG(sTextStoreLog, PR_LOG_ALWAYS,
+         ("TSF: 0x%p nsTextStore::GetACPFromPoint(vcView=%ld, "
+          "pt(0x%p)={ x=%ld, y=%ld }, dwFlags=%s, pacp=0x%p) called "
+          "but not supported (E_NOTIMPL)", this));
+
   // not supported for now
   return E_NOTIMPL;
 }
 
 STDMETHODIMP
 nsTextStore::GetTextExt(TsViewCookie vcView,
                         LONG acpStart,
                         LONG acpEnd,
                         RECT *prc,
                         BOOL *pfClipped)
 {
-  NS_ENSURE_TRUE(TS_LF_READ == (mLock & TS_LF_READ), TS_E_NOLOCK);
-  NS_ENSURE_TRUE(TEXTSTORE_DEFAULT_VIEW == vcView && prc && pfClipped,
-                 E_INVALIDARG);
-  NS_ENSURE_TRUE(acpStart >= 0 && acpEnd >= acpStart, TS_E_INVALIDPOS);
+  PR_LOG(sTextStoreLog, PR_LOG_ALWAYS,
+         ("TSF: 0x%p nsTextStore::GetTextExt(vcView=%ld, "
+          "acpStart=%ld, acpEnd=%ld, prc=0x%p, pfClipped=0x%p)",
+          this, vcView, acpStart, acpEnd, prc, pfClipped));
+
+  if (!IsReadLocked()) {
+    PR_LOG(sTextStoreLog, PR_LOG_ERROR,
+           ("TSF: 0x%p   nsTextStore::GetTextExt() FAILED due to "
+            "not locked (read)", this));
+    return TS_E_NOLOCK;
+  }
+
+  if (vcView != TEXTSTORE_DEFAULT_VIEW) {
+    PR_LOG(sTextStoreLog, PR_LOG_ERROR,
+           ("TSF: 0x%p   nsTextStore::GetTextExt() FAILED due to "
+            "called with invalid view", this));
+    return E_INVALIDARG;
+  }
+
+  if (!prc || !pfClipped) {
+    PR_LOG(sTextStoreLog, PR_LOG_ERROR,
+           ("TSF: 0x%p   nsTextStore::GetTextExt() FAILED due to "
+            "null argument", this));
+    return E_INVALIDARG;
+  }
+
+  if (acpStart < 0 || acpEnd < acpStart) {
+    PR_LOG(sTextStoreLog, PR_LOG_ERROR,
+           ("TSF: 0x%p   nsTextStore::GetTextExt() FAILED due to "
+            "invalid position", this));
+    return TS_E_INVALIDPOS;
+  }
 
   // use NS_QUERY_TEXT_RECT to get rect in system, screen coordinates
   nsQueryContentEvent event(true, NS_QUERY_TEXT_RECT, mWindow);
   mWindow->InitEvent(event);
   event.InitForQueryTextRect(acpStart, acpEnd - acpStart);
   mWindow->DispatchWindowEvent(&event);
-  NS_ENSURE_TRUE(event.mSucceeded, TS_E_INVALIDPOS);
+  if (!event.mSucceeded) {
+    PR_LOG(sTextStoreLog, PR_LOG_ERROR,
+           ("TSF: 0x%p   nsTextStore::GetTextExt() FAILED due to "
+            "NS_QUERY_TEXT_RECT failure", this));
+    return TS_E_INVALIDPOS; // but unexpected failure, maybe.
+  }
   // IMEs don't like empty rects, fix here
   if (event.mReply.mRect.width <= 0)
     event.mReply.mRect.width = 1;
   if (event.mReply.mRect.height <= 0)
     event.mReply.mRect.height = 1;
 
   // convert to unclipped screen rect
   nsWindow* refWindow = static_cast<nsWindow*>(
       event.mReply.mFocusedWidget ? event.mReply.mFocusedWidget : mWindow);
   // Result rect is in top level widget coordinates
   refWindow = refWindow->GetTopLevelWindow(false);
-  NS_ENSURE_TRUE(refWindow, E_FAIL);
+  if (!refWindow) {
+    PR_LOG(sTextStoreLog, PR_LOG_ERROR,
+           ("TSF: 0x%p   nsTextStore::GetTextExt() FAILED due to "
+            "no top level window", this));
+    return E_FAIL;
+  }
 
   event.mReply.mRect.MoveBy(refWindow->WidgetToScreenOffset());
 
   // get bounding screen rect to test for clipping
-  HRESULT hr = GetScreenExt(vcView, prc);
-  NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
+  if (!GetScreenExtInternal(*prc)) {
+    PR_LOG(sTextStoreLog, PR_LOG_ERROR,
+           ("TSF: 0x%p   nsTextStore::GetTextExt() FAILED due to "
+            "GetScreenExtInternal() failure", this));
+    return E_FAIL;
+  }
 
   // clip text rect to bounding rect
   RECT textRect;
   ::SetRect(&textRect, event.mReply.mRect.x, event.mReply.mRect.y,
             event.mReply.mRect.XMost(), event.mReply.mRect.YMost());
   if (!::IntersectRect(prc, prc, &textRect))
     // Text is not visible
     ::SetRectEmpty(prc);
 
   // not equal if text rect was clipped
   *pfClipped = !::EqualRect(prc, &textRect);
+
+  PR_LOG(sTextStoreLog, PR_LOG_ALWAYS,
+         ("TSF: 0x%p   nsTextStore::GetTextExt() succeeded: "
+          "*prc={ left=%ld, top=%ld, right=%ld, bottom=%ld }, *pfClipped=%s",
+          this, prc->left, prc->top, prc->right, prc->bottom,
+          GetBoolName(*pfClipped)));
+
   return S_OK;
 }
 
 STDMETHODIMP
 nsTextStore::GetScreenExt(TsViewCookie vcView,
                           RECT *prc)
 {
-  NS_ENSURE_TRUE(TEXTSTORE_DEFAULT_VIEW == vcView && prc, E_INVALIDARG);
+  PR_LOG(sTextStoreLog, PR_LOG_ALWAYS,
+         ("TSF: 0x%p nsTextStore::GetScreenExt(vcView=%ld, prc=0x%p)",
+          this, vcView, prc));
+
+  if (vcView != TEXTSTORE_DEFAULT_VIEW) {
+    PR_LOG(sTextStoreLog, PR_LOG_ERROR,
+           ("TSF: 0x%p   nsTextStore::GetScreenExt() FAILED due to "
+            "called with invalid view", this));
+    return E_INVALIDARG;
+  }
+
+  if (!prc) {
+    PR_LOG(sTextStoreLog, PR_LOG_ERROR,
+           ("TSF: 0x%p   nsTextStore::GetScreenExt() FAILED due to "
+            "null argument", this));
+    return E_INVALIDARG;
+  }
+
+  if (!GetScreenExtInternal(*prc)) {
+    PR_LOG(sTextStoreLog, PR_LOG_ERROR,
+           ("TSF: 0x%p   nsTextStore::GetScreenExt() FAILED due to "
+            "GetScreenExtInternal() failure", this));
+    return E_FAIL;
+  }
+
+  PR_LOG(sTextStoreLog, PR_LOG_ALWAYS,
+         ("TSF: 0x%p   nsTextStore::GetScreenExt() succeeded: "
+          "*prc={ left=%ld, top=%ld, right=%ld, bottom=%ld }",
+          this, prc->left, prc->top, prc->right, prc->bottom));
+  return S_OK;
+}
+
+bool
+nsTextStore::GetScreenExtInternal(RECT &aScreenExt)
+{
+  PR_LOG(sTextStoreLog, PR_LOG_DEBUG,
+         ("TSF: 0x%p   nsTextStore::GetScreenExtInternal()", this));
+
   // use NS_QUERY_EDITOR_RECT to get rect in system, screen coordinates
   nsQueryContentEvent event(true, NS_QUERY_EDITOR_RECT, mWindow);
   mWindow->InitEvent(event);
   mWindow->DispatchWindowEvent(&event);
-  NS_ENSURE_TRUE(event.mSucceeded, E_FAIL);
+  if (!event.mSucceeded) {
+    PR_LOG(sTextStoreLog, PR_LOG_ERROR,
+           ("TSF: 0x%p   nsTextStore::GetScreenExtInternal() FAILED due to "
+            "NS_QUERY_EDITOR_RECT failure", this));
+    return false;
+  }
 
   nsWindow* refWindow = static_cast<nsWindow*>(
       event.mReply.mFocusedWidget ? event.mReply.mFocusedWidget : mWindow);
   // Result rect is in top level widget coordinates
   refWindow = refWindow->GetTopLevelWindow(false);
-  NS_ENSURE_TRUE(refWindow, E_FAIL);
+  if (!refWindow) {
+    PR_LOG(sTextStoreLog, PR_LOG_ERROR,
+           ("TSF: 0x%p   nsTextStore::GetScreenExtInternal() FAILED due to "
+            "no top level window", this));
+    return false;
+  }
 
   nsIntRect boundRect;
-  nsresult rv = refWindow->GetClientBounds(boundRect);
-  NS_ENSURE_SUCCESS(rv, E_FAIL);
+  if (NS_FAILED(refWindow->GetClientBounds(boundRect))) {
+    PR_LOG(sTextStoreLog, PR_LOG_ERROR,
+           ("TSF: 0x%p   nsTextStore::GetScreenExtInternal() FAILED due to "
+            "failed to get the client bounds", this));
+    return false;
+  }
 
   boundRect.MoveTo(0, 0);
 
   // Clip frame rect to window rect
   boundRect.IntersectRect(event.mReply.mRect, boundRect);
   if (!boundRect.IsEmpty()) {
     boundRect.MoveBy(refWindow->WidgetToScreenOffset());
-    ::SetRect(prc, boundRect.x, boundRect.y,
+    ::SetRect(&aScreenExt, boundRect.x, boundRect.y,
               boundRect.XMost(), boundRect.YMost());
   } else {
-    ::SetRectEmpty(prc);
+    ::SetRectEmpty(&aScreenExt);
   }
-  return S_OK;
+
+  PR_LOG(sTextStoreLog, PR_LOG_DEBUG,
+         ("TSF: 0x%p   nsTextStore::GetScreenExtInternal() succeeded: "
+          "aScreenExt={ left=%ld, top=%ld, right=%ld, bottom=%ld }",
+          this, aScreenExt.left, aScreenExt.top,
+          aScreenExt.right, aScreenExt.bottom));
+  return true;
 }
 
 STDMETHODIMP
 nsTextStore::GetWnd(TsViewCookie vcView,
                     HWND *phwnd)
 {
-  NS_ENSURE_TRUE(TEXTSTORE_DEFAULT_VIEW == vcView && phwnd, E_INVALIDARG);
+  PR_LOG(sTextStoreLog, PR_LOG_ALWAYS,
+         ("TSF: 0x%p nsTextStore::GetWnd(vcView=%ld, phwnd=0x%p), mWindow=0x%p",
+          this, vcView, phwnd, mWindow));
+
+  if (vcView != TEXTSTORE_DEFAULT_VIEW) {
+    PR_LOG(sTextStoreLog, PR_LOG_ERROR,
+           ("TSF: 0x%p   nsTextStore::GetWnd() FAILED due to "
+            "called with invalid view", this));
+    return E_INVALIDARG;
+  }
+
+  if (!phwnd) {
+    PR_LOG(sTextStoreLog, PR_LOG_ERROR,
+           ("TSF: 0x%p   nsTextStore::GetScreenExt() FAILED due to "
+            "null argument", this));
+    return E_INVALIDARG;
+  }
+
   *phwnd = mWindow->GetWindowHandle();
+
+  PR_LOG(sTextStoreLog, PR_LOG_ALWAYS,
+         ("TSF: 0x%p   nsTextStore::GetWnd() succeeded: *phwnd=0x%p",
+          this, static_cast<void*>(*phwnd)));
   return S_OK;
 }
 
 STDMETHODIMP
 nsTextStore::InsertTextAtSelection(DWORD dwFlags,
                                    const WCHAR *pchText,
                                    ULONG cch,
                                    LONG *pacpStart,
                                    LONG *pacpEnd,
                                    TS_TEXTCHANGE *pChange)
 {
   PR_LOG(sTextStoreLog, PR_LOG_ALWAYS,
-         ("TSF: InsertTextAtSelection, cch=%lu\n", cch));
-  NS_ENSURE_TRUE(TS_LF_READWRITE == (mLock & TS_LF_READWRITE), TS_E_NOLOCK);
-  NS_ENSURE_TRUE(!cch || pchText, E_INVALIDARG);
+         ("TSF: 0x%p nsTextStore::InsertTextAtSelection(dwFlags=%s, "
+          "pchText=0x%p \"%s\", cch=%lu, pacpStart=0x%p, pacpEnd=0x%p, "
+          "pChange=0x%p), %s",
+          this, dwFlags == 0 ? "0" :
+                dwFlags == TF_IAS_NOQUERY ? "TF_IAS_NOQUERY" :
+                dwFlags == TF_IAS_QUERYONLY ? "TF_IAS_QUERYONLY" : "Unknown",
+          pchText,
+          pchText && cch ? NS_ConvertUTF16toUTF8(pchText, cch).get() : "",
+          cch, pacpStart, pacpEnd, pChange,
+          mCompositionView ? "there is composition view" :
+                             "there is no composition view"));
+
+  if (!IsReadWriteLocked()) {
+    PR_LOG(sTextStoreLog, PR_LOG_ERROR,
+           ("TSF: 0x%p   nsTextStore::InsertTextAtSelection() FAILED due to "
+            "not locked (read)", this));
+    return TS_E_NOLOCK;
+  }
+
+  if (cch && !pchText) {
+    PR_LOG(sTextStoreLog, PR_LOG_ERROR,
+           ("TSF: 0x%p   nsTextStore::InsertTextAtSelection() FAILED due to "
+            "null pchText", this));
+    return E_INVALIDARG;
+  }
 
   // Get selection first
   TS_SELECTION_ACP sel;
-  ULONG selFetched;
-  NS_ENSURE_TRUE(SUCCEEDED(GetSelection(
-      TS_DEFAULT_SELECTION, 1, &sel, &selFetched)) && selFetched, E_FAIL);
+  if (!GetSelectionInternal(sel)) {
+    PR_LOG(sTextStoreLog, PR_LOG_ERROR,
+           ("TSF: 0x%p   nsTextStore::InsertTextAtSelection() FAILED due to "
+            "GetSelectionInternal() failure", this));
+    return E_FAIL;
+  }
+
   if (TS_IAS_QUERYONLY == dwFlags) {
-    NS_ENSURE_TRUE(pacpStart && pacpEnd, E_INVALIDARG);
+    if (!pacpStart || !pacpEnd) {
+      PR_LOG(sTextStoreLog, PR_LOG_ERROR,
+             ("TSF: 0x%p   nsTextStore::InsertTextAtSelection() FAILED due to "
+              "null argument", this));
+      return E_INVALIDARG;
+    }
     // Simulate text insertion
     *pacpStart = sel.acpStart;
     *pacpEnd = sel.acpEnd;
     if (pChange) {
       pChange->acpStart = sel.acpStart;
       pChange->acpOldEnd = sel.acpEnd;
       pChange->acpNewEnd = sel.acpStart + cch;
     }
   } else {
-    NS_ENSURE_TRUE(pChange, E_INVALIDARG);
-    NS_ENSURE_TRUE(TS_IAS_NOQUERY == dwFlags || (pacpStart && pacpEnd),
-                   E_INVALIDARG);
+    if (!pChange) {
+      PR_LOG(sTextStoreLog, PR_LOG_ERROR,
+             ("TSF: 0x%p   nsTextStore::InsertTextAtSelection() FAILED due to "
+              "null pChange", this));
+      return E_INVALIDARG;
+    }
+    if (TS_IAS_NOQUERY != dwFlags && (!pacpStart || !pacpEnd)) {
+      PR_LOG(sTextStoreLog, PR_LOG_ERROR,
+             ("TSF: 0x%p   nsTextStore::InsertTextAtSelection() FAILED due to "
+              "null argument", this));
+      return E_INVALIDARG;
+    }
+
     if (mCompositionView) {
       // Emulate text insertion during compositions, because during a
       // composition, editor expects the whole composition string to
       // be sent in NS_TEXT_TEXT, not just the inserted part.
       // The actual NS_TEXT_TEXT will be sent in SetSelection or
       // OnUpdateComposition.
       mCompositionString.Replace(uint32_t(sel.acpStart - mCompositionStart),
                                  sel.acpEnd - sel.acpStart, pchText, cch);
 
       mCompositionSelection.acpStart += cch;
       mCompositionSelection.acpEnd = mCompositionSelection.acpStart;
       mCompositionSelection.style.ase = TS_AE_END;
       PR_LOG(sTextStoreLog, PR_LOG_ALWAYS,
-             ("TSF: InsertTextAtSelection, replaced=%lu-%lu\n",
+             ("TSF: 0x%p   nsTextStore::InsertTextAtSelection() replaced a "
+              "part of (%lu-%lu) the composition string, waiting "
+              "SetSelection() or OnUpdateComposition()...", this,
               sel.acpStart - mCompositionStart,
               sel.acpEnd - mCompositionStart));
     } else {
       // Use a temporary composition to contain the text
+      PR_LOG(sTextStoreLog, PR_LOG_ALWAYS,
+             ("TSF: 0x%p   nsTextStore::InsertTextAtSelection() dispatching "
+              "a compositionstart event...", this));
       nsCompositionEvent compEvent(true, NS_COMPOSITION_START, mWindow);
       mWindow->InitEvent(compEvent);
       mWindow->DispatchWindowEvent(&compEvent);
       if (mWindow && !mWindow->Destroyed()) {
+        PR_LOG(sTextStoreLog, PR_LOG_ALWAYS,
+               ("TSF: 0x%p   nsTextStore::InsertTextAtSelection() dispatching "
+                "a compositionupdate event...", this));
         compEvent.message = NS_COMPOSITION_UPDATE;
         compEvent.data.Assign(pchText, cch);
         mWindow->DispatchWindowEvent(&compEvent);
         if (mWindow && !mWindow->Destroyed()) {
+          PR_LOG(sTextStoreLog, PR_LOG_ALWAYS,
+                 ("TSF: 0x%p   nsTextStore::InsertTextAtSelection() "
+                  "dispatching a text event...", this));
           nsTextEvent event(true, NS_TEXT_TEXT, mWindow);
           mWindow->InitEvent(event);
           event.theText.Assign(pchText, cch);
           event.theText.ReplaceSubstring(NS_LITERAL_STRING("\r\n"),
                                          NS_LITERAL_STRING("\n"));
           mWindow->DispatchWindowEvent(&event);
           if (mWindow && !mWindow->Destroyed()) {
+            PR_LOG(sTextStoreLog, PR_LOG_ALWAYS,
+                   ("TSF: 0x%p   nsTextStore::InsertTextAtSelection() "
+                    "dispatching a compositionend event...", this));
             compEvent.message = NS_COMPOSITION_END;
             mWindow->DispatchWindowEvent(&compEvent);
           }
         }
       }
     }
     pChange->acpStart = sel.acpStart;
     pChange->acpOldEnd = sel.acpEnd;
     // Get new selection
-    NS_ENSURE_TRUE(SUCCEEDED(GetSelection(
-        TS_DEFAULT_SELECTION, 1, &sel, &selFetched)) && selFetched, E_FAIL);
+    if (!GetSelectionInternal(sel)) {
+      PR_LOG(sTextStoreLog, PR_LOG_ERROR,
+             ("TSF: 0x%p   nsTextStore::InsertTextAtSelection() FAILED due to "
+              "GetSelectionInternal() failure after inserted the text", this));
+      return E_FAIL;
+    }
     pChange->acpNewEnd = sel.acpEnd;
     if (TS_IAS_NOQUERY != dwFlags) {
       *pacpStart = pChange->acpStart;
       *pacpEnd = pChange->acpNewEnd;
     }
   }
   PR_LOG(sTextStoreLog, PR_LOG_ALWAYS,
-         ("TSF: InsertTextAtSelection SUCCEEDED\n"));
+         ("TSF: 0x%p   nsTextStore::InsertTextAtSelection() succeeded: "
+          "*pacpStart=%ld, *pacpEnd=%ld, "
+          "*pChange={ acpStart=%ld, acpOldEnd=%ld, acpNewEnd=%ld })",
+          this, pacpStart ? *pacpStart : 0, pacpEnd ? *pacpEnd : 0,
+          pChange ? pChange->acpStart: 0, pChange ? pChange->acpOldEnd : 0,
+          pChange ? pChange->acpNewEnd : 0));
   return S_OK;
 }
 
 STDMETHODIMP
 nsTextStore::InsertEmbeddedAtSelection(DWORD dwFlags,
                                        IDataObject *pDataObject,
                                        LONG *pacpStart,
                                        LONG *pacpEnd,
                                        TS_TEXTCHANGE *pChange)
 {
+  PR_LOG(sTextStoreLog, PR_LOG_ALWAYS,
+         ("TSF: 0x%p nsTextStore::InsertEmbeddedAtSelection() called "
+          "but not supported (E_NOTIMPL)", this));
+
   // embedded objects are not supported
   return E_NOTIMPL;
 }
 
 HRESULT
 nsTextStore::OnStartCompositionInternal(ITfCompositionView* pComposition,
                                         ITfRange* aRange,
                                         bool aPreserveSelection)
 {
+  PR_LOG(sTextStoreLog, PR_LOG_DEBUG,
+         ("TSF: 0x%p   nsTextStore::OnStartCompositionInternal("
+          "pComposition=0x%p, aRange=0x%p, aPreserveSelection=%s), "
+          "mCompositionView=0x%p",
+          this, pComposition, aRange, GetBoolName(aPreserveSelection),
+          mCompositionView));
+
   mCompositionView = pComposition;
   HRESULT hr = GetRangeExtent(aRange, &mCompositionStart, &mCompositionLength);
-  NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
+  if (FAILED(hr)) {
+    PR_LOG(sTextStoreLog, PR_LOG_ERROR,
+           ("TSF: 0x%p   nsTextStore::OnStartCompositionInternal() FAILED due "
+            "to GetRangeExtent() failure", this));
+    return hr;
+  }
 
-  PR_LOG(sTextStoreLog, PR_LOG_ALWAYS,
-         ("TSF: OnStartComposition, range=%ld-%ld\n", mCompositionStart,
-          mCompositionStart + mCompositionLength));
+  PR_LOG(sTextStoreLog, PR_LOG_DEBUG,
+         ("TSF: 0x%p   nsTextStore::OnStartCompositionInternal(), "
+          "mCompositionStart=%ld, mCompositionLength=%ld",
+          this, mCompositionStart, mCompositionLength));
+
+  PR_LOG(sTextStoreLog, PR_LOG_DEBUG,
+         ("TSF: 0x%p   nsTextStore::OnStartCompositionInternal(), "
+          "dispatching selectionset event..."));
 
   // Select composition range so the new composition replaces the range
   nsSelectionEvent selEvent(true, NS_SELECTION_SET, mWindow);
   mWindow->InitEvent(selEvent);
   selEvent.mOffset = uint32_t(mCompositionStart);
   selEvent.mLength = uint32_t(mCompositionLength);
   selEvent.mReversed = false;
   mWindow->DispatchWindowEvent(&selEvent);
-  NS_ENSURE_TRUE(selEvent.mSucceeded, E_FAIL);
+  if (!selEvent.mSucceeded) {
+    PR_LOG(sTextStoreLog, PR_LOG_ERROR,
+           ("TSF: 0x%p   nsTextStore::OnStartCompositionInternal() FAILED due "
+            "to NS_SELECTION_SET failure", this));
+    return E_FAIL;
+  }
 
   // Set up composition
   nsQueryContentEvent queryEvent(true, NS_QUERY_SELECTED_TEXT, mWindow);
   mWindow->InitEvent(queryEvent);
   mWindow->DispatchWindowEvent(&queryEvent);
-  NS_ENSURE_TRUE(queryEvent.mSucceeded, E_FAIL);
+  if (!queryEvent.mSucceeded) {
+    PR_LOG(sTextStoreLog, PR_LOG_ERROR,
+           ("TSF: 0x%p   nsTextStore::OnStartCompositionInternal() FAILED due "
+            "to NS_QUERY_SELECTED_TEXT failure", this));
+    return E_FAIL;
+  }
+
+  PR_LOG(sTextStoreLog, PR_LOG_DEBUG,
+         ("TSF: 0x%p   nsTextStore::OnStartCompositionInternal(), "
+          "dispatching compositionstart event..."));
+
   mCompositionString = queryEvent.mReply.mString;
   if (!aPreserveSelection) {
     mCompositionSelection.acpStart = mCompositionStart;
     mCompositionSelection.acpEnd = mCompositionStart + mCompositionLength;
     mCompositionSelection.style.ase = TS_AE_END;
     mCompositionSelection.style.fInterimChar = FALSE;
   }
   nsCompositionEvent event(true, NS_COMPOSITION_START, mWindow);
   mWindow->InitEvent(event);
   mWindow->DispatchWindowEvent(&event);
+
+  PR_LOG(sTextStoreLog, PR_LOG_DEBUG,
+         ("TSF: 0x%p   nsTextStore::OnStartCompositionInternal() succeeded: "
+          "mCompositionStart=%ld, mCompositionLength=%ld, "
+          "mCompositionSelection={ acpStart=%ld, acpEnd=%ld, style.ase=%s, "
+          "style.iInterimChar=%s }",
+          this, mCompositionStart, mCompositionLength,
+          mCompositionSelection.acpStart, mCompositionSelection.acpEnd,
+          GetActiveSelEndName(mCompositionSelection.style.ase),
+          GetBoolName(mCompositionSelection.style.fInterimChar)));
   return S_OK;
 }
 
 static uint32_t
 GetLayoutChangeIntervalTime()
 {
   static int32_t sTime = -1;
   if (sTime > 0)
@@ -1324,120 +2230,233 @@ GetLayoutChangeIntervalTime()
     Preferences::GetInt("intl.tsf.on_layout_change_interval", 100));
   return uint32_t(sTime);
 }
 
 STDMETHODIMP
 nsTextStore::OnStartComposition(ITfCompositionView* pComposition,
                                 BOOL* pfOk)
 {
+  PR_LOG(sTextStoreLog, PR_LOG_ALWAYS,
+         ("TSF: 0x%p nsTextStore::OnStartComposition(pComposition=0x%p, "
+          "pfOk=0x%p), mCompositionView=0x%p",
+          this, pComposition, pfOk, mCompositionView));
+
   *pfOk = FALSE;
 
   // Only one composition at a time
-  if (mCompositionView)
+  if (mCompositionView) {
+    PR_LOG(sTextStoreLog, PR_LOG_ERROR,
+           ("TSF: 0x%p   nsTextStore::OnStartComposition() FAILED due to "
+            "there is another composition already (but returns S_OK)", this));
     return S_OK;
+  }
 
   nsRefPtr<ITfRange> range;
   HRESULT hr = pComposition->GetRange(getter_AddRefs(range));
-  NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
+  if (FAILED(hr)) {
+    PR_LOG(sTextStoreLog, PR_LOG_ERROR,
+           ("TSF: 0x%p   nsTextStore::OnStartComposition() FAILED due to "
+            "pComposition->GetRange() failure", this));
+    return hr;
+  }
   hr = OnStartCompositionInternal(pComposition, range, false);
-  if (FAILED(hr))
+  if (FAILED(hr)) {
+    PR_LOG(sTextStoreLog, PR_LOG_ERROR,
+           ("TSF: 0x%p   nsTextStore::OnStartComposition() FAILED due to "
+            "OnStartCompositionInternal() failure", this));
     return hr;
+  }
 
   NS_ASSERTION(!mCompositionTimer, "The timer is alive!");
   mCompositionTimer = do_CreateInstance(NS_TIMER_CONTRACTID);
   if (mCompositionTimer) {
     mCompositionTimer->InitWithFuncCallback(CompositionTimerCallbackFunc, this,
                                             GetLayoutChangeIntervalTime(),
                                             nsITimer::TYPE_REPEATING_SLACK);
   }
   *pfOk = TRUE;
+  PR_LOG(sTextStoreLog, PR_LOG_ALWAYS,
+         ("TSF: 0x%p   nsTextStore::OnStartComposition() succeeded", this));
   return S_OK;
 }
 
 STDMETHODIMP
 nsTextStore::OnUpdateComposition(ITfCompositionView* pComposition,
                                  ITfRange* pRangeNew)
 {
-  NS_ENSURE_TRUE(mCompositionView &&
-                 mCompositionView == pComposition &&
-                 mDocumentMgr && mContext, E_UNEXPECTED);
+  PR_LOG(sTextStoreLog, PR_LOG_ALWAYS,
+         ("TSF: 0x%p nsTextStore::OnUpdateComposition(pComposition=0x%p, "
+          "pRangeNew=0x%p), mCompositionView=0x%p",
+          this, pComposition, pRangeNew, mCompositionView));
 
-  if (!pRangeNew) // pRangeNew is null when the update is not complete
+  if (!mDocumentMgr || !mContext) {
+    PR_LOG(sTextStoreLog, PR_LOG_ERROR,
+           ("TSF: 0x%p   nsTextStore::OnUpdateComposition() FAILED due to "
+            "not ready for the composition", this));
+    return E_UNEXPECTED;
+  }
+  if (!mCompositionView) {
+    PR_LOG(sTextStoreLog, PR_LOG_ERROR,
+           ("TSF: 0x%p   nsTextStore::OnUpdateComposition() FAILED due to "
+            "no active composition", this));
+    return E_UNEXPECTED;
+  }
+  if (mCompositionView != pComposition) {
+    PR_LOG(sTextStoreLog, PR_LOG_ERROR,
+           ("TSF: 0x%p   nsTextStore::OnUpdateComposition() FAILED due to "
+            "different composition view specified", this));
+    return E_UNEXPECTED;
+  }
+
+  // pRangeNew is null when the update is not complete
+  if (!pRangeNew) {
+    PR_LOG(sTextStoreLog, PR_LOG_ALWAYS,
+           ("TSF: 0x%p   nsTextStore::OnUpdateComposition() succeeded but "
+            "not complete", this));
     return S_OK;
+  }
 
   HRESULT hr = UpdateCompositionExtent(pRangeNew);
-  NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
+  if (FAILED(hr)) {
+    PR_LOG(sTextStoreLog, PR_LOG_ERROR,
+           ("TSF: 0x%p   nsTextStore::OnUpdateComposition() FAILED due to "
+            "UpdateCompositionExtent() failure", this));
+    return hr;
+  }
 
-  return SendTextEventForCompositionString();
+  hr = SendTextEventForCompositionString();
+  if (FAILED(hr)) {
+    PR_LOG(sTextStoreLog, PR_LOG_ERROR,
+           ("TSF: 0x%p   nsTextStore::OnUpdateComposition() FAILED due to "
+            "SendTextEventForCompositionString() failure", this));
+    return hr;
+  }
+
+  PR_LOG(sTextStoreLog, PR_LOG_ALWAYS,
+         ("TSF: 0x%p   nsTextStore::OnUpdateComposition() succeeded: "
+          "mCompositionStart=%ld, mCompositionLength=%ld, "
+          "mCompositionSelection={ acpStart=%ld, acpEnd=%ld, style.ase=%s, "
+          "style.iInterimChar=%s }, mCompositionString=\"%s\"",
+          this, mCompositionStart, mCompositionLength,
+          mCompositionSelection.acpStart, mCompositionSelection.acpEnd,
+          GetActiveSelEndName(mCompositionSelection.style.ase),
+          GetBoolName(mCompositionSelection.style.fInterimChar),
+          NS_ConvertUTF16toUTF8(mCompositionString).get()));
+  return S_OK;
 }
 
 STDMETHODIMP
 nsTextStore::OnEndComposition(ITfCompositionView* pComposition)
 {
-  NS_ENSURE_TRUE(mCompositionView &&
-                 mCompositionView == pComposition, E_UNEXPECTED);
   PR_LOG(sTextStoreLog, PR_LOG_ALWAYS,
-         ("TSF: OnEndComposition\n"));
+         ("TSF: 0x%p nsTextStore::OnEndComposition(pComposition=0x%p), "
+          "mCompositionView=0x%p, mCompositionString=\"%s\"",
+          this, pComposition, mCompositionView,
+          NS_ConvertUTF16toUTF8(mCompositionString).get()));
+
+  if (!mCompositionView) {
+    PR_LOG(sTextStoreLog, PR_LOG_ERROR,
+           ("TSF: 0x%p   nsTextStore::OnEndComposition() FAILED due to "
+            "no active composition", this));
+    return E_UNEXPECTED;
+  }
+
+  if (mCompositionView != pComposition) {
+    PR_LOG(sTextStoreLog, PR_LOG_ERROR,
+           ("TSF: 0x%p   nsTextStore::OnEndComposition() FAILED due to "
+            "different composition view specified", this));
+    return E_UNEXPECTED;
+  }
 
   // Clear the saved text event
   SaveTextEvent(nullptr);
 
   if (mCompositionTimer) {
     mCompositionTimer->Cancel();
     mCompositionTimer = nullptr;
   }
 
   if (mCompositionString != mLastDispatchedCompositionString) {
+    PR_LOG(sTextStoreLog, PR_LOG_ALWAYS,
+           ("TSF: 0x%p   nsTextStore::OnEndComposition(), "
+            "dispatching compositionupdate event...", this));
     nsCompositionEvent compositionUpdate(true, NS_COMPOSITION_UPDATE,
                                          mWindow);
     mWindow->InitEvent(compositionUpdate);
     compositionUpdate.data = mCompositionString;
     mLastDispatchedCompositionString = mCompositionString;
     mWindow->DispatchWindowEvent(&compositionUpdate);
     if (!mWindow || mWindow->Destroyed()) {
       PR_LOG(sTextStoreLog, PR_LOG_ALWAYS,
-             ("TSF: CompositionUpdate caused aborting compositionend\n"));
+             ("TSF: 0x%p   nsTextStore::OnEndComposition(), "
+              "succeeded, but the widget has gone", this));
       return S_OK;
     }
   }
 
+  PR_LOG(sTextStoreLog, PR_LOG_ALWAYS,
+         ("TSF: 0x%p   nsTextStore::OnEndComposition(), "
+          "dispatching text event...", this));
+
   // Use NS_TEXT_TEXT to commit composition string
   nsTextEvent textEvent(true, NS_TEXT_TEXT, mWindow);
   mWindow->InitEvent(textEvent);
   textEvent.theText = mCompositionString;
   textEvent.theText.ReplaceSubstring(NS_LITERAL_STRING("\r\n"),
                                      NS_LITERAL_STRING("\n"));
   mWindow->DispatchWindowEvent(&textEvent);
 
   if (!mWindow || mWindow->Destroyed()) {
     PR_LOG(sTextStoreLog, PR_LOG_ALWAYS,
-           ("TSF: Text event caused aborting compositionend\n"));
+           ("TSF: 0x%p   nsTextStore::OnEndComposition(), "
+            "succeeded, but the widget has gone", this));
     return S_OK;
   }
 
+  PR_LOG(sTextStoreLog, PR_LOG_ALWAYS,
+         ("TSF: 0x%p   nsTextStore::OnEndComposition(), "
+          "dispatching compositionend event...", this));
+
   nsCompositionEvent event(true, NS_COMPOSITION_END, mWindow);
   event.data = mLastDispatchedCompositionString;
   mWindow->InitEvent(event);
   mWindow->DispatchWindowEvent(&event);
 
+  if (!mWindow || mWindow->Destroyed()) {
+    PR_LOG(sTextStoreLog, PR_LOG_ALWAYS,
+           ("TSF: 0x%p   nsTextStore::OnEndComposition(), "
+            "succeeded, but the widget has gone", this));
+    return S_OK;
+  }
+
   mCompositionView = NULL;
   mCompositionString.Truncate(0);
   mLastDispatchedCompositionString.Truncate();
 
   // Maintain selection
   SetSelectionInternal(&mCompositionSelection);
+
+  PR_LOG(sTextStoreLog, PR_LOG_ALWAYS,
+         ("TSF: 0x%p   nsTextStore::OnEndComposition(), succeeded", this));
   return S_OK;
 }
 
+// static
 nsresult
 nsTextStore::OnFocusChange(bool aFocus,
                            nsWindow* aWindow,
                            IMEState::Enabled aIMEEnabled)
 {
+  PR_LOG(sTextStoreLog, PR_LOG_DEBUG,
+         ("TSF: nsTextStore::OnFocusChange(aFocus=%s, aWindow=0x%p, "
+          "aIMEEnabled=%s), sTsfThreadMgr=0x%p, sTsfTextStore=0x%p",
+          GetBoolName(aFocus), aWindow, GetIMEEnabledName(aIMEEnabled),
+          sTsfThreadMgr, sTsfTextStore));
+
   // no change notifications if TSF is disabled
   if (!sTsfThreadMgr || !sTsfTextStore)
     return NS_ERROR_NOT_AVAILABLE;
 
   if (aFocus) {
     bool bRet = sTsfTextStore->Create(aWindow, aIMEEnabled);
     NS_ENSURE_TRUE(bRet, NS_ERROR_FAILURE);
     NS_ENSURE_TRUE(sTsfTextStore->mDocumentMgr, NS_ERROR_FAILURE);
@@ -1449,85 +2468,136 @@ nsTextStore::OnFocusChange(bool aFocus,
   return NS_OK;
 }
 
 nsresult
 nsTextStore::OnTextChangeInternal(uint32_t aStart,
                                   uint32_t aOldEnd,
                                   uint32_t aNewEnd)
 {
+  PR_LOG(sTextStoreLog, PR_LOG_DEBUG,
+         ("TSF: 0x%p nsTextStore::OnTextChangeInternal(aStart=%lu, "
+          "aOldEnd=%lu, aNewEnd=%lu), mLock=%s, mSink=0x%p, mSinkMask=%s, "
+          "mTextChange={ acpStart=%ld, acpOldEnd=%ld, acpNewEnd=%ld }",
+          this, aStart, aOldEnd, aNewEnd, GetLockFlagNameStr(mLock).get(),
+          mSink, GetSinkMaskNameStr(mSinkMask).get(), mTextChange.acpStart,
+          mTextChange.acpOldEnd, mTextChange.acpNewEnd));
+
   if (!mLock && mSink && 0 != (mSinkMask & TS_AS_TEXT_CHANGE)) {
     mTextChange.acpStart = NS_MIN(mTextChange.acpStart, LONG(aStart));
     mTextChange.acpOldEnd = NS_MAX(mTextChange.acpOldEnd, LONG(aOldEnd));
     mTextChange.acpNewEnd = NS_MAX(mTextChange.acpNewEnd, LONG(aNewEnd));
     ::PostMessageW(mWindow->GetWindowHandle(),
                    WM_USER_TSF_TEXTCHANGE, 0, 0);
   }
   return NS_OK;
 }
 
 void
 nsTextStore::OnTextChangeMsgInternal(void)
 {
+  PR_LOG(sTextStoreLog, PR_LOG_DEBUG,
+         ("TSF: 0x%p nsTextStore::OnTextChangeMsgInternal(), mLock=%s, "
+          "mSink=0x%p, mSinkMask=%s, mTextChange={ acpStart=%ld, "
+          "acpOldEnd=%ld, acpNewEnd=%ld }",
+          this, GetLockFlagNameStr(mLock).get(), mSink,
+          GetSinkMaskNameStr(mSinkMask).get(), mTextChange.acpStart,
+          mTextChange.acpOldEnd, mTextChange.acpNewEnd));
+
   if (!mLock && mSink && 0 != (mSinkMask & TS_AS_TEXT_CHANGE) &&
       PR_INT32_MAX > mTextChange.acpStart) {
+    PR_LOG(sTextStoreLog, PR_LOG_ALWAYS,
+           ("TSF: 0x%p   nsTextStore::OnTextChangeMsgInternal(), calling"
+            "mSink->OnTextChange(0, { acpStart=%ld, acpOldEnd=%ld, "
+            "acpNewEnd=%ld })...", this, mTextChange.acpStart,
+            mTextChange.acpOldEnd, mTextChange.acpNewEnd));
     mSink->OnTextChange(0, &mTextChange);
     mTextChange.acpStart = PR_INT32_MAX;
     mTextChange.acpOldEnd = mTextChange.acpNewEnd = 0;
   }
 }
 
 nsresult
 nsTextStore::OnSelectionChangeInternal(void)
 {
+  PR_LOG(sTextStoreLog, PR_LOG_DEBUG,
+         ("TSF: 0x%p nsTextStore::OnSelectionChangeInternal(), mLock=%s, "
+          "mSink=0x%p, mSinkMask=%s",
+          this, GetLockFlagNameStr(mLock).get(), mSink,
+          GetSinkMaskNameStr(mSinkMask).get()));
+
   if (!mLock && mSink && 0 != (mSinkMask & TS_AS_SEL_CHANGE)) {
+    PR_LOG(sTextStoreLog, PR_LOG_ALWAYS,
+           ("TSF: 0x%p   nsTextStore::OnSelectionChangeInternal(), calling "
+            "mSink->OnSelectionChange()...", this));
     mSink->OnSelectionChange();
   }
   return NS_OK;
 }
 
 nsresult
 nsTextStore::OnCompositionTimer()
 {
   NS_ENSURE_TRUE(mContext, NS_ERROR_FAILURE);
   NS_ENSURE_TRUE(mSink, NS_ERROR_FAILURE);
 
   // XXXmnakano We always call OnLayoutChange for now, but this might use CPU
   // power when the focused editor has very long text. Ideally, we should call
   // this only when the composition string screen position is changed by window
   // moving, resizing. And also reflowing and scrolling the contents.
+  PR_LOG(sTextStoreLog, PR_LOG_ALWAYS,
+         ("TSF: 0x%p   nsTextStore::OnCompositionTimer(), calling "
+          "mSink->OnLayoutChange()...", this));
   HRESULT hr = mSink->OnLayoutChange(TS_LC_CHANGE, TEXTSTORE_DEFAULT_VIEW);
   NS_ENSURE_TRUE(SUCCEEDED(hr), NS_ERROR_FAILURE);
 
   return NS_OK;
 }
 
 void
 nsTextStore::CommitCompositionInternal(bool aDiscard)
 {
+  PR_LOG(sTextStoreLog, PR_LOG_DEBUG,
+         ("TSF: 0x%p nsTextStore::CommitCompositionInternal(aDiscard=%s), "
+          "mLock=%s, mSink=0x%p, mContext=0x%p, mCompositionView=0x%p, "
+          "mCompositionString=\"%s\"",
+          this, GetBoolName(aDiscard), GetLockFlagNameStr(mLock).get(), mSink,
+          mContext, mCompositionView,
+          NS_ConvertUTF16toUTF8(mCompositionString)));
+
   if (mCompositionView && aDiscard) {
     mCompositionString.Truncate(0);
     if (mSink && !mLock) {
       TS_TEXTCHANGE textChange;
       textChange.acpStart = mCompositionStart;
       textChange.acpOldEnd = mCompositionStart + mCompositionLength;
       textChange.acpNewEnd = mCompositionStart;
+      PR_LOG(sTextStoreLog, PR_LOG_ALWAYS,
+             ("TSF: 0x%p   nsTextStore::CommitCompositionInternal(), calling"
+              "mSink->OnTextChange(0, { acpStart=%ld, acpOldEnd=%ld, "
+              "acpNewEnd=%ld })...", this, textChange.acpStart,
+              textChange.acpOldEnd, textChange.acpNewEnd));
       mSink->OnTextChange(0, &textChange);
     }
   }
   // Terminate two contexts, the base context (mContext) and the top
   // if the top context is not the same as the base context
   nsRefPtr<ITfContext> context = mContext;
   do {
     if (context) {
       nsRefPtr<ITfContextOwnerCompositionServices> services;
       context->QueryInterface(IID_ITfContextOwnerCompositionServices,
                               getter_AddRefs(services));
-      if (services)
+      if (services) {
+        PR_LOG(sTextStoreLog, PR_LOG_DEBUG,
+               ("TSF: 0x%p   nsTextStore::CommitCompositionInternal(), "
+                "requesting TerminateComposition() for the context 0x%p...",
+                this, context));
         services->TerminateComposition(NULL);
+      }
     }
     if (context != mContext)
       break;
     if (mDocumentMgr)
       mDocumentMgr->GetTop(getter_AddRefs(context));
   } while (context != mContext);
 }
 
@@ -1542,34 +2612,44 @@ GetCompartment(IUnknown* pUnk,
   nsRefPtr<ITfCompartmentMgr> compMgr;
   pUnk->QueryInterface(IID_ITfCompartmentMgr, getter_AddRefs(compMgr));
   if (!compMgr) return false;
 
   return SUCCEEDED(compMgr->GetCompartment(aID, aCompartment)) &&
          (*aCompartment) != NULL;
 }
 
+// static
 void
 nsTextStore::SetIMEOpenState(bool aState)
 {
-  PR_LOG(sTextStoreLog, PR_LOG_ALWAYS,
-         ("TSF: SetIMEOpenState, state=%lu\n", aState));
+  PR_LOG(sTextStoreLog, PR_LOG_DEBUG,
+         ("TSF: nsTextStore::SetIMEOpenState(aState=%s)", GetBoolName(aState)));
 
   nsRefPtr<ITfCompartment> comp;
   if (!GetCompartment(sTsfThreadMgr,
                       GUID_COMPARTMENT_KEYBOARD_OPENCLOSE,
-                      getter_AddRefs(comp)))
+                      getter_AddRefs(comp))) {
+    PR_LOG(sTextStoreLog, PR_LOG_DEBUG,
+           ("TSF:   nsTextStore::SetIMEOpenState() FAILED due to"
+            "no compartment available"));
     return;
+  }
 
   VARIANT variant;
   variant.vt = VT_I4;
   variant.lVal = aState;
+  PR_LOG(sTextStoreLog, PR_LOG_DEBUG,
+         ("TSF:   nsTextStore::SetIMEOpenState(), setting "
+          "0x%04X to GUID_COMPARTMENT_KEYBOARD_OPENCLOSE...",
+          variant.lVal));
   comp->SetValue(sTsfClientId, &variant);
 }
 
+// static
 bool
 nsTextStore::GetIMEOpenState(void)
 {
   nsRefPtr<ITfCompartment> comp;
   if (!GetCompartment(sTsfThreadMgr,
                       GUID_COMPARTMENT_KEYBOARD_OPENCLOSE,
                       getter_AddRefs(comp)))
     return false;
@@ -1581,92 +2661,143 @@ nsTextStore::GetIMEOpenState(void)
 
   ::VariantClear(&variant); // clear up in case variant.vt != VT_I4
   return false;
 }
 
 void
 nsTextStore::SetInputContextInternal(IMEState::Enabled aState)
 {
-  PR_LOG(sTextStoreLog, PR_LOG_ALWAYS,
-         ("TSF: SetInputContext, state=%ld\n", static_cast<int32_t>(aState)));
+  PR_LOG(sTextStoreLog, PR_LOG_DEBUG,
+         ("TSF: 0x%p nsTextStore::SetInputContextInternal(aState=%s), "
+          "mContext=0x%p",
+          this, GetIMEEnabledName(aState), mContext));
 
   VARIANT variant;
   variant.vt = VT_I4;
   variant.lVal = (aState != IMEState::ENABLED);
 
   // Set two contexts, the base context (mContext) and the top
   // if the top context is not the same as the base context
   nsRefPtr<ITfContext> context = mContext;
   nsRefPtr<ITfCompartment> comp;
   do {
     if (GetCompartment(context, GUID_COMPARTMENT_KEYBOARD_DISABLED,
-                       getter_AddRefs(comp)))
+                       getter_AddRefs(comp))) {
+      PR_LOG(sTextStoreLog, PR_LOG_DEBUG,
+             ("TSF: 0x%p   nsTextStore::SetInputContextInternal(), setting "
+              "0x%04X to GUID_COMPARTMENT_KEYBOARD_DISABLED of context 0x%p...",
+             this, variant.lVal, context));
       comp->SetValue(sTsfClientId, &variant);
+    }
 
     if (context != mContext)
       break;
     if (mDocumentMgr)
       mDocumentMgr->GetTop(getter_AddRefs(context));
   } while (context != mContext);
 }
 
+// static
 void
 nsTextStore::Initialize(void)
 {
 #ifdef PR_LOGGING
-  if (!sTextStoreLog)
+  if (!sTextStoreLog) {
     sTextStoreLog = PR_NewLogModule("nsTextStoreWidgets");
+  }
 #endif
+
+  bool enableTsf = Preferences::GetBool("intl.enable_tsf_support", false);
+  PR_LOG(sTextStoreLog, PR_LOG_ALWAYS,
+    ("TSF: nsTextStore::Initialize(), TSF is %s",
+     enableTsf ? "enabled" : "disabled"));
+  if (!enableTsf) {
+    return;
+  }
+
   if (!sTsfThreadMgr) {
-    bool enableTsf =
-      Preferences::GetBool("intl.enable_tsf_support", false);
-    if (enableTsf) {
-      if (SUCCEEDED(CoCreateInstance(CLSID_TF_ThreadMgr, NULL,
-            CLSCTX_INPROC_SERVER, IID_ITfThreadMgr,
-            reinterpret_cast<void**>(&sTsfThreadMgr)))) {
-        if (FAILED(sTsfThreadMgr->Activate(&sTsfClientId))) {
-          NS_RELEASE(sTsfThreadMgr);
-          NS_WARNING("failed to activate TSF\n");
-        }
-      } else
-        // TSF not installed?
-        NS_WARNING("failed to create TSF manager\n");
+    if (SUCCEEDED(CoCreateInstance(CLSID_TF_ThreadMgr, NULL,
+          CLSCTX_INPROC_SERVER, IID_ITfThreadMgr,
+          reinterpret_cast<void**>(&sTsfThreadMgr)))) {
+      PR_LOG(sTextStoreLog, PR_LOG_ALWAYS,
+        ("TSF:   nsTextStore::Initialize() succeeded to "
+         "create the thread manager, activating..."));
+      if (FAILED(sTsfThreadMgr->Activate(&sTsfClientId))) {
+        PR_LOG(sTextStoreLog, PR_LOG_ERROR,
+          ("TSF:   nsTextStore::Initialize() FAILED to activate, "
+           "releasing the thread manager..."));
+        NS_RELEASE(sTsfThreadMgr);
+      }
     }
+#ifdef PR_LOGGING
+    else {
+      PR_LOG(sTextStoreLog, PR_LOG_ERROR,
+        ("TSF:   nsTextStore::Initialize() FAILED to "
+         "create the thread manager"));
+    }
+#endif // #ifdef PR_LOGGING
   }
   if (sTsfThreadMgr && !sTsfTextStore) {
+    PR_LOG(sTextStoreLog, PR_LOG_ALWAYS,
+      ("TSF:   nsTextStore::Initialize() is creating "
+       "an nsTextStore instance..."));
     sTsfTextStore = new nsTextStore();
-    if (!sTsfTextStore)
-      NS_ERROR("failed to create text store");
   }
   if (sTsfThreadMgr && !sDisplayAttrMgr) {
+    PR_LOG(sTextStoreLog, PR_LOG_ALWAYS,
+      ("TSF:   nsTextStore::Initialize() is creating "
+       "a display attribute manager instance..."));
     HRESULT hr =
       ::CoCreateInstance(CLSID_TF_DisplayAttributeMgr, NULL,
                          CLSCTX_INPROC_SERVER, IID_ITfDisplayAttributeMgr,
                          reinterpret_cast<void**>(&sDisplayAttrMgr));
-    if (FAILED(hr) || !sDisplayAttrMgr)
-      NS_ERROR("failed to create display attribute manager");
+    if (FAILED(hr) || !sDisplayAttrMgr) {
+      PR_LOG(sTextStoreLog, PR_LOG_ERROR,
+        ("TSF:   nsTextStore::Initialize() FAILED to create "
+         "a display attribute manager instance"));
+    }
   }
-  if (sTsfThreadMgr && !sCategoryMgr) {
+  if (sTsfThreadMgr && sDisplayAttrMgr && !sCategoryMgr) {
+    PR_LOG(sTextStoreLog, PR_LOG_ALWAYS,
+      ("TSF:   nsTextStore::Initialize() is creating "
+       "a category manager instance..."));
     HRESULT hr =
       ::CoCreateInstance(CLSID_TF_CategoryMgr, NULL,
                          CLSCTX_INPROC_SERVER, IID_ITfCategoryMgr,
                          reinterpret_cast<void**>(&sCategoryMgr));
-    if (FAILED(hr) || !sCategoryMgr)
-      NS_ERROR("failed to create category manager");
+    if (FAILED(hr) || !sCategoryMgr) {
+      PR_LOG(sTextStoreLog, PR_LOG_ERROR,
+        ("TSF:   nsTextStore::Initialize() FAILED to create "
+         "a category manager instance"));
+      // release the display manager because it cannot work without the
+      // category manager
+      NS_RELEASE(sDisplayAttrMgr);
+    }
   }
   if (sTsfThreadMgr && !sFlushTIPInputMessage) {
     sFlushTIPInputMessage = ::RegisterWindowMessageW(
         NS_LITERAL_STRING("Flush TIP Input Message").get());
   }
+
+  PR_LOG(sTextStoreLog, PR_LOG_ALWAYS,
+    ("TSF:   nsTextStore::Initialize(), sTsfThreadMgr=0x%p, "
+     "sTsfClientId=0x%08X, sTsfTextStore=0x%p, sDisplayAttrMgr=0x%p, "
+     "sCategoryMgr=0x%p",
+     sTsfThreadMgr, sTsfClientId, sTsfTextStore,
+     sDisplayAttrMgr, sCategoryMgr));
 }
 
+// static
 void
 nsTextStore::Terminate(void)
 {
+  PR_LOG(sTextStoreLog, PR_LOG_ALWAYS, ("TSF: nsTextStore::Terminate()"));
+
   NS_IF_RELEASE(sDisplayAttrMgr);
   NS_IF_RELEASE(sCategoryMgr);
   NS_IF_RELEASE(sTsfTextStore);
+  sTsfClientId = 0;
   if (sTsfThreadMgr) {
     sTsfThreadMgr->Deactivate();
     NS_RELEASE(sTsfThreadMgr);
   }
 }
--- a/widget/windows/nsTextStore.h
+++ b/widget/windows/nsTextStore.h
@@ -150,16 +150,29 @@ public:
 
 protected:
   nsTextStore();
   ~nsTextStore();
 
   bool     Create(nsWindow*, IMEState::Enabled);
   bool     Destroy(void);
 
+  bool     IsReadLock(DWORD aLock) const
+  {
+    return (TS_LF_READ == (aLock & TS_LF_READ));
+  }
+  bool     IsReadWriteLock(DWORD aLock) const
+  {
+    return (TS_LF_READWRITE == (aLock & TS_LF_READWRITE));
+  }
+  bool     IsReadLocked() const { return IsReadLock(mLock); }
+  bool     IsReadWriteLocked() const { return IsReadWriteLock(mLock); }
+
+  bool     GetScreenExtInternal(RECT &aScreenExt);
+  bool     GetSelectionInternal(TS_SELECTION_ACP &aSelectionACP);
   // If aDispatchTextEvent is true, this method will dispatch text event if
   // this is called during IME composing.  aDispatchTextEvent should be true
   // only when this is called from SetSelection.  Because otherwise, the text
   // event should not be sent from here.
   HRESULT  SetSelectionInternal(const TS_SELECTION_ACP*,
                                 bool aDispatchTextEvent = false);
   HRESULT  OnStartCompositionInternal(ITfCompositionView*, ITfRange*, bool);
   void     CommitCompositionInternal(bool);
--- a/widget/xpwidgets/PuppetWidget.cpp
+++ b/widget/xpwidgets/PuppetWidget.cpp
@@ -470,20 +470,27 @@ PuppetWidget::OnIMESelectionChange(void)
     }
   }
   return NS_OK;
 }
 
 NS_IMETHODIMP
 PuppetWidget::SetCursor(nsCursor aCursor)
 {
+  if (mCursor == aCursor) {
+    return NS_OK;
+  }
+
   if (!mTabChild ||
       !mTabChild->SendSetCursor(aCursor)) {
     return NS_ERROR_FAILURE;
   }
+
+  mCursor = aCursor;
+
   return NS_OK;
 }
 
 nsresult
 PuppetWidget::Paint()
 {
   NS_ABORT_IF_FALSE(!mDirtyRegion.IsEmpty(), "paint event logic messed up");