Merge mozilla-central to autoland. a=merge CLOSED TREE

This commit is contained in:
Brindusan Cristian 2018-05-12 12:50:40 +03:00
Родитель c9ec03e046 1df25b391a
Коммит e471ad3958
123 изменённых файлов: 1724 добавлений и 1882 удалений

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

@ -44,7 +44,7 @@ ARIAGridAccessible::NativeRole()
// Table
uint32_t
ARIAGridAccessible::ColCount()
ARIAGridAccessible::ColCount() const
{
AccIterator rowIter(this, filters::GetRow);
Accessible* row = rowIter.Next();

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

@ -29,7 +29,7 @@ public:
virtual TableAccessible* AsTable() override { return this; }
// TableAccessible
virtual uint32_t ColCount() override;
virtual uint32_t ColCount() const override;
virtual uint32_t RowCount() override;
virtual Accessible* CellAt(uint32_t aRowIndex, uint32_t aColumnIndex) override;
virtual bool IsColSelected(uint32_t aColIdx) override;

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

@ -1842,12 +1842,12 @@ Accessible::GetNativeInterface(void** aNativeAccessible)
}
void
Accessible::DoCommand(nsIContent *aContent, uint32_t aActionIndex)
Accessible::DoCommand(nsIContent* aContent, uint32_t aActionIndex) const
{
class Runnable final : public mozilla::Runnable
{
public:
Runnable(Accessible* aAcc, nsIContent* aContent, uint32_t aIdx)
Runnable(const Accessible* aAcc, nsIContent* aContent, uint32_t aIdx)
: mozilla::Runnable("Runnable")
, mAcc(aAcc)
, mContent(aContent)
@ -1870,7 +1870,7 @@ Accessible::DoCommand(nsIContent *aContent, uint32_t aActionIndex)
}
private:
RefPtr<Accessible> mAcc;
RefPtr<const Accessible> mAcc;
nsCOMPtr<nsIContent> mContent;
uint32_t mIdx;
};
@ -1881,7 +1881,7 @@ Accessible::DoCommand(nsIContent *aContent, uint32_t aActionIndex)
}
void
Accessible::DispatchClickEvent(nsIContent *aContent, uint32_t aActionIndex)
Accessible::DispatchClickEvent(nsIContent *aContent, uint32_t aActionIndex) const
{
if (IsDefunct())
return;

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

@ -1096,12 +1096,14 @@ protected:
* @param aContent [in, optional] element to click
* @param aActionIndex [in, optional] index of accessible action
*/
void DoCommand(nsIContent *aContent = nullptr, uint32_t aActionIndex = 0);
void DoCommand(nsIContent* aContent = nullptr,
uint32_t aActionIndex = 0) const;
/**
* Dispatch click event.
*/
virtual void DispatchClickEvent(nsIContent *aContent, uint32_t aActionIndex);
virtual void DispatchClickEvent(nsIContent *aContent,
uint32_t aActionIndex) const;
//////////////////////////////////////////////////////////////////////////////
// Helpers

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

@ -35,7 +35,7 @@ public:
/**
* Return the number of columns in the table.
*/
virtual uint32_t ColCount() { return 0; }
virtual uint32_t ColCount() const { return 0; }
/**
* Return the number of rows in the table.

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

@ -484,7 +484,7 @@ HTMLTableAccessible::Summary(nsString& aSummary)
}
uint32_t
HTMLTableAccessible::ColCount()
HTMLTableAccessible::ColCount() const
{
nsTableWrapperFrame* tableFrame = do_QueryFrame(mContent->GetPrimaryFrame());
return tableFrame ? tableFrame->GetColCount() : 0;

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

@ -132,7 +132,7 @@ public:
// TableAccessible
virtual Accessible* Caption() const override;
virtual void Summary(nsString& aSummary) override;
virtual uint32_t ColCount() override;
virtual uint32_t ColCount() const override;
virtual uint32_t RowCount() override;
virtual Accessible* CellAt(uint32_t aRowIndex, uint32_t aColumnIndex) override;
virtual int32_t CellIndexAt(uint32_t aRowIdx, uint32_t aColIdx) override;

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

@ -156,9 +156,6 @@ var AccessFu = {
case "AccessFu:Present":
this._output(aMessage.json, aMessage.target);
break;
case "AccessFu:Input":
this.Input.setEditState(aMessage.json);
break;
case "AccessFu:DoScroll":
this.Input.doScroll(aMessage.json);
break;
@ -207,14 +204,12 @@ var AccessFu = {
_addMessageListeners: function _addMessageListeners(aMessageManager) {
aMessageManager.addMessageListener("AccessFu:Present", this);
aMessageManager.addMessageListener("AccessFu:Input", this);
aMessageManager.addMessageListener("AccessFu:Ready", this);
aMessageManager.addMessageListener("AccessFu:DoScroll", this);
},
_removeMessageListeners: function _removeMessageListeners(aMessageManager) {
aMessageManager.removeMessageListener("AccessFu:Present", this);
aMessageManager.removeMessageListener("AccessFu:Input", this);
aMessageManager.removeMessageListener("AccessFu:Ready", this);
aMessageManager.removeMessageListener("AccessFu:DoScroll", this);
},
@ -364,8 +359,6 @@ var AccessFu = {
};
var Input = {
editState: {},
moveToPoint: function moveToPoint(aRule, aX, aY) {
// XXX: Bug 1013408 - There is no alignment between the chrome window's
// viewport size and the content viewport size in Android. This makes
@ -396,23 +389,8 @@ var Input = {
},
moveByGranularity: function moveByGranularity(aDetails) {
const GRANULARITY_PARAGRAPH = 8;
const GRANULARITY_LINE = 4;
if (!this.editState.editing) {
if (aDetails.granularity & (GRANULARITY_PARAGRAPH | GRANULARITY_LINE)) {
this.moveCursor("move" + aDetails.direction, "Simple", "gesture");
return;
}
} else {
aDetails.atStart = this.editState.atStart;
aDetails.atEnd = this.editState.atEnd;
}
let mm = Utils.getMessageManager(Utils.CurrentBrowser);
let type = this.editState.editing ? "AccessFu:MoveCaret" :
"AccessFu:MoveByGranularity";
mm.sendAsyncMessage(type, aDetails);
mm.sendAsyncMessage("AccessFu:MoveByGranularity", aDetails);
},
activateCurrent: function activateCurrent(aData, aActivateIfKey = false) {
@ -423,11 +401,6 @@ var Input = {
{offset, activateIfKey: aActivateIfKey});
},
setEditState: function setEditState(aEditState) {
Logger.debug(() => { return ["setEditState", JSON.stringify(aEditState)]; });
this.editState = aEditState;
},
// XXX: This is here for backwards compatability with screen reader simulator
// it should be removed when the extension is updated on amo.
scroll: function scroll(aPage, aHorizontal) {

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

@ -9,6 +9,8 @@ ChromeUtils.defineModuleGetter(this, "Logger",
"resource://gre/modules/accessibility/Utils.jsm");
ChromeUtils.defineModuleGetter(this, "Roles",
"resource://gre/modules/accessibility/Constants.jsm");
ChromeUtils.defineModuleGetter(this, "States",
"resource://gre/modules/accessibility/Constants.jsm");
ChromeUtils.defineModuleGetter(this, "TraversalRules",
"resource://gre/modules/accessibility/Traversal.jsm");
ChromeUtils.defineModuleGetter(this, "TraversalHelper",
@ -33,7 +35,6 @@ this.ContentControl.prototype = {
"AccessFu:MoveToPoint",
"AccessFu:AutoMove",
"AccessFu:Activate",
"AccessFu:MoveCaret",
"AccessFu:MoveByGranularity",
"AccessFu:AndroidScroll"],
@ -300,25 +301,29 @@ this.ContentControl.prototype = {
},
handleMoveByGranularity: function cc_handleMoveByGranularity(aMessage) {
// XXX: Add sendToChild. Right now this is only used in Android, so no need.
let direction = aMessage.json.direction;
let granularity;
let { direction, granularity } = aMessage.json;
let focusedAcc = Utils.AccService.getAccessibleFor(this.document.activeElement);
if (focusedAcc && Utils.getState(focusedAcc).contains(States.EDITABLE)) {
this.moveCaret(focusedAcc, direction, granularity);
return;
}
switch (aMessage.json.granularity) {
let pivotGranularity;
switch (granularity) {
case MOVEMENT_GRANULARITY_CHARACTER:
granularity = Ci.nsIAccessiblePivot.CHAR_BOUNDARY;
pivotGranularity = Ci.nsIAccessiblePivot.CHAR_BOUNDARY;
break;
case MOVEMENT_GRANULARITY_WORD:
granularity = Ci.nsIAccessiblePivot.WORD_BOUNDARY;
pivotGranularity = Ci.nsIAccessiblePivot.WORD_BOUNDARY;
break;
default:
return;
}
if (direction === "Previous") {
this.vc.movePreviousByText(granularity);
this.vc.movePreviousByText(pivotGranularity);
} else if (direction === "Next") {
this.vc.moveNextByText(granularity);
this.vc.moveNextByText(pivotGranularity);
}
},
@ -331,16 +336,13 @@ this.ContentControl.prototype = {
}
},
handleMoveCaret: function cc_handleMoveCaret(aMessage) {
let direction = aMessage.json.direction;
let granularity = aMessage.json.granularity;
let accessible = this.vc.position;
moveCaret: function cc_moveCaret(accessible, direction, granularity) {
let accText = accessible.QueryInterface(Ci.nsIAccessibleText);
let oldOffset = accText.caretOffset;
let text = accText.getText(0, accText.characterCount);
let start = {}, end = {};
if (direction === "Previous" && !aMessage.json.atStart) {
if (direction === "Previous" && oldOffset > 0) {
switch (granularity) {
case MOVEMENT_GRANULARITY_CHARACTER:
accText.caretOffset--;
@ -356,7 +358,7 @@ this.ContentControl.prototype = {
accText.caretOffset = startOfParagraph !== -1 ? startOfParagraph : 0;
break;
}
} else if (direction === "Next" && !aMessage.json.atEnd) {
} else if (direction === "Next" && oldOffset < accText.characterCount) {
switch (granularity) {
case MOVEMENT_GRANULARITY_CHARACTER:
accText.caretOffset++;

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

@ -37,8 +37,6 @@ function EventManager(aContentScope, aContentControl) {
}
this.EventManager.prototype = {
editState: { editing: false },
start: function start() {
try {
if (!this._started) {
@ -144,8 +142,7 @@ this.EventManager.prototype = {
let reason = event.reason;
let oldAccessible = event.oldAccessible;
if (this.editState.editing &&
!Utils.getState(position).contains(States.FOCUSED)) {
if (!Utils.getState(position).contains(States.FOCUSED)) {
aEvent.accessibleDocument.takeFocus();
}
this.present(
@ -208,12 +205,9 @@ this.EventManager.prototype = {
// it doesn't mean we are not on any editable accessible. just not
// on this one..
let state = Utils.getState(acc);
if (state.contains(States.FOCUSED)) {
this._setEditingMode(aEvent, caretOffset);
if (state.contains(States.EDITABLE)) {
this.present(Presentation.textSelectionChanged(acc.getText(0, -1),
caretOffset, caretOffset, 0, 0, aEvent.isFromUserInput));
}
if (state.contains(States.FOCUSED) && state.contains(States.EDITABLE)) {
this.present(Presentation.textSelectionChanged(acc.getText(0, -1),
caretOffset, caretOffset, 0, 0, aEvent.isFromUserInput));
}
break;
}
@ -259,12 +253,13 @@ this.EventManager.prototype = {
{
// Put vc where the focus is at
let acc = aEvent.accessible;
this._setEditingMode(aEvent);
if (![Roles.CHROME_WINDOW,
Roles.DOCUMENT,
Roles.APPLICATION].includes(acc.role)) {
this.contentControl.autoMove(acc);
}
}
this.present(Presentation.focused(acc));
if (this.inTest) {
this.sendMsgFunc("AccessFu:Focused");
@ -288,8 +283,10 @@ this.EventManager.prototype = {
this.contentControl.autoMove(aEvent.accessible, { delay: 500 });
break;
}
case Events.VALUE_CHANGE:
case Events.TEXT_VALUE_CHANGE:
// We handle this events in TEXT_INSERTED/TEXT_REMOVED.
break;
case Events.VALUE_CHANGE:
{
let position = this.contentControl.vc.position;
let target = aEvent.accessible;
@ -307,54 +304,6 @@ this.EventManager.prototype = {
}
},
_setEditingMode: function _setEditingMode(aEvent, aCaretOffset) {
let acc = aEvent.accessible;
let accText, characterCount;
let caretOffset = aCaretOffset;
try {
accText = acc.QueryInterface(Ci.nsIAccessibleText);
} catch (e) {
// No text interface on this accessible.
}
if (accText) {
characterCount = accText.characterCount;
if (caretOffset === undefined) {
caretOffset = accText.caretOffset;
}
}
// Update editing state, both for presenter and other things
let state = Utils.getState(acc);
let editState = {
editing: state.contains(States.EDITABLE) &&
state.contains(States.FOCUSED),
multiline: state.contains(States.MULTI_LINE),
atStart: caretOffset === 0,
atEnd: caretOffset === characterCount
};
// Not interesting
if (!editState.editing && editState.editing === this.editState.editing) {
return;
}
if (editState.editing !== this.editState.editing) {
this.present(Presentation.editingModeChanged(editState.editing));
}
if (editState.editing !== this.editState.editing ||
editState.multiline !== this.editState.multiline ||
editState.atEnd !== this.editState.atEnd ||
editState.atStart !== this.editState.atStart) {
this.sendMsgFunc("AccessFu:Input", editState);
}
this.editState = editState;
},
_handleShow: function _handleShow(aEvent) {
let {liveRegion, isPolite} = this._handleLiveRegion(aEvent,
["additions", "all"]);

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

@ -65,15 +65,10 @@ class AndroidPresentor {
});
}
} else {
let state = Utils.getState(context.accessible);
androidEvents.push({eventType: (isExploreByTouch) ?
AndroidEvents.VIEW_HOVER_ENTER : focusEventType,
text: Utils.localize(UtteranceGenerator.genForContext(
context)),
bounds: context.bounds,
clickable: context.accessible.actionCount > 0,
checkable: state.contains(States.CHECKABLE),
checked: state.contains(States.CHECKED)});
let info = this._infoFromContext(context);
let eventType = isExploreByTouch ?
AndroidEvents.VIEW_HOVER_ENTER : focusEventType;
androidEvents.push({...info, eventType});
}
try {
@ -88,6 +83,12 @@ class AndroidPresentor {
return androidEvents;
}
focused(aObject) {
let info = this._infoFromContext(
new PivotContext(aObject, null, -1, -1, true, false));
return [{ eventType: AndroidEvents.VIEW_FOCUSED, ...info }];
}
/**
* An object's action has been invoked.
* @param {nsIAccessible} aObject the object that has been invoked.
@ -250,13 +251,6 @@ class AndroidPresentor {
return events;
}
/**
* We have entered or left text editing mode.
*/
editingModeChanged(aIsEditing) {
return this.announce(UtteranceGenerator.genForEditingMode(aIsEditing));
}
/**
* Announce something. Typically an app state change.
*/
@ -299,6 +293,20 @@ class AndroidPresentor {
return this.announce(
UtteranceGenerator.genForLiveRegion(context, aIsHide, aModifiedText));
}
_infoFromContext(aContext) {
let state = Utils.getState(aContext.accessible);
return {
text: Utils.localize(UtteranceGenerator.genForContext(aContext)),
bounds: aContext.bounds,
focusable: state.contains(States.FOCUSABLE),
focused: state.contains(States.FOCUSED),
clickable: aContext.accessible.actionCount > 0,
checkable: state.contains(States.CHECKABLE),
checked: state.contains(States.CHECKED),
editable: state.contains(States.EDITABLE),
};
}
}
const Presentation = new AndroidPresentor();

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

@ -408,26 +408,4 @@ class AccessFuContentTestRunner {
movePreviousByGranularity(aGranularity, ...aExpectedEvents) {
return this.moveByGranularity("Previous", aGranularity, ...aExpectedEvents);
}
// XXX: moveCaret* methods will go away soon as we fold it into the
// granularity messages above.
moveCaret(aDirection, aGranularity, ...aExpectedEvents) {
return this.expectAndroidEvents(() => {
this.sendMessage({
name: "AccessFu:MoveCaret",
data: {
direction: aDirection,
granularity: aGranularity
}
});
}, ...aExpectedEvents);
}
moveCaretNext(aGranularity, ...aExpectedEvents) {
return this.moveCaret("Next", aGranularity, ...aExpectedEvents);
}
moveCaretPrevious(aGranularity, ...aExpectedEvents) {
return this.moveCaret("Previous", aGranularity, ...aExpectedEvents);
}
}

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

@ -27,7 +27,7 @@
evt = await runner.moveNext("Simple",
AndroidEvents.VIEW_ACCESSIBILITY_FOCUSED);
runner.eventTextMatches(evt, ["Traversal Rule test document", "Phone status bar"]);
runner.isFocused("body");
runner.isFocused("html");
evt = await runner.movePrevious("Simple",
AndroidEvents.VIEW_ACCESSIBILITY_FOCUSED);

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

@ -36,15 +36,15 @@
let evt;
evt = await runner.focusSelector("textarea",
AndroidEvents.ANNOUNCEMENT,
AndroidEvents.VIEW_FOCUSED,
AndroidEvents.VIEW_ACCESSIBILITY_FOCUSED,
AndroidEvents.VIEW_TEXT_SELECTION_CHANGED);
// XXX: Get rid of announcements, and send focus events instead
runner.eventTextMatches(evt[0], ["editing"]);
is(evt[0].editable, true, "focused item is editable");
runner.eventTextMatches(evt[1],
["Text content test document",
"Please refrain from Mayoneggs during this salmonella scare.",
"text area"]);
is(evt[1].focused, true, "a11y focused item is focused");
is(evt[2].fromIndex, 0, "Correct fromIndex");
is(evt[2].toIndex, 0, "Correct toIndex");
@ -58,38 +58,38 @@
AndroidEvents.VIEW_TEXT_SELECTION_CHANGED);
checkMoveCaret(...evt, 10, 20);
evt = await runner.moveCaretNext(MovementGranularity.WORD,
evt = await runner.moveNextByGranularity(MovementGranularity.WORD,
AndroidEvents.VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY,
AndroidEvents.VIEW_TEXT_SELECTION_CHANGED);
checkMoveCaret(...evt, 20, 29);
evt = await runner.moveCaretNext(MovementGranularity.WORD,
evt = await runner.moveNextByGranularity(MovementGranularity.WORD,
AndroidEvents.VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY,
AndroidEvents.VIEW_TEXT_SELECTION_CHANGED);
checkMoveCaret(...evt, 29, 36);
evt = await runner.moveCaretNext(MovementGranularity.CHARACTER,
evt = await runner.moveNextByGranularity(MovementGranularity.CHARACTER,
AndroidEvents.VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY,
AndroidEvents.VIEW_TEXT_SELECTION_CHANGED);
checkMoveCaret(...evt, 36, 37);
evt = await runner.moveCaretNext(MovementGranularity.CHARACTER,
evt = await runner.moveNextByGranularity(MovementGranularity.CHARACTER,
AndroidEvents.VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY,
AndroidEvents.VIEW_TEXT_SELECTION_CHANGED);
checkMoveCaret(...evt, 37, 38);
evt = await runner.moveCaretNext(MovementGranularity.PARAGRAPH,
evt = await runner.moveNextByGranularity(MovementGranularity.PARAGRAPH,
AndroidEvents.VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY,
AndroidEvents.VIEW_TEXT_SELECTION_CHANGED);
checkMoveCaret(...evt, 38, 59);
evt = await runner.moveCaretPrevious(MovementGranularity.WORD,
evt = await runner.movePreviousByGranularity(MovementGranularity.WORD,
AndroidEvents.VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY,
AndroidEvents.VIEW_TEXT_SELECTION_CHANGED);
checkMoveCaret(...evt, 59, 53);
evt = await runner.blur(AndroidEvents.ANNOUNCEMENT);
runner.eventTextMatches(evt, ["navigating"]);
evt = await runner.blur(AndroidEvents.VIEW_FOCUSED);
is(evt.editable, false, "Focused out of editable");
}
function doTest() {

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

@ -37,77 +37,67 @@
let evt;
evt = await runner.focusSelector("input",
AndroidEvents.ANNOUNCEMENT,
AndroidEvents.VIEW_FOCUSED,
AndroidEvents.VIEW_ACCESSIBILITY_FOCUSED,
AndroidEvents.VIEW_TEXT_SELECTION_CHANGED);
// XXX: Get rid of announcements, and send focus events instead
runner.eventTextMatches(evt[0], ["editing"]);
is(evt[0].editable, true, "focused item is editable");
runner.eventTextMatches(evt[1], ["Text content test document", "entry"]);
is(evt[1].focused, true, "a11y focused item is focused");
is(evt[2].fromIndex, 0, "Caret at start (fromIndex)");
is(evt[2].toIndex, 0, "Caret at start (toIndex)");
evt = await runner.typeKey("B",
AndroidEvents.VIEW_TEXT_CHANGED,
AndroidEvents.VIEW_TEXT_SELECTION_CHANGED,
"todo.value-changed");
AndroidEvents.VIEW_TEXT_SELECTION_CHANGED);
checkInsert(evt[0], evt[1], ["B"], 0, 1);
evt = await runner.typeKey("o",
AndroidEvents.VIEW_TEXT_CHANGED,
AndroidEvents.VIEW_TEXT_SELECTION_CHANGED,
"todo.value-changed");
AndroidEvents.VIEW_TEXT_SELECTION_CHANGED);
checkInsert(evt[0], evt[1], ["Bo"], 1, 1);
evt = await runner.typeKey("b",
AndroidEvents.VIEW_TEXT_CHANGED,
AndroidEvents.VIEW_TEXT_SELECTION_CHANGED,
"todo.value-changed");
AndroidEvents.VIEW_TEXT_SELECTION_CHANGED);
checkInsert(evt[0], evt[1], ["Bob"], 2, 1);
evt = await runner.typeKey(" ",
AndroidEvents.VIEW_TEXT_CHANGED,
AndroidEvents.VIEW_TEXT_SELECTION_CHANGED,
"todo.value-changed");
AndroidEvents.VIEW_TEXT_SELECTION_CHANGED);
checkInsert(evt[0], evt[1], ["Bob "], 3, 1);
evt = await runner.typeKey("L",
AndroidEvents.VIEW_TEXT_CHANGED,
AndroidEvents.VIEW_TEXT_SELECTION_CHANGED,
"todo.value-changed");
AndroidEvents.VIEW_TEXT_SELECTION_CHANGED);
checkInsert(evt[0], evt[1], ["Bob L"], 4, 1);
evt = await runner.typeKey("o",
AndroidEvents.VIEW_TEXT_CHANGED,
AndroidEvents.VIEW_TEXT_SELECTION_CHANGED,
"todo.value-changed");
AndroidEvents.VIEW_TEXT_SELECTION_CHANGED);
checkInsert(evt[0], evt[1], ["Bob Lo"], 5, 1);
evt = await runner.typeKey("b",
AndroidEvents.VIEW_TEXT_CHANGED,
AndroidEvents.VIEW_TEXT_SELECTION_CHANGED,
"todo.value-changed");
AndroidEvents.VIEW_TEXT_SELECTION_CHANGED);
checkInsert(evt[0], evt[1], ["Bob Lob"], 6, 1);
evt = await runner.typeKey("l",
AndroidEvents.VIEW_TEXT_CHANGED,
AndroidEvents.VIEW_TEXT_SELECTION_CHANGED,
"todo.value-changed");
AndroidEvents.VIEW_TEXT_SELECTION_CHANGED);
checkInsert(evt[0], evt[1], ["Bob Lobl"], 7, 1);
evt = await runner.typeKey("a",
AndroidEvents.VIEW_TEXT_CHANGED,
AndroidEvents.VIEW_TEXT_SELECTION_CHANGED,
"todo.value-changed");
AndroidEvents.VIEW_TEXT_SELECTION_CHANGED);
checkInsert(evt[0], evt[1], ["Bob Lobla"], 8, 1);
evt = await runner.typeKey("w",
AndroidEvents.VIEW_TEXT_CHANGED,
AndroidEvents.VIEW_TEXT_SELECTION_CHANGED,
"todo.value-changed");
AndroidEvents.VIEW_TEXT_SELECTION_CHANGED);
checkInsert(evt[0], evt[1], ["Bob Loblaw"], 9, 1);
evt = await runner.blur(AndroidEvents.ANNOUNCEMENT);
runner.eventTextMatches(evt, ["navigating"]);
evt = await runner.blur(AndroidEvents.VIEW_FOCUSED);
is(evt.editable, false, "Focused out of editable");
}

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

