This commit is contained in:
Wes Kocher 2016-08-29 17:40:50 -07:00
Родитель e7d85d7c46 6a58d2ee18
Коммит ed461fdf11
164 изменённых файлов: 3053 добавлений и 1198 удалений

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

@ -83,9 +83,7 @@ addEventListener("blur", function(event) {
LoginManagerContent.onUsernameInput(event);
});
var gLastContextMenuEvent = null; // null or a WeakReference to a contextmenu event
var handleContentContextMenu = function (event) {
gLastContextMenuEvent = null;
let defaultPrevented = event.defaultPrevented;
if (!Services.prefs.getBoolPref("dom.event.contextmenu.enabled")) {
let plugin = null;
@ -100,36 +98,8 @@ var handleContentContextMenu = function (event) {
defaultPrevented = false;
}
if (defaultPrevented) {
if (defaultPrevented)
return;
}
if (event.mozInputSource == Ci.nsIDOMMouseEvent.MOZ_SOURCE_TOUCH) {
// If this was triggered by touch, then we don't want to show the actual
// context menu until we get the APZ:LongTapUp notification. However, we
// will need the |event| object when we get that notification, so we save
// it in a WeakReference. That way it won't leak things if we never get
// the APZ:LongTapUp notification (which is quite possible).
gLastContextMenuEvent = Cu.getWeakReference(event);
return;
}
// For non-touch-derived contextmenu events, we can handle it right away.
showContentContextMenu(event);
}
var showContentContextMenu = function (event) {
if (event == null) {
// If we weren't given an event, then this is being invoked from the
// APZ:LongTapUp observer, and the contextmenu event is stashed in
// gLastContextMenuEvent.
event = (gLastContextMenuEvent ? gLastContextMenuEvent.get() : null);
gLastContextMenuEvent = null;
if (event == null) {
// Still no event? We can't do anything, bail out.
return;
}
}
let addonInfo = {};
let subject = {
@ -247,11 +217,6 @@ Cc["@mozilla.org/eventlistenerservice;1"]
.getService(Ci.nsIEventListenerService)
.addSystemEventListener(global, "contextmenu", handleContentContextMenu, false);
Services.obs.addObserver(showContentContextMenu, "APZ:LongTapUp", false);
addEventListener("unload", () => {
Services.obs.removeObserver(showContentContextMenu, "APZ:LongTapUp")
}, false);
// Values for telemtery bins: see TLS_ERROR_REPORT_UI in Histograms.json
const TLS_ERROR_REPORT_TELEMETRY_UI_SHOWN = 0;
const TLS_ERROR_REPORT_TELEMETRY_EXPANDED = 1;

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

@ -39,6 +39,21 @@ const PAGECONTENT_SMALL =
" <option value='Six'>Six</option>" +
"</select></body></html>";
const PAGECONTENT_SOMEHIDDEN =
"<html>" +
"<body><select id='one'>" +
" <option value='One' style='display: none;'>OneHidden</option>" +
" <option value='Two' style='display: none;'>TwoHidden</option>" +
" <option value='Three'>ThreeVisible</option>" +
" <option value='Four'style='display: table;'>FourVisible</option>" +
" <option value='Five'>FiveVisible</option>" +
" <optgroup label='GroupHidden' style='display: none;'>" +
" <option value='Four'>Six.OneHidden</option>" +
" <option value='Five' style='display: block;'>Six.TwoHidden</option>" +
" </optgroup>" +
" <option value='Six'>SevenVisible</option>" +
"</select></body></html>";
const PAGECONTENT_TRANSLATED =
"<html><body>" +
"<div id='div'>" +
@ -485,3 +500,33 @@ add_task(function* test_mousemove_correcttarget() {
yield BrowserTestUtils.removeTab(tab);
});
// This test checks when a <select> element has some options with altered display values.
add_task(function* test_somehidden() {
const pageUrl = "data:text/html," + escape(PAGECONTENT_SOMEHIDDEN);
let tab = yield BrowserTestUtils.openNewForegroundTab(gBrowser, pageUrl);
let selectPopup = document.getElementById("ContentSelectDropdown").menupopup;
let popupShownPromise = BrowserTestUtils.waitForEvent(selectPopup, "popupshown");
yield BrowserTestUtils.synthesizeMouseAtCenter("#one", { type: "mousedown" }, gBrowser.selectedBrowser);
yield popupShownPromise;
// The exact number is not needed; just ensure the height is larger than 4 items to accomodate any popup borders.
ok(selectPopup.getBoundingClientRect().height >= selectPopup.lastChild.getBoundingClientRect().height * 4, "Height contains at least 4 items");
ok(selectPopup.getBoundingClientRect().height < selectPopup.lastChild.getBoundingClientRect().height * 5, "Height doesn't contain 5 items");
// The label contains the substring 'Visible' for items that are visible.
// Otherwise, it is expected to be display: none.
is(selectPopup.parentNode.itemCount, 9, "Correct number of items");
let child = selectPopup.firstChild;
let idx = 1;
while (child) {
is(getComputedStyle(child).display, child.label.indexOf("Visible") > 0 ? "-moz-box" : "none",
"Item " + (idx++) + " is visible");
child = child.nextSibling;
}
yield hideSelectPopup(selectPopup, "escape");
yield BrowserTestUtils.removeTab(tab);
});

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

@ -59,7 +59,7 @@ add_task(function* () {
let obsPromise = TestUtils.topicObserved("PopupNotifications-updateNotShowing");
let overlayPromise = promisePopupNotification("click-to-play-plugins");
gTestBrowser.contentWindow.history.back();
gTestBrowser.goBack();
yield obsPromise;
yield overlayPromise;
});

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

@ -177,6 +177,15 @@ restartNow=Restart Now
restartLater=Restart Later
disableContainersAlertTitle=Close All Container Tabs?
# LOCALIZATION NOTE (disableContainersMsg): Semi-colon list of plural forms.
# See: http://developer.mozilla.org/en/docs/Localization_and_Plurals
# #S is the number of container tabs
disableContainersMsg=If you disable Container Tabs now, #S container tab will be closed. Are you sure you want to disable Container Tabs?;If you disable Containers Tabs now, #S container tabs will be closed. Are you sure you want to disable Containers Tabs?
# LOCALIZATION NOTE (disableContainersOkButton): Semi-colon list of plural forms.
# See: http://developer.mozilla.org/en/docs/Localization_and_Plurals
# #S is the number of container tabs
disableContainersOkButton=Close #S Container Tab;Close #S Container Tabs
disableContainersButton2=Keep enabled

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

@ -1054,7 +1054,7 @@ toolbaritem[cui-areatype="menu-panel"] > :-moz-any(@nestedButtons@) > .toolbarbu
}
#identity-box:-moz-focusring {
outline: 1px dotted #000;
outline: 1px dotted;
outline-offset: -3px;
}

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

@ -1,5 +1,5 @@
#PopupAutoCompleteRichResult > hbox[anonid="search-suggestions-notification"] {
border-bottom: 1px solid hsla(210, 4%, 10%, 0.14);
border-bottom: 1px solid var(--panel-separator-color);
background-color: hsla(210, 4%, 10%, 0.07);
padding: 6px 0;
padding-inline-start: 44px;

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

@ -1489,7 +1489,7 @@ html|*.urlbar-input:-moz-lwtheme::-moz-placeholder,
/* identity box */
#identity-box:-moz-focusring {
outline: 1px dotted #000;
outline: 1px dotted;
outline-offset: -3px;
}

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

@ -220,9 +220,9 @@ nsPrincipal::SubsumesInternal(nsIPrincipal* aOther,
}
}
nsCOMPtr<nsIURI> otherURI;
rv = aOther->GetURI(getter_AddRefs(otherURI));
NS_ENSURE_SUCCESS(rv, false);
nsCOMPtr<nsIURI> otherURI;
rv = aOther->GetURI(getter_AddRefs(otherURI));
NS_ENSURE_SUCCESS(rv, false);
// Compare codebases.
return nsScriptSecurityManager::SecurityCompareURIs(mCodebase, otherURI);

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

