Merge inbound to mozilla-central. a=merge
authorMargareta Eliza Balazs <ebalazs@mozilla.com>
Fri, 10 Aug 2018 12:17:09 +0300
changeset 430956 d999fb858fb2c007c5be4af72bce419c63c69b8e
parent 430955 64e80e767f816f6cf43f906b40b603a245fe2110 (current diff)
parent 430913 ac7bd965f86b3ae24921f35072eeea2204c82bba (diff)
child 430957 af32e7b1cb1e3e3fd797c2497bf206216bfa9442
child 430984 d05ae84b507f7c0ba986f09202d8be8b3b2eded2
push id106305
push userebalazs@mozilla.com
push dateFri, 10 Aug 2018 09:24:36 +0000
treeherdermozilla-inbound@af32e7b1cb1e [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone63.0a1
first release with
nightly linux32
d999fb858fb2 / 63.0a1 / 20180810100128 / files
nightly linux64
d999fb858fb2 / 63.0a1 / 20180810100128 / files
nightly mac
d999fb858fb2 / 63.0a1 / 20180810100128 / files
nightly win32
d999fb858fb2 / 63.0a1 / 20180810100128 / files
nightly win64
d999fb858fb2 / 63.0a1 / 20180810100128 / files
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
releases
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge inbound to mozilla-central. a=merge
accessible/windows/msaa/IDSet.h
browser/base/content/tabbrowser.js
dom/ipc/ContentChild.cpp
gfx/layers/BufferEdgePad.cpp
gfx/layers/BufferEdgePad.h
gfx/layers/BufferUnrotate.cpp
gfx/layers/BufferUnrotate.h
gfx/thebes/gfxPrefs.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.");
     }