@ -28,20 +28,20 @@
let evt;
evt = await runner.focusSelector("textarea",
AndroidEvents.VIEW_ACCESSIBILITY_FOCUSED,
AndroidEvents.ANNOUNCEMENT);
// XXX: Get rid of announcements, and send focus events instead
runner.eventTextMatches(evt[0],
AndroidEvents.VIEW_FOCUSED,
AndroidEvents.VIEW_ACCESSIBILITY_FOCUSED);
is(evt[0].editable, true, "focused item is editable");
is(evt[1].focused, true, "a11y focused item is focused");
runner.eventTextMatches(evt[1],
["Text content test document",
"Please refrain from Mayoneggs during this salmonella scare.",
"text area"]);
runner.eventTextMatches(evt[1], ["editing"]);
evt = await runner.moveNext("Simple",
AndroidEvents.VIEW_ACCESSIBILITY_FOCUSED,
AndroidEvents.ANNOUNCEMENT);
runner.eventTextMatches(evt[0], ["So we don't get dessert?", "label"]);
runner.eventTextMatches(evt[1], ["navigating"]);
AndroidEvents.VIEW_FOCUSED,
AndroidEvents.VIEW_ACCESSIBILITY_FOCUSED);
is(evt[0].editable, false, "focused out of editable");
runner.eventTextMatches(evt[1], ["So we don't get dessert?", "label"]);
runner.isFocused("html");
evt = await runner.moveNext("Simple",
@ -51,17 +51,17 @@
evt = await runner.activateCurrent(0,
AndroidEvents.VIEW_CLICKED,
AndroidEvents.ANNOUNCEMENT,
AndroidEvents.VIEW_FOCUSED,
AndroidEvents.VIEW_TEXT_SELECTION_CHANGED);
runner.eventTextMatches(evt[1], ["editing"]);
is(evt[1].editable, true, "focused item is editable");
is(evt[2].fromIndex, 0, "Cursor at start");
runner.isFocused("input[type=text]");
evt = await runner.movePrevious("Simple",
AndroidEvents.VIEW_ACCESSIBILITY_FOCUSED,
AndroidEvents.ANNOUNCEMENT);
runner.eventTextMatches(evt[0], ["So we don't get dessert?", "label"]);
runner.eventTextMatches(evt[1], ["navigating"]);
AndroidEvents.VIEW_FOCUSED,
AndroidEvents.VIEW_ACCESSIBILITY_FOCUSED);
is(evt[0].editable, false, "focused out of editable");
runner.eventTextMatches(evt[1], ["So we don't get dessert?", "label"]);
runner.isFocused("html");
evt = await runner.moveNext("Simple",
@ -72,12 +72,12 @@
// XXX: TEXT_SELECTION_CHANGED should be fired here
evt = await runner.activateCurrent(0,
AndroidEvents.VIEW_CLICKED,
AndroidEvents.ANNOUNCEMENT);
runner.eventTextMatches(evt[1], ["editing"]);
AndroidEvents.VIEW_FOCUSED);
is(evt[1].editable, true, "focused item is editable");
runner.isFocused("input[type=text]");
evt = await runner.blur(AndroidEvents.ANNOUNCEMENT);
runner.eventTextMatches(evt, ["navigating"]);
evt = await runner.blur(AndroidEvents.VIEW_FOCUSED);
is(evt.editable, false, "Focused out of editable");
}

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

@ -166,7 +166,7 @@ XULListboxAccessible::NativeRole()
// XULListboxAccessible: Table
uint32_t
XULListboxAccessible::ColCount()
XULListboxAccessible::ColCount() const
{
nsIContent* headContent = nullptr;
for (nsIContent* childContent = mContent->GetFirstChild(); childContent;

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

@ -62,7 +62,7 @@ public:
XULListboxAccessible(nsIContent* aContent, DocAccessible* aDoc);
// TableAccessible
virtual uint32_t ColCount() override;
virtual uint32_t ColCount() const override;
virtual uint32_t RowCount() override;
virtual Accessible* CellAt(uint32_t aRowIndex, uint32_t aColumnIndex) override;
virtual bool IsColSelected(uint32_t aColIdx) override;
@ -95,7 +95,7 @@ public:
protected:
virtual ~XULListboxAccessible() {}
bool IsMulticolumn() { return ColCount() > 1; }
bool IsMulticolumn() const { return ColCount() > 1; }
};
/**

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

@ -982,7 +982,7 @@ XULTreeItemAccessibleBase::ContainerWidget() const
void
XULTreeItemAccessibleBase::DispatchClickEvent(nsIContent* aContent,
uint32_t aActionIndex)
uint32_t aActionIndex) const
{
if (IsDefunct())
return;

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

@ -191,7 +191,8 @@ protected:
enum { eAction_Click = 0, eAction_Expand = 1 };
// Accessible
virtual void DispatchClickEvent(nsIContent *aContent, uint32_t aActionIndex) override;
virtual void DispatchClickEvent(nsIContent *aContent,
uint32_t aActionIndex) const override;
virtual Accessible* GetSiblingAtOffset(int32_t aOffset,
nsresult *aError = nullptr) const override;

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

@ -33,7 +33,7 @@ XULTreeGridAccessible::~XULTreeGridAccessible()
// XULTreeGridAccessible: Table
uint32_t
XULTreeGridAccessible::ColCount()
XULTreeGridAccessible::ColCount() const
{
return nsCoreUtils::GetSensibleColumnCount(mTree);
}
@ -805,7 +805,7 @@ XULTreeGridCellAccessible::GetSiblingAtOffset(int32_t aOffset,
void
XULTreeGridCellAccessible::DispatchClickEvent(nsIContent* aContent,
uint32_t aActionIndex)
uint32_t aActionIndex) const
{
if (IsDefunct())
return;

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

@ -30,7 +30,7 @@ public:
{ mGenericTypes |= eTable; }
// TableAccessible
virtual uint32_t ColCount() override;
virtual uint32_t ColCount() const override;
virtual uint32_t RowCount() override;
virtual Accessible* CellAt(uint32_t aRowIndex, uint32_t aColumnIndex) override;
virtual void ColDescription(uint32_t aColIdx, nsString& aDescription) override;
@ -163,7 +163,8 @@ protected:
// Accessible
virtual Accessible* GetSiblingAtOffset(int32_t aOffset,
nsresult* aError = nullptr) const override;
virtual void DispatchClickEvent(nsIContent* aContent, uint32_t aActionIndex) override;
virtual void DispatchClickEvent(nsIContent* aContent,
uint32_t aActionIndex) const override;
// XULTreeGridCellAccessible

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

@ -1,6 +1,5 @@
/* 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/. */
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";

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

@ -14,6 +14,7 @@
"cxx": "cl.exe",
"ml": "ml64.exe",
"patches": [
"r332092.patch",
"loosen-msvc-detection.patch"
]
}

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

@ -0,0 +1,22 @@
Bug 1458325: Fix copy/paste error in AddrIsInHighShadow that breaks Win64 jit-tests
https://reviews.llvm.org/D46291
https://github.com/llvm-mirror/compiler-rt/commit/d55f7bdbe7079a3d331d8ac7d0e82352eaf26af1
--- a/compiler-rt/lib/asan/asan_mapping.h
+++ b/compiler-rt/lib/asan/asan_mapping.h
@@ -319,12 +319,12 @@
static inline bool AddrIsInHighShadow(uptr a) {
PROFILE_ASAN_MAPPING();
- return a >= kHighShadowBeg && a <= kHighMemEnd;
+ return a >= kHighShadowBeg && a <= kHighShadowEnd;
}
static inline bool AddrIsInMidShadow(uptr a) {
PROFILE_ASAN_MAPPING();
- return kMidMemBeg && a >= kMidShadowBeg && a <= kMidMemEnd;
+ return kMidMemBeg && a >= kMidShadowBeg && a <= kMidShadowEnd;
}
static inline bool AddrIsInShadow(uptr a) {

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

@ -925,8 +925,9 @@ ifndef MOZ_TSAN
# Cargo needs the same linker flags as the C/C++ compiler,
# but not the final libraries. Filter those out because they
# cause problems on macOS 10.7; see bug 1365993 for details.
# Also, we don't want to pass PGO flags until cargo supports them.
target_cargo_env_vars := \
MOZ_CARGO_WRAP_LDFLAGS="$(filter-out -framework Cocoa -lobjc AudioToolbox ExceptionHandling,$(LDFLAGS))" \
MOZ_CARGO_WRAP_LDFLAGS="$(filter-out -framework Cocoa -lobjc AudioToolbox ExceptionHandling -fprofile-%,$(LDFLAGS))" \
MOZ_CARGO_WRAP_LD="$(CC)" \
$(cargo_linker_env_var)=$(topsrcdir)/build/cargo-linker
endif # MOZ_TSAN

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

@ -1551,7 +1551,7 @@ FragmentOrElement::RemoveBlackMarkedNode(nsINode* aNode)
static bool
IsCertainlyAliveNode(nsINode* aNode, nsIDocument* aDoc)
{
MOZ_ASSERT(aNode->GetUncomposedDoc() == aDoc);
MOZ_ASSERT(aNode->GetComposedDoc() == aDoc);
// Marked to be in-CC-generation or if the document is an svg image that's
// being kept alive by the image cache. (Note that an svg image's internal
@ -1573,9 +1573,7 @@ FragmentOrElement::CanSkipInCC(nsINode* aNode)
return false;
}
//XXXsmaug Need to figure out in which cases Shadow DOM can be optimized out
// from the CC graph.
nsIDocument* currentDoc = aNode->GetUncomposedDoc();
nsIDocument* currentDoc = aNode->GetComposedDoc();
if (currentDoc && IsCertainlyAliveNode(aNode, currentDoc)) {
return !NeedsScriptTraverse(aNode);
}
@ -1752,7 +1750,7 @@ FragmentOrElement::CanSkip(nsINode* aNode, bool aRemovingAllowed)
}
bool unoptimizable = aNode->UnoptimizableCCNode();
nsIDocument* currentDoc = aNode->GetUncomposedDoc();
nsIDocument* currentDoc = aNode->GetComposedDoc();
if (currentDoc && IsCertainlyAliveNode(aNode, currentDoc) &&
(!unoptimizable || NodeHasActiveFrame(currentDoc, aNode) ||
OwnedByBindingManager(currentDoc, aNode))) {
@ -1880,7 +1878,7 @@ FragmentOrElement::CanSkipThis(nsINode* aNode)
if (aNode->HasKnownLiveWrapper()) {
return true;
}
nsIDocument* c = aNode->GetUncomposedDoc();
nsIDocument* c = aNode->GetComposedDoc();
return
((c && IsCertainlyAliveNode(aNode, c)) || aNode->InCCBlackTree()) &&
!NeedsScriptTraverse(aNode);

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

@ -10496,19 +10496,6 @@ nsContentUtils::ShouldBlockReservedKeys(WidgetKeyboardEvent* aKeyEvent)
return false;
}
/* static */ Element*
nsContentUtils::GetClosestNonNativeAnonymousAncestor(Element* aElement)
{
MOZ_ASSERT(aElement);
MOZ_ASSERT(aElement->IsNativeAnonymous());
Element* e = aElement;
while (e && e->IsNativeAnonymous()) {
e = e->GetParentElement();
}
return e;
}
/**
* Checks whether the given type is a supported document type for
* loading within the nsObjectLoadingContent specified by aContent.

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

@ -3120,12 +3120,6 @@ public:
*/
static bool ShouldBlockReservedKeys(mozilla::WidgetKeyboardEvent* aKeyEvent);
/**
* Walks up the tree from aElement until it finds an element that is
* not native anonymous content. aElement must be NAC itself.
*/
static Element* GetClosestNonNativeAnonymousAncestor(Element* aElement);
/**
* Returns the nsIPluginTag for the plugin we should try to use for a given
* MIME type.

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

@ -1155,8 +1155,7 @@ nsINode::UnoptimizableCCNode() const
const uintptr_t problematicFlags = (NODE_IS_ANONYMOUS_ROOT |
NODE_IS_IN_NATIVE_ANONYMOUS_SUBTREE |
NODE_IS_NATIVE_ANONYMOUS_ROOT |
NODE_MAY_BE_IN_BINDING_MNGR |
NODE_IS_IN_SHADOW_TREE);
NODE_MAY_BE_IN_BINDING_MNGR);
return HasFlag(problematicFlags) ||
NodeType() == ATTRIBUTE_NODE ||
// For strange cases like xbl:content/xbl:children
@ -1169,7 +1168,7 @@ bool
nsINode::Traverse(nsINode *tmp, nsCycleCollectionTraversalCallback &cb)
{
if (MOZ_LIKELY(!cb.WantAllTraces())) {
nsIDocument *currentDoc = tmp->GetUncomposedDoc();
nsIDocument* currentDoc = tmp->GetComposedDoc();
if (currentDoc &&
nsCCUncollectableMarker::InGeneration(currentDoc->GetMarkedCCGeneration())) {
return false;

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

@ -194,6 +194,10 @@ struct PropertyInfo {
uint32_t prefIndex: NUM_BITS_PROPERTY_INFO_PREF_INDEX;
// The index to the corresponding spec in Duo.mPrefables[prefIndex].specs[].
uint32_t specIndex: NUM_BITS_PROPERTY_INFO_SPEC_INDEX;
// Note: the default constructor is not constexpr because of the bit fields,
// so we need this one.
constexpr PropertyInfo() : id(), type(0), prefIndex(0), specIndex(0) {}
};
static_assert(ePropertyTypeCount <= 1ull << NUM_BITS_PROPERTY_INFO_TYPE,

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

@ -1519,6 +1519,10 @@ ContentParent::OnChannelConnected(int32_t pid)
{
MOZ_ASSERT(NS_IsMainThread());
#ifndef ASYNC_CONTENTPROC_LAUNCH
SetOtherProcessId(pid);
#endif
#if defined(ANDROID) || defined(LINUX)
// Check nice preference
int32_t nice = Preferences::GetInt("dom.ipc.content.nice", 0);
@ -1543,7 +1547,7 @@ ContentParent::OnChannelConnected(int32_t pid)
}
#endif
#ifdef MOZ_CODE_COVERAGE
#if defined(MOZ_CODE_COVERAGE) && defined(ASYNC_CONTENTPROC_LAUNCH)
Unused << SendShareCodeCoverageMutex(
CodeCoverageHandler::Get()->GetMutexHandle(pid));
#endif
@ -2059,13 +2063,27 @@ ContentParent::LaunchSubprocess(ProcessPriority aInitialPriority /* = PROCESS_PR
extraArgs.push_back(parentBuildID.get());
SetOtherProcessId(kInvalidProcessId, ProcessIdState::ePending);
#ifdef ASYNC_CONTENTPROC_LAUNCH
if (!mSubprocess->Launch(extraArgs)) {
#else
if (!mSubprocess->LaunchAndWaitForProcessHandle(extraArgs)) {
#endif
NS_ERROR("failed to launch child in the parent");
MarkAsDead();
return false;
}
#ifdef ASYNC_CONTENTPROC_LAUNCH
OpenWithAsyncPid(mSubprocess->GetChannel());
#else
base::ProcessId procId =
base::GetProcId(mSubprocess->GetChildProcessHandle());
Open(mSubprocess->GetChannel(), procId);
#ifdef MOZ_CODE_COVERAGE
Unused << SendShareCodeCoverageMutex(
CodeCoverageHandler::Get()->GetMutexHandle(procId));
#endif
#endif // ASYNC_CONTENTPROC_LAUNCH
InitInternal(aInitialPriority);
@ -2076,8 +2094,9 @@ ContentParent::LaunchSubprocess(ProcessPriority aInitialPriority /* = PROCESS_PR
// Set a reply timeout for CPOWs.
SetReplyTimeoutMs(Preferences::GetInt("dom.ipc.cpow.timeout", 0));
// TODO: If OtherPid() is not called between mSubprocess->Launch() and this,
// then we're not really measuring how long it took to spawn the process.
// TODO: In ASYNC_CONTENTPROC_LAUNCH, if OtherPid() is not called between
// mSubprocess->Launch() and this, then we're not really measuring how long it
// took to spawn the process.
Telemetry::Accumulate(Telemetry::CONTENT_PROCESS_LAUNCH_TIME_MS,
static_cast<uint32_t>((TimeStamp::Now() - mLaunchTS)
.ToMilliseconds()));

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

@ -88,7 +88,10 @@ interface mozISpellCheckingEngine : nsISupports {
void removeDirectory(in nsIFile dir);
/**
* Add a dictionary with the given language code and file URI.
* Add a dictionary with the given language code and source URI. The URI
* must point to an affix file, with the ".aff" extension. The word list
* file must be in the same directory, with the same base name, and the
* ".dic" extension.
*/
void addDictionary(in AString lang, in nsIURI file);

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

@ -32,9 +32,9 @@ GPUProcessImpl::Init(int aArgc, char* aArgv[])
mozilla::SandboxTarget::Instance()->StartSandbox();
#endif
char* parentBuildID = nullptr;
for (int idx = aArgc; idx > 0; idx--) {
if (!strcmp(aArgv[idx], "-parentBuildID")) {
parentBuildID = aArgv[idx + 1];
for (int i = 1; i < aArgc; i++) {
if (strcmp(aArgv[i], "-parentBuildID") == 0) {
parentBuildID = aArgv[i + 1];
}
}

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

@ -3364,7 +3364,7 @@ gfxFont::InitFakeSmallCapsRun(DrawTarget *aDrawTarget,
const char16_t *aText,
uint32_t aOffset,
uint32_t aLength,
uint8_t aMatchType,
gfxTextRange::MatchType aMatchType,
gfx::ShapedTextFlags aOrientation,
Script aScript,
bool aSyntheticLower,
@ -3539,7 +3539,7 @@ gfxFont::InitFakeSmallCapsRun(DrawTarget *aDrawTarget,
const uint8_t *aText,
uint32_t aOffset,
uint32_t aLength,
uint8_t aMatchType,
gfxTextRange::MatchType aMatchType,
gfx::ShapedTextFlags aOrientation,
Script aScript,
bool aSyntheticLower,

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

@ -631,14 +631,15 @@ protected:
};
struct gfxTextRange {
enum {
// flags for recording the kind of font-matching that was used
kFontGroup = 0x0001,
kPrefsFallback = 0x0002,
kSystemFallback = 0x0004
enum class MatchType : uint8_t {
// Flags for recording the kind of font-matching that was used.
// Note that multiple flags may be set on a single range.
kFontGroup = 0x01,
kPrefsFallback = 0x02,
kSystemFallback = 0x04
};
gfxTextRange(uint32_t aStart, uint32_t aEnd,
gfxFont* aFont, uint8_t aMatchType,
gfxFont* aFont, MatchType aMatchType,
mozilla::gfx::ShapedTextFlags aOrientation)
: start(aStart),
end(aEnd),
@ -649,10 +650,12 @@ struct gfxTextRange {
uint32_t Length() const { return end - start; }
uint32_t start, end;
RefPtr<gfxFont> font;
uint8_t matchType;
MatchType matchType;
mozilla::gfx::ShapedTextFlags orientation;
};
MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(gfxTextRange::MatchType)
/**
* gfxFontShaper
*
@ -1865,7 +1868,7 @@ public:
const T *aText,
uint32_t aOffset,
uint32_t aLength,
uint8_t aMatchType,
gfxTextRange::MatchType aMatchType,
mozilla::gfx::ShapedTextFlags aOrientation,
Script aScript,
bool aSyntheticLower,

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

@ -1276,7 +1276,7 @@ gfxTextRun::FindFirstGlyphRunContaining(uint32_t aOffset) const
}
nsresult
gfxTextRun::AddGlyphRun(gfxFont *aFont, uint8_t aMatchType,
gfxTextRun::AddGlyphRun(gfxFont *aFont, gfxTextRange::MatchType aMatchType,
uint32_t aUTF16Offset, bool aForceNewRun,
gfx::ShapedTextFlags aOrientation)
{
@ -1608,8 +1608,8 @@ gfxTextRun::SetSpaceGlyph(gfxFont* aFont, DrawTarget* aDrawTarget,
roundingFlags,
nullptr);
if (sw) {
AddGlyphRun(aFont, gfxTextRange::kFontGroup, aCharIndex, false,
aOrientation);
AddGlyphRun(aFont, gfxTextRange::MatchType::kFontGroup, aCharIndex,
false, aOrientation);
CopyGlyphDataFrom(sw, aCharIndex);
}
}
@ -1634,7 +1634,7 @@ gfxTextRun::SetSpaceGlyphIfSimple(gfxFont* aFont, uint32_t aCharIndex,
return false;
}
AddGlyphRun(aFont, gfxTextRange::kFontGroup, aCharIndex, false,
AddGlyphRun(aFont, gfxTextRange::MatchType::kFontGroup, aCharIndex, false,
aOrientation);
CompressedGlyph g =
CompressedGlyph::MakeSimpleGlyph(spaceWidthAppUnits, spaceGlyph);
@ -2186,8 +2186,8 @@ gfxFontGroup::MakeSpaceTextRun(const Parameters *aParams,
// Short-circuit for size-0 fonts, as Windows and ATSUI can't handle
// them, and always create at least size 1 fonts, i.e. they still
// render something for size 0 fonts.
textRun->AddGlyphRun(font, gfxTextRange::kFontGroup, 0, false,
orientation);
textRun->AddGlyphRun(font, gfxTextRange::MatchType::kFontGroup, 0,
false, orientation);
}
else {
if (font->GetSpaceGlyph()) {
@ -2197,7 +2197,7 @@ gfxFontGroup::MakeSpaceTextRun(const Parameters *aParams,
} else {
// In case the primary font doesn't have <space> (bug 970891),
// find one that does.
uint8_t matchType;
gfxTextRange::MatchType matchType;
gfxFont* spaceFont =
FindFontForChar(' ', 0, 0, Script::LATIN, nullptr,
&matchType);
@ -2230,7 +2230,8 @@ gfxFontGroup::MakeBlankTextRun(uint32_t aLength,
if (orientation == ShapedTextFlags::TEXT_ORIENT_VERTICAL_MIXED) {
orientation = ShapedTextFlags::TEXT_ORIENT_VERTICAL_UPRIGHT;
}
textRun->AddGlyphRun(GetFirstValidFont(), gfxTextRange::kFontGroup, 0, false,
textRun->AddGlyphRun(GetFirstValidFont(),
gfxTextRange::MatchType::kFontGroup, 0, false,
orientation);
return textRun.forget();
}
@ -2664,7 +2665,8 @@ gfxFontGroup::InitScriptRun(DrawTarget* aDrawTarget,
}
}
} else {
aTextRun->AddGlyphRun(mainFont, gfxTextRange::kFontGroup,
aTextRun->AddGlyphRun(mainFont,
gfxTextRange::MatchType::kFontGroup,
aOffset + runStart, (matchedLength > 0),
range.orientation);
}
@ -2846,7 +2848,7 @@ gfxFontGroup::GetUnderlineOffset()
gfxFont*
gfxFontGroup::FindFontForChar(uint32_t aCh, uint32_t aPrevCh, uint32_t aNextCh,
Script aRunScript, gfxFont *aPrevMatchedFont,
uint8_t *aMatchType)
gfxTextRange::MatchType* aMatchType)
{
// If the char is a cluster extender, we want to use the same font as the
// preceding character if possible. This is preferable to using the font
@ -2887,7 +2889,7 @@ gfxFontGroup::FindFontForChar(uint32_t aCh, uint32_t aPrevCh, uint32_t aNextCh,
gfxFont* firstFont = GetFontAt(0, aCh);
if (firstFont) {
if (firstFont->HasCharacter(aCh)) {
*aMatchType = gfxTextRange::kFontGroup;
*aMatchType = gfxTextRange::MatchType::kFontGroup;
return firstFont;
}
@ -2902,7 +2904,7 @@ gfxFontGroup::FindFontForChar(uint32_t aCh, uint32_t aPrevCh, uint32_t aNextCh,
font = FindFallbackFaceForChar(mFonts[0].Family(), aCh);
}
if (font) {
*aMatchType = gfxTextRange::kFontGroup;
*aMatchType = gfxTextRange::MatchType::kFontGroup;
return font;
}
}
@ -2980,7 +2982,7 @@ gfxFontGroup::FindFontForChar(uint32_t aCh, uint32_t aPrevCh, uint32_t aNextCh,
if (pfe && pfe->HasCharacter(aCh)) {
font = GetFontAt(i, aCh);
if (font) {
*aMatchType = gfxTextRange::kFontGroup;
*aMatchType = gfxTextRange::MatchType::kFontGroup;
return font;
}
}
@ -2989,7 +2991,7 @@ gfxFontGroup::FindFontForChar(uint32_t aCh, uint32_t aPrevCh, uint32_t aNextCh,
// build the font via GetFontAt
font = GetFontAt(i, aCh);
if (font) {
*aMatchType = gfxTextRange::kFontGroup;
*aMatchType = gfxTextRange::MatchType::kFontGroup;
return font;
}
}
@ -3002,7 +3004,7 @@ gfxFontGroup::FindFontForChar(uint32_t aCh, uint32_t aPrevCh, uint32_t aNextCh,
"should only do fallback once per font family");
font = FindFallbackFaceForChar(ff.Family(), aCh);
if (font) {
*aMatchType = gfxTextRange::kFontGroup;
*aMatchType = gfxTextRange::MatchType::kFontGroup;
return font;
}
} else {
@ -3013,7 +3015,7 @@ gfxFontGroup::FindFontForChar(uint32_t aCh, uint32_t aPrevCh, uint32_t aNextCh,
if (!fe->mIsUserFontContainer && !fe->IsUserFont()) {
font = FindFallbackFaceForChar(ff.Family(), aCh);
if (font) {
*aMatchType = gfxTextRange::kFontGroup;
*aMatchType = gfxTextRange::MatchType::kFontGroup;
return font;
}
}
@ -3023,7 +3025,7 @@ gfxFontGroup::FindFontForChar(uint32_t aCh, uint32_t aPrevCh, uint32_t aNextCh,
if (fontListLength == 0) {
gfxFont* defaultFont = GetDefaultFont();
if (defaultFont->HasCharacter(aCh)) {
*aMatchType = gfxTextRange::kFontGroup;
*aMatchType = gfxTextRange::MatchType::kFontGroup;
return defaultFont;
}
}
@ -3035,14 +3037,14 @@ gfxFontGroup::FindFontForChar(uint32_t aCh, uint32_t aPrevCh, uint32_t aNextCh,
// 2. search pref fonts
gfxFont* font = WhichPrefFontSupportsChar(aCh, aNextCh);
if (font) {
*aMatchType = gfxTextRange::kPrefsFallback;
*aMatchType = gfxTextRange::MatchType::kPrefsFallback;
return font;
}
// 3. use fallback fonts
// -- before searching for something else check the font used for the previous character
if (aPrevMatchedFont && aPrevMatchedFont->HasCharacter(aCh)) {
*aMatchType = gfxTextRange::kSystemFallback;
*aMatchType = gfxTextRange::MatchType::kSystemFallback;
return aPrevMatchedFont;
}
@ -3056,7 +3058,7 @@ gfxFontGroup::FindFontForChar(uint32_t aCh, uint32_t aPrevCh, uint32_t aNextCh,
}
// -- otherwise look for other stuff
*aMatchType = gfxTextRange::kSystemFallback;
*aMatchType = gfxTextRange::MatchType::kSystemFallback;
return WhichSystemFontSupportsChar(aCh, aNextCh, aRunScript);
}
@ -3086,7 +3088,7 @@ void gfxFontGroup::ComputeRanges(nsTArray<gfxTextRange>& aRanges,
// if we use the initial value of prevFont, we treat this as a match from
// the font group; fixes bug 978313
uint8_t matchType = gfxTextRange::kFontGroup;
gfxTextRange::MatchType matchType = gfxTextRange::MatchType::kFontGroup;
for (uint32_t i = 0; i < aLength; i++) {
@ -3136,7 +3138,7 @@ void gfxFontGroup::ComputeRanges(nsTArray<gfxTextRange>& aRanges,
&& !gfxFontUtils::IsJoinControl(ch)
&& !gfxFontUtils::IsJoinCauser(prevCh)
&& !gfxFontUtils::IsVarSelector(ch)))) {
matchType = gfxTextRange::kFontGroup;
matchType = gfxTextRange::MatchType::kFontGroup;
} else {
font = FindFontForChar(ch, prevCh, nextCh, aRunScript, prevFont,
&matchType);
@ -3144,9 +3146,9 @@ void gfxFontGroup::ComputeRanges(nsTArray<gfxTextRange>& aRanges,
#ifndef RELEASE_OR_BETA
if (MOZ_UNLIKELY(mTextPerf)) {
if (matchType == gfxTextRange::kPrefsFallback) {
if (matchType == gfxTextRange::MatchType::kPrefsFallback) {
mTextPerf->current.fallbackPrefs++;
} else if (matchType == gfxTextRange::kSystemFallback) {
} else if (matchType == gfxTextRange::MatchType::kSystemFallback) {
mTextPerf->current.fallbackSystem++;
}
}
@ -3194,7 +3196,7 @@ void gfxFontGroup::ComputeRanges(nsTArray<gfxTextRange>& aRanges,
// if font or orientation has changed, make a new range...
// unless ch is a variation selector (bug 1248248)
gfxTextRange& prevRange = aRanges[lastRangeIndex];
if (prevRange.font != font || prevRange.matchType != matchType ||
if (prevRange.font != font ||
(prevRange.orientation != orient && !IsClusterExtender(ch))) {
// close out the previous range
prevRange.end = origI;
@ -3210,6 +3212,8 @@ void gfxFontGroup::ComputeRanges(nsTArray<gfxTextRange>& aRanges,
{
prevFont = font;
}
} else {
prevRange.matchType |= matchType;
}
}
}
@ -3231,13 +3235,26 @@ void gfxFontGroup::ComputeRanges(nsTArray<gfxTextRange>& aRanges,
nsAutoCString fontMatches;
for (size_t i = 0, i_end = aRanges.Length(); i < i_end; i++) {
const gfxTextRange& r = aRanges[i];
nsAutoCString matchTypes;
if (r.matchType & gfxTextRange::MatchType::kFontGroup) {
matchTypes.AppendLiteral("list");
}
if (r.matchType & gfxTextRange::MatchType::kPrefsFallback) {
if (!matchTypes.IsEmpty()) {
matchTypes.AppendLiteral(",");
}
matchTypes.AppendLiteral("prefs");
}
if (r.matchType & gfxTextRange::MatchType::kPrefsFallback) {
if (!matchTypes.IsEmpty()) {
matchTypes.AppendLiteral(",");
}
matchTypes.AppendLiteral("sys");
}
fontMatches.AppendPrintf(" [%u:%u] %.200s (%s)", r.start, r.end,
(r.font.get() ?
NS_ConvertUTF16toUTF8(r.font->GetName()).get() : "<null>"),
(r.matchType == gfxTextRange::kFontGroup ?
"list" :
(r.matchType == gfxTextRange::kPrefsFallback) ?
"prefs" : "sys"));
matchTypes.get());
}
MOZ_LOG(log, LogLevel::Debug,\
("(%s-fontmatching) fontgroup: [%s] default: %s lang: %s script: %d"

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

@ -469,7 +469,7 @@ public:
RefPtr<gfxFont> mFont; // never null in a valid GlyphRun
uint32_t mCharacterOffset; // into original UTF16 string
mozilla::gfx::ShapedTextFlags mOrientation; // gfxTextRunFactory::TEXT_ORIENT_* value
uint8_t mMatchType;
gfxTextRange::MatchType mMatchType;
};
class MOZ_STACK_CLASS GlyphRunIterator {
@ -527,7 +527,7 @@ public:
* are added before any further operations are performed with this
* TextRun.
*/
nsresult AddGlyphRun(gfxFont *aFont, uint8_t aMatchType,
nsresult AddGlyphRun(gfxFont *aFont, gfxTextRange::MatchType aMatchType,
uint32_t aStartCharIndex, bool aForceNewRun,
mozilla::gfx::ShapedTextFlags aOrientation);
void ResetGlyphRuns()
@ -957,7 +957,7 @@ public:
gfxFont* FindFontForChar(uint32_t ch, uint32_t prevCh, uint32_t aNextCh,
Script aRunScript, gfxFont *aPrevMatchedFont,
uint8_t *aMatchType);
gfxTextRange::MatchType *aMatchType);
gfxUserFontSet* GetUserFontSet();

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

@ -555,13 +555,17 @@ GeckoChildProcessHost::RunPerformAsyncLaunch(std::vector<std::string> aExtraOpts
MonitorAutoLock lock(mMonitor);
mProcessState = PROCESS_ERROR;
lock.Notify();
#ifdef ASYNC_CONTENTPROC_LAUNCH
OnProcessLaunchError();
#endif
CHROMIUM_LOG(ERROR) << "Failed to launch " <<
XRE_ChildProcessTypeToString(mProcessType) << " subprocess";
Telemetry::Accumulate(Telemetry::SUBPROCESS_LAUNCH_FAILURE,
nsDependentCString(XRE_ChildProcessTypeToString(mProcessType)));
#ifdef ASYNC_CONTENTPROC_LAUNCH
} else {
OnProcessHandleReady(mChildProcessHandle);
#endif
}
return ok;
}

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

@ -27,20 +27,29 @@
#include "js/TypeDecls.h"
#include "js/Utility.h"
struct jsid
{
size_t asBits;
bool operator==(const jsid& rhs) const { return asBits == rhs.asBits; }
bool operator!=(const jsid& rhs) const { return asBits != rhs.asBits; }
} JS_HAZ_GC_POINTER;
#define JSID_BITS(id) (id.asBits)
#define JSID_TYPE_STRING 0x0
#define JSID_TYPE_INT 0x1
#define JSID_TYPE_VOID 0x2
#define JSID_TYPE_SYMBOL 0x4
#define JSID_TYPE_MASK 0x7
struct jsid
{
size_t asBits;
constexpr jsid() : asBits(JSID_TYPE_VOID) {}
static constexpr jsid fromRawBits(size_t bits) {
jsid id;
id.asBits = bits;
return id;
}
bool operator==(const jsid& rhs) const { return asBits == rhs.asBits; }
bool operator!=(const jsid& rhs) const { return asBits != rhs.asBits; }
} JS_HAZ_GC_POINTER;
#define JSID_BITS(id) (id.asBits)
// Avoid using canonical 'id' for jsid parameters since this is a magic word in
// Objective-C++ which, apparently, wants to be able to #include jsapi.h.
#define id iden
@ -156,7 +165,7 @@ JSID_IS_EMPTY(const jsid id)
return (size_t)JSID_BITS(id) == JSID_TYPE_SYMBOL;
}
constexpr const jsid JSID_VOID = { size_t(JSID_TYPE_VOID) };
constexpr const jsid JSID_VOID;
extern JS_PUBLIC_DATA(const jsid) JSID_EMPTY;
extern JS_PUBLIC_DATA(const JS::HandleId) JSID_VOIDHANDLE;

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

@ -7,6 +7,7 @@
/* JS reflection package. */
#include "mozilla/DebugOnly.h"
#include "mozilla/Maybe.h"
#include "mozilla/Move.h"
#include <stdlib.h>
@ -3471,10 +3472,16 @@ reflect_parse(JSContext* cx, uint32_t argc, Value* vp)
UsedNameTracker usedNames(cx);
if (!usedNames.init())
return false;
RootedScriptSourceObject sourceObject(cx, frontend::CreateScriptSourceObject(cx, options,
mozilla::Nothing()));
if (!sourceObject)
return false;
Parser<FullParseHandler, char16_t> parser(cx, cx->tempLifoAlloc(), options,
chars.begin().get(), chars.length(),
/* foldConstants = */ false, usedNames, nullptr,
nullptr);
nullptr, sourceObject);
if (!parser.checkOptions())
return false;

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

@ -223,14 +223,15 @@ BytecodeCompiler::createParser()
if (canLazilyParse()) {
syntaxParser.emplace(cx, alloc, options, sourceBuffer.get(), sourceBuffer.length(),
/* foldConstants = */ false, *usedNames, nullptr, nullptr);
/* foldConstants = */ false, *usedNames, nullptr, nullptr,
sourceObject);
if (!syntaxParser->checkOptions())
return false;
}
parser.emplace(cx, alloc, options, sourceBuffer.get(), sourceBuffer.length(),
/* foldConstants = */ true, *usedNames, syntaxParser.ptrOr(nullptr), nullptr);
/* foldConstants = */ true, *usedNames, syntaxParser.ptrOr(nullptr), nullptr,
sourceObject);
parser->ss = scriptSource;
return parser->checkOptions();
}
@ -741,6 +742,8 @@ bool
frontend::CompileLazyFunction(JSContext* cx, Handle<LazyScript*> lazy, const char16_t* chars, size_t length)
{
MOZ_ASSERT(cx->compartment() == lazy->functionNonDelazifying()->compartment());
// We can't be running this script unless we've run its parent.
MOZ_ASSERT(!lazy->isEnclosingScriptLazy());
AutoAssertReportedException assertException(cx);
@ -773,9 +776,11 @@ frontend::CompileLazyFunction(JSContext* cx, Handle<LazyScript*> lazy, const cha
UsedNameTracker usedNames(cx);
if (!usedNames.init())
return false;
RootedScriptSourceObject sourceObject(cx, &lazy->sourceObject());
Parser<FullParseHandler, char16_t> parser(cx, cx->tempLifoAlloc(), options, chars, length,
/* foldConstants = */ true, usedNames, nullptr,
lazy);
lazy, sourceObject);
if (!parser.checkOptions())
return false;
@ -786,9 +791,6 @@ frontend::CompileLazyFunction(JSContext* cx, Handle<LazyScript*> lazy, const cha
if (!pn)
return false;
RootedScriptSourceObject sourceObject(cx, lazy->sourceObject());
MOZ_ASSERT(sourceObject);
Rooted<JSScript*> script(cx, JSScript::Create(cx, options, sourceObject,
lazy->sourceStart(), lazy->sourceEnd(),
lazy->toStringStart(), lazy->toStringEnd()));

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

@ -7943,8 +7943,7 @@ BytecodeEmitter::emitFunction(ParseNode* pn, bool needsProto)
// fact. If we attempt to compile the outer script again, the
// static scope chain will be newly allocated and will mismatch
// the previously compiled LazyScript's.
ScriptSourceObject* source = &script->sourceObject()->as<ScriptSourceObject>();
fun->lazyScript()->setEnclosingScopeAndSource(innermostScope(), source);
fun->lazyScript()->setEnclosingScope(innermostScope());
if (emittingRunOnceLambda)
fun->lazyScript()->setTreatAsRunOnce();
} else {

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

@ -797,7 +797,8 @@ ParserBase::errorNoOffset(unsigned errorNumber, ...)
ParserBase::ParserBase(JSContext* cx, LifoAlloc& alloc,
const ReadOnlyCompileOptions& options,
bool foldConstants,
UsedNameTracker& usedNames)
UsedNameTracker& usedNames,
ScriptSourceObject* sourceObject)
: AutoGCRooter(cx, PARSER),
context(cx),
alloc(alloc),
@ -806,6 +807,7 @@ ParserBase::ParserBase(JSContext* cx, LifoAlloc& alloc,
pc(nullptr),
usedNames(usedNames),
ss(nullptr),
sourceObject(cx, sourceObject),
keepAtoms(cx),
foldConstants(foldConstants),
#ifdef DEBUG
@ -848,8 +850,9 @@ template <class ParseHandler>
PerHandlerParser<ParseHandler>::PerHandlerParser(JSContext* cx, LifoAlloc& alloc,
const ReadOnlyCompileOptions& options,
bool foldConstants, UsedNameTracker& usedNames,
LazyScript* lazyOuterFunction)
: ParserBase(cx, alloc, options, foldConstants, usedNames),
LazyScript* lazyOuterFunction,
ScriptSourceObject* sourceObject)
: ParserBase(cx, alloc, options, foldConstants, usedNames, sourceObject),
handler(cx, alloc, lazyOuterFunction)
{
@ -862,8 +865,9 @@ GeneralParser<ParseHandler, CharT>::GeneralParser(JSContext* cx, LifoAlloc& allo
bool foldConstants,
UsedNameTracker& usedNames,
SyntaxParser* syntaxParser,
LazyScript* lazyOuterFunction)
: Base(cx, alloc, options, foldConstants, usedNames, lazyOuterFunction),
LazyScript* lazyOuterFunction,
ScriptSourceObject* sourceObject)
: Base(cx, alloc, options, foldConstants, usedNames, lazyOuterFunction, sourceObject),
tokenStream(cx, options, chars, length)
{
// The Mozilla specific JSOPTION_EXTRA_WARNINGS option adds extra warnings
@ -2534,7 +2538,8 @@ PerHandlerParser<SyntaxParseHandler>::finishFunction(bool isStandaloneFunction /
FunctionBox* funbox = pc->functionBox();
RootedFunction fun(context, funbox->function());
LazyScript* lazy = LazyScript::Create(context, fun, pc->closedOverBindingsForLazy(),
LazyScript* lazy = LazyScript::Create(context, fun, sourceObject,
pc->closedOverBindingsForLazy(),
pc->innerFunctionsForLazy,
funbox->bufStart, funbox->bufEnd,
funbox->toStringStart,

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

@ -247,7 +247,7 @@ enum AwaitHandling : uint8_t { AwaitIsName, AwaitIsKeyword, AwaitIsModuleKeyword
template <class ParseHandler, typename CharT>
class AutoAwaitIsKeyword;
class ParserBase
class MOZ_STACK_CLASS ParserBase
: public StrictModeGetter,
private JS::AutoGCRooter
{
@ -276,6 +276,8 @@ class ParserBase
ScriptSource* ss;
RootedScriptSourceObject sourceObject;
/* Root atoms and objects allocated for the parsed tree. */
AutoKeepAtoms keepAtoms;
@ -301,7 +303,8 @@ class ParserBase
template<class, typename> friend class AutoAwaitIsKeyword;
ParserBase(JSContext* cx, LifoAlloc& alloc, const ReadOnlyCompileOptions& options,
bool foldConstants, UsedNameTracker& usedNames);
bool foldConstants, UsedNameTracker& usedNames,
ScriptSourceObject* sourceObject);
~ParserBase();
bool checkOptions();
@ -433,7 +436,7 @@ enum FunctionCallBehavior {
};
template <class ParseHandler>
class PerHandlerParser
class MOZ_STACK_CLASS PerHandlerParser
: public ParserBase
{
private:
@ -465,7 +468,8 @@ class PerHandlerParser
protected:
PerHandlerParser(JSContext* cx, LifoAlloc& alloc, const ReadOnlyCompileOptions& options,
bool foldConstants, UsedNameTracker& usedNames,
LazyScript* lazyOuterFunction);
LazyScript* lazyOuterFunction,
ScriptSourceObject* sourceObject);
static Node null() { return ParseHandler::null(); }
@ -636,7 +640,7 @@ template <class ParseHandler, typename CharT>
class Parser;
template <class ParseHandler, typename CharT>
class GeneralParser
class MOZ_STACK_CLASS GeneralParser
: public PerHandlerParser<ParseHandler>
{
public:
@ -867,7 +871,8 @@ class GeneralParser
GeneralParser(JSContext* cx, LifoAlloc& alloc, const ReadOnlyCompileOptions& options,
const CharT* chars, size_t length, bool foldConstants,
UsedNameTracker& usedNames, SyntaxParser* syntaxParser,
LazyScript* lazyOuterFunction);
LazyScript* lazyOuterFunction,
ScriptSourceObject* sourceObject);
inline void setAwaitHandling(AwaitHandling awaitHandling);
@ -1248,7 +1253,7 @@ class GeneralParser
};
template <typename CharT>
class Parser<SyntaxParseHandler, CharT> final
class MOZ_STACK_CLASS Parser<SyntaxParseHandler, CharT> final
: public GeneralParser<SyntaxParseHandler, CharT>
{
using Base = GeneralParser<SyntaxParseHandler, CharT>;
@ -1358,7 +1363,7 @@ class Parser<SyntaxParseHandler, CharT> final
};
template <typename CharT>
class Parser<FullParseHandler, CharT> final
class MOZ_STACK_CLASS Parser<FullParseHandler, CharT> final
: public GeneralParser<FullParseHandler, CharT>
{
using Base = GeneralParser<FullParseHandler, CharT>;

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

@ -96,9 +96,9 @@ const I64RemUCode = 0x82;
const FirstInvalidOpcode = wasmThreadsSupported() ? 0xc5 : 0xc0;
const LastInvalidOpcode = 0xfb;
const NumericPrefix = 0xfc;
const MiscPrefix = 0xfc;
const SimdPrefix = 0xfd;
const AtomicPrefix = 0xfe;
const ThreadPrefix = 0xfe;
const MozPrefix = 0xff;
// DefinitionKind

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

@ -480,7 +480,7 @@ function checkIllegalPrefixed(prefix, opcode) {
assertEq(WebAssembly.validate(binary), false);
}
// Illegal AtomicPrefix opcodes
// Illegal ThreadPrefix opcodes
//
// June 2017 threads draft:
//
@ -488,19 +488,25 @@ function checkIllegalPrefixed(prefix, opcode) {
// 0x10 .. 0x4f are primitive atomic ops
for (let i = 3; i < 0x10; i++)
checkIllegalPrefixed(AtomicPrefix, i);
checkIllegalPrefixed(ThreadPrefix, i);
for (let i = 0x4f; i < 0x100; i++)
checkIllegalPrefixed(AtomicPrefix, i);
checkIllegalPrefixed(ThreadPrefix, i);
// Illegal Numeric opcodes
//
// Feb 2018 numeric draft:
//
// 0x00 .. 0x07 are saturating truncation ops
// 0x00 .. 0x07 are saturating truncation ops. 0x40 and 0x41 are
// from the bulk memory proposal. 0x40/0x41 are unofficial values,
// until such time as there is an official assignment for memory.copy/fill
// subopcodes.
for (let i = 0x08; i < 256; i++)
checkIllegalPrefixed(NumericPrefix, i);
for (let i = 0; i < 256; i++) {
if (i <= 0x07 || i == 0x40 || i == 0x41)
continue;
checkIllegalPrefixed(MiscPrefix, i);
}
// Illegal SIMD opcodes (all of them, for now)
for (let i = 0; i < 256; i++)
@ -510,7 +516,7 @@ for (let i = 0; i < 256; i++)
for (let i = 0; i < 256; i++)
checkIllegalPrefixed(MozPrefix, i);
for (let prefix of [AtomicPrefix, NumericPrefix, SimdPrefix, MozPrefix]) {
for (let prefix of [ThreadPrefix, MiscPrefix, SimdPrefix, MozPrefix]) {
// Prefix without a subsequent opcode
let binary = moduleWithSections([v2vSigSection, declSection([0]), bodySection([funcBody({locals:[], body:[prefix]})])]);
assertErrorMessage(() => wasmEval(binary), CompileError, /unrecognized opcode/);

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

@ -40,7 +40,7 @@ class MOZ_RAII BaselineCacheIRCompiler : public CacheIRCompiler
ICStubEngine engine_;
#endif
uint32_t stubDataOffset_;
bool inStubFrame_;
bool makesGCCalls_;
@ -57,11 +57,10 @@ class MOZ_RAII BaselineCacheIRCompiler : public CacheIRCompiler
BaselineCacheIRCompiler(JSContext* cx, const CacheIRWriter& writer, ICStubEngine engine,
uint32_t stubDataOffset)
: CacheIRCompiler(cx, writer, Mode::Baseline),
: CacheIRCompiler(cx, writer, stubDataOffset, Mode::Baseline, StubFieldPolicy::Address),
#ifdef DEBUG
engine_(engine),
#endif
stubDataOffset_(stubDataOffset),
inStubFrame_(false),
makesGCCalls_(false)
{}

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

@ -924,7 +924,7 @@ CacheIRWriter::copyStubData(uint8_t* dest) const
InitGCPtr<JSString*>(destWords, field.asWord());
break;
case StubField::Type::Id:
InitGCPtr<jsid>(destWords, field.asWord());
AsGCPtr<jsid>(destWords)->init(jsid::fromRawBits(field.asWord()));
break;
case StubField::Type::RawInt64:
case StubField::Type::DOMExpandoGeneration:
@ -2934,6 +2934,40 @@ CacheIRCompiler::emitCallObjectHasSparseElementResult()
return true;
}
/*
* Move a constant value into register dest.
*/
void CacheIRCompiler::EmitLoadStubFieldConstant(StubFieldOffset val, Register dest) {
MOZ_ASSERT(mode_ == Mode::Ion);
switch (val.getStubFieldType()) {
case StubField::Type::Shape:
masm.movePtr(ImmGCPtr(shapeStubField(val.getOffset())),dest);
break;
case StubField::Type::String:
masm.movePtr(ImmGCPtr(stringStubField(val.getOffset())), dest);
break;
default:
MOZ_CRASH("Unhandled stub field constant type");
}
}
/*
* After this is done executing, dest contains the value; either through a constant load
* or through the load from the stub data.
*
* The current policy is that Baseline will use loads from the stub data (to allow IC
* sharing), where as Ion doesn't share ICs, and so we can safely use constants in the
* IC.
*/
void CacheIRCompiler::EmitLoadStubField(StubFieldOffset val, Register dest) {
if (stubFieldPolicy_ == StubFieldPolicy::Constant) {
EmitLoadStubFieldConstant(val, dest);
} else {
Address load(ICStubReg, stubDataOffset_ + val.getOffset());
masm.loadPtr(load, dest);
}
}
bool
CacheIRCompiler::emitLoadInstanceOfObjectResult()
{

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

@ -531,6 +531,24 @@ class FailurePath
bool canShareFailurePath(const FailurePath& other) const;
};
/**
* Wrap an offset so that a call can decide to embed a constant
* or load from the stub data.
*/
class StubFieldOffset {
private:
uint32_t offset_;
StubField::Type type_;
public:
StubFieldOffset(uint32_t offset, StubField::Type type)
: offset_(offset),
type_(type)
{ }
uint32_t getOffset() { return offset_; }
StubField::Type getStubFieldType() { return type_; }
};
class AutoOutputRegister;
// Base class for BaselineCacheIRCompiler and IonCacheIRCompiler.
@ -561,13 +579,29 @@ class MOZ_RAII CacheIRCompiler
// Whether this IC may read double values from uint32 arrays.
mozilla::Maybe<bool> allowDoubleResult_;
CacheIRCompiler(JSContext* cx, const CacheIRWriter& writer, Mode mode)
// Distance from the IC to the stub data; mostly will be
// sizeof(stubType)
uint32_t stubDataOffset_;
uint32_t nextStubField_;
enum class StubFieldPolicy {
Address,
Constant
};
StubFieldPolicy stubFieldPolicy_;
CacheIRCompiler(JSContext* cx, const CacheIRWriter& writer, uint32_t stubDataOffset, Mode mode, StubFieldPolicy policy)
: cx_(cx),
reader(writer),
writer_(writer),
allocator(writer_),
liveFloatRegs_(FloatRegisterSet::All()),
mode_(mode)
mode_(mode),
stubDataOffset_(stubDataOffset),
nextStubField_(0),
stubFieldPolicy_(policy)
{
MOZ_ASSERT(!writer.failed());
}
@ -624,6 +658,63 @@ class MOZ_RAII CacheIRCompiler
#define DEFINE_SHARED_OP(op) MOZ_MUST_USE bool emit##op();
CACHE_IR_SHARED_OPS(DEFINE_SHARED_OP)
#undef DEFINE_SHARED_OP
void EmitLoadStubField(StubFieldOffset val, Register dest);
void EmitLoadStubFieldConstant(StubFieldOffset val, Register dest);
uintptr_t readStubWord(uint32_t offset, StubField::Type type) {
MOZ_ASSERT(stubFieldPolicy_ == StubFieldPolicy::Constant);
MOZ_ASSERT((offset % sizeof(uintptr_t)) == 0);
// We use nextStubField_ to access the data as it's stored in an as-of-yet
// unpacked vector, and so using the offset can be incorrect where the index
// would change as a result of packing.
return writer_.readStubFieldForIon(nextStubField_++, type).asWord();
}
uint64_t readStubInt64(uint32_t offset, StubField::Type type) {
MOZ_ASSERT(stubFieldPolicy_ == StubFieldPolicy::Constant);
MOZ_ASSERT((offset % sizeof(uintptr_t)) == 0);
return writer_.readStubFieldForIon(nextStubField_++, type).asInt64();
}
int32_t int32StubField(uint32_t offset) {
MOZ_ASSERT(stubFieldPolicy_ == StubFieldPolicy::Constant);
return readStubWord(offset, StubField::Type::RawWord);
}
Shape* shapeStubField(uint32_t offset) {
MOZ_ASSERT(stubFieldPolicy_ == StubFieldPolicy::Constant);
return (Shape*)readStubWord(offset, StubField::Type::Shape);
}
JSObject* objectStubField(uint32_t offset) {
MOZ_ASSERT(stubFieldPolicy_ == StubFieldPolicy::Constant);
return (JSObject*)readStubWord(offset, StubField::Type::JSObject);
}
JSString* stringStubField(uint32_t offset) {
MOZ_ASSERT(stubFieldPolicy_ == StubFieldPolicy::Constant);
return (JSString*)readStubWord(offset, StubField::Type::String);
}
JS::Symbol* symbolStubField(uint32_t offset) {
MOZ_ASSERT(stubFieldPolicy_ == StubFieldPolicy::Constant);
return (JS::Symbol*)readStubWord(offset, StubField::Type::Symbol);
}
ObjectGroup* groupStubField(uint32_t offset) {
MOZ_ASSERT(stubFieldPolicy_ == StubFieldPolicy::Constant);
return (ObjectGroup*)readStubWord(offset, StubField::Type::ObjectGroup);
}
JSCompartment* compartmentStubField(uint32_t offset) {
MOZ_ASSERT(stubFieldPolicy_ == StubFieldPolicy::Constant);
return (JSCompartment*)readStubWord(offset, StubField::Type::RawWord);
}
const Class* classStubField(uintptr_t offset) {
MOZ_ASSERT(stubFieldPolicy_ == StubFieldPolicy::Constant);
return (const Class*)readStubWord(offset, StubField::Type::RawWord);
}
const void* proxyHandlerStubField(uintptr_t offset) {
MOZ_ASSERT(stubFieldPolicy_ == StubFieldPolicy::Constant);
return (const void*)readStubWord(offset, StubField::Type::RawWord);
}
jsid idStubField(uint32_t offset) {
MOZ_ASSERT(stubFieldPolicy_ == StubFieldPolicy::Constant);
return jsid::fromRawBits(readStubWord(offset, StubField::Type::Id));
}
};
// Ensures the IC's output register is available for writing.

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

@ -36,14 +36,13 @@ class MOZ_RAII IonCacheIRCompiler : public CacheIRCompiler
friend class AutoSaveLiveRegisters;
IonCacheIRCompiler(JSContext* cx, const CacheIRWriter& writer, IonIC* ic, IonScript* ionScript,
IonICStub* stub, const PropertyTypeCheckInfo* typeCheckInfo)
: CacheIRCompiler(cx, writer, Mode::Ion),
IonICStub* stub, const PropertyTypeCheckInfo* typeCheckInfo, uint32_t stubDataOffset)
: CacheIRCompiler(cx, writer, stubDataOffset, Mode::Ion, StubFieldPolicy::Constant),
writer_(writer),
ic_(ic),
ionScript_(ionScript),
stub_(stub),
typeCheckInfo_(typeCheckInfo),
nextStubField_(0),
#ifdef DEBUG
calledPrepareVMCall_(false),
#endif
@ -72,51 +71,13 @@ class MOZ_RAII IonCacheIRCompiler : public CacheIRCompiler
Vector<CodeOffset, 4, SystemAllocPolicy> nextCodeOffsets_;
Maybe<LiveRegisterSet> liveRegs_;
Maybe<CodeOffset> stubJitCodeOffset_;
uint32_t nextStubField_;
#ifdef DEBUG
bool calledPrepareVMCall_;
#endif
bool savedLiveRegs_;
uintptr_t readStubWord(uint32_t offset, StubField::Type type) {
MOZ_ASSERT((offset % sizeof(uintptr_t)) == 0);
return writer_.readStubFieldForIon(nextStubField_++, type).asWord();
}
uint64_t readStubInt64(uint32_t offset, StubField::Type type) {
MOZ_ASSERT((offset % sizeof(uintptr_t)) == 0);
return writer_.readStubFieldForIon(nextStubField_++, type).asInt64();
}
int32_t int32StubField(uint32_t offset) {
return readStubWord(offset, StubField::Type::RawWord);
}
Shape* shapeStubField(uint32_t offset) {
return (Shape*)readStubWord(offset, StubField::Type::Shape);
}
JSObject* objectStubField(uint32_t offset) {
return (JSObject*)readStubWord(offset, StubField::Type::JSObject);
}
JSString* stringStubField(uint32_t offset) {
return (JSString*)readStubWord(offset, StubField::Type::String);
}
JS::Symbol* symbolStubField(uint32_t offset) {
return (JS::Symbol*)readStubWord(offset, StubField::Type::Symbol);
}
ObjectGroup* groupStubField(uint32_t offset) {
return (ObjectGroup*)readStubWord(offset, StubField::Type::ObjectGroup);
}
JSCompartment* compartmentStubField(uint32_t offset) {
return (JSCompartment*)readStubWord(offset, StubField::Type::RawWord);
}
const Class* classStubField(uintptr_t offset) {
return (const Class*)readStubWord(offset, StubField::Type::RawWord);
}
const void* proxyHandlerStubField(uintptr_t offset) {
return (const void*)readStubWord(offset, StubField::Type::RawWord);
}
jsid idStubField(uint32_t offset) {
return mozilla::BitwiseCast<jsid>(readStubWord(offset, StubField::Type::Id));
}
template <typename T>
T rawWordStubField(uint32_t offset) {
static_assert(sizeof(T) == sizeof(uintptr_t), "T must have word size");
@ -599,7 +560,7 @@ IonCacheIRCompiler::compile()
allocator.nextOp();
} while (reader.more());
MOZ_ASSERT(nextStubField_ == writer_.numStubFields());
MOZ_RELEASE_ASSERT(nextStubField_ == writer_.numStubFields());
masm.assumeUnreachable("Should have returned from IC");
@ -2559,7 +2520,7 @@ IonIC::attachCacheIRStub(JSContext* cx, const CacheIRWriter& writer, CacheKind k
writer.copyStubData(newStub->stubDataStart());
JitContext jctx(cx, nullptr);
IonCacheIRCompiler compiler(cx, writer, this, ionScript, newStub, typeCheckInfo);
IonCacheIRCompiler compiler(cx, writer, this, ionScript, newStub, typeCheckInfo, stubDataOffset);
if (!compiler.init())
return;

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

@ -19,8 +19,9 @@
#endif
#include "jsapi.h"
#include "mozilla/Maybe.h"
#include "jsapi.h"
#include "frontend/BinSource.h"
#include "frontend/FullParseHandler.h"
@ -167,10 +168,16 @@ runTestFromPath(JSContext* cx, const char* path)
UsedNameTracker txtUsedNames(cx);
if (!txtUsedNames.init())
MOZ_CRASH("Couldn't initialize used names");
RootedScriptSourceObject sourceObject(cx, frontend::CreateScriptSourceObject(
cx, txtOptions, mozilla::Nothing()));
if (!sourceObject)
MOZ_CRASH("Couldn't initialize ScriptSourceObject");
js::frontend::Parser<js::frontend::FullParseHandler, char16_t> txtParser(
cx, allocScope.alloc(), txtOptions, txtSource.begin(), txtSource.length(),
/* foldConstants = */ false, txtUsedNames, nullptr,
nullptr);
nullptr, sourceObject);
if (!txtParser.checkOptions())
MOZ_CRASH("Bad options");

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

@ -4462,10 +4462,17 @@ JS_BufferIsCompilableUnit(JSContext* cx, HandleObject obj, const char* utf8, siz
frontend::UsedNameTracker usedNames(cx);
if (!usedNames.init())
return false;
RootedScriptSourceObject sourceObject(cx, frontend::CreateScriptSourceObject(cx, options,
mozilla::Nothing()));
if (!sourceObject)
return false;
frontend::Parser<frontend::FullParseHandler, char16_t> parser(cx, cx->tempLifoAlloc(),
options, chars, length,
/* foldConstants = */ true,
usedNames, nullptr, nullptr);
usedNames, nullptr, nullptr,
sourceObject);
JS::WarningReporter older = JS::SetWarningReporter(cx, nullptr);
if (!parser.checkOptions() || !parser.parse()) {
// We ran into an error. If it was because we ran out of source, we

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

@ -2688,12 +2688,16 @@ static size_t
FormatTime(char* buf, int buflen, const char* fmt, double utcTime, double localTime)
{
PRMJTime prtm = ToPRMJTime(localTime, utcTime);
int eqivalentYear = IsRepresentableAsTime32(utcTime)
? prtm.tm_year
: EquivalentYearForDST(prtm.tm_year);
// If an equivalent year was used to compute the date/time components, use
// the same equivalent year to determine the time zone name and offset in
// PRMJ_FormatTime(...).
int timeZoneYear = IsRepresentableAsTime32(utcTime)
? prtm.tm_year
: EquivalentYearForDST(prtm.tm_year);
int offsetInSeconds = (int) floor((localTime - utcTime) / msPerSecond);
return PRMJ_FormatTime(buf, buflen, fmt, &prtm, eqivalentYear, offsetInSeconds);
return PRMJ_FormatTime(buf, buflen, fmt, &prtm, timeZoneYear, offsetInSeconds);
}
enum class FormatSpec {

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

@ -4486,9 +4486,15 @@ Parse(JSContext* cx, unsigned argc, Value* vp)
UsedNameTracker usedNames(cx);
if (!usedNames.init())
return false;
RootedScriptSourceObject sourceObject(cx, frontend::CreateScriptSourceObject(cx, options,
Nothing()));
if (!sourceObject)
return false;
Parser<FullParseHandler, char16_t> parser(cx, cx->tempLifoAlloc(), options, chars, length,
/* foldConstants = */ false, usedNames, nullptr,
nullptr);
nullptr, sourceObject);
if (!parser.checkOptions())
return false;
@ -4537,9 +4543,16 @@ SyntaxParse(JSContext* cx, unsigned argc, Value* vp)
UsedNameTracker usedNames(cx);
if (!usedNames.init())
return false;
RootedScriptSourceObject sourceObject(cx, frontend::CreateScriptSourceObject(cx, options,
Nothing()));
if (!sourceObject)
return false;
Parser<frontend::SyntaxParseHandler, char16_t> parser(cx, cx->tempLifoAlloc(),
options, chars, length, false,
usedNames, nullptr, nullptr);
usedNames, nullptr, nullptr,
sourceObject);
if (!parser.checkOptions())
return false;

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

@ -5050,11 +5050,18 @@ Debugger::isCompilableUnit(JSContext* cx, unsigned argc, Value* vp)
frontend::UsedNameTracker usedNames(cx);
if (!usedNames.init())
return false;
RootedScriptSourceObject sourceObject(cx, frontend::CreateScriptSourceObject(cx, options,
Nothing()));
if (!sourceObject)
return false;
frontend::Parser<frontend::FullParseHandler, char16_t> parser(cx, cx->tempLifoAlloc(),
options, chars.twoByteChars(),
length,
/* foldConstants = */ true,
usedNames, nullptr, nullptr);
usedNames, nullptr, nullptr,
sourceObject);
JS::WarningReporter older = JS::SetWarningReporter(cx, nullptr);
if (!parser.checkOptions() || !parser.parse()) {
// We ran into an error. If it was because we ran out of memory we report

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

@ -7,10 +7,9 @@
#include "js/Id.h"
#include "js/RootingAPI.h"
const jsid JSID_EMPTY = { size_t(JSID_TYPE_SYMBOL) };
const jsid JSID_EMPTY = jsid::fromRawBits(size_t(JSID_TYPE_SYMBOL));
static const jsid voidIdValue = JSID_VOID;
static const jsid emptyIdValue = JSID_EMPTY;
const JS::HandleId JSID_VOIDHANDLE = JS::HandleId::fromMarkedLocation(&voidIdValue);
const JS::HandleId JSID_EMPTYHANDLE = JS::HandleId::fromMarkedLocation(&emptyIdValue);

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

@ -1090,10 +1090,10 @@ static bool
AddLazyFunctionsForCompartment(JSContext* cx, AutoObjectVector& lazyFunctions, AllocKind kind)
{
// Find all live root lazy functions in the compartment: those which have a
// source object, indicating that they have a parent, and which do not have
// an uncompiled enclosing script. The last condition is so that we don't
// compile lazy scripts whose enclosing scripts failed to compile,
// indicating that the lazy script did not escape the script.
// non-lazy enclosing script, and which do not have an uncompiled enclosing
// script. The last condition is so that we don't compile lazy scripts
// whose enclosing scripts failed to compile, indicating that the lazy
// script did not escape the script.
//
// Some LazyScripts have a non-null |JSScript* script| pointer. We still
// want to delazify in that case: this pointer is weak so the JSScript
@ -1113,7 +1113,7 @@ AddLazyFunctionsForCompartment(JSContext* cx, AutoObjectVector& lazyFunctions, A
if (fun->isInterpretedLazy()) {
LazyScript* lazy = fun->lazyScriptOrNull();
if (lazy && lazy->sourceObject() && !lazy->hasUncompiledEnclosingScript()) {
if (lazy && !lazy->isEnclosingScriptLazy() && !lazy->hasUncompletedEnclosingScript()) {
if (!lazyFunctions.append(fun))
return false;
}

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

@ -792,7 +792,7 @@ JSFunction::trace(JSTracer* trc)
// Functions can be be marked as interpreted despite having no script
// yet at some points when parsing, and can be lazy with no lazy script
// for self-hosted code.
if (hasScript() && !hasUncompiledScript())
if (hasScript() && !hasUncompletedScript())
TraceManuallyBarrieredEdge(trc, &u.scripted.s.script_, "script");
else if (isInterpretedLazy() && u.scripted.s.lazy_)
TraceManuallyBarrieredEdge(trc, &u.scripted.s.lazy_, "lazyScript");
@ -1655,7 +1655,7 @@ JSFunction::createScriptForLazilyInterpretedFunction(JSContext* cx, HandleFuncti
// XDR the newly delazified function.
if (script->scriptSource()->hasEncoder()) {
RootedScriptSourceObject sourceObject(cx, lazy->sourceObject());
RootedScriptSourceObject sourceObject(cx, &lazy->sourceObject());
if (!script->scriptSource()->xdrEncodeFunction(cx, fun, sourceObject))
return false;
}

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

@ -564,13 +564,13 @@ class JSFunction : public js::NativeObject
// The state of a JSFunction whose script errored out during bytecode
// compilation. Such JSFunctions are only reachable via GC iteration and
// not from script.
bool hasUncompiledScript() const {
bool hasUncompletedScript() const {
MOZ_ASSERT(hasScript());
return !u.scripted.s.script_;
}
JSScript* nonLazyScript() const {
MOZ_ASSERT(!hasUncompiledScript());
MOZ_ASSERT(!hasUncompletedScript());
return u.scripted.s.script_;
}

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

@ -909,6 +909,8 @@ js::XDRLazyScript(XDRState<mode>* xdr, HandleScope enclosingScope,
HandleScriptSourceObject sourceObject, HandleFunction fun,
MutableHandle<LazyScript*> lazy)
{
MOZ_ASSERT_IF(mode == XDR_DECODE, sourceObject);
JSContext* cx = xdr->cx();
{
@ -967,7 +969,7 @@ js::XDRLazyScript(XDRState<mode>* xdr, HandleScope enclosingScope,
if (mode == XDR_ENCODE)
func = innerFunctions[i];
MOZ_TRY(XDRInterpretedFunction(xdr, nullptr, nullptr, &func));
MOZ_TRY(XDRInterpretedFunction(xdr, nullptr, sourceObject, &func));
if (mode == XDR_DECODE)
innerFunctions[i] = func;
@ -3655,7 +3657,7 @@ js::CloneScriptIntoFunction(JSContext* cx, HandleScope enclosingScope, HandleFun
HandleScript src)
{
MOZ_ASSERT(fun->isInterpreted());
MOZ_ASSERT(!fun->hasScript() || fun->hasUncompiledScript());
MOZ_ASSERT(!fun->hasScript() || fun->hasUncompletedScript());
RootedScript dst(cx, CreateEmptyScriptForClone(cx, src));
if (!dst)
@ -4175,13 +4177,14 @@ JSScript::formalLivesInArgumentsObject(unsigned argSlot)
return argsObjAliasesFormals() && !formalIsAliased(argSlot);
}
LazyScript::LazyScript(JSFunction* fun, void* table, uint64_t packedFields,
LazyScript::LazyScript(JSFunction* fun, ScriptSourceObject& sourceObject,
void* table, uint64_t packedFields,
uint32_t sourceStart, uint32_t sourceEnd,
uint32_t toStringStart, uint32_t lineno, uint32_t column)
: script_(nullptr),
function_(fun),
enclosingScope_(nullptr),
sourceObject_(nullptr),
sourceObject_(&sourceObject),
table_(table),
packedFields_(packedFields),
sourceStart_(sourceStart),
@ -4191,6 +4194,9 @@ LazyScript::LazyScript(JSFunction* fun, void* table, uint64_t packedFields,
lineno_(lineno),
column_(column)
{
MOZ_ASSERT(function_);
MOZ_ASSERT(sourceObject_);
MOZ_ASSERT(function_->compartment() == sourceObject_->compartment());
MOZ_ASSERT(sourceStart <= sourceEnd);
MOZ_ASSERT(toStringStart <= sourceStart);
}
@ -4211,36 +4217,33 @@ LazyScript::resetScript()
}
void
LazyScript::setEnclosingScopeAndSource(Scope* enclosingScope, ScriptSourceObject* sourceObject)
LazyScript::setEnclosingScope(Scope* enclosingScope)
{
MOZ_ASSERT(function_->compartment() == sourceObject->compartment());
// This method may be called to update the enclosing scope. See comment
// above the callsite in BytecodeEmitter::emitFunction.
MOZ_ASSERT_IF(sourceObject_, sourceObject_ == sourceObject && enclosingScope_);
MOZ_ASSERT_IF(!sourceObject_, !enclosingScope_);
enclosingScope_ = enclosingScope;
sourceObject_ = sourceObject;
}
ScriptSourceObject*
ScriptSourceObject&
LazyScript::sourceObject() const
{
return sourceObject_ ? &sourceObject_->as<ScriptSourceObject>() : nullptr;
return sourceObject_->as<ScriptSourceObject>();
}
ScriptSource*
LazyScript::maybeForwardedScriptSource() const
{
JSObject* source = MaybeForwarded(sourceObject());
JSObject* source = MaybeForwarded(&sourceObject());
return UncheckedUnwrapWithoutExpose(source)->as<ScriptSourceObject>().source();
}
/* static */ LazyScript*
LazyScript::CreateRaw(JSContext* cx, HandleFunction fun,
HandleScriptSourceObject sourceObject,
uint64_t packedFields, uint32_t sourceStart, uint32_t sourceEnd,
uint32_t toStringStart, uint32_t lineno, uint32_t column)
{
MOZ_ASSERT(sourceObject);
union {
PackedView p;
uint64_t packed;
@ -4267,12 +4270,13 @@ LazyScript::CreateRaw(JSContext* cx, HandleFunction fun,
cx->compartment()->scheduleDelazificationForDebugger();
return new (res) LazyScript(fun, table.forget(), packed, sourceStart, sourceEnd,
return new (res) LazyScript(fun, *sourceObject, table.forget(), packed, sourceStart, sourceEnd,
toStringStart, lineno, column);
}
/* static */ LazyScript*
LazyScript::Create(JSContext* cx, HandleFunction fun,
HandleScriptSourceObject sourceObject,
const frontend::AtomVector& closedOverBindings,
Handle<GCVector<JSFunction*, 8>> innerFunctions,
uint32_t sourceStart, uint32_t sourceEnd,
@ -4298,7 +4302,8 @@ LazyScript::Create(JSContext* cx, HandleFunction fun,
p.isDerivedClassConstructor = false;
p.needsHomeObject = false;
LazyScript* res = LazyScript::CreateRaw(cx, fun, packedFields, sourceStart, sourceEnd,
LazyScript* res = LazyScript::CreateRaw(cx, fun, sourceObject, packedFields,
sourceStart, sourceEnd,
toStringStart, lineno, column);
if (!res)
return nullptr;
@ -4328,7 +4333,8 @@ LazyScript::Create(JSContext* cx, HandleFunction fun,
// holding this lazy script.
HandleFunction dummyFun = fun;
LazyScript* res = LazyScript::CreateRaw(cx, fun, packedFields, sourceStart, sourceEnd,
LazyScript* res = LazyScript::CreateRaw(cx, fun, sourceObject, packedFields,
sourceStart, sourceEnd,
toStringStart, lineno, column);
if (!res)
return nullptr;
@ -4344,15 +4350,13 @@ LazyScript::Create(JSContext* cx, HandleFunction fun,
for (i = 0, num = res->numInnerFunctions(); i < num; i++)
functions[i].init(dummyFun);
// Set the enclosing scope and source object of the lazy function. These
// values should only be non-null if we have a non-lazy enclosing script.
// AddLazyFunctionsForCompartment relies on the source object being null
// if we're nested inside another lazy function.
MOZ_ASSERT(!!sourceObject == !!enclosingScope);
MOZ_ASSERT(!res->sourceObject());
// Set the enclosing scope of the lazy function. This value should only be
// non-null if we have a non-lazy enclosing script.
// LazyScript::isEnclosingScriptLazy relies on the enclosing scope being
// null if we're nested inside another lazy function.
MOZ_ASSERT(!res->enclosingScope());
if (sourceObject)
res->setEnclosingScopeAndSource(enclosingScope, sourceObject);
if (enclosingScope)
res->setEnclosingScope(enclosingScope);
MOZ_ASSERT(!res->hasScript());
if (script)
@ -4375,7 +4379,7 @@ LazyScript::initRuntimeFields(uint64_t packedFields)
}
bool
LazyScript::hasUncompiledEnclosingScript() const
LazyScript::hasUncompletedEnclosingScript() const
{
// It can happen that we created lazy scripts while compiling an enclosing
// script, but we errored out while compiling that script. When we iterate
@ -4389,7 +4393,7 @@ LazyScript::hasUncompiledEnclosingScript() const
return false;
JSFunction* fun = enclosingScope()->as<FunctionScope>().canonicalFunction();
return !fun->hasScript() || fun->hasUncompiledScript() || !fun->nonLazyScript()->code();
return !fun->hasScript() || fun->hasUncompletedScript() || !fun->nonLazyScript()->code();
}
void
@ -4502,11 +4506,7 @@ JS::ubi::Concrete<js::LazyScript>::size(mozilla::MallocSizeOf mallocSizeOf) cons
const char*
JS::ubi::Concrete<js::LazyScript>::scriptFilename() const
{
auto sourceObject = get().sourceObject();
if (!sourceObject)
return nullptr;
auto source = sourceObject->source();
auto source = get().sourceObject().source();
if (!source)
return nullptr;

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

@ -2159,7 +2159,8 @@ class LazyScript : public gc::TenuredCell
uint32_t lineno_;
uint32_t column_;
LazyScript(JSFunction* fun, void* table, uint64_t packedFields,
LazyScript(JSFunction* fun, ScriptSourceObject& sourceObject,
void* table, uint64_t packedFields,
uint32_t begin, uint32_t end, uint32_t toStringStart,
uint32_t lineno, uint32_t column);
@ -2167,6 +2168,7 @@ class LazyScript : public gc::TenuredCell
// innerFunctions. To be GC-safe, the caller must initialize both vectors
// with valid atoms and functions.
static LazyScript* CreateRaw(JSContext* cx, HandleFunction fun,
HandleScriptSourceObject sourceObject,
uint64_t packedData, uint32_t begin, uint32_t end,
uint32_t toStringStart, uint32_t lineno, uint32_t column);
@ -2177,6 +2179,7 @@ class LazyScript : public gc::TenuredCell
// Create a LazyScript and initialize closedOverBindings and innerFunctions
// with the provided vectors.
static LazyScript* Create(JSContext* cx, HandleFunction fun,
HandleScriptSourceObject sourceObject,
const frontend::AtomVector& closedOverBindings,
Handle<GCVector<JSFunction*, 8>> innerFunctions,
uint32_t begin, uint32_t end,
@ -2221,16 +2224,16 @@ class LazyScript : public gc::TenuredCell
return enclosingScope_;
}
ScriptSourceObject* sourceObject() const;
ScriptSourceObject& sourceObject() const;
ScriptSource* scriptSource() const {
return sourceObject()->source();
return sourceObject().source();
}
ScriptSource* maybeForwardedScriptSource() const;
bool mutedErrors() const {
return scriptSource()->mutedErrors();
}
void setEnclosingScopeAndSource(Scope* enclosingScope, ScriptSourceObject* sourceObject);
void setEnclosingScope(Scope* enclosingScope);
uint32_t numClosedOverBindings() const {
return p_.numClosedOverBindings;
@ -2382,7 +2385,14 @@ class LazyScript : public gc::TenuredCell
toStringEnd_ = toStringEnd;
}
bool hasUncompiledEnclosingScript() const;
// Returns true if the enclosing script failed to compile.
// See the comment in the definition for more details.
bool hasUncompletedEnclosingScript() const;
// Returns true if the enclosing script is also lazy.
bool isEnclosingScriptLazy() const {
return !enclosingScope_;
}
friend class GCMarker;
void traceChildren(JSTracer* trc);

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

@ -262,7 +262,7 @@ PRMJ_InvalidParameterHandler(const wchar_t* expression,
/* Format a time value into a buffer. Same semantics as strftime() */
size_t
PRMJ_FormatTime(char* buf, int buflen, const char* fmt, const PRMJTime* prtm,
int equivalentYear, int offsetInSeconds)
int timeZoneYear, int offsetInSeconds)
{
size_t result = 0;
#if defined(XP_UNIX) || defined(XP_WIN)
@ -295,7 +295,8 @@ PRMJ_FormatTime(char* buf, int buflen, const char* fmt, const PRMJTime* prtm,
* Fill out |td| to the time represented by |prtm|, leaving the
* timezone fields zeroed out. localtime_r will then fill in the
* timezone fields for that local time according to the system's
* timezone parameters.
* timezone parameters. Use |timeZoneYear| for the year to ensure the
* time zone name matches the time zone offset used by the caller.
*/
struct tm td;
memset(&td, 0, sizeof(td));
@ -305,19 +306,12 @@ PRMJ_FormatTime(char* buf, int buflen, const char* fmt, const PRMJTime* prtm,
td.tm_mday = prtm->tm_mday;
td.tm_mon = prtm->tm_mon;
td.tm_wday = prtm->tm_wday;
td.tm_year = prtm->tm_year - 1900;
td.tm_year = timeZoneYear - 1900;
td.tm_yday = prtm->tm_yday;
td.tm_isdst = prtm->tm_isdst;
time_t t = mktime(&td);
// If |prtm| cannot be represented in |time_t| the year is probably
// out of range, try again with the DST equivalent year.
if (t == static_cast<time_t>(-1)) {
td.tm_year = equivalentYear - 1900;
t = mktime(&td);
}
// If either mktime or localtime_r failed, fill in the fallback time
// zone offset |offsetInSeconds| and set the time zone identifier to
// the empty string.

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

@ -55,7 +55,7 @@ PRMJ_NowShutdown() {}
/* Format a time value into a buffer. Same semantics as strftime() */
extern size_t
PRMJ_FormatTime(char* buf, int buflen, const char* fmt, const PRMJTime* tm,
int equivalentYear, int offsetInSeconds);
int timeZoneYear, int offsetInSeconds);
/**

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

@ -1192,20 +1192,20 @@ class AstConversionOperator final : public AstExpr
};
#ifdef ENABLE_WASM_SATURATING_TRUNC_OPS
// Like AstConversionOperator, but for opcodes encoded with the Numeric prefix.
// Like AstConversionOperator, but for opcodes encoded with the Misc prefix.
class AstExtraConversionOperator final : public AstExpr
{
NumericOp op_;
MiscOp op_;
AstExpr* operand_;
public:
static const AstExprKind Kind = AstExprKind::ExtraConversionOperator;
explicit AstExtraConversionOperator(NumericOp op, AstExpr* operand)
explicit AstExtraConversionOperator(MiscOp op, AstExpr* operand)
: AstExpr(Kind, ExprType::Limit),
op_(op), operand_(operand)
{}
NumericOp op() const { return op_; }
MiscOp op() const { return op_; }
AstExpr* operand() const { return operand_; }
};
#endif

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

@ -9803,21 +9803,6 @@ BaseCompiler::emitBody()
case uint16_t(Op::CurrentMemory):
CHECK_NEXT(emitCurrentMemory());
#ifdef ENABLE_WASM_BULKMEM_OPS
// Bulk memory operations
case uint16_t(Op::CopyOrFillPrefix): {
switch (op.b1) {
case uint16_t(CopyOrFillOp::Copy):
CHECK_NEXT(emitMemCopy());
case uint16_t(CopyOrFillOp::Fill):
CHECK_NEXT(emitMemFill());
default:
return iter_.unrecognizedOpcode(&op);
}
break;
}
#endif
#ifdef ENABLE_WASM_GC
case uint16_t(Op::RefNull):
if (env_.gcTypesEnabled == HasGcTypes::False)
@ -9831,23 +9816,23 @@ BaseCompiler::emitBody()
break;
#endif
// Numeric operations
case uint16_t(Op::NumericPrefix): {
#ifdef ENABLE_WASM_SATURATING_TRUNC_OPS
// "Miscellaneous" operations
case uint16_t(Op::MiscPrefix): {
switch (op.b1) {
case uint16_t(NumericOp::I32TruncSSatF32):
#ifdef ENABLE_WASM_SATURATING_TRUNC_OPS
case uint16_t(MiscOp::I32TruncSSatF32):
CHECK_NEXT(emitConversionOOM(emitTruncateF32ToI32<TRUNC_SATURATING>,
ValType::F32, ValType::I32));
case uint16_t(NumericOp::I32TruncUSatF32):
case uint16_t(MiscOp::I32TruncUSatF32):
CHECK_NEXT(emitConversionOOM(emitTruncateF32ToI32<TRUNC_UNSIGNED | TRUNC_SATURATING>,
ValType::F32, ValType::I32));
case uint16_t(NumericOp::I32TruncSSatF64):
case uint16_t(MiscOp::I32TruncSSatF64):
CHECK_NEXT(emitConversionOOM(emitTruncateF64ToI32<TRUNC_SATURATING>,
ValType::F64, ValType::I32));
case uint16_t(NumericOp::I32TruncUSatF64):
case uint16_t(MiscOp::I32TruncUSatF64):
CHECK_NEXT(emitConversionOOM(emitTruncateF64ToI32<TRUNC_UNSIGNED | TRUNC_SATURATING>,
ValType::F64, ValType::I32));
case uint16_t(NumericOp::I64TruncSSatF32):
case uint16_t(MiscOp::I64TruncSSatF32):
#ifdef RABALDR_FLOAT_TO_I64_CALLOUT
CHECK_NEXT(emitCalloutConversionOOM(emitConvertFloatingToInt64Callout,
SymbolicAddress::SaturatingTruncateDoubleToInt64,
@ -9856,7 +9841,7 @@ BaseCompiler::emitBody()
CHECK_NEXT(emitConversionOOM(emitTruncateF32ToI64<TRUNC_SATURATING>,
ValType::F32, ValType::I64));
#endif
case uint16_t(NumericOp::I64TruncUSatF32):
case uint16_t(MiscOp::I64TruncUSatF32):
#ifdef RABALDR_FLOAT_TO_I64_CALLOUT
CHECK_NEXT(emitCalloutConversionOOM(emitConvertFloatingToInt64Callout,
SymbolicAddress::SaturatingTruncateDoubleToUint64,
@ -9865,7 +9850,7 @@ BaseCompiler::emitBody()
CHECK_NEXT(emitConversionOOM(emitTruncateF32ToI64<TRUNC_UNSIGNED | TRUNC_SATURATING>,
ValType::F32, ValType::I64));
#endif
case uint16_t(NumericOp::I64TruncSSatF64):
case uint16_t(MiscOp::I64TruncSSatF64):
#ifdef RABALDR_FLOAT_TO_I64_CALLOUT
CHECK_NEXT(emitCalloutConversionOOM(emitConvertFloatingToInt64Callout,
SymbolicAddress::SaturatingTruncateDoubleToInt64,
@ -9874,7 +9859,7 @@ BaseCompiler::emitBody()
CHECK_NEXT(emitConversionOOM(emitTruncateF64ToI64<TRUNC_SATURATING>,
ValType::F64, ValType::I64));
#endif
case uint16_t(NumericOp::I64TruncUSatF64):
case uint16_t(MiscOp::I64TruncUSatF64):
#ifdef RABALDR_FLOAT_TO_I64_CALLOUT
CHECK_NEXT(emitCalloutConversionOOM(emitConvertFloatingToInt64Callout,
SymbolicAddress::SaturatingTruncateDoubleToUint64,
@ -9883,13 +9868,17 @@ BaseCompiler::emitBody()
CHECK_NEXT(emitConversionOOM(emitTruncateF64ToI64<TRUNC_UNSIGNED | TRUNC_SATURATING>,
ValType::F64, ValType::I64));
#endif
#endif // ENABLE_WASM_SATURATING_TRUNC_OPS
#ifdef ENABLE_WASM_BULKMEM_OPS
case uint16_t(MiscOp::MemCopy):
CHECK_NEXT(emitMemCopy());
case uint16_t(MiscOp::MemFill):
CHECK_NEXT(emitMemFill());
#endif // ENABLE_WASM_BULKMEM_OPS
default:
return iter_.unrecognizedOpcode(&op);
}
break;
#else
break;
} // switch (op.b1)
return iter_.unrecognizedOpcode(&op);
#endif
}
// Thread operations

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

@ -336,9 +336,8 @@ enum class Op
RefNull = 0xd0,
RefIsNull = 0xd1,
FirstPrefix = 0xfb,
CopyOrFillPrefix = 0xfb,
NumericPrefix = 0xfc,
FirstPrefix = 0xfc,
MiscPrefix = 0xfc,
ThreadPrefix = 0xfe,
MozPrefix = 0xff,
@ -351,8 +350,8 @@ IsPrefixByte(uint8_t b)
return b >= uint8_t(Op::FirstPrefix);
}
// Opcodes in the "numeric" opcode space.
enum class NumericOp
// Opcodes in the "miscellaneous" opcode space.
enum class MiscOp
{
// Saturating float-to-int conversions
I32TruncSSatF32 = 0x00,
@ -364,6 +363,10 @@ enum class NumericOp
I64TruncSSatF64 = 0x06,
I64TruncUSatF64 = 0x07,
// Bulk memory operations. Note, these are unofficial.
MemCopy = 0x40,
MemFill = 0x41,
Limit
};

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

@ -714,7 +714,7 @@ AstDecodeConversion(AstDecodeContext& c, ValType fromType, ValType toType, Op op
#ifdef ENABLE_WASM_SATURATING_TRUNC_OPS
static bool
AstDecodeExtraConversion(AstDecodeContext& c, ValType fromType, ValType toType, NumericOp op)
AstDecodeExtraConversion(AstDecodeContext& c, ValType fromType, ValType toType, MiscOp op)
{
if (!c.iter().readConversion(fromType, toType, nullptr))
return false;
@ -1712,50 +1712,44 @@ AstDecodeExpr(AstDecodeContext& c)
if (!c.push(AstDecodeStackItem(tmp)))
return false;
break;
#ifdef ENABLE_WASM_BULKMEM_OPS
case uint16_t(Op::CopyOrFillPrefix):
case uint16_t(Op::MiscPrefix):
switch (op.b1) {
case uint16_t(CopyOrFillOp::Copy):
#ifdef ENABLE_WASM_SATURATING_TRUNC_OPS
case uint16_t(MiscOp::I32TruncSSatF32):
case uint16_t(MiscOp::I32TruncUSatF32):
if (!AstDecodeExtraConversion(c, ValType::F32, ValType::I32, MiscOp(op.b1)))
return false;
break;
case uint16_t(MiscOp::I32TruncSSatF64):
case uint16_t(MiscOp::I32TruncUSatF64):
if (!AstDecodeExtraConversion(c, ValType::F64, ValType::I32, MiscOp(op.b1)))
return false;
break;
case uint16_t(MiscOp::I64TruncSSatF32):
case uint16_t(MiscOp::I64TruncUSatF32):
if (!AstDecodeExtraConversion(c, ValType::F32, ValType::I64, MiscOp(op.b1)))
return false;
break;
case uint16_t(MiscOp::I64TruncSSatF64):
case uint16_t(MiscOp::I64TruncUSatF64):
if (!AstDecodeExtraConversion(c, ValType::F64, ValType::I64, MiscOp(op.b1)))
return false;
break;
#endif
#ifdef ENABLE_WASM_BULKMEM_OPS
case uint16_t(MiscOp::MemCopy):
if (!AstDecodeMemCopy(c))
return false;
break;
case uint16_t(CopyOrFillOp::Fill):
case uint16_t(MiscOp::MemFill):
if (!AstDecodeMemFill(c))
return false;
break;
#endif
default:
return c.iter().unrecognizedOpcode(&op);
}
break;
#endif
#ifdef ENABLE_WASM_SATURATING_TRUNC_OPS
case uint16_t(Op::NumericPrefix):
switch (op.b1) {
case uint16_t(NumericOp::I32TruncSSatF32):
case uint16_t(NumericOp::I32TruncUSatF32):
if (!AstDecodeExtraConversion(c, ValType::F32, ValType::I32, NumericOp(op.b1)))
return false;
break;
case uint16_t(NumericOp::I32TruncSSatF64):
case uint16_t(NumericOp::I32TruncUSatF64):
if (!AstDecodeExtraConversion(c, ValType::F64, ValType::I32, NumericOp(op.b1)))
return false;
break;
case uint16_t(NumericOp::I64TruncSSatF32):
case uint16_t(NumericOp::I64TruncUSatF32):
if (!AstDecodeExtraConversion(c, ValType::F32, ValType::I64, NumericOp(op.b1)))
return false;
break;
case uint16_t(NumericOp::I64TruncSSatF64):
case uint16_t(NumericOp::I64TruncUSatF64):
if (!AstDecodeExtraConversion(c, ValType::F64, ValType::I64, NumericOp(op.b1)))
return false;
break;
default:
return c.iter().unrecognizedOpcode(&op);
}
break;
#endif
case uint16_t(Op::ThreadPrefix):
switch (op.b1) {
case uint16_t(ThreadOp::Wake):

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

@ -762,14 +762,14 @@ RenderExtraConversionOperator(WasmRenderContext& c, AstExtraConversionOperator&
MAP_AST_EXPR(c, conv);
const char* opStr;
switch (conv.op()) {
case NumericOp::I32TruncSSatF32: opStr = "i32.trunc_s:sat/f32"; break;
case NumericOp::I32TruncUSatF32: opStr = "i32.trunc_u:sat/f32"; break;
case NumericOp::I32TruncSSatF64: opStr = "i32.trunc_s:sat/f64"; break;
case NumericOp::I32TruncUSatF64: opStr = "i32.trunc_u:sat/f64"; break;
case NumericOp::I64TruncSSatF32: opStr = "i64.trunc_s:sat/f32"; break;
case NumericOp::I64TruncUSatF32: opStr = "i64.trunc_u:sat/f32"; break;
case NumericOp::I64TruncSSatF64: opStr = "i64.trunc_s:sat/f64"; break;
case NumericOp::I64TruncUSatF64: opStr = "i64.trunc_u:sat/f64"; break;
case MiscOp::I32TruncSSatF32: opStr = "i32.trunc_s:sat/f32"; break;
case MiscOp::I32TruncUSatF32: opStr = "i32.trunc_u:sat/f32"; break;
case MiscOp::I32TruncSSatF64: opStr = "i32.trunc_s:sat/f64"; break;
case MiscOp::I32TruncUSatF64: opStr = "i32.trunc_u:sat/f64"; break;
case MiscOp::I64TruncSSatF32: opStr = "i64.trunc_s:sat/f32"; break;
case MiscOp::I64TruncUSatF32: opStr = "i64.trunc_u:sat/f32"; break;
case MiscOp::I64TruncSSatF64: opStr = "i64.trunc_s:sat/f64"; break;
case MiscOp::I64TruncUSatF64: opStr = "i64.trunc_u:sat/f64"; break;
default: return Fail(c, "unexpected extra conversion operator");
}
return c.buffer.append(opStr, strlen(opStr));

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

@ -4077,48 +4077,37 @@ EmitBodyExprs(FunctionCompiler& f)
CHECK(EmitSignExtend(f, 4, 8));
#endif
// Bulk memory operations
#ifdef ENABLE_WASM_BULKMEM_OPS
case uint16_t(Op::CopyOrFillPrefix): {
// Miscellaneous operations
case uint16_t(Op::MiscPrefix): {
switch (op.b1) {
case uint16_t(CopyOrFillOp::Copy):
CHECK(EmitMemCopy(f));
case uint16_t(CopyOrFillOp::Fill):
CHECK(EmitMemFill(f));
default:
return f.iter().unrecognizedOpcode(&op);
}
break;
}
#endif
// Numeric operations
case uint16_t(Op::NumericPrefix): {
#ifdef ENABLE_WASM_SATURATING_TRUNC_OPS
switch (op.b1) {
case uint16_t(NumericOp::I32TruncSSatF32):
case uint16_t(NumericOp::I32TruncUSatF32):
case uint16_t(MiscOp::I32TruncSSatF32):
case uint16_t(MiscOp::I32TruncUSatF32):
CHECK(EmitTruncate(f, ValType::F32, ValType::I32,
NumericOp(op.b1) == NumericOp::I32TruncUSatF32, true));
case uint16_t(NumericOp::I32TruncSSatF64):
case uint16_t(NumericOp::I32TruncUSatF64):
MiscOp(op.b1) == MiscOp::I32TruncUSatF32, true));
case uint16_t(MiscOp::I32TruncSSatF64):
case uint16_t(MiscOp::I32TruncUSatF64):
CHECK(EmitTruncate(f, ValType::F64, ValType::I32,
NumericOp(op.b1) == NumericOp::I32TruncUSatF64, true));
case uint16_t(NumericOp::I64TruncSSatF32):
case uint16_t(NumericOp::I64TruncUSatF32):
MiscOp(op.b1) == MiscOp::I32TruncUSatF64, true));
case uint16_t(MiscOp::I64TruncSSatF32):
case uint16_t(MiscOp::I64TruncUSatF32):
CHECK(EmitTruncate(f, ValType::F32, ValType::I64,
NumericOp(op.b1) == NumericOp::I64TruncUSatF32, true));
case uint16_t(NumericOp::I64TruncSSatF64):
case uint16_t(NumericOp::I64TruncUSatF64):
MiscOp(op.b1) == MiscOp::I64TruncUSatF32, true));
case uint16_t(MiscOp::I64TruncSSatF64):
case uint16_t(MiscOp::I64TruncUSatF64):
CHECK(EmitTruncate(f, ValType::F64, ValType::I64,
NumericOp(op.b1) == NumericOp::I64TruncUSatF64, true));
MiscOp(op.b1) == MiscOp::I64TruncUSatF64, true));
#endif
#ifdef ENABLE_WASM_BULKMEM_OPS
case uint16_t(MiscOp::MemCopy):
CHECK(EmitMemCopy(f));
case uint16_t(MiscOp::MemFill):
CHECK(EmitMemFill(f));
#endif
default:
return f.iter().unrecognizedOpcode(&op);
}
break;
#else
return f.iter().unrecognizedOpcode(&op);
#endif
}
// Thread operations

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

@ -241,37 +241,30 @@ wasm::Classify(OpBytes op)
return OpKind::CurrentMemory;
case Op::GrowMemory:
return OpKind::GrowMemory;
case Op::CopyOrFillPrefix: {
#ifdef ENABLE_WASM_BULKMEM_OPS
switch (CopyOrFillOp(op.b1)) {
case CopyOrFillOp::Copy:
return OpKind::MemCopy;
case CopyOrFillOp::Fill:
return OpKind::MemFill;
default:
break;
}
#endif
break;
}
case Op::RefNull:
return OpKind::RefNull;
case Op::NumericPrefix: {
case Op::MiscPrefix: {
switch (MiscOp(op.b1)) {
#ifdef ENABLE_WASM_SATURATING_TRUNC_OPS
switch (NumericOp(op.b1)) {
case NumericOp::I32TruncSSatF32:
case NumericOp::I32TruncUSatF32:
case NumericOp::I32TruncSSatF64:
case NumericOp::I32TruncUSatF64:
case NumericOp::I64TruncSSatF32:
case NumericOp::I64TruncUSatF32:
case NumericOp::I64TruncSSatF64:
case NumericOp::I64TruncUSatF64:
case MiscOp::I32TruncSSatF32:
case MiscOp::I32TruncUSatF32:
case MiscOp::I32TruncSSatF64:
case MiscOp::I32TruncUSatF64:
case MiscOp::I64TruncSSatF32:
case MiscOp::I64TruncUSatF32:
case MiscOp::I64TruncSSatF64:
case MiscOp::I64TruncUSatF64:
return OpKind::Conversion;
#endif
#ifdef ENABLE_WASM_BULKMEM_OPS
case MiscOp::MemCopy:
return OpKind::MemCopy;
case MiscOp::MemFill:
return OpKind::MemFill;
#endif
default:
break;
}
#endif
break;
}
case Op::ThreadPrefix: {

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

@ -153,7 +153,7 @@ class WasmToken
FloatLiteralKind floatLiteralKind_;
ValType valueType_;
Op op_;
NumericOp numericOp_;
MiscOp miscOp_;
ThreadOp threadOp_;
} u;
public:
@ -226,14 +226,14 @@ class WasmToken
u.op_ = op;
}
#ifdef ENABLE_WASM_SATURATING_TRUNC_OPS
explicit WasmToken(Kind kind, NumericOp op, const char16_t* begin, const char16_t* end)
explicit WasmToken(Kind kind, MiscOp op, const char16_t* begin, const char16_t* end)
: kind_(kind),
begin_(begin),
end_(end)
{
MOZ_ASSERT(begin != end);
MOZ_ASSERT(kind_ == ExtraConversionOpcode);
u.numericOp_ = op;
u.miscOp_ = op;
}
#endif
explicit WasmToken(Kind kind, ThreadOp op, const char16_t* begin, const char16_t* end)
@ -298,9 +298,9 @@ class WasmToken
return u.op_;
}
#ifdef ENABLE_WASM_SATURATING_TRUNC_OPS
NumericOp numericOp() const {
MiscOp miscOp() const {
MOZ_ASSERT(kind_ == ExtraConversionOpcode);
return u.numericOp_;
return u.miscOp_;
}
#endif
ThreadOp threadOp() const {
@ -1359,16 +1359,16 @@ WasmTokenStream::next()
begin, cur_);
#ifdef ENABLE_WASM_SATURATING_TRUNC_OPS
if (consume(u"trunc_s:sat/f32"))
return WasmToken(WasmToken::ExtraConversionOpcode, NumericOp::I32TruncSSatF32,
return WasmToken(WasmToken::ExtraConversionOpcode, MiscOp::I32TruncSSatF32,
begin, cur_);
if (consume(u"trunc_s:sat/f64"))
return WasmToken(WasmToken::ExtraConversionOpcode, NumericOp::I32TruncSSatF64,
return WasmToken(WasmToken::ExtraConversionOpcode, MiscOp::I32TruncSSatF64,
begin, cur_);
if (consume(u"trunc_u:sat/f32"))
return WasmToken(WasmToken::ExtraConversionOpcode, NumericOp::I32TruncUSatF32,
return WasmToken(WasmToken::ExtraConversionOpcode, MiscOp::I32TruncUSatF32,
begin, cur_);
if (consume(u"trunc_u:sat/f64"))
return WasmToken(WasmToken::ExtraConversionOpcode, NumericOp::I32TruncUSatF64,
return WasmToken(WasmToken::ExtraConversionOpcode, MiscOp::I32TruncUSatF64,
begin, cur_);
#endif
break;
@ -1609,16 +1609,16 @@ WasmTokenStream::next()
begin, cur_);
#ifdef ENABLE_WASM_SATURATING_TRUNC_OPS
if (consume(u"trunc_s:sat/f32"))
return WasmToken(WasmToken::ExtraConversionOpcode, NumericOp::I64TruncSSatF32,
return WasmToken(WasmToken::ExtraConversionOpcode, MiscOp::I64TruncSSatF32,
begin, cur_);
if (consume(u"trunc_s:sat/f64"))
return WasmToken(WasmToken::ExtraConversionOpcode, NumericOp::I64TruncSSatF64,
return WasmToken(WasmToken::ExtraConversionOpcode, MiscOp::I64TruncSSatF64,
begin, cur_);
if (consume(u"trunc_u:sat/f32"))
return WasmToken(WasmToken::ExtraConversionOpcode, NumericOp::I64TruncUSatF32,
return WasmToken(WasmToken::ExtraConversionOpcode, MiscOp::I64TruncUSatF32,
begin, cur_);
if (consume(u"trunc_u:sat/f64"))
return WasmToken(WasmToken::ExtraConversionOpcode, NumericOp::I64TruncUSatF64,
return WasmToken(WasmToken::ExtraConversionOpcode, MiscOp::I64TruncUSatF64,
begin, cur_);
#endif
break;
@ -2454,7 +2454,7 @@ ParseConversionOperator(WasmParseContext& c, Op op, bool inParens)
#ifdef ENABLE_WASM_SATURATING_TRUNC_OPS
static AstExtraConversionOperator*
ParseExtraConversionOperator(WasmParseContext& c, NumericOp op, bool inParens)
ParseExtraConversionOperator(WasmParseContext& c, MiscOp op, bool inParens)
{
AstExpr* operand = ParseExpr(c, inParens);
if (!operand)
@ -3056,7 +3056,7 @@ ParseExprBody(WasmParseContext& c, WasmToken token, bool inParens)
return ParseConversionOperator(c, token.op(), inParens);
#ifdef ENABLE_WASM_SATURATING_TRUNC_OPS
case WasmToken::ExtraConversionOpcode:
return ParseExtraConversionOperator(c, token.numericOp(), inParens);
return ParseExtraConversionOperator(c, token.miscOp(), inParens);
#endif
case WasmToken::Drop:
return ParseDrop(c, inParens);
@ -5051,7 +5051,7 @@ EncodeMemCopy(Encoder& e, AstMemCopy& s)
return EncodeExpr(e, s.dest()) &&
EncodeExpr(e, s.src()) &&
EncodeExpr(e, s.len()) &&
e.writeOp(CopyOrFillOp::Copy);
e.writeOp(MiscOp::MemCopy);
}
static bool
@ -5060,7 +5060,7 @@ EncodeMemFill(Encoder& e, AstMemFill& s)
return EncodeExpr(e, s.start()) &&
EncodeExpr(e, s.val()) &&
EncodeExpr(e, s.len()) &&
e.writeOp(CopyOrFillOp::Fill);
e.writeOp(MiscOp::MemFill);
}
#endif

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

@ -801,28 +801,26 @@ DecodeFunctionBodyExprs(const ModuleEnvironment& env, const Sig& sig, const ValT
CHECK(iter.readReturn(&nothing));
case uint16_t(Op::Unreachable):
CHECK(iter.readUnreachable());
case uint16_t(Op::NumericPrefix): {
#ifdef ENABLE_WASM_SATURATING_TRUNC_OPS
case uint16_t(Op::MiscPrefix): {
switch (op.b1) {
case uint16_t(NumericOp::I32TruncSSatF32):
case uint16_t(NumericOp::I32TruncUSatF32):
#ifdef ENABLE_WASM_SATURATING_TRUNC_OPS
case uint16_t(MiscOp::I32TruncSSatF32):
case uint16_t(MiscOp::I32TruncUSatF32):
CHECK(iter.readConversion(ValType::F32, ValType::I32, &nothing));
case uint16_t(NumericOp::I32TruncSSatF64):
case uint16_t(NumericOp::I32TruncUSatF64):
case uint16_t(MiscOp::I32TruncSSatF64):
case uint16_t(MiscOp::I32TruncUSatF64):
CHECK(iter.readConversion(ValType::F64, ValType::I32, &nothing));
case uint16_t(NumericOp::I64TruncSSatF32):
case uint16_t(NumericOp::I64TruncUSatF32):
case uint16_t(MiscOp::I64TruncSSatF32):
case uint16_t(MiscOp::I64TruncUSatF32):
CHECK(iter.readConversion(ValType::F32, ValType::I64, &nothing));
case uint16_t(NumericOp::I64TruncSSatF64):
case uint16_t(NumericOp::I64TruncUSatF64):
case uint16_t(MiscOp::I64TruncSSatF64):
case uint16_t(MiscOp::I64TruncUSatF64):
CHECK(iter.readConversion(ValType::F64, ValType::I64, &nothing));
#endif
default:
return iter.unrecognizedOpcode(&op);
}
break;
#else
return iter.unrecognizedOpcode(&op);
#endif
}
#ifdef ENABLE_WASM_GC
case uint16_t(Op::RefNull): {

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

@ -282,22 +282,10 @@ class Encoder
MOZ_ASSERT(size_t(op) < size_t(Op::Limit));
return writeFixedU8(uint8_t(op));
}
MOZ_MUST_USE bool writeOp(MozOp op) {
static_assert(size_t(MozOp::Limit) <= 256, "fits");
MOZ_ASSERT(size_t(op) < size_t(MozOp::Limit));
return writeFixedU8(uint8_t(Op::MozPrefix)) &&
writeFixedU8(uint8_t(op));
}
MOZ_MUST_USE bool writeOp(CopyOrFillOp op) {
static_assert(size_t(CopyOrFillOp::Limit) <= 256, "fits");
MOZ_ASSERT(size_t(op) < size_t(CopyOrFillOp::Limit));
return writeFixedU8(uint8_t(Op::CopyOrFillPrefix)) &&
writeFixedU8(uint8_t(op));
}
MOZ_MUST_USE bool writeOp(NumericOp op) {
static_assert(size_t(NumericOp::Limit) <= 256, "fits");
MOZ_ASSERT(size_t(op) < size_t(NumericOp::Limit));
return writeFixedU8(uint8_t(Op::NumericPrefix)) &&
MOZ_MUST_USE bool writeOp(MiscOp op) {
static_assert(size_t(MiscOp::Limit) <= 256, "fits");
MOZ_ASSERT(size_t(op) < size_t(MiscOp::Limit));
return writeFixedU8(uint8_t(Op::MiscPrefix)) &&
writeFixedU8(uint8_t(op));
}
MOZ_MUST_USE bool writeOp(ThreadOp op) {
@ -306,6 +294,12 @@ class Encoder
return writeFixedU8(uint8_t(Op::ThreadPrefix)) &&
writeFixedU8(uint8_t(op));
}
MOZ_MUST_USE bool writeOp(MozOp op) {
static_assert(size_t(MozOp::Limit) <= 256, "fits");
MOZ_ASSERT(size_t(op) < size_t(MozOp::Limit));
return writeFixedU8(uint8_t(Op::MozPrefix)) &&
writeFixedU8(uint8_t(op));
}
// Fixed-length encodings that allow back-patching.

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

@ -29,7 +29,7 @@ skip-if = toolkit == 'android' # Bug 1355815
[test_bug386575.xhtml]
[test_bug388019.html]
[test_bug394057.html]
skip-if = toolkit == 'android' # Bug 1355817
skip-if = toolkit == 'android' || (os == 'win' && asan) # Bug 1355817, bug 1460993
[test_bug399284.html]
[test_bug399951.html]
[test_bug404209.xhtml]

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

@ -670,7 +670,7 @@ MathMLTextRunFactory::RebuildTextRun(nsTransformedTextRun* aTextRun,
// Bug 930504. Some platforms do not have fonts for Mathematical
// Alphanumeric Symbols. Hence we check whether the transformed
// character is actually available.
uint8_t matchType;
gfxTextRange::MatchType matchType;
RefPtr<gfxFont> mathFont = fontGroup->
FindFontForChar(ch2, 0, 0, unicode::Script::COMMON, nullptr, &matchType);
if (mathFont) {

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

@ -22,19 +22,19 @@ namespace dom {
bool
InspectorFontFace::FromFontGroup()
{
return mMatchType & gfxTextRange::kFontGroup;
return bool(mMatchType & gfxTextRange::MatchType::kFontGroup);
}
bool
InspectorFontFace::FromLanguagePrefs()
{
return mMatchType & gfxTextRange::kPrefsFallback;
return bool(mMatchType & gfxTextRange::MatchType::kPrefsFallback);
}
bool
InspectorFontFace::FromSystemFallback()
{
return mMatchType & gfxTextRange::kSystemFallback;
return bool(mMatchType & gfxTextRange::MatchType::kSystemFallback);
}
void

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

@ -11,8 +11,8 @@
#include "mozilla/dom/InspectorUtilsBinding.h"
#include "mozilla/dom/NonRefcountedDOMObject.h"
#include "nsRange.h"
#include "gfxFont.h"
class gfxFontEntry;
class gfxFontGroup;
namespace mozilla {
@ -27,7 +27,7 @@ class InspectorFontFace final : public NonRefcountedDOMObject
public:
InspectorFontFace(gfxFontEntry* aFontEntry,
gfxFontGroup* aFontGroup,
uint8_t aMatchType)
gfxTextRange::MatchType aMatchType)
: mFontEntry(aFontEntry)
, mFontGroup(aFontGroup)
, mMatchType(aMatchType)
@ -41,7 +41,9 @@ public:
}
gfxFontEntry* GetFontEntry() const { return mFontEntry; }
void AddMatchType(uint8_t aMatchType) { mMatchType |= aMatchType; }
void AddMatchType(gfxTextRange::MatchType aMatchType) {
mMatchType |= aMatchType;
}
void AddRange(nsRange* aRange);
size_t RangeCount() const {
@ -81,7 +83,7 @@ protected:
RefPtr<gfxFontEntry> mFontEntry;
RefPtr<gfxFontGroup> mFontGroup;
RefPtr<ServoFontFaceRule> mRule;
uint8_t mMatchType;
gfxTextRange::MatchType mMatchType;
nsTArray<RefPtr<nsRange>> mRanges;
};

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

@ -578,7 +578,7 @@ nsOpenTypeTable::MakeTextRun(DrawTarget* aDrawTarget,
gfxTextRun::Create(&params, 1, aFontGroup,
gfx::ShapedTextFlags(), nsTextFrameUtils::Flags());
textRun->AddGlyphRun(aFontGroup->GetFirstValidFont(),
gfxTextRange::kFontGroup, 0,
gfxTextRange::MatchType::kFontGroup, 0,
false, gfx::ShapedTextFlags::TEXT_ORIENT_HORIZONTAL);
// We don't care about CSS writing mode here;
// math runs are assumed to be horizontal.

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

@ -356,6 +356,9 @@ public class SessionAccessibility {
node.setCheckable(message.getBoolean("checkable"));
node.setChecked(message.getBoolean("checked"));
node.setPassword(message.getBoolean("password"));
node.setFocusable(message.getBoolean("focusable"));
node.setFocused(message.getBoolean("focused"));
node.setEditable(message.getBoolean("editable"));
final String[] textArray = message.getStringArray("text");
StringBuilder sb = new StringBuilder();
@ -418,7 +421,10 @@ public class SessionAccessibility {
}
}
if (eventSource != View.NO_ID) {
if (eventSource != View.NO_ID &&
(eventType == AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED ||
eventType == AccessibilityEvent.TYPE_VIEW_FOCUSED ||
eventType == AccessibilityEvent.TYPE_VIEW_HOVER_ENTER)) {
// In Jelly Bean we populate an AccessibilityNodeInfo with the minimal amount of data to have
// it work with TalkBack.
if (mVirtualContentNode == null) {

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

@ -1453,12 +1453,3 @@ nsNSSCertificateDB::OpenSignedAppFileAsync(
aCallback));
return task->Dispatch("SignedJAR");
}
NS_IMETHODIMP
nsNSSCertificateDB::VerifySignedDirectoryAsync(AppTrustedRoot, nsIFile*,
nsIVerifySignedDirectoryCallback* aCallback)
{
NS_ENSURE_ARG_POINTER(aCallback);
return aCallback->VerifySignedDirectoryFinished(
NS_ERROR_SIGNED_JAR_NOT_SIGNED, nullptr);
}

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

@ -28,15 +28,6 @@ interface nsIOpenSignedAppFileCallback : nsISupports
in nsIX509Cert aSignerCert);
};
// Only relevant while we transition away from legacy add-ons. rv will always be
// NS_ERROR_SIGNED_JAR_NOT_SIGNED. aSignerCert will always be null.
[scriptable, function, uuid(d5f97827-622a-488f-be08-d850432ac8ec)]
interface nsIVerifySignedDirectoryCallback : nsISupports
{
void verifySignedDirectoryFinished(in nsresult rv,
in nsIX509Cert aSignerCert);
};
/**
* Callback type for use with asyncVerifyCertAtTime.
* If aPRErrorCode is PRErrorCodeSuccess (i.e. 0), aVerifiedChain represents the
@ -258,16 +249,6 @@ interface nsIX509CertDB : nsISupports {
in nsIFile aJarFile,
in nsIOpenSignedAppFileCallback callback);
/**
* Vestigial implementation of verifying signed unpacked add-ons. trustedRoot
* and aUnpackedDir are ignored. The callback is always called with
* NS_ERROR_SIGNED_JAR_NOT_SIGNED and a null signer cert.
*/
[must_use]
void verifySignedDirectoryAsync(in AppTrustedRoot trustedRoot,
in nsIFile aUnpackedDir,
in nsIVerifySignedDirectoryCallback callback);
/*
* Add a cert to a cert DB from a binary string.
*

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

@ -1,68 +0,0 @@
// Any copyright is dedicated to the Public Domain.
// http://creativecommons.org/publicdomain/zero/1.0/
"use strict";
// Tests that signed extensions extracted/unpacked into a directory do not pass
// signature verification, because that's no longer supported.
const { ZipUtils } = ChromeUtils.import("resource://gre/modules/ZipUtils.jsm", {});
do_get_profile(); // must be called before getting nsIX509CertDB
const certdb = Cc["@mozilla.org/security/x509certdb;1"]
.getService(Ci.nsIX509CertDB);
/**
* Signed test extension. This is any arbitrary Mozilla signed XPI that
* preferably has recently been signed (but note that it actually doesn't
* matter, since we ignore expired certificates when checking signing).
* @type nsIFile
*/
var gSignedXPI =
do_get_file("test_signed_dir/lightbeam_for_firefox-1.3.1-fx.xpi", false);
/**
* The directory that the test extension will be extracted to.
* @type nsIFile
*/
var gTarget = FileUtils.getDir("TmpD", ["test_signed_dir"]);
gTarget.createUnique(Ci.nsIFile.DIRECTORY_TYPE, FileUtils.PERMS_DIRECTORY);
/**
* Extracts the signed XPI into a directory, and tampers the files in that
* directory if instructed.
*
* @returns {nsIFile}
* The directory where the XPI was extracted to.
*/
function prepare() {
ZipUtils.extractFiles(gSignedXPI, gTarget);
return gTarget;
}
function checkResult(expectedRv, dir, resolve) {
return function verifySignedDirCallback(rv, aSignerCert) {
equal(rv, expectedRv, "Actual and expected return value should match");
equal(aSignerCert != null, Components.isSuccessCode(expectedRv),
"expecting certificate:");
dir.remove(true);
resolve();
};
}
function verifyDirAsync(expectedRv) {
let targetDir = prepare();
return new Promise((resolve, reject) => {
certdb.verifySignedDirectoryAsync(
Ci.nsIX509CertDB.AddonsPublicRoot, targetDir,
checkResult(expectedRv, targetDir, resolve));
});
}
add_task(async function testAPIFails() {
await verifyDirAsync(Cr.NS_ERROR_SIGNED_JAR_NOT_SIGNED);
});
registerCleanupFunction(function() {
if (gTarget.exists()) {
gTarget.remove(true);
}
});

Двоичный файл не отображается.

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

@ -31,7 +31,6 @@ support-files =
test_sdr_preexisting/**
test_sdr_preexisting_with_password/**
test_signed_apps/**
test_signed_dir/**
test_startcom_wosign/**
test_symantec_apple_google/**
test_validity/**
@ -150,8 +149,6 @@ skip-if = toolkit == 'android'
[test_session_resumption.js]
run-sequentially = hardcoded ports
[test_signed_apps.js]
[test_signed_dir.js]
tags = addons psm
[test_ssl_status.js]
[test_sss_enumerate.js]
[test_sss_eviction.js]

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

@ -22,6 +22,17 @@ awsy:
.*-devedition/.*: [] # don't run on devedition
default: built-projects
awsy-base:
description: "Are we slim yet - about:blank base case"
treeherder-symbol: SY(ab)
run-on-projects:
by-test-platform:
.*-devedition/.*: [] # don't run on devedition
default: built-projects
mozharness:
extra-options:
- --base
awsy-stylo-sequential:
description: "Are we slim yet for Stylo sequential"
treeherder-symbol: SYss(sy)

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

@ -82,6 +82,7 @@ talos:
awsy:
- awsy
- awsy-base
awsy-stylo-sequential:
- awsy-stylo-sequential

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

@ -0,0 +1,373 @@
# 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/.
import fnmatch
import glob
import gzip
import json
import os
import sys
import time
import shutil
import tempfile
from marionette_harness import MarionetteTestCase
from marionette_driver import Actions
from marionette_driver.errors import JavascriptException, ScriptTimeoutException
import mozlog.structured
from marionette_driver.keys import Keys
AWSY_PATH = os.path.dirname(os.path.dirname(os.path.realpath(__file__)))
if AWSY_PATH not in sys.path:
sys.path.append(AWSY_PATH)
from awsy import ITERATIONS, PER_TAB_PAUSE, SETTLE_WAIT_TIME, MAX_TABS
from awsy import process_perf_data
class AwsyTestCase(MarionetteTestCase):
"""
Base test case for AWSY tests.
"""
def urls(self):
raise NotImplementedError()
def perf_suites(self):
raise NotImplementedError()
def perf_checkpoints(self):
raise NotImplementedError()
def iterations(self):
return self._iterations
def pages_to_load(self):
return self._pages_to_load if self._pages_to_load else len(self.urls())
def settle(self):
"""
Pauses for the settle time.
"""
time.sleep(self._settleWaitTime)
def setUp(self):
MarionetteTestCase.setUp(self)
self.logger = mozlog.structured.structuredlog.get_default_logger()
self.marionette.set_context('chrome')
self._resultsDir = self.testvars["resultsDir"]
# Cleanup our files from previous runs.
for patt in ('memory-report-*.json.gz',
'perfherder_data.json',
'dmd-*.json.gz'):
for f in glob.glob(os.path.join(self._resultsDir, patt)):
os.unlink(f)
# Optional testvars.
self._pages_to_load = self.testvars.get("entities", 0)
self._iterations = self.testvars.get("iterations", ITERATIONS)
self._perTabPause = self.testvars.get("perTabPause", PER_TAB_PAUSE)
self._settleWaitTime = self.testvars.get("settleWaitTime", SETTLE_WAIT_TIME)
self._maxTabs = self.testvars.get("maxTabs", MAX_TABS)
self._dmd = self.testvars.get("dmd", False)
self.logger.info("areweslimyet run by %d pages, %d iterations, %d perTabPause, %d settleWaitTime"
% (self._pages_to_load, self._iterations, self._perTabPause, self._settleWaitTime))
self.reset_state()
def tearDown(self):
MarionetteTestCase.tearDown(self)
self.logger.info("processing data in %s!" % self._resultsDir)
perf_blob = process_perf_data.create_perf_data(
self._resultsDir, self.perf_suites(),
self.perf_checkpoints())
self.logger.info("PERFHERDER_DATA: %s" % json.dumps(perf_blob))
perf_file = os.path.join(self._resultsDir, "perfherder_data.json")
with open(perf_file, 'w') as fp:
json.dump(perf_blob, fp, indent=2)
self.logger.info("Perfherder data written to %s" % perf_file)
if self._dmd:
self.cleanup_dmd()
# copy it to moz upload dir if set
if 'MOZ_UPLOAD_DIR' in os.environ:
for file in os.listdir(self._resultsDir):
file = os.path.join(self._resultsDir, file)
if os.path.isfile(file):
shutil.copy2(file, os.environ["MOZ_UPLOAD_DIR"])
def cleanup_dmd(self):
"""
Handles moving DMD reports from the temp dir to our resultsDir.
"""
from dmd import fixStackTraces
# Move DMD files from temp dir to resultsDir.
tmpdir = tempfile.gettempdir()
tmp_files = os.listdir(tmpdir)
for f in fnmatch.filter(tmp_files, "dmd-*.json.gz"):
f = os.path.join(tmpdir, f)
self.logger.info("Fixing stacks for %s, this may take a while" % f)
isZipped = True
fixStackTraces(f, isZipped, gzip.open)
shutil.move(f, self._resultsDir)
# Also attempt to cleanup the unified memory reports.
for f in fnmatch.filter(tmp_files, "unified-memory-report-*.json.gz"):
try:
os.remove(f)
except OSError:
self.logger.info("Unable to remove %s" % f)
def reset_state(self):
self._pages_loaded = 0
# Close all tabs except one
for x in self.marionette.window_handles[1:]:
self.logger.info("closing window: %s" % x)
self.marionette.switch_to_window(x)
self.marionette.close()
self._tabs = self.marionette.window_handles
self.marionette.switch_to_window(self._tabs[0])
def do_full_gc(self):
"""Performs a full garbage collection cycle and returns when it is finished.
Returns True on success and False on failure.
"""
# NB: we could do this w/ a signal or the fifo queue too
self.logger.info("starting gc...")
gc_script = """
Cu.import("resource://gre/modules/Services.jsm");
Services.obs.notifyObservers(null, "child-mmu-request", null);
let memMgrSvc = Cc["@mozilla.org/memory-reporter-manager;1"].getService(Ci.nsIMemoryReporterManager);
memMgrSvc.minimizeMemoryUsage(() => marionetteScriptFinished("gc done!"));
"""
result = None
try:
result = self.marionette.execute_async_script(
gc_script, script_timeout=180000)
except JavascriptException, e:
self.logger.error("GC JavaScript error: %s" % e)
except ScriptTimeoutException:
self.logger.error("GC timed out")
except:
self.logger.error("Unexpected error: %s" % sys.exc_info()[0])
else:
self.logger.info(result)
return result is not None
def do_memory_report(self, checkpointName, iteration):
"""Creates a memory report for all processes and and returns the
checkpoint.
This will block until all reports are retrieved or a timeout occurs.
Returns the checkpoint or None on error.
:param checkpointName: The name of the checkpoint.
"""
self.logger.info("starting checkpoint %s..." % checkpointName)
checkpoint_file = "memory-report-%s-%d.json.gz" % (checkpointName, iteration)
checkpoint_path = os.path.join(self._resultsDir, checkpoint_file)
# On Windows, replace / with the Windows directory
# separator \ and escape it to prevent it from being
# interpreted as an escape character.
if sys.platform.startswith('win'):
checkpoint_path = (checkpoint_path.
replace('\\', '\\\\').
replace('/', '\\\\'))
checkpoint_script = r"""
let dumper = Cc["@mozilla.org/memory-info-dumper;1"].getService(Ci.nsIMemoryInfoDumper);
dumper.dumpMemoryReportsToNamedFile(
"%s",
() => marionetteScriptFinished("memory report done!"),
null,
/* anonymize */ false);
""" % checkpoint_path
checkpoint = None
try:
finished = self.marionette.execute_async_script(
checkpoint_script, script_timeout=60000)
if finished:
checkpoint = checkpoint_path
except JavascriptException, e:
self.logger.error("Checkpoint JavaScript error: %s" % e)
except ScriptTimeoutException:
self.logger.error("Memory report timed out")
except:
self.logger.error("Unexpected error: %s" % sys.exc_info()[0])
else:
self.logger.info("checkpoint created, stored in %s" % checkpoint_path)
# Now trigger a DMD report if requested.
if self._dmd:
self.do_dmd(checkpointName, iteration)
return checkpoint
def do_dmd(self, checkpointName, iteration):
"""
Triggers DMD reports that are used to help identify sources of
'heap-unclassified'.
NB: This will dump DMD reports to the temp dir. Unfortunately it also
dumps memory reports, but that's all we have to work with right now.
"""
self.logger.info("Starting %s DMD reports..." % checkpointName)
ident = "%s-%d" % (checkpointName, iteration)
# TODO(ER): This actually takes a minimize argument. We could use that
# rather than have a separate `do_gc` function. Also it generates a
# memory report so we could combine this with `do_checkpoint`. The main
# issue would be moving everything out of the temp dir.
#
# Generated files have the form:
# dmd-<checkpoint>-<iteration>-pid.json.gz, ie:
# dmd-TabsOpenForceGC-0-10885.json.gz
#
# and for the memory report:
# unified-memory-report-<checkpoint>-<iteration>.json.gz
dmd_script = r"""
let dumper = Cc["@mozilla.org/memory-info-dumper;1"].getService(Ci.nsIMemoryInfoDumper);
dumper.dumpMemoryInfoToTempDir(
"%s",
/* anonymize = */ false,
/* minimize = */ false);
""" % ident
try:
# This is async and there's no callback so we use the existence
# of an incomplete memory report to check if it hasn't finished yet.
self.marionette.execute_script(dmd_script, script_timeout=60000)
tmpdir = tempfile.gettempdir()
prefix = "incomplete-unified-memory-report-%s-%d-*" % (checkpointName, iteration)
max_wait = 60
elapsed = 0
while fnmatch.filter(os.listdir(tmpdir), prefix) and elapsed < max_wait:
self.logger.info("Waiting for memory report to finish")
time.sleep(1)
elapsed += 1
incomplete = fnmatch.filter(os.listdir(tmpdir), prefix)
if incomplete:
# The memory reports never finished.
self.logger.error("Incomplete memory reports leftover.")
for f in incomplete:
os.remove(os.path.join(tmpdir, f))
except JavascriptException, e:
self.logger.error("DMD JavaScript error: %s" % e)
except ScriptTimeoutException:
self.logger.error("DMD timed out")
except:
self.logger.error("Unexpected error: %s" % sys.exc_info()[0])
else:
self.logger.info("DMD started, prefixed with %s" % ident)
def open_and_focus(self):
"""Opens the next URL in the list and focuses on the tab it is opened in.
A new tab will be opened if |_maxTabs| has not been exceeded, otherwise
the URL will be loaded in the next tab.
"""
page_to_load = self.urls()[self._pages_loaded % len(self.urls())]
tabs_loaded = len(self._tabs)
is_new_tab = False
if tabs_loaded < self._maxTabs and tabs_loaded <= self._pages_loaded:
full_tab_list = self.marionette.window_handles
# Trigger opening a new tab by finding the new tab button and
# clicking it
newtab_button = (self.marionette.find_element('id', 'tabbrowser-tabs')
.find_element('anon attribute',
{'anonid': 'tabs-newtab-button'}))
newtab_button.click()
self.wait_for_condition(lambda mn: len(
mn.window_handles) == tabs_loaded + 1)
# NB: The tab list isn't sorted, so we do a set diff to determine
# which is the new tab
new_tab_list = self.marionette.window_handles
new_tabs = list(set(new_tab_list) - set(full_tab_list))
self._tabs.append(new_tabs[0])
tabs_loaded += 1
is_new_tab = True
tab_idx = self._pages_loaded % self._maxTabs
tab = self._tabs[tab_idx]
# Tell marionette which tab we're on
# NB: As a work-around for an e10s marionette bug, only select the tab
# if we're really switching tabs.
if tabs_loaded > 1:
self.logger.info("switching to tab")
self.marionette.switch_to_window(tab)
self.logger.info("switched to tab")
with self.marionette.using_context('content'):
self.logger.info("loading %s" % page_to_load)
self.marionette.navigate(page_to_load)
self.logger.info("loaded!")
# On e10s the tab handle can change after actually loading content
if is_new_tab:
# First build a set up w/o the current tab
old_tabs = set(self._tabs)
old_tabs.remove(tab)
# Perform a set diff to get the (possibly) new handle
[new_tab] = set(self.marionette.window_handles) - old_tabs
# Update the tab list at the current index to preserve the tab
# ordering
self._tabs[tab_idx] = new_tab
# give the page time to settle
time.sleep(self._perTabPause)
self._pages_loaded += 1
def signal_user_active(self):
"""Signal to the browser that the user is active.
Normally when being driven by marionette the browser thinks the
user is inactive the whole time because user activity is
detected by looking at key and mouse events.
This would be a problem for this test because user inactivity is
used to schedule some GCs (in particular shrinking GCs), so it
would make this unrepresentative of real use.
Instead we manually cause some inconsequential activity (a press
and release of the shift key) to make the browser think the user
is active. Then when we sleep to allow things to settle the
browser will see the user as becoming inactive and trigger
appropriate GCs, as would have happened in real use.
"""
action = Actions(self.marionette)
action.key_down(Keys.SHIFT)
action.key_up(Keys.SHIFT)
action.perform()
def open_pages(self):
"""
Opens all pages with our given configuration.
"""
for _ in range(self.pages_to_load()):
self.open_and_focus()
self.signal_user_active()

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

@ -32,10 +32,11 @@ PERF_SUITES = [
{ 'name': "Images", 'node': "explicit/images/" }
]
def update_checkpoint_paths(checkpoint_files):
def update_checkpoint_paths(checkpoint_files, checkpoints):
"""
Updates CHECKPOINTS with memory report file fetched in data_path
Updates checkpoints with memory report file fetched in data_path
:param checkpoint_files: list of files in data_path
:param checkpoints: The checkpoints to update the path of.
"""
target_path = [['Start-', 0],
['StartSettled-', 0],
@ -49,9 +50,14 @@ def update_checkpoint_paths(checkpoint_files):
for i in range(len(target_path)):
(name, idx) = target_path[i]
paths = sorted([x for x in checkpoint_files if name in x])
CHECKPOINTS[i]['path'] = paths[idx]
if paths:
indices = [i for i,x in enumerate(checkpoints) if name in x['path']]
if indices:
checkpoints[indices[0]]['path'] = paths[idx]
else:
print "found files but couldn't find %s" % name
def create_suite(name, node, data_path):
def create_suite(name, node, data_path, checkpoints=CHECKPOINTS):
"""
Creates a suite suitable for adding to a perfherder blob. Calculates the
geometric mean of the checkpoint values and adds that to the suite as
@ -60,6 +66,7 @@ def create_suite(name, node, data_path):
:param name: The name of the suite.
:param node: The path of the data node to extract data from.
:param data_path: The directory to retrieve data from.
:param checkpoints: Which checkpoints to include.
"""
suite = {
'name': name,
@ -71,16 +78,22 @@ def create_suite(name, node, data_path):
suite['extraOptions'] = ["stylo"]
if 'STYLO_THREADS' in os.environ and os.environ['STYLO_THREADS'] == '1':
suite['extraOptions'] = ["stylo-sequential"]
update_checkpoint_paths(glob.glob(os.path.join(data_path, "memory-report*")))
update_checkpoint_paths(glob.glob(os.path.join(data_path, "memory-report*")), checkpoints)
total = 0
for checkpoint in CHECKPOINTS:
for checkpoint in checkpoints:
memory_report_path = os.path.join(data_path, checkpoint['path'])
name_filter = checkpoint.get('name_filter', None)
count = checkpoint.get('count', 0)
if node != "resident":
totals = parse_about_memory.calculate_memory_report_values(
memory_report_path, node)
value = sum(totals.values())
memory_report_path, node, name_filter)
if count:
value = sum(totals.values()[:count])
else:
value = sum(totals.values())
else:
# For "resident" we really want RSS of the chrome ("Main") process
# and USS of the child processes. We'll still call it resident
@ -104,12 +117,12 @@ def create_suite(name, node, data_path):
# Add the geometric mean. For more details on the calculation see:
# https://en.wikipedia.org/wiki/Geometric_mean#Relationship_with_arithmetic_mean_of_logarithms
suite['value'] = math.exp(total / len(CHECKPOINTS))
suite['value'] = math.exp(total / len(checkpoints))
return suite
def create_perf_data(data_path):
def create_perf_data(data_path, perf_suites=PERF_SUITES, checkpoints=CHECKPOINTS):
"""
Builds up a performance data blob suitable for submitting to perfherder.
"""
@ -122,8 +135,8 @@ def create_perf_data(data_path):
'suites': []
}
for suite in PERF_SUITES:
perf_blob['suites'].append(create_suite(suite['name'], suite['node'], data_path))
for suite in perf_suites:
perf_blob['suites'].append(create_suite(suite['name'], suite['node'], data_path, checkpoints))
return perf_blob

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

@ -0,0 +1,90 @@
# 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/.
import os
import sys
AWSY_PATH = os.path.dirname(os.path.dirname(os.path.realpath(__file__)))
if AWSY_PATH not in sys.path:
sys.path.append(AWSY_PATH)
from awsy.awsy_test_case import AwsyTestCase
# A description of each checkpoint and the root path to it.
CHECKPOINTS = [
{
'name': "After tabs open [+30s, forced GC]",
'path': "memory-report-TabsOpenForceGC-4.json.gz",
'name_filter': 'Web Content', # We only want the content process
'count': 1 # We only care about the first one
},
]
# A description of each perfherder suite and the path to its values.
PERF_SUITES = [
{ 'name': "Base Content Resident Unique Memory", 'node': "resident-unique" },
{ 'name': "Base Content Heap Unclassified", 'node': "explicit/heap-unclassified" },
{ 'name': "Base Content JS", 'node': "js-main-runtime/" },
]
class TestMemoryUsage(AwsyTestCase):
"""
Provides a base case test that just loads about:memory and reports the
memory usage of a single content process.
"""
def urls(self):
return self._urls
def perf_suites(self):
return PERF_SUITES
def perf_checkpoints(self):
return CHECKPOINTS
def setUp(self):
AwsyTestCase.setUp(self)
self.logger.info("setting up!")
# Override AwsyTestCase value, this is always going to be 1 iteration.
self._iterations = 1
self._urls = ['about:blank'] * 4
self.logger.info("areweslimyet run by %d pages, %d iterations, %d perTabPause, %d settleWaitTime"
% (self._pages_to_load, self._iterations, self._perTabPause, self._settleWaitTime))
self.logger.info("done setting up!")
def tearDown(self):
self.logger.info("tearing down!")
AwsyTestCase.tearDown(self)
self.logger.info("done tearing down!")
def test_open_tabs(self):
"""Marionette test entry that returns an array of checkoint arrays.
This will generate a set of checkpoints for each iteration requested.
Upon succesful completion the results will be stored in
|self.testvars["results"]| and accessible to the test runner via the
|testvars| object it passed in.
"""
# setup the results array
results = [[] for _ in range(self.iterations())]
def create_checkpoint(name, iteration):
checkpoint = self.do_memory_report(name, iteration)
self.assertIsNotNone(checkpoint, "Checkpoint was recorded")
results[iteration].append(checkpoint)
for itr in range(self.iterations()):
self.open_pages()
self.settle()
self.settle()
self.assertTrue(self.do_full_gc())
self.settle()
create_checkpoint("TabsOpenForceGC", itr)
# TODO(ER): Temporary hack until bug 1121139 lands
self.logger.info("setting results")
self.testvars["results"] = results

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

@ -2,31 +2,19 @@
# 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/.
import fnmatch
import glob
import gzip
import json
import os
import sys
import time
import shutil
import tempfile
from marionette_harness import MarionetteTestCase
from marionette_driver import Actions
from marionette_driver.errors import JavascriptException, ScriptTimeoutException
import mozlog.structured
from marionette_driver.keys import Keys
AWSY_PATH = os.path.dirname(os.path.dirname(os.path.realpath(__file__)))
if AWSY_PATH not in sys.path:
sys.path.append(AWSY_PATH)
from awsy import ITERATIONS, PER_TAB_PAUSE, SETTLE_WAIT_TIME, MAX_TABS
from awsy import process_perf_data, webservers
from awsy.awsy_test_case import AwsyTestCase
class TestMemoryUsage(MarionetteTestCase):
class TestMemoryUsage(AwsyTestCase):
"""Provides a test that collects memory usage at various checkpoints:
- "Start" - Just after startup
- "StartSettled" - After an additional wait time
@ -38,23 +26,19 @@ class TestMemoryUsage(MarionetteTestCase):
- "TabsClosedForceGC" - After forcibly invoking garbage collection
"""
def urls(self):
return self._urls
def perf_suites(self):
return process_perf_data.PERF_SUITES
def perf_checkpoints(self):
return process_perf_data.CHECKPOINTS
def setUp(self):
MarionetteTestCase.setUp(self)
self.logger = mozlog.structured.structuredlog.get_default_logger()
self.logger.info("setting up!")
self.marionette.set_context('chrome')
AwsyTestCase.setUp(self)
self.logger.info("setting up")
self._webroot_dir = self.testvars["webRootDir"]
self._resultsDir = self.testvars["resultsDir"]
# Be conservative in what we delete automatically.
for f in glob.glob(os.path.join(self._resultsDir, 'memory-report-*.json.gz')):
os.unlink(f)
for f in glob.glob(os.path.join(self._resultsDir, 'perfherder_data.json')):
os.unlink(f)
for f in glob.glob(os.path.join(self._resultsDir, 'dmd-*.json.gz')):
os.unlink(f)
self._urls = []
urls = None
@ -65,89 +49,33 @@ class TestMemoryUsage(MarionetteTestCase):
urls = fp.readlines()
urls = map(lambda x:x.replace('localhost', 'localhost:{}'), urls)
# Optional testvars.
self._pages_to_load = self.testvars.get("entities", len(urls))
self._iterations = self.testvars.get("iterations", ITERATIONS)
self._perTabPause = self.testvars.get("perTabPause", PER_TAB_PAUSE)
self._settleWaitTime = self.testvars.get("settleWaitTime", SETTLE_WAIT_TIME)
self._maxTabs = self.testvars.get("maxTabs", MAX_TABS)
self._dmd = self.testvars.get("dmd", False)
# We haven't set self._urls yet, so this value might be zero if
# 'entities' wasn't specified.
to_load = self.pages_to_load()
if not to_load:
to_load = len(urls)
self._webservers = webservers.WebServers("localhost",
8001,
self._webroot_dir,
self._pages_to_load)
to_load)
self._webservers.start()
for url, server in zip(urls, self._webservers.servers):
self._urls.append(url.strip().format(server.port))
self.logger.info("areweslimyet run by %d pages, %d iterations, %d perTabPause, %d settleWaitTime"
% (self._pages_to_load, self._iterations, self._perTabPause, self._settleWaitTime))
self.reset_state()
self.logger.info("done setting up!")
def tearDown(self):
self.logger.info("tearing down!")
MarionetteTestCase.tearDown(self)
self.logger.info("tearing down webservers!")
self._webservers.stop()
self.logger.info("processing data in %s!" % self._resultsDir)
perf_blob = process_perf_data.create_perf_data(self._resultsDir)
self.logger.info("PERFHERDER_DATA: %s" % json.dumps(perf_blob))
perf_file = os.path.join(self._resultsDir, "perfherder_data.json")
with open(perf_file, 'w') as fp:
json.dump(perf_blob, fp, indent=2)
self.logger.info("Perfherder data written to %s" % perf_file)
if self._dmd:
self.cleanup_dmd()
# copy it to moz upload dir if set
if 'MOZ_UPLOAD_DIR' in os.environ:
for file in os.listdir(self._resultsDir):
file = os.path.join(self._resultsDir, file)
if os.path.isfile(file):
shutil.copy2(file, os.environ["MOZ_UPLOAD_DIR"])
AwsyTestCase.tearDown(self)
self.logger.info("done tearing down!")
def cleanup_dmd(self):
"""
Handles moving DMD reports from the temp dir to our resultsDir.
"""
from dmd import fixStackTraces
# Move DMD files from temp dir to resultsDir.
tmpdir = tempfile.gettempdir()
tmp_files = os.listdir(tmpdir)
for f in fnmatch.filter(tmp_files, "dmd-*.json.gz"):
f = os.path.join(tmpdir, f)
self.logger.info("Fixing stacks for %s, this may take a while" % f)
isZipped = True
fixStackTraces(f, isZipped, gzip.open)
shutil.move(f, self._resultsDir)
# Also attempt to cleanup the unified memory reports.
for f in fnmatch.filter(tmp_files, "unified-memory-report-*.json.gz"):
try:
os.remove(f)
except OSError:
self.logger.info("Unable to remove %s" % f)
def reset_state(self):
self._pages_loaded = 0
# Close all tabs except one
for x in self.marionette.window_handles[1:]:
self.logger.info("closing window: %s" % x)
self.marionette.switch_to_window(x)
self.marionette.close()
self._tabs = self.marionette.window_handles
self.marionette.switch_to_window(self._tabs[0])
def clear_preloaded_browser(self):
"""
Clears out the preloaded browser.
@ -176,234 +104,6 @@ class TestMemoryUsage(MarionetteTestCase):
if result:
self.logger.info(result)
def do_full_gc(self):
"""Performs a full garbage collection cycle and returns when it is finished.
Returns True on success and False on failure.
"""
# NB: we could do this w/ a signal or the fifo queue too
self.logger.info("starting gc...")
gc_script = """
Cu.import("resource://gre/modules/Services.jsm");
Services.obs.notifyObservers(null, "child-mmu-request", null);
let memMgrSvc = Cc["@mozilla.org/memory-reporter-manager;1"].getService(Ci.nsIMemoryReporterManager);
memMgrSvc.minimizeMemoryUsage(() => marionetteScriptFinished("gc done!"));
"""
result = None
try:
result = self.marionette.execute_async_script(
gc_script, script_timeout=180000)
except JavascriptException, e:
self.logger.error("GC JavaScript error: %s" % e)
except ScriptTimeoutException:
self.logger.error("GC timed out")
except:
self.logger.error("Unexpected error: %s" % sys.exc_info()[0])
else:
self.logger.info(result)
return result is not None
def do_memory_report(self, checkpointName, iteration):
"""Creates a memory report for all processes and and returns the
checkpoint.
This will block until all reports are retrieved or a timeout occurs.
Returns the checkpoint or None on error.
:param checkpointName: The name of the checkpoint.
"""
self.logger.info("starting checkpoint %s..." % checkpointName)
checkpoint_file = "memory-report-%s-%d.json.gz" % (checkpointName, iteration)
checkpoint_path = os.path.join(self._resultsDir, checkpoint_file)
# On Windows, replace / with the Windows directory
# separator \ and escape it to prevent it from being
# interpreted as an escape character.
if sys.platform.startswith('win'):
checkpoint_path = (checkpoint_path.
replace('\\', '\\\\').
replace('/', '\\\\'))
checkpoint_script = r"""
let dumper = Cc["@mozilla.org/memory-info-dumper;1"].getService(Ci.nsIMemoryInfoDumper);
dumper.dumpMemoryReportsToNamedFile(
"%s",
() => marionetteScriptFinished("memory report done!"),
null,
/* anonymize */ false);
""" % checkpoint_path
checkpoint = None
try:
finished = self.marionette.execute_async_script(
checkpoint_script, script_timeout=60000)
if finished:
checkpoint = checkpoint_path
except JavascriptException, e:
self.logger.error("Checkpoint JavaScript error: %s" % e)
except ScriptTimeoutException:
self.logger.error("Memory report timed out")
except:
self.logger.error("Unexpected error: %s" % sys.exc_info()[0])
else:
self.logger.info("checkpoint created, stored in %s" % checkpoint_path)
# Now trigger a DMD report if requested.
if self._dmd:
self.do_dmd(checkpointName, iteration)
return checkpoint
def do_dmd(self, checkpointName, iteration):
"""
Triggers DMD reports that are used to help identify sources of
'heap-unclassified'.
NB: This will dump DMD reports to the temp dir. Unfortunately it also
dumps memory reports, but that's all we have to work with right now.
"""
self.logger.info("Starting %s DMD reports..." % checkpointName)
ident = "%s-%d" % (checkpointName, iteration)
# TODO(ER): This actually takes a minimize argument. We could use that
# rather than have a separate `do_gc` function. Also it generates a
# memory report so we could combine this with `do_checkpoint`. The main
# issue would be moving everything out of the temp dir.
#
# Generated files have the form:
# dmd-<checkpoint>-<iteration>-pid.json.gz, ie:
# dmd-TabsOpenForceGC-0-10885.json.gz
#
# and for the memory report:
# unified-memory-report-<checkpoint>-<iteration>.json.gz
dmd_script = r"""
let dumper = Cc["@mozilla.org/memory-info-dumper;1"].getService(Ci.nsIMemoryInfoDumper);
dumper.dumpMemoryInfoToTempDir(
"%s",
/* anonymize = */ false,
/* minimize = */ false);
""" % ident
try:
# This is async and there's no callback so we use the existence
# of an incomplete memory report to check if it hasn't finished yet.
self.marionette.execute_script(dmd_script, script_timeout=60000)
tmpdir = tempfile.gettempdir()
prefix = "incomplete-unified-memory-report-%s-%d-*" % (checkpointName, iteration)
max_wait = 60
elapsed = 0
while fnmatch.filter(os.listdir(tmpdir), prefix) and elapsed < max_wait:
self.logger.info("Waiting for memory report to finish")
time.sleep(1)
elapsed += 1
incomplete = fnmatch.filter(os.listdir(tmpdir), prefix)
if incomplete:
# The memory reports never finished.
self.logger.error("Incomplete memory reports leftover.")
for f in incomplete:
os.remove(os.path.join(tmpdir, f))
except JavascriptException, e:
self.logger.error("DMD JavaScript error: %s" % e)
except ScriptTimeoutException:
self.logger.error("DMD timed out")
except:
self.logger.error("Unexpected error: %s" % sys.exc_info()[0])
else:
self.logger.info("DMD started, prefixed with %s" % ident)
def open_and_focus(self):
"""Opens the next URL in the list and focuses on the tab it is opened in.
A new tab will be opened if |_maxTabs| has not been exceeded, otherwise
the URL will be loaded in the next tab.
"""
page_to_load = self._urls[self._pages_loaded % len(self._urls)]
tabs_loaded = len(self._tabs)
is_new_tab = False
if tabs_loaded < self._maxTabs and tabs_loaded <= self._pages_loaded:
full_tab_list = self.marionette.window_handles
# Trigger opening a new tab by finding the new tab button and
# clicking it
newtab_button = (self.marionette.find_element('id', 'tabbrowser-tabs')
.find_element('anon attribute',
{'anonid': 'tabs-newtab-button'}))
newtab_button.click()
self.wait_for_condition(lambda mn: len(
mn.window_handles) == tabs_loaded + 1)
# NB: The tab list isn't sorted, so we do a set diff to determine
# which is the new tab
new_tab_list = self.marionette.window_handles
new_tabs = list(set(new_tab_list) - set(full_tab_list))
self._tabs.append(new_tabs[0])
tabs_loaded += 1
is_new_tab = True
tab_idx = self._pages_loaded % self._maxTabs
tab = self._tabs[tab_idx]
# Tell marionette which tab we're on
# NB: As a work-around for an e10s marionette bug, only select the tab
# if we're really switching tabs.
if tabs_loaded > 1:
self.logger.info("switching to tab")
self.marionette.switch_to_window(tab)
self.logger.info("switched to tab")
with self.marionette.using_context('content'):
self.logger.info("loading %s" % page_to_load)
self.marionette.navigate(page_to_load)
self.logger.info("loaded!")
# On e10s the tab handle can change after actually loading content
if is_new_tab:
# First build a set up w/o the current tab
old_tabs = set(self._tabs)
old_tabs.remove(tab)
# Perform a set diff to get the (possibly) new handle
[new_tab] = set(self.marionette.window_handles) - old_tabs
# Update the tab list at the current index to preserve the tab
# ordering
self._tabs[tab_idx] = new_tab
# give the page time to settle
time.sleep(self._perTabPause)
self._pages_loaded += 1
def signal_user_active(self):
"""Signal to the browser that the user is active.
Normally when being driven by marionette the browser thinks the
user is inactive the whole time because user activity is
detected by looking at key and mouse events.
This would be a problem for this test because user inactivity is
used to schedule some GCs (in particular shrinking GCs), so it
would make this unrepresentative of real use.
Instead we manually cause some inconsequential activity (a press
and release of the shift key) to make the browser think the user
is active. Then when we sleep to allow things to settle the
browser will see the user as becoming inactive and trigger
appropriate GCs, as would have happened in real use.
"""
action = Actions(self.marionette)
action.key_down(Keys.SHIFT)
action.key_up(Keys.SHIFT)
action.perform()
def test_open_tabs(self):
"""Marionette test entry that returns an array of checkoint arrays.
@ -413,7 +113,7 @@ class TestMemoryUsage(MarionetteTestCase):
|testvars| object it passed in.
"""
# setup the results array
results = [[] for _ in range(self._iterations)]
results = [[] for _ in range(self.iterations())]
def create_checkpoint(name, iteration):
checkpoint = self.do_memory_report(name, iteration)
@ -423,16 +123,14 @@ class TestMemoryUsage(MarionetteTestCase):
# The first iteration gets Start and StartSettled entries before
# opening tabs
create_checkpoint("Start", 0)
time.sleep(self._settleWaitTime)
self.settle()
create_checkpoint("StartSettled", 0)
for itr in range(self._iterations):
for _ in range(self._pages_to_load):
self.open_and_focus()
self.signal_user_active()
for itr in range(self.iterations()):
self.open_pages()
create_checkpoint("TabsOpen", itr)
time.sleep(self._settleWaitTime)
self.settle()
create_checkpoint("TabsOpenSettled", itr)
self.assertTrue(self.do_full_gc())
create_checkpoint("TabsOpenForceGC", itr)
@ -440,9 +138,6 @@ class TestMemoryUsage(MarionetteTestCase):
# Close all tabs
self.reset_state()
self.logger.info("switching to first window")
self.marionette.switch_to_window(self._tabs[0])
self.logger.info("switched to first window")
with self.marionette.using_context('content'):
self.logger.info("navigating to about:blank")
self.marionette.navigate("about:blank")
@ -457,7 +152,7 @@ class TestMemoryUsage(MarionetteTestCase):
self.clear_preloaded_browser()
create_checkpoint("TabsClosed", itr)
time.sleep(self._settleWaitTime)
self.settle()
create_checkpoint("TabsClosedSettled", itr)
self.assertTrue(self.do_full_gc(), "GC ran")
create_checkpoint("TabsClosedForceGC", itr)

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

@ -0,0 +1,14 @@
{
"browser.urlbar.userMadeSearchSuggestionsChoice": true,
"javascript.options.asyncstack": false,
"image.mem.surfacecache.min_expiration_ms": 10000,
"network.proxy.socks": "localhost",
"network.proxy.socks_port": 90000,
"network.proxy.socks_remote_dns": true,
"network.proxy.type": 1,
"plugin.disable": true,
"startup.homepage_override_url": "",
"startup.homepage_welcome_url": "",
"browser.startup.homepage": "about:blank",
"browser.newtabpage.enabled": false
}

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

@ -0,0 +1,6 @@
{
"entities": 4,
"iterations": 1,
"perTabPause": 10,
"settleWaitTime": 60
}

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

@ -76,7 +76,7 @@ class MachCommands(MachCommandBase):
runtime_testvars = {}
for arg in ('webRootDir', 'pageManifest', 'resultsDir', 'entities', 'iterations',
'perTabPause', 'settleWaitTime', 'maxTabs', 'dmd'):
if kwargs[arg]:
if arg in kwargs and kwargs[arg] is not None:
runtime_testvars[arg] = kwargs[arg]
if 'webRootDir' not in runtime_testvars:

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

@ -816,7 +816,8 @@ class AndroidEmulatorTest(TestingMixin, BaseScript, MozbaseMixin, CodeCoverageMi
log_obj=self.log_obj,
error_list=[])
self.run_command(final_cmd, cwd=cwd, env=env, output_parser=parser)
tbpl_status, log_level, summary = parser.evaluate_parser(0, summary)
tbpl_status, log_level, summary = parser.evaluate_parser(0,
previous_summary=summary)
parser.append_tinderboxprint_line(self.test_suite)
self.info("##### %s log ends" % self.test_suite)

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

@ -49,6 +49,12 @@ class AWSY(TestingMixin, MercurialScript, BlobUploadMixin, TooltoolMixin, CodeCo
"dest": "enable_webrender",
"default": False,
"help": "Tries to enable the WebRender compositor.",
}],
[["--base"],
{"action": "store_true",
"dest": "test_about_blank",
"default": False,
"help": "Runs the about:blank base case memory test.",
}]
] + testing_config_options + copy.deepcopy(blobupload_config_options) \
+ copy.deepcopy(code_coverage_config_options)
@ -151,8 +157,13 @@ class AWSY(TestingMixin, MercurialScript, BlobUploadMixin, TooltoolMixin, CodeCo
runtime_testvars_file.close()
cmd = ['marionette']
cmd.append("--preferences=%s" % os.path.join(self.awsy_path, "conf", "prefs.json"))
cmd.append("--testvars=%s" % os.path.join(self.awsy_path, "conf", "testvars.json"))
if self.config['test_about_blank']:
cmd.append("--testvars=%s" % os.path.join(self.awsy_path, "conf",
"base-testvars.json"))
else:
cmd.append("--testvars=%s" % os.path.join(self.awsy_path, "conf", "testvars.json"))
cmd.append("--testvars=%s" % runtime_testvars_path)
cmd.append("--log-raw=-")
cmd.append("--log-errorsummary=%s" % error_summary_file)
@ -166,7 +177,14 @@ class AWSY(TestingMixin, MercurialScript, BlobUploadMixin, TooltoolMixin, CodeCo
# self.symbols_path
cmd.append('--symbols-path=%s' % self.symbols_path)
test_file = os.path.join(self.awsy_libdir, 'test_memory_usage.py')
if self.config['test_about_blank']:
test_file = os.path.join(self.awsy_libdir, 'test_base_memory_usage.py')
prefs_file = "base-prefs.json"
else:
test_file = os.path.join(self.awsy_libdir, 'test_memory_usage.py')
prefs_file = "prefs.json"
cmd.append("--preferences=%s" % os.path.join(self.awsy_path, "conf", prefs_file))
cmd.append(test_file)
if self.config['single_stylo_traversal']:

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

@ -1887,7 +1887,7 @@ class Dictionary extends ExtensionData {
async startup(reason) {
this.dictionaries = {};
for (let [lang, path] of Object.entries(this.startupData.dictionaries)) {
let uri = Services.io.newURI(path, null, this.rootURI);
let uri = Services.io.newURI(path.slice(0, -4) + ".aff", null, this.rootURI);
this.dictionaries[lang] = uri;
spellCheck.addDictionary(lang, uri);

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

@ -121,7 +121,7 @@ skip-if = os == 'android' && debug # bug 1397615
skip-if = os == 'android'
[test_ext_webrequest_background_events.html]
[test_ext_webrequest_basic.html]
skip-if = os == 'android' && debug || (os == 'linux' && !asan && bits == 64) # bug 1397615, bug 1455405
skip-if = os == 'android' && debug || (os == 'linux' && !asan) # bug 1397615, bug 1455405
[test_ext_webrequest_errors.html]
[test_ext_webrequest_filter.html]
[test_ext_webrequest_frameId.html]

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

@ -2056,19 +2056,6 @@ var AddonManagerInternal = {
.installTemporaryAddon(aFile);
},
installAddonFromSources(aFile) {
if (!gStarted)
throw Components.Exception("AddonManager is not initialized",
Cr.NS_ERROR_NOT_INITIALIZED);
if (!(aFile instanceof Ci.nsIFile))
throw Components.Exception("aFile must be a nsIFile",
Cr.NS_ERROR_INVALID_ARG);
return AddonManagerInternal._getProviderByName("XPIProvider")
.installAddonFromSources(aFile);
},
/**
* Returns an Addon corresponding to an instance ID.
* @param aInstanceID
@ -3441,10 +3428,6 @@ var AddonManager = {
return AddonManagerInternal.installTemporaryAddon(aDirectory);
},
installAddonFromSources(aDirectory) {
return AddonManagerInternal.installAddonFromSources(aDirectory);
},
getAddonByInstanceID(aInstanceID) {
return AddonManagerInternal.getAddonByInstanceID(aInstanceID);
},

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

@ -675,16 +675,6 @@ var AddonTestUtils = {
});
},
verifySignedDirectoryAsync(root, dir, callback) {
// First try calling the real cert DB
this._genuine.verifySignedDirectoryAsync(root, dir, (result, cert) => {
verifyCert(dir.clone(), result, cert, callback)
.then(([callback, result, cert]) => {
callback.verifySignedDirectoryFinished(result, cert);
});
});
},
QueryInterface: ChromeUtils.generateQI([Ci.nsIX509CertDB]),
};

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