Merge inbound to mozilla-central a=merge

This commit is contained in:
Coroiu Cristina 2018-05-25 20:51:27 +03:00
Родитель e24fd18f32 246756a336
Коммит 19e81b8d28
219 изменённых файлов: 2537 добавлений и 1321 удалений

Просмотреть файл

@ -40,6 +40,21 @@ ARIAGridAccessible::NativeRole() const
return r != roles::NOTHING ? r : roles::TABLE; return r != roles::NOTHING ? r : roles::TABLE;
} }
already_AddRefed<nsIPersistentProperties>
ARIAGridAccessible::NativeAttributes()
{
nsCOMPtr<nsIPersistentProperties> attributes =
AccessibleWrap::NativeAttributes();
if (IsProbablyLayoutTable()) {
nsAutoString unused;
attributes->SetStringProperty(NS_LITERAL_CSTRING("layout-guess"),
NS_LITERAL_STRING("true"), unused);
}
return attributes.forget();
}
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// Table // Table

Просмотреть файл

@ -26,6 +26,7 @@ public:
// Accessible // Accessible
virtual a11y::role NativeRole() const override; virtual a11y::role NativeRole() const override;
virtual already_AddRefed<nsIPersistentProperties> NativeAttributes() override;
virtual TableAccessible* AsTable() override { return this; } virtual TableAccessible* AsTable() override { return this; }
// TableAccessible // TableAccessible

Просмотреть файл

@ -0,0 +1,240 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "TableAccessible.h"
#include "Accessible-inl.h"
#include "nsTableCellFrame.h"
#include "nsTableWrapperFrame.h"
using namespace mozilla;
using namespace mozilla::a11y;
bool
TableAccessible::IsProbablyLayoutTable()
{
// Implement a heuristic to determine if table is most likely used for layout.
// XXX do we want to look for rowspan or colspan, especialy that span all but
// a couple cells at the beginning or end of a row/col, and especially when
// they occur at the edge of a table?
// XXX For now debugging descriptions are always on via SHOW_LAYOUT_HEURISTIC
// This will allow release trunk builds to be used by testers to refine
// the algorithm. Integrate it into Logging.
// Change to |#define SHOW_LAYOUT_HEURISTIC DEBUG| before final release
#ifdef SHOW_LAYOUT_HEURISTIC
#define RETURN_LAYOUT_ANSWER(isLayout, heuristic) \
{ \
mLayoutHeuristic = isLayout ? \
NS_LITERAL_STRING("layout table: " heuristic) : \
NS_LITERAL_STRING("data table: " heuristic); \
return isLayout; \
}
#else
#define RETURN_LAYOUT_ANSWER(isLayout, heuristic) { return isLayout; }
#endif
Accessible* thisacc = AsAccessible();
// Need to see all elements while document is being edited.
if (thisacc->Document()->State() & states::EDITABLE) {
RETURN_LAYOUT_ANSWER(false, "In editable document");
}
// Check to see if an ARIA role overrides the role from native markup,
// but for which we still expose table semantics (treegrid, for example).
if (thisacc->HasARIARole()) {
RETURN_LAYOUT_ANSWER(false, "Has role attribute");
}
dom::Element* el = thisacc->Elm();
if (el->IsMathMLElement(nsGkAtoms::mtable_)) {
RETURN_LAYOUT_ANSWER(false, "MathML matrix");
}
MOZ_ASSERT(el->IsHTMLElement(nsGkAtoms::table),
"Table should not be built by CSS display:table style");
// Check if datatable attribute has "0" value.
if (el->AttrValueIs(kNameSpaceID_None, nsGkAtoms::datatable,
NS_LITERAL_STRING("0"), eCaseMatters)) {
RETURN_LAYOUT_ANSWER(true, "Has datatable = 0 attribute, it's for layout");
}
// Check for legitimate data table attributes.
nsAutoString summary;
if (el->GetAttr(kNameSpaceID_None, nsGkAtoms::summary, summary) &&
!summary.IsEmpty()) {
RETURN_LAYOUT_ANSWER(false, "Has summary -- legitimate table structures");
}
// Check for legitimate data table elements.
Accessible* caption = thisacc->FirstChild();
if (caption && caption->IsHTMLCaption() && caption->HasChildren()) {
RETURN_LAYOUT_ANSWER(false, "Not empty caption -- legitimate table structures");
}
for (nsIContent* childElm = el->GetFirstChild(); childElm;
childElm = childElm->GetNextSibling()) {
if (!childElm->IsHTMLElement())
continue;
if (childElm->IsAnyOfHTMLElements(nsGkAtoms::col,
nsGkAtoms::colgroup,
nsGkAtoms::tfoot,
nsGkAtoms::thead)) {
RETURN_LAYOUT_ANSWER(false,
"Has col, colgroup, tfoot or thead -- legitimate table structures");
}
if (childElm->IsHTMLElement(nsGkAtoms::tbody)) {
for (nsIContent* rowElm = childElm->GetFirstChild(); rowElm;
rowElm = rowElm->GetNextSibling()) {
if (rowElm->IsHTMLElement(nsGkAtoms::tr)) {
for (nsIContent* cellElm = rowElm->GetFirstChild(); cellElm;
cellElm = cellElm->GetNextSibling()) {
if (cellElm->IsHTMLElement()) {
if (cellElm->NodeInfo()->Equals(nsGkAtoms::th)) {
RETURN_LAYOUT_ANSWER(false,
"Has th -- legitimate table structures");
}
if (cellElm->AsElement()->HasAttr(kNameSpaceID_None, nsGkAtoms::headers) ||
cellElm->AsElement()->HasAttr(kNameSpaceID_None, nsGkAtoms::scope) ||
cellElm->AsElement()->HasAttr(kNameSpaceID_None, nsGkAtoms::abbr)) {
RETURN_LAYOUT_ANSWER(false,
"Has headers, scope, or abbr attribute -- legitimate table structures");
}
Accessible* cell = thisacc->Document()->GetAccessible(cellElm);
if (cell && cell->ChildCount() == 1 &&
cell->FirstChild()->IsAbbreviation()) {
RETURN_LAYOUT_ANSWER(false,
"has abbr -- legitimate table structures");
}
}
}
}
}
}
}
// Check for nested tables.
nsCOMPtr<nsIHTMLCollection> nestedTables =
el->GetElementsByTagName(NS_LITERAL_STRING("table"));
if (nestedTables->Length() > 0) {
RETURN_LAYOUT_ANSWER(true, "Has a nested table within it");
}
// If only 1 column or only 1 row, it's for layout.
auto colCount = ColCount();
if (colCount <= 1) {
RETURN_LAYOUT_ANSWER(true, "Has only 1 column");
}
auto rowCount = RowCount();
if (rowCount <=1) {
RETURN_LAYOUT_ANSWER(true, "Has only 1 row");
}
// Check for many columns.
if (colCount >= 5) {
RETURN_LAYOUT_ANSWER(false, ">=5 columns");
}
// Now we know there are 2-4 columns and 2 or more rows. Check to see if
// there are visible borders on the cells.
// XXX currently, we just check the first cell -- do we really need to do more?
nsTableWrapperFrame* tableFrame = do_QueryFrame(el->GetPrimaryFrame());
if (!tableFrame) {
RETURN_LAYOUT_ANSWER(false, "table with no frame!");
}
nsIFrame* cellFrame = tableFrame->GetCellFrameAt(0, 0);
if (!cellFrame) {
RETURN_LAYOUT_ANSWER(false, "table's first cell has no frame!");
}
nsMargin border;
cellFrame->GetXULBorder(border);
if (border.top && border.bottom && border.left && border.right) {
RETURN_LAYOUT_ANSWER(false, "Has nonzero border-width on table cell");
}
// Rules for non-bordered tables with 2-4 columns and 2+ rows from here on
// forward.
// Check for styled background color across rows (alternating background
// color is a common feature for data tables).
auto childCount = thisacc->ChildCount();
nscolor rowColor = 0;
nscolor prevRowColor;
for (auto childIdx = 0U; childIdx < childCount; childIdx++) {
Accessible* child = thisacc->GetChildAt(childIdx);
if (child->IsHTMLTableRow()) {
prevRowColor = rowColor;
nsIFrame* rowFrame = child->GetFrame();
MOZ_ASSERT(rowFrame, "Table hierarchy got screwed up");
if (!rowFrame) {
RETURN_LAYOUT_ANSWER(false, "Unexpected table hierarchy");
}
rowColor = rowFrame->StyleBackground()->BackgroundColor(rowFrame);
if (childIdx > 0 && prevRowColor != rowColor) {
RETURN_LAYOUT_ANSWER(
false, "2 styles of row background color, non-bordered"
);
}
}
}
// Check for many rows.
const uint32_t kMaxLayoutRows = 20;
if (rowCount > kMaxLayoutRows) { // A ton of rows, this is probably for data
RETURN_LAYOUT_ANSWER(false, ">= kMaxLayoutRows (20) and non-bordered");
}
// Check for very wide table.
nsIFrame* documentFrame = thisacc->Document()->GetFrame();
nsSize documentSize = documentFrame->GetSize();
if (documentSize.width > 0) {
nsSize tableSize = thisacc->GetFrame()->GetSize();
int32_t percentageOfDocWidth = (100 * tableSize.width) / documentSize.width;
if (percentageOfDocWidth > 95) {
// 3-4 columns, no borders, not a lot of rows, and 95% of the doc's width
// Probably for layout
RETURN_LAYOUT_ANSWER(
true, "<= 4 columns, table width is 95% of document width"
);
}
}
// Two column rules.
if (rowCount * colCount <= 10) {
RETURN_LAYOUT_ANSWER(true, "2-4 columns, 10 cells or less, non-bordered");
}
static const nsLiteralString tags[] = {
NS_LITERAL_STRING("embed"),
NS_LITERAL_STRING("object"),
NS_LITERAL_STRING("iframe")
};
for (auto& tag : tags) {
nsCOMPtr<nsIHTMLCollection> descendants = el->GetElementsByTagName(tag);
if (descendants->Length() > 0) {
RETURN_LAYOUT_ANSWER(
true, "Has no borders, and has iframe, object or embed, typical of advertisements"
);
}
}
RETURN_LAYOUT_ANSWER(
false, "No layout factor strong enough, so will guess data"
);
}

Просмотреть файл

@ -173,7 +173,7 @@ public:
/** /**
* Return true if the table is probably for layout. * Return true if the table is probably for layout.
*/ */
virtual bool IsProbablyLayoutTable() { return false; } virtual bool IsProbablyLayoutTable();
/** /**
* Convert the table to an Accessible*. * Convert the table to an Accessible*.

Просмотреть файл

@ -21,6 +21,7 @@ UNIFIED_SOURCES += [
'ImageAccessible.cpp', 'ImageAccessible.cpp',
'OuterDocAccessible.cpp', 'OuterDocAccessible.cpp',
'RootAccessible.cpp', 'RootAccessible.cpp',
'TableAccessible.cpp',
'TableCellAccessible.cpp', 'TableCellAccessible.cpp',
'TextLeafAccessible.cpp', 'TextLeafAccessible.cpp',
] ]

Просмотреть файл

@ -860,244 +860,6 @@ HTMLTableAccessible::Description(nsString& aDescription)
#endif #endif
} }
bool
HTMLTableAccessible::HasDescendant(const nsAString& aTagName, bool aAllowEmpty)
{
nsCOMPtr<nsIHTMLCollection> elements =
mContent->AsElement()->GetElementsByTagName(aTagName);
Element* foundItem = elements->Item(0);
if (!foundItem)
return false;
if (aAllowEmpty)
return true;
// Make sure that the item we found has contents and either has multiple
// children or the found item is not a whitespace-only text node.
if (foundItem->GetChildCount() > 1)
return true; // Treat multiple child nodes as non-empty
nsIContent *innerItemContent = foundItem->GetFirstChild();
if (innerItemContent && !innerItemContent->TextIsOnlyWhitespace())
return true;
// If we found more than one node then return true not depending on
// aAllowEmpty flag.
// XXX it might be dummy but bug 501375 where we changed this addresses
// performance problems only. Note, currently 'aAllowEmpty' flag is used for
// caption element only. On another hand we create accessible object for
// the first entry of caption element (see
// HTMLTableAccessible::InsertChildAt).
return !!elements->Item(1);
}
bool
HTMLTableAccessible::IsProbablyLayoutTable()
{
// Implement a heuristic to determine if table is most likely used for layout
// XXX do we want to look for rowspan or colspan, especialy that span all but a couple cells
// at the beginning or end of a row/col, and especially when they occur at the edge of a table?
// XXX expose this info via object attributes to AT-SPI
// XXX For now debugging descriptions are always on via SHOW_LAYOUT_HEURISTIC
// This will allow release trunk builds to be used by testers to refine the algorithm
// Change to |#define SHOW_LAYOUT_HEURISTIC DEBUG| before final release
#ifdef SHOW_LAYOUT_HEURISTIC
#define RETURN_LAYOUT_ANSWER(isLayout, heuristic) \
{ \
mLayoutHeuristic = isLayout ? \
NS_LITERAL_STRING("layout table: " heuristic) : \
NS_LITERAL_STRING("data table: " heuristic); \
return isLayout; \
}
#else
#define RETURN_LAYOUT_ANSWER(isLayout, heuristic) { return isLayout; }
#endif
DocAccessible* docAccessible = Document();
if (docAccessible) {
uint64_t docState = docAccessible->State();
if (docState & states::EDITABLE) { // Need to see all elements while document is being edited
RETURN_LAYOUT_ANSWER(false, "In editable document");
}
}
// Check to see if an ARIA role overrides the role from native markup,
// but for which we still expose table semantics (treegrid, for example).
if (Role() != roles::TABLE)
RETURN_LAYOUT_ANSWER(false, "Has role attribute");
if (mContent->AsElement()->HasAttr(kNameSpaceID_None, nsGkAtoms::role)) {
// Role attribute is present, but overridden roles have already been dealt with.
// Only landmarks and other roles that don't override the role from native
// markup are left to deal with here.
RETURN_LAYOUT_ANSWER(false, "Has role attribute, weak role, and role is table");
}
NS_ASSERTION(mContent->IsHTMLElement(nsGkAtoms::table),
"table should not be built by CSS display:table style");
// Check if datatable attribute has "0" value.
if (mContent->AsElement()->AttrValueIs(kNameSpaceID_None, nsGkAtoms::datatable,
NS_LITERAL_STRING("0"), eCaseMatters)) {
RETURN_LAYOUT_ANSWER(true, "Has datatable = 0 attribute, it's for layout");
}
// Check for legitimate data table attributes.
nsAutoString summary;
if (mContent->AsElement()->GetAttr(kNameSpaceID_None, nsGkAtoms::summary, summary) &&
!summary.IsEmpty())
RETURN_LAYOUT_ANSWER(false, "Has summary -- legitimate table structures");
// Check for legitimate data table elements.
Accessible* caption = FirstChild();
if (caption && caption->Role() == roles::CAPTION && caption->HasChildren())
RETURN_LAYOUT_ANSWER(false, "Not empty caption -- legitimate table structures");
for (nsIContent* childElm = mContent->GetFirstChild(); childElm;
childElm = childElm->GetNextSibling()) {
if (!childElm->IsHTMLElement())
continue;
if (childElm->IsAnyOfHTMLElements(nsGkAtoms::col,
nsGkAtoms::colgroup,
nsGkAtoms::tfoot,
nsGkAtoms::thead)) {
RETURN_LAYOUT_ANSWER(false,
"Has col, colgroup, tfoot or thead -- legitimate table structures");
}
if (childElm->IsHTMLElement(nsGkAtoms::tbody)) {
for (nsIContent* rowElm = childElm->GetFirstChild(); rowElm;
rowElm = rowElm->GetNextSibling()) {
if (rowElm->IsHTMLElement(nsGkAtoms::tr)) {
for (nsIContent* cellElm = rowElm->GetFirstChild(); cellElm;
cellElm = cellElm->GetNextSibling()) {
if (cellElm->IsHTMLElement()) {
if (cellElm->NodeInfo()->Equals(nsGkAtoms::th)) {
RETURN_LAYOUT_ANSWER(false,
"Has th -- legitimate table structures");
}
if (cellElm->AsElement()->HasAttr(kNameSpaceID_None, nsGkAtoms::headers) ||
cellElm->AsElement()->HasAttr(kNameSpaceID_None, nsGkAtoms::scope) ||
cellElm->AsElement()->HasAttr(kNameSpaceID_None, nsGkAtoms::abbr)) {
RETURN_LAYOUT_ANSWER(false,
"Has headers, scope, or abbr attribute -- legitimate table structures");
}
Accessible* cell = mDoc->GetAccessible(cellElm);
if (cell && cell->ChildCount() == 1 &&
cell->FirstChild()->IsAbbreviation()) {
RETURN_LAYOUT_ANSWER(false,
"has abbr -- legitimate table structures");
}
}
}
}
}
}
}
if (HasDescendant(NS_LITERAL_STRING("table"))) {
RETURN_LAYOUT_ANSWER(true, "Has a nested table within it");
}
// If only 1 column or only 1 row, it's for layout
uint32_t colCount = ColCount();
if (colCount <=1) {
RETURN_LAYOUT_ANSWER(true, "Has only 1 column");
}
uint32_t rowCount = RowCount();
if (rowCount <=1) {
RETURN_LAYOUT_ANSWER(true, "Has only 1 row");
}
// Check for many columns
if (colCount >= 5) {
RETURN_LAYOUT_ANSWER(false, ">=5 columns");
}
// Now we know there are 2-4 columns and 2 or more rows
// Check to see if there are visible borders on the cells
// XXX currently, we just check the first cell -- do we really need to do more?
nsTableWrapperFrame* tableFrame = do_QueryFrame(mContent->GetPrimaryFrame());
if (!tableFrame)
RETURN_LAYOUT_ANSWER(false, "table with no frame!");
nsIFrame* cellFrame = tableFrame->GetCellFrameAt(0, 0);
if (!cellFrame)
RETURN_LAYOUT_ANSWER(false, "table's first cell has no frame!");
nsMargin border;
cellFrame->GetXULBorder(border);
if (border.top && border.bottom && border.left && border.right) {
RETURN_LAYOUT_ANSWER(false, "Has nonzero border-width on table cell");
}
/**
* Rules for non-bordered tables with 2-4 columns and 2+ rows from here on forward
*/
// Check for styled background color across rows (alternating background
// color is a common feature for data tables).
uint32_t childCount = ChildCount();
nscolor rowColor = 0;
nscolor prevRowColor;
for (uint32_t childIdx = 0; childIdx < childCount; childIdx++) {
Accessible* child = GetChildAt(childIdx);
if (child->Role() == roles::ROW) {
prevRowColor = rowColor;
nsIFrame* rowFrame = child->GetFrame();
MOZ_ASSERT(rowFrame, "Table hierarchy got screwed up");
if (!rowFrame) {
RETURN_LAYOUT_ANSWER(false, "Unexpected table hierarchy");
}
rowColor = rowFrame->StyleBackground()->BackgroundColor(rowFrame);
if (childIdx > 0 && prevRowColor != rowColor)
RETURN_LAYOUT_ANSWER(false, "2 styles of row background color, non-bordered");
}
}
// Check for many rows
const uint32_t kMaxLayoutRows = 20;
if (rowCount > kMaxLayoutRows) { // A ton of rows, this is probably for data
RETURN_LAYOUT_ANSWER(false, ">= kMaxLayoutRows (20) and non-bordered");
}
// Check for very wide table.
nsIFrame* documentFrame = Document()->GetFrame();
nsSize documentSize = documentFrame->GetSize();
if (documentSize.width > 0) {
nsSize tableSize = GetFrame()->GetSize();
int32_t percentageOfDocWidth = (100 * tableSize.width) / documentSize.width;
if (percentageOfDocWidth > 95) {
// 3-4 columns, no borders, not a lot of rows, and 95% of the doc's width
// Probably for layout
RETURN_LAYOUT_ANSWER(true,
"<= 4 columns, table width is 95% of document width");
}
}
// Two column rules
if (rowCount * colCount <= 10) {
RETURN_LAYOUT_ANSWER(true, "2-4 columns, 10 cells or less, non-bordered");
}
if (HasDescendant(NS_LITERAL_STRING("embed")) ||
HasDescendant(NS_LITERAL_STRING("object")) ||
HasDescendant(NS_LITERAL_STRING("iframe"))) {
RETURN_LAYOUT_ANSWER(true, "Has no borders, and has iframe, object, or iframe, typical of advertisements");
}
RETURN_LAYOUT_ANSWER(false, "no layout factor strong enough, so will guess data");
}
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// HTMLCaptionAccessible // HTMLCaptionAccessible
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////

Просмотреть файл

@ -156,7 +156,6 @@ public:
virtual void SelectRow(uint32_t aRowIdx) override; virtual void SelectRow(uint32_t aRowIdx) override;
virtual void UnselectCol(uint32_t aColIdx) override; virtual void UnselectCol(uint32_t aColIdx) override;
virtual void UnselectRow(uint32_t aRowIdx) override; virtual void UnselectRow(uint32_t aRowIdx) override;
virtual bool IsProbablyLayoutTable() override;
virtual Accessible* AsAccessible() override { return this; } virtual Accessible* AsAccessible() override { return this; }
// Accessible // Accessible
@ -199,15 +198,6 @@ protected:
TableSelection aTarget, TableSelection aTarget,
bool aIsOuter); bool aIsOuter);
/**
* Return true if table has an element with the given tag name.
*
* @param aTagName [in] tag name of searched element
* @param aAllowEmpty [in, optional] points if found element can be empty
* or contain whitespace text only.
*/
bool HasDescendant(const nsAString& aTagName, bool aAllowEmpty = true);
#ifdef SHOW_LAYOUT_HEURISTIC #ifdef SHOW_LAYOUT_HEURISTIC
nsString mLayoutHeuristic; nsString mLayoutHeuristic;
#endif #endif

Просмотреть файл

@ -14,106 +14,114 @@
src="../attributes.js"></script> src="../attributes.js"></script>
<script type="application/javascript"> <script type="application/javascript">
function doTest() { function isLayoutTable(id) {
// Attribute we're looking for testAttrs(id, { "layout-guess": "true" }, true);
var attr = { }
"layout-guess": "true" function isDataTable(id) {
}; testAbsentAttrs(id, { "layout-guess": "true" });
}
function doTest() {
// table with role of grid // table with role of grid
testAbsentAttrs("table1", attr); isDataTable("table1");
// table with role of grid and datatable="0" // table with role of grid and datatable="0"
testAbsentAttrs("table1.1", attr); isDataTable("table1.1");
// table with landmark role // table with landmark role
testAbsentAttrs("table2", attr); isDataTable("table2");
// table with summary // table with summary
testAbsentAttrs("table3", attr); isDataTable("table3");
// table with caption // table with caption
testAbsentAttrs("table4", attr); isDataTable("table4");
// layout table with empty caption // layout table with empty caption
testAttrs("table4.2", attr, true); isLayoutTable("table4.2");
// table with thead element // table with thead element
testAbsentAttrs("table5", attr); isDataTable("table5");
// table with tfoot element // table with tfoot element
testAbsentAttrs("table5.1", attr); isDataTable("table5.1");
// table with colgroup or col elements // table with colgroup or col elements
testAbsentAttrs("table5.2", attr); isDataTable("table5.2");
testAbsentAttrs("table5.3", attr); isDataTable("table5.3");
// table with th element // table with th element
testAbsentAttrs("table6", attr); isDataTable("table6");
// table with headers attribute // table with headers attribute
testAbsentAttrs("table6.2", attr); isDataTable("table6.2");
// table with scope attribute // table with scope attribute
testAbsentAttrs("table6.2.2", attr); isDataTable("table6.2.2");
// table with abbr attribute // table with abbr attribute
testAbsentAttrs("table6.2.3", attr); isDataTable("table6.2.3");
// table with abbr element // table with abbr element
testAbsentAttrs("table6.3", attr); isDataTable("table6.3");
// table with abbr element having empty text node // table with abbr element having empty text node
testAbsentAttrs("table6.4", attr); isDataTable("table6.4");
// table with abbr element and non-empty text node // table with abbr element and non-empty text node
testAttrs("table6.5", attr, true); isLayoutTable("table6.5");
// layout table with nested table // layout table with nested table
testAttrs("table9", attr, true); isLayoutTable("table9");
// layout table with 1 column // layout table with 1 column
testAttrs("table10", attr, true); isLayoutTable("table10");
// layout table with 1 row // layout table with 1 row
testAttrs("table11", attr, true); isLayoutTable("table11");
// table with 5 columns // table with 5 columns
testAbsentAttrs("table12", attr); isDataTable("table12");
// table with a bordered cell // table with a bordered cell
testAbsentAttrs("table13", attr); isDataTable("table13");
// table with alternating row background colors // table with alternating row background colors
testAbsentAttrs("table14", attr); isDataTable("table14");
// table with 3 columns and 21 rows // table with 3 columns and 21 rows
testAbsentAttrs("table15", attr); isDataTable("table15");
// layout table that has a 100% width // layout table that has a 100% width
testAttrs("table16", attr, true); isLayoutTable("table16");
// layout table that has a 95% width in pixels // layout table that has a 95% width in pixels
testAttrs("table17", attr, true); isLayoutTable("table17");
// layout table with less than 10 columns // layout table with less than 10 columns
testAttrs("table18", attr, true); isLayoutTable("table18");
// layout table with embedded iframe // layout table with embedded iframe
testAttrs("table19", attr, true); isLayoutTable("table19");
// tree grid, no layout table // tree grid, no layout table
testAbsentAttrs("table20", attr); isDataTable("table20");
// layout table containing nested data table (having data structures) // layout table containing nested data table (having data structures)
testAttrs("table21", attr, true); isLayoutTable("table21");
testAttrs("table21.2", attr, true); isLayoutTable("table21.2");
testAttrs("table21.3", attr, true); isLayoutTable("table21.3");
testAttrs("table21.4", attr, true); isLayoutTable("table21.4");
testAttrs("table21.5", attr, true); isLayoutTable("table21.5");
testAttrs("table21.6", attr, true); isLayoutTable("table21.6");
// layout table having datatable="0" attribute and containing data table structure (tfoot element) // layout table having datatable="0" attribute and containing data table structure (tfoot element)
testAttrs("table22", attr, true); isLayoutTable("table22");
// layout display:block table with 1 column
isLayoutTable("displayblock_table1");
// matrix
isDataTable("mtable1");
SimpleTest.finish(); SimpleTest.finish();
} }
@ -501,5 +509,32 @@
</tfoot> </tfoot>
</table> </table>
<!-- display:block table -->
<table id="displayblock_table1" style="display:block">
<tr><td>Row1</td></tr>
<tr><td>Row2</td></tr>
</table>
<!-- MathML matrix -->
<math>
<mtable id="mtable1">
<mtr>
<mtd>
<mn>1</mn>
</mtd>
<mtd>
<mn>0</mn>
</mtd>
</mtr>
<mtr>
<mtd>
<mn>0</mn>
</mtd>
<mtd>
<mn>1</mn>
</mtd>
</mtr>
</mtable>
</math>
</body> </body>
</html> </html>

Просмотреть файл

