import changes from tenfourfox:

- #522: basic window.open=noopener, refactor popup blocker M1267338 M1267339 (46bf256a1)
- closes #522: rel=noopener M1222516 M1358469 M1419960 (6abcdc2cc)
- closes #524: enable MSE by default (3c3b61b6f)
- #399: M1342849 (47b8abd55)
- more hosts for adblock (8f342c327)
- #334: remove Telemetry from JS-DOM-XPConnect runtime (b95f6e968)
- #525: data URL opaque origins M1324406 M1381728 (3920907ee)
- #392: prerequisite SetCanonicalName M1235656 M1236638 (c1f84d628)
- #392: Symbol.toStringTag M1114580 (w/o ESClassValue change; w/45ESR boilerplate) (3cf6b4057)
- #525: fix assertion (until asyncOpen2 is implemented) (d9ffd4d15)
- another host for adblock (ff9433ee7)
- #526: M1493347 M1487098 M1423278 (4d34a54ce)
- #526: update certs and pins (bcc8aabb9)
This commit is contained in:
2018-10-10 21:23:35 +08:00
parent bb65879364
commit 0b27a01673
76 changed files with 4099 additions and 1248 deletions
+2
View File
@@ -138,6 +138,8 @@ ImageAccessible::DoAction(uint8_t aIndex)
nsCOMPtr<nsPIDOMWindow> tmp;
return NS_SUCCEEDED(piWindow->Open(spec, EmptyString(), EmptyString(),
/* aLoadInfo = */ nullptr,
/* aForceNoOpener = */ false,
getter_AddRefs(tmp)));
}
+11 -4
View File
@@ -1742,6 +1742,7 @@
var aForceNotRemote;
var aNoReferrer;
var aUserContextId;
var aSkipBackgroundNotify;
if (arguments.length == 2 &&
typeof arguments[1] == "object" &&
!(arguments[1] instanceof Ci.nsIURI)) {
@@ -1759,6 +1760,7 @@
aForceNotRemote = params.forceNotRemote;
aNoReferrer = params.noReferrer;
aUserContextId = params.userContextId;
aSkipBackgroundNotify = params.skipBackgroundNotify;
}
// if we're adding tabs, we're past interrupt mode, ditch the owner
@@ -1773,6 +1775,11 @@
t.setAttribute("usercontextid", aUserContextId);
t.setAttribute("crop", "end");
t.setAttribute("onerror", "this.removeAttribute('image');");
if (aSkipBackgroundNotify) {
t.setAttribute("skipbackgroundnotify", true);
}
t.className = "tabbrowser-tab";
// The new browser should be remote if this is an e10s window and
@@ -5145,10 +5152,10 @@
selected.left - scrollRect.left);
}
if (!this._animateElement.hasAttribute("notifybgtab")) {
this._animateElement.setAttribute("notifybgtab", "true");
if (!this._animateElement.hasAttribute("highlight")) {
this._animateElement.setAttribute("highlight", "true");
setTimeout(function (ele) {
ele.removeAttribute("notifybgtab");
ele.removeAttribute("highlight");
}, 150, this._animateElement);
}
]]></body>
@@ -5239,7 +5246,7 @@
if (tab.getAttribute("selected") == "true") {
//this._fillTrailingGap();
this._handleTabSelect();
} else {
} else if (!tab.hasAttribute("skipbackgroundnotify")) {
this._notifyBackgroundTab(tab);
}
@@ -2932,6 +2932,7 @@ var SessionStoreInternal = {
tabbrowser.addTab("about:blank", {
skipAnimation: true,
forceNotRemote: true,
skipBackgroundNotify: true,
}));
if (winData.tabs[t].pinned)
@@ -32,7 +32,8 @@ var TabAttributesInternal = {
// 'muted' should not be accessed directly but handled by using the
// tab.linkedBrowser.audioMuted/toggleMuteAudio methods.
// 'pending' is used internal by sessionstore and managed accordingly.
_skipAttrs: new Set(["image", "muted", "pending"]),
// 'skipbackgroundnotify' is used to speed up startup time (bug 1342849).
_skipAttrs: new Set(["image", "muted", "pending", "skipbackgroundnotify"]),
persist: function (name) {
if (this._attrs.has(name) || this._skipAttrs.has(name)) {
+1 -1
View File
@@ -1564,7 +1564,7 @@ richlistitem[type~="action"][actiontype$="tab"] > .ac-url-box > .ac-action-icon
transition: 1s background-color ease-out;
}
.tabbrowser-arrowscrollbox > .scrollbutton-down[notifybgtab] {
.tabbrowser-arrowscrollbox > .scrollbutton-down[highlight] {
background-color: Highlight;
transition: none;
}
+1 -1
View File
@@ -2641,7 +2641,7 @@ toolbarbutton.chevron > .toolbarbutton-menu-dropmarker {
transition: 1s background-color ease-out;
}
.tabbrowser-arrowscrollbox > .scrollbutton-down[notifybgtab] {
.tabbrowser-arrowscrollbox > .scrollbutton-down[highlight] {
background-color: Highlight;
transition: none;
}
+1 -1
View File
@@ -2046,7 +2046,7 @@ richlistitem[type~="action"][actiontype$="tab"] > .ac-url-box > .ac-action-icon
transition: 1s background-color ease-out;
}
.tabbrowser-arrowscrollbox > .scrollbutton-down[notifybgtab] {
.tabbrowser-arrowscrollbox > .scrollbutton-down[highlight] {
background-color: Highlight;
transition: none;
}
+8
View File
@@ -1144,6 +1144,14 @@ nsScriptSecurityManager::CheckLoadURIWithPrincipal(nsIPrincipal* aPrincipal,
BLOK("synchrobox.adswizz.com") ||
BLOK("delivery-cdn-cf.adswizz.com") ||
BLOK("router.infolinks.com") ||
BLOK("rps-uk.rockpapershotgun.com") || // XXX?
BLOK("buy.tinypass.com") ||
BLOK("cdn.tinypass.com") ||
0) {
#undef BLOK
// Yup.
+70 -10
View File
@@ -9592,9 +9592,20 @@ nsDocShell::InternalLoad(nsIURI* aURI,
if (aWindowTarget && *aWindowTarget) {
// Locate the target DocShell.
nsCOMPtr<nsIDocShellTreeItem> targetItem;
rv = FindItemWithName(aWindowTarget, nullptr, this,
getter_AddRefs(targetItem));
NS_ENSURE_SUCCESS(rv, rv);
nsDependentString name(aWindowTarget);
// Only _self, _parent, and _top are supported in noopener case. But we
// have to be careful to not apply that to the noreferrer case. See bug
// 1358469.
bool allowNamedTarget = !(aFlags & INTERNAL_LOAD_FLAGS_NO_OPENER) ||
(aFlags & INTERNAL_LOAD_FLAGS_DONT_SEND_REFERRER);
if (allowNamedTarget ||
name.LowerCaseEqualsLiteral("_self") ||
name.LowerCaseEqualsLiteral("_parent") ||
name.LowerCaseEqualsLiteral("_top")) {
rv = FindItemWithName(aWindowTarget, nullptr, this,
getter_AddRefs(targetItem));
NS_ENSURE_SUCCESS(rv, rv);
}
targetDocShell = do_QueryInterface(targetItem);
// If the targetDocShell doesn't exist, then this is a new docShell
@@ -9737,11 +9748,60 @@ nsDocShell::InternalLoad(nsIURI* aURI,
NS_ENSURE_TRUE(win, NS_ERROR_NOT_AVAILABLE);
nsDependentString name(aWindowTarget);
nsCOMPtr<nsIDOMWindow> newWin;
nsAutoCString spec;
if (aURI) {
aURI->GetSpec(spec);
}
// If we are a noopener load, we just hand the whole thing over to our
// window.
if (aFlags & INTERNAL_LOAD_FLAGS_NO_OPENER) {
// Various asserts that we know to hold because NO_OPENER loads can only
// happen for links.
MOZ_ASSERT(!aLoadReplace);
/* MOZ_ASSERT(aPrincipalToInherit == aTriggeringPrincipal); */
MOZ_ASSERT(aFlags == INTERNAL_LOAD_FLAGS_NO_OPENER ||
aFlags == (INTERNAL_LOAD_FLAGS_NO_OPENER |
INTERNAL_LOAD_FLAGS_DONT_SEND_REFERRER));
MOZ_ASSERT(!aPostData);
MOZ_ASSERT(!aHeadersData);
MOZ_ASSERT(aLoadType == LOAD_LINK);
MOZ_ASSERT(!aSHEntry);
MOZ_ASSERT(aFirstParty); // Windowwatcher will assume this.
nsCOMPtr<nsIDocShellLoadInfo> loadInfo;
rv = CreateLoadInfo(getter_AddRefs(loadInfo));
if (NS_FAILED(rv)) {
return rv;
}
// Set up our loadinfo so it will do the load as much like we would have
// as possible.
loadInfo->SetReferrer(aReferrer);
loadInfo->SetReferrerPolicy(aReferrerPolicy);
loadInfo->SetSendReferrer(!(aFlags &
INTERNAL_LOAD_FLAGS_DONT_SEND_REFERRER));
loadInfo->SetOriginalURI(aOriginalURI);
loadInfo->SetLoadReplace(aLoadReplace);
loadInfo->SetOwner(loadingPrincipal); // SetTriggeringPrincipal
loadInfo->SetInheritOwner( /* SetInheritPrincipal _INHERIT_PRINCIPAL */
!!(aFlags & INTERNAL_LOAD_FLAGS_INHERIT_OWNER));
// Explicit principal because we do not want any guesses as to what the
// principal to inherit is: it should be aTriggeringPrincipal.
loadInfo->SetOwnerIsExplicit(true); // SetPrincipalIsExplicit(true);
loadInfo->SetLoadType(ConvertLoadTypeToDocShellLoadInfo(LOAD_LINK));
nsCOMPtr<nsPIDOMWindow> newWin;
rv = win->Open(NS_ConvertUTF8toUTF16(spec),
name, // window name
EmptyString(), // Features
loadInfo,
true, // aForceNoOpener
getter_AddRefs(newWin));
MOZ_ASSERT(!newWin);
return rv;
}
nsCOMPtr<nsIDOMWindow> newWin;
rv = win->OpenNoNavigate(NS_ConvertUTF8toUTF16(spec),
name, // window name
EmptyString(), // Features
@@ -9756,11 +9816,6 @@ nsDocShell::InternalLoad(nsIURI* aURI,
if (!newDoc || newDoc->IsInitialDocument()) {
isNewWindow = true;
aFlags |= INTERNAL_LOAD_FLAGS_FIRST_LOAD;
// set opener object to null for noreferrer
if (aFlags & INTERNAL_LOAD_FLAGS_NO_OPENER) {
piNewWin->SetOpenerWindow(nullptr, false);
}
}
}
@@ -13497,11 +13552,16 @@ nsDocShell::OnLinkClickSync(nsIContent* aContent,
aContent->GetAttr(kNameSpaceID_None, nsGkAtoms::rel, referrer);
nsWhitespaceTokenizerTemplate<nsContentUtils::IsHTMLWhitespace> tok(referrer);
while (tok.hasMoreTokens()) {
if (tok.nextToken().LowerCaseEqualsLiteral("noreferrer")) {
const nsAString& token = tok.nextToken();
if (token.LowerCaseEqualsLiteral("noreferrer")) {
flags |= INTERNAL_LOAD_FLAGS_DONT_SEND_REFERRER |
INTERNAL_LOAD_FLAGS_NO_OPENER;
// We now have all the flags we could possibly have, so just stop.
break;
}
if (token.LowerCaseEqualsLiteral("noopener")) {
flags |= INTERNAL_LOAD_FLAGS_NO_OPENER;
}
}
}
+84 -43
View File
@@ -51,6 +51,7 @@
#include "nsJSUtils.h"
#include "jsapi.h" // for JSAutoRequest
#include "jswrapper.h"
#include "nsCharSeparatedTokenizer.h"
#include "nsReadableUtils.h"
#include "nsDOMClassInfo.h"
#include "nsJSEnvironment.h"
@@ -1487,9 +1488,20 @@ void
nsGlobalWindow::MaybeForgiveSpamCount()
{
if (IsOuterWindow() &&
IsPopupSpamWindow())
{
SetPopupSpamWindow(false);
IsPopupSpamWindow()) {
SetIsPopupSpamWindow(false);
}
}
void
nsGlobalWindow::SetIsPopupSpamWindow(bool aIsPopupSpam)
{
MOZ_ASSERT(IsOuterWindow());
mIsPopupSpam = aIsPopupSpam;
if (aIsPopupSpam) {
++gOpenPopupSpamCount;
} else {
--gOpenPopupSpamCount;
NS_ASSERTION(gOpenPopupSpamCount >= 0,
"Unbalanced decrement of gOpenPopupSpamCount");
@@ -5722,11 +5734,18 @@ GetCallerDocShellTreeItem()
bool
nsGlobalWindow::WindowExists(const nsAString& aName,
bool aForceNoOpener,
bool aLookForCallerOnJSStack)
{
NS_PRECONDITION(IsOuterWindow(), "Must be outer window");
NS_PRECONDITION(mDocShell, "Must have docshell");
if (aForceNoOpener) {
return aName.LowerCaseEqualsLiteral("_self") ||
aName.LowerCaseEqualsLiteral("_top") ||
aName.LowerCaseEqualsLiteral("_parent");
}
nsCOMPtr<nsIDocShellTreeItem> caller;
if (aLookForCallerOnJSStack) {
caller = GetCallerDocShellTreeItem();
@@ -7536,14 +7555,6 @@ nsGlobalWindow::FirePopupBlockedEvent(nsIDocument* aDoc,
aDoc->DispatchEvent(event, &defaultActionEnabled);
}
static void FirePopupWindowEvent(nsIDocument* aDoc)
{
// Fire a "PopupWindow" event
nsContentUtils::DispatchTrustedEvent(aDoc, aDoc,
NS_LITERAL_STRING("PopupWindow"),
true, true);
}
// static
bool
nsGlobalWindow::CanSetProperty(const char *aPrefName)
@@ -7612,13 +7623,9 @@ nsGlobalWindow::RevisePopupAbuseLevel(PopupControlState aControl)
return abuse;
}
/* If a window open is blocked, fire the appropriate DOM events.
aBlocked signifies we just blocked a popup.
aWindow signifies we just opened what is probably a popup.
*/
/* If a window open is blocked, fire the appropriate DOM events. */
void
nsGlobalWindow::FireAbuseEvents(bool aBlocked, bool aWindow,
const nsAString &aPopupURL,
nsGlobalWindow::FireAbuseEvents(const nsAString &aPopupURL,
const nsAString &aPopupWindowName,
const nsAString &aPopupWindowFeatures)
{
@@ -7649,13 +7656,8 @@ nsGlobalWindow::FireAbuseEvents(bool aBlocked, bool aWindow,
ios->NewURI(NS_ConvertUTF16toUTF8(aPopupURL), 0, baseURL,
getter_AddRefs(popupURI));
// fire an event chock full of informative URIs
if (aBlocked) {
FirePopupBlockedEvent(topDoc, popupURI, aPopupWindowName,
aPopupWindowFeatures);
}
if (aWindow)
FirePopupWindowEvent(topDoc);
FirePopupBlockedEvent(topDoc, popupURI, aPopupWindowName,
aPopupWindowFeatures);
}
already_AddRefed<nsIDOMWindow>
@@ -7679,9 +7681,11 @@ nsGlobalWindow::Open(const nsAString& aUrl, const nsAString& aName,
nsresult
nsGlobalWindow::Open(const nsAString& aUrl, const nsAString& aName,
const nsAString& aOptions, nsPIDOMWindow **_retval)
const nsAString& aOptions, nsIDocShellLoadInfo* aLoadInfo,
bool aForceNoOpener, nsPIDOMWindow **_retval)
{
FORWARD_TO_OUTER(Open, (aUrl, aName, aOptions, _retval),
FORWARD_TO_OUTER(Open, (aUrl, aName, aOptions, aLoadInfo, aForceNoOpener,
_retval),
NS_ERROR_NOT_INITIALIZED);
nsCOMPtr<nsIDOMWindow> window;
nsresult rv = OpenInternal(aUrl, aName, aOptions,
@@ -7691,6 +7695,8 @@ nsGlobalWindow::Open(const nsAString& aUrl, const nsAString& aName,
false, // aDoJSFixups
true, // aNavigate
nullptr, nullptr, // No args
aLoadInfo,
aForceNoOpener,
GetPrincipal(), // aCalleePrincipal
nullptr, // aJSCallerContext
getter_AddRefs(window));
@@ -7712,6 +7718,8 @@ nsGlobalWindow::OpenJS(const nsAString& aUrl, const nsAString& aName,
true, // aDoJSFixups
true, // aNavigate
nullptr, nullptr, // No args
nullptr, // aLoadInfo
false, // aForceNoOpener
GetPrincipal(), // aCalleePrincipal
nsContentUtils::GetCurrentJSContext(), // aJSCallerContext
_retval);
@@ -7732,6 +7740,8 @@ nsGlobalWindow::OpenDialog(const nsAString& aUrl, const nsAString& aName,
false, // aDoJSFixups
true, // aNavigate
nullptr, aExtraArgument, // Arguments
nullptr, // aLoadInfo
false, // aForceNoOpener
GetPrincipal(), // aCalleePrincipal
nullptr, // aJSCallerContext
_retval);
@@ -7752,6 +7762,8 @@ nsGlobalWindow::OpenNoNavigate(const nsAString& aUrl,
false, // aDoJSFixups
false, // aNavigate
nullptr, nullptr, // No args
nullptr, // aLoadInfo
false, // aForceNoOpener
GetPrincipal(), // aCalleePrincipal
nullptr, // aJSCallerContext
_retval);
@@ -7782,6 +7794,8 @@ nsGlobalWindow::OpenDialogOuter(JSContext* aCx, const nsAString& aUrl,
false, // aDoJSFixups
true, // aNavigate
argvArray, nullptr, // Arguments
nullptr, // aLoadInfo
false, // aForceNoOpener
GetPrincipal(), // aCalleePrincipal
aCx, // aJSCallerContext
getter_AddRefs(dialog));
@@ -8862,6 +8876,8 @@ nsGlobalWindow::ShowModalDialogOuter(const nsAString& aUrl, nsIVariant* aArgumen
true, // aDoJSFixups
true, // aNavigate
nullptr, argHolder, // args
nullptr, // aLoadInfo
false, // aForceNoOpener
GetPrincipal(), // aCalleePrincipal
nullptr, // aJSCallerContext
getter_AddRefs(dlgWin));
@@ -11296,6 +11312,8 @@ nsGlobalWindow::OpenInternal(const nsAString& aUrl, const nsAString& aName,
bool aDoJSFixups, bool aNavigate,
nsIArray *argv,
nsISupports *aExtraArgument,
nsIDocShellLoadInfo* aLoadInfo,
bool aForceNoOpener,
nsIPrincipal *aCalleePrincipal,
JSContext *aJSCallerContext,
nsIDOMWindow **aReturn)
@@ -11337,8 +11355,32 @@ nsGlobalWindow::OpenInternal(const nsAString& aUrl, const nsAString& aName,
nsIPrincipal::APP_STATUS_INSTALLED;
}
nsAutoCString options;
bool forceNoOpener = aForceNoOpener;
// Unlike other window flags, "noopener" comes from splitting on commas with
// HTML whitespace trimming...
nsCharSeparatedTokenizerTemplate<nsContentUtils::IsHTMLWhitespace> tok(
aOptions, ',');
while (tok.hasMoreTokens()) {
auto nextTok = tok.nextToken();
if (nextTok.EqualsLiteral("noopener")) {
forceNoOpener = true;
continue;
}
// Want to create a copy of the options without 'noopener' because having
// 'noopener' in the options affects other window features.
if (!options.IsEmpty()) {
options.Append(',');
}
AppendUTF16toUTF8(nextTok, options);
}
// XXXbz When this gets fixed to not use LegacyIsCallerNativeCode()
// (indirectly) maybe we can nix the AutoJSAPI usage OnLinkClickEvent::Run.
// But note that if you change this to GetEntryGlobal(), say, then
// OnLinkClickEvent::Run will need a full-blown AutoEntryScript.
const bool checkForPopup = !nsContentUtils::LegacyIsCallerChromeOrNativeCode() &&
!isApp && !aDialog && !WindowExists(aName, !aCalledNoScript);
!isApp && !aDialog && !WindowExists(aName, forceNoOpener, !aCalledNoScript);
// Note: it's very important that this be an nsXPIDLCString, since we want
// .get() on it to return nullptr until we write stuff to it. The window
@@ -11381,7 +11423,7 @@ nsGlobalWindow::OpenInternal(const nsAString& aUrl, const nsAString& aName,
}
}
FireAbuseEvents(true, false, aUrl, aName, aOptions);
FireAbuseEvents(aUrl, aName, aOptions);
return aDoJSFixups ? NS_OK : NS_ERROR_FAILURE;
}
}
@@ -11392,15 +11434,21 @@ nsGlobalWindow::OpenInternal(const nsAString& aUrl, const nsAString& aName,
do_GetService(NS_WINDOWWATCHER_CONTRACTID, &rv);
NS_ENSURE_TRUE(wwatch, rv);
NS_ConvertUTF16toUTF8 options(aOptions);
NS_ConvertUTF16toUTF8 name(aName);
const char *options_ptr = aOptions.IsEmpty() ? nullptr : options.get();
const char *options_ptr = options.IsEmpty() ? nullptr : options.get();
const char *name_ptr = aName.IsEmpty() ? nullptr : name.get();
nsCOMPtr<nsPIWindowWatcher> pwwatch(do_QueryInterface(wwatch));
NS_ENSURE_STATE(pwwatch);
MOZ_ASSERT_IF(checkForPopup, abuseLevel < openAbused);
// At this point we should know for a fact that if checkForPopup then
// abuseLevel < openAbused, so we could just check for abuseLevel ==
// openControlled. But let's be defensive just in case and treat anything
// that fails the above assert as a spam popup too, if it ever happens.
bool isPopupSpamWindow = checkForPopup && (abuseLevel >= openControlled);
{
// Reset popup state while opening a window to prevent the
// current state from being active the whole time a modal
@@ -11413,6 +11461,9 @@ nsGlobalWindow::OpenInternal(const nsAString& aUrl, const nsAString& aName,
rv = pwwatch->OpenWindow2(this, url.get(), name_ptr, options_ptr,
/* aCalledFromScript = */ true,
aDialog, aNavigate, nullptr, argv,
isPopupSpamWindow,
forceNoOpener,
aLoadInfo,
getter_AddRefs(domReturn));
} else {
// Force a system caller here so that the window watcher won't screw us
@@ -11429,10 +11480,12 @@ nsGlobalWindow::OpenInternal(const nsAString& aUrl, const nsAString& aName,
nojsapi.emplace();
}
rv = pwwatch->OpenWindow2(this, url.get(), name_ptr, options_ptr,
/* aCalledFromScript = */ false,
aDialog, aNavigate, nullptr, aExtraArgument,
isPopupSpamWindow,
forceNoOpener,
aLoadInfo,
getter_AddRefs(domReturn));
}
@@ -11467,18 +11520,6 @@ nsGlobalWindow::OpenInternal(const nsAString& aUrl, const nsAString& aName,
}
}
if (checkForPopup) {
if (abuseLevel >= openControlled) {
nsGlobalWindow *opened = static_cast<nsGlobalWindow *>(*aReturn);
if (!opened->IsPopupSpamWindow()) {
opened->SetPopupSpamWindow(true);
++gOpenPopupSpamCount;
}
}
if (abuseLevel >= openAbused)
FireAbuseEvents(false, true, aUrl, aName, aOptions);
}
return rv;
}
+23 -18
View File
@@ -901,7 +901,10 @@ public:
const nsAString& aOptions,
mozilla::ErrorResult& aError);
nsresult Open(const nsAString& aUrl, const nsAString& aName,
const nsAString& aOptions, nsPIDOMWindow **_retval) override;
const nsAString& aOptions,
nsIDocShellLoadInfo* aLoadInfo,
bool aForceNoOpener,
nsPIDOMWindow **_retval) override;
mozilla::dom::Navigator* GetNavigator(mozilla::ErrorResult& aError);
nsIDOMNavigator* GetNavigator() override;
nsIDOMOfflineResourceList* GetApplicationCache(mozilla::ErrorResult& aError);
@@ -1321,6 +1324,7 @@ protected:
// Get the parent, returns null if this is a toplevel window
nsIDOMWindow* GetParentInternal();
public:
// popup tracking
bool IsPopupSpamWindow()
{
@@ -1331,17 +1335,10 @@ protected:
return GetOuterWindowInternal()->mIsPopupSpam;
}
void SetPopupSpamWindow(bool aPopup)
{
if (IsInnerWindow() && !mOuterWindow) {
NS_ERROR("SetPopupSpamWindow() called on inner window w/o an outer!");
return;
}
GetOuterWindowInternal()->mIsPopupSpam = aPopup;
}
// Outer windows only.
void SetIsPopupSpamWindow(bool aIsPopupSpam);
protected:
// Window Control Functions
// Outer windows only.
@@ -1386,15 +1383,21 @@ private:
* three args, if present, will be aUrl, aName, and aOptions. So this
* param only matters if there are more than 3 arguments.
*
* @param argc The number of arguments in argv.
*
* @param aExtraArgument Another way to pass arguments in. This is mutually
* exclusive with the argv/argc approach.
* exclusive with the argv approach.
*
* @param aLoadInfo to be passed on along to the windowwatcher.
*
* @param aForceNoOpener if true, will act as if "noopener" were passed in
* aOptions, but without affecting any other window
* features.
*
* @param aJSCallerContext The calling script's context. This must be null
* when aCalledNoScript is true.
*
* @param aReturn [out] The window that was opened, if any.
* @param aReturn [out] The window that was opened, if any. Will be null if
* aForceNoOpener is true of if aOptions contains
* "noopener".
*
* Outer windows only.
*/
@@ -1408,6 +1411,8 @@ private:
bool aNavigate,
nsIArray *argv,
nsISupports *aExtraArgument,
nsIDocShellLoadInfo* aLoadInfo,
bool aForceNoOpener,
nsIPrincipal *aCalleePrincipal,
JSContext *aJSCallerContext,
nsIDOMWindow **aReturn);
@@ -1471,8 +1476,7 @@ public:
bool PopupWhitelisted();
PopupControlState RevisePopupAbuseLevel(PopupControlState);
void FireAbuseEvents(bool aBlocked, bool aWindow,
const nsAString &aPopupURL,
void FireAbuseEvents(const nsAString &aPopupURL,
const nsAString &aPopupWindowName,
const nsAString &aPopupWindowFeatures);
void FireOfflineStatusEventIfChanged();
@@ -1538,7 +1542,8 @@ public:
// If aLookForCallerOnJSStack is true, this method will look at the JS stack
// to determine who the caller is. If it's false, it'll use |this| as the
// caller.
bool WindowExists(const nsAString& aName, bool aLookForCallerOnJSStack);
bool WindowExists(const nsAString& aName, bool aForceNoOpener,
bool aLookForCallerOnJSStack);
already_AddRefed<nsIWidget> GetMainWidget();
nsIWidget* GetNearestWidget() const;
+4 -2
View File
@@ -1684,6 +1684,7 @@ nsJSContext::EndCycleCollectionCallback(CycleCollectorResults &aResults)
endCCTime = PR_Now();
}
#if(0)
// Log information about the CC via telemetry, JSON and the console.
Telemetry::Accumulate(Telemetry::CYCLE_COLLECTOR_FINISH_IGC, gCCStats.mAnyLockedOut);
Telemetry::Accumulate(Telemetry::CYCLE_COLLECTOR_SYNC_SKIPPABLE, gCCStats.mRanSyncForgetSkippable);
@@ -1695,10 +1696,11 @@ nsJSContext::EndCycleCollectionCallback(CycleCollectorResults &aResults)
uint32_t timeBetween = TimeBetween(sLastCCEndTime, gCCStats.mBeginTime) / 1000;
Telemetry::Accumulate(Telemetry::CYCLE_COLLECTOR_TIME_BETWEEN, timeBetween);
}
#endif
sLastCCEndTime = endCCTimeStamp;
Telemetry::Accumulate(Telemetry::FORGET_SKIPPABLE_MAX,
sMaxForgetSkippableTime / PR_USEC_PER_MSEC);
// Telemetry::Accumulate(Telemetry::FORGET_SKIPPABLE_MAX,
// sMaxForgetSkippableTime / PR_USEC_PER_MSEC);
PRTime delta = GetCollectionTimeDelta();
+8 -1
View File
@@ -22,6 +22,7 @@
#include "nsIExternalProtocolHandler.h"
#include "nsIInterfaceRequestorUtils.h"
#include "nsIObjectFrame.h"
#include "nsIOService.h"
#include "nsIPermissionManager.h"
#include "nsPluginHost.h"
#include "nsPluginInstanceOwner.h"
@@ -2525,7 +2526,13 @@ nsObjectLoadingContent::OpenChannel()
true, // aInheritForAboutBlank
false); // aForceInherit
nsSecurityFlags securityFlags = nsILoadInfo::SEC_NORMAL;
if (inherit) {
bool isData;
bool isURIUniqueOrigin = nsIOService::IsDataURIUniqueOpaqueOrigin() &&
NS_SUCCEEDED(mURI->SchemeIs("data", &isData)) &&
isData;
if (inherit && !isURIUniqueOrigin) {
securityFlags |= nsILoadInfo::SEC_FORCE_INHERIT_PRINCIPAL;
}
if (isSandBoxed) {
+8 -1
View File
@@ -25,6 +25,7 @@ class nsIArray;
class nsIContent;
class nsICSSDeclaration;
class nsIDocShell;
class nsIDocShellLoadInfo;
class nsIDocument;
class nsIIdleObserver;
class nsIScriptTimeoutHandler;
@@ -795,8 +796,14 @@ public:
virtual already_AddRefed<nsISelection> GetSelection() = 0;
virtual already_AddRefed<nsPIDOMWindow> GetOpener() = 0;
virtual already_AddRefed<nsIDOMWindowCollection> GetFrames() = 0;
// aLoadInfo will be passed on through to the windowwatcher.
// aForceNoOpener will act just like a "noopener" feature in aOptions except
// will not affect any other window features.
virtual nsresult Open(const nsAString& aUrl, const nsAString& aName,
const nsAString& aOptions, nsPIDOMWindow **_retval) = 0;
const nsAString& aOptions,
nsIDocShellLoadInfo* aLoadInfo,
bool aForceNoOpener,
nsPIDOMWindow **_retval) = 0;
virtual nsresult OpenDialog(const nsAString& aUrl, const nsAString& aName,
const nsAString& aOptions,
nsISupports* aExtraArgument, nsIDOMWindow** _retval) = 0;
+1
View File
@@ -42,6 +42,7 @@ ASSERT_NODE_FLAGS_SPACE(ELEMENT_TYPE_SPECIFIC_BITS_OFFSET + 2);
// static
const DOMTokenListSupportedToken HTMLAnchorElement::sSupportedRelValues[] = {
"noreferrer",
"noopener",
nullptr
};
+5
View File
@@ -5575,8 +5575,13 @@ ContentParent::RecvCreateWindow(PBrowserParent* aThisTab,
const char* name = aName.IsVoid() ? nullptr : NS_ConvertUTF16toUTF8(aName).get();
const char* features = aFeatures.IsVoid() ? nullptr : aFeatures.get();
#if(0)
// Needs update for issue 522
*aResult = pwwatch->OpenWindow2(parent, uri, name, features, aCalledFromJS,
false, false, thisTabParent, nullptr, getter_AddRefs(window));
#else
MOZ_ASSERT(0);
#endif
if (NS_WARN_IF(NS_FAILED(*aResult))) {
return true;
+1
View File
@@ -1327,6 +1327,7 @@ static bool
NPObjWrapper_SetProperty(JSContext *cx, JS::Handle<JSObject*> obj, JS::Handle<jsid> id,
JS::MutableHandle<JS::Value> vp, JS::ObjectOpResult &result)
{
MOZ_ASSERT(false, "See bug 1114580, 2f9eb93beee9"); // NYI XXX TenFourFox 392
NPObject *npobj = GetNPObject(cx, obj);
if (!npobj || !npobj->_class || !npobj->_class->hasProperty ||
+7
View File
@@ -608,6 +608,13 @@ private:
nullptr,
nullptr,
false, false, true, nullptr, nullptr,
// Not a spammy popup; we got permission, we swear!
/* aIsPopupSpam = */ false,
// Don't force noopener. We're not passing in an
// opener anyway, and we _do_ want the returned
// window.
/* aForceNoOpener = */ false,
/* aLoadInfo = */ nullptr,
getter_AddRefs(newWindow));
nsCOMPtr<nsPIDOMWindow> pwindow = do_QueryInterface(newWindow);
pwindow.forget(aWindow);
@@ -16,8 +16,9 @@ interface nsIWebBrowserChrome;
interface nsIDocShellTreeItem;
interface nsIArray;
interface nsITabParent;
interface nsIDocShellLoadInfo;
[uuid(0f2d9d75-c46b-4114-802e-83b4655e61d2)]
[uuid(0f2d9d75-c46b-4114-802e-83b4655e61d3)]
interface nsPIWindowWatcher : nsISupports
{
@@ -56,6 +57,18 @@ interface nsPIWindowWatcher : nsISupports
nsITabParent is a remote tab belonging to aParent. Can
be nullptr if this window is not being opened from a tab.
@param aArgs Window argument
@param aIsPopupSpam true if the window is a popup spam window; used for
popup blocker internals.
@param aForceNoOpener If true, force noopener behavior. This means not
looking for existing windows with the given name,
not setting an opener on the newly opened window,
and returning null from this method.
@param aLoadInfo if aNavigate is true, this allows the caller to pass in
an nsIDocShellLoadInfo to use for the navigation.
Callers can pass in null if they want the windowwatcher
to just construct a loadinfo itself. If aNavigate is
false, this argument is ignored.
@return the new window
@note This method may examine the JS context stack for purposes of
@@ -70,7 +83,10 @@ interface nsPIWindowWatcher : nsISupports
in string aName, in string aFeatures,
in boolean aCalledFromScript, in boolean aDialog,
in boolean aNavigate, in nsITabParent aOpeningTab,
in nsISupports aArgs);
in nsISupports aArgs,
in boolean aIsPopupSpam,
in boolean aForceNoOpener,
in nsIDocShellLoadInfo aLoadInfo);
/**
* Find a named docshell tree item amongst all windows registered
@@ -18,6 +18,7 @@
#include "nsJSUtils.h"
#include "plstr.h"
#include "nsGlobalWindow.h"
#include "nsIBaseWindow.h"
#include "nsIBrowserDOMWindow.h"
#include "nsIDocShell.h"
@@ -366,7 +367,11 @@ nsWindowWatcher::OpenWindow(nsIDOMWindow* aParent,
return OpenWindowInternal(aParent, aUrl, aName, aFeatures,
/* calledFromJS = */ false, dialog,
/* navigate = */ true, nullptr, argv, aResult);
/* navigate = */ true, nullptr, argv,
/* aIsPopupSpam = */ false,
/* aForceNoOpener = */ false,
/* aLoadInfo = */ nullptr,
aResult);
}
struct SizeSpec
@@ -424,6 +429,9 @@ nsWindowWatcher::OpenWindow2(nsIDOMWindow* aParent,
bool aNavigate,
nsITabParent* aOpeningTab,
nsISupports* aArguments,
bool aIsPopupSpam,
bool aForceNoOpener,
nsIDocShellLoadInfo* aLoadInfo,
nsIDOMWindow** aResult)
{
nsCOMPtr<nsIArray> argv = ConvertArgsToArray(aArguments);
@@ -443,7 +451,11 @@ nsWindowWatcher::OpenWindow2(nsIDOMWindow* aParent,
return OpenWindowInternal(aParent, aUrl, aName, aFeatures,
aCalledFromScript, dialog,
aNavigate, aOpeningTab, argv, aResult);
aNavigate, aOpeningTab, argv,
aIsPopupSpam,
aForceNoOpener,
aLoadInfo,
aResult);
}
nsresult
@@ -456,6 +468,9 @@ nsWindowWatcher::OpenWindowInternal(nsIDOMWindow* aParent,
bool aNavigate,
nsITabParent* aOpeningTab,
nsIArray* aArgv,
bool aIsPopupSpam,
bool aForceNoOpener,
nsIDocShellLoadInfo* aLoadInfo,
nsIDOMWindow** aResult)
{
nsresult rv = NS_OK;
@@ -531,7 +546,8 @@ nsWindowWatcher::OpenWindowInternal(nsIDOMWindow* aParent,
// know or care about names - unless we're opening named windows from chrome.
if (!aOpeningTab) {
// try to find an extant window with the given name
nsCOMPtr<nsIDOMWindow> foundWindow = SafeGetWindowByName(name, aParent);
nsCOMPtr<nsIDOMWindow> foundWindow =
SafeGetWindowByName(name, aForceNoOpener, aParent);
GetWindowTreeItem(foundWindow, getter_AddRefs(newDocShellItem));
}
@@ -828,7 +844,8 @@ nsWindowWatcher::OpenWindowInternal(nsIDOMWindow* aParent,
}
}
rv = ReadyOpenedDocShellItem(newDocShellItem, aParent, windowIsNew, aResult);
rv = ReadyOpenedDocShellItem(newDocShellItem, aParent, windowIsNew,
aForceNoOpener, aResult);
if (NS_FAILED(rv)) {
return rv;
}
@@ -900,6 +917,16 @@ nsWindowWatcher::OpenWindowInternal(nsIDOMWindow* aParent,
// SetInitialPrincipalToSubject is safe to call multiple times.
if (newWindow) {
newWindow->SetInitialPrincipalToSubject();
if (aIsPopupSpam) {
nsGlobalWindow* globalWin = static_cast<nsGlobalWindow*>(newWindow.get());
MOZ_ASSERT(!globalWin->IsPopupSpamWindow(),
"Who marked it as popup spam already???");
if (!globalWin->IsPopupSpamWindow()) { // Make sure we don't mess up our
// counter even if the above
// assert fails.
globalWin->SetIsPopupSpamWindow(true);
}
}
}
}
@@ -944,8 +971,8 @@ nsWindowWatcher::OpenWindowInternal(nsIDOMWindow* aParent,
}
}
nsCOMPtr<nsIDocShellLoadInfo> loadInfo;
if (uriToLoad && aNavigate) {
nsCOMPtr<nsIDocShellLoadInfo> loadInfo = aLoadInfo;
if (uriToLoad && aNavigate && !loadInfo) {
newDocShell->CreateLoadInfo(getter_AddRefs(loadInfo));
NS_ENSURE_TRUE(loadInfo, NS_ERROR_FAILURE);
@@ -1066,6 +1093,10 @@ nsWindowWatcher::OpenWindowInternal(nsIDOMWindow* aParent,
}
}
if (aForceNoOpener && windowIsNew) {
NS_RELEASE(*aResult);
}
return NS_OK;
}
@@ -1854,8 +1885,18 @@ nsWindowWatcher::GetCallerTreeItem(nsIDocShellTreeItem* aParentItem)
nsPIDOMWindow*
nsWindowWatcher::SafeGetWindowByName(const nsAString& aName,
bool aForceNoOpener,
nsIDOMWindow* aCurrentWindow)
{
if (aForceNoOpener) {
if (!aName.LowerCaseEqualsLiteral("_self") &&
!aName.LowerCaseEqualsLiteral("_top") &&
!aName.LowerCaseEqualsLiteral("_parent")) {
// Ignore all other names in the noopener case.
return nullptr;
}
}
nsCOMPtr<nsIDocShellTreeItem> startItem;
GetWindowTreeItem(aCurrentWindow, getter_AddRefs(startItem));
@@ -1884,6 +1925,7 @@ nsresult
nsWindowWatcher::ReadyOpenedDocShellItem(nsIDocShellTreeItem* aOpenedItem,
nsIDOMWindow* aParent,
bool aWindowIsNew,
bool aForceNoOpener,
nsIDOMWindow** aOpenedWindow)
{
nsresult rv = NS_ERROR_FAILURE;
@@ -1894,7 +1936,9 @@ nsWindowWatcher::ReadyOpenedDocShellItem(nsIDocShellTreeItem* aOpenedItem,
nsCOMPtr<nsPIDOMWindow> piOpenedWindow = aOpenedItem->GetWindow();
if (piOpenedWindow) {
if (aParent) {
piOpenedWindow->SetOpenerWindow(aParent, aWindowIsNew); // damnit
if (!aForceNoOpener) {
piOpenedWindow->SetOpenerWindow(aParent, aWindowIsNew); // damnit
}
if (aWindowIsNew) {
#ifdef DEBUG
@@ -70,7 +70,9 @@ protected:
// Unlike GetWindowByName this will look for a caller on the JS
// stack, and then fall back on aCurrentWindow if it can't find one.
// It also knows to not look for things if aForceNoOpener is set.
nsPIDOMWindow* SafeGetWindowByName(const nsAString& aName,
bool aForceNoOpener,
nsIDOMWindow* aCurrentWindow);
// Just like OpenWindowJS, but knows whether it got called via OpenWindowJS
@@ -84,6 +86,9 @@ protected:
bool aNavigate,
nsITabParent* aOpeningTab,
nsIArray* aArgv,
bool aIsPopupSpam,
bool aForceNoOpener,
nsIDocShellLoadInfo* aLoadInfo,
nsIDOMWindow** aResult);
static nsresult URIfromURL(const char* aURL,
@@ -105,6 +110,7 @@ protected:
static nsresult ReadyOpenedDocShellItem(nsIDocShellTreeItem* aOpenedItem,
nsIDOMWindow* aParent,
bool aWindowIsNew,
bool aForceNoOpener,
nsIDOMWindow** aOpenedWindow);
static void SizeOpenedDocShellItem(nsIDocShellTreeItem* aDocShellItem,
nsIDOMWindow* aParent,
@@ -164,7 +164,7 @@ NS_IMETHODIMP mozEnglishWordUtils::FindNextWord(const char16_t *word, uint32_t l
// before we spend more time looking to see if the word is a url, look for a url identifer
// and make sure that identifer isn't the last character in the word fragment.
if ( (*p == ':' || *p == '@' || *p == '.') && p < endbuf - 1) {
if ((p < endbuf - 1) && (*p == ':' || *p == '@' || *p == '.')) {
// ok, we have a possible url...do more research to find out if we really have one
// and determine the length of the url so we can skip over it.
+4
View File
@@ -847,6 +847,10 @@ enum ESClassValue {
ESClass_Boolean, ESClass_RegExp, ESClass_ArrayBuffer, ESClass_SharedArrayBuffer,
ESClass_Date, ESClass_Set, ESClass_Map,
/** Not yet implemented (TenFourFox issue 392). */
ESClass_Promise, ESClass_MapIterator, ESClass_SetIterator,
ESClass_Arguments, ESClass_Error,
/** None of the above. */
ESClass_Other
};
+1
View File
@@ -732,6 +732,7 @@ function ArrayValuesAt(n) {
function ArrayValues() {
return CreateArrayIterator(this, ITEM_KIND_VALUE);
}
_SetCanonicalName(ArrayValues, "values");
function ArrayEntries() {
return CreateArrayIterator(this, ITEM_KIND_KEY_AND_VALUE);
+1
View File
@@ -88,6 +88,7 @@ function LegacyGeneratorNext(val) {
throw e;
}
}
_SetCanonicalName(LegacyGeneratorNext, "next");
function LegacyGeneratorThrow(val) {
if (!IsObject(this) || !IsLegacyGeneratorObject(this))
+15 -15
View File
@@ -100,8 +100,8 @@ function removeUnicodeExtensions(locale) {
if (pos < 0)
pos = locale.length;
var left = callFunction(std_String_substring, locale, 0, pos);
var right = callFunction(std_String_substring, locale, pos);
var left = callFunction(String_substring, locale, 0, pos);
var right = callFunction(String_substring, locale, pos);
var extensions;
var unicodeLocaleExtensionSequenceRE = getUnicodeLocaleExtensionSequenceRE();
@@ -332,7 +332,7 @@ function IsStructurallyValidLanguageTag(locale) {
return true;
var pos = callFunction(std_String_indexOf, locale, "-x-");
if (pos !== -1)
locale = callFunction(std_String_substring, locale, 0, pos);
locale = callFunction(String_substring, locale, 0, pos);
// Check for duplicate variant or singleton subtags.
var duplicateVariantRE = getDuplicateVariantRE();
@@ -401,7 +401,7 @@ function CanonicalizeLanguageTag(locale) {
// 4-character subtags are script codes; their first character
// needs to be capitalized. "hans" -> "Hans"
subtag = callFunction(std_String_toUpperCase, subtag[0]) +
callFunction(std_String_substring, subtag, 1);
callFunction(String_substring, subtag, 1);
} else if (i !== 0 && subtag.length === 2) {
// 2-character subtags that are not in initial position are region
// codes; they need to be upper case. "bu" -> "BU"
@@ -678,7 +678,7 @@ function CanonicalizeLocaleList(locales) {
if (!IsStructurallyValidLanguageTag(tag))
ThrowRangeError(JSMSG_INVALID_LANGUAGE_TAG, tag);
tag = CanonicalizeLanguageTag(tag);
if (callFunction(std_Array_indexOf, seen, tag) === -1)
if (callFunction(ArrayIndexOf, seen, tag) === -1)
callFunction(std_Array_push, seen, tag);
}
k++;
@@ -726,7 +726,7 @@ function BestAvailableLocaleHelper(availableLocales, locale, considerDefaultLoca
if (pos >= 2 && candidate[pos - 2] === "-")
pos -= 2;
candidate = callFunction(std_String_substring, candidate, 0, pos);
candidate = callFunction(String_substring, candidate, 0, pos);
}
}
@@ -879,7 +879,7 @@ function ResolveLocale(availableLocales, requestedLocales, options, relevantExte
// Step 11.g.
if (extensionSubtags !== undefined) {
// Step 11.g.i.
var keyPos = callFunction(std_Array_indexOf, extensionSubtags, key);
var keyPos = callFunction(ArrayIndexOf, extensionSubtags, key);
// Step 11.g.ii.
if (keyPos !== -1) {
@@ -891,7 +891,7 @@ function ResolveLocale(availableLocales, requestedLocales, options, relevantExte
var requestedValue = extensionSubtags[keyPos + 1];
// Step 11.g.ii.1.b.
valuePos = callFunction(std_Array_indexOf, keyLocaleData, requestedValue);
valuePos = callFunction(ArrayIndexOf, keyLocaleData, requestedValue);
// Step 11.g.ii.1.c.
if (valuePos !== -1) {
@@ -905,7 +905,7 @@ function ResolveLocale(availableLocales, requestedLocales, options, relevantExte
// and true is an allowed value, it's used.
// Step 11.g.ii.2.a.
valuePos = callFunction(std_Array_indexOf, keyLocaleData, "true");
valuePos = callFunction(ArrayIndexOf, keyLocaleData, "true");
// Step 11.g.ii.2.b.
if (valuePos !== -1)
@@ -921,7 +921,7 @@ function ResolveLocale(availableLocales, requestedLocales, options, relevantExte
// Step 11.h, 11.h.ii.
if (optionsValue !== undefined &&
callFunction(std_Array_indexOf, keyLocaleData, optionsValue) !== -1)
callFunction(ArrayIndexOf, keyLocaleData, optionsValue) !== -1)
{
// Step 11.h.ii.1.
if (optionsValue !== value) {
@@ -938,8 +938,8 @@ function ResolveLocale(availableLocales, requestedLocales, options, relevantExte
// Step 12.
if (supportedExtension.length > 2) {
var preExtension = callFunction(std_String_substring, foundLocale, 0, extensionIndex);
var postExtension = callFunction(std_String_substring, foundLocale, extensionIndex);
var preExtension = callFunction(String_substring, foundLocale, 0, extensionIndex);
var postExtension = callFunction(String_substring, foundLocale, extensionIndex);
foundLocale = preExtension + supportedExtension + postExtension;
}
@@ -1060,7 +1060,7 @@ function GetOption(options, property, type, values, fallback) {
assert(false, "GetOption");
// Step 2.d.
if (values !== undefined && callFunction(std_Array_indexOf, values, value) === -1)
if (values !== undefined && callFunction(ArrayIndexOf, values, value) === -1)
ThrowRangeError(JSMSG_INVALID_OPTION_VALUE, property, value);
// Step 2.e.
@@ -2612,8 +2612,8 @@ function BasicFormatMatcher(options, formats) {
score -= removalPenalty;
} else {
// Step 11.c.vi.
var optionsPropIndex = callFunction(std_Array_indexOf, values, optionsProp);
var formatPropIndex = callFunction(std_Array_indexOf, values, formatProp);
var optionsPropIndex = callFunction(ArrayIndexOf, values, optionsProp);
var formatPropIndex = callFunction(ArrayIndexOf, values, formatProp);
var delta = std_Math_max(std_Math_min(formatPropIndex - optionsPropIndex, 2), -2);
if (delta === 2)
score -= longMorePenalty;
+2 -1
View File
@@ -25,7 +25,7 @@ function MapForEach(callbackfn, thisArg = undefined) {
/* Step 6-8. */
var entries = callFunction(std_Map_iterator, M);
while (true) {
var result = callFunction(std_Map_iterator_next, entries);
var result = callFunction(MapIteratorNext, entries);
if (result.done)
break;
var entry = result.value;
@@ -88,3 +88,4 @@ function MapSpecies() {
// Step 1.
return this;
}
_SetCanonicalName(MapSpecies, "get [Symbol.species]");
+12 -2
View File
@@ -167,7 +167,8 @@ GlobalObject::initMapIteratorProto(JSContext* cx, Handle<GlobalObject*> global)
RootedPlainObject proto(cx, NewObjectWithGivenProto<PlainObject>(cx, base));
if (!proto)
return false;
if (!JS_DefineFunctions(cx, proto, MapIteratorObject::methods))
if (!JS_DefineFunctions(cx, proto, MapIteratorObject::methods) ||
!DefineToStringTag(cx, proto, cx->names().MapIterator))
return false;
global->setReservedSlot(MAP_ITERATOR_PROTO, ObjectValue(*proto));
return true;
@@ -316,6 +317,10 @@ MapObject::initClass(JSContext* cx, JSObject* obj)
RootedId iteratorId(cx, SYMBOL_TO_JSID(cx->wellKnownSymbols().iterator));
if (!JS_DefinePropertyById(cx, proto, iteratorId, funval, 0))
return nullptr;
// Define Map.prototype[@@toStringTag].
if (!DefineToStringTag(cx, proto, cx->names().Map))
return nullptr;
}
return proto;
}
@@ -893,7 +898,8 @@ GlobalObject::initSetIteratorProto(JSContext* cx, Handle<GlobalObject*> global)
RootedPlainObject proto(cx, NewObjectWithGivenProto<PlainObject>(cx, base));
if (!proto)
return false;
if (!JS_DefineFunctions(cx, proto, SetIteratorObject::methods))
if (!JS_DefineFunctions(cx, proto, SetIteratorObject::methods) ||
!DefineToStringTag(cx, proto, cx->names().SetIterator))
return false;
global->setReservedSlot(SET_ITERATOR_PROTO, ObjectValue(*proto));
return true;
@@ -1047,6 +1053,10 @@ SetObject::initClass(JSContext* cx, JSObject* obj)
RootedId iteratorId(cx, SYMBOL_TO_JSID(cx->wellKnownSymbols().iterator));
if (!JS_DefinePropertyById(cx, proto, iteratorId, funval, 0))
return nullptr;
// Define Set.prototype[@@toStringTag].
if (!DefineToStringTag(cx, proto, cx->names().Set))
return nullptr;
}
return proto;
}
+114 -36
View File
@@ -306,63 +306,141 @@ js::ObjectToSource(JSContext* cx, HandleObject obj)
}
#endif /* JS_HAS_TOSOURCE */
JSString*
JS_BasicObjectToString(JSContext* cx, HandleObject obj)
{
// Some classes are really common, don't allocate new strings for them.
// The ordering below is based on the measurements in bug 966264.
if (obj->is<PlainObject>())
return cx->names().objectObject;
if (obj->is<StringObject>())
return cx->names().objectString;
if (obj->is<ArrayObject>())
return cx->names().objectArray;
if (obj->is<JSFunction>())
return cx->names().objectFunction;
if (obj->is<NumberObject>())
return cx->names().objectNumber;
const char* className = GetObjectClassName(cx, obj);
if (strcmp(className, "Window") == 0)
return cx->names().objectWindow;
StringBuffer sb(cx);
if (!sb.append("[object ") || !sb.append(className, strlen(className)) ||
!sb.append("]"))
{
return nullptr;
}
return sb.finishString();
}
/* ES5 15.2.4.2. Note steps 1 and 2 are errata. */
/* ES6 19.1.3.6 (after bug 1114580/TenFourFox issue 392) */
bool
js::obj_toString(JSContext* cx, unsigned argc, Value* vp)
{
CallArgs args = CallArgsFromVp(argc, vp);
/* Step 1. */
// Step 1.
if (args.thisv().isUndefined()) {
args.rval().setString(cx->names().objectUndefined);
return true;
}
/* Step 2. */
// Step 2.
if (args.thisv().isNull()) {
args.rval().setString(cx->names().objectNull);
return true;
}
/* Step 3. */
// Step 3.
RootedObject obj(cx, ToObject(cx, args.thisv()));
if (!obj)
return false;
/* Steps 4-5. */
JSString* str = JS_BasicObjectToString(cx, obj);
// Step 4.
bool isArray;
if (!IsArray(cx, obj, &isArray))
return false;
// Step 5.
RootedString builtinTag(cx);
if (isArray) {
builtinTag = cx->names().objectArray;
} else {
// Steps 6-13.
ESClassValue cls;
if (!GetBuiltinClass(cx, obj, &cls))
return false;
switch (cls) {
case ESClass_String:
builtinTag = cx->names().objectString;
break;
case ESClass_Arguments: // NYI XXX
builtinTag = cx->names().objectArguments;
break;
case ESClass_Error: // NYI XXX
builtinTag = cx->names().objectError;
break;
case ESClass_Boolean:
builtinTag = cx->names().objectBoolean;
break;
case ESClass_Number:
builtinTag = cx->names().objectNumber;
break;
case ESClass_Date:
builtinTag = cx->names().objectDate;
break;
case ESClass_RegExp:
builtinTag = cx->names().objectRegExp;
break;
default:
if (obj->isCallable()) {
// Non-standard: Prevent <object> from showing up as Function.
RootedObject unwrapped(cx, CheckedUnwrap(obj));
if (!unwrapped || !unwrapped->getClass()->isDOMClass())
builtinTag = cx->names().objectFunction;
}
break;
}
}
// Step 14.
// Currently omitted for non-standard fallback.
// Step 15.
RootedValue tag(cx);
RootedId toStringTagId(cx, SYMBOL_TO_JSID(cx->wellKnownSymbols().toStringTag));
if (!GetProperty(cx, obj, obj, toStringTagId, &tag)) {
if (IsProxy(obj)) {
// XXX: This is a dirty hack for jit-test/tests/basic/bug807623.js.
// Just pass through if the property lookup fails; assume that we
// didn't have a tag set in that situation. Proxy::get sets the tag
// to undefined for us in that case. TenFourFox issue 392.
//
// Note that this isn't an issue for current Firefox because
// Proxy.create() was removed. We can't do this because of our
// backwards compatibility, and other tests also rely on it
// currently (see M892903), but fortunately using proper ES6 Proxy
// methods works as expected even without this hack:
//
// var h={}; var p=new Proxy({[Symbol.toStringTag]:"abc"}, h);
// print(Object.prototype.toString.call(p)); /* [object abc] */
//
// Thus, this code path is only entered in the legacy case, which
// shouldn't know about @@toStringTag anyway.
//
RootedValue receiver(cx, ObjectValue(*obj));
(void)proxy_GetProperty(cx, obj, receiver, toStringTagId, &tag);
cx->clearPendingException();
} else
return false;
}
// Step 16.
if (!tag.isString()) {
// Non-standard (bug 1277801): Use ClassName as a fallback in the interim
if (!builtinTag) {
const char* className = GetObjectClassName(cx, obj);
StringBuffer sb(cx);
if (!sb.append("[object ") || !sb.append(className, strlen(className)) ||
!sb.append("]"))
{
return false;
}
builtinTag = sb.finishString();
if (!builtinTag)
return false;
}
args.rval().setString(builtinTag);
return true;
}
// Step 17.
StringBuffer sb(cx);
if (!sb.append("[object ") || !sb.append(tag.toString()) || !sb.append("]"))
return false;
RootedString str(cx, sb.finishString());
if (!str)
return false;
args.rval().setString(str);
return true;
}
+2
View File
@@ -35,6 +35,7 @@ function RegExpFlagsGetter() {
// Step 19.
return result;
}
_SetCanonicalName(RegExpFlagsGetter, "get flags");
// ES6 draft rc1 21.2.5.14.
function RegExpToString()
@@ -53,3 +54,4 @@ function RegExpToString()
// Step 7.
return '/' + pattern + '/' + flags;
}
_SetCanonicalName(RegExpToString, "toString");
+5
View File
@@ -34,6 +34,11 @@
// stored.
#define LAZY_FUNCTION_NAME_SLOT 0
// The extended slot which contains a boolean value that indicates whether
// that the canonical name of the self-hosted builtins is set in self-hosted
// global. This slot is used only in debug build.
#define HAS_SELFHOSTED_CANONICAL_NAME_SLOT 0
// Stores the private WeakMap slot used for WeakSets
#define WEAKSET_MAP_SLOT 0
+1
View File
@@ -38,3 +38,4 @@ function SetSpecies() {
// Step 1.
return this;
}
_SetCanonicalName(SetSpecies, "get [Symbol.species]");
+3 -3
View File
@@ -277,7 +277,7 @@ function StringIteratorNext() {
}
UnsafeSetReservedSlot(this, ITERATOR_SLOT_NEXT_INDEX, index + charCount);
result.value = callFunction(std_String_substring, S, index, index + charCount);
result.value = callFunction(String_substring, S, index, index + charCount);
return result;
}
@@ -482,14 +482,14 @@ function EscapeAttributeValue(v) {
var chunkStart = 0;
for (var i = 0; i < inputLen; i++) {
if (inputStr[i] === '"') {
outputStr += callFunction(std_String_substring, inputStr, chunkStart, i) + '&quot;';
outputStr += callFunction(String_substring, inputStr, chunkStart, i) + '&quot;';
chunkStart = i + 1;
}
}
if (chunkStart === 0)
return inputStr;
if (chunkStart < inputLen)
outputStr += callFunction(std_String_substring, inputStr, chunkStart);
outputStr += callFunction(String_substring, inputStr, chunkStart);
return outputStr;
}
+1
View File
@@ -79,6 +79,7 @@ SymbolObject::initClass(JSContext* cx, HandleObject obj)
if (!LinkConstructorAndPrototype(cx, ctor, proto) ||
!DefinePropertiesAndFunctions(cx, proto, properties, methods) ||
!DefineToStringTag(cx, proto, cx->names().Symbol) ||
!DefinePropertiesAndFunctions(cx, ctor, nullptr, staticMethods) ||
!GlobalObject::initBuiltinConstructor(cx, global, JSProto_Symbol, ctor, proto))
{
+23
View File
@@ -964,6 +964,7 @@ function TypedArrayValues() {
// Step 7.
return CreateArrayIterator(O, ITEM_KIND_VALUE);
}
_SetCanonicalName(TypedArrayValues, "values");
// Proposed for ES7:
// https://github.com/tc39/Array.prototype.includes/blob/7c023c19a0/spec.md
@@ -1166,3 +1167,25 @@ function TypedArrayStaticOf(/*...items*/) {
// Step 8.
return newObj;
}
// ES 2016 draft Mar 25, 2016 22.2.2.4.
function TypedArraySpecies() {
// Step 1.
return this;
}
// ES 2017 draft June 2, 2016 22.2.3.32
function TypedArrayToStringTag() {
// Step 1.
var O = this;
// Steps 2-3.
if (!IsObject(O) || !IsTypedArray(O))
return undefined;
// Steps 4-6.
// Modified to retrieve the [[TypedArrayName]] from the constructor.
return _NameForTypedArray(O);
}
_SetCanonicalName(TypedArrayToStringTag, "get [Symbol.toStringTag]");
+3 -5
View File
@@ -36,15 +36,13 @@
// code are installed via the std_functions JSFunctionSpec[] in
// SelfHosting.cpp.
//
// The few items below here are either self-hosted or installing them under a
// std_Foo name would require ugly contortions, so they just get aliased here.
var std_Array_indexOf = ArrayIndexOf;
var std_String_substring = String_substring;
// Do not create an alias to a self-hosted builtin, otherwise it will be cloned
// twice.
//
// WeakMap is a bare constructor without properties or methods.
var std_WeakMap = WeakMap;
// StopIteration is a bare constructor without properties or methods.
var std_StopIteration = StopIteration;
var std_Map_iterator_next = MapIteratorNext;
/********** List specification type **********/
+2
View File
@@ -455,6 +455,8 @@ InitWeakMapClass(JSContext* cx, HandleObject obj, bool defineMembers)
if (defineMembers) {
if (!DefinePropertiesAndFunctions(cx, proto, nullptr, weak_map_methods))
return nullptr;
if (!DefineToStringTag(cx, proto, cx->names().WeakMap))
return nullptr;
}
if (!GlobalObject::initBuiltinConstructor(cx, global, JSProto_WeakMap, ctor, proto))
+1
View File
@@ -53,6 +53,7 @@ WeakSetObject::initClass(JSContext* cx, JSObject* obj)
if (!ctor ||
!LinkConstructorAndPrototype(cx, ctor, proto) ||
!DefinePropertiesAndFunctions(cx, proto, properties, methods) ||
!DefineToStringTag(cx, proto, cx->names().WeakSet) ||
!GlobalObject::initBuiltinConstructor(cx, global, JSProto_WeakSet, ctor, proto))
{
return nullptr;
+17 -1
View File
@@ -30,6 +30,7 @@
#include "asmjs/AsmJSValidate.h"
#include "builtin/ModuleObject.h"
#include "builtin/SelfHostingDefines.h"
#include "frontend/BytecodeCompiler.h"
#include "frontend/FoldConstants.h"
#include "frontend/ParseMaps.h"
@@ -1619,6 +1620,9 @@ Parser<ParseHandler>::newFunction(HandleAtom atom, FunctionSyntaxKind kind,
gc::AllocKind allocKind = gc::AllocKind::FUNCTION;
JSFunction::Flags flags;
#ifdef DEBUG
bool isGlobalSelfHostedBuiltin = false;
#endif
switch (kind) {
case Expression:
flags = (generatorKind == NotGenerator
@@ -1652,6 +1656,13 @@ Parser<ParseHandler>::newFunction(HandleAtom atom, FunctionSyntaxKind kind,
allocKind = gc::AllocKind::FUNCTION_EXTENDED;
break;
default:
MOZ_ASSERT(kind == Statement);
#ifdef DEBUG
if (options().selfHostingMode && !pc->sc->isFunctionBox()) {
isGlobalSelfHostedBuiltin = true;
allocKind = gc::AllocKind::FUNCTION_EXTENDED;
}
#endif
flags = (generatorKind == NotGenerator
? JSFunction::INTERPRETED_NORMAL
: JSFunction::INTERPRETED_GENERATOR);
@@ -1661,8 +1672,13 @@ Parser<ParseHandler>::newFunction(HandleAtom atom, FunctionSyntaxKind kind,
allocKind, TenuredObject);
if (!fun)
return nullptr;
if (options().selfHostingMode)
if (options().selfHostingMode) {
fun->setIsSelfHostedBuiltin();
#ifdef DEBUG
if (isGlobalSelfHostedBuiltin)
fun->setExtendedSlot(HAS_SELFHOSTED_CANONICAL_NAME_SLOT, BooleanValue(false));
#endif
}
return fun;
}
@@ -13,11 +13,7 @@ assertEq(Map.length, 0);
assertEq(Map.name, "Map");
assertEq(Object.getPrototypeOf(Map.prototype), Object.prototype);
assertEq("toStringTag" in Symbol, false,
"if this fails, congratulations! implement " +
"Map.prototype[Symbol.toStringTag] = 'Map' in SpiderMonkey and make " +
"the next test check for '[object Map]' again");
assertEq(Object.prototype.toString.call(Map.prototype), "[object Object]");
assertEq(Object.prototype.toString.call(Map.prototype), "[object Map]");
assertEq(Object.prototype.toString.call(new Map()), "[object Map]");
assertEq(Object.keys(Map.prototype).join(), "");
assertEq(Map.prototype.constructor, Map);
@@ -13,11 +13,7 @@ assertEq(Set.length, 0);
assertEq(Set.name, "Set");
assertEq(Object.getPrototypeOf(Set.prototype), Object.prototype);
assertEq("toStringTag" in Symbol, false,
"if this fails, congratulations! implement " +
"Set.prototype[Symbol.toStringTag] = 'Set' in SpiderMonkey and make " +
"the next test check for '[object Set]' again");
assertEq(Object.prototype.toString.call(Set.prototype), "[object Object]");
assertEq(Object.prototype.toString.call(Set.prototype), "[object Set]");
assertEq(Object.prototype.toString.call(new Set()), "[object Set]");
assertEq(Object.keys(Set.prototype).join(), "");
assertEq(Set.prototype.constructor, Set);
@@ -11,7 +11,7 @@ assertEq(WeakMap.length, 0);
assertEq(WeakMap.name, "WeakMap");
assertEq(Object.getPrototypeOf(WeakMap.prototype), Object.prototype);
assertEq(Object.prototype.toString.call(WeakMap.prototype), "[object Object]");
assertEq(Object.prototype.toString.call(WeakMap.prototype), "[object WeakMap]");
assertEq(Object.prototype.toString.call(new WeakMap()), "[object WeakMap]");
assertEq(Object.keys(WeakMap.prototype).join(), "");
assertEq(WeakMap.prototype.constructor, WeakMap);
@@ -11,7 +11,7 @@ assertEq(WeakSet.length, 0);
assertEq(WeakSet.name, "WeakSet");
assertEq(Object.getPrototypeOf(WeakSet.prototype), Object.prototype);
assertEq(Object.prototype.toString.call(WeakSet.prototype), "[object Object]");
assertEq(Object.prototype.toString.call(WeakSet.prototype), "[object WeakSet]");
assertEq(Object.prototype.toString.call(new WeakSet), "[object WeakSet]");
assertEq(Object.keys(WeakSet.prototype).length, 0);
assertEq(WeakSet.prototype.constructor, WeakSet);
@@ -9,13 +9,9 @@ function test(constructor) {
var iter = new constructor()[Symbol.iterator]();
assertDeepEq(Reflect.ownKeys(iter), []);
// Iterator prototypes only have a .next property.
// At least until we support @@toStringTag.
// Iterator prototypes only have a .next and @@toStringTag property.
var proto1 = Object.getPrototypeOf(iter);
var names = Reflect.ownKeys(proto1);
names.sort();
assertDeepEq(Reflect.ownKeys(proto1), ['next']);
assertDeepEq(Reflect.ownKeys(proto1), ['next', Symbol.toStringTag]);
var desc = Object.getOwnPropertyDescriptor(proto1, 'next');
assertEq(desc.configurable, true);
+1 -1
View File
@@ -12,7 +12,7 @@ dbg.onDebuggerStatement = function (frame) {
assertEq(arr[3].class, "Date");
assertEq(arr[4].class, "Object");
assertEq(arr[5].class, "Function");
assertEq(arr[6].class, "Date");
assertEq(arr[6].class, "Object");
hits++;
};
g.f(Object.prototype, [], eval, new Date,
@@ -11,8 +11,8 @@ var p2 = r2.proxy;
assertThrowsInstanceOf(() => ({} instanceof p), TypeError);
assertThrowsInstanceOf(() => ({} instanceof p2), TypeError);
assertEq(Object.prototype.toString.call(p), "[object Object]");
assertEq(Object.prototype.toString.call(p2), "[object Function]");
assertThrowsInstanceOf(() => Object.prototype.toString.call(p), TypeError);
assertThrowsInstanceOf(() => Object.prototype.toString.call(p2), TypeError);
assertThrowsInstanceOf(() => RegExp.prototype.exec.call(p, ""), TypeError);
assertThrowsInstanceOf(() => RegExp.prototype.exec.call(p2, ""), TypeError);
+1
View File
@@ -4561,6 +4561,7 @@ GetSymbolDescription(HandleSymbol symbol);
macro(match) \
macro(species) \
macro(toPrimitive) \
macro(toStringTag) \
macro(unscopables)
enum class SymbolCode : uint32_t {
+2
View File
@@ -306,6 +306,8 @@ class JSFunction : public js::NativeObject
void initAtom(JSAtom* atom) { atom_.init(atom); }
void setAtom(JSAtom* atom) { atom_ = atom; }
JSAtom* displayAtom() const {
return atom_;
}
+6 -2
View File
@@ -1473,7 +1473,9 @@ GlobalObject::initArrayIteratorProto(JSContext* cx, Handle<GlobalObject*> global
const Class* cls = &ArrayIteratorPrototypeClass;
RootedObject proto(cx, global->createBlankPrototypeInheriting(cx, cls, iteratorProto));
if (!proto || !DefinePropertiesAndFunctions(cx, proto, nullptr, array_iterator_methods))
if (!proto ||
!DefinePropertiesAndFunctions(cx, proto, nullptr, array_iterator_methods) ||
!DefineToStringTag(cx, proto, cx->names().ArrayIterator))
return false;
global->setReservedSlot(ARRAY_ITERATOR_PROTO, ObjectValue(*proto));
@@ -1492,7 +1494,9 @@ GlobalObject::initStringIteratorProto(JSContext* cx, Handle<GlobalObject*> globa
const Class* cls = &StringIteratorPrototypeClass;
RootedObject proto(cx, global->createBlankPrototypeInheriting(cx, cls, iteratorProto));
if (!proto || !DefinePropertiesAndFunctions(cx, proto, nullptr, string_iterator_methods))
if (!proto ||
!DefinePropertiesAndFunctions(cx, proto, nullptr, string_iterator_methods) ||
!DefineToStringTag(cx, proto, cx->names().StringIterator))
return false;
global->setReservedSlot(STRING_ITERATOR_PROTO, ObjectValue(*proto));
+2
View File
@@ -1647,6 +1647,8 @@ js::InitMathClass(JSContext* cx, HandleObject obj)
return nullptr;
if (!JS_DefineConstDoubles(cx, Math, math_constants))
return nullptr;
if (!DefineToStringTag(cx, Math, cx->names().Math))
return nullptr;
obj->as<GlobalObject>().setConstructor(JSProto_Math, ObjectValue(*Math));
+3
View File
@@ -954,6 +954,9 @@ js::InitJSONClass(JSContext* cx, HandleObject obj)
if (!JS_DefineFunctions(cx, JSON, json_static_methods))
return nullptr;
if (!DefineToStringTag(cx, JSON, cx->names().JSON))
return nullptr;
global->setConstructor(JSProto_JSON, ObjectValue(*JSON));
return JSON;
+2 -5
View File
@@ -1128,12 +1128,9 @@ const char*
ScriptedDirectProxyHandler::className(JSContext* cx, HandleObject proxy) const
{
// Right now the caller is not prepared to handle failures.
RootedObject target(cx, proxy->as<ProxyObject>().target());
if (!target)
return BaseProxyHandler::className(cx, proxy);
return GetObjectClassName(cx, target);
return BaseProxyHandler::className(cx, proxy);
}
JSString*
ScriptedDirectProxyHandler::fun_toString(JSContext* cx, HandleObject proxy,
unsigned indent) const
+1 -3
View File
@@ -74,9 +74,7 @@ function TestGeneratorObjectPrototype() {
found_property_names.sort();
assertDeepEq(found_property_names, expected_property_names);
// No symbol properties, at least until we have @@toStringTag.
assertEq(Object.getOwnPropertySymbols(GeneratorObjectPrototype).length, 0);
assertDeepEq(Object.getOwnPropertySymbols(GeneratorObjectPrototype), [Symbol.toStringTag]);
}
TestGeneratorObjectPrototype();
+158
View File
@@ -0,0 +1,158 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/licenses/publicdomain/ */
// ES6 19.1.3.6 Object.prototype.toString ( )
function testToString() {
var tests = [
[undefined, "[object Undefined]"],
[null, "[object Null]"],
[[], "[object Array]"],
[new String("abc"), "[object String]"],
[(function () {return arguments;})(), "[object Arguments]"],
[(function () {"use strict"; return arguments;})(), "[object Arguments]"],
[function() {}, "[object Function]"],
[new Error("abc"), "[object Error]"],
[true, "[object Boolean]"],
[5, "[object Number]"],
[new Date(), "[object Date]"],
[/regexp/, "[object RegExp]"],
[{[Symbol.toStringTag]: "abc"}, "[object abc]"],
[Object.create(JSON), "[object JSON]"],
[Object.create(new Number), "[object Object]"],
[Object.create(new Number, {[Symbol.toStringTag]: {value: "abc"}}), "[object abc]"],
[(function() { var x = new Number(); x[Symbol.toStringTag] = "abc"; return x; })(), "[object abc]"],
[[], "[object Array]"]
];
// Testing if the values are obtained the right way.
for (let [value, expected] of tests) {
let result = Object.prototype.toString.call(value);
assertEq(result, expected);
}
}
testToString();
function testProxy() {
var count = 0;
var metaHandler = new Proxy({}, {
get(target, property, receiver) {
assertEq(property, "get");
return function(target, property, receiver) {
assertEq(property, Symbol.toStringTag);
count++;
return undefined;
}
}
});
assertEq(Object.prototype.toString.call(new Proxy({}, metaHandler)), "[object Object]")
assertEq(Object.prototype.toString.call(new Proxy(new Date, metaHandler)), "[object Object]")
assertEq(Object.prototype.toString.call(new Proxy([], metaHandler)), "[object Array]")
assertEq(Object.prototype.toString.call(new Proxy(function() {}, metaHandler)), "[object Function]")
var {proxy, revoke} = Proxy.revocable({}, metaHandler);
revoke();
assertThrowsInstanceOf(() => Object.prototype.toString.call(proxy), TypeError);
assertEq(count, 4);
}
testProxy();
// Tests the passed objects toStringTag values and ensures it's
// desc is writable: false, enumerable: false, configurable: true
function testDefault(object, expected) {
let desc = Object.getOwnPropertyDescriptor(object, Symbol.toStringTag);
assertEq(desc.value, expected);
assertEq(desc.writable, false);
assertEq(desc.enumerable, false);
assertEq(desc.configurable, true);
}
// ES6 19.4.3.5 Symbol.prototype [ @@toStringTag ]
testDefault(Symbol.prototype, "Symbol");
// ES6 20.2.1.9 Math [ @@toStringTag ]
testDefault(Math, "Math");
// ES6 21.1.5.2.2 %StringIteratorPrototype% [ @@toStringTag ]
testDefault(""[Symbol.iterator]().__proto__, "String Iterator")
// ES6 22.1.5.2.2 %ArrayIteratorPrototype% [ @@toStringTag ]
testDefault([][Symbol.iterator]().__proto__, "Array Iterator")
// ES6 22.2.3.31 get %TypedArray%.prototype [ @@toStringTag ]
function testTypedArray() {
let ta = (new Uint8Array(0)).__proto__.__proto__;
let desc = Object.getOwnPropertyDescriptor(ta, Symbol.toStringTag);
assertEq(desc.enumerable, false);
assertEq(desc.configurable, true);
assertEq(desc.set, undefined);
let get = desc.get;
assertEq(get.name, "get [Symbol.toStringTag]");
assertEq(get.call(3.14), undefined);
assertEq(get.call({}), undefined);
assertEq(get.call(ta), undefined);
let types = [
Int8Array,
Uint8Array,
Int16Array,
Uint16Array,
Int32Array,
Uint32Array,
Float32Array,
Float64Array
];
for (let type of types) {
let array = new type(0);
assertEq(get.call(array), type.name);
assertEq(Object.prototype.toString.call(array), `[object ${type.name}]`);
}
}
testTypedArray();
// ES6 23.1.3.13 Map.prototype [ @@toStringTag ]
testDefault(Map.prototype, "Map");
// ES6 23.1.5.2.2 %MapIteratorPrototype% [ @@toStringTag ]
testDefault(new Map()[Symbol.iterator]().__proto__, "Map Iterator")
// ES6 23.2.3.12 Set.prototype [ @@toStringTag ]
testDefault(Set.prototype, "Set");
// ES6 23.2.5.2.2 %SetIteratorPrototype% [ @@toStringTag ]
testDefault(new Set()[Symbol.iterator]().__proto__, "Set Iterator")
// ES6 23.3.3.6 WeakMap.prototype [ @@toStringTag ]
testDefault(WeakMap.prototype, "WeakMap");
// ES6 23.4.3.5 WeakSet.prototype [ @@toStringTag ]
testDefault(WeakSet.prototype, "WeakSet");
// ES6 24.1.4.4 ArrayBuffer.prototype [ @@toStringTag ]
testDefault(ArrayBuffer.prototype, "ArrayBuffer");
// ES6 24.2.4.21 DataView.prototype[ @@toStringTag ]
testDefault(DataView.prototype, "DataView");
// ES6 24.3.3 JSON [ @@toStringTag ]
testDefault(JSON, "JSON");
// ES6 25.2.3.3 GeneratorFunction.prototype [ @@toStringTag ]
testDefault(function* () {}.constructor.prototype, "GeneratorFunction");
// ES6 25.3.1.5 Generator.prototype [ @@toStringTag ]
testDefault(function* () {}().__proto__.__proto__, "Generator");
// ES6 25.4.5.4 Promise.prototype [ @@toStringTag ]
// Not yet implemented!
if (typeof Promise !== "undefined")
testDefault(Promise.prototype, "Promise");
// AsyncFunction.prototype [ @@toStringTag ]
// Not yet implemented!
// testDefault(async function() {}.constructor.prototype, "AsyncFunction");
reportCompare(true, true);
+2 -1
View File
@@ -82,7 +82,8 @@ if (typeof assertDeepEq === 'undefined') {
assertSameValue(ac, bc, msg);
switch (ac) {
case "[object Function]":
assertSameValue(Function_toString(a), Function_toString(b), msg);
if (typeof isProxy !== "undefined" && !isProxy(a) && !isProxy(b))
assertSameValue(Function_toString(a), Function_toString(b), msg);
}
}
+1 -1
View File
@@ -1562,7 +1562,7 @@ function test() {
assertEq(Object.prototype.toString.apply(new Float32Array(0)), "[object Float32Array]");
assertEq(Object.prototype.toString.apply(new ArrayBuffer()), "[object ArrayBuffer]");
assertEq(Object.prototype.toString.apply(new DataView(view.buffer)), "[object DataView]");
assertEq(Object.prototype.toString.apply(DataView.prototype), "[object DataViewPrototype]");
assertEq(Object.prototype.toString.apply(DataView.prototype), "[object DataView]");
// Technically the spec requires these throw a TypeError -- right now. It's
// not clear this is desirable. Once we implement @@toStringTag we can see
+3
View File
@@ -1650,6 +1650,9 @@ js::InitArrayBufferClass(JSContext* cx, HandleObject obj)
if (!JS_DefineFunctions(cx, arrayBufferProto, ArrayBufferObject::jsfuncs))
return nullptr;
if (!DefineToStringTag(cx, arrayBufferProto, cx->names().ArrayBuffer))
return nullptr;
return arrayBufferProto;
}
+19 -8
View File
@@ -18,6 +18,7 @@
macro(apply, apply, "apply") \
macro(arguments, arguments, "arguments") \
macro(as, as, "as") \
macro(ArrayIterator, ArrayIterator, "Array Iterator") \
macro(ArrayIteratorNext, ArrayIteratorNext, "ArrayIteratorNext") \
macro(ArrayType, ArrayType, "ArrayType") \
macro(ArrayValues, ArrayValues, "ArrayValues") \
@@ -99,6 +100,7 @@
macro(frame, frame, "frame") \
macro(from, from, "from") \
macro(gcCycleNumber, gcCycleNumber, "gcCycleNumber") \
macro(Generator, Generator, "Generator") \
macro(GeneratorFunction, GeneratorFunction, "GeneratorFunction") \
macro(get, get, "get") \
macro(getInternals, getInternals, "getInternals") \
@@ -139,6 +141,7 @@
macro(keys, keys, "keys") \
macro(label, label, "label") \
macro(lastIndex, lastIndex, "lastIndex") \
macro(LegacyGenerator, LegacyGenerator, "LegacyGenerator") \
macro(LegacyGeneratorCloseInternal, LegacyGeneratorCloseInternal, "LegacyGeneratorCloseInternal") \
macro(length, length, "length") \
macro(let, let, "let") \
@@ -148,6 +151,7 @@
macro(locale, locale, "locale") \
macro(lookupGetter, lookupGetter, "__lookupGetter__") \
macro(lookupSetter, lookupSetter, "__lookupSetter__") \
macro(MapIterator, MapIterator, "Map Iterator") \
macro(maximumFractionDigits, maximumFractionDigits, "maximumFractionDigits") \
macro(maximumSignificantDigits, maximumSignificantDigits, "maximumSignificantDigits") \
macro(message, message, "message") \
@@ -171,15 +175,18 @@
macro(NumberFormat, NumberFormat, "NumberFormat") \
macro(NumberFormatFormatGet, NumberFormatFormatGet, "Intl_NumberFormat_format_get") \
macro(numeric, numeric, "numeric") \
macro(objectArray, objectArray, "[object Array]") \
macro(objectFunction, objectFunction, "[object Function]") \
macro(objectNull, objectNull, "[object Null]") \
macro(objectNumber, objectNumber, "[object Number]") \
macro(objectObject, objectObject, "[object Object]") \
macro(objects, objects, "objects") \
macro(objectString, objectString, "[object String]") \
macro(objectUndefined, objectUndefined, "[object Undefined]") \
macro(objectWindow, objectWindow, "[object Window]") \
macro(objectNull, objectNull, "[object Null]") \
macro(objectArray, objectArray, "[object Array]") \
macro(objectString, objectString, "[object String]") \
macro(objectArguments, objectArguments, "[object Arguments]") \
macro(objectFunction, objectFunction, "[object Function]") \
macro(objectError, objectError, "[object Error]") \
macro(objectBoolean, objectBoolean, "[object Boolean]") \
macro(objectNumber, objectNumber, "[object Number]") \
macro(objectDate, objectDate, "[object Date]") \
macro(objectRegExp, objectRegExp, "[object RegExp]") \
macro(objects, objects, "objects") \
macro(of, of, "of") \
macro(offset, offset, "offset") \
macro(optimizedOut, optimizedOut, "optimizedOut") \
@@ -204,6 +211,7 @@
macro(scripts, scripts, "scripts") \
macro(sensitivity, sensitivity, "sensitivity") \
macro(set, set, "set") \
macro(SetIterator, SetIterator, "Set Iterator") \
macro(shape, shape, "shape") \
macro(signMask, signMask, "signMask") \
macro(size, size, "size") \
@@ -215,6 +223,7 @@
macro(static, static_, "static") \
macro(sticky, sticky, "sticky") \
macro(strings, strings, "strings") \
macro(StringIterator, StringIterator, "String Iterator") \
macro(StructType, StructType, "StructType") \
macro(style, style, "style") \
macro(super, super, "super") \
@@ -277,6 +286,7 @@
macro(match, match, "match") \
macro(species, species, "species") \
macro(toPrimitive, toPrimitive, "toPrimitive") \
macro(toStringTag, toStringTag, "toStringTag") \
macro(unscopables, unscopables, "unscopables") \
/* Same goes for the descriptions of the well-known symbols. */ \
macro(Symbol_hasInstance, Symbol_hasInstance, "Symbol.hasInstance") \
@@ -285,6 +295,7 @@
macro(Symbol_match, Symbol_match, "Symbol.match") \
macro(Symbol_species, Symbol_species, "Symbol.species") \
macro(Symbol_toPrimitive, Symbol_toPrimitive, "Symbol.toPrimitive") \
macro(Symbol_toStringTag, Symbol_toStringTag, "Symbol.toStringTag") \
macro(Symbol_unscopables, Symbol_unscopables, "Symbol.unscopables") \
/* Function names for properties named by symbols. */ \
macro(Symbol_iterator_fun, Symbol_iterator_fun, "[Symbol.iterator]") \
+11 -2
View File
@@ -282,7 +282,14 @@ GlobalObject::initLegacyGeneratorProto(JSContext* cx, Handle<GlobalObject*> glob
RootedObject proto(cx, NewSingletonObjectWithObjectPrototype(cx, global));
if (!proto || !proto->setDelegate(cx))
return false;
#if(0)
/* XXX: Stub @@toStringTag for legacy generators.
TenFourFox issue 392 */
if (!DefinePropertiesAndFunctions(cx, proto, nullptr, legacy_generator_methods) ||
!DefineToStringTag(cx, proto, cx->names().LegacyGenerator))
#else
if (!DefinePropertiesAndFunctions(cx, proto, nullptr, legacy_generator_methods))
#endif
return false;
global->setReservedSlot(LEGACY_GENERATOR_OBJECT_PROTO, ObjectValue(*proto));
@@ -304,13 +311,15 @@ GlobalObject::initStarGenerators(JSContext* cx, Handle<GlobalObject*> global)
iteratorProto));
if (!genObjectProto)
return false;
if (!DefinePropertiesAndFunctions(cx, genObjectProto, nullptr, star_generator_methods))
if (!DefinePropertiesAndFunctions(cx, genObjectProto, nullptr, star_generator_methods) ||
!DefineToStringTag(cx, genObjectProto, cx->names().Generator))
return false;
RootedObject genFunctionProto(cx, NewSingletonObjectWithFunctionPrototype(cx, global));
if (!genFunctionProto || !genFunctionProto->setDelegate(cx))
return false;
if (!LinkConstructorAndPrototype(cx, genFunctionProto, genObjectProto))
if (!LinkConstructorAndPrototype(cx, genFunctionProto, genObjectProto) ||
!DefineToStringTag(cx, genFunctionProto, cx->names().GeneratorFunction))
return false;
RootedValue function(cx, global->getConstructor(JSProto_Function));
+37 -8
View File
@@ -529,6 +529,14 @@ js::DefinePropertiesAndFunctions(JSContext* cx, HandleObject obj,
return true;
}
bool
js::DefineToStringTag(JSContext *cx, HandleObject obj, JSAtom* tag)
{
RootedId toStringTagId(cx, SYMBOL_TO_JSID(cx->wellKnownSymbols().toStringTag));
RootedValue tagString(cx, StringValue(tag));
return DefineProperty(cx, obj, toStringTagId, tagString, nullptr, nullptr, JSPROP_READONLY);
}
static void
GlobalDebuggees_finalize(FreeOp* fop, JSObject* obj)
{
@@ -658,16 +666,37 @@ GlobalObject::getSelfHostedFunction(JSContext* cx, Handle<GlobalObject*> global,
HandlePropertyName selfHostedName, HandleAtom name,
unsigned nargs, MutableHandleValue funVal)
{
if (GlobalObject::maybeGetIntrinsicValue(cx, global, selfHostedName, funVal))
return true;
if (GlobalObject::maybeGetIntrinsicValue(cx, global, selfHostedName, funVal)) {
RootedFunction fun(cx, &funVal.toObject().as<JSFunction>());
if (fun->atom() == name)
return true;
JSFunction* fun =
NewScriptedFunction(cx, nargs, JSFunction::INTERPRETED_LAZY,
name, gc::AllocKind::FUNCTION_EXTENDED, SingletonObject);
if (!fun)
if (fun->atom() == selfHostedName) {
// This function was initially cloned because it was called by
// other self-hosted code, so the clone kept its self-hosted name,
// instead of getting the name it's intended to have in content
// compartments. This can happen when a lazy builtin is initialized
// after self-hosted code for another builtin used the same
// function. In that case, we need to change the function's name,
// which is ok because it can't have been exposed to content
// before.
fun->initAtom(name);
return true;
}
// The function might be installed multiple times on the same or
// different builtins, under different property names, so its name
// might be neither "selfHostedName" nor "name". In that case, its
// canonical name must've been set using the `_SetCanonicalName`
// intrinsic.
cx->runtime()->assertSelfHostedFunctionHasCanonicalName(cx, selfHostedName);
return true;
}
RootedFunction fun(cx);
if (!cx->runtime()->createLazySelfHostedFunctionClone(cx, selfHostedName, name, nargs, &fun))
return false;
fun->setIsSelfHostedBuiltin();
fun->setExtendedSlot(LAZY_FUNCTION_NAME_SLOT, StringValue(selfHostedName));
funVal.setObject(*fun);
return GlobalObject::addIntrinsicValue(cx, global, selfHostedName, funVal);
+3
View File
@@ -905,6 +905,9 @@ DefinePropertiesAndFunctions(JSContext* cx, HandleObject obj,
typedef HashSet<GlobalObject*, DefaultHasher<GlobalObject*>, SystemAllocPolicy> GlobalObjectSet;
extern bool
DefineToStringTag(JSContext *cx, HandleObject obj, JSAtom* tag);
/*
* Convenience templates to generic constructor and prototype creation functions
* for ClassSpecs.
+8
View File
@@ -934,6 +934,10 @@ struct JSRuntime : public JS::shadow::Runtime,
static js::GlobalObject*
createSelfHostingGlobal(JSContext* cx);
bool getUnclonedSelfHostedValue(JSContext* cx, js::HandlePropertyName name,
js::MutableHandleValue vp);
JSFunction* getUnclonedSelfHostedFunction(JSContext* cx, js::HandlePropertyName name);
/* Space for interpreter frames. */
js::InterpreterStack interpreterStack_;
@@ -974,10 +978,14 @@ struct JSRuntime : public JS::shadow::Runtime,
}
bool isSelfHostingCompartment(JSCompartment* comp) const;
bool isSelfHostingZone(const JS::Zone* zone) const;
bool createLazySelfHostedFunctionClone(JSContext* cx, js::HandlePropertyName selfHostedName,
js::HandleAtom name, unsigned nargs,
js::MutableHandleFunction fun);
bool cloneSelfHostedFunctionScript(JSContext* cx, js::Handle<js::PropertyName*> name,
js::Handle<JSFunction*> targetFun);
bool cloneSelfHostedValue(JSContext* cx, js::Handle<js::PropertyName*> name,
js::MutableHandleValue vp);
void assertSelfHostedFunctionHasCanonicalName(JSContext* cx, js::HandlePropertyName name);
//-------------------------------------------------------------------------
// Locale information
+101 -9
View File
@@ -15,6 +15,7 @@
#include "jscompartment.h"
#include "jsdate.h"
#include "jsfriendapi.h"
#include "jsfun.h"
#include "jshashutil.h"
#include "jsweakmap.h"
#include "jswrapper.h"
@@ -39,6 +40,7 @@
#include "vm/String.h"
#include "vm/TypedArrayCommon.h"
#include "jsatominlines.h"
#include "jsfuninlines.h"
#include "jsscriptinlines.h"
@@ -573,6 +575,26 @@ intrinsic_ActiveFunction(JSContext* cx, unsigned argc, Value* vp)
return true;
}
static bool
intrinsic_SetCanonicalName(JSContext* cx, unsigned argc, Value* vp)
{
CallArgs args = CallArgsFromVp(argc, vp);
MOZ_ASSERT(args.length() == 2);
RootedFunction fun(cx, &args[0].toObject().as<JSFunction>());
MOZ_ASSERT(fun->isSelfHostedBuiltin());
RootedAtom atom(cx, AtomizeString(cx, args[1].toString()));
if (!atom)
return false;
fun->setAtom(atom);
#ifdef DEBUG
fun->setExtendedSlot(HAS_SELFHOSTED_CANONICAL_NAME_SLOT, BooleanValue(true));
#endif
args.rval().setUndefined();
return true;
}
static bool
intrinsic_StarGeneratorObjectIsClosed(JSContext* cx, unsigned argc, Value* vp)
{
@@ -1260,6 +1282,23 @@ intrinsic_ConstructorForTypedArray(JSContext* cx, unsigned argc, Value* vp)
return true;
}
static bool
intrinsic_NameForTypedArray(JSContext* cx, unsigned argc, Value* vp)
{
CallArgs args = CallArgsFromVp(argc, vp);
MOZ_ASSERT(args.length() == 1);
MOZ_ASSERT(args[0].isObject());
RootedObject object(cx, &args[0].toObject());
MOZ_ASSERT(object->is<TypedArrayObject>());
JSProtoKey protoKey = StandardProtoKeyOrNull(object);
MOZ_ASSERT(protoKey);
args.rval().setString(ClassName(protoKey, cx));
return true;
}
static bool
intrinsic_HostResolveImportedModule(JSContext* cx, unsigned argc, Value* vp)
{
@@ -1510,6 +1549,7 @@ static const JSFunctionSpec intrinsic_functions[] = {
JS_FN("AssertionFailed", intrinsic_AssertionFailed, 1,0),
JS_FN("MakeConstructible", intrinsic_MakeConstructible, 2,0),
JS_FN("_ConstructorForTypedArray", intrinsic_ConstructorForTypedArray, 1,0),
JS_FN("_NameForTypedArray", intrinsic_NameForTypedArray, 1,0),
JS_FN("DecompileArg", intrinsic_DecompileArg, 2,0),
JS_FN("RuntimeDefaultLocale", intrinsic_RuntimeDefaultLocale, 0,0),
JS_FN("LocalTZA", intrinsic_LocalTZA, 0,0),
@@ -1546,6 +1586,8 @@ static const JSFunctionSpec intrinsic_functions[] = {
CallNonGenericSelfhostedMethod<Is<ListIteratorObject>>, 2,0),
JS_FN("ActiveFunction", intrinsic_ActiveFunction, 0,0),
JS_FN("_SetCanonicalName", intrinsic_SetCanonicalName, 2,0),
JS_INLINABLE_FN("IsArrayIterator",
intrinsic_IsInstanceOfBuiltin<ArrayIteratorObject>, 1,0,
IntrinsicIsArrayIterator),
@@ -2005,8 +2047,10 @@ CloneObject(JSContext* cx, HandleNativeObject selfHostedObject)
staticGlobalLexical, kind);
// To be able to re-lazify the cloned function, its name in the
// self-hosting compartment has to be stored on the clone.
if (clone && hasName)
clone->as<JSFunction>().setExtendedSlot(0, StringValue(selfHostedFunction->atom()));
if (clone && hasName) {
clone->as<JSFunction>().setExtendedSlot(LAZY_FUNCTION_NAME_SLOT,
StringValue(selfHostedFunction->atom()));
}
} else if (selfHostedObject->is<RegExpObject>()) {
RegExpObject& reobj = selfHostedObject->as<RegExpObject>();
RootedAtom source(cx, reobj.getSource());
@@ -2073,16 +2117,37 @@ CloneValue(JSContext* cx, HandleValue selfHostedValue, MutableHandleValue vp)
return true;
}
bool
JSRuntime::createLazySelfHostedFunctionClone(JSContext* cx, HandlePropertyName selfHostedName,
HandleAtom name, unsigned nargs,
MutableHandleFunction fun)
{
RootedAtom funName(cx, name);
JSFunction* selfHostedFun = getUnclonedSelfHostedFunction(cx, selfHostedName);
if (!selfHostedFun)
return false;
if (selfHostedFun->atom() != selfHostedName) {
MOZ_ASSERT(selfHostedFun->getExtendedSlot(HAS_SELFHOSTED_CANONICAL_NAME_SLOT).toBoolean());
funName = selfHostedFun->atom();
}
fun.set(NewScriptedFunction(cx, nargs, JSFunction::INTERPRETED_LAZY,
funName, gc::AllocKind::FUNCTION_EXTENDED, SingletonObject));
if (!fun)
return false;
fun->setIsSelfHostedBuiltin();
fun->setExtendedSlot(LAZY_FUNCTION_NAME_SLOT, StringValue(selfHostedName));
return true;
}
bool
JSRuntime::cloneSelfHostedFunctionScript(JSContext* cx, HandlePropertyName name,
HandleFunction targetFun)
{
RootedId id(cx, NameToId(name));
RootedValue funVal(cx);
if (!GetUnclonedValue(cx, HandleNativeObject::fromMarkedLocation(&selfHostingGlobal_), id, &funVal))
RootedFunction sourceFun(cx, getUnclonedSelfHostedFunction(cx, name));
if (!sourceFun)
return false;
RootedFunction sourceFun(cx, &funVal.toObject().as<JSFunction>());
// JSFunction::generatorKind can't handle lazy self-hosted functions, so we make sure there
// aren't any.
MOZ_ASSERT(!sourceFun->isGenerator());
@@ -2112,11 +2177,28 @@ JSRuntime::cloneSelfHostedFunctionScript(JSContext* cx, HandlePropertyName name,
}
bool
JSRuntime::cloneSelfHostedValue(JSContext* cx, HandlePropertyName name, MutableHandleValue vp)
JSRuntime::getUnclonedSelfHostedValue(JSContext* cx, HandlePropertyName name,
MutableHandleValue vp)
{
RootedId id(cx, NameToId(name));
return GetUnclonedValue(cx, HandleNativeObject::fromMarkedLocation(&selfHostingGlobal_), id, vp);
}
JSFunction*
JSRuntime::getUnclonedSelfHostedFunction(JSContext* cx, HandlePropertyName name)
{
RootedValue selfHostedValue(cx);
if (!GetUnclonedValue(cx, HandleNativeObject::fromMarkedLocation(&selfHostingGlobal_), id, &selfHostedValue))
if (!getUnclonedSelfHostedValue(cx, name, &selfHostedValue))
return nullptr;
return &selfHostedValue.toObject().as<JSFunction>();
}
bool
JSRuntime::cloneSelfHostedValue(JSContext* cx, HandlePropertyName name, MutableHandleValue vp)
{
RootedValue selfHostedValue(cx);
if (!getUnclonedSelfHostedValue(cx, name, &selfHostedValue))
return false;
/*
@@ -2132,6 +2214,16 @@ JSRuntime::cloneSelfHostedValue(JSContext* cx, HandlePropertyName name, MutableH
return CloneValue(cx, selfHostedValue, vp);
}
void
JSRuntime::assertSelfHostedFunctionHasCanonicalName(JSContext* cx, HandlePropertyName name)
{
#ifdef DEBUG
JSFunction* selfHostedFun = getUnclonedSelfHostedFunction(cx, name);
MOZ_ASSERT(selfHostedFun);
MOZ_ASSERT(selfHostedFun->getExtendedSlot(HAS_SELFHOSTED_CANONICAL_NAME_SLOT).toBoolean());
#endif
}
JSFunction*
js::SelfHostedFunction(JSContext* cx, HandlePropertyName propName)
{
+4
View File
@@ -830,6 +830,7 @@ TypedArrayObject::protoAccessors[] = {
JS_PSG("buffer", TypedArray_bufferGetter, 0),
JS_PSG("byteLength", TypedArray_byteLengthGetter, 0),
JS_PSG("byteOffset", TypedArray_byteOffsetGetter, 0),
JS_SELF_HOSTED_SYM_GET(toStringTag, "TypedArrayToStringTag", 0),
JS_PS_END
};
@@ -2146,6 +2147,9 @@ DataViewObject::initClass(JSContext* cx)
if (!JS_DefineFunctions(cx, proto, DataViewObject::jsfuncs))
return false;
if (!DefineToStringTag(cx, proto, cx->names().DataView))
return false;
/*
* Create a helper function to implement the craziness of
* |new DataView(new otherWindow.ArrayBuffer())|, and install it in the
+6 -4
View File
@@ -144,10 +144,10 @@ class AsyncFreeSnowWhite : public nsRunnable
public:
NS_IMETHOD Run()
{
TimeStamp start = TimeStamp::Now();
//TimeStamp start = TimeStamp::Now();
bool hadSnowWhiteObjects = nsCycleCollector_doDeferredDeletion();
Telemetry::Accumulate(Telemetry::CYCLE_COLLECTOR_ASYNC_SNOW_WHITE_FREEING,
uint32_t((TimeStamp::Now() - start).ToMilliseconds()));
//Telemetry::Accumulate(Telemetry::CYCLE_COLLECTOR_ASYNC_SNOW_WHITE_FREEING,
// uint32_t((TimeStamp::Now() - start).ToMilliseconds()));
if (hadSnowWhiteObjects && !mContinuation) {
mContinuation = true;
if (NS_FAILED(NS_DispatchToCurrentThread(this))) {
@@ -3096,6 +3096,7 @@ JSSizeOfTab(JSObject* objArg, size_t* jsObjectsSize, size_t* jsStringsSize,
static void
AccumulateTelemetryCallback(int id, uint32_t sample, const char* key)
{
#if(0)
switch (id) {
case JS_TELEMETRY_GC_REASON:
Telemetry::Accumulate(Telemetry::GC_REASON_2, sample);
@@ -3172,6 +3173,7 @@ AccumulateTelemetryCallback(int id, uint32_t sample, const char* key)
default:
MOZ_ASSERT_UNREACHABLE("Unexpected JS_TELEMETRY id");
}
#endif
}
static void
@@ -3484,7 +3486,7 @@ XPCJSRuntime::XPCJSRuntime(nsXPConnect* aXPConnect)
if (PseudoStack* stack = mozilla_get_pseudo_stack())
stack->sampleRuntime(runtime);
#endif
JS_SetAccumulateTelemetryCallback(runtime, AccumulateTelemetryCallback);
//JS_SetAccumulateTelemetryCallback(runtime, AccumulateTelemetryCallback);
js::SetScriptEnvironmentPreparer(runtime, &mEnvironmentPreparer);
js::SetActivityCallback(runtime, ActivityCallback, this);
JS_SetInterruptCallback(runtime, InterruptCallback);
+7
View File
@@ -2220,6 +2220,13 @@ XrayWrapper<Base, Traits>::construct(JSContext* cx, HandleObject wrapper, const
return Traits::construct(cx, wrapper, args, Base::singleton);
}
template <typename Base, typename Traits>
bool
XrayWrapper<Base, Traits>::getBuiltinClass(JSContext* cx, JS::HandleObject wrapper, js::ESClassValue* cls) const
{
return Traits::getBuiltinClass(cx, wrapper, Base::singleton, cls);
}
template <typename Base, typename Traits>
const char*
XrayWrapper<Base, Traits>::className(JSContext* cx, HandleObject wrapper) const
+12
View File
@@ -83,6 +83,11 @@ public:
return result.succeed();
}
static bool getBuiltinClass(JSContext* cx, JS::HandleObject wrapper, const js::Wrapper& baseInstance,
js::ESClassValue* cls) {
return baseInstance.getBuiltinClass(cx, wrapper, cls);
}
static const char* className(JSContext* cx, JS::HandleObject wrapper, const js::Wrapper& baseInstance) {
return baseInstance.className(cx, wrapper);
}
@@ -407,6 +412,12 @@ public:
return JS_WrapObject(cx, protop);
}
static bool getBuiltinClass(JSContext* cx, JS::HandleObject wrapper, const js::Wrapper& baseInstance,
js::ESClassValue* cls) {
*cls = js::ESClass_Other;
return true;
}
static const char* className(JSContext* cx, JS::HandleObject wrapper, const js::Wrapper& baseInstance) {
return "Opaque";
}
@@ -473,6 +484,7 @@ class XrayWrapper : public Base {
virtual bool getOwnEnumerablePropertyKeys(JSContext* cx, JS::Handle<JSObject*> wrapper,
JS::AutoIdVector& props) const override;
virtual bool getBuiltinClass(JSContext* cx, JS::HandleObject wapper, js::ESClassValue* cls) const override;
virtual const char* className(JSContext* cx, JS::HandleObject proxy) const override;
static const XrayWrapper singleton;
+10 -4
View File
@@ -493,11 +493,10 @@ pref("media.webvtt.regions.enabled", false);
pref("media.track.enabled", false);
// Whether to enable MediaSource support.
// MediaSource is pretty much hosed on PowerPC OS X, so ... no.
pref("media.mediasource.enabled", false);
pref("media.mediasource.enabled", true);
pref("media.mediasource.mp4.enabled", false);
pref("media.mediasource.webm.enabled", false);
pref("media.mediasource.webm.audio.enabled", false);
pref("media.mediasource.webm.enabled", true);
pref("media.mediasource.webm.audio.enabled", true);
// Enable new MediaFormatReader architecture for plain webm.
pref("media.format-reader.webm", true);
@@ -2012,6 +2011,13 @@ pref("security.cert_pinning.enforcement_level", 0);
// for tests.
pref("security.cert_pinning.process_headers_from_non_builtin_roots", false);
// Bug 1324406: Treat 'data:' documents as unique, opaque origins
// If true, data: URIs will be treated as unique opaque origins, hence will use
// a NullPrincipal as the security context.
// Otherwise it will inherit the origin from parent node, this is the legacy
// behavior of Firefox.
pref("security.data_uri.unique_opaque_origin", true);
// Modifier key prefs: default to Windows settings,
// menu access key = alt, accelerator key = control.
// Use 17 for Ctrl, 18 for Alt, 224 for Meta, 91 for Win, 0 for none. Mac settings in macprefs.js
+13 -2
View File
@@ -166,7 +166,9 @@ static const char kNetworkActiveChanged[] = "network-active-changed";
uint32_t nsIOService::gDefaultSegmentSize = 4096;
uint32_t nsIOService::gDefaultSegmentCount = 24;
bool nsIOService::sTelemetryEnabled = false;
bool nsIOService::sIsDataURIUniqueOpaqueOrigin = false;
//bool nsIOService::sTelemetryEnabled = false;
NS_IMPL_ISUPPORTS(nsAppOfflineInfo, nsIAppOfflineInfo)
@@ -250,7 +252,8 @@ nsIOService::Init()
else
NS_WARNING("failed to get observer service");
Preferences::AddBoolVarCache(&sTelemetryEnabled, "toolkit.telemetry.enabled", false);
//Preferences::AddBoolVarCache(&sTelemetryEnabled, "toolkit.telemetry.enabled", false);
Preferences::AddBoolVarCache(&sIsDataURIUniqueOpaqueOrigin, "security.data_uri.unique_opaque_origin", true);
Preferences::AddBoolVarCache(&mOfflineMirrorsConnectivity, OFFLINE_MIRRORS_CONNECTIVITY, true);
gIOService = this;
@@ -715,6 +718,7 @@ nsIOService::NewChannelFromURIWithProxyFlagsInternal(nsIURI* aURI,
if (NS_FAILED(rv))
return rv;
#if(0)
if (sTelemetryEnabled) {
nsAutoCString path;
aURI->GetPath(path);
@@ -736,6 +740,7 @@ nsIOService::NewChannelFromURIWithProxyFlagsInternal(nsIURI* aURI,
Telemetry::Accumulate(Telemetry::URL_PATH_CONTAINS_EXCLAMATION_DOUBLE_SLASH,
hasBangDoubleSlash);
}
#endif
nsCOMPtr<nsIProtocolHandler> handler;
rv = GetProtocolHandler(scheme.get(), getter_AddRefs(handler));
@@ -2066,3 +2071,9 @@ nsIOService::IsAppOffline(uint32_t aAppId, bool* aResult)
return NS_OK;
}
/*static*/ bool
nsIOService::IsDataURIUniqueOpaqueOrigin()
{
return sIsDataURIUniqueOpaqueOrigin;
}
+4 -1
View File
@@ -87,6 +87,8 @@ public:
bool IsShutdown() { return mShutdown; }
bool IsLinkUp();
static bool IsDataURIUniqueOpaqueOrigin();
// Should only be called from NeckoChild. Use SetAppOffline instead.
void SetAppOfflineInternal(uint32_t appId, int32_t status);
@@ -174,7 +176,8 @@ private:
// that is used especially in IsAppOffline
nsDataHashtable<nsUint32HashKey, int32_t> mAppsOfflineStatus;
static bool sTelemetryEnabled;
//static bool sTelemetryEnabled;
static bool sIsDataURIUniqueOpaqueOrigin;
// These timestamps are needed for collecting telemetry on PR_Connect,
// PR_ConnectContinue and PR_Close blocking time. If we spend very long
+8 -1
View File
@@ -52,9 +52,16 @@ nsDataHandler::GetDefaultPort(int32_t *result) {
NS_IMETHODIMP
nsDataHandler::GetProtocolFlags(uint32_t *result) {
*result = URI_NORELATIVE | URI_NOAUTH | URI_INHERITS_SECURITY_CONTEXT |
*result = URI_NORELATIVE | URI_NOAUTH |
URI_LOADABLE_BY_ANYONE | URI_NON_PERSISTABLE | URI_IS_LOCAL_RESOURCE |
URI_SYNC_LOAD_IS_OK;
// From bug 1324406:
// data: URIs inherit the security context.
if (!nsIOService::IsDataURIUniqueOpaqueOrigin()) {
*result |= URI_INHERITS_SECURITY_CONTEXT;
}
return NS_OK;
}
@@ -436,13 +436,11 @@ nsHttpChannelAuthProvider::PrepareForAuthentication(bool proxyAuth)
// We need to remove any Proxy_Authorization header left over from a
// non-request based authentication handshake (e.g., for NTLM auth).
nsAutoCString contractId;
contractId.Assign(NS_HTTP_AUTHENTICATOR_CONTRACTID_PREFIX);
contractId.Append(mProxyAuthType);
nsresult rv;
nsCOMPtr<nsIHttpAuthenticator> precedingAuth =
do_GetService(contractId.get(), &rv);
nsCOMPtr<nsIHttpAuthenticator> precedingAuth;
nsCString proxyAuthType;
rv = GetAuthenticator(mProxyAuthType.get(), proxyAuthType,
getter_AddRefs(precedingAuth));
if (NS_FAILED(rv))
return rv;
+1
View File
@@ -232,6 +232,7 @@ DataChannelConnection::Destroy()
MOZ_ASSERT(mSTS);
ASSERT_WEBRTC(NS_IsMainThread());
mListener = nullptr;
// Must do this in Destroy() since we may then delete this object.
// Do this before dispatching to create a consistent ordering of calls to
// the SCTP stack.
+3 -7
View File
@@ -610,17 +610,13 @@ static const StaticFingerprints kPinset_spideroak = {
static const char* const kPinset_yahoo_Data[] = {
kYahooBackup1Fingerprint,
kGOOGLE_PIN_VeriSignClass2_G2Fingerprint,
kDigiCert_Assured_ID_Root_CAFingerprint,
kVeriSign_Class_3_Public_Primary_Certification_Authority___G5Fingerprint,
kVerisign_Class_3_Public_Primary_Certification_Authority___G3Fingerprint,
kVeriSign_Class_3_Public_Primary_Certification_Authority___G4Fingerprint,
kGlobalSign_Root_CAFingerprint,
kDigiCert_Trusted_Root_G4Fingerprint,
kDigiCert_High_Assurance_EV_Root_CAFingerprint,
kVerisign_Class_2_Public_Primary_Certification_Authority___G3Fingerprint,
kGlobalSign_Root_CA___R3Fingerprint,
kYahooBackup2Fingerprint,
kDigiCert_Global_Root_G2Fingerprint,
kVeriSign_Universal_Root_Certification_AuthorityFingerprint,
kDigiCert_Global_Root_CAFingerprint,
kDigiCert_Global_Root_G3Fingerprint,
};
@@ -1174,4 +1170,4 @@ static const TransportSecurityPreload kPublicKeyPinningPreloadList[] = {
static const int32_t kUnknownId = -1;
static const PRTime kPreloadPKPinsExpirationTime = INT64_C(1544124515242000);
static const PRTime kPreloadPKPinsExpirationTime = INT64_C(1547121807387000);
File diff suppressed because it is too large Load Diff
@@ -35,14 +35,6 @@ function do_check_throws(f, type, stack)
do_throw("expected " + type.name + " exception, none thrown", stack);
}
function do_check_class(obj, classname, stack)
{
if (!stack)
stack = Components.stack.caller;
do_check_eq(Object.prototype.toString.call(obj), "[object " + classname + "]", stack);
}
function run_test()
{
// Test ctypes.CType and ctypes.CData are set up correctly.
@@ -231,10 +223,6 @@ function run_abstract_class_tests()
do_check_throws(function() { ctypes.CType(); }, Error);
do_check_throws(function() { new ctypes.CType() }, Error);
// Test that classes and prototypes are set up correctly.
do_check_class(ctypes.CType, "Function");
do_check_class(ctypes.CType.prototype, "CType");
do_check_true(ctypes.CType.hasOwnProperty("prototype"));
do_check_throws(function() { ctypes.CType.prototype(); }, Error);
do_check_throws(function() { new ctypes.CType.prototype() }, Error);
@@ -269,10 +257,6 @@ function run_abstract_class_tests()
do_check_throws(function() { ctypes.CData(); }, Error);
do_check_throws(function() { new ctypes.CData() }, Error);
// Test that classes and prototypes are set up correctly.
do_check_class(ctypes.CData, "Function");
do_check_class(ctypes.CData.prototype, "CData");
do_check_true(ctypes.CData.__proto__ === ctypes.CType.prototype);
do_check_true(ctypes.CData instanceof ctypes.CType);
@@ -302,10 +286,6 @@ function run_abstract_class_tests()
function run_Int64_tests() {
do_check_throws(function() { ctypes.Int64(); }, TypeError);
// Test that classes and prototypes are set up correctly.
do_check_class(ctypes.Int64, "Function");
do_check_class(ctypes.Int64.prototype, "Int64");
do_check_true(ctypes.Int64.hasOwnProperty("prototype"));
do_check_true(ctypes.Int64.prototype.hasOwnProperty("constructor"));
do_check_true(ctypes.Int64.prototype.constructor === ctypes.Int64);
@@ -473,10 +453,6 @@ function run_Int64_tests() {
function run_UInt64_tests() {
do_check_throws(function() { ctypes.UInt64(); }, TypeError);
// Test that classes and prototypes are set up correctly.
do_check_class(ctypes.UInt64, "Function");
do_check_class(ctypes.UInt64.prototype, "UInt64");
do_check_true(ctypes.UInt64.hasOwnProperty("prototype"));
do_check_true(ctypes.UInt64.prototype.hasOwnProperty("constructor"));
do_check_true(ctypes.UInt64.prototype.constructor === ctypes.UInt64);
@@ -738,10 +714,6 @@ function offsetof(struct, member) {
// Test the class and prototype hierarchy for a given basic type 't'.
function run_basic_class_tests(t)
{
// Test that classes and prototypes are set up correctly.
do_check_class(t, "CType");
do_check_class(t.prototype, "CData");
do_check_true(t.__proto__ === ctypes.CType.prototype);
do_check_true(t instanceof ctypes.CType);
@@ -762,7 +734,6 @@ function run_basic_class_tests(t)
// Test that an instance 'd' of 't' is a CData.
let d = t();
do_check_class(d, "CData");
do_check_true(d.__proto__ === t.prototype);
do_check_true(d instanceof t);
do_check_true(d.constructor === t);
@@ -1283,10 +1254,6 @@ function run_char16_tests(library, t, name, limits) {
// Test the class and prototype hierarchy for a given type constructor 'c'.
function run_type_ctor_class_tests(c, t, t2, props=[], fns=[], instanceProps=[], instanceFns=[], specialProps=[])
{
// Test that classes and prototypes are set up correctly on the type ctor 'c'.
do_check_class(c, "Function");
do_check_class(c.prototype, "CType");
do_check_true(c.prototype.__proto__ === ctypes.CType.prototype);
do_check_true(c.prototype instanceof ctypes.CType);
do_check_true(c.prototype.constructor === c);
@@ -1303,15 +1270,9 @@ function run_type_ctor_class_tests(c, t, t2, props=[], fns=[], instanceProps=[],
for (let f of fns)
do_check_throws(function() { c.prototype[f](); }, Error);
// Test that classes and prototypes are set up correctly on a constructed
// type 't'.
do_check_class(t, "CType");
do_check_class(t.prototype, "CData");
do_check_true(t.__proto__ === c.prototype);
do_check_true(t instanceof c);
do_check_class(t.prototype.__proto__, "CData");
// 't.prototype.__proto__' is the common ancestor of all types constructed
// from 'c'; while not available from 'c' directly, it should be identically
// equal to 't2.prototype.__proto__' where 't2' is a different CType
@@ -1359,7 +1320,6 @@ function run_type_ctor_class_tests(c, t, t2, props=[], fns=[], instanceProps=[],
// Test that an instance 'd' of 't' is a CData.
if (t.__proto__ != ctypes.FunctionType.prototype) {
let d = t();
do_check_class(d, "CData");
do_check_true(d.__proto__ === t.prototype);
do_check_true(d instanceof t);
do_check_true(d.constructor === t);