зеркало из https://github.com/mozilla/gecko-dev.git
Merge inbound to mozilla-central. a=merge
This commit is contained in:
Коммит
12a8bddd95
|
@ -44,11 +44,10 @@ XULMAP_TYPE(tooltip, XULTooltipAccessible)
|
|||
|
||||
XULMAP(
|
||||
colorpicker,
|
||||
[](nsIContent* aContent, Accessible* aContext) -> Accessible* {
|
||||
if (aContent->IsElement() &&
|
||||
aContent->AsElement()->AttrValueIs(kNameSpaceID_None, nsGkAtoms::type,
|
||||
nsGkAtoms::button, eIgnoreCase)) {
|
||||
return new XULColorPickerAccessible(aContent, aContext->Document());
|
||||
[](Element* aElement, Accessible* aContext) -> Accessible* {
|
||||
if (aElement->AttrValueIs(kNameSpaceID_None, nsGkAtoms::type,
|
||||
nsGkAtoms::button, eIgnoreCase)) {
|
||||
return new XULColorPickerAccessible(aElement, aContext->Document());
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
@ -56,52 +55,47 @@ XULMAP(
|
|||
|
||||
XULMAP(
|
||||
label,
|
||||
[](nsIContent* aContent, Accessible* aContext) -> Accessible* {
|
||||
if (aContent->IsElement() &&
|
||||
aContent->AsElement()->ClassList()->Contains(NS_LITERAL_STRING("text-link"))) {
|
||||
return new XULLinkAccessible(aContent, aContext->Document());
|
||||
[](Element* aElement, Accessible* aContext) -> Accessible* {
|
||||
if (aElement->ClassList()->Contains(NS_LITERAL_STRING("text-link"))) {
|
||||
return new XULLinkAccessible(aElement, aContext->Document());
|
||||
}
|
||||
return new XULLabelAccessible(aContent, aContext->Document());
|
||||
return new XULLabelAccessible(aElement, aContext->Document());
|
||||
}
|
||||
)
|
||||
|
||||
XULMAP(
|
||||
image,
|
||||
[](nsIContent* aContent, Accessible* aContext) -> Accessible* {
|
||||
if (!aContent->IsElement()) {
|
||||
return nullptr;
|
||||
[](Element* aElement, Accessible* aContext) -> Accessible* {
|
||||
if (aElement->HasAttr(kNameSpaceID_None, nsGkAtoms::onclick)) {
|
||||
return new XULToolbarButtonAccessible(aElement, aContext->Document());
|
||||
}
|
||||
|
||||
if (aContent->AsElement()->HasAttr(kNameSpaceID_None, nsGkAtoms::onclick)) {
|
||||
return new XULToolbarButtonAccessible(aContent, aContext->Document());
|
||||
}
|
||||
|
||||
if (aContent->AsElement()->ClassList()->Contains(NS_LITERAL_STRING("colorpickertile"))) {
|
||||
return new XULColorPickerTileAccessible(aContent, aContext->Document());
|
||||
if (aElement->ClassList()->Contains(NS_LITERAL_STRING("colorpickertile"))) {
|
||||
return new XULColorPickerTileAccessible(aElement, aContext->Document());
|
||||
}
|
||||
|
||||
// Don't include nameless images in accessible tree.
|
||||
if (!aContent->AsElement()->HasAttr(kNameSpaceID_None, nsGkAtoms::tooltiptext)) {
|
||||
if (!aElement->HasAttr(kNameSpaceID_None, nsGkAtoms::tooltiptext)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return new ImageAccessibleWrap(aContent, aContext->Document());
|
||||
return new ImageAccessibleWrap(aElement, aContext->Document());
|
||||
}
|
||||
)
|
||||
|
||||
XULMAP(
|
||||
listcell,
|
||||
[](nsIContent* aContent, Accessible* aContext) -> Accessible* {
|
||||
[](Element* aElement, Accessible* aContext) -> Accessible* {
|
||||
// Only create cells if there's more than one per row.
|
||||
nsIContent* listItem = aContent->GetParent();
|
||||
nsIContent* listItem = aElement->GetParent();
|
||||
if (!listItem) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
for (nsIContent* child = listItem->GetFirstChild(); child;
|
||||
child = child->GetNextSibling()) {
|
||||
if (child->IsXULElement(nsGkAtoms::listcell) && child != aContent) {
|
||||
return new XULListCellAccessibleWrap(aContent, aContext->Document());
|
||||
if (child->IsXULElement(nsGkAtoms::listcell) && child != aElement) {
|
||||
return new XULListCellAccessibleWrap(aElement, aContext->Document());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -111,59 +105,55 @@ XULMAP(
|
|||
|
||||
XULMAP(
|
||||
menupopup,
|
||||
[](nsIContent* aContent, Accessible* aContext) {
|
||||
return CreateMenupopupAccessible(aContent, aContext);
|
||||
[](Element* aElement, Accessible* aContext) {
|
||||
return CreateMenupopupAccessible(aElement, aContext);
|
||||
}
|
||||
)
|
||||
|
||||
XULMAP(
|
||||
panel,
|
||||
[](nsIContent* aContent, Accessible* aContext) -> Accessible* {
|
||||
[](Element* aElement, Accessible* aContext) -> Accessible* {
|
||||
static const Element::AttrValuesArray sIgnoreTypeVals[] =
|
||||
{ &nsGkAtoms::autocomplete_richlistbox, &nsGkAtoms::autocomplete, nullptr };
|
||||
|
||||
if (!aContent->IsElement() ||
|
||||
aContent->AsElement()->FindAttrValueIn(kNameSpaceID_None, nsGkAtoms::type,
|
||||
sIgnoreTypeVals, eIgnoreCase) >= 0) {
|
||||
if (aElement->FindAttrValueIn(kNameSpaceID_None, nsGkAtoms::type,
|
||||
sIgnoreTypeVals, eIgnoreCase) >= 0) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (aContent->AsElement()->AttrValueIs(kNameSpaceID_None,
|
||||
nsGkAtoms::noautofocus,
|
||||
nsGkAtoms::_true, eCaseMatters)) {
|
||||
return new XULAlertAccessible(aContent, aContext->Document());
|
||||
if (aElement->AttrValueIs(kNameSpaceID_None, nsGkAtoms::noautofocus,
|
||||
nsGkAtoms::_true, eCaseMatters)) {
|
||||
return new XULAlertAccessible(aElement, aContext->Document());
|
||||
}
|
||||
|
||||
return new EnumRoleAccessible<roles::PANE>(aContent, aContext->Document());
|
||||
return new EnumRoleAccessible<roles::PANE>(aElement, aContext->Document());
|
||||
}
|
||||
)
|
||||
|
||||
XULMAP(
|
||||
popup,
|
||||
[](nsIContent* aContent, Accessible* aContext) {
|
||||
return CreateMenupopupAccessible(aContent, aContext);
|
||||
[](Element* aElement, Accessible* aContext) {
|
||||
return CreateMenupopupAccessible(aElement, aContext);
|
||||
}
|
||||
)
|
||||
|
||||
XULMAP(
|
||||
textbox,
|
||||
[](nsIContent* aContent, Accessible* aContext) -> Accessible* {
|
||||
if (aContent->IsElement() &&
|
||||
aContent->AsElement()->AttrValueIs(kNameSpaceID_None, nsGkAtoms::type,
|
||||
nsGkAtoms::autocomplete, eIgnoreCase)) {
|
||||
return new XULComboboxAccessible(aContent, aContext->Document());
|
||||
[](Element* aElement, Accessible* aContext) -> Accessible* {
|
||||
if (aElement->AttrValueIs(kNameSpaceID_None, nsGkAtoms::type,
|
||||
nsGkAtoms::autocomplete, eIgnoreCase)) {
|
||||
return new XULComboboxAccessible(aElement, aContext->Document());
|
||||
}
|
||||
|
||||
return new EnumRoleAccessible<roles::SECTION>(aContent, aContext->Document());
|
||||
return new EnumRoleAccessible<roles::SECTION>(aElement, aContext->Document());
|
||||
}
|
||||
)
|
||||
|
||||
XULMAP(
|
||||
thumb,
|
||||
[](nsIContent* aContent, Accessible* aContext) -> Accessible* {
|
||||
if (aContent->IsElement() &&
|
||||
aContent->AsElement()->ClassList()->Contains(NS_LITERAL_STRING("scale-thumb"))) {
|
||||
return new XULThumbAccessible(aContent, aContext->Document());
|
||||
[](Element* aElement, Accessible* aContext) -> Accessible* {
|
||||
if (aElement->ClassList()->Contains(NS_LITERAL_STRING("scale-thumb"))) {
|
||||
return new XULThumbAccessible(aElement, aContext->Document());
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
@ -171,8 +161,8 @@ XULMAP(
|
|||
|
||||
XULMAP(
|
||||
tree,
|
||||
[](nsIContent* aContent, Accessible* aContext) -> Accessible* {
|
||||
nsIContent* child = nsTreeUtils::GetDescendantChild(aContent,
|
||||
[](Element* aElement, Accessible* aContext) -> Accessible* {
|
||||
nsIContent* child = nsTreeUtils::GetDescendantChild(aElement,
|
||||
nsGkAtoms::treechildren);
|
||||
if (!child)
|
||||
return nullptr;
|
||||
|
@ -187,10 +177,10 @@ XULMAP(
|
|||
|
||||
// Outline of list accessible.
|
||||
if (count == 1) {
|
||||
return new XULTreeAccessible(aContent, aContext->Document(), treeFrame);
|
||||
return new XULTreeAccessible(aElement, aContext->Document(), treeFrame);
|
||||
}
|
||||
|
||||
// Table or tree table accessible.
|
||||
return new XULTreeGridAccessibleWrap(aContent, aContext->Document(), treeFrame);
|
||||
return new XULTreeGridAccessibleWrap(aElement, aContext->Document(), treeFrame);
|
||||
}
|
||||
)
|
||||
|
|
|
@ -149,7 +149,7 @@ MustBeAccessible(nsIContent* aContent, DocAccessible* aDocument)
|
|||
*/
|
||||
#ifdef MOZ_XUL
|
||||
Accessible*
|
||||
CreateMenupopupAccessible(nsIContent* aContent, Accessible* aContext)
|
||||
CreateMenupopupAccessible(Element* aElement, Accessible* aContext)
|
||||
{
|
||||
#ifdef MOZ_ACCESSIBILITY_ATK
|
||||
// ATK considers this node to be redundant when within menubars, and it makes menu
|
||||
|
@ -157,12 +157,12 @@ CreateMenupopupAccessible(nsIContent* aContent, Accessible* aContext)
|
|||
// XXX In the future we will should this for consistency across the nsIAccessible
|
||||
// implementations on each platform for a consistent scripting environment, but
|
||||
// then strip out redundant accessibles in the AccessibleWrap class for each platform.
|
||||
nsIContent *parent = aContent->GetParent();
|
||||
nsIContent *parent = aElement->GetParent();
|
||||
if (parent && parent->IsXULElement(nsGkAtoms::menu))
|
||||
return nullptr;
|
||||
#endif
|
||||
|
||||
return new XULMenupopupAccessible(aContent, aContext->Document());
|
||||
return new XULMenupopupAccessible(aElement, aContext->Document());
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -170,128 +170,122 @@ CreateMenupopupAccessible(nsIContent* aContent, Accessible* aContext)
|
|||
// Accessible constructors
|
||||
|
||||
static Accessible*
|
||||
New_HTMLLink(nsIContent* aContent, Accessible* aContext)
|
||||
New_HTMLLink(Element* aElement, Accessible* aContext)
|
||||
{
|
||||
// Only some roles truly enjoy life as HTMLLinkAccessibles, for details
|
||||
// see closed bug 494807.
|
||||
const nsRoleMapEntry* roleMapEntry = aria::GetRoleMap(aContent->AsElement());
|
||||
const nsRoleMapEntry* roleMapEntry = aria::GetRoleMap(aElement);
|
||||
if (roleMapEntry && roleMapEntry->role != roles::NOTHING &&
|
||||
roleMapEntry->role != roles::LINK) {
|
||||
return new HyperTextAccessibleWrap(aContent, aContext->Document());
|
||||
return new HyperTextAccessibleWrap(aElement, aContext->Document());
|
||||
}
|
||||
|
||||
return new HTMLLinkAccessible(aContent, aContext->Document());
|
||||
return new HTMLLinkAccessible(aElement, aContext->Document());
|
||||
}
|
||||
|
||||
static Accessible* New_HyperText(nsIContent* aContent, Accessible* aContext)
|
||||
{ return new HyperTextAccessibleWrap(aContent, aContext->Document()); }
|
||||
static Accessible* New_HyperText(Element* aElement, Accessible* aContext)
|
||||
{ return new HyperTextAccessibleWrap(aElement, aContext->Document()); }
|
||||
|
||||
static Accessible* New_HTMLFigcaption(nsIContent* aContent, Accessible* aContext)
|
||||
{ return new HTMLFigcaptionAccessible(aContent, aContext->Document()); }
|
||||
static Accessible* New_HTMLFigcaption(Element* aElement, Accessible* aContext)
|
||||
{ return new HTMLFigcaptionAccessible(aElement, aContext->Document()); }
|
||||
|
||||
static Accessible* New_HTMLFigure(nsIContent* aContent, Accessible* aContext)
|
||||
{ return new HTMLFigureAccessible(aContent, aContext->Document()); }
|
||||
static Accessible* New_HTMLFigure(Element* aElement, Accessible* aContext)
|
||||
{ return new HTMLFigureAccessible(aElement, aContext->Document()); }
|
||||
|
||||
static Accessible* New_HTMLHeaderOrFooter(nsIContent* aContent, Accessible* aContext)
|
||||
{ return new HTMLHeaderOrFooterAccessible(aContent, aContext->Document()); }
|
||||
static Accessible* New_HTMLHeaderOrFooter(Element* aElement, Accessible* aContext)
|
||||
{ return new HTMLHeaderOrFooterAccessible(aElement, aContext->Document()); }
|
||||
|
||||
static Accessible* New_HTMLLegend(nsIContent* aContent, Accessible* aContext)
|
||||
{ return new HTMLLegendAccessible(aContent, aContext->Document()); }
|
||||
static Accessible* New_HTMLLegend(Element* aElement, Accessible* aContext)
|
||||
{ return new HTMLLegendAccessible(aElement, aContext->Document()); }
|
||||
|
||||
static Accessible* New_HTMLOption(nsIContent* aContent, Accessible* aContext)
|
||||
{ return new HTMLSelectOptionAccessible(aContent, aContext->Document()); }
|
||||
static Accessible* New_HTMLOption(Element* aElement, Accessible* aContext)
|
||||
{ return new HTMLSelectOptionAccessible(aElement, aContext->Document()); }
|
||||
|
||||
static Accessible* New_HTMLOptgroup(nsIContent* aContent, Accessible* aContext)
|
||||
{ return new HTMLSelectOptGroupAccessible(aContent, aContext->Document()); }
|
||||
static Accessible* New_HTMLOptgroup(Element* aElement, Accessible* aContext)
|
||||
{ return new HTMLSelectOptGroupAccessible(aElement, aContext->Document()); }
|
||||
|
||||
static Accessible* New_HTMLList(nsIContent* aContent, Accessible* aContext)
|
||||
{ return new HTMLListAccessible(aContent, aContext->Document()); }
|
||||
static Accessible* New_HTMLList(Element* aElement, Accessible* aContext)
|
||||
{ return new HTMLListAccessible(aElement, aContext->Document()); }
|
||||
|
||||
static Accessible*
|
||||
New_HTMLListitem(nsIContent* aContent, Accessible* aContext)
|
||||
New_HTMLListitem(Element* aElement, Accessible* aContext)
|
||||
{
|
||||
// If list item is a child of accessible list then create an accessible for
|
||||
// it unconditionally by tag name. nsBlockFrame creates the list item
|
||||
// accessible for other elements styled as list items.
|
||||
if (aContext->IsList() && aContext->GetContent() == aContent->GetParent())
|
||||
return new HTMLLIAccessible(aContent, aContext->Document());
|
||||
if (aContext->IsList() && aContext->GetContent() == aElement->GetParent())
|
||||
return new HTMLLIAccessible(aElement, aContext->Document());
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
static Accessible*
|
||||
New_HTMLDefinition(nsIContent* aContent, Accessible* aContext)
|
||||
New_HTMLDefinition(Element* aElement, Accessible* aContext)
|
||||
{
|
||||
if (aContext->IsList())
|
||||
return new HyperTextAccessibleWrap(aContent, aContext->Document());
|
||||
return new HyperTextAccessibleWrap(aElement, aContext->Document());
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
static Accessible* New_HTMLLabel(nsIContent* aContent, Accessible* aContext)
|
||||
{ return new HTMLLabelAccessible(aContent, aContext->Document()); }
|
||||
static Accessible* New_HTMLLabel(Element* aElement, Accessible* aContext)
|
||||
{ return new HTMLLabelAccessible(aElement, aContext->Document()); }
|
||||
|
||||
static Accessible* New_HTMLInput(nsIContent* aContent, Accessible* aContext)
|
||||
static Accessible* New_HTMLInput(Element* aElement, Accessible* aContext)
|
||||
{
|
||||
if (!aContent->IsElement()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Element* element = aContent->AsElement();
|
||||
if (element->AttrValueIs(kNameSpaceID_None, nsGkAtoms::type,
|
||||
if (aElement->AttrValueIs(kNameSpaceID_None, nsGkAtoms::type,
|
||||
nsGkAtoms::checkbox, eIgnoreCase)) {
|
||||
return new HTMLCheckboxAccessible(aContent, aContext->Document());
|
||||
return new HTMLCheckboxAccessible(aElement, aContext->Document());
|
||||
}
|
||||
if (element->AttrValueIs(kNameSpaceID_None, nsGkAtoms::type,
|
||||
if (aElement->AttrValueIs(kNameSpaceID_None, nsGkAtoms::type,
|
||||
nsGkAtoms::radio, eIgnoreCase)) {
|
||||
return new HTMLRadioButtonAccessible(aContent, aContext->Document());
|
||||
return new HTMLRadioButtonAccessible(aElement, aContext->Document());
|
||||
}
|
||||
if (element->AttrValueIs(kNameSpaceID_None, nsGkAtoms::type,
|
||||
if (aElement->AttrValueIs(kNameSpaceID_None, nsGkAtoms::type,
|
||||
nsGkAtoms::time, eIgnoreCase)) {
|
||||
return new EnumRoleAccessible<roles::GROUPING>(aContent, aContext->Document());
|
||||
return new EnumRoleAccessible<roles::GROUPING>(aElement, aContext->Document());
|
||||
}
|
||||
if (element->AttrValueIs(kNameSpaceID_None, nsGkAtoms::type,
|
||||
if (aElement->AttrValueIs(kNameSpaceID_None, nsGkAtoms::type,
|
||||
nsGkAtoms::date, eIgnoreCase)) {
|
||||
return new EnumRoleAccessible<roles::DATE_EDITOR>(aContent, aContext->Document());
|
||||
return new EnumRoleAccessible<roles::DATE_EDITOR>(aElement, aContext->Document());
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
static Accessible* New_HTMLOutput(nsIContent* aContent, Accessible* aContext)
|
||||
{ return new HTMLOutputAccessible(aContent, aContext->Document()); }
|
||||
static Accessible* New_HTMLOutput(Element* aElement, Accessible* aContext)
|
||||
{ return new HTMLOutputAccessible(aElement, aContext->Document()); }
|
||||
|
||||
static Accessible* New_HTMLProgress(nsIContent* aContent, Accessible* aContext)
|
||||
{ return new HTMLProgressMeterAccessible(aContent, aContext->Document()); }
|
||||
static Accessible* New_HTMLProgress(Element* aElement, Accessible* aContext)
|
||||
{ return new HTMLProgressMeterAccessible(aElement, aContext->Document()); }
|
||||
|
||||
static Accessible* New_HTMLSummary(nsIContent* aContent, Accessible* aContext)
|
||||
{ return new HTMLSummaryAccessible(aContent, aContext->Document()); }
|
||||
static Accessible* New_HTMLSummary(Element* aElement, Accessible* aContext)
|
||||
{ return new HTMLSummaryAccessible(aElement, aContext->Document()); }
|
||||
|
||||
static Accessible*
|
||||
New_HTMLTableAccessible(nsIContent* aContent, Accessible* aContext)
|
||||
{ return new HTMLTableAccessible(aContent, aContext->Document()); }
|
||||
New_HTMLTableAccessible(Element* aElement, Accessible* aContext)
|
||||
{ return new HTMLTableAccessible(aElement, aContext->Document()); }
|
||||
|
||||
static Accessible*
|
||||
New_HTMLTableRowAccessible(nsIContent* aContent, Accessible* aContext)
|
||||
{ return new HTMLTableRowAccessible(aContent, aContext->Document()); }
|
||||
New_HTMLTableRowAccessible(Element* aElement, Accessible* aContext)
|
||||
{ return new HTMLTableRowAccessible(aElement, aContext->Document()); }
|
||||
|
||||
static Accessible*
|
||||
New_HTMLTableCellAccessible(nsIContent* aContent, Accessible* aContext)
|
||||
{ return new HTMLTableCellAccessible(aContent, aContext->Document()); }
|
||||
New_HTMLTableCellAccessible(Element* aElement, Accessible* aContext)
|
||||
{ return new HTMLTableCellAccessible(aElement, aContext->Document()); }
|
||||
|
||||
static Accessible*
|
||||
New_HTMLTableHeaderCell(nsIContent* aContent, Accessible* aContext)
|
||||
New_HTMLTableHeaderCell(Element* aElement, Accessible* aContext)
|
||||
{
|
||||
if (aContext->IsTableRow() && aContext->GetContent() == aContent->GetParent())
|
||||
return new HTMLTableHeaderCellAccessibleWrap(aContent, aContext->Document());
|
||||
if (aContext->IsTableRow() && aContext->GetContent() == aElement->GetParent())
|
||||
return new HTMLTableHeaderCellAccessibleWrap(aElement, aContext->Document());
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
static Accessible*
|
||||
New_HTMLTableHeaderCellIfScope(nsIContent* aContent, Accessible* aContext)
|
||||
New_HTMLTableHeaderCellIfScope(Element* aElement, Accessible* aContext)
|
||||
{
|
||||
if (aContext->IsTableRow() && aContext->GetContent() == aContent->GetParent() &&
|
||||
aContent->IsElement() &&
|
||||
aContent->AsElement()->HasAttr(kNameSpaceID_None, nsGkAtoms::scope))
|
||||
return new HTMLTableHeaderCellAccessibleWrap(aContent, aContext->Document());
|
||||
if (aContext->IsTableRow() && aContext->GetContent() == aElement->GetParent() &&
|
||||
aElement->HasAttr(kNameSpaceID_None, nsGkAtoms::scope))
|
||||
return new HTMLTableHeaderCellAccessibleWrap(aElement, aContext->Document());
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
@ -328,8 +322,8 @@ static const HTMLMarkupMapInfo sHTMLMarkupMapList[] = {
|
|||
#define XULMAP_TYPE(atom, new_type) \
|
||||
XULMAP( \
|
||||
atom, \
|
||||
[](nsIContent* aContent, Accessible* aContext) -> Accessible* { \
|
||||
return new new_type(aContent, aContext->Document()); \
|
||||
[](Element* aElement, Accessible* aContext) -> Accessible* { \
|
||||
return new new_type(aElement, aContext->Document()); \
|
||||
} \
|
||||
)
|
||||
|
||||
|
@ -1177,7 +1171,7 @@ nsAccessibilityService::CreateAccessible(nsINode* aNode,
|
|||
const HTMLMarkupMapInfo* markupMap =
|
||||
mHTMLMarkupMap.Get(content->NodeInfo()->NameAtom());
|
||||
if (markupMap && markupMap->new_func)
|
||||
newAcc = markupMap->new_func(content, aContext);
|
||||
newAcc = markupMap->new_func(content->AsElement(), aContext);
|
||||
|
||||
if (!newAcc) // try by frame accessible type.
|
||||
newAcc = CreateAccessibleByFrameType(frame, content, aContext);
|
||||
|
@ -1240,7 +1234,7 @@ nsAccessibilityService::CreateAccessible(nsINode* aNode,
|
|||
const XULMarkupMapInfo* xulMap =
|
||||
mXULMarkupMap.Get(content->NodeInfo()->NameAtom());
|
||||
if (xulMap && xulMap->new_func) {
|
||||
newAcc = xulMap->new_func(content, aContext);
|
||||
newAcc = xulMap->new_func(content->AsElement(), aContext);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -1272,7 +1266,7 @@ nsAccessibilityService::CreateAccessible(nsINode* aNode,
|
|||
const HTMLMarkupMapInfo* markupMap =
|
||||
mHTMLMarkupMap.Get(content->NodeInfo()->NameAtom());
|
||||
if (markupMap && markupMap->new_func)
|
||||
newAcc = markupMap->new_func(content, aContext);
|
||||
newAcc = markupMap->new_func(content->AsElement(), aContext);
|
||||
|
||||
// Fall back to text when encountering Content MathML.
|
||||
if (!newAcc && !content->IsAnyOfMathMLElements(nsGkAtoms::annotation_,
|
||||
|
|
|
@ -51,7 +51,7 @@ SelectionManager* SelectionMgr();
|
|||
ApplicationAccessible* ApplicationAcc();
|
||||
xpcAccessibleApplication* XPCApplicationAcc();
|
||||
|
||||
typedef Accessible* (New_Accessible)(nsIContent* aContent, Accessible* aContext);
|
||||
typedef Accessible* (New_Accessible)(Element* aElement, Accessible* aContext);
|
||||
|
||||
struct MarkupAttrInfo {
|
||||
nsStaticAtom** name;
|
||||
|
|
|
@ -339,6 +339,7 @@ add_task(async function checkAllTheCSS() {
|
|||
iframe.contentWindow.location = testFile;
|
||||
await iframeLoaded;
|
||||
let doc = iframe.contentWindow.document;
|
||||
doc.docShell.cssErrorReportingEnabled = true;
|
||||
|
||||
// Parse and remove all manifests from the list.
|
||||
// NOTE that this must be done before filtering out devtools paths
|
||||
|
|
|
@ -40,6 +40,7 @@ function AccessibilityPanel(iframeWindow, toolbox) {
|
|||
this.onAccessibilityInspectorUpdated.bind(this);
|
||||
this.updateA11YServiceDurationTimer = this.updateA11YServiceDurationTimer.bind(this);
|
||||
this.updatePickerButton = this.updatePickerButton.bind(this);
|
||||
this.updateToolboxButtons = this.updateToolboxButtons.bind(this);
|
||||
|
||||
EventEmitter.decorate(this);
|
||||
}
|
||||
|
@ -130,11 +131,11 @@ AccessibilityPanel.prototype = {
|
|||
this.cancelPicker();
|
||||
|
||||
if (this.isVisible) {
|
||||
this._front.on("init", this.updatePickerButton);
|
||||
this._front.on("shutdown", this.updatePickerButton);
|
||||
this._front.on("init", this.updateToolboxButtons);
|
||||
this._front.on("shutdown", this.updateToolboxButtons);
|
||||
} else {
|
||||
this._front.off("init", this.updatePickerButton);
|
||||
this._front.off("shutdown", this.updatePickerButton);
|
||||
this._front.off("init", this.updateToolboxButtons);
|
||||
this._front.off("shutdown", this.updateToolboxButtons);
|
||||
// Do not refresh if the panel isn't visible.
|
||||
return;
|
||||
}
|
||||
|
@ -183,6 +184,10 @@ AccessibilityPanel.prototype = {
|
|||
this.panelWin.dispatchEvent(event);
|
||||
},
|
||||
|
||||
updateToolboxButtons() {
|
||||
this._toolbox.updatePickerButton();
|
||||
},
|
||||
|
||||
updatePickerButton() {
|
||||
this.picker && this.picker.updateButton();
|
||||
},
|
||||
|
|
|
@ -145,6 +145,7 @@ support-files =
|
|||
[browser_dbg-asm.js]
|
||||
[browser_dbg-async-stepping.js]
|
||||
[browser_dbg-babel-breakpoint-console.js]
|
||||
skip-if = (os == "win" && ccov) # Bug 1453549
|
||||
[browser_dbg-babel-scopes.js]
|
||||
skip-if = ccov # Bug 1441545
|
||||
[browser_dbg-babel-stepping.js]
|
||||
|
|
|
@ -155,7 +155,7 @@ function Toolbox(target, selectedTool, hostType, contentWindow, frameId) {
|
|||
this._onPickerStopped = this._onPickerStopped.bind(this);
|
||||
this._onInspectObject = this._onInspectObject.bind(this);
|
||||
this._onNewSelectedNodeFront = this._onNewSelectedNodeFront.bind(this);
|
||||
this._updatePickerButton = this._updatePickerButton.bind(this);
|
||||
this.updatePickerButton = this.updatePickerButton.bind(this);
|
||||
this.selectTool = this.selectTool.bind(this);
|
||||
this.toggleSplitConsole = this.toggleSplitConsole.bind(this);
|
||||
|
||||
|
@ -180,7 +180,7 @@ function Toolbox(target, selectedTool, hostType, contentWindow, frameId) {
|
|||
|
||||
this.on("host-changed", this._refreshHostTitle);
|
||||
this.on("select", this._refreshHostTitle);
|
||||
this.on("select", this._updatePickerButton);
|
||||
this.on("select", this.updatePickerButton);
|
||||
|
||||
this.on("ready", this._showDevEditionPromo);
|
||||
|
||||
|
@ -1365,7 +1365,7 @@ Toolbox.prototype = {
|
|||
* update the visual state of the picker button such as disabled state,
|
||||
* additional CSS classes (className), and tooltip (description).
|
||||
*/
|
||||
_updatePickerButton() {
|
||||
updatePickerButton() {
|
||||
const button = this.pickerButton;
|
||||
let currentPanel = this.getCurrentPanel();
|
||||
|
||||
|
@ -2670,7 +2670,7 @@ Toolbox.prototype = {
|
|||
this._target.off("navigate", this._refreshHostTitle);
|
||||
this._target.off("frame-update", this._updateFrames);
|
||||
this.off("select", this._refreshHostTitle);
|
||||
this.off("select", this._updatePickerButton);
|
||||
this.off("select", this.updatePickerButton);
|
||||
this.off("host-changed", this._refreshHostTitle);
|
||||
this.off("ready", this._showDevEditionPromo);
|
||||
|
||||
|
|
|
@ -7,11 +7,6 @@
|
|||
// Tests that the contextual menu items shown when clicking on linked attributes
|
||||
// for <script> and <link> tags actually open the right tools.
|
||||
|
||||
// The following rejection should not be left uncaught. This test has been
|
||||
// whitelisted until the issue is fixed.
|
||||
ChromeUtils.import("resource://testing-common/PromiseTestUtils.jsm", this);
|
||||
PromiseTestUtils.expectUncaughtRejection(/NS_ERROR_NOT_INITIALIZED/);
|
||||
|
||||
const TEST_URL = URL_ROOT + "doc_markup_links.html";
|
||||
|
||||
add_task(async function() {
|
||||
|
|
|
@ -22,6 +22,8 @@ const {
|
|||
REMOVED_ACTORS_CLEAR,
|
||||
NETWORK_MESSAGE_UPDATE,
|
||||
PREFS,
|
||||
INITIALIZE,
|
||||
FILTER_TOGGLE,
|
||||
} = require("devtools/client/webconsole/constants");
|
||||
const { reducers } = require("./reducers/index");
|
||||
const {
|
||||
|
@ -77,6 +79,7 @@ function configureStore(hud, options = {}) {
|
|||
enableBatching(),
|
||||
enableNetProvider(hud),
|
||||
enableMessagesCacheClearing(hud),
|
||||
ensureCSSErrorReportingEnabled(hud),
|
||||
)
|
||||
);
|
||||
}
|
||||
|
@ -165,6 +168,34 @@ function enableActorReleaser(hud) {
|
|||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* This is responsible for ensuring that error reporting is enabled if the CSS
|
||||
* filter is toggled on.
|
||||
*/
|
||||
function ensureCSSErrorReportingEnabled(hud) {
|
||||
return next => (reducer, initialState, enhancer) => {
|
||||
function ensureErrorReportingEnhancer(state, action) {
|
||||
let proxy = hud ? hud.proxy : null;
|
||||
if (!proxy) {
|
||||
return reducer(state, action);
|
||||
}
|
||||
|
||||
state = reducer(state, action);
|
||||
if (!state.filters.css) {
|
||||
return state;
|
||||
}
|
||||
|
||||
let cssFilterToggled =
|
||||
action.type == FILTER_TOGGLE && action.filter == "css";
|
||||
if (cssFilterToggled || action.type == INITIALIZE) {
|
||||
proxy.target.activeTab.ensureCSSErrorReportingEnabled();
|
||||
}
|
||||
return state;
|
||||
}
|
||||
return next(ensureErrorReportingEnhancer, initialState, enhancer);
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* This enhancer is responsible for fetching HTTP details data
|
||||
* collected by the backend. The fetch happens on-demand
|
||||
|
|
|
@ -370,6 +370,7 @@ async function generateCssMessageStubs() {
|
|||
gBrowser.selectedBrowser,
|
||||
[key, code],
|
||||
function([subKey, subCode]) {
|
||||
content.document.docShell.cssErrorReportingEnabled = true;
|
||||
let style = content.document.createElement("style");
|
||||
// eslint-disable-next-line no-unsanitized/property
|
||||
style.innerHTML = subCode;
|
||||
|
|
|
@ -9,19 +9,14 @@
|
|||
"use strict";
|
||||
|
||||
const TEST_URI = "data:text/html;charset=utf8,<p>hello world" +
|
||||
"<button onclick='foobar.explode()' " +
|
||||
"style='test-color: green-please'>click!</button>";
|
||||
"<button onclick='foobar.explode()'>click!</button>";
|
||||
|
||||
add_task(async function() {
|
||||
await addTab(TEST_URI);
|
||||
|
||||
let hud = await HUDService.toggleBrowserConsole();
|
||||
ok(hud, "browser console opened");
|
||||
|
||||
// Enable CSS warnings and errors.
|
||||
await setFilterState(hud, {
|
||||
css: true
|
||||
});
|
||||
|
||||
// On e10s, the exception is triggered in child process
|
||||
// and is ignored by test harness
|
||||
if (!Services.appinfo.browserTabsRemoteAutostart) {
|
||||
|
@ -36,9 +31,6 @@ add_task(async function() {
|
|||
|
||||
await waitForMessageAndViewSource(hud,
|
||||
"ReferenceError: foobar is not defined");
|
||||
await waitForMessageAndViewSource(hud,
|
||||
"Unknown property \u2018test-color\u2019.");
|
||||
await resetFilters(hud);
|
||||
});
|
||||
|
||||
async function waitForMessageAndViewSource(hud, message) {
|
||||
|
|
|
@ -25,17 +25,18 @@ add_task(async function() {
|
|||
|
||||
info("Open the console");
|
||||
let hud = await openConsole();
|
||||
testMessagesVisibility(hud);
|
||||
|
||||
await testMessagesVisibility(hud, true);
|
||||
|
||||
info("Close the toolbox");
|
||||
await closeToolbox();
|
||||
|
||||
info("Open the console again");
|
||||
hud = await openConsole();
|
||||
testMessagesVisibility(hud);
|
||||
await testMessagesVisibility(hud, false);
|
||||
});
|
||||
|
||||
function testMessagesVisibility(hud) {
|
||||
async function testMessagesVisibility(hud, waitForCSSMessage) {
|
||||
let message = findMessage(hud, "log Bazzle", ".message.log");
|
||||
ok(message, "console.log message is visible");
|
||||
|
||||
|
@ -45,6 +46,11 @@ function testMessagesVisibility(hud) {
|
|||
message = findMessage(hud, "bazBug611032", ".message.error");
|
||||
ok(message, "exception message is visible");
|
||||
|
||||
// The CSS message arrives lazily, so spin a bit for it unless it should be
|
||||
// cached.
|
||||
if (waitForCSSMessage) {
|
||||
await waitForMessage(hud, "cssColorBug611032");
|
||||
}
|
||||
message = findMessage(hud, "cssColorBug611032", ".message.warn.css");
|
||||
ok(message, "css warning message is visible");
|
||||
}
|
||||
|
|
|
@ -125,6 +125,137 @@ var MediaRuleActor = protocol.ActorClassWithSpec(mediaRuleSpec, {
|
|||
}
|
||||
});
|
||||
|
||||
function getSheetText(sheet, consoleActor) {
|
||||
let cssText = modifiedStyleSheets.get(sheet);
|
||||
if (cssText !== undefined) {
|
||||
return Promise.resolve(cssText);
|
||||
}
|
||||
|
||||
if (!sheet.href) {
|
||||
// this is an inline <style> sheet
|
||||
let content = sheet.ownerNode.textContent;
|
||||
return Promise.resolve(content);
|
||||
}
|
||||
|
||||
return fetchStylesheet(sheet, consoleActor).then(({ content }) => content);
|
||||
}
|
||||
|
||||
exports.getSheetText = getSheetText;
|
||||
|
||||
/**
|
||||
* Try to fetch the stylesheet text from the network monitor. If it was enabled during
|
||||
* the load, it should have a copy of the text saved.
|
||||
*
|
||||
* @param string href
|
||||
* The URL of the sheet to fetch.
|
||||
*/
|
||||
function fetchStylesheetFromNetworkMonitor(href, consoleActor) {
|
||||
if (!consoleActor) {
|
||||
return null;
|
||||
}
|
||||
let request = consoleActor.getNetworkEventActorForURL(href);
|
||||
if (!request) {
|
||||
return null;
|
||||
}
|
||||
let content = request._response.content;
|
||||
if (request._discardResponseBody || request._truncated || !content) {
|
||||
return null;
|
||||
}
|
||||
if (content.text.type != "longString") {
|
||||
// For short strings, the text is available directly.
|
||||
return {
|
||||
content: content.text,
|
||||
contentType: content.mimeType,
|
||||
};
|
||||
}
|
||||
// For long strings, look up the actor that holds the full text.
|
||||
let longStringActor = consoleActor.conn._getOrCreateActor(content.text.actor);
|
||||
if (!longStringActor) {
|
||||
return null;
|
||||
}
|
||||
return {
|
||||
content: longStringActor.rawValue(),
|
||||
contentType: content.mimeType,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the charset of the stylesheet.
|
||||
*/
|
||||
function getCSSCharset(sheet) {
|
||||
if (sheet) {
|
||||
// charset attribute of <link> or <style> element, if it exists
|
||||
if (sheet.ownerNode && sheet.ownerNode.getAttribute) {
|
||||
let linkCharset = sheet.ownerNode.getAttribute("charset");
|
||||
if (linkCharset != null) {
|
||||
return linkCharset;
|
||||
}
|
||||
}
|
||||
|
||||
// charset of referring document.
|
||||
if (sheet.ownerNode && sheet.ownerNode.ownerDocument.characterSet) {
|
||||
return sheet.ownerNode.ownerDocument.characterSet;
|
||||
}
|
||||
}
|
||||
|
||||
return "UTF-8";
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch a stylesheet at the provided URL. Returns a promise that will resolve the
|
||||
* result of the fetch command.
|
||||
*
|
||||
* @return {Promise} a promise that resolves with an object with the following members
|
||||
* on success:
|
||||
* - content: the document at that URL, as a string,
|
||||
* - contentType: the content type of the document
|
||||
* If an error occurs, the promise is rejected with that error.
|
||||
*/
|
||||
async function fetchStylesheet(sheet, consoleActor) {
|
||||
let href = sheet.href;
|
||||
|
||||
let result = fetchStylesheetFromNetworkMonitor(href, consoleActor);
|
||||
if (result) {
|
||||
return result;
|
||||
}
|
||||
|
||||
let options = {
|
||||
loadFromCache: true,
|
||||
policy: Ci.nsIContentPolicy.TYPE_INTERNAL_STYLESHEET,
|
||||
charset: getCSSCharset(sheet)
|
||||
};
|
||||
|
||||
// Bug 1282660 - We use the system principal to load the default internal
|
||||
// stylesheets instead of the content principal since such stylesheets
|
||||
// require system principal to load. At meanwhile, we strip the loadGroup
|
||||
// for preventing the assertion of the userContextId mismatching.
|
||||
|
||||
// chrome|file|resource|moz-extension protocols rely on the system principal.
|
||||
let excludedProtocolsRe = /^(chrome|file|resource|moz-extension):\/\//;
|
||||
if (!excludedProtocolsRe.test(href)) {
|
||||
// Stylesheets using other protocols should use the content principal.
|
||||
if (sheet.ownerNode) {
|
||||
// eslint-disable-next-line mozilla/use-ownerGlobal
|
||||
options.window = sheet.ownerNode.ownerDocument.defaultView;
|
||||
options.principal = sheet.ownerNode.ownerDocument.nodePrincipal;
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
result = await fetch(href, options);
|
||||
} catch (e) {
|
||||
// The list of excluded protocols can be missing some protocols, try to use the
|
||||
// system principal if the first fetch failed.
|
||||
console.error(`stylesheets actor: fetch failed for ${href},` +
|
||||
` using system principal instead.`);
|
||||
options.window = undefined;
|
||||
options.principal = undefined;
|
||||
result = await fetch(href, options);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* A StyleSheetActor represents a stylesheet on the server.
|
||||
*/
|
||||
|
@ -372,80 +503,16 @@ var StyleSheetActor = protocol.ActorClassWithSpec(styleSheetSpec, {
|
|||
return Promise.resolve(this.text);
|
||||
}
|
||||
|
||||
let cssText = modifiedStyleSheets.get(this.rawSheet);
|
||||
if (cssText !== undefined) {
|
||||
this.text = cssText;
|
||||
return Promise.resolve(cssText);
|
||||
}
|
||||
|
||||
if (!this.href) {
|
||||
// this is an inline <style> sheet
|
||||
let content = this.ownerNode.textContent;
|
||||
this.text = content;
|
||||
return Promise.resolve(content);
|
||||
}
|
||||
|
||||
return this.fetchStylesheet(this.href).then(({ content }) => {
|
||||
this.text = content;
|
||||
return content;
|
||||
return getSheetText(this.rawSheet, this._consoleActor).then(text => {
|
||||
this.text = text;
|
||||
return text;
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Fetch a stylesheet at the provided URL. Returns a promise that will resolve the
|
||||
* result of the fetch command.
|
||||
*
|
||||
* @param {String} href
|
||||
* The href of the stylesheet to retrieve.
|
||||
* @return {Promise} a promise that resolves with an object with the following members
|
||||
* on success:
|
||||
* - content: the document at that URL, as a string,
|
||||
* - contentType: the content type of the document
|
||||
* If an error occurs, the promise is rejected with that error.
|
||||
*/
|
||||
async fetchStylesheet(href) {
|
||||
// Check if network monitor observed this load, and if so, use that.
|
||||
let result = this.fetchStylesheetFromNetworkMonitor(href);
|
||||
if (result) {
|
||||
return result;
|
||||
}
|
||||
|
||||
let options = {
|
||||
loadFromCache: true,
|
||||
policy: Ci.nsIContentPolicy.TYPE_INTERNAL_STYLESHEET,
|
||||
charset: this._getCSSCharset()
|
||||
};
|
||||
|
||||
// Bug 1282660 - We use the system principal to load the default internal
|
||||
// stylesheets instead of the content principal since such stylesheets
|
||||
// require system principal to load. At meanwhile, we strip the loadGroup
|
||||
// for preventing the assertion of the userContextId mismatching.
|
||||
|
||||
// chrome|file|resource|moz-extension protocols rely on the system principal.
|
||||
let excludedProtocolsRe = /^(chrome|file|resource|moz-extension):\/\//;
|
||||
if (!excludedProtocolsRe.test(this.href)) {
|
||||
// Stylesheets using other protocols should use the content principal.
|
||||
options.window = this.ownerWindow;
|
||||
options.principal = this.ownerDocument.nodePrincipal;
|
||||
}
|
||||
|
||||
try {
|
||||
result = await fetch(this.href, options);
|
||||
} catch (e) {
|
||||
// The list of excluded protocols can be missing some protocols, try to use the
|
||||
// system principal if the first fetch failed.
|
||||
console.error(`stylesheets actor: fetch failed for ${this.href},` +
|
||||
` using system principal instead.`);
|
||||
options.window = undefined;
|
||||
options.principal = undefined;
|
||||
result = await fetch(this.href, options);
|
||||
}
|
||||
|
||||
return result;
|
||||
},
|
||||
|
||||
/**
|
||||
* Try to locate the console actor if it exists via our parent actor (the tab).
|
||||
*
|
||||
* Keep this in sync with the TabActor version.
|
||||
*/
|
||||
get _consoleActor() {
|
||||
if (this.parentActor.exited) {
|
||||
|
@ -455,44 +522,6 @@ var StyleSheetActor = protocol.ActorClassWithSpec(styleSheetSpec, {
|
|||
return this.conn._getOrCreateActor(form.consoleActor);
|
||||
},
|
||||
|
||||
/**
|
||||
* Try to fetch the stylesheet text from the network monitor. If it was enabled during
|
||||
* the load, it should have a copy of the text saved.
|
||||
*
|
||||
* @param string href
|
||||
* The URL of the sheet to fetch.
|
||||
*/
|
||||
fetchStylesheetFromNetworkMonitor(href) {
|
||||
let consoleActor = this._consoleActor;
|
||||
if (!consoleActor) {
|
||||
return null;
|
||||
}
|
||||
let request = consoleActor.getNetworkEventActorForURL(href);
|
||||
if (!request) {
|
||||
return null;
|
||||
}
|
||||
let content = request._response.content;
|
||||
if (request._discardResponseBody || request._truncated || !content) {
|
||||
return null;
|
||||
}
|
||||
if (content.text.type != "longString") {
|
||||
// For short strings, the text is available directly.
|
||||
return {
|
||||
content: content.text,
|
||||
contentType: content.mimeType,
|
||||
};
|
||||
}
|
||||
// For long strings, look up the actor that holds the full text.
|
||||
let longStringActor = this.conn._getOrCreateActor(content.text.actor);
|
||||
if (!longStringActor) {
|
||||
return null;
|
||||
}
|
||||
return {
|
||||
content: longStringActor.rawValue(),
|
||||
contentType: content.mimeType,
|
||||
};
|
||||
},
|
||||
|
||||
/**
|
||||
* Protocol method to get the media rules for the stylesheet.
|
||||
*/
|
||||
|
@ -523,49 +552,6 @@ var StyleSheetActor = protocol.ActorClassWithSpec(styleSheetSpec, {
|
|||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Get the charset of the stylesheet according to the character set rules
|
||||
* defined in <http://www.w3.org/TR/CSS2/syndata.html#charset>.
|
||||
* Note that some of the algorithm is implemented in DevToolsUtils.fetch.
|
||||
*/
|
||||
_getCSSCharset: function() {
|
||||
let sheet = this.rawSheet;
|
||||
if (sheet) {
|
||||
// Do we have a @charset rule in the stylesheet?
|
||||
// step 2 of syndata.html (without the BOM check).
|
||||
if (sheet.cssRules) {
|
||||
let rules = sheet.cssRules;
|
||||
if (rules.length
|
||||
&& rules.item(0).type == CSSRule.CHARSET_RULE) {
|
||||
return rules.item(0).encoding;
|
||||
}
|
||||
}
|
||||
|
||||
// step 3: charset attribute of <link> or <style> element, if it exists
|
||||
if (sheet.ownerNode && sheet.ownerNode.getAttribute) {
|
||||
let linkCharset = sheet.ownerNode.getAttribute("charset");
|
||||
if (linkCharset != null) {
|
||||
return linkCharset;
|
||||
}
|
||||
}
|
||||
|
||||
// step 4 (1 of 2): charset of referring stylesheet.
|
||||
let parentSheet = sheet.parentStyleSheet;
|
||||
if (parentSheet && parentSheet.cssRules &&
|
||||
parentSheet.cssRules[0].type == CSSRule.CHARSET_RULE) {
|
||||
return parentSheet.cssRules[0].encoding;
|
||||
}
|
||||
|
||||
// step 4 (2 of 2): charset of referring document.
|
||||
if (sheet.ownerNode && sheet.ownerNode.ownerDocument.characterSet) {
|
||||
return sheet.ownerNode.ownerDocument.characterSet;
|
||||
}
|
||||
}
|
||||
|
||||
// step 5: default to utf-8.
|
||||
return "UTF-8";
|
||||
},
|
||||
|
||||
/**
|
||||
* Update the style sheet in place with new text.
|
||||
*
|
||||
|
|
|
@ -24,6 +24,7 @@ var { assert } = DevToolsUtils;
|
|||
var { TabSources } = require("./utils/TabSources");
|
||||
var makeDebugger = require("./utils/make-debugger");
|
||||
const EventEmitter = require("devtools/shared/event-emitter");
|
||||
const InspectorUtils = require("InspectorUtils");
|
||||
|
||||
const EXTENSION_CONTENT_JSM = "resource://gre/modules/ExtensionContent.jsm";
|
||||
|
||||
|
@ -33,6 +34,7 @@ loader.lazyRequireGetter(this, "WorkerActorList", "devtools/server/actors/worker
|
|||
loader.lazyImporter(this, "ExtensionContent", EXTENSION_CONTENT_JSM);
|
||||
|
||||
loader.lazyRequireGetter(this, "StyleSheetActor", "devtools/server/actors/stylesheets", true);
|
||||
loader.lazyRequireGetter(this, "getSheetText", "devtools/server/actors/stylesheets", true);
|
||||
|
||||
function getWindowID(window) {
|
||||
return window.QueryInterface(Ci.nsIInterfaceRequestor)
|
||||
|
@ -258,6 +260,17 @@ TabActor.prototype = {
|
|||
return !!this._attached;
|
||||
},
|
||||
|
||||
/**
|
||||
* Try to locate the console actor if it exists.
|
||||
*/
|
||||
get _consoleActor() {
|
||||
if (this.exited) {
|
||||
return null;
|
||||
}
|
||||
let form = this.form();
|
||||
return this.conn._getOrCreateActor(form.consoleActor);
|
||||
},
|
||||
|
||||
_tabPool: null,
|
||||
get tabActorPool() {
|
||||
return this._tabPool;
|
||||
|
@ -1007,6 +1020,33 @@ TabActor.prototype = {
|
|||
return {};
|
||||
},
|
||||
|
||||
/**
|
||||
* Ensure that CSS error reporting is enabled.
|
||||
*/
|
||||
ensureCSSErrorReportingEnabled(request) {
|
||||
for (let docShell of this.docShells) {
|
||||
if (docShell.cssErrorReportingEnabled) {
|
||||
continue;
|
||||
}
|
||||
try {
|
||||
docShell.cssErrorReportingEnabled = true;
|
||||
} catch (e) {
|
||||
continue;
|
||||
}
|
||||
// We don't really want to reparse UA sheets and such, but want to do
|
||||
// Shadow DOM / XBL.
|
||||
let sheets =
|
||||
InspectorUtils.getAllStyleSheets(docShell.document, /* documentOnly = */ true);
|
||||
for (let sheet of sheets) {
|
||||
getSheetText(sheet, this._consoleActor).then(text => {
|
||||
InspectorUtils.parseStyleSheet(sheet, text, /* aUpdate = */ false);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return {};
|
||||
},
|
||||
|
||||
/**
|
||||
* Handle logic to enable/disable JS/cache/Service Worker testing.
|
||||
*/
|
||||
|
@ -1430,6 +1470,7 @@ TabActor.prototype.requestTypes = {
|
|||
"reload": TabActor.prototype.onReload,
|
||||
"navigateTo": TabActor.prototype.onNavigateTo,
|
||||
"reconfigure": TabActor.prototype.onReconfigure,
|
||||
"ensureCSSErrorReportingEnabled": TabActor.prototype.ensureCSSErrorReportingEnabled,
|
||||
"switchToFrame": TabActor.prototype.onSwitchToFrame,
|
||||
"listFrames": TabActor.prototype.onListFrames,
|
||||
"listWorkers": TabActor.prototype.onListWorkers,
|
||||
|
|
|
@ -102,6 +102,13 @@ TabClient.prototype = {
|
|||
type: "focus"
|
||||
}, {}),
|
||||
|
||||
/**
|
||||
* Ensure relevant pages have error reporting enabled.
|
||||
*/
|
||||
ensureCSSErrorReportingEnabled: DebuggerClient.requester({
|
||||
type: "ensureCSSErrorReportingEnabled",
|
||||
}, {}),
|
||||
|
||||
/**
|
||||
* Reload the page in this tab.
|
||||
*
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
<p>Test for cached messages</p>
|
||||
|
||||
<script class="testbody" type="application/javascript">
|
||||
document.docShell.cssErrorReportingEnabled = true;
|
||||
var ConsoleAPIStorage = Cc["@mozilla.org/consoleAPI-storage;1"]
|
||||
.getService(Ci.nsIConsoleAPIStorage);
|
||||
let expectedConsoleCalls = [];
|
||||
|
|
|
@ -362,6 +362,7 @@ nsDocShell::nsDocShell()
|
|||
, mAllowContentRetargetingOnChildren(true)
|
||||
, mUseErrorPages(false)
|
||||
, mObserveErrorPages(true)
|
||||
, mCSSErrorReportingEnabled(false)
|
||||
, mAllowAuth(true)
|
||||
, mAllowKeywordFixup(false)
|
||||
, mIsOffScreenBrowser(false)
|
||||
|
@ -1686,6 +1687,21 @@ nsDocShell::GetAllowJavascript(bool* aAllowJavascript)
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDocShell::GetCssErrorReportingEnabled(bool* aEnabled)
|
||||
{
|
||||
MOZ_ASSERT(aEnabled);
|
||||
*aEnabled = mCSSErrorReportingEnabled;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDocShell::SetCssErrorReportingEnabled(bool aEnabled)
|
||||
{
|
||||
mCSSErrorReportingEnabled = aEnabled;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDocShell::SetAllowJavascript(bool aAllowJavascript)
|
||||
{
|
||||
|
|
|
@ -890,6 +890,11 @@ private: // member functions
|
|||
return (mObserveErrorPages ? sUseErrorPages : mUseErrorPages);
|
||||
}
|
||||
|
||||
bool CSSErrorReportingEnabled() const
|
||||
{
|
||||
return mCSSErrorReportingEnabled;
|
||||
}
|
||||
|
||||
private: // data members
|
||||
static nsIURIFixup* sURIFixup;
|
||||
|
||||
|
@ -1108,6 +1113,7 @@ private: // data members
|
|||
bool mAllowContentRetargetingOnChildren : 1;
|
||||
bool mUseErrorPages : 1;
|
||||
bool mObserveErrorPages : 1;
|
||||
bool mCSSErrorReportingEnabled : 1;
|
||||
bool mAllowAuth : 1;
|
||||
bool mAllowKeywordFixup : 1;
|
||||
bool mIsOffScreenBrowser : 1;
|
||||
|
|
|
@ -289,10 +289,15 @@ interface nsIDocShell : nsIDocShellTreeItem
|
|||
attribute nsIDOMEventTarget chromeEventHandler;
|
||||
|
||||
/**
|
||||
* This allows chrome to set a custom User agent on a specific docshell
|
||||
*/
|
||||
* This allows chrome to set a custom User agent on a specific docshell
|
||||
*/
|
||||
attribute DOMString customUserAgent;
|
||||
|
||||
/**
|
||||
* Whether CSS error reporting is enabled.
|
||||
*/
|
||||
attribute boolean cssErrorReportingEnabled;
|
||||
|
||||
/**
|
||||
* Whether to allow plugin execution
|
||||
*/
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
#include "TimelineConsumers.h"
|
||||
|
||||
#include "mozilla/ClearOnShutdown.h"
|
||||
#include "jsapi.h"
|
||||
#include "nsAppRunner.h" // for XRE_IsContentProcess, XRE_IsParentProcess
|
||||
#include "nsDocShell.h"
|
||||
|
||||
|
@ -126,6 +127,9 @@ TimelineConsumers::AddConsumer(nsDocShell* aDocShell)
|
|||
UniquePtr<ObservedDocShell>& observed = aDocShell->mObserved;
|
||||
MOZ_ASSERT(!observed);
|
||||
|
||||
if (mActiveConsumers == 0) {
|
||||
JS::SetProfileTimelineRecordingEnabled(true);
|
||||
}
|
||||
mActiveConsumers++;
|
||||
|
||||
ObservedDocShell* obsDocShell = new ObservedDocShell(aDocShell);
|
||||
|
@ -145,6 +149,9 @@ TimelineConsumers::RemoveConsumer(nsDocShell* aDocShell)
|
|||
MOZ_ASSERT(observed);
|
||||
|
||||
mActiveConsumers--;
|
||||
if (mActiveConsumers == 0) {
|
||||
JS::SetProfileTimelineRecordingEnabled(false);
|
||||
}
|
||||
|
||||
// Clear all markers from the `mTimelineMarkers` store.
|
||||
observed.get()->ClearMarkers();
|
||||
|
|
|
@ -17,7 +17,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=513194
|
|||
// The use of document.write is deliberate. We are testing for the
|
||||
// HTML parser to call the CSS parser once and only once when it
|
||||
// encounters a new <style> element.
|
||||
|
||||
SpecialPowers.wrap(document).docShell.cssErrorReportingEnabled = true;
|
||||
SimpleTest.runTestExpectingConsoleMessages(
|
||||
function () { document.write("<style>qux { foo : bar; }<\/style>") },
|
||||
[{ errorMessage: /Unknown property/ }]
|
||||
|
|
|
@ -125,48 +125,6 @@ private:
|
|||
ErrorResult& mRv;
|
||||
};
|
||||
|
||||
class BCPostMessageRunnable final : public nsIRunnable,
|
||||
public nsICancelableRunnable
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
|
||||
BCPostMessageRunnable(BroadcastChannelChild* aActor,
|
||||
BroadcastChannelMessage* aData)
|
||||
: mActor(aActor)
|
||||
, mData(aData)
|
||||
{
|
||||
MOZ_ASSERT(mActor);
|
||||
}
|
||||
|
||||
NS_IMETHOD Run() override
|
||||
{
|
||||
MOZ_ASSERT(mActor);
|
||||
if (mActor->IsActorDestroyed()) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
ClonedMessageData message;
|
||||
mData->BuildClonedMessageDataForBackgroundChild(mActor->Manager(), message);
|
||||
mActor->SendPostMessage(message);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult Cancel() override
|
||||
{
|
||||
mActor = nullptr;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
private:
|
||||
~BCPostMessageRunnable() {}
|
||||
|
||||
RefPtr<BroadcastChannelChild> mActor;
|
||||
RefPtr<BroadcastChannelMessage> mData;
|
||||
};
|
||||
|
||||
NS_IMPL_ISUPPORTS(BCPostMessageRunnable, nsICancelableRunnable, nsIRunnable)
|
||||
|
||||
class CloseRunnable final : public nsIRunnable,
|
||||
public nsICancelableRunnable
|
||||
{
|
||||
|
@ -398,14 +356,6 @@ BroadcastChannel::PostMessage(JSContext* aCx, JS::Handle<JS::Value> aMessage,
|
|||
return;
|
||||
}
|
||||
|
||||
PostMessageInternal(aCx, aMessage, aRv);
|
||||
}
|
||||
|
||||
void
|
||||
BroadcastChannel::PostMessageInternal(JSContext* aCx,
|
||||
JS::Handle<JS::Value> aMessage,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
RefPtr<BroadcastChannelMessage> data = new BroadcastChannelMessage();
|
||||
|
||||
data->Write(aCx, aMessage, aRv);
|
||||
|
@ -413,20 +363,11 @@ BroadcastChannel::PostMessageInternal(JSContext* aCx,
|
|||
return;
|
||||
}
|
||||
|
||||
PostMessageData(data);
|
||||
}
|
||||
|
||||
void
|
||||
BroadcastChannel::PostMessageData(BroadcastChannelMessage* aData)
|
||||
{
|
||||
RemoveDocFromBFCache();
|
||||
|
||||
RefPtr<BCPostMessageRunnable> runnable =
|
||||
new BCPostMessageRunnable(mActor, aData);
|
||||
|
||||
if (NS_FAILED(NS_DispatchToCurrentThread(runnable))) {
|
||||
NS_WARNING("Failed to dispatch to the current thread!");
|
||||
}
|
||||
ClonedMessageData message;
|
||||
data->BuildClonedMessageDataForBackgroundChild(mActor->Manager(), message);
|
||||
mActor->SendPostMessage(message);
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
@ -1,8 +1,7 @@
|
|||
(new BroadcastChannel('foobar')).postMessage('READY');
|
||||
|
||||
(new BroadcastChannel('foobar')).addEventListener('message', function(event) {
|
||||
if (event.data != 'READY') {
|
||||
event.target.postMessage(event.data);
|
||||
}
|
||||
});
|
||||
|
||||
(new BroadcastChannel('foobar')).postMessage('READY');
|
||||
|
|
|
@ -23,10 +23,10 @@ async function useBroadcastChannel(contentWindow) {
|
|||
count += 1;
|
||||
const name = `test_event_listener_leaks-${count}`;
|
||||
|
||||
let bc = new contentWindow.BroadcastChannel(name);
|
||||
let outer = new BroadcastChannel(name);
|
||||
outer.postMessage('foo');
|
||||
|
||||
let bc = new contentWindow.BroadcastChannel(name);
|
||||
await new Promise(resolve => {
|
||||
bc.onmessage = e => {
|
||||
contentWindow.messageCount += 1;
|
||||
|
|
|
@ -11,7 +11,8 @@
|
|||
*/
|
||||
[ChromeOnly]
|
||||
namespace InspectorUtils {
|
||||
sequence<StyleSheet> getAllStyleSheets(Document document);
|
||||
// documentOnly tells whether user and UA sheets should get included.
|
||||
sequence<StyleSheet> getAllStyleSheets(Document document, optional boolean documentOnly = false);
|
||||
sequence<CSSRule> getCSSStyleRules(
|
||||
Element element,
|
||||
[TreatNullAs=EmptyString] optional DOMString pseudo = "");
|
||||
|
|
|
@ -289,7 +289,7 @@ GMPChild::RecvPreloadLibs(const nsCString& aLibs)
|
|||
u"msmpeg2vdec.dll", // H.264 decoder
|
||||
u"psapi.dll", // For GetMappedFileNameW, see bug 1383611
|
||||
};
|
||||
constexpr static bool (*IsASCII)(const char16_t*) = NS_ConstExprIsAscii;
|
||||
constexpr static bool (*IsASCII)(const char16_t*) = NS_IsAscii;
|
||||
static_assert(AllOf(std::begin(whitelist), std::end(whitelist), IsASCII),
|
||||
"Items in the whitelist must not contain non-ASCII "
|
||||
"characters!");
|
||||
|
|
|
@ -33,7 +33,8 @@ struct ScrollbarData {
|
|||
CSSCoord aThumbLength,
|
||||
bool aThumbIsAsyncDraggable,
|
||||
CSSCoord aScrollTrackStart,
|
||||
CSSCoord aScrollTrackLength)
|
||||
CSSCoord aScrollTrackLength,
|
||||
uint64_t aTargetViewId)
|
||||
: mDirection(Some(aDirection))
|
||||
, mScrollbarLayerType(aScrollbarLayerType)
|
||||
, mThumbRatio(aThumbRatio)
|
||||
|
@ -42,6 +43,7 @@ struct ScrollbarData {
|
|||
, mThumbIsAsyncDraggable(aThumbIsAsyncDraggable)
|
||||
, mScrollTrackStart(aScrollTrackStart)
|
||||
, mScrollTrackLength(aScrollTrackLength)
|
||||
, mTargetViewId(aTargetViewId)
|
||||
{}
|
||||
|
||||
/**
|
||||
|
@ -158,20 +160,6 @@ public:
|
|||
return true;
|
||||
}
|
||||
|
||||
bool SetScrollbarContainer(FrameMetrics::ViewID aTargetViewId,
|
||||
ScrollDirection aDirection) {
|
||||
if (mScrollbarData.mScrollbarLayerType == ScrollbarLayerType::Container &&
|
||||
mScrollbarData.mDirection &&
|
||||
*mScrollbarData.mDirection == aDirection &&
|
||||
mScrollbarData.mTargetViewId == aTargetViewId) {
|
||||
return false;
|
||||
}
|
||||
mScrollbarData.mDirection = Some(aDirection);
|
||||
mScrollbarData.mTargetViewId = aTargetViewId;
|
||||
mScrollbarData.mScrollbarLayerType = ScrollbarLayerType::Container;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SetMixBlendMode(gfx::CompositionOp aMixBlendMode) {
|
||||
if (mMixBlendMode == aMixBlendMode) {
|
||||
return false;
|
||||
|
|
|
@ -1259,9 +1259,9 @@ public:
|
|||
|
||||
/**
|
||||
* CONSTRUCTION PHASE ONLY
|
||||
* If a layer is a scroll thumb container layer, set the scroll identifier
|
||||
* of the scroll frame scrolled by the thumb, and other data related to the
|
||||
* thumb.
|
||||
* If a layer is a scroll thumb container layer or a scrollbar container
|
||||
* layer, set the scroll identifier of the scroll frame scrolled by
|
||||
* the scrollbar, and other data related to the scrollbar.
|
||||
*/
|
||||
void SetScrollbarData(const ScrollbarData& aThumbData)
|
||||
{
|
||||
|
@ -1271,17 +1271,6 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
// Set during construction for the container layer of scrollbar components.
|
||||
// |aScrollId| holds the scroll identifier of the scrollable content that
|
||||
// the scrollbar is for.
|
||||
void SetScrollbarContainer(FrameMetrics::ViewID aScrollId,
|
||||
ScrollDirection aDirection)
|
||||
{
|
||||
if (mSimpleAttrs.SetScrollbarContainer(aScrollId, aDirection)) {
|
||||
MutatedSimple();
|
||||
}
|
||||
}
|
||||
|
||||
// Used when forwarding transactions. Do not use at any other time.
|
||||
void SetSimpleAttributes(const SimpleLayerAttributes& aAttrs) {
|
||||
mSimpleAttrs = aAttrs;
|
||||
|
|
|
@ -485,7 +485,7 @@ IProtocol::AllocShmem(size_t aSize,
|
|||
return false;
|
||||
}
|
||||
|
||||
*aOutMem = Shmem(Shmem::IHadBetterBeIPDLCodeCallingThis_OtherwiseIAmADoodyhead(), rawmem, id);
|
||||
*aOutMem = Shmem(Shmem::PrivateIPDLCaller(), rawmem, id);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -500,7 +500,7 @@ IProtocol::AllocUnsafeShmem(size_t aSize,
|
|||
return false;
|
||||
}
|
||||
|
||||
*aOutMem = Shmem(Shmem::IHadBetterBeIPDLCodeCallingThis_OtherwiseIAmADoodyhead(), rawmem, id);
|
||||
*aOutMem = Shmem(Shmem::PrivateIPDLCaller(), rawmem, id);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -518,7 +518,7 @@ IProtocol::DeallocShmem(Shmem& aMem)
|
|||
return false;
|
||||
}
|
||||
#endif // DEBUG
|
||||
aMem.forget(Shmem::IHadBetterBeIPDLCodeCallingThis_OtherwiseIAmADoodyhead());
|
||||
aMem.forget(Shmem::PrivateIPDLCaller());
|
||||
return ok;
|
||||
}
|
||||
|
||||
|
@ -747,13 +747,13 @@ IToplevelProtocol::CreateSharedMemory(size_t aSize,
|
|||
Shmem::id_t* aId)
|
||||
{
|
||||
RefPtr<Shmem::SharedMemory> segment(
|
||||
Shmem::Alloc(Shmem::IHadBetterBeIPDLCodeCallingThis_OtherwiseIAmADoodyhead(), aSize, aType, aUnsafe));
|
||||
Shmem::Alloc(Shmem::PrivateIPDLCaller(), aSize, aType, aUnsafe));
|
||||
if (!segment) {
|
||||
return nullptr;
|
||||
}
|
||||
int32_t id = GetSide() == ParentSide ? ++mLastShmemId : --mLastShmemId;
|
||||
Shmem shmem(
|
||||
Shmem::IHadBetterBeIPDLCodeCallingThis_OtherwiseIAmADoodyhead(),
|
||||
Shmem::PrivateIPDLCaller(),
|
||||
segment.get(),
|
||||
id);
|
||||
|
||||
|
@ -768,13 +768,13 @@ IToplevelProtocol::CreateSharedMemory(size_t aSize,
|
|||
#endif
|
||||
|
||||
Message* descriptor = shmem.ShareTo(
|
||||
Shmem::IHadBetterBeIPDLCodeCallingThis_OtherwiseIAmADoodyhead(), pid, MSG_ROUTING_CONTROL);
|
||||
Shmem::PrivateIPDLCaller(), pid, MSG_ROUTING_CONTROL);
|
||||
if (!descriptor) {
|
||||
return nullptr;
|
||||
}
|
||||
Unused << GetIPCChannel()->Send(descriptor);
|
||||
|
||||
*aId = shmem.Id(Shmem::IHadBetterBeIPDLCodeCallingThis_OtherwiseIAmADoodyhead());
|
||||
*aId = shmem.Id(Shmem::PrivateIPDLCaller());
|
||||
Shmem::SharedMemory* rawSegment = segment.get();
|
||||
mShmemMap.AddWithID(segment.forget().take(), *aId);
|
||||
return rawSegment;
|
||||
|
@ -795,17 +795,17 @@ IToplevelProtocol::IsTrackingSharedMemory(Shmem::SharedMemory* segment)
|
|||
bool
|
||||
IToplevelProtocol::DestroySharedMemory(Shmem& shmem)
|
||||
{
|
||||
Shmem::id_t aId = shmem.Id(Shmem::IHadBetterBeIPDLCodeCallingThis_OtherwiseIAmADoodyhead());
|
||||
Shmem::id_t aId = shmem.Id(Shmem::PrivateIPDLCaller());
|
||||
Shmem::SharedMemory* segment = LookupSharedMemory(aId);
|
||||
if (!segment) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Message* descriptor = shmem.UnshareFrom(
|
||||
Shmem::IHadBetterBeIPDLCodeCallingThis_OtherwiseIAmADoodyhead(), MSG_ROUTING_CONTROL);
|
||||
Shmem::PrivateIPDLCaller(), MSG_ROUTING_CONTROL);
|
||||
|
||||
mShmemMap.Remove(aId);
|
||||
Shmem::Dealloc(Shmem::IHadBetterBeIPDLCodeCallingThis_OtherwiseIAmADoodyhead(), segment);
|
||||
Shmem::Dealloc(Shmem::PrivateIPDLCaller(), segment);
|
||||
|
||||
if (!GetIPCChannel()->CanSend()) {
|
||||
delete descriptor;
|
||||
|
@ -819,7 +819,7 @@ void
|
|||
IToplevelProtocol::DeallocShmems()
|
||||
{
|
||||
for (IDMap<SharedMemory*>::const_iterator cit = mShmemMap.begin(); cit != mShmemMap.end(); ++cit) {
|
||||
Shmem::Dealloc(Shmem::IHadBetterBeIPDLCodeCallingThis_OtherwiseIAmADoodyhead(), cit->second);
|
||||
Shmem::Dealloc(Shmem::PrivateIPDLCaller(), cit->second);
|
||||
}
|
||||
mShmemMap.Clear();
|
||||
}
|
||||
|
@ -828,7 +828,7 @@ bool
|
|||
IToplevelProtocol::ShmemCreated(const Message& aMsg)
|
||||
{
|
||||
Shmem::id_t id;
|
||||
RefPtr<Shmem::SharedMemory> rawmem(Shmem::OpenExisting(Shmem::IHadBetterBeIPDLCodeCallingThis_OtherwiseIAmADoodyhead(), aMsg, &id, true));
|
||||
RefPtr<Shmem::SharedMemory> rawmem(Shmem::OpenExisting(Shmem::PrivateIPDLCaller(), aMsg, &id, true));
|
||||
if (!rawmem) {
|
||||
return false;
|
||||
}
|
||||
|
@ -849,7 +849,7 @@ IToplevelProtocol::ShmemDestroyed(const Message& aMsg)
|
|||
Shmem::SharedMemory* rawmem = LookupSharedMemory(id);
|
||||
if (rawmem) {
|
||||
mShmemMap.Remove(id);
|
||||
Shmem::Dealloc(Shmem::IHadBetterBeIPDLCodeCallingThis_OtherwiseIAmADoodyhead(), rawmem);
|
||||
Shmem::Dealloc(Shmem::PrivateIPDLCaller(), rawmem);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -247,7 +247,7 @@ Unprotect(SharedMemory* aSegment)
|
|||
// to touch the segment, it dies with SIGSEGV.
|
||||
//
|
||||
|
||||
Shmem::Shmem(IHadBetterBeIPDLCodeCallingThis_OtherwiseIAmADoodyhead,
|
||||
Shmem::Shmem(PrivateIPDLCaller,
|
||||
SharedMemory* aSegment, id_t aId) :
|
||||
mSegment(aSegment),
|
||||
mData(nullptr),
|
||||
|
@ -300,7 +300,7 @@ Shmem::AssertInvariants() const
|
|||
}
|
||||
|
||||
void
|
||||
Shmem::RevokeRights(IHadBetterBeIPDLCodeCallingThis_OtherwiseIAmADoodyhead)
|
||||
Shmem::RevokeRights(PrivateIPDLCaller)
|
||||
{
|
||||
AssertInvariants();
|
||||
|
||||
|
@ -319,7 +319,7 @@ Shmem::RevokeRights(IHadBetterBeIPDLCodeCallingThis_OtherwiseIAmADoodyhead)
|
|||
|
||||
// static
|
||||
already_AddRefed<Shmem::SharedMemory>
|
||||
Shmem::Alloc(IHadBetterBeIPDLCodeCallingThis_OtherwiseIAmADoodyhead,
|
||||
Shmem::Alloc(PrivateIPDLCaller,
|
||||
size_t aNBytes,
|
||||
SharedMemoryType aType,
|
||||
bool aUnsafe,
|
||||
|
@ -360,7 +360,7 @@ Shmem::Alloc(IHadBetterBeIPDLCodeCallingThis_OtherwiseIAmADoodyhead,
|
|||
|
||||
// static
|
||||
already_AddRefed<Shmem::SharedMemory>
|
||||
Shmem::OpenExisting(IHadBetterBeIPDLCodeCallingThis_OtherwiseIAmADoodyhead,
|
||||
Shmem::OpenExisting(PrivateIPDLCaller,
|
||||
const IPC::Message& aDescriptor,
|
||||
id_t* aId,
|
||||
bool aProtect)
|
||||
|
@ -396,7 +396,7 @@ Shmem::OpenExisting(IHadBetterBeIPDLCodeCallingThis_OtherwiseIAmADoodyhead,
|
|||
|
||||
// static
|
||||
void
|
||||
Shmem::Dealloc(IHadBetterBeIPDLCodeCallingThis_OtherwiseIAmADoodyhead,
|
||||
Shmem::Dealloc(PrivateIPDLCaller,
|
||||
SharedMemory* aSegment)
|
||||
{
|
||||
if (!aSegment)
|
||||
|
@ -422,7 +422,7 @@ Shmem::Dealloc(IHadBetterBeIPDLCodeCallingThis_OtherwiseIAmADoodyhead,
|
|||
|
||||
// static
|
||||
already_AddRefed<Shmem::SharedMemory>
|
||||
Shmem::Alloc(IHadBetterBeIPDLCodeCallingThis_OtherwiseIAmADoodyhead,
|
||||
Shmem::Alloc(PrivateIPDLCaller,
|
||||
size_t aNBytes,
|
||||
SharedMemoryType aType,
|
||||
bool /*unused*/,
|
||||
|
@ -440,7 +440,7 @@ Shmem::Alloc(IHadBetterBeIPDLCodeCallingThis_OtherwiseIAmADoodyhead,
|
|||
|
||||
// static
|
||||
already_AddRefed<Shmem::SharedMemory>
|
||||
Shmem::OpenExisting(IHadBetterBeIPDLCodeCallingThis_OtherwiseIAmADoodyhead,
|
||||
Shmem::OpenExisting(PrivateIPDLCaller,
|
||||
const IPC::Message& aDescriptor,
|
||||
id_t* aId,
|
||||
bool /*unused*/)
|
||||
|
@ -461,7 +461,7 @@ Shmem::OpenExisting(IHadBetterBeIPDLCodeCallingThis_OtherwiseIAmADoodyhead,
|
|||
|
||||
// static
|
||||
void
|
||||
Shmem::Dealloc(IHadBetterBeIPDLCodeCallingThis_OtherwiseIAmADoodyhead,
|
||||
Shmem::Dealloc(PrivateIPDLCaller,
|
||||
SharedMemory* aSegment)
|
||||
{
|
||||
DestroySegment(aSegment);
|
||||
|
@ -470,7 +470,7 @@ Shmem::Dealloc(IHadBetterBeIPDLCodeCallingThis_OtherwiseIAmADoodyhead,
|
|||
#endif // if defined(DEBUG)
|
||||
|
||||
IPC::Message*
|
||||
Shmem::ShareTo(IHadBetterBeIPDLCodeCallingThis_OtherwiseIAmADoodyhead,
|
||||
Shmem::ShareTo(PrivateIPDLCaller,
|
||||
base::ProcessId aTargetPid,
|
||||
int32_t routingId)
|
||||
{
|
||||
|
@ -486,7 +486,7 @@ Shmem::ShareTo(IHadBetterBeIPDLCodeCallingThis_OtherwiseIAmADoodyhead,
|
|||
}
|
||||
|
||||
IPC::Message*
|
||||
Shmem::UnshareFrom(IHadBetterBeIPDLCodeCallingThis_OtherwiseIAmADoodyhead,
|
||||
Shmem::UnshareFrom(PrivateIPDLCaller,
|
||||
int32_t routingId)
|
||||
{
|
||||
AssertInvariants();
|
||||
|
@ -500,9 +500,9 @@ IPDLParamTraits<Shmem>::Write(IPC::Message* aMsg, IProtocol* aActor,
|
|||
WriteIPDLParam(aMsg, aActor, aParam.mId);
|
||||
|
||||
aParam.RevokeRights(
|
||||
Shmem::IHadBetterBeIPDLCodeCallingThis_OtherwiseIAmADoodyhead());
|
||||
Shmem::PrivateIPDLCaller());
|
||||
aParam.forget(
|
||||
Shmem::IHadBetterBeIPDLCodeCallingThis_OtherwiseIAmADoodyhead());
|
||||
Shmem::PrivateIPDLCaller());
|
||||
}
|
||||
|
||||
bool
|
||||
|
@ -517,7 +517,7 @@ IPDLParamTraits<Shmem>::Read(const IPC::Message* aMsg, PickleIterator* aIter,
|
|||
Shmem::SharedMemory* rawmem = aActor->LookupSharedMemory(id);
|
||||
if (rawmem) {
|
||||
*aResult = Shmem(
|
||||
Shmem::IHadBetterBeIPDLCodeCallingThis_OtherwiseIAmADoodyhead(),
|
||||
Shmem::PrivateIPDLCaller(),
|
||||
rawmem, id);
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -73,7 +73,11 @@ public:
|
|||
// Low-level wrapper around platform shmem primitives.
|
||||
typedef mozilla::ipc::SharedMemory SharedMemory;
|
||||
typedef SharedMemory::SharedMemoryType SharedMemoryType;
|
||||
struct IHadBetterBeIPDLCodeCallingThis_OtherwiseIAmADoodyhead {};
|
||||
// Shmem objects should only be constructed directly from SharedMemory
|
||||
// objects by the Shmem implementation itself, or by a select few functions
|
||||
// in ProtocolUtils.{h,cpp}. You should not need to add new instances of
|
||||
// this token.
|
||||
struct PrivateIPDLCaller {};
|
||||
|
||||
Shmem() :
|
||||
mSegment(nullptr),
|
||||
|
@ -92,7 +96,7 @@ public:
|
|||
}
|
||||
|
||||
#if !defined(DEBUG)
|
||||
Shmem(IHadBetterBeIPDLCodeCallingThis_OtherwiseIAmADoodyhead,
|
||||
Shmem(PrivateIPDLCaller,
|
||||
SharedMemory* aSegment, id_t aId) :
|
||||
mSegment(aSegment),
|
||||
mData(aSegment->memory()),
|
||||
|
@ -102,7 +106,7 @@ public:
|
|||
mSize = static_cast<size_t>(*PtrToSize(mSegment));
|
||||
}
|
||||
#else
|
||||
Shmem(IHadBetterBeIPDLCodeCallingThis_OtherwiseIAmADoodyhead,
|
||||
Shmem(PrivateIPDLCaller,
|
||||
SharedMemory* aSegment, id_t aId);
|
||||
#endif
|
||||
|
||||
|
@ -110,7 +114,7 @@ public:
|
|||
{
|
||||
// Shmem only holds a "weak ref" to the actual segment, which is
|
||||
// owned by IPDL. So there's nothing interesting to be done here
|
||||
forget(IHadBetterBeIPDLCodeCallingThis_OtherwiseIAmADoodyhead());
|
||||
forget(PrivateIPDLCaller());
|
||||
}
|
||||
|
||||
Shmem& operator=(const Shmem& aRhs)
|
||||
|
@ -169,23 +173,23 @@ public:
|
|||
}
|
||||
|
||||
// These shouldn't be used directly, use the IPDL interface instead.
|
||||
id_t Id(IHadBetterBeIPDLCodeCallingThis_OtherwiseIAmADoodyhead) const {
|
||||
id_t Id(PrivateIPDLCaller) const {
|
||||
return mId;
|
||||
}
|
||||
|
||||
SharedMemory* Segment(IHadBetterBeIPDLCodeCallingThis_OtherwiseIAmADoodyhead) const {
|
||||
SharedMemory* Segment(PrivateIPDLCaller) const {
|
||||
return mSegment;
|
||||
}
|
||||
|
||||
#ifndef DEBUG
|
||||
void RevokeRights(IHadBetterBeIPDLCodeCallingThis_OtherwiseIAmADoodyhead)
|
||||
void RevokeRights(PrivateIPDLCaller)
|
||||
{
|
||||
}
|
||||
#else
|
||||
void RevokeRights(IHadBetterBeIPDLCodeCallingThis_OtherwiseIAmADoodyhead);
|
||||
void RevokeRights(PrivateIPDLCaller);
|
||||
#endif
|
||||
|
||||
void forget(IHadBetterBeIPDLCodeCallingThis_OtherwiseIAmADoodyhead)
|
||||
void forget(PrivateIPDLCaller)
|
||||
{
|
||||
mSegment = nullptr;
|
||||
mData = nullptr;
|
||||
|
@ -194,7 +198,7 @@ public:
|
|||
}
|
||||
|
||||
static already_AddRefed<Shmem::SharedMemory>
|
||||
Alloc(IHadBetterBeIPDLCodeCallingThis_OtherwiseIAmADoodyhead,
|
||||
Alloc(PrivateIPDLCaller,
|
||||
size_t aNBytes,
|
||||
SharedMemoryType aType,
|
||||
bool aUnsafe,
|
||||
|
@ -205,7 +209,7 @@ public:
|
|||
// this segment in OpenExisting() below. Return a new message if
|
||||
// successful (owned by the caller), nullptr if not.
|
||||
IPC::Message*
|
||||
ShareTo(IHadBetterBeIPDLCodeCallingThis_OtherwiseIAmADoodyhead,
|
||||
ShareTo(PrivateIPDLCaller,
|
||||
base::ProcessId aTargetPid,
|
||||
int32_t routingId);
|
||||
|
||||
|
@ -214,7 +218,7 @@ public:
|
|||
// segment. Return a new message if successful (owned by the
|
||||
// caller), nullptr if not.
|
||||
IPC::Message*
|
||||
UnshareFrom(IHadBetterBeIPDLCodeCallingThis_OtherwiseIAmADoodyhead,
|
||||
UnshareFrom(PrivateIPDLCaller,
|
||||
int32_t routingId);
|
||||
|
||||
// Return a SharedMemory instance in this process using the
|
||||
|
@ -222,13 +226,13 @@ public:
|
|||
// underlying OS shmem resource. The contents of the descriptor
|
||||
// depend on the type of SharedMemory that was passed to us.
|
||||
static already_AddRefed<SharedMemory>
|
||||
OpenExisting(IHadBetterBeIPDLCodeCallingThis_OtherwiseIAmADoodyhead,
|
||||
OpenExisting(PrivateIPDLCaller,
|
||||
const IPC::Message& aDescriptor,
|
||||
id_t* aId,
|
||||
bool aProtect=false);
|
||||
|
||||
static void
|
||||
Dealloc(IHadBetterBeIPDLCodeCallingThis_OtherwiseIAmADoodyhead,
|
||||
Dealloc(PrivateIPDLCaller,
|
||||
SharedMemory* aSegment);
|
||||
|
||||
private:
|
||||
|
|
|
@ -189,7 +189,7 @@ impl Runtime {
|
|||
});
|
||||
|
||||
if use_internal_job_queue {
|
||||
assert!(js::UseInternalJobQueues(js_context, false));
|
||||
assert!(js::UseInternalJobQueues(js_context));
|
||||
}
|
||||
|
||||
JS::InitSelfHostedCode(js_context);
|
||||
|
|
|
@ -139,7 +139,7 @@ public:
|
|||
static mozilla::Atomic<js::Mutex*> lock_;
|
||||
|
||||
// A flag that controls whether waiting is allowed.
|
||||
ThreadLocalData<bool> canWait_;
|
||||
ThreadData<bool> canWait_;
|
||||
};
|
||||
|
||||
JSObject*
|
||||
|
|
|
@ -2344,8 +2344,8 @@ js::PromiseResolve(JSContext* cx, HandleObject constructor, HandleValue value)
|
|||
/**
|
||||
* ES2016, 25.4.4.4, Promise.reject.
|
||||
*/
|
||||
bool
|
||||
js::Promise_reject(JSContext* cx, unsigned argc, Value* vp)
|
||||
static bool
|
||||
Promise_reject(JSContext* cx, unsigned argc, Value* vp)
|
||||
{
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
RootedValue thisVal(cx, args.thisv());
|
||||
|
@ -2373,8 +2373,8 @@ PromiseObject::unforgeableReject(JSContext* cx, HandleValue value)
|
|||
/**
|
||||
* ES2016, 25.4.4.5, Promise.resolve.
|
||||
*/
|
||||
bool
|
||||
js::Promise_static_resolve(JSContext* cx, unsigned argc, Value* vp)
|
||||
static bool
|
||||
Promise_static_resolve(JSContext* cx, unsigned argc, Value* vp)
|
||||
{
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
RootedValue thisVal(cx, args.thisv());
|
||||
|
@ -2461,7 +2461,7 @@ IsPromiseSpecies(JSContext* cx, JSFunction* species)
|
|||
MOZ_MUST_USE bool
|
||||
js::OriginalPromiseThen(JSContext* cx, Handle<PromiseObject*> promise,
|
||||
HandleValue onFulfilled, HandleValue onRejected,
|
||||
MutableHandleObject dependent, bool createDependent)
|
||||
MutableHandleObject dependent, CreateDependentPromise createDependent)
|
||||
{
|
||||
RootedObject promiseObj(cx, promise);
|
||||
if (promise->compartment() != cx->compartment()) {
|
||||
|
@ -2473,15 +2473,19 @@ js::OriginalPromiseThen(JSContext* cx, Handle<PromiseObject*> promise,
|
|||
RootedObject resolve(cx);
|
||||
RootedObject reject(cx);
|
||||
|
||||
if (createDependent) {
|
||||
if (createDependent != CreateDependentPromise::Never) {
|
||||
// Step 3.
|
||||
RootedObject C(cx, SpeciesConstructor(cx, promiseObj, JSProto_Promise, IsPromiseSpecies));
|
||||
if (!C)
|
||||
return false;
|
||||
|
||||
// Step 4.
|
||||
if (!NewPromiseCapability(cx, C, &resultPromise, &resolve, &reject, true))
|
||||
return false;
|
||||
if (createDependent == CreateDependentPromise::Always ||
|
||||
!IsNativeFunction(C, PromiseConstructor))
|
||||
{
|
||||
// Step 4.
|
||||
if (!NewPromiseCapability(cx, C, &resultPromise, &resolve, &reject, true))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Step 5.
|
||||
|
@ -3024,18 +3028,79 @@ js::AsyncGeneratorEnqueue(JSContext* cx, HandleValue asyncGenVal,
|
|||
return true;
|
||||
}
|
||||
|
||||
// ES2016, 25.4.5.3.
|
||||
bool
|
||||
js::Promise_then(JSContext* cx, unsigned argc, Value* vp)
|
||||
static bool Promise_then(JSContext* cx, unsigned argc, Value* vp);
|
||||
static bool Promise_then_impl(JSContext* cx, HandleValue promiseVal, HandleValue onFulfilled,
|
||||
HandleValue onRejected, MutableHandleValue rval, bool rvalUsed);
|
||||
|
||||
static bool
|
||||
Promise_catch_impl(JSContext* cx, unsigned argc, Value* vp, bool rvalUsed)
|
||||
{
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
|
||||
// Step 1.
|
||||
RootedValue promiseVal(cx, args.thisv());
|
||||
RootedValue thenVal(cx);
|
||||
if (!GetProperty(cx, args.thisv(), cx->names().then, &thenVal))
|
||||
return false;
|
||||
|
||||
RootedValue onFulfilled(cx, args.get(0));
|
||||
RootedValue onRejected(cx, args.get(1));
|
||||
if (IsNativeFunction(thenVal, &Promise_then)) {
|
||||
return Promise_then_impl(cx, args.thisv(), UndefinedHandleValue, args.get(0),
|
||||
args.rval(), rvalUsed);
|
||||
}
|
||||
|
||||
FixedInvokeArgs<2> iargs(cx);
|
||||
iargs[0].setUndefined();
|
||||
iargs[1].set(args.get(0));
|
||||
|
||||
return Call(cx, thenVal, args.thisv(), iargs, args.rval());
|
||||
}
|
||||
|
||||
static MOZ_ALWAYS_INLINE bool
|
||||
IsPromiseThenOrCatchRetValImplicitlyUsed(JSContext* cx)
|
||||
{
|
||||
// The returned promise of Promise#then and Promise#catch contains
|
||||
// stack info if async stack is enabled. Even if their return value is not
|
||||
// used explicitly in the script, the stack info is observable in devtools
|
||||
// and profilers. We shouldn't apply the optimization not to allocate the
|
||||
// returned Promise object if the it's implicitly used by them.
|
||||
//
|
||||
// FIXME: Once bug 1280819 gets fixed, we can use ShouldCaptureDebugInfo.
|
||||
if (!cx->options().asyncStack())
|
||||
return false;
|
||||
|
||||
// If devtools is opened, the current compartment will become debuggee.
|
||||
if (cx->compartment()->isDebuggee())
|
||||
return true;
|
||||
|
||||
// There are 2 profilers, and they can be independently enabled.
|
||||
if (cx->runtime()->geckoProfiler().enabled())
|
||||
return true;
|
||||
if (JS::IsProfileTimelineRecordingEnabled())
|
||||
return true;
|
||||
|
||||
// The stack is also observable from Error#stack, but we don't care since
|
||||
// it's nonstandard feature.
|
||||
return false;
|
||||
}
|
||||
|
||||
// ES2016, 25.4.5.3.
|
||||
static bool
|
||||
Promise_catch_noRetVal(JSContext* cx, unsigned argc, Value* vp)
|
||||
{
|
||||
return Promise_catch_impl(cx, argc, vp, IsPromiseThenOrCatchRetValImplicitlyUsed(cx));
|
||||
}
|
||||
|
||||
// ES2016, 25.4.5.3.
|
||||
static bool
|
||||
Promise_catch(JSContext* cx, unsigned argc, Value* vp)
|
||||
{
|
||||
return Promise_catch_impl(cx, argc, vp, true);
|
||||
}
|
||||
|
||||
static bool
|
||||
Promise_then_impl(JSContext* cx, HandleValue promiseVal, HandleValue onFulfilled,
|
||||
HandleValue onRejected, MutableHandleValue rval, bool rvalUsed)
|
||||
{
|
||||
// Step 1 (implicit).
|
||||
// Step 2.
|
||||
if (!promiseVal.isObject()) {
|
||||
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_NOT_NONNULL_OBJECT,
|
||||
|
@ -3063,14 +3128,40 @@ js::Promise_then(JSContext* cx, unsigned argc, Value* vp)
|
|||
}
|
||||
|
||||
// Steps 3-5.
|
||||
CreateDependentPromise createDependent = rvalUsed
|
||||
? CreateDependentPromise::Always
|
||||
: CreateDependentPromise::SkipIfCtorUnobservable;
|
||||
RootedObject resultPromise(cx);
|
||||
if (!OriginalPromiseThen(cx, promise, onFulfilled, onRejected, &resultPromise, true))
|
||||
if (!OriginalPromiseThen(cx, promise, onFulfilled, onRejected, &resultPromise,
|
||||
createDependent))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
args.rval().setObject(*resultPromise);
|
||||
if (rvalUsed)
|
||||
rval.setObject(*resultPromise);
|
||||
else
|
||||
rval.setUndefined();
|
||||
return true;
|
||||
}
|
||||
|
||||
// ES2016, 25.4.5.3.
|
||||
bool
|
||||
Promise_then_noRetVal(JSContext* cx, unsigned argc, Value* vp)
|
||||
{
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
return Promise_then_impl(cx, args.thisv(), args.get(0), args.get(1), args.rval(),
|
||||
IsPromiseThenOrCatchRetValImplicitlyUsed(cx));
|
||||
}
|
||||
|
||||
// ES2016, 25.4.5.3.
|
||||
static bool
|
||||
Promise_then(JSContext* cx, unsigned argc, Value* vp)
|
||||
{
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
return Promise_then_impl(cx, args.thisv(), args.get(0), args.get(1), args.rval(), true);
|
||||
}
|
||||
|
||||
// ES2016, 25.4.5.3.1.
|
||||
static MOZ_MUST_USE bool
|
||||
PerformPromiseThen(JSContext* cx, Handle<PromiseObject*> promise, HandleValue onFulfilled_,
|
||||
|
@ -3737,9 +3828,27 @@ CreatePromisePrototype(JSContext* cx, JSProtoKey key)
|
|||
return GlobalObject::createBlankPrototype(cx, cx->global(), &PromiseObject::protoClass_);
|
||||
}
|
||||
|
||||
const JSJitInfo promise_then_info = {
|
||||
{ (JSJitGetterOp)Promise_then_noRetVal },
|
||||
{ 0 }, /* unused */
|
||||
{ 0 }, /* unused */
|
||||
JSJitInfo::IgnoresReturnValueNative,
|
||||
JSJitInfo::AliasEverything,
|
||||
JSVAL_TYPE_UNDEFINED,
|
||||
};
|
||||
|
||||
const JSJitInfo promise_catch_info = {
|
||||
{ (JSJitGetterOp)Promise_catch_noRetVal },
|
||||
{ 0 }, /* unused */
|
||||
{ 0 }, /* unused */
|
||||
JSJitInfo::IgnoresReturnValueNative,
|
||||
JSJitInfo::AliasEverything,
|
||||
JSVAL_TYPE_UNDEFINED,
|
||||
};
|
||||
|
||||
static const JSFunctionSpec promise_methods[] = {
|
||||
JS_SELF_HOSTED_FN("catch", "Promise_catch", 1, 0),
|
||||
JS_FN("then", Promise_then, 2, 0),
|
||||
JS_FNINFO("then", Promise_then, &promise_then_info, 2, 0),
|
||||
JS_FNINFO("catch", Promise_catch, &promise_catch_info, 1, 0),
|
||||
JS_SELF_HOSTED_FN("finally", "Promise_finally", 1, 0),
|
||||
JS_FS_END
|
||||
};
|
||||
|
|
|
@ -103,6 +103,12 @@ class PromiseObject : public NativeObject
|
|||
MOZ_MUST_USE JSObject*
|
||||
GetWaitForAllPromise(JSContext* cx, const JS::AutoObjectVector& promises);
|
||||
|
||||
enum class CreateDependentPromise {
|
||||
Always,
|
||||
SkipIfCtorUnobservable,
|
||||
Never
|
||||
};
|
||||
|
||||
/**
|
||||
* Enqueues resolve/reject reactions in the given Promise's reactions lists
|
||||
* as though calling the original value of Promise.prototype.then.
|
||||
|
@ -116,7 +122,7 @@ GetWaitForAllPromise(JSContext* cx, const JS::AutoObjectVector& promises);
|
|||
MOZ_MUST_USE bool
|
||||
OriginalPromiseThen(JSContext* cx, Handle<PromiseObject*> promise,
|
||||
HandleValue onFulfilled, HandleValue onRejected,
|
||||
MutableHandleObject dependent, bool createDependent);
|
||||
MutableHandleObject dependent, CreateDependentPromise createDependent);
|
||||
|
||||
/**
|
||||
* PromiseResolve ( C, x )
|
||||
|
@ -253,13 +259,6 @@ class OffThreadPromiseRuntimeState
|
|||
void shutdown(JSContext* cx);
|
||||
};
|
||||
|
||||
bool
|
||||
Promise_static_resolve(JSContext* cx, unsigned argc, Value* vp);
|
||||
bool
|
||||
Promise_reject(JSContext* cx, unsigned argc, Value* vp);
|
||||
bool
|
||||
Promise_then(JSContext* cx, unsigned argc, Value* vp);
|
||||
|
||||
} // namespace js
|
||||
|
||||
#endif /* builtin_Promise_h */
|
||||
|
|
|
@ -3632,7 +3632,7 @@ ReadableStreamBYOBRequest::constructor(JSContext* cx, unsigned argc, Value* vp)
|
|||
return false;
|
||||
}
|
||||
|
||||
RootedArrayBufferObject view(cx, &viewVal.toObject().as<ArrayBufferObject>());
|
||||
Rooted<ArrayBufferViewObject*> view(cx, &viewVal.toObject().as<ArrayBufferViewObject>());
|
||||
|
||||
RootedObject request(cx, CreateReadableStreamBYOBRequest(cx, controller, view));
|
||||
if (!request)
|
||||
|
|
|
@ -636,7 +636,7 @@ frontend::CompileLazyFunction(JSContext* cx, Handle<LazyScript*> lazy, const cha
|
|||
options.setMutedErrors(lazy->mutedErrors())
|
||||
.setFileAndLine(lazy->filename(), lazy->lineno())
|
||||
.setColumn(lazy->column())
|
||||
.setScriptSourceOffset(lazy->begin())
|
||||
.setScriptSourceOffset(lazy->sourceStart())
|
||||
.setNoScriptRval(false)
|
||||
.setSelfHostingMode(false);
|
||||
|
||||
|
@ -678,7 +678,7 @@ frontend::CompileLazyFunction(JSContext* cx, Handle<LazyScript*> lazy, const cha
|
|||
MOZ_ASSERT(sourceObject);
|
||||
|
||||
Rooted<JSScript*> script(cx, JSScript::Create(cx, options, sourceObject,
|
||||
lazy->begin(), lazy->end(),
|
||||
lazy->sourceStart(), lazy->sourceEnd(),
|
||||
lazy->toStringStart(), lazy->toStringEnd()));
|
||||
if (!script)
|
||||
return false;
|
||||
|
|
|
@ -3256,7 +3256,7 @@ Parser<FullParseHandler, CharT>::skipLazyInnerFunction(ParseNode* funcNode, uint
|
|||
|
||||
PropagateTransitiveParseFlags(lazy, pc->sc());
|
||||
|
||||
if (!tokenStream.advance(fun->lazyScript()->end()))
|
||||
if (!tokenStream.advance(fun->lazyScript()->sourceEnd()))
|
||||
return false;
|
||||
|
||||
// Append possible Annex B function box only upon successfully parsing.
|
||||
|
|
|
@ -252,7 +252,7 @@ impl GlobalRules {
|
|||
let mut rules = self.per_node.get(name)
|
||||
.cloned()
|
||||
.unwrap_or_default();
|
||||
if let Some(ref parent) = rule.inherits {
|
||||
if let Some(ref parent) = rules.inherits {
|
||||
let NodeRules {
|
||||
inherits: _,
|
||||
type_ok,
|
||||
|
|
|
@ -251,7 +251,7 @@ class ArenaLists
|
|||
const BackgroundFinalizeState& backgroundFinalizeState(AllocKind i) const { return backgroundFinalizeState_.ref()[i]; }
|
||||
|
||||
/* For each arena kind, a list of arenas remaining to be swept. */
|
||||
ActiveThreadOrGCTaskData<AllAllocKindArray<Arena*>> arenaListsToSweep_;
|
||||
MainThreadOrGCTaskData<AllAllocKindArray<Arena*>> arenaListsToSweep_;
|
||||
Arena*& arenaListsToSweep(AllocKind i) { return arenaListsToSweep_.ref()[i]; }
|
||||
Arena* arenaListsToSweep(AllocKind i) const { return arenaListsToSweep_.ref()[i]; }
|
||||
|
||||
|
|
360
js/src/gc/GC.cpp
360
js/src/gc/GC.cpp
|
@ -192,6 +192,7 @@
|
|||
#include "mozilla/MacroForEach.h"
|
||||
#include "mozilla/MemoryReporting.h"
|
||||
#include "mozilla/Move.h"
|
||||
#include "mozilla/Range.h"
|
||||
#include "mozilla/ScopeExit.h"
|
||||
#include "mozilla/TimeStamp.h"
|
||||
#include "mozilla/TypeTraits.h"
|
||||
|
@ -1019,30 +1020,49 @@ const char* gc::ZealModeHelpText =
|
|||
" both modes 2 and 4. Modes can be specified by name or number.\n"
|
||||
" \n"
|
||||
" Values:\n"
|
||||
" 0: (None) Normal amount of collection (resets all modes)\n"
|
||||
" 1: (RootsChange) Collect when roots are added or removed\n"
|
||||
" 2: (Alloc) Collect when every N allocations (default: 100)\n"
|
||||
" 4: (VerifierPre) Verify pre write barriers between instructions\n"
|
||||
" 7: (GenerationalGC) Collect the nursery every N nursery allocations\n"
|
||||
" 8: (IncrementalRootsThenFinish) Incremental GC in two slices: 1) mark roots 2) finish collection\n"
|
||||
" 9: (IncrementalMarkAllThenFinish) Incremental GC in two slices: 1) mark all 2) new marking and finish\n"
|
||||
" 10: (IncrementalMultipleSlices) Incremental GC in multiple slices\n"
|
||||
" 11: (IncrementalMarkingValidator) Verify incremental marking\n"
|
||||
" 12: (ElementsBarrier) Always use the individual element post-write barrier, regardless of elements size\n"
|
||||
" 13: (CheckHashTablesOnMinorGC) Check internal hashtables on minor GC\n"
|
||||
" 14: (Compact) Perform a shrinking collection every N allocations\n"
|
||||
" 15: (CheckHeapAfterGC) Walk the heap to check its integrity after every GC\n"
|
||||
" 16: (CheckNursery) Check nursery integrity on minor GC\n"
|
||||
" 17: (IncrementalSweepThenFinish) Incremental GC in two slices: 1) start sweeping 2) finish collection\n"
|
||||
" 18: (CheckGrayMarking) Check gray marking invariants after every GC\n";
|
||||
" 0: (None) Normal amount of collection (resets all modes)\n"
|
||||
" 1: (RootsChange) Collect when roots are added or removed\n"
|
||||
" 2: (Alloc) Collect when every N allocations (default: 100)\n"
|
||||
" 4: (VerifierPre) Verify pre write barriers between instructions\n"
|
||||
" 7: (GenerationalGC) Collect the nursery every N nursery allocations\n"
|
||||
" 8: (YieldBeforeMarking) Incremental GC in two slices that yields between\n"
|
||||
" the root marking and marking phases\n"
|
||||
" 9: (YieldBeforeSweeping) Incremental GC in two slices that yields between\n"
|
||||
" the marking and sweeping phases\n"
|
||||
" 10: (IncrementalMultipleSlices) Incremental GC in many slices\n"
|
||||
" 11: (IncrementalMarkingValidator) Verify incremental marking\n"
|
||||
" 12: (ElementsBarrier) Use the individual element post-write barrier\n"
|
||||
" regardless of elements size\n"
|
||||
" 13: (CheckHashTablesOnMinorGC) Check internal hashtables on minor GC\n"
|
||||
" 14: (Compact) Perform a shrinking collection every N allocations\n"
|
||||
" 15: (CheckHeapAfterGC) Walk the heap to check its integrity after every GC\n"
|
||||
" 16: (CheckNursery) Check nursery integrity on minor GC\n"
|
||||
" 17: (YieldBeforeSweepingAtoms) Incremental GC in two slices that yields\n"
|
||||
" before sweeping the atoms table\n"
|
||||
" 18: (CheckGrayMarking) Check gray marking invariants after every GC\n"
|
||||
" 19: (YieldBeforeSweepingCaches) Incremental GC in two slices that yields\n"
|
||||
" before sweeping weak caches\n"
|
||||
" 20: (YieldBeforeSweepingTypes) Incremental GC in two slices that yields\n"
|
||||
" before sweeping type information\n"
|
||||
" 21: (YieldBeforeSweepingObjects) Incremental GC in two slices that yields\n"
|
||||
" before sweeping foreground finalized objects\n"
|
||||
" 22: (YieldBeforeSweepingNonObjects) Incremental GC in two slices that yields\n"
|
||||
" before sweeping non-object GC things\n"
|
||||
" 23: (YieldBeforeSweepingShapeTrees) Incremental GC in two slices that yields\n"
|
||||
" before sweeping shape trees\n";
|
||||
|
||||
// The set of zeal modes that control incremental slices. These modes are
|
||||
// mutually exclusive.
|
||||
static const mozilla::EnumSet<ZealMode> IncrementalSliceZealModes = {
|
||||
ZealMode::IncrementalRootsThenFinish,
|
||||
ZealMode::IncrementalMarkAllThenFinish,
|
||||
ZealMode::YieldBeforeMarking,
|
||||
ZealMode::YieldBeforeSweeping,
|
||||
ZealMode::IncrementalMultipleSlices,
|
||||
ZealMode::IncrementalSweepThenFinish
|
||||
ZealMode::YieldBeforeSweepingAtoms,
|
||||
ZealMode::YieldBeforeSweepingCaches,
|
||||
ZealMode::YieldBeforeSweepingTypes,
|
||||
ZealMode::YieldBeforeSweepingObjects,
|
||||
ZealMode::YieldBeforeSweepingNonObjects,
|
||||
ZealMode::YieldBeforeSweepingShapeTrees
|
||||
};
|
||||
|
||||
void
|
||||
|
@ -1089,66 +1109,108 @@ GCRuntime::setNextScheduled(uint32_t count)
|
|||
nextScheduled = count;
|
||||
}
|
||||
|
||||
using CharRange = mozilla::Range<const char>;
|
||||
using CharRangeVector = Vector<CharRange, 0, SystemAllocPolicy>;
|
||||
|
||||
static bool
|
||||
ParseZealModeName(CharRange text, uint32_t* modeOut)
|
||||
{
|
||||
struct ModeInfo
|
||||
{
|
||||
const char* name;
|
||||
size_t length;
|
||||
uint32_t value;
|
||||
};
|
||||
|
||||
static const ModeInfo zealModes[] = {
|
||||
{"None", 0},
|
||||
#define ZEAL_MODE(name, value) {#name, strlen(#name), value},
|
||||
JS_FOR_EACH_ZEAL_MODE(ZEAL_MODE)
|
||||
#undef ZEAL_MODE
|
||||
};
|
||||
|
||||
for (auto mode : zealModes) {
|
||||
if (text.length() == mode.length &&
|
||||
memcmp(text.begin().get(), mode.name, mode.length) == 0)
|
||||
{
|
||||
*modeOut = mode.value;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool
|
||||
ParseZealModeNumericParam(CharRange text, uint32_t* paramOut)
|
||||
{
|
||||
if (text.length() == 0)
|
||||
return false;
|
||||
|
||||
for (auto c : text) {
|
||||
if (!isdigit(c))
|
||||
return false;
|
||||
}
|
||||
|
||||
*paramOut = atoi(text.begin().get());
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
SplitStringBy(CharRange text, char delimiter, CharRangeVector* result)
|
||||
{
|
||||
auto start = text.begin();
|
||||
for (auto ptr = start; ptr != text.end(); ptr++) {
|
||||
if (*ptr == delimiter) {
|
||||
if (!result->emplaceBack(start, ptr))
|
||||
return false;
|
||||
start = ptr + 1;
|
||||
}
|
||||
}
|
||||
|
||||
return result->emplaceBack(start, text.end());
|
||||
}
|
||||
|
||||
static bool
|
||||
PrintZealHelpAndFail()
|
||||
{
|
||||
fprintf(stderr, "Format: JS_GC_ZEAL=level(;level)*[,N]\n");
|
||||
fputs(ZealModeHelpText, stderr);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
GCRuntime::parseAndSetZeal(const char* str)
|
||||
{
|
||||
int frequency = -1;
|
||||
bool foundFrequency = false;
|
||||
mozilla::Vector<int, 0, SystemAllocPolicy> zeals;
|
||||
// Set the zeal mode from a string consisting of one or more mode specifiers
|
||||
// separated by ';', optionally followed by a ',' and the trigger frequency.
|
||||
// The mode specifiers can by a mode name or its number.
|
||||
|
||||
static const struct {
|
||||
const char* const zealMode;
|
||||
size_t length;
|
||||
uint32_t zeal;
|
||||
} zealModes[] = {
|
||||
#define ZEAL_MODE(name, value) {#name, sizeof(#name) - 1, value},
|
||||
JS_FOR_EACH_ZEAL_MODE(ZEAL_MODE)
|
||||
#undef ZEAL_MODE
|
||||
{"None", 4, 0}
|
||||
};
|
||||
auto text = CharRange(str, strlen(str));
|
||||
|
||||
do {
|
||||
int zeal = -1;
|
||||
CharRangeVector parts;
|
||||
if (!SplitStringBy(text, ',', &parts))
|
||||
return false;
|
||||
|
||||
const char* p = nullptr;
|
||||
if (isdigit(str[0])) {
|
||||
zeal = atoi(str);
|
||||
if (parts.length() == 0 || parts.length() > 2)
|
||||
return PrintZealHelpAndFail();
|
||||
|
||||
size_t offset = strspn(str, "0123456789");
|
||||
p = str + offset;
|
||||
} else {
|
||||
for (auto z : zealModes) {
|
||||
if (!strncmp(str, z.zealMode, z.length)) {
|
||||
zeal = z.zeal;
|
||||
p = str + z.length;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (p) {
|
||||
if (!*p || *p == ';') {
|
||||
frequency = JS_DEFAULT_ZEAL_FREQ;
|
||||
} else if (*p == ',') {
|
||||
frequency = atoi(p + 1);
|
||||
foundFrequency = true;
|
||||
}
|
||||
}
|
||||
uint32_t frequency = JS_DEFAULT_ZEAL_FREQ;
|
||||
if (parts.length() == 2 && !ParseZealModeNumericParam(parts[1], &frequency))
|
||||
return PrintZealHelpAndFail();
|
||||
|
||||
if (zeal < 0 || zeal > int(ZealMode::Limit) || frequency <= 0) {
|
||||
fprintf(stderr, "Format: JS_GC_ZEAL=level(;level)*[,N]\n");
|
||||
fputs(ZealModeHelpText, stderr);
|
||||
return false;
|
||||
}
|
||||
CharRangeVector modes;
|
||||
if (!SplitStringBy(parts[0], ';', &modes))
|
||||
return false;
|
||||
|
||||
if (!zeals.emplaceBack(zeal)) {
|
||||
return false;
|
||||
}
|
||||
} while (!foundFrequency &&
|
||||
(str = strchr(str, ';')) != nullptr &&
|
||||
str++);
|
||||
for (const auto& descr : modes) {
|
||||
uint32_t mode;
|
||||
if (!ParseZealModeName(descr, &mode) && !ParseZealModeNumericParam(descr, &mode))
|
||||
return PrintZealHelpAndFail();
|
||||
|
||||
setZeal(mode, frequency);
|
||||
}
|
||||
|
||||
for (auto z : zeals)
|
||||
setZeal(z, frequency);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -4944,12 +5006,10 @@ GCRuntime::groupZonesForSweeping(JS::gcreason::Reason reason)
|
|||
finder.useOneComponent();
|
||||
|
||||
#ifdef JS_GC_ZEAL
|
||||
// Use one component for IncrementalSweepThenFinish zeal mode.
|
||||
if (isIncremental && reason == JS::gcreason::DEBUG_GC &&
|
||||
hasZealMode(ZealMode::IncrementalSweepThenFinish))
|
||||
{
|
||||
// Use one component for two-slice zeal modes.
|
||||
MOZ_ASSERT_IF(useZeal, isIncremental);
|
||||
if (useZeal && hasIncrementalTwoSliceZealMode())
|
||||
finder.useOneComponent();
|
||||
}
|
||||
#endif
|
||||
|
||||
for (GCZonesIter zone(rt); !zone.done(); zone.next()) {
|
||||
|
@ -5688,6 +5748,14 @@ GCRuntime::beginSweepingSweepGroup(FreeOp* fop, SliceBudget& budget)
|
|||
}
|
||||
|
||||
#ifdef JS_GC_ZEAL
|
||||
|
||||
bool
|
||||
GCRuntime::shouldYieldForZeal(ZealMode mode)
|
||||
{
|
||||
MOZ_ASSERT_IF(useZeal, isIncremental);
|
||||
return useZeal && hasZealMode(mode);
|
||||
}
|
||||
|
||||
IncrementalProgress
|
||||
GCRuntime::maybeYieldForSweepingZeal(FreeOp* fop, SliceBudget& budget)
|
||||
{
|
||||
|
@ -5696,15 +5764,12 @@ GCRuntime::maybeYieldForSweepingZeal(FreeOp* fop, SliceBudget& budget)
|
|||
* in incremental multi-slice zeal mode so RunDebugGC can reset the slice
|
||||
* budget.
|
||||
*/
|
||||
if (isIncremental && useZeal && initialState != State::Sweep &&
|
||||
(hasZealMode(ZealMode::IncrementalMultipleSlices) ||
|
||||
hasZealMode(ZealMode::IncrementalSweepThenFinish)))
|
||||
{
|
||||
if (initialState != State::Sweep && shouldYieldForZeal(ZealMode::IncrementalMultipleSlices))
|
||||
return NotFinished;
|
||||
}
|
||||
|
||||
return Finished;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
IncrementalProgress
|
||||
|
@ -6235,6 +6300,38 @@ class SweepActionCall final : public SweepAction<GCRuntime*, Args...>
|
|||
void assertFinished() const override { }
|
||||
};
|
||||
|
||||
#ifdef JS_GC_ZEAL
|
||||
// Implementation of the SweepAction interface that yields in a specified zeal
|
||||
// mode and then calls another action.
|
||||
template <typename... Args>
|
||||
class SweepActionMaybeYield final : public SweepAction<GCRuntime*, Args...>
|
||||
{
|
||||
using Action = SweepAction<GCRuntime*, Args...>;
|
||||
|
||||
ZealMode mode;
|
||||
UniquePtr<Action> action;
|
||||
bool triggered;
|
||||
|
||||
public:
|
||||
SweepActionMaybeYield(UniquePtr<Action> action, ZealMode mode)
|
||||
: mode(mode), action(Move(action)), triggered(false) {}
|
||||
|
||||
IncrementalProgress run(GCRuntime* gc, Args... args) override {
|
||||
if (!triggered && gc->shouldYieldForZeal(mode)) {
|
||||
triggered = true;
|
||||
return NotFinished;
|
||||
}
|
||||
|
||||
triggered = false;
|
||||
return action->run(gc, args...);
|
||||
}
|
||||
|
||||
void assertFinished() const override {
|
||||
MOZ_ASSERT(!triggered);
|
||||
}
|
||||
};
|
||||
#endif
|
||||
|
||||
// Implementation of the SweepAction interface that calls a list of actions in
|
||||
// sequence.
|
||||
template <typename... Args>
|
||||
|
@ -6371,7 +6468,17 @@ class RemoveLastTemplateParameter<Target<Args...>>
|
|||
template <typename... Args>
|
||||
static UniquePtr<SweepAction<GCRuntime*, Args...>>
|
||||
Call(IncrementalProgress (GCRuntime::*method)(Args...)) {
|
||||
return MakeUnique<SweepActionCall<Args...>>(method);
|
||||
return MakeUnique<SweepActionCall<Args...>>(method);
|
||||
}
|
||||
|
||||
template <typename... Args>
|
||||
static UniquePtr<SweepAction<GCRuntime*, Args...>>
|
||||
MaybeYield(ZealMode zealMode, UniquePtr<SweepAction<GCRuntime*, Args...>> action) {
|
||||
#ifdef JS_GC_ZEAL
|
||||
return js::MakeUnique<SweepActionMaybeYield<Args...>>(Move(action), zealMode);
|
||||
#else
|
||||
return action;
|
||||
#endif
|
||||
}
|
||||
|
||||
template <typename... Args, typename... Rest>
|
||||
|
@ -6437,16 +6544,22 @@ GCRuntime::initSweepActions()
|
|||
#ifdef JS_GC_ZEAL
|
||||
Call(&GCRuntime::maybeYieldForSweepingZeal),
|
||||
#endif
|
||||
Call(&GCRuntime::sweepAtomsTable),
|
||||
Call(&GCRuntime::sweepWeakCaches),
|
||||
MaybeYield(ZealMode::YieldBeforeSweepingAtoms,
|
||||
Call(&GCRuntime::sweepAtomsTable)),
|
||||
MaybeYield(ZealMode::YieldBeforeSweepingCaches,
|
||||
Call(&GCRuntime::sweepWeakCaches)),
|
||||
ForEachZoneInSweepGroup(rt,
|
||||
Sequence(
|
||||
Call(&GCRuntime::sweepTypeInformation),
|
||||
ForEachAllocKind(ForegroundObjectFinalizePhase.kinds,
|
||||
Call(&GCRuntime::finalizeAllocKind)),
|
||||
ForEachAllocKind(ForegroundNonObjectFinalizePhase.kinds,
|
||||
Call(&GCRuntime::finalizeAllocKind)),
|
||||
Call(&GCRuntime::sweepShapeTree),
|
||||
MaybeYield(ZealMode::YieldBeforeSweepingTypes,
|
||||
Call(&GCRuntime::sweepTypeInformation)),
|
||||
MaybeYield(ZealMode::YieldBeforeSweepingObjects,
|
||||
ForEachAllocKind(ForegroundObjectFinalizePhase.kinds,
|
||||
Call(&GCRuntime::finalizeAllocKind))),
|
||||
MaybeYield(ZealMode::YieldBeforeSweepingNonObjects,
|
||||
ForEachAllocKind(ForegroundNonObjectFinalizePhase.kinds,
|
||||
Call(&GCRuntime::finalizeAllocKind))),
|
||||
MaybeYield(ZealMode::YieldBeforeSweepingShapeTrees,
|
||||
Call(&GCRuntime::sweepShapeTree)),
|
||||
Call(&GCRuntime::releaseSweptEmptyArenas))),
|
||||
Call(&GCRuntime::endSweepingSweepGroup)));
|
||||
|
||||
|
@ -6944,10 +7057,7 @@ GCRuntime::incrementalCollectSlice(SliceBudget& budget, JS::gcreason::Reason rea
|
|||
|
||||
isIncremental = !budget.isUnlimited();
|
||||
|
||||
if (useZeal && (hasZealMode(ZealMode::IncrementalRootsThenFinish) ||
|
||||
hasZealMode(ZealMode::IncrementalMarkAllThenFinish) ||
|
||||
hasZealMode(ZealMode::IncrementalSweepThenFinish)))
|
||||
{
|
||||
if (useZeal && hasIncrementalTwoSliceZealMode()) {
|
||||
/*
|
||||
* Yields between slices occurs at predetermined points in these modes;
|
||||
* the budget is not used.
|
||||
|
@ -6978,7 +7088,7 @@ GCRuntime::incrementalCollectSlice(SliceBudget& budget, JS::gcreason::Reason rea
|
|||
|
||||
incrementalState = State::Mark;
|
||||
|
||||
if (isIncremental && useZeal && hasZealMode(ZealMode::IncrementalRootsThenFinish))
|
||||
if (isIncremental && useZeal && hasZealMode(ZealMode::YieldBeforeMarking))
|
||||
break;
|
||||
|
||||
MOZ_FALLTHROUGH;
|
||||
|
@ -7004,16 +7114,16 @@ GCRuntime::incrementalCollectSlice(SliceBudget& budget, JS::gcreason::Reason rea
|
|||
* the next slice, since the first slice of sweeping can be expensive.
|
||||
*
|
||||
* This is modified by the various zeal modes. We don't yield in
|
||||
* IncrementalRootsThenFinish mode and we always yield in
|
||||
* IncrementalMarkAllThenFinish mode.
|
||||
* YieldBeforeMarking mode and we always yield in YieldBeforeSweeping
|
||||
* mode.
|
||||
*
|
||||
* We will need to mark anything new on the stack when we resume, so
|
||||
* we stay in Mark state.
|
||||
*/
|
||||
if (!lastMarkSlice && isIncremental &&
|
||||
((initialState == State::Mark &&
|
||||
!(useZeal && hasZealMode(ZealMode::IncrementalRootsThenFinish))) ||
|
||||
(useZeal && hasZealMode(ZealMode::IncrementalMarkAllThenFinish))))
|
||||
!(useZeal && hasZealMode(ZealMode::YieldBeforeMarking))) ||
|
||||
(useZeal && hasZealMode(ZealMode::YieldBeforeSweeping))))
|
||||
{
|
||||
lastMarkSlice = true;
|
||||
break;
|
||||
|
@ -8024,43 +8134,37 @@ GCRuntime::runDebugGC()
|
|||
PrepareForDebugGC(rt);
|
||||
|
||||
auto budget = SliceBudget::unlimited();
|
||||
if (hasZealMode(ZealMode::IncrementalRootsThenFinish) ||
|
||||
hasZealMode(ZealMode::IncrementalMarkAllThenFinish) ||
|
||||
hasZealMode(ZealMode::IncrementalMultipleSlices) ||
|
||||
hasZealMode(ZealMode::IncrementalSweepThenFinish))
|
||||
{
|
||||
js::gc::State initialState = incrementalState;
|
||||
if (hasZealMode(ZealMode::IncrementalMultipleSlices)) {
|
||||
/*
|
||||
* Start with a small slice limit and double it every slice. This
|
||||
* ensure that we get multiple slices, and collection runs to
|
||||
* completion.
|
||||
*/
|
||||
if (!isIncrementalGCInProgress())
|
||||
incrementalLimit = zealFrequency / 2;
|
||||
else
|
||||
incrementalLimit *= 2;
|
||||
budget = SliceBudget(WorkBudget(incrementalLimit));
|
||||
} else {
|
||||
// This triggers incremental GC but is actually ignored by IncrementalMarkSlice.
|
||||
budget = SliceBudget(WorkBudget(1));
|
||||
}
|
||||
if (hasZealMode(ZealMode::IncrementalMultipleSlices)) {
|
||||
/*
|
||||
* Start with a small slice limit and double it every slice. This
|
||||
* ensure that we get multiple slices, and collection runs to
|
||||
* completion.
|
||||
*/
|
||||
if (!isIncrementalGCInProgress())
|
||||
incrementalLimit = zealFrequency / 2;
|
||||
else
|
||||
incrementalLimit *= 2;
|
||||
budget = SliceBudget(WorkBudget(incrementalLimit));
|
||||
|
||||
js::gc::State initialState = incrementalState;
|
||||
if (!isIncrementalGCInProgress())
|
||||
invocationKind = GC_SHRINK;
|
||||
collect(false, budget, JS::gcreason::DEBUG_GC);
|
||||
|
||||
/*
|
||||
* For multi-slice zeal, reset the slice size when we get to the sweep
|
||||
* or compact phases.
|
||||
*/
|
||||
if (hasZealMode(ZealMode::IncrementalMultipleSlices)) {
|
||||
if ((initialState == State::Mark && incrementalState == State::Sweep) ||
|
||||
(initialState == State::Sweep && incrementalState == State::Compact))
|
||||
{
|
||||
incrementalLimit = zealFrequency / 2;
|
||||
}
|
||||
/* Reset the slice size when we get to the sweep or compact phases. */
|
||||
if ((initialState == State::Mark && incrementalState == State::Sweep) ||
|
||||
(initialState == State::Sweep && incrementalState == State::Compact))
|
||||
{
|
||||
incrementalLimit = zealFrequency / 2;
|
||||
}
|
||||
} else if (hasIncrementalTwoSliceZealMode()) {
|
||||
// These modes trigger incremental GC that happens in two slices and the
|
||||
// supplied budget is ignored by incrementalCollectSlice.
|
||||
budget = SliceBudget(WorkBudget(1));
|
||||
|
||||
if (!isIncrementalGCInProgress())
|
||||
invocationKind = GC_NORMAL;
|
||||
collect(false, budget, JS::gcreason::DEBUG_GC);
|
||||
} else if (hasZealMode(ZealMode::Compact)) {
|
||||
gc(GC_SHRINK, JS::gcreason::DEBUG_GC);
|
||||
} else {
|
||||
|
|
|
@ -164,10 +164,11 @@ MaybeVerifyBarriers(JSContext* cx, bool always = false) {}
|
|||
#endif
|
||||
|
||||
/*
|
||||
* Instances of this class set the |JSRuntime::suppressGC| flag for the duration
|
||||
* that they are live. Use of this class is highly discouraged. Please carefully
|
||||
* read the comment in vm/Runtime.h above |suppressGC| and take all appropriate
|
||||
* precautions before instantiating this class.
|
||||
* Instances of this class prevent GC while they are live by updating the
|
||||
* |JSContext::suppressGC| counter. Use of this class is highly
|
||||
* discouraged. Please carefully read the comment in vm/JSContext.h above
|
||||
* |suppressGC| and take all appropriate precautions before instantiating this
|
||||
* class.
|
||||
*/
|
||||
class MOZ_RAII JS_HAZ_GC_SUPPRESSED AutoSuppressGC
|
||||
{
|
||||
|
|
|
@ -57,28 +57,34 @@ enum class AbortReason {
|
|||
#undef MAKE_REASON
|
||||
};
|
||||
|
||||
#define JS_FOR_EACH_ZEAL_MODE(D) \
|
||||
D(RootsChange, 1) \
|
||||
D(Alloc, 2) \
|
||||
D(VerifierPre, 4) \
|
||||
D(GenerationalGC, 7) \
|
||||
D(IncrementalRootsThenFinish, 8) \
|
||||
D(IncrementalMarkAllThenFinish, 9) \
|
||||
D(IncrementalMultipleSlices, 10) \
|
||||
D(IncrementalMarkingValidator, 11) \
|
||||
D(ElementsBarrier, 12) \
|
||||
D(CheckHashTablesOnMinorGC, 13) \
|
||||
D(Compact, 14) \
|
||||
D(CheckHeapAfterGC, 15) \
|
||||
D(CheckNursery, 16) \
|
||||
D(IncrementalSweepThenFinish, 17) \
|
||||
D(CheckGrayMarking, 18)
|
||||
#define JS_FOR_EACH_ZEAL_MODE(D) \
|
||||
D(RootsChange, 1) \
|
||||
D(Alloc, 2) \
|
||||
D(VerifierPre, 4) \
|
||||
D(GenerationalGC, 7) \
|
||||
D(YieldBeforeMarking, 8) \
|
||||
D(YieldBeforeSweeping, 9) \
|
||||
D(IncrementalMultipleSlices, 10) \
|
||||
D(IncrementalMarkingValidator, 11) \
|
||||
D(ElementsBarrier, 12) \
|
||||
D(CheckHashTablesOnMinorGC, 13) \
|
||||
D(Compact, 14) \
|
||||
D(CheckHeapAfterGC, 15) \
|
||||
D(CheckNursery, 16) \
|
||||
D(YieldBeforeSweepingAtoms, 17) \
|
||||
D(CheckGrayMarking, 18) \
|
||||
D(YieldBeforeSweepingCaches, 19) \
|
||||
D(YieldBeforeSweepingTypes, 20) \
|
||||
D(YieldBeforeSweepingObjects, 21) \
|
||||
D(YieldBeforeSweepingNonObjects, 22) \
|
||||
D(YieldBeforeSweepingShapeTrees, 23)
|
||||
|
||||
enum class ZealMode {
|
||||
#define ZEAL_MODE(name, value) name = value,
|
||||
JS_FOR_EACH_ZEAL_MODE(ZEAL_MODE)
|
||||
#undef ZEAL_MODE
|
||||
Limit = 18
|
||||
Count,
|
||||
Limit = Count - 1
|
||||
};
|
||||
|
||||
} /* namespace gc */
|
||||
|
|
|
@ -42,7 +42,7 @@ class GCHelperState
|
|||
ConditionVariable done;
|
||||
|
||||
// Activity for the helper to do, protected by the GC lock.
|
||||
ActiveThreadOrGCTaskData<State> state_;
|
||||
MainThreadOrGCTaskData<State> state_;
|
||||
|
||||
// Whether work is being performed on some thread.
|
||||
GCLockData<bool> hasThread;
|
||||
|
|
|
@ -174,13 +174,13 @@ class MarkStack
|
|||
const TaggedPtr& peekPtr() const;
|
||||
MOZ_MUST_USE bool pushTaggedPtr(Tag tag, Cell* ptr);
|
||||
|
||||
ActiveThreadData<TaggedPtr*> stack_;
|
||||
ActiveThreadData<TaggedPtr*> tos_;
|
||||
ActiveThreadData<TaggedPtr*> end_;
|
||||
MainThreadData<TaggedPtr*> stack_;
|
||||
MainThreadData<TaggedPtr*> tos_;
|
||||
MainThreadData<TaggedPtr*> end_;
|
||||
|
||||
// The capacity we start with and reset() to.
|
||||
ActiveThreadData<size_t> baseCapacity_;
|
||||
ActiveThreadData<size_t> maxCapacity_;
|
||||
MainThreadData<size_t> baseCapacity_;
|
||||
MainThreadData<size_t> maxCapacity_;
|
||||
|
||||
#ifdef DEBUG
|
||||
mutable size_t iteratorCount_;
|
||||
|
@ -349,29 +349,29 @@ class GCMarker : public JSTracer
|
|||
gc::MarkStack stack;
|
||||
|
||||
/* The color is only applied to objects and functions. */
|
||||
ActiveThreadData<gc::MarkColor> color;
|
||||
MainThreadData<gc::MarkColor> color;
|
||||
|
||||
/* Pointer to the top of the stack of arenas we are delaying marking on. */
|
||||
ActiveThreadData<js::gc::Arena*> unmarkedArenaStackTop;
|
||||
MainThreadData<js::gc::Arena*> unmarkedArenaStackTop;
|
||||
|
||||
/*
|
||||
* If the weakKeys table OOMs, disable the linear algorithm and fall back
|
||||
* to iterating until the next GC.
|
||||
*/
|
||||
ActiveThreadData<bool> linearWeakMarkingDisabled_;
|
||||
MainThreadData<bool> linearWeakMarkingDisabled_;
|
||||
|
||||
#ifdef DEBUG
|
||||
/* Count of arenas that are currently in the stack. */
|
||||
ActiveThreadData<size_t> markLaterArenas;
|
||||
MainThreadData<size_t> markLaterArenas;
|
||||
|
||||
/* Assert that start and stop are called with correct ordering. */
|
||||
ActiveThreadData<bool> started;
|
||||
MainThreadData<bool> started;
|
||||
|
||||
/*
|
||||
* If this is true, all marked objects must belong to a compartment being
|
||||
* GCed. This is used to look for compartment bugs.
|
||||
*/
|
||||
ActiveThreadData<bool> strictCompartmentChecking;
|
||||
MainThreadData<bool> strictCompartmentChecking;
|
||||
#endif // DEBUG
|
||||
};
|
||||
|
||||
|
|
|
@ -28,7 +28,7 @@ class GCParallelTask
|
|||
UnprotectedData<TaskState> state;
|
||||
|
||||
// Amount of time this task took to execute.
|
||||
ActiveThreadOrGCTaskData<mozilla::TimeDuration> duration_;
|
||||
MainThreadOrGCTaskData<mozilla::TimeDuration> duration_;
|
||||
|
||||
explicit GCParallelTask(const GCParallelTask&) = delete;
|
||||
|
||||
|
|
|
@ -134,13 +134,13 @@ class BackgroundDecommitTask : public GCParallelTask
|
|||
void run() override;
|
||||
|
||||
private:
|
||||
ActiveThreadOrGCTaskData<ChunkVector> toDecommit;
|
||||
MainThreadOrGCTaskData<ChunkVector> toDecommit;
|
||||
};
|
||||
|
||||
template<typename F>
|
||||
struct Callback {
|
||||
ActiveThreadOrGCTaskData<F> op;
|
||||
ActiveThreadOrGCTaskData<void*> data;
|
||||
MainThreadOrGCTaskData<F> op;
|
||||
MainThreadOrGCTaskData<void*> data;
|
||||
|
||||
Callback()
|
||||
: op(nullptr), data(nullptr)
|
||||
|
@ -151,7 +151,7 @@ struct Callback {
|
|||
};
|
||||
|
||||
template<typename F>
|
||||
using CallbackVector = ActiveThreadData<Vector<Callback<F>, 4, SystemAllocPolicy>>;
|
||||
using CallbackVector = MainThreadData<Vector<Callback<F>, 4, SystemAllocPolicy>>;
|
||||
|
||||
template <typename T, typename Iter0, typename Iter1>
|
||||
class ChainedIter
|
||||
|
@ -230,6 +230,7 @@ class GCRuntime
|
|||
inline void clearZealMode(ZealMode mode);
|
||||
inline bool upcomingZealousGC();
|
||||
inline bool needZealousGC();
|
||||
inline bool hasIncrementalTwoSliceZealMode();
|
||||
|
||||
MOZ_MUST_USE bool addRoot(Value* vp, const char* name);
|
||||
void removeRoot(Value* vp);
|
||||
|
@ -446,6 +447,7 @@ class GCRuntime
|
|||
void endVerifyPreBarriers();
|
||||
void finishVerifier();
|
||||
bool isVerifyPreBarriersEnabled() const { return !!verifyPreData; }
|
||||
bool shouldYieldForZeal(ZealMode mode);
|
||||
#else
|
||||
bool isVerifyPreBarriersEnabled() const { return false; }
|
||||
#endif
|
||||
|
@ -643,7 +645,7 @@ class GCRuntime
|
|||
|
||||
// All zones in the runtime, except the atoms zone.
|
||||
private:
|
||||
ActiveThreadOrGCTaskData<ZoneVector> zones_;
|
||||
MainThreadOrGCTaskData<ZoneVector> zones_;
|
||||
public:
|
||||
ZoneVector& zones() { return zones_.ref(); }
|
||||
|
||||
|
@ -690,7 +692,7 @@ class GCRuntime
|
|||
// so as to reduce the cost of operations on the available lists.
|
||||
GCLockData<ChunkPool> fullChunks_;
|
||||
|
||||
ActiveThreadData<RootedValueMap> rootsHash;
|
||||
MainThreadData<RootedValueMap> rootsHash;
|
||||
|
||||
// An incrementing id used to assign unique ids to cells that require one.
|
||||
mozilla::Atomic<uint64_t, mozilla::ReleaseAcquire> nextCellUniqueId_;
|
||||
|
@ -699,23 +701,23 @@ class GCRuntime
|
|||
* Number of the committed arenas in all GC chunks including empty chunks.
|
||||
*/
|
||||
mozilla::Atomic<uint32_t, mozilla::ReleaseAcquire> numArenasFreeCommitted;
|
||||
ActiveThreadData<VerifyPreTracer*> verifyPreData;
|
||||
MainThreadData<VerifyPreTracer*> verifyPreData;
|
||||
|
||||
private:
|
||||
UnprotectedData<bool> chunkAllocationSinceLastGC;
|
||||
ActiveThreadData<int64_t> lastGCTime;
|
||||
MainThreadData<int64_t> lastGCTime;
|
||||
|
||||
/*
|
||||
* JSGC_MODE
|
||||
* prefs: javascript.options.mem.gc_per_zone and
|
||||
* javascript.options.mem.gc_incremental.
|
||||
*/
|
||||
ActiveThreadData<JSGCMode> mode;
|
||||
MainThreadData<JSGCMode> mode;
|
||||
|
||||
mozilla::Atomic<size_t, mozilla::ReleaseAcquire> numActiveZoneIters;
|
||||
|
||||
/* During shutdown, the GC needs to clean up every possible object. */
|
||||
ActiveThreadData<bool> cleanUpEverything;
|
||||
MainThreadData<bool> cleanUpEverything;
|
||||
|
||||
// Gray marking must be done after all black marking is complete. However,
|
||||
// we do not have write barriers on XPConnect roots. Therefore, XPConnect
|
||||
|
@ -728,7 +730,7 @@ class GCRuntime
|
|||
Okay,
|
||||
Failed
|
||||
};
|
||||
ActiveThreadOrGCTaskData<GrayBufferState> grayBufferState;
|
||||
MainThreadOrGCTaskData<GrayBufferState> grayBufferState;
|
||||
bool hasValidGrayRootsBuffer() const { return grayBufferState == GrayBufferState::Okay; }
|
||||
|
||||
// Clear each zone's gray buffers, but do not change the current state.
|
||||
|
@ -750,85 +752,85 @@ class GCRuntime
|
|||
|
||||
private:
|
||||
/* Perform full GC if rt->keepAtoms() becomes false. */
|
||||
ActiveThreadData<bool> fullGCForAtomsRequested_;
|
||||
MainThreadData<bool> fullGCForAtomsRequested_;
|
||||
|
||||
/* Incremented at the start of every minor GC. */
|
||||
ActiveThreadData<uint64_t> minorGCNumber;
|
||||
MainThreadData<uint64_t> minorGCNumber;
|
||||
|
||||
/* Incremented at the start of every major GC. */
|
||||
ActiveThreadData<uint64_t> majorGCNumber;
|
||||
MainThreadData<uint64_t> majorGCNumber;
|
||||
|
||||
/* The major GC number at which to release observed type information. */
|
||||
ActiveThreadData<uint64_t> jitReleaseNumber;
|
||||
MainThreadData<uint64_t> jitReleaseNumber;
|
||||
|
||||
/* Incremented on every GC slice. */
|
||||
ActiveThreadData<uint64_t> number;
|
||||
MainThreadData<uint64_t> number;
|
||||
|
||||
/* Whether the currently running GC can finish in multiple slices. */
|
||||
ActiveThreadData<bool> isIncremental;
|
||||
MainThreadData<bool> isIncremental;
|
||||
|
||||
/* Whether all zones are being collected in first GC slice. */
|
||||
ActiveThreadData<bool> isFull;
|
||||
MainThreadData<bool> isFull;
|
||||
|
||||
/* Whether the heap will be compacted at the end of GC. */
|
||||
ActiveThreadData<bool> isCompacting;
|
||||
MainThreadData<bool> isCompacting;
|
||||
|
||||
/* The invocation kind of the current GC, taken from the first slice. */
|
||||
ActiveThreadData<JSGCInvocationKind> invocationKind;
|
||||
MainThreadData<JSGCInvocationKind> invocationKind;
|
||||
|
||||
/* The initial GC reason, taken from the first slice. */
|
||||
ActiveThreadData<JS::gcreason::Reason> initialReason;
|
||||
MainThreadData<JS::gcreason::Reason> initialReason;
|
||||
|
||||
/*
|
||||
* The current incremental GC phase. This is also used internally in
|
||||
* non-incremental GC.
|
||||
*/
|
||||
ActiveThreadOrGCTaskData<State> incrementalState;
|
||||
MainThreadOrGCTaskData<State> incrementalState;
|
||||
|
||||
/* The incremental state at the start of this slice. */
|
||||
ActiveThreadData<State> initialState;
|
||||
MainThreadData<State> initialState;
|
||||
|
||||
#ifdef JS_GC_ZEAL
|
||||
/* Whether to pay attention the zeal settings in this incremental slice. */
|
||||
ActiveThreadData<bool> useZeal;
|
||||
MainThreadData<bool> useZeal;
|
||||
#endif
|
||||
|
||||
/* Indicates that the last incremental slice exhausted the mark stack. */
|
||||
ActiveThreadData<bool> lastMarkSlice;
|
||||
MainThreadData<bool> lastMarkSlice;
|
||||
|
||||
/* Whether it's currently safe to yield to the mutator in an incremental GC. */
|
||||
ActiveThreadData<bool> safeToYield;
|
||||
MainThreadData<bool> safeToYield;
|
||||
|
||||
/* Whether any sweeping will take place in the separate GC helper thread. */
|
||||
ActiveThreadData<bool> sweepOnBackgroundThread;
|
||||
MainThreadData<bool> sweepOnBackgroundThread;
|
||||
|
||||
/* Whether observed type information is being released in the current GC. */
|
||||
ActiveThreadData<bool> releaseObservedTypes;
|
||||
MainThreadData<bool> releaseObservedTypes;
|
||||
|
||||
/* Singly linked list of zones to be swept in the background. */
|
||||
ActiveThreadOrGCTaskData<ZoneList> backgroundSweepZones;
|
||||
MainThreadOrGCTaskData<ZoneList> backgroundSweepZones;
|
||||
|
||||
/*
|
||||
* Free LIFO blocks are transferred to this allocator before being freed on
|
||||
* the background GC thread after sweeping.
|
||||
*/
|
||||
ActiveThreadOrGCTaskData<LifoAlloc> blocksToFreeAfterSweeping;
|
||||
MainThreadOrGCTaskData<LifoAlloc> blocksToFreeAfterSweeping;
|
||||
|
||||
private:
|
||||
/* Index of current sweep group (for stats). */
|
||||
ActiveThreadData<unsigned> sweepGroupIndex;
|
||||
MainThreadData<unsigned> sweepGroupIndex;
|
||||
|
||||
/*
|
||||
* Incremental sweep state.
|
||||
*/
|
||||
|
||||
ActiveThreadData<JS::Zone*> sweepGroups;
|
||||
ActiveThreadOrGCTaskData<JS::Zone*> currentSweepGroup;
|
||||
ActiveThreadData<UniquePtr<SweepAction<GCRuntime*, FreeOp*, SliceBudget&>>> sweepActions;
|
||||
ActiveThreadOrGCTaskData<JS::Zone*> sweepZone;
|
||||
ActiveThreadData<mozilla::Maybe<AtomSet::Enum>> maybeAtomsToSweep;
|
||||
ActiveThreadOrGCTaskData<JS::detail::WeakCacheBase*> sweepCache;
|
||||
ActiveThreadData<bool> abortSweepAfterCurrentGroup;
|
||||
MainThreadData<JS::Zone*> sweepGroups;
|
||||
MainThreadOrGCTaskData<JS::Zone*> currentSweepGroup;
|
||||
MainThreadData<UniquePtr<SweepAction<GCRuntime*, FreeOp*, SliceBudget&>>> sweepActions;
|
||||
MainThreadOrGCTaskData<JS::Zone*> sweepZone;
|
||||
MainThreadData<mozilla::Maybe<AtomSet::Enum>> maybeAtomsToSweep;
|
||||
MainThreadOrGCTaskData<JS::detail::WeakCacheBase*> sweepCache;
|
||||
MainThreadData<bool> abortSweepAfterCurrentGroup;
|
||||
|
||||
friend class SweepGroupsIter;
|
||||
friend class WeakCacheSweepIterator;
|
||||
|
@ -836,12 +838,12 @@ class GCRuntime
|
|||
/*
|
||||
* Incremental compacting state.
|
||||
*/
|
||||
ActiveThreadData<bool> startedCompacting;
|
||||
ActiveThreadData<ZoneList> zonesToMaybeCompact;
|
||||
ActiveThreadData<Arena*> relocatedArenasToRelease;
|
||||
MainThreadData<bool> startedCompacting;
|
||||
MainThreadData<ZoneList> zonesToMaybeCompact;
|
||||
MainThreadData<Arena*> relocatedArenasToRelease;
|
||||
|
||||
#ifdef JS_GC_ZEAL
|
||||
ActiveThreadData<MarkingValidator*> markingValidator;
|
||||
MainThreadData<MarkingValidator*> markingValidator;
|
||||
#endif
|
||||
|
||||
/*
|
||||
|
@ -850,13 +852,13 @@ class GCRuntime
|
|||
* JSGC_SLICE_TIME_BUDGET
|
||||
* pref: javascript.options.mem.gc_incremental_slice_ms,
|
||||
*/
|
||||
ActiveThreadData<int64_t> defaultTimeBudget_;
|
||||
MainThreadData<int64_t> defaultTimeBudget_;
|
||||
|
||||
/*
|
||||
* We disable incremental GC if we encounter a Class with a trace hook
|
||||
* that does not implement write barriers.
|
||||
*/
|
||||
ActiveThreadData<bool> incrementalAllowed;
|
||||
MainThreadData<bool> incrementalAllowed;
|
||||
|
||||
/*
|
||||
* Whether compacting GC can is enabled globally.
|
||||
|
@ -864,9 +866,9 @@ class GCRuntime
|
|||
* JSGC_COMPACTING_ENABLED
|
||||
* pref: javascript.options.mem.gc_compacting
|
||||
*/
|
||||
ActiveThreadData<bool> compactingEnabled;
|
||||
MainThreadData<bool> compactingEnabled;
|
||||
|
||||
ActiveThreadData<bool> rootsRemoved;
|
||||
MainThreadData<bool> rootsRemoved;
|
||||
|
||||
/*
|
||||
* These options control the zealousness of the GC. At every allocation,
|
||||
|
@ -894,18 +896,20 @@ class GCRuntime
|
|||
* zeal_ value 14 performs periodic shrinking collections.
|
||||
*/
|
||||
#ifdef JS_GC_ZEAL
|
||||
ActiveThreadData<uint32_t> zealModeBits;
|
||||
ActiveThreadData<int> zealFrequency;
|
||||
ActiveThreadData<int> nextScheduled;
|
||||
ActiveThreadData<bool> deterministicOnly;
|
||||
ActiveThreadData<int> incrementalLimit;
|
||||
static_assert(size_t(ZealMode::Count) <= 32,
|
||||
"Too many zeal modes to store in a uint32_t");
|
||||
MainThreadData<uint32_t> zealModeBits;
|
||||
MainThreadData<int> zealFrequency;
|
||||
MainThreadData<int> nextScheduled;
|
||||
MainThreadData<bool> deterministicOnly;
|
||||
MainThreadData<int> incrementalLimit;
|
||||
|
||||
ActiveThreadData<Vector<JSObject*, 0, SystemAllocPolicy>> selectedForMarking;
|
||||
MainThreadData<Vector<JSObject*, 0, SystemAllocPolicy>> selectedForMarking;
|
||||
#endif
|
||||
|
||||
ActiveThreadData<bool> fullCompartmentChecks;
|
||||
MainThreadData<bool> fullCompartmentChecks;
|
||||
|
||||
ActiveThreadData<uint32_t> gcCallbackDepth;
|
||||
MainThreadData<uint32_t> gcCallbackDepth;
|
||||
|
||||
Callback<JSGCCallback> gcCallback;
|
||||
Callback<JS::DoCycleCollectionCallback> gcDoCycleCollectionCallback;
|
||||
|
@ -926,10 +930,10 @@ class GCRuntime
|
|||
Callback<JSTraceDataOp> grayRootTracer;
|
||||
|
||||
/* Always preserve JIT code during GCs, for testing. */
|
||||
ActiveThreadData<bool> alwaysPreserveCode;
|
||||
MainThreadData<bool> alwaysPreserveCode;
|
||||
|
||||
#ifdef DEBUG
|
||||
ActiveThreadData<bool> arenasEmptyAtShutdown;
|
||||
MainThreadData<bool> arenasEmptyAtShutdown;
|
||||
#endif
|
||||
|
||||
/* Synchronize GC heap access among GC helper threads and active threads. */
|
||||
|
@ -946,18 +950,18 @@ class GCRuntime
|
|||
* During incremental sweeping, this field temporarily holds the arenas of
|
||||
* the current AllocKind being swept in order of increasing free space.
|
||||
*/
|
||||
ActiveThreadData<SortedArenaList> incrementalSweepList;
|
||||
MainThreadData<SortedArenaList> incrementalSweepList;
|
||||
|
||||
private:
|
||||
ActiveThreadData<Nursery> nursery_;
|
||||
ActiveThreadData<gc::StoreBuffer> storeBuffer_;
|
||||
MainThreadData<Nursery> nursery_;
|
||||
MainThreadData<gc::StoreBuffer> storeBuffer_;
|
||||
public:
|
||||
Nursery& nursery() { return nursery_.ref(); }
|
||||
gc::StoreBuffer& storeBuffer() { return storeBuffer_.ref(); }
|
||||
|
||||
// Free LIFO blocks are transferred to this allocator before being freed
|
||||
// after minor GC.
|
||||
ActiveThreadData<LifoAlloc> blocksToFreeAfterMinorGC;
|
||||
MainThreadData<LifoAlloc> blocksToFreeAfterMinorGC;
|
||||
|
||||
const void* addressOfNurseryPosition() {
|
||||
return nursery_.refNoCheck().addressOfPosition();
|
||||
|
@ -1024,11 +1028,9 @@ GCRuntime::needZealousGC() {
|
|||
if (nextScheduled > 0 && --nextScheduled == 0) {
|
||||
if (hasZealMode(ZealMode::Alloc) ||
|
||||
hasZealMode(ZealMode::GenerationalGC) ||
|
||||
hasZealMode(ZealMode::IncrementalRootsThenFinish) ||
|
||||
hasZealMode(ZealMode::IncrementalMarkAllThenFinish) ||
|
||||
hasZealMode(ZealMode::IncrementalMultipleSlices) ||
|
||||
hasZealMode(ZealMode::Compact) ||
|
||||
hasZealMode(ZealMode::IncrementalSweepThenFinish))
|
||||
hasIncrementalTwoSliceZealMode())
|
||||
{
|
||||
nextScheduled = zealFrequency;
|
||||
}
|
||||
|
@ -1036,11 +1038,25 @@ GCRuntime::needZealousGC() {
|
|||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
inline bool
|
||||
GCRuntime::hasIncrementalTwoSliceZealMode() {
|
||||
return hasZealMode(ZealMode::YieldBeforeMarking) ||
|
||||
hasZealMode(ZealMode::YieldBeforeSweeping) ||
|
||||
hasZealMode(ZealMode::YieldBeforeSweepingAtoms) ||
|
||||
hasZealMode(ZealMode::YieldBeforeSweepingCaches) ||
|
||||
hasZealMode(ZealMode::YieldBeforeSweepingTypes) ||
|
||||
hasZealMode(ZealMode::YieldBeforeSweepingObjects) ||
|
||||
hasZealMode(ZealMode::YieldBeforeSweepingNonObjects) ||
|
||||
hasZealMode(ZealMode::YieldBeforeSweepingShapeTrees);
|
||||
}
|
||||
|
||||
#else
|
||||
inline bool GCRuntime::hasZealMode(ZealMode mode) { return false; }
|
||||
inline void GCRuntime::clearZealMode(ZealMode mode) { }
|
||||
inline bool GCRuntime::upcomingZealousGC() { return false; }
|
||||
inline bool GCRuntime::needZealousGC() { return false; }
|
||||
inline bool GCRuntime::hasIncrementalTwoSliceZealMode() { return false; }
|
||||
#endif
|
||||
|
||||
} /* namespace gc */
|
||||
|
|
|
@ -342,7 +342,7 @@ class GCSchedulingTunables
|
|||
*
|
||||
* Maximum nursery size for each runtime.
|
||||
*/
|
||||
ActiveThreadData<size_t> gcMaxNurseryBytes_;
|
||||
MainThreadData<size_t> gcMaxNurseryBytes_;
|
||||
|
||||
/*
|
||||
* JSGC_ALLOCATION_THRESHOLD
|
||||
|
@ -351,7 +351,7 @@ class GCSchedulingTunables
|
|||
* usage.gcBytes() surpasses threshold.gcTriggerBytes() for a zone, the
|
||||
* zone may be scheduled for a GC, depending on the exact circumstances.
|
||||
*/
|
||||
ActiveThreadOrGCTaskData<size_t> gcZoneAllocThresholdBase_;
|
||||
MainThreadOrGCTaskData<size_t> gcZoneAllocThresholdBase_;
|
||||
|
||||
/*
|
||||
* JSGC_ALLOCATION_THRESHOLD_FACTOR
|
||||
|
@ -381,7 +381,7 @@ class GCSchedulingTunables
|
|||
* Totally disables |highFrequencyGC|, the HeapGrowthFactor, and other
|
||||
* tunables that make GC non-deterministic.
|
||||
*/
|
||||
ActiveThreadData<bool> dynamicHeapGrowthEnabled_;
|
||||
MainThreadData<bool> dynamicHeapGrowthEnabled_;
|
||||
|
||||
/*
|
||||
* JSGC_HIGH_FREQUENCY_TIME_LIMIT
|
||||
|
@ -389,7 +389,7 @@ class GCSchedulingTunables
|
|||
* We enter high-frequency mode if we GC a twice within this many
|
||||
* microseconds. This value is stored directly in microseconds.
|
||||
*/
|
||||
ActiveThreadData<uint64_t> highFrequencyThresholdUsec_;
|
||||
MainThreadData<uint64_t> highFrequencyThresholdUsec_;
|
||||
|
||||
/*
|
||||
* JSGC_HIGH_FREQUENCY_LOW_LIMIT
|
||||
|
@ -400,10 +400,10 @@ class GCSchedulingTunables
|
|||
* When in the |highFrequencyGC| mode, these parameterize the per-zone
|
||||
* "HeapGrowthFactor" computation.
|
||||
*/
|
||||
ActiveThreadData<uint64_t> highFrequencyLowLimitBytes_;
|
||||
ActiveThreadData<uint64_t> highFrequencyHighLimitBytes_;
|
||||
ActiveThreadData<double> highFrequencyHeapGrowthMax_;
|
||||
ActiveThreadData<double> highFrequencyHeapGrowthMin_;
|
||||
MainThreadData<uint64_t> highFrequencyLowLimitBytes_;
|
||||
MainThreadData<uint64_t> highFrequencyHighLimitBytes_;
|
||||
MainThreadData<double> highFrequencyHeapGrowthMax_;
|
||||
MainThreadData<double> highFrequencyHeapGrowthMin_;
|
||||
|
||||
/*
|
||||
* JSGC_LOW_FREQUENCY_HEAP_GROWTH
|
||||
|
@ -411,14 +411,14 @@ class GCSchedulingTunables
|
|||
* When not in |highFrequencyGC| mode, this is the global (stored per-zone)
|
||||
* "HeapGrowthFactor".
|
||||
*/
|
||||
ActiveThreadData<double> lowFrequencyHeapGrowth_;
|
||||
MainThreadData<double> lowFrequencyHeapGrowth_;
|
||||
|
||||
/*
|
||||
* JSGC_DYNAMIC_MARK_SLICE
|
||||
*
|
||||
* Doubles the length of IGC slices when in the |highFrequencyGC| mode.
|
||||
*/
|
||||
ActiveThreadData<bool> dynamicMarkSliceEnabled_;
|
||||
MainThreadData<bool> dynamicMarkSliceEnabled_;
|
||||
|
||||
/*
|
||||
* JSGC_MIN_EMPTY_CHUNK_COUNT
|
||||
|
@ -473,7 +473,7 @@ class GCSchedulingState
|
|||
* growth factor is a measure of how large (as a percentage of the last GC)
|
||||
* the heap is allowed to grow before we try to schedule another GC.
|
||||
*/
|
||||
ActiveThreadData<bool> inHighFrequencyGCMode_;
|
||||
MainThreadData<bool> inHighFrequencyGCMode_;
|
||||
|
||||
public:
|
||||
GCSchedulingState()
|
||||
|
@ -500,7 +500,7 @@ class MemoryCounter
|
|||
size_t maxBytes_;
|
||||
|
||||
// The counter value at the start of a GC.
|
||||
ActiveThreadData<size_t> bytesAtStartOfGC_;
|
||||
MainThreadData<size_t> bytesAtStartOfGC_;
|
||||
|
||||
// Which kind of GC has been triggered if any.
|
||||
mozilla::Atomic<TriggerKind, mozilla::ReleaseAcquire> triggered_;
|
||||
|
|
|
@ -307,7 +307,7 @@ struct Zone : public JS::shadow::Zone,
|
|||
|
||||
private:
|
||||
// The set of compartments in this zone.
|
||||
js::ActiveThreadOrGCTaskData<CompartmentVector> compartments_;
|
||||
js::MainThreadOrGCTaskData<CompartmentVector> compartments_;
|
||||
public:
|
||||
CompartmentVector& compartments() { return compartments_.ref(); }
|
||||
|
||||
|
@ -349,7 +349,7 @@ struct Zone : public JS::shadow::Zone,
|
|||
//
|
||||
// This is used during GC while calculating sweep groups to record edges
|
||||
// that can't be determined by examining this zone by itself.
|
||||
js::ActiveThreadData<ZoneSet> gcSweepGroupEdges_;
|
||||
js::MainThreadData<ZoneSet> gcSweepGroupEdges_;
|
||||
|
||||
public:
|
||||
ZoneSet& gcSweepGroupEdges() { return gcSweepGroupEdges_.ref(); }
|
||||
|
@ -705,15 +705,15 @@ struct Zone : public JS::shadow::Zone,
|
|||
private:
|
||||
js::ZoneData<js::jit::JitZone*> jitZone_;
|
||||
|
||||
js::ActiveThreadData<bool> gcScheduled_;
|
||||
js::ActiveThreadData<bool> gcScheduledSaved_;
|
||||
js::MainThreadData<bool> gcScheduled_;
|
||||
js::MainThreadData<bool> gcScheduledSaved_;
|
||||
js::ZoneData<bool> gcPreserveCode_;
|
||||
js::ZoneData<bool> keepShapeTables_;
|
||||
|
||||
// Allow zones to be linked into a list
|
||||
friend class js::gc::ZoneList;
|
||||
static Zone * const NotOnList;
|
||||
js::ActiveThreadOrGCTaskData<Zone*> listNext_;
|
||||
js::MainThreadOrGCTaskData<Zone*> listNext_;
|
||||
bool isOnList() const;
|
||||
Zone* nextZone() const;
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
load(libdir + "../../tests/non262/shell.js");
|
||||
|
||||
if (typeof assertWarning === 'undefined') {
|
||||
var assertWarning = function assertWarning(f, errorClass, msg) {
|
||||
var assertWarning = function assertWarning(f, pattern) {
|
||||
var hadWerror = options().split(",").indexOf("werror") !== -1;
|
||||
|
||||
// Ensure the "werror" option is disabled.
|
||||
|
@ -19,10 +19,6 @@ if (typeof assertWarning === 'undefined') {
|
|||
if (hadWerror)
|
||||
options("werror");
|
||||
|
||||
// print() rather than throw a different exception value, in case
|
||||
// the caller wants exc.stack.
|
||||
if (msg)
|
||||
print("assertWarning: " + msg);
|
||||
print("assertWarning: Unexpected exception calling " + f +
|
||||
" with warnings-as-errors disabled");
|
||||
throw exc;
|
||||
|
@ -32,20 +28,21 @@ if (typeof assertWarning === 'undefined') {
|
|||
options("werror");
|
||||
|
||||
try {
|
||||
assertThrowsInstanceOf(f, errorClass, msg);
|
||||
f();
|
||||
} catch (exc) {
|
||||
if (msg)
|
||||
print("assertWarning: " + msg);
|
||||
throw exc;
|
||||
if (!String(exc).match(pattern))
|
||||
throw new Error(`assertWarning failed: "${exc}" does not match "${pattern}"`);
|
||||
return;
|
||||
} finally {
|
||||
if (!hadWerror)
|
||||
options("werror");
|
||||
}
|
||||
throw new Error("assertWarning failed: no warning");
|
||||
};
|
||||
}
|
||||
|
||||
if (typeof assertNoWarning === 'undefined') {
|
||||
var assertNoWarning = function assertWarning(f, msg) {
|
||||
var assertNoWarning = function assertNoWarning(f, msg) {
|
||||
// Ensure the "werror" option is enabled.
|
||||
var hadWerror = options().split(",").indexOf("werror") !== -1;
|
||||
if (!hadWerror)
|
||||
|
|
|
@ -56,11 +56,23 @@ while (gcstate() == "Finalize") { gcslice(1); }
|
|||
while (gcstate() == "Decommit") { gcslice(1); }
|
||||
assertEq(gcstate(), "NotActive");
|
||||
|
||||
// Zeal mode 17: Incremental GC in two slices:
|
||||
// 1) mark everything and start sweeping
|
||||
// 2) finish sweeping
|
||||
gczeal(17, 0);
|
||||
gcslice(1);
|
||||
assertEq(gcstate(), "Sweep");
|
||||
gcslice(1);
|
||||
assertEq(gcstate(), "NotActive");
|
||||
// Two-slice zeal modes that yield once during sweeping.
|
||||
for (let mode of [ 17, 19 ]) {
|
||||
print(mode);
|
||||
gczeal(mode, 0);
|
||||
gcslice(1);
|
||||
assertEq(gcstate(), "Sweep");
|
||||
gcslice(1);
|
||||
assertEq(gcstate(), "NotActive");
|
||||
}
|
||||
|
||||
// Two-slice zeal modes that yield per-zone during sweeping.
|
||||
const sweepingZealModes = [ 20, 21, 22, 23 ];
|
||||
for (let mode of sweepingZealModes) {
|
||||
print(mode);
|
||||
gczeal(mode, 0);
|
||||
gcslice(1);
|
||||
while (gcstate() === "Sweep")
|
||||
gcslice(1);
|
||||
assertEq(gcstate(), "NotActive");
|
||||
}
|
||||
|
|
|
@ -232,34 +232,41 @@ function elemSection(elemArrays) {
|
|||
return { name: elemId, body };
|
||||
}
|
||||
|
||||
function nameSection(moduleName, funcNames) {
|
||||
function moduleNameSubsection(moduleName) {
|
||||
var body = [];
|
||||
body.push(...varU32(nameTypeModule));
|
||||
|
||||
var subsection = encodedString(moduleName);
|
||||
body.push(...varU32(subsection.length));
|
||||
body.push(...subsection);
|
||||
|
||||
return body;
|
||||
}
|
||||
|
||||
function funcNameSubsection(funcNames) {
|
||||
var body = [];
|
||||
body.push(...varU32(nameTypeFunction));
|
||||
|
||||
var subsection = varU32(funcNames.length);
|
||||
|
||||
var funcIndex = 0;
|
||||
for (let f of funcNames) {
|
||||
subsection.push(...varU32(f.index ? f.index : funcIndex));
|
||||
subsection.push(...encodedString(f.name, f.nameLen));
|
||||
funcIndex++;
|
||||
}
|
||||
|
||||
body.push(...varU32(subsection.length));
|
||||
body.push(...subsection);
|
||||
return body;
|
||||
}
|
||||
|
||||
function nameSection(subsections) {
|
||||
var body = [];
|
||||
body.push(...string(nameName));
|
||||
|
||||
if (moduleName) {
|
||||
body.push(...varU32(nameTypeModule));
|
||||
|
||||
var subsection = encodedString(moduleName);
|
||||
|
||||
body.push(...varU32(subsection.length));
|
||||
body.push(...subsection);
|
||||
}
|
||||
|
||||
if (funcNames) {
|
||||
body.push(...varU32(nameTypeFunction));
|
||||
|
||||
var subsection = varU32(funcNames.length);
|
||||
|
||||
var funcIndex = 0;
|
||||
for (let f of funcNames) {
|
||||
subsection.push(...varU32(f.index ? f.index : funcIndex));
|
||||
subsection.push(...encodedString(f.name, f.nameLen));
|
||||
funcIndex++;
|
||||
}
|
||||
|
||||
body.push(...varU32(subsection.length));
|
||||
body.push(...subsection);
|
||||
}
|
||||
for (let ss of subsections)
|
||||
body.push(...ss);
|
||||
|
||||
return { name: userDefinedId, body };
|
||||
}
|
||||
|
@ -395,7 +402,7 @@ wasmEval(moduleWithSections([tooBigNameSection]));
|
|||
var customDefSec = customSection("wee", 42, 13);
|
||||
var declSec = declSection([0]);
|
||||
var bodySec = bodySection([v2vBody]);
|
||||
var nameSec = nameSection(null, [{name:'hi'}]);
|
||||
var nameSec = nameSection([funcNameSubsection([{name:'hi'}])]);
|
||||
wasmEval(moduleWithSections([customDefSec, v2vSigSection, declSec, bodySec]));
|
||||
wasmEval(moduleWithSections([v2vSigSection, customDefSec, declSec, bodySec]));
|
||||
wasmEval(moduleWithSections([v2vSigSection, declSec, customDefSec, bodySec]));
|
||||
|
@ -432,6 +439,26 @@ var arr = Module.customSections(m, "name");
|
|||
assertEq(arr.length, 1);
|
||||
assertEq(arr[0].byteLength, nameSec.body.length - 5 /* 4name */);
|
||||
|
||||
// Test name/custom section warnings:
|
||||
const nameWarning = /validated with warning.*'name' custom section/;
|
||||
const okNameSec = nameSection([]);
|
||||
assertNoWarning(() => wasmEval(moduleWithSections([v2vSigSection, declSec, bodySec, okNameSec])));
|
||||
const badNameSec1 = nameSection([]);
|
||||
badNameSec1.body.push(1);
|
||||
assertWarning(() => wasmEval(moduleWithSections([v2vSigSection, declSec, bodySec, badNameSec1])), nameWarning);
|
||||
const badNameSec2 = nameSection([funcNameSubsection([{name:'blah'}])]);
|
||||
badNameSec2.body.push(100, 20, 42, 83);
|
||||
assertWarning(() => wasmEval(moduleWithSections([v2vSigSection, declSec, bodySec, badNameSec2])), nameWarning);
|
||||
const badNameSec3 = nameSection([funcNameSubsection([{name:'blah'}])]);
|
||||
badNameSec3.body.pop();
|
||||
assertWarning(() => wasmEval(moduleWithSections([v2vSigSection, declSec, bodySec, badNameSec3])), nameWarning);
|
||||
assertNoWarning(() => wasmEval(moduleWithSections([nameSection([moduleNameSubsection('hi')])])));
|
||||
assertWarning(() => wasmEval(moduleWithSections([nameSection([moduleNameSubsection('hi'), moduleNameSubsection('boo')])])), nameWarning);
|
||||
// Unknown name subsection
|
||||
assertNoWarning(() => wasmEval(moduleWithSections([nameSection([moduleNameSubsection('hi'), [4, 0]])])));
|
||||
assertWarning(() => wasmEval(moduleWithSections([nameSection([moduleNameSubsection('hi'), [4, 1]])])), nameWarning);
|
||||
assertNoWarning(() => wasmEval(moduleWithSections([nameSection([moduleNameSubsection('hi'), [4, 1, 42]])])));
|
||||
|
||||
// Diagnose nonstandard block signature types.
|
||||
for (var bad of [0xff, 0, 1, 0x3f])
|
||||
assertErrorMessage(() => wasmEval(moduleWithSections([sigSection([v2vSig]), declSection([0]), bodySection([funcBody({locals:[], body:[BlockCode, bad, EndCode]})])])), CompileError, /invalid inline block type/);
|
||||
|
@ -499,8 +526,14 @@ function runStackTraceTest(moduleName, funcNames, expectedName) {
|
|||
customSection("whoa"),
|
||||
customSection("wee", 42),
|
||||
];
|
||||
if (moduleName || funcNames)
|
||||
sections.push(nameSection(moduleName, funcNames));
|
||||
if (moduleName || funcNames) {
|
||||
var subsections = [];
|
||||
if (moduleName)
|
||||
subsections.push(moduleNameSubsection(moduleName));
|
||||
if (funcNames)
|
||||
subsections.push(funcNameSubsection(funcNames));
|
||||
sections.push(nameSection(subsections));
|
||||
}
|
||||
sections.push(customSection("yay", 13));
|
||||
|
||||
var result = "";
|
||||
|
|
|
@ -62,9 +62,9 @@ class JitRuntime
|
|||
friend class JitCompartment;
|
||||
|
||||
// Executable allocator for all code except wasm code.
|
||||
ActiveThreadData<ExecutableAllocator> execAlloc_;
|
||||
MainThreadData<ExecutableAllocator> execAlloc_;
|
||||
|
||||
ActiveThreadData<uint64_t> nextCompilationId_;
|
||||
MainThreadData<uint64_t> nextCompilationId_;
|
||||
|
||||
// Shared exception-handler tail.
|
||||
ExclusiveAccessLockWriteOnceData<uint32_t> exceptionTailOffset_;
|
||||
|
@ -138,7 +138,7 @@ class JitRuntime
|
|||
#ifdef DEBUG
|
||||
// The number of possible bailing places encounters before forcefully bailing
|
||||
// in that place. Zero means inactive.
|
||||
ActiveThreadData<uint32_t> ionBailAfter_;
|
||||
MainThreadData<uint32_t> ionBailAfter_;
|
||||
#endif
|
||||
|
||||
// Number of Ion compilations which were finished off thread and are
|
||||
|
@ -148,8 +148,8 @@ class JitRuntime
|
|||
|
||||
// List of Ion compilation waiting to get linked.
|
||||
using IonBuilderList = mozilla::LinkedList<js::jit::IonBuilder>;
|
||||
ActiveThreadData<IonBuilderList> ionLazyLinkList_;
|
||||
ActiveThreadData<size_t> ionLazyLinkListSize_;
|
||||
MainThreadData<IonBuilderList> ionLazyLinkList_;
|
||||
MainThreadData<size_t> ionLazyLinkListSize_;
|
||||
|
||||
private:
|
||||
void generateLazyLinkStub(MacroAssembler& masm);
|
||||
|
|
|
@ -357,6 +357,7 @@ MSG_DEF(JSMSG_USE_ASM_LINK_FAIL, 1, JSEXN_TYPEERR, "asm.js link error: {0}
|
|||
MSG_DEF(JSMSG_USE_ASM_TYPE_OK, 1, JSEXN_WARN, "Successfully compiled asm.js code ({0})")
|
||||
|
||||
// wasm
|
||||
MSG_DEF(JSMSG_WASM_COMPILE_WARNING, 1, JSEXN_WARN, "WebAssembly module validated with warning: {0}")
|
||||
MSG_DEF(JSMSG_WASM_COMPILE_ERROR, 1, JSEXN_WASMCOMPILEERROR, "{0}")
|
||||
MSG_DEF(JSMSG_WASM_NO_SHMEM_COMPILE, 0, JSEXN_WASMCOMPILEERROR, "shared memory is disabled")
|
||||
MSG_DEF(JSMSG_WASM_BAD_IMPORT_TYPE, 2, JSEXN_WASMLINKERROR, "import object field '{0}' is not a {1}")
|
||||
|
|
|
@ -111,7 +111,7 @@ BEGIN_TEST(testGCFinalizeCallback)
|
|||
while (cx->runtime()->gc.isIncrementalGCInProgress())
|
||||
cx->runtime()->gc.debugGCSlice(budget);
|
||||
CHECK(!cx->runtime()->gc.isIncrementalGCInProgress());
|
||||
CHECK(checkMultipleGroups());
|
||||
CHECK(checkSingleGroup());
|
||||
CHECK(checkFinalizeStatus());
|
||||
|
||||
JS_SetGCZeal(cx, 0, 0);
|
||||
|
|
|
@ -1339,6 +1339,20 @@ JS::detail::ComputeThis(JSContext* cx, Value* vp, MutableHandleObject thisObject
|
|||
return true;
|
||||
}
|
||||
|
||||
static bool gProfileTimelineRecordingEnabled = false;
|
||||
|
||||
JS_PUBLIC_API(void)
|
||||
JS::SetProfileTimelineRecordingEnabled(bool enabled)
|
||||
{
|
||||
gProfileTimelineRecordingEnabled = enabled;
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(bool)
|
||||
JS::IsProfileTimelineRecordingEnabled()
|
||||
{
|
||||
return gProfileTimelineRecordingEnabled;
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(void*)
|
||||
JS_malloc(JSContext* cx, size_t nbytes)
|
||||
{
|
||||
|
@ -1640,7 +1654,7 @@ JS_SetNativeStackQuota(JSContext* cx, size_t systemCodeStackSize, size_t trusted
|
|||
SetNativeStackQuotaAndLimit(cx, JS::StackForTrustedScript, trustedScriptStackSize);
|
||||
SetNativeStackQuotaAndLimit(cx, JS::StackForUntrustedScript, untrustedScriptStackSize);
|
||||
|
||||
if (cx->isCooperativelyScheduled())
|
||||
if (cx->isMainThreadContext())
|
||||
cx->initJitStackLimit();
|
||||
}
|
||||
|
||||
|
@ -5205,7 +5219,8 @@ JS::RejectPromise(JSContext* cx, JS::HandleObject promiseObj, JS::HandleValue re
|
|||
static bool
|
||||
CallOriginalPromiseThenImpl(JSContext* cx, JS::HandleObject promiseObj,
|
||||
JS::HandleObject onResolvedObj_, JS::HandleObject onRejectedObj_,
|
||||
JS::MutableHandleObject resultObj, bool createDependent)
|
||||
JS::MutableHandleObject resultObj,
|
||||
CreateDependentPromise createDependent)
|
||||
{
|
||||
AssertHeapIsIdle();
|
||||
CHECK_REQUEST(cx);
|
||||
|
@ -5254,8 +5269,11 @@ JS::CallOriginalPromiseThen(JSContext* cx, JS::HandleObject promiseObj,
|
|||
JS::HandleObject onResolvedObj, JS::HandleObject onRejectedObj)
|
||||
{
|
||||
RootedObject resultPromise(cx);
|
||||
if (!CallOriginalPromiseThenImpl(cx, promiseObj, onResolvedObj, onRejectedObj, &resultPromise, true))
|
||||
if (!CallOriginalPromiseThenImpl(cx, promiseObj, onResolvedObj, onRejectedObj, &resultPromise,
|
||||
CreateDependentPromise::Always))
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
return resultPromise;
|
||||
}
|
||||
|
||||
|
@ -5264,7 +5282,8 @@ JS::AddPromiseReactions(JSContext* cx, JS::HandleObject promiseObj,
|
|||
JS::HandleObject onResolvedObj, JS::HandleObject onRejectedObj)
|
||||
{
|
||||
RootedObject resultPromise(cx);
|
||||
bool result = CallOriginalPromiseThenImpl(cx, promiseObj, onResolvedObj, onRejectedObj, &resultPromise, false);
|
||||
bool result = CallOriginalPromiseThenImpl(cx, promiseObj, onResolvedObj, onRejectedObj,
|
||||
&resultPromise, CreateDependentPromise::Never);
|
||||
MOZ_ASSERT(!resultPromise);
|
||||
return result;
|
||||
}
|
||||
|
|
|
@ -1502,6 +1502,22 @@ JS_DefineProfilingFunctions(JSContext* cx, JS::HandleObject obj);
|
|||
extern JS_PUBLIC_API(bool)
|
||||
JS_DefineDebuggerObject(JSContext* cx, JS::HandleObject obj);
|
||||
|
||||
namespace JS {
|
||||
|
||||
/**
|
||||
* Tell JS engine whether Profile Timeline Recording is enabled or not.
|
||||
* If Profile Timeline Recording is enabled, data shown there like stack won't
|
||||
* be optimized out.
|
||||
* This is global state and not associated with specific runtime or context.
|
||||
*/
|
||||
extern JS_PUBLIC_API(void)
|
||||
SetProfileTimelineRecordingEnabled(bool enabled);
|
||||
|
||||
extern JS_PUBLIC_API(bool)
|
||||
IsProfileTimelineRecordingEnabled();
|
||||
|
||||
} // namespace JS
|
||||
|
||||
#ifdef JS_HAS_CTYPES
|
||||
/**
|
||||
* Initialize the 'ctypes' object on a global variable 'obj'. The 'ctypes'
|
||||
|
|
|
@ -431,7 +431,7 @@ ForgetSourceHook(JSContext* cx);
|
|||
* right time(s), such as after evaluation of a script has run to completion.
|
||||
*/
|
||||
extern JS_FRIEND_API(bool)
|
||||
UseInternalJobQueues(JSContext* cx, bool cooperative = false);
|
||||
UseInternalJobQueues(JSContext* cx);
|
||||
|
||||
/**
|
||||
* Enqueue |job| on the internal job queue.
|
||||
|
|
|
@ -402,7 +402,6 @@ UNIFIED_SOURCES += [
|
|||
'vm/Xdr.cpp',
|
||||
'wasm/AsmJS.cpp',
|
||||
'wasm/WasmBaselineCompile.cpp',
|
||||
'wasm/WasmBinaryIterator.cpp',
|
||||
'wasm/WasmBinaryToAST.cpp',
|
||||
'wasm/WasmBinaryToText.cpp',
|
||||
'wasm/WasmBuiltins.cpp',
|
||||
|
@ -416,6 +415,7 @@ UNIFIED_SOURCES += [
|
|||
'wasm/WasmIonCompile.cpp',
|
||||
'wasm/WasmJS.cpp',
|
||||
'wasm/WasmModule.cpp',
|
||||
'wasm/WasmOpIter.cpp',
|
||||
'wasm/WasmProcess.cpp',
|
||||
'wasm/WasmSignalHandlers.cpp',
|
||||
'wasm/WasmStubs.cpp',
|
||||
|
|
|
@ -3548,34 +3548,22 @@ WorkerMain(void* arg)
|
|||
js_delete(input);
|
||||
});
|
||||
|
||||
if (input->parentRuntime)
|
||||
sc->isWorker = true;
|
||||
sc->isWorker = true;
|
||||
JS_SetContextPrivate(cx, sc);
|
||||
SetWorkerContextOptions(cx);
|
||||
JS::SetBuildIdOp(cx, ShellBuildId);
|
||||
|
||||
Maybe<EnvironmentPreparer> environmentPreparer;
|
||||
if (input->parentRuntime) {
|
||||
JS_SetFutexCanWait(cx);
|
||||
JS::SetWarningReporter(cx, WarningReporter);
|
||||
js::SetPreserveWrapperCallback(cx, DummyPreserveWrapperCallback);
|
||||
JS_InitDestroyPrincipalsCallback(cx, ShellPrincipals::destroy);
|
||||
JS_SetFutexCanWait(cx);
|
||||
JS::SetWarningReporter(cx, WarningReporter);
|
||||
js::SetPreserveWrapperCallback(cx, DummyPreserveWrapperCallback);
|
||||
JS_InitDestroyPrincipalsCallback(cx, ShellPrincipals::destroy);
|
||||
|
||||
js::UseInternalJobQueues(cx);
|
||||
js::UseInternalJobQueues(cx);
|
||||
|
||||
if (!JS::InitSelfHostedCode(cx))
|
||||
return;
|
||||
if (!JS::InitSelfHostedCode(cx))
|
||||
return;
|
||||
|
||||
environmentPreparer.emplace(cx);
|
||||
} else {
|
||||
JS_AddInterruptCallback(cx, ShellInterruptCallback);
|
||||
|
||||
js::UseInternalJobQueues(cx, /* cooperative = */true);
|
||||
|
||||
// The Gecko Profiler requires that all cooperating contexts have
|
||||
// profiling stacks installed.
|
||||
MOZ_ALWAYS_TRUE(EnsureGeckoProfilingStackInstalled(cx, sc));
|
||||
}
|
||||
EnvironmentPreparer environmentPreparer(cx);
|
||||
|
||||
do {
|
||||
JSAutoRequest ar(cx);
|
||||
|
@ -8627,11 +8615,10 @@ SetWorkerContextOptions(JSContext* cx)
|
|||
|
||||
#ifdef JS_GC_ZEAL
|
||||
if (gZealBits && gZealFrequency) {
|
||||
#define ZEAL_MODE(_, value) \
|
||||
if (gZealBits & (1 << value)) \
|
||||
cx->runtime()->gc.setZeal(value, gZealFrequency);
|
||||
JS_FOR_EACH_ZEAL_MODE(ZEAL_MODE)
|
||||
#undef ZEAL_MODE
|
||||
for (size_t i = 0; i < size_t(gc::ZealMode::Count); i++) {
|
||||
if (gZealBits & (1 << i))
|
||||
cx->runtime()->gc.setZeal(i, gZealFrequency);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -8863,6 +8850,8 @@ main(int argc, char** argv, char** envp)
|
|||
"instantiation on completion of tier2")
|
||||
#ifdef ENABLE_WASM_GC
|
||||
|| !op.addBoolOption('\0', "wasm-gc", "Enable wasm GC features")
|
||||
#else
|
||||
|| !op.addBoolOption('\0', "wasm-gc", "No-op")
|
||||
#endif
|
||||
|| !op.addBoolOption('\0', "no-native-regexp", "Disable native regexp compilation")
|
||||
|| !op.addBoolOption('\0', "no-unboxed-objects", "Disable creating unboxed plain objects")
|
||||
|
|
|
@ -38,19 +38,14 @@ CheckThreadLocal::check() const
|
|||
{
|
||||
JSContext* cx = TlsContext.get();
|
||||
MOZ_ASSERT(cx);
|
||||
|
||||
// As for CheckZone, in a cooperatively scheduled runtime the active
|
||||
// thread is permitted access to thread local state for other suspended
|
||||
// threads in the same runtime.
|
||||
if (cx->isCooperativelyScheduled())
|
||||
MOZ_ASSERT(CurrentThreadCanAccessRuntime(cx->runtime()));
|
||||
else
|
||||
MOZ_ASSERT(id == ThisThread::GetId());
|
||||
MOZ_ASSERT_IF(cx->isMainThreadContext(),
|
||||
CurrentThreadCanAccessRuntime(cx->runtime()));
|
||||
MOZ_ASSERT(id == ThisThread::GetId());
|
||||
}
|
||||
|
||||
template <AllowedHelperThread Helper>
|
||||
void
|
||||
CheckActiveThread<Helper>::check() const
|
||||
CheckMainThread<Helper>::check() const
|
||||
{
|
||||
if (OnHelperThread<Helper>())
|
||||
return;
|
||||
|
@ -59,9 +54,9 @@ CheckActiveThread<Helper>::check() const
|
|||
MOZ_ASSERT(CurrentThreadCanAccessRuntime(cx->runtime()));
|
||||
}
|
||||
|
||||
template class CheckActiveThread<AllowedHelperThread::None>;
|
||||
template class CheckActiveThread<AllowedHelperThread::GCTask>;
|
||||
template class CheckActiveThread<AllowedHelperThread::IonCompile>;
|
||||
template class CheckMainThread<AllowedHelperThread::None>;
|
||||
template class CheckMainThread<AllowedHelperThread::GCTask>;
|
||||
template class CheckMainThread<AllowedHelperThread::IonCompile>;
|
||||
|
||||
template <AllowedHelperThread Helper>
|
||||
void
|
||||
|
|
|
@ -189,7 +189,7 @@ class CheckThreadLocal
|
|||
|
||||
// Data which may only be accessed by the thread on which it is created.
|
||||
template <typename T>
|
||||
using ThreadLocalData = ProtectedDataNoCheckArgs<CheckThreadLocal, T>;
|
||||
using ThreadData = ProtectedDataNoCheckArgs<CheckThreadLocal, T>;
|
||||
|
||||
// Enum describing which helper threads (GC tasks or Ion compilations) may
|
||||
// access data even though they do not have exclusive access to any zone.
|
||||
|
@ -202,26 +202,25 @@ enum class AllowedHelperThread
|
|||
};
|
||||
|
||||
template <AllowedHelperThread Helper>
|
||||
class CheckActiveThread
|
||||
class CheckMainThread
|
||||
{
|
||||
public:
|
||||
void check() const;
|
||||
};
|
||||
|
||||
// Data which may only be accessed by the runtime's cooperatively scheduled
|
||||
// active thread.
|
||||
// Data which may only be accessed by the runtime's main thread.
|
||||
template <typename T>
|
||||
using ActiveThreadData =
|
||||
ProtectedDataNoCheckArgs<CheckActiveThread<AllowedHelperThread::None>, T>;
|
||||
using MainThreadData =
|
||||
ProtectedDataNoCheckArgs<CheckMainThread<AllowedHelperThread::None>, T>;
|
||||
|
||||
// Data which may only be accessed by the runtime's cooperatively scheduled
|
||||
// active thread, or by various helper thread tasks.
|
||||
// Data which may only be accessed by the runtime's main thread or by various
|
||||
// helper thread tasks.
|
||||
template <typename T>
|
||||
using ActiveThreadOrGCTaskData =
|
||||
ProtectedDataNoCheckArgs<CheckActiveThread<AllowedHelperThread::GCTask>, T>;
|
||||
using MainThreadOrGCTaskData =
|
||||
ProtectedDataNoCheckArgs<CheckMainThread<AllowedHelperThread::GCTask>, T>;
|
||||
template <typename T>
|
||||
using ActiveThreadOrIonCompileData =
|
||||
ProtectedDataNoCheckArgs<CheckActiveThread<AllowedHelperThread::IonCompile>, T>;
|
||||
using MainThreadOrIonCompileData =
|
||||
ProtectedDataNoCheckArgs<CheckMainThread<AllowedHelperThread::IonCompile>, T>;
|
||||
|
||||
template <AllowedHelperThread Helper>
|
||||
class CheckZone
|
||||
|
|
|
@ -2224,7 +2224,7 @@ HelperThread::threadLoop()
|
|||
JSContext cx(nullptr, JS::ContextOptions());
|
||||
{
|
||||
AutoEnterOOMUnsafeRegion oomUnsafe;
|
||||
if (!cx.init(ContextKind::Background))
|
||||
if (!cx.init(ContextKind::HelperThread))
|
||||
oomUnsafe.crash("HelperThread cx.init()");
|
||||
}
|
||||
cx.setHelperThread(this);
|
||||
|
|
|
@ -100,7 +100,7 @@ bool
|
|||
JSContext::init(ContextKind kind)
|
||||
{
|
||||
// Skip most of the initialization if this thread will not be running JS.
|
||||
if (kind == ContextKind::Cooperative) {
|
||||
if (kind == ContextKind::MainThread) {
|
||||
if (!regexpStack.ref().init())
|
||||
return false;
|
||||
|
||||
|
@ -153,7 +153,7 @@ js::NewContext(uint32_t maxBytes, uint32_t maxNurseryBytes, JSRuntime* parentRun
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
if (!cx->init(ContextKind::Cooperative)) {
|
||||
if (!cx->init(ContextKind::MainThread)) {
|
||||
runtime->destroyRuntime();
|
||||
js_delete(cx);
|
||||
js_delete(runtime);
|
||||
|
@ -1071,11 +1071,11 @@ class MOZ_STACK_CLASS ReportExceptionClosure : public ScriptEnvironmentPreparer:
|
|||
} // anonymous namespace
|
||||
|
||||
JS_FRIEND_API(bool)
|
||||
js::UseInternalJobQueues(JSContext* cx, bool cooperative)
|
||||
js::UseInternalJobQueues(JSContext* cx)
|
||||
{
|
||||
// Internal job queue handling must be set up very early. Self-hosting
|
||||
// initialization is as good a marker for that as any.
|
||||
MOZ_RELEASE_ASSERT(cooperative || !cx->runtime()->hasInitializedSelfHosting(),
|
||||
MOZ_RELEASE_ASSERT(!cx->runtime()->hasInitializedSelfHosting(),
|
||||
"js::UseInternalJobQueues must be called early during runtime startup.");
|
||||
MOZ_ASSERT(!cx->jobQueue);
|
||||
auto* queue = js_new<PersistentRooted<JobQueue>>(cx, JobQueue(SystemAllocPolicy()));
|
||||
|
@ -1084,8 +1084,7 @@ js::UseInternalJobQueues(JSContext* cx, bool cooperative)
|
|||
|
||||
cx->jobQueue = queue;
|
||||
|
||||
if (!cooperative)
|
||||
cx->runtime()->offThreadPromiseState.ref().initInternalDispatchQueue();
|
||||
cx->runtime()->offThreadPromiseState.ref().initInternalDispatchQueue();
|
||||
MOZ_ASSERT(cx->runtime()->offThreadPromiseState.ref().initialized());
|
||||
|
||||
JS::SetEnqueuePromiseJobCallback(cx, InternalEnqueuePromiseJobCallback);
|
||||
|
@ -1218,7 +1217,7 @@ JSContext::alreadyReportedError()
|
|||
|
||||
JSContext::JSContext(JSRuntime* runtime, const JS::ContextOptions& options)
|
||||
: runtime_(runtime),
|
||||
kind_(ContextKind::Background),
|
||||
kind_(ContextKind::HelperThread),
|
||||
helperThread_(nullptr),
|
||||
options_(options),
|
||||
arenas_(nullptr),
|
||||
|
@ -1316,7 +1315,7 @@ JSContext::~JSContext()
|
|||
{
|
||||
// Clear the ContextKind first, so that ProtectedData checks will allow us to
|
||||
// destroy this context even if the runtime is already gone.
|
||||
kind_ = ContextKind::Background;
|
||||
kind_ = ContextKind::HelperThread;
|
||||
|
||||
/* Free the stuff hanging off of cx. */
|
||||
MOZ_ASSERT(!resolvingList);
|
||||
|
|
|
@ -80,8 +80,11 @@ extern MOZ_THREAD_LOCAL(JSContext*) TlsContext;
|
|||
|
||||
enum class ContextKind
|
||||
{
|
||||
Cooperative,
|
||||
Background
|
||||
// Context for the main thread of a JSRuntime.
|
||||
MainThread,
|
||||
|
||||
// Context for a helper thread.
|
||||
HelperThread
|
||||
};
|
||||
|
||||
#ifdef DEBUG
|
||||
|
@ -108,21 +111,21 @@ struct JSContext : public JS::RootingContext,
|
|||
js::WriteOnceData<js::ContextKind> kind_;
|
||||
|
||||
// The thread on which this context is running if this is not the main thread.
|
||||
js::ThreadLocalData<js::HelperThread*> helperThread_;
|
||||
js::ThreadData<js::HelperThread*> helperThread_;
|
||||
|
||||
friend class js::gc::AutoSuppressNurseryCellAlloc;
|
||||
js::ThreadLocalData<size_t> nurserySuppressions_;
|
||||
js::ThreadData<size_t> nurserySuppressions_;
|
||||
|
||||
js::ThreadLocalData<JS::ContextOptions> options_;
|
||||
js::ThreadData<JS::ContextOptions> options_;
|
||||
|
||||
js::ThreadLocalData<js::gc::ArenaLists*> arenas_;
|
||||
js::ThreadData<js::gc::ArenaLists*> arenas_;
|
||||
|
||||
public:
|
||||
// This is used by helper threads to change the runtime their context is
|
||||
// currently operating on.
|
||||
void setRuntime(JSRuntime* rt);
|
||||
|
||||
bool isCooperativelyScheduled() const { return kind_ == js::ContextKind::Cooperative; }
|
||||
bool isMainThreadContext() const { return kind_ == js::ContextKind::MainThread; }
|
||||
|
||||
inline js::gc::ArenaLists* arenas() const { return arenas_; }
|
||||
|
||||
|
@ -192,7 +195,7 @@ struct JSContext : public JS::RootingContext,
|
|||
* manually calling cx->enterCompartment/leaveCompartment.
|
||||
*/
|
||||
protected:
|
||||
js::ThreadLocalData<unsigned> enterCompartmentDepth_;
|
||||
js::ThreadData<unsigned> enterCompartmentDepth_;
|
||||
|
||||
inline void setCompartment(JSCompartment* comp,
|
||||
const js::AutoLockForExclusiveAccess* maybeLock = nullptr);
|
||||
|
@ -332,16 +335,16 @@ struct JSContext : public JS::RootingContext,
|
|||
* Points to the most recent JitActivation pushed on the thread.
|
||||
* See JitActivation constructor in vm/Stack.cpp
|
||||
*/
|
||||
js::ThreadLocalData<js::jit::JitActivation*> jitActivation;
|
||||
js::ThreadData<js::jit::JitActivation*> jitActivation;
|
||||
|
||||
// Information about the heap allocated backtrack stack used by RegExp JIT code.
|
||||
js::ThreadLocalData<js::irregexp::RegExpStack> regexpStack;
|
||||
js::ThreadData<js::irregexp::RegExpStack> regexpStack;
|
||||
|
||||
/*
|
||||
* Points to the most recent activation running on the thread.
|
||||
* See Activation comment in vm/Stack.h.
|
||||
*/
|
||||
js::ThreadLocalData<js::Activation*> activation_;
|
||||
js::ThreadData<js::Activation*> activation_;
|
||||
|
||||
/*
|
||||
* Points to the most recent profiling activation running on the
|
||||
|
@ -376,7 +379,7 @@ struct JSContext : public JS::RootingContext,
|
|||
|
||||
private:
|
||||
/* Space for interpreter frames. */
|
||||
js::ThreadLocalData<js::InterpreterStack> interpreterStack_;
|
||||
js::ThreadData<js::InterpreterStack> interpreterStack_;
|
||||
|
||||
public:
|
||||
js::InterpreterStack& interpreterStack() {
|
||||
|
@ -387,11 +390,11 @@ struct JSContext : public JS::RootingContext,
|
|||
const uintptr_t nativeStackBase;
|
||||
|
||||
/* The native stack size limit that runtime should not exceed. */
|
||||
js::ThreadLocalData<size_t> nativeStackQuota[JS::StackKindCount];
|
||||
js::ThreadData<size_t> nativeStackQuota[JS::StackKindCount];
|
||||
|
||||
public:
|
||||
/* If non-null, report JavaScript entry points to this monitor. */
|
||||
js::ThreadLocalData<JS::dbg::AutoEntryMonitor*> entryMonitor;
|
||||
js::ThreadData<JS::dbg::AutoEntryMonitor*> entryMonitor;
|
||||
|
||||
/*
|
||||
* Stack of debuggers that currently disallow debuggee execution.
|
||||
|
@ -400,46 +403,46 @@ struct JSContext : public JS::RootingContext,
|
|||
* stack of Debuggers that have prevented execution need to be tracked to
|
||||
* enter the correct Debugger compartment to report the error.
|
||||
*/
|
||||
js::ThreadLocalData<js::EnterDebuggeeNoExecute*> noExecuteDebuggerTop;
|
||||
js::ThreadData<js::EnterDebuggeeNoExecute*> noExecuteDebuggerTop;
|
||||
|
||||
js::ThreadLocalData<js::ActivityCallback> activityCallback;
|
||||
js::ThreadLocalData<void*> activityCallbackArg;
|
||||
js::ThreadData<js::ActivityCallback> activityCallback;
|
||||
js::ThreadData<void*> activityCallbackArg;
|
||||
void triggerActivityCallback(bool active);
|
||||
|
||||
/* The request depth for this thread. */
|
||||
js::ThreadLocalData<unsigned> requestDepth;
|
||||
js::ThreadData<unsigned> requestDepth;
|
||||
|
||||
#ifdef DEBUG
|
||||
js::ThreadLocalData<unsigned> checkRequestDepth;
|
||||
js::ThreadLocalData<uint32_t> inUnsafeCallWithABI;
|
||||
js::ThreadLocalData<bool> hasAutoUnsafeCallWithABI;
|
||||
js::ThreadData<unsigned> checkRequestDepth;
|
||||
js::ThreadData<uint32_t> inUnsafeCallWithABI;
|
||||
js::ThreadData<bool> hasAutoUnsafeCallWithABI;
|
||||
#endif
|
||||
|
||||
#ifdef JS_SIMULATOR
|
||||
private:
|
||||
js::ThreadLocalData<js::jit::Simulator*> simulator_;
|
||||
js::ThreadData<js::jit::Simulator*> simulator_;
|
||||
public:
|
||||
js::jit::Simulator* simulator() const;
|
||||
uintptr_t* addressOfSimulatorStackLimit();
|
||||
#endif
|
||||
|
||||
#ifdef JS_TRACE_LOGGING
|
||||
js::ThreadLocalData<js::TraceLoggerThread*> traceLogger;
|
||||
js::ThreadData<js::TraceLoggerThread*> traceLogger;
|
||||
#endif
|
||||
|
||||
private:
|
||||
/* Pointer to the current AutoFlushICache. */
|
||||
js::ThreadLocalData<js::jit::AutoFlushICache*> autoFlushICache_;
|
||||
js::ThreadData<js::jit::AutoFlushICache*> autoFlushICache_;
|
||||
public:
|
||||
|
||||
js::jit::AutoFlushICache* autoFlushICache() const;
|
||||
void setAutoFlushICache(js::jit::AutoFlushICache* afc);
|
||||
|
||||
// State used by util/DoubleToString.cpp.
|
||||
js::ThreadLocalData<DtoaState*> dtoaState;
|
||||
js::ThreadData<DtoaState*> dtoaState;
|
||||
|
||||
// Any GC activity occurring on this thread.
|
||||
js::ThreadLocalData<JS::HeapState> heapState;
|
||||
js::ThreadData<JS::HeapState> heapState;
|
||||
|
||||
/*
|
||||
* When this flag is non-zero, any attempt to GC will be skipped. It is used
|
||||
|
@ -449,37 +452,37 @@ struct JSContext : public JS::RootingContext,
|
|||
* extremely dangerous and should only be used when in an OOM situation or
|
||||
* in non-exposed debugging facilities.
|
||||
*/
|
||||
js::ThreadLocalData<int32_t> suppressGC;
|
||||
js::ThreadData<int32_t> suppressGC;
|
||||
|
||||
#ifdef DEBUG
|
||||
// Whether this thread is actively Ion compiling.
|
||||
js::ThreadLocalData<bool> ionCompiling;
|
||||
js::ThreadData<bool> ionCompiling;
|
||||
|
||||
// Whether this thread is actively Ion compiling in a context where a minor
|
||||
// GC could happen simultaneously. If this is true, this thread cannot use
|
||||
// any pointers into the nursery.
|
||||
js::ThreadLocalData<bool> ionCompilingSafeForMinorGC;
|
||||
js::ThreadData<bool> ionCompilingSafeForMinorGC;
|
||||
|
||||
// Whether this thread is currently performing GC. This thread could be the
|
||||
// active thread or a helper thread while the active thread is running the
|
||||
// collector.
|
||||
js::ThreadLocalData<bool> performingGC;
|
||||
js::ThreadData<bool> performingGC;
|
||||
|
||||
// Whether this thread is currently sweeping GC things. This thread could
|
||||
// be the active thread or a helper thread while the active thread is running
|
||||
// the mutator. This is used to assert that destruction of GCPtr only
|
||||
// happens when we are sweeping.
|
||||
js::ThreadLocalData<bool> gcSweeping;
|
||||
js::ThreadData<bool> gcSweeping;
|
||||
|
||||
// Whether this thread is performing work in the background for a runtime's
|
||||
// GCHelperState.
|
||||
js::ThreadLocalData<bool> gcHelperStateThread;
|
||||
js::ThreadData<bool> gcHelperStateThread;
|
||||
|
||||
// Whether this thread is currently manipulating possibly-gray GC things.
|
||||
js::ThreadLocalData<size_t> isTouchingGrayThings;
|
||||
js::ThreadData<size_t> isTouchingGrayThings;
|
||||
|
||||
js::ThreadLocalData<size_t> noGCOrAllocationCheck;
|
||||
js::ThreadLocalData<size_t> noNurseryAllocationCheck;
|
||||
js::ThreadData<size_t> noGCOrAllocationCheck;
|
||||
js::ThreadData<size_t> noNurseryAllocationCheck;
|
||||
|
||||
/*
|
||||
* If this is 0, all cross-compartment proxies must be registered in the
|
||||
|
@ -487,7 +490,7 @@ struct JSContext : public JS::RootingContext,
|
|||
* new wrappers. When non-zero, this records the recursion depth of wrapper
|
||||
* creation.
|
||||
*/
|
||||
js::ThreadLocalData<uintptr_t> disableStrictProxyCheckingCount;
|
||||
js::ThreadData<uintptr_t> disableStrictProxyCheckingCount;
|
||||
|
||||
bool isAllocAllowed() { return noGCOrAllocationCheck == 0; }
|
||||
void disallowAlloc() { ++noGCOrAllocationCheck; }
|
||||
|
@ -513,13 +516,13 @@ struct JSContext : public JS::RootingContext,
|
|||
|
||||
#if defined(DEBUG) || defined(JS_OOM_BREAKPOINT)
|
||||
// We are currently running a simulated OOM test.
|
||||
js::ThreadLocalData<bool> runningOOMTest;
|
||||
js::ThreadData<bool> runningOOMTest;
|
||||
#endif
|
||||
|
||||
// True if we should assert that
|
||||
// !comp->validAccessPtr || *comp->validAccessPtr
|
||||
// is true for every |comp| that we run JS code in.
|
||||
js::ThreadLocalData<unsigned> enableAccessValidation;
|
||||
js::ThreadData<unsigned> enableAccessValidation;
|
||||
|
||||
/*
|
||||
* Some regions of code are hard for the static rooting hazard analysis to
|
||||
|
@ -527,14 +530,14 @@ struct JSContext : public JS::RootingContext,
|
|||
* analysis. When this is non-zero, we should assert if we trigger, or
|
||||
* might trigger, a GC.
|
||||
*/
|
||||
js::ThreadLocalData<int> inUnsafeRegion;
|
||||
js::ThreadData<int> inUnsafeRegion;
|
||||
|
||||
// Count of AutoDisableGenerationalGC instances on the thread's stack.
|
||||
js::ThreadLocalData<unsigned> generationalDisabled;
|
||||
js::ThreadData<unsigned> generationalDisabled;
|
||||
|
||||
// Some code cannot tolerate compacting GC so it can be disabled temporarily
|
||||
// with AutoDisableCompactingGC which uses this counter.
|
||||
js::ThreadLocalData<unsigned> compactingDisabledCount;
|
||||
js::ThreadData<unsigned> compactingDisabledCount;
|
||||
|
||||
// Count of AutoKeepAtoms instances on the current thread's stack. When any
|
||||
// instances exist, atoms in the runtime will not be collected. Threads
|
||||
|
@ -545,7 +548,7 @@ struct JSContext : public JS::RootingContext,
|
|||
// their exclusive compartment (which is not collected) or to the atoms
|
||||
// compartment. Therefore, we avoid collecting the atoms compartment when
|
||||
// exclusive threads are running.
|
||||
js::ThreadLocalData<unsigned> keepAtoms;
|
||||
js::ThreadData<unsigned> keepAtoms;
|
||||
|
||||
bool canCollectAtoms() const {
|
||||
return !keepAtoms && !runtime()->hasHelperThreadZones();
|
||||
|
@ -555,7 +558,7 @@ struct JSContext : public JS::RootingContext,
|
|||
// Pools used for recycling name maps and vectors when parsing and
|
||||
// emitting bytecode. Purged on GC when there are no active script
|
||||
// compilations.
|
||||
js::ThreadLocalData<js::frontend::NameCollectionPool> frontendCollectionPool_;
|
||||
js::ThreadData<js::frontend::NameCollectionPool> frontendCollectionPool_;
|
||||
public:
|
||||
|
||||
js::frontend::NameCollectionPool& frontendCollectionPool() {
|
||||
|
@ -589,20 +592,20 @@ struct JSContext : public JS::RootingContext,
|
|||
/* Temporary arena pool used while compiling and decompiling. */
|
||||
static const size_t TEMP_LIFO_ALLOC_PRIMARY_CHUNK_SIZE = 4 * 1024;
|
||||
private:
|
||||
js::ThreadLocalData<js::LifoAlloc> tempLifoAlloc_;
|
||||
js::ThreadData<js::LifoAlloc> tempLifoAlloc_;
|
||||
public:
|
||||
js::LifoAlloc& tempLifoAlloc() { return tempLifoAlloc_.ref(); }
|
||||
const js::LifoAlloc& tempLifoAlloc() const { return tempLifoAlloc_.ref(); }
|
||||
|
||||
js::ThreadLocalData<uint32_t> debuggerMutations;
|
||||
js::ThreadData<uint32_t> debuggerMutations;
|
||||
|
||||
// Cache for jit::GetPcScript().
|
||||
js::ThreadLocalData<js::jit::PcScriptCache*> ionPcScriptCache;
|
||||
js::ThreadData<js::jit::PcScriptCache*> ionPcScriptCache;
|
||||
|
||||
private:
|
||||
/* Exception state -- the exception member is a GC root by definition. */
|
||||
js::ThreadLocalData<bool> throwing; /* is there a pending exception? */
|
||||
js::ThreadLocalData<JS::PersistentRooted<JS::Value>> unwrappedException_; /* most-recently-thrown exception */
|
||||
js::ThreadData<bool> throwing; /* is there a pending exception? */
|
||||
js::ThreadData<JS::PersistentRooted<JS::Value>> unwrappedException_; /* most-recently-thrown exception */
|
||||
|
||||
JS::Value& unwrappedException() {
|
||||
if (!unwrappedException_.ref().initialized())
|
||||
|
@ -612,32 +615,32 @@ struct JSContext : public JS::RootingContext,
|
|||
|
||||
// True if the exception currently being thrown is by result of
|
||||
// ReportOverRecursed. See Debugger::slowPathOnExceptionUnwind.
|
||||
js::ThreadLocalData<bool> overRecursed_;
|
||||
js::ThreadData<bool> overRecursed_;
|
||||
|
||||
// True if propagating a forced return from an interrupt handler during
|
||||
// debug mode.
|
||||
js::ThreadLocalData<bool> propagatingForcedReturn_;
|
||||
js::ThreadData<bool> propagatingForcedReturn_;
|
||||
|
||||
// A stack of live iterators that need to be updated in case of debug mode
|
||||
// OSR.
|
||||
js::ThreadLocalData<js::jit::DebugModeOSRVolatileJitFrameIter*>
|
||||
js::ThreadData<js::jit::DebugModeOSRVolatileJitFrameIter*>
|
||||
liveVolatileJitFrameIter_;
|
||||
|
||||
public:
|
||||
js::ThreadLocalData<int32_t> reportGranularity; /* see vm/Probes.h */
|
||||
js::ThreadData<int32_t> reportGranularity; /* see vm/Probes.h */
|
||||
|
||||
js::ThreadLocalData<js::AutoResolving*> resolvingList;
|
||||
js::ThreadData<js::AutoResolving*> resolvingList;
|
||||
|
||||
#ifdef DEBUG
|
||||
js::ThreadLocalData<js::AutoEnterPolicy*> enteredPolicy;
|
||||
js::ThreadData<js::AutoEnterPolicy*> enteredPolicy;
|
||||
#endif
|
||||
|
||||
/* True if generating an error, to prevent runaway recursion. */
|
||||
js::ThreadLocalData<bool> generatingError;
|
||||
js::ThreadData<bool> generatingError;
|
||||
|
||||
private:
|
||||
/* State for object and array toSource conversion. */
|
||||
js::ThreadLocalData<js::AutoCycleDetector::Vector> cycleDetectorVector_;
|
||||
js::ThreadData<js::AutoCycleDetector::Vector> cycleDetectorVector_;
|
||||
|
||||
public:
|
||||
js::AutoCycleDetector::Vector& cycleDetectorVector() {
|
||||
|
@ -663,9 +666,9 @@ struct JSContext : public JS::RootingContext,
|
|||
}
|
||||
|
||||
// Number of JS_BeginRequest calls without the corresponding JS_EndRequest.
|
||||
js::ThreadLocalData<unsigned> outstandingRequests;
|
||||
js::ThreadData<unsigned> outstandingRequests;
|
||||
|
||||
js::ThreadLocalData<bool> jitIsBroken;
|
||||
js::ThreadData<bool> jitIsBroken;
|
||||
|
||||
void updateJITEnabled();
|
||||
|
||||
|
@ -679,7 +682,7 @@ struct JSContext : public JS::RootingContext,
|
|||
* New activations will reset this to nullptr on construction after getting
|
||||
* the current value, and will restore the previous value on destruction.
|
||||
*/
|
||||
js::ThreadLocalData<JS::PersistentRooted<js::SavedFrame*>> asyncStackForNewActivations_;
|
||||
js::ThreadData<JS::PersistentRooted<js::SavedFrame*>> asyncStackForNewActivations_;
|
||||
public:
|
||||
|
||||
js::SavedFrame*& asyncStackForNewActivations() {
|
||||
|
@ -691,13 +694,13 @@ struct JSContext : public JS::RootingContext,
|
|||
/*
|
||||
* Value of asyncCause to be attached to asyncStackForNewActivations.
|
||||
*/
|
||||
js::ThreadLocalData<const char*> asyncCauseForNewActivations;
|
||||
js::ThreadData<const char*> asyncCauseForNewActivations;
|
||||
|
||||
/*
|
||||
* True if the async call was explicitly requested, e.g. via
|
||||
* callFunctionWithAsyncStack.
|
||||
*/
|
||||
js::ThreadLocalData<bool> asyncCallIsExplicit;
|
||||
js::ThreadData<bool> asyncCallIsExplicit;
|
||||
|
||||
bool currentlyRunningInInterpreter() const {
|
||||
return activation()->isInterpreter();
|
||||
|
@ -778,11 +781,11 @@ struct JSContext : public JS::RootingContext,
|
|||
using InterruptCallbackVector = js::Vector<JSInterruptCallback, 2, js::SystemAllocPolicy>;
|
||||
|
||||
private:
|
||||
js::ThreadLocalData<InterruptCallbackVector> interruptCallbacks_;
|
||||
js::ThreadData<InterruptCallbackVector> interruptCallbacks_;
|
||||
public:
|
||||
InterruptCallbackVector& interruptCallbacks() { return interruptCallbacks_.ref(); }
|
||||
|
||||
js::ThreadLocalData<bool> interruptCallbackDisabled;
|
||||
js::ThreadData<bool> interruptCallbackDisabled;
|
||||
|
||||
mozilla::Atomic<uint32_t, mozilla::Relaxed> interrupt_;
|
||||
mozilla::Atomic<uint32_t, mozilla::Relaxed> interruptRegExpJit_;
|
||||
|
@ -838,7 +841,7 @@ struct JSContext : public JS::RootingContext,
|
|||
|
||||
// Buffer for OSR from baseline to Ion. To avoid holding on to this for
|
||||
// too long, it's also freed in EnterBaseline (after returning from JIT code).
|
||||
js::ThreadLocalData<uint8_t*> osrTempData_;
|
||||
js::ThreadData<uint8_t*> osrTempData_;
|
||||
|
||||
uint8_t* allocateOsrTempData(size_t size);
|
||||
void freeOsrTempData();
|
||||
|
@ -855,7 +858,7 @@ struct JSContext : public JS::RootingContext,
|
|||
// value that will be temporarily corrupt. This special override value is set
|
||||
// only in callVM() targets that are about to return *and* have invalidated
|
||||
// their callee.
|
||||
js::ThreadLocalData<js::Value> ionReturnOverride_;
|
||||
js::ThreadData<js::Value> ionReturnOverride_;
|
||||
|
||||
bool hasIonReturnOverride() const {
|
||||
return !ionReturnOverride_.ref().isMagic(JS_ARG_POISON);
|
||||
|
@ -874,22 +877,22 @@ struct JSContext : public JS::RootingContext,
|
|||
mozilla::Atomic<uintptr_t, mozilla::Relaxed> jitStackLimit;
|
||||
|
||||
// Like jitStackLimit, but not reset to trigger interrupts.
|
||||
js::ThreadLocalData<uintptr_t> jitStackLimitNoInterrupt;
|
||||
js::ThreadData<uintptr_t> jitStackLimitNoInterrupt;
|
||||
|
||||
// Promise callbacks.
|
||||
js::ThreadLocalData<JSGetIncumbentGlobalCallback> getIncumbentGlobalCallback;
|
||||
js::ThreadLocalData<JSEnqueuePromiseJobCallback> enqueuePromiseJobCallback;
|
||||
js::ThreadLocalData<void*> enqueuePromiseJobCallbackData;
|
||||
js::ThreadData<JSGetIncumbentGlobalCallback> getIncumbentGlobalCallback;
|
||||
js::ThreadData<JSEnqueuePromiseJobCallback> enqueuePromiseJobCallback;
|
||||
js::ThreadData<void*> enqueuePromiseJobCallbackData;
|
||||
|
||||
// Queue of pending jobs as described in ES2016 section 8.4.
|
||||
// Only used if internal job queue handling was activated using
|
||||
// `js::UseInternalJobQueues`.
|
||||
js::ThreadLocalData<JS::PersistentRooted<js::JobQueue>*> jobQueue;
|
||||
js::ThreadLocalData<bool> drainingJobQueue;
|
||||
js::ThreadLocalData<bool> stopDrainingJobQueue;
|
||||
js::ThreadData<JS::PersistentRooted<js::JobQueue>*> jobQueue;
|
||||
js::ThreadData<bool> drainingJobQueue;
|
||||
js::ThreadData<bool> stopDrainingJobQueue;
|
||||
|
||||
js::ThreadLocalData<JSPromiseRejectionTrackerCallback> promiseRejectionTrackerCallback;
|
||||
js::ThreadLocalData<void*> promiseRejectionTrackerCallbackData;
|
||||
js::ThreadData<JSPromiseRejectionTrackerCallback> promiseRejectionTrackerCallback;
|
||||
js::ThreadData<void*> promiseRejectionTrackerCallbackData;
|
||||
|
||||
JSObject* getIncumbentGlobal(JSContext* cx);
|
||||
bool enqueuePromiseJob(JSContext* cx, js::HandleFunction job, js::HandleObject promise,
|
||||
|
|
|
@ -1616,10 +1616,10 @@ JSFunction::createScriptForLazilyInterpretedFunction(JSContext* cx, HandleFuncti
|
|||
MOZ_ASSERT(lazy->scriptSource()->hasSourceData());
|
||||
|
||||
// Parse and compile the script from source.
|
||||
size_t lazyLength = lazy->end() - lazy->begin();
|
||||
size_t lazyLength = lazy->sourceEnd() - lazy->sourceStart();
|
||||
UncompressedSourceCache::AutoHoldEntry holder;
|
||||
ScriptSource::PinnedChars chars(cx, lazy->scriptSource(), holder,
|
||||
lazy->begin(), lazyLength);
|
||||
lazy->sourceStart(), lazyLength);
|
||||
if (!chars.get())
|
||||
return false;
|
||||
|
||||
|
|
|
@ -530,6 +530,11 @@ IsNativeFunction(const js::Value& v, JSNative native)
|
|||
return IsFunctionObject(v, &fun) && fun->maybeNative() == native;
|
||||
}
|
||||
|
||||
static MOZ_ALWAYS_INLINE bool
|
||||
IsNativeFunction(const JSObject* obj, JSNative native)
|
||||
{
|
||||
return obj->is<JSFunction>() && obj->as<JSFunction>().maybeNative() == native;
|
||||
}
|
||||
|
||||
// Return whether looking up a method on 'obj' definitely resolves to the
|
||||
// original specified native function. The method may conservatively return
|
||||
|
|
|
@ -244,8 +244,8 @@ XDRRelazificationInfo(XDRState<mode>* xdr, HandleFunction fun, HandleScript scri
|
|||
|
||||
uint64_t packedFields;
|
||||
{
|
||||
uint32_t begin = script->sourceStart();
|
||||
uint32_t end = script->sourceEnd();
|
||||
uint32_t sourceStart = script->sourceStart();
|
||||
uint32_t sourceEnd = script->sourceEnd();
|
||||
uint32_t toStringStart = script->toStringStart();
|
||||
uint32_t toStringEnd = script->toStringEnd();
|
||||
uint32_t lineno = script->lineno();
|
||||
|
@ -253,8 +253,8 @@ XDRRelazificationInfo(XDRState<mode>* xdr, HandleFunction fun, HandleScript scri
|
|||
|
||||
if (mode == XDR_ENCODE) {
|
||||
packedFields = lazy->packedFields();
|
||||
MOZ_ASSERT(begin == lazy->begin());
|
||||
MOZ_ASSERT(end == lazy->end());
|
||||
MOZ_ASSERT(sourceStart == lazy->sourceStart());
|
||||
MOZ_ASSERT(sourceEnd == lazy->sourceEnd());
|
||||
MOZ_ASSERT(toStringStart == lazy->toStringStart());
|
||||
MOZ_ASSERT(toStringEnd == lazy->toStringEnd());
|
||||
MOZ_ASSERT(lineno == lazy->lineno());
|
||||
|
@ -270,7 +270,8 @@ XDRRelazificationInfo(XDRState<mode>* xdr, HandleFunction fun, HandleScript scri
|
|||
if (mode == XDR_DECODE) {
|
||||
RootedScriptSource sourceObject(cx, &script->scriptSourceUnwrap());
|
||||
lazy.set(LazyScript::Create(cx, fun, script, enclosingScope, sourceObject,
|
||||
packedFields, begin, end, toStringStart, lineno, column));
|
||||
packedFields, sourceStart, sourceEnd, toStringStart,
|
||||
lineno, column));
|
||||
if (!lazy)
|
||||
return xdr->fail(JS::TranscodeResult_Throw);
|
||||
|
||||
|
@ -911,8 +912,8 @@ js::XDRLazyScript(XDRState<mode>* xdr, HandleScope enclosingScope,
|
|||
JSContext* cx = xdr->cx();
|
||||
|
||||
{
|
||||
uint32_t begin;
|
||||
uint32_t end;
|
||||
uint32_t sourceStart;
|
||||
uint32_t sourceEnd;
|
||||
uint32_t toStringStart;
|
||||
uint32_t toStringEnd;
|
||||
uint32_t lineno;
|
||||
|
@ -926,8 +927,8 @@ js::XDRLazyScript(XDRState<mode>* xdr, HandleScope enclosingScope,
|
|||
|
||||
MOZ_ASSERT(fun == lazy->functionNonDelazifying());
|
||||
|
||||
begin = lazy->begin();
|
||||
end = lazy->end();
|
||||
sourceStart = lazy->sourceStart();
|
||||
sourceEnd = lazy->sourceEnd();
|
||||
toStringStart = lazy->toStringStart();
|
||||
toStringEnd = lazy->toStringEnd();
|
||||
lineno = lazy->lineno();
|
||||
|
@ -935,8 +936,8 @@ js::XDRLazyScript(XDRState<mode>* xdr, HandleScope enclosingScope,
|
|||
packedFields = lazy->packedFields();
|
||||
}
|
||||
|
||||
MOZ_TRY(xdr->codeUint32(&begin));
|
||||
MOZ_TRY(xdr->codeUint32(&end));
|
||||
MOZ_TRY(xdr->codeUint32(&sourceStart));
|
||||
MOZ_TRY(xdr->codeUint32(&sourceEnd));
|
||||
MOZ_TRY(xdr->codeUint32(&toStringStart));
|
||||
MOZ_TRY(xdr->codeUint32(&toStringEnd));
|
||||
MOZ_TRY(xdr->codeUint32(&lineno));
|
||||
|
@ -945,7 +946,8 @@ js::XDRLazyScript(XDRState<mode>* xdr, HandleScope enclosingScope,
|
|||
|
||||
if (mode == XDR_DECODE) {
|
||||
lazy.set(LazyScript::Create(cx, fun, nullptr, enclosingScope, sourceObject,
|
||||
packedFields, begin, end, toStringStart, lineno, column));
|
||||
packedFields, sourceStart, sourceEnd, toStringStart,
|
||||
lineno, column));
|
||||
if (!lazy)
|
||||
return xdr->fail(JS::TranscodeResult_Throw);
|
||||
lazy->setToStringEnd(toStringEnd);
|
||||
|
@ -4173,7 +4175,7 @@ JSScript::formalLivesInArgumentsObject(unsigned argSlot)
|
|||
}
|
||||
|
||||
LazyScript::LazyScript(JSFunction* fun, void* table, uint64_t packedFields,
|
||||
uint32_t begin, uint32_t end,
|
||||
uint32_t sourceStart, uint32_t sourceEnd,
|
||||
uint32_t toStringStart, uint32_t lineno, uint32_t column)
|
||||
: script_(nullptr),
|
||||
function_(fun),
|
||||
|
@ -4181,15 +4183,15 @@ LazyScript::LazyScript(JSFunction* fun, void* table, uint64_t packedFields,
|
|||
sourceObject_(nullptr),
|
||||
table_(table),
|
||||
packedFields_(packedFields),
|
||||
begin_(begin),
|
||||
end_(end),
|
||||
sourceStart_(sourceStart),
|
||||
sourceEnd_(sourceEnd),
|
||||
toStringStart_(toStringStart),
|
||||
toStringEnd_(end),
|
||||
toStringEnd_(sourceEnd),
|
||||
lineno_(lineno),
|
||||
column_(column)
|
||||
{
|
||||
MOZ_ASSERT(begin <= end);
|
||||
MOZ_ASSERT(toStringStart <= begin);
|
||||
MOZ_ASSERT(sourceStart <= sourceEnd);
|
||||
MOZ_ASSERT(toStringStart <= sourceStart);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -4235,7 +4237,7 @@ LazyScript::maybeForwardedScriptSource() const
|
|||
|
||||
/* static */ LazyScript*
|
||||
LazyScript::CreateRaw(JSContext* cx, HandleFunction fun,
|
||||
uint64_t packedFields, uint32_t begin, uint32_t end,
|
||||
uint64_t packedFields, uint32_t sourceStart, uint32_t sourceEnd,
|
||||
uint32_t toStringStart, uint32_t lineno, uint32_t column)
|
||||
{
|
||||
union {
|
||||
|
@ -4264,7 +4266,7 @@ LazyScript::CreateRaw(JSContext* cx, HandleFunction fun,
|
|||
|
||||
cx->compartment()->scheduleDelazificationForDebugger();
|
||||
|
||||
return new (res) LazyScript(fun, table.forget(), packed, begin, end,
|
||||
return new (res) LazyScript(fun, table.forget(), packed, sourceStart, sourceEnd,
|
||||
toStringStart, lineno, column);
|
||||
}
|
||||
|
||||
|
@ -4272,7 +4274,7 @@ LazyScript::CreateRaw(JSContext* cx, HandleFunction fun,
|
|||
LazyScript::Create(JSContext* cx, HandleFunction fun,
|
||||
const frontend::AtomVector& closedOverBindings,
|
||||
Handle<GCVector<JSFunction*, 8>> innerFunctions,
|
||||
uint32_t begin, uint32_t end,
|
||||
uint32_t sourceStart, uint32_t sourceEnd,
|
||||
uint32_t toStringStart, uint32_t lineno, uint32_t column)
|
||||
{
|
||||
union {
|
||||
|
@ -4295,8 +4297,8 @@ LazyScript::Create(JSContext* cx, HandleFunction fun,
|
|||
p.isDerivedClassConstructor = false;
|
||||
p.needsHomeObject = false;
|
||||
|
||||
LazyScript* res = LazyScript::CreateRaw(cx, fun, packedFields, begin, end, toStringStart,
|
||||
lineno, column);
|
||||
LazyScript* res = LazyScript::CreateRaw(cx, fun, packedFields, sourceStart, sourceEnd,
|
||||
toStringStart, lineno, column);
|
||||
if (!res)
|
||||
return nullptr;
|
||||
|
||||
|
@ -4315,7 +4317,7 @@ LazyScript::Create(JSContext* cx, HandleFunction fun,
|
|||
LazyScript::Create(JSContext* cx, HandleFunction fun,
|
||||
HandleScript script, HandleScope enclosingScope,
|
||||
HandleScriptSource sourceObject,
|
||||
uint64_t packedFields, uint32_t begin, uint32_t end,
|
||||
uint64_t packedFields, uint32_t sourceStart, uint32_t sourceEnd,
|
||||
uint32_t toStringStart, uint32_t lineno, uint32_t column)
|
||||
{
|
||||
// Dummy atom which is not a valid property name.
|
||||
|
@ -4325,8 +4327,8 @@ LazyScript::Create(JSContext* cx, HandleFunction fun,
|
|||
// holding this lazy script.
|
||||
HandleFunction dummyFun = fun;
|
||||
|
||||
LazyScript* res = LazyScript::CreateRaw(cx, fun, packedFields, begin, end, toStringStart,
|
||||
lineno, column);
|
||||
LazyScript* res = LazyScript::CreateRaw(cx, fun, packedFields, sourceStart, sourceEnd,
|
||||
toStringStart, lineno, column);
|
||||
if (!res)
|
||||
return nullptr;
|
||||
|
||||
|
|
|
@ -2145,8 +2145,8 @@ class LazyScript : public gc::TenuredCell
|
|||
|
||||
// Source location for the script.
|
||||
// See the comment in JSScript for the details
|
||||
uint32_t begin_;
|
||||
uint32_t end_;
|
||||
uint32_t sourceStart_;
|
||||
uint32_t sourceEnd_;
|
||||
uint32_t toStringStart_;
|
||||
uint32_t toStringEnd_;
|
||||
// Line and column of |begin_| position, that is the position where we
|
||||
|
@ -2352,11 +2352,11 @@ class LazyScript : public gc::TenuredCell
|
|||
const char* filename() const {
|
||||
return scriptSource()->filename();
|
||||
}
|
||||
uint32_t begin() const {
|
||||
return begin_;
|
||||
uint32_t sourceStart() const {
|
||||
return sourceStart_;
|
||||
}
|
||||
uint32_t end() const {
|
||||
return end_;
|
||||
uint32_t sourceEnd() const {
|
||||
return sourceEnd_;
|
||||
}
|
||||
uint32_t toStringStart() const {
|
||||
return toStringStart_;
|
||||
|
@ -2373,7 +2373,7 @@ class LazyScript : public gc::TenuredCell
|
|||
|
||||
void setToStringEnd(uint32_t toStringEnd) {
|
||||
MOZ_ASSERT(toStringStart_ <= toStringEnd);
|
||||
MOZ_ASSERT(toStringEnd_ >= end_);
|
||||
MOZ_ASSERT(toStringEnd_ >= sourceEnd_);
|
||||
toStringEnd_ = toStringEnd;
|
||||
}
|
||||
|
||||
|
|
|
@ -18,7 +18,6 @@
|
|||
_(TestMutex, 100) \
|
||||
_(ShellContextWatchdog, 100) \
|
||||
_(ShellWorkerThreads, 100) \
|
||||
_(ShellThreadCooperation, 100) \
|
||||
_(ShellArrayBufferMailbox, 100) \
|
||||
\
|
||||
_(RuntimeExclusiveAccess, 200) \
|
||||
|
|
|
@ -160,8 +160,8 @@ ObjectGroup::useSingletonForClone(JSFunction* fun)
|
|||
} else {
|
||||
if (!fun->lazyScript()->isLikelyConstructorWrapper())
|
||||
return false;
|
||||
begin = fun->lazyScript()->begin();
|
||||
end = fun->lazyScript()->end();
|
||||
begin = fun->lazyScript()->sourceStart();
|
||||
end = fun->lazyScript()->sourceEnd();
|
||||
}
|
||||
|
||||
return end - begin <= 100;
|
||||
|
|
|
@ -301,10 +301,10 @@ struct JSRuntime : public js::MallocProvider<JSRuntime>
|
|||
}
|
||||
|
||||
/* Call this to accumulate telemetry data. */
|
||||
js::ActiveThreadData<JSAccumulateTelemetryDataCallback> telemetryCallback;
|
||||
js::MainThreadData<JSAccumulateTelemetryDataCallback> telemetryCallback;
|
||||
|
||||
/* Call this to accumulate use counter data. */
|
||||
js::ActiveThreadData<JSSetUseCounterCallback> useCounterCallback;
|
||||
js::MainThreadData<JSSetUseCounterCallback> useCounterCallback;
|
||||
|
||||
public:
|
||||
// Accumulates data for Firefox telemetry. |id| is the ID of a JS_TELEMETRY_*
|
||||
|
@ -345,35 +345,35 @@ struct JSRuntime : public js::MallocProvider<JSRuntime>
|
|||
* Allow relazifying functions in compartments that are active. This is
|
||||
* only used by the relazifyFunctions() testing function.
|
||||
*/
|
||||
js::ActiveThreadData<bool> allowRelazificationForTesting;
|
||||
js::MainThreadData<bool> allowRelazificationForTesting;
|
||||
|
||||
/* Compartment destroy callback. */
|
||||
js::ActiveThreadData<JSDestroyCompartmentCallback> destroyCompartmentCallback;
|
||||
js::MainThreadData<JSDestroyCompartmentCallback> destroyCompartmentCallback;
|
||||
|
||||
/* Compartment memory reporting callback. */
|
||||
js::ActiveThreadData<JSSizeOfIncludingThisCompartmentCallback> sizeOfIncludingThisCompartmentCallback;
|
||||
js::MainThreadData<JSSizeOfIncludingThisCompartmentCallback> sizeOfIncludingThisCompartmentCallback;
|
||||
|
||||
/* Call this to get the name of a compartment. */
|
||||
js::ActiveThreadData<JSCompartmentNameCallback> compartmentNameCallback;
|
||||
js::MainThreadData<JSCompartmentNameCallback> compartmentNameCallback;
|
||||
|
||||
/* Realm destroy callback. */
|
||||
js::ActiveThreadData<JS::DestroyRealmCallback> destroyRealmCallback;
|
||||
js::MainThreadData<JS::DestroyRealmCallback> destroyRealmCallback;
|
||||
|
||||
/* Call this to get the name of a realm. */
|
||||
js::ActiveThreadData<JS::RealmNameCallback> realmNameCallback;
|
||||
js::MainThreadData<JS::RealmNameCallback> realmNameCallback;
|
||||
|
||||
/* Callback for doing memory reporting on external strings. */
|
||||
js::ActiveThreadData<JSExternalStringSizeofCallback> externalStringSizeofCallback;
|
||||
js::MainThreadData<JSExternalStringSizeofCallback> externalStringSizeofCallback;
|
||||
|
||||
js::ActiveThreadData<mozilla::UniquePtr<js::SourceHook>> sourceHook;
|
||||
js::MainThreadData<mozilla::UniquePtr<js::SourceHook>> sourceHook;
|
||||
|
||||
js::ActiveThreadData<const JSSecurityCallbacks*> securityCallbacks;
|
||||
js::ActiveThreadData<const js::DOMCallbacks*> DOMcallbacks;
|
||||
js::ActiveThreadData<JSDestroyPrincipalsOp> destroyPrincipals;
|
||||
js::ActiveThreadData<JSReadPrincipalsOp> readPrincipals;
|
||||
js::MainThreadData<const JSSecurityCallbacks*> securityCallbacks;
|
||||
js::MainThreadData<const js::DOMCallbacks*> DOMcallbacks;
|
||||
js::MainThreadData<JSDestroyPrincipalsOp> destroyPrincipals;
|
||||
js::MainThreadData<JSReadPrincipalsOp> readPrincipals;
|
||||
|
||||
/* Optional warning reporter. */
|
||||
js::ActiveThreadData<JS::WarningReporter> warningReporter;
|
||||
js::MainThreadData<JS::WarningReporter> warningReporter;
|
||||
|
||||
private:
|
||||
/* Gecko profiling metadata */
|
||||
|
@ -382,7 +382,7 @@ struct JSRuntime : public js::MallocProvider<JSRuntime>
|
|||
js::GeckoProfilerRuntime& geckoProfiler() { return geckoProfiler_.ref(); }
|
||||
|
||||
// Heap GC roots for PersistentRooted pointers.
|
||||
js::ActiveThreadData<mozilla::EnumeratedArray<JS::RootKind, JS::RootKind::Limit,
|
||||
js::MainThreadData<mozilla::EnumeratedArray<JS::RootKind, JS::RootKind::Limit,
|
||||
mozilla::LinkedList<JS::PersistentRooted<void*>>>> heapRoots;
|
||||
|
||||
void tracePersistentRoots(JSTracer* trc);
|
||||
|
@ -402,12 +402,12 @@ struct JSRuntime : public js::MallocProvider<JSRuntime>
|
|||
void setTrustedPrincipals(const JSPrincipals* p) { trustedPrincipals_ = p; }
|
||||
const JSPrincipals* trustedPrincipals() const { return trustedPrincipals_; }
|
||||
|
||||
js::ActiveThreadData<const JSWrapObjectCallbacks*> wrapObjectCallbacks;
|
||||
js::ActiveThreadData<js::PreserveWrapperCallback> preserveWrapperCallback;
|
||||
js::MainThreadData<const JSWrapObjectCallbacks*> wrapObjectCallbacks;
|
||||
js::MainThreadData<js::PreserveWrapperCallback> preserveWrapperCallback;
|
||||
|
||||
js::ActiveThreadData<js::ScriptEnvironmentPreparer*> scriptEnvironmentPreparer;
|
||||
js::MainThreadData<js::ScriptEnvironmentPreparer*> scriptEnvironmentPreparer;
|
||||
|
||||
js::ActiveThreadData<js::CTypesActivityCallback> ctypesActivityCallback;
|
||||
js::MainThreadData<js::CTypesActivityCallback> ctypesActivityCallback;
|
||||
|
||||
private:
|
||||
js::WriteOnceData<const js::Class*> windowProxyClass_;
|
||||
|
@ -422,7 +422,7 @@ struct JSRuntime : public js::MallocProvider<JSRuntime>
|
|||
|
||||
private:
|
||||
// List of non-ephemeron weak containers to sweep during beginSweepingSweepGroup.
|
||||
js::ActiveThreadData<mozilla::LinkedList<JS::detail::WeakCacheBase>> weakCaches_;
|
||||
js::MainThreadData<mozilla::LinkedList<JS::detail::WeakCacheBase>> weakCaches_;
|
||||
public:
|
||||
mozilla::LinkedList<JS::detail::WeakCacheBase>& weakCaches() { return weakCaches_.ref(); }
|
||||
void registerWeakCache(JS::detail::WeakCacheBase* cachep) {
|
||||
|
@ -444,14 +444,14 @@ struct JSRuntime : public js::MallocProvider<JSRuntime>
|
|||
* List of all enabled Debuggers that have onNewGlobalObject handler
|
||||
* methods established.
|
||||
*/
|
||||
js::ActiveThreadData<WatchersList> onNewGlobalObjectWatchers_;
|
||||
js::MainThreadData<WatchersList> onNewGlobalObjectWatchers_;
|
||||
|
||||
public:
|
||||
WatchersList& onNewGlobalObjectWatchers() { return onNewGlobalObjectWatchers_.ref(); }
|
||||
|
||||
private:
|
||||
/* Linked list of all Debugger objects in the runtime. */
|
||||
js::ActiveThreadData<mozilla::LinkedList<js::Debugger>> debuggerList_;
|
||||
js::MainThreadData<mozilla::LinkedList<js::Debugger>> debuggerList_;
|
||||
public:
|
||||
mozilla::LinkedList<js::Debugger>& debuggerList() { return debuggerList_.ref(); }
|
||||
|
||||
|
@ -480,10 +480,7 @@ struct JSRuntime : public js::MallocProvider<JSRuntime>
|
|||
bool activeThreadHasScriptDataAccess;
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Number of zones which may be operated on by non-cooperating helper
|
||||
* threads.
|
||||
*/
|
||||
// Number of zones which may be operated on by helper threads.
|
||||
mozilla::Atomic<size_t> numActiveHelperThreadZones;
|
||||
|
||||
friend class js::AutoLockForExclusiveAccess;
|
||||
|
@ -516,19 +513,19 @@ struct JSRuntime : public js::MallocProvider<JSRuntime>
|
|||
// How many compartments there are across all zones. This number includes
|
||||
// off thread context compartments, so it isn't necessarily equal to the
|
||||
// number of compartments visited by CompartmentsIter.
|
||||
js::ActiveThreadData<size_t> numCompartments;
|
||||
js::MainThreadData<size_t> numCompartments;
|
||||
|
||||
/* Locale-specific callbacks for string conversion. */
|
||||
js::ActiveThreadData<const JSLocaleCallbacks*> localeCallbacks;
|
||||
js::MainThreadData<const JSLocaleCallbacks*> localeCallbacks;
|
||||
|
||||
/* Default locale for Internationalization API */
|
||||
js::ActiveThreadData<char*> defaultLocale;
|
||||
js::MainThreadData<char*> defaultLocale;
|
||||
|
||||
/* If true, new scripts must be created with PC counter information. */
|
||||
js::ActiveThreadOrIonCompileData<bool> profilingScripts;
|
||||
js::MainThreadOrIonCompileData<bool> profilingScripts;
|
||||
|
||||
/* Strong references on scripts held for PCCount profiling API. */
|
||||
js::ActiveThreadData<JS::PersistentRooted<js::ScriptAndCountsVector>*> scriptAndCountsVector;
|
||||
js::MainThreadData<JS::PersistentRooted<js::ScriptAndCountsVector>*> scriptAndCountsVector;
|
||||
|
||||
private:
|
||||
/* Code coverage output. */
|
||||
|
@ -789,7 +786,7 @@ struct JSRuntime : public js::MallocProvider<JSRuntime>
|
|||
js::WriteOnceData<js::WellKnownSymbols*> wellKnownSymbols;
|
||||
|
||||
/* Shared Intl data for this runtime. */
|
||||
js::ActiveThreadData<js::intl::SharedIntlData> sharedIntlData;
|
||||
js::MainThreadData<js::intl::SharedIntlData> sharedIntlData;
|
||||
|
||||
void traceSharedIntlData(JSTracer* trc);
|
||||
|
||||
|
@ -862,7 +859,7 @@ struct JSRuntime : public js::MallocProvider<JSRuntime>
|
|||
mozilla::Atomic<bool> offthreadIonCompilationEnabled_;
|
||||
mozilla::Atomic<bool> parallelParsingEnabled_;
|
||||
|
||||
js::ActiveThreadData<bool> autoWritableJitCodeActive_;
|
||||
js::MainThreadData<bool> autoWritableJitCodeActive_;
|
||||
|
||||
public:
|
||||
|
||||
|
@ -887,20 +884,20 @@ struct JSRuntime : public js::MallocProvider<JSRuntime>
|
|||
}
|
||||
|
||||
/* See comment for JS::SetOutOfMemoryCallback in jsapi.h. */
|
||||
js::ActiveThreadData<JS::OutOfMemoryCallback> oomCallback;
|
||||
js::ActiveThreadData<void*> oomCallbackData;
|
||||
js::MainThreadData<JS::OutOfMemoryCallback> oomCallback;
|
||||
js::MainThreadData<void*> oomCallbackData;
|
||||
|
||||
/*
|
||||
* Debugger.Memory functions like takeCensus use this embedding-provided
|
||||
* function to assess the size of malloc'd blocks of memory.
|
||||
*/
|
||||
js::ActiveThreadData<mozilla::MallocSizeOf> debuggerMallocSizeOf;
|
||||
js::MainThreadData<mozilla::MallocSizeOf> debuggerMallocSizeOf;
|
||||
|
||||
/* Last time at which an animation was played for this runtime. */
|
||||
mozilla::Atomic<int64_t> lastAnimationTime;
|
||||
|
||||
private:
|
||||
js::ActiveThreadData<js::PerformanceMonitoring> performanceMonitoring_;
|
||||
js::MainThreadData<js::PerformanceMonitoring> performanceMonitoring_;
|
||||
public:
|
||||
js::PerformanceMonitoring& performanceMonitoring() { return performanceMonitoring_.ref(); }
|
||||
|
||||
|
@ -930,7 +927,7 @@ struct JSRuntime : public js::MallocProvider<JSRuntime>
|
|||
friend class JS::AutoEnterCycleCollection;
|
||||
|
||||
private:
|
||||
js::ActiveThreadData<js::RuntimeCaches> caches_;
|
||||
js::MainThreadData<js::RuntimeCaches> caches_;
|
||||
public:
|
||||
js::RuntimeCaches& caches() { return caches_.ref(); }
|
||||
|
||||
|
|
|
@ -869,7 +869,7 @@ TraceLoggerThreadState::init()
|
|||
"\n"
|
||||
"usage: TLOPTIONS=option,option,option,... where options can be:\n"
|
||||
"\n"
|
||||
" EnableActiveThread Start logging cooperating threads immediately.\n"
|
||||
" EnableMainThread Start logging main threads immediately.\n"
|
||||
" EnableOffThread Start logging helper threads immediately.\n"
|
||||
" EnableGraph Enable spewing the tracelogging graph to a file.\n"
|
||||
" Errors Report errors during tracing to stderr.\n"
|
||||
|
@ -879,8 +879,8 @@ TraceLoggerThreadState::init()
|
|||
/*NOTREACHED*/
|
||||
}
|
||||
|
||||
if (strstr(options, "EnableActiveThread"))
|
||||
cooperatingThreadEnabled = true;
|
||||
if (strstr(options, "EnableMainThread"))
|
||||
mainThreadEnabled = true;
|
||||
if (strstr(options, "EnableOffThread"))
|
||||
helperThreadEnabled = true;
|
||||
if (strstr(options, "EnableGraph"))
|
||||
|
@ -985,7 +985,7 @@ TraceLoggerThreadState::forCurrentThread(JSContext* maybecx)
|
|||
if (graphSpewingEnabled)
|
||||
logger->initGraph();
|
||||
|
||||
if (CurrentHelperThread() ? helperThreadEnabled : cooperatingThreadEnabled)
|
||||
if (CurrentHelperThread() ? helperThreadEnabled : mainThreadEnabled)
|
||||
logger->enable();
|
||||
}
|
||||
|
||||
|
|
|
@ -378,7 +378,7 @@ class TraceLoggerThreadState
|
|||
#endif
|
||||
|
||||
bool enabledTextIds[TraceLogger_Last];
|
||||
bool cooperatingThreadEnabled;
|
||||
bool mainThreadEnabled;
|
||||
bool helperThreadEnabled;
|
||||
bool graphSpewingEnabled;
|
||||
bool spewErrors;
|
||||
|
@ -405,7 +405,7 @@ class TraceLoggerThreadState
|
|||
#ifdef DEBUG
|
||||
initialized(false),
|
||||
#endif
|
||||
cooperatingThreadEnabled(false),
|
||||
mainThreadEnabled(false),
|
||||
helperThreadEnabled(false),
|
||||
graphSpewingEnabled(false),
|
||||
spewErrors(false),
|
||||
|
|
|
@ -230,10 +230,10 @@ AutoXDRTree::Key
|
|||
XDRIncrementalEncoder::getTreeKey(JSFunction* fun) const
|
||||
{
|
||||
if (fun->isInterpretedLazy()) {
|
||||
static_assert(sizeof(fun->lazyScript()->begin()) == 4 ||
|
||||
sizeof(fun->lazyScript()->end()) == 4,
|
||||
static_assert(sizeof(fun->lazyScript()->sourceStart()) == 4 ||
|
||||
sizeof(fun->lazyScript()->sourceEnd()) == 4,
|
||||
"AutoXDRTree key requires LazyScripts positions to be uint32");
|
||||
return uint64_t(fun->lazyScript()->begin()) << 32 | fun->lazyScript()->end();
|
||||
return uint64_t(fun->lazyScript()->sourceStart()) << 32 | fun->lazyScript()->sourceEnd();
|
||||
}
|
||||
|
||||
if (fun->isInterpreted()) {
|
||||
|
|
|
@ -135,8 +135,8 @@
|
|||
# include "jit/mips64/Assembler-mips64.h"
|
||||
#endif
|
||||
|
||||
#include "wasm/WasmBinaryIterator.h"
|
||||
#include "wasm/WasmGenerator.h"
|
||||
#include "wasm/WasmOpIter.h"
|
||||
#include "wasm/WasmSignalHandlers.h"
|
||||
#include "wasm/WasmValidate.h"
|
||||
|
||||
|
|
|
@ -592,14 +592,14 @@ struct OpBytes
|
|||
OpBytes() = default;
|
||||
};
|
||||
|
||||
static const char NameSectionName[] = "name";
|
||||
static const char NameSectionName[] = "name";
|
||||
static const char SourceMappingURLSectionName[] = "sourceMappingURL";
|
||||
|
||||
enum class NameType
|
||||
{
|
||||
Module = 0,
|
||||
Function = 1,
|
||||
Local = 2
|
||||
Module = 0,
|
||||
Function = 1,
|
||||
Local = 2
|
||||
};
|
||||
|
||||
// These limits are agreed upon with other engines for consistency.
|
||||
|
|
|
@ -23,7 +23,7 @@
|
|||
|
||||
#include "vm/JSCompartment.h"
|
||||
#include "vm/JSContext.h"
|
||||
#include "wasm/WasmBinaryIterator.h"
|
||||
#include "wasm/WasmOpIter.h"
|
||||
#include "wasm/WasmValidate.h"
|
||||
|
||||
using namespace js;
|
||||
|
@ -2277,7 +2277,7 @@ wasm::BinaryToAst(JSContext* cx, const uint8_t* bytes, uint32_t length, LifoAllo
|
|||
return false;
|
||||
|
||||
UniqueChars error;
|
||||
Decoder d(bytes, bytes + length, 0, &error, /* resilient */ true);
|
||||
Decoder d(bytes, bytes + length, 0, &error, nullptr, /* resilient */ true);
|
||||
AstDecodeContext c(cx, lifo, d, *result, true);
|
||||
|
||||
if (!AstDecodeEnvironment(c) ||
|
||||
|
|
|
@ -24,9 +24,9 @@
|
|||
#include "jit/ProcessExecutableMemory.h"
|
||||
#include "util/Text.h"
|
||||
#include "wasm/WasmBaselineCompile.h"
|
||||
#include "wasm/WasmBinaryIterator.h"
|
||||
#include "wasm/WasmGenerator.h"
|
||||
#include "wasm/WasmIonCompile.h"
|
||||
#include "wasm/WasmOpIter.h"
|
||||
#include "wasm/WasmSignalHandlers.h"
|
||||
#include "wasm/WasmValidate.h"
|
||||
|
||||
|
@ -420,11 +420,12 @@ InitialCompileFlags(const CompileArgs& args, Decoder& d, CompileMode* mode, Tier
|
|||
}
|
||||
|
||||
SharedModule
|
||||
wasm::CompileBuffer(const CompileArgs& args, const ShareableBytes& bytecode, UniqueChars* error)
|
||||
wasm::CompileBuffer(const CompileArgs& args, const ShareableBytes& bytecode, UniqueChars* error,
|
||||
UniqueCharsVector* warnings)
|
||||
{
|
||||
MOZ_RELEASE_ASSERT(wasm::HaveSignalHandlers());
|
||||
|
||||
Decoder d(bytecode.bytes, 0, error);
|
||||
Decoder d(bytecode.bytes, 0, error, warnings);
|
||||
|
||||
CompileMode mode;
|
||||
Tier tier;
|
||||
|
@ -486,8 +487,8 @@ class StreamingDecoder
|
|||
public:
|
||||
StreamingDecoder(const ModuleEnvironment& env, const Bytes& begin,
|
||||
const ExclusiveStreamEnd& streamEnd, const Atomic<bool>& cancelled,
|
||||
UniqueChars* error)
|
||||
: d_(begin, env.codeSection->start, error),
|
||||
UniqueChars* error, UniqueCharsVector* warnings)
|
||||
: d_(begin, env.codeSection->start, error, warnings),
|
||||
streamEnd_(streamEnd),
|
||||
cancelled_(cancelled)
|
||||
{}
|
||||
|
@ -567,14 +568,15 @@ wasm::CompileStreaming(const CompileArgs& args,
|
|||
const ExclusiveStreamEnd& codeStreamEnd,
|
||||
const ExclusiveTailBytesPtr& tailBytesPtr,
|
||||
const Atomic<bool>& cancelled,
|
||||
UniqueChars* error)
|
||||
UniqueChars* error,
|
||||
UniqueCharsVector* warnings)
|
||||
{
|
||||
MOZ_ASSERT(wasm::HaveSignalHandlers());
|
||||
|
||||
Maybe<ModuleEnvironment> env;
|
||||
|
||||
{
|
||||
Decoder d(envBytes, 0, error);
|
||||
Decoder d(envBytes, 0, error, warnings);
|
||||
|
||||
CompileMode mode;
|
||||
Tier tier;
|
||||
|
@ -595,7 +597,7 @@ wasm::CompileStreaming(const CompileArgs& args,
|
|||
|
||||
{
|
||||
MOZ_ASSERT(env->codeSection->size == codeBytes.length());
|
||||
StreamingDecoder d(*env, codeBytes, codeStreamEnd, cancelled, error);
|
||||
StreamingDecoder d(*env, codeBytes, codeStreamEnd, cancelled, error, warnings);
|
||||
|
||||
if (!DecodeCodeSection(*env, d, mg))
|
||||
return nullptr;
|
||||
|
@ -615,7 +617,7 @@ wasm::CompileStreaming(const CompileArgs& args,
|
|||
const Bytes& tailBytes = *tailBytesPtr.lock();
|
||||
|
||||
{
|
||||
Decoder d(tailBytes, env->codeSection->end(), error);
|
||||
Decoder d(tailBytes, env->codeSection->end(), error, warnings);
|
||||
|
||||
if (!DecodeModuleTail(d, env.ptr()))
|
||||
return nullptr;
|
||||
|
|
|
@ -86,7 +86,10 @@ EstimateCompiledCodeSize(Tier tier, size_t bytecodeSize);
|
|||
// - *error is null and the caller should report out-of-memory.
|
||||
|
||||
SharedModule
|
||||
CompileBuffer(const CompileArgs& args, const ShareableBytes& bytecode, UniqueChars* error);
|
||||
CompileBuffer(const CompileArgs& args,
|
||||
const ShareableBytes& bytecode,
|
||||
UniqueChars* error,
|
||||
UniqueCharsVector* warnings);
|
||||
|
||||
// Attempt to compile the second tier of the given wasm::Module, returning whether
|
||||
// tier-2 compilation succeeded and Module::finishTier2 was called.
|
||||
|
@ -121,7 +124,8 @@ CompileStreaming(const CompileArgs& args,
|
|||
const ExclusiveStreamEnd& codeStreamEnd,
|
||||
const ExclusiveTailBytesPtr& tailBytesPtr,
|
||||
const Atomic<bool>& cancelled,
|
||||
UniqueChars* error);
|
||||
UniqueChars* error,
|
||||
UniqueCharsVector* warnings);
|
||||
|
||||
} // namespace wasm
|
||||
} // namespace js
|
||||
|
|
|
@ -23,8 +23,8 @@
|
|||
#include "jit/CodeGenerator.h"
|
||||
|
||||
#include "wasm/WasmBaselineCompile.h"
|
||||
#include "wasm/WasmBinaryIterator.h"
|
||||
#include "wasm/WasmGenerator.h"
|
||||
#include "wasm/WasmOpIter.h"
|
||||
#include "wasm/WasmSignalHandlers.h"
|
||||
#include "wasm/WasmValidate.h"
|
||||
|
||||
|
|
|
@ -337,7 +337,8 @@ wasm::Eval(JSContext* cx, Handle<TypedArrayObject*> code, HandleObject importObj
|
|||
return false;
|
||||
|
||||
UniqueChars error;
|
||||
SharedModule module = CompileBuffer(*compileArgs, *bytecode, &error);
|
||||
UniqueCharsVector warnings;
|
||||
SharedModule module = CompileBuffer(*compileArgs, *bytecode, &error, &warnings);
|
||||
if (!module) {
|
||||
if (error) {
|
||||
JS_ReportErrorNumberUTF8(cx, GetErrorMessage, nullptr, JSMSG_WASM_COMPILE_ERROR,
|
||||
|
@ -871,6 +872,27 @@ InitCompileArgs(JSContext* cx)
|
|||
return compileArgs;
|
||||
}
|
||||
|
||||
static bool
|
||||
ReportCompileWarnings(JSContext* cx, const UniqueCharsVector& warnings)
|
||||
{
|
||||
// Avoid spamming the console.
|
||||
size_t numWarnings = Min<size_t>(warnings.length(), 3);
|
||||
|
||||
for (size_t i = 0; i < numWarnings; i++) {
|
||||
if (!JS_ReportErrorFlagsAndNumberASCII(cx, JSREPORT_WARNING, GetErrorMessage, nullptr,
|
||||
JSMSG_WASM_COMPILE_WARNING, warnings[i].get()))
|
||||
return false;
|
||||
}
|
||||
|
||||
if (warnings.length() > numWarnings) {
|
||||
if (!JS_ReportErrorFlagsAndNumberASCII(cx, JSREPORT_WARNING, GetErrorMessage, nullptr,
|
||||
JSMSG_WASM_COMPILE_WARNING, "other warnings suppressed"))
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/* static */ bool
|
||||
WasmModuleObject::construct(JSContext* cx, unsigned argc, Value* vp)
|
||||
{
|
||||
|
@ -896,7 +918,8 @@ WasmModuleObject::construct(JSContext* cx, unsigned argc, Value* vp)
|
|||
return false;
|
||||
|
||||
UniqueChars error;
|
||||
SharedModule module = CompileBuffer(*compileArgs, *bytecode, &error);
|
||||
UniqueCharsVector warnings;
|
||||
SharedModule module = CompileBuffer(*compileArgs, *bytecode, &error, &warnings);
|
||||
if (!module) {
|
||||
if (error) {
|
||||
JS_ReportErrorNumberUTF8(cx, GetErrorMessage, nullptr, JSMSG_WASM_COMPILE_ERROR,
|
||||
|
@ -907,6 +930,9 @@ WasmModuleObject::construct(JSContext* cx, unsigned argc, Value* vp)
|
|||
return false;
|
||||
}
|
||||
|
||||
if (!ReportCompileWarnings(cx, warnings))
|
||||
return false;
|
||||
|
||||
RootedObject proto(cx, &cx->global()->getPrototype(JSProto_WasmModule).toObject());
|
||||
RootedObject moduleObj(cx, WasmModuleObject::create(cx, *module, proto));
|
||||
if (!moduleObj)
|
||||
|
@ -2334,7 +2360,8 @@ RejectWithPendingException(JSContext* cx, Handle<PromiseObject*> promise)
|
|||
}
|
||||
|
||||
static bool
|
||||
Reject(JSContext* cx, const CompileArgs& args, UniqueChars error, Handle<PromiseObject*> promise)
|
||||
Reject(JSContext* cx, const CompileArgs& args, Handle<PromiseObject*> promise,
|
||||
const UniqueChars& error)
|
||||
{
|
||||
if (!error) {
|
||||
ReportOutOfMemory(cx);
|
||||
|
@ -2371,8 +2398,11 @@ Reject(JSContext* cx, const CompileArgs& args, UniqueChars error, Handle<Promise
|
|||
|
||||
static bool
|
||||
Resolve(JSContext* cx, Module& module, Handle<PromiseObject*> promise, bool instantiate,
|
||||
HandleObject importObj)
|
||||
HandleObject importObj, const UniqueCharsVector& warnings)
|
||||
{
|
||||
if (!ReportCompileWarnings(cx, warnings))
|
||||
return false;
|
||||
|
||||
RootedObject proto(cx, &cx->global()->getPrototype(JSProto_WasmModule).toObject());
|
||||
RootedObject moduleObj(cx, WasmModuleObject::create(cx, module, proto));
|
||||
if (!moduleObj)
|
||||
|
@ -2413,6 +2443,7 @@ struct CompileBufferTask : PromiseHelperTask
|
|||
MutableBytes bytecode;
|
||||
SharedCompileArgs compileArgs;
|
||||
UniqueChars error;
|
||||
UniqueCharsVector warnings;
|
||||
SharedModule module;
|
||||
bool instantiate;
|
||||
PersistentRootedObject importObj;
|
||||
|
@ -2436,13 +2467,13 @@ struct CompileBufferTask : PromiseHelperTask
|
|||
}
|
||||
|
||||
void execute() override {
|
||||
module = CompileBuffer(*compileArgs, *bytecode, &error);
|
||||
module = CompileBuffer(*compileArgs, *bytecode, &error, &warnings);
|
||||
}
|
||||
|
||||
bool resolve(JSContext* cx, Handle<PromiseObject*> promise) override {
|
||||
return module
|
||||
? Resolve(cx, *module, promise, instantiate, importObj)
|
||||
: Reject(cx, *compileArgs, Move(error), promise);
|
||||
? Resolve(cx, *module, promise, instantiate, importObj, warnings)
|
||||
: Reject(cx, *compileArgs, promise, error);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -2640,6 +2671,7 @@ class CompileStreamTask : public PromiseHelperTask, public JS::StreamConsumer
|
|||
// Mutated on helper thread (execute()):
|
||||
SharedModule module_;
|
||||
UniqueChars compileError_;
|
||||
UniqueCharsVector warnings_;
|
||||
|
||||
// Called on some thread before consumeChunk() or streamClosed():
|
||||
|
||||
|
@ -2773,7 +2805,7 @@ class CompileStreamTask : public PromiseHelperTask, public JS::StreamConsumer
|
|||
rejectAndDestroyBeforeHelperThreadStarted(JSMSG_OUT_OF_MEMORY);
|
||||
return;
|
||||
}
|
||||
module_ = CompileBuffer(*compileArgs_, *bytecode, &compileError_);
|
||||
module_ = CompileBuffer(*compileArgs_, *bytecode, &compileError_, &warnings_);
|
||||
setClosedAndDestroyBeforeHelperThreadStarted();
|
||||
return;
|
||||
}
|
||||
|
@ -2810,8 +2842,14 @@ class CompileStreamTask : public PromiseHelperTask, public JS::StreamConsumer
|
|||
// Called on a helper thread:
|
||||
|
||||
void execute() override {
|
||||
module_ = CompileStreaming(*compileArgs_, envBytes_, codeBytes_, exclusiveCodeStreamEnd_,
|
||||
exclusiveTailBytes_, streamFailed_, &compileError_);
|
||||
module_ = CompileStreaming(*compileArgs_,
|
||||
envBytes_,
|
||||
codeBytes_,
|
||||
exclusiveCodeStreamEnd_,
|
||||
exclusiveTailBytes_,
|
||||
streamFailed_,
|
||||
&compileError_,
|
||||
&warnings_);
|
||||
|
||||
// When execute() returns, the CompileStreamTask will be dispatched
|
||||
// back to its JS thread to call resolve() and then be destroyed. We
|
||||
|
@ -2828,10 +2866,10 @@ class CompileStreamTask : public PromiseHelperTask, public JS::StreamConsumer
|
|||
MOZ_ASSERT(streamState_.lock() == Closed);
|
||||
MOZ_ASSERT_IF(module_, !streamFailed_ && !streamError_ && !compileError_);
|
||||
return module_
|
||||
? Resolve(cx, *module_, promise, instantiate_, importObj_)
|
||||
? Resolve(cx, *module_, promise, instantiate_, importObj_, warnings_)
|
||||
: streamError_
|
||||
? RejectWithErrorNumber(cx, *streamError_, promise)
|
||||
: Reject(cx, *compileArgs_, Move(compileError_), promise);
|
||||
: Reject(cx, *compileArgs_, promise, compileError_);
|
||||
}
|
||||
|
||||
public:
|
||||
|
|
|
@ -603,7 +603,8 @@ wasm::DeserializeModule(PRFileDesc* bytecodeFile, PRFileDesc* maybeCompiledFile,
|
|||
args->sharedMemoryEnabled = true;
|
||||
|
||||
UniqueChars error;
|
||||
return CompileBuffer(*args, *bytecode, &error);
|
||||
UniqueCharsVector warnings;
|
||||
return CompileBuffer(*args, *bytecode, &error, &warnings);
|
||||
}
|
||||
|
||||
/* virtual */ void
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "wasm/WasmBinaryIterator.h"
|
||||
#include "wasm/WasmOpIter.h"
|
||||
|
||||
using namespace js;
|
||||
using namespace js::jit;
|
|
@ -16,8 +16,8 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef wasm_binary_iterator_h
|
||||
#define wasm_binary_iterator_h
|
||||
#ifndef wasm_op_iter_h
|
||||
#define wasm_op_iter_h
|
||||
|
||||
#include "mozilla/Poison.h"
|
||||
|
||||
|
@ -2244,4 +2244,4 @@ template<> struct IsPod<js::wasm::ControlStackEntry<Nothing>> : TrueType {};
|
|||
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // wasm_iterator_h
|
||||
#endif // wasm_op_iter_h
|
|
@ -328,7 +328,7 @@ SuppressGC(MacroAssembler& masm, int32_t increment, Register scratch)
|
|||
masm.loadPtr(Address(WasmTlsReg, offsetof(TlsData, cx)), scratch);
|
||||
masm.add32(Imm32(increment),
|
||||
Address(scratch, offsetof(JSContext, suppressGC) +
|
||||
js::ThreadLocalData<int32_t>::offsetOfValue()));
|
||||
js::ThreadData<int32_t>::offsetOfValue()));
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
|
@ -108,6 +108,7 @@ typedef UniquePtr<Bytes> UniqueBytes;
|
|||
typedef UniquePtr<const Bytes> UniqueConstBytes;
|
||||
typedef Vector<char, 0, SystemAllocPolicy> UTF8Bytes;
|
||||
typedef Vector<Instance*, 0, SystemAllocPolicy> InstanceVector;
|
||||
typedef Vector<UniqueChars, 0, SystemAllocPolicy> UniqueCharsVector;
|
||||
|
||||
// To call Vector::podResizeToFit, a type must specialize mozilla::IsPod
|
||||
// which is pretty verbose to do within js::wasm, so factor that process out
|
||||
|
|
|
@ -19,18 +19,20 @@
|
|||
#include "wasm/WasmValidate.h"
|
||||
|
||||
#include "mozilla/CheckedInt.h"
|
||||
#include "mozilla/Unused.h"
|
||||
|
||||
#include "jit/JitOptions.h"
|
||||
#include "js/Printf.h"
|
||||
#include "vm/JSCompartment.h"
|
||||
#include "vm/JSContext.h"
|
||||
#include "wasm/WasmBinaryIterator.h"
|
||||
#include "wasm/WasmOpIter.h"
|
||||
|
||||
using namespace js;
|
||||
using namespace js::jit;
|
||||
using namespace js::wasm;
|
||||
|
||||
using mozilla::CheckedInt;
|
||||
using mozilla::Unused;
|
||||
|
||||
// Decoder implementation.
|
||||
|
||||
|
@ -47,6 +49,22 @@ Decoder::failf(const char* msg, ...)
|
|||
return fail(str.get());
|
||||
}
|
||||
|
||||
void
|
||||
Decoder::warnf(const char* msg, ...)
|
||||
{
|
||||
if (!warnings_)
|
||||
return;
|
||||
|
||||
va_list ap;
|
||||
va_start(ap, msg);
|
||||
UniqueChars str(JS_vsmprintf(msg, ap));
|
||||
va_end(ap);
|
||||
if (!str)
|
||||
return;
|
||||
|
||||
Unused << warnings_->append(Move(str));
|
||||
}
|
||||
|
||||
bool
|
||||
Decoder::fail(size_t errorOffset, const char* msg)
|
||||
{
|
||||
|
@ -192,7 +210,7 @@ Decoder::startCustomSection(const char* expected, size_t expectedLength, ModuleE
|
|||
}
|
||||
|
||||
// Otherwise, blindly skip the custom section and keep looking.
|
||||
finishCustomSection(**range);
|
||||
skipAndFinishCustomSection(**range);
|
||||
range->reset();
|
||||
}
|
||||
MOZ_CRASH("unreachable");
|
||||
|
@ -207,7 +225,35 @@ Decoder::startCustomSection(const char* expected, size_t expectedLength, ModuleE
|
|||
}
|
||||
|
||||
void
|
||||
Decoder::finishCustomSection(const SectionRange& range)
|
||||
Decoder::finishCustomSection(const char* name, const SectionRange& range)
|
||||
{
|
||||
MOZ_ASSERT(cur_ >= beg_);
|
||||
MOZ_ASSERT(cur_ <= end_);
|
||||
|
||||
if (error_ && *error_) {
|
||||
warnf("in the '%s' custom section: %s", name, error_->get());
|
||||
skipAndFinishCustomSection(range);
|
||||
return;
|
||||
}
|
||||
|
||||
uint32_t actualSize = currentOffset() - range.start;
|
||||
if (range.size != actualSize) {
|
||||
if (actualSize < range.size) {
|
||||
warnf("in the '%s' custom section: %" PRIu32 " unconsumed bytes",
|
||||
name, uint32_t(range.size - actualSize));
|
||||
} else {
|
||||
warnf("in the '%s' custom section: %" PRIu32 " bytes consumed past the end",
|
||||
name, uint32_t(actualSize - range.size));
|
||||
}
|
||||
skipAndFinishCustomSection(range);
|
||||
return;
|
||||
}
|
||||
|
||||
// Nothing to do! (c.f. skipAndFinishCustomSection())
|
||||
}
|
||||
|
||||
void
|
||||
Decoder::skipAndFinishCustomSection(const SectionRange& range)
|
||||
{
|
||||
MOZ_ASSERT(cur_ >= beg_);
|
||||
MOZ_ASSERT(cur_ <= end_);
|
||||
|
@ -225,7 +271,7 @@ Decoder::skipCustomSection(ModuleEnvironment* env)
|
|||
if (!range)
|
||||
return fail("expected custom section");
|
||||
|
||||
finishCustomSection(*range);
|
||||
skipAndFinishCustomSection(*range);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -234,29 +280,59 @@ Decoder::startNameSubsection(NameType nameType, Maybe<uint32_t>* endOffset)
|
|||
{
|
||||
MOZ_ASSERT(!*endOffset);
|
||||
|
||||
const uint8_t* initialPosition = cur_;
|
||||
const uint8_t* const initialPosition = cur_;
|
||||
|
||||
uint8_t nameTypeValue;
|
||||
if (!readFixedU8(&nameTypeValue))
|
||||
return false;
|
||||
goto rewind;
|
||||
|
||||
if (nameTypeValue != uint8_t(nameType)) {
|
||||
cur_ = initialPosition;
|
||||
return true;
|
||||
}
|
||||
if (nameTypeValue != uint8_t(nameType))
|
||||
goto rewind;
|
||||
|
||||
uint32_t payloadLength;
|
||||
if (!readVarU32(&payloadLength) || payloadLength > bytesRemain())
|
||||
return false;
|
||||
return fail("bad name subsection payload length");
|
||||
|
||||
*endOffset = Some(currentOffset() + payloadLength);
|
||||
return true;
|
||||
|
||||
rewind:
|
||||
cur_ = initialPosition;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
Decoder::finishNameSubsection(uint32_t endOffset)
|
||||
Decoder::finishNameSubsection(uint32_t expected)
|
||||
{
|
||||
return endOffset == uint32_t(currentOffset());
|
||||
uint32_t actual = currentOffset();
|
||||
if (expected != actual) {
|
||||
return failf("bad name subsection length (expected: %" PRIu32 ", actual: %" PRIu32 ")",
|
||||
expected, actual);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
Decoder::skipNameSubsection()
|
||||
{
|
||||
uint8_t nameTypeValue;
|
||||
if (!readFixedU8(&nameTypeValue))
|
||||
return fail("unable to read name subsection id");
|
||||
|
||||
switch (nameTypeValue) {
|
||||
case uint8_t(NameType::Module):
|
||||
case uint8_t(NameType::Function):
|
||||
return fail("out of order name subsections");
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
uint32_t payloadLength;
|
||||
if (!readVarU32(&payloadLength) || !readBytes(payloadLength))
|
||||
return fail("bad name subsection payload length");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Misc helpers.
|
||||
|
@ -1885,11 +1961,11 @@ DecodeModuleNameSubsection(Decoder& d)
|
|||
|
||||
uint32_t nameLength;
|
||||
if (!d.readVarU32(&nameLength))
|
||||
return false;
|
||||
return d.fail("failed to read module name length");
|
||||
|
||||
const uint8_t* bytes;
|
||||
if (!d.readBytes(nameLength, &bytes))
|
||||
return false;
|
||||
return d.fail("failed to read module name bytes");
|
||||
|
||||
// Do nothing with module name for now; a future patch will incorporate the
|
||||
// module name into the callstack format.
|
||||
|
@ -1908,22 +1984,22 @@ DecodeFunctionNameSubsection(Decoder& d, ModuleEnvironment* env)
|
|||
|
||||
uint32_t nameCount = 0;
|
||||
if (!d.readVarU32(&nameCount) || nameCount > MaxFuncs)
|
||||
return false;
|
||||
return d.fail("bad function name count");
|
||||
|
||||
NameInBytecodeVector funcNames;
|
||||
|
||||
for (uint32_t i = 0; i < nameCount; ++i) {
|
||||
uint32_t funcIndex = 0;
|
||||
if (!d.readVarU32(&funcIndex))
|
||||
return false;
|
||||
return d.fail("unable to read function index");
|
||||
|
||||
// Names must refer to real functions and be given in ascending order.
|
||||
if (funcIndex >= env->numFuncs() || funcIndex < funcNames.length())
|
||||
return false;
|
||||
return d.fail("invalid function index");
|
||||
|
||||
uint32_t nameLength = 0;
|
||||
if (!d.readVarU32(&nameLength) || nameLength > MaxStringLength)
|
||||
return false;
|
||||
return d.fail("unable to read function name length");
|
||||
|
||||
if (!nameLength)
|
||||
continue;
|
||||
|
@ -1934,7 +2010,7 @@ DecodeFunctionNameSubsection(Decoder& d, ModuleEnvironment* env)
|
|||
funcNames[funcIndex] = NameInBytecode(d.currentOffset(), nameLength);
|
||||
|
||||
if (!d.readBytes(nameLength))
|
||||
return false;
|
||||
return d.fail("unable to read function name bytes");
|
||||
}
|
||||
|
||||
if (!d.finishNameSubsection(*endOffset))
|
||||
|
@ -1963,12 +2039,13 @@ DecodeNameSection(Decoder& d, ModuleEnvironment* env)
|
|||
if (!DecodeFunctionNameSubsection(d, env))
|
||||
goto finish;
|
||||
|
||||
// The names we care about have already been extracted into 'env' so don't
|
||||
// bother decoding the rest of the name section. finishCustomSection() will
|
||||
// skip to the end of the name section (as it would for any other error).
|
||||
while (d.currentOffset() < range->end()) {
|
||||
if (!d.skipNameSubsection())
|
||||
goto finish;
|
||||
}
|
||||
|
||||
finish:
|
||||
d.finishCustomSection(*range);
|
||||
d.finishCustomSection(NameSectionName, *range);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -354,6 +354,7 @@ class Decoder
|
|||
const uint8_t* cur_;
|
||||
const size_t offsetInModule_;
|
||||
UniqueChars* error_;
|
||||
UniqueCharsVector* warnings_;
|
||||
bool resilientMode_;
|
||||
|
||||
template <class T>
|
||||
|
@ -439,28 +440,32 @@ class Decoder
|
|||
|
||||
public:
|
||||
Decoder(const uint8_t* begin, const uint8_t* end, size_t offsetInModule, UniqueChars* error,
|
||||
bool resilientMode = false)
|
||||
UniqueCharsVector* warnings = nullptr, bool resilientMode = false)
|
||||
: beg_(begin),
|
||||
end_(end),
|
||||
cur_(begin),
|
||||
offsetInModule_(offsetInModule),
|
||||
error_(error),
|
||||
warnings_(warnings),
|
||||
resilientMode_(resilientMode)
|
||||
{
|
||||
MOZ_ASSERT(begin <= end);
|
||||
}
|
||||
explicit Decoder(const Bytes& bytes, size_t offsetInModule = 0, UniqueChars* error = nullptr)
|
||||
explicit Decoder(const Bytes& bytes, size_t offsetInModule = 0, UniqueChars* error = nullptr,
|
||||
UniqueCharsVector* warnings = nullptr)
|
||||
: beg_(bytes.begin()),
|
||||
end_(bytes.end()),
|
||||
cur_(bytes.begin()),
|
||||
offsetInModule_(offsetInModule),
|
||||
error_(error),
|
||||
warnings_(warnings),
|
||||
resilientMode_(false)
|
||||
{}
|
||||
|
||||
// These convenience functions use currentOffset() as the errorOffset.
|
||||
bool fail(const char* msg) { return fail(currentOffset(), msg); }
|
||||
bool failf(const char* msg, ...) MOZ_FORMAT_PRINTF(2, 3);
|
||||
void warnf(const char* msg, ...) MOZ_FORMAT_PRINTF(2, 3);
|
||||
|
||||
// Report an error at the given offset (relative to the whole module).
|
||||
bool fail(size_t errorOffset, const char* msg);
|
||||
|
@ -594,6 +599,7 @@ class Decoder
|
|||
size_t expectedLength,
|
||||
ModuleEnvironment* env,
|
||||
MaybeSectionRange* range);
|
||||
|
||||
template <size_t NameSizeWith0>
|
||||
MOZ_MUST_USE bool startCustomSection(const char (&name)[NameSizeWith0],
|
||||
ModuleEnvironment* env,
|
||||
|
@ -602,13 +608,17 @@ class Decoder
|
|||
MOZ_ASSERT(name[NameSizeWith0 - 1] == '\0');
|
||||
return startCustomSection(name, NameSizeWith0 - 1, env, range);
|
||||
}
|
||||
void finishCustomSection(const SectionRange& range);
|
||||
|
||||
void finishCustomSection(const char* name, const SectionRange& range);
|
||||
void skipAndFinishCustomSection(const SectionRange& range);
|
||||
|
||||
MOZ_MUST_USE bool skipCustomSection(ModuleEnvironment* env);
|
||||
|
||||
// The Name section has its own optional subsections.
|
||||
|
||||
MOZ_MUST_USE bool startNameSubsection(NameType nameType, Maybe<uint32_t>* endOffset);
|
||||
MOZ_MUST_USE bool finishNameSubsection(uint32_t endOffset);
|
||||
MOZ_MUST_USE bool skipNameSubsection();
|
||||
|
||||
// The infallible "unchecked" decoding functions can be used when we are
|
||||
// sure that the bytes are well-formed (by construction or due to previous
|
||||
|
|
|
@ -189,8 +189,6 @@ public:
|
|||
typedef ServoElementSnapshotTable SnapshotTable;
|
||||
typedef mozilla::dom::Element Element;
|
||||
|
||||
NS_INLINE_DECL_REFCOUNTING(mozilla::RestyleManager)
|
||||
|
||||
// Get an integer that increments every time we process pending restyles.
|
||||
// The value is never 0.
|
||||
uint64_t GetRestyleGeneration() const { return mRestyleGeneration; }
|
||||
|
@ -204,6 +202,13 @@ public:
|
|||
|
||||
void Disconnect() { mPresContext = nullptr; }
|
||||
|
||||
~RestyleManager()
|
||||
{
|
||||
MOZ_ASSERT(!mAnimationsWithDestroyedFrame,
|
||||
"leaving dangling pointers from AnimationsWithDestroyedFrame");
|
||||
MOZ_ASSERT(!mReentrantChanges);
|
||||
}
|
||||
|
||||
static nsCString RestyleHintToString(nsRestyleHint aHint);
|
||||
|
||||
#ifdef DEBUG
|
||||
|
@ -449,13 +454,6 @@ protected:
|
|||
|
||||
ServoStyleSet* StyleSet() const { return PresContext()->StyleSet(); }
|
||||
|
||||
~RestyleManager()
|
||||
{
|
||||
MOZ_ASSERT(!mAnimationsWithDestroyedFrame,
|
||||
"leaving dangling pointers from AnimationsWithDestroyedFrame");
|
||||
MOZ_ASSERT(!mReentrantChanges);
|
||||
}
|
||||
|
||||
void RestyleForEmptyChange(Element* aContainer);
|
||||
void MaybeRestyleForEdgeChildChange(Element* aContainer, nsIContent* aChangedChild);
|
||||
|
||||
|
|
|
@ -102,9 +102,6 @@ void
|
|||
nsFrameManager::RemoveFrame(ChildListID aListID,
|
||||
nsIFrame* aOldFrame)
|
||||
{
|
||||
bool wasDestroyingFrames = mIsDestroyingFrames;
|
||||
mIsDestroyingFrames = true;
|
||||
|
||||
// In case the reflow doesn't invalidate anything since it just leaves
|
||||
// a gap where the old frame was, we invalidate it here. (This is
|
||||
// reasonably likely to happen when removing a last child in a way
|
||||
|
@ -128,8 +125,6 @@ nsFrameManager::RemoveFrame(ChildListID aListID,
|
|||
} else {
|
||||
parentFrame->RemoveFrame(aListID, aOldFrame);
|
||||
}
|
||||
|
||||
mIsDestroyingFrames = wasDestroyingFrames;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
|
|
|
@ -37,14 +37,11 @@ public:
|
|||
explicit nsFrameManager(nsIPresShell* aPresShell)
|
||||
: mPresShell(aPresShell)
|
||||
, mRootFrame(nullptr)
|
||||
, mIsDestroyingFrames(false)
|
||||
{
|
||||
MOZ_ASSERT(mPresShell, "need a pres shell");
|
||||
}
|
||||
~nsFrameManager();
|
||||
|
||||
bool IsDestroyingFrames() const { return mIsDestroyingFrames; }
|
||||
|
||||
/*
|
||||
* Gets and sets the root frame (typically the viewport). The lifetime of the
|
||||
* root frame is controlled by the frame manager. When the frame manager is
|
||||
|
@ -104,7 +101,6 @@ protected:
|
|||
// weak link, because the pres shell owns us
|
||||
nsIPresShell* MOZ_NON_OWNING_REF mPresShell;
|
||||
nsIFrame* mRootFrame;
|
||||
bool mIsDestroyingFrames; // The frame manager is destroying some frame(s).
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -843,8 +843,8 @@ nsPresContext::Init(nsDeviceContext* aDeviceContext)
|
|||
|
||||
mAnimationEventDispatcher = new mozilla::AnimationEventDispatcher(this);
|
||||
mEffectCompositor = new mozilla::EffectCompositor(this);
|
||||
mTransitionManager = new nsTransitionManager(this);
|
||||
mAnimationManager = new nsAnimationManager(this);
|
||||
mTransitionManager = MakeUnique<nsTransitionManager>(this);
|
||||
mAnimationManager = MakeUnique<nsAnimationManager>(this);
|
||||
|
||||
if (mDocument->GetDisplayDocument()) {
|
||||
NS_ASSERTION(mDocument->GetDisplayDocument()->GetPresContext(),
|
||||
|
@ -956,7 +956,7 @@ nsPresContext::AttachShell(nsIPresShell* aShell)
|
|||
MOZ_ASSERT(!mShell);
|
||||
mShell = aShell;
|
||||
|
||||
mRestyleManager = new mozilla::RestyleManager(this);
|
||||
mRestyleManager = MakeUnique<mozilla::RestyleManager>(this);
|
||||
|
||||
// Since CounterStyleManager is also the name of a method of
|
||||
// nsPresContext, it is necessary to prefix the class with the mozilla
|
||||
|
|
|
@ -239,15 +239,15 @@ public:
|
|||
}
|
||||
|
||||
mozilla::EffectCompositor* EffectCompositor() { return mEffectCompositor; }
|
||||
nsTransitionManager* TransitionManager() { return mTransitionManager; }
|
||||
nsAnimationManager* AnimationManager() { return mAnimationManager; }
|
||||
const nsAnimationManager* AnimationManager() const { return mAnimationManager; }
|
||||
nsTransitionManager* TransitionManager() { return mTransitionManager.get(); }
|
||||
nsAnimationManager* AnimationManager() { return mAnimationManager.get(); }
|
||||
const nsAnimationManager* AnimationManager() const { return mAnimationManager.get(); }
|
||||
|
||||
nsRefreshDriver* RefreshDriver() { return mRefreshDriver; }
|
||||
|
||||
mozilla::RestyleManager* RestyleManager() {
|
||||
MOZ_ASSERT(mRestyleManager);
|
||||
return mRestyleManager;
|
||||
return mRestyleManager.get();
|
||||
}
|
||||
|
||||
mozilla::CounterStyleManager* CounterStyleManager() const {
|
||||
|
@ -1298,9 +1298,9 @@ protected:
|
|||
RefPtr<nsRefreshDriver> mRefreshDriver;
|
||||
RefPtr<mozilla::AnimationEventDispatcher> mAnimationEventDispatcher;
|
||||
RefPtr<mozilla::EffectCompositor> mEffectCompositor;
|
||||
RefPtr<nsTransitionManager> mTransitionManager;
|
||||
RefPtr<nsAnimationManager> mAnimationManager;
|
||||
RefPtr<mozilla::RestyleManager> mRestyleManager;
|
||||
mozilla::UniquePtr<nsTransitionManager> mTransitionManager;
|
||||
mozilla::UniquePtr<nsAnimationManager> mAnimationManager;
|
||||
mozilla::UniquePtr<mozilla::RestyleManager> mRestyleManager;
|
||||
RefPtr<mozilla::CounterStyleManager> mCounterStyleManager;
|
||||
nsAtom* MOZ_UNSAFE_REF("always a static atom") mMedium; // initialized by subclass ctors
|
||||
RefPtr<nsAtom> mMediaEmulated;
|
||||
|
|
|
@ -3382,7 +3382,6 @@ nsIFrame::BuildDisplayListForStackingContext(nsDisplayListBuilder* aBuilder,
|
|||
MakeDisplayItem<nsDisplayOwnLayer>(aBuilder, this, &resultList,
|
||||
aBuilder->CurrentActiveScrolledRoot(),
|
||||
nsDisplayOwnLayerFlags::eNone,
|
||||
mozilla::layers::FrameMetrics::NULL_SCROLL_ID,
|
||||
ScrollbarData{}, /* aForceActive = */ false));
|
||||
if (aCreatedContainerItem) {
|
||||
*aCreatedContainerItem = true;
|
||||
|
|
|
@ -3042,21 +3042,21 @@ AppendToTop(nsDisplayListBuilder* aBuilder, const nsDisplayListSet& aLists,
|
|||
nsDisplayWrapList* newItem;
|
||||
const ActiveScrolledRoot* asr = aBuilder->CurrentActiveScrolledRoot();
|
||||
if (aFlags & APPEND_OWN_LAYER) {
|
||||
FrameMetrics::ViewID scrollTarget = FrameMetrics::NULL_SCROLL_ID;
|
||||
nsDisplayOwnLayerFlags flags = aBuilder->GetCurrentScrollbarFlags();
|
||||
// The flags here should be at most one scrollbar direction and nothing else
|
||||
MOZ_ASSERT(flags == nsDisplayOwnLayerFlags::eNone ||
|
||||
flags == nsDisplayOwnLayerFlags::eVerticalScrollbar ||
|
||||
flags == nsDisplayOwnLayerFlags::eHorizontalScrollbar);
|
||||
|
||||
ScrollbarData scrollbarData;
|
||||
if (aFlags & APPEND_SCROLLBAR_CONTAINER) {
|
||||
scrollTarget = aBuilder->GetCurrentScrollbarTarget();
|
||||
scrollbarData.mTargetViewId = aBuilder->GetCurrentScrollbarTarget();
|
||||
// The flags here should be exactly one scrollbar direction
|
||||
MOZ_ASSERT(flags != nsDisplayOwnLayerFlags::eNone);
|
||||
flags |= nsDisplayOwnLayerFlags::eScrollbarContainer;
|
||||
}
|
||||
|
||||
newItem = MakeDisplayItem<nsDisplayOwnLayer>(aBuilder, aSourceFrame, aSource, asr, flags, scrollTarget);
|
||||
newItem = MakeDisplayItem<nsDisplayOwnLayer>(aBuilder, aSourceFrame, aSource, asr, flags, scrollbarData);
|
||||
} else {
|
||||
newItem = MakeDisplayItem<nsDisplayWrapList>(aBuilder, aSourceFrame, aSource, asr);
|
||||
}
|
||||
|
|
|
@ -61,6 +61,7 @@ namespace dom {
|
|||
/* static */ void
|
||||
InspectorUtils::GetAllStyleSheets(GlobalObject& aGlobalObject,
|
||||
nsIDocument& aDocument,
|
||||
bool aDocumentOnly,
|
||||
nsTArray<RefPtr<StyleSheet>>& aResult)
|
||||
{
|
||||
// Get the agent, then user and finally xbl sheets in the style set.
|
||||
|
@ -68,19 +69,24 @@ InspectorUtils::GetAllStyleSheets(GlobalObject& aGlobalObject,
|
|||
|
||||
if (presShell) {
|
||||
ServoStyleSet* styleSet = presShell->StyleSet();
|
||||
SheetType sheetType = SheetType::Agent;
|
||||
for (int32_t i = 0; i < styleSet->SheetCount(sheetType); i++) {
|
||||
aResult.AppendElement(styleSet->StyleSheetAt(sheetType, i));
|
||||
}
|
||||
sheetType = SheetType::User;
|
||||
for (int32_t i = 0; i < styleSet->SheetCount(sheetType); i++) {
|
||||
aResult.AppendElement(styleSet->StyleSheetAt(sheetType, i));
|
||||
|
||||
if (!aDocumentOnly) {
|
||||
SheetType sheetType = SheetType::Agent;
|
||||
for (int32_t i = 0; i < styleSet->SheetCount(sheetType); i++) {
|
||||
aResult.AppendElement(styleSet->StyleSheetAt(sheetType, i));
|
||||
}
|
||||
sheetType = SheetType::User;
|
||||
for (int32_t i = 0; i < styleSet->SheetCount(sheetType); i++) {
|
||||
aResult.AppendElement(styleSet->StyleSheetAt(sheetType, i));
|
||||
}
|
||||
}
|
||||
|
||||
AutoTArray<StyleSheet*, 32> xblSheetArray;
|
||||
styleSet->AppendAllXBLStyleSheets(xblSheetArray);
|
||||
styleSet->AppendAllNonDocumentAuthorSheets(xblSheetArray);
|
||||
|
||||
// The XBL stylesheet array will quite often be full of duplicates. Cope:
|
||||
//
|
||||
// FIXME(emilio, bug 1454467): I think this is not true since bug 1452525.
|
||||
nsTHashtable<nsPtrHashKey<StyleSheet>> sheetSet;
|
||||
for (StyleSheet* sheet : xblSheetArray) {
|
||||
if (!sheetSet.Contains(sheet)) {
|
||||
|
@ -1048,16 +1054,8 @@ InspectorUtils::ParseStyleSheet(GlobalObject& aGlobalObject,
|
|||
ErrorResult& aRv)
|
||||
{
|
||||
|
||||
RefPtr<ServoStyleSheet> servoSheet = do_QueryObject(&aSheet);
|
||||
if (servoSheet) {
|
||||
nsresult rv = servoSheet->ReparseSheet(aInput);
|
||||
if (NS_FAILED(rv)) {
|
||||
aRv.Throw(rv);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
aRv.Throw(NS_ERROR_INVALID_POINTER);
|
||||
RefPtr<ServoStyleSheet> servoSheet = aSheet.AsServo();
|
||||
aRv = servoSheet->ReparseSheet(aInput);
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
@ -37,6 +37,7 @@ class InspectorUtils
|
|||
public:
|
||||
static void GetAllStyleSheets(GlobalObject& aGlobal,
|
||||
nsIDocument& aDocument,
|
||||
bool aDocumentOnly,
|
||||
nsTArray<RefPtr<StyleSheet>>& aResult);
|
||||
static void GetCSSStyleRules(GlobalObject& aGlobal,
|
||||
Element& aElement,
|
||||
|
|
|
@ -6922,14 +6922,13 @@ nsDisplayTableBlendContainer::CreateForBackgroundBlendMode(nsDisplayListBuilder*
|
|||
nsDisplayOwnLayer::nsDisplayOwnLayer(nsDisplayListBuilder* aBuilder,
|
||||
nsIFrame* aFrame, nsDisplayList* aList,
|
||||
const ActiveScrolledRoot* aActiveScrolledRoot,
|
||||
nsDisplayOwnLayerFlags aFlags, ViewID aScrollTarget,
|
||||
const ScrollbarData& aThumbData,
|
||||
nsDisplayOwnLayerFlags aFlags,
|
||||
const ScrollbarData& aScrollbarData,
|
||||
bool aForceActive,
|
||||
bool aClearClipChain)
|
||||
: nsDisplayWrapList(aBuilder, aFrame, aList, aActiveScrolledRoot, aClearClipChain)
|
||||
, mFlags(aFlags)
|
||||
, mScrollTarget(aScrollTarget)
|
||||
, mThumbData(aThumbData)
|
||||
, mScrollbarData(aScrollbarData)
|
||||
, mForceActive(aForceActive)
|
||||
, mWrAnimationId(0)
|
||||
{
|
||||
|
@ -6965,7 +6964,7 @@ nsDisplayOwnLayer::GetLayerState(nsDisplayListBuilder* aBuilder,
|
|||
bool
|
||||
nsDisplayOwnLayer::IsScrollThumbLayer() const
|
||||
{
|
||||
return mThumbData.mScrollbarLayerType == layers::ScrollbarLayerType::Thumb;
|
||||
return mScrollbarData.mScrollbarLayerType == layers::ScrollbarLayerType::Thumb;
|
||||
}
|
||||
|
||||
bool
|
||||
|
@ -6986,15 +6985,16 @@ nsDisplayOwnLayer::BuildLayer(nsDisplayListBuilder* aBuilder,
|
|||
BuildContainerLayerFor(aBuilder, aManager, mFrame, this, &mList,
|
||||
aContainerParameters, nullptr,
|
||||
FrameLayerBuilder::CONTAINER_ALLOW_PULL_BACKGROUND_COLOR);
|
||||
|
||||
if (IsScrollThumbLayer()) {
|
||||
mThumbData.mTargetViewId = mScrollTarget;
|
||||
layer->SetScrollbarData(mThumbData);
|
||||
}
|
||||
if (mFlags & nsDisplayOwnLayerFlags::eScrollbarContainer) {
|
||||
ScrollDirection dir = (mFlags & nsDisplayOwnLayerFlags::eVerticalScrollbar)
|
||||
? ScrollDirection::eVertical
|
||||
: ScrollDirection::eHorizontal;
|
||||
layer->SetScrollbarContainer(mScrollTarget, dir);
|
||||
layer->SetScrollbarData(mScrollbarData);
|
||||
} else if (mFlags & nsDisplayOwnLayerFlags::eScrollbarContainer) {
|
||||
mScrollbarData.mScrollbarLayerType = ScrollbarLayerType::Container;
|
||||
mScrollbarData.mDirection = (mFlags & nsDisplayOwnLayerFlags::eVerticalScrollbar)
|
||||
? Some(ScrollDirection::eVertical)
|
||||
: Some(ScrollDirection::eHorizontal);
|
||||
|
||||
layer->SetScrollbarData(mScrollbarData);
|
||||
}
|
||||
|
||||
if (mFlags & nsDisplayOwnLayerFlags::eGenerateSubdocInvalidations) {
|
||||
|
@ -7044,9 +7044,9 @@ nsDisplayOwnLayer::UpdateScrollData(mozilla::layers::WebRenderScrollData* aData,
|
|||
if (IsScrollThumbLayer()) {
|
||||
ret = true;
|
||||
if (aLayerData) {
|
||||
aLayerData->SetScrollbarData(mThumbData);
|
||||
aLayerData->SetScrollbarData(mScrollbarData);
|
||||
aLayerData->SetScrollbarAnimationId(mWrAnimationId);
|
||||
aLayerData->SetScrollbarTargetContainerId(mScrollTarget);
|
||||
aLayerData->SetScrollbarTargetContainerId(mScrollbarData.mTargetViewId);
|
||||
}
|
||||
}
|
||||
if (mFlags & nsDisplayOwnLayerFlags::eScrollbarContainer) {
|
||||
|
@ -7056,7 +7056,7 @@ nsDisplayOwnLayer::UpdateScrollData(mozilla::layers::WebRenderScrollData* aData,
|
|||
? ScrollDirection::eVertical
|
||||
: ScrollDirection::eHorizontal;
|
||||
aLayerData->SetScrollbarContainerDirection(dir);
|
||||
aLayerData->SetScrollbarTargetContainerId(mScrollTarget);
|
||||
aLayerData->SetScrollbarTargetContainerId(mScrollbarData.mTargetViewId);
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
|
@ -7065,7 +7065,7 @@ nsDisplayOwnLayer::UpdateScrollData(mozilla::layers::WebRenderScrollData* aData,
|
|||
void
|
||||
nsDisplayOwnLayer::WriteDebugInfo(std::stringstream& aStream)
|
||||
{
|
||||
aStream << nsPrintfCString(" (flags 0x%x) (scrolltarget %" PRIu64 ")", (int)mFlags, mScrollTarget).get();
|
||||
aStream << nsPrintfCString(" (flags 0x%x) (scrolltarget %" PRIu64 ")", (int)mFlags, mScrollbarData.mTargetViewId).get();
|
||||
}
|
||||
|
||||
nsDisplaySubDocument::nsDisplaySubDocument(nsDisplayListBuilder* aBuilder,
|
||||
|
|
|
@ -5606,18 +5606,18 @@ public:
|
|||
nsDisplayList* aList,
|
||||
const ActiveScrolledRoot* aActiveScrolledRoot,
|
||||
nsDisplayOwnLayerFlags aFlags = nsDisplayOwnLayerFlags::eNone,
|
||||
ViewID aScrollTarget = mozilla::layers::FrameMetrics::NULL_SCROLL_ID,
|
||||
const ScrollbarData& aThumbData = ScrollbarData{},
|
||||
const ScrollbarData& aScrollbarData = ScrollbarData{},
|
||||
bool aForceActive = true,
|
||||
bool aClearClipChain = false);
|
||||
|
||||
#ifdef NS_BUILD_REFCNT_LOGGING
|
||||
virtual ~nsDisplayOwnLayer();
|
||||
#endif
|
||||
|
||||
nsDisplayOwnLayer(nsDisplayListBuilder* aBuilder, const nsDisplayOwnLayer& aOther)
|
||||
: nsDisplayWrapList(aBuilder, aOther)
|
||||
, mFlags(aOther.mFlags)
|
||||
, mScrollTarget(aOther.mScrollTarget)
|
||||
, mThumbData(aOther.mThumbData)
|
||||
, mScrollbarData(aOther.mScrollbarData)
|
||||
, mForceActive(aOther.mForceActive)
|
||||
, mWrAnimationId(aOther.mWrAnimationId)
|
||||
{
|
||||
|
@ -5657,12 +5657,15 @@ public:
|
|||
NS_DISPLAY_DECL_NAME("OwnLayer", TYPE_OWN_LAYER)
|
||||
protected:
|
||||
nsDisplayOwnLayerFlags mFlags;
|
||||
ViewID mScrollTarget;
|
||||
// If this nsDisplayOwnLayer represents a scroll thumb layer, mThumbData
|
||||
// stores information about the scroll thumb. Otherwise, mThumbData will be
|
||||
// default-constructed (in particular with mDirection == Nothing())
|
||||
// and can be ignored.
|
||||
ScrollbarData mThumbData;
|
||||
|
||||
/**
|
||||
* If this nsDisplayOwnLayer represents a scroll thumb layer or a
|
||||
* scrollbar container layer, mScrollbarData stores information
|
||||
* about the scrollbar. Otherwise, mScrollbarData will be
|
||||
* default-constructed (in particular with mDirection == Nothing())
|
||||
* and can be ignored.
|
||||
*/
|
||||
ScrollbarData mScrollbarData;
|
||||
bool mForceActive;
|
||||
uint64_t mWrAnimationId;
|
||||
};
|
||||
|
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче