Merge m-c to b-s.
authorKyle Huey <khuey@kylehuey.com>
Thu, 15 Sep 2011 16:44:46 -0700
changeset 78319 75b7a4cec456459e55b2d10c0c567e55dd0f8408
parent 78318 094d9a3fee33e1df096e530c8937f41b97c2494f (current diff)
parent 78301 f3f5d8a8a4735a14b25de36a7e8b6fdfdd5e9d9d (diff)
child 78320 39b192706927904d23385f8d37a3bf7d2f026f29
child 78696 f850d4a184c955003375648a659737e1359e186f
push id78
push userclegnitto@mozilla.com
push dateFri, 16 Dec 2011 17:32:24 +0000
treeherdermozilla-release@79d24e644fdd [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone9.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 m-c to b-s.
config/autoconf.mk.in
configure.in
xpcom/reflect/xptcall/src/md/unix/xptc_platforms_unixish_x86.h
--- a/accessible/tests/mochitest/tree/test_cssoverflow.html
+++ b/accessible/tests/mochitest/tree/test_cssoverflow.html
@@ -30,29 +30,25 @@
     {
       this.linkNode = getNode(aID);
       this.link = getAccessible(this.linkNode);
 
       this.eventSeq = [
         new invokerChecker(EVENT_FOCUS, getAccessible, this.linkNode)
       ];
 
-      this.unexpectedEventSeq = [
-        new invokerChecker(EVENT_REORDER, this.linkNode.parentNode)
-      ];
-
       this.invoke = function focusAnchor_invoke()
       {
         this.linkNode.focus();
       }
 
       this.check = function focusAnchor_check(aEvent)
       {
-        is(this.link, aEvent.accessible,
-           "The link accessible shouldn't be recreated!");
+        todo_is(this.link, aEvent.accessible,
+                "Focus should be fired against new link accessible!");
       }
 
       this.getID = function focusAnchor_getID()
       {
         return "focus a:focus{overflow:scroll} #1";
       }
     }
 
@@ -60,29 +56,25 @@
     {
       this.linkNode = getNode(aID);
       this.link = getAccessible(this.linkNode);
 
       this.eventSeq = [
         new invokerChecker(EVENT_FOCUS, getAccessible, this.linkNode)
       ];
 
-      this.unexpectedEventSeq = [
-        new invokerChecker(EVENT_REORDER, this.linkNode.parentNode)
-      ];
-
       this.invoke = function tabAnchor_invoke()
       {
         synthesizeKey("VK_TAB", { shiftKey: false });
       }
 
       this.check = function tabAnchor_check(aEvent)
       {
-        is(this.link, aEvent.accessible,
-           "The link accessible shouldn't be recreated!");
+        todo_is(this.link, aEvent.accessible,
+                   "Focus should be fired against new link accessible!");
       }
 
       this.getID = function tabAnchor_getID()
       {
         return "focus a:focus{overflow:scroll} #2";
       }
     }
 
@@ -121,19 +113,19 @@
     Mozilla Bug 591163
   </a><br>
   <a target="_blank"
      title="Rework accessible tree update code"
      href="https://bugzilla.mozilla.org/show_bug.cgi?id=570275">
     Mozilla Bug 570275
   </a><br>
   <a target="_blank"
-     title="Don't recreate frames for inlines with overflow style applied"
-     href="https://bugzilla.mozilla.org/show_bug.cgi?id=606087">
-    Mozilla Bug 606087
+     title="Text control frames should accept dynamic changes to the CSS overflow property"
+     href="https://bugzilla.mozilla.org/show_bug.cgi?id=686247">
+    Mozilla Bug 686247
   </a><br>
 
   <p id="display"></p>
   <div id="content" style="display: none"></div>
   <pre id="test">
   </pre>
   <div id="eventdump"></div>
 
--- a/browser/base/content/pageinfo/permissions.js
+++ b/browser/base/content/pageinfo/permissions.js
@@ -133,17 +133,19 @@ function onUnloadPermission()
 
 function initRow(aPartId)
 {
   var permissionManager = Components.classes[PERMISSION_CONTRACTID]
                                     .getService(nsIPermissionManager);
 
   var checkbox = document.getElementById(aPartId + "Def");
   var command  = document.getElementById("cmd_" + aPartId + "Toggle");
-  var perm = permissionManager.testPermission(gPermURI, aPartId);
+  // Geolocation permission consumers use testExactPermission, not testPermission. 
+  var perm = aPartId == "geo" ? permissionManager.testExactPermission(gPermURI, aPartId) :
+                                permissionManager.testPermission(gPermURI, aPartId);
   if (perm) {
     checkbox.checked = false;
     command.removeAttribute("disabled");
   }
   else {
     checkbox.checked = true;
     command.setAttribute("disabled", "true");
     perm = gPermObj[aPartId]();
--- a/browser/base/content/tabbrowser.xml
+++ b/browser/base/content/tabbrowser.xml
@@ -560,16 +560,18 @@
                     this.mTabBrowser.useDefaultIcon(this.mTab);
                 }
 
                 if (this.mBlank)
                   this.mBlank = false;
 
                 this.mTab.removeAttribute("busy");
                 this.mTab.removeAttribute("progress");
+                if (!this.mTab.selected)
+                  this.mTab.setAttribute("unread", "true");
 
                 var location = aRequest.QueryInterface(nsIChannel).URI;
 
                 // For keyword URIs clear the user typed value since they will be changed into real URIs
                 if (location.scheme == "keyword")
                   this.mBrowser.userTypedValue = null;
 
                 if (this.mTab.label == this.mTabBrowser.mStringBundle.getString("tabs.connecting"))
@@ -866,16 +868,17 @@
                 (!oldBrowser.pageReport && newBrowser.pageReport))
               updatePageReport = true;
 
             newBrowser.setAttribute("type", "content-primary");
             newBrowser.docShellIsActive =
               (window.windowState != window.STATE_MINIMIZED);
             this.mCurrentBrowser = newBrowser;
             this.mCurrentTab = this.selectedTab;
+            this.mCurrentTab.removeAttribute("unread");
             this.showTab(this.mCurrentTab);
 
             if (updatePageReport)
               this.mCurrentBrowser.updatePageReport();
 
             // Update the URL bar.
             var loc = this.mCurrentBrowser.currentURI;
 
@@ -3671,23 +3674,20 @@
         ]]></body>
       </method>
 
       <method name="_handleNewTab">
         <parameter name="tab"/>
         <body><![CDATA[
           if (tab.parentNode != this)
             return;
+          tab._fullyOpen = true;
 
           this.adjustTabstrip();
 
-          if (tab._fullyOpen)
-            return;
-          tab._fullyOpen = true;
-
           if (tab.getAttribute("selected") == "true") {
             this._fillTrailingGap();
             this._handleTabSelect();
           } else {
             this._notifyBackgroundTab(tab);
           }
 
           // XXXmano: this is a temporary workaround for bug 345399
@@ -3719,20 +3719,24 @@
       <handler event="TabSelect" action="this._handleTabSelect();"/>
 
       <handler event="transitionend"><![CDATA[
         if (event.propertyName != "max-width")
           return;
 
         var tab = event.target;
 
-        if (tab.getAttribute("fadein") == "true")
-          this._handleNewTab(tab);
-        else if (tab.closing)
+        if (tab.getAttribute("fadein") == "true") {
+          if (tab._fullyOpen)
+            this.adjustTabstrip();
+          else
+            this._handleNewTab(tab);
+        } else if (tab.closing) {
           this.tabbrowser._endRemoveTab(tab);
+        }
       ]]></handler>
 
       <handler event="dblclick"><![CDATA[
 #ifndef XP_MACOSX
         // When the tabbar has an unified appearance with the titlebar
         // and menubar, a double-click in it should have the same behavior
         // as double-clicking the titlebar
         if (TabsInTitlebar.enabled ||
--- a/browser/base/content/tabview/groupitems.js
+++ b/browser/base/content/tabview/groupitems.js
@@ -117,16 +117,17 @@ function GroupItem(listOfEls, options) {
       .css(rectToBe);
   }
 
   this.bounds = $container.bounds();
 
   this.isDragging = false;
   $container
     .css({zIndex: -100})
+    .attr("data-id", this.id)
     .appendTo("body");
 
   // ___ Resizer
   this.$resizer = iQ("<div>")
     .addClass('resizer')
     .appendTo($container)
     .hide();
 
@@ -1045,16 +1046,17 @@ GroupItem.prototype = Utils.extend(new I
       item.setZ(this.getZ() + 1);
 
       if (!wasAlreadyInThisGroupItem) {
         item.droppable(false);
         item.groupItemData = {};
 
         item.addSubscriber("close", this._onChildClose);
         item.setParent(this);
+        $el.attr("data-group", this.id);
 
         if (typeof item.setResizable == 'function')
           item.setResizable(false, options.immediately);
 
         if (item == UI.getActiveTab() || !this._activeTab)
           this.setActiveTab(item);
 
         // if it matches the selected tab or no active tab and the browser
@@ -1130,16 +1132,17 @@ GroupItem.prototype = Utils.extend(new I
 
       if (item == this._activeTab || !this._activeTab) {
         if (this._children.length > 0)
           this._activeTab = this._children[0];
         else
           this._activeTab = null;
       }
 
+      $el[0].removeAttribute("data-group");
       item.setParent(null);
       item.removeClass("stacked");
       item.isStacked = false;
       item.setHidden(false);
       item.removeClass("stack-trayed");
       item.setRotation(0);
 
       // Force tabItem resize if it's dragged out of a stacked groupItem.
--- a/browser/locales/en-US/chrome/browser/browser.dtd
+++ b/browser/locales/en-US/chrome/browser/browser.dtd
@@ -291,17 +291,17 @@ can reach it easily. -->
 <!ENTITY appMenuFind.label "Find…">
 <!ENTITY appMenuUnsorted.label "Unsorted Bookmarks">
 <!ENTITY appMenuWebDeveloper.label "Web Developer">
 <!ENTITY appMenuGettingStarted.label "Getting Started">
 <!ENTITY appMenuSafeMode.label "Restart with Add-ons Disabled…">
 <!ENTITY appMenuSafeMode.accesskey "R">
 
 <!ENTITY openCmd.commandkey           "l">
-<!ENTITY urlbar.placeholder           "Go to a Web Site">
+<!ENTITY urlbar.placeholder           "Go to a Website">
 <!ENTITY urlbar.accesskey             "d">
 <!ENTITY urlbar.switchToTab.label     "Switch to tab:">
 
 <!-- 
   Comment duplicated from browser-sets.inc:
 
   Search Command Key Logic works like this:
 
@@ -487,17 +487,17 @@ you can use these alternative items. Oth
 
 <!ENTITY pageStyleMenu.label "Page Style">
 <!ENTITY pageStyleMenu.accesskey "y">
 <!ENTITY pageStyleNoStyle.label "No Style">
 <!ENTITY pageStyleNoStyle.accesskey "n">
 <!ENTITY pageStylePersistentOnly.label "Basic Page Style">
 <!ENTITY pageStylePersistentOnly.accesskey "b">
 
-<!ENTITY pageReportIcon.tooltip            "Change pop-up blocking settings for this web site">
+<!ENTITY pageReportIcon.tooltip            "Change pop-up blocking settings for this website">
 
 <!ENTITY allowPopups.accesskey "p">
 <!-- On Windows we use the term "Options" to describe settings, but
      on Linux and Mac OS X we use "Preferences" - carry that distinction
      over into this string, which is used in the "popup blocked" info bar . -->
 <!ENTITY editPopupSettingsUnix.label "Edit Pop-up Blocker Preferences…">
 <!ENTITY editPopupSettings.label "Edit Pop-up Blocker Options…">
 <!ENTITY editPopupSettings.accesskey "E">
@@ -519,17 +519,17 @@ you can use these alternative items. Oth
 
 <!ENTITY spellAddDictionaries.label "Add Dictionaries…">
 <!ENTITY spellAddDictionaries.accesskey "A">
 
 <!ENTITY editBookmark.done.label                     "Done">
 <!ENTITY editBookmark.cancel.label                   "Cancel">
 <!ENTITY editBookmark.removeBookmark.accessKey       "R">
 
-<!ENTITY identity.unverifiedsite2 "This web site does not supply identity information.">
+<!ENTITY identity.unverifiedsite2 "This website does not supply identity information.">
 <!ENTITY identity.connectedTo "You are connected to">
 <!-- Localization note (identity.runBy) : This string appears between a
 domain name (above) and an organization name (below). E.g.
 
 example.com
 which is run by
 Example Enterprises, Inc.
 
--- a/browser/locales/en-US/chrome/browser/browser.properties
+++ b/browser/locales/en-US/chrome/browser/browser.properties
@@ -200,21 +200,21 @@ offlineApps.manageUsageAccessKey=S
 # LOCALIZATION NOTE (indexedDB.usage): %1$S is the website host name
 # %2$S a number of megabytes.
 indexedDB.usage=This website (%1$S) is attempting to store more than %2$S MB of data on your computer for offline use.
 
 identity.identified.verifier=Verified by: %S
 identity.identified.verified_by_you=You have added a security exception for this site.
 identity.identified.state_and_country=%S, %S
 
-identity.encrypted=Your connection to this web site is encrypted to prevent eavesdropping.
-identity.unencrypted=Your connection to this web site is not encrypted.
+identity.encrypted=Your connection to this website is encrypted to prevent eavesdropping.
+identity.unencrypted=Your connection to this website is not encrypted.
 identity.mixed_content=Your connection to this site is only partially encrypted, and does not prevent eavesdropping.
 
-identity.unknown.tooltip=This web site does not supply identity information.
+identity.unknown.tooltip=This website does not supply identity information.
 
 identity.ownerUnknown2=(unknown)
 
 # Downloads Monitor Panel
 # LOCALIZATION NOTE (activeDownloads1, pausedDownloads1): Semi-colon list of plural
 # forms. See: http://developer.mozilla.org/en/docs/Localization_and_Plurals
 # #1 number of downloads; #2 time left
 # examples: 1 active download (2 minutes remaining); 11 paused downloads
--- a/browser/locales/en-US/chrome/browser/pageInfo.dtd
+++ b/browser/locales/en-US/chrome/browser/pageInfo.dtd
@@ -106,23 +106,23 @@
 <!ENTITY  securityTab           "Security">
 <!ENTITY  securityTab.accesskey "S">
 <!ENTITY  securityHeader        "Security information for this page">
 <!ENTITY  securityView.certView "View Certificate">
 <!ENTITY  securityView.accesskey "V">
 <!ENTITY  securityView.unknown   "Unknown">
 
 
-<!ENTITY  securityView.identity.header   "Web Site Identity">
+<!ENTITY  securityView.identity.header   "Website Identity">
 <!ENTITY  securityView.identity.owner    "Owner:">
-<!ENTITY  securityView.identity.domain   "Web site:">
+<!ENTITY  securityView.identity.domain   "Website:">
 <!ENTITY  securityView.identity.verifier "Verified by:">
 
 <!ENTITY  securityView.privacy.header                   "Privacy &amp; History">
-<!ENTITY  securityView.privacy.history                  "Have I visited this web site prior to today?">
-<!ENTITY  securityView.privacy.cookies                  "Is this web site storing information (cookies) on my computer?">
+<!ENTITY  securityView.privacy.history                  "Have I visited this website prior to today?">
+<!ENTITY  securityView.privacy.cookies                  "Is this website storing information (cookies) on my computer?">
 <!ENTITY  securityView.privacy.viewCookies              "View Cookies">
 <!ENTITY  securityView.privacy.viewCookies.accessKey    "k">
-<!ENTITY  securityView.privacy.passwords                "Have I saved any passwords for this web site?">
+<!ENTITY  securityView.privacy.passwords                "Have I saved any passwords for this website?">
 <!ENTITY  securityView.privacy.viewPasswords            "View Saved Passwords">
 <!ENTITY  securityView.privacy.viewPasswords.accessKey  "w">
 
 <!ENTITY  securityView.technical.header                 "Technical Details">
--- a/browser/locales/en-US/chrome/browser/pageInfo.properties
+++ b/browser/locales/en-US/chrome/browser/pageInfo.properties
@@ -65,24 +65,24 @@ mediaAnimatedImageType=%S Image (animate
 mediaDimensions=%Spx \u00D7 %Spx
 mediaDimensionsScaled=%Spx \u00D7 %Spx (scaled to %Spx \u00D7 %Spx)
 
 generalQuirksMode=Quirks mode
 generalStrictMode=Standards compliance mode
 generalSize=%S KB (%S bytes)
 generalMetaTag=Meta (1 tag)
 generalMetaTags=Meta (%S tags)
-generalSiteIdentity=This web site is owned by %S\nThis has been verified by %S
+generalSiteIdentity=This website is owned by %S\nThis has been verified by %S
 
 feedRss=RSS
 feedAtom=Atom
 feedXML=XML
 
-securityNoOwner=This web site does not supply ownership information.
+securityNoOwner=This website does not supply ownership information.
 securityOneVisit=Yes, once
 securityNVisits=Yes, %S times
 
 # LOCALIZATION NOTE: The next string is for the disk usage of the
 # database
 #   e.g. indexedDBUsage : "50.23 MB"
 #   %1$S = size (in bytes or megabytes, ...)
 #   %2$S = unit of measure (bytes, KB, MB, ...)
-indexedDBUsage=This web site is using %1$S %2$S
+indexedDBUsage=This website is using %1$S %2$S
--- a/browser/locales/en-US/chrome/browser/preferences/aboutPermissions.properties
+++ b/browser/locales/en-US/chrome/browser/preferences/aboutPermissions.properties
@@ -1,5 +1,5 @@
 # LOCALIZATION NOTE (visitCount): #1 is the number of history visits for a site
 visitCount=#1 visit;#1 visits
 
-passwordsCount=#1 password is stored for this web site.;#1 passwords are stored for this web site.
-cookiesCount=#1 cookie is set for this web site.;#1 cookies are set for this web site.
+passwordsCount=#1 password is stored for this website.;#1 passwords are stored for this website.
+cookiesCount=#1 cookie is set for this website.;#1 cookies are set for this website.
--- a/browser/locales/en-US/chrome/browser/preferences/advanced.dtd
+++ b/browser/locales/en-US/chrome/browser/preferences/advanced.dtd
@@ -3,17 +3,17 @@
 <!ENTITY generalTab.label                "General">
 
 <!ENTITY accessibility.label             "Accessibility">
 
 <!ENTITY useCursorNavigation.label       "Always use the cursor keys to navigate within pages">
 <!ENTITY useCursorNavigation.accesskey   "c">
 <!ENTITY searchStartTyping.label         "Search for text when I start typing">
 <!ENTITY searchStartTyping.accesskey     "x">
-<!ENTITY blockAutoRefresh.label          "Warn me when web sites try to redirect or reload the page">
+<!ENTITY blockAutoRefresh.label          "Warn me when websites try to redirect or reload the page">
 <!ENTITY blockAutoRefresh.accesskey      "b">
 
 <!ENTITY browsing.label                  "Browsing">
 
 <!ENTITY useAutoScroll.label             "Use autoscrolling">
 <!ENTITY useAutoScroll.accesskey         "a">
 <!ENTITY useSmoothScrolling.label        "Use smooth scrolling">
 <!ENTITY useSmoothScrolling.accesskey    "m">
--- a/browser/locales/en-US/chrome/browser/preferences/permissions.dtd
+++ b/browser/locales/en-US/chrome/browser/preferences/permissions.dtd
@@ -2,17 +2,17 @@
 <!ENTITY window.width                 "36em">
 
 <!ENTITY treehead.sitename.label      "Site">
 <!ENTITY treehead.status.label        "Status">
 <!ENTITY removepermission.label       "Remove Site">
 <!ENTITY removepermission.accesskey   "R">
 <!ENTITY removeallpermissions.label   "Remove All Sites">
 <!ENTITY removeallpermissions.accesskey "e">
-<!ENTITY address.label                "Address of web site:">
+<!ENTITY address.label                "Address of website:">
 <!ENTITY address.accesskey            "d">
 <!ENTITY block.label                  "Block">
 <!ENTITY block.accesskey              "B">
 <!ENTITY session.label                "Allow for Session">
 <!ENTITY session.accesskey            "S">
 <!ENTITY allow.label                  "Allow">
 <!ENTITY allow.accesskey              "A">
 <!ENTITY windowClose.key              "w">
--- a/browser/locales/en-US/chrome/browser/preferences/preferences.properties
+++ b/browser/locales/en-US/chrome/browser/preferences/preferences.properties
@@ -6,23 +6,23 @@
 phishBeforeText=Selecting this option will send the address of web pages you are viewing to %S. To continue, please review and accept the following terms of service.
 
 #### Fonts
 
 labelDefaultFont=Default (%S)
 
 #### Permissions Manager
 
-cookiepermissionstext=You can specify which web sites are always or never allowed to use cookies.  Type the exact address of the site you want to manage and then click Block, Allow for Session, or Allow.
+cookiepermissionstext=You can specify which websites are always or never allowed to use cookies.  Type the exact address of the site you want to manage and then click Block, Allow for Session, or Allow.
 cookiepermissionstitle=Exceptions - Cookies
-addonspermissionstext=You can specify which web sites are allowed to install add-ons. Type the exact address of the site you want to allow and then click Allow.
+addonspermissionstext=You can specify which websites are allowed to install add-ons. Type the exact address of the site you want to allow and then click Allow.
 addons_permissions_title=Allowed Sites - Add-ons Installation
-popuppermissionstext=You can specify which web sites are allowed to open pop-up windows. Type the exact address of the site you want to allow and then click Allow.
+popuppermissionstext=You can specify which websites are allowed to open pop-up windows. Type the exact address of the site you want to allow and then click Allow.
 popuppermissionstitle=Allowed Sites - Pop-ups
-imagepermissionstext=You can specify which web sites are allowed to load images. Type the exact address of the site you want to manage and then click Block or Allow.
+imagepermissionstext=You can specify which websites are allowed to load images. Type the exact address of the site you want to manage and then click Block or Allow.
 imagepermissionstitle=Exceptions - Images
 invalidURI=Please enter a valid hostname
 invalidURITitle=Invalid Hostname Entered
 
 #### Master Password
 
 pw_change2empty_in_fips_mode=You are currently in FIPS mode. FIPS requires a non-empty Master Password.
 pw_change_failed_title=Password Change Failed
--- a/browser/locales/en-US/chrome/browser/preferences/privacy.dtd
+++ b/browser/locales/en-US/chrome/browser/preferences/privacy.dtd
@@ -1,11 +1,11 @@
 <!ENTITY tracking.label                 "Tracking">
 
-<!ENTITY doNotTrack.label               "Tell web sites I do not want to be tracked">
+<!ENTITY doNotTrack.label               "Tell websites I do not want to be tracked">
 <!ENTITY doNotTrack.accesskey           "d">
 
 <!ENTITY  history.label                 "History">
 
 <!ENTITY  locationBar.label             "Location Bar">
 
 <!ENTITY  locbar.pre.label              "When using the location bar, suggest:">
 <!ENTITY  locbar.pre.accessKey          "u">
@@ -37,17 +37,17 @@
 
 <!ENTITY  historyHeader.pre.label          "&brandShortName; will:">
 <!ENTITY  historyHeader.pre.accesskey      "w">
 <!ENTITY  historyHeader.remember.label     "Remember history">
 <!ENTITY  historyHeader.dontremember.label "Never remember history">
 <!ENTITY  historyHeader.custom.label       "Use custom settings for history">
 <!ENTITY  historyHeader.post.label         "">
 
-<!ENTITY  rememberDescription.label      "&brandShortName; will remember your browsing, download, form and search history, and keep cookies from Web sites you visit.">
+<!ENTITY  rememberDescription.label      "&brandShortName; will remember your browsing, download, form and search history, and keep cookies from websites you visit.">
 
 <!-- LOCALIZATION NOTE (rememberActions.pre.label): include a trailing space as needed -->
 <!-- LOCALIZATION NOTE (rememberActions.middle.label): include a starting and trailing space as needed -->
 <!-- LOCALIZATION NOTE (rememberActions.post.label): include a starting space as needed -->
 <!ENTITY  rememberActions.pre.label           "You may want to ">
 <!ENTITY  rememberActions.clearHistory.label  "clear your recent history">
 <!ENTITY  rememberActions.middle.label        ", or ">
 <!ENTITY  rememberActions.removeCookies.label "remove individual cookies">
--- a/browser/locales/en-US/chrome/overrides/appstrings.properties
+++ b/browser/locales/en-US/chrome/overrides/appstrings.properties
@@ -56,12 +56,12 @@ contentEncodingError=The page you are tr
 unsafeContentType=The page you are trying to view cannot be shown because it is contained in a file type that may not be safe to open. Please contact the website owners to inform them of this problem.
 externalProtocolTitle=External Protocol Request
 externalProtocolPrompt=An external application must be launched to handle %1$S: links.\n\n\nRequested link:\n\n%2$S\n\nApplication: %3$S\n\n\nIf you were not expecting this request it may be an attempt to exploit a weakness in that other program. Cancel this request unless you are sure it is not malicious.\n
 #LOCALIZATION NOTE (externalProtocolUnknown): The following string is shown if the application name can't be determined
 externalProtocolUnknown=<Unknown>
 externalProtocolChkMsg=Remember my choice for all links of this type.
 externalProtocolLaunchBtn=Launch application
 malwareBlocked=The site at %S has been reported as an attack site and has been blocked based on your security preferences.
-phishingBlocked=The web site at %S has been reported as a web forgery designed to trick users into sharing personal or financial information.
+phishingBlocked=The website at %S has been reported as a web forgery designed to trick users into sharing personal or financial information.
 cspFrameAncestorBlocked=This page has a content security policy that prevents it from being embedded in this way.
 corruptedContentError=The page you are trying to view cannot be shown because an error in the data transmission was detected.
 remoteXUL=This page uses an unsupported technology that is no longer available by default in Firefox.
--- a/browser/locales/en-US/chrome/overrides/netError.dtd
+++ b/browser/locales/en-US/chrome/overrides/netError.dtd
@@ -121,17 +121,17 @@
   <li>This might be due to a non-standard configuration on the server.</li>
 </ul>
 ">
 
 <!ENTITY nssFailure2.title "Secure Connection Failed">
 <!ENTITY nssFailure2.longDesc "
 <ul>
   <li>The page you are trying to view can not be shown because the authenticity of the received data could not be verified.</li>
-  <li>Please contact the web site owners to inform them of this problem. Alternatively, use the command found in the help menu to report this broken site.</li>
+  <li>Please contact the website owners to inform them of this problem. Alternatively, use the command found in the help menu to report this broken site.</li>
 </ul>
 ">
 
 <!ENTITY nssBadCert.title "Secure Connection Failed">
 <!ENTITY nssBadCert.longDesc2 "
 <ul>
   <li>This could be a problem with the server's configuration, or it could be
 someone trying to impersonate the server.</li>
@@ -149,17 +149,17 @@ be temporary, and you can try again late
   <li>If your computer or network is protected by a firewall or proxy, make sure
     that &brandShortName; is permitted to access the Web.</li>
 </ul>
 ">
 
 <!ENTITY malwareBlocked.title "Suspected Attack Site!">
 <!ENTITY malwareBlocked.longDesc "
 <p>Attack sites try to install programs that steal private information, use your computer to attack others, or damage your system.</p>
-<p>Web site owners who believe their site has been reported as an attack site in error may <a href='http://www.stopbadware.org/home/reviewinfo' >request a review</a>.</p>
+<p>Website owners who believe their site has been reported as an attack site in error may <a href='http://www.stopbadware.org/home/reviewinfo' >request a review</a>.</p>
 ">
 
 <!ENTITY phishingBlocked.title "Suspected Web Forgery!">
 <!ENTITY phishingBlocked.longDesc "
 <p>Entering any personal information on this page may result in identity theft or other fraud.</p>
 <p>These types of web forgeries are used in scams known as phishing attacks, in which fraudulent web pages and emails are used to imitate sources you may trust.</p>
 ">
 
--- a/browser/themes/winstripe/browser/browser.css
+++ b/browser/themes/winstripe/browser/browser.css
@@ -682,17 +682,17 @@ menuitem.bookmark-item {
 @navbarLargeIcons@ .toolbarbutton-1 > .toolbarbutton-menubutton-dropmarker,
 @navbarLargeIcons@ .toolbarbutton-1 {
   -moz-appearance: none;
   padding: 1px 5px;
   background: rgba(151,152,153,.05)
               -moz-linear-gradient(rgba(251,252,253,.95), rgba(246,247,248,.47) 49%, 
                                    rgba(231,232,233,.45) 51%, rgba(225,226,229,.3));
   background-clip: padding-box;
-  border-radius: 3.5px;
+  border-radius: 2.5px;
   border: 1px solid;
   border-color: rgba(0,0,0,.12) rgba(0,0,0,.19) rgba(0,0,0,.38);
   box-shadow: 0 0 0 1px rgba(255,255,255,.3) inset,
               0 0 0 2px rgba(255,255,255,.1) inset;
   color: black;
   text-shadow: 0 0 2px white;
 }
 
@@ -1190,17 +1190,17 @@ toolbar[mode="full"] .toolbarbutton-1 > 
 
 #urlbar,
 .searchbar-textbox {
   -moz-appearance: none;
   margin: 1px 3px;
   padding: 2px;
   background-clip: padding-box;
   border: 1px solid ThreeDShadow;
-  border-radius: 3.5px;
+  border-radius: 2.5px;
 }
 
 @media all and (-moz-windows-default-theme) {
   #urlbar,
   .searchbar-textbox {
     @navbarTextboxCustomBorder@
   }
 }
@@ -1277,23 +1277,23 @@ html|*.urlbar-input:-moz-lwtheme:-moz-pl
   box-shadow: 0 1px 0 hsla(0,0%,0%,.05) inset;
   -moz-border-end: 1px solid hsla(0,0%,0%,.1);
   padding: 2px;
   margin: -2px;
   -moz-margin-end: 0;
 }
 
 #identity-box:-moz-locale-dir(ltr) {
-  border-top-left-radius: 2.5px;
-  border-bottom-left-radius: 2.5px;
+  border-top-left-radius: 1.5px;
+  border-bottom-left-radius: 1.5px;
 }
 
 #identity-box:-moz-locale-dir(rtl) {
-  border-top-right-radius: 2.5px;
-  border-bottom-right-radius: 2.5px;
+  border-top-right-radius: 1.5px;
+  border-bottom-right-radius: 1.5px;
 }
 
 #identity-box:hover {
   background-image: -moz-linear-gradient(hsl(0,0%,95%), hsl(0,0%,87%));
 }
 
 #identity-box[open="true"],
 #identity-box:hover:active {
@@ -1495,23 +1495,23 @@ richlistitem[type~="action"][actiontype=
   background-origin: border-box;
   border: none;
   -moz-border-start: 1px solid rgba(0,0,0,.25);
   box-shadow: 0 1px 0 rgba(0,0,0,.1) inset,
               -1px -1px 1px rgba(255,255,255,.25) inset;
 }
 
 #urlbar:-moz-locale-dir(ltr) > toolbarbutton {
-  border-top-right-radius: 2px;
-  border-bottom-right-radius: 2px;
+  border-top-right-radius: 1.5px;
+  border-bottom-right-radius: 1.5px;
 }
 
 #urlbar:-moz-locale-dir(rtl) > toolbarbutton {
-  border-top-left-radius: 2px;
-  border-bottom-left-radius: 2px;
+  border-top-left-radius: 1.5px;
+  border-bottom-left-radius: 1.5px;
 }
 
 #urlbar > toolbarbutton:not([disabled]):active:hover,
 #urlbar-reload-button:not(:hover) {
   -moz-border-start-style: none;
   -moz-padding-start: 4px;
   box-shadow: none;
 }
--- a/config/autoconf.mk.in
+++ b/config/autoconf.mk.in
@@ -541,16 +541,17 @@ MOZ_GTK2_LIBS		= @MOZ_GTK2_LIBS@
 
 MOZ_QT_CFLAGS		= @MOZ_QT_CFLAGS@
 MOZ_QT_LIBS		= @MOZ_QT_LIBS@
 MOZ_ENABLE_QTNETWORK    = @MOZ_ENABLE_QTNETWORK@
 MOZ_ENABLE_QMSYSTEM2    = @MOZ_ENABLE_QMSYSTEM2@
 MOZ_ENABLE_QTMOBILITY   = @MOZ_ENABLE_QTMOBILITY@
 MOZ_ENABLE_CONTENTACTION   = @MOZ_ENABLE_CONTENTACTION@
 MOZ_ENABLE_MEEGOTOUCHSHARE = @MOZ_ENABLE_MEEGOTOUCHSHARE@
+MOZ_ENABLE_CONTENTMANAGER = @MOZ_ENABLE_CONTENTMANAGER@
 
 MOZ_DBUS_CFLAGS         = @MOZ_DBUS_CFLAGS@
 MOZ_DBUS_LIBS           = @MOZ_DBUS_LIBS@
 MOZ_DBUS_GLIB_CFLAGS    = @MOZ_DBUS_GLIB_CFLAGS@
 MOZ_DBUS_GLIB_LIBS      = @MOZ_DBUS_GLIB_LIBS@
 MOZ_ENABLE_DBUS         = @MOZ_ENABLE_DBUS@
 
 MOZ_GTHREAD_CFLAGS      = @MOZ_GTHREAD_CFLAGS@
--- a/config/system-headers
+++ b/config/system-headers
@@ -1015,16 +1015,24 @@ conic/conicstatisticsevent.h
 event.h
 #endif
 #ifdef MOZ_ENABLE_LIBPROXY
 proxy.h
 #endif
 #if MOZ_PLATFORM_MAEMO==6
 contentaction/contentaction.h
 #endif
+#ifdef MOZ_ENABLE_CONTENTMANAGER
+SelectSingleContentItemPage.h
+SelectMultipleContentItemsPage.h
+QtSparql/qsparqlconnection.h
+QtSparql/qsparqlquery.h
+QtSparql/qsparqlresult.h
+#endif
+
 #if MOZ_TREE_PIXMAN!=1
 pixman.h
 #endif
 #if MOZ_ENABLE_MEEGOTOUCHSHARE
 shareuiinterface.h
 #endif
 #if MOZ_NATIVE_LIBVPX==1
 vpx/vpx_decoder.h
--- a/configure.in
+++ b/configure.in
@@ -6383,16 +6383,30 @@ if test $MOZ_PLATFORM_MAEMO; then
       MOZ_PLATFORM_MAEMO_LIBS="$MOZ_PLATFORM_MAEMO_LIBS $LIBHILDONFM_LIBS"
       MOZ_PLATFORM_MAEMO_CFLAGS="$MOZ_PLATFORM_MAEMO_CFLAGS $LIBHILDONFM_CFLAGS"
       if test -z "$_LIB_FOUND"; then
          AC_MSG_ERROR([Hildon FM-2 is required when building for Maemo])
       fi
 
    fi
    if test $MOZ_PLATFORM_MAEMO = 6; then
+
+      PKG_CHECK_MODULES(LIBCONTENTMANAGER, ContentManager QtSparql,
+                        _LIB_FOUND=1,
+                        _LIB_FOUND=)
+      if test "$_LIB_FOUND"; then
+         MOZ_PLATFORM_MAEMO_LIBS="$MOZ_PLATFORM_MAEMO_LIBS $LIBCONTENTMANAGER_LIBS"
+         MOZ_PLATFORM_MAEMO_CFLAGS="$MOZ_PLATFORM_MAEMO_CFLAGS $LIBCONTENTMANAGER_CFLAGS"
+         MOZ_ENABLE_CONTENTMANAGER=1
+         AC_DEFINE(MOZ_ENABLE_CONTENTMANAGER)
+      else
+         AC_MSG_WARN([Cannot find libcontentmanager and or QtSparql building for Maemo 6])
+      fi
+      AC_SUBST(MOZ_ENABLE_CONTENTMANAGER)
+
       dnl ========================================================
       dnl = Enable meego libcontentaction
       dnl ========================================================
       MOZ_ARG_ENABLE_BOOL(meegocontentaction,
       [  --enable-meegocontentaction           Enable meegocontentaction support],
          MOZ_MEEGOCONTENTACTION=1,
          MOZ_MEEGOCONTENTACTION=)
 
--- a/content/canvas/src/nsCanvasRenderingContext2DAzure.cpp
+++ b/content/canvas/src/nsCanvasRenderingContext2DAzure.cpp
@@ -4093,21 +4093,22 @@ nsCanvasRenderingContext2DAzure::GetImag
   }
 
   IntRect srcReadRect = srcRect.Intersect(destRect);
   IntRect dstWriteRect = srcReadRect;
   dstWriteRect.MoveBy(-x, -y);
 
   PRUint8 *src = aData;
   PRUint32 srcStride = w * 4;
-    
+  
+  RefPtr<DataSourceSurface> readback;
   if (!srcReadRect.IsEmpty()) {
     RefPtr<SourceSurface> snapshot = mTarget->Snapshot();
 
-    RefPtr<DataSourceSurface> readback = snapshot->GetDataSurface();
+    readback = snapshot->GetDataSurface();
 
     srcStride = readback->Stride();
     src = readback->GetData() + srcReadRect.y * srcStride + srcReadRect.x * 4;
   }
 
   // make sure sUnpremultiplyTable has been created
   EnsureUnpremultiplyTable();
 
--- a/content/html/content/src/nsTextEditorState.cpp
+++ b/content/html/content/src/nsTextEditorState.cpp
@@ -1053,16 +1053,19 @@ nsTextEditorState::BindToFrame(nsTextCon
   if (mEditor) {
     GetValue(currentValue, PR_TRUE);
   }
 
   mBoundFrame = aFrame;
 
   nsIContent *rootNode = GetRootNode();
 
+  nsresult rv = InitializeRootNode();
+  NS_ENSURE_SUCCESS(rv, rv);
+
   nsIPresShell *shell = mBoundFrame->PresContext()->GetPresShell();
   NS_ENSURE_TRUE(shell, NS_ERROR_FAILURE);
 
   // Create selection
   nsRefPtr<nsFrameSelection> frameSel = new nsFrameSelection();
 
   // Create a SelectionController
   mSelCon = new nsTextInputSelectionImpl(frameSel, shell, rootNode);
@@ -1540,16 +1543,27 @@ nsTextEditorState::CreateRootNode()
                                                  kNameSpaceID_XHTML,
                                                  nsIDOMNode::ELEMENT_NODE);
   NS_ENSURE_TRUE(nodeInfo, NS_ERROR_OUT_OF_MEMORY);
 
   nsresult rv = NS_NewHTMLElement(getter_AddRefs(mRootNode), nodeInfo.forget(),
                                   NOT_FROM_PARSER);
   NS_ENSURE_SUCCESS(rv, rv);
 
+  if (!IsSingleLineTextControl()) {
+    mMutationObserver = new nsAnonDivObserver(this);
+    mRootNode->AddMutationObserver(mMutationObserver);
+  }
+
+  return rv;
+}
+
+nsresult
+nsTextEditorState::InitializeRootNode()
+{
   // Set the necessary classes on the text control. We use class values
   // instead of a 'style' attribute so that the style comes from a user-agent
   // style sheet and is still applied even if author styles are disabled.
   nsAutoString classValue;
   classValue.AppendLiteral("anonymous-div");
   PRInt32 wrapCols = GetWrapCols();
   if (wrapCols >= 0) {
     classValue.AppendLiteral(" wrap");
@@ -1559,29 +1573,22 @@ nsTextEditorState::CreateRootNode()
     // crash when the number of lines exceeds the height of the textarea and
     // setting -moz-hidden-unscrollable overflow (NS_STYLE_OVERFLOW_CLIP)
     // doesn't paint the caret for some reason.
     const nsStyleDisplay* disp = mBoundFrame->GetStyleDisplay();
     if (disp->mOverflowX != NS_STYLE_OVERFLOW_VISIBLE &&
         disp->mOverflowX != NS_STYLE_OVERFLOW_CLIP) {
       classValue.AppendLiteral(" inherit-overflow");
     }
-
-    mMutationObserver = new nsAnonDivObserver(this);
-    NS_ENSURE_TRUE(mMutationObserver, NS_ERROR_OUT_OF_MEMORY);
-    mRootNode->AddMutationObserver(mMutationObserver);
   }
-  rv = mRootNode->SetAttr(kNameSpaceID_None, nsGkAtoms::_class,
-                          classValue, PR_FALSE);
+  nsresult rv = mRootNode->SetAttr(kNameSpaceID_None, nsGkAtoms::_class,
+                                   classValue, PR_FALSE);
   NS_ENSURE_SUCCESS(rv, rv);
 
-  rv = mBoundFrame->UpdateValueDisplay(PR_FALSE);
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  return rv;
+  return mBoundFrame->UpdateValueDisplay(PR_FALSE);
 }
 
 nsresult
 nsTextEditorState::CreatePlaceholderNode()
 {
 #ifdef DEBUG
   {
     nsCOMPtr<nsIContent> content = do_QueryInterface(mTextCtrlElement);
--- a/content/html/content/src/nsTextEditorState.h
+++ b/content/html/content/src/nsTextEditorState.h
@@ -248,16 +248,18 @@ private:
 
   nsresult CreateRootNode();
 
   void ValueWasChanged(PRBool aNotify);
 
   void DestroyEditor();
   void Clear();
 
+  nsresult InitializeRootNode();
+
   void FinishedRestoringSelection() { mRestoringSelection = nsnull; }
 
   class InitializationGuard {
   public:
     explicit InitializationGuard(nsTextEditorState& aState) :
       mState(aState),
       mGuardSet(PR_FALSE)
     {
--- a/content/media/VideoUtils.h
+++ b/content/media/VideoUtils.h
@@ -136,27 +136,27 @@ PRBool SamplesToUsecs(PRInt64 aSamples, 
 
 // Converts from microseconds (aUsecs) to number of audio samples, given the
 // specified audio rate (aRate). Stores the result in aOutSamples. Returns
 // PR_TRUE if the operation succeeded, or PR_FALSE if there was an integer
 // overflow while calulating the conversion.
 PRBool UsecsToSamples(PRInt64 aUsecs, PRUint32 aRate, PRInt64& aOutSamples);
 
 // Number of microseconds per second. 1e6.
-#define USECS_PER_S 1000000
+static const PRInt64 USECS_PER_S = 1000000;
 
 // Number of microseconds per millisecond.
-#define USECS_PER_MS 1000
+static const PRInt64 USECS_PER_MS = 1000;
 
 // The maximum height and width of the video. Used for
 // sanitizing the memory allocation of the RGB buffer.
 // The maximum resolution we anticipate encountering in the
 // wild is 2160p - 3840x2160 pixels.
-#define MAX_VIDEO_WIDTH  4000
-#define MAX_VIDEO_HEIGHT 3000
+static const PRInt32 MAX_VIDEO_WIDTH = 4000;
+static const PRInt32 MAX_VIDEO_HEIGHT = 3000;
 
 // Scales the display rect aDisplay by aspect ratio aAspectRatio.
 // Note that aDisplay must be validated by nsVideoInfo::ValidateVideoRegion()
 // before being used!
 void ScaleDisplayByAspectRatio(nsIntSize& aDisplay, float aAspectRatio);
 
 // The amount of virtual memory reserved for thread stacks.
 #if defined(XP_WIN) || defined(XP_MACOSX) || defined(LINUX)
--- a/content/media/nsAudioAvailableEventManager.cpp
+++ b/content/media/nsAudioAvailableEventManager.cpp
@@ -36,17 +36,17 @@
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 #include "nsTArray.h"
 #include "nsAudioAvailableEventManager.h"
 #include "VideoUtils.h"
 
-#define MAX_PENDING_EVENTS 100
+static const nsTArray< nsCOMPtr<nsIRunnable> >::size_type MAX_PENDING_EVENTS = 100;
 
 using namespace mozilla;
 
 class nsAudioAvailableEventRunner : public nsRunnable
 {
 private:
   nsCOMPtr<nsBuiltinDecoder> mDecoder;
   nsAutoArrayPtr<float> mFrameBuffer;
--- a/content/media/nsAudioStream.cpp
+++ b/content/media/nsAudioStream.cpp
@@ -73,17 +73,17 @@ using namespace mozilla;
 #endif
 
 using mozilla::TimeStamp;
 
 #ifdef PR_LOGGING
 PRLogModuleInfo* gAudioStreamLog = nsnull;
 #endif
 
-#define FAKE_BUFFER_SIZE 176400
+static const PRUint32 FAKE_BUFFER_SIZE = 176400;
 
 class nsAudioStreamLocal : public nsAudioStream
 {
  public:
   NS_DECL_ISUPPORTS
 
   ~nsAudioStreamLocal();
   nsAudioStreamLocal();
--- a/content/media/nsBuiltinDecoderStateMachine.cpp
+++ b/content/media/nsBuiltinDecoderStateMachine.cpp
@@ -54,17 +54,17 @@ extern PRLogModuleInfo* gBuiltinDecoderL
 #define LOG(type, msg) PR_LOG(gBuiltinDecoderLog, type, msg)
 #else
 #define LOG(type, msg)
 #endif
 
 // Wait this number of seconds when buffering, then leave and play
 // as best as we can if the required amount of data hasn't been
 // retrieved.
-#define BUFFERING_WAIT 30
+static const PRUint32 BUFFERING_WAIT = 30;
 
 // The amount of data to retrieve during buffering is computed based
 // on the download rate. BUFFERING_MIN_RATE is the minimum download
 // rate to be used in that calculation to help avoid constant buffering
 // attempts at a time when the average download rate has not stabilised.
 #define BUFFERING_MIN_RATE 50000
 #define BUFFERING_RATE(x) ((x)< BUFFERING_MIN_RATE ? BUFFERING_MIN_RATE : (x))
 
--- a/content/media/nsMediaDecoder.cpp
+++ b/content/media/nsMediaDecoder.cpp
@@ -52,28 +52,28 @@
 #include "nsDOMError.h"
 #include "nsDisplayList.h"
 #include "nsSVGEffects.h"
 #include "VideoUtils.h"
 
 using namespace mozilla;
 
 // Number of milliseconds between progress events as defined by spec
-#define PROGRESS_MS 350
+static const PRUint32 PROGRESS_MS = 350;
 
 // Number of milliseconds of no data before a stall event is fired as defined by spec
-#define STALL_MS 3000
+static const PRUint32 STALL_MS = 3000;
 
 // Number of estimated seconds worth of data we need to have buffered 
 // ahead of the current playback position before we allow the media decoder
 // to report that it can play through the entire media without the decode
 // catching up with the download. Having this margin make the
 // nsMediaDecoder::CanPlayThrough() calculation more stable in the case of
 // fluctuating bitrates.
-#define CAN_PLAY_THROUGH_MARGIN 10
+static const PRInt64 CAN_PLAY_THROUGH_MARGIN = 10;
 
 nsMediaDecoder::nsMediaDecoder() :
   mElement(0),
   mRGBWidth(-1),
   mRGBHeight(-1),
   mVideoUpdateLock("nsMediaDecoder.mVideoUpdateLock"),
   mFrameBufferLength(0),
   mPinnedForSeek(PR_FALSE),
--- a/content/media/nsMediaDecoder.h
+++ b/content/media/nsMediaDecoder.h
@@ -54,22 +54,22 @@
 class nsHTMLMediaElement;
 class nsMediaStream;
 class nsIStreamListener;
 class nsTimeRanges;
 
 // The size to use for audio data frames in MozAudioAvailable events.
 // This value is per channel, and is chosen to give ~43 fps of events,
 // for example, 44100 with 2 channels, 2*1024 = 2048.
-#define FRAMEBUFFER_LENGTH_PER_CHANNEL 1024
+static const PRUint32 FRAMEBUFFER_LENGTH_PER_CHANNEL = 1024;
 
 // The total size of the framebuffer used for MozAudioAvailable events
 // has to be within the following range.
-#define FRAMEBUFFER_LENGTH_MIN 512
-#define FRAMEBUFFER_LENGTH_MAX 16384
+static const PRUint32 FRAMEBUFFER_LENGTH_MIN = 512;
+static const PRUint32 FRAMEBUFFER_LENGTH_MAX = 16384;
 
 // All methods of nsMediaDecoder must be called from the main thread only
 // with the exception of GetImageContainer, SetVideoData and GetStatistics,
 // which can be called from any thread.
 class nsMediaDecoder : public nsIObserver
 {
 public:
   typedef mozilla::TimeStamp TimeStamp;
--- a/content/media/nsMediaStream.cpp
+++ b/content/media/nsMediaStream.cpp
@@ -57,18 +57,18 @@
 #include "nsIDocument.h"
 #include "nsDOMError.h"
 #include "nsICachingChannel.h"
 #include "nsURILoader.h"
 #include "nsIAsyncVerifyRedirectCallback.h"
 #include "mozilla/Util.h" // for DebugOnly
 #include "nsContentUtils.h"
 
-#define HTTP_OK_CODE 200
-#define HTTP_PARTIAL_RESPONSE_CODE 206
+static const PRUint32 HTTP_OK_CODE = 200;
+static const PRUint32 HTTP_PARTIAL_RESPONSE_CODE = 206;
 
 using namespace mozilla;
 
 nsMediaChannelStream::nsMediaChannelStream(nsMediaDecoder* aDecoder,
     nsIChannel* aChannel, nsIURI* aURI)
   : nsMediaStream(aDecoder, aChannel, aURI),
     mOffset(0), mSuspendCount(0),
     mReopenOnError(PR_FALSE), mIgnoreClose(PR_FALSE),
--- a/content/media/nsMediaStream.h
+++ b/content/media/nsMediaStream.h
@@ -46,19 +46,19 @@
 #include "nsIStreamListener.h"
 #include "nsIChannelEventSink.h"
 #include "nsIInterfaceRequestor.h"
 #include "nsMediaCache.h"
 
 // For HTTP seeking, if number of bytes needing to be
 // seeked forward is less than this value then a read is
 // done rather than a byte range request.
-#define SEEK_VS_READ_THRESHOLD (32*1024)
+static const PRInt64 SEEK_VS_READ_THRESHOLD = 32*1024;
 
-#define HTTP_REQUESTED_RANGE_NOT_SATISFIABLE_CODE 416
+static const PRUint32 HTTP_REQUESTED_RANGE_NOT_SATISFIABLE_CODE = 416;
 
 class nsMediaDecoder;
 
 /**
  * This class is useful for estimating rates of data passing through
  * some channel. The idea is that activity on the channel "starts"
  * and "stops" over time. At certain times data passes through the
  * channel (usually while the channel is active; data passing through
--- a/content/media/ogg/nsOggCodecState.cpp
+++ b/content/media/ogg/nsOggCodecState.cpp
@@ -768,44 +768,44 @@ nsSkeletonState::~nsSkeletonState()
 {
   MOZ_COUNT_DTOR(nsSkeletonState);
 }
 
 // Support for Ogg Skeleton 4.0, as per specification at:
 // http://wiki.xiph.org/Ogg_Skeleton_4
 
 // Minimum length in bytes of a Skeleton header packet.
-#define SKELETON_MIN_HEADER_LEN 28
-#define SKELETON_4_0_MIN_HEADER_LEN 80
+static const long SKELETON_MIN_HEADER_LEN = 28;
+static const long SKELETON_4_0_MIN_HEADER_LEN = 80;
 
 // Minimum length in bytes of a Skeleton 4.0 index packet.
-#define SKELETON_4_0_MIN_INDEX_LEN 42
+static const long SKELETON_4_0_MIN_INDEX_LEN = 42;
 
 // Minimum possible size of a compressed index keypoint.
-#define MIN_KEY_POINT_SIZE 2
+static const size_t MIN_KEY_POINT_SIZE = 2;
 
 // Byte offset of the major and minor version numbers in the
 // Ogg Skeleton 4.0 header packet.
-#define SKELETON_VERSION_MAJOR_OFFSET 8
-#define SKELETON_VERSION_MINOR_OFFSET 10
+static const size_t SKELETON_VERSION_MAJOR_OFFSET = 8;
+static const size_t SKELETON_VERSION_MINOR_OFFSET = 10;
 
 // Byte-offsets of the presentation time numerator and denominator
-#define SKELETON_PRESENTATION_TIME_NUMERATOR_OFFSET 12
-#define SKELETON_PRESENTATION_TIME_DENOMINATOR_OFFSET 20
+static const size_t SKELETON_PRESENTATION_TIME_NUMERATOR_OFFSET = 12;
+static const size_t SKELETON_PRESENTATION_TIME_DENOMINATOR_OFFSET = 20;
 
 // Byte-offsets of the length of file field in the Skeleton 4.0 header packet.
-#define SKELETON_FILE_LENGTH_OFFSET 64
+static const size_t SKELETON_FILE_LENGTH_OFFSET = 64;
 
 // Byte-offsets of the fields in the Skeleton index packet.
-#define INDEX_SERIALNO_OFFSET 6
-#define INDEX_NUM_KEYPOINTS_OFFSET 10
-#define INDEX_TIME_DENOM_OFFSET 18
-#define INDEX_FIRST_NUMER_OFFSET 26
-#define INDEX_LAST_NUMER_OFFSET 34
-#define INDEX_KEYPOINT_OFFSET 42
+static const size_t INDEX_SERIALNO_OFFSET = 6;
+static const size_t INDEX_NUM_KEYPOINTS_OFFSET = 10;
+static const size_t INDEX_TIME_DENOM_OFFSET = 18;
+static const size_t INDEX_FIRST_NUMER_OFFSET = 26;
+static const size_t INDEX_LAST_NUMER_OFFSET = 34;
+static const size_t INDEX_KEYPOINT_OFFSET = 42;
 
 static PRBool IsSkeletonBOS(ogg_packet* aPacket)
 {
   return aPacket->bytes >= SKELETON_MIN_HEADER_LEN && 
          memcmp(reinterpret_cast<char*>(aPacket->packet), "fishead", 8) == 0;
 }
 
 static PRBool IsSkeletonIndex(ogg_packet* aPacket)
--- a/content/media/ogg/nsOggReader.cpp
+++ b/content/media/ogg/nsOggReader.cpp
@@ -58,30 +58,23 @@ extern PRLogModuleInfo* gBuiltinDecoderL
 #else
 #define SEEK_LOG(type, msg)
 #endif
 #else
 #define LOG(type, msg)
 #define SEEK_LOG(type, msg)
 #endif
 
-// If we don't have a Theora video stream, then during seeking, if a seek
-// target is less than SEEK_DECODE_MARGIN ahead of the current playback
-// position, we'll just decode forwards rather than performing a bisection
-// search. If we have Theora video we use the maximum keyframe interval as
-// this value, rather than SEEK_DECODE_MARGIN. This makes small seeks faster.
-#define SEEK_DECODE_MARGIN 2000000
-
 // The number of microseconds of "fuzz" we use in a bisection search over
 // HTTP. When we're seeking with fuzz, we'll stop the search if a bisection
 // lands between the seek target and SEEK_FUZZ_USECS microseconds before the
 // seek target.  This is becaue it's usually quicker to just keep downloading
 // from an exisiting connection than to do another bisection inside that
 // small range, which would open a new HTTP connetion.
-#define SEEK_FUZZ_USECS 500000
+static const PRUint32 SEEK_FUZZ_USECS = 500000;
 
 enum PageSyncResult {
   PAGE_SYNC_ERROR = 1,
   PAGE_SYNC_END_OF_RANGE= 2,
   PAGE_SYNC_OK = 3
 };
 
 // Reads a page from the media stream.
--- a/content/media/raw/nsRawReader.cpp
+++ b/content/media/raw/nsRawReader.cpp
@@ -38,17 +38,17 @@
  * ***** END LICENSE BLOCK ***** */
 
 #include "nsBuiltinDecoderStateMachine.h"
 #include "nsBuiltinDecoder.h"
 #include "nsRawReader.h"
 #include "nsRawDecoder.h"
 #include "VideoUtils.h"
 
-#define RAW_ID 0x595556
+static const PRUint24 RAW_ID = 0x595556;
 
 nsRawReader::nsRawReader(nsBuiltinDecoder* aDecoder)
   : nsBuiltinDecoderReader(aDecoder),
     mCurrentFrame(0), mFrameSize(0)
 {
   MOZ_COUNT_CTOR(nsRawReader);
 }
 
--- a/content/media/wave/nsWaveReader.cpp
+++ b/content/media/wave/nsWaveReader.cpp
@@ -57,37 +57,37 @@ extern PRLogModuleInfo* gBuiltinDecoderL
 #define SEEK_LOG(type, msg)
 #endif
 #else
 #define LOG(type, msg)
 #define SEEK_LOG(type, msg)
 #endif
 
 // Magic values that identify RIFF chunks we're interested in.
-#define RIFF_CHUNK_MAGIC 0x52494646
-#define WAVE_CHUNK_MAGIC 0x57415645
-#define FRMT_CHUNK_MAGIC 0x666d7420
-#define DATA_CHUNK_MAGIC 0x64617461
+static const PRUint32 RIFF_CHUNK_MAGIC = 0x52494646;
+static const PRUint32 WAVE_CHUNK_MAGIC = 0x57415645;
+static const PRUint32 FRMT_CHUNK_MAGIC = 0x666d7420;
+static const PRUint32 DATA_CHUNK_MAGIC = 0x64617461;
 
 // Size of RIFF chunk header.  4 byte chunk header type and 4 byte size field.
-#define RIFF_CHUNK_HEADER_SIZE 8
+static const PRUint16 RIFF_CHUNK_HEADER_SIZE = 8;
 
 // Size of RIFF header.  RIFF chunk and 4 byte RIFF type.
-#define RIFF_INITIAL_SIZE (RIFF_CHUNK_HEADER_SIZE + 4)
+static const PRUint16 RIFF_INITIAL_SIZE = RIFF_CHUNK_HEADER_SIZE + 4;
 
 // Size of required part of format chunk.  Actual format chunks may be
 // extended (for non-PCM encodings), but we skip any extended data.
-#define WAVE_FORMAT_CHUNK_SIZE 16
+static const PRUint16 WAVE_FORMAT_CHUNK_SIZE = 16;
 
 // PCM encoding type from format chunk.  Linear PCM is the only encoding
 // supported by nsAudioStream.
-#define WAVE_FORMAT_ENCODING_PCM 1
+static const PRUint16 WAVE_FORMAT_ENCODING_PCM = 1;
 
 // Maximum number of channels supported
-#define MAX_CHANNELS 2
+static const PRUint8 MAX_CHANNELS = 2;
 
 namespace {
   PRUint32
   ReadUint32BE(const char** aBuffer)
   {
     PRUint32 result =
       PRUint8((*aBuffer)[0]) << 24 |
       PRUint8((*aBuffer)[1]) << 16 |
--- a/content/media/webm/nsWebMReader.h
+++ b/content/media/webm/nsWebMReader.h
@@ -172,17 +172,17 @@ private:
   nsReturnRef<NesteggPacketHolder> NextPacket(TrackType aTrackType);
 
   // Returns an initialized ogg packet with data obtained from the WebM container.
   ogg_packet InitOggPacket(unsigned char* aData,
                            size_t aLength,
                            PRBool aBOS,
                            PRBool aEOS,
                            PRInt64 aGranulepos);
-                     
+
   // Decode a nestegg packet of audio data. Push the audio data on the
   // audio queue. Returns PR_TRUE when there's more audio to decode,
   // PR_FALSE if the audio is finished, end of file has been reached,
   // or an un-recoverable read error has occured. The reader's monitor
   // must be held during this call. This function will free the packet
   // so the caller must not use the packet after calling.
   PRBool DecodeAudioPacket(nestegg_packet* aPacket, PRInt64 aOffset);
 
--- a/content/svg/content/src/nsSVGFilters.cpp
+++ b/content/svg/content/src/nsSVGFilters.cpp
@@ -4940,21 +4940,23 @@ nsSVGFELightingElement::Filter(nsSVGFilt
     for (PRInt32 x = dataRect.x; x < dataRect.XMost(); x++) {
       PRInt32 index = y * stride + x * 4;
 
       float N[3];
       GenerateNormal(N, sourceData, stride, surfaceWidth, surfaceHeight,
                      x, y, surfaceScale);
 
       if (pointLight || spotLight) {
-        float Z =
-          surfaceScale * sourceData[index + GFX_ARGB32_OFFSET_A] / 255;
-
-        L[0] = lightPos[0] - x;
-        L[1] = lightPos[1] - y;
+        gfxPoint pt = instance->FilterSpaceToUserSpace(
+                gfxPoint(x + instance->GetSurfaceRect().x,
+                         y + instance->GetSurfaceRect().y));
+        float Z = surfaceScale * sourceData[index + GFX_ARGB32_OFFSET_A] / 255;
+
+        L[0] = lightPos[0] - pt.x;
+        L[1] = lightPos[1] - pt.y;
         L[2] = lightPos[2] - Z;
         NORMALIZE(L);
       }
 
       nscolor color;
 
       if (spotLight) {
         float S[3];
--- a/dom/base/nsDOMClassInfo.cpp
+++ b/dom/base/nsDOMClassInfo.cpp
@@ -8115,17 +8115,17 @@ nsDOMStringMapSH::Enumerate(nsIXPConnect
   NS_ENSURE_TRUE(dataset, NS_ERROR_UNEXPECTED);
 
   nsDOMStringMap* stringMap = static_cast<nsDOMStringMap*>(dataset.get());
   nsTArray<nsString> properties;
   nsresult rv = stringMap->GetDataPropList(properties);
   NS_ENSURE_SUCCESS(rv, rv);
 
   for (PRUint32 i = 0; i < properties.Length(); ++i) {
-    nsDependentString prop(properties[i]);
+    nsString& prop(properties[i]);
     *_retval = JS_DefineUCProperty(cx, obj, prop.get(), prop.Length(),
                                    JSVAL_VOID, nsnull, nsnull,
                                    JSPROP_ENUMERATE | JSPROP_SHARED);
     NS_ENSURE_TRUE(*_retval, NS_ERROR_FAILURE);
   }
 
   return NS_OK;
 }
--- a/dom/base/nsGlobalWindow.cpp
+++ b/dom/base/nsGlobalWindow.cpp
@@ -2670,17 +2670,17 @@ nsGlobalWindow::AreDialogsBlocked()
          (topWindow->mDialogDisabled &&
           (topWindow->GetPopupControlState() > openAllowed ||
            topWindow->mDialogAbuseCount >= MAX_DIALOG_COUNT));
 }
 
 bool
 nsGlobalWindow::ConfirmDialogAllowed()
 {
-  FORWARD_TO_OUTER(ConfirmDialogAllowed, (), NS_ERROR_NOT_INITIALIZED);
+  FORWARD_TO_OUTER(ConfirmDialogAllowed, (), false);
 
   NS_ENSURE_TRUE(mDocShell, false);
   nsCOMPtr<nsIPromptService> promptSvc =
     do_GetService("@mozilla.org/embedcomp/prompt-service;1");
 
   if (!DialogOpenAttempted() || !promptSvc) {
     return true;
   }
--- a/dom/locales/en-US/chrome/appstrings.properties
+++ b/dom/locales/en-US/chrome/appstrings.properties
@@ -55,12 +55,12 @@ contentEncodingError=The page you are tr
 unsafeContentType=The page you are trying to view cannot be shown because it is contained in a file type that may not be safe to open. Please contact the website owners to inform them of this problem.
 externalProtocolTitle=External Protocol Request
 externalProtocolPrompt=An external application must be launched to handle %1$S: links.\n\n\nRequested link:\n\n%2$S\n\nApplication: %3$S\n\n\nIf you were not expecting this request it may be an attempt to exploit a weakness in that other program. Cancel this request unless you are sure it is not malicious.\n
 #LOCALIZATION NOTE (externalProtocolUnknown): The following string is shown if the application name can't be determined
 externalProtocolUnknown=<Unknown>
 externalProtocolChkMsg=Remember my choice for all links of this type.
 externalProtocolLaunchBtn=Launch application
 malwareBlocked=The site at %S has been reported as an attack site and has been blocked based on your security preferences.
-phishingBlocked=The web site at %S has been reported as a web forgery designed to trick users into sharing personal or financial information.
+phishingBlocked=The website at %S has been reported as a web forgery designed to trick users into sharing personal or financial information.
 cspFrameAncestorBlocked=This page has a content security policy that prevents it from being embedded in this way.
 corruptedContentError=The page you are trying to view cannot be shown because an error in the data transmission was detected.
 remoteXUL=This page uses an unsupported technology that is no longer available by default.
--- a/dom/locales/en-US/chrome/netError.dtd
+++ b/dom/locales/en-US/chrome/netError.dtd
@@ -54,29 +54,29 @@
 
 <!ENTITY redirectLoop.title "Redirect Loop">
 <!ENTITY redirectLoop.longDesc "<p>The browser has stopped trying to retrieve the requested item. The site is redirecting the request in a way that will never complete.</p><ul><li>Have you disabled or blocked cookies required by this site?</li><li><em>NOTE</em>: If accepting the site's cookies does not resolve the problem, it is likely a server configuration issue and not your computer.</li></ul>">
 
 <!ENTITY unknownSocketType.title "Incorrect Response">
 <!ENTITY unknownSocketType.longDesc "<p>The site responded to the network request in an unexpected way and the browser cannot continue.</p>">
 
 <!ENTITY nssFailure2.title "Secure Connection Failed">
-<!ENTITY nssFailure2.longDesc "<p>The page you are trying to view can not be shown because the authenticity of the received data could not be verified.</p><ul><li>Please contact the web site owners to inform them of this problem.</li></ul>">
+<!ENTITY nssFailure2.longDesc "<p>The page you are trying to view can not be shown because the authenticity of the received data could not be verified.</p><ul><li>Please contact the website owners to inform them of this problem.</li></ul>">
 
 <!ENTITY nssBadCert.title "Secure Connection Failed">
 <!ENTITY nssBadCert.longDesc2 "<ul>
 <li>This could be a problem with the server's configuration, or it could be someone trying to impersonate the server.</li>
 <li>If you have connected to this server successfully in the past, the error may be temporary, and you can try again later.</li>
 </ul>
 ">
 
 <!ENTITY malwareBlocked.title "Suspected Attack Site!">
 <!ENTITY malwareBlocked.longDesc "
 <p>Attack sites try to install programs that steal private information, use your computer to attack others, or damage your system.</p>
-<p>Web site owners who believe their site has been reported as an attack site in error may <a href='http://www.stopbadware.org/home/reviewinfo' >request a review</a>.</p>
+<p>Website owners who believe their site has been reported as an attack site in error may <a href='http://www.stopbadware.org/home/reviewinfo' >request a review</a>.</p>
 ">
 
 <!ENTITY phishingBlocked.title "Suspected Web Forgery!">
 <!ENTITY phishingBlocked.longDesc "
 <p>Entering any personal information on this page may result in identity theft or other fraud.</p>
 <p>These types of web forgeries are used in scams known as phishing attacks, in which fraudulent web pages and emails are used to imitate sources you may trust.</p>
 ">
 
--- a/dom/plugins/base/npapi.h
+++ b/dom/plugins/base/npapi.h
@@ -406,17 +406,19 @@ typedef enum {
 
   /* Get the NPObject wrapper for the plugins DOM element. */
   NPNVPluginElementNPObject = 16,
 
   NPNVSupportsWindowless = 17,
 
   NPNVprivateModeBool = 18,
 
-  NPNVsupportsAdvancedKeyHandling = 21
+  NPNVsupportsAdvancedKeyHandling = 21,
+
+  NPNVdocumentOrigin = 22
 
 #if defined(XP_MACOSX)
   /* Used for negotiating drawing models */
   , NPNVpluginDrawingModel = 1000
 #ifndef NP_NO_QUICKDRAW
   , NPNVsupportsQuickDrawBool = 2000
 #endif
   , NPNVsupportsCoreGraphicsBool = 2001
--- a/dom/plugins/base/nptypes.h
+++ b/dom/plugins/base/nptypes.h
@@ -50,17 +50,17 @@
    * is predefined tho, both in C and C++.
    */
   typedef short int16_t;
   typedef unsigned short uint16_t;
   typedef int int32_t;
   typedef unsigned int uint32_t;
   typedef long long int64_t;
   typedef unsigned long long uint64_t;
-#elif defined(_AIX) || defined(__sun) || defined(__osf__) || defined(HPUX)
+#elif defined(_AIX) || defined(__sun) || defined(__osf__) || defined(IRIX) || defined(HPUX)
   /*
    * AIX and SunOS ship a inttypes.h header that defines [u]int32_t,
    * but not bool for C.
    */
   #include <inttypes.h>
 
   #ifndef __cplusplus
     typedef int bool;
--- a/dom/plugins/base/nsNPAPIPlugin.cpp
+++ b/dom/plugins/base/nsNPAPIPlugin.cpp
@@ -65,21 +65,24 @@
 #include "nsPluginLogging.h"
 
 #include "nsIJSContextStack.h"
 
 #include "nsIDOMElement.h"
 #include "nsIDOMDocument.h"
 #include "nsPIDOMWindow.h"
 #include "nsIDocument.h"
+#include "nsIContent.h"
 #include "nsIScriptGlobalObject.h"
 #include "nsIScriptContext.h"
+#include "nsIUnicodeNormalizer.h"
 #include "nsDOMJSUtils.h"
 #include "nsIPrincipal.h"
 #include "nsWildCard.h"
+#include "nsContentUtils.h"
 
 #include "nsIXPConnect.h"
 
 #include "nsIObserverService.h"
 #include <prinrval.h>
 
 #ifdef MOZ_WIDGET_COCOA
 #include <Carbon/Carbon.h>
@@ -2154,16 +2157,56 @@ NPError NP_CALLBACK
       PRBool enabled;
       pbs->GetPrivateBrowsingEnabled(&enabled);
       *(NPBool*)result = (NPBool)enabled;
       return NPERR_NO_ERROR;
     }
     return NPERR_GENERIC_ERROR;
   }
 
+  case NPNVdocumentOrigin: {
+    nsNPAPIPluginInstance *inst = (nsNPAPIPluginInstance *)npp->ndata;
+    if (!inst) {
+      return NPERR_GENERIC_ERROR;
+    }
+
+    nsCOMPtr<nsIDOMElement> element;
+    inst->GetDOMElement(getter_AddRefs(element));
+    if (!element) {
+      return NPERR_GENERIC_ERROR;
+    }
+
+    nsCOMPtr<nsIContent> content(do_QueryInterface(element));
+    if (!content) {
+      return NPERR_GENERIC_ERROR;
+    }
+
+    nsIPrincipal* principal = content->NodePrincipal();
+
+    nsAutoString utf16Origin;
+    res = nsContentUtils::GetUTFOrigin(principal, utf16Origin);
+    if (NS_FAILED(res)) {
+      return NPERR_GENERIC_ERROR;
+    }
+
+    nsCOMPtr<nsIUnicodeNormalizer> normalizer = do_GetService(NS_UNICODE_NORMALIZER_CONTRACTID);
+    if (!normalizer) {
+      return NPERR_GENERIC_ERROR;
+    }
+
+    nsAutoString normalizedUTF16Origin;
+    res = normalizer->NormalizeUnicodeNFKC(utf16Origin, normalizedUTF16Origin);
+    if (NS_FAILED(res)) {
+      return NPERR_GENERIC_ERROR;
+    }
+
+    *(char**)result = ToNewUTF8String(normalizedUTF16Origin);
+    return *(char**)result ? NPERR_NO_ERROR : NPERR_GENERIC_ERROR;
+  }
+
 #ifdef XP_MACOSX
   case NPNVpluginDrawingModel: {
     if (npp) {
       nsNPAPIPluginInstance *inst = (nsNPAPIPluginInstance*)npp->ndata;
       if (inst) {
         NPDrawingModel drawingModel;
         inst->GetDrawingModel((PRInt32*)&drawingModel);
         *(NPDrawingModel*)result = drawingModel;
--- a/dom/plugins/ipc/PPluginInstance.ipdl
+++ b/dom/plugins/ipc/PPluginInstance.ipdl
@@ -166,16 +166,18 @@ parent:
   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);
+  rpc NPN_GetValue_NPNVdocumentOrigin()
+    returns (nsCString value, NPError result);
 
   rpc NPN_SetValue_NPPVpluginWindow(bool windowed)
     returns (NPError result);
   rpc NPN_SetValue_NPPVpluginTransparent(bool transparent)
     returns (NPError result);
   rpc NPN_SetValue_NPPVpluginUsesDOMForCursor(bool useDOMForCursor)
     returns (NPError result);
   rpc NPN_SetValue_NPPVpluginDrawingModel(int drawingModel)
--- a/dom/plugins/ipc/PluginInstanceChild.cpp
+++ b/dom/plugins/ipc/PluginInstanceChild.cpp
@@ -354,16 +354,28 @@ PluginInstanceChild::NPN_GetValue(NPNVar
         NPError result;
         if (!CallNPN_GetValue_NPNVprivateModeBool(&v, &result)) {
             return NPERR_GENERIC_ERROR;
         }
         *static_cast<NPBool*>(aValue) = v;
         return result;
     }
 
+    case NPNVdocumentOrigin: {
+        nsCString v;
+        NPError result;
+        if (!CallNPN_GetValue_NPNVdocumentOrigin(&v, &result)) {
+            return NPERR_GENERIC_ERROR;
+        }
+        if (result == NPERR_NO_ERROR) {
+            *static_cast<char**>(aValue) = ToNewCString(v);
+        }
+        return result;
+    }
+
     case NPNVWindowNPObject: // Intentional fall-through
     case NPNVPluginElementNPObject: {
         NPObject* object;
         NPError result = InternalGetNPObjectForValue(aVar, &object);
         if (result == NPERR_NO_ERROR) {
             *((NPObject**)aValue) = object;
         }
         return result;
--- a/dom/plugins/ipc/PluginInstanceParent.cpp
+++ b/dom/plugins/ipc/PluginInstanceParent.cpp
@@ -337,16 +337,28 @@ PluginInstanceParent::AnswerNPN_GetValue
 {
     NPBool v;
     *result = mNPNIface->getvalue(mNPP, NPNVprivateModeBool, &v);
     *value = v;
     return true;
 }
 
 bool
+PluginInstanceParent::AnswerNPN_GetValue_NPNVdocumentOrigin(nsCString* value,
+                                                            NPError* result)
+{
+    void *v = nsnull;
+    *result = mNPNIface->getvalue(mNPP, NPNVdocumentOrigin, &v);
+    if (*result == NPERR_NO_ERROR && v) {
+        value->Adopt(static_cast<char*>(v));
+    }
+    return true;
+}
+
+bool
 PluginInstanceParent::AnswerNPN_SetValue_NPPVpluginWindow(
     const bool& windowed, NPError* result)
 {
     NPBool isWindowed = windowed;
     *result = mNPNIface->setvalue(mNPP, NPPVpluginWindowBool,
                                   (void*)isWindowed);
     return true;
 }
--- a/dom/plugins/ipc/PluginInstanceParent.h
+++ b/dom/plugins/ipc/PluginInstanceParent.h
@@ -125,16 +125,19 @@ public:
                                        PPluginScriptableObjectParent** value,
                                        NPError* result);
     virtual bool
     AnswerNPN_GetValue_NPNVPluginElementNPObject(
                                        PPluginScriptableObjectParent** value,
                                        NPError* result);
     virtual bool
     AnswerNPN_GetValue_NPNVprivateModeBool(bool* value, NPError* result);
+  
+    virtual bool
+    AnswerNPN_GetValue_NPNVdocumentOrigin(nsCString* value, NPError* result);
 
     virtual bool
     AnswerNPN_SetValue_NPPVpluginWindow(const bool& windowed, NPError* result);
     virtual bool
     AnswerNPN_SetValue_NPPVpluginTransparent(const bool& transparent,
                                              NPError* result);
     virtual bool
     AnswerNPN_SetValue_NPPVpluginUsesDOMForCursor(const bool& useDOMForCursor,
--- a/dom/plugins/ipc/PluginMessageUtils.h
+++ b/dom/plugins/ipc/PluginMessageUtils.h
@@ -208,16 +208,17 @@ NPNVariableToString(NPNVariable aVar)
 
         VARSTR(NPNVWindowNPObject);
 
         VARSTR(NPNVPluginElementNPObject);
 
         VARSTR(NPNVSupportsWindowless);
 
         VARSTR(NPNVprivateModeBool);
+        VARSTR(NPNVdocumentOrigin);
 
     default: return "???";
     }
 }
 #undef VARSTR
 
 inline bool IsPluginThread()
 {
--- a/dom/plugins/test/mochitest/Makefile.in
+++ b/dom/plugins/test/mochitest/Makefile.in
@@ -97,16 +97,17 @@ include $(topsrcdir)/config/rules.mk
   test_bug539565-2.html \
   test_enumerate.html \
   test_npruntime_construct.html \
   307-xo-redirect.sjs \
   test_redirect_handling.html \
   test_zero_opacity.html \
   test_NPPVpluginWantsAllNetworkStreams.html \
   test_npruntime_npnsetexception.html \
+  test_NPNVdocumentOrigin.html \
   $(NULL)
 
 #  test_plugin_scroll_painting.html \ bug 596491
 
 ifeq ($(OS_ARCH),WINNT)
 _MOCHITEST_FILES += \
   test_windowed_invalidate.html \
   $(NULL)
new file mode 100644
--- /dev/null
+++ b/dom/plugins/test/mochitest/test_NPNVdocumentOrigin.html
@@ -0,0 +1,34 @@
+<html>
+<head>
+  <title>Test NPNVdocumentOrigin</title>
+  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+</head>
+<body onload="runTest()">
+  <embed id="plugin1" type="application/x-test" width="200" height="200"></embed>
+
+  <script class="testbody" type="application/javascript">
+    SimpleTest.waitForExplicitFinish();
+
+    function runTest() {
+      var p1 = document.getElementById("plugin1");
+      var realOrigin = "http://mochi.test:8888";
+
+      // Test with no modifications
+      is(p1.getNPNVdocumentOrigin(), realOrigin, "Checking for expected origin.");
+
+      // Mess with window.location.toString
+      window.location.toString = function() { return 'http://victim.rckc.at/'; }
+      is(p1.getNPNVdocumentOrigin(), realOrigin, "Checking for expected origin afer modifying window.location.toString.");
+
+      // Create a plugin in a new window with about:blank
+      var newWindow = window.open("about:blank");
+      newWindow.document.writeln('<embed id="plugin2" type="application/x-test" width="200" height="200"></embed>');
+      var p2 = newWindow.document.getElementById("plugin2");
+      is(p2.getNPNVdocumentOrigin(), realOrigin, "Checking for expected origin of plugin in new about:blank window.");
+      newWindow.close();
+
+      SimpleTest.finish();
+    }
+  </script>
+</body>
+</html>
--- a/dom/plugins/test/testplugin/README
+++ b/dom/plugins/test/testplugin/README
@@ -32,16 +32,20 @@ Attempts to set the value of an undefine
 returns true if it succeeds and false if it doesn't. It should never succeed.
 
 * .getReflector()
 Hands back an object which reflects properties as values, e.g.
   .getReflector().foo = 'foo'
   .getReflector()['foo'] = 'foo'
   .getReflector()[1] = 1
 
+* .getNPNVdocumentOrigin()
+Returns the origin string retrieved from the browser by a NPNVdocumentOrigin
+variable request. Does not cache the value, gets it from the browser every time.
+
 == NPN_ConvertPoint testing ==
 
 * convertPointX(sourceSpace, sourceX, sourceY, destSpace)
 * convertPointY(sourceSpace, sourceX, sourceY, destSpace)
 The plugin uses NPN_ConvertPoint to convert sourceX and sourceY from the source
 to dest space and returns the X or Y result based on the call.
 
 == NPCocoaEventWindowFocusChanged ==
--- a/dom/plugins/test/testplugin/nptest.cpp
+++ b/dom/plugins/test/testplugin/nptest.cpp
@@ -162,16 +162,17 @@ static bool getFocusEventCount(NPObject*
 static bool getEventModel(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result);
 static bool getReflector(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result);
 static bool isVisible(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result);
 static bool getWindowPosition(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result);
 static bool constructObject(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result);
 static bool setSitesWithData(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result);
 static bool setSitesWithDataCapabilities(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result);
 static bool getLastKeyText(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result);
+static bool getNPNVdocumentOrigin(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result);
 
 static const NPUTF8* sPluginMethodIdentifierNames[] = {
   "npnEvaluateTest",
   "npnInvokeTest",
   "npnInvokeDefaultTest",
   "setUndefinedValueTest",
   "identifierToStringTest",
   "timerTest",
@@ -220,17 +221,18 @@ static const NPUTF8* sPluginMethodIdenti
   "getFocusEventCount",
   "getEventModel",
   "getReflector",
   "isVisible",
   "getWindowPosition",
   "constructObject",
   "setSitesWithData",
   "setSitesWithDataCapabilities",
-  "getLastKeyText"
+  "getLastKeyText",
+  "getNPNVdocumentOrigin"
 };
 static NPIdentifier sPluginMethodIdentifiers[ARRAY_LENGTH(sPluginMethodIdentifierNames)];
 static const ScriptableFunction sPluginMethodFunctions[] = {
   npnEvaluateTest,
   npnInvokeTest,
   npnInvokeDefaultTest,
   setUndefinedValueTest,
   identifierToStringTest,
@@ -280,17 +282,18 @@ static const ScriptableFunction sPluginM
   getFocusEventCount,
   getEventModel,
   getReflector,
   isVisible,
   getWindowPosition,
   constructObject,
   setSitesWithData,
   setSitesWithDataCapabilities,
-  getLastKeyText
+  getLastKeyText,
+  getNPNVdocumentOrigin
 };
 
 STATIC_ASSERT(ARRAY_LENGTH(sPluginMethodIdentifierNames) ==
               ARRAY_LENGTH(sPluginMethodFunctions));
 
 static const NPUTF8* sPluginPropertyIdentifierNames[] = {
   "propertyAndMethod"
 };
@@ -3469,8 +3472,27 @@ bool getLastKeyText(NPObject* npobj, con
     return false;
   }
 
   NPP npp = static_cast<TestNPObject*>(npobj)->npp;
   InstanceData* id = static_cast<InstanceData*>(npp->pdata);
   STRINGZ_TO_NPVARIANT(NPN_StrDup(id->lastKeyText.c_str()), *result);
   return true;
 }
+
+bool getNPNVdocumentOrigin(NPObject* npobj, const NPVariant* args, uint32_t argCount,
+                           NPVariant* result)
+{
+  if (argCount != 0) {
+    return false;
+  }
+
+  NPP npp = static_cast<TestNPObject*>(npobj)->npp;
+
+  char *origin = NULL;
+  NPError err = NPN_GetValue(npp, NPNVdocumentOrigin, &origin);
+  if (err != NPERR_NO_ERROR) {
+    return false;
+  }
+
+  STRINGZ_TO_NPVARIANT(origin, *result);
+  return true;
+}
--- a/dom/workers/ChromeWorkerScope.cpp
+++ b/dom/workers/ChromeWorkerScope.cpp
@@ -40,16 +40,20 @@
 
 #include "jsapi.h"
 #include "jscntxt.h"
 
 #include "nsXPCOM.h"
 #include "nsNativeCharsetUtils.h"
 #include "nsStringGlue.h"
 
+#include "WorkerPrivate.h"
+
+#define CTYPES_STR "ctypes"
+
 USING_WORKERS_NAMESPACE
 
 namespace {
 
 #ifdef BUILD_CTYPES
 char*
 UnicodeToNative(JSContext* aCx, const jschar* aSource, size_t aSourceLen)
 {
@@ -69,34 +73,75 @@ UnicodeToNative(JSContext* aCx, const js
   memcpy(result, native.get(), native.Length());
   result[native.Length()] = 0;
   return result;
 }
 
 JSCTypesCallbacks gCTypesCallbacks = {
   UnicodeToNative
 };
+
+JSBool
+CTypesLazyGetter(JSContext* aCx, JSObject* aObj, jsid aId, jsval* aVp)
+{
+  NS_ASSERTION(JS_GetGlobalObject(aCx) == aObj, "Not a global object!");
+  NS_ASSERTION(JSID_IS_STRING(aId), "Bad id!");
+  NS_ASSERTION(JS_FlatStringEqualsAscii(JSID_TO_FLAT_STRING(aId), CTYPES_STR),
+               "Bad id!");
+
+  WorkerPrivate* worker = GetWorkerPrivateFromContext(aCx);
+  NS_ASSERTION(worker->IsChromeWorker(), "This should always be true!");
+
+  if (!worker->DisableMemoryReporter()) {
+    return false;
+  }
+
+  jsval ctypes;
+  return JS_DeletePropertyById(aCx, aObj, aId) &&
+         JS_InitCTypesClass(aCx, aObj) &&
+         JS_GetPropertyById(aCx, aObj, aId, &ctypes) &&
+         JS_SetCTypesCallbacks(aCx, JSVAL_TO_OBJECT(ctypes),
+                               &gCTypesCallbacks) &&
+         JS_GetPropertyById(aCx, aObj, aId, aVp);
+}
 #endif
 
+inline bool
+DefineCTypesLazyGetter(JSContext* aCx, JSObject* aGlobal)
+{
+#ifdef BUILD_CTYPES
+  {
+    JSString* ctypesStr = JS_InternString(aCx, CTYPES_STR);
+    if (!ctypesStr) {
+      return false;
+    }
+
+    jsid ctypesId = INTERNED_STRING_TO_JSID(aCx, ctypesStr);
+
+    // We use a lazy getter here to let us unregister the blocking memory
+    // reporter since ctypes can easily block the worker thread and we can
+    // deadlock. Remove once bug 673323 is fixed.
+    if (!JS_DefinePropertyById(aCx, aGlobal, ctypesId, JSVAL_VOID,
+                               CTypesLazyGetter, NULL, 0)) {
+      return false;
+    }
+  }
+#endif
+
+  return true;
+}
+
 } // anonymous namespace
 
 BEGIN_WORKERS_NAMESPACE
 
 namespace chromeworker {
 
 bool
 DefineChromeWorkerFunctions(JSContext* aCx, JSObject* aGlobal)
 {
-#ifdef BUILD_CTYPES
-  jsval ctypes;
-  if (!JS_InitCTypesClass(aCx, aGlobal) ||
-      !JS_GetProperty(aCx, aGlobal, "ctypes", &ctypes) ||
-      !JS_SetCTypesCallbacks(aCx, JSVAL_TO_OBJECT(ctypes), &gCTypesCallbacks)) {
-    return false;
-  }
-#endif
-
-  return true;
+  // Currently ctypes is the only special property given to ChromeWorkers.
+  return DefineCTypesLazyGetter(aCx, aGlobal);
 }
 
 } // namespace chromeworker
 
 END_WORKERS_NAMESPACE
--- a/dom/workers/RuntimeService.cpp
+++ b/dom/workers/RuntimeService.cpp
@@ -41,23 +41,21 @@
 
 #include "nsIDOMChromeWindow.h"
 #include "nsIDocument.h"
 #include "nsIEffectiveTLDService.h"
 #include "nsIObserverService.h"
 #include "nsIPlatformCharset.h"
 #include "nsIPrincipal.h"
 #include "nsIJSContextStack.h"
-#include "nsIMemoryReporter.h"
 #include "nsIScriptSecurityManager.h"
 #include "nsISupportsPriority.h"
 #include "nsITimer.h"
 #include "nsPIDOMWindow.h"
 
-#include "jsprf.h"
 #include "mozilla/Preferences.h"
 #include "nsContentUtils.h"
 #include "nsDOMJSUtils.h"
 #include "nsGlobalWindow.h"
 #include "nsNetUtil.h"
 #include "nsServiceManagerUtils.h"
 #include "nsThreadUtils.h"
 #include "nsXPCOM.h"
@@ -282,71 +280,16 @@ CreateJSContextForWorker(WorkerPrivate* 
 
   if (aWorkerPrivate->IsChromeWorker()) {
     JS_SetVersion(workerCx, JSVERSION_LATEST);
   }
 
   return workerCx;
 }
 
-class WorkerMemoryReporter : public nsIMemoryMultiReporter
-{
-  WorkerPrivate* mWorkerPrivate;
-  nsCString mPathPrefix;
-
-public:
-  NS_DECL_ISUPPORTS
-
-  WorkerMemoryReporter(WorkerPrivate* aWorkerPrivate)
-  : mWorkerPrivate(aWorkerPrivate)
-  {
-    aWorkerPrivate->AssertIsOnWorkerThread();
-
-    nsCString escapedDomain(aWorkerPrivate->Domain());
-    escapedDomain.ReplaceChar('/', '\\');
-
-    NS_ConvertUTF16toUTF8 escapedURL(aWorkerPrivate->ScriptURL());
-    escapedURL.ReplaceChar('/', '\\');
-
-    // 64bit address plus '0x' plus null terminator.
-    char address[21];
-    JSUint32 addressSize =
-      JS_snprintf(address, sizeof(address), "0x%llx", aWorkerPrivate);
-    if (addressSize == JSUint32(-1)) {
-      NS_WARNING("JS_snprintf failed!");
-      address[0] = '\0';
-      addressSize = 0;
-    }
-
-    mPathPrefix = NS_LITERAL_CSTRING("explicit/dom/workers(") +
-                  escapedDomain + NS_LITERAL_CSTRING(")/worker(") +
-                  escapedURL + NS_LITERAL_CSTRING(", ") +
-                  nsDependentCString(address, addressSize) +
-                  NS_LITERAL_CSTRING(")/");
-  }
-
-  NS_IMETHOD
-  CollectReports(nsIMemoryMultiReporterCallback* aCallback,
-                 nsISupports* aClosure)
-  {
-    AssertIsOnMainThread();
-
-    IterateData data;
-    if (!mWorkerPrivate->BlockAndCollectRuntimeStats(&data)) {
-      return NS_ERROR_FAILURE;
-    }
-
-    ReportJSRuntimeStats(data, mPathPrefix, aCallback, aClosure);
-
-    return NS_OK;
-  }
-};
-
-NS_IMPL_THREADSAFE_ISUPPORTS1(WorkerMemoryReporter, nsIMemoryMultiReporter)
-
 class WorkerThreadRunnable : public nsRunnable
 {
   WorkerPrivate* mWorkerPrivate;
 
 public:
   WorkerThreadRunnable(WorkerPrivate* aWorkerPrivate)
   : mWorkerPrivate(aWorkerPrivate)
   {
@@ -363,35 +306,21 @@ public:
 
     JSContext* cx = CreateJSContextForWorker(workerPrivate);
     if (!cx) {
       // XXX need to fire an error at parent.
       NS_ERROR("Failed to create runtime and context!");
       return NS_ERROR_FAILURE;
     }
 
-    nsRefPtr<WorkerMemoryReporter> reporter =
-      new WorkerMemoryReporter(workerPrivate);
-    if (NS_FAILED(NS_RegisterMemoryMultiReporter(reporter))) {
-      NS_WARNING("Failed to register memory reporter!");
-      reporter = nsnull;
-    }
-
     {
       JSAutoRequest ar(cx);
       workerPrivate->DoRunLoop(cx);
     }
 
-    if (reporter) {
-      if (NS_FAILED(NS_UnregisterMemoryMultiReporter(reporter))) {
-        NS_WARNING("Failed to unregister memory reporter!");
-      }
-      reporter = nsnull;
-    }
-
     JSRuntime* rt = JS_GetRuntime(cx);
 
     // XXX Bug 666963 - CTypes can create another JSContext for use with
     // closures, and then it holds that context in a reserved slot on the CType
     // prototype object. We have to destroy that context before we can destroy
     // the runtime, and we also have to make sure that it isn't the last context
     // to be destroyed (otherwise it will assert). To accomplish this we create
     // an unused dummy context, destroy our real context, and then destroy the
--- a/dom/workers/WorkerPrivate.cpp
+++ b/dom/workers/WorkerPrivate.cpp
@@ -40,28 +40,30 @@
 #include "WorkerPrivate.h"
 
 #include "nsIClassInfo.h"
 #include "nsIConsoleService.h"
 #include "nsIDOMFile.h"
 #include "nsIDocument.h"
 #include "nsIEffectiveTLDService.h"
 #include "nsIJSContextStack.h"
+#include "nsIMemoryReporter.h"
 #include "nsIScriptError.h"
 #include "nsIScriptGlobalObject.h"
 #include "nsIScriptSecurityManager.h"
 #include "nsPIDOMWindow.h"
 #include "nsITextToSubURI.h"
 #include "nsITimer.h"
 #include "nsIURI.h"
 #include "nsIURL.h"
 #include "nsIXPConnect.h"
 
 #include "jscntxt.h"
 #include "jsdbgapi.h"
+#include "jsprf.h"
 #include "nsAlgorithm.h"
 #include "nsContentUtils.h"
 #include "nsDOMClassInfo.h"
 #include "nsDOMJSUtils.h"
 #include "nsGUIEvent.h"
 #include "nsJSEnvironment.h"
 #include "nsJSUtils.h"
 #include "nsNetUtil.h"
@@ -135,16 +137,97 @@ SwapToISupportsArray(SmartPtr<T>& aSrc,
   T* raw = nsnull;
   aSrc.swap(raw);
 
   nsISupports* rawSupports =
     static_cast<typename ISupportsBaseInfo<T>::ISupportsBase*>(raw);
   dest->swap(rawSupports);
 }
 
+class WorkerMemoryReporter : public nsIMemoryMultiReporter
+{
+  WorkerPrivate* mWorkerPrivate;
+  nsCString mAddressString;
+  nsCString mPathPrefix;
+
+public:
+  NS_DECL_ISUPPORTS
+
+  WorkerMemoryReporter(WorkerPrivate* aWorkerPrivate)
+  : mWorkerPrivate(aWorkerPrivate)
+  {
+    aWorkerPrivate->AssertIsOnWorkerThread();
+
+    nsCString escapedDomain(aWorkerPrivate->Domain());
+    escapedDomain.ReplaceChar('/', '\\');
+
+    NS_ConvertUTF16toUTF8 escapedURL(aWorkerPrivate->ScriptURL());
+    escapedURL.ReplaceChar('/', '\\');
+
+    {
+      // 64bit address plus '0x' plus null terminator.
+      char address[21];
+      JSUint32 addressSize =
+        JS_snprintf(address, sizeof(address), "0x%llx", aWorkerPrivate);
+      if (addressSize != JSUint32(-1)) {
+        mAddressString.Assign(address, addressSize);
+      }
+      else {
+        NS_WARNING("JS_snprintf failed!");
+        mAddressString.AssignLiteral("<unknown address>");
+      }
+    }
+
+    mPathPrefix = NS_LITERAL_CSTRING("explicit/dom/workers(") +
+                  escapedDomain + NS_LITERAL_CSTRING(")/worker(") +
+                  escapedURL + NS_LITERAL_CSTRING(", ") + mAddressString +
+                  NS_LITERAL_CSTRING(")/");
+  }
+
+  NS_IMETHOD
+  CollectReports(nsIMemoryMultiReporterCallback* aCallback,
+                 nsISupports* aClosure)
+  {
+    AssertIsOnMainThread();
+
+    IterateData data;
+
+    if (mWorkerPrivate) {
+      bool disabled;
+      if (!mWorkerPrivate->BlockAndCollectRuntimeStats(&data, &disabled)) {
+        return NS_ERROR_FAILURE;
+      }
+
+      // Don't ever try to talk to the worker again.
+      if (disabled) {
+#ifdef DEBUG
+        {
+          nsCAutoString message("Unable to report memory for ");
+          if (mWorkerPrivate->IsChromeWorker()) {
+            message.AppendLiteral("Chrome");
+          }
+          message += NS_LITERAL_CSTRING("Worker (") + mAddressString +
+                     NS_LITERAL_CSTRING(")! It is either using ctypes or is in "
+                                        "the process of being destroyed");
+          NS_WARNING(message.get());
+        }
+#endif
+        mWorkerPrivate = nsnull;
+      }
+    }
+
+    // Always report, even if we're disabled, so that we at least get an entry
+    // in about::memory.
+    ReportJSRuntimeStats(data, mPathPrefix, aCallback, aClosure);
+    return NS_OK;
+  }
+};
+
+NS_IMPL_THREADSAFE_ISUPPORTS1(WorkerMemoryReporter, nsIMemoryMultiReporter)
+
 struct WorkerStructuredCloneCallbacks
 {
   static JSObject*
   Read(JSContext* aCx, JSStructuredCloneReader* aReader, uint32 aTag,
        uint32 aData, void* aClosure)
   {
     // See if object is a nsIDOMFile pointer.
     if (aTag == DOMWORKER_SCTAG_FILE) {
@@ -1277,29 +1360,29 @@ public:
 };
 #endif
 
 class CollectRuntimeStatsRunnable : public WorkerControlRunnable
 {
   typedef mozilla::Mutex Mutex;
   typedef mozilla::CondVar CondVar;
 
-  Mutex* mMutex;
-  CondVar* mCondVar;
-  volatile bool* mDoneFlag;
+  Mutex mMutex;
+  CondVar mCondVar;
+  volatile bool mDone;
   IterateData* mData;
-  volatile bool* mSucceeded;
+  bool* mSucceeded;
 
 public:
-  CollectRuntimeStatsRunnable(WorkerPrivate* aWorkerPrivate, Mutex* aMutex,
-                              CondVar* aCondVar, volatile bool* aDoneFlag,
-                              IterateData* aData, volatile bool* aSucceeded)
+  CollectRuntimeStatsRunnable(WorkerPrivate* aWorkerPrivate, IterateData* aData,
+                              bool* aSucceeded)
   : WorkerControlRunnable(aWorkerPrivate, WorkerThread, UnchangedBusyCount),
-    mMutex(aMutex), mCondVar(aCondVar), mDoneFlag(aDoneFlag), mData(aData),
-    mSucceeded(aSucceeded)
+    mMutex("CollectRuntimeStatsRunnable::mMutex"),
+    mCondVar(mMutex, "CollectRuntimeStatsRunnable::mCondVar"), mDone(false),
+    mData(aData), mSucceeded(aSucceeded)
   { }
 
   bool
   PreDispatch(JSContext* aCx, WorkerPrivate* aWorkerPrivate)
   {
     AssertIsOnMainThread();
     return true;
   }
@@ -1307,29 +1390,46 @@ public:
   void
   PostDispatch(JSContext* aCx, WorkerPrivate* aWorkerPrivate,
                bool aDispatchResult)
   {
     AssertIsOnMainThread();
   }
 
   bool
+  DispatchInternal()
+  {
+    AssertIsOnMainThread();
+
+    if (!WorkerControlRunnable::DispatchInternal()) {
+      NS_WARNING("Failed to dispatch runnable!");
+      return false;
+    }
+
+    {
+      MutexAutoLock lock(mMutex);
+      while (!mDone) {
+        mCondVar.Wait();
+      }
+    }
+
+    return true;
+  }
+
+  bool
   WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate)
   {
     JSAutoSuspendRequest asr(aCx);
 
     *mSucceeded = CollectCompartmentStatsForRuntime(JS_GetRuntime(aCx), mData);
 
     {
-      MutexAutoLock lock(*mMutex);
-
-      NS_ASSERTION(!*mDoneFlag, "Should be false!");
-
-      *mDoneFlag = true;
-      mCondVar->Notify();
+      MutexAutoLock lock(mMutex);
+      mDone = true;
+      mCondVar.Notify();
     }
 
     return true;
   }
 };
 
 } /* anonymous namespace */
 
@@ -2096,17 +2196,18 @@ WorkerPrivate::WorkerPrivate(JSContext* 
                              nsCOMPtr<nsIDocument>& aDocument)
 : WorkerPrivateParent<WorkerPrivate>(aCx, aObject, aParent, aParentJSContext,
                                      aScriptURL, aIsChromeWorker, aDomain,
                                      aWindow, aParentScriptContext, aBaseURI,
                                      aPrincipal, aDocument),
   mJSContext(nsnull), mErrorHandlerRecursionCount(0), mNextTimeoutId(1),
   mStatus(Pending), mSuspended(false), mTimerRunning(false),
   mRunningExpiredTimeouts(false), mCloseHandlerStarted(false),
-  mCloseHandlerFinished(false)
+  mCloseHandlerFinished(false), mMemoryReporterRunning(false),
+  mMemoryReporterDisabled(false)
 {
   MOZ_COUNT_CTOR(mozilla::dom::workers::WorkerPrivate);
 }
 
 WorkerPrivate::~WorkerPrivate()
 {
   MOZ_COUNT_DTOR(mozilla::dom::workers::WorkerPrivate);
 }
@@ -2303,16 +2404,23 @@ WorkerPrivate::DoRunLoop(JSContext* aCx)
   {
     MutexAutoLock lock(mMutex);
     mJSContext = aCx;
 
     NS_ASSERTION(mStatus == Pending, "Huh?!");
     mStatus = Running;
   }
 
+  mMemoryReporter = new WorkerMemoryReporter(this);
+
+  if (NS_FAILED(NS_RegisterMemoryMultiReporter(mMemoryReporter))) {
+    NS_WARNING("Failed to register memory reporter!");
+    mMemoryReporter = nsnull;
+  }
+
   for (;;) {
     Status currentStatus;
     nsIRunnable* event;
     {
       MutexAutoLock lock(mMutex);
 
       while (!mControlQueue.Pop(event) && !mQueue.Pop(event)) {
         mCondVar.Wait();
@@ -2353,16 +2461,27 @@ WorkerPrivate::DoRunLoop(JSContext* aCx)
         NS_ASSERTION(currentStatus == Killing, "Should have changed status!");
 #else
         currentStatus = Killing;
 #endif
       }
 
       // If we're supposed to die then we should exit the loop.
       if (currentStatus == Killing) {
+        // Call this before unregistering the reporter as we may be racing with
+        // the main thread.
+        DisableMemoryReporter();
+
+        if (mMemoryReporter) {
+          if (NS_FAILED(NS_UnregisterMemoryMultiReporter(mMemoryReporter))) {
+            NS_WARNING("Failed to unregister memory reporter!");
+          }
+          mMemoryReporter = nsnull;
+        }
+
         StopAcceptingEvents();
         return;
       }
     }
   }
 
   NS_NOTREACHED("Shouldn't get here!");
 }
@@ -2371,31 +2490,17 @@ bool
 WorkerPrivate::OperationCallback(JSContext* aCx)
 {
   AssertIsOnWorkerThread();
 
   bool mayContinue = true;
 
   for (;;) {
     // Run all control events now.
-    for (;;) {
-      nsIRunnable* event;
-      {
-        MutexAutoLock lock(mMutex);
-        if (!mControlQueue.Pop(event)) {
-          break;
-        }
-      }
-
-      if (NS_FAILED(event->Run())) {
-        mayContinue = false;
-      }
-
-      NS_RELEASE(event);
-    }
+    mayContinue = ProcessAllControlRunnables();
 
     if (!mayContinue || !mSuspended) {
       break;
     }
 
     // Clean up before suspending.
     JS_FlushCaches(aCx);
     JS_GC(aCx);
@@ -2452,46 +2557,97 @@ WorkerPrivate::ScheduleDeletion(bool aWa
       new TopLevelWorkerFinishedRunnable(this, currentThread);
     if (NS_FAILED(NS_DispatchToMainThread(runnable, NS_DISPATCH_NORMAL))) {
       NS_WARNING("Failed to dispatch runnable!");
     }
   }
 }
 
 bool
-WorkerPrivate::BlockAndCollectRuntimeStats(IterateData* aData)
+WorkerPrivate::BlockAndCollectRuntimeStats(IterateData* aData, bool* aDisabled)
 {
   AssertIsOnMainThread();
-  mMutex.AssertNotCurrentThreadOwns();
   NS_ASSERTION(aData, "Null data!");
 
-  mozilla::Mutex mutex("BlockAndCollectRuntimeStats mutex");
-  mozilla::CondVar condvar(mutex, "BlockAndCollectRuntimeStats condvar");
-  volatile bool doneFlag = false;
-  volatile bool succeeded = false;
+  {
+    MutexAutoLock lock(mMutex);
+
+    if (mMemoryReporterDisabled) {
+      *aDisabled = true;
+      return true;
+    }
+
+    *aDisabled = false;
+    mMemoryReporterRunning = true;
+  }
+
+  bool succeeded;
 
   nsRefPtr<CollectRuntimeStatsRunnable> runnable =
-    new CollectRuntimeStatsRunnable(this, &mutex, &condvar, &doneFlag, aData,
-                                    &succeeded);
+    new CollectRuntimeStatsRunnable(this, aData, &succeeded);
   if (!runnable->Dispatch(nsnull)) {
     NS_WARNING("Failed to dispatch runnable!");
-    return false;
+    succeeded = false;
   }
 
   {
-    MutexAutoLock lock(mutex);
-    while (!doneFlag) {
-      condvar.Wait();
-    }
+    MutexAutoLock lock(mMutex);
+    mMemoryReporterRunning = false;
   }
 
   return succeeded;
 }
 
 bool
+WorkerPrivate::DisableMemoryReporter()
+{
+  AssertIsOnWorkerThread();
+
+  bool result = true;
+
+  {
+    MutexAutoLock lock(mMutex);
+
+    mMemoryReporterDisabled = true;
+
+    while (mMemoryReporterRunning) {
+      MutexAutoUnlock unlock(mMutex);
+      result = ProcessAllControlRunnables() && result;
+    }
+  }
+
+  return result;
+}
+
+bool
+WorkerPrivate::ProcessAllControlRunnables()
+{
+  AssertIsOnWorkerThread();
+
+  bool result = true;
+
+  for (;;) {
+    nsIRunnable* event;
+    {
+      MutexAutoLock lock(mMutex);
+      if (!mControlQueue.Pop(event)) {
+        break;
+      }
+    }
+
+    if (NS_FAILED(event->Run())) {
+      result = false;
+    }
+
+    NS_RELEASE(event);
+  }
+  return result;
+}
+
+bool
 WorkerPrivate::Dispatch(WorkerRunnable* aEvent, EventQueue* aQueue)
 {
   nsRefPtr<WorkerRunnable> event(aEvent);
 
   {
     MutexAutoLock lock(mMutex);
 
     if (mStatus == Dead) {
--- a/dom/workers/WorkerPrivate.h
+++ b/dom/workers/WorkerPrivate.h
@@ -58,16 +58,17 @@
 
 #include "EventTarget.h"
 #include "Queue.h"
 #include "WorkerFeature.h"
 
 class JSAutoStructuredCloneBuffer;
 class nsIDocument;
 class nsIPrincipal;
+class nsIMemoryMultiReporter;
 class nsIScriptContext;
 class nsIURI;
 class nsPIDOMWindow;
 class nsITimer;
 
 namespace mozilla {
 namespace xpconnect {
 namespace memory {
@@ -507,26 +508,29 @@ class WorkerPrivate : public WorkerPriva
   JSContext* mJSContext;
 
   // Things touched on worker thread only.
   nsTArray<ParentType*> mChildWorkers;
   nsTArray<WorkerFeature*> mFeatures;
   nsTArray<nsAutoPtr<TimeoutInfo> > mTimeouts;
 
   nsCOMPtr<nsITimer> mTimer;
+  nsCOMPtr<nsIMemoryMultiReporter> mMemoryReporter;
 
   mozilla::TimeStamp mKillTime;
   PRUint32 mErrorHandlerRecursionCount;
   PRUint32 mNextTimeoutId;
   Status mStatus;
   bool mSuspended;
   bool mTimerRunning;
   bool mRunningExpiredTimeouts;
   bool mCloseHandlerStarted;
   bool mCloseHandlerFinished;
+  bool mMemoryReporterRunning;
+  bool mMemoryReporterDisabled;
 
 #ifdef DEBUG
   nsCOMPtr<nsIThread> mThread;
 #endif
 
 public:
   ~WorkerPrivate();
 
@@ -649,17 +653,21 @@ public:
 
   void
   UpdateJSContextOptionsInternal(JSContext* aCx, PRUint32 aOptions);
 
   void
   ScheduleDeletion(bool aWasPending);
 
   bool
-  BlockAndCollectRuntimeStats(mozilla::xpconnect::memory::IterateData* aData);
+  BlockAndCollectRuntimeStats(mozilla::xpconnect::memory::IterateData* aData,
+                              bool* aDisabled);
+
+  bool
+  DisableMemoryReporter();
 
 #ifdef JS_GC_ZEAL
   void
   UpdateGCZealInternal(JSContext* aCx, PRUint8 aGCZeal);
 #endif
 
   JSContext*
   GetJSContext() const
@@ -738,16 +746,19 @@ private:
     mozilla::MutexAutoLock lock(mMutex);
 
     mStatus = Dead;
     mJSContext = nsnull;
 
     ClearQueue(&mQueue);
     ClearQueue(&mControlQueue);
   }
+
+  bool
+  ProcessAllControlRunnables();
 };
 
 WorkerPrivate*
 GetWorkerPrivateFromContext(JSContext* aCx);
 
 enum WorkerStructuredDataType
 {
   DOMWORKER_SCTAG_FILE = JS_SCTAG_USER_MIN + 0x1000,
--- a/dom/workers/test/chromeWorker_worker.js
+++ b/dom/workers/test/chromeWorker_worker.js
@@ -1,15 +1,20 @@
 /**
  * Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/
  */
 if (!("ctypes" in self)) {
   throw "No ctypes!";
 }
 
+// Go ahead and verify that the ctypes lazy getter actually works.
+if (ctypes.toString() != "[object ctypes]") {
+  throw "Bad ctypes object: " + ctypes.toString();
+}
+
 onmessage = function(event) {
   let worker = new ChromeWorker("chromeWorker_subworker.js");
   worker.onmessage = function(event) {
     postMessage(event.data);
   }
   worker.postMessage(event.data);
 }
--- a/gfx/cairo/README
+++ b/gfx/cairo/README
@@ -169,16 +169,18 @@ pixman-image-transform.patch: Reset the 
 fix-cairo-surface-wrapper-flush-build-warning.patch: Ensures that _cairo_surface_wrapper_flush always returns a status, to silence the build warning
 
 fixup-unbounded.patch: Hack to work around bad assumption.
 
 quartz-get-image-performance: Make cairo_quartz_get_image faster in the failure case by not flushing unless we are going to succeed.
 
 lround-c99-only.patch: Only use lround in C99 programs.
 
+unicode-printing.patch: Print as unicode (bug 454532)
+
 ==== pixman patches ====
 
 pixman-android-cpu-detect.patch: Add CPU detection support for Android, where we can't reliably access /proc/self/auxv.
 
 pixman-rename-and-endian.patch: include cairo-platform.h for renaming of external symbols and endian macros
 
 NOTE: we previously supported ARM assembler on MSVC, this has been removed because of the maintenance burden
 
--- a/gfx/cairo/cairo/src/cairo-win32-printing-surface.c
+++ b/gfx/cairo/cairo/src/cairo-win32-printing-surface.c
@@ -1426,16 +1426,104 @@ static cairo_int_status_t
     }
 
     fflush(stderr);
 
     return status;
 }
 
 static cairo_int_status_t
+_cairo_win32_printing_surface_emit_win32_glyphs (cairo_win32_surface_t 	*surface,
+						 cairo_operator_t	 op,
+						 const cairo_pattern_t  *source,
+						 cairo_glyph_t        	*glyphs,
+						 int			 num_glyphs,
+						 cairo_scaled_font_t  	*scaled_font,
+						 cairo_clip_t		*clip,
+						 int			*remaining_glyphs)
+{
+    cairo_matrix_t ctm;
+    cairo_glyph_t  *unicode_glyphs;
+    cairo_scaled_font_subsets_glyph_t subset_glyph;
+    int i, first;
+    cairo_bool_t sequence_is_unicode;
+    cairo_status_t status = CAIRO_STATUS_SUCCESS;
+
+    /* Where possible reverse the glyph indices back to unicode
+     * characters. Strings of glyphs that could not be reversed to
+     * unicode will be printed with ETO_GLYPH_INDEX.
+     *
+     * As _cairo_win32_scaled_font_index_to_ucs4() is a slow
+     * operation, the font subsetting function
+     * _cairo_scaled_font_subsets_map_glyph() is used to obtain
+     * the unicode value because it caches the reverse mapping in
+     * the subsets.
+     */
+
+    if (surface->has_ctm) {
+	for (i = 0; i < num_glyphs; i++)
+	    cairo_matrix_transform_point (&surface->ctm, &glyphs[i].x, &glyphs[i].y);
+	cairo_matrix_multiply (&ctm, &scaled_font->ctm, &surface->ctm);
+	scaled_font = cairo_scaled_font_create (scaled_font->font_face,
+						&scaled_font->font_matrix,
+						&ctm,
+						&scaled_font->options);
+    }
+
+    unicode_glyphs = _cairo_malloc_ab (num_glyphs, sizeof (cairo_glyph_t));
+    if (unicode_glyphs == NULL)
+	return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+
+    memcpy (unicode_glyphs, glyphs, num_glyphs * sizeof (cairo_glyph_t));
+    for (i = 0; i < num_glyphs; i++) {
+	status = _cairo_scaled_font_subsets_map_glyph (surface->font_subsets,
+						       scaled_font,
+						       glyphs[i].index,
+						       NULL, 0,
+						       &subset_glyph);
+	if (status)
+	    goto fail;
+
+	unicode_glyphs[i].index = subset_glyph.unicode;
+    }
+
+    i = 0;
+    first = 0;
+    sequence_is_unicode = unicode_glyphs[0].index <= 0xffff;
+    while (i < num_glyphs) {
+	if (i == num_glyphs - 1 ||
+	    ((unicode_glyphs[i + 1].index < 0xffff) != sequence_is_unicode))
+	{
+	    status = _cairo_win32_surface_show_glyphs_internal (
+		surface,
+		op,
+		source,
+		sequence_is_unicode ? &unicode_glyphs[first] : &glyphs[first],
+		i - first + 1,
+		scaled_font,
+		clip,
+		remaining_glyphs,
+		! sequence_is_unicode);
+	    first = i + 1;
+	    if (i < num_glyphs - 1)
+		sequence_is_unicode = unicode_glyphs[i + 1].index <= 0xffff;
+	}
+	i++;
+    }
+
+fail:
+    if (surface->has_ctm)
+	cairo_scaled_font_destroy (scaled_font);
+
+    free (unicode_glyphs);
+
+    return status;
+}
+
+static cairo_int_status_t
 _cairo_win32_printing_surface_show_glyphs (void                 *abstract_surface,
                                            cairo_operator_t	 op,
                                            const cairo_pattern_t *source,
                                            cairo_glyph_t        *glyphs,
                                            int			 num_glyphs,
                                            cairo_scaled_font_t  *scaled_font,
 					   cairo_clip_t		*clip,
 					   int			*remaining_glyphs)
@@ -1533,77 +1621,24 @@ static cairo_int_status_t
         }
     }
 #endif
 
 #if CAIRO_HAS_WIN32_FONT
     if (cairo_scaled_font_get_type (scaled_font) == CAIRO_FONT_TYPE_WIN32 &&
 	source->type == CAIRO_PATTERN_TYPE_SOLID)
     {
-	cairo_matrix_t ctm;
-	cairo_glyph_t  *type1_glyphs = NULL;
-	cairo_scaled_font_subsets_glyph_t subset_glyph;
-
-	/* Calling ExtTextOutW() with ETO_GLYPH_INDEX and a Type 1
-	 * font on a printer DC prints garbled text. The text displays
-	 * correctly on a display DC. When using a printer
-	 * DC, ExtTextOutW() only works with characters and not glyph
-	 * indices.
-	 *
-	 * For Type 1 fonts the glyph indices are converted back to
-	 * unicode characters before calling _cairo_win32_surface_show_glyphs().
-	 *
-	 * As _cairo_win32_scaled_font_index_to_ucs4() is a slow
-	 * operation, the font subsetting function
-	 * _cairo_scaled_font_subsets_map_glyph() is used to obtain
-	 * the unicode value because it caches the reverse mapping in
-	 * the subsets.
-	 */
-	if (_cairo_win32_scaled_font_is_type1 (scaled_font)) {
-	    type1_glyphs = _cairo_malloc_ab (num_glyphs, sizeof (cairo_glyph_t));
-	    if (type1_glyphs == NULL) {
-		status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
-		goto FINISH;
-	    }
-	    memcpy (type1_glyphs, glyphs, num_glyphs * sizeof (cairo_glyph_t));
-	    for (i = 0; i < num_glyphs; i++) {
-		status = _cairo_scaled_font_subsets_map_glyph (surface->font_subsets,
-							       scaled_font,
-							       type1_glyphs[i].index,
-							       NULL, 0,
-							       &subset_glyph);
-		if (status)
-		    goto FINISH;
-
-		type1_glyphs[i].index = subset_glyph.unicode;
-	    }
-	    glyphs = type1_glyphs;
-	}
-
-	if (surface->has_ctm || surface->has_gdi_ctm) {
-	    cairo_matrix_multiply (&ctm, &surface->ctm, &surface->gdi_ctm);
-	    for (i = 0; i < num_glyphs; i++)
-		cairo_matrix_transform_point (&ctm, &glyphs[i].x, &glyphs[i].y);
-	    cairo_matrix_multiply (&ctm, &scaled_font->ctm, &ctm);
-	    scaled_font = cairo_scaled_font_create (scaled_font->font_face,
-						    &scaled_font->font_matrix,
-						    &ctm,
-						    &scaled_font->options);
-	}
-	status = _cairo_win32_surface_show_glyphs (surface, op,
-						   source, glyphs,
-						   num_glyphs, scaled_font,
-						   clip,
-						   remaining_glyphs);
-	if (surface->has_ctm || surface->has_gdi_ctm)
-	    cairo_scaled_font_destroy (scaled_font);
-
-	if (type1_glyphs != NULL)
-	    free (type1_glyphs);
-
+	status = _cairo_win32_printing_surface_emit_win32_glyphs (surface,
+								  op,
+								  source,
+								  glyphs,
+								  num_glyphs,
+								  scaled_font,
+								  clip,
+								  remaining_glyphs);
 	goto FINISH;
     }
 #endif
 
     SaveDC (surface->dc);
     old_ctm = surface->ctm;
     old_has_ctm = surface->has_ctm;
     surface->has_ctm = TRUE;
--- a/gfx/cairo/cairo/src/cairo-win32-private.h
+++ b/gfx/cairo/cairo/src/cairo-win32-private.h
@@ -157,16 +157,27 @@ cairo_bool_t
 uint32_t
 _cairo_win32_flags_for_dc (HDC dc);
 
 cairo_status_t
 _cairo_win32_surface_set_clip_region (void           *abstract_surface,
 				      cairo_region_t *region);
 
 cairo_int_status_t
+_cairo_win32_surface_show_glyphs_internal (void			 *surface,
+					   cairo_operator_t	  op,
+					   const cairo_pattern_t *source,
+					   cairo_glyph_t	 *glyphs,
+					   int			  num_glyphs,
+					   cairo_scaled_font_t	 *scaled_font,
+					   cairo_clip_t		 *clip,
+					   int			 *remaining_glyphs,
+					   cairo_bool_t		  glyph_indices);
+
+cairo_int_status_t
 _cairo_win32_surface_show_glyphs (void			*surface,
 				  cairo_operator_t	 op,
 				  const cairo_pattern_t	*source,
 				  cairo_glyph_t		*glyphs,
 				  int			 num_glyphs,
 				  cairo_scaled_font_t	*scaled_font,
 				  cairo_clip_t		*clip,
 				  int			*remaining_glyphs);
--- a/gfx/cairo/cairo/src/cairo-win32-surface.c
+++ b/gfx/cairo/cairo/src/cairo-win32-surface.c
@@ -1607,24 +1607,25 @@ static cairo_status_t
 _cairo_win32_surface_flush (void *abstract_surface)
 {
     return _cairo_win32_surface_set_clip_region (abstract_surface, NULL);
 }
 
 #define STACK_GLYPH_SIZE 256
 
 cairo_int_status_t
-_cairo_win32_surface_show_glyphs (void			*surface,
-				  cairo_operator_t	 op,
-				  const cairo_pattern_t	*source,
-				  cairo_glyph_t		*glyphs,
-				  int			 num_glyphs,
-				  cairo_scaled_font_t	*scaled_font,
-				  cairo_clip_t		*clip,
-				  int			*remaining_glyphs)
+_cairo_win32_surface_show_glyphs_internal (void			*surface,
+					   cairo_operator_t	 op,
+					   const cairo_pattern_t	*source,
+					   cairo_glyph_t		*glyphs,
+					   int			 num_glyphs,
+					   cairo_scaled_font_t	*scaled_font,
+					   cairo_clip_t		*clip,
+					   int			*remaining_glyphs,
+					   cairo_bool_t           glyph_indexing)
 {
 #ifdef CAIRO_HAS_WIN32_FONT
     if (scaled_font->backend->type == CAIRO_FONT_TYPE_DWRITE) {
 #ifdef CAIRO_HAS_DWRITE_FONT
         return _cairo_dwrite_show_glyphs_on_surface(surface, op, source, glyphs, num_glyphs, scaled_font, clip);
 #endif
     } else {
 	cairo_win32_surface_t *dst = surface;
@@ -1737,29 +1738,20 @@ cairo_int_status_t
 		dxy_buf[j+1] = _cairo_lround (logical_y - next_logical_y);
 		    /* note that GDI coordinate system is inverted */
 
 		logical_x = next_logical_x;
 		logical_y = next_logical_y;
 	    }
 	}
 
-	/* Using glyph indices for a Type 1 font does not work on a
-	 * printer DC. The win32 printing surface will convert the the
-	 * glyph indices of Type 1 fonts to the unicode values.
-	 */
-	if ((dst->flags & CAIRO_WIN32_SURFACE_FOR_PRINTING) &&
-	    _cairo_win32_scaled_font_is_type1 (scaled_font))
-	{
+	if (glyph_indexing)
+	    glyph_index_option = ETO_GLYPH_INDEX;
+	else
 	    glyph_index_option = 0;
-	}
-	else
-	{
-	    glyph_index_option = ETO_GLYPH_INDEX;
-	}
 
 	win_result = ExtTextOutW(dst->dc,
 				 start_x,
 				 start_y,
 				 glyph_index_option | ETO_PDY,
 				 NULL,
 				 glyph_buf,
 				 num_glyphs,
@@ -1778,16 +1770,37 @@ cairo_int_status_t
     }
 #else
     return CAIRO_INT_STATUS_UNSUPPORTED;
 #endif
 }
 
 #undef STACK_GLYPH_SIZE
 
+cairo_int_status_t
+_cairo_win32_surface_show_glyphs (void			*surface,
+ 				  cairo_operator_t	 op,
+ 				  const cairo_pattern_t *source,
+ 				  cairo_glyph_t	 	*glyphs,
+ 				  int			 num_glyphs,
+ 				  cairo_scaled_font_t	*scaled_font,
+ 				  cairo_clip_t          *clip,
+ 				  int		      	*remaining_glyphs)
+{
+    return _cairo_win32_surface_show_glyphs_internal (surface,
+ 						      op,
+ 						      source,
+ 						      glyphs,
+ 						      num_glyphs,
+ 						      scaled_font,
+ 						      clip,
+ 						      remaining_glyphs,
+ 						      TRUE);
+}
+
 static cairo_surface_t *
 cairo_win32_surface_create_internal (HDC hdc, cairo_format_t format)
 {
     cairo_win32_surface_t *surface;
 
     RECT rect;
 
     surface = malloc (sizeof (cairo_win32_surface_t));
new file mode 100644
--- /dev/null
+++ b/gfx/cairo/unicode-printing.patch
@@ -0,0 +1,333 @@
+diff --git a/gfx/cairo/cairo/src/cairo-win32-printing-surface.c b/gfx/cairo/cairo/src/cairo-win32-printing-surface.c
+--- a/gfx/cairo/cairo/src/cairo-win32-printing-surface.c
++++ b/gfx/cairo/cairo/src/cairo-win32-printing-surface.c
+@@ -1426,16 +1426,104 @@ _cairo_win32_printing_surface_fill (void
+     }
+ 
+     fflush(stderr);
+ 
+     return status;
+ }
+ 
+ static cairo_int_status_t
++_cairo_win32_printing_surface_emit_win32_glyphs (cairo_win32_surface_t 	*surface,
++						 cairo_operator_t	 op,
++						 const cairo_pattern_t  *source,
++						 cairo_glyph_t        	*glyphs,
++						 int			 num_glyphs,
++						 cairo_scaled_font_t  	*scaled_font,
++						 cairo_clip_t		*clip,
++						 int			*remaining_glyphs)
++{
++    cairo_matrix_t ctm;
++    cairo_glyph_t  *unicode_glyphs;
++    cairo_scaled_font_subsets_glyph_t subset_glyph;
++    int i, first;
++    cairo_bool_t sequence_is_unicode;
++    cairo_status_t status = CAIRO_STATUS_SUCCESS;
++
++    /* Where possible reverse the glyph indices back to unicode
++     * characters. Strings of glyphs that could not be reversed to
++     * unicode will be printed with ETO_GLYPH_INDEX.
++     *
++     * As _cairo_win32_scaled_font_index_to_ucs4() is a slow
++     * operation, the font subsetting function
++     * _cairo_scaled_font_subsets_map_glyph() is used to obtain
++     * the unicode value because it caches the reverse mapping in
++     * the subsets.
++     */
++
++    if (surface->has_ctm) {
++	for (i = 0; i < num_glyphs; i++)
++	    cairo_matrix_transform_point (&surface->ctm, &glyphs[i].x, &glyphs[i].y);
++	cairo_matrix_multiply (&ctm, &scaled_font->ctm, &surface->ctm);
++	scaled_font = cairo_scaled_font_create (scaled_font->font_face,
++						&scaled_font->font_matrix,
++						&ctm,
++						&scaled_font->options);
++    }
++
++    unicode_glyphs = _cairo_malloc_ab (num_glyphs, sizeof (cairo_glyph_t));
++    if (unicode_glyphs == NULL)
++	return _cairo_error (CAIRO_STATUS_NO_MEMORY);
++
++    memcpy (unicode_glyphs, glyphs, num_glyphs * sizeof (cairo_glyph_t));
++    for (i = 0; i < num_glyphs; i++) {
++	status = _cairo_scaled_font_subsets_map_glyph (surface->font_subsets,
++						       scaled_font,
++						       glyphs[i].index,
++						       NULL, 0,
++						       &subset_glyph);
++	if (status)
++	    goto fail;
++
++	unicode_glyphs[i].index = subset_glyph.unicode;
++    }
++
++    i = 0;
++    first = 0;
++    sequence_is_unicode = unicode_glyphs[0].index <= 0xffff;
++    while (i < num_glyphs) {
++	if (i == num_glyphs - 1 ||
++	    ((unicode_glyphs[i + 1].index < 0xffff) != sequence_is_unicode))
++	{
++	    status = _cairo_win32_surface_show_glyphs_internal (
++		surface,
++		op,
++		source,
++		sequence_is_unicode ? &unicode_glyphs[first] : &glyphs[first],
++		i - first + 1,
++		scaled_font,
++		clip,
++		remaining_glyphs,
++		! sequence_is_unicode);
++	    first = i + 1;
++	    if (i < num_glyphs - 1)
++		sequence_is_unicode = unicode_glyphs[i + 1].index <= 0xffff;
++	}
++	i++;
++    }
++
++fail:
++    if (surface->has_ctm)
++	cairo_scaled_font_destroy (scaled_font);
++
++    free (unicode_glyphs);
++
++    return status;
++}
++
++static cairo_int_status_t
+ _cairo_win32_printing_surface_show_glyphs (void                 *abstract_surface,
+                                            cairo_operator_t	 op,
+                                            const cairo_pattern_t *source,
+                                            cairo_glyph_t        *glyphs,
+                                            int			 num_glyphs,
+                                            cairo_scaled_font_t  *scaled_font,
+ 					   cairo_clip_t		*clip,
+ 					   int			*remaining_glyphs)
+@@ -1533,77 +1621,24 @@ _cairo_win32_printing_surface_show_glyph
+         }
+     }
+ #endif
+ 
+ #if CAIRO_HAS_WIN32_FONT
+     if (cairo_scaled_font_get_type (scaled_font) == CAIRO_FONT_TYPE_WIN32 &&
+ 	source->type == CAIRO_PATTERN_TYPE_SOLID)
+     {
+-	cairo_matrix_t ctm;
+-	cairo_glyph_t  *type1_glyphs = NULL;
+-	cairo_scaled_font_subsets_glyph_t subset_glyph;
+-
+-	/* Calling ExtTextOutW() with ETO_GLYPH_INDEX and a Type 1
+-	 * font on a printer DC prints garbled text. The text displays
+-	 * correctly on a display DC. When using a printer
+-	 * DC, ExtTextOutW() only works with characters and not glyph
+-	 * indices.
+-	 *
+-	 * For Type 1 fonts the glyph indices are converted back to
+-	 * unicode characters before calling _cairo_win32_surface_show_glyphs().
+-	 *
+-	 * As _cairo_win32_scaled_font_index_to_ucs4() is a slow
+-	 * operation, the font subsetting function
+-	 * _cairo_scaled_font_subsets_map_glyph() is used to obtain
+-	 * the unicode value because it caches the reverse mapping in
+-	 * the subsets.
+-	 */
+-	if (_cairo_win32_scaled_font_is_type1 (scaled_font)) {
+-	    type1_glyphs = _cairo_malloc_ab (num_glyphs, sizeof (cairo_glyph_t));
+-	    if (type1_glyphs == NULL) {
+-		status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
+-		goto FINISH;
+-	    }
+-	    memcpy (type1_glyphs, glyphs, num_glyphs * sizeof (cairo_glyph_t));
+-	    for (i = 0; i < num_glyphs; i++) {
+-		status = _cairo_scaled_font_subsets_map_glyph (surface->font_subsets,
+-							       scaled_font,
+-							       type1_glyphs[i].index,
+-							       NULL, 0,
+-							       &subset_glyph);
+-		if (status)
+-		    goto FINISH;
+-
+-		type1_glyphs[i].index = subset_glyph.unicode;
+-	    }
+-	    glyphs = type1_glyphs;
+-	}
+-
+-	if (surface->has_ctm || surface->has_gdi_ctm) {
+-	    cairo_matrix_multiply (&ctm, &surface->ctm, &surface->gdi_ctm);
+-	    for (i = 0; i < num_glyphs; i++)
+-		cairo_matrix_transform_point (&ctm, &glyphs[i].x, &glyphs[i].y);
+-	    cairo_matrix_multiply (&ctm, &scaled_font->ctm, &ctm);
+-	    scaled_font = cairo_scaled_font_create (scaled_font->font_face,
+-						    &scaled_font->font_matrix,
+-						    &ctm,
+-						    &scaled_font->options);
+-	}
+-	status = _cairo_win32_surface_show_glyphs (surface, op,
+-						   source, glyphs,
+-						   num_glyphs, scaled_font,
+-						   clip,
+-						   remaining_glyphs);
+-	if (surface->has_ctm || surface->has_gdi_ctm)
+-	    cairo_scaled_font_destroy (scaled_font);
+-
+-	if (type1_glyphs != NULL)
+-	    free (type1_glyphs);
+-
++	status = _cairo_win32_printing_surface_emit_win32_glyphs (surface,
++								  op,
++								  source,
++								  glyphs,
++								  num_glyphs,
++								  scaled_font,
++								  clip,
++								  remaining_glyphs);
+ 	goto FINISH;
+     }
+ #endif
+ 
+     SaveDC (surface->dc);
+     old_ctm = surface->ctm;
+     old_has_ctm = surface->has_ctm;
+     surface->has_ctm = TRUE;
+diff --git a/gfx/cairo/cairo/src/cairo-win32-private.h b/gfx/cairo/cairo/src/cairo-win32-private.h
+--- a/gfx/cairo/cairo/src/cairo-win32-private.h
++++ b/gfx/cairo/cairo/src/cairo-win32-private.h
+@@ -157,16 +157,27 @@ _cairo_win32_surface_get_extents (void		
+ uint32_t
+ _cairo_win32_flags_for_dc (HDC dc);
+ 
+ cairo_status_t
+ _cairo_win32_surface_set_clip_region (void           *abstract_surface,
+ 				      cairo_region_t *region);
+ 
+ cairo_int_status_t
++_cairo_win32_surface_show_glyphs_internal (void			 *surface,
++					   cairo_operator_t	  op,
++					   const cairo_pattern_t *source,
++					   cairo_glyph_t	 *glyphs,
++					   int			  num_glyphs,
++					   cairo_scaled_font_t	 *scaled_font,
++					   cairo_clip_t		 *clip,
++					   int			 *remaining_glyphs,
++					   cairo_bool_t		  glyph_indices);
++
++cairo_int_status_t
+ _cairo_win32_surface_show_glyphs (void			*surface,
+ 				  cairo_operator_t	 op,
+ 				  const cairo_pattern_t	*source,
+ 				  cairo_glyph_t		*glyphs,
+ 				  int			 num_glyphs,
+ 				  cairo_scaled_font_t	*scaled_font,
+ 				  cairo_clip_t		*clip,
+ 				  int			*remaining_glyphs);
+diff --git a/gfx/cairo/cairo/src/cairo-win32-surface.c b/gfx/cairo/cairo/src/cairo-win32-surface.c
+--- a/gfx/cairo/cairo/src/cairo-win32-surface.c
++++ b/gfx/cairo/cairo/src/cairo-win32-surface.c
+@@ -1607,24 +1607,25 @@ static cairo_status_t
+ _cairo_win32_surface_flush (void *abstract_surface)
+ {
+     return _cairo_win32_surface_set_clip_region (abstract_surface, NULL);
+ }
+ 
+ #define STACK_GLYPH_SIZE 256
+ 
+ cairo_int_status_t
+-_cairo_win32_surface_show_glyphs (void			*surface,
+-				  cairo_operator_t	 op,
+-				  const cairo_pattern_t	*source,
+-				  cairo_glyph_t		*glyphs,
+-				  int			 num_glyphs,
+-				  cairo_scaled_font_t	*scaled_font,
+-				  cairo_clip_t		*clip,
+-				  int			*remaining_glyphs)
++_cairo_win32_surface_show_glyphs_internal (void			*surface,
++					   cairo_operator_t	 op,
++					   const cairo_pattern_t	*source,
++					   cairo_glyph_t		*glyphs,
++					   int			 num_glyphs,
++					   cairo_scaled_font_t	*scaled_font,
++					   cairo_clip_t		*clip,
++					   int			*remaining_glyphs,
++					   cairo_bool_t           glyph_indexing)
+ {
+ #ifdef CAIRO_HAS_WIN32_FONT
+     if (scaled_font->backend->type == CAIRO_FONT_TYPE_DWRITE) {
+ #ifdef CAIRO_HAS_DWRITE_FONT
+         return _cairo_dwrite_show_glyphs_on_surface(surface, op, source, glyphs, num_glyphs, scaled_font, clip);
+ #endif
+     } else {
+ 	cairo_win32_surface_t *dst = surface;
+@@ -1737,29 +1738,20 @@ _cairo_win32_surface_show_glyphs (void		
+ 		dxy_buf[j+1] = _cairo_lround (logical_y - next_logical_y);
+ 		    /* note that GDI coordinate system is inverted */
+ 
+ 		logical_x = next_logical_x;
+ 		logical_y = next_logical_y;
+ 	    }
+ 	}
+ 
+-	/* Using glyph indices for a Type 1 font does not work on a
+-	 * printer DC. The win32 printing surface will convert the the
+-	 * glyph indices of Type 1 fonts to the unicode values.
+-	 */
+-	if ((dst->flags & CAIRO_WIN32_SURFACE_FOR_PRINTING) &&
+-	    _cairo_win32_scaled_font_is_type1 (scaled_font))
+-	{
++	if (glyph_indexing)
++	    glyph_index_option = ETO_GLYPH_INDEX;
++	else
+ 	    glyph_index_option = 0;
+-	}
+-	else
+-	{
+-	    glyph_index_option = ETO_GLYPH_INDEX;
+-	}
+ 
+ 	win_result = ExtTextOutW(dst->dc,
+ 				 start_x,
+ 				 start_y,
+ 				 glyph_index_option | ETO_PDY,
+ 				 NULL,
+ 				 glyph_buf,
+ 				 num_glyphs,
+@@ -1778,16 +1770,37 @@ _cairo_win32_surface_show_glyphs (void		
+     }
+ #else
+     return CAIRO_INT_STATUS_UNSUPPORTED;
+ #endif
+ }
+ 
+ #undef STACK_GLYPH_SIZE
+ 
++cairo_int_status_t
++_cairo_win32_surface_show_glyphs (void			*surface,
++ 				  cairo_operator_t	 op,
++ 				  const cairo_pattern_t *source,
++ 				  cairo_glyph_t	 	*glyphs,
++ 				  int			 num_glyphs,
++ 				  cairo_scaled_font_t	*scaled_font,
++ 				  cairo_clip_t          *clip,
++ 				  int		      	*remaining_glyphs)
++{
++    return _cairo_win32_surface_show_glyphs_internal (surface,
++ 						      op,
++ 						      source,
++ 						      glyphs,
++ 						      num_glyphs,
++ 						      scaled_font,
++ 						      clip,
++ 						      remaining_glyphs,
++ 						      TRUE);
++}
++
+ static cairo_surface_t *
+ cairo_win32_surface_create_internal (HDC hdc, cairo_format_t format)
+ {
+     cairo_win32_surface_t *surface;
+ 
+     RECT rect;
+ 
+     surface = malloc (sizeof (cairo_win32_surface_t));
--- a/gfx/thebes/GLContext.cpp
+++ b/gfx/thebes/GLContext.cpp
@@ -1849,19 +1849,19 @@ GLContext::TexImage2D(GLenum target, GLi
 #endif
 
     // Don't use UNPACK_ROW_LENGTH if the length would be greater than the
     // maximum texture size
     int rowLength = stride/pixelsize;
     if (rowLength > mMaxTextureSize)
       useUnpackRowLength = false;
 
-    if (useUnpackRowLength)
+    if (useUnpackRowLength) {
         fPixelStorei(LOCAL_GL_UNPACK_ROW_LENGTH, rowLength);
-    else if (stride != width * pixelsize) {
+    } else if (stride != width * pixelsize) {
         // Not using the whole row of texture data and GLES doesn't 
         // support GL_UNPACK_ROW_LENGTH. We need to upload each row
         // separately.
         fTexImage2D(target,
                     border,
                     internalformat,
                     width,
                     height,
@@ -1911,19 +1911,28 @@ GLContext::TexSubImage2D(GLenum target, 
                          GLint pixelsize, GLenum format, 
                          GLenum type, const GLvoid* pixels)
 {
     fPixelStorei(LOCAL_GL_UNPACK_ALIGNMENT, 
                  NS_MIN(GetAddressAlignment((ptrdiff_t)pixels),
                         GetAddressAlignment((ptrdiff_t)stride)));
 
 #ifndef USE_GLES2
-    fPixelStorei(LOCAL_GL_UNPACK_ROW_LENGTH, stride/pixelsize);
+    bool useUnpackRowLength = true;
 #else
-    if (stride != width * pixelsize) {
+    bool useUnpackRowLength = IsExtensionSupported(EXT_unpack_subimage);
+#endif
+
+    int rowLength = stride/pixelsize;
+    if (rowLength > mMaxTextureSize)
+      useUnpackRowLength = false;
+
+    if (useUnpackRowLength) {
+        fPixelStorei(LOCAL_GL_UNPACK_ROW_LENGTH, rowLength);
+    } else if (stride != width * pixelsize) {
         // Not using the whole row of texture data and GLES doesn't 
         // support GL_UNPACK_ROW_LENGTH. We need to upload each row
         // separately.
         const unsigned char *row = (const unsigned char *)pixels; 
         for (int h = 0; h < height; h++) {
             fTexSubImage2D(target,
                            level,
                            xoffset,
@@ -1935,31 +1944,29 @@ GLContext::TexSubImage2D(GLenum target, 
                            row);
 
             row += stride;
         }
 
         fPixelStorei(LOCAL_GL_UNPACK_ALIGNMENT, 4);
         return;
     }
-#endif
 
     fTexSubImage2D(target,
                    level,
                    xoffset,
                    yoffset,
                    width,
                    height,
                    format,
                    type,
                    pixels);
 
-#ifndef USE_GLES2
-    fPixelStorei(LOCAL_GL_UNPACK_ROW_LENGTH, 0);
-#endif
+    if (useUnpackRowLength)
+        fPixelStorei(LOCAL_GL_UNPACK_ROW_LENGTH, 0);
     fPixelStorei(LOCAL_GL_UNPACK_ALIGNMENT, 4);
 }
 
 void
 GLContext::RectTriangles::addRect(GLfloat x0, GLfloat y0, GLfloat x1, GLfloat y1,
                                   GLfloat tx0, GLfloat ty0, GLfloat tx1, GLfloat ty1)
 {
     vert_coord v;
--- a/gfx/thebes/GLContextProviderEGL.cpp
+++ b/gfx/thebes/GLContextProviderEGL.cpp
@@ -164,17 +164,21 @@ typedef void *EGLConfig;
 typedef void *EGLContext;
 typedef void *EGLDisplay;
 typedef void *EGLSurface;
 typedef void *EGLClientBuffer;
 typedef void *EGLCastToRelevantPtr;
 typedef void *EGLImageKHR;
 typedef void *GLeglImageOES;
 
+#ifdef MOZ_WIDGET_QT
+#define EGL_DEFAULT_DISPLAY  ((EGLNativeDisplayType)QX11Info::display())
+#else
 #define EGL_DEFAULT_DISPLAY  ((EGLNativeDisplayType)0)
+#endif
 #define EGL_NO_CONTEXT       ((EGLContext)0)
 #define EGL_NO_DISPLAY       ((EGLDisplay)0)
 #define EGL_NO_SURFACE       ((EGLSurface)0)
 
 #define EGL_DISPLAY()        sEGLLibrary.Display()
 
 #define ADD_ATTR_2(_array, _k, _v) do {         \
     (_array).AppendElement(_k);                 \
@@ -237,16 +241,18 @@ public:
         mHave_EGL_KHR_image_pixmap = PR_FALSE;
         mHave_EGL_KHR_gl_texture_2D_image = PR_FALSE;
         mHave_EGL_KHR_lock_surface = PR_FALSE;
         mHave_EGL_ANGLE_surface_d3d_texture_2d_share_handle = PR_FALSE;
     }
 
     typedef EGLDisplay (GLAPIENTRY * pfnGetDisplay)(void *display_id);
     pfnGetDisplay fGetDisplay;
+    typedef EGLSurface (GLAPIENTRY * pfnGetCurrentSurface)(EGLint);
+    pfnGetCurrentSurface fGetCurrentSurface;
     typedef EGLContext (GLAPIENTRY * pfnGetCurrentContext)(void);
     pfnGetCurrentContext fGetCurrentContext;
     typedef EGLBoolean (GLAPIENTRY * pfnMakeCurrent)(EGLDisplay dpy, EGLSurface draw, EGLSurface read, EGLContext ctx);
     pfnMakeCurrent fMakeCurrent;
     typedef EGLBoolean (GLAPIENTRY * pfnDestroyContext)(EGLDisplay dpy, EGLContext ctx);
     pfnDestroyContext fDestroyContext;
     typedef EGLContext (GLAPIENTRY * pfnCreateContext)(EGLDisplay dpy, EGLConfig config, EGLContext share_context, const EGLint *attrib_list);
     pfnCreateContext fCreateContext;
@@ -359,16 +365,17 @@ public:
             return PR_FALSE;
         }
 
 #define SYMBOL(name) \
     { (PRFuncPtr*) &f##name, { "egl" #name, NULL } }
 
         LibrarySymbolLoader::SymLoadStruct earlySymbols[] = {
             SYMBOL(GetDisplay),
+            SYMBOL(GetCurrentSurface),
             SYMBOL(GetCurrentContext),
             SYMBOL(MakeCurrent),
             SYMBOL(DestroyContext),
             SYMBOL(CreateContext),
             SYMBOL(DestroySurface),
             SYMBOL(CreateWindowSurface),
             SYMBOL(CreatePbufferSurface),
             SYMBOL(CreatePixmapSurface),
@@ -688,17 +695,17 @@ public:
         if (mPlatformContext)
             return;
 
 #ifdef DEBUG
         printf_stderr("Destroying context %p surface %p on display %p\n", mContext, mSurface, EGL_DISPLAY());
 #endif
 
         sEGLLibrary.fDestroyContext(EGL_DISPLAY(), mContext);
-        if (mSurface) {
+        if (mSurface && !mPlatformContext) {
             sEGLLibrary.fDestroySurface(EGL_DISPLAY(), mSurface);
         }
     }
 
     GLContextType GetContextType() {
         return ContextTypeEGL;
     }
 
@@ -820,27 +827,25 @@ public:
         mSurface = CreateSurfaceForWindow(NULL, config);
 
         return sEGLLibrary.fMakeCurrent(EGL_DISPLAY(),
                                         mSurface, mSurface,
                                         mContext);
     }
 #endif
 
-#ifndef MOZ_WIDGET_QT
     virtual void
     ReleaseSurface() {
-        if (mSurface) {
+        if (mSurface && !mPlatformContext) {
             sEGLLibrary.fMakeCurrent(EGL_DISPLAY(), EGL_NO_SURFACE, EGL_NO_SURFACE,
                                      EGL_NO_CONTEXT);
             sEGLLibrary.fDestroySurface(EGL_DISPLAY(), mSurface);
             mSurface = NULL;
         }
     }
-#endif
 
     PRBool SetupLookupFunction()
     {
         mLookupFunc = (PlatformLookupFunction)sEGLLibrary.fGetProcAddress;
         return PR_TRUE;
     }
 
     void *GetNativeData(NativeDataType aType)
@@ -851,17 +856,17 @@ public:
 
         default:
             return nsnull;
         }
     }
 
     PRBool SwapBuffers()
     {
-        if (mSurface) {
+        if (mSurface && !mPlatformContext) {
             return sEGLLibrary.fSwapBuffers(EGL_DISPLAY(), mSurface);
         } else {
             return PR_FALSE;
         }
     }
     // GLContext interface - returns Tiled Texture Image in our case
     virtual already_AddRefed<TextureImage>
     CreateTextureImage(const nsIntSize& aSize,
@@ -1058,17 +1063,17 @@ GLContextEGL::ResizeOffscreen(const gfxI
                                                  pbsize);
         if (!surface) {
             NS_WARNING("Failed to resize pbuffer");
             return nsnull;
         }
 
         SetOffscreenSize(aNewSize, pbsize);
 
-        if (mSurface) {
+        if (mSurface && !mPlatformContext) {
             sEGLLibrary.fDestroySurface(EGL_DISPLAY(), mSurface);
         }
 
         mSurface = surface;
 
         MakeCurrent(PR_TRUE);
         ClearSafely();
 
@@ -1728,17 +1733,18 @@ GLContextProviderEGL::CreateForWindow(ns
 
     QGLContext* context = const_cast<QGLContext*>(QGLContext::currentContext());
     if (context && context->device()) {
         // Qt widget viewport already have GL context created by Qt
         // Create dummy GLContextEGL class
         nsRefPtr<GLContextEGL> glContext =
             new GLContextEGL(ContextFormat(DepthToGLFormat(context->device()->depth())),
                              NULL,
-                             NULL, NULL,
+                             NULL,
+                             sEGLLibrary.fGetCurrentSurface(LOCAL_EGL_DRAW), // just use same surface for read and draw
                              sEGLLibrary.fGetCurrentContext(),
                              PR_FALSE);
 
         if (!glContext->Init())
             return nsnull;
 
         glContext->SetIsDoubleBuffered(context->format().doubleBuffer());
 
--- a/gfx/thebes/GLDefs.h
+++ b/gfx/thebes/GLDefs.h
@@ -3193,10 +3193,11 @@ typedef ptrdiff_t GLintptr;
 #define LOCAL_EGL_BITMAP_PITCH_KHR            0x30C7
 #define LOCAL_EGL_BITMAP_PIXEL_SIZE_KHR       0x3110
 #define LOCAL_EGL_LOCK_USAGE_HINT_KHR         0x30C5
 #define LOCAL_EGL_MAP_PRESERVE_PIXELS_KHR     0x30C4
 #define LOCAL_EGL_READ_SURFACE_BIT_KHR        0x0001
 #define LOCAL_EGL_WRITE_SURFACE_BIT_KHR       0x0002
 #define LOCAL_EGL_LOCK_SURFACE_BIT_KHR        0x0080
 #define LOCAL_EGL_CORE_NATIVE_ENGINE          0x305B
-
+#define LOCAL_EGL_READ                        0x305A
+#define LOCAL_EGL_DRAW                        0x3059
 #endif
--- a/gfx/thebes/gfxFT2FontList.cpp
+++ b/gfx/thebes/gfxFT2FontList.cpp
@@ -307,18 +307,17 @@ gfxFT2FontList::GetDefaultFont(const gfx
     if (hGDI && ::GetObjectW(hGDI, sizeof(logFont), &logFont)) {
         nsAutoString resolvedName;
         if (ResolveFontName(nsDependentString(logFont.lfFaceName), resolvedName)) {
             return FindFontForFamily(resolvedName, aStyle, aNeedsBold);
         }
     }
 #elif defined(ANDROID)
     nsAutoString resolvedName;
-    if (ResolveFontName(nsDependentString(NS_LITERAL_STRING("Droid Sans")), 
-                        resolvedName))
+    if (ResolveFontName(NS_LITERAL_STRING("Droid Sans"), resolvedName))
         return FindFontForFamily(resolvedName, aStyle, aNeedsBold);
 #endif
     /* TODO: what about Qt or other platforms that may use this? */
     return nsnull;
 }
 
 gfxFontEntry*
 gfxFT2FontList::MakePlatformFont(const gfxProxyFontEntry *aProxyEntry,
--- a/intl/hyphenation/src/Makefile.in
+++ b/intl/hyphenation/src/Makefile.in
@@ -46,11 +46,12 @@ MODULE           = hyphenation
 LIBRARY_NAME     = hyphenation_s
 LIBXUL_LIBRARY   = 1
 
 CSRCS            = hyphen.c \
                    $(NULL)
 
 CPPSRCS          = nsHyphenator.cpp \
                    nsHyphenationManager.cpp \
+                   hnjstdio.cpp \
                    $(NULL)
 
 include $(topsrcdir)/config/rules.mk
--- a/intl/hyphenation/src/hnjalloc.h
+++ b/intl/hyphenation/src/hnjalloc.h
@@ -43,8 +43,41 @@
  */
 
 #include "mozilla/mozalloc.h"
 
 #define hnj_malloc(size)      moz_xmalloc(size)
 #define hnj_realloc(p, size)  moz_xrealloc(p, size)
 #define hnj_free(p)           moz_free(p)
 
+/*
+ * To enable us to load hyphenation dictionaries from arbitrary resource URIs,
+ * not just through file paths using stdio, we override the (few) stdio APIs
+ * that hyphen.c uses and provide our own reimplementation that calls Gecko
+ * i/o methods.
+ */
+
+#include <stdio.h> /* ensure stdio.h is loaded before our macros */
+
+#undef FILE
+#define FILE hnjFile
+
+#define fopen(path,mode)      hnjFopen(path,mode)
+#define fclose(file)          hnjFclose(file)
+#define fgets(buf,count,file) hnjFgets(buf,count,file)
+
+typedef struct hnjFile_ hnjFile;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+hnjFile* hnjFopen(const char* aURISpec, const char* aMode);
+
+int hnjFclose(hnjFile* f);
+
+char* hnjFgets(char* s, int n, hnjFile* f);
+
+#ifdef __cplusplus
+}
+#endif
+
+
new file mode 100644
--- /dev/null
+++ b/intl/hyphenation/src/hnjstdio.cpp
@@ -0,0 +1,137 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Hyphenation Service.
+ *
+ * The Initial Developer of the Original Code is
+ * Mozilla Foundation.
+ * Portions created by the Initial Developer are Copyright (C) 2011
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Jonathan Kew <jfkthame@gmail.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+// This file provides substitutes for the basic stdio routines used by hyphen.c
+// to read its dictionary files. We #define the stdio names to these versions
+// in hnjalloc.h, so that we can use nsIURI and nsIInputStream to specify and
+// access the dictionary resources.
+
+#include "hnjalloc.h"
+#include "nsNetUtil.h"
+
+#define BUFSIZE 1024
+
+struct hnjFile_ {
+    nsCOMPtr<nsIInputStream> mStream;
+    char                     mBuffer[BUFSIZE];
+    PRUint32                 mCurPos;
+    PRUint32                 mLimit;
+};
+
+// replacement for fopen()
+// (not a full substitute: only supports read access)
+hnjFile*
+hnjFopen(const char* aURISpec, const char* aMode)
+{
+    // this override only needs to support "r"
+    NS_ASSERTION(!strcmp(aMode, "r"), "unsupported fopen() mode in hnjFopen");
+
+    nsCOMPtr<nsIURI> uri;
+    nsresult rv = NS_NewURI(getter_AddRefs(uri), aURISpec);
+    if (NS_FAILED(rv)) {
+        return nsnull;
+    }
+
+    nsCOMPtr<nsIInputStream> instream;
+    rv = NS_OpenURI(getter_AddRefs(instream), uri);
+    if (NS_FAILED(rv)) {
+        return nsnull;
+    }
+
+    hnjFile *f = new hnjFile;
+    f->mStream = instream;
+    f->mCurPos = 0;
+    f->mLimit = 0;
+
+    return f;
+}
+
+// replacement for fclose()
+int
+hnjFclose(hnjFile* f)
+{
+    NS_ASSERTION(f && f->mStream, "bad argument to hnjFclose");
+
+    int result = 0;
+    nsresult rv = f->mStream->Close();
+    if (NS_FAILED(rv)) {
+        result = EOF;
+    }
+    f->mStream = nsnull;
+
+    delete f;
+    return result;
+}
+
+// replacement for fgets()
+// (not a full reimplementation, but sufficient for libhyphen's needs)
+char*
+hnjFgets(char* s, int n, hnjFile* f)
+{
+    NS_ASSERTION(s && f, "bad argument to hnjFgets");
+
+    int i = 0;
+    while (i < n - 1) {
+        if (f->mCurPos < f->mLimit) {
+            char c = f->mBuffer[f->mCurPos++];
+            s[i++] = c;
+            if (c == '\n' || c == '\r') {
+                break;
+            }
+            continue;
+        }
+
+        f->mCurPos = 0;
+
+        nsresult rv = f->mStream->Read(f->mBuffer, BUFSIZE, &f->mLimit);
+        if (NS_FAILED(rv)) {
+            f->mLimit = 0;
+            return nsnull;
+        }
+
+        if (f->mLimit == 0) {
+            break;
+        }
+    }
+
+    if (i == 0) {
+        return nsnull; // end of file
+    }
+
+    s[i] = '\0'; // null-terminate the returned string
+    return s;
+}
--- a/intl/hyphenation/src/nsHyphenator.cpp
+++ b/intl/hyphenation/src/nsHyphenator.cpp
@@ -35,33 +35,35 @@
  *
  * ***** END LICENSE BLOCK ***** */
 
 #include "nsHyphenator.h"
 #include "nsIFile.h"
 #include "nsUTF8Utils.h"
 #include "nsIUGenCategory.h"
 #include "nsUnicharUtilCIID.h"
+#include "nsNetUtil.h"
 
 #include "hyphen.h"
 
 nsHyphenator::nsHyphenator(nsIFile *aFile)
   : mDict(nsnull)
 {
-  nsCString path;
-  aFile->GetNativePath(path);
-  mDict = hnj_hyphen_load(path.get());
+  nsCString urlSpec;
+  nsresult rv = NS_GetURLSpecFromFile(aFile, urlSpec);
+  if (NS_FAILED(rv)) {
+    return;
+  }
+  mDict = hnj_hyphen_load(urlSpec.get());
 #ifdef DEBUG
   if (mDict) {
-    printf("loaded hyphenation patterns from %s\n", path.get());
+    printf("loaded hyphenation patterns from %s\n", urlSpec.get());
   }
 #endif
-  nsresult rv;
-  mCategories =
-    do_GetService(NS_UNICHARCATEGORY_CONTRACTID, &rv);
+  mCategories = do_GetService(NS_UNICHARCATEGORY_CONTRACTID, &rv);
   NS_ASSERTION(NS_SUCCEEDED(rv), "failed to get category service");
 }
 
 nsHyphenator::~nsHyphenator()
 {
   if (mDict != nsnull) {
     hnj_hyphen_free((HyphenDict*)mDict);
     mDict = nsnull;
--- a/js/src/config/system-headers
+++ b/js/src/config/system-headers
@@ -1015,16 +1015,24 @@ conic/conicstatisticsevent.h
 event.h
 #endif
 #ifdef MOZ_ENABLE_LIBPROXY
 proxy.h
 #endif
 #if MOZ_PLATFORM_MAEMO==6
 contentaction/contentaction.h
 #endif
+#ifdef MOZ_ENABLE_CONTENTMANAGER
+SelectSingleContentItemPage.h
+SelectMultipleContentItemsPage.h
+QtSparql/qsparqlconnection.h
+QtSparql/qsparqlquery.h
+QtSparql/qsparqlresult.h
+#endif
+
 #if MOZ_TREE_PIXMAN!=1
 pixman.h
 #endif
 #if MOZ_ENABLE_MEEGOTOUCHSHARE
 shareuiinterface.h
 #endif
 #if MOZ_NATIVE_LIBVPX==1
 vpx/vpx_decoder.h
--- a/js/src/jsemit.cpp
+++ b/js/src/jsemit.cpp
@@ -1440,17 +1440,17 @@ static ptrdiff_t
 EmitTraceOp(JSContext *cx, JSCodeGenerator *cg, JSParseNode *nextpn)
 {
     if (nextpn) {
         /*
          * Try to give the JSOP_TRACE the same line number as the next
          * instruction. nextpn is often a block, in which case the next
          * instruction typically comes from the first statement inside.
          */
-        if (nextpn->pn_type == TOK_LC && nextpn->pn_arity == PN_LIST && nextpn->pn_head)
+        if (nextpn->isKind(TOK_LC) && nextpn->isArity(PN_LIST) && nextpn->pn_head)
             nextpn = nextpn->pn_head;
         if (!UpdateLineNumberNotes(cx, cg, nextpn->pn_pos.begin.lineno))
             return -1;
     }
 
     uint32 index = cg->traceIndex;
     if (index < UINT16_MAX)
         cg->traceIndex++;
@@ -1690,17 +1690,17 @@ js_PopStatementCG(JSContext *cx, JSCodeG
     return JS_TRUE;
 }
 
 JSBool
 js_DefineCompileTimeConstant(JSContext *cx, JSCodeGenerator *cg, JSAtom *atom,
                              JSParseNode *pn)
 {
     /* XXX just do numbers for now */
-    if (pn->pn_type == TOK_NUMBER) {
+    if (pn->isKind(TOK_NUMBER)) {
         if (!cg->constMap.put(atom, NumberValue(pn->pn_dval)))
             return JS_FALSE;
     }
     return JS_TRUE;
 }
 
 JSStmtInfo *
 js_LexicalLookup(JSTreeContext *tc, JSAtom *atom, jsint *slotp, JSStmtInfo *stmt)
@@ -1950,17 +1950,17 @@ EmitSlotIndexOp(JSContext *cx, JSOp op, 
     pc += 2;
     SET_INDEX(pc, index);
     return bigSuffix == JSOP_NOP || js_Emit1(cx, cg, bigSuffix) >= 0;
 }
 
 bool
 JSCodeGenerator::shouldNoteClosedName(JSParseNode *pn)
 {
-    return !callsEval() && pn->pn_defn && pn->isClosed();
+    return !callsEval() && pn->isDefn() && pn->isClosed();
 }
 
 /*
  * Adjust the slot for a block local to account for the number of variables
  * that share the same index space with locals. Due to the incremental code
  * generation for top-level script, we do the adjustment via code patching in
  * Compiler::compileScript; see comments there.
  *
@@ -1978,17 +1978,17 @@ AdjustBlockSlot(JSContext *cx, JSCodeGen
         }
     }
     return slot;
 }
 
 static bool
 EmitEnterBlock(JSContext *cx, JSParseNode *pn, JSCodeGenerator *cg)
 {
-    JS_ASSERT(PN_TYPE(pn) == TOK_LEXICALSCOPE);
+    JS_ASSERT(pn->isKind(TOK_LEXICALSCOPE));
     if (!EmitObjectOp(cx, pn->pn_objbox, JSOP_ENTERBLOCK, cg))
         return false;
 
     JSObject *blockObj = pn->pn_objbox->object;
     jsint depth = AdjustBlockSlot(cx, cg, OBJ_BLOCK_DEPTH(cx, blockObj));
     if (depth < 0)
         return false;
 
@@ -1998,17 +1998,17 @@ EmitEnterBlock(JSContext *cx, JSParseNod
 
         /* Beware the empty destructuring dummy. */
         if (v.isUndefined()) {
             JS_ASSERT(slot + 1 <= limit);
             continue;
         }
 
         JSDefinition *dn = (JSDefinition *) v.toPrivate();
-        JS_ASSERT(dn->pn_defn);
+        JS_ASSERT(dn->isDefn());
         JS_ASSERT(uintN(dn->frameSlot() + depth) < JS_BIT(16));
         dn->pn_cookie.set(dn->pn_cookie.level(), uint16(dn->frameSlot() + depth));
 #ifdef DEBUG
         for (JSParseNode *pnu = dn->dn_uses; pnu; pnu = pnu->pn_link) {
             JS_ASSERT(pnu->pn_lexdef == dn);
             JS_ASSERT(!(pnu->pn_dflags & PND_BOUND));
             JS_ASSERT(pnu->pn_cookie.isFree());
         }
@@ -2145,20 +2145,20 @@ BindKnownGlobal(JSContext *cx, JSCodeGen
 
 // See BindKnownGlobal()'s comment.
 static bool
 BindGlobal(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn, JSAtom *atom)
 {
     pn->pn_cookie.makeFree();
 
     JSDefinition *dn;
-    if (pn->pn_used) {
+    if (pn->isUsed()) {
         dn = pn->pn_lexdef;
     } else {
-        if (!pn->pn_defn)
+        if (!pn->isDefn())
             return true;
         dn = (JSDefinition *)pn;
     }
 
     // Only optimize for defined globals.
     if (!dn->isGlobal())
         return true;
 
@@ -2185,43 +2185,43 @@ BindGlobal(JSContext *cx, JSCodeGenerato
 static JSBool
 BindNameToSlot(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
 {
     JSDefinition *dn;
     JSOp op;
     JSAtom *atom;
     JSDefinition::Kind dn_kind;
 
-    JS_ASSERT(pn->pn_type == TOK_NAME);
+    JS_ASSERT(pn->isKind(TOK_NAME));
 
     /* Idempotency tests come first, since we may be called more than once. */
     if (pn->pn_dflags & PND_BOUND)
         return JS_TRUE;
 
     /* No cookie initialized for these two, they're pre-bound by definition. */
-    JS_ASSERT(pn->pn_op != JSOP_ARGUMENTS && pn->pn_op != JSOP_CALLEE);
+    JS_ASSERT(!pn->isOp(JSOP_ARGUMENTS) && !pn->isOp(JSOP_CALLEE));
 
     /*
      * The parser linked all uses (including forward references) to their
      * definitions, unless a with statement or direct eval intervened.
      */
-    if (pn->pn_used) {
+    if (pn->isUsed()) {
         JS_ASSERT(pn->pn_cookie.isFree());
         dn = pn->pn_lexdef;
-        JS_ASSERT(dn->pn_defn);
+        JS_ASSERT(dn->isDefn());
         if (pn->isDeoptimized())
             return JS_TRUE;
         pn->pn_dflags |= (dn->pn_dflags & PND_CONST);
     } else {
-        if (!pn->pn_defn)
+        if (!pn->isDefn())
             return JS_TRUE;
         dn = (JSDefinition *) pn;
     }
 
-    op = PN_OP(pn);
+    op = pn->getOp();
     if (op == JSOP_NOP)
         return JS_TRUE;
 
     JS_ASSERT(JOF_OPTYPE(op) == JOF_ATOM);
     atom = pn->pn_atom;
     UpvarCookie cookie = dn->pn_cookie;
     dn_kind = dn->kind();
 
@@ -2238,45 +2238,45 @@ BindNameToSlot(JSContext *cx, JSCodeGene
       case JSOP_NAME:
       case JSOP_SETCONST:
         break;
       case JSOP_DELNAME:
         if (dn_kind != JSDefinition::UNKNOWN) {
             if (cg->parser->callerFrame && dn->isTopLevel())
                 JS_ASSERT(cg->compileAndGo());
             else
-                pn->pn_op = JSOP_FALSE;
+                pn->setOp(JSOP_FALSE);
             pn->pn_dflags |= PND_BOUND;
             return JS_TRUE;
         }
         break;
       default:
         if (pn->isConst()) {
             if (cg->needStrictChecks()) {
                 JSAutoByteString name;
                 if (!js_AtomToPrintableString(cx, atom, &name) ||
                     !ReportStrictModeError(cx, CG_TS(cg), cg, pn, JSMSG_READ_ONLY, name.ptr())) {
                     return JS_FALSE;
                 }
             }
-            pn->pn_op = op = JSOP_NAME;
+            pn->setOp(op = JSOP_NAME);
         }
     }
 
     if (dn->isGlobal()) {
         if (op == JSOP_NAME) {
             /*
              * If the definition is a defined global, not potentially aliased
              * by a local variable, and not mutating the variable, try and
              * optimize to a fast, unguarded global access.
              */
             if (!BindKnownGlobal(cx, cg, dn, pn, atom))
                 return JS_FALSE;
             if (!pn->pn_cookie.isFree()) {
-                pn->pn_op = JSOP_GETGLOBAL;
+                pn->setOp(JSOP_GETGLOBAL);
                 return JS_TRUE;
             }
         }
 
         /*
          * The locally stored cookie here should really come from |pn|, not
          * |dn|. For example, we could have a SETGNAME op's lexdef be a
          * GETGLOBAL op, and their cookies have very different meanings. As
@@ -2303,17 +2303,17 @@ BindNameToSlot(JSContext *cx, JSCodeGene
              * If this is an eval in the global scope, then unbound variables
              * must be globals, so try to use GNAME ops.
              */
             if (caller->isGlobalFrame() && TryConvertToGname(cg, pn, &op)) {
                 jsatomid _;
                 if (!cg->makeAtomIndex(atom, &_))
                     return JS_FALSE;
 
-                pn->pn_op = op;
+                pn->setOp(op);
                 pn->pn_dflags |= PND_BOUND;
                 return JS_TRUE;
             }
 
             /*
              * Out of tricks, so we must rely on PICs to optimize named
              * accesses from direct eval called from function code.
              */
@@ -2323,17 +2323,17 @@ BindNameToSlot(JSContext *cx, JSCodeGene
         /* Optimize accesses to undeclared globals. */
         if (!cg->mightAliasLocals() && !TryConvertToGname(cg, pn, &op))
             return JS_TRUE;
 
         jsatomid _;
         if (!cg->makeAtomIndex(atom, &_))
             return JS_FALSE;
 
-        pn->pn_op = op;
+        pn->setOp(op);
         pn->pn_dflags |= PND_BOUND;
 
         return JS_TRUE;
     }
 
     uint16 level = cookie.level();
     JS_ASSERT(cg->staticLevel >= level);
 
@@ -2401,17 +2401,17 @@ BindNameToSlot(JSContext *cx, JSCodeGene
                 if (tc->inFunction())
                     slot += tc->fun()->nargs;
             }
 
             JS_ASSERT(index < upvarMap.length());
             upvarMap[index].set(skip, slot);
         }
 
-        pn->pn_op = JSOP_GETFCSLOT;
+        pn->setOp(JSOP_GETFCSLOT);
         JS_ASSERT((index & JS_BITMASK(16)) == index);
         pn->pn_cookie.set(0, index);
         pn->pn_dflags |= PND_BOUND;
         return JS_TRUE;
     }
 
     /*
      * We are compiling a function body and may be able to optimize name
@@ -2443,22 +2443,22 @@ BindNameToSlot(JSContext *cx, JSCodeGene
           case JSOP_DECNAME:  op = JSOP_DECARG; break;
           case JSOP_NAMEDEC:  op = JSOP_ARGDEC; break;
           default: JS_NOT_REACHED("arg");
         }
         JS_ASSERT(!pn->isConst());
         break;
 
       case JSDefinition::VAR:
-        if (PN_OP(dn) == JSOP_CALLEE) {
+        if (dn->isOp(JSOP_CALLEE)) {
             JS_ASSERT(op != JSOP_CALLEE);
             JS_ASSERT((cg->fun()->flags & JSFUN_LAMBDA) && atom == cg->fun()->atom);
 
             /*
-             * Leave pn->pn_op == JSOP_NAME if cg->fun is heavyweight to
+             * Leave pn->isOp(JSOP_NAME) if cg->fun is heavyweight to
              * address two cases: a new binding introduced by eval, and
              * assignment to the name in strict mode.
              *
              *   var fun = (function f(s) { eval(s); return f; });
              *   assertEq(fun("var f = 42"), 42);
              *
              * ECMAScript specifies that a function expression's name is bound
              * in a lexical environment distinct from that used to bind its
@@ -2477,17 +2477,17 @@ BindNameToSlot(JSContext *cx, JSCodeGene
              * the scope chain so that assignment will throw a TypeError.
              */
             JS_ASSERT(op != JSOP_DELNAME);
             if (!(cg->flags & TCF_FUN_HEAVYWEIGHT)) {
                 op = JSOP_CALLEE;
                 pn->pn_dflags |= PND_CONST;
             }
 
-            pn->pn_op = op;
+            pn->setOp(op);
             pn->pn_dflags |= PND_BOUND;
             return JS_TRUE;
         }
         /* FALL THROUGH */
 
       default:
         JS_ASSERT_IF(dn_kind != JSDefinition::FUNCTION,
                      dn_kind == JSDefinition::VAR ||
@@ -2501,18 +2501,18 @@ BindNameToSlot(JSContext *cx, JSCodeGene
           case JSOP_DECNAME:  op = JSOP_DECLOCAL; break;
           case JSOP_NAMEDEC:  op = JSOP_LOCALDEC; break;
           default: JS_NOT_REACHED("local");
         }
         JS_ASSERT_IF(dn_kind == JSDefinition::CONST, pn->pn_dflags & PND_CONST);
         break;
     }
 
-    JS_ASSERT(op != PN_OP(pn));
-    pn->pn_op = op;
+    JS_ASSERT(!pn->isOp(op));
+    pn->setOp(op);
     pn->pn_cookie.set(0, cookie.slot());
     pn->pn_dflags |= PND_BOUND;
     return JS_TRUE;
 }
 
 bool
 JSCodeGenerator::addGlobalUse(JSAtom *atom, uint32 slot, UpvarCookie *cookie)
 {
@@ -2565,32 +2565,31 @@ CheckSideEffects(JSContext *cx, JSCodeGe
 {
     JSBool ok;
     JSParseNode *pn2;
 
     ok = JS_TRUE;
     if (!pn || *answer)
         return ok;
 
-    switch (pn->pn_arity) {
+    switch (pn->getArity()) {
       case PN_FUNC:
         /*
          * A named function, contrary to ES3, is no longer useful, because we
          * bind its name lexically (using JSOP_CALLEE) instead of creating an
          * Object instance and binding a readonly, permanent property in it
          * (the object and binding can be detected and hijacked or captured).
          * This is a bug fix to ES3; it is fixed in ES3.1 drafts.
          */
         *answer = JS_FALSE;
         break;
 
       case PN_LIST:
-        if (pn->pn_op == JSOP_NOP ||
-            pn->pn_op == JSOP_OR || pn->pn_op == JSOP_AND ||
-            pn->pn_op == JSOP_STRICTEQ || pn->pn_op == JSOP_STRICTNE) {
+        if (pn->isOp(JSOP_NOP) || pn->isOp(JSOP_OR) || pn->isOp(JSOP_AND) ||
+            pn->isOp(JSOP_STRICTEQ) || pn->isOp(JSOP_STRICTNE)) {
             /*
              * Non-operators along with ||, &&, ===, and !== never invoke
              * toString or valueOf.
              */
             for (pn2 = pn->pn_head; pn2; pn2 = pn2->pn_next)
                 ok &= CheckSideEffects(cx, cg, pn2, answer);
         } else {
             /*
@@ -2615,40 +2614,40 @@ CheckSideEffects(JSContext *cx, JSCodeGe
 
       case PN_TERNARY:
         ok = CheckSideEffects(cx, cg, pn->pn_kid1, answer) &&
              CheckSideEffects(cx, cg, pn->pn_kid2, answer) &&
              CheckSideEffects(cx, cg, pn->pn_kid3, answer);
         break;
 
       case PN_BINARY:
-        if (pn->pn_type == TOK_ASSIGN) {
+        if (pn->isKind(TOK_ASSIGN)) {
             /*
              * Assignment is presumed to be useful, even if the next operation
              * is another assignment overwriting this one's ostensible effect,
              * because the left operand may be a property with a setter that
              * has side effects.
              *
              * The only exception is assignment of a useless value to a const
              * declared in the function currently being compiled.
              */
             pn2 = pn->pn_left;
-            if (pn2->pn_type != TOK_NAME) {
+            if (!pn2->isKind(TOK_NAME)) {
                 *answer = JS_TRUE;
             } else {
                 if (!BindNameToSlot(cx, cg, pn2))
                     return JS_FALSE;
                 if (!CheckSideEffects(cx, cg, pn->pn_right, answer))
                     return JS_FALSE;
-                if (!*answer && (pn->pn_op != JSOP_NOP || !pn2->isConst()))
+                if (!*answer && (!pn->isOp(JSOP_NOP) || !pn2->isConst()))
                     *answer = JS_TRUE;
             }
         } else {
-            if (pn->pn_op == JSOP_OR || pn->pn_op == JSOP_AND ||
-                pn->pn_op == JSOP_STRICTEQ || pn->pn_op == JSOP_STRICTNE) {
+            if (pn->isOp(JSOP_OR) || pn->isOp(JSOP_AND) || pn->isOp(JSOP_STRICTEQ) ||
+                pn->isOp(JSOP_STRICTNE)) {
                 /*
                  * ||, &&, ===, and !== do not convert their operands via
                  * toString or valueOf method calls.
                  */
                 ok = CheckSideEffects(cx, cg, pn->pn_left, answer) &&
                      CheckSideEffects(cx, cg, pn->pn_right, answer);
             } else {
                 /*
@@ -2656,20 +2655,20 @@ CheckSideEffects(JSContext *cx, JSCodeGe
                  * object with a toString or valueOf method.
                  */
                 *answer = JS_TRUE;
             }
         }
         break;
 
       case PN_UNARY:
-        switch (pn->pn_type) {
+        switch (pn->getKind()) {
           case TOK_DELETE:
             pn2 = pn->pn_kid;
-            switch (pn2->pn_type) {
+            switch (pn2->getKind()) {
               case TOK_NAME:
                 if (!BindNameToSlot(cx, cg, pn2))
                     return JS_FALSE;
                 if (pn2->isConst()) {
                     *answer = JS_FALSE;
                     break;
                 }
                 /* FALL THROUGH */
@@ -2684,17 +2683,17 @@ CheckSideEffects(JSContext *cx, JSCodeGe
                 break;
               default:
                 ok = CheckSideEffects(cx, cg, pn2, answer);
                 break;
             }
             break;
 
           case TOK_UNARYOP:
-            if (pn->pn_op == JSOP_NOT) {
+            if (pn->isOp(JSOP_NOT)) {
                 /* ! does not convert its operand via toString or valueOf. */
                 ok = CheckSideEffects(cx, cg, pn->pn_kid, answer);
                 break;
             }
             /* FALL THROUGH */
 
           default:
             /*
@@ -2709,66 +2708,66 @@ CheckSideEffects(JSContext *cx, JSCodeGe
         break;
 
       case PN_NAME:
         /*
          * Take care to avoid trying to bind a label name (labels, both for
          * statements and property values in object initialisers, have pn_op
          * defaulted to JSOP_NOP).
          */
-        if (pn->pn_type == TOK_NAME && pn->pn_op != JSOP_NOP) {
+        if (pn->isKind(TOK_NAME) && !pn->isOp(JSOP_NOP)) {
             if (!BindNameToSlot(cx, cg, pn))
                 return JS_FALSE;
-            if (pn->pn_op != JSOP_ARGUMENTS && pn->pn_op != JSOP_CALLEE &&
+            if (!pn->isOp(JSOP_ARGUMENTS) && !pn->isOp(JSOP_CALLEE) &&
                 pn->pn_cookie.isFree()) {
                 /*
                  * Not an argument or local variable use, and not a use of a
                  * unshadowed named function expression's given name, so this
                  * expression could invoke a getter that has side effects.
                  */
                 *answer = JS_TRUE;
             }
         }
         pn2 = pn->maybeExpr();
-        if (pn->pn_type == TOK_DOT) {
-            if (pn2->pn_type == TOK_NAME && !BindNameToSlot(cx, cg, pn2))
-                return JS_FALSE;
-            if (!(pn2->pn_op == JSOP_ARGUMENTS &&
+        if (pn->isKind(TOK_DOT)) {
+            if (pn2->isKind(TOK_NAME) && !BindNameToSlot(cx, cg, pn2))
+                return JS_FALSE;
+            if (!(pn2->isOp(JSOP_ARGUMENTS) &&
                   pn->pn_atom == cx->runtime->atomState.lengthAtom)) {
                 /*
                  * Any dotted property reference could call a getter, except
                  * for arguments.length where arguments is unambiguous.
                  */
                 *answer = JS_TRUE;
             }
         }
         ok = CheckSideEffects(cx, cg, pn2, answer);
         break;
 
       case PN_NAMESET:
         ok = CheckSideEffects(cx, cg, pn->pn_tree, answer);
         break;
 
       case PN_NULLARY:
-        if (pn->pn_type == TOK_DEBUGGER)
+        if (pn->isKind(TOK_DEBUGGER))
             *answer = JS_TRUE;
         break;
     }
     return ok;
 }
 
 static JSBool
 EmitNameOp(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn,
            JSBool callContext)
 {
     JSOp op;
 
     if (!BindNameToSlot(cx, cg, pn))
         return JS_FALSE;
-    op = PN_OP(pn);
+    op = pn->getOp();
 
     if (callContext) {
         switch (op) {
           case JSOP_NAME:
             op = JSOP_CALLNAME;
             break;
           case JSOP_GETGNAME:
             op = JSOP_CALLGNAME;
@@ -2810,18 +2809,18 @@ EmitNameOp(JSContext *cx, JSCodeGenerato
 
 #if JS_HAS_XML_SUPPORT
 static JSBool
 EmitXMLName(JSContext *cx, JSParseNode *pn, JSOp op, JSCodeGenerator *cg)
 {
     JSParseNode *pn2;
     uintN oldflags;
 
-    JS_ASSERT(pn->pn_type == TOK_UNARYOP);
-    JS_ASSERT(pn->pn_op == JSOP_XMLNAME);
+    JS_ASSERT(pn->isKind(TOK_UNARYOP));
+    JS_ASSERT(pn->isOp(JSOP_XMLNAME));
     JS_ASSERT(op == JSOP_XMLNAME || op == JSOP_CALLXMLNAME);
 
     pn2 = pn->pn_kid;
     oldflags = cg->flags;
     cg->flags &= ~TCF_IN_FOR_INIT;
     if (!js_EmitTree(cx, cg, pn2))
         return JS_FALSE;
     cg->flags |= oldflags & TCF_IN_FOR_INIT;
@@ -2861,63 +2860,63 @@ EmitSpecialPropOp(JSContext *cx, JSParse
 
 static JSBool
 EmitPropOp(JSContext *cx, JSParseNode *pn, JSOp op, JSCodeGenerator *cg,
            JSBool callContext, JSOp *psuffix = NULL)
 {
     JSParseNode *pn2, *pndot, *pnup, *pndown;
     ptrdiff_t top;
 
-    JS_ASSERT(pn->pn_arity == PN_NAME);
+    JS_ASSERT(pn->isArity(PN_NAME));
     pn2 = pn->maybeExpr();
 
     /* Special case deoptimization for __proto__. */
     if ((op == JSOP_GETPROP || op == JSOP_CALLPROP) &&
         pn->pn_atom == cx->runtime->atomState.protoAtom) {
         if (pn2 && !js_EmitTree(cx, cg, pn2))
             return JS_FALSE;
         return EmitSpecialPropOp(cx, pn, callContext ? JSOP_CALLELEM : JSOP_GETELEM, cg);
     }
 
     if (callContext) {
-        JS_ASSERT(pn->pn_type == TOK_DOT);
+        JS_ASSERT(pn->isKind(TOK_DOT));
         JS_ASSERT(op == JSOP_GETPROP);
         op = JSOP_CALLPROP;
-    } else if (op == JSOP_GETPROP && pn->pn_type == TOK_DOT) {
-        if (pn2->pn_type == TOK_NAME) {
+    } else if (op == JSOP_GETPROP && pn->isKind(TOK_DOT)) {
+        if (pn2->isKind(TOK_NAME)) {
             /*
              * Try to optimize arguments.length into JSOP_ARGCNT. If type
              * inference is enabled this is optimized separately.
              */
             if (!BindNameToSlot(cx, cg, pn2))
                 return JS_FALSE;
             if (!cx->typeInferenceEnabled() &&
                 pn->pn_atom == cx->runtime->atomState.lengthAtom) {
-                if (pn2->pn_op == JSOP_ARGUMENTS)
+                if (pn2->isOp(JSOP_ARGUMENTS))
                     return js_Emit1(cx, cg, JSOP_ARGCNT) >= 0;
             }
         }
     }
 
     /*
      * If the object operand is also a dotted property reference, reverse the
      * list linked via pn_expr temporarily so we can iterate over it from the
      * bottom up (reversing again as we go), to avoid excessive recursion.
      */
-    if (pn2->pn_type == TOK_DOT) {
+    if (pn2->isKind(TOK_DOT)) {
         pndot = pn2;
         pnup = NULL;
         top = CG_OFFSET(cg);
         for (;;) {
             /* Reverse pndot->pn_expr to point up, not down. */
             pndot->pn_offset = top;
-            JS_ASSERT(!pndot->pn_used);
+            JS_ASSERT(!pndot->isUsed());
             pndown = pndot->pn_expr;
             pndot->pn_expr = pnup;
-            if (pndown->pn_type != TOK_DOT)
+            if (!pndown->isKind(TOK_DOT))
                 break;
             pnup = pndot;
             pndot = pndown;
         }
 
         /* pndown is a primary expression, not a dotted property reference. */
         if (!js_EmitTree(cx, cg, pndown))
             return JS_FALSE;
@@ -2925,20 +2924,20 @@ EmitPropOp(JSContext *cx, JSParseNode *p
         do {
             /* Walk back up the list, emitting annotated name ops. */
             if (js_NewSrcNote2(cx, cg, SRC_PCBASE,
                                CG_OFFSET(cg) - pndown->pn_offset) < 0) {
                 return JS_FALSE;
             }
 
             /* Special case deoptimization on __proto__, as above. */
-            if (pndot->pn_arity == PN_NAME && pndot->pn_atom == cx->runtime->atomState.protoAtom) {
+            if (pndot->isArity(PN_NAME) && pndot->pn_atom == cx->runtime->atomState.protoAtom) {
                 if (!EmitSpecialPropOp(cx, pndot, JSOP_GETELEM, cg))
                     return JS_FALSE;
-            } else if (!EmitAtomOp(cx, pndot, PN_OP(pndot), cg)) {
+            } else if (!EmitAtomOp(cx, pndot, pndot->getOp(), cg)) {
                 return JS_FALSE;
             }
 
             /* Reverse the pn_expr link again. */
             pnup = pndot->pn_expr;
             pndot->pn_expr = pndown;
             pndown = pndot;
         } while ((pndot = pnup) != NULL);
@@ -3075,34 +3074,34 @@ EmitNameIncDec(JSContext *cx, JSParseNod
 static JSBool
 EmitElemOp(JSContext *cx, JSParseNode *pn, JSOp op, JSCodeGenerator *cg)
 {
     ptrdiff_t top;
     JSParseNode *left, *right, *next, ltmp, rtmp;
     int32_t slot;
 
     top = CG_OFFSET(cg);
-    if (pn->pn_arity == PN_LIST) {
+    if (pn->isArity(PN_LIST)) {
         /* Left-associative operator chain to avoid too much recursion. */
-        JS_ASSERT(pn->pn_op == JSOP_GETELEM);
+        JS_ASSERT(pn->isOp(JSOP_GETELEM));
         JS_ASSERT(pn->pn_count >= 3);
         left = pn->pn_head;
         right = pn->last();
         next = left->pn_next;
         JS_ASSERT(next != right);
 
         /*
          * Try to optimize arguments[0][j]... into JSOP_ARGSUB<0> followed by
          * one or more index expression and JSOP_GETELEM op pairs. If type
          * inference is enabled this is optimized separately.
          */
-        if (left->pn_type == TOK_NAME && next->pn_type == TOK_NUMBER) {
+        if (left->isKind(TOK_NAME) && next->isKind(TOK_NUMBER)) {
             if (!BindNameToSlot(cx, cg, left))
                 return JS_FALSE;
-            if (left->pn_op == JSOP_ARGUMENTS &&
+            if (left->isOp(JSOP_ARGUMENTS) &&
                 JSDOUBLE_IS_INT32(next->pn_dval, &slot) &&
                 jsuint(slot) < JS_BIT(16) &&
                 !cx->typeInferenceEnabled() &&
                 (!cg->inStrictMode() ||
                  (!cg->mutatesParameter() && !cg->callsEval()))) {
                 /*
                  * arguments[i]() requires arguments object as "this".
                  * Check that we never generates list for that usage.
@@ -3132,75 +3131,73 @@ EmitElemOp(JSContext *cx, JSParseNode *p
                 return JS_FALSE;
             if (js_NewSrcNote2(cx, cg, SRC_PCBASE, CG_OFFSET(cg) - top) < 0)
                 return JS_FALSE;
             if (!EmitElemOpBase(cx, cg, JSOP_GETELEM))
                 return JS_FALSE;
             next = next->pn_next;
         }
     } else {
-        if (pn->pn_arity == PN_NAME) {
+        if (pn->isArity(PN_NAME)) {
             /*
              * Set left and right so pn appears to be a TOK_LB node, instead
              * of a TOK_DOT node.  See the TOK_FOR/IN case in js_EmitTree, and
              * EmitDestructuringOps nearer below.  In the destructuring case,
              * the base expression (pn_expr) of the name may be null, which
              * means we have to emit a JSOP_BINDNAME.
              */
             left = pn->maybeExpr();
             if (!left) {
                 left = &ltmp;
-                left->pn_type = TOK_STRING;
-                left->pn_op = JSOP_BINDNAME;
-                left->pn_arity = PN_NULLARY;
+                left->setKind(TOK_STRING);
+                left->setOp(JSOP_BINDNAME);
+                left->setArity(PN_NULLARY);
                 left->pn_pos = pn->pn_pos;
                 left->pn_atom = pn->pn_atom;
             }
             right = &rtmp;
-            right->pn_type = TOK_STRING;
-            right->pn_op = js_IsIdentifier(pn->pn_atom)
-                           ? JSOP_QNAMEPART
-                           : JSOP_STRING;
-            right->pn_arity = PN_NULLARY;
+            right->setKind(TOK_STRING);
+            right->setOp(js_IsIdentifier(pn->pn_atom) ? JSOP_QNAMEPART : JSOP_STRING);
+            right->setArity(PN_NULLARY);
             right->pn_pos = pn->pn_pos;
             right->pn_atom = pn->pn_atom;
         } else {
-            JS_ASSERT(pn->pn_arity == PN_BINARY);
+            JS_ASSERT(pn->isArity(PN_BINARY));
             left = pn->pn_left;
             right = pn->pn_right;
         }
 
         /*
          * Try to optimize arguments[0] (e.g.) into JSOP_ARGSUB<0>. If type
          * inference is enabled this is optimized separately.
          */
         if (op == JSOP_GETELEM &&
-            left->pn_type == TOK_NAME &&
-            right->pn_type == TOK_NUMBER) {
+            left->isKind(TOK_NAME) &&
+            right->isKind(TOK_NUMBER)) {
             if (!BindNameToSlot(cx, cg, left))
                 return JS_FALSE;
-            if (left->pn_op == JSOP_ARGUMENTS &&
+            if (left->isOp(JSOP_ARGUMENTS) &&
                 JSDOUBLE_IS_INT32(right->pn_dval, &slot) &&
                 jsuint(slot) < JS_BIT(16) &&
                 !cx->typeInferenceEnabled() &&
                 (!cg->inStrictMode() ||
                  (!cg->mutatesParameter() && !cg->callsEval()))) {
                 left->pn_offset = right->pn_offset = top;
                 EMIT_UINT16_IMM_OP(JSOP_ARGSUB, (jsatomid)slot);
                 return JS_TRUE;
             }
         }
 
         if (!js_EmitTree(cx, cg, left))
             return JS_FALSE;
     }
 
     /* The right side of the descendant operator is implicitly quoted. */
-    JS_ASSERT(op != JSOP_DESCENDANTS || right->pn_type != TOK_STRING ||
-              right->pn_op == JSOP_QNAMEPART);
+    JS_ASSERT(op != JSOP_DESCENDANTS || !right->isKind(TOK_STRING) ||
+              right->isOp(JSOP_QNAMEPART));
     if (!js_EmitTree(cx, cg, right))
         return JS_FALSE;
     if (js_NewSrcNote2(cx, cg, SRC_PCBASE, CG_OFFSET(cg) - top) < 0)
         return JS_FALSE;
     return EmitElemOpBase(cx, cg, op);
 }
 
 static bool
@@ -3402,17 +3399,17 @@ EmitSwitch(JSContext *cx, JSCodeGenerato
      * If the switch contains let variables scoped by its body, model the
      * resulting block on the stack first, before emitting the discriminant's
      * bytecode (in case the discriminant contains a stack-model dependency
      * such as a let expression).
      */
     pn2 = pn->pn_right;
 #if JS_HAS_BLOCK_SCOPE
     TempPopScope tps;
-    if (pn2->pn_type == TOK_LEXICALSCOPE) {
+    if (pn2->isKind(TOK_LEXICALSCOPE)) {
         /*
          * Push the body's block scope before discriminant code-gen to reflect
          * the order of slots on the stack. The block's locals must lie under
          * the discriminant on the stack so that case-dispatch bytecodes can
          * find the discriminant on top of stack.
          */
         box = pn2->pn_objbox;
         js_PushBlockScope(cg, stmtInfo, box, -1);
@@ -3443,17 +3440,17 @@ EmitSwitch(JSContext *cx, JSCodeGenerato
     if (!js_EmitTree(cx, cg, pn->pn_left))
         return JS_FALSE;
 
     /* Switch bytecodes run from here till end of final case. */
     top = CG_OFFSET(cg);
 #if !JS_HAS_BLOCK_SCOPE
     js_PushStatement(cg, stmtInfo, STMT_SWITCH, top);
 #else
-    if (pn2->pn_type == TOK_LC) {
+    if (pn2->isKind(TOK_LC)) {
         js_PushStatement(cg, stmtInfo, STMT_SWITCH, top);
     } else {
         /* Re-push the switch's statement info record. */
         if (!tps.repushBlock(cx, cg))
             return JS_FALSE;
 
         /*
          * Set the statement info record's idea of top. Reset top too, since
@@ -3467,46 +3464,46 @@ EmitSwitch(JSContext *cx, JSCodeGenerato
 #endif
 
     caseCount = pn2->pn_count;
     tableLength = 0;
     table = NULL;
 
     if (caseCount == 0 ||
         (caseCount == 1 &&
-         (hasDefault = (pn2->pn_head->pn_type == TOK_DEFAULT)))) {
+         (hasDefault = (pn2->pn_head->isKind(TOK_DEFAULT))))) {
         caseCount = 0;
         low = 0;
         high = -1;
     } else {
 #define INTMAP_LENGTH   256
         jsbitmap intmap_space[INTMAP_LENGTH];
         jsbitmap *intmap = NULL;
         int32 intmap_bitlen = 0;
 
         low  = JSVAL_INT_MAX;
         high = JSVAL_INT_MIN;
 
         for (pn3 = pn2->pn_head; pn3; pn3 = pn3->pn_next) {
-            if (pn3->pn_type == TOK_DEFAULT) {
+            if (pn3->isKind(TOK_DEFAULT)) {
                 hasDefault = JS_TRUE;
                 caseCount--;    /* one of the "cases" was the default */
                 continue;
             }
 
-            JS_ASSERT(pn3->pn_type == TOK_CASE);
+            JS_ASSERT(pn3->isKind(TOK_CASE));
             if (switchOp == JSOP_CONDSWITCH)
                 continue;
 
             pn4 = pn3->pn_left;
-            while (pn4->pn_type == TOK_RP)
+            while (pn4->isKind(TOK_RP))
                 pn4 = pn4->pn_kid;
 
             Value constVal;
-            switch (pn4->pn_type) {
+            switch (pn4->getKind()) {
               case TOK_NUMBER:
                 constVal.setNumber(pn4->pn_dval);
                 break;
               case TOK_STRING:
                 constVal.setString(pn4->pn_atom);
                 break;
               case TOK_NAME:
                 if (!pn4->maybeExpr()) {
@@ -3523,25 +3520,25 @@ EmitSwitch(JSContext *cx, JSCodeGenerato
                             continue;
                         }
                         constPropagated = JS_TRUE;
                         break;
                     }
                 }
                 /* FALL THROUGH */
               case TOK_PRIMARY:
-                if (pn4->pn_op == JSOP_TRUE) {
+                if (pn4->isOp(JSOP_TRUE)) {
                     constVal.setBoolean(true);
                     break;
                 }
-                if (pn4->pn_op == JSOP_FALSE) {
+                if (pn4->isOp(JSOP_FALSE)) {
                     constVal.setBoolean(false);
                     break;
                 }
-                if (pn4->pn_op == JSOP_NULL) {
+                if (pn4->isOp(JSOP_NULL)) {
                     constVal.setNull();
                     break;
                 }
                 /* FALL THROUGH */
               default:
                 switchOp = JSOP_CONDSWITCH;
                 continue;
             }
@@ -3684,17 +3681,17 @@ EmitSwitch(JSContext *cx, JSCodeGenerato
             if (caseNoteIndex >= 0) {
                 /* off is the previous JSOP_CASE's bytecode offset. */
                 if (!js_SetSrcNoteOffset(cx, cg, (uintN)caseNoteIndex, 0,
                                          CG_OFFSET(cg) - off)) {
                     return JS_FALSE;
                 }
             }
             if (!pn4) {
-                JS_ASSERT(pn3->pn_type == TOK_DEFAULT);
+                JS_ASSERT(pn3->isKind(TOK_DEFAULT));
                 continue;
             }
             caseNoteIndex = js_NewSrcNote2(cx, cg, SRC_PCDELTA, 0);
             if (caseNoteIndex < 0)
                 return JS_FALSE;
             off = EmitJump(cx, cg, JSOP_CASE, 0);
             if (off < 0)
                 return JS_FALSE;
@@ -3748,17 +3745,17 @@ EmitSwitch(JSContext *cx, JSCodeGenerato
              */
             if (tableLength != 0) {
                 tableSize = (size_t)tableLength * sizeof *table;
                 table = (JSParseNode **) cx->malloc_(tableSize);
                 if (!table)
                     return JS_FALSE;
                 memset(table, 0, tableSize);
                 for (pn3 = pn2->pn_head; pn3; pn3 = pn3->pn_next) {
-                    if (pn3->pn_type == TOK_DEFAULT)
+                    if (pn3->isKind(TOK_DEFAULT))
                         continue;
                     i = pn3->pn_pval->toInt32();
                     i -= low;
                     JS_ASSERT((uint32)i < tableLength);
                     table[i] = pn3;
                 }
             }
         } else {
@@ -3794,32 +3791,32 @@ EmitSwitch(JSContext *cx, JSCodeGenerato
              */
             savepc = CG_NEXT(cg);
             CG_NEXT(cg) = pc + 1;
             if (switchOp == JSOP_TABLESWITCH) {
                 for (i = 0; i < (jsint)tableLength; i++) {
                     pn3 = table[i];
                     if (pn3 &&
                         (pn4 = pn3->pn_left) != NULL &&
-                        pn4->pn_type == TOK_NAME) {
+                        pn4->isKind(TOK_NAME)) {
                         /* Note a propagated constant with the const's name. */
                         JS_ASSERT(!pn4->maybeExpr());
                         jsatomid index;
                         if (!cg->makeAtomIndex(pn4->pn_atom, &index))
                             goto bad;
                         CG_NEXT(cg) = pc;
                         if (js_NewSrcNote2(cx, cg, SRC_LABEL, ptrdiff_t(index)) < 0)
                             goto bad;
                     }
                     pc += JUMP_OFFSET_LEN;
                 }
             } else {
                 for (pn3 = pn2->pn_head; pn3; pn3 = pn3->pn_next) {
                     pn4 = pn3->pn_left;
-                    if (pn4 && pn4->pn_type == TOK_NAME) {
+                    if (pn4 && pn4->isKind(TOK_NAME)) {
                         /* Note a propagated constant with the const's name. */
                         JS_ASSERT(!pn4->maybeExpr());
                         jsatomid index;
                         if (!cg->makeAtomIndex(pn4->pn_atom, &index))
                             goto bad;
                         CG_NEXT(cg) = pc;
                         if (js_NewSrcNote2(cx, cg, SRC_LABEL, ptrdiff_t(index)) < 0)
                             goto bad;
@@ -3828,24 +3825,24 @@ EmitSwitch(JSContext *cx, JSCodeGenerato
                 }
             }
             CG_NEXT(cg) = savepc;
         }
     }
 
     /* Emit code for each case's statements, copying pn_offset up to pn3. */
     for (pn3 = pn2->pn_head; pn3; pn3 = pn3->pn_next) {
-        if (switchOp == JSOP_CONDSWITCH && pn3->pn_type != TOK_DEFAULT)
+        if (switchOp == JSOP_CONDSWITCH && !pn3->isKind(TOK_DEFAULT))
             CHECK_AND_SET_JUMP_OFFSET_AT_CUSTOM(cx, cg, pn3->pn_offset, goto bad);
         pn4 = pn3->pn_right;
         ok = js_EmitTree(cx, cg, pn4);
         if (!ok)
             goto out;
         pn3->pn_offset = pn4->pn_offset;
-        if (pn3->pn_type == TOK_DEFAULT)
+        if (pn3->isKind(TOK_DEFAULT))
             off = pn3->pn_offset - top;
     }
 
     if (!hasDefault) {
         /* If no default case, offset for default is to end of switch. */
         off = CG_OFFSET(cg) - top;
     }
 
@@ -3887,17 +3884,17 @@ EmitSwitch(JSContext *cx, JSCodeGenerato
                 goto out;
             pc += JUMP_OFFSET_LEN;
         }
     } else if (switchOp == JSOP_LOOKUPSWITCH) {
         /* Skip over the already-initialized number of cases. */
         pc += INDEX_LEN;
 
         for (pn3 = pn2->pn_head; pn3; pn3 = pn3->pn_next) {
-            if (pn3->pn_type == TOK_DEFAULT)
+            if (pn3->isKind(TOK_DEFAULT))
                 continue;
             if (!cg->constList.append(*pn3->pn_pval))
                 goto bad;
             SET_INDEX(pc, cg->constList.length() - 1);
             pc += INDEX_LEN;
 
             off = pn3->pn_offset - top;
             ok = js_SetJumpOffset(cx, cg, pc, off);
@@ -3909,17 +3906,17 @@ EmitSwitch(JSContext *cx, JSCodeGenerato
 
 out:
     if (table)
         cx->free_(table);
     if (ok) {
         ok = js_PopStatementCG(cx, cg);
 
 #if JS_HAS_BLOCK_SCOPE
-        if (ok && pn->pn_right->pn_type == TOK_LEXICALSCOPE)
+        if (ok && pn->pn_right->isKind(TOK_LEXICALSCOPE))
             ok = EmitLeaveBlock(cx, cg, JSOP_LEAVEBLOCK, box);
 #endif
     }
     return ok;
 
 bad:
     ok = JS_FALSE;
     goto out;
@@ -3978,29 +3975,29 @@ MaybeEmitVarDecl(JSContext *cx, JSCodeGe
 
     if (!pn->pn_cookie.isFree()) {
         atomIndex = pn->pn_cookie.slot();
     } else {
         if (!cg->makeAtomIndex(pn->pn_atom, &atomIndex))
             return false;
     }
 
-    if (JOF_OPTYPE(pn->pn_op) == JOF_ATOM &&
+    if (JOF_OPTYPE(pn->getOp()) == JOF_ATOM &&
         (!cg->inFunction() || (cg->flags & TCF_FUN_HEAVYWEIGHT)) &&
         !(pn->pn_dflags & PND_GVAR))
     {
         CG_SWITCH_TO_PROLOG(cg);
         if (!UpdateLineNumberNotes(cx, cg, pn->pn_pos.begin.lineno))
             return false;
         EMIT_INDEX_OP(prologOp, atomIndex);
         CG_SWITCH_TO_MAIN(cg);
     }
 
     if (cg->inFunction() &&
-        JOF_OPTYPE(pn->pn_op) == JOF_LOCAL &&
+        JOF_OPTYPE(pn->getOp()) == JOF_LOCAL &&
         pn->pn_cookie.slot() < cg->bindings.countVars() &&
         cg->shouldNoteClosedName(pn))
     {
         if (!cg->closedVars.append(pn->pn_cookie.slot()))
             return false;
     }
 
     if (result)
@@ -4013,48 +4010,46 @@ MaybeEmitVarDecl(JSContext *cx, JSCodeGe
 typedef JSBool
 (*DestructuringDeclEmitter)(JSContext *cx, JSCodeGenerator *cg, JSOp prologOp,
                             JSParseNode *pn);
 
 static JSBool
 EmitDestructuringDecl(JSContext *cx, JSCodeGenerator *cg, JSOp prologOp,
                       JSParseNode *pn)
 {
-    JS_ASSERT(pn->pn_type == TOK_NAME);
+    JS_ASSERT(pn->isKind(TOK_NAME));
     if (!BindNameToSlot(cx, cg, pn))
         return JS_FALSE;
 
-    JS_ASSERT(PN_OP(pn) != JSOP_ARGUMENTS && PN_OP(pn) != JSOP_CALLEE);
+    JS_ASSERT(!pn->isOp(JSOP_ARGUMENTS) && !pn->isOp(JSOP_CALLEE));
     return MaybeEmitVarDecl(cx, cg, prologOp, pn, NULL);
 }
 
 static JSBool
 EmitDestructuringDecls(JSContext *cx, JSCodeGenerator *cg, JSOp prologOp,
                        JSParseNode *pn)
 {
     JSParseNode *pn2, *pn3;
     DestructuringDeclEmitter emitter;
 
-    if (pn->pn_type == TOK_RB) {
+    if (pn->isKind(TOK_RB)) {
         for (pn2 = pn->pn_head; pn2; pn2 = pn2->pn_next) {
-            if (pn2->pn_type == TOK_COMMA)
+            if (pn2->isKind(TOK_COMMA))
                 continue;
-            emitter = (pn2->pn_type == TOK_NAME)
+            emitter = (pn2->isKind(TOK_NAME))
                       ? EmitDestructuringDecl
                       : EmitDestructuringDecls;
             if (!emitter(cx, cg, prologOp, pn2))
                 return JS_FALSE;
         }
     } else {
-        JS_ASSERT(pn->pn_type == TOK_RC);
+        JS_ASSERT(pn->isKind(TOK_RC));
         for (pn2 = pn->pn_head; pn2; pn2 = pn2->pn_next) {
             pn3 = pn2->pn_right;
-            emitter = (pn3->pn_type == TOK_NAME)
-                      ? EmitDestructuringDecl
-                      : EmitDestructuringDecls;
+            emitter = pn3->isKind(TOK_NAME) ? EmitDestructuringDecl : EmitDestructuringDecls;
             if (!emitter(cx, cg, prologOp, pn3))
                 return JS_FALSE;
         }
     }
     return JS_TRUE;
 }
 
 static JSBool
@@ -4064,30 +4059,30 @@ static JSBool
 EmitDestructuringLHS(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
 {
     /*
      * Now emit the lvalue opcode sequence.  If the lvalue is a nested
      * destructuring initialiser-form, call ourselves to handle it, then
      * pop the matched value.  Otherwise emit an lvalue bytecode sequence
      * ending with a JSOP_ENUMELEM or equivalent op.
      */
-    if (pn->pn_type == TOK_RB || pn->pn_type == TOK_RC) {
+    if (pn->isKind(TOK_RB) || pn->isKind(TOK_RC)) {
         if (!EmitDestructuringOpsHelper(cx, cg, pn))
             return JS_FALSE;
         if (js_Emit1(cx, cg, JSOP_POP) < 0)
             return JS_FALSE;
     } else {
-        if (pn->pn_type == TOK_NAME) {
+        if (pn->isKind(TOK_NAME)) {
             if (!BindNameToSlot(cx, cg, pn))
                 return JS_FALSE;
             if (pn->isConst() && !pn->isInitialized())
                 return js_Emit1(cx, cg, JSOP_POP) >= 0;
         }
 
-        switch (pn->pn_op) {
+        switch (pn->getOp()) {
           case JSOP_SETNAME:
           case JSOP_SETGNAME:
             /*
              * NB: pn is a PN_NAME node, not a PN_BINARY.  Nevertheless,
              * we want to emit JSOP_ENUMELEM, which has format JOF_ELEM.
              * So here and for JSOP_ENUMCONSTELEM, we use EmitElemOp.
              */
             if (!EmitElemOp(cx, pn, JSOP_ENUMELEM, cg))
@@ -4104,17 +4099,17 @@ EmitDestructuringLHS(JSContext *cx, JSCo
             jsuint slot = pn->pn_cookie.asInteger();
             EMIT_UINT16_IMM_OP(JSOP_SETLOCALPOP, slot);
             break;
           }
 
           case JSOP_SETARG:
           {
             jsuint slot = pn->pn_cookie.asInteger();
-            EMIT_UINT16_IMM_OP(PN_OP(pn), slot);
+            EMIT_UINT16_IMM_OP(pn->getOp(), slot);
             if (js_Emit1(cx, cg, JSOP_POP) < 0)
                 return JS_FALSE;
             break;
           }
 
           default:
           {
             ptrdiff_t top;
@@ -4149,18 +4144,18 @@ EmitDestructuringOpsHelper(JSContext *cx
 {
     jsuint index;
     JSParseNode *pn2, *pn3;
     JSBool doElemOp;
 
 #ifdef DEBUG
     intN stackDepth = cg->stackDepth;
     JS_ASSERT(stackDepth != 0);
-    JS_ASSERT(pn->pn_arity == PN_LIST);
-    JS_ASSERT(pn->pn_type == TOK_RB || pn->pn_type == TOK_RC);
+    JS_ASSERT(pn->isArity(PN_LIST));
+    JS_ASSERT(pn->isKind(TOK_RB) || pn->isKind(TOK_RC));
 #endif
 
     if (pn->pn_count == 0) {
         /* Emit a DUP;POP sequence for the decompiler. */
         return js_Emit1(cx, cg, JSOP_DUP) >= 0 &&
                js_Emit1(cx, cg, JSOP_POP) >= 0;
     }
 
@@ -4177,37 +4172,36 @@ EmitDestructuringOpsHelper(JSContext *cx
 
         /*
          * Now push the property name currently being matched, which is either
          * the array initialiser's current index, or the current property name
          * "label" on the left of a colon in the object initialiser.  Set pn3
          * to the lvalue node, which is in the value-initializing position.
          */
         doElemOp = JS_TRUE;
-        if (pn->pn_type == TOK_RB) {
+        if (pn->isKind(TOK_RB)) {
             if (!EmitNumberOp(cx, index, cg))
                 return JS_FALSE;
             pn3 = pn2;
         } else {
-            JS_ASSERT(pn->pn_type == TOK_RC);
-            JS_ASSERT(pn2->pn_type == TOK_COLON);
+            JS_ASSERT(pn->isKind(TOK_RC));
+            JS_ASSERT(pn2->isKind(TOK_COLON));
             pn3 = pn2->pn_left;
-            if (pn3->pn_type == TOK_NUMBER) {
+            if (pn3->isKind(TOK_NUMBER)) {
                 /*
                  * If we are emitting an object destructuring initialiser,
                  * annotate the index op with SRC_INITPROP so we know we are
                  * not decompiling an array initialiser.
                  */
                 if (js_NewSrcNote(cx, cg, SRC_INITPROP) < 0)
                     return JS_FALSE;
                 if (!EmitNumberOp(cx, pn3->pn_dval, cg))
                     return JS_FALSE;
             } else {
-                JS_ASSERT(pn3->pn_type == TOK_STRING ||
-                          pn3->pn_type == TOK_NAME);
+                JS_ASSERT(pn3->isKind(TOK_STRING) || pn3->isKind(TOK_NAME));
                 if (!EmitAtomOp(cx, pn3, JSOP_GETPROP, cg))
                     return JS_FALSE;
                 doElemOp = JS_FALSE;
             }
             pn3 = pn2->pn_right;
         }
 
         if (doElemOp) {
@@ -4217,18 +4211,18 @@ EmitDestructuringOpsHelper(JSContext *cx
              * is one deeper than when we started.
              */
             if (!EmitElemOpBase(cx, cg, JSOP_GETELEM))
                 return JS_FALSE;
             JS_ASSERT(cg->stackDepth == stackDepth + 1);
         }
 
         /* Nullary comma node makes a hole in the array destructurer. */
-        if (pn3->pn_type == TOK_COMMA && pn3->pn_arity == PN_NULLARY) {
-            JS_ASSERT(pn->pn_type == TOK_RB);
+        if (pn3->isKind(TOK_COMMA) && pn3->isArity(PN_NULLARY)) {
+            JS_ASSERT(pn->isKind(TOK_RB));
             JS_ASSERT(pn2 == pn3);
             if (js_Emit1(cx, cg, JSOP_POP) < 0)
                 return JS_FALSE;
         } else {
             if (!EmitDestructuringLHS(cx, cg, pn3))
                 return JS_FALSE;
         }
 
@@ -4284,17 +4278,17 @@ EmitGroupAssignment(JSContext *cx, JSCod
     depth = limit = (uintN) cg->stackDepth;
     for (pn = rhs->pn_head; pn; pn = pn->pn_next) {
         if (limit == JS_BIT(16)) {
             ReportCompileErrorNumber(cx, CG_TS(cg), rhs, JSREPORT_ERROR, JSMSG_ARRAY_INIT_TOO_BIG);
             return JS_FALSE;
         }
 
         /* MaybeEmitGroupAssignment won't call us if rhs is holey. */
-        JS_ASSERT(!(pn->pn_type == TOK_COMMA && pn->pn_arity == PN_NULLARY));
+        JS_ASSERT(!(pn->isKind(TOK_COMMA) && pn->isArity(PN_NULLARY)));
         if (!js_EmitTree(cx, cg, pn))
             return JS_FALSE;
         ++limit;
     }
 
     if (js_NewSrcNote2(cx, cg, SRC_GROUPASSIGN, OpToDeclType(prologOp)) < 0)
         return JS_FALSE;
 
@@ -4302,17 +4296,17 @@ EmitGroupAssignment(JSContext *cx, JSCod
     for (pn = lhs->pn_head; pn; pn = pn->pn_next, ++i) {
         /* MaybeEmitGroupAssignment requires lhs->pn_count <= rhs->pn_count. */
         JS_ASSERT(i < limit);
         jsint slot = AdjustBlockSlot(cx, cg, i);
         if (slot < 0)
             return JS_FALSE;
         EMIT_UINT16_IMM_OP(JSOP_GETLOCAL, slot);
 
-        if (pn->pn_type == TOK_COMMA && pn->pn_arity == PN_NULLARY) {
+        if (pn->isKind(TOK_COMMA) && pn->isArity(PN_NULLARY)) {
             if (js_Emit1(cx, cg, JSOP_POP) < 0)
                 return JS_FALSE;
         } else {
             if (!EmitDestructuringLHS(cx, cg, pn))
                 return JS_FALSE;
         }
     }
 
@@ -4328,21 +4322,21 @@ EmitGroupAssignment(JSContext *cx, JSCod
  * we set *pop to JSOP_NOP so callers can veto emitting pn followed by a pop.
  */
 static JSBool
 MaybeEmitGroupAssignment(JSContext *cx, JSCodeGenerator *cg, JSOp prologOp,
                          JSParseNode *pn, JSOp *pop)
 {
     JSParseNode *lhs, *rhs;
 
-    JS_ASSERT(pn->pn_type == TOK_ASSIGN);
+    JS_ASSERT(pn->isKind(TOK_ASSIGN));
     JS_ASSERT(*pop == JSOP_POP || *pop == JSOP_POPV);
     lhs = pn->pn_left;
     rhs = pn->pn_right;
-    if (lhs->pn_type == TOK_RB && rhs->pn_type == TOK_RB &&
+    if (lhs->isKind(TOK_RB) && rhs->isKind(TOK_RB) &&
         !(rhs->pn_xflags & PNX_HOLEY) &&
         lhs->pn_count <= rhs->pn_count) {
         if (!EmitGroupAssignment(cx, cg, prologOp, lhs, rhs))
             return JS_FALSE;
         *pop = JSOP_NOP;
     }
     return JS_TRUE;
 }
@@ -4370,61 +4364,61 @@ EmitVariables(JSContext *cx, JSCodeGener
      * block from any calls to BindNameToSlot hiding in pn2->pn_expr so that
      * it won't find any names in the new let block.
      *
      * The same goes for let declarations in the head of any kind of for loop.
      * Unlike a let declaration 'let x = i' within a block, where x is hoisted
      * to the start of the block, a 'for (let x = i...) ...' loop evaluates i
      * in the containing scope, and puts x in the loop body's scope.
      */
-    DebugOnly<bool> let = (pn->pn_op == JSOP_NOP);
+    DebugOnly<bool> let = (pn->isOp(JSOP_NOP));
     forInVar = (pn->pn_xflags & PNX_FORINVAR) != 0;
 
     off = noteIndex = -1;
     for (pn2 = pn->pn_head; ; pn2 = next) {
         first = pn2 == pn->pn_head;
         next = pn2->pn_next;
 
-        if (pn2->pn_type != TOK_NAME) {
+        if (!pn2->isKind(TOK_NAME)) {
 #if JS_HAS_DESTRUCTURING
-            if (pn2->pn_type == TOK_RB || pn2->pn_type == TOK_RC) {
+            if (pn2->isKind(TOK_RB) || pn2->isKind(TOK_RC)) {
                 /*
                  * Emit variable binding ops, but not destructuring ops.
                  * The parser (see Variables, jsparse.c) has ensured that
                  * our caller will be the TOK_FOR/TOK_IN case in js_EmitTree,
                  * and that case will emit the destructuring code only after
                  * emitting an enumerating opcode and a branch that tests
                  * whether the enumeration ended.
                  */
                 JS_ASSERT(forInVar);
                 JS_ASSERT(pn->pn_count == 1);
-                if (!EmitDestructuringDecls(cx, cg, PN_OP(pn), pn2))
+                if (!EmitDestructuringDecls(cx, cg, pn->getOp(), pn2))
                     return JS_FALSE;
                 break;
             }
 #endif
 
             /*
              * A destructuring initialiser assignment preceded by var will
              * never occur to the left of 'in' in a for-in loop.  As with 'for
              * (var x = i in o)...', this will cause the entire 'var [a, b] =
              * i' to be hoisted out of the loop.
              */
-            JS_ASSERT(pn2->pn_type == TOK_ASSIGN);
+            JS_ASSERT(pn2->isKind(TOK_ASSIGN));
             JS_ASSERT(!forInVar);
 
             /*
              * To allow the front end to rewrite var f = x; as f = x; when a
              * function f(){} precedes the var, detect simple name assignment
              * here and initialize the name.
              */
 #if !JS_HAS_DESTRUCTURING
-            JS_ASSERT(pn2->pn_left->pn_type == TOK_NAME);
+            JS_ASSERT(pn2->pn_left->isKind(TOK_NAME));
 #else
-            if (pn2->pn_left->pn_type == TOK_NAME)
+            if (pn2->pn_left->isKind(TOK_NAME))
 #endif
             {
                 pn3 = pn2->pn_right;
                 pn2 = pn2->pn_left;
                 goto do_name;
             }
 
 #if JS_HAS_DESTRUCTURING
@@ -4433,40 +4427,40 @@ EmitVariables(JSContext *cx, JSCodeGener
                  * If this is the only destructuring assignment in the list,
                  * try to optimize to a group assignment.  If we're in a let
                  * head, pass JSOP_POP rather than the pseudo-prolog JSOP_NOP
                  * in pn->pn_op, to suppress a second (and misplaced) 'let'.
                  */
                 JS_ASSERT(noteIndex < 0 && !pn2->pn_next);
                 op = JSOP_POP;
                 if (!MaybeEmitGroupAssignment(cx, cg,
-                                              inLetHead ? JSOP_POP : PN_OP(pn),
+                                              inLetHead ? JSOP_POP : pn->getOp(),
                                               pn2, &op)) {
                     return JS_FALSE;
                 }
                 if (op == JSOP_NOP) {
                     pn->pn_xflags = (pn->pn_xflags & ~PNX_POPVAR) | PNX_GROUPINIT;
                     break;
                 }
             }
 
             pn3 = pn2->pn_left;
-            if (!EmitDestructuringDecls(cx, cg, PN_OP(pn), pn3))
+            if (!EmitDestructuringDecls(cx, cg, pn->getOp(), pn3))
                 return JS_FALSE;
 
             if (!js_EmitTree(cx, cg, pn2->pn_right))
                 return JS_FALSE;
 
             /*
              * Veto pn->pn_op if inLetHead to avoid emitting a SRC_DESTRUCT
              * that's redundant with respect to the SRC_DECL/SRC_DECL_LET that
              * we will emit at the bottom of this function.
              */
             if (!EmitDestructuringOps(cx, cg,
-                                      inLetHead ? JSOP_POP : PN_OP(pn),
+                                      inLetHead ? JSOP_POP : pn->getOp(),
                                       pn3)) {
                 return JS_FALSE;
             }
             goto emit_note_pop;
 #endif
         }
 
         /*
@@ -4476,40 +4470,40 @@ EmitVariables(JSContext *cx, JSCodeGener
          * pn_lexdef.
          */
         pn3 = pn2->maybeExpr();
 
      do_name:
         if (!BindNameToSlot(cx, cg, pn2))
             return JS_FALSE;
 
-        op = PN_OP(pn2);
+        op = pn2->getOp();
         if (op == JSOP_ARGUMENTS) {
             /* JSOP_ARGUMENTS => no initializer */
             JS_ASSERT(!pn3 && !let);
             pn3 = NULL;
 #ifdef __GNUC__
             atomIndex = 0;            /* quell GCC overwarning */
 #endif
         } else {
             JS_ASSERT(op != JSOP_CALLEE);
             JS_ASSERT(!pn2->pn_cookie.isFree() || !let);
-            if (!MaybeEmitVarDecl(cx, cg, PN_OP(pn), pn2, &atomIndex))
+            if (!MaybeEmitVarDecl(cx, cg, pn->getOp(), pn2, &atomIndex))
                 return JS_FALSE;
 
             if (pn3) {
                 JS_ASSERT(!forInVar);
                 if (op == JSOP_SETNAME) {
                     JS_ASSERT(!let);
                     EMIT_INDEX_OP(JSOP_BINDNAME, atomIndex);
                 } else if (op == JSOP_SETGNAME) {
                     JS_ASSERT(!let);
                     EMIT_INDEX_OP(JSOP_BINDGNAME, atomIndex);
                 }
-                if (pn->pn_op == JSOP_DEFCONST &&
+                if (pn->isOp(JSOP_DEFCONST) &&
                     !js_DefineCompileTimeConstant(cx, cg, pn2->pn_atom, pn3)) {
                     return JS_FALSE;
                 }
 
                 oldflags = cg->flags;
                 cg->flags &= ~TCF_IN_FOR_INIT;
                 if (!js_EmitTree(cx, cg, pn3))
                     return JS_FALSE;
@@ -4520,29 +4514,29 @@ EmitVariables(JSContext *cx, JSCodeGener
         /*
          * The parser rewrites 'for (var x = i in o)' to hoist 'var x = i' --
          * likewise 'for (let x = i in o)' becomes 'i; for (let x in o)' using
          * a TOK_SEQ node to make the two statements appear as one. Therefore
          * if this declaration is part of a for-in loop head, we do not need to
          * emit op or any source note. Our caller, the TOK_FOR/TOK_IN case in
          * js_EmitTree, will annotate appropriately.
          */
-        JS_ASSERT_IF(pn2->pn_defn, pn3 == pn2->pn_expr);
+        JS_ASSERT_IF(pn2->isDefn(), pn3 == pn2->pn_expr);
         if (forInVar) {
             JS_ASSERT(pn->pn_count == 1);
             JS_ASSERT(!pn3);
             break;
         }
 
         if (first &&
             !inLetHead &&
             js_NewSrcNote2(cx, cg, SRC_DECL,
-                           (pn->pn_op == JSOP_DEFCONST)
+                           (pn->isOp(JSOP_DEFCONST))
                            ? SRC_DECL_CONST
-                           : (pn->pn_op == JSOP_DEFVAR)
+                           : (pn->isOp(JSOP_DEFVAR))
                            ? SRC_DECL_VAR
                            : SRC_DECL_LET) < 0) {
             return JS_FALSE;
         }
         if (op == JSOP_ARGUMENTS) {
             if (js_Emit1(cx, cg, op) < 0)
                 return JS_FALSE;
         } else if (!pn2->pn_cookie.isFree()) {
@@ -4587,41 +4581,41 @@ EmitAssignment(JSContext *cx, JSCodeGene
     /*
      * Check left operand type and generate specialized code for it.
      * Specialize to avoid ECMA "reference type" values on the operand
      * stack, which impose pervasive runtime "GetValue" costs.
      */
     jsatomid atomIndex = (jsatomid) -1;              /* quell GCC overwarning */
     jsbytecode offset = 1;
 
-    switch (PN_TYPE(lhs)) {
+    switch (lhs->getKind()) {
       case TOK_NAME:
         if (!BindNameToSlot(cx, cg, lhs))
             return false;
         if (!lhs->pn_cookie.isFree()) {
             atomIndex = lhs->pn_cookie.asInteger();
         } else {
             if (!cg->makeAtomIndex(lhs->pn_atom, &atomIndex))
                 return false;
             if (!lhs->isConst()) {
-                JSOp op = PN_OP(lhs) == JSOP_SETGNAME ? JSOP_BINDGNAME : JSOP_BINDNAME;
+                JSOp op = lhs->isOp(JSOP_SETGNAME) ? JSOP_BINDGNAME : JSOP_BINDNAME;
                 EMIT_INDEX_OP(op, atomIndex);
                 offset++;
             }
         }
         break;
       case TOK_DOT:
         if (!js_EmitTree(cx, cg, lhs->expr()))
             return false;
         offset++;
         if (!cg->makeAtomIndex(lhs->pn_atom, &atomIndex))
             return false;
         break;
       case TOK_LB:
-        JS_ASSERT(lhs->pn_arity == PN_BINARY);
+        JS_ASSERT(lhs->isArity(PN_BINARY));
         if (!js_EmitTree(cx, cg, lhs->pn_left))
             return false;
         if (!js_EmitTree(cx, cg, lhs->pn_right))
             return false;
         offset += 2;
         break;
 #if JS_HAS_DESTRUCTURING
       case TOK_RB:
@@ -4630,55 +4624,52 @@ EmitAssignment(JSContext *cx, JSCodeGene
 #endif
       case TOK_LP:
         if (!js_EmitTree(cx, cg, lhs))
             return false;
         offset++;
         break;
 #if JS_HAS_XML_SUPPORT
       case TOK_UNARYOP:
-        JS_ASSERT(lhs->pn_op == JSOP_SETXMLNAME);
+        JS_ASSERT(lhs->isOp(JSOP_SETXMLNAME));
         if (!js_EmitTree(cx, cg, lhs->pn_kid))
             return false;
         if (js_Emit1(cx, cg, JSOP_BINDXMLNAME) < 0)
             return false;
         offset++;
         break;
 #endif
       default:
         JS_ASSERT(0);
     }
 
     if (op != JSOP_NOP) {
         JS_ASSERT(rhs);
-        switch (lhs->pn_type) {
+        switch (lhs->getKind()) {
           case TOK_NAME:
             if (lhs->isConst()) {
-                if (PN_OP(lhs) == JSOP_CALLEE) {
+                if (lhs->isOp(JSOP_CALLEE)) {
                     if (js_Emit1(cx, cg, JSOP_CALLEE) < 0)
                         return false;
                 } else {
-                    EMIT_INDEX_OP(PN_OP(lhs), atomIndex);
+                    EMIT_INDEX_OP(lhs->getOp(), atomIndex);
                 }
-            } else if (PN_OP(lhs) == JSOP_SETNAME) {
+            } else if (lhs->isOp(JSOP_SETNAME)) {
                 if (js_Emit1(cx, cg, JSOP_DUP) < 0)
                     return false;
                 EMIT_INDEX_OP(JSOP_GETXPROP, atomIndex);
-            } else if (PN_OP(lhs) == JSOP_SETGNAME) {
+            } else if (lhs->isOp(JSOP_SETGNAME)) {
                 if (!BindGlobal(cx, cg, lhs, lhs->pn_atom))
                     return false;
                 if (lhs->pn_cookie.isFree())
                     EmitAtomOp(cx, lhs, JSOP_GETGNAME, cg);
                 else
                     EMIT_UINT16_IMM_OP(JSOP_GETGLOBAL, lhs->pn_cookie.asInteger());
             } else {
-                EMIT_UINT16_IMM_OP((PN_OP(lhs) == JSOP_SETARG)
-                                   ? JSOP_GETARG
-                                   : JSOP_GETLOCAL,
-                                   atomIndex);
+                EMIT_UINT16_IMM_OP(lhs->isOp(JSOP_SETARG) ? JSOP_GETARG : JSOP_GETLOCAL, atomIndex);
             }
             break;
           case TOK_DOT:
             if (js_Emit1(cx, cg, JSOP_DUP) < 0)
                 return false;
             if (lhs->pn_atom == cx->runtime->atomState.protoAtom) {
                 if (!EmitIndexOp(cx, JSOP_QNAMEPART, atomIndex, cg))
                     return false;
@@ -4715,48 +4706,48 @@ EmitAssignment(JSContext *cx, JSCodeGene
 
     /* If += etc., emit the binary operator with a decompiler note. */
     if (op != JSOP_NOP) {
         /*
          * Take care to avoid SRC_ASSIGNOP if the left-hand side is a const
          * declared in the current compilation unit, as in this case (just
          * a bit further below) we will avoid emitting the assignment op.
          */
-        if (lhs->pn_type != TOK_NAME || !lhs->isConst()) {
+        if (!lhs->isKind(TOK_NAME) || !lhs->isConst()) {
             if (js_NewSrcNote(cx, cg, SRC_ASSIGNOP) < 0)
                 return false;
         }
         if (js_Emit1(cx, cg, op) < 0)
             return false;
     }
 
     /* Left parts such as a.b.c and a[b].c need a decompiler note. */
-    if (lhs->pn_type != TOK_NAME &&
+    if (!lhs->isKind(TOK_NAME) &&
 #if JS_HAS_DESTRUCTURING
-        lhs->pn_type != TOK_RB &&
-        lhs->pn_type != TOK_RC &&
+        !lhs->isKind(TOK_RB) &&
+        !lhs->isKind(TOK_RC) &&
 #endif
         js_NewSrcNote2(cx, cg, SRC_PCBASE, CG_OFFSET(cg) - top) < 0) {
         return false;
     }
 
     /* Finally, emit the specialized assignment bytecode. */
-    switch (lhs->pn_type) {
+    switch (lhs->getKind()) {
       case TOK_NAME:
         if (lhs->isConst()) {
             if (!rhs) {
                 ReportCompileErrorNumber(cx, CG_TS(cg), lhs, JSREPORT_ERROR,
                                          JSMSG_BAD_FOR_LEFTSIDE);
                 return false;
             }
             break;
         }
         /* FALL THROUGH */
       case TOK_DOT:
-        EMIT_INDEX_OP(PN_OP(lhs), atomIndex);
+        EMIT_INDEX_OP(lhs->getOp(), atomIndex);
         break;
       case TOK_LB:
       case TOK_LP:
         if (js_Emit1(cx, cg, JSOP_SETELEM) < 0)
             return false;
         break;
 #if JS_HAS_DESTRUCTURING
       case TOK_RB:
@@ -4831,40 +4822,40 @@ EmitEndInit(JSContext *cx, JSCodeGenerat
         EMIT_UINT16_IMM_OP(JSOP_SHARPINIT, cg->sharpSlotBase);
 #endif
     return js_Emit1(cx, cg, JSOP_ENDINIT) >= 0;
 }
 
 bool
 JSParseNode::getConstantValue(JSContext *cx, bool strictChecks, Value *vp)
 {
-    switch (pn_type) {
+    switch (getKind()) {
       case TOK_NUMBER:
         vp->setNumber(pn_dval);
         return true;
       case TOK_STRING:
         vp->setString(pn_atom);
         return true;
       case TOK_PRIMARY:
-        switch (pn_op) {
+        switch (getOp()) {
           case JSOP_NULL:
             vp->setNull();
             return true;
           case JSOP_FALSE:
             vp->setBoolean(false);
             return true;
           case JSOP_TRUE:
             vp->setBoolean(true);
             return true;
           default:
             JS_NOT_REACHED("Unexpected node");
             return false;
         }
       case TOK_RB: {
-        JS_ASSERT((pn_op == JSOP_NEWINIT) && !(pn_xflags & PNX_NONCONST));
+        JS_ASSERT(isOp(JSOP_NEWINIT) && !(pn_xflags & PNX_NONCONST));
  
         JSObject *obj = NewDenseAllocatedArray(cx, pn_count);
         if (!obj)
             return false;
 
         unsigned idx = 0;
         for (JSParseNode *pn = pn_head; pn; idx++, pn = pn->pn_next) {
             Value value;
@@ -4875,41 +4866,41 @@ JSParseNode::getConstantValue(JSContext 
         }
         JS_ASSERT(idx == pn_count);
 
         types::FixArrayType(cx, obj);
         vp->setObject(*obj);
         return true;
       }
       case TOK_RC: {
-        JS_ASSERT((pn_op == JSOP_NEWINIT) && !(pn_xflags & PNX_NONCONST));
+        JS_ASSERT(isOp(JSOP_NEWINIT) && !(pn_xflags & PNX_NONCONST));
 
         gc::AllocKind kind = GuessObjectGCKind(pn_count, false);
         JSObject *obj = NewBuiltinClassInstance(cx, &ObjectClass, kind);
         if (!obj)
             return false;
 
         for (JSParseNode *pn = pn_head; pn; pn = pn->pn_next) {
             Value value;
             if (!pn->pn_right->getConstantValue(cx, strictChecks, &value))
                 return false;
 
             JSParseNode *pnid = pn->pn_left;
-            if (pnid->pn_type == TOK_NUMBER) {
+            if (pnid->isKind(TOK_NUMBER)) {
                 Value idvalue = NumberValue(pnid->pn_dval);
                 jsid id;
                 if (idvalue.isInt32() && INT_FITS_IN_JSID(idvalue.toInt32()))
                     id = INT_TO_JSID(idvalue.toInt32());
                 else if (!js_InternNonIntElementId(cx, obj, idvalue, &id))
                     return false;
                 if (!obj->defineProperty(cx, id, value, NULL, NULL, JSPROP_ENUMERATE))
                     return false;
             } else {
-                JS_ASSERT(pnid->pn_type == TOK_NAME ||
-                          pnid->pn_type == TOK_STRING);
+                JS_ASSERT(pnid->isKind(TOK_NAME) ||
+                          pnid->isKind(TOK_STRING));
                 JS_ASSERT(pnid->pn_atom != cx->runtime->atomState.protoAtom);
                 jsid id = ATOM_TO_JSID(pnid->pn_atom);
                 if (!DefineNativeProperty(cx, obj, id, value, NULL, NULL,
                                           JSPROP_ENUMERATE, 0, 0)) {
                     return false;
                 }
             }
         }
@@ -4978,39 +4969,39 @@ js_EmitTree(JSContext *cx, JSCodeGenerat
     JS_CHECK_RECURSION(cx, return JS_FALSE);
 
     ok = JS_TRUE;
     pn->pn_offset = top = CG_OFFSET(cg);
 
     /* Emit notes to tell the current bytecode's source line number. */
     UPDATE_LINE_NUMBER_NOTES(cx, cg, pn->pn_pos.begin.lineno);
 
-    switch (pn->pn_type) {
+    switch (pn->getKind()) {
       case TOK_FUNCTION:
       {
         JSFunction *fun;
         uintN slot;
 
 #if JS_HAS_XML_SUPPORT
-        if (pn->pn_arity == PN_NULLARY) {
+        if (pn->isArity(PN_NULLARY)) {
             if (js_Emit1(cx, cg, JSOP_GETFUNNS) < 0)
                 return JS_FALSE;
             break;
         }
 #endif
 
         fun = pn->pn_funbox->function();
         JS_ASSERT(fun->isInterpreted());
         if (fun->script()) {
             /*
              * This second pass is needed to emit JSOP_NOP with a source note
              * for the already-emitted function definition prolog opcode. See
              * comments in the TOK_LC case.
              */
-            JS_ASSERT(pn->pn_op == JSOP_NOP);
+            JS_ASSERT(pn->isOp(JSOP_NOP));
             JS_ASSERT(cg->inFunction());
             if (!EmitFunctionDefNop(cx, cg, pn->pn_index))
                 return JS_FALSE;
             break;
         }
 
         JS_ASSERT_IF(pn->pn_funbox->tcflags & TCF_FUN_HEAVYWEIGHT,
                      fun->kind() == JSFUN_INTERPRETED);
@@ -5054,17 +5045,17 @@ js_EmitTree(JSContext *cx, JSCodeGenerat
         cg2 = NULL;
         if (!pn)
             return JS_FALSE;
 
         /* Make the function object a literal in the outer script's pool. */
         index = cg->objectList.index(pn->pn_funbox);
 
         /* Emit a bytecode pointing to the closure object in its immediate. */
-        op = PN_OP(pn);
+        op = pn->getOp();
         if (op != JSOP_NOP) {
             if ((pn->pn_funbox->tcflags & TCF_GENEXP_LAMBDA) &&
                 js_NewSrcNote(cx, cg, SRC_GENEXP) < 0) {
                 return JS_FALSE;
             }
             EMIT_INDEX_OP(op, index);
 
             /* Make blockChain determination quicker. */
@@ -5120,21 +5111,21 @@ js_EmitTree(JSContext *cx, JSCodeGenerat
         }
         break;
       }
 
       case TOK_ARGSBODY:
       {
         JSParseNode *pnlast = pn->last();
         for (JSParseNode *pn2 = pn->pn_head; pn2 != pnlast; pn2 = pn2->pn_next) {
-            if (!pn2->pn_defn)
+            if (!pn2->isDefn())
                 continue;
             if (!BindNameToSlot(cx, cg, pn2))
                 return JS_FALSE;
-            if (JOF_OPTYPE(pn2->pn_op) == JOF_QARG && cg->shouldNoteClosedName(pn2)) {
+            if (JOF_OPTYPE(pn2->getOp()) == JOF_QARG && cg->shouldNoteClosedName(pn2)) {
                 if (!cg->closedArgs.append(pn2->pn_cookie.slot()))
                     return JS_FALSE;
             }
         }
         ok = js_EmitTree(cx, cg, pnlast);
         break;
       }
 
@@ -5201,17 +5192,17 @@ js_EmitTree(JSContext *cx, JSCodeGenerat
              * stmtInfo.breaks.
              */
             jmp = EmitGoto(cx, cg, &stmtInfo, &stmtInfo.breaks);
             if (jmp < 0)
                 return JS_FALSE;
 
             /* Ensure the branch-if-false comes here, then emit the else. */
             CHECK_AND_SET_JUMP_OFFSET_AT(cx, cg, beq);
-            if (pn3->pn_type == TOK_IF) {
+            if (pn3->isKind(TOK_IF)) {
                 pn = pn3;
                 goto if_again;
             }
 
             if (!js_EmitTree(cx, cg, pn3))
                 return JS_FALSE;
 
             /*
@@ -5337,31 +5328,31 @@ js_EmitTree(JSContext *cx, JSCodeGenerat
         break;
 
       case TOK_FOR:
         beq = 0;                /* suppress gcc warnings */
         jmp = -1;
         pn2 = pn->pn_left;
         js_PushStatement(cg, &stmtInfo, STMT_FOR_LOOP, top);
 
-        if (pn2->pn_type == TOK_IN) {
+        if (pn2->isKind(TOK_IN)) {
             /* Set stmtInfo type for later testing. */
             stmtInfo.type = STMT_FOR_IN_LOOP;
 
             /*
              * If the left part is 'var x', emit code to define x if necessary
              * using a prolog opcode, but do not emit a pop. If the left part
              * was originally 'var x = i', the parser will have rewritten it;
              * see Parser::forStatement. 'for (let x = i in o)' is mercifully
              * banned.
              */
             bool forLet = false;
             if (JSParseNode *decl = pn2->pn_kid1) {
-                JS_ASSERT(TokenKindIsDecl(PN_TYPE(decl)));
-                forLet = PN_TYPE(decl) == TOK_LET;
+                JS_ASSERT(TokenKindIsDecl(decl->getKind()));
+                forLet = decl->isKind(TOK_LET);
                 cg->flags |= TCF_IN_FOR_INIT;
                 if (!js_EmitTree(cx, cg, decl))
                     return JS_FALSE;
                 cg->flags &= ~TCF_IN_FOR_INIT;
             }
 
             /* Compile the object expression to the right of 'in'. */
             {
@@ -5374,17 +5365,17 @@ js_EmitTree(JSContext *cx, JSCodeGenerat
                     return JS_FALSE;
             }
 
             /*
              * Emit a bytecode to convert top of stack value to the iterator
              * object depending on the loop variant (for-in, for-each-in, or
              * destructuring for-in).
              */
-            JS_ASSERT(pn->pn_op == JSOP_ITER);
+            JS_ASSERT(pn->isOp(JSOP_ITER));
             if (js_Emit2(cx, cg, JSOP_ITER, (uint8) pn->pn_iflags) < 0)
                 return JS_FALSE;
 
             /* Annotate so the decompiler can find the loop-closing jump. */
             noteIndex = js_NewSrcNote(cx, cg, SRC_FOR_IN);
             if (noteIndex < 0)
                 return JS_FALSE;
 
@@ -5414,17 +5405,17 @@ js_EmitTree(JSContext *cx, JSCodeGenerat
              * left hand side. The JSOP_POP after this assignment is annotated
              * so that the decompiler can distinguish 'for (x in y)' from
              * 'for (var x in y)'.
              */
             if (!EmitAssignment(cx, cg, pn2->pn_kid2, JSOP_NOP, NULL))
                 return false;
             tmp2 = CG_OFFSET(cg);
             if (pn2->pn_kid1 && js_NewSrcNote2(cx, cg, SRC_DECL,
-                                               (pn2->pn_kid1->pn_op == JSOP_DEFVAR)
+                                               (pn2->pn_kid1->isOp(JSOP_DEFVAR))
                                                ? SRC_DECL_VAR
                                                : SRC_DECL_LET) < 0) {
                 return false;
             }
             if (js_Emit1(cx, cg, JSOP_POP) < 0)
                 return false;
 
             /* The stack should be balanced around the assignment opcode sequence. */
@@ -5467,32 +5458,32 @@ js_EmitTree(JSContext *cx, JSCodeGenerat
             op = JSOP_POP;
             pn3 = pn2->pn_kid1;
             if (!pn3) {
                 /* No initializer: emit an annotated nop for the decompiler. */
                 op = JSOP_NOP;
             } else {
                 cg->flags |= TCF_IN_FOR_INIT;
 #if JS_HAS_DESTRUCTURING
-                if (pn3->pn_type == TOK_ASSIGN &&
+                if (pn3->isKind(TOK_ASSIGN) &&
                     !MaybeEmitGroupAssignment(cx, cg, op, pn3, &op)) {
                     return JS_FALSE;
                 }
 #endif
                 if (op == JSOP_POP) {
                     if (!js_EmitTree(cx, cg, pn3))
                         return JS_FALSE;
-                    if (TokenKindIsDecl(PN_TYPE(pn3))) {
+                    if (TokenKindIsDecl(pn3->getKind())) {
                         /*
                          * Check whether a destructuring-initialized var decl
                          * was optimized to a group assignment.  If so, we do
                          * not need to emit a pop below, so switch to a nop,
                          * just for the decompiler.
                          */
-                        JS_ASSERT(pn3->pn_arity == PN_LIST);
+                        JS_ASSERT(pn3->isArity(PN_LIST));
                         if (pn3->pn_xflags & PNX_GROUPINIT)
                             op = JSOP_NOP;
                     }
                 }
                 cg->flags &= ~TCF_IN_FOR_INIT;
             }
 
             /*
@@ -5536,17 +5527,17 @@ js_EmitTree(JSContext *cx, JSCodeGenerat
                 stmt->update = CG_OFFSET(cg);
             } while ((stmt = stmt->down) != NULL && stmt->type == STMT_LABEL);
 
             /* Check for update code to do before the condition (if any). */
             pn3 = pn2->pn_kid3;
             if (pn3) {
                 op = JSOP_POP;
 #if JS_HAS_DESTRUCTURING
-                if (pn3->pn_type == TOK_ASSIGN &&
+                if (pn3->isKind(TOK_ASSIGN) &&
                     !MaybeEmitGroupAssignment(cx, cg, op, pn3, &op)) {
                     return JS_FALSE;
                 }
 #endif
                 if (op == JSOP_POP && !js_EmitTree(cx, cg, pn3))
                     return JS_FALSE;
 
                 /* Always emit the POP or NOP, to help the decompiler. */
@@ -5607,17 +5598,17 @@ js_EmitTree(JSContext *cx, JSCodeGenerat
                     return JS_FALSE;
             }
         }
 
         /* Now fixup all breaks and continues (before for/in's JSOP_ENDITER). */
         if (!js_PopStatementCG(cx, cg))
             return JS_FALSE;
 
-        if (pn2->pn_type == TOK_IN) {
+        if (pn2->isKind(TOK_IN)) {
             if (!NewTryNote(cx, cg, JSTRY_ITER, cg->stackDepth, top, CG_OFFSET(cg)) ||
                 js_Emit1(cx, cg, JSOP_ENDITER) < 0) {
                 return JS_FALSE;
             }
         }
         break;
 
       case TOK_BREAK: {
@@ -5826,17 +5817,17 @@ js_EmitTree(JSContext *cx, JSCodeGenerat
                     return JS_FALSE;
                 CATCHNOTE(stmtInfo) = catchNote;
 
                 /*
                  * Emit the lexical scope and catch body.  Save the catch's
                  * block object population via count, for use when targeting
                  * guardJump at the next catch (the guard mismatch case).
                  */
-                JS_ASSERT(pn3->pn_type == TOK_LEXICALSCOPE);
+                JS_ASSERT(pn3->isKind(TOK_LEXICALSCOPE));
                 count = OBJ_BLOCK_COUNT(cx, pn3->pn_objbox->object);
                 prevBox = pn3->pn_objbox;
                 if (!js_EmitTree(cx, cg, pn3))
                     return JS_FALSE;
 
                 /* gosub <finally>, if required */
                 if (pn->pn_kid3) {
                     jmp = EmitBackPatchOp(cx, cg, JSOP_BACKPATCH,
@@ -5975,17 +5966,17 @@ js_EmitTree(JSContext *cx, JSCodeGenerat
         /*
          * Dup the exception object if there is a guard for rethrowing to use
          * it later when rethrowing or in other catches.
          */
         if (pn->pn_kid2 && js_Emit1(cx, cg, JSOP_DUP) < 0)
             return JS_FALSE;
 
         pn2 = pn->pn_kid1;
-        switch (pn2->pn_type) {
+        switch (pn2->getKind()) {
 #if JS_HAS_DESTRUCTURING
           case TOK_RB:
           case TOK_RC:
             if (!EmitDestructuringOps(cx, cg, JSOP_NOP, pn2))
                 return JS_FALSE;
             if (js_Emit1(cx, cg, JSOP_POP) < 0)
                 return JS_FALSE;
             break;
@@ -6090,26 +6081,26 @@ js_EmitTree(JSContext *cx, JSCodeGenerat
         if (js_Emit1(cx, cg, JSOP_YIELD) < 0)
             return JS_FALSE;
         break;
 #endif
 
       case TOK_LC:
       {
 #if JS_HAS_XML_SUPPORT
-        if (pn->pn_arity == PN_UNARY) {
+        if (pn->isArity(PN_UNARY)) {
             if (!js_EmitTree(cx, cg, pn->pn_kid))
                 return JS_FALSE;
-            if (js_Emit1(cx, cg, PN_OP(pn)) < 0)
+            if (js_Emit1(cx, cg, pn->getOp()) < 0)
                 return JS_FALSE;
             break;
         }
 #endif
 
-        JS_ASSERT(pn->pn_arity == PN_LIST);
+        JS_ASSERT(pn->isArity(PN_LIST));
 
         noteIndex = -1;
         tmp = CG_OFFSET(cg);
         if (pn->pn_xflags & PNX_NEEDBRACES) {
             noteIndex = js_NewSrcNote2(cx, cg, SRC_BRACE, 0);
             if (noteIndex < 0 || js_Emit1(cx, cg, JSOP_NOP) < 0)
                 return JS_FALSE;
         }
@@ -6130,36 +6121,36 @@ js_EmitTree(JSContext *cx, JSCodeGenerat
              * mode for scripts does not allow separate emitter passes.
              */
             JS_ASSERT(cg->inFunction());
             if (pn->pn_xflags & PNX_DESTRUCT) {
                 /*
                  * Assign the destructuring arguments before defining any
                  * functions, see bug 419662.
                  */
-                JS_ASSERT(pnchild->pn_type == TOK_SEMI);
-                JS_ASSERT(pnchild->pn_kid->pn_type == TOK_VAR);
+                JS_ASSERT(pnchild->isKind(TOK_SEMI));
+                JS_ASSERT(pnchild->pn_kid->isKind(TOK_VAR));
                 if (!js_EmitTree(cx, cg, pnchild))
                     return JS_FALSE;
                 pnchild = pnchild->pn_next;
             }
 
             for (pn2 = pnchild; pn2; pn2 = pn2->pn_next) {
-                if (pn2->pn_type == TOK_FUNCTION) {
-                    if (pn2->pn_op == JSOP_NOP) {
+                if (pn2->isKind(TOK_FUNCTION)) {
+                    if (pn2->isOp(JSOP_NOP)) {
                         if (!js_EmitTree(cx, cg, pn2))
                             return JS_FALSE;
                     } else {
                         /*
                          * JSOP_DEFFUN in a top-level block with function
                          * definitions appears, for example, when "if (true)"
                          * is optimized away from "if (true) function x() {}".
                          * See bug 428424.
                          */
-                        JS_ASSERT(pn2->pn_op == JSOP_DEFFUN);
+                        JS_ASSERT(pn2->isOp(JSOP_DEFFUN));
                     }
                 }
             }
         }
         for (pn2 = pnchild; pn2; pn2 = pn2->pn_next) {
             if (!js_EmitTree(cx, cg, pn2))
                 return JS_FALSE;
         }
@@ -6170,17 +6161,17 @@ js_EmitTree(JSContext *cx, JSCodeGenerat
             return JS_FALSE;
         }
 
         ok = js_PopStatementCG(cx, cg);
         break;
       }
 
       case TOK_SEQ:
-        JS_ASSERT(pn->pn_arity == PN_LIST);
+        JS_ASSERT(pn->isArity(PN_LIST));
         js_PushStatement(cg, &stmtInfo, STMT_SEQ, top);
         for (pn2 = pn->pn_head; pn2; pn2 = pn2->pn_next) {
             if (!js_EmitTree(cx, cg, pn2))
                 return JS_FALSE;
         }
         ok = js_PopStatementCG(cx, cg);
         break;
 
@@ -6226,36 +6217,36 @@ js_EmitTree(JSContext *cx, JSCodeGenerat
                                                   JSMSG_USELESS_EXPR)) {
                         return JS_FALSE;
                     }
                 }
             } else {
                 op = wantval ? JSOP_POPV : JSOP_POP;
 #if JS_HAS_DESTRUCTURING
                 if (!wantval &&
-                    pn2->pn_type == TOK_ASSIGN &&
+                    pn2->isKind(TOK_ASSIGN) &&
                     !MaybeEmitGroupAssignment(cx, cg, op, pn2, &op)) {
                     return JS_FALSE;
                 }
 #endif
                 if (op != JSOP_NOP) {
                     /*
                      * Specialize JSOP_SETPROP to JSOP_SETMETHOD to defer or
                      * avoid null closure cloning. Do this only for assignment
                      * statements that are not completion values wanted by a
                      * script evaluator, to ensure that the joined function
                      * can't escape directly.
                      */
                     if (!wantval &&
-                        PN_TYPE(pn2) == TOK_ASSIGN &&
-                        PN_OP(pn2) == JSOP_NOP &&
-                        PN_OP(pn2->pn_left) == JSOP_SETPROP &&
-                        PN_OP(pn2->pn_right) == JSOP_LAMBDA &&
+                        pn2->isKind(TOK_ASSIGN) &&
+                        pn2->isOp(JSOP_NOP) &&
+                        pn2->pn_left->isOp(JSOP_SETPROP) &&
+                        pn2->pn_right->isOp(JSOP_LAMBDA) &&
                         pn2->pn_right->pn_funbox->joinable()) {
-                        pn2->pn_left->pn_op = JSOP_SETMETHOD;
+                        pn2->pn_left->setOp(JSOP_SETMETHOD);
                     }
                     if (!js_EmitTree(cx, cg, pn2))
                         return JS_FALSE;
                     if (js_Emit1(cx, cg, op) < 0)
                         return JS_FALSE;
                 }
             }
         }
@@ -6265,19 +6256,19 @@ js_EmitTree(JSContext *cx, JSCodeGenerat
         /* Emit an annotated nop so we know to decompile a label. */
         atom = pn->pn_atom;
 
         jsatomid index;
         if (!cg->makeAtomIndex(atom, &index))
             return JS_FALSE;
 
         pn2 = pn->expr();
-        noteType = (pn2->pn_type == TOK_LC ||
-                    (pn2->pn_type == TOK_LEXICALSCOPE &&
-                     pn2->expr()->pn_type == TOK_LC))
+        noteType = (pn2->isKind(TOK_LC) ||
+                    (pn2->isKind(TOK_LEXICALSCOPE) &&
+                     pn2->expr()->isKind(TOK_LC)))
                    ? SRC_LABELBRACE
                    : SRC_LABEL;
         noteIndex = js_NewSrcNote2(cx, cg, noteType, ptrdiff_t(index));
         if (noteIndex < 0 ||
             js_Emit1(cx, cg, JSOP_NOP) < 0) {
             return JS_FALSE;
         }
 
@@ -6320,17 +6311,17 @@ js_EmitTree(JSContext *cx, JSCodeGenerat
             if (noteIndex < 0 ||
                 js_Emit1(cx, cg, JSOP_POP) < 0) {
                 return JS_FALSE;
             }
         }
         break;
 
       case TOK_ASSIGN:
-        if (!EmitAssignment(cx, cg, pn->pn_left, PN_OP(pn), pn->pn_right))
+        if (!EmitAssignment(cx, cg, pn->pn_left, pn->getOp(), pn->pn_right))
             return false;
         break;
 
       case TOK_HOOK:
         /* Emit the condition, then branch if false to the else part. */
         if (!js_EmitTree(cx, cg, pn->pn_kid1))
             return JS_FALSE;
         noteIndex = js_NewSrcNote(cx, cg, SRC_COND);
@@ -6374,30 +6365,30 @@ js_EmitTree(JSContext *cx, JSCodeGenerat
          * leaves the original operand value on the stack and jumps; otherwise
          * it pops and falls into the next bytecode, which evaluates the right
          * operand.  The jump goes around the right operand evaluation.
          *
          * JSOP_AND converts the operand on the stack to boolean, and if false,
          * leaves the original operand value on the stack and jumps; otherwise
          * it pops and falls into the right operand's bytecode.
          */
-        if (pn->pn_arity == PN_BINARY) {
+        if (pn->isArity(PN_BINARY)) {
             if (!js_EmitTree(cx, cg, pn->pn_left))
                 return JS_FALSE;
             top = EmitJump(cx, cg, JSOP_BACKPATCH_POP, 0);
             if (top < 0)
                 return JS_FALSE;
             if (!js_EmitTree(cx, cg, pn->pn_right))
                 return JS_FALSE;
             off = CG_OFFSET(cg);
             pc = CG_CODE(cg, top);
             CHECK_AND_SET_JUMP_OFFSET(cx, cg, pc, off - top);
-            *pc = pn->pn_op;
+            *pc = pn->getOp();
         } else {
-            JS_ASSERT(pn->pn_arity == PN_LIST);
+            JS_ASSERT(pn->isArity(PN_LIST));
             JS_ASSERT(pn->pn_head->pn_next->pn_next);
 
             /* Left-associative operator chain: avoid too much recursion. */
             pn2 = pn->pn_head;
             if (!js_EmitTree(cx, cg, pn2))
                 return JS_FALSE;
             top = EmitJump(cx, cg, JSOP_BACKPATCH_POP, 0);
             if (top < 0)
@@ -6420,17 +6411,17 @@ js_EmitTree(JSContext *cx, JSCodeGenerat
                 return JS_FALSE;
 
             pn2 = pn->pn_head;
             off = CG_OFFSET(cg);
             do {
                 pc = CG_CODE(cg, top);
                 tmp = GetJumpOffset(cg, pc);
                 CHECK_AND_SET_JUMP_OFFSET(cx, cg, pc, off - top);
-                *pc = pn->pn_op;
+                *pc = pn->getOp();
                 top += tmp;
             } while ((pn2 = pn2->pn_next)->pn_next);
         }
         break;
 
       case TOK_PLUS:
       case TOK_BITOR:
       case TOK_BITXOR:
@@ -6438,37 +6429,37 @@ js_EmitTree(JSContext *cx, JSCodeGenerat
       case TOK_EQOP:
       case TOK_RELOP:
       case TOK_IN:
       case TOK_INSTANCEOF:
       case TOK_SHOP:
       case TOK_MINUS:
       case TOK_STAR:
       case TOK_DIVOP:
-        if (pn->pn_arity == PN_LIST) {
+        if (pn->isArity(PN_LIST)) {
             /* Left-associative operator chain: avoid too much recursion. */
             pn2 = pn->pn_head;
             if (!js_EmitTree(cx, cg, pn2))
                 return JS_FALSE;
-            op = PN_OP(pn);
+            op = pn->getOp();
             while ((pn2 = pn2->pn_next) != NULL) {
                 if (!js_EmitTree(cx, cg, pn2))
                     return JS_FALSE;
                 if (js_Emit1(cx, cg, op) < 0)
                     return JS_FALSE;
             }
         } else {
 #if JS_HAS_XML_SUPPORT
             uintN oldflags;
 
       case TOK_DBLCOLON:
-            if (pn->pn_arity == PN_NAME) {
+            if (pn->isArity(PN_NAME)) {
                 if (!js_EmitTree(cx, cg, pn->expr()))
                     return JS_FALSE;
-                if (!EmitAtomOp(cx, pn, PN_OP(pn), cg))
+                if (!EmitAtomOp(cx, pn, pn->getOp(), cg))
                     return JS_FALSE;
                 break;
             }
 
             /*
              * Binary :: has a right operand that brackets arbitrary code,
              * possibly including a let (a = b) ... expression.  We must clear
              * TCF_IN_FOR_INIT to avoid mis-compiling such beasts.
@@ -6480,69 +6471,69 @@ js_EmitTree(JSContext *cx, JSCodeGenerat
             /* Binary operators that evaluate both operands unconditionally. */
             if (!js_EmitTree(cx, cg, pn->pn_left))
                 return JS_FALSE;
             if (!js_EmitTree(cx, cg, pn->pn_right))
                 return JS_FALSE;
 #if JS_HAS_XML_SUPPORT
             cg->flags |= oldflags & TCF_IN_FOR_INIT;
 #endif
-            if (js_Emit1(cx, cg, PN_OP(pn)) < 0)
+            if (js_Emit1(cx, cg, pn->getOp()) < 0)
                 return JS_FALSE;
         }
         break;
 
       case TOK_THROW:
 #if JS_HAS_XML_SUPPORT
       case TOK_AT:
       case TOK_DEFAULT:
-        JS_ASSERT(pn->pn_arity == PN_UNARY);
+        JS_ASSERT(pn->isArity(PN_UNARY));
         /* FALL THROUGH */
 #endif
       case TOK_UNARYOP:
       {
         uintN oldflags;
 
         /* Unary op, including unary +/-. */
-        op = PN_OP(pn);
+        op = pn->getOp();
 #if JS_HAS_XML_SUPPORT
         if (op == JSOP_XMLNAME) {
             if (!EmitXMLName(cx, pn, op, cg))
                 return JS_FALSE;
             break;
         }
 #endif
         pn2 = pn->pn_kid;
 
-        if (op == JSOP_TYPEOF && pn2->pn_type != TOK_NAME)
+        if (op == JSOP_TYPEOF && !pn2->isKind(TOK_NAME))
             op = JSOP_TYPEOFEXPR;
 
         oldflags = cg->flags;
         cg->flags &= ~TCF_IN_FOR_INIT;
         if (!js_EmitTree(cx, cg, pn2))
             return JS_FALSE;
         cg->flags |= oldflags & TCF_IN_FOR_INIT;
         if (js_Emit1(cx, cg, op) < 0)
             return JS_FALSE;
         break;
       }
 
       case TOK_INC:
       case TOK_DEC:
         /* Emit lvalue-specialized code for ++/-- operators. */
         pn2 = pn->pn_kid;
-        JS_ASSERT(pn2->pn_type != TOK_RP);
-        op = PN_OP(pn);
-        switch (pn2->pn_type) {
+        JS_ASSERT(!pn2->isKind(TOK_RP));
+        op = pn->getOp();
+        switch (pn2->getKind()) {
           default:
-            JS_ASSERT(pn2->pn_type == TOK_NAME);
-            pn2->pn_op = op;
+            JS_ASSERT(pn2->isKind(TOK_NAME));
+            pn2->setOp(op);
             if (!BindNameToSlot(cx, cg, pn2))
                 return JS_FALSE;
-            op = PN_OP(pn2);
+            op = pn2->getOp();
             if (op == JSOP_CALLEE) {
                 if (js_Emit1(cx, cg, op) < 0)
                     return JS_FALSE;
             } else if (!pn2->pn_cookie.isFree()) {
                 atomIndex = pn2->pn_cookie.asInteger();
                 EMIT_UINT16_IMM_OP(op, atomIndex);
             } else {
                 JS_ASSERT(JOF_OPTYPE(op) == JOF_ATOM);
@@ -6553,17 +6544,17 @@ js_EmitTree(JSContext *cx, JSCodeGenerat
                     if (!EmitAtomOp(cx, pn2, op, cg))
                         return JS_FALSE;
                 }
                 break;
             }
             if (pn2->isConst()) {
                 if (js_Emit1(cx, cg, JSOP_POS) < 0)
                     return JS_FALSE;
-                op = PN_OP(pn);
+                op = pn->getOp();
                 if (!(js_CodeSpec[op].format & JOF_POST)) {
                     if (js_Emit1(cx, cg, JSOP_ONE) < 0)
                         return JS_FALSE;
                     op = (js_CodeSpec[op].format & JOF_INC) ? JSOP_ADD : JSOP_SUB;
                     if (js_Emit1(cx, cg, op) < 0)
                         return JS_FALSE;
                 }
             }
@@ -6594,17 +6585,17 @@ js_EmitTree(JSContext *cx, JSCodeGenerat
             JS_ASSERT(js_CodeSpec[op].format & JOF_ELEM);
             if (js_Emit1(cx, cg, (JSOp)1) < 0)
                 return JS_FALSE;
             if (js_Emit1(cx, cg, JSOP_POP) < 0)
                 return JS_FALSE;
             break;
 #if JS_HAS_XML_SUPPORT
           case TOK_UNARYOP:
-            JS_ASSERT(pn2->pn_op == JSOP_SETXMLNAME);
+            JS_ASSERT(pn2->isOp(JSOP_SETXMLNAME));
             if (!js_EmitTree(cx, cg, pn2->pn_kid))
                 return JS_FALSE;
             if (js_Emit1(cx, cg, JSOP_BINDXMLNAME) < 0)
                 return JS_FALSE;
             if (!EmitElemIncDec(cx, NULL, op, cg))
                 return JS_FALSE;
             break;
 #endif
@@ -6612,21 +6603,21 @@ js_EmitTree(JSContext *cx, JSCodeGenerat
         break;
 
       case TOK_DELETE:
         /*
          * Under ECMA 3, deleting a non-reference returns true -- but alas we
          * must evaluate the operand if it appears it might have side effects.
          */
         pn2 = pn->pn_kid;
-        switch (pn2->pn_type) {
+        switch (pn2->getKind()) {
           case TOK_NAME:
             if (!BindNameToSlot(cx, cg, pn2))
                 return JS_FALSE;
-            op = PN_OP(pn2);
+            op = pn2->getOp();
             if (op == JSOP_FALSE) {
                 if (js_Emit1(cx, cg, op) < 0)
                     return JS_FALSE;
             } else {
                 if (!EmitAtomOp(cx, pn2, op, cg))
                     return JS_FALSE;
             }
             break;
@@ -6650,17 +6641,17 @@ js_EmitTree(JSContext *cx, JSCodeGenerat
              * to foo(), true (a comma expression, requiring SRC_PCDELTA).
              */
             useful = JS_FALSE;
             if (!CheckSideEffects(cx, cg, pn2, &useful))
                 return JS_FALSE;
             if (!useful) {
                 off = noteIndex = -1;
             } else {
-                JS_ASSERT_IF(pn2->pn_type == TOK_LP, !(pn2->pn_xflags & PNX_SETCALL));
+                JS_ASSERT_IF(pn2->isKind(TOK_LP), !(pn2->pn_xflags & PNX_SETCALL));
                 if (!js_EmitTree(cx, cg, pn2))
                     return JS_FALSE;
                 off = CG_OFFSET(cg);
                 noteIndex = js_NewSrcNote2(cx, cg, SRC_PCDELTA, 0);
                 if (noteIndex < 0 || js_Emit1(cx, cg, JSOP_POP) < 0)
                     return JS_FALSE;
             }
             if (js_Emit1(cx, cg, JSOP_TRUE) < 0)
@@ -6696,36 +6687,36 @@ js_EmitTree(JSContext *cx, JSCodeGenerat
 #endif
 
       case TOK_DOT:
         /*
          * Pop a stack operand, convert it to object, get a property named by
          * this bytecode's immediate-indexed atom operand, and push its value
          * (not a reference to it).
          */
-        ok = EmitPropOp(cx, pn, PN_OP(pn), cg, JS_FALSE);
+        ok = EmitPropOp(cx, pn, pn->getOp(), cg, JS_FALSE);
         break;
 
       case TOK_LB:
 #if JS_HAS_XML_SUPPORT
       case TOK_DBLDOT:
 #endif
         /*
          * Pop two operands, convert the left one to object and the right one
          * to property name (atom or tagged int), get the named property, and
          * push its value.  Set the "obj" register to the result of ToObject
          * on the left operand.
          */
-        ok = EmitElemOp(cx, pn, PN_OP(pn), cg);
+        ok = EmitElemOp(cx, pn, pn->getOp(), cg);
         break;
 
       case TOK_NEW:
       case TOK_LP:
       {
-        bool callop = (PN_TYPE(pn) == TOK_LP);
+        bool callop = pn->isKind(TOK_LP);
 
         /*
          * Emit callable invocation or operator new (constructor call) code.
          * First, emit code for the left operand to evaluate the callable or
          * constructable object expression.
          *
          * For operator new applied to other expressions than E4X ones, we emit
          * JSOP_GETPROP instead of JSOP_CALLPROP, etc. This is necessary to
@@ -6733,33 +6724,33 @@ js_EmitTree(JSContext *cx, JSCodeGenerat
          * in jsinterp.cpp for JSOP_LAMBDA followed by JSOP_{SET,INIT}PROP.
          *
          * Then (or in a call case that has no explicit reference-base
          * object) we emit JSOP_PUSH to produce the |this| slot required
          * for calls (which non-strict mode functions will box into the
          * global object).
          */
         pn2 = pn->pn_head;
-        switch (pn2->pn_type) {
+        switch (pn2->getKind()) {
           case TOK_NAME:
             if (!EmitNameOp(cx, cg, pn2, callop))
                 return JS_FALSE;
             break;
           case TOK_DOT:
-            if (!EmitPropOp(cx, pn2, PN_OP(pn2), cg, callop))
+            if (!EmitPropOp(cx, pn2, pn2->getOp(), cg, callop))
                 return JS_FALSE;
             break;
           case TOK_LB:
-            JS_ASSERT(pn2->pn_op == JSOP_GETELEM);
+            JS_ASSERT(pn2->isOp(JSOP_GETELEM));
             if (!EmitElemOp(cx, pn2, callop ? JSOP_CALLELEM : JSOP_GETELEM, cg))
                 return JS_FALSE;
             break;
           case TOK_UNARYOP:
 #if JS_HAS_XML_SUPPORT
-            if (pn2->pn_op == JSOP_XMLNAME) {
+            if (pn2->isOp(JSOP_XMLNAME)) {
                 if (!EmitXMLName(cx, pn2, JSOP_CALLXMLNAME, cg))
                     return JS_FALSE;
                 callop = true;          /* suppress JSOP_PUSH after */
                 break;
             }
 #endif
             /* FALL THROUGH */
           default:
@@ -6785,20 +6776,20 @@ js_EmitTree(JSContext *cx, JSCodeGenerat
             if (!js_EmitTree(cx, cg, pn3))
                 return JS_FALSE;
         }
         cg->flags |= oldflags & TCF_IN_FOR_INIT;
         if (js_NewSrcNote2(cx, cg, SRC_PCBASE, CG_OFFSET(cg) - off) < 0)
             return JS_FALSE;
 
         argc = pn->pn_count - 1;
-        if (js_Emit3(cx, cg, PN_OP(pn), ARGC_HI(argc), ARGC_LO(argc)) < 0)
-            return JS_FALSE;
-        CheckTypeSet(cx, cg, PN_OP(pn));
-        if (PN_OP(pn) == JSOP_EVAL) {
+        if (js_Emit3(cx, cg, pn->getOp(), ARGC_HI(argc), ARGC_LO(argc)) < 0)
+            return JS_FALSE;
+        CheckTypeSet(cx, cg, pn->getOp());
+        if (pn->isOp(JSOP_EVAL)) {
             EMIT_UINT16_IMM_OP(JSOP_LINENO, pn->pn_pos.begin.lineno);
             if (EmitBlockChain(cx, cg) < 0)
                 return JS_FALSE;
         }
         if (pn->pn_xflags & PNX_SETCALL) {
             if (js_Emit1(cx, cg, JSOP_SETCALL) < 0)
                 return JS_FALSE;
         }
@@ -6816,17 +6807,17 @@ js_EmitTree(JSContext *cx, JSCodeGenerat
          * If this lexical scope is not for a catch block, let block or let
          * expression, or any kind of for loop (where the scope starts in the
          * head after the first part if for (;;), else in the body if for-in);
          * and if our container is top-level but not a function body, or else
          * a block statement; then emit a SRC_BRACE note.  All other container
          * statements get braces by default from the decompiler.
          */
         noteIndex = -1;
-        type = PN_TYPE(pn->expr());
+        type = pn->expr()->getKind();
         if (type != TOK_CATCH && type != TOK_LET && type != TOK_FOR &&
             (!(stmt = stmtInfo.down)
              ? !cg->inFunction()
              : stmt->type == STMT_BLOCK)) {
 #if defined DEBUG_brendan || defined DEBUG_mrbkap
             /* There must be no source note already output for the next op. */
             JS_ASSERT(CG_NOTE_COUNT(cg) == 0 ||
                       CG_LAST_NOTE_OFFSET(cg) != CG_OFFSET(cg) ||
@@ -6839,17 +6830,17 @@ js_EmitTree(JSContext *cx, JSCodeGenerat
 
         JS_ASSERT(CG_OFFSET(cg) == top);
         if (!EmitEnterBlock(cx, pn, cg))
             return JS_FALSE;
 
         if (!js_EmitTree(cx, cg, pn->pn_expr))
             return JS_FALSE;
 
-        op = PN_OP(pn);
+        op = pn->getOp();
         if (op == JSOP_LEAVEBLOCKEXPR) {
             if (js_NewSrcNote2(cx, cg, SRC_PCBASE, CG_OFFSET(cg) - top) < 0)
                 return JS_FALSE;
         } else {
             if (noteIndex >= 0 &&
                 !js_SetSrcNoteOffset(cx, cg, (uintN)noteIndex, 0,
                                      CG_OFFSET(cg) - top)) {
                 return JS_FALSE;
@@ -6872,33 +6863,33 @@ js_EmitTree(JSContext *cx, JSCodeGenerat
          *   let-statement:                         let (x = y) { ... }
          *   let-declaration in statement context:  let x = y;
          *   let-declaration in for-loop head:      for (let ...) ...
          *
          * Let-expressions and let-statements are represented as binary nodes
          * with their variable declarations on the left and the body on the
          * right.
          */
-        if (pn->pn_arity == PN_BINARY) {
+        if (pn->isArity(PN_BINARY)) {
             pn2 = pn->pn_right;
             pn = pn->pn_left;
         } else {
             pn2 = NULL;
         }
 
         /*
          * Non-null pn2 means that pn is the variable list from a let head.
          *
          * Use TempPopScope to evaluate the expressions in the enclosing scope.
          * This also causes the initializing assignments to be emitted in the
          * enclosing scope, but the assignment opcodes emitted here
          * (essentially just setlocal, though destructuring assignment uses
          * other additional opcodes) do not care about the block chain.
          */
-        JS_ASSERT(pn->pn_arity == PN_LIST);
+        JS_ASSERT(pn->isArity(PN_LIST));
         TempPopScope tps;
         bool popScope = pn2 || (cg->flags & TCF_IN_FOR_INIT);
         if (popScope && !tps.popBlock(cx, cg))
             return JS_FALSE;
         if (!EmitVariables(cx, cg, pn, pn2 != NULL, &noteIndex))
             return JS_FALSE;
         tmp = CG_OFFSET(cg);
         if (popScope && !tps.repushBlock(cx, cg))
@@ -6926,17 +6917,17 @@ js_EmitTree(JSContext *cx, JSCodeGenerat
          * under the array initialiser code generator for array comprehension
          * special casing.
          */
         if (!js_EmitTree(cx, cg, pn->pn_kid))
             return JS_FALSE;
         slot = AdjustBlockSlot(cx, cg, cg->arrayCompDepth);
         if (slot < 0)
             return JS_FALSE;
-        EMIT_UINT16_IMM_OP(PN_OP(pn), slot);
+        EMIT_UINT16_IMM_OP(pn->getOp(), slot);
         break;
       }
 #endif
 
       case TOK_RB:
 #if JS_HAS_GENERATORS
       case TOK_ARRAYCOMP:
 #endif
@@ -6949,17 +6940,17 @@ js_EmitTree(JSContext *cx, JSCodeGenerat
          * JSOP_SETELEM/JSOP_SETPROP would do.
          */
 #if JS_HAS_SHARP_VARS
         sharpnum = -1;
       do_emit_array:
 #endif
 
 #if JS_HAS_GENERATORS
-        if (pn->pn_type == TOK_ARRAYCOMP) {
+        if (pn->isKind(TOK_ARRAYCOMP)) {
             uintN saveDepth;
 
             if (!EmitNewInit(cx, cg, JSProto_Array, pn, sharpnum))
                 return JS_FALSE;
 
             /*
              * Pass the new array's stack index to the TOK_ARRAYPUSH case via
              * cg->arrayCompDepth, then simply traverse the TOK_FOR node and
@@ -6997,17 +6988,17 @@ js_EmitTree(JSContext *cx, JSCodeGenerat
             pc = CG_CODE(cg, off);
             SET_UINT24(pc, pn->pn_count);
         }
 
         pn2 = pn->pn_head;
         for (atomIndex = 0; pn2; atomIndex++, pn2 = pn2->pn_next) {
             if (!EmitNumberOp(cx, atomIndex, cg))
                 return JS_FALSE;
-            if (pn2->pn_type == TOK_COMMA && pn2->pn_arity == PN_NULLARY) {
+            if (pn2->isKind(TOK_COMMA) && pn2->isArity(PN_NULLARY)) {
                 if (js_Emit1(cx, cg, JSOP_HOLE) < 0)
                     return JS_FALSE;
             } else {
                 if (!js_EmitTree(cx, cg, pn2))
                     return JS_FALSE;
             }
             if (js_Emit1(cx, cg, JSOP_INITELEM) < 0)
                 return JS_FALSE;
@@ -7070,55 +7061,55 @@ js_EmitTree(JSContext *cx, JSCodeGenerat
             if (!obj)
                 return JS_FALSE;
         }
 
         uintN methodInits = 0, slowMethodInits = 0;
         for (pn2 = pn->pn_head; pn2; pn2 = pn2->pn_next) {
             /* Emit an index for t[2] for later consumption by JSOP_INITELEM. */
             pn3 = pn2->pn_left;
-            if (pn3->pn_type == TOK_NUMBER) {
+            if (pn3->isKind(TOK_NUMBER)) {
                 if (!EmitNumberOp(cx, pn3->pn_dval, cg))
                     return JS_FALSE;
             }
 
             /* Emit code for the property initializer. */
             if (!js_EmitTree(cx, cg, pn2->pn_right))
                 return JS_FALSE;
 
-            op = PN_OP(pn2);
+            op = pn2->getOp();
             if (op == JSOP_GETTER || op == JSOP_SETTER) {
                 obj = NULL;
                 if (js_Emit1(cx, cg, op) < 0)
                     return JS_FALSE;
             }
 
             /* Annotate JSOP_INITELEM so we decompile 2:c and not just c. */
-            if (pn3->pn_type == TOK_NUMBER) {
+            if (pn3->isKind(TOK_NUMBER)) {
                 obj = NULL;
                 if (js_NewSrcNote(cx, cg, SRC_INITPROP) < 0)
                     return JS_FALSE;
                 if (js_Emit1(cx, cg, JSOP_INITELEM) < 0)
                     return JS_FALSE;
             } else {
-                JS_ASSERT(pn3->pn_type == TOK_NAME ||
-                          pn3->pn_type == TOK_STRING);
+                JS_ASSERT(pn3->isKind(TOK_NAME) ||
+                          pn3->isKind(TOK_STRING));
                 jsatomid index;
                 if (!cg->makeAtomIndex(pn3->pn_atom, &index))
                     return JS_FALSE;
 
                 /* Check whether we can optimize to JSOP_INITMETHOD. */
                 JSParseNode *init = pn2->pn_right;
-                bool lambda = PN_OP(init) == JSOP_LAMBDA;
+                bool lambda = init->isOp(JSOP_LAMBDA);
                 if (lambda)
                     ++methodInits;
                 if (op == JSOP_INITPROP && lambda && init->pn_funbox->joinable()) {
                     obj = NULL;
                     op = JSOP_INITMETHOD;
-                    pn2->pn_op = uint8(op);
+                    pn2->setOp(op);
                 } else {
                     /*
                      * Disable NEWOBJECT on initializers that set __proto__, which has
                      * a non-standard setter on objects.
                      */
                     if (pn3->pn_atom == cx->runtime->atomState.protoAtom)
                         obj = NULL;
                     op = JSOP_INITPROP;
@@ -7165,23 +7156,23 @@ js_EmitTree(JSContext *cx, JSCodeGenerat
         break;
       }
 
 #if JS_HAS_SHARP_VARS
       case TOK_DEFSHARP:
         JS_ASSERT(cg->hasSharps());
         sharpnum = pn->pn_num;
         pn = pn->pn_kid;
-        if (pn->pn_type == TOK_RB)
+        if (pn->isKind(TOK_RB))
             goto do_emit_array;
 # if JS_HAS_GENERATORS
-        if (pn->pn_type == TOK_ARRAYCOMP)
+        if (pn->isKind(TOK_ARRAYCOMP))
             goto do_emit_array;
 # endif
-        if (pn->pn_type == TOK_RC)
+        if (pn->isKind(TOK_RC))
             goto do_emit_object;
 
         if (!js_EmitTree(cx, cg, pn))
             return JS_FALSE;
         EMIT_UINT16PAIR_IMM_OP(JSOP_DEFSHARP, cg->sharpSlotBase, (jsatomid) sharpnum);
         break;
 
       case TOK_USESHARP:
@@ -7191,95 +7182,95 @@ js_EmitTree(JSContext *cx, JSCodeGenerat
 #endif /* JS_HAS_SHARP_VARS */
 
       case TOK_NAME:
         /*
          * Cope with a left-over function definition that was replaced by a use
          * of a later function definition of the same name. See FunctionDef and
          * MakeDefIntoUse in jsparse.cpp.
          */
-        if (pn->pn_op == JSOP_NOP)
+        if (pn->isOp(JSOP_NOP))
             break;
         if (!EmitNameOp(cx, cg, pn, JS_FALSE))
             return JS_FALSE;
         break;
 
 #if JS_HAS_XML_SUPPORT
       case TOK_XMLATTR:
       case TOK_XMLSPACE:
       case TOK_XMLTEXT:
       case TOK_XMLCDATA:
       case TOK_XMLCOMMENT:
 #endif
       case TOK_STRING:
-        ok = EmitAtomOp(cx, pn, PN_OP(pn), cg);
+        ok = EmitAtomOp(cx, pn, pn->getOp(), cg);
         break;
 
       case TOK_NUMBER:
         ok = EmitNumberOp(cx, pn->pn_dval, cg);
         break;
 
       case TOK_REGEXP: {
-        JS_ASSERT(pn->pn_op == JSOP_REGEXP);
+        JS_ASSERT(pn->isOp(JSOP_REGEXP));
         ok = EmitIndexOp(cx, JSOP_REGEXP,
                          cg->regexpList.index(pn->pn_objbox),
                          cg);
         break;
       }
 
 #if JS_HAS_XML_SUPPORT
       case TOK_ANYNAME:
 #endif
       case TOK_PRIMARY:
-        if (js_Emit1(cx, cg, PN_OP(pn)) < 0)
+        if (js_Emit1(cx, cg, pn->getOp()) < 0)
             return JS_FALSE;
         break;
 
       case TOK_DEBUGGER:
         if (js_Emit1(cx, cg, JSOP_DEBUGGER) < 0)
             return JS_FALSE;
         break;
 
 #if JS_HAS_XML_SUPPORT
       case TOK_XMLELEM:
       case TOK_XMLLIST:
-        JS_ASSERT(PN_TYPE(pn) == TOK_XMLLIST || pn->pn_count != 0);
-        switch (pn->pn_head ? PN_TYPE(pn->pn_head) : TOK_XMLLIST) {
+        JS_ASSERT(pn->isKind(TOK_XMLLIST) || pn->pn_count != 0);
+        switch (pn->pn_head ? pn->pn_head->getKind() : TOK_XMLLIST) {
           case TOK_XMLETAGO:
             JS_ASSERT(0);
             /* FALL THROUGH */
           case TOK_XMLPTAGC:
           case TOK_XMLSTAGO:
             break;
           default:
             if (js_Emit1(cx, cg, JSOP_STARTXML) < 0)
                 return JS_FALSE;
         }
 
         for (pn2 = pn->pn_head; pn2; pn2 = pn2->pn_next) {
-            if (pn2->pn_type == TOK_LC &&
+            if (pn2->isKind(TOK_LC) &&
                 js_Emit1(cx, cg, JSOP_STARTXMLEXPR) < 0) {
                 return JS_FALSE;
             }
             if (!js_EmitTree(cx, cg, pn2))
                 return JS_FALSE;
             if (pn2 != pn->pn_head && js_Emit1(cx, cg, JSOP_ADD) < 0)
                 return JS_FALSE;
         }
 
         if (pn->pn_xflags & PNX_XMLROOT) {
             if (pn->pn_count == 0) {
-                JS_ASSERT(pn->pn_type == TOK_XMLLIST);
+                JS_ASSERT(pn->isKind(TOK_XMLLIST));
                 atom = cx->runtime->atomState.emptyAtom;
                 jsatomid index;
                 if (!cg->makeAtomIndex(atom, &index))
                     return JS_FALSE;
                 EMIT_INDEX_OP(JSOP_STRING, index);
             }
-            if (js_Emit1(cx, cg, PN_OP(pn)) < 0)
+            if (js_Emit1(cx, cg, pn->getOp()) < 0)
                 return JS_FALSE;
         }
 #ifdef DEBUG
         else
             JS_ASSERT(pn->pn_count != 0);
 #endif
         break;
 
@@ -7289,83 +7280,83 @@ js_EmitTree(JSContext *cx, JSCodeGenerat
       {
         uint32 i;
 
         if (js_Emit1(cx, cg, JSOP_STARTXML) < 0)
             return JS_FALSE;
 
         {
             jsatomid index;
-            JSAtom *tmp = (pn->pn_type == TOK_XMLETAGO) ? cx->runtime->atomState.etagoAtom
-                                                        : cx->runtime->atomState.stagoAtom;
+            JSAtom *tmp = (pn->isKind(TOK_XMLETAGO)) ? cx->runtime->atomState.etagoAtom
+                                                     : cx->runtime->atomState.stagoAtom;
             if (!cg->makeAtomIndex(tmp, &index))
                 return JS_FALSE;
             EMIT_INDEX_OP(JSOP_STRING, index);
         }
 
         JS_ASSERT(pn->pn_count != 0);
         pn2 = pn->pn_head;
-        if (pn2->pn_type == TOK_LC && js_Emit1(cx, cg, JSOP_STARTXMLEXPR) < 0)
+        if (pn2->isKind(TOK_LC) && js_Emit1(cx, cg, JSOP_STARTXMLEXPR) < 0)
             return JS_FALSE;
         if (!js_EmitTree(cx, cg, pn2))
             return JS_FALSE;
         if (js_Emit1(cx, cg, JSOP_ADD) < 0)
             return JS_FALSE;
 
         for (pn2 = pn2->pn_next, i = 0; pn2; pn2 = pn2->pn_next, i++) {
-            if (pn2->pn_type == TOK_LC &&
+            if (pn2->isKind(TOK_LC) &&
                 js_Emit1(cx, cg, JSOP_STARTXMLEXPR) < 0) {
                 return JS_FALSE;
             }
             if (!js_EmitTree(cx, cg, pn2))
                 return JS_FALSE;
-            if ((i & 1) && pn2->pn_type == TOK_LC) {
+            if ((i & 1) && pn2->isKind(TOK_LC)) {
                 if (js_Emit1(cx, cg, JSOP_TOATTRVAL) < 0)
                     return JS_FALSE;
             }
             if (js_Emit1(cx, cg,
                          (i & 1) ? JSOP_ADDATTRVAL : JSOP_ADDATTRNAME) < 0) {
                 return JS_FALSE;
             }
         }
 
         {
             jsatomid index;
-            JSAtom *tmp = (pn->pn_type == TOK_XMLPTAGC) ? cx->runtime->atomState.ptagcAtom
-                                                        : cx->runtime->atomState.tagcAtom;
+            JSAtom *tmp = (pn->isKind(TOK_XMLPTAGC)) ? cx->runtime->atomState.ptagcAtom
+                                                     : cx->runtime->atomState.tagcAtom;
             if (!cg->makeAtomIndex(tmp, &index))
                 return JS_FALSE;
             EMIT_INDEX_OP(JSOP_STRING, index);
         }
         if (js_Emit1(cx, cg, JSOP_ADD) < 0)
             return JS_FALSE;
 
-        if ((pn->pn_xflags & PNX_XMLROOT) && js_Emit1(cx, cg, PN_OP(pn)) < 0)
+        if ((pn->pn_xflags & PNX_XMLROOT) && js_Emit1(cx, cg, pn->getOp()) < 0)
             return JS_FALSE;
         break;
       }
 
       case TOK_XMLNAME:
-        if (pn->pn_arity == PN_LIST) {
+        if (pn->isArity(PN_LIST)) {
             JS_ASSERT(pn->pn_count != 0);
             for (pn2 = pn->pn_head; pn2; pn2 = pn2->pn_next) {
-                if (pn2->pn_type == TOK_LC &&
+                if (pn2->isKind(TOK_LC) &&
                     js_Emit1(cx, cg, JSOP_STARTXMLEXPR) < 0) {
                     return JS_FALSE;
                 }
                 if (!js_EmitTree(cx, cg, pn2))
                     return JS_FALSE;
                 if (pn2 != pn->pn_head && js_Emit1(cx, cg, JSOP_ADD) < 0)
                     return JS_FALSE;
             }
         } else {
-            JS_ASSERT(pn->pn_arity == PN_NULLARY);
-            ok = (pn->pn_op == JSOP_OBJECT)
-                 ? EmitObjectOp(cx, pn->pn_objbox, PN_OP(pn), cg)
-                 : EmitAtomOp(cx, pn, PN_OP(pn), cg);
+            JS_ASSERT(pn->isArity(PN_NULLARY));
+            ok = pn->isOp(JSOP_OBJECT)
+                 ? EmitObjectOp(cx, pn->pn_objbox, pn->getOp(), cg)
+                 : EmitAtomOp(cx, pn, pn->getOp(), cg);
         }
         break;
 
       case TOK_XMLPI: {
         jsatomid index;
         if (!cg->makeAtomIndex(pn->pn_atom2, &index))
             return false;
         if (!EmitIndexOp(cx, JSOP_QNAMEPART, index, cg))
--- a/js/src/jsinterp.cpp
+++ b/js/src/jsinterp.cpp
@@ -3061,39 +3061,21 @@ END_CASE(JSOP_MUL)
 BEGIN_CASE(JSOP_DIV)
 {
     Value rval = regs.sp[-1];
     Value lval = regs.sp[-2];
     double d1, d2;
     if (!ToNumber(cx, lval, &d1) || !ToNumber(cx, rval, &d2))
         goto error;
     regs.sp--;
-    if (d2 == 0) {
-        const Value *vp;
-#ifdef XP_WIN
-        /* XXX MSVC miscompiles such that (NaN == 0) */
-        if (JSDOUBLE_IS_NaN(d2))
-            vp = &rt->NaNValue;
-        else
-#endif
-        if (d1 == 0 || JSDOUBLE_IS_NaN(d1))
-            vp = &rt->NaNValue;
-        else if (JSDOUBLE_IS_NEG(d1) != JSDOUBLE_IS_NEG(d2))
-            vp = &rt->negativeInfinityValue;
-        else
-            vp = &rt->positiveInfinityValue;
-        regs.sp[-1] = *vp;
+
+    regs.sp[-1].setNumber(NumberDiv(d1, d2));
+
+    if (d2 == 0 || (regs.sp[-1].isDouble() && !(lval.isDouble() || rval.isDouble())))
         TypeScript::MonitorOverflow(cx, script, regs.pc);
-    } else {
-        d1 /= d2;
-        if (!regs.sp[-1].setNumber(d1) &&
-            !(lval.isDouble() || rval.isDouble())) {
-            TypeScript::MonitorOverflow(cx, script, regs.pc);
-        }
-    }
 }
 END_CASE(JSOP_DIV)
 
 BEGIN_CASE(JSOP_MOD)
 {
     Value &lref = regs.sp[-2];
     Value &rref = regs.sp[-1];
     int32_t l, r;
--- a/js/src/jslibmath.h
+++ b/js/src/jslibmath.h
@@ -37,19 +37,17 @@
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 #ifndef _LIBMATH_H
 #define _LIBMATH_H
 
 #include <math.h>
-#ifdef XP_WIN
-# include "jsnum.h"
-#endif
+#include "jsnum.h"
 
 /*
  * Use system provided math routines.
  */
 
 /* The right copysign function is not always named the same thing. */
 #if __GNUC__ >= 4 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4)
 #define js_copysign __builtin_copysign
@@ -83,10 +81,32 @@ js_fmod(double d, double d2)
     if ((JSDOUBLE_IS_FINITE(d) && JSDOUBLE_IS_INFINITE(d2)) ||
         (d == 0 && JSDOUBLE_IS_FINITE(d2))) {
         return d;
     }
 #endif
     return fmod(d, d2);
 }
 
+namespace js {
+
+inline double
+NumberDiv(double a, double b) {
+    if (b == 0) {
+        if (a == 0 || JSDOUBLE_IS_NaN(a) 
+#ifdef XP_WIN
+            || JSDOUBLE_IS_NaN(a) /* XXX MSVC miscompiles such that (NaN == 0) */
+#endif
+        )
+            return js_NaN;    
+        else if (JSDOUBLE_IS_NEG(a) != JSDOUBLE_IS_NEG(b))
+            return js_NegativeInfinity;
+        else
+            return js_PositiveInfinity; 
+    }
+
+    return a / b;
+}
+
+}
+
 #endif /* _LIBMATH_H */
 
--- a/js/src/jsparse.cpp
+++ b/js/src/jsparse.cpp
@@ -129,20 +129,20 @@ JS_STATIC_ASSERT(pn_offsetof(pn_u.name.a
         }                                                                                   \
     JS_END_MACRO
 #define MUST_MATCH_TOKEN(tt, errno) MUST_MATCH_TOKEN_WITH_FLAGS(tt, errno, 0)
 
 void
 JSParseNode::become(JSParseNode *pn2)
 {
     JS_ASSERT(!pn_defn);
-    JS_ASSERT(!pn2->pn_defn);
+    JS_ASSERT(!pn2->isDefn());
 
     JS_ASSERT(!pn_used);
-    if (pn2->pn_used) {
+    if (pn2->isUsed()) {
         JSParseNode **pnup = &pn2->pn_lexdef->dn_uses;
         while (*pnup != pn2)
             pnup = &(*pnup)->pn_link;
         *pnup = this;
         pn_link = pn2->pn_link;
         pn_used = true;
         pn2->pn_link = NULL;
         pn2->pn_used = false;
@@ -153,17 +153,17 @@ JSParseNode::become(JSParseNode *pn2)
     pn_arity = pn2->pn_arity;
     pn_parens = pn2->pn_parens;
     pn_u = pn2->pn_u;
 
     /*
      * If any pointers are pointing to pn2, change them to point to this
      * instead, since pn2 will be cleared and probably recycled.
      */
-    if (PN_TYPE(this) == TOK_FUNCTION && pn_arity == PN_FUNC) {
+    if (this->isKind(TOK_FUNCTION) && isArity(PN_FUNC)) {
         /* Function node: fix up the pn_funbox->node back-pointer. */
         JS_ASSERT(pn_funbox->node == pn2);
         pn_funbox->node = this;
     } else if (pn_arity == PN_LIST && !pn_head) {
         /* Empty list: fix up the pn_tail pointer. */
         JS_ASSERT(pn_count == 0);
         JS_ASSERT(pn_tail == &pn2->pn_head);
         pn_tail = &pn_head;
@@ -171,17 +171,17 @@ JSParseNode::become(JSParseNode *pn2)
 
     pn2->clear();
 }
 
 void
 JSParseNode::clear()
 {
     pn_type = TOK_EOF;
-    pn_op = JSOP_NOP;
+    setOp(JSOP_NOP);
     pn_used = pn_defn = false;
     pn_arity = PN_NULLARY;
     pn_parens = false;
 }
 
 Parser::Parser(JSContext *cx, JSPrincipals *prin, StackFrame *cfp, bool foldConstants)
   : js::AutoGCRooter(cx, PARSER),
     context(cx),
@@ -369,20 +369,20 @@ AddNodeToFreeList(JSParseNode *pn, js::P
     JS_ASSERT(pn != parser->nodeList);
 
     /* 
      * It's too hard to clear these nodes from the AtomDefnMaps, etc. that
      * hold references to them, so we never free them. It's our caller's job to
      * recognize and process these, since their children do need to be dealt
      * with.
      */
-    JS_ASSERT(!pn->pn_used);
-    JS_ASSERT(!pn->pn_defn);
-
-    if (pn->pn_arity == PN_NAMESET && pn->pn_names.hasMap())
+    JS_ASSERT(!pn->isUsed());
+    JS_ASSERT(!pn->isDefn());
+
+    if (pn->isArity(PN_NAMESET) && pn->pn_names.hasMap())
         pn->pn_names.releaseMap(parser->context);
 
 #ifdef DEBUG
     /* Poison the node, to catch attempts to use it without initializing it. */
     memset(pn, 0xab, sizeof(*pn));
 #endif
 
     pn->pn_next = parser->nodeList;
@@ -446,17 +446,17 @@ Parser::cleanFunctionList(JSFunctionBox 
         } else {
             /* The function is still live. */
 
             /* First, remove nodes for deleted functions from our methods list. */
             {
                 JSParseNode **methodLink = &box->methods;
                 while (JSParseNode *method = *methodLink) {
                     /* Method nodes are never rewritten in place to be other kinds of nodes. */
-                    JS_ASSERT(method->pn_arity == PN_FUNC);
+                    JS_ASSERT(method->isArity(PN_FUNC));
                     if (!method->pn_funbox) {
                         /* Deleted: drop the node, and stay on this link. */
                         *methodLink = method->pn_link;
                     } else {
                         /* Live: keep the node, and move to the next link. */
                         methodLink = &method->pn_link;
                     }
                 }
@@ -515,17 +515,17 @@ class NodeStack {
  * nodes, and all function nodes; see comments for
  * js::Parser::cleanFunctionList). Some callers want to free |pn|; others
  * (PrepareNodeForMutation) don't care about |pn|, and just need to take care of
  * its children.
  */
 static bool
 PushNodeChildren(JSParseNode *pn, NodeStack *stack)
 {
-    switch (pn->pn_arity) {
+    switch (pn->getArity()) {
       case PN_FUNC:
         /*
          * Function nodes are linked into the function box tree, and may
          * appear on method lists. Both of those lists are singly-linked,
          * so trying to update them now could result in quadratic behavior
          * when recycling trees containing many functions; and the lists
          * can be very long. So we put off cleaning the lists up until just
          * before function analysis, when we call
@@ -553,21 +553,21 @@ PushNodeChildren(JSParseNode *pn, NodeSt
          * them, so clean up the pointers to avoid dangling references. The
          * top-level decls table carries references to them that later
          * iterations through the compileScript loop may find, so they need
          * to be neat.
          *
          * pn_expr and pn_lexdef share storage; the latter isn't an owning
          * reference.
          */
-        if (!pn->pn_used) {
+        if (!pn->isUsed()) {
             stack->pushUnlessNull(pn->pn_expr);
             pn->pn_expr = NULL;
         }
-        return !pn->pn_used && !pn->pn_defn;
+        return !pn->isUsed() && !pn->isDefn();
 
       case PN_LIST:
         stack->pushList(pn);
         break;
       case PN_TERNARY:
         stack->pushUnlessNull(pn->pn_kid1);
         stack->pushUnlessNull(pn->pn_kid2);
         stack->pushUnlessNull(pn->pn_kid3);
@@ -580,32 +580,34 @@ PushNodeChildren(JSParseNode *pn, NodeSt
       case PN_UNARY:
         stack->pushUnlessNull(pn->pn_kid);
         break;
       case PN_NULLARY:
         /* 
          * E4X function namespace nodes are PN_NULLARY, but can appear on use
          * lists.
          */
-        return !pn->pn_used && !pn->pn_defn;
+        return !pn->isUsed() && !pn->isDefn();
+      default:
+        ;
     }
 
     return true;
 }
 
 /*
  * Prepare |pn| to be mutated in place into a new kind of node. Recycle all
  * |pn|'s recyclable children (but not |pn| itself!), and disconnect it from
  * metadata structures (the function box tree).
  */
 static void
 PrepareNodeForMutation(JSParseNode *pn, JSTreeContext *tc)
 {
-    if (pn->pn_arity != PN_NULLARY) {
-        if (pn->pn_arity == PN_FUNC) {
+    if (!pn->isArity(PN_NULLARY)) {
+        if (pn->isArity(PN_FUNC)) {
             /*
              * Since this node could be turned into anything, we can't
              * ensure it won't be subsequently recycled, so we must
              * disconnect it from the funbox tree entirely.
              *
              * Note that pn_funbox may legitimately be NULL. functionDef
              * applies MakeDefIntoUse to definition nodes, which can come
              * from prior iterations of the big loop in compileScript. In
@@ -679,17 +681,18 @@ NewOrRecycledNode(JSTreeContext *tc)
         JS_ARENA_ALLOCATE_TYPE(pn, JSParseNode, &cx->tempPool);
         if (!pn)
             js_ReportOutOfMemory(cx);
     } else {
         tc->parser->nodeList = pn->pn_next;
     }
 
     if (pn) {
-        pn->pn_used = pn->pn_defn = false;
+        pn->setUsed(false);
+        pn->setDefn(false);
         memset(&pn->pn_u, 0, sizeof pn->pn_u);
         pn->pn_next = NULL;
     }
     return pn;
 }
 
 /* used only by static create methods of subclasses */
 
@@ -720,57 +723,57 @@ JSParseNode::newBinaryOrAppend(TokenKind
 
     if (!left || !right)
         return NULL;
 
     /*
      * Flatten a left-associative (left-heavy) tree of a given operator into
      * a list, to reduce js_FoldConstants and js_EmitTree recursion.
      */
-    if (PN_TYPE(left) == tt &&
-        PN_OP(left) == op &&
+    if (left->isKind(tt) &&
+        left->isOp(op) &&
         (js_CodeSpec[op].format & JOF_LEFTASSOC)) {
         if (left->pn_arity != PN_LIST) {
             pn1 = left->pn_left, pn2 = left->pn_right;
-            left->pn_arity = PN_LIST;
+            left->setArity(PN_LIST);
             left->pn_parens = false;
             left->initList(pn1);
             left->append(pn2);
             if (tt == TOK_PLUS) {
-                if (pn1->pn_type == TOK_STRING)
+                if (pn1->isKind(TOK_STRING))
                     left->pn_xflags |= PNX_STRCAT;
-                else if (pn1->pn_type != TOK_NUMBER)
+                else if (!pn1->isKind(TOK_NUMBER))
                     left->pn_xflags |= PNX_CANTFOLD;
-                if (pn2->pn_type == TOK_STRING)
+                if (pn2->isKind(TOK_STRING))
                     left->pn_xflags |= PNX_STRCAT;
-                else if (pn2->pn_type != TOK_NUMBER)
+                else if (!pn2->isKind(TOK_NUMBER))
                     left->pn_xflags |= PNX_CANTFOLD;
             }
         }
         left->append(right);
         left->pn_pos.end = right->pn_pos.end;
         if (tt == TOK_PLUS) {
-            if (right->pn_type == TOK_STRING)
+            if (right->isKind(TOK_STRING))
                 left->pn_xflags |= PNX_STRCAT;
-            else if (right->pn_type != TOK_NUMBER)
+            else if (!right->isKind(TOK_NUMBER))
                 left->pn_xflags |= PNX_CANTFOLD;
         }
         return left;
     }
 
     /*
      * Fold constant addition immediately, to conserve node space and, what's
      * more, so js_FoldConstants never sees mixed addition and concatenation
      * operations with more than one leading non-string operand in a PN_LIST
      * generated for expressions such as 1 + 2 + "pt" (which should evaluate
      * to "3pt", not "12pt").
      */
     if (tt == TOK_PLUS &&
-        left->pn_type == TOK_NUMBER &&
-        right->pn_type == TOK_NUMBER &&
+        left->isKind(TOK_NUMBER) &&
+        right->isKind(TOK_NUMBER) &&
         tc->parser->foldConstants) {
         left->pn_dval += right->pn_dval;
         left->pn_pos.end = right->pn_pos.end;
         RecycleTree(right, tc);
         return left;
     }
 
     pn = NewOrRecycledNode(tc);
@@ -824,17 +827,17 @@ GenerateBlockId(JSTreeContext *tc, uint3
     return true;
 }
 
 static bool
 GenerateBlockIdForStmtNode(JSParseNode *pn, JSTreeContext *tc)
 {
     JS_ASSERT(tc->topStmt);
     JS_ASSERT(STMT_MAYBE_SCOPE(tc->topStmt));
-    JS_ASSERT(pn->pn_type == TOK_LC || pn->pn_type == TOK_LEXICALSCOPE);
+    JS_ASSERT(pn->isKind(TOK_LC) || pn->isKind(TOK_LEXICALSCOPE));
     if (!GenerateBlockId(tc, tc->topStmt->blockid))
         return false;
     pn->pn_blockid = tc->topStmt->blockid;
     return true;
 }
 
 /*
  * Parse a top-level JS script.
@@ -1034,21 +1037,18 @@ Compiler::compileScript(JSContext *cx, J
         if (!parser.analyzeFunctions(&cg))
             goto out;
         cg.functionList = NULL;
 
         if (!js_EmitTree(cx, &cg, pn))
             goto out;
 
 #if JS_HAS_XML_SUPPORT
-        if (PN_TYPE(pn) != TOK_SEMI ||
-            !pn->pn_kid ||
-            !TreeTypeIsXML(PN_TYPE(pn->pn_kid))) {
+        if (!pn->isKind(TOK_SEMI) || !pn->pn_kid || !TreeTypeIsXML(pn->pn_kid->getKind()))
             onlyXML = false;
-        }
 #endif
         RecycleTree(pn, &cg);
     }
 
 #if JS_HAS_XML_SUPPORT
     /*
      * Prevent XML data theft via <script src="http://victim.com/foo.xml">.
      * For background, see:
@@ -1236,67 +1236,67 @@ Compiler::defineGlobals(JSContext *cx, G
 #define ENDS_IN_BREAK   2
 
 static int
 HasFinalReturn(JSParseNode *pn)
 {
     JSParseNode *pn2, *pn3;
     uintN rv, rv2, hasDefault;
 
-    switch (pn->pn_type) {
+    switch (pn->getKind()) {
       case TOK_LC:
         if (!pn->pn_head)
             return ENDS_IN_OTHER;
         return HasFinalReturn(pn->last());
 
       case TOK_IF:
         if (!pn->pn_kid3)
             return ENDS_IN_OTHER;
         return HasFinalReturn(pn->pn_kid2) & HasFinalReturn(pn->pn_kid3);
 
       case TOK_WHILE:
         pn2 = pn->pn_left;
-        if (pn2->pn_type == TOK_PRIMARY && pn2->pn_op == JSOP_TRUE)
+        if (pn2->isKind(TOK_PRIMARY) && pn2->isOp(JSOP_TRUE))
             return ENDS_IN_RETURN;
-        if (pn2->pn_type == TOK_NUMBER && pn2->pn_dval)
+        if (pn2->isKind(TOK_NUMBER) && pn2->pn_dval)
             return ENDS_IN_RETURN;
         return ENDS_IN_OTHER;
 
       case TOK_DO:
         pn2 = pn->pn_right;
-        if (pn2->pn_type == TOK_PRIMARY) {
-            if (pn2->pn_op == JSOP_FALSE)
+        if (pn2->isKind(TOK_PRIMARY)) {
+            if (pn2->isOp(JSOP_FALSE))
                 return HasFinalReturn(pn->pn_left);
-            if (pn2->pn_op == JSOP_TRUE)
+            if (pn2->isOp(JSOP_TRUE))
                 return ENDS_IN_RETURN;
         }
-        if (pn2->pn_type == TOK_NUMBER) {
+        if (pn2->isKind(TOK_NUMBER)) {
             if (pn2->pn_dval == 0)
                 return HasFinalReturn(pn->pn_left);
             return ENDS_IN_RETURN;
         }
         return ENDS_IN_OTHER;
 
       case TOK_FOR:
         pn2 = pn->pn_left;
-        if (pn2->pn_arity == PN_TERNARY && !pn2->pn_kid2)
+        if (pn2->isArity(PN_TERNARY) && !pn2->pn_kid2)
             return ENDS_IN_RETURN;
         return ENDS_IN_OTHER;
 
       case TOK_SWITCH:
         rv = ENDS_IN_RETURN;
         hasDefault = ENDS_IN_OTHER;
         pn2 = pn->pn_right;
-        if (pn2->pn_type == TOK_LEXICALSCOPE)
+        if (pn2->isKind(TOK_LEXICALSCOPE))
             pn2 = pn2->expr();
         for (pn2 = pn2->pn_head; rv && pn2; pn2 = pn2->pn_next) {
-            if (pn2->pn_type == TOK_DEFAULT)
+            if (pn2->isKind(TOK_DEFAULT))
                 hasDefault = ENDS_IN_RETURN;
             pn3 = pn2->pn_right;
-            JS_ASSERT(pn3->pn_type == TOK_LC);
+            JS_ASSERT(pn3->isKind(TOK_LC));
             if (pn3->pn_head) {
                 rv2 = HasFinalReturn(pn3->last());
                 if (rv2 == ENDS_IN_OTHER && pn2->pn_next)
                     /* Falling through to next case or default. */;
                 else
                     rv &= rv2;
             }
         }
@@ -1326,29 +1326,29 @@ HasFinalReturn(JSParseNode *pn)
             rv = HasFinalReturn(pn->pn_kid3);
             if (rv == ENDS_IN_RETURN)
                 return rv;
         }
 
         /* Else check the try block and any and all catch statements. */
         rv = HasFinalReturn(pn->pn_kid1);
         if (pn->pn_kid2) {
-            JS_ASSERT(pn->pn_kid2->pn_arity == PN_LIST);
+            JS_ASSERT(pn->pn_kid2->isArity(PN_LIST));
             for (pn2 = pn->pn_kid2->pn_head; pn2; pn2 = pn2->pn_next)
                 rv &= HasFinalReturn(pn2);
         }
         return rv;
 
       case TOK_CATCH:
         /* Check this catch block's body. */
         return HasFinalReturn(pn->pn_kid3);
 
       case TOK_LET:
         /* Non-binary let statements are let declarations. */
-        if (pn->pn_arity != PN_BINARY)
+        if (!pn->isArity(PN_BINARY))
             return ENDS_IN_OTHER;
         return HasFinalReturn(pn->pn_right);
 
       default:
         return ENDS_IN_OTHER;
     }
 }
 
@@ -1377,17 +1377,17 @@ CheckFinalReturn(JSContext *cx, JSTreeCo
 
 /*
  * Check that it is permitted to assign to lhs.  Strict mode code may not
  * assign to 'eval' or 'arguments'.
  */
 bool
 CheckStrictAssignment(JSContext *cx, JSTreeContext *tc, JSParseNode *lhs)
 {
-    if (tc->needStrictChecks() && lhs->pn_type == TOK_NAME) {
+    if (tc->needStrictChecks() && lhs->isKind(TOK_NAME)) {
         JSAtom *atom = lhs->pn_atom;
         JSAtomState *atomState = &cx->runtime->atomState;
         if (atom == atomState->evalAtom || atom == atomState->argumentsAtom) {
             JSAutoByteString name;
             if (!js_AtomToPrintableString(cx, atom, &name) ||
                 !ReportStrictModeError(cx, TS(tc->parser), tc, lhs, JSMSG_DEPRECATED_ASSIGN,
                                        name.ptr())) {
                 return false;
@@ -1517,18 +1517,18 @@ Parser::functionBody()
                 pn = NULL;
             } else {
                 if (tc->flags & TCF_FUN_IS_GENERATOR) {
                     ReportBadReturn(context, tc, pn, JSREPORT_ERROR,
                                     JSMSG_BAD_GENERATOR_RETURN,
                                     JSMSG_BAD_ANON_GENERATOR_RETURN);
                     pn = NULL;
                 } else {
-                    pn->pn_type = TOK_RETURN;
-                    pn->pn_op = JSOP_RETURN;
+                    pn->setKind(TOK_RETURN);
+                    pn->setOp(JSOP_RETURN);
                     pn->pn_pos.end = pn->pn_kid->pn_pos.end;
                 }
             }
         }
     }
 #else
     pn = statements();
 #endif
@@ -1551,28 +1551,28 @@ Parser::functionBody()
 /* Create a placeholder JSDefinition node for |atom|. */
 static JSDefinition *
 MakePlaceholder(JSParseNode *pn, JSTreeContext *tc)
 {
     JSDefinition *dn = (JSDefinition *) NameNode::create(pn->pn_atom, tc);
     if (!dn)
         return NULL;
 
-    dn->pn_type = TOK_NAME;
-    dn->pn_op = JSOP_NOP;
-    dn->pn_defn = true;
+    dn->setKind(TOK_NAME);
+    dn->setOp(JSOP_NOP);
+    dn->setDefn(true);
     dn->pn_dflags |= PND_PLACEHOLDER;
     return dn;
 }
 
 static bool
 Define(JSParseNode *pn, JSAtom *atom, JSTreeContext *tc, bool let = false)
 {
-    JS_ASSERT(!pn->pn_used);
-    JS_ASSERT_IF(pn->pn_defn, pn->isPlaceholder());
+    JS_ASSERT(!pn->isUsed());
+    JS_ASSERT_IF(pn->isDefn(), pn->isPlaceholder());
 
     bool foundLexdep = false;
     JSDefinition *dn = NULL;
 
     if (let)
         dn = tc->decls.lookupFirst(atom);
 
     if (!dn) {
@@ -1581,17 +1581,17 @@ Define(JSParseNode *pn, JSAtom *atom, JS
     }
 
     if (dn && dn != pn) {
         JSParseNode **pnup = &dn->dn_uses;
         JSParseNode *pnu;
         uintN start = let ? pn->pn_blockid : tc->bodyid;
 
         while ((pnu = *pnup) != NULL && pnu->pn_blockid >= start) {
-            JS_ASSERT(pnu->pn_used);
+            JS_ASSERT(pnu->isUsed());
             pnu->pn_lexdef = (JSDefinition *) pn;
             pn->pn_dflags |= pnu->pn_dflags & PND_USE2DEF_FLAGS;
             pnup = &pnu->pn_link;
         }
 
         if (pnu != dn->dn_uses) {
             *pnup = pn->dn_uses;
             pn->dn_uses = dn->dn_uses;
@@ -1601,76 +1601,77 @@ Define(JSParseNode *pn, JSAtom *atom, JS
                 tc->lexdeps->remove(atom);
         }
     }
 
     JSDefinition *toAdd = (JSDefinition *) pn;
     bool ok = let ? tc->decls.addShadow(atom, toAdd) : tc->decls.addUnique(atom, toAdd);
     if (!ok)
         return false;
-    pn->pn_defn = true;
+    pn->setDefn(true);
     pn->pn_dflags &= ~PND_PLACEHOLDER;
     if (!tc->parent)
         pn->pn_dflags |= PND_TOPLEVEL;
     return true;
 }
 
 static void
 LinkUseToDef(JSParseNode *pn, JSDefinition *dn, JSTreeContext *tc)
 {
-    JS_ASSERT(!pn->pn_used);
-    JS_ASSERT(!pn->pn_defn);
+    JS_ASSERT(!pn->isUsed());
+    JS_ASSERT(!pn->isDefn());
     JS_ASSERT(pn != dn->dn_uses);
     pn->pn_link = dn->dn_uses;
     dn->dn_uses = pn;
     dn->pn_dflags |= pn->pn_dflags & PND_USE2DEF_FLAGS;
-    pn->pn_used = true;
+    pn->setUsed(true);
     pn->pn_lexdef = dn;
 }
 
 static void
 ForgetUse(JSParseNode *pn)
 {
-    if (!pn->pn_used) {
-        JS_ASSERT(!pn->pn_defn);
+    if (!pn->isUsed()) {
+        JS_ASSERT(!pn->isDefn());
         return;
     }
 
     JSParseNode **pnup = &pn->lexdef()->dn_uses;
     JSParseNode *pnu;
     while ((pnu = *pnup) != pn)
         pnup = &pnu->pn_link;
     *pnup = pn->pn_link;
-    pn->pn_used = false;
+    pn->setUsed(false);
 }
 
 static JSParseNode *
 MakeAssignment(JSParseNode *pn, JSParseNode *rhs, JSTreeContext *tc)
 {
     JSParseNode *lhs = NewOrRecycledNode(tc);
     if (!lhs)
         return NULL;
     *lhs = *pn;
 
-    if (pn->pn_used) {
+    if (pn->isUsed()) {
         JSDefinition *dn = pn->pn_lexdef;
         JSParseNode **pnup = &dn->dn_uses;
 
         while (*pnup != pn)
             pnup = &(*pnup)->pn_link;
         *pnup = lhs;
         lhs->pn_link = pn->pn_link;
         pn->pn_link = NULL;
     }
 
-    pn->pn_type = TOK_ASSIGN;
-    pn->pn_op = JSOP_NOP;
-    pn->pn_arity = PN_BINARY;
-    pn->pn_parens = false;
-    pn->pn_used = pn->pn_defn = false;
+    pn->setKind(TOK_ASSIGN);
+    pn->setOp(JSOP_NOP);
+    pn->setArity(PN_BINARY);
+    pn->setInParens(false);
+    pn->setUsed(false);
+    pn->setDefn(false);
     pn->pn_left = lhs;
     pn->pn_right = rhs;
     return lhs;
 }
 
 static JSParseNode *
 MakeDefIntoUse(JSDefinition *dn, JSParseNode *pn, JSAtom *atom, JSTreeContext *tc)
 {
@@ -1684,41 +1685,41 @@ MakeDefIntoUse(JSDefinition *dn, JSParse
         if (rhs) {
             JSParseNode *lhs = MakeAssignment(dn, rhs, tc);
             if (!lhs)
                 return NULL;
             //pn->dn_uses = lhs;
             dn = (JSDefinition *) lhs;
         }
 
-        dn->pn_op = (js_CodeSpec[dn->pn_op].format & JOF_SET) ? JSOP_SETNAME : JSOP_NAME;
+        dn->setOp((js_CodeSpec[dn->getOp()].format & JOF_SET) ? JSOP_SETNAME : JSOP_NAME);
     } else if (dn->kind() == JSDefinition::FUNCTION) {
-        JS_ASSERT(dn->pn_op == JSOP_NOP);
+        JS_ASSERT(dn->isOp(JSOP_NOP));
         PrepareNodeForMutation(dn, tc);
-        dn->pn_type = TOK_NAME;
-        dn->pn_arity = PN_NAME;
+        dn->setKind(TOK_NAME);
+        dn->setArity(PN_NAME);
         dn->pn_atom = atom;
     }
 
     /* Now make dn no longer a definition, rather a use of pn. */
-    JS_ASSERT(dn->pn_type == TOK_NAME);
-    JS_ASSERT(dn->pn_arity == PN_NAME);
+    JS_ASSERT(dn->isKind(TOK_NAME));
+    JS_ASSERT(dn->isArity(PN_NAME));
     JS_ASSERT(dn->pn_atom == atom);
 
     for (JSParseNode *pnu = dn->dn_uses; pnu; pnu = pnu->pn_link) {
-        JS_ASSERT(pnu->pn_used);
-        JS_ASSERT(!pnu->pn_defn);
+        JS_ASSERT(pnu->isUsed());
+        JS_ASSERT(!pnu->isDefn());
         pnu->pn_lexdef = (JSDefinition *) pn;
         pn->pn_dflags |= pnu->pn_dflags & PND_USE2DEF_FLAGS;
     }
     pn->pn_dflags |= dn->pn_dflags & PND_USE2DEF_FLAGS;
     pn->dn_uses = dn;
 
-    dn->pn_defn = false;
-    dn->pn_used = true;
+    dn->setDefn(false);
+    dn->setUsed(true);
     dn->pn_lexdef = (JSDefinition *) pn;
     dn->pn_cookie.makeFree();
     dn->pn_dflags &= ~PND_BOUND;
     return dn;
 }
 
 static bool
 DefineArg(JSParseNode *pn, JSAtom *atom, uintN i, JSTreeContext *tc)
@@ -1732,36 +1733,36 @@ DefineArg(JSParseNode *pn, JSAtom *atom,
     /*
      * Make an argument definition node, distinguished by being in tc->decls
      * but having TOK_NAME type and JSOP_NOP op. Insert it in a TOK_ARGSBODY
      * list node returned via pn->pn_body.
      */
     argpn = NameNode::create(atom, tc);
     if (!argpn)
         return false;
-    JS_ASSERT(PN_TYPE(argpn) == TOK_NAME && PN_OP(argpn) == JSOP_NOP);
+    JS_ASSERT(argpn->isKind(TOK_NAME) && argpn->isOp(JSOP_NOP));
 
     /* Arguments are initialized by definition. */
     argpn->pn_dflags |= PND_INITIALIZED;
     if (!Define(argpn, atom, tc))
         return false;
 
     argsbody = pn->pn_body;
     if (!argsbody) {
         argsbody = ListNode::create(tc);
         if (!argsbody)
             return false;
-        argsbody->pn_type = TOK_ARGSBODY;
-        argsbody->pn_op = JSOP_NOP;
+        argsbody->setKind(TOK_ARGSBODY);
+        argsbody->setOp(JSOP_NOP);
         argsbody->makeEmpty();
         pn->pn_body = argsbody;
     }
     argsbody->append(argpn);
 
-    argpn->pn_op = JSOP_GETARG;
+    argpn->setOp(JSOP_GETARG);
     argpn->pn_cookie.set(tc->staticLevel, i);
     argpn->pn_dflags |= PND_BOUND;
     return true;
 }
 
 /*
  * Compile a JS function body, which might appear as the value of an event
  * handler attribute in an HTML <INPUT> tag.
@@ -1833,17 +1834,17 @@ Compiler::compileFunctionBody(JSContext 
             pn = NULL;
         } else if (!js_FoldConstants(cx, pn, &funcg)) {
             /* js_FoldConstants reported the error already. */
             pn = NULL;
         } else if (!parser.analyzeFunctions(&funcg)) {
             pn = NULL;
         } else {
             if (fn->pn_body) {
-                JS_ASSERT(PN_TYPE(fn->pn_body) == TOK_ARGSBODY);
+                JS_ASSERT(fn->pn_body->isKind(TOK_ARGSBODY));
                 fn->pn_body->append(pn);
                 fn->pn_body->pn_pos = pn->pn_pos;
                 pn = fn->pn_body;
             }
 
             if (!js_EmitFunctionScript(cx, &funcg, pn))
                 pn = NULL;
         }
@@ -1931,17 +1932,17 @@ BindDestructuringArg(JSContext *cx, Bind
      *
      * Thus a destructuring formal parameter binds an ARG (as in arguments[i]
      * element) with a null atom name for the object or array passed in to be
      * destructured, and zero or more VARs (as in named local variables) for
      * the destructured-to identifiers in the property value positions within
      * the object or array destructuring pattern, and all ARGs for the formal
      * parameter list bound as locals before any VAR for a destructured name.
      */
-    pn->pn_op = JSOP_SETLOCAL;
+    pn->setOp(JSOP_SETLOCAL);
     pn->pn_dflags |= PND_BOUND;
 
     return Define(pn, atom, tc);
 }
 #endif /* JS_HAS_DESTRUCTURING */
 
 JSFunction *
 Parser::newFunction(JSTreeContext *tc, JSAtom *atom, FunctionSyntaxKind kind)
@@ -2030,17 +2031,17 @@ Parser::analyzeFunctions(JSTreeContext *
  */
 static uintN
 FindFunArgs(JSFunctionBox *funbox, int level, JSFunctionBoxQueue *queue)
 {
     uintN allskipmin = UpvarCookie::FREE_LEVEL;
 
     do {
         JSParseNode *fn = funbox->node;
-        JS_ASSERT(fn->pn_arity == PN_FUNC);
+        JS_ASSERT(fn->isArity(PN_FUNC));
         JSFunction *fun = funbox->function();
         int fnlevel = level;
 
         /*
          * An eval can leak funbox, functions along its ancestor line, and its
          * immediate kids. Since FindFunArgs uses DFS and the parser propagates
          * TCF_FUN_HEAVYWEIGHT bottom up, funbox's ancestor function nodes have
          * already been marked as funargs by this point. Therefore we have to
@@ -2062,17 +2063,17 @@ FindFunArgs(JSFunctionBox *funbox, int l
         /*
          * Compute in skipmin the least distance from fun's static level up to
          * an upvar, whether used directly by fun, or indirectly by a function
          * nested in fun.
          */
         uintN skipmin = UpvarCookie::FREE_LEVEL;
         JSParseNode *pn = fn->pn_body;
 
-        if (pn->pn_type == TOK_UPVARS) {
+        if (pn->isKind(TOK_UPVARS)) {
             AtomDefnMapPtr &upvars = pn->pn_names;
             JS_ASSERT(upvars->count() != 0);
 
             for (AtomDefnRange r = upvars->all(); !r.empty(); r.popFront()) {
                 JSDefinition *defn = r.front().value();
                 JSDefinition *lexdep = defn->resolve();
 
                 if (!lexdep->isFreeVar()) {
@@ -2141,41 +2142,41 @@ Parser::markFunArgs(JSFunctionBox *funbo
     }
 
     FindFunArgs(funbox, -1, &queue);
     while ((funbox = queue.pull()) != NULL) {
         JSParseNode *fn = funbox->node;
         JS_ASSERT(fn->isFunArg());
 
         JSParseNode *pn = fn->pn_body;
-        if (pn->pn_type == TOK_UPVARS) {
+        if (pn->isKind(TOK_UPVARS)) {
             AtomDefnMapPtr upvars = pn->pn_names;
             JS_ASSERT(!upvars->empty());
 
             for (AtomDefnRange r = upvars->all(); !r.empty(); r.popFront()) {
                 JSDefinition *defn = r.front().value();
                 JSDefinition *lexdep = defn->resolve();
 
                 if (!lexdep->isFreeVar() &&
                     !lexdep->isFunArg() &&
                     (lexdep->kind() == JSDefinition::FUNCTION ||
-                     PN_OP(lexdep) == JSOP_CALLEE)) {
+                     lexdep->isOp(JSOP_CALLEE))) {
                     /*
                      * Mark this formerly-Algol-like function as an escaping
                      * function (i.e., as a funarg), because it is used from
                      * another funarg.
                      *
                      * Progress is guaranteed because we set the funarg flag
                      * here, which suppresses revisiting this function (thanks
                      * to the !lexdep->isFunArg() test just above).
                      */
                     lexdep->setFunArg();
 
                     JSFunctionBox *afunbox;
-                    if (PN_OP(lexdep) == JSOP_CALLEE) {
+                    if (lexdep->isOp(JSOP_CALLEE)) {
                         /*
                          * A named function expression will not appear to be a
                          * funarg if it is immediately applied. However, if its
                          * name is used in an escaping function nested within
                          * it, then it must become flagged as a funarg again.
                          * See bug 545980.
                          */
                         afunbox = funbox;
@@ -2206,17 +2207,17 @@ Parser::markFunArgs(JSFunctionBox *funbo
     return true;
 }
 
 static uint32
 MinBlockId(JSParseNode *fn, uint32 id)
 {
     if (fn->pn_blockid < id)
         return false;
-    if (fn->pn_defn) {
+    if (fn->isDefn()) {
         for (JSParseNode *pn = fn->dn_uses; pn; pn = pn->pn_link) {
             if (pn->pn_blockid < id)
                 return false;
         }
     }
     return true;
 }
 
@@ -2385,18 +2386,18 @@ FlagHeavyweights(JSDefinition *dn, JSFun
 }
 
 static bool
 DeoptimizeUsesWithin(JSDefinition *dn, const TokenPos &pos)
 {
     uintN ndeoptimized = 0;
 
     for (JSParseNode *pnu = dn->dn_uses; pnu; pnu = pnu->pn_link) {
-        JS_ASSERT(pnu->pn_used);
-        JS_ASSERT(!pnu->pn_defn);
+        JS_ASSERT(pnu->isUsed());
+        JS_ASSERT(!pnu->isDefn());
         if (pnu->pn_pos.begin >= pos.begin && pnu->pn_pos.end <= pos.end) {
             pnu->pn_dflags |= PND_DEOPTIMIZED;
             ++ndeoptimized;
         }
     }
 
     return ndeoptimized != 0;
 }
@@ -2413,29 +2414,29 @@ ConsiderUnbranding(JSFunctionBox *funbox
      * slot-based shape if this function smells like a constructor and too many
      * of its methods are *not* joinable null closures (i.e., they have one or
      * more upvars fetched via the display).
      */
     bool returnsExpr = !!(funbox->tcflags & TCF_RETURN_EXPR);
 #if JS_HAS_EXPR_CLOSURES
     {
         JSParseNode *pn2 = funbox->node->pn_body;
-        if (PN_TYPE(pn2) == TOK_UPVARS)
+        if (pn2->isKind(TOK_UPVARS))
             pn2 = pn2->pn_tree;
-        if (PN_TYPE(pn2) == TOK_ARGSBODY)
+        if (pn2->isKind(TOK_ARGSBODY))
             pn2 = pn2->last();
-        if (PN_TYPE(pn2) != TOK_LC)
+        if (!pn2->isKind(TOK_LC))
             returnsExpr = true;
     }
 #endif
     if (!returnsExpr) {
         uintN methodSets = 0, slowMethodSets = 0;
 
         for (JSParseNode *method = funbox->methods; method; method = method->pn_link) {
-            JS_ASSERT(PN_OP(method) == JSOP_LAMBDA || PN_OP(method) == JSOP_LAMBDA_FC);
+            JS_ASSERT(method->isOp(JSOP_LAMBDA) || method->isOp(JSOP_LAMBDA_FC));
             ++methodSets;
             if (!method->pn_funbox->joinable())
                 ++slowMethodSets;
         }
 
         if (funbox->shouldUnbrand(methodSets, slowMethodSets))
             funbox->tcflags |= TCF_FUN_UNBRAND_THIS;
     }
@@ -2460,17 +2461,17 @@ Parser::setFunctionKinds(JSFunctionBox *
         if (funbox->tcflags & TCF_FUN_HEAVYWEIGHT) {
             /* nothing to do */
         } else if (funbox->inAnyDynamicScope()) {
             JS_ASSERT(!fun->isNullClosure());
         } else {
             bool hasUpvars = false;
             bool canFlatten = true;
 
-            if (pn->pn_type == TOK_UPVARS) {
+            if (pn->isKind(TOK_UPVARS)) {
                 AtomDefnMapPtr upvars = pn->pn_names;
                 JS_ASSERT(!upvars->empty());
 
                 /*
                  * For each lexical dependency from this closure to an outer
                  * binding, analyze whether it is safe to copy the binding's
                  * value into a flat closure slot when the closure is formed.
                  */
@@ -2494,34 +2495,34 @@ Parser::setFunctionKinds(JSFunctionBox *
                 }
             }
 
             if (!hasUpvars) {
                 /* No lexical dependencies => null closure, for best performance. */
                 fun->setKind(JSFUN_NULL_CLOSURE);
             } else if (canFlatten) {
                 fun->setKind(JSFUN_FLAT_CLOSURE);
-                switch (PN_OP(fn)) {
-                case JSOP_DEFFUN:
-                    fn->pn_op = JSOP_DEFFUN_FC;
+                switch (fn->getOp()) {
+                  case JSOP_DEFFUN:
+                    fn->setOp(JSOP_DEFFUN_FC);
                     break;
-                case JSOP_DEFLOCALFUN:
-                    fn->pn_op = JSOP_DEFLOCALFUN_FC;
+                  case JSOP_DEFLOCALFUN:
+                    fn->setOp(JSOP_DEFLOCALFUN_FC);
                     break;
-                case JSOP_LAMBDA:
-                    fn->pn_op = JSOP_LAMBDA_FC;
+                  case JSOP_LAMBDA:
+                    fn->setOp(JSOP_LAMBDA_FC);
                     break;
-                default:
+                  default:
                     /* js_EmitTree's case TOK_FUNCTION: will select op. */
-                    JS_ASSERT(PN_OP(fn) == JSOP_NOP);
+                    JS_ASSERT(fn->isOp(JSOP_NOP));
                 }
             }
         }
 
-        if (fun->kind() == JSFUN_INTERPRETED && pn->pn_type == TOK_UPVARS) {
+        if (fun->kind() == JSFUN_INTERPRETED && pn->isKind(TOK_UPVARS)) {
             /*
              * One or more upvars cannot be safely snapshot into a flat
              * closure's non-reserved slot (see JSOP_GETFCSLOT), so we loop
              * again over all upvars, and for each non-free upvar, ensure that
              * its containing function has been flagged as heavyweight.
              *
              * The emitter must see TCF_FUN_HEAVYWEIGHT accurately before
              * generating any code for a tree of nested functions.
@@ -2642,17 +2643,17 @@ LeaveFunction(JSParseNode *fn, JSTreeCon
         int foundCallee = 0;
 
         for (AtomDefnRange r = funtc->lexdeps->all(); !r.empty(); r.popFront()) {
             JSAtom *atom = r.front().key();
             JSDefinition *dn = r.front().value();
             JS_ASSERT(dn->isPlaceholder());
 
             if (atom == funAtom && kind == Expression) {
-                dn->pn_op = JSOP_CALLEE;
+                dn->setOp(JSOP_CALLEE);
                 dn->pn_cookie.set(funtc->staticLevel, UpvarCookie::CALLEE_SLOT);
                 dn->pn_dflags |= PND_BOUND;
 
                 /*
                  * If this named function expression uses its own name other
                  * than to call itself, flag this function specially.
                  */
                 if (dn->isFunArg())
@@ -2747,33 +2748,33 @@ LeaveFunction(JSParseNode *fn, JSTreeCon
                  * Make dn be a use that redirects to outer_dn, because we
                  * can't replace dn with outer_dn in all the pn_namesets in
                  * the AST where it may be. Instead we make it forward to
                  * outer_dn. See JSDefinition::resolve.
                  */
                 *pnup = outer_dn->dn_uses;
                 outer_dn->dn_uses = dn;
                 outer_dn->pn_dflags |= dn->pn_dflags & ~PND_PLACEHOLDER;
-                dn->pn_defn = false;
-                dn->pn_used = true;
+                dn->setDefn(false);
+                dn->setUsed(true);
                 dn->pn_lexdef = outer_dn;
             }
 
             /* Mark the outer dn as escaping. */
             outer_dn->pn_dflags |= PND_CLOSED;
         }
 
         if (funtc->lexdeps->count() - foundCallee != 0) {
             JSParseNode *body = fn->pn_body;
 
             fn->pn_body = NameSetNode::create(tc);
             if (!fn->pn_body)
                 return false;
 
-            fn->pn_body->pn_type = TOK_UPVARS;
+            fn->pn_body->setKind(TOK_UPVARS);
             fn->pn_body->pn_pos = body->pn_pos;
             if (foundCallee)
                 funtc->lexdeps->remove(funAtom);
             /* Transfer ownership of the lexdep map to the parse node. */
             fn->pn_body->pn_names = funtc->lexdeps;
             funtc->lexdeps.clearMap();
             fn->pn_body->pn_tree = body;
         } else {
@@ -2866,30 +2867,30 @@ Parser::functionArguments(JSTreeContext 
                 /*
                  * Synthesize a destructuring assignment from the single
                  * anonymous positional parameter into the destructuring
                  * left-hand-side expression and accumulate it in list.
                  */
                 JSParseNode *rhs = NameNode::create(context->runtime->atomState.emptyAtom, &funtc);
                 if (!rhs)
                     return false;
-                rhs->pn_type = TOK_NAME;
-                rhs->pn_op = JSOP_GETARG;
+                rhs->setKind(TOK_NAME);
+                rhs->setOp(JSOP_GETARG);
                 rhs->pn_cookie.set(funtc.staticLevel, slot);
                 rhs->pn_dflags |= PND_BOUND;
 
                 JSParseNode *item =
                     JSParseNode::newBinaryOrAppend(TOK_ASSIGN, JSOP_NOP, lhs, rhs, &funtc);
                 if (!item)
                     return false;
                 if (!list) {
                     list = ListNode::create(&funtc);
                     if (!list)
                         return false;
-                    list->pn_type = TOK_VAR;
+                    list->setKind(TOK_VAR);
                     list->makeEmpty();
                     *listp = list;
                 }
                 list->append(item);
                 break;
               }
 #endif /* JS_HAS_DESTRUCTURING */
 
@@ -2981,18 +2982,18 @@ Parser::functionDef(JSAtom *funAtom, Fun
     /*
      * Record names for function statements in tc->decls so we know when to
      * avoid optimizing variable references that might name a function.
      */
     if (kind == Statement) {
         if (JSDefinition *dn = tc->decls.lookupFirst(funAtom)) {
             JSDefinition::Kind dn_kind = dn->kind();
 
-            JS_ASSERT(!dn->pn_used);
-            JS_ASSERT(dn->pn_defn);
+            JS_ASSERT(!dn->isUsed());
+            JS_ASSERT(dn->isDefn());
 
             if (context->hasStrictOption() || dn_kind == JSDefinition::CONST) {
                 JSAutoByteString name;
                 if (!js_AtomToPrintableString(context, funAtom, &name) ||
                     !reportErrorNumber(NULL,
                                        (dn_kind != JSDefinition::CONST)
                                        ? JSREPORT_WARNING | JSREPORT_STRICT
                                        : JSREPORT_ERROR,
@@ -3000,33 +3001,33 @@ Parser::functionDef(JSAtom *funAtom, Fun
                                        JSDefinition::kindString(dn_kind),
                                        name.ptr())) {
                     return NULL;
                 }
             }
 
             if (bodyLevel) {
                 tc->decls.updateFirst(funAtom, (JSDefinition *) pn);
-                pn->pn_defn = true;
+                pn->setDefn(true);
                 pn->dn_uses = dn; /* dn->dn_uses is now pn_link */
 
                 if (!MakeDefIntoUse(dn, pn, funAtom, tc))
                     return NULL;
             }
         } else if (bodyLevel) {
             /*
              * If this function was used before it was defined, claim the
              * pre-created definition node for this function that primaryExpr
              * put in tc->lexdeps on first forward reference, and recycle pn.
              */
 
             if (JSDefinition *fn = tc->lexdeps.lookupDefn(funAtom)) {
-                JS_ASSERT(fn->pn_defn);
-                fn->pn_type = TOK_FUNCTION;
-                fn->pn_arity = PN_FUNC;
+                JS_ASSERT(fn->isDefn());
+                fn->setKind(TOK_FUNCTION);
+                fn->setArity(PN_FUNC);
                 fn->pn_pos.begin = pn->pn_pos.begin;
 
                 /*
                  * Set fn->pn_pos.end too, in case of error before we parse the
                  * closing brace.  See bug 640075.
                  */
                 fn->pn_pos.end = pn->pn_pos.end;
 
@@ -3106,17 +3107,17 @@ Parser::functionDef(JSAtom *funAtom, Fun
      * we can't bind vars induced by formal parameter destructuring until after
      * Parser::functionArguments has returned.
      */
     if (prelude) {
         AtomDeclsIter iter(&funtc.decls);
 
         while (JSDefinition *apn = iter()) {
             /* Filter based on pn_op -- see BindDestructuringArg, above. */
-            if (apn->pn_op != JSOP_SETLOCAL)
+            if (!apn->isOp(JSOP_SETLOCAL))
                 continue;
 
             if (!BindLocalVariable(context, &funtc, apn, VARIABLE))
                 return NULL;
         }
     }
 #endif
 
@@ -3180,34 +3181,34 @@ Parser::functionDef(JSAtom *funAtom, Fun
 #if JS_HAS_DESTRUCTURING
     /*
      * If there were destructuring formal parameters, prepend the initializing
      * comma expression that we synthesized to body. If the body is a return
      * node, we must make a special TOK_SEQ node, to prepend the destructuring
      * code without bracing the decompilation of the function body.
      */
     if (prelude) {
-        if (body->pn_arity != PN_LIST) {
+        if (!body->isArity(PN_LIST)) {
             JSParseNode *block;
 
             block = ListNode::create(outertc);
             if (!block)
                 return NULL;
-            block->pn_type = TOK_SEQ;
+            block->setKind(TOK_SEQ);
             block->pn_pos = body->pn_pos;
             block->initList(body);
 
             body = block;
         }
 
         JSParseNode *item = UnaryNode::create(outertc);
         if (!item)
             return NULL;
 
-        item->pn_type = TOK_SEMI;
+        item->setKind(TOK_SEMI);
         item->pn_pos.begin = item->pn_pos.end = body->pn_pos.begin;
         item->pn_kid = prelude;
         item->pn_next = body->pn_head;
         body->pn_head = item;
         if (body->pn_tail == &body->pn_head)
             body->pn_tail = &item->pn_next;
         ++body->pn_count;
         body->pn_xflags |= PNX_DESTRUCT;
@@ -3249,17 +3250,17 @@ Parser::functionDef(JSAtom *funAtom, Fun
             op = JSOP_DEFFUN;
             outertc->noteMightAliasLocals();
         }
     }
 
     funbox->kids = funtc.functionList;
 
     pn->pn_funbox = funbox;
-    pn->pn_op = op;
+    pn->setOp(op);
     if (pn->pn_body) {
         pn->pn_body->append(body);
         pn->pn_body->pn_pos = body->pn_pos;
     } else {
         pn->pn_body = body;
     }
 
     if (!outertc->inFunction() && bodyLevel && kind == Statement && outertc->compiling()) {
@@ -3393,17 +3394,17 @@ Parser::statements()
     JSParseNode *pn, *pn2, *saveBlock;
     TokenKind tt;
 
     JS_CHECK_RECURSION(context, return NULL);
 
     pn = ListNode::create(tc);
     if (!pn)
         return NULL;
-    pn->pn_type = TOK_LC;
+    pn->setKind(TOK_LC);
     pn->makeEmpty();
     pn->pn_blockid = tc->blockid();
     saveBlock = tc->blockNode;
     tc->blockNode = pn;
 
     bool inDirectivePrologue = tc->atBodyLevel();
     tokenStream.setOctalCharacterEscape(false);
     for (;;) {
@@ -3421,17 +3422,17 @@ Parser::statements()
             if (tokenStream.isEOF())
                 tokenStream.setUnexpectedEOF();
             return NULL;
         }
 
         if (inDirectivePrologue && !recognizeDirectivePrologue(pn2, &inDirectivePrologue))
             return NULL;
 
-        if (pn2->pn_type == TOK_FUNCTION) {
+        if (pn2->isKind(TOK_FUNCTION)) {
             /*
              * PNX_FUNCDEFS notifies the emitter that the block contains body-
              * level function definitions that should be processed before the
              * rest of nodes.
              *
              * TCF_HAS_FUNCTION_STMT is for the TOK_LC case in Statement. It
              * is relevant only for function definitions not at body-level,
              * which we call function statements.
@@ -3467,19 +3468,19 @@ Parser::condition()
 
     MUST_MATCH_TOKEN(TOK_LP, JSMSG_PAREN_BEFORE_COND);
     pn = parenExpr();
     if (!pn)
         return NULL;
     MUST_MATCH_TOKEN(TOK_RP, JSMSG_PAREN_AFTER_COND);
 
     /* Check for (a = b) and warn about possible (a == b) mistype. */
-    if (pn->pn_type == TOK_ASSIGN &&
-        pn->pn_op == JSOP_NOP &&
-        !pn->pn_parens &&
+    if (pn->isKind(TOK_ASSIGN) &&
+        pn->isOp(JSOP_NOP) &&
+        !pn->isInParens() &&
         !reportErrorNumber(NULL, JSREPORT_WARNING | JSREPORT_STRICT, JSMSG_EQUAL_AS_ASSIGN, "")) {
         return NULL;
     }
     return pn;
 }
 
 static JSBool
 MatchLabel(JSContext *cx, TokenStream *ts, JSParseNode *pn)
@@ -3555,17 +3556,17 @@ BindLet(JSContext *cx, BindData *data, J
 
     /*
      * Assign block-local index to pn->pn_cookie right away, encoding it as an
      * upvar cookie whose skip tells the current static level. The emitter will
      * adjust the node's slot based on its stack depth model -- and, for global
      * and eval code, Compiler::compileScript will adjust the slot again to
      * include script->nfixed.
      */
-    pn->pn_op = JSOP_GETLOCAL;
+    pn->setOp(JSOP_GETLOCAL);
     pn->pn_cookie.set(tc->staticLevel, uint16(n));
     pn->pn_dflags |= PND_LET | PND_BOUND;
 
     /*
      * Define the let binding's property before storing pn in the the binding's
      * slot indexed by n off the class-reserved slot base.
      */
     const Shape *shape = blockObj->defineBlockVariable(cx, ATOM_TO_JSID(atom), n);
@@ -3645,17 +3646,17 @@ DefineGlobal(JSParseNode *pn, JSCodeGene
     if (!p) {
         JSContext *cx = cg->parser->context;
 
         JSObject *holder;
         JSProperty *prop;
         if (!globalObj->lookupProperty(cx, ATOM_TO_JSID(atom), &holder, &prop))
             return false;
 
-        JSFunctionBox *funbox = (pn->pn_type == TOK_FUNCTION) ? pn->pn_funbox : NULL;
+        JSFunctionBox *funbox = pn->isKind(TOK_FUNCTION) ? pn->pn_funbox : NULL;
 
         GlobalScope::GlobalDef def;
         if (prop) {
             /*
              * A few cases where we don't bother aggressively caching:
              *   1) Function value changes.
              *   2) Configurable properties.
              *   3) Properties without slots, or with getters/setters.
@@ -3692,32 +3693,32 @@ DefineGlobal(JSParseNode *pn, JSCodeGene
          * example:
          *   var c = []
          *   function c() { }
          *
          * This rewrite is allowed because the function will be statically
          * hoisted to the top of the script, and the |c = []| will just
          * overwrite it at runtime.
          */
-        if (pn->pn_type == TOK_FUNCTION) {
-            JS_ASSERT(pn->pn_arity = PN_FUNC);
+        if (pn->isKind(TOK_FUNCTION)) {
+            JS_ASSERT(pn->isArity(PN_FUNC));
             jsatomid index = p.value();
             globalScope->defs[index].funbox = pn->pn_funbox;
         }
     }
 
     pn->pn_dflags |= PND_GVAR;
 
     return true;
 }
 
 static bool
 BindTopLevelVar(JSContext *cx, BindData *data, JSParseNode *pn, JSTreeContext *tc)
 {
-    JS_ASSERT(pn->pn_op == JSOP_NAME);
+    JS_ASSERT(pn->isOp(JSOP_NAME));
     JS_ASSERT(!tc->inFunction());
 
     /* There's no need to optimize bindings if we're not compiling code. */
     if (!tc->compiling())
         return true;
 
     /*
      * Bindings at top level in eval code aren't like bindings at top level in
@@ -3772,17 +3773,17 @@ BindFunctionLocal(JSContext *cx, BindDat
 
     /*
      * Don't create a local variable with the name 'arguments', per ECMA-262.
      * Instead, 'var arguments' always restates that predefined binding of the
      * lexical environment for function activations. Assignments to arguments
      * must be handled specially -- see NoteLValue.
      */
     if (name == cx->runtime->atomState.argumentsAtom) {
-        pn->pn_op = JSOP_ARGUMENTS;
+        pn->setOp(JSOP_ARGUMENTS);
         pn->pn_dflags |= PND_BOUND;
         return true;
     }
 
     BindingKind kind = tc->bindings.lookup(cx, name, NULL);
     if (kind == NONE) {
         /*
          * Property not found in current variable scope: we have not seen this
@@ -3790,17 +3791,17 @@ BindFunctionLocal(JSContext *cx, BindDat
          * declared in a with statement body are handled at runtime, by script
          * prolog JSOP_DEFVAR opcodes generated for global and heavyweight-
          * function-local vars.
          */
         kind = (data->op == JSOP_DEFCONST) ? CONSTANT : VARIABLE;
 
         if (!BindLocalVariable(cx, tc, pn, kind))
             return false;
-        pn->pn_op = JSOP_GETLOCAL;
+        pn->setOp(JSOP_GETLOCAL);
         return true;
     }
 
     if (kind == ARGUMENT) {
         JS_ASSERT(tc->inFunction());
         JS_ASSERT(!mdl.empty() && mdl.front()->kind() == JSDefinition::ARG);
     } else {
         JS_ASSERT(kind == VARIABLE || kind == CONSTANT);
@@ -3810,17 +3811,17 @@ BindFunctionLocal(JSContext *cx, BindDat
 }
 
 static JSBool
 BindVarOrConst(JSContext *cx, BindData *data, JSAtom *atom, JSTreeContext *tc)
 {
     JSParseNode *pn = data->pn;
 
     /* Default best op for pn is JSOP_NAME; we'll try to improve below. */
-    pn->pn_op = JSOP_NAME;
+    pn->setOp(JSOP_NAME);
 
     if (!CheckStrictBinding(cx, tc, atom, pn))
         return false;
 
     JSStmtInfo *stmt = js_LexicalLookup(tc, atom, NULL);
 
     if (stmt && stmt->type == STMT_WITH) {
         data->fresh = false;
@@ -3890,28 +3891,28 @@ BindVarOrConst(JSContext *cx, BindData *
          * A case such as let (x = 1) { var x = 2; print(x); } is even harder.
          * There the x definition is hoisted but the x = 2 assignment mutates
          * the block-local binding of x.
          */
         JSDefinition *dn = mdl.front();
 
         data->fresh = false;
 
-        if (!pn->pn_used) {
+        if (!pn->isUsed()) {
             /* Make pnu be a fresh name node that uses dn. */
             JSParseNode *pnu = pn;
 
-            if (pn->pn_defn) {
+            if (pn->isDefn()) {
                 pnu = NameNode::create(atom, tc);
                 if (!pnu)
                     return JS_FALSE;
             }
 
             LinkUseToDef(pnu, dn, tc);
-            pnu->pn_op = JSOP_NAME;
+            pnu->setOp(JSOP_NAME);
         }
 
         /* Find the first non-let binding of this atom. */
         while (dn->kind() == JSDefinition::LET) {
             mdl.popFront();
             if (mdl.empty())
                 break;
             dn = mdl.front();
@@ -3923,69 +3924,69 @@ BindVarOrConst(JSContext *cx, BindData *
             return JS_TRUE;
         }
 
         /*
          * A var or const that is shadowed by one or more let bindings of the
          * same name, but that has not been declared until this point, must be
          * hoisted above the let bindings.
          */
-        if (!pn->pn_defn) {
+        if (!pn->isDefn()) {
             if (tc->lexdeps->lookup(atom)) {
                 tc->lexdeps->remove(atom);
             } else {
                 JSParseNode *pn2 = NameNode::create(atom, tc);
                 if (!pn2)
                     return JS_FALSE;
 
                 /* The token stream may be past the location for pn. */
-                pn2->pn_type = TOK_NAME;
+                pn2->setKind(TOK_NAME);
                 pn2->pn_pos = pn->pn_pos;
                 pn = pn2;
             }
-            pn->pn_op = JSOP_NAME;
+            pn->setOp(JSOP_NAME);
         }
 
         if (!tc->decls.addHoist(atom, (JSDefinition *) pn))
             return JS_FALSE;
-        pn->pn_defn = true;
+        pn->setDefn(true);
         pn->pn_dflags &= ~PND_PLACEHOLDER;
     }
 
     if (data->op == JSOP_DEFCONST)
         pn->pn_dflags |= PND_CONST;
 
     if (tc->inFunction())
         return BindFunctionLocal(cx, data, mdl, tc);
 
     return BindTopLevelVar(cx, data, pn, tc);
 }
 
 static bool
 MakeSetCall(JSContext *cx, JSParseNode *pn, JSTreeContext *tc, uintN msg)
 {
-    JS_ASSERT(pn->pn_arity == PN_LIST);
-    JS_ASSERT(pn->pn_op == JSOP_CALL || pn->pn_op == JSOP_EVAL ||
-              pn->pn_op == JSOP_FUNCALL || pn->pn_op == JSOP_FUNAPPLY);
+    JS_ASSERT(pn->isArity(PN_LIST));
+    JS_ASSERT(pn->isOp(JSOP_CALL) || pn->isOp(JSOP_EVAL) ||
+              pn->isOp(JSOP_FUNCALL) || pn->isOp(JSOP_FUNAPPLY));
     if (!ReportStrictModeError(cx, TS(tc->parser), tc, pn, msg))
         return false;
 
     JSParseNode *pn2 = pn->pn_head;
-    if (pn2->pn_type == TOK_FUNCTION && (pn2->pn_funbox->tcflags & TCF_GENEXP_LAMBDA)) {
+    if (pn2->isKind(TOK_FUNCTION) && (pn2->pn_funbox->tcflags & TCF_GENEXP_LAMBDA)) {
         ReportCompileErrorNumber(cx, TS(tc->parser), pn, JSREPORT_ERROR, msg);
         return false;
     }
     pn->pn_xflags |= PNX_SETCALL;
     return true;
 }
 
 static void
 NoteLValue(JSContext *cx, JSParseNode *pn, JSTreeContext *tc, uintN dflag = PND_ASSIGNED)
 {
-    if (pn->pn_used) {
+    if (pn->isUsed()) {
         JSDefinition *dn = pn->pn_lexdef;
 
         /*
          * Save the win of PND_INITIALIZED if we can prove 'var x;' and 'x = y'
          * occur as direct kids of the same block with no forward refs to x.
          */
         if (!(dn->pn_dflags & (PND_INITIALIZED | PND_CONST | PND_PLACEHOLDER)) &&
             dn->isBlockChild() &&
@@ -4030,38 +4031,34 @@ BindDestructuringVar(JSContext *cx, Bind
 {
     JSAtom *atom;
 
     /*
      * Destructuring is a form of assignment, so just as for an initialized
      * simple variable, we must check for assignment to 'arguments' and flag
      * the enclosing function (if any) as heavyweight.
      */
-    JS_ASSERT(pn->pn_type == TOK_NAME);
+    JS_ASSERT(pn->isKind(TOK_NAME));
     atom = pn->pn_atom;
     if (atom == cx->runtime->atomState.argumentsAtom)
         tc->flags |= TCF_FUN_HEAVYWEIGHT;
 
     data->pn = pn;
     if (!data->binder(cx, data, atom, tc))
         return JS_FALSE;
 
     /*
      * Select the appropriate name-setting opcode, respecting eager selection
      * done by the data->binder function.
      */
     if (pn->pn_dflags & PND_BOUND) {
         JS_ASSERT(!(pn->pn_dflags & PND_GVAR));
-        pn->pn_op = (pn->pn_op == JSOP_ARGUMENTS)
-                    ? JSOP_SETNAME
-                    : JSOP_SETLOCAL;
+        pn->setOp(pn->isOp(JSOP_ARGUMENTS) ? JSOP_SETNAME : JSOP_SETLOCAL);
     } else {
-        pn->pn_op = (data->op == JSOP_DEFCONST)
-                    ? JSOP_SETCONST
-                    : JSOP_SETNAME;
+        pn->setOp((data->op == JSOP_DEFCONST) ? JSOP_SETCONST : JSOP_SETNAME);
     }
 
     if (data->op == JSOP_DEFCONST)
         pn->pn_dflags |= PND_CONST;
 
     NoteLValue(cx, pn, tc, PND_INITIALIZED);
     return JS_TRUE;
 }
@@ -4082,41 +4079,41 @@ BindDestructuringVar(JSContext *cx, Bind
  *
  * and pops all three values, setting lval[xval] = rval.  But we cannot select
  * JSOP_ENUMELEM yet, because the LHS may turn out to be an arg or local var,
  * which can be optimized further.  So we select JSOP_SETNAME.
  */
 static JSBool
 BindDestructuringLHS(JSContext *cx, JSParseNode *pn, JSTreeContext *tc)
 {
-    switch (pn->pn_type) {
+    switch (pn->getKind()) {
       case TOK_NAME:
         NoteLValue(cx, pn, tc);
         /* FALL THROUGH */
 
       case TOK_DOT:
       case TOK_LB:
         /*
          * We may be called on a name node that has already been specialized,
          * in the very weird and ECMA-262-required "for (var [x] = i in o) ..."
          * case. See bug 558633.
          */
-        if (!(js_CodeSpec[pn->pn_op].format & JOF_SET))
-            pn->pn_op = JSOP_SETNAME;
+        if (!(js_CodeSpec[pn->getOp()].format & JOF_SET))
+            pn->setOp(JSOP_SETNAME);
         break;
 
       case TOK_LP:
         if (!MakeSetCall(cx, pn, tc, JSMSG_BAD_LEFTSIDE_OF_ASS))
             return JS_FALSE;
         break;
 
 #if JS_HAS_XML_SUPPORT
       case TOK_UNARYOP:
-        if (pn->pn_op == JSOP_XMLNAME) {
-            pn->pn_op = JSOP_BINDXMLNAME;
+        if (pn->isOp(JSOP_XMLNAME)) {
+            pn->setOp(JSOP_BINDXMLNAME);
             break;
         }
         /* FALL THROUGH */
 #endif
 
       default:
         ReportCompileErrorNumber(cx, TS(tc->parser), pn,
                                  JSREPORT_ERROR, JSMSG_BAD_LEFTSIDE_OF_ASS);
@@ -4166,54 +4163,54 @@ BindDestructuringLHS(JSContext *cx, JSPa
  * either of these functions, you might have to change the other to
  * match.
  */
 static bool
 CheckDestructuring(JSContext *cx, BindData *data, JSParseNode *left, JSTreeContext *tc)
 {
     bool ok;
 
-    if (left->pn_type == TOK_ARRAYCOMP) {
+    if (left->isKind(TOK_ARRAYCOMP)) {
         ReportCompileErrorNumber(cx, TS(tc->parser), left, JSREPORT_ERROR,
                                  JSMSG_ARRAY_COMP_LEFTSIDE);
         return false;
     }
 
-    if (left->pn_type == TOK_RB) {
+    if (left->isKind(TOK_RB)) {
         for (JSParseNode *pn = left->pn_head; pn; pn = pn->pn_next) {
             /* Nullary comma is an elision; binary comma is an expression.*/
-            if (pn->pn_type != TOK_COMMA || pn->pn_arity != PN_NULLARY) {
-                if (pn->pn_type == TOK_RB || pn->pn_type == TOK_RC) {
+            if (!pn->isKind(TOK_COMMA) || !pn->isArity(PN_NULLARY)) {
+                if (pn->isKind(TOK_RB) || pn->isKind(TOK_RC)) {
                     ok = CheckDestructuring(cx, data, pn, tc);
                 } else {
                     if (data) {
-                        if (pn->pn_type != TOK_NAME) {
+                        if (!pn->isKind(TOK_NAME)) {
                             ReportCompileErrorNumber(cx, TS(tc->parser), pn, JSREPORT_ERROR,
                                                      JSMSG_NO_VARIABLE_NAME);
                             return false;
                         }
                         ok = BindDestructuringVar(cx, data, pn, tc);
                     } else {
                         ok = BindDestructuringLHS(cx, pn, tc);
                     }
                 }
                 if (!ok)
                     return false;
             }
         }
     } else {
-        JS_ASSERT(left->pn_type == TOK_RC);
+        JS_ASSERT(left->isKind(TOK_RC));
         for (JSParseNode *pair = left->pn_head; pair; pair = pair->pn_next) {
-            JS_ASSERT(pair->pn_type == TOK_COLON);
+            JS_ASSERT(pair->isKind(TOK_COLON));
             JSParseNode *pn = pair->pn_right;
 
-            if (pn->pn_type == TOK_RB || pn->pn_type == TOK_RC) {
+            if (pn->isKind(TOK_RB) || pn->isKind(TOK_RC)) {
                 ok = CheckDestructuring(cx, data, pn, tc);
             } else if (data) {
-                if (pn->pn_type != TOK_NAME) {
+                if (!pn->isKind(TOK_NAME)) {
                     ReportCompileErrorNumber(cx, TS(tc->parser), pn, JSREPORT_ERROR,
                                              JSMSG_NO_VARIABLE_NAME);
                     return false;
                 }
                 ok = BindDestructuringVar(cx, data, pn, tc);
             } else {
                 ok = BindDestructuringLHS(cx, pn, tc);
             }
@@ -4269,33 +4266,33 @@ CheckDestructuring(JSContext *cx, BindDa
  * Languages", Brandis and Mössenböck), we could do much better.
  *
  * See CheckDestructuring, immediately above. If you change either of these
  * functions, you might have to change the other to match.
  */
 static void
 UndominateInitializers(JSParseNode *left, const TokenPtr &end, JSTreeContext *tc)
 {
-    if (left->pn_type == TOK_RB) {
+    if (left->isKind(TOK_RB)) {
         for (JSParseNode *pn = left->pn_head; pn; pn = pn->pn_next) {
             /* Nullary comma is an elision; binary comma is an expression.*/
-            if (pn->pn_type != TOK_COMMA || pn->pn_arity != PN_NULLARY) {
-                if (pn->pn_type == TOK_RB || pn->pn_type == TOK_RC)
+            if (!pn->isKind(TOK_COMMA) || !pn->isArity(PN_NULLARY)) {
+                if (pn->isKind(TOK_RB) || pn->isKind(TOK_RC))
                     UndominateInitializers(pn, end, tc);
                 else
                     pn->pn_pos.end = end;
             }
         }
     } else {
-        JS_ASSERT(left->pn_type == TOK_RC);
+        JS_ASSERT(left->isKind(TOK_RC));
 
         for (JSParseNode *pair = left->pn_head; pair; pair = pair->pn_next) {
-            JS_ASSERT(pair->pn_type == TOK_COLON);
+            JS_ASSERT(pair->isKind(TOK_COLON));
             JSParseNode *pn = pair->pn_right;
-            if (pn->pn_type == TOK_RB || pn->pn_type == TOK_RC)
+            if (pn->isKind(TOK_RB) || pn->isKind(TOK_RC))
                 UndominateInitializers(pn, end, tc);
             else
                 pn->pn_pos.end = end;
         }
     }
 }
 
 JSParseNode *
@@ -4323,25 +4320,25 @@ CloneParseTree(JSParseNode *opn, JSTreeC
 {
     JS_CHECK_RECURSION(tc->parser->context, return NULL);
 
     JSParseNode *pn, *pn2, *opn2;
 
     pn = NewOrRecycledNode(tc);
     if (!pn)
         return NULL;
-    pn->pn_type = opn->pn_type;
+    pn->setKind(opn->getKind());
+    pn->setOp(opn->getOp());
+    pn->setUsed(opn->isUsed());
+    pn->setDefn(opn->isDefn());
+    pn->setArity(opn->getArity());
+    pn->setInParens(opn->isInParens());
     pn->pn_pos = opn->pn_pos;
-    pn->pn_op = opn->pn_op;
-    pn->pn_used = opn->pn_used;
-    pn->pn_defn = opn->pn_defn;
-    pn->pn_arity = opn->pn_arity;
-    pn->pn_parens = opn->pn_parens;
-
-    switch (pn->pn_arity) {
+
+    switch (pn->getArity()) {
 #define NULLCHECK(e)    JS_BEGIN_MACRO if (!(e)) return NULL; JS_END_MACRO
 
       case PN_FUNC:
         NULLCHECK(pn->pn_funbox =
                   tc->parser->newFunctionBox(opn->pn_funbox->object, pn, tc));
         NULLCHECK(pn->pn_body = CloneParseTree(opn->pn_body, tc));
         pn->pn_cookie = opn->pn_cookie;
         pn->pn_dflags = opn->pn_dflags;
@@ -4377,34 +4374,34 @@ CloneParseTree(JSParseNode *opn, JSTreeC
         NULLCHECK(pn->pn_kid = CloneParseTree(opn->pn_kid, tc));
         pn->pn_num = opn->pn_num;
         pn->pn_hidden = opn->pn_hidden;
         break;
 
       case PN_NAME:
         // PN_NAME could mean several arms in pn_u, so copy the whole thing.
         pn->pn_u = opn->pn_u;
-        if (opn->pn_used) {
+        if (opn->isUsed()) {
             /*
              * The old name is a use of its pn_lexdef. Make the clone also be a
              * use of that definition.
              */
             JSDefinition *dn = pn->pn_lexdef;
 
             pn->pn_link = dn->dn_uses;
             dn->dn_uses = pn;
         } else if (opn->pn_expr) {
             NULLCHECK(pn->pn_expr = CloneParseTree(opn->pn_expr, tc));
 
             /*
              * If the old name is a definition, the new one has pn_defn set.
              * Make the old name a use of the new node.
              */
-            if (opn->pn_defn) {
-                opn->pn_defn = false;
+            if (opn->isDefn()) {
+                opn->setDefn(false);
                 LinkUseToDef(opn, (JSDefinition *) pn, tc);
             }
         }
         break;
 
       case PN_NAMESET:
         pn->pn_names = opn->pn_names;
         NULLCHECK(pn->pn_tree = CloneParseTree(opn->pn_tree, tc));
@@ -4424,19 +4421,19 @@ CloneParseTree(JSParseNode *opn, JSTreeC
 
 static JSParseNode *
 ContainsStmt(JSParseNode *pn, TokenKind tt)
 {
     JSParseNode *pn2, *pnt;
 
     if (!pn)
         return NULL;
-    if (PN_TYPE(pn) == tt)
+    if (pn->isKind(tt))
         return pn;
-    switch (pn->pn_arity) {
+    switch (pn->getArity()) {
       case PN_LIST:
         for (pn2 = pn->pn_head; pn2; pn2 = pn2->pn_next) {
             pnt = ContainsStmt(pn2, tt);
             if (pnt)
                 return pnt;
         }
         break;
       case PN_TERNARY:
@@ -4447,24 +4444,24 @@ ContainsStmt(JSParseNode *pn, TokenKind 
         if (pnt)
             return pnt;
         return ContainsStmt(pn->pn_kid3, tt);
       case PN_BINARY:
         /*
          * Limit recursion if pn is a binary expression, which can't contain a
          * var statement.
          */
-        if (pn->pn_op != JSOP_NOP)
+        if (!pn->isOp(JSOP_NOP))
             return NULL;
         pnt = ContainsStmt(pn->pn_left, tt);
         if (pnt)
             return pnt;
         return ContainsStmt(pn->pn_right, tt);
       case PN_UNARY:
-        if (pn->pn_op != JSOP_NOP)
+        if (!pn->isOp(JSOP_NOP))
             return NULL;
         return ContainsStmt(pn->pn_kid, tt);
       case PN_NAME:
         return ContainsStmt(pn->maybeExpr(), tt);
       case PN_NAMESET:
         return ContainsStmt(pn->pn_tree, tt);
       default:;
     }
@@ -4566,18 +4563,18 @@ PushLexicalScope(JSContext *cx, TokenStr
     if (!obj)
         return NULL;
 
     blockbox = tc->parser->newObjectBox(obj);
     if (!blockbox)
         return NULL;
 
     js_PushBlockScope(tc, stmt, blockbox, -1);
-    pn->pn_type = TOK_LEXICALSCOPE;
-    pn->pn_op = JSOP_LEAVEBLOCK;
+    pn->setKind(TOK_LEXICALSCOPE);
+    pn->setOp(JSOP_LEAVEBLOCK);
     pn->pn_objbox = blockbox;
     pn->pn_cookie.makeFree();
     pn->pn_dflags = 0;
     if (!GenerateBlockId(tc, stmt->blockid))
         return NULL;
     pn->pn_blockid = stmt->blockid;
     return pn;
 }
@@ -4630,34 +4627,34 @@ Parser::letBlock(JSBool statement)
         /*
          * If this is really an expression in let statement guise, then we
          * need to wrap the TOK_LET node in a TOK_SEMI node so that we pop
          * the return value of the expression.
          */
         pn = UnaryNode::create(tc);
         if (!pn)
             return NULL;
-        pn->pn_type = TOK_SEMI;
+        pn->setKind(TOK_SEMI);
         pn->pn_num = -1;
         pn->pn_kid = pnblock;
 
         statement = JS_FALSE;
     }
 
     if (statement) {
         pnlet->pn_right = statements();
         if (!pnlet->pn_right)
             return NULL;
         MUST_MATCH_TOKEN(TOK_RC, JSMSG_CURLY_AFTER_LET);
     } else {
         /*
          * Change pnblock's opcode to the variant that propagates the last
          * result down after popping the block, and clear statement.
          */
-        pnblock->pn_op = JSOP_LEAVEBLOCKEXPR;
+        pnblock->setOp(JSOP_LEAVEBLOCKEXPR);
         pnlet->pn_right = assignExpr();
         if (!pnlet->pn_right)
             return NULL;
     }
 
     PopStatement(tc);
     return pn;
 }
@@ -4681,17 +4678,17 @@ NewBindingNode(JSAtom *atom, JSTreeConte
         JS_ASSERT(!pn->isPlaceholder());
     } else {
         removal = tc->lexdeps->lookup(atom);
         pn = removal ? removal.value() : NULL;
         JS_ASSERT_IF(pn, pn->isPlaceholder());
     }
 
     if (pn) {
-        JS_ASSERT(pn->pn_defn);
+        JS_ASSERT(pn->isDefn());
 
         /*
          * A let binding at top level becomes a var before we get here, so if
          * pn and tc have the same blockid then that id must not be the bodyid.
          * If pn is a forward placeholder definition from the same or a higher
          * block then we claim it.
          */
         JS_ASSERT_IF(let && pn->pn_blockid == tc->blockid(),
@@ -4790,17 +4787,17 @@ Parser::switchStatement()
             reportErrorNumber(NULL, JSREPORT_ERROR, JSMSG_BAD_SWITCH);
             return NULL;
         }
         MUST_MATCH_TOKEN(TOK_COLON, JSMSG_COLON_AFTER_CASE);
 
         JSParseNode *pn4 = ListNode::create(tc);
         if (!pn4)
             return NULL;
-        pn4->pn_type = TOK_LC;
+        pn4->setKind(TOK_LC);
         pn4->makeEmpty();
         while ((tt = tokenStream.peekToken(TSF_OPERAND)) != TOK_RC &&
                tt != TOK_CASE && tt != TOK_DEFAULT) {
             if (tt == TOK_ERROR)
                 return NULL;
             pn5 = statement();
             if (!pn5)
                 return NULL;
@@ -4843,75 +4840,75 @@ Parser::switchStatement()
  * the original tree.
  */
 static JSParseNode *
 CloneLeftHandSide(JSParseNode *opn, JSTreeContext *tc)
 {
     JSParseNode *pn = NewOrRecycledNode(tc);
     if (!pn)
         return NULL;
-    pn->pn_type = opn->pn_type;
+    pn->setKind(opn->getKind());
+    pn->setOp(opn->getOp());
+    pn->setUsed(opn->isUsed());
+    pn->setDefn(opn->isDefn());
+    pn->setArity(opn->getArity());
+    pn->setInParens(opn->isInParens());
     pn->pn_pos = opn->pn_pos;
-    pn->pn_op = opn->pn_op;
-    pn->pn_used = opn->pn_used;
-    pn->pn_defn = opn->pn_defn;
-    pn->pn_arity = opn->pn_arity;
-    pn->pn_parens = opn->pn_parens;
 
 #if JS_HAS_DESTRUCTURING
-    if (opn->pn_arity == PN_LIST) {
-        JS_ASSERT(opn->pn_type == TOK_RB || opn->pn_type == TOK_RC);
+    if (opn->isArity(PN_LIST)) {
+        JS_ASSERT(opn->isKind(TOK_RB) || opn->isKind(TOK_RC));
         pn->makeEmpty();
         for (JSParseNode *opn2 = opn->pn_head; opn2; opn2 = opn2->pn_next) {
             JSParseNode *pn2;
-            if (opn->pn_type == TOK_RC) {
-                JS_ASSERT(opn2->pn_arity == PN_BINARY);
-                JS_ASSERT(opn2->pn_type == TOK_COLON);
+            if (opn->isKind(TOK_RC)) {
+                JS_ASSERT(opn2->isArity(PN_BINARY));
+                JS_ASSERT(opn2->isKind(TOK_COLON));
 
                 JSParseNode *tag = CloneParseTree(opn2->pn_left, tc);
                 if (!tag)
                     return NULL;
                 JSParseNode *target = CloneLeftHandSide(opn2->pn_right, tc);
                 if (!target)
                     return NULL;
                 pn2 = BinaryNode::create(TOK_COLON, JSOP_INITPROP, opn2->pn_pos, tag, target, tc);
-            } else if (opn2->pn_arity == PN_NULLARY) {
-                JS_ASSERT(opn2->pn_type == TOK_COMMA);
+            } else if (opn2->isArity(PN_NULLARY)) {
+                JS_ASSERT(opn2->isKind(TOK_COMMA));
                 pn2 = CloneParseTree(opn2, tc);
             } else {
                 pn2 = CloneLeftHandSide(opn2, tc);
             }
 
             if (!pn2)
                 return NULL;
             pn->append(pn2);
         }
         pn->pn_xflags = opn->pn_xflags;
         return pn;
     }
 #endif
 
-    JS_ASSERT(opn->pn_arity == PN_NAME);
-    JS_ASSERT(opn->pn_type == TOK_NAME);
+    JS_ASSERT(opn->isArity(PN_NAME));
+    JS_ASSERT(opn->isKind(TOK_NAME));
 
     /* If opn is a definition or use, make pn a use. */
     pn->pn_u.name = opn->pn_u.name;
-    pn->pn_op = JSOP_SETNAME;
-    if (opn->pn_used) {
+    pn->setOp(JSOP_SETNAME);
+    if (opn->isUsed()) {
         JSDefinition *dn = pn->pn_lexdef;
 
         pn->pn_link = dn->dn_uses;
         dn->dn_uses = pn;
     } else {
         pn->pn_expr = NULL;
-        if (opn->pn_defn) {
+        if (opn->isDefn()) {
             /* We copied some definition-specific state into pn. Clear it out. */
             pn->pn_cookie.makeFree();
             pn->pn_dflags &= ~PND_BOUND;
-            pn->pn_defn = false;
+            pn->setDefn(false);
 
             LinkUseToDef(pn, (JSDefinition *) opn, tc);
         }
     }
     return pn;
 }
 
 JSParseNode *
@@ -4925,17 +4922,17 @@ Parser::forStatement()
 
     /* A FOR node is binary, left is loop control and right is the body. */
     JSParseNode *pn = BinaryNode::create(tc);
     if (!pn)
         return NULL;
     JSStmtInfo stmtInfo;
     js_PushStatement(tc, &stmtInfo, STMT_FOR_LOOP, -1);
 
-    pn->pn_op = JSOP_ITER;
+    pn->setOp(JSOP_ITER);
     pn->pn_iflags = 0;
     if (tokenStream.matchToken(TOK_NAME)) {
         if (tokenStream.currentToken().t_atom == context->runtime->atomState.eachAtom)
             pn->pn_iflags = JSITER_FOREACH;
         else
             tokenStream.ungetToken();
     }
 
@@ -5013,46 +5010,46 @@ Parser::forStatement()
          * Here pn1 is everything to the left of 'in'. At the end of this block,
          * pn1 is a decl or NULL, pn2 is the assignment target that receives the
          * enumeration value each iteration, and pn3 is the rhs of 'in'.
          */
         pn->pn_iflags |= JSITER_ENUMERATE;
         stmtInfo.type = STMT_FOR_IN_LOOP;
 
         /* Check that the left side of the 'in' is valid. */
-        JS_ASSERT(!TokenKindIsDecl(tt) || PN_TYPE(pn1) == tt);
+        JS_ASSERT(!TokenKindIsDecl(tt) || pn1->isKind(tt));
         if (TokenKindIsDecl(tt)
-            ? (pn1->pn_count > 1 || pn1->pn_op == JSOP_DEFCONST
+            ? (pn1->pn_count > 1 || pn1->isOp(JSOP_DEFCONST)
 #if JS_HAS_DESTRUCTURING
                || (versionNumber() == JSVERSION_1_7 &&
-                   pn->pn_op == JSOP_ITER &&
+                   pn->isOp(JSOP_ITER) &&
                    !(pn->pn_iflags & JSITER_FOREACH) &&
-                   (pn1->pn_head->pn_type == TOK_RC ||
-                    (pn1->pn_head->pn_type == TOK_RB &&
+                   (pn1->pn_head->isKind(TOK_RC) ||
+                    (pn1->pn_head->isKind(TOK_RB) &&
                      pn1->pn_head->pn_count != 2) ||
-                    (pn1->pn_head->pn_type == TOK_ASSIGN &&
-                     (pn1->pn_head->pn_left->pn_type != TOK_RB ||
+                    (pn1->pn_head->isKind(TOK_ASSIGN) &&
+                     (!pn1->pn_head->pn_left->isKind(TOK_RB) ||
                       pn1->pn_head->pn_left->pn_count != 2))))
 #endif
               )
-            : (pn1->pn_type != TOK_NAME &&
-               pn1->pn_type != TOK_DOT &&
+            : (!pn1->isKind(TOK_NAME) &&
+               !pn1->isKind(TOK_DOT) &&
 #if JS_HAS_DESTRUCTURING
                ((versionNumber() == JSVERSION_1_7 &&
-                 pn->pn_op == JSOP_ITER &&
+                 pn->isOp(JSOP_ITER) &&
                  !(pn->pn_iflags & JSITER_FOREACH))
-                ? (pn1->pn_type != TOK_RB || pn1->pn_count != 2)
-                : (pn1->pn_type != TOK_RB && pn1->pn_type != TOK_RC)) &&
+                ? (!pn1->isKind(TOK_RB) || pn1->pn_count != 2)
+                : (!pn1->isKind(TOK_RB) && !pn1->isKind(TOK_RC))) &&
 #endif
-               pn1->pn_type != TOK_LP &&
+               !pn1->isKind(TOK_LP) &&
 #if JS_HAS_XML_SUPPORT
-               (pn1->pn_type != TOK_UNARYOP ||
-                pn1->pn_op != JSOP_XMLNAME) &&
+               (!pn1->isKind(TOK_UNARYOP) ||
+                !pn1->isOp(JSOP_XMLNAME)) &&
 #endif
-               pn1->pn_type != TOK_LB)) {
+               !pn1->isKind(TOK_LB))) {
             reportErrorNumber(pn1, JSREPORT_ERROR, JSMSG_BAD_FOR_LEFTSIDE);
             return NULL;
         }
 
         /*
          * After the following if-else, pn2 will point to the name or
          * destructuring pattern on in's left. pn1 will point to the decl, if
          * any, else NULL. Note that the "declaration with initializer" case
@@ -5060,19 +5057,19 @@ Parser::forStatement()
          */
         pn2 = NULL;
         uintN dflag = PND_ASSIGNED;
         if (TokenKindIsDecl(tt)) {
             /* Tell EmitVariables that pn1 is part of a for/in. */
             pn1->pn_xflags |= PNX_FORINVAR;
 
             pn2 = pn1->pn_head;
-            if ((pn2->pn_type == TOK_NAME && pn2->maybeExpr())
+            if ((pn2->isKind(TOK_NAME) && pn2->maybeExpr())
 #if JS_HAS_DESTRUCTURING
-                || pn2->pn_type == TOK_ASSIGN
+                || pn2->isKind(TOK_ASSIGN)
 #endif
                 ) {
                 /*
                  * Declaration with initializer.
                  *
                  * Rewrite 'for (<decl> x = i in o)' where <decl> is 'var' or
                  * 'const' to hoist the initializer or the entire decl out of
                  * the loop head. TOK_VAR is the type for both 'var' and 'const'.
@@ -5082,17 +5079,17 @@ Parser::forStatement()
                     reportErrorNumber(pn2, JSREPORT_ERROR, JSMSG_INVALID_FOR_IN_INIT);
                     return NULL;
                 }
 #endif /* JS_HAS_BLOCK_SCOPE */
 
                 pnseq = ListNode::create(tc);
                 if (!pnseq)
                     return NULL;
-                pnseq->pn_type = TOK_SEQ;
+                pnseq->setKind(TOK_SEQ);
                 pnseq->pn_pos.begin = pn->pn_pos.begin;
 
                 dflag = PND_INITIALIZED;
 
                 /*
                  * All of 'var x = i' is hoisted above 'for (x in o)',
                  * so clear PNX_FORINVAR.
                  *
@@ -5100,20 +5097,20 @@ Parser::forStatement()
                  * name (it is not a destructuring binding's left-hand
                  * side) and it has an initializer.
                  */
                 pn1->pn_xflags &= ~PNX_FORINVAR;
                 pn1->pn_xflags |= PNX_POPVAR;
                 pnseq->initList(pn1);
 
 #if JS_HAS_DESTRUCTURING
-                if (pn2->pn_type == TOK_ASSIGN) {
+                if (pn2->isKind(TOK_ASSIGN)) {
                     pn2 = pn2->pn_left;
-                    JS_ASSERT(pn2->pn_type == TOK_RB || pn2->pn_type == TOK_RC ||
-                              pn2->pn_type == TOK_NAME);
+                    JS_ASSERT(pn2->isKind(TOK_RB) || pn2->isKind(TOK_RC) ||
+                              pn2->isKind(TOK_NAME));
                 }
 #endif
                 pn1 = NULL;
             }
 
             /*
              * pn2 is part of a declaration. Make a copy that can be passed to
              * EmitAssignment.
@@ -5125,17 +5122,17 @@ Parser::forStatement()
             /* Not a declaration. */
             pn2 = pn1;
             pn1 = NULL;
 
             if (!setAssignmentLhsOps(pn2, JSOP_NOP))
                 return NULL;
         }
 
-        switch (pn2->pn_type) {
+        switch (pn2->getKind()) {
           case TOK_NAME:
             /* Beware 'for (arguments in ...)' with or without a 'var'. */
             NoteLValue(context, pn2, tc, dflag);
             break;
 
 #if JS_HAS_DESTRUCTURING
           case TOK_ASSIGN:
             JS_NOT_REACHED("forStatement TOK_ASSIGN");
@@ -5143,17 +5140,17 @@ Parser::forStatement()
 
           case TOK_RB:
           case TOK_RC:
             if (versionNumber() == JSVERSION_1_7) {
                 /*
                  * Destructuring for-in requires [key, value] enumeration
                  * in JS1.7.
                  */
-                JS_ASSERT(pn->pn_op == JSOP_ITER);
+                JS_ASSERT(pn->isOp(JSOP_ITER));
                 if (!(pn->pn_iflags & JSITER_FOREACH))
                     pn->pn_iflags |= JSITER_FOREACH | JSITER_KEYVALUE;
             }
             break;
 #endif
 
           default:;
         }
@@ -5171,23 +5168,23 @@ Parser::forStatement()
         pn3 = expr();
         if (!pn3)
             return NULL;
 #if JS_HAS_BLOCK_SCOPE
         if (let)
             tc->topStmt = save;
 #endif
 
-        pn4->pn_type = TOK_IN;
+        pn4->setKind(TOK_IN);
     } else {
         if (pn->pn_iflags & JSITER_FOREACH) {
             reportErrorNumber(pn, JSREPORT_ERROR, JSMSG_BAD_FOR_EACH_LOOP);
             return NULL;
         }
-        pn->pn_op = JSOP_NOP;
+        pn->setOp(JSOP_NOP);
 
         /* Parse the loop condition or null into pn2. */
         MUST_MATCH_TOKEN(TOK_SEMI, JSMSG_SEMI_AFTER_FOR_INIT);
         tt = tokenStream.peekToken(TSF_OPERAND);
         if (tt == TOK_SEMI) {
             pn2 = NULL;
         } else {
             pn2 = expr();
@@ -5201,19 +5198,19 @@ Parser::forStatement()
         if (tt == TOK_RP) {
             pn3 = NULL;
         } else {
             pn3 = expr();
             if (!pn3)
                 return NULL;
         }
 
-        pn4->pn_type = TOK_FORHEAD;
-    }
-    pn4->pn_op = JSOP_NOP;
+        pn4->setKind(TOK_FORHEAD);
+    }
+    pn4->setOp(JSOP_NOP);
     pn4->pn_kid1 = pn1;
     pn4->pn_kid2 = pn2;
     pn4->pn_kid3 = pn3;
     pn->pn_left = pn4;
 
     MUST_MATCH_TOKEN(TOK_RP, JSMSG_PAREN_AFTER_FOR_CTRL);
 
     /* Parse the loop body into pn->pn_right. */
@@ -5261,17 +5258,17 @@ Parser::tryStatement()
      *   TOK_NAME for a single identifier
      *   TOK_RB or TOK_RC for a destructuring left-hand side
      *
      * finally nodes are TOK_LC statement lists.
      */
     JSParseNode *pn = TernaryNode::create(tc);
     if (!pn)
         return NULL;
-    pn->pn_op = JSOP_NOP;
+    pn->setOp(JSOP_NOP);
 
     MUST_MATCH_TOKEN(TOK_LC, JSMSG_CURLY_BEFORE_TRY);
     JSStmtInfo stmtInfo;
     if (!PushBlocklikeStatement(&stmtInfo, STMT_TRY, tc))
         return NULL;
     pn->pn_kid1 = statements();
     if (!pn->pn_kid1)
         return NULL;
@@ -5279,17 +5276,17 @@ Parser::tryStatement()
     PopStatement(tc);
 
     catchList = NULL;
     TokenKind tt = tokenStream.getToken();
     if (tt == TOK_CATCH) {
         catchList = ListNode::create(tc);
         if (!catchList)
             return NULL;
-        catchList->pn_type = TOK_RESERVED;
+        catchList->setKind(TOK_RESERVED);
         catchList->makeEmpty();
         lastCatch = NULL;
 
         do {
             JSParseNode *pnblock;
             BindData data;
 
             /* Check for another catch after unconditional catch. */
@@ -5467,22 +5464,21 @@ Parser::letStatement()
 {
     JSObjectBox *blockbox;
 
     JSParseNode *pn;
     do {
         /* Check for a let statement or let expression. */
         if (tokenStream.peekToken() == TOK_LP) {
             pn = letBlock(JS_TRUE);
-            if (!pn || pn->pn_op == JSOP_LEAVEBLOCK)
+            if (!pn || pn->isOp(JSOP_LEAVEBLOCK))
                 return pn;
 
             /* Let expressions require automatic semicolon insertion. */
-            JS_ASSERT(pn->pn_type == TOK_SEMI ||
-                      pn->pn_op == JSOP_LEAVEBLOCKEXPR);
+            JS_ASSERT(pn->isKind(TOK_SEMI) || pn->isOp(JSOP_LEAVEBLOCKEXPR));
             break;
         }
 
         /*
          * This is a let declaration. We must be directly under a block per
          * the proposed ES4 specs, but not an implicit block created due to
          * 'for (let ...)'. If we pass this error test, make the enclosing
          * JSStmtInfo be our scope. Further let declarations in this block
@@ -5550,26 +5546,26 @@ Parser::letStatement()
 
             obj->setParent(tc->blockChain());
             blockbox->parent = tc->blockChainBox;
             tc->blockChainBox = blockbox;
             stmt->blockBox = blockbox;
 
 #ifdef DEBUG
             JSParseNode *tmp = tc->blockNode;
-            JS_ASSERT(!tmp || tmp->pn_type != TOK_LEXICALSCOPE);
+            JS_ASSERT(!tmp || !tmp->isKind(TOK_LEXICALSCOPE));
 #endif
 
             /* Create a new lexical scope node for these statements. */
             JSParseNode *pn1 = LexicalScopeNode::create(tc);
             if (!pn1)
                 return NULL;
 
-            pn1->pn_type = TOK_LEXICALSCOPE;
-            pn1->pn_op = JSOP_LEAVEBLOCK;
+            pn1->setKind(TOK_LEXICALSCOPE);
+            pn1->setOp(JSOP_LEAVEBLOCK);
             pn1->pn_pos = tc->blockNode->pn_pos;
             pn1->pn_objbox = blockbox;
             pn1->pn_expr = tc->blockNode;
             pn1->pn_blockid = tc->blockNode->pn_blockid;
             tc->blockNode = pn1;
         }
 
         pn = variables(false);
@@ -5587,17 +5583,17 @@ JSParseNode *
 Parser::expressionStatement()
 {
     tokenStream.ungetToken();
     JSParseNode *pn2 = expr();
     if (!pn2)
         return NULL;
 
     if (tokenStream.peekToken() == TOK_COLON) {
-        if (pn2->pn_type != TOK_NAME) {
+        if (!pn2->isKind(TOK_NAME)) {
             reportErrorNumber(NULL, JSREPORT_ERROR, JSMSG_BAD_LABEL);
             return NULL;
         }
         JSAtom *label = pn2->pn_atom;
         for (JSStmtInfo *stmt = tc->topStmt; stmt; stmt = stmt->down) {
             if (stmt->type == STMT_LABEL && stmt->label == label) {
                 reportErrorNumber(NULL, JSREPORT_ERROR, JSMSG_DUPLICATE_LABEL);
                 return NULL;
@@ -5611,61 +5607,61 @@ Parser::expressionStatement()
         JSStmtInfo stmtInfo;
         js_PushStatement(tc, &stmtInfo, STMT_LABEL, -1);
         stmtInfo.label = label;
         JSParseNode *pn = statement();
         if (!pn)
             return NULL;
 
         /* Normalize empty statement to empty block for the decompiler. */
-        if (pn->pn_type == TOK_SEMI && !pn->pn_kid) {
-            pn->pn_type = TOK_LC;
-            pn->pn_arity = PN_LIST;
+        if (pn->isKind(TOK_SEMI) && !pn->pn_kid) {
+            pn->setKind(TOK_LC);
+            pn->setArity(PN_LIST);
             pn->makeEmpty();
         }
 
         /* Pop the label, set pn_expr, and return early. */
         PopStatement(tc);
-        pn2->pn_type = TOK_COLON;
+        pn2->setKind(TOK_COLON);
         pn2->pn_pos.end = pn->pn_pos.end;
         pn2->pn_expr = pn;
         return pn2;
     }
 
     JSParseNode *pn = UnaryNode::create(tc);
     if (!pn)
         return NULL;
-    pn->pn_type = TOK_SEMI;
+    pn->setKind(TOK_SEMI);
     pn->pn_pos = pn2->pn_pos;
     pn->pn_kid = pn2;
 
-    switch (PN_TYPE(pn2)) {
+    switch (pn2->getKind()) {
       case TOK_LP:
         /*
          * Flag lambdas immediately applied as statements as instances of
          * the JS "module pattern". See CheckForImmediatelyAppliedLambda.
          */
-        if (PN_TYPE(pn2->pn_head) == TOK_FUNCTION &&
+        if (pn2->pn_head->isKind(TOK_FUNCTION) &&
             !pn2->pn_head->pn_funbox->node->isFunArg()) {
             pn2->pn_head->pn_funbox->tcflags |= TCF_FUN_MODULE_PATTERN;
         }
         break;
       case TOK_ASSIGN:
         /*
          * Keep track of all apparent methods created by assignments such
          * as this.foo = function (...) {...} in a function that could end
          * up a constructor function. See Parser::setFunctionKinds.
          */
         if (tc->funbox &&
-            PN_OP(pn2) == JSOP_NOP &&
-            PN_OP(pn2->pn_left) == JSOP_SETPROP &&
-            PN_OP(pn2->pn_left->pn_expr) == JSOP_THIS &&
-            PN_OP(pn2->pn_right) == JSOP_LAMBDA) {
-            JS_ASSERT(!pn2->pn_defn);
-            JS_ASSERT(!pn2->pn_used);
+            pn2->isOp(JSOP_NOP) &&
+            pn2->pn_left->isOp(JSOP_SETPROP) &&
+            pn2->pn_left->pn_expr->isOp(JSOP_THIS) &&
+            pn2->pn_right->isOp(JSOP_LAMBDA)) {
+            JS_ASSERT(!pn2->isDefn());
+            JS_ASSERT(!pn2->isUsed());
             pn2->pn_right->pn_link = tc->funbox->methods;
             tc->funbox->methods = pn2->pn_right;
         }
         break;
       default:;
     }
 
     /* Check termination of this primitive statement. */
@@ -5795,17 +5791,17 @@ Parser::statement()
             reportErrorNumber(NULL, JSREPORT_ERROR, JSMSG_SYNTAX_ERROR);
             return NULL;
         }
 
         JSParseNode *pn2 = expr();
         if (!pn2)
             return NULL;
         pn->pn_pos.end = pn2->pn_pos.end;
-        pn->pn_op = JSOP_THROW;
+        pn->setOp(JSOP_THROW);
         pn->pn_kid = pn2;
         break;
       }
 
       /* TOK_CATCH and TOK_FINALLY are both handled in the TOK_TRY case */
       case TOK_CATCH:
         reportErrorNumber(NULL, JSREPORT_ERROR, JSMSG_CATCH_WITHOUT_TRY);
         return NULL;
@@ -5939,24 +5935,24 @@ Parser::statement()
         tc->flags = oldflags | (tc->flags & (TCF_FUN_FLAGS | TCF_RETURN_FLAGS));
         return pn;
       }
 
       case TOK_SEMI:
         pn = UnaryNode::create(tc);
         if (!pn)
             return NULL;
-        pn->pn_type = TOK_SEMI;
+        pn->setKind(TOK_SEMI);
         return pn;
 
       case TOK_DEBUGGER:
         pn = NullaryNode::create(tc);
         if (!pn)
             return NULL;
-        pn->pn_type = TOK_DEBUGGER;
+        pn->setKind(TOK_DEBUGGER);
         tc->flags |= TCF_FUN_HEAVYWEIGHT;
         break;
 
 #if JS_HAS_XML_SUPPORT
       case TOK_DEFAULT:
       {
         pn = UnaryNode::create(tc);
         if (!pn)
@@ -5971,17 +5967,17 @@ Parser::statement()
             return NULL;
         }
 
         /* Is this an E4X dagger I see before me? */
         tc->flags |= TCF_FUN_HEAVYWEIGHT;
         JSParseNode *pn2 = expr();
         if (!pn2)
             return NULL;
-        pn->pn_op = JSOP_DEFXMLNS;
+        pn->setOp(JSOP_DEFXMLNS);
         pn->pn_pos.end = pn2->pn_pos.end;
         pn->pn_kid = pn2;
         break;
       }
 #endif
 
       case TOK_ERROR:
         return NULL;
@@ -6031,17 +6027,17 @@ Parser::variables(bool inLetHead)
         }
         JS_ASSERT(scopeStmt);
     }
 
     data.op = let ? JSOP_NOP : tokenStream.currentToken().t_op;
     pn = ListNode::create(tc);
     if (!pn)
         return NULL;
-    pn->pn_op = data.op;
+    pn->setOp(data.op);
     pn->makeEmpty();
 
     /*
      * SpiderMonkey const is really "write once per initialization evaluation"
      * var, whereas let is block scoped. ES-Harmony wants block-scoped const so
      * this code will change soon.
      */
     if (let) {
@@ -6131,33 +6127,33 @@ Parser::variables(bool inLetHead)
             if (popScope) {
                 tc->topStmt = save;
                 tc->topScopeStmt = saveScope;
             }
 #endif
             if (!init)
                 return NULL;
 
-            if (pn2->pn_used) {
+            if (pn2->isUsed()) {
                 pn2 = MakeAssignment(pn2, init, tc);
                 if (!pn2)
                     return NULL;
             } else {
                 pn2->pn_expr = init;
             }
 
             JS_ASSERT_IF(pn2->pn_dflags & PND_GVAR, !(pn2->pn_dflags & PND_BOUND));
 
-            pn2->pn_op = (PN_OP(pn2) == JSOP_ARGUMENTS)
-                         ? JSOP_SETNAME
-                         : (pn2->pn_dflags & PND_BOUND)
-                         ? JSOP_SETLOCAL
-                         : (data.op == JSOP_DEFCONST)
-                         ? JSOP_SETCONST
-                         : JSOP_SETNAME;
+            pn2->setOp(pn2->isOp(JSOP_ARGUMENTS)
+                       ? JSOP_SETNAME
+                       : (pn2->pn_dflags & PND_BOUND)
+                       ? JSOP_SETLOCAL
+                       : (data.op == JSOP_DEFCONST)
+                       ? JSOP_SETCONST
+                       : JSOP_SETNAME);
 
             NoteLValue(context, pn2, tc, data.fresh ? PND_INITIALIZED : PND_ASSIGNED);
 
             /* The declarator's position must include the initializer. */
             pn2->pn_pos.end = init->pn_pos.end;
 
             if (tc->inFunction() &&
                 atom == context->runtime->atomState.argumentsAtom) {
@@ -6185,17 +6181,17 @@ Parser::expr()
         if (!pn2)
             return NULL;
         pn2->pn_pos.begin = pn->pn_pos.begin;
         pn2->initList(pn);
         pn = pn2;
         do {
 #if JS_HAS_GENERATORS
             pn2 = pn->last();
-            if (pn2->pn_type == TOK_YIELD && !pn2->pn_parens) {
+            if (pn2->isKind(TOK_YIELD) && !pn2->isInParens()) {
                 reportErrorNumber(pn2, JSREPORT_ERROR, JSMSG_BAD_GENERATOR_SYNTAX, js_yield_str);
                 return NULL;
             }
 #endif
             pn2 = assignExpr();
             if (!pn2)
                 return NULL;
             pn->append(pn2);
@@ -6383,28 +6379,28 @@ Parser::condExpr1()
         tokenStream.getToken();     /* need to read one token past the end */
     }
     return pn;
 }
 
 bool
 Parser::setAssignmentLhsOps(JSParseNode *pn, JSOp op)
 {
-    switch (pn->pn_type) {
+    switch (pn->getKind()) {
       case TOK_NAME:
         if (!CheckStrictAssignment(context, tc, pn))
             return false;
-        pn->pn_op = (pn->pn_op == JSOP_GETLOCAL) ? JSOP_SETLOCAL : JSOP_SETNAME;
+        pn->setOp(pn->isOp(JSOP_GETLOCAL) ? JSOP_SETLOCAL : JSOP_SETNAME);
         NoteLValue(context, pn, tc);
         break;
       case TOK_DOT:
-        pn->pn_op = JSOP_SETPROP;
+        pn->setOp(JSOP_SETPROP);
         break;
       case TOK_LB:
-        pn->pn_op = JSOP_SETELEM;
+        pn->setOp(JSOP_SETELEM);
         break;
 #if JS_HAS_DESTRUCTURING
       case TOK_RB:
       case TOK_RC:
         if (op != JSOP_NOP) {
             reportErrorNumber(NULL, JSREPORT_ERROR, JSMSG_BAD_DESTRUCT_ASS);
             return false;
         }
@@ -6413,18 +6409,18 @@ Parser::setAssignmentLhsOps(JSParseNode 
         break;
 #endif
       case TOK_LP:
         if (!MakeSetCall(context, pn, tc, JSMSG_BAD_LEFTSIDE_OF_ASS))
             return false;
         break;
 #if JS_HAS_XML_SUPPORT
       case TOK_UNARYOP:
-        if (pn->pn_op == JSOP_XMLNAME) {
-            pn->pn_op = JSOP_SETXMLNAME;
+        if (pn->isOp(JSOP_XMLNAME)) {
+            pn->setOp(JSOP_SETXMLNAME);
             break;
         }
         /* FALL THROUGH */
 #endif
       default:
         reportErrorNumber(NULL, JSREPORT_ERROR, JSMSG_BAD_LEFTSIDE_OF_ASS);
         return false;
     }
@@ -6452,17 +6448,17 @@ Parser::assignExpr()
 
     JSOp op = tokenStream.currentToken().t_op;
     if (!setAssignmentLhsOps(pn, op))
         return NULL;
 
     JSParseNode *rhs = assignExpr();
     if (!rhs)
         return NULL;
-    if (PN_TYPE(pn) == TOK_NAME && pn->pn_used) {
+    if (pn->isKind(TOK_NAME) && pn->isUsed()) {
         JSDefinition *dn = pn->pn_lexdef;
 
         /*
          * If the definition is not flagged as assigned, we must have imputed
          * the initialized flag to it, to optimize for flat closures. But that
          * optimization uses source coordinates to check dominance relations,
          * so we must extend the end of the definition to cover the right-hand
          * side of this assignment, i.e., the initializer.
@@ -6475,25 +6471,25 @@ Parser::assignExpr()
 
     return JSParseNode::newBinaryOrAppend(TOK_ASSIGN, op, pn, rhs, tc);
 }
 
 static JSParseNode *
 SetLvalKid(JSContext *cx, TokenStream *ts, JSTreeContext *tc,
            JSParseNode *pn, JSParseNode *kid, const char *name)
 {
-    if (kid->pn_type != TOK_NAME &&
-        kid->pn_type != TOK_DOT &&
-        (kid->pn_type != TOK_LP ||
-         (kid->pn_op != JSOP_CALL && kid->pn_op != JSOP_EVAL &&
-          kid->pn_op != JSOP_FUNCALL && kid->pn_op != JSOP_FUNAPPLY)) &&
+    if (!kid->isKind(TOK_NAME) &&
+        !kid->isKind(TOK_DOT) &&
+        (!kid->isKind(TOK_LP) ||
+         (!kid->isOp(JSOP_CALL) && !kid->isOp(JSOP_EVAL) &&
+          !kid->isOp(JSOP_FUNCALL) && !kid->isOp(JSOP_FUNAPPLY))) &&
 #if JS_HAS_XML_SUPPORT
-        (kid->pn_type != TOK_UNARYOP || kid->pn_op != JSOP_XMLNAME) &&
+        (!kid->isKind(TOK_UNARYOP) || !kid->isOp(JSOP_XMLNAME)) &&
 #endif
-        kid->pn_type != TOK_LB) {
+        !kid->isKind(TOK_LB)) {
         ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR, JSMSG_BAD_OPERAND, name);
         return NULL;
     }
     if (!CheckStrictAssignment(cx, tc, kid))
         return NULL;
     pn->pn_kid = kid;
     return kid;
 }
@@ -6505,17 +6501,17 @@ SetIncOpKid(JSContext *cx, TokenStream *
             JSParseNode *pn, JSParseNode *kid,
             TokenKind tt, JSBool preorder)
 {
     JSOp op;
 
     kid = SetLvalKid(cx, ts, tc, pn, kid, incop_name_str[tt == TOK_DEC]);
     if (!kid)
         return JS_FALSE;
-    switch (kid->pn_type) {
+    switch (kid->getKind()) {
       case TOK_NAME:
         op = (tt == TOK_INC)
              ? (preorder ? JSOP_INCNAME : JSOP_NAMEINC)
              : (preorder ? JSOP_DECNAME : JSOP_NAMEDEC);
         NoteLValue(cx, kid, tc);
         break;
 
       case TOK_DOT:
@@ -6525,31 +6521,31 @@ SetIncOpKid(JSContext *cx, TokenStream *
         break;
 
       case TOK_LP:
         if (!MakeSetCall(cx, kid, tc, JSMSG_BAD_INCOP_OPERAND))
             return JS_FALSE;
         /* FALL THROUGH */
 #if JS_HAS_XML_SUPPORT
       case TOK_UNARYOP:
-        if (kid->pn_op == JSOP_XMLNAME)
-            kid->pn_op = JSOP_SETXMLNAME;
+        if (kid->isOp(JSOP_XMLNAME))
+            kid->setOp(JSOP_SETXMLNAME);
         /* FALL THROUGH */
 #endif
       case TOK_LB:
         op = (tt == TOK_INC)
              ? (preorder ? JSOP_INCELEM : JSOP_ELEMINC)
              : (preorder ? JSOP_DECELEM : JSOP_ELEMDEC);
         break;
 
       default:
         JS_ASSERT(0);
         op = JSOP_NOP;
     }
-    pn->pn_op = op;
+    pn->setOp(op);
     return JS_TRUE;
 }
 
 JSParseNode *
 Parser::unaryExpr()
 {
     JSParseNode *pn, *pn2;
 
@@ -6558,18 +6554,18 @@ Parser::unaryExpr()
     TokenKind tt = tokenStream.getToken(TSF_OPERAND);
     switch (tt) {
       case TOK_UNARYOP:
       case TOK_PLUS:
       case TOK_MINUS:
         pn = UnaryNode::create(tc);
         if (!pn)
             return NULL;
-        pn->pn_type = TOK_UNARYOP;      /* PLUS and MINUS are binary */
-        pn->pn_op = tokenStream.currentToken().t_op;
+        pn->setKind(TOK_UNARYOP);      /* PLUS and MINUS are binary */
+        pn->setOp(tokenStream.currentToken().t_op);
         pn2 = unaryExpr();
         if (!pn2)
             return NULL;
         pn->pn_pos.end = pn2->pn_pos.end;
         pn->pn_kid = pn2;
         break;
 
       case TOK_INC:
@@ -6597,34 +6593,34 @@ Parser::unaryExpr()
 
         /*
          * Under ECMA3, deleting any unary expression is valid -- it simply
          * returns true. Here we fold constants before checking for a call
          * expression, in order to rule out delete of a generator expression.
          */
         if (foldConstants && !js_FoldConstants(context, pn2, tc))
             return NULL;
-        switch (pn2->pn_type) {
+        switch (pn2->getKind()) {
           case TOK_LP:
             if (!(pn2->pn_xflags & PNX_SETCALL)) {
                 /*
                  * Call MakeSetCall to check for errors, but clear PNX_SETCALL
                  * because the optimizer will eliminate the useless delete.
                  */
                 if (!MakeSetCall(context, pn2, tc, JSMSG_BAD_DELETE_OPERAND))
                     return NULL;
                 pn2->pn_xflags &= ~PNX_SETCALL;
             }
             break;
           case TOK_NAME:
             if (!ReportStrictModeError(context, &tokenStream, tc, pn,
                                        JSMSG_DEPRECATED_DELETE_OPERAND)) {
                 return NULL;
             }
-            pn2->pn_op = JSOP_DELNAME;
+            pn2->setOp(JSOP_DELNAME);
             if (pn2->pn_atom == context->runtime->atomState.argumentsAtom) {
                 tc->flags |= TCF_FUN_HEAVYWEIGHT;
                 tc->countArgumentsUse(pn2);
             }
             break;
           default:;
         }
         pn->pn_kid = pn2;
@@ -6821,29 +6817,29 @@ BumpStaticLevel(JSParseNode *pn, JSTreeC
         pn->pn_cookie.set(level, pn->pn_cookie.slot());
     }
     return true;
 }
 
 static void
 AdjustBlockId(JSParseNode *pn, uintN adjust, JSTreeContext *tc)
 {
-    JS_ASSERT(pn->pn_arity == PN_LIST || pn->pn_arity == PN_FUNC || pn->pn_arity == PN_NAME);
+    JS_ASSERT(pn->isArity(PN_LIST) || pn->isArity(PN_FUNC) || pn->isArity(PN_NAME));
     pn->pn_blockid += adjust;
     if (pn->pn_blockid >= tc->blockidGen)
         tc->blockidGen = pn->pn_blockid + 1;
 }
 
 bool
 CompExprTransplanter::transplant(JSParseNode *pn)
 {
     if (!pn)
         return true;
 
-    switch (pn->pn_arity) {
+    switch (pn->getArity()) {
       case PN_LIST:
         for (JSParseNode *pn2 = pn->pn_head; pn2; pn2 = pn2->pn_next) {
             if (!transplant(pn2))
                 return false;
         }
         if (pn->pn_pos >= root->pn_pos)
             AdjustBlockId(pn, adjust, tc);
         break;
@@ -6900,28 +6896,28 @@ CompExprTransplanter::transplant(JSParse
             funbox->level = tc->staticLevel;
         }
         /* FALL THROUGH */
       }
 
       case PN_NAME:
         if (!transplant(pn->maybeExpr()))
             return false;
-        if (pn->pn_arity == PN_FUNC)
+        if (pn->isArity(PN_FUNC))
             --funcLevel;
 
-        if (pn->pn_defn) {
+        if (pn->isDefn()) {
             if (genexp && !BumpStaticLevel(pn, tc))
                 return false;
-        } else if (pn->pn_used) {
-            JS_ASSERT(pn->pn_op != JSOP_NOP);
+        } else if (pn->isUsed()) {
+            JS_ASSERT(!pn->isOp(JSOP_NOP));
             JS_ASSERT(pn->pn_cookie.isFree());
 
             JSDefinition *dn = pn->pn_lexdef;
-            JS_ASSERT(dn->pn_defn);
+            JS_ASSERT(dn->isDefn());
 
             /*
              * Adjust the definition's block id only if it is a placeholder not
              * to the left of the root node, and if pn is the last use visited
              * in the comprehension expression (to avoid adjusting the blockid
              * multiple times).
              *
              * Non-placeholder definitions within the comprehension expression
@@ -6933,17 +6929,17 @@ CompExprTransplanter::transplant(JSParse
                 AdjustBlockId(dn, adjust, tc);
             }
 
             JSAtom *atom = pn->pn_atom;
 #ifdef DEBUG
             JSStmtInfo *stmt = js_LexicalLookup(tc, atom, NULL);
             JS_ASSERT(!stmt || stmt != tc->topStmt);
 #endif
-            if (genexp && PN_OP(dn) != JSOP_CALLEE) {
+            if (genexp && !dn->isOp(JSOP_CALLEE)) {
                 JS_ASSERT(!tc->decls.lookupFirst(atom));
 
                 if (dn->pn_pos < root->pn_pos) {
                     /*
                      * The variable originally appeared to be a use of a
                      * definition or placeholder outside the generator, but now
                      * we know it is scoped within the comprehension tail's
                      * clauses. Make it (along with any other uses within the
@@ -6987,16 +6983,20 @@ CompExprTransplanter::transplant(JSParse
         if (pn->pn_pos >= root->pn_pos)
             AdjustBlockId(pn, adjust, tc);
         break;
 
       case PN_NAMESET:
         if (!transplant(pn->pn_tree))
             return false;
         break;
+
+      case PN_NULLARY:
+        /* Nothing. */
+        break;
     }
     return true;
 }
 
 /*
  * Starting from a |for| keyword after the first array initialiser element or
  * an expression in an open parenthesis, parse the tail of the comprehension
  * or generator expression signified by this |for| keyword in context.
@@ -7071,17 +7071,17 @@ Parser::comprehensionTail(JSParseNode *k
          * FOR node is binary, left is loop control and right is body.  Use
          * index to count each block-local let-variable on the left-hand side
          * of the IN.
          */
         pn2 = BinaryNode::create(tc);
         if (!pn2)
             return NULL;
 
-        pn2->pn_op = JSOP_ITER;
+        pn2->setOp(JSOP_ITER);
         pn2->pn_iflags = JSITER_ENUMERATE;
         if (tokenStream.matchToken(TOK_NAME)) {
             if (tokenStream.currentToken().t_atom == context->runtime->atomState.eachAtom)
                 pn2->pn_iflags |= JSITER_FOREACH;
             else
                 tokenStream.ungetToken();
         }
         MUST_MATCH_TOKEN(TOK_LP, JSMSG_PAREN_AFTER_FOR);
@@ -7144,22 +7144,22 @@ Parser::comprehensionTail(JSParseNode *k
 #if JS_HAS_DESTRUCTURING
           case TOK_LB:
           case TOK_LC:
             if (!CheckDestructuring(context, &data, pn3, tc))
                 return NULL;
 
             if (versionNumber() == JSVERSION_1_7) {
                 /* Destructuring requires [key, value] enumeration in JS1.7. */
-                if (pn3->pn_type != TOK_RB || pn3->pn_count != 2) {
+                if (!pn3->isKind(TOK_RB) || pn3->pn_count != 2) {
                     reportErrorNumber(NULL, JSREPORT_ERROR, JSMSG_BAD_FOR_LEFTSIDE);
                     return NULL;
                 }
 
-                JS_ASSERT(pn2->pn_op == JSOP_ITER);
+                JS_ASSERT(pn2->isOp(JSOP_ITER));
                 JS_ASSERT(pn2->pn_iflags & JSITER_ENUMERATE);
                 if (!(pn2->pn_iflags & JSITER_FOREACH))
                     pn2->pn_iflags |= JSITER_FOREACH | JSITER_KEYVALUE;
             }
             break;
 #endif
 
           case TOK_NAME:
@@ -7173,18 +7173,18 @@ Parser::comprehensionTail(JSParseNode *k
 
         /*
          * Synthesize a declaration. Every definition must appear in the parse
          * tree in order for ComprehensionTranslator to work.
          */
         JSParseNode *vars = ListNode::create(tc);
         if (!vars)
             return NULL;
-        vars->pn_op = JSOP_NOP;
-        vars->pn_type = TOK_VAR;
+        vars->setOp(JSOP_NOP);
+        vars->setKind(TOK_VAR);
         vars->pn_pos = pn3->pn_pos;
         vars->makeEmpty();
         vars->append(pn3);
         vars->pn_xflags |= PNX_FORINVAR;
 
         /* Definitions can't be passed directly to EmitAssignment as lhs. */
         pn3 = CloneLeftHandSide(pn3, tc);
         if (!pn3)
@@ -7206,18 +7206,18 @@ Parser::comprehensionTail(JSParseNode *k
             return NULL;
         *pnp = pn2;
         pnp = &pn2->pn_kid2;
     }
 
     pn2 = UnaryNode::create(tc);
     if (!pn2)
         return NULL;
-    pn2->pn_type = type;
-    pn2->pn_op = op;
+    pn2->setKind(type);
+    pn2->setOp(op);
     pn2->pn_kid = kid;
     *pnp = pn2;
 
     PopStatement(tc);
     return pn;
 }
 
 #if JS_HAS_GENERATOR_EXPRS
@@ -7239,29 +7239,29 @@ Parser::comprehensionTail(JSParseNode *k
  */
 JSParseNode *
 Parser::generatorExpr(JSParseNode *kid)
 {
     /* Create a |yield| node for |kid|. */
     JSParseNode *pn = UnaryNode::create(tc);
     if (!pn)
         return NULL;
-    pn->pn_type = TOK_YIELD;
-    pn->pn_op = JSOP_YIELD;
-    pn->pn_parens = true;
+    pn->setKind(TOK_YIELD);
+    pn->setOp(JSOP_YIELD);
+    pn->setInParens(true);
     pn->pn_pos = kid->pn_pos;
     pn->pn_kid = kid;
     pn->pn_hidden = true;
 
     /* Make a new node for the desugared generator function. */
     JSParseNode *genfn = FunctionNode::create(tc);
     if (!genfn)
         return NULL;
-    genfn->pn_type = TOK_FUNCTION;
-    genfn->pn_op = JSOP_LAMBDA;
+    genfn->setKind(TOK_FUNCTION);
+    genfn->setOp(JSOP_LAMBDA);
     JS_ASSERT(!genfn->pn_body);
     genfn->pn_dflags = PND_FUNARG;
 
     {
         JSTreeContext *outertc = tc;
         JSTreeContext gentc(tc->parser);
         if (!gentc.init(context))
             return NULL;
@@ -7310,18 +7310,18 @@ Parser::generatorExpr(JSParseNode *kid)
 
     /*
      * Our result is a call expression that invokes the anonymous generator
      * function object.
      */
     JSParseNode *result = ListNode::create(tc);
     if (!result)
         return NULL;
-    result->pn_type = TOK_LP;
-    result->pn_op = JSOP_CALL;
+    result->setKind(TOK_LP);
+    result->setOp(JSOP_CALL);
     result->pn_pos.begin = genfn->pn_pos.begin;
     result->initList(genfn);
     return result;
 }
 
 static const char js_generator_str[] = "generator";
 
 #endif /* JS_HAS_GENERATOR_EXPRS */
@@ -7339,18 +7339,18 @@ Parser::argumentList(JSParseNode *listNo
     do {
         JSParseNode *argNode = assignExpr();
         if (!argNode)
             return JS_FALSE;
         if (arg0)
             guard.endBody();
 
 #if JS_HAS_GENERATORS
-        if (argNode->pn_type == TOK_YIELD &&
-            !argNode->pn_parens &&
+        if (argNode->isKind(TOK_YIELD) &&
+            !argNode->isInParens() &&
             tokenStream.peekToken() == TOK_COMMA) {
             reportErrorNumber(argNode, JSREPORT_ERROR, JSMSG_BAD_GENERATOR_SYNTAX, js_yield_str);
             return JS_FALSE;
         }
 #endif
 #if JS_HAS_GENERATOR_EXPRS
         if (tokenStream.matchToken(TOK_FOR)) {
             if (!guard.checkValidBody(argNode))
@@ -7380,18 +7380,18 @@ Parser::argumentList(JSParseNode *listNo
     }
     return JS_TRUE;
 }
 
 /* Check for an immediately-applied (new'ed) lambda and clear PND_FUNARG. */
 static JSParseNode *
 CheckForImmediatelyAppliedLambda(JSParseNode *pn)
 {
-    if (pn->pn_type == TOK_FUNCTION) {
-        JS_ASSERT(pn->pn_arity == PN_FUNC);
+    if (pn->isKind(TOK_FUNCTION)) {
+        JS_ASSERT(pn->isArity(PN_FUNC));
 
         JSFunctionBox *funbox = pn->pn_funbox;
         JS_ASSERT((funbox->function())->flags & JSFUN_LAMBDA);
         if (!(funbox->tcflags & (TCF_FUN_USES_ARGUMENTS | TCF_FUN_USES_OWN_NAME)))
             pn->pn_dflags &= ~PND_FUNARG;
     }
     return pn;
 }
@@ -7408,44 +7408,42 @@ Parser::memberExpr(JSBool allowCallSynta
     if (tt == TOK_NEW) {
         pn = ListNode::create(tc);
         if (!pn)
             return NULL;
         pn2 = memberExpr(JS_FALSE);
         if (!pn2)
             return NULL;
         pn2 = CheckForImmediatelyAppliedLambda(pn2);
-        pn->pn_op = JSOP_NEW;
+        pn->setOp(JSOP_NEW);
         pn->initList(pn2);
         pn->pn_pos.begin = pn2->pn_pos.begin;
 
         if (tokenStream.matchToken(TOK_LP) && !argumentList(pn))
             return NULL;
         if (pn->pn_count > ARGC_LIMIT) {
             JS_ReportErrorNumber(context, js_GetErrorMessage, NULL,
                                  JSMSG_TOO_MANY_CON_ARGS);
             return NULL;
         }
         pn->pn_pos.end = pn->last()->pn_pos.end;
     } else {
         pn = primaryExpr(tt, JS_FALSE);
         if (!pn)
             return NULL;
 
-        if (pn->pn_type == TOK_ANYNAME ||
-            pn->pn_type == TOK_AT ||
-            pn->pn_type == TOK_DBLCOLON) {
+        if (pn->isKind(TOK_ANYNAME) || pn->isKind(TOK_AT) || pn->isKind(TOK_DBLCOLON)) {
             pn2 = NewOrRecycledNode(tc);
             if (!pn2)
                 return NULL;
-            pn2->pn_type = TOK_UNARYOP;
+            pn2->setKind(TOK_UNARYOP);
             pn2->pn_pos = pn->pn_pos;
-            pn2->pn_op = JSOP_XMLNAME;
-            pn2->pn_arity = PN_UNARY;
-            pn2->pn_parens = false;
+            pn2->setOp(JSOP_XMLNAME);
+            pn2->setArity(PN_UNARY);
+            pn2->setInParens(false);
             pn2->pn_kid = pn;
             pn = pn2;
         }
     }
 
     while ((tt = tokenStream.getToken()) > TOK_EOF) {
         if (tt == TOK_DOT) {
             pn2 = NameNode::create(NULL, tc);
@@ -7467,66 +7465,66 @@ Parser::memberExpr(JSBool allowCallSynta
                 return NULL;
 
             if (tt == TOK_LP) {
                 tc->innermostWith = oldWith;
                 PopStatement(tc);
             }
 
             /* Check both tt and pn_type, to distinguish |x.(y)| and |x.y::z| from |x.y|. */
-            if (tt == TOK_NAME && pn3->pn_type == TOK_NAME) {
-                pn2->pn_op = JSOP_GETPROP;
+            if (tt == TOK_NAME && pn3->isKind(TOK_NAME)) {
+                pn2->setOp(JSOP_GETPROP);
                 pn2->pn_expr = pn;
                 pn2->pn_atom = pn3->pn_atom;
                 RecycleTree(pn3, tc);
             } else {
                 if (tt == TOK_LP) {
-                    pn2->pn_type = TOK_FILTER;
-                    pn2->pn_op = JSOP_FILTER;
+                    pn2->setKind(TOK_FILTER);
+                    pn2->setOp(JSOP_FILTER);
 
                     /* A filtering predicate is like a with statement. */
                     tc->flags |= TCF_FUN_HEAVYWEIGHT;
-                } else if (TokenKindIsXML(PN_TYPE(pn3))) {
-                    pn2->pn_type = TOK_LB;
-                    pn2->pn_op = JSOP_GETELEM;
+                } else if (TokenKindIsXML(pn3->getKind())) {
+                    pn2->setKind(TOK_LB);
+                    pn2->setOp(JSOP_GETELEM);
                 } else {
                     reportErrorNumber(NULL, JSREPORT_ERROR, JSMSG_NAME_AFTER_DOT);
                     return NULL;
                 }
-                pn2->pn_arity = PN_BINARY;
+                pn2->setArity(PN_BINARY);
                 pn2->pn_left = pn;
                 pn2->pn_right = pn3;
             }
 #else
             MUST_MATCH_TOKEN_WITH_FLAGS(TOK_NAME, JSMSG_NAME_AFTER_DOT, TSF_KEYWORD_IS_NAME);
-            pn2->pn_op = JSOP_GETPROP;
+            pn2->setOp(JSOP_GETPROP);
             pn2->pn_expr = pn;
             pn2->pn_atom = tokenStream.currentToken().t_atom;
 #endif
             pn2->pn_pos.begin = pn->pn_pos.begin;
             pn2->pn_pos.end = tokenStream.currentToken().pos.end;
 #if JS_HAS_XML_SUPPORT
         } else if (tt == TOK_DBLDOT) {
             pn2 = BinaryNode::create(tc);
             if (!pn2)
                 return NULL;
             tt = tokenStream.getToken(TSF_OPERAND | TSF_KEYWORD_IS_NAME);
             pn3 = primaryExpr(tt, JS_TRUE);
             if (!pn3)
                 return NULL;
-            tt = PN_TYPE(pn3);
-            if (tt == TOK_NAME && !pn3->pn_parens) {
-                pn3->pn_type = TOK_STRING;
-                pn3->pn_arity = PN_NULLARY;
-                pn3->pn_op = JSOP_QNAMEPART;
+            tt = pn3->getKind();
+            if (tt == TOK_NAME && !pn3->isInParens()) {
+                pn3->setKind(TOK_STRING);
+                pn3->setArity(PN_NULLARY);
+                pn3->setOp(JSOP_QNAMEPART);
             } else if (!TokenKindIsXML(tt)) {
                 reportErrorNumber(NULL, JSREPORT_ERROR, JSMSG_NAME_AFTER_DOT);
                 return NULL;
             }
-            pn2->pn_op = JSOP_DESCENDANTS;
+            pn2->setOp(JSOP_DESCENDANTS);
             pn2->pn_left = pn;
             pn2->pn_right = pn3;
             pn2->pn_pos.begin = pn->pn_pos.begin;
             pn2->pn_pos.end = tokenStream.currentToken().pos.end;
 #endif
         } else if (tt == TOK_LB) {
             pn2 = BinaryNode::create(tc);
             if (!pn2)
@@ -7542,61 +7540,61 @@ Parser::memberExpr(JSBool allowCallSynta
             /*
              * Optimize o['p'] to o.p by rewriting pn2, but avoid rewriting
              * o['0'] to use JSOP_GETPROP, to keep fast indexing disjoint in
              * the interpreter from fast property access. However, if the
              * bracketed string is a uint32, we rewrite pn3 to be a number
              * instead of a string.
              */
             do {
-                if (pn3->pn_type == TOK_STRING) {
+                if (pn3->isKind(TOK_STRING)) {
                     jsuint index;
 
                     if (!js_IdIsIndex(ATOM_TO_JSID(pn3->pn_atom), &index)) {
-                        pn2->pn_type = TOK_DOT;
-                        pn2->pn_op = JSOP_GETPROP;
-                        pn2->pn_arity = PN_NAME;
+                        pn2->setKind(TOK_DOT);
+                        pn2->setOp(JSOP_GETPROP);
+                        pn2->setArity(PN_NAME);
                         pn2->pn_expr = pn;
                         pn2->pn_atom = pn3->pn_atom;
                         break;
                     }
-                    pn3->pn_type = TOK_NUMBER;
-                    pn3->pn_op = JSOP_DOUBLE;
+                    pn3->setKind(TOK_NUMBER);
+                    pn3->setOp(JSOP_DOUBLE);
                     pn3->pn_dval = index;
                 }
-                pn2->pn_op = JSOP_GETELEM;
+                pn2->setOp(JSOP_GETELEM);
                 pn2->pn_left = pn;
                 pn2->pn_right = pn3;
             } while (0);
         } else if (allowCallSyntax && tt == TOK_LP) {
             pn2 = ListNode::create(tc);
             if (!pn2)
                 return NULL;
-            pn2->pn_op = JSOP_CALL;
+            pn2->setOp(JSOP_CALL);
 
             pn = CheckForImmediatelyAppliedLambda(pn);
-            if (pn->pn_op == JSOP_NAME) {
+            if (pn->isOp(JSOP_NAME)) {
                 if (pn->pn_atom == context->runtime->atomState.evalAtom) {
                     /* Select JSOP_EVAL and flag tc as heavyweight. */
-                    pn2->pn_op = JSOP_EVAL;
+                    pn2->setOp(JSOP_EVAL);
                     tc->noteCallsEval();
                     tc->flags |= TCF_FUN_HEAVYWEIGHT;
                     /*
                      * In non-strict mode code, direct calls to eval can add
                      * variables to the call object.
                      */
                     if (!tc->inStrictMode())
                         tc->noteHasExtensibleScope();
                 }
-            } else if (pn->pn_op == JSOP_GETPROP) {
+            } else if (pn->isOp(JSOP_GETPROP)) {
                 /* Select JSOP_FUNAPPLY given foo.apply(...). */
                 if (pn->pn_atom == context->runtime->atomState.applyAtom)
-                    pn2->pn_op = JSOP_FUNAPPLY;
+                    pn2->setOp(JSOP_FUNAPPLY);
                 else if (pn->pn_atom == context->runtime->atomState.callAtom)
-                    pn2->pn_op = JSOP_FUNCALL;
+                    pn2->setOp(JSOP_FUNCALL);
             }
 
             pn2->initList(pn);
             pn2->pn_pos.begin = pn->pn_pos.begin;
 
             if (!argumentList(pn2))
                 return NULL;
             if (pn2->pn_count > ARGC_LIMIT) {
@@ -7704,24 +7702,24 @@ Parser::endBracketedExpr()
 JSParseNode *
 Parser::propertySelector()
 {
     JSParseNode *pn;
 
     pn = NullaryNode::create(tc);
     if (!pn)
         return NULL;
-    if (pn->pn_type == TOK_STAR) {
-        pn->pn_type = TOK_ANYNAME;
-        pn->pn_op = JSOP_ANYNAME;
+    if (pn->isKind(TOK_STAR)) {
+        pn->setKind(TOK_ANYNAME);
+        pn->setOp(JSOP_ANYNAME);
         pn->pn_atom = context->runtime->atomState.starAtom;
     } else {
-        JS_ASSERT(pn->pn_type == TOK_NAME);
-        pn->pn_op = JSOP_QNAMEPART;
-        pn->pn_arity = PN_NAME;
+        JS_ASSERT(pn->isKind(TOK_NAME));
+        pn->setOp(JSOP_QNAMEPART);
+        pn->setArity(PN_NAME);
         pn->pn_atom = tokenStream.currentToken().t_atom;
         pn->pn_cookie.makeFree();
     }
     return pn;
 }
 
 JSParseNode *
 Parser::qualifiedSuffix(JSParseNode *pn)
@@ -7730,23 +7728,23 @@ Parser::qualifiedSuffix(JSParseNode *pn)
     TokenKind tt;
 
     JS_ASSERT(tokenStream.currentToken().type == TOK_DBLCOLON);
     pn2 = NameNode::create(NULL, tc);
     if (!pn2)
         return NULL;
 
     /* Left operand of :: must be evaluated if it is an identifier. */
-    if (pn->pn_op == JSOP_QNAMEPART)
-        pn->pn_op = JSOP_NAME;
+    if (pn->isOp(JSOP_QNAMEPART))
+        pn->setOp(JSOP_NAME);
 
     tt = tokenStream.getToken(TSF_KEYWORD_IS_NAME);
     if (tt == TOK_STAR || tt == TOK_NAME) {
         /* Inline and specialize propertySelector for JSOP_QNAMECONST. */
-        pn2->pn_op = JSOP_QNAMECONST;
+        pn2->setOp(JSOP_QNAMECONST);
         pn2->pn_pos.begin = pn->pn_pos.begin;
         pn2->pn_atom = (tt == TOK_STAR)
                        ? context->runtime->atomState.starAtom
                        : tokenStream.currentToken().t_atom;
         pn2->pn_expr = pn;
         pn2->pn_cookie.makeFree();
         return pn2;
     }
@@ -7754,18 +7752,18 @@ Parser::qualifiedSuffix(JSParseNode *pn)
     if (tt != TOK_LB) {
         reportErrorNumber(NULL, JSREPORT_ERROR, JSMSG_SYNTAX_ERROR);
         return NULL;
     }
     pn3 = endBracketedExpr();
     if (!pn3)
         return NULL;
 
-    pn2->pn_op = JSOP_QNAME;
-    pn2->pn_arity = PN_BINARY;
+    pn2->setOp(JSOP_QNAME);
+    pn2->setArity(PN_BINARY);
     pn2->pn_pos.begin = pn->pn_pos.begin;
     pn2->pn_pos.end = pn3->pn_pos.end;
     pn2->pn_left = pn;
     pn2->pn_right = pn3;
     return pn2;
 }
 
 JSParseNode *
@@ -7789,17 +7787,17 @@ Parser::attributeIdentifier()
 {
     JSParseNode *pn, *pn2;
     TokenKind tt;
 
     JS_ASSERT(tokenStream.currentToken().type == TOK_AT);
     pn = UnaryNode::create(tc);
     if (!pn)
         return NULL;
-    pn->pn_op = JSOP_TOATTRNAME;
+    pn->setOp(JSOP_TOATTRNAME);
     tt = tokenStream.getToken(TSF_KEYWORD_IS_NAME);
     if (tt == TOK_STAR || tt == TOK_NAME) {
         pn2 = qualifiedIdentifier();
     } else if (tt == TOK_LB) {
         pn2 = endBracketedExpr();
     } else {
         reportErrorNumber(NULL, JSREPORT_ERROR, JSMSG_SYNTAX_ERROR);
         return NULL;
@@ -7833,34 +7831,34 @@ Parser::xmlExpr(JSBool inTag)
     tokenStream.setXMLTagMode(false);
     pn2 = expr();
     if (!pn2)
         return NULL;
 
     MUST_MATCH_TOKEN(TOK_RC, JSMSG_CURLY_IN_XML_EXPR);
     tokenStream.setXMLTagMode(oldflag);
     pn->pn_kid = pn2;
-    pn->pn_op = inTag ? JSOP_XMLTAGEXPR : JSOP_XMLELTEXPR;
+    pn->setOp(inTag ? JSOP_XMLTAGEXPR : JSOP_XMLELTEXPR);
     return pn;
 }
 
 /*
  * Make a terminal node for one of TOK_XMLNAME, TOK_XMLATTR, TOK_XMLSPACE,
  * TOK_XMLTEXT, TOK_XMLCDATA, TOK_XMLCOMMENT, or TOK_XMLPI.  When converting
  * parse tree to XML, we preserve a TOK_XMLSPACE node only if it's the sole
  * child of a container tag.
  */
 JSParseNode *
 Parser::xmlAtomNode()
 {
     JSParseNode *pn = NullaryNode::create(tc);
     if (!pn)
         return NULL;
     const Token &tok = tokenStream.currentToken();
-    pn->pn_op = tok.t_op;
+    pn->setOp(tok.t_op);
     pn->pn_atom = tok.t_atom;
     if (tok.type == TOK_XMLPI)
         pn->pn_atom2 = tok.t_atom2;
     return pn;
 }
 
 /*
  * Parse the productions:
@@ -7896,17 +7894,17 @@ Parser::xmlNameExpr()
 
         if (!pn) {
             pn = pn2;
         } else {
             if (!list) {
                 list = ListNode::create(tc);
                 if (!list)
                     return NULL;
-                list->pn_type = TOK_XMLNAME;
+                list->setKind(TOK_XMLNAME);
                 list->pn_pos.begin = pn->pn_pos.begin;
                 list->initList(pn);
                 list->pn_xflags = PNX_CANTFOLD;
                 pn = list;
             }
             pn->pn_pos.end = pn2->pn_pos.end;
             pn->append(pn2);
         }
@@ -7915,19 +7913,19 @@ Parser::xmlNameExpr()
     tokenStream.ungetToken();
     return pn;
 }
 
 /*
  * Macro to test whether an XMLNameExpr or XMLTagContent node can be folded
  * at compile time into a JSXML tree.
  */
-#define XML_FOLDABLE(pn)        ((pn)->pn_arity == PN_LIST                    \
-                                 ? ((pn)->pn_xflags & PNX_CANTFOLD) == 0      \
-                                 : (pn)->pn_type != TOK_LC)
+#define XML_FOLDABLE(pn)        ((pn)->isArity(PN_LIST)                     \
+                                 ? ((pn)->pn_xflags & PNX_CANTFOLD) == 0    \
+                                 : !(pn)->isKind(TOK_LC))
 
 /*
  * Parse the productions:
  *
  *      XMLTagContent:
  *              XMLNameExpr
  *              XMLTagContent S XMLNameExpr S? = S? XMLAttr
  *              XMLTagContent S XMLNameExpr S? = S? { Expr }
@@ -7945,34 +7943,34 @@ JSParseNode *
 Parser::xmlTagContent(TokenKind tagtype, JSAtom **namep)
 {
     JSParseNode *pn, *pn2, *list;
     TokenKind tt;
 
     pn = xmlNameExpr();
     if (!pn)
         return NULL;
-    *namep = (pn->pn_arity == PN_NULLARY) ? pn->pn_atom : NULL;
+    *namep = (pn->isArity(PN_NULLARY)) ? pn->pn_atom : NULL;
     list = NULL;
 
     while (tokenStream.matchToken(TOK_XMLSPACE)) {
         tt = tokenStream.getToken();
         if (tt != TOK_XMLNAME && tt != TOK_LC) {
             tokenStream.ungetToken();
             break;
         }
 
         pn2 = xmlNameExpr();
         if (!pn2)
             return NULL;
         if (!list) {
             list = ListNode::create(tc);
             if (!list)
                 return NULL;
-            list->pn_type = tagtype;
+            list->setKind(tagtype);
             list->pn_pos.begin = pn->pn_pos.begin;
             list->initList(pn);
             pn = list;
         }
         pn->append(pn2);
         if (!XML_FOLDABLE(pn2))
             pn->pn_xflags |= PNX_CANTFOLD;
 
@@ -8092,50 +8090,50 @@ Parser::xmlElementOrList(JSBool allowLis
         pn2 = xmlTagContent(TOK_XMLSTAGO, &startAtom);
         if (!pn2)
             return NULL;
         tokenStream.matchToken(TOK_XMLSPACE);
 
         tt = tokenStream.getToken();
         if (tt == TOK_XMLPTAGC) {
             /* Point tag (/>): recycle pn if pn2 is a list of tag contents. */
-            if (pn2->pn_type == TOK_XMLSTAGO) {
+            if (pn2->isKind(TOK_XMLSTAGO)) {
                 pn->makeEmpty();
                 RecycleTree(pn, tc);
                 pn = pn2;
             } else {
-                JS_ASSERT(pn2->pn_type == TOK_XMLNAME ||
-                          pn2->pn_type == TOK_LC);
+                JS_ASSERT(pn2->isKind(TOK_XMLNAME) ||
+                          pn2->isKind(TOK_LC));
                 pn->initList(pn2);
                 if (!XML_FOLDABLE(pn2))
                     pn->pn_xflags |= PNX_CANTFOLD;
             }
-            pn->pn_type = TOK_XMLPTAGC;
+            pn->setKind(TOK_XMLPTAGC);
             pn->pn_xflags |= PNX_XMLROOT;
         } else {
             /* We had better have a tag-close (>) at this point. */
             if (tt != TOK_XMLTAGC) {
                 reportErrorNumber(NULL, JSREPORT_ERROR, JSMSG_BAD_XML_TAG_SYNTAX);
                 return NULL;
             }
             pn2->pn_pos.end = tokenStream.currentToken().pos.end;
 
             /* Make sure pn2 is a TOK_XMLSTAGO list containing tag contents. */
-            if (pn2->pn_type != TOK_XMLSTAGO) {
+            if (!pn2->isKind(TOK_XMLSTAGO)) {
                 pn->initList(pn2);
                 if (!XML_FOLDABLE(pn2))
                     pn->pn_xflags |= PNX_CANTFOLD;
                 pn2 = pn;
                 pn = ListNode::create(tc);
                 if (!pn)
                     return NULL;
             }
 
             /* Now make pn a nominal-root TOK_XMLELEM list containing pn2. */
-            pn->pn_type = TOK_XMLELEM;
+            pn->setKind(TOK_XMLELEM);
             pn->pn_pos.begin = pn2->pn_pos.begin;
             pn->initList(pn2);
             if (!XML_FOLDABLE(pn2))
                 pn->pn_xflags |= PNX_CANTFOLD;
             pn->pn_xflags |= PNX_XMLROOT;
 
             /* Get element contents and delimiting end-tag-open sequence. */
             if (!xmlElementContent(pn))
@@ -8147,51 +8145,51 @@ Parser::xmlElementOrList(JSBool allowLis
                 reportErrorNumber(NULL, JSREPORT_ERROR, JSMSG_BAD_XML_TAG_SYNTAX);
                 return NULL;
             }
 
             /* Parse end tag; check mismatch at compile-time if we can. */
             pn2 = xmlTagContent(TOK_XMLETAGO, &endAtom);
             if (!pn2)
                 return NULL;
-            if (pn2->pn_type == TOK_XMLETAGO) {
+            if (pn2->isKind(TOK_XMLETAGO)) {
                 /* Oops, end tag has attributes! */
                 reportErrorNumber(NULL, JSREPORT_ERROR, JSMSG_BAD_XML_TAG_SYNTAX);
                 return NULL;
             }
             if (endAtom && startAtom && endAtom != startAtom) {
                 /* End vs. start tag name mismatch: point to the tag name. */
                 reportErrorNumber(pn2, JSREPORT_UC | JSREPORT_ERROR, JSMSG_XML_TAG_NAME_MISMATCH,
                                   startAtom->chars());
                 return NULL;
             }
 
             /* Make a TOK_XMLETAGO list with pn2 as its single child. */
-            JS_ASSERT(pn2->pn_type == TOK_XMLNAME || pn2->pn_type == TOK_LC);
+            JS_ASSERT(pn2->isKind(TOK_XMLNAME) || pn2->isKind(TOK_LC));
             list = ListNode::create(tc);
             if (!list)
                 return NULL;
-            list->pn_type = TOK_XMLETAGO;
+            list->setKind(TOK_XMLETAGO);
             list->initList(pn2);
             pn->append(list);
             if (!XML_FOLDABLE(pn2)) {
                 list->pn_xflags |= PNX_CANTFOLD;
                 pn->pn_xflags |= PNX_CANTFOLD;
             }
 
             tokenStream.matchToken(TOK_XMLSPACE);
             MUST_MATCH_TOKEN(TOK_XMLTAGC, JSMSG_BAD_XML_TAG_SYNTAX);
         }
 
         /* Set pn_op now that pn has been updated to its final value. */
-        pn->pn_op = JSOP_TOXML;
+        pn->setOp(JSOP_TOXML);
     } else if (allowList && tt == TOK_XMLTAGC) {
         /* XMLList Initialiser. */
-        pn->pn_type = TOK_XMLLIST;
-        pn->pn_op = JSOP_TOXMLLIST;
+        pn->setKind(TOK_XMLLIST);
+        pn->setOp(JSOP_TOXMLLIST);
         pn->makeEmpty();
         pn->pn_xflags |= PNX_XMLROOT;
         if (!xmlElementContent(pn))
             return NULL;
 
         MUST_MATCH_TOKEN(TOK_XMLTAGC, JSMSG_BAD_XML_LIST_SYNTAX);
     } else {
         reportErrorNumber(NULL, JSREPORT_ERROR, JSMSG_BAD_XML_NAME_SYNTAX);
@@ -8297,17 +8295,17 @@ JSParseNode::isConstant()
           case JSOP_FALSE:
           case JSOP_TRUE:
             return true;
           default:
             return false;
         }
       case TOK_RB:
       case TOK_RC:
-        return (pn_op == JSOP_NEWINIT) && !(pn_xflags & PNX_NONCONST);
+        return isOp(JSOP_NEWINIT) && !(pn_xflags & PNX_NONCONST);
       default:
         return false;
     }
 }
 
 JSParseNode *
 Parser::primaryExpr(TokenKind tt, JSBool afterDot)
 {
@@ -8318,17 +8316,17 @@ Parser::primaryExpr(TokenKind tt, JSBool
 
     switch (tt) {
       case TOK_FUNCTION:
 #if JS_HAS_XML_SUPPORT
         if (tokenStream.matchToken(TOK_DBLCOLON, TSF_KEYWORD_IS_NAME)) {
             pn2 = NullaryNode::create(tc);
             if (!pn2)
                 return NULL;
-            pn2->pn_type = TOK_FUNCTION;
+            pn2->setKind(TOK_FUNCTION);
             pn = qualifiedSuffix(pn2);
             if (!pn)
                 return NULL;
             break;
         }
 #endif
         pn = functionExpr();
         if (!pn)
@@ -8338,18 +8336,18 @@ Parser::primaryExpr(TokenKind tt, JSBool
       case TOK_LB:
       {
         JSBool matched;
         jsuint index;
 
         pn = ListNode::create(tc);
         if (!pn)
             return NULL;
-        pn->pn_type = TOK_RB;
-        pn->pn_op = JSOP_NEWINIT;
+        pn->setKind(TOK_RB);
+        pn->setOp(JSOP_NEWINIT);
         pn->makeEmpty();
 
 #if JS_HAS_GENERATORS
         pn->pn_blockid = tc->blockidGen;
 #endif
 
         matched = tokenStream.matchToken(TOK_RB, TSF_OPERAND);
         if (!matched) {
@@ -8427,17 +8425,17 @@ Parser::primaryExpr(TokenKind tt, JSBool
              * The array comprehension iteration step, array.push(i * j) in
              * the example above, is done by <i * j>; JSOP_ARRAYCOMP <array>,
              * where <array> is the index of array's stack slot.
              */
             if (index == 0 && pn->pn_count != 0 && tokenStream.matchToken(TOK_FOR)) {
                 JSParseNode *pnexp, *pntop;
 
                 /* Relabel pn as an array comprehension node. */
-                pn->pn_type = TOK_ARRAYCOMP;
+                pn->setKind(TOK_ARRAYCOMP);
 
                 /*
                  * Remove the comprehension expression from pn's linked list
                  * and save it via pnexp.  We'll re-install it underneath the
                  * ARRAYPUSH node after we parse the rest of the comprehension.
                  */
                 pnexp = pn->last();
                 JS_ASSERT(pn->pn_count == 1);
@@ -8473,18 +8471,18 @@ Parser::primaryExpr(TokenKind tt, JSBool
             GET     = 0x1,
             SET     = 0x2,
             VALUE   = 0x4 | GET | SET
         };
 
         pn = ListNode::create(tc);
         if (!pn)
             return NULL;
-        pn->pn_type = TOK_RC;
-        pn->pn_op = JSOP_NEWINIT;
+        pn->setKind(TOK_RC);
+        pn->setOp(JSOP_NEWINIT);
         pn->makeEmpty();
 
         for (;;) {
             JSAtom *atom;
             tt = tokenStream.getToken(TSF_KEYWORD_IS_NAME);
             switch (tt) {
               case TOK_NUMBER:
                 pn3 = NullaryNode::create(tc);
@@ -8569,18 +8567,18 @@ Parser::primaryExpr(TokenKind tt, JSBool
 
                 /*
                  * Support, e.g., |var {x, y} = o| as destructuring shorthand
                  * for |var {x: x, y: y} = o|, per proposed JS2/ES4 for JS1.8.
                  */
                 tokenStream.ungetToken();
                 pn->pn_xflags |= PNX_DESTRUCT | PNX_NONCONST;
                 pnval = pn3;
-                if (pnval->pn_type == TOK_NAME) {
-                    pnval->pn_arity = PN_NAME;
+                if (pnval->isKind(TOK_NAME)) {
+                    pnval->setArity(PN_NAME);
                     ((NameNode *)pnval)->initCommon(tc);
                 }
 #endif
             }
 
             pn2 = JSParseNode::newBinaryOrAppend(TOK_COLON, op, pn3, pnval, tc);
           skip:
             if (!pn2)
@@ -8660,21 +8658,21 @@ Parser::primaryExpr(TokenKind tt, JSBool
         pn = UnaryNode::create(tc);
         if (!pn)
             return NULL;
         pn->pn_num = (jsint) tokenStream.currentToken().t_dval;
         tt = tokenStream.getToken(TSF_OPERAND);
         pn->pn_kid = primaryExpr(tt, JS_FALSE);
         if (!pn->pn_kid)
             return NULL;
-        if (PN_TYPE(pn->pn_kid) == TOK_USESHARP ||
-            PN_TYPE(pn->pn_kid) == TOK_DEFSHARP ||
-            PN_TYPE(pn->pn_kid) == TOK_STRING ||
-            PN_TYPE(pn->pn_kid) == TOK_NUMBER ||
-            PN_TYPE(pn->pn_kid) == TOK_PRIMARY) {
+        if (pn->pn_kid->isKind(TOK_USESHARP) ||
+            pn->pn_kid->isKind(TOK_DEFSHARP) ||
+            pn->pn_kid->isKind(TOK_STRING) ||
+            pn->pn_kid->isKind(TOK_NUMBER) ||
+            pn->pn_kid->isKind(TOK_PRIMARY)) {
             reportErrorNumber(pn->pn_kid, JSREPORT_ERROR, JSMSG_BAD_SHARP_VAR_DEF);
             return NULL;
         }
         if (!tc->ensureSharpSlots())
             return NULL;
         break;
 
       case TOK_USESHARP:
@@ -8690,17 +8688,17 @@ Parser::primaryExpr(TokenKind tt, JSBool
 
       case TOK_LP:
       {
         JSBool genexp;
 
         pn = parenExpr(&genexp);
         if (!pn)
             return NULL;
-        pn->pn_parens = true;
+        pn->setInParens(true);
         if (!genexp)
             MUST_MATCH_TOKEN(TOK_RP, JSMSG_PAREN_IN_PAREN);
         break;
       }
 
 #if JS_HAS_XML_SUPPORT
       case TOK_STAR:
         pn = qualifiedIdentifier();
@@ -8735,25 +8733,25 @@ Parser::primaryExpr(TokenKind tt, JSBool
         if (!pn)
             return NULL;
         pn->pn_atom = tokenStream.currentToken().t_atom;
 #if JS_HAS_XML_SUPPORT
         if (tt == TOK_XMLPI)
             pn->pn_atom2 = tokenStream.currentToken().t_atom2;
         else
 #endif
-            pn->pn_op = tokenStream.currentToken().t_op;
+            pn->setOp(tokenStream.currentToken().t_op);
         break;
 
       case TOK_NAME:
         pn = NameNode::create(tokenStream.currentToken().t_atom, tc);
         if (!pn)
             return NULL;
         JS_ASSERT(tokenStream.currentToken().t_op == JSOP_NAME);
-        pn->pn_op = JSOP_NAME;
+        pn->setOp(JSOP_NAME);
 
         if ((tc->flags & (TCF_IN_FUNCTION | TCF_FUN_PARAM_ARGUMENTS)) == TCF_IN_FUNCTION &&
             pn->pn_atom == context->runtime->atomState.argumentsAtom) {
             /*
              * Flag arguments usage so we can avoid unsafe optimizations such
              * as formal parameter assignment analysis (because of the hated
              * feature whereby arguments alias formals). We do this even for
              * a reference of the form foo.arguments, which ancient code may
@@ -8762,17 +8760,17 @@ Parser::primaryExpr(TokenKind tt, JSBool
             tc->noteArgumentsUse(pn);
 
             /*
              * Bind early to JSOP_ARGUMENTS to relieve later code from having
              * to do this work (new rule for the emitter to count on).
              */
             if (!afterDot && !(tc->flags & TCF_DECL_DESTRUCTURING)
                 && !tc->inStatement(STMT_WITH)) {
-                pn->pn_op = JSOP_ARGUMENTS;
+                pn->setOp(JSOP_ARGUMENTS);
                 pn->pn_dflags |= PND_BOUND;
             }
         } else if ((!afterDot
 #if JS_HAS_XML_SUPPORT
                     || tokenStream.peekToken() == TOK_DBLCOLON
 #endif
                    ) && !(tc->flags & TCF_DECL_DESTRUCTURING)) {
             /* In case this is a generator expression outside of any function. */
@@ -8834,17 +8832,17 @@ Parser::primaryExpr(TokenKind tt, JSBool
                      * necessary for safe context->display-based optimiza-
                      * tion of the closure's static link.
                      */
                     if (tokenStream.peekToken() != TOK_LP)
                         dn->pn_dflags |= PND_FUNARG;
                 }
             }
 
-            JS_ASSERT(dn->pn_defn);
+            JS_ASSERT(dn->isDefn());
             LinkUseToDef(pn, dn, tc);
 
             /* Here we handle the backward function reference case. */
             if (tokenStream.peekToken() != TOK_LP)
                 dn->pn_dflags |= PND_FUNARG;
 
             pn->pn_dflags |= (dn->pn_dflags & PND_FUNARG);
             if (stmt && stmt->type == STMT_WITH)
@@ -8861,18 +8859,18 @@ Parser::primaryExpr(TokenKind tt, JSBool
                  */
                 const KeywordInfo *ki = FindKeyword(pn->pn_atom->charsZ(), pn->pn_atom->length());
                 if (ki) {
                     if (ki->tokentype != TOK_FUNCTION) {
                         reportErrorNumber(NULL, JSREPORT_ERROR, JSMSG_KEYWORD_NOT_NS);
                         return NULL;
                     }
 
-                    pn->pn_arity = PN_NULLARY;
-                    pn->pn_type = TOK_FUNCTION;
+                    pn->setArity(PN_NULLARY);
+                    pn->setKind(TOK_FUNCTION);
                 }
             }
             pn = qualifiedSuffix(pn);
             if (!pn)
                 return NULL;
         }
 #endif
         break;
@@ -8904,33 +8902,33 @@ Parser::primaryExpr(TokenKind tt, JSBool
             obj->clearParent();
             obj->clearType();
         }
 
         pn->pn_objbox = tc->parser->newObjectBox(obj);
         if (!pn->pn_objbox)
             return NULL;
 
-        pn->pn_op = JSOP_REGEXP;
+        pn->setOp(JSOP_REGEXP);
         break;
       }
 
       case TOK_NUMBER:
         pn = NullaryNode::create(tc);
         if (!pn)
             return NULL;
-        pn->pn_op = JSOP_DOUBLE;
+        pn->setOp(JSOP_DOUBLE);
         pn->pn_dval = tokenStream.currentToken().t_dval;
         break;
 
       case TOK_PRIMARY:
         pn = NullaryNode::create(tc);
         if (!pn)
             return NULL;
-        pn->pn_op = tokenStream.currentToken().t_op;
+        pn->setOp(tokenStream.currentToken().t_op);
         break;
 
       case TOK_ERROR:
         /* The scanner or one of its subroutines reported the error. */
         return NULL;
 
       default:
         reportErrorNumber(NULL, JSREPORT_ERROR, JSMSG_SYNTAX_ERROR);
@@ -8957,18 +8955,18 @@ Parser::parenExpr(JSBool *genexp)
     if (!pn)
         return NULL;
     guard.endBody();
 
 #if JS_HAS_GENERATOR_EXPRS
     if (tokenStream.matchToken(TOK_FOR)) {
         if (!guard.checkValidBody(pn))
             return NULL;
-        JS_ASSERT(pn->pn_type != TOK_YIELD);
-        if (pn->pn_type == TOK_COMMA && !pn->pn_parens) {
+        JS_ASSERT(!pn->isKind(TOK_YIELD));
+        if (pn->isKind(TOK_COMMA) && !pn->isInParens()) {
             reportErrorNumber(pn->last(), JSREPORT_ERROR, JSMSG_BAD_GENERATOR_SYNTAX,
                               js_generator_str);
             return NULL;
         }
         pn = generatorExpr(pn);
         if (!pn)
             return NULL;
         pn->pn_pos.begin = begin;
@@ -8992,39 +8990,39 @@ Parser::parenExpr(JSBool *genexp)
 
 /*
  * Fold from one constant type to another.
  * XXX handles only strings and numbers for now
  */
 static JSBool
 FoldType(JSContext *cx, JSParseNode *pn, TokenKind type)
 {
-    if (PN_TYPE(pn) != type) {
+    if (!pn->isKind(type)) {
         switch (type) {
           case TOK_NUMBER:
-            if (pn->pn_type == TOK_STRING) {
+            if (pn->isKind(TOK_STRING)) {
                 jsdouble d;
                 if (!ToNumber(cx, StringValue(pn->pn_atom), &d))
                     return JS_FALSE;
                 pn->pn_dval = d;
-                pn->pn_type = TOK_NUMBER;
-                pn->pn_op = JSOP_DOUBLE;
+                pn->setKind(TOK_NUMBER);
+                pn->setOp(JSOP_DOUBLE);
             }
             break;
 
           case TOK_STRING:
-            if (pn->pn_type == TOK_NUMBER) {
+            if (pn->isKind(TOK_NUMBER)) {
                 JSString *str = js_NumberToString(cx, pn->pn_dval);
                 if (!str)
                     return JS_FALSE;
                 pn->pn_atom = js_AtomizeString(cx, str);
                 if (!pn->pn_atom)
                     return JS_FALSE;
-                pn->pn_type = TOK_STRING;
-                pn->pn_op = JSOP_STRING;
+                pn->setKind(TOK_STRING);
+                pn->setOp(JSOP_STRING);
             }
             break;
 
           default:;
         }
     }
     return JS_TRUE;
 }
@@ -9036,17 +9034,17 @@ FoldType(JSContext *cx, JSParseNode *pn,
  */
 static JSBool
 FoldBinaryNumeric(JSContext *cx, JSOp op, JSParseNode *pn1, JSParseNode *pn2,
                   JSParseNode *pn, JSTreeContext *tc)
 {
     jsdouble d, d2;
     int32 i, j;
 
-    JS_ASSERT(pn1->pn_type == TOK_NUMBER && pn2->pn_type == TOK_NUMBER);
+    JS_ASSERT(pn1->isKind(TOK_NUMBER) && pn2->isKind(TOK_NUMBER));
     d = pn1->pn_dval;
     d2 = pn2->pn_dval;
     switch (op) {
       case JSOP_LSH:
       case JSOP_RSH:
         i = js_DoubleToECMAInt32(d);
         j = js_DoubleToECMAInt32(d2);
         j &= 31;
@@ -9101,35 +9099,35 @@ FoldBinaryNumeric(JSContext *cx, JSOp op
       default:;
     }
 
     /* Take care to allow pn1 or pn2 to alias pn. */
     if (pn1 != pn)
         RecycleTree(pn1, tc);
     if (pn2 != pn)
         RecycleTree(pn2, tc);
-    pn->pn_type = TOK_NUMBER;
-    pn->pn_op = JSOP_DOUBLE;
-    pn->pn_arity = PN_NULLARY;
+    pn->setKind(TOK_NUMBER);
+    pn->setOp(JSOP_DOUBLE);
+    pn->setArity(PN_NULLARY);
     pn->pn_dval = d;
     return JS_TRUE;
 }
 
 #if JS_HAS_XML_SUPPORT
 
 static JSBool
 FoldXMLConstants(JSContext *cx, JSParseNode *pn, JSTreeContext *tc)
 {
     TokenKind tt;
     JSParseNode **pnp, *pn1, *pn2;
     JSString *accum, *str;
     uint32 i, j;
 
-    JS_ASSERT(pn->pn_arity == PN_LIST);
-    tt = PN_TYPE(pn);
+    JS_ASSERT(pn->isArity(PN_LIST));
+    tt = pn->getKind();
     pnp = &pn->pn_head;
     pn1 = *pnp;
     accum = NULL;
     str = NULL;
     if ((pn->pn_xflags & PNX_CANTFOLD) == 0) {
         if (tt == TOK_XMLETAGO)
             accum = cx->runtime->atomState.etagoAtom;
         else if (tt == TOK_XMLSTAGO || tt == TOK_XMLPTAGC)
@@ -9141,26 +9139,26 @@ FoldXMLConstants(JSContext *cx, JSParseN
      * the newborn string root. However, when |pn2->pn_type| is TOK_XMLCDATA,
      * TOK_XMLCOMMENT, or TOK_XMLPI it is knocked out of the newborn root.
      * Therefore, we have to add additonal protection from GC nesting under
      * js_ConcatStrings.
      */
     for (pn2 = pn1, i = j = 0; pn2; pn2 = pn2->pn_next, i++) {
         /* The parser already rejected end-tags with attributes. */
         JS_ASSERT(tt != TOK_XMLETAGO || i == 0);
-        switch (pn2->pn_type) {
+        switch (pn2->getKind()) {
           case TOK_XMLATTR:
             if (!accum)
                 goto cantfold;
             /* FALL THROUGH */