Merge mozilla-central to autoland. a=merge CLOSED TREE
authorMargareta Eliza Balazs <ebalazs@mozilla.com>
Fri, 10 Aug 2018 12:22:04 +0300
changeset 486039 d05ae84b507f7c0ba986f09202d8be8b3b2eded2
parent 486038 925d2fd06a2451ceee7c9136fe6f337a87c2af67 (current diff)
parent 486037 d999fb858fb2c007c5be4af72bce419c63c69b8e (diff)
child 486040 1bbc2b8d4a31ea210f6aaf2984d56370f8fb62c0
push id9719
push userffxbld-merge
push dateFri, 24 Aug 2018 17:49:46 +0000
treeherdermozilla-beta@719ec98fba77 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone63.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 mozilla-central to autoland. a=merge CLOSED TREE
accessible/windows/msaa/IDSet.h
gfx/layers/BufferEdgePad.cpp
gfx/layers/BufferEdgePad.h
gfx/layers/BufferUnrotate.cpp
gfx/layers/BufferUnrotate.h
media/libvpx/libvpx/test/fdct4x4_test.cc
media/libvpx/libvpx/test/vp9_denoiser_sse2_test.cc
media/libvpx/libvpx/test/vp9_error_block_test.cc
media/libvpx/libvpx/test/vp9_frame_parallel_test.cc
media/libvpx/libvpx/third_party/googletest/src/README
media/libvpx/libvpx/tools/all_builds.py
media/libvpx/libvpx/tools/author_first_release.sh
media/libvpx/libvpx/tools/ftfy.sh
media/libvpx/libvpx/vp8/encoder/x86/quantize_mmx.asm
media/libvpx/libvpx/vp8/encoder/x86/quantize_ssse3.c
media/libvpx/libvpx/vp8/encoder/x86/vp8_enc_stubs_mmx.c
media/libvpx/libvpx/vp9/decoder/vp9_dthread.c
media/libvpx/libvpx/vp9/decoder/vp9_dthread.h
media/libvpx/libvpx/vp9/encoder/mips/msa/vp9_temporal_filter_msa.c
media/libvpx/libvpx/vp9/encoder/x86/vp9_error_intrin_avx2.c
media/libvpx/libvpx/vp9/encoder/x86/vp9_highbd_error_avx.asm
media/libvpx/libvpx/vp9/encoder/x86/vp9_highbd_error_sse2.asm
media/libvpx/libvpx/vp9/encoder/x86/vp9_temporal_filter_apply_sse2.asm
media/libvpx/libvpx/vpx_dsp/arm/idct16x16_1_add_neon.asm
media/libvpx/libvpx/vpx_dsp/arm/idct16x16_add_neon.asm
media/libvpx/libvpx/vpx_dsp/arm/idct16x16_neon.c
media/libvpx/libvpx/vpx_dsp/arm/idct8x8_1_add_neon.asm
media/libvpx/libvpx/vpx_dsp/arm/idct8x8_add_neon.asm
media/libvpx/libvpx/vpx_dsp/x86/fdct.h
media/libvpx/libvpx/vpx_dsp/x86/inv_txfm_ssse3_x86_64.asm
media/libvpx/libvpx/vpx_dsp/x86/quantize_avx_x86_64.asm
media/libvpx/libvpx/vpx_dsp/x86/quantize_ssse3_x86_64.asm
media/libvpx/libvpx/vpx_dsp/x86/variance_impl_avx2.c
media/libvpx/vp9_svc.patch
--- a/Makefile.in
+++ b/Makefile.in
@@ -299,36 +299,34 @@ update-packaging:
 	$(MAKE) -C tools/update-packaging
 
 .PHONY: package-generated-sources
 package-generated-sources:
 	$(call py_action,package_generated_sources,'$(DIST)/$(PKG_PATH)$(GENERATED_SOURCE_FILE_PACKAGE)')
 
 #XXX: this is a hack, since we don't want to clobber for MSVC
 # PGO support, but we can't do this test in client.mk
-ifneq ($(OS_ARCH)_$(GNU_CC), WINNT_)
 # No point in clobbering if PGO has been explicitly disabled.
-ifndef NO_PROFILE_GUIDED_OPTIMIZE
+ifdef NO_PROFILE_GUIDED_OPTIMIZE
+maybe_clobber_profiledbuild:
+else
+ifneq ($(CC_TYPE),msvc)
 maybe_clobber_profiledbuild: clean
-else
-maybe_clobber_profiledbuild:
+ifneq (,$(findstring clang,$(CC_TYPE)))
+# 32-bit Windows PGO is currently blocked by bug 1479800
+ifneq ($(CC_TYPE)_$(CPU_ARCH),clang-cl_x86)
+	$(LLVM_PROFDATA) merge -o $(DEPTH)/merged.profdata $(DEPTH)/*.profraw
 endif
-else
-ifdef CLANG_CL
-maybe_clobber_profiledbuild: clean
-# 32-bit PGO is currently blocked by bug 1479800
-ifeq ($(CPU_ARCH),x86_64)
-	$(LLVM_PROFDATA) merge -o $(DEPTH)/merged.profdata $(DEPTH)/*.profraw
 endif
 else
 maybe_clobber_profiledbuild:
 	$(RM) $(DIST)/bin/*.pgc
 	find $(DIST)/$(MOZ_APP_NAME) -name '*.pgc' -exec mv {} $(DIST)/bin \;
-endif # CLANG_CL
-endif
+endif # msvc
+endif # NO_PROFILE_GUIDED_OPTIMIZE
 
 .PHONY: maybe_clobber_profiledbuild
 
 # Look for R_386_PC32 relocations in shared libs, these
 # break x86_64 builds and SELinux users.
 ifeq ($(OS_TARGET)_$(TARGET_XPCOM_ABI),Linux_x86-gcc3)
 check::
 	@relcount=`find $(DIST)/bin -name '*.so' | xargs objdump -R | grep R_386_PC32 | wc -l` && if test $$relcount -gt 0; then echo 'FAILED: R_386_PC32 relocations detected in a shared library.  Did you use a system header without adding it to config/system-headers?'; exit 1; else echo 'PASSED'; fi
--- a/accessible/atk/AccessibleWrap.cpp
+++ b/accessible/atk/AccessibleWrap.cpp
@@ -673,17 +673,17 @@ getRoleCB(AtkObject *aAtkObj)
 #ifdef DEBUG
   if (AccessibleWrap* accWrap = GetAccessibleWrap(aAtkObj)) {
     NS_ASSERTION(nsAccUtils::IsTextInterfaceSupportCorrect(accWrap),
                  "Does not support Text interface when it should");
   }
 #endif
 
 #define ROLE(geckoRole, stringRole, atkRole, macRole, \
-             msaaRole, ia2Role, nameRule) \
+             msaaRole, ia2Role, androidClass, nameRule) \
   case roles::geckoRole: \
     aAtkObj->role = atkRole; \
     break;
 
   switch (acc.Role()) {
 #include "RoleMap.h"
     default:
       MOZ_CRASH("Unknown role.");
--- a/accessible/base/Asserts.cpp
+++ b/accessible/base/Asserts.cpp
@@ -6,17 +6,17 @@
 
 #include "nsIAccessibleRelation.h"
 #include "nsIAccessibleRole.h"
 #include "RelationType.h"
 #include "Role.h"
 
 using namespace mozilla::a11y;
 
-#define ROLE(geckoRole, stringRole, atkRole, macRole, msaaRole, ia2Role, nameRule) \
+#define ROLE(geckoRole, stringRole, atkRole, macRole, msaaRole, ia2Role, androidClass, nameRule) \
   static_assert(static_cast<uint32_t>(roles::geckoRole) \
                 == static_cast<uint32_t>(nsIAccessibleRole::ROLE_ ## geckoRole), \
                 "internal and xpcom roles differ!");
 #include "RoleMap.h"
 #undef ROLE
 
 #define RELATIONTYPE(geckoType, stringType, atkType, msaaType, ia2Type) \
   static_assert(static_cast<uint32_t>(RelationType::geckoType) \
rename from accessible/windows/msaa/IDSet.h
rename to accessible/base/IDSet.h
--- a/accessible/base/RoleMap.h
+++ b/accessible/base/RoleMap.h
@@ -8,136 +8,152 @@
  */
 
 ROLE(NOTHING,
      "nothing",
      ATK_ROLE_UNKNOWN,
      NSAccessibilityUnknownRole,
      USE_ROLE_STRING,
      IA2_ROLE_UNKNOWN,
+     "android.view.View",
      eNameFromSubtreeIfReqRule)
 
 ROLE(TITLEBAR,
      "titlebar",
      ATK_ROLE_UNKNOWN,
      NSAccessibilityUnknownRole,  //Irrelevant on OS X; windows are always native.
      ROLE_SYSTEM_TITLEBAR,
      ROLE_SYSTEM_TITLEBAR,
+     "android.view.View",
      eNoNameRule)
 
 ROLE(MENUBAR,
      "menubar",
      ATK_ROLE_MENU_BAR,
      NSAccessibilityMenuBarRole,  //Irrelevant on OS X; the menubar will always be native and on the top of the screen.
      ROLE_SYSTEM_MENUBAR,
      ROLE_SYSTEM_MENUBAR,
+     "android.view.View",
      eNoNameRule)
 
 ROLE(SCROLLBAR,
      "scrollbar",
      ATK_ROLE_SCROLL_BAR,
      NSAccessibilityScrollBarRole,  //We might need to make this its own mozAccessible, to support the children objects (valueindicator, down/up buttons).
      ROLE_SYSTEM_SCROLLBAR,
      ROLE_SYSTEM_SCROLLBAR,
+     "android.view.View",
      eNameFromValueRule)
 
 ROLE(GRIP,
      "grip",
      ATK_ROLE_UNKNOWN,
      NSAccessibilitySplitterRole,
      ROLE_SYSTEM_GRIP,
      ROLE_SYSTEM_GRIP,
+     "android.view.View",
      eNoNameRule)
 
 ROLE(SOUND,
      "sound",
      ATK_ROLE_UNKNOWN,
      NSAccessibilityUnknownRole,  //Unused on OS X.
      ROLE_SYSTEM_SOUND,
      ROLE_SYSTEM_SOUND,
+     "android.view.View",
      eNoNameRule)
 
 ROLE(CURSOR,
      "cursor",
      ATK_ROLE_UNKNOWN,
      NSAccessibilityUnknownRole,  //Unused on OS X.
      ROLE_SYSTEM_CURSOR,
      ROLE_SYSTEM_CURSOR,
+     "android.view.View",
      eNoNameRule)
 
 ROLE(CARET,
      "caret",
      ATK_ROLE_UNKNOWN,
      NSAccessibilityUnknownRole,  //Unused on OS X.
      ROLE_SYSTEM_CARET,
      ROLE_SYSTEM_CARET,
+     "android.view.View",
      eNoNameRule)
 
 ROLE(ALERT,
      "alert",
      ATK_ROLE_ALERT,
      NSAccessibilityGroupRole,
      ROLE_SYSTEM_ALERT,
      ROLE_SYSTEM_ALERT,
+     "android.view.View",
      eNoNameRule)
 
 ROLE(WINDOW,
      "window",
      ATK_ROLE_WINDOW,
      NSAccessibilityWindowRole,  //Irrelevant on OS X; all window a11y is handled by the system.
      ROLE_SYSTEM_WINDOW,
      ROLE_SYSTEM_WINDOW,
+     "android.view.View",
      eNoNameRule)
 
 ROLE(INTERNAL_FRAME,
      "internal frame",
      ATK_ROLE_INTERNAL_FRAME,
      NSAccessibilityScrollAreaRole,
      USE_ROLE_STRING,
      IA2_ROLE_INTERNAL_FRAME,
+     "android.view.View",
      eNoNameRule)
 
 ROLE(MENUPOPUP,
      "menupopup",
      ATK_ROLE_MENU,
      NSAccessibilityMenuRole,  //The parent of menuitems.
      ROLE_SYSTEM_MENUPOPUP,
      ROLE_SYSTEM_MENUPOPUP,
+     "android.view.View",
      eNoNameRule)
 
 ROLE(MENUITEM,
      "menuitem",
      ATK_ROLE_MENU_ITEM,
      NSAccessibilityMenuItemRole,
      ROLE_SYSTEM_MENUITEM,
      ROLE_SYSTEM_MENUITEM,
+     "android.view.MenuItem",
      eNameFromSubtreeRule)
 
 ROLE(TOOLTIP,
      "tooltip",
      ATK_ROLE_TOOL_TIP,
      @"AXHelpTag",  //10.4+ only, so we re-define the constant.
      ROLE_SYSTEM_TOOLTIP,
      ROLE_SYSTEM_TOOLTIP,
+     "android.view.View",
      eNameFromSubtreeRule)
 
 ROLE(APPLICATION,
      "application",
      ATK_ROLE_EMBEDDED,
      NSAccessibilityGroupRole,  //Unused on OS X. the system will take care of this.
      ROLE_SYSTEM_APPLICATION,
      ROLE_SYSTEM_APPLICATION,
+     "android.view.View",
      eNoNameRule)
 
 ROLE(DOCUMENT,
      "document",
      ATK_ROLE_DOCUMENT_WEB,
      @"AXWebArea",
      ROLE_SYSTEM_DOCUMENT,
      ROLE_SYSTEM_DOCUMENT,
+     "android.view.View",
      eNoNameRule)
 
 /**
  *  msaa comment:
  *   We used to map to ROLE_SYSTEM_PANE, but JAWS would
  *   not read the accessible name for the contaning pane.
  *   However, JAWS will read the accessible name for a groupbox.
  *   By mapping a PANE to a GROUPING, we get no undesirable effects,
@@ -145,1300 +161,1462 @@ ROLE(DOCUMENT,
  *   when an inner control gets focused.
  */
 ROLE(PANE,
      "pane",
      ATK_ROLE_PANEL,
      NSAccessibilityGroupRole,
      ROLE_SYSTEM_GROUPING,
      ROLE_SYSTEM_GROUPING,
+     "android.view.View",
      eNoNameRule)
 
 ROLE(CHART,
      "chart",
      ATK_ROLE_CHART,
      NSAccessibilityUnknownRole,
      ROLE_SYSTEM_CHART,
      ROLE_SYSTEM_CHART,
+     "android.view.View",
      eNoNameRule)
 
 ROLE(DIALOG,
      "dialog",
      ATK_ROLE_DIALOG,
      NSAccessibilityWindowRole,  //There's a dialog subrole.
      ROLE_SYSTEM_DIALOG,
      ROLE_SYSTEM_DIALOG,
+     "android.app.Dialog",
      eNoNameRule)
 
 ROLE(BORDER,
      "border",
      ATK_ROLE_UNKNOWN,
      NSAccessibilityUnknownRole,  //Unused on OS X.
      ROLE_SYSTEM_BORDER,
      ROLE_SYSTEM_BORDER,
+     "android.view.View",
      eNoNameRule)
 
 ROLE(GROUPING,
      "grouping",
      ATK_ROLE_PANEL,
      NSAccessibilityGroupRole,
      ROLE_SYSTEM_GROUPING,
      ROLE_SYSTEM_GROUPING,
+     "android.view.View",
      eNoNameRule)
 
 ROLE(SEPARATOR,
      "separator",
      ATK_ROLE_SEPARATOR,
      NSAccessibilitySplitterRole,
      ROLE_SYSTEM_SEPARATOR,
      ROLE_SYSTEM_SEPARATOR,
+     "android.view.View",
      eNoNameRule)
 
 ROLE(TOOLBAR,
      "toolbar",
      ATK_ROLE_TOOL_BAR,
      NSAccessibilityToolbarRole,
      ROLE_SYSTEM_TOOLBAR,
      ROLE_SYSTEM_TOOLBAR,
+     "android.view.View",
      eNoNameRule)
 
 ROLE(STATUSBAR,
      "statusbar",
      ATK_ROLE_STATUSBAR,
      NSAccessibilityUnknownRole,  //Doesn't exist on OS X (a status bar is its parts; a progressbar, a label, etc.)
      ROLE_SYSTEM_STATUSBAR,
      ROLE_SYSTEM_STATUSBAR,
+     "android.view.View",
      eNoNameRule)
 
 ROLE(TABLE,
      "table",
      ATK_ROLE_TABLE,
      NSAccessibilityTableRole,
      ROLE_SYSTEM_TABLE,
      ROLE_SYSTEM_TABLE,
+     "android.widget.GridView",
      eNoNameRule)
 
 ROLE(COLUMNHEADER,
      "columnheader",
      ATK_ROLE_COLUMN_HEADER,
      NSAccessibilityCellRole,
      ROLE_SYSTEM_COLUMNHEADER,
      ROLE_SYSTEM_COLUMNHEADER,
+     "android.view.View",
      eNameFromSubtreeRule)
 
 ROLE(ROWHEADER,
      "rowheader",
      ATK_ROLE_ROW_HEADER,
      NSAccessibilityCellRole,
      ROLE_SYSTEM_ROWHEADER,
      ROLE_SYSTEM_ROWHEADER,
+     "android.view.View",
      eNameFromSubtreeRule)
 
 ROLE(COLUMN,
      "column",
      ATK_ROLE_UNKNOWN,
      NSAccessibilityColumnRole,
      ROLE_SYSTEM_COLUMN,
      ROLE_SYSTEM_COLUMN,
+     "android.view.View",
      eNameFromSubtreeRule)
 
 ROLE(ROW,
      "row",
      ATK_ROLE_TABLE_ROW,
      NSAccessibilityRowRole,
      ROLE_SYSTEM_ROW,
      ROLE_SYSTEM_ROW,
+     "android.view.View",
      eNameFromSubtreeRule)
 
 ROLE(CELL,
      "cell",
      ATK_ROLE_TABLE_CELL,
      NSAccessibilityCellRole,
      ROLE_SYSTEM_CELL,
      ROLE_SYSTEM_CELL,
+     "android.view.View",
      eNameFromSubtreeIfReqRule)
 
 ROLE(LINK,
      "link",
      ATK_ROLE_LINK,
      @"AXLink",  //10.4+ the attr first define in SDK 10.4, so we define it here too. ROLE_LINK
      ROLE_SYSTEM_LINK,
      ROLE_SYSTEM_LINK,
+     "android.view.View",
      eNameFromSubtreeRule)
 
 ROLE(HELPBALLOON,
      "helpballoon",
      ATK_ROLE_UNKNOWN,
      @"AXHelpTag",
      ROLE_SYSTEM_HELPBALLOON,
      ROLE_SYSTEM_HELPBALLOON,
+     "android.view.View",
      eNameFromSubtreeRule)
 
 ROLE(CHARACTER,
      "character",
      ATK_ROLE_IMAGE,
      NSAccessibilityUnknownRole,  //Unused on OS X.
      ROLE_SYSTEM_CHARACTER,
      ROLE_SYSTEM_CHARACTER,
+     "android.view.View",
      eNoNameRule)
 
 ROLE(LIST,
      "list",
      ATK_ROLE_LIST,
      NSAccessibilityListRole,
      ROLE_SYSTEM_LIST,
      ROLE_SYSTEM_LIST,
+     "android.widget.ListView",
      eNameFromSubtreeIfReqRule)
 
 ROLE(LISTITEM,
      "listitem",
      ATK_ROLE_LIST_ITEM,
      NSAccessibilityGroupRole,
      ROLE_SYSTEM_LISTITEM,
      ROLE_SYSTEM_LISTITEM,
+     "android.view.View",
      eNameFromSubtreeRule)
 
 ROLE(OUTLINE,
      "outline",
      ATK_ROLE_TREE,
      NSAccessibilityOutlineRole,
      ROLE_SYSTEM_OUTLINE,
      ROLE_SYSTEM_OUTLINE,
+     "android.view.View",
      eNoNameRule)
 
 ROLE(OUTLINEITEM,
      "outlineitem",
      ATK_ROLE_TREE_ITEM,
      NSAccessibilityRowRole,
      ROLE_SYSTEM_OUTLINEITEM,
      ROLE_SYSTEM_OUTLINEITEM,
+     "android.view.View",
      eNameFromSubtreeRule)
 
 ROLE(PAGETAB,
      "pagetab",
      ATK_ROLE_PAGE_TAB,
      NSAccessibilityRadioButtonRole,
      ROLE_SYSTEM_PAGETAB,
      ROLE_SYSTEM_PAGETAB,
+     "android.view.View",
      eNameFromSubtreeRule)
 
 ROLE(PROPERTYPAGE,
      "propertypage",
      ATK_ROLE_SCROLL_PANE,
      NSAccessibilityGroupRole,
      ROLE_SYSTEM_PROPERTYPAGE,
      ROLE_SYSTEM_PROPERTYPAGE,
+     "android.view.View",
      eNoNameRule)
 
 ROLE(INDICATOR,
      "indicator",
      ATK_ROLE_UNKNOWN,
      NSAccessibilityUnknownRole,
      ROLE_SYSTEM_INDICATOR,
      ROLE_SYSTEM_INDICATOR,
+     "android.view.View",
      eNoNameRule)
 
 ROLE(GRAPHIC,
      "graphic",
      ATK_ROLE_IMAGE,
      NSAccessibilityImageRole,
      ROLE_SYSTEM_GRAPHIC,
      ROLE_SYSTEM_GRAPHIC,
+     "android.widget.Image",
      eNoNameRule)
 
 ROLE(STATICTEXT,
      "statictext",
      ATK_ROLE_UNKNOWN,
      NSAccessibilityStaticTextRole,
      ROLE_SYSTEM_STATICTEXT,
      ROLE_SYSTEM_STATICTEXT,
+     "android.view.View",
      eNoNameRule)
 
 ROLE(TEXT_LEAF,
      "text leaf",
      ATK_ROLE_UNKNOWN,
      NSAccessibilityStaticTextRole,
      ROLE_SYSTEM_TEXT,
      ROLE_SYSTEM_TEXT,
+     "android.view.View",
      eNoNameRule)
 
 ROLE(PUSHBUTTON,
      "pushbutton",
      ATK_ROLE_PUSH_BUTTON,
      NSAccessibilityButtonRole,
      ROLE_SYSTEM_PUSHBUTTON,
      ROLE_SYSTEM_PUSHBUTTON,
+     "android.widget.Button",
      eNameFromSubtreeRule)
 
 ROLE(CHECKBUTTON,
      "checkbutton",
      ATK_ROLE_CHECK_BOX,
      NSAccessibilityCheckBoxRole,
      ROLE_SYSTEM_CHECKBUTTON,
      ROLE_SYSTEM_CHECKBUTTON,
+     "android.widget.CheckBox",
      eNameFromSubtreeRule)
 
 ROLE(RADIOBUTTON,
      "radiobutton",
      ATK_ROLE_RADIO_BUTTON,
      NSAccessibilityRadioButtonRole,
      ROLE_SYSTEM_RADIOBUTTON,
      ROLE_SYSTEM_RADIOBUTTON,
+     "android.widget.RadioButton",
      eNameFromSubtreeRule)
 
 // Equivalent of HTML select element with size="1". See also EDITCOMBOBOX.
 ROLE(COMBOBOX,
      "combobox",
      ATK_ROLE_COMBO_BOX,
      NSAccessibilityPopUpButtonRole,
      ROLE_SYSTEM_COMBOBOX,
      ROLE_SYSTEM_COMBOBOX,
+     "android.widget.Spinner",
      eNameFromValueRule)
 
 ROLE(DROPLIST,
      "droplist",
      ATK_ROLE_COMBO_BOX,
      NSAccessibilityPopUpButtonRole,
      ROLE_SYSTEM_DROPLIST,
      ROLE_SYSTEM_DROPLIST,
+     "android.view.View",
      eNoNameRule)
 
 ROLE(PROGRESSBAR,
      "progressbar",
      ATK_ROLE_PROGRESS_BAR,
      NSAccessibilityProgressIndicatorRole,
      ROLE_SYSTEM_PROGRESSBAR,
      ROLE_SYSTEM_PROGRESSBAR,
+     "android.widget.ProgressBar",
      eNameFromValueRule)
 
 ROLE(DIAL,
      "dial",
      ATK_ROLE_DIAL,
      NSAccessibilityUnknownRole,
      ROLE_SYSTEM_DIAL,
      ROLE_SYSTEM_DIAL,
+     "android.view.View",
      eNoNameRule)
 
 ROLE(HOTKEYFIELD,
      "hotkeyfield",
      ATK_ROLE_UNKNOWN,
      NSAccessibilityUnknownRole,
      ROLE_SYSTEM_HOTKEYFIELD,
      ROLE_SYSTEM_HOTKEYFIELD,
+     "android.view.View",
      eNoNameRule)
 
 ROLE(SLIDER,
      "slider",
      ATK_ROLE_SLIDER,
      NSAccessibilitySliderRole,
      ROLE_SYSTEM_SLIDER,
      ROLE_SYSTEM_SLIDER,
+     "android.widget.SeekBar",
      eNameFromValueRule)
 
 ROLE(SPINBUTTON,
      "spinbutton",
      ATK_ROLE_SPIN_BUTTON,
      NSAccessibilityIncrementorRole,  //Subroles: Increment/Decrement.
      ROLE_SYSTEM_SPINBUTTON,
      ROLE_SYSTEM_SPINBUTTON,
+     "android.widget.EditText",
      eNameFromValueRule)
 
 ROLE(DIAGRAM,
      "diagram",
      ATK_ROLE_IMAGE,
      NSAccessibilityUnknownRole,
      ROLE_SYSTEM_DIAGRAM,
      ROLE_SYSTEM_DIAGRAM,
+     "android.widget.Image",
      eNoNameRule)
 
 ROLE(ANIMATION,
      "animation",
      ATK_ROLE_ANIMATION,
      NSAccessibilityUnknownRole,
      ROLE_SYSTEM_ANIMATION,
      ROLE_SYSTEM_ANIMATION,
+     "android.view.View",
      eNoNameRule)
 
 ROLE(EQUATION,
      "equation",
      ATK_ROLE_UNKNOWN,
      NSAccessibilityUnknownRole,
      ROLE_SYSTEM_EQUATION,
      ROLE_SYSTEM_EQUATION,
+     "android.view.View",
      eNoNameRule)
 
 ROLE(BUTTONDROPDOWN,
      "buttondropdown",
      ATK_ROLE_PUSH_BUTTON,
      NSAccessibilityPopUpButtonRole,
      ROLE_SYSTEM_BUTTONDROPDOWN,
      ROLE_SYSTEM_BUTTONDROPDOWN,
+     "android.view.View",
      eNameFromSubtreeRule)
 
 ROLE(BUTTONMENU,
      "buttonmenu",
      ATK_ROLE_PUSH_BUTTON,
      NSAccessibilityMenuButtonRole,
      ROLE_SYSTEM_BUTTONMENU,
      ROLE_SYSTEM_BUTTONMENU,
+     "android.widget.Spinner",
      eNameFromSubtreeRule)
 
 ROLE(BUTTONDROPDOWNGRID,
      "buttondropdowngrid",
      ATK_ROLE_UNKNOWN,
      NSAccessibilityGroupRole,
      ROLE_SYSTEM_BUTTONDROPDOWNGRID,
      ROLE_SYSTEM_BUTTONDROPDOWNGRID,
+     "android.view.View",
      eNameFromSubtreeRule)
 
 ROLE(WHITESPACE,
      "whitespace",
      ATK_ROLE_UNKNOWN,
      NSAccessibilityUnknownRole,
      ROLE_SYSTEM_WHITESPACE,
      ROLE_SYSTEM_WHITESPACE,
+     "android.view.View",
      eNoNameRule)
 
 ROLE(PAGETABLIST,
      "pagetablist",
      ATK_ROLE_PAGE_TAB_LIST,
      NSAccessibilityTabGroupRole,
      ROLE_SYSTEM_PAGETABLIST,
      ROLE_SYSTEM_PAGETABLIST,
+     "android.widget.TabWidget",
      eNoNameRule)
 
 ROLE(CLOCK,
      "clock",
      ATK_ROLE_UNKNOWN,
      NSAccessibilityUnknownRole,  //Unused on OS X
      ROLE_SYSTEM_CLOCK,
      ROLE_SYSTEM_CLOCK,
+     "android.view.View",
      eNoNameRule)
 
 ROLE(SPLITBUTTON,
      "splitbutton",
      ATK_ROLE_PUSH_BUTTON,
      NSAccessibilityButtonRole,
      ROLE_SYSTEM_SPLITBUTTON,
      ROLE_SYSTEM_SPLITBUTTON,
+     "android.widget.Button",
      eNoNameRule)
 
 ROLE(IPADDRESS,
      "ipaddress",
      ATK_ROLE_UNKNOWN,
      NSAccessibilityUnknownRole,
      ROLE_SYSTEM_IPADDRESS,
      ROLE_SYSTEM_IPADDRESS,
+     "android.view.View",
      eNoNameRule)
 
 ROLE(ACCEL_LABEL,
      "accel label",
      ATK_ROLE_ACCEL_LABEL,
      NSAccessibilityStaticTextRole,
      ROLE_SYSTEM_STATICTEXT,
      ROLE_SYSTEM_STATICTEXT,
+     "android.view.View",
      eNoNameRule)
 
 ROLE(ARROW,
      "arrow",
      ATK_ROLE_ARROW,
      NSAccessibilityUnknownRole,
      ROLE_SYSTEM_INDICATOR,
      ROLE_SYSTEM_INDICATOR,
+     "android.view.View",
      eNoNameRule)
 
 ROLE(CANVAS,
      "canvas",
      ATK_ROLE_CANVAS,
      NSAccessibilityImageRole,
      USE_ROLE_STRING,
      IA2_ROLE_CANVAS,
+     "android.widget.Image",
      eNoNameRule)
 
 ROLE(CHECK_MENU_ITEM,
      "check menu item",
      ATK_ROLE_CHECK_MENU_ITEM,
      NSAccessibilityMenuItemRole,
      ROLE_SYSTEM_MENUITEM,
      IA2_ROLE_CHECK_MENU_ITEM,
+     "android.view.MenuItem",
      eNameFromSubtreeRule)
 
 ROLE(COLOR_CHOOSER,
      "color chooser",
      ATK_ROLE_COLOR_CHOOSER,
      NSAccessibilityColorWellRole,
      ROLE_SYSTEM_DIALOG,
      IA2_ROLE_COLOR_CHOOSER,
+     "android.view.View",
      eNoNameRule)
 
 ROLE(DATE_EDITOR,
      "date editor",
      ATK_ROLE_DATE_EDITOR,
      NSAccessibilityUnknownRole,
      USE_ROLE_STRING,
      IA2_ROLE_DATE_EDITOR,
+     "android.widget.Spinner",
      eNoNameRule)
 
 ROLE(DESKTOP_ICON,
      "desktop icon",
      ATK_ROLE_DESKTOP_ICON,
      NSAccessibilityImageRole,
      USE_ROLE_STRING,
      IA2_ROLE_DESKTOP_ICON,
+     "android.view.View",
      eNoNameRule)
 
 ROLE(DESKTOP_FRAME,
      "desktop frame",
      ATK_ROLE_DESKTOP_FRAME,
      NSAccessibilityUnknownRole,
      USE_ROLE_STRING,
      IA2_ROLE_DESKTOP_PANE,
+     "android.view.View",
      eNoNameRule)
 
 ROLE(DIRECTORY_PANE,
      "directory pane",
      ATK_ROLE_DIRECTORY_PANE,
      NSAccessibilityBrowserRole,
      USE_ROLE_STRING,
      IA2_ROLE_DIRECTORY_PANE,
+     "android.view.View",
      eNoNameRule)
 
 ROLE(FILE_CHOOSER,
      "file chooser",
      ATK_ROLE_FILE_CHOOSER,
      NSAccessibilityUnknownRole,  //Unused on OS X
      USE_ROLE_STRING,
      IA2_ROLE_FILE_CHOOSER,
+     "android.view.View",
      eNoNameRule)
 
 ROLE(FONT_CHOOSER,
      "font chooser",
      ATK_ROLE_FONT_CHOOSER,
      NSAccessibilityUnknownRole,
      USE_ROLE_STRING,
      IA2_ROLE_FONT_CHOOSER,
+     "android.view.View",
      eNoNameRule)
 
 ROLE(CHROME_WINDOW,
      "chrome window",
      ATK_ROLE_FRAME,
      NSAccessibilityGroupRole,  //Contains the main Firefox UI
      ROLE_SYSTEM_APPLICATION,
      IA2_ROLE_FRAME,
+     "android.view.View",
      eNoNameRule)
 
 ROLE(GLASS_PANE,
      "glass pane",
      ATK_ROLE_GLASS_PANE,
      NSAccessibilityGroupRole,
      USE_ROLE_STRING,
      IA2_ROLE_GLASS_PANE,
+     "android.view.View",
      eNoNameRule)
 
 ROLE(HTML_CONTAINER,
      "html container",
      ATK_ROLE_HTML_CONTAINER,
      NSAccessibilityUnknownRole,
      USE_ROLE_STRING,
      IA2_ROLE_UNKNOWN,
+     "android.view.View",
      eNameFromSubtreeIfReqRule)
 
 ROLE(ICON,
      "icon",
      ATK_ROLE_ICON,
      NSAccessibilityImageRole,
      ROLE_SYSTEM_PUSHBUTTON,
      IA2_ROLE_ICON,
+     "android.view.View",
      eNoNameRule)
 
 ROLE(LABEL,
      "label",
      ATK_ROLE_LABEL,
      NSAccessibilityGroupRole,
      ROLE_SYSTEM_STATICTEXT,
      IA2_ROLE_LABEL,
+     "android.view.View",
      eNameFromSubtreeRule)
 
 ROLE(LAYERED_PANE,
      "layered pane",
      ATK_ROLE_LAYERED_PANE,
      NSAccessibilityGroupRole,
      USE_ROLE_STRING,
      IA2_ROLE_LAYERED_PANE,
+     "android.view.View",
      eNoNameRule)
 
 ROLE(OPTION_PANE,
      "option pane",
      ATK_ROLE_OPTION_PANE,
      NSAccessibilityGroupRole,
      USE_ROLE_STRING,
      IA2_ROLE_OPTION_PANE,
+     "android.view.View",
      eNoNameRule)
 
 ROLE(PASSWORD_TEXT,
      "password text",
      ATK_ROLE_PASSWORD_TEXT,
      NSAccessibilityTextFieldRole,
      ROLE_SYSTEM_TEXT,
      ROLE_SYSTEM_TEXT,
+     "android.widget.EditText",
      eNoNameRule)
 
 ROLE(POPUP_MENU,
      "popup menu",
      ATK_ROLE_POPUP_MENU,
      NSAccessibilityUnknownRole,  //Unused
      ROLE_SYSTEM_MENUPOPUP,
      ROLE_SYSTEM_MENUPOPUP,
+     "android.view.View",
      eNoNameRule)
 
 ROLE(RADIO_MENU_ITEM,
      "radio menu item",
      ATK_ROLE_RADIO_MENU_ITEM,
      NSAccessibilityMenuItemRole,
      ROLE_SYSTEM_MENUITEM,
      IA2_ROLE_RADIO_MENU_ITEM,
+     "android.view.MenuItem",
      eNameFromSubtreeRule)
 
 ROLE(ROOT_PANE,
      "root pane",
      ATK_ROLE_ROOT_PANE,
      NSAccessibilityGroupRole,
      USE_ROLE_STRING,
      IA2_ROLE_ROOT_PANE,
+     "android.view.View",
      eNoNameRule)
 
 ROLE(SCROLL_PANE,
      "scroll pane",
      ATK_ROLE_SCROLL_PANE,
      NSAccessibilityScrollAreaRole,
      USE_ROLE_STRING,
      IA2_ROLE_SCROLL_PANE,
+     "android.view.View",
      eNoNameRule)
 
 ROLE(SPLIT_PANE,
      "split pane",
      ATK_ROLE_SPLIT_PANE,
      NSAccessibilitySplitGroupRole,
      USE_ROLE_STRING,
      IA2_ROLE_SPLIT_PANE,
+     "android.view.View",
      eNoNameRule)
 
 ROLE(TABLE_COLUMN_HEADER,
      "table column header",
      ATK_ROLE_TABLE_COLUMN_HEADER,
      NSAccessibilityUnknownRole,
      ROLE_SYSTEM_COLUMNHEADER,
      ROLE_SYSTEM_COLUMNHEADER,
+     "android.view.View",
      eNameFromSubtreeRule)
 
 ROLE(TABLE_ROW_HEADER,
      "table row header",
      ATK_ROLE_TABLE_ROW_HEADER,
      NSAccessibilityUnknownRole,
      ROLE_SYSTEM_ROWHEADER,
      ROLE_SYSTEM_ROWHEADER,
+     "android.view.View",
      eNameFromSubtreeRule)
 
 ROLE(TEAR_OFF_MENU_ITEM,
      "tear off menu item",
      ATK_ROLE_TEAR_OFF_MENU_ITEM,
      NSAccessibilityMenuItemRole,
      ROLE_SYSTEM_MENUITEM,
      IA2_ROLE_TEAR_OFF_MENU,
+     "android.view.View",
      eNameFromSubtreeRule)
 
 ROLE(TERMINAL,
      "terminal",
      ATK_ROLE_TERMINAL,
      NSAccessibilityUnknownRole,
      USE_ROLE_STRING,
      IA2_ROLE_TERMINAL,
+     "android.view.View",
      eNoNameRule)
 
 ROLE(TEXT_CONTAINER,
      "text container",
      ATK_ROLE_SECTION,
      NSAccessibilityGroupRole,
      USE_ROLE_STRING,
      IA2_ROLE_TEXT_FRAME,
+     "android.view.View",
      eNameFromSubtreeIfReqRule)
 
 ROLE(TOGGLE_BUTTON,
      "toggle button",
      ATK_ROLE_TOGGLE_BUTTON,
      NSAccessibilityButtonRole,
      ROLE_SYSTEM_PUSHBUTTON,
      IA2_ROLE_TOGGLE_BUTTON,
+     "android.widget.ToggleButton",
      eNameFromSubtreeRule)
 
 ROLE(TREE_TABLE,
      "tree table",
      ATK_ROLE_TREE_TABLE,
      NSAccessibilityTableRole,
      ROLE_SYSTEM_OUTLINE,
      ROLE_SYSTEM_OUTLINE,
+     "android.widget.GridView",
      eNoNameRule)
 
 ROLE(VIEWPORT,
      "viewport",
      ATK_ROLE_VIEWPORT,
      NSAccessibilityUnknownRole,
      ROLE_SYSTEM_PANE,
      IA2_ROLE_VIEW_PORT,
+     "android.view.View",
      eNoNameRule)
 
 ROLE(HEADER,
      "header",
      ATK_ROLE_HEADER,
      NSAccessibilityGroupRole,
      USE_ROLE_STRING,
      IA2_ROLE_HEADER,
+     "android.view.View",
      eNoNameRule)
 
 ROLE(FOOTER,
      "footer",
      ATK_ROLE_FOOTER,
      NSAccessibilityGroupRole,
      USE_ROLE_STRING,
      IA2_ROLE_FOOTER,
+     "android.view.View",
      eNoNameRule)
 
 ROLE(PARAGRAPH,
      "paragraph",
      ATK_ROLE_PARAGRAPH,
      NSAccessibilityGroupRole,
      USE_ROLE_STRING,
      IA2_ROLE_PARAGRAPH,
+     "android.view.View",
      eNameFromSubtreeIfReqRule)
 
 ROLE(RULER,
      "ruler",
      ATK_ROLE_RULER,
      @"AXRuler",  //10.4+ only, so we re-define the constant.
      USE_ROLE_STRING,
      IA2_ROLE_RULER,
+     "android.view.View",
      eNoNameRule)
 
 ROLE(AUTOCOMPLETE,
      "autocomplete",
      ATK_ROLE_AUTOCOMPLETE,
      NSAccessibilityUnknownRole,
      ROLE_SYSTEM_COMBOBOX,
      ROLE_SYSTEM_COMBOBOX,
+     "android.widget.EditText",
      eNoNameRule)
 
 ROLE(EDITBAR,
      "editbar",
      ATK_ROLE_EDITBAR,
      NSAccessibilityTextFieldRole,
      ROLE_SYSTEM_TEXT,
      IA2_ROLE_EDITBAR,
+     "android.view.View",
      eNoNameRule)
 
 ROLE(ENTRY,
      "entry",
      ATK_ROLE_ENTRY,
      NSAccessibilityTextFieldRole,
      ROLE_SYSTEM_TEXT,
      ROLE_SYSTEM_TEXT,
+     "android.widget.EditText",
      eNameFromValueRule)
 
 ROLE(CAPTION,
      "caption",
      ATK_ROLE_CAPTION,
      NSAccessibilityStaticTextRole,
      USE_ROLE_STRING,
      IA2_ROLE_CAPTION,
+     "android.view.View",
      eNameFromSubtreeIfReqRule)
 
 ROLE(NON_NATIVE_DOCUMENT,
      "non-native document",
      ATK_ROLE_DOCUMENT_FRAME,
      NSAccessibilityGroupRole,
      USE_ROLE_STRING,
      ROLE_SYSTEM_DOCUMENT,
+     "android.view.View",
      eNoNameRule)
 
 ROLE(HEADING,
      "heading",
      ATK_ROLE_HEADING,
      @"AXHeading",
      USE_ROLE_STRING,
      IA2_ROLE_HEADING,
+     "android.view.View",
      eNameFromSubtreeRule)
 
 ROLE(PAGE,
      "page",
      ATK_ROLE_PAGE,
      NSAccessibilityGroupRole,
      USE_ROLE_STRING,
      IA2_ROLE_PAGE,
+     "android.view.View",
      eNoNameRule)
 
 ROLE(SECTION,
      "section",
      ATK_ROLE_SECTION,
      NSAccessibilityGroupRole,
      USE_ROLE_STRING,
      IA2_ROLE_SECTION,
+     "android.view.View",
      eNameFromSubtreeIfReqRule)
 
 ROLE(REDUNDANT_OBJECT,
      "redundant object",
      ATK_ROLE_REDUNDANT_OBJECT,
      NSAccessibilityUnknownRole,
      USE_ROLE_STRING,
      IA2_ROLE_REDUNDANT_OBJECT,
+     "android.view.View",
      eNoNameRule)
 
 ROLE(FORM,
      "form",
      ATK_ROLE_FORM,
      NSAccessibilityGroupRole,
      USE_ROLE_STRING,
      IA2_ROLE_FORM,
+     "android.view.View",
      eNoNameRule)
 
 ROLE(IME,
      "ime",
      ATK_ROLE_INPUT_METHOD_WINDOW,
      NSAccessibilityUnknownRole,
      USE_ROLE_STRING,
      IA2_ROLE_INPUT_METHOD_WINDOW,
+     "android.view.View",
      eNoNameRule)
 
 ROLE(APP_ROOT,
      "app root",
      ATK_ROLE_APPLICATION,
      NSAccessibilityUnknownRole,  //Unused on OS X
      ROLE_SYSTEM_APPLICATION,
      ROLE_SYSTEM_APPLICATION,
+     "android.view.View",
      eNoNameRule)
 
 ROLE(PARENT_MENUITEM,
      "parent menuitem",
      ATK_ROLE_MENU,
      NSAccessibilityMenuItemRole,
      ROLE_SYSTEM_MENUITEM,
      ROLE_SYSTEM_MENUITEM,
+     "android.view.MenuItem",
      eNameFromSubtreeRule)
 
 ROLE(CALENDAR,
      "calendar",
      ATK_ROLE_CALENDAR,
      NSAccessibilityGroupRole,
      ROLE_SYSTEM_CLIENT,
      ROLE_SYSTEM_CLIENT,
+     "android.view.View",
      eNoNameRule)
 
 ROLE(COMBOBOX_LIST,
      "combobox list",
      ATK_ROLE_MENU,
      NSAccessibilityMenuRole,
      ROLE_SYSTEM_LIST,
      ROLE_SYSTEM_LIST,
+     "android.view.View",
      eNoNameRule)
 
 ROLE(COMBOBOX_OPTION,
      "combobox option",
      ATK_ROLE_MENU_ITEM,
      NSAccessibilityMenuItemRole,
      ROLE_SYSTEM_LISTITEM,
      ROLE_SYSTEM_LISTITEM,
+     "android.view.MenuItem",
      eNameFromSubtreeRule)
 
 ROLE(IMAGE_MAP,
      "image map",
      ATK_ROLE_IMAGE,
      NSAccessibilityUnknownRole,
      ROLE_SYSTEM_GRAPHIC,
      ROLE_SYSTEM_GRAPHIC,
+     "android.widget.Image",
      eNoNameRule)
 
 ROLE(OPTION,
      "listbox option",
      ATK_ROLE_LIST_ITEM,
      NSAccessibilityStaticTextRole,
      ROLE_SYSTEM_LISTITEM,
      ROLE_SYSTEM_LISTITEM,
+     "android.view.View",
      eNameFromSubtreeRule)
 
 ROLE(RICH_OPTION,
      "listbox rich option",
      ATK_ROLE_LIST_ITEM,
      NSAccessibilityRowRole,
      ROLE_SYSTEM_LISTITEM,
      ROLE_SYSTEM_LISTITEM,
+     "android.view.View",
      eNameFromSubtreeRule)
 
 ROLE(LISTBOX,
      "listbox",
      ATK_ROLE_LIST_BOX,
      NSAccessibilityListRole,
      ROLE_SYSTEM_LIST,
      ROLE_SYSTEM_LIST,
+     "android.widget.ListView",
      eNoNameRule)
 
 ROLE(FLAT_EQUATION,
      "flat equation",
      ATK_ROLE_UNKNOWN,
      NSAccessibilityUnknownRole,
      ROLE_SYSTEM_EQUATION,
      ROLE_SYSTEM_EQUATION,
+     "android.view.View",
      eNoNameRule)
 
 ROLE(GRID_CELL,
      "gridcell",
      ATK_ROLE_TABLE_CELL,
      NSAccessibilityGroupRole,
      ROLE_SYSTEM_CELL,
      ROLE_SYSTEM_CELL,
+     "android.view.View",
      eNameFromSubtreeRule)
 
 ROLE(EMBEDDED_OBJECT,
      "embedded object",
      ATK_ROLE_PANEL,
      NSAccessibilityGroupRole,
      USE_ROLE_STRING,
      IA2_ROLE_EMBEDDED_OBJECT,
+     "android.view.View",
      eNoNameRule)
 
 ROLE(NOTE,
      "note",
      ATK_ROLE_COMMENT,
      NSAccessibilityGroupRole,
      USE_ROLE_STRING,
      IA2_ROLE_NOTE,
+     "android.view.View",
      eNameFromSubtreeIfReqRule)
 
 ROLE(FIGURE,
      "figure",
      ATK_ROLE_PANEL,
      NSAccessibilityGroupRole,
      ROLE_SYSTEM_GROUPING,
      ROLE_SYSTEM_GROUPING,
+     "android.view.View",
      eNoNameRule)
 
 ROLE(CHECK_RICH_OPTION,
      "check rich option",
      ATK_ROLE_CHECK_BOX,
      NSAccessibilityCheckBoxRole,
      ROLE_SYSTEM_CHECKBUTTON,
      ROLE_SYSTEM_CHECKBUTTON,
+     "android.widget.CheckBox",
      eNameFromSubtreeRule)
 
 ROLE(DEFINITION_LIST,
      "definitionlist",
      ATK_ROLE_LIST,
      NSAccessibilityListRole,
      ROLE_SYSTEM_LIST,
      ROLE_SYSTEM_LIST,
+     "android.widget.ListView",
      eNameFromSubtreeIfReqRule)
 
 ROLE(TERM,
      "term",
      ATK_ROLE_DESCRIPTION_TERM,
      NSAccessibilityGroupRole,
      ROLE_SYSTEM_LISTITEM,
      ROLE_SYSTEM_LISTITEM,
+     "android.view.View",
      eNameFromSubtreeRule)
 
 ROLE(DEFINITION,
      "definition",
      ATK_ROLE_PARAGRAPH,
      NSAccessibilityGroupRole,
      USE_ROLE_STRING,
      IA2_ROLE_PARAGRAPH,
+     "android.view.View",
      eNameFromSubtreeRule)
 
 ROLE(KEY,
      "key",
      ATK_ROLE_PUSH_BUTTON,
      NSAccessibilityButtonRole,
      ROLE_SYSTEM_PUSHBUTTON,
      ROLE_SYSTEM_PUSHBUTTON,
+     "android.widget.Button",
      eNameFromSubtreeRule)
 
 ROLE(SWITCH,
      "switch",
      ATK_ROLE_TOGGLE_BUTTON,
      NSAccessibilityCheckBoxRole,
      ROLE_SYSTEM_CHECKBUTTON,
      IA2_ROLE_TOGGLE_BUTTON,
+     "android.widget.CheckBox",
      eNameFromSubtreeRule)
 
 ROLE(MATHML_MATH,
      "math",
      ATK_ROLE_MATH,
      NSAccessibilityGroupRole,
      ROLE_SYSTEM_EQUATION,
      ROLE_SYSTEM_EQUATION,
+     "android.view.View",
      eNoNameRule)
 
 ROLE(MATHML_IDENTIFIER,
      "mathml identifier",
      ATK_ROLE_STATIC,
      NSAccessibilityGroupRole,
      0,
      IA2_ROLE_UNKNOWN,
+     "android.view.View",
      eNameFromSubtreeRule)
 
 ROLE(MATHML_NUMBER,
      "mathml number",
      ATK_ROLE_STATIC,
      NSAccessibilityGroupRole,
      0,
      IA2_ROLE_UNKNOWN,
+     "android.view.View",
      eNameFromSubtreeRule)
 
 ROLE(MATHML_OPERATOR,
      "mathml operator",
      ATK_ROLE_STATIC,
      NSAccessibilityGroupRole,
      0,
      IA2_ROLE_UNKNOWN,
+     "android.view.View",
      eNameFromSubtreeRule)
 
 ROLE(MATHML_TEXT,
      "mathml text",
      ATK_ROLE_STATIC,
      NSAccessibilityGroupRole,
      0,
      IA2_ROLE_UNKNOWN,
+     "android.view.View",
      eNameFromSubtreeRule)
 
 ROLE(MATHML_STRING_LITERAL,
      "mathml string literal",
      ATK_ROLE_STATIC,
      NSAccessibilityGroupRole,
      0,
      IA2_ROLE_UNKNOWN,
+     "android.view.View",
      eNameFromSubtreeRule)
 
 ROLE(MATHML_GLYPH,
      "mathml glyph",
      ATK_ROLE_IMAGE,
      NSAccessibilityGroupRole,
      0,
      IA2_ROLE_UNKNOWN,
+     "android.widget.Image",
      eNameFromSubtreeRule)
 
 ROLE(MATHML_ROW,
      "mathml row",
      ATK_ROLE_SECTION,
      NSAccessibilityGroupRole,
      0,
      IA2_ROLE_UNKNOWN,
+     "android.view.View",
      eNoNameRule)
 
 ROLE(MATHML_FRACTION,
      "mathml fraction",
      ATK_ROLE_MATH_FRACTION,
      NSAccessibilityGroupRole,
      0,
      IA2_ROLE_UNKNOWN,
+     "android.view.View",
      eNoNameRule)
 
 ROLE(MATHML_SQUARE_ROOT,
      "mathml square root",
      ATK_ROLE_MATH_ROOT,
      NSAccessibilityGroupRole,
      0,
      IA2_ROLE_UNKNOWN,
+     "android.view.View",
      eNoNameRule)
 
 ROLE(MATHML_ROOT,
      "mathml root",
      ATK_ROLE_MATH_ROOT,
      NSAccessibilityGroupRole,
      0,
      IA2_ROLE_UNKNOWN,
+     "android.view.View",
      eNoNameRule)
 
 ROLE(MATHML_FENCED,
      "mathml fenced",
      ATK_ROLE_SECTION,
      NSAccessibilityGroupRole,
      0,
      IA2_ROLE_UNKNOWN,
+     "android.view.View",
      eNoNameRule)
 
 ROLE(MATHML_ENCLOSED,
      "mathml enclosed",
      ATK_ROLE_SECTION,
      NSAccessibilityGroupRole,
      0,
      IA2_ROLE_UNKNOWN,
+     "android.view.View",
      eNoNameRule)
 
 ROLE(MATHML_STYLE,
      "mathml style",
      ATK_ROLE_SECTION,
      NSAccessibilityGroupRole,
      0,
      IA2_ROLE_UNKNOWN,
+     "android.view.View",
      eNoNameRule)
 
 ROLE(MATHML_SUB,
      "mathml sub",
      ATK_ROLE_SECTION,
      NSAccessibilityGroupRole,
      0,
      IA2_ROLE_UNKNOWN,
+     "android.view.View",
      eNoNameRule)
 
 ROLE(MATHML_SUP,
      "mathml sup",
      ATK_ROLE_SECTION,
      NSAccessibilityGroupRole,
      0,
      IA2_ROLE_UNKNOWN,
+     "android.view.View",
      eNoNameRule)
 
 ROLE(MATHML_SUB_SUP,
      "mathml sub sup",
      ATK_ROLE_SECTION,
      NSAccessibilityGroupRole,
      0,
      IA2_ROLE_UNKNOWN,
+     "android.view.View",
      eNoNameRule)
 
 ROLE(MATHML_UNDER,
      "mathml under",
      ATK_ROLE_SECTION,
      NSAccessibilityGroupRole,
      0,
      IA2_ROLE_UNKNOWN,
+     "android.view.View",
      eNoNameRule)
 
 ROLE(MATHML_OVER,
      "mathml over",
      ATK_ROLE_SECTION,
      NSAccessibilityGroupRole,
      0,
      IA2_ROLE_UNKNOWN,
+     "android.view.View",
      eNoNameRule)
 
 ROLE(MATHML_UNDER_OVER,
      "mathml under over",
      ATK_ROLE_SECTION,
      NSAccessibilityGroupRole,
      0,
      IA2_ROLE_UNKNOWN,
+     "android.view.View",
      eNoNameRule)
 
 ROLE(MATHML_MULTISCRIPTS,
      "mathml multiscripts",
      ATK_ROLE_SECTION,
      NSAccessibilityGroupRole,
      0,
      IA2_ROLE_UNKNOWN,
+     "android.view.View",
      eNoNameRule)
 
 ROLE(MATHML_TABLE,
      "mathml table",
      ATK_ROLE_TABLE,
      NSAccessibilityGroupRole,
      0,
      IA2_ROLE_UNKNOWN,
+     "android.widget.GridView",
      eNoNameRule)
 
 ROLE(MATHML_LABELED_ROW,
      "mathml labeled row",
      ATK_ROLE_TABLE_ROW,
      NSAccessibilityGroupRole,
      0,
      IA2_ROLE_UNKNOWN,
+     "android.view.View",
      eNoNameRule)
 
 ROLE(MATHML_TABLE_ROW,
      "mathml table row",
      ATK_ROLE_TABLE_ROW,
      NSAccessibilityGroupRole,
      0,
      IA2_ROLE_UNKNOWN,
+     "android.view.View",
      eNoNameRule)
 
 ROLE(MATHML_CELL,
      "mathml cell",
      ATK_ROLE_TABLE_CELL,
      NSAccessibilityGroupRole,
      0,
      IA2_ROLE_UNKNOWN,
+     "android.view.View",
      eNoNameRule)
 
 ROLE(MATHML_ACTION,
      "mathml action",
      ATK_ROLE_SECTION,
      NSAccessibilityGroupRole,
      0,
      IA2_ROLE_UNKNOWN,
+     "android.view.View",
      eNoNameRule)
 
 ROLE(MATHML_ERROR,
      "mathml error",
      ATK_ROLE_SECTION,
      NSAccessibilityGroupRole,
      0,
      IA2_ROLE_UNKNOWN,
+     "android.view.View",
      eNoNameRule)
 
 ROLE(MATHML_STACK,
      "mathml stack",
      ATK_ROLE_UNKNOWN,
      NSAccessibilityGroupRole,
      0,
      IA2_ROLE_UNKNOWN,
+     "android.view.View",
      eNoNameRule)
 
 ROLE(MATHML_LONG_DIVISION,
      "mathml long division",
      ATK_ROLE_UNKNOWN,
      NSAccessibilityGroupRole,
      0,
      IA2_ROLE_UNKNOWN,
+     "android.view.View",
      eNoNameRule)
 
 ROLE(MATHML_STACK_GROUP,
      "mathml stack group",
      ATK_ROLE_UNKNOWN,
      NSAccessibilityGroupRole,
      0,
      IA2_ROLE_UNKNOWN,
+     "android.view.View",
      eNoNameRule)
 
 ROLE(MATHML_STACK_ROW,
      "mathml stack row",
      ATK_ROLE_UNKNOWN,
      NSAccessibilityGroupRole,
      0,
      IA2_ROLE_UNKNOWN,
+     "android.view.View",
      eNoNameRule)
 
 ROLE(MATHML_STACK_CARRIES,
      "mathml stack carries",
      ATK_ROLE_UNKNOWN,
      NSAccessibilityGroupRole,
      0,
      IA2_ROLE_UNKNOWN,
+     "android.view.View",
      eNoNameRule)
 
 ROLE(MATHML_STACK_CARRY,
      "mathml stack carry",
      ATK_ROLE_UNKNOWN,
      NSAccessibilityGroupRole,
      0,
      IA2_ROLE_UNKNOWN,
+     "android.view.View",
      eNoNameRule)
 
 ROLE(MATHML_STACK_LINE,
      "mathml stack line",
      ATK_ROLE_UNKNOWN,
      NSAccessibilityGroupRole,
      0,
      IA2_ROLE_UNKNOWN,
+     "android.view.View",
      eNoNameRule)
 
 ROLE(RADIO_GROUP,
      "grouping",
      ATK_ROLE_PANEL,
      NSAccessibilityRadioGroupRole,
      ROLE_SYSTEM_GROUPING,
      ROLE_SYSTEM_GROUPING,
+     "android.view.View",
      eNoNameRule)
 
 ROLE(TEXT,
      "text",
      ATK_ROLE_STATIC,
      NSAccessibilityGroupRole,
      USE_ROLE_STRING,
      IA2_ROLE_TEXT_FRAME,
+     "android.view.View",
      eNameFromSubtreeIfReqRule)
 
 ROLE(DETAILS,
      "details",
      ATK_ROLE_PANEL,
      NSAccessibilityGroupRole,
      ROLE_SYSTEM_GROUPING,
      ROLE_SYSTEM_GROUPING,
+     "android.view.View",
      eNoNameRule)
 
 ROLE(SUMMARY,
      "summary",
      ATK_ROLE_PUSH_BUTTON,
      NSAccessibilityGroupRole,
      ROLE_SYSTEM_PUSHBUTTON,
      ROLE_SYSTEM_PUSHBUTTON,
+     "android.widget.Button",
      eNameFromSubtreeRule)
 
 ROLE(LANDMARK,
      "landmark",
      ATK_ROLE_LANDMARK,
      NSAccessibilityGroupRole,
      USE_ROLE_STRING,
      IA2_ROLE_LANDMARK,
+     "android.view.View",
      eNoNameRule)
 
 ROLE(NAVIGATION,
      "navigation",
      ATK_ROLE_LANDMARK,
      NSAccessibilityGroupRole,
      USE_ROLE_STRING,
      IA2_ROLE_LANDMARK,
+     "android.view.View",
      eNoNameRule)
 
 ROLE(FOOTNOTE,
      "footnote",
      ATK_ROLE_FOOTNOTE,
      NSAccessibilityGroupRole,
      USE_ROLE_STRING,
      IA2_ROLE_FOOTNOTE,
+     "android.view.View",
      eNoNameRule)
 
 ROLE(ARTICLE,
      "article",
      ATK_ROLE_ARTICLE,
      NSAccessibilityGroupRole,
      ROLE_SYSTEM_DOCUMENT,
      ROLE_SYSTEM_DOCUMENT,
+     "android.view.View",
      eNoNameRule)
 
 ROLE(REGION,
      "region",
      ATK_ROLE_LANDMARK,
      NSAccessibilityGroupRole,
      USE_ROLE_STRING,
      IA2_ROLE_LANDMARK,
+     "android.view.View",
      eNoNameRule)
 
 // A composite widget with a text input and popup. Used for ARIA role combobox.
 // See also COMBOBOX.
 ROLE(EDITCOMBOBOX,
      "editcombobox",
      ATK_ROLE_COMBO_BOX,
      NSAccessibilityComboBoxRole,
      ROLE_SYSTEM_COMBOBOX,
      ROLE_SYSTEM_COMBOBOX,
+     "android.widget.EditText",
      eNameFromValueRule)
 
 ROLE(BLOCKQUOTE,
      "blockquote",
      ATK_ROLE_BLOCK_QUOTE,
      NSAccessibilityGroupRole,
      ROLE_SYSTEM_GROUPING,
      IA2_ROLE_BLOCK_QUOTE,
+     "android.view.View",
      eNoNameRule)
 
 ROLE(CONTENT_DELETION,
      "content deletion",
      ATK_ROLE_SECTION,
      NSAccessibilityGroupRole,
      USE_ROLE_STRING,
      IA2_ROLE_CONTENT_DELETION,
+     "android.view.View",
      eNoNameRule)
 
 ROLE(CONTENT_INSERTION,
      "content insertion",
      ATK_ROLE_SECTION,
      NSAccessibilityGroupRole,
      USE_ROLE_STRING,
      IA2_ROLE_CONTENT_INSERTION,
+     "android.view.View",
      eNoNameRule)
--- a/accessible/base/moz.build
+++ b/accessible/base/moz.build
@@ -8,16 +8,17 @@ EXPORTS += [
     'AccEvent.h',
     'nsAccessibilityService.h'
 ]
 
 EXPORTS.mozilla.a11y += [
     'AccTypes.h',
     'DocManager.h',
     'FocusManager.h',
+    'IDSet.h',
     'Platform.h',
     'RelationType.h',
     'Role.h',
     'SelectionManager.h',
     'States.h',
 ]
 
 if CONFIG['MOZ_DEBUG']:
--- a/accessible/base/nsAccessibilityService.cpp
+++ b/accessible/base/nsAccessibilityService.cpp
@@ -781,17 +781,17 @@ nsAccessibilityService::RecreateAccessib
   if (document)
     document->RecreateAccessible(aContent);
 }
 
 void
 nsAccessibilityService::GetStringRole(uint32_t aRole, nsAString& aString)
 {
 #define ROLE(geckoRole, stringRole, atkRole, \
-             macRole, msaaRole, ia2Role, nameRule) \
+             macRole, msaaRole, ia2Role, androidClass, nameRule) \
   case roles::geckoRole: \
     aString.AssignLiteral(stringRole); \
     return;
 
   switch (aRole) {
 #include "RoleMap.h"
     default:
       aString.AssignLiteral("unknown");
@@ -1388,17 +1388,17 @@ nsAccessibilityService::Init()
     gApplicationAccessible = new ApplicationAccessible();
 #endif // defined(XP_WIN)
   }
 
   NS_ADDREF(gApplicationAccessible); // will release in Shutdown()
   gApplicationAccessible->Init();
 
   CrashReporter::
-    AnnotateCrashReport(NS_LITERAL_CSTRING("Accessibility"),
+    AnnotateCrashReport(CrashReporter::Annotation::Accessibility,
                         NS_LITERAL_CSTRING("Active"));
 
 #ifdef XP_WIN
   sPendingPlugins = new nsTArray<nsCOMPtr<nsIContent> >;
   sPluginTimers = new nsTArray<nsCOMPtr<nsITimer> >;
 #endif
 
   // Now its safe to start platform accessibility.
--- a/accessible/base/nsTextEquivUtils.cpp
+++ b/accessible/base/nsTextEquivUtils.cpp
@@ -347,17 +347,17 @@ nsTextEquivUtils::AppendString(nsAString
 
   return true;
 }
 
 uint32_t
 nsTextEquivUtils::GetRoleRule(role aRole)
 {
 #define ROLE(geckoRole, stringRole, atkRole, \
-             macRole, msaaRole, ia2Role, nameRule) \
+             macRole, msaaRole, ia2Role, androidClass, nameRule) \
   case roles::geckoRole: \
     return nameRule;
 
   switch (aRole) {
 #include "RoleMap.h"
     default:
       MOZ_CRASH("Unknown role.");
   }
--- a/accessible/mac/mozAccessible.mm
+++ b/accessible/mac/mozAccessible.mm
@@ -708,17 +708,17 @@ ConvertToNSArray(nsTArray<ProxyAccessibl
     #ifdef DEBUG_A11Y
       NS_ASSERTION(nsAccUtils::IsTextInterfaceSupportCorrect(accWrap),
                    "Does not support Text when it should");
     #endif
   } else if (![self getProxyAccessible]) {
     return nil;
   }
 
-#define ROLE(geckoRole, stringRole, atkRole, macRole, msaaRole, ia2Role, nameRule) \
+#define ROLE(geckoRole, stringRole, atkRole, macRole, msaaRole, ia2Role, androidClass, nameRule) \
   case roles::geckoRole: \
     return macRole;
 
   switch (mRole) {
 #include "RoleMap.h"
     default:
       MOZ_ASSERT_UNREACHABLE("Unknown role.");
       return NSAccessibilityUnknownRole;
--- a/accessible/tests/mochitest/name/test_browserui.xul
+++ b/accessible/tests/mochitest/name/test_browserui.xul
@@ -27,17 +27,17 @@
     function addTab(aURL)
     {
       this.eventSeq = [
         new invokerChecker(EVENT_DOCUMENT_LOAD_COMPLETE, tabDocumentAt, 1)
       ];
 
       this.invoke = function addTab_invoke()
       {
-        tabBrowser().addTab(aURL);
+        tabBrowser().addTrustedTab(aURL);
       }
 
       this.getID = function addTab_getID()
       {
         return "add tab: " + aURL;
       }
     }
 
--- a/accessible/windows/ia2/ia2Accessible.cpp
+++ b/accessible/windows/ia2/ia2Accessible.cpp
@@ -163,17 +163,17 @@ ia2Accessible::role(long* aRole)
     return E_INVALIDARG;
   *aRole = 0;
 
   AccessibleWrap* acc = static_cast<AccessibleWrap*>(this);
   if (acc->IsDefunct())
     return CO_E_OBJNOTCONNECTED;
 
 #define ROLE(_geckoRole, stringRole, atkRole, macRole, \
-             msaaRole, ia2Role, nameRule) \
+             msaaRole, ia2Role, androidClass, nameRule) \
   case roles::_geckoRole: \
     *aRole = ia2Role; \
     break;
 
   a11y::role geckoRole;
   MOZ_ASSERT(!acc->IsProxy());
   geckoRole = acc->Role();
   switch (geckoRole) {
--- a/accessible/windows/msaa/AccessibleWrap.cpp
+++ b/accessible/windows/msaa/AccessibleWrap.cpp
@@ -471,17 +471,17 @@ AccessibleWrap::get_accRole(
                "Does not support Text when it should");
 #endif
 
   geckoRole = Role();
 
   uint32_t msaaRole = 0;
 
 #define ROLE(_geckoRole, stringRole, atkRole, macRole, \
-             _msaaRole, ia2Role, nameRule) \
+             _msaaRole, ia2Role, androidClass, nameRule) \
   case roles::_geckoRole: \
     msaaRole = _msaaRole; \
     break;
 
   switch (geckoRole) {
 #include "RoleMap.h"
     default:
       MOZ_CRASH("Unknown role.");
--- a/accessible/windows/msaa/Compatibility.cpp
+++ b/accessible/windows/msaa/Compatibility.cpp
@@ -237,17 +237,17 @@ Compatibility::HasKnownNonUiaConsumer()
 
 void
 Compatibility::Init()
 {
   // Note we collect some AT statistics/telemetry here for convenience.
   InitConsumers();
 
   CrashReporter::
-    AnnotateCrashReport(NS_LITERAL_CSTRING("AccessibilityInProcClient"),
+    AnnotateCrashReport(CrashReporter::Annotation::AccessibilityInProcClient,
                         nsPrintfCString("0x%X", sConsumers));
 
   // Gather telemetry
   uint32_t temp = sConsumers;
   for (int i = 0; temp; i++) {
     if (temp & 0x1)
       statistics::A11yConsumers(i);
 
@@ -431,18 +431,19 @@ UseIAccessibleProxyStub()
   // Otherwise we try the proxy/stub
   if (IsIAccessiblePSRegistered()) {
     return true;
   }
 
   // If we reach this point then something is seriously wrong with the
   // IAccessible configuration in the computer's registry. Let's annotate this
   // so that we can easily determine this condition during crash analysis.
-  CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("IAccessibleConfig"),
-                                     NS_LITERAL_CSTRING("NoSystemTypeLibOrPS"));
+  CrashReporter::AnnotateCrashReport(
+    CrashReporter::Annotation::IAccessibleConfig,
+    NS_LITERAL_CSTRING("NoSystemTypeLibOrPS"));
   return false;
 }
 
 #endif // !defined(HAVE_64BIT_BUILD)
 
 uint16_t
 Compatibility::GetActCtxResourceId()
 {
--- a/accessible/windows/msaa/LazyInstantiator.cpp
+++ b/accessible/windows/msaa/LazyInstantiator.cpp
@@ -12,17 +12,16 @@
 #include "mozilla/a11y/Platform.h"
 #include "mozilla/Assertions.h"
 #include "mozilla/mscom/MainThreadRuntime.h"
 #include "mozilla/mscom/Registration.h"
 #include "mozilla/UniquePtr.h"
 #include "nsAccessibilityService.h"
 #include "nsWindowsHelpers.h"
 #include "nsCOMPtr.h"
-#include "nsExceptionHandler.h"
 #include "nsIFile.h"
 #include "nsXPCOM.h"
 #include "RootAccessibleWrap.h"
 #include "WinUtils.h"
 
 #include <oaidl.h>
 
 #if !defined(STATE_SYSTEM_NORMAL)
--- a/accessible/windows/msaa/Platform.cpp
+++ b/accessible/windows/msaa/Platform.cpp
@@ -353,17 +353,17 @@ AccumulateInstantiatorTelemetry(const ns
 
   if (!aValue.IsEmpty()) {
 #if defined(MOZ_TELEMETRY_REPORTING)
     Telemetry::ScalarSet(Telemetry::ScalarID::A11Y_INSTANTIATORS,
                          aValue);
 #endif // defined(MOZ_TELEMETRY_REPORTING)
 #if defined(MOZ_CRASHREPORTER)
     CrashReporter::
-      AnnotateCrashReport(NS_LITERAL_CSTRING("AccessibilityClient"),
+      AnnotateCrashReport(CrashReporter::Annotation::AccessibilityClient,
                           NS_ConvertUTF16toUTF8(aValue));
 #endif // defined(MOZ_CRASHREPORTER)
   }
 }
 
 static void
 GatherInstantiatorTelemetry(nsIFile* aClientExe)
 {
--- a/accessible/windows/msaa/moz.build
+++ b/accessible/windows/msaa/moz.build
@@ -7,17 +7,16 @@
 EXPORTS += [
     'IUnknownImpl.h',
 ]
 
 EXPORTS.mozilla.a11y += [
     'AccessibleWrap.h',
     'Compatibility.h',
     'HyperTextAccessibleWrap.h',
-    'IDSet.h',
     'LazyInstantiator.h',
     'MsaaIdGenerator.h',
     'nsWinUtils.h',
 ]
 
 UNIFIED_SOURCES += [
     'AccessibleWrap.cpp',
     'ApplicationAccessibleWrap.cpp',
--- a/browser/base/content/browser-captivePortal.js
+++ b/browser/base/content/browser-captivePortal.js
@@ -242,17 +242,22 @@ var CaptivePortalWatcher = {
   ensureCaptivePortalTab() {
     let tab;
     if (this._captivePortalTab) {
       tab = this._captivePortalTab.get();
     }
 
     // If the tab is gone or going, we need to open a new one.
     if (!tab || tab.closing || !tab.parentNode) {
-      tab = gBrowser.addTab(this.canonicalURL, { ownerTab: gBrowser.selectedTab });
+      tab = gBrowser.addWebTab(this.canonicalURL, {
+        ownerTab: gBrowser.selectedTab,
+        triggeringPrincipal: Services.scriptSecurityManager.createNullPrincipal({
+          userContextId: gBrowser.contentPrincipal.userContextId,
+        }),
+      });
       this._captivePortalTab = Cu.getWeakReference(tab);
     }
 
     gBrowser.selectedTab = tab;
 
     let canonicalURI = makeURI(this.canonicalURL);
 
     // When we are no longer captive, close the tab if it's at the canonical URL.
--- a/browser/base/content/browser-context.inc
+++ b/browser/base/content/browser-context.inc
@@ -303,17 +303,17 @@
                 accesskey="&selectAllCmd.accesskey;"
                 command="cmd_selectAll"/>
       <menuseparator id="context-sep-selectall"/>
       <menuitem id="context-keywordfield"
                 label="&keywordfield.label;"
                 accesskey="&keywordfield.accesskey;"
                 oncommand="AddKeywordForSearchField();"/>
       <menuitem id="context-searchselect"
-                oncommand="BrowserSearch.loadSearchFromContext(this.searchTerms);"/>
+                oncommand="BrowserSearch.loadSearchFromContext(this.searchTerms, this.principal);"/>
       <menuseparator id="context-sep-sendlinktodevice" class="sync-ui-item"
                      hidden="true"/>
       <menu id="context-sendlinktodevice"
             class="sync-ui-item"
             label="&sendLinkToDevice.label;"
             accesskey="&sendLinkToDevice.accesskey;"
             hidden="true">
         <menupopup id="context-sendlinktodevice-popup"
--- a/browser/base/content/browser.js
+++ b/browser/base/content/browser.js
@@ -533,17 +533,18 @@ const gStoragePressureObserver = {
     let usage = subject.QueryInterface(Ci.nsISupportsPRUint64).data;
     let prefStrBundle = document.getElementById("bundle_preferences");
     let brandShortName = document.getElementById("bundle_brand").getString("brandShortName");
     buttons.push({
       label: prefStrBundle.getString("spaceAlert.learnMoreButton.label"),
       accessKey: prefStrBundle.getString("spaceAlert.learnMoreButton.accesskey"),
       callback(notificationBar, button) {
         let learnMoreURL = Services.urlFormatter.formatURLPref("app.support.baseURL") + "storage-permissions";
-        gBrowser.selectedTab = gBrowser.addTab(learnMoreURL);
+        // This is a content URL, loaded from trusted UX.
+        gBrowser.selectedTab = gBrowser.addTrustedTab(learnMoreURL);
       }
     });
     if (usage < USAGE_THRESHOLD_BYTES) {
       // The firefox-used space < 5GB, then warn user to free some disk space.
       // This is because this usage is small and not the main cause for space issue.
       // In order to avoid the bad and wrong impression among users that
       // firefox eats disk space a lot, indicate users to clean up other disk space.
       msg = prefStrBundle.getFormattedString("spaceAlert.under5GB.message", [brandShortName]);
@@ -3966,18 +3967,21 @@ const BrowserSearch = {
    * @param purpose [optional]
    *        A string meant to indicate the context of the search request. This
    *        allows the search service to provide a different nsISearchSubmission
    *        depending on e.g. where the search is triggered in the UI.
    *
    * @return engine The search engine used to perform a search, or null if no
    *                search was performed.
    */
-  _loadSearch(searchText, useNewTab, purpose) {
+  _loadSearch(searchText, useNewTab, purpose, triggeringPrincipal) {
     let engine;
+    if (!triggeringPrincipal) {
+      throw new Error("Required argument triggeringPrincipal missing within _loadSearch");
+    }
 
     // If the search bar is visible, use the current engine, otherwise, fall
     // back to the default engine.
     if (isElementVisible(this.searchBar))
       engine = Services.search.currentEngine;
     else
       engine = Services.search.defaultEngine;
 
@@ -3991,43 +3995,30 @@ const BrowserSearch = {
       return null;
     }
 
     let inBackground = Services.prefs.getBoolPref("browser.search.context.loadInBackground");
     openLinkIn(submission.uri.spec,
                useNewTab ? "tab" : "current",
                { postData: submission.postData,
                  inBackground,
-                 relatedToCurrent: true });
+                 relatedToCurrent: true,
+                 triggeringPrincipal });
 
     return engine;
   },
 
   /**
-   * Just like _loadSearch, but preserving an old API.
-   *
-   * @return string Name of the search engine used to perform a search or null
-   *         if a search was not performed.
-   */
-  loadSearch: function BrowserSearch_search(searchText, useNewTab, purpose) {
-    let engine = BrowserSearch._loadSearch(searchText, useNewTab, purpose);
-    if (!engine) {
-      return null;
-    }
-    return engine.name;
-  },
-
-  /**
    * Perform a search initiated from the context menu.
    *
    * This should only be called from the context menu. See
    * BrowserSearch.loadSearch for the preferred API.
    */
-  loadSearchFromContext(terms) {
-    let engine = BrowserSearch._loadSearch(terms, true, "contextmenu");
+  loadSearchFromContext(terms, triggeringPrincipal) {
+    let engine = BrowserSearch._loadSearch(terms, true, "contextmenu", triggeringPrincipal);
     if (engine) {
       BrowserSearch.recordSearchInTelemetry(engine, "contextmenu");
     }
   },
 
   pasteAndSearch(event) {
     BrowserSearch.searchBar.select();
     goDoCommand("cmd_paste");
@@ -7092,17 +7083,17 @@ function BrowserOpenAddonsMgr(aView) {
       aSubject.QueryInterface(Ci.nsIDOMWindow);
       aSubject.focus();
       resolve(aSubject);
     }, "EM-loaded");
   });
 }
 
 function BeginRecordExecution() {
-  gBrowser.selectedTab = gBrowser.addTab("about:blank", { recordExecution: "*" });
+  gBrowser.selectedTab = gBrowser.addWebTab("about:blank", { recordExecution: "*" });
 }
 
 function SaveRecordedExecution() {
   let fp = Cc["@mozilla.org/filepicker;1"].createInstance(Ci.nsIFilePicker);
   let window = gBrowser.ownerGlobal;
   fp.init(window, null, Ci.nsIFilePicker.modeSave);
   fp.open(rv => {
     if (rv == Ci.nsIFilePicker.returnOK || rv == Ci.nsIFilePicker.returnReplace) {
@@ -7115,17 +7106,17 @@ function SaveRecordedExecution() {
 }
 
 function BeginReplayExecution() {
   let fp = Cc["@mozilla.org/filepicker;1"].createInstance(Ci.nsIFilePicker);
   let window = gBrowser.ownerGlobal;
   fp.init(window, null, Ci.nsIFilePicker.modeOpen);
   fp.open(rv => {
     if (rv == Ci.nsIFilePicker.returnOK || rv == Ci.nsIFilePicker.returnReplace) {
-      gBrowser.selectedTab = gBrowser.addTab(null, { replayExecution: fp.file.path });
+      gBrowser.selectedTab = gBrowser.addWebTab(null, { replayExecution: fp.file.path });
     }
   });
 }
 
 function AddKeywordForSearchField() {
   let mm = gBrowser.selectedBrowser.messageManager;
 
   let onMessage = (message) => {
@@ -7384,17 +7375,18 @@ const gAccessibilityServiceIndicator = {
     return Services.prefs.getBoolPref("accessibility.indicator.enabled");
   },
 
   handleEvent({ key, type }) {
     if ((type === "keypress" && [" ", "Enter"].includes(key)) ||
          type === "click") {
       let a11yServicesSupportURL =
         Services.urlFormatter.formatURLPref("accessibility.support.url");
-      gBrowser.selectedTab = gBrowser.addTab(a11yServicesSupportURL);
+      // This is a known URL coming from trusted UI
+      gBrowser.selectedTab = gBrowser.addTrustedTab(a11yServicesSupportURL);
       Services.telemetry.scalarSet("a11y.indicator_acted_on", true);
     }
   },
 
   uninit() {
     Services.prefs.removeObserver("accessibility.indicator.enabled", this);
     Services.obs.removeObserver(this, "a11y-init-or-shutdown");
     this.update();
--- a/browser/base/content/nsContextMenu.js
+++ b/browser/base/content/nsContextMenu.js
@@ -1497,16 +1497,17 @@ nsContextMenu.prototype = {
 
   // Formats the 'Search <engine> for "<selection or link text>"' context menu.
   formatSearchContextItem() {
     var menuItem = document.getElementById("context-searchselect");
     let selectedText = this.isTextSelected ? this.textSelected : this.linkTextStr;
 
     // Store searchTerms in context menu item so we know what to search onclick
     menuItem.searchTerms = selectedText;
+    menuItem.principal = this.principal;
 
     // Copied to alert.js' prefillAlertInfo().
     // If the JS character after our truncation point is a trail surrogate,
     // include it in the truncated string to avoid splitting a surrogate pair.
     if (selectedText.length > 15) {
       let truncLength = 15;
       let truncChar = selectedText[15].charCodeAt(0);
       if (truncChar >= 0xDC00 && truncChar <= 0xDFFF)
--- a/browser/base/content/tabbrowser.js
+++ b/browser/base/content/tabbrowser.js
@@ -1368,16 +1368,21 @@ window._gBrowser = {
       aOpener = params.opener;
       aOpenerBrowser = params.openerBrowser;
       aCreateLazyBrowser = params.createLazyBrowser;
       aNextTabParentId = params.nextTabParentId;
       aFocusUrlBar = params.focusUrlBar;
       aName = params.name;
     }
 
+    // all callers of loadOneTab need to pass a valid triggeringPrincipal.
+    if (!aTriggeringPrincipal) {
+      throw new Error("Required argument triggeringPrincipal missing within loadOneTab");
+    }
+
     var bgLoad = (aLoadInBackground != null) ? aLoadInBackground :
       Services.prefs.getBoolPref("browser.tabs.loadInBackground");
     var owner = bgLoad ? null : this.selectedTab;
 
     var tab = this.addTab(aURI, {
       triggeringPrincipal: aTriggeringPrincipal,
       referrerURI: aReferrerURI,
       referrerPolicy: aReferrerPolicy,
@@ -2129,16 +2134,40 @@ window._gBrowser = {
     tab.removeAttribute("linkedpanel");
 
     this._createLazyBrowser(tab);
 
     let evt = new CustomEvent("TabBrowserDiscarded", { bubbles: true });
     tab.dispatchEvent(evt);
   },
 
+  /**
+   * Loads a tab with a default null principal unless specified
+   */
+  addWebTab(aURI, params = {}) {
+    if (!params.triggeringPrincipal) {
+      params.triggeringPrincipal = Services.scriptSecurityManager.createNullPrincipal({
+        userContextId: params.userContextId,
+      });
+    }
+    if (Services.scriptSecurityManager.isSystemPrincipal(params.triggeringPrincipal)) {
+      throw new Error("System principal should never be passed into addWebTab()");
+    }
+    return this.addTab(aURI, params);
+  },
+
+  /**
+   * Must only be used sparingly for content that came from Chrome context
+   * If in doubt use addWebTab
+   */
+  addTrustedTab(aURI, params = {}) {
+    params.triggeringPrincipal = Services.scriptSecurityManager.getSystemPrincipal();
+    return this.addTab(aURI, params);
+  },
+
   // eslint-disable-next-line complexity
   addTab(aURI, {
     allowMixedContent,
     allowThirdPartyFixup,
     bulkOrderedOpen,
     charset,
     createLazyBrowser,
     disallowInheritPrincipal,
@@ -2164,16 +2193,23 @@ window._gBrowser = {
     sameProcessAsFrameLoader,
     skipAnimation,
     skipBackgroundNotify,
     triggeringPrincipal,
     userContextId,
     recordExecution,
     replayExecution,
   } = {}) {
+    // all callers of addTab that pass a params object need to pass
+    // a valid triggeringPrincipal.
+    if (!triggeringPrincipal) {
+      throw new Error("Required argument triggeringPrincipal missing within addTab");
+    }
+
+
     // if we're adding tabs, we're past interrupt mode, ditch the owner
     if (this.selectedTab.owner) {
       this.selectedTab.owner = null;
     }
 
     // Find the tab that opened this one, if any. This is used for
     // determining positioning, and inherited attributes such as the
     // user context ID.
@@ -2819,17 +2855,19 @@ window._gBrowser = {
     this._removingTabs.push(aTab);
     this._visibleTabs = null; // invalidate cache
 
     // Invalidate hovered tab state tracking for this closing tab.
     if (this.tabContainer._hoveredTab == aTab)
       aTab._mouseleave();
 
     if (newTab)
-      this.addTab(BROWSER_NEW_TAB_URL, { skipAnimation: true });
+      this.addTrustedTab(BROWSER_NEW_TAB_URL, {
+        skipAnimation: true,
+      });
     else
       TabBarVisibility.update();
 
     // We're committed to closing the tab now.
     // Dispatch a notification.
     // We dispatch it before any teardown so that event listeners can
     // inspect the tab that's about to close.
     var evt = new CustomEvent("TabClose", { bubbles: true, detail: { adoptedBy: aAdoptedByTab } });
@@ -3600,17 +3638,17 @@ window._gBrowser = {
     if (aIndex < numPinned || (aTab.pinned && aIndex == numPinned)) {
       params.pinned = true;
     }
 
     if (aTab.hasAttribute("usercontextid")) {
       // new tab must have the same usercontextid as the old one
       params.userContextId = aTab.getAttribute("usercontextid");
     }
-    let newTab = this.addTab("about:blank", params);
+    let newTab = this.addWebTab("about:blank", params);
     let newBrowser = this.getBrowserForTab(newTab);
 
     // Stop the about:blank load.
     newBrowser.stop();
     // Make sure it has a docshell.
     newBrowser.docShell;
 
     // We need to select the tab before calling swapBrowsersAndCloseOther
@@ -5282,20 +5320,32 @@ var TabContextMenu = {
   },
   createReopenInContainerMenu(event) {
     createUserContextMenu(event, {
       isContextMenu: true,
       excludeUserContextId: this.contextTab.getAttribute("usercontextid"),
     });
   },
   reopenInContainer(event) {
+    let userContextId = parseInt(event.target.getAttribute("data-usercontextid"));
+    /* Create a triggering principal that is able to load the new tab
+       For codebase principals that are about: chrome: or resource: we need system to load them.
+       Anything other than system principal needs to have the new userContextId.
+    */
+    let triggeringPrincipal = this.contextTab.linkedBrowser.contentPrincipal;
+    if (triggeringPrincipal.isNullPrincipal) {
+      triggeringPrincipal = Services.scriptSecurityManager.createNullPrincipal({ userContextId });
+    } else if (triggeringPrincipal.isCodebasePrincipal) {
+      triggeringPrincipal = Services.scriptSecurityManager.createCodebasePrincipal(triggeringPrincipal.URI, { userContextId });
+    }
     let newTab = gBrowser.addTab(this.contextTab.linkedBrowser.currentURI.spec, {
-      userContextId: parseInt(event.target.getAttribute("data-usercontextid")),
+      userContextId,
       pinned: this.contextTab.pinned,
       index: this.contextTab._tPos + 1,
+      triggeringPrincipal,
     });
 
     if (gBrowser.selectedTab == this.contextTab) {
       gBrowser.selectedTab = newTab;
     }
     if (this.contextTab.muted) {
       if (!newTab.muted) {
         newTab.toggleMuteAudio(this.contextTab.muteReason);
--- a/browser/base/content/test/general/browser_beforeunload_duplicate_dialogs.js
+++ b/browser/base/content/test/general/browser_beforeunload_duplicate_dialogs.js
@@ -40,17 +40,17 @@ add_task(async function closeLastTabInWi
   ok(newWin.closed, "Window should be closed.");
 });
 
 add_task(async function closeWindowWithMultipleTabsIncludingOneBeforeUnload() {
   Services.prefs.setBoolPref("browser.tabs.warnOnClose", false);
   let newWin = await promiseOpenAndLoadWindow({}, true);
   let firstTab = newWin.gBrowser.selectedTab;
   await promiseTabLoadEvent(firstTab, TEST_PAGE);
-  await promiseTabLoadEvent(newWin.gBrowser.addTab(), "http://example.com/");
+  await promiseTabLoadEvent(BrowserTestUtils.addTab(newWin.gBrowser), "http://example.com/");
   let windowClosedPromise = BrowserTestUtils.domWindowClosed(newWin);
   expectingDialog = true;
   newWin.BrowserTryToCloseWindow();
   await windowClosedPromise;
   ok(!expectingDialog, "There should have been a dialog.");
   ok(newWin.closed, "Window should be closed.");
   Services.prefs.clearUserPref("browser.tabs.warnOnClose");
 });
--- a/browser/base/content/test/general/browser_bookmark_popup.js
+++ b/browser/base/content/test/general/browser_bookmark_popup.js
@@ -21,16 +21,24 @@ StarUI._closePanelQuickForTesting = true
 
 add_task(async function setup() {
   bookmarkPanel.setAttribute("animate", false);
   registerCleanupFunction(() => {
     bookmarkPanel.removeAttribute("animate");
   });
 });
 
+function mouseout() {
+  let mouseOutPromise = BrowserTestUtils.waitForEvent(bookmarkPanel, "mouseout");
+  EventUtils.synthesizeMouse(bookmarkPanel, 0, 0, {type: "mouseout"});
+  EventUtils.synthesizeMouseAtCenter(gURLBar, {type: "mousemove"});
+  info("Waiting for mouseout event");
+  return mouseOutPromise;
+}
+
 async function test_bookmarks_popup({isNewBookmark, popupShowFn, popupEditFn,
                                 shouldAutoClose, popupHideFn, isBookmarkRemoved}) {
   await BrowserTestUtils.withNewTab({gBrowser, url: TEST_URL}, async function(browser) {
     try {
       if (!isNewBookmark) {
         await PlacesUtils.bookmarks.insert({
           parentGuid: PlacesUtils.bookmarks.unfiledGuid,
           url: TEST_URL,
@@ -165,21 +173,17 @@ add_task(async function panel_shown_for_
       info("Waiting for mousemove event");
       await mouseMovePromise;
       info("Got mousemove event");
 
       await new Promise(resolve => setTimeout(resolve, 400));
       is(bookmarkPanel.state, "open", "Panel should still be open on mousemove");
     },
     async popupHideFn() {
-      let mouseOutPromise = BrowserTestUtils.waitForEvent(bookmarkPanel, "mouseout");
-      EventUtils.synthesizeMouse(bookmarkPanel, 0, 0, {type: "mouseout"});
-      EventUtils.synthesizeMouseAtCenter(document.documentElement, {type: "mousemove"});
-      info("Waiting for mouseout event");
-      await mouseOutPromise;
+      await mouseout();
       info("Got mouseout event, should autoclose now");
     },
     shouldAutoClose: false,
     isBookmarkRemoved: false,
   });
 });
 
 add_task(async function panel_shown_for_new_bookmark_close_with_ESC() {
@@ -264,21 +268,17 @@ add_task(async function panel_shown_for_
       info("Got mousemove event");
 
       let compositionStartPromise = BrowserTestUtils.waitForEvent(bookmarkPanel, "compositionstart");
       EventUtils.synthesizeComposition({ type: "compositionstart" }, window);
       info("Waiting for compositionstart event");
       await compositionStartPromise;
       info("Got compositionstart event");
 
-      let mouseOutPromise = BrowserTestUtils.waitForEvent(bookmarkPanel, "mouseout");
-      EventUtils.synthesizeMouse(bookmarkPanel, 0, 0, {type: "mouseout"});
-      EventUtils.synthesizeMouseAtCenter(document.documentElement, {type: "mousemove"});
-      info("Waiting for mouseout event");
-      await mouseOutPromise;
+      await mouseout();
       info("Got mouseout event, but shouldn't run autoclose");
     },
     shouldAutoClose: false,
     popupHideFn() {
       EventUtils.synthesizeComposition({ type: "compositioncommitasis" });
       bookmarkPanel.hidePopup();
     },
     isBookmarkRemoved: false,
@@ -428,21 +428,17 @@ add_task(async function ctrl_d_new_bookm
       await mouseMovePromise;
       info("Got mousemove event");
 
       await new Promise(resolve => setTimeout(resolve, 400));
       is(bookmarkPanel.state, "open", "Panel should still be open on mousemove");
 
       EventUtils.synthesizeMouseAtCenter(bookmarkPanelTitle, {button: 1, type: "mousedown"});
 
-      let mouseOutPromise = BrowserTestUtils.waitForEvent(bookmarkPanel, "mouseout");
-      EventUtils.synthesizeMouse(bookmarkPanel, 0, 0, {type: "mouseout"});
-      EventUtils.synthesizeMouseAtCenter(document.documentElement, {type: "mousemove"});
-      info("Waiting for mouseout event");
-      await mouseOutPromise;
+      await mouseout();
     },
     shouldAutoClose: false,
     popupHideFn() {
       document.getElementById("editBookmarkPanelRemoveButton").click();
     },
     isBookmarkRemoved: true,
   });
 });
--- a/browser/base/content/test/general/browser_bug462673.js
+++ b/browser/base/content/test/general/browser_bug462673.js
@@ -15,17 +15,17 @@ add_task(async function() {
 
 add_task(async function() {
   var win = openDialog(AppConstants.BROWSER_CHROME_URL, "_blank", "chrome,all,dialog=no");
   await SimpleTest.promiseFocus(win);
 
   let tab = win.gBrowser.tabContainer.firstChild;
   await promiseTabLoadEvent(tab, getRootDirectory(gTestPath) + "test_bug462673.html");
 
-  var newTab = win.gBrowser.addTab();
+  var newTab = BrowserTestUtils.addTab(win.gBrowser);
   var newBrowser = newTab.linkedBrowser;
   win.gBrowser.removeTab(tab);
   ok(!win.closed, "Window stays open");
   if (!win.closed) {
     is(win.gBrowser.tabContainer.childElementCount, 1, "Window has one tab");
     is(win.gBrowser.browsers.length, 1, "Window has one browser");
     is(win.gBrowser.selectedTab, newTab, "Remaining tab is selected");
     is(win.gBrowser.selectedBrowser, newBrowser, "Browser for remaining tab is selected");
--- a/browser/base/content/test/general/browser_bug963945.js
+++ b/browser/base/content/test/general/browser_bug963945.js
@@ -5,17 +5,17 @@
 /*
  * This test ensures the about:addons tab is only
  * opened one time when in private browsing.
  */
 
 add_task(async function test() {
   let win = await BrowserTestUtils.openNewBrowserWindow({private: true});
 
-  let tab = win.gBrowser.selectedTab = win.gBrowser.addTab("about:addons");
+  let tab = win.gBrowser.selectedTab = BrowserTestUtils.addTab(win.gBrowser, "about:addons");
   await BrowserTestUtils.browserLoaded(tab.linkedBrowser);
   await promiseWaitForFocus(win);
 
   EventUtils.synthesizeKey("a", { ctrlKey: true, shiftKey: true }, win);
 
   is(win.gBrowser.tabs.length, 2, "about:addons tab was re-focused.");
   is(win.gBrowser.currentURI.spec, "about:addons", "Addons tab was opened.");
 
--- a/browser/base/content/test/general/browser_tab_dragdrop2.js
+++ b/browser/base/content/test/general/browser_tab_dragdrop2.js
@@ -12,17 +12,17 @@ add_task(async function() {
   let args = "chrome,all,dialog=no";
   let win = window.openDialog(AppConstants.BROWSER_CHROME_URL, "_blank", args, URI);
 
   // Wait until the tests were run.
   await promiseTestsDone(win);
   ok(true, "tests succeeded");
 
   // Create a second tab so that we can move the original one out.
-  win.gBrowser.addTab("about:blank", {skipAnimation: true});
+  BrowserTestUtils.addTab(win.gBrowser, "about:blank", {skipAnimation: true});
 
   // Tear off the original tab.
   let browser = win.gBrowser.selectedBrowser;
   let tabClosed = promiseWaitForEvent(browser, "pagehide", true);
   let win2 = win.gBrowser.replaceTabWithWindow(win.gBrowser.tabs[0]);
 
   // Add a 'TestsDone' event listener to ensure that the docShells is properly
   // swapped to the new window instead of the page being loaded again. If this
--- a/browser/base/content/test/general/browser_trackingUI_5.js
+++ b/browser/base/content/test/general/browser_trackingUI_5.js
@@ -92,17 +92,17 @@ add_task(async function testExceptionAdd
   let tabReloadPromise = promiseTabLoadEvent(tab);
   clickButton("#tracking-action-unblock");
   is(identityPopupState(), "closed", "foobar");
 
   await tabReloadPromise;
   testTrackingPageUnblocked();
 
   info("Test that the exception is remembered across tabs in the same private window");
-  tab = browser.selectedTab = browser.addTab();
+  tab = browser.selectedTab = BrowserTestUtils.addTab(browser);
 
   info("Load a test page containing tracking elements");
   await promiseTabLoadEvent(tab, TRACKING_PAGE);
   testTrackingPageUnblocked();
 
   await promiseWindowClosed(privateWin);
 });
 
--- a/browser/base/content/test/general/browser_utilityOverlay.js
+++ b/browser/base/content/test/general/browser_utilityOverlay.js
@@ -85,17 +85,17 @@ function test_getTopWin() {
 function test_getBoolPref() {
   is(getBoolPref("browser.search.openintab", false), false, "getBoolPref");
   is(getBoolPref("this.pref.doesnt.exist", true), true, "getBoolPref fallback");
   is(getBoolPref("this.pref.doesnt.exist", false), false, "getBoolPref fallback #2");
   runNextTest();
 }
 
 function test_openNewTabWith() {
-  openNewTabWith("http://example.com/");
+  openNewTabWith("http://example.com/", null, {triggeringPrincipal: Services.scriptSecurityManager.createNullPrincipal({})});
   let tab = gBrowser.selectedTab = gBrowser.tabs[1];
   BrowserTestUtils.browserLoaded(tab.linkedBrowser).then(() => {
     is(tab.linkedBrowser.currentURI.spec, "http://example.com/", "example.com loaded");
     gBrowser.removeCurrentTab();
     runNextTest();
   });
 }
 
--- a/browser/base/content/test/metaTags/browser_meta_tags.js
+++ b/browser/base/content/test/metaTags/browser_meta_tags.js
@@ -27,17 +27,17 @@ add_task(async function test_metadata() 
  * make sure the extra tab does not cause the debounce logic to be skipped. If
  * incorrectly skipped, the updated metadata would not include the delayed meta.
  */
 add_task(async function multiple_tabs() {
   const tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, TEST_PATH);
 
   // Add a background tab to cause another page to load *without* putting the
   // desired URL in a background tab, which results in its timers being throttled.
-  gBrowser.addTab();
+  BrowserTestUtils.addTab(gBrowser);
 
   // Wait until places has stored the page info
   const pageInfo = await waitForPageInfo(TEST_PATH);
   is(pageInfo.description, "og:description", "got the correct description");
   is(pageInfo.previewImageURL.href, "https://test.com/og-image-secure-url.jpg", "got the correct preview image");
 
   BrowserTestUtils.removeTab(tab);
   BrowserTestUtils.removeTab(gBrowser.selectedTab);
--- a/browser/base/content/test/performance/head.js
+++ b/browser/base/content/test/performance/head.js
@@ -298,17 +298,20 @@ function computeMaxTabCount() {
  *        How many about:blank tabs to open.
  */
 async function createTabs(howMany) {
   let uris = [];
   while (howMany--) {
     uris.push("about:blank");
   }
 
-  gBrowser.loadTabs(uris, { inBackground: true });
+  gBrowser.loadTabs(uris, {
+    inBackground: true,
+    triggeringPrincipal: Services.scriptSecurityManager.getSystemPrincipal(),
+  });
 
   await BrowserTestUtils.waitForCondition(() => {
     return Array.from(gBrowser.tabs).every(tab => tab._fullyOpen);
   });
 }
 
 /**
  * Removes all of the tabs except the originally selected
--- a/browser/base/content/test/referrer/head.js
+++ b/browser/base/content/test/referrer/head.js
@@ -205,17 +205,17 @@ function referrerTestCaseLoaded(aTestNum
                              REFERRER_POLICYSERVER_URL_ATTRIBUTE;
   let url = test.fromScheme + server +
             "?scheme=" + escape(test.toScheme) +
             "&policy=" + escape(test.policy || "") +
             "&rel=" + escape(test.rel || "") +
             "&cross=" + escape(test.cross || "");
   let browser = gTestWindow.gBrowser;
   return BrowserTestUtils.openNewForegroundTab(browser, () => {
-    browser.selectedTab = browser.addTab(url, aParams);
+    browser.selectedTab = BrowserTestUtils.addTab(browser, url, aParams);
   }, false, true);
 }
 
 /**
  * Checks the result of the referrer test, and moves on to the next test.
  * @param aTestNumber The test number - 0, 1, 2, ...
  * @param aNewWindow The new window where the referrer target opened, or null.
  * @param aNewTab The new tab where the referrer target opened, or null.
--- a/browser/base/content/test/tabs/browser_new_tab_insert_position.js
+++ b/browser/base/content/test/tabs/browser_new_tab_insert_position.js
@@ -149,17 +149,20 @@ async function doTest(aInsertRelatedAfte
   verifyTabState(newState);
 
   // Bug 1442679 - Test bulk opening with loadTabs loads the tabs in order
 
   let loadPromises = Promise.all(bulkLoad.map(url => BrowserTestUtils.waitForNewTab(gBrowser, url, false, true)));
   // loadTabs will insertAfterCurrent
   let nextTab = aInsertAfterCurrent ? gBrowser.selectedTab._tPos + 1 : gBrowser.tabs.length;
 
-  gBrowser.loadTabs(bulkLoad, { inBackground: true });
+  gBrowser.loadTabs(bulkLoad, {
+    inBackground: true,
+    triggeringPrincipal: Services.scriptSecurityManager.getSystemPrincipal(),
+  });
   await loadPromises;
   for (let i = nextTab, j = 0; j < bulkLoad.length; i++, j++) {
     is(gBrowser.tabs[i].linkedBrowser.currentURI.spec, bulkLoad[j], `bulkLoad tab pos ${i} matched`);
   }
 
   // Now we want to test that positioning remains correct after a session restore.
 
   // Restore pre-test state so we can restore and test tab ordering.
--- a/browser/base/content/test/tabs/browser_pinnedTabs_closeByKeyboard.js
+++ b/browser/base/content/test/tabs/browser_pinnedTabs_closeByKeyboard.js
@@ -16,17 +16,17 @@ function test() {
        "menu_close should always have key_close set");
   }
 
   let unpinnedTab = gBrowser.selectedTab;
   ok(!unpinnedTab.pinned, "We should have started with a regular tab selected");
 
   testState(false);
 
-  let pinnedTab = gBrowser.addTab();
+  let pinnedTab = BrowserTestUtils.addTab(gBrowser);
   gBrowser.pinTab(pinnedTab);
 
   // Just pinning the tab shouldn't change the key state.
   testState(false);
 
   // Test key state after selecting a tab.
   gBrowser.selectedTab = pinnedTab;
   testState(true);
@@ -40,17 +40,17 @@ function test() {
   // Test the key state after un/pinning the tab.
   gBrowser.unpinTab(pinnedTab);
   testState(false);
 
   gBrowser.pinTab(pinnedTab);
   testState(true);
 
   // Test that accel+w in a pinned tab selects the next tab.
-  let pinnedTab2 = gBrowser.addTab();
+  let pinnedTab2 = BrowserTestUtils.addTab(gBrowser);
   gBrowser.pinTab(pinnedTab2);
   gBrowser.selectedTab = pinnedTab;
 
   EventUtils.synthesizeKey("w", { accelKey: true });
   is(gBrowser.tabs.length, 3, "accel+w in a pinned tab didn't close it");
   is(gBrowser.selectedTab, unpinnedTab, "accel+w in a pinned tab selected the first unpinned tab");
 
   // Test the key state after removing the tab.
--- a/browser/base/content/test/tabs/browser_positional_attributes.js
+++ b/browser/base/content/test/tabs/browser_positional_attributes.js
@@ -1,16 +1,18 @@
 /* Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/
  */
 
 var tabs = [];
 
 function addTab(aURL) {
-  tabs.push(gBrowser.addTab(aURL, {skipAnimation: true}));
+  tabs.push(BrowserTestUtils.addTab(gBrowser, aURL, {
+    skipAnimation: true,
+  }));
 }
 
 function switchTab(index) {
   return BrowserTestUtils.switchTab(gBrowser, gBrowser.tabs[index]);
 }
 
 function testAttrib(tabIndex, attrib, expected) {
   is(gBrowser.tabs[tabIndex].hasAttribute(attrib), expected,
@@ -19,23 +21,23 @@ function testAttrib(tabIndex, attrib, ex
 
 add_task(async function setup() {
   is(gBrowser.tabs.length, 1, "one tab is open initially");
 
   addTab("http://mochi.test:8888/#0");
   addTab("http://mochi.test:8888/#1");
   addTab("http://mochi.test:8888/#2");
   addTab("http://mochi.test:8888/#3");
+
+  is(gBrowser.tabs.length, 5, "five tabs are open after setup");
 });
 
 // Add several new tabs in sequence, hiding some, to ensure that the
 // correct attributes get set
 add_task(async function test() {
-  await switchTab(0);
-
   testAttrib(0, "first-visible-tab", true);
   testAttrib(4, "last-visible-tab", true);
   testAttrib(0, "visuallyselected", true);
   testAttrib(0, "beforeselected-visible", false);
 
   await switchTab(2);
 
   testAttrib(2, "visuallyselected", true);
--- a/browser/base/content/test/trackingUI/browser_trackingUI_animation.js
+++ b/browser/base/content/test/trackingUI/browser_trackingUI_animation.js
@@ -9,17 +9,17 @@ const TP_PREF = "privacy.trackingprotect
 const ANIMATIONS_PREF = "toolkit.cosmeticAnimations.enabled";
 
 // Test that the shield icon animation can be controlled by the cosmetic
 // animations pref and that one of the icons is visible in each case.
 add_task(async function testShieldAnimation() {
   await UrlClassifierTestUtils.addTestTrackers();
   Services.prefs.setBoolPref(TP_PREF, true);
 
-  let tab = gBrowser.selectedTab = gBrowser.addTab();
+  let tab = gBrowser.selectedTab = BrowserTestUtils.addTab(gBrowser);
 
   let animationIcon = document.getElementById("tracking-protection-icon-animatable-image");
   let noAnimationIcon = document.getElementById("tracking-protection-icon");
 
   Services.prefs.setBoolPref(ANIMATIONS_PREF, true);
   await promiseTabLoadEvent(tab, TRACKING_PAGE);
   ok(BrowserTestUtils.is_hidden(noAnimationIcon), "the default icon is hidden when animations are enabled");
   ok(BrowserTestUtils.is_visible(animationIcon), "the animated icon is shown when animations are enabled");
--- a/browser/base/content/test/trackingUI/browser_trackingUI_state.js
+++ b/browser/base/content/test/trackingUI/browser_trackingUI_state.js
@@ -226,17 +226,17 @@ async function testTrackingProtectionDis
   await promiseTabLoadEvent(tab, TRACKING_PAGE);
   testTrackingPageUnblocked();
 }
 
 add_task(async function testNormalBrowsing() {
   await UrlClassifierTestUtils.addTestTrackers();
 
   tabbrowser = gBrowser;
-  let tab = tabbrowser.selectedTab = tabbrowser.addTab();
+  let tab = tabbrowser.selectedTab = BrowserTestUtils.addTab(tabbrowser);
 
   TrackingProtection = gBrowser.ownerGlobal.TrackingProtection;
   ok(TrackingProtection, "TP is attached to the browser window");
   is(TrackingProtection.enabled, Services.prefs.getBoolPref(PREF),
      "TP.enabled is based on the original pref value");
 
   Services.prefs.setBoolPref(PREF, true);
   ok(TrackingProtection.enabled, "TP is enabled after setting the pref");
@@ -247,17 +247,17 @@ add_task(async function testNormalBrowsi
   ok(!TrackingProtection.enabled, "TP is disabled after setting the pref");
 
   await testTrackingProtectionDisabled(tab);
 });
 
 add_task(async function testPrivateBrowsing() {
   let privateWin = await BrowserTestUtils.openNewBrowserWindow({private: true});
   tabbrowser = privateWin.gBrowser;
-  let tab = tabbrowser.selectedTab = tabbrowser.addTab();
+  let tab = tabbrowser.selectedTab = BrowserTestUtils.addTab(tabbrowser);
 
   TrackingProtection = tabbrowser.ownerGlobal.TrackingProtection;
   ok(TrackingProtection, "TP is attached to the private window");
   is(TrackingProtection.enabled, Services.prefs.getBoolPref(PB_PREF),
      "TP.enabled is based on the pb pref value");
 
   Services.prefs.setBoolPref(PB_PREF, true);
   ok(TrackingProtection.enabled, "TP is enabled after setting the pref");
--- a/browser/base/content/test/urlbar/browser_URLBarSetURI.js
+++ b/browser/base/content/test/urlbar/browser_URLBarSetURI.js
@@ -62,17 +62,17 @@ var tests = [
       next();
     });
   }
 ];
 
 function loadTabInWindow(win, callback) {
   info("Loading tab");
   let url = "http://user:pass@example.com/";
-  let tab = win.gBrowser.selectedTab = win.gBrowser.addTab(url);
+  let tab = win.gBrowser.selectedTab = BrowserTestUtils.addTab(win.gBrowser, url);
   BrowserTestUtils.browserLoaded(tab.linkedBrowser, false, url).then(() => {
     info("Tab loaded");
     is(win.gURLBar.textValue, "example.com", "URL bar had user/pass stripped initially");
     callback(tab);
   }, true);
 }
 
 function openToolbarCustomizationUI(aCallback, aBrowserWin) {
--- a/browser/base/content/test/urlbar/browser_urlbarSearchSingleWordNotification.js
+++ b/browser/base/content/test/urlbar/browser_urlbarSearchSingleWordNotification.js
@@ -157,17 +157,17 @@ function get_test_function_for_localhost
     // check pref value
     let prefValue = Services.prefs.getBoolPref(pref);
     is(prefValue, !isPrivate, "Pref should have the correct state.");
 
     await docLoadPromise;
     browser.removeTab(tab);
 
     // Now try again with the pref set.
-    tab = browser.selectedTab = browser.addTab("about:blank");
+    tab = browser.selectedTab = BrowserTestUtils.addTab(browser, "about:blank");
     await BrowserTestUtils.browserLoaded(tab.linkedBrowser);
     // In a private window, the notification should appear again.
     await runURLBarSearchTest({
       valueToOpen: hostName,
       expectSearch: isPrivate,
       expectNotification: isPrivate,
       aWindow: win,
     });
--- a/browser/base/content/utilityOverlay.js
+++ b/browser/base/content/utilityOverlay.js
@@ -207,16 +207,19 @@ function openTrustedLinkIn(url, where, a
 function openWebLinkIn(url, where, params) {
   if (!params) {
     params = {};
   }
 
   if (!params.triggeringPrincipal) {
     params.triggeringPrincipal = Services.scriptSecurityManager.createNullPrincipal({});
   }
+  if (Services.scriptSecurityManager.isSystemPrincipal(params.triggeringPrincipal)) {
+    throw new Error("System principal should never be passed into openWebLinkIn()");
+  }
 
   openUILinkIn(url, where, params);
 }
 
 /* openUILinkIn opens a URL in a place specified by the parameter |where|.
  *
  * |where| can be:
  *  "current"     current tab            (if there aren't any browser windows, then in a new window instead)
@@ -251,17 +254,18 @@ function openWebLinkIn(url, where, param
  *   userContextId        (unsigned int)
  *   targetBrowser        (XUL browser)
  */
 function openUILinkIn(url, where, aAllowThirdPartyFixup, aPostData, aReferrerURI) {
   var params;
 
   if (arguments.length == 3 && typeof arguments[2] == "object") {
     params = aAllowThirdPartyFixup;
-  } else {
+  }
+  if (!params || !params.triggeringPrincipal) {
     throw new Error("Required argument triggeringPrincipal missing within openUILinkIn");
   }
 
   params.fromChrome = true;
 
   openLinkIn(url, where, params);
 }
 
--- a/browser/components/extensions/parent/ext-browser.js
+++ b/browser/components/extensions/parent/ext-browser.js
@@ -49,17 +49,21 @@ const getSender = (extension, target, se
 
 // Used by Extension.jsm
 global.tabGetSender = getSender;
 
 /* eslint-disable mozilla/balanced-listeners */
 extensions.on("uninstalling", (msg, extension) => {
   if (extension.uninstallURL) {
     let browser = windowTracker.topWindow.gBrowser;
-    browser.addTab(extension.uninstallURL, {relatedToCurrent: true});
+    browser.addTab(extension.uninstallURL, {
+      disallowInheritPrincipal: true,
+      relatedToCurrent: true,
+      triggeringPrincipal: Services.scriptSecurityManager.createNullPrincipal({}),
+    });
   }
 });
 
 extensions.on("page-shutdown", (type, context) => {
   if (context.viewType == "tab") {
     if (context.extension.id !== context.xulBrowser.contentPrincipal.addonId) {
       // Only close extension tabs.
       // This check prevents about:addons from closing when it contains a
--- a/browser/components/extensions/parent/ext-tabs.js
+++ b/browser/components/extensions/parent/ext-tabs.js
@@ -522,28 +522,18 @@ this.tabs = class extends ExtensionAPI {
                 resolve(window);
               };
               Services.obs.addObserver(obs, "browser-delayed-startup-finished");
             } else {
               resolve(window);
             }
           }).then(window => {
             let url;
-
-            if (createProperties.url !== null) {
-              url = context.uri.resolve(createProperties.url);
+            let principal = context.principal;
 
-              if (!context.checkLoadURL(url, {dontReportErrors: true})) {
-                return Promise.reject({message: `Illegal URL: ${url}`});
-              }
-
-              if (createProperties.openInReaderMode) {
-                url = `about:reader?url=${encodeURIComponent(url)}`;
-              }
-            }
 
             if (createProperties.cookieStoreId && !extension.hasPermission("cookies")) {
               return Promise.reject({message: `No permission for cookieStoreId: ${createProperties.cookieStoreId}`});
             }
 
             let options = {};
             if (createProperties.cookieStoreId) {
               if (!global.isValidCookieStoreId(createProperties.cookieStoreId)) {
@@ -564,27 +554,43 @@ this.tabs = class extends ExtensionAPI {
                 if (!containerId) {
                   return Promise.reject({message: `No cookie store exists with ID ${createProperties.cookieStoreId}`});
                 }
 
                 options.userContextId = containerId;
               }
             }
 
+            if (createProperties.url !== null) {
+              url = context.uri.resolve(createProperties.url);
+
+              if (!context.checkLoadURL(url, {dontReportErrors: true})) {
+                return Promise.reject({message: `Illegal URL: ${url}`});
+              }
+
+              if (createProperties.openInReaderMode) {
+                url = `about:reader?url=${encodeURIComponent(url)}`;
+              }
+            } else {
+              url = window.BROWSER_NEW_TAB_URL;
+            }
             // Only set disallowInheritPrincipal on non-discardable urls as it
             // will override creating a lazy browser.  Setting triggeringPrincipal
             // will ensure other cases are handled, but setting it may prevent
             // creating about and data urls.
             let discardable = url && !url.startsWith("about:");
             if (!discardable) {
               // Make sure things like about:blank and data: URIs never inherit,
               // and instead always get a NullPrincipal.
               options.disallowInheritPrincipal = true;
-            } else {
-              options.triggeringPrincipal = context.principal;
+              // Falling back to codebase here as about: requires it, however is safe.
+              principal = Services.scriptSecurityManager.createCodebasePrincipal(Services.io.newURI(url), {
+                userContextId: options.userContextId,
+                privateBrowsingId: PrivateBrowsingUtils.isBrowserPrivate(window.gBrowser) ? 1 : 0,
+              });
             }
 
             tabListener.initTabReady();
             let currentTab = window.gBrowser.selectedTab;
 
             if (createProperties.openerTabId !== null) {
               options.ownerTab = tabTracker.getTab(createProperties.openerTabId);
               options.openerBrowser = options.ownerTab.linkedBrowser;
@@ -613,23 +619,24 @@ this.tabs = class extends ExtensionAPI {
               if (!discardable) {
                 return Promise.reject({message: `Cannot create a discarded new tab or "about" urls.`});
               }
               options.createLazyBrowser = true;
             } else if (createProperties.title) {
               return Promise.reject({message: `Title may only be set for discarded tabs.`});
             }
 
-            let nativeTab = window.gBrowser.addTab(url || window.BROWSER_NEW_TAB_URL, options);
+            options.triggeringPrincipal = principal;
+            let nativeTab = window.gBrowser.addTab(url, options);
             if (createProperties.discarded) {
               SessionStore.setTabState(nativeTab, {
                 entries: [{
                   url: url,
                   title: options.title,
-                  triggeringPrincipal_base64: Utils.serializePrincipal(context.principal),
+                  triggeringPrincipal_base64: Utils.serializePrincipal(principal),
                 }],
               });
             }
 
             if (active) {
               window.gBrowser.selectedTab = nativeTab;
               if (!url) {
                 window.focusAndSelectUrlBar();
--- a/browser/components/extensions/test/browser/browser-common.ini
+++ b/browser/components/extensions/test/browser/browser-common.ini
@@ -162,16 +162,17 @@ skip-if = !e10s || !crashreporter # the 
 [browser_ext_slow_script.js]
 skip-if = !e10s || debug || asan
 [browser_ext_tab_runtimeConnect.js]
 [browser_ext_tabs_audio.js]
 [browser_ext_tabs_captureTab.js]
 [browser_ext_tabs_captureVisibleTab.js]
 [browser_ext_tabs_create.js]
 skip-if = os == "linux" && debug && bits == 32 # Bug 1350189
+[browser_ext_tabs_create_url.js]
 [browser_ext_tabs_create_invalid_url.js]
 [browser_ext_tabs_detectLanguage.js]
 [browser_ext_tabs_discard.js]
 skip-if = !e10s
 [browser_ext_tabs_discarded.js]
 [browser_ext_tabs_duplicate.js]
 [browser_ext_tabs_events.js]
 [browser_ext_tabs_executeScript.js]
--- a/browser/components/extensions/test/browser/browser_ext_tabs_create.js
+++ b/browser/components/extensions/test/browser/browser_ext_tabs_create.js
@@ -170,67 +170,16 @@ add_task(async function test_create_opti
 
   await extension.startup();
   await extension.awaitFinish("tabs.create");
   await extension.unload();
 
   BrowserTestUtils.removeTab(tab);
 });
 
-add_task(async function test_urlbar_focus() {
-  const extension = ExtensionTestUtils.loadExtension({
-    background() {
-      browser.tabs.onUpdated.addListener(function onUpdated(_, info) {
-        if (info.status === "complete") {
-          browser.test.sendMessage("complete");
-          browser.tabs.onUpdated.removeListener(onUpdated);
-        }
-      });
-      browser.test.onMessage.addListener(async (cmd, ...args) => {
-        const result = await browser.tabs[cmd](...args);
-        browser.test.sendMessage("result", result);
-      });
-    },
-  });
-
-  await extension.startup();
-
-  // Test content is focused after opening a regular url
-  extension.sendMessage("create", {url: "https://example.com"});
-  const [tab1] = await Promise.all([
-    extension.awaitMessage("result"),
-    extension.awaitMessage("complete"),
-  ]);
-
-  is(document.activeElement.tagName, "browser", "Content focused after opening a web page");
-
-  extension.sendMessage("remove", tab1.id);
-  await extension.awaitMessage("result");
-
-  // Test urlbar is focused after opening an empty tab
-  extension.sendMessage("create", {});
-  const tab2 = await extension.awaitMessage("result");
-
-  const active = document.activeElement;
-  info(`Active element: ${active.tagName}, id: ${active.id}, class: ${active.className}`);
-
-  const parent = active.parentNode;
-  info(`Parent element: ${parent.tagName}, id: ${parent.id}, class: ${parent.className}`);
-
-  info(`After opening an empty tab, gURLBar.focused: ${gURLBar.focused}`);
-
-  is(active.tagName, "html:input", "Input element focused");
-  ok(active.classList.contains("urlbar-input"), "Urlbar focused");
-
-  extension.sendMessage("remove", tab2.id);
-  await extension.awaitMessage("result");
-
-  await extension.unload();
-});
-
 add_task(async function test_create_with_popup() {
   const extension = ExtensionTestUtils.loadExtension({
     async background() {
       let normalWin = await browser.windows.create();
       let lastFocusedNormalWin = await browser.windows.getLastFocused({});
       browser.test.assertEq(lastFocusedNormalWin.id, normalWin.id, "The normal window is the last focused window.");
       let popupWin = await browser.windows.create({type: "popup"});
       let lastFocusedPopupWin = await browser.windows.getLastFocused({});
new file mode 100644
--- /dev/null
+++ b/browser/components/extensions/test/browser/browser_ext_tabs_create_url.js
@@ -0,0 +1,55 @@
+/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */
+/* vim: set sts=2 sw=2 et tw=80: */
+"use strict";
+
+add_task(async function test_urlbar_focus() {
+  const extension = ExtensionTestUtils.loadExtension({
+    background() {
+      browser.tabs.onUpdated.addListener(function onUpdated(_, info) {
+        if (info.status === "complete") {
+          browser.test.sendMessage("complete");
+          browser.tabs.onUpdated.removeListener(onUpdated);
+        }
+      });
+      browser.test.onMessage.addListener(async (cmd, ...args) => {
+        const result = await browser.tabs[cmd](...args);
+        browser.test.sendMessage("result", result);
+      });
+    },
+  });
+
+  await extension.startup();
+
+  // Test content is focused after opening a regular url
+  extension.sendMessage("create", {url: "https://example.com"});
+  const [tab1] = await Promise.all([
+    extension.awaitMessage("result"),
+    extension.awaitMessage("complete"),
+  ]);
+
+  is(document.activeElement.tagName, "browser", "Content focused after opening a web page");
+
+  extension.sendMessage("remove", tab1.id);
+  await extension.awaitMessage("result");
+
+  // Test urlbar is focused after opening an empty tab
+  extension.sendMessage("create", {});
+  const tab2 = await extension.awaitMessage("result");
+
+  const active = document.activeElement;
+  info(`Active element: ${active.tagName}, id: ${active.id}, class: ${active.className}`);
+
+  const parent = active.parentNode;
+  info(`Parent element: ${parent.tagName}, id: ${parent.id}, class: ${parent.className}`);
+
+  info(`After opening an empty tab, gURLBar.focused: ${gURLBar.focused}`);
+
+
+  is(active.tagName, "html:input", "Input element focused");
+  ok(active.classList.contains("urlbar-input"), "Urlbar focused");
+
+  extension.sendMessage("remove", tab2.id);
+  await extension.awaitMessage("result");
+
+  await extension.unload();
+});
--- a/browser/components/migration/tests/marionette/test_refresh_firefox.py
+++ b/browser/components/migration/tests/marionette/test_refresh_firefox.py
@@ -166,17 +166,19 @@ class TestFirefoxRefresh(MarionetteTestC
                     resolve();
                   }
                 });
               }
             }
           });
           let expectedTabs = new Set();
           for (let url of expectedURLs) {
-            expectedTabs.add(gBrowser.addTab(url));
+            expectedTabs.add(gBrowser.addTab(url, {
+              triggeringPrincipal: Services.scriptSecurityManager.getSystemPrincipal(),
+            }));
           }
           // Close any other tabs that might be open:
           let allTabs = Array.from(gBrowser.tabs);
           for (let tab of allTabs) {
             if (!expectedTabs.has(tab)) {
               gBrowser.removeTab(tab);
             }
           }
--- a/browser/components/nsBrowserGlue.js
+++ b/browser/components/nsBrowserGlue.js
@@ -2350,17 +2350,17 @@ BrowserGlue.prototype = {
 
       const openTab = async (URI) => {
         let tab;
         if (!win) {
           win = await this._openURLInNewWindow(URI.uri);
           let tabs = win.gBrowser.tabs;
           tab = tabs[tabs.length - 1];
         } else {
-          tab = win.gBrowser.addTab(URI.uri);
+          tab = win.gBrowser.addWebTab(URI.uri);
         }
         tab.setAttribute("attention", true);
         return tab;
       };
 
       const firstTab = await openTab(URIs[0]);
       await Promise.all(URIs.slice(1).map(URI => openTab(URI)));
 
@@ -2430,17 +2430,17 @@ BrowserGlue.prototype = {
       imageURL = "chrome://branding/content/icon64.png";
     }
     let win = BrowserWindowTracker.getTopWindow({private: false});
     if (!win) {
       win = await this._openURLInNewWindow(url);
       let tabs = win.gBrowser.tabs;
       tab = tabs[tabs.length - 1];
     } else {
-      tab = win.gBrowser.addTab(url);
+      tab = win.gBrowser.addWebTab(url);
     }
     tab.setAttribute("attention", true);
     let clickCallback = (subject, topic, data) => {
       if (topic != "alertclickcallback")
         return;
       win.gBrowser.selectedTab = tab;
     };
 
@@ -2463,17 +2463,17 @@ BrowserGlue.prototype = {
     let clickCallback = async (subject, topic, data) => {
       if (topic != "alertclickcallback")
         return;
       let url = await FxAccounts.config.promiseManageDevicesURI("device-connected-notification");
       let win = BrowserWindowTracker.getTopWindow({private: false});
       if (!win) {
         this._openURLInNewWindow(url);
       } else {
-        win.gBrowser.addTab(url);
+        win.gBrowser.addWebTab(url);
       }
     };
 
     try {
       this.AlertsService.showAlertNotification(null, title, body, true, null, clickCallback);
     } catch (ex) {
       Cu.reportError("Error notifying of a new Sync device: " + ex);
     }
--- a/browser/components/preferences/in-content/main.js
+++ b/browser/components/preferences/in-content/main.js
@@ -726,17 +726,17 @@ var gMainPane = {
     }
     const user = await fxAccounts.getSignedInUser();
     if (user) {
       // We have a user, open Sync preferences in the same tab
       win.openTrustedLinkIn("about:preferences#sync", "current");
       return;
     }
     let url = await FxAccounts.config.promiseSignInURI("dev-edition-setup");
-    let accountsTab = win.gBrowser.addTab(url);
+    let accountsTab = win.gBrowser.addWebTab(url);
     win.gBrowser.selectedTab = accountsTab;
   },
 
   // HOME PAGE
   /*
    * Preferences:
    *
    * browser.startup.page
--- a/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_aboutSessionRestore.js
+++ b/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_aboutSessionRestore.js
@@ -4,17 +4,17 @@
 
 // This test checks that the session restore button from about:sessionrestore
 // is disabled in private mode
 add_task(async function testNoSessionRestoreButton() {
   // Opening, then closing, a private window shouldn't create session data.
   (await BrowserTestUtils.openNewBrowserWindow({private: true})).close();
 
   let win = await BrowserTestUtils.openNewBrowserWindow({private: true});
-  let tab = win.gBrowser.addTab("about:sessionrestore");
+  let tab = BrowserTestUtils.addTab(win.gBrowser, "about:sessionrestore");
   let browser = tab.linkedBrowser;
 
   await BrowserTestUtils.browserLoaded(browser);
 
   await ContentTask.spawn(browser, null, async function() {
     Assert.ok(content.document.getElementById("errorTryAgain").disabled,
       "The Restore about:sessionrestore button should be disabled");
   });
--- a/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_cache.js
+++ b/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_cache.js
@@ -56,17 +56,17 @@ function getStorageEntryCount(device, go
 
 function get_cache_for_private_window() {
   let win = whenNewWindowLoaded({private: true}, function() {
 
     executeSoon(function() {
 
       ok(true, "The private window got loaded");
 
-      let tab = win.gBrowser.addTab("http://example.org");
+      let tab = BrowserTestUtils.addTab(win.gBrowser, "http://example.org");
       win.gBrowser.selectedTab = tab;
       let newTabBrowser = win.gBrowser.getBrowserForTab(tab);
 
       BrowserTestUtils.browserLoaded(newTabBrowser).then(function() {
         executeSoon(function() {
 
           getStorageEntryCount("private", function(nrEntriesP) {
             ok(nrEntriesP >= 1, "Memory cache reports some entries from example.org domain");
--- a/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_favicon.js
+++ b/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_favicon.js
@@ -154,17 +154,17 @@ async function assignCookies(aBrowser, a
   await ContentTask.spawn(tabInfo.browser, aCookieValue, async function(value) {
     content.document.cookie = value;
   });
 
   BrowserTestUtils.removeTab(tabInfo.tab);
 }
 
 async function openTab(aBrowser, aURL) {
-  let tab = aBrowser.addTab(aURL);
+  let tab = BrowserTestUtils.addTab(aBrowser, aURL);
 
   // Select tab and make sure its browser is focused.
   aBrowser.selectedTab = tab;
   tab.ownerGlobal.focus();
 
   let browser = aBrowser.getBrowserForTab(tab);
   await BrowserTestUtils.browserLoaded(browser);
   return {tab, browser};
--- a/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_geoprompt.js
+++ b/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_geoprompt.js
@@ -6,17 +6,17 @@
 // control inside the private browsing mode.
 
 add_task(async function test() {
   const testPageURL = "https://example.com/browser/" +
     "browser/components/privatebrowsing/test/browser/browser_privatebrowsing_geoprompt_page.html";
 
   function checkGeolocation(aPrivateMode, aWindow) {
     return (async function() {
-      aWindow.gBrowser.selectedTab = aWindow.gBrowser.addTab(testPageURL);
+      aWindow.gBrowser.selectedTab = BrowserTestUtils.addTab(aWindow.gBrowser, testPageURL);
       await BrowserTestUtils.browserLoaded(aWindow.gBrowser.selectedBrowser);
 
       let notification = aWindow.PopupNotifications.getNotification("geolocation");
 
       // Wait until the notification is available.
       while (!notification) {
         await new Promise(resolve => { executeSoon(resolve); });
         notification = aWindow.PopupNotifications.getNotification("geolocation");
--- a/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_localStorage.js
+++ b/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_localStorage.js
@@ -4,17 +4,17 @@
 
  add_task(async function test() {
   requestLongerTimeout(2);
   const page1 = "http://mochi.test:8888/browser/browser/components/privatebrowsing/test/browser/" +
                 "browser_privatebrowsing_localStorage_page1.html";
 
   let win = await BrowserTestUtils.openNewBrowserWindow({private: true});
 
-  win.gBrowser.selectedTab = win.gBrowser.addTab(page1);
+  win.gBrowser.selectedTab = BrowserTestUtils.addTab(win.gBrowser, page1);
   let browser = win.gBrowser.selectedBrowser;
   await BrowserTestUtils.browserLoaded(browser);
 
   browser.loadURI(
     "http://mochi.test:8888/browser/browser/components/privatebrowsing/test/browser/" +
     "browser_privatebrowsing_localStorage_page2.html");
   await BrowserTestUtils.browserLoaded(browser);
 
--- a/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_localStorage_before_after.js
+++ b/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_localStorage_before_after.js
@@ -10,25 +10,25 @@
 // Step 2: Load the same page in a non-private tab, ensuring that the storage instance reports only one item
 //   existing.
 
 add_task(async function test() {
   let prefix = "http://mochi.test:8888/browser/browser/components/privatebrowsing/test/browser/";
 
   // Step 1.
   let privateWin = await BrowserTestUtils.openNewBrowserWindow({private: true});
-  let privateBrowser = privateWin.gBrowser.addTab(
+  let privateBrowser = BrowserTestUtils.addTab(privateWin.gBrowser,
     prefix + "browser_privatebrowsing_localStorage_before_after_page.html").linkedBrowser;
   await BrowserTestUtils.browserLoaded(privateBrowser);
 
   is(privateBrowser.contentTitle, "1", "localStorage should contain 1 item");
 
   // Step 2.
   let win = await BrowserTestUtils.openNewBrowserWindow();
-  let browser = win.gBrowser.addTab(
+  let browser = BrowserTestUtils.addTab(win.gBrowser,
     prefix + "browser_privatebrowsing_localStorage_before_after_page2.html").linkedBrowser;
   await BrowserTestUtils.browserLoaded(browser);
 
   is(browser.contentTitle, "null|0", "localStorage should contain 0 items");
 
   // Cleanup
   await BrowserTestUtils.closeWindow(privateWin);
   await BrowserTestUtils.closeWindow(win);
--- a/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_noSessionRestoreMenuOption.js
+++ b/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_noSessionRestoreMenuOption.js
@@ -3,17 +3,17 @@
 /**
  * Tests that if we open a tab within a private browsing window, and then
  * close that private browsing window, that subsequent private browsing
  * windows do not allow the command for restoring the last session.
  */
 add_task(async function test_no_session_restore_menu_option() {
   let win = await BrowserTestUtils.openNewBrowserWindow({ private: true });
   ok(true, "The first private window got loaded");
-  win.gBrowser.addTab("about:mozilla");
+  BrowserTestUtils.addTab(win.gBrowser, "about:mozilla");
   await BrowserTestUtils.closeWindow(win);
 
   win = await BrowserTestUtils.openNewBrowserWindow({ private: true });
   let srCommand = win.document.getElementById("Browser:RestoreLastSession");
   ok(srCommand, "The Session Restore command should exist");
   is(PrivateBrowsingUtils.isWindowPrivate(win), true,
      "PrivateBrowsingUtils should report the correct per-window private browsing status");
   is(srCommand.hasAttribute("disabled"), true,
--- a/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_protocolhandler.js
+++ b/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_protocolhandler.js
@@ -7,17 +7,17 @@
 // inside the private browsing mode.
 
 add_task(async function test() {
   let notificationValue = "Protocol Registration: web+testprotocol";
   let testURI = "https://example.com/browser/" +
     "browser/components/privatebrowsing/test/browser/browser_privatebrowsing_protocolhandler_page.html";
 
   let doTest = async function(aIsPrivateMode, aWindow) {
-    let tab = aWindow.gBrowser.selectedTab = aWindow.gBrowser.addTab(testURI);
+    let tab = aWindow.gBrowser.selectedTab = BrowserTestUtils.addTab(aWindow.gBrowser, testURI);
     await BrowserTestUtils.browserLoaded(tab.linkedBrowser);
 
     let promiseFinished = PromiseUtils.defer();
     setTimeout(function() {
       let notificationBox = aWindow.gBrowser.getNotificationBox();
       let notification = notificationBox.getNotificationWithValue(notificationValue);
 
       if (aIsPrivateMode) {
--- a/browser/components/safebrowsing/content/test/browser_whitelisted.js
+++ b/browser/components/safebrowsing/content/test/browser_whitelisted.js
@@ -22,17 +22,17 @@ function testWhitelistedPage(window) {
   var getmeout_button = window.document.getElementById("getMeOutButton");
   var ignorewarning_button = window.document.getElementById("ignoreWarningButton");
   ok(!getmeout_button, "GetMeOut button not present");
   ok(!ignorewarning_button, "IgnoreWarning button not present");
 }
 
 add_task(async function testNormalBrowsing() {
   tabbrowser = gBrowser;
-  let tab = tabbrowser.selectedTab = tabbrowser.addTab();
+  let tab = tabbrowser.selectedTab = BrowserTestUtils.addTab(tabbrowser);
 
   info("Load a test page that's whitelisted");
   Services.prefs.setCharPref(PREF_WHITELISTED_HOSTNAMES, "example.com,www.ItIsaTrap.org,example.net");
   await promiseTabLoadEvent(tab, TEST_PAGE, "load");
   testWhitelistedPage(tab.ownerGlobal);
 
   info("Load a test page that's no longer whitelisted");
   Services.prefs.setCharPref(PREF_WHITELISTED_HOSTNAMES, "");
--- a/browser/components/search/test/browser_contextSearchTabPosition.js
+++ b/browser/components/search/test/browser_contextSearchTabPosition.js
@@ -28,18 +28,18 @@ add_task(async function test() {
       tabsLoadedDeferred.resolve();
     }
   }
 
   let container = gBrowser.tabContainer;
   container.addEventListener("TabOpen", tabAdded);
 
   BrowserTestUtils.addTab(gBrowser, "about:blank");
-  BrowserSearch.loadSearchFromContext("mozilla");
-  BrowserSearch.loadSearchFromContext("firefox");
+  BrowserSearch.loadSearchFromContext("mozilla", Services.scriptSecurityManager.getSystemPrincipal());
+  BrowserSearch.loadSearchFromContext("firefox", Services.scriptSecurityManager.getSystemPrincipal());
 
   // Wait for all the tabs to open.
   await tabsLoadedDeferred.promise;
 
   is(tabs[0], gBrowser.tabs[3], "blank tab has been pushed to the end");
   is(tabs[1], gBrowser.tabs[1], "first search tab opens next to the current tab");
   is(tabs[2], gBrowser.tabs[2], "second search tab opens next to the first search tab");
 
--- a/browser/components/search/test/browser_google_behavior.js
+++ b/browser/components/search/test/browser_google_behavior.js
@@ -88,17 +88,17 @@ async function testSearchEngine(engineDe
 
   let engineTests = [
     {
       name: "context menu search",
       searchURL: base + engineDetails.codes.context,
       run() {
         // Simulate a contextmenu search
         // FIXME: This is a bit "low-level"...
-        BrowserSearch.loadSearch("foo", false, "contextmenu");
+        BrowserSearch._loadSearch("foo", false, "contextmenu", Services.scriptSecurityManager.getSystemPrincipal());
       }
     },
     {
       name: "keyword search",
       searchURL: base + engineDetails.codes.keyword,
       run() {
         gURLBar.value = "? foo";
         gURLBar.focus();
--- a/browser/components/search/test/browser_searchEngine_behaviors.js
+++ b/browser/components/search/test/browser_searchEngine_behaviors.js
@@ -106,17 +106,17 @@ async function testSearchEngine(engineDe
 
   let engineTests = [
     {
       name: "context menu search",
       searchURL: base + engineDetails.codes.context,
       run() {
         // Simulate a contextmenu search
         // FIXME: This is a bit "low-level"...
-        BrowserSearch.loadSearch("foo", false, "contextmenu");
+        BrowserSearch._loadSearch("foo", false, "contextmenu", Services.scriptSecurityManager.getSystemPrincipal());
       }
     },
     {
       name: "keyword search",
       searchURL: base + engineDetails.codes.keyword,
       run() {
         gURLBar.value = "? foo";
         gURLBar.focus();
--- a/browser/components/sessionstore/SessionStore.jsm
+++ b/browser/components/sessionstore/SessionStore.jsm
@@ -2426,19 +2426,22 @@ var SessionStoreInternal = {
       throw Components.Exception("Default view is not tracked", Cr.NS_ERROR_INVALID_ARG);
     }
     if (!aWindow.gBrowser) {
       throw Components.Exception("Invalid window object: no gBrowser", Cr.NS_ERROR_INVALID_ARG);
     }
 
     // Create a new tab.
     let userContextId = aTab.getAttribute("usercontextid");
-    let newTab = aTab == aWindow.gBrowser.selectedTab ?
-      aWindow.gBrowser.addTab(null, {relatedToCurrent: true, ownerTab: aTab, userContextId}) :
-      aWindow.gBrowser.addTab(null, {userContextId});
+
+    let tabOptions = {
+      userContextId,
+      ...(aTab == aWindow.gBrowser.selectedTab ? {relatedToCurrent: true, ownerTab: aTab} : {})
+    };
+    let newTab = aWindow.gBrowser.addTrustedTab(null, tabOptions);
 
     // Start the throbber to pretend we're doing something while actually
     // waiting for data from the frame script.
     newTab.setAttribute("busy", "true");
 
     // Collect state before flushing.
     let tabState = TabState.collect(aTab, TAB_CUSTOM_VALUES.get(aTab));
 
@@ -2517,17 +2520,17 @@ var SessionStoreInternal = {
     }
 
     // fetch the data of closed tab, while removing it from the array
     let {state, pos} = this.removeClosedTabData(closedTabs, aIndex);
 
     // create a new tab
     let tabbrowser = aWindow.gBrowser;
     let tab = tabbrowser.selectedTab =
-      tabbrowser.addTab(null, {
+      tabbrowser.addTrustedTab(null, {
         index: pos,
         pinned: state.pinned,
         userContextId: state.userContextId,
       });
 
     // restore tab content
     this.restoreTab(tab, state);
 
@@ -3487,23 +3490,23 @@ var SessionStoreInternal = {
           activeIndex = Math.min(activeIndex, tabData.entries.length - 1);
           activeIndex = Math.max(activeIndex, 0);
           url = tabData.entries[activeIndex].url;
         }
 
         // Setting noInitialLabel is a perf optimization. Rendering tab labels
         // would make resizing the tabs more expensive as we're adding them.
         // Each tab will get its initial label set in restoreTab.
-        tab = tabbrowser.addTab(url,
-                                { createLazyBrowser,
-                                  skipAnimation: true,
-                                  noInitialLabel: true,
-                                  userContextId,
-                                  skipBackgroundNotify: true,
-                                  bulkOrderedOpen: true });
+        tab = tabbrowser.addTrustedTab(url,
+                                       { createLazyBrowser,
+                                         skipAnimation: true,
+                                         noInitialLabel: true,
+                                         userContextId,
+                                         skipBackgroundNotify: true,
+                                         bulkOrderedOpen: true });
 
         if (select) {
           let leftoverTab = tabbrowser.selectedTab;
           tabbrowser.selectedTab = tab;
           tabbrowser.removeTab(leftoverTab);
         }
       }
 
--- a/browser/components/sessionstore/content/aboutSessionRestore.js
+++ b/browser/components/sessionstore/content/aboutSessionRestore.js
@@ -259,17 +259,17 @@ function toggleRowChecked(aIx) {
   // we only disable the button when there's no cancel button.
   if (document.getElementById("errorCancel")) {
     document.getElementById("errorTryAgain").disabled = !gTreeData.some(isChecked);
   }
 }
 
 function restoreSingleTab(aIx, aShifted) {
   var tabbrowser = getBrowserWindow().gBrowser;
-  var newTab = tabbrowser.addTab();
+  var newTab = tabbrowser.addWebTab();
   var item = gTreeData[aIx];
 
   var tabState = gStateObject.windows[item.parent.ix]
                              .tabs[aIx - gTreeData.indexOf(item.parent) - 1];
   // ensure tab would be visible on the tabstrip.
   tabState.hidden = false;
   SessionStore.setTabState(newTab, JSON.stringify(tabState));
 
--- a/browser/components/sessionstore/test/browser_248970_b_perwindowpb.js
+++ b/browser/components/sessionstore/test/browser_248970_b_perwindowpb.js
@@ -92,17 +92,17 @@ function test() {
     ok(0 <= count && count <= max_tabs_undo,
       "getClosedTabCount should return zero or at most max_tabs_undo");
 
     // setup a state for tab (A) so we can check later that is restored
     let value = "Value " + Math.random();
     let state = { entries: [{ url: testURL }], extData: { key: value } };
 
     // public session, add new tab: (A)
-    let tab_A = aWin.gBrowser.addTab(testURL);
+    let tab_A = BrowserTestUtils.addTab(aWin.gBrowser, testURL);
     ss.setTabState(tab_A, JSON.stringify(state));
     promiseBrowserLoaded(tab_A.linkedBrowser).then(() => {
       // make sure that the next closed tab will increase getClosedTabCount
       Services.prefs.setIntPref(
         "browser.sessionstore.max_tabs_undo", max_tabs_undo + 1);
 
       // populate tab_A with form data
       for (let i in fieldList)
@@ -129,17 +129,17 @@ function test() {
           // setup a state for tab (B) so we can check that its duplicated
           // properly
           let key1 = "key1";
           let value1 = "Value " + Math.random();
           let state1 = {
             entries: [{ url: testURL2 }], extData: { key1: value1 }
           };
 
-          let tab_B = win.gBrowser.addTab(testURL2);
+          let tab_B = BrowserTestUtils.addTab(win.gBrowser, testURL2);
           promiseTabState(tab_B, state1).then(() => {
             // populate tab: (B) with different form data
             for (let item in fieldList)
               setFormValue(tab_B, item, fieldList[item]);
 
             // duplicate tab: (B)
             let tab_C = win.gBrowser.duplicateTab(tab_B);
             promiseTabRestored(tab_C).then(() => {
--- a/browser/components/sessionstore/test/browser_354894_perwindowpb.js
+++ b/browser/components/sessionstore/test/browser_354894_perwindowpb.js
@@ -158,17 +158,17 @@ let setupTest = async function(options, 
 
 /**
  * Loads a TEST_URLS into a browser window.
  *
  * @param win (Window)
  *        The browser window to load the tabs in
  */
 function injectTestTabs(win) {
-  let promises = TEST_URLS.map(url => win.gBrowser.addTab(url))
+  let promises = TEST_URLS.map(url => BrowserTestUtils.addTab(win.gBrowser, url))
                           .map(tab => BrowserTestUtils.browserLoaded(tab.linkedBrowser));
   return Promise.all(promises);
 }
 
 /**
  * Attempts to close a window via BrowserTryToCloseWindow so that
  * we get the browser-lastwindow-close-requested and
  * browser-lastwindow-close-granted observer notifications.
@@ -308,17 +308,17 @@ add_task(async function test_open_close_
     let popupPromise = BrowserTestUtils.waitForNewWindow();
     openDialog(location, "popup", POPUP_FEATURES, TEST_URLS[0]);
     let popup = await popupPromise;
 
     let popup2Promise = BrowserTestUtils.waitForNewWindow();
     openDialog(location, "popup2", POPUP_FEATURES, TEST_URLS[1]);
     let popup2 = await popup2Promise;
 
-    popup2.gBrowser.addTab(TEST_URLS[0]);
+    BrowserTestUtils.addTab(popup2.gBrowser, TEST_URLS[0]);
 
     let closed = await closeWindowForRestoration(newWin);
     ok(closed, "Should be able to close the window");
 
     await BrowserTestUtils.closeWindow(popup2);
 
     newWin = await promiseNewWindowLoaded();
 
@@ -373,17 +373,17 @@ add_task(async function test_open_close_
 
     let closed = await closeWindowForRestoration(popup);
     ok(closed, "Should be able to close the window");
 
     popupPromise = BrowserTestUtils.waitForNewWindow();
     openDialog(location, "popup", POPUP_FEATURES, TEST_URLS[1]);
     popup = await popupPromise;
 
-    popup.gBrowser.addTab(TEST_URLS[0]);
+    BrowserTestUtils.addTab(popup.gBrowser, TEST_URLS[0]);
     is(popup.gBrowser.browsers.length, 2,
        "Did not restore to the popup window (2)");
 
     await BrowserTestUtils.closeWindow(popup);
 
     newWin = await promiseNewWindowLoaded();
     isnot(newWin.gBrowser.browsers.length, 2,
           "Did not restore the popup window");
--- a/browser/components/sessionstore/test/browser_394759_basic.js
+++ b/browser/components/sessionstore/test/browser_394759_basic.js
@@ -20,17 +20,17 @@ function test() {
   let uniqueKey = "bug 394759";
   let uniqueValue = "unik" + Date.now();
   let uniqueText = "pi != " + Math.random();
 
   // Clear the list of closed windows.
   forgetClosedWindows();
 
   provideWindow(function onTestURLLoaded(newWin) {
-    newWin.gBrowser.addTab().linkedBrowser.stop();
+    BrowserTestUtils.addTab(newWin.gBrowser).linkedBrowser.stop();
 
     // Mark the window with some unique data to be restored later on.
     ss.setWindowValue(newWin, uniqueKey, uniqueValue);
     let [txt] = newWin.content.document.querySelectorAll("#txt");
     txt.value = uniqueText;
 
     let browser = newWin.gBrowser.selectedBrowser;
     setInputChecked(browser, {id: "chk", checked: true}).then(() => {
--- a/browser/components/sessionstore/test/browser_589246.js
+++ b/browser/components/sessionstore/test/browser_589246.js
@@ -167,18 +167,18 @@ function onStateRestored(aSubject, aTopi
 
       newWin.addEventListener("unload", function() {
         onWindowUnloaded();
       }, {once: true});
       // Open a new tab as well. On Windows/Linux this will be restored when the
       // new window is opened below (in onWindowUnloaded). On OS X we'll just
       // restore the pinned tabs, leaving the unpinned tab in the closedWindowsData.
       if (shouldOpenTabs) {
-        let newTab = newWin.gBrowser.addTab("about:config");
-        let newTab2 = newWin.gBrowser.addTab("about:buildconfig");
+        let newTab = BrowserTestUtils.addTab(newWin.gBrowser, "about:config");
+        let newTab2 = BrowserTestUtils.addTab(newWin.gBrowser, "about:buildconfig");
 
         newTab.linkedBrowser.addEventListener("load", function() {
           if (shouldCloseTab == "one") {
             newWin.gBrowser.removeTab(newTab2);
           } else if (shouldCloseTab == "both") {
             newWin.gBrowser.removeTab(newTab);
             newWin.gBrowser.removeTab(newTab2);
           }
--- a/browser/components/sessionstore/test/browser_597071.js
+++ b/browser/components/sessionstore/test/browser_597071.js
@@ -15,17 +15,17 @@ add_task(async function test_close_last_
     {tabs: [{entries: []}], isPopup: true, hidden: "toolbar"}
   ]};
 
   // Set this window to be a popup.
   ss.setWindowState(window, JSON.stringify(popupState), true);
 
   // Open a new window with a tab.
   let win = await BrowserTestUtils.openNewBrowserWindow({private: false});
-  let tab = win.gBrowser.addTab("http://example.com/");
+  let tab = BrowserTestUtils.addTab(win.gBrowser, "http://example.com/");
   await BrowserTestUtils.browserLoaded(tab.linkedBrowser);
 
   // Make sure sessionstore sees this window.
   let state = JSON.parse(ss.getBrowserState());
   is(state.windows.length, 2, "sessionstore knows about this window");
 
   // Closed the window and check the closed window count.
   await BrowserTestUtils.closeWindow(win);
--- a/browser/components/sessionstore/test/browser_625016.js
+++ b/browser/components/sessionstore/test/browser_625016.js
@@ -20,17 +20,17 @@ add_task(async function setup() {
   forgetClosedWindows();
   is(ss.getClosedWindowCount(), 0, "starting with no closed windows");
 });
 
 add_task(async function new_window() {
   let newWin;
   try {
     newWin = await promiseNewWindowLoaded();
-    let tab = newWin.gBrowser.addTab("http://example.com/browser_625016.js?" + Math.random());
+    let tab = BrowserTestUtils.addTab(newWin.gBrowser, "http://example.com/browser_625016.js?" + Math.random());
     await promiseBrowserLoaded(tab.linkedBrowser);
 
     // Double check that we have no closed windows
     is(ss.getClosedWindowCount(), 0, "no closed windows on first save");
 
     await BrowserTestUtils.closeWindow(newWin);
     newWin = null;
 
--- a/browser/components/sessionstore/test/browser_819510_perwindowpb.js
+++ b/browser/components/sessionstore/test/browser_819510_perwindowpb.js
@@ -108,12 +108,12 @@ add_task(async function test_3() {
     "Closed windows are not private");
 
   // Cleanup.
   await promiseAllButPrimaryWindowClosed();
   forgetClosedWindows();
 });
 
 async function promiseTabLoad(win, url) {
-  let tab = win.gBrowser.addTab(url);
+  let tab = BrowserTestUtils.addTab(win.gBrowser, url);
   await promiseBrowserLoaded(tab.linkedBrowser);
   await TabStateFlusher.flush(tab.linkedBrowser);
 }
--- a/browser/components/sessionstore/test/browser_broadcast.js
+++ b/browser/components/sessionstore/test/browser_broadcast.js
@@ -111,17 +111,17 @@ add_task(async function flush_on_tabclos
 
 function promiseNewWindow() {
   return new Promise(resolve => {
     whenNewWindowLoaded({private: false}, resolve);
   });
 }
 
 async function createTabWithStorageData(urls, win = window) {
-  let tab = win.gBrowser.addTab();
+  let tab = BrowserTestUtils.addTab(win.gBrowser);
   let browser = tab.linkedBrowser;
 
   for (let url of urls) {
     browser.loadURI(url);
     await promiseBrowserLoaded(browser);
     await modifySessionStorage(browser, {test: INITIAL_VALUE});
   }
 
--- a/browser/components/sessionstore/test/browser_cleaner.js
+++ b/browser/components/sessionstore/test/browser_cleaner.js
@@ -45,17 +45,17 @@ add_task(async function init() {
 add_task(async function test_open_and_close() {
   let newTab1 = BrowserTestUtils.addTab(gBrowser, URL_TAB1);
   await promiseBrowserLoaded(newTab1.linkedBrowser);
 
   let newTab2 = BrowserTestUtils.addTab(gBrowser, URL_TAB2);
   await promiseBrowserLoaded(newTab2.linkedBrowser);
 
   let newWin = await promiseNewWindowLoaded();
-  let tab = newWin.gBrowser.addTab(URL_NEWWIN);
+  let tab = BrowserTestUtils.addTab(newWin.gBrowser, URL_NEWWIN);
 
   await promiseBrowserLoaded(tab.linkedBrowser);
 
   await TabStateFlusher.flushWindow(window);
   await TabStateFlusher.flushWindow(newWin);
 
   info("1. Making sure that before closing, we don't have closedAt");
   // For the moment, no "closedAt"
--- a/browser/components/sessionstore/test/browser_crashedTabs.js
+++ b/browser/components/sessionstore/test/browser_crashedTabs.js
@@ -295,17 +295,17 @@ add_task(async function test_revive_all_
 
   browser.loadURI(PAGE_1);
   await promiseBrowserLoaded(browser);
 
   // In order to see a second about:tabcrashed page, we'll need
   // a second window, since only selected tabs will show
   // about:tabcrashed.
   let win2 = await BrowserTestUtils.openNewBrowserWindow();
-  let newTab2 = win2.gBrowser.addTab(PAGE_1, { sameProcessAsFrameLoader: browser.frameLoader });
+  let newTab2 = BrowserTestUtils.addTab(win2.gBrowser, PAGE_1, { sameProcessAsFrameLoader: browser.frameLoader });
   win2.gBrowser.selectedTab = newTab2;
   let browser2 = newTab2.linkedBrowser;
   ok(browser2.isRemoteBrowser, "Should be a remote browser");
   await promiseBrowserLoaded(browser2);
 
   browser.loadURI(PAGE_1);
   await promiseBrowserLoaded(browser);
 
@@ -402,17 +402,17 @@ add_task(async function test_hide_restor
   gBrowser.selectedTab = newTab;
 
   browser.loadURI(PAGE_2);
   await promiseBrowserLoaded(browser);
 
   // Load up a second window so we can get another tab to show
   // about:tabcrashed
   let win2 = await BrowserTestUtils.openNewBrowserWindow();
-  let newTab3 = win2.gBrowser.addTab(PAGE_2, { sameProcessAsFrameLoader: browser.frameLoader });
+  let newTab3 = BrowserTestUtils.addTab(win2.gBrowser, PAGE_2, { sameProcessAsFrameLoader: browser.frameLoader });
   win2.gBrowser.selectedTab = newTab3;
   let otherWinBrowser = newTab3.linkedBrowser;
   await promiseBrowserLoaded(otherWinBrowser);
   // We'll need to make sure the second tab's browser has finished
   // sending its AboutTabCrashedReady event before we know for
   // sure whether or not we're showing the right Restore buttons.
   let otherBrowserReady = promiseTabCrashedReady(otherWinBrowser);
 
--- a/browser/components/sessionstore/test/browser_dying_cache.js
+++ b/browser/components/sessionstore/test/browser_dying_cache.js
@@ -11,17 +11,17 @@ add_task(async function test() {
   let win = await promiseNewWindowLoaded();
 
   // Load some URL in the current tab.
   let flags = Ci.nsIWebNavigation.LOAD_FLAGS_REPLACE_HISTORY;
   win.gBrowser.selectedBrowser.loadURI("about:robots", { flags });
   await promiseBrowserLoaded(win.gBrowser.selectedBrowser);
 
   // Open a second tab and close the first one.
-  let tab = win.gBrowser.addTab("about:mozilla");
+  let tab = BrowserTestUtils.addTab(win.gBrowser, "about:mozilla");
   await promiseBrowserLoaded(tab.linkedBrowser);
   await TabStateFlusher.flush(tab.linkedBrowser);
   await promiseRemoveTabAndSessionState(win.gBrowser.tabs[0]);
 
   // Make sure our window is still tracked by sessionstore
   // and the window state is as expected.
   ok("__SSi" in win, "window is being tracked by sessionstore");
   ss.setWindowValue(win, "foo", "bar");
--- a/browser/components/sessionstore/test/browser_privatetabs.js
+++ b/browser/components/sessionstore/test/browser_privatetabs.js
@@ -67,31 +67,31 @@ add_task(async function() {
   forgetClosedWindows();
 
   // Create a new window to attach our frame script to.
   let win = await promiseNewWindowLoaded();
   let mm = win.getGroupMessageManager("browsers");
   mm.loadFrameScript(FRAME_SCRIPT, true);
 
   // Create a new tab in the new window that will load the frame script.
-  let tab = win.gBrowser.addTab("about:mozilla");
+  let tab = BrowserTestUtils.addTab(win.gBrowser, "about:mozilla");
   let browser = tab.linkedBrowser;
   await promiseBrowserLoaded(browser);
   await TabStateFlusher.flush(browser);
 
   // Check that we consider the tab as private.
   let state = JSON.parse(ss.getTabState(tab));
   ok(state.isPrivate, "tab considered private");
 
   // Ensure we don't allow restoring closed private tabs in non-private windows.
   win.gBrowser.removeTab(tab);
   is(ss.getClosedTabCount(win), 0, "no tabs to restore");
 
   // Create a new tab in the new window that will load the frame script.
-  tab = win.gBrowser.addTab("about:mozilla");
+  tab = BrowserTestUtils.addTab(win.gBrowser, "about:mozilla");
   browser = tab.linkedBrowser;
   await promiseBrowserLoaded(browser);
   await TabStateFlusher.flush(browser);
 
   // Check that we consider the tab as private.
   state = JSON.parse(ss.getTabState(tab));
   ok(state.isPrivate, "tab considered private");
 
@@ -104,17 +104,17 @@ add_task(async function() {
 add_task(async function() {
   // Clear the list of closed windows.
   forgetClosedWindows();
 
   // Create a new window to attach our frame script to.
   let win = await promiseNewWindowLoaded({private: true});
 
   // Create a new tab in the new window that will load the frame script.
-  let tab = win.gBrowser.addTab("about:mozilla");
+  let tab = BrowserTestUtils.addTab(win.gBrowser, "about:mozilla");
   let browser = tab.linkedBrowser;
   await promiseBrowserLoaded(browser);
   await TabStateFlusher.flush(browser);
 
   // Check that we consider the tab as private.
   let state = JSON.parse(ss.getTabState(tab));
   ok(state.isPrivate, "tab considered private");
 
--- a/browser/components/sessionstore/test/browser_scrollPositions.js
+++ b/browser/components/sessionstore/test/browser_scrollPositions.js
@@ -111,17 +111,17 @@ add_task(async function test_scroll_nest
  * a restored window (bug 1228518).
  * Also test that scroll positions for previous session history entries
  * are preserved as well (bug 1265818).
  */
 add_task(async function test_scroll_background_tabs() {
   pushPrefs(["browser.sessionstore.restore_on_demand", true]);
 
   let newWin = await BrowserTestUtils.openNewBrowserWindow();
-  let tab = newWin.gBrowser.addTab(URL);
+  let tab = BrowserTestUtils.addTab(newWin.gBrowser, URL);
   let browser = tab.linkedBrowser;
   await BrowserTestUtils.browserLoaded(browser);
 
   // Scroll down a little.
   await sendMessage(browser, "ss-test:setScrollPosition", {x: SCROLL_X, y: SCROLL_Y});
   await checkScroll(tab, {scroll: SCROLL_STR}, "scroll on first page is fine");
 
   // Navigate to a different page and scroll there as well.
--- a/browser/components/sessionstore/test/browser_scrollPositionsReaderMode.js
+++ b/browser/components/sessionstore/test/browser_scrollPositionsReaderMode.js
@@ -16,17 +16,17 @@ requestLongerTimeout(2);
 /**
  * Test that scroll positions of about reader page after restoring background
  * tabs in a restored window (bug 1153393).
  */
 add_task(async function test_scroll_background_about_reader_tabs() {
   pushPrefs(["browser.sessionstore.restore_on_demand", true]);
 
   let newWin = await BrowserTestUtils.openNewBrowserWindow();
-  let tab = newWin.gBrowser.addTab(READER_MODE_URL);
+  let tab = BrowserTestUtils.addTab(newWin.gBrowser, READER_MODE_URL);
   let browser = tab.linkedBrowser;
   await Promise.all([
     BrowserTestUtils.browserLoaded(browser),
     BrowserTestUtils.waitForContentEvent(browser, "AboutReaderContentReady")
   ]);
 
   // Scroll down a little.
   await sendMessage(browser, "ss-test:setScrollPosition", {x: 0, y: SCROLL_READER_MODE_Y});
--- a/browser/components/sessionstore/test/browser_switch_remoteness.js
+++ b/browser/components/sessionstore/test/browser_switch_remoteness.js
@@ -11,17 +11,17 @@ function countHistoryEntries(browser, ex
   });
 }
 
 add_task(async function() {
   // Open a new window.
   let win = await promiseNewWindowLoaded();
 
   // Add a new tab.
-  let tab = win.gBrowser.addTab("about:blank");
+  let tab = BrowserTestUtils.addTab(win.gBrowser, "about:blank");
   let browser = tab.linkedBrowser;
   await promiseBrowserLoaded(browser);
   ok(browser.isRemoteBrowser, "browser is remote");
 
   // Get the maximum number of preceding entries to save.
   const MAX_BACK = Services.prefs.getIntPref("browser.sessionstore.max_serialize_back");
   ok(MAX_BACK > -1, "check that the default has a value that caps data");
 
--- a/browser/components/sessionstore/test/browser_undoCloseById.js
+++ b/browser/components/sessionstore/test/browser_undoCloseById.js
@@ -3,17 +3,17 @@
 
 /**
  * This test is for the undoCloseById function.
  */
 
 ChromeUtils.import("resource:///modules/sessionstore/SessionStore.jsm");
 
 async function openAndCloseTab(window, url) {
-  let tab = window.gBrowser.addTab(url);
+  let tab = BrowserTestUtils.addTab(window.gBrowser, url);
   await promiseBrowserLoaded(tab.linkedBrowser, true, url);
   await TabStateFlusher.flush(tab.linkedBrowser);
   await promiseRemoveTabAndSessionState(tab);
 }
 
 async function openWindow(url) {
   let win = await promiseNewWindowLoaded();
   let flags = Ci.nsIWebNavigation.LOAD_FLAGS_REPLACE_HISTORY;
--- a/browser/components/sessionstore/test/browser_windowStateContainer.js
+++ b/browser/components/sessionstore/test/browser_windowStateContainer.js
@@ -8,17 +8,19 @@ add_task(async function setup() {
   });
 });
 
 add_task(async function() {
   let win = await BrowserTestUtils.openNewBrowserWindow();
 
   // Create 4 tabs with different userContextId.
   for (let userContextId = 1; userContextId < 5; userContextId++) {
-    let tab = win.gBrowser.addTab("http://example.com/", {userContextId});
+    let tab = BrowserTestUtils.addTab(win.gBrowser, "http://example.com/", {
+      userContextId,
+    });
     await promiseBrowserLoaded(tab.linkedBrowser);
     await TabStateFlusher.flush(tab.linkedBrowser);
   }
 
   // Move the default tab of window to the end.
   // We want the 1st tab to have non-default userContextId, so later when we
   // restore into win2 we can test restore into an existing tab with different
   // userContextId.
@@ -31,17 +33,19 @@ add_task(async function() {
                  "1st Window: tabs[" + i + "].userContextId should exist.");
   }
 
   let win2 = await BrowserTestUtils.openNewBrowserWindow();
 
   // Create tabs with different userContextId, but this time we create them with
   // fewer tabs and with different order with win.
   for (let userContextId = 3; userContextId > 0; userContextId--) {
-    let tab = win2.gBrowser.addTab("http://example.com/", {userContextId});
+    let tab = BrowserTestUtils.addTab(win2.gBrowser, "http://example.com/", {
+      userContextId,
+    });
     await promiseBrowserLoaded(tab.linkedBrowser);
     await TabStateFlusher.flush(tab.linkedBrowser);
   }
 
   await setWindowState(win2, winState, true);
 
   for (let i = 0; i < 4; i++) {
     let browser = win2.gBrowser.tabs[i].linkedBrowser;
@@ -71,33 +75,37 @@ add_task(async function() {
   await BrowserTestUtils.closeWindow(win);
   await BrowserTestUtils.closeWindow(win2);
 });
 
 add_task(async function() {
   let win = await BrowserTestUtils.openNewBrowserWindow();
   await TabStateFlusher.flush(win.gBrowser.selectedBrowser);
 
-  let tab = win.gBrowser.addTab("http://example.com/", { userContextId: 1 });
+  let tab = BrowserTestUtils.addTab(win.gBrowser, "http://example.com/", {
+    userContextId: 1,
+  });
   await promiseBrowserLoaded(tab.linkedBrowser);
   await TabStateFlusher.flush(tab.linkedBrowser);
 
   // win should have 1 default tab, and 1 container tab.
   Assert.equal(win.gBrowser.tabs.length, 2, "win should have 2 tabs");
 
   let winState = JSON.parse(ss.getWindowState(win));
 
   for (let i = 0; i < 2; i++) {
     Assert.equal(winState.windows[0].tabs[i].userContextId, i,
                  "1st Window: tabs[" + i + "].userContextId should be " + i);
   }
 
   let win2 = await BrowserTestUtils.openNewBrowserWindow();
 
-  let tab2 = win2.gBrowser.addTab("http://example.com/", { userContextId: 1 });
+  let tab2 = BrowserTestUtils.addTab(win2.gBrowser, "http://example.com/", {
+    userContextId: 1,
+  });
   await promiseBrowserLoaded(tab2.linkedBrowser);
   await TabStateFlusher.flush(tab2.linkedBrowser);
 
   // Move the first normal tab to end, so the first tab of win2 will be a
   // container tab.
   win2.gBrowser.moveTabTo(win2.gBrowser.tabs[0], win2.gBrowser.tabs.length - 1);
   await TabStateFlusher.flush(win2.gBrowser.tabs[0].linkedBrowser);
 
--- a/browser/tools/mozscreenshots/mozscreenshots/extension/configurations/Tabs.jsm
+++ b/browser/tools/mozscreenshots/mozscreenshots/extension/configurations/Tabs.jsm
@@ -35,23 +35,31 @@ var Tabs = {
       },
     },
 
     fourPinned: {
       selectors: ["#tabbrowser-tabs"],
       async applyConfig() {
         fiveTabsHelper();
         let browserWindow = Services.wm.getMostRecentWindow("navigator:browser");
-        let tab = browserWindow.gBrowser.addTab(PREFS_TAB);
+        let tab = browserWindow.gBrowser.addTab(PREFS_TAB, {
+          triggeringPrincipal: Services.scriptSecurityManager.getSystemPrincipal(),
+        });
         browserWindow.gBrowser.pinTab(tab);
-        tab = browserWindow.gBrowser.addTab(CUST_TAB);
+        tab = browserWindow.gBrowser.addTab(CUST_TAB, {
+          triggeringPrincipal: Services.scriptSecurityManager.getSystemPrincipal(),
+        });
         browserWindow.gBrowser.pinTab(tab);
-        tab = browserWindow.gBrowser.addTab("about:privatebrowsing");
+        tab = browserWindow.gBrowser.addTab("about:privatebrowsing", {
+          triggeringPrincipal: Services.scriptSecurityManager.getSystemPrincipal(),
+        });
         browserWindow.gBrowser.pinTab(tab);
-        tab = browserWindow.gBrowser.addTab("about:home");
+        tab = browserWindow.gBrowser.addTab("about:home", {
+          triggeringPrincipal: Services.scriptSecurityManager.getSystemPrincipal(),
+        });
         browserWindow.gBrowser.pinTab(tab);
         browserWindow.gBrowser.selectTabAtIndex(5);
         hoverTab(browserWindow.gBrowser.tabs[2]);
         // also hover the new tab button
         let newTabButton = browserWindow.document.getAnonymousElementByAttribute(browserWindow.
                            gBrowser.tabContainer, "anonid", "tabs-newtab-button");
         hoverTab(newTabButton);
         browserWindow.gBrowser.tabs[browserWindow.gBrowser.tabs.length - 1].
--- a/build/build-clang/build-clang.py
+++ b/build/build-clang/build-clang.py
@@ -119,16 +119,19 @@ def install_libgcc(gcc_dir, clang_dir):
     clang_lib_dir = os.path.join(clang_dir, "lib", "gcc",
                                  "x86_64-unknown-linux-gnu",
                                  os.path.basename(libgcc_dir))
     mkdir_p(clang_lib_dir)
     copy_tree(libgcc_dir, clang_lib_dir)
     libgcc_dir = os.path.join(gcc_dir, "lib64")
     clang_lib_dir = os.path.join(clang_dir, "lib")
     copy_tree(libgcc_dir, clang_lib_dir)
+    libgcc_dir = os.path.join(gcc_dir, "lib32")
+    clang_lib_dir = os.path.join(clang_dir, "lib32")
+    copy_tree(libgcc_dir, clang_lib_dir)
     include_dir = os.path.join(gcc_dir, "include")
     clang_include_dir = os.path.join(clang_dir, "include")
     copy_tree(include_dir, clang_include_dir)
 
 
 def install_import_library(build_dir, clang_dir):
     shutil.copy2(os.path.join(build_dir, "lib", "clang.lib"),
                  os.path.join(clang_dir, "lib"))
@@ -289,17 +292,17 @@ def get_tool(config, key):
 #           * (nothing will be deleted here)
 #   share/
 #     clang/
 #       clang-format-diff.py
 #       clang-tidy-diff.py
 #       run-clang-tidy.py
 def prune_final_dir_for_clang_tidy(final_dir):
     # Make sure we only have what we expect.
-    dirs = ("bin", "include", "lib", "libexec", "msbuild-bin", "share", "tools")
+    dirs = ("bin", "include", "lib", "lib32", "libexec", "msbuild-bin", "share", "tools")
     for f in glob.glob("%s/*" % final_dir):
         if os.path.basename(f) not in dirs:
             raise Exception("Found unknown file %s in the final directory" % f)
         if not os.path.isdir(f):
             raise Exception("Expected %s to be a directory" % f)
 
     # In bin/, only keep clang-tidy and clang-apply-replacements. The last one
     # is used to auto-fix some of the issues detected by clang-tidy.
--- a/build/moz.configure/toolchain.configure
+++ b/build/moz.configure/toolchain.configure
@@ -1245,37 +1245,45 @@ set_config('VISIBILITY_FLAGS', visibilit
 @depends(c_compiler, check_build_environment, target)
 @imports('multiprocessing')
 @imports(_from='__builtin__', _import='min')
 def pgo_flags(compiler, build_env, target):
     topobjdir = build_env.topobjdir
     if topobjdir.endswith('/js/src'):
         topobjdir = topobjdir[:-7]
 
-    if compiler.type in ('gcc', 'clang'):
+    if compiler.type == 'gcc':
         return namespace(
             gen_cflags=['-fprofile-generate'],
             gen_ldflags=['-fprofile-generate'],
             use_cflags=['-fprofile-use', '-fprofile-correction',
                         '-Wcoverage-mismatch'],
             use_ldflags=['-fprofile-use'],
         )
 
-    if compiler.type == 'clang-cl':
+    if compiler.type in ('clang-cl', 'clang'):
         profdata = os.path.join(topobjdir, 'merged.profdata')
-        # 32-bit PGO is currently blocked by bug 1479800
-        if target.cpu == 'x86_64':
-          return namespace(
-              gen_cflags=['-fprofile-instr-generate'],
-              gen_ldflags=['clang_rt.profile-x86_64.lib'],
-              use_cflags=['-fprofile-instr-use=%s' % profdata,
-                          '-Wno-error=profile-instr-out-of-date',
-                          '-Wno-error=profile-instr-unprofiled'],
-              use_ldflags=[],
-          )
+        if compiler.type == 'clang-cl':
+            # 32-bit PGO is currently blocked by bug 1479800
+            if target.cpu == 'x86_64':
+                gen_ldflags = ['clang_rt.profile-x86_64.lib']
+            else:
+                gen_ldflags = None
+        else:
+            gen_ldflags = ['-fprofile-instr-generate']
+
+        if gen_ldflags:
+            return namespace(
+                gen_cflags=['-fprofile-instr-generate'],
+                gen_ldflags=gen_ldflags,
+                use_cflags=['-fprofile-instr-use=%s' % profdata,
+                            '-Wno-error=profile-instr-out-of-date',
+                            '-Wno-error=profile-instr-unprofiled'],
+                use_ldflags=[],
+            )
 
     if compiler.type == 'msvc':
         num_cores = min(8, multiprocessing.cpu_count())
         cgthreads = '-CGTHREADS:%s' % num_cores
 
         return namespace(
             gen_cflags=['-GL'],
             gen_ldflags=['-LTCG:PGINSTRUMENT', '-PogoSafeMode', cgthreads],
@@ -1740,35 +1748,39 @@ add_old_configure_assignment('ENABLE_MOZ
 # Libstdc++ compatibility hacks
 # ==============================================================
 #
 js_option('--enable-stdcxx-compat', env='MOZ_STDCXX_COMPAT',
           help='Enable compatibility with older libstdc++')
 
 
 @template
-def libstdcxx_version(var, compiler):
-    @depends(compiler, when='--enable-stdcxx-compat')
+def libstdcxx_version(var, compiler, host_or_target):
+    @depends(compiler, host_or_target, when='--enable-stdcxx-compat')
     @imports(_from='mozbuild.configure.libstdcxx', _import='find_version')
-    def version(compiler):
+    def version(compiler, host_or_target):
+        if host_or_target.os == 'Android':
+            return None
         result = find_version(
             compiler.wrapper + [compiler.compiler] + compiler.flags)
         if result:
             return str(result)
 
     set_config(var, version)
     return version
 
 
 add_gcc_flag(
     '-D_GLIBCXX_USE_CXX11_ABI=0', cxx_compiler,
-    when=libstdcxx_version('MOZ_LIBSTDCXX_TARGET_VERSION', cxx_compiler))
+    when=libstdcxx_version(
+        'MOZ_LIBSTDCXX_TARGET_VERSION', cxx_compiler, target))
 add_gcc_flag(
     '-D_GLIBCXX_USE_CXX11_ABI=0', host_cxx_compiler,
-    when=libstdcxx_version('MOZ_LIBSTDCXX_HOST_VERSION', host_cxx_compiler))
+    when=libstdcxx_version(
+        'MOZ_LIBSTDCXX_HOST_VERSION', host_cxx_compiler, host))
 
 
 @depends(c_compiler.try_compile(flags=['-fsanitize=fuzzer-no-link'],
          check_msg='whether the C compiler supports -fsanitize=fuzzer-no-link'))
 def have_libfuzzer_flag_fuzzer_no_link(value):
     if value:
         return True
 
--- a/config/rules.mk
+++ b/config/rules.mk
@@ -620,16 +620,18 @@ endif
 $(SIMPLE_PROGRAMS): %$(BIN_SUFFIX): %.$(OBJ_SUFFIX) $(STATIC_LIBS) $(EXTRA_DEPS) $(GLOBAL_DEPS)
 	$(REPORT_BUILD)
 ifeq (_WINNT,$(GNU_CC)_$(OS_ARCH))
 	$(LINKER) -nologo -out:$@ -pdb:$(LINK_PDBFILE) $($@_$(OBJS_VAR_SUFFIX)) $(WIN32_EXE_LDFLAGS) $(LDFLAGS) $(MOZ_PROGRAM_LDFLAGS) $(STATIC_LIBS) $(SHARED_LIBS) $(OS_LIBS)
 ifdef MSMANIFEST_TOOL
 	@if test -f $@.manifest; then \
 		$(MT) -NOLOGO -MANIFEST $@.manifest -OUTPUTRESOURCE:$@\;1; \
 		rm -f $@.manifest; \
+	elif test -f '$(srcdir)/$(notdir $@).manifest'; then \
+		$(MT) -NOLOGO -MANIFEST '$(win_srcdir)/$(notdir $@).manifest' -OUTPUTRESOURCE:$@\;1; \
 	fi
 endif	# MSVC with manifest tool
 else
 	$(call EXPAND_CC_OR_CXX,$@) $(COMPUTED_CXX_LDFLAGS) $(PGO_CFLAGS) -o $@ $($@_$(OBJS_VAR_SUFFIX)) $(WIN32_EXE_LDFLAGS) $(LDFLAGS) $(STATIC_LIBS) $(MOZ_PROGRAM_LDFLAGS) $(SHARED_LIBS) $(OS_LIBS)
 	$(call py_action,check_binary,--target $@)
 endif # WINNT && !GNU_CC
 
 ifdef ENABLE_STRIP
--- a/devtools/client/commandline/test/helpers.js
+++ b/devtools/client/commandline/test/helpers.js
@@ -66,17 +66,17 @@ var { helpers, assert } = (function () {
   helpers.addTab = function (url, callback, options) {
     waitForExplicitFinish();
 
     options = options || {};
     options.chromeWindow = options.chromeWindow || window;
     options.isFirefox = true;
 
     var tabbrowser = options.chromeWindow.gBrowser;
-    options.tab = tabbrowser.addTab();
+    options.tab = BrowserTestUtils.addTab(tabbrowser);
     tabbrowser.selectedTab = options.tab;
     options.browser = tabbrowser.getBrowserForTab(options.tab);
     options.target = TargetFactory.forTab(options.tab);
 
     var loaded = BrowserTestUtils.browserLoaded(options.browser).then(function () {
       var reply = callback.call(null, options);
 
       return Promise.resolve(reply).catch(function (error) {
@@ -112,17 +112,17 @@ var { helpers, assert } = (function () {
   helpers.openTab = function (url, options) {
     waitForExplicitFinish();
 
     options = options || {};
     options.chromeWindow = options.chromeWindow || window;
     options.isFirefox = true;
 
     var tabbrowser = options.chromeWindow.gBrowser;
-    options.tab = tabbrowser.addTab();
+    options.tab = BrowserTestUtils.addTab(tabbrowser);
     tabbrowser.selectedTab = options.tab;
     options.browser = tabbrowser.getBrowserForTab(options.tab);
     options.target = TargetFactory.forTab(options.tab);
 
     return helpers.navigate(url, options);
   };
 
 /**
--- a/devtools/client/debugger/new/README.mozilla
+++ b/devtools/client/debugger/new/README.mozilla
@@ -1,13 +1,13 @@
 This is the debugger.html project output.
 See https://github.com/devtools-html/debugger.html
 
-Version 79
+Version 80
 
-Comparison: https://github.com/devtools-html/debugger.html/compare/release-78...release-79
+Comparison: https://github.com/devtools-html/debugger.html/compare/release-79...release-80
 
 Packages:
 - babel-plugin-transform-es2015-modules-commonjs @6.26.2
 - babel-preset-react @6.24.1
 - react @16.4.1
 - react-dom @16.4.1
 - webpack @3.12.0
--- a/devtools/client/debugger/new/dist/parser-worker.js
+++ b/devtools/client/debugger/new/dist/parser-worker.js
@@ -729,16 +729,207 @@ var overArg = __webpack_require__(13);
 /** Built-in value references. */
 var getPrototype = overArg(Object.getPrototypeOf, Object);
 
 module.exports = getPrototype;
 
 
 /***/ }),
 
+/***/ 120:
+/***/ (function(module, exports) {
+
+// shim for using process in browser
+var process = module.exports = {};
+
+// cached from whatever global is present so that test runners that stub it
+// don't break things.  But we need to wrap it in a try catch in case it is
+// wrapped in strict mode code which doesn't define any globals.  It's inside a
+// function because try/catches deoptimize in certain engines.
+
+var cachedSetTimeout;
+var cachedClearTimeout;
+
+function defaultSetTimout() {
+    throw new Error('setTimeout has not been defined');
+}
+function defaultClearTimeout () {
+    throw new Error('clearTimeout has not been defined');
+}
+(function () {
+    try {
+        if (typeof setTimeout === 'function') {
+            cachedSetTimeout = setTimeout;
+        } else {
+            cachedSetTimeout = defaultSetTimout;
+        }
+    } catch (e) {
+        cachedSetTimeout = defaultSetTimout;
+    }
+    try {
+        if (typeof clearTimeout === 'function') {
+            cachedClearTimeout = clearTimeout;
+        } else {
+            cachedClearTimeout = defaultClearTimeout;
+        }
+    } catch (e) {
+        cachedClearTimeout = defaultClearTimeout;
+    }
+} ())
+function runTimeout(fun) {
+    if (cachedSetTimeout === setTimeout) {
+        //normal enviroments in sane situations
+        return setTimeout(fun, 0);
+    }
+    // if setTimeout wasn't available but was latter defined
+    if ((cachedSetTimeout === defaultSetTimout || !cachedSetTimeout) && setTimeout) {
+        cachedSetTimeout = setTimeout;
+        return setTimeout(fun, 0);
+    }
+    try {
+        // when when somebody has screwed with setTimeout but no I.E. maddness
+        return cachedSetTimeout(fun, 0);
+    } catch(e){
+        try {
+            // When we are in I.E. but the script has been evaled so I.E. doesn't trust the global object when called normally
+            return cachedSetTimeout.call(null, fun, 0);
+        } catch(e){
+            // same as above but when it's a version of I.E. that must have the global object for 'this', hopfully our context correct otherwise it will throw a global error
+            return cachedSetTimeout.call(this, fun, 0);
+        }
+    }
+
+
+}
+function runClearTimeout(marker) {
+    if (cachedClearTimeout === clearTimeout) {
+        //normal enviroments in sane situations
+        return clearTimeout(marker);
+    }
+    // if clearTimeout wasn't available but was latter defined
+    if ((cachedClearTimeout === defaultClearTimeout || !cachedClearTimeout) && clearTimeout) {
+        cachedClearTimeout = clearTimeout;
+        return clearTimeout(marker);
+    }
+    try {
+        // when when somebody has screwed with setTimeout but no I.E. maddness
+        return cachedClearTimeout(marker);
+    } catch (e){
+        try {
+            // When we are in I.E. but the script has been evaled so I.E. doesn't  trust the global object when called normally
+            return cachedClearTimeout.call(null, marker);
+        } catch (e){
+            // same as above but when it's a version of I.E. that must have the global object for 'this', hopfully our context correct otherwise it will throw a global error.
+            // Some versions of I.E. have different rules for clearTimeout vs setTimeout
+            return cachedClearTimeout.call(this, marker);
+        }
+    }
+
+
+
+}
+var queue = [];
+var draining = false;
+var currentQueue;
+var queueIndex = -1;
+
+function cleanUpNextTick() {
+    if (!draining || !currentQueue) {
+        return;
+    }
+    draining = false;
+    if (currentQueue.length) {
+        queue = currentQueue.concat(queue);
+    } else {
+        queueIndex = -1;
+    }
+    if (queue.length) {
+        drainQueue();
+    }
+}
+
+function drainQueue() {
+    if (draining) {
+        return;
+    }
+    var timeout = runTimeout(cleanUpNextTick);
+    draining = true;
+
+    var len = queue.length;
+    while(len) {
+        currentQueue = queue;
+        queue = [];
+        while (++queueIndex < len) {
+            if (currentQueue) {
+                currentQueue[queueIndex].run();
+            }
+        }
+        queueIndex = -1;
+        len = queue.length;
+    }
+    currentQueue = null;
+    draining = false;
+    runClearTimeout(timeout);
+}
+
+process.nextTick = function (fun) {
+    var args = new Array(arguments.length - 1);
+    if (arguments.length > 1) {
+        for (var i = 1; i < arguments.length; i++) {
+            args[i - 1] = arguments[i];
+        }
+    }
+    queue.push(new Item(fun, args));
+    if (queue.length === 1 && !draining) {
+        runTimeout(drainQueue);
+    }
+};
+
+// v8 likes predictible objects
+function Item(fun, array) {
+    this.fun = fun;
+    this.array = array;
+}
+Item.prototype.run = function () {
+    this.fun.apply(null, this.array);
+};
+process.title = 'browser';
+process.browser = true;
+process.env = {};
+process.argv = [];
+process.version = ''; // empty string to avoid regexp issues
+process.versions = {};
+
+function noop() {}
+
+process.on = noop;
+process.addListener = noop;
+process.once = noop;
+process.off = noop;
+process.removeListener = noop;
+process.removeAllListeners = noop;
+process.emit = noop;
+process.prependListener = noop;
+process.prependOnceListener = noop;
+
+process.listeners = function (name) { return [] }
+
+process.binding = function (name) {
+    throw new Error('process.binding is not supported');
+};
+
+process.cwd = function () { return '/' };
+process.chdir = function (dir) {
+    throw new Error('process.chdir is not supported');
+};
+process.umask = function() { return 0; };
+
+
+/***/ }),
+
 /***/ 1272:
 /***/ (function(module, exports, __webpack_require__) {
 
 module.exports = __webpack_require__(1618);
 
 
 /***/ }),
 
@@ -773,20 +964,22 @@ module.exports = overArg;
 Object.defineProperty(exports, "__esModule", {
   value: true
 });
 
 var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; /* This Source Code Form is subject to the terms of the Mozilla Public
                                                                                                                                                                                                                                                                    * License, v. 2.0. If a copy of the MPL was not distributed with this
                                                                                                                                                                                                                                                                    * file, You can obtain one at <http://mozilla.org/MPL/2.0/>. */
 
+exports.parse = parse;
 exports.parseScript = parseScript;
 exports.getAst = getAst;
 exports.clearASTs = clearASTs;
 exports.traverseAst = traverseAst;
+exports.hasNode = hasNode;
 
 var _parseScriptTags = __webpack_require__(1023);
 
 var _parseScriptTags2 = _interopRequireDefault(_parseScriptTags);
 
 var _parser = __webpack_require__(3773);
 
 var babelParser = _interopRequireWildcard(_parser);
@@ -883,16 +1076,20 @@ function parseScript(text, opts) {
 
 function getAst(sourceId) {
   if (ASTs.has(sourceId)) {
     return ASTs.get(sourceId);
   }
 
   const source = (0, _sources.getSource)(sourceId);
 
+  if (source.isWasm) {
+    return null;
+  }
+
   let ast = {};
   const { contentType } = source;
   if (contentType == "text/html") {
     ast = (0, _parseScriptTags2.default)(source.text, htmlParser) || {};
   } else if (contentType && contentType === "text/vue") {
     ast = parseVueScript(source.text) || {};
   } else if (contentType && contentType.match(/(javascript|jsx)/) && !contentType.match(/typescript-jsx/)) {
     const type = source.id.includes("original") ? "original" : "generated";
@@ -918,16 +1115,33 @@ function traverseAst(sourceId, visitor, 
   if ((0, _isEmpty2.default)(ast)) {
     return null;
   }
 
   t.traverse(ast, visitor, state);
   return ast;
 }
 
+function hasNode(rootNode, predicate) {
+  try {
+    t.traverse(rootNode, {
+      enter: (node, ancestors) => {
+        if (predicate(node, ancestors)) {
+          throw new Error("MATCH");
+        }
+      }
+    });
+  } catch (e) {
+    if (e.message === "MATCH") {
+      return true;
+    }
+  }
+  return false;
+}
+
 /***/ }),
 
 /***/ 14:
 /***/ (function(module, exports) {
 
 /**
  * Checks if `value` is object-like. A value is object-like if it's not `null`
  * and has a `typeof` result of "object".
@@ -978,16 +1192,17 @@ exports.getObjectExpressionValue = getOb
 exports.getCode = getCode;
 exports.getVariableNames = getVariableNames;
 exports.getComments = getComments;
 exports.getSpecifiers = getSpecifiers;
 exports.isVariable = isVariable;
 exports.isComputedExpression = isComputedExpression;
 exports.getMemberExpression = getMemberExpression;
 exports.getVariables = getVariables;
+exports.isTopLevel = isTopLevel;
 
 var _types = __webpack_require__(2268);
 
 var t = _interopRequireWildcard(_types);
 
 var _generator = __webpack_require__(2365);
 
 var _generator2 = _interopRequireDefault(_generator);
@@ -1142,16 +1357,22 @@ function getVariables(dec) {
   }
 
   return [{
     name: dec.id.name,
     location: dec.loc
   }];
 }
 
+// Top Level checks the number of "body" nodes in the ancestor chain
+// if the node is top-level, then it shoul only have one body.
+function isTopLevel(ancestors) {
+  return ancestors.filter(ancestor => ancestor.key == "body").length == 1;
+}
+
 /***/ }),
 
 /***/ 1455:
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
 
 
@@ -15813,16 +16034,93 @@ function BigIntLiteral(node) {
     return;
   }
 
   this.token(node.value);
 }
 
 /***/ }),
 
+/***/ 2348:
+/***/ (function(module, exports, __webpack_require__) {
+
+"use strict";
+
+
+Object.defineProperty(exports, "__esModule", {
+  value: true
+});
+exports.merge = merge;
+exports.validate = validate;
+exports.normalizeReplacements = normalizeReplacements;
+
+function _objectWithoutProperties(source, excluded) { if (source == null) return {}; var target = {}; var sourceKeys = Object.keys(source); var key, i; for (i = 0; i < sourceKeys.length; i++) { key = sourceKeys[i]; if (excluded.indexOf(key) >= 0) continue; target[key] = source[key]; } if (Object.getOwnPropertySymbols) { var sourceSymbolKeys = Object.getOwnPropertySymbols(source); for (i = 0; i < sourceSymbolKeys.length; i++) { key = sourceSymbolKeys[i]; if (excluded.indexOf(key) >= 0) continue; if (!Object.prototype.propertyIsEnumerable.call(source, key)) continue; target[key] = source[key]; } } return target; }
+
+function merge(a, b) {
+  const {
+    placeholderWhitelist = a.placeholderWhitelist,
+    placeholderPattern = a.placeholderPattern,
+    preserveComments = a.preserveComments
+  } = b;
+  return {
+    parser: Object.assign({}, a.parser, b.parser),
+    placeholderWhitelist,
+    placeholderPattern,
+    preserveComments
+  };
+}
+
+function validate(opts) {
+  if (opts != null && typeof opts !== "object") {
+    throw new Error("Unknown template options.");
+  }
+
+  const _ref = opts || {},
+        {
+    placeholderWhitelist,
+    placeholderPattern,
+    preserveComments
+  } = _ref,
+        parser = _objectWithoutProperties(_ref, ["placeholderWhitelist", "placeholderPattern", "preserveComments"]);
+
+  if (placeholderWhitelist != null && !(placeholderWhitelist instanceof Set)) {
+    throw new Error("'.placeholderWhitelist' must be a Set, null, or undefined");
+  }
+
+  if (placeholderPattern != null && !(placeholderPattern instanceof RegExp) && placeholderPattern !== false) {
+    throw new Error("'.placeholderPattern' must be a RegExp, false, null, or undefined");
+  }
+
+  if (preserveComments != null && typeof preserveComments !== "boolean") {
+    throw new Error("'.preserveComments' must be a boolean, null, or undefined");
+  }
+
+  return {
+    parser,
+    placeholderWhitelist: placeholderWhitelist || undefined,
+    placeholderPattern: placeholderPattern == null ? undefined : placeholderPattern,
+    preserveComments: preserveComments == null ? false : preserveComments
+  };
+}
+
+function normalizeReplacements(replacements) {
+  if (Array.isArray(replacements)) {
+    return replacements.reduce((acc, replacement, i) => {
+      acc["$" + i] = replacement;
+      return acc;
+    }, {});
+  } else if (typeof replacements === "object" || replacements == null) {
+    return replacements || undefined;
+  }
+
+  throw new Error("Template replacements must be an array, object, null, or undefined");
+}
+
+/***/ }),
+
 /***/ 2353:
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
 
 
 Object.defineProperty(exports, "__esModule", {
   value: true
@@ -16158,16 +16456,1196 @@ function ImportNamespaceSpecifier(node) 
   this.space();
   this.word("as");
   this.space();
   this.print(node.local, node);
 }
 
 /***/ }),
 
+/***/ 2355:
+/***/ (function(module, exports, __webpack_require__) {
+
+/* MIT license */
+var cssKeywords = __webpack_require__(2389);
+
+// NOTE: conversions should only return primitive values (i.e. arrays, or
+//       values that give correct `typeof` results).
+//       do not use box values types (i.e. Number(), String(), etc.)
+
+var reverseKeywords = {};
+for (var key in cssKeywords) {
+	if (cssKeywords.hasOwnProperty(key)) {
+		reverseKeywords[cssKeywords[key]] = key;
+	}
+}
+
+var convert = module.exports = {
+	rgb: {channels: 3, labels: 'rgb'},
+	hsl: {channels: 3, labels: 'hsl'},
+	hsv: {channels: 3, labels: 'hsv'},
+	hwb: {channels: 3, labels: 'hwb'},
+	cmyk: {channels: 4, labels: 'cmyk'},
+	xyz: {channels: 3, labels: 'xyz'},
+	lab: {channels: 3, labels: 'lab'},
+	lch: {channels: 3, labels: 'lch'},
+	hex: {channels: 1, labels: ['hex']},
+	keyword: {channels: 1, labels: ['keyword']},
+	ansi16: {channels: 1, labels: ['ansi16']},
+	ansi256: {channels: 1, labels: ['ansi256']},
+	hcg: {channels: 3, labels: ['h', 'c', 'g']},
+	apple: {channels: 3, labels: ['r16', 'g16', 'b16']},
+	gray: {channels: 1, labels: ['gray']}
+};
+
+// hide .channels and .labels properties
+for (var model in convert) {
+	if (convert.hasOwnProperty(model)) {
+		if (!('channels' in convert[model])) {
+			throw new Error('missing channels property: ' + model);
+		}
+
+		if (!('labels' in convert[model])) {
+			throw new Error('missing channel labels property: ' + model);
+		}
+
+		if (convert[model].labels.length !== convert[model].channels) {
+			throw new Error('channel and label counts mismatch: ' + model);
+		}
+
+		var channels = convert[model].channels;
+		var labels = convert[model].labels;
+		delete convert[model].channels;
+		delete convert[model].labels;
+		Object.defineProperty(convert[model], 'channels', {value: channels});
+		Object.defineProperty(convert[model], 'labels', {value: labels});
+	}
+}
+
+convert.rgb.hsl = function (rgb) {
+	var r = rgb[0] / 255;
+	var g = rgb[1] / 255;
+	var b = rgb[2] / 255;
+	var min = Math.min(r, g, b);
+	var max = Math.max(r, g, b);
+	var delta = max - min;
+	var h;
+	var s;
+	var l;
+
+	if (max === min) {
+		h = 0;
+	} else if (r === max) {
+		h = (g - b) / delta;
+	} else if (g === max) {
+		h = 2 + (b - r) / delta;
+	} else if (b === max) {
+		h = 4 + (r - g) / delta;
+	}
+
+	h = Math.min(h * 60, 360);
+
+	if (h < 0) {
+		h += 360;
+	}
+
+	l = (min + max) / 2;
+
+	if (max === min) {
+		s = 0;
+	} else if (l <= 0.5) {
+		s = delta / (max + min);
+	} else {
+		s = delta / (2 - max - min);
+	}
+
+	return [h, s * 100, l * 100];
+};
+
+convert.rgb.hsv = function (rgb) {
+	var rdif;
+	var gdif;
+	var bdif;
+	var h;
+	var s;
+
+	var r = rgb[0] / 255;
+	var g = rgb[1] / 255;
+	var b = rgb[2] / 255;
+	var v = Math.max(r, g, b);
+	var diff = v - Math.min(r, g, b);
+	var diffc = function (c) {
+		return (v - c) / 6 / diff + 1 / 2;
+	};
+
+	if (diff === 0) {
+		h = s = 0;
+	} else {
+		s = diff / v;
+		rdif = diffc(r);
+		gdif = diffc(g);
+		bdif = diffc(b);
+
+		if (r === v) {
+			h = bdif - gdif;
+		} else if (g === v) {
+			h = (1 / 3) + rdif - bdif;
+		} else if (b === v) {
+			h = (2 / 3) + gdif - rdif;
+		}
+		if (h < 0) {
+			h += 1;
+		} else if (h > 1) {
+			h -= 1;
+		}
+	}
+
+	return [
+		h * 360,
+		s * 100,
+		v * 100
+	];
+};
+
+convert.rgb.hwb = function (rgb) {
+	var r = rgb[0];
+	var g = rgb[1];
+	var b = rgb[2];
+	var h = convert.rgb.hsl(rgb)[0];
+	var w = 1 / 255 * Math.min(r, Math.min(g, b));
+
+	b = 1 - 1 / 255 * Math.max(r, Math.max(g, b));
+
+	return [h, w * 100, b * 100];
+};
+
+convert.rgb.cmyk = function (rgb) {
+	var r = rgb[0] / 255;
+	var g = rgb[1] / 255;
+	var b = rgb[2] / 255;
+	var c;
+	var m;
+	var y;
+	var k;
+
+	k = Math.min(1 - r, 1 - g, 1 - b);
+	c = (1 - r - k) / (1 - k) || 0;
+	m = (1 - g - k) / (1 - k) || 0;
+	y = (1 - b - k) / (1 - k) || 0;
+
+	return [c * 100, m * 100, y * 100, k * 100];
+};
+
+/**
+ * See https://en.m.wikipedia.org/wiki/Euclidean_distance#Squared_Euclidean_distance
+ * */
+function comparativeDistance(x, y) {
+	return (
+		Math.pow(x[0] - y[0], 2) +
+		Math.pow(x[1] - y[1], 2) +
+		Math.pow(x[2] - y[2], 2)
+	);
+}
+
+convert.rgb.keyword = function (rgb) {
+	var reversed = reverseKeywords[rgb];
+	if (reversed) {
+		return reversed;
+	}
+
+	var currentClosestDistance = Infinity;
+	var currentClosestKeyword;
+
+	for (var keyword in cssKeywords) {
+		if (cssKeywords.hasOwnProperty(keyword)) {
+			var value = cssKeywords[keyword];
+
+			// Compute comparative distance
+			var distance = comparativeDistance(rgb, value);
+
+			// Check if its less, if so set as closest
+			if (distance < currentClosestDistance) {
+				currentClosestDistance = distance;
+				currentClosestKeyword = keyword;
+			}
+		}
+	}
+
+	return currentClosestKeyword;
+};
+
+convert.keyword.rgb = function (keyword) {
+	return cssKeywords[keyword];
+};
+
+convert.rgb.xyz = function (rgb) {
+	var r = rgb[0] / 255;
+	var g = rgb[1] / 255;
+	var b = rgb[2] / 255;
+
+	// assume sRGB
+	r = r > 0.04045 ? Math.pow(((r + 0.055) / 1.055), 2.4) : (r / 12.92);
+	g = g > 0.04045 ? Math.pow(((g + 0.055) / 1.055), 2.4) : (g / 12.92);
+	b = b > 0.04045 ? Math.pow(((b + 0.055) / 1.055), 2.4) : (b / 12.92);
+
+	var x = (r * 0.4124) + (g * 0.3576) + (b * 0.1805);
+	var y = (r * 0.2126) + (g * 0.7152) + (b * 0.0722);
+	var z = (r * 0.0193) + (g * 0.1192) + (b * 0.9505);
+
+	return [x * 100, y * 100, z * 100];
+};
+
+convert.rgb.lab = function (rgb) {
+	var xyz = convert.rgb.xyz(rgb);
+	var x = xyz[0];
+	var y = xyz[1];
+	var z = xyz[2];
+	var l;
+	var a;
+	var b;
+
+	x /= 95.047;
+	y /= 100;
+	z /= 108.883;
+
+	x = x > 0.008856 ? Math.pow(x, 1 / 3) : (7.787 * x) + (16 / 116);
+	y = y > 0.008856 ? Math.pow(y, 1 / 3) : (7.787 * y) + (16 / 116);
+	z = z > 0.008856 ? Math.pow(z, 1 / 3) : (7.787 * z) + (16 / 116);
+
+	l = (116 * y) - 16;
+	a = 500 * (x - y);
+	b = 200 * (y - z);
+
+	return [l, a, b];
+};
+
+convert.hsl.rgb = function (hsl) {
+	var h = hsl[0] / 360;
+	var s = hsl[1] / 100;
+	var l = hsl[2] / 100;
+	var t1;
+	var t2;
+	var t3;
+	var rgb;
+	var val;
+
+	if (s === 0) {
+		val = l * 255;
+		return [val, val, val];
+	}
+
+	if (l < 0.5) {
+		t2 = l * (1 + s);
+	} else {
+		t2 = l + s - l * s;
+	}
+
+	t1 = 2 * l - t2;
+
+	rgb = [0, 0, 0];
+	for (var i = 0; i < 3; i++) {
+		t3 = h + 1 / 3 * -(i - 1);
+		if (t3 < 0) {
+			t3++;
+		}
+		if (t3 > 1) {
+			t3--;
+		}
+
+		if (6 * t3 < 1) {
+			val = t1 + (t2 - t1) * 6 * t3;
+		} else if (2 * t3 < 1) {
+			val = t2;
+		} else if (3 * t3 < 2) {
+			val = t1 + (t2 - t1) * (2 / 3 - t3) * 6;
+		} else {
+			val = t1;
+		}
+
+		rgb[i] = val * 255;
+	}
+
+	return rgb;
+};
+
+convert.hsl.hsv = function (hsl) {
+	var h = hsl[0];
+	var s = hsl[1] / 100;
+	var l = hsl[2] / 100;
+	var smin = s;
+	var lmin = Math.max(l, 0.01);
+	var sv;
+	var v;
+
+	l *= 2;
+	s *= (l <= 1) ? l : 2 - l;
+	smin *= lmin <= 1 ? lmin : 2 - lmin;
+	v = (l + s) / 2;
+	sv = l === 0 ? (2 * smin) / (lmin + smin) : (2 * s) / (l + s);
+
+	return [h, sv * 100, v * 100];
+};
+
+convert.hsv.rgb = function (hsv) {
+	var h = hsv[0] / 60;
+	var s = hsv[1] / 100;
+	var v = hsv[2] / 100;
+	var hi = Math.floor(h) % 6;
+
+	var f = h - Math.floor(h);
+	var p = 255 * v * (1 - s);
+	var q = 255 * v * (1 - (s * f));
+	var t = 255 * v * (1 - (s * (1 - f)));
+	v *= 255;
+
+	switch (hi) {
+		case 0:
+			return [v, t, p];
+		case 1:
+			return [q, v, p];
+		case 2:
+			return [p, v, t];
+		case 3:
+			return [p, q, v];
+		case 4:
+			return [t, p, v];
+		case 5:
+			return [v, p, q];
+	}
+};
+
+convert.hsv.hsl = function (hsv) {
+	var h = hsv[0];
+	var s = hsv[1] / 100;
+	var v = hsv[2] / 100;
+	var vmin = Math.max(v, 0.01);
+	var lmin;
+	var sl;
+	var l;
+
+	l = (2 - s) * v;
+	lmin = (2 - s) * vmin;
+	sl = s * vmin;
+	sl /= (lmin <= 1) ? lmin : 2 - lmin;
+	sl = sl || 0;
+	l /= 2;
+
+	return [h, sl * 100, l * 100];
+};
+
+// http://dev.w3.org/csswg/css-color/#hwb-to-rgb
+convert.hwb.rgb = function (hwb) {
+	var h = hwb[0] / 360;
+	var wh = hwb[1] / 100;
+	var bl = hwb[2] / 100;
+	var ratio = wh + bl;
+	var i;
+	var v;
+	var f;
+	var n;
+
+	// wh + bl cant be > 1
+	if (ratio > 1) {
+		wh /= ratio;
+		bl /= ratio;
+	}
+
+	i = Math.floor(6 * h);
+	v = 1 - bl;
+	f = 6 * h - i;
+
+	if ((i & 0x01) !== 0) {
+		f = 1 - f;
+	}
+
+	n = wh + f * (v - wh); // linear interpolation
+
+	var r;
+	var g;
+	var b;
+	switch (i) {
+		default:
+		case 6:
+		case 0: r = v; g = n; b = wh; break;
+		case 1: r = n; g = v; b = wh; break;
+		case 2: r = wh; g = v; b = n; break;
+		case 3: r = wh; g = n; b = v; break;
+		case 4: r = n; g = wh; b = v; break;
+		case 5: r = v; g = wh; b = n; break;
+	}
+
+	return [r * 255, g * 255, b * 255];
+};
+
+convert.cmyk.rgb = function (cmyk) {
+	var c = cmyk[0] / 100;
+	var m = cmyk[1] / 100;
+	var y = cmyk[2] / 100;
+	var k = cmyk[3] / 100;
+	var r;
+	var g;
+	var b;
+
+	r = 1 - Math.min(1, c * (1 - k) + k);
+	g = 1 - Math.min(1, m * (1 - k) + k);
+	b = 1 - Math.min(1, y * (1 - k) + k);
+
+	return [r * 255, g * 255, b * 255];
+};
+
+convert.xyz.rgb = function (xyz) {
+	var x = xyz[0] / 100;
+	var y = xyz[1] / 100;
+	var z = xyz[2] / 100;
+	var r;
+	var g;
+	var b;
+
+	r = (x * 3.2406) + (y * -1.5372) + (z * -0.4986);
+	g = (x * -0.9689) + (y * 1.8758) + (z * 0.0415);
+	b = (x * 0.0557) + (y * -0.2040) + (z * 1.0570);
+
+	// assume sRGB
+	r = r > 0.0031308
+		? ((1.055 * Math.pow(r, 1.0 / 2.4)) - 0.055)
+		: r * 12.92;
+
+	g = g > 0.0031308
+		? ((1.055 * Math.pow(g, 1.0 / 2.4)) - 0.055)
+		: g * 12.92;
+
+	b = b > 0.0031308
+		? ((1.055 * Math.pow(b, 1.0 / 2.4)) - 0.055)
+		: b * 12.92;
+
+	r = Math.min(Math.max(0, r), 1);
+	g = Math.min(Math.max(0, g), 1);
+	b = Math.min(Math.max(0, b), 1);
+
+	return [r * 255, g * 255, b * 255];
+};
+
+convert.xyz.lab = function (xyz) {
+	var x = xyz[0];
+	var y = xyz[1];
+	var z = xyz[2];
+	var l;
+	var a;
+	var b;
+
+	x /= 95.047;
+	y /= 100;
+	z /= 108.883;
+
+	x = x > 0.008856 ? Math.pow(x, 1 / 3) : (7.787 * x) + (16 / 116);
+	y = y > 0.008856 ? Math.pow(y, 1 / 3) : (7.787 * y) + (16 / 116);
+	z = z > 0.008856 ? Math.pow(z, 1 / 3) : (7.787 * z) + (16 / 116);
+
+	l = (116 * y) - 16;
+	a = 500 * (x - y);
+	b = 200 * (y - z);
+
+	return [l, a, b];
+};
+
+convert.lab.xyz = function (lab) {
+	var l = lab[0];
+	var a = lab[1];
+	var b = lab[2];
+	var x;
+	var y;
+	var z;
+
+	y = (l + 16) / 116;
+	x = a / 500 + y;
+	z = y - b / 200;
+
+	var y2 = Math.pow(y, 3);
+	var x2 = Math.pow(x, 3);
+	var z2 = Math.pow(z, 3);
+	y = y2 > 0.008856 ? y2 : (y - 16 / 116) / 7.787;
+	x = x2 > 0.008856 ? x2 : (x - 16 / 116) / 7.787;
+	z = z2 > 0.008856 ? z2 : (z - 16 / 116) / 7.787;
+
+	x *= 95.047;
+	y *= 100;
+	z *= 108.883;
+
+	return [x, y, z];
+};
+
+convert.lab.lch = function (lab) {
+	var l = lab[0];
+	var a = lab[1];
+	var b = lab[2];
+	var hr;
+	var h;
+	var c;
+
+	hr = Math.atan2(b, a);
+	h = hr * 360 / 2 / Math.PI;
+
+	if (h < 0) {
+		h += 360;
+	}
+
+	c = Math.sqrt(a * a + b * b);
+
+	return [l, c, h];
+};
+
+convert.lch.lab = function (lch) {
+	var l = lch[0];
+	var c = lch[1];
+	var h = lch[2];
+	var a;
+	var b;
+	var hr;
+
+	hr = h / 360 * 2 * Math.PI;
+	a = c * Math.cos(hr);
+	b = c * Math.sin(hr);
+
+	return [l, a, b];
+};
+
+convert.rgb.ansi16 = function (args) {
+	var r = args[0];
+	var g = args[1];
+	var b = args[2];
+	var value = 1 in arguments ? arguments[1] : convert.rgb.hsv(args)[2]; // hsv -> ansi16 optimization
+
+	value = Math.round(value / 50);
+
+	if (value === 0) {
+		return 30;
+	}
+
+	var ansi = 30
+		+ ((Math.round(b / 255) << 2)
+		| (Math.round(g / 255) << 1)
+		| Math.round(r / 255));
+
+	if (value === 2) {
+		ansi += 60;
+	}
+
+	return ansi;
+};
+
+convert.hsv.ansi16 = function (args) {
+	// optimization here; we already know the value and don't need to get
+	// it converted for us.
+	return convert.rgb.ansi16(convert.hsv.rgb(args), args[2]);
+};
+
+convert.rgb.ansi256 = function (args) {
+	var r = args[0];
+	var g = args[1];
+	var b = args[2];
+
+	// we use the extended greyscale palette here, with the exception of
+	// black and white. normal palette only has 4 greyscale shades.
+	if (r === g && g === b) {
+		if (r < 8) {
+			return 16;
+		}
+
+		if (r > 248) {
+			return 231;
+		}
+
+		return Math.round(((r - 8) / 247) * 24) + 232;
+	}
+
+	var ansi = 16
+		+ (36 * Math.round(r / 255 * 5))
+		+ (6 * Math.round(g / 255 * 5))
+		+ Math.round(b / 255 * 5);
+
+	return ansi;
+};
+
+convert.ansi16.rgb = function (args) {
+	var color = args % 10;
+
+	// handle greyscale
+	if (color === 0 || color === 7) {
+		if (args > 50) {
+			color += 3.5;
+		}
+
+		color = color / 10.5 * 255;
+
+		return [color, color, color];
+	}
+
+	var mult = (~~(args > 50) + 1) * 0.5;
+	var r = ((color & 1) * mult) * 255;
+	var g = (((color >> 1) & 1) * mult) * 255;
+	var b = (((color >> 2) & 1) * mult) * 255;
+
+	return [r, g, b];
+};
+
+convert.ansi256.rgb = function (args) {
+	// handle greyscale
+	if (args >= 232) {
+		var c = (args - 232) * 10 + 8;
+		return [c, c, c];
+	}
+
+	args -= 16;
+
+	var rem;
+	var r = Math.floor(args / 36) / 5 * 255;
+	var g = Math.floor((rem = args % 36) / 6) / 5 * 255;
+	var b = (rem % 6) / 5 * 255;
+
+	return [r, g, b];
+};
+
+convert.rgb.hex = function (args) {
+	var integer = ((Math.round(args[0]) & 0xFF) << 16)
+		+ ((Math.round(args[1]) & 0xFF) << 8)
+		+ (Math.round(args[2]) & 0xFF);
+
+	var string = integer.toString(16).toUpperCase();
+	return '000000'.substring(string.length) + string;
+};
+
+convert.hex.rgb = function (args) {
+	var match = args.toString(16).match(/[a-f0-9]{6}|[a-f0-9]{3}/i);
+	if (!match) {
+		return [0, 0, 0];
+	}
+
+	var colorString = match[0];
+
+	if (match[0].length === 3) {
+		colorString = colorString.split('').map(function (char) {
+			return char + char;
+		}).join('');
+	}
+
+	var integer = parseInt(colorString, 16);
+	var r = (integer >> 16) & 0xFF;
+	var g = (integer >> 8) & 0xFF;
+	var b = integer & 0xFF;
+
+	return [r, g, b];
+};
+
+convert.rgb.hcg = function (rgb) {
+	var r = rgb[0] / 255;
+	var g = rgb[1] / 255;
+	var b = rgb[2] / 255;
+	var max = Math.max(Math.max(r, g), b);
+	var min = Math.min(Math.min(r, g), b);
+	var chroma = (max - min);
+	var grayscale;
+	var hue;
+
+	if (chroma < 1) {
+		grayscale = min / (1 - chroma);
+	} else {
+		grayscale = 0;
+	}
+
+	if (chroma <= 0) {
+		hue = 0;
+	} else
+	if (max === r) {
+		hue = ((g - b) / chroma) % 6;
+	} else
+	if (max === g) {
+		hue = 2 + (b - r) / chroma;
+	} else {
+		hue = 4 + (r - g) / chroma + 4;
+	}
+
+	hue /= 6;
+	hue %= 1;
+
+	return [hue * 360, chroma * 100, grayscale * 100];
+};
+
+convert.hsl.hcg = function (hsl) {
+	var s = hsl[1] / 100;
+	var l = hsl[2] / 100;
+	var c = 1;
+	var f = 0;
+
+	if (l < 0.5) {
+		c = 2.0 * s * l;
+	} else {
+		c = 2.0 * s * (1.0 - l);
+	}
+
+	if (c < 1.0) {
+		f = (l - 0.5 * c) / (1.0 - c);
+	}
+
+	return [hsl[0], c * 100, f * 100];
+};
+
+convert.hsv.hcg = function (hsv) {
+	var s = hsv[1] / 100;
+	var v = hsv[2] / 100;
+
+	var c = s * v;
+	var f = 0;
+
+	if (c < 1.0) {
+		f = (v - c) / (1 - c);
+	}
+
+	return [hsv[0], c * 100, f * 100];
+};
+
+convert.hcg.rgb = function (hcg) {
+	var h = hcg[0] / 360;
+	var c = hcg[1] / 100;
+	var g = hcg[2] / 100;
+
+	if (c === 0.0) {
+		return [g * 255, g * 255, g * 255];
+	}
+
+	var pure = [0, 0, 0];
+	var hi = (h % 1) * 6;
+	var v = hi % 1;
+	var w = 1 - v;
+	var mg = 0;
+
+	switch (Math.floor(hi)) {
+		case 0:
+			pure[0] = 1; pure[1] = v; pure[2] = 0; break;
+		case 1:
+			pure[0] = w; pure[1] = 1; pure[2] = 0; break;
+		case 2:
+			pure[0] = 0; pure[1] = 1; pure[2] = v; break;
+		case 3:
+			pure[0] = 0; pure[1] = w; pure[2] = 1; break;
+		case 4:
+			pure[0] = v; pure[1] = 0; pure[2] = 1; break;
+		default:
+			pure[0] = 1; pure[1] = 0; pure[2] = w;
+	}
+
+	mg = (1.0 - c) * g;
+
+	return [
+		(c * pure[0] + mg) * 255,
+		(c * pure[1] + mg) * 255,
+		(c * pure[2] + mg) * 255
+	];
+};
+
+convert.hcg.hsv = function (hcg) {
+	var c = hcg[1] / 100;
+	var g = hcg[2] / 100;
+
+	var v = c + g * (1.0 - c);
+	var f = 0;
+
+	if (v > 0.0) {
+		f = c / v;
+	}
+
+	return [hcg[0], f * 100, v * 100];
+};
+
+convert.hcg.hsl = function (hcg) {
+	var c = hcg[1] / 100;
+	var g = hcg[2] / 100;
+
+	var l = g * (1.0 - c) + 0.5 * c;
+	var s = 0;
+
+	if (l > 0.0 && l < 0.5) {
+		s = c / (2 * l);
+	} else
+	if (l >= 0.5 && l < 1.0) {
+		s = c / (2 * (1 - l));
+	}
+
+	return [hcg[0], s * 100, l * 100];
+};
+
+convert.hcg.hwb = function (hcg) {
+	var c = hcg[1] / 100;
+	var g = hcg[2] / 100;
+	var v = c + g * (1.0 - c);
+	return [hcg[0], (v - c) * 100, (1 - v) * 100];
+};
+
+convert.hwb.hcg = function (hwb) {
+	var w = hwb[1] / 100;
+	var b = hwb[2] / 100;
+	var v = 1 - b;
+	var c = v - w;
+	var g = 0;
+
+	if (c < 1) {
+		g = (v - c) / (1 - c);
+	}
+
+	return [hwb[0], c * 100, g * 100];
+};
+
+convert.apple.rgb = function (apple) {
+	return [(apple[0] / 65535) * 255, (apple[1] / 65535) * 255, (apple[2] / 65535) * 255];
+};
+
+convert.rgb.apple = function (rgb) {
+	return [(rgb[0] / 255) * 65535, (rgb[1] / 255) * 65535, (rgb[2] / 255) * 65535];
+};
+
+convert.gray.rgb = function (args) {
+	return [args[0] / 100 * 255, args[0] / 100 * 255, args[0] / 100 * 255];
+};
+
+convert.gray.hsl = convert.gray.hsv = function (args) {
+	return [0, 0, args[0]];
+};
+
+convert.gray.hwb = function (gray) {
+	return [0, 100, gray[0]];
+};
+
+convert.gray.cmyk = function (gray) {
+	return [0, 0, 0, gray[0]];
+};
+
+convert.gray.lab = function (gray) {
+	return [gray[0], 0, 0];
+};
+
+convert.gray.hex = function (gray) {
+	var val = Math.round(gray[0] / 100 * 255) & 0xFF;
+	var integer = (val << 16) + (val << 8) + val;
+
+	var string = integer.toString(16).toUpperCase();
+	return '000000'.substring(string.length) + string;
+};
+
+convert.rgb.gray = function (rgb) {
+	var val = (rgb[0] + rgb[1] + rgb[2]) / 3;
+	return [val / 255 * 100];
+};
+
+
+/***/ }),
+
+/***/ 2356:
+/***/ (function(module, exports, __webpack_require__) {
+
+"use strict";
+
+
+Object.defineProperty(exports, "__esModule", {
+  value: true
+});
+exports.default = parseAndBuildMetadata;
+
+function t() {
+  const data = _interopRequireWildcard(__webpack_require__(2268));
+
+  t = function () {
+    return data;
+  };
+
+  return data;
+}
+
+function _parser() {
+  const data = __webpack_require__(3773);
+
+  _parser = function () {
+    return data;
+  };
+
+  return data;
+}
+
+function _codeFrame() {
+  const data = __webpack_require__(2415);
+
+  _codeFrame = function () {
+    return data;
+  };
+
+  return data;
+}
+
+function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = Object.defineProperty && Object.getOwnPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : {}; if (desc.get || desc.set) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } } newObj.default = obj; return newObj; } }
+
+const PATTERN = /^[_$A-Z0-9]+$/;
+
+function parseAndBuildMetadata(formatter, code, opts) {
+  const ast = parseWithCodeFrame(code, opts.parser);
+  const {
+    placeholderWhitelist,
+    placeholderPattern = PATTERN,
+    preserveComments
+  } = opts;
+  t().removePropertiesDeep(ast, {
+    preserveComments
+  });
+  formatter.validate(ast);
+  const placeholders = [];
+  const placeholderNames = new Set();
+  t().traverse(ast, placeholderVisitorHandler, {
+    placeholders,
+    placeholderNames,
+    placeholderWhitelist,
+    placeholderPattern
+  });
+  return {
+    ast,
+    placeholders,
+    placeholderNames
+  };
+}
+
+function placeholderVisitorHandler(node, ancestors, state) {
+  let name;
+
+  if (t().isIdentifier(node) || t().isJSXIdentifier(node)) {
+    name = node.name;
+  } else if (t().isStringLiteral(node)) {
+    name = node.value;
+  } else {
+    return;
+  }
+
+  if ((!state.placeholderPattern || !state.placeholderPattern.test(name)) && (!state.placeholderWhitelist || !state.placeholderWhitelist.has(name))) {
+    return;
+  }
+
+  ancestors = ancestors.slice();
+  const {
+    node: parent,
+    key
+  } = ancestors[ancestors.length - 1];
+  let type;
+
+  if (t().isStringLiteral(node)) {
+    type = "string";
+  } else if (t().isNewExpression(parent) && key === "arguments" || t().isCallExpression(parent) && key === "arguments" || t().isFunction(parent) && key === "params") {
+    type = "param";
+  } else if (t().isExpressionStatement(parent)) {
+    type = "statement";
+    ancestors = ancestors.slice(0, -1);
+  } else {
+    type = "other";
+  }
+
+  state.placeholders.push({
+    name,
+    type,
+    resolve: ast => resolveAncestors(ast, ancestors),
+    isDuplicate: state.placeholderNames.has(name)
+  });
+  state.placeholderNames.add(name);
+}
+
+function resolveAncestors(ast, ancestors) {
+  let parent = ast;
+
+  for (let i = 0; i < ancestors.length - 1; i++) {
+    const {
+      key,
+      index
+    } = ancestors[i];
+
+    if (index === undefined) {
+      parent = parent[key];
+    } else {
+      parent = parent[key][index];
+    }
+  }
+
+  const {
+    key,
+    index
+  } = ancestors[ancestors.length - 1];
+  return {
+    parent,
+    key,
+    index
+  };
+}
+
+function parseWithCodeFrame(code, parserOpts) {
+  parserOpts = Object.assign({
+    allowReturnOutsideFunction: true,
+    allowSuperOutsideMethod: true,
+    sourceType: "module"
+  }, parserOpts);
+
+  try {
+    return (0, _parser().parse)(code, parserOpts);
+  } catch (err) {
+    const loc = err.loc;
+
+    if (loc) {
+      err.message += "\n" + (0, _codeFrame().codeFrameColumns)(code, {
+        start: loc
+      });
+      err.code = "BABEL_TEMPLATE_PARSE_ERROR";
+    }
+
+    throw err;
+  }
+}
+
+/***/ }),
+
+/***/ 2357:
+/***/ (function(module, exports, __webpack_require__) {
+
+"use strict";
+
+
+Object.defineProperty(exports, "__esModule", {
+  value: true
+});
+exports.default = populatePlaceholders;
+
+function t() {
+  const data = _interopRequireWildcard(__webpack_require__(2268));
+
+  t = function () {
+    return data;
+  };
+
+  return data;
+}
+
+function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = Object.defineProperty && Object.getOwnPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : {}; if (desc.get || desc.set) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } } newObj.default = obj; return newObj; } }
+
+function populatePlaceholders(metadata, replacements) {
+  const ast = t().cloneNode(metadata.ast);
+
+  if (replacements) {
+    metadata.placeholders.forEach(placeholder => {
+      if (!Object.prototype.hasOwnProperty.call(replacements, placeholder.name)) {
+        const placeholderName = placeholder.name;
+        throw new Error(`Error: No substitution given for "${placeholderName}". If this is not meant to be a
+            placeholder you may want to consider passing one of the following options to @babel/template:
+            - { placeholderPattern: false, placeholderWhitelist: new Set(['${placeholderName}'])}
+            - { placeholderPattern: /^${placeholderName}$/ }`);
+      }
+    });
+    Object.keys(replacements).forEach(key => {
+      if (!metadata.placeholderNames.has(key)) {
+        throw new Error(`Unknown substitution "${key}" given`);
+      }
+    });
+  }
+
+  metadata.placeholders.slice().reverse().forEach(placeholder => {
+    try {
+      applyReplacement(placeholder, ast, replacements && replacements[placeholder.name] || null);
+    } catch (e) {
+      e.message = `@babel/template placeholder "${placeholder.name}": ${e.message}`;
+      throw e;
+    }
+  });
+  return ast;
+}
+
+function applyReplacement(placeholder, ast, replacement) {
+  if (placeholder.isDuplicate) {
+    if (Array.isArray(replacement)) {
+      replacement = replacement.map(node => t().cloneNode(node));
+    } else if (typeof replacement === "object") {
+      replacement = t().cloneNode(replacement);
+    }
+  }
+
+  const {
+    parent,
+    key,
+    index
+  } = placeholder.resolve(ast);
+
+  if (placeholder.type === "string") {
+    if (typeof replacement === "string") {
+      replacement = t().stringLiteral(replacement);
+    }
+
+    if (!replacement || !t().isStringLiteral(replacement)) {
+      throw new Error("Expected string substitution");
+    }
+  } else if (placeholder.type === "statement") {
+    if (index === undefined) {
+      if (!replacement) {
+        replacement = t().emptyStatement();
+      } else if (Array.isArray(replacement)) {
+        replacement = t().blockStatement(replacement);
+      } else if (typeof replacement === "string") {
+        replacement = t().expressionStatement(t().identifier(replacement));
+      } else if (!t().isStatement(replacement)) {
+        replacement = t().expressionStatement(replacement);
+      }
+    } else {
+      if (replacement && !Array.isArray(replacement)) {
+        if (typeof replacement === "string") {
+          replacement = t().identifier(replacement);
+        }
+
+        if (!t().isStatement(replacement)) {
+          replacement = t().expressionStatement(replacement);
+        }
+      }
+    }
+  } else if (placeholder.type === "param") {
+    if (typeof replacement === "string") {
+      replacement = t().identifier(replacement);
+    }
+
+    if (index === undefined) throw new Error("Assertion failure.");
+  } else {
+    if (typeof replacement === "string") {
+      replacement = t().identifier(replacement);
+    }
+
+    if (Array.isArray(replacement)) {
+      throw new Error("Cannot replace single expression with an array.");
+    }
+  }
+
+  if (index === undefined) {
+    t().validate(parent, key, replacement);
+    parent[key] = replacement;
+  } else {
+    const items = parent[key].slice();
+
+    if (placeholder.type === "statement" || placeholder.type === "param") {
+      if (replacement == null) {
+        items.splice(index, 1);
+      } else if (Array.isArray(replacement)) {
+        items.splice(index, 1, ...replacement);
+      } else {
+        items[index] = replacement;
+      }
+    } else {
+      items[index] = replacement;
+    }
+
+    t().validate(parent, key, items);
+    parent[key] = items;
+  }
+}
+
+/***/ }),
+
 /***/ 2365:
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
 
 
 Object.defineProperty(exports, "__esModule", {
   value: true
@@ -20600,16 +22078,819 @@ function tsPrintSignatureDeclarationBase
   this._parameters(parameters, node);
 
   this.token(")");
   this.print(node.typeAnnotation, node);
 }
 
 /***/ }),
 
+/***/ 2388:
+/***/ (function(module, exports, __webpack_require__) {
+
+var conversions = __webpack_require__(2355);
+var route = __webpack_require__(2390);
+
+var convert = {};
+
+var models = Object.keys(conversions);
+
+function wrapRaw(fn) {
+	var wrappedFn = function (args) {
+		if (args === undefined || args === null) {
+			return args;
+		}
+
+		if (arguments.length > 1) {
+			args = Array.prototype.slice.call(arguments);
+		}
+
+		return fn(args);
+	};
+
+	// preserve .conversion property if there is one
+	if ('conversion' in fn) {
+		wrappedFn.conversion = fn.conversion;
+	}
+
+	return wrappedFn;
+}
+
+function wrapRounded(fn) {
+	var wrappedFn = function (args) {
+		if (args === undefined || args === null) {
+			return args;
+		}
+
+		if (arguments.length > 1) {
+			args = Array.prototype.slice.call(arguments);
+		}
+
+		var result = fn(args);
+
+		// we're assuming the result is an array here.
+		// see notice in conversions.js; don't use box types
+		// in conversion functions.
+		if (typeof result === 'object') {
+			for (var len = result.length, i = 0; i < len; i++) {
+				result[i] = Math.round(result[i]);
+			}
+		}
+
+		return result;
+	};
+
+	// preserve .conversion property if there is one
+	if ('conversion' in fn) {
+		wrappedFn.conversion = fn.conversion;
+	}
+
+	return wrappedFn;
+}
+
+models.forEach(function (fromModel) {
+	convert[fromModel] = {};
+
+	Object.defineProperty(convert[fromModel], 'channels', {value: conversions[fromModel].channels});
+	Object.defineProperty(convert[fromModel], 'labels', {value: conversions[fromModel].labels});
+
+	var routes = route(fromModel);
+	var routeModels = Object.keys(routes);
+
+	routeModels.forEach(function (toModel) {
+		var fn = routes[toModel];
+
+		convert[fromModel][toModel] = wrapRounded(fn);
+		convert[fromModel][toModel].raw = wrapRaw(fn);
+	});
+});
+
+module.exports = convert;
+
+
+/***/ }),
+
+/***/ 2389:
+/***/ (function(module, exports) {
+
+module.exports = {
+	"aliceblue": [240, 248, 255],
+	"antiquewhite": [250, 235, 215],
+	"aqua": [0, 255, 255],
+	"aquamarine": [127, 255, 212],
+	"azure": [240, 255, 255],
+	"beige": [245, 245, 220],
+	"bisque": [255, 228, 196],
+	"black": [0, 0, 0],
+	"blanchedalmond": [255, 235, 205],
+	"blue": [0, 0, 255],
+	"blueviolet": [138, 43, 226],
+	"brown": [165, 42, 42],
+	"burlywood": [222, 184, 135],
+	"cadetblue": [95, 158, 160],
+	"chartreuse": [127, 255, 0],
+	"chocolate": [210, 105, 30],
+	"coral": [255, 127, 80],
+	"cornflowerblue": [100, 149, 237],
+	"cornsilk": [255, 248, 220],
+	"crimson": [220, 20, 60],
+	"cyan": [0, 255, 255],
+	"darkblue": [0, 0, 139],
+	"darkcyan": [0, 139, 139],
+	"darkgoldenrod": [184, 134, 11],
+	"darkgray": [169, 169, 169],
+	"darkgreen": [0, 100, 0],
+	"darkgrey": [169, 169, 169],
+	"darkkhaki": [189, 183, 107],
+	"darkmagenta": [139, 0, 139],
+	"darkolivegreen": [85, 107, 47],
+	"darkorange": [255, 140, 0],
+	"darkorchid": [153, 50, 204],
+	"darkred": [139, 0, 0],
+	"darksalmon": [233, 150, 122],
+	"darkseagreen": [143, 188, 143],
+	"darkslateblue": [72, 61, 139],
+	"darkslategray": [47, 79, 79],
+	"darkslategrey": [47, 79, 79],
+	"darkturquoise": [0, 206, 209],
+	"darkviolet": [148, 0, 211],
+	"deeppink": [255, 20, 147],
+	"deepskyblue": [0, 191, 255],
+	"dimgray": [105, 105, 105],
+	"dimgrey": [105, 105, 105],
+	"dodgerblue": [30, 144, 255],
+	"firebrick": [178, 34, 34],
+	"floralwhite": [255, 250, 240],
+	"forestgreen": [34, 139, 34],
+	"fuchsia": [255, 0, 255],
+	"gainsboro": [220, 220, 220],
+	"ghostwhite": [248, 248, 255],
+	"gold": [255, 215, 0],
+	"goldenrod": [218, 165, 32],
+	"gray": [128, 128, 128],
+	"green": [0, 128, 0],
+	"greenyellow": [173, 255, 47],
+	"grey": [128, 128, 128],
+	"honeydew": [240, 255, 240],
+	"hotpink": [255, 105, 180],
+	"indianred": [205, 92, 92],
+	"indigo": [75, 0, 130],
+	"ivory": [255, 255, 240],
+	"khaki": [240, 230, 140],
+	"lavender": [230, 230, 250],
+	"lavenderblush": [255, 240, 245],
+	"lawngreen": [124, 252, 0],
+	"lemonchiffon": [255, 250, 205],
+	"lightblue": [173, 216, 230],
+	"lightcoral": [240, 128, 128],
+	"lightcyan": [224, 255, 255],
+	"lightgoldenrodyellow": [250, 250, 210],
+	"lightgray": [211, 211, 211],
+	"lightgreen": [144, 238, 144],
+	"lightgrey": [211, 211, 211],
+	"lightpink": [255, 182, 193],
+	"lightsalmon": [255, 160, 122],
+	"lightseagreen": [32, 178, 170],
+	"lightskyblue": [135, 206, 250],
+	"lightslategray": [119, 136, 153],
+	"lightslategrey": [119, 136, 153],
+	"lightsteelblue": [176, 196, 222],
+	"lightyellow": [255, 255, 224],
+	"lime": [0, 255, 0],
+	"limegreen": [50, 205, 50],
+	"linen": [250, 240, 230],
+	"magenta": [255, 0, 255],
+	"maroon": [128, 0, 0],
+	"mediumaquamarine": [102, 205, 170],
+	"mediumblue": [0, 0, 205],
+	"mediumorchid": [186, 85, 211],
+	"mediumpurple": [147, 112, 219],
+	"mediumseagreen": [60, 179, 113],
+	"mediumslateblue": [123, 104, 238],
+	"mediumspringgreen": [0, 250, 154],
+	"mediumturquoise": [72, 209, 204],
+	"mediumvioletred": [199, 21, 133],
+	"midnightblue": [25, 25, 112],
+	"mintcream": [245, 255, 250],
+	"mistyrose": [255, 228, 225],
+	"moccasin": [255, 228, 181],
+	"navajowhite": [255, 222, 173],
+	"navy": [0, 0, 128],
+	"oldlace": [253, 245, 230],
+	"olive": [128, 128, 0],
+	"olivedrab": [107, 142, 35],
+	"orange": [255, 165, 0],
+	"orangered": [255, 69, 0],
+	"orchid": [218, 112, 214],
+	"palegoldenrod": [238, 232, 170],
+	"palegreen": [152, 251, 152],
+	"paleturquoise": [175, 238, 238],
+	"palevioletred": [219, 112, 147],
+	"papayawhip": [255, 239, 213],
+	"peachpuff": [255, 218, 185],
+	"peru": [205, 133, 63],
+	"pink": [255, 192, 203],
+	"plum": [221, 160, 221],
+	"powderblue": [176, 224, 230],
+	"purple": [128, 0, 128],
+	"rebeccapurple": [102, 51, 153],
+	"red": [255, 0, 0],
+	"rosybrown": [188, 143, 143],
+	"royalblue": [65, 105, 225],
+	"saddlebrown": [139, 69, 19],
+	"salmon": [250, 128, 114],
+	"sandybrown": [244, 164, 96],
+	"seagreen": [46, 139, 87],
+	"seashell": [255, 245, 238],
+	"sienna": [160, 82, 45],
+	"silver": [192, 192, 192],
+	"skyblue": [135, 206, 235],
+	"slateblue": [106, 90, 205],
+	"slategray": [112, 128, 144],
+	"slategrey": [112, 128, 144],
+	"snow": [255, 250, 250],
+	"springgreen": [0, 255, 127],
+	"steelblue": [70, 130, 180],
+	"tan": [210, 180, 140],
+	"teal": [0, 128, 128],
+	"thistle": [216, 191, 216],
+	"tomato": [255, 99, 71],
+	"turquoise": [64, 224, 208],
+	"violet": [238, 130, 238],
+	"wheat": [245, 222, 179],
+	"white": [255, 255, 255],
+	"whitesmoke": [245, 245, 245],
+	"yellow": [255, 255, 0],
+	"yellowgreen": [154, 205, 50]
+};
+
+/***/ }),
+
+/***/ 2390:
+/***/ (function(module, exports, __webpack_require__) {
+
+var conversions = __webpack_require__(2355);
+
+/*
+	this function routes a model to all other models.
+
+	all functions that are routed have a property `.conversion` attached
+	to the returned synthetic function. This property is an array
+	of strings, each with the steps in between the 'from' and 'to'
+	color models (inclusive).
+
+	conversions that are not possible simply are not included.
+*/
+
+function buildGraph() {
+	var graph = {};
+	// https://jsperf.com/object-keys-vs-for-in-with-closure/3
+	var models = Object.keys(conversions);
+
+	for (var len = models.length, i = 0; i < len; i++) {
+		graph[models[i]] = {
+			// http://jsperf.com/1-vs-infinity
+			// micro-opt, but this is simple.
+			distance: -1,
+			parent: null
+		};
+	}
+
+	return graph;
+}
+
+// https://en.wikipedia.org/wiki/Breadth-first_search
+function deriveBFS(fromModel) {
+	var graph = buildGraph();
+	var queue = [fromModel]; // unshift -> queue -> pop
+
+	graph[fromModel].distance = 0;
+
+	while (queue.length) {
+		var current = queue.pop();
+		var adjacents = Object.keys(conversions[current]);
+
+		for (var len = adjacents.length, i = 0; i < len; i++) {
+			var adjacent = adjacents[i];
+			var node = graph[adjacent];
+
+			if (node.distance === -1) {
+				node.distance = graph[current].distance + 1;
+				node.parent = current;
+				queue.unshift(adjacent);
+			}
+		}
+	}
+
+	return graph;
+}
+
+function link(from, to) {
+	return function (args) {
+		return to(from(args));
+	};
+}
+
+function wrapConversion(toModel, graph) {
+	var path = [graph[toModel].parent, toModel];
+	var fn = conversions[graph[toModel].parent][toModel];
+
+	var cur = graph[toModel].parent;
+	while (graph[cur].parent) {
+		path.unshift(graph[cur].parent);
+		fn = link(conversions[graph[cur].parent][cur], fn);
+		cur = graph[cur].parent;
+	}
+
+	fn.conversion = path;
+	return fn;
+}
+
+module.exports = function (fromModel) {
+	var graph = deriveBFS(fromModel);
+	var conversion = {};
+
+	var models = Object.keys(graph);
+	for (var len = models.length, i = 0; i < len; i++) {
+		var toModel = models[i];
+		var node = graph[toModel];
+
+		if (node.parent === null) {
+			// no possible conversion, or this node is the source model.
+			continue;
+		}
+
+		conversion[toModel] = wrapConversion(toModel, graph);
+	}
+
+	return conversion;
+};
+
+
+
+/***/ }),
+
+/***/ 2392:
+/***/ (function(module, exports, __webpack_require__) {
+
+"use strict";
+
+const TEMPLATE_REGEX = /(?:\\(u[a-f\d]{4}|x[a-f\d]{2}|.))|(?:\{(~)?(\w+(?:\([^)]*\))?(?:\.\w+(?:\([^)]*\))?)*)(?:[ \t]|(?=\r?\n)))|(\})|((?:.|[\r\n\f])+?)/gi;
+const STYLE_REGEX = /(?:^|\.)(\w+)(?:\(([^)]*)\))?/g;
+const STRING_REGEX = /^(['"])((?:\\.|(?!\1)[^\\])*)\1$/;
+const ESCAPE_REGEX = /\\(u[a-f\d]{4}|x[a-f\d]{2}|.)|([^\\])/gi;
+
+const ESCAPES = new Map([
+	['n', '\n'],
+	['r', '\r'],
+	['t', '\t'],
+	['b', '\b'],
+	['f', '\f'],
+	['v', '\v'],
+	['0', '\0'],
+	['\\', '\\'],
+	['e', '\u001B'],
+	['a', '\u0007']
+]);
+
+function unescape(c) {
+	if ((c[0] === 'u' && c.length === 5) || (c[0] === 'x' && c.length === 3)) {
+		return String.fromCharCode(parseInt(c.slice(1), 16));
+	}
+
+	return ESCAPES.get(c) || c;
+}
+
+function parseArguments(name, args) {
+	const results = [];
+	const chunks = args.trim().split(/\s*,\s*/g);
+	let matches;
+
+	for (const chunk of chunks) {
+		if (!isNaN(chunk)) {
+			results.push(Number(chunk));
+		} else if ((matches = chunk.match(STRING_REGEX))) {
+			results.push(matches[2].replace(ESCAPE_REGEX, (m, escape, chr) => escape ? unescape(escape) : chr));
+		} else {
+			throw new Error(`Invalid Chalk template style argument: ${chunk} (in style '${name}')`);
+		}
+	}
+
+	return results;
+}
+
+function parseStyle(style) {
+	STYLE_REGEX.lastIndex = 0;
+
+	const results = [];
+	let matches;
+
+	while ((matches = STYLE_REGEX.exec(style)) !== null) {
+		const name = matches[1];
+
+		if (matches[2]) {
+			const args = parseArguments(name, matches[2]);
+			results.push([name].concat(args));
+		} else {
+			results.push([name]);
+		}
+	}
+
+	return results;
+}
+
+function buildStyle(chalk, styles) {
+	const enabled = {};
+
+	for (const layer of styles) {
+		for (const style of layer.styles) {
+			enabled[style[0]] = layer.inverse ? null : style.slice(1);
+		}
+	}
+
+	let current = chalk;
+	for (const styleName of Object.keys(enabled)) {
+		if (Array.isArray(enabled[styleName])) {
+			if (!(styleName in current)) {
+				throw new Error(`Unknown Chalk style: ${styleName}`);
+			}
+
+			if (enabled[styleName].length > 0) {
+				current = current[styleName].apply(current, enabled[styleName]);
+			} else {
+				current = current[styleName];
+			}
+		}
+	}
+
+	return current;
+}
+
+module.exports = (chalk, tmp) => {
+	const styles = [];
+	const chunks = [];
+	let chunk = [];
+
+	// eslint-disable-next-line max-params
+	tmp.replace(TEMPLATE_REGEX, (m, escapeChar, inverse, style, close, chr) => {
+		if (escapeChar) {
+			chunk.push(unescape(escapeChar));
+		} else if (style) {
+			const str = chunk.join('');
+			chunk = [];
+			chunks.push(styles.length === 0 ? str : buildStyle(chalk, styles)(str));
+			styles.push({inverse, styles: parseStyle(style)});
+		} else if (close) {
+			if (styles.length === 0) {
+				throw new Error('Found extraneous } in Chalk template literal');
+			}
+
+			chunks.push(buildStyle(chalk, styles)(chunk.join('')));
+			chunk = [];
+			styles.pop();
+		} else {
+			chunk.push(chr);
+		}
+	});
+
+	chunks.push(chunk.join(''));
+
+	if (styles.length > 0) {
+		const errMsg = `Chalk template literal is missing ${styles.length} closing bracket${styles.length === 1 ? '' : 's'} (\`}\`)`;
+		throw new Error(errMsg);
+	}
+
+	return chunks.join('');
+};
+
+
+/***/ }),
+
+/***/ 2397:
+/***/ (function(module, exports, __webpack_require__) {
+
+"use strict";
+
+
+Object.defineProperty(exports, "__esModule", {
+  value: true
+});
+exports.default = exports.program = exports.expression = exports.statements = exports.statement = exports.smart = void 0;
+
+var formatters = _interopRequireWildcard(__webpack_require__(2398));
+
+var _builder = _interopRequireDefault(__webpack_require__(2399));
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = Object.defineProperty && Object.getOwnPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : {}; if (desc.get || desc.set) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } } newObj.default = obj; return newObj; } }
+
+const smart = (0, _builder.default)(formatters.smart);
+exports.smart = smart;
+const statement = (0, _builder.default)(formatters.statement);
+exports.statement = statement;
+const statements = (0, _builder.default)(formatters.statements);
+exports.statements = statements;
+const expression = (0, _builder.default)(formatters.expression);
+exports.expression = expression;
+const program = (0, _builder.default)(formatters.program);
+exports.program = program;
+
+var _default = Object.assign(smart.bind(undefined), {
+  smart,
+  statement,
+  statements,
+  expression,
+  program,
+  ast: smart.ast
+});
+
+exports.default = _default;
+
+/***/ }),
+
+/***/ 2398:
+/***/ (function(module, exports, __webpack_require__) {
+
+"use strict";
+
+
+Object.defineProperty(exports, "__esModule", {
+  value: true
+});
+exports.program = exports.expression = exports.statement = exports.statements = exports.smart = void 0;
+
+function makeStatementFormatter(fn) {
+  return {
+    code: str => `/* @babel/template */;\n${str}`,
+    validate: () => {},
+    unwrap: ast => {
+      return fn(ast.program.body.slice(1));
+    }
+  };
+}
+
+const smart = makeStatementFormatter(body => {
+  if (body.length > 1) {
+    return body;
+  } else {
+    return body[0];
+  }
+});
+exports.smart = smart;
+const statements = makeStatementFormatter(body => body);
+exports.statements = statements;
+const statement = makeStatementFormatter(body => {
+  if (body.length === 0) {
+    throw new Error("Found nothing to return.");
+  }
+
+  if (body.length > 1) {
+    throw new Error("Found multiple statements but wanted one");
+  }
+
+  return body[0];
+});
+exports.statement = statement;
+const expression = {
+  code: str => `(\n${str}\n)`,
+  validate: ({
+    program
+  }) => {
+    if (program.body.length > 1) {
+      throw new Error("Found multiple statements but wanted one");
+    }
+
+    const expression = program.body[0].expression;
+
+    if (expression.start === 0) {
+      throw new Error("Parse result included parens.");
+    }
+  },
+  unwrap: ast => ast.program.body[0].expression
+};
+exports.expression = expression;
+const program = {
+  code: str => str,
+  validate: () => {},
+  unwrap: ast => ast.program
+};
+exports.program = program;
+
+/***/ }),
+
+/***/ 2399:
+/***/ (function(module, exports, __webpack_require__) {
+
+"use strict";
+
+
+Object.defineProperty(exports, "__esModule", {
+  value: true
+});
+exports.default = createTemplateBuilder;
+
+var _options = __webpack_require__(2348);
+
+var _string = _interopRequireDefault(__webpack_require__(2400));
+
+var _literal = _interopRequireDefault(__webpack_require__(2402));
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+const NO_PLACEHOLDER = (0, _options.validate)({
+  placeholderPattern: false
+});
+
+function createTemplateBuilder(formatter, defaultOpts) {
+  const templateFnCache = new WeakMap();
+  const templateAstCache = new WeakMap();
+  const cachedOpts = defaultOpts || (0, _options.validate)(null);
+  return Object.assign((tpl, ...args) => {
+    if (typeof tpl === "string") {
+      if (args.length > 1) throw new Error("Unexpected extra params.");
+      return extendedTrace((0, _string.default)(formatter, tpl, (0, _options.merge)(cachedOpts, (0, _options.validate)(args[0]))));
+    } else if (Array.isArray(tpl)) {
+      let builder = templateFnCache.get(tpl);
+
+      if (!builder) {
+        builder = (0, _literal.default)(formatter, tpl, cachedOpts);
+        templateFnCache.set(tpl, builder);
+      }
+
+      return extendedTrace(builder(args));
+    } else if (typeof tpl === "object" && tpl) {
+      if (args.length > 0) throw new Error("Unexpected extra params.");
+      return createTemplateBuilder(formatter, (0, _options.merge)(cachedOpts, (0, _options.validate)(tpl)));
+    }
+
+    throw new Error(`Unexpected template param ${typeof tpl}`);
+  }, {
+    ast: (tpl, ...args) => {
+      if (typeof tpl === "string") {
+        if (args.length > 1) throw new Error("Unexpected extra params.");
+        return (0, _string.default)(formatter, tpl, (0, _options.merge)((0, _options.merge)(cachedOpts, (0, _options.validate)(args[0])), NO_PLACEHOLDER))();
+      } else if (Array.isArray(tpl)) {
+        let builder = templateAstCache.get(tpl);
+
+        if (!builder) {
+          builder = (0, _literal.default)(formatter, tpl, (0, _options.merge)(cachedOpts, NO_PLACEHOLDER));
+          templateAstCache.set(tpl, builder);
+        }
+
+        return builder(args)();
+      }
+
+      throw new Error(`Unexpected template param ${typeof tpl}`);
+    }
+  });
+}
+
+function extendedTrace(fn) {
+  let rootStack = "";
+
+  try {
+    throw new Error();
+  } catch (error) {
+    if (error.stack) {
+      rootStack = error.stack.split("\n").slice(3).join("\n");
+    }
+  }
+
+  return arg => {
+    try {
+      return fn(arg);
+    } catch (err) {
+      err.stack += `\n    =============\n${rootStack}`;
+      throw err;
+    }
+  };
+}
+
+/***/ }),
+
+/***/ 2400:
+/***/ (function(module, exports, __webpack_require__) {
+
+"use strict";
+
+
+Object.defineProperty(exports, "__esModule", {
+  value: true
+});
+exports.default = stringTemplate;
+
+var _options = __webpack_require__(2348);
+
+var _parse = _interopRequireDefault(__webpack_require__(2356));
+
+var _populate = _interopRequireDefault(__webpack_require__(2357));
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+function stringTemplate(formatter, code, opts) {
+  code = formatter.code(code);
+  let metadata;
+  return arg => {
+    const replacements = (0, _options.normalizeReplacements)(arg);
+    if (!metadata) metadata = (0, _parse.default)(formatter, code, opts);
+    return formatter.unwrap((0, _populate.default)(metadata, replacements));
+  };
+}
+
+/***/ }),
+
+/***/ 2402:
+/***/ (function(module, exports, __webpack_require__) {
+
+"use strict";
+
+
+Object.defineProperty(exports, "__esModule", {
+  value: true
+});
+exports.default = literalTemplate;
+
+var _options = __webpack_require__(2348);
+
+var _parse = _interopRequireDefault(__webpack_require__(2356));
+
+var _populate = _interopRequireDefault(__webpack_require__(2357));
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+function literalTemplate(formatter, tpl, opts) {
+  const {
+    metadata,
+    names
+  } = buildLiteralData(formatter, tpl, opts);
+  return arg => {
+    const defaultReplacements = arg.reduce((acc, replacement, i) => {
+      acc[names[i]] = replacement;
+      return acc;
+    }, {});
+    return arg => {
+      const replacements = (0, _options.normalizeReplacements)(arg);
+
+      if (replacements) {
+        Object.keys(replacements).forEach(key => {
+          if (Object.prototype.hasOwnProperty.call(defaultReplacements, key)) {
+            throw new Error("Unexpected replacement overlap.");
+          }
+        });
+      }
+
+      return formatter.unwrap((0, _populate.default)(metadata, replacements ? Object.assign(replacements, defaultReplacements) : defaultReplacements));
+    };
+  };
+}
+
+function buildLiteralData(formatter, tpl, opts) {
+  let names;
+  let nameSet;
+  let metadata;
+  let prefix = "";
+
+  do {
+    prefix += "$";
+    const result = buildTemplateCode(tpl, prefix);
+    names = result.names;
+    nameSet = new Set(names);
+    metadata = (0, _parse.default)(formatter, formatter.code(result.code), {
+      parser: opts.parser,
+      placeholderWhitelist: new Set(result.names.concat(opts.placeholderWhitelist ? Array.from(opts.placeholderWhitelist) : [])),
+      placeholderPattern: opts.placeholderPattern,
+      preserveComments: opts.preserveComments
+    });
+  } while (metadata.placeholders.some(placeholder => placeholder.isDuplicate && nameSet.has(placeholder.name)));
+
+  return {
+    metadata,
+    names
+  };
+}
+
+function buildTemplateCode(tpl, prefix) {
+  const names = [];
+  let code = tpl[0];
+
+  for (let i = 1; i < tpl.length; i++) {
+    const value = `${prefix}${i - 1}`;
+    names.push(value);
+    code += value + tpl[i];
+  }
+
+  return {
+    names,
+    code
+  };
+}
+
+/***/ }),
+
 /***/ 2413:
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
 
 
 Object.defineProperty(exports, "__esModule", {
   value: true
@@ -21419,16 +23700,197 @@ function stripModuleScope(rootScope) {
   rootLexicalScope.children = moduleScope.children;
   rootLexicalScope.children.forEach(child => {
     child.parent = rootLexicalScope;
   });
 }
 
 /***/ }),
 
+/***/ 2415:
+/***/ (function(module, exports, __webpack_require__) {
+
+"use strict";
+/* WEBPACK VAR INJECTION */(function(process) {
+
+Object.defineProperty(exports, "__esModule", {
+  value: true
+});
+exports.codeFrameColumns = codeFrameColumns;
+exports.default = _default;
+
+function _highlight() {
+  const data = _interopRequireWildcard(__webpack_require__(3779));
+
+  _highlight = function () {
+    return data;
+  };
+
+  return data;
+}
+
+function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = Object.defineProperty && Object.getOwnPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : {}; if (desc.get || desc.set) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } } newObj.default = obj; return newObj; } }
+
+let deprecationWarningShown = false;
+
+function getDefs(chalk) {
+  return {
+    gutter: chalk.grey,
+    marker: chalk.red.bold,
+    message: chalk.red.bold
+  };
+}
+
+const NEWLINE = /\r\n|[\n\r\u2028\u2029]/;
+
+function getMarkerLines(loc, source, opts) {
+  const startLoc = Object.assign({
+    column: 0,
+    line: -1
+  }, loc.start);
+  const endLoc = Object.assign({}, startLoc, loc.end);
+  const {
+    linesAbove = 2,
+    linesBelow = 3
+  } = opts || {};
+  const startLine = startLoc.line;
+  const startColumn = startLoc.column;
+  const endLine = endLoc.line;
+  const endColumn = endLoc.column;
+  let start = Math.max(startLine - (linesAbove + 1), 0);
+  let end = Math.min(source.length, endLine + linesBelow);
+
+  if (startLine === -1) {
+    start = 0;
+  }
+
+  if (endLine === -1) {
+    end = source.length;
+  }
+
+  const lineDiff = endLine - startLine;
+  const markerLines = {};
+
+  if (lineDiff) {
+    for (let i = 0; i <= lineDiff; i++) {
+      const lineNumber = i + startLine;
+
+      if (!startColumn) {
+        markerLines[lineNumber] = true;
+      } else if (i === 0) {
+        const sourceLength = source[lineNumber - 1].length;
+        markerLines[lineNumber] = [startColumn, sourceLength - startColumn];
+      } else if (i === lineDiff) {
+        markerLines[lineNumber] = [0, endColumn];
+      } else {
+        const sourceLength = source[lineNumber - i].length;
+        markerLines[lineNumber] = [0, sourceLength];
+      }
+    }
+  } else {
+    if (startColumn === endColumn) {
+      if (startColumn) {
+        markerLines[startLine] = [startColumn, 0];
+      } else {
+        markerLines[startLine] = true;
+      }
+    } else {
+      markerLines[startLine] = [startColumn, endColumn - startColumn];
+    }
+  }
+
+  return {
+    start,
+    end,
+    markerLines
+  };
+}
+
+function codeFrameColumns(rawLines, loc, opts = {}) {
+  const highlighted = (opts.highlightCode || opts.forceColor) && (0, _highlight().shouldHighlight)(opts);
+  const chalk = (0, _highlight().getChalk)(opts);
+  const defs = getDefs(chalk);
+
+  const maybeHighlight = (chalkFn, string) => {
+    return highlighted ? chalkFn(string) : string;
+  };
+
+  if (highlighted) rawLines = (0, _highlight().default)(rawLines, opts);
+  const lines = rawLines.split(NEWLINE);
+  const {
+    start,
+    end,
+    markerLines
+  } = getMarkerLines(loc, lines, opts);
+  const hasColumns = loc.start && typeof loc.start.column === "number";
+  const numberMaxWidth = String(end).length;
+  let frame = lines.slice(start, end).map((line, index) => {
+    const number = start + 1 + index;
+    const paddedNumber = ` ${number}`.slice(-numberMaxWidth);
+    const gutter = ` ${paddedNumber} | `;
+    const hasMarker = markerLines[number];
+    const lastMarkerLine = !markerLines[number + 1];
+
+    if (hasMarker) {
+      let markerLine = "";
+
+      if (Array.isArray(hasMarker)) {
+        const markerSpacing = line.slice(0, Math.max(hasMarker[0] - 1, 0)).replace(/[^\t]/g, " ");
+        const numberOfMarkers = hasMarker[1] || 1;
+        markerLine = ["\n ", maybeHighlight(defs.gutter, gutter.replace(/\d/g, " ")), markerSpacing, maybeHighlight(defs.marker, "^").repeat(numberOfMarkers)].join("");
+
+        if (lastMarkerLine && opts.message) {
+          markerLine += " " + maybeHighlight(defs.message, opts.message);
+        }
+      }
+
+      return [maybeHighlight(defs.marker, ">"), maybeHighlight(defs.gutter, gutter), line, markerLine].join("");
+    } else {
+      return ` ${maybeHighlight(defs.gutter, gutter)}${line}`;
+    }
+  }).join("\n");
+
+  if (opts.message && !hasColumns) {
+    frame = `${" ".repeat(numberMaxWidth + 1)}${opts.message}\n${frame}`;
+  }
+
+  if (highlighted) {
+    return chalk.reset(frame);
+  } else {
+    return frame;
+  }
+}
+
+function _default(rawLines, lineNumber, colNumber, opts = {}) {
+  if (!deprecationWarningShown) {
+    deprecationWarningShown = true;
+    const message = "Passing lineNumber and colNumber is deprecated to @babel/code-frame. Please use `codeFrameColumns`.";
+
+    if (process.emitWarning) {
+      process.emitWarning(message, "DeprecationWarning");
+    } else {
+      const deprecationError = new Error(message);
+      deprecationError.name = "DeprecationWarning";
+      console.warn(new Error(message));
+    }
+  }
+
+  colNumber = Math.max(colNumber, 0);
+  const location = {
+    start: {
+      column: colNumber,
+      line: lineNumber
+    }
+  };
+  return codeFrameColumns(rawLines, location, opts);
+}
+/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(120)))
+
+/***/ }),
+
 /***/ 248:
 /***/ (function(module, exports, __webpack_require__) {
 
 (function(){
   var crypt = __webpack_require__(249),
       utf8 = __webpack_require__(250).utf8,
       isBuffer = __webpack_require__(251),
       bin = __webpack_require__(250).bin,
@@ -23024,17 +25486,17 @@ function getFirstExpression(ast) {
   return statements[0].expression;
 }
 
 function locationKey(start) {
   return `${start.line}:${start.column}`;
 }
 
 function mapOriginalExpression(expression, mappings) {
-  const ast = (0, _ast.parseScript)(expression);
+  const ast = (0, _ast.parseScript)(expression, { allowAwaitOutsideFunction: true });
   const scopes = (0, _getScopes.buildScopeList)(ast, "");
 
   const nodes = new Map();
 
   const replacements = new Map();
 
   // The ref-only global bindings are the ones that are accessed, but not
   // declared anywhere in the parsed code, meaning they are either global,
@@ -23464,92 +25926,98 @@ exports.default = mapExpression;
 var _mapOriginalExpression = __webpack_require__(3613);
 
 var _mapOriginalExpression2 = _interopRequireDefault(_mapOriginalExpression);
 
 var _mapBindings = __webpack_require__(3756);
 
 var _mapBindings2 = _interopRequireDefault(_mapBindings);
 
-function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
-
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at <http://mozilla.org/MPL/2.0/>. */
-
-function mapExpression(expression, mappings, bindings, shouldMapBindings = true) {
-  let originalExpression = expression;
-  if (mappings) {
-    originalExpression = (0, _mapOriginalExpression2.default)(expression, mappings);
-  }
-
-  let safeExpression = originalExpression;
-  if (shouldMapBindings) {
-    safeExpression = (0, _mapBindings2.default)(originalExpression, bindings);
-  }
-
-  return safeExpression;
-}
+var _mapAwaitExpression = __webpack_require__(3778);
+
+var _mapAwaitExpression2 = _interopRequireDefault(_mapAwaitExpression);
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+function mapExpression(expression, mappings, bindings, shouldMapBindings = true, shouldMapAwait = true) {
+  try {
+    if (mappings) {
+      expression = (0, _mapOriginalExpression2.default)(expression, mappings);
+    }
+
+    if (shouldMapBindings) {
+      expression = (0, _mapBindings2.default)(expression, bindings);
+    }
+
+    if (shouldMapAwait) {
+      expression = (0, _mapAwaitExpression2.default)(expression);
+    }
+  } catch (e) {
+    console.log(e);
+  }
+
+  return expression;
+} /* This Source Code Form is subject to the terms of the Mozilla Public
+   * License, v. 2.0. If a copy of the MPL was not distributed with this
+   * file, You can obtain one at <http://mozilla.org/MPL/2.0/>. */
 
 /***/ }),
 
 /***/ 3756:
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
 
 
 Object.defineProperty(exports, "__esModule", {
   value: true
 });
 exports.default = mapExpressionBindings;
 
 var _ast = __webpack_require__(1375);
 
+var _helpers = __webpack_require__(1411);
+
 var _generator = __webpack_require__(2365);
 
 var _generator2 = _interopRequireDefault(_generator);
 
 var _types = __webpack_require__(2268);
 
 var t = _interopRequireWildcard(_types);
 
 function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } }
 
 function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
 
 // translates new bindings `var a = 3` into `self.a = 3`
 // and existing bindings `var a = 3` into `a = 3` for re-assignments
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at <http://mozilla.org/MPL/2.0/>. */
+
 function globalizeDeclaration(node, bindings) {
   return node.declarations.map(declaration => {
     const identifier = bindings.includes(declaration.id.name) ? declaration.id : t.memberExpression(t.identifier("self"), declaration.id);
 
     return t.expressionStatement(t.assignmentExpression("=", identifier, declaration.init));
   });
 }
 
 // translates new bindings `a = 3` into `self.a = 3`
 // and keeps assignments the same for existing bindings.
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at <http://mozilla.org/MPL/2.0/>. */
-
 function globalizeAssignment(node, bindings) {
   if (bindings.includes(node.left.name)) {
     return node;
   }
 
   const identifier = t.memberExpression(t.identifier("self"), node.left);
   return t.assignmentExpression(node.operator, identifier, node.right);
 }
 
-function isTopLevel(ancestors) {
-  return ancestors.filter(ancestor => ancestor.key == "body").length == 1;
-}
-
 function replaceNode(ancestors, node) {
   const parent = ancestors[ancestors.length - 1];
 
   if (typeof parent.index === "number") {
     if (Array.isArray(node)) {
       parent.node[parent.key].splice(parent.index, 1, ...node);
     } else {
       parent.node[parent.key][parent.index] = node;
@@ -23559,27 +26027,27 @@ function replaceNode(ancestors, node) {
   }
 }
 
 function hasDestructuring(node) {
   return node.declarations.some(declaration => t.isPattern(declaration.id));
 }
 
 function mapExpressionBindings(expression, bindings = []) {
-  const ast = (0, _ast.parseScript)(expression);
+  const ast = (0, _ast.parseScript)(expression, { allowAwaitOutsideFunction: true });
   let shouldUpdate = true;
   t.traverse(ast, (node, ancestors) => {
     const parent = ancestors[ancestors.length - 1];
 
     if (t.isWithStatement(node)) {
       shouldUpdate = false;
       return;
     }
 
-    if (!isTopLevel(ancestors)) {
+    if (!(0, _helpers.isTopLevel)(ancestors)) {
       return;
     }
 
     if (t.isAssignmentExpression(node)) {
       if (t.isIdentifier(node.left)) {
         const newNode = globalizeAssignment(node, bindings);
         return replaceNode(ancestors, newNode);
       }
@@ -44253,16 +46721,226 @@ function getParserClass(pluginsFromOptio
 
 exports.parse = parse;
 exports.parseExpression = parseExpression;
 exports.tokTypes = types;
 
 
 /***/ }),
 
+/***/ 3778:
+/***/ (function(module, exports, __webpack_require__) {
+
+"use strict";
+
+
+Object.defineProperty(exports, "__esModule", {
+  value: true
+});
+exports.default = handleTopLevelAwait;
+
+var _template = __webpack_require__(2397);
+
+var _template2 = _interopRequireDefault(_template);
+
+var _generator = __webpack_require__(2365);
+
+var _generator2 = _interopRequireDefault(_generator);
+
+var _types = __webpack_require__(2268);
+
+var t = _interopRequireWildcard(_types);
+
+var _ast = __webpack_require__(1375);
+
+var _helpers = __webpack_require__(1411);
+
+function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } }
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+function hasTopLevelAwait(expression) {
+  const ast = (0, _ast.parse)(expression, { allowAwaitOutsideFunction: true });
+  const hasAwait = (0, _ast.hasNode)(ast, (node, ancestors, b) => t.isAwaitExpression(node) && (0, _helpers.isTopLevel)(ancestors));
+
+  return hasAwait && ast;
+} /* This Source Code Form is subject to the terms of the Mozilla Public
+   * License, v. 2.0. If a copy of the MPL was not distributed with this
+   * file, You can obtain one at <http://mozilla.org/MPL/2.0/>. */
+
+function wrapExpression(ast) {
+  const statements = ast.program.body;
+  const lastStatement = statements[statements.length - 1];
+  const body = statements.slice(0, -1).concat(t.returnStatement(lastStatement.expression));
+
+  const newAst = t.arrowFunctionExpression([], t.blockStatement(body), true);
+  return (0, _generator2.default)(newAst).code;
+}
+
+function handleTopLevelAwait(expression) {
+  const ast = hasTopLevelAwait(expression);
+  if (ast) {
+    const func = wrapExpression(ast);
+    return (0, _generator2.default)(_template2.default.ast(`(${func})().then(r => console.log(r));`)).code;
+  }
+
+  return expression;
+}
+
+/***/ }),
+
+/***/ 3779:
+/***/ (function(module, exports, __webpack_require__) {
+
+"use strict";
+
+
+Object.defineProperty(exports, "__esModule", {
+  value: true
+});
+exports.shouldHighlight = shouldHighlight;
+exports.getChalk = getChalk;
+exports.default = highlight;
+
+function _jsTokens() {
+  const data = _interopRequireWildcard(__webpack_require__(630));
+
+  _jsTokens = function () {
+    return data;
+  };
+
+  return data;
+}
+
+function _esutils() {
+  const data = _interopRequireDefault(__webpack_require__(530));
+
+  _esutils = function () {
+    return data;
+  };
+
+  return data;
+}
+
+function _chalk() {
+  const data = _interopRequireDefault(__webpack_require__(631));
+
+  _chalk = function () {
+    return data;
+  };
+
+  return data;
+}
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = Object.defineProperty && Object.getOwnPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : {}; if (desc.get || desc.set) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } } newObj.default = obj; return newObj; } }
+
+function getDefs(chalk) {
+  return {
+    keyword: chalk.cyan,
+    capitalized: chalk.yellow,
+    jsx_tag: chalk.yellow,
+    punctuator: chalk.yellow,
+    number: chalk.magenta,
+    string: chalk.green,
+    regex: chalk.magenta,
+    comment: chalk.grey,
+    invalid: chalk.white.bgRed.bold
+  };
+}
+
+const NEWLINE = /\r\n|[\n\r\u2028\u2029]/;
+const JSX_TAG = /^[a-z][\w-]*$/i;
+const BRACKET = /^[()[\]{}]$/;
+
+function getTokenType(match) {
+  const [offset, text] = match.slice(-2);
+  const token = (0, _jsTokens().matchToToken)(match);
+
+  if (token.type === "name") {
+    if (_esutils().default.keyword.isReservedWordES6(token.value)) {
+      return "keyword";
+    }
+
+    if (JSX_TAG.test(token.value) && (text[offset - 1] === "<" || text.substr(offset - 2, 2) == "</")) {
+      return "jsx_tag";
+    }
+
+    if (token.value[0] !== token.value[0].toLowerCase()) {
+      return "capitalized";
+    }
+  }
+
+  if (token.type === "punctuator" && BRACKET.test(token.value)) {
+    return "bracket";
+  }
+
+  if (token.type === "invalid" && (token.value === "@" || token.value === "#")) {
+    return "punctuator";
+  }
+
+  return token.type;
+}
+
+function highlightTokens(defs, text) {
+  return text.replace(_jsTokens().default, function (...args) {
+    const type = getTokenType(args);
+    const colorize = defs[type];
+
+    if (colorize) {
+      return args[0].split(NEWLINE).map(str => colorize(str)).join("\n");
+    } else {
+      return args[0];
+    }
+  });
+}
+
+function shouldHighlight(options) {
+  return _chalk().default.supportsColor || options.forceColor;
+}
+
+function getChalk(options) {
+  let chalk = _chalk().default;
+
+  if (options.forceColor) {
+    chalk = new (_chalk().default.constructor)({
+      enabled: true,
+      level: 1
+    });
+  }
+
+  return chalk;
+}
+
+function highlight(code, options = {}) {
+  if (shouldHighlight(options)) {
+    const chalk = getChalk(options);
+    const defs = getDefs(chalk);
+    return highlightTokens(defs, code);
+  } else {
+    return code;
+  }
+}
+
+/***/ }),
+
+/***/ 3780:
+/***/ (function(module, exports, __webpack_require__) {
+
+"use strict";
+
+module.exports = {
+	stdout: false,
+	stderr: false
+};
+
+
+/***/ }),
+
 /***/ 398:
 /***/ (function(module, exports, __webpack_require__) {
 
 /* WEBPACK VAR INJECTION */(function(module) {var root = __webpack_require__(8);
 
 /** Detect free variable `exports`. */
 var freeExports = typeof exports == 'object' && exports && !exports.nodeType && exports;
 
@@ -46289,16 +48967,476 @@ function baseRepeat(string, n) {
   return result;
 }
 
 module.exports = baseRepeat;
 
 
 /***/ }),
 
+/***/ 630:
+/***/ (function(module, exports) {
+
+// Copyright 2014, 2015, 2016, 2017 Simon Lydell
+// License: MIT. (See LICENSE.)
+
+Object.defineProperty(exports, "__esModule", {
+  value: true
+})
+
+// This regex comes from regex.coffee, and is inserted here by generate-index.js
+// (run `npm run build`).
+exports.default = /((['"])(?:(?!\2|\\).|\\(?:\r\n|[\s\S]))*(\2)?|`(?:[^`\\$]|\\[\s\S]|\$(?!\{)|\$\{(?:[^{}]|\{[^}]*\}?)*\}?)*(`)?)|(\/\/.*)|(\/\*(?:[^*]|\*(?!\/))*(\*\/)?)|(\/(?!\*)(?:\[(?:(?![\]\\]).|\\.)*\]|(?![\/\]\\]).|\\.)+\/(?:(?!\s*(?:\b|[\u0080-\uFFFF$\\'"~({]|[+\-!](?!=)|\.?\d))|[gmiyu]{1,5}\b(?![\u0080-\uFFFF$\\]|\s*(?:[+\-*%&|^<>!=?({]|\/(?![\/*])))))|(0[xX][\da-fA-F]+|0[oO][0-7]+|0[bB][01]+|(?:\d*\.\d+|\d+\.?)(?:[eE][+-]?\d+)?)|((?!\d)(?:(?!\s)[$\w\u0080-\uFFFF]|\\u[\da-fA-F]{4}|\\u\{[\da-fA-F]+\})+)|(--|\+\+|&&|\|\||=>|\.{3}|(?:[+\-\/%&|^]|\*{1,2}|<{1,2}|>{1,3}|!=?|={1,2})=?|[?~.,:;[\](){}])|(\s+)|(^$|[\s\S])/g
+
+exports.matchToToken = function(match) {
+  var token = {type: "invalid", value: match[0]}
+       if (match[ 1]) token.type = "string" , token.closed = !!(match[3] || match[4])
+  else if (match[ 5]) token.type = "comment"
+  else if (match[ 6]) token.type = "comment", token.closed = !!match[7]
+  else if (match[ 8]) token.type = "regex"
+  else if (match[ 9]) token.type = "number"
+  else if (match[10]) token.type = "name"
+  else if (match[11]) token.type = "punctuator"
+  else if (match[12]) token.type = "whitespace"
+  return token
+}
+
+
+/***/ }),
+
+/***/ 631:
+/***/ (function(module, exports, __webpack_require__) {
+
+"use strict";
+/* WEBPACK VAR INJECTION */(function(process) {
+const escapeStringRegexp = __webpack_require__(632);
+const ansiStyles = __webpack_require__(633);
+const stdoutColor = __webpack_require__(3780).stdout;
+
+const template = __webpack_require__(2392);
+
+const isSimpleWindowsTerm = process.platform === 'win32' && !(Object({"NODE_ENV":"production","TARGET":"firefox-panel"}).TERM || '').toLowerCase().startsWith('xterm');
+
+// `supportsColor.level` → `ansiStyles.color[name]` mapping
+const levelMapping = ['ansi', 'ansi', 'ansi256', 'ansi16m'];
+
+// `color-convert` models to exclude from the Chalk API due to conflicts and such
+const skipModels = new Set(['gray']);
+
+const styles = Object.create(null);
+
+function applyOptions(obj, options) {
+	options = options || {};
+
+	// Detect level if not set manually
+	const scLevel = stdoutColor ? stdoutColor.level : 0;
+	obj.level = options.level === undefined ? scLevel : options.level;
+	obj.enabled = 'enabled' in options ? options.enabled : obj.level > 0;
+}
+
+function Chalk(options) {
+	// We check for this.template here since calling `chalk.constructor()`
+	// by itself will have a `this` of a previously constructed chalk object
+	if (!this || !(this instanceof Chalk) || this.template) {
+		const chalk = {};
+		applyOptions(chalk, options);
+
+		chalk.template = function () {
+			const args = [].slice.call(arguments);
+			return chalkTag.apply(null, [chalk.template].concat(args));
+		};
+
+		Object.setPrototypeOf(chalk, Chalk.prototype);
+		Object.setPrototypeOf(chalk.template, chalk);
+
+		chalk.template.constructor = Chalk;
+
+		return chalk.template;
+	}
+
+	applyOptions(this, options);
+}
+
+// Use bright blue on Windows as the normal blue color is illegible
+if (isSimpleWindowsTerm) {
+	ansiStyles.blue.open = '\u001B[94m';
+}
+
+for (const key of Object.keys(ansiStyles)) {
+	ansiStyles[key].closeRe = new RegExp(escapeStringRegexp(ansiStyles[key].close), 'g');
+
+	styles[key] = {
+		get() {
+			const codes = ansiStyles[key];
+			return build.call(this, this._styles ? this._styles.concat(codes) : [codes], this._empty, key);
+		}
+	};
+}
+
+styles.visible = {
+	get() {
+		return build.call(this, this._styles || [], true, 'visible');
+	}
+};
+
+ansiStyles.color.closeRe = new RegExp(escapeStringRegexp(ansiStyles.color.close), 'g');
+for (const model of Object.keys(ansiStyles.color.ansi)) {
+	if (skipModels.has(model)) {
+		continue;
+	}
+
+	styles[model] = {
+		get() {
+			const level = this.level;
+			return function () {
+				const open = ansiStyles.color[levelMapping[level]][model].apply(null, arguments);
+				const codes = {
+					open,
+					close: ansiStyles.color.close,
+					closeRe: ansiStyles.color.closeRe
+				};
+				return build.call(this, this._styles ? this._styles.concat(codes) : [codes], this._empty, model);
+			};
+		}
+	};
+}
+
+ansiStyles.bgColor.closeRe = new RegExp(escapeStringRegexp(ansiStyles.bgColor.close), 'g');
+for (const model of Object.keys(ansiStyles.bgColor.ansi)) {
+	if (skipModels.has(model)) {
+		continue;
+	}
+
+	const bgModel = 'bg' + model[0].toUpperCase() + model.slice(1);
+	styles[bgModel] = {
+		get() {
+			const level = this.level;
+			return function () {
+				const open = ansiStyles.bgColor[levelMapping[level]][model].apply(null, arguments);
+				const codes = {
+					open,
+					close: ansiStyles.bgColor.close,
+					closeRe: ansiStyles.bgColor.closeRe
+				};
+				return build.call(this, this._styles ? this._styles.concat(codes) : [codes], this._empty, model);
+			};
+		}
+	};
+}
+
+const proto = Object.defineProperties(() => {}, styles);
+
+function build(_styles, _empty, key) {
+	const builder = function () {
+		return applyStyle.apply(builder, arguments);
+	};
+
+	builder._styles = _styles;
+	builder._empty = _empty;
+
+	const self = this;
+
+	Object.defineProperty(builder, 'level', {
+		enumerable: true,
+		get() {
+			return self.level;
+		},
+		set(level) {
+			self.level = level;
+		}
+	});
+
+	Object.defineProperty(builder, 'enabled', {
+		enumerable: true,
+		get() {
+			return self.enabled;
+		},
+		set(enabled) {
+			self.enabled = enabled;
+		}
+	});
+
+	// See below for fix regarding invisible grey/dim combination on Windows
+	builder.hasGrey = this.hasGrey || key === 'gray' || key === 'grey';
+
+	// `__proto__` is used because we must return a function, but there is
+	// no way to create a function with a different prototype
+	builder.__proto__ = proto; // eslint-disable-line no-proto
+
+	return builder;
+}
+
+function applyStyle() {
+	// Support varags, but simply cast to string in case there's only one arg
+	const args = arguments;
+	const argsLen = args.length;
+	let str = String(arguments[0]);
+
+	if (argsLen === 0) {
+		return '';
+	}
+
+	if (argsLen > 1) {
+		// Don't slice `arguments`, it prevents V8 optimizations
+		for (let a = 1; a < argsLen; a++) {
+			str += ' ' + args[a];
+		}
+	}
+
+	if (!this.enabled || this.level <= 0 || !str) {
+		return this._empty ? '' : str;
+	}
+
+	// Turns out that on Windows dimmed gray text becomes invisible in cmd.exe,
+	// see https://github.com/chalk/chalk/issues/58
+	// If we're on Windows and we're dealing with a gray color, temporarily make 'dim' a noop.
+	const originalDim = ansiStyles.dim.open;
+	if (isSimpleWindowsTerm && this.hasGrey) {
+		ansiStyles.dim.open = '';
+	}
+
+	for (const code of this._styles.slice().reverse()) {
+		// Replace any instances already present with a re-opening code
+		// otherwise only the part of the string until said closing code
+		// will be colored, and the rest will simply be 'plain'.
+		str = code.open + str.replace(code.closeRe, code.open) + code.close;
+
+		// Close the styling before a linebreak and reopen
+		// after next line to fix a bleed issue on macOS
+		// https://github.com/chalk/chalk/pull/92
+		str = str.replace(/\r?\n/g, `${code.close}$&${code.open}`);
+	}
+
+	// Reset the original `dim` if we changed it to work around the Windows dimmed gray issue
+	ansiStyles.dim.open = originalDim;
+
+	return str;
+}
+
+function chalkTag(chalk, strings) {
+	if (!Array.isArray(strings)) {
+		// If chalk() was called by itself or with a string,
+		// return the string itself as a string.
+		return [].slice.call(arguments, 1).join(' ');
+	}
+
+	const args = [].slice.call(arguments, 2);
+	const parts = [strings.raw[0]];
+
+	for (let i = 1; i < strings.length; i++) {
+		parts.push(String(args[i - 1]).replace(/[{}\\]/g, '\\$&'));
+		parts.push(String(strings.raw[i]));
+	}
+
+	return template(chalk, parts.join(''));
+}
+
+Object.defineProperties(Chalk.prototype, styles);
+
+module.exports = Chalk(); // eslint-disable-line new-cap
+module.exports.supportsColor = stdoutColor;
+module.exports.default = module.exports; // For TypeScript
+
+/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(120)))
+
+/***/ }),
+
+/***/ 632:
+/***/ (function(module, exports, __webpack_require__) {
+
+"use strict";
+
+
+var matchOperatorsRe = /[|\\{}()[\]^$+*?.]/g;
+
+module.exports = function (str) {
+	if (typeof str !== 'string') {
+		throw new TypeError('Expected a string');
+	}
+
+	return str.replace(matchOperatorsRe, '\\$&');
+};
+
+
+/***/ }),
+
+/***/ 633:
+/***/ (function(module, exports, __webpack_require__) {
+
+"use strict";
+/* WEBPACK VAR INJECTION */(function(module) {
+const colorConvert = __webpack_require__(2388);
+
+const wrapAnsi16 = (fn, offset) => function () {
+	const code = fn.apply(colorConvert, arguments);
+	return `\u001B[${code + offset}m`;
+};
+
+const wrapAnsi256 = (fn, offset) => function () {
+	const code = fn.apply(colorConvert, arguments);
+	return `\u001B[${38 + offset};5;${code}m`;
+};
+
+const wrapAnsi16m = (fn, offset) => function () {
+	const rgb = fn.apply(colorConvert, arguments);
+	return `\u001B[${38 + offset};2;${rgb[0]};${rgb[1]};${rgb[2]}m`;
+};
+
+function assembleStyles() {
+	const codes = new Map();
+	const styles = {
+		modifier: {
+			reset: [0, 0],
+			// 21 isn't widely supported and 22 does the same thing
+			bold: [1, 22],
+			dim: [2, 22],
+			italic: [3, 23],
+			underline: [4, 24],
+			inverse: [7, 27],
+			hidden: [8, 28],
+			strikethrough: [9, 29]
+		},
+		color: {
+			black: [30, 39],
+			red: [31, 39],
+			green: [32, 39],
+			yellow: [33, 39],
+			blue: [34, 39],
+			magenta: [35, 39],
+			cyan: [36, 39],
+			white: [37, 39],
+			gray: [90, 39],
+
+			// Bright color
+			redBright: [91, 39],
+			greenBright: [92, 39],
+			yellowBright: [93, 39],
+			blueBright: [94, 39],
+			magentaBright: [95, 39],
+			cyanBright: [96, 39],
+			whiteBright: [97, 39]
+		},
+		bgColor: {
+			bgBlack: [40, 49],
+			bgRed: [41, 49],
+			bgGreen: [42, 49],
+			bgYellow: [43, 49],
+			bgBlue: [44, 49],
+			bgMagenta: [45, 49],
+			bgCyan: [46, 49],
+			bgWhite: [47, 49],
+
+			// Bright color
+			bgBlackBright: [100, 49],
+			bgRedBright: [101, 49],
+			bgGreenBright: [102, 49],
+			bgYellowBright: [103, 49],
+			bgBlueBright: [104, 49],
+			bgMagentaBright: [105, 49],
+			bgCyanBright: [106, 49],
+			bgWhiteBright: [107, 49]
+		}
+	};
+
+	// Fix humans
+	styles.color.grey = styles.color.gray;
+
+	for (const groupName of Object.keys(styles)) {
+		const group = styles[groupName];
+
+		for (const styleName of Object.keys(group)) {
+			const style = group[styleName];
+
+			styles[styleName] = {
+				open: `\u001B[${style[0]}m`,
+				close: `\u001B[${style[1]}m`
+			};
+
+			group[styleName] = styles[styleName];
+
+			codes.set(style[0], style[1]);
+		}
+
+		Object.defineProperty(styles, groupName, {
+			value: group,
+			enumerable: false
+		});
+
+		Object.defineProperty(styles, 'codes', {
+			value: codes,
+			enumerable: false
+		});
+	}
+
+	const ansi2ansi = n => n;
+	const rgb2rgb = (r, g, b) => [r, g, b];
+
+	styles.color.close = '\u001B[39m';
+	styles.bgColor.close = '\u001B[49m';
+
+	styles.color.ansi = {
+		ansi: wrapAnsi16(ansi2ansi, 0)
+	};
+	styles.color.ansi256 = {
+		ansi256: wrapAnsi256(ansi2ansi, 0)
+	};
+	styles.color.ansi16m = {
+		rgb: wrapAnsi16m(rgb2rgb, 0)
+	};
+
+	styles.bgColor.ansi = {
+		ansi: wrapAnsi16(ansi2ansi, 10)
+	};
+	styles.bgColor.ansi256 = {
+		ansi256: wrapAnsi256(ansi2ansi, 10)
+	};
+	styles.bgColor.ansi16m = {
+		rgb: wrapAnsi16m(rgb2rgb, 10)
+	};
+
+	for (let key of Object.keys(colorConvert)) {
+		if (typeof colorConvert[key] !== 'object') {
+			continue;
+		}
+
+		const suite = colorConvert[key];
+
+		if (key === 'ansi16') {
+			key = 'ansi';
+		}
+
+		if ('ansi16' in suite) {
+			styles.color.ansi[key] = wrapAnsi16(suite.ansi16, 0);
+			styles.bgColor.ansi[key] = wrapAnsi16(suite.ansi16, 10);
+		}
+
+		if ('ansi256' in suite) {
+			styles.color.ansi256[key] = wrapAnsi256(suite.ansi256, 0);
+			styles.bgColor.ansi256[key] = wrapAnsi256(suite.ansi256, 10);
+		}
+
+		if ('rgb' in suite) {
+			styles.color.ansi16m[key] = wrapAnsi16m(suite.rgb, 0);
+			styles.bgColor.ansi16m[key] = wrapAnsi16m(suite.rgb, 10);
+		}
+	}
+
+	return styles;
+}
+
+// Make the export immutable
+Object.defineProperty(module, 'exports', {
+	enumerable: true,
+	get: assembleStyles
+});
+
+/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(793)(module)))
+
+/***/ }),
+
 /***/ 67:
 /***/ (function(module, exports, __webpack_require__) {
 
 var baseGet = __webpack_require__(68);
 
 /**
  * Gets the value at `path` of `object`. If the resolved value is
  * `undefined`, the `defaultValue` is returned in its place.
--- a/devtools/client/debugger/new/src/actions/ast.js
+++ b/devtools/client/debugger/new/src/actions/ast.js
@@ -120,17 +120,21 @@ function compressPausePoints(pausePoints
 function setPausePoints(sourceId) {
   return async ({
     dispatch,
     getState,
     client
   }) => {
     const source = (0, _selectors.getSourceFromId)(getState(), sourceId);
 
-    if (!_prefs.features.pausePoints || !source || !source.text || source.isWasm) {
+    if (!_prefs.features.pausePoints || !source || !source.text) {
+      return;
+    }
+
+    if (source.isWasm) {
       return;
     }
 
     const pausePoints = await (0, _parser.getPausePoints)(sourceId);
     const compressed = compressPausePoints(pausePoints);
 
     if ((0, _devtoolsSourceMap.isGeneratedId)(sourceId)) {
       await client.setPausePoints(sourceId, compressed);
--- a/devtools/client/debugger/new/src/actions/breakpoints/addBreakpoint.js
+++ b/devtools/client/debugger/new/src/actions/breakpoints/addBreakpoint.js
@@ -21,16 +21,17 @@ var _telemetry = require("../../utils/te
 
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at <http://mozilla.org/MPL/2.0/>. */
 async function addBreakpointPromise(getState, client, sourceMaps, breakpoint) {
   const state = getState();
   const source = (0, _selectors.getSource)(state, breakpoint.location.sourceId);
   const location = { ...breakpoint.location,
+    sourceId: source.id,
     sourceUrl: source.url
   };
   const generatedLocation = await (0, _sourceMaps.getGeneratedLocation)(state, source, location, sourceMaps);
   const generatedSource = (0, _selectors.getSource)(state, generatedLocation.sourceId);
   (0, _breakpoint.assertLocation)(location);
   (0, _breakpoint.assertLocation)(generatedLocation);
 
   if ((0, _breakpoint.breakpointExists)(state, location)) {
--- a/devtools/client/debugger/new/src/actions/expressions.js
+++ b/devtools/client/debugger/new/src/actions/expressions.js
@@ -214,15 +214,15 @@ function getMappedExpression(expression)
     dispatch,
     getState,
     client,
     sourceMaps
   }) {
     const mappings = (0, _selectors.getSelectedScopeMappings)(getState());
     const bindings = (0, _selectors.getSelectedFrameBindings)(getState());
 
-    if (!mappings && !bindings) {
+    if (!mappings && !bindings && !expression.includes("await")) {
       return expression;
     }
 
-    return parser.mapExpression(expression, mappings, bindings, _prefs.features.mapExpressionBindings);
+    return parser.mapExpression(expression, mappings, bindings || [], _prefs.features.mapExpressionBindings, _prefs.features.mapAwaitExpression);
   };
 }
\ No newline at end of file
--- a/devtools/client/debugger/new/src/actions/pause/commands.js
+++ b/devtools/client/debugger/new/src/actions/pause/commands.js
@@ -204,17 +204,17 @@ function reverseStepOut() {
 
 
 function hasAwait(source, pauseLocation) {
   const {
     line,
     column
   } = pauseLocation;
 
-  if (!source.text) {
+  if (source.isWasm || !source.text) {
     return false;
   }
 
   const lineText = source.text.split("\n")[line - 1];
 
   if (!lineText) {
     return false;
   }
--- a/devtools/client/debugger/new/src/actions/preview.js
+++ b/devtools/client/debugger/new/src/actions/preview.js
@@ -49,17 +49,17 @@ function updatePreview(target, tokenPos,
   return ({
     dispatch,
     getState,
     client,
     sourceMaps
   }) => {
     const cursorPos = target.getBoundingClientRect();
 
-    if ((0, _selectors.getCanRewind)(getState()) || !(0, _selectors.isSelectedFrameVisible)(getState()) || !(0, _selectors.isLineInScope)(getState(), tokenPos.line)) {
+    if (!(0, _selectors.isSelectedFrameVisible)(getState()) || !(0, _selectors.isLineInScope)(getState(), tokenPos.line)) {
       return;
     }
 
     const match = findExpressionMatch(getState(), codeMirror, tokenPos);
 
     if (!match) {
       return;
     }
--- a/devtools/client/debugger/new/src/actions/sources/newSources.js
+++ b/devtools/client/debugger/new/src/actions/sources/newSources.js
@@ -82,16 +82,17 @@ function loadSourceMap(sourceId) {
     } catch (e) {
       console.error(e);
     }
 
     if (!urls) {
       // If this source doesn't have a sourcemap, enable it for pretty printing
       dispatch({
         type: "UPDATE_SOURCE",
+        // NOTE: Flow https://github.com/facebook/flow/issues/6342 issue
         source: { ...source,
           sourceMapURL: ""
         }
       });
       return;
     }
 
     return urls.map(url => createOriginalSource(url, source, sourceMaps));
--- a/devtools/client/debugger/new/src/client/firefox/create.js
+++ b/devtools/client/debugger/new/src/client/firefox/create.js
@@ -39,26 +39,29 @@ function createFrame(frame) {
     this: frame.this,
     scope: frame.environment
   };
 }
 
 function createSource(source, {
   supportsWasm
 }) {
-  return {
+  const createdSource = {
     id: source.actor,
     url: source.url,
     relativeUrl: source.url,
     isPrettyPrinted: false,
-    isWasm: supportsWasm && source.introductionType === "wasm",
+    isWasm: false,
     sourceMapURL: source.sourceMapURL,
     isBlackBoxed: false,
     loadedState: "unloaded"
   };
+  return Object.assign(createdSource, {
+    isWasm: supportsWasm && source.introductionType === "wasm"
+  });
 }
 
 function createPause(packet, response) {
   // NOTE: useful when the debugger is already paused
   const frame = packet.frame || response.frames[0];
   return { ...packet,
     frame: createFrame(frame),
     frames: response.frames.map(createFrame)
--- a/devtools/client/debugger/new/src/reducers/pending-breakpoints.js
+++ b/devtools/client/debugger/new/src/reducers/pending-breakpoints.js
@@ -69,18 +69,25 @@ function update(state = {}, action) {
 
 function addBreakpoint(state, action) {
   if (action.breakpoint.hidden || action.status !== "done") {
     return state;
   } // when the action completes, we can commit the breakpoint
 
 
   const {
-    breakpoint
+    breakpoint,
+    previousLocation
   } = action.value;
+
+  if (previousLocation) {
+    const previousLocationId = (0, _breakpoint.makePendingLocationId)(previousLocation);
+    state = deleteBreakpoint(state, previousLocationId);
+  }
+
   const locationId = (0, _breakpoint.makePendingLocationId)(breakpoint.location);
   const pendingBreakpoint = (0, _breakpoint.createPendingBreakpoint)(breakpoint);
   return { ...state,
     [locationId]: pendingBreakpoint
   };
 }
 
 function syncBreakpoint(state, action) {
--- a/devtools/client/debugger/new/src/selectors/breakpointSources.js
+++ b/devtools/client/debugger/new/src/selectors/breakpointSources.js
@@ -13,17 +13,17 @@ var _selectors = require("../selectors/i
 
 var _source = require("../utils/source");
 
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at <http://mozilla.org/MPL/2.0/>. */
 function getBreakpointsForSource(source, breakpoints) {
   const bpList = breakpoints.valueSeq();
-  return bpList.filter(bp => bp.location.sourceId == source.id && !bp.hidden && (bp.text || bp.originalText || bp.condition)).sortBy(bp => bp.location.line).toJS();
+  return bpList.filter(bp => bp.location.sourceId == source.id && !bp.hidden && (bp.text || bp.originalText || bp.condition || bp.disabled)).sortBy(bp => bp.location.line).toJS();
 }
 
 function findBreakpointSources(sources, breakpoints) {
   const sourceIds = (0, _lodash.uniq)(breakpoints.valueSeq().map(bp => bp.location.sourceId).toJS());
   const breakpointSources = sourceIds.map(id => sources[id]).filter(source => source && !source.isBlackBoxed);
   return (0, _lodash.sortBy)(breakpointSources, source => (0, _source.getFilename)(source));
 }
 
--- a/devtools/client/debugger/new/src/selectors/getRelativeSources.js
+++ b/devtools/client/debugger/new/src/selectors/getRelativeSources.js
@@ -27,16 +27,17 @@ function getRelativeUrl(source, root) {
   } // + 1 removes the leading "/"
 
 
   const url = group + path;
   return url.slice(url.indexOf(root) + root.length + 1);
 }
 
 function formatSource(source, root) {
+  // NOTE: Flow https://github.com/facebook/flow/issues/6342 issue
   return { ...source,
     relativeUrl: getRelativeUrl(source, root)
   };
 }
 
 function underRoot(source, root) {
   return source.url && source.url.includes(root);
 }
--- a/devtools/client/debugger/new/src/utils/function.js
+++ b/devtools/client/debugger/new/src/utils/function.js
@@ -14,17 +14,17 @@ var _indentation = require("./indentatio
  * file, You can obtain one at <http://mozilla.org/MPL/2.0/>. */
 function findFunctionText(line, source, symbols) {
   const func = (0, _ast.findClosestFunction)(symbols, {
     sourceId: source.id,
     line,
     column: Infinity
   });
 
-  if (!func || !source.text) {
+  if (source.isWasm || !func || !source.text) {
     return null;
   }
 
   const {
     location: {
       start,
       end
     }
--- a/devtools/client/debugger/new/src/utils/isMinified.js
+++ b/devtools/client/debugger/new/src/utils/isMinified.js
@@ -15,16 +15,20 @@ const CHARACTER_LIMIT = 250;
 
 const _minifiedCache = new Map();
 
 function isMinified(source) {
   if (_minifiedCache.has(source.id)) {
     return _minifiedCache.get(source.id);
   }
 
+  if (source.isWasm) {
+    return false;
+  }
+
   let text = source.text;
 
   if (!text) {
     return false;
   }
 
   let lineEndIndex = 0;
   let lineStartIndex = 0;
--- a/devtools/client/debugger/new/src/utils/prefs.js
+++ b/devtools/client/debugger/new/src/utils/prefs.js
@@ -64,16 +64,17 @@ if ((0, _devtoolsEnvironment.isDevelopme
   pref("devtools.debugger.features.outline", true);
   pref("devtools.debugger.features.column-breakpoints", true);
   pref("devtools.debugger.features.replay", true);
   pref("devtools.debugger.features.pause-points", true);
   pref("devtools.debugger.features.skip-pausing", true);
   pref("devtools.debugger.features.component-pane", false);
   pref("devtools.debugger.features.autocomplete-expressions", false);
   pref("devtools.debugger.features.map-expression-bindings", true);
+  pref("devtools.debugger.features.map-await-expression", true);
 }
 
 const prefs = exports.prefs = new _devtoolsModules.PrefsHelper("devtools", {
   alphabetizeOutline: ["Bool", "debugger.alphabetize-outline"],
   autoPrettyPrint: ["Bool", "debugger.auto-pretty-print"],
   clientSourceMapsEnabled: ["Bool", "source-map.client-service.enabled"],
   pauseOnExceptions: ["Bool", "debugger.pause-on-exceptions"],
   pauseOnCaughtExceptions: ["Bool", "debugger.pause-on-caught-exceptions"],
@@ -112,16 +113,17 @@ const features = exports.features = new 
   eventListeners: ["Bool", "event-listeners"],
   outline: ["Bool", "outline"],
   codeFolding: ["Bool", "code-folding"],
   replay: ["Bool", "replay"],
   pausePoints: ["Bool", "pause-points"],
   skipPausing: ["Bool", "skip-pausing"],
   autocompleteExpression: ["Bool", "autocomplete-expressions"],
   mapExpressionBindings: ["Bool", "map-expression-bindings"],
+  mapAwaitExpression: ["Bool", "map-await-expression"],
   componentPane: ["Bool", "component-pane"]
 });
 const asyncStore = exports.asyncStore = (0, _asyncStoreHelper.asyncStoreHelper)("debugger", {
   pendingBreakpoints: ["pending-breakpoints", {}]
 });
 
 if (prefs.debuggerPrefsSchemaVersion !== prefsSchemaVersion) {
   // clear pending Breakpoints
--- a/devtools/client/debugger/new/src/utils/source.js
+++ b/devtools/client/debugger/new/src/utils/source.js
@@ -192,17 +192,17 @@ function getTruncatedFileName(source, le
  * @static
  */
 
 
 function getDisplayPath(mySource, sources) {
   const filename = getFilename(mySource); // Find sources that have the same filename, but different paths
   // as the original source
 
-  const similarSources = sources.filter(source => mySource.url != source.url && filename == getFilename(source));
+  const similarSources = sources.filter(source => getRawSourceURL(mySource.url) != getRawSourceURL(source.url) && filename == getFilename(source));
 
   if (similarSources.length == 0) {
     return undefined;
   } // get an array of source path directories e.g. ['a/b/c.html'] => [['b', 'a']]
 
 
   const paths = [mySource, ...similarSources].map(source => (0, _sourcesTree.getURL)(source).path.split("/").reverse().slice(1)); // create an array of similar path directories and one dis-similar directory
   // for example [`a/b/c.html`, `a1/b/c.html`] => ['b', 'a']
@@ -290,17 +290,21 @@ function getSourcePath(url) {
 }
 /**
  * Returns amount of lines in the source. If source is a WebAssembly binary,
  * the function returns amount of bytes.
  */
 
 
 function getSourceLineCount(source) {
-  if (source.isWasm && !source.error) {
+  if (source.error) {
+    return 0;
+  }
+
+  if (source.isWasm) {
     const {
       binary
     } = source.text;
     return binary.length;
   }
 
   return source.text != undefined ? source.text.split("\n").length : 0;
 }
@@ -320,24 +324,29 @@ function getSourceLineCount(source) {
  * @param contentType
  * @return String
  * @memberof utils/source
  * @static
  */
 
 
 function getMode(source, symbols) {
+  if (source.isWasm) {
+    return {
+      name: "text"
+    };
+  }
+
   const {
     contentType,
     text,
-    isWasm,
     url
   } = source;
 
-  if (!text || isWasm) {
+  if (!text) {
     return {
       name: "text"
     };
   }
 
   if (url && url.match(/\.jsx$/i) || symbols && symbols.hasJsx) {
     if (symbols && symbols.hasTypes) {
       return {
@@ -446,17 +455,17 @@ function isLoaded(source) {
   return source.loadedState === "loaded";
 }
 
 function isLoading(source) {
   return source.loadedState === "loading";
 }
 
 function getTextAtPosition(source, location) {
-  if (!source || !source.text || source.isWasm) {
+  if (!source || source.isWasm || !source.text) {
     return "";
   }
 
   const line = location.line;
   const column = location.column || 0;
   const lineText = source.text.split("\n")[line - 1];
 
   if (!lineText) {
--- a/devtools/client/debugger/new/src/utils/sources-tree/addToTree.js
+++ b/devtools/client/debugger/new/src/utils/sources-tree/addToTree.js
@@ -73,17 +73,17 @@ function traverseTree(url, tree, debugge
  * Add a source file to a directory node in the tree
  */
 
 
 function addSourceToNode(node, url, source) {
   const isFile = !(0, _utils.isPathDirectory)(url.path);
 
   if (node.type == "source") {
-    throw new Error(`wtf ${node.name}`);
+    throw new Error(`Unexpected type "source" at: ${node.name}`);
   } // if we have a file, and the subtree has no elements, overwrite the
   // subtree contents with the source
 
 
   if (isFile) {
     // $FlowIgnore
     node.type = "source";
     return source;
--- a/devtools/client/debugger/new/src/utils/sources-tree/collapseTree.js
+++ b/devtools/client/debugger/new/src/utils/sources-tree/collapseTree.js
@@ -13,26 +13,26 @@ var _utils = require("./utils");
 
 /**
  * Take an existing source tree, and return a new one with collapsed nodes.
  */
 function _collapseTree(node, depth) {
   // Node is a folder.
   if (node.type === "directory") {
     if (!Array.isArray(node.contents)) {
-      console.log(`WTF: ${node.path}`);
+      console.log(`Expected array at: ${node.path}`);
     } // Node is not a root/domain node, and only contains 1 item.
 
 
     if (depth > 1 && node.contents.length === 1) {
       const next = node.contents[0]; // Do not collapse if the next node is a leaf node.
 
       if (next.type === "directory") {
         if (!Array.isArray(next.contents)) {
-          console.log(`WTF: ${next.name} -- ${node.name} -- ${JSON.stringify(next.contents)}`);
+          console.log(`Expected array at: ${next.name} -- ${node.name} -- ${JSON.stringify(next.contents)}`);
         }
 
         const name = `${node.name}/${next.name}`;
         const nextNode = (0, _utils.createDirectoryNode)(name, next.path, next.contents);
         return _collapseTree(nextNode, depth + 1);
       }
     } // Map the contents.
 
--- a/devtools/client/debugger/new/test/mochitest/browser.ini
+++ b/devtools/client/debugger/new/test/mochitest/browser.ini
@@ -649,16 +649,17 @@ skip-if = !e10s || verify # This test is
 [browser_dbg-breakpoints-reloading.js]
 [browser_dbg-breakpoint-skipping.js]
 [browser_dbg-call-stack.js]
 [browser_dbg-scopes.js]
 [browser_dbg-chrome-create.js]
 skip-if = (verify && !debug && (os == 'linux'))
 [browser_dbg-chrome-debugging.js]
 [browser_dbg-console.js]
+[browser_dbg-console-async.js]
 [browser_dbg-console-link.js]
 [browser_dbg-console-map-bindings.js]
 [browser_dbg-content-script-sources.js]
 skip-if = (os == "win" && ccov) # Bug 1424154
 [browser_dbg-debugger-buttons.js]
 [browser_dbg-editor-gutter.js]
 [browser_dbg-editor-select.js]
 [browser_dbg-editor-highlight.js]
new file mode 100644
--- /dev/null
+++ b/devtools/client/debugger/new/test/mochitest/browser_dbg-console-async.js
@@ -0,0 +1,52 @@
+// Return a promise with a reference to jsterm, opening the split
+// console if necessary.  This cleans up the split console pref so
+// it won't pollute other tests.
+function getSplitConsole(dbg) {
+  const { toolbox, win } = dbg;
+
+  if (!win) {
+    win = toolbox.win;
+  }
+
+  if (!toolbox.splitConsole) {
+    pressKey(dbg, "Escape");
+  }
+
+  return new Promise(resolve => {
+    toolbox.getPanelWhenReady("webconsole").then(() => {
+      ok(toolbox.splitConsole, "Split console is shown.");
+      let jsterm = toolbox.getPanel("webconsole").hud.jsterm;
+      resolve(jsterm);
+    });
+  });
+}
+
+function findMessages(win, query) {
+  return Array.prototype.filter.call(
+    win.document.querySelectorAll(".message"),
+    e => e.innerText.includes(query)
+  )
+}
+
+add_task(async function() {
+  Services.prefs.setBoolPref("devtools.toolbox.splitconsoleEnabled", true);
+  const dbg = await initDebugger("doc-script-switching.html");
+
+  await selectSource(dbg, "switching-01");
+
+  // open the console
+  await getSplitConsole(dbg);
+  ok(dbg.toolbox.splitConsole, "Split console is shown.");
+
+  const webConsole = await dbg.toolbox.getPanel("webconsole")
+  const jsterm = webConsole.hud.jsterm;
+
+  await jsterm.execute(`let sleep = async (time, v) => new Promise(
+    res => setTimeout(() => res(v+'!!!'), time)
+  )`);
+
+  await jsterm.execute(`await sleep(200, "DONE")`)
+
+  await waitFor(async () => findMessages(webConsole._frameWindow, "DONE!!!").length > 0)
+
+});
--- a/devtools/client/debugger/new/test/mochitest/browser_dbg-sourcemapped-breakpoint-console.js
+++ b/devtools/client/debugger/new/test/mochitest/browser_dbg-sourcemapped-breakpoint-console.js
@@ -42,17 +42,16 @@ async function assertConsoleEval(dbg, st
     is(result.result, true, `'${statement}' evaluates to true`);
   }
 }
 
 add_task(async function() {
   await pushPref("devtools.debugger.features.map-scopes", true);
 
   const dbg = await initDebugger("doc-sourcemapped.html");
-
   await evalInConsoleAtPoint(dbg, "webpack3-babel6", "eval-maps", { line: 14, column: 4 }, [
     "one === 1",
     "two === 4",
     "three === 5"
   ]);
 
   await evalInConsoleAtPoint(
     dbg,
--- a/devtools/client/debugger/new/test/mochitest/browser_dbg-sources-named-eval.js
+++ b/devtools/client/debugger/new/test/mochitest/browser_dbg-sources-named-eval.js
@@ -3,17 +3,17 @@
 
 // Make sure named eval sources appear in the list.
 
 async function waitForSourceCount(dbg, i) {
   // We are forced to wait until the DOM nodes appear because the
   // source tree batches its rendering.
   await waitUntil(() => {
     return findAllElements(dbg, "sourceNodes").length === i;
-  });
+  }, `waiting for source count ${i}`);
 }
 
 function getLabel(dbg, index) {
   return findElement(dbg, "sourceNode", index)
     .textContent.trim()
     .replace(/^[\s\u200b]*/g, "");
 }
 
@@ -21,15 +21,18 @@ add_task(async function() {
   const dbg = await initDebugger("doc-sources.html");
   const {
     selectors: { getSelectedSource },
     getState
   } = dbg;
 
   await waitForSources(dbg, "simple1", "simple2", "nested-source", "long.js");
 
+
+  dump(`>>> contentTask: evaluate evaled.js\n`)
   ContentTask.spawn(gBrowser.selectedBrowser, null, function() {
     content.eval("window.evaledFunc = function() {} //# sourceURL=evaled.js");
   });
 
   await waitForSourceCount(dbg, 3);
-  is(getLabel(dbg, 3), "evaled.js", "evaled exists");
+  // is(getLabel(dbg, 3), "evaled.js", "evaled exists");
+  ok(true)
 });
--- a/devtools/client/debugger/new/test/mochitest/browser_dbg_rr_breakpoints-01.js
+++ b/devtools/client/debugger/new/test/mochitest/browser_dbg_rr_breakpoints-01.js
@@ -2,17 +2,17 @@
 /* vim: set ft=javascript ts=2 et sw=2 tw=80: */
 /* Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/ */
 
 // Test basic breakpoint functionality in web replay.
 async function test() {
   waitForExplicitFinish();
 
-  let tab = gBrowser.addTab(null, { recordExecution: "*" });
+  let tab = BrowserTestUtils.addTab(gBrowser, null, { recordExecution: "*" });
   gBrowser.selectedTab = tab;
   openTrustedLinkIn(EXAMPLE_URL + "doc_rr_basic.html", "current");
   await once(Services.ppmm, "RecordingFinished");
 
   let toolbox = await attachDebugger(tab), client = toolbox.threadClient;
   await client.interrupt();
   await setBreakpoint(client, "doc_rr_basic.html", 21);
 
--- a/devtools/client/debugger/new/test/mochitest/helpers.js
+++ b/devtools/client/debugger/new/test/mochitest/helpers.js
@@ -477,17 +477,17 @@ function createDebuggerContext(toolbox) 
     panel: panel
   };
 }
 
 /**
  * Clear all the debugger related preferences.
  */
 function clearDebuggerPreferences() {
-  asyncStorage.clear();
+  asyncStorage.clear()
   Services.prefs.clearUserPref("devtools.recordreplay.enabled");
   Services.prefs.clearUserPref("devtools.debugger.pause-on-exceptions");
   Services.prefs.clearUserPref("devtools.debugger.pause-on-caught-exceptions");
   Services.prefs.clearUserPref("devtools.debugger.ignore-caught-exceptions");
   Services.prefs.clearUserPref("devtools.debugger.tabs");
   Services.prefs.clearUserPref("devtools.debugger.pending-selected-location");
   Services.prefs.clearUserPref("devtools.debugger.pending-breakpoints");
   Services.prefs.clearUserPref("devtools.debugger.expressions");
--- a/devtools/client/debugger/test/mochitest/head.js
+++ b/devtools/client/debugger/test/mochitest/head.js
@@ -83,17 +83,17 @@ function getChromeWindow(aWindow) {
 this.addTab = function addTab(aUrl, aWindow) {
   info("Adding tab: " + aUrl);
 
   let deferred = promise.defer();
   let targetWindow = aWindow || window;
   let targetBrowser = targetWindow.gBrowser;
 
   targetWindow.focus();
-  let tab = targetBrowser.selectedTab = targetBrowser.addTab(aUrl);
+  let tab = targetBrowser.selectedTab = BrowserTestUtils.addTab(targetBrowser, aUrl);
   let linkedBrowser = tab.linkedBrowser;
 
   info("Loading frame script with url " + FRAME_SCRIPT_URL + ".");
   linkedBrowser.messageManager.loadFrameScript(FRAME_SCRIPT_URL, false);
 
   BrowserTestUtils.browserLoaded(linkedBrowser)
     .then(function () {
       info("Tab added and finished loading: " + aUrl);
--- a/devtools/client/framework/devtools-browser.js
+++ b/devtools/client/framework/devtools-browser.js
@@ -280,25 +280,25 @@ var gDevToolsBrowser = exports.gDevTools
   },
 
   /**
    * Open a tab on "about:debugging", optionally pre-select a given tab.
    */
    // Used by browser-sets.inc, command
   openAboutDebugging(gBrowser, hash) {
     const url = "about:debugging" + (hash ? "#" + hash : "");
-    gBrowser.selectedTab = gBrowser.addTab(url);
+    gBrowser.selectedTab = gBrowser.addTrustedTab(url);
   },
 
   /**
    * Open a tab to allow connects to a remote browser
    */
    // Used by browser-sets.inc, command
   openConnectScreen(gBrowser) {
-    gBrowser.selectedTab = gBrowser.addTab("chrome://devtools/content/framework/connect/connect.xhtml");
+    gBrowser.selectedTab = gBrowser.addTrustedTab("chrome://devtools/content/framework/connect/connect.xhtml");
   },
 
   /**
    * Open WebIDE
    */
    // Used by browser-sets.inc, command
    //         itself, webide widget
   openWebIDE() {
--- a/devtools/client/inspector/animation/animation.js
+++ b/devtools/client/inspector/animation/animation.js
@@ -657,16 +657,24 @@ class AnimationInspector {
   updateState(animations) {
     // Animation inspector already destroyed
     if (!this.inspector) {
       return;
     }
 
     this.stopAnimationsCurrentTimeTimer();
 
+    // Although it is not possible to set a delay or end delay of infinity using
+    // the animation API, if the value passed exceeds the limit of our internal
+    // representation of times, it will be treated as infinity. Rather than
+    // adding special case code to represent this very rare case, we simply omit
+    // such animations from the graph.
+    animations = animations.filter(anim => anim.state.delay !== Infinity &&
+                                           anim.state.endDelay !== Infinity);
+
     this.inspector.store.dispatch(updateAnimations(animations));
 
     if (hasRunningAnimation(animations)) {
       this.startAnimationsCurrentTimeTimer();
     } else {
       // Even no running animations, update the current time once
       // so as to show the state.
       this.onCurrentTimeTimerUpdated(this.state.timeScale.getCurrentTime());
--- a/devtools/client/inspector/animation/test/browser.ini
+++ b/devtools/client/inspector/animation/test/browser.ini
@@ -5,16 +5,17 @@ support-files =
   current-time-scrubber_head.js
   doc_custom_playback_rate.html
   doc_frame_script.js
   doc_infinity_duration.html
   doc_multi_easings.html
   doc_multi_keyframes.html
   doc_multi_timings.html
   doc_mutations_fast.html
+  doc_overflowed_delay_end_delay.html
   doc_pseudo.html
   doc_short_duration.html
   doc_simple_animation.html
   head.js
   keyframes-graph_keyframe-marker_head.js
   summary-graph_delay-sign_head.js
   summary-graph_end-delay-sign_head.js
   !/devtools/client/inspector/test/head.js
@@ -61,16 +62,17 @@ skip-if = (verify && !debug)
 [browser_animation_logic_adjust-time.js]
 [browser_animation_logic_adjust-time-with-playback-rate.js]
 [browser_animation_logic_auto-stop.js]
 [browser_animation_logic_avoid-updating-during-hiding.js]
 [browser_animation_logic_created-time.js]
 [browser_animation_logic_mutations.js]
 [browser_animation_logic_mutations_fast.js]
 [browser_animation_logic_mutations_properties.js]
+[browser_animation_logic_overflowed_delay_end-delay.js]
 [browser_animation_logic_scroll-amount.js]
 [browser_animation_pause-resume-button.js]
 [browser_animation_pause-resume-button_end-time.js]
 [browser_animation_pause-resume-button_respectively.js]
 [browser_animation_pause-resume-button_spacebar.js]
 [browser_animation_playback-rate-selector.js]
 [browser_animation_pseudo-element.js]
 [browser_animation_rewind-button.js]
new file mode 100644
--- /dev/null
+++ b/devtools/client/inspector/animation/test/browser_animation_logic_overflowed_delay_end-delay.js
@@ -0,0 +1,20 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+// Test that animations with an overflowed delay and end delay are not displayed.
+
+add_task(async function() {
+  await addTab(URL_ROOT + "doc_overflowed_delay_end_delay.html");
+  const { panel } = await openAnimationInspector();
+
+  info("Check the number of animation item");
+  const animationItemEls = panel.querySelectorAll(".animation-list .animation-item");
+  is(animationItemEls.length, 1, "The number of animations displayed should be 1");
+
+  info("Check the id of animation displayed");
+  const animationNameEl = animationItemEls[0].querySelector(".animation-name");
+  is(animationNameEl.textContent, "big-iteration-start",
+    "The animation name should be 'big-iteration-start'");
+});
new file mode 100644
--- /dev/null
+++ b/devtools/client/inspector/animation/test/doc_overflowed_delay_end_delay.html
@@ -0,0 +1,53 @@
+<!DOCTYPE html>
+<html lang="en">
+  <head>
+    <meta charset="UTF-8">
+    <style>
+    div {
+      width: 100px;
+      height: 100px;
+      outline: 1px solid lime;
+    }
+    </style>
+  </head>
+  <body>
+    <div id="target"></div>
+    <script>
+    "use strict";
+
+    const target = document.getElementById("target");
+    target.animate(
+      {
+        color: ["red", "lime"]
+      },
+      {
+        id: "big-delay",
+        duration: 1000,
+        delay: Number.MAX_VALUE,
+        iterations: Infinity,
+      });
+
+    target.animate(
+      {
+        opacity: [1, 0]
+      },
+      {
+        id: "big-end-delay",
+        duration: 1000,
+        endDelay: Number.MAX_VALUE,
+        iterations: Infinity,
+      });
+
+    target.animate(
+      {
+        backgroundColor: ["lime", "white"]
+      },
+      {
+        id: "big-iteration-start",
+        duration: 1000,
+        iterations: Infinity,
+        iterationStart: Number.MAX_VALUE,
+      });
+    </script>
+  </body>
+</html>
--- a/devtools/client/netmonitor/src/utils/firefox/open-request-in-tab.js
+++ b/devtools/client/netmonitor/src/utils/firefox/open-request-in-tab.js
@@ -28,18 +28,25 @@ function openRequestInTab(url, requestPo
 
   if (rawData && rawData.text) {
     const stringStream = getInputStreamFromString(rawData.text);
     postData = Cc["@mozilla.org/network/mime-input-stream;1"]
       .createInstance(Ci.nsIMIMEInputStream);
     postData.addHeader("Content-Type", "application/x-www-form-urlencoded");
     postData.setData(stringStream);
   }
-
-  win.gBrowser.selectedTab = win.gBrowser.addTab(url, { postData });
+  const userContextId = win.gBrowser.contentPrincipal.userContextId;
+  win.gBrowser.selectedTab = win.gBrowser.addWebTab(url, {
+    // TODO this should be using the original request principal
+    triggeringPrincipal: Services.scriptSecurityManager.createNullPrincipal({
+      userContextId,
+    }),
+    userContextId,
+    postData,
+  });
 }
 
 function getInputStreamFromString(data) {
   const stringStream = Cc["@mozilla.org/io/string-input-stream;1"]
     .createInstance(Ci.nsIStringInputStream);
   stringStream.data = data;
   return stringStream;
 }
--- a/devtools/client/performance-new/browser.js
+++ b/devtools/client/performance-new/browser.js
@@ -23,17 +23,21 @@ function receiveProfile(profile) {
   // of hosts.
   const win = Services.wm.getMostRecentWindow("navigator:browser");
   if (!win) {
     throw new Error("No browser window");
   }
   const browser = win.gBrowser;
   Services.focus.activeWindow = win;
 
-  const tab = browser.addTab("https://perf-html.io/from-addon");
+  const tab = browser.addWebTab("https://perf-html.io/from-addon", {
+    triggeringPrincipal: Services.scriptSecurityManager.createNullPrincipal({
+      userContextId: browser.contentPrincipal.userContextId,
+    })
+  });
   browser.selectedTab = tab;
   const mm = tab.linkedBrowser.messageManager;
   mm.loadFrameScript(
     "chrome://devtools/content/performance-new/frame-script.js",
     false
   );
   mm.sendAsyncMessage("devtools:perf-html-transfer-profile", profile);
 }
--- a/devtools/client/preferences/devtools-client.js
+++ b/devtools/client/preferences/devtools-client.js
@@ -321,8 +321,15 @@ pref("devtools.responsive.reloadNotifica
 pref("devtools.aboutdebugging.new-enabled", false);
 
 // about:debugging: only show system add-ons in local builds by default.
 #ifdef MOZILLA_OFFICIAL
   pref("devtools.aboutdebugging.showSystemAddons", false);
 #else
   pref("devtools.aboutdebugging.showSystemAddons", true);
 #endif
+
+// Map top-level await expressions in the console
+#if defined(RELEASE_OR_BETA)
+pref("devtools.debugger.features.map-await-expression", false);
+#else
+pref("devtools.debugger.features.map-await-expression", true);
+#endif
--- a/devtools/client/responsive.html/browser/swap.js
+++ b/devtools/client/responsive.html/browser/swap.js
@@ -2,16 +2,17 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 
 const { Ci } = require("chrome");
 const { E10SUtils } = require("resource://gre/modules/E10SUtils.jsm");
 const { tunnelToInnerBrowser } = require("./tunnel");
+const Services = require("Services");
 
 function debug(msg) {
   // console.log(`RDM swap: ${msg}`);
 }
 
 /**
  * Swap page content from an existing tab into a new browser within a container
  * page.  Page state is preserved by using `swapFrameLoaders`, just like when
@@ -53,17 +54,20 @@ function swapToInnerBrowser({ tab, conta
 
   // A version of `gBrowser.addTab` that absorbs the `TabOpen` event.
   // The swap process uses a temporary tab, and there's no real need for others to hear
   // about it.  This hides the temporary tab from things like WebExtensions.
   const addTabSilently = (uri, options) => {
     browserWindow.addEventListener("TabOpen", event => {
       event.stopImmediatePropagation();
     }, { capture: true, once: true });
-    return gBrowser.addTab(uri, options);
+    options.triggeringPrincipal = Services.scriptSecurityManager.createNullPrincipal({
+      userContextId: options.userContextId,
+    });
+    return gBrowser.addWebTab(uri, options);
   };
 
   // A version of `gBrowser.swapBrowsersAndCloseOther` that absorbs the `TabClose` event.
   // The swap process uses a temporary tab, and there's no real need for others to hear
   // about it.  This hides the temporary tab from things like WebExtensions.
   const swapBrowsersAndCloseOtherSilently = (ourTab, otherTab) => {
     browserWindow.addEventListener("TabClose", event => {
       event.stopImmediatePropagation();
--- a/devtools/client/styleeditor/test/head.js
+++ b/devtools/client/styleeditor/test/head.js
@@ -23,17 +23,17 @@ const TEST_HOST = "mochi.test:8888";
  */
 var addTab = function(url, win) {
   info("Adding a new tab with URL: '" + url + "'");
 
   return new Promise(resolve => {
     const targetWindow = win || window;
     const targetBrowser = targetWindow.gBrowser;
 
-    const tab = targetBrowser.selectedTab = targetBrowser.addTab(url);
+    const tab = targetBrowser.selectedTab = BrowserTestUtils.addTab(targetBrowser, url);
     BrowserTestUtils.browserLoaded(targetBrowser.selectedBrowser)
       .then(function() {
         info("URL '" + url + "' loading complete");
         resolve(tab);
       });
   });
 };
 
--- a/devtools/client/webconsole/test/mochitest/browser_console_webconsole_private_browsing.js
+++ b/devtools/client/webconsole/test/mochitest/browser_console_webconsole_private_browsing.js
@@ -26,17 +26,17 @@ const PRIVATE_TEST_URI = `data:text/html
   </script>`;
 
 add_task(async function() {
   await addTab(NON_PRIVATE_TEST_URI);
 
   const privateWindow = await openNewBrowserWindow({ private: true });
   ok(PrivateBrowsingUtils.isWindowPrivate(privateWindow), "window is private");
   const privateBrowser = privateWindow.gBrowser;
-  privateBrowser.selectedTab = privateBrowser.addTab(PRIVATE_TEST_URI);
+  privateBrowser.selectedTab = BrowserTestUtils.addTab(privateBrowser, PRIVATE_TEST_URI);
   const privateTab = privateBrowser.selectedTab;
 
   info("private tab opened");
   ok(PrivateBrowsingUtils.isBrowserPrivate(privateBrowser.selectedBrowser),
     "tab window is private");
 
   let hud = await openConsole(privateTab);
   ok(hud, "web console opened");
--- a/devtools/startup/devtools-startup.js
+++ b/devtools/startup/devtools-startup.js
@@ -686,17 +686,17 @@ DevToolsStartup.prototype = {
       params.push("keyid=" + keyId);
     }
 
     if (params.length > 0) {
       url += "?" + params.join("&");
     }
 
     // Set relatedToCurrent: true to open the tab next to the current one.
-    gBrowser.selectedTab = gBrowser.addTab(url, {relatedToCurrent: true});
+    gBrowser.selectedTab = gBrowser.addTrustedTab(url, {relatedToCurrent: true});
   },
 
   handleConsoleFlag: function(cmdLine) {
     const window = Services.wm.getMostRecentWindow("devtools:webconsole");
     if (!window) {
       const require = this.initDevTools("CommandLine");
       const { HUDService } = require("devtools/client/webconsole/hudservice");
       HUDService.toggleBrowserConsole().catch(console.error);
--- a/devtools/startup/tests/browser/browser_shim_disable_devtools.js
+++ b/devtools/startup/tests/browser/browser_shim_disable_devtools.js
@@ -29,17 +29,18 @@ add_task(async function() {
     CustomizableUI.removeWidgetFromArea("developer-button");
   }
 
   info("Open a new window, all window-specific hooks for DevTools will be disabled.");
   const win = OpenBrowserWindow({private: false});
   await waitForDelayedStartupFinished(win);
 
   info("Open a new tab on the new window to ensure the focus is on the new window");
-  const tab = win.gBrowser.addTab("data:text/html;charset=utf-8,<title>foo</title>");
+  const tab = BrowserTestUtils.addTab(win.gBrowser,
+    "data:text/html;charset=utf-8,<title>foo</title>");
   await BrowserTestUtils.browserLoaded(win.gBrowser.getBrowserForTab(tab));
 
   info("Synthesize a DevTools shortcut, the toolbox should not open on this new window.");
   synthesizeToggleToolboxKey(win);
 
   // There is no event to wait for here as this shortcut should have no effect.
   /* eslint-disable mozilla/no-arbitrary-setTimeout */
   await new Promise(r => setTimeout(r, 1000));
--- a/docshell/base/nsDocShell.cpp
+++ b/docshell/base/nsDocShell.cpp
@@ -945,16 +945,17 @@ nsDocShell::LoadURI(nsIURI* aURI,
     else {
       triggeringPrincipal = nsContentUtils::GetSystemPrincipal();
     }
   }
 
   uint32_t flags = 0;
 
   if (inheritPrincipal) {
+    MOZ_ASSERT(!nsContentUtils::IsSystemPrincipal(principalToInherit), "Should not inherit SystemPrincipal");
     flags |= INTERNAL_LOAD_FLAGS_INHERIT_PRINCIPAL;
   }
 
   if (!sendReferrer) {
     flags |= INTERNAL_LOAD_FLAGS_DONT_SEND_REFERRER;
   }
 
   if (aLoadFlags & LOAD_FLAGS_ALLOW_THIRD_PARTY_FIXUP) {
@@ -1694,18 +1695,18 @@ nsDocShell::GetUseRemoteTabs(bool* aUseR
   *aUseRemoteTabs = mUseRemoteTabs;
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsDocShell::SetRemoteTabs(bool aUseRemoteTabs)
 {
   if (aUseRemoteTabs) {
-    CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("DOMIPCEnabled"),
-                                       NS_LITERAL_CSTRING("1"));
+    CrashReporter::AnnotateCrashReport(CrashReporter::Annotation::DOMIPCEnabled,
+                                       true);
   }
 
   mUseRemoteTabs = aUseRemoteTabs;
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsDocShell::SetAffectPrivateSessionLifetime(bool aAffectLifetime)
--- a/docshell/test/browser/head.js
+++ b/docshell/test/browser/head.js
@@ -43,17 +43,18 @@ function timelineTestOpenUrl(url) {
 
   let tabSwitchPromise = new Promise((resolve, reject) => {
     window.gBrowser.addEventListener("TabSwitchDone", function() {
       resolve();
     }, {once: true});
   });
 
   let loadPromise = new Promise(function(resolve, reject) {
-    let tab = window.gBrowser.selectedTab = window.gBrowser.addTab(url);
+    let browser = window.gBrowser;
+    let tab = browser.selectedTab = BrowserTestUtils.addTab(browser, url);
     let linkedBrowser = tab.linkedBrowser;
 
     BrowserTestUtils.browserLoaded(linkedBrowser).then(() => resolve(tab));
   });
 
   return Promise.all([tabSwitchPromise, loadPromise]).then(([_, tab]) => tab);
 }
 
--- a/dom/base/nsFocusManager.cpp
+++ b/dom/base/nsFocusManager.cpp
@@ -3593,34 +3593,37 @@ nsFocusManager::GetNextTabbableContent(n
 
     // Walk frames to find something tabbable matching mCurrentTabIndex
     nsIFrame* frame = static_cast<nsIFrame*>(frameTraversal->CurrentItem());
     while (frame) {
       // Try to find the topmost Shadow DOM host, since we want to
       // skip Shadow DOM in frame traversal.
       nsIContent* currentContent = frame->GetContent();
       nsIContent* oldTopLevelHost = currentTopLevelHost;
-      nsIContent* topLevel = GetTopLevelHost(currentContent);
-      currentTopLevelHost = topLevel;
-      if (topLevel) {
-        if (topLevel == oldTopLevelHost) {
+      if (oldTopLevelHost != currentContent) {
+        currentTopLevelHost = GetTopLevelHost(currentContent);
+      } else {
+        currentTopLevelHost = currentContent;
+      }
+      if (currentTopLevelHost) {
+        if (currentTopLevelHost == oldTopLevelHost) {
           // We're within Shadow DOM, continue.
           do {
             if (aForward) {
               frameTraversal->Next();
             } else {
               frameTraversal->Prev();
             }
             frame = static_cast<nsIFrame*>(frameTraversal->CurrentItem());
             // For the usage of GetPrevContinuation, see the comment
             // at the end of while (frame) loop.
           } while (frame && frame->GetPrevContinuation());
           continue;
         }
-        currentContent = topLevel;
+        currentContent = currentTopLevelHost;
       }
 
       // For document navigation, check if this element is an open panel. Since
       // panels aren't focusable (tabIndex would be -1), we'll just assume that
       // for document navigation, the tabIndex is 0.
       if (aForDocumentNavigation && currentContent && (aCurrentTabIndex == 0) &&
           currentContent->IsXULElement(nsGkAtoms::panel)) {
         nsMenuPopupFrame* popupFrame = do_QueryFrame(frame);
--- a/dom/base/nsIContentPolicy.idl
+++ b/dom/base/nsIContentPolicy.idl
@@ -343,20 +343,21 @@ interface nsIContentPolicy : nsISupports
 
   /**
    * Indicates a speculative connection.
    */
   const nsContentPolicyType TYPE_SPECULATIVE = 44;
 
   /* When adding new content types, please update nsContentBlocker,
    * NS_CP_ContentTypeName, nsCSPContext, CSP_ContentTypeToDirective,
-   * DoContentSecurityChecks, all nsIContentPolicy implementations, the
-   * static_assert in dom/cache/DBSchema.cpp, ChannelWrapper.webidl,
-   * ChannelWrapper.cpp, nsPermissionManager.cpp, and other things that are not
-   * listed here that are related to nsIContentPolicy. */
+   * DoContentSecurityChecks, IsContentPolicyTypeWhitelistedForFastBlock,
+   * all nsIContentPolicy implementations, the static_assert in
+   * dom/cache/DBSchema.cpp, ChannelWrapper.webidl, ChannelWrapper.cpp,
+   * nsPermissionManager.cpp, and other things that are not listed here
+   * that are related to nsIContentPolicy. */
 
   //////////////////////////////////////////////////////////////////////
 
   /**
    * Returned from shouldLoad or shouldProcess if the load or process request
    * is rejected based on details of the request.
    */
   const short REJECT_REQUEST = -1;
--- a/dom/base/test/browser_blocking_image.js
+++ b/dom/base/test/browser_blocking_image.js
@@ -1,15 +1,15 @@
 const TEST_URI = getRootDirectory(gTestPath).replace("chrome://mochitests/content", "https://example.com") + "file_blocking_image.html";
 
 /**
  * Loading an image from https:// should work.
  */
 add_task(async function load_image_from_https_test() {
-  let tab = gBrowser.addTab(TEST_URI);
+  let tab = BrowserTestUtils.addTab(gBrowser, TEST_URI);
   await BrowserTestUtils.browserLoaded(tab.linkedBrowser);
 
   gBrowser.selectedTab = tab;
 
   await ContentTask.spawn(tab.linkedBrowser, { }, async function() {
     function imgListener(img) {
       return new Promise((resolve, reject) => {
         img.addEventListener("load", () => resolve());
@@ -33,17 +33,17 @@ add_task(async function load_image_from_
 
   gBrowser.removeTab(tab);
 });
 
 /**
  * Loading an image from http:// should be rejected.
  */
 add_task(async function load_image_from_http_test() {
-  let tab = gBrowser.addTab(TEST_URI);
+  let tab = BrowserTestUtils.addTab(gBrowser, TEST_URI);
   await BrowserTestUtils.browserLoaded(tab.linkedBrowser);
 
   gBrowser.selectedTab = tab;
 
   await ContentTask.spawn(tab.linkedBrowser, { }, async function () {
     function imgListener(img) {
       return new Promise((resolve, reject) => {
         img.addEventListener("load", () => reject());
@@ -69,17 +69,17 @@ add_task(async function load_image_from_
   gBrowser.removeTab(tab);
 });
 
 /**
  * Loading an image from http:// immediately after loading from https://
  * The load from https:// should be replaced.
  */
 add_task(async function load_https_and_http_test() {
-  let tab = gBrowser.addTab(TEST_URI);
+  let tab = BrowserTestUtils.addTab(gBrowser, TEST_URI);
   await BrowserTestUtils.browserLoaded(tab.linkedBrowser);
 
   // Clear image cache, otherwise in non-e10s mode the image might be cached by
   // previous test, and make the image from https is loaded immediately.
   let imgTools = Cc["@mozilla.org/image/tools;1"].getService(Ci.imgITools);
   let imageCache = imgTools.getImgCacheForDocument(window.document);
   imageCache.clearCache(false); // false=content
 
@@ -116,17 +116,17 @@ add_task(async function load_https_and_h
 /**
  * Loading an image from https.
  * Then after we have size information of the image, we immediately change the
  * location to a http:// site (hence should be blocked by CSP). This will make
  * the 2nd request as a PENDING_REQUEST, also blocking 2nd load shouldn't change
  * the imageBlockingStatus value.
  */
 add_task(async function block_pending_request_test() {
-  let tab = gBrowser.addTab(TEST_URI);
+  let tab = BrowserTestUtils.addTab(gBrowser, TEST_URI);
   await BrowserTestUtils.browserLoaded(tab.linkedBrowser);
 
   gBrowser.selectedTab = tab;
 
   await ContentTask.spawn(tab.linkedBrowser, { }, async function () {
     let wrapper = {
       _resolve: null,
       _sizeAvail: false,
--- a/dom/base/test/file_bug1453693.html
+++ b/dom/base/test/file_bug1453693.html
@@ -249,31 +249,86 @@
 
         // Backwards
         synthesizeKey("KEY_Tab", {shiftKey: true});
         opener.is(lastFocusTarget, shadowInput1, "Should have focused input element. (3)");
 
         // Back to beginning, outside of Shadow DOM.
         synthesizeKey("KEY_Tab", {shiftKey: true});
         opener.is(document.activeElement, document.body.firstChild, "body's first child should have focus. (2)");
+
+        host.remove();
+      }
+
+      function testTabbingThroughLightDOMShadowDOMLightDOM() {
+        opener.is(document.activeElement, document.body.firstChild,
+                  "body's first child should have focus.");
+
+        var host = document.createElement("span");
+        host.innerHTML = "\n";
+        host.id = "host";
+        document.body.appendChild(host);
+
+        var sr0 = host.attachShadow({mode: "open"});
+        sr0.innerHTML = document.getElementById("template").innerHTML;
+        var p1 = sr0.getElementById("p1");
+        p1.onfocus = focusLogger;
+        var p2 = sr0.getElementById("p2");
+        p2.onfocus = focusLogger;
+
+        var p = document.createElement("p");
+        p.innerHTML = " <a href='#p'>link 1</a> ";
+        var a = p.firstElementChild;
+        a.onfocus = focusLogger;
+        document.body.appendChild(p);
+
+        document.body.offsetLeft;
+
+        synthesizeKey("KEY_Tab");
+        opener.is(lastFocusTarget, p1, "Should have focused p1.");
+
+        synthesizeKey("KEY_Tab");
+        opener.is(lastFocusTarget, p2, "Should have focused p2.");
+
+        synthesizeKey("KEY_Tab");
+        opener.is(lastFocusTarget, a, "Should have focused a.");
+
+        // Backwards
+        synthesizeKey("KEY_Tab", {shiftKey: true});
+        opener.is(lastFocusTarget, p2, "Should have focused p2.");
+
+        synthesizeKey("KEY_Tab", {shiftKey: true});
+        opener.is(lastFocusTarget, p1, "Should have focused p1.");
+
+        synthesizeKey("KEY_Tab", {shiftKey: true});
+        opener.is(document.activeElement, document.body.firstChild,
+                  "body's first child should have focus.");
+
+        host.remove();
+        p.remove();
       }
 
       function runTest() {
 
         testTabbingThroughShadowDOMWithTabIndexes();
         testTabbingThroughSimpleShadowDOM();
         testTabbingThroughNestedShadowDOM();
         testTabbingThroughDisplayContentsHost();
+        testTabbingThroughLightDOMShadowDOMLightDOM();
 
         opener.didRunTests();
         window.close();
       }
 
       function init() {
         SimpleTest.waitForFocus(runTest);
       }
     </script>
     <style>
     </style>
+    <template id="template">
+      <p tabindex="0" id="p1">component</p>
+      <p tabindex="0" id="p2">/component</p>
+    </template>
   </head>
   <body onload="init()">
   </body>
 </html>
--- a/dom/bindings/parser/tests/test_toJSON.py
+++ b/dom/bindings/parser/tests/test_toJSON.py
@@ -78,24 +78,115 @@ def WebIDLTest(parser, harness):
               [Default] long toJSON();
             };
             """)
         results = parser.finish()
     except:
         threw = True
     harness.ok(threw, "Should not allow a default toJSON method with non-'object' as return type.")
 
-    parser = parser.reset()
-    threw = False
-    try:
-        parser.parse(
-            """
-            interface Test {
-              any toJSON();
-            };
-            """)
-        results = parser.finish()
-    except:
-        threw = True
-    harness.ok(threw, "Should not allow a toJSON method with a non-JSON return type.")
+    JsonTypes = [ "byte", "octet", "short", "unsigned short", "long", "unsigned long", "long long",
+                  "unsigned long long", "float", "unrestricted float", "double", "unrestricted double", "boolean",
+                  "DOMString", "ByteString", "USVString", "Enum", "InterfaceWithToJSON", "object" ]
+
+    nonJsonTypes = [ "InterfaceWithoutToJSON", "any", "Int8Array", "Int16Array", "Int32Array","Uint8Array",
+                     "Uint16Array", "Uint32Array", "Uint8ClampedArray", "Float32Array", "Float64Array", "ArrayBuffer" ]
+
+    def doTest(testIDL, shouldThrow, description):
+        p = parser.reset()
+        threw = False
+        try:
+            p.parse(testIDL +
+                """
+                enum Enum { "a", "b", "c" };
+                interface InterfaceWithToJSON { long toJSON(); };
+                interface InterfaceWithoutToJSON {};
+                """);
+            p.finish();
+        except Exception as x:
+            threw = True
+            harness.ok(x.message == "toJSON method has non-JSON return type", x)
+        harness.check(threw, shouldThrow, description)
+
+
+    for type in JsonTypes:
+        doTest("interface Test { %s toJSON(); };" % type, False,
+               "%s should be a JSON type" % type)
+
+        doTest("interface Test { sequence<%s> toJSON(); };" % type, False,
+               "sequence<%s> should be a JSON type" % type)
+
+        doTest("dictionary Foo { %s foo; }; "
+               "interface Test { Foo toJSON(); }; " % type, False,
+               "dictionary containing only JSON type (%s) should be a JSON type" % type)
+
+        doTest("dictionary Foo { %s foo; }; dictionary Bar : Foo { }; "
+               "interface Test { Bar toJSON(); }; " % type, False,
+               "dictionary whose ancestors only contain JSON types should be a JSON type")
+
+        doTest("dictionary Foo { any foo; }; dictionary Bar : Foo { %s bar; };"
+               "interface Test { Bar toJSON(); };" % type, True,
+               "dictionary whose ancestors contain non-JSON types should not be a JSON type")
+
+        doTest("interface Test { record<DOMString, %s> toJSON(); };" % type, False,
+               "record<DOMString, %s> should be a JSON type" % type)
+
+        doTest("interface Test { record<ByteString, %s> toJSON(); };" % type, False, 
+               "record<ByteString, %s> should be a JSON type" % type)
+
+        doTest("interface Test { record<USVString, %s> toJSON(); };" % type, False,
+               "record<USVString, %s> should be a JSON type" % type)
 
-    # We should probably write some tests here about what types are
-    # considered JSON types.  Bug 1462537.
+        otherUnionType = "Foo" if type != "object" else "long"
+        doTest("interface Foo { object toJSON(); };"
+               "interface Test { (%s or %s) toJSON(); };" % (otherUnionType, type), False,
+               "union containing only JSON types (%s or %s) should be a JSON type" %(otherUnionType, type))
+
+        doTest("interface test { %s? toJSON(); };" % type, False,
+               "Nullable type (%s) should be a JSON type" % type)
+
+        doTest("interface Foo : InterfaceWithoutToJSON { %s toJSON(); };"
+               "interface Test { Foo toJSON(); };" % type, False,
+               "interface with toJSON should be a JSON type")
+
+    doTest("interface Foo : InterfaceWithToJSON { };"
+           "interface Test { Foo toJSON(); };", False,
+           "inherited interface with toJSON should be a JSON type")
+
+    for type in nonJsonTypes:
+        doTest("interface Test { %s toJSON(); };" % type, True,
+               "%s should not be a JSON type" % type)
+
+        doTest("interface Test { sequence<%s> toJSON(); };" % type, True,
+               "sequence<%s> should not be a JSON type" % type)
+
+        doTest("dictionary Foo { %s foo; }; "
+               "interface Test { Foo toJSON(); }; " % type, True, 
+               "Dictionary containing a non-JSON type (%s) should not be a JSON type" % type)
+
+        doTest("dictionary Foo { %s foo; }; dictionary Bar : Foo { }; "
+               "interface Test { Bar toJSON(); }; " % type, True,
+               "dictionary whose ancestors only contain non-JSON types should not be a JSON type")
+
+        doTest("interface Test { record<DOMString, %s> toJSON(); };" % type, True,
+               "record<DOMString, %s> should not be a JSON type" % type)
+
+        doTest("interface Test { record<ByteString, %s> toJSON(); };" % type, True,
+               "record<ByteString, %s> should not be a JSON type" % type)
+
+        doTest("interface Test { record<USVString, %s> toJSON(); };" % type, True,
+               "record<USVString, %s> should not be a JSON type" % type)
+        
+        if type != "any":
+            doTest("interface Foo { object toJSON(); }; "
+                   "interface Test { (Foo or %s) toJSON(); };" % type, True,
+                   "union containing a non-JSON type (%s) should not be a JSON type" % type)
+        
+            doTest("interface test { %s? toJSON(); };" % type, True,
+                   "Nullable type (%s) should not be a JSON type" % type)
+
+    doTest("dictionary Foo { long foo; any bar; };"
+           "interface Test { Foo toJSON(); };", True,
+           "dictionary containing a non-JSON type should not be a JSON type")
+
+    doTest("interface Foo : InterfaceWithoutToJSON { }; "
+           "interface Test { Foo toJSON(); };", True, 
+           "interface without toJSON should not be a JSON type")
--- a/dom/broadcastchannel/tests/browser_private_browsing.js
+++ b/dom/broadcastchannel/tests/browser_private_browsing.js
@@ -15,21 +15,21 @@ add_task(async function() {
   var win2 = OpenBrowserWindow({private: false});
   var win2Promise = new win2.Promise(resolve => {
     win2.addEventListener("load", function() {
       resolve();
     }, {once: true});
   });
   await win2Promise;
 
-  var tab1 = win1.gBrowser.addTab(URL);
+  var tab1 = BrowserTestUtils.addTab(win1.gBrowser, URL);
   await BrowserTestUtils.browserLoaded(win1.gBrowser.getBrowserForTab(tab1));
   var browser1 = gBrowser.getBrowserForTab(tab1);
 
-  var tab2 = win2.gBrowser.addTab(URL);
+  var tab2 = BrowserTestUtils.addTab(win2.gBrowser, URL);
   await BrowserTestUtils.browserLoaded(win2.gBrowser.getBrowserForTab(tab2));
   var browser2 = gBrowser.getBrowserForTab(tab2);
 
   var p1 = ContentTask.spawn(browser1, null, function(opts) {
     return new content.window.Promise(resolve => {
       content.window.bc = new content.window.BroadcastChannel('foobar');
       content.window.bc.onmessage = function(e) { resolve(e.data); }
     });
--- a/dom/cache/test/mochitest/browser_cache_pb_window.js
+++ b/dom/cache/test/mochitest/browser_cache_pb_window.js
@@ -100,17 +100,17 @@ function test() {
   let privateWin, privateTab;
   waitForExplicitFinish();
   SpecialPowers.pushPrefEnv({'set': [['dom.caches.enabled', true],
                                      ['dom.caches.testing.enabled', true]]}
   ).then(() => {
     return BrowserTestUtils.openNewBrowserWindow({private: true});
   }).then(pw => {
     privateWin = pw;
-    privateTab = pw.gBrowser.addTab("http://example.com/");
+    privateTab = BrowserTestUtils.addTab(pw.gBrowser, "http://example.com/");
     return BrowserTestUtils.browserLoaded(privateTab.linkedBrowser);
   }).then(tab => {
     return Promise.all([
       testMatch(privateTab.linkedBrowser),
       testHas(privateTab.linkedBrowser),
       testOpen(privateTab.linkedBrowser),
       testDelete(privateTab.linkedBrowser),
       testKeys(privateTab.linkedBrowser),
--- a/dom/canvas/TexUnpackBlob.cpp
+++ b/dom/canvas/TexUnpackBlob.cpp
@@ -62,22 +62,20 @@ IsPIValidForDOM(const webgl::PackingInfo
     default:
         return false;
     }
 
     return true;
 }
 
 static bool
-ValidatePIForDOM(WebGLContext* webgl, const char* funcName,
-                 const webgl::PackingInfo& pi)
+ValidatePIForDOM(WebGLContext* webgl, const webgl::PackingInfo& pi)
 {
     if (!IsPIValidForDOM(pi)) {
-        webgl->ErrorInvalidOperation("%s: Format or type is invalid for DOM sources.",
-                                     funcName);
+        webgl->ErrorInvalidOperation("Format or type is invalid for DOM sources.");
         return false;
     }
     return true;
 }
 
 static WebGLTexelFormat
 FormatForPackingInfo(const PackingInfo& pi)
 {
@@ -174,91 +172,89 @@ FormatForPackingInfo(const PackingInfo& 
     }
 
     return WebGLTexelFormat::FormatNotSupportingAnyConversion;
 }
 
 ////////////////////
 
 static bool
-ValidateUnpackPixels(WebGLContext* webgl, const char* funcName, uint32_t fullRows,
+ValidateUnpackPixels(WebGLContext* webgl, uint32_t fullRows,
                      uint32_t tailPixels, webgl::TexUnpackBlob* blob)
 {
     if (!blob->mWidth || !blob->mHeight || !blob->mDepth)
         return true;
 
     const auto usedPixelsPerRow = CheckedUint32(blob->mSkipPixels) + blob->mWidth;
     if (!usedPixelsPerRow.isValid() || usedPixelsPerRow.value() > blob->mRowLength) {
-        webgl->ErrorInvalidOperation("%s: UNPACK_SKIP_PIXELS + width >"
-                                     " UNPACK_ROW_LENGTH.",
-                                     funcName);
+        webgl->ErrorInvalidOperation("UNPACK_SKIP_PIXELS + width >"
+                                     " UNPACK_ROW_LENGTH.");
         return false;
     }
 
     if (blob->mHeight > blob->mImageHeight) {
-        webgl->ErrorInvalidOperation("%s: height > UNPACK_IMAGE_HEIGHT.", funcName);
+        webgl->ErrorInvalidOperation("height > UNPACK_IMAGE_HEIGHT.");
         return false;
     }
 
     //////
 
     // The spec doesn't bound SKIP_ROWS + height <= IMAGE_HEIGHT, unfortunately.
     auto skipFullRows = CheckedUint32(blob->mSkipImages) * blob->mImageHeight;
     skipFullRows += blob->mSkipRows;
 
     MOZ_ASSERT(blob->mDepth >= 1);
     MOZ_ASSERT(blob->mHeight >= 1);
     auto usedFullRows = CheckedUint32(blob->mDepth - 1) * blob->mImageHeight;
     usedFullRows += blob->mHeight - 1; // Full rows in the final image, excluding the tail.
 
     const auto fullRowsNeeded = skipFullRows + usedFullRows;
     if (!fullRowsNeeded.isValid()) {
-        webgl->ErrorOutOfMemory("%s: Invalid calculation for required row count.",
-                                funcName);
+        webgl->ErrorOutOfMemory("Invalid calculation for required row count.");
         return false;
     }
 
     if (fullRows > fullRowsNeeded.value())
         return true;
 
     if (fullRows == fullRowsNeeded.value() && tailPixels >= usedPixelsPerRow.value()) {
         blob->mNeedsExactUpload = true;
         return true;
     }
 
-    webgl->ErrorInvalidOperation("%s: Desired upload requires more data than is"
+    webgl->ErrorInvalidOperation("Desired upload requires more data than is"
                                  " available: (%u rows plus %u pixels needed, %u rows"
                                  " plus %u pixels available)",
-                                 funcName, fullRowsNeeded.value(),
+                                 fullRowsNeeded.value(),
                                  usedPixelsPerRow.value(), fullRows, tailPixels);
     return false;
 }
 
 static bool
-ValidateUnpackBytes(WebGLContext* webgl, const char* funcName,
+ValidateUnpackBytes(WebGLContext* webgl,
                     const webgl::PackingInfo& pi, size_t availByteCount,
                     webgl::TexUnpackBlob* blob)
 {
     if (!blob->mWidth || !blob->mHeight || !blob->mDepth)
         return true;
 
     const auto bytesPerPixel = webgl::BytesPerPixel(pi);
     const auto bytesPerRow = CheckedUint32(blob->mRowLength) * bytesPerPixel;
     const auto rowStride = RoundUpToMultipleOf(bytesPerRow, blob->mAlignment);
 
     const auto fullRows = availByteCount / rowStride;
     if (!fullRows.isValid()) {
-        webgl->ErrorOutOfMemory("%s: Unacceptable upload size calculated.", funcName);
+        webgl->ErrorOutOfMemory("Unacceptable upload size calculated.");
         return false;
     }
 
     const auto bodyBytes = fullRows.value() * rowStride.value();
     const auto tailPixels = (availByteCount - bodyBytes) / bytesPerPixel;
 
-    return ValidateUnpackPixels(webgl, funcName, fullRows.value(), tailPixels, blob);
+    return ValidateUnpackPixels(webgl, fullRows.value(), tailPixels, blob);
 }
 
 ////////////////////
 
 static uint32_t
 ZeroOn2D(TexImageTarget target, uint32_t val)
 {
     return (IsTarget3D(target) ? val : 0);
@@ -308,17 +304,17 @@ HasColorAndAlpha(const WebGLTexelFormat 
     case WebGLTexelFormat::BGRA8:
         return true;
     default:
         return false;
     }
 }
 
 bool
-TexUnpackBlob::ConvertIfNeeded(WebGLContext* webgl, const char* funcName,
+TexUnpackBlob::ConvertIfNeeded(WebGLContext* webgl,
                                const uint32_t rowLength, const uint32_t rowCount,
                                WebGLTexelFormat srcFormat,
                                const uint8_t* const srcBegin, const ptrdiff_t srcStride,
                                WebGLTexelFormat dstFormat, const ptrdiff_t dstStride,
                                const uint8_t** const out_begin,
                                UniqueBuffer* const out_anchoredBuffer) const
 {
     MOZ_ASSERT(srcFormat != WebGLTexelFormat::FormatNotSupportingAnyConversion);
@@ -341,57 +337,56 @@ TexUnpackBlob::ConvertIfNeeded(WebGLCont
         return srcIsPremult != dstIsPremult;
     };
 
     const auto srcOrigin = (webgl->mPixelStore_FlipY ? gl::OriginPos::TopLeft
                                                      : gl::OriginPos::BottomLeft);
     const auto dstOrigin = gl::OriginPos::BottomLeft;
 
     if (srcFormat != dstFormat) {
-        webgl->GeneratePerfWarning("%s: Conversion requires pixel reformatting. (%u->%u)",
-                                   funcName, uint32_t(srcFormat),
+        webgl->GeneratePerfWarning("Conversion requires pixel reformatting. (%u->%u)",
+                                   uint32_t(srcFormat),
                                    uint32_t(dstFormat));
     } else if (fnHasPremultMismatch()) {
-        webgl->GeneratePerfWarning("%s: Conversion requires change in"
-                                   " alpha-premultiplication.",
-                                   funcName);
+        webgl->GeneratePerfWarning("Conversion requires change in"
+                                   " alpha-premultiplication.");
     } else if (srcOrigin != dstOrigin) {
-        webgl->GeneratePerfWarning("%s: Conversion requires y-flip.", funcName);
+        webgl->GeneratePerfWarning("Conversion requires y-flip.");
     } else if (srcStride != dstStride) {
-        webgl->GeneratePerfWarning("%s: Conversion requires change in stride. (%u->%u)",
-                                   funcName, uint32_t(srcStride), uint32_t(dstStride));
+        webgl->GeneratePerfWarning("Conversion requires change in stride. (%u->%u)",
+                                   uint32_t(srcStride), uint32_t(dstStride));
     } else {
         return true;
     }
 
     ////
 
     const auto dstTotalBytes = CheckedUint32(rowCount) * dstStride;
     if (!dstTotalBytes.isValid()) {
-        webgl->ErrorOutOfMemory("%s: Calculation failed.", funcName);
+        webgl->ErrorOutOfMemory("Calculation failed.");
         return false;
     }
 
     UniqueBuffer dstBuffer = calloc(1, dstTotalBytes.value());
     if (!dstBuffer.get()) {
-        webgl->ErrorOutOfMemory("%s: Failed to allocate dest buffer.", funcName);
+        webgl->ErrorOutOfMemory("Failed to allocate dest buffer.");
         return false;
     }
     const auto dstBegin = static_cast<uint8_t*>(dstBuffer.get());
 
     ////
 
     // And go!:
     bool wasTrivial;
     if (!ConvertImage(rowLength, rowCount,
                       srcBegin, srcStride, srcOrigin, srcFormat, srcIsPremult,
                       dstBegin, dstStride, dstOrigin, dstFormat, dstIsPremult,
                       &wasTrivial))
     {
-        webgl->ErrorImplementationBug("%s: ConvertImage failed.", funcName);
+        webgl->ErrorImplementationBug("ConvertImage failed.");
         return false;
     }
 
     *out_begin = dstBegin;
     *out_anchoredBuffer = std::move(dstBuffer);
     return true;
 }
 
@@ -418,27 +413,26 @@ TexUnpackBytes::TexUnpackBytes(const Web
                     FallbackOnZero(webgl->mPixelStore_UnpackRowLength, width),
                     width, height, depth, gfxAlphaType::NonPremult)
     , mIsClientData(isClientData)
     , mPtr(ptr)
     , mAvailBytes(availBytes)
 { }
 
 bool
-TexUnpackBytes::Validate(WebGLContext* webgl, const char* funcName,
-                         const webgl::PackingInfo& pi)
+TexUnpackBytes::Validate(WebGLContext* webgl, const webgl::PackingInfo& pi)
 {
     if (mIsClientData && !mPtr)
         return true;
 
-    return ValidateUnpackBytes(webgl, funcName, pi, mAvailBytes, this);
+    return ValidateUnpackBytes(webgl, pi, mAvailBytes, this);
 }
 
 bool
-TexUnpackBytes::TexOrSubImage(bool isSubImage, bool needsRespec, const char* funcName,
+TexUnpackBytes::TexOrSubImage(bool isSubImage, bool needsRespec,
                               WebGLTexture* tex, TexImageTarget target, GLint level,
                               const webgl::DriverUnpackInfo* dui, GLint xOffset,
                               GLint yOffset, GLint zOffset, const webgl::PackingInfo& pi,
                               GLenum* const out_error) const
 {
     WebGLContext* webgl = tex->mContext;
 
     const auto format = FormatForPackingInfo(pi);
@@ -458,46 +452,43 @@ TexUnpackBytes::TexOrSubImage(bool isSub
         }
 
         if (webgl->mPixelStore_UnpackImageHeight ||
             webgl->mPixelStore_UnpackSkipImages ||
             webgl->mPixelStore_UnpackRowLength ||
             webgl->mPixelStore_UnpackSkipRows ||
             webgl->mPixelStore_UnpackSkipPixels)
         {
-            webgl->ErrorInvalidOperation("%s: Non-DOM-Element uploads with alpha-premult"
-                                         " or y-flip do not support subrect selection.",
-                                         funcName);
+            webgl->ErrorInvalidOperation("Non-DOM-Element uploads with alpha-premult"
+                                         " or y-flip do not support subrect selection.");
             return false;
         }
 
-        webgl->GenerateWarning("%s: Alpha-premult and y-flip are deprecated for"
-                               " non-DOM-Element uploads.",
-                               funcName);
+        webgl->GenerateWarning("Alpha-premult and y-flip are deprecated for"
+                               " non-DOM-Element uploads.");
 
         const uint32_t rowLength = mWidth;
         const uint32_t rowCount = mHeight * mDepth;
         const auto stride = RoundUpToMultipleOf(rowLength * bytesPerPixel, mAlignment);
-        if (!ConvertIfNeeded(webgl, funcName, rowLength, rowCount, format, mPtr, stride,
+        if (!ConvertIfNeeded(webgl, rowLength, rowCount, format, mPtr, stride,
                              format, stride, &uploadPtr, &tempBuffer))
         {
             return false;
         }
     } while (false);
 
     //////
 
     const auto& gl = webgl->gl;
 
     bool useParanoidHandling = false;
     if (mNeedsExactUpload && webgl->mBoundPixelUnpackBuffer) {
-        webgl->GenerateWarning("%s: Uploads from a buffer with a final row with a byte"
+        webgl->GenerateWarning("Uploads from a buffer with a final row with a byte"
                                " count smaller than the row stride can incur extra"
-                               " overhead.",
-                               funcName);
+                               " overhead.");
 
         if (gl->WorkAroundDriverBugs()) {
             useParanoidHandling |= (gl->Vendor() == gl::GLVendor::NVIDIA);
         }
     }
 
     if (!useParanoidHandling) {
         if (webgl->mBoundPixelUnpackBuffer) {
@@ -596,28 +587,27 @@ TexUnpackImage::TexUnpackImage(const Web
                     srcAlphaType)
     , mImage(image)
 { }
 
 TexUnpackImage::~TexUnpackImage()
 { }
 
 bool
-TexUnpackImage::Validate(WebGLContext* webgl, const char* funcName,
-                         const webgl::PackingInfo& pi)
+TexUnpackImage::Validate(WebGLContext* webgl, const webgl::PackingInfo& pi)
 {
-    if (!ValidatePIForDOM(webgl, funcName, pi))
+    if (!ValidatePIForDOM(webgl, pi))
         return false;
 
     const auto fullRows = mImage->GetSize().height;
-    return ValidateUnpackPixels(webgl, funcName, fullRows, 0, this);
+    return ValidateUnpackPixels(webgl, fullRows, 0, this);
 }
 
 bool
-TexUnpackImage::TexOrSubImage(bool isSubImage, bool needsRespec, const char* funcName,
+TexUnpackImage::TexOrSubImage(bool isSubImage, bool needsRespec,
                               WebGLTexture* tex, TexImageTarget target, GLint level,
                               const webgl::DriverUnpackInfo* dui, GLint xOffset,
                               GLint yOffset, GLint zOffset, const webgl::PackingInfo& pi,
                               GLenum* const out_error) const
 {
     MOZ_ASSERT_IF(needsRespec, !isSubImage);
 
     WebGLContext* webgl = tex->mContext;
@@ -709,18 +699,18 @@ TexUnpackImage::TexOrSubImage(bool isSub
             break;
         }
 
         // Blitting was successful, so we're done!
         *out_error = 0;
         return true;
     } while (false);
 
-    const nsPrintfCString perfMsg("%s: Failed to hit GPU-copy fast-path: %s (src type %u)",
-                                  funcName, fallbackReason, uint32_t(mImage->GetFormat()));
+    const nsPrintfCString perfMsg("Failed to hit GPU-copy fast-path: %s (src type %u)",
+                                  fallbackReason, uint32_t(mImage->GetFormat()));
 
     if (webgl->mPixelStore_RequireFastPath) {
         webgl->ErrorInvalidOperation("%s", perfMsg.BeginReading());
         return false;
     }
 
     webgl->GeneratePerfWarning("%s Falling back to CPU upload.",
                                perfMsg.BeginReading());
@@ -728,26 +718,25 @@ TexUnpackImage::TexOrSubImage(bool isSub
     const RefPtr<gfx::SourceSurface> surf = mImage->GetAsSourceSurface();
 
     RefPtr<gfx::DataSourceSurface> dataSurf;
     if (surf) {
         // WARNING: OSX can lose our MakeCurrent here.
         dataSurf = surf->GetDataSurface();
     }
     if (!dataSurf) {
-        webgl->ErrorOutOfMemory("%s: GetAsSourceSurface or GetDataSurface failed after"
-                                " blit failed for TexUnpackImage.",
-                                funcName);
+        webgl->ErrorOutOfMemory("GetAsSourceSurface or GetDataSurface failed after"
+                                " blit failed for TexUnpackImage.");
         return false;
     }
 
     const TexUnpackSurface surfBlob(webgl, target, mWidth, mHeight, mDepth, dataSurf,
                                     mSrcAlphaType);
 
-    return surfBlob.TexOrSubImage(isSubImage, needsRespec, funcName, tex, target, level,
+    return surfBlob.TexOrSubImage(isSubImage, needsRespec, tex, target, level,
                                   dui, xOffset, yOffset, zOffset, pi, out_error);
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////////////////
 // TexUnpackSurface
 
 TexUnpackSurface::TexUnpackSurface(const WebGLContext* webgl, TexImageTarget target,
@@ -807,28 +796,27 @@ GetFormatForSurf(gfx::SourceSurface* sur
     default:
         return false;
     }
 }
 
 //////////
 
 bool
-TexUnpackSurface::Validate(WebGLContext* webgl, const char* funcName,
-                           const webgl::PackingInfo& pi)
+TexUnpackSurface::Validate(WebGLContext* webgl, const webgl::PackingInfo& pi)
 {
-    if (!ValidatePIForDOM(webgl, funcName, pi))
+    if (!ValidatePIForDOM(webgl, pi))
         return false;
 
     const auto fullRows = mSurf->GetSize().height;
-    return ValidateUnpackPixels(webgl, funcName, fullRows, 0, this);
+    return ValidateUnpackPixels(webgl, fullRows, 0, this);
 }
 
 bool
-TexUnpackSurface::TexOrSubImage(bool isSubImage, bool needsRespec, const char* funcName,
+TexUnpackSurface::TexOrSubImage(bool isSubImage, bool needsRespec,
                                 WebGLTexture* tex, TexImageTarget target, GLint level,
                                 const webgl::DriverUnpackInfo* dui, GLint xOffset,
                                 GLint yOffset, GLint zOffset, const webgl::PackingInfo& dstPI,
                                 GLenum* const out_error) const
 {
     const auto& webgl = tex->mContext;
 
     ////
@@ -839,25 +827,25 @@ TexUnpackSurface::TexOrSubImage(bool isS
     const auto& dstBPP = webgl::BytesPerPixel(dstPI);
     const auto dstFormat = FormatForPackingInfo(dstPI);
 
     ////
 
     WebGLTexelFormat srcFormat;
     uint8_t srcBPP;
     if (!GetFormatForSurf(mSurf, &srcFormat, &srcBPP)) {
-        webgl->ErrorImplementationBug("%s: GetFormatForSurf failed for"
+        webgl->ErrorImplementationBug("GetFormatForSurf failed for"
                                       " WebGLTexelFormat::%u.",
-                                      funcName, uint32_t(mSurf->GetFormat()));
+                                      uint32_t(mSurf->GetFormat()));
         return false;
     }
 
     gfx::DataSourceSurface::ScopedMap map(mSurf, gfx::DataSourceSurface::MapType::READ);
     if (!map.IsMapped()) {
-        webgl->ErrorOutOfMemory("%s: Failed to map source surface for upload.", funcName);
+        webgl->ErrorOutOfMemory("Failed to map source surface for upload.");
         return false;
     }
 
     const auto& srcBegin = map.GetData();
     const auto& srcStride = map.GetStride();
 
     ////
 
@@ -874,17 +862,17 @@ TexUnpackSurface::TexOrSubImage(bool isS
 
     const auto dstRowLengthBytes = rowLength * dstBPP;
     const auto dstStride = RoundUpToMultipleOf(dstRowLengthBytes, dstAlignment);
 
     ////
 
     const uint8_t* dstBegin = srcBegin;
     UniqueBuffer tempBuffer;
-    if (!ConvertIfNeeded(webgl, funcName, rowLength, rowCount, srcFormat, srcBegin,
+    if (!ConvertIfNeeded(webgl, rowLength, rowCount, srcFormat, srcBegin,
                          srcStride, dstFormat, dstStride, &dstBegin, &tempBuffer))
     {
         return false;
     }
 
     ////
 
     const auto& gl = webgl->gl;
--- a/dom/canvas/TexUnpackBlob.h
+++ b/dom/canvas/TexUnpackBlob.h
@@ -59,35 +59,34 @@ protected:
     TexUnpackBlob(const WebGLContext* webgl, TexImageTarget target, uint32_t rowLength,
                   uint32_t width, uint32_t height, uint32_t depth,
                   gfxAlphaType srcAlphaType);
 
 public:
     virtual ~TexUnpackBlob() { }
 
 protected:
-    bool ConvertIfNeeded(WebGLContext* webgl, const char* funcName,
+    bool ConvertIfNeeded(WebGLContext* webgl,
                          const uint32_t rowLength, const uint32_t rowCount,
                          WebGLTexelFormat srcFormat,
                          const uint8_t* const srcBegin, const ptrdiff_t srcStride,
                          WebGLTexelFormat dstFormat, const ptrdiff_t dstStride,
 
                          const uint8_t** const out_begin,
                          UniqueBuffer* const out_anchoredBuffer) const;
 
 public:
     virtual bool HasData() const { return true; }
 
-    virtual bool Validate(WebGLContext* webgl, const char* funcName,
-                          const webgl::PackingInfo& pi) = 0;
+    virtual bool Validate(WebGLContext* webgl, const webgl::PackingInfo& pi) = 0;
 
     // Returns false when we've generated a WebGL error.
     // Returns true but with a non-zero *out_error if we still need to generate a WebGL
     // error.
-    virtual bool TexOrSubImage(bool isSubImage, bool needsRespec, const char* funcName,
+    virtual bool TexOrSubImage(bool isSubImage, bool needsRespec,
                                WebGLTexture* tex, TexImageTarget target, GLint level,
                                const webgl::DriverUnpackInfo* dui, GLint xOffset,
                                GLint yOffset, GLint zOffset,
                                const webgl::PackingInfo& pi, GLenum* const out_error) const = 0;
 };
 
 class TexUnpackBytes final : public TexUnpackBlob
 {
@@ -97,19 +96,19 @@ public:
     const size_t mAvailBytes;
 
     TexUnpackBytes(const WebGLContext* webgl, TexImageTarget target, uint32_t width,
                    uint32_t height, uint32_t depth, bool isClientData, const uint8_t* ptr,
                    size_t availBytes);
 
     virtual bool HasData() const override { return !mIsClientData || bool(mPtr); }
 
-    virtual bool Validate(WebGLContext* webgl, const char* funcName,
+    virtual bool Validate(WebGLContext* webgl,
                           const webgl::PackingInfo& pi) override;
-    virtual bool TexOrSubImage(bool isSubImage, bool needsRespec, const char* funcName,
+    virtual bool TexOrSubImage(bool isSubImage, bool needsRespec,
                                WebGLTexture* tex, TexImageTarget target, GLint level,
                                const webgl::DriverUnpackInfo* dui, GLint xOffset,
                                GLint yOffset, GLint zOffset,
                                const webgl::PackingInfo& pi, GLenum* const out_error) const override;
 };
 
 class TexUnpackImage final : public TexUnpackBlob
 {
@@ -117,37 +116,37 @@ public:
     const RefPtr<layers::Image> mImage;
 
     TexUnpackImage(const WebGLContext* webgl, TexImageTarget target, uint32_t width,
                    uint32_t height, uint32_t depth, layers::Image* image,
                    gfxAlphaType srcAlphaType);
 
     ~TexUnpackImage(); // Prevent needing to define layers::Image in the header.
 
-    virtual bool Validate(WebGLContext* webgl, const char* funcName,
+    virtual bool Validate(WebGLContext* webgl,
                           const webgl::PackingInfo& pi) override;
-    virtual bool TexOrSubImage(bool isSubImage, bool needsRespec, const char* funcName,
+    virtual bool TexOrSubImage(bool isSubImage, bool needsRespec,
                                WebGLTexture* tex, TexImageTarget target, GLint level,
                                const webgl::DriverUnpackInfo* dui, GLint xOffset,
                                GLint yOffset, GLint zOffset,
                                const webgl::PackingInfo& dstPI, GLenum* const out_error)  const override;
 };
 
 class TexUnpackSurface final : public TexUnpackBlob
 {
 public:
     const RefPtr<gfx::DataSourceSurface> mSurf;
 
     TexUnpackSurface(const WebGLContext* webgl, TexImageTarget target, uint32_t width,
                      uint32_t height, uint32_t depth, gfx::DataSourceSurface* surf,
                      gfxAlphaType srcAlphaType);
 
-    virtual bool Validate(WebGLContext* webgl, const char* funcName,
+    virtual bool Validate(WebGLContext* webgl,
                           const webgl::PackingInfo& pi) override;
-    virtual bool TexOrSubImage(bool isSubImage, bool needsRespec, const char* funcName,
+    virtual bool TexOrSubImage(bool isSubImage, bool needsRespec,
                                WebGLTexture* tex, TexImageTarget target, GLint level,
                                const webgl::DriverUnpackInfo* dui, GLint xOffset,
                                GLint yOffset, GLint zOffset,
                                const webgl::PackingInfo& dstPI, GLenum* const out_error) const override;
 };
 
 } // namespace webgl
 } // namespace mozilla
--- a/dom/canvas/WebGL2Context.h
+++ b/dom/canvas/WebGL2Context.h
@@ -77,108 +77,110 @@ public:
 
 
     // -------------------------------------------------------------------------
     // Renderbuffer objects - WebGL2ContextRenderbuffers.cpp
 
     void GetInternalformatParameter(JSContext*, GLenum target, GLenum internalformat,
                                     GLenum pname, JS::MutableHandleValue retval,
                                     ErrorResult& rv);
-    void RenderbufferStorageMultisample(GLenum target, GLsizei samples, GLenum internalformat,
-                                        GLsizei width, GLsizei height);
+    void RenderbufferStorageMultisample(GLenum target, GLsizei samples, GLenum internalFormat,
+                                        GLsizei width, GLsizei height)
+    {
+        const FuncScope funcScope(*this, "renderbufferStorageMultisample");
+        RenderbufferStorage_base(target, samples, internalFormat, width, height);
+    }
 
 
     // -------------------------------------------------------------------------
     // Texture objects - WebGL2ContextTextures.cpp
 
     void TexStorage2D(GLenum target, GLsizei levels, GLenum internalFormat, GLsizei width,
                       GLsizei height)
     {
-        const char funcName[] = "TexStorage2D";
+        const FuncScope funcScope(*this, "TexStorage2D");
         const uint8_t funcDims = 2;
         const GLsizei depth = 1;
-        TexStorage(funcName, funcDims, target, levels, internalFormat, width, height,
-                   depth);
+        TexStorage(funcDims, target, levels, internalFormat, width, height, depth);
     }
 
     void TexStorage3D(GLenum target, GLsizei levels, GLenum internalFormat, GLsizei width,
                       GLsizei height, GLsizei depth)
     {
-        const char funcName[] = "TexStorage3D";
+        const FuncScope funcScope(*this, "TexStorage3D");
         const uint8_t funcDims = 3;
-        TexStorage(funcName, funcDims, target, levels, internalFormat, width, height,
-                   depth);
+        TexStorage(funcDims, target, levels, internalFormat, width, height, depth);
     }
 
 protected:
-    void TexStorage(const char* funcName, uint8_t funcDims, GLenum target, GLsizei levels,
+    void TexStorage(uint8_t funcDims, GLenum target, GLsizei levels,
                     GLenum internalFormat, GLsizei width, GLsizei height, GLsizei depth);
 
     ////////////////////////////////////
 
 public:
     void CompressedTexImage3D(GLenum target, GLint level, GLenum internalFormat,
                               GLsizei width, GLsizei height, GLsizei depth, GLint border,
                               GLsizei imageSize, WebGLintptr offset)
     {
-        const char funcName[] = "compressedTexImage3D";
+        const FuncScope funcScope(*this, "compressedTexImage3D");
         const uint8_t funcDims = 3;
         const TexImageSourceAdapter src(&offset, 0, 0);
-        CompressedTexImage(funcName, funcDims, target, level, internalFormat, width,
+        CompressedTexImage(funcDims, target, level, internalFormat, width,
                            height, depth, border, src, Some(imageSize));
     }
 
     template<typename T>
     void CompressedTexImage3D(GLenum target, GLint level, GLenum internalFormat,
                               GLsizei width, GLsizei height, GLsizei depth, GLint border,
                               const T& anySrc, GLuint viewElemOffset = 0,
                               GLuint viewElemLengthOverride = 0)
     {
-        const char funcName[] = "compressedTexImage3D";
+        const FuncScope funcScope(*this, "compressedTexImage3D");
         const uint8_t funcDims = 3;
         const TexImageSourceAdapter src(&anySrc, viewElemOffset, viewElemLengthOverride);
-        CompressedTexImage(funcName, funcDims, target, level, internalFormat, width,
+        CompressedTexImage(funcDims, target, level, internalFormat, width,
                            height, depth, border, src, Nothing());
     }
 
     void CompressedTexSubImage3D(GLenum target, GLint level, GLint xOffset, GLint yOffset,
                                  GLint zOffset, GLsizei width, GLsizei height,
                                  GLsizei depth, GLenum unpackFormat,
                                  GLsizei imageSize, WebGLintptr offset)
     {
-        const char funcName[] = "compressedTexSubImage3D";
+        const FuncScope funcScope(*this, "compressedTexSubImage3D");
         const uint8_t funcDims = 3;
         const TexImageSourceAdapter src(&offset, 0, 0);
-        CompressedTexSubImage(funcName, funcDims, target, level, xOffset, yOffset,
+        CompressedTexSubImage(funcDims, target, level, xOffset, yOffset,
                               zOffset, width, height, depth, unpackFormat, src, Some(imageSize));
     }
 
     template<typename T>
     void CompressedTexSubImage3D(GLenum target, GLint level, GLint xOffset, GLint yOffset,
                                  GLint zOffset, GLsizei width, GLsizei height,
                                  GLsizei depth, GLenum unpackFormat, const T& anySrc,
                                  GLuint viewElemOffset = 0,
                                  GLuint viewElemLengthOverride = 0)
     {
-        const char funcName[] = "compressedTexSubImage3D";
+        const FuncScope funcScope(*this, "compressedTexSubImage3D");
         const uint8_t funcDims = 3;
         const TexImageSourceAdapter src(&anySrc, viewElemOffset, viewElemLengthOverride);
-        CompressedTexSubImage(funcName, funcDims, target, level, xOffset, yOffset,
+        CompressedTexSubImage(funcDims, target, level, xOffset, yOffset,
                               zOffset, width, height, depth, unpackFormat, src, Nothing());
     }
 
     ////////////////////////////////////
 
     void CopyTexSubImage3D(GLenum target, GLint level, GLint xOffset, GLint yOffset,
                            GLint zOffset, GLint x, GLint y, GLsizei width,
                            GLsizei height)
     {
-        const char funcName[] = "copyTexSubImage3D";
+        const FuncScope funcScope(*this, "copyTexSubImage3D");
         const uint8_t funcDims = 3;
-        CopyTexSubImage(funcName, funcDims, target, level, xOffset, yOffset, zOffset,
+        CopyTexSubImage(funcDims, target, level, xOffset, yOffset, zOffset,
                         x, y, width, height);
     }
 
     ////////////////////////////////////
 
     template<typename T>
     void TexImage3D(GLenum target, GLint level, GLenum internalFormat, GLsizei width,
                     GLsizei height, GLsizei depth, GLint border, GLenum unpackFormat,
@@ -199,19 +201,19 @@ public:
                    unpackFormat, unpackType, src);
     }
 
 protected:
     void TexImage3D(GLenum target, GLint level, GLenum internalFormat, GLsizei width,
                     GLsizei height, GLsizei depth, GLint border, GLenum unpackFormat,
                     GLenum unpackType, const TexImageSource& src)
     {
-        const char funcName[] = "texImage3D";
+        const FuncScope funcScope(*this, "texImage3D");
         const uint8_t funcDims = 3;
-        TexImage(funcName, funcDims, target, level, internalFormat, width, height, depth,
+        TexImage(funcDims, target, level, internalFormat, width, height, depth,
                  border, unpackFormat, unpackType, src);
     }
 
     ////////////////////////////////////
 
 public:
     template<typename T>
     void TexSubImage3D(GLenum target, GLint level, GLint xOffset, GLint yOffset,
@@ -225,78 +227,79 @@ public:
     }
 
     void TexSubImage3D(GLenum target, GLint level, GLint xOffset, GLint yOffset,
                        GLint zOffset, GLsizei width, GLsizei height, GLsizei depth,
                        GLenum unpackFormat, GLenum unpackType,
                        const dom::Nullable<dom::ArrayBufferView>& maybeSrcView,
                        GLuint srcElemOffset, ErrorResult&)
     {
+        const FuncScope funcScope(*this, "texSubImage3D");
         if (IsContextLost())
             return;
 
-        if (!ValidateNonNull("texSubImage3D", maybeSrcView))
+        if (!ValidateNonNull("src", maybeSrcView))
             return;
         const auto& srcView = maybeSrcView.Value();
 
         const TexImageSourceAdapter src(&srcView, srcElemOffset);
         TexSubImage3D(target, level, xOffset, yOffset, zOffset, width, height, depth,
                       unpackFormat, unpackType, src);
     }
 
 protected:
     void TexSubImage3D(GLenum target, GLint level, GLint xOffset, GLint yOffset,
                        GLint zOffset, GLsizei width, GLsizei height, GLsizei depth,
                        GLenum unpackFormat, GLenum unpackType, const TexImageSource& src)
     {
-        const char funcName[] = "texSubImage3D";
+        const FuncScope funcScope(*this, "texSubImage3D");
         const uint8_t funcDims = 3;
-        TexSubImage(funcName, funcDims, target, level, xOffset, yOffset, zOffset, width,
+        TexSubImage(funcDims, target, level, xOffset, yOffset, zOffset, width,
                     height, depth, unpackFormat, unpackType, src);
     }
 
 public:
     // -------------------------------------------------------------------------
     // Programs and shaders - WebGL2ContextPrograms.cpp
     GLint GetFragDataLocation(const WebGLProgram& program, const nsAString& name);
 
 
     // -------------------------------------------------------------------------
     // Uniforms and attributes - WebGL2ContextUniforms.cpp
 
     void VertexAttribIPointer(GLuint index, GLint size, GLenum type, GLsizei stride,
                               WebGLintptr byteOffset)
     {
-        const char funcName[] = "vertexAttribIPointer";
+        const FuncScope funcScope(*this, "vertexAttribIPointer");
         const bool isFuncInt = true;
         const bool normalized = false;
-        VertexAttribAnyPointer(funcName, isFuncInt, index, size, type, normalized, stride,
+        VertexAttribAnyPointer(isFuncInt, index, size, type, normalized, stride,
                                byteOffset);
     }
 
     ////////////////
 
     // GL 3.0 & ES 3.0
-    void VertexAttribI4i(GLuint index, GLint x, GLint y, GLint z, GLint w,
-                         const char* funcName = nullptr);
-    void VertexAttribI4ui(GLuint index, GLuint x, GLuint y, GLuint z, GLuint w,
-                          const char* funcName = nullptr);
+    void VertexAttribI4i(GLuint index, GLint x, GLint y, GLint z, GLint w);
+    void VertexAttribI4ui(GLuint index, GLuint x, GLuint y, GLuint z, GLuint w);
 
     void VertexAttribI4iv(GLuint index, const Int32ListU& list) {
+        const FuncScope funcScope(*this, "VertexAttribI4iv");
         const auto& arr = Int32Arr::From(list);
-        if (!ValidateAttribArraySetter("vertexAttribI4iv", 4, arr.elemCount))
+        if (!ValidateAttribArraySetter(4, arr.elemCount))
             return;
 
         const auto& itr = arr.elemBytes;
         VertexAttribI4i(index, itr[0], itr[1], itr[2], itr[3]);
     }
 
     void VertexAttribI4uiv(GLuint index, const Uint32ListU& list) {
+        const FuncScope funcScope(*this, "vertexAttribI4uiv");
         const auto& arr = Uint32Arr::From(list);
-        if (!ValidateAttribArraySetter("vertexAttribI4uiv", 4, arr.elemCount))
+        if (!ValidateAttribArraySetter(4, arr.elemCount))
             return;
 
         const auto& itr = arr.elemBytes;
         VertexAttribI4ui(index, itr[0], itr[1], itr[2], itr[3]);
     }
 
     // -------------------------------------------------------------------------
     // Writing to the drawing buffer
@@ -305,36 +308,36 @@ public:
     void VertexAttribDivisor(GLuint index, GLuint divisor);
     void DrawArraysInstanced(GLenum mode, GLint first, GLsizei count, GLsizei instanceCount);
     void DrawElementsInstanced(GLenum mode, GLsizei count, GLenum type, GLintptr offset, GLsizei instanceCount);
     */
 
     void DrawRangeElements(GLenum mode, GLuint start, GLuint end, GLsizei count,
                            GLenum type, WebGLintptr byteOffset)
     {
-        const char funcName[] = "drawRangeElements";
+        const FuncScope funcScope(*this, "drawRangeElements");
         if (IsContextLost())
             return;
 
         if (end < start) {
-            ErrorInvalidValue("%s: end must be >= start.", funcName);
+            ErrorInvalidValue("end must be >= start.");
             return;
         }
 
-        DrawElements(mode, count, type, byteOffset, funcName);
+        DrawElements(mode, count, type, byteOffset);
     }
 
     // ------------------------------------------------------------------------
     // Multiple Render Targets - WebGL2ContextMRTs.cpp
     /* Implemented in WebGLContext
     void DrawBuffers(const dom::Sequence<GLenum>& buffers);
     */
 
 private:
-    bool ValidateClearBuffer(const char* funcName, GLenum buffer, GLint drawBuffer,
+    bool ValidateClearBuffer(GLenum buffer, GLint drawBuffer,
                              size_t availElemCount, GLuint elemOffset, GLenum funcType);
 
     void ClearBufferfv(GLenum buffer, GLint drawBuffer, const Float32Arr& src,
                        GLuint srcElemOffset);
     void ClearBufferiv(GLenum buffer, GLint drawBuffer, const Int32Arr& src,
                        GLuint srcElemOffset);
     void ClearBufferuiv(GLenum buffer, GLint drawBuffer, const Uint32Arr& src,
                         GLuint srcElemOffset);
--- a/dom/canvas/WebGL2ContextBuffers.cpp
+++ b/dom/canvas/WebGL2ContextBuffers.cpp
@@ -14,41 +14,41 @@ namespace mozilla {
 // -------------------------------------------------------------------------
 // Buffer objects
 
 void
 WebGL2Context::CopyBufferSubData(GLenum readTarget, GLenum writeTarget,
                                  GLintptr readOffset, GLintptr writeOffset,
                                  GLsizeiptr size)
 {
-    const char funcName[] = "copyBufferSubData";
+    const FuncScope funcScope(*this, "copyBufferSubData");
     if (IsContextLost())
         return;
 
-    const auto& readBuffer = ValidateBufferSelection(funcName, readTarget);
+    const auto& readBuffer = ValidateBufferSelection(readTarget);
     if (!readBuffer)
         return;
 
-    const auto& writeBuffer = ValidateBufferSelection(funcName, writeTarget);
+    const auto& writeBuffer = ValidateBufferSelection(writeTarget);
     if (!writeBuffer)
         return;
 
-    if (!ValidateNonNegative(funcName, "readOffset", readOffset) ||
-        !ValidateNonNegative(funcName, "writeOffset", writeOffset) ||
-        !ValidateNonNegative(funcName, "size", size))
+    if (!ValidateNonNegative("readOffset", readOffset) ||
+        !ValidateNonNegative("writeOffset", writeOffset) ||
+        !ValidateNonNegative("size", size))
     {
         return;
     }
 
     const auto fnValidateOffsetSize = [&](const char* info, GLintptr offset,
                                           const WebGLBuffer* buffer)
     {
         const auto neededBytes = CheckedInt<size_t>(offset) + size;
         if (!neededBytes.isValid() || neededBytes.value() > buffer->ByteLength()) {
-            ErrorInvalidValue("%s: Invalid %s range.", funcName, info);
+            ErrorInvalidValue("Invalid %s range.", info);
             return false;
         }
         return true;
     };
 
     if (!fnValidateOffsetSize("read", readOffset, readBuffer) ||
         !fnValidateOffsetSize("write", writeOffset, writeBuffer))
     {
@@ -57,30 +57,28 @@ WebGL2Context::CopyBufferSubData(GLenum 
 
     if (readBuffer == writeBuffer) {
         MOZ_ASSERT((CheckedInt<WebGLsizeiptr>(readOffset) + size).isValid());
         MOZ_ASSERT((CheckedInt<WebGLsizeiptr>(writeOffset) + size).isValid());
 
         const bool separate = (readOffset + size <= writeOffset ||
                                writeOffset + size <= readOffset);
         if (!separate) {
-            ErrorInvalidValue("%s: ranges [readOffset, readOffset + size) and"
-                              " [writeOffset, writeOffset + size) overlap",
-                              funcName);
+            ErrorInvalidValue("Ranges [readOffset, readOffset + size) and"
+                              " [writeOffset, writeOffset + size) overlap.");
             return;
         }
     }
 
     const auto& readType = readBuffer->Content();
     const auto& writeType = writeBuffer->Content();
     MOZ_ASSERT(readType != WebGLBuffer::Kind::Undefined);
     MOZ_ASSERT(writeType != WebGLBuffer::Kind::Undefined);
     if (writeType != readType) {
-        ErrorInvalidOperation("%s: Can't copy %s data to %s data.",
-                              funcName,
+        ErrorInvalidOperation("Can't copy %s data to %s data.",
                               (readType == WebGLBuffer::Kind::OtherData) ? "other"
                                                                          : "element",
                               (writeType == WebGLBuffer::Kind::OtherData) ? "other"
                                                                           : "element");
         return;
     }
 
     const ScopedLazyBind readBind(gl, readTarget, readBuffer);
@@ -90,65 +88,63 @@ WebGL2Context::CopyBufferSubData(GLenum 
     writeBuffer->ResetLastUpdateFenceId();
 }
 
 void
 WebGL2Context::GetBufferSubData(GLenum target, GLintptr srcByteOffset,
                                 const dom::ArrayBufferView& dstData, GLuint dstElemOffset,
                                 GLuint dstElemCountOverride)
 {
-    const char funcName[] = "getBufferSubData";
+    const FuncScope funcScope(*this, "getBufferSubData");
     if (IsContextLost())
         return;
 
-    if (!ValidateNonNegative(funcName, "srcByteOffset", srcByteOffset))
+    if (!ValidateNonNegative("srcByteOffset", srcByteOffset))
         return;
 
     uint8_t* bytes;
     size_t byteLen;
-    if (!ValidateArrayBufferView(funcName, dstData, dstElemOffset, dstElemCountOverride,
+    if (!ValidateArrayBufferView(dstData, dstElemOffset, dstElemCountOverride,
                                  &bytes, &byteLen))
     {
         return;
     }
 
     ////
 
-    const auto& buffer = ValidateBufferSelection(funcName, target);
+    const auto& buffer = ValidateBufferSelection(target);
     if (!buffer)
         return;
 
-    if (!buffer->ValidateRange(funcName, srcByteOffset, byteLen))
+    if (!buffer->ValidateRange(srcByteOffset, byteLen))
         return;
 
     ////
 
     if (!CheckedInt<GLsizeiptr>(byteLen).isValid()) {
-        ErrorOutOfMemory("%s: Size too large.", funcName);
+        ErrorOutOfMemory("Size too large.");
         return;
     }
     const GLsizeiptr glByteLen(byteLen);
 
     ////
 
     switch (buffer->mUsage) {
     case LOCAL_GL_STATIC_READ:
     case LOCAL_GL_STREAM_READ:
     case LOCAL_GL_DYNAMIC_READ:
         if (mCompletedFenceId < buffer->mLastUpdateFenceId) {
-            GenerateWarning("%s: Reading from a buffer without checking for previous"
+            GenerateWarning("Reading from a buffer without checking for previous"
                             " command completion likely causes pipeline stalls."
-                            " Please use FenceSync.",
-                            funcName);
+                            " Please use FenceSync.");
         }
         break;
     default:
-        GenerateWarning("%s: Reading from a buffer with usage other than *_READ"
-                        " causes pipeline stalls. Copy through a STREAM_READ buffer.",
-                        funcName);
+        GenerateWarning("Reading from a buffer with usage other than *_READ"
+                        " causes pipeline stalls. Copy through a STREAM_READ buffer.");
         break;
     }
 
     ////
 
     const ScopedLazyBind readBind(gl, target, buffer);
 
     if (byteLen) {
--- a/dom/canvas/WebGL2ContextFramebuffers.cpp
+++ b/dom/canvas/WebGL2ContextFramebuffers.cpp
@@ -14,56 +14,56 @@
 
 namespace mozilla {
 
 void
 WebGL2Context::BlitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1,
                                GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1,
                                GLbitfield mask, GLenum filter)
 {
+    const FuncScope funcScope(*this, "blitFramebuffer");
     if (IsContextLost())
         return;
 
     const GLbitfield validBits = LOCAL_GL_COLOR_BUFFER_BIT |
                                  LOCAL_GL_DEPTH_BUFFER_BIT |
                                  LOCAL_GL_STENCIL_BUFFER_BIT;
     if ((mask | validBits) != validBits) {
-        ErrorInvalidValue("blitFramebuffer: Invalid bit set in mask.");
+        ErrorInvalidValue("Invalid bit set in mask.");
         return;
     }
 
     switch (filter) {
     case LOCAL_GL_NEAREST:
     case LOCAL_GL_LINEAR:
         break;
     default:
-        ErrorInvalidEnumInfo("blitFramebuffer: Bad `filter`:", filter);
+        ErrorInvalidEnumInfo("filter", filter);
         return;
     }
 
     // --
 
     const auto fnLikelyOverflow = [](GLint p0, GLint p1) {
         auto checked = CheckedInt<GLint>(p1) - p0;
         checked = -checked; // And check the negation!
         return !checked.isValid();
     };
 
     if (fnLikelyOverflow(srcX0, srcX1) || fnLikelyOverflow(srcY0, srcY1) ||
         fnLikelyOverflow(dstX0, dstX1) || fnLikelyOverflow(dstY0, dstY1))
     {
-        ErrorInvalidValue("blitFramebuffer: Likely-to-overflow large ranges are"
-                          " forbidden.");
+        ErrorInvalidValue("Likely-to-overflow large ranges are forbidden.");
         return;
     }
 
     // --
 
-    if (!ValidateAndInitFB("blitFramebuffer: READ_FRAMEBUFFER", mBoundReadFramebuffer) ||
-        !ValidateAndInitFB("blitFramebuffer: DRAW_FRAMEBUFFER", mBoundDrawFramebuffer))
+    if (!ValidateAndInitFB(mBoundReadFramebuffer) ||
+        !ValidateAndInitFB(mBoundDrawFramebuffer))
     {
         return;
     }
 
     DoBindFB(mBoundReadFramebuffer, LOCAL_GL_READ_FRAMEBUFFER);
     DoBindFB(mBoundDrawFramebuffer, LOCAL_GL_DRAW_FRAMEBUFFER);
 
     WebGLFramebuffer::BlitFramebuffer(this,
@@ -71,21 +71,21 @@ WebGL2Context::BlitFramebuffer(GLint src
                                       dstX0, dstY0, dstX1, dstY1,
                                       mask, filter);
 }
 
 void
 WebGL2Context::FramebufferTextureLayer(GLenum target, GLenum attachment,
                                        WebGLTexture* texture, GLint level, GLint layer)
 {
-    const char funcName[] = "framebufferTextureLayer";
+    const FuncScope funcScope(*this, "framebufferTextureLayer");
     if (IsContextLost())
         return;
 
-    if (!ValidateFramebufferTarget(target, funcName))
+    if (!ValidateFramebufferTarget(target))
         return;
 
     WebGLFramebuffer* fb;
     switch (target) {
     case LOCAL_GL_FRAMEBUFFER:
     case LOCAL_GL_DRAW_FRAMEBUFFER:
         fb = mBoundDrawFramebuffer;
         break;
@@ -94,90 +94,86 @@ WebGL2Context::FramebufferTextureLayer(G
         fb = mBoundReadFramebuffer;
         break;
 
     default:
         MOZ_CRASH("GFX: Bad target.");
     }
 
     if (!fb)
-        return ErrorInvalidOperation("%s: Cannot modify framebuffer 0.", funcName);
+        return ErrorInvalidOperation("Cannot modify framebuffer 0.");
 
-    fb->FramebufferTextureLayer(funcName, attachment, texture, level, layer);
+    fb->FramebufferTextureLayer(attachment, texture, level, layer);
 }
 
 JS::Value
 WebGL2Context::GetFramebufferAttachmentParameter(JSContext* cx,
                                                  GLenum target,
                                                  GLenum attachment,
                                                  GLenum pname,
                                                  ErrorResult& out_error)
 {
     return WebGLContext::GetFramebufferAttachmentParameter(cx, target, attachment, pname,
                                                            out_error);
 }
 
 ////
 
 static bool
-ValidateBackbufferAttachmentEnum(WebGLContext* webgl, const char* funcName,
-                                 GLenum attachment)
+ValidateBackbufferAttachmentEnum(WebGLContext* webgl, GLenum attachment)
 {
     switch (attachment) {
     case LOCAL_GL_COLOR:
     case LOCAL_GL_DEPTH:
     case LOCAL_GL_STENCIL:
         return true;
 
     default:
-        webgl->ErrorInvalidEnum("%s: attachment: invalid enum value 0x%x.",
-                                funcName, attachment);
+        webgl->ErrorInvalidEnumInfo("attachment", attachment);
         return false;
     }
 }
 
 static bool
-ValidateFramebufferAttachmentEnum(WebGLContext* webgl, const char* funcName,
+ValidateFramebufferAttachmentEnum(WebGLContext* webgl,
                                   GLenum attachment)
 {
     switch (attachment) {
     case LOCAL_GL_DEPTH_ATTACHMENT:
     case LOCAL_GL_STENCIL_ATTACHMENT:
     case LOCAL_GL_DEPTH_STENCIL_ATTACHMENT:
         return true;
     }
 
     if (attachment < LOCAL_GL_COLOR_ATTACHMENT0) {
-        webgl->ErrorInvalidEnum("%s: attachment: invalid enum value 0x%x.",
-                                funcName, attachment);
+        webgl->ErrorInvalidEnumInfo("attachment", attachment);
         return false;
     }
 
     if (attachment > webgl->LastColorAttachmentEnum()) {
         // That these errors have different types is ridiculous.
-        webgl->ErrorInvalidOperation("%s: Too-large LOCAL_GL_COLOR_ATTACHMENTn.",
-                                     funcName);
+        webgl->ErrorInvalidOperation("Too-large LOCAL_GL_COLOR_ATTACHMENTn.");
         return false;
     }
 
     return true;
 }
 
 bool
-WebGLContext::ValidateInvalidateFramebuffer(const char* funcName, GLenum target,
+WebGLContext::ValidateInvalidateFramebuffer(GLenum target,
                                             const dom::Sequence<GLenum>& attachments,
                                             ErrorResult* const out_rv,
                                             std::vector<GLenum>* const scopedVector,
                                             GLsizei* const out_glNumAttachments,
                                             const GLenum** const out_glAttachments)
 {
     if (IsContextLost())
         return false;
 
-    if (!ValidateFramebufferTarget(target, funcName))
+    if (!ValidateFramebufferTarget(target))
         return false;
 
     const WebGLFramebuffer* fb;
     bool isDefaultFB = false;
     switch (target) {
     case LOCAL_GL_FRAMEBUFFER:
     case LOCAL_GL_DRAW_FRAMEBUFFER:
         fb = mBoundDrawFramebuffer;
@@ -187,36 +183,36 @@ WebGLContext::ValidateInvalidateFramebuf
         fb = mBoundReadFramebuffer;
         break;
 
     default:
         MOZ_CRASH("GFX: Bad target.");
     }
 
     if (fb) {
-        const auto fbStatus = fb->CheckFramebufferStatus(funcName);
+        const auto fbStatus = fb->CheckFramebufferStatus();
         if (fbStatus != LOCAL_GL_FRAMEBUFFER_COMPLETE)
             return false; // Not an error, but don't run forward to driver either.
     } else {
-        if (!EnsureDefaultFB(funcName))
+        if (!EnsureDefaultFB())
             return false;
     }
     DoBindFB(fb, target);
 
     *out_glNumAttachments = attachments.Length();
     *out_glAttachments = attachments.Elements();
 
     if (fb) {
         for (const auto& attachment : attachments) {
-            if (!ValidateFramebufferAttachmentEnum(this, funcName, attachment))
+            if (!ValidateFramebufferAttachmentEnum(this, attachment))
                 return false;
         }
     } else {
         for (const auto& attachment : attachments) {
-            if (!ValidateBackbufferAttachmentEnum(this, funcName, attachment))
+            if (!ValidateBackbufferAttachmentEnum(this, attachment))
                 return false;
         }
 
         if (!isDefaultFB) {
             MOZ_ASSERT(scopedVector->empty());
             scopedVector->reserve(attachments.Length());
             for (const auto& attachment : attachments) {
                 switch (attachment) {
@@ -250,22 +246,22 @@ WebGLContext::ValidateInvalidateFramebuf
     return true;
 }
 
 void
 WebGL2Context::InvalidateFramebuffer(GLenum target,
                                      const dom::Sequence<GLenum>& attachments,
                                      ErrorResult& rv)
 {
-    const char funcName[] = "invalidateSubFramebuffer";
+    const FuncScope funcScope(*this, "invalidateFramebuffer");
 
     std::vector<GLenum> scopedVector;
     GLsizei glNumAttachments;
     const GLenum* glAttachments;
-    if (!ValidateInvalidateFramebuffer(funcName, target, attachments, &rv, &scopedVector,
+    if (!ValidateInvalidateFramebuffer(target, attachments, &rv, &scopedVector,
                                        &glNumAttachments, &glAttachments))
     {
         return;
     }
 
     ////
 
     // Some drivers (like OSX 10.9 GL) just don't support invalidate_fra