@ -4844,8 +4844,6 @@ nsDocument::SetScriptHandlingObject(nsIScriptGlobalObject* aScriptObject)
NS_ASSERTION(!mScriptGlobalObject ||
mScriptGlobalObject == aScriptObject,
"Wrong script object!");
// XXXkhuey why bother?
nsCOMPtr<nsPIDOMWindowInner> win = do_QueryInterface(aScriptObject);
if (aScriptObject) {
mScopeObject = do_GetWeakReference(aScriptObject);
mHasHadScriptHandlingObject = true;
@ -7710,8 +7708,6 @@ nsDOMAttributeMap::BlastSubtreeToPieces(nsINode *aNode)
Element *element = aNode->AsElement();
const nsDOMAttributeMap *map = element->GetAttributeMap();
if (map) {
nsCOMPtr<nsIAttribute> attr;
// This non-standard style of iteration is presumably used because some
// of the code in the loop body can trigger element removal, which
// invalidates the iterator.
@ -8764,7 +8760,6 @@ nsDocument::Sanitize()
RefPtr<nsContentList> nodes = GetElementsByTagName(NS_LITERAL_STRING("input"));
nsCOMPtr<nsIContent> item;
nsAutoString value;
uint32_t length = nodes->Length(true);
@ -10439,7 +10434,6 @@ nsDocument::GetStateObject(nsIVariant** aState)
// mStateObjectContainer may be null; this just means that there's no
// current state object.
nsCOMPtr<nsIVariant> stateObj;
if (!mStateObjectCached && mStateObjectContainer) {
AutoJSContext cx;
nsIGlobalObject* sgo = GetScopeObject();
@ -10880,7 +10874,6 @@ nsIDocument::CaretPositionFromPoint(float aX, float aY)
if (nodeIsAnonymous) {
node = ptFrame->GetContent();
nsIContent* nonanon = node->FindFirstNonChromeOnlyAccessContent();
nsCOMPtr<nsIDOMHTMLInputElement> input = do_QueryInterface(nonanon);
nsCOMPtr<nsIDOMHTMLTextAreaElement> textArea = do_QueryInterface(nonanon);
nsITextControlFrame* textFrame = do_QueryFrame(nonanon->GetPrimaryFrame());
nsNumberControlFrame* numberFrame = do_QueryFrame(nonanon->GetPrimaryFrame());

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

@ -8,7 +8,7 @@
* Object that can be used to serialize selections, ranges, or nodes
* to strings in a gazillion different ways.
*/
#include "nsIDocumentEncoder.h"
#include "nscore.h"
@ -89,8 +89,8 @@ protected:
nsAString& aStr);
nsresult SerializeRangeToString(nsRange *aRange,
nsAString& aOutputString);
nsresult SerializeRangeNodes(nsRange* aRange,
nsINode* aNode,
nsresult SerializeRangeNodes(nsRange* aRange,
nsINode* aNode,
nsAString& aString,
int32_t aDepth);
nsresult SerializeRangeContextStart(const nsTArray<nsINode*>& aAncestorArray,
@ -167,7 +167,7 @@ protected:
AutoTArray<int32_t, 8> mStartOffsets;
AutoTArray<nsIContent*, 8> mEndNodes;
AutoTArray<int32_t, 8> mEndOffsets;
bool mHaltRangeHint;
bool mHaltRangeHint;
// Used when context has already been serialized for
// table cell selections (where parent is <tr>)
bool mDisableContextSerialize;
@ -412,14 +412,14 @@ nsDocumentEncoder::SerializeNodeStart(nsINode* aNode,
{
if (!IsVisibleNode(aNode))
return NS_OK;
nsINode* node = nullptr;
nsCOMPtr<nsINode> fixedNodeKungfuDeathGrip;
// Caller didn't do fixup, so we'll do it ourselves
if (!aOriginalNode) {
aOriginalNode = aNode;
if (mNodeFixup) {
if (mNodeFixup) {
bool dummy;
nsCOMPtr<nsIDOMNode> domNodeIn = do_QueryInterface(aNode);
nsCOMPtr<nsIDOMNode> domNodeOut;
@ -433,7 +433,7 @@ nsDocumentEncoder::SerializeNodeStart(nsINode* aNode,
// or the caller did fixup themselves and aNode is already fixed
if (!node)
node = aNode;
if (node->IsElement()) {
if ((mFlags & (nsIDocumentEncoder::OutputPreformatted |
nsIDocumentEncoder::OutputDropInvisibleBreak)) &&
@ -655,7 +655,7 @@ ConvertAndWrite(const nsAString& aString,
// If the converter couldn't convert a chraacer we replace the
// character with a characre entity.
if (convert_rv == NS_ERROR_UENC_NOMAPPING) {
// Finishes the conversion.
// Finishes the conversion.
// The converter has the possibility to write some extra data and flush its final state.
char finish_buf[33];
charLength = sizeof(finish_buf) - 1;
@ -671,7 +671,7 @@ ConvertAndWrite(const nsAString& aString,
NS_ENSURE_SUCCESS(rv, rv);
nsAutoCString entString("&#");
if (NS_IS_HIGH_SURROGATE(unicodeBuf[unicodeLength - 1]) &&
if (NS_IS_HIGH_SURROGATE(unicodeBuf[unicodeLength - 1]) &&
unicodeLength < startLength && NS_IS_LOW_SURROGATE(unicodeBuf[unicodeLength])) {
entString.AppendInt(SURROGATE_TO_UCS4(unicodeBuf[unicodeLength - 1],
unicodeBuf[unicodeLength]));
@ -859,7 +859,7 @@ nsDocumentEncoder::SerializeRangeNodes(nsRange* aRange,
}
else
{
// due to implementation it is impossible for text node to be both start and end of
// due to implementation it is impossible for text node to be both start and end of
// range. We would have handled that case without getting here.
//XXXsmaug What does this all mean?
if (IsTextNode(aNode))
@ -889,12 +889,12 @@ nsDocumentEncoder::SerializeRangeNodes(nsRange* aRange,
}
if ((startNode == content) && !mHaltRangeHint) mStartDepth++;
if ((endNode == content) && !mHaltRangeHint) mEndDepth++;
// serialize the start of this node
rv = SerializeNodeStart(aNode, 0, -1, aString);
NS_ENSURE_SUCCESS(rv, rv);
}
// do some calculations that will tell us which children of this
// node are in the range.
nsIContent* childAsNode = nullptr;
@ -903,7 +903,7 @@ nsDocumentEncoder::SerializeRangeNodes(nsRange* aRange,
startOffset = mStartOffsets[mStartRootIndex - aDepth];
if (endNode == content && mEndRootIndex >= aDepth)
endOffset = mEndOffsets[mEndRootIndex - aDepth];
// generated content will cause offset values of -1 to be returned.
// generated content will cause offset values of -1 to be returned.
int32_t j;
uint32_t childCount = content->GetChildCount();
@ -914,7 +914,7 @@ nsDocumentEncoder::SerializeRangeNodes(nsRange* aRange,
// if we are at the "tip" of the selection, endOffset is fine.
// otherwise, we need to add one. This is because of the semantics
// of the offset list created by GetAncestorsAndOffsets(). The
// intermediate points on the list use the endOffset of the
// intermediate points on the list use the endOffset of the
// location of the ancestor, rather than just past it. So we need
// to add one here in order to include it in the children we serialize.
if (aNode != aRange->GetEndParent())
@ -939,7 +939,7 @@ nsDocumentEncoder::SerializeRangeNodes(nsRange* aRange,
if (aNode != mCommonParent)
{
rv = SerializeNodeEnd(aNode, aString);
NS_ENSURE_SUCCESS(rv, rv);
NS_ENSURE_SUCCESS(rv, rv);
}
}
}
@ -1020,7 +1020,7 @@ nsDocumentEncoder::SerializeRangeToString(nsRange *aRange,
if (!mCommonParent)
return NS_OK;
nsINode* startParent = aRange->GetStartParent();
NS_ENSURE_TRUE(startParent, NS_ERROR_FAILURE);
int32_t startOffset = aRange->StartOffset();
@ -1047,7 +1047,7 @@ nsDocumentEncoder::SerializeRangeToString(nsRange *aRange,
nsCOMPtr<nsIContent> commonContent = do_QueryInterface(mCommonParent);
mStartRootIndex = mStartNodes.IndexOf(commonContent);
mEndRootIndex = mEndNodes.IndexOf(commonContent);
nsresult rv = NS_OK;
rv = SerializeRangeContextStart(mCommonAncestors, aOutputString);
@ -1108,7 +1108,7 @@ nsDocumentEncoder::EncodeToStringWithMaxLength(uint32_t aMaxLength,
mCachedBuffer->ToString(0, output, true);
// output owns the buffer now!
mCachedBuffer = nullptr;
if (!mSerializer) {
nsAutoCString progId(NS_CONTENTSERIALIZER_CONTRACTID_PREFIX);
@ -1120,8 +1120,6 @@ nsDocumentEncoder::EncodeToStringWithMaxLength(uint32_t aMaxLength,
nsresult rv = NS_OK;
nsCOMPtr<nsIAtom> charsetAtom;
bool rewriteEncodingDeclaration = !(mSelection || mRange || mNode) && !(mFlags & OutputDontRewriteEncodingDeclaration);
mSerializer->Init(mFlags, mWrapColumn, mCharset.get(), mIsCopying, rewriteEncodingDeclaration);
@ -1195,13 +1193,13 @@ nsDocumentEncoder::EncodeToStringWithMaxLength(uint32_t aMaxLength,
NS_ENSURE_SUCCESS(rv, rv);
mCommonAncestors.Clear();
nsContentUtils::GetAncestors(p->GetParentNode(), mCommonAncestors);
mDisableContextSerialize = false;
mDisableContextSerialize = false;
rv = SerializeRangeContextEnd(mCommonAncestors, output);
NS_ENSURE_SUCCESS(rv, rv);
}
// Just to be safe
mDisableContextSerialize = false;
mDisableContextSerialize = false;
mSelection = nullptr;
} else if (mRange) {
@ -1226,7 +1224,7 @@ nsDocumentEncoder::EncodeToStringWithMaxLength(uint32_t aMaxLength,
NS_ENSURE_SUCCESS(rv, rv);
rv = mSerializer->Flush(output);
mCachedBuffer = nsStringBuffer::FromString(output);
// We have to be careful how we set aOutputString, because we don't
// want it to end up sharing mCachedBuffer if we plan to reuse it.
@ -1335,12 +1333,12 @@ protected:
kStart,
kEnd
};
nsresult PromoteRange(nsIDOMRange *inRange);
nsresult PromoteAncestorChain(nsCOMPtr<nsIDOMNode> *ioNode,
int32_t *ioStartOffset,
nsresult PromoteAncestorChain(nsCOMPtr<nsIDOMNode> *ioNode,
int32_t *ioStartOffset,
int32_t *ioEndOffset);
nsresult GetPromotedPoint(Endpoint aWhere, nsIDOMNode *aNode, int32_t aOffset,
nsresult GetPromotedPoint(Endpoint aWhere, nsIDOMNode *aNode, int32_t aOffset,
nsCOMPtr<nsIDOMNode> *outNode, int32_t *outOffset, nsIDOMNode *aCommon);
nsCOMPtr<nsIDOMNode> GetChildAt(nsIDOMNode *aParent, int32_t aOffset);
bool IsMozBR(nsIDOMNode* aNode);
@ -1406,10 +1404,10 @@ nsHTMLCopyEncoder::SetSelection(nsISelection* aSelection)
// check for text widgets: we need to recognize these so that
// we don't tweak the selection to be outside of the magic
// div that ender-lite text widgets are embedded in.
if (!aSelection)
if (!aSelection)
return NS_ERROR_NULL_POINTER;
nsCOMPtr<nsIDOMRange> range;
nsCOMPtr<nsIDOMNode> commonParent;
Selection* selection = aSelection->AsSelection();
@ -1418,7 +1416,7 @@ nsHTMLCopyEncoder::SetSelection(nsISelection* aSelection)
// if selection is uninitialized return
if (!rangeCount)
return NS_ERROR_FAILURE;
// we'll just use the common parent of the first range. Implicit assumption
// here that multi-range selections are table cell selections, in which case
// the common parent is somewhere in the table and we don't really care where.
@ -1481,7 +1479,7 @@ nsHTMLCopyEncoder::SetSelection(nsISelection* aSelection)
}
// normalize selection if we are not in a widget
if (mIsTextWidget)
if (mIsTextWidget)
{
mSelection = aSelection;
mMimeType.AssignLiteral("text/plain");
@ -1496,13 +1494,13 @@ nsHTMLCopyEncoder::SetSelection(nsISelection* aSelection)
// mMimeType is set to text/plain when encoding starts.
return NS_OK;
}
// there's no Clone() for selection! fix...
//nsresult rv = aSelection->Clone(getter_AddRefs(mSelection);
//NS_ENSURE_SUCCESS(rv, rv);
NS_NewDomSelection(getter_AddRefs(mSelection));
NS_ENSURE_TRUE(mSelection, NS_ERROR_FAILURE);
// loop thru the ranges in the selection
for (uint32_t rangeIdx = 0; rangeIdx < rangeCount; ++rangeIdx) {
range = selection->GetRangeAt(rangeIdx);
@ -1514,7 +1512,7 @@ nsHTMLCopyEncoder::SetSelection(nsISelection* aSelection)
// adjust range to include any ancestors who's children are entirely selected
rv = PromoteRange(myRange);
NS_ENSURE_SUCCESS(rv, rv);
rv = mSelection->AddRange(myRange);
NS_ENSURE_SUCCESS(rv, rv);
}
@ -1544,7 +1542,7 @@ nsHTMLCopyEncoder::EncodeToStringWithContext(nsAString& aContextString,
// now encode common ancestors into aContextString. Note that the common ancestors
// will be for the last range in the selection in the case of multirange selections.
// encoding ancestors every range in a multirange selection in a way that could be
// encoding ancestors every range in a multirange selection in a way that could be
// understood by the paste code would be a lot more work to do. As a practical matter,
// selections are single range, and the ones that aren't are table cell selections
// where all the cells are in the same table.
@ -1556,7 +1554,7 @@ nsHTMLCopyEncoder::EncodeToStringWithContext(nsAString& aContextString,
if (count > 0)
node = mCommonAncestors.ElementAt(0);
if (node && IsTextNode(node))
if (node && IsTextNode(node))
{
mCommonAncestors.RemoveElementAt(0);
// don't forget to adjust range depth info
@ -1565,7 +1563,7 @@ nsHTMLCopyEncoder::EncodeToStringWithContext(nsAString& aContextString,
// and the count
count--;
}
i = count;
while (i > 0)
{
@ -1579,7 +1577,7 @@ nsHTMLCopyEncoder::EncodeToStringWithContext(nsAString& aContextString,
SerializeNodeEnd(node, aContextString);
}
// encode range info : the start and end depth of the selection, where the depth is
// encode range info : the start and end depth of the selection, where the depth is
// distance down in the parent hierarchy. Later we will need to add leading/trailing
// whitespace info to this.
nsAutoString infoString;
@ -1587,7 +1585,7 @@ nsHTMLCopyEncoder::EncodeToStringWithContext(nsAString& aContextString,
infoString.Append(char16_t(','));
infoString.AppendInt(mEndDepth);
aInfoString = infoString;
return NS_OK;
}
@ -1629,14 +1627,14 @@ nsHTMLCopyEncoder::IncludeInContext(nsINode *aNode)
}
nsresult
nsresult
nsHTMLCopyEncoder::PromoteRange(nsIDOMRange *inRange)
{
if (!inRange) return NS_ERROR_NULL_POINTER;
nsresult rv;
nsCOMPtr<nsIDOMNode> startNode, endNode, common;
int32_t startOffset, endOffset;
rv = inRange->GetCommonAncestorContainer(getter_AddRefs(common));
NS_ENSURE_SUCCESS(rv, rv);
rv = inRange->GetStartContainer(getter_AddRefs(startNode));
@ -1647,18 +1645,17 @@ nsHTMLCopyEncoder::PromoteRange(nsIDOMRange *inRange)
NS_ENSURE_SUCCESS(rv, rv);
rv = inRange->GetEndOffset(&endOffset);
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIDOMNode> opStartNode;
nsCOMPtr<nsIDOMNode> opEndNode;
int32_t opStartOffset, opEndOffset;
nsCOMPtr<nsIDOMRange> opRange;
// examine range endpoints.
// examine range endpoints.
rv = GetPromotedPoint( kStart, startNode, startOffset, address_of(opStartNode), &opStartOffset, common);
NS_ENSURE_SUCCESS(rv, rv);
rv = GetPromotedPoint( kEnd, endNode, endOffset, address_of(opEndNode), &opEndOffset, common);
NS_ENSURE_SUCCESS(rv, rv);
// if both range endpoints are at the common ancestor, check for possible inclusion of ancestors
if ( (opStartNode == common) && (opEndNode == common) )
{
@ -1666,22 +1663,22 @@ nsHTMLCopyEncoder::PromoteRange(nsIDOMRange *inRange)
NS_ENSURE_SUCCESS(rv, rv);
opEndNode = opStartNode;
}
// set the range to the new values
rv = inRange->SetStart(opStartNode, opStartOffset);
NS_ENSURE_SUCCESS(rv, rv);
rv = inRange->SetEnd(opEndNode, opEndOffset);
return rv;
}
}
// PromoteAncestorChain will promote a range represented by [{*ioNode,*ioStartOffset} , {*ioNode,*ioEndOffset}]
// The promotion is different from that found in getPromotedPoint: it will only promote one endpoint if it can
// promote the other. Thus, instead of having a startnode/endNode, there is just the one ioNode.
nsresult
nsHTMLCopyEncoder::PromoteAncestorChain(nsCOMPtr<nsIDOMNode> *ioNode,
int32_t *ioStartOffset,
int32_t *ioEndOffset)
nsHTMLCopyEncoder::PromoteAncestorChain(nsCOMPtr<nsIDOMNode> *ioNode,
int32_t *ioStartOffset,
int32_t *ioEndOffset)
{
if (!ioNode || !ioStartOffset || !ioEndOffset) return NS_ERROR_NULL_POINTER;
@ -1694,7 +1691,7 @@ nsHTMLCopyEncoder::PromoteAncestorChain(nsCOMPtr<nsIDOMNode> *ioNode,
//save the editable state of the ioNode, so we don't promote an ancestor if it has different editable state
nsCOMPtr<nsINode> node = do_QueryInterface(*ioNode);
bool isEditable = node->IsEditable();
// loop for as long as we can promote both endpoints
while (!done)
{
@ -1712,13 +1709,13 @@ nsHTMLCopyEncoder::PromoteAncestorChain(nsCOMPtr<nsIDOMNode> *ioNode,
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsINode> frontINode = do_QueryInterface(frontNode);
// if both endpoints were promoted one level and isEditable is the same as the original node,
// if both endpoints were promoted one level and isEditable is the same as the original node,
// keep looping - otherwise we are done.
if ( (frontNode != parent) || (endNode != parent) || (frontINode->IsEditable() != isEditable) )
done = true;
else
{
*ioNode = frontNode;
*ioNode = frontNode;
*ioStartOffset = frontOffset;
*ioEndOffset = endOffset;
}
@ -1728,7 +1725,7 @@ nsHTMLCopyEncoder::PromoteAncestorChain(nsCOMPtr<nsIDOMNode> *ioNode,
}
nsresult
nsHTMLCopyEncoder::GetPromotedPoint(Endpoint aWhere, nsIDOMNode *aNode, int32_t aOffset,
nsHTMLCopyEncoder::GetPromotedPoint(Endpoint aWhere, nsIDOMNode *aNode, int32_t aOffset,
nsCOMPtr<nsIDOMNode> *outNode, int32_t *outOffset, nsIDOMNode *common)
{
nsresult rv = NS_OK;
@ -1736,14 +1733,14 @@ nsHTMLCopyEncoder::GetPromotedPoint(Endpoint aWhere, nsIDOMNode *aNode, int32_t
nsCOMPtr<nsIDOMNode> parent = aNode;
int32_t offset = aOffset;
bool bResetPromotion = false;
// default values
*outNode = node;
*outOffset = offset;
if (common == node)
if (common == node)
return NS_OK;
if (aWhere == kStart)
{
// some special casing for text nodes
@ -1751,7 +1748,7 @@ nsHTMLCopyEncoder::GetPromotedPoint(Endpoint aWhere, nsIDOMNode *aNode, int32_t
if (IsTextNode(t))
{
// if not at beginning of text node, we are done
if (offset > 0)
if (offset > 0)
{
// unless everything before us in just whitespace. NOTE: we need a more
// general solution that truly detects all cases of non-significant
@ -1774,7 +1771,7 @@ nsHTMLCopyEncoder::GetPromotedPoint(Endpoint aWhere, nsIDOMNode *aNode, int32_t
}
if (!node) node = parent;
// finding the real start for this point. look up the tree for as long as we are the
// finding the real start for this point. look up the tree for as long as we are the
// first node in the container, and as long as we haven't hit the body node.
if (!IsRoot(node) && (parent != common))
{
@ -1798,9 +1795,9 @@ nsHTMLCopyEncoder::GetPromotedPoint(Endpoint aWhere, nsIDOMNode *aNode, int32_t
{
bResetPromotion = false;
}
}
}
}
node = parent;
rv = GetNodeLocation(node, address_of(parent), &offset);
NS_ENSURE_SUCCESS(rv, rv);
@ -1811,7 +1808,7 @@ nsHTMLCopyEncoder::GetPromotedPoint(Endpoint aWhere, nsIDOMNode *aNode, int32_t
offset = 0;
break;
}
}
}
if (bResetPromotion)
{
*outNode = aNode;
@ -1825,7 +1822,7 @@ nsHTMLCopyEncoder::GetPromotedPoint(Endpoint aWhere, nsIDOMNode *aNode, int32_t
return rv;
}
}
if (aWhere == kEnd)
{
// some special casing for text nodes
@ -1856,8 +1853,8 @@ nsHTMLCopyEncoder::GetPromotedPoint(Endpoint aWhere, nsIDOMNode *aNode, int32_t
node = GetChildAt(parent,offset);
}
if (!node) node = parent;
// finding the real end for this point. look up the tree for as long as we are the
// finding the real end for this point. look up the tree for as long as we are the
// last node in the container, and as long as we haven't hit the body node.
if (!IsRoot(node) && (parent != common))
{
@ -1881,9 +1878,9 @@ nsHTMLCopyEncoder::GetPromotedPoint(Endpoint aWhere, nsIDOMNode *aNode, int32_t
{
bResetPromotion = false;
}
}
}
}
node = parent;
rv = GetNodeLocation(node, address_of(parent), &offset);
NS_ENSURE_SUCCESS(rv, rv);
@ -1894,7 +1891,7 @@ nsHTMLCopyEncoder::GetPromotedPoint(Endpoint aWhere, nsIDOMNode *aNode, int32_t
offset = 0;
break;
}
}
}
if (bResetPromotion)
{
*outNode = aNode;
@ -1909,18 +1906,18 @@ nsHTMLCopyEncoder::GetPromotedPoint(Endpoint aWhere, nsIDOMNode *aNode, int32_t
return rv;
}
}
return rv;
}
nsCOMPtr<nsIDOMNode>
nsCOMPtr<nsIDOMNode>
nsHTMLCopyEncoder::GetChildAt(nsIDOMNode *aParent, int32_t aOffset)
{
nsCOMPtr<nsIDOMNode> resultNode;
if (!aParent)
if (!aParent)
return resultNode;
nsCOMPtr<nsIContent> content = do_QueryInterface(aParent);
NS_PRECONDITION(content, "null content in nsHTMLCopyEncoder::GetChildAt");
@ -1929,7 +1926,7 @@ nsHTMLCopyEncoder::GetChildAt(nsIDOMNode *aParent, int32_t aOffset)
return resultNode;
}
bool
bool
nsHTMLCopyEncoder::IsMozBR(nsIDOMNode* aNode)
{
MOZ_ASSERT(aNode);
@ -1940,7 +1937,7 @@ nsHTMLCopyEncoder::IsMozBR(nsIDOMNode* aNode)
NS_LITERAL_STRING("_moz"), eIgnoreCase);
}
nsresult
nsresult
nsHTMLCopyEncoder::GetNodeLocation(nsIDOMNode *inChild,
nsCOMPtr<nsIDOMNode> *outParent,
int32_t *outOffset)
@ -1986,26 +1983,26 @@ nsHTMLCopyEncoder::IsFirstNode(nsIDOMNode *aNode)
nsCOMPtr<nsIDOMNode> parent;
int32_t offset, j=0;
nsresult rv = GetNodeLocation(aNode, address_of(parent), &offset);
if (NS_FAILED(rv))
if (NS_FAILED(rv))
{
NS_NOTREACHED("failure in IsFirstNode");
return false;
}
if (offset == 0) // easy case, we are first dom child
return true;
if (!parent)
if (!parent)
return true;
// need to check if any nodes before us are really visible.
// Mike wrote something for me along these lines in nsSelectionController,
// but I don't think it's ready for use yet - revisit.
// HACK: for now, simply consider all whitespace text nodes to be
// HACK: for now, simply consider all whitespace text nodes to be
// invisible formatting nodes.
nsCOMPtr<nsIDOMNodeList> childList;
nsCOMPtr<nsIDOMNode> child;
rv = parent->GetChildNodes(getter_AddRefs(childList));
if (NS_FAILED(rv) || !childList)
if (NS_FAILED(rv) || !childList)
{
NS_NOTREACHED("failure in IsFirstNode");
return true;
@ -2013,7 +2010,7 @@ nsHTMLCopyEncoder::IsFirstNode(nsIDOMNode *aNode)
while (j < offset)
{
childList->Item(j, getter_AddRefs(child));
if (!IsEmptyTextContent(child))
if (!IsEmptyTextContent(child))
return false;
j++;
}
@ -2027,7 +2024,7 @@ nsHTMLCopyEncoder::IsLastNode(nsIDOMNode *aNode)
nsCOMPtr<nsIDOMNode> parent;
int32_t offset,j;
nsresult rv = GetNodeLocation(aNode, address_of(parent), &offset);
if (NS_FAILED(rv))
if (NS_FAILED(rv))
{
NS_NOTREACHED("failure in IsLastNode");
return false;
@ -2043,13 +2040,13 @@ nsHTMLCopyEncoder::IsLastNode(nsIDOMNode *aNode)
// need to check if any nodes after us are really visible.
// Mike wrote something for me along these lines in nsSelectionController,
// but I don't think it's ready for use yet - revisit.
// HACK: for now, simply consider all whitespace text nodes to be
// HACK: for now, simply consider all whitespace text nodes to be
// invisible formatting nodes.
j = (int32_t)numChildren-1;
nsCOMPtr<nsIDOMNodeList>childList;
nsCOMPtr<nsIDOMNode> child;
rv = parent->GetChildNodes(getter_AddRefs(childList));
if (NS_FAILED(rv) || !childList)
if (NS_FAILED(rv) || !childList)
{
NS_NOTREACHED("failure in IsLastNode");
return true;
@ -2058,9 +2055,9 @@ nsHTMLCopyEncoder::IsLastNode(nsIDOMNode *aNode)
{
childList->Item(j, getter_AddRefs(child));
j--;
if (IsMozBR(child)) // we ignore trailing moz BRs.
if (IsMozBR(child)) // we ignore trailing moz BRs.
continue;
if (!IsEmptyTextContent(child))
if (!IsEmptyTextContent(child))
return false;
}
return true;
@ -2105,4 +2102,3 @@ nsHTMLCopyEncoder::GetImmediateContextCount(const nsTArray<nsINode*>& aAncestorA
}
return j;
}

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

@ -14020,7 +14020,6 @@ nsGlobalModalWindow::GetReturnValue(nsIVariant **aRetVal)
{
FORWARD_TO_OUTER_MODAL_CONTENT_WINDOW(GetReturnValue, (aRetVal), NS_OK);
nsCOMPtr<nsIVariant> result;
if (!mReturnValue) {
nsCOMPtr<nsIVariant> variant = CreateVoidVariant();
variant.forget(aRetVal);

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

@ -220,7 +220,6 @@ class BlobURLsReporter final : public nsIMemoryReporter
"blob cannot be freed until all URLs for it have been explicitly "
"invalidated with URL.revokeObjectURL.");
nsAutoCString path, url, owner, specialDesc;
nsCOMPtr<nsIURI> principalURI;
uint64_t size = 0;
uint32_t refCount = 1;
DebugOnly<bool> blobImplWasCounted;

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

@ -263,7 +263,6 @@ nsLocation::SetURI(nsIURI* aURI, bool aReplace)
nsCOMPtr<nsIDocShell> docShell(do_QueryReferent(mDocShell));
if (docShell) {
nsCOMPtr<nsIDocShellLoadInfo> loadInfo;
nsCOMPtr<nsIWebNavigation> webNav(do_QueryInterface(docShell));
if(NS_FAILED(CheckURL(aURI, getter_AddRefs(loadInfo))))
return NS_ERROR_FAILURE;

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

@ -2660,7 +2660,6 @@ nsScriptLoader::PrepareLoadedRequest(nsScriptLoadRequest* aRequest,
return NS_ERROR_FAILURE;
}
nsCOMPtr<nsIURI> baseURL;
channel->GetURI(getter_AddRefs(request->mBaseURL));
// Attempt to compile off main thread.

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

@ -3118,8 +3118,6 @@ nsDOMDeviceStorage::AddOrAppendNamed(Blob* aBlob, const nsAString& aPath,
return nullptr;
}
nsCOMPtr<nsIRunnable> r;
if (IsFullPath(aPath)) {
nsString storagePath;
RefPtr<nsDOMDeviceStorage> ds = GetStorage(aPath, storagePath);

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

@ -614,7 +614,6 @@ HTMLSelectElement::Add(nsIDOMHTMLElement* aElement,
}
nsCOMPtr<nsISupports> supports;
nsCOMPtr<nsIDOMHTMLElement> beforeElement;
// whether aBefore is nsIDOMHTMLElement...
if (NS_SUCCEEDED(aBefore->GetAsISupports(getter_AddRefs(supports)))) {

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

@ -3123,9 +3123,6 @@ nsGenericHTMLElement::GetInnerText(mozilla::dom::DOMString& aValue,
void
nsGenericHTMLElement::SetInnerText(const nsAString& aValue)
{
// Fire DOMNodeRemoved mutation events before we do anything else.
nsCOMPtr<nsIContent> kungFuDeathGrip;
// Batch possible DOMSubtreeModified events.
mozAutoSubtreeModified subtree(OwnerDoc(), nullptr);
FireNodeRemovedForChildren();

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

@ -1303,6 +1303,14 @@ StartMacOSContentSandbox()
MOZ_CRASH("Failed to get NS_OS_TEMP_DIR path");
}
nsCOMPtr<nsIFile> profileDir;
ContentChild::GetSingleton()->GetProfileDir(getter_AddRefs(profileDir));
nsCString profileDirPath;
rv = profileDir->GetNativePath(profileDirPath);
if (NS_FAILED(rv)) {
MOZ_CRASH("Failed to get profile path");
}
MacSandboxInfo info;
info.type = MacSandboxType_Content;
info.level = info.level = sandboxLevel;
@ -1310,6 +1318,7 @@ StartMacOSContentSandbox()
info.appBinaryPath.assign(appBinaryPath.get());
info.appDir.assign(appDir.get());
info.appTempDir.assign(tempDirPath.get());
info.profileDir.assign(profileDirPath.get());
std::string err;
if (!mozilla::StartMacSandbox(info, err)) {

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

@ -21,6 +21,9 @@
#include "nsWeakPtr.h"
#include "nsIWindowProvider.h"
#if defined(XP_MACOSX) && defined(MOZ_CONTENT_SANDBOX)
#include "nsIFile.h"
#endif
struct ChromePackage;
class nsIObserver;
@ -114,6 +117,19 @@ public:
void GetProcessName(nsACString& aName) const;
#if defined(XP_MACOSX) && defined(MOZ_CONTENT_SANDBOX)
void GetProfileDir(nsIFile** aProfileDir) const
{
*aProfileDir = mProfileDir;
NS_IF_ADDREF(*aProfileDir);
}
void SetProfileDir(nsIFile* aProfileDir)
{
mProfileDir = aProfileDir;
}
#endif
bool IsAlive() const;
static void AppendProcessId(nsACString& aName);
@ -681,6 +697,10 @@ private:
nsCOMPtr<nsIDomainPolicy> mPolicy;
nsCOMPtr<nsITimer> mForceKillTimer;
#if defined(XP_MACOSX) && defined(MOZ_CONTENT_SANDBOX)
nsCOMPtr<nsIFile> mProfileDir;
#endif
// Hashtable to keep track of the pending GetFilesHelper objects.
// This GetFilesHelperChild objects are removed when RecvGetFilesResponse is
// received.

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

@ -1085,7 +1085,6 @@ ContentParent::CreateBrowserOrApp(const TabContext& aContext,
}
if (aContext.IsMozBrowserElement() || !aContext.HasOwnApp()) {
RefPtr<TabParent> tp;
RefPtr<nsIContentParent> constructorSender;
if (isInContentProcess) {
MOZ_ASSERT(aContext.IsMozBrowserElement());

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

@ -114,6 +114,21 @@ ContentProcess::SetAppDir(const nsACString& aPath)
mXREEmbed.SetAppDir(aPath);
}
#if defined(XP_MACOSX) && defined(MOZ_CONTENT_SANDBOX)
void
ContentProcess::SetProfile(const nsACString& aProfile)
{
bool flag;
nsresult rv =
XRE_GetFileFromPath(aProfile.BeginReading(), getter_AddRefs(mProfileDir));
if (NS_FAILED(rv) ||
NS_FAILED(mProfileDir->Exists(&flag)) || !flag) {
NS_WARNING("Invalid profile directory passed to content process.");
mProfileDir = nullptr;
}
}
#endif
bool
ContentProcess::Init()
{
@ -124,6 +139,10 @@ ContentProcess::Init()
mContent.InitXPCOM();
mContent.InitGraphicsDeviceData();
#if (defined(XP_MACOSX)) && defined(MOZ_CONTENT_SANDBOX)
mContent.SetProfileDir(mProfileDir);
#endif
#if (defined(XP_WIN) || defined(XP_MACOSX)) && defined(MOZ_CONTENT_SANDBOX)
SetUpSandboxEnvironment();
#endif

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

@ -39,9 +39,18 @@ public:
void SetAppDir(const nsACString& aPath);
#if defined(XP_MACOSX) && defined(MOZ_CONTENT_SANDBOX)
void SetProfile(const nsACString& aProfile);
#endif
private:
ContentChild mContent;
mozilla::ipc::ScopedXREEmbed mXREEmbed;
#if defined(XP_MACOSX) && defined(MOZ_CONTENT_SANDBOX)
nsCOMPtr<nsIFile> mProfileDir;
#endif
#if defined(XP_WIN)
// This object initializes and configures COM.
mozilla::mscom::MainThreadRuntime mCOMRuntime;

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

@ -398,21 +398,31 @@ SystemClockDriver::WaitForNextIteration()
PRIntervalTime timeout = PR_INTERVAL_NO_TIMEOUT;
TimeStamp now = TimeStamp::Now();
if (mGraphImpl->mNeedAnotherIteration) {
// This lets us avoid hitting the Atomic twice when we know we won't sleep
bool another = mGraphImpl->mNeedAnotherIteration; // atomic
if (!another) {
mGraphImpl->mGraphDriverAsleep = true; // atomic
mWaitState = WAITSTATE_WAITING_INDEFINITELY;
}
// NOTE: mNeedAnotherIteration while also atomic may have changed before
// we could set mGraphDriverAsleep, so we must re-test it.
// (EnsureNextIteration sets mNeedAnotherIteration, then tests
// mGraphDriverAsleep
if (another || mGraphImpl->mNeedAnotherIteration) { // atomic
int64_t timeoutMS = MEDIA_GRAPH_TARGET_PERIOD_MS -
int64_t((now - mCurrentTimeStamp).ToMilliseconds());
// Make sure timeoutMS doesn't overflow 32 bits by waking up at
// least once a minute, if we need to wake up at all
timeoutMS = std::max<int64_t>(0, std::min<int64_t>(timeoutMS, 60*1000));
timeout = PR_MillisecondsToInterval(uint32_t(timeoutMS));
STREAM_LOG(LogLevel::Verbose, ("Waiting for next iteration; at %f, timeout=%f", (now - mInitialTimeStamp).ToSeconds(), timeoutMS/1000.0));
STREAM_LOG(LogLevel::Verbose,
("Waiting for next iteration; at %f, timeout=%f",
(now - mInitialTimeStamp).ToSeconds(), timeoutMS/1000.0));
if (mWaitState == WAITSTATE_WAITING_INDEFINITELY) {
mGraphImpl->mGraphDriverAsleep = false; // atomic
}
mWaitState = WAITSTATE_WAITING_FOR_NEXT_ITERATION;
} else {
mGraphImpl->mGraphDriverAsleep = true; // atomic
mWaitState = WAITSTATE_WAITING_INDEFINITELY;
}
if (timeout > 0) {
mGraphImpl->GetMonitor().Wait(timeout);
@ -424,13 +434,19 @@ SystemClockDriver::WaitForNextIteration()
if (mWaitState == WAITSTATE_WAITING_INDEFINITELY) {
mGraphImpl->mGraphDriverAsleep = false; // atomic
}
// Note: this can race against the EnsureNextIteration setting
// WAITSTATE_RUNNING and setting mGraphDriverAsleep to false, so you can
// have an iteration with WAITSTATE_WAKING_UP instead of RUNNING.
mWaitState = WAITSTATE_RUNNING;
mGraphImpl->mNeedAnotherIteration = false;
mGraphImpl->mNeedAnotherIteration = false; // atomic
}
void SystemClockDriver::WakeUp()
{
mGraphImpl->GetMonitor().AssertCurrentThreadOwns();
// Note: this can race against the thread setting WAITSTATE_RUNNING and
// setting mGraphDriverAsleep to false, so you can have an iteration
// with WAITSTATE_WAKING_UP instead of RUNNING.
mWaitState = WAITSTATE_WAKING_UP;
mGraphImpl->mGraphDriverAsleep = false; // atomic
mGraphImpl->GetMonitor().Notify();

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

@ -528,8 +528,6 @@ MediaDecoderReader::Shutdown()
// Shut down the watch manager before shutting down our task queue.
mWatchManager.Shutdown();
RefPtr<ShutdownPromise> p;
mDecoder = nullptr;
ReaderQueue::Instance().Remove(this);

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

@ -522,6 +522,8 @@ public:
void EnsureNextIteration()
{
mNeedAnotherIteration = true; // atomic
// Note: GraphDriver must ensure that there's no race on setting
// mNeedAnotherIteration and mGraphDriverAsleep -- see WaitForNextIteration()
if (mGraphDriverAsleep) { // atomic
MonitorAutoLock mon(mMonitor);
CurrentDriver()->WakeUp(); // Might not be the same driver; might have woken already

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

@ -36,7 +36,7 @@
// Service instantiation
#include "ipc/SmsIPCService.h"
#include "MobileMessageService.h"
#ifdef MOZ_WIDGET_ANDROID
#if defined(MOZ_WIDGET_ANDROID) && defined(MOZ_WEBSMS_BACKEND)
#include "android/MobileMessageDatabaseService.h"
#include "android/SmsService.h"
#elif defined(MOZ_WIDGET_GONK) && defined(MOZ_B2G_RIL)
@ -853,7 +853,7 @@ NS_CreateSmsService()
if (XRE_IsContentProcess()) {
smsService = SmsIPCService::GetSingleton();
} else {
#ifdef MOZ_WIDGET_ANDROID
#if defined(MOZ_WIDGET_ANDROID) && defined(MOZ_WEBSMS_BACKEND)
smsService = new SmsService();
#elif defined(MOZ_WIDGET_GONK) && defined(MOZ_B2G_RIL)
smsService = do_GetService(GONK_SMSSERVICE_CONTRACTID);
@ -870,7 +870,7 @@ NS_CreateMobileMessageDatabaseService()
if (XRE_IsContentProcess()) {
mobileMessageDBService = SmsIPCService::GetSingleton();
} else {
#ifdef MOZ_WIDGET_ANDROID
#if defined(MOZ_WIDGET_ANDROID) && defined(MOZ_WEBSMS_BACKEND)
mobileMessageDBService = new MobileMessageDatabaseService();
#elif defined(MOZ_WIDGET_GONK) && defined(MOZ_B2G_RIL)
mobileMessageDBService =

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

@ -16,7 +16,7 @@ EXPORTS.mozilla.dom.mobilemessage += [
'Types.h', # Required by IPDL SmsTypes.h
]
if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'android':
if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'android' and CONFIG['MOZ_WEBSMS_BACKEND']:
SOURCES += [
'android/MobileMessageDatabaseService.cpp',
'android/SmsManager.cpp',

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

@ -0,0 +1,2 @@
<h1>I'm just a support file</h1>
<p>I get loaded to do permission testing.</p>

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

@ -2,6 +2,7 @@
support-files =
file_framework.js
file_shim.html
file_empty.html
[test_alarms.html]
skip-if = true

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

@ -4,143 +4,203 @@
-->
<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
<title>Test for Permissions API</title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
<link rel="stylesheet" href="/tests/SimpleTest/test.css">
</head>
<body onload='runTests()'>
<pre id="test">
<script type="application/javascript;version=1.8">
'use strict';
let { UNKNOWN_ACTION, PROMPT_ACTION, ALLOW_ACTION, DENY_ACTION } =
SpecialPowers.Ci.nsIPermissionManager;
<body>
<pre id="test"></pre>
<script type="application/javascript;version=1.8">
/*globals SpecialPowers, SimpleTest, is, ok, */
'use strict';
SimpleTest.waitForExplicitFinish();
const {
UNKNOWN_ACTION,
PROMPT_ACTION,
ALLOW_ACTION,
DENY_ACTION
} = SpecialPowers.Ci.nsIPermissionManager;
const PERMISSIONS = [
{ name: 'geolocation', perm: 'geo' },
{ name: 'notifications', perm: 'desktop-notification' },
{ name: 'push', perm: 'desktop-notification' },
];
SimpleTest.waitForExplicitFinish();
const UNSUPPORTED_PERMISSIONS = [
'foobarbaz', // Not in spec, for testing only.
'midi'
];
const PERMISSIONS = [{
name: 'geolocation',
type: 'geo'
}, {
name: 'notifications',
type: 'desktop-notification'
}, {
name: 'push',
type: 'desktop-notification'
}, ];
function setPermissions(action) {
let permissions = PERMISSIONS.map(x => {
return { 'type': x.perm, 'allow': action, 'context': document };
});
return new Promise((resolve, reject) => {
SpecialPowers.popPermissions(() => {
SpecialPowers.pushPermissions(permissions, resolve);
const UNSUPPORTED_PERMISSIONS = [
'foobarbaz', // Not in spec, for testing only.
'midi',
];
// Create a closure, so that tests are run on the correct window object.
function createPermissionTester(aWindow) {
return {
setPermissions(allow) {
const permissions = PERMISSIONS.map(({ type }) => {
return {
type,
allow,
'context': aWindow.document
};
});
return new Promise((resolve) => {
SpecialPowers.popPermissions(() => {
SpecialPowers.pushPermissions(permissions, resolve);
});
});
},
revokePermissions() {
const promisesToRevoke = PERMISSIONS.map(({ name }) => {
return aWindow.navigator.permissions
.revoke({ name })
.then(
({ state }) => is(state, 'prompt', `correct state for '${name}'`),
() => ok(false, `revoke should not have rejected for '${name}'`)
);
});
return Promise.all(promisesToRevoke);
},
revokeUnsupportedPermissions() {
const promisesToRevoke = UNSUPPORTED_PERMISSIONS.map(({ name }) => {
return aWindow.navigator.permissions
.revoke({ name })
.then(
() => ok(false, `revoke should not have resolved for '${name}'`),
error => is(error.name, 'TypeError', `revoke should have thrown TypeError for '${name}'`)
);
});
return Promise.all(promisesToRevoke);
},
checkPermissions(state) {
const promisesToQuery = PERMISSIONS.map(({ name }) => {
return aWindow.navigator.permissions
.query({ name })
.then(
() => is(state, state, `correct state for '${name}'`),
() => ok(false, `query should not have rejected for '${name}'`)
);
});
return Promise.all(promisesToQuery);
},
checkUnsupportedPermissions() {
const promisesToQuery = UNSUPPORTED_PERMISSIONS.map(({ name }) => {
return aWindow.navigator.permissions
.query({ name })
.then(
() => ok(false, `query should not have resolved for '${name}'`),
error => {
is(error.name, 'TypeError',
`query should have thrown TypeError for '${name}'`);
}
);
});
return Promise.all(promisesToQuery);
},
promiseStateChanged(name, state) {
return aWindow.navigator.permissions
.query({ name })
.then(status => {
return new Promise( resolve => {
status.onchange = () => {
status.onchange = null;
is(status.state, state, `state changed for '${name}'`);
resolve();
};
});
},
() => ok(false, `query should not have rejected for '${name}'`));
},
testStatusOnChange() {
return new Promise((resolve) => {
SpecialPowers.popPermissions(() => {
const permission = 'geolocation';
const promiseGranted = this.promiseStateChanged(permission, 'granted');
this.setPermissions(ALLOW_ACTION);
promiseGranted.then(() => {
const promisePrompt = this.promiseStateChanged(permission, 'prompt');
SpecialPowers.popPermissions();
return promisePrompt;
}).then(resolve);
});
});
},
testInvalidQuery() {
return aWindow.navigator.permissions
.query({ name: 'invalid' })
.then(
() => ok(false, 'invalid query should not have resolved'),
() => ok(true, 'invalid query should have rejected')
);
},
testInvalidRevoke() {
return aWindow.navigator.permissions
.revoke({ name: 'invalid' })
.then(
() => ok(false, 'invalid revoke should not have resolved'),
() => ok(true, 'invalid revoke should have rejected')
);
},
};
}
function enablePrefs() {
const ops = {
'set': [
['dom.permissions.revoke.enable', true],
],
};
return SpecialPowers.pushPrefEnv(ops);
}
function createIframe() {
return new Promise((resolve) => {
const iframe = document.createElement('iframe');
iframe.src = 'file_empty.html';
iframe.onload = () => resolve(iframe.contentWindow);
document.body.appendChild(iframe);
});
});
}
function revokePermissions(action) {
return Promise.all(PERMISSIONS.map(x =>
navigator.permissions.revoke({ name: x.name }).then(
result => is(result.state, "prompt", `correct state for '${x.name}'`),
error => ok(false, `revoke should not have rejected for '${x.name}'`))
));
}
function revokeUnsupportedPermissions() {
return Promise.all(UNSUPPORTED_PERMISSIONS.map(name =>
navigator.permissions.revoke({ name: name }).then(
result => ok(false, `revoke should not have resolved for '${name}'`),
error => is(error.name, 'TypeError', `revoke should have thrown TypeError for '${name}'`))
));
}
function checkPermissions(state) {
return Promise.all(PERMISSIONS.map(x => {
return navigator.permissions.query({ name: x.name }).then(
result => is(result.state, state, `correct state for '${x.name}'`),
error => ok(false, `query should not have rejected for '${x.name}'`));
}));
}
function checkUnsupportedPermissions() {
return Promise.all(UNSUPPORTED_PERMISSIONS.map(name => {
return navigator.permissions.query({ name: name }).then(
result => ok(false, `query should not have resolved for '${name}'`),
error => {
is(error.name, 'TypeError',
`query should have thrown TypeError for '${name}'`);
}
debugger;
window.onload = () => {
enablePrefs()
.then(createIframe)
.then(createPermissionTester)
.then((tester) => {
return tester
.checkUnsupportedPermissions()
.then(() => tester.setPermissions(UNKNOWN_ACTION))
.then(() => tester.checkPermissions('prompt'))
.then(() => tester.setPermissions(PROMPT_ACTION))
.then(() => tester.checkPermissions('prompt'))
.then(() => tester.setPermissions(ALLOW_ACTION))
.then(() => tester.checkPermissions('granted'))
.then(() => tester.setPermissions(DENY_ACTION))
.then(() => tester.checkPermissions('denied'))
.then(() => tester.testStatusOnChange())
.then(() => tester.testInvalidQuery())
.then(() => tester.revokeUnsupportedPermissions())
.then(() => tester.revokePermissions())
.then(() => tester.checkPermissions('prompt'))
.then(() => tester.testInvalidRevoke());
})
.then(SimpleTest.finish)
.catch((e) => {
ok(false, `Unexpected error ${e}`);
SimpleTest.finish();
});
}));
}
function promiseStateChanged(name, state) {
return navigator.permissions.query({ name }).then(
status => {
return new Promise((resolve, reject) => {
status.onchange = () => {
status.onchange = null;
is(status.state, state, `state changed for '${name}'`);
resolve();
};
});
},
error => ok(false, `query should not have rejected for '${name}'`));
}
function testStatusOnChange() {
return new Promise((resolve, reject) => {
SpecialPowers.popPermissions(() => {
let permission = 'geolocation';
let promiseGranted = promiseStateChanged(permission, 'granted');
setPermissions(ALLOW_ACTION);
promiseGranted.then(() => {
let promisePrompt = promiseStateChanged(permission, 'prompt');
SpecialPowers.popPermissions();
return promisePrompt;
}).then(resolve);
});
});
}
function testInvalidQuery() {
navigator.permissions.query({ name: 'invalid' }).then(
result => ok(false, 'invalid query should not have resolved'),
error => ok(true, 'invalid query should have rejected'));
}
function testInvalidRevoke() {
navigator.permissions.revoke({ name: 'invalid' }).then(
result => ok(false, 'invalid revoke should not have resolved'),
error => ok(true, 'invalid revoke should have rejected'));
}
function runTests() {
checkUnsupportedPermissions()
.then(() => setPermissions(UNKNOWN_ACTION))
.then(() => checkPermissions('prompt'))
.then(() => setPermissions(PROMPT_ACTION))
.then(() => checkPermissions('prompt'))
.then(() => setPermissions(ALLOW_ACTION))
.then(() => checkPermissions('granted'))
.then(() => setPermissions(DENY_ACTION))
.then(() => checkPermissions('denied'))
.then(testStatusOnChange)
.then(testInvalidQuery)
.then(revokeUnsupportedPermissions)
.then(revokePermissions)
.then(() => checkPermissions('prompt'))
.then(testInvalidRevoke)
.then(SimpleTest.finish)
.catch ((e) => {
ok(false, 'Unexpected error ' + e);
SimpleTest.finish();
});
}
</script>
</pre>
};
</script>
</body>
</html>

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

@ -411,7 +411,6 @@ nsPluginStreamListenerPeer::SetupPluginCacheFile(nsIChannel* channel)
return rv;
// create a file output stream to write to...
nsCOMPtr<nsIOutputStream> outstream;
rv = NS_NewLocalFileOutputStream(getter_AddRefs(mFileCacheOutputStream), pluginTmp, -1, 00600);
if (NS_FAILED(rv))
return rv;

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

@ -3355,7 +3355,6 @@ PluginInstanceChild::CreateOptSurface(void)
"Need a valid surface type here");
NS_ASSERTION(!mCurrentSurface, "mCurrentSurfaceActor can get out of sync.");
RefPtr<gfxASurface> retsurf;
// Use an opaque surface unless we're transparent and *don't* have
// a background to source from.
gfxImageFormat format =
@ -3581,7 +3580,9 @@ PluginInstanceChild::EnsureCurrentBuffer(void)
void
PluginInstanceChild::UpdateWindowAttributes(bool aForceSetWindow)
{
#if defined(MOZ_X11) || defined(XP_WIN)
RefPtr<gfxASurface> curSurface = mHelperSurface ? mHelperSurface : mCurrentSurface;
#endif // Only used within MOZ_X11 or XP_WIN blocks. Unused variable otherwise
bool needWindowUpdate = aForceSetWindow;
#ifdef MOZ_X11
Visual* visual = nullptr;

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

@ -7488,8 +7488,6 @@ UpgradeDirectoryMetadataFrom1To2Helper::DoProcessOriginDirectories()
{
AssertIsOnIOThread();
nsCOMPtr<nsIFile> permanentStorageDir;
for (uint32_t count = mOriginProps.Length(), index = 0;
index < count;
index++) {

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

@ -457,7 +457,6 @@ DOMStorageDBThread::OpenDatabaseConnection()
= do_GetService(MOZ_STORAGE_SERVICE_CONTRACTID, &rv);
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<mozIStorageConnection> connection;
rv = service->OpenUnsharedDatabase(mDatabaseFile, getter_AddRefs(mWorkerConnection));
if (rv == NS_ERROR_FILE_CORRUPTED) {
// delete the db and try opening again

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

@ -25,6 +25,6 @@ dictionary PermissionDescriptor {
interface Permissions {
[Throws]
Promise<PermissionStatus> query(object permission);
[Throws]
[Throws, Pref="dom.permissions.revoke.enable"]
Promise<PermissionStatus> revoke(object permission);
};

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

@ -1050,7 +1050,8 @@ public:
const nsString& aLine, uint32_t aLineNumber,
uint32_t aColumnNumber, uint32_t aFlags,
uint32_t aErrorNumber, JSExnType aExnType,
bool aMutedError, uint64_t aInnerWindowId)
bool aMutedError, uint64_t aInnerWindowId,
JS::Handle<JS::Value> aException = JS::NullHandleValue)
{
if (aWorkerPrivate) {
aWorkerPrivate->AssertIsOnWorkerThread();
@ -1070,6 +1071,7 @@ public:
init.mMessage = aMessage;
init.mFilename = aFilename;
init.mLineno = aLineNumber;
init.mError = aException;
}
init.mCancelable = true;
@ -5919,6 +5921,12 @@ WorkerPrivate::ReportError(JSContext* aCx, const char* aFallbackMessage,
mErrorHandlerRecursionCount == 1,
"Bad recursion logic!");
JS::Rooted<JS::Value> exn(aCx);
if (!JS_GetPendingException(aCx, &exn)) {
// Probably shouldn't actually happen? But let's go ahead and just use null
// for lack of anything better.
exn.setNull();
}
JS_ClearPendingException(aCx);
nsString message, filename, line;
@ -5966,7 +5974,7 @@ WorkerPrivate::ReportError(JSContext* aCx, const char* aFallbackMessage,
ReportErrorRunnable::ReportError(aCx, this, fireAtScope, nullptr, message,
filename, line, lineNumber,
columnNumber, flags, errorNumber, exnType,
mutedError, 0);
mutedError, 0, exn);
mErrorHandlerRecursionCount--;
}

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

@ -2613,7 +2613,7 @@ XMLHttpRequestMainThread::InitiateFetch(nsIInputStream* aUploadStream,
// Per spec, we throw on sync errors, but not async.
if (mFlagSynchronous) {
return rv;
return NS_ERROR_DOM_NETWORK_ERR;
}
}
@ -2874,7 +2874,7 @@ XMLHttpRequestMainThread::SendInternal(const RequestBodyBase* aBody)
if (!mChannel) {
// Per spec, silently fail on async request failures; throw for sync.
if (mFlagSynchronous) {
return NS_ERROR_FAILURE;
return NS_ERROR_DOM_NETWORK_ERR;
} else {
// Defer the actual sending of async events just in case listeners
// are attached after the send() method is called.

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

@ -167,8 +167,6 @@ nsXMLFragmentContentSink::WillBuildModel(nsDTDMode aDTDMode)
NS_IMETHODIMP
nsXMLFragmentContentSink::DidBuildModel(bool aTerminated)
{
RefPtr<nsParserBase> kungFuDeathGrip(mParser);
// Drop our reference to the parser to get rid of a circular
// reference.
mParser = nullptr;

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

@ -225,7 +225,6 @@ nsXULTemplateQueryProcessorStorage::GetDatasource(nsIArray* aDataSources,
return rv;
}
nsCOMPtr<nsIFile> file;
rv = fileChannel->GetFile(getter_AddRefs(databaseFile));
NS_ENSURE_SUCCESS(rv, rv);
}

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

@ -281,11 +281,10 @@ RectTyped<units> IntRectToRect(const IntRectTyped<units>& aRect)
return RectTyped<units>(aRect.x, aRect.y, aRect.width, aRect.height);
}
// Convenience function for intersecting two IntRects wrapped in Maybes.
template <typename Units>
Maybe<IntRectTyped<Units>>
IntersectMaybeRects(const Maybe<IntRectTyped<Units>>& a,
const Maybe<IntRectTyped<Units>>& b)
// Convenience function for intersecting two rectangles wrapped in Maybes.
template <typename T>
Maybe<T>
IntersectMaybeRects(const Maybe<T>& a, const Maybe<T>& b)
{
if (!a) {
return b;

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

@ -51,7 +51,7 @@ public:
virtual void SetContentController(GeckoContentController* aController) = 0;
// Return the Async Pan/Zoom Tree Manager for this compositor.
virtual already_AddRefed<IAPZCTreeManager> GetAPZCTreeManager() const = 0;
virtual RefPtr<IAPZCTreeManager> GetAPZCTreeManager() const = 0;
// Return the child end of the compositor IPC bridge.
CompositorBridgeChild* GetCompositorBridgeChild();

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

@ -11,6 +11,7 @@
#include "mozilla/Assertions.h"
#include "mozilla/gfx/gfxVars.h"
#include "mozilla/ipc/ProcessChild.h"
#include "mozilla/layers/APZThreadUtils.h"
#include "mozilla/layers/CompositorBridgeParent.h"
#include "mozilla/layers/CompositorThread.h"
#include "mozilla/layers/ImageBridgeParent.h"
@ -63,6 +64,7 @@ GPUParent::Init(base::ProcessId aParentPid,
return false;
}
CompositorThreadHolder::Start();
APZThreadUtils::SetControllerThread(CompositorThreadHolder::Loop());
VRManager::ManagerInit();
LayerTreeOwnerTracker::Initialize();
mozilla::ipc::SetThisProcessName("GPU Process");
@ -170,8 +172,12 @@ GPUParent::RecvGetDeviceStatus(GPUDeviceData* aOut)
#if defined(XP_WIN)
if (DeviceManagerDx* dm = DeviceManagerDx::Get()) {
dm->ExportDeviceInfo(&aOut->d3d11Device());
D3D11DeviceStatus deviceStatus;
dm->ExportDeviceInfo(&deviceStatus);
aOut->gpuDevice() = deviceStatus;
}
#else
aOut->gpuDevice() = null_t();
#endif
return true;

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

@ -8,6 +8,7 @@
#include "mozilla/StaticPtr.h"
#include "mozilla/dom/ContentParent.h"
#include "mozilla/layers/APZCTreeManager.h"
#include "mozilla/layers/APZCTreeManagerChild.h"
#include "mozilla/layers/CompositorBridgeParent.h"
#include "mozilla/layers/ImageBridgeChild.h"
#include "mozilla/layers/ImageBridgeParent.h"
@ -394,8 +395,17 @@ GPUProcessManager::CreateRemoteSession(nsBaseWidget* aWidget,
return nullptr;
}
RefPtr<APZCTreeManagerChild> apz = nullptr;
if (aUseAPZ) {
PAPZCTreeManagerChild* papz = child->SendPAPZCTreeManagerConstructor(0);
if (!papz) {
return nullptr;
}
apz = static_cast<APZCTreeManagerChild*>(papz);
}
RefPtr<RemoteCompositorSession> session =
new RemoteCompositorSession(child, widget, aRootLayerTreeId);
new RemoteCompositorSession(child, widget, apz, aRootLayerTreeId);
return session.forget();
#else
gfxCriticalNote << "Platform does not support out-of-process compositing";

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

@ -54,12 +54,18 @@ union FeatureChange
FeatureFailure;
};
union GPUDeviceStatus
{
null_t;
D3D11DeviceStatus;
};
struct GPUDeviceData
{
FeatureChange d3d11Compositing;
FeatureChange d3d9Compositing;
FeatureChange oglCompositing;
D3D11DeviceStatus d3d11Device;
GPUDeviceStatus gpuDevice;
};
union GfxVarValue

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

@ -54,7 +54,7 @@ InProcessCompositorSession::SetContentController(GeckoContentController* aContro
mCompositorBridgeParent->SetControllerForLayerTree(mRootLayerTreeId, aController);
}
already_AddRefed<IAPZCTreeManager>
RefPtr<IAPZCTreeManager>
InProcessCompositorSession::GetAPZCTreeManager() const
{
return mCompositorBridgeParent->GetAPZCTreeManager(mRootLayerTreeId);

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

@ -29,7 +29,7 @@ public:
CompositorBridgeParent* GetInProcessBridge() const override;
void SetContentController(GeckoContentController* aController) override;
already_AddRefed<IAPZCTreeManager> GetAPZCTreeManager() const override;
RefPtr<IAPZCTreeManager> GetAPZCTreeManager() const override;
void Shutdown() override;
private:

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

@ -3,8 +3,12 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "RemoteCompositorSession.h"
#include "mozilla/layers/APZChild.h"
#include "mozilla/layers/APZCTreeManagerChild.h"
namespace mozilla {
namespace layers {
@ -13,8 +17,10 @@ using namespace widget;
RemoteCompositorSession::RemoteCompositorSession(CompositorBridgeChild* aChild,
CompositorWidgetDelegate* aWidgetDelegate,
APZCTreeManagerChild* aAPZ,
const uint64_t& aRootLayerTreeId)
: CompositorSession(aWidgetDelegate, aChild, aRootLayerTreeId)
, mAPZ(aAPZ)
{
}
@ -27,13 +33,13 @@ RemoteCompositorSession::GetInProcessBridge() const
void
RemoteCompositorSession::SetContentController(GeckoContentController* aController)
{
MOZ_CRASH("NYI");
mCompositorBridgeChild->SendPAPZConstructor(new APZChild(aController), 0);
}
already_AddRefed<IAPZCTreeManager>
RefPtr<IAPZCTreeManager>
RemoteCompositorSession::GetAPZCTreeManager() const
{
return nullptr;
return mAPZ;
}
void

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

@ -18,13 +18,16 @@ class RemoteCompositorSession final : public CompositorSession
public:
RemoteCompositorSession(CompositorBridgeChild* aChild,
CompositorWidgetDelegate* aWidgetDelegate,
APZCTreeManagerChild* aAPZ,
const uint64_t& aRootLayerTreeId);
CompositorBridgeParent* GetInProcessBridge() const override;
void SetContentController(GeckoContentController* aController) override;
already_AddRefed<IAPZCTreeManager> GetAPZCTreeManager() const override;
RefPtr<IAPZCTreeManager> GetAPZCTreeManager() const override;
void Shutdown() override;
private:
RefPtr<APZCTreeManagerChild> mAPZ;
};
} // namespace layers

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

@ -27,7 +27,11 @@ public:
/**
* Requests a paint of the given FrameMetrics |aFrameMetrics| from Gecko.
* Implementations per-platform are responsible for actually handling this.
* This method will always be called on the Gecko main thread.
*
* This method must always be called on the repaint thread, which depends
* on the GeckoContentController. For ChromeProcessController it is the
* Gecko main thread, while for RemoteContentController it is the compositor
* thread where it can send IPDL messages.
*/
virtual void RequestContentRepaint(const FrameMetrics& aFrameMetrics) = 0;

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

@ -171,6 +171,10 @@ ChromeProcessController::HandleTap(TapType aType,
return;
}
if (!mAPZEventState) {
return;
}
nsCOMPtr<nsIPresShell> presShell = GetPresShell();
if (!presShell) {
return;
@ -217,6 +221,10 @@ ChromeProcessController::NotifyAPZStateChange(const ScrollableLayerGuid& aGuid,
return;
}
if (!mAPZEventState) {
return;
}
mAPZEventState->ProcessAPZStateChange(GetRootDocument(), aGuid.mScrollId, aChange, aArg);
}

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

@ -24,8 +24,14 @@ namespace layers {
class IAPZCTreeManager;
class APZEventState;
// A ChromeProcessController is attached to the root of a compositor's layer
// tree.
/**
* ChromeProcessController is a GeckoContentController attached to the root of
* a compositor's layer tree. It's used directly by APZ by default, and remoted
* using PAPZ if there is a gpu process.
*
* If ChromeProcessController needs to implement a new method on GeckoContentController
* PAPZ, APZChild, and RemoteContentController must be updated to handle it.
*/
class ChromeProcessController : public mozilla::layers::GeckoContentController
{
protected:

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

@ -21,6 +21,17 @@ namespace layers {
class APZChild;
/**
* ContentProcessController is a GeckoContentController for a TabChild, and is always
* remoted using PAPZ/APZChild.
*
* ContentProcessController is created in ContentChild when a layer tree id has
* been allocated for a PBrowser that lives in that content process, and is destroyed
* when the Destroy message is received, or when the tab dies.
*
* If ContentProcessController needs to implement a new method on GeckoContentController
* PAPZ, APZChild, and RemoteContentController must be updated to handle it.
*/
class ContentProcessController final
: public GeckoContentController
{

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

@ -15,6 +15,10 @@ namespace layers {
class GeckoContentController;
/**
* APZChild implements PAPZChild and is used to remote a GeckoContentController
* that lives in a different process than where APZ lives.
*/
class APZChild final : public PAPZChild
{
public:

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

@ -1432,31 +1432,64 @@ CompositorBridgeParent::ForceComposeToTarget(DrawTarget* aTarget, const gfx::Int
PAPZCTreeManagerParent*
CompositorBridgeParent::AllocPAPZCTreeManagerParent(const uint64_t& aLayersId)
{
return nullptr;
// The main process should pass in 0 because we assume mRootLayerTreeID
MOZ_ASSERT(aLayersId == 0);
// This message doubles as initialization
MOZ_ASSERT(!mApzcTreeManager);
mApzcTreeManager = new APZCTreeManager();
MonitorAutoLock lock(*sIndirectLayerTreesLock);
CompositorBridgeParent::LayerTreeState& state = sIndirectLayerTrees[mRootLayerTreeID];
MOZ_ASSERT(state.mParent);
MOZ_ASSERT(!state.mApzcTreeManagerParent);
state.mApzcTreeManagerParent = new APZCTreeManagerParent(mRootLayerTreeID, state.mParent->GetAPZCTreeManager());
return state.mApzcTreeManagerParent;
}
bool
CompositorBridgeParent::DeallocPAPZCTreeManagerParent(PAPZCTreeManagerParent* aActor)
{
return false;
delete aActor;
return true;
}
PAPZParent*
CompositorBridgeParent::AllocPAPZParent(const uint64_t& aLayersId)
{
return nullptr;
// The main process should pass in 0 because we assume mRootLayerTreeID
MOZ_ASSERT(aLayersId == 0);
RemoteContentController* controller = new RemoteContentController();
// Increment the controller's refcount before we return it. This will keep the
// controller alive until it is released by IPDL in DeallocPAPZParent.
controller->AddRef();
MonitorAutoLock lock(*sIndirectLayerTreesLock);
CompositorBridgeParent::LayerTreeState& state = sIndirectLayerTrees[mRootLayerTreeID];
MOZ_ASSERT(!state.mController);
state.mController = controller;
return controller;
}
bool
CompositorBridgeParent::DeallocPAPZParent(PAPZParent* aActor)
{
return false;
RemoteContentController* controller = static_cast<RemoteContentController*>(aActor);
controller->Release();
return true;
}
bool
CompositorBridgeParent::RecvAsyncPanZoomEnabled(const uint64_t& aLayersId, bool* aHasAPZ)
{
return false;
// The main process should pass in 0 because we assume mRootLayerTreeID
MOZ_ASSERT(aLayersId == 0);
*aHasAPZ = AsyncPanZoomEnabled();
return true;
}
RefPtr<APZCTreeManager>

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

@ -29,13 +29,19 @@ namespace layers {
/**
* If APZ is enabled then one PAPZ will be opened per PBrowser between the
* process where the PBrowser child actor lives and the main process (the
* PBrowser parent actor doesn't necessarily live in the main process, for
* example with nested browsers). This will typically be set up when the layers
* id is allocated for the PBrowser.
* PAPZ is a protocol for remoting a GeckoContentController. PAPZ lives on the
* PCompositorBridge protocol which either connects to the compositor thread
* in the main process, or to the compositor thread in the gpu processs.
*
* Opened through PContent and runs on the main thread in both parent and child.
* PAPZParent lives in the compositor thread, while PAPZChild lives wherever the remoted
* GeckoContentController lives (generally the main thread of the main or content process).
* RemoteContentController implements PAPZParent, while APZChild implements PAPZChild.
*
* PAPZ is always used for ContentProcessController and only used for ChromeProcessController
* when there is a gpu process, otherwhise ChromeProcessController is used directly on the
* compositor thread. Only the methods that are used by the [Chrome,Content]ProcessController
* are implemented. If a new method is needed then PAPZ, APZChild, and RemoteContentController
* must be updated to handle it.
*/
sync protocol PAPZ
{
@ -48,6 +54,7 @@ parent:
async __delete__();
child:
async RequestContentRepaint(FrameMetrics frame);
// The aCallTakeFocusForClickFromTap argument is used for eSingleTap types,

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

@ -34,6 +34,15 @@ using class mozilla::ScrollWheelInput from "InputData.h";
namespace mozilla {
namespace layers {
/**
* PAPZCTreeManager is a protocol for remoting an IAPZCTreeManager. PAPZCTreeManager
* lives on the PCompositorBridge protocol which either connects to the compositor
* thread in the main process, or to the compositor thread in the gpu processs.
*
* PAPZCTreeManagerParent lives in the compositor thread, while PAPZCTreeManagerChild
* lives in the main thread of the main or the content process. APZCTreeManagerParent
* and APZCTreeManagerChild implement this protocol.
*/
sync protocol PAPZCTreeManager
{
manager PCompositorBridge;

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

@ -20,11 +20,14 @@ class TabParent;
namespace layers {
/**
* RemoteContentController uses the PAPZ protocol to implement a
* GeckoContentController for a browser living in a remote process.
* Most of the member functions can be called on any thread, exceptions are
* annotated in comments. The PAPZ protocol runs on the main thread (so all the
* Recv* member functions do too).
* RemoteContentController implements PAPZChild and is used to access a
* GeckoContentController that lives in a different process.
*
* RemoteContentController lives on the compositor thread. All methods can
* be called off the compositor thread and will get dispatched to the right
* thread, with the exception of RequestContentRepaint and NotifyFlushComplete,
* which must be called on the repaint thread, which in this case is the compositor
* thread.
*/
class RemoteContentController : public GeckoContentController
, public PAPZParent

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

@ -219,6 +219,9 @@ public:
if (!gFontHintingEnabled || !isAxisAligned(*rec)) {
rec->setHinting(SkPaint::kNo_Hinting);
}
// Don't apply any gamma so that we match cairo-ft's results.
rec->ignorePreBlend();
}
virtual void onGetFontDescriptor(SkFontDescriptor*, bool*) const override
@ -760,7 +763,7 @@ void SkScalerContext_CairoFT::generatePath(const SkGlyph& glyph, SkPath* path)
CairoLockedFTFace faceLock(fScaledFont);
FT_Face face = faceLock.getFace();
SkASSERT(&glyph && path);
SkASSERT(path);
uint32_t flags = fLoadGlyphFlags;
flags |= FT_LOAD_NO_BITMAP; // ignore embedded bitmaps so we're sure to get the outline
@ -780,7 +783,9 @@ void SkScalerContext_CairoFT::generatePath(const SkGlyph& glyph, SkPath* path)
void SkScalerContext_CairoFT::generateFontMetrics(SkPaint::FontMetrics* metrics)
{
SkDEBUGCODE(SkDebugf("SkScalerContext_CairoFT::generateFontMetrics unimplemented\n"));
if (metrics) {
memset(metrics, 0, sizeof(SkPaint::FontMetrics));
}
}
SkUnichar SkScalerContext_CairoFT::generateGlyphToChar(uint16_t glyph)

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

@ -2004,7 +2004,7 @@ gfxWindowsPlatform::ImportGPUDeviceData(const mozilla::gfx::GPUDeviceData& aData
DeviceManagerDx* dm = DeviceManagerDx::Get();
if (gfxConfig::IsEnabled(Feature::D3D11_COMPOSITING)) {
dm->ImportDeviceInfo(aData.d3d11Device());
dm->ImportDeviceInfo(aData.gpuDevice().get_D3D11DeviceStatus());
} else {
// There should be no devices, so this just takes away the device status.
dm->ResetDevices();

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

@ -23,6 +23,10 @@
#include "prenv.h"
#include "nsXPCOMPrivate.h"
#if defined(XP_MACOSX) && defined(MOZ_CONTENT_SANDBOX)
#include "nsAppDirectoryServiceDefs.h"
#endif
#include "nsExceptionHandler.h"
#include "nsDirectoryServiceDefs.h"
@ -608,6 +612,20 @@ AddAppDirToCommandLine(std::vector<std::string>& aCmdLine)
aCmdLine.push_back(path.get());
#endif
}
#if defined(XP_MACOSX) && defined(MOZ_CONTENT_SANDBOX)
// Full path to the profile dir
nsCOMPtr<nsIFile> profileDir;
rv = directoryService->Get(NS_APP_USER_PROFILE_50_DIR,
NS_GET_IID(nsIFile),
getter_AddRefs(profileDir));
if (NS_SUCCEEDED(rv)) {
nsAutoCString path;
MOZ_ALWAYS_SUCCEEDS(profileDir->GetNativePath(path));
aCmdLine.push_back("-profile");
aCmdLine.push_back(path.get());
}
#endif
}
}
}

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

@ -464,5 +464,17 @@ void ArrayLengthReadError(const char* aElementName)
NS_RUNTIMEABORT(message.get());
}
void
TableToArray(const nsTHashtable<nsPtrHashKey<void>>& aTable,
nsTArray<void*>& aArray)
{
uint32_t i = 0;
void** elements = aArray.AppendElements(aTable.Count());
for (auto iter = aTable.ConstIter(); !iter.Done(); iter.Next()) {
elements[i] = iter.Get()->GetKey();
++i;
}
}
} // namespace ipc
} // namespace mozilla

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

@ -1,4 +1,4 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
* vim: sw=4 ts=4 et :
*/
/* This Source Code Form is subject to the terms of the Mozilla Public
@ -121,11 +121,13 @@ struct Trigger
Trigger(Action action, int32_t msg) :
mAction(action),
mMsg(msg)
{}
mMessage(msg)
{
MOZ_ASSERT(0 <= msg && msg < INT32_MAX);
}
Action mAction;
int32_t mMsg;
uint32_t mAction : 1;
uint32_t mMessage : 31;
};
class ProtocolCloneContext
@ -604,10 +606,31 @@ CreateEndpoints(const PrivateIPDLInterface& aPrivate,
return NS_OK;
}
void
TableToArray(const nsTHashtable<nsPtrHashKey<void>>& aTable,
nsTArray<void*>& aArray);
} // namespace ipc
template<typename Protocol>
using ManagedContainer = nsTHashtable<nsPtrHashKey<Protocol>>;
class ManagedContainer : public nsTHashtable<nsPtrHashKey<Protocol>>
{
typedef nsTHashtable<nsPtrHashKey<Protocol>> BaseClass;
public:
// Having the core logic work on void pointers, rather than typed pointers,
// means that we can have one instance of this code out-of-line, rather
// than several hundred instances of this code out-of-lined. (Those
// repeated instances don't necessarily get folded together by the linker
// because they contain member offsets and such that differ between the
// functions.) We do have to pay for it with some eye-bleedingly bad casts,
// though.
void ToArray(nsTArray<Protocol*>& aArray) const {
::mozilla::ipc::TableToArray(*reinterpret_cast<const nsTHashtable<nsPtrHashKey<void>>*>
(static_cast<const BaseClass*>(this)),
reinterpret_cast<nsTArray<void*>&>(aArray));
}
};
template<typename Protocol>
Protocol*

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

@ -50,6 +50,7 @@ HeaderIncludes = (
'nsTArray.h',
'mozilla/ipc/ProtocolUtils.h',
'nsTHashtable.h',
'mozilla/OperatorNewExtensions.h',
)
CppIncludes = (

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

@ -851,7 +851,7 @@ IPDL union type."""
else:
return ExprNew(self.bareType(self.side),
args=args,
newargs=[ self.callGetPtr() ])
newargs=[ ExprVar('mozilla::KnownNotNull'), self.callGetPtr() ])
def callDtor(self):
if self.recursive:
@ -1797,17 +1797,17 @@ class _GenerateProtocolCode(ipdl.ast.Visitor):
else:
return ExprVar(s.decl.cxxname)
# bool Transition(State from, Trigger trigger, State* next)
# bool Transition(Trigger trigger, State* next)
# The state we are transitioning from is stored in *next.
fromvar = ExprVar('from')
triggervar = ExprVar('trigger')
nextvar = ExprVar('next')
msgexpr = ExprSelect(triggervar, '.', 'mMsg')
msgexpr = ExprSelect(triggervar, '.', 'mMessage')
actionexpr = ExprSelect(triggervar, '.', 'mAction')
transitionfunc = FunctionDefn(FunctionDecl(
'Transition',
params=[ Decl(Type('State'), fromvar.name),
Decl(Type('mozilla::ipc::Trigger'), triggervar.name),
params=[ Decl(Type('mozilla::ipc::Trigger'), triggervar.name),
Decl(Type('State', ptr=1), nextvar.name) ],
ret=Type.BOOL))
@ -1902,6 +1902,8 @@ class _GenerateProtocolCode(ipdl.ast.Visitor):
if usesend or userecv:
transitionfunc.addstmt(Whitespace.NL)
transitionfunc.addstmt(StmtDecl(Decl(Type('State'), fromvar.name),
init=ExprDeref(nextvar)))
transitionfunc.addstmt(fromswitch)
# all --> Error transitions break to here. But only insert this
# block if there is any possibility of such transitions.
@ -3086,22 +3088,10 @@ class _GenerateProtocolActorCode(ipdl.ast.Visitor):
params=[ Decl(_cxxArrayType(p.managedCxxType(managed, self.side), ref=1),
arrvar.name) ],
const=1))
ivar = ExprVar('i')
elementsvar = ExprVar('elements')
itervar = ExprVar('iter')
meth.addstmt(StmtDecl(Decl(Type.UINT32, ivar.name),
init=ExprLiteral.ZERO))
meth.addstmt(StmtDecl(Decl(Type(_actorName(managed.name(), self.side), ptrptr=1), elementsvar.name),
init=ExprCall(ExprSelect(arrvar, '.', 'AppendElements'),
args=[ ExprCall(ExprSelect(p.managedVar(managed, self.side),
'.', 'Count')) ])))
foreachaccumulate = forLoopOverHashtable(p.managedVar(managed, self.side),
itervar, const=True)
foreachaccumulate.addstmt(StmtExpr(
ExprAssn(ExprIndex(elementsvar, ivar),
actorFromIter(itervar))))
foreachaccumulate.addstmt(StmtExpr(ExprPrefixUnop(ivar, '++')))
meth.addstmt(foreachaccumulate)
meth.addstmt(StmtExpr(
ExprCall(ExprSelect(p.managedVar(managed, self.side),
'.', 'ToArray'),
args=[ arrvar ])))
refmeth = MethodDefn(MethodDecl(
p.managedMethod(managed, self.side).name,
@ -5441,8 +5431,7 @@ class _GenerateProtocolActorCode(ipdl.ast.Visitor):
ifbad = StmtIf(ExprNot(
ExprCall(
ExprVar(self.protocol.name +'::Transition'),
args=[ stateexpr,
ExprCall(ExprVar('Trigger'),
args=[ ExprCall(ExprVar('Trigger'),
args=[ action, ExprVar(msgid) ]),
ExprAddrOf(stateexpr) ])))
ifbad.addifstmts(_badTransition())

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

@ -132,7 +132,7 @@ struct ParamTraits<mozilla::mscom::COMPtrHolder<Interface, _IID>>
if (!proxyStream.GetInterface(_IID, (void**)&rawInterface)) {
return false;
}
paramType::COMPtrType ptr(rawInterface);
typename paramType::COMPtrType ptr(rawInterface);
aResult->Set(mozilla::Move(ptr));
return true;
}

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

@ -12,7 +12,7 @@
#include "mozilla/DebugOnly.h"
#include "mozilla/Function.h"
#include "mozilla/mscom/COMApartmentRegion.h"
#include "mozilla/mscom/utils.h"
#include "mozilla/mscom/Utils.h"
#include "nsCOMPtr.h"
#include "nsIThread.h"
#include "nsThreadUtils.h"

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

@ -11,7 +11,7 @@
#include "mozilla/mscom/DispatchForwarder.h"
#include "mozilla/mscom/MainThreadInvoker.h"
#include "mozilla/mscom/Registration.h"
#include "mozilla/mscom/utils.h"
#include "mozilla/mscom/Utils.h"
#include "MainThreadUtils.h"
#include "mozilla/Assertions.h"
#include "mozilla/DebugOnly.h"

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

@ -8,7 +8,7 @@
#include "mozilla/mscom/InterceptorLog.h"
#include "mozilla/mscom/Registration.h"
#include "mozilla/mscom/utils.h"
#include "mozilla/mscom/Utils.h"
#include "mozilla/Assertions.h"
#include "mozilla/DebugOnly.h"
#include "nsThreadUtils.h"

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

@ -7,7 +7,7 @@
#include "DynamicallyLinkedFunctionPtr.h"
#include "mozilla/mscom/EnsureMTA.h"
#include "mozilla/mscom/ProxyStream.h"
#include "mozilla/mscom/utils.h"
#include "mozilla/mscom/Utils.h"
#include "mozilla/Move.h"

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

@ -781,7 +781,7 @@ ParseVarOrConstStatement(AsmJSParser& parser, ParseNode** var)
return true;
}
*var = parser.statement(YieldIsName);
*var = parser.statementListItem(YieldIsName);
if (!*var)
return false;
@ -7206,7 +7206,7 @@ CheckModuleReturn(ModuleValidator& m)
}
ts.ungetToken();
ParseNode* returnStmt = m.parser().statement(YieldIsName);
ParseNode* returnStmt = m.parser().statementListItem(YieldIsName);
if (!returnStmt)
return false;

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

@ -698,6 +698,19 @@ class FunctionCompiler
}
private:
// False means we're sure to be out-of-bounds after this bounds check.
bool maybeAddBoundsCheck(MDefinition* base, const MWasmMemoryAccess& access)
{
if (access.offset() > uint32_t(INT32_MAX)) {
curBlock_->end(MWasmTrap::New(alloc(), Trap::OutOfBounds));
curBlock_ = nullptr;
return false;
}
if (!mg().usesSignal.forOOB)
curBlock_->add(MWasmBoundsCheck::New(alloc(), base, access));
return true;
}
MDefinition* loadHeapPrivate(MDefinition* base, const MWasmMemoryAccess& access,
bool isInt64 = false)
{
@ -708,8 +721,8 @@ class FunctionCompiler
if (mg().isAsmJS()) {
load = MAsmJSLoadHeap::New(alloc(), base, access);
} else {
if (!mg().usesSignal.forOOB)
curBlock_->add(MWasmBoundsCheck::New(alloc(), base, access));
if (!maybeAddBoundsCheck(base, access))
return nullptr;
load = MWasmLoad::New(alloc(), base, access, isInt64);
}
@ -726,8 +739,8 @@ class FunctionCompiler
if (mg().isAsmJS()) {
store = MAsmJSStoreHeap::New(alloc(), base, access, v);
} else {
if (!mg().usesSignal.forOOB)
curBlock_->add(MWasmBoundsCheck::New(alloc(), base, access));
if (!maybeAddBoundsCheck(base, access))
return;
store = MWasmStore::New(alloc(), base, access, v);
}
@ -1109,7 +1122,7 @@ class FunctionCompiler
if (inDeadCode())
return;
auto* ins = MAsmThrowUnreachable::New(alloc());
auto* ins = MWasmTrap::New(alloc(), wasm::Trap::Unreachable);
curBlock_->end(ins);
curBlock_ = nullptr;
}

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

@ -101,9 +101,6 @@ function RadixSort(array, len, buffer, nbytes, signed, floating, comparefn) {
return array;
}
// Verify that the buffer is non-null
assert(buffer !== null, "Attached data buffer should be reified when array length is >= 128.");
let aux = new List();
for (let i = 0; i < len; i++) {
aux[i] = 0;
@ -114,6 +111,14 @@ function RadixSort(array, len, buffer, nbytes, signed, floating, comparefn) {
// Preprocess
if (floating) {
// This happens if the array object is constructed under JIT
if (buffer === null) {
buffer = callFunction(std_TypedArray_buffer, array);
}
// Verify that the buffer is non-null
assert(buffer !== null, "Attached data buffer should be reified when array length is >= 128.");
view = new Int32Array(buffer);
// Flip sign bit for positive numbers; flip all bits for negative

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

@ -766,7 +766,7 @@ Parser<ParseHandler>::parse()
if (!varScope.init(pc))
return null();
Node pn = statements(YieldIsName);
Node pn = statementList(YieldIsName);
if (!pn)
return null();
@ -1296,7 +1296,7 @@ Parser<FullParseHandler>::checkStatementsEOF()
// This is designed to be paired with parsing a statement list at the top
// level.
//
// The statements() call breaks on TOK_RC, so make sure we've
// The statementList() call breaks on TOK_RC, so make sure we've
// reached EOF here.
TokenKind tt;
if (!tokenStream.peekToken(&tt, TokenStream::Operand))
@ -1732,7 +1732,7 @@ Parser<FullParseHandler>::evalBody(EvalSharedContext* evalsc)
if (!lexicalScope.init(pc))
return nullptr;
ParseNode* body = statements(YieldIsName);
ParseNode* body = statementList(YieldIsName);
if (!body)
return nullptr;
@ -1805,7 +1805,7 @@ Parser<FullParseHandler>::globalBody(GlobalSharedContext* globalsc)
if (!varScope.init(pc))
return nullptr;
ParseNode* body = statements(YieldIsName);
ParseNode* body = statementList(YieldIsName);
if (!body)
return nullptr;
@ -1844,7 +1844,7 @@ Parser<FullParseHandler>::moduleBody(ModuleSharedContext* modulesc)
if (!mn)
return null();
ParseNode* pn = statements(YieldIsKeyword);
ParseNode* pn = statementList(YieldIsKeyword);
if (!pn)
return null();
@ -2249,7 +2249,7 @@ Parser<ParseHandler>::functionBody(InHandling inHandling, YieldHandling yieldHan
Node pn;
if (type == StatementListBody) {
pn = statements(yieldHandling);
pn = statementList(yieldHandling);
if (!pn)
return null();
} else {
@ -2714,12 +2714,12 @@ Parser<ParseHandler>::checkFunctionDefinition(HandleAtom funAtom, Node pn, Funct
// declarations. Otherwise it is a parse error.
ParseContext::Statement* declaredInStmt = pc->innermostStatement();
if (declaredInStmt && declaredInStmt->kind() == StatementKind::Label) {
if (pc->sc()->strict()) {
reportWithOffset(ParseError, false, pos.begin, JSMSG_FUNCTION_LABEL);
return false;
}
MOZ_ASSERT(!pc->sc()->strict(),
"labeled functions shouldn't be parsed in strict mode");
// Find the innermost non-label statement.
// Find the innermost non-label statement. Report an error if it's
// unbraced: functions can't appear in it. Otherwise the statement
// (or its absence) determines the scope the function's bound in.
while (declaredInStmt && declaredInStmt->kind() == StatementKind::Label)
declaredInStmt = declaredInStmt->enclosing();
@ -2730,9 +2730,8 @@ Parser<ParseHandler>::checkFunctionDefinition(HandleAtom funAtom, Node pn, Funct
}
if (declaredInStmt) {
DeclarationKind declKind = DeclarationKind::LexicalFunction;
if (!checkLexicalDeclarationDirectlyWithinBlock(*declaredInStmt, declKind, pos))
return false;
MOZ_ASSERT(declaredInStmt->kind() != StatementKind::Label);
MOZ_ASSERT(StatementKindIsBraced(declaredInStmt->kind()));
if (!pc->sc()->strict()) {
// Under sloppy mode, try Annex B.3.3 semantics. If making an
@ -2745,7 +2744,7 @@ Parser<ParseHandler>::checkFunctionDefinition(HandleAtom funAtom, Node pn, Funct
return false;
}
if (!noteDeclaredName(funName, declKind, pos))
if (!noteDeclaredName(funName, DeclarationKind::LexicalFunction, pos))
return false;
} else {
if (!noteDeclaredName(funName, DeclarationKind::BodyLevelFunction, pos))
@ -3528,14 +3527,9 @@ Parser<ParseHandler>::maybeParseDirective(Node list, Node pn, bool* cont)
return true;
}
/*
* Parse the statements in a block, creating a StatementList node that lists
* the statements. If called from block-parsing code, the caller must match
* '{' before and '}' after.
*/
template <typename ParseHandler>
typename ParseHandler::Node
Parser<ParseHandler>::statements(YieldHandling yieldHandling)
Parser<ParseHandler>::statementList(YieldHandling yieldHandling)
{
JS_CHECK_RECURSION(context, return null());
@ -3562,7 +3556,7 @@ Parser<ParseHandler>::statements(YieldHandling yieldHandling)
return null();
statementBegin = pos.begin;
}
Node next = statement(yieldHandling, canHaveDirectives);
Node next = statementListItem(yieldHandling, canHaveDirectives);
if (!next) {
if (tokenStream.isEOF())
isUnexpectedEOF_ = true;
@ -3957,7 +3951,7 @@ Parser<ParseHandler>::blockStatement(YieldHandling yieldHandling, unsigned error
if (!scope.init(pc))
return null();
Node list = statements(yieldHandling);
Node list = statementList(yieldHandling);
if (!list)
return null();
@ -4864,6 +4858,27 @@ Parser<ParseHandler>::expressionStatement(YieldHandling yieldHandling, InvokedPr
return handler.newExprStatement(pnexpr, pos().end);
}
template <class ParseHandler>
typename ParseHandler::Node
Parser<ParseHandler>::consequentOrAlternative(YieldHandling yieldHandling)
{
TokenKind next;
if (!tokenStream.peekToken(&next, TokenStream::Operand))
return null();
if (next == TOK_FUNCTION) {
// Apply Annex B.3.4 in non-strict code to allow FunctionDeclaration as
// the consequent/alternative of an |if| or |else|. Parser::statement
// will report the strict mode error.
if (!pc->sc()->strict()) {
tokenStream.consumeKnownToken(next, TokenStream::Operand);
return functionStmt(yieldHandling, NameRequired);
}
}
return statement(yieldHandling);
}
template <typename ParseHandler>
typename ParseHandler::Node
Parser<ParseHandler>::ifStatement(YieldHandling yieldHandling)
@ -4890,7 +4905,7 @@ Parser<ParseHandler>::ifStatement(YieldHandling yieldHandling)
return null();
}
Node thenBranch = statement(yieldHandling);
Node thenBranch = consequentOrAlternative(yieldHandling);
if (!thenBranch)
return null();
@ -4905,7 +4920,7 @@ Parser<ParseHandler>::ifStatement(YieldHandling yieldHandling)
return null();
if (matched)
continue;
elseBranch = statement(yieldHandling);
elseBranch = consequentOrAlternative(yieldHandling);
if (!elseBranch)
return null();
} else {
@ -5062,13 +5077,24 @@ Parser<ParseHandler>::forHeadStart(YieldHandling yieldHandling,
parsingLexicalDeclaration = true;
tokenStream.consumeKnownToken(tt, TokenStream::Operand);
} else if (tt == TOK_NAME && tokenStream.nextName() == context->names().let) {
// Check for the backwards-compatibility corner case in sloppy
// mode like |for (let in e)| where the 'let' token should be
// parsed as an identifier.
if (!peekShouldParseLetDeclaration(&parsingLexicalDeclaration, TokenStream::Operand))
MOZ_ASSERT(!pc->sc()->strict(),
"should parse |let| as TOK_LET in strict mode code");
// We could have a {For,Lexical}Declaration, or we could have a
// LeftHandSideExpression with lookahead restrictions so it's not
// ambiguous with the former. Check for a continuation of the former
// to decide which we have.
tokenStream.consumeKnownToken(TOK_NAME, TokenStream::Operand);
TokenKind next;
if (!tokenStream.peekToken(&next))
return false;
letIsIdentifier = !parsingLexicalDeclaration;
parsingLexicalDeclaration = nextTokenContinuesLetDeclaration(next, yieldHandling);
if (!parsingLexicalDeclaration) {
tokenStream.ungetToken();
letIsIdentifier = true;
}
}
if (parsingLexicalDeclaration) {
@ -5386,7 +5412,7 @@ Parser<ParseHandler>::switchStatement(YieldHandling yieldHandling)
return null();
statementBegin = pos.begin;
}
Node stmt = statement(yieldHandling);
Node stmt = statementListItem(yieldHandling);
if (!stmt)
return null();
if (!warnedAboutStatementsAfterReturn) {
@ -5774,6 +5800,41 @@ Parser<SyntaxParseHandler>::withStatement(YieldHandling yieldHandling)
return null();
}
template <typename ParseHandler>
typename ParseHandler::Node
Parser<ParseHandler>::labeledItem(YieldHandling yieldHandling)
{
TokenKind tt;
if (!tokenStream.getToken(&tt, TokenStream::Operand))
return null();
if (tt == TOK_FUNCTION) {
TokenKind next;
if (!tokenStream.peekToken(&next))
return null();
// GeneratorDeclaration is only matched by HoistableDeclaration in
// StatementListItem, so generators can't be inside labels.
if (next == TOK_MUL) {
report(ParseError, false, null(), JSMSG_GENERATOR_LABEL);
return null();
}
// Per 13.13.1 it's a syntax error if LabelledItem: FunctionDeclaration
// is ever matched. Per Annex B.3.2 that modifies this text, this
// applies only to strict mode code.
if (pc->sc()->strict()) {
report(ParseError, false, null(), JSMSG_FUNCTION_LABEL);
return null();
}
return functionStmt(yieldHandling, NameRequired);
}
tokenStream.ungetToken();
return statement(yieldHandling);
}
template <typename ParseHandler>
typename ParseHandler::Node
Parser<ParseHandler>::labeledStatement(YieldHandling yieldHandling)
@ -5794,7 +5855,7 @@ Parser<ParseHandler>::labeledStatement(YieldHandling yieldHandling)
/* Push a label struct and parse the statement. */
ParseContext::LabelStatement stmt(pc, label);
Node pn = statement(yieldHandling);
Node pn = labeledItem(yieldHandling);
if (!pn)
return null();
@ -5865,7 +5926,7 @@ Parser<ParseHandler>::tryStatement(YieldHandling yieldHandling)
if (!scope.init(pc))
return null();
innerBlock = statements(yieldHandling);
innerBlock = statementList(yieldHandling);
if (!innerBlock)
return null();
@ -6005,7 +6066,7 @@ Parser<ParseHandler>::tryStatement(YieldHandling yieldHandling)
if (!scope.init(pc))
return null();
finallyBlock = statements(yieldHandling);
finallyBlock = statementList(yieldHandling);
if (!finallyBlock)
return null();
@ -6047,7 +6108,7 @@ Parser<ParseHandler>::catchBlockStatement(YieldHandling yieldHandling,
if (!noteDeclaredName(simpleCatchParam, DeclarationKind::SimpleCatchParameter, pos()))
return null();
Node list = statements(yieldHandling);
Node list = statementList(yieldHandling);
if (!list)
return null();
@ -6057,7 +6118,7 @@ Parser<ParseHandler>::catchBlockStatement(YieldHandling yieldHandling,
body = finishLexicalScope(scope, list);
} else {
body = statements(yieldHandling);
body = statementList(yieldHandling);
}
if (!body)
return null();
@ -6361,77 +6422,71 @@ Parser<SyntaxParseHandler>::classDefinition(YieldHandling yieldHandling,
return SyntaxParseHandler::NodeFailure;
}
template <typename ParseHandler>
template <class ParseHandler>
bool
Parser<ParseHandler>::shouldParseLetDeclaration(bool* parseDeclOut)
Parser<ParseHandler>::nextTokenContinuesLetDeclaration(TokenKind next, YieldHandling yieldHandling)
{
TokenKind tt;
if (!tokenStream.peekToken(&tt))
return false;
if (tt == TOK_NAME) {
// |let| followed by a name is a lexical declaration. This is so even
// if the name is on a new line. ASI applies *only* if an offending
// token not allowed by the grammar is encountered, and there's no
// [no LineTerminator here] restriction in LexicalDeclaration or
// ForDeclaration forbidding a line break.
//
// It's a tricky point, but this is true *even if* the name is "let", a
// name that can't be bound by LexicalDeclaration or ForDeclaration.
// Per ES6 5.3, static semantics early errors are validated *after*
// determining productions matching the source text. So in this
// example:
//
// let // ASI opportunity...except not
// let;
//
// the text matches LexicalDeclaration. *Then* static semantics in
// ES6 13.3.1.1 (corresponding to the LexicalDeclaration production
// just chosen), per ES6 5.3, are validated to recognize the Script as
// invalid. It can't be evaluated, so a SyntaxError is thrown.
*parseDeclOut = true;
} else if (tt == TOK_LB || tt == TOK_LC) {
*parseDeclOut = true;
} else {
// Whatever we have isn't a declaration. Either it's an expression, or
// it's invalid: expression-parsing code will decide.
*parseDeclOut = false;
}
return true;
}
template <typename ParseHandler>
bool
Parser<ParseHandler>::peekShouldParseLetDeclaration(bool* parseDeclOut,
TokenStream::Modifier modifier)
{
// 'let' is a reserved keyword in strict mode and we shouldn't get here.
MOZ_ASSERT(!pc->sc()->strict());
*parseDeclOut = false;
MOZ_ASSERT(tokenStream.isCurrentTokenType(TOK_NAME),
"TOK_LET should have been summarily considered a "
"LexicalDeclaration");
MOZ_ASSERT(tokenStream.currentName() == context->names().let);
#ifdef DEBUG
TokenKind tt;
if (!tokenStream.peekToken(&tt, modifier))
return false;
MOZ_ASSERT(tt == TOK_NAME && tokenStream.nextName() == context->names().let);
TokenKind verify;
MOZ_ALWAYS_TRUE(tokenStream.peekToken(&verify));
MOZ_ASSERT(next == verify);
#endif
tokenStream.consumeKnownToken(TOK_NAME, modifier);
if (!shouldParseLetDeclaration(parseDeclOut))
// Destructuring is (for once) the easy case.
if (next == TOK_LB || next == TOK_LC)
return true;
// Otherwise a let declaration must have a name.
if (next == TOK_NAME) {
// One non-"yield" TOK_NAME edge case deserves special comment.
// Consider this:
//
// let // not an ASI opportunity
// let;
//
// Static semantics in §13.3.1.1 turn a LexicalDeclaration that binds
// "let" into an early error. Does this retroactively permit ASI so
// that we should parse this as two ExpressionStatements? No. ASI
// resolves during parsing. Static semantics only apply to the full
// parse tree with ASI applied. No backsies!
if (tokenStream.nextName() != context->names().yield)
return true;
} else if (next != TOK_YIELD) {
return false;
}
// Unget the TOK_NAME of 'let' if not parsing a declaration.
if (!*parseDeclOut)
tokenStream.ungetToken();
return true;
// We have the name "yield": the grammar parameter exactly states whether
// this is okay. Even if YieldIsKeyword, the code might be valid if ASI
// induces a preceding semicolon. If YieldIsName, the code is valid
// outside strict mode, and declaration-parsing code will enforce strict
// mode restrictions.
//
// No checkYieldNameValidity for TOK_YIELD is needed here. It'll happen
// when TOK_YIELD is consumed as BindingIdentifier or as start of a fresh
// Statement.
return yieldHandling == YieldIsName;
}
template <typename ParseHandler>
typename ParseHandler::Node
Parser<ParseHandler>::statement(YieldHandling yieldHandling, bool canHaveDirectives)
Parser<ParseHandler>::variableStatement(YieldHandling yieldHandling)
{
Node vars = declarationList(yieldHandling, PNK_VAR);
if (!vars)
return null();
if (!MatchOrInsertSemicolonAfterExpression(tokenStream))
return null();
return vars;
}
template <typename ParseHandler>
typename ParseHandler::Node
Parser<ParseHandler>::statement(YieldHandling yieldHandling)
{
MOZ_ASSERT(checkOptionsCalled);
@ -6447,31 +6502,14 @@ Parser<ParseHandler>::statement(YieldHandling yieldHandling, bool canHaveDirecti
return blockStatement(yieldHandling);
// VariableStatement[?Yield]
case TOK_VAR: {
Node pn = declarationList(yieldHandling, PNK_VAR);
if (!pn)
return null();
if (!MatchOrInsertSemicolonAfterExpression(tokenStream))
return null();
return pn;
}
case TOK_VAR:
return variableStatement(yieldHandling);
// EmptyStatement
case TOK_SEMI:
return handler.newEmptyStatement(pos());
// ExpressionStatement[?Yield].
//
// These should probably be handled by a single ExpressionStatement
// function in a default, not split up this way.
case TOK_STRING:
if (!canHaveDirectives && tokenStream.currentToken().atom() == context->names().useAsm) {
if (!abortIfSyntaxParser())
return null();
if (!report(ParseWarning, false, null(), JSMSG_USE_ASM_DIRECTIVE_FAIL))
return null();
}
return expressionStatement(yieldHandling);
case TOK_YIELD: {
// Don't use a ternary operator here due to obscure linker issues
@ -6494,29 +6532,58 @@ Parser<ParseHandler>::statement(YieldHandling yieldHandling, bool canHaveDirecti
}
case TOK_NAME: {
// 'let' is a contextual keyword outside strict mode. In strict mode
// it's always tokenized as TOK_LET except in this one weird case:
//
// "use strict" // ExpressionStatement, terminated by ASI
// let a = 1; // LexicalDeclaration
//
// We can't apply strict mode until we know "use strict" is the entire
// statement, but we can't know "use strict" is the entire statement
// until we see the next token. So 'let' is still TOK_NAME here.
if (tokenStream.currentName() == context->names().let) {
bool parseDecl;
if (!shouldParseLetDeclaration(&parseDecl))
return null();
if (parseDecl)
return lexicalDeclaration(yieldHandling, /* isConst = */ false);
}
TokenKind next;
if (!tokenStream.peekToken(&next))
return null();
#ifdef DEBUG
if (tokenStream.currentName() == context->names().let) {
MOZ_ASSERT(!pc->sc()->strict(),
"observing |let| as TOK_NAME and not TOK_LET implies "
"non-strict code (and the edge case of 'use strict' "
"immediately followed by |let| on a new line only "
"applies to StatementListItems, not to Statements)");
}
#endif
// Statement context forbids LexicalDeclaration.
if ((next == TOK_LB || next == TOK_LC || next == TOK_NAME) &&
tokenStream.currentName() == context->names().let)
{
bool forbiddenLetDeclaration = false;
if (next == TOK_LB) {
// ExpressionStatement has a 'let [' lookahead restriction.
forbiddenLetDeclaration = true;
} else {
// 'let {' and 'let foo' aren't completely forbidden, if ASI
// causes 'let' to be the entire Statement. But if they're
// same-line, we can aggressively give a better error message.
//
// Note that this ignores 'yield' as TOK_YIELD: we'll handle it
// correctly but with a worse error message.
TokenKind nextSameLine;
if (!tokenStream.peekTokenSameLine(&nextSameLine))
return null();
MOZ_ASSERT(nextSameLine == TOK_NAME ||
nextSameLine == TOK_LC ||
nextSameLine == TOK_EOL);
forbiddenLetDeclaration = nextSameLine != TOK_EOL;
}
if (forbiddenLetDeclaration) {
report(ParseError, false, null(), JSMSG_FORBIDDEN_AS_STATEMENT,
"lexical declarations");
return null();
}
}
// NOTE: It's unfortunately allowed to have a label named 'let' in
// non-strict code. 💯
if (next == TOK_COLON)
return labeledStatement(yieldHandling);
return expressionStatement(yieldHandling);
}
@ -6585,23 +6652,222 @@ Parser<ParseHandler>::statement(YieldHandling yieldHandling, bool canHaveDirecti
case TOK_DEBUGGER:
return debuggerStatement();
// HoistableDeclaration[?Yield]
// |function| is forbidden by lookahead restriction (unless as child
// statement of |if| or |else|, but Parser::consequentOrAlternative
// handles that).
case TOK_FUNCTION:
report(ParseError, false, null(), JSMSG_FORBIDDEN_AS_STATEMENT, "function declarations");
return null();
// |class| is also forbidden by lookahead restriction.
case TOK_CLASS:
report(ParseError, false, null(), JSMSG_FORBIDDEN_AS_STATEMENT, "classes");
return null();
// ImportDeclaration (only inside modules)
case TOK_IMPORT:
return importDeclaration();
// ExportDeclaration (only inside modules)
case TOK_EXPORT:
return exportDeclaration();
// Miscellaneous error cases arguably better caught here than elsewhere.
case TOK_CATCH:
report(ParseError, false, null(), JSMSG_CATCH_WITHOUT_TRY);
return null();
case TOK_FINALLY:
report(ParseError, false, null(), JSMSG_FINALLY_WITHOUT_TRY);
return null();
// TOK_LET implies we're in strict mode code where static semantics
// forbid IdentifierName to be "let": a stronger restriction than
// Statement's lookahead restriction on |let [|. Provide a better error
// message here than the default case would.
case TOK_LET:
report(ParseError, false, null(), JSMSG_FORBIDDEN_AS_STATEMENT, "let declarations");
return null();
// NOTE: default case handled in the ExpressionStatement section.
}
}
template <typename ParseHandler>
typename ParseHandler::Node
Parser<ParseHandler>::statementListItem(YieldHandling yieldHandling,
bool canHaveDirectives /* = false */)
{
MOZ_ASSERT(checkOptionsCalled);
JS_CHECK_RECURSION(context, return null());
TokenKind tt;
if (!tokenStream.getToken(&tt, TokenStream::Operand))
return null();
switch (tt) {
// BlockStatement[?Yield, ?Return]
case TOK_LC:
return blockStatement(yieldHandling);
// VariableStatement[?Yield]
case TOK_VAR:
return variableStatement(yieldHandling);
// EmptyStatement
case TOK_SEMI:
return handler.newEmptyStatement(pos());
// ExpressionStatement[?Yield].
//
// These should probably be handled by a single ExpressionStatement
// function in a default, not split up this way.
case TOK_STRING:
if (!canHaveDirectives && tokenStream.currentToken().atom() == context->names().useAsm) {
if (!abortIfSyntaxParser())
return null();
if (!report(ParseWarning, false, null(), JSMSG_USE_ASM_DIRECTIVE_FAIL))
return null();
}
return expressionStatement(yieldHandling);
case TOK_YIELD: {
// Don't use a ternary operator here due to obscure linker issues
// around using static consts in the arms of a ternary.
TokenStream::Modifier modifier;
if (yieldExpressionsSupported())
modifier = TokenStream::Operand;
else
modifier = TokenStream::None;
TokenKind next;
if (!tokenStream.peekToken(&next, modifier))
return null();
if (next == TOK_COLON) {
if (!checkYieldNameValidity())
return null();
return labeledStatement(yieldHandling);
}
return expressionStatement(yieldHandling);
}
case TOK_NAME: {
TokenKind next;
if (!tokenStream.peekToken(&next))
return null();
if (tokenStream.currentName() == context->names().let) {
if (nextTokenContinuesLetDeclaration(next, yieldHandling))
return lexicalDeclaration(yieldHandling, /* isConst = */ false);
// IdentifierName can't be "let" in strict mode code. |let| in
// strict mode code is usually TOK_LET, but in this one weird case
// in global code it's TOK_NAME:
//
// "use strict" // ExpressionStatement ended by ASI
// let <...whatever else...> // a fresh StatementListItem
//
// Carefully reject strict mode |let| non-declarations.
if (pc->sc()->strict()) {
report(ParseError, false, null(), JSMSG_UNEXPECTED_TOKEN,
"declaration pattern", TokenKindToDesc(next));
return null();
}
}
if (next == TOK_COLON)
return labeledStatement(yieldHandling);
return expressionStatement(yieldHandling);
}
case TOK_NEW:
return expressionStatement(yieldHandling, PredictInvoked);
default:
return expressionStatement(yieldHandling);
// IfStatement[?Yield, ?Return]
case TOK_IF:
return ifStatement(yieldHandling);
// BreakableStatement[?Yield, ?Return]
//
// BreakableStatement[Yield, Return]:
// IterationStatement[?Yield, ?Return]
// SwitchStatement[?Yield, ?Return]
case TOK_DO:
return doWhileStatement(yieldHandling);
case TOK_WHILE:
return whileStatement(yieldHandling);
case TOK_FOR:
return forStatement(yieldHandling);
case TOK_SWITCH:
return switchStatement(yieldHandling);
// ContinueStatement[?Yield]
case TOK_CONTINUE:
return continueStatement(yieldHandling);
// BreakStatement[?Yield]
case TOK_BREAK:
return breakStatement(yieldHandling);
// [+Return] ReturnStatement[?Yield]
case TOK_RETURN:
// The Return parameter is only used here, and the effect is easily
// detected this way, so don't bother passing around an extra parameter
// everywhere.
if (!pc->isFunctionBox()) {
report(ParseError, false, null(), JSMSG_BAD_RETURN_OR_YIELD, js_return_str);
return null();
}
return returnStatement(yieldHandling);
// WithStatement[?Yield, ?Return]
case TOK_WITH:
return withStatement(yieldHandling);
// LabelledStatement[?Yield, ?Return]
// This is really handled by TOK_NAME and TOK_YIELD cases above.
// ThrowStatement[?Yield]
case TOK_THROW:
return throwStatement(yieldHandling);
// TryStatement[?Yield, ?Return]
case TOK_TRY:
return tryStatement(yieldHandling);
// DebuggerStatement
case TOK_DEBUGGER:
return debuggerStatement();
// Declaration[Yield]:
// HoistableDeclaration[?Yield, ~Default]
case TOK_FUNCTION:
return functionStmt(yieldHandling, NameRequired);
// ClassDeclaration[?Yield]
// ClassDeclaration[?Yield, ~Default]
case TOK_CLASS:
if (!abortIfSyntaxParser())
return null();
return classDefinition(yieldHandling, ClassStatement, NameRequired);
// LexicalDeclaration[In, ?Yield]
// LexicalDeclaration[In, ?Yield]
// LetOrConst BindingList[?In, ?Yield]
case TOK_LET:
case TOK_CONST:
if (!abortIfSyntaxParser())
return null();
// [In] is the default behavior, because for-loops currently specially
// parse their heads to handle |in| in this situation.
// [In] is the default behavior, because for-loops specially parse
// their heads to handle |in| in this situation.
return lexicalDeclaration(yieldHandling, /* isConst = */ tt == TOK_CONST);
// ImportDeclaration (only inside modules)

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

@ -938,7 +938,8 @@ class Parser final : private JS::AutoGCRooter, public StrictModeGetter
public:
/* Public entry points for parsing. */
Node statement(YieldHandling yieldHandling, bool canHaveDirectives = false);
Node statement(YieldHandling yieldHandling);
Node statementListItem(YieldHandling yieldHandling, bool canHaveDirectives = false);
bool maybeParseDirective(Node list, Node pn, bool* cont);
@ -1017,11 +1018,11 @@ class Parser final : private JS::AutoGCRooter, public StrictModeGetter
*/
Node functionStmt(YieldHandling yieldHandling, DefaultHandling defaultHandling);
Node functionExpr(InvokedPrediction invoked = PredictUninvoked);
Node statements(YieldHandling yieldHandling);
Node statementList(YieldHandling yieldHandling);
Node blockStatement(YieldHandling yieldHandling,
unsigned errorNumber = JSMSG_CURLY_IN_COMPOUND);
Node ifStatement(YieldHandling yieldHandling);
Node doWhileStatement(YieldHandling yieldHandling);
Node whileStatement(YieldHandling yieldHandling);
@ -1039,13 +1040,26 @@ class Parser final : private JS::AutoGCRooter, public StrictModeGetter
Node breakStatement(YieldHandling yieldHandling);
Node returnStatement(YieldHandling yieldHandling);
Node withStatement(YieldHandling yieldHandling);
Node labeledStatement(YieldHandling yieldHandling);
Node throwStatement(YieldHandling yieldHandling);
Node tryStatement(YieldHandling yieldHandling);
Node catchBlockStatement(YieldHandling yieldHandling, HandlePropertyName simpleCatchParam);
Node debuggerStatement();
Node variableStatement(YieldHandling yieldHandling);
Node labeledStatement(YieldHandling yieldHandling);
Node labeledItem(YieldHandling yieldHandling);
Node ifStatement(YieldHandling yieldHandling);
Node consequentOrAlternative(YieldHandling yieldHandling);
// While on a |let| TOK_NAME token, examine |next|. Indicate whether
// |next|, the next token already gotten with modifier TokenStream::None,
// continues a LexicalDeclaration.
bool nextTokenContinuesLetDeclaration(TokenKind next, YieldHandling yieldHandling);
Node lexicalDeclaration(YieldHandling yieldHandling, bool isConst);
Node importDeclaration();
Node exportDeclaration();
Node expressionStatement(YieldHandling yieldHandling,
@ -1239,15 +1253,6 @@ class Parser final : private JS::AutoGCRooter, public StrictModeGetter
bool finishFunction();
bool leaveInnerFunction(ParseContext* outerpc);
// Use when the current token is TOK_NAME and is known to be 'let'.
bool shouldParseLetDeclaration(bool* parseDeclOut);
// Use when the lookahead token is TOK_NAME and is known to be 'let'. If a
// let declaration should be parsed, the TOK_NAME token of 'let' is
// consumed. Otherwise, the current token remains the TOK_NAME token of
// 'let'.
bool peekShouldParseLetDeclaration(bool* parseDeclOut, TokenStream::Modifier modifier);
public:
enum FunctionCallBehavior {
PermitAssignmentToFunctionCalls,

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

@ -2,6 +2,8 @@ setJitCompilerOption("baseline.warmup.trigger", 10);
setJitCompilerOption("ion.warmup.trigger", 20);
var i;
var config = getBuildConfiguration();
// Check that we are able to remove the operation inside recover test functions (denoted by "rop..."),
// when we inline the first version of uceFault, and ensure that the bailout is correct
// when uceFault is replaced (which cause an invalidation bailout)
@ -1286,6 +1288,29 @@ function rhypot_object_4args(i) {
return i;
}
var uceFault_random = eval(uneval(uceFault).replace('uceFault', 'uceFault_random'));
function rrandom(i) {
// setRNGState() exists only in debug builds
if(config.debug) {
setRNGState(2, 0);
var x = Math.random();
if (uceFault_random(i) || uceFault_random(i)) {
setRNGState(2, 0);
assertEq(x, Math.random());
}
assertRecoveredOnBailout(x, true);
} else {
var x = Math.random();
if (uceFault_random(i) || uceFault_random(i)) {
Math.random();
}
assertRecoveredOnBailout(x, true);
}
return i;
}
var uceFault_sin_number = eval(uneval(uceFault).replace('uceFault', 'uceFault_sin_number'));
function rsin_number(i) {
var x = Math.sin(i);
@ -1444,6 +1469,7 @@ for (i = 0; i < 100; i++) {
rhypot_object_2args(i);
rhypot_object_3args(i);
rhypot_object_4args(i);
rrandom(i);
rsin_number(i);
rsin_object(i);
rlog_number(i);

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

@ -0,0 +1,24 @@
setJitCompilerOption("ion.warmup.trigger", 40);
const constructors = [
Int8Array,
Uint8Array,
Uint8ClampedArray,
Int16Array,
Uint16Array,
Int32Array,
Uint32Array,
Float32Array,
Float64Array ];
// Ensure that when creating TypedArrays under JIT
// the sort() method works as expected (bug 1295034).
for (var ctor of constructors) {
for (var _ of Array(1024)) {
var testArray = new ctor(10);
testArray.sort();
}
}
if (typeof reportCompare === "function")
reportCompare(true, true);

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

@ -11520,10 +11520,10 @@ CodeGenerator::visitAsmJSInterruptCheck(LAsmJSInterruptCheck* lir)
}
void
CodeGenerator::visitAsmThrowUnreachable(LAsmThrowUnreachable* lir)
CodeGenerator::visitWasmTrap(LWasmTrap* lir)
{
MOZ_ASSERT(gen->compilingAsmJS());
masm.jump(wasm::JumpTarget::Unreachable);
masm.jump(wasm::JumpTarget(lir->mir()->trap()));
}
typedef bool (*RecompileFn)(JSContext*);

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

@ -415,7 +415,7 @@ class CodeGenerator final : public CodeGeneratorSpecific
void visitInterruptCheck(LInterruptCheck* lir);
void visitOutOfLineInterruptCheckImplicit(OutOfLineInterruptCheckImplicit* ins);
void visitAsmJSInterruptCheck(LAsmJSInterruptCheck* lir);
void visitAsmThrowUnreachable(LAsmThrowUnreachable* lir);
void visitWasmTrap(LWasmTrap* lir);
void visitRecompileCheck(LRecompileCheck* ins);
void visitRotate(LRotate* ins);

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

@ -2530,9 +2530,9 @@ LIRGenerator::visitAsmJSInterruptCheck(MAsmJSInterruptCheck* ins)
}
void
LIRGenerator::visitAsmThrowUnreachable(MAsmThrowUnreachable* ins)
LIRGenerator::visitWasmTrap(MWasmTrap* ins)
{
add(new(alloc()) LAsmThrowUnreachable, ins);
add(new(alloc()) LWasmTrap, ins);
}
void

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

@ -191,7 +191,7 @@ class LIRGenerator : public LIRGeneratorSpecific
void visitFunctionEnvironment(MFunctionEnvironment* ins);
void visitInterruptCheck(MInterruptCheck* ins);
void visitAsmJSInterruptCheck(MAsmJSInterruptCheck* ins);
void visitAsmThrowUnreachable(MAsmThrowUnreachable* ins);
void visitWasmTrap(MWasmTrap* ins);
void visitAsmReinterpret(MAsmReinterpret* ins);
void visitStoreSlot(MStoreSlot* ins);
void visitFilterTypeSet(MFilterTypeSet* ins);

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

@ -6584,6 +6584,16 @@ class MRandom : public MNullaryInstruction
void computeRange(TempAllocator& alloc) override;
MOZ_MUST_USE bool writeRecoverData(CompactBufferWriter& writer) const override;
bool canRecoverOnBailout() const override {
#ifdef JS_MORE_DETERMINISTIC
return false;
#else
return true;
#endif
}
ALLOW_CLONE(MRandom)
};
@ -7738,18 +7748,28 @@ class MAsmJSInterruptCheck
TRIVIAL_NEW_WRAPPERS
};
// Directly jumps to the unreachable trap handler.
class MAsmThrowUnreachable
// Directly jumps to the indicated trap, leaving Wasm code and reporting a
// runtime error.
class MWasmTrap
: public MAryControlInstruction<0, 0>,
public NoTypePolicy::Data
{
wasm::Trap trap_;
explicit MWasmTrap(wasm::Trap trap)
: trap_(trap)
{}
public:
INSTRUCTION_HEADER(AsmThrowUnreachable)
INSTRUCTION_HEADER(WasmTrap)
TRIVIAL_NEW_WRAPPERS
AliasSet getAliasSet() const override {
return AliasSet::None();
}
wasm::Trap trap() const { return trap_; }
};
// Checks if a value is JS_UNINITIALIZED_LEXICAL, bailout out if so, leaving

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

@ -262,7 +262,6 @@ namespace jit {
_(CallInstanceOf) \
_(InterruptCheck) \
_(AsmJSInterruptCheck) \
_(AsmThrowUnreachable) \
_(GetDOMProperty) \
_(GetDOMMember) \
_(SetDOMProperty) \
@ -274,6 +273,7 @@ namespace jit {
_(WasmBoundsCheck) \
_(WasmLoad) \
_(WasmStore) \
_(WasmTrap) \
_(WasmTruncateToInt32) \
_(AsmJSNeg) \
_(AsmJSUnsignedToDouble) \

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

@ -1005,6 +1005,24 @@ RMathFunction::recover(JSContext* cx, SnapshotIterator& iter) const
}
}
bool
MRandom::writeRecoverData(CompactBufferWriter& writer) const
{
MOZ_ASSERT(this->canRecoverOnBailout());
writer.writeUnsigned(uint32_t(RInstruction::Recover_Random));
return true;
}
RRandom::RRandom(CompactBufferReader& reader)
{}
bool
RRandom::recover(JSContext* cx, SnapshotIterator& iter) const
{
iter.storeInstructionResult(DoubleValue(math_random_impl(cx)));
return true;
}
bool
MStringSplit::writeRecoverData(CompactBufferWriter& writer) const
{

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

@ -88,6 +88,7 @@ namespace jit {
_(Atan2) \
_(Hypot) \
_(MathFunction) \
_(Random) \
_(StringSplit) \
_(RegExpMatcher) \
_(RegExpSearcher) \
@ -462,6 +463,13 @@ class RMathFunction final : public RInstruction
MOZ_MUST_USE bool recover(JSContext* cx, SnapshotIterator& iter) const;
};
class RRandom final : public RInstruction
{
RINSTRUCTION_HEADER_NUM_OP_(Random, 0)
public:
MOZ_MUST_USE bool recover(JSContext* cx, SnapshotIterator& iter) const;
};
class RStringSplit final : public RInstruction
{
public:

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

@ -2291,11 +2291,7 @@ CodeGeneratorARM::visitWasmBoundsCheck(LWasmBoundsCheck* ins)
{
MWasmBoundsCheck* mir = ins->mir();
uint32_t offset = mir->offset();
if (offset > INT32_MAX) {
masm.as_b(wasm::JumpTarget::OutOfBounds);
return;
}
MOZ_ASSERT(mir->offset() <= INT32_MAX);
if (!mir->isRedundant()) {
// No guarantee that heapBase + endOffset can be properly encoded in
@ -2348,11 +2344,7 @@ CodeGeneratorARM::emitWasmLoad(T* lir)
MOZ_ASSERT(!mir->barrierBefore() && !mir->barrierAfter(), "atomics NYI");
uint32_t offset = mir->offset();
if (offset > INT32_MAX) {
// This is unreachable because of bounds checks.
masm.breakpoint();
return;
}
MOZ_ASSERT(offset <= INT32_MAX);
Register ptr = ToRegister(lir->ptr());
Scalar::Type type = mir->accessType();
@ -2419,11 +2411,7 @@ CodeGeneratorARM::emitWasmUnalignedLoad(T* lir)
MOZ_ASSERT(!mir->barrierBefore() && !mir->barrierAfter(), "atomics NYI");
uint32_t offset = mir->offset();
if (offset > INT32_MAX) {
// This is unreachable because of bounds checks.
masm.breakpoint();
return;
}
MOZ_ASSERT(offset <= INT32_MAX);
Register ptr = ToRegister(lir->ptrCopy());
if (offset)
@ -2503,11 +2491,7 @@ CodeGeneratorARM::emitWasmStore(T* lir)
MOZ_ASSERT(!mir->barrierBefore() && !mir->barrierAfter(), "atomics NYI");
uint32_t offset = mir->offset();
if (offset > INT32_MAX) {
// This is unreachable because of bounds checks.
masm.breakpoint();
return;
}
MOZ_ASSERT(offset <= INT32_MAX);
Register ptr = ToRegister(lir->ptr());
unsigned byteSize = mir->byteSize();

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

@ -1666,10 +1666,7 @@ CodeGeneratorMIPSShared::visitWasmBoundsCheck(LWasmBoundsCheck* ins)
MWasmBoundsCheck* mir = ins->mir();
uint32_t offset = mir->offset();
if (offset > INT32_MAX) {
masm.jump(wasm::JumpTarget::OutOfBounds);
return;
}
MOZ_ASSERT(offset <= INT32_MAX);
uint32_t endOffset = mir->endOffset();
Register ptr = ToRegister(ins->ptr());
@ -1693,11 +1690,7 @@ CodeGeneratorMIPSShared::visitWasmLoad(LWasmLoad* lir)
MOZ_ASSERT(!mir->barrierBefore() && !mir->barrierAfter(), "atomics NYI");
uint32_t offset = mir->offset();
if (offset > INT32_MAX) {
// This is unreachable because of bounds checks.
masm.breakpoint();
return;
}
MOZ_ASSERT(offset <= INT32_MAX);
Register ptr = ToRegister(lir->ptr());
@ -1745,11 +1738,7 @@ CodeGeneratorMIPSShared::visitWasmStore(LWasmStore* lir)
MOZ_ASSERT(!mir->barrierBefore() && !mir->barrierAfter(), "atomics NYI");
uint32_t offset = mir->offset();
if (offset > INT32_MAX) {
// This is unreachable because of bounds checks.
masm.breakpoint();
return;
}
MOZ_ASSERT(offset <= INT32_MAX);
Register ptr = ToRegister(lir->ptr());

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

@ -1067,26 +1067,14 @@ MacroAssemblerMIPSCompat::storePtr(Register src, AbsoluteAddress dest)
void
MacroAssemblerMIPSCompat::clampIntToUint8(Register reg)
{
// look at (reg >> 8) if it is 0, then src shouldn't be clamped
// if it is <0, then we want to clamp to 0,
// otherwise, we wish to clamp to 255
Label done;
ma_move(ScratchRegister, reg);
asMasm().rshiftPtrArithmetic(Imm32(8), ScratchRegister);
ma_b(ScratchRegister, ScratchRegister, &done, Assembler::Zero, ShortJump);
{
Label negative;
ma_b(ScratchRegister, ScratchRegister, &negative, Assembler::Signed, ShortJump);
{
ma_li(reg, Imm32(255));
ma_b(&done, ShortJump);
}
bind(&negative);
{
ma_move(reg, zero);
}
}
bind(&done);
// If reg is < 0, then we want to clamp to 0.
as_slti(ScratchRegister, reg, 0);
as_movn(reg, zero, ScratchRegister);
// If reg is >= 255, then we want to clamp to 255.
ma_li(SecondScratchReg, Imm32(255));
as_slti(ScratchRegister, reg, 255);
as_movz(reg, SecondScratchReg, ScratchRegister);
}
// Note: this function clobbers the input register.

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

@ -1214,26 +1214,14 @@ MacroAssemblerMIPS64Compat::storePtr(Register src, AbsoluteAddress dest)
void
MacroAssemblerMIPS64Compat::clampIntToUint8(Register reg)
{
// look at (reg >> 8) if it is 0, then src shouldn't be clamped
// if it is <0, then we want to clamp to 0,
// otherwise, we wish to clamp to 255
Label done;
ma_move(ScratchRegister, reg);
asMasm().rshiftPtrArithmetic(Imm32(8), ScratchRegister);
ma_b(ScratchRegister, ScratchRegister, &done, Assembler::Zero, ShortJump);
{
Label negative;
ma_b(ScratchRegister, ScratchRegister, &negative, Assembler::Signed, ShortJump);
{
ma_li(reg, Imm32(255));
ma_b(&done, ShortJump);
}
bind(&negative);
{
ma_move(reg, zero);
}
}
bind(&done);
// If reg is < 0, then we want to clamp to 0.
as_slti(ScratchRegister, reg, 0);
as_movn(reg, zero, ScratchRegister);
// If reg is >= 255, then we want to clamp to 255.
ma_li(SecondScratchReg, Imm32(255));
as_slti(ScratchRegister, reg, 255);
as_movz(reg, SecondScratchReg, ScratchRegister);
}
// Note: this function clobbers the input register.
@ -1330,15 +1318,13 @@ MacroAssemblerMIPS64Compat::unboxNonDouble(const BaseIndex& src, Register dest)
void
MacroAssemblerMIPS64Compat::unboxInt32(const ValueOperand& operand, Register dest)
{
ma_dsll(dest, operand.valueReg(), Imm32(32));
ma_dsra(dest, dest, Imm32(32));
ma_sll(dest, operand.valueReg(), Imm32(0));
}
void
MacroAssemblerMIPS64Compat::unboxInt32(Register src, Register dest)
{
ma_dsll(dest, src, Imm32(32));
ma_dsra(dest, dest, Imm32(32));
ma_sll(dest, src, Imm32(0));
}
void

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

@ -1404,13 +1404,17 @@ class LAsmJSInterruptCheck : public LInstructionHelper<0, 0, 0>
}
};
class LAsmThrowUnreachable : public LInstructionHelper<0, 0, 0>
class LWasmTrap : public LInstructionHelper<0, 0, 0>
{
public:
LIR_HEADER(AsmThrowUnreachable);
LIR_HEADER(WasmTrap);
LAsmThrowUnreachable()
LWasmTrap()
{ }
const MWasmTrap* mir() const {
return mir_->toWasmTrap();
}
};
template<size_t Defs, size_t Ops>

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

@ -369,7 +369,7 @@
_(CallInstanceOf) \
_(InterruptCheck) \
_(AsmJSInterruptCheck) \
_(AsmThrowUnreachable) \
_(WasmTrap) \
_(AsmReinterpret) \
_(AsmReinterpretToI64) \
_(AsmReinterpretFromI64) \

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

@ -538,11 +538,7 @@ CodeGeneratorX64::emitWasmLoad(T* ins)
Scalar::Type accessType = mir->accessType();
MOZ_ASSERT(!Scalar::isSimdType(accessType), "SIMD NYI");
MOZ_ASSERT(!mir->barrierBefore() && !mir->barrierAfter(), "atomics NYI");
if (mir->offset() > INT32_MAX) {
masm.jump(wasm::JumpTarget::OutOfBounds);
return;
}
MOZ_ASSERT(mir->offset() <= INT32_MAX);
const LAllocation* ptr = ins->ptr();
Operand srcAddr = ptr->isBogus()
@ -583,11 +579,7 @@ CodeGeneratorX64::emitWasmStore(T* ins)
Scalar::Type accessType = mir->accessType();
MOZ_ASSERT(!Scalar::isSimdType(accessType), "SIMD NYI");
MOZ_ASSERT(!mir->barrierBefore() && !mir->barrierAfter(), "atomics NYI");
if (mir->offset() > INT32_MAX) {
masm.jump(wasm::JumpTarget::OutOfBounds);
return;
}
MOZ_ASSERT(mir->offset() <= INT32_MAX);
const LAllocation* value = ins->getOperand(ins->ValueIndex);
const LAllocation* ptr = ins->ptr();

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

@ -494,11 +494,9 @@ void
CodeGeneratorX86Shared::visitWasmBoundsCheck(LWasmBoundsCheck* ins)
{
const MWasmBoundsCheck* mir = ins->mir();
MOZ_ASSERT(gen->needsBoundsCheckBranch(mir));
if (mir->offset() > INT32_MAX) {
masm.jump(wasm::JumpTarget::OutOfBounds);
return;
}
MOZ_ASSERT(mir->offset() <= INT32_MAX);
Register ptrReg = ToRegister(ins->ptr());
maybeEmitWasmBoundsCheckBranch(mir, ptrReg, mir->isRedundant());
@ -548,9 +546,8 @@ CodeGeneratorX86Shared::maybeEmitWasmBoundsCheckBranch(const MWasmMemoryAccess*
MOZ_ASSERT(mir->endOffset() >= 1,
"need to subtract 1 to use JAE, see also AssemblerX86Shared::UpdateBoundsCheck");
/*
* TODO: See 1287224 Unify MWasmBoundsCheck::redunant_ and needsBoundsCheck
*/
// TODO: See 1287224 Unify MWasmBoundsCheck::redunant_ and needsBoundsCheck
if (!redundant) {
uint32_t cmpOffset = masm.cmp32WithPatch(ptr, Imm32(1 - mir->endOffset())).offset();
masm.j(Assembler::AboveOrEqual, wasm::JumpTarget::OutOfBounds);

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

@ -500,12 +500,7 @@ CodeGeneratorX86::emitWasmLoad(T* ins)
Scalar::Type accessType = mir->accessType();
MOZ_ASSERT(!Scalar::isSimdType(accessType), "SIMD NYI");
MOZ_ASSERT(!mir->barrierBefore() && !mir->barrierAfter(), "atomics NYI");
if (mir->offset() > INT32_MAX) {
// This is unreachable because of the bounds check.
masm.breakpoint();
return;
}
MOZ_ASSERT(mir->offset() <= INT32_MAX);
const LAllocation* ptr = ins->ptr();
Operand srcAddr = ptr->isBogus()
@ -539,12 +534,7 @@ CodeGeneratorX86::emitWasmStore(T* ins)
Scalar::Type accessType = mir->accessType();
MOZ_ASSERT(!Scalar::isSimdType(accessType), "SIMD NYI");
MOZ_ASSERT(!mir->barrierBefore() && !mir->barrierAfter(), "atomics NYI");
if (mir->offset() > INT32_MAX) {
// This is unreachable because of the bounds check.
masm.breakpoint();
return;
}
MOZ_ASSERT(mir->offset() <= INT32_MAX);
const LAllocation* ptr = ins->ptr();
Operand dstAddr = ptr->isBogus()

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

@ -248,6 +248,7 @@ MSG_DEF(JSMSG_EMPTY_CONSEQUENT, 0, JSEXN_SYNTAXERR, "mistyped ; after con
MSG_DEF(JSMSG_EQUAL_AS_ASSIGN, 0, JSEXN_SYNTAXERR, "test for equality (==) mistyped as assignment (=)?")
MSG_DEF(JSMSG_EXPORT_DECL_AT_TOP_LEVEL,0, JSEXN_SYNTAXERR, "export declarations may only appear at top level of a module")
MSG_DEF(JSMSG_FINALLY_WITHOUT_TRY, 0, JSEXN_SYNTAXERR, "finally without try")
MSG_DEF(JSMSG_FORBIDDEN_AS_STATEMENT, 1, JSEXN_SYNTAXERR, "{0} can't appear in single-statement context")
MSG_DEF(JSMSG_FROM_AFTER_IMPORT_CLAUSE, 0, JSEXN_SYNTAXERR, "missing keyword 'from' after import clause")
MSG_DEF(JSMSG_FROM_AFTER_EXPORT_STAR, 0, JSEXN_SYNTAXERR, "missing keyword 'from' after export *")
MSG_DEF(JSMSG_GARBAGE_AFTER_INPUT, 2, JSEXN_SYNTAXERR, "unexpected garbage after {0}, starting with {1}")
@ -260,6 +261,7 @@ MSG_DEF(JSMSG_LET_CLASS_BINDING, 0, JSEXN_SYNTAXERR, "'let' is not a valid
MSG_DEF(JSMSG_LET_COMP_BINDING, 0, JSEXN_SYNTAXERR, "'let' is not a valid name for a comprehension variable")
MSG_DEF(JSMSG_LEXICAL_DECL_NOT_IN_BLOCK, 1, JSEXN_SYNTAXERR, "{0} declaration not directly within block")
MSG_DEF(JSMSG_LEXICAL_DECL_LABEL, 1, JSEXN_SYNTAXERR, "{0} declarations cannot be labelled")
MSG_DEF(JSMSG_GENERATOR_LABEL, 0, JSEXN_SYNTAXERR, "generator functions cannot be labelled")
MSG_DEF(JSMSG_FUNCTION_LABEL, 0, JSEXN_SYNTAXERR, "functions cannot be labelled")
MSG_DEF(JSMSG_SLOPPY_FUNCTION_LABEL, 0, JSEXN_SYNTAXERR, "functions can only be labelled inside blocks")
MSG_DEF(JSMSG_LINE_BREAK_AFTER_THROW, 0, JSEXN_SYNTAXERR, "no line break is allowed between 'throw' and its expression")

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

@ -719,16 +719,19 @@ JSCompartment::ensureRandomNumberGenerator()
}
}
double
js::math_random_impl(JSContext* cx)
{
JSCompartment* comp = cx->compartment();
comp->ensureRandomNumberGenerator();
return comp->randomNumberGenerator.ref().nextDouble();
}
bool
js::math_random(JSContext* cx, unsigned argc, Value* vp)
{
CallArgs args = CallArgsFromVp(argc, vp);
JSCompartment* comp = cx->compartment();
comp->ensureRandomNumberGenerator();
double z = comp->randomNumberGenerator.ref().nextDouble();
args.rval().setDouble(z);
args.rval().setNumber(math_random_impl(cx));
return true;
}

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

@ -94,6 +94,9 @@ GenerateXorShift128PlusSeed(mozilla::Array<uint64_t, 2>& seed);
extern uint64_t
random_next(uint64_t* rngState, int bits);
extern double
math_random_impl(JSContext* cx);
extern bool
math_random(JSContext* cx, unsigned argc, js::Value* vp);

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

@ -2544,6 +2544,13 @@ js::SetPrototype(JSContext* cx, HandleObject obj, HandleObject proto, JS::Object
return Proxy::setPrototype(cx, obj, proto, result);
}
/*
* ES6 9.1.2 step 3-4 if |obj.[[Prototype]]| has SameValue as |proto| return true.
* Since the values in question are objects, we can just compare pointers.
*/
if (proto == obj->staticPrototype())
return result.succeed();
/* Disallow mutation of immutable [[Prototype]]s. */
if (obj->staticPrototypeIsImmutable() && ImmutablePrototypesEnabled)
return result.fail(JSMSG_CANT_SET_PROTO);
@ -2578,13 +2585,6 @@ js::SetPrototype(JSContext* cx, HandleObject obj, HandleObject proto, JS::Object
return false;
}
/*
* ES6 9.1.2 step 3-4 if |obj.[[Prototype]]| has SameValue as |proto| return true.
* Since the values in question are objects, we can just compare pointers.
*/
if (proto == obj->staticPrototype())
return result.succeed();
/* ES6 9.1.2 step 5 forbids changing [[Prototype]] if not [[Extensible]]. */
bool extensible;
if (!IsExtensible(cx, obj, &extensible))

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

@ -0,0 +1,11 @@
// Setting a "new" prototype to the current [[Prototype]] value should never fail
var x = {}, t = Object.create(x);
Object.preventExtensions(t);
// Should not fail, because it is the same [[Prototype]] value
Object.setPrototypeOf(t, x);
// Object.prototype's [[Prototype]] is immutable, make sure we can still set null
Object.setPrototypeOf(Object.prototype, null);
reportCompare(true, true);

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

@ -0,0 +1,34 @@
/*
* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/licenses/publicdomain/
*/
//-----------------------------------------------------------------------------
var BUGNUMBER = 1288459;
var summary =
"Properly implement the spec's distinctions between StatementListItem and " +
"Statement grammar productions and their uses";
print(BUGNUMBER + ": " + summary);
/**************
* BEGIN TEST *
**************/
assertThrowsInstanceOf(() => Function("a: let x;"), SyntaxError);
assertThrowsInstanceOf(() => Function("b: const y = 3;"), SyntaxError);
assertThrowsInstanceOf(() => Function("c: class z {};"), SyntaxError);
assertThrowsInstanceOf(() => Function("'use strict'; d: function w() {};"), SyntaxError);
// Annex B.3.2 allows this in non-strict mode code.
Function("e: function x() {};");
assertThrowsInstanceOf(() => Function("f: function* y() {}"), SyntaxError);
/******************************************************************************/
if (typeof reportCompare === "function")
reportCompare(true, true);
print("Tests complete");

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

@ -0,0 +1,29 @@
/*
* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/licenses/publicdomain/
*/
//-----------------------------------------------------------------------------
var BUGNUMBER = 1288459;
var summary = "let can't be used as a label in strict mode code";
print(BUGNUMBER + ": " + summary);
/**************
* BEGIN TEST *
**************/
Function("let: 42")
assertThrowsInstanceOf(() => Function(" 'use strict'; let: 42"), SyntaxError);
assertThrowsInstanceOf(() => Function(" 'use strict' \n let: 42"), SyntaxError);
eval("let: 42")
assertThrowsInstanceOf(() => eval(" 'use strict'; let: 42"), SyntaxError);
assertThrowsInstanceOf(() => eval(" 'use strict' \n let: 42;"), SyntaxError);
/******************************************************************************/
if (typeof reportCompare === "function")
reportCompare(true, true);
print("Tests complete");

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