Merge last PGO-green changeset of mozilla-inbound to mozilla-central
authorEd Morley <emorley@mozilla.com>
Thu, 27 Sep 2012 11:56:13 +0100
changeset 114541 aacf4867f83067e33f31f81ecaa14a7152a82d1c
parent 114498 b038e9e2023f712021f36ff1a706fc106fb7a2af (current diff)
parent 114540 880c0c02dcc0651085bb72e7312f68c803c11b55 (diff)
child 114542 2310fb3518ee869d6be3940b7419a69dc965f4d1
child 114566 e4dd1fa6d2225c1440752936c3cba38c3e663314
push id1708
push userakeybl@mozilla.com
push dateMon, 19 Nov 2012 21:10:21 +0000
treeherdermozilla-beta@27b14fe50103 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone18.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge last PGO-green changeset of mozilla-inbound to mozilla-central
browser/app/profile/firefox.js
content/base/src/nsBlobProtocolHandler.h
--- a/accessible/src/base/FocusManager.cpp
+++ b/accessible/src/base/FocusManager.cpp
@@ -109,18 +109,20 @@ FocusManager::IsInOrContainsFocus(const 
   }
 
   return eNone;
 }
 
 void
 FocusManager::NotifyOfDOMFocus(nsISupports* aTarget)
 {
-  A11YDEBUG_FOCUS_NOTIFICATION_SUPPORTSTARGET("DOM focus", "DOM focus target",
-                                              aTarget)
+#ifdef DEBUG
+  if (logging::IsEnabled(logging::eFocus))
+    logging::FocusNotificationTarget("DOM focus", "Target", aTarget);
+#endif
 
   mActiveItem = nullptr;
 
   nsCOMPtr<nsINode> targetNode(do_QueryInterface(aTarget));
   if (targetNode) {
     DocAccessible* document =
       GetAccService()->GetDocAccessible(targetNode->OwnerDoc());
     if (document) {
@@ -135,18 +137,20 @@ FocusManager::NotifyOfDOMFocus(nsISuppor
         (this, &FocusManager::ProcessDOMFocus, targetNode);
     }
   }
 }
 
 void
 FocusManager::NotifyOfDOMBlur(nsISupports* aTarget)
 {
-  A11YDEBUG_FOCUS_NOTIFICATION_SUPPORTSTARGET("DOM blur", "DOM blur target",
-                                              aTarget)
+#ifdef DEBUG
+  if (logging::IsEnabled(logging::eFocus))
+    logging::FocusNotificationTarget("DOM blur", "Target", aTarget);
+#endif
 
   mActiveItem = nullptr;
 
   // If DOM document stays focused then fire accessible focus event to process
   // the case when no element within this DOM document will be focused.
   nsCOMPtr<nsINode> targetNode(do_QueryInterface(aTarget));
   if (targetNode && targetNode->OwnerDoc() == FocusedDOMDocument()) {
     nsIDocument* DOMDoc = targetNode->OwnerDoc();
@@ -157,28 +161,33 @@ FocusManager::NotifyOfDOMBlur(nsISupport
         (this, &FocusManager::ProcessDOMFocus, DOMDoc);
     }
   }
 }
 
 void
 FocusManager::ActiveItemChanged(Accessible* aItem, bool aCheckIfActive)
 {
-  A11YDEBUG_FOCUS_NOTIFICATION_ACCTARGET("active item changed",
-                                         "Active item", aItem)
+#ifdef DEBUG
+  if (logging::IsEnabled(logging::eFocus))
+    logging::FocusNotificationTarget("active item changed", "Item", aItem);
+#endif
 
   // Nothing changed, happens for XUL trees and HTML selects.
   if (aItem && aItem == mActiveItem)
     return;
 
   mActiveItem = nullptr;
 
   if (aItem && aCheckIfActive) {
     Accessible* widget = aItem->ContainerWidget();
-    A11YDEBUG_FOCUS_LOG_WIDGET("Active item widget", widget)
+#ifdef DEBUG
+    if (logging::IsEnabled(logging::eFocus))
+      logging::ActiveWidget(widget);
+#endif
     if (!widget || !widget->IsActiveWidget() || !widget->AreItemsOperable())
       return;
   }
   mActiveItem = aItem;
 
   // If active item is changed then fire accessible focus event on it, otherwise
   // if there's no an active item then fire focus event to accessible having
   // DOM focus.
@@ -207,25 +216,30 @@ FocusManager::DispatchFocusEvent(DocAcce
 {
   NS_PRECONDITION(aDocument, "No document for focused accessible!");
   if (aDocument) {
     nsRefPtr<AccEvent> event =
       new AccEvent(nsIAccessibleEvent::EVENT_FOCUS, aTarget,
                    eAutoDetect, AccEvent::eCoalesceOfSameType);
     aDocument->FireDelayedAccessibleEvent(event);
 
-    A11YDEBUG_FOCUS_LOG_ACCTARGET("Focus notification", aTarget)
+#ifdef DEBUG
+    if (logging::IsEnabled(logging::eFocus))
+      logging::FocusDispatched(aTarget);
+#endif
   }
 }
 
 void
 FocusManager::ProcessDOMFocus(nsINode* aTarget)
 {
-  A11YDEBUG_FOCUS_NOTIFICATION_DOMTARGET("Process DOM focus",
-                                         "Notification target", aTarget)
+#ifdef DEBUG
+  if (logging::IsEnabled(logging::eFocus))
+    logging::FocusNotificationTarget("process DOM focus", "Target", aTarget);
+#endif
 
   DocAccessible* document =
     GetAccService()->GetDocAccessible(aTarget->OwnerDoc());
 
   Accessible* target = document->GetAccessibleOrContainer(aTarget);
   if (target && document) {
     // Check if still focused. Otherwise we can end up with storing the active
     // item for control that isn't focused anymore.
@@ -303,18 +317,20 @@ FocusManager::ProcessFocusEvent(AccEvent
     nsRefPtr<AccEvent> menuEndEvent =
       new AccEvent(nsIAccessibleEvent::EVENT_MENU_END, mActiveARIAMenubar,
                    fromUserInputFlag);
     nsEventShell::FireEvent(menuEndEvent);
 
     mActiveARIAMenubar = nullptr;
   }
 
-  A11YDEBUG_FOCUS_NOTIFICATION_ACCTARGET("FIRE FOCUS EVENT", "Focus target",
-                                         target)
+#ifdef DEBUG
+  if (logging::IsEnabled(logging::eFocus))
+    logging::FocusNotificationTarget("fire focus event", "Target", target);
+#endif
 
   nsRefPtr<AccEvent> focusEvent =
     new AccEvent(nsIAccessibleEvent::EVENT_FOCUS, target, fromUserInputFlag);
   nsEventShell::FireEvent(focusEvent);
 
   // Fire scrolling_start event when the document receives the focus if it has
   // an anchor jump. If an accessible within the document receive the focus
   // then null out the anchor jump because it no longer applies.
--- a/accessible/src/base/FocusManager.h
+++ b/accessible/src/base/FocusManager.h
@@ -123,131 +123,9 @@ private:
 private:
   nsRefPtr<Accessible> mActiveItem;
   nsRefPtr<Accessible> mActiveARIAMenubar;
 };
 
 } // namespace a11y
 } // namespace mozilla
 
-
-//#define A11YDEBUG_FOCUS
-
-#ifdef A11YDEBUG_FOCUS
-
-// Util macros (don't use them directly)
-#define A11YDEBUG_FOCUS_STARTBLOCK                                             \
-  printf("  {\n    ");
-
-#define A11YDEBUG_FOCUS_ENDBLOCK                                               \
-  printf("\n  }\n");
-
-#define A11YDEBUG_FOCUS_BLOCKOFFSET                                            \
-  printf("    ");
-
-#define A11YDEBUG_FOCUS_LOG_TIME                                               \
-  {                                                                            \
-    PRIntervalTime time = PR_IntervalNow();                                    \
-    uint32_t mins = (PR_IntervalToSeconds(time) / 60) % 60;                    \
-    uint32_t secs = PR_IntervalToSeconds(time) % 60;                           \
-    uint32_t msecs = PR_IntervalToMilliseconds(time) % 1000;                   \
-    printf("Time: %2d:%2d.%3d\n", mins, secs, msecs);                          \
-  }
-
-#define A11YDEBUG_FOCUS_LOG_DOMNODE(aNode)                                     \
-  if (aNode) {                                                                 \
-    if (aNode->IsElement()) {                                                  \
-      dom::Element* targetElm = aNode->AsElement();                            \
-      nsAutoCString tag;                                                       \
-      targetElm->Tag()->ToUTF8String(tag);                                     \
-      nsAutoCString id;                                                        \
-      nsIAtom* atomid = targetElm->GetID();                                    \
-      if (atomid)                                                              \
-        atomid->ToUTF8String(id);                                              \
-      printf("element %s@id='%s': %p", tag.get(), id.get(), (void*)aNode);     \
-    } else if (aNode->IsNodeOfType(nsINode::eDOCUMENT)) {                      \
-      nsCOMPtr<nsIDocument> document = do_QueryInterface(aNode);               \
-      nsIURI* uri = document->GetDocumentURI();                                \
-      nsAutoCString spec;                                                      \
-      uri->GetSpec(spec);                                                      \
-      printf("document: %p; uri: %s", (void*)aNode, spec.get());               \
-    }                                                                          \
-  }
-
-#define A11YDEBUG_FOCUS_LOG_ACCESSIBLE(aAccessible)                            \
-  printf("accessible: %p; ", (void*)aAccessible);                              \
-  if (aAccessible) {                                                           \
-    nsAutoString role;                                                         \
-    GetAccService()->GetStringRole(aAccessible->Role(), role);                 \
-    nsAutoString name;                                                         \
-    aAccessible->Name(name);                                                   \
-    printf(" role: %s, name: %s; ", NS_ConvertUTF16toUTF8(role).get(),         \
-           NS_ConvertUTF16toUTF8(name).get());                                 \
-    A11YDEBUG_FOCUS_LOG_DOMNODE(aAccessible->GetNode())                        \
-  }
-
-// Public macros
-#define A11YDEBUG_FOCUS_LOG_DOMTARGET(aMsg, aTarget)                           \
-  A11YDEBUG_FOCUS_STARTBLOCK                                                   \
-  printf(aMsg "\n");                                                           \
-  if (aTarget) {                                                               \
-    A11YDEBUG_FOCUS_BLOCKOFFSET                                                \
-    A11YDEBUG_FOCUS_LOG_DOMNODE(aTarget)                                       \
-  }                                                                            \
-  A11YDEBUG_FOCUS_ENDBLOCK
-
-#define A11YDEBUG_FOCUS_LOG_ACCTARGET(aMsg, aTarget)                           \
-  A11YDEBUG_FOCUS_STARTBLOCK                                                   \
-  printf(aMsg "\n");                                                           \
-  A11YDEBUG_FOCUS_BLOCKOFFSET                                                  \
-  A11YDEBUG_FOCUS_LOG_ACCESSIBLE(aTarget)                                      \
-  A11YDEBUG_FOCUS_ENDBLOCK
-
-#define A11YDEBUG_FOCUS_LOG_WIDGET(aMsg, aWidget)                              \
-  A11YDEBUG_FOCUS_STARTBLOCK                                                   \
-  printf(aMsg "\n");                                                           \
-  A11YDEBUG_FOCUS_BLOCKOFFSET                                                  \
-  A11YDEBUG_FOCUS_LOG_ACCESSIBLE(aWidget)                                      \
-  printf("; widget is active: %s, has operable items: %s",                     \
-         (aWidget && aWidget->IsActiveWidget() ? "true" : "false"),            \
-         (aWidget && aWidget->AreItemsOperable() ? "true" : "false"));         \
-  A11YDEBUG_FOCUS_ENDBLOCK
-
-#define A11YDEBUG_FOCUS_NOTIFICATION_SUPPORTSTARGET(aMsg, aTargetMsg, aTarget) \
-  printf("\nA11Y FOCUS: " aMsg ". ");                                          \
-  A11YDEBUG_FOCUS_LOG_TIME                                                     \
-  if (aTarget) {                                                               \
-    A11YDEBUG_FOCUS_STARTBLOCK                                                 \
-    printf(aTargetMsg "\n");                                                   \
-    A11YDEBUG_FOCUS_BLOCKOFFSET                                                \
-    nsCOMPtr<nsINode> targetNode(do_QueryInterface(aTarget));                  \
-    if (targetNode) {                                                          \
-      A11YDEBUG_FOCUS_LOG_DOMNODE(targetNode)                                  \
-    } else {                                                                   \
-      printf("window: %p", (void*)aTarget);                                    \
-    }                                                                          \
-    A11YDEBUG_FOCUS_ENDBLOCK                                                   \
-  }
-
-#define A11YDEBUG_FOCUS_NOTIFICATION_DOMTARGET(aMsg, aTargetMsg, aTarget)      \
-  printf("\nA11Y FOCUS: " aMsg ". ");                                          \
-  A11YDEBUG_FOCUS_LOG_TIME                                                     \
-  A11YDEBUG_FOCUS_LOG_DOMTARGET(aTargetMsg, aTarget)
-
-#define A11YDEBUG_FOCUS_NOTIFICATION_ACCTARGET(aMsg, aTargetMsg, aTarget)      \
-  printf("\nA11Y FOCUS: " aMsg ". ");                                          \
-  A11YDEBUG_FOCUS_LOG_TIME                                                     \
-  A11YDEBUG_FOCUS_LOG_ACCTARGET(aTargetMsg, aTarget)
-
-#define A11YDEBUG_FOCUS_ACTIVEITEMCHANGE_CAUSE(aMsg, aTarget)                  \
-  A11YDEBUG_FOCUS_LOG_ACCTARGET("Caused by: " aMsg, aTarget)
-
-#else
-#define A11YDEBUG_FOCUS_LOG_DOMTARGET(aMsg, aTarget)
-#define A11YDEBUG_FOCUS_LOG_ACCTARGET(aMsg, aTarget)
-#define A11YDEBUG_FOCUS_LOG_WIDGET(aMsg, aWidget)
-#define A11YDEBUG_FOCUS_NOTIFICATION_SUPPORTSTARGET(aMsg, aTargetMsg, aTarget)
-#define A11YDEBUG_FOCUS_NOTIFICATION_DOMTARGET(aMsg, aTargetMsg, aTarget)
-#define A11YDEBUG_FOCUS_NOTIFICATION_ACCTARGET(aMsg, aTargetMsg, aTarget)
-#define A11YDEBUG_FOCUS_ACTIVEITEMCHANGE_CAUSE(aMsg, aTarget)
 #endif
-
-#endif
--- a/accessible/src/base/Logging.cpp
+++ b/accessible/src/base/Logging.cpp
@@ -1,16 +1,17 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set ts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "Logging.h"
 
+#include "Accessible-inl.h"
 #include "AccEvent.h"
 #include "DocAccessible.h"
 #include "nsAccessibilityService.h"
 #include "nsCoreUtils.h"
 #include "OuterDocAccessible.h"
 
 #include "nsDocShellLoadTypes.h"
 #include "nsIChannel.h"
@@ -345,16 +346,17 @@ GetDocLoadEventType(AccEvent* aEvent, ns
 
 ////////////////////////////////////////////////////////////////////////////////
 // namespace logging:: document life cycle logging methods
 
 static const char* sDocLoadTitle = "DOCLOAD";
 static const char* sDocCreateTitle = "DOCCREATE";
 static const char* sDocDestroyTitle = "DOCDESTROY";
 static const char* sDocEventTitle = "DOCEVENT";
+static const char* sFocusTitle = "FOCUS";
 
 void
 logging::DocLoad(const char* aMsg, nsIWebProgress* aWebProgress,
                  nsIRequest* aRequest, uint32_t aStateFlags)
 {
   MsgBegin(sDocLoadTitle, aMsg);
 
   nsCOMPtr<nsIDOMWindow> DOMWindow;
@@ -461,16 +463,82 @@ void
 logging::OuterDocDestroy(OuterDocAccessible* aOuterDoc)
 {
   MsgBegin(sDocDestroyTitle, "outerdoc shutdown");
   logging::Address("outerdoc", aOuterDoc);
   MsgEnd();
 }
 
 void
+logging::FocusNotificationTarget(const char* aMsg, const char* aTargetDescr,
+                                 Accessible* aTarget)
+{
+  MsgBegin(sFocusTitle, aMsg);
+  AccessibleNNode(aTargetDescr, aTarget);
+  MsgEnd();
+}
+
+void
+logging::FocusNotificationTarget(const char* aMsg, const char* aTargetDescr,
+                                 nsINode* aTargetNode)
+{
+  MsgBegin(sFocusTitle, aMsg);
+  Node(aTargetDescr, aTargetNode);
+  MsgEnd();
+}
+
+void
+logging::FocusNotificationTarget(const char* aMsg, const char* aTargetDescr,
+                                 nsISupports* aTargetThing)
+{
+  MsgBegin(sFocusTitle, aMsg);
+
+  if (aTargetThing) {
+    nsCOMPtr<nsINode> targetNode(do_QueryInterface(aTargetThing));
+    if (targetNode)
+      Node(aTargetDescr, targetNode);
+    else
+      printf("    %s: %p, window\n", aTargetDescr,
+             static_cast<void*>(aTargetThing));
+  }
+
+  MsgEnd();
+}
+
+void
+logging::ActiveItemChangeCausedBy(const char* aCause, Accessible* aTarget)
+{
+  SubMsgBegin();
+  printf("    Caused by: %s\n", aCause);
+  AccessibleNNode("Item", aTarget);
+  SubMsgEnd();
+}
+
+void
+logging::ActiveWidget(Accessible* aWidget)
+{
+  SubMsgBegin();
+
+  AccessibleNNode("Widget", aWidget);
+  printf("    Widget is active: %s, has operable items: %s\n",
+         (aWidget && aWidget->IsActiveWidget() ? "true" : "false"),
+         (aWidget && aWidget->AreItemsOperable() ? "true" : "false"));
+
+  SubMsgEnd();
+}
+
+void
+logging::FocusDispatched(Accessible* aTarget)
+{
+  SubMsgBegin();
+  AccessibleNNode("A11y target", aTarget);
+  SubMsgEnd();
+}
+
+void
 logging::SelChange(nsISelection* aSelection, DocAccessible* aDocument)
 {
   nsCOMPtr<nsISelectionPrivate> privSel(do_QueryInterface(aSelection));
 
   int16_t type = 0;
   privSel->GetType(&type);
 
   const char* strType = 0;
@@ -491,26 +559,44 @@ logging::MsgBegin(const char* aTitle, co
 {
   printf("\nA11Y %s: ", aTitle);
 
   va_list argptr;
   va_start(argptr, aMsgText);
   vprintf(aMsgText, argptr);
   va_end(argptr);
 
+  PRIntervalTime time = PR_IntervalNow();
+  uint32_t mins = (PR_IntervalToSeconds(time) / 60) % 60;
+  uint32_t secs = PR_IntervalToSeconds(time) % 60;
+  uint32_t msecs = PR_IntervalToMilliseconds(time) % 1000;
+  printf("; %02d:%02d.%03d", mins, secs, msecs);
+
   printf("\n  {\n");
 }
 
 void
 logging::MsgEnd()
 {
   printf("  }\n");
 }
 
 void
+logging::SubMsgBegin()
+{
+  printf("  {\n");
+}
+
+void
+logging::SubMsgEnd()
+{
+  printf("  }\n");
+}
+
+void
 logging::MsgEntry(const char* aEntryText, ...)
 {
   printf("    ");
 
   va_list argptr;
   va_start(argptr, aEntryText);
   vprintf(aEntryText, argptr);
   va_end(argptr);
@@ -582,16 +668,44 @@ logging::Node(const char* aDescr, nsINod
   if (idAtom)
     idAtom->ToUTF8String(id);
 
   printf("%s: %p, %s@id='%s', idx in parent: %d\n",
          aDescr, static_cast<void*>(elm), tag.get(), id.get(), idxInParent);
 }
 
 void
+logging::AccessibleNNode(const char* aDescr, Accessible* aAccessible)
+{
+  printf("    %s: %p; ", aDescr, static_cast<void*>(aAccessible));
+  if (!aAccessible)
+    return;
+
+  nsAutoString role;
+  GetAccService()->GetStringRole(aAccessible->Role(), role);
+  nsAutoString name;
+  aAccessible->Name(name);
+
+  printf("role: %s, name: '%s';\n", NS_ConvertUTF16toUTF8(role).get(),
+         NS_ConvertUTF16toUTF8(name).get());
+
+  nsAutoCString nodeDescr(aDescr);
+  nodeDescr.AppendLiteral(" node");
+  Node(nodeDescr.get(), aAccessible->GetNode());
+
+  printf("    Document: %p, document node: %p\n",
+         static_cast<void*>(aAccessible->Document()),
+         static_cast<void*>(aAccessible->GetDocumentNode()));
+
+  printf("    Document");
+  LogDocURI(static_cast<nsIDocument*>(aAccessible->GetDocumentNode()));
+  printf("\n");
+}
+
+void
 logging::Stack()
 {
   if (IsEnabled(eStack)) {
     printf("  stack: \n");
     nsTraceRefcntImpl::WalkTheStack(stdout);
   }
 }
 
--- a/accessible/src/base/Logging.h
+++ b/accessible/src/base/Logging.h
@@ -80,29 +80,61 @@ void DocDestroy(const char* aMsg, nsIDoc
                 DocAccessible* aDocument = nullptr);
 
 /**
  * Log the outer document was destroyed.
  */
 void OuterDocDestroy(OuterDocAccessible* OuterDoc);
 
 /**
+ * Log the focus notification target.
+ */
+void FocusNotificationTarget(const char* aMsg, const char* aTargetDescr,
+                             Accessible* aTarget);
+void FocusNotificationTarget(const char* aMsg, const char* aTargetDescr,
+                             nsINode* aTargetNode);
+void FocusNotificationTarget(const char* aMsg, const char* aTargetDescr,
+                             nsISupports* aTargetThing);
+
+/**
+ * Log a cause of active item descendant change (submessage).
+ */
+void ActiveItemChangeCausedBy(const char* aMsg, Accessible* aTarget);
+
+/**
+ * Log the active widget (submessage).
+ */
+void ActiveWidget(Accessible* aWidget);
+
+/**
+ * Log the focus event was dispatched (submessage).
+ */
+void FocusDispatched(Accessible* aTarget);
+
+/**
  * Log the selection change.
  */
 void SelChange(nsISelection* aSelection, DocAccessible* aDocument);
 
 /**
  * Log the message ('title: text' format) on new line. Print the start and end
  * boundaries of the message body designated by '{' and '}' (2 spaces indent for
  * body).
  */
 void MsgBegin(const char* aTitle, const char* aMsgText, ...);
 void MsgEnd();
 
 /**
+ * Print start and end boundaries of the message body designated by '{' and '}'
+ * (2 spaces indent for body).
+ */
+void SubMsgBegin();
+void SubMsgEnd();
+
+/**
  * Log the entry into message body (4 spaces indent).
  */
 void MsgEntry(const char* aEntryText, ...);
 
 /**
  * Log the text, two spaces offset is used.
  */
 void Text(const char* aText);
@@ -113,16 +145,21 @@ void Text(const char* aText);
 void Address(const char* aDescr, Accessible* aAcc);
 
 /**
  * Log the DOM node info as message entry.
  */
 void Node(const char* aDescr, nsINode* aNode);
 
 /**
+ * Log the accessible and its DOM node as a message entry.
+ */
+void AccessibleNNode(const char* aDescr, Accessible* aAccessible);
+
+/**
  * Log the call stack, two spaces offset is used.
  */
 void Stack();
 
 /**
  * Enable logging of the specified modules, all other modules aren't logged.
  */
 void Enable(const nsAFlatCString& aModules);
--- a/accessible/src/generic/Accessible.cpp
+++ b/accessible/src/generic/Accessible.cpp
@@ -612,27 +612,43 @@ Accessible::VisibilityState()
     return states::INVISIBLE;
 
   // Walk the parent frame chain to see if there's invisible parent or the frame
   // is in background tab.
   if (!frame->GetStyleVisibility()->IsVisible())
     return states::INVISIBLE;
 
   nsIFrame* curFrame = frame;
+  nsPoint framePos(0, 0);
   do {
     nsIView* view = curFrame->GetView();
     if (view && view->GetVisibility() == nsViewVisibility_kHide)
       return states::INVISIBLE;
 
     // Offscreen state for background tab content.
     nsIFrame* parentFrame = curFrame->GetParent();
     nsDeckFrame* deckFrame = do_QueryFrame(parentFrame);
     if (deckFrame && deckFrame->GetSelectedBox() != curFrame)
       return states::OFFSCREEN;
 
+    // If contained by scrollable frame then check that at least 12 pixels
+    // around the object is visible, otherwise the object is offscreen.
+    framePos += curFrame->GetPosition();
+    nsIScrollableFrame* scrollableFrame = do_QueryFrame(parentFrame);
+    if (scrollableFrame) {
+      nsRect scrollPortRect = scrollableFrame->GetScrollPortRect();
+      nsRect frameRect(framePos, frame->GetSize());
+      if (!scrollPortRect.Contains(frameRect)) {
+        const nscoord kMinPixels = nsPresContext::CSSPixelsToAppUnits(12);
+        scrollPortRect.Deflate(kMinPixels, kMinPixels);
+        if (!scrollPortRect.Intersects(frameRect))
+          return states::OFFSCREEN;
+      }
+    }
+
     if (!parentFrame) {
       parentFrame = nsLayoutUtils::GetCrossDocParentFrame(curFrame);
       if (parentFrame && !parentFrame->GetStyleVisibility()->IsVisible())
         return states::INVISIBLE;
     }
 
     curFrame = parentFrame;
   } while (curFrame);
@@ -646,27 +662,16 @@ Accessible::VisibilityState()
       !(frame->GetStateBits() & NS_FRAME_OUT_OF_FLOW) &&
       frame->GetRect().IsEmpty()) {
     nsAutoString renderedText;
     frame->GetRenderedText(&renderedText, nullptr, nullptr, 0, 1);
     if (renderedText.IsEmpty())
       return states::INVISIBLE;
   }
 
-  // We need to know if at least a kMinPixels around the object is visible,
-  // otherwise it will be marked states::OFFSCREEN.
-  const uint16_t kMinPixels  = 12;
-  const nsSize frameSize = frame->GetSize();
-  const nsRectVisibility rectVisibility =
-    mDoc->PresShell()->GetRectVisibility(frame, nsRect(nsPoint(0,0), frameSize),
-                                         nsPresContext::CSSPixelsToAppUnits(kMinPixels));
-
-  if (rectVisibility != nsRectVisibility_kVisible)
-    return states::OFFSCREEN;
-
   return 0;
 }
 
 uint64_t
 Accessible::NativeState()
 {
   uint64_t state = 0;
 
--- a/accessible/src/generic/DocAccessible.cpp
+++ b/accessible/src/generic/DocAccessible.cpp
@@ -1225,18 +1225,21 @@ DocAccessible::ARIAActiveDescendantChang
   if (widget && widget->IsActiveWidget()) {
     nsAutoString id;
     if (aElm->GetAttr(kNameSpaceID_None, nsGkAtoms::aria_activedescendant, id)) {
       dom::Element* activeDescendantElm = aElm->OwnerDoc()->GetElementById(id);
       if (activeDescendantElm) {
         Accessible* activeDescendant = GetAccessible(activeDescendantElm);
         if (activeDescendant) {
           FocusMgr()->ActiveItemChanged(activeDescendant, false);
-          A11YDEBUG_FOCUS_ACTIVEITEMCHANGE_CAUSE("ARIA activedescedant changed",
-                                                 activeDescendant)
+#ifdef DEBUG
+          if (logging::IsEnabled(logging::eFocus))
+            logging::ActiveItemChangeCausedBy("ARIA activedescedant changed",
+                                              activeDescendant);
+#endif
         }
       }
     }
   }
 }
 
 void
 DocAccessible::ContentAppended(nsIDocument* aDocument,
@@ -1408,17 +1411,20 @@ DocAccessible::UnbindFromDocument(Access
 {
   NS_ASSERTION(mAccessibleCache.GetWeak(aAccessible->UniqueID()),
                "Unbinding the unbound accessible!");
 
   // Fire focus event on accessible having DOM focus if active item was removed
   // from the tree.
   if (FocusMgr()->IsActiveItem(aAccessible)) {
     FocusMgr()->ActiveItemChanged(nullptr);
-    A11YDEBUG_FOCUS_ACTIVEITEMCHANGE_CAUSE("tree shutdown", aAccessible)
+#ifdef DEBUG
+          if (logging::IsEnabled(logging::eFocus))
+            logging::ActiveItemChangeCausedBy("tree shutdown", aAccessible);
+#endif
   }
 
   // Remove an accessible from node-to-accessible map if it exists there.
   if (aAccessible->IsPrimaryForNode() &&
       mNodeToAccessibleMap.Get(aAccessible->GetNode()) == aAccessible)
     mNodeToAccessibleMap.Remove(aAccessible->GetNode());
 
   void* uniqueID = aAccessible->UniqueID();
--- a/accessible/src/generic/RootAccessible.cpp
+++ b/accessible/src/generic/RootAccessible.cpp
@@ -337,17 +337,20 @@ RootAccessible::ProcessDOMEvent(nsIDOMEv
     bool isEnabled = (state & (states::CHECKED | states::SELECTED)) != 0;
 
     nsRefPtr<AccEvent> accEvent =
       new AccStateChangeEvent(accessible, states::CHECKED, isEnabled);
     nsEventShell::FireEvent(accEvent);
 
     if (isEnabled) {
       FocusMgr()->ActiveItemChanged(accessible);
-      A11YDEBUG_FOCUS_ACTIVEITEMCHANGE_CAUSE("RadioStateChange", accessible)
+#ifdef DEBUG
+      if (logging::IsEnabled(logging::eFocus))
+        logging::ActiveItemChangeCausedBy("RadioStateChange", accessible);
+#endif
     }
 
     return;
   }
 
   if (eventType.EqualsLiteral("CheckboxStateChange")) {
     uint64_t state = accessible->State();
 
@@ -416,52 +419,64 @@ RootAccessible::ProcessDOMEvent(nsIDOMEv
   else if (eventType.EqualsLiteral("DOMMenuInactive")) {
     if (accessible->Role() == roles::MENUPOPUP) {
       nsEventShell::FireEvent(nsIAccessibleEvent::EVENT_MENUPOPUP_END,
                               accessible);
     }
   }
   else if (eventType.EqualsLiteral("DOMMenuItemActive")) {
     FocusMgr()->ActiveItemChanged(accessible);
-    A11YDEBUG_FOCUS_ACTIVEITEMCHANGE_CAUSE("DOMMenuItemActive", accessible)
+#ifdef DEBUG
+    if (logging::IsEnabled(logging::eFocus))
+      logging::ActiveItemChangeCausedBy("DOMMenuItemActive", accessible);
+#endif
   }
   else if (eventType.EqualsLiteral("DOMMenuItemInactive")) {
     // Process DOMMenuItemInactive event for autocomplete only because this is
     // unique widget that may acquire focus from autocomplete popup while popup
     // stays open and has no active item. In case of XUL tree autocomplete
     // popup this event is fired for tree accessible.
     Accessible* widget =
       accessible->IsWidget() ? accessible : accessible->ContainerWidget();
     if (widget && widget->IsAutoCompletePopup()) {
       FocusMgr()->ActiveItemChanged(nullptr);
-      A11YDEBUG_FOCUS_ACTIVEITEMCHANGE_CAUSE("DOMMenuItemInactive", accessible)
+#ifdef DEBUG
+      if (logging::IsEnabled(logging::eFocus))
+        logging::ActiveItemChangeCausedBy("DOMMenuItemInactive", accessible);
+#endif
     }
   }
   else if (eventType.EqualsLiteral("DOMMenuBarActive")) {  // Always from user input
     nsEventShell::FireEvent(nsIAccessibleEvent::EVENT_MENU_START,
                             accessible, eFromUserInput);
 
     // Notify of active item change when menubar gets active and if it has
     // current item. This is a case of mouseover (set current menuitem) and
     // mouse click (activate the menubar). If menubar doesn't have current item
     // (can be a case of menubar activation from keyboard) then ignore this
     // notification because later we'll receive DOMMenuItemActive event after
     // current menuitem is set.
     Accessible* activeItem = accessible->CurrentItem();
     if (activeItem) {
       FocusMgr()->ActiveItemChanged(activeItem);
-      A11YDEBUG_FOCUS_ACTIVEITEMCHANGE_CAUSE("DOMMenuBarActive", accessible)
+#ifdef DEBUG
+      if (logging::IsEnabled(logging::eFocus))
+        logging::ActiveItemChangeCausedBy("DOMMenuBarActive", accessible);
+#endif
     }
   }
   else if (eventType.EqualsLiteral("DOMMenuBarInactive")) {  // Always from user input
     nsEventShell::FireEvent(nsIAccessibleEvent::EVENT_MENU_END,
                             accessible, eFromUserInput);
 
     FocusMgr()->ActiveItemChanged(nullptr);
-    A11YDEBUG_FOCUS_ACTIVEITEMCHANGE_CAUSE("DOMMenuBarInactive", accessible)
+#ifdef DEBUG
+    if (logging::IsEnabled(logging::eFocus))
+      logging::ActiveItemChangeCausedBy("DOMMenuBarInactive", accessible);
+#endif
   }
   else if (eventType.EqualsLiteral("ValueChange")) {
     targetDocument->
       FireDelayedAccessibleEvent(nsIAccessibleEvent::EVENT_VALUE_CHANGE,
                                  targetNode, AccEvent::eRemoveDupes);
   }
 #ifdef DEBUG_DRAGDROPSTART
   else if (eventType.EqualsLiteral("mouseover")) {
@@ -642,17 +657,20 @@ RootAccessible::HandlePopupHidingEvent(n
     // For menubars processing we listen DOMMenubarActive/Inactive
     // notifications.
     notifyOf = kNotifyOfFocus;
   }
 
   // Restore focus to where it was.
   if (notifyOf & kNotifyOfFocus) {
     FocusMgr()->ActiveItemChanged(nullptr);
-    A11YDEBUG_FOCUS_ACTIVEITEMCHANGE_CAUSE("popuphiding", popup)
+#ifdef DEBUG
+    if (logging::IsEnabled(logging::eFocus))
+      logging::ActiveItemChangeCausedBy("popuphiding", popup);
+#endif
   }
 
   // Fire expanded state change event.
   if (notifyOf & kNotifyOfState) {
     nsRefPtr<AccEvent> event =
       new AccStateChangeEvent(widget, states::EXPANDED, false);
     document->FireDelayedAccessibleEvent(event);
   }
--- a/accessible/tests/mochitest/events/test_focus_contextmenu.xul
+++ b/accessible/tests/mochitest/events/test_focus_contextmenu.xul
@@ -45,16 +45,19 @@
       gQueue.push(new synthContextMenu("button",
                                        new invokerChecker(EVENT_MENUPOPUP_START, "contextmenu")));
       gQueue.push(new synthDownKey("contextmenu", new focusChecker("item1")));
       gQueue.push(new synthDownKey("item1", new focusChecker("item2")));
       gQueue.push(new synthRightKey("item2", new focusChecker("item2.1")));
       gQueue.push(new synthEscapeKey("item2.1", new focusChecker("item2")));
       gQueue.push(new synthEscapeKey("item2", new focusChecker("button")));
 
+      enableLogging("focus");
+      gQueue.onFinish = function() { disableLogging(); }
+
       gQueue.invoke(); // Will call SimpleTest.finish();
     }
 
     SimpleTest.waitForExplicitFinish();
     addA11yLoadEvent(doTests);
   </script>
 
   <hbox flex="1" style="overflow: auto;">
--- a/accessible/tests/mochitest/events/test_focus_menu.xul
+++ b/accessible/tests/mochitest/events/test_focus_menu.xul
@@ -66,16 +66,19 @@
       // move to first menu in cycle, DOMMenuItemActive is fired for fruit,
       // cycle and apple menuitems (bug 685191)
       todo(false, "focus is fired for 'cycle' menuitem");
       //gQueue.push(new synthRightKey("vehicle", new focusChecker("apple")));
 
       // click menuitem to close menu, focus gets back to document
       gQueue.push(new synthClick("tricycle", new focusChecker(document)));
 
+      enableLogging("focus");
+      gQueue.onFinish = function() { disableLogging(); }
+
       gQueue.invoke(); // Will call SimpleTest.finish();
     }
 
     SimpleTest.waitForExplicitFinish();
     addA11yLoadEvent(doTests);
   </script>
 
   <hbox flex="1" style="overflow: auto;">
--- a/accessible/tests/mochitest/states/test_visibility.html
+++ b/accessible/tests/mochitest/states/test_visibility.html
@@ -17,71 +17,142 @@
   <script type="application/javascript"
           src="../states.js"></script>
   <script type="application/javascript"
           src="../events.js"></script>
   <script type="application/javascript"
           src="../browser.js"></script>
 
   <script type="application/javascript">
-    function addTab(aURL)
+    ////////////////////////////////////////////////////////////////////////////
+    // Invokers
+
+    function loadURIInvoker(aURI, aFunc)
+    {
+      this.invoke = function loadURIInvoker_invoke()
+      {
+        tabBrowser().loadURI(aURI);
+      }
+
+      this.eventSeq = [
+        new invokerChecker(EVENT_DOCUMENT_LOAD_COMPLETE, currentTabDocument)
+      ];
+
+      this.finalCheck = function loadURIInvoker_finalCheck()
+      {
+        aFunc.call();
+      }
+
+      this.getID = function loadURIInvoker_getID()
+      {
+        return "load uri " + aURI;
+      }
+    }
+
+    function addTabInvoker(aURL, aFunc)
     {
       this.eventSeq = [
         new invokerChecker(EVENT_DOCUMENT_LOAD_COMPLETE, tabDocumentAt, 1)
       ];
 
-      this.invoke = function addTab_invoke()
+      this.invoke = function addTabInvoker_invoke()
       {
         tabBrowser().loadOneTab(aURL, null, "", null, false);
       }
 
-      this.finalCheck = function addTab_finalCheck()
+      this.finalCheck = function addTabInvoker_finalCheck()
       {
-        var tabDoc = tabDocumentAt(0);
-        var input = getAccessible(tabDoc.getElementById("input"));
-        testStates(input, STATE_OFFSCREEN, 0, STATE_INVISIBLE);
+        aFunc.call();
       }
 
-      this.getID = function addTab_getID()
+      this.getID = function addTabInvoker_getID()
       {
         return "add tab: " + aURL;
       }
     }
 
-    var gInputDocURI = "data:text/html,<html><input id='input'></html>";
+    ////////////////////////////////////////////////////////////////////////////
+    // Tests
+
+    function testBackgroundTab()
+    {
+      // Accessibles in background tab should have offscreen state and no
+      // invisible state.
+      var tabDoc = tabDocumentAt(0);
+      var input = getAccessible(tabDoc.getElementById("input"));
+      testStates(input, STATE_OFFSCREEN, 0, STATE_INVISIBLE);
+    }
+
+    function testScrolledOff()
+    {
+      var tabDoc = tabDocumentAt(1);
+
+      // scrolled off
+      input = getAccessible(tabDoc.getElementById("input_scrolledoff"));
+      testStates(input, STATE_OFFSCREEN, 0, STATE_INVISIBLE);
+
+      // scrolled off item (twice)
+      var lastLiNode = tabDoc.getElementById("li_last");
+      var lastLi = getAccessible(lastLiNode);
+      testStates(lastLi, STATE_OFFSCREEN, 0, STATE_INVISIBLE);
+
+      // scroll into view the item
+      lastLiNode.scrollIntoView(true);
+      testStates(lastLi, 0, 0, STATE_OFFSCREEN | STATE_INVISIBLE);
+
+      // first item is scrolled off now (testcase for bug 768786)
+      var firstLi = getAccessible(tabDoc.getElementById("li_first"));
+      testStates(firstLi, STATE_OFFSCREEN, 0, STATE_INVISIBLE);
+    }
+
+    var gInputDocURI = "data:text/html,<html><body>";
+    gInputDocURI += "<input id='input'></body></html>";
+
+    var gDocURI = "data:text/html,<html><body>";
+    gDocURI += "<div style='border:2px solid blue; width: 500px; height: 600px;'></div>";
+    gDocURI += "<input id='input_scrolledoff'>";
+    gDocURI += "<ul style='border:2px solid red; width: 100px; height: 50px; overflow: auto;'>";
+    gDocURI += "  <li id='li_first'>item1</li><li>item2</li><li>item3</li>";
+    gDocURI += "  <li>item4</li><li>item5</li><li id='li_last'>item6</li>";
+    gDocURI += "</ul>";
+    gDocURI += "</body></html>";
 
     function doTests()
     {
       testStates("div", 0, 0, STATE_INVISIBLE | STATE_OFFSCREEN);
       testStates("div_off", STATE_OFFSCREEN, 0, STATE_INVISIBLE);
       testStates("div_abschild", 0, 0, STATE_INVISIBLE | STATE_OFFSCREEN);
 
       gQueue = new eventQueue();
 
-      // Accessibles in background tab should have offscreen state and no
-      // invisible state.
-      gQueue.push(new addTab("about:blank"));
+      gQueue.push(new addTabInvoker("about:blank", testBackgroundTab));
+      gQueue.push(new loadURIInvoker(gDocURI, testScrolledOff));
 
       gQueue.onFinish = function() { closeBrowserWindow(); }
       gQueue.invoke(); // Will call SimpleTest.finish();
     }
 
     SimpleTest.waitForExplicitFinish();
-    openBrowserWindow(doTests, gInputDocURI);
+    openBrowserWindow(doTests, gInputDocURI, { width: 600, height: 600 });
   </script>
 
 </head>
 
 <body>
 
   <a target="_blank"
      href="https://bugzilla.mozilla.org/show_bug.cgi?id=591363"
      title="(in)visible state is not always correct?">
     Mozilla Bug 591363
   </a>
+  <a target="_blank"
+     href="https://bugzilla.mozilla.org/show_bug.cgi?id=768786"
+     title="Offscreen state is not exposed under certain circumstances">
+    Mozilla Bug 768786
+  </a>
   <p id="display"></p>
   <div id="content" style="display: none"></div>
   <pre id="test">
   </pre>
 
   <div id="outer_div">
 
     <!-- trivial cases -->
--- a/b2g/chrome/content/shell.js
+++ b/b2g/chrome/content/shell.js
@@ -72,21 +72,16 @@ var shell = {
     let crashID;
     try {
       crashID = Cc["@mozilla.org/xre/app-info;1"]
                 .getService(Ci.nsIXULRuntime).lastRunCrashID;
     } catch(e) { }
     if (Services.prefs.getBoolPref('app.reportCrashes') &&
         crashID) {
 
-      if (!Services.io.offline) {
-        this.CrashSubmit.submit(crashID);
-        return;
-      }
-
       Services.obs.addObserver(function observer(subject, topic, state) {
           if (topic != "network:offline-status-changed")
             return;
           if (state == 'online') {
             shell.CrashSubmit.submit(crashID);
             Services.obs.removeObserver(observer, topic);
           }
         }
@@ -109,16 +104,29 @@ var shell = {
     return Services.prefs.getCharPref('browser.homescreenURL');
   },
 
   get manifestURL() {
     return Services.prefs.getCharPref('browser.manifestURL');
    },
 
   start: function shell_start() {
+
+    // Dogfood id. We might want to remove it in the future.
+    // see bug 789466
+    try {
+      let dogfoodId = Services.prefs.getCharPref('prerelease.dogfood.id');
+      if (dogfoodId != "") {
+        let cr = Cc["@mozilla.org/xre/app-info;1"]
+                   .getService(Ci.nsICrashReporter);
+        cr.annotateCrashReport("Email", dogfoodId);
+      }
+    }
+    catch (e) { }
+
     let homeURL = this.homeURL;
     if (!homeURL) {
       let msg = 'Fatal error during startup: No homescreen found: try setting B2G_HOMESCREEN';
       alert(msg);
       return;
     }
 
     let manifestURL = this.manifestURL;
@@ -427,16 +435,26 @@ Services.obs.addObserver(function(aSubje
   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);
 
+Services.obs.addObserver(function onBluetoothVolumeChange(subject, topic, data) {
+  if (data == 'up') {
+    shell.sendChromeEvent({ type: 'volume-up-button-press' });
+    shell.sendChromeEvent({ type: 'volume-up-button-release' });
+  } else if (data == 'down') {
+    shell.sendChromeEvent({ type: 'volume-down-button-press' });
+    shell.sendChromeEvent({ type: 'volume-down-button-release' });
+  }
+}, 'bluetooth-volume-change', 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
@@ -579,17 +579,16 @@ pref("accessibility.typeaheadfind.flashB
 // plugin finder service url
 pref("pfs.datasource.url", "https://pfs.mozilla.org/plugins/PluginFinderService.php?mimetype=%PLUGIN_MIMETYPE%&appID=%APP_ID%&appVersion=%APP_VERSION%&clientOS=%CLIENT_OS%&chromeLocale=%CHROME_LOCALE%&appRelease=%APP_RELEASE%");
 
 // by default we show an infobar message when pages require plugins the user has not installed, or are outdated
 pref("plugins.hide_infobar_for_missing_plugin", false);
 pref("plugins.hide_infobar_for_outdated_plugin", false);
 
 #ifdef XP_MACOSX
-pref("plugins.use_layers", true);
 pref("plugins.hide_infobar_for_carbon_failure_plugin", false);
 #endif
 
 pref("plugins.update.url", "https://www.mozilla.org/%LOCALE%/plugincheck/");
 pref("plugins.update.notifyUser", false);
 
 pref("plugins.click_to_play", false);
 
@@ -1178,10 +1177,11 @@ pref("image.mem.max_decoded_image_kb", 2
 
 // Example social provider
 pref("social.manifest.motown", "{\"origin\":\"https://motown-dev.mozillalabs.com\",\"name\":\"MoTown\",\"workerURL\":\"https://motown-dev.mozillalabs.com/social/worker.js\",\"iconURL\":\"https://motown-dev.mozillalabs.com/images/motown-icon.png\",\"sidebarURL\":\"https://motown-dev.mozillalabs.com/social/sidebar\"}");
 // Comma-separated list of nsIURI::prePaths that are allowed to activate
 // built-in social functionality.
 pref("social.activation.whitelist", "https://motown-dev.mozillalabs.com");
 pref("social.sidebar.open", true);
 pref("social.active", false);
+pref("social.toast-notifications.enabled", true);
 
 pref("dom.identity.enabled", false);
--- a/browser/base/content/abouthome/aboutHome.xhtml
+++ b/browser/base/content/abouthome/aboutHome.xhtml
@@ -49,17 +49,17 @@
           <span id="defaultSnippet1">&abouthome.defaultSnippet1.v1;</span>
           <span id="defaultSnippet2">&abouthome.defaultSnippet2.v1;</span>
         </div>
         <div id="snippets"/>
       </div>
     </div>
     <div class="spacer"/>
 
-    <div id="launcher" session="true">
+    <div id="launcher">
       <button class="launchButton" id="downloads">&abouthome.downloadsButton.label;</button>
       <button class="launchButton" id="bookmarks">&abouthome.bookmarksButton.label;</button>
       <button class="launchButton" id="history">&abouthome.historyButton.label;</button>
       <button class="launchButton" id="apps" hidden="true">&abouthome.appsButton.label;</button>
       <button class="launchButton" id="addons">&abouthome.addonsButton.label;</button>
       <button class="launchButton" id="sync">&abouthome.syncButton.label;</button>
       <button class="launchButton" id="settings">&abouthome.settingsButton.label;</button>
       <div id="restorePreviousSessionSeparator"/>
--- a/browser/base/content/browser-sets.inc
+++ b/browser/base/content/browser-sets.inc
@@ -104,16 +104,17 @@
      oncommand="Cc['@mozilla.org/browser/browserglue;1'].getService(Ci.nsIBrowserGlue).sanitize(window);"/>
     <command id="Tools:PrivateBrowsing" oncommand="gPrivateBrowsingUI.toggleMode();"/>
     <command id="History:UndoCloseTab" oncommand="undoCloseTab();"/>
     <command id="History:UndoCloseWindow" oncommand="undoCloseWindow();"/>
     <command id="Browser:ToggleAddonBar" oncommand="toggleAddonBar();"/>
     <command id="Social:SharePage" oncommand="SocialShareButton.sharePage();"/>
     <command id="Social:UnsharePage" oncommand="SocialShareButton.unsharePage();"/>
     <command id="Social:ToggleSidebar" oncommand="Social.toggleSidebar();"/>
+    <command id="Social:ToggleNotifications" oncommand="Social.toggleNotifications();"/>
     <command id="Social:Toggle" oncommand="Social.toggle();" hidden="true"/>
   </commandset>
 
   <commandset id="placesCommands">
     <command id="Browser:ShowAllBookmarks"
              oncommand="PlacesCommandHook.showPlacesOrganizer('AllBookmarks');"/>
     <command id="Browser:ShowAllHistory"
              oncommand="PlacesCommandHook.showPlacesOrganizer('History');"/>
--- a/browser/base/content/browser-social.js
+++ b/browser/base/content/browser-social.js
@@ -5,29 +5,31 @@
 let SocialUI = {
   // Called on delayed startup to initialize UI
   init: function SocialUI_init() {
     Services.obs.addObserver(this, "social:pref-changed", false);
     Services.obs.addObserver(this, "social:ambient-notification-changed", false);
     Services.obs.addObserver(this, "social:profile-changed", false);
 
     Services.prefs.addObserver("social.sidebar.open", this, false);
+    Services.prefs.addObserver("social.toast-notifications.enabled", this, false);
 
     gBrowser.addEventListener("ActivateSocialFeature", this._activationEventHandler, true, true);
 
     Social.init(this._providerReady.bind(this));
   },
 
   // Called on window unload
   uninit: function SocialUI_uninit() {
     Services.obs.removeObserver(this, "social:pref-changed");
     Services.obs.removeObserver(this, "social:ambient-notification-changed");
     Services.obs.removeObserver(this, "social:profile-changed");
 
     Services.prefs.removeObserver("social.sidebar.open", this);
+    Services.prefs.removeObserver("social.toast-notifications.enabled", this);
   },
 
   showProfile: function SocialUI_showProfile() {
     if (Social.provider)
       openUILinkIn(Social.provider.profile.profileURL, "tab");
   },
 
   observe: function SocialUI_observe(subject, topic, data) {
@@ -52,16 +54,17 @@ let SocialUI = {
         break;
       case "social:profile-changed":
         SocialToolbar.updateProfile();
         SocialShareButton.updateProfileInfo();
         SocialChatBar.update();
         break;
       case "nsPref:changed":
         SocialSidebar.updateSidebar();
+        SocialToolbar.updateButton();
     }
   },
 
   get toggleCommand() {
     return document.getElementById("Social:Toggle");
   },
 
   // Called once Social.jsm's provider has been set
@@ -584,16 +587,19 @@ var SocialToolbar = {
     let iconNames = Object.keys(provider.ambientNotificationIcons);
     let iconBox = document.getElementById("social-status-iconbox");
     let notifBox = document.getElementById("social-notification-box");
     let panel = document.getElementById("social-notification-panel");
     panel.hidden = false;
     let notificationFrames = document.createDocumentFragment();
     let iconContainers = document.createDocumentFragment();
 
+    let command = document.getElementById("Social:ToggleNotifications");
+    command.setAttribute("checked", Services.prefs.getBoolPref("social.toast-notifications.enabled"));
+
     for each(let name in iconNames) {
       let icon = provider.ambientNotificationIcons[name];
 
       let notificationFrameId = "social-status-" + icon.name;
       let notificationFrame = document.getElementById(notificationFrameId);
       if (!notificationFrame) {
         notificationFrame = document.createElement("iframe");
         notificationFrame.setAttribute("type", "content");
--- a/browser/base/content/browser.js
+++ b/browser/base/content/browser.js
@@ -2488,18 +2488,18 @@ function BrowserOnAboutPageLoad(document
   if (/^about:home$/i.test(document.documentURI)) {
     // XXX bug 738646 - when Marketplace is launched, remove this statement and
     // the hidden attribute set on the apps button in aboutHome.xhtml
     if (getBoolPref("browser.aboutHome.apps", false))
       document.getElementById("apps").removeAttribute("hidden");
 
     let ss = Components.classes["@mozilla.org/browser/sessionstore;1"].
              getService(Components.interfaces.nsISessionStore);
-    if (!ss.canRestoreLastSession)
-      document.getElementById("launcher").removeAttribute("session");
+    if (ss.canRestoreLastSession)
+      document.getElementById("launcher").setAttribute("session", "true");
 
     // Inject search engine and snippets URL.
     let docElt = document.documentElement;
     docElt.setAttribute("snippetsURL", AboutHomeUtils.snippetsURL);
     docElt.setAttribute("searchEngineName",
                         AboutHomeUtils.defaultSearchEngine.name);
     docElt.setAttribute("searchEngineURL",
                         AboutHomeUtils.defaultSearchEngine.searchURL);
--- a/browser/base/content/browser.xul
+++ b/browser/base/content/browser.xul
@@ -679,16 +679,22 @@
                 </vbox>
               </hbox>
               <menuitem id="social-toggle-sidebar-menuitem"
                         type="checkbox"
                         autocheck="false"
                         command="Social:ToggleSidebar"
                         label="&social.toggleSidebar.label;"
                         accesskey="&social.toggleSidebar.accesskey;"/>
+              <menuitem id="social-toggle-notifications-menuitem"
+                        type="checkbox"
+                        autocheck="false"
+                        command="Social:ToggleNotifications"
+                        label="&social.toggleNotifications.label;"
+                        accesskey="&social.toggleNotifications.accesskey;"/>
             </menupopup>
           </button>
           <hbox id="social-status-iconbox" flex="1">
           </hbox>
         </hbox>
       </toolbaritem>
 
       <toolbaritem id="bookmarks-menu-button-container"
--- a/browser/base/content/socialchat.xml
+++ b/browser/base/content/socialchat.xml
@@ -2,17 +2,17 @@
 
 <bindings id="socialChatBindings"
     xmlns="http://www.mozilla.org/xbl"
     xmlns:xbl="http://www.mozilla.org/xbl"
     xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
 
   <binding id="chatbox">
     <content orient="vertical" mousethrough="never">
-      <xul:hbox class="chat-titlebar" xbl:inherits="minimized,selected"
+      <xul:hbox class="chat-titlebar" xbl:inherits="minimized,selected,activity"
                 onclick="document.getBindingParent(this).toggle();" align="baseline">
         <xul:image class="chat-status-icon" xbl:inherits="src=image"/>
         <xul:label class="chat-title" flex="1" xbl:inherits="value=label,crop"/>
         <xul:toolbarbutton class="chat-close-button chat-toolbarbutton"
                            oncommand="document.getBindingParent(this).close();"/>
       </xul:hbox>
       <xul:iframe anonid="iframe" class="chat-frame" flex="1"
                   xbl:inherits="src,origin,collapsed=minimized" type="content"/>
@@ -73,37 +73,52 @@
         ]]></body>
       </method>
     </implementation>
 
     <handlers>
       <handler event="focus" phase="capturing">
         this.parentNode.selectedChat = this;
       </handler>
-      <handler event="load"><![CDATA[
+      <handler event="DOMContentLoaded"><![CDATA[
         this.isActive = !this.minimized;
         if (this._callback) this._callback(this.iframe.contentWindow);
+        let chatbox = this;
+        function chatActivity() {
+          chatbox.setAttribute("activity", true);
+          chatbox.parentNode.updateTitlebar(chatbox);
+        };
+        let iframeWindow = this.iframe.contentWindow;
+        iframeWindow.addEventListener("socialChatActivity", chatActivity);
+        iframeWindow.addEventListener("unload", function unload() {
+          iframeWindow.removeEventListener("unload", unload);
+          iframeWindow.removeEventListener("socialChatActivity", chatActivity);
+        });
       ]]></handler>
-      <handler event="DOMTitleChanged" action="this.setAttribute('label', this.iframe.contentDocument.title);"/>
+      <handler event="DOMTitleChanged"><![CDATA[
+        this.setAttribute('label', this.iframe.contentDocument.title);
+        this.parentNode.updateTitlebar(this);
+      ]]></handler>
       <handler event="DOMLinkAdded"><![CDATA[
         // much of this logic is from DOMLinkHandler in browser.js
         // this sets the presence icon for a chat user, we simply use favicon style updating
         let link = event.originalTarget;
         let rel = link.rel && link.rel.toLowerCase();
         if (!link || !link.ownerDocument || !rel || !link.href)
           return;
         if (link.rel.indexOf("icon") < 0)
           return;
 
         let uri = DOMLinkHandler.getLinkIconURI(link);
         if (!uri)
           return;
 
         // we made it this far, use it
         this.setAttribute('image', uri.spec);
+        this.parentNode.updateTitlebar(this);
       ]]></handler>
     </handlers>
   </binding>
 
   <binding id="chatbar">
     <content>
       <xul:hbox align="end" pack="end" anonid="innerbox" class="chatbar-innerbox" mousethrough="always" flex="1">
         <xul:toolbarbutton anonid="nub" class="chatbar-button" type="menu" collapsed="true" mousethrough="never">
@@ -119,32 +134,37 @@
       <field name="innerbox" readonly="true">
         document.getAnonymousElementByAttribute(this, "anonid", "innerbox");
       </field>
 
       <field name="menupopup" readonly="true">
         document.getAnonymousElementByAttribute(this, "anonid", "nubMenu");
       </field>
 
+      <field name="nub" readonly="true">
+        document.getAnonymousElementByAttribute(this, "anonid", "nub");
+      </field>
+
       <property name="emptyWidth">
         <getter>
           return document.getAnonymousElementByAttribute(this, "anonid", "spacer").boxObject.width;
         </getter>
       </property>
 
       <property name="selectedChat">
         <getter><![CDATA[
           return this._selectedChat;
         ]]></getter>
         <setter><![CDATA[
           if (this._selectedChat)
             this._selectedChat.removeAttribute("selected");
           this._selectedChat = val;
           if (val) {
             this._selectedChat.setAttribute("selected", "true");
+            this._selectedChat.removeAttribute("activity");
           }
         ]]></setter>
       </property>
 
       <field name="menuitemMap">new WeakMap()</field>
       <field name="chatboxForURL">new Map();</field>
 
       <property name="firstCollapsedChild">
@@ -191,16 +211,31 @@
           }
           if (!this.firstCollapsedChild) {
             window.removeEventListener("resize", this);
             this.menupopup.parentNode.collapsed = true;
           }
         ]]></body>
       </method>
 
+      <method name="updateTitlebar">
+        <parameter name="aChatbox"/>
+        <body><![CDATA[
+          if (aChatbox.collapsed) {
+            let menuitem = this.menuitemMap.get(aChatbox);
+            if (aChatbox.getAttribute("activity")) {
+              menuitem.setAttribute("activity", true);
+              this.nub.setAttribute("activity", true);
+            }
+            menuitem.setAttribute("label", aChatbox.getAttribute("label"));
+            menuitem.setAttribute("image", aChatbox.getAttribute("image"));
+          }
+        ]]></body>
+      </method>
+
       <method name="handleEvent">
         <parameter name="aEvent"/>
         <body><![CDATA[
           if (aEvent.type == "resize") {
             this.resize();
           }
         ]]></body>
       </method>
@@ -220,17 +255,19 @@
 
       <method name="collapseChat">
         <parameter name="aChatbox"/>
         <body><![CDATA[
           aChatbox.viewWidth = aChatbox.getBoundingClientRect().width;
           aChatbox.collapsed = true;
           aChatbox.isActive = false;
           let menu = document.createElementNS("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul", "menuitem");
+          menu.setAttribute("class", "menuitem-iconic");
           menu.setAttribute("label", aChatbox.iframe.contentDocument.title);
+          menu.setAttribute("image", aChatbox.getAttribute("image"));
           menu.chat = aChatbox;
           this.menuitemMap.set(aChatbox, menu);
           this.menupopup.appendChild(menu);
           this.menupopup.parentNode.collapsed = false;
         ]]></body>
       </method>
 
       <method name="showChat">
@@ -291,16 +328,19 @@
           this.insertBefore(cb, this.firstChild);
           cb.init(aProvider, aURL, aCallback);
           this.chatboxForURL.set(aURL, Cu.getWeakReference(cb));
         ]]></body>
       </method>
 
     </implementation>
     <handlers>
+      <handler event="popupshown"><![CDATA[
+        this.nub.removeAttribute("activity");
+      ]]></handler>
       <handler event="overflow"><![CDATA[
         // make sure we're not getting an overflow from content
         if (event.originalTarget != this.innerbox)
           return;
 
         let hasHidden = this.firstCollapsedChild;
         let child = this.firstRemovableChild;
         if (child)
--- a/browser/locales/en-US/chrome/browser/browser.dtd
+++ b/browser/locales/en-US/chrome/browser/browser.dtd
@@ -646,10 +646,13 @@ toolbar button -->
 <!ENTITY social.notLoggedIn.label   "Not logged in">
 
 <!ENTITY social.ok.label       "OK">
 <!ENTITY social.ok.accesskey   "O">
 
 <!ENTITY social.toggleSidebar.label "Show sidebar">
 <!ENTITY social.toggleSidebar.accesskey "s">
 
+<!ENTITY social.toggleNotifications.label "Show desktop notifications">
+<!ENTITY social.toggleNotifications.accesskey "n">
+
 <!ENTITY social.activated.undobutton.label "Undo">
 <!ENTITY social.activated.undobutton.accesskey "U">
--- a/browser/modules/Social.jsm
+++ b/browser/modules/Social.jsm
@@ -57,16 +57,21 @@ let Social = {
     this.enabled = !this.enabled;
   },
 
   toggleSidebar: function SocialSidebar_toggle() {
     let prefValue = Services.prefs.getBoolPref("social.sidebar.open");
     Services.prefs.setBoolPref("social.sidebar.open", !prefValue);
   },
 
+  toggleNotifications: function SocialNotifications_toggle() {
+    let prefValue = Services.prefs.getBoolPref("social.toast-notifications.enabled");
+    Services.prefs.setBoolPref("social.toast-notifications.enabled", !prefValue);
+  },
+
   // Sharing functionality
   _getShareablePageUrl: function Social_getShareablePageUrl(aURI) {
     let uri = aURI.clone();
     try {
       // Setting userPass on about:config throws.
       uri.userPass = "";
     } catch (e) {}
     return uri.spec;
--- a/browser/themes/gnomestripe/browser.css
+++ b/browser/themes/gnomestripe/browser.css
@@ -2775,16 +2775,20 @@ html|*#gcli-output-frame {
 .chat-titlebar[minimized="true"] {
   border-bottom: none;
 }
 
 .chat-titlebar[selected] {
   background-color: #f0f0f0;
 }
 
+.chat-titlebar[activity] {
+  background-color: #ceeaff;
+}
+
 .chat-frame {
   padding: 0;
   margin: 0;
   overflow: hidden;
 }
 
 .chatbar-button {
   background-color: #d9d9d9;
@@ -2804,16 +2808,24 @@ html|*#gcli-output-frame {
   box-shadow: inset 0 2px 5px rgba(0,0,0,0.6), 0 1px rgba(255,255,255,0.2);
 }
 
 .chatbar-button > .toolbarbutton-text,
 .chatbar-button > .toolbarbutton-menu-dropmarker {
   display: none;
 }
 
+.chatbar-button[activity] {
+  background-color: #ceeaff;
+}
+
+.chatbar-button > menupopup > menuitem[activity] {
+  font-weight: bold;
+}
+
 .chatbar-innerbox {
   background: transparent;
   margin: -285px -1px 0 -1px;
   overflow: hidden;
 }
 
 chatbar {
   -moz-margin-end: 20px;
--- a/browser/themes/pinstripe/browser.css
+++ b/browser/themes/pinstripe/browser.css
@@ -3457,16 +3457,20 @@ html|*#gcli-output-frame {
   border-bottom: 1px solid #404040;
   cursor: pointer;
 }
 
 .chat-titlebar[minimized="true"] {
   border-bottom: none;
 }
 
+.chat-titlebar[activity] {
+  background-color: #ceeaff;
+}
+
 .chat-titlebar[selected] {
   background-color: #f0f0f0;
 }
 
 .chat-frame {
   padding: 0;
   margin: 0;
   overflow: hidden;
@@ -3490,16 +3494,24 @@ html|*#gcli-output-frame {
   box-shadow: inset 0 2px 5px rgba(0,0,0,0.6), 0 1px rgba(255,255,255,0.2);
 }
 
 .chatbar-button > .toolbarbutton-text,
 .chatbar-button > .toolbarbutton-menu-dropmarker {
   display: none;
 }
 
+.chatbar-button[activity] {
+  background-color: #ceeaff;
+}
+
+.chatbar-button > menupopup > menuitem[activity] {
+  font-weight: bold;
+}
+
 .chatbar-innerbox {
   background: transparent;
   margin: -285px -1px 0 -1px;
   overflow: hidden;
 }
 
 chatbar {
   -moz-margin-end: 20px;
--- a/browser/themes/winstripe/browser.css
+++ b/browser/themes/winstripe/browser.css
@@ -3479,16 +3479,20 @@ html|*#gcli-output-frame {
 .chat-titlebar[minimized="true"] {
   border-bottom: none;
 }
 
 .chat-titlebar[selected] {
   background-color: #dae3f0;
 }
 
+.chat-titlebar[activity] {
+  background-color: #ceeaff;
+}
+
 .chat-frame {
   padding: 0;
   margin: 0;
   overflow: hidden;
 }
 
 .chatbar-button {
   /* XXX get a real image for this */
@@ -3517,16 +3521,24 @@ html|*#gcli-output-frame {
   box-shadow: inset 0 2px 5px rgba(0,0,0,0.6), 0 1px rgba(255,255,255,0.2);
 }
 
 .chatbar-button > .toolbarbutton-text,
 .chatbar-button > .toolbarbutton-menu-dropmarker {
   display: none;
 }
 
+.chatbar-button[activity] {
+  background-color: #ceeaff;
+}
+
+.chatbar-button > menupopup > menuitem[activity] {
+  font-weight: bold;
+}
+
 .chatbar-innerbox {
   background: transparent;
   margin: -285px -1px 0 -1px;
   overflow: hidden;
 }
 
 chatbar {
   -moz-margin-end: 20px;
--- a/configure.in
+++ b/configure.in
@@ -60,17 +60,17 @@ NSS_VERSION=3
 dnl Set the minimum version of toolkit libs used by mozilla
 dnl ========================================================
 GLIB_VERSION=1.2.0
 PERL_VERSION=5.006
 PYTHON_VERSION_MAJOR=2
 PYTHON_VERSION_MINOR=5
 CAIRO_VERSION=1.10
 PANGO_VERSION=1.14.0
-GTK2_VERSION=2.18.0
+GTK2_VERSION=2.10.0
 WINDRES_VERSION=2.14.90
 W32API_VERSION=3.14
 GNOMEVFS_VERSION=2.0
 GNOMEUI_VERSION=2.2.0
 GCONF_VERSION=1.2.1
 GIO_VERSION=2.18
 STARTUP_NOTIFICATION_VERSION=0.8
 DBUS_VERSION=0.60
deleted file mode 100644
--- a/content/base/src/nsBlobProtocolHandler.h
+++ /dev/null
@@ -1,51 +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/. */
-
-#ifndef nsBlobProtocolHandler_h
-#define nsBlobProtocolHandler_h
-
-#include "nsIProtocolHandler.h"
-#include "nsIURI.h"
-#include "nsCOMPtr.h"
-
-#define BLOBURI_SCHEME "blob"
-
-class nsIDOMBlob;
-class nsIPrincipal;
-class nsIInputStream;
-
-inline bool IsBlobURI(nsIURI* aUri)
-{
-  bool isBlob;
-  return NS_SUCCEEDED(aUri->SchemeIs(BLOBURI_SCHEME, &isBlob)) && isBlob;
-}
-
-extern nsresult
-NS_GetStreamForBlobURI(nsIURI* aURI, nsIInputStream** aStream);
-
-class nsBlobProtocolHandler : public nsIProtocolHandler
-{
-public:
-  NS_DECL_ISUPPORTS
-
-  // nsIProtocolHandler methods:
-  NS_DECL_NSIPROTOCOLHANDLER
-
-  // nsBlobProtocolHandler methods:
-  nsBlobProtocolHandler() {}
-  virtual ~nsBlobProtocolHandler() {}
-
-  // Methods for managing uri->file mapping
-  static void AddFileDataEntry(nsACString& aUri,
-                               nsIDOMBlob* aFile,
-                               nsIPrincipal* aPrincipal);
-  static void RemoveFileDataEntry(nsACString& aUri);
-  static nsIPrincipal* GetFileDataEntryPrincipal(nsACString& aUri);
-};
-
-#define NS_BLOBPROTOCOLHANDLER_CID \
-{ 0xb43964aa, 0xa078, 0x44b2, \
-  { 0xb0, 0x6b, 0xfd, 0x4d, 0x1b, 0x17, 0x2e, 0x66 } }
-
-#endif /* nsBlobProtocolHandler_h */
--- a/dom/apps/src/AppsUtils.jsm
+++ b/dom/apps/src/AppsUtils.jsm
@@ -29,17 +29,23 @@ let AppsUtils = {
       origin: aApp.origin,
       receipts: aApp.receipts ? JSON.parse(JSON.stringify(aApp.receipts)) : null,
       installTime: aApp.installTime,
       manifestURL: aApp.manifestURL,
       appStatus: aApp.appStatus,
       removable: aApp.removable,
       localId: aApp.localId,
       progress: aApp.progress || 0.0,
-      status: aApp.status || "installed"
+      installState: aApp.installState || "installed",
+      downloadAvailable: aApp.downloadAvailable,
+      downloading: aApp.downloading,
+      readyToApplyDownload: aApp.readyToApplyDownload,
+      downloadSize: aApp.downloadSize || 0,
+      lastUpdateCheck: aApp.lastUpdateCheck,
+      etag: aApp.etag
     };
   },
 
   cloneAsMozIApplication: function cloneAsMozIApplication(aApp) {
     let res = this.cloneAppObject(aApp);
     res.hasPermission = function(aPermission) {
       let uri = Services.io.newURI(this.origin, null, null);
       let secMan = Cc["@mozilla.org/scriptsecuritymanager;1"]
--- a/dom/apps/src/Webapps.js
+++ b/dom/apps/src/Webapps.js
@@ -7,16 +7,17 @@ const Ci = Components.interfaces;
 const Cu = Components.utils;
 const Cr = Components.results;
 
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 Cu.import("resource://gre/modules/Services.jsm");
 Cu.import("resource://gre/modules/DOMRequestHelper.jsm");
 Cu.import("resource://gre/modules/ObjectWrapper.jsm");
 Cu.import("resource://gre/modules/AppsUtils.jsm");
+Cu.import("resource://gre/modules/BrowserElementPromptService.jsm");
 
 XPCOMUtils.defineLazyServiceGetter(this, "cpmm",
                                    "@mozilla.org/childprocessmessagemanager;1",
                                    "nsIMessageSender");
 
 function convertAppsArray(aApps, aWindow) {
   let apps = Cu.createArrayIn(aWindow);
   for (let i = 0; i < aApps.length; i++) {
@@ -49,17 +50,16 @@ WebappsRegistry.prototype = {
     if (!req)
       return;
     let app = msg.app;
     switch (aMessage.name) {
       case "Webapps:Install:Return:OK":
         Services.DOMRequest.fireSuccess(req, createApplicationObject(this._window, app));
         break;
       case "Webapps:Install:Return:KO":
-      dump("XxXxX Webapps:Install:Return:KO\n");
         Services.DOMRequest.fireError(req, msg.error || "DENIED");
         break;
       case "Webapps:GetSelf:Return:OK":
         if (msg.apps.length) {
           app = msg.apps[0];
           Services.DOMRequest.fireSuccess(req, createApplicationObject(this._window, app));
         } else {
           Services.DOMRequest.fireSuccess(req, null);
@@ -115,20 +115,22 @@ WebappsRegistry.prototype = {
 
         if (!AppsUtils.checkManifest(manifest, installOrigin)) {
           Services.DOMRequest.fireError(request, "INVALID_MANIFEST");
         } else if (!this.checkAppStatus(manifest)) {
           Services.DOMRequest.fireError(request, "INVALID_SECURITY_LEVEL");
         } else {
           let receipts = (aParams && aParams.receipts && Array.isArray(aParams.receipts)) ? aParams.receipts : [];
           let categories = (aParams && aParams.categories && Array.isArray(aParams.categories)) ? aParams.categories : [];
+          let etag = xhr.getResponseHeader("Etag");
           cpmm.sendAsyncMessage("Webapps:Install", { app: { installOrigin: installOrigin,
                                                             origin: this._getOrigin(aURL),
                                                             manifestURL: aURL,
                                                             manifest: manifest,
+                                                            etag: etag,
                                                             receipts: receipts,
                                                             categories: categories },
                                                             from: installURL,
                                                             oid: this._id,
                                                             requestID: requestID });
         }
       } else {
         Services.DOMRequest.fireError(request, "MANIFEST_URL_ERROR");
@@ -254,16 +256,46 @@ WebappsRegistry.prototype = {
                                                  Ci.mozIDOMApplicationRegistry2,
 #endif
                                                  ],
                                     flags: Ci.nsIClassInfo.DOM_OBJECT,
                                     classDescription: "Webapps Registry"})
 }
 
 /**
+  * nsIDOMDOMError object
+  */
+function createDOMError(aError) {
+  let error = Cc["@mozilla.org/dom-error;1"]
+                .createInstance(Ci.nsIDOMDOMError);
+  error.wrappedJSObject.init(aError);
+  return error;
+}
+
+function DOMError() {
+  this.wrappedJSObject = this;
+}
+
+DOMError.prototype = {
+  init: function domerror_init(aError) {
+    this.name = aError;
+  },
+
+  classID: Components.ID("{dcc1d5b7-43d8-4740-9244-b3d8db0f503d}"),
+
+  QueryInterface: XPCOMUtils.generateQI([Ci.nsIDOMDOMError]),
+
+  classInfo: XPCOMUtils.generateCI({classID: Components.ID("{dcc1d5b7-43d8-4740-9244-b3d8db0f503d}"),
+                                    contractID: "@mozilla.org/dom-error;1",
+                                    interfaces: [Ci.nsIDOMDOMError],
+                                    flags: Ci.nsIClassInfo.DOM_OBJECT,
+                                    classDescription: "DOMError object"})
+}
+
+/**
   * mozIDOMApplication object
   */
 
 function createApplicationObject(aWindow, aApp) {
   let app = Cc["@mozilla.org/webapps/application;1"].createInstance(Ci.mozIDOMApplication);
   app.wrappedJSObject.init(aWindow, aApp);
   return app;
 }
@@ -273,39 +305,111 @@ function WebappsApplication() {
 }
 
 WebappsApplication.prototype = {
   __proto__: DOMRequestIpcHelper.prototype,
 
   init: function(aWindow, aApp) {
     this.origin = aApp.origin;
     this.manifest = ObjectWrapper.wrap(aApp.manifest, aWindow);
+    this.updateManifest = aApp.updateManifest ? ObjectWrapper.wrap(aApp.updateManifest, aWindow)
+                                              : null;
     this.manifestURL = aApp.manifestURL;
     this.receipts = aApp.receipts;
     this.installOrigin = aApp.installOrigin;
     this.installTime = aApp.installTime;
-    this.status = "installed";
+    this.installState = aApp.installState || "installed";
     this.removable = aApp.removable;
+    this.lastUpdateCheck = aApp.lastUpdateCheck ? aApp.lastUpdateCheck
+                                                : Date.now();
     this.progress = NaN;
+    this.downloadAvailable = aApp.downloadAvailable;
+    this.downloading = aApp.downloading;
+    this.readyToApplyDownload = aApp.readyToApplyDownload;
+    this.downloadSize = aApp.downloadSize || 0;
+
     this._onprogress = null;
+    this._ondownloadsuccess = null;
+    this._ondownloaderror = null;
+    this._ondownloadavailable = null;
+    this._ondownloadapplied = null;
+
+    this._downloadError = null;
+
     this.initHelper(aWindow, ["Webapps:Uninstall:Return:OK",
                               "Webapps:Uninstall:Return:KO",
-                              "Webapps:OfflineCache"]);
+                              "Webapps:OfflineCache",
+                              "Webapps:CheckForUpdate:Return:OK",
+                              "Webapps:CheckForUpdate:Return:KO"]);
     cpmm.sendAsyncMessage("Webapps:RegisterForMessages",
                           ["Webapps:Uninstall:Return:OK", "Webapps:OfflineCache"]);
   },
 
   set onprogress(aCallback) {
     this._onprogress = aCallback;
   },
 
   get onprogress() {
     return this._onprogress;
   },
 
+  set ondownloadsuccess(aCallback) {
+    this._ondownloadsuccess = aCallback;
+  },
+
+  get ondownloadsuccess() {
+    return this._ondownloadsuccess;
+  },
+
+  set ondownloaderror(aCallback) {
+    this._ondownloaderror = aCallback;
+  },
+
+  get ondownloaderror() {
+    return this._ondownloaderror;
+  },
+
+  set ondownloadavailable(aCallback) {
+    this._ondownloadavailable = aCallback;
+  },
+
+  get ondownloadavailable() {
+    return this._ondownloadavailable;
+  },
+
+  set ondownloadapplied(aCallback) {
+    this._ondownloadapplied = aCallback;
+  },
+
+  get ondownloadapplied() {
+    return this._ondownloadapplied;
+  },
+
+  get downloadError() {
+    return createDOMError(this._downloadError);
+  },
+
+  download: function() {
+    throw Cr.NS_ERROR_NOT_IMPLEMENTED;
+  },
+
+  cancelDownload: function() {
+    cpmm.sendAsyncMessage("Webapps:CancelDownload",
+                          { manifestURL: this.manifestURL });
+  },
+
+  checkForUpdate: function() {
+    let request = this.createRequest();
+    cpmm.sendAsyncMessage("Webapps:CheckForUpdate",
+                          { manifestURL: this.manifestURL,
+                            oid: this._id,
+                            requestID: this.getRequestId(request) });
+    return request;
+  },
+
   launch: function(aStartPoint) {
     let request = this.createRequest();
     cpmm.sendAsyncMessage("Webapps:Launch", { origin: this.origin,
                                               manifestURL: this.manifestURL,
                                               startPoint: aStartPoint || "",
                                               oid: this._id,
                                               requestID: this.getRequestId(request) });
     return request;
@@ -314,44 +418,84 @@ WebappsApplication.prototype = {
   uninstall: function() {
     let request = this.createRequest();
     cpmm.sendAsyncMessage("Webapps:Uninstall", { origin: this.origin,
                                                  oid: this._id,
                                                  requestID: this.getRequestId(request) });
     return request;
   },
 
+  clearBrowserData: function() {
+    let browserChild =
+      BrowserElementPromptService.getBrowserElementChildForWindow(this._window);
+    if (browserChild) {
+      browserChild.messageManager.sendAsyncMessage("Webapps:ClearBrowserData");
+    }
+  },
+
   uninit: function() {
     this._onprogress = null;
     cpmm.sendAsyncMessage("Webapps:UnregisterForMessages",
                           ["Webapps:Uninstall:Return:OK", "Webapps:OfflineCache"]);
   },
 
+  _fireEvent: function(aName, aHandler) {
+    if (aHandler) {
+      let event = new this._window.MozApplicationEvent(aName, { application: this });
+      aHandler.handleEvent(event);
+    }
+  },
+
   receiveMessage: function(aMessage) {
     var msg = aMessage.json;
     let req = this.takeRequest(msg.requestID);
     if ((msg.oid != this._id || !req) && aMessage.name !== "Webapps:OfflineCache")
       return;
     switch (aMessage.name) {
       case "Webapps:Uninstall:Return:OK":
         Services.DOMRequest.fireSuccess(req, msg.origin);
         break;
       case "Webapps:Uninstall:Return:KO":
         Services.DOMRequest.fireError(req, "NOT_INSTALLED");
         break;
+      case "Webapps:Launch:Return:KO":
+        Services.DOMRequest.fireError(req, "APP_INSTALL_PENDING");
+        break;
+      case "Webapps:Uninstall:Return:KO":
+        Services.DOMRequest.fireError(req, "NOT_INSTALLED");
+        break;
       case "Webapps:OfflineCache":
         if (msg.manifest != this.manifestURL)
           return;
 
-        this.status = msg.status;
-        if (this._onprogress) {
-          let event = new this._window.MozApplicationEvent("applicationinstall", { application: this });
-          this._onprogress.handleEvent(event);
+        if (installState in msg) {
+          this.installState = msg.installState;
+          if (this.installState == "installed") {
+            this._fireEvent("downloadsuccess", this._ondownloadsuccess);
+            this._fireEvent("downloadapplied", this._ondownloadapplied);
+          } else {
+            this._fireEvent("downloadprogress", this._onprogress);
+          }
+        } else if (msg.error) {
+          this._downloadError = msg.error;
+          this._fireEvent("downloaderror", this._ondownloaderror);
         }
         break;
+        case "Webapps:CheckForUpdate:Return:OK":
+          for (let prop in msg.app) {
+            this[prop] = msg.app[prop];
+            if (msg.event == "downloadapplied") {
+              Services.DOMRequest.fireSuccess(req, this.manifestURL);
+              this._fireEvent("downloadapplied", this._ondownloadapplied);
+            }
+          }
+          break;
+        case "Webapps:CheckForUpdate:Return:KO":
+          Services.DOMRequest.fireError(req, msg.error);
+          break;
     }
   },
 
   classID: Components.ID("{723ed303-7757-4fb0-b261-4f78b1f6bd22}"),
 
   QueryInterface: XPCOMUtils.generateQI([Ci.mozIDOMApplication]),
 
   classInfo: XPCOMUtils.generateCI({classID: Components.ID("{723ed303-7757-4fb0-b261-4f78b1f6bd22}"),
@@ -384,29 +528,34 @@ function WebappsApplicationMgmt(aWindow)
 
   this._oninstall = null;
   this._onuninstall = null;
 }
 
 WebappsApplicationMgmt.prototype = {
   __proto__: DOMRequestIpcHelper.prototype,
   __exposedProps__: {
-                      getAll: 'r',
-                      getNotInstalled: 'r',
-                      oninstall: 'rw',
-                      onuninstall: 'rw'
+                      applyDownload: "r",
+                      getAll: "r",
+                      getNotInstalled: "r",
+                      oninstall: "rw",
+                      onuninstall: "rw"
                      },
 
   uninit: function() {
     this._oninstall = null;
     this._onuninstall = null;
     cpmm.sendAsyncMessage("Webapps:UnregisterForMessages",
                           ["Webapps:Install:Return:OK", "Webapps:Uninstall:Return:OK"]);
   },
 
+  applyDownload: function(aApp) {
+    return Cr.NS_ERROR_NOT_IMPLEMENTED;
+  },
+
   getAll: function() {
     let request = this.createRequest();
     cpmm.sendAsyncMessage("Webapps:GetAll", { oid: this._id,
                                               requestID: this.getRequestId(request),
                                               hasPrivileges: this.hasPrivileges });
     return request;
   },
 
@@ -482,9 +631,11 @@ WebappsApplicationMgmt.prototype = {
 
   classInfo: XPCOMUtils.generateCI({classID: Components.ID("{8c1bca96-266f-493a-8d57-ec7a95098c15}"),
                                     contractID: "@mozilla.org/webapps/application-mgmt;1",
                                     interfaces: [Ci.mozIDOMApplicationMgmt],
                                     flags: Ci.nsIClassInfo.DOM_OBJECT,
                                     classDescription: "Webapps Application Mgmt"})
 }
 
-const NSGetFactory = XPCOMUtils.generateNSGetFactory([WebappsRegistry, WebappsApplication]);
+const NSGetFactory = XPCOMUtils.generateNSGetFactory([WebappsRegistry,
+                                                      WebappsApplication,
+                                                      DOMError]);
--- a/dom/apps/src/Webapps.jsm
+++ b/dom/apps/src/Webapps.jsm
@@ -12,16 +12,20 @@ const Cr = Components.results;
 let EXPORTED_SYMBOLS = ["DOMApplicationRegistry", "DOMApplicationManifest"];
 
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 Cu.import("resource://gre/modules/Services.jsm");
 Cu.import("resource://gre/modules/FileUtils.jsm");
 Cu.import('resource://gre/modules/ActivitiesService.jsm');
 Cu.import("resource://gre/modules/AppsUtils.jsm");
 
+function debug(aMsg) {
+  //dump("-*-*- Webapps.jsm : " + aMsg + "\n");
+}
+
 const WEBAPP_RUNTIME = Services.appinfo.ID == "webapprt@mozilla.org";
 
 XPCOMUtils.defineLazyGetter(this, "NetUtil", function() {
   Cu.import("resource://gre/modules/NetUtil.jsm");
   return NetUtil;
 });
 
 XPCOMUtils.defineLazyServiceGetter(this, "ppmm",
@@ -56,17 +60,20 @@ let DOMApplicationRegistry = {
 
   init: function() {
     this.messages = ["Webapps:Install", "Webapps:Uninstall",
                      "Webapps:GetSelf", "Webapps:IsInstalled",
                      "Webapps:GetInstalled", "Webapps:GetNotInstalled",
                      "Webapps:Launch", "Webapps:GetAll",
                      "Webapps:InstallPackage", "Webapps:GetBasePath",
                      "Webapps:GetList", "Webapps:RegisterForMessages",
-                     "Webapps:UnregisterForMessages"];
+                     "Webapps:UnregisterForMessages",
+                     "Webapps:CancelDownload", "Webapps:CheckForUpdate"];
+
+    this.frameMessages = ["Webapps:ClearBrowserData"];
 
     this.messages.forEach((function(msgName) {
       ppmm.addMessageListener(msgName, this);
     }).bind(this));
 
     cpmm.addMessageListener("Activities:Register:OK", this);
 
     Services.obs.addObserver(this, "xpcom-shutdown", false);
@@ -440,17 +447,17 @@ let DOMApplicationRegistry = {
       case "Webapps:GetSelf":
         this.getSelf(msg, mm);
         break;
       case "Webapps:Uninstall":
         Services.obs.notifyObservers(mm, "webapps-uninstall", JSON.stringify(msg));
         this.uninstall(msg);
         break;
       case "Webapps:Launch":
-        Services.obs.notifyObservers(mm, "webapps-launch", JSON.stringify(msg));
+        this.launchApp(msg, mm);
         break;
       case "Webapps:IsInstalled":
         this.isInstalled(msg, mm);
         break;
       case "Webapps:GetInstalled":
         this.getInstalled(msg, mm);
         break;
       case "Webapps:GetNotInstalled":
@@ -472,16 +479,22 @@ let DOMApplicationRegistry = {
         this.addMessageListener(msg, mm);
         break;
       case "Webapps:UnregisterForMessages":
         this.removeMessageListener(msg, mm);
         break;
       case "Webapps:GetList":
         this.addMessageListener(["Webapps:AddApp", "Webapps:RemoveApp"], mm);
         return this.webapps;
+      case "Webapps:CancelDownload":
+        this.cancelDowload(msg.manifestURL);
+        break;
+      case "Webapps:CheckForUpdate":
+        this.checkForUpdate(msg, mm);
+        break;
       case "Activities:Register:OK":
         this.activitiesRegistered++;
         if (this.allActivitiesSent &&
             this.activitiesRegistered === this.activitiesToRegister) {
           this.onInitDone();
         }
         break;
     }
@@ -529,16 +542,167 @@ let DOMApplicationRegistry = {
     // Asynchronously copy the data to the file.
     let istream = converter.convertToInputStream(aData);
     NetUtil.asyncCopy(istream, ostream, function(rc) {
       if (aCallbak)
         aCallbak();
     });
   },
 
+  launchApp: function launchApp(aData, aMm) {
+    let app = this.getAppByManifestURL(aData.manifestURL);
+    if (!app) {
+      aMm.sendAsyncMessage("Webapps:Launch:Return:KO", aData);
+      return;
+    }
+
+    // Fire an error when trying to launch an app that is not
+    // yet fully installed.
+    if (app.installState == "pending") {
+      aMm.sendAsyncMessage("Webapps:Launch:Return:KO", aData);
+      return;
+    }
+
+    Services.obs.notifyObservers(aMm, "webapps-launch", JSON.stringify(aData));
+  },
+
+  cancelDownload: function cancelDowload(aManifestURL) {
+    // We can't cancel appcache dowloads for now.
+  },
+
+  startOfflineCacheDownload: function startOfflineCacheDownload(aManifest, aApp, aProfileDir) {
+    // if the manifest has an appcache_path property, use it to populate the appcache
+    if (aManifest.appcache_path) {
+      let appcacheURI = Services.io.newURI(aManifest.fullAppcachePath(), null, null);
+      let updateService = Cc["@mozilla.org/offlinecacheupdate-service;1"]
+                            .getService(Ci.nsIOfflineCacheUpdateService);
+      let docURI = Services.io.newURI(aManifest.fullLaunchPath(), null, null);
+      let cacheUpdate = aProfileDir ? updateService.scheduleCustomProfileUpdate(appcacheURI, docURI, aProfileDir)
+                                    : updateService.scheduleUpdate(appcacheURI, docURI, null);
+      cacheUpdate.addObserver(new AppcacheObserver(aApp), false);
+      if (aOfflineCacheObserver) {
+        cacheUpdate.addObserver(aOfflineCacheObserver, false);
+      }
+    }
+  },
+
+  checkForUpdate: function(aData, aMm) {
+    let app = this.getAppByManifestURL(aData.manifestURL);
+    if (!app) {
+      aData.error = "NO_SUCH_APP";
+      aMm.sendAsyncMessage("Webapps:CheckForUpdate:Return:KO", aData);
+      return;
+    }
+
+    function sendError(aError) {
+      aData.error = aError;
+      aMm.sendAsyncMessage("Webapps:CheckForUpdate:Return:KO", aData);
+    }
+
+    function updatePackagedApp(aManifest) {
+      debug("updatePackagedApp");
+    }
+
+    function updateHostedApp(aManifest) {
+      debug("updateHostedApp");
+      let id = this._appId(app.origin);
+
+#ifdef MOZ_SYS_MSG
+      // Update the Web Activities
+      this._readManifests([{ id: id }], (function unregisterManifest(aResult) {
+        this._unregisterActivities(aResult[0].manifest, app);
+        this._registerSystemMessages(aManifest, app);
+        this._registerActivities(aManifest, app);
+      }).bind(this));
+#endif
+
+      // Store the new manifest.
+      let dir = FileUtils.getDir(DIRECTORY_NAME, ["webapps", id], true, true);
+      let manFile = dir.clone();
+      manFile.append("manifest.webapp");
+      this._writeFile(manFile, JSON.stringify(aManifest), function() { });
+
+      let manifest = new DOMApplicationManifest(aManifest, app.origin);
+
+      if (manifest.appcache_path) {
+        app.installState = "updating";
+        app.downloadAvailable = true;
+        app.downloading = true;
+        app.downloadsize = 0;
+        app.readyToApplyDownload = false;
+      } else {
+        app.installState = "installed";
+        app.downloadAvailable = false;
+        app.downloading = false;
+        app.readyToApplyDownload = false;
+      }
+
+      app.name = aManifest.name;
+
+      // Update the registry.
+      this.webapps[id] = app;
+
+      this._saveApps((function() {
+        // XXX Should we fire notifications ?
+      }).bind(this));
+
+      // Preload the appcache if needed.
+      this.startOfflineCacheDownload(manifest, app);
+    }
+
+    // First, we download the manifest.
+    let xhr = Cc["@mozilla.org/xmlextras/xmlhttprequest;1"]
+                .createInstance(Ci.nsIXMLHttpRequest);
+    xhr.open("GET", aData.manifestURL, true);
+    if (aData.etag) {
+      xhr.setRequestHeader("If-None-Match", aData.etag);
+    }
+
+    xhr.addEventListener("load", (function() {
+      if (xhr.status == 200) {
+        let manifest;
+        try {
+          JSON.parse(xhr.responseText, installOrigin);
+        } catch(e) {
+          sendError("MANIFEST_PARSE_ERROR");
+          return;
+        }
+        if (!AppsUtils.checkManifest(manifest, installOrigin)) {
+          sendError("INVALID_MANIFEST");
+        } else {
+          app.etag = xhr.getResponseHeader("Etag");
+          app.lastCheckedUpdate = Date.now();
+          if (package_path in manifest) {
+            updatePackagedApp(manifest);
+          } else {
+            updateHostedApp(manifest);
+          }
+        }
+        this._saveApps();
+      } else if (xhr.status == 304) {
+        // The manifest has not changed. We just update lastCheckedUpdate.
+        app.lastCheckedUpdate = Date.now();
+        aData.event = "downloadapplied";
+        aData.app = {
+          lastCheckedUpdate: app.lastCheckedUpdate
+        }
+        aMm.sendAsyncMessage("Webapps:CheckForUpdate:Return:OK", aData);
+        this._saveApps();
+      } else {
+        sendError("MANIFEST_URL_ERROR");
+      }
+    }).bind(this), false);
+
+    xhr.addEventListener("error", (function() {
+      sendError(request, "NETWORK_ERROR");
+    }).bind(this), false);
+
+    xhr.send(null);
+  },
+
   denyInstall: function(aData) {
     let packageId = aData.app.packageId;
     if (packageId) {
       let dir = FileUtils.getDir("TmpD", ["webapps", packageId],
                                  true, true);
       try {
         dir.remove(true);
       } catch(e) {
@@ -568,16 +732,17 @@ let DOMApplicationRegistry = {
     if (app.packageId) {
       // Override the origin with the correct id.
       app.origin = "app://" + id;
     }
 
     let appObject = AppsUtils.cloneAppObject(app);
     appObject.appStatus = app.appStatus || Ci.nsIPrincipal.APP_STATUS_INSTALLED;
     appObject.installTime = app.installTime = Date.now();
+    appObject.lastUpdateCheck = app.lastUpdateCheck = Date.now();
     let appNote = JSON.stringify(appObject);
     appNote.id = id;
 
     appObject.localId = localId;
     appObject.basePath = FileUtils.getDir(DIRECTORY_NAME, ["webapps"], true, true).path;
 
     let dir = FileUtils.getDir(DIRECTORY_NAME, ["webapps", id], true, true);
     let manFile = dir.clone();
@@ -592,48 +757,49 @@ let DOMApplicationRegistry = {
         let tmpDir = FileUtils.getDir("TmpD", ["webapps", app.packageId],
                                         true, true);
         try {
           tmpDir.remove(true);
         } catch(e) {
         }
       }
     });
-    this.webapps[id] = appObject;
+
+    let manifest = new DOMApplicationManifest(app.manifest, app.origin);
 
-    appObject.status = "installed";
+    if (manifest.appcache_path) {
+      appObject.installState = "pending";
+      appObject.downloadAvailable = true;
+      appObject.downloading = true;
+      appObject.downloadsize = 0;
+      appObject.readyToApplyDownload = false;
+    } else {
+      appObject.installState = "installed";
+      appObject.downloadAvailable = false;
+      appObject.downloading = false;
+      appObject.readyToApplyDownload = false;
+    }
+
     appObject.name = app.manifest.name;
 
-    let manifest = new DOMApplicationManifest(app.manifest, app.origin);
+    this.webapps[id] = appObject;
 
     if (!aFromSync)
       this._saveApps((function() {
         this.broadcastMessage("Webapps:Install:Return:OK", aData);
         Services.obs.notifyObservers(this, "webapps-sync-install", appNote);
         this.broadcastMessage("Webapps:AddApp", { id: id, app: appObject });
       }).bind(this));
 
 #ifdef MOZ_SYS_MSG
     this._registerSystemMessages(app.manifest, app);
     this._registerActivities(app.manifest, app);
 #endif
 
-    // if the manifest has an appcache_path property, use it to populate the appcache
-    if (manifest.appcache_path) {
-      let appcacheURI = Services.io.newURI(manifest.fullAppcachePath(), null, null);
-      let updateService = Cc["@mozilla.org/offlinecacheupdate-service;1"]
-                            .getService(Ci.nsIOfflineCacheUpdateService);
-      let docURI = Services.io.newURI(manifest.fullLaunchPath(), null, null);
-      let cacheUpdate = aProfileDir ? updateService.scheduleCustomProfileUpdate(appcacheURI, docURI, aProfileDir)
-                                    : updateService.scheduleUpdate(appcacheURI, docURI, null);
-      cacheUpdate.addObserver(new AppcacheObserver(appObject), false);
-      if (aOfflineCacheObserver) {
-        cacheUpdate.addObserver(aOfflineCacheObserver, false);
-      }
-    }
+    this.startOfflineCacheDownload(manifest, appObject, aProfileDir);
   },
 
   _nextLocalId: function() {
     let id = Services.prefs.getIntPref("dom.mozApps.maxLocalId") + 1;
     Services.prefs.setIntPref("dom.mozApps.maxLocalId", id);
     return id;
   },
 
@@ -646,17 +812,17 @@ let DOMApplicationRegistry = {
   },
 
   makeAppId: function() {
     let uuidGenerator = Cc["@mozilla.org/uuid-generator;1"].getService(Ci.nsIUUIDGenerator);
     return uuidGenerator.generateUUID().toString();
   },
 
   _saveApps: function(aCallback) {
-    this._writeFile(this.appsFile, JSON.stringify(this.webapps), function() {
+    this._writeFile(this.appsFile, JSON.stringify(this.webapps, null, 2), function() {
       if (aCallback)
         aCallback();
     });
   },
 
   /**
     * Asynchronously reads a list of manifests
     */
@@ -837,21 +1003,21 @@ let DOMApplicationRegistry = {
 
       if (!this.webapps[id].removable)
         return;
 
       found = true;
       let appNote = JSON.stringify(AppsUtils.cloneAppObject(app));
       appNote.id = id;
 
+#ifdef MOZ_SYS_MSG
       this._readManifests([{ id: id }], (function unregisterManifest(aResult) {
-#ifdef MOZ_SYS_MSG
         this._unregisterActivities(aResult[0].manifest, app);
+      }).bind(this));
 #endif
-      }).bind(this));
 
       let dir = this._getAppDir(id);
       try {
         dir.remove(true);
       } catch (e) {}
 
       delete this.webapps[id];
 
@@ -1131,54 +1297,134 @@ let DOMApplicationRegistry = {
 
     desktopINI.append("owa-" + uniqueName + ".desktop");
 
     return desktopINI.exists();
 #else
     return true;
 #endif
 
+  },
+
+  _notifyCategoryAndObservers: function(subject, topic, data) {
+    const serviceMarker = "service,";
+
+    // First create observers from the category manager.
+    let cm =
+      Cc["@mozilla.org/categorymanager;1"].getService(Ci.nsICategoryManager);
+    let enumerator = cm.enumerateCategory(topic);
+
+    let observers = [];
+
+    while (enumerator.hasMoreElements()) {
+      let entry =
+        enumerator.getNext().QueryInterface(Ci.nsISupportsCString).data;
+      let contractID = cm.getCategoryEntry(topic, entry);
+
+      let factoryFunction;
+      if (contractID.substring(0, serviceMarker.length) == serviceMarker) {
+        contractID = contractID.substring(serviceMarker.length);
+        factoryFunction = "getService";
+      }
+      else {
+        factoryFunction = "createInstance";
+      }
+
+      try {
+        let handler = Cc[contractID][factoryFunction]();
+        if (handler) {
+          let observer = handler.QueryInterface(Ci.nsIObserver);
+          observers.push(observer);
+        }
+      } catch(e) { }
+    }
+
+    // Next enumerate the registered observers.
+    enumerator = Services.obs.enumerateObservers(topic);
+    while (enumerator.hasMoreElements()) {
+      let observer = enumerator.getNext();
+      if (observers.indexOf(observer) == -1) {
+        observers.push(observer);
+      }
+    }
+
+    observers.forEach(function (observer) {
+      try {
+        observer.observe(subject, topic, data);
+      } catch(e) { }
+    });
+  },
+
+  registerBrowserElementParentForApp: function(bep, appId) {
+    let mm = bep._mm;
+
+    // Make a listener function that holds on to this appId.
+    let listener = this.receiveAppMessage.bind(this, appId);
+
+    this.frameMessages.forEach(function(msgName) {
+      mm.addMessageListener(msgName, listener);
+    });
+  },
+
+  receiveAppMessage: function(appId, message) {
+    switch (message.name) {
+      case "Webapps:ClearBrowserData":
+        let subject = {
+          appId: appId,
+          browserOnly: true,
+          QueryInterface: XPCOMUtils.generateQI([Ci.mozIApplicationClearPrivateDataParams])
+        };
+        this._notifyCategoryAndObservers(subject, "webapps-clear-data", null);
+        break;
+    }
   }
 };
 
 /**
  * Appcache download observer
  */
 let AppcacheObserver = function(aApp) {
   this.app = aApp;
+  this.startStatus = aApp.installState;
 };
 
 AppcacheObserver.prototype = {
   // nsIOfflineCacheUpdateObserver implementation
   updateStateChanged: function appObs_Update(aUpdate, aState) {
     let mustSave = false;
     let app = this.app;
 
     let setStatus = function appObs_setStatus(aStatus) {
-      mustSave = (app.status != aStatus);
-      app.status = aStatus;
+      mustSave = (app.installState != aStatus);
+      app.installState = aStatus;
       DOMApplicationRegistry.broadcastMessage("Webapps:OfflineCache",
                                               { manifest: app.manifestURL,
-                                                status: aStatus });
+                                                installState: app.installState });
+    }
+
+    let setError = function appObs_setError(aError) {
+      DOMApplicationRegistry.broadcastMessage("Webapps:OfflineCache",
+                                              { manifest: app.manifestURL,
+                                                error: aError });
     }
 
     switch (aState) {
       case Ci.nsIOfflineCacheUpdateObserver.STATE_ERROR:
         aUpdate.removeObserver(this);
-        setStatus("cache-error");
+        setError("APP_CACHE_DOWNLOAD_ERROR");
         break;
       case Ci.nsIOfflineCacheUpdateObserver.STATE_NOUPDATE:
       case Ci.nsIOfflineCacheUpdateObserver.STATE_FINISHED:
         aUpdate.removeObserver(this);
-        setStatus("cached");
+        setStatus("installed");
         break;
       case Ci.nsIOfflineCacheUpdateObserver.STATE_DOWNLOADING:
       case Ci.nsIOfflineCacheUpdateObserver.STATE_ITEMSTARTED:
       case Ci.nsIOfflineCacheUpdateObserver.STATE_ITEMPROGRESS:
-        setStatus("downloading")
+        setStatus(this.startStatus);
         break;
     }
 
     // Status changed, update the stored version.
     if (mustSave) {
       DOMApplicationRegistry._saveApps();
     }
   },
--- a/dom/apps/src/Webapps.manifest
+++ b/dom/apps/src/Webapps.manifest
@@ -1,7 +1,10 @@
 # Webapps.js
 component {fff440b3-fae2-45c1-bf03-3b5a2e432270} Webapps.js
 contract @mozilla.org/webapps;1 {fff440b3-fae2-45c1-bf03-3b5a2e432270}
 category JavaScript-navigator-property mozApps @mozilla.org/webapps;1
 
 component {723ed303-7757-4fb0-b261-4f78b1f6bd22} Webapps.js
 contract @mozilla.org/webapps/application;1 {723ed303-7757-4fb0-b261-4f78b1f6bd22}
+
+component {dcc1d5b7-43d8-4740-9244-b3d8db0f503d} Webapps.js
+contract @mozilla.org/dom-error;1 {dcc1d5b7-43d8-4740-9244-b3d8db0f503d}
--- a/dom/base/nsIDOMDOMError.idl
+++ b/dom/base/nsIDOMDOMError.idl
@@ -1,13 +1,13 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set ts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "nsISupports.idl"
 
-[scriptable, builtinclass, uuid(e4e28307-d409-4cf7-93cd-6ea8e889f87a)]
+[scriptable, uuid(e4e28307-d409-4cf7-93cd-6ea8e889f87a)]
 interface nsIDOMDOMError : nsISupports
 {
   readonly attribute DOMString name;
 };
--- a/dom/bluetooth/BluetoothHfpManager.cpp
+++ b/dom/bluetooth/BluetoothHfpManager.cpp
@@ -5,22 +5,25 @@
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "BluetoothHfpManager.h"
 
 #include "BluetoothReplyRunnable.h"
 #include "BluetoothService.h"
 #include "BluetoothServiceUuid.h"
 
+#include "mozilla/Services.h"
+#include "nsIObserverService.h"
+
 USING_BLUETOOTH_NAMESPACE
 using namespace mozilla::ipc;
 
 static nsRefPtr<BluetoothHfpManager> sInstance = nullptr;
 
-BluetoothHfpManager::BluetoothHfpManager()
+BluetoothHfpManager::BluetoothHfpManager() : mCurrentVgs(-1)
 {
 }
 
 BluetoothHfpManager::~BluetoothHfpManager()
 {
 }
 
 //static
@@ -36,16 +39,89 @@ BluetoothHfpManager::Get()
   return sInstance;
 }
 
 // Virtual function of class SocketConsumer
 void
 BluetoothHfpManager::ReceiveSocketData(UnixSocketRawData* aMessage)
 {
   MOZ_ASSERT(NS_IsMainThread());
+
+  const char* msg = (const char*)aMessage->mData;
+
+  // For more information, please refer to 4.34.1 "Bluetooth Defined AT
+  // Capabilities" in Bluetooth hands-free profile 1.6
+  if (!strncmp(msg, "AT+BRSF=", 8)) {
+    SendLine("+BRSF: 23");
+    SendLine("OK");
+  } else if (!strncmp(msg, "AT+CIND=?", 9)) {
+    nsAutoCString cindRange;
+
+    cindRange += "+CIND: ";
+    cindRange += "(\"battchg\",(0-5)),";
+    cindRange += "(\"signal\",(0-5)),";
+    cindRange += "(\"service\",(0,1)),";
+    cindRange += "(\"call\",(0,1)),";
+    cindRange += "(\"callsetup\",(0-3)),";
+    cindRange += "(\"callheld\",(0-2)),";
+    cindRange += "(\"roam\",(0,1))";
+
+    SendLine(cindRange.get());
+    SendLine("OK");
+  } else if (!strncmp(msg, "AT+CIND", 7)) {
+    // FIXME - Bug 794349
+    // This value reflects current status of telephony, roaming, battery ...,
+    // so obviously fixed value must be wrong if there is an ongoing call. 
+    // Need a patch for this, but currently just using fixed value for basic 
+    // SLC establishment.
+    SendLine("+CIND: 5,5,1,0,0,0,0");
+    SendLine("OK");
+  } else if (!strncmp(msg, "AT+CMER=", 8)) {
+    SendLine("OK");
+  } else if (!strncmp(msg, "AT+CHLD=?", 9)) {
+    SendLine("+CHLD: (0,1,2,3)");
+    SendLine("OK");
+  } else if (!strncmp(msg, "AT+CHLD=", 8)) {
+    SendLine("OK");
+  } else if (!strncmp(msg, "AT+VGS=", 7)) {
+    // VGS range: [0, 15]
+    int newVgs = msg[7] - '0';
+
+    if (strlen(msg) > 8) {
+      newVgs *= 10;
+      newVgs += (msg[8] - '0');
+    }
+
+#ifdef DEBUG
+    NS_ASSERTION(newVgs >= 0 && newVgs <= 15, "Received invalid VGS value");
+#endif
+
+    // Currently, we send volume up/down commands to represent that
+    // volume has been changed by Bluetooth headset, and that will affect
+    // the main stream volume of our device. In the future, we may want to
+    // be able to set volume by stream.
+    nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService();
+    if (newVgs > mCurrentVgs) {
+      os->NotifyObservers(nullptr, "bluetooth-volume-change", NS_LITERAL_STRING("up").get());
+    } else if (newVgs < mCurrentVgs) {
+      os->NotifyObservers(nullptr, "bluetooth-volume-change", NS_LITERAL_STRING("down").get());
+    }
+
+    mCurrentVgs = newVgs;
+
+    SendLine("OK");
+  } else {
+#ifdef DEBUG
+    nsCString warningMsg;
+    warningMsg.AssignLiteral("Not handling HFP message, reply ok: ");
+    warningMsg.Append(msg);
+    NS_WARNING(warningMsg.get());
+#endif
+    SendLine("OK");
+  }
 }
 
 bool
 BluetoothHfpManager::Connect(const nsAString& aDeviceObjectPath,
                              BluetoothReplyRunnable* aRunnable)
 {
   MOZ_ASSERT(NS_IsMainThread());
 
@@ -73,8 +149,21 @@ BluetoothHfpManager::Connect(const nsASt
 }
 
 void
 BluetoothHfpManager::Disconnect()
 {
   CloseSocket();
 }
 
+bool
+BluetoothHfpManager::SendLine(const char* aMessage)
+{
+  const char* kHfpCrlf = "\xd\xa";
+  nsAutoCString msg;
+
+  msg += kHfpCrlf;
+  msg += aMessage;
+  msg += kHfpCrlf;
+
+  return SendSocketData(msg);
+}
+
--- a/dom/bluetooth/BluetoothHfpManager.h
+++ b/dom/bluetooth/BluetoothHfpManager.h
@@ -20,16 +20,19 @@ public:
   ~BluetoothHfpManager();
 
   static BluetoothHfpManager* Get();
   void ReceiveSocketData(mozilla::ipc::UnixSocketRawData* aMessage);
 
   bool Connect(const nsAString& aDeviceObjectPath,
                BluetoothReplyRunnable* aRunnable);
   void Disconnect();
+  bool SendLine(const char* aMessage);
 
 private:
   BluetoothHfpManager();
+
+  int mCurrentVgs;
 };
 
 END_BLUETOOTH_NAMESPACE
 
 #endif
--- a/dom/browser-element/BrowserElementChild.js
+++ b/dom/browser-element/BrowserElementChild.js
@@ -670,16 +670,28 @@ BrowserElementChild.prototype = {
 
       sendAsyncMsg('securitychange', {state: stateDesc, extendedValidation: isEV});
     },
 
     onStatusChange: function(webProgress, request, status, message) {},
     onProgressChange: function(webProgress, request, curSelfProgress,
                                maxSelfProgress, curTotalProgress, maxTotalProgress) {},
   },
+
+  // Expose the message manager for WebApps and others.
+  _messageManagerPublic: {
+    sendAsyncMessage: global.sendAsyncMessage.bind(global),
+    sendSyncMessage: global.sendSyncMessage.bind(global),
+    addMessageListener: global.addMessageListener.bind(global),
+    removeMessageListener: global.removeMessageListener.bind(global)
+  },
+
+  get messageManager() {
+    return this._messageManagerPublic;
+  }
 };
 
 var api = new BrowserElementChild();
 
 // FIXME/bug 775438: use a JSM?
 //
 // The code in this included file depends on the |addEventListener|,
 // |addMessageListener|, |content|, |Geometry| and |Services| symbols
--- a/dom/browser-element/BrowserElementParent.js
+++ b/dom/browser-element/BrowserElementParent.js
@@ -8,16 +8,21 @@ let Cu = Components.utils;
 let Ci = Components.interfaces;
 let Cc = Components.classes;
 let Cr = Components.results;
 
 Cu.import("resource://gre/modules/Services.jsm");
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 Cu.import("resource://gre/modules/BrowserElementPromptService.jsm");
 
+XPCOMUtils.defineLazyGetter(this, "DOMApplicationRegistry", function () {
+  Cu.import("resource://gre/modules/Webapps.jsm");
+  return DOMApplicationRegistry;
+});
+
 const NS_PREFBRANCH_PREFCHANGE_TOPIC_ID = "nsPref:changed";
 const BROWSER_FRAMES_ENABLED_PREF = "dom.mozBrowserFramesEnabled";
 const TOUCH_EVENTS_ENABLED_PREF = "dom.w3c_touch_events.enabled";
 
 function debug(msg) {
   //dump("BrowserElementParent - " + msg + "\n");
 }
 
@@ -245,16 +250,28 @@ function BrowserElementParent(frameLoade
   // down to the child.
   this._window.addEventListener('mozvisibilitychange',
                                 this._ownerVisibilityChange.bind(this),
                                 /* useCapture = */ false,
                                 /* wantsUntrusted = */ false);
 
   // Insert ourself into the prompt service.
   BrowserElementPromptService.mapFrameToBrowserElementParent(this._frameElement, this);
+
+  // If this browser represents an app then let the Webapps module register for
+  // any messages that it needs.
+  let appManifestURL =
+    this._frameElement.QueryInterface(Ci.nsIMozBrowserFrame).appManifestURL;
+  if (appManifestURL) {
+    let appId =
+      DOMApplicationRegistry.getAppLocalIdByManifestURL(appManifestURL);
+    if (appId != Ci.nsIScriptSecurityManager.NO_APP_ID) {
+      DOMApplicationRegistry.registerBrowserElementParentForApp(this, appId);
+    }
+  }
 }
 
 BrowserElementParent.prototype = {
 
   QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver,
                                          Ci.nsISupportsWeakReference]),
 
   /**
--- a/dom/interfaces/apps/Makefile.in
+++ b/dom/interfaces/apps/Makefile.in
@@ -11,16 +11,17 @@ VPATH          = @srcdir@
 include $(DEPTH)/config/autoconf.mk
 
 MODULE         = dom
 XPIDL_MODULE   = dom_apps
 GRE_MODULE     = 1
 
 XPIDLSRCS =                               \
             mozIApplication.idl \
+            mozIApplicationClearPrivateDataParams.idl \
             nsIDOMApplicationRegistry.idl \
             nsIDOMApplicationRegistry2.idl \
             nsIAppsService.idl \
             nsIDOMMozApplicationEvent.idl \
             $(NULL)
 
 include $(topsrcdir)/config/rules.mk
 
new file mode 100644
--- /dev/null
+++ b/dom/interfaces/apps/mozIApplicationClearPrivateDataParams.idl
@@ -0,0 +1,15 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ * vim: sw=2 ts=8 et :
+ */
+/* 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 "nsISupports.idl"
+
+[scriptable, uuid(ba0e6c8e-8c03-4b9b-8f9b-4fb14216f56e)]
+interface mozIApplicationClearPrivateDataParams
+{
+  readonly attribute unsigned long appId;
+  readonly attribute boolean browserOnly;
+};
--- a/dom/interfaces/apps/nsIDOMApplicationRegistry.idl
+++ b/dom/interfaces/apps/nsIDOMApplicationRegistry.idl
@@ -1,54 +1,96 @@
 /* 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 "domstubs.idl"
 #include "nsIDOMEventTarget.idl"
 
 interface nsIDOMDOMRequest;
-interface nsIArray;
+interface nsIDOMDOMError;
 
-[scriptable, uuid(e3649c1d-c950-495e-b0ed-6ce40be9743b)]
+[scriptable, uuid(b00a5908-1228-46bf-a42b-091dce3abde1)]
 interface mozIDOMApplication  : nsISupports
 {
   readonly attribute jsval manifest;
+  readonly attribute jsval updateManifest;
   readonly attribute DOMString manifestURL;
   readonly attribute jsval receipts; /* an array of strings */
   readonly attribute DOMString origin;
   readonly attribute DOMString installOrigin;
   readonly attribute unsigned long long installTime;
   readonly attribute boolean removable;
 
-  /* 
+  /**
    * The current progress when downloading an offline cache.
    */
   readonly attribute double progress;
 
-  /*
-   * The application status :
-   * "installed"   : The app is in the registry, but we have no offline cache.
-   * "downlading"  : We are downloading the offline cache.
-   * "cached"      : We are done with the offline cache download.
-   * "cache-error" : An error occured while downloading the offline-cache.
+  /**
+   * The application installation state :
+   * "pending"   : The application is being installed (eg, we're downloading the
+   *               offline cache or the package).
+   * "installed" : The application is installed and ready to be launched.
+   * "updating"  : We are updating the offline-cache or the package.
    */
-  readonly attribute DOMString status;
+  readonly attribute DOMString installState;
 
-  /*
-   * fires a nsIDOMApplicationEvent when a change in appcache download or status happens
+  /**
+   * fires a nsIDOMApplicationEvent when a change in appcache download or
+   * package download happens.
    */
   attribute nsIDOMEventListener onprogress;
 
+  /**
+   * The date of the last update.
+   */
+  readonly attribute unsigned long long lastUpdateCheck;
+
+  /**
+   * Starts the process of looking for an update.
+   */
+  nsIDOMDOMRequest checkForUpdate();
+
+  readonly attribute boolean downloadAvailable;
+  readonly attribute boolean downloading;
+  readonly attribute boolean readyToApplyDownload;
+  readonly attribute long downloadSize;
+
+  readonly attribute nsIDOMDOMError downloadError;
+
+  attribute nsIDOMEventListener ondownloadsuccess;
+  attribute nsIDOMEventListener ondownloaderror;
+  attribute nsIDOMEventListener ondownloadavailable;
+
+  /**
+   * Will fire once the mgmt.applyDownload() call succeeds.
+   */
+  attribute nsIDOMEventListener ondownloadapplied;
+
+  /**
+   * Starts to download an update. If |downloading| is true, this
+   * is a no-op.
+   */
+  void download();
+
+  /**
+   * Cancels an ongoing update download.
+   */
+  void cancelDownload();
+
   /* startPoint will be used when several launch_path exists for an app */
   nsIDOMDOMRequest launch([optional] in DOMString startPoint);
   nsIDOMDOMRequest uninstall();
+
+  /* Clear data that has been collected through mozbrowser elements. */
+  void clearBrowserData();
 };
 
-[scriptable, uuid(4c36ca48-841e-4d5a-8c46-dda14ac633ca)]
+[scriptable, uuid(0015d114-70c1-44ae-a8a3-fb6c107fe0e1)]
 interface mozIDOMApplicationMgmt : nsISupports
 {
   /**
    * the request will return the all the applications installed. Only accessible
    * to privileged callers.
    */
   nsIDOMDOMRequest getAll();
 
@@ -66,16 +108,23 @@ interface mozIDOMApplicationMgmt : nsISu
   attribute nsIDOMEventListener oninstall;
 
   /**
    * event listener to get notified of application uninstalls. Only settable by
    * privileged callers.
    * the event will be a mozIDOMApplicationEvent
    */
   attribute nsIDOMEventListener onuninstall;
+
+  /**
+   * Applies a downloaded update.
+   * This function is a no-op if it's passed an app object which doesn't have
+   * |readyToApplyDownload| set to true.
+   */
+  void applyDownload(in mozIDOMApplication app);
 };
 
 [scriptable, uuid(7ca34d3e-d855-4d0a-a3b3-58c0acad9ec3)]
 interface mozIDOMApplicationRegistry : nsISupports
 {
   /**
    * Install a web app.
    *
--- a/dom/plugins/base/nsNPAPIPluginInstance.cpp
+++ b/dom/plugins/base/nsNPAPIPluginInstance.cpp
@@ -166,32 +166,24 @@ nsNPAPIPluginInstance::nsNPAPIPluginInst
     mWindowless(false),
     mTransparent(false),
     mCached(false),
     mUsesDOMForCursor(false),
     mInPluginInitCall(false),
     mPlugin(nullptr),
     mMIMEType(nullptr),
     mOwner(nullptr),
-    mCurrentPluginEvent(nullptr),
-#if defined(MOZ_X11) || defined(XP_WIN) || defined(XP_MACOSX)
-    mUsePluginLayersPref(true)
-#else
-    mUsePluginLayersPref(false)
-#endif
+    mCurrentPluginEvent(nullptr)
 #ifdef MOZ_WIDGET_ANDROID
   , mOnScreen(true)
 #endif
 {
   mNPP.pdata = NULL;
   mNPP.ndata = this;
 
-  mUsePluginLayersPref =
-    Preferences::GetBool("plugins.use_layers", mUsePluginLayersPref);
-
   PLUGIN_LOG(PLUGIN_LOG_BASIC, ("nsNPAPIPluginInstance ctor: this=%p\n",this));
 }
 
 nsNPAPIPluginInstance::~nsNPAPIPluginInstance()
 {
   PLUGIN_LOG(PLUGIN_LOG_BASIC, ("nsNPAPIPluginInstance dtor: this=%p\n",this));
 
   if (mMIMEType) {
@@ -1207,23 +1199,18 @@ nsNPAPIPluginInstance::GetImageSize(nsIn
 nsresult
 nsNPAPIPluginInstance::NotifyPainted(void)
 {
   NS_NOTREACHED("Dead code, shouldn't be called.");
   return NS_ERROR_NOT_IMPLEMENTED;
 }
 
 nsresult
-nsNPAPIPluginInstance::UseAsyncPainting(bool* aIsAsync)
+nsNPAPIPluginInstance::GetIsOOP(bool* aIsAsync)
 {
-  if (!mUsePluginLayersPref) {
-    *aIsAsync = mUsePluginLayersPref;
-    return NS_OK;
-  }
-
   AutoPluginLibraryCall library(this);
   if (!library)
     return NS_ERROR_FAILURE;
 
   *aIsAsync = library->IsOOP();
   return NS_OK;
 }
 
--- a/dom/plugins/base/nsNPAPIPluginInstance.h
+++ b/dom/plugins/base/nsNPAPIPluginInstance.h
@@ -79,17 +79,17 @@ public:
   nsresult IsRemoteDrawingCoreAnimation(bool* aDrawing);
   nsresult GetJSObject(JSContext *cx, JSObject** outObject);
   bool ShouldCache();
   nsresult IsWindowless(bool* isWindowless);
   nsresult AsyncSetWindow(NPWindow* window);
   nsresult GetImageContainer(ImageContainer **aContainer);
   nsresult GetImageSize(nsIntSize* aSize);
   nsresult NotifyPainted(void);
-  nsresult UseAsyncPainting(bool* aIsAsync);
+  nsresult GetIsOOP(bool* aIsOOP);
   nsresult SetBackgroundUnknown();
   nsresult BeginUpdateBackground(nsIntRect* aRect, gfxContext** aContext);
   nsresult EndUpdateBackground(gfxContext* aContext, nsIntRect* aRect);
   nsresult IsTransparent(bool* isTransparent);
   nsresult GetFormValue(nsAString& aValue);
   nsresult PushPopupsEnabledState(bool aEnabled);
   nsresult PopPopupsEnabledState();
   nsresult GetPluginAPIVersion(uint16_t* version);
@@ -338,17 +338,16 @@ private:
 
   // non-null during a HandleEvent call
   void* mCurrentPluginEvent;
 
   // Timestamp for the last time this plugin was stopped.
   // This is only valid when the plugin is actually stopped!
   mozilla::TimeStamp mStopTime;
 
-  bool mUsePluginLayersPref;
 #ifdef MOZ_WIDGET_ANDROID
   void EnsureSharedTexture();
   nsSurfaceTexture* CreateSurfaceTexture();
 
   std::map<void*, VideoInfo*> mVideos;
   bool mOnScreen;
 
   nsIntSize mCurrentSize;
--- a/dom/plugins/base/nsPluginInstanceOwner.cpp
+++ b/dom/plugins/base/nsPluginInstanceOwner.cpp
@@ -258,20 +258,19 @@ bool
 nsPluginInstanceOwner::UseAsyncRendering()
 {
 #ifdef XP_MACOSX
   if (mUseAsyncRendering) {
     return true;
   }
 #endif
 
-  bool useAsyncRendering;
+  bool isOOP;
   bool result = (mInstance &&
-          NS_SUCCEEDED(mInstance->UseAsyncPainting(&useAsyncRendering)) &&
-          useAsyncRendering
+          NS_SUCCEEDED(mInstance->GetIsOOP(&isOOP)) && isOOP
 #ifndef XP_MACOSX
           && (!mPluginWindow ||
            mPluginWindow->type == NPWindowTypeDrawable)
 #endif
           );
 
 #ifdef XP_MACOSX
   if (result) {
--- a/dom/plugins/ipc/PPluginInstance.ipdl
+++ b/dom/plugins/ipc/PPluginInstance.ipdl
@@ -141,20 +141,16 @@ child:
     returns (bool handled);
 
   async NPP_DidComposite();
 
   rpc NPP_Destroy()
     returns (NPError rv);
 
 parent:
-  rpc NPN_GetValue_NPNVjavascriptEnabledBool()
-    returns (bool value, NPError result);
-  rpc NPN_GetValue_NPNVisOfflineBool()
-    returns (bool value, NPError result);
   rpc NPN_GetValue_NPNVWindowNPObject()
     returns (nullable PPluginScriptableObject value, NPError result);
   rpc NPN_GetValue_NPNVPluginElementNPObject()
     returns (nullable PPluginScriptableObject value, NPError result);
   rpc NPN_GetValue_NPNVprivateModeBool()
     returns (bool value, NPError result);
   rpc NPN_GetValue_NPNVnetscapeWindow()
     returns (NativeWindowHandle value, NPError result);
--- a/dom/plugins/ipc/PluginInstanceChild.cpp
+++ b/dom/plugins/ipc/PluginInstanceChild.cpp
@@ -282,41 +282,29 @@ NPError
 PluginInstanceChild::NPN_GetValue(NPNVariable aVar,
                                   void* aValue)
 {
     PLUGIN_LOG_DEBUG(("%s (aVar=%i)", FULLFUNCTION, (int) aVar));
     AssertPluginThread();
 
     switch(aVar) {
 
-    case NPNVSupportsWindowless:
-#if defined(OS_LINUX) || defined(MOZ_X11) || defined(OS_WIN)
-        *((NPBool*)aValue) = true;
-#else
-        *((NPBool*)aValue) = false;
-#endif
-        return NPERR_NO_ERROR;
-
 #if (MOZ_PLATFORM_MAEMO == 5) || (MOZ_PLATFORM_MAEMO == 6)
     case NPNVSupportsWindowlessLocal: {
 #ifdef MOZ_WIDGET_QT
         const char *graphicsSystem = PR_GetEnv("MOZ_QT_GRAPHICSSYSTEM");
         // we should set local rendering to false in order to render X-Plugin
         // there is no possibility to change it later on maemo5 platform
         mMaemoImageRendering = (!(graphicsSystem && !strcmp(graphicsSystem, "native")));
 #endif
         *((NPBool*)aValue) = mMaemoImageRendering;
         return NPERR_NO_ERROR;
     }
 #endif
 #if defined(MOZ_X11)
-    case NPNVSupportsXEmbedBool:
-        *((NPBool*)aValue) = true;
-        return NPERR_NO_ERROR;
-
     case NPNVToolkit:
         *((NPNToolkitType*)aValue) = NPNVGtk2;
         return NPERR_NO_ERROR;
 
     case NPNVxDisplay:
         if (!mWsInfo.display) {
             // We are called before Initialize() so we have to call it now.
            Initialize();
@@ -324,36 +312,16 @@ PluginInstanceChild::NPN_GetValue(NPNVar
         }
         *(void **)aValue = mWsInfo.display;
         return NPERR_NO_ERROR;
     
 #elif defined(OS_WIN)
     case NPNVToolkit:
         return NPERR_GENERIC_ERROR;
 #endif
-    case NPNVjavascriptEnabledBool: {
-        bool v = false;
-        NPError result;
-        if (!CallNPN_GetValue_NPNVjavascriptEnabledBool(&v, &result)) {
-            return NPERR_GENERIC_ERROR;
-        }
-        *static_cast<NPBool*>(aValue) = v;
-        return result;
-    }
-
-    case NPNVisOfflineBool: {
-        bool v = false;
-        NPError result;
-        if (!CallNPN_GetValue_NPNVisOfflineBool(&v, &result)) {
-            return NPERR_GENERIC_ERROR;
-        }
-        *static_cast<NPBool*>(aValue) = v;
-        return result;
-    }
-
     case NPNVprivateModeBool: {
         bool v = false;
         NPError result;
         if (!CallNPN_GetValue_NPNVprivateModeBool(&v, &result)) {
             return NPERR_GENERIC_ERROR;
         }
         *static_cast<NPBool*>(aValue) = v;
         return result;
@@ -463,16 +431,25 @@ PluginInstanceChild::NPN_GetValue(NPNVar
 #ifndef NP_NO_QUICKDRAW
     case NPNVsupportsQuickDrawBool: {
         *((NPBool*)aValue) = false;
         return NPERR_NO_ERROR;
     }
 #endif /* NP_NO_QUICKDRAW */
 #endif /* XP_MACOSX */
 
+#ifdef DEBUG
+    case NPNVjavascriptEnabledBool:
+    case NPNVasdEnabledBool:
+    case NPNVisOfflineBool:
+    case NPNVSupportsXEmbedBool:
+    case NPNVSupportsWindowless:
+        NS_NOTREACHED("NPNVariable should be handled in PluginModuleChild.");
+#endif
+
     default:
         PR_LOG(gPluginLog, PR_LOG_WARNING,
                ("In PluginInstanceChild::NPN_GetValue: Unhandled NPNVariable %i (%s)",
                 (int) aVar, NPNVariableToString(aVar)));
         return NPERR_GENERIC_ERROR;
     }
 
 }
--- a/dom/plugins/ipc/PluginInstanceParent.cpp
+++ b/dom/plugins/ipc/PluginInstanceParent.cpp
@@ -187,37 +187,16 @@ PluginInstanceParent::AllocPPluginStream
 bool
 PluginInstanceParent::DeallocPPluginStream(PPluginStreamParent* stream)
 {
     delete stream;
     return true;
 }
 
 bool
-PluginInstanceParent::AnswerNPN_GetValue_NPNVjavascriptEnabledBool(
-                                                       bool* value,
-                                                       NPError* result)
-{
-    NPBool v;
-    *result = mNPNIface->getvalue(mNPP, NPNVjavascriptEnabledBool, &v);
-    *value = v;
-    return true;
-}
-
-bool
-PluginInstanceParent::AnswerNPN_GetValue_NPNVisOfflineBool(bool* value,
-                                                           NPError* result)
-{
-    NPBool v;
-    *result = mNPNIface->getvalue(mNPP, NPNVisOfflineBool, &v);
-    *value = v;
-    return true;
-}
-
-bool
 PluginInstanceParent::AnswerNPN_GetValue_NPNVnetscapeWindow(NativeWindowHandle* value,
                                                             NPError* result)
 {
 #ifdef XP_WIN
     HWND id;
 #elif defined(MOZ_X11)
     XID id;
 #elif defined(XP_MACOSX)
--- a/dom/plugins/ipc/PluginInstanceParent.h
+++ b/dom/plugins/ipc/PluginInstanceParent.h
@@ -84,20 +84,16 @@ public:
     virtual PPluginStreamParent*
     AllocPPluginStream(const nsCString& mimeType,
                        const nsCString& target,
                        NPError* result);
     virtual bool
     DeallocPPluginStream(PPluginStreamParent* stream);
 
     virtual bool
-    AnswerNPN_GetValue_NPNVjavascriptEnabledBool(bool* value, NPError* result);
-    virtual bool
-    AnswerNPN_GetValue_NPNVisOfflineBool(bool* value, NPError* result);
-    virtual bool
     AnswerNPN_GetValue_NPNVnetscapeWindow(NativeWindowHandle* value,
                                           NPError* result);
     virtual bool
     AnswerNPN_GetValue_NPNVWindowNPObject(
                                        PPluginScriptableObjectParent** value,
                                        NPError* result);
     virtual bool
     AnswerNPN_GetValue_NPNVPluginElementNPObject(
--- a/dom/tests/mochitest/webapps/test_list_api.xul
+++ b/dom/tests/mochitest/webapps/test_list_api.xul
@@ -31,16 +31,17 @@ isDeeply([p for (p in navigator.mozApps)
          "navigator.mozApps has only the expected properties");
 
 for (var p in props) {
   is(typeof navigator.mozApps[p], props[p], "typeof " + p);
 }
 
 var mgmtProps = {
   QueryInterface: "function",
+  applyDownload: "function",
   getAll: "function",
   getNotInstalled: "function",
   oninstall: "object",
   onuninstall: "object",
 };
 
 isDeeply([p for (p in navigator.mozApps.mgmt)].sort(),
          Object.keys(mgmtProps).sort(),
--- a/gfx/layers/ipc/ShmemYCbCrImage.h
+++ b/gfx/layers/ipc/ShmemYCbCrImage.h
@@ -31,17 +31,18 @@ namespace layers {
 class ShmemYCbCrImage
 {
 public:
   typedef mozilla::ipc::Shmem Shmem;
 
   ShmemYCbCrImage() : mOffset(0) {}
 
   ShmemYCbCrImage(Shmem& shm, size_t offset = 0) {
-    NS_ABORT_IF_FALSE(Open(shm,offset), "Invalid data in Shmem.");
+    DebugOnly<bool> status = Open(shm,offset);
+    NS_ASSERTION(status, "Invalid data in the shmem");
   }
 
   /**
    * This function is meant as a helper to know how much shared memory we need
    * to allocate in a shmem in order to place a shared YCbCr image blob of 
    * given dimensions.
    */
   static size_t ComputeMinBufferSize(const gfxIntSize& aYSize,
--- a/js/src/ion/Bailouts.cpp
+++ b/js/src/ion/Bailouts.cpp
@@ -438,17 +438,17 @@ ion::InvalidationBailout(InvalidationBai
     return BAILOUT_RETURN_FATAL_ERROR;
 }
 
 static void
 ReflowArgTypes(JSContext *cx)
 {
     StackFrame *fp = cx->fp();
     unsigned nargs = fp->fun()->nargs;
-    JSScript *script = fp->script();
+    RootedScript script(cx, fp->script());
 
     types::AutoEnterTypeInference enter(cx);
 
     if (!fp->isConstructing())
         types::TypeScript::SetThis(cx, script, fp->thisValue());
     for (unsigned i = 0; i < nargs; ++i)
         types::TypeScript::SetArgument(cx, script, i, fp->unaliasedFormal(i, DONT_CHECK_ALIASING));
 }
@@ -462,17 +462,17 @@ ion::ReflowTypeInfo(uint32 bailoutResult
     IonSpew(IonSpew_Bailouts, "reflowing type info");
 
     if (bailoutResult == BAILOUT_RETURN_ARGUMENT_CHECK) {
         IonSpew(IonSpew_Bailouts, "reflowing type info at argument-checked entry");
         ReflowArgTypes(cx);
         return true;
     }
 
-    JSScript *script = cx->fp()->script();
+    RootedScript script(cx, cx->fp()->script());
     jsbytecode *pc = activation->bailout()->bailoutPc();
 
     JS_ASSERT(js_CodeSpec[*pc].format & JOF_TYPESET);
 
     IonSpew(IonSpew_Bailouts, "reflowing type info at %s:%d pcoff %d", script->filename,
             script->lineno, pc - script->code);
 
     types::AutoEnterTypeInference enter(cx);
--- a/js/src/ion/Ion.cpp
+++ b/js/src/ion/Ion.cpp
@@ -145,20 +145,20 @@ IonCompartment::initialize(JSContext *cx
         return false;
 
     return true;
 }
 
 void
 ion::FinishOffThreadBuilder(IonBuilder *builder)
 {
-    if (builder->script->isIonCompilingOffThread()) {
-        types::TypeCompartment &types = builder->script->compartment()->types;
+    if (builder->script()->isIonCompilingOffThread()) {
+        types::TypeCompartment &types = builder->script()->compartment()->types;
         builder->recompileInfo.compilerOutput(types)->invalidate();
-        builder->script->ion = NULL;
+        builder->script()->ion = NULL;
     }
     js_delete(builder->temp().lifoAlloc());
 }
 
 static inline void
 FinishAllOffThreadCompilations(IonCompartment *ion)
 {
     OffThreadCompilationVector &compilations = ion->finishedOffThreadCompilations();
@@ -898,27 +898,27 @@ class AutoDestroyAllocator
         if (alloc)
             js_delete(alloc);
     }
 };
 
 bool
 TestCompiler(IonBuilder *builder, MIRGraph *graph, AutoDestroyAllocator &autoDestroy)
 {
-    JS_ASSERT(!builder->script->ion);
+    JS_ASSERT(!builder->script()->ion);
     JSContext *cx = GetIonContext()->cx;
 
-    IonSpewNewFunction(graph, builder->script);
+    IonSpewNewFunction(graph, builder->script());
 
     if (!builder->build())
         return false;
     builder->clearForBackEnd();
 
     if (js_IonOptions.parallelCompilation) {
-        builder->script->ion = ION_COMPILING_SCRIPT;
+        builder->script()->ion = ION_COMPILING_SCRIPT;
 
         if (!StartOffThreadIonCompile(cx, builder))
             return false;
 
         // The allocator and associated data will be destroyed after being
         // processed in the finishedOffThreadCompilations list.
         autoDestroy.cancel();
 
@@ -950,17 +950,17 @@ AttachFinishedCompilations(JSContext *cx
 
     // Incorporate any off thread compilations which have finished, failed or
     // have been cancelled, and destroy JM jitcode for any compilations which
     // succeeded, to allow entering the Ion code from the interpreter.
     while (!compilations.empty()) {
         IonBuilder *builder = compilations.popCopy();
 
         if (builder->lir) {
-            JSScript *script = builder->script;
+            JSScript *script = builder->script();
             IonContext ictx(cx, cx->compartment, &builder->temp());
 
             CodeGenerator codegen(builder, *builder->lir);
 
             types::AutoEnterCompilation enterCompiler(cx, types::AutoEnterCompilation::Ion);
             enterCompiler.initExisting(builder->recompileInfo);
 
             bool success;
--- a/js/src/ion/IonBuilder.cpp
+++ b/js/src/ion/IonBuilder.cpp
@@ -21,28 +21,28 @@
 #endif
 
 using namespace js;
 using namespace js::ion;
 
 IonBuilder::IonBuilder(JSContext *cx, TempAllocator *temp, MIRGraph *graph,
                        TypeOracle *oracle, CompileInfo *info, size_t inliningDepth, uint32 loopDepth)
   : MIRGenerator(cx->compartment, temp, graph, info),
-    script(info->script()),
     recompileInfo(cx->compartment->types.compiledInfo),
     lir(NULL),
     cx(cx),
     loopDepth_(loopDepth),
     callerResumePoint_(NULL),
     callerBuilder_(NULL),
     oracle(oracle),
     inliningDepth(inliningDepth),
-    failedBoundsCheck_(script->failedBoundsCheck),
+    failedBoundsCheck_(info->script()->failedBoundsCheck),
     lazyArguments_(NULL)
 {
+    script_.init(info->script());
     pc = info->startPC();
 }
 
 void
 IonBuilder::clearForBackEnd()
 {
     cx = NULL;
     oracle = NULL;
@@ -52,27 +52,27 @@ bool
 IonBuilder::abort(const char *message, ...)
 {
     // Don't call PCToLineNumber in release builds.
 #ifdef DEBUG
     va_list ap;
     va_start(ap, message);
     abortFmt(message, ap);
     va_end(ap);
-    IonSpew(IonSpew_Abort, "aborted @ %s:%d", script->filename, PCToLineNumber(script, pc));
+    IonSpew(IonSpew_Abort, "aborted @ %s:%d", script_->filename, PCToLineNumber(script_, pc));
 #endif
     return false;
 }
 
 void
 IonBuilder::spew(const char *message)
 {
     // Don't call PCToLineNumber in release builds.
 #ifdef DEBUG
-    IonSpew(IonSpew_MIR, "%s @ %s:%d", message, script->filename, PCToLineNumber(script, pc));
+    IonSpew(IonSpew_MIR, "%s @ %s:%d", message, script_->filename, PCToLineNumber(script_, pc));
 #endif
 }
 
 static inline int32
 GetJumpOffset(jsbytecode *pc)
 {
     JS_ASSERT(js_CodeSpec[JSOp(*pc)].type() == JOF_JUMP);
     return GET_JUMP_OFFSET(pc);
@@ -141,32 +141,32 @@ IonBuilder::CFGState::LookupSwitch(jsbyt
         (FixedList<MBasicBlock *> *)GetIonContext()->temp->allocate(sizeof(FixedList<MBasicBlock *>));
     state.lookupswitch.currentBlock = 0;
     return state;
 }
 
 JSFunction *
 IonBuilder::getSingleCallTarget(uint32 argc, jsbytecode *pc)
 {
-    types::StackTypeSet *calleeTypes = oracle->getCallTarget(script, argc, pc);
+    types::StackTypeSet *calleeTypes = oracle->getCallTarget(script(), argc, pc);
     if (!calleeTypes)
         return NULL;
 
     JSObject *obj = calleeTypes->getSingleton();
     if (!obj || !obj->isFunction())
         return NULL;
 
     return obj->toFunction();
 }
 
 uint32_t
 IonBuilder::getPolyCallTargets(uint32 argc, jsbytecode *pc,
                                AutoObjectVector &targets, uint32_t maxTargets)
 {
-    types::TypeSet *calleeTypes = oracle->getCallTarget(script, argc, pc);
+    types::TypeSet *calleeTypes = oracle->getCallTarget(script_, argc, pc);
     if (!calleeTypes)
         return 0;
 
     if (calleeTypes->baseFlags() != 0)
         return 0;
 
     unsigned objCount = calleeTypes->getObjectCount();
 
@@ -186,42 +186,42 @@ IonBuilder::getPolyCallTargets(uint32 ar
 bool
 IonBuilder::canInlineTarget(JSFunction *target)
 {
     if (!target->isInterpreted()) {
         IonSpew(IonSpew_Inlining, "Cannot inline due to non-interpreted");
         return false;
     }
 
-    if (target->getParent() != &script->global()) {
+    if (target->getParent() != &script_->global()) {
         IonSpew(IonSpew_Inlining, "Cannot inline due to scope mismatch");
         return false;
     }
 
     JSScript *inlineScript = target->script();
 
     if (!inlineScript->canIonCompile()) {
         IonSpew(IonSpew_Inlining, "Cannot inline due to disable Ion compilation");
         return false;
     }
 
     // Allow inlining of recursive calls, but only one level deep.
     IonBuilder *builder = callerBuilder_;
     while (builder) {
-        if (builder->script == inlineScript) {
+        if (builder->script() == inlineScript) {
             IonSpew(IonSpew_Inlining, "Not inlining recursive call");
             return false;
         }
         builder = builder->callerBuilder_;
     }
 
     bool canInline = oracle->canEnterInlinedFunction(target);
 
     if (!canInline) {
-        IonSpew(IonSpew_Inlining, "Cannot inline due to oracle veto %d", script->lineno);
+        IonSpew(IonSpew_Inlining, "Cannot inline due to oracle veto %d", script_->lineno);
         return false;
     }
 
     IonSpew(IonSpew_Inlining, "Inlining good to go!");
     return true;
 }
 
 void
@@ -260,20 +260,20 @@ IonBuilder::pushLoop(CFGState::State ini
 bool
 IonBuilder::build()
 {
     current = newBlock(pc);
     if (!current)
         return false;
 
     IonSpew(IonSpew_Scripts, "Analyzing script %s:%d (%p) (usecount=%d) (maxloopcount=%d)",
-            script->filename, script->lineno, (void *)script, (int)script->getUseCount(),
-            (int)script->getMaxLoopCount());
-
-    if (!graph().addScript(script))
+            script_->filename, script_->lineno, (void *)script_, (int)script_->getUseCount(),
+            (int)script_->getMaxLoopCount());
+
+    if (!graph().addScript(script_))
         return false;
 
     if (!initParameters())
         return false;
 
     // Initialize local variables.
     for (uint32 i = 0; i < info().nlocals(); i++) {
         MConstant *undef = MConstant::New(UndefinedValue());
@@ -289,17 +289,17 @@ IonBuilder::build()
         MInstruction *scope = MConstant::New(UndefinedValue());
         current->add(scope);
         current->initSlot(info().scopeChainSlot(), scope);
     }
 
     // Emit the start instruction, so we can begin real instructions.
     current->makeStart(MStart::New(MStart::StartType_Default));
     if (instrumentedProfiling())
-        current->add(MFunctionBoundary::New(script, MFunctionBoundary::Enter));
+        current->add(MFunctionBoundary::New(script_, MFunctionBoundary::Enter));
 
     // Parameters have been checked to correspond to the typeset, now we unbox
     // what we can in an infallible manner.
     rewriteParameters();
 
     // It's safe to start emitting actual IR, so now build the scope chain.
     if (!initScopeChain())
         return false;
@@ -332,17 +332,17 @@ IonBuilder::build()
         MInstruction *ins = current->getEntrySlot(i)->toInstruction();
         if (ins->type() == MIRType_Value)
             ins->setResumePoint(current->entryResumePoint());
     }
 
     // Recompile to inline calls if this function is hot.
     insertRecompileCheck();
 
-    if (script->argumentsHasVarBinding()) {
+    if (script_->argumentsHasVarBinding()) {
         lazyArguments_ = MConstant::New(MagicValue(JS_OPTIMIZED_ARGUMENTS));
         current->add(lazyArguments_);
     }
 
     if (!traverseBytecode())
         return false;
 
     if (!processIterators())
@@ -386,19 +386,19 @@ IonBuilder::processIterators()
     return true;
 }
 
 bool
 IonBuilder::buildInline(IonBuilder *callerBuilder, MResumePoint *callerResumePoint,
                         MDefinition *thisDefn, MDefinitionVector &argv)
 {
     IonSpew(IonSpew_Scripts, "Inlining script %s:%d (%p)",
-            script->filename, script->lineno, (void *)script);
-
-    if (!graph().addScript(script))
+            script_->filename, script_->lineno, (void *)script_);
+
+    if (!graph().addScript(script_))
         return false;
 
     callerBuilder_ = callerBuilder;
     callerResumePoint_ = callerResumePoint;
 
     if (callerBuilder->failedBoundsCheck_)
         failedBoundsCheck_ = true;
 
@@ -413,17 +413,17 @@ IonBuilder::buildInline(IonBuilder *call
     MBasicBlock *predecessor = callerBuilder->current;
     JS_ASSERT(predecessor == callerResumePoint->block());
 
     // All further instructions generated in from this scope should be
     // considered as part of the function that we're inlining. We also need to
     // keep track of the inlining depth because all scripts inlined on the same
     // level contiguously have only one Inline_Exit node.
     if (instrumentedProfiling())
-        predecessor->add(MFunctionBoundary::New(script,
+        predecessor->add(MFunctionBoundary::New(script_,
                                                 MFunctionBoundary::Inline_Enter,
                                                 inliningDepth));
 
     predecessor->end(MGoto::New(current));
     if (!current->addPredecessorWithoutPhis(predecessor))
         return false;
 
     // Explicitly pass Undefined for missing arguments.
@@ -437,17 +437,17 @@ IonBuilder::buildInline(IonBuilder *call
             MConstant *undef = MConstant::New(UndefinedValue());
             current->add(undef);
             if (!argv.append(undef))
                 return false;
         }
     }
 
     // The Oracle ensures that the inlined script does not use the scope chain.
-    JS_ASSERT(!script->analysis()->usesScopeChain());
+    JS_ASSERT(!script_->analysis()->usesScopeChain());
     MInstruction *scope = MConstant::New(UndefinedValue());
     current->add(scope);
     current->initSlot(info().scopeChainSlot(), scope);
 
     current->initSlot(info().thisSlot(), thisDefn);
 
     IonSpew(IonSpew_Inlining, "Initializing %u arg slots", nargs);
 
@@ -528,44 +528,44 @@ IonBuilder::rewriteParameters()
 
 bool
 IonBuilder::initParameters()
 {
     if (!info().fun())
         return true;
 
     MParameter *param = MParameter::New(MParameter::THIS_SLOT,
-                                        oracle->thisTypeSet(script));
+                                        oracle->thisTypeSet(script_));
     current->add(param);
     current->initSlot(info().thisSlot(), param);
 
     for (uint32 i = 0; i < info().nargs(); i++) {
-        param = MParameter::New(i, oracle->parameterTypeSet(script, i));
+        param = MParameter::New(i, oracle->parameterTypeSet(script_, i));
         current->add(param);
         current->initSlot(info().argSlot(i), param);
     }
 
     return true;
 }
 
 bool
 IonBuilder::initScopeChain()
 {
     MInstruction *scope = NULL;
 
     // If the script doesn't use the scopechain, then it's already initialized
     // from earlier.
-    if (!script->analysis()->usesScopeChain())
+    if (!script_->analysis()->usesScopeChain())
         return true;
 
     // The scope chain is only tracked in scripts that have NAME opcodes which
     // will try to access the scope. For other scripts, the scope instructions
     // will be held live by resume points and code will still be generated for
     // them, so just use a constant undefined value.
-    if (!script->compileAndGo)
+    if (!script_->compileAndGo)
         return abort("non-CNG global scripts are not supported");
 
     if (JSFunction *fun = info().fun()) {
         MCallee *callee = MCallee::New();
         current->add(callee);
 
         scope = MFunctionEnvironment::New(callee);
         current->add(scope);
@@ -575,17 +575,17 @@ IonBuilder::initScopeChain()
             if (fun->isNamedLambda())
                 return abort("DeclEnv scope objects are not yet supported");
 
             scope = createCallObject(callee, scope);
             if (!scope)
                 return false;
         }
     } else {
-        scope = MConstant::New(ObjectValue(script->global()));
+        scope = MConstant::New(ObjectValue(script_->global()));
         current->add(scope);
     }
 
     current->setScopeChain(scope);
     return true;
 }
 
 // We try to build a control-flow graph in the order that it would be built as
@@ -738,17 +738,17 @@ IonBuilder::snoopControlFlow(JSOp op)
         break;
     }
     return ControlStatus_None;
 }
 
 void
 IonBuilder::markPhiBytecodeUses(jsbytecode *pc)
 {
-    unsigned nuses = analyze::GetUseCount(script, pc - script->code);
+    unsigned nuses = analyze::GetUseCount(script_, pc - script_->code);
     for (unsigned i = 0; i < nuses; i++) {
         MDefinition *def = current->peek(-(i + 1));
         if (def->isPassArg())
             def = def->toPassArg()->getArgument();
         if (def->isPhi())
             def->toPhi()->setHasBytecodeUses();
     }
 }
@@ -942,17 +942,17 @@ IonBuilder::inspectOpcode(JSOp op)
       case JSOP_GETGNAME:
       case JSOP_CALLGNAME:
       {
         RootedPropertyName name(cx, info().getAtom(pc)->asPropertyName());
         return jsop_getgname(name);
       }
 
       case JSOP_BINDGNAME:
-        return pushConstant(ObjectValue(script->global()));
+        return pushConstant(ObjectValue(script_->global()));
 
       case JSOP_SETGNAME:
       {
         RootedPropertyName name(cx, info().getAtom(pc)->asPropertyName());
         return jsop_setgname(name);
       }
 
       case JSOP_NAME:
@@ -2285,17 +2285,17 @@ IonBuilder::lookupSwitch(JSOp op, jssrcn
     bool defaultShared = false;
 
     MBasicBlock *prevCond = NULL;
     MCompare *prevCmpIns = NULL;
     MBasicBlock *prevBody = NULL;
     bool prevShared = false;
     jsbytecode *prevpc = NULL;
     for (unsigned int i = 0; i < ncases; i++) {
-        Value rval = script->getConst(GET_UINT32_INDEX(pc2));
+        Value rval = script_->getConst(GET_UINT32_INDEX(pc2));
         pc2 += UINT32_INDEX_LEN;
         jsbytecode *casepc = pc + GET_JUMP_OFFSET(pc2);
         pc2 += JUMP_OFFSET_LEN;
         JS_ASSERT(casepc > pc && casepc <= exitpc);
         JS_ASSERT_IF(i > 0, prevpc <= casepc);
 
         // Create case block
         MBasicBlock *cond = newBlock(((i == 0) ? current : prevCond), casepc);
@@ -2565,17 +2565,17 @@ IonBuilder::processReturn(JSOp op)
 
       default:
         def = NULL;
         JS_NOT_REACHED("unknown return op");
         break;
     }
 
     if (instrumentedProfiling())
-        current->add(MFunctionBoundary::New(script, MFunctionBoundary::Exit));
+        current->add(MFunctionBoundary::New(script_, MFunctionBoundary::Exit));
     MReturn *ret = MReturn::New(def);
     current->end(ret);
 
     if (!graph().addExit(current))
         return ControlStatus_Error;
 
     // Make sure no one tries to use this block now.
     current = NULL;
@@ -2609,17 +2609,17 @@ IonBuilder::pushConstant(const Value &v)
 
 bool
 IonBuilder::jsop_bitnot()
 {
     MDefinition *input = current->pop();
     MBitNot *ins = MBitNot::New(input);
 
     current->add(ins);
-    ins->infer(oracle->unaryTypes(script, pc));
+    ins->infer(oracle->unaryTypes(script_, pc));
 
     current->push(ins);
     if (ins->isEffectful() && !resumeAfter(ins))
         return false;
     return true;
 }
 bool
 IonBuilder::jsop_bitop(JSOp op)
@@ -2655,29 +2655,29 @@ IonBuilder::jsop_bitop(JSOp op)
         break;
 
       default:
         JS_NOT_REACHED("unexpected bitop");
         return false;
     }
 
     current->add(ins);
-    ins->infer(oracle->binaryTypes(script, pc));
+    ins->infer(oracle->binaryTypes(script_, pc));
 
     current->push(ins);
     if (ins->isEffectful() && !resumeAfter(ins))
         return false;
 
     return true;
 }
 
 bool
 IonBuilder::jsop_binary(JSOp op, MDefinition *left, MDefinition *right)
 {
-    TypeOracle::Binary b = oracle->binaryOp(script, pc);
+    TypeOracle::Binary b = oracle->binaryOp(script_, pc);
 
     if (op == JSOP_ADD && b.rval == MIRType_String &&
         (b.lhs == MIRType_String || b.lhs == MIRType_Int32) &&
         (b.rhs == MIRType_String || b.rhs == MIRType_Int32))
     {
         MConcat *ins = MConcat::New(left, right);
         current->add(ins);
         current->push(ins);
@@ -2706,17 +2706,17 @@ IonBuilder::jsop_binary(JSOp op, MDefini
         ins = MMod::New(left, right);
         break;
 
       default:
         JS_NOT_REACHED("unexpected binary opcode");
         return false;
     }
 
-    TypeOracle::BinaryTypes types = oracle->binaryTypes(script, pc);
+    TypeOracle::BinaryTypes types = oracle->binaryTypes(script_, pc);
     current->add(ins);
     ins->infer(cx, types);
     current->push(ins);
 
     if (ins->isEffectful())
         return resumeAfter(ins);
     return true;
 }
@@ -2728,17 +2728,17 @@ IonBuilder::jsop_binary(JSOp op)
     MDefinition *left = current->pop();
 
     return jsop_binary(op, left, right);
 }
 
 bool
 IonBuilder::jsop_pos()
 {
-    TypeOracle::Unary types = oracle->unaryOp(script, pc);
+    TypeOracle::Unary types = oracle->unaryOp(script_, pc);
     if (IsNumberType(types.ival)) {
         // Already int32 or double.
         JS_ASSERT(IsNumberType(types.rval));
         return true;
     }
 
     // Compile +x as x * 1.
     MDefinition *value = current->pop();
@@ -2913,22 +2913,22 @@ IonBuilder::makeInliningDecision(AutoObj
             return false;
 
         if (script->length > js_IonOptions.smallFunctionMaxBytecodeLength)
             allFunctionsAreSmall = false;
     }
     if (allFunctionsAreSmall)
         checkUses = js_IonOptions.smallFunctionUsesBeforeInlining;
 
-    if (script->getUseCount() < checkUses) {
+    if (script_->getUseCount() < checkUses) {
         IonSpew(IonSpew_Inlining, "Not inlining, caller is not hot");
         return false;
     }
 
-    if (!oracle->canInlineCall(script, pc)) {
+    if (!oracle->canInlineCall(script_, pc)) {
         IonSpew(IonSpew_Inlining, "Cannot inline due to uninlineable call site");
         return false;
     }
 
     for (size_t i = 0; i < targets.length(); i++) {
         if (!canInlineTarget(targets[i]->toFunction())) {
             IonSpew(IonSpew_Inlining, "Decided not to inline");
             return false;
@@ -3418,17 +3418,17 @@ IonBuilder::inlineScriptedCall(AutoObjec
 }
 
 MInstruction *
 IonBuilder::createCallObject(MDefinition *callee, MDefinition *scope)
 {
     // Create a template CallObject that we'll use to generate inline object
     // creation.
 
-    RootedObject templateObj(cx, CallObject::createTemplateObject(cx, script));
+    RootedObject templateObj(cx, CallObject::createTemplateObject(cx, script_));
     if (!templateObj)
         return NULL;
 
     // If the CallObject needs dynamic slots, allocate those now.
     MInstruction *slots;
     if (templateObj->hasDynamicSlots()) {
         size_t nslots = JSObject::dynamicSlotsCount(templateObj->numFixedSlots(),
                                                     templateObj->slotSpan());
@@ -3444,17 +3444,17 @@ IonBuilder::createCallObject(MDefinition
     MInstruction *callObj = MNewCallObject::New(templateObj, slots);
     current->add(callObj);
 
     // Initialize the object's reserved slots.
     current->add(MStoreFixedSlot::New(callObj, CallObject::calleeSlot(), callee));
     current->add(MStoreFixedSlot::New(callObj, CallObject::enclosingScopeSlot(), scope));
 
     // Initialize argument slots.
-    for (AliasedFormalIter i(script); i; i++) {
+    for (AliasedFormalIter i(script_); i; i++) {
         unsigned slot = i.scopeSlot();
         unsigned formal = i.frameIndex();
         MDefinition *param = current->getSlot(info().argSlot(formal));
         if (slot >= templateObj->numFixedSlots())
             current->add(MStoreSlot::New(slots, slot - templateObj->numFixedSlots(), param));
         else
             current->add(MStoreFixedSlot::New(callObj, slot, param));
     }
@@ -3568,17 +3568,17 @@ IonBuilder::jsop_funcall(uint32 argc)
     // argc+2: The native 'call' function.
 
     // If |Function.prototype.call| may be overridden, don't optimize callsite.
     RootedFunction native(cx, getSingleCallTarget(argc, pc));
     if (!native || !native->isNative() || native->native() != &js_fun_call)
         return makeCall(native, argc, false);
 
     // Extract call target.
-    types::StackTypeSet *funTypes = oracle->getCallArg(script, argc, 0, pc);
+    types::StackTypeSet *funTypes = oracle->getCallArg(script_, argc, 0, pc);
     RootedObject funobj(cx, (funTypes) ? funTypes->getSingleton() : NULL);
     RootedFunction target(cx, (funobj && funobj->isFunction()) ? funobj->toFunction() : NULL);
 
     // Unwrap the (JSFunction *) parameter.
     int funcDepth = -((int)argc + 1);
     MPassArg *passFunc = current->peek(funcDepth)->toPassArg();
     current->rewriteAtDepth(funcDepth, passFunc->getArgument());
 
@@ -3610,17 +3610,17 @@ bool
 IonBuilder::jsop_funapply(uint32 argc)
 {
     RootedFunction native(cx, getSingleCallTarget(argc, pc));
     if (argc != 2)
         return makeCall(native, argc, false);
 
     // Disable compilation if the second argument to |apply| cannot be guaranteed
     // to be either definitely |arguments| or definitely not |arguments|.
-    types::StackTypeSet *argObjTypes = oracle->getCallArg(script, argc, 2, pc);
+    types::StackTypeSet *argObjTypes = oracle->getCallArg(script_, argc, 2, pc);
     LazyArgumentsType isArgObj = oracle->isArgumentObject(argObjTypes);
     if (isArgObj == MaybeArguments)
         return abort("fun.apply with MaybeArguments");
 
     // Fallback to regular call if arg 2 is not definitely |arguments|.
     if (isArgObj != DefinitelyArguments)
         return makeCall(native, argc, false);
 
@@ -3633,17 +3633,17 @@ IonBuilder::jsop_funapply(uint32 argc)
 
     // Stack for JSOP_FUNAPPLY:
     // 1:      MPassArg(Vp)
     // 2:      MPassArg(This)
     // argc+1: MPassArg(JSFunction *), the 'f' in |f.call()|, in |this| position.
     // argc+2: The native 'apply' function.
 
     // Extract call target.
-    types::StackTypeSet *funTypes = oracle->getCallArg(script, argc, 0, pc);
+    types::StackTypeSet *funTypes = oracle->getCallArg(script_, argc, 0, pc);
     RootedObject funobj(cx, (funTypes) ? funTypes->getSingleton() : NULL);
     RootedFunction target(cx, (funobj && funobj->isFunction()) ? funobj->toFunction() : NULL);
 
     // Vp
     MPassArg *passVp = current->pop()->toPassArg();
     passVp->replaceAllUsesWith(passVp->getArgument());
     passVp->block()->discard(passVp);
 
@@ -3667,17 +3667,17 @@ IonBuilder::jsop_funapply(uint32 argc)
 
     MApplyArgs *apply = MApplyArgs::New(target, argFunc, numArgs, argThis);
     current->add(apply);
     current->push(apply);
     if (!resumeAfter(apply))
         return false;
 
     types::StackTypeSet *barrier;
-    types::StackTypeSet *types = oracle->returnTypeSet(script, pc, &barrier);
+    types::StackTypeSet *types = oracle->returnTypeSet(script_, pc, &barrier);
     return pushTypeBarrier(apply, types, barrier);
 }
 
 // Get the builtin RegExp.prototype.test function.
 static bool
 GetBuiltinRegExpTest(JSContext *cx, JSScript *script, JSFunction **result)
 {
     JS_ASSERT(*result == NULL);
@@ -3713,17 +3713,17 @@ GetBuiltinRegExpTest(JSContext *cx, JSSc
 
 bool
 IonBuilder::jsop_call(uint32 argc, bool constructing)
 {
     // Acquire known call target if existent.
     AutoObjectVector targets(cx);
     uint32_t numTargets = getPolyCallTargets(argc, pc, targets, 4);
     types::StackTypeSet *barrier;
-    types::StackTypeSet *types = oracle->returnTypeSet(script, pc, &barrier);
+    types::StackTypeSet *types = oracle->returnTypeSet(script_, pc, &barrier);
 
     // Attempt to inline native and scripted functions.
     if (inliningEnabled()) {
         // Inline a single native call if possible.
         if (numTargets == 1 && targets[0]->toFunction()->isNative()) {
             RootedFunction target(cx, targets[0]->toFunction());
             switch (inlineNativeCall(target->native(), argc, constructing)) {
               case InliningStatus_Inlined:
@@ -3742,17 +3742,17 @@ IonBuilder::jsop_call(uint32 argc, bool 
     RootedFunction target(cx, NULL);
     if (numTargets == 1) {
         target = targets[0]->toFunction();
 
         // Call RegExp.test instead of RegExp.exec if the result will not be used
         // or will only be used to test for existence.
         if (target->maybeNative() == regexp_exec && !CallResultEscapes(pc)) {
             JSFunction *newTarget = NULL;
-            if (!GetBuiltinRegExpTest(cx, script, &newTarget))
+            if (!GetBuiltinRegExpTest(cx, script_, &newTarget))
                 return false;
             if (newTarget)
                 target = newTarget;
         }
     }
 
     return makeCallBarrier(target, argc, constructing, types, barrier);
 }
@@ -3843,26 +3843,26 @@ IonBuilder::makeCallBarrier(HandleFuncti
 
     return pushTypeBarrier(call, types, barrier);
 }
 
 bool
 IonBuilder::makeCall(HandleFunction target, uint32 argc, bool constructing)
 {
     types::StackTypeSet *barrier;
-    types::StackTypeSet *types = oracle->returnTypeSet(script, pc, &barrier);
+    types::StackTypeSet *types = oracle->returnTypeSet(script_, pc, &barrier);
     return makeCallBarrier(target, argc, constructing, types, barrier);
 }
 
 bool
 IonBuilder::jsop_incslot(JSOp op, uint32 slot)
 {
     int32 amt = (js_CodeSpec[op].format & JOF_INC) ? 1 : -1;
     bool post = !!(js_CodeSpec[op].format & JOF_POST);
-    TypeOracle::BinaryTypes types = oracle->incslot(script, pc);
+    TypeOracle::BinaryTypes types = oracle->incslot(script_, pc);
 
     // Grab the value at the local slot, and convert it to a number. Currently,
     // we use ToInt32 or ToNumber which are fallible but idempotent. This whole
     // operation must be idempotent because we cannot resume in the middle of
     // an INC op.
     current->pushSlot(slot);
     MDefinition *value = current->pop();
     MInstruction *lhs;
@@ -3913,47 +3913,48 @@ IonBuilder::jsop_compare(JSOp op)
 {
     MDefinition *right = current->pop();
     MDefinition *left = current->pop();
 
     MCompare *ins = MCompare::New(left, right, op);
     current->add(ins);
     current->push(ins);
 
-    ins->infer(cx, oracle->binaryTypes(script, pc));
+    ins->infer(cx, oracle->binaryTypes(script_, pc));
 
     if (ins->isEffectful() && !resumeAfter(ins))
         return false;
     return true;
 }
 
 JSObject *
 IonBuilder::getNewArrayTemplateObject(uint32 count)
 {
     RootedObject templateObject(cx, NewDenseUnallocatedArray(cx, count));
     if (!templateObject)
         return NULL;
 
+    RootedScript script(cx, script_);
     if (types::UseNewTypeForInitializer(cx, script, pc, JSProto_Array)) {
         if (!JSObject::setSingletonType(cx, templateObject))
             return NULL;
     } else {
         types::TypeObject *type = types::TypeScript::InitObject(cx, script, pc, JSProto_Array);
         if (!type)
             return NULL;
         templateObject->setType(type);
     }
 
     return templateObject;
 }
 
 bool
 IonBuilder::jsop_newarray(uint32 count)
 {
-    JS_ASSERT(script->compileAndGo);
+    JS_ASSERT(script_->compileAndGo);
 
     JSObject *templateObject = getNewArrayTemplateObject(count);
     if (!templateObject)
         return false;
 
     MNewArray *ins = new MNewArray(count, templateObject, MNewArray::NewArray_Allocating);
 
     current->add(ins);
@@ -3961,30 +3962,31 @@ IonBuilder::jsop_newarray(uint32 count)
 
     return true;
 }
 
 bool
 IonBuilder::jsop_newobject(HandleObject baseObj)
 {
     // Don't bake in the TypeObject for non-CNG scripts.
-    JS_ASSERT(script->compileAndGo);
+    JS_ASSERT(script_->compileAndGo);
 
     RootedObject templateObject(cx);
 
     if (baseObj) {
         templateObject = CopyInitializerObject(cx, baseObj);
     } else {
         gc::AllocKind kind = GuessObjectGCKind(0);
         templateObject = NewBuiltinClassInstance(cx, &ObjectClass, kind);
     }
 
     if (!templateObject)
         return false;
 
+    RootedScript script(cx, script_);
     if (types::UseNewTypeForInitializer(cx, script, pc, JSProto_Object)) {
         if (!JSObject::setSingletonType(cx, templateObject))
             return false;
     } else {
         types::TypeObject *type = types::TypeScript::InitObject(cx, script, pc, JSProto_Object);
         if (!type)
             return false;
         templateObject->setType(type);
@@ -3996,18 +3998,18 @@ IonBuilder::jsop_newobject(HandleObject 
     current->push(ins);
 
     return resumeAfter(ins);
 }
 
 bool
 IonBuilder::jsop_initelem()
 {
-    if (oracle->propertyWriteCanSpecialize(script, pc)) {
-        if (oracle->elementWriteIsDenseArray(script, pc))
+    if (oracle->propertyWriteCanSpecialize(script_, pc)) {
+        if (oracle->elementWriteIsDenseArray(script_, pc))
             return jsop_initelem_dense();
     }
 
     return abort("NYI: JSOP_INITELEM supports for non dense objects/arrays.");
 }
 
 bool
 IonBuilder::jsop_initelem_dense()
@@ -4050,17 +4052,17 @@ CanEffectlesslyCallLookupGenericOnObject
 bool
 IonBuilder::jsop_initprop(HandlePropertyName name)
 {
     MDefinition *value = current->pop();
     MDefinition *obj = current->peek(-1);
 
     RootedObject templateObject(cx, obj->toNewObject()->templateObject());
 
-    if (!oracle->propertyWriteCanSpecialize(script, pc)) {
+    if (!oracle->propertyWriteCanSpecialize(script_, pc)) {
         // This should only happen for a few names like __proto__.
         return abort("INITPROP Monitored initprop");
     }
 
     if (!CanEffectlesslyCallLookupGenericOnObject(templateObject))
         return abort("INITPROP template object is special");
 
     RootedObject holder(cx);
@@ -4074,17 +4076,17 @@ IonBuilder::jsop_initprop(HandleProperty
     if (!shape || holder != templateObject) {
         // JSOP_NEWINIT becomes an MNewObject without preconfigured properties.
         MInitProp *init = MInitProp::New(obj, name, value);
         current->add(init);
         return resumeAfter(init);
     }
 
     bool needsBarrier = true;
-    TypeOracle::BinaryTypes b = oracle->binaryTypes(script, pc);
+    TypeOracle::BinaryTypes b = oracle->binaryTypes(script_, pc);
     if (b.lhsTypes &&
         ((jsid)id == types::MakeTypeId(cx, id)) &&
         !b.lhsTypes->propertyNeedsBarrier(cx, id))
     {
         needsBarrier = false;
     }
 
     if (templateObject->isFixedSlot(shape->slot())) {
@@ -4368,25 +4370,25 @@ IonBuilder::insertRecompileCheck()
 {
     if (!inliningEnabled())
         return;
 
     if (inliningDepth > 0)
         return;
 
     // Don't recompile if we are already inlining.
-    if (script->getUseCount() >= js_IonOptions.usesBeforeInlining)
+    if (script_->getUseCount() >= js_IonOptions.usesBeforeInlining)
         return;
 
     // Don't recompile if the oracle cannot provide inlining information
     // or if the script has no calls.
     if (!oracle->canInlineCalls())
         return;
 
-    uint32_t minUses = UsesBeforeIonRecompile(script, pc);
+    uint32_t minUses = UsesBeforeIonRecompile(script_, pc);
     MRecompileCheck *check = MRecompileCheck::New(minUses);
     current->add(check);
 }
 
 static inline bool
 TestSingletonProperty(JSContext *cx, HandleObject obj, HandleId id, bool *isKnownConstant)
 {
     // We would like to completely no-op property/global accesses which can
@@ -4627,39 +4629,39 @@ IonBuilder::jsop_getgname(HandleProperty
     // Optimize undefined, NaN, and Infinity.
     if (name == cx->names().undefined)
         return pushConstant(UndefinedValue());
     if (name == cx->names().NaN)
         return pushConstant(cx->runtime->NaNValue);
     if (name == cx->names().Infinity)
         return pushConstant(cx->runtime->positiveInfinityValue);
 
-    RootedObject globalObj(cx, &script->global());
+    RootedObject globalObj(cx, &script_->global());
     JS_ASSERT(globalObj->isNative());
 
     RootedId id(cx, NameToId(name));
 
     // For the fastest path, the property must be found, and it must be found
     // as a normal data property on exactly the global object.
     const js::Shape *shape = globalObj->nativeLookup(cx, id);
     if (!shape || !shape->hasDefaultGetter() || !shape->hasSlot())
         return jsop_getname(name);
 
-    types::HeapTypeSet *propertyTypes = oracle->globalPropertyTypeSet(script, pc, id);
+    types::HeapTypeSet *propertyTypes = oracle->globalPropertyTypeSet(script_, pc, id);
     if (propertyTypes && propertyTypes->isOwnProperty(cx, globalObj->getType(cx), true)) {
         // The property has been reconfigured as non-configurable, non-enumerable
         // or non-writable.
         return jsop_getname(name);
     }
 
     // If the property is permanent, a shape guard isn't necessary.
     JSValueType knownType = JSVAL_TYPE_UNKNOWN;
 
-    types::StackTypeSet *barrier = oracle->propertyReadBarrier(script, pc);
-    types::StackTypeSet *types = oracle->propertyRead(script, pc);
+    types::StackTypeSet *barrier = oracle->propertyReadBarrier(script_, pc);
+    types::StackTypeSet *types = oracle->propertyRead(script_, pc);
     if (types) {
         JSObject *singleton = types->getSingleton();
 
         knownType = types->getKnownTypeTag();
         if (!barrier) {
             if (singleton) {
                 // Try to inline a known constant value.
                 bool isKnownConstant;
@@ -4698,23 +4700,23 @@ IonBuilder::jsop_getgname(HandleProperty
 
     current->push(load);
     return pushTypeBarrier(load, types, barrier);
 }
 
 bool
 IonBuilder::jsop_setgname(HandlePropertyName name)
 {
-    RootedObject globalObj(cx, &script->global());
+    RootedObject globalObj(cx, &script_->global());
     RootedId id(cx, NameToId(name));
 
     JS_ASSERT(globalObj->isNative());
 
     bool canSpecialize;
-    types::HeapTypeSet *propertyTypes = oracle->globalPropertyWrite(script, pc, id, &canSpecialize);
+    types::HeapTypeSet *propertyTypes = oracle->globalPropertyWrite(script_, pc, id, &canSpecialize);
 
     // This should only happen for a few names like __proto__.
     if (!canSpecialize || globalObj->watched())
         return jsop_setprop(name);
 
     // For the fastest path, the property must be found, and it must be found
     // as a normal data property on exactly the global object.
     const js::Shape *shape = globalObj->nativeLookup(cx, id);
@@ -4771,17 +4773,17 @@ IonBuilder::jsop_setgname(HandleProperty
     return resumeAfter(store);
 }
 
 bool
 IonBuilder::jsop_getname(HandlePropertyName name)
 {
     MDefinition *object;
     if (js_CodeSpec[*pc].format & JOF_GNAME) {
-        MInstruction *global = MConstant::New(ObjectValue(script->global()));
+        MInstruction *global = MConstant::New(ObjectValue(script_->global()));
         current->add(global);
         object = global;
     } else {
         current->push(current->scopeChain());
         object = current->pop();
     }
 
     MGetNameCache *ins;
@@ -4791,51 +4793,51 @@ IonBuilder::jsop_getname(HandlePropertyN
         ins = MGetNameCache::New(object, name, MGetNameCache::NAME);
 
     current->add(ins);
     current->push(ins);
 
     if (!resumeAfter(ins))
         return false;
 
-    types::StackTypeSet *barrier = oracle->propertyReadBarrier(script, pc);
-    types::StackTypeSet *types = oracle->propertyRead(script, pc);
+    types::StackTypeSet *barrier = oracle->propertyReadBarrier(script_, pc);
+    types::StackTypeSet *types = oracle->propertyRead(script_, pc);
 
     monitorResult(ins, types);
     return pushTypeBarrier(ins, types, barrier);
 }
 
 bool
 IonBuilder::jsop_bindname(PropertyName *name)
 {
-    JS_ASSERT(script->analysis()->usesScopeChain());
+    JS_ASSERT(script_->analysis()->usesScopeChain());
 
     MDefinition *scopeChain = current->scopeChain();
-    MBindNameCache *ins = MBindNameCache::New(scopeChain, name, script, pc);
+    MBindNameCache *ins = MBindNameCache::New(scopeChain, name, script_, pc);
 
     current->add(ins);
     current->push(ins);
 
     return resumeAfter(ins);
 }
 
 bool
 IonBuilder::jsop_getelem()
 {
-    if (oracle->elementReadIsDenseArray(script, pc))
+    if (oracle->elementReadIsDenseArray(script_, pc))
         return jsop_getelem_dense();
 
     int arrayType = TypedArray::TYPE_MAX;
-    if (oracle->elementReadIsTypedArray(script, pc, &arrayType))
+    if (oracle->elementReadIsTypedArray(script_, pc, &arrayType))
         return jsop_getelem_typed(arrayType);
 
-    if (oracle->elementReadIsString(script, pc))
+    if (oracle->elementReadIsString(script_, pc))
         return jsop_getelem_string();
 
-    LazyArgumentsType isArguments = oracle->elementReadMagicArguments(script, pc);
+    LazyArgumentsType isArguments = oracle->elementReadMagicArguments(script_, pc);
     if (isArguments == MaybeArguments)
         return abort("Type is not definitely lazy arguments.");
     if (isArguments == DefinitelyArguments)
         return jsop_arguments_getelem();
 
     MDefinition *rhs = current->pop();
     MDefinition *lhs = current->pop();
 
@@ -4843,46 +4845,46 @@ IonBuilder::jsop_getelem()
 
     // TI does not account for GETELEM with string indexes, so we have to monitor
     // the result of MGetElementCache if it's expected to access string properties.
     // If the result of MGetElementCache is not monitored, we won't generate any
     // getprop stubs.
     bool mustMonitorResult = false;
     bool cacheable = false;
 
-    oracle->elementReadGeneric(script, pc, &cacheable, &mustMonitorResult);
+    oracle->elementReadGeneric(script_, pc, &cacheable, &mustMonitorResult);
 
     if (cacheable)
         ins = MGetElementCache::New(lhs, rhs, mustMonitorResult);
     else
         ins = MCallGetElement::New(lhs, rhs);
 
     current->add(ins);
     current->push(ins);
 
     if (!resumeAfter(ins))
         return false;
 
-    types::StackTypeSet *barrier = oracle->propertyReadBarrier(script, pc);
-    types::StackTypeSet *types = oracle->propertyRead(script, pc);
+    types::StackTypeSet *barrier = oracle->propertyReadBarrier(script_, pc);
+    types::StackTypeSet *types = oracle->propertyRead(script_, pc);
 
     if (mustMonitorResult)
         monitorResult(ins, types);
     return pushTypeBarrier(ins, types, barrier);
 }
 
 bool
 IonBuilder::jsop_getelem_dense()
 {
     if (oracle->arrayPrototypeHasIndexedProperty())
         return abort("GETELEM Array proto has indexed properties");
 
-    types::StackTypeSet *barrier = oracle->propertyReadBarrier(script, pc);
-    types::StackTypeSet *types = oracle->propertyRead(script, pc);
-    bool needsHoleCheck = !oracle->elementReadIsPacked(script, pc);
+    types::StackTypeSet *barrier = oracle->propertyReadBarrier(script_, pc);
+    types::StackTypeSet *types = oracle->propertyRead(script_, pc);
+    bool needsHoleCheck = !oracle->elementReadIsPacked(script_, pc);
     bool maybeUndefined = types->hasType(types::Type::UndefinedType());
 
     MDefinition *id = current->pop();
     MDefinition *obj = current->pop();
 
     JSValueType knownType = JSVAL_TYPE_UNKNOWN;
     if (!needsHoleCheck && !barrier) {
         knownType = types->getKnownTypeTag();
@@ -4959,18 +4961,18 @@ GetTypedArrayElements(MDefinition *obj)
         return MConstantElements::New(data);
     }
     return MTypedArrayElements::New(obj);
 }
 
 bool
 IonBuilder::jsop_getelem_typed(int arrayType)
 {
-    types::StackTypeSet *barrier = oracle->propertyReadBarrier(script, pc);
-    types::StackTypeSet *types = oracle->propertyRead(script, pc);
+    types::StackTypeSet *barrier = oracle->propertyReadBarrier(script_, pc);
+    types::StackTypeSet *types = oracle->propertyRead(script_, pc);
 
     MDefinition *id = current->pop();
     MDefinition *obj = current->pop();
 
     bool maybeUndefined = types->hasType(types::Type::UndefinedType());
 
     // Reading from an Uint32Array will result in a double for values
     // that don't fit in an int32. We have to bailout if this happens
@@ -5069,26 +5071,26 @@ IonBuilder::jsop_getelem_string()
     current->add(result);
     current->push(result);
     return true;
 }
 
 bool
 IonBuilder::jsop_setelem()
 {
-    if (oracle->propertyWriteCanSpecialize(script, pc)) {
-        if (oracle->elementWriteIsDenseArray(script, pc))
+    if (oracle->propertyWriteCanSpecialize(script_, pc)) {
+        if (oracle->elementWriteIsDenseArray(script_, pc))
             return jsop_setelem_dense();
 
         int arrayType = TypedArray::TYPE_MAX;
-        if (oracle->elementWriteIsTypedArray(script, pc, &arrayType))
+        if (oracle->elementWriteIsTypedArray(script_, pc, &arrayType))
             return jsop_setelem_typed(arrayType);
     }
 
-    LazyArgumentsType isArguments = oracle->elementWriteMagicArguments(script, pc);
+    LazyArgumentsType isArguments = oracle->elementWriteMagicArguments(script_, pc);
     if (isArguments == MaybeArguments)
         return abort("Type is not definitely lazy arguments.");
     if (isArguments == DefinitelyArguments)
         return jsop_arguments_setelem();
 
     MDefinition *value = current->pop();
     MDefinition *index = current->pop();
     MDefinition *object = current->pop();
@@ -5101,18 +5103,18 @@ IonBuilder::jsop_setelem()
 }
 
 bool
 IonBuilder::jsop_setelem_dense()
 {
     if (oracle->arrayPrototypeHasIndexedProperty())
         return abort("SETELEM Array proto has indexed properties");
 
-    MIRType elementType = oracle->elementWrite(script, pc);
-    bool packed = oracle->elementWriteIsPacked(script, pc);
+    MIRType elementType = oracle->elementWrite(script_, pc);
+    bool packed = oracle->elementWriteIsPacked(script_, pc);
 
     MDefinition *value = current->pop();
     MDefinition *id = current->pop();
     MDefinition *obj = current->pop();
 
     // Ensure id is an integer.
     MInstruction *idInt32 = MToInt32::New(id);
     current->add(idInt32);
@@ -5121,17 +5123,17 @@ IonBuilder::jsop_setelem_dense()
     // Get the elements vector.
     MElements *elements = MElements::New(obj);
     current->add(elements);
 
     // Use MStoreElementHole if this SETELEM has written to out-of-bounds
     // indexes in the past. Otherwise, use MStoreElement so that we can hoist
     // the initialized length and bounds check.
     MStoreElementCommon *store;
-    if (oracle->setElementHasWrittenHoles(script, pc)) {
+    if (oracle->setElementHasWrittenHoles(script_, pc)) {
         MStoreElementHole *ins = MStoreElementHole::New(obj, elements, id, value);
         store = ins;
 
         current->add(ins);
         current->push(value);
 
         if (!resumeAfter(ins))
             return false;
@@ -5147,17 +5149,17 @@ IonBuilder::jsop_setelem_dense()
         current->add(ins);
         current->push(value);
 
         if (!resumeAfter(ins))
             return false;
     }
 
     // Determine whether a write barrier is required.
-    if (oracle->elementWriteNeedsBarrier(script, pc))
+    if (oracle->elementWriteNeedsBarrier(script_, pc))
         store->setNeedsBarrier();
 
     if (elementType != MIRType_None && packed)
         store->setElementType(elementType);
 
     return true;
 }
 
@@ -5207,17 +5209,17 @@ IonBuilder::jsop_length()
 
     RootedPropertyName name(cx, info().getAtom(pc)->asPropertyName());
     return jsop_getprop(name);
 }
 
 bool
 IonBuilder::jsop_length_fastPath()
 {
-    TypeOracle::UnaryTypes sig = oracle->unaryTypes(script, pc);
+    TypeOracle::UnaryTypes sig = oracle->unaryTypes(script_, pc);
     if (!sig.inTypes || !sig.outTypes)
         return false;
 
     if (sig.outTypes->getKnownTypeTag() != JSVAL_TYPE_INT32)
         return false;
 
     switch (sig.inTypes->getKnownTypeTag()) {
       case JSVAL_TYPE_STRING: {
@@ -5277,18 +5279,18 @@ IonBuilder::jsop_arguments_length()
     current->add(ins);
     current->push(ins);
     return true;
 }
 
 bool
 IonBuilder::jsop_arguments_getelem()
 {
-    types::StackTypeSet *barrier = oracle->propertyReadBarrier(script, pc);
-    types::StackTypeSet *types = oracle->propertyRead(script, pc);
+    types::StackTypeSet *barrier = oracle->propertyReadBarrier(script_, pc);
+    types::StackTypeSet *types = oracle->propertyRead(script_, pc);
 
     MDefinition *idx = current->pop();
 
     // Type Inference has guaranteed this is an optimized arguments object.
     current->pop();
 
     // To ensure that we are not looking above the number of actual arguments.
     MArgumentsLength *length = MArgumentsLength::New();
@@ -5384,17 +5386,17 @@ IonBuilder::TestCommonPropFunc(JSContext
                 return true;
 
             // If the type has an own property, we can't be sure we don't shadow
             // the chain.
             jsid typeId = types::MakeTypeId(cx, id);
             types::HeapTypeSet *propSet = typeObj->getProperty(cx, typeId, false);
             if (!propSet)
                 return false;
-            if (propSet->isOwnProperty(cx, typeObj, false))
+            if (propSet->ownProperty(false))
                 return true;
 
             // Check the DOM status of the instance type
             thinkDOM = thinkDOM && !typeObj->hasAnyFlags(types::OBJECT_FLAG_NON_DOM);
 
             // Otherwise try using the prototype.
             curObj = typeObj->proto;
         } else {
@@ -5447,31 +5449,42 @@ IonBuilder::TestCommonPropFunc(JSContext
         // We only support cases with a single prototype shared. This is
         // overwhelmingly more likely than having multiple different prototype
         // chains with the same custom property function.
         if (!foundProto)
             foundProto = proto;
         else if (foundProto != proto)
             return true;
 
-        // Check here to make sure that everyone has Type Objects which known
+        // Check here to make sure that everyone has Type Objects with known
         // properties between them and the proto we found the accessor on. We
         // need those to add freezes safely. NOTE: We do not do this above, as
         // we may be able to freeze all the types up to where we found the
         // property, even if there are unknown types higher in the prototype
         // chain.
         while (curObj != foundProto) {
-            if (curObj->getType(cx)->unknownProperties())
+            types::TypeObject *typeObj = curObj->getType(cx);
+
+            if (typeObj->unknownProperties())
                 return true;
 
-            // If anyone on the chain is watched, TI thinks they have an own
-            // property, which means if they were to actually overwrite the
-            // property accessors, we would never know, since we are freezing on
-            // setting that flag.
-            if (curObj->watched())
+            // Check here to make sure that nobody on the prototype chain is
+            // marked as having the property as an "own property". This can
+            // happen in cases of |delete| having been used, or cases with
+            // watched objects. If TI ever decides to be more accurate about
+            // |delete| handling, this should go back to curObj->watched().
+
+            // Even though we are not directly accessing the properties on the whole
+            // prototype chain, we need to fault in the sets anyway, as we need
+            // to freeze on them.
+            jsid typeId = types::MakeTypeId(cx, id);
+            types::HeapTypeSet *propSet = typeObj->getProperty(cx, typeId, false);
+            if (!propSet)
+                return false;
+            if (propSet->ownProperty(false))
                 return true;
 
             curObj = curObj->getProto();
         }
     }
 
     // No need to add a freeze if we didn't find anything
     if (!found)
@@ -5513,16 +5526,18 @@ IonBuilder::TestCommonPropFunc(JSContext
         // If we found a Singleton object's own-property, there's nothing to
         // freeze.
         if (obj != foundProto) {
             // Walk the prototype chain. Everyone has to have the property, since we
             // just checked, so propSet cannot be NULL.
             jsid typeId = types::MakeTypeId(cx, id);
             while (true) {
                 types::HeapTypeSet *propSet = curType->getProperty(cx, typeId, false);
+                // This assert is now assured, since we have faulted them in
+                // above.
                 JS_ASSERT(propSet);
                 // Asking, freeze by asking.
                 DebugOnly<bool> isOwn = propSet->isOwnProperty(cx, curType, false);
                 JS_ASSERT(!isOwn);
                 // Don't mark the proto. It will be held down by the shape
                 // guard. This allows us tp use properties found on prototypes
                 // with properties unknown to TI.
                 if (curType->proto == foundProto)
@@ -5729,32 +5744,32 @@ IonBuilder::annotateGetPropertyCache(JSC
 
 // Returns true if an idempotent cache has ever invalidated this script
 // or an outer script.
 bool
 IonBuilder::invalidatedIdempotentCache()
 {
     IonBuilder *builder = this;
     do {
-        if (builder->script->invalidatedIdempotentCache)
+        if (builder->script()->invalidatedIdempotentCache)
             return true;
         builder = builder->callerBuilder_;
     } while (builder);
 
     return false;
 }
 
 bool
 IonBuilder::loadSlot(MDefinition *obj, Shape *shape, MIRType rvalType)
 {
     JS_ASSERT(shape->hasDefaultGetter());
     JS_ASSERT(shape->hasSlot());
 
-    types::StackTypeSet *barrier = oracle->propertyReadBarrier(script, pc);
-    types::StackTypeSet *types = oracle->propertyRead(script, pc);
+    types::StackTypeSet *barrier = oracle->propertyReadBarrier(script_, pc);
+    types::StackTypeSet *types = oracle->propertyRead(script_, pc);
 
     if (shape->slot() < shape->numFixedSlots()) {
         MLoadFixedSlot *load = MLoadFixedSlot::New(obj, shape->slot());
         current->add(load);
         current->push(load);
 
         load->setResultType(rvalType);
         return pushTypeBarrier(load, types, barrier);
@@ -5796,40 +5811,40 @@ IonBuilder::storeSlot(MDefinition *obj, 
     if (needsBarrier)
         store->setNeedsBarrier();
     return resumeAfter(store);
 }
 
 bool
 IonBuilder::jsop_getprop(HandlePropertyName name)
 {
-    LazyArgumentsType isArguments = oracle->propertyReadMagicArguments(script, pc);
+    LazyArgumentsType isArguments = oracle->propertyReadMagicArguments(script_, pc);
     if (isArguments == MaybeArguments)
         return abort("Type is not definitely lazy arguments.");
     if (isArguments == DefinitelyArguments) {
         if (JSOp(*pc) == JSOP_LENGTH)
             return jsop_arguments_length();
         // Can also be a callee.
     }
 
     MDefinition *obj = current->pop();
     MInstruction *ins;
 
-    types::StackTypeSet *barrier = oracle->propertyReadBarrier(script, pc);
-    types::StackTypeSet *types = oracle->propertyRead(script, pc);
-
-    TypeOracle::Unary unary = oracle->unaryOp(script, pc);
-    TypeOracle::UnaryTypes unaryTypes = oracle->unaryTypes(script, pc);
+    types::StackTypeSet *barrier = oracle->propertyReadBarrier(script_, pc);
+    types::StackTypeSet *types = oracle->propertyRead(script_, pc);
+
+    TypeOracle::Unary unary = oracle->unaryOp(script_, pc);
+    TypeOracle::UnaryTypes unaryTypes = oracle->unaryTypes(script_, pc);
 
     RootedId id(cx, NameToId(name));
 
     JSObject *singleton = types ? types->getSingleton() : NULL;
     if (singleton && !barrier) {
         bool isKnownConstant, testObject;
-        RootedObject global(cx, &script->global());
+        RootedObject global(cx, &script_->global());
         if (!TestSingletonPropertyTypes(cx, unaryTypes.inTypes,
                                         global, id,
                                         &isKnownConstant, &testObject))
         {
             return false;
         }
 
         if (isKnownConstant) {
@@ -5900,17 +5915,17 @@ IonBuilder::jsop_getprop(HandlePropertyN
     }
 
     if (unary.ival == MIRType_Object) {
         MIRType rvalType = MIRType_Value;
         if (!barrier && !IsNullOrUndefined(unary.rval))
             rvalType = unary.rval;
 
         Shape *objShape;
-        if ((objShape = mjit::GetPICSingleShape(cx, script, pc, info().constructing())) &&
+        if ((objShape = mjit::GetPICSingleShape(cx, script_, pc, info().constructing())) &&
             !objShape->inDictionary())
         {
             // The JM IC was monomorphic, so we inline the property access as
             // long as the shape is not in dictionary mode. We cannot be sure
             // that the shape is still a lastProperty, and calling
             // Shape::search() on dictionary mode shapes that aren't
             // lastProperty is invalid.
             MGuardShape *guard = MGuardShape::New(obj, objShape, Bailout_CachedShapeGuard);
@@ -5930,17 +5945,17 @@ IonBuilder::jsop_getprop(HandlePropertyN
         load->setResultType(rvalType);
 
         // Try to mark the cache as idempotent. We only do this if JM is enabled
         // (its ICs are used to mark property reads as likely non-idempotent) or
         // if we are compiling eagerly (to improve test coverage).
         if ((cx->methodJitEnabled || js_IonOptions.eagerCompilation) &&
             !invalidatedIdempotentCache())
         {
-            if (oracle->propertyReadIdempotent(script, pc, id))
+            if (oracle->propertyReadIdempotent(script_, pc, id))
                 load->setIdempotent();
         }
 
         ins = load;
         if (JSOp(*pc) == JSOP_CALLPROP) {
             if (!annotateGetPropertyCache(cx, obj, load, unaryTypes.inTypes, types))
                 return false;
         }
@@ -5960,19 +5975,19 @@ IonBuilder::jsop_getprop(HandlePropertyN
 }
 
 bool
 IonBuilder::jsop_setprop(HandlePropertyName name)
 {
     MDefinition *value = current->pop();
     MDefinition *obj = current->pop();
 
-    bool monitored = !oracle->propertyWriteCanSpecialize(script, pc);
-
-    TypeOracle::BinaryTypes binaryTypes = oracle->binaryTypes(script, pc);
+    bool monitored = !oracle->propertyWriteCanSpecialize(script_, pc);
+
+    TypeOracle::BinaryTypes binaryTypes = oracle->binaryTypes(script_, pc);
 
     if (!monitored) {
         if (types::HeapTypeSet *propTypes = GetDefiniteSlot(cx, binaryTypes.lhsTypes, name)) {
             MStoreFixedSlot *fixed = MStoreFixedSlot::New(obj, propTypes->definiteSlot(), value);
             current->add(fixed);
             current->push(value);
             if (propTypes->needsBarrier(cx))
                 fixed->setNeedsBarrier();
@@ -6016,47 +6031,47 @@ IonBuilder::jsop_setprop(HandlePropertyN
         MCall *call = makeCallHelper(setter, 1, false);
         if (!call)
             return false;
 
         current->push(value);
         return resumeAfter(call);
     }
 
-    oracle->binaryOp(script, pc);
+    oracle->binaryOp(script_, pc);
 
     MSetPropertyInstruction *ins;
     if (monitored) {
-        ins = MCallSetProperty::New(obj, value, name, script->strictModeCode);
+        ins = MCallSetProperty::New(obj, value, name, script_->strictModeCode);
     } else {
         Shape *objShape;
-        if ((objShape = mjit::GetPICSingleShape(cx, script, pc, info().constructing())) &&
+        if ((objShape = mjit::GetPICSingleShape(cx, script_, pc, info().constructing())) &&
             !objShape->inDictionary())
         {
             // The JM IC was monomorphic, so we inline the property access as
             // long as the shape is not in dictionary mode. We cannot be sure
             // that the shape is still a lastProperty, and calling Shape::search
             // on dictionary mode shapes that aren't lastProperty is invalid.
             MGuardShape *guard = MGuardShape::New(obj, objShape, Bailout_CachedShapeGuard);
             current->add(guard);
 
             Shape *shape = objShape->search(cx, NameToId(name));
             JS_ASSERT(shape);
 
             spew("Inlining monomorphic SETPROP");
 
             jsid typeId = types::MakeTypeId(cx, id);
-            bool needsBarrier = oracle->propertyWriteNeedsBarrier(script, pc, typeId);
+            bool needsBarrier = oracle->propertyWriteNeedsBarrier(script_, pc, typeId);
 
             return storeSlot(obj, shape, value, needsBarrier);
         }
 
         spew("SETPROP not monomorphic");
 
-        ins = MSetPropertyCache::New(obj, value, name, script->strictModeCode);
+        ins = MSetPropertyCache::New(obj, value, name, script_->strictModeCode);
 
         if (!binaryTypes.lhsTypes || binaryTypes.lhsTypes->propertyNeedsBarrier(cx, id))
             ins->setNeedsBarrier();
     }
 
     current->add(ins);
     current->push(value);
 
@@ -6074,17 +6089,17 @@ IonBuilder::jsop_delprop(HandlePropertyN
     current->push(ins);
 
     return resumeAfter(ins);
 }
 
 bool
 IonBuilder::jsop_regexp(RegExpObject *reobj)
 {
-    JSObject *prototype = script->global().getOrCreateRegExpPrototype(cx);
+    JSObject *prototype = script_->global().getOrCreateRegExpPrototype(cx);
     if (!prototype)
         return false;
 
     MRegExp *ins = MRegExp::New(reobj, prototype, MRegExp::MustClone);
     current->add(ins);
     current->push(ins);
 
     return true;
@@ -6098,105 +6113,105 @@ IonBuilder::jsop_object(JSObject *obj)
     current->push(ins);
 
     return true;
 }
 
 bool
 IonBuilder::jsop_lambda(JSFunction *fun)
 {
-    JS_ASSERT(script->analysis()->usesScopeChain());
+    JS_ASSERT(script_->analysis()->usesScopeChain());
     MLambda *ins = MLambda::New(current->scopeChain(), fun);
     current->add(ins);
     current->push(ins);
 
     return resumeAfter(ins);
 }
 
 bool
 IonBuilder::jsop_deflocalfun(uint32 local, JSFunction *fun)
 {
-    JS_ASSERT(script->analysis()->usesScopeChain());
+    JS_ASSERT(script_->analysis()->usesScopeChain());
 
     MLambda *ins = MLambda::New(current->scopeChain(), fun);
     current->add(ins);
     current->push(ins);
 
     current->setLocal(local);
     current->pop();
 
     return resumeAfter(ins);
 }
 
 bool
 IonBuilder::jsop_defvar(uint32 index)
 {
     JS_ASSERT(JSOp(*pc) == JSOP_DEFVAR || JSOp(*pc) == JSOP_DEFCONST);
 
-    PropertyName *name = script->getName(index);
+    PropertyName *name = script_->getName(index);
 
     // Bake in attrs.
     unsigned attrs = JSPROP_ENUMERATE | JSPROP_PERMANENT;
     if (JSOp(*pc) == JSOP_DEFCONST)
         attrs |= JSPROP_READONLY;
 
     // Pass the ScopeChain.
-    JS_ASSERT(script->analysis()->usesScopeChain());
+    JS_ASSERT(script_->analysis()->usesScopeChain());
 
     // Bake the name pointer into the MDefVar.
     MDefVar *defvar = MDefVar::New(name, attrs, current->scopeChain());
     current->add(defvar);
 
     return resumeAfter(defvar);
 }
 
 bool
 IonBuilder::jsop_this()
 {
     if (!info().fun())
         return abort("JSOP_THIS outside of a JSFunction.");
 
-    if (script->strictModeCode) {
+    if (script_->strictModeCode) {
         current->pushSlot(info().thisSlot());
         return true;
     }
 
-    types::StackTypeSet *types = oracle->thisTypeSet(script);
+    types::StackTypeSet *types = oracle->thisTypeSet(script_);
     if (types && types->getKnownTypeTag() == JSVAL_TYPE_OBJECT) {
         // This is safe, because if the entry type of |this| is an object, it
         // will necessarily be an object throughout the entire function. OSR
         // can introduce a phi, but this phi will be specialized.
         current->pushSlot(info().thisSlot());
         return true;
     }
 
     return abort("JSOP_THIS hard case not yet handled");
 }
 
 bool
 IonBuilder::jsop_typeof()
 {
-    TypeOracle::Unary unary = oracle->unaryOp(script, pc);
+    TypeOracle::Unary unary = oracle->unaryOp(script_, pc);
 
     MDefinition *input = current->pop();
     MTypeOf *ins = MTypeOf::New(input, unary.ival);
 
     current->add(ins);
     current->push(ins);
 
     if (ins->isEffectful() && !resumeAfter(ins))
         return false;
     return true;
 }
 
 bool
 IonBuilder::jsop_toid()
 {
     // No-op if the index is an integer.
-    TypeOracle::Unary unary = oracle->unaryOp(script, pc);
+    TypeOracle::Unary unary = oracle->unaryOp(script_, pc);
     if (unary.ival == MIRType_Int32)
         return true;
 
     MDefinition *index = current->pop();
     MToId *ins = MToId::New(current->peek(-1), index);
 
     current->add(ins);
     current->push(ins);
@@ -6267,21 +6282,21 @@ IonBuilder::walkScopeChain(unsigned hops
 
     return scope;
 }
 
 bool
 IonBuilder::jsop_getaliasedvar(ScopeCoordinate sc)
 {
     types::StackTypeSet *barrier;
-    types::StackTypeSet *actual = oracle->aliasedVarBarrier(script, pc, &barrier);
+    types::StackTypeSet *actual = oracle->aliasedVarBarrier(script_, pc, &barrier);
 
     MDefinition *obj = walkScopeChain(sc.hops);
 
-    RootedShape shape(cx, ScopeCoordinateToStaticScope(script, pc).scopeShape());
+    RootedShape shape(cx, ScopeCoordinateToStaticScope(script_, pc).scopeShape());
 
     MInstruction *load;
     if (shape->numFixedSlots() <= sc.slot) {
         MInstruction *slots = MSlots::New(obj);
         current->add(slots);
 
         load = MLoadSlot::New(slots, sc.slot - shape->numFixedSlots());
     } else {
@@ -6305,17 +6320,17 @@ IonBuilder::jsop_getaliasedvar(ScopeCoor
 }
 
 bool
 IonBuilder::jsop_setaliasedvar(ScopeCoordinate sc)
 {
     MDefinition *rval = current->peek(-1);
     MDefinition *obj = walkScopeChain(sc.hops);
 
-    RootedShape shape(cx, ScopeCoordinateToStaticScope(script, pc).scopeShape());
+    RootedShape shape(cx, ScopeCoordinateToStaticScope(script_, pc).scopeShape());
 
     MInstruction *store;
     if (shape->numFixedSlots() <= sc.slot) {
         MInstruction *slots = MSlots::New(obj);
         current->add(slots);
 
         store = MStoreSlot::NewBarriered(slots, sc.slot - shape->numFixedSlots(), rval);
     } else {
--- a/js/src/ion/IonBuilder.h
+++ b/js/src/ion/IonBuilder.h
@@ -410,28 +410,30 @@ class IonBuilder : public MIRGenerator
 
     MPolyInlineDispatch *
     makePolyInlineDispatch(JSContext *cx, AutoObjectVector &targets, int argc,
                            MGetPropertyCache *getPropCache,
                            types::StackTypeSet *types, types::StackTypeSet *barrier,
                            MBasicBlock *bottom,
                            Vector<MDefinition *, 8, IonAllocPolicy> &retvalDefns);
 
+    // A builder is inextricably tied to a particular script.
+    HeapPtrScript script_;
+
   public:
-    // A builder is inextricably tied to a particular script.
-    JSScript * const script;
-
     // Compilation index for this attempt.
     types::RecompileInfo const recompileInfo;
 
     // If off thread compilation is successful, final LIR is attached here.
     LIRGraph *lir;
 
     void clearForBackEnd();
 
+    JSScript *script() const { return script_; }
+
   private:
     JSContext *cx;
 
     jsbytecode *pc;
     MBasicBlock *current;
     uint32 loopDepth_;
 
     /* Information used for inline-call builders. */
--- a/js/src/ion/IonCaches.cpp
+++ b/js/src/ion/IonCaches.cpp
@@ -309,17 +309,17 @@ js::ion::GetPropertyCache(JSContext *cx,
     JSScript *topScript = GetTopIonJSScript(cx);
     IonScript *ion = topScript->ionScript();
 
     IonCacheGetProperty &cache = ion->getCache(cacheIndex).toGetProperty();
     RootedPropertyName name(cx, cache.name());
 
     RootedScript script(cx);
     jsbytecode *pc;
-    cache.getScriptedLocation(script.address(), &pc);
+    cache.getScriptedLocation(&script, &pc);
 
     // Override the return value if we are invalidated (bug 728188).
     AutoDetectInvalidation adi(cx, vp.address(), ion);
 
     // If the cache is idempotent, we will redo the op in the interpreter.
     if (cache.idempotent())
         adi.disable();
 
@@ -826,17 +826,17 @@ js::ion::GetElementCache(JSContext *cx, 
             // Generate at most one dense array stub.
             cache.incrementStubCount();
 
             if (!cache.attachDenseArray(cx, obj, idval))
                 return false;
         }
     }
 
-    JSScript *script;
+    RootedScript script(cx);
     jsbytecode *pc;
     cache.getScriptedLocation(&script, &pc);
 
     RootedValue lval(cx, ObjectValue(*obj));
     if (!GetElementOperation(cx, JSOp(*pc), lval, idval, res))
         return false;
 
     types::TypeScript::Monitor(cx, script, pc, res);
@@ -1150,17 +1150,17 @@ js::ion::GetNameCache(JSContext *cx, siz
 {
     AutoFlushCache afc ("GetNameCache");
 
     IonScript *ion = GetTopIonJSScript(cx)->ionScript();
 
     IonCacheName &cache = ion->getCache(cacheIndex).toName();
     RootedPropertyName name(cx, cache.name());
 
-    JSScript *script;
+    RootedScript script(cx);
     jsbytecode *pc;
     cache.getScriptedLocation(&script, &pc);
 
     RootedObject obj(cx);
     RootedObject holder(cx);
     RootedShape shape(cx);
     if (!LookupName(cx, name, scopeChain, &obj, &holder, &shape))
         return false;
--- a/js/src/ion/IonCaches.h
+++ b/js/src/ion/IonCaches.h
@@ -228,18 +228,18 @@ class IonCache
     }
 
     void setScriptedLocation(JSScript *script, jsbytecode *pc) {
         JS_ASSERT(!idempotent_);
         this->script = script;
         this->pc = pc;
     }
 
-    void getScriptedLocation(JSScript **pscript, jsbytecode **ppc) {
-        *pscript = script;
+    void getScriptedLocation(MutableHandleScript pscript, jsbytecode **ppc) {
+        pscript.set(script);
         *ppc = pc;
     }
 };
 
 inline IonCache &
 IonScript::getCache(size_t index) {
     JS_ASSERT(index < numCaches());
     return cacheList()[index];
--- a/js/src/ion/IonFrames.cpp
+++ b/js/src/ion/IonFrames.cpp
@@ -652,28 +652,28 @@ ion::MarkIonActivations(JSRuntime *rt, J
 void
 ion::AutoTempAllocatorRooter::trace(JSTracer *trc)
 {
     for (CompilerRootNode *root = temp->rootList(); root != NULL; root = root->next)
         gc::MarkGCThingRoot(trc, root->address(), "ion-compiler-root");
 }
 
 void
-ion::GetPcScript(JSContext *cx, JSScript **scriptRes, jsbytecode **pcRes)
+ion::GetPcScript(JSContext *cx, MutableHandleScript scriptRes, jsbytecode **pcRes)
 {
     JS_ASSERT(cx->fp()->beginsIonActivation());
     IonSpew(IonSpew_Snapshots, "Recover PC & Script from the last frame.");
 
     // Recover the innermost inlined frame.
     IonFrameIterator it(cx->runtime->ionTop);
     ++it;
     InlineFrameIterator ifi(&it);
 
     // Set the result.
-    *scriptRes = ifi.script();
+    scriptRes.set(ifi.script());
     if (pcRes)
         *pcRes = ifi.pc();
 }
 
 void
 OsiIndex::fixUpOffset(MacroAssembler &masm)
 {
     callPointDisplacement_ = masm.actualOffset(callPointDisplacement_);
--- a/js/src/ion/IonFrames.h
+++ b/js/src/ion/IonFrames.h
@@ -257,17 +257,17 @@ namespace js {
 namespace ion {
 
 JSScript *
 GetTopIonJSScript(JSContext *cx,
                   const SafepointIndex **safepointIndexOut = NULL,
                   void **returnAddrOut = NULL);
 
 void
-GetPcScript(JSContext *cx, JSScript **scriptRes, jsbytecode **pcRes);
+GetPcScript(JSContext *cx, MutableHandleScript scriptRes, jsbytecode **pcRes);
 
 // Given a slot index, returns the offset, in bytes, of that slot from an
 // IonJSFrameLayout. Slot distances are uniform across architectures, however,
 // the distance does depend on the size of the frame header.
 static inline int32
 OffsetOfFrameSlot(int32 slot)
 {
     if (slot <= 0)
--- a/js/src/ion/MCallOptimize.cpp
+++ b/js/src/ion/MCallOptimize.cpp
@@ -94,33 +94,33 @@ IonBuilder::discardCall(uint32 argc, MDe
     bb->pop();
     return true;
 }
 
 types::StackTypeSet *
 IonBuilder::getInlineReturnTypeSet()
 {
     types::StackTypeSet *barrier;
-    types::StackTypeSet *returnTypes = oracle->returnTypeSet(script, pc, &barrier);
+    types::StackTypeSet *returnTypes = oracle->returnTypeSet(script_, pc, &barrier);
 
     JS_ASSERT(returnTypes);
     return returnTypes;
 }
 
 MIRType
 IonBuilder::getInlineReturnType()
 {
     types::StackTypeSet *returnTypes = getInlineReturnTypeSet();
     return MIRTypeFromValueType(returnTypes->getKnownTypeTag());
 }
 
 types::StackTypeSet *
 IonBuilder::getInlineArgTypeSet(uint32 argc, uint32 arg)
 {
-    types::StackTypeSet *argTypes = oracle->getCallArg(script, argc, arg, pc);
+    types::StackTypeSet *argTypes = oracle->getCallArg(script_, argc, arg, pc);
     JS_ASSERT(argTypes);
     return argTypes;
 }
 
 MIRType
 IonBuilder::getInlineArgType(uint32 argc, uint32 arg)
 {
     types::StackTypeSet *argTypes = getInlineArgTypeSet(argc, arg);
@@ -240,16 +240,17 @@ IonBuilder::inlineArrayPopShift(MArrayPo
     // Inference's TypeConstraintCall generates the constraints that propagate
     // properties directly into the result type set.
     types::TypeObjectFlags unhandledFlags =
         types::OBJECT_FLAG_NON_DENSE_ARRAY | types::OBJECT_FLAG_ITERATED;
 
     types::StackTypeSet *thisTypes = getInlineArgTypeSet(argc, 0);
     if (thisTypes->hasObjectFlags(cx, unhandledFlags))
         return InliningStatus_NotInlined;
+    RootedScript script(cx, script_);
     if (types::ArrayPrototypeHasIndexedProperty(cx, script))
         return InliningStatus_NotInlined;
 
     MDefinitionVector argv;
     if (!discardCall(argc, argv, current))
         return InliningStatus_Error;
 
     types::StackTypeSet *returnTypes = getInlineReturnTypeSet();
@@ -277,16 +278,17 @@ IonBuilder::inlineArrayPush(uint32 argc,
     if (getInlineArgType(argc, 0) != MIRType_Object)
         return InliningStatus_NotInlined;
 
     // Inference's TypeConstraintCall generates the constraints that propagate
     // properties directly into the result type set.
     types::StackTypeSet *thisTypes = getInlineArgTypeSet(argc, 0);
     if (thisTypes->hasObjectFlags(cx, types::OBJECT_FLAG_NON_DENSE_ARRAY))
         return InliningStatus_NotInlined;
+    RootedScript script(cx, script_);
     if (types::ArrayPrototypeHasIndexedProperty(cx, script))
         return InliningStatus_NotInlined;
 
     MDefinitionVector argv;
     if (!discardCall(argc, argv, current))
         return InliningStatus_Error;
 
     MArrayPush *ins = MArrayPush::New(argv[0], argv[1]);
--- a/js/src/ion/TypeOracle.cpp
+++ b/js/src/ion/TypeOracle.cpp
@@ -16,17 +16,17 @@ using namespace js;
 using namespace js::ion;
 using namespace js::types;
 using namespace js::analyze;
 
 bool
 TypeInferenceOracle::init(JSContext *cx, JSScript *script)
 {
     this->cx = cx;
-    this->script = script;
+    this->script_.init(script);
     return script->ensureRanInference(cx);
 }
 
 MIRType
 GetMIRType(JSValueType type)
 {
     /* Get the suggested representation to use for values in a given type set. */
     switch (type) {
@@ -61,28 +61,28 @@ MIRType
 TypeInferenceOracle::getMIRType(HeapTypeSet *types)
 {
     return GetMIRType(types->getKnownTypeTag(cx));
 }
 
 TypeOracle::UnaryTypes
 TypeInferenceOracle::unaryTypes(JSScript *script, jsbytecode *pc)
 {
-    JS_ASSERT(script == this->script);
+    JS_ASSERT(script == this->script_);
 
     UnaryTypes res;
     res.inTypes = script->analysis()->poppedTypes(pc, 0);
     res.outTypes = script->analysis()->pushedTypes(pc, 0);
     return res;
 }
 
 TypeOracle::BinaryTypes
 TypeInferenceOracle::binaryTypes(JSScript *script, jsbytecode *pc)
 {
-    JS_ASSERT(script == this->script);
+    JS_ASSERT(script == this->script_);
 
     JSOp op = (JSOp)*pc;
 
     BinaryTypes res;
     if ((js_CodeSpec[op].format & JOF_INCDEC) || op == JSOP_NEG || op == JSOP_POS) {
         res.lhsTypes = script->analysis()->poppedTypes(pc, 0);
         res.rhsTypes = NULL;
         res.outTypes = script->analysis()->pushedTypes(pc, 0);
@@ -116,28 +116,28 @@ TypeInferenceOracle::incslot(JSScript *s
     b.rhsTypes = NULL;
     b.outTypes = script->analysis()->pushedTypes(pc, 0);
     return b;
 }
 
 TypeOracle::Unary
 TypeInferenceOracle::unaryOp(JSScript *script, jsbytecode *pc)
 {
-    JS_ASSERT(script == this->script);
+    JS_ASSERT(script == this->script_);
 
     Unary res;
     res.ival = getMIRType(script->analysis()->poppedTypes(pc, 0));
     res.rval = getMIRType(script->analysis()->pushedTypes(pc, 0));
     return res;
 }
 
 TypeOracle::Binary
 TypeInferenceOracle::binaryOp(JSScript *script, jsbytecode *pc)
 {
-    JS_ASSERT(script == this->script);
+    JS_ASSERT(script == this->script_);
 
     JSOp op = (JSOp)*pc;
 
     Binary res;
     if ((js_CodeSpec[op].format & JOF_INCDEC) || op == JSOP_NEG || op == JSOP_POS) {
         res.lhs = getMIRType(script->analysis()->poppedTypes(pc, 0));
         res.rhs = MIRType_Int32;
         res.rval = getMIRType(script->analysis()->pushedTypes(pc, 0));
@@ -147,55 +147,55 @@ TypeInferenceOracle::binaryOp(JSScript *
         res.rval = getMIRType(script->analysis()->pushedTypes(pc, 0));
     }
     return res;
 }
 
 StackTypeSet *
 TypeInferenceOracle::thisTypeSet(JSScript *script)
 {
-    JS_ASSERT(script == this->script);
+    JS_ASSERT(script == this->script_);
     return TypeScript::ThisTypes(script);
 }
 
 bool
 TypeInferenceOracle::getOsrTypes(jsbytecode *osrPc, Vector<MIRType> &slotTypes)
 {
     JS_ASSERT(JSOp(*osrPc) == JSOP_LOOPENTRY);
-    JS_ASSERT(script->code < osrPc);
-    JS_ASSERT(osrPc < script->code + script->length);
+    JS_ASSERT(script_->code < osrPc);
+    JS_ASSERT(osrPc < script_->code + script_->length);
 
     Vector<types::StackTypeSet *> slotTypeSets(cx);
-    if (!slotTypeSets.resize(TotalSlots(script)))
+    if (!slotTypeSets.resize(TotalSlots(script_)))
         return false;
 
-    for (uint32_t slot = ThisSlot(); slot < TotalSlots(script); slot++)
-        slotTypeSets[slot] = TypeScript::SlotTypes(script, slot);
+    for (uint32_t slot = ThisSlot(); slot < TotalSlots(script_); slot++)
+        slotTypeSets[slot] = TypeScript::SlotTypes(script_, slot);
 
-    jsbytecode *pc = script->code;
-    ScriptAnalysis *analysis = script->analysis();
+    jsbytecode *pc = script_->code;
+    ScriptAnalysis *analysis = script_->analysis();
 
     // To determine the slot types at the OSR pc, we have to do a forward walk
     // over the bytecode to reconstruct the types.
     for (;;) {
         Bytecode *opinfo = analysis->maybeCode(pc);
         if (opinfo) {
             if (opinfo->jumpTarget) {
                 // Update variable types for all new values at this bytecode.
                 if (const SlotValue *newv = analysis->newValues(pc)) {
                     while (newv->slot) {
-                        if (newv->slot < TotalSlots(script))
+                        if (newv->slot < TotalSlots(script_))
                             slotTypeSets[newv->slot] = analysis->getValueTypes(newv->value);
                         newv++;
                     }
                 }
             }
 
             if (BytecodeUpdatesSlot(JSOp(*pc))) {
-                uint32_t slot = GetBytecodeSlot(script, pc);
+                uint32_t slot = GetBytecodeSlot(script_, pc);
                 if (analysis->trackSlot(slot))
                     slotTypeSets[slot] = analysis->pushedTypes(pc, 0);
             }
         }
 
         if (pc == osrPc)
             break;
 
@@ -208,35 +208,35 @@ TypeInferenceOracle::getOsrTypes(jsbytec
     // scripts. This means we have to subtract 1 for global/eval scripts.
     JS_ASSERT(ThisSlot() == 1);
     JS_ASSERT(ArgSlot(0) == 2);
 
 #ifdef DEBUG
     uint32_t stackDepth = analysis->getCode(osrPc).stackDepth;
 #endif
 
-    if (script->function()) {
-        JS_ASSERT(slotTypes.length() == TotalSlots(script) + stackDepth);
+    if (script_->function()) {
+        JS_ASSERT(slotTypes.length() == TotalSlots(script_) + stackDepth);
 
-        for (size_t i = ThisSlot(); i < TotalSlots(script); i++)
+        for (size_t i = ThisSlot(); i < TotalSlots(script_); i++)
             slotTypes[i] = getMIRType(slotTypeSets[i]);
     } else {
-        JS_ASSERT(slotTypes.length() == TotalSlots(script) + stackDepth - 1);
+        JS_ASSERT(slotTypes.length() == TotalSlots(script_) + stackDepth - 1);
 
-        for (size_t i = ArgSlot(0); i < TotalSlots(script); i++)
+        for (size_t i = ArgSlot(0); i < TotalSlots(script_); i++)
             slotTypes[i - 1] = getMIRType(slotTypeSets[i]);
     }
 
     return true;
 }
 
 StackTypeSet *
 TypeInferenceOracle::parameterTypeSet(JSScript *script, size_t index)
 {
-    JS_ASSERT(script == this->script);
+    JS_ASSERT(script == this->script_);
     return TypeScript::ArgTypes(script, index);
 }
 
 StackTypeSet *
 TypeInferenceOracle::propertyRead(JSScript *script, jsbytecode *pc)
 {
     return script->analysis()->pushedTypes(pc, 0);
 }
@@ -463,23 +463,24 @@ TypeInferenceOracle::elementWrite(JSScri
     }
 
     return elementType;
 }
 
 bool
 TypeInferenceOracle::arrayPrototypeHasIndexedProperty()
 {
+    RootedScript script(cx, script_);
     return ArrayPrototypeHasIndexedProperty(cx, script);
 }
 
 bool
 TypeInferenceOracle::canInlineCalls()
 {
-    return script->analysis()->hasFunctionCalls();
+    return script_->analysis()->hasFunctionCalls();
 }
 
 bool
 TypeInferenceOracle::propertyWriteCanSpecialize(JSScript *script, jsbytecode *pc)
 {
     return !script->analysis()->getCode(pc).monitoredTypes;
 }
 
@@ -497,20 +498,20 @@ TypeInferenceOracle::elementWriteNeedsBa
     // a property. The object is the third value popped by SETELEM.
     StackTypeSet *types = script->analysis()->poppedTypes(pc, 2);
     return types->propertyNeedsBarrier(cx, JSID_VOID);
 }
 
 StackTypeSet *
 TypeInferenceOracle::getCallTarget(JSScript *caller, uint32 argc, jsbytecode *pc)
 {
-    JS_ASSERT(caller == this->script);
+    JS_ASSERT(caller == this->script_);
     JS_ASSERT(js_CodeSpec[*pc].format & JOF_INVOKE && JSOp(*pc) != JSOP_EVAL);
 
-    ScriptAnalysis *analysis = script->analysis();
+    ScriptAnalysis *analysis = script_->analysis();
     return analysis->poppedTypes(pc, argc + 1);
 }
 
 StackTypeSet *
 TypeInferenceOracle::getCallArg(JSScript *script, uint32 argc, uint32 arg, jsbytecode *pc)
 {
     JS_ASSERT(argc >= arg);
     // Bytecode order: Function, This, Arg0, Arg1, ..., ArgN, Call.
--- a/js/src/ion/TypeOracle.h
+++ b/js/src/ion/TypeOracle.h
@@ -208,23 +208,23 @@ class DummyOracle : public TypeOracle
         b.rval = MIRType_Int32;
         return b;
     }
 };
 
 class TypeInferenceOracle : public TypeOracle
 {
     JSContext *cx;
-    JSScript *script;
+    HeapPtrScript script_;
 
     MIRType getMIRType(types::StackTypeSet *types);
     MIRType getMIRType(types::HeapTypeSet *types);
 
   public:
-    TypeInferenceOracle() : cx(NULL), script(NULL) {}
+    TypeInferenceOracle() : cx(NULL), script_(NULL) {}
 
     bool init(JSContext *cx, JSScript *script);
 
     UnaryTypes unaryTypes(JSScript *script, jsbytecode *pc);
     BinaryTypes binaryTypes(JSScript *script, jsbytecode *pc);
     Unary unaryOp(JSScript *script, jsbytecode *pc);
     Binary binaryOp(JSScript *script, jsbytecode *pc);
     types::StackTypeSet *thisTypeSet(JSScript *script);
--- a/js/src/ion/shared/Assembler-x86-shared.cpp
+++ b/js/src/ion/shared/Assembler-x86-shared.cpp
@@ -3,16 +3,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/. */
 
 #include "ion/IonMacroAssembler.h"
 #include "gc/Marking.h"
 
+#include "jsscriptinlines.h"
+
 using namespace js;
 using namespace js::ion;
 
 void
 AssemblerX86Shared::copyJumpRelocationTable(uint8 *dest)
 {
     if (jumpRelocations_.length())
         memcpy(dest, jumpRelocations_.buffer(), jumpRelocations_.length());
--- a/js/src/ion/shared/MoveEmitter-x86-shared.cpp
+++ b/js/src/ion/shared/MoveEmitter-x86-shared.cpp
@@ -2,16 +2,18 @@
  * vim: set ts=4 sw=4 et tw=99:
  *
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "MoveEmitter-x86-shared.h"
 
+#include "jsscriptinlines.h"
+
 using namespace js;
 using namespace js::ion;
 
 MoveEmitterX86::MoveEmitterX86(MacroAssemblerSpecific &masm)
   : inCycle_(false),
     masm(masm),
     pushedAtCycle_(-1),
     pushedAtSpill_(-1),
--- a/js/src/ion/x64/Assembler-x64.cpp
+++ b/js/src/ion/x64/Assembler-x64.cpp
@@ -3,16 +3,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/. */
 
 #include "Assembler-x64.h"
 #include "gc/Marking.h"
 
+#include "jsscriptinlines.h"
+
 using namespace js;
 using namespace js::ion;
 
 void
 Assembler::writeRelocation(JmpSrc src, Relocation::Kind reloc)
 {
     if (!jumpRelocations_.length()) {
         // The jump relocation table starts with a fixed-width integer pointing
--- a/js/src/ion/x64/MacroAssembler-x64.cpp
+++ b/js/src/ion/x64/MacroAssembler-x64.cpp
@@ -4,16 +4,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/. */
 
 #include "MacroAssembler-x64.h"
 #include "ion/MoveEmitter.h"
 #include "ion/IonFrames.h"
 
+#include "jsscriptinlines.h"
+
 using namespace js;
 using namespace js::ion;
 
 void
 MacroAssemblerX64::setupABICall(uint32 args)
 {
     JS_ASSERT(!inCall_);
     inCall_ = true;
--- a/js/src/ion/x64/Trampoline-x64.cpp
+++ b/js/src/ion/x64/Trampoline-x64.cpp
@@ -9,16 +9,18 @@
 #include "assembler/assembler/MacroAssembler.h"
 #include "ion/IonCompartment.h"
 #include "ion/IonLinker.h"
 #include "ion/IonFrames.h"
 #include "ion/Bailouts.h"
 #include "ion/VMFunctions.h"
 #include "ion/IonSpewer.h"
 
+#include "jsscriptinlines.h"
+
 using namespace js;
 using namespace js::ion;
 
 /* This method generates a trampoline on x64 for a c++ function with
  * the following signature:
  *   JSBool blah(void *code, int argc, Value *argv, Value *vp)
  *   ...using standard x64 fastcall calling convention
  */
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/ion/bug792166-1.js
@@ -0,0 +1,8 @@
+Object.defineProperty(Object.prototype, 'x', {
+    set: function() {}
+});
+var obj = {};
+for (var i = 0; i < 100 ; ++i) {
+    obj.x = 1;
+    delete obj.x;
+}
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/ion/bug792166-2.js
@@ -0,0 +1,8 @@
+try {
+  __defineGetter__("eval", function() {
+    this["__proto__"]
+  })
+  delete this["__proto__"]
+  this["__proto__"]
+} catch (e) {}
+eval
--- a/js/src/jsanalyze.cpp
+++ b/js/src/jsanalyze.cpp
@@ -50,17 +50,17 @@ IsJumpOpcode(JSOp op)
 // Bytecode Analysis
 /////////////////////////////////////////////////////////////////////
 
 inline bool
 ScriptAnalysis::addJump(JSContext *cx, unsigned offset,
                         unsigned *currentOffset, unsigned *forwardJump, unsigned *forwardLoop,
                         unsigned stackDepth)
 {
-    JS_ASSERT(offset < script->length);
+    JS_ASSERT(offset < script_->length);
 
     Bytecode *&code = codeArray[offset];
     if (!code) {
         code = cx->analysisLifoAlloc().new_<Bytecode>();
         if (!code) {
             setOOM(cx);
             return false;
         }
@@ -106,19 +106,19 @@ ScriptAnalysis::addJump(JSContext *cx, u
 
 void
 ScriptAnalysis::analyzeBytecode(JSContext *cx)
 {
     JS_ASSERT(cx->compartment->activeAnalysis);
     JS_ASSERT(!ranBytecode());
     LifoAlloc &alloc = cx->analysisLifoAlloc();
 
-    numSlots = TotalSlots(script);
+    numSlots = TotalSlots(script_);
 
-    unsigned length = script->length;
+    unsigned length = script_->length;
     codeArray = alloc.newArray<Bytecode*>(length);
     escapedSlots = alloc.newArray<bool>(numSlots);
 
     if (!codeArray || !escapedSlots) {
         setOOM(cx);
         return;
     }
 
@@ -133,39 +133,39 @@ ScriptAnalysis::analyzeBytecode(JSContex
      * (needsArgsObj requires SSA which requires escapedSlots). Lastly, the
      * debugger can access any local at any time. Even though debugger
      * reads/writes are monitored by the DebugScopeProxy, this monitoring
      * updates the flow-insensitive type sets, so we cannot use SSA.
      */
 
     PodZero(escapedSlots, numSlots);
 
-    bool allVarsAliased = script->compartment()->debugMode();
-    bool allArgsAliased = allVarsAliased || script->argumentsHasVarBinding();
+    bool allVarsAliased = script_->compartment()->debugMode();
+    bool allArgsAliased = allVarsAliased || script_->argumentsHasVarBinding();
 
-    for (BindingIter bi(script->bindings); bi; bi++) {
+    for (BindingIter bi(script_->bindings); bi; bi++) {
         if (bi->kind() == ARGUMENT)
             escapedSlots[ArgSlot(bi.frameIndex())] = allArgsAliased || bi->aliased();
         else
-            escapedSlots[LocalSlot(script, bi.frameIndex())] = allVarsAliased || bi->aliased();
+            escapedSlots[LocalSlot(script_, bi.frameIndex())] = allVarsAliased || bi->aliased();
     }
 
     /*
      * If the script is in debug mode, JS_SetFrameReturnValue can be called at
      * any safe point.
      */
     if (cx->compartment->debugMode())
         usesReturnValue_ = true;
 
-    bool heavyweight = script->function() && script->function()->isHeavyweight();
+    bool heavyweight = script_->function() && script_->function()->isHeavyweight();
 
     isJaegerCompileable = true;
 
     isInlineable = true;
-    if (heavyweight || script->argumentsHasVarBinding() || cx->compartment->debugMode())
+    if (heavyweight || script_->argumentsHasVarBinding() || cx->compartment->debugMode())
         isInlineable = false;
 
     modifiesArguments_ = false;
     if (heavyweight)
         modifiesArguments_ = true;
 
     canTrackVars = true;
 
@@ -192,32 +192,32 @@ ScriptAnalysis::analyzeBytecode(JSContex
         return;
     }
 
     startcode->stackDepth = 0;
     codeArray[0] = startcode;
 
     /* Number of JOF_TYPESET opcodes we have encountered. */
     unsigned nTypeSets = 0;
-    types::TypeSet *typeArray = script->types->typeArray();
+    types::TypeSet *typeArray = script_->types->typeArray();
 
     unsigned offset, nextOffset = 0;
     while (nextOffset < length) {
         offset = nextOffset;
 
         JS_ASSERT(forwardCatch <= forwardJump);
 
         /* Check if the current forward jump/try-block has finished. */
         if (forwardJump && forwardJump == offset)
             forwardJump = 0;
         if (forwardCatch && forwardCatch == offset)
             forwardCatch = 0;
 
         Bytecode *code = maybeCode(offset);
-        jsbytecode *pc = script->code + offset;
+        jsbytecode *pc = script_->code + offset;
 
         JSOp op = (JSOp)*pc;
         JS_ASSERT(op < JSOP_LIMIT);
 
         /* Immediate successor of this bytecode. */
         unsigned successorOffset = offset + GetBytecodeLength(pc);
 
         /*
@@ -246,48 +246,48 @@ ScriptAnalysis::analyzeBytecode(JSContex
             continue;
         }
 
         code->analyzed = true;
 
         if (forwardCatch)
             code->inTryBlock = true;
 
-        if (script->hasBreakpointsAt(pc)) {
+        if (script_->hasBreakpointsAt(pc)) {
             code->safePoint = true;
             isInlineable = canTrackVars = false;
         }
 
         unsigned stackDepth = code->stackDepth;
 
         if (!forwardJump)
             code->unconditional = true;
 
         /*
          * Treat decompose ops as no-ops which do not adjust the stack. We will
          * pick up the stack depths as we go through the decomposed version.
          */
         if (!(js_CodeSpec[op].format & JOF_DECOMPOSE)) {
-            unsigned nuses = GetUseCount(script, offset);
-            unsigned ndefs = GetDefCount(script, offset);
+            unsigned nuses = GetUseCount(script_, offset);
+            unsigned ndefs = GetDefCount(script_, offset);
 
             JS_ASSERT(stackDepth >= nuses);
             stackDepth -= nuses;
             stackDepth += ndefs;
         }
 
         /*
          * Assign an observed type set to each reachable JOF_TYPESET opcode.
          * This may be less than the number of type sets in the script if some
          * are unreachable, and may be greater in case the number of type sets
          * overflows a uint16. In the latter case a single type set will be
          * used for the observed types of all ops after the overflow.
          */
         if ((js_CodeSpec[op].format & JOF_TYPESET) && cx->typeInferenceEnabled()) {
-            if (nTypeSets < script->nTypeSets) {
+            if (nTypeSets < script_->nTypeSets) {
                 code->observedTypes = typeArray[nTypeSets++].toStackTypeSet();
             } else {
                 JS_ASSERT(nTypeSets == UINT16_MAX);
                 code->observedTypes = typeArray[nTypeSets - 1].toStackTypeSet();
             }
         }
 
         switch (op) {
@@ -408,20 +408,20 @@ ScriptAnalysis::analyzeBytecode(JSContex
           case JSOP_TRY: {
             /*
              * Everything between a try and corresponding catch or finally is conditional.
              * Note that there is no problem with code which is skipped by a thrown
              * exception but is not caught by a later handler in the same function:
              * no more code will execute, and it does not matter what is defined.
              */
             isInlineable = false;
-            JSTryNote *tn = script->trynotes()->vector;
-            JSTryNote *tnlimit = tn + script->trynotes()->length;
+            JSTryNote *tn = script_->trynotes()->vector;
+            JSTryNote *tnlimit = tn + script_->trynotes()->length;
             for (; tn < tnlimit; tn++) {
-                unsigned startOffset = script->mainOffset + tn->start;
+                unsigned startOffset = script_->mainOffset + tn->start;
                 if (startOffset == offset + 1) {
                     unsigned catchOffset = startOffset + tn->length;
 
                     /* This will overestimate try block code, for multiple catch/finally. */
                     if (catchOffset > forwardCatch)
                         forwardCatch = catchOffset;
 
                     if (tn->kind != JSTRY_ITER) {
@@ -439,32 +439,32 @@ ScriptAnalysis::analyzeBytecode(JSContex
             /*
              * Watch for uses of variables not known to be defined, and mark
              * them as having possible uses before definitions.  Ignore GETLOCAL
              * followed by a POP, these are generated for, e.g. 'var x;'
              */
             jsbytecode *next = pc + JSOP_GETLOCAL_LENGTH;
             if (JSOp(*next) != JSOP_POP || jumpTarget(next)) {
                 uint32_t local = GET_SLOTNO(pc);
-                if (local >= script->nfixed) {
+                if (local >= script_->nfixed) {
                     localsAliasStack_ = true;
                     break;
                 }
             }
             break;
           }
 
           case JSOP_CALLLOCAL:
           case JSOP_INCLOCAL:
           case JSOP_DECLOCAL:
           case JSOP_LOCALINC:
           case JSOP_LOCALDEC:
           case JSOP_SETLOCAL: {
             uint32_t local = GET_SLOTNO(pc);
-            if (local >= script->nfixed) {
+            if (local >= script_->nfixed) {
                 localsAliasStack_ = true;
                 break;
             }
             break;
           }
 
           case JSOP_SETARG:
           case JSOP_INCARG:
@@ -609,17 +609,17 @@ ScriptAnalysis::analyzeBytecode(JSContex
 
             unsigned targetOffset = offset + GET_JUMP_OFFSET(pc);
             if (!addJump(cx, targetOffset, &nextOffset, &forwardJump, &forwardLoop, newStackDepth))
                 return;
         }
 
         /* Handle any fallthrough from this opcode. */
         if (!BytecodeNoFallThrough(op)) {
-            JS_ASSERT(successorOffset < script->length);
+            JS_ASSERT(successorOffset < script_->length);
 
             Bytecode *&nextcode = codeArray[successorOffset];
 
             if (!nextcode) {
                 nextcode = alloc.new_<Bytecode>();
                 if (!nextcode) {
                     setOOM(cx);
                     return;
@@ -644,30 +644,30 @@ ScriptAnalysis::analyzeBytecode(JSContex
 
     ranBytecode_ = true;
 
     /*
      * Always ensure that a script's arguments usage has been analyzed before
      * entering the script. This allows the functionPrologue to ensure that
      * arguments are always created eagerly which simplifies interp logic.
      */
-    if (!script->analyzedArgsUsage())
+    if (!script_->analyzedArgsUsage())
         analyzeSSA(cx);
 
     /*
      * If the script has JIT information (we are reanalyzing the script after
      * a purge), add safepoints for the targets of any cross chunk edges in
      * the script. These safepoints are normally added when the JITScript is
      * constructed, but will have been lost during the purge.
      */
 #ifdef JS_METHODJIT
     mjit::JITScript *jit = NULL;
     for (int constructing = 0; constructing <= 1 && !jit; constructing++) {
         for (int barriers = 0; barriers <= 1 && !jit; barriers++)
-            jit = script->getJIT((bool) constructing, (bool) barriers);
+            jit = script_->getJIT((bool) constructing, (bool) barriers);
     }
     if (jit) {
         mjit::CrossChunkEdge *edges = jit->edges();
         for (size_t i = 0; i < jit->nedges; i++)
             getCode(edges[i].target).safePoint = true;
     }
 #endif
 }
@@ -704,28 +704,28 @@ ScriptAnalysis::analyzeLifetimes(JSConte
     if (!saved) {
         setOOM(cx);
         return;
     }
     unsigned savedCount = 0;
 
     LoopAnalysis *loop = NULL;
 
-    uint32_t offset = script->length - 1;
-    while (offset < script->length) {
+    uint32_t offset = script_->length - 1;
+    while (offset < script_->length) {
         Bytecode *code = maybeCode(offset);
         if (!code) {
             offset--;
             continue;
         }
 
         if (loop && code->safePoint)
             loop->hasSafePoints = true;
 
-        jsbytecode *pc = script->code + offset;
+        jsbytecode *pc = script_->code + offset;
 
         JSOp op = (JSOp) *pc;
 
         if (op == JSOP_LOOPHEAD && code->loop) {
             /*
              * This is the head of a loop, we need to go and make sure that any
              * variables live at the head are live at the backedge and points prior.
              * For each such variable, look for the last lifetime segment in the body
@@ -743,20 +743,20 @@ ScriptAnalysis::analyzeLifetimes(JSConte
         }
 
         /* Find the last jump target in the loop, other than the initial entry point. */
         if (loop && code->jumpTarget && offset != loop->entry && offset > loop->lastBlock)
             loop->lastBlock = offset;
 
         if (code->exceptionEntry) {
             DebugOnly<bool> found = false;
-            JSTryNote *tn = script->trynotes()->vector;
-            JSTryNote *tnlimit = tn + script->trynotes()->length;
+            JSTryNote *tn = script_->trynotes()->vector;
+            JSTryNote *tnlimit = tn + script_->trynotes()->length;
             for (; tn < tnlimit; tn++) {
-                unsigned startOffset = script->mainOffset + tn->start;
+                unsigned startOffset = script_->mainOffset + tn->start;
                 if (startOffset + tn->length == offset) {
                     /*
                      * Extend all live variables at exception entry to the start of
                      * the try block.
                      */
                     for (unsigned i = 0; i < numSlots; i++) {
                         if (lifetimes[i].lifetime)
                             ensureVariable(lifetimes[i], startOffset - 1);
@@ -770,39 +770,39 @@ ScriptAnalysis::analyzeLifetimes(JSConte
         }
 
         switch (op) {
           case JSOP_GETARG:
           case JSOP_CALLARG:
           case JSOP_GETLOCAL:
           case JSOP_CALLLOCAL:
           case JSOP_THIS: {
-            uint32_t slot = GetBytecodeSlot(script, pc);
+            uint32_t slot = GetBytecodeSlot(script_, pc);
             if (!slotEscapes(slot))
                 addVariable(cx, lifetimes[slot], offset, saved, savedCount);
             break;
           }
 
           case JSOP_SETARG:
           case JSOP_SETLOCAL: {
-            uint32_t slot = GetBytecodeSlot(script, pc);
+            uint32_t slot = GetBytecodeSlot(script_, pc);
             if (!slotEscapes(slot))
                 killVariable(cx, lifetimes[slot], offset, saved, savedCount);
             break;
           }
 
           case JSOP_INCARG:
           case JSOP_DECARG:
           case JSOP_ARGINC:
           case JSOP_ARGDEC:
           case JSOP_INCLOCAL:
           case JSOP_DECLOCAL:
           case JSOP_LOCALINC:
           case JSOP_LOCALDEC: {
-            uint32_t slot = GetBytecodeSlot(script, pc);
+            uint32_t slot = GetBytecodeSlot(script_, pc);
             if (!slotEscapes(slot)) {
                 killVariable(cx, lifetimes[slot], offset, saved, savedCount);
                 addVariable(cx, lifetimes[slot], offset, saved, savedCount);
             }
             break;
           }
 
           case JSOP_LOOKUPSWITCH:
@@ -850,30 +850,30 @@ ScriptAnalysis::analyzeLifetimes(JSConte
         }
 
         if (IsJumpOpcode(op)) {
             /*
              * Forward jumps need to pull in all variables which are live at
              * their target offset --- the variables live before the jump are
              * the union of those live at the fallthrough and at the target.
              */
-            uint32_t targetOffset = FollowBranch(cx, script, offset);
+            uint32_t targetOffset = FollowBranch(cx, script_, offset);
 
             /*
              * Watch for 'continue' statements in the loop body, which are
              * jumps to the entry offset separate from the initial jump.
              */
             if (loop && loop->entry == targetOffset && loop->entry > loop->lastBlock)
                 loop->lastBlock = loop->entry;
 
             if (targetOffset < offset) {
                 /* This is a loop back edge, no lifetime to pull in yet. */
 
 #ifdef DEBUG
-                JSOp nop = JSOp(script->code[targetOffset]);
+                JSOp nop = JSOp(script_->code[targetOffset]);
                 JS_ASSERT(nop == JSOP_LOOPHEAD);
 #endif
 
                 /*
                  * If we already have a loop, it is an outer loop and we
                  * need to prune the last block in the loop --- we do not
                  * track 'continue' statements for outer loops.
                  */
@@ -906,28 +906,28 @@ ScriptAnalysis::analyzeLifetimes(JSConte
                  * 'while' loops or a fallthrough for 'do while' loops.
                  */
                 uint32_t entry = targetOffset;
                 if (entry) {
                     do {
                         entry--;
                     } while (!maybeCode(entry));
 
-                    jsbytecode *entrypc = script->code + entry;
+                    jsbytecode *entrypc = script_->code + entry;
 
                     if (JSOp(*entrypc) == JSOP_GOTO || JSOp(*entrypc) == JSOP_FILTER)
                         loop->entry = entry + GET_JUMP_OFFSET(entrypc);
                     else
                         loop->entry = targetOffset;
                 } else {
                     /* Do-while loop at the start of the script. */
                     loop->entry = targetOffset;
                 }
-                JS_ASSERT(script->code[loop->entry] == JSOP_LOOPHEAD ||
-                          script->code[loop->entry] == JSOP_LOOPENTRY);
+                JS_ASSERT(script_->code[loop->entry] == JSOP_LOOPHEAD ||
+                          script_->code[loop->entry] == JSOP_LOOPENTRY);
             } else {
                 for (unsigned i = 0; i < savedCount; i++) {
                     LifetimeVariable &var = *saved[i];
                     JS_ASSERT(!var.lifetime && var.saved);
                     if (var.live(targetOffset)) {
                         /*
                          * Jumping to a place where this variable is live. Make a new
                          * lifetime segment for the variable.
@@ -1181,17 +1181,17 @@ ScriptAnalysis::ensureVariable(LifetimeV
 void
 ScriptAnalysis::clearAllocations()
 {
     /*
      * Clear out storage used for register allocations in a compilation once
      * that compilation has finished. Register allocations are only used for
      * a single compilation.
      */
-    for (unsigned i = 0; i < script->length; i++) {
+    for (unsigned i = 0; i < script_->length; i++) {
         Bytecode *code = maybeCode(i);
         if (code)
             code->allocation = NULL;
     }
 }
 
 /////////////////////////////////////////////////////////////////////
 // SSA Analysis
@@ -1204,17 +1204,17 @@ ScriptAnalysis::analyzeSSA(JSContext *cx
 
     if (!ranLifetimes()) {
         analyzeLifetimes(cx);
         if (failed())
             return;
     }
 
     LifoAlloc &alloc = cx->analysisLifoAlloc();
-    unsigned maxDepth = script->nslots - script->nfixed;
+    unsigned maxDepth = script_->nslots - script_->nfixed;
 
     /*
      * Current value of each variable and stack value. Empty for missing or
      * untracked entries, i.e. escaping locals and arguments.
      */
     SSAValueInfo *values = cx->pod_calloc<SSAValueInfo>(numSlots + maxDepth);
     if (!values) {
         setOOM(cx);
@@ -1246,18 +1246,18 @@ ScriptAnalysis::analyzeSSA(JSContext *cx
     /*
      * Subset of branchTargets which are exception handlers at future offsets.
      * Any new value of a variable modified before the target is reached is a
      * potential value at that target, along with the lazy original value.
      */
     Vector<uint32_t> exceptionTargets(cx);
 
     uint32_t offset = 0;
-    while (offset < script->length) {
-        jsbytecode *pc = script->code + offset;
+    while (offset < script_->length) {
+        jsbytecode *pc = script_->code + offset;
         JSOp op = (JSOp)*pc;
 
         uint32_t successorOffset = offset + GetBytecodeLength(pc);
 
         Bytecode *code = maybeCode(pc);
         if (!code) {
             offset = successorOffset;
             continue;
@@ -1379,18 +1379,18 @@ ScriptAnalysis::analyzeSSA(JSContext *cx
             freezeNewValues(cx, offset);
         }
 
         if (js_CodeSpec[op].format & JOF_DECOMPOSE) {
             offset = successorOffset;
             continue;
         }
 
-        unsigned nuses = GetUseCount(script, offset);
-        unsigned ndefs = GetDefCount(script, offset);
+        unsigned nuses = GetUseCount(script_, offset);
+        unsigned ndefs = GetDefCount(script_, offset);
         JS_ASSERT(stackDepth >= nuses);
 
         unsigned xuses = ExtendedUse(pc) ? nuses + 1 : nuses;
 
         if (xuses) {
             code->poppedValues = alloc.newArray<SSAValue>(xuses);
             if (!code->poppedValues) {
                 setOOM(cx);
@@ -1401,17 +1401,17 @@ ScriptAnalysis::analyzeSSA(JSContext *cx
                 code->poppedValues[i] = v;
                 v.clear();
             }
             if (xuses > nuses) {
                 /*
                  * For SETLOCAL, INCLOCAL, etc. opcodes, add an extra popped
                  * value holding the value of the local before the op.
                  */
-                uint32_t slot = GetBytecodeSlot(script, pc);
+                uint32_t slot = GetBytecodeSlot(script_, pc);
                 if (trackSlot(slot))
                     code->poppedValues[nuses] = values[slot].v;
                 else
                     code->poppedValues[nuses].clear();
             }
 
             if (xuses) {
                 SSAUseChain *useChains = alloc.newArray<SSAUseChain>(xuses);
@@ -1447,28 +1447,28 @@ ScriptAnalysis::analyzeSSA(JSContext *cx
                 return;
             }
             PodZero(code->pushedUses, xdefs);
         }
 
         stackDepth += ndefs;
 
         if (BytecodeUpdatesSlot(op)) {
-            uint32_t slot = GetBytecodeSlot(script, pc);
+            uint32_t slot = GetBytecodeSlot(script_, pc);
             if (trackSlot(slot)) {
                 mergeBranchTarget(cx, values[slot], slot, branchTargets, offset);
                 mergeExceptionTarget(cx, values[slot].v, slot, exceptionTargets);
                 values[slot].v.initWritten(slot, offset);
             }
         }
 
         switch (op) {
           case JSOP_GETARG:
           case JSOP_GETLOCAL: {
-            uint32_t slot = GetBytecodeSlot(script, pc);
+            uint32_t slot = GetBytecodeSlot(script_, pc);
             if (trackSlot(slot)) {
                 /*
                  * Propagate the current value of the local to the pushed value,
                  * and remember it with an extended use on the opcode.
                  */
                 stack[stackDepth - 1].v = code->poppedValues[0] = values[slot].v;
             }
             break;
@@ -1550,20 +1550,20 @@ ScriptAnalysis::analyzeSSA(JSContext *cx
                 npairs--;
             }
 
             checkBranchTarget(cx, defaultOffset, branchTargets, values, stackDepth);
             break;
           }
 
           case JSOP_TRY: {
-            JSTryNote *tn = script->trynotes()->vector;
-            JSTryNote *tnlimit = tn + script->trynotes()->length;
+            JSTryNote *tn = script_->trynotes()->vector;
+            JSTryNote *tnlimit = tn + script_->trynotes()->length;
             for (; tn < tnlimit; tn++) {
-                unsigned startOffset = script->mainOffset + tn->start;
+                unsigned startOffset = script_->mainOffset + tn->start;
                 if (startOffset == offset + 1) {
                     unsigned catchOffset = startOffset + tn->length;
 
                     if (tn->kind != JSTRY_ITER) {
                         checkBranchTarget(cx, catchOffset, branchTargets, values, stackDepth);
                         checkExceptionTarget(cx, catchOffset, exceptionTargets);
                     }
                 }
@@ -1577,17 +1577,17 @@ ScriptAnalysis::analyzeSSA(JSContext *cx
           case JSOP_RETRVAL:
             mergeAllExceptionTargets(cx, values, exceptionTargets);
             break;
 
           default:;
         }
 
         if (IsJumpOpcode(op)) {
-            unsigned targetOffset = FollowBranch(cx, script, offset);
+            unsigned targetOffset = FollowBranch(cx, script_, offset);
             checkBranchTarget(cx, targetOffset, branchTargets, values, stackDepth);
 
             /*
              * If this is a back edge, we're done with the loop and can freeze
              * the phi values at the head now.
              */
             if (targetOffset < offset)
                 freezeNewValues(cx, targetOffset);
@@ -1597,18 +1597,18 @@ ScriptAnalysis::analyzeSSA(JSContext *cx
     }
 
     ranSSA_ = true;
 
     /*
      * Now that we have full SSA information for the script, analyze whether
      * we can avoid creating the arguments object.
      */
-    if (!script->analyzedArgsUsage())
-        script->setNeedsArgsObj(needsArgsObj(cx));
+    if (!script_->analyzedArgsUsage())
+        script_->setNeedsArgsObj(needsArgsObj(cx));
 }
 
 /* Get a phi node's capacity for a given length. */
 static inline unsigned
 PhiNodeCapacity(unsigned length)
 {
     if (length <= 4)
         return 4;
@@ -1750,17 +1750,17 @@ ScriptAnalysis::checkBranchTarget(JSCont
 
     /*
      * Make sure there is a pending entry for each value on the stack.
      * The number of stack entries at join points is usually zero, and
      * we don't want to look at the active branches while popping and
      * pushing values in each opcode.
      */
     for (unsigned i = 0; i < targetDepth; i++) {
-        uint32_t slot = StackSlot(script, i);
+        uint32_t slot = StackSlot(script_, i);
         checkPendingValue(cx, values[slot].v, slot, pending);
     }
 }
 
 void
 ScriptAnalysis::checkExceptionTarget(JSContext *cx, uint32_t catchOffset,
                                      Vector<uint32_t> &exceptionTargets)
 {
@@ -1917,17 +1917,17 @@ ScriptAnalysis::needsArgsObj(JSContext *
 }
 
 bool
 ScriptAnalysis::needsArgsObj(JSContext *cx, SeenVector &seen, SSAUseChain *use)
 {
     if (!use->popped)
         return needsArgsObj(cx, seen, SSAValue::PhiValue(use->offset, use->u.phi));
 
-    jsbytecode *pc = script->code + use->offset;
+    jsbytecode *pc = script_->code + use->offset;
     JSOp op = JSOp(*pc);
 
     if (op == JSOP_POP || op == JSOP_POPN)
         return false;
 
     /* SplatApplyArgs can read fp->canonicalActualArg(i) directly. */
     if (op == JSOP_FUNAPPLY && GET_ARGC(pc) == 2 && use->u.which == 0) {
 #ifdef JS_METHODJIT
@@ -1942,46 +1942,46 @@ ScriptAnalysis::needsArgsObj(JSContext *
 
     /* arguments.length length can read fp->numActualArgs() directly. */
     if (op == JSOP_LENGTH)
         return false;
 
     /* Allow assignments to non-closed locals (but not arguments). */
 
     if (op == JSOP_SETLOCAL) {
-        uint32_t slot = GetBytecodeSlot(script, pc);
+        uint32_t slot = GetBytecodeSlot(script_, pc);
         if (!trackSlot(slot))
             return true;
         return needsArgsObj(cx, seen, SSAValue::PushedValue(use->offset, 0)) ||
                needsArgsObj(cx, seen, SSAValue::WrittenVar(slot, use->offset));
     }
 
     if (op == JSOP_GETLOCAL)
         return needsArgsObj(cx, seen, SSAValue::PushedValue(use->offset, 0));
 
     return true;
 }
 
 bool
 ScriptAnalysis::needsArgsObj(JSContext *cx)
 {
-    JS_ASSERT(script->argumentsHasVarBinding());
+    JS_ASSERT(script_->argumentsHasVarBinding());
 
     /*
      * Since let variables and dynamic name access are not tracked, we cannot
      * soundly perform this analysis in their presence. Generators can be
      * suspended when the speculation fails, so disallow it also.
      */
-    if (script->bindingsAccessedDynamically || script->funHasAnyAliasedFormal ||
-        localsAliasStack() || cx->compartment->debugMode() || script->isGenerator)
+    if (script_->bindingsAccessedDynamically || script_->funHasAnyAliasedFormal ||
+        localsAliasStack() || cx->compartment->debugMode() || script_->isGenerator)
     {
         return true;
     }
 
-    unsigned pcOff = script->argumentsBytecode() - script->code;
+    unsigned pcOff = script_->argumentsBytecode() - script_->code;
 
     SeenVector seen(cx);
     return needsArgsObj(cx, seen, SSAValue::PushedValue(pcOff, 0));
 }
 
 CrossSSAValue
 CrossScriptSSA::foldValue(const CrossSSAValue &cv)
 {
@@ -2068,24 +2068,24 @@ CrossScriptSSA::foldValue(const CrossSSA
 
 void
 ScriptAnalysis::printSSA(JSContext *cx)
 {
     AutoEnterAnalysis enter(cx);
 
     printf("\n");
 
-    for (unsigned offset = 0; offset < script->length; offset++) {
+    for (unsigned offset = 0; offset < script_->length; offset++) {
         Bytecode *code = maybeCode(offset);
         if (!code)
             continue;
 
-        jsbytecode *pc = script->code + offset;
+        jsbytecode *pc = script_->code + offset;
 
-        PrintBytecode(cx, script, pc);
+        PrintBytecode(cx, script_, pc);
 
         SlotValue *newv = code->newValues;
         if (newv) {
             while (newv->slot) {
                 if (newv->value.kind() != SSAValue::PHI || newv->value.phiOffset() != offset) {
                     newv++;
                     continue;
                 }
@@ -2097,17 +2097,17 @@ ScriptAnalysis::printSSA(JSContext *cx)
                         printf(",");
                     newv->value.phiValue(i).print();
                 }
                 printf("]\n");
                 newv++;
             }
         }
 
-        unsigned nuses = GetUseCount(script, offset);
+        unsigned nuses = GetUseCount(script_, offset);
         unsigned xuses = ExtendedUse(pc) ? nuses + 1 : nuses;
 
         for (unsigned i = 0; i < xuses; i++) {
             printf("  popped%d: ", i);
             code->poppedValues[i].print();
             printf("\n");
         }
     }
@@ -2142,15 +2142,15 @@ SSAValue::print() const
       default:
         JS_NOT_REACHED("Bad kind");
     }
 }
 
 void
 ScriptAnalysis::assertMatchingDebugMode()
 {
-    JS_ASSERT(!!script->compartment()->debugMode() == !!originalDebugMode_);
+    JS_ASSERT(!!script_->compartment()->debugMode() == !!originalDebugMode_);
 }
 
 #endif  /* DEBUG */
 
 } /* namespace analyze */
 } /* namespace js */
--- a/js/src/jsanalyze.h
+++ b/js/src/jsanalyze.h
@@ -834,17 +834,17 @@ class SlotValue
 
 struct NeedsArgsObjState;
 
 /* Analysis information about a script. */
 class ScriptAnalysis
 {
     friend class Bytecode;
 
-    JSScript *script;
+    JSScript *script_;
 
     Bytecode **codeArray;
 
     uint32_t numSlots;
     uint32_t numPropertyReads_;
 
     bool outOfMemory;
     bool hadFailure;
@@ -880,19 +880,19 @@ class ScriptAnalysis
     /* --------- Lifetime analysis --------- */
 
     LifetimeVariable *lifetimes;
 
   public:
 
     ScriptAnalysis(JSScript *script) {
         PodZero(this);
-        this->script = script;
+        this->script_ = script;
 #ifdef DEBUG
-        this->originalDebugMode_ = script->compartment()->debugMode();
+        this->originalDebugMode_ = script_->compartment()->debugMode();
 #endif
     }
 
     bool ranBytecode() { return ranBytecode_; }
     bool ranSSA() { return ranSSA_; }
     bool ranLifetimes() { return ranLifetimes_; }
     bool ranInference() { return ranInference_; }
 
@@ -902,17 +902,17 @@ class ScriptAnalysis
     void analyzeTypes(JSContext *cx);
 
     /* Analyze the effect of invoking 'new' on script. */
     void analyzeTypesNew(JSContext *cx);
 
     bool OOM() const { return outOfMemory; }
     bool failed() const { return hadFailure; }
     bool inlineable() const { return isInlineable; }
-    bool inlineable(uint32_t argc) const { return isInlineable && argc == script->function()->nargs; }
+    bool inlineable(uint32_t argc) const { return isInlineable && argc == script_->function()->nargs; }
     bool jaegerCompileable() { return isJaegerCompileable; }
 
     /* Number of property read opcodes in the script. */
     uint32_t numPropertyReads() const { return numPropertyReads_; }
 
     /* Whether there are POPV/SETRVAL bytecodes which can write to the frame's rval. */
     bool usesReturnValue() const { return usesReturnValue_; }
 
@@ -928,40 +928,40 @@ class ScriptAnalysis
     /*
      * True if all named formal arguments are not modified. If the arguments
      * object cannot escape, the arguments are never modified within the script.
      */
     bool modifiesArguments() { return modifiesArguments_; }
 
     /*
      * True if there are any LOCAL opcodes aliasing values on the stack (above
-     * script->nfixed).
+     * script_->nfixed).
      */
     bool localsAliasStack() { return localsAliasStack_; }
 
     /* Accessors for bytecode information. */
 
     Bytecode& getCode(uint32_t offset) {
-        JS_ASSERT(offset < script->length);
+        JS_ASSERT(offset < script_->length);
         JS_ASSERT(codeArray[offset]);
         return *codeArray[offset];
     }
-    Bytecode& getCode(const jsbytecode *pc) { return getCode(pc - script->code); }
+    Bytecode& getCode(const jsbytecode *pc) { return getCode(pc - script_->code); }
 
     Bytecode* maybeCode(uint32_t offset) {
-        JS_ASSERT(offset < script->length);
+        JS_ASSERT(offset < script_->length);
         return codeArray[offset];
     }
-    Bytecode* maybeCode(const jsbytecode *pc) { return maybeCode(pc - script->code); }
+    Bytecode* maybeCode(const jsbytecode *pc) { return maybeCode(pc - script_->code); }
 
     bool jumpTarget(uint32_t offset) {
-        JS_ASSERT(offset < script->length);
+        JS_ASSERT(offset < script_->length);
         return codeArray[offset] && codeArray[offset]->jumpTarget;
     }
-    bool jumpTarget(const jsbytecode *pc) { return jumpTarget(pc - script->code); }
+    bool jumpTarget(const jsbytecode *pc) { return jumpTarget(pc - script_->code); }
 
     bool popGuaranteed(jsbytecode *pc) {
         jsbytecode *next = pc + GetBytecodeLength(pc);
         return JSOp(*next) == JSOP_POP && !jumpTarget(next);
     }
 
     bool incrementInitialValueObserved(jsbytecode *pc) {
         const JSCodeSpec *cs = &js_CodeSpec[*pc];
@@ -969,52 +969,52 @@ class ScriptAnalysis
     }
 
     types::StackTypeSet *bytecodeTypes(const jsbytecode *pc) {
         JS_ASSERT(js_CodeSpec[*pc].format & JOF_TYPESET);
         return getCode(pc).observedTypes;
     }
 
     const SSAValue &poppedValue(uint32_t offset, uint32_t which) {
-        JS_ASSERT(offset < script->length);
-        JS_ASSERT(which < GetUseCount(script, offset) +
-                  (ExtendedUse(script->code + offset) ? 1 : 0));
+        JS_ASSERT(offset < script_->length);
+        JS_ASSERT(which < GetUseCount(script_, offset) +
+                  (ExtendedUse(script_->code + offset) ? 1 : 0));
         return getCode(offset).poppedValues[which];
     }
     const SSAValue &poppedValue(const jsbytecode *pc, uint32_t which) {
-        return poppedValue(pc - script->code, which);
+        return poppedValue(pc - script_->code, which);
     }
 
     const SlotValue *newValues(uint32_t offset) {
-        JS_ASSERT(offset < script->length);
+        JS_ASSERT(offset < script_->length);
         return getCode(offset).newValues;
     }
-    const SlotValue *newValues(const jsbytecode *pc) { return newValues(pc - script->code); }
+    const SlotValue *newValues(const jsbytecode *pc) { return newValues(pc - script_->code); }
 
     types::StackTypeSet *pushedTypes(uint32_t offset, uint32_t which = 0) {
-        JS_ASSERT(offset < script->length);
-        JS_ASSERT(which < GetDefCount(script, offset) +
-                  (ExtendedDef(script->code + offset) ? 1 : 0));
+        JS_ASSERT(offset < script_->length);
+        JS_ASSERT(which < GetDefCount(script_, offset) +
+                  (ExtendedDef(script_->code + offset) ? 1 : 0));
         types::StackTypeSet *array = getCode(offset).pushedTypes;
         JS_ASSERT(array);
         return array + which;
     }
     types::StackTypeSet *pushedTypes(const jsbytecode *pc, uint32_t which) {
-        return pushedTypes(pc - script->code, which);
+        return pushedTypes(pc - script_->code, which);
     }
 
     bool hasPushedTypes(const jsbytecode *pc) { return getCode(pc).pushedTypes != NULL; }
 
     types::TypeBarrier *typeBarriers(JSContext *cx, uint32_t offset) {
         if (getCode(offset).typeBarriers)
             pruneTypeBarriers(cx, offset);
         return getCode(offset).typeBarriers;
     }
     types::TypeBarrier *typeBarriers(JSContext *cx, const jsbytecode *pc) {
-        return typeBarriers(cx, pc - script->code);
+        return typeBarriers(cx, pc - script_->code);
     }
     void addTypeBarrier(JSContext *cx, const jsbytecode *pc,
                         types::TypeSet *target, types::Type type);
     void addSingletonTypeBarrier(JSContext *cx, const jsbytecode *pc,
                                  types::TypeSet *target, HandleObject singleton, jsid singletonId);
 
     /* Remove obsolete type barriers at the given offset. */
     void pruneTypeBarriers(JSContext *cx, uint32_t offset);
@@ -1033,17 +1033,17 @@ class ScriptAnalysis
 
     types::StackTypeSet *getValueTypes(const SSAValue &v) {
         switch (v.kind()) {
           case SSAValue::PUSHED:
             return pushedTypes(v.pushedOffset(), v.pushedIndex());
           case SSAValue::VAR:
             JS_ASSERT(!slotEscapes(v.varSlot()));
             if (v.varInitial()) {
-                return types::TypeScript::SlotTypes(script, v.varSlot());
+                return types::TypeScript::SlotTypes(script_, v.varSlot());
             } else {
                 /*
                  * Results of intermediate assignments have the same type as
                  * the first type pushed by the assignment op. Note that this
                  * may not be the exact same value as was pushed, due to
                  * post-inc/dec ops.
                  */
                 return pushedTypes(v.varOffset(), 0);
@@ -1077,69 +1077,69 @@ class ScriptAnalysis
      * Get the use chain for an SSA value. May be invalid for some opcodes in
      * scripts where localsAliasStack(). You have been warned!
      */
     SSAUseChain *& useChain(const SSAValue &v) {
         JS_ASSERT(trackUseChain(v));
         if (v.kind() == SSAValue::PUSHED)
             return getCode(v.pushedOffset()).pushedUses[v.pushedIndex()];
         if (v.kind() == SSAValue::VAR)
-            return getCode(v.varOffset()).pushedUses[GetDefCount(script, v.varOffset())];
+            return getCode(v.varOffset()).pushedUses[GetDefCount(script_, v.varOffset())];
         return v.phiNode()->uses;
     }
 
     mjit::RegisterAllocation *&getAllocation(uint32_t offset) {
-        JS_ASSERT(offset < script->length);
+        JS_ASSERT(offset < script_->length);
         return getCode(offset).allocation;
     }
     mjit::RegisterAllocation *&getAllocation(const jsbytecode *pc) {
-        return getAllocation(pc - script->code);
+        return getAllocation(pc - script_->code);
     }
 
     LoopAnalysis *getLoop(uint32_t offset) {
-        JS_ASSERT(offset < script->length);
+        JS_ASSERT(offset < script_->length);
         return getCode(offset).loop;
     }
-    LoopAnalysis *getLoop(const jsbytecode *pc) { return getLoop(pc - script->code); }
+    LoopAnalysis *getLoop(const jsbytecode *pc) { return getLoop(pc - script_->code); }
 
     /* For a JSOP_CALL* op, get the pc of the corresponding JSOP_CALL/NEW/etc. */
     jsbytecode *getCallPC(jsbytecode *pc)
     {
-        SSAUseChain *uses = useChain(SSAValue::PushedValue(pc - script->code, 0));
+        SSAUseChain *uses = useChain(SSAValue::PushedValue(pc - script_->code, 0));
         JS_ASSERT(uses && uses->popped);
-        JS_ASSERT(js_CodeSpec[script->code[uses->offset]].format & JOF_INVOKE);
-        return script->code + uses->offset;
+        JS_ASSERT(js_CodeSpec[script_->code[uses->offset]].format & JOF_INVOKE);
+        return script_->code + uses->offset;
     }
 
     /* Accessors for local variable information. */
 
     /*
      * Escaping slots include all slots that can be accessed in ways other than
      * through the corresponding LOCAL/ARG opcode. This includes all closed
      * slots in the script, all slots in scripts which use eval or are in debug
      * mode, and slots which are aliased by NAME or similar opcodes in the
      * containing script (which does not imply the variable is closed).
      */
     bool slotEscapes(uint32_t slot) {
-        JS_ASSERT(script->compartment()->activeAnalysis);
+        JS_ASSERT(script_->compartment()->activeAnalysis);
         if (slot >= numSlots)
             return true;
         return escapedSlots[slot];
     }
 
     /*
      * Whether we distinguish different writes of this variable while doing
      * SSA analysis. Escaping locals can be written in other scripts, and the
      * presence of NAME opcodes which could alias local variables or arguments
      * keeps us from tracking variable values at each point.
      */
     bool trackSlot(uint32_t slot) { return !slotEscapes(slot) && canTrackVars && slot < 1000; }
 
     const LifetimeVariable & liveness(uint32_t slot) {
-        JS_ASSERT(script->compartment()->activeAnalysis);
+        JS_ASSERT(script_->compartment()->activeAnalysis);
         JS_ASSERT(!slotEscapes(slot));
         return lifetimes[slot];
     }
 
     void printSSA(JSContext *cx);
     void printTypes(JSContext *cx);
 
     void clearAllocations();
--- a/js/src/jscompartment.cpp
+++ b/js/src/jscompartment.cpp
@@ -575,17 +575,17 @@ JSCompartment::sweep(FreeOp *fop, bool r
          * Sweep analysis information and everything depending on it from the
          * compartment, including all remaining mjit code if inference is
          * enabled in the compartment.
          */
         if (types.inferenceEnabled) {
             gcstats::AutoPhase ap2(rt->gcStats, gcstats::PHASE_DISCARD_TI);
 
             for (CellIterUnderGC i(this, FINALIZE_SCRIPT); !i.done(); i.next()) {
-                JSScript *script = i.get<JSScript>();
+                RawScript script = i.get<JSScript>();
                 if (script->types) {
                     types::TypeScript::Sweep(fop, script);
 
                     if (releaseTypes) {
                         script->types->destroy();
                         script->types = NULL;
                     }
                 }
--- a/js/src/jsgc.cpp
+++ b/js/src/jsgc.cpp
@@ -954,54 +954,57 @@ InFreeList(ArenaHeader *aheader, uintptr
          * The last possible empty span is an the end of the arena. Here
          * span->end < thing < thingsEnd and so we must have more spans.
          */
         span = span->nextSpan();
     }
 }
 
 #ifdef JSGC_USE_EXACT_ROOTING
+static inline void
+MarkExactStackRooter(JSTracer *trc, Rooted<void*> rooter, ThingRootKind kind)
+{
+    void **addr = (void **)rooter->address();
+    if (!*addr)
+        return;
+
+    switch (kind) {
+      case THING_ROOT_OBJECT:      MarkObjectRoot(trc, (JSObject **)addr, "exact-object"); break;
+      case THING_ROOT_STRING:      MarkStringRoot(trc, (JSSTring **)addr, "exact-string"); break;
+      case THING_ROOT_SCRIPT:      MarkScriptRoot(trc, (JSScript **)addr, "exact-script"); break;
+      case THING_ROOT_SHAPE:       MarkShapeRoot(trc, (Shape **)addr, "exact-shape"); break;
+      case THING_ROOT_BASE_SHAPE:  MarkBaseShapeRoot(trc, (BaseShape **)addr, "exact-baseshape"); break;
+      case THING_ROOT_TYPE:        MarkTypeRoot(trc, (types::Type *)addr, "exact-type"); break;
+      case THING_ROOT_TYPE_OBJECT: MarkTypeObjectRoot(trc, (types::TypeObject **)addr, "exact-typeobject"); break;
+      case THING_ROOT_VALUE:       MarkValueRoot(trc, (Value *)addr, "exact-value"); break;
+      case THING_ROOT_ID:          MarkIdRoot(trc, (jsid *)addr, "exact-id"); break;
+      case THING_ROOT_PROPERTY_ID: MarkIdRoot(trc, &((js::PropertyId *)addr)->asId(), "exact-propertyid"); break;
+      case THING_ROOT_BINDINGS:    ((Bindings *)addr)->trace(trc); break;
+      default: JS_NOT_REACHED("Invalid THING_ROOT kind"); break;
+    }
+}
+
+static inline void
+MarkExactStackRooters(JSTracer *trc, Rooted<void*> rooter, ThingRootKind kind)
+{
+    Rooted<void*> *rooter = cx->thingGCRooters[i];
+    while (rooter) {
+        MarkExactStackRoot(trc, rooter, ThingRootKind(i));
+        rooter = rooter->previous();
+    }
+}
+
 static void
 MarkExactStackRoots(JSTracer *trc)
 {
-    for (ContextIter cx(trc->runtime); !cx.done(); cx.next()) {
-        for (unsigned i = 0; i < THING_ROOT_LIMIT; i++) {
-            Rooted<void*> *rooter = cx->thingGCRooters[i];
-            while (rooter) {
-                void **addr = (void **)rooter->address();
-                if (*addr) {
-                    if (i == THING_ROOT_OBJECT) {
-                        MarkObjectRoot(trc, (JSObject **)addr, "exact stackroot object");
-                    } else if (i == THING_ROOT_STRING) {
-                        MarkStringRoot(trc, (JSString **)addr, "exact stackroot string");
-                    } else if (i == THING_ROOT_ID) {
-                        MarkIdRoot(trc, (jsid *)addr, "exact stackroot id");
-                    } else if (i == THING_ROOT_PROPERTY_ID) {
-                        MarkIdRoot(trc, &((PropertyId *)addr)->asId(), "exact stackroot property id");
-                    } else if (i == THING_ROOT_VALUE) {
-                        MarkValueRoot(trc, (Value *)addr, "exact stackroot value");
-                    } else if (i == THING_ROOT_TYPE) {
-                        MarkTypeRoot(trc, (types::Type *)addr, "exact stackroot type");
-                    } else if (i == THING_ROOT_SHAPE) {
-                        MarkShapeRoot(trc, (Shape **)addr, "exact stackroot shape");
-                    } else if (i == THING_ROOT_BASE_SHAPE) {
-                        MarkBaseShapeRoot(trc, (BaseShape **)addr, "exact stackroot baseshape");
-                    } else if (i == THING_ROOT_TYPE_OBJECT) {
-                        MarkTypeObjectRoot(trc, (types::TypeObject **)addr, "exact stackroot typeobject");
-                    } else if (i == THING_ROOT_SCRIPT) {
-                        MarkScriptRoot(trc, (JSScript **)addr, "exact stackroot script");
-                    } else if (i == THING_ROOT_XML) {
-                        MarkXMLRoot(trc, (JSXML **)addr, "exact stackroot xml");
-                    } else {
-                        JS_NOT_REACHED("Invalid thing root kind.");
-                    }
-                }
-                rooter = rooter->previous();
-            }
+    for (unsigned i = 0; i < THING_ROOT_LIMIT; i++) {
+        for (ContextIter cx(trc->runtime); !cx.done(); cx.next()) {
+            MarkExactStackRooters(trc, cx->thingGCRooters[i], ThingRootKind(i));
         }
+        MarkExactStackRooters(trc, rt->thingGCRooters[i], ThingRootKind(i));
     }
 }
 #endif /* JSGC_USE_EXACT_ROOTING */
 
 enum ConservativeGCTest
 {
     CGCT_VALID,
     CGCT_LOWBITSET, /* excluded because one of the low bits was set */
@@ -4965,21 +4968,31 @@ SetValidateGC(JSContext *cx, bool enable
     rt->gcValidate = enabled;
 }
 
 } /* namespace gc */
 } /* namespace js */
 
 #if defined(DEBUG) && defined(JS_GC_ZEAL) && defined(JSGC_ROOT_ANALYSIS) && !defined(JS_THREADSAFE)
 
+JS_ALWAYS_INLINE bool
+CheckStackRootThing(uintptr_t *w, void *address, ThingRootKind kind)
+{
+    if (kind != THING_ROOT_BINDINGS)
+        return address == static_cast<void*>(w);
+
+    Bindings *bp = static_cast<Bindings*>(address);
+    return w >= (uintptr_t*)bp && w < (uintptr_t*)(bp + 1);
+}
+
 JS_ALWAYS_INLINE void
-CheckStackRootThings(uintptr_t *w, Rooted<void*> *rooter, bool *matched)
+CheckStackRootThings(uintptr_t *w, Rooted<void*> *rooter, ThingRootKind kind, bool *matched)
 {
     while (rooter) {
-        if (rooter->address() == static_cast<void*>(w))
+        if (CheckStackRootThing(w, rooter->address(), kind))
             *matched = true;
         rooter = rooter->previous();
     }
 }
 
 static void
 CheckStackRoot(JSTracer *trc, uintptr_t *w)
 {
@@ -4989,19 +5002,19 @@ CheckStackRoot(JSTracer *trc, uintptr_t 
 #endif
 
     ConservativeGCTest test = MarkIfGCThingWord(trc, *w);
 
     if (test == CGCT_VALID) {
         bool matched = false;
         JSRuntime *rt = trc->runtime;
         for (unsigned i = 0; i < THING_ROOT_LIMIT; i++) {
-            CheckStackRootThings(w, rt->thingGCRooters[i], &matched);
+            CheckStackRootThings(w, rt->thingGCRooters[i], ThingRootKind(i), &matched);
             for (ContextIter cx(rt); !cx.done(); cx.next()) {
-                CheckStackRootThings(w, cx->thingGCRooters[i], &matched);
+                CheckStackRootThings(w, cx->thingGCRooters[i], ThingRootKind(i), &matched);
                 SkipRoot *skip = cx->skipGCRooters;
                 while (skip) {
                     if (skip->contains(reinterpret_cast<uint8_t*>(w), sizeof(w)))
                         matched = true;
                     skip = skip->previous();
                 }
             }
         }
--- a/js/src/jsinfer.cpp
+++ b/js/src/jsinfer.cpp
@@ -471,17 +471,17 @@ StackTypeSet::make(JSContext *cx, const 
 
 /////////////////////////////////////////////////////////////////////
 // TypeSet constraints
 /////////////////////////////////////////////////////////////////////
 
 /* Standard subset constraint, propagate all types from one set to another. */
 class TypeConstraintSubset : public TypeConstraint
 {
-public:
+  public:
     TypeSet *target;
 
     TypeConstraintSubset(TypeSet *target)
         : target(target)
     {
         JS_ASSERT(target);
     }
 
@@ -512,105 +512,107 @@ enum PropertyAccessKind {
     PROPERTY_READ,
     PROPERTY_READ_EXISTING
 };
 
 /* Constraints for reads/writes on object properties. */
 template <PropertyAccessKind access>
 class TypeConstraintProp : public TypeConstraint
 {
-public:
-    JSScript *script;
+    JSScript *script_;
+
+  public:
     jsbytecode *pc;
 
     /*
      * If assign is true, the target is used to update a property of the object.
      * If assign is false, the target is assigned the value of the property.
      */
     StackTypeSet *target;
 
     /* Property being accessed. */
     jsid id;
 
     TypeConstraintProp(JSScript *script, jsbytecode *pc, StackTypeSet *target, jsid id)
-        : script(script), pc(pc), target(target), id(id)
+        : script_(script), pc(pc), target(target), id(id)
     {
         JS_ASSERT(script && pc && target);
     }
 
     const char *kind() { return "prop"; }
 
     void newType(JSContext *cx, TypeSet *source, Type type);
 };
 
 typedef TypeConstraintProp<PROPERTY_WRITE> TypeConstraintSetProperty;
 typedef TypeConstraintProp<PROPERTY_READ>  TypeConstraintGetProperty;
 typedef TypeConstraintProp<PROPERTY_READ_EXISTING> TypeConstraintGetPropertyExisting;
 
 void
-StackTypeSet::addGetProperty(JSContext *cx, JSScript *script, jsbytecode *pc,
+StackTypeSet::addGetProperty(JSContext *cx, HandleScript script, jsbytecode *pc,
                              StackTypeSet *target, jsid id)
 {
     /*
      * GetProperty constraints are normally used with property read input type
      * sets, except for array_pop/array_shift special casing.
      */
     JS_ASSERT(js_CodeSpec[*pc].format & JOF_INVOKE);
 
     add(cx, cx->analysisLifoAlloc().new_<TypeConstraintGetProperty>(script, pc, target, id));
 }
 
 void
-StackTypeSet::addSetProperty(JSContext *cx, JSScript *script, jsbytecode *pc,
+StackTypeSet::addSetProperty(JSContext *cx, HandleScript script, jsbytecode *pc,
                              StackTypeSet *target, jsid id)
 {
     add(cx, cx->analysisLifoAlloc().new_<TypeConstraintSetProperty>(script, pc, target, id));
 }
 
 void
-HeapTypeSet::addGetProperty(JSContext *cx, JSScript *script, jsbytecode *pc,
+HeapTypeSet::addGetProperty(JSContext *cx, HandleScript script, jsbytecode *pc,
                             StackTypeSet *target, jsid id)
 {
     JS_ASSERT(!target->purged());
     add(cx, cx->typeLifoAlloc().new_<TypeConstraintGetProperty>(script, pc, target, id));
 }
 
 /*
  * Constraints for updating the 'this' types of callees on CALLPROP/CALLELEM.
  * These are derived from the types on the properties themselves, rather than
  * those pushed in the 'this' slot at the call site, which allows us to retain
  * correlations between the type of the 'this' object and the associated
  * callee scripts at polymorphic call sites.
  */
 template <PropertyAccessKind access>
 class TypeConstraintCallProp : public TypeConstraint
 {
-public:
-    JSScript *script;
+    JSScript *script_;
+
+  public:
     jsbytecode *callpc;
 
     /* Property being accessed. */
     jsid id;
 
     TypeConstraintCallProp(JSScript *script, jsbytecode *callpc, jsid id)
-        : script(script), callpc(callpc), id(id)
+        : script_(script), callpc(callpc), id(id)
     {
         JS_ASSERT(script && callpc);
     }
 
     const char *kind() { return "callprop"; }
 
     void newType(JSContext *cx, TypeSet *source, Type type);
 };
 
 typedef TypeConstraintCallProp<PROPERTY_READ> TypeConstraintCallProperty;
 typedef TypeConstraintCallProp<PROPERTY_READ_EXISTING> TypeConstraintCallPropertyExisting;
 
 void
-HeapTypeSet::addCallProperty(JSContext *cx, JSScript *script, jsbytecode *pc, jsid id)
+HeapTypeSet::addCallProperty(JSContext *cx, HandleScript script, jsbytecode *pc, jsid id)
 {
     /*
      * For calls which will go through JSOP_NEW, don't add any constraints to
      * modify the 'this' types of callees. The initial 'this' value will be
      * outright ignored.
      */
     jsbytecode *callpc = script->analysis()->getCallPC(pc);
     if (JSOp(*callpc) == JSOP_NEW)
@@ -622,52 +624,53 @@ HeapTypeSet::addCallProperty(JSContext *
 /*
  * Constraints for generating 'set' property constraints on a SETELEM only if
  * the element type may be a number. For SETELEM we only account for integer
  * indexes, and if the element cannot be an integer (e.g. it must be a string)
  * then we lose precision by treating it like one.
  */
 class TypeConstraintSetElement : public TypeConstraint
 {
-public:
-    JSScript *script;
+    JSScript *script_;
+
+  public:
     jsbytecode *pc;
 
     StackTypeSet *objectTypes;
     StackTypeSet *valueTypes;
 
     TypeConstraintSetElement(JSScript *script, jsbytecode *pc,
                              StackTypeSet *objectTypes, StackTypeSet *valueTypes)
-        : script(script), pc(pc),
+        : script_(script), pc(pc),
           objectTypes(objectTypes), valueTypes(valueTypes)
     {
         JS_ASSERT(script && pc);
     }
 
     const char *kind() { return "setelement"; }
 
     void newType(JSContext *cx, TypeSet *source, Type type);
 };
 
 void
-StackTypeSet::addSetElement(JSContext *cx, JSScript *script, jsbytecode *pc,
+StackTypeSet::addSetElement(JSContext *cx, HandleScript script, jsbytecode *pc,
                             StackTypeSet *objectTypes, StackTypeSet *valueTypes)
 {
     add(cx, cx->analysisLifoAlloc().new_<TypeConstraintSetElement>(script, pc, objectTypes,
                                                                    valueTypes));
 }
 
 /*
  * Constraints for watching call edges as they are discovered and invoking native
  * function handlers, adding constraints for arguments, receiver objects and the
  * return value, and updating script foundOffsets.
  */
 class TypeConstraintCall : public TypeConstraint
 {
-public:
+  public:
     /* Call site being tracked. */
     TypeCallsite *callsite;
 
     TypeConstraintCall(TypeCallsite *callsite)
         : callsite(callsite)
     {}
 
     const char *kind() { return "call"; }
@@ -679,102 +682,106 @@ void
 StackTypeSet::addCall(JSContext *cx, TypeCallsite *site)
 {
     add(cx, cx->analysisLifoAlloc().new_<TypeConstraintCall>(site));
 }
 
 /* Constraints for arithmetic operations. */
 class TypeConstraintArith : public TypeConstraint
 {
-public:
-    JSScript *script;
+    JSScript *script_;
+
+  public:
     jsbytecode *pc;
 
     /* Type set receiving the result of the arithmetic. */
     TypeSet *target;
 
     /* For addition operations, the other operand. */
     TypeSet *other;
 
     TypeConstraintArith(JSScript *script, jsbytecode *pc, TypeSet *target, TypeSet *other)
-        : script(script), pc(pc), target(target), other(other)
+        : script_(script), pc(pc), target(target), other(other)
     {
         JS_ASSERT(target);
     }
 
     const char *kind() { return "arith"; }
 
     void newType(JSContext *cx, TypeSet *source, Type type);
 };
 
 void
-StackTypeSet::addArith(JSContext *cx, JSScript *script, jsbytecode *pc, TypeSet *target, TypeSet *other)
+StackTypeSet::addArith(JSContext *cx, HandleScript script, jsbytecode *pc, TypeSet *target,
+                       TypeSet *other)
 {
     add(cx, cx->analysisLifoAlloc().new_<TypeConstraintArith>(script, pc, target, other));
 }
 
 /* Subset constraint which transforms primitive values into appropriate objects. */
 class TypeConstraintTransformThis : public TypeConstraint
 {
-public:
-    JSScript *script;
+    JSScript *script_;
+
+  public:
     TypeSet *target;
 
     TypeConstraintTransformThis(JSScript *script, TypeSet *target)
-        : script(script), target(target)
+        : script_(script), target(target)
     {}
 
     const char *kind() { return "transformthis"; }
 
     void newType(JSContext *cx, TypeSet *source, Type type);
 };
 
 void
-StackTypeSet::addTransformThis(JSContext *cx, JSScript *script, TypeSet *target)
+StackTypeSet::addTransformThis(JSContext *cx, HandleScript script, TypeSet *target)
 {
     add(cx, cx->analysisLifoAlloc().new_<TypeConstraintTransformThis>(script, target));
 }
 
 /*
  * Constraint which adds a particular type to the 'this' types of all
  * discovered scripted functions.
  */
 class TypeConstraintPropagateThis : public TypeConstraint
 {
-public:
-    JSScript *script;
+    JSScript *script_;
+
+  public:
     jsbytecode *callpc;
     Type type;
     StackTypeSet *types;
 
     TypeConstraintPropagateThis(JSScript *script, jsbytecode *callpc, Type type, StackTypeSet *types)
-        : script(script), callpc(callpc), type(type), types(types)
+        : script_(script), callpc(callpc), type(type), types(types)
     {}
 
     const char *kind() { return "propagatethis"; }
 
     void newType(JSContext *cx, TypeSet *source, Type type);
 };
 
 void
-StackTypeSet::addPropagateThis(JSContext *cx, JSScript *script, jsbytecode *pc,
+StackTypeSet::addPropagateThis(JSContext *cx, HandleScript script, jsbytecode *pc,
                                Type type, StackTypeSet *types)
 {
     /* Don't add constraints when the call will be 'new' (see addCallProperty). */
     jsbytecode *callpc = script->analysis()->getCallPC(pc);
     if (JSOp(*callpc) == JSOP_NEW)
         return;
 
     add(cx, cx->analysisLifoAlloc().new_<TypeConstraintPropagateThis>(script, callpc, type, types));
 }
 
 /* Subset constraint which filters out primitive types. */
 class TypeConstraintFilterPrimitive : public TypeConstraint
 {
-public:
+  public:
     TypeSet *target;
 
     TypeConstraintFilterPrimitive(TypeSet *target)
         : target(target)
     {}
 
     const char *kind() { return "filter"; }
 
@@ -886,29 +893,29 @@ void ScriptAnalysis::breakTypeBarriers(J
 }
 
 void ScriptAnalysis::breakTypeBarriersSSA(JSContext *cx, const SSAValue &v)
 {
     if (v.kind() != SSAValue::PUSHED)
         return;
 
     uint32_t offset = v.pushedOffset();
-    if (JSOp(script->code[offset]) == JSOP_GETPROP)
+    if (JSOp(script_->code[offset]) == JSOP_GETPROP)
         breakTypeBarriersSSA(cx, poppedValue(offset, 0));
 
     breakTypeBarriers(cx, offset, true);
 }
 
 /*
  * Subset constraint for property reads and argument passing which can add type
  * barriers on the read instead of passing types along.
  */
 class TypeConstraintSubsetBarrier : public TypeConstraint
 {
-public:
+  public:
     JSScript *script;
     jsbytecode *pc;
     TypeSet *target;
 
     TypeConstraintSubsetBarrier(JSScript *script, jsbytecode *pc, TypeSet *target)
         : script(script), pc(pc), target(target)
     {}
 
@@ -920,35 +927,35 @@ public:
             if (!script->ensureRanAnalysis(cx))
                 return;
             script->analysis()->addTypeBarrier(cx, pc, target, type);
         }
     }
 };
 
 void
-StackTypeSet::addSubsetBarrier(JSContext *cx, JSScript *script, jsbytecode *pc, TypeSet *target)
+StackTypeSet::addSubsetBarrier(JSContext *cx, HandleScript script, jsbytecode *pc, TypeSet *target)
 {
     add(cx, cx->analysisLifoAlloc().new_<TypeConstraintSubsetBarrier>(script, pc, target));
 }
 
 void
-HeapTypeSet::addSubsetBarrier(JSContext *cx, JSScript *script, jsbytecode *pc, TypeSet *target)
+HeapTypeSet::addSubsetBarrier(JSContext *cx, HandleScript script, jsbytecode *pc, TypeSet *target)
 {
     JS_ASSERT(!target->purged());
     add(cx, cx->typeLifoAlloc().new_<TypeConstraintSubsetBarrier>(script, pc, target));
 }
 
 /////////////////////////////////////////////////////////////////////
 // TypeConstraint
 /////////////////////////////////////////////////////////////////////
 
 /* Get the object to use for a property access on type. */
 static inline TypeObject *
-GetPropertyObject(JSContext *cx, JSScript *script, Type type)
+GetPropertyObject(JSContext *cx, HandleScript script, Type type)
 {
     if (type.isTypeObject())
         return type.typeObject();
 
     /* Force instantiation of lazy types for singleton objects. */
     if (type.isSingleObject())
         return type.singleObject()->getType(cx);
 
@@ -989,17 +996,17 @@ UsePropertyTypeBarrier(jsbytecode *pc)
      * At call opcodes, type barriers can only be added for the call bindings,
      * which TypeConstraintCall will add barrier constraints for directly.
      */
     uint32_t format = js_CodeSpec[*pc].format;
     return (format & JOF_TYPESET) && !(format & JOF_INVOKE);
 }
 
 static inline void
-MarkPropertyAccessUnknown(JSContext *cx, JSScript *script, jsbytecode *pc, TypeSet *target)
+MarkPropertyAccessUnknown(JSContext *cx, HandleScript script, jsbytecode *pc, TypeSet *target)
 {
     if (UsePropertyTypeBarrier(pc))
         script->analysis()->addTypeBarrier(cx, pc, target, Type::UnknownType());
     else
         target->addType(cx, Type::UnknownType());
 }
 
 /*
@@ -1041,17 +1048,17 @@ GetSingletonPropertyType(JSContext *cx, 
 }
 
 /*
  * Handle a property access on a specific object. All property accesses go through
  * here, whether via x.f, x[f], or global name accesses.
  */
 template <PropertyAccessKind access>
 static inline void
-PropertyAccess(JSContext *cx, JSScript *script, jsbytecode *pc, TypeObject *object,
+PropertyAccess(JSContext *cx, HandleScript script, jsbytecode *pc, TypeObject *object,
                StackTypeSet *target, jsid id)
 {
     /* Reads from objects with unknown properties are unknown, writes to such objects are ignored. */
     if (object->unknownProperties()) {
         if (access != PROPERTY_WRITE)
             MarkPropertyAccessUnknown(cx, script, pc, target);
         return;
     }
@@ -1142,27 +1149,29 @@ PropertyAccess(JSContext *cx, JSScript *
             JS_ASSERT(access == PROPERTY_READ);
             types->addSubset(cx, target);
         }
     }
 }
 
 /* Whether the JSObject/TypeObject referent of an access on type cannot be determined. */
 static inline bool
-UnknownPropertyAccess(JSScript *script, Type type)
+UnknownPropertyAccess(HandleScript script, Type type)
 {
     return type.isUnknown()
         || type.isAnyObject()
         || (!type.isObject() && !script->compileAndGo);
 }
 
 template <PropertyAccessKind access>
 void
 TypeConstraintProp<access>::newType(JSContext *cx, TypeSet *source, Type type)
 {
+    RootedScript script(cx, script_);
+
     if (UnknownPropertyAccess(script, type)) {
         /*
          * Access on an unknown object. Reads produce an unknown result, writes
          * need to be monitored.
          */
         if (access == PROPERTY_WRITE)
             cx->compartment->types.monitorBytecode(cx, script, pc - script->code);
         else
@@ -1186,16 +1195,18 @@ TypeConstraintProp<access>::newType(JSCo
     if (object)
         PropertyAccess<access>(cx, script, pc, object, target, id);
 }
 
 template <PropertyAccessKind access>
 void
 TypeConstraintCallProp<access>::newType(JSContext *cx, TypeSet *source, Type type)
 {
+    RootedScript script(cx, script_);
+
     /*
      * For CALLPROP, we need to update not just the pushed types but also the
      * 'this' types of possible callees. If we can't figure out that set of
      * callees, monitor the call to make sure discovered callees get their
      * 'this' types updated.
      */
 
     if (UnknownPropertyAccess(script, type)) {
@@ -1211,39 +1222,40 @@ TypeConstraintCallProp<access>::newType(
             TypeSet *types = object->getProperty(cx, id, false);
             if (!types)
                 return;
             if (!types->hasPropagatedProperty())
                 object->getFromPrototypes(cx, id, types);
             /* Bypass addPropagateThis, we already have the callpc. */
             if (access == PROPERTY_READ) {
                 types->add(cx, cx->typeLifoAlloc().new_<TypeConstraintPropagateThis>(
-                                script, callpc, type, (StackTypeSet *) NULL));
+                                script_, callpc, type, (StackTypeSet *) NULL));
             } else {
                 TypeConstraintPropagateThis constraint(script, callpc, type, NULL);
                 types->addTypesToConstraint(cx, &constraint);
             }
         }
     }
 }
 
 void
 TypeConstraintSetElement::newType(JSContext *cx, TypeSet *source, Type type)
 {
+    RootedScript script(cx, script_);
     if (type.isUnknown() ||
         type.isPrimitive(JSVAL_TYPE_INT32) ||
         type.isPrimitive(JSVAL_TYPE_DOUBLE)) {
         objectTypes->addSetProperty(cx, script, pc, valueTypes, JSID_VOID);
     }
 }
 
 void
 TypeConstraintCall::newType(JSContext *cx, TypeSet *source, Type type)
 {
-    JSScript *script = callsite->script;
+    RootedScript script(cx, callsite->script);
     jsbytecode *pc = callsite->pc;
 
     JS_ASSERT_IF(script->hasAnalysis(),
                  callsite->returnTypes == script->analysis()->bytecodeTypes(pc));
 
     if (type.isUnknown() || type.isAnyObject()) {
         /* Monitor calls on unknown functions. */
         cx->compartment->types.monitorBytecode(cx, script, pc - script->code);
@@ -1364,16 +1376,17 @@ TypeConstraintPropagateThis::newType(JSC
 {
     if (type.isUnknown() || type.isAnyObject()) {
         /*
          * The callee is unknown, make sure the call is monitored so we pick up
          * possible this/callee correlations. This only comes into play for
          * CALLPROP, for other calls we are past the type barrier and a
          * TypeConstraintCall will also monitor the call.
          */
+        RootedScript script(cx, script_);
         cx->compartment->types.monitorBytecode(cx, script, callpc - script->code);
         return;
     }
 
     /* Ignore calls to natives, these will be handled by TypeConstraintCall. */
     JSFunction *callee = NULL;
 
     if (type.isSingleObject()) {
@@ -1407,16 +1420,17 @@ TypeConstraintArith::newType(JSContext *
     /*
      * We only model a subset of the arithmetic behavior that is actually
      * possible. The following need to be watched for at runtime:
      *
      * 1. Operations producing a double where no operand was a double.
      * 2. Operations producing a string where no operand was a string (addition only).
      * 3. Operations producing a value other than int/double/string.
      */
+    RootedScript script(cx, script_);
     if (other) {
         /*
          * Addition operation, consider these cases:
          *   {int,bool} x {int,bool} -> int
          *   double x {int,bool,double} -> double
          *   string x any -> string
          */
         if (type.isUnknown() || other->unknown()) {
@@ -1450,21 +1464,23 @@ TypeConstraintArith::newType(JSContext *
         else
             target->addType(cx, Type::Int32Type());
     }
 }
 
 void
 TypeConstraintTransformThis::newType(JSContext *cx, TypeSet *source, Type type)
 {
-    if (type.isUnknown() || type.isAnyObject() || type.isObject() || script->strictModeCode) {
+    if (type.isUnknown() || type.isAnyObject() || type.isObject() || script_->strictModeCode) {
         target->addType(cx, type);
         return;
     }
 
+    RootedScript script(cx, script_);
+
     /*
      * Note: if |this| is null or undefined, the pushed value is the outer window. We
      * can't use script->getGlobalType() here because it refers to the inner window.
      */
     if (!script->compileAndGo ||
         type.isPrimitive(JSVAL_TYPE_NULL) ||
         type.isPrimitive(JSVAL_TYPE_UNDEFINED)) {
         target->addType(cx, Type::UnknownType());
@@ -1497,17 +1513,17 @@ TypeConstraintTransformThis::newType(JSC
 
 /////////////////////////////////////////////////////////////////////
 // Freeze constraints
 /////////////////////////////////////////////////////////////////////
 
 /* Constraint which triggers recompilation of a script if any type is added to a type set. */
 class TypeConstraintFreeze : public TypeConstraint
 {
-public:
+  public:
     RecompileInfo info;
 
     /* Whether a new type has already been added, triggering recompilation. */
     bool typeAdded;
 
     TypeConstraintFreeze(RecompileInfo info)
         : info(info), typeAdded(false)
     {}
@@ -1605,17 +1621,17 @@ HeapTypeSet::getKnownTypeTag(JSContext *
     JS_ASSERT_IF(empty, type == JSVAL_TYPE_UNKNOWN);
 
     return type;
 }
 
 /* Constraint which triggers recompilation if an object acquires particular flags. */
 class TypeConstraintFreezeObjectFlags : public TypeConstraint
 {
-public:
+  public:
     RecompileInfo info;
 
     /* Flags we are watching for on this object. */
     TypeObjectFlags flags;
 
     /* Whether the object has already been marked as having one of the flags. */
     bool marked;
 
@@ -1726,17 +1742,17 @@ HeapTypeSet::WatchObjectStateChange(JSCo
      */
     types->add(cx, cx->typeLifoAlloc().new_<TypeConstraintFreezeObjectFlags>(
                      cx->compartment->types.compiledInfo,
                      0));
 }
 
 class TypeConstraintFreezeOwnProperty : public TypeConstraint
 {
-public:
+  public:
     RecompileInfo info;
 
     bool updated;
     bool configurable;
 
     TypeConstraintFreezeOwnProperty(RecompileInfo info, bool configurable)
         : info(info), updated(false), configurable(configurable)
     {}
@@ -1950,17 +1966,17 @@ enum RecompileKind {
 /*
  * Whether all jitcode for a given pc was compiled with monitoring or barriers.
  * If we reanalyze the script after generating jitcode, new monitoring and
  * barriers will be added which may be duplicating information available when
  * the script was originally compiled, and which should not invalidate that
  * compilation.
  */
 static inline bool
-JITCodeHasCheck(JSScript *script, jsbytecode *pc, RecompileKind kind)
+JITCodeHasCheck(HandleScript script, jsbytecode *pc, RecompileKind kind)
 {
     if (kind == RECOMPILE_NONE)
         return false;
 
 #ifdef JS_METHODJIT
     for (int constructing = 0; constructing <= 1; constructing++) {
         for (int barriers = 0; barriers <= 1; barriers++) {
             mjit::JITScript *jit = script->getJIT((bool) constructing, (bool) barriers);
@@ -1992,17 +2008,17 @@ JITCodeHasCheck(JSScript *script, jsbyte
     return true;
 }
 
 /*
  * Force recompilation of any jitcode for script at pc, or of any other script
  * which this script was inlined into.
  */
 static inline void
-AddPendingRecompile(JSContext *cx, JSScript *script, jsbytecode *pc,
+AddPendingRecompile(JSContext *cx, HandleScript script, jsbytecode *pc,
                     RecompileKind kind = RECOMPILE_NONE)
 {
     /*
      * Trigger recompilation of the script itself, if code was not previously
      * compiled with the specified information.
      */
     if (!JITCodeHasCheck(script, pc, kind))
         cx->compartment->types.addPendingRecompile(cx, script, pc);
@@ -2018,31 +2034,32 @@ AddPendingRecompile(JSContext *cx, JSScr
 
 /*
  * As for TypeConstraintFreeze, but describes an implicit freeze constraint
  * added for stack types within a script. Applies to all compilations of the
  * script, not just a single one.
  */
 class TypeConstraintFreezeStack : public TypeConstraint
 {
-public:
-    JSScript *script;
-
+    JSScript *script_;
+
+  public:
     TypeConstraintFreezeStack(JSScript *script)
-        : script(script)
+        : script_(script)
     {}
 
     const char *kind() { return "freezeStack"; }
 
     void newType(JSContext *cx, TypeSet *source, Type type)
     {
         /*
          * Unlike TypeConstraintFreeze, triggering this constraint once does
          * not disable it on future changes to the type set.
          */
+        RootedScript script(cx, script_);
         AddPendingRecompile(cx, script, NULL);
     }
 };
 
 /////////////////////////////////////////////////////////////////////
 // TypeCompartment
 /////////////////////////////////////////////////////////////////////
 
@@ -2084,17 +2101,17 @@ TypeCompartment::newTypeObject(JSContext
             object->setFlagsFromKey(cx, key);
         }
     }
 
     return object;
 }
 
 static inline jsbytecode *
-PreviousOpcode(JSScript *script, jsbytecode *pc)
+PreviousOpcode(HandleScript script, jsbytecode *pc)
 {
     ScriptAnalysis *analysis = script->analysis();
     JS_ASSERT(analysis->maybeCode(pc));
 
     if (pc == script->code)
         return NULL;
 
     for (pc--;; pc--) {
@@ -2105,17 +2122,17 @@ PreviousOpcode(JSScript *script, jsbytec
     return pc;
 }
 
 /*
  * If pc is an array initializer within an outer multidimensional array
  * initializer, find the opcode of the previous newarray. NULL otherwise.
  */
 static inline jsbytecode *
-FindPreviousInnerInitializer(JSScript *script, jsbytecode *initpc)
+FindPreviousInnerInitializer(HandleScript script, jsbytecode *initpc)
 {
     if (!script->hasAnalysis())
         return NULL;
 
     /*
      * Pattern match the following bytecode, which will appear between
      * adjacent initializer elements:
      *
@@ -2196,17 +2213,18 @@ TypeCompartment::addAllocationSiteTypeOb
     TypeObject *res = NULL;
 
     /*
      * If this is an array initializer nested in another array initializer,
      * try to reuse the type objects from earlier elements to avoid
      * distinguishing elements of the outer array unnecessarily.
      */
     jsbytecode *pc = key.script->code + key.offset;
-    jsbytecode *prev = FindPreviousInnerInitializer(key.script, pc);
+    RootedScript keyScript(cx, key.script);
+    jsbytecode *prev = FindPreviousInnerInitializer(keyScript, pc);
     if (prev) {
         AllocationSiteKey nkey;
         nkey.script = key.script;
         nkey.offset = prev - key.script->code;
         nkey.kind = JSProto_Array;
 
         AllocationSiteTable::Ptr p = cx->compartment->types.allocationSiteTable->lookup(nkey);
         if (p)
@@ -2244,24 +2262,24 @@ TypeCompartment::addAllocationSiteTypeOb
         cx->compartment->types.setPendingNukeTypes(cx);
         return NULL;
     }
 
     return res;
 }
 
 static inline jsid
-GetAtomId(JSContext *cx, JSScript *script, const jsbytecode *pc, unsigned offset)
+GetAtomId(JSContext *cx, HandleScript script, const jsbytecode *pc, unsigned offset)
 {
     PropertyName *name = script->getName(GET_UINT32_INDEX(pc + offset));
     return MakeTypeId(cx, NameToId(name));
 }
 
 bool
-types::UseNewType(JSContext *cx, JSScript *script, jsbytecode *pc)
+types::UseNewType(JSContext *cx, HandleScript script, jsbytecode *pc)
 {
     JS_ASSERT(cx->typeInferenceEnabled());
 
     /*
      * Make a heuristic guess at a use of JSOP_NEW that the constructed object
      * should have a fresh type object. We do this when the NEW is immediately
      * followed by a simple assignment to an object's .prototype field.
      * This is designed to catch common patterns for subclassing in JS:
@@ -2285,17 +2303,17 @@ types::UseNewType(JSContext *cx, JSScrip
         if (id == id_prototype(cx))
             return true;
     }
 
     return false;
 }
 
 bool
-types::UseNewTypeForInitializer(JSContext *cx, JSScript *script, jsbytecode *pc, JSProtoKey key)
+types::UseNewTypeForInitializer(JSContext *cx, HandleScript script, jsbytecode *pc, JSProtoKey key)
 {
     /*
      * Objects created outside loops in global and eval scripts should have
      * singleton types. For now this is only done for plain objects and typed
      * arrays, but not normal arrays.
      */
 
     if (!cx->typeInferenceEnabled() || script->function())
@@ -2308,17 +2326,17 @@ types::UseNewTypeForInitializer(JSContex
 
     if (!script->ensureRanAnalysis(cx))
         return false;
 
     return !script->analysis()->getCode(pc).inLoop;
 }
 
 bool
-types::ArrayPrototypeHasIndexedProperty(JSContext *cx, JSScript *script)
+types::ArrayPrototypeHasIndexedProperty(JSContext *cx, HandleScript script)
 {
     if (!cx->typeInferenceEnabled() || !script->compileAndGo)
         return true;
 
     RootedObject proto(cx, script->global().getOrCreateArrayPrototype(cx));
     if (!proto)
         return true;
 
@@ -2435,17 +2453,17 @@ TypeCompartment::nukeTypes(FreeOp *fop)
     mjit::ClearAllFrames(compartment);
 # ifdef JS_ION
     ion::InvalidateAll(fop, compartment);
 # endif
 
     /* Throw away all JIT code in the compartment, but leave everything else alone. */
 
     for (gc::CellIter i(compartment, gc::FINALIZE_SCRIPT); !i.done(); i.next()) {
-        JSScript *script = i.get<JSScript>();
+        RawScript script = i.get<JSScript>();
         mjit::ReleaseScriptCode(fop, script);
 # ifdef JS_ION
         ion::FinishInvalidation(fop, script);
 # endif
     }
 #endif /* JS_METHODJIT */
 }
 
@@ -2498,17 +2516,17 @@ TypeCompartment::addPendingRecompile(JSC
         cx->compartment->types.setPendingNukeTypes(cx);
         return;
     }
 
     co->setPendingRecompilation();
 }
 
 void
-TypeCompartment::addPendingRecompile(JSContext *cx, JSScript *script, jsbytecode *pc)
+TypeCompartment::addPendingRecompile(JSContext *cx, HandleScript script, jsbytecode *pc)
 {
     JS_ASSERT(script);
     if (!constrainedOutputs)
         return;
 
 #ifdef JS_METHODJIT
     for (int constructing = 0; constructing <= 1; constructing++) {
         for (int barriers = 0; barriers <= 1; barriers++) {
@@ -2536,17 +2554,17 @@ TypeCompartment::addPendingRecompile(JSC
 
     if (script->hasIonScript())
         addPendingRecompile(cx, script->ionScript()->recompileInfo());
 # endif
 #endif
 }
 
 void
-TypeCompartment::monitorBytecode(JSContext *cx, JSScript *script, uint32_t offset,
+TypeCompartment::monitorBytecode(JSContext *cx, HandleScript script, uint32_t offset,
                                  bool returnOnly)
 {
     if (!script->ensureRanInference(cx))
         return;
 
     ScriptAnalysis *analysis = script->analysis();
     jsbytecode *pc = script->code + offset;
 
@@ -2606,17 +2624,17 @@ TypeCompartment::markSetsUnknown(JSConte
             }
         }
     }
 
     for (unsigned i = 0; i < pending.length(); i++)
         pending[i]->addType(cx, Type::AnyObjectType());
 
     for (gc::CellIter i(cx->compartment, gc::FINALIZE_SCRIPT); !i.done(); i.next()) {
-        JSScript *script = i.get<JSScript>();
+        RootedScript script(cx, i.get<JSScript>());
         if (script->types) {
             unsigned count = TypeScript::NumTypeSets(script);
             TypeSet *typeArray = script->types->typeArray();
             for (unsigned i = 0; i < count; i++) {
                 if (typeArray[i].hasType(Type::ObjectType(target)))
                     typeArray[i].addType(cx, Type::AnyObjectType());
             }
         }
@@ -2654,29 +2672,30 @@ ScriptAnalysis::addTypeBarrier(JSContext
 
     if (!code.typeBarriers) {
         /*
          * Adding type barriers at a bytecode which did not have them before
          * will trigger recompilation. If there were already type barriers,
          * however, do not trigger recompilation (the script will be recompiled
          * if any of the barriers is ever violated).
          */
+        RootedScript script(cx, script_);
         AddPendingRecompile(cx, script, const_cast<jsbytecode*>(pc), RECOMPILE_CHECK_BARRIERS);
     }
 
     /* Ignore duplicate barriers. */
     TypeBarrier *barrier = code.typeBarriers;
     while (barrier) {
         if (barrier->target == target && barrier->type == type && !barrier->singleton)
             return;
         barrier = barrier->next;
     }
 
     InferSpew(ISpewOps, "typeBarrier: #%u:%05u: %sT%p%s %s",
-              script->id(), pc - script->code,
+              script_->id(), pc - script_->code,
               InferSpewColor(target), target, InferSpewColorReset(),
               TypeString(type));
 
     barrier = cx->analysisLifoAlloc().new_<TypeBarrier>(target, type, (JSObject *) NULL, JSID_VOID);
 
     if (!barrier) {
         cx->compartment->types.setPendingNukeTypes(cx);
         return;
@@ -2691,21 +2710,22 @@ ScriptAnalysis::addSingletonTypeBarrier(
                                         HandleObject singleton, jsid singletonId)
 {
     JS_ASSERT(singletonId == MakeTypeId(cx, singletonId) && !JSID_IS_VOID(singletonId));
 
     Bytecode &code = getCode(pc);
 
     if (!code.typeBarriers) {
         /* Trigger recompilation as for normal type barriers. */
+        RootedScript script(cx, script_);
         AddPendingRecompile(cx, script, const_cast<jsbytecode*>(pc), RECOMPILE_CHECK_BARRIERS);
     }
 
     InferSpew(ISpewOps, "singletonTypeBarrier: #%u:%05u: %sT%p%s %p %s",
-              script->id(), pc - script->code,
+              script_->id(), pc - script_->code,
               InferSpewColor(target), target, InferSpewColorReset(),
               (void *) singleton.get(), TypeIdString(singletonId));
 
     TypeBarrier *barrier = cx->analysisLifoAlloc().new_<TypeBarrier>(target, Type::UndefinedType(),
                               singleton, singletonId);
 
     if (!barrier) {
         cx->compartment->types.setPendingNukeTypes(cx);
@@ -2721,17 +2741,17 @@ TypeCompartment::print(JSContext *cx, bo
 {
     JSCompartment *compartment = this->compartment();
     AutoEnterAnalysis enter(compartment);
 
     if (!force && !InferSpewActive(ISpewResult))
         return;
 
     for (gc::CellIter i(compartment, gc::FINALIZE_SCRIPT); !i.done(); i.next()) {
-        JSScript *script = i.get<JSScript>();
+        RootedScript script(cx, i.get<JSScript>());
         if (script->hasAnalysis() && script->analysis()->ranInference())
             script->analysis()->printTypes(cx);
     }
 
 #ifdef DEBUG
     for (gc::CellIter i(compartment, gc::FINALIZE_TYPE_OBJECT); !i.done(); i.next()) {
         TypeObject *object = i.get<TypeObject>();
         object->print(cx);
@@ -3494,17 +3514,17 @@ TypeObject::print(JSContext *cx)
     printf("\n}\n");
 }
 
 /////////////////////////////////////////////////////////////////////
 // Type Analysis
 /////////////////////////////////////////////////////////////////////
 
 static inline TypeObject *
-GetInitializerType(JSContext *cx, JSScript *script, jsbytecode *pc)
+GetInitializerType(JSContext *cx, HandleScript script, jsbytecode *pc)
 {
     if (!script->compileAndGo)
         return NULL;
 
     JSOp op = JSOp(*pc);
     JS_ASSERT(op == JSOP_NEWARRAY || op == JSOP_NEWOBJECT || op == JSOP_NEWINIT);
 
     bool isArray = (op == JSOP_NEWARRAY || (op == JSOP_NEWINIT && GET_UINT8(pc) == JSProto_Array));
@@ -3523,28 +3543,29 @@ GetCalleeThisType(jsbytecode *pc)
     if (*pc == JSOP_UNDEFINED)
         return Type::UndefinedType();
     JS_ASSERT(*pc == JSOP_IMPLICITTHIS);
     return Type::UnknownType();
 }
 
 /* Analyze type information for a single bytecode. */
 bool
-ScriptAnalysis::analyzeTypesBytecode(JSContext *cx, unsigned offset,
-                                     TypeInferenceState &state)
-{
-    jsbytecode *pc = script->code + offset;
+ScriptAnalysis::analyzeTypesBytecode(JSContext *cx, unsigned offset, TypeInferenceState &state)
+{
+    RootedScript script(cx, script_);
+
+    jsbytecode *pc = script_->code + offset;
     JSOp op = (JSOp)*pc;
 
     Bytecode &code = getCode(offset);
     JS_ASSERT(!code.pushedTypes);
 
-    InferSpew(ISpewOps, "analyze: #%u:%05u", script->id(), offset);
-
-    unsigned defCount = GetDefCount(script, offset);
+    InferSpew(ISpewOps, "analyze: #%u:%05u", script_->id(), offset);
+
+    unsigned defCount = GetDefCount(script_, offset);
     if (ExtendedDef(pc))
         defCount++;
 
     StackTypeSet *pushed = cx->analysisLifoAlloc().newArrayUninitialized<StackTypeSet>(defCount);
     if (!pushed)
         return false;
     PodZero(pushed, defCount);
     code.pushedTypes = pushed;
@@ -3567,34 +3588,34 @@ ScriptAnalysis::analyzeTypesBytecode(JSC
              * The phi nodes at join points should all be unique, and every phi
              * node created should be in the phiValues list on some bytecode.
              */
             if (!state.phiNodes.append(newv->value.phiNode()))
                 return false;
             TypeSet &types = newv->value.phiNode()->types;
             InferSpew(ISpewOps, "typeSet: %sT%p%s phi #%u:%05u:%u",
                       InferSpewColor(&types), &types, InferSpewColorReset(),
-                      script->id(), offset, newv->slot);
+                      script_->id(), offset, newv->slot);
             types.setPurged();
 
             newv++;
         }
     }
 
     /*
      * Treat decomposed ops as no-ops, we will analyze the decomposed version
      * instead. (We do, however, need to look at introduced phi nodes).
      */
     if (js_CodeSpec[*pc].format & JOF_DECOMPOSE)
         return true;
 
     for (unsigned i = 0; i < defCount; i++) {
         InferSpew(ISpewOps, "typeSet: %sT%p%s pushed%u #%u:%05u",
                   InferSpewColor(&pushed[i]), &pushed[i], InferSpewColorReset(),
-                  i, script->id(), offset);
+                  i, script_->id(), offset);
         pushed[i].setPurged();
     }
 
     /* Add type constraints for the various opcodes. */
     switch (op) {
 
         /* Nop bytecodes. */
       case JSOP_POP:
@@ -3679,34 +3700,34 @@ ScriptAnalysis::analyzeTypesBytecode(JSC
       case JSOP_XMLELTEXPR:
         pushed[0].addType(cx, Type::StringType());
         break;
       case JSOP_NULL:
         pushed[0].addType(cx, Type::NullType());
         break;
 
       case JSOP_REGEXP:
-        if (script->compileAndGo) {
+        if (script_->compileAndGo) {
             TypeObject *object = TypeScript::StandardType(cx, script, JSProto_RegExp);
             if (!object)
                 return false;
             pushed[0].addType(cx, Type::ObjectType(object));
         } else {
             pushed[0].addType(cx, Type::UnknownType());
         }
         break;
 
       case JSOP_OBJECT:
-        pushed[0].addType(cx, Type::ObjectType(script->getObject(GET_UINT32_INDEX(pc))));
+        pushed[0].addType(cx, Type::ObjectType(script_->getObject(GET_UINT32_INDEX(pc))));
         break;
 
       case JSOP_STOP:
         /* If a stop is reachable then the return type may be void. */
-          if (script->function())
-            TypeScript::ReturnTypes(script)->addType(cx, Type::UndefinedType());
+          if (script_->function())
+            TypeScript::ReturnTypes(script_)->addType(cx, Type::UndefinedType());
         break;
 
       case JSOP_OR:
       case JSOP_AND:
         /* OR/AND push whichever operand determined the result. */
         poppedTypes(pc, 0)->addSubset(cx, &pushed[0]);
         break;
 
@@ -3747,17 +3768,17 @@ ScriptAnalysis::analyzeTypesBytecode(JSC
          */
         if (id == NameToId(cx->names().undefined))
             seen->addType(cx, Type::UndefinedType());
         if (id == NameToId(cx->names().NaN))
             seen->addType(cx, Type::DoubleType());
         if (id == NameToId(cx->names().Infinity))
             seen->addType(cx, Type::DoubleType());
 
-        TypeObject *global = script->global().getType(cx);
+        TypeObject *global = script_->global().getType(cx);
 
         /* Handle as a property access. */
         if (state.hasPropertyReadTypes)
             PropertyAccess<PROPERTY_READ_EXISTING>(cx, script, pc, global, seen, id);
         else
             PropertyAccess<PROPERTY_READ>(cx, script, pc, global, seen, id);
 
         if (op == JSOP_CALLGNAME)
@@ -3778,17 +3799,17 @@ ScriptAnalysis::analyzeTypesBytecode(JSC
       }
 
       case JSOP_BINDGNAME:
       case JSOP_BINDNAME:
         break;
 
       case JSOP_SETGNAME: {
         jsid id = GetAtomId(cx, script, pc, 0);
-        TypeObject *global = script->global().getType(cx);
+        TypeObject *global = script_->global().getType(cx);
         PropertyAccess<PROPERTY_WRITE>(cx, script, pc, global, poppedTypes(pc, 0), id);
         poppedTypes(pc, 0)->addSubset(cx, &pushed[0]);
         break;
       }
 
       case JSOP_SETNAME:
       case JSOP_SETCONST:
         cx->compartment->types.monitorBytecode(cx, script, offset);
@@ -3801,41 +3822,41 @@ ScriptAnalysis::analyzeTypesBytecode(JSC
         seen->addSubset(cx, &pushed[0]);
         break;
       }
 
       case JSOP_GETARG:
       case JSOP_CALLARG:
       case JSOP_GETLOCAL:
       case JSOP_CALLLOCAL: {
-        uint32_t slot = GetBytecodeSlot(script, pc);
+        uint32_t slot = GetBytecodeSlot(script_, pc);
         if (trackSlot(slot)) {
             /*
              * Normally these opcodes don't pop anything, but they are given
              * an extended use holding the variable's SSA value before the
              * access. Use the types from here.
              */
             poppedTypes(pc, 0)->addSubset(cx, &pushed[0]);
-        } else if (slot < TotalSlots(script)) {
-            StackTypeSet *types = TypeScript::SlotTypes(script, slot);
+        } else if (slot < TotalSlots(script_)) {
+            StackTypeSet *types = TypeScript::SlotTypes(script_, slot);
             types->addSubset(cx, &pushed[0]);
         } else {
             /* Local 'let' variable. Punt on types for these, for now. */
             pushed[0].addType(cx, Type::UnknownType());
         }
         if (op == JSOP_CALLARG || op == JSOP_CALLLOCAL)
             pushed[0].addPropagateThis(cx, script, pc, Type::UndefinedType());
         break;
       }
 
       case JSOP_SETARG:
       case JSOP_SETLOCAL: {
-        uint32_t slot = GetBytecodeSlot(script, pc);
-        if (!trackSlot(slot) && slot < TotalSlots(script)) {
-            TypeSet *types = TypeScript::SlotTypes(script, slot);
+        uint32_t slot = GetBytecodeSlot(script_, pc);
+        if (!trackSlot(slot) && slot < TotalSlots(script_)) {
+            TypeSet *types = TypeScript::SlotTypes(script_, slot);
             poppedTypes(pc, 0)->addSubset(cx, types);
         }
 
         /*
          * For assignments to non-escaping locals/args, we don't need to update
          * the possible types of the var, as for each read of the var SSA gives
          * us the writes that could have produced that read.
          */
@@ -3864,40 +3885,40 @@ ScriptAnalysis::analyzeTypesBytecode(JSC
       case JSOP_INCARG:
       case JSOP_DECARG:
       case JSOP_ARGINC:
       case JSOP_ARGDEC:
       case JSOP_INCLOCAL:
       case JSOP_DECLOCAL:
       case JSOP_LOCALINC:
       case JSOP_LOCALDEC: {
-        uint32_t slot = GetBytecodeSlot(script, pc);
+        uint32_t slot = GetBytecodeSlot(script_, pc);
         if (trackSlot(slot)) {
             poppedTypes(pc, 0)->addArith(cx, script, pc, &pushed[0]);
-        } else if (slot < TotalSlots(script)) {
-            StackTypeSet *types = TypeScript::SlotTypes(script, slot);
+        } else if (slot < TotalSlots(script_)) {
+            StackTypeSet *types = TypeScript::SlotTypes(script_, slot);
             types->addArith(cx, script, pc, types);
             types->addSubset(cx, &pushed[0]);
         } else {
             pushed[0].addType(cx, Type::UnknownType());
         }
         break;
       }
 
       case JSOP_ARGUMENTS:
         /* Compute a precise type only when we know the arguments won't escape. */
-        if (script->needsArgsObj())
+        if (script_->needsArgsObj())
             pushed[0].addType(cx, Type::UnknownType());
         else
             pushed[0].addType(cx, Type::MagicArgType());
         break;
 
       case JSOP_REST: {
-        StackTypeSet *types = script->analysis()->bytecodeTypes(pc);
-        if (script->compileAndGo) {
+        StackTypeSet *types = script_->analysis()->bytecodeTypes(pc);
+        if (script_->compileAndGo) {
             TypeObject *rest = TypeScript::InitObject(cx, script, pc, JSProto_Array);
             if (!rest)
                 return false;
 
             // Simulate setting a element.
             if (!rest->unknownProperties()) {
                 HeapTypeSet *propTypes = rest->getProperty(cx, JSID_VOID, true);
                 if (!propTypes)
@@ -3920,26 +3941,26 @@ ScriptAnalysis::analyzeTypesBytecode(JSC
         poppedTypes(pc, 0)->addSubset(cx, &pushed[0]);
         break;
       }
 
       case JSOP_LENGTH:
       case JSOP_GETPROP:
       case JSOP_CALLPROP: {
         jsid id = GetAtomId(cx, script, pc, 0);
-        StackTypeSet *seen = script->analysis()->bytecodeTypes(pc);
-
-        HeapTypeSet *input = &script->types->propertyReadTypes[state.propertyReadIndex++];
+        StackTypeSet *seen = script_->analysis()->bytecodeTypes(pc);
+
+        HeapTypeSet *input = &script_->types->propertyReadTypes[state.propertyReadIndex++];
         poppedTypes(pc, 0)->addSubset(cx, input);
 
         if (state.hasPropertyReadTypes) {
-            TypeConstraintGetPropertyExisting getProp(script, pc, seen, id);
+            TypeConstraintGetPropertyExisting getProp(script_, pc, seen, id);
             input->addTypesToConstraint(cx, &getProp);
             if (op == JSOP_CALLPROP) {
-                TypeConstraintCallPropertyExisting callProp(script, pc, id);
+                TypeConstraintCallPropertyExisting callProp(script_, pc, id);
                 input->addTypesToConstraint(cx, &callProp);
             }
         } else {
             input->addGetProperty(cx, script, pc, seen, id);
             if (op == JSOP_CALLPROP)
                 input->addCallProperty(cx, script, pc, id);
         }
 
@@ -3949,27 +3970,27 @@ ScriptAnalysis::analyzeTypesBytecode(JSC
 
       /*
        * We only consider ELEM accesses on integers below. Any element access
        * which is accessing a non-integer property must be monitored.
        */
 
       case JSOP_GETELEM:
       case JSOP_CALLELEM: {
-        StackTypeSet *seen = script->analysis()->bytecodeTypes(pc);
+        StackTypeSet *seen = script_->analysis()->bytecodeTypes(pc);
 
         /* Don't try to compute a precise callee for CALLELEM. */
         if (op == JSOP_CALLELEM)
             seen->addType(cx, Type::AnyObjectType());
 
-        HeapTypeSet *input = &script->types->propertyReadTypes[state.propertyReadIndex++];
+        HeapTypeSet *input = &script_->types->propertyReadTypes[state.propertyReadIndex++];
         poppedTypes(pc, 1)->addSubset(cx, input);
 
         if (state.hasPropertyReadTypes) {
-            TypeConstraintGetPropertyExisting getProp(script, pc, seen, JSID_VOID);
+            TypeConstraintGetPropertyExisting getProp(script_, pc, seen, JSID_VOID);
             input->addTypesToConstraint(cx, &getProp);
         } else {
             input->addGetProperty(cx, script, pc, seen, JSID_VOID);
         }
 
         seen->addSubset(cx, &pushed[0]);
         if (op == JSOP_CALLELEM)
             pushed[0].addPropagateThis(cx, script, pc, Type::UndefinedType(), poppedTypes(pc, 1));
@@ -3985,23 +4006,23 @@ ScriptAnalysis::analyzeTypesBytecode(JSC
         /*
          * This is only used for element inc/dec ops; any id produced which
          * is not an integer must be monitored.
          */
         pushed[0].addType(cx, Type::Int32Type());
         break;
 
       case JSOP_THIS:
-        TypeScript::ThisTypes(script)->addTransformThis(cx, script, &pushed[0]);
+        TypeScript::ThisTypes(script_)->addTransformThis(cx, script, &pushed[0]);
         break;
 
       case JSOP_RETURN:
       case JSOP_SETRVAL:
-          if (script->function())
-            poppedTypes(pc, 0)->addSubset(cx, TypeScript::ReturnTypes(script));
+          if (script_->function())
+            poppedTypes(pc, 0)->addSubset(cx, TypeScript::ReturnTypes(script_));
         break;
 
       case JSOP_ADD:
         poppedTypes(pc, 0)->addArith(cx, script, pc, &pushed[0], poppedTypes(pc, 1));
         poppedTypes(pc, 1)->addArith(cx, script, pc, &pushed[0], poppedTypes(pc, 0));
         break;
 
       case JSOP_SUB:
@@ -4014,24 +4035,24 @@ ScriptAnalysis::analyzeTypesBytecode(JSC
 
       case JSOP_NEG:
       case JSOP_POS:
         poppedTypes(pc, 0)->addArith(cx, script, pc, &pushed[0]);
         break;
 
       case JSOP_LAMBDA:
       case JSOP_DEFFUN: {
-        RootedObject obj(cx, script->getObject(GET_UINT32_INDEX(pc)));
+        RootedObject obj(cx, script_->getObject(GET_UINT32_INDEX(pc)));
 
         TypeSet *res = NULL;
         if (op == JSOP_LAMBDA)
             res = &pushed[0];
 
         if (res) {
-            if (script->compileAndGo && !UseNewTypeForClone(obj->toFunction()))
+            if (script_->compileAndGo && !UseNewTypeForClone(obj->toFunction()))
                 res->addType(cx, Type::ObjectType(obj));
             else
                 res->addType(cx, Type::UnknownType());
         } else {
             cx->compartment->types.monitorBytecode(cx, script, offset);
         }
         break;
       }
@@ -4039,61 +4060,61 @@ ScriptAnalysis::analyzeTypesBytecode(JSC
       case JSOP_DEFVAR:
         break;
 
       case JSOP_CALL:
       case JSOP_EVAL:
       case JSOP_FUNCALL:
       case JSOP_FUNAPPLY:
       case JSOP_NEW: {
-        StackTypeSet *seen = script->analysis()->bytecodeTypes(pc);
+        StackTypeSet *seen = script_->analysis()->bytecodeTypes(pc);
         seen->addSubset(cx, &pushed[0]);
 
         /* Construct the base call information about this site. */
-        unsigned argCount = GetUseCount(script, offset) - 2;
+        unsigned argCount = GetUseCount(script_, offset) - 2;
         TypeCallsite *callsite = cx->analysisLifoAlloc().new_<TypeCallsite>(
-                                                        cx, script, pc, op == JSOP_NEW, argCount);
+                                                        cx, script_, pc, op == JSOP_NEW, argCount);
         if (!callsite || (argCount && !callsite->argumentTypes)) {
             cx->compartment->types.setPendingNukeTypes(cx);
             break;
         }
         callsite->thisTypes = poppedTypes(pc, argCount);
         callsite->returnTypes = seen;
 
         for (unsigned i = 0; i < argCount; i++)
             callsite->argumentTypes[i] = poppedTypes(pc, argCount - 1 - i);
 
         /*
          * Mark FUNCALL and FUNAPPLY sites as monitored. The method JIT may
          * lower these into normal calls, and we need to make sure the
          * callee's argument types are checked on entry.
          */
         if (op == JSOP_FUNCALL || op == JSOP_FUNAPPLY)
-            cx->compartment->types.monitorBytecode(cx, script, pc - script->code);
+            cx->compartment->types.monitorBytecode(cx, script, pc - script_->code);
 
         poppedTypes(pc, argCount + 1)->addCall(cx, callsite);
         break;
       }
 
       case JSOP_NEWINIT:
       case JSOP_NEWARRAY:
       case JSOP_NEWOBJECT: {
-        StackTypeSet *types = script->analysis()->bytecodeTypes(pc);
+        StackTypeSet *types = script_->analysis()->bytecodeTypes(pc);
         types->addSubset(cx, &pushed[0]);
 
         bool isArray = (op == JSOP_NEWARRAY || (op == JSOP_NEWINIT && GET_UINT8(pc) == JSProto_Array));
         JSProtoKey key = isArray ? JSProto_Array : JSProto_Object;
 
         if (UseNewTypeForInitializer(cx, script, pc, key)) {
             /* Defer types pushed by this bytecode until runtime. */
             break;
         }
 
         TypeObject *initializer = GetInitializerType(cx, script, pc);
-        if (script->compileAndGo) {
+        if (script_->compileAndGo) {
             if (!initializer)
                 return false;
             types->addType(cx, Type::ObjectType(initializer));
         } else {
             JS_ASSERT(!initializer);
             types->addType(cx, Type::UnknownType());
         }
         break;
@@ -4101,17 +4122,17 @@ ScriptAnalysis::analyzeTypesBytecode(JSC
 
       case JSOP_ENDINIT:
         break;
 
       case JSOP_INITELEM:
       case JSOP_INITELEM_INC:
       case JSOP_SPREAD: {
         const SSAValue &objv = poppedValue(pc, 2);
-        jsbytecode *initpc = script->code + objv.pushedOffset();
+        jsbytecode *initpc = script_->code + objv.pushedOffset();
         TypeObject *initializer = GetInitializerType(cx, script, initpc);
 
         if (initializer) {
             pushed[0].addType(cx, Type::ObjectType(initializer));
             if (!initializer->unknownProperties()) {
                 /*
                  * Assume the initialized element is an integer. INITELEM can be used
                  * for doubles which don't map to the JSID_VOID property, which must
@@ -4154,17 +4175,17 @@ ScriptAnalysis::analyzeTypesBytecode(JSC
         break;
 
       case JSOP_HOLE:
         state.hasHole = true;
         break;
 
       case JSOP_INITPROP: {
         const SSAValue &objv = poppedValue(pc, 1);
-        jsbytecode *initpc = script->code + objv.pushedOffset();
+        jsbytecode *initpc = script_->code + objv.pushedOffset();
         TypeObject *initializer = GetInitializerType(cx, script, initpc);
 
         if (initializer) {
             pushed[0].addType(cx, Type::ObjectType(initializer));
             if (!initializer->unknownProperties()) {
                 jsid id = GetAtomId(cx, script, pc, 0);
                 TypeSet *types = initializer->getProperty(cx, id, true);
                 if (!types)
@@ -4266,27 +4287,27 @@ ScriptAnalysis::analyzeTypesBytecode(JSC
       case JSOP_LEAVEFORLETIN:
         break;
 
       case JSOP_CASE:
         poppedTypes(pc, 1)->addSubset(cx, &pushed[0]);
         break;
 
       case JSOP_GENERATOR:
-          if (script->function()) {
-            if (script->compileAndGo) {
-                RawObject proto = script->global().getOrCreateGeneratorPrototype(cx);
+          if (script_->function()) {
+            if (script_->compileAndGo) {
+                RawObject proto = script_->global().getOrCreateGeneratorPrototype(cx);
                 if (!proto)
                     return false;
                 TypeObject *object = proto->getNewType(cx);
                 if (!object)
                     return false;
-                TypeScript::ReturnTypes(script)->addType(cx, Type::ObjectType(object));
+                TypeScript::ReturnTypes(script_)->addType(cx, Type::ObjectType(object));
             } else {
-                TypeScript::ReturnTypes(script)->addType(cx, Type::UnknownType());
+                TypeScript::ReturnTypes(script_)->addType(cx, Type::UnknownType());
             }
         }
         break;
 
       case JSOP_YIELD:
         pushed[0].addType(cx, Type::UnknownType());
         break;
 
@@ -4319,27 +4340,27 @@ ScriptAnalysis::analyzeTypesBytecode(JSC
       case JSOP_GETFUNNS:
       case JSOP_FILTER:
         /* Note: the second value pushed by filter is a hole, and not modelled. */
       case JSOP_ENDFILTER:
         pushed[0].addType(cx, Type::UnknownType());
         break;
 
       case JSOP_CALLEE: {
-        JSFunction *fun = script->function();
-        if (script->compileAndGo && !UseNewTypeForClone(fun))
+        JSFunction *fun = script_->function();
+        if (script_->compileAndGo && !UseNewTypeForClone(fun))
             pushed[0].addType(cx, Type::ObjectType(fun));
         else
             pushed[0].addType(cx, Type::UnknownType());
         break;
       }
 
       default:
         /* Display fine-grained debug information first */
-        fprintf(stderr, "Unknown bytecode %02x at #%u:%05u\n", op, script->id(), offset);
+        fprintf(stderr, "Unknown bytecode %02x at #%u:%05u\n", op, script_->id(), offset);
         TypeFailure(cx, "Unknown bytecode %02x", op);
     }
 
     return true;
 }
 
 void
 ScriptAnalysis::analyzeTypes(JSContext *cx)
@@ -4359,54 +4380,54 @@ ScriptAnalysis::analyzeTypes(JSContext *
 
     /*
      * Set this early to avoid reentrance. Any failures are OOMs, and will nuke
      * all types in the compartment.
      */
     ranInference_ = true;
 
     /* Make sure the initial type set of all local vars includes void. */
-    for (unsigned i = 0; i < script->nfixed; i++)
-        TypeScript::LocalTypes(script, i)->addType(cx, Type::UndefinedType());
+    for (unsigned i = 0; i < script_->nfixed; i++)
+        TypeScript::LocalTypes(script_, i)->addType(cx, Type::UndefinedType());
 
     TypeInferenceState state(cx);
 
     /*
      * Generate type sets for the inputs to property reads in the script,
      * unless it already has them. If we purge analysis information and end up
      * reanalyzing types in the script, we don't want to regenerate constraints
      * on these property inputs as they will be duplicating information on the
      * property type sets previously added.
      */
-    if (script->types->propertyReadTypes) {
+    if (script_->types->propertyReadTypes) {
         state.hasPropertyReadTypes = true;
     } else {
         HeapTypeSet *typeArray =
             (HeapTypeSet*) cx->typeLifoAlloc().alloc(sizeof(HeapTypeSet) * numPropertyReads());
         if (!typeArray) {
             cx->compartment->types.setPendingNukeTypes(cx);
             return;
         }
-        script->types->propertyReadTypes = typeArray;
+        script_->types->propertyReadTypes = typeArray;
         PodZero(typeArray, numPropertyReads());
 
 #ifdef DEBUG
         for (unsigned i = 0; i < numPropertyReads(); i++) {
             InferSpew(ISpewOps, "typeSet: %sT%p%s propertyRead%u #%u",
                       InferSpewColor(&typeArray[i]), &typeArray[i], InferSpewColorReset(),
-                      i, script->id());
+                      i, script_->id());
         }
 #endif
     }
 
     unsigned offset = 0;
-    while (offset < script->length) {
+    while (offset < script_->length) {
         Bytecode *code = maybeCode(offset);
 
-        jsbytecode *pc = script->code + offset;
+        jsbytecode *pc = script_->code + offset;
 
         if (code && !analyzeTypesBytecode(cx, offset, state)) {
             cx->compartment->types.setPendingNukeTypes(cx);
             return;
         }
 
         offset += GetBytecodeLength(pc);
     }
@@ -4421,51 +4442,52 @@ ScriptAnalysis::analyzeTypes(JSContext *
         }
     }
 
     /*
      * Replay any dynamic type results which have been generated for the script
      * either because we ran the interpreter some before analyzing or because
      * we are reanalyzing after a GC.
      */
-    TypeResult *result = script->types->dynamicList;
+    TypeResult *result = script_->types->dynamicList;
     while (result) {
         if (result->offset != UINT32_MAX) {
             pushedTypes(result->offset)->addType(cx, result->type);
         } else {
             /* Custom for-in loop iteration has happened in this script. */
             state.forTypes->addType(cx, Type::UnknownType());
         }
         result = result->next;
     }
 
-    if (!script->hasFreezeConstraints) {
+    if (!script_->hasFreezeConstraints) {
+        RootedScript script(cx, script_);
         TypeScript::AddFreezeConstraints(cx, script);
-        script->hasFreezeConstraints = true;
+        script_->hasFreezeConstraints = true;
     }
 }
 
 bool
 ScriptAnalysis::integerOperation(JSContext *cx, jsbytecode *pc)
 {
-    JS_ASSERT(uint32_t(pc - script->code) < script->length);
+    JS_ASSERT(uint32_t(pc - script_->code) < script_->length);
 
     switch (JSOp(*pc)) {
 
       case JSOP_INCARG:
       case JSOP_DECARG:
       case JSOP_ARGINC:
       case JSOP_ARGDEC:
       case JSOP_INCLOCAL:
       case JSOP_DECLOCAL:
       case JSOP_LOCALINC:
       case JSOP_LOCALDEC: {
         if (pushedTypes(pc, 0)->getKnownTypeTag() != JSVAL_TYPE_INT32)
             return false;
-        uint32_t slot = GetBytecodeSlot(script, pc);
+        uint32_t slot = GetBytecodeSlot(script_, pc);
         if (trackSlot(slot)) {
             if (poppedTypes(pc, 0)->getKnownTypeTag() != JSVAL_TYPE_INT32)
                 return false;
         }
         return true;
       }
 
       case JSOP_ADD:
@@ -4486,17 +4508,17 @@ ScriptAnalysis::integerOperation(JSConte
 }
 
 /*
  * Persistent constraint clearing out newScript and definite properties from
  * an object should a property on another object get a setter.
  */
 class TypeConstraintClearDefiniteSetter : public TypeConstraint
 {
-public:
+  public:
     TypeObject *object;
 
     TypeConstraintClearDefiniteSetter(TypeObject *object)
         : object(object)
     {}
 
     const char *kind() { return "clearDefiniteSetter"; }
 
@@ -4518,17 +4540,17 @@ public:
 };
 
 /*
  * Constraint which clears definite properties on an object should a type set
  * contain any types other than a single object.
  */
 class TypeConstraintClearDefiniteSingle : public TypeConstraint
 {
-public:
+  public:
     TypeObject *object;
 
     TypeConstraintClearDefiniteSingle(TypeObject *object)
         : object(object)
     {}
 
     const char *kind() { return "clearDefiniteSingle"; }
 
@@ -4564,17 +4586,17 @@ AnalyzeNewScriptProperties(JSContext *cx
     if (initializerList->length() > 50) {
         /*
          * Bail out on really long initializer lists (far longer than maximum
          * number of properties we can track), we may be recursing.
          */
         return false;
     }
 
-    JSScript *script = fun->script();
+    RootedScript script(cx, fun->script());
     if (!script->ensureRanAnalysis(cx) || !script->ensureRanInference(cx)) {
         pbaseobj.set(NULL);
         cx->compartment->types.setPendingNukeTypes(cx);
         return false;
     }
 
     ScriptAnalysis *analysis = script->analysis();
 
@@ -4702,17 +4724,17 @@ AnalyzeNewScriptProperties(JSContext *cx
     return entirelyAnalyzed;
 }
 
 static bool
 AnalyzePoppedThis(JSContext *cx, Vector<SSAUseChain *> *pendingPoppedThis,
                   TypeObject *type, JSFunction *fun, MutableHandleObject pbaseobj,
                   Vector<TypeNewScript::Initializer> *initializerList)
 {
-    JSScript *script = fun->script();
+    RootedScript script(cx, fun->script());
     ScriptAnalysis *analysis = script->analysis();
 
     while (!pendingPoppedThis->empty()) {
         SSAUseChain *uses = pendingPoppedThis->back();
         pendingPoppedThis->popBack();
 
         jsbytecode *pc = script->code + uses->offset;
         JSOp op = JSOp(*pc);
@@ -4938,33 +4960,33 @@ CheckNewScriptProperties(JSContext *cx, 
 
 /////////////////////////////////////////////////////////////////////
 // Printing
 /////////////////////////////////////////////////////////////////////
 
 void
 ScriptAnalysis::printTypes(JSContext *cx)
 {
-    AutoEnterAnalysis enter(script->compartment());
-    TypeCompartment *compartment = &script->compartment()->types;
+    AutoEnterAnalysis enter(script_->compartment());
+    TypeCompartment *compartment = &script_->compartment()->types;
 
     /*
      * Check if there are warnings for used values with unknown types, and build
      * statistics about the size of type sets found for stack values.
      */
-    for (unsigned offset = 0; offset < script->length; offset++) {
+    for (unsigned offset = 0; offset < script_->length; offset++) {
         if (!maybeCode(offset))
             continue;
 
-        jsbytecode *pc = script->code + offset;
+        jsbytecode *pc = script_->code + offset;
 
         if (js_CodeSpec[*pc].format & JOF_DECOMPOSE)
             continue;
 
-        unsigned defCount = GetDefCount(script, offset);
+        unsigned defCount = GetDefCount(script_, offset);
         if (!defCount)
             continue;
 
         for (unsigned i = 0; i < defCount; i++) {
             TypeSet *types = pushedTypes(offset, i);
 
             if (types->unknown()) {
                 compartment->typeCountOver++;
@@ -4997,61 +5019,61 @@ ScriptAnalysis::printTypes(JSContext *cx
             } else {
                 compartment->typeCounts[typeCount-1]++;
             }
         }
     }
 
 #ifdef DEBUG
 
-    if (script->function())
+    if (script_->function())
         printf("Function");
-    else if (script->isCachedEval)
+    else if (script_->isCachedEval)
         printf("Eval");
     else
         printf("Main");
-    printf(" #%u %s (line %d):\n", script->id(), script->filename, script->lineno);
+    printf(" #%u %s (line %d):\n", script_->id(), script_->filename, script_->lineno);
 
     printf("locals:");
     printf("\n    return:");
-    TypeScript::ReturnTypes(script)->print(cx);
+    TypeScript::ReturnTypes(script_)->print(cx);
     printf("\n    this:");
-    TypeScript::ThisTypes(script)->print(cx);
-
-    for (unsigned i = 0; script->function() && i < script->function()->nargs; i++) {
+    TypeScript::ThisTypes(script_)->print(cx);
+
+    for (unsigned i = 0; script_->function() && i < script_->function()->nargs; i++) {
         printf("\n    arg%u:", i);
-        TypeScript::ArgTypes(script, i)->print(cx);
-    }
-    for (unsigned i = 0; i < script->nfixed; i++) {
-        if (!trackSlot(LocalSlot(script, i))) {
+        TypeScript::ArgTypes(script_, i)->print(cx);
+    }
+    for (unsigned i = 0; i < script_->nfixed; i++) {
+        if (!trackSlot(LocalSlot(script_, i))) {
             printf("\n    local%u:", i);
-            TypeScript::LocalTypes(script, i)->print(cx);
+            TypeScript::LocalTypes(script_, i)->print(cx);
         }
     }
     printf("\n");
 
-    for (unsigned offset = 0; offset < script->length; offset++) {
+    for (unsigned offset = 0; offset < script_->length; offset++) {
         if (!maybeCode(offset))
             continue;
 
-        jsbytecode *pc = script->code + offset;
-
-        PrintBytecode(cx, script, pc);
+        jsbytecode *pc = script_->code + offset;
+
+        PrintBytecode(cx, script_, pc);
 
         if (js_CodeSpec[*pc].format & JOF_DECOMPOSE)
             continue;
 
         if (js_CodeSpec[*pc].format & JOF_TYPESET) {
-            TypeSet *types = script->analysis()->bytecodeTypes(pc);
-            printf("  typeset %d:", (int) (types - script->types->typeArray()));
+            TypeSet *types = script_->analysis()->bytecodeTypes(pc);
+            printf("  typeset %d:", (int) (types - script_->types->typeArray()));
             types->print(cx);
             printf("\n");
         }
 
-        unsigned defCount = GetDefCount(script, offset);
+        unsigned defCount = GetDefCount(script_, offset);
         for (unsigned i = 0; i < defCount; i++) {
             printf("  type %d:", i);
             pushedTypes(offset, i)->print(cx);
             printf("\n");
         }
 
         if (getCode(offset).monitoredTypes)
             printf("  monitored\n");
@@ -5081,17 +5103,17 @@ namespace js {
 namespace types {
 
 void
 MarkIteratorUnknownSlow(JSContext *cx)
 {
     /* Check whether we are actually at an ITER opcode. */
 
     jsbytecode *pc;
-    JSScript *script = cx->stack.currentScript(&pc);
+    RootedScript script(cx, cx->stack.currentScript(&pc));
     if (!script || !pc)
         return;
 
     if (JSOp(*pc) != JSOP_ITER)
         return;
 
     AutoEnterTypeInference enter(cx);
 
@@ -5139,17 +5161,17 @@ MarkIteratorUnknownSlow(JSContext *cx)
             analysis->pushedTypes(pc, 0)->addType(cx, Type::UnknownType());
     }
 }
 
 void
 TypeMonitorCallSlow(JSContext *cx, HandleObject callee, const CallArgs &args, bool constructing)
 {
     unsigned nargs = callee->toFunction()->nargs;
-    JSScript *script = callee->toFunction()->script();
+    RootedScript script(cx, callee->toFunction()->script());
 
     if (!constructing)
         TypeScript::SetThis(cx, script, args.thisv());
 
     /*
      * Add constraints going up to the minimum of the actual and formal count.
      * If there are more actuals than formals the later values can only be
      * accessed through the arguments object, which is monitored.
@@ -5169,17 +5191,17 @@ IsAboutToBeFinalized(TypeObjectKey *key)
     /* Mask out the low bit indicating whether this is a type or JS object. */
     gc::Cell *tmp = reinterpret_cast<gc::Cell *>(uintptr_t(key) & ~1);
     bool isMarked = IsCellMarked(&tmp);
     JS_ASSERT(tmp == reinterpret_cast<gc::Cell *>(uintptr_t(key) & ~1));
     return !isMarked;
 }
 
 void
-TypeDynamicResult(JSContext *cx, JSScript *script, jsbytecode *pc, Type type)
+TypeDynamicResult(JSContext *cx, HandleScript script, jsbytecode *pc, Type type)
 {
     JS_ASSERT(cx->typeInferenceEnabled());
     AutoEnterTypeInference enter(cx);
 
     /* Directly update associated type sets for applicable bytecodes. */
     if (js_CodeSpec[*pc].format & JOF_TYPESET) {
         if (!script->ensureRanAnalysis(cx)) {
             cx->compartment->types.setPendingNukeTypes(cx);
@@ -5307,17 +5329,17 @@ TypeDynamicResult(JSContext *cx, JSScrip
 
     if (script->hasAnalysis() && script->analysis()->ranInference()) {
         TypeSet *pushed = script->analysis()->pushedTypes(pc, 0);
         pushed->addType(cx, type);
     }
 }
 
 void
-TypeMonitorResult(JSContext *cx, JSScript *script, jsbytecode *pc, const js::Value &rval)
+TypeMonitorResult(JSContext *cx, HandleScript script, jsbytecode *pc, const js::Value &rval)
 {
     /* Allow the non-TYPESET scenario to simplify stubs used in compound opcodes. */
     if (!(js_CodeSpec[*pc].format & JOF_TYPESET))
         return;
 
     AutoEnterTypeInference enter(cx);
 
     if (!script->ensureRanAnalysis(cx)) {
@@ -5488,19 +5510,19 @@ JSScript::makeAnalysis(JSContext *cx)
 
     AutoEnterAnalysis enter(cx);
 
     types->analysis = cx->analysisLifoAlloc().new_<ScriptAnalysis>(this);
 
     if (!types->analysis)
         return false;
 
-    Rooted<JSScript*> self(cx, this);
-
-    types->analysis->analyzeBytecode(cx);
+    RootedScript self(cx, this);
+
+    self->types->analysis->analyzeBytecode(cx);
 
     if (self->types->analysis->OOM()) {
         self->types->analysis = NULL;
         return false;
     }
 
     return true;
 }
@@ -5533,17 +5555,17 @@ JSFunction::setTypeForScriptedFunction(J
     }
 
     return true;
 }
 
 #ifdef DEBUG
 
 /* static */ void
-TypeScript::CheckBytecode(JSContext *cx, JSScript *script, jsbytecode *pc, const js::Value *sp)
+TypeScript::CheckBytecode(JSContext *cx, HandleScript script, jsbytecode *pc, const js::Value *sp)
 {
     AutoEnterTypeInference enter(cx);
 
     if (js_CodeSpec[*pc].format & JOF_DECOMPOSE)
         return;
 
     if (!script->hasAnalysis() || !script->analysis()->ranInference())
         return;
@@ -5676,18 +5698,17 @@ JSObject::makeLazyType(JSContext *cx)
     AutoEnterTypeInference enter(cx);
 
     /* Fill in the type according to the state of this object. */
 
     type->singleton = self;
 
     if (self->isFunction() && self->toFunction()->isInterpreted()) {
         type->interpretedFunction = self->toFunction();
-        JSScript *script = type->interpretedFunction->script();
-        if (script->uninlineable)
+        if (type->interpretedFunction->script()->uninlineable)
             type->flags |= OBJECT_FLAG_UNINLINEABLE;
     }
 
     if (self->lastProperty()->hasObjectFlag(BaseShape::ITERATED_SINGLETON))
         type->flags |= OBJECT_FLAG_ITERATED;
 
 #if JS_HAS_XML_SUPPORT
     /*
@@ -6211,17 +6232,17 @@ TypeCompartment::~TypeCompartment()
     if (objectTypeTable)
         js_delete(objectTypeTable);
 
     if (allocationSiteTable)
         js_delete(allocationSiteTable);
 }
 
 /* static */ void
-TypeScript::Sweep(FreeOp *fop, JSScript *script)
+TypeScript::Sweep(FreeOp *fop, RawScript script)
 {
     JSCompartment *compartment = script->compartment();
     JS_ASSERT(compartment->types.inferenceEnabled);
 
     unsigned num = NumTypeSets(script);
     TypeSet *typeArray = script->types->typeArray();
 
     /* Remove constraints and references to dead objects from the persistent type sets. */
@@ -6258,17 +6279,17 @@ TypeScript::destroy()
         js_delete(dynamicList);
         dynamicList = next;
     }
 
     js_free(this);
 }
 
 /* static */ void
-TypeScript::AddFreezeConstraints(JSContext *cx, JSScript *script)
+TypeScript::AddFreezeConstraints(JSContext *cx, HandleScript script)
 {
     /*
      * Adding freeze constraints to a script ensures that code for the script
      * will be recompiled any time any type set for stack values in the script
      * change: these type sets are implicitly frozen during compilation.
      *
      * To ensure this occurs, we don't need to add freeze constraints to the
      * type sets for every stack value, but rather only the input type sets
@@ -6291,17 +6312,17 @@ TypeScript::AddFreezeConstraints(JSConte
         if (types == returnTypes)
             continue;
         JS_ASSERT(types->constraintsPurged());
         types->add(cx, cx->analysisLifoAlloc().new_<TypeConstraintFreezeStack>(script), false);
     }
 }
 
 /* static */ void
-TypeScript::Purge(JSContext *cx, JSScript *script)
+TypeScript::Purge(JSContext *cx, HandleScript script)
 {
     if (!script->types)
         return;
 
     unsigned num = NumTypeSets(script);
     TypeSet *typeArray = script->types->typeArray();
     TypeSet *returnTypes = ReturnTypes(script);
 
@@ -6357,17 +6378,17 @@ TypeCompartment::maybePurgeAnalysis(JSCo
     AutoEnterTypeInference enter(cx);
 
     /* Reset the analysis pool, making its memory available for reuse. */
     cx->compartment->analysisLifoAlloc.releaseAll();
 
     uint64_t start = PRMJ_Now();
 
     for (gc::CellIter i(cx->compartment, gc::FINALIZE_SCRIPT); !i.done(); i.next()) {
-        JSScript *script = i.get<JSScript>();
+        RootedScript script(cx, i.get<JSScript>());
         TypeScript::Purge(cx, script);
     }
 
     uint64_t done = PRMJ_Now();
 
     if (cx->runtime->analysisPurgeCallback) {
         size_t afterUsed = cx->compartment->analysisLifoAlloc.used();
         size_t typeUsed = cx->compartment->typeLifoAlloc.used();
@@ -6423,17 +6444,17 @@ TypeObject::computedSizeOfExcludingThis(
         if (prop)
             bytes += sizeof(Property) + prop->types.computedSizeOfExcludingThis();
     }
 
     return bytes;
 }
 
 static void
-SizeOfScriptTypeInferenceData(JSScript *script, TypeInferenceSizes *sizes,
+SizeOfScriptTypeInferenceData(RawScript script, TypeInferenceSizes *sizes,
                               JSMallocSizeOfFun mallocSizeOf)
 {
     TypeScript *typeScript = script->types;
     if (!typeScript)
         return;
 
     /* If TI is disabled, a single TypeScript is still present. */
     if (!script->compartment()->types.inferenceEnabled) {
--- a/js/src/jsinfer.h
+++ b/js/src/jsinfer.h
@@ -535,29 +535,29 @@ class StackTypeSet : public TypeSet
      * Make a type set with the specified debugging name, not embedded in
      * another structure.
      */
     static StackTypeSet *make(JSContext *cx, const char *name);
 
     /* Constraints for type inference. */
 
     void addSubset(JSContext *cx, TypeSet *target);
-    void addGetProperty(JSContext *cx, JSScript *script, jsbytecode *pc,
+    void addGetProperty(JSContext *cx, HandleScript script, jsbytecode *pc,
                         StackTypeSet *target, jsid id);
-    void addSetProperty(JSContext *cx, JSScript *script, jsbytecode *pc,
+    void addSetProperty(JSContext *cx, HandleScript script, jsbytecode *pc,
                         StackTypeSet *target, jsid id);
-    void addSetElement(JSContext *cx, JSScript *script, jsbytecode *pc,
+    void addSetElement(JSContext *cx, HandleScript script, jsbytecode *pc,
                        StackTypeSet *objectTypes, StackTypeSet *valueTypes);
     void addCall(JSContext *cx, TypeCallsite *site);
-    void addArith(JSContext *cx, JSScript *script, jsbytecode *pc,
+    void addArith(JSContext *cx, HandleScript script, jsbytecode *pc,
                   TypeSet *target, TypeSet *other = NULL);
-    void addTransformThis(JSContext *cx, JSScript *script, TypeSet *target);
-    void addPropagateThis(JSContext *cx, JSScript *script, jsbytecode *pc,
+    void addTransformThis(JSContext *cx, HandleScript script, TypeSet *target);
+    void addPropagateThis(JSContext *cx, HandleScript script, jsbytecode *pc,
                           Type type, StackTypeSet *types = NULL);
-    void addSubsetBarrier(JSContext *cx, JSScript *script, jsbytecode *pc, TypeSet *target);
+    void addSubsetBarrier(JSContext *cx, HandleScript script, jsbytecode *pc, TypeSet *target);
 
     /*
      * Constraints for JIT compilation.
      *
      * Methods for JIT compilation. These must be used when a script is
      * currently being compiled (see AutoEnterCompilation) and will add
      * constraints ensuring that if the return value change in the future due
      * to new type information, the script's jitcode will be discarded.
@@ -601,28 +601,27 @@ class StackTypeSet : public TypeSet
  */
 class HeapTypeSet : public TypeSet
 {
   public:
 
     /* Constraints for type inference. */
 
     void addSubset(JSContext *cx, TypeSet *target);
-    void addGetProperty(JSContext *cx, JSScript *script, jsbytecode *pc,
+    void addGetProperty(JSContext *cx, HandleScript script, jsbytecode *pc,
                         StackTypeSet *target, jsid id);
-    void addCallProperty(JSContext *cx, JSScript *script, jsbytecode *pc, jsid id);
+    void addCallProperty(JSContext *cx, HandleScript script, jsbytecode *pc, jsid id);
     void addFilterPrimitives(JSContext *cx, TypeSet *target);
-    void addSubsetBarrier(JSContext *cx, JSScript *script, jsbytecode *pc, TypeSet *target);
+    void addSubsetBarrier(JSContext *cx, HandleScript script, jsbytecode *pc, TypeSet *target);
 
     /* Constraints for JIT compilation. */
 
     /* Completely freeze the contents of this type set. */
     void addFreeze(JSContext *cx);
 
-
     /*
      * Watch for a generic object state change on a type object. This currently
      * includes reallocations of slot pointers for global objects, and changes
      * to newScript data on types.
      */
     static void WatchObjectStateChange(JSContext *cx, TypeObject *object);
 
     /* Whether an object has any of a set of flags. */
@@ -1049,28 +1048,28 @@ struct TypeObjectEntry
 
     static inline HashNumber hash(TaggedProto base);
     static inline bool match(TypeObject *key, TaggedProto lookup);
 };
 typedef HashSet<ReadBarriered<TypeObject>, TypeObjectEntry, SystemAllocPolicy> TypeObjectSet;
 
 /* Whether to use a new type object when calling 'new' at script/pc. */
 bool
-UseNewType(JSContext *cx, JSScript *script, jsbytecode *pc);
+UseNewType(JSContext *cx, HandleScript script, jsbytecode *pc);
 
 /* Whether to use a new type object for an initializer opcode at script/pc. */
 bool
-UseNewTypeForInitializer(JSContext *cx, JSScript *script, jsbytecode *pc, JSProtoKey key);
+UseNewTypeForInitializer(JSContext *cx, HandleScript script, jsbytecode *pc, JSProtoKey key);
 
 /*
  * Whether Array.prototype, or an object on its proto chain, has an
  * indexed property.
  */
 bool
-ArrayPrototypeHasIndexedProperty(JSContext *cx, JSScript *script);
+ArrayPrototypeHasIndexedProperty(JSContext *cx, HandleScript script);
 
 /*
  * Type information about a callsite. this is separated from the bytecode
  * information itself so we can handle higher order functions not called
  * directly via a bytecode.
  */
 struct TypeCallsite
 {
@@ -1111,76 +1110,80 @@ class TypeScript
      * Generated the first time the script is analyzed by inference and kept
      * after analysis purges.
      */
     HeapTypeSet *propertyReadTypes;
 
     /* Array of type type sets for variables and JOF_TYPESET ops. */
     TypeSet *typeArray() { return (TypeSet *) (uintptr_t(this) + sizeof(TypeScript)); }
 
-    static inline unsigned NumTypeSets(JSScript *script);
+    static inline unsigned NumTypeSets(RawScript script);
 
-    static inline HeapTypeSet  *ReturnTypes(JSScript *script);
-    static inline StackTypeSet *ThisTypes(JSScript *script);
-    static inline StackTypeSet *ArgTypes(JSScript *script, unsigned i);
-    static inline StackTypeSet *LocalTypes(JSScript *script, unsigned i);
+    static inline HeapTypeSet  *ReturnTypes(RawScript script);
+    static inline StackTypeSet *ThisTypes(RawScript script);
+    static inline StackTypeSet *ArgTypes(RawScript script, unsigned i);
+    static inline StackTypeSet *LocalTypes(RawScript script, unsigned i);
 
     /* Follows slot layout in jsanalyze.h, can get this/arg/local type sets. */
-    static inline StackTypeSet *SlotTypes(JSScript *script, unsigned slot);
+    static inline StackTypeSet *SlotTypes(RawScript script, unsigned slot);
 
 #ifdef DEBUG
     /* Check that correct types were inferred for the values pushed by this bytecode. */
-    static void CheckBytecode(JSContext *cx, JSScript *script, jsbytecode *pc, const js::Value *sp);
+    static void CheckBytecode(JSContext *cx, HandleScript script, jsbytecode *pc,
+                              const js::Value *sp);
 #endif
 
     /* Get the default 'new' object for a given standard class, per the script's global. */
-    static inline TypeObject *StandardType(JSContext *cx, JSScript *script, JSProtoKey kind);
+    static inline TypeObject *StandardType(JSContext *cx, HandleScript script, JSProtoKey kind);
 
     /* Get a type object for an allocation site in this script. */
-    static inline TypeObject *InitObject(JSContext *cx, JSScript *script, jsbytecode *pc, JSProtoKey kind);
+    static inline TypeObject *InitObject(JSContext *cx, HandleScript script, jsbytecode *pc,
+                                         JSProtoKey kind);
 
     /*
      * Monitor a bytecode pushing a value which is not accounted for by the
      * inference type constraints, such as integer overflow.
      */
-    static inline void MonitorOverflow(JSContext *cx, JSScript *script, jsbytecode *pc);
-    static inline void MonitorString(JSContext *cx, JSScript *script, jsbytecode *pc);
-    static inline void MonitorUnknown(JSContext *cx, JSScript *script, jsbytecode *pc);
+    static inline void MonitorOverflow(JSContext *cx, HandleScript script, jsbytecode *pc);
+    static inline void MonitorString(JSContext *cx, HandleScript script, jsbytecode *pc);
+    static inline void MonitorUnknown(JSContext *cx, HandleScript script, jsbytecode *pc);
 
-    static inline void GetPcScript(JSContext *cx, JSScript **script, jsbytecode **pc);
+    static inline void GetPcScript(JSContext *cx, MutableHandleScript script, jsbytecode **pc);
     static inline void MonitorOverflow(JSContext *cx);
     static inline void MonitorString(JSContext *cx);
     static inline void MonitorUnknown(JSContext *cx);
 
     /*
      * Monitor a bytecode pushing any value. This must be called for any opcode
      * which is JOF_TYPESET, and where either the script has not been analyzed
      * by type inference or where the pc has type barriers. For simplicity, we
      * always monitor JOF_TYPESET opcodes in the interpreter and stub calls,
      * and only look at barriers when generating JIT code for the script.
      */
-    static inline void Monitor(JSContext *cx, JSScript *script, jsbytecode *pc,
+    static inline void Monitor(JSContext *cx, HandleScript script, jsbytecode *pc,
                                const js::Value &val);
     static inline void Monitor(JSContext *cx, const js::Value &rval);
 
     /* Monitor an assignment at a SETELEM on a non-integer identifier. */
     static inline void MonitorAssign(JSContext *cx, HandleObject obj, jsid id);
 
     /* Add a type for a variable in a script. */
-    static inline void SetThis(JSContext *cx, JSScript *script, Type type);
-    static inline void SetThis(JSContext *cx, JSScript *script, const js::Value &value);
-    static inline void SetLocal(JSContext *cx, JSScript *script, unsigned local, Type type);
-    static inline void SetLocal(JSContext *cx, JSScript *script, unsigned local, const js::Value &value);
-    static inline void SetArgument(JSContext *cx, JSScript *script, unsigned arg, Type type);
-    static inline void SetArgument(JSContext *cx, JSScript *script, unsigned arg, const js::Value &value);
+    static inline void SetThis(JSContext *cx, HandleScript script, Type type);
+    static inline void SetThis(JSContext *cx, HandleScript script, const js::Value &value);
+    static inline void SetLocal(JSContext *cx, HandleScript script, unsigned local, Type type);
+    static inline void SetLocal(JSContext *cx, HandleScript script, unsigned local,
+                                const js::Value &value);
+    static inline void SetArgument(JSContext *cx, HandleScript script, unsigned arg, Type type);
+    static inline void SetArgument(JSContext *cx, HandleScript script, unsigned arg,
+                                   const js::Value &value);
 
-    static void AddFreezeConstraints(JSContext *cx, JSScript *script);
-    static void Purge(JSContext *cx, JSScript *script);
+    static void AddFreezeConstraints(JSContext *cx, HandleScript script);
+    static void Purge(JSContext *cx, HandleScript script);
 
-    static void Sweep(FreeOp *fop, JSScript *script);
+    static void Sweep(FreeOp *fop, RawScript script);
     void destroy();
 };
 
 struct ArrayTableKey;
 typedef HashMap<ArrayTableKey,ReadBarriered<TypeObject>,ArrayTableKey,SystemAllocPolicy> ArrayTypeTable;
 
 struct ObjectTableKey;
 struct ObjectTableEntry;
@@ -1343,20 +1346,20 @@ struct TypeCompartment
     void processPendingRecompiles(FreeOp *fop);
 
     /* Mark all types as needing destruction once inference has 'finished'. */
     void setPendingNukeTypes(JSContext *cx);
     void setPendingNukeTypesNoReport();
 
     /* Mark a script as needing recompilation once inference has finished. */
     void addPendingRecompile(JSContext *cx, const RecompileInfo &info);
-    void addPendingRecompile(JSContext *cx, JSScript *script, jsbytecode *pc);
+    void addPendingRecompile(JSContext *cx, HandleScript script, jsbytecode *pc);
 
     /* Monitor future effects on a bytecode. */
-    void monitorBytecode(JSContext *cx, JSScript *script, uint32_t offset,
+    void monitorBytecode(JSContext *cx, HandleScript script, uint32_t offset,
                          bool returnOnly = false);
 
     /* Mark any type set containing obj as having a generic object type. */
     void markSetsUnknown(JSContext *cx, TypeObject *obj);
 
     void sweep(FreeOp *fop);
     void sweepCompilerOutputs(FreeOp *fop, bool discardConstraints);
 
--- a/js/src/jsinferinlines.h
+++ b/js/src/jsinferinlines.h
@@ -474,17 +474,17 @@ GetTypeNewObject(JSContext *cx, JSProtoK
 }
 
 /* Get a type object for the immediate allocation site within a native. */
 inline TypeObject *
 GetTypeCallerInitObject(JSContext *cx, JSProtoKey key)
 {
     if (cx->typeInferenceEnabled()) {
         jsbytecode *pc;
-        JSScript *script = cx->stack.currentScript(&pc);
+        RootedScript script(cx, cx->stack.currentScript(&pc));
         if (script)
             return TypeScript::InitObject(cx, script, pc, key);
     }
     return GetTypeNewObject(cx, key);
 }
 
 /*
  * When using a custom iterator within the initialization of a 'for in' loop,
@@ -631,24 +631,30 @@ FixArrayType(JSContext *cx, HandleObject
 inline void
 FixObjectType(JSContext *cx, HandleObject obj)
 {
     if (cx->typeInferenceEnabled())
         cx->compartment->types.fixObjectType(cx, obj);
 }
 
 /* Interface helpers for JSScript */
-extern void TypeMonitorResult(JSContext *cx, JSScript *script, jsbytecode *pc, const js::Value &rval);
-extern void TypeDynamicResult(JSContext *cx, JSScript *script, jsbytecode *pc, js::types::Type type);
+extern void TypeMonitorResult(JSContext *cx, HandleScript script, jsbytecode *pc,
+                              const js::Value &rval);
+extern void TypeDynamicResult(JSContext *cx, HandleScript script, jsbytecode *pc,
+                              js::types::Type type);
 
 inline bool
 UseNewTypeAtEntry(JSContext *cx, StackFrame *fp)
 {
-    return fp->isConstructing() && cx->typeInferenceEnabled() &&
-           fp->prev() && UseNewType(cx, fp->prev()->script(), fp->prevpc());
+
+    if (!fp->isConstructing() || !cx->typeInferenceEnabled() || !fp->prev())
+        return false;
+
+    RootedScript prevScript(cx, fp->prev()->script());
+    return UseNewType(cx, prevScript, fp->prevpc());
 }
 
 inline bool
 UseNewTypeForClone(JSFunction *fun)
 {
     if (fun->hasSingletonType() || !fun->isInterpreted())
         return false;
 
@@ -671,17 +677,17 @@ UseNewTypeForClone(JSFunction *fun)
      *
      * Each instance of the innermost function will have a different wrapped
      * initialize method. We capture this, along with similar cases, by looking
      * for short scripts which use both .apply and arguments. For such scripts,
      * whenever creating a new instance of the function we both give that
      * instance a singleton type and clone the underlying script.
      */
 
-    JSScript *script = fun->script();
+    RawScript script = fun->script();
 
     if (script->length >= 50)
         return false;
 
     if (script->hasConsts() || script->hasObjects() || script->hasRegexps() || fun->isHeavyweight())
         return false;
 
     bool hasArguments = false;
@@ -700,67 +706,67 @@ UseNewTypeForClone(JSFunction *fun)
     return hasArguments && hasApply;
 }
 
 /////////////////////////////////////////////////////////////////////
 // Script interface functions
 /////////////////////////////////////////////////////////////////////
 
 /* static */ inline unsigned
-TypeScript::NumTypeSets(JSScript *script)
+TypeScript::NumTypeSets(RawScript script)
 {
     return script->nTypeSets + analyze::TotalSlots(script);
 }
 
 /* static */ inline HeapTypeSet *
-TypeScript::ReturnTypes(JSScript *script)
+TypeScript::ReturnTypes(RawScript script)
 {
     TypeSet *types = script->types->typeArray() + script->nTypeSets + js::analyze::CalleeSlot();
     return types->toHeapTypeSet();
 }
 
 /* static */ inline StackTypeSet *
-TypeScript::ThisTypes(JSScript *script)
+TypeScript::ThisTypes(RawScript script)
 {
     TypeSet *types = script->types->typeArray() + script->nTypeSets + js::analyze::ThisSlot();
     return types->toStackTypeSet();
 }
 
 /*
  * Note: for non-escaping arguments and locals, argTypes/localTypes reflect
  * only the initial type of the variable (e.g. passed values for argTypes,
  * or undefined for localTypes) and not types from subsequent assignments.
  */
 
 /* static */ inline StackTypeSet *
-TypeScript::ArgTypes(JSScript *script, unsigned i)
+TypeScript::ArgTypes(RawScript script, unsigned i)
 {
     JS_ASSERT(i < script->function()->nargs);
     TypeSet *types = script->types->typeArray() + script->nTypeSets + js::analyze::ArgSlot(i);
     return types->toStackTypeSet();
 }
 
 /* static */ inline StackTypeSet *
-TypeScript::LocalTypes(JSScript *script, unsigned i)
+TypeScript::LocalTypes(RawScript script, unsigned i)
 {
     JS_ASSERT(i < script->nfixed);
     TypeSet *types = script->types->typeArray() + script->nTypeSets + js::analyze::LocalSlot(script, i);
     return types->toStackTypeSet();
 }
 
 /* static */ inline StackTypeSet *
-TypeScript::SlotTypes(JSScript *script, unsigned slot)
+TypeScript::SlotTypes(RawScript script, unsigned slot)
 {
     JS_ASSERT(slot < js::analyze::TotalSlots(script));
     TypeSet *types = script->types->typeArray() + script->nTypeSets + slot;
     return types->toStackTypeSet();
 }
 
 /* static */ inline TypeObject *
-TypeScript::StandardType(JSContext *cx, JSScript *script, JSProtoKey key)
+TypeScript::StandardType(JSContext *cx, HandleScript script, JSProtoKey key)
 {
     js::RootedObject proto(cx);
     if (!js_GetClassPrototype(cx, key, &proto, NULL))
         return NULL;
     return proto->getNewType(cx);
 }
 
 struct AllocationSiteKey {
@@ -780,17 +786,17 @@ struct AllocationSiteKey {
     }
 
     static inline bool match(const AllocationSiteKey &a, const AllocationSiteKey &b) {
         return a.script == b.script && a.offset == b.offset && a.kind == b.kind;
     }
 };
 
 /* static */ inline TypeObject *
-TypeScript::InitObject(JSContext *cx, JSScript *script, jsbytecode *pc, JSProtoKey kind)
+TypeScript::InitObject(JSContext *cx, HandleScript script, jsbytecode *pc, JSProtoKey kind)
 {
     JS_ASSERT(!UseNewTypeForInitializer(cx, script, pc, kind));
 
     /* :XXX: Limit script->length so we don't need to check the offset up front? */
     uint32_t offset = pc - script->code;
 
     if (!cx->typeInferenceEnabled() || !script->compileAndGo || offset >= AllocationSiteKey::OFFSET_LIMIT)
         return GetTypeNewObject(cx, kind);
@@ -836,87 +842,87 @@ SetInitializerObjectType(JSContext *cx, 
             return false;
         obj->setType(type);
     }
 
     return true;
 }
 
 /* static */ inline void
-TypeScript::Monitor(JSContext *cx, JSScript *script, jsbytecode *pc, const js::Value &rval)
+TypeScript::Monitor(JSContext *cx, HandleScript script, jsbytecode *pc, const js::Value &rval)
 {
     if (cx->typeInferenceEnabled())
         TypeMonitorResult(cx, script, pc, rval);
 }
 
 /* static */ inline void
-TypeScript::MonitorOverflow(JSContext *cx, JSScript *script, jsbytecode *pc)
+TypeScript::MonitorOverflow(JSContext *cx, HandleScript script, jsbytecode *pc)
 {
     if (cx->typeInferenceEnabled())
         TypeDynamicResult(cx, script, pc, Type::DoubleType());
 }
 
 /* static */ inline void
-TypeScript::MonitorString(JSContext *cx, JSScript *script, jsbytecode *pc)
+TypeScript::MonitorString(JSContext *cx, HandleScript script, jsbytecode *pc)
 {
     if (cx->typeInferenceEnabled())
         TypeDynamicResult(cx, script, pc, Type::StringType());
 }
 
 /* static */ inline void
-TypeScript::MonitorUnknown(JSContext *cx, JSScript *script, jsbytecode *pc)
+TypeScript::MonitorUnknown(JSContext *cx, HandleScript script, jsbytecode *pc)
 {
     if (cx->typeInferenceEnabled())
         TypeDynamicResult(cx, script, pc, Type::UnknownType());
 }
 
 /* static */ inline void
-TypeScript::GetPcScript(JSContext *cx, JSScript **script, jsbytecode **pc)
+TypeScript::GetPcScript(JSContext *cx, MutableHandleScript script, jsbytecode **pc)
 {
 #ifdef JS_ION
     if (cx->fp()->beginsIonActivation()) {
         ion::GetPcScript(cx, script, pc);
         return;
     }
 #endif
-    *script = cx->fp()->script();
+    script.set(cx->fp()->script());
     *pc = cx->regs().pc;
 }
 
 /* static */ inline void
 TypeScript::MonitorOverflow(JSContext *cx)
 {
-    JSScript *script;
+    RootedScript script(cx);
     jsbytecode *pc;
     GetPcScript(cx, &script, &pc);
     MonitorOverflow(cx, script, pc);
 }
 
 /* static */ inline void
 TypeScript::MonitorString(JSContext *cx)
 {
-    JSScript *script;
+    RootedScript script(cx);
     jsbytecode *pc;
     GetPcScript(cx, &script, &pc);
     MonitorString(cx, script, pc);
 }
 
 /* static */ inline void
 TypeScript::MonitorUnknown(JSContext *cx)
 {
-    JSScript *script;
+    RootedScript script(cx);
     jsbytecode *pc;
     GetPcScript(cx, &script, &pc);
     MonitorUnknown(cx, script, pc);
 }
 
 /* static */ inline void
 TypeScript::Monitor(JSContext *cx, const js::Value &rval)
 {
-    JSScript *script;
+    RootedScript script(cx);
     jsbytecode *pc;
     GetPcScript(cx, &script, &pc);
     Monitor(cx, script, pc, rval);
 }
 
 /* static */ inline void
 TypeScript::MonitorAssign(JSContext *cx, HandleObject obj, jsid id)
 {
@@ -932,17 +938,17 @@ TypeScript::MonitorAssign(JSContext *cx,
         uint32_t i;
         if (js_IdIsIndex(id, &i))
             return;
         MarkTypeObjectUnknownProperties(cx, obj->type());
     }
 }
 
 /* static */ inline void
-TypeScript::SetThis(JSContext *cx, JSScript *script, Type type)
+TypeScript::SetThis(JSContext *cx, HandleScript script, Type type)
 {
     if (!cx->typeInferenceEnabled())
         return;
     JS_ASSERT(script->types);
 
     /* Analyze the script regardless if -a was used. */
     bool analyze = cx->hasRunOption(JSOPTION_METHODJIT_ALWAYS);
 
@@ -954,65 +960,65 @@ TypeScript::SetThis(JSContext *cx, JSScr
         ThisTypes(script)->addType(cx, type);
 
         if (analyze)
             script->ensureRanInference(cx);
     }
 }
 
 /* static */ inline void
-TypeScript::SetThis(JSContext *cx, JSScript *script, const js::Value &value)
+TypeScript::SetThis(JSContext *cx, HandleScript script, const js::Value &value)
 {
     if (cx->typeInferenceEnabled())
         SetThis(cx, script, GetValueType(cx, value));
 }
 
 /* static */ inline void
-TypeScript::SetLocal(JSContext *cx, JSScript *script, unsigned local, Type type)
+TypeScript::SetLocal(JSContext *cx, HandleScript script, unsigned local, Type type)
 {
     if (!cx->typeInferenceEnabled())
         return;
     JS_ASSERT(script->types);
 
     if (!LocalTypes(script, local)->hasType(type)) {
         AutoEnterTypeInference enter(cx);
 
         InferSpew(ISpewOps, "externalType: setLocal #%u %u: %s",
                   script->id(), local, TypeString(type));
         LocalTypes(script, local)->addType(cx, type);
     }
 }
 
 /* static */ inline void
-TypeScript::SetLocal(JSContext *cx, JSScript *script, unsigned local, const js::Value &value)
+TypeScript::SetLocal(JSContext *cx, HandleScript script, unsigned local, const js::Value &value)
 {
     if (cx->typeInferenceEnabled()) {
         Type type = GetValueType(cx, value);
         SetLocal(cx, script, local, type);
     }
 }
 
 /* static */ inline void
-TypeScript::SetArgument(JSContext *cx, JSScript *script, unsigned arg, Type type)
+TypeScript::SetArgument(JSContext *cx, HandleScript script, unsigned arg, Type type)
 {
     if (!cx->typeInferenceEnabled())
         return;
     JS_ASSERT(script->types);
 
     if (!ArgTypes(script, arg)->hasType(type)) {
         AutoEnterTypeInference enter(cx);
 
         InferSpew(ISpewOps, "externalType: setArg #%u %u: %s",
                   script->id(), arg, TypeString(type));
         ArgTypes(script, arg)->addType(cx, type);
     }
 }
 
 /* static */ inline void
-TypeScript::SetArgument(JSContext *cx, JSScript *script, unsigned arg, const js::Value &value)
+TypeScript::SetArgument(JSContext *cx, HandleScript script, unsigned arg, const js::Value &value)
 {
     if (cx->typeInferenceEnabled()) {
         Type type = GetValueType(cx, value);
         SetArgument(cx, script, arg, type);
     }
 }
 
 /////////////////////////////////////////////////////////////////////
--- a/js/src/jsinterp.cpp
+++ b/js/src/jsinterp.cpp
@@ -1043,21 +1043,23 @@ IteratorNext(JSContext *cx, HandleObject
     return js_IteratorNext(cx, iterobj, rval);
 }
 
 /*
  * For bytecodes which push values and then fall through, make sure the
  * types of the pushed values are consistent with type inference information.
  */
 static inline void
-TypeCheckNextBytecode(JSContext *cx, JSScript *script, unsigned n, const FrameRegs &regs)
+TypeCheckNextBytecode(JSContext *cx, JSScript *script_, unsigned n, const FrameRegs &regs)
 {
 #ifdef DEBUG
     if (cx->typeInferenceEnabled() &&
-        n == GetBytecodeLength(regs.pc)) {
+        n == GetBytecodeLength(regs.pc))
+    {
+        RootedScript script(cx, script_);
         TypeScript::CheckBytecode(cx, script, regs.pc, regs.sp);
     }
 #endif
 }
 
 JS_NEVER_INLINE InterpretStatus
 js::Interpret(JSContext *cx, StackFrame *entryFrame, InterpMode interpMode)
 {
--- a/js/src/jsinterpinlines.h
+++ b/js/src/jsinterpinlines.h
@@ -701,17 +701,17 @@ GetObjectElementOperation(JSContext *cx,
             }
             if (!JSObject::getElement(cx, obj, obj, index, res))
                 return false;
         } while(0);
     } else {
         if (!cx->fp()->beginsIonActivation()) {
             // Don't update getStringElement if called from Ion code, since
             // ion::GetPcScript is expensive.
-            JSScript *script;
+            RootedScript script(cx);
             jsbytecode *pc;
             types::TypeScript::GetPcScript(cx, &script, &pc);
 
             if (script->hasAnalysis())
                 script->analysis()->getCode(pc).getStringElement = true;
         }
 
         SpecialId special;
@@ -804,17 +804,17 @@ SetObjectElementOperation(JSContext *cx,
                         break;
                     if ((uint32_t)i >= obj->getArrayLength())
                         JSObject::setArrayLength(cx, obj, i + 1);
                 }
                 JSObject::setDenseArrayElementWithType(cx, obj, i, value);
                 return true;
             } else {
                 if (!cx->fp()->beginsIonActivation()) {
-                    JSScript *script;
+                    RootedScript script(cx);
                     jsbytecode *pc;
                     types::TypeScript::GetPcScript(cx, &script, &pc);
 
                     if (script->hasAnalysis())
                         script->analysis()->getCode(pc).arrayWriteHole = true;
                 }
             }
         }
--- a/js/src/jsobj.cpp
+++ b/js/src/jsobj.cpp
@@ -2363,18 +2363,20 @@ js_CreateThisForFunctionWithProto(JSCont
         if (!type)
             return NULL;
         res = CreateThisForFunctionWithType(cx, type, callee->getParent());
     } else {
         gc::AllocKind kind = NewObjectGCKind(cx, &ObjectClass);
         res = NewObjectWithClassProto(cx, &ObjectClass, proto, callee->getParent(), kind);
     }
 
-    if (res && cx->typeInferenceEnabled())
-        TypeScript::SetThis(cx, callee->toFunction()->script(), types::Type::ObjectType(res));
+    if (res && cx->typeInferenceEnabled()) {
+        RootedScript script(cx, callee->toFunction()->script());
+        TypeScript::SetThis(cx, script, types::Type::ObjectType(res));
+    }
 
     return res;
 }
 
 JSObject *
 js_CreateThisForFunction(JSContext *cx, HandleObject callee, bool newType)
 {
     RootedValue protov(cx);
@@ -2393,17 +2395,17 @@ js_CreateThisForFunction(JSContext *cx, 
         /*
          * Reshape the object and give it a (lazily instantiated) singleton
          * type before passing it as the 'this' value for the call.
          */
         JSObject::clear(cx, nobj);
         if (!JSObject::setSingletonType(cx, nobj))
             return NULL;
 
-        JSScript *calleeScript = callee->toFunction()->script();
+        RootedScript calleeScript(cx, callee->toFunction()->script());
         TypeScript::SetThis(cx, calleeScript, types::Type::ObjectType(nobj));
 
         return nobj;
     }
 
     return obj;
 }
 
--- a/js/src/jspubtd.h
+++ b/js/src/jspubtd.h
@@ -235,16 +235,17 @@ enum ThingRootKind
     THING_ROOT_TYPE_OBJECT,
     THING_ROOT_STRING,
     THING_ROOT_SCRIPT,
     THING_ROOT_XML,
     THING_ROOT_ID,
     THING_ROOT_PROPERTY_ID,
     THING_ROOT_VALUE,
     THING_ROOT_TYPE,
+    THING_ROOT_BINDINGS,
     THING_ROOT_LIMIT
 };
 
 template <typename T>
 struct RootKind;
 
 /*
  * Specifically mark the ThingRootKind of externally visible types, so that
--- a/js/src/jsscript.cpp
+++ b/js/src/jsscript.cpp
@@ -88,19 +88,22 @@ Bindings::initWithTemporaryStorage(JSCon
      * aliased variables. While the debugger may observe any scope object at
      * any time, such accesses are mediated by DebugScopeProxy (see
      * DebugScopeProxy::handleUnaliasedAccess).
      */
 
     JS_STATIC_ASSERT(CallObject::RESERVED_SLOTS == 2);
     gc::AllocKind allocKind = gc::FINALIZE_OBJECT2_BACKGROUND;
     JS_ASSERT(gc::GetGCKindSlots(allocKind) == CallObject::RESERVED_SLOTS);
-    self->callObjShape_ =
+    RootedShape initial(cx,
         EmptyShape::getInitialShape(cx, &CallClass, NULL, cx->global(),
-                                    allocKind, BaseShape::VAROBJ | BaseShape::DELEGATE);
+                                    allocKind, BaseShape::VAROBJ | BaseShape::DELEGATE));
+    if (!initial)
+        return false;
+    self->callObjShape_.init(initial);
 
 #ifdef DEBUG
     HashSet<PropertyName *> added(cx);
     if (!added.init())
         return false;
 #endif
 
     BindingIter bi(*self);
@@ -164,16 +167,22 @@ Bindings::clone(JSContext *cx, InternalH
      * the source's bindingArray directly.
      */
     if (!initWithTemporaryStorage(cx, self, src.numArgs(), src.numVars(), src.bindingArray()))
         return false;
     self->switchToScriptStorage(dstPackedBindings);
     return true;
 }
 
+/* static */ Bindings
+RootMethods<Bindings>::initial()
+{
+    return Bindings();
+}
+
 template<XDRMode mode>
 static bool
 XDRScriptBindings(XDRState<mode> *xdr, LifoAllocScope &las, unsigned numArgs, unsigned numVars,
                   HandleScript script)
 {
     JSContext *cx = xdr->cx();
 
     if (mode == XDR_ENCODE) {
@@ -2085,19 +2094,19 @@ js::CloneScript(JSContext *cx, HandleObj
                                  nobjects, nregexps, ntrynotes, nconsts);
 
     uint8_t *data = AllocScriptData(cx, size);
     if (!data)
         return NULL;
 
     /* Bindings */
 
-    Bindings bindings;
+    Rooted<Bindings> bindings(cx);
     InternalHandle<Bindings*> bindingsHandle =
-        InternalHandle<Bindings*>::fromMarkedLocation(&bindings);
+        InternalHandle<Bindings*>::fromMarkedLocation(bindings.address());
     if (!Bindings::clone(cx, bindingsHandle, data, src))
         return NULL;
 
     /* Objects */
 
     AutoObjectVector objects(cx);
     if (nobjects != 0) {
         HeapPtrObject *vector = src->objects()->vector;
@@ -2605,8 +2614,9 @@ JSScript::formalIsAliased(unsigned argSl
     return bindings.bindingIsAliased(argSlot);
 }
 
 bool
 JSScript::formalLivesInArgumentsObject(unsigned argSlot)
 {
     return argsObjAliasesFormals() && !formalIsAliased(argSlot);
 }
+
--- a/js/src/jsscript.h
+++ b/js/src/jsscript.h
@@ -194,16 +194,25 @@ class Bindings
     bool bindingIsAliased(unsigned bindingIndex);
 
     /* Return whether this scope has any aliased bindings. */
     bool hasAnyAliasedBindings() const { return !callObjShape_->isEmptyShape(); }
 
     void trace(JSTracer *trc);
 };
 
+template <>
+struct RootMethods<Bindings> {
+    static Bindings initial();
+    static ThingRootKind kind() { return THING_ROOT_BINDINGS; }
+    static bool poisoned(const Bindings &bindings) {
+        return IsPoisonedPtr(bindings.callObjShape());
+    }
+};
+
 class ScriptCounts
 {
     friend struct ::JSScript;
     friend struct ScriptAndCounts;
     /*
      * This points to a single block that holds an array of PCCounts followed
      * by an array of doubles.  Each element in the PCCounts array has a
      * pointer into the array of doubles.
--- a/js/src/jstypedarray.cpp
+++ b/js/src/jstypedarray.cpp
@@ -546,31 +546,32 @@ ArrayBufferObject::obj_trace(JSTracer *t
 void
 ArrayBufferObject::sweepAll(JSRuntime *rt)
 {
     JSObject *buffer = rt->liveArrayBuffers;
     while (buffer) {
         JSObject **views = GetViewList(&buffer->asArrayBuffer());
         JS_ASSERT(*views);
         JSObject *nextBuffer = BufferLink(*views);
-        SetBufferLink(*views, UNSET_BUFFER_LINK);
 
         // Rebuild the list of views of the ArrayBuffer, discarding dead views
         JSObject *prevLiveView = NULL;
         JSObject *view = *views;
         while (view) {
             JSObject *nextView =
                 static_cast<JSObject*>(view->getFixedSlot(BufferView::NEXT_VIEW_SLOT).toPrivate());
             if (!JS_IsAboutToBeFinalized(view)) {
                 view->setFixedSlot(BufferView::NEXT_VIEW_SLOT, PrivateValue(prevLiveView));
                 prevLiveView = view;
             }
             view = nextView;
         }
         *views = prevLiveView;
+        if (*views)
+            SetBufferLink(*views, UNSET_BUFFER_LINK);
 
         buffer = nextBuffer;
     }
 
     rt->liveArrayBuffers = NULL;
 }
 
 JSBool
--- a/js/src/jsworkers.cpp
+++ b/js/src/jsworkers.cpp
@@ -34,17 +34,17 @@ js::StartOffThreadIonCompile(JSContext *
 /*
  * Move an IonBuilder for which compilation has either finished, failed, or
  * been cancelled into the Ion compartment's finished compilations list.
  * All off thread compilations which are started must eventually be finished.
  */
 static void
 FinishOffThreadIonCompile(ion::IonBuilder *builder)
 {
-    JSCompartment *compartment = builder->script->compartment();
+    JSCompartment *compartment = builder->script()->compartment();
     JS_ASSERT(compartment->rt->workerThreadState->isLocked());
 
     compartment->ionCompartment()->finishedOffThreadCompilations().append(builder);
 }
 
 static inline bool
 CompiledScriptMatches(JSCompartment *compartment, JSScript *script, JSScript *target)
 {
@@ -62,17 +62,17 @@ js::CancelOffThreadIonCompile(JSCompartm
     if (!ion)
         return;
 
     AutoLockWorkerThreadState lock(compartment->rt);
 
     /* Cancel any pending entries for which processing hasn't started. */
     for (size_t i = 0; i < state.ionWorklist.length(); i++) {
         ion::IonBuilder *builder = state.ionWorklist[i];
-        if (CompiledScriptMatches(compartment, script, builder->script)) {
+        if (CompiledScriptMatches(compartment, script, builder->script())) {
             FinishOffThreadIonCompile(builder);
             state.ionWorklist[i--] = state.ionWorklist.back();
             state.ionWorklist.popBack();
         }
     }
 
     /* Wait for in progress entries to finish up. */
     for (size_t i = 0; i < state.numThreads; i++) {
@@ -81,17 +81,17 @@ js::CancelOffThreadIonCompile(JSCompartm
             state.wait(WorkerThreadState::MAIN);
     }
 
     ion::OffThreadCompilationVector &compilations = ion->finishedOffThreadCompilations();
 
     /* Cancel code generation for any completed entries. */
     for (size_t i = 0; i < compilations.length(); i++) {
         ion::IonBuilder *builder = compilations[i];
-        if (CompiledScriptMatches(compartment, script, builder->script)) {
+        if (CompiledScriptMatches(compartment, script, builder->script())) {
             ion::FinishOffThreadBuilder(builder);
             compilations[i--] = compilations.back();
             compilations.popBack();
         }
     }
 }
 
 bool
@@ -256,17 +256,17 @@ WorkerThread::threadLoop()
             if (terminate) {
                 state.unlock();
                 return;
             }
             state.wait(WorkerThreadState::WORKER);
         }
 
         ion::IonBuilder *builder = state.ionWorklist.popCopy();
-        ionScript = builder->script;
+        ionScript = builder->script();
 
         JS_ASSERT(ionScript->ion == ION_COMPILING_SCRIPT);
 
         state.unlock();
 
         {
             ion::IonContext ictx(NULL, ionScript->compartment(), &builder->temp());
             ion::CompileBackEnd(builder);
--- a/js/src/methodjit/Compiler.cpp
+++ b/js/src/methodjit/Compiler.cpp
@@ -74,17 +74,17 @@ mjit::Compiler::Compiler(JSContext *cx, 
     isConstructing(isConstructing),
     outerChunk(outerJIT()->chunkDescriptor(chunkIndex)),
     ssa(cx, outerScript),
     globalObj(cx, outerScript->compileAndGo ? &outerScript->global() : NULL),
     globalSlots(globalObj ? globalObj->getRawSlots() : NULL),
     sps(&cx->runtime->spsProfiler),
     masm(&sps, &PC),
     frame(cx, *thisFromCtor(), masm, stubcc),
-    a(NULL), outer(NULL), script(NULL), PC(NULL), loop(NULL),
+    a(NULL), outer(NULL), script_(NULL), PC(NULL), loop(NULL),
     inlineFrames(CompilerAllocPolicy(cx, *thisFromCtor())),
     branchPatches(CompilerAllocPolicy(cx, *thisFromCtor())),
 #if defined JS_MONOIC
     getGlobalNames(CompilerAllocPolicy(cx, *thisFromCtor())),
     setGlobalNames(CompilerAllocPolicy(cx, *thisFromCtor())),
     callICs(CompilerAllocPolicy(cx, *thisFromCtor())),
     equalityICs(CompilerAllocPolicy(cx, *thisFromCtor())),
 #endif
@@ -473,34 +473,34 @@ mjit::Compiler::pushActiveFrame(JSScript
         CompileStatus status = prepareInferenceTypes(script, newa);
         if (status != Compile_Okay)
             return status;
     }
 
     if (script != outerScript && !sps.enterInlineFrame())
         return Compile_Error;
 
-    this->script = script;
+    this->script_ = script;
     this->analysis = newAnalysis;
     this->PC = script->code;
     this->a = newa;
 
     return Compile_Okay;
 }
 
 void
 mjit::Compiler::popActiveFrame()
 {
     JS_ASSERT(a->parent);
     a->mainCodeEnd = masm.size();
     a->stubCodeEnd = stubcc.size();
     this->PC = a->parentPC;
     this->a = (ActiveFrame *) a->parent;
-    this->script = a->script;
-    this->analysis = this->script->analysis();
+    this->script_ = a->script;
+    this->analysis = this->script_->analysis();
 
     frame.popActiveFrame();
     sps.leaveInlineFrame();
 }
 
 #define CHECK_STATUS(expr)                                           \
     JS_BEGIN_MACRO                                                   \
         CompileStatus status_ = (expr);                              \
@@ -552,17 +552,17 @@ mjit::Compiler::performCompilation()
             pcLengths = js_pod_calloc<PCLengthEntry>(length);
             if (!pcLengths)
                 return Compile_Error;
         }
 
         if (chunkIndex == 0)
             CHECK_STATUS(generatePrologue());
         else
-            sps.setPushed(script);
+            sps.setPushed(script_);
         CHECK_STATUS(generateMethod());
         if (outerJIT() && chunkIndex == outerJIT()->nchunks - 1)
             CHECK_STATUS(generateEpilogue());
         CHECK_STATUS(finishThisUp());
     }
 
 #ifdef JS_METHODJIT_SPEW
     prof.stop();
@@ -1119,77 +1119,77 @@ CompileStatus
 mjit::Compiler::generatePrologue()
 {
     fastEntryLabel = masm.label();
 
     /*
      * If there is no function, then this can only be called via JaegerShot(),
      * which expects an existing frame to be initialized like the interpreter.
      */
-    if (script->function()) {
+    if (script_->function()) {
         Jump j = masm.jump();
 
         /*
          * Entry point #2: The caller has partially constructed a frame, and
          * either argc >= nargs or the arity check has corrected the frame.
          */
         fastEntryLabel = masm.label();
 
         /* Store this early on so slow paths can access it. */
-        masm.storePtr(ImmPtr(script->function()),
+        masm.storePtr(ImmPtr(script_->function()),
                       Address(JSFrameReg, StackFrame::offsetOfExec()));
 
         {
             /*
              * Entry point #3: The caller has partially constructed a frame,
              * but argc might be != nargs, so an arity check might be called.
              *
              * This loops back to entry point #2.
              */
             arityLabel = stubcc.masm.label();
 
             Jump argMatch = stubcc.masm.branch32(Assembler::Equal, JSParamReg_Argc,
-                                                 Imm32(script->function()->nargs));
+                                                 Imm32(script_->function()->nargs));
 
             if (JSParamReg_Argc != Registers::ArgReg1)
                 stubcc.masm.move(JSParamReg_Argc, Registers::ArgReg1);
 
             /* Slow path - call the arity check function. Returns new fp. */
-            stubcc.masm.storePtr(ImmPtr(script->function()),
+            stubcc.masm.storePtr(ImmPtr(script_->function()),
                                  Address(JSFrameReg, StackFrame::offsetOfExec()));
             OOL_STUBCALL(stubs::FixupArity, REJOIN_NONE);
             stubcc.masm.move(Registers::ReturnReg, JSFrameReg);
             argMatch.linkTo(stubcc.masm.label(), &stubcc.masm);
 
             argsCheckLabel = stubcc.masm.label();
 
             /* Type check the arguments as well. */
             if (cx->typeInferenceEnabled()) {
 #ifdef JS_MONOIC
                 this->argsCheckJump = stubcc.masm.jump();
                 this->argsCheckStub = stubcc.masm.label();
                 this->argsCheckJump.linkTo(this->argsCheckStub, &stubcc.masm);
 #endif
-                stubcc.masm.storePtr(ImmPtr(script->function()),
+                stubcc.masm.storePtr(ImmPtr(script_->function()),
                                      Address(JSFrameReg, StackFrame::offsetOfExec()));
                 OOL_STUBCALL(stubs::CheckArgumentTypes, REJOIN_CHECK_ARGUMENTS);
 #ifdef JS_MONOIC
                 this->argsCheckFallthrough = stubcc.masm.label();
 #endif
             }
 
             stubcc.crossJump(stubcc.masm.jump(), fastEntryLabel);
         }
 
         /*
          * Guard that there is enough stack space. Note we reserve space for
          * any inline frames we end up generating, or a callee's stack frame
          * we write to before the callee checks the stack.
          */
-        uint32_t nvals = VALUES_PER_STACK_FRAME + script->nslots + StackSpace::STACK_JIT_EXTRA;
+        uint32_t nvals = VALUES_PER_STACK_FRAME + script_->nslots + StackSpace::STACK_JIT_EXTRA;
         masm.addPtr(Imm32(nvals * sizeof(Value)), JSFrameReg, Registers::ReturnReg);
         Jump stackCheck = masm.branchPtr(Assembler::AboveOrEqual, Registers::ReturnReg,
                                          FrameAddress(offsetof(VMFrame, stackLimit)));
 
         /*
          * If the stack check fails then we need to either commit more of the
          * reserved stack space or throw an error. Specify that the number of
          * local slots is 0 (instead of the default script->nfixed) since the
@@ -1205,60 +1205,60 @@ mjit::Compiler::generatePrologue()
         markUndefinedLocals();
 
         /*
          * Load the scope chain into the frame if it will be needed by NAME
          * opcodes or by the nesting prologue below. The scope chain is always
          * set for global and eval frames, and will have been set by
          * HeavyweightFunctionPrologue for heavyweight function frames.
          */
-        if (!script->function()->isHeavyweight() && analysis->usesScopeChain()) {
+        if (!script_->function()->isHeavyweight() && analysis->usesScopeChain()) {
             RegisterID t0 = Registers::ReturnReg;
             Jump hasScope = masm.branchTest32(Assembler::NonZero,
                                               FrameFlagsAddress(), Imm32(StackFrame::HAS_SCOPECHAIN));
-            masm.loadPayload(Address(JSFrameReg, StackFrame::offsetOfCallee(script->function())), t0);
+            masm.loadPayload(Address(JSFrameReg, StackFrame::offsetOfCallee(script_->function())), t0);
             masm.loadPtr(Address(t0, JSFunction::offsetOfEnvironment()), t0);
             masm.storePtr(t0, Address(JSFrameReg, StackFrame::offsetOfScopeChain()));
             hasScope.linkTo(masm.label(), &masm);
         }
 
         /*
          * When 'arguments' is used in the script, it may be optimized away
          * which involves reading from the stack frame directly, including
          * fp->u.nactual. fp->u.nactual is only set when numActual != numFormal,
          * so store 'fp->u.nactual = numFormal' when there is no over/underflow.
          */
-        if (script->argumentsHasVarBinding()) {
+        if (script_->argumentsHasVarBinding()) {
             Jump hasArgs = masm.branchTest32(Assembler::NonZero, FrameFlagsAddress(),
                                              Imm32(StackFrame::UNDERFLOW_ARGS |
                                                    StackFrame::OVERFLOW_ARGS));
-            masm.storePtr(ImmPtr((void *)(size_t) script->function()->nargs),
+            masm.storePtr(ImmPtr((void *)(size_t) script_->function()->nargs),
                           Address(JSFrameReg, StackFrame::offsetOfNumActual()));
             hasArgs.linkTo(masm.label(), &masm);
         }
 
         j.linkTo(masm.label(), &masm);
     }
 
     if (cx->typeInferenceEnabled()) {
 #ifdef DEBUG
-        if (script->function()) {
+        if (script_->function()) {
             prepareStubCall(Uses(0));
             INLINE_STUBCALL(stubs::AssertArgumentTypes, REJOIN_NONE);
         }
 #endif
         ensureDoubleArguments();
     }
 
     /* Inline StackFrame::prologue. */
-    if (script->isActiveEval && script->strictModeCode) {
+    if (script_->isActiveEval && script_->strictModeCode) {
         prepareStubCall(Uses(0));
         INLINE_STUBCALL(stubs::StrictEvalPrologue, REJOIN_EVAL_PROLOGUE);
-    } else if (script->function()) {
-        if (script->function()->isHeavyweight()) {
+    } else if (script_->function()) {
+        if (script_->function()->isHeavyweight()) {
             prepareStubCall(Uses(0));
             INLINE_STUBCALL(stubs::HeavyweightFunctionPrologue, REJOIN_FUNCTION_PROLOGUE);
         }
 
         if (isConstructing && !constructThis())
             return Compile_Error;
     }
 
@@ -1272,28 +1272,28 @@ mjit::Compiler::generatePrologue()
 
     return status;
 }
 
 void
 mjit::Compiler::ensureDoubleArguments()
 {
     /* Convert integer arguments which were inferred as (int|double) to doubles. */
-    for (uint32_t i = 0; script->function() && i < script->function()->nargs; i++) {
+    for (uint32_t i = 0; script_->function() && i < script_->function()->nargs; i++) {
         uint32_t slot = ArgSlot(i);
         if (a->varTypes[slot].getTypeTag() == JSVAL_TYPE_DOUBLE && analysis->trackSlot(slot))
             frame.ensureDouble(frame.getArg(i));
     }
 }
 
 void
 mjit::Compiler::markUndefinedLocal(uint32_t offset, uint32_t i)
 {
     uint32_t depth = ssa.getFrame(a->inlineIndex).depth;
-    uint32_t slot = LocalSlot(script, i);
+    uint32_t slot = LocalSlot(script_, i);
     Address local(JSFrameReg, sizeof(StackFrame) + (depth + i) * sizeof(Value));
     if (!cx->typeInferenceEnabled() || !analysis->trackSlot(slot)) {
         masm.storeValue(UndefinedValue(), local);
     } else {
         Lifetime *lifetime = analysis->liveness(slot).live(offset);
         if (lifetime)
             masm.storeValue(UndefinedValue(), local);
 #ifdef DEBUG
@@ -1305,22 +1305,22 @@ mjit::Compiler::markUndefinedLocal(uint3
 
 void
 mjit::Compiler::markUndefinedLocals()
 {
     /*
      * Set locals to undefined. Skip locals which aren't closed and are known
      * to be defined before used,
      */
-    for (uint32_t i = 0; i < script->nfixed; i++)
+    for (uint32_t i = 0; i < script_->nfixed; i++)
         markUndefinedLocal(0, i);
 
 #ifdef DEBUG
     uint32_t depth = ssa.getFrame(a->inlineIndex).depth;
-    for (uint32_t i = script->nfixed; i < script->nslots; i++) {
+    for (uint32_t i = script_->nfixed; i < script_->nslots; i++) {
         Address local(JSFrameReg, sizeof(StackFrame) + (depth + i) * sizeof(Value));
         masm.storeValue(ObjectValueCrashOnTouch(), local);
     }
 #endif
 }
 
 CompileStatus
 mjit::Compiler::generateEpilogue()
@@ -1447,24 +1447,24 @@ mjit::Compiler::finishThisUp()
         execPool->release();
         js_ReportOutOfMemory(cx);
         return Compile_Error;
     }
 
     JITChunk *chunk = new(cursor) JITChunk;
     cursor += sizeof(JITChunk);
 
-    JS_ASSERT(outerScript == script);
+    JS_ASSERT(outerScript == script_);
 
     chunk->code = JSC::MacroAssemblerCodeRef(result, execPool, masm.size() + stubcc.size());
     chunk->pcLengths = pcLengths;
 
     if (chunkIndex == 0) {
         jit->invokeEntry = result;
-        if (script->function()) {
+        if (script_->function()) {
             jit->arityCheckEntry = stubCode.locationOf(arityLabel).executableAddress();
             jit->argsCheckEntry = stubCode.locationOf(argsCheckLabel).executableAddress();
             jit->fastEntry = fullCode.locationOf(fastEntryLabel).executableAddress();
         }
     }
 
     /*
      * WARNING: mics(), callICs() et al depend on the ordering of these
@@ -1581,17 +1581,17 @@ mjit::Compiler::finishThisUp()
 
     uint32_t *jitTypeBarrierBytecodes = (uint32_t *)cursor;
     chunk->nTypeBarrierBytecodes = typeBarrierBytecodes.length();
     cursor += sizeof(uint32_t) * chunk->nTypeBarrierBytecodes;
     for (size_t i = 0; i < chunk->nTypeBarrierBytecodes; i++)
         jitTypeBarrierBytecodes[i] = typeBarrierBytecodes[i];
 
 #if defined JS_MONOIC
-    if (chunkIndex == 0 && script->function()) {
+    if (chunkIndex == 0 && script_->function()) {
         JS_ASSERT(jit->argsCheckPool == NULL);
         if (cx->typeInferenceEnabled()) {
             jit->argsCheckStub = stubCode.locationOf(argsCheckStub);
             jit->argsCheckFallthrough = stubCode.locationOf(argsCheckFallthrough);
             jit->argsCheckJump = stubCode.locationOf(argsCheckJump);
         }
     }
 
@@ -1707,17 +1707,17 @@ mjit::Compiler::finishThisUp()
 
     ic::EqualityICInfo *jitEqualityICs = (ic::EqualityICInfo *)cursor;
     chunk->nEqualityICs = equalityICs.length();
     cursor += sizeof(ic::EqualityICInfo) * chunk->nEqualityICs;
     for (size_t i = 0; i < chunk->nEqualityICs; i++) {
         if (equalityICs[i].trampoline) {
             jitEqualityICs[i].target = stubCode.locationOf(equalityICs[i].trampolineStart);
         } else {
-            uint32_t offs = uint32_t(equalityICs[i].jumpTarget - script->code);
+            uint32_t offs = uint32_t(equalityICs[i].jumpTarget - script_->code);
             JS_ASSERT(jumpMap[offs].isSet());
             jitEqualityICs[i].target = fullCode.locationOf(jumpMap[offs]);
         }
         jitEqualityICs[i].stubEntry = stubCode.locationOf(equalityICs[i].stubEntry);
         jitEqualityICs[i].stubCall = stubCode.locationOf(equalityICs[i].stubCall);
         jitEqualityICs[i].stub = equalityICs[i].stub;
         jitEqualityICs[i].lvr = equalityICs[i].lvr;
         jitEqualityICs[i].rvr = equalityICs[i].rvr;
@@ -1778,17 +1778,17 @@ mjit::Compiler::finishThisUp()
     cursor += sizeof(ic::SetElementIC) * chunk->nSetElems;
     for (size_t i = 0; i < chunk->nSetElems; i++) {
         ic::SetElementIC &to = jitSetElems[i];
         SetElementICInfo &from = setElemICs[i];
 
         new (&to) ic::SetElementIC();
         from.copyTo(to, fullCode, stubCode);
 
-        to.strictMode = script->strictModeCode;
+        to.strictMode = script_->strictModeCode;
         to.vr = from.vr;
         to.objReg = from.objReg;
         to.objRemat = from.objRemat.toInt32();
         JS_ASSERT(to.objRemat == from.objRemat.toInt32());
 
         to.hasConstantKey = from.key.isConstant();
         if (from.key.isConstant())
             to.keyValue = from.key.index();
@@ -1863,17 +1863,17 @@ mjit::Compiler::finishThisUp()
     double *oolDoubles = (double*) (result + doubleOffset +
                                     masm.numDoubles() * sizeof(double));
 
     /* Generate jump tables. */
     void **jumpVec = (void **)(oolDoubles + stubcc.masm.numDoubles());
 
     for (size_t i = 0; i < jumpTableEdges.length(); i++) {
         JumpTableEdge edge = jumpTableEdges[i];
-        if (bytecodeInChunk(script->code + edge.target)) {
+        if (bytecodeInChunk(script_->code + edge.target)) {
             JS_ASSERT(jumpMap[edge.target].isSet());
             jumpVec[i] = (void *)(result + masm.distanceOf(jumpMap[edge.target]));
         } else {
             ChunkJumpTableEdge nedge;
             nedge.edge = edge;
             nedge.jumpTableEntry = &jumpVec[i];
             chunkJumps.infallibleAppend(nedge);
             jumpVec[i] = NULL;
@@ -1910,17 +1910,17 @@ mjit::Compiler::finishThisUp()
     /* Patch all incoming and outgoing cross-chunk jumps. */
     CrossChunkEdge *crossEdges = jit->edges();
     for (unsigned i = 0; i < jit->nedges; i++) {
         CrossChunkEdge &edge = crossEdges[i];
         if (bytecodeInChunk(outerScript->code + edge.source)) {
             JS_ASSERT(!edge.sourceJump1 && !edge.sourceJump2);
             void *label = edge.targetLabel ? edge.targetLabel : edge.shimLabel;
             CodeLocationLabel targetLabel(label);
-            JSOp op = JSOp(script->code[edge.source]);
+            JSOp op = JSOp(script_->code[edge.source]);
             if (op == JSOP_TABLESWITCH) {
                 if (edge.jumpTableEntries)
                     js_free(edge.jumpTableEntries);
                 CrossChunkEdge::JumpTableEntryVector *jumpTableEntries = NULL;
                 bool failed = false;
                 for (unsigned j = 0; j < chunkJumps.length(); j++) {
                     ChunkJumpTableEdge nedge = chunkJumps[j];
                     if (nedge.edge.source == edge.source && nedge.edge.target == edge.target) {
@@ -1978,18 +1978,18 @@ mjit::Compiler::finishThisUp()
 }
 
 #ifdef DEBUG
 #define SPEW_OPCODE()                                                         \
     JS_BEGIN_MACRO                                                            \
         if (IsJaegerSpewChannelActive(JSpew_JSOps)) {                         \
             Sprinter sprinter(cx);                                            \
             sprinter.init();                                                  \
-            RootedScript script_(cx, script);                                 \
-            js_Disassemble1(cx, script_, PC, PC - script->code,               \
+            RootedScript script(cx, script_);                                 \
+            js_Disassemble1(cx, script, PC, PC - script_->code,               \
                             JS_TRUE, &sprinter);                              \
             JaegerSpew(JSpew_JSOps, "    %2d %s",                             \
                        frame.stackDepth(), sprinter.string());                \
         }                                                                     \
     JS_END_MACRO;
 #else
 #define SPEW_OPCODE()
 #endif /* DEBUG */
@@ -2012,62 +2012,62 @@ inline bool
 mjit::Compiler::shouldStartLoop(jsbytecode *head)
 {
     /*
      * Don't do loop based optimizations or register allocation for loops which
      * span multiple chunks.
      */
     if (*head == JSOP_LOOPHEAD && analysis->getLoop(head)) {
         uint32_t backedge = analysis->getLoop(head)->backedge;
-        if (!bytecodeInChunk(script->code + backedge))
+        if (!bytecodeInChunk(script_->code + backedge))
             return false;
         return true;
     }
     return false;
 }
 
 CompileStatus
 mjit::Compiler::generateMethod()
 {
-    SrcNoteLineScanner scanner(script->notes(), script->lineno);
+    SrcNoteLineScanner scanner(script_->notes(), script_->lineno);
 
     /* For join points, whether there was fallthrough from the previous opcode. */
     bool fallthrough = true;
 
     /* Last bytecode processed. */
     jsbytecode *lastPC = NULL;
 
     if (!outerJIT())
         return Compile_Retry;
 
-    uint32_t chunkBegin = 0, chunkEnd = script->length;
+    uint32_t chunkBegin = 0, chunkEnd = script_->length;
     if (!a->parent) {
         const ChunkDescriptor &desc =
             outerJIT()->chunkDescriptor(chunkIndex);
         chunkBegin = desc.begin;
         chunkEnd = desc.end;
 
-        while (PC != script->code + chunkBegin) {
+        while (PC != script_->code + chunkBegin) {
             Bytecode *opinfo = analysis->maybeCode(PC);
             if (opinfo) {
                 if (opinfo->jumpTarget) {
                     /* Update variable types for all new values at this bytecode. */
                     const SlotValue *newv = analysis->newValues(PC);
                     if (newv) {
                         while (newv->slot) {
-                            if (newv->slot < TotalSlots(script)) {
+                            if (newv->slot < TotalSlots(script_)) {
                                 VarType &vt = a->varTypes[newv->slot];
                                 vt.setTypes(analysis->getValueTypes(newv->value));
                             }
                             newv++;
                         }
                     }
                 }
                 if (analyze::BytecodeUpdatesSlot(JSOp(*PC))) {
-                    uint32_t slot = GetBytecodeSlot(script, PC);
+                    uint32_t slot = GetBytecodeSlot(script_, PC);
                     if (analysis->trackSlot(slot)) {
                         VarType &vt = a->varTypes[slot];
                         vt.setTypes(analysis->pushedTypes(PC, 0));
                     }
                 }
             }
 
             PC += GetBytecodeLength(PC);
@@ -2079,36 +2079,36 @@ mjit::Compiler::generateMethod()
                 frame.pushSynced(JSVAL_TYPE_UNKNOWN);
         }
     }
 
     for (;;) {
         JSOp op = JSOp(*PC);
         int trap = stubs::JSTRAP_NONE;
 
-        if (script->hasBreakpointsAt(PC))
+        if (script_->hasBreakpointsAt(PC))
             trap |= stubs::JSTRAP_TRAP;
 
         Bytecode *opinfo = analysis->maybeCode(PC);
 
         if (!opinfo) {
             if (op == JSOP_STOP)
                 break;
             if (js_CodeSpec[op].length != -1)
                 PC += js_CodeSpec[op].length;
             else
                 PC += js_GetVariableBytecodeLength(PC);
             continue;
         }
 
-        if (PC >= script->code + script->length)
+        if (PC >= script_->code + script_->length)
             break;
 
-        scanner.advanceTo(PC - script->code);
-        if (script->stepModeEnabled() &&
+        scanner.advanceTo(PC - script_->code);
+        if (script_->stepModeEnabled() &&
             (scanner.isLineHeader() || opinfo->jumpTarget))
         {
             trap |= stubs::JSTRAP_SINGLESTEP;
         }
 
         frame.setPC(PC);
         frame.setInTryBlock(opinfo->inTryBlock);
 
@@ -2127,17 +2127,17 @@ mjit::Compiler::generateMethod()
             for (unsigned i = 0; i < fixedDoubleToAnyEntries.length(); i++) {
                 FrameEntry *fe = frame.getSlotEntry(fixedDoubleToAnyEntries[i]);
                 frame.syncAndForgetFe(fe);
             }
         }
         fixedIntToDoubleEntries.clear();
         fixedDoubleToAnyEntries.clear();
 
-        if (PC >= script->code + chunkEnd) {
+        if (PC >= script_->code + chunkEnd) {
             if (fallthrough) {
                 if (opinfo->jumpTarget)
                     fixDoubleTypes(PC);
                 frame.syncAndForgetEverything();
                 jsbytecode *curPC = PC;
                 do {
                     PC--;
                 } while (!analysis->maybeCode(PC));
@@ -2167,17 +2167,17 @@ mjit::Compiler::generateMethod()
                         return Compile_Error;
                 } else {
                     Label start = masm.label();
                     if (!frame.syncForBranch(PC, Uses(0)))
                         return Compile_Error;
                     if (pcLengths && lastPC) {
                         /* Track this sync code for the previous op. */
                         size_t length = masm.size() - masm.distanceOf(start);
-                        uint32_t offset = ssa.frameLength(a->inlineIndex) + lastPC - script->code;
+                        uint32_t offset = ssa.frameLength(a->inlineIndex) + lastPC - script_->code;
                         pcLengths[offset].codeLengthAugment += length;
                     }
                     JS_ASSERT(frame.consistentRegisters(PC));
                 }
             }
 
             if (!frame.discardForJoin(analysis->getAllocation(PC), opinfo->stackDepth))
                 return Compile_Error;
@@ -2187,30 +2187,30 @@ mjit::Compiler::generateMethod()
             if (!cx->typeInferenceEnabled()) {
                 /* All join points have synced state if we aren't doing cross-branch regalloc. */
                 opinfo->safePoint = true;
             }
         } else if (opinfo->safePoint) {
             frame.syncAndForgetEverything();
         }
         frame.assertValidRegisterState();
-        a->jumpMap[uint32_t(PC - script->code)] = masm.label();
+        a->jumpMap[uint32_t(PC - script_->code)] = masm.label();
 
         if (cx->typeInferenceEnabled() && opinfo->safePoint) {
             /*
              * We may have come in from a table switch, which does not watch
              * for the new types introduced for variables at each dispatch
              * target. Make sure that new SSA values at this safe point with
              * double type have the correct in memory representation.
              */
             const SlotValue *newv = analysis->newValues(PC);
             if (newv) {
                 while (newv->slot) {
                     if (newv->value.kind() == SSAValue::PHI &&
-                        newv->value.phiOffset() == uint32_t(PC - script->code) &&
+                        newv->value.phiOffset() == uint32_t(PC - script_->code) &&
                         analysis->trackSlot(newv->slot) &&
                         a->varTypes[newv->slot].getTypeTag() == JSVAL_TYPE_DOUBLE) {
                         FrameEntry *fe = frame.getSlotEntry(newv->slot);
                         masm.ensureInMemoryDouble(frame.addressOf(fe));
                     }
                     newv++;
                 }
             }
@@ -2221,19 +2221,19 @@ mjit::Compiler::generateMethod()
         // are allocated later on.
         if (loop && !a->parent)
             loop->setOuterPC(PC);
 
         SPEW_OPCODE();
         JS_ASSERT(frame.stackDepth() == opinfo->stackDepth);
 
         if (op == JSOP_LOOPHEAD && analysis->getLoop(PC)) {
-            jsbytecode *backedge = script->code + analysis->getLoop(PC)->backedge;
+            jsbytecode *backedge = script_->code + analysis->getLoop(PC)->backedge;
             if (!bytecodeInChunk(backedge)){
-                for (uint32_t slot = ArgSlot(0); slot < TotalSlots(script); slot++) {
+                for (uint32_t slot = ArgSlot(0); slot < TotalSlots(script_); slot++) {
                     if (a->varTypes[slot].getTypeTag() == JSVAL_TYPE_DOUBLE) {
                         FrameEntry *fe = frame.getSlotEntry(slot);
                         masm.ensureInMemoryDouble(frame.addressOf(fe));
                     }
                 }
             }
         }
 
@@ -2261,18 +2261,18 @@ mjit::Compiler::generateMethod()
 
         Label inlineStart = masm.label();
         Label stubStart = stubcc.masm.label();
         bool countsUpdated = false;
         bool arithUpdated = false;
 
         JSValueType arithFirstUseType = JSVAL_TYPE_UNKNOWN;
         JSValueType arithSecondUseType = JSVAL_TYPE_UNKNOWN;
-        if (script->hasScriptCounts && !!(js_CodeSpec[op].format & JOF_ARITH)) {
-            if (GetUseCount(script, PC - script->code) == 1) {
+        if (script_->hasScriptCounts && !!(js_CodeSpec[op].format & JOF_ARITH)) {
+            if (GetUseCount(script_, PC - script_->code) == 1) {
                 FrameEntry *use = frame.peek(-1);
                 /*
                  * Pretend it's a binary operation and the second operand has
                  * the same type as the first one.
                  */
                 if (use->isTypeKnown())
                     arithFirstUseType = arithSecondUseType = use->getKnownType();
             } else {
@@ -2285,32 +2285,32 @@ mjit::Compiler::generateMethod()
             }
         }
 
         /*
          * Update PC counts for jump opcodes at their start, so that we don't
          * miss them when taking the jump. This is delayed for other opcodes,
          * as we want to skip updating for ops we didn't generate any code for.
          */
-        if (script->hasScriptCounts && JOF_OPTYPE(op) == JOF_JUMP)
+        if (script_->hasScriptCounts && JOF_OPTYPE(op) == JOF_JUMP)
             updatePCCounts(PC, &countsUpdated);
 
     /**********************
      * BEGIN COMPILER OPS *
      **********************/
 
         lastPC = PC;
 
         switch (op) {
           BEGIN_CASE(JSOP_NOP)
           END_CASE(JSOP_NOP)
 
           BEGIN_CASE(JSOP_NOTEARG)
           END_CASE(JSOP_NOTEARG)
-          
+
           BEGIN_CASE(JSOP_UNDEFINED)
             frame.push(UndefinedValue());
           END_CASE(JSOP_UNDEFINED)
 
           BEGIN_CASE(JSOP_POPV)
           BEGIN_CASE(JSOP_SETRVAL)
           {
             RegisterID reg = frame.allocReg();
@@ -2324,27 +2324,27 @@ mjit::Compiler::generateMethod()
 
             FrameEntry *fe = frame.peek(-1);
             frame.storeTo(fe, Address(JSFrameReg, StackFrame::offsetOfReturnValue()), true);
             frame.pop();
           }
           END_CASE(JSOP_POPV)
 
           BEGIN_CASE(JSOP_RETURN)
-            if (script->hasScriptCounts)
+            if (script_->hasScriptCounts)
                 updatePCCounts(PC, &countsUpdated);
             emitReturn(frame.peek(-1));
             fallthrough = false;
           END_CASE(JSOP_RETURN)
 
           BEGIN_CASE(JSOP_GOTO)
           BEGIN_CASE(JSOP_DEFAULT)
           {
-            unsigned targetOffset = FollowBranch(cx, script, PC - script->code);
-            jsbytecode *target = script->code + targetOffset;
+            unsigned targetOffset = FollowBranch(cx, script_, PC - script_->code);
+            jsbytecode *target = script_->code + targetOffset;
 
             fixDoubleTypes(target);
 
             /*
              * Watch for gotos which are entering a 'for' or 'while' loop.
              * These jump to the loop condition test and are immediately
              * followed by the head of the loop.
              */
@@ -2378,17 +2378,17 @@ mjit::Compiler::generateMethod()
             if (!jsop_ifneq(op, target))
                 return Compile_Error;
             PC += js_CodeSpec[op].length;
             break;
           }
           END_CASE(JSOP_IFNE)
 
           BEGIN_CASE(JSOP_ARGUMENTS)
-            if (script->needsArgsObj()) {
+            if (script_->needsArgsObj()) {
                 prepareStubCall(Uses(0));
                 INLINE_STUBCALL(stubs::Arguments, REJOIN_FALLTHROUGH);
                 pushSyncedEntry(0);
             } else {
                 frame.push(MagicValue(JS_OPTIMIZED_ARGUMENTS));
             }
           END_CASE(JSOP_ARGUMENTS)
 
@@ -2445,31 +2445,31 @@ mjit::Compiler::generateMethod()
 
           BEGIN_CASE(JSOP_LT)
           BEGIN_CASE(JSOP_LE)
           BEGIN_CASE(JSOP_GT)
           BEGIN_CASE(JSOP_GE)
           BEGIN_CASE(JSOP_EQ)
           BEGIN_CASE(JSOP_NE)
           {
-           if (script->hasScriptCounts) {
+           if (script_->hasScriptCounts) {
                updateArithCounts(PC, NULL, arithFirstUseType, arithSecondUseType);
                arithUpdated = true;
            }
 
             /* Detect fusions. */
             jsbytecode *next = &PC[JSOP_GE_LENGTH];
             JSOp fused = JSOp(*next);
             if ((fused != JSOP_IFEQ && fused != JSOP_IFNE) || analysis->jumpTarget(next))
                 fused = JSOP_NOP;
 
             /* Get jump target, if any. */
             jsbytecode *target = NULL;
             if (fused != JSOP_NOP) {
-                if (script->hasScriptCounts)
+                if (script_->hasScriptCounts)
                     updatePCCounts(PC, &countsUpdated);
                 target = next + GET_JUMP_OFFSET(next);
                 fixDoubleTypes(target);
             }
 
             BoolStub stub = NULL;
             switch (op) {
               case JSOP_LT:
@@ -2613,16 +2613,17 @@ mjit::Compiler::generateMethod()
                 double d;
                 JS_ALWAYS_TRUE(ToNumber(cx, top->getValue(), &d));
                 d = -d;
                 Value v = NumberValue(d);
 
                 /* Watch for overflow in constant propagation. */
                 types::TypeSet *pushed = pushedTypeSet(0);
                 if (!v.isInt32() && pushed && !pushed->hasType(types::Type::DoubleType())) {
+                    RootedScript script(cx, script_);
                     types::TypeScript::MonitorOverflow(cx, script, PC);
                     return Compile_Retry;
                 }
 
                 frame.pop();
                 frame.push(v);
             } else {
                 jsop_neg();
@@ -2632,42 +2633,42 @@ mjit::Compiler::generateMethod()
 
           BEGIN_CASE(JSOP_POS)
             jsop_pos();
           END_CASE(JSOP_POS)
 
           BEGIN_CASE(JSOP_DELNAME)
           {
             uint32_t index = GET_UINT32_INDEX(PC);
-            PropertyName *name = script->getName(index);
+            PropertyName *name = script_->getName(index);
 
             prepareStubCall(Uses(0));
             masm.move(ImmPtr(name), Registers::ArgReg1);
             INLINE_STUBCALL(stubs::DelName, REJOIN_FALLTHROUGH);
             pushSyncedEntry(0);
           }
           END_CASE(JSOP_DELNAME)
 
           BEGIN_CASE(JSOP_DELPROP)
           {
             uint32_t index = GET_UINT32_INDEX(PC);
-            PropertyName *name = script->getName(index);
+            PropertyName *name = script_->getName(index);
 
             prepareStubCall(Uses(1));
             masm.move(ImmPtr(name), Registers::ArgReg1);
-            INLINE_STUBCALL(STRICT_VARIANT(script, stubs::DelProp), REJOIN_FALLTHROUGH);
+            INLINE_STUBCALL(STRICT_VARIANT(script_, stubs::DelProp), REJOIN_FALLTHROUGH);
             frame.pop();
             pushSyncedEntry(0);
           }
           END_CASE(JSOP_DELPROP)
 
           BEGIN_CASE(JSOP_DELELEM)
           {
             prepareStubCall(Uses(2));
-            INLINE_STUBCALL(STRICT_VARIANT(script, stubs::DelElem), REJOIN_FALLTHROUGH);
+            INLINE_STUBCALL(STRICT_VARIANT(script_, stubs::DelElem), REJOIN_FALLTHROUGH);
             frame.popn(2);
             pushSyncedEntry(0);
           }
           END_CASE(JSOP_DELELEM)
 
           BEGIN_CASE(JSOP_TYPEOF)
           BEGIN_CASE(JSOP_TYPEOFEXPR)
             jsop_typeof();
@@ -2676,35 +2677,35 @@ mjit::Compiler::generateMethod()
           BEGIN_CASE(JSOP_VOID)
             frame.pop();
             frame.push(UndefinedValue());
           END_CASE(JSOP_VOID)
 
           BEGIN_CASE(JSOP_GETPROP)
           BEGIN_CASE(JSOP_CALLPROP)
           BEGIN_CASE(JSOP_LENGTH)
-            if (!jsop_getprop(script->getName(GET_UINT32_INDEX(PC)), knownPushedType(0)))
+            if (!jsop_getprop(script_->getName(GET_UINT32_INDEX(PC)), knownPushedType(0)))
                 return Compile_Error;
           END_CASE(JSOP_GETPROP)
 
           BEGIN_CASE(JSOP_GETELEM)
           BEGIN_CASE(JSOP_CALLELEM)
-            if (script->hasScriptCounts)
+            if (script_->hasScriptCounts)
                 updateElemCounts(PC, frame.peek(-2), frame.peek(-1));
             if (!jsop_getelem())
                 return Compile_Error;
           END_CASE(JSOP_GETELEM)
 
           BEGIN_CASE(JSOP_TOID)
             jsop_toid();
           END_CASE(JSOP_TOID)
 
           BEGIN_CASE(JSOP_SETELEM)
           {
-            if (script->hasScriptCounts)
+            if (script_->hasScriptCounts)
                 updateElemCounts(PC, frame.peek(-3), frame.peek(-2));
             jsbytecode *next = &PC[JSOP_SETELEM_LENGTH];
             bool pop = (JSOp(*next) == JSOP_POP && !analysis->jumpTarget(next));
             if (!jsop_setelem(pop))
                 return Compile_Error;
           }
           END_CASE(JSOP_SETELEM);
 
@@ -2732,17 +2733,17 @@ mjit::Compiler::generateMethod()
                     return status;
             }
             if (!done && inlining()) {
                 CompileStatus status = inlineScriptedFunction(GET_ARGC(PC), callingNew);
                 if (status == Compile_Okay)
                     done = true;
                 else if (status != Compile_InlineAbort)
                     return status;
-                if (script->hasScriptCounts) {
+                if (script_->hasScriptCounts) {
                     /* Code generated while inlining has been accounted for. */
                     countsUpdated = true;
                 }
             }
 
             FrameSize frameSize;
             frameSize.initStatic(frame.totalDepth(), GET_ARGC(PC));
 
@@ -2753,49 +2754,49 @@ mjit::Compiler::generateMethod()
                 JaegerSpew(JSpew_Insns, " --- END SCRIPTED CALL --- \n");
             }
           }
           END_CASE(JSOP_CALL)
 
           BEGIN_CASE(JSOP_NAME)
           BEGIN_CASE(JSOP_CALLNAME)
           {
-            PropertyName *name = script->getName(GET_UINT32_INDEX(PC));
+            PropertyName *name = script_->getName(GET_UINT32_INDEX(PC));
             jsop_name(name, knownPushedType(0));
             frame.extra(frame.peek(-1)).name = name;
           }
           END_CASE(JSOP_NAME)
 
           BEGIN_CASE(JSOP_INTRINSICNAME)
           BEGIN_CASE(JSOP_CALLINTRINSIC)
           {
-            PropertyName *name = script->getName(GET_UINT32_INDEX(PC));
+            PropertyName *name = script_->getName(GET_UINT32_INDEX(PC));
             jsop_intrinsicname(name, knownPushedType(0));
             frame.extra(frame.peek(-1)).name = name;
           }
           END_CASE(JSOP_INTRINSICNAME)
 
           BEGIN_CASE(JSOP_IMPLICITTHIS)
           {
             prepareStubCall(Uses(0));
-            masm.move(ImmPtr(script->getName(GET_UINT32_INDEX(PC))), Registers::ArgReg1);