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;
}
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

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

@ -26,6 +26,7 @@ public:
// Accessible
virtual a11y::role NativeRole() const override;
virtual already_AddRefed<nsIPersistentProperties> NativeAttributes() override;
virtual TableAccessible* AsTable() override { return this; }
// 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.
*/
virtual bool IsProbablyLayoutTable() { return false; }
virtual bool IsProbablyLayoutTable();
/**
* Convert the table to an Accessible*.

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

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

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

@ -860,244 +860,6 @@ HTMLTableAccessible::Description(nsString& aDescription)
#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
////////////////////////////////////////////////////////////////////////////////

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

@ -156,7 +156,6 @@ public:
virtual void SelectRow(uint32_t aRowIdx) override;
virtual void UnselectCol(uint32_t aColIdx) override;
virtual void UnselectRow(uint32_t aRowIdx) override;
virtual bool IsProbablyLayoutTable() override;
virtual Accessible* AsAccessible() override { return this; }
// Accessible
@ -199,15 +198,6 @@ protected:
TableSelection aTarget,
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
nsString mLayoutHeuristic;
#endif

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

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

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

@ -213,21 +213,17 @@ OptionsPanel.prototype = {
"tools-not-supported-label");
let atleastOneToolNotSupported = false;
const toolbox = this.toolbox;
// Signal tool registering/unregistering globally (for the tools registered
// 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.
let onCheckboxClick = function(tool) {
let onCheckboxClick = function(telemetry, tool) {
// Set the kill switch pref boolean to true
Services.prefs.setBoolPref(tool.visibilityswitch, this.checked);
if (!tool.isWebExtension) {
gDevTools.emit(this.checked ? "tool-registered" : "tool-unregistered", tool.id);
// Record which tools were registered and unregistered.
this.telemetry.keyedScalarSet("devtools.tool.registered",
tool.id,
this.checked);
telemetry.keyedScalarSet("devtools.tool.registered", tool.id, this.checked);
}
};
@ -253,7 +249,8 @@ OptionsPanel.prototype = {
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(checkboxSpanLabel);
@ -287,7 +284,7 @@ OptionsPanel.prototype = {
}
// 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;
additionalToolsBox.appendChild(createToolCheckbox({

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

@ -36,15 +36,10 @@ pref("devtools.inspector.enabled", true);
pref("devtools.inspector.activeSidebar", "ruleview");
pref("devtools.inspector.remote", false);
#if defined(NIGHTLY_BUILD)
// Show the 3 pane onboarding tooltip in the inspector
pref("devtools.inspector.show-three-pane-tooltip", true);
// Enable the 3 pane mode in the inspector
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
pref("devtools.inspector.show_pseudo_elements", false);

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

@ -27,6 +27,7 @@ class Telemetry {
this.scalarSet = this.scalarSet.bind(this);
this.scalarAdd = this.scalarAdd.bind(this);
this.keyedScalarAdd = this.keyedScalarAdd.bind(this);
this.keyedScalarSet = this.keyedScalarSet.bind(this);
this.recordEvent = this.recordEvent.bind(this);
this.setEventRecordingEnabled = this.setEventRecordingEnabled.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.
*

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

@ -2039,7 +2039,7 @@ Element::UnbindFromTree(bool aDeep, bool aNullParent)
}
nsDOMCSSAttributeDeclaration*
Element::GetSMILOverrideStyle()
Element::SMILOverrideStyle()
{
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>
// 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
// display: none subtree, we keep it clean.
//

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

@ -361,7 +361,7 @@ public:
* Note: This method is analogous to the 'GetStyle' method in
* nsGenericHTMLElement and nsStyledElement.
*/
nsDOMCSSAttributeDeclaration* GetSMILOverrideStyle();
nsDOMCSSAttributeDeclaration* SMILOverrideStyle();
/**
* 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);
/**
* @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
* created.

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

@ -135,6 +135,10 @@ nsImageLoadingContent::Notify(imgIRequest* aRequest,
int32_t aType,
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) {
return OnImageIsAnimated(aRequest);
}
@ -144,14 +148,6 @@ nsImageLoadingContent::Notify(imgIRequest* aRequest,
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
// a local copy.
@ -629,12 +625,6 @@ nsImageLoadingContent::GetRequest(int32_t aRequestType,
return result.StealNSResult();
}
NS_IMETHODIMP_(bool)
nsImageLoadingContent::CurrentRequestHasSize()
{
return HaveSize(mCurrentRequest);
}
NS_IMETHODIMP_(void)
nsImageLoadingContent::FrameCreated(nsIFrame* aFrame)
{

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

@ -521,7 +521,8 @@ skip-if = toolkit == 'android' #bug 687032
[test_bug698381.html]
[test_bug698384.html]
[test_bug704063.html]
[test_bug704320.html]
[test_bug704320-1.html]
[test_bug704320-2.html]
[test_bug704320_policyset.html]
[test_bug704320_policyset2.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>
<!--
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</title>
<title>Test for Bug 704320-Part2</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"/>
@ -29,9 +30,7 @@ var generateURLArray = (function(from, to){
];
});
let testIframeUrls = [generateURLArray('http', 'http'),
generateURLArray('https', 'https'),
generateURLArray('http', 'https'),
let testIframeUrls = [generateURLArray('http', 'https'),
generateURLArray('https', 'http')];
SimpleTest.waitForExplicitFinish();
@ -39,13 +38,12 @@ let advance = function(testName) {
testsGenerator[testName].next();
};
let testNames = ['testframeone', 'testframetwo', 'testframethree',
'testframefour'];
let testNames = ['testframeone', 'testframetwo'];
let isTestFinished = 0;
function checkTestsCompleted() {
isTestFinished++;
if (isTestFinished == 4) {
if (isTestFinished == 2) {
SimpleTest.finish();
}
}
@ -82,15 +80,11 @@ for (i = 0; i < testIframeUrls.length; i++) {
</head>
<body onload="testsGenerator[testNames[0]].next();
testsGenerator[testNames[1]].next();
testsGenerator[testNames[2]].next();
testsGenerator[testNames[3]].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>
<iframe id="testframethree"></iframe>
<iframe id="testframefour"></iframe>
</body>

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

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

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

@ -13,6 +13,7 @@
#include "nsSize.h"
#include "nsDocument.h"
#include "nsIDocument.h"
#include "nsImageFrame.h"
#include "nsIScriptContext.h"
#include "nsIURL.h"
#include "nsIIOService.h"
@ -949,7 +950,7 @@ HTMLImageElement::InResponsiveMode()
}
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.
// Similarly for if there is no newly selected source.
@ -957,32 +958,58 @@ HTMLImageElement::SelectedSourceMatchesLast(nsIURI* aSelectedSource, double aSel
return false;
}
bool equal = false;
return NS_SUCCEEDED(mLastSelectedSource->Equals(aSelectedSource, &equal)) && equal &&
aSelectedDensity == mCurrentDensity;
return NS_SUCCEEDED(mLastSelectedSource->Equals(aSelectedSource, &equal)) && equal;
}
nsresult
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) {
// In responsive mode we generally want to re-run the full
// selection algorithm whenever starting a new load, per
// spec. This also causes us to re-resolve the URI as appropriate.
if (!UpdateResponsiveSource() && !aAlwaysLoad) {
// In responsive mode we generally want to re-run the full selection
// algorithm whenever starting a new load, per spec.
//
// 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;
}
} else if (mResponsiveSelector) {
currentDensity = mResponsiveSelector->GetSelectedImageDensity();
}
nsresult rv = NS_ERROR_FAILURE;
nsCOMPtr<nsIURI> selectedSource;
double currentDensity = 1.0; // default to 1.0 for the src attribute case
if (mResponsiveSelector) {
nsCOMPtr<nsIURI> url = mResponsiveSelector->GetSelectedImageURL();
nsCOMPtr<nsIPrincipal> triggeringPrincipal = mResponsiveSelector->GetSelectedImageTriggeringPrincipal();
selectedSource = url;
currentDensity = mResponsiveSelector->GetSelectedImageDensity();
if (!aAlwaysLoad && SelectedSourceMatchesLast(selectedSource, currentDensity)) {
if (!aAlwaysLoad && SelectedSourceMatchesLast(selectedSource)) {
UpdateDensityOnly();
return NS_OK;
}
if (url) {
@ -995,12 +1022,11 @@ HTMLImageElement::LoadSelectedImage(bool aForce, bool aNotify, bool aAlwaysLoad)
CancelImageRequests(aNotify);
rv = NS_OK;
} else {
nsIDocument* doc = GetOurOwnerDoc();
if (doc) {
StringToURI(src, doc, getter_AddRefs(selectedSource));
if (!aAlwaysLoad && SelectedSourceMatchesLast(selectedSource, currentDensity)) {
return NS_OK;
}
nsIDocument* doc = OwnerDoc();
StringToURI(src, doc, getter_AddRefs(selectedSource));
if (!aAlwaysLoad && SelectedSourceMatchesLast(selectedSource)) {
UpdateDensityOnly();
return NS_OK;
}
// If we have a srcset attribute or are in a <picture> element,

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

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

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

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

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

@ -107,17 +107,14 @@ nsresult
nsSMILCSSProperty::SetAnimValue(const nsSMILValue& aValue)
{
NS_ENSURE_TRUE(IsPropertyAnimatable(mPropID), NS_ERROR_FAILURE);
return mElement->GetSMILOverrideStyle()->SetSMILValue(mPropID, aValue);
return mElement->SMILOverrideStyle()->SetSMILValue(mPropID, aValue);
}
void
nsSMILCSSProperty::ClearAnimValue()
{
// Put empty string in override style for our property
nsDOMCSSAttributeDeclaration* overrideDecl = mElement->GetSMILOverrideStyle();
if (overrideDecl) {
overrideDecl->SetPropertyValue(mPropID, EmptyString(), nullptr);
}
mElement->SMILOverrideStyle()->SetPropertyValue(mPropID, EmptyString(), nullptr);
}
// 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
// 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.
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,

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

@ -29,6 +29,7 @@
#include "mozilla/Likely.h"
#include "mozilla/Maybe.h"
#include "mozilla/Move.h"
#include "mozilla/Tuple.h"
#include "mozilla/UniquePtr.h"
#include "mozilla/Unused.h"
#include "mozilla/Variant.h"
@ -174,6 +175,43 @@ public:
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
* surface one at a time by repeatedly calling a lambda that yields pixels.
@ -448,6 +486,50 @@ protected:
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
* WritePixelsToRow(). Those methods differ only in their behavior after a row
@ -558,6 +640,20 @@ public:
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
* 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>
NextPixel<PixelSize>
nsGIFDecoder2::YieldPixel(const uint8_t* aData,
size_t aLength,
size_t* aBytesReadOut)
Tuple<int32_t, Maybe<WriteState>>
nsGIFDecoder2::YieldPixels(const uint8_t* aData,
size_t aLength,
size_t* aBytesReadOut,
PixelSize* aPixelBlock,
int32_t aBlockSize)
{
MOZ_ASSERT(aData);
MOZ_ASSERT(aBytesReadOut);
@ -304,108 +306,119 @@ nsGIFDecoder2::YieldPixel(const uint8_t* aData,
// Advance to the next byte we should read.
const uint8_t* data = aData + *aBytesReadOut;
// If we don't have any decoded data to yield, try to read some input and
// produce some.
if (mGIFStruct.stackp == mGIFStruct.stack) {
while (mGIFStruct.bits < mGIFStruct.codesize && *aBytesReadOut < aLength) {
// Feed the next byte into the decoder's 32-bit input buffer.
mGIFStruct.datum += int32_t(*data) << mGIFStruct.bits;
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.
int32_t written = 0;
while (aBlockSize > written) {
// If we don't have any decoded data to yield, try to read some input and
// produce some.
if (mGIFStruct.stackp == mGIFStruct.stack) {
while (mGIFStruct.bits < mGIFStruct.codesize && *aBytesReadOut < aLength) {
// Feed the next byte into the decoder's 32-bit input buffer.
mGIFStruct.datum += int32_t(*data) << mGIFStruct.bits;
mGIFStruct.bits += 8;
data += 1;
*aBytesReadOut += 1;
}
mGIFStruct.firstchar = mGIFStruct.oldcode = code;
// 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);
if (mGIFStruct.bits < mGIFStruct.codesize) {
return MakeTuple(written, Some(WriteState::NEED_MORE_DATA));
}
*mGIFStruct.stackp++ = mGIFStruct.suffix[code];
code = mGIFStruct.prefix[code];
// Get the leading variable-length symbol from the data stream.
int code = mGIFStruct.datum & mGIFStruct.codemask;
mGIFStruct.datum >>= mGIFStruct.codesize;
mGIFStruct.bits -= mGIFStruct.codesize;
if (mGIFStruct.stackp >= mGIFStruct.stack + MAX_BITS) {
return AsVariant(WriteState::FAILURE); // Stack overflow; something's wrong.
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 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];
// 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;
}
if (MOZ_UNLIKELY(mGIFStruct.stackp <= mGIFStruct.stack)) {
MOZ_ASSERT_UNREACHABLE("No decoded data but we didn't return early?");
return MakeTuple(written, Some(WriteState::FAILURE));
}
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)) {
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));
return MakeTuple(written, Maybe<WriteState>());
}
/// 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;
auto result = mGIFStruct.images_decoded == 0
? mPipe.WritePixels<uint32_t>([&]{ return YieldPixel<uint32_t>(data, length, &bytesRead); })
: mPipe.WritePixels<uint8_t>([&]{ return YieldPixel<uint8_t>(data, length, &bytesRead); });
? mPipe.WritePixelBlocks<uint32_t>([&](uint32_t* aPixelBlock, int32_t aBlockSize) {
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)) {
MOZ_ASSERT_UNREACHABLE("Overread?");

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

@ -65,8 +65,12 @@ private:
ColormapIndexToPixel(uint8_t aIndex);
/// A generator function that performs LZW decompression and yields pixels.
template <typename PixelSize> NextPixel<PixelSize>
YieldPixel(const uint8_t* aData, size_t aLength, size_t* aBytesReadOut);
template <typename PixelSize> Tuple<int32_t, Maybe<WriteState>>
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
/// there's alpha, or because the frame rect doesn't cover the entire image.

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

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

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

@ -201,6 +201,22 @@ TEST_F(ImageSurfacePipeIntegration, SurfacePipe)
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.
{
uint32_t count = 0;
@ -281,6 +297,22 @@ TEST_F(ImageSurfacePipeIntegration, PalettedSurfacePipe)
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.
{
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)
{
WithSurfaceSink<Orient::NORMAL>([](Decoder* aDecoder, SurfaceSink* aSink) {

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

@ -150,7 +150,7 @@ class Builder {
// A rooted reference to our 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.assertBuilt(value_);

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

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

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

@ -112,9 +112,6 @@ struct GCPolicy<mozilla::Variant<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) {
Impl::trace(trc, v, name);
}

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

@ -176,7 +176,6 @@ namespace JS {
template <>
struct GCPolicy<jsid>
{
static jsid initial() { return JSID_VOID; }
static void trace(JSTracer* trc, jsid* idp, const char* 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) 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
/**
* 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() {
static_assert(sizeof(T) == sizeof(Heap<T>),
"Heap<T> must be binary compatible with T.");
init(GCPolicy<T>::initial());
init(SafelyInitialized<T>());
}
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); }
~Heap() {
post(ptr, GCPolicy<T>::initial());
post(ptr, SafelyInitialized<T>());
}
DECLARE_POINTER_CONSTREF_OPS(T);
@ -291,7 +325,7 @@ class MOZ_NON_MEMMOVABLE Heap : public js::HeapBase<T, Heap<T>>
private:
void init(const T& newPtr) {
ptr = newPtr;
post(GCPolicy<T>::initial(), ptr);
post(SafelyInitialized<T>(), ptr);
}
void set(const T& newPtr) {
@ -950,7 +984,7 @@ class MOZ_RAII Rooted : public js::RootedBase<T, Rooted<T>>
template <typename RootingContext>
explicit Rooted(const RootingContext& cx)
: ptr(GCPolicy<T>::initial())
: ptr(SafelyInitialized<T>())
{
registerWithRootLists(rootLists(cx));
}
@ -1219,16 +1253,16 @@ class PersistentRooted : public js::RootedBase<T, PersistentRooted<T>>,
public:
using ElementType = T;
PersistentRooted() : ptr(GCPolicy<T>::initial()) {}
PersistentRooted() : ptr(SafelyInitialized<T>()) {}
explicit PersistentRooted(RootingContext* cx)
: ptr(GCPolicy<T>::initial())
: ptr(SafelyInitialized<T>())
{
registerWithRootLists(cx);
}
explicit PersistentRooted(JSContext* cx)
: ptr(GCPolicy<T>::initial())
: ptr(SafelyInitialized<T>())
{
registerWithRootLists(RootingContext::get(cx));
}
@ -1248,7 +1282,7 @@ class PersistentRooted : public js::RootedBase<T, PersistentRooted<T>>,
}
explicit PersistentRooted(JSRuntime* rt)
: ptr(GCPolicy<T>::initial())
: ptr(SafelyInitialized<T>())
{
registerWithRootLists(rt);
}
@ -1280,7 +1314,7 @@ class PersistentRooted : public js::RootedBase<T, PersistentRooted<T>>,
}
void init(JSContext* cx) {
init(cx, GCPolicy<T>::initial());
init(cx, SafelyInitialized<T>());
}
template <typename U>
@ -1291,7 +1325,7 @@ class PersistentRooted : public js::RootedBase<T, PersistentRooted<T>>,
void reset() {
if (initialized()) {
set(GCPolicy<T>::initial());
set(SafelyInitialized<T>());
ListBase::remove();
}
}

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

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

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

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

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

@ -350,8 +350,8 @@ function InnerModuleInstantiation(module, stack, index)
}
// Step 3
assert(module.status === MODULE_STATUS_UNINSTANTIATED,
"Bad module status in ModuleDeclarationInstantiation");
if (module.status !== MODULE_STATUS_UNINSTANTIATED)
ThrowInternalError(JSMSG_BAD_MODULE_STATUS);
// Steps 4
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
* 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 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 */
JSObject* templateObject = cx->compartment()->regExps.getOrCreateMatchResultTemplateObject(cx);
JSObject* templateObject = cx->realm()->regExps.getOrCreateMatchResultTemplateObject(cx);
if (!templateObject)
return false;
@ -1568,7 +1568,7 @@ js::RegExpPrototypeOptimizableRaw(JSContext* cx, JSObject* proto)
NativeObject* nproto = static_cast<NativeObject*>(proto);
Shape* shape = cx->compartment()->regExps.getOptimizableRegExpPrototypeShape();
Shape* shape = cx->realm()->regExps.getOptimizableRegExpPrototypeShape();
if (shape == nproto->lastProperty())
return true;
@ -1635,7 +1635,7 @@ js::RegExpPrototypeOptimizableRaw(JSContext* cx, JSObject* proto)
if (!has)
return false;
cx->compartment()->regExps.setOptimizableRegExpPrototypeShape(nproto->lastProperty());
cx->realm()->regExps.setOptimizableRegExpPrototypeShape(nproto->lastProperty());
return true;
}
@ -1659,7 +1659,7 @@ js::RegExpInstanceOptimizableRaw(JSContext* cx, JSObject* obj, JSObject* proto)
RegExpObject* rx = &obj->as<RegExpObject>();
Shape* shape = cx->compartment()->regExps.getOptimizableRegExpInstanceShape();
Shape* shape = cx->realm()->regExps.getOptimizableRegExpInstanceShape();
if (shape == rx->lastProperty())
return true;
@ -1672,7 +1672,7 @@ js::RegExpInstanceOptimizableRaw(JSContext* cx, JSObject* obj, JSObject* proto)
if (!RegExpObject::isInitialShape(rx))
return false;
cx->compartment()->regExps.setOptimizableRegExpInstanceShape(rx->lastProperty());
cx->realm()->regExps.setOptimizableRegExpInstanceShape(rx->lastProperty());
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 */
JSObject* templateObject = cx->compartment()->regExps.getOrCreateMatchResultTemplateObject(cx);
JSObject* templateObject = cx->realm()->regExps.getOrCreateMatchResultTemplateObject(cx);
if (!templateObject)
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;
// 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;
}
@ -1279,7 +1279,7 @@ static bool
GetSavedFrameCount(JSContext* cx, unsigned argc, Value* vp)
{
CallArgs args = CallArgsFromVp(argc, vp);
args.rval().setNumber(cx->compartment()->savedStacks().count());
args.rval().setNumber(cx->realm()->savedStacks().count());
return true;
}
@ -1288,13 +1288,12 @@ ClearSavedFrames(JSContext* cx, unsigned argc, Value* vp)
{
CallArgs args = CallArgsFromVp(argc, vp);
js::SavedStacks& savedStacks = cx->compartment()->savedStacks();
js::SavedStacks& savedStacks = cx->realm()->savedStacks();
if (savedStacks.initialized())
savedStacks.clear();
for (ActivationIterator iter(cx); !iter.done(); ++iter) {
for (ActivationIterator iter(cx); !iter.done(); ++iter)
iter->clearLiveSavedFrameCache();
}
args.rval().setUndefined();
return true;

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

@ -409,7 +409,7 @@ template <class T>
class PreBarriered : public WriteBarrieredBase<T>
{
public:
PreBarriered() : WriteBarrieredBase<T>(JS::GCPolicy<T>::initial()) {}
PreBarriered() : WriteBarrieredBase<T>(JS::SafelyInitialized<T>()) {}
/*
* Allow implicit construction for use in generic contexts, such as
* DebuggerWeakMap::markKeys.
@ -453,12 +453,12 @@ template <class T>
class GCPtr : public WriteBarrieredBase<T>
{
public:
GCPtr() : WriteBarrieredBase<T>(JS::GCPolicy<T>::initial()) {}
GCPtr() : WriteBarrieredBase<T>(JS::SafelyInitialized<T>()) {}
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) {
this->post(JS::GCPolicy<T>::initial(), v);
this->post(JS::SafelyInitialized<T>(), v);
}
#ifdef DEBUG
~GCPtr() {
@ -471,7 +471,7 @@ class GCPtr : public WriteBarrieredBase<T>
//
// Note that when sweeping the wrapped pointer may already have been
// 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);
}
#endif
@ -479,7 +479,7 @@ class GCPtr : public WriteBarrieredBase<T>
void init(const T& v) {
CheckTargetIsNotGray(v);
this->value = v;
this->post(JS::GCPolicy<T>::initial(), v);
this->post(JS::SafelyInitialized<T>(), v);
}
DECLARE_POINTER_ASSIGN_OPS(GCPtr, T);
@ -529,11 +529,11 @@ template <class T>
class HeapPtr : public WriteBarrieredBase<T>
{
public:
HeapPtr() : WriteBarrieredBase<T>(JS::GCPolicy<T>::initial()) {}
HeapPtr() : WriteBarrieredBase<T>(JS::SafelyInitialized<T>()) {}
// Implicitly adding barriers is a reasonable default.
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.
*/
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() {
this->pre();
this->post(this->value, JS::GCPolicy<T>::initial());
this->post(this->value, JS::SafelyInitialized<T>());
}
void init(const T& v) {
CheckTargetIsNotGray(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);
@ -611,17 +611,17 @@ class ReadBarriered : public ReadBarrieredBase<T>,
using ReadBarrieredBase<T>::value;
public:
ReadBarriered() : ReadBarrieredBase<T>(JS::GCPolicy<T>::initial()) {}
ReadBarriered() : ReadBarrieredBase<T>(JS::SafelyInitialized<T>()) {}
// It is okay to add barriers implicitly.
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
// not escape, so no read barrier is necessary.
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
@ -629,11 +629,11 @@ class ReadBarriered : public ReadBarrieredBase<T>,
ReadBarriered(ReadBarriered&& v)
: ReadBarrieredBase<T>(mozilla::Move(v))
{
this->post(JS::GCPolicy<T>::initial(), v.value);
this->post(JS::SafelyInitialized<T>(), v.value);
}
~ReadBarriered() {
this->post(this->value, JS::GCPolicy<T>::initial());
this->post(this->value, JS::SafelyInitialized<T>());
}
ReadBarriered& operator=(const ReadBarriered& v) {

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

@ -3,7 +3,7 @@ if (!('oomTest' in this))
var x = ``.split();
oomTest(function() {
var lfGlobal = newGlobal();
var lfGlobal = newGlobal({sameZoneAs: this});
for (lfLocal in this) {
if (!(lfLocal in lfGlobal)) {
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;
// These types should work:
assertEq(new Global({type: "i32"}) instanceof Global, true);
assertEq(new Global({type: "f32"}) instanceof Global, true);
assertEq(new Global({type: "f64"}) instanceof Global, true);
assertEq(new Global({value: "i32"}) instanceof Global, true);
assertEq(new Global({value: "f32"}) instanceof Global, true);
assertEq(new Global({value: "f64"}) instanceof Global, true);
// These types should not work:
assertErrorMessage(() => new Global({type: "i64"}), 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(), TypeError, /Global requires more than 0 arguments/);
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({value: "fnord"}), TypeError, /bad type for a WebAssembly.Global/);
assertErrorMessage(() => new Global(), TypeError, /Global requires more than 0 arguments/);
// Coercion of init value; ".value" accessor
assertEq((new Global({type: "i32"}, 3.14)).value, 3);
assertEq((new Global({type: "f32"}, { valueOf: () => 33.5 })).value, 33.5);
assertEq((new Global({type: "f64"}, "3.25")).value, 3.25);
assertEq((new Global({value: "i32"}, 3.14)).value, 3);
assertEq((new Global({value: "f32"}, { valueOf: () => 33.5 })).value, 33.5);
assertEq((new Global({value: "f64"}, "3.25")).value, 3.25);
// 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.
assertEq((new Global({type: "i32"})).value, 0);
assertEq((new Global({type: "f32"})).value, 0);
assertEq((new Global({type: "f64"})).value, 0);
assertEq((new Global({value: "i32"})).value, 0);
assertEq((new Global({value: "f32"})).value, 0);
assertEq((new Global({value: "f64"})).value, 0);
{
// "value" is enumerable
let x = new Global({type: "i32"});
let x = new Global({value: "i32"});
let s = "";
for ( let i in x )
s = s + i + ",";
@ -386,20 +386,20 @@ if (typeof WebAssembly.Global === "function") {
assertEq("value" in Global.prototype, true);
// Can't set the value of an immutable global
assertErrorMessage(() => (new Global({type: "i32"})).value = 10,
assertErrorMessage(() => (new Global({value: "i32"})).value = 10,
TypeError,
/can't set value of immutable 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;
assertEq(g.value, 10);
}
{
// Misc internal conversions
let g = new Global({type: "i32"}, 42);
let g = new Global({value: "i32"}, 42);
// valueOf
assertEq(g - 5, 37);
@ -513,7 +513,7 @@ if (typeof WebAssembly.Global === "function") {
(import "m" "g" (global i32)))`));
// 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}}),
LinkError,
mutErr);
@ -522,7 +522,7 @@ if (typeof WebAssembly.Global === "function") {
(import "m" "g" (global (mut i32))))`));
// 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}}),
LinkError,
mutErr);

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

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

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

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

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

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

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

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

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

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

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

@ -1129,7 +1129,7 @@ RStringSplit::recover(JSContext* cx, SnapshotIterator& iter) const
{
RootedString str(cx, iter.read().toString());
RootedString sep(cx, iter.read().toString());
RootedObjectGroup group(cx, ObjectGroupCompartment::getStringSplitStringGroup(cx));
RootedObjectGroup group(cx, ObjectGroupRealm::getStringSplitStringGroup(cx));
if (!group) {
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_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_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_BAD_SIG, 0, JSEXN_WASMRUNTIMEERROR, "indirect call signature mismatch")
MSG_DEF(JSMSG_WASM_UNREACHABLE, 0, JSEXN_WASMRUNTIMEERROR, "unreachable executed")

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

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

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

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

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

@ -172,6 +172,15 @@ enum JSShellExitCode {
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
* js/xpconnect/src/XPCJSContext.cpp
@ -610,8 +619,7 @@ ShellContext::ShellContext(JSContext* cx)
readLineBufPos(0),
errFilePtr(nullptr),
outFilePtr(nullptr),
offThreadMonitor(mutexid::ShellOffThreadState),
moduleResolveHook(cx)
offThreadMonitor(mutexid::ShellOffThreadState)
{}
ShellContext::~ShellContext()
@ -4279,8 +4287,8 @@ SetModuleResolveHook(JSContext* cx, unsigned argc, Value* vp)
return false;
}
ShellContext* sc = GetShellContext(cx);
sc->moduleResolveHook = &args[0].toObject().as<JSFunction>();
Handle<GlobalObject*> global = cx->global();
global->setReservedSlot(GlobalAppSlotModuleResolveHook, args[0]);
args.rval().setUndefined();
return true;
@ -4289,18 +4297,20 @@ SetModuleResolveHook(JSContext* cx, unsigned argc, Value* vp)
static JSObject*
CallModuleResolveHook(JSContext* cx, HandleObject module, HandleString specifier)
{
ShellContext* sc = GetShellContext(cx);
if (!sc->moduleResolveHook) {
Handle<GlobalObject*> global = cx->global();
RootedValue hookValue(cx, global->getReservedSlot(GlobalAppSlotModuleResolveHook));
if (hookValue.isUndefined()) {
JS_ReportErrorASCII(cx, "Module resolve hook not set");
return nullptr;
}
MOZ_ASSERT(hookValue.toObject().is<JSFunction>());
JS::AutoValueArray<2> args(cx);
args[0].setObject(*module);
args[1].setString(specifier);
RootedValue result(cx);
if (!JS_CallFunction(cx, nullptr, sc->moduleResolveHook, args, &result))
if (!JS_CallFunctionValue(cx, nullptr, hookValue, args, &result))
return nullptr;
if (!result.isObject() || !result.toObject().is<ModuleObject>()) {

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

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

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

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

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

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

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

@ -308,10 +308,10 @@ DebuggerMemory::setAllocationSamplingProbability(JSContext* cx, unsigned argc, V
dbg->allocationSamplingProbability = probability;
// 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) {
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_));
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)
return nullptr;
@ -2314,7 +2316,7 @@ const DebugEnvironmentProxyHandler DebugEnvironmentProxyHandler::singleton;
/* static */ DebugEnvironmentProxy*
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>());
RootedValue priv(cx, ObjectValue(env));
@ -2514,11 +2516,11 @@ CanUseDebugEnvironmentMaps(JSContext* cx)
}
DebugEnvironments*
DebugEnvironments::ensureCompartmentData(JSContext* cx)
DebugEnvironments::ensureRealmData(JSContext* cx)
{
JSCompartment* c = cx->compartment();
if (c->debugEnvs)
return c->debugEnvs.get();
Realm* realm = cx->realm();
if (auto* debugEnvs = realm->debugEnvs())
return debugEnvs;
auto debugEnvs = cx->make_unique<DebugEnvironments>(cx, cx->zone());
if (!debugEnvs || !debugEnvs->init()) {
@ -2526,14 +2528,14 @@ DebugEnvironments::ensureCompartmentData(JSContext* cx)
return nullptr;
}
c->debugEnvs = Move(debugEnvs);
return c->debugEnvs.get();
realm->debugEnvsRef() = Move(debugEnvs);
return realm->debugEnvs();
}
/* static */ DebugEnvironmentProxy*
DebugEnvironments::hasDebugEnvironment(JSContext* cx, EnvironmentObject& env)
{
DebugEnvironments* envs = env.compartment()->debugEnvs.get();
DebugEnvironments* envs = env.realm()->debugEnvs();
if (!envs)
return nullptr;
@ -2549,13 +2551,13 @@ DebugEnvironments::hasDebugEnvironment(JSContext* cx, EnvironmentObject& env)
DebugEnvironments::addDebugEnvironment(JSContext* cx, Handle<EnvironmentObject*> env,
Handle<DebugEnvironmentProxy*> debugEnv)
{
MOZ_ASSERT(cx->compartment() == env->compartment());
MOZ_ASSERT(cx->compartment() == debugEnv->compartment());
MOZ_ASSERT(cx->realm() == env->realm());
MOZ_ASSERT(cx->realm() == debugEnv->realm());
if (!CanUseDebugEnvironmentMaps(cx))
return true;
DebugEnvironments* envs = ensureCompartmentData(cx);
DebugEnvironments* envs = ensureRealmData(cx);
if (!envs)
return false;
@ -2567,7 +2569,7 @@ DebugEnvironments::hasDebugEnvironment(JSContext* cx, const EnvironmentIter& ei)
{
MOZ_ASSERT(!ei.hasSyntacticEnvironment());
DebugEnvironments* envs = cx->compartment()->debugEnvs.get();
DebugEnvironments* envs = cx->realm()->debugEnvs();
if (!envs)
return nullptr;
@ -2583,7 +2585,7 @@ DebugEnvironments::addDebugEnvironment(JSContext* cx, const EnvironmentIter& ei,
Handle<DebugEnvironmentProxy*> debugEnv)
{
MOZ_ASSERT(!ei.hasSyntacticEnvironment());
MOZ_ASSERT(cx->compartment() == debugEnv->compartment());
MOZ_ASSERT(cx->realm() == debugEnv->realm());
// Generators should always have environments.
MOZ_ASSERT_IF(ei.scope().is<FunctionScope>(),
!ei.scope().as<FunctionScope>().canonicalFunction()->isGenerator() &&
@ -2592,7 +2594,7 @@ DebugEnvironments::addDebugEnvironment(JSContext* cx, const EnvironmentIter& ei,
if (!CanUseDebugEnvironmentMaps(cx))
return true;
DebugEnvironments* envs = ensureCompartmentData(cx);
DebugEnvironments* envs = ensureRealmData(cx);
if (!envs)
return false;
@ -2717,7 +2719,7 @@ DebugEnvironments::onPopCall(JSContext* cx, AbstractFramePtr frame)
{
assertSameCompartment(cx, frame);
DebugEnvironments* envs = cx->compartment()->debugEnvs.get();
DebugEnvironments* envs = cx->realm()->debugEnvs();
if (!envs)
return;
@ -2759,7 +2761,7 @@ DebugEnvironments::onPopLexical(JSContext* cx, AbstractFramePtr frame, jsbytecod
{
assertSameCompartment(cx, frame);
DebugEnvironments* envs = cx->compartment()->debugEnvs.get();
DebugEnvironments* envs = cx->realm()->debugEnvs();
if (!envs)
return;
@ -2771,7 +2773,7 @@ template <typename Environment, typename Scope>
void
DebugEnvironments::onPopGeneric(JSContext* cx, const EnvironmentIter& ei)
{
DebugEnvironments* envs = cx->compartment()->debugEnvs.get();
DebugEnvironments* envs = cx->realm()->debugEnvs();
if (!envs)
return;
@ -2807,7 +2809,7 @@ DebugEnvironments::onPopVar(JSContext* cx, AbstractFramePtr frame, jsbytecode* p
{
assertSameCompartment(cx, frame);
DebugEnvironments* envs = cx->compartment()->debugEnvs.get();
DebugEnvironments* envs = cx->realm()->debugEnvs();
if (!envs)
return;
@ -2827,14 +2829,15 @@ DebugEnvironments::onPopVar(JSContext* cx, const EnvironmentIter& ei)
void
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>());
}
void
DebugEnvironments::onCompartmentUnsetIsDebuggee(JSCompartment* c)
DebugEnvironments::onRealmUnsetIsDebuggee(Realm* realm)
{
if (DebugEnvironments* envs = c->debugEnvs.get()) {
if (DebugEnvironments* envs = realm->debugEnvs()) {
envs->proxiedEnvs.clear();
envs->missingEnvs.clear();
envs->liveEnvs.clear();
@ -2864,7 +2867,7 @@ DebugEnvironments::updateLiveEnvironments(JSContext* cx)
continue;
AbstractFramePtr frame = i.abstractFramePtr();
if (frame.environmentChain()->compartment() != cx->compartment())
if (frame.environmentChain()->realm() != cx->realm())
continue;
if (frame.isFunctionFrame()) {
@ -2882,8 +2885,8 @@ DebugEnvironments::updateLiveEnvironments(JSContext* cx)
for (EnvironmentIter ei(cx, env, scope, frame); ei.withinInitialFrame(); ei++) {
if (ei.hasSyntacticEnvironment() && !ei.scope().is<GlobalScope>()) {
MOZ_ASSERT(ei.environment().compartment() == cx->compartment());
DebugEnvironments* envs = ensureCompartmentData(cx);
MOZ_ASSERT(ei.environment().realm() == cx->realm());
DebugEnvironments* envs = ensureRealmData(cx);
if (!envs)
return false;
if (!envs->liveEnvs.put(&ei.environment(), LiveEnvironmentVal(ei)))
@ -2903,7 +2906,7 @@ DebugEnvironments::updateLiveEnvironments(JSContext* cx)
LiveEnvironmentVal*
DebugEnvironments::hasLiveEnvironment(EnvironmentObject& env)
{
DebugEnvironments* envs = env.compartment()->debugEnvs.get();
DebugEnvironments* envs = env.realm()->debugEnvs();
if (!envs)
return nullptr;
@ -2932,7 +2935,7 @@ DebugEnvironments::unsetPrevUpToDateUntil(JSContext* cx, AbstractFramePtr until)
if (frame == until)
return;
if (frame.environmentChain()->compartment() != cx->compartment())
if (frame.environmentChain()->realm() != cx->realm())
continue;
frame.unsetPrevUpToDate();
@ -2942,7 +2945,7 @@ DebugEnvironments::unsetPrevUpToDateUntil(JSContext* cx, AbstractFramePtr until)
/* static */ void
DebugEnvironments::forwardLiveFrame(JSContext* cx, AbstractFramePtr from, AbstractFramePtr to)
{
DebugEnvironments* envs = cx->compartment()->debugEnvs.get();
DebugEnvironments* envs = cx->realm()->debugEnvs();
if (!envs)
return;

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

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

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

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

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

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

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

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

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

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

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

@ -557,10 +557,27 @@ struct JSCompartment
JSRuntime* runtime_;
private:
friend struct JSRuntime;
friend struct JSContext;
js::WrapperMap crossCompartmentWrappers;
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_; }
const JS::Zone* zone() const { return zone_; }
@ -575,53 +592,19 @@ struct JSCompartment
return runtime_;
}
public:
void* data;
protected:
js::SavedStacks savedStacks_;
private:
js::WrapperMap crossCompartmentWrappers;
public:
void assertNoCrossCompartmentWrappers() {
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:
void addSizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf,
size_t* crossCompartmentWrappersArg);
public:
// Object group tables and other state in the compartment.
js::ObjectGroupCompartment objectGroups;
#ifdef JSGC_HASH_TABLE_CHECKS
void checkWrapperMapAfterMovingGC();
#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:
bool getNonWrapperObjectForCurrentCompartment(JSContext* cx, js::MutableHandleObject obj);
bool getOrCreateWrapper(JSContext* cx, js::HandleObject existing, js::MutableHandleObject obj);
@ -689,30 +672,11 @@ struct JSCompartment
void sweepAfterMinorGC(JSTracer* trc);
void sweepCrossCompartmentWrappers();
void sweepSavedStacks();
void sweepRegExps();
void sweepDebugEnvironments();
static void fixupCrossCompartmentWrappersAfterMovingGC(JSTracer* trc);
void fixupAfterMovingGC();
js::SavedStacks& savedStacks() { return savedStacks_; }
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 {
@ -782,7 +746,7 @@ class ObjectRealm
} // namespace js
class JS::Realm : public JSCompartment
class JS::Realm : private JSCompartment
{
const JS::RealmCreationOptions creationOptions_;
JS::RealmBehaviors behaviors_;
@ -794,6 +758,12 @@ class JS::Realm : public JSCompartment
js::ObjectRealm objects_;
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
// names declared using FunctionDeclaration, GeneratorDeclaration, and
// VariableDeclaration declarations in global code in this realm.
@ -817,6 +787,11 @@ class JS::Realm : public JSCompartment
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.
JS::RealmStats* realmStats_ = nullptr;
@ -863,6 +838,8 @@ class JS::Realm : public JSCompartment
// is enabled.
js::coverage::LCovRealm lcovOutput;
js::RegExpRealm regExps;
js::DtoaCache dtoaCache;
js::NewProxyCache newProxyCache;
js::ArraySpeciesLookup arraySpeciesLookup;
@ -927,6 +904,24 @@ class JS::Realm : public JSCompartment
size_t* privateData,
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_; }
JS::RealmBehaviors& behaviors() { return behaviors_; }
const JS::RealmBehaviors& behaviors() const { return behaviors_; }
@ -987,18 +982,28 @@ class JS::Realm : public JSCompartment
void finishRoots();
void sweepAfterMinorGC();
void sweepDebugEnvironments();
void sweepObjectRealm();
void sweepRegExps();
void sweepSelfHostingScriptSource();
void sweepTemplateObjects();
void sweepObjectGroups() {
objectGroups_.sweep();
}
void clearScriptCounts();
void clearScriptNames();
void purge();
void fixupAfterMovingGC();
void fixupScriptMapsAfterMovingGC();
#ifdef JSGC_HASH_TABLE_CHECKS
void checkObjectGroupTablesAfterMovingGC() {
objectGroups_.checkTablesAfterMovingGC();
}
void checkScriptMapsAfterMovingGC();
#endif
@ -1266,6 +1271,31 @@ class JS::Realm : public JSCompartment
js::jit::JitRealm* jitRealm() {
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 {

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

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

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

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

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

@ -158,7 +158,8 @@ JSObject::setSingleton(JSContext* cx, js::HandleObject 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());
if (!group)
return false;

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

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

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

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

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

@ -29,6 +29,7 @@ class HeapTypeSet;
class AutoClearTypeInferenceStateOnOOM;
class AutoSweepObjectGroup;
class CompilerConstraintList;
class ObjectGroupRealm;
namespace gc {
void MergeCompartments(JSCompartment* source, JSCompartment* target);
@ -527,21 +528,22 @@ class ObjectGroup : public gc::TenuredCell
static bool useSingletonForAllocationSite(JSScript* script, jsbytecode* pc,
const Class* clasp);
// Static accessors for ObjectGroupCompartment NewTable.
// Static accessors for ObjectGroupRealm NewTable.
static ObjectGroup* defaultNewGroup(JSContext* cx, const Class* clasp,
TaggedProto proto,
JSObject* associated = nullptr);
static ObjectGroup* lazySingletonGroup(JSContext* cx, const Class* clasp,
TaggedProto proto);
static ObjectGroup* lazySingletonGroup(JSContext* cx, ObjectGroupRealm& realm,
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
static bool hasDefaultNewGroup(JSObject* proto, const Class* clasp, ObjectGroup* group);
#endif
// Static accessors for ObjectGroupCompartment ArrayObjectTable and PlainObjectTable.
// Static accessors for ObjectGroupRealm ArrayObjectTable and PlainObjectTable.
enum class NewArrayKind {
Normal, // Specialize array group based on its element type.
@ -561,7 +563,7 @@ class ObjectGroup : public gc::TenuredCell
IdValuePair* properties, size_t nproperties,
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
// allocation site.
@ -589,8 +591,8 @@ class ObjectGroup : public gc::TenuredCell
static ObjectGroup* defaultNewGroup(JSContext* cx, JSProtoKey key);
};
// Structure used to manage the groups in a compartment.
class ObjectGroupCompartment
// Structure used to manage the groups in a realm.
class ObjectGroupRealm
{
private:
class NewTable;
@ -615,7 +617,7 @@ class ObjectGroupCompartment
class AllocationSiteTable;
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* lazyTable = nullptr;
@ -655,7 +657,7 @@ class ObjectGroupCompartment
// Table for referencing types of objects keyed to an allocation site.
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
// 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
@ -663,6 +665,10 @@ class ObjectGroupCompartment
// on the basis of call-site pc.
ReadBarrieredObjectGroup stringSplitStringGroup = {};
public:
// All unboxed layouts in the realm.
mozilla::LinkedList<js::UnboxedLayout> unboxedLayouts;
// END OF PROPERTIES
private:
@ -673,8 +679,14 @@ class ObjectGroupCompartment
public:
struct NewEntry;
ObjectGroupCompartment() = default;
~ObjectGroupCompartment();
ObjectGroupRealm() = default;
~ObjectGroupRealm();
ObjectGroupRealm(ObjectGroupRealm&) = delete;
void operator=(ObjectGroupRealm&) = delete;
static ObjectGroupRealm& get(ObjectGroup* group);
static ObjectGroupRealm& getForNewObject(JSContext* cx);
void replaceAllocationSiteGroup(JSScript* script, jsbytecode* pc,
JSProtoKey kind, ObjectGroup* group);
@ -693,7 +705,7 @@ class ObjectGroupCompartment
size_t* allocationSiteTables,
size_t* arrayGroupTables,
size_t* plainObjectGroupTables,
size_t* compartmentTables);
size_t* realmTables);
void clearTables();

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

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

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

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

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

@ -28,7 +28,7 @@
namespace js {
class ArrayObject;
class RegExpCompartment;
class RegExpRealm;
class RegExpShared;
class RegExpStatics;
class VectorMatchPairs;
@ -288,7 +288,7 @@ class RegExpZone
size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf);
};
class RegExpCompartment
class RegExpRealm
{
/*
* This is the template object where the result of re.exec() is based on,
@ -321,7 +321,7 @@ class RegExpCompartment
ArrayObject* createMatchResultTemplateObject(JSContext* cx);
public:
explicit RegExpCompartment();
explicit RegExpRealm();
void sweep();
@ -346,10 +346,10 @@ class RegExpCompartment
}
static size_t offsetOfOptimizableRegExpPrototypeShape() {
return offsetof(RegExpCompartment, optimizableRegExpPrototypeShape_);
return offsetof(RegExpRealm, optimizableRegExpPrototypeShape_);
}
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;
gc.atomsZone = atomsZone.get();
if (!atomsZone->compartments().append(atomsRealm.get()))
if (!atomsZone->compartments().append(JS::GetCompartmentForRealm(atomsRealm.get())))
return false;
atomsRealm->setIsSystem(true);

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

@ -101,21 +101,21 @@ LiveSavedFrameCache::find(JSContext* cx, FramePtr& framePtr, const jsbytecode* p
MOZ_ASSERT(initialized());
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.
if (frames->empty()) {
frame.set(nullptr);
return;
}
// All our SavedFrames should be in the same compartment. If the last
// entry's SavedFrame's compartment doesn't match cx's, flush the cache.
if (frames->back().savedFrame->compartment() != cx->compartment()) {
// All our SavedFrames should be in the same realm. If the last
// entry's SavedFrame's realm doesn't match cx's, flush the cache.
if (frames->back().savedFrame->realm() != cx->realm()) {
#ifdef DEBUG
// Check that they are, indeed, all in the same compartment.
auto compartment = frames->back().savedFrame->compartment();
// Check that they are, indeed, all in the same realm.
auto compartment = frames->back().savedFrame->realm();
for (const auto& f : (*frames))
MOZ_ASSERT(compartment == f.savedFrame->compartment());
MOZ_ASSERT(compartment == f.savedFrame->realm());
#endif
frames->clear();
frame.set(nullptr);
@ -124,7 +124,7 @@ LiveSavedFrameCache::find(JSContext* cx, FramePtr& framePtr, const jsbytecode* p
Key key(framePtr);
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,
// 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
// `SavedStacksMetadataBuilder` for this new SavedFrame object, and
// 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));
if (!proto)
@ -829,7 +829,7 @@ GetSavedFrameSource(JSContext* cx, HandleObject savedFrame, MutableHandleString
{
js::AssertHeapIsIdle();
CHECK_REQUEST(cx);
MOZ_RELEASE_ASSERT(cx->compartment());
MOZ_RELEASE_ASSERT(cx->realm());
{
AutoMaybeEnterFrameRealm ar(cx, savedFrame);
@ -852,7 +852,7 @@ GetSavedFrameLine(JSContext* cx, HandleObject savedFrame, uint32_t* linep,
{
js::AssertHeapIsIdle();
CHECK_REQUEST(cx);
MOZ_RELEASE_ASSERT(cx->compartment());
MOZ_RELEASE_ASSERT(cx->realm());
MOZ_ASSERT(linep);
AutoMaybeEnterFrameRealm ar(cx, savedFrame);
@ -872,7 +872,7 @@ GetSavedFrameColumn(JSContext* cx, HandleObject savedFrame, uint32_t* columnp,
{
js::AssertHeapIsIdle();
CHECK_REQUEST(cx);
MOZ_RELEASE_ASSERT(cx->compartment());
MOZ_RELEASE_ASSERT(cx->realm());
MOZ_ASSERT(columnp);
AutoMaybeEnterFrameRealm ar(cx, savedFrame);
@ -892,7 +892,7 @@ GetSavedFrameFunctionDisplayName(JSContext* cx, HandleObject savedFrame, Mutable
{
js::AssertHeapIsIdle();
CHECK_REQUEST(cx);
MOZ_RELEASE_ASSERT(cx->compartment());
MOZ_RELEASE_ASSERT(cx->realm());
{
AutoMaybeEnterFrameRealm ar(cx, savedFrame);
@ -915,7 +915,7 @@ GetSavedFrameAsyncCause(JSContext* cx, HandleObject savedFrame, MutableHandleStr
{
js::AssertHeapIsIdle();
CHECK_REQUEST(cx);
MOZ_RELEASE_ASSERT(cx->compartment());
MOZ_RELEASE_ASSERT(cx->realm());
{
AutoMaybeEnterFrameRealm ar(cx, savedFrame);
@ -946,7 +946,7 @@ GetSavedFrameAsyncParent(JSContext* cx, HandleObject savedFrame, MutableHandleOb
{
js::AssertHeapIsIdle();
CHECK_REQUEST(cx);
MOZ_RELEASE_ASSERT(cx->compartment());
MOZ_RELEASE_ASSERT(cx->realm());
AutoMaybeEnterFrameRealm ar(cx, savedFrame);
bool skippedAsync;
@ -979,7 +979,7 @@ GetSavedFrameParent(JSContext* cx, HandleObject savedFrame, MutableHandleObject
{
js::AssertHeapIsIdle();
CHECK_REQUEST(cx);
MOZ_RELEASE_ASSERT(cx->compartment());
MOZ_RELEASE_ASSERT(cx->realm());
AutoMaybeEnterFrameRealm ar(cx, savedFrame);
bool skippedAsync;
@ -1085,7 +1085,7 @@ BuildStackString(JSContext* cx, HandleObject stack, MutableHandleString stringp,
{
js::AssertHeapIsIdle();
CHECK_REQUEST(cx);
MOZ_RELEASE_ASSERT(cx->compartment());
MOZ_RELEASE_ASSERT(cx->realm());
js::StringBuffer sb(cx);
@ -1279,8 +1279,8 @@ SavedStacks::saveCurrentStack(JSContext* cx, MutableHandleSavedFrame frame,
JS::StackCapture&& capture /* = JS::StackCapture(JS::AllFrames()) */)
{
MOZ_ASSERT(initialized());
MOZ_RELEASE_ASSERT(cx->compartment());
assertSameCompartment(cx, this);
MOZ_RELEASE_ASSERT(cx->realm());
MOZ_DIAGNOSTIC_ASSERT(&cx->realm()->savedStacks() == this);
if (creatingSavedFrame ||
cx->isExceptionPending() ||
@ -1301,8 +1301,8 @@ SavedStacks::copyAsyncStack(JSContext* cx, HandleObject asyncStack, HandleString
const Maybe<size_t>& maxFrameCount)
{
MOZ_ASSERT(initialized());
MOZ_RELEASE_ASSERT(cx->compartment());
assertSameCompartment(cx, this);
MOZ_RELEASE_ASSERT(cx->realm());
MOZ_DIAGNOSTIC_ASSERT(&cx->realm()->savedStacks() == this);
RootedAtom asyncCauseAtom(cx, AtomizeString(cx, asyncCause));
if (!asyncCauseAtom)
@ -1475,7 +1475,7 @@ SavedStacks::insertFrames(JSContext* cx, MutableHandleSavedFrame frame,
Rooted<LocationValue> location(cx);
{
AutoRealmUnchecked ar(cx, iter.compartment());
if (!cx->compartment()->savedStacks().getLocation(cx, iter, &location))
if (!cx->realm()->savedStacks().getLocation(cx, iter, &location))
return false;
}
@ -1618,12 +1618,12 @@ SavedStacks::adoptAsyncStack(JSContext* cx, MutableHandleSavedFrame asyncStack,
// Attach the asyncCause to the youngest frame.
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
// just use the existing chain. Only the asyncCause on the youngest frame
// needs to be changed.
if (currentSavedFrame == nullptr &&
asyncStack->compartment() == cx->compartment())
asyncStack->realm() == cx->realm())
{
SavedFrame::HandleLookup lookup = stackChain[0];
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
// the cache because our compartment's sweep method isn't called when their
// 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
// location from our PCLocationMap and copy it into |locationp|. When we do
@ -1806,9 +1807,8 @@ SavedStacks::getLocation(JSContext* cx, const FrameIter& iter,
}
void
SavedStacks::chooseSamplingProbability(JSCompartment* compartment)
SavedStacks::chooseSamplingProbability(Realm* realm)
{
Realm* realm = JS::GetRealmForCompartment(compartment);
GlobalObject* global = realm->maybeGlobal();
if (!global)
return;
@ -1850,7 +1850,7 @@ SavedStacks::MetadataBuilder::build(JSContext* cx, HandleObject target,
{
RootedObject obj(cx, target);
SavedStacks& stacks = cx->compartment()->savedStacks();
SavedStacks& stacks = cx->realm()->savedStacks();
if (!stacks.bernoulli.trial())
return nullptr;
@ -1867,18 +1867,6 @@ SavedStacks::MetadataBuilder::build(JSContext* cx, HandleObject target,
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::IsNotSystem;
@ -2001,7 +1989,7 @@ ConstructSavedFrameStackSlow(JSContext* cx, JS::ubi::StackFrame& frame,
for (size_t i = stackChain->length(); i != 0; i--) {
SavedFrame::HandleLookup lookup = stackChain[i-1];
lookup->parent = parentFrame;
parentFrame = cx->compartment()->savedStacks().getOrCreateSavedFrame(cx, lookup);
parentFrame = cx->realm()->savedStacks().getOrCreateSavedFrame(cx, lookup);
if (!parentFrame)
return false;
}

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

@ -174,7 +174,7 @@ class SavedStacks {
void trace(JSTracer* trc);
uint32_t count();
void clear();
void chooseSamplingProbability(JSCompartment*);
void chooseSamplingProbability(JS::Realm* realm);
// Set the sampling random number generator's state to |state0| and
// |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 sep(cx, args[1].toString());
RootedObjectGroup group(cx, ObjectGroupCompartment::getStringSplitStringGroup(cx));
RootedObjectGroup group(cx, ObjectGroupRealm::getStringSplitStringGroup(cx));
if (!group)
return false;
@ -1790,7 +1790,7 @@ intrinsic_StringSplitStringLimit(JSContext* cx, unsigned argc, Value* vp)
uint32_t limit = uint32_t(args[2].toNumber());
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)
return false;
@ -2809,7 +2809,7 @@ JSRuntime::createSelfHostingGlobal(JSContext* cx)
&shgClassOps
};
AutoRealmUnchecked ar(cx, realm);
AutoRealmUnchecked ar(cx, compartment);
Rooted<GlobalObject*> shg(cx, GlobalObject::createInternal(cx, &shgClass));
if (!shg)
return nullptr;

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

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

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