@ -213,21 +213,17 @@ OptionsPanel.prototype = {
"tools-not-supported-label"); "tools-not-supported-label");
let atleastOneToolNotSupported = false; let atleastOneToolNotSupported = false;
const toolbox = this.toolbox;
// Signal tool registering/unregistering globally (for the tools registered // Signal tool registering/unregistering globally (for the tools registered
// globally) and per toolbox (for the tools registered to a single toolbox). // globally) and per toolbox (for the tools registered to a single toolbox).
// This event handler expect this to be binded to the related checkbox element. // This event handler expect this to be binded to the related checkbox element.
let onCheckboxClick = function(tool) { let onCheckboxClick = function(telemetry, tool) {
// Set the kill switch pref boolean to true // Set the kill switch pref boolean to true
Services.prefs.setBoolPref(tool.visibilityswitch, this.checked); Services.prefs.setBoolPref(tool.visibilityswitch, this.checked);
if (!tool.isWebExtension) { if (!tool.isWebExtension) {
gDevTools.emit(this.checked ? "tool-registered" : "tool-unregistered", tool.id); gDevTools.emit(this.checked ? "tool-registered" : "tool-unregistered", tool.id);
// Record which tools were registered and unregistered. // Record which tools were registered and unregistered.
this.telemetry.keyedScalarSet("devtools.tool.registered", telemetry.keyedScalarSet("devtools.tool.registered", tool.id, this.checked);
tool.id,
this.checked);
} }
}; };
@ -253,7 +249,8 @@ OptionsPanel.prototype = {
checkboxInput.setAttribute("checked", "true"); checkboxInput.setAttribute("checked", "true");
} }
checkboxInput.addEventListener("change", onCheckboxClick.bind(checkboxInput, tool)); checkboxInput.addEventListener("change",
onCheckboxClick.bind(checkboxInput, this.telemetry, tool));
checkboxLabel.appendChild(checkboxInput); checkboxLabel.appendChild(checkboxInput);
checkboxLabel.appendChild(checkboxSpanLabel); checkboxLabel.appendChild(checkboxSpanLabel);
@ -287,7 +284,7 @@ OptionsPanel.prototype = {
} }
// Populating the additional tools that came from the installed WebExtension add-ons. // Populating the additional tools that came from the installed WebExtension add-ons.
for (let {uuid, name, pref} of toolbox.listWebExtensions()) { for (let {uuid, name, pref} of this.toolbox.listWebExtensions()) {
atleastOneAddon = true; atleastOneAddon = true;
additionalToolsBox.appendChild(createToolCheckbox({ additionalToolsBox.appendChild(createToolCheckbox({

Просмотреть файл

@ -36,15 +36,10 @@ pref("devtools.inspector.enabled", true);
pref("devtools.inspector.activeSidebar", "ruleview"); pref("devtools.inspector.activeSidebar", "ruleview");
pref("devtools.inspector.remote", false); pref("devtools.inspector.remote", false);
#if defined(NIGHTLY_BUILD)
// Show the 3 pane onboarding tooltip in the inspector // Show the 3 pane onboarding tooltip in the inspector
pref("devtools.inspector.show-three-pane-tooltip", true); pref("devtools.inspector.show-three-pane-tooltip", true);
// Enable the 3 pane mode in the inspector // Enable the 3 pane mode in the inspector
pref("devtools.inspector.three-pane-enabled", true); pref("devtools.inspector.three-pane-enabled", true);
#else
pref("devtools.inspector.show-three-pane-tooltip", false);
pref("devtools.inspector.three-pane-enabled", false);
#endif
// Collapse pseudo-elements by default in the rule-view // Collapse pseudo-elements by default in the rule-view
pref("devtools.inspector.show_pseudo_elements", false); pref("devtools.inspector.show_pseudo_elements", false);

Просмотреть файл

@ -27,6 +27,7 @@ class Telemetry {
this.scalarSet = this.scalarSet.bind(this); this.scalarSet = this.scalarSet.bind(this);
this.scalarAdd = this.scalarAdd.bind(this); this.scalarAdd = this.scalarAdd.bind(this);
this.keyedScalarAdd = this.keyedScalarAdd.bind(this); this.keyedScalarAdd = this.keyedScalarAdd.bind(this);
this.keyedScalarSet = this.keyedScalarSet.bind(this);
this.recordEvent = this.recordEvent.bind(this); this.recordEvent = this.recordEvent.bind(this);
this.setEventRecordingEnabled = this.setEventRecordingEnabled.bind(this); this.setEventRecordingEnabled = this.setEventRecordingEnabled.bind(this);
this.preparePendingEvent = this.preparePendingEvent.bind(this); this.preparePendingEvent = this.preparePendingEvent.bind(this);
@ -246,6 +247,38 @@ class Telemetry {
} }
} }
/**
* Log a value to a keyed scalar.
*
* @param {String} scalarId
* Scalar in which the data is to be stored.
* @param {String} key
* The key within the scalar.
* @param value
* Value to store.
*/
keyedScalarSet(scalarId, key, value) {
if (!scalarId) {
return;
}
try {
if (isNaN(value) && typeof value !== "boolean") {
dump(`Warning: An attempt was made to write a non-numeric and ` +
`non-boolean value ${value} to the ${scalarId} scalar. Only ` +
`numeric and boolean values are allowed.\n` +
`CALLER: ${getCaller()}`);
return;
}
Services.telemetry.keyedScalarSet(scalarId, key, value);
} catch (e) {
dump(`Warning: An attempt was made to write to the ${scalarId} ` +
`scalar, which is not defined in Scalars.yaml\n` +
`CALLER: ${getCaller()}`);
}
}
/** /**
* Log a value to a keyed count scalar. * Log a value to a keyed count scalar.
* *

Просмотреть файл

@ -2039,7 +2039,7 @@ Element::UnbindFromTree(bool aDeep, bool aNullParent)
} }
nsDOMCSSAttributeDeclaration* nsDOMCSSAttributeDeclaration*
Element::GetSMILOverrideStyle() Element::SMILOverrideStyle()
{ {
Element::nsExtendedDOMSlots* slots = ExtendedDOMSlots(); Element::nsExtendedDOMSlots* slots = ExtendedDOMSlots();
@ -4489,7 +4489,7 @@ NoteDirtyElement(Element* aElement, uint32_t aBits)
// We can't check for a frame here, since <frame> elements inside <frameset> // We can't check for a frame here, since <frame> elements inside <frameset>
// still need to generate a frame, even if they're display: none. :( // still need to generate a frame, even if they're display: none. :(
// //
// The servo traversal doesn't keep style data under display: none subtrees, // The servo traversal doesn't keep style data under display: none subtrees,
// so in order for it to not need to cleanup each time anything happens in a // so in order for it to not need to cleanup each time anything happens in a
// display: none subtree, we keep it clean. // display: none subtree, we keep it clean.
// //

Просмотреть файл

@ -361,7 +361,7 @@ public:
* Note: This method is analogous to the 'GetStyle' method in * Note: This method is analogous to the 'GetStyle' method in
* nsGenericHTMLElement and nsStyledElement. * nsGenericHTMLElement and nsStyledElement.
*/ */
nsDOMCSSAttributeDeclaration* GetSMILOverrideStyle(); nsDOMCSSAttributeDeclaration* SMILOverrideStyle();
/** /**
* Returns if the element is labelable as per HTML specification. * Returns if the element is labelable as per HTML specification.

Просмотреть файл

@ -113,11 +113,6 @@ interface nsIImageLoadingContent : imgINotificationObserver
*/ */
[notxpcom, nostdcall] void setBlockedRequest(in int16_t aContentDecision); [notxpcom, nostdcall] void setBlockedRequest(in int16_t aContentDecision);
/**
* @return true if the current request's size is available.
*/
[noscript, notxpcom] boolean currentRequestHasSize();
/** /**
* Used to notify the image loading content node that a frame has been * Used to notify the image loading content node that a frame has been
* created. * created.

Просмотреть файл

@ -135,6 +135,10 @@ nsImageLoadingContent::Notify(imgIRequest* aRequest,
int32_t aType, int32_t aType,
const nsIntRect* aData) const nsIntRect* aData)
{ {
MOZ_ASSERT(aRequest, "no request?");
MOZ_ASSERT(aRequest == mCurrentRequest || aRequest == mPendingRequest,
"Forgot to cancel a previous request?");
if (aType == imgINotificationObserver::IS_ANIMATED) { if (aType == imgINotificationObserver::IS_ANIMATED) {
return OnImageIsAnimated(aRequest); return OnImageIsAnimated(aRequest);
} }
@ -144,14 +148,6 @@ nsImageLoadingContent::Notify(imgIRequest* aRequest,
return NS_OK; return NS_OK;
} }
if (aType == imgINotificationObserver::LOAD_COMPLETE) {
// We should definitely have a request here
MOZ_ASSERT(aRequest, "no request?");
MOZ_ASSERT(aRequest == mCurrentRequest || aRequest == mPendingRequest,
"Unknown request");
}
{ {
// Calling Notify on observers can modify the list of observers so make // Calling Notify on observers can modify the list of observers so make
// a local copy. // a local copy.
@ -629,12 +625,6 @@ nsImageLoadingContent::GetRequest(int32_t aRequestType,
return result.StealNSResult(); return result.StealNSResult();
} }
NS_IMETHODIMP_(bool)
nsImageLoadingContent::CurrentRequestHasSize()
{
return HaveSize(mCurrentRequest);
}
NS_IMETHODIMP_(void) NS_IMETHODIMP_(void)
nsImageLoadingContent::FrameCreated(nsIFrame* aFrame) nsImageLoadingContent::FrameCreated(nsIFrame* aFrame)
{ {

Просмотреть файл

@ -521,7 +521,8 @@ skip-if = toolkit == 'android' #bug 687032
[test_bug698381.html] [test_bug698381.html]
[test_bug698384.html] [test_bug698384.html]
[test_bug704063.html] [test_bug704063.html]
[test_bug704320.html] [test_bug704320-1.html]
[test_bug704320-2.html]
[test_bug704320_policyset.html] [test_bug704320_policyset.html]
[test_bug704320_policyset2.html] [test_bug704320_policyset2.html]
[test_bug704320_preload.html] [test_bug704320_preload.html]

Просмотреть файл

@ -0,0 +1,90 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=704320
This Test is split into two for Bug 1453396
-->
<head>
<meta charset="utf-8">
<title>Test for Bug 704320-Part1</title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="application/javascript" src="referrerHelper.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
<script type="application/javascript">
//generates URLs to test
var generateURLArray = (function(from, to){
const baseURL = '://example.com/tests/dom/base/test/bug704320.sjs?action=create-1st-level-iframe&scheme-from=';
const schemeTo = '&scheme-to=';
return [
from + baseURL + from + schemeTo + to + '&policy=no-referrer-when-downgrade',
from + baseURL + from + schemeTo + to + '&policy=no-referrer',
from + baseURL + from + schemeTo + to + '&policy=unsafe-url',
from + baseURL + from + schemeTo + to + '&policy=origin',
from + baseURL + from + schemeTo + to + '&policy=origin-when-cross-origin',
from + baseURL + from + schemeTo + to + '&policy=same-origin',
from + baseURL + from + schemeTo + to + '&policy=strict-origin',
from + baseURL + from + schemeTo + to + '&policy=strict-origin-when-cross-origin',
];
});
let testIframeUrls = [generateURLArray('http', 'http'),
generateURLArray('https', 'https')];
SimpleTest.waitForExplicitFinish();
let advance = function(testName) {
testsGenerator[testName].next();
};
let testNames = ['testframeone', 'testframetwo'];
let isTestFinished = 0;
function checkTestsCompleted() {
isTestFinished++;
if (isTestFinished == 2) {
SimpleTest.finish();
}
}
let testsGenerator = {};
SimpleTest.requestLongerTimeout(4);
/**
* This is the main test routine -- serialized by use of a generator.
* It performs all tests in sequence using four iframes.
*/
function startTests(testName, testIframeUrls) {
testsGenerator[testName] = (function*() {
var testframe = document.getElementById(testName);
testframe.onload = function() {
advance(testName);
}
// load the test frame from testIframeUrls[url]
// it will call back into this function via postMessage when it finishes
// loading and continue beyond the yield.
for(url in testIframeUrls) {
yield testframe.src = testIframeUrls[url];
// run test and check result for loaded test URL
yield checkExpectedGlobalResults(testName);
}
checkTestsCompleted();
})();
}
for (i = 0; i < testIframeUrls.length; i++) {
startTests(testNames[i], testIframeUrls[i]);
}
</script>
</head>
<body onload="testsGenerator[testNames[0]].next();
testsGenerator[testNames[1]].next();">
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=704320">Mozilla Bug 704320 - HTTP/HTTPS to HTTPS/HTTP</a>
<p id="display"></p>
<pre id="content">
</pre>
<iframe id="testframeone"></iframe>
<iframe id="testframetwo"></iframe>
</body>

Просмотреть файл

@ -2,10 +2,11 @@
<html> <html>
<!-- <!--
https://bugzilla.mozilla.org/show_bug.cgi?id=704320 https://bugzilla.mozilla.org/show_bug.cgi?id=704320
This Test is split into two for Bug 1453396
--> -->
<head> <head>
<meta charset="utf-8"> <meta charset="utf-8">
<title>Test for Bug 704320</title> <title>Test for Bug 704320-Part2</title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script> <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="application/javascript" src="referrerHelper.js"></script> <script type="application/javascript" src="referrerHelper.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
@ -29,9 +30,7 @@ var generateURLArray = (function(from, to){
]; ];
}); });
let testIframeUrls = [generateURLArray('http', 'http'), let testIframeUrls = [generateURLArray('http', 'https'),
generateURLArray('https', 'https'),
generateURLArray('http', 'https'),
generateURLArray('https', 'http')]; generateURLArray('https', 'http')];
SimpleTest.waitForExplicitFinish(); SimpleTest.waitForExplicitFinish();
@ -39,13 +38,12 @@ let advance = function(testName) {
testsGenerator[testName].next(); testsGenerator[testName].next();
}; };
let testNames = ['testframeone', 'testframetwo', 'testframethree', let testNames = ['testframeone', 'testframetwo'];
'testframefour'];
let isTestFinished = 0; let isTestFinished = 0;
function checkTestsCompleted() { function checkTestsCompleted() {
isTestFinished++; isTestFinished++;
if (isTestFinished == 4) { if (isTestFinished == 2) {
SimpleTest.finish(); SimpleTest.finish();
} }
} }
@ -82,15 +80,11 @@ for (i = 0; i < testIframeUrls.length; i++) {
</head> </head>
<body onload="testsGenerator[testNames[0]].next(); <body onload="testsGenerator[testNames[0]].next();
testsGenerator[testNames[1]].next(); testsGenerator[testNames[1]].next();">
testsGenerator[testNames[2]].next();
testsGenerator[testNames[3]].next();">
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=704320">Mozilla Bug 704320 - HTTP/HTTPS to HTTPS/HTTP</a> <a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=704320">Mozilla Bug 704320 - HTTP/HTTPS to HTTPS/HTTP</a>
<p id="display"></p> <p id="display"></p>
<pre id="content"> <pre id="content">
</pre> </pre>
<iframe id="testframeone"></iframe> <iframe id="testframeone"></iframe>
<iframe id="testframetwo"></iframe> <iframe id="testframetwo"></iframe>
<iframe id="testframethree"></iframe>
<iframe id="testframefour"></iframe>
</body> </body>

Просмотреть файл

@ -481,7 +481,9 @@ public:
return NS_OK; return NS_OK;
} }
#ifdef MOZ_COLLECTING_RUNNABLE_TELEMETRY
using nsINamed::GetName; using nsINamed::GetName;
#endif
// nsIAsyncShutdownBlocker interface // nsIAsyncShutdownBlocker interface

Просмотреть файл

