mirror of
https://github.com/roytam1/mozilla45esr.git
synced 2026-05-26 06:25:03 +00:00
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:
@@ -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)));
|
||||
}
|
||||
|
||||
|
||||
@@ -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)) {
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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
@@ -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
@@ -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;
|
||||
|
||||
@@ -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();
|
||||
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -42,6 +42,7 @@ ASSERT_NODE_FLAGS_SPACE(ELEMENT_TYPE_SPECIFIC_BITS_OFFSET + 2);
|
||||
// static
|
||||
const DOMTokenListSupportedToken HTMLAnchorElement::sSupportedRelValues[] = {
|
||||
"noreferrer",
|
||||
"noopener",
|
||||
nullptr
|
||||
};
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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 ||
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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
|
||||
};
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -88,6 +88,7 @@ function LegacyGeneratorNext(val) {
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
_SetCanonicalName(LegacyGeneratorNext, "next");
|
||||
|
||||
function LegacyGeneratorThrow(val) {
|
||||
if (!IsObject(this) || !IsLegacyGeneratorObject(this))
|
||||
|
||||
+15
-15
@@ -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;
|
||||
|
||||
@@ -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]");
|
||||
|
||||
@@ -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
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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");
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -38,3 +38,4 @@ function SetSpecies() {
|
||||
// Step 1.
|
||||
return this;
|
||||
}
|
||||
_SetCanonicalName(SetSpecies, "get [Symbol.species]");
|
||||
|
||||
@@ -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) + '"';
|
||||
outputStr += callFunction(String_substring, inputStr, chunkStart, i) + '"';
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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))
|
||||
{
|
||||
|
||||
@@ -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]");
|
||||
|
||||
|
||||
@@ -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 **********/
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -4561,6 +4561,7 @@ GetSymbolDescription(HandleSymbol symbol);
|
||||
macro(match) \
|
||||
macro(species) \
|
||||
macro(toPrimitive) \
|
||||
macro(toStringTag) \
|
||||
macro(unscopables)
|
||||
|
||||
enum class SymbolCode : uint32_t {
|
||||
|
||||
@@ -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
@@ -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));
|
||||
|
||||
@@ -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));
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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();
|
||||
|
||||
|
||||
@@ -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);
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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]") \
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user