@ -13,6 +13,7 @@
#include "nsSize.h" #include "nsSize.h"
#include "nsDocument.h" #include "nsDocument.h"
#include "nsIDocument.h" #include "nsIDocument.h"
#include "nsImageFrame.h"
#include "nsIScriptContext.h" #include "nsIScriptContext.h"
#include "nsIURL.h" #include "nsIURL.h"
#include "nsIIOService.h" #include "nsIIOService.h"
@ -949,7 +950,7 @@ HTMLImageElement::InResponsiveMode()
} }
bool bool
HTMLImageElement::SelectedSourceMatchesLast(nsIURI* aSelectedSource, double aSelectedDensity) HTMLImageElement::SelectedSourceMatchesLast(nsIURI* aSelectedSource)
{ {
// If there was no selected source previously, we don't want to short-circuit the load. // If there was no selected source previously, we don't want to short-circuit the load.
// Similarly for if there is no newly selected source. // Similarly for if there is no newly selected source.
@ -957,32 +958,58 @@ HTMLImageElement::SelectedSourceMatchesLast(nsIURI* aSelectedSource, double aSel
return false; return false;
} }
bool equal = false; bool equal = false;
return NS_SUCCEEDED(mLastSelectedSource->Equals(aSelectedSource, &equal)) && equal && return NS_SUCCEEDED(mLastSelectedSource->Equals(aSelectedSource, &equal)) && equal;
aSelectedDensity == mCurrentDensity;
} }
nsresult nsresult
HTMLImageElement::LoadSelectedImage(bool aForce, bool aNotify, bool aAlwaysLoad) HTMLImageElement::LoadSelectedImage(bool aForce, bool aNotify, bool aAlwaysLoad)
{ {
nsresult rv = NS_ERROR_FAILURE; double currentDensity = 1.0; // default to 1.0 for the src attribute case
// Helper to update state when only density may have changed (i.e., the source
// to load hasn't changed, and we don't do any request at all). We need (apart
// from updating our internal state) to tell the image frame because its
// intrinsic size may have changed.
//
// In the case we actually trigger a new load, that load will trigger a call
// to nsImageFrame::NotifyNewCurrentRequest, which takes care of that for us.
auto UpdateDensityOnly = [&]() -> void {
if (mCurrentDensity == currentDensity) {
return;
}
mCurrentDensity = currentDensity;
if (nsImageFrame* f = do_QueryFrame(GetPrimaryFrame())) {
f->ResponsiveContentDensityChanged();
}
};
if (aForce) { if (aForce) {
// In responsive mode we generally want to re-run the full // In responsive mode we generally want to re-run the full selection
// selection algorithm whenever starting a new load, per // algorithm whenever starting a new load, per spec.
// spec. This also causes us to re-resolve the URI as appropriate. //
if (!UpdateResponsiveSource() && !aAlwaysLoad) { // This also causes us to re-resolve the URI as appropriate.
const bool sourceChanged = UpdateResponsiveSource();
if (mResponsiveSelector) {
currentDensity = mResponsiveSelector->GetSelectedImageDensity();
}
if (!sourceChanged && !aAlwaysLoad) {
UpdateDensityOnly();
return NS_OK; return NS_OK;
} }
} else if (mResponsiveSelector) {
currentDensity = mResponsiveSelector->GetSelectedImageDensity();
} }
nsresult rv = NS_ERROR_FAILURE;
nsCOMPtr<nsIURI> selectedSource; nsCOMPtr<nsIURI> selectedSource;
double currentDensity = 1.0; // default to 1.0 for the src attribute case
if (mResponsiveSelector) { if (mResponsiveSelector) {
nsCOMPtr<nsIURI> url = mResponsiveSelector->GetSelectedImageURL(); nsCOMPtr<nsIURI> url = mResponsiveSelector->GetSelectedImageURL();
nsCOMPtr<nsIPrincipal> triggeringPrincipal = mResponsiveSelector->GetSelectedImageTriggeringPrincipal(); nsCOMPtr<nsIPrincipal> triggeringPrincipal = mResponsiveSelector->GetSelectedImageTriggeringPrincipal();
selectedSource = url; selectedSource = url;
currentDensity = mResponsiveSelector->GetSelectedImageDensity(); if (!aAlwaysLoad && SelectedSourceMatchesLast(selectedSource)) {
if (!aAlwaysLoad && SelectedSourceMatchesLast(selectedSource, currentDensity)) { UpdateDensityOnly();
return NS_OK; return NS_OK;
} }
if (url) { if (url) {
@ -995,12 +1022,11 @@ HTMLImageElement::LoadSelectedImage(bool aForce, bool aNotify, bool aAlwaysLoad)
CancelImageRequests(aNotify); CancelImageRequests(aNotify);
rv = NS_OK; rv = NS_OK;
} else { } else {
nsIDocument* doc = GetOurOwnerDoc(); nsIDocument* doc = OwnerDoc();
if (doc) { StringToURI(src, doc, getter_AddRefs(selectedSource));
StringToURI(src, doc, getter_AddRefs(selectedSource)); if (!aAlwaysLoad && SelectedSourceMatchesLast(selectedSource)) {
if (!aAlwaysLoad && SelectedSourceMatchesLast(selectedSource, currentDensity)) { UpdateDensityOnly();
return NS_OK; return NS_OK;
}
} }
// If we have a srcset attribute or are in a <picture> element, // If we have a srcset attribute or are in a <picture> element,

Просмотреть файл

@ -43,6 +43,11 @@ public:
virtual bool Draggable() const override; virtual bool Draggable() const override;
ResponsiveImageSelector* GetResponsiveImageSelector()
{
return mResponsiveSelector.get();
}
// Element // Element
virtual bool IsInteractiveHTMLContent(bool aIgnoreTabindex) const override; virtual bool IsInteractiveHTMLContent(bool aIgnoreTabindex) const override;
@ -325,8 +330,8 @@ protected:
// only mode after Bug 1076583 // only mode after Bug 1076583
bool InResponsiveMode(); bool InResponsiveMode();
// True if the given URL and density equal the last URL and density that was loaded by this element. // True if the given URL equals the last URL that was loaded by this element.
bool SelectedSourceMatchesLast(nsIURI* aSelectedSource, double aSelectedDensity); bool SelectedSourceMatchesLast(nsIURI* aSelectedSource);
// Resolve and load the current mResponsiveSelector (responsive mode) or src // Resolve and load the current mResponsiveSelector (responsive mode) or src
// attr image. // attr image.

Просмотреть файл

@ -902,6 +902,10 @@ nsPluginInstanceOwner::RequestCommitOrCancel(bool aCommitted)
bool bool
nsPluginInstanceOwner::EnableIME(bool aEnable) nsPluginInstanceOwner::EnableIME(bool aEnable)
{ {
if (NS_WARN_IF(!mPluginFrame)) {
return false;
}
nsCOMPtr<nsIWidget> widget = GetContainingWidgetIfOffset(); nsCOMPtr<nsIWidget> widget = GetContainingWidgetIfOffset();
if (!widget) { if (!widget) {
widget = GetRootWidgetForPluginFrame(mPluginFrame); widget = GetRootWidgetForPluginFrame(mPluginFrame);

Просмотреть файл

@ -107,17 +107,14 @@ nsresult
nsSMILCSSProperty::SetAnimValue(const nsSMILValue& aValue) nsSMILCSSProperty::SetAnimValue(const nsSMILValue& aValue)
{ {
NS_ENSURE_TRUE(IsPropertyAnimatable(mPropID), NS_ERROR_FAILURE); NS_ENSURE_TRUE(IsPropertyAnimatable(mPropID), NS_ERROR_FAILURE);
return mElement->GetSMILOverrideStyle()->SetSMILValue(mPropID, aValue); return mElement->SMILOverrideStyle()->SetSMILValue(mPropID, aValue);
} }
void void
nsSMILCSSProperty::ClearAnimValue() nsSMILCSSProperty::ClearAnimValue()
{ {
// Put empty string in override style for our property // Put empty string in override style for our property
nsDOMCSSAttributeDeclaration* overrideDecl = mElement->GetSMILOverrideStyle(); mElement->SMILOverrideStyle()->SetPropertyValue(mPropID, EmptyString(), nullptr);
if (overrideDecl) {
overrideDecl->SetPropertyValue(mPropID, EmptyString(), nullptr);
}
} }
// Based on http://www.w3.org/TR/SVG/propidx.html // Based on http://www.w3.org/TR/SVG/propidx.html

Просмотреть файл

@ -564,7 +564,12 @@ static bool clip_to_limit(const SkRegion& orig, SkRegion* reduced) {
// Bias used for conservative rounding of float rects to int rects, to nudge the irects a little // Bias used for conservative rounding of float rects to int rects, to nudge the irects a little
// larger, so we don't "think" a path's bounds are inside a clip, when (due to numeric drift in // larger, so we don't "think" a path's bounds are inside a clip, when (due to numeric drift in
// the scan-converter) we might walk beyond the predicted limits. // the scan-converter) we might walk beyond the predicted limits.
static const double kConservativeRoundBias = 0.5 + 0.5 / SK_FDot6One; //
// This value has been determined trial and error: pick the smallest value (after the 0.5) that
// fixes any problematic cases (e.g. crbug.com/844457)
// NOTE: cubics appear to be the main reason for needing this slop. If we could (perhaps) have a
// more accurate walker for cubics, we may be able to reduce this fudge factor.
static const double kConservativeRoundBias = 0.5 + 1.5 / SK_FDot6One;
/** /**
* Round the value down. This is used to round the top and left of a rectangle, * Round the value down. This is used to round the top and left of a rectangle,

Просмотреть файл

@ -29,6 +29,7 @@
#include "mozilla/Likely.h" #include "mozilla/Likely.h"
#include "mozilla/Maybe.h" #include "mozilla/Maybe.h"
#include "mozilla/Move.h" #include "mozilla/Move.h"
#include "mozilla/Tuple.h"
#include "mozilla/UniquePtr.h" #include "mozilla/UniquePtr.h"
#include "mozilla/Unused.h" #include "mozilla/Unused.h"
#include "mozilla/Variant.h" #include "mozilla/Variant.h"
@ -174,6 +175,43 @@ public:
return *result; return *result;
} }
/**
* Write pixels to the surface by calling a lambda which may write as many
* pixels as there is remaining to complete the row. It is not completely
* memory safe as it trusts the underlying decoder not to overrun the given
* buffer, however it is an acceptable tradeoff for performance.
*
* Writing continues until every pixel in the surface has been written to
* (i.e., IsSurfaceFinished() returns true) or the lambda returns a WriteState
* which WritePixelBlocks() will return to the caller.
*
* The template parameter PixelType must be uint8_t (for paletted surfaces) or
* uint32_t (for BGRA/BGRX surfaces) and must be in agreement with the pixel
* size passed to ConfigureFilter().
*
* XXX(seth): We'll remove all support for paletted surfaces in bug 1247520,
* which means we can remove the PixelType template parameter from this
* method.
*
* @param aFunc A lambda that functions as a generator, yielding at most the
* maximum number of pixels requested. The lambda must accept a
* pointer argument to the first pixel to write, a maximum
* number of pixels to write as part of the block, and return a
* NextPixel<PixelType> value.
*
* @return A WriteState value indicating the lambda generator's state.
* WritePixelBlocks() itself will return WriteState::FINISHED if
* writing has finished, regardless of the lambda's internal state.
*/
template <typename PixelType, typename Func>
WriteState WritePixelBlocks(Func aFunc)
{
Maybe<WriteState> result;
while (!(result = DoWritePixelBlockToRow<PixelType>(Forward<Func>(aFunc)))) { }
return *result;
}
/** /**
* A variant of WritePixels() that writes a single row of pixels to the * A variant of WritePixels() that writes a single row of pixels to the
* surface one at a time by repeatedly calling a lambda that yields pixels. * surface one at a time by repeatedly calling a lambda that yields pixels.
@ -448,6 +486,50 @@ protected:
private: private:
/**
* An internal method used to implement WritePixelBlocks. This method writes
* up to the number of pixels necessary to complete the row and returns Some()
* if we either finished the entire surface or the lambda returned a
* WriteState indicating that we should return to the caller. If the row was
* successfully written without either of those things happening, it returns
* Nothing(), allowing WritePixelBlocks() to iterate to fill as many rows as
* possible.
*/
template <typename PixelType, typename Func>
Maybe<WriteState> DoWritePixelBlockToRow(Func aFunc)
{
MOZ_ASSERT(mPixelSize == 1 || mPixelSize == 4);
MOZ_ASSERT_IF(mPixelSize == 1, sizeof(PixelType) == sizeof(uint8_t));
MOZ_ASSERT_IF(mPixelSize == 4, sizeof(PixelType) == sizeof(uint32_t));
if (IsSurfaceFinished()) {
return Some(WriteState::FINISHED); // We're already done.
}
PixelType* rowPtr = reinterpret_cast<PixelType*>(mRowPointer);
int32_t remainder = mInputSize.width - mCol;
int32_t written;
Maybe<WriteState> result;
Tie(written, result) = aFunc(&rowPtr[mCol], remainder);
if (written == remainder) {
MOZ_ASSERT(result.isNothing());
mCol = mInputSize.width;
AdvanceRow(); // We've finished the row.
return IsSurfaceFinished() ? Some(WriteState::FINISHED)
: Nothing();
}
MOZ_ASSERT(written >= 0 && written < remainder);
MOZ_ASSERT(result.isSome());
mCol += written;
if (*result == WriteState::FINISHED) {
ZeroOutRestOfSurface<PixelType>();
}
return result;
}
/** /**
* An internal method used to implement both WritePixels() and * An internal method used to implement both WritePixels() and
* WritePixelsToRow(). Those methods differ only in their behavior after a row * WritePixelsToRow(). Those methods differ only in their behavior after a row
@ -558,6 +640,20 @@ public:
return mHead->WritePixels<PixelType>(Forward<Func>(aFunc)); return mHead->WritePixels<PixelType>(Forward<Func>(aFunc));
} }
/**
* A variant of WritePixels() that writes up to a single row of pixels to the
* surface in blocks by repeatedly calling a lambda that yields up to the
* requested number of pixels.
*
* @see SurfaceFilter::WritePixelBlocks() for the canonical documentation.
*/
template <typename PixelType, typename Func>
WriteState WritePixelBlocks(Func aFunc)
{
MOZ_ASSERT(mHead, "Use before configured!");
return mHead->WritePixelBlocks<PixelType>(Forward<Func>(aFunc));
}
/** /**
* A variant of WritePixels() that writes a single row of pixels to the * A variant of WritePixels() that writes a single row of pixels to the
* surface one at a time by repeatedly calling a lambda that yields pixels. * surface one at a time by repeatedly calling a lambda that yields pixels.

Просмотреть файл

@ -292,10 +292,12 @@ nsGIFDecoder2::ColormapIndexToPixel<uint8_t>(uint8_t aIndex)
} }
template <typename PixelSize> template <typename PixelSize>
NextPixel<PixelSize> Tuple<int32_t, Maybe<WriteState>>
nsGIFDecoder2::YieldPixel(const uint8_t* aData, nsGIFDecoder2::YieldPixels(const uint8_t* aData,
size_t aLength, size_t aLength,
size_t* aBytesReadOut) size_t* aBytesReadOut,
PixelSize* aPixelBlock,
int32_t aBlockSize)
{ {
MOZ_ASSERT(aData); MOZ_ASSERT(aData);
MOZ_ASSERT(aBytesReadOut); MOZ_ASSERT(aBytesReadOut);
@ -304,108 +306,119 @@ nsGIFDecoder2::YieldPixel(const uint8_t* aData,
// Advance to the next byte we should read. // Advance to the next byte we should read.
const uint8_t* data = aData + *aBytesReadOut; const uint8_t* data = aData + *aBytesReadOut;
// If we don't have any decoded data to yield, try to read some input and int32_t written = 0;
// produce some. while (aBlockSize > written) {
if (mGIFStruct.stackp == mGIFStruct.stack) { // If we don't have any decoded data to yield, try to read some input and
while (mGIFStruct.bits < mGIFStruct.codesize && *aBytesReadOut < aLength) { // produce some.
// Feed the next byte into the decoder's 32-bit input buffer. if (mGIFStruct.stackp == mGIFStruct.stack) {
mGIFStruct.datum += int32_t(*data) << mGIFStruct.bits; while (mGIFStruct.bits < mGIFStruct.codesize && *aBytesReadOut < aLength) {
mGIFStruct.bits += 8; // Feed the next byte into the decoder's 32-bit input buffer.
data += 1; mGIFStruct.datum += int32_t(*data) << mGIFStruct.bits;
*aBytesReadOut += 1; mGIFStruct.bits += 8;
} data += 1;
*aBytesReadOut += 1;
if (mGIFStruct.bits < mGIFStruct.codesize) {
return AsVariant(WriteState::NEED_MORE_DATA);
}
// Get the leading variable-length symbol from the data stream.
int code = mGIFStruct.datum & mGIFStruct.codemask;
mGIFStruct.datum >>= mGIFStruct.codesize;
mGIFStruct.bits -= mGIFStruct.codesize;
const int clearCode = ClearCode();
// Reset the dictionary to its original state, if requested
if (code == clearCode) {
mGIFStruct.codesize = mGIFStruct.datasize + 1;
mGIFStruct.codemask = (1 << mGIFStruct.codesize) - 1;
mGIFStruct.avail = clearCode + 2;
mGIFStruct.oldcode = -1;
return AsVariant(WriteState::NEED_MORE_DATA);
}
// Check for explicit end-of-stream code. It should only appear after all
// image data, but if that was the case we wouldn't be in this function, so
// this is always an error condition.
if (code == (clearCode + 1)) {
return AsVariant(WriteState::FAILURE);
}
if (mGIFStruct.oldcode == -1) {
if (code >= MAX_BITS) {
return AsVariant(WriteState::FAILURE); // The code's too big; something's wrong.
} }
mGIFStruct.firstchar = mGIFStruct.oldcode = code; if (mGIFStruct.bits < mGIFStruct.codesize) {
return MakeTuple(written, Some(WriteState::NEED_MORE_DATA));
// Yield a pixel at the appropriate index in the colormap.
mGIFStruct.pixels_remaining--;
return AsVariant(ColormapIndexToPixel<PixelSize>(mGIFStruct.suffix[code]));
}
int incode = code;
if (code >= mGIFStruct.avail) {
*mGIFStruct.stackp++ = mGIFStruct.firstchar;
code = mGIFStruct.oldcode;
if (mGIFStruct.stackp >= mGIFStruct.stack + MAX_BITS) {
return AsVariant(WriteState::FAILURE); // Stack overflow; something's wrong.
}
}
while (code >= clearCode) {
if ((code >= MAX_BITS) || (code == mGIFStruct.prefix[code])) {
return AsVariant(WriteState::FAILURE);
} }
*mGIFStruct.stackp++ = mGIFStruct.suffix[code]; // Get the leading variable-length symbol from the data stream.
code = mGIFStruct.prefix[code]; int code = mGIFStruct.datum & mGIFStruct.codemask;
mGIFStruct.datum >>= mGIFStruct.codesize;
mGIFStruct.bits -= mGIFStruct.codesize;
if (mGIFStruct.stackp >= mGIFStruct.stack + MAX_BITS) { const int clearCode = ClearCode();
return AsVariant(WriteState::FAILURE); // Stack overflow; something's wrong.
// Reset the dictionary to its original state, if requested
if (code == clearCode) {
mGIFStruct.codesize = mGIFStruct.datasize + 1;
mGIFStruct.codemask = (1 << mGIFStruct.codesize) - 1;
mGIFStruct.avail = clearCode + 2;
mGIFStruct.oldcode = -1;
return MakeTuple(written, Some(WriteState::NEED_MORE_DATA));
} }
// Check for explicit end-of-stream code. It should only appear after all
// image data, but if that was the case we wouldn't be in this function, so
// this is always an error condition.
if (code == (clearCode + 1)) {
return MakeTuple(written, Some(WriteState::FAILURE));
}
if (mGIFStruct.oldcode == -1) {
if (code >= MAX_BITS) {
// The code's too big; something's wrong.
return MakeTuple(written, Some(WriteState::FAILURE));
}
mGIFStruct.firstchar = mGIFStruct.oldcode = code;
// Yield a pixel at the appropriate index in the colormap.
mGIFStruct.pixels_remaining--;
aPixelBlock[written++] =
ColormapIndexToPixel<PixelSize>(mGIFStruct.suffix[code]);
continue;
}
int incode = code;
if (code >= mGIFStruct.avail) {
*mGIFStruct.stackp++ = mGIFStruct.firstchar;
code = mGIFStruct.oldcode;
if (mGIFStruct.stackp >= mGIFStruct.stack + MAX_BITS) {
// Stack overflow; something's wrong.
return MakeTuple(written, Some(WriteState::FAILURE));
}
}
while (code >= clearCode) {
if ((code >= MAX_BITS) || (code == mGIFStruct.prefix[code])) {
return MakeTuple(written, Some(WriteState::FAILURE));
}
*mGIFStruct.stackp++ = mGIFStruct.suffix[code];
code = mGIFStruct.prefix[code];
if (mGIFStruct.stackp >= mGIFStruct.stack + MAX_BITS) {
// Stack overflow; something's wrong.
return MakeTuple(written, Some(WriteState::FAILURE));
}
}
*mGIFStruct.stackp++ = mGIFStruct.firstchar = mGIFStruct.suffix[code];
// Define a new codeword in the dictionary.
if (mGIFStruct.avail < 4096) {
mGIFStruct.prefix[mGIFStruct.avail] = mGIFStruct.oldcode;
mGIFStruct.suffix[mGIFStruct.avail] = mGIFStruct.firstchar;
mGIFStruct.avail++;
// If we've used up all the codewords of a given length increase the
// length of codewords by one bit, but don't exceed the specified maximum
// codeword size of 12 bits.
if (((mGIFStruct.avail & mGIFStruct.codemask) == 0) &&
(mGIFStruct.avail < 4096)) {
mGIFStruct.codesize++;
mGIFStruct.codemask += mGIFStruct.avail;
}
}
mGIFStruct.oldcode = incode;
} }
*mGIFStruct.stackp++ = mGIFStruct.firstchar = mGIFStruct.suffix[code]; if (MOZ_UNLIKELY(mGIFStruct.stackp <= mGIFStruct.stack)) {
MOZ_ASSERT_UNREACHABLE("No decoded data but we didn't return early?");
// Define a new codeword in the dictionary. return MakeTuple(written, Some(WriteState::FAILURE));
if (mGIFStruct.avail < 4096) {
mGIFStruct.prefix[mGIFStruct.avail] = mGIFStruct.oldcode;
mGIFStruct.suffix[mGIFStruct.avail] = mGIFStruct.firstchar;
mGIFStruct.avail++;
// If we've used up all the codewords of a given length increase the
// length of codewords by one bit, but don't exceed the specified maximum
// codeword size of 12 bits.
if (((mGIFStruct.avail & mGIFStruct.codemask) == 0) &&
(mGIFStruct.avail < 4096)) {
mGIFStruct.codesize++;
mGIFStruct.codemask += mGIFStruct.avail;
}
} }
mGIFStruct.oldcode = incode; // Yield a pixel at the appropriate index in the colormap.
mGIFStruct.pixels_remaining--;
aPixelBlock[written++]
= ColormapIndexToPixel<PixelSize>(*--mGIFStruct.stackp);
} }
if (MOZ_UNLIKELY(mGIFStruct.stackp <= mGIFStruct.stack)) { return MakeTuple(written, Maybe<WriteState>());
MOZ_ASSERT_UNREACHABLE("No decoded data but we didn't return early?");
return AsVariant(WriteState::FAILURE);
}
// Yield a pixel at the appropriate index in the colormap.
mGIFStruct.pixels_remaining--;
return AsVariant(ColormapIndexToPixel<PixelSize>(*--mGIFStruct.stackp));
} }
/// Expand the colormap from RGB to Packed ARGB as needed by Cairo. /// Expand the colormap from RGB to Packed ARGB as needed by Cairo.
@ -1032,8 +1045,12 @@ nsGIFDecoder2::ReadLZWData(const char* aData, size_t aLength)
size_t bytesRead = 0; size_t bytesRead = 0;
auto result = mGIFStruct.images_decoded == 0 auto result = mGIFStruct.images_decoded == 0
? mPipe.WritePixels<uint32_t>([&]{ return YieldPixel<uint32_t>(data, length, &bytesRead); }) ? mPipe.WritePixelBlocks<uint32_t>([&](uint32_t* aPixelBlock, int32_t aBlockSize) {
: mPipe.WritePixels<uint8_t>([&]{ return YieldPixel<uint8_t>(data, length, &bytesRead); }); return YieldPixels<uint32_t>(data, length, &bytesRead, aPixelBlock, aBlockSize);
})
: mPipe.WritePixelBlocks<uint8_t>([&](uint8_t* aPixelBlock, int32_t aBlockSize) {
return YieldPixels<uint8_t>(data, length, &bytesRead, aPixelBlock, aBlockSize);
});
if (MOZ_UNLIKELY(bytesRead > length)) { if (MOZ_UNLIKELY(bytesRead > length)) {
MOZ_ASSERT_UNREACHABLE("Overread?"); MOZ_ASSERT_UNREACHABLE("Overread?");

Просмотреть файл

@ -65,8 +65,12 @@ private:
ColormapIndexToPixel(uint8_t aIndex); ColormapIndexToPixel(uint8_t aIndex);
/// A generator function that performs LZW decompression and yields pixels. /// A generator function that performs LZW decompression and yields pixels.
template <typename PixelSize> NextPixel<PixelSize> template <typename PixelSize> Tuple<int32_t, Maybe<WriteState>>
YieldPixel(const uint8_t* aData, size_t aLength, size_t* aBytesReadOut); YieldPixels(const uint8_t* aData,
size_t aLength,
size_t* aBytesReadOut,
PixelSize* aPixelBlock,
int32_t aBlockSize);
/// Checks if we have transparency, either because the header indicates that /// Checks if we have transparency, either because the header indicates that
/// there's alpha, or because the frame rect doesn't cover the entire image. /// there's alpha, or because the frame rect doesn't cover the entire image.

Просмотреть файл

@ -305,12 +305,14 @@ imgTools::DecodeImageAsync(nsIInputStream* aInStr,
*/ */
static nsresult static nsresult
EncodeImageData(DataSourceSurface* aDataSurface, EncodeImageData(DataSourceSurface* aDataSurface,
DataSourceSurface::ScopedMap& aMap,
const nsACString& aMimeType, const nsACString& aMimeType,
const nsAString& aOutputOptions, const nsAString& aOutputOptions,
nsIInputStream** aStream) nsIInputStream** aStream)
{ {
MOZ_ASSERT(aDataSurface->GetFormat() == SurfaceFormat::B8G8R8A8, MOZ_ASSERT(aDataSurface->GetFormat() == SurfaceFormat::B8G8R8A8 ||
"We're assuming B8G8R8A8"); aDataSurface->GetFormat() == SurfaceFormat::B8G8R8X8,
"We're assuming B8G8R8A8/X8");
// Get an image encoder for the media type // Get an image encoder for the media type
nsAutoCString encoderCID( nsAutoCString encoderCID(
@ -321,29 +323,37 @@ EncodeImageData(DataSourceSurface* aDataSurface,
return NS_IMAGELIB_ERROR_NO_ENCODER; return NS_IMAGELIB_ERROR_NO_ENCODER;
} }
DataSourceSurface::MappedSurface map;
if (!aDataSurface->Map(DataSourceSurface::MapType::READ, &map)) {
return NS_ERROR_FAILURE;
}
IntSize size = aDataSurface->GetSize(); IntSize size = aDataSurface->GetSize();
uint32_t dataLength = map.mStride * size.height; uint32_t dataLength = aMap.GetStride() * size.height;
// Encode the bitmap // Encode the bitmap
nsresult rv = encoder->InitFromData(map.mData, nsresult rv = encoder->InitFromData(aMap.GetData(),
dataLength, dataLength,
size.width, size.width,
size.height, size.height,
map.mStride, aMap.GetStride(),
imgIEncoder::INPUT_FORMAT_HOSTARGB, imgIEncoder::INPUT_FORMAT_HOSTARGB,
aOutputOptions); aOutputOptions);
aDataSurface->Unmap();
NS_ENSURE_SUCCESS(rv, rv); NS_ENSURE_SUCCESS(rv, rv);
encoder.forget(aStream); encoder.forget(aStream);
return NS_OK; return NS_OK;
} }
static nsresult
EncodeImageData(DataSourceSurface* aDataSurface,
const nsACString& aMimeType,
const nsAString& aOutputOptions,
nsIInputStream** aStream)
{
DataSourceSurface::ScopedMap map(aDataSurface, DataSourceSurface::READ);
if (!map.IsMapped()) {
return NS_ERROR_FAILURE;
}
return EncodeImageData(aDataSurface, map, aMimeType, aOutputOptions, aStream);
}
NS_IMETHODIMP NS_IMETHODIMP
imgTools::EncodeImage(imgIContainer* aContainer, imgTools::EncodeImage(imgIContainer* aContainer,
const nsACString& aMimeType, const nsACString& aMimeType,
@ -358,7 +368,8 @@ imgTools::EncodeImage(imgIContainer* aContainer,
RefPtr<DataSourceSurface> dataSurface; RefPtr<DataSourceSurface> dataSurface;
if (frame->GetFormat() == SurfaceFormat::B8G8R8A8) { if (frame->GetFormat() == SurfaceFormat::B8G8R8A8 ||
frame->GetFormat() == SurfaceFormat::B8G8R8X8) {
dataSurface = frame->GetDataSurface(); dataSurface = frame->GetDataSurface();
} else { } else {
// Convert format to SurfaceFormat::B8G8R8A8 // Convert format to SurfaceFormat::B8G8R8A8
@ -407,22 +418,33 @@ imgTools::EncodeScaledImage(imgIContainer* aContainer,
imgIContainer::FLAG_SYNC_DECODE); imgIContainer::FLAG_SYNC_DECODE);
NS_ENSURE_TRUE(frame, NS_ERROR_FAILURE); NS_ENSURE_TRUE(frame, NS_ERROR_FAILURE);
// If the given surface is the right size/format, we can encode it directly.
if (scaledSize == frame->GetSize() &&
(frame->GetFormat() == SurfaceFormat::B8G8R8A8 ||
frame->GetFormat() == SurfaceFormat::B8G8R8X8)) {
RefPtr<DataSourceSurface> dataSurface = frame->GetDataSurface();
if (dataSurface) {
return EncodeImageData(dataSurface, aMimeType, aOutputOptions, aStream);
}
}
// Otherwise we need to scale it using a draw target.
RefPtr<DataSourceSurface> dataSurface = RefPtr<DataSourceSurface> dataSurface =
Factory::CreateDataSourceSurface(scaledSize, SurfaceFormat::B8G8R8A8); Factory::CreateDataSourceSurface(scaledSize, SurfaceFormat::B8G8R8A8);
if (NS_WARN_IF(!dataSurface)) { if (NS_WARN_IF(!dataSurface)) {
return NS_ERROR_FAILURE; return NS_ERROR_FAILURE;
} }
DataSourceSurface::MappedSurface map; DataSourceSurface::ScopedMap map(dataSurface, DataSourceSurface::READ_WRITE);
if (!dataSurface->Map(DataSourceSurface::MapType::WRITE, &map)) { if (!map.IsMapped()) {
return NS_ERROR_FAILURE; return NS_ERROR_FAILURE;
} }
RefPtr<DrawTarget> dt = RefPtr<DrawTarget> dt =
Factory::CreateDrawTargetForData(BackendType::CAIRO, Factory::CreateDrawTargetForData(BackendType::SKIA,
map.mData, map.GetData(),
dataSurface->GetSize(), dataSurface->GetSize(),
map.mStride, map.GetStride(),
SurfaceFormat::B8G8R8A8); SurfaceFormat::B8G8R8A8);
if (!dt) { if (!dt) {
gfxWarning() << "imgTools::EncodeImage failed in CreateDrawTargetForData"; gfxWarning() << "imgTools::EncodeImage failed in CreateDrawTargetForData";
@ -436,9 +458,7 @@ imgTools::EncodeScaledImage(imgIContainer* aContainer,
DrawSurfaceOptions(), DrawSurfaceOptions(),
DrawOptions(1.0f, CompositionOp::OP_SOURCE)); DrawOptions(1.0f, CompositionOp::OP_SOURCE));
dataSurface->Unmap(); return EncodeImageData(dataSurface, map, aMimeType, aOutputOptions, aStream);
return EncodeImageData(dataSurface, aMimeType, aOutputOptions, aStream);
} }
NS_IMETHODIMP NS_IMETHODIMP
@ -492,16 +512,16 @@ imgTools::EncodeCroppedImage(imgIContainer* aContainer,
return NS_ERROR_FAILURE; return NS_ERROR_FAILURE;
} }
DataSourceSurface::MappedSurface map; DataSourceSurface::ScopedMap map(dataSurface, DataSourceSurface::READ_WRITE);
if (!dataSurface->Map(DataSourceSurface::MapType::WRITE, &map)) { if (!map.IsMapped()) {
return NS_ERROR_FAILURE; return NS_ERROR_FAILURE;
} }
RefPtr<DrawTarget> dt = RefPtr<DrawTarget> dt =
Factory::CreateDrawTargetForData(BackendType::CAIRO, Factory::CreateDrawTargetForData(BackendType::SKIA,
map.mData, map.GetData(),
dataSurface->GetSize(), dataSurface->GetSize(),
map.mStride, map.GetStride(),
SurfaceFormat::B8G8R8A8); SurfaceFormat::B8G8R8A8);
if (!dt) { if (!dt) {
gfxWarning() << gfxWarning() <<
@ -512,9 +532,7 @@ imgTools::EncodeCroppedImage(imgIContainer* aContainer,
IntRect(aOffsetX, aOffsetY, aWidth, aHeight), IntRect(aOffsetX, aOffsetY, aWidth, aHeight),
IntPoint(0, 0)); IntPoint(0, 0));
dataSurface->Unmap(); return EncodeImageData(dataSurface, map, aMimeType, aOutputOptions, aStream);
return EncodeImageData(dataSurface, aMimeType, aOutputOptions, aStream);
} }
NS_IMETHODIMP NS_IMETHODIMP

Просмотреть файл

@ -201,6 +201,22 @@ TEST_F(ImageSurfacePipeIntegration, SurfacePipe)
CheckSurfacePipeMethodResults(&pipe, decoder); CheckSurfacePipeMethodResults(&pipe, decoder);
} }
// Test that WritePixelBlocks() gets passed through to the underlying pipeline.
{
uint32_t count = 0;
WriteState result = pipe.WritePixelBlocks<uint32_t>([&](uint32_t* aBlockStart,
int32_t aLength) {
++count;
EXPECT_EQ(int32_t(100), aLength);
memcpy(aBlockStart, buffer, 100 * sizeof(uint32_t));
return MakeTuple(int32_t(100), Maybe<WriteState>());
});
EXPECT_EQ(WriteState::FINISHED, result);
EXPECT_EQ(100u, count);
CheckSurfacePipeMethodResults(&pipe, decoder);
}
// Test that WriteEmptyRow() gets passed through to the underlying pipeline. // Test that WriteEmptyRow() gets passed through to the underlying pipeline.
{ {
uint32_t count = 0; uint32_t count = 0;
@ -281,6 +297,22 @@ TEST_F(ImageSurfacePipeIntegration, PalettedSurfacePipe)
CheckPalettedSurfacePipeMethodResults(&pipe, decoder); CheckPalettedSurfacePipeMethodResults(&pipe, decoder);
} }
// Test that WritePixelBlocks() gets passed through to the underlying pipeline.
{
uint32_t count = 0;
WriteState result = pipe.WritePixelBlocks<uint8_t>([&](uint8_t* aBlockStart,
int32_t aLength) {
++count;
EXPECT_EQ(int32_t(100), aLength);
memcpy(aBlockStart, buffer, 100 * sizeof(uint8_t));
return MakeTuple(int32_t(100), Maybe<WriteState>());
});
EXPECT_EQ(WriteState::FINISHED, result);
EXPECT_EQ(100u, count);
CheckPalettedSurfacePipeMethodResults(&pipe, decoder);
}
// Test that WriteEmptyRow() gets passed through to the underlying pipeline. // Test that WriteEmptyRow() gets passed through to the underlying pipeline.
{ {
uint32_t count = 0; uint32_t count = 0;

Просмотреть файл

@ -602,6 +602,154 @@ TEST(ImageSurfaceSink, SurfaceSinkWriteUnsafeComputedRow)
}); });
} }
TEST(ImageSurfaceSink, SurfaceSinkWritePixelBlocks)
{
WithSurfaceSink<Orient::NORMAL>([](Decoder* aDecoder, SurfaceSink* aSink) {
// Create a green buffer the same size as one row of the surface (which is 100x100),
// containing 60 pixels of green in the middle and 20 transparent pixels on
// either side.
uint32_t buffer[100];
for (int i = 0; i < 100; ++i) {
buffer[i] = 20 <= i && i < 80 ? BGRAColor::Green().AsPixel()
: BGRAColor::Transparent().AsPixel();
}
uint32_t count = 0;
WriteState result = aSink->WritePixelBlocks<uint32_t>([&](uint32_t* aBlockStart,
int32_t aLength) {
++count;
EXPECT_EQ(int32_t(100), aLength);
memcpy(aBlockStart, buffer, 100 * sizeof(uint32_t));
return MakeTuple(int32_t(100), Maybe<WriteState>());
});
EXPECT_EQ(WriteState::FINISHED, result);
EXPECT_EQ(100u, count);
AssertCorrectPipelineFinalState(aSink,
IntRect(0, 0, 100, 100),
IntRect(0, 0, 100, 100));
// Check that the generated image is correct.
CheckGeneratedImage(aDecoder, IntRect(20, 0, 60, 100));
// Attempt to write more and make sure that nothing gets written.
count = 0;
result = aSink->WritePixelBlocks<uint32_t>([&](uint32_t* aBlockStart,
int32_t aLength) {
count++;
for (int32_t i = 0; i < aLength; ++i) {
aBlockStart[i] = BGRAColor::Red().AsPixel();
}
return MakeTuple(aLength, Maybe<WriteState>());
});
EXPECT_EQ(WriteState::FINISHED, result);
EXPECT_EQ(0u, count);
EXPECT_TRUE(aSink->IsSurfaceFinished());
// Check that the generated image is still correct.
CheckGeneratedImage(aDecoder, IntRect(20, 0, 60, 100));
});
}
TEST(ImageSurfaceSink, SurfaceSinkWritePixelBlocksPartialRow)
{
WithSurfaceSink<Orient::NORMAL>([](Decoder* aDecoder, SurfaceSink* aSink) {
// Create a green buffer the same size as one row of the surface (which is 100x100),
// containing 60 pixels of green in the middle and 20 transparent pixels on
// either side.
uint32_t buffer[100];
for (int i = 0; i < 100; ++i) {
buffer[i] = 20 <= i && i < 80 ? BGRAColor::Green().AsPixel()
: BGRAColor::Transparent().AsPixel();
}
// Write the first 99 rows of our 100x100 surface and verify that even
// though our lambda will yield pixels forever, only one row is written per
// call to WritePixelsToRow().
for (int row = 0; row < 99; ++row) {
for (int32_t written = 0; written < 100; ) {
WriteState result = aSink->WritePixelBlocks<uint32_t>([&](uint32_t* aBlockStart,
int32_t aLength) {
// When we write the final block of pixels, it will request we start
// another row. We should abort at that point.
if (aLength == int32_t(100) && written == int32_t(100)) {
return MakeTuple(int32_t(0), Some(WriteState::NEED_MORE_DATA));
}
// It should always request enough data to fill the row. So it should
// request 100, 75, 50, and finally 25 pixels.
EXPECT_EQ(int32_t(100) - written, aLength);
// Only write one quarter of the pixels for the row.
memcpy(aBlockStart, &buffer[written], 25 * sizeof(uint32_t));
written += 25;
// We've written the last pixels remaining for the row.
if (written == int32_t(100)) {
return MakeTuple(int32_t(25), Maybe<WriteState>());
}
// We've written another quarter of the row but not yet all of it.
return MakeTuple(int32_t(25), Some(WriteState::NEED_MORE_DATA));
});
EXPECT_EQ(WriteState::NEED_MORE_DATA, result);
}
EXPECT_FALSE(aSink->IsSurfaceFinished());
Maybe<SurfaceInvalidRect> invalidRect = aSink->TakeInvalidRect();
EXPECT_TRUE(invalidRect.isSome());
EXPECT_EQ(IntRect(0, row, 100, 1), invalidRect->mInputSpaceRect);
EXPECT_EQ(IntRect(0, row, 100, 1), invalidRect->mOutputSpaceRect);
CheckGeneratedImage(aDecoder, IntRect(20, 0, 60, row + 1));
}
// Write the final line, which should finish the surface.
uint32_t count = 0;
WriteState result = aSink->WritePixelBlocks<uint32_t>([&](uint32_t* aBlockStart,
int32_t aLength) {
++count;
EXPECT_EQ(int32_t(100), aLength);
memcpy(aBlockStart, buffer, 100 * sizeof(uint32_t));
return MakeTuple(int32_t(100), Maybe<WriteState>());
});
EXPECT_EQ(WriteState::FINISHED, result);
EXPECT_EQ(1u, count);
// Note that the final invalid rect we expect here is only the last row;
// that's because we called TakeInvalidRect() repeatedly in the loop above.
AssertCorrectPipelineFinalState(aSink,
IntRect(0, 99, 100, 1),
IntRect(0, 99, 100, 1));
// Check that the generated image is correct.
CheckGeneratedImage(aDecoder, IntRect(20, 0, 60, 100));
// Attempt to write more and make sure that nothing gets written.
count = 0;
result = aSink->WritePixelBlocks<uint32_t>([&](uint32_t* aBlockStart,
int32_t aLength) {
count++;
for (int32_t i = 0; i < aLength; ++i) {
aBlockStart[i] = BGRAColor::Red().AsPixel();
}
return MakeTuple(aLength, Maybe<WriteState>());
});
EXPECT_EQ(WriteState::FINISHED, result);
EXPECT_EQ(0u, count);
EXPECT_TRUE(aSink->IsSurfaceFinished());
// Check that the generated image is still correct.
CheckGeneratedImage(aDecoder, IntRect(20, 0, 60, 100));
});
}
TEST(ImageSurfaceSink, SurfaceSinkProgressivePasses) TEST(ImageSurfaceSink, SurfaceSinkProgressivePasses)
{ {
WithSurfaceSink<Orient::NORMAL>([](Decoder* aDecoder, SurfaceSink* aSink) { WithSurfaceSink<Orient::NORMAL>([](Decoder* aDecoder, SurfaceSink* aSink) {

Просмотреть файл

@ -150,7 +150,7 @@ class Builder {
// A rooted reference to our value. // A rooted reference to our value.
PersistentRooted<T> value; PersistentRooted<T> value;
BuiltThing(JSContext* cx, Builder& owner_, T value_ = GCPolicy<T>::initial()) BuiltThing(JSContext* cx, Builder& owner_, T value_ = SafelyInitialized<T>())
: owner(owner_), value(cx, value_) : owner(owner_), value(cx, value_)
{ {
owner.assertBuilt(value_); owner.assertBuilt(value_);

Просмотреть файл

@ -13,9 +13,6 @@
// //
// The GCPolicy provides at a minimum: // The GCPolicy provides at a minimum:
// //
// static T initial()
// - Construct and return an empty T.
//
// static void trace(JSTracer, T* tp, const char* name) // static void trace(JSTracer, T* tp, const char* name)
// - Trace the edge |*tp|, calling the edge |name|. Containers like // - Trace the edge |*tp|, calling the edge |name|. Containers like
// GCHashMap and GCHashSet use this method to trace their children. // GCHashMap and GCHashSet use this method to trace their children.
@ -72,10 +69,6 @@ namespace JS {
template <typename T> template <typename T>
struct StructGCPolicy struct StructGCPolicy
{ {
static T initial() {
return T();
}
static void trace(JSTracer* trc, T* tp, const char* name) { static void trace(JSTracer* trc, T* tp, const char* name) {
tp->trace(trc); tp->trace(trc);
} }
@ -102,7 +95,6 @@ template <typename T> struct GCPolicy : public StructGCPolicy<T> {};
// This policy ignores any GC interaction, e.g. for non-GC types. // This policy ignores any GC interaction, e.g. for non-GC types.
template <typename T> template <typename T>
struct IgnoreGCPolicy { struct IgnoreGCPolicy {
static T initial() { return T(); }
static void trace(JSTracer* trc, T* t, const char* name) {} static void trace(JSTracer* trc, T* t, const char* name) {}
static bool needsSweep(T* v) { return false; } static bool needsSweep(T* v) { return false; }
static bool isValid(const T& v) { return true; } static bool isValid(const T& v) { return true; }
@ -113,7 +105,6 @@ template <> struct GCPolicy<uint64_t> : public IgnoreGCPolicy<uint64_t> {};
template <typename T> template <typename T>
struct GCPointerPolicy struct GCPointerPolicy
{ {
static T initial() { return nullptr; }
static void trace(JSTracer* trc, T* vp, const char* name) { static void trace(JSTracer* trc, T* vp, const char* name) {
if (*vp) if (*vp)
js::UnsafeTraceManuallyBarrieredEdge(trc, vp, name); js::UnsafeTraceManuallyBarrieredEdge(trc, vp, name);
@ -140,7 +131,6 @@ template <> struct GCPolicy<JSString*> : public GCPointerPolicy<JSString*> {};
template <typename T> template <typename T>
struct NonGCPointerPolicy struct NonGCPointerPolicy
{ {
static T initial() { return nullptr; }
static void trace(JSTracer* trc, T* vp, const char* name) { static void trace(JSTracer* trc, T* vp, const char* name) {
if (*vp) if (*vp)
(*vp)->trace(trc); (*vp)->trace(trc);
@ -170,7 +160,6 @@ struct GCPolicy<JS::Heap<T>>
template <typename T, typename D> template <typename T, typename D>
struct GCPolicy<mozilla::UniquePtr<T, D>> struct GCPolicy<mozilla::UniquePtr<T, D>>
{ {
static mozilla::UniquePtr<T,D> initial() { return mozilla::UniquePtr<T,D>(); }
static void trace(JSTracer* trc, mozilla::UniquePtr<T,D>* tp, const char* name) { static void trace(JSTracer* trc, mozilla::UniquePtr<T,D>* tp, const char* name) {
if (tp->get()) if (tp->get())
GCPolicy<T>::trace(trc, tp->get(), name); GCPolicy<T>::trace(trc, tp->get(), name);
@ -192,7 +181,6 @@ struct GCPolicy<mozilla::UniquePtr<T, D>>
template <typename T> template <typename T>
struct GCPolicy<mozilla::Maybe<T>> struct GCPolicy<mozilla::Maybe<T>>
{ {
static mozilla::Maybe<T> initial() { return mozilla::Maybe<T>(); }
static void trace(JSTracer* trc, mozilla::Maybe<T>* tp, const char* name) { static void trace(JSTracer* trc, mozilla::Maybe<T>* tp, const char* name) {
if (tp->isSome()) if (tp->isSome())
GCPolicy<T>::trace(trc, tp->ptr(), name); GCPolicy<T>::trace(trc, tp->ptr(), name);

Просмотреть файл

@ -112,9 +112,6 @@ struct GCPolicy<mozilla::Variant<Ts...>>
{ {
using Impl = detail::GCVariantImplementation<Ts...>; using Impl = detail::GCVariantImplementation<Ts...>;
// Variants do not provide initial(). They do not have a default initial
// value and one must be provided.
static void trace(JSTracer* trc, mozilla::Variant<Ts...>* v, const char* name) { static void trace(JSTracer* trc, mozilla::Variant<Ts...>* v, const char* name) {
Impl::trace(trc, v, name); Impl::trace(trc, v, name);
} }

Просмотреть файл

@ -176,7 +176,6 @@ namespace JS {
template <> template <>
struct GCPolicy<jsid> struct GCPolicy<jsid>
{ {
static jsid initial() { return JSID_VOID; }
static void trace(JSTracer* trc, jsid* idp, const char* name) { static void trace(JSTracer* trc, jsid* idp, const char* name) {
js::UnsafeTraceManuallyBarrieredEdge(trc, idp, name); js::UnsafeTraceManuallyBarrieredEdge(trc, idp, name);
} }

Просмотреть файл

@ -200,6 +200,40 @@ template <typename T> class PersistentRooted;
JS_FRIEND_API(void) HeapObjectPostBarrier(JSObject** objp, JSObject* prev, JSObject* next); JS_FRIEND_API(void) HeapObjectPostBarrier(JSObject** objp, JSObject* prev, JSObject* next);
JS_FRIEND_API(void) HeapStringPostBarrier(JSString** objp, JSString* prev, JSString* next); JS_FRIEND_API(void) HeapStringPostBarrier(JSString** objp, JSString* prev, JSString* next);
/**
* Create a safely-initialized |T|, suitable for use as a default value in
* situations requiring a safe but arbitrary |T| value.
*/
template<typename T>
inline T
SafelyInitialized()
{
// This function wants to presume that |T()| -- which value-initializes a
// |T| per C++11 [expr.type.conv]p2 -- will produce a safely-initialized,
// safely-usable T that it can return.
#if defined(XP_WIN) || defined(XP_MACOSX) || (defined(XP_UNIX) && !defined(__clang__))
// That presumption holds for pointers, where value initialization produces
// a null pointer.
constexpr bool IsPointer = std::is_pointer<T>::value;
// For classes and unions we *assume* that if |T|'s default constructor is
// non-trivial it'll initialize correctly. (This is unideal, but C++
// doesn't offer a type trait indicating whether a class's constructor is
// user-defined, which better approximates our desired semantics.)
constexpr bool IsNonTriviallyDefaultConstructibleClassOrUnion =
(std::is_class<T>::value || std::is_union<T>::value) &&
!std::is_trivially_default_constructible<T>::value;
static_assert(IsPointer || IsNonTriviallyDefaultConstructibleClassOrUnion,
"T() must evaluate to a safely-initialized T");
#endif
return T();
}
#ifdef JS_DEBUG #ifdef JS_DEBUG
/** /**
* For generational GC, assert that an object is in the tenured generation as * For generational GC, assert that an object is in the tenured generation as
@ -247,7 +281,7 @@ class MOZ_NON_MEMMOVABLE Heap : public js::HeapBase<T, Heap<T>>
Heap() { Heap() {
static_assert(sizeof(T) == sizeof(Heap<T>), static_assert(sizeof(T) == sizeof(Heap<T>),
"Heap<T> must be binary compatible with T."); "Heap<T> must be binary compatible with T.");
init(GCPolicy<T>::initial()); init(SafelyInitialized<T>());
} }
explicit Heap(const T& p) { init(p); } explicit Heap(const T& p) { init(p); }
@ -260,7 +294,7 @@ class MOZ_NON_MEMMOVABLE Heap : public js::HeapBase<T, Heap<T>>
explicit Heap(const Heap<T>& p) { init(p.ptr); } explicit Heap(const Heap<T>& p) { init(p.ptr); }
~Heap() { ~Heap() {
post(ptr, GCPolicy<T>::initial()); post(ptr, SafelyInitialized<T>());
} }
DECLARE_POINTER_CONSTREF_OPS(T); DECLARE_POINTER_CONSTREF_OPS(T);
@ -291,7 +325,7 @@ class MOZ_NON_MEMMOVABLE Heap : public js::HeapBase<T, Heap<T>>
private: private:
void init(const T& newPtr) { void init(const T& newPtr) {
ptr = newPtr; ptr = newPtr;
post(GCPolicy<T>::initial(), ptr); post(SafelyInitialized<T>(), ptr);
} }
void set(const T& newPtr) { void set(const T& newPtr) {
@ -950,7 +984,7 @@ class MOZ_RAII Rooted : public js::RootedBase<T, Rooted<T>>
template <typename RootingContext> template <typename RootingContext>
explicit Rooted(const RootingContext& cx) explicit Rooted(const RootingContext& cx)
: ptr(GCPolicy<T>::initial()) : ptr(SafelyInitialized<T>())
{ {
registerWithRootLists(rootLists(cx)); registerWithRootLists(rootLists(cx));
} }
@ -1219,16 +1253,16 @@ class PersistentRooted : public js::RootedBase<T, PersistentRooted<T>>,
public: public:
using ElementType = T; using ElementType = T;
PersistentRooted() : ptr(GCPolicy<T>::initial()) {} PersistentRooted() : ptr(SafelyInitialized<T>()) {}
explicit PersistentRooted(RootingContext* cx) explicit PersistentRooted(RootingContext* cx)
: ptr(GCPolicy<T>::initial()) : ptr(SafelyInitialized<T>())
{ {
registerWithRootLists(cx); registerWithRootLists(cx);
} }
explicit PersistentRooted(JSContext* cx) explicit PersistentRooted(JSContext* cx)
: ptr(GCPolicy<T>::initial()) : ptr(SafelyInitialized<T>())
{ {
registerWithRootLists(RootingContext::get(cx)); registerWithRootLists(RootingContext::get(cx));
} }
@ -1248,7 +1282,7 @@ class PersistentRooted : public js::RootedBase<T, PersistentRooted<T>>,
} }
explicit PersistentRooted(JSRuntime* rt) explicit PersistentRooted(JSRuntime* rt)
: ptr(GCPolicy<T>::initial()) : ptr(SafelyInitialized<T>())
{ {
registerWithRootLists(rt); registerWithRootLists(rt);
} }
@ -1280,7 +1314,7 @@ class PersistentRooted : public js::RootedBase<T, PersistentRooted<T>>,
} }
void init(JSContext* cx) { void init(JSContext* cx) {
init(cx, GCPolicy<T>::initial()); init(cx, SafelyInitialized<T>());
} }
template <typename U> template <typename U>
@ -1291,7 +1325,7 @@ class PersistentRooted : public js::RootedBase<T, PersistentRooted<T>>,
void reset() { void reset() {
if (initialized()) { if (initialized()) {
set(GCPolicy<T>::initial()); set(SafelyInitialized<T>());
ListBase::remove(); ListBase::remove();
} }
} }

Просмотреть файл

@ -1244,7 +1244,6 @@ JS_PUBLIC_API(void) HeapValuePostBarrier(Value* valuep, const Value& prev, const
template <> template <>
struct GCPolicy<JS::Value> struct GCPolicy<JS::Value>
{ {
static Value initial() { return UndefinedValue(); }
static void trace(JSTracer* trc, Value* v, const char* name) { static void trace(JSTracer* trc, Value* v, const char* name) {
js::UnsafeTraceManuallyBarrieredEdge(trc, v, name); js::UnsafeTraceManuallyBarrieredEdge(trc, v, name);
} }

Просмотреть файл

@ -3702,7 +3702,8 @@ CreateArrayPrototype(JSContext* cx, JSProtoKey key)
* arrays in JSON and script literals and allows setDenseArrayElement to * arrays in JSON and script literals and allows setDenseArrayElement to
* be used without updating the indexed type set for such default arrays. * be used without updating the indexed type set for such default arrays.
*/ */
if (!JSObject::setNewGroupUnknown(cx, &ArrayObject::class_, arrayProto)) ObjectGroupRealm& realm = ObjectGroupRealm::getForNewObject(cx);
if (!JSObject::setNewGroupUnknown(cx, realm, &ArrayObject::class_, arrayProto))
return nullptr; return nullptr;
return arrayProto; return arrayProto;

Просмотреть файл

@ -376,7 +376,7 @@ MapIteratorObject::createResultPair(JSContext* cx)
return nullptr; return nullptr;
Rooted<TaggedProto> proto(cx, resultPairObj->taggedProto()); Rooted<TaggedProto> proto(cx, resultPairObj->taggedProto());
ObjectGroup* group = ObjectGroupCompartment::makeGroup(cx, resultPairObj->getClass(), proto); ObjectGroup* group = ObjectGroupRealm::makeGroup(cx, resultPairObj->getClass(), proto);
if (!group) if (!group)
return nullptr; return nullptr;
resultPairObj->setGroup(group); resultPairObj->setGroup(group);
@ -1204,7 +1204,7 @@ SetIteratorObject::createResult(JSContext* cx)
return nullptr; return nullptr;
Rooted<TaggedProto> proto(cx, resultObj->taggedProto()); Rooted<TaggedProto> proto(cx, resultObj->taggedProto());
ObjectGroup* group = ObjectGroupCompartment::makeGroup(cx, resultObj->getClass(), proto); ObjectGroup* group = ObjectGroupRealm::makeGroup(cx, resultObj->getClass(), proto);
if (!group) if (!group)
return nullptr; return nullptr;
resultObj->setGroup(group); resultObj->setGroup(group);

Просмотреть файл

@ -350,8 +350,8 @@ function InnerModuleInstantiation(module, stack, index)
} }
// Step 3 // Step 3
assert(module.status === MODULE_STATUS_UNINSTANTIATED, if (module.status !== MODULE_STATUS_UNINSTANTIATED)
"Bad module status in ModuleDeclarationInstantiation"); ThrowInternalError(JSMSG_BAD_MODULE_STATUS);
// Steps 4 // Steps 4
ModuleSetStatus(module, MODULE_STATUS_INSTANTIATING); ModuleSetStatus(module, MODULE_STATUS_INSTANTIATING);

Просмотреть файл

@ -2023,7 +2023,8 @@ CreateObjectPrototype(JSContext* cx, JSProtoKey key)
* to have unknown properties, to simplify handling of e.g. heterogenous * to have unknown properties, to simplify handling of e.g. heterogenous
* objects in JSON and script literals. * objects in JSON and script literals.
*/ */
if (!JSObject::setNewGroupUnknown(cx, &PlainObject::class_, objectProto)) ObjectGroupRealm& realm = ObjectGroupRealm::getForNewObject(cx);
if (!JSObject::setNewGroupUnknown(cx, realm, &PlainObject::class_, objectProto))
return nullptr; return nullptr;
return objectProto; return objectProto;

Просмотреть файл

@ -48,7 +48,7 @@ js::CreateRegExpMatchResult(JSContext* cx, HandleString input, const MatchPairs&
*/ */
/* Get the templateObject that defines the shape and type of the output object */ /* Get the templateObject that defines the shape and type of the output object */
JSObject* templateObject = cx->compartment()->regExps.getOrCreateMatchResultTemplateObject(cx); JSObject* templateObject = cx->realm()->regExps.getOrCreateMatchResultTemplateObject(cx);
if (!templateObject) if (!templateObject)
return false; return false;
@ -1568,7 +1568,7 @@ js::RegExpPrototypeOptimizableRaw(JSContext* cx, JSObject* proto)
NativeObject* nproto = static_cast<NativeObject*>(proto); NativeObject* nproto = static_cast<NativeObject*>(proto);
Shape* shape = cx->compartment()->regExps.getOptimizableRegExpPrototypeShape(); Shape* shape = cx->realm()->regExps.getOptimizableRegExpPrototypeShape();
if (shape == nproto->lastProperty()) if (shape == nproto->lastProperty())
return true; return true;
@ -1635,7 +1635,7 @@ js::RegExpPrototypeOptimizableRaw(JSContext* cx, JSObject* proto)
if (!has) if (!has)
return false; return false;
cx->compartment()->regExps.setOptimizableRegExpPrototypeShape(nproto->lastProperty()); cx->realm()->regExps.setOptimizableRegExpPrototypeShape(nproto->lastProperty());
return true; return true;
} }
@ -1659,7 +1659,7 @@ js::RegExpInstanceOptimizableRaw(JSContext* cx, JSObject* obj, JSObject* proto)
RegExpObject* rx = &obj->as<RegExpObject>(); RegExpObject* rx = &obj->as<RegExpObject>();
Shape* shape = cx->compartment()->regExps.getOptimizableRegExpInstanceShape(); Shape* shape = cx->realm()->regExps.getOptimizableRegExpInstanceShape();
if (shape == rx->lastProperty()) if (shape == rx->lastProperty())
return true; return true;
@ -1672,7 +1672,7 @@ js::RegExpInstanceOptimizableRaw(JSContext* cx, JSObject* obj, JSObject* proto)
if (!RegExpObject::isInitialShape(rx)) if (!RegExpObject::isInitialShape(rx))
return false; return false;
cx->compartment()->regExps.setOptimizableRegExpInstanceShape(rx->lastProperty()); cx->realm()->regExps.setOptimizableRegExpInstanceShape(rx->lastProperty());
return true; return true;
} }

Просмотреть файл

@ -4081,7 +4081,7 @@ BuildFlatMatchArray(JSContext* cx, HandleString str, HandleString pattern, int32
} }
/* Get the templateObject that defines the shape and type of the output object */ /* Get the templateObject that defines the shape and type of the output object */
JSObject* templateObject = cx->compartment()->regExps.getOrCreateMatchResultTemplateObject(cx); JSObject* templateObject = cx->realm()->regExps.getOrCreateMatchResultTemplateObject(cx);
if (!templateObject) if (!templateObject)
return false; return false;

Просмотреть файл

@ -1271,7 +1271,7 @@ SetSavedStacksRNGState(JSContext* cx, unsigned argc, Value* vp)
// Either one or the other of the seed arguments must be non-zero; // Either one or the other of the seed arguments must be non-zero;
// make this true no matter what value 'seed' has. // make this true no matter what value 'seed' has.
cx->compartment()->savedStacks().setRNGState(seed, (seed + 1) * 33); cx->realm()->savedStacks().setRNGState(seed, (seed + 1) * 33);
return true; return true;
} }
@ -1279,7 +1279,7 @@ static bool
GetSavedFrameCount(JSContext* cx, unsigned argc, Value* vp) GetSavedFrameCount(JSContext* cx, unsigned argc, Value* vp)
{ {
CallArgs args = CallArgsFromVp(argc, vp); CallArgs args = CallArgsFromVp(argc, vp);
args.rval().setNumber(cx->compartment()->savedStacks().count()); args.rval().setNumber(cx->realm()->savedStacks().count());
return true; return true;
} }
@ -1288,13 +1288,12 @@ ClearSavedFrames(JSContext* cx, unsigned argc, Value* vp)
{ {
CallArgs args = CallArgsFromVp(argc, vp); CallArgs args = CallArgsFromVp(argc, vp);
js::SavedStacks& savedStacks = cx->compartment()->savedStacks(); js::SavedStacks& savedStacks = cx->realm()->savedStacks();
if (savedStacks.initialized()) if (savedStacks.initialized())
savedStacks.clear(); savedStacks.clear();
for (ActivationIterator iter(cx); !iter.done(); ++iter) { for (ActivationIterator iter(cx); !iter.done(); ++iter)
iter->clearLiveSavedFrameCache(); iter->clearLiveSavedFrameCache();
}
args.rval().setUndefined(); args.rval().setUndefined();
return true; return true;

Просмотреть файл

@ -409,7 +409,7 @@ template <class T>
class PreBarriered : public WriteBarrieredBase<T> class PreBarriered : public WriteBarrieredBase<T>
{ {
public: public:
PreBarriered() : WriteBarrieredBase<T>(JS::GCPolicy<T>::initial()) {} PreBarriered() : WriteBarrieredBase<T>(JS::SafelyInitialized<T>()) {}
/* /*
* Allow implicit construction for use in generic contexts, such as * Allow implicit construction for use in generic contexts, such as
* DebuggerWeakMap::markKeys. * DebuggerWeakMap::markKeys.
@ -453,12 +453,12 @@ template <class T>
class GCPtr : public WriteBarrieredBase<T> class GCPtr : public WriteBarrieredBase<T>
{ {
public: public:
GCPtr() : WriteBarrieredBase<T>(JS::GCPolicy<T>::initial()) {} GCPtr() : WriteBarrieredBase<T>(JS::SafelyInitialized<T>()) {}
explicit GCPtr(const T& v) : WriteBarrieredBase<T>(v) { explicit GCPtr(const T& v) : WriteBarrieredBase<T>(v) {
this->post(JS::GCPolicy<T>::initial(), v); this->post(JS::SafelyInitialized<T>(), v);
} }
explicit GCPtr(const GCPtr<T>& v) : WriteBarrieredBase<T>(v) { explicit GCPtr(const GCPtr<T>& v) : WriteBarrieredBase<T>(v) {
this->post(JS::GCPolicy<T>::initial(), v); this->post(JS::SafelyInitialized<T>(), v);
} }
#ifdef DEBUG #ifdef DEBUG
~GCPtr() { ~GCPtr() {
@ -471,7 +471,7 @@ class GCPtr : public WriteBarrieredBase<T>
// //
// Note that when sweeping the wrapped pointer may already have been // Note that when sweeping the wrapped pointer may already have been
// freed by this point. // freed by this point.
MOZ_ASSERT(CurrentThreadIsGCSweeping() || this->value == JS::GCPolicy<T>::initial()); MOZ_ASSERT(CurrentThreadIsGCSweeping() || this->value == JS::SafelyInitialized<T>());
Poison(this, JS_FREED_HEAP_PTR_PATTERN, sizeof(*this), MemCheckKind::MakeNoAccess); Poison(this, JS_FREED_HEAP_PTR_PATTERN, sizeof(*this), MemCheckKind::MakeNoAccess);
} }
#endif #endif
@ -479,7 +479,7 @@ class GCPtr : public WriteBarrieredBase<T>
void init(const T& v) { void init(const T& v) {
CheckTargetIsNotGray(v); CheckTargetIsNotGray(v);
this->value = v; this->value = v;
this->post(JS::GCPolicy<T>::initial(), v); this->post(JS::SafelyInitialized<T>(), v);
} }
DECLARE_POINTER_ASSIGN_OPS(GCPtr, T); DECLARE_POINTER_ASSIGN_OPS(GCPtr, T);
@ -529,11 +529,11 @@ template <class T>
class HeapPtr : public WriteBarrieredBase<T> class HeapPtr : public WriteBarrieredBase<T>
{ {
public: public:
HeapPtr() : WriteBarrieredBase<T>(JS::GCPolicy<T>::initial()) {} HeapPtr() : WriteBarrieredBase<T>(JS::SafelyInitialized<T>()) {}
// Implicitly adding barriers is a reasonable default. // Implicitly adding barriers is a reasonable default.
MOZ_IMPLICIT HeapPtr(const T& v) : WriteBarrieredBase<T>(v) { MOZ_IMPLICIT HeapPtr(const T& v) : WriteBarrieredBase<T>(v) {
this->post(JS::GCPolicy<T>::initial(), this->value); this->post(JS::SafelyInitialized<T>(), this->value);
} }
/* /*
@ -543,18 +543,18 @@ class HeapPtr : public WriteBarrieredBase<T>
* simply omit the rvalue variant. * simply omit the rvalue variant.
*/ */
MOZ_IMPLICIT HeapPtr(const HeapPtr<T>& v) : WriteBarrieredBase<T>(v) { MOZ_IMPLICIT HeapPtr(const HeapPtr<T>& v) : WriteBarrieredBase<T>(v) {
this->post(JS::GCPolicy<T>::initial(), this->value); this->post(JS::SafelyInitialized<T>(), this->value);
} }
~HeapPtr() { ~HeapPtr() {
this->pre(); this->pre();
this->post(this->value, JS::GCPolicy<T>::initial()); this->post(this->value, JS::SafelyInitialized<T>());
} }
void init(const T& v) { void init(const T& v) {
CheckTargetIsNotGray(v); CheckTargetIsNotGray(v);
this->value = v; this->value = v;
this->post(JS::GCPolicy<T>::initial(), this->value); this->post(JS::SafelyInitialized<T>(), this->value);
} }
DECLARE_POINTER_ASSIGN_OPS(HeapPtr, T); DECLARE_POINTER_ASSIGN_OPS(HeapPtr, T);
@ -611,17 +611,17 @@ class ReadBarriered : public ReadBarrieredBase<T>,
using ReadBarrieredBase<T>::value; using ReadBarrieredBase<T>::value;
public: public:
ReadBarriered() : ReadBarrieredBase<T>(JS::GCPolicy<T>::initial()) {} ReadBarriered() : ReadBarrieredBase<T>(JS::SafelyInitialized<T>()) {}
// It is okay to add barriers implicitly. // It is okay to add barriers implicitly.
MOZ_IMPLICIT ReadBarriered(const T& v) : ReadBarrieredBase<T>(v) { MOZ_IMPLICIT ReadBarriered(const T& v) : ReadBarrieredBase<T>(v) {
this->post(JS::GCPolicy<T>::initial(), v); this->post(JS::SafelyInitialized<T>(), v);
} }
// The copy constructor creates a new weak edge but the wrapped pointer does // The copy constructor creates a new weak edge but the wrapped pointer does
// not escape, so no read barrier is necessary. // not escape, so no read barrier is necessary.
explicit ReadBarriered(const ReadBarriered& v) : ReadBarrieredBase<T>(v) { explicit ReadBarriered(const ReadBarriered& v) : ReadBarrieredBase<T>(v) {
this->post(JS::GCPolicy<T>::initial(), v.unbarrieredGet()); this->post(JS::SafelyInitialized<T>(), v.unbarrieredGet());
} }
// Move retains the lifetime status of the source edge, so does not fire // Move retains the lifetime status of the source edge, so does not fire
@ -629,11 +629,11 @@ class ReadBarriered : public ReadBarrieredBase<T>,
ReadBarriered(ReadBarriered&& v) ReadBarriered(ReadBarriered&& v)
: ReadBarrieredBase<T>(mozilla::Move(v)) : ReadBarrieredBase<T>(mozilla::Move(v))
{ {
this->post(JS::GCPolicy<T>::initial(), v.value); this->post(JS::SafelyInitialized<T>(), v.value);
} }
~ReadBarriered() { ~ReadBarriered() {
this->post(this->value, JS::GCPolicy<T>::initial()); this->post(this->value, JS::SafelyInitialized<T>());
} }
ReadBarriered& operator=(const ReadBarriered& v) { ReadBarriered& operator=(const ReadBarriered& v) {

Просмотреть файл

@ -2577,7 +2577,7 @@ GCRuntime::sweepZoneAfterCompacting(Zone* zone)
jitZone->sweep(); jitZone->sweep();
for (RealmsInZoneIter r(zone); !r.done(); r.next()) { for (RealmsInZoneIter r(zone); !r.done(); r.next()) {
r->objectGroups.sweep(); r->sweepObjectGroups();
r->sweepRegExps(); r->sweepRegExps();
r->sweepSavedStacks(); r->sweepSavedStacks();
r->sweepVarNames(); r->sweepVarNames();
@ -4253,8 +4253,9 @@ GCRuntime::prepareZonesForCollection(JS::gcreason::Reason reason, bool* isFullOu
for (RealmsIter r(rt, WithAtoms); !r.done(); r.next()) { for (RealmsIter r(rt, WithAtoms); !r.done(); r.next()) {
r->unmark(); r->unmark();
r->scheduledForDestruction = false; JSCompartment* comp = JS::GetCompartmentForRealm(r);
r->maybeAlive = r->shouldTraceGlobal() || !r->zone()->isGCScheduled(); comp->scheduledForDestruction = false;
comp->maybeAlive = r->shouldTraceGlobal() || !r->zone()->isGCScheduled();
if (shouldPreserveJITCode(r, currentTime, reason, canAllocateMoreCode)) if (shouldPreserveJITCode(r, currentTime, reason, canAllocateMoreCode))
r->zone()->setPreservingCode(true); r->zone()->setPreservingCode(true);
} }
@ -5424,8 +5425,8 @@ static void
SweepObjectGroups(GCParallelTask* task) SweepObjectGroups(GCParallelTask* task)
{ {
JSRuntime* runtime = task->runtime(); JSRuntime* runtime = task->runtime();
for (SweepGroupCompartmentsIter c(runtime); !c.done(); c.next()) for (SweepGroupRealmsIter r(runtime); !r.done(); r.next())
c->objectGroups.sweep(); r->sweepObjectGroups();
} }
static void static void
@ -5532,8 +5533,8 @@ GCRuntime::sweepDebuggerOnMainThread(FreeOp* fop)
// table. // table.
{ {
gcstats::AutoPhase ap2(stats(), gcstats::PhaseKind::SWEEP_MISC); gcstats::AutoPhase ap2(stats(), gcstats::PhaseKind::SWEEP_MISC);
for (SweepGroupCompartmentsIter c(rt); !c.done(); c.next()) for (SweepGroupRealmsIter r(rt); !r.done(); r.next())
c->sweepDebugEnvironments(); r->sweepDebugEnvironments();
} }
// Sweep breakpoints. This is done here to be with the other debug sweeping, // Sweep breakpoints. This is done here to be with the other debug sweeping,
@ -7953,16 +7954,16 @@ js::NewCompartment(JSContext* cx, JSPrincipals* principals,
} }
} }
ScopedJSDeletePtr<Realm> compartment(cx->new_<Realm>(zone, options)); ScopedJSDeletePtr<Realm> realm(cx->new_<Realm>(zone, options));
if (!compartment || !compartment->init(cx)) if (!realm || !realm->init(cx))
return nullptr; return nullptr;
// Set up the principals. // Set up the principals.
JS_SetCompartmentPrincipals(compartment, principals); JS_SetCompartmentPrincipals(JS::GetCompartmentForRealm(realm), principals);
AutoLockGC lock(rt); AutoLockGC lock(rt);
if (!zone->compartments().append(compartment.get())) { if (!zone->compartments().append(JS::GetCompartmentForRealm(realm.get()))) {
ReportOutOfMemory(cx); ReportOutOfMemory(cx);
return nullptr; return nullptr;
} }
@ -7982,7 +7983,7 @@ js::NewCompartment(JSContext* cx, JSPrincipals* principals,
} }
zoneHolder.forget(); zoneHolder.forget();
return compartment.forget(); return JS::GetCompartmentForRealm(realm.forget());
} }
void void
@ -8482,12 +8483,12 @@ js::gc::CheckHashTablesAfterMovingGC(JSRuntime* rt)
} }
for (RealmsIter r(rt, SkipAtoms); !r.done(); r.next()) { for (RealmsIter r(rt, SkipAtoms); !r.done(); r.next()) {
r->objectGroups.checkTablesAfterMovingGC(); r->checkObjectGroupTablesAfterMovingGC();
r->dtoaCache.checkCacheAfterMovingGC(); r->dtoaCache.checkCacheAfterMovingGC();
JS::GetCompartmentForRealm(r)->checkWrapperMapAfterMovingGC(); JS::GetCompartmentForRealm(r)->checkWrapperMapAfterMovingGC();
r->checkScriptMapsAfterMovingGC(); r->checkScriptMapsAfterMovingGC();
if (r->debugEnvs) if (r->debugEnvs())
r->debugEnvs->checkHashTablesAfterMovingGC(); r->debugEnvs()->checkHashTablesAfterMovingGC();
} }
} }
#endif #endif

Просмотреть файл

@ -23,7 +23,7 @@ template <typename T>
class UnsafeBareReadBarriered : public ReadBarrieredBase<T> class UnsafeBareReadBarriered : public ReadBarrieredBase<T>
{ {
public: public:
UnsafeBareReadBarriered() : ReadBarrieredBase<T>(JS::GCPolicy<T>::initial()) {} UnsafeBareReadBarriered() : ReadBarrieredBase<T>(JS::SafelyInitialized<T>()) {}
MOZ_IMPLICIT UnsafeBareReadBarriered(const T& v) : ReadBarrieredBase<T>(v) {} MOZ_IMPLICIT UnsafeBareReadBarriered(const T& v) : ReadBarrieredBase<T>(v) {}
explicit UnsafeBareReadBarriered(const UnsafeBareReadBarriered& v) : ReadBarrieredBase<T>(v) {} explicit UnsafeBareReadBarriered(const UnsafeBareReadBarriered& v) : ReadBarrieredBase<T>(v) {}
UnsafeBareReadBarriered(UnsafeBareReadBarriered&& v) UnsafeBareReadBarriered(UnsafeBareReadBarriered&& v)
@ -42,7 +42,7 @@ class UnsafeBareReadBarriered : public ReadBarrieredBase<T>
const T get() const { const T get() const {
if (!InternalBarrierMethods<T>::isMarkable(this->value)) if (!InternalBarrierMethods<T>::isMarkable(this->value))
return JS::GCPolicy<T>::initial(); return JS::SafelyInitialized<T>();
this->read(); this->read();
return this->value; return this->value;
} }

Просмотреть файл

@ -121,7 +121,6 @@ namespace js {
template <typename T> template <typename T>
struct InternalGCPointerPolicy { struct InternalGCPointerPolicy {
using Type = typename mozilla::RemovePointer<T>::Type; using Type = typename mozilla::RemovePointer<T>::Type;
static T initial() { return nullptr; }
static void preBarrier(T v) { static void preBarrier(T v) {
if (v) if (v)
Type::writeBarrierPre(v); Type::writeBarrierPre(v);

Просмотреть файл

@ -89,7 +89,7 @@ class MOZ_RAII FakeRooted : public RootedBase<T, FakeRooted<T>>
using ElementType = T; using ElementType = T;
template <typename CX> template <typename CX>
explicit FakeRooted(CX* cx) : ptr(JS::GCPolicy<T>::initial()) {} explicit FakeRooted(CX* cx) : ptr(JS::SafelyInitialized<T>()) {}
template <typename CX> template <typename CX>
FakeRooted(CX* cx, T initial) : ptr(initial) {} FakeRooted(CX* cx, T initial) : ptr(initial) {}

Просмотреть файл

@ -2,7 +2,7 @@ if (!('oomTest' in this))
quit(); quit();
oomTest(() => { oomTest(() => {
var g = newGlobal(); var g = newGlobal({sameZoneAs: this});
g.eval("\ g.eval("\
function f(){}; \ function f(){}; \
getLcovInfo(); \ getLcovInfo(); \

Просмотреть файл

@ -10,5 +10,5 @@ for (var i = 0; i < 9; ++i) {
} }
// jsfunfuzz-generated // jsfunfuzz-generated
oomTest(function() { oomTest(function() {
newGlobal(); newGlobal({sameZoneAs: this});
}) })

Просмотреть файл

@ -8,5 +8,5 @@ dbg.onNewGlobalObject = function(global) {
dbg.memory.takeCensus({}); dbg.memory.takeCensus({});
}; };
oomTest(function() { oomTest(function() {
newGlobal({}) newGlobal({sameZoneAs: this})
}); });

Просмотреть файл

@ -9,5 +9,5 @@ fullcompartmentchecks(true);
var dbg = new Debugger; var dbg = new Debugger;
dbg.onNewGlobalObject = function() {}; dbg.onNewGlobalObject = function() {};
oomTest(function() { oomTest(function() {
newGlobal(); newGlobal({sameZoneAs: this});
}) })

Просмотреть файл

@ -12,6 +12,6 @@ for (var i = 0; i < 9; ++ i) {
dbg.onNewGlobalObject = ERROR; dbg.onNewGlobalObject = ERROR;
} }
oomTest(function() { oomTest(function() {
newGlobal(); newGlobal({sameZoneAs: this});
}) })
`); `);

Просмотреть файл

@ -10,6 +10,6 @@ dbg.onNewScript = function (s) {
} }
log = ""; log = "";
oomTest(() => { oomTest(() => {
var static = newGlobal(); var static = newGlobal({sameZoneAs: this});
g.eval("(function() {})()"); g.eval("(function() {})()");
}); });

Просмотреть файл

@ -18,6 +18,5 @@ dbg.onNewGlobalObject = function(global) {
get.seen = true; get.seen = true;
}; };
oomTest(function() { oomTest(function() {
newGlobal({ newGlobal({sameZoneAs: this})
})
}); });

Просмотреть файл

@ -8,7 +8,7 @@ loadFile(`
var global = this; var global = this;
var p = new Proxy(o, { var p = new Proxy(o, {
"deleteProperty": function (await , key) { "deleteProperty": function (await , key) {
var g = newGlobal(); var g = newGlobal({sameZoneAs: this});
g.parent = global; g.parent = global;
g.eval("var dbg = new Debugger(parent); dbg.onEnterFrame = function(frame) {};"); g.eval("var dbg = new Debugger(parent); dbg.onEnterFrame = function(frame) {};");
} }

Просмотреть файл

@ -14,6 +14,6 @@ function ERROR(msg) {
var dbg = new Debugger; var dbg = new Debugger;
dbg.onNewGlobalObject = ERROR; dbg.onNewGlobalObject = ERROR;
oomTest(function() { oomTest(function() {
newGlobal(); newGlobal({sameZoneAs: this});
}) })

Просмотреть файл

@ -3,8 +3,8 @@
if (!('oomTest' in this)) if (!('oomTest' in this))
quit(); quit();
var source = ` function x() {
var global = newGlobal(); var global = newGlobal({sameZoneAs: this});
global.eval('function f() { debugger; }'); global.eval('function f() { debugger; }');
var debug = new Debugger(global); var debug = new Debugger(global);
var foo; var foo;
@ -13,8 +13,6 @@ var source = `
return null; return null;
}; };
global.eval('f(0)'); global.eval('f(0)');
`;
function test() {
oomTest(new Function(source), false);
} }
test();
oomTest(x, false);

Просмотреть файл

@ -4,6 +4,6 @@ if (!('oomTest' in this))
quit(); quit();
oomTest(() => { oomTest(() => {
var g = newGlobal(); var g = newGlobal({sameZoneAs: this});
g.eval("(function() {})()"); g.eval("(function() {})()");
}); });

Просмотреть файл

@ -4,7 +4,7 @@ if (!('oomTest' in this))
quit(); quit();
oomTest(() => { oomTest(() => {
let global = newGlobal(); let global = newGlobal({sameZoneAs: this});
Debugger(global).onDebuggerStatement = function (frame) { Debugger(global).onDebuggerStatement = function (frame) {
frame.eval("f") frame.eval("f")
} }

Просмотреть файл

@ -3,7 +3,7 @@ if (!('oomTest' in this))
var x = ``.split(); var x = ``.split();
oomTest(function() { oomTest(function() {
var lfGlobal = newGlobal(); var lfGlobal = newGlobal({sameZoneAs: this});
for (lfLocal in this) { for (lfLocal in this) {
if (!(lfLocal in lfGlobal)) { if (!(lfLocal in lfGlobal)) {
lfGlobal[lfLocal] = this[lfLocal]; lfGlobal[lfLocal] = this[lfLocal];

Просмотреть файл

@ -0,0 +1,10 @@
// |jit-test| error: Error
var g = newGlobal();
g.eval(`
setModuleResolveHook(function(module, specifier) { return module; });
`);
let m = parseModule(`
import {} from './foo.js';
`);
m.declarationInstantiation();

Просмотреть файл

@ -0,0 +1,11 @@
// |jit-test| error: InternalError
let m = parseModule(`
let c = parseModule(\`
import "a";
\`);
c.declarationInstantiation();
`);
setModuleResolveHook(function(module, specifier) { return m; });
m.declarationInstantiation();
m.evaluation();

Просмотреть файл

@ -350,32 +350,32 @@ if (typeof WebAssembly.Global === "function") {
const Global = WebAssembly.Global; const Global = WebAssembly.Global;
// These types should work: // These types should work:
assertEq(new Global({type: "i32"}) instanceof Global, true); assertEq(new Global({value: "i32"}) instanceof Global, true);
assertEq(new Global({type: "f32"}) instanceof Global, true); assertEq(new Global({value: "f32"}) instanceof Global, true);
assertEq(new Global({type: "f64"}) instanceof Global, true); assertEq(new Global({value: "f64"}) instanceof Global, true);
// These types should not work: // These types should not work:
assertErrorMessage(() => new Global({type: "i64"}), TypeError, /bad type for a WebAssembly.Global/); assertErrorMessage(() => new Global({value: "i64"}), TypeError, /bad type for a WebAssembly.Global/);
assertErrorMessage(() => new Global({}), TypeError, /bad type for a WebAssembly.Global/); assertErrorMessage(() => new Global({}), TypeError, /bad type for a WebAssembly.Global/);
assertErrorMessage(() => new Global({type: "fnord"}), TypeError, /bad type for a WebAssembly.Global/); assertErrorMessage(() => new Global({value: "fnord"}), TypeError, /bad type for a WebAssembly.Global/);
assertErrorMessage(() => new Global(), TypeError, /Global requires more than 0 arguments/); assertErrorMessage(() => new Global(), TypeError, /Global requires more than 0 arguments/);
// Coercion of init value; ".value" accessor // Coercion of init value; ".value" accessor
assertEq((new Global({type: "i32"}, 3.14)).value, 3); assertEq((new Global({value: "i32"}, 3.14)).value, 3);
assertEq((new Global({type: "f32"}, { valueOf: () => 33.5 })).value, 33.5); assertEq((new Global({value: "f32"}, { valueOf: () => 33.5 })).value, 33.5);
assertEq((new Global({type: "f64"}, "3.25")).value, 3.25); assertEq((new Global({value: "f64"}, "3.25")).value, 3.25);
// Nothing special about NaN, it coerces just fine // Nothing special about NaN, it coerces just fine
assertEq((new Global({type: "i32"}, NaN)).value, 0); assertEq((new Global({value: "i32"}, NaN)).value, 0);
// The default init value is zero. // The default init value is zero.
assertEq((new Global({type: "i32"})).value, 0); assertEq((new Global({value: "i32"})).value, 0);
assertEq((new Global({type: "f32"})).value, 0); assertEq((new Global({value: "f32"})).value, 0);
assertEq((new Global({type: "f64"})).value, 0); assertEq((new Global({value: "f64"})).value, 0);
{ {
// "value" is enumerable // "value" is enumerable
let x = new Global({type: "i32"}); let x = new Global({value: "i32"});
let s = ""; let s = "";
for ( let i in x ) for ( let i in x )
s = s + i + ","; s = s + i + ",";
@ -386,20 +386,20 @@ if (typeof WebAssembly.Global === "function") {
assertEq("value" in Global.prototype, true); assertEq("value" in Global.prototype, true);
// Can't set the value of an immutable global // Can't set the value of an immutable global
assertErrorMessage(() => (new Global({type: "i32"})).value = 10, assertErrorMessage(() => (new Global({value: "i32"})).value = 10,
TypeError, TypeError,
/can't set value of immutable global/); /can't set value of immutable global/);
{ {
// Can set the value of a mutable global // Can set the value of a mutable global
let g = new Global({type: "i32", mutable: true}, 37); let g = new Global({value: "i32", mutable: true}, 37);
g.value = 10; g.value = 10;
assertEq(g.value, 10); assertEq(g.value, 10);
} }
{ {
// Misc internal conversions // Misc internal conversions
let g = new Global({type: "i32"}, 42); let g = new Global({value: "i32"}, 42);
// valueOf // valueOf
assertEq(g - 5, 37); assertEq(g - 5, 37);
@ -513,7 +513,7 @@ if (typeof WebAssembly.Global === "function") {
(import "m" "g" (global i32)))`)); (import "m" "g" (global i32)))`));
// Mutable Global matched to immutable import // Mutable Global matched to immutable import
let gm = new Global({type: "i32", mutable: true}, 42); let gm = new Global({value: "i32", mutable: true}, 42);
assertErrorMessage(() => new Instance(m1, {m: {g: gm}}), assertErrorMessage(() => new Instance(m1, {m: {g: gm}}),
LinkError, LinkError,
mutErr); mutErr);
@ -522,7 +522,7 @@ if (typeof WebAssembly.Global === "function") {
(import "m" "g" (global (mut i32))))`)); (import "m" "g" (global (mut i32))))`));
// Immutable Global matched to mutable import // Immutable Global matched to mutable import
let gi = new Global({type: "i32", mutable: false}, 42); let gi = new Global({value: "i32", mutable: false}, 42);
assertErrorMessage(() => new Instance(m2, {m: {g: gi}}), assertErrorMessage(() => new Instance(m2, {m: {g: gi}}),
LinkError, LinkError,
mutErr); mutErr);

Просмотреть файл

@ -6,7 +6,7 @@ if (typeof oomTest !== 'function' || !wasmIsSupported()) {
} }
function foo() { function foo() {
var g = newGlobal(); var g = newGlobal({sameZoneAs: this});
g.eval(`o = new WebAssembly.Instance(new WebAssembly.Module(wasmTextToBinary('(module (func) (export "" 0))')));`); g.eval(`o = new WebAssembly.Instance(new WebAssembly.Module(wasmTextToBinary('(module (func) (export "" 0))')));`);
} }
oomTest(foo); oomTest(foo);

Просмотреть файл

@ -83,8 +83,8 @@ BaselineFrame::trace(JSTracer* trc, const JSJitFrameIter& frameIterator)
TraceLocals(this, trc, 0, nlivefixed); TraceLocals(this, trc, 0, nlivefixed);
} }
if (script->compartment()->debugEnvs) if (auto* debugEnvs = script->realm()->debugEnvs())
script->compartment()->debugEnvs->traceLiveFrame(trc, this); debugEnvs->traceLiveFrame(trc, this);
} }
bool bool

Просмотреть файл

@ -4406,7 +4406,7 @@ CallIRGenerator::tryAttachStringSplit()
return false; return false;
// Get the object group to use for this location. // Get the object group to use for this location.
RootedObjectGroup group(cx_, ObjectGroupCompartment::getStringSplitStringGroup(cx_)); RootedObjectGroup group(cx_, ObjectGroupRealm::getStringSplitStringGroup(cx_));
if (!group) if (!group)
return false; return false;

Просмотреть файл

@ -1930,7 +1930,7 @@ JitRealm::generateRegExpMatcherStub(JSContext* cx)
maybeTemp4 = regs.takeAny(); maybeTemp4 = regs.takeAny();
} }
ArrayObject* templateObject = cx->compartment()->regExps.getOrCreateMatchResultTemplateObject(cx); ArrayObject* templateObject = cx->realm()->regExps.getOrCreateMatchResultTemplateObject(cx);
if (!templateObject) if (!templateObject)
return nullptr; return nullptr;
@ -2543,7 +2543,7 @@ CodeGenerator::visitRegExpPrototypeOptimizable(LRegExpPrototypeOptimizable* ins)
masm.loadJSContext(temp); masm.loadJSContext(temp);
masm.loadPtr(Address(temp, JSContext::offsetOfRealm()), temp); masm.loadPtr(Address(temp, JSContext::offsetOfRealm()), temp);
size_t offset = Realm::offsetOfRegExps() + size_t offset = Realm::offsetOfRegExps() +
RegExpCompartment::offsetOfOptimizableRegExpPrototypeShape(); RegExpRealm::offsetOfOptimizableRegExpPrototypeShape();
masm.loadPtr(Address(temp, offset), temp); masm.loadPtr(Address(temp, offset), temp);
masm.branchTestObjShapeUnsafe(Assembler::NotEqual, object, temp, ool->entry()); masm.branchTestObjShapeUnsafe(Assembler::NotEqual, object, temp, ool->entry());
@ -2603,7 +2603,7 @@ CodeGenerator::visitRegExpInstanceOptimizable(LRegExpInstanceOptimizable* ins)
masm.loadJSContext(temp); masm.loadJSContext(temp);
masm.loadPtr(Address(temp, JSContext::offsetOfRealm()), temp); masm.loadPtr(Address(temp, JSContext::offsetOfRealm()), temp);
size_t offset = Realm::offsetOfRegExps() + size_t offset = Realm::offsetOfRegExps() +
RegExpCompartment::offsetOfOptimizableRegExpInstanceShape(); RegExpRealm::offsetOfOptimizableRegExpInstanceShape();
masm.loadPtr(Address(temp, offset), temp); masm.loadPtr(Address(temp, offset), temp);
masm.branchTestObjShapeUnsafe(Assembler::NotEqual, object, temp, ool->entry()); masm.branchTestObjShapeUnsafe(Assembler::NotEqual, object, temp, ool->entry());

Просмотреть файл

@ -1770,7 +1770,7 @@ IonBuilder::inlineStringSplitString(CallInfo& callInfo)
return resultConstStringSplit; return resultConstStringSplit;
JSContext* cx = TlsContext.get(); JSContext* cx = TlsContext.get();
ObjectGroup* group = ObjectGroupCompartment::getStringSplitStringGroup(cx); ObjectGroup* group = ObjectGroupRealm::getStringSplitStringGroup(cx);
if (!group) if (!group)
return InliningStatus_NotInlined; return InliningStatus_NotInlined;
AutoSweepObjectGroup sweep(group); AutoSweepObjectGroup sweep(group);

Просмотреть файл

@ -1129,7 +1129,7 @@ RStringSplit::recover(JSContext* cx, SnapshotIterator& iter) const
{ {
RootedString str(cx, iter.read().toString()); RootedString str(cx, iter.read().toString());
RootedString sep(cx, iter.read().toString()); RootedString sep(cx, iter.read().toString());
RootedObjectGroup group(cx, ObjectGroupCompartment::getStringSplitStringGroup(cx)); RootedObjectGroup group(cx, ObjectGroupRealm::getStringSplitStringGroup(cx));
if (!group) { if (!group) {
return false; return false;
} }

Просмотреть файл

@ -371,6 +371,7 @@ MSG_DEF(JSMSG_WASM_BAD_FIT, 2, JSEXN_WASMLINKERROR, "{0} segment does
MSG_DEF(JSMSG_WASM_BAD_I64_LINK, 0, JSEXN_WASMLINKERROR, "cannot pass i64 to or from JS") MSG_DEF(JSMSG_WASM_BAD_I64_LINK, 0, JSEXN_WASMLINKERROR, "cannot pass i64 to or from JS")
MSG_DEF(JSMSG_WASM_NO_SHMEM_LINK, 0, JSEXN_WASMLINKERROR, "shared memory is disabled") MSG_DEF(JSMSG_WASM_NO_SHMEM_LINK, 0, JSEXN_WASMLINKERROR, "shared memory is disabled")
MSG_DEF(JSMSG_WASM_BAD_MUT_LINK, 0, JSEXN_WASMLINKERROR, "imported global mutability mismatch") MSG_DEF(JSMSG_WASM_BAD_MUT_LINK, 0, JSEXN_WASMLINKERROR, "imported global mutability mismatch")
MSG_DEF(JSMSG_WASM_BAD_TYPE_LINK, 0, JSEXN_WASMLINKERROR, "imported global type mismatch")
MSG_DEF(JSMSG_WASM_IND_CALL_TO_NULL, 0, JSEXN_WASMRUNTIMEERROR, "indirect call to null") MSG_DEF(JSMSG_WASM_IND_CALL_TO_NULL, 0, JSEXN_WASMRUNTIMEERROR, "indirect call to null")
MSG_DEF(JSMSG_WASM_IND_CALL_BAD_SIG, 0, JSEXN_WASMRUNTIMEERROR, "indirect call signature mismatch") MSG_DEF(JSMSG_WASM_IND_CALL_BAD_SIG, 0, JSEXN_WASMRUNTIMEERROR, "indirect call signature mismatch")
MSG_DEF(JSMSG_WASM_UNREACHABLE, 0, JSEXN_WASMRUNTIMEERROR, "unreachable executed") MSG_DEF(JSMSG_WASM_UNREACHABLE, 0, JSEXN_WASMRUNTIMEERROR, "unreachable executed")

Просмотреть файл

@ -682,7 +682,7 @@ JS::EnterRealm(JSContext* cx, JSObject* target)
Realm* oldRealm = cx->realm(); Realm* oldRealm = cx->realm();
cx->enterRealmOf(target); cx->enterRealmOf(target);
return JS::GetRealmForCompartment(oldRealm); return JS::GetCompartmentForRealm(oldRealm);
} }
JS_PUBLIC_API(void) JS_PUBLIC_API(void)
@ -7796,11 +7796,11 @@ JS::CaptureCurrentStack(JSContext* cx, JS::MutableHandleObject stackp,
{ {
AssertHeapIsIdle(); AssertHeapIsIdle();
CHECK_REQUEST(cx); CHECK_REQUEST(cx);
MOZ_RELEASE_ASSERT(cx->compartment()); MOZ_RELEASE_ASSERT(cx->realm());
JSCompartment* compartment = cx->compartment(); Realm* realm = cx->realm();
Rooted<SavedFrame*> frame(cx); Rooted<SavedFrame*> frame(cx);
if (!compartment->savedStacks().saveCurrentStack(cx, &frame, mozilla::Move(capture))) if (!realm->savedStacks().saveCurrentStack(cx, &frame, mozilla::Move(capture)))
return false; return false;
stackp.set(frame.get()); stackp.set(frame.get());
return true; return true;
@ -7813,13 +7813,12 @@ JS::CopyAsyncStack(JSContext* cx, JS::HandleObject asyncStack,
{ {
AssertHeapIsIdle(); AssertHeapIsIdle();
CHECK_REQUEST(cx); CHECK_REQUEST(cx);
MOZ_RELEASE_ASSERT(cx->compartment()); MOZ_RELEASE_ASSERT(cx->realm());
js::AssertObjectIsSavedFrameOrWrapper(cx, asyncStack); js::AssertObjectIsSavedFrameOrWrapper(cx, asyncStack);
JSCompartment* compartment = cx->compartment(); Realm* realm = cx->realm();
Rooted<SavedFrame*> frame(cx); Rooted<SavedFrame*> frame(cx);
if (!compartment->savedStacks().copyAsyncStack(cx, asyncStack, asyncCause, if (!realm->savedStacks().copyAsyncStack(cx, asyncStack, asyncCause, &frame, maxFrameCount))
&frame, maxFrameCount))
return false; return false;
stackp.set(frame.get()); stackp.set(frame.get());
return true; return true;

Просмотреть файл

@ -447,7 +447,7 @@ ErrorCopier::~ErrorCopier()
// The provenance of Debugger.DebuggeeWouldRun is the topmost locking // The provenance of Debugger.DebuggeeWouldRun is the topmost locking
// debugger compartment; it should not be copied around. // debugger compartment; it should not be copied around.
if (ar->origin() != cx->compartment() && if (JS::GetCompartmentForRealm(ar->origin()) != cx->compartment() &&
cx->isExceptionPending() && cx->isExceptionPending() &&
!cx->isThrowingDebuggeeWouldRun()) !cx->isThrowingDebuggeeWouldRun())
{ {

Просмотреть файл

@ -172,6 +172,15 @@ enum JSShellExitCode {
EXITCODE_TIMEOUT = 6 EXITCODE_TIMEOUT = 6
}; };
// Define use of application-specific slots on the shell's global object.
enum GlobalAppSlot
{
GlobalAppSlotModuleResolveHook,
GlobalAppSlotCount
};
static_assert(GlobalAppSlotCount <= JSCLASS_GLOBAL_APPLICATION_SLOTS,
"Too many applications slots defined for shell global");
/* /*
* Note: This limit should match the stack limit set by the browser in * Note: This limit should match the stack limit set by the browser in
* js/xpconnect/src/XPCJSContext.cpp * js/xpconnect/src/XPCJSContext.cpp
@ -610,8 +619,7 @@ ShellContext::ShellContext(JSContext* cx)
readLineBufPos(0), readLineBufPos(0),
errFilePtr(nullptr), errFilePtr(nullptr),
outFilePtr(nullptr), outFilePtr(nullptr),
offThreadMonitor(mutexid::ShellOffThreadState), offThreadMonitor(mutexid::ShellOffThreadState)
moduleResolveHook(cx)
{} {}
ShellContext::~ShellContext() ShellContext::~ShellContext()
@ -4279,8 +4287,8 @@ SetModuleResolveHook(JSContext* cx, unsigned argc, Value* vp)
return false; return false;
} }
ShellContext* sc = GetShellContext(cx); Handle<GlobalObject*> global = cx->global();
sc->moduleResolveHook = &args[0].toObject().as<JSFunction>(); global->setReservedSlot(GlobalAppSlotModuleResolveHook, args[0]);
args.rval().setUndefined(); args.rval().setUndefined();
return true; return true;
@ -4289,18 +4297,20 @@ SetModuleResolveHook(JSContext* cx, unsigned argc, Value* vp)
static JSObject* static JSObject*
CallModuleResolveHook(JSContext* cx, HandleObject module, HandleString specifier) CallModuleResolveHook(JSContext* cx, HandleObject module, HandleString specifier)
{ {
ShellContext* sc = GetShellContext(cx); Handle<GlobalObject*> global = cx->global();
if (!sc->moduleResolveHook) { RootedValue hookValue(cx, global->getReservedSlot(GlobalAppSlotModuleResolveHook));
if (hookValue.isUndefined()) {
JS_ReportErrorASCII(cx, "Module resolve hook not set"); JS_ReportErrorASCII(cx, "Module resolve hook not set");
return nullptr; return nullptr;
} }
MOZ_ASSERT(hookValue.toObject().is<JSFunction>());
JS::AutoValueArray<2> args(cx); JS::AutoValueArray<2> args(cx);
args[0].setObject(*module); args[0].setObject(*module);
args[1].setString(specifier); args[1].setString(specifier);
RootedValue result(cx); RootedValue result(cx);
if (!JS_CallFunction(cx, nullptr, sc->moduleResolveHook, args, &result)) if (!JS_CallFunctionValue(cx, nullptr, hookValue, args, &result))
return nullptr; return nullptr;
if (!result.isObject() || !result.toObject().is<ModuleObject>()) { if (!result.isObject() || !result.toObject().is<ModuleObject>()) {

Просмотреть файл

@ -180,8 +180,6 @@ struct ShellContext
// Off-thread parse state. // Off-thread parse state.
js::Monitor offThreadMonitor; js::Monitor offThreadMonitor;
Vector<OffThreadJob*, 0, SystemAllocPolicy> offThreadJobs; Vector<OffThreadJob*, 0, SystemAllocPolicy> offThreadJobs;
JS::PersistentRootedFunction moduleResolveHook;
}; };
extern ShellContext* extern ShellContext*

Просмотреть файл

@ -2742,9 +2742,8 @@ Debugger::ensureExecutionObservabilityOfFrame(JSContext* cx, AbstractFramePtr fr
} }
/* static */ bool /* static */ bool
Debugger::ensureExecutionObservabilityOfCompartment(JSContext* cx, JSCompartment* comp) Debugger::ensureExecutionObservabilityOfRealm(JSContext* cx, Realm* realm)
{ {
Realm* realm = JS::GetRealmForCompartment(comp);
if (realm->debuggerObservesAllExecution()) if (realm->debuggerObservesAllExecution())
return true; return true;
ExecutionObservableRealms obs(cx); ExecutionObservableRealms obs(cx);
@ -3746,7 +3745,7 @@ Debugger::addAllGlobalsAsDebuggees(JSContext* cx, unsigned argc, Value* vp)
for (RealmsInZoneIter r(zone); !r.done(); r.next()) { for (RealmsInZoneIter r(zone); !r.done(); r.next()) {
if (r == dbg->object->realm() || r->creationOptions().invisibleToDebugger()) if (r == dbg->object->realm() || r->creationOptions().invisibleToDebugger())
continue; continue;
r->scheduledForDestruction = false; JS::GetCompartmentForRealm(r)->scheduledForDestruction = false;
GlobalObject* global = r->maybeGlobal(); GlobalObject* global = r->maybeGlobal();
if (global) { if (global) {
Rooted<GlobalObject*> rg(cx, global); Rooted<GlobalObject*> rg(cx, global);
@ -4078,7 +4077,7 @@ Debugger::addDebuggeeGlobal(JSContext* cx, Handle<GlobalObject*> global)
debuggeeRealm->updateDebuggerObservesAsmJS(); debuggeeRealm->updateDebuggerObservesAsmJS();
debuggeeRealm->updateDebuggerObservesBinarySource(); debuggeeRealm->updateDebuggerObservesBinarySource();
debuggeeRealm->updateDebuggerObservesCoverage(); debuggeeRealm->updateDebuggerObservesCoverage();
if (observesAllExecution() && !ensureExecutionObservabilityOfCompartment(cx, debuggeeRealm)) if (observesAllExecution() && !ensureExecutionObservabilityOfRealm(cx, debuggeeRealm))
return false; return false;
globalDebuggersGuard.release(); globalDebuggersGuard.release();
@ -4963,7 +4962,7 @@ Debugger::findAllGlobals(JSContext* cx, unsigned argc, Value* vp)
if (r->creationOptions().invisibleToDebugger()) if (r->creationOptions().invisibleToDebugger())
continue; continue;
r->scheduledForDestruction = false; JS::GetCompartmentForRealm(r)->scheduledForDestruction = false;
GlobalObject* global = r->maybeGlobal(); GlobalObject* global = r->maybeGlobal();

Просмотреть файл

@ -754,8 +754,8 @@ class Debugger : private mozilla::LinkedListElement<Debugger>
private: private:
static MOZ_MUST_USE bool ensureExecutionObservabilityOfFrame(JSContext* cx, static MOZ_MUST_USE bool ensureExecutionObservabilityOfFrame(JSContext* cx,
AbstractFramePtr frame); AbstractFramePtr frame);
static MOZ_MUST_USE bool ensureExecutionObservabilityOfCompartment(JSContext* cx, static MOZ_MUST_USE bool ensureExecutionObservabilityOfRealm(JSContext* cx,
JSCompartment* comp); JS::Realm* realm);
static bool hookObservesAllExecution(Hook which); static bool hookObservesAllExecution(Hook which);

Просмотреть файл

@ -308,10 +308,10 @@ DebuggerMemory::setAllocationSamplingProbability(JSContext* cx, unsigned argc, V
dbg->allocationSamplingProbability = probability; dbg->allocationSamplingProbability = probability;
// If this is a change any debuggees would observe, have all debuggee // If this is a change any debuggees would observe, have all debuggee
// compartments recompute their sampling probabilities. // realms recompute their sampling probabilities.
if (dbg->enabled && dbg->trackingAllocationSites) { if (dbg->enabled && dbg->trackingAllocationSites) {
for (auto r = dbg->debuggees.all(); !r.empty(); r.popFront()) for (auto r = dbg->debuggees.all(); !r.empty(); r.popFront())
r.front()->compartment()->chooseAllocationSamplingProbability(); r.front()->realm()->chooseAllocationSamplingProbability();
} }
} }

Просмотреть файл

@ -145,7 +145,9 @@ CallObject::createSingleton(JSContext* cx, HandleShape shape)
MOZ_ASSERT(CanBeFinalizedInBackground(kind, &CallObject::class_)); MOZ_ASSERT(CanBeFinalizedInBackground(kind, &CallObject::class_));
kind = gc::GetBackgroundAllocKind(kind); kind = gc::GetBackgroundAllocKind(kind);
RootedObjectGroup group(cx, ObjectGroup::lazySingletonGroup(cx, &class_, TaggedProto(nullptr))); ObjectGroupRealm& realm = ObjectGroupRealm::getForNewObject(cx);
RootedObjectGroup group(cx, ObjectGroup::lazySingletonGroup(cx, realm, &class_,
TaggedProto(nullptr)));
if (!group) if (!group)
return nullptr; return nullptr;
@ -2314,7 +2316,7 @@ const DebugEnvironmentProxyHandler DebugEnvironmentProxyHandler::singleton;
/* static */ DebugEnvironmentProxy* /* static */ DebugEnvironmentProxy*
DebugEnvironmentProxy::create(JSContext* cx, EnvironmentObject& env, HandleObject enclosing) DebugEnvironmentProxy::create(JSContext* cx, EnvironmentObject& env, HandleObject enclosing)
{ {
MOZ_ASSERT(env.compartment() == cx->compartment()); MOZ_ASSERT(env.realm() == cx->realm());
MOZ_ASSERT(!enclosing->is<EnvironmentObject>()); MOZ_ASSERT(!enclosing->is<EnvironmentObject>());
RootedValue priv(cx, ObjectValue(env)); RootedValue priv(cx, ObjectValue(env));
@ -2514,11 +2516,11 @@ CanUseDebugEnvironmentMaps(JSContext* cx)
} }
DebugEnvironments* DebugEnvironments*
DebugEnvironments::ensureCompartmentData(JSContext* cx) DebugEnvironments::ensureRealmData(JSContext* cx)
{ {
JSCompartment* c = cx->compartment(); Realm* realm = cx->realm();
if (c->debugEnvs) if (auto* debugEnvs = realm->debugEnvs())
return c->debugEnvs.get(); return debugEnvs;
auto debugEnvs = cx->make_unique<DebugEnvironments>(cx, cx->zone()); auto debugEnvs = cx->make_unique<DebugEnvironments>(cx, cx->zone());
if (!debugEnvs || !debugEnvs->init()) { if (!debugEnvs || !debugEnvs->init()) {
@ -2526,14 +2528,14 @@ DebugEnvironments::ensureCompartmentData(JSContext* cx)
return nullptr; return nullptr;
} }
c->debugEnvs = Move(debugEnvs); realm->debugEnvsRef() = Move(debugEnvs);
return c->debugEnvs.get(); return realm->debugEnvs();
} }
/* static */ DebugEnvironmentProxy* /* static */ DebugEnvironmentProxy*
DebugEnvironments::hasDebugEnvironment(JSContext* cx, EnvironmentObject& env) DebugEnvironments::hasDebugEnvironment(JSContext* cx, EnvironmentObject& env)
{ {
DebugEnvironments* envs = env.compartment()->debugEnvs.get(); DebugEnvironments* envs = env.realm()->debugEnvs();
if (!envs) if (!envs)
return nullptr; return nullptr;
@ -2549,13 +2551,13 @@ DebugEnvironments::hasDebugEnvironment(JSContext* cx, EnvironmentObject& env)
DebugEnvironments::addDebugEnvironment(JSContext* cx, Handle<EnvironmentObject*> env, DebugEnvironments::addDebugEnvironment(JSContext* cx, Handle<EnvironmentObject*> env,
Handle<DebugEnvironmentProxy*> debugEnv) Handle<DebugEnvironmentProxy*> debugEnv)
{ {
MOZ_ASSERT(cx->compartment() == env->compartment()); MOZ_ASSERT(cx->realm() == env->realm());
MOZ_ASSERT(cx->compartment() == debugEnv->compartment()); MOZ_ASSERT(cx->realm() == debugEnv->realm());
if (!CanUseDebugEnvironmentMaps(cx)) if (!CanUseDebugEnvironmentMaps(cx))
return true; return true;
DebugEnvironments* envs = ensureCompartmentData(cx); DebugEnvironments* envs = ensureRealmData(cx);
if (!envs) if (!envs)
return false; return false;
@ -2567,7 +2569,7 @@ DebugEnvironments::hasDebugEnvironment(JSContext* cx, const EnvironmentIter& ei)
{ {
MOZ_ASSERT(!ei.hasSyntacticEnvironment()); MOZ_ASSERT(!ei.hasSyntacticEnvironment());
DebugEnvironments* envs = cx->compartment()->debugEnvs.get(); DebugEnvironments* envs = cx->realm()->debugEnvs();
if (!envs) if (!envs)
return nullptr; return nullptr;
@ -2583,7 +2585,7 @@ DebugEnvironments::addDebugEnvironment(JSContext* cx, const EnvironmentIter& ei,
Handle<DebugEnvironmentProxy*> debugEnv) Handle<DebugEnvironmentProxy*> debugEnv)
{ {
MOZ_ASSERT(!ei.hasSyntacticEnvironment()); MOZ_ASSERT(!ei.hasSyntacticEnvironment());
MOZ_ASSERT(cx->compartment() == debugEnv->compartment()); MOZ_ASSERT(cx->realm() == debugEnv->realm());
// Generators should always have environments. // Generators should always have environments.
MOZ_ASSERT_IF(ei.scope().is<FunctionScope>(), MOZ_ASSERT_IF(ei.scope().is<FunctionScope>(),
!ei.scope().as<FunctionScope>().canonicalFunction()->isGenerator() && !ei.scope().as<FunctionScope>().canonicalFunction()->isGenerator() &&
@ -2592,7 +2594,7 @@ DebugEnvironments::addDebugEnvironment(JSContext* cx, const EnvironmentIter& ei,
if (!CanUseDebugEnvironmentMaps(cx)) if (!CanUseDebugEnvironmentMaps(cx))
return true; return true;
DebugEnvironments* envs = ensureCompartmentData(cx); DebugEnvironments* envs = ensureRealmData(cx);
if (!envs) if (!envs)
return false; return false;
@ -2717,7 +2719,7 @@ DebugEnvironments::onPopCall(JSContext* cx, AbstractFramePtr frame)
{ {
assertSameCompartment(cx, frame); assertSameCompartment(cx, frame);
DebugEnvironments* envs = cx->compartment()->debugEnvs.get(); DebugEnvironments* envs = cx->realm()->debugEnvs();
if (!envs) if (!envs)
return; return;
@ -2759,7 +2761,7 @@ DebugEnvironments::onPopLexical(JSContext* cx, AbstractFramePtr frame, jsbytecod
{ {
assertSameCompartment(cx, frame); assertSameCompartment(cx, frame);
DebugEnvironments* envs = cx->compartment()->debugEnvs.get(); DebugEnvironments* envs = cx->realm()->debugEnvs();
if (!envs) if (!envs)
return; return;
@ -2771,7 +2773,7 @@ template <typename Environment, typename Scope>
void void
DebugEnvironments::onPopGeneric(JSContext* cx, const EnvironmentIter& ei) DebugEnvironments::onPopGeneric(JSContext* cx, const EnvironmentIter& ei)
{ {
DebugEnvironments* envs = cx->compartment()->debugEnvs.get(); DebugEnvironments* envs = cx->realm()->debugEnvs();
if (!envs) if (!envs)
return; return;
@ -2807,7 +2809,7 @@ DebugEnvironments::onPopVar(JSContext* cx, AbstractFramePtr frame, jsbytecode* p
{ {
assertSameCompartment(cx, frame); assertSameCompartment(cx, frame);
DebugEnvironments* envs = cx->compartment()->debugEnvs.get(); DebugEnvironments* envs = cx->realm()->debugEnvs();
if (!envs) if (!envs)
return; return;
@ -2827,14 +2829,15 @@ DebugEnvironments::onPopVar(JSContext* cx, const EnvironmentIter& ei)
void void
DebugEnvironments::onPopWith(AbstractFramePtr frame) DebugEnvironments::onPopWith(AbstractFramePtr frame)
{ {
if (DebugEnvironments* envs = frame.compartment()->debugEnvs.get()) Realm* realm = JS::GetRealmForCompartment(frame.compartment());
if (DebugEnvironments* envs = realm->debugEnvs())
envs->liveEnvs.remove(&frame.environmentChain()->as<WithEnvironmentObject>()); envs->liveEnvs.remove(&frame.environmentChain()->as<WithEnvironmentObject>());
} }
void void
DebugEnvironments::onCompartmentUnsetIsDebuggee(JSCompartment* c) DebugEnvironments::onRealmUnsetIsDebuggee(Realm* realm)
{ {
if (DebugEnvironments* envs = c->debugEnvs.get()) { if (DebugEnvironments* envs = realm->debugEnvs()) {
envs->proxiedEnvs.clear(); envs->proxiedEnvs.clear();
envs->missingEnvs.clear(); envs->missingEnvs.clear();
envs->liveEnvs.clear(); envs->liveEnvs.clear();
@ -2864,7 +2867,7 @@ DebugEnvironments::updateLiveEnvironments(JSContext* cx)
continue; continue;
AbstractFramePtr frame = i.abstractFramePtr(); AbstractFramePtr frame = i.abstractFramePtr();
if (frame.environmentChain()->compartment() != cx->compartment()) if (frame.environmentChain()->realm() != cx->realm())
continue; continue;
if (frame.isFunctionFrame()) { if (frame.isFunctionFrame()) {
@ -2882,8 +2885,8 @@ DebugEnvironments::updateLiveEnvironments(JSContext* cx)
for (EnvironmentIter ei(cx, env, scope, frame); ei.withinInitialFrame(); ei++) { for (EnvironmentIter ei(cx, env, scope, frame); ei.withinInitialFrame(); ei++) {
if (ei.hasSyntacticEnvironment() && !ei.scope().is<GlobalScope>()) { if (ei.hasSyntacticEnvironment() && !ei.scope().is<GlobalScope>()) {
MOZ_ASSERT(ei.environment().compartment() == cx->compartment()); MOZ_ASSERT(ei.environment().realm() == cx->realm());
DebugEnvironments* envs = ensureCompartmentData(cx); DebugEnvironments* envs = ensureRealmData(cx);
if (!envs) if (!envs)
return false; return false;
if (!envs->liveEnvs.put(&ei.environment(), LiveEnvironmentVal(ei))) if (!envs->liveEnvs.put(&ei.environment(), LiveEnvironmentVal(ei)))
@ -2903,7 +2906,7 @@ DebugEnvironments::updateLiveEnvironments(JSContext* cx)
LiveEnvironmentVal* LiveEnvironmentVal*
DebugEnvironments::hasLiveEnvironment(EnvironmentObject& env) DebugEnvironments::hasLiveEnvironment(EnvironmentObject& env)
{ {
DebugEnvironments* envs = env.compartment()->debugEnvs.get(); DebugEnvironments* envs = env.realm()->debugEnvs();
if (!envs) if (!envs)
return nullptr; return nullptr;
@ -2932,7 +2935,7 @@ DebugEnvironments::unsetPrevUpToDateUntil(JSContext* cx, AbstractFramePtr until)
if (frame == until) if (frame == until)
return; return;
if (frame.environmentChain()->compartment() != cx->compartment()) if (frame.environmentChain()->realm() != cx->realm())
continue; continue;
frame.unsetPrevUpToDate(); frame.unsetPrevUpToDate();
@ -2942,7 +2945,7 @@ DebugEnvironments::unsetPrevUpToDateUntil(JSContext* cx, AbstractFramePtr until)
/* static */ void /* static */ void
DebugEnvironments::forwardLiveFrame(JSContext* cx, AbstractFramePtr from, AbstractFramePtr to) DebugEnvironments::forwardLiveFrame(JSContext* cx, AbstractFramePtr from, AbstractFramePtr to)
{ {
DebugEnvironments* envs = cx->compartment()->debugEnvs.get(); DebugEnvironments* envs = cx->realm()->debugEnvs();
if (!envs) if (!envs)
return; return;

Просмотреть файл

@ -952,7 +952,7 @@ class DebugEnvironmentProxy : public ProxyObject
bool isOptimizedOut() const; bool isOptimizedOut() const;
}; };
/* Maintains per-compartment debug environment bookkeeping information. */ /* Maintains per-realm debug environment bookkeeping information. */
class DebugEnvironments class DebugEnvironments
{ {
Zone* zone_; Zone* zone_;
@ -993,7 +993,7 @@ class DebugEnvironments
private: private:
bool init(); bool init();
static DebugEnvironments* ensureCompartmentData(JSContext* cx); static DebugEnvironments* ensureRealmData(JSContext* cx);
template <typename Environment, typename Scope> template <typename Environment, typename Scope>
static void onPopGeneric(JSContext* cx, const EnvironmentIter& ei); static void onPopGeneric(JSContext* cx, const EnvironmentIter& ei);
@ -1044,7 +1044,7 @@ class DebugEnvironments
static void onPopLexical(JSContext* cx, const EnvironmentIter& ei); static void onPopLexical(JSContext* cx, const EnvironmentIter& ei);
static void onPopLexical(JSContext* cx, AbstractFramePtr frame, jsbytecode* pc); static void onPopLexical(JSContext* cx, AbstractFramePtr frame, jsbytecode* pc);
static void onPopWith(AbstractFramePtr frame); static void onPopWith(AbstractFramePtr frame);
static void onCompartmentUnsetIsDebuggee(JSCompartment* c); static void onRealmUnsetIsDebuggee(Realm* realm);
}; };
} /* namespace js */ } /* namespace js */

Просмотреть файл

@ -346,10 +346,10 @@ GlobalObject::resolveOffThreadConstructor(JSContext* cx,
return false; return false;
} }
if ((key == JSProto_Object || key == JSProto_Function || key == JSProto_Array) && if (key == JSProto_Object || key == JSProto_Function || key == JSProto_Array) {
!JSObject::setNewGroupUnknown(cx, placeholder->getClass(), placeholder)) ObjectGroupRealm& realm = ObjectGroupRealm::getForNewObject(cx);
{ if (!JSObject::setNewGroupUnknown(cx, realm, placeholder->getClass(), placeholder))
return false; return false;
} }
global->setPrototype(key, ObjectValue(*placeholder)); global->setPrototype(key, ObjectValue(*placeholder));

Просмотреть файл

@ -1660,11 +1660,11 @@ class ReservedRooted : public RootedBase<T, ReservedRooted<T>>
} }
explicit ReservedRooted(Rooted<T>* root) : savedRoot(root) { explicit ReservedRooted(Rooted<T>* root) : savedRoot(root) {
*root = JS::GCPolicy<T>::initial(); *root = JS::SafelyInitialized<T>();
} }
~ReservedRooted() { ~ReservedRooted() {
*savedRoot = JS::GCPolicy<T>::initial(); *savedRoot = JS::SafelyInitialized<T>();
} }
void set(const T& p) const { *savedRoot = p; } void set(const T& p) const { *savedRoot = p; }

Просмотреть файл

@ -971,8 +971,8 @@ Realm::getOrCreateIterResultTemplateObject(JSContext* cx)
// Create a new group for the template. // Create a new group for the template.
Rooted<TaggedProto> proto(cx, templateObject->taggedProto()); Rooted<TaggedProto> proto(cx, templateObject->taggedProto());
RootedObjectGroup group(cx, ObjectGroupCompartment::makeGroup(cx, templateObject->getClass(), RootedObjectGroup group(cx, ObjectGroupRealm::makeGroup(cx, templateObject->getClass(),
proto)); proto));
if (!group) if (!group)
return iterResultTemplate_; // = nullptr return iterResultTemplate_; // = nullptr
templateObject->setGroup(group); templateObject->setGroup(group);

Просмотреть файл

@ -43,10 +43,7 @@ using mozilla::PodArrayZero;
JSCompartment::JSCompartment(Zone* zone) JSCompartment::JSCompartment(Zone* zone)
: zone_(zone), : zone_(zone),
runtime_(zone->runtimeFromAnyThread()), runtime_(zone->runtimeFromAnyThread())
data(nullptr),
regExps(),
gcIncomingGrayPointers(nullptr)
{ {
runtime_->numCompartments++; runtime_->numCompartments++;
} }
@ -80,17 +77,17 @@ Realm::~Realm()
JSRuntime* rt = runtimeFromMainThread(); JSRuntime* rt = runtimeFromMainThread();
if (rt->lcovOutput().isEnabled()) if (rt->lcovOutput().isEnabled())
rt->lcovOutput().writeLCovResult(lcovOutput); rt->lcovOutput().writeLCovResult(lcovOutput);
}
JSCompartment::~JSCompartment()
{
#ifdef DEBUG #ifdef DEBUG
// Avoid assertion destroying the unboxed layouts list if the embedding // Avoid assertion destroying the unboxed layouts list if the embedding
// leaked GC things. // leaked GC things.
if (!runtime_->gc.shutdownCollectedEverything()) if (!runtime_->gc.shutdownCollectedEverything())
unboxedLayouts.clear(); objectGroups_.unboxedLayouts.clear();
#endif #endif
}
JSCompartment::~JSCompartment()
{
runtime_->numCompartments--; runtime_->numCompartments--;
} }
@ -710,8 +707,8 @@ Realm::traceRoots(JSTracer* trc, js::gc::GCRuntime::TraceOrMarkRuntime traceOrMa
return; return;
/* Mark debug scopes, if present */ /* Mark debug scopes, if present */
if (debugEnvs) if (debugEnvs_)
debugEnvs->trace(trc); debugEnvs_->trace(trc);
objects_.trace(trc); objects_.trace(trc);
@ -757,8 +754,8 @@ ObjectRealm::finishRoots()
void void
Realm::finishRoots() Realm::finishRoots()
{ {
if (debugEnvs) if (debugEnvs_)
debugEnvs->finish(); debugEnvs_->finish();
objects_.finishRoots(); objects_.finishRoots();
@ -792,7 +789,7 @@ JSCompartment::sweepAfterMinorGC(JSTracer* trc)
} }
void void
JSCompartment::sweepSavedStacks() Realm::sweepSavedStacks()
{ {
savedStacks_.sweep(); savedStacks_.sweep();
} }
@ -822,7 +819,7 @@ Realm::sweepJitRealm()
} }
void void
JSCompartment::sweepRegExps() Realm::sweepRegExps()
{ {
/* /*
* JIT code increments activeWarmUpCounter for any RegExpShared used by jit * JIT code increments activeWarmUpCounter for any RegExpShared used by jit
@ -833,10 +830,10 @@ JSCompartment::sweepRegExps()
} }
void void
JSCompartment::sweepDebugEnvironments() Realm::sweepDebugEnvironments()
{ {
if (debugEnvs) if (debugEnvs_)
debugEnvs->sweep(); debugEnvs_->sweep();
} }
void void
@ -932,17 +929,22 @@ JSCompartment::fixupCrossCompartmentWrappersAfterMovingGC(JSTracer* trc)
} }
} }
void
Realm::fixupAfterMovingGC()
{
purge();
fixupGlobal();
objectGroups_.fixupTablesAfterMovingGC();
fixupScriptMapsAfterMovingGC();
}
void void
JSCompartment::fixupAfterMovingGC() JSCompartment::fixupAfterMovingGC()
{ {
MOZ_ASSERT(zone()->isGCCompacting()); MOZ_ASSERT(zone()->isGCCompacting());
Realm* realm = JS::GetRealmForCompartment(this); Realm* realm = JS::GetRealmForCompartment(this);
realm->fixupAfterMovingGC();
realm->purge();
realm->fixupGlobal();
objectGroups.fixupTablesAfterMovingGC();
realm->fixupScriptMapsAfterMovingGC();
// Sweep the wrapper map to update values (wrapper objects) in this // Sweep the wrapper map to update values (wrapper objects) in this
// compartment that may have been moved. // compartment that may have been moved.
@ -1035,7 +1037,7 @@ Realm::purge()
{ {
dtoaCache.purge(); dtoaCache.purge();
newProxyCache.purge(); newProxyCache.purge();
objectGroups.purge(); objectGroups_.purge();
objects_.iteratorCache.clearAndShrink(); objects_.iteratorCache.clearAndShrink();
arraySpeciesLookup.purge(); arraySpeciesLookup.purge();
} }
@ -1049,10 +1051,10 @@ Realm::clearTables()
// a realm that has been used off thread into another realm and zone. // a realm that has been used off thread into another realm and zone.
JS::GetCompartmentForRealm(this)->assertNoCrossCompartmentWrappers(); JS::GetCompartmentForRealm(this)->assertNoCrossCompartmentWrappers();
MOZ_ASSERT(!jitRealm_); MOZ_ASSERT(!jitRealm_);
MOZ_ASSERT(!debugEnvs); MOZ_ASSERT(!debugEnvs_);
MOZ_ASSERT(objects_.enumerators->next() == objects_.enumerators); MOZ_ASSERT(objects_.enumerators->next() == objects_.enumerators);
objectGroups.clearTables(); objectGroups_.clearTables();
if (savedStacks_.initialized()) if (savedStacks_.initialized())
savedStacks_.clear(); savedStacks_.clear();
if (varNames_.initialized()) if (varNames_.initialized())
@ -1086,7 +1088,7 @@ void
Realm::setNewObjectMetadata(JSContext* cx, HandleObject obj) Realm::setNewObjectMetadata(JSContext* cx, HandleObject obj)
{ {
MOZ_ASSERT(obj->realm() == this); MOZ_ASSERT(obj->realm() == this);
assertSameCompartment(cx, this, obj); assertSameCompartment(cx, JS::GetCompartmentForRealm(this), obj);
AutoEnterOOMUnsafeRegion oomUnsafe; AutoEnterOOMUnsafeRegion oomUnsafe;
if (JSObject* metadata = allocationMetadataBuilder_->build(cx, obj, oomUnsafe)) { if (JSObject* metadata = allocationMetadataBuilder_->build(cx, obj, oomUnsafe)) {
@ -1239,7 +1241,7 @@ Realm::unsetIsDebuggee()
{ {
if (isDebuggee()) { if (isDebuggee()) {
debugModeBits_ &= ~DebuggerObservesMask; debugModeBits_ &= ~DebuggerObservesMask;
DebugEnvironments::onCompartmentUnsetIsDebuggee(this); DebugEnvironments::onRealmUnsetIsDebuggee(this);
} }
} }
@ -1371,9 +1373,9 @@ Realm::addSizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf,
JSCompartment::addSizeOfExcludingThis(mallocSizeOf, crossCompartmentWrappersArg); JSCompartment::addSizeOfExcludingThis(mallocSizeOf, crossCompartmentWrappersArg);
*realmObject += mallocSizeOf(this); *realmObject += mallocSizeOf(this);
objectGroups.addSizeOfExcludingThis(mallocSizeOf, tiAllocationSiteTables, objectGroups_.addSizeOfExcludingThis(mallocSizeOf, tiAllocationSiteTables,
tiArrayTypeTables, tiObjectTypeTables, tiArrayTypeTables, tiObjectTypeTables,
realmTables); realmTables);
wasm.addSizeOfExcludingThis(mallocSizeOf, realmTables); wasm.addSizeOfExcludingThis(mallocSizeOf, realmTables);
objects_.addSizeOfExcludingThis(mallocSizeOf, objects_.addSizeOfExcludingThis(mallocSizeOf,

Просмотреть файл

@ -557,10 +557,27 @@ struct JSCompartment
JSRuntime* runtime_; JSRuntime* runtime_;
private: private:
friend struct JSRuntime; js::WrapperMap crossCompartmentWrappers;
friend struct JSContext;
public: public:
/*
* During GC, stores the head of a list of incoming pointers from gray cells.
*
* The objects in the list are either cross-compartment wrappers, or
* debugger wrapper objects. The list link is either in the second extra
* slot for the former, or a special slot for the latter.
*/
JSObject* gcIncomingGrayPointers = nullptr;
void* data = nullptr;
// These flags help us to discover if a compartment that shouldn't be alive
// manages to outlive a GC. Note that these flags have to be on the
// compartment, not the realm, because same-compartment realms can have
// cross-realm pointers without wrappers.
bool scheduledForDestruction = false;
bool maybeAlive = true;
JS::Zone* zone() { return zone_; } JS::Zone* zone() { return zone_; }
const JS::Zone* zone() const { return zone_; } const JS::Zone* zone() const { return zone_; }
@ -575,53 +592,19 @@ struct JSCompartment
return runtime_; return runtime_;
} }
public:
void* data;
protected:
js::SavedStacks savedStacks_;
private:
js::WrapperMap crossCompartmentWrappers;
public:
void assertNoCrossCompartmentWrappers() { void assertNoCrossCompartmentWrappers() {
MOZ_ASSERT(crossCompartmentWrappers.empty()); MOZ_ASSERT(crossCompartmentWrappers.empty());
} }
public:
js::RegExpCompartment regExps;
// Recompute the probability with which this compartment should record
// profiling data (stack traces, allocations log, etc.) about each
// allocation. We consult the probabilities requested by the Debugger
// instances observing us, if any.
void chooseAllocationSamplingProbability() { savedStacks_.chooseSamplingProbability(this); }
protected: protected:
void addSizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf, void addSizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf,
size_t* crossCompartmentWrappersArg); size_t* crossCompartmentWrappersArg);
public: public:
// Object group tables and other state in the compartment.
js::ObjectGroupCompartment objectGroups;
#ifdef JSGC_HASH_TABLE_CHECKS #ifdef JSGC_HASH_TABLE_CHECKS
void checkWrapperMapAfterMovingGC(); void checkWrapperMapAfterMovingGC();
#endif #endif
// All unboxed layouts in the compartment.
mozilla::LinkedList<js::UnboxedLayout> unboxedLayouts;
/*
* During GC, stores the head of a list of incoming pointers from gray cells.
*
* The objects in the list are either cross-compartment wrappers, or
* debugger wrapper objects. The list link is either in the second extra
* slot for the former, or a special slot for the latter.
*/
JSObject* gcIncomingGrayPointers;
private: private:
bool getNonWrapperObjectForCurrentCompartment(JSContext* cx, js::MutableHandleObject obj); bool getNonWrapperObjectForCurrentCompartment(JSContext* cx, js::MutableHandleObject obj);
bool getOrCreateWrapper(JSContext* cx, js::HandleObject existing, js::MutableHandleObject obj); bool getOrCreateWrapper(JSContext* cx, js::HandleObject existing, js::MutableHandleObject obj);
@ -689,30 +672,11 @@ struct JSCompartment
void sweepAfterMinorGC(JSTracer* trc); void sweepAfterMinorGC(JSTracer* trc);
void sweepCrossCompartmentWrappers(); void sweepCrossCompartmentWrappers();
void sweepSavedStacks();
void sweepRegExps();
void sweepDebugEnvironments();
static void fixupCrossCompartmentWrappersAfterMovingGC(JSTracer* trc); static void fixupCrossCompartmentWrappersAfterMovingGC(JSTracer* trc);
void fixupAfterMovingGC(); void fixupAfterMovingGC();
js::SavedStacks& savedStacks() { return savedStacks_; }
void findOutgoingEdges(js::gc::ZoneComponentFinder& finder); void findOutgoingEdges(js::gc::ZoneComponentFinder& finder);
static size_t offsetOfRegExps() {
return offsetof(JSCompartment, regExps);
}
/* Bookkeeping information for debug scope objects. */
js::UniquePtr<js::DebugEnvironments> debugEnvs;
// These flags help us to discover if a compartment that shouldn't be alive
// manages to outlive a GC. Note that these flags have to be on the
// compartment, not the realm, because same-compartment realms can have
// cross-realm pointers without wrappers.
bool scheduledForDestruction = false;
bool maybeAlive = true;
}; };
namespace js { namespace js {
@ -782,7 +746,7 @@ class ObjectRealm
} // namespace js } // namespace js
class JS::Realm : public JSCompartment class JS::Realm : private JSCompartment
{ {
const JS::RealmCreationOptions creationOptions_; const JS::RealmCreationOptions creationOptions_;
JS::RealmBehaviors behaviors_; JS::RealmBehaviors behaviors_;
@ -794,6 +758,12 @@ class JS::Realm : public JSCompartment
js::ObjectRealm objects_; js::ObjectRealm objects_;
friend js::ObjectRealm& js::ObjectRealm::get(const JSObject*); friend js::ObjectRealm& js::ObjectRealm::get(const JSObject*);
// Object group tables and other state in the realm. This is private to
// enforce use of ObjectGroupRealm::get(group)/getForNewObject(cx).
js::ObjectGroupRealm objectGroups_;
friend js::ObjectGroupRealm& js::ObjectGroupRealm::get(js::ObjectGroup* group);
friend js::ObjectGroupRealm& js::ObjectGroupRealm::getForNewObject(JSContext* cx);
// The global environment record's [[VarNames]] list that contains all // The global environment record's [[VarNames]] list that contains all
// names declared using FunctionDeclaration, GeneratorDeclaration, and // names declared using FunctionDeclaration, GeneratorDeclaration, and
// VariableDeclaration declarations in global code in this realm. // VariableDeclaration declarations in global code in this realm.
@ -817,6 +787,11 @@ class JS::Realm : public JSCompartment
js::UniquePtr<js::jit::JitRealm> jitRealm_; js::UniquePtr<js::jit::JitRealm> jitRealm_;
// Bookkeeping information for debug scope objects.
js::UniquePtr<js::DebugEnvironments> debugEnvs_;
js::SavedStacks savedStacks_;
// Used by memory reporters and invalid otherwise. // Used by memory reporters and invalid otherwise.
JS::RealmStats* realmStats_ = nullptr; JS::RealmStats* realmStats_ = nullptr;
@ -863,6 +838,8 @@ class JS::Realm : public JSCompartment
// is enabled. // is enabled.
js::coverage::LCovRealm lcovOutput; js::coverage::LCovRealm lcovOutput;
js::RegExpRealm regExps;
js::DtoaCache dtoaCache; js::DtoaCache dtoaCache;
js::NewProxyCache newProxyCache; js::NewProxyCache newProxyCache;
js::ArraySpeciesLookup arraySpeciesLookup; js::ArraySpeciesLookup arraySpeciesLookup;
@ -927,6 +904,24 @@ class JS::Realm : public JSCompartment
size_t* privateData, size_t* privateData,
size_t* scriptCountsMapArg); size_t* scriptCountsMapArg);
JS::Zone* zone() {
return zone_;
}
const JS::Zone* zone() const {
return zone_;
}
JSRuntime* runtimeFromMainThread() const {
MOZ_ASSERT(js::CurrentThreadCanAccessRuntime(runtime_));
return runtime_;
}
// Note: Unrestricted access to the runtime from an arbitrary thread
// can easily lead to races. Use this method very carefully.
JSRuntime* runtimeFromAnyThread() const {
return runtime_;
}
const JS::RealmCreationOptions& creationOptions() const { return creationOptions_; } const JS::RealmCreationOptions& creationOptions() const { return creationOptions_; }
JS::RealmBehaviors& behaviors() { return behaviors_; } JS::RealmBehaviors& behaviors() { return behaviors_; }
const JS::RealmBehaviors& behaviors() const { return behaviors_; } const JS::RealmBehaviors& behaviors() const { return behaviors_; }
@ -987,18 +982,28 @@ class JS::Realm : public JSCompartment
void finishRoots(); void finishRoots();
void sweepAfterMinorGC(); void sweepAfterMinorGC();
void sweepDebugEnvironments();
void sweepObjectRealm(); void sweepObjectRealm();
void sweepRegExps();
void sweepSelfHostingScriptSource(); void sweepSelfHostingScriptSource();
void sweepTemplateObjects(); void sweepTemplateObjects();
void sweepObjectGroups() {
objectGroups_.sweep();
}
void clearScriptCounts(); void clearScriptCounts();
void clearScriptNames(); void clearScriptNames();
void purge(); void purge();
void fixupAfterMovingGC();
void fixupScriptMapsAfterMovingGC(); void fixupScriptMapsAfterMovingGC();
#ifdef JSGC_HASH_TABLE_CHECKS #ifdef JSGC_HASH_TABLE_CHECKS
void checkObjectGroupTablesAfterMovingGC() {
objectGroups_.checkTablesAfterMovingGC();
}
void checkScriptMapsAfterMovingGC(); void checkScriptMapsAfterMovingGC();
#endif #endif
@ -1266,6 +1271,31 @@ class JS::Realm : public JSCompartment
js::jit::JitRealm* jitRealm() { js::jit::JitRealm* jitRealm() {
return jitRealm_.get(); return jitRealm_.get();
} }
js::DebugEnvironments* debugEnvs() {
return debugEnvs_.get();
}
js::UniquePtr<js::DebugEnvironments>& debugEnvsRef() {
return debugEnvs_;
}
js::SavedStacks& savedStacks() {
return savedStacks_;
}
// Recompute the probability with which this realm should record
// profiling data (stack traces, allocations log, etc.) about each
// allocation. We consult the probabilities requested by the Debugger
// instances observing us, if any.
void chooseAllocationSamplingProbability() {
savedStacks_.chooseSamplingProbability(this);
}
void sweepSavedStacks();
static constexpr size_t offsetOfRegExps() {
return offsetof(JS::Realm, regExps);
}
}; };
namespace js { namespace js {

Просмотреть файл

@ -166,7 +166,6 @@ class CompartmentChecker
void check(InterpreterFrame* fp); void check(InterpreterFrame* fp);
void check(AbstractFramePtr frame); void check(AbstractFramePtr frame);
void check(SavedStacks* stacks);
void check(Handle<PropertyDescriptor> desc) { void check(Handle<PropertyDescriptor> desc) {
check(desc.object()); check(desc.object());

Просмотреть файл

@ -890,7 +890,8 @@ CreateFunctionPrototype(JSContext* cx, JSProtoKey key)
* inference to have unknown properties, to simplify handling of e.g. * inference to have unknown properties, to simplify handling of e.g.
* NewFunctionClone. * NewFunctionClone.
*/ */
if (!JSObject::setNewGroupUnknown(cx, &JSFunction::class_, functionProto)) ObjectGroupRealm& realm = ObjectGroupRealm::getForNewObject(cx);
if (!JSObject::setNewGroupUnknown(cx, realm, &JSFunction::class_, functionProto))
return nullptr; return nullptr;
return functionProto; return functionProto;

Просмотреть файл

@ -158,7 +158,8 @@ JSObject::setSingleton(JSContext* cx, js::HandleObject obj)
{ {
MOZ_ASSERT(!IsInsideNursery(obj)); MOZ_ASSERT(!IsInsideNursery(obj));
js::ObjectGroup* group = js::ObjectGroup::lazySingletonGroup(cx, obj->getClass(), js::ObjectGroupRealm& realm = js::ObjectGroupRealm::get(obj->group_);
js::ObjectGroup* group = js::ObjectGroup::lazySingletonGroup(cx, realm, obj->getClass(),
obj->taggedProto()); obj->taggedProto());
if (!group) if (!group)
return false; return false;

Просмотреть файл

@ -2108,7 +2108,7 @@ SetClassAndProto(JSContext* cx, HandleObject obj,
// group so we can keep track of the interpreted function for Ion // group so we can keep track of the interpreted function for Ion
// inlining. // inlining.
MOZ_ASSERT(obj->is<JSFunction>()); MOZ_ASSERT(obj->is<JSFunction>());
newGroup = ObjectGroupCompartment::makeGroup(cx, &JSFunction::class_, proto); newGroup = ObjectGroupRealm::makeGroup(cx, &JSFunction::class_, proto);
if (!newGroup) if (!newGroup)
return false; return false;
newGroup->setInterpretedFunction(oldGroup->maybeInterpretedFunction()); newGroup->setInterpretedFunction(oldGroup->maybeInterpretedFunction());
@ -2144,7 +2144,8 @@ JSObject::changeToSingleton(JSContext* cx, HandleObject obj)
MarkObjectGroupUnknownProperties(cx, obj->group()); MarkObjectGroupUnknownProperties(cx, obj->group());
ObjectGroup* group = ObjectGroup::lazySingletonGroup(cx, obj->getClass(), ObjectGroupRealm& realm = ObjectGroupRealm::get(obj->group());
ObjectGroup* group = ObjectGroup::lazySingletonGroup(cx, realm, obj->getClass(),
obj->taggedProto()); obj->taggedProto());
if (!group) if (!group)
return false; return false;

Просмотреть файл

@ -390,7 +390,8 @@ class JSObject : public js::gc::Cell
* properties. * properties.
*/ */
inline bool isNewGroupUnknown() const; inline bool isNewGroupUnknown() const;
static bool setNewGroupUnknown(JSContext* cx, const js::Class* clasp, JS::HandleObject obj); static bool setNewGroupUnknown(JSContext* cx, js::ObjectGroupRealm& realm,
const js::Class* clasp, JS::HandleObject obj);
/* Set a new prototype for an object with a singleton type. */ /* Set a new prototype for an object with a singleton type. */
static bool splicePrototype(JSContext* cx, js::HandleObject obj, const js::Class* clasp, static bool splicePrototype(JSContext* cx, js::HandleObject obj, const js::Class* clasp,

Просмотреть файл

@ -322,8 +322,8 @@ JSObject::makeLazyGroup(JSContext* cx, HandleObject obj)
initialFlags |= OBJECT_FLAG_LENGTH_OVERFLOW; initialFlags |= OBJECT_FLAG_LENGTH_OVERFLOW;
Rooted<TaggedProto> proto(cx, obj->taggedProto()); Rooted<TaggedProto> proto(cx, obj->taggedProto());
ObjectGroup* group = ObjectGroupCompartment::makeGroup(cx, obj->getClass(), proto, ObjectGroup* group = ObjectGroupRealm::makeGroup(cx, obj->getClass(), proto,
initialFlags); initialFlags);
if (!group) if (!group)
return nullptr; return nullptr;
@ -340,26 +340,27 @@ JSObject::makeLazyGroup(JSContext* cx, HandleObject obj)
} }
/* static */ bool /* static */ bool
JSObject::setNewGroupUnknown(JSContext* cx, const js::Class* clasp, JS::HandleObject obj) JSObject::setNewGroupUnknown(JSContext* cx, ObjectGroupRealm& realm, const js::Class* clasp,
JS::HandleObject obj)
{ {
ObjectGroup::setDefaultNewGroupUnknown(cx, clasp, obj); ObjectGroup::setDefaultNewGroupUnknown(cx, realm, clasp, obj);
return JSObject::setFlags(cx, obj, BaseShape::NEW_GROUP_UNKNOWN); return JSObject::setFlags(cx, obj, BaseShape::NEW_GROUP_UNKNOWN);
} }
///////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////
// ObjectGroupCompartment NewTable // ObjectGroupRealm NewTable
///////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////
/* /*
* Entries for the per-compartment set of groups which are the default * Entries for the per-realm set of groups which are the default
* types to use for some prototype. An optional associated object is used which * types to use for some prototype. An optional associated object is used which
* allows multiple groups to be created with the same prototype. The * allows multiple groups to be created with the same prototype. The
* associated object may be a function (for types constructed with 'new') or a * associated object may be a function (for types constructed with 'new') or a
* type descriptor (for typed objects). These entries are also used for the set * type descriptor (for typed objects). These entries are also used for the set
* of lazy groups in the compartment, which use a null associated object * of lazy groups in the realm, which use a null associated object
* (though there are only a few of these per compartment). * (though there are only a few of these per realm).
*/ */
struct ObjectGroupCompartment::NewEntry struct ObjectGroupRealm::NewEntry
{ {
ReadBarrieredObjectGroup group; ReadBarrieredObjectGroup group;
@ -405,7 +406,7 @@ struct ObjectGroupCompartment::NewEntry
return mozilla::AddToHash(hash, mozilla::HashGeneric(lookup.clasp)); return mozilla::AddToHash(hash, mozilla::HashGeneric(lookup.clasp));
} }
static inline bool match(const ObjectGroupCompartment::NewEntry& key, const Lookup& lookup) { static inline bool match(const ObjectGroupRealm::NewEntry& key, const Lookup& lookup) {
if (lookup.clasp && key.group.unbarrieredGet()->clasp() != lookup.clasp) if (lookup.clasp && key.group.unbarrieredGet()->clasp() != lookup.clasp)
return false; return false;
@ -430,18 +431,18 @@ struct ObjectGroupCompartment::NewEntry
namespace js { namespace js {
template <> template <>
struct FallibleHashMethods<ObjectGroupCompartment::NewEntry> struct FallibleHashMethods<ObjectGroupRealm::NewEntry>
{ {
template <typename Lookup> static bool hasHash(Lookup&& l) { template <typename Lookup> static bool hasHash(Lookup&& l) {
return ObjectGroupCompartment::NewEntry::hasHash(mozilla::Forward<Lookup>(l)); return ObjectGroupRealm::NewEntry::hasHash(mozilla::Forward<Lookup>(l));
} }
template <typename Lookup> static bool ensureHash(Lookup&& l) { template <typename Lookup> static bool ensureHash(Lookup&& l) {
return ObjectGroupCompartment::NewEntry::ensureHash(mozilla::Forward<Lookup>(l)); return ObjectGroupRealm::NewEntry::ensureHash(mozilla::Forward<Lookup>(l));
} }
}; };
} // namespace js } // namespace js
class ObjectGroupCompartment::NewTable : public JS::WeakCache<js::GCHashSet<NewEntry, NewEntry, class ObjectGroupRealm::NewTable : public JS::WeakCache<js::GCHashSet<NewEntry, NewEntry,
SystemAllocPolicy>> SystemAllocPolicy>>
{ {
using Table = js::GCHashSet<NewEntry, NewEntry, SystemAllocPolicy>; using Table = js::GCHashSet<NewEntry, NewEntry, SystemAllocPolicy>;
@ -451,8 +452,20 @@ class ObjectGroupCompartment::NewTable : public JS::WeakCache<js::GCHashSet<NewE
explicit NewTable(Zone* zone) : Base(zone) {} explicit NewTable(Zone* zone) : Base(zone) {}
}; };
/* static*/ ObjectGroupRealm&
ObjectGroupRealm::get(ObjectGroup* group)
{
return group->realm()->objectGroups_;
}
/* static*/ ObjectGroupRealm&
ObjectGroupRealm::getForNewObject(JSContext* cx)
{
return cx->realm()->objectGroups_;
}
MOZ_ALWAYS_INLINE ObjectGroup* MOZ_ALWAYS_INLINE ObjectGroup*
ObjectGroupCompartment::DefaultNewGroupCache::lookup(const Class* clasp, TaggedProto proto, ObjectGroupRealm::DefaultNewGroupCache::lookup(const Class* clasp, TaggedProto proto,
JSObject* associated) JSObject* associated)
{ {
if (group_ && if (group_ &&
@ -503,17 +516,17 @@ ObjectGroup::defaultNewGroup(JSContext* cx, const Class* clasp,
clasp = &PlainObject::class_; clasp = &PlainObject::class_;
} }
ObjectGroupCompartment& groups = cx->compartment()->objectGroups; ObjectGroupRealm& groups = ObjectGroupRealm::getForNewObject(cx);
if (ObjectGroup* group = groups.defaultNewGroupCache.lookup(clasp, proto, associated)) if (ObjectGroup* group = groups.defaultNewGroupCache.lookup(clasp, proto, associated))
return group; return group;
AutoEnterAnalysis enter(cx); AutoEnterAnalysis enter(cx);
ObjectGroupCompartment::NewTable*& table = groups.defaultNewTable; ObjectGroupRealm::NewTable*& table = groups.defaultNewTable;
if (!table) { if (!table) {
table = cx->new_<ObjectGroupCompartment::NewTable>(cx->zone()); table = cx->new_<ObjectGroupRealm::NewTable>(cx->zone());
if (!table || !table->init()) { if (!table || !table->init()) {
js_delete(table); js_delete(table);
table = nullptr; table = nullptr;
@ -545,8 +558,8 @@ ObjectGroup::defaultNewGroup(JSContext* cx, const Class* clasp,
} }
} }
ObjectGroupCompartment::NewTable::AddPtr p = ObjectGroupRealm::NewTable::AddPtr p =
table->lookupForAdd(ObjectGroupCompartment::NewEntry::Lookup(clasp, proto, associated)); table->lookupForAdd(ObjectGroupRealm::NewEntry::Lookup(clasp, proto, associated));
if (p) { if (p) {
ObjectGroup* group = p->group; ObjectGroup* group = p->group;
MOZ_ASSERT_IF(clasp, group->clasp() == clasp); MOZ_ASSERT_IF(clasp, group->clasp() == clasp);
@ -562,12 +575,12 @@ ObjectGroup::defaultNewGroup(JSContext* cx, const Class* clasp,
initialFlags = OBJECT_FLAG_DYNAMIC_MASK; initialFlags = OBJECT_FLAG_DYNAMIC_MASK;
Rooted<TaggedProto> protoRoot(cx, proto); Rooted<TaggedProto> protoRoot(cx, proto);
ObjectGroup* group = ObjectGroupCompartment::makeGroup(cx, clasp ? clasp : &PlainObject::class_, ObjectGroup* group = ObjectGroupRealm::makeGroup(cx, clasp ? clasp : &PlainObject::class_,
protoRoot, initialFlags); protoRoot, initialFlags);
if (!group) if (!group)
return nullptr; return nullptr;
if (!table->add(p, ObjectGroupCompartment::NewEntry(group, associated))) { if (!table->add(p, ObjectGroupRealm::NewEntry(group, associated))) {
ReportOutOfMemory(cx); ReportOutOfMemory(cx);
return nullptr; return nullptr;
} }
@ -605,14 +618,15 @@ ObjectGroup::defaultNewGroup(JSContext* cx, const Class* clasp,
} }
/* static */ ObjectGroup* /* static */ ObjectGroup*
ObjectGroup::lazySingletonGroup(JSContext* cx, const Class* clasp, TaggedProto proto) ObjectGroup::lazySingletonGroup(JSContext* cx, ObjectGroupRealm& realm, const Class* clasp,
TaggedProto proto)
{ {
MOZ_ASSERT_IF(proto.isObject(), cx->compartment() == proto.toObject()->compartment()); MOZ_ASSERT_IF(proto.isObject(), cx->compartment() == proto.toObject()->compartment());
ObjectGroupCompartment::NewTable*& table = cx->compartment()->objectGroups.lazyTable; ObjectGroupRealm::NewTable*& table = realm.lazyTable;
if (!table) { if (!table) {
table = cx->new_<ObjectGroupCompartment::NewTable>(cx->zone()); table = cx->new_<ObjectGroupRealm::NewTable>(cx->zone());
if (!table || !table->init()) { if (!table || !table->init()) {
ReportOutOfMemory(cx); ReportOutOfMemory(cx);
js_delete(table); js_delete(table);
@ -621,8 +635,8 @@ ObjectGroup::lazySingletonGroup(JSContext* cx, const Class* clasp, TaggedProto p
} }
} }
ObjectGroupCompartment::NewTable::AddPtr p = ObjectGroupRealm::NewTable::AddPtr p =
table->lookupForAdd(ObjectGroupCompartment::NewEntry::Lookup(clasp, proto, nullptr)); table->lookupForAdd(ObjectGroupRealm::NewEntry::Lookup(clasp, proto, nullptr));
if (p) { if (p) {
ObjectGroup* group = p->group; ObjectGroup* group = p->group;
MOZ_ASSERT(group->lazy()); MOZ_ASSERT(group->lazy());
@ -634,12 +648,12 @@ ObjectGroup::lazySingletonGroup(JSContext* cx, const Class* clasp, TaggedProto p
Rooted<TaggedProto> protoRoot(cx, proto); Rooted<TaggedProto> protoRoot(cx, proto);
ObjectGroup* group = ObjectGroup* group =
ObjectGroupCompartment::makeGroup(cx, clasp, protoRoot, ObjectGroupRealm::makeGroup(cx, clasp, protoRoot,
OBJECT_FLAG_SINGLETON | OBJECT_FLAG_LAZY_SINGLETON); OBJECT_FLAG_SINGLETON | OBJECT_FLAG_LAZY_SINGLETON);
if (!group) if (!group)
return nullptr; return nullptr;
if (!table->add(p, ObjectGroupCompartment::NewEntry(group, nullptr))) { if (!table->add(p, ObjectGroupRealm::NewEntry(group, nullptr))) {
ReportOutOfMemory(cx); ReportOutOfMemory(cx);
return nullptr; return nullptr;
} }
@ -648,13 +662,14 @@ ObjectGroup::lazySingletonGroup(JSContext* cx, const Class* clasp, TaggedProto p
} }
/* static */ void /* static */ void
ObjectGroup::setDefaultNewGroupUnknown(JSContext* cx, const Class* clasp, HandleObject obj) ObjectGroup::setDefaultNewGroupUnknown(JSContext* cx, ObjectGroupRealm& realm, const Class* clasp,
HandleObject obj)
{ {
// If the object already has a new group, mark that group as unknown. // If the object already has a new group, mark that group as unknown.
ObjectGroupCompartment::NewTable* table = cx->compartment()->objectGroups.defaultNewTable; ObjectGroupRealm::NewTable* table = realm.defaultNewTable;
if (table) { if (table) {
Rooted<TaggedProto> taggedProto(cx, TaggedProto(obj)); Rooted<TaggedProto> taggedProto(cx, TaggedProto(obj));
auto lookup = ObjectGroupCompartment::NewEntry::Lookup(clasp, taggedProto, nullptr); auto lookup = ObjectGroupRealm::NewEntry::Lookup(clasp, taggedProto, nullptr);
auto p = table->lookup(lookup); auto p = table->lookup(lookup);
if (p) if (p)
MarkObjectGroupUnknownProperties(cx, p->group); MarkObjectGroupUnknownProperties(cx, p->group);
@ -665,10 +680,10 @@ ObjectGroup::setDefaultNewGroupUnknown(JSContext* cx, const Class* clasp, Handle
/* static */ bool /* static */ bool
ObjectGroup::hasDefaultNewGroup(JSObject* proto, const Class* clasp, ObjectGroup* group) ObjectGroup::hasDefaultNewGroup(JSObject* proto, const Class* clasp, ObjectGroup* group)
{ {
ObjectGroupCompartment::NewTable* table = proto->compartment()->objectGroups.defaultNewTable; ObjectGroupRealm::NewTable* table = ObjectGroupRealm::get(group).defaultNewTable;
if (table) { if (table) {
auto lookup = ObjectGroupCompartment::NewEntry::Lookup(clasp, TaggedProto(proto), nullptr); auto lookup = ObjectGroupRealm::NewEntry::Lookup(clasp, TaggedProto(proto), nullptr);
auto p = table->lookup(lookup); auto p = table->lookup(lookup);
return p && p->group == group; return p && p->group == group;
} }
@ -735,10 +750,10 @@ ObjectGroup::defaultNewGroup(JSContext* cx, JSProtoKey key)
} }
///////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////
// ObjectGroupCompartment ArrayObjectTable // ObjectGroupRealm ArrayObjectTable
///////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////
struct ObjectGroupCompartment::ArrayObjectKey : public DefaultHasher<ArrayObjectKey> struct ObjectGroupRealm::ArrayObjectKey : public DefaultHasher<ArrayObjectKey>
{ {
TypeSet::Type type; TypeSet::Type type;
@ -833,11 +848,11 @@ ObjectGroup::newArrayObject(JSContext* cx,
} }
} }
ObjectGroupCompartment::ArrayObjectTable*& table = ObjectGroupRealm& realm = ObjectGroupRealm::getForNewObject(cx);
cx->compartment()->objectGroups.arrayObjectTable; ObjectGroupRealm::ArrayObjectTable*& table = realm.arrayObjectTable;
if (!table) { if (!table) {
table = cx->new_<ObjectGroupCompartment::ArrayObjectTable>(); table = cx->new_<ObjectGroupRealm::ArrayObjectTable>();
if (!table || !table->init()) { if (!table || !table->init()) {
ReportOutOfMemory(cx); ReportOutOfMemory(cx);
js_delete(table); js_delete(table);
@ -846,8 +861,8 @@ ObjectGroup::newArrayObject(JSContext* cx,
} }
} }
ObjectGroupCompartment::ArrayObjectKey key(elementType); ObjectGroupRealm::ArrayObjectKey key(elementType);
DependentAddPtr<ObjectGroupCompartment::ArrayObjectTable> p(cx, *table, key); DependentAddPtr<ObjectGroupRealm::ArrayObjectTable> p(cx, *table, key);
RootedObjectGroup group(cx); RootedObjectGroup group(cx);
if (p) { if (p) {
@ -857,13 +872,13 @@ ObjectGroup::newArrayObject(JSContext* cx,
if (!proto) if (!proto)
return nullptr; return nullptr;
Rooted<TaggedProto> taggedProto(cx, TaggedProto(proto)); Rooted<TaggedProto> taggedProto(cx, TaggedProto(proto));
group = ObjectGroupCompartment::makeGroup(cx, &ArrayObject::class_, taggedProto); group = ObjectGroupRealm::makeGroup(cx, &ArrayObject::class_, taggedProto);
if (!group) if (!group)
return nullptr; return nullptr;
AddTypePropertyId(cx, group, nullptr, JSID_VOID, elementType); AddTypePropertyId(cx, group, nullptr, JSID_VOID, elementType);
if (!p.add(cx, *table, ObjectGroupCompartment::ArrayObjectKey(elementType), group)) if (!p.add(cx, *table, ObjectGroupRealm::ArrayObjectKey(elementType), group))
return nullptr; return nullptr;
} }
@ -1041,10 +1056,10 @@ js::CombinePlainObjectPropertyTypes(JSContext* cx, JSObject* newObj,
} }
///////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////
// ObjectGroupCompartment PlainObjectTable // ObjectGroupRealm PlainObjectTable
///////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////
struct ObjectGroupCompartment::PlainObjectKey struct ObjectGroupRealm::PlainObjectKey
{ {
jsid* properties; jsid* properties;
uint32_t nproperties; uint32_t nproperties;
@ -1082,7 +1097,7 @@ struct ObjectGroupCompartment::PlainObjectKey
} }
}; };
struct ObjectGroupCompartment::PlainObjectEntry struct ObjectGroupRealm::PlainObjectEntry
{ {
ReadBarrieredObjectGroup group; ReadBarrieredObjectGroup group;
ReadBarrieredShape shape; ReadBarrieredShape shape;
@ -1156,11 +1171,11 @@ ObjectGroup::newPlainObject(JSContext* cx, IdValuePair* properties, size_t nprop
if (newKind == SingletonObject || nproperties == 0 || nproperties >= PropertyTree::MAX_HEIGHT) if (newKind == SingletonObject || nproperties == 0 || nproperties >= PropertyTree::MAX_HEIGHT)
return NewPlainObjectWithProperties(cx, properties, nproperties, newKind); return NewPlainObjectWithProperties(cx, properties, nproperties, newKind);
ObjectGroupCompartment::PlainObjectTable*& table = ObjectGroupRealm& realm = ObjectGroupRealm::getForNewObject(cx);
cx->compartment()->objectGroups.plainObjectTable; ObjectGroupRealm::PlainObjectTable*& table = realm.plainObjectTable;
if (!table) { if (!table) {
table = cx->new_<ObjectGroupCompartment::PlainObjectTable>(); table = cx->new_<ObjectGroupRealm::PlainObjectTable>();
if (!table || !table->init()) { if (!table || !table->init()) {
ReportOutOfMemory(cx); ReportOutOfMemory(cx);
js_delete(table); js_delete(table);
@ -1169,8 +1184,8 @@ ObjectGroup::newPlainObject(JSContext* cx, IdValuePair* properties, size_t nprop
} }
} }
ObjectGroupCompartment::PlainObjectKey::Lookup lookup(properties, nproperties); ObjectGroupRealm::PlainObjectKey::Lookup lookup(properties, nproperties);
ObjectGroupCompartment::PlainObjectTable::Ptr p = table->lookup(lookup); ObjectGroupRealm::PlainObjectTable::Ptr p = table->lookup(lookup);
if (!p) { if (!p) {
if (!CanShareObjectGroup(properties, nproperties)) if (!CanShareObjectGroup(properties, nproperties))
@ -1181,8 +1196,8 @@ ObjectGroup::newPlainObject(JSContext* cx, IdValuePair* properties, size_t nprop
return nullptr; return nullptr;
Rooted<TaggedProto> tagged(cx, TaggedProto(proto)); Rooted<TaggedProto> tagged(cx, TaggedProto(proto));
RootedObjectGroup group(cx, ObjectGroupCompartment::makeGroup(cx, &PlainObject::class_, RootedObjectGroup group(cx, ObjectGroupRealm::makeGroup(cx, &PlainObject::class_,
tagged)); tagged));
if (!group) if (!group)
return nullptr; return nullptr;
@ -1234,17 +1249,17 @@ ObjectGroup::newPlainObject(JSContext* cx, IdValuePair* properties, size_t nprop
AddTypePropertyId(cx, group, nullptr, IdToTypeId(ids[i]), types[i]); AddTypePropertyId(cx, group, nullptr, IdToTypeId(ids[i]), types[i]);
} }
ObjectGroupCompartment::PlainObjectKey key; ObjectGroupRealm::PlainObjectKey key;
key.properties = ids; key.properties = ids;
key.nproperties = nproperties; key.nproperties = nproperties;
MOZ_ASSERT(ObjectGroupCompartment::PlainObjectKey::match(key, lookup)); MOZ_ASSERT(ObjectGroupRealm::PlainObjectKey::match(key, lookup));
ObjectGroupCompartment::PlainObjectEntry entry; ObjectGroupRealm::PlainObjectEntry entry;
entry.group.set(group); entry.group.set(group);
entry.shape.set(obj->lastProperty()); entry.shape.set(obj->lastProperty());
entry.types = types; entry.types = types;
ObjectGroupCompartment::PlainObjectTable::AddPtr np = table->lookupForAdd(lookup); ObjectGroupRealm::PlainObjectTable::AddPtr np = table->lookupForAdd(lookup);
if (!table->add(np, key, entry)) { if (!table->add(np, key, entry)) {
ReportOutOfMemory(cx); ReportOutOfMemory(cx);
return nullptr; return nullptr;
@ -1323,10 +1338,10 @@ ObjectGroup::newPlainObject(JSContext* cx, IdValuePair* properties, size_t nprop
} }
///////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////
// ObjectGroupCompartment AllocationSiteTable // ObjectGroupRealm AllocationSiteTable
///////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////
struct ObjectGroupCompartment::AllocationSiteKey : public DefaultHasher<AllocationSiteKey> { struct ObjectGroupRealm::AllocationSiteKey : public DefaultHasher<AllocationSiteKey> {
ReadBarrieredScript script; ReadBarrieredScript script;
uint32_t offset : 24; uint32_t offset : 24;
@ -1394,7 +1409,7 @@ struct ObjectGroupCompartment::AllocationSiteKey : public DefaultHasher<Allocati
} }
}; };
class ObjectGroupCompartment::AllocationSiteTable class ObjectGroupRealm::AllocationSiteTable
: public JS::WeakCache<js::GCHashMap<AllocationSiteKey, ReadBarrieredObjectGroup, : public JS::WeakCache<js::GCHashMap<AllocationSiteKey, ReadBarrieredObjectGroup,
AllocationSiteKey, SystemAllocPolicy>> AllocationSiteKey, SystemAllocPolicy>>
{ {
@ -1412,20 +1427,21 @@ ObjectGroup::allocationSiteGroup(JSContext* cx, JSScript* scriptArg, jsbytecode*
{ {
MOZ_ASSERT(!useSingletonForAllocationSite(scriptArg, pc, kind)); MOZ_ASSERT(!useSingletonForAllocationSite(scriptArg, pc, kind));
MOZ_ASSERT_IF(protoArg, kind == JSProto_Array); MOZ_ASSERT_IF(protoArg, kind == JSProto_Array);
MOZ_ASSERT(cx->realm() == scriptArg->realm());
uint32_t offset = scriptArg->pcToOffset(pc); uint32_t offset = scriptArg->pcToOffset(pc);
if (offset >= ObjectGroupCompartment::AllocationSiteKey::OFFSET_LIMIT) { if (offset >= ObjectGroupRealm::AllocationSiteKey::OFFSET_LIMIT) {
if (protoArg) if (protoArg)
return defaultNewGroup(cx, GetClassForProtoKey(kind), TaggedProto(protoArg)); return defaultNewGroup(cx, GetClassForProtoKey(kind), TaggedProto(protoArg));
return defaultNewGroup(cx, kind); return defaultNewGroup(cx, kind);
} }
ObjectGroupCompartment::AllocationSiteTable*& table = ObjectGroupRealm& realm = ObjectGroupRealm::getForNewObject(cx);
cx->compartment()->objectGroups.allocationSiteTable; ObjectGroupRealm::AllocationSiteTable*& table = realm.allocationSiteTable;
if (!table) { if (!table) {
table = cx->new_<ObjectGroupCompartment::AllocationSiteTable>(cx->zone()); table = cx->new_<ObjectGroupRealm::AllocationSiteTable>(cx->zone());
if (!table || !table->init()) { if (!table || !table->init()) {
ReportOutOfMemory(cx); ReportOutOfMemory(cx);
js_delete(table); js_delete(table);
@ -1442,18 +1458,18 @@ ObjectGroup::allocationSiteGroup(JSContext* cx, JSScript* scriptArg, jsbytecode*
return nullptr; return nullptr;
} }
Rooted<ObjectGroupCompartment::AllocationSiteKey> key(cx, Rooted<ObjectGroupRealm::AllocationSiteKey> key(cx,
ObjectGroupCompartment::AllocationSiteKey(script, offset, kind, proto)); ObjectGroupRealm::AllocationSiteKey(script, offset, kind, proto));
ObjectGroupCompartment::AllocationSiteTable::AddPtr p = table->lookupForAdd(key); ObjectGroupRealm::AllocationSiteTable::AddPtr p = table->lookupForAdd(key);
if (p) if (p)
return p->value(); return p->value();
AutoEnterAnalysis enter(cx); AutoEnterAnalysis enter(cx);
Rooted<TaggedProto> tagged(cx, TaggedProto(proto)); Rooted<TaggedProto> tagged(cx, TaggedProto(proto));
ObjectGroup* res = ObjectGroupCompartment::makeGroup(cx, GetClassForProtoKey(kind), tagged, ObjectGroup* res = ObjectGroupRealm::makeGroup(cx, GetClassForProtoKey(kind), tagged,
OBJECT_FLAG_FROM_ALLOCATION_SITE); OBJECT_FLAG_FROM_ALLOCATION_SITE);
if (!res) if (!res)
return nullptr; return nullptr;
@ -1480,9 +1496,11 @@ ObjectGroup::allocationSiteGroup(JSContext* cx, JSScript* scriptArg, jsbytecode*
} }
void void
ObjectGroupCompartment::replaceAllocationSiteGroup(JSScript* script, jsbytecode* pc, ObjectGroupRealm::replaceAllocationSiteGroup(JSScript* script, jsbytecode* pc,
JSProtoKey kind, ObjectGroup* group) JSProtoKey kind, ObjectGroup* group)
{ {
MOZ_ASSERT(script->realm() == group->realm());
AllocationSiteKey key(script, script->pcToOffset(pc), kind, group->proto().toObjectOrNull()); AllocationSiteKey key(script, script->pcToOffset(pc), kind, group->proto().toObjectOrNull());
AllocationSiteTable::Ptr p = allocationSiteTable->lookup(key); AllocationSiteTable::Ptr p = allocationSiteTable->lookup(key);
@ -1590,13 +1608,13 @@ ObjectGroup::findAllocationSite(JSContext* cx, ObjectGroup* group,
*script = nullptr; *script = nullptr;
*offset = 0; *offset = 0;
const ObjectGroupCompartment::AllocationSiteTable* table = ObjectGroupRealm& realm = ObjectGroupRealm::get(group);
cx->compartment()->objectGroups.allocationSiteTable; const ObjectGroupRealm::AllocationSiteTable* table = realm.allocationSiteTable;
if (!table) if (!table)
return false; return false;
for (ObjectGroupCompartment::AllocationSiteTable::Range r = table->all(); for (ObjectGroupRealm::AllocationSiteTable::Range r = table->all();
!r.empty(); !r.empty();
r.popFront()) r.popFront())
{ {
@ -1611,10 +1629,10 @@ ObjectGroup::findAllocationSite(JSContext* cx, ObjectGroup* group,
} }
///////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////
// ObjectGroupCompartment // ObjectGroupRealm
///////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////
ObjectGroupCompartment::~ObjectGroupCompartment() ObjectGroupRealm::~ObjectGroupRealm()
{ {
js_delete(defaultNewTable); js_delete(defaultNewTable);
js_delete(lazyTable); js_delete(lazyTable);
@ -1625,7 +1643,7 @@ ObjectGroupCompartment::~ObjectGroupCompartment()
} }
void void
ObjectGroupCompartment::removeDefaultNewGroup(const Class* clasp, TaggedProto proto, ObjectGroupRealm::removeDefaultNewGroup(const Class* clasp, TaggedProto proto,
JSObject* associated) JSObject* associated)
{ {
auto p = defaultNewTable->lookup(NewEntry::Lookup(clasp, proto, associated)); auto p = defaultNewTable->lookup(NewEntry::Lookup(clasp, proto, associated));
@ -1636,7 +1654,7 @@ ObjectGroupCompartment::removeDefaultNewGroup(const Class* clasp, TaggedProto pr
} }
void void
ObjectGroupCompartment::replaceDefaultNewGroup(const Class* clasp, TaggedProto proto, ObjectGroupRealm::replaceDefaultNewGroup(const Class* clasp, TaggedProto proto,
JSObject* associated, ObjectGroup* group) JSObject* associated, ObjectGroup* group)
{ {
NewEntry::Lookup lookup(clasp, proto, associated); NewEntry::Lookup lookup(clasp, proto, associated);
@ -1654,9 +1672,9 @@ ObjectGroupCompartment::replaceDefaultNewGroup(const Class* clasp, TaggedProto p
/* static */ /* static */
ObjectGroup* ObjectGroup*
ObjectGroupCompartment::makeGroup(JSContext* cx, const Class* clasp, ObjectGroupRealm::makeGroup(JSContext* cx, const Class* clasp,
Handle<TaggedProto> proto, Handle<TaggedProto> proto,
ObjectGroupFlags initialFlags /* = 0 */) ObjectGroupFlags initialFlags /* = 0 */)
{ {
MOZ_ASSERT_IF(proto.isObject(), cx->isInsideCurrentCompartment(proto.toObject())); MOZ_ASSERT_IF(proto.isObject(), cx->isInsideCurrentCompartment(proto.toObject()));
@ -1670,9 +1688,9 @@ ObjectGroupCompartment::makeGroup(JSContext* cx, const Class* clasp,
/* static */ /* static */
ObjectGroup* ObjectGroup*
ObjectGroupCompartment::getStringSplitStringGroup(JSContext* cx) ObjectGroupRealm::getStringSplitStringGroup(JSContext* cx)
{ {
ObjectGroupCompartment& groups = cx->compartment()->objectGroups; ObjectGroupRealm& groups = ObjectGroupRealm::getForNewObject(cx);
ObjectGroup* group = groups.stringSplitStringGroup.get(); ObjectGroup* group = groups.stringSplitStringGroup.get();
if (group) { if (group) {
@ -1698,11 +1716,11 @@ ObjectGroupCompartment::getStringSplitStringGroup(JSContext* cx)
} }
void void
ObjectGroupCompartment::addSizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf, ObjectGroupRealm::addSizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf,
size_t* allocationSiteTables, size_t* allocationSiteTables,
size_t* arrayObjectGroupTables, size_t* arrayObjectGroupTables,
size_t* plainObjectGroupTables, size_t* plainObjectGroupTables,
size_t* compartmentTables) size_t* realmTables)
{ {
if (allocationSiteTable) if (allocationSiteTable)
*allocationSiteTables += allocationSiteTable->sizeOfIncludingThis(mallocSizeOf); *allocationSiteTables += allocationSiteTable->sizeOfIncludingThis(mallocSizeOf);
@ -1726,14 +1744,14 @@ ObjectGroupCompartment::addSizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeO
} }
if (defaultNewTable) if (defaultNewTable)
*compartmentTables += defaultNewTable->sizeOfIncludingThis(mallocSizeOf); *realmTables += defaultNewTable->sizeOfIncludingThis(mallocSizeOf);
if (lazyTable) if (lazyTable)
*compartmentTables += lazyTable->sizeOfIncludingThis(mallocSizeOf); *realmTables += lazyTable->sizeOfIncludingThis(mallocSizeOf);
} }
void void
ObjectGroupCompartment::clearTables() ObjectGroupRealm::clearTables()
{ {
if (allocationSiteTable && allocationSiteTable->initialized()) if (allocationSiteTable && allocationSiteTable->initialized())
allocationSiteTable->clear(); allocationSiteTable->clear();
@ -1756,8 +1774,8 @@ ObjectGroupCompartment::clearTables()
} }
/* static */ bool /* static */ bool
ObjectGroupCompartment::PlainObjectTableSweepPolicy::needsSweep(PlainObjectKey* key, ObjectGroupRealm::PlainObjectTableSweepPolicy::needsSweep(PlainObjectKey* key,
PlainObjectEntry* entry) PlainObjectEntry* entry)
{ {
if (!(JS::GCPolicy<PlainObjectKey>::needsSweep(key) || entry->needsSweep(key->nproperties))) if (!(JS::GCPolicy<PlainObjectKey>::needsSweep(key) || entry->needsSweep(key->nproperties)))
return false; return false;
@ -1767,7 +1785,7 @@ ObjectGroupCompartment::PlainObjectTableSweepPolicy::needsSweep(PlainObjectKey*
} }
void void
ObjectGroupCompartment::sweep() ObjectGroupRealm::sweep()
{ {
/* /*
* Iterate through the array/object group tables and remove all entries * Iterate through the array/object group tables and remove all entries
@ -1786,7 +1804,7 @@ ObjectGroupCompartment::sweep()
} }
void void
ObjectGroupCompartment::fixupNewTableAfterMovingGC(NewTable* table) ObjectGroupRealm::fixupNewTableAfterMovingGC(NewTable* table)
{ {
/* /*
* Each entry's hash depends on the object's prototype and we can't tell * Each entry's hash depends on the object's prototype and we can't tell
@ -1817,7 +1835,7 @@ ObjectGroupCompartment::fixupNewTableAfterMovingGC(NewTable* table)
#ifdef JSGC_HASH_TABLE_CHECKS #ifdef JSGC_HASH_TABLE_CHECKS
void void
ObjectGroupCompartment::checkNewTableAfterMovingGC(NewTable* table) ObjectGroupRealm::checkNewTableAfterMovingGC(NewTable* table)
{ {
/* /*
* Assert that nothing points into the nursery or needs to be relocated, and * Assert that nothing points into the nursery or needs to be relocated, and

Просмотреть файл

@ -29,6 +29,7 @@ class HeapTypeSet;
class AutoClearTypeInferenceStateOnOOM; class AutoClearTypeInferenceStateOnOOM;
class AutoSweepObjectGroup; class AutoSweepObjectGroup;
class CompilerConstraintList; class CompilerConstraintList;
class ObjectGroupRealm;
namespace gc { namespace gc {
void MergeCompartments(JSCompartment* source, JSCompartment* target); void MergeCompartments(JSCompartment* source, JSCompartment* target);
@ -527,21 +528,22 @@ class ObjectGroup : public gc::TenuredCell
static bool useSingletonForAllocationSite(JSScript* script, jsbytecode* pc, static bool useSingletonForAllocationSite(JSScript* script, jsbytecode* pc,
const Class* clasp); const Class* clasp);
// Static accessors for ObjectGroupCompartment NewTable. // Static accessors for ObjectGroupRealm NewTable.
static ObjectGroup* defaultNewGroup(JSContext* cx, const Class* clasp, static ObjectGroup* defaultNewGroup(JSContext* cx, const Class* clasp,
TaggedProto proto, TaggedProto proto,
JSObject* associated = nullptr); JSObject* associated = nullptr);
static ObjectGroup* lazySingletonGroup(JSContext* cx, const Class* clasp, static ObjectGroup* lazySingletonGroup(JSContext* cx, ObjectGroupRealm& realm,
TaggedProto proto); const Class* clasp, TaggedProto proto);
static void setDefaultNewGroupUnknown(JSContext* cx, const js::Class* clasp, JS::HandleObject obj); static void setDefaultNewGroupUnknown(JSContext* cx, ObjectGroupRealm& realm,
const js::Class* clasp, JS::HandleObject obj);
#ifdef DEBUG #ifdef DEBUG
static bool hasDefaultNewGroup(JSObject* proto, const Class* clasp, ObjectGroup* group); static bool hasDefaultNewGroup(JSObject* proto, const Class* clasp, ObjectGroup* group);
#endif #endif
// Static accessors for ObjectGroupCompartment ArrayObjectTable and PlainObjectTable. // Static accessors for ObjectGroupRealm ArrayObjectTable and PlainObjectTable.
enum class NewArrayKind { enum class NewArrayKind {
Normal, // Specialize array group based on its element type. Normal, // Specialize array group based on its element type.
@ -561,7 +563,7 @@ class ObjectGroup : public gc::TenuredCell
IdValuePair* properties, size_t nproperties, IdValuePair* properties, size_t nproperties,
NewObjectKind newKind); NewObjectKind newKind);
// Static accessors for ObjectGroupCompartment AllocationSiteTable. // Static accessors for ObjectGroupRealm AllocationSiteTable.
// Get a non-singleton group to use for objects created at the specified // Get a non-singleton group to use for objects created at the specified
// allocation site. // allocation site.
@ -589,8 +591,8 @@ class ObjectGroup : public gc::TenuredCell
static ObjectGroup* defaultNewGroup(JSContext* cx, JSProtoKey key); static ObjectGroup* defaultNewGroup(JSContext* cx, JSProtoKey key);
}; };
// Structure used to manage the groups in a compartment. // Structure used to manage the groups in a realm.
class ObjectGroupCompartment class ObjectGroupRealm
{ {
private: private:
class NewTable; class NewTable;
@ -615,7 +617,7 @@ class ObjectGroupCompartment
class AllocationSiteTable; class AllocationSiteTable;
private: private:
// Set of default 'new' or lazy groups in the compartment. // Set of default 'new' or lazy groups in the realm.
NewTable* defaultNewTable = nullptr; NewTable* defaultNewTable = nullptr;
NewTable* lazyTable = nullptr; NewTable* lazyTable = nullptr;
@ -655,7 +657,7 @@ class ObjectGroupCompartment
// Table for referencing types of objects keyed to an allocation site. // Table for referencing types of objects keyed to an allocation site.
AllocationSiteTable* allocationSiteTable = nullptr; AllocationSiteTable* allocationSiteTable = nullptr;
// A single per-compartment ObjectGroup for all calls to StringSplitString. // A single per-realm ObjectGroup for all calls to StringSplitString.
// StringSplitString is always called from self-hosted code, and conceptually // StringSplitString is always called from self-hosted code, and conceptually
// the return object for a string.split(string) operation should have a // the return object for a string.split(string) operation should have a
// unified type. Having a global group for this also allows us to remove // unified type. Having a global group for this also allows us to remove
@ -663,6 +665,10 @@ class ObjectGroupCompartment
// on the basis of call-site pc. // on the basis of call-site pc.
ReadBarrieredObjectGroup stringSplitStringGroup = {}; ReadBarrieredObjectGroup stringSplitStringGroup = {};
public:
// All unboxed layouts in the realm.
mozilla::LinkedList<js::UnboxedLayout> unboxedLayouts;
// END OF PROPERTIES // END OF PROPERTIES
private: private:
@ -673,8 +679,14 @@ class ObjectGroupCompartment
public: public:
struct NewEntry; struct NewEntry;
ObjectGroupCompartment() = default; ObjectGroupRealm() = default;
~ObjectGroupCompartment(); ~ObjectGroupRealm();
ObjectGroupRealm(ObjectGroupRealm&) = delete;
void operator=(ObjectGroupRealm&) = delete;
static ObjectGroupRealm& get(ObjectGroup* group);
static ObjectGroupRealm& getForNewObject(JSContext* cx);
void replaceAllocationSiteGroup(JSScript* script, jsbytecode* pc, void replaceAllocationSiteGroup(JSScript* script, jsbytecode* pc,
JSProtoKey kind, ObjectGroup* group); JSProtoKey kind, ObjectGroup* group);
@ -693,7 +705,7 @@ class ObjectGroupCompartment
size_t* allocationSiteTables, size_t* allocationSiteTables,
size_t* arrayGroupTables, size_t* arrayGroupTables,
size_t* plainObjectGroupTables, size_t* plainObjectGroupTables,
size_t* compartmentTables); size_t* realmTables);
void clearTables(); void clearTables();

Просмотреть файл

@ -64,8 +64,9 @@ ProxyObject::New(JSContext* cx, const BaseProxyHandler* handler, HandleValue pri
* ways. * ways.
*/ */
if (proto.isObject() && !options.singleton() && !clasp->isDOMClass()) { if (proto.isObject() && !options.singleton() && !clasp->isDOMClass()) {
ObjectGroupRealm& realm = ObjectGroupRealm::getForNewObject(cx);
RootedObject protoObj(cx, proto.toObject()); RootedObject protoObj(cx, proto.toObject());
if (!JSObject::setNewGroupUnknown(cx, clasp, protoObj)) if (!JSObject::setNewGroupUnknown(cx, realm, clasp, protoObj))
return nullptr; return nullptr;
} }

Просмотреть файл

@ -1208,16 +1208,16 @@ RegExpShared::sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf)
return n; return n;
} }
/* RegExpCompartment */ /* RegExpRealm */
RegExpCompartment::RegExpCompartment() RegExpRealm::RegExpRealm()
: matchResultTemplateObject_(nullptr), : matchResultTemplateObject_(nullptr),
optimizableRegExpPrototypeShape_(nullptr), optimizableRegExpPrototypeShape_(nullptr),
optimizableRegExpInstanceShape_(nullptr) optimizableRegExpInstanceShape_(nullptr)
{} {}
ArrayObject* ArrayObject*
RegExpCompartment::createMatchResultTemplateObject(JSContext* cx) RegExpRealm::createMatchResultTemplateObject(JSContext* cx)
{ {
MOZ_ASSERT(!matchResultTemplateObject_); MOZ_ASSERT(!matchResultTemplateObject_);
@ -1229,7 +1229,7 @@ RegExpCompartment::createMatchResultTemplateObject(JSContext* cx)
// Create a new group for the template. // Create a new group for the template.
Rooted<TaggedProto> proto(cx, templateObject->taggedProto()); Rooted<TaggedProto> proto(cx, templateObject->taggedProto());
ObjectGroup* group = ObjectGroupCompartment::makeGroup(cx, templateObject->getClass(), proto); ObjectGroup* group = ObjectGroupRealm::makeGroup(cx, templateObject->getClass(), proto);
if (!group) if (!group)
return matchResultTemplateObject_; // = nullptr return matchResultTemplateObject_; // = nullptr
templateObject->setGroup(group); templateObject->setGroup(group);
@ -1274,7 +1274,7 @@ RegExpZone::init()
} }
void void
RegExpCompartment::sweep() RegExpRealm::sweep()
{ {
if (matchResultTemplateObject_ && if (matchResultTemplateObject_ &&
IsAboutToBeFinalized(&matchResultTemplateObject_)) IsAboutToBeFinalized(&matchResultTemplateObject_))

Просмотреть файл

@ -28,7 +28,7 @@
namespace js { namespace js {
class ArrayObject; class ArrayObject;
class RegExpCompartment; class RegExpRealm;
class RegExpShared; class RegExpShared;
class RegExpStatics; class RegExpStatics;
class VectorMatchPairs; class VectorMatchPairs;
@ -288,7 +288,7 @@ class RegExpZone
size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf); size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf);
}; };
class RegExpCompartment class RegExpRealm
{ {
/* /*
* This is the template object where the result of re.exec() is based on, * This is the template object where the result of re.exec() is based on,
@ -321,7 +321,7 @@ class RegExpCompartment
ArrayObject* createMatchResultTemplateObject(JSContext* cx); ArrayObject* createMatchResultTemplateObject(JSContext* cx);
public: public:
explicit RegExpCompartment(); explicit RegExpRealm();
void sweep(); void sweep();
@ -346,10 +346,10 @@ class RegExpCompartment
} }
static size_t offsetOfOptimizableRegExpPrototypeShape() { static size_t offsetOfOptimizableRegExpPrototypeShape() {
return offsetof(RegExpCompartment, optimizableRegExpPrototypeShape_); return offsetof(RegExpRealm, optimizableRegExpPrototypeShape_);
} }
static size_t offsetOfOptimizableRegExpInstanceShape() { static size_t offsetOfOptimizableRegExpInstanceShape() {
return offsetof(RegExpCompartment, optimizableRegExpInstanceShape_); return offsetof(RegExpRealm, optimizableRegExpInstanceShape_);
} }
}; };

Просмотреть файл

@ -225,7 +225,7 @@ JSRuntime::init(JSContext* cx, uint32_t maxbytes, uint32_t maxNurseryBytes)
return false; return false;
gc.atomsZone = atomsZone.get(); gc.atomsZone = atomsZone.get();
if (!atomsZone->compartments().append(atomsRealm.get())) if (!atomsZone->compartments().append(JS::GetCompartmentForRealm(atomsRealm.get())))
return false; return false;
atomsRealm->setIsSystem(true); atomsRealm->setIsSystem(true);

Просмотреть файл

@ -101,21 +101,21 @@ LiveSavedFrameCache::find(JSContext* cx, FramePtr& framePtr, const jsbytecode* p
MOZ_ASSERT(initialized()); MOZ_ASSERT(initialized());
MOZ_ASSERT(framePtr.hasCachedSavedFrame()); MOZ_ASSERT(framePtr.hasCachedSavedFrame());
// If we flushed the cache due to a compartment mismatch, then we shouldn't // If we flushed the cache due to a realm mismatch, then we shouldn't
// expect to find any frames in the cache. // expect to find any frames in the cache.
if (frames->empty()) { if (frames->empty()) {
frame.set(nullptr); frame.set(nullptr);
return; return;
} }
// All our SavedFrames should be in the same compartment. If the last // All our SavedFrames should be in the same realm. If the last
// entry's SavedFrame's compartment doesn't match cx's, flush the cache. // entry's SavedFrame's realm doesn't match cx's, flush the cache.
if (frames->back().savedFrame->compartment() != cx->compartment()) { if (frames->back().savedFrame->realm() != cx->realm()) {
#ifdef DEBUG #ifdef DEBUG
// Check that they are, indeed, all in the same compartment. // Check that they are, indeed, all in the same realm.
auto compartment = frames->back().savedFrame->compartment(); auto compartment = frames->back().savedFrame->realm();
for (const auto& f : (*frames)) for (const auto& f : (*frames))
MOZ_ASSERT(compartment == f.savedFrame->compartment()); MOZ_ASSERT(compartment == f.savedFrame->realm());
#endif #endif
frames->clear(); frames->clear();
frame.set(nullptr); frame.set(nullptr);
@ -124,7 +124,7 @@ LiveSavedFrameCache::find(JSContext* cx, FramePtr& framePtr, const jsbytecode* p
Key key(framePtr); Key key(framePtr);
while (key != frames->back().key) { while (key != frames->back().key) {
MOZ_ASSERT(frames->back().savedFrame->compartment() == cx->compartment()); MOZ_ASSERT(frames->back().savedFrame->realm() == cx->realm());
// We know that the cache does contain an entry for frameIter's frame, // We know that the cache does contain an entry for frameIter's frame,
// since its bit is set. That entry must be below this one in the stack, // since its bit is set. That entry must be below this one in the stack,
@ -559,7 +559,7 @@ SavedFrame::create(JSContext* cx)
// Ensure that we don't try to capture the stack again in the // Ensure that we don't try to capture the stack again in the
// `SavedStacksMetadataBuilder` for this new SavedFrame object, and // `SavedStacksMetadataBuilder` for this new SavedFrame object, and
// accidentally cause O(n^2) behavior. // accidentally cause O(n^2) behavior.
SavedStacks::AutoReentrancyGuard guard(cx->compartment()->savedStacks()); SavedStacks::AutoReentrancyGuard guard(cx->realm()->savedStacks());
RootedNativeObject proto(cx, GlobalObject::getOrCreateSavedFramePrototype(cx, global)); RootedNativeObject proto(cx, GlobalObject::getOrCreateSavedFramePrototype(cx, global));
if (!proto) if (!proto)
@ -829,7 +829,7 @@ GetSavedFrameSource(JSContext* cx, HandleObject savedFrame, MutableHandleString
{ {
js::AssertHeapIsIdle(); js::AssertHeapIsIdle();
CHECK_REQUEST(cx); CHECK_REQUEST(cx);
MOZ_RELEASE_ASSERT(cx->compartment()); MOZ_RELEASE_ASSERT(cx->realm());
{ {
AutoMaybeEnterFrameRealm ar(cx, savedFrame); AutoMaybeEnterFrameRealm ar(cx, savedFrame);
@ -852,7 +852,7 @@ GetSavedFrameLine(JSContext* cx, HandleObject savedFrame, uint32_t* linep,
{ {
js::AssertHeapIsIdle(); js::AssertHeapIsIdle();
CHECK_REQUEST(cx); CHECK_REQUEST(cx);
MOZ_RELEASE_ASSERT(cx->compartment()); MOZ_RELEASE_ASSERT(cx->realm());
MOZ_ASSERT(linep); MOZ_ASSERT(linep);
AutoMaybeEnterFrameRealm ar(cx, savedFrame); AutoMaybeEnterFrameRealm ar(cx, savedFrame);
@ -872,7 +872,7 @@ GetSavedFrameColumn(JSContext* cx, HandleObject savedFrame, uint32_t* columnp,
{ {
js::AssertHeapIsIdle(); js::AssertHeapIsIdle();
CHECK_REQUEST(cx); CHECK_REQUEST(cx);
MOZ_RELEASE_ASSERT(cx->compartment()); MOZ_RELEASE_ASSERT(cx->realm());
MOZ_ASSERT(columnp); MOZ_ASSERT(columnp);
AutoMaybeEnterFrameRealm ar(cx, savedFrame); AutoMaybeEnterFrameRealm ar(cx, savedFrame);
@ -892,7 +892,7 @@ GetSavedFrameFunctionDisplayName(JSContext* cx, HandleObject savedFrame, Mutable
{ {
js::AssertHeapIsIdle(); js::AssertHeapIsIdle();
CHECK_REQUEST(cx); CHECK_REQUEST(cx);
MOZ_RELEASE_ASSERT(cx->compartment()); MOZ_RELEASE_ASSERT(cx->realm());
{ {
AutoMaybeEnterFrameRealm ar(cx, savedFrame); AutoMaybeEnterFrameRealm ar(cx, savedFrame);
@ -915,7 +915,7 @@ GetSavedFrameAsyncCause(JSContext* cx, HandleObject savedFrame, MutableHandleStr
{ {
js::AssertHeapIsIdle(); js::AssertHeapIsIdle();
CHECK_REQUEST(cx); CHECK_REQUEST(cx);
MOZ_RELEASE_ASSERT(cx->compartment()); MOZ_RELEASE_ASSERT(cx->realm());
{ {
AutoMaybeEnterFrameRealm ar(cx, savedFrame); AutoMaybeEnterFrameRealm ar(cx, savedFrame);
@ -946,7 +946,7 @@ GetSavedFrameAsyncParent(JSContext* cx, HandleObject savedFrame, MutableHandleOb
{ {
js::AssertHeapIsIdle(); js::AssertHeapIsIdle();
CHECK_REQUEST(cx); CHECK_REQUEST(cx);
MOZ_RELEASE_ASSERT(cx->compartment()); MOZ_RELEASE_ASSERT(cx->realm());
AutoMaybeEnterFrameRealm ar(cx, savedFrame); AutoMaybeEnterFrameRealm ar(cx, savedFrame);
bool skippedAsync; bool skippedAsync;
@ -979,7 +979,7 @@ GetSavedFrameParent(JSContext* cx, HandleObject savedFrame, MutableHandleObject
{ {
js::AssertHeapIsIdle(); js::AssertHeapIsIdle();
CHECK_REQUEST(cx); CHECK_REQUEST(cx);
MOZ_RELEASE_ASSERT(cx->compartment()); MOZ_RELEASE_ASSERT(cx->realm());
AutoMaybeEnterFrameRealm ar(cx, savedFrame); AutoMaybeEnterFrameRealm ar(cx, savedFrame);
bool skippedAsync; bool skippedAsync;
@ -1085,7 +1085,7 @@ BuildStackString(JSContext* cx, HandleObject stack, MutableHandleString stringp,
{ {
js::AssertHeapIsIdle(); js::AssertHeapIsIdle();
CHECK_REQUEST(cx); CHECK_REQUEST(cx);
MOZ_RELEASE_ASSERT(cx->compartment()); MOZ_RELEASE_ASSERT(cx->realm());
js::StringBuffer sb(cx); js::StringBuffer sb(cx);
@ -1279,8 +1279,8 @@ SavedStacks::saveCurrentStack(JSContext* cx, MutableHandleSavedFrame frame,
JS::StackCapture&& capture /* = JS::StackCapture(JS::AllFrames()) */) JS::StackCapture&& capture /* = JS::StackCapture(JS::AllFrames()) */)
{ {
MOZ_ASSERT(initialized()); MOZ_ASSERT(initialized());
MOZ_RELEASE_ASSERT(cx->compartment()); MOZ_RELEASE_ASSERT(cx->realm());
assertSameCompartment(cx, this); MOZ_DIAGNOSTIC_ASSERT(&cx->realm()->savedStacks() == this);
if (creatingSavedFrame || if (creatingSavedFrame ||
cx->isExceptionPending() || cx->isExceptionPending() ||
@ -1301,8 +1301,8 @@ SavedStacks::copyAsyncStack(JSContext* cx, HandleObject asyncStack, HandleString
const Maybe<size_t>& maxFrameCount) const Maybe<size_t>& maxFrameCount)
{ {
MOZ_ASSERT(initialized()); MOZ_ASSERT(initialized());
MOZ_RELEASE_ASSERT(cx->compartment()); MOZ_RELEASE_ASSERT(cx->realm());
assertSameCompartment(cx, this); MOZ_DIAGNOSTIC_ASSERT(&cx->realm()->savedStacks() == this);
RootedAtom asyncCauseAtom(cx, AtomizeString(cx, asyncCause)); RootedAtom asyncCauseAtom(cx, AtomizeString(cx, asyncCause));
if (!asyncCauseAtom) if (!asyncCauseAtom)
@ -1475,7 +1475,7 @@ SavedStacks::insertFrames(JSContext* cx, MutableHandleSavedFrame frame,
Rooted<LocationValue> location(cx); Rooted<LocationValue> location(cx);
{ {
AutoRealmUnchecked ar(cx, iter.compartment()); AutoRealmUnchecked ar(cx, iter.compartment());
if (!cx->compartment()->savedStacks().getLocation(cx, iter, &location)) if (!cx->realm()->savedStacks().getLocation(cx, iter, &location))
return false; return false;
} }
@ -1618,12 +1618,12 @@ SavedStacks::adoptAsyncStack(JSContext* cx, MutableHandleSavedFrame asyncStack,
// Attach the asyncCause to the youngest frame. // Attach the asyncCause to the youngest frame.
stackChain[0]->asyncCause = asyncCause; stackChain[0]->asyncCause = asyncCause;
// If we walked the entire stack, and it's in cx's compartment, we don't // If we walked the entire stack, and it's in cx's realm, we don't
// need to rebuild the full chain again using the lookup objects - we can // need to rebuild the full chain again using the lookup objects - we can
// just use the existing chain. Only the asyncCause on the youngest frame // just use the existing chain. Only the asyncCause on the youngest frame
// needs to be changed. // needs to be changed.
if (currentSavedFrame == nullptr && if (currentSavedFrame == nullptr &&
asyncStack->compartment() == cx->compartment()) asyncStack->realm() == cx->realm())
{ {
SavedFrame::HandleLookup lookup = stackChain[0]; SavedFrame::HandleLookup lookup = stackChain[0];
lookup->parent = asyncStack->getParent(); lookup->parent = asyncStack->getParent();
@ -1748,7 +1748,8 @@ SavedStacks::getLocation(JSContext* cx, const FrameIter& iter,
// compartment. Otherwise, we would get dead cross-compartment scripts in // compartment. Otherwise, we would get dead cross-compartment scripts in
// the cache because our compartment's sweep method isn't called when their // the cache because our compartment's sweep method isn't called when their
// compartment gets collected. // compartment gets collected.
assertSameCompartment(cx, this, iter.compartment()); MOZ_DIAGNOSTIC_ASSERT(&cx->realm()->savedStacks() == this);
assertSameCompartment(cx, iter.compartment());
// When we have a |JSScript| for this frame, use a potentially memoized // When we have a |JSScript| for this frame, use a potentially memoized
// location from our PCLocationMap and copy it into |locationp|. When we do // location from our PCLocationMap and copy it into |locationp|. When we do
@ -1806,9 +1807,8 @@ SavedStacks::getLocation(JSContext* cx, const FrameIter& iter,
} }
void void
SavedStacks::chooseSamplingProbability(JSCompartment* compartment) SavedStacks::chooseSamplingProbability(Realm* realm)
{ {
Realm* realm = JS::GetRealmForCompartment(compartment);
GlobalObject* global = realm->maybeGlobal(); GlobalObject* global = realm->maybeGlobal();
if (!global) if (!global)
return; return;
@ -1850,7 +1850,7 @@ SavedStacks::MetadataBuilder::build(JSContext* cx, HandleObject target,
{ {
RootedObject obj(cx, target); RootedObject obj(cx, target);
SavedStacks& stacks = cx->compartment()->savedStacks(); SavedStacks& stacks = cx->realm()->savedStacks();
if (!stacks.bernoulli.trial()) if (!stacks.bernoulli.trial())
return nullptr; return nullptr;
@ -1867,18 +1867,6 @@ SavedStacks::MetadataBuilder::build(JSContext* cx, HandleObject target,
const SavedStacks::MetadataBuilder SavedStacks::metadataBuilder; const SavedStacks::MetadataBuilder SavedStacks::metadataBuilder;
#ifdef JS_CRASH_DIAGNOSTICS
void
CompartmentChecker::check(SavedStacks* stacks)
{
if (&compartment->savedStacks() != stacks) {
printf("*** Compartment SavedStacks mismatch: %p vs. %p\n",
(void*) &compartment->savedStacks(), stacks);
MOZ_CRASH();
}
}
#endif /* JS_CRASH_DIAGNOSTICS */
/* static */ ReconstructedSavedFramePrincipals ReconstructedSavedFramePrincipals::IsSystem; /* static */ ReconstructedSavedFramePrincipals ReconstructedSavedFramePrincipals::IsSystem;
/* static */ ReconstructedSavedFramePrincipals ReconstructedSavedFramePrincipals::IsNotSystem; /* static */ ReconstructedSavedFramePrincipals ReconstructedSavedFramePrincipals::IsNotSystem;
@ -2001,7 +1989,7 @@ ConstructSavedFrameStackSlow(JSContext* cx, JS::ubi::StackFrame& frame,
for (size_t i = stackChain->length(); i != 0; i--) { for (size_t i = stackChain->length(); i != 0; i--) {
SavedFrame::HandleLookup lookup = stackChain[i-1]; SavedFrame::HandleLookup lookup = stackChain[i-1];
lookup->parent = parentFrame; lookup->parent = parentFrame;
parentFrame = cx->compartment()->savedStacks().getOrCreateSavedFrame(cx, lookup); parentFrame = cx->realm()->savedStacks().getOrCreateSavedFrame(cx, lookup);
if (!parentFrame) if (!parentFrame)
return false; return false;
} }

Просмотреть файл

@ -174,7 +174,7 @@ class SavedStacks {
void trace(JSTracer* trc); void trace(JSTracer* trc);
uint32_t count(); uint32_t count();
void clear(); void clear();
void chooseSamplingProbability(JSCompartment*); void chooseSamplingProbability(JS::Realm* realm);
// Set the sampling random number generator's state to |state0| and // Set the sampling random number generator's state to |state0| and
// |state1|. One or the other must be non-zero. See the comments for // |state1|. One or the other must be non-zero. See the comments for

Просмотреть файл

@ -1764,7 +1764,7 @@ js::intrinsic_StringSplitString(JSContext* cx, unsigned argc, Value* vp)
RootedString string(cx, args[0].toString()); RootedString string(cx, args[0].toString());
RootedString sep(cx, args[1].toString()); RootedString sep(cx, args[1].toString());
RootedObjectGroup group(cx, ObjectGroupCompartment::getStringSplitStringGroup(cx)); RootedObjectGroup group(cx, ObjectGroupRealm::getStringSplitStringGroup(cx));
if (!group) if (!group)
return false; return false;
@ -1790,7 +1790,7 @@ intrinsic_StringSplitStringLimit(JSContext* cx, unsigned argc, Value* vp)
uint32_t limit = uint32_t(args[2].toNumber()); uint32_t limit = uint32_t(args[2].toNumber());
MOZ_ASSERT(limit > 0, "Zero limit case is already handled in self-hosted code."); MOZ_ASSERT(limit > 0, "Zero limit case is already handled in self-hosted code.");
RootedObjectGroup group(cx, ObjectGroupCompartment::getStringSplitStringGroup(cx)); RootedObjectGroup group(cx, ObjectGroupRealm::getStringSplitStringGroup(cx));
if (!group) if (!group)
return false; return false;
@ -2809,7 +2809,7 @@ JSRuntime::createSelfHostingGlobal(JSContext* cx)
&shgClassOps &shgClassOps
}; };
AutoRealmUnchecked ar(cx, realm); AutoRealmUnchecked ar(cx, compartment);
Rooted<GlobalObject*> shg(cx, GlobalObject::createInternal(cx, &shgClass)); Rooted<GlobalObject*> shg(cx, GlobalObject::createInternal(cx, &shgClass));
if (!shg) if (!shg)
return nullptr; return nullptr;

Просмотреть файл

@ -385,8 +385,8 @@ InterpreterFrame::trace(JSTracer* trc, Value* sp, jsbytecode* pc)
traceValues(trc, 0, nlivefixed); traceValues(trc, 0, nlivefixed);
} }
if (script->compartment()->debugEnvs) if (auto* debugEnvs = script->realm()->debugEnvs())
script->compartment()->debugEnvs->traceLiveFrame(trc, this); debugEnvs->traceLiveFrame(trc, this);
} }
void void

Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше