зеркало из https://github.com/mozilla/gecko-dev.git
Merge autoland to mozilla-central. a=merge
This commit is contained in:
Коммит
90fa4c6afd
|
@ -537,7 +537,22 @@ Accessible* Accessible::ChildAtPoint(int32_t aX, int32_t aY,
|
|||
// This happens in mobile platforms with async pinch zooming.
|
||||
offset = offset.RemoveResolution(presContext->PresShell()->GetResolution());
|
||||
|
||||
nsIFrame* foundFrame = nsLayoutUtils::GetFrameForPoint(startFrame, offset);
|
||||
// We need to translate with the offset of the edge of the visual
|
||||
// viewport from top edge of the layout viewport.
|
||||
offset += presContext->PresShell()->GetVisualViewportOffset() -
|
||||
presContext->PresShell()->GetLayoutViewportOffset();
|
||||
|
||||
EnumSet<nsLayoutUtils::FrameForPointOption> options = {
|
||||
#ifdef MOZ_WIDGET_ANDROID
|
||||
// This is needed in Android to ignore the clipping of the scroll frame
|
||||
// when zoomed in. May regress something on other platforms, so
|
||||
// keeping it Android-exclusive for now.
|
||||
nsLayoutUtils::FrameForPointOption::IgnoreRootScrollFrame
|
||||
#endif
|
||||
};
|
||||
|
||||
nsIFrame* foundFrame =
|
||||
nsLayoutUtils::GetFrameForPoint(startFrame, offset, options);
|
||||
|
||||
nsIContent* content = nullptr;
|
||||
if (!foundFrame || !(content = foundFrame->GetContent()))
|
||||
|
@ -645,11 +660,18 @@ nsRect Accessible::BoundsInAppUnits() const {
|
|||
return nsRect();
|
||||
}
|
||||
|
||||
PresShell* presShell = mDoc->PresContext()->PresShell();
|
||||
|
||||
// We need to inverse translate with the offset of the edge of the visual
|
||||
// viewport from top edge of the layout viewport.
|
||||
nsPoint viewportOffset = presShell->GetVisualViewportOffset() -
|
||||
presShell->GetLayoutViewportOffset();
|
||||
unionRectTwips.MoveBy(-viewportOffset);
|
||||
|
||||
// We need to take into account a non-1 resolution set on the presshell.
|
||||
// This happens in mobile platforms with async pinch zooming. Here we
|
||||
// scale the bounds before adding the screen-relative offset.
|
||||
unionRectTwips.ScaleRoundOut(
|
||||
mDoc->PresContext()->PresShell()->GetResolution());
|
||||
unionRectTwips.ScaleRoundOut(presShell->GetResolution());
|
||||
// We have the union of the rectangle, now we need to put it in absolute
|
||||
// screen coords.
|
||||
nsRect orgRectPixels = boundingFrame->GetScreenRectInAppUnits();
|
||||
|
|
|
@ -304,7 +304,7 @@ bool HTMLComboboxAccessible::RemoveChild(Accessible* aChild) {
|
|||
}
|
||||
|
||||
void HTMLComboboxAccessible::Shutdown() {
|
||||
MOZ_ASSERT(mDoc->IsDefunct() || !mListAccessible);
|
||||
MOZ_ASSERT(!mDoc || mDoc->IsDefunct() || !mListAccessible);
|
||||
if (mListAccessible) {
|
||||
mListAccessible->Shutdown();
|
||||
mListAccessible = nullptr;
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<?xml version='1.0' encoding='UTF-8'?>
|
||||
<blocklist lastupdate="1558349549359" xmlns="http://www.mozilla.org/2006/addons-blocklist">
|
||||
<blocklist lastupdate="1558536765550" xmlns="http://www.mozilla.org/2006/addons-blocklist">
|
||||
<emItems>
|
||||
<emItem blockID="i334" id="{0F827075-B026-42F3-885D-98981EE7B1AE}">
|
||||
<prefs/>
|
||||
|
@ -2997,6 +2997,38 @@
|
|||
<prefs/>
|
||||
<versionRange minVersion="0" maxVersion="2.9.1.0" severity="3"/>
|
||||
</emItem>
|
||||
<emItem blockID="0225ae55-626d-42b2-8f48-46ec95ec89f8" id="/^((\{2b3eed60-8f6e-4afc-99f1-38d12f4253da\})|(\{3a6f9dac-3a93-4f6f-8b74-9ebc0f501306\})|(\{46bba8e9-7a75-4dd6-932e-bdd74141cb87\})|(\{4b480ab6-b63a-43f8-b4f4-d312972ab086\})|(\{6106687e-ca0c-4d7e-93bc-115929e4d299\})|(\{717ce133-3c0a-448e-b6ed-fc7d22b76534\})|(\{7224f1ae-c342-4bb5-8441-d324a8951624\})|(\{768e9638-2eba-42e4-a13a-4f3f1df391a2\})|(\{7b655f43-c871-46d2-8f6d-31989e8ee939\})|(\{7e46c692-9488-4671-8c39-7830f92628b0\})|(\{83bc6b56-545f-4ba1-a80b-f82d55cc0f68\})|(\{970a774e-b7a7-498f-b3f2-d88b14b4dab1\})|(\{9d2e8731-3287-46eb-9c19-ece63fe693c7\})|(\{a37ccd20-e04f-4949-b055-98ca58639606\})|(\{af85f82c-3e8f-4ee5-ab53-b8d3aaac34ec\})|(\{b35c6d47-8b07-4d49-89a9-dfe8c10f58f6\})|(\{c2485579-368c-4593-a1cd-985b2fa0b990\})|(\{c85c16ba-78b4-41b3-9201-f80fa662c52f\})|(\{c97e5535-6f2e-4d34-a5a3-0e6e07f7fd13\})|(\{ce7db166-9564-482f-91d9-3a450ec3216d\})|(\{d64a2c73-ff21-4e3e-998f-ec2dc42ad725\})|(\{db6d93c3-67a0-410c-b7bd-f72f267f0cec\})|(\{e513775f-359f-47aa-a3d9-eddc946aabe0\})|(\{f70258e4-643b-4ec2-9c84-de89009eec61\})|(\{f8794e87-82b2-4df4-bce6-db207f62c165\}))$/">
|
||||
<prefs/>
|
||||
<versionRange minVersion="0" maxVersion="*" severity="3"/>
|
||||
</emItem>
|
||||
<emItem blockID="2212748f-ad60-497f-af7b-50d20b326e40" id="{da993d54-9605-42f7-a32f-9f565245070c}">
|
||||
<prefs/>
|
||||
<versionRange minVersion="0" maxVersion="*" severity="3"/>
|
||||
</emItem>
|
||||
<emItem blockID="41137e55-8a11-4259-a009-42c29daadf17" id="{ac4be7d1-4db6-4b4c-bf48-e345350bcb59}">
|
||||
<prefs/>
|
||||
<versionRange minVersion="0" maxVersion="*" severity="3"/>
|
||||
</emItem>
|
||||
<emItem blockID="a5fa8f77-7761-4996-a11d-d8cf723103da" id="{dc6176c4-a192-4a92-849f-ad13abe889ad}">
|
||||
<prefs/>
|
||||
<versionRange minVersion="0" maxVersion="*" severity="3"/>
|
||||
</emItem>
|
||||
<emItem blockID="efecef61-549b-4c13-8a52-394c636dd24b" id="/^((\{ec19994c-c5a5-46d9-bd4d-0fc417c6f4b8\})|(\{a0be7e8d-b0a3-460b-8a52-429c79e49ee2\})|(\{1814dd58-4147-4cca-a0a3-c5aa35966d9c\}))$/">
|
||||
<prefs/>
|
||||
<versionRange minVersion="0" maxVersion="*" severity="3"/>
|
||||
</emItem>
|
||||
<emItem blockID="9c5f5681-8547-4e65-9c05-5796e483b8e1" id="/^((\{3e20d1e2-a7ee-4ce2-ab9c-51c8300a8ff6\})|(\{30906bbc-0942-445b-89c8-f74dac0edb8f\}))$/">
|
||||
<prefs/>
|
||||
<versionRange minVersion="0" maxVersion="*" severity="3"/>
|
||||
</emItem>
|
||||
<emItem blockID="7e86024e-5621-4ded-bc16-184f94fa2e29" id="{a37a7625-b64e-45f3-8b79-f71634f14438}">
|
||||
<prefs/>
|
||||
<versionRange minVersion="0" maxVersion="*" severity="3"/>
|
||||
</emItem>
|
||||
<emItem blockID="43966df2-e95c-415b-bffc-13814e1d2b11" id="{3fc1db2b-e7db-4512-b24e-1faf4d3a1b4d}">
|
||||
<prefs/>
|
||||
<versionRange minVersion="0" maxVersion="*" severity="3"/>
|
||||
</emItem>
|
||||
</emItems>
|
||||
<pluginItems>
|
||||
<pluginItem blockID="p332">
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
[DEFAULT]
|
||||
|
||||
[browser_file_menu_import_wizard.js]
|
||||
[browser_window_menu_list.js]
|
||||
skip-if = os != "mac" # Mac only feature
|
||||
|
|
|
@ -0,0 +1,38 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
"use strict";
|
||||
|
||||
add_task(async function test_window_menu_list() {
|
||||
// This title is different depending on the build. For example, it's "Nightly"
|
||||
// for a local build, "Mozilla Firefox" for an official release build.
|
||||
const windowTitle = window.document.title;
|
||||
await checkWindowMenu([windowTitle, "Browser chrome tests"]);
|
||||
let newWindow = await BrowserTestUtils.openNewBrowserWindow();
|
||||
await checkWindowMenu([windowTitle, "Browser chrome tests", windowTitle]);
|
||||
await BrowserTestUtils.closeWindow(newWindow);
|
||||
});
|
||||
|
||||
async function checkWindowMenu(labels) {
|
||||
let menu = document.querySelector("#windowMenu");
|
||||
// We can't toggle menubar items on OSX, so mocking instead.
|
||||
await new Promise(resolve => {
|
||||
menu.addEventListener("popupshown", resolve, { once: true });
|
||||
menu.dispatchEvent(new MouseEvent("popupshowing"));
|
||||
menu.dispatchEvent(new MouseEvent("popupshown"));
|
||||
});
|
||||
|
||||
let menuitems = [...menu.querySelectorAll("menuseparator ~ menuitem")];
|
||||
is(menuitems.length, labels.length, "Correct number of windows in the menu");
|
||||
is(menuitems.map(item => item.label).join(","), labels.join(","), "Correct labels on menuitems");
|
||||
for (let menuitem of menuitems) {
|
||||
ok(menuitem instanceof customElements.get("menuitem"), "sibling is menuitem");
|
||||
}
|
||||
|
||||
// We can't toggle menubar items on OSX, so mocking instead.
|
||||
await new Promise(resolve => {
|
||||
menu.addEventListener("popuphidden", resolve, { once: true });
|
||||
menu.dispatchEvent(new MouseEvent("popuphiding"));
|
||||
menu.dispatchEvent(new MouseEvent("popuphidden"));
|
||||
});
|
||||
}
|
|
@ -289,16 +289,6 @@ const startupPhases = {
|
|||
read: 3,
|
||||
close: 3,
|
||||
},
|
||||
{
|
||||
path: "UChrm:userChrome.css",
|
||||
condition: WIN,
|
||||
stat: 1,
|
||||
},
|
||||
{ // bug 1541233
|
||||
path: "UChrm:userContent.css",
|
||||
condition: WIN,
|
||||
stat: 1,
|
||||
},
|
||||
{ // bug 1541246
|
||||
path: "XREUSysExt:",
|
||||
condition: WIN,
|
||||
|
|
|
@ -22,3 +22,9 @@ export MOZ_PACKAGE_JSSHELL=1
|
|||
if test -n "$MOZ_ARTIFACT_TASK_WIN32_OPT"; then
|
||||
ac_add_options --enable-eme=widevine
|
||||
fi
|
||||
|
||||
# Temporary signal to toolchain.configure that our compiler is patched to
|
||||
# support CFG, until such support can be assumed.
|
||||
if test -z "$USE_ARTIFACT"; then
|
||||
ac_add_options --enable-hardening
|
||||
fi
|
||||
|
|
|
@ -1,9 +1,3 @@
|
|||
# This file is used by all AArch64 Win64 builds
|
||||
|
||||
ac_add_options --target=aarch64-windows-mingw32
|
||||
|
||||
# Temporary signal to toolchain.configure that our compiler is patched to
|
||||
# support CFG, until such support can be assumed.
|
||||
if test -z "$USE_ARTIFACT"; then
|
||||
ac_add_options --enable-hardening
|
||||
fi
|
||||
|
|
|
@ -288,6 +288,7 @@
|
|||
@RESPATH@/greprefs.js
|
||||
@RESPATH@/defaults/autoconfig/prefcalls.js
|
||||
@RESPATH@/browser/defaults/permissions
|
||||
; Remote Settings JSON dumps
|
||||
@RESPATH@/browser/defaults/settings/blocklists
|
||||
@RESPATH@/browser/defaults/settings/pinning
|
||||
@RESPATH@/browser/defaults/settings/main
|
||||
|
|
|
@ -11,7 +11,10 @@ import platform
|
|||
import subprocess
|
||||
import sys
|
||||
import uuid
|
||||
import __builtin__
|
||||
if sys.version_info[0] < 3:
|
||||
import __builtin__ as builtins
|
||||
else:
|
||||
import builtins
|
||||
|
||||
from types import ModuleType
|
||||
|
||||
|
@ -434,4 +437,4 @@ class ImportHook(object):
|
|||
|
||||
|
||||
# Install our hook
|
||||
__builtin__.__import__ = ImportHook(__builtin__.__import__)
|
||||
builtins.__import__ = ImportHook(builtins.__import__)
|
||||
|
|
|
@ -714,11 +714,8 @@ $(foreach f,$(HOST_CSRCS) $(HOST_CPPSRCS) $(HOST_CMSRCS) $(HOST_CMMSRCS),$(eval
|
|||
|
||||
# The Rust compiler only outputs library objects, and so we need different
|
||||
# mangling to generate dependency rules for it.
|
||||
mk_libname = $(basename lib$(notdir $1)).rlib
|
||||
src_libdep = $(call mk_libname,$1): $1 $$(call mkdir_deps,$$(MDDEPDIR))
|
||||
mk_global_crate_libname = $(basename lib$(notdir $1)).$(LIB_SUFFIX)
|
||||
crate_src_libdep = $(call mk_global_crate_libname,$1): $1 $$(call mkdir_deps,$$(MDDEPDIR))
|
||||
$(foreach f,$(RSSRCS),$(eval $(call src_libdep,$(f))))
|
||||
$(foreach f,$(RS_STATICLIB_CRATE_SRC),$(eval $(call crate_src_libdep,$(f))))
|
||||
|
||||
$(OBJS) $(HOST_OBJS) $(PROGOBJS) $(HOST_PROGOBJS): $(GLOBAL_DEPS)
|
||||
|
|
|
@ -101,7 +101,6 @@ devtools.jar:
|
|||
skin/breadcrumbs.css (themes/breadcrumbs.css)
|
||||
skin/chart.css (themes/chart.css)
|
||||
skin/widgets.css (themes/widgets.css)
|
||||
skin/images/alerticon-unused.svg (themes/images/alerticon-unused.svg)
|
||||
skin/rules.css (themes/rules.css)
|
||||
skin/images/command-paintflashing.svg (themes/images/command-paintflashing.svg)
|
||||
skin/images/command-screenshot.svg (themes/images/command-screenshot.svg)
|
||||
|
|
|
@ -552,6 +552,10 @@ netmonitor.toolbar.method=Method
|
|||
# in the network table toolbar, above the "file" column.
|
||||
netmonitor.toolbar.file=File
|
||||
|
||||
# LOCALIZATION NOTE (netmonitor.toolbar.url): This is the label displayed
|
||||
# in the network table toolbar, above the "url" column.
|
||||
netmonitor.toolbar.url=URL
|
||||
|
||||
# LOCALIZATION NOTE (netmonitor.toolbar.protocol): This is the label displayed
|
||||
# in the network table toolbar, above the "protocol" column.
|
||||
netmonitor.toolbar.protocol=Protocol
|
||||
|
|
|
@ -4,14 +4,12 @@
|
|||
|
||||
"use strict";
|
||||
|
||||
const { Component } = require("devtools/client/shared/vendor/react");
|
||||
const dom = require("devtools/client/shared/vendor/react-dom-factories");
|
||||
const { Component, createFactory } = require("devtools/client/shared/vendor/react");
|
||||
const { td } = require("devtools/client/shared/vendor/react-dom-factories");
|
||||
const PropTypes = require("devtools/client/shared/vendor/react-prop-types");
|
||||
const { getFormattedIPAndPort } = require("../utils/format-utils");
|
||||
const { L10N } = require("../utils/l10n");
|
||||
const { propertiesEqual } = require("../utils/request-utils");
|
||||
|
||||
const { div } = dom;
|
||||
const SecurityState = createFactory(require("./SecurityState"));
|
||||
|
||||
const UPDATED_DOMAIN_PROPS = [
|
||||
"remoteAddress",
|
||||
|
@ -32,38 +30,26 @@ class RequestListColumnDomain extends Component {
|
|||
}
|
||||
|
||||
render() {
|
||||
const { item, onSecurityIconMouseDown } = this.props;
|
||||
const { remoteAddress, remotePort, securityState,
|
||||
urlDetails: { host, isLocal } } = item;
|
||||
const iconClassList = ["requests-security-state-icon"];
|
||||
let iconTitle;
|
||||
const {
|
||||
item,
|
||||
onSecurityIconMouseDown,
|
||||
} = this.props;
|
||||
|
||||
const {
|
||||
remoteAddress,
|
||||
remotePort,
|
||||
urlDetails: {
|
||||
host,
|
||||
isLocal,
|
||||
},
|
||||
} = item;
|
||||
|
||||
const title = host + (remoteAddress ?
|
||||
` (${getFormattedIPAndPort(remoteAddress, remotePort)})` : "");
|
||||
|
||||
let realSecurityState = securityState;
|
||||
|
||||
// Locally delivered files such as http://localhost and file:// paths
|
||||
// are considered to have been delivered securely.
|
||||
if (isLocal) {
|
||||
realSecurityState = "secure";
|
||||
}
|
||||
|
||||
if (realSecurityState) {
|
||||
iconClassList.push(`security-state-${realSecurityState}`);
|
||||
iconTitle = L10N.getStr(`netmonitor.security.state.${realSecurityState}`);
|
||||
}
|
||||
|
||||
return (
|
||||
dom.td({ className: "requests-list-column requests-list-domain", title },
|
||||
div({
|
||||
className: iconClassList.join(" "),
|
||||
onMouseDown: onSecurityIconMouseDown,
|
||||
title: iconTitle,
|
||||
}),
|
||||
item.isThirdPartyTrackingResource && div({
|
||||
className: "tracking-resource",
|
||||
title: L10N.getStr("netmonitor.trackingResource.tooltip"),
|
||||
}),
|
||||
td({ className: "requests-list-column requests-list-domain", title },
|
||||
SecurityState({item, onSecurityIconMouseDown, isLocal}),
|
||||
host,
|
||||
)
|
||||
);
|
||||
|
|
|
@ -0,0 +1,75 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
"use strict";
|
||||
|
||||
const { Component, createFactory } = require("devtools/client/shared/vendor/react");
|
||||
const { td } = require("devtools/client/shared/vendor/react-dom-factories");
|
||||
const { L10N } = require("../utils/l10n");
|
||||
const PropTypes = require("devtools/client/shared/vendor/react-prop-types");
|
||||
const { getFormattedIPAndPort } = require("../utils/format-utils");
|
||||
const { propertiesEqual } = require("../utils/request-utils");
|
||||
const SecurityState = createFactory(require("./SecurityState"));
|
||||
const UPDATED_FILE_PROPS = [
|
||||
"remoteAddress",
|
||||
"securityState",
|
||||
"urlDetails",
|
||||
];
|
||||
|
||||
class RequestListColumnUrl extends Component {
|
||||
static get propTypes() {
|
||||
return {
|
||||
item: PropTypes.object.isRequired,
|
||||
onSecurityIconMouseDown: PropTypes.func.isRequired,
|
||||
};
|
||||
}
|
||||
|
||||
shouldComponentUpdate(nextProps) {
|
||||
return !propertiesEqual(UPDATED_FILE_PROPS, this.props.item, nextProps.item);
|
||||
}
|
||||
|
||||
render() {
|
||||
const {
|
||||
item: { urlDetails },
|
||||
} = this.props;
|
||||
|
||||
const {
|
||||
item,
|
||||
onSecurityIconMouseDown,
|
||||
} = this.props;
|
||||
|
||||
const {
|
||||
remoteAddress,
|
||||
remotePort,
|
||||
urlDetails: {
|
||||
isLocal,
|
||||
},
|
||||
} = item;
|
||||
|
||||
const title = (remoteAddress ?
|
||||
` (${getFormattedIPAndPort(remoteAddress, remotePort)})` : "");
|
||||
|
||||
// deals with returning whole url
|
||||
const originalURL = urlDetails.url;
|
||||
const decodedFileURL = urlDetails.unicodeUrl;
|
||||
const ORIGINAL_FILE_URL = L10N.getFormatStr("netRequest.originalFileURL.tooltip",
|
||||
originalURL);
|
||||
const DECODED_FILE_URL = L10N.getFormatStr("netRequest.decodedFileURL.tooltip",
|
||||
decodedFileURL);
|
||||
const urlToolTip = originalURL === decodedFileURL ?
|
||||
originalURL : ORIGINAL_FILE_URL + "\n\n" + DECODED_FILE_URL;
|
||||
|
||||
return (
|
||||
td({
|
||||
className: "requests-list-column requests-list-url",
|
||||
title: urlToolTip + title,
|
||||
},
|
||||
SecurityState({item, onSecurityIconMouseDown, isLocal}),
|
||||
originalURL
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = RequestListColumnUrl;
|
|
@ -30,6 +30,7 @@ const { RESPONSE_HEADERS } = require("../constants");
|
|||
RequestListColumnTime,
|
||||
RequestListColumnTransferredSize,
|
||||
RequestListColumnType,
|
||||
RequestListColumnUrl,
|
||||
RequestListColumnWaterfall
|
||||
*/
|
||||
|
||||
|
@ -48,6 +49,9 @@ loader.lazyGetter(this, "RequestListColumnDomain", function() {
|
|||
loader.lazyGetter(this, "RequestListColumnFile", function() {
|
||||
return createFactory(require("./RequestListColumnFile"));
|
||||
});
|
||||
loader.lazyGetter(this, "RequestListColumnUrl", function() {
|
||||
return createFactory(require("./RequestListColumnUrl"));
|
||||
});
|
||||
loader.lazyGetter(this, "RequestListColumnMethod", function() {
|
||||
return createFactory(require("./RequestListColumnMethod"));
|
||||
});
|
||||
|
@ -227,6 +231,10 @@ class RequestListItem extends Component {
|
|||
onSecurityIconMouseDown,
|
||||
}),
|
||||
columns.file && RequestListColumnFile({ item }),
|
||||
columns.url && RequestListColumnUrl({
|
||||
item,
|
||||
onSecurityIconMouseDown,
|
||||
}),
|
||||
columns.protocol && RequestListColumnProtocol({ item }),
|
||||
columns.scheme && RequestListColumnScheme({ item }),
|
||||
columns.remoteip && RequestListColumnRemoteIP({ item }),
|
||||
|
|
|
@ -0,0 +1,75 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
"use strict";
|
||||
|
||||
const { Component } = require("devtools/client/shared/vendor/react");
|
||||
const { div } = require("devtools/client/shared/vendor/react-dom-factories");
|
||||
const PropTypes = require("devtools/client/shared/vendor/react-prop-types");
|
||||
const { L10N } = require("../utils/l10n");
|
||||
const { propertiesEqual } = require("../utils/request-utils");
|
||||
|
||||
const UPDATED_DOMAIN_PROPS = [
|
||||
"remoteAddress",
|
||||
"securityState",
|
||||
"urlDetails",
|
||||
];
|
||||
|
||||
class SecurityState extends Component {
|
||||
static get propTypes() {
|
||||
return {
|
||||
item: PropTypes.object.isRequired,
|
||||
onSecurityIconMouseDown: PropTypes.func.isRequired,
|
||||
};
|
||||
}
|
||||
|
||||
shouldComponentUpdate(nextProps) {
|
||||
return !propertiesEqual(UPDATED_DOMAIN_PROPS, this.props.item, nextProps.item);
|
||||
}
|
||||
|
||||
render() {
|
||||
const {
|
||||
item,
|
||||
onSecurityIconMouseDown,
|
||||
} = this.props;
|
||||
|
||||
const {
|
||||
securityState,
|
||||
urlDetails: {
|
||||
isLocal,
|
||||
},
|
||||
} = item;
|
||||
const iconClassList = ["requests-security-state-icon"];
|
||||
|
||||
let iconTitle;
|
||||
let realSecurityState = securityState;
|
||||
|
||||
// Locally delivered files such as http://localhost and file:// paths
|
||||
// are considered to have been delivered securely.
|
||||
if (isLocal) {
|
||||
realSecurityState = "secure";
|
||||
}
|
||||
|
||||
if (realSecurityState) {
|
||||
iconClassList.push(`security-state-${realSecurityState}`);
|
||||
iconTitle = L10N.getStr(`netmonitor.security.state.${realSecurityState}`);
|
||||
}
|
||||
|
||||
return (
|
||||
div({},
|
||||
div({
|
||||
className: iconClassList.join(" "),
|
||||
onMouseDown: onSecurityIconMouseDown,
|
||||
title: iconTitle,
|
||||
}),
|
||||
item.isThirdPartyTrackingResource && div({
|
||||
className: "tracking-resource",
|
||||
title: L10N.getStr("netmonitor.trackingResource.tooltip"),
|
||||
}),
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = SecurityState;
|
|
@ -30,6 +30,7 @@ DevToolsModules(
|
|||
'RequestListColumnTime.js',
|
||||
'RequestListColumnTransferredSize.js',
|
||||
'RequestListColumnType.js',
|
||||
'RequestListColumnUrl.js',
|
||||
'RequestListColumnWaterfall.js',
|
||||
'RequestListContent.js',
|
||||
'RequestListEmptyNotice.js',
|
||||
|
@ -37,6 +38,7 @@ DevToolsModules(
|
|||
'RequestListItem.js',
|
||||
'ResponsePanel.js',
|
||||
'SecurityPanel.js',
|
||||
'SecurityState.js',
|
||||
'SourceEditor.js',
|
||||
'StackTracePanel.js',
|
||||
'StatisticsPanel.js',
|
||||
|
|
|
@ -198,6 +198,10 @@ const HEADERS = [
|
|||
name: "file",
|
||||
canFilter: false,
|
||||
},
|
||||
{
|
||||
name: "url",
|
||||
canFilter: true,
|
||||
},
|
||||
{
|
||||
name: "protocol",
|
||||
canFilter: true,
|
||||
|
|
|
@ -30,6 +30,7 @@ const cols = {
|
|||
method: true,
|
||||
domain: true,
|
||||
file: true,
|
||||
url: false,
|
||||
protocol: false,
|
||||
scheme: false,
|
||||
remoteip: false,
|
||||
|
|
|
@ -25,15 +25,23 @@ add_task(async function() {
|
|||
"There were two requests due to redirect.");
|
||||
|
||||
const [
|
||||
initialSecurityIcon,
|
||||
redirectSecurityIcon,
|
||||
initialDomainSecurityIcon,
|
||||
initialUrlSecurityIcon,
|
||||
redirectDomainSecurityIcon,
|
||||
redirectUrlSecurityIcon,
|
||||
] = document.querySelectorAll(".requests-security-state-icon");
|
||||
|
||||
ok(initialSecurityIcon.classList.contains("security-state-insecure"),
|
||||
"Initial request was marked insecure.");
|
||||
ok(initialDomainSecurityIcon.classList.contains("security-state-insecure"),
|
||||
"Initial request was marked insecure for domain column.");
|
||||
|
||||
ok(redirectSecurityIcon.classList.contains("security-state-secure"),
|
||||
"Redirected request was marked secure.");
|
||||
ok(redirectDomainSecurityIcon.classList.contains("security-state-secure"),
|
||||
"Redirected request was marked secure for domain column.");
|
||||
|
||||
ok(initialUrlSecurityIcon.classList.contains("security-state-insecure"),
|
||||
"Initial request was marked insecure for URL column.");
|
||||
|
||||
ok(redirectUrlSecurityIcon.classList.contains("security-state-secure"),
|
||||
"Redirected request was marked secure for URL column.");
|
||||
|
||||
await teardown(monitor);
|
||||
});
|
||||
|
|
|
@ -30,8 +30,12 @@ add_task(async function() {
|
|||
// Execute request with third party tracking protection flag.
|
||||
await performRequests(monitor, tab, 1);
|
||||
|
||||
const requests = document.querySelectorAll(".request-list-item .tracking-resource");
|
||||
is(requests.length, 1, "There should be one tracking request");
|
||||
const domainRequests =
|
||||
document.querySelectorAll(".requests-list-domain .tracking-resource");
|
||||
const UrlRequests = document.querySelectorAll(".requests-list-url .tracking-resource");
|
||||
|
||||
is(domainRequests.length, 1, "There should be one domain column tracking request");
|
||||
is(UrlRequests.length, 1, "There should be one URL column tracking request");
|
||||
|
||||
await teardown(monitor);
|
||||
});
|
||||
|
|
|
@ -118,7 +118,7 @@ const gDefaultFilters = Services.prefs.getCharPref("devtools.netmonitor.filters"
|
|||
Services.prefs.setCharPref(
|
||||
"devtools.netmonitor.visibleColumns",
|
||||
"[\"cause\",\"contentSize\",\"cookies\",\"domain\",\"duration\"," +
|
||||
"\"endTime\",\"file\",\"latency\",\"method\",\"protocol\"," +
|
||||
"\"endTime\",\"file\",\"url\",\"latency\",\"method\",\"protocol\"," +
|
||||
"\"remoteip\",\"responseTime\",\"scheme\",\"setCookies\"," +
|
||||
"\"startTime\",\"status\",\"transferred\",\"type\",\"waterfall\"]"
|
||||
);
|
||||
|
@ -128,6 +128,7 @@ Services.prefs.setCharPref("devtools.netmonitor.columnsData",
|
|||
'{"name":"method","minWidth":30,"width":5},' +
|
||||
'{"name":"domain","minWidth":30,"width":10},' +
|
||||
'{"name":"file","minWidth":30,"width":25},' +
|
||||
'{"name":"url","minWidth":30,"width":25},' +
|
||||
'{"name":"cause","minWidth":30,"width":10},' +
|
||||
'{"name":"type","minWidth":30,"width":5},' +
|
||||
'{"name":"transferred","minWidth":30,"width":10},' +
|
||||
|
|
|
@ -168,7 +168,7 @@ pref("devtools.netmonitor.visibleColumns",
|
|||
"[\"status\",\"method\",\"domain\",\"file\",\"cause\",\"type\",\"transferred\",\"contentSize\",\"waterfall\"]"
|
||||
);
|
||||
pref("devtools.netmonitor.columnsData",
|
||||
'[{"name":"status","minWidth":30,"width":5}, {"name":"method","minWidth":30,"width":5}, {"name":"domain","minWidth":30,"width":10}, {"name":"file","minWidth":30,"width":25}, {"name":"cause","minWidth":30,"width":10},{"name":"type","minWidth":30,"width":5},{"name":"transferred","minWidth":30,"width":10},{"name":"contentSize","minWidth":30,"width":5},{"name":"waterfall","minWidth":150,"width":25}]');
|
||||
'[{"name":"status","minWidth":30,"width":5}, {"name":"method","minWidth":30,"width":5}, {"name":"domain","minWidth":30,"width":10}, {"name":"file","minWidth":30,"width":25}, {"name":"url","minWidth":30,"width":25}, {"name":"cause","minWidth":30,"width":10},{"name":"type","minWidth":30,"width":5},{"name":"transferred","minWidth":30,"width":10},{"name":"contentSize","minWidth":30,"width":5},{"name":"waterfall","minWidth":150,"width":25}]');
|
||||
|
||||
// Support for columns resizing pref is now enabled (after merge date 03/18/19).
|
||||
pref("devtools.netmonitor.features.resizeColumns", true);
|
||||
|
|
|
@ -32,7 +32,7 @@ class SearchBox extends PureComponent {
|
|||
onFocus: PropTypes.func,
|
||||
onKeyDown: PropTypes.func,
|
||||
placeholder: PropTypes.string.isRequired,
|
||||
type: PropTypes.string.isRequired,
|
||||
type: PropTypes.string,
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<!-- This Source Code Form is subject to the terms of the Mozilla Public
|
||||
- License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 13.5 12.7" width="12" height="12">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 12 12" width="12" height="12">
|
||||
<path fill="context-fill" d="M6 0a1 1 0 0 1 .89.54l5 9.6A1 1 0 0 1 11 11.6H1a1 1 0 0 1-.89-1.46l5-9.6A1 1 0 0 1 6 0zm-.25 8a.75.75 0 0 0-.75.75v.5c0 .41.34.75.75.75h.5c.41 0 .75-.34.75-.75v-.5A.75.75 0 0 0 6.25 8h-.5zM7 3.7a1 1 0 1 0-2 0v2.6a1 1 0 1 0 2 0V3.7z" />
|
||||
</svg>
|
||||
|
|
До Ширина: | Высота: | Размер: 574 B После Ширина: | Высота: | Размер: 570 B |
|
@ -1,8 +0,0 @@
|
|||
<!-- This Source Code Form is subject to the terms of the Mozilla Public
|
||||
- License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="10" height="10" viewBox="0 0 14 14">
|
||||
<path stroke="context-stroke" fill="none" d="M13 7C13 10.31 10.31 13 7 13C3.69 13 1 10.31 1 7C1 3.69 3.69 1 7 1C10.31 1 13 3.69 13 7Z"/>
|
||||
<path fill="context-fill" d="M7.54 5.88C8.02 5.88 8.41 6.26 8.41 6.74C8.41 7.6 8.41 9.29 8.41 10.15C8.41 10.63 8.02 11.02 7.54 11.02C7.2 11.02 7.05 11.02 6.71 11.02C6.23 11.02 5.84 10.63 5.84 10.15C5.84 9.29 5.84 7.6 5.84 6.74C5.84 6.26 6.23 5.88 6.71 5.88C7.05 5.88 7.2 5.88 7.54 5.88Z"/>
|
||||
<path fill="context-fill" d="M8.41 4.11C8.41 4.82 7.83 5.4 7.12 5.4C6.42 5.4 5.84 4.82 5.84 4.11C5.84 3.4 6.42 2.83 7.12 2.83C7.83 2.83 8.41 3.4 8.41 4.11Z"/>
|
||||
</svg>
|
До Ширина: | Высота: | Размер: 895 B |
|
@ -365,22 +365,20 @@
|
|||
display: inline-block;
|
||||
width: 12px;
|
||||
height: 12px;
|
||||
background-size: cover;
|
||||
background-size: 12px;
|
||||
background-repeat: no-repeat;
|
||||
-moz-context-properties: fill;
|
||||
}
|
||||
|
||||
.ruleview-warning {
|
||||
background-image: url(chrome://devtools/skin/images/alert.svg);
|
||||
background-position: 0.73px 0.4px;
|
||||
-moz-context-properties: fill;
|
||||
fill: var(--yellow-60);
|
||||
}
|
||||
|
||||
.ruleview-unused-warning {
|
||||
background-image: url(chrome://devtools/skin/images/alerticon-unused.svg);
|
||||
background-image: url(chrome://devtools/skin/images/webconsole/info.svg);
|
||||
background-color: var(--theme-sidebar-background);
|
||||
-moz-context-properties: fill, stroke;
|
||||
fill: var(--theme-icon-dimmed-color);
|
||||
stroke: var(--theme-icon-dimmed-color);
|
||||
}
|
||||
|
||||
.ruleview-unused-warning:hover {
|
||||
|
|
|
@ -28,7 +28,6 @@ class FilterBar extends Component {
|
|||
return {
|
||||
dispatch: PropTypes.func.isRequired,
|
||||
filter: PropTypes.object.isRequired,
|
||||
attachRefToWebConsoleUI: PropTypes.func.isRequired,
|
||||
persistLogs: PropTypes.bool.isRequired,
|
||||
hidePersistLogsCheckbox: PropTypes.bool.isRequired,
|
||||
showContentMessages: PropTypes.bool.isRequired,
|
||||
|
|
|
@ -1664,14 +1664,15 @@ const ThreadActor = ActorClassWithSpec(threadSpec, {
|
|||
sourceActor = this.sources.createSourceActor(source);
|
||||
}
|
||||
|
||||
if (this._onLoadBreakpointURLs.has(source.url)) {
|
||||
this.setBreakpoint({ sourceUrl: source.url, line: 1 }, {});
|
||||
const sourceUrl = sourceActor.url;
|
||||
if (this._onLoadBreakpointURLs.has(sourceUrl)) {
|
||||
this.setBreakpoint({ sourceUrl, line: 1 }, {});
|
||||
}
|
||||
|
||||
const bpActors = this.breakpointActorMap.findActors()
|
||||
.filter((actor) => {
|
||||
return actor.location.sourceUrl && actor.location.sourceUrl == source.url;
|
||||
});
|
||||
.filter((actor) =>
|
||||
actor.location.sourceUrl && actor.location.sourceUrl == sourceUrl
|
||||
);
|
||||
|
||||
for (const actor of bpActors) {
|
||||
sourceActor.applyBreakpoint(actor);
|
||||
|
|
|
@ -0,0 +1,29 @@
|
|||
/* eslint-disable max-nested-callbacks */
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
"use strict";
|
||||
|
||||
/**
|
||||
* Bug 1552453 - Verify that breakpoints are hit for evaluated
|
||||
* scripts that contain a source url pragma.
|
||||
*/
|
||||
add_task(threadClientTest(async ({ threadClient, targetFront }) => {
|
||||
await threadClient.setBreakpoint(
|
||||
{ sourceUrl: "http://example.com/code.js", line: 2, column: 1 },
|
||||
{}
|
||||
);
|
||||
|
||||
info("Create a new script with the displayUrl code.js");
|
||||
const consoleFront = await targetFront.getFront("console");
|
||||
consoleFront.evaluateJSAsync("function f() {\n return 5; \n}\n//# sourceURL=http://example.com/code.js");
|
||||
|
||||
const sourcePacket = await waitForEvent(threadClient, "newSource");
|
||||
equal(sourcePacket.source.url, "http://example.com/code.js");
|
||||
|
||||
info("Evaluate f() and pause at line 2");
|
||||
consoleFront.evaluateJSAsync("f()");
|
||||
const pausedPacket = await waitForPause(threadClient);
|
||||
equal(pausedPacket.why.type, "breakpoint");
|
||||
equal(pausedPacket.frame.where.line, 2);
|
||||
}));
|
|
@ -132,6 +132,7 @@ reason = bug 1104838
|
|||
[test_breakpoint-21.js]
|
||||
[test_breakpoint-22.js]
|
||||
skip-if = true # breakpoint sliding is not supported bug 1525685
|
||||
[test_breakpoint-23.js]
|
||||
[test_conditional_breakpoint-01.js]
|
||||
[test_conditional_breakpoint-02.js]
|
||||
[test_conditional_breakpoint-03.js]
|
||||
|
|
|
@ -5,12 +5,24 @@
|
|||
|
||||
"use strict";
|
||||
|
||||
const {arg, DebuggerClient} = require("devtools/shared/client/debugger-client");
|
||||
const {
|
||||
arg,
|
||||
DebuggerClient,
|
||||
} = require("devtools/shared/client/debugger-client");
|
||||
const eventSource = require("devtools/shared/client/event-source");
|
||||
const {ThreadStateTypes} = require("devtools/shared/client/constants");
|
||||
const { ThreadStateTypes } = require("devtools/shared/client/constants");
|
||||
|
||||
loader.lazyRequireGetter(this, "ObjectClient", "devtools/shared/client/object-client");
|
||||
loader.lazyRequireGetter(this, "SourceFront", "devtools/shared/fronts/source", true);
|
||||
loader.lazyRequireGetter(
|
||||
this,
|
||||
"ObjectClient",
|
||||
"devtools/shared/client/object-client"
|
||||
);
|
||||
loader.lazyRequireGetter(
|
||||
this,
|
||||
"SourceFront",
|
||||
"devtools/shared/fronts/source",
|
||||
true
|
||||
);
|
||||
|
||||
/**
|
||||
* Creates a thread client for the remote debugging protocol server. This client
|
||||
|
@ -50,7 +62,9 @@ ThreadClient.prototype = {
|
|||
|
||||
_assertPaused: function(command) {
|
||||
if (!this.paused) {
|
||||
throw Error(command + " command sent while not paused. Currently " + this._state);
|
||||
throw Error(
|
||||
command + " command sent while not paused. Currently " + this._state
|
||||
);
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -67,11 +81,13 @@ ThreadClient.prototype = {
|
|||
* than proceeding forwards. This parameter has no effect if the
|
||||
* server does not support rewinding.
|
||||
*/
|
||||
_doResume: DebuggerClient.requester({
|
||||
_doResume: DebuggerClient.requester(
|
||||
{
|
||||
type: "resume",
|
||||
resumeLimit: arg(0),
|
||||
rewind: arg(1),
|
||||
}, {
|
||||
},
|
||||
{
|
||||
before: function(packet) {
|
||||
this._assertPaused("resume");
|
||||
|
||||
|
@ -96,7 +112,8 @@ ThreadClient.prototype = {
|
|||
delete this._previousState;
|
||||
return response;
|
||||
},
|
||||
}),
|
||||
}
|
||||
),
|
||||
|
||||
/**
|
||||
* Reconfigure the thread actor.
|
||||
|
@ -214,14 +231,17 @@ ThreadClient.prototype = {
|
|||
/**
|
||||
* Detach from the thread actor.
|
||||
*/
|
||||
detach: DebuggerClient.requester({
|
||||
detach: DebuggerClient.requester(
|
||||
{
|
||||
type: "detach",
|
||||
}, {
|
||||
},
|
||||
{
|
||||
after: function(response) {
|
||||
this.client.unregisterClient(this);
|
||||
return response;
|
||||
},
|
||||
}),
|
||||
}
|
||||
),
|
||||
|
||||
/**
|
||||
* Promote multiple pause-lifetime object actors to thread-lifetime ones.
|
||||
|
|
|
@ -3291,11 +3291,7 @@ CORSMode Element::AttrValueToCORSMode(const nsAttrValue* aValue) {
|
|||
}
|
||||
|
||||
static const char* GetFullscreenError(CallerType aCallerType) {
|
||||
if (!nsContentUtils::IsRequestFullscreenAllowed(aCallerType)) {
|
||||
return "FullscreenDeniedNotInputDriven";
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
return nsContentUtils::CheckRequestFullscreenAllowed(aCallerType);
|
||||
}
|
||||
|
||||
already_AddRefed<Promise> Element::RequestFullscreen(CallerType aCallerType,
|
||||
|
|
|
@ -6581,24 +6581,36 @@ bool nsContentUtils::ChannelShouldInheritPrincipal(
|
|||
}
|
||||
|
||||
/* static */
|
||||
bool nsContentUtils::IsRequestFullscreenAllowed(CallerType aCallerType) {
|
||||
// If more time has elapsed since the user input than is specified by the
|
||||
// dom.event.handling-user-input-time-limit pref (default 1 second), this
|
||||
// function also returns false.
|
||||
|
||||
const char* nsContentUtils::CheckRequestFullscreenAllowed(
|
||||
CallerType aCallerType) {
|
||||
if (!StaticPrefs::full_screen_api_allow_trusted_requests_only() ||
|
||||
aCallerType == CallerType::System) {
|
||||
return true;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (EventStateManager::IsHandlingUserInput()) {
|
||||
if (!EventStateManager::IsHandlingUserInput()) {
|
||||
return "FullscreenDeniedNotInputDriven";
|
||||
}
|
||||
|
||||
// If more time has elapsed since the user input than is specified by the
|
||||
// dom.event.handling-user-input-time-limit pref (default 1 second),
|
||||
// disallow fullscreen
|
||||
TimeDuration timeout = HandlingUserInputTimeout();
|
||||
return timeout <= TimeDuration(nullptr) ||
|
||||
(TimeStamp::Now() - EventStateManager::GetHandlingInputStart()) <=
|
||||
timeout;
|
||||
if (timeout > TimeDuration(nullptr) &&
|
||||
(TimeStamp::Now() - EventStateManager::GetHandlingInputStart()) >
|
||||
timeout) {
|
||||
return "FullscreenDeniedNotInputDriven";
|
||||
}
|
||||
|
||||
return false;
|
||||
// Entering full-screen on mouse mouse event is only allowed with left mouse
|
||||
// button
|
||||
if (StaticPrefs::full_screen_api_mouse_event_allow_left_button_only() &&
|
||||
(EventStateManager::sCurrentMouseBtn == MouseButton::eMiddle ||
|
||||
EventStateManager::sCurrentMouseBtn == MouseButton::eRight)) {
|
||||
return "FullscreenDeniedMouseEventOnlyLeftBtn";
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/* static */
|
||||
|
|
|
@ -2332,12 +2332,14 @@ class nsContentUtils {
|
|||
static bool IsFocusedContent(const nsIContent* aContent);
|
||||
|
||||
/**
|
||||
* Returns true if requests for fullscreen are allowed in the current
|
||||
* Returns nullptr if requests for fullscreen are allowed in the current
|
||||
* context. Requests are only allowed if the user initiated them (like with
|
||||
* a mouse-click or key press), unless this check has been disabled by
|
||||
* setting the pref "full-screen-api.allow-trusted-requests-only" to false.
|
||||
* If fullscreen is not allowed, a key for the error message is returned.
|
||||
*/
|
||||
static bool IsRequestFullscreenAllowed(mozilla::dom::CallerType aCallerType);
|
||||
static const char* CheckRequestFullscreenAllowed(
|
||||
mozilla::dom::CallerType aCallerType);
|
||||
|
||||
/**
|
||||
* Returns true if calling execCommand with 'cut' or 'copy' arguments is
|
||||
|
|
|
@ -179,6 +179,25 @@ class EncodingScope {
|
|||
|
||||
bool EncodingScope::IsLimited() const { return mSelection || mRange || mNode; }
|
||||
|
||||
struct RangeBoundaryPathsAndOffsets {
|
||||
using ContainerPath = AutoTArray<nsIContent*, 8>;
|
||||
using ContainerOffsets = AutoTArray<int32_t, 8>;
|
||||
|
||||
// The first node is the range's boundary node, the following ones the
|
||||
// ancestors.
|
||||
ContainerPath mStartContainerPath;
|
||||
// The first offset represents where at the boundary node the range starts.
|
||||
// Each other offset is the index of the child relative to its parent.
|
||||
ContainerOffsets mStartContainerOffsets;
|
||||
|
||||
// The first node is the range's boundary node, the following one the
|
||||
// ancestors.
|
||||
ContainerPath mEndContainerPath;
|
||||
// The first offset represents where at the boundary node the range ends.
|
||||
// Each other offset is the index of the child relative to its parent.
|
||||
ContainerOffsets mEndContainerOffsets;
|
||||
};
|
||||
|
||||
class nsDocumentEncoder : public nsIDocumentEncoder {
|
||||
public:
|
||||
nsDocumentEncoder();
|
||||
|
@ -263,7 +282,7 @@ class nsDocumentEncoder : public nsIDocumentEncoder {
|
|||
|
||||
virtual bool IncludeInContext(nsINode* aNode);
|
||||
|
||||
void Clear();
|
||||
void ReleaseDocumentReferenceAndInitialize(bool aClearCachedSerializer);
|
||||
|
||||
class MOZ_STACK_CLASS AutoReleaseDocumentIfNeeded final {
|
||||
public:
|
||||
|
@ -272,7 +291,8 @@ class nsDocumentEncoder : public nsIDocumentEncoder {
|
|||
|
||||
~AutoReleaseDocumentIfNeeded() {
|
||||
if (mEncoder->mFlags & RequiresReinitAfterOutput) {
|
||||
mEncoder->Clear();
|
||||
const bool clearCachedSerializer = false;
|
||||
mEncoder->ReleaseDocumentReferenceAndInitialize(clearCachedSerializer);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -296,10 +316,7 @@ class nsDocumentEncoder : public nsIDocumentEncoder {
|
|||
int32_t mStartRootIndex;
|
||||
int32_t mEndRootIndex;
|
||||
AutoTArray<nsINode*, 8> mCommonAncestors;
|
||||
AutoTArray<nsIContent*, 8> mStartNodes;
|
||||
AutoTArray<int32_t, 8> mStartOffsets;
|
||||
AutoTArray<nsIContent*, 8> mEndNodes;
|
||||
AutoTArray<int32_t, 8> mEndOffsets;
|
||||
RangeBoundaryPathsAndOffsets mRangeBoundaryPathsAndOffsets;
|
||||
AutoTArray<AutoTArray<nsINode*, 8>, 8> mRangeContexts;
|
||||
// Whether the serializer cares about being notified to scan elements to
|
||||
// keep track of whether they are preformatted. This stores the out
|
||||
|
@ -314,7 +331,8 @@ class nsDocumentEncoder : public nsIDocumentEncoder {
|
|||
};
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTING_ADDREF(nsDocumentEncoder)
|
||||
NS_IMPL_CYCLE_COLLECTING_RELEASE_WITH_LAST_RELEASE(nsDocumentEncoder, Clear())
|
||||
NS_IMPL_CYCLE_COLLECTING_RELEASE_WITH_LAST_RELEASE(
|
||||
nsDocumentEncoder, ReleaseDocumentReferenceAndInitialize(true))
|
||||
|
||||
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsDocumentEncoder)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIDocumentEncoder)
|
||||
|
@ -342,6 +360,9 @@ void nsDocumentEncoder::Initialize(bool aClearCachedSerializer) {
|
|||
mHaltRangeHint = false;
|
||||
mDisableContextSerialize = false;
|
||||
mEncodingScope = {};
|
||||
mCommonParent = nullptr;
|
||||
mNodeFixup = nullptr;
|
||||
mRangeBoundaryPathsAndOffsets = {};
|
||||
if (aClearCachedSerializer) {
|
||||
mSerializer = nullptr;
|
||||
}
|
||||
|
@ -771,13 +792,18 @@ nsresult nsDocumentEncoder::SerializeRangeNodes(nsRange* const aRange,
|
|||
// get start and end nodes for this recursion level
|
||||
nsCOMPtr<nsIContent> startNode, endNode;
|
||||
{
|
||||
auto& startContainerPath =
|
||||
mRangeBoundaryPathsAndOffsets.mStartContainerPath;
|
||||
auto& endContainerPath = mRangeBoundaryPathsAndOffsets.mEndContainerPath;
|
||||
int32_t start = mStartRootIndex - aDepth;
|
||||
if (start >= 0 && (uint32_t)start <= mStartNodes.Length())
|
||||
startNode = mStartNodes[start];
|
||||
if (start >= 0 && (uint32_t)start <= startContainerPath.Length()) {
|
||||
startNode = startContainerPath[start];
|
||||
}
|
||||
|
||||
int32_t end = mEndRootIndex - aDepth;
|
||||
if (end >= 0 && (uint32_t)end <= mEndNodes.Length())
|
||||
endNode = mEndNodes[end];
|
||||
if (end >= 0 && (uint32_t)end <= endContainerPath.Length()) {
|
||||
endNode = endContainerPath[end];
|
||||
}
|
||||
}
|
||||
|
||||
if (startNode != content && endNode != content) {
|
||||
|
@ -816,13 +842,19 @@ nsresult nsDocumentEncoder::SerializeRangeNodes(nsRange* const aRange,
|
|||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
|
||||
const auto& startContainerOffsets =
|
||||
mRangeBoundaryPathsAndOffsets.mStartContainerOffsets;
|
||||
const auto& endContainerOffsets =
|
||||
mRangeBoundaryPathsAndOffsets.mEndContainerOffsets;
|
||||
// do some calculations that will tell us which children of this
|
||||
// node are in the range.
|
||||
int32_t startOffset = 0, endOffset = -1;
|
||||
if (startNode == content && mStartRootIndex >= aDepth)
|
||||
startOffset = mStartOffsets[mStartRootIndex - aDepth];
|
||||
if (endNode == content && mEndRootIndex >= aDepth)
|
||||
endOffset = mEndOffsets[mEndRootIndex - aDepth];
|
||||
if (startNode == content && mStartRootIndex >= aDepth) {
|
||||
startOffset = startContainerOffsets[mStartRootIndex - aDepth];
|
||||
}
|
||||
if (endNode == content && mEndRootIndex >= aDepth) {
|
||||
endOffset = endContainerOffsets[mEndRootIndex - aDepth];
|
||||
}
|
||||
// generated content will cause offset values of -1 to be returned.
|
||||
uint32_t childCount = content->GetChildCount();
|
||||
|
||||
|
@ -944,20 +976,24 @@ nsresult nsDocumentEncoder::SerializeRangeToString(nsRange* aRange,
|
|||
|
||||
mStartDepth = mEndDepth = 0;
|
||||
mCommonAncestors.Clear();
|
||||
mStartNodes.Clear();
|
||||
mStartOffsets.Clear();
|
||||
mEndNodes.Clear();
|
||||
mEndOffsets.Clear();
|
||||
|
||||
mRangeBoundaryPathsAndOffsets = {};
|
||||
auto& startContainerPath = mRangeBoundaryPathsAndOffsets.mStartContainerPath;
|
||||
auto& startContainerOffsets =
|
||||
mRangeBoundaryPathsAndOffsets.mStartContainerOffsets;
|
||||
auto& endContainerPath = mRangeBoundaryPathsAndOffsets.mEndContainerPath;
|
||||
auto& endContainerOffsets =
|
||||
mRangeBoundaryPathsAndOffsets.mEndContainerOffsets;
|
||||
|
||||
nsContentUtils::GetAncestors(mCommonParent, mCommonAncestors);
|
||||
nsContentUtils::GetAncestorsAndOffsets(startContainer, startOffset,
|
||||
&mStartNodes, &mStartOffsets);
|
||||
nsContentUtils::GetAncestorsAndOffsets(endContainer, endOffset, &mEndNodes,
|
||||
&mEndOffsets);
|
||||
nsContentUtils::GetAncestorsAndOffsets(
|
||||
startContainer, startOffset, &startContainerPath, &startContainerOffsets);
|
||||
nsContentUtils::GetAncestorsAndOffsets(
|
||||
endContainer, endOffset, &endContainerPath, &endContainerOffsets);
|
||||
|
||||
nsCOMPtr<nsIContent> commonContent = do_QueryInterface(mCommonParent);
|
||||
mStartRootIndex = mStartNodes.IndexOf(commonContent);
|
||||
mEndRootIndex = mEndNodes.IndexOf(commonContent);
|
||||
mStartRootIndex = startContainerPath.IndexOf(commonContent);
|
||||
mEndRootIndex = endContainerPath.IndexOf(commonContent);
|
||||
|
||||
nsresult rv = NS_OK;
|
||||
|
||||
|
@ -991,12 +1027,11 @@ nsresult nsDocumentEncoder::SerializeRangeToString(nsRange* aRange,
|
|||
return rv;
|
||||
}
|
||||
|
||||
void nsDocumentEncoder::Clear() {
|
||||
void nsDocumentEncoder::ReleaseDocumentReferenceAndInitialize(
|
||||
bool aClearCachedSerializer) {
|
||||
mDocument = nullptr;
|
||||
mCommonParent = nullptr;
|
||||
mNodeFixup = nullptr;
|
||||
|
||||
Initialize(false);
|
||||
Initialize(aClearCachedSerializer);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
|
|
|
@ -231,6 +231,7 @@ interface nsIDocumentEncoder : nsISupports
|
|||
|
||||
/**
|
||||
* Initialize with a pointer to the document and the mime type.
|
||||
* Resets wrap column to 72 and resets node fixup.
|
||||
* @param aDocument Document to encode.
|
||||
* @param aMimeType MimeType to use. May also be set by SetMimeType.
|
||||
* @param aFlags Flags to use while encoding. May also be set by SetFlags.
|
||||
|
|
|
@ -396,7 +396,7 @@ partial namespace ChromeUtils {
|
|||
void resetLastExternalProtocolIframeAllowed();
|
||||
|
||||
[ChromeOnly, Throws]
|
||||
void registerWindowActor(DOMString aName, WindowActorOptions aOptions);
|
||||
void registerWindowActor(DOMString aName, optional WindowActorOptions aOptions);
|
||||
|
||||
[ChromeOnly]
|
||||
void unregisterWindowActor(DOMString aName);
|
||||
|
@ -621,13 +621,13 @@ dictionary WindowActorOptions {
|
|||
sequence<DOMString> remoteTypes;
|
||||
|
||||
/** This fields are used for configuring individual sides of the actor. */
|
||||
required WindowActorSidedOptions parent;
|
||||
required WindowActorChildOptions child;
|
||||
WindowActorSidedOptions parent = null;
|
||||
WindowActorChildOptions child = null;
|
||||
};
|
||||
|
||||
dictionary WindowActorSidedOptions {
|
||||
/** The module path which should be loaded for the actor on this side. */
|
||||
required ByteString moduleURI;
|
||||
ByteString moduleURI;
|
||||
};
|
||||
|
||||
dictionary WindowActorChildOptions : WindowActorSidedOptions {
|
||||
|
|
|
@ -197,6 +197,7 @@ static uint32_t sESMInstanceCount = 0;
|
|||
int32_t EventStateManager::sUserInputEventDepth = 0;
|
||||
int32_t EventStateManager::sUserKeyboardEventDepth = 0;
|
||||
bool EventStateManager::sNormalLMouseEventInProcess = false;
|
||||
int16_t EventStateManager::sCurrentMouseBtn = MouseButton::eNotPressed;
|
||||
EventStateManager* EventStateManager::sActiveESM = nullptr;
|
||||
Document* EventStateManager::sMouseOverDocument = nullptr;
|
||||
AutoWeakFrame EventStateManager::sLastDragOverFrame = nullptr;
|
||||
|
@ -6280,6 +6281,12 @@ AutoHandlingUserInputStatePusher::AutoHandlingUserInputStatePusher(
|
|||
mMouseButtonEventHandlingDocument =
|
||||
fm->SetMouseButtonHandlingDocument(aDocument);
|
||||
}
|
||||
if (NeedsToUpdateCurrentMouseBtnState()) {
|
||||
WidgetMouseEvent* mouseEvent = aEvent->AsMouseEvent();
|
||||
if (mouseEvent) {
|
||||
EventStateManager::sCurrentMouseBtn = mouseEvent->mButton;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
AutoHandlingUserInputStatePusher::~AutoHandlingUserInputStatePusher() {
|
||||
|
@ -6296,6 +6303,9 @@ AutoHandlingUserInputStatePusher::~AutoHandlingUserInputStatePusher() {
|
|||
nsCOMPtr<Document> handlingDocument =
|
||||
fm->SetMouseButtonHandlingDocument(mMouseButtonEventHandlingDocument);
|
||||
}
|
||||
if (NeedsToUpdateCurrentMouseBtnState()) {
|
||||
EventStateManager::sCurrentMouseBtn = MouseButton::eNotPressed;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace mozilla
|
||||
|
|
|
@ -1262,6 +1262,7 @@ class EventStateManager : public nsSupportsWeakReference, public nsIObserver {
|
|||
static int32_t sUserKeyboardEventDepth;
|
||||
|
||||
static bool sNormalLMouseEventInProcess;
|
||||
static int16_t sCurrentMouseBtn;
|
||||
|
||||
static EventStateManager* sActiveESM;
|
||||
|
||||
|
@ -1298,6 +1299,11 @@ class MOZ_RAII AutoHandlingUserInputStatePusher final {
|
|||
bool NeedsToResetFocusManagerMouseButtonHandlingState() const {
|
||||
return mMessage == eMouseDown || mMessage == eMouseUp;
|
||||
}
|
||||
|
||||
bool NeedsToUpdateCurrentMouseBtnState() const {
|
||||
return mMessage == eMouseDown || mMessage == eMouseUp ||
|
||||
mMessage == ePointerDown || mMessage == ePointerUp;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
|
|
@ -112,14 +112,49 @@ function testLongRunningEventHandler() {
|
|||
addFullscreenErrorContinuation(() => {
|
||||
ok(!document.fullscreenElement,
|
||||
"Should not grant request in long-running event handler.");
|
||||
// Restore the pref environment we changed before
|
||||
// entering testNonTrustContext.
|
||||
SpecialPowers.popPrefEnv(finish);
|
||||
SimpleTest.executeSoon(testFullscreenMouseBtn);
|
||||
});
|
||||
window.addEventListener("keypress", longRunningHandler);
|
||||
sendString("a");
|
||||
}
|
||||
|
||||
function requestFullscreenMouseBtn(event, button) {
|
||||
let clickEl = document.createElement("p");
|
||||
clickEl.innerText = "Click Me";
|
||||
|
||||
function eventHandler(event) {
|
||||
document.body.requestFullscreen();
|
||||
event.target.removeEventListener(event, this);
|
||||
}
|
||||
|
||||
clickEl.addEventListener(event, eventHandler);
|
||||
document.body.appendChild(clickEl);
|
||||
synthesizeMouseAtCenter(clickEl, { button });
|
||||
}
|
||||
|
||||
async function testFullscreenMouseBtn(event, button, next) {
|
||||
await SpecialPowers.pushPrefEnv({
|
||||
"set": [["full-screen-api.mouse-event-allow-left-button-only", true]]
|
||||
});
|
||||
let fsRequestEvents = ["mousedown", "mouseup", "pointerdown", "pointerup"];
|
||||
let mouseButtons = [1, 2];
|
||||
|
||||
for (let i = 0; i < fsRequestEvents.length; i++) {
|
||||
let event = fsRequestEvents[i];
|
||||
for (let j = 0; j < mouseButtons.length; j++) {
|
||||
let mouseButton = mouseButtons[j];
|
||||
let fsDenied = addFullscreenErrorContinuation();
|
||||
requestFullscreenMouseBtn(event, mouseButton);
|
||||
await fsDenied;
|
||||
ok(!document.fullscreenElement, `Should not grant request on '${event}' triggered by mouse button ${mouseButton}`);
|
||||
}
|
||||
}
|
||||
// Restore the pref environment we changed before
|
||||
// entering testNonTrustContext.
|
||||
await SpecialPowers.popPrefEnv();
|
||||
finish();
|
||||
}
|
||||
|
||||
function finish() {
|
||||
opener.nextTest();
|
||||
}
|
||||
|
|
|
@ -72,12 +72,19 @@ function addFullscreenChangeContinuation(type, callback, inDoc) {
|
|||
|
||||
// Calls |callback| when the next fullscreenerror is dispatched to inDoc||document.
|
||||
function addFullscreenErrorContinuation(callback, inDoc) {
|
||||
var doc = inDoc || document;
|
||||
var listener = function(event) {
|
||||
return new Promise((resolve) => {
|
||||
let doc = inDoc || document;
|
||||
let listener = function(event) {
|
||||
doc.removeEventListener("fullscreenerror", listener);
|
||||
setTimeout(function(){callback(event);}, 0);
|
||||
setTimeout(function(){
|
||||
if(callback) {
|
||||
callback(event);
|
||||
}
|
||||
resolve();
|
||||
}, 0);
|
||||
};
|
||||
doc.addEventListener("fullscreenerror", listener);
|
||||
})
|
||||
}
|
||||
|
||||
// Waits until the window has both the load event and a MozAfterPaint called on
|
||||
|
|
|
@ -47,7 +47,7 @@ JSWindowActorProtocol::FromIPC(const JSWindowActorInfo& aInfo) {
|
|||
proto->mAllFrames = aInfo.allFrames();
|
||||
proto->mMatches = aInfo.matches();
|
||||
proto->mRemoteTypes = aInfo.remoteTypes();
|
||||
proto->mChild.mModuleURI.Assign(aInfo.url());
|
||||
proto->mChild.mModuleURI = aInfo.url();
|
||||
|
||||
proto->mChild.mEvents.SetCapacity(aInfo.events().Length());
|
||||
for (auto& ipc : aInfo.events()) {
|
||||
|
@ -111,8 +111,13 @@ JSWindowActorProtocol::FromWebIDLOptions(const nsAString& aName,
|
|||
proto->mRemoteTypes = aOptions.mRemoteTypes.Value();
|
||||
}
|
||||
|
||||
proto->mParent.mModuleURI = aOptions.mParent.mModuleURI;
|
||||
proto->mChild.mModuleURI = aOptions.mChild.mModuleURI;
|
||||
if (aOptions.mParent.mModuleURI.WasPassed()) {
|
||||
proto->mParent.mModuleURI.emplace(aOptions.mParent.mModuleURI.Value());
|
||||
}
|
||||
|
||||
if (aOptions.mChild.mModuleURI.WasPassed()) {
|
||||
proto->mChild.mModuleURI.emplace(aOptions.mChild.mModuleURI.Value());
|
||||
}
|
||||
|
||||
// For each event declared in the source dictionary, initialize the
|
||||
// corresponding envent declaration entry in the JSWindowActorProtocol.
|
||||
|
|
|
@ -51,7 +51,7 @@ class JSWindowActorProtocol final : public nsIObserver,
|
|||
ErrorResult& aRv);
|
||||
|
||||
struct Sided {
|
||||
nsCString mModuleURI;
|
||||
Maybe<nsCString> mModuleURI;
|
||||
};
|
||||
|
||||
struct ParentSide : public Sided {};
|
||||
|
|
|
@ -227,7 +227,7 @@ struct JSWindowActorInfo
|
|||
{
|
||||
nsString name;
|
||||
bool allFrames;
|
||||
nsCString url;
|
||||
nsCString? url;
|
||||
|
||||
JSWindowActorEventDecl[] events;
|
||||
nsCString[] observers;
|
||||
|
|
|
@ -9,6 +9,8 @@
|
|||
#include "mozJSComponentLoader.h"
|
||||
#include "mozilla/Logging.h"
|
||||
#include "mozilla/dom/JSWindowActorService.h"
|
||||
#include "mozilla/dom/JSWindowActorParent.h"
|
||||
#include "mozilla/dom/JSWindowActorChild.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
@ -57,7 +59,28 @@ void WindowGlobalActor::ConstructActor(const nsAString& aName,
|
|||
side = &proto->Child();
|
||||
}
|
||||
|
||||
aRv = loader->Import(cx, side->mModuleURI, &global, &exports);
|
||||
// Support basic functionally such as SendAsyncMessage and SendQuery for
|
||||
// unspecified moduleURI.
|
||||
if (!side->mModuleURI) {
|
||||
RefPtr<JSWindowActor> actor;
|
||||
if (actorType == JSWindowActor::Type::Parent) {
|
||||
actor = new JSWindowActorParent();
|
||||
} else {
|
||||
actor = new JSWindowActorChild();
|
||||
}
|
||||
|
||||
JS::Rooted<JS::Value> wrapper(cx);
|
||||
if (!ToJSValue(cx, actor, &wrapper)) {
|
||||
aRv.NoteJSContextException(cx);
|
||||
return;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(wrapper.isObject());
|
||||
aActor.set(&wrapper.toObject());
|
||||
return;
|
||||
}
|
||||
|
||||
aRv = loader->Import(cx, side->mModuleURI.ref(), &global, &exports);
|
||||
if (aRv.Failed()) {
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -63,6 +63,7 @@ FullscreenDeniedFocusedPlugin=Request for fullscreen was denied because a window
|
|||
FullscreenDeniedHidden=Request for fullscreen was denied because the document is no longer visible.
|
||||
FullscreenDeniedContainerNotAllowed=Request for fullscreen was denied because at least one of the document’s containing elements is not an iframe or does not have an “allowfullscreen” attribute.
|
||||
FullscreenDeniedNotInputDriven=Request for fullscreen was denied because Element.requestFullscreen() was not called from inside a short running user-generated event handler.
|
||||
FullscreenDeniedMouseEventOnlyLeftBtn=Request for fullscreen was denied because Element.requestFullscreen() was called from inside a mouse event handler not triggered by left mouse button.
|
||||
FullscreenDeniedNotHTMLSVGOrMathML=Request for fullscreen was denied because requesting element is not <svg>, <math>, or an HTML element.
|
||||
FullscreenDeniedNotInDocument=Request for fullscreen was denied because requesting element is no longer in its document.
|
||||
FullscreenDeniedMovedDocument=Request for fullscreen was denied because requesting element has moved document.
|
||||
|
|
|
@ -758,7 +758,8 @@ void DecodedStream::SendVideo(bool aIsSameOrigin,
|
|||
|
||||
for (uint32_t i = 0; i < video.Length(); ++i) {
|
||||
VideoData* v = video[i];
|
||||
TimeUnit lastStart = mData->mLastVideoStartTime.valueOr(mStartTime.ref());
|
||||
TimeUnit lastStart = mData->mLastVideoStartTime.valueOr(
|
||||
mStartTime.ref() - TimeUnit::FromMicroseconds(1));
|
||||
TimeUnit lastEnd = mData->mLastVideoEndTime.valueOr(mStartTime.ref());
|
||||
|
||||
if (lastEnd < v->mTime) {
|
||||
|
@ -777,7 +778,10 @@ void DecodedStream::SendVideo(bool aIsSameOrigin,
|
|||
mData->WriteVideoToSegment(mData->mLastVideoImage, lastEnd, v->mTime,
|
||||
mData->mLastVideoImageDisplaySize, t, &output,
|
||||
aPrincipalHandle);
|
||||
} else if (lastStart < v->mTime) {
|
||||
lastEnd = v->mTime;
|
||||
}
|
||||
|
||||
if (lastStart < v->mTime) {
|
||||
// This frame starts after the last frame's start. Note that this could be
|
||||
// before the last frame's end time for some videos. This only matters for
|
||||
// the track's lifetime in the MSG, as rendering is based on timestamps,
|
||||
|
|
|
@ -278,7 +278,7 @@ var gPlayTests = [
|
|||
{ name:"test-7-6.1.opus", type:"audio/ogg; codecs=opus", duration:11.690 },
|
||||
{ name:"test-8-7.1.opus", type:"audio/ogg; codecs=opus", duration:13.478 },
|
||||
|
||||
{ name:"gizmo-short.mp4", type:"video/mp4", duration:0.27 },
|
||||
{ name:"gizmo-short.mp4", type:"video/mp4", duration:0.27, contentDuration:0.267 },
|
||||
// Test playback of a MP4 file with a non-zero start time (and audio starting
|
||||
// a second later).
|
||||
{ name:"bipbop-lateaudio.mp4", type:"video/mp4" },
|
||||
|
|
|
@ -78,6 +78,14 @@ already_AddRefed<MessageChannel> MessageChannel::Constructor(
|
|||
channel->mPort1->UnshippedEntangle(channel->mPort2);
|
||||
channel->mPort2->UnshippedEntangle(channel->mPort1);
|
||||
|
||||
// MessagePorts should not work if created from a disconnected window.
|
||||
nsCOMPtr<nsPIDOMWindowInner> window = do_QueryInterface(aGlobal);
|
||||
if (window && !window->GetDocShell()) {
|
||||
// The 2 ports are entangled. We can close one of them to close the other
|
||||
// too.
|
||||
channel->mPort1->CloseForced();
|
||||
}
|
||||
|
||||
return channel.forget();
|
||||
}
|
||||
|
||||
|
|
|
@ -29,3 +29,4 @@ skip-if = (os == "win" && processor == "aarch64") #bug 1535784
|
|||
[test_messageChannel_bug1178076.html]
|
||||
[test_messageChannel_bug1224825.html]
|
||||
[test_messageChannel_worker_forceClose.html]
|
||||
[test_removedWindow.html]
|
||||
|
|
|
@ -0,0 +1,55 @@
|
|||
<!DOCTYPE html>
|
||||
<title>MessagePort should not work when created from a disconnected window</title>
|
||||
<script src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
|
||||
<body>
|
||||
<script>
|
||||
"use strict";
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
runTest();
|
||||
|
||||
async function runTest() {
|
||||
let ifr = document.createElement('iframe');
|
||||
await new Promise(resolve => {
|
||||
ifr.onload = resolve;
|
||||
ifr.src = 'support/empty.html';
|
||||
document.body.appendChild(ifr);
|
||||
});
|
||||
|
||||
let w = ifr.contentWindow;
|
||||
|
||||
let pre = new w.MessageChannel();
|
||||
ok(!!pre, "We have a channel");
|
||||
|
||||
ifr.remove();
|
||||
|
||||
let post = new w.MessageChannel();
|
||||
ok(!!post, "We have a channel");
|
||||
|
||||
// This should silently fail.
|
||||
pre.port1.postMessage(42);
|
||||
pre.port2.onmessage = e => {
|
||||
ok(false, "No messages should be received!");
|
||||
}
|
||||
|
||||
// This should silently fail.
|
||||
post.port1.postMessage(42);
|
||||
post.port2.onmessage = e => {
|
||||
ok(false, "No messages should be received!");
|
||||
}
|
||||
|
||||
// Let's use another MessagePort just to be sure no messages are received by
|
||||
// port2.
|
||||
|
||||
let mc = new MessageChannel();
|
||||
mc.port1.postMessage(42);
|
||||
mc.port2.onmessage = e => {
|
||||
ok(true, "Ready to complete the test");
|
||||
SimpleTest.finish();
|
||||
}
|
||||
}
|
||||
|
||||
</script>
|
||||
</body>
|
|
@ -771,7 +771,7 @@ struct RealmStats {
|
|||
MACRO(Other, MallocHeap, baselineData) \
|
||||
MACRO(Other, MallocHeap, baselineStubsFallback) \
|
||||
MACRO(Other, MallocHeap, ionData) \
|
||||
MACRO(Other, MallocHeap, typeInferenceTypeScripts) \
|
||||
MACRO(Other, MallocHeap, jitScripts) \
|
||||
MACRO(Other, MallocHeap, typeInferenceAllocationSiteTables) \
|
||||
MACRO(Other, MallocHeap, typeInferenceArrayTypeTables) \
|
||||
MACRO(Other, MallocHeap, typeInferenceObjectTypeTables) \
|
||||
|
|
|
@ -2531,7 +2531,7 @@ void GCRuntime::sweepTypesAfterCompacting(Zone* zone) {
|
|||
|
||||
for (auto script = zone->cellIterUnsafe<JSScript>(); !script.done();
|
||||
script.next()) {
|
||||
AutoSweepTypeScript sweep(script);
|
||||
AutoSweepJitScript sweep(script);
|
||||
}
|
||||
for (auto group = zone->cellIterUnsafe<ObjectGroup>(); !group.done();
|
||||
group.next()) {
|
||||
|
@ -5916,7 +5916,7 @@ static void SweepThing(Shape* shape) {
|
|||
}
|
||||
}
|
||||
|
||||
static void SweepThing(JSScript* script) { AutoSweepTypeScript sweep(script); }
|
||||
static void SweepThing(JSScript* script) { AutoSweepJitScript sweep(script); }
|
||||
|
||||
static void SweepThing(ObjectGroup* group) {
|
||||
AutoSweepObjectGroup sweep(group);
|
||||
|
@ -8102,7 +8102,7 @@ void GCRuntime::mergeRealms(Realm* source, Realm* target) {
|
|||
script.next()) {
|
||||
MOZ_ASSERT(script->realm() == source);
|
||||
script->realm_ = target;
|
||||
MOZ_ASSERT(!script->types());
|
||||
MOZ_ASSERT(!script->jitScript());
|
||||
}
|
||||
|
||||
GlobalObject* global = target->maybeGlobal();
|
||||
|
|
|
@ -16,8 +16,9 @@
|
|||
namespace js {
|
||||
namespace gc {
|
||||
|
||||
// Mark colors to pass to markIfUnmarked.
|
||||
enum class MarkColor : uint32_t { Black = 0, Gray };
|
||||
// Mark colors. Order is important here: the greater value the 'more marked' a
|
||||
// cell is.
|
||||
enum class MarkColor : uint8_t { Gray = 1, Black = 2 };
|
||||
|
||||
// The phases of an incremental GC.
|
||||
#define GCSTATES(D) \
|
||||
|
|
|
@ -17,9 +17,12 @@ namespace js {
|
|||
namespace gc {
|
||||
|
||||
// Like gc::MarkColor but allows the possibility of the cell being
|
||||
// unmarked. Order is important here, with white being 'least marked'
|
||||
// and black being 'most marked'.
|
||||
enum class CellColor : uint8_t { White = 0, Gray = 1, Black = 2 };
|
||||
// unmarked.
|
||||
enum class CellColor : uint8_t {
|
||||
White = 0,
|
||||
Gray = uint8_t(MarkColor::Gray),
|
||||
Black = uint8_t(MarkColor::Black)
|
||||
};
|
||||
|
||||
static constexpr CellColor AllCellColors[] = {
|
||||
CellColor::White, CellColor::Gray, CellColor::Black
|
||||
|
|
|
@ -207,16 +207,16 @@ void Zone::discardJitCode(FreeOp* fop,
|
|||
|
||||
if (discardBaselineCode || releaseTypes) {
|
||||
#ifdef DEBUG
|
||||
// Assert no TypeScripts are marked as active.
|
||||
// Assert no JitScripts are marked as active.
|
||||
for (auto script = cellIter<JSScript>(); !script.done(); script.next()) {
|
||||
if (TypeScript* types = script.unbarrieredGet()->types()) {
|
||||
MOZ_ASSERT(!types->active());
|
||||
if (JitScript* jitScript = script.unbarrieredGet()->jitScript()) {
|
||||
MOZ_ASSERT(!jitScript->active());
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// Mark TypeScripts on the stack as active.
|
||||
jit::MarkActiveTypeScripts(this);
|
||||
// Mark JitScripts on the stack as active.
|
||||
jit::MarkActiveJitScripts(this);
|
||||
}
|
||||
|
||||
// Invalidate all Ion code in this zone.
|
||||
|
@ -228,7 +228,7 @@ void Zone::discardJitCode(FreeOp* fop,
|
|||
|
||||
// Discard baseline script if it's not marked as active.
|
||||
if (discardBaselineCode && script->hasBaselineScript()) {
|
||||
if (script->types()->active()) {
|
||||
if (script->jitScript()->active()) {
|
||||
// ICs will be purged so the script will need to warm back up before it
|
||||
// can be inlined during Ion compilation.
|
||||
script->baselineScript()->clearIonCompiledOrInlined();
|
||||
|
@ -248,24 +248,22 @@ void Zone::discardJitCode(FreeOp* fop,
|
|||
script->baselineScript()->setControlFlowGraph(nullptr);
|
||||
}
|
||||
|
||||
// Try to release the script's TypeScript. This should happen after
|
||||
// Try to release the script's JitScript. This should happen after
|
||||
// releasing JIT code because we can't do this when the script still has
|
||||
// JIT code.
|
||||
if (releaseTypes) {
|
||||
script->maybeReleaseTypes();
|
||||
script->maybeReleaseJitScript();
|
||||
}
|
||||
|
||||
// The optimizedStubSpace will be purged below so make sure ICScript
|
||||
// doesn't point into it. We do this after (potentially) releasing types
|
||||
// because TypeScript contains the ICScript* and there's no need to
|
||||
// purge stubs if we just destroyed the Typescript.
|
||||
if (discardBaselineCode && script->hasICScript()) {
|
||||
script->icScript()->purgeOptimizedStubs(script);
|
||||
if (JitScript* jitScript = script->jitScript()) {
|
||||
// If we did not release the JitScript, we need to purge optimized IC
|
||||
// stubs because the optimizedStubSpace will be purged below.
|
||||
if (discardBaselineCode) {
|
||||
jitScript->purgeOptimizedStubs(script);
|
||||
}
|
||||
|
||||
// Finally, reset the active flag.
|
||||
if (TypeScript* types = script->types()) {
|
||||
types->resetActive();
|
||||
jitScript->resetActive();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -527,10 +525,11 @@ void MemoryTracker::adopt(MemoryTracker& other) {
|
|||
|
||||
static const char* MemoryUseName(MemoryUse use) {
|
||||
switch (use) {
|
||||
#define DEFINE_CASE(Name) \
|
||||
case MemoryUse::Name: return #Name;
|
||||
JS_FOR_EACH_MEMORY_USE(DEFINE_CASE)
|
||||
#undef DEFINE_CASE
|
||||
# define DEFINE_CASE(Name) \
|
||||
case MemoryUse::Name: \
|
||||
return #Name;
|
||||
JS_FOR_EACH_MEMORY_USE(DEFINE_CASE)
|
||||
# undef DEFINE_CASE
|
||||
}
|
||||
|
||||
MOZ_CRASH("Unknown memory use");
|
||||
|
@ -551,8 +550,7 @@ MemoryTracker::~MemoryTracker() {
|
|||
|
||||
fprintf(stderr, "Missing calls to JS::RemoveAssociatedMemory:\n");
|
||||
for (auto r = map.all(); !r.empty(); r.popFront()) {
|
||||
fprintf(stderr, " %p 0x%zx %s\n", r.front().key().cell,
|
||||
r.front().value(),
|
||||
fprintf(stderr, " %p 0x%zx %s\n", r.front().key().cell, r.front().value(),
|
||||
MemoryUseName(r.front().key().use));
|
||||
}
|
||||
|
||||
|
|
|
@ -1073,7 +1073,7 @@ static bool InitFromBailout(JSContext* cx, size_t frameNo, HandleFunction fun,
|
|||
|
||||
const uint32_t pcOff = script->pcToOffset(pc);
|
||||
BaselineScript* baselineScript = script->baselineScript();
|
||||
ICScript* icScript = script->icScript();
|
||||
JitScript* jitScript = script->jitScript();
|
||||
|
||||
#ifdef DEBUG
|
||||
uint32_t expectedDepth;
|
||||
|
@ -1136,7 +1136,7 @@ static bool InitFromBailout(JSContext* cx, size_t frameNo, HandleFunction fun,
|
|||
// Not every monitored op has a monitored fallback stub, e.g.
|
||||
// JSOP_NEWOBJECT, which always returns the same type for a
|
||||
// particular script/pc location.
|
||||
ICEntry& icEntry = icScript->icEntryFromPCOffset(pcOff);
|
||||
ICEntry& icEntry = jitScript->icEntryFromPCOffset(pcOff);
|
||||
ICFallbackStub* fallbackStub = icEntry.firstStub()->getChainFallback();
|
||||
if (fallbackStub->isMonitoredFallback()) {
|
||||
enterMonitorChain = true;
|
||||
|
@ -1153,7 +1153,7 @@ static bool InitFromBailout(JSContext* cx, size_t frameNo, HandleFunction fun,
|
|||
builder.setResumeFramePtr(prevFramePtr);
|
||||
|
||||
if (enterMonitorChain) {
|
||||
ICEntry& icEntry = icScript->icEntryFromPCOffset(pcOff);
|
||||
ICEntry& icEntry = jitScript->icEntryFromPCOffset(pcOff);
|
||||
ICFallbackStub* fallbackStub = icEntry.firstStub()->getChainFallback();
|
||||
MOZ_ASSERT(fallbackStub->isMonitoredFallback());
|
||||
JitSpew(JitSpew_BaselineBailouts, " [TYPE-MONITOR CHAIN]");
|
||||
|
@ -1337,7 +1337,7 @@ static bool InitFromBailout(JSContext* cx, size_t frameNo, HandleFunction fun,
|
|||
|
||||
// Calculate and write out return address.
|
||||
// The icEntry in question MUST have an inlinable fallback stub.
|
||||
ICEntry& icEntry = icScript->icEntryFromPCOffset(pcOff);
|
||||
ICEntry& icEntry = jitScript->icEntryFromPCOffset(pcOff);
|
||||
MOZ_ASSERT(IsInlinableFallback(icEntry.firstStub()->getChainFallback()));
|
||||
|
||||
RetAddrEntry& retAddrEntry =
|
||||
|
|
|
@ -162,8 +162,8 @@ MethodStatus BaselineCompiler::compile() {
|
|||
AutoTraceLog logScript(logger, scriptEvent);
|
||||
AutoTraceLog logCompile(logger, TraceLogger_BaselineCompilation);
|
||||
|
||||
AutoKeepTypeScripts keepTypes(cx);
|
||||
if (!script->ensureHasTypes(cx, keepTypes)) {
|
||||
AutoKeepJitScripts keepJitScript(cx);
|
||||
if (!script->ensureHasJitScript(cx, keepJitScript)) {
|
||||
return Method_Error;
|
||||
}
|
||||
|
||||
|
@ -542,8 +542,8 @@ bool BaselineCodeGen<Handler>::emitOutOfLinePostBarrierSlot() {
|
|||
|
||||
template <>
|
||||
bool BaselineCompilerCodeGen::emitNextIC() {
|
||||
// Emit a call to an IC stored in ICScript. Calls to this must match the
|
||||
// ICEntry order in ICScript: first the non-op IC entries for |this| and
|
||||
// Emit a call to an IC stored in JitScript. Calls to this must match the
|
||||
// ICEntry order in JitScript: first the non-op IC entries for |this| and
|
||||
// formal arguments, then the for-op IC entries for JOF_IC ops.
|
||||
|
||||
JSScript* script = handler.script();
|
||||
|
@ -553,7 +553,7 @@ bool BaselineCompilerCodeGen::emitNextIC() {
|
|||
// to loop until we find an ICEntry for the current pc.
|
||||
const ICEntry* entry;
|
||||
do {
|
||||
entry = &script->icScript()->icEntry(handler.icEntryIndex());
|
||||
entry = &script->jitScript()->icEntry(handler.icEntryIndex());
|
||||
handler.moveToNextICEntry();
|
||||
} while (entry->pcOffset() < pcOffset);
|
||||
|
||||
|
@ -1111,10 +1111,9 @@ void BaselineInterpreterCodeGen::emitInitFrameFields() {
|
|||
masm.storePtr(scratch1, frame.addressOfInterpreterScript());
|
||||
|
||||
// Initialize interpreterICEntry.
|
||||
masm.loadPtr(Address(scratch1, JSScript::offsetOfTypes()), scratch2);
|
||||
masm.loadPtr(Address(scratch2, TypeScript::offsetOfICScript()), scratch2);
|
||||
masm.computeEffectiveAddress(Address(scratch2, ICScript::offsetOfICEntries()),
|
||||
scratch2);
|
||||
masm.loadPtr(Address(scratch1, JSScript::offsetOfJitScript()), scratch2);
|
||||
masm.computeEffectiveAddress(
|
||||
Address(scratch2, JitScript::offsetOfICEntries()), scratch2);
|
||||
masm.storePtr(scratch2, frame.addressOfInterpreterICEntry());
|
||||
|
||||
// Initialize interpreterPC.
|
||||
|
@ -5897,7 +5896,7 @@ bool BaselineCodeGen<Handler>::emitGeneratorResume(
|
|||
ValueOperand retVal = regs.takeAnyValue();
|
||||
masm.loadValue(frame.addressOfStackValue(-1), retVal);
|
||||
|
||||
// Branch to interpret if the script does not have a TypeScript or
|
||||
// Branch to interpret if the script does not have a JitScript or
|
||||
// BaselineScript (depending on whether the Baseline Interpreter is enabled).
|
||||
// Note that we don't relazify generator scripts, so the function is
|
||||
// guaranteed to be non-lazy.
|
||||
|
@ -5906,8 +5905,9 @@ bool BaselineCodeGen<Handler>::emitGeneratorResume(
|
|||
masm.loadPtr(Address(callee, JSFunction::offsetOfScript()), scratch1);
|
||||
Address baselineAddr(scratch1, JSScript::offsetOfBaselineScript());
|
||||
if (JitOptions.baselineInterpreter) {
|
||||
Address typesAddr(scratch1, JSScript::offsetOfTypes());
|
||||
masm.branchPtr(Assembler::Equal, typesAddr, ImmPtr(nullptr), &interpret);
|
||||
Address jitScriptAddr(scratch1, JSScript::offsetOfJitScript());
|
||||
masm.branchPtr(Assembler::Equal, jitScriptAddr, ImmPtr(nullptr),
|
||||
&interpret);
|
||||
} else {
|
||||
masm.branchPtr(Assembler::BelowOrEqual, baselineAddr,
|
||||
ImmPtr(BASELINE_DISABLED_SCRIPT), &interpret);
|
||||
|
@ -6126,7 +6126,7 @@ bool BaselineCodeGen<Handler>::emitGeneratorResume(
|
|||
masm.implicitPop((fun.explicitStackSlots() + 1) * sizeof(void*));
|
||||
}
|
||||
|
||||
// Call into the VM to run in the C++ interpreter if there's no TypeScript or
|
||||
// Call into the VM to run in the C++ interpreter if there's no JitScript or
|
||||
// BaselineScript.
|
||||
masm.bind(&interpret);
|
||||
|
||||
|
@ -6264,10 +6264,9 @@ bool BaselineInterpreterCodeGen::emit_JSOP_JUMPTARGET() {
|
|||
|
||||
// Compute ICEntry* and store to frame->interpreterICEntry.
|
||||
loadScript(scratch2);
|
||||
masm.loadPtr(Address(scratch2, JSScript::offsetOfTypes()), scratch2);
|
||||
masm.loadPtr(Address(scratch2, TypeScript::offsetOfICScript()), scratch2);
|
||||
masm.loadPtr(Address(scratch2, JSScript::offsetOfJitScript()), scratch2);
|
||||
masm.computeEffectiveAddress(
|
||||
BaseIndex(scratch2, scratch1, TimesOne, ICScript::offsetOfICEntries()),
|
||||
BaseIndex(scratch2, scratch1, TimesOne, JitScript::offsetOfICEntries()),
|
||||
scratch2);
|
||||
masm.storePtr(scratch2, frame.addressOfInterpreterICEntry());
|
||||
return true;
|
||||
|
|
|
@ -526,7 +526,7 @@ class BaselineCompilerHandler {
|
|||
JSScript* script_;
|
||||
jsbytecode* pc_;
|
||||
|
||||
// Index of the current ICEntry in the script's ICScript.
|
||||
// Index of the current ICEntry in the script's JitScript.
|
||||
uint32_t icEntryIndex_;
|
||||
|
||||
bool compileDebugInstrumentation_;
|
||||
|
|
|
@ -615,7 +615,7 @@ static bool RecompileBaselineScriptForDebugMode(
|
|||
script->filename(), script->lineno(), script->column(),
|
||||
observing ? "DEBUGGING" : "NORMAL EXECUTION");
|
||||
|
||||
AutoKeepTypeScripts keepTypes(cx);
|
||||
AutoKeepJitScripts keepJitScripts(cx);
|
||||
script->setBaselineScript(cx->runtime(), nullptr);
|
||||
|
||||
MethodStatus status =
|
||||
|
|
|
@ -110,9 +110,9 @@ bool BaselineFrame::pushVarEnvironment(JSContext* cx, HandleScope scope) {
|
|||
|
||||
void BaselineFrame::setInterpreterPC(jsbytecode* pc) {
|
||||
uint32_t pcOffset = script()->pcToOffset(pc);
|
||||
ICScript* icScript = script()->icScript();
|
||||
JitScript* jitScript = script()->jitScript();
|
||||
interpreterPC_ = pc;
|
||||
interpreterICEntry_ = icScript->interpreterICEntryFromPCOffset(pcOffset);
|
||||
interpreterICEntry_ = jitScript->interpreterICEntryFromPCOffset(pcOffset);
|
||||
}
|
||||
|
||||
bool BaselineFrame::initForOsr(InterpreterFrame* fp, uint32_t numStackValues) {
|
||||
|
|
|
@ -156,36 +156,25 @@ class MOZ_RAII FallbackStubAllocator {
|
|||
}
|
||||
};
|
||||
|
||||
/* static */
|
||||
UniquePtr<ICScript> ICScript::create(JSContext* cx, JSScript* script) {
|
||||
} // namespace jit
|
||||
|
||||
bool JitScript::initICEntries(JSContext* cx, JSScript* script) {
|
||||
MOZ_ASSERT(cx->realm()->jitRealm());
|
||||
MOZ_ASSERT(jit::IsBaselineEnabled(cx));
|
||||
|
||||
const uint32_t numICEntries = script->numICEntries();
|
||||
MOZ_ASSERT(numICEntries() == script->numICEntries());
|
||||
|
||||
// Allocate the ICScript.
|
||||
UniquePtr<ICScript> icScript(
|
||||
script->zone()->pod_malloc_with_extra<ICScript, ICEntry>(numICEntries));
|
||||
if (!icScript) {
|
||||
ReportOutOfMemory(cx);
|
||||
return nullptr;
|
||||
}
|
||||
new (icScript.get()) ICScript(numICEntries);
|
||||
// TODO(bug 1551796): move JitScript into jit namespace so we don't need this.
|
||||
using namespace js::jit;
|
||||
|
||||
// We need to call prepareForDestruction on ICScript before we |delete| it.
|
||||
auto prepareForDestruction = mozilla::MakeScopeExit(
|
||||
[&] { icScript->prepareForDestruction(cx->zone()); });
|
||||
|
||||
FallbackStubAllocator alloc(cx, icScript->fallbackStubSpace_);
|
||||
FallbackStubAllocator alloc(cx, fallbackStubSpace_);
|
||||
|
||||
// Index of the next ICEntry to initialize.
|
||||
uint32_t icEntryIndex = 0;
|
||||
|
||||
using Kind = BaselineICFallbackKind;
|
||||
|
||||
ICScript* icScriptPtr = icScript.get();
|
||||
auto addIC = [cx, icScriptPtr, &icEntryIndex, script](jsbytecode* pc,
|
||||
ICStub* stub) {
|
||||
auto addIC = [cx, this, &icEntryIndex, script](jsbytecode* pc, ICStub* stub) {
|
||||
if (!stub) {
|
||||
MOZ_ASSERT(cx->isExceptionPending());
|
||||
mozilla::Unused << cx; // Silence -Wunused-lambda-capture in opt builds.
|
||||
|
@ -194,7 +183,7 @@ UniquePtr<ICScript> ICScript::create(JSContext* cx, JSScript* script) {
|
|||
|
||||
// Initialize the ICEntry.
|
||||
uint32_t offset = pc ? script->pcToOffset(pc) : ICEntry::ProloguePCOffset;
|
||||
ICEntry& entryRef = icScriptPtr->icEntry(icEntryIndex);
|
||||
ICEntry& entryRef = icEntry(icEntryIndex);
|
||||
icEntryIndex++;
|
||||
new (&entryRef) ICEntry(stub, offset);
|
||||
|
||||
|
@ -215,14 +204,14 @@ UniquePtr<ICScript> ICScript::create(JSContext* cx, JSScript* script) {
|
|||
ICStub* stub =
|
||||
alloc.newStub<ICTypeMonitor_Fallback>(Kind::TypeMonitor, nullptr, 0);
|
||||
if (!addIC(nullptr, stub)) {
|
||||
return nullptr;
|
||||
return false;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < fun->nargs(); i++) {
|
||||
ICStub* stub = alloc.newStub<ICTypeMonitor_Fallback>(Kind::TypeMonitor,
|
||||
nullptr, i + 1);
|
||||
if (!addIC(nullptr, stub)) {
|
||||
return nullptr;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -248,7 +237,7 @@ UniquePtr<ICScript> ICScript::create(JSContext* cx, JSScript* script) {
|
|||
case JSOP_IFNE: {
|
||||
ICStub* stub = alloc.newStub<ICToBool_Fallback>(Kind::ToBool);
|
||||
if (!addIC(pc, stub)) {
|
||||
return nullptr;
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -258,7 +247,7 @@ UniquePtr<ICScript> ICScript::create(JSContext* cx, JSScript* script) {
|
|||
case JSOP_DEC: {
|
||||
ICStub* stub = alloc.newStub<ICUnaryArith_Fallback>(Kind::UnaryArith);
|
||||
if (!addIC(pc, stub)) {
|
||||
return nullptr;
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -276,7 +265,7 @@ UniquePtr<ICScript> ICScript::create(JSContext* cx, JSScript* script) {
|
|||
case JSOP_POW: {
|
||||
ICStub* stub = alloc.newStub<ICBinaryArith_Fallback>(Kind::BinaryArith);
|
||||
if (!addIC(pc, stub)) {
|
||||
return nullptr;
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -290,7 +279,7 @@ UniquePtr<ICScript> ICScript::create(JSContext* cx, JSScript* script) {
|
|||
case JSOP_STRICTNE: {
|
||||
ICStub* stub = alloc.newStub<ICCompare_Fallback>(Kind::Compare);
|
||||
if (!addIC(pc, stub)) {
|
||||
return nullptr;
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -298,7 +287,7 @@ UniquePtr<ICScript> ICScript::create(JSContext* cx, JSScript* script) {
|
|||
ICStub* stub =
|
||||
alloc.newStub<ICWarmUpCounter_Fallback>(Kind::WarmUpCounter);
|
||||
if (!addIC(pc, stub)) {
|
||||
return nullptr;
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -306,12 +295,12 @@ UniquePtr<ICScript> ICScript::create(JSContext* cx, JSScript* script) {
|
|||
ObjectGroup* group =
|
||||
ObjectGroup::allocationSiteGroup(cx, script, pc, JSProto_Array);
|
||||
if (!group) {
|
||||
return nullptr;
|
||||
return false;
|
||||
}
|
||||
ICStub* stub =
|
||||
alloc.newStub<ICNewArray_Fallback>(Kind::NewArray, group);
|
||||
if (!addIC(pc, stub)) {
|
||||
return nullptr;
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -319,7 +308,7 @@ UniquePtr<ICScript> ICScript::create(JSContext* cx, JSScript* script) {
|
|||
case JSOP_NEWINIT: {
|
||||
ICStub* stub = alloc.newStub<ICNewObject_Fallback>(Kind::NewObject);
|
||||
if (!addIC(pc, stub)) {
|
||||
return nullptr;
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -331,7 +320,7 @@ UniquePtr<ICScript> ICScript::create(JSContext* cx, JSScript* script) {
|
|||
case JSOP_STRICTSETELEM: {
|
||||
ICStub* stub = alloc.newStub<ICSetElem_Fallback>(Kind::SetElem);
|
||||
if (!addIC(pc, stub)) {
|
||||
return nullptr;
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -347,7 +336,7 @@ UniquePtr<ICScript> ICScript::create(JSContext* cx, JSScript* script) {
|
|||
case JSOP_STRICTSETGNAME: {
|
||||
ICStub* stub = alloc.newStub<ICSetProp_Fallback>(Kind::SetProp);
|
||||
if (!addIC(pc, stub)) {
|
||||
return nullptr;
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -357,14 +346,14 @@ UniquePtr<ICScript> ICScript::create(JSContext* cx, JSScript* script) {
|
|||
case JSOP_GETBOUNDNAME: {
|
||||
ICStub* stub = alloc.newStub<ICGetProp_Fallback>(Kind::GetProp);
|
||||
if (!addIC(pc, stub)) {
|
||||
return nullptr;
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case JSOP_GETPROP_SUPER: {
|
||||
ICStub* stub = alloc.newStub<ICGetProp_Fallback>(Kind::GetPropSuper);
|
||||
if (!addIC(pc, stub)) {
|
||||
return nullptr;
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -372,28 +361,28 @@ UniquePtr<ICScript> ICScript::create(JSContext* cx, JSScript* script) {
|
|||
case JSOP_CALLELEM: {
|
||||
ICStub* stub = alloc.newStub<ICGetElem_Fallback>(Kind::GetElem);
|
||||
if (!addIC(pc, stub)) {
|
||||
return nullptr;
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case JSOP_GETELEM_SUPER: {
|
||||
ICStub* stub = alloc.newStub<ICGetElem_Fallback>(Kind::GetElemSuper);
|
||||
if (!addIC(pc, stub)) {
|
||||
return nullptr;
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case JSOP_IN: {
|
||||
ICStub* stub = alloc.newStub<ICIn_Fallback>(Kind::In);
|
||||
if (!addIC(pc, stub)) {
|
||||
return nullptr;
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case JSOP_HASOWN: {
|
||||
ICStub* stub = alloc.newStub<ICHasOwn_Fallback>(Kind::HasOwn);
|
||||
if (!addIC(pc, stub)) {
|
||||
return nullptr;
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -401,7 +390,7 @@ UniquePtr<ICScript> ICScript::create(JSContext* cx, JSScript* script) {
|
|||
case JSOP_GETGNAME: {
|
||||
ICStub* stub = alloc.newStub<ICGetName_Fallback>(Kind::GetName);
|
||||
if (!addIC(pc, stub)) {
|
||||
return nullptr;
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -409,7 +398,7 @@ UniquePtr<ICScript> ICScript::create(JSContext* cx, JSScript* script) {
|
|||
case JSOP_BINDGNAME: {
|
||||
ICStub* stub = alloc.newStub<ICBindName_Fallback>(Kind::BindName);
|
||||
if (!addIC(pc, stub)) {
|
||||
return nullptr;
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -418,7 +407,7 @@ UniquePtr<ICScript> ICScript::create(JSContext* cx, JSScript* script) {
|
|||
ICStub* stub =
|
||||
alloc.newStub<ICTypeMonitor_Fallback>(Kind::TypeMonitor, nullptr);
|
||||
if (!addIC(pc, stub)) {
|
||||
return nullptr;
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -426,7 +415,7 @@ UniquePtr<ICScript> ICScript::create(JSContext* cx, JSScript* script) {
|
|||
ICStub* stub =
|
||||
alloc.newStub<ICGetIntrinsic_Fallback>(Kind::GetIntrinsic);
|
||||
if (!addIC(pc, stub)) {
|
||||
return nullptr;
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -439,7 +428,7 @@ UniquePtr<ICScript> ICScript::create(JSContext* cx, JSScript* script) {
|
|||
case JSOP_STRICTEVAL: {
|
||||
ICStub* stub = alloc.newStub<ICCall_Fallback>(Kind::Call);
|
||||
if (!addIC(pc, stub)) {
|
||||
return nullptr;
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -447,7 +436,7 @@ UniquePtr<ICScript> ICScript::create(JSContext* cx, JSScript* script) {
|
|||
case JSOP_NEW: {
|
||||
ICStub* stub = alloc.newStub<ICCall_Fallback>(Kind::CallConstructing);
|
||||
if (!addIC(pc, stub)) {
|
||||
return nullptr;
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -456,7 +445,7 @@ UniquePtr<ICScript> ICScript::create(JSContext* cx, JSScript* script) {
|
|||
case JSOP_STRICTSPREADEVAL: {
|
||||
ICStub* stub = alloc.newStub<ICCall_Fallback>(Kind::SpreadCall);
|
||||
if (!addIC(pc, stub)) {
|
||||
return nullptr;
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -465,14 +454,14 @@ UniquePtr<ICScript> ICScript::create(JSContext* cx, JSScript* script) {
|
|||
ICStub* stub =
|
||||
alloc.newStub<ICCall_Fallback>(Kind::SpreadCallConstructing);
|
||||
if (!addIC(pc, stub)) {
|
||||
return nullptr;
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case JSOP_INSTANCEOF: {
|
||||
ICStub* stub = alloc.newStub<ICInstanceOf_Fallback>(Kind::InstanceOf);
|
||||
if (!addIC(pc, stub)) {
|
||||
return nullptr;
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -480,14 +469,14 @@ UniquePtr<ICScript> ICScript::create(JSContext* cx, JSScript* script) {
|
|||
case JSOP_TYPEOFEXPR: {
|
||||
ICStub* stub = alloc.newStub<ICTypeOf_Fallback>(Kind::TypeOf);
|
||||
if (!addIC(pc, stub)) {
|
||||
return nullptr;
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case JSOP_ITER: {
|
||||
ICStub* stub = alloc.newStub<ICGetIterator_Fallback>(Kind::GetIterator);
|
||||
if (!addIC(pc, stub)) {
|
||||
return nullptr;
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -496,12 +485,12 @@ UniquePtr<ICScript> ICScript::create(JSContext* cx, JSScript* script) {
|
|||
cx, nullptr, 0, TenuredObject,
|
||||
ObjectGroup::NewArrayKind::UnknownIndex);
|
||||
if (!templateObject) {
|
||||
return nullptr;
|
||||
return false;
|
||||
}
|
||||
ICStub* stub =
|
||||
alloc.newStub<ICRest_Fallback>(Kind::Rest, templateObject);
|
||||
if (!addIC(pc, stub)) {
|
||||
return nullptr;
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -511,13 +500,13 @@ UniquePtr<ICScript> ICScript::create(JSContext* cx, JSScript* script) {
|
|||
}
|
||||
|
||||
// Assert all ICEntries have been initialized.
|
||||
MOZ_ASSERT(icEntryIndex == numICEntries);
|
||||
MOZ_ASSERT(icEntryIndex == numICEntries());
|
||||
|
||||
prepareForDestruction.release();
|
||||
|
||||
return icScript;
|
||||
return true;
|
||||
}
|
||||
|
||||
namespace jit {
|
||||
|
||||
ICStubConstIterator& ICStubConstIterator::operator++() {
|
||||
MOZ_ASSERT(currentStub_ != nullptr);
|
||||
currentStub_ = currentStub_->next();
|
||||
|
@ -1098,7 +1087,7 @@ bool ICMonitoredFallbackStub::initMonitoringChain(JSContext* cx,
|
|||
JSScript* script) {
|
||||
MOZ_ASSERT(fallbackMonitorStub_ == nullptr);
|
||||
|
||||
ICStubSpace* space = script->icScript()->fallbackStubSpace();
|
||||
ICStubSpace* space = script->jitScript()->fallbackStubSpace();
|
||||
FallbackStubAllocator alloc(cx, *space);
|
||||
auto* stub = alloc.newStub<ICTypeMonitor_Fallback>(
|
||||
BaselineICFallbackKind::TypeMonitor, this);
|
||||
|
@ -1127,9 +1116,9 @@ static MOZ_MUST_USE bool TypeMonitorResult(JSContext* cx,
|
|||
BaselineFrame* frame,
|
||||
HandleScript script, jsbytecode* pc,
|
||||
HandleValue val) {
|
||||
AutoSweepTypeScript sweep(script);
|
||||
StackTypeSet* types = script->types()->bytecodeTypes(sweep, script, pc);
|
||||
TypeScript::MonitorBytecodeType(cx, script, pc, types, val);
|
||||
AutoSweepJitScript sweep(script);
|
||||
StackTypeSet* types = script->jitScript()->bytecodeTypes(sweep, script, pc);
|
||||
JitScript::MonitorBytecodeType(cx, script, pc, types, val);
|
||||
|
||||
return stub->addMonitorStubForValue(cx, frame, types, val);
|
||||
}
|
||||
|
@ -1152,7 +1141,7 @@ bool ICCacheIR_Updated::initUpdatingChain(JSContext* cx, ICStubSpace* space) {
|
|||
ICStubSpace* ICStubCompiler::StubSpaceForStub(bool makesGCCalls,
|
||||
JSScript* script) {
|
||||
if (makesGCCalls) {
|
||||
return script->icScript()->fallbackStubSpace();
|
||||
return script->jitScript()->fallbackStubSpace();
|
||||
}
|
||||
return script->zone()->jitZone()->optimizedStubSpace();
|
||||
}
|
||||
|
@ -1297,15 +1286,19 @@ void ICStubCompilerBase::PushStubPayload(MacroAssembler& masm,
|
|||
masm.adjustFrame(sizeof(intptr_t));
|
||||
}
|
||||
|
||||
void ICScript::noteAccessedGetter(uint32_t pcOffset) {
|
||||
ICEntry& entry = icEntryFromPCOffset(pcOffset);
|
||||
ICFallbackStub* stub = entry.fallbackStub();
|
||||
} // namespace jit
|
||||
|
||||
void JitScript::noteAccessedGetter(uint32_t pcOffset) {
|
||||
jit::ICEntry& entry = icEntryFromPCOffset(pcOffset);
|
||||
jit::ICFallbackStub* stub = entry.fallbackStub();
|
||||
|
||||
if (stub->isGetProp_Fallback()) {
|
||||
stub->toGetProp_Fallback()->noteAccessedGetter();
|
||||
}
|
||||
}
|
||||
|
||||
namespace jit {
|
||||
|
||||
// TypeMonitor_Fallback
|
||||
//
|
||||
|
||||
|
@ -1514,29 +1507,29 @@ bool DoTypeMonitorFallback(JSContext* cx, BaselineFrame* frame,
|
|||
*GetNextPc(pc) == JSOP_CHECKTHISREINIT ||
|
||||
*GetNextPc(pc) == JSOP_CHECKRETURN);
|
||||
if (stub->monitorsThis()) {
|
||||
TypeScript::MonitorThisType(cx, script, TypeSet::UnknownType());
|
||||
JitScript::MonitorThisType(cx, script, TypeSet::UnknownType());
|
||||
} else {
|
||||
TypeScript::MonitorBytecodeType(cx, script, pc, TypeSet::UnknownType());
|
||||
JitScript::MonitorBytecodeType(cx, script, pc, TypeSet::UnknownType());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
TypeScript* typeScript = script->types();
|
||||
AutoSweepTypeScript sweep(script);
|
||||
JitScript* jitScript = script->jitScript();
|
||||
AutoSweepJitScript sweep(script);
|
||||
|
||||
StackTypeSet* types;
|
||||
uint32_t argument;
|
||||
if (stub->monitorsArgument(&argument)) {
|
||||
MOZ_ASSERT(pc == script->code());
|
||||
types = typeScript->argTypes(sweep, script, argument);
|
||||
TypeScript::MonitorArgType(cx, script, argument, value);
|
||||
types = jitScript->argTypes(sweep, script, argument);
|
||||
JitScript::MonitorArgType(cx, script, argument, value);
|
||||
} else if (stub->monitorsThis()) {
|
||||
MOZ_ASSERT(pc == script->code());
|
||||
types = typeScript->thisTypes(sweep, script);
|
||||
TypeScript::MonitorThisType(cx, script, value);
|
||||
types = jitScript->thisTypes(sweep, script);
|
||||
JitScript::MonitorThisType(cx, script, value);
|
||||
} else {
|
||||
types = typeScript->bytecodeTypes(sweep, script, pc);
|
||||
TypeScript::MonitorBytecodeType(cx, script, pc, types, value);
|
||||
types = jitScript->bytecodeTypes(sweep, script, pc);
|
||||
JitScript::MonitorBytecodeType(cx, script, pc, types, value);
|
||||
}
|
||||
|
||||
return stub->addMonitorStubForValue(cx, frame, types, value);
|
||||
|
@ -2493,15 +2486,19 @@ bool FallbackICCodeCompiler::emit_SetElem() {
|
|||
return tailCallVM<Fn, DoSetElemFallback>(masm);
|
||||
}
|
||||
|
||||
void ICScript::noteHasDenseAdd(uint32_t pcOffset) {
|
||||
ICEntry& entry = icEntryFromPCOffset(pcOffset);
|
||||
ICFallbackStub* stub = entry.fallbackStub();
|
||||
} // namespace jit
|
||||
|
||||
void JitScript::noteHasDenseAdd(uint32_t pcOffset) {
|
||||
jit::ICEntry& entry = icEntryFromPCOffset(pcOffset);
|
||||
jit::ICFallbackStub* stub = entry.fallbackStub();
|
||||
|
||||
if (stub->isSetElem_Fallback()) {
|
||||
stub->toSetElem_Fallback()->noteHasDenseAdd();
|
||||
}
|
||||
}
|
||||
|
||||
namespace jit {
|
||||
|
||||
template <typename T>
|
||||
void StoreToTypedArray(JSContext* cx, MacroAssembler& masm, Scalar::Type type,
|
||||
const ValueOperand& value, const T& dest,
|
||||
|
@ -2779,7 +2776,7 @@ bool DoGetIntrinsicFallback(JSContext* cx, BaselineFrame* frame,
|
|||
// needs to be monitored once. Attach a stub to load the resulting constant
|
||||
// directly.
|
||||
|
||||
TypeScript::MonitorBytecodeType(cx, script, pc, res);
|
||||
JitScript::MonitorBytecodeType(cx, script, pc, res);
|
||||
|
||||
TryAttachStub<GetIntrinsicIRGenerator>("GetIntrinsic", cx, frame, stub,
|
||||
BaselineCacheIRStubKind::Regular, res);
|
||||
|
|
|
@ -269,102 +269,6 @@ class ICEntry {
|
|||
void trace(JSTracer* trc);
|
||||
};
|
||||
|
||||
// [SMDOC] ICScript
|
||||
//
|
||||
// ICScript contains IC data used by Baseline (Ion has its own IC chains, stored
|
||||
// in IonScript).
|
||||
//
|
||||
// For each IC we store an ICEntry, which points to the first ICStub in the
|
||||
// chain. Note that multiple stubs in the same zone can share Baseline IC code.
|
||||
// This works because the stub data is stored in the ICStub instead of baked in
|
||||
// in the stub code.
|
||||
//
|
||||
// Storing this separate from BaselineScript simplifies debug mode OSR because
|
||||
// the ICScript can be reused when we replace the BaselineScript. It also makes
|
||||
// it easier to experiment with interpreter ICs in the future because the
|
||||
// interpreter and Baseline JIT will be able to use exactly the same IC data.
|
||||
//
|
||||
// ICScript contains the following:
|
||||
//
|
||||
// * Fallback stub space: this stores all fallback stubs and the "can GC" stubs.
|
||||
// These stubs are never purged before destroying the ICScript. (Other stubs
|
||||
// are stored in the optimized stub space stored in JitZone and can be
|
||||
// discarded more eagerly. See ICScript::purgeOptimizedStubs.)
|
||||
//
|
||||
// * List of IC entries, in the following order:
|
||||
//
|
||||
// - Type monitor IC for |this|.
|
||||
// - Type monitor IC for each formal argument.
|
||||
// - IC for each JOF_IC bytecode op.
|
||||
//
|
||||
// ICScript is stored in TypeScript and allocated/destroyed at the same time.
|
||||
class ICScript {
|
||||
// Allocated space for fallback stubs.
|
||||
FallbackICStubSpace fallbackStubSpace_ = {};
|
||||
|
||||
uint32_t numICEntries_;
|
||||
|
||||
explicit ICScript(uint32_t numICEntries) : numICEntries_(numICEntries) {}
|
||||
|
||||
ICEntry* icEntryList() {
|
||||
return (ICEntry*)(reinterpret_cast<uint8_t*>(this) + sizeof(ICScript));
|
||||
}
|
||||
|
||||
public:
|
||||
static MOZ_MUST_USE js::UniquePtr<ICScript> create(JSContext* cx,
|
||||
JSScript* script);
|
||||
|
||||
~ICScript() {
|
||||
// The contents of the fallback stub space are removed and freed
|
||||
// separately after the next minor GC. See prepareForDestruction.
|
||||
MOZ_ASSERT(fallbackStubSpace_.isEmpty());
|
||||
}
|
||||
void prepareForDestruction(Zone* zone) {
|
||||
// When the script contains pointers to nursery things, the store buffer can
|
||||
// contain entries that point into the fallback stub space. Since we can
|
||||
// destroy scripts outside the context of a GC, this situation could result
|
||||
// in us trying to mark invalid store buffer entries.
|
||||
//
|
||||
// Defer freeing any allocated blocks until after the next minor GC.
|
||||
fallbackStubSpace_.freeAllAfterMinorGC(zone);
|
||||
}
|
||||
|
||||
FallbackICStubSpace* fallbackStubSpace() { return &fallbackStubSpace_; }
|
||||
|
||||
void addSizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf, size_t* data,
|
||||
size_t* fallbackStubs) const {
|
||||
*data += mallocSizeOf(this);
|
||||
|
||||
// |data| already includes the ICStubSpace itself, so use
|
||||
// sizeOfExcludingThis.
|
||||
*fallbackStubs += fallbackStubSpace_.sizeOfExcludingThis(mallocSizeOf);
|
||||
}
|
||||
|
||||
size_t numICEntries() const { return numICEntries_; }
|
||||
|
||||
ICEntry& icEntry(size_t index) {
|
||||
MOZ_ASSERT(index < numICEntries());
|
||||
return icEntryList()[index];
|
||||
}
|
||||
|
||||
void noteAccessedGetter(uint32_t pcOffset);
|
||||
void noteHasDenseAdd(uint32_t pcOffset);
|
||||
|
||||
void trace(JSTracer* trc);
|
||||
void purgeOptimizedStubs(JSScript* script);
|
||||
|
||||
ICEntry* interpreterICEntryFromPCOffset(uint32_t pcOffset);
|
||||
|
||||
ICEntry* maybeICEntryFromPCOffset(uint32_t pcOffset);
|
||||
ICEntry* maybeICEntryFromPCOffset(uint32_t pcOffset,
|
||||
ICEntry* prevLookedUpEntry);
|
||||
|
||||
ICEntry& icEntryFromPCOffset(uint32_t pcOffset);
|
||||
ICEntry& icEntryFromPCOffset(uint32_t pcOffset, ICEntry* prevLookedUpEntry);
|
||||
|
||||
static constexpr size_t offsetOfICEntries() { return sizeof(ICScript); }
|
||||
};
|
||||
|
||||
class ICMonitoredStub;
|
||||
class ICMonitoredFallbackStub;
|
||||
|
||||
|
|
|
@ -127,7 +127,10 @@ static bool GetCacheIRReceiverForNativeSetSlot(ICCacheIR_Updated* stub,
|
|||
return true;
|
||||
}
|
||||
|
||||
ICScript* BaselineInspector::icScript() const { return script->icScript(); }
|
||||
JitScript* BaselineInspector::jitScript() const {
|
||||
MOZ_ASSERT(script->hasJitScript());
|
||||
return script->jitScript();
|
||||
}
|
||||
|
||||
ICEntry& BaselineInspector::icEntryFromPC(jsbytecode* pc) {
|
||||
ICEntry* entry = maybeICEntryFromPC(pc);
|
||||
|
@ -136,9 +139,8 @@ ICEntry& BaselineInspector::icEntryFromPC(jsbytecode* pc) {
|
|||
}
|
||||
|
||||
ICEntry* BaselineInspector::maybeICEntryFromPC(jsbytecode* pc) {
|
||||
MOZ_ASSERT(hasICScript());
|
||||
MOZ_ASSERT(isValidPC(pc));
|
||||
ICEntry* ent = icScript()->maybeICEntryFromPCOffset(script->pcToOffset(pc),
|
||||
ICEntry* ent = jitScript()->maybeICEntryFromPCOffset(script->pcToOffset(pc),
|
||||
prevLookedUpEntry);
|
||||
if (!ent) {
|
||||
return nullptr;
|
||||
|
@ -156,10 +158,6 @@ bool BaselineInspector::maybeInfoForPropertyOp(jsbytecode* pc,
|
|||
// uncacheable access.
|
||||
MOZ_ASSERT(receivers.empty());
|
||||
|
||||
if (!hasICScript()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(isValidPC(pc));
|
||||
const ICEntry& entry = icEntryFromPC(pc);
|
||||
|
||||
|
@ -203,10 +201,6 @@ bool BaselineInspector::maybeInfoForPropertyOp(jsbytecode* pc,
|
|||
}
|
||||
|
||||
ICStub* BaselineInspector::monomorphicStub(jsbytecode* pc) {
|
||||
if (!hasICScript()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// IonBuilder::analyzeNewLoopTypes may call this (via expectedResultType
|
||||
// below) on code that's unreachable, according to BytecodeAnalysis. Use
|
||||
// maybeICEntryFromPC to handle this.
|
||||
|
@ -227,10 +221,6 @@ ICStub* BaselineInspector::monomorphicStub(jsbytecode* pc) {
|
|||
|
||||
bool BaselineInspector::dimorphicStub(jsbytecode* pc, ICStub** pfirst,
|
||||
ICStub** psecond) {
|
||||
if (!hasICScript()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const ICEntry& entry = icEntryFromPC(pc);
|
||||
|
||||
ICStub* stub = entry.firstStub();
|
||||
|
@ -575,10 +565,6 @@ static bool TryToSpecializeBinaryArithOp(ICStub** stubs, uint32_t nstubs,
|
|||
}
|
||||
|
||||
MIRType BaselineInspector::expectedBinaryArithSpecialization(jsbytecode* pc) {
|
||||
if (!hasICScript()) {
|
||||
return MIRType::None;
|
||||
}
|
||||
|
||||
MIRType result;
|
||||
ICStub* stubs[2];
|
||||
|
||||
|
@ -610,10 +596,6 @@ MIRType BaselineInspector::expectedBinaryArithSpecialization(jsbytecode* pc) {
|
|||
}
|
||||
|
||||
bool BaselineInspector::hasSeenNonIntegerIndex(jsbytecode* pc) {
|
||||
if (!hasICScript()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const ICEntry& entry = icEntryFromPC(pc);
|
||||
ICStub* stub = entry.fallbackStub();
|
||||
|
||||
|
@ -623,10 +605,6 @@ bool BaselineInspector::hasSeenNonIntegerIndex(jsbytecode* pc) {
|
|||
}
|
||||
|
||||
bool BaselineInspector::hasSeenNegativeIndexGetElement(jsbytecode* pc) {
|
||||
if (!hasICScript()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const ICEntry& entry = icEntryFromPC(pc);
|
||||
ICStub* stub = entry.fallbackStub();
|
||||
|
||||
|
@ -637,10 +615,6 @@ bool BaselineInspector::hasSeenNegativeIndexGetElement(jsbytecode* pc) {
|
|||
}
|
||||
|
||||
bool BaselineInspector::hasSeenAccessedGetter(jsbytecode* pc) {
|
||||
if (!hasICScript()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const ICEntry& entry = icEntryFromPC(pc);
|
||||
ICStub* stub = entry.fallbackStub();
|
||||
|
||||
|
@ -651,10 +625,6 @@ bool BaselineInspector::hasSeenAccessedGetter(jsbytecode* pc) {
|
|||
}
|
||||
|
||||
bool BaselineInspector::hasSeenDoubleResult(jsbytecode* pc) {
|
||||
if (!hasICScript()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const ICEntry& entry = icEntryFromPC(pc);
|
||||
ICStub* stub = entry.fallbackStub();
|
||||
|
||||
|
@ -720,10 +690,6 @@ JSObject* MaybeTemplateObject(ICStub* stub, MetaTwoByteKind kind,
|
|||
}
|
||||
|
||||
JSObject* BaselineInspector::getTemplateObject(jsbytecode* pc) {
|
||||
if (!hasICScript()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const ICEntry& entry = icEntryFromPC(pc);
|
||||
for (ICStub* stub = entry.firstStub(); stub; stub = stub->next()) {
|
||||
switch (stub->kind()) {
|
||||
|
@ -760,10 +726,6 @@ JSObject* BaselineInspector::getTemplateObject(jsbytecode* pc) {
|
|||
}
|
||||
|
||||
ObjectGroup* BaselineInspector::getTemplateObjectGroup(jsbytecode* pc) {
|
||||
if (!hasICScript()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const ICEntry& entry = icEntryFromPC(pc);
|
||||
for (ICStub* stub = entry.firstStub(); stub; stub = stub->next()) {
|
||||
switch (stub->kind()) {
|
||||
|
@ -780,10 +742,6 @@ ObjectGroup* BaselineInspector::getTemplateObjectGroup(jsbytecode* pc) {
|
|||
JSFunction* BaselineInspector::getSingleCallee(jsbytecode* pc) {
|
||||
MOZ_ASSERT(*pc == JSOP_NEW);
|
||||
|
||||
if (!hasICScript()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const ICEntry& entry = icEntryFromPC(pc);
|
||||
ICStub* stub = entry.firstStub();
|
||||
|
||||
|
@ -815,10 +773,6 @@ JSFunction* BaselineInspector::getSingleCallee(jsbytecode* pc) {
|
|||
|
||||
JSObject* BaselineInspector::getTemplateObjectForNative(jsbytecode* pc,
|
||||
Native native) {
|
||||
if (!hasICScript()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const ICEntry& entry = icEntryFromPC(pc);
|
||||
for (ICStub* stub = entry.firstStub(); stub; stub = stub->next()) {
|
||||
if (stub->isCall_Native() &&
|
||||
|
@ -845,10 +799,6 @@ JSObject* BaselineInspector::getTemplateObjectForNative(jsbytecode* pc,
|
|||
|
||||
JSObject* BaselineInspector::getTemplateObjectForClassHook(jsbytecode* pc,
|
||||
const Class* clasp) {
|
||||
if (!hasICScript()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const ICEntry& entry = icEntryFromPC(pc);
|
||||
for (ICStub* stub = entry.firstStub(); stub; stub = stub->next()) {
|
||||
if (stub->isCall_ClassHook() &&
|
||||
|
@ -1204,10 +1154,6 @@ bool BaselineInspector::commonGetPropFunction(
|
|||
jsbytecode* pc, jsid id, bool innerized, JSObject** holder,
|
||||
Shape** holderShape, JSFunction** commonGetter, Shape** globalShape,
|
||||
bool* isOwnProperty, ReceiverVector& receivers) {
|
||||
if (!hasICScript()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(IsGetPropPC(pc) || IsGetElemPC(pc) || JSOp(*pc) == JSOP_GETGNAME);
|
||||
MOZ_ASSERT(receivers.empty());
|
||||
|
||||
|
@ -1286,10 +1232,6 @@ static JSFunction* GetMegamorphicGetterSetterFunction(
|
|||
|
||||
bool BaselineInspector::megamorphicGetterSetterFunction(
|
||||
jsbytecode* pc, jsid id, bool isGetter, JSFunction** getterOrSetter) {
|
||||
if (!hasICScript()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(IsGetPropPC(pc) || IsGetElemPC(pc) || IsSetPropPC(pc) ||
|
||||
JSOp(*pc) == JSOP_GETGNAME || JSOp(*pc) == JSOP_INITGLEXICAL ||
|
||||
JSOp(*pc) == JSOP_INITPROP || JSOp(*pc) == JSOP_INITLOCKEDPROP ||
|
||||
|
@ -1451,10 +1393,6 @@ bool BaselineInspector::commonSetPropFunction(jsbytecode* pc, JSObject** holder,
|
|||
JSFunction** commonSetter,
|
||||
bool* isOwnProperty,
|
||||
ReceiverVector& receivers) {
|
||||
if (!hasICScript()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(IsSetPropPC(pc) || JSOp(*pc) == JSOP_INITGLEXICAL ||
|
||||
JSOp(*pc) == JSOP_INITPROP || JSOp(*pc) == JSOP_INITLOCKEDPROP ||
|
||||
JSOp(*pc) == JSOP_INITHIDDENPROP);
|
||||
|
@ -1551,10 +1489,6 @@ bool BaselineInspector::maybeInfoForProtoReadSlot(jsbytecode* pc,
|
|||
MOZ_ASSERT(receivers.empty());
|
||||
MOZ_ASSERT(!*holder);
|
||||
|
||||
if (!hasICScript()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(isValidPC(pc));
|
||||
const ICEntry& entry = icEntryFromPC(pc);
|
||||
|
||||
|
@ -1614,10 +1548,6 @@ static MIRType GetCacheIRExpectedInputType(ICCacheIR_Monitored* stub) {
|
|||
}
|
||||
|
||||
MIRType BaselineInspector::expectedPropertyAccessInputType(jsbytecode* pc) {
|
||||
if (!hasICScript()) {
|
||||
return MIRType::Value;
|
||||
}
|
||||
|
||||
const ICEntry& entry = icEntryFromPC(pc);
|
||||
MIRType type = MIRType::None;
|
||||
|
||||
|
@ -1653,9 +1583,6 @@ bool BaselineInspector::instanceOfData(jsbytecode* pc, Shape** shape,
|
|||
uint32_t* slot,
|
||||
JSObject** prototypeObject) {
|
||||
MOZ_ASSERT(*pc == JSOP_INSTANCEOF);
|
||||
if (!hasICScript()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const ICEntry& entry = icEntryFromPC(pc);
|
||||
ICStub* firstStub = entry.firstStub();
|
||||
|
|
|
@ -47,9 +47,7 @@ class BaselineInspector {
|
|||
MOZ_ASSERT(script);
|
||||
}
|
||||
|
||||
bool hasICScript() const { return script->hasICScript(); }
|
||||
|
||||
ICScript* icScript() const;
|
||||
JitScript* jitScript() const;
|
||||
|
||||
private:
|
||||
#ifdef DEBUG
|
||||
|
@ -62,11 +60,8 @@ class BaselineInspector {
|
|||
template <typename ICInspectorType>
|
||||
ICInspectorType makeICInspector(jsbytecode* pc,
|
||||
ICStub::Kind expectedFallbackKind) {
|
||||
ICEntry* ent = nullptr;
|
||||
if (hasICScript()) {
|
||||
ent = &icEntryFromPC(pc);
|
||||
ICEntry* ent = &icEntryFromPC(pc);
|
||||
MOZ_ASSERT(ent->fallbackStub()->kind() == expectedFallbackKind);
|
||||
}
|
||||
return ICInspectorType(this, pc, ent);
|
||||
}
|
||||
|
||||
|
|
|
@ -320,7 +320,7 @@ static MethodStatus CanEnterBaselineInterpreter(JSContext* cx,
|
|||
MOZ_ASSERT(jit::IsBaselineEnabled(cx));
|
||||
MOZ_ASSERT(JitOptions.baselineInterpreter);
|
||||
|
||||
if (script->types()) {
|
||||
if (script->jitScript()) {
|
||||
return Method_Compiled;
|
||||
}
|
||||
|
||||
|
@ -338,8 +338,8 @@ static MethodStatus CanEnterBaselineInterpreter(JSContext* cx,
|
|||
return Method_Error;
|
||||
}
|
||||
|
||||
AutoKeepTypeScripts keepTypes(cx);
|
||||
if (!script->ensureHasTypes(cx, keepTypes)) {
|
||||
AutoKeepJitScripts keepJitScript(cx);
|
||||
if (!script->ensureHasJitScript(cx, keepJitScript)) {
|
||||
return Method_Error;
|
||||
}
|
||||
|
||||
|
@ -517,7 +517,7 @@ void BaselineScript::trace(JSTracer* trc) {
|
|||
TraceNullableEdge(trc, &templateEnv_, "baseline-template-environment");
|
||||
}
|
||||
|
||||
void ICScript::trace(JSTracer* trc) {
|
||||
void JitScript::trace(JSTracer* trc) {
|
||||
// Mark all IC stub codes hanging off the IC stub entries.
|
||||
for (size_t i = 0; i < numICEntries(); i++) {
|
||||
ICEntry& ent = icEntry(i);
|
||||
|
@ -620,12 +620,12 @@ CompactBufferReader BaselineScript::pcMappingReader(size_t indexEntry) {
|
|||
}
|
||||
|
||||
struct ICEntries {
|
||||
ICScript* const icScript_;
|
||||
JitScript* const jitScript_;
|
||||
|
||||
explicit ICEntries(ICScript* icScript) : icScript_(icScript) {}
|
||||
explicit ICEntries(JitScript* jitScript) : jitScript_(jitScript) {}
|
||||
|
||||
size_t numEntries() const { return icScript_->numICEntries(); }
|
||||
ICEntry& operator[](size_t index) const { return icScript_->icEntry(index); }
|
||||
size_t numEntries() const { return jitScript_->numICEntries(); }
|
||||
ICEntry& operator[](size_t index) const { return jitScript_->icEntry(index); }
|
||||
};
|
||||
|
||||
struct RetAddrEntries {
|
||||
|
@ -712,7 +712,7 @@ uint8_t* BaselineScript::returnAddressForEntry(const RetAddrEntry& ent) {
|
|||
return method()->raw() + ent.returnOffset().offset();
|
||||
}
|
||||
|
||||
ICEntry* ICScript::maybeICEntryFromPCOffset(uint32_t pcOffset) {
|
||||
ICEntry* JitScript::maybeICEntryFromPCOffset(uint32_t pcOffset) {
|
||||
// This method ignores prologue IC entries. There can be at most one
|
||||
// non-prologue IC per bytecode op.
|
||||
|
||||
|
@ -729,13 +729,13 @@ ICEntry* ICScript::maybeICEntryFromPCOffset(uint32_t pcOffset) {
|
|||
return &entry;
|
||||
}
|
||||
|
||||
ICEntry& ICScript::icEntryFromPCOffset(uint32_t pcOffset) {
|
||||
ICEntry& JitScript::icEntryFromPCOffset(uint32_t pcOffset) {
|
||||
ICEntry* entry = maybeICEntryFromPCOffset(pcOffset);
|
||||
MOZ_RELEASE_ASSERT(entry);
|
||||
return *entry;
|
||||
}
|
||||
|
||||
ICEntry* ICScript::maybeICEntryFromPCOffset(uint32_t pcOffset,
|
||||
ICEntry* JitScript::maybeICEntryFromPCOffset(uint32_t pcOffset,
|
||||
ICEntry* prevLookedUpEntry) {
|
||||
// Do a linear forward search from the last queried PC offset, or fallback to
|
||||
// a binary search if the last offset is too far away.
|
||||
|
@ -756,14 +756,14 @@ ICEntry* ICScript::maybeICEntryFromPCOffset(uint32_t pcOffset,
|
|||
return maybeICEntryFromPCOffset(pcOffset);
|
||||
}
|
||||
|
||||
ICEntry& ICScript::icEntryFromPCOffset(uint32_t pcOffset,
|
||||
ICEntry& JitScript::icEntryFromPCOffset(uint32_t pcOffset,
|
||||
ICEntry* prevLookedUpEntry) {
|
||||
ICEntry* entry = maybeICEntryFromPCOffset(pcOffset, prevLookedUpEntry);
|
||||
MOZ_RELEASE_ASSERT(entry);
|
||||
return *entry;
|
||||
}
|
||||
|
||||
ICEntry* ICScript::interpreterICEntryFromPCOffset(uint32_t pcOffset) {
|
||||
ICEntry* JitScript::interpreterICEntryFromPCOffset(uint32_t pcOffset) {
|
||||
// We have to return the entry to store in BaselineFrame::interpreterICEntry
|
||||
// when resuming in the Baseline Interpreter at pcOffset. The bytecode op at
|
||||
// pcOffset does not necessarily have an ICEntry, so we want to return the
|
||||
|
@ -1197,8 +1197,8 @@ void BaselineInterpreter::toggleCodeCoverageInstrumentation(bool enable) {
|
|||
toggleCodeCoverageInstrumentationUnchecked(enable);
|
||||
}
|
||||
|
||||
void ICScript::purgeOptimizedStubs(JSScript* script) {
|
||||
MOZ_ASSERT(script->icScript() == this);
|
||||
void JitScript::purgeOptimizedStubs(JSScript* script) {
|
||||
MOZ_ASSERT(script->jitScript() == this);
|
||||
|
||||
Zone* zone = script->zone();
|
||||
if (zone->isGCSweeping() && IsAboutToBeFinalizedDuringSweep(*script)) {
|
||||
|
@ -1294,18 +1294,18 @@ bool HasEnteredCounters(ICEntry& entry) {
|
|||
}
|
||||
|
||||
void jit::JitSpewBaselineICStats(JSScript* script, const char* dumpReason) {
|
||||
MOZ_ASSERT(script->hasICScript());
|
||||
MOZ_ASSERT(script->hasJitScript());
|
||||
JSContext* cx = TlsContext.get();
|
||||
AutoStructuredSpewer spew(cx, SpewChannel::BaselineICStats, script);
|
||||
if (!spew) {
|
||||
return;
|
||||
}
|
||||
|
||||
ICScript* icScript = script->icScript();
|
||||
JitScript* jitScript = script->jitScript();
|
||||
spew->property("reason", dumpReason);
|
||||
spew->beginListProperty("entries");
|
||||
for (size_t i = 0; i < icScript->numICEntries(); i++) {
|
||||
ICEntry& entry = icScript->icEntry(i);
|
||||
for (size_t i = 0; i < jitScript->numICEntries(); i++) {
|
||||
ICEntry& entry = jitScript->icEntry(i);
|
||||
if (!HasEnteredCounters(entry)) {
|
||||
continue;
|
||||
}
|
||||
|
@ -1343,7 +1343,7 @@ void jit::JitSpewBaselineICStats(JSScript* script, const char* dumpReason) {
|
|||
|
||||
void jit::FinishDiscardBaselineScript(FreeOp* fop, JSScript* script) {
|
||||
MOZ_ASSERT(script->hasBaselineScript());
|
||||
MOZ_ASSERT(!script->types()->active());
|
||||
MOZ_ASSERT(!script->jitScript()->active());
|
||||
|
||||
BaselineScript* baseline = script->baselineScript();
|
||||
script->setBaselineScript(fop->runtime(), nullptr);
|
||||
|
@ -1352,13 +1352,7 @@ void jit::FinishDiscardBaselineScript(FreeOp* fop, JSScript* script) {
|
|||
|
||||
void jit::AddSizeOfBaselineData(JSScript* script,
|
||||
mozilla::MallocSizeOf mallocSizeOf,
|
||||
size_t* data, size_t* fallbackStubs) {
|
||||
if (script->hasICScript()) {
|
||||
// ICScript is stored in TypeScript but we report its size here and not
|
||||
// in TypeScript::sizeOfIncludingThis.
|
||||
script->icScript()->addSizeOfIncludingThis(mallocSizeOf, data,
|
||||
fallbackStubs);
|
||||
}
|
||||
size_t* data) {
|
||||
if (script->hasBaselineScript()) {
|
||||
script->baselineScript()->addSizeOfIncludingThis(mallocSizeOf, data);
|
||||
}
|
||||
|
@ -1416,13 +1410,13 @@ void jit::ToggleBaselineTraceLoggerEngine(JSRuntime* runtime, bool enable) {
|
|||
}
|
||||
#endif
|
||||
|
||||
static void MarkActiveTypeScripts(JSContext* cx,
|
||||
static void MarkActiveJitScripts(JSContext* cx,
|
||||
const JitActivationIterator& activation) {
|
||||
for (OnlyJSJitFrameIter iter(activation); !iter.done(); ++iter) {
|
||||
const JSJitFrameIter& frame = iter.frame();
|
||||
switch (frame.type()) {
|
||||
case FrameType::BaselineJS:
|
||||
frame.script()->types()->setActive();
|
||||
frame.script()->jitScript()->setActive();
|
||||
break;
|
||||
case FrameType::Exit:
|
||||
if (frame.exitFrame()->is<LazyLinkExitFrameLayout>()) {
|
||||
|
@ -1430,17 +1424,17 @@ static void MarkActiveTypeScripts(JSContext* cx,
|
|||
frame.exitFrame()->as<LazyLinkExitFrameLayout>();
|
||||
JSScript* script =
|
||||
ScriptFromCalleeToken(ll->jsFrame()->calleeToken());
|
||||
script->types()->setActive();
|
||||
script->jitScript()->setActive();
|
||||
}
|
||||
break;
|
||||
case FrameType::Bailout:
|
||||
case FrameType::IonJS: {
|
||||
// Keep the TypeScript and BaselineScript around, since bailouts from
|
||||
// Keep the JitScript and BaselineScript around, since bailouts from
|
||||
// the ion jitcode need to re-enter into the Baseline code.
|
||||
frame.script()->types()->setActive();
|
||||
frame.script()->jitScript()->setActive();
|
||||
for (InlineFrameIterator inlineIter(cx, &frame); inlineIter.more();
|
||||
++inlineIter) {
|
||||
inlineIter.script()->types()->setActive();
|
||||
inlineIter.script()->jitScript()->setActive();
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -1449,14 +1443,14 @@ static void MarkActiveTypeScripts(JSContext* cx,
|
|||
}
|
||||
}
|
||||
|
||||
void jit::MarkActiveTypeScripts(Zone* zone) {
|
||||
void jit::MarkActiveJitScripts(Zone* zone) {
|
||||
if (zone->isAtomsZone()) {
|
||||
return;
|
||||
}
|
||||
JSContext* cx = TlsContext.get();
|
||||
for (JitActivationIterator iter(cx); !iter.done(); ++iter) {
|
||||
if (iter->compartment()->zone() == zone) {
|
||||
MarkActiveTypeScripts(cx, iter);
|
||||
MarkActiveJitScripts(cx, iter);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -575,7 +575,7 @@ bool BaselineCompileFromBaselineInterpreter(JSContext* cx, BaselineFrame* frame,
|
|||
void FinishDiscardBaselineScript(FreeOp* fop, JSScript* script);
|
||||
|
||||
void AddSizeOfBaselineData(JSScript* script, mozilla::MallocSizeOf mallocSizeOf,
|
||||
size_t* data, size_t* fallbackStubs);
|
||||
size_t* data);
|
||||
|
||||
void ToggleBaselineProfiling(JSRuntime* runtime, bool enable);
|
||||
|
||||
|
@ -638,9 +638,9 @@ MOZ_MUST_USE bool BailoutIonToBaseline(
|
|||
bool invalidate, BaselineBailoutInfo** bailoutInfo,
|
||||
const ExceptionBailoutInfo* exceptionInfo);
|
||||
|
||||
// Mark TypeScripts on the stack as active, so that they are not discarded
|
||||
// Mark JitScripts on the stack as active, so that they are not discarded
|
||||
// during GC.
|
||||
void MarkActiveTypeScripts(Zone* zone);
|
||||
void MarkActiveJitScripts(Zone* zone);
|
||||
|
||||
MethodStatus BaselineCompile(JSContext* cx, JSScript* script,
|
||||
bool forceDebugInstrumentation = false);
|
||||
|
|
|
@ -3146,8 +3146,8 @@ void jit::TraceJitScripts(JSTracer* trc, JSScript* script) {
|
|||
jit::BaselineScript::Trace(trc, script->baselineScript());
|
||||
}
|
||||
|
||||
if (script->hasICScript()) {
|
||||
script->icScript()->trace(trc);
|
||||
if (script->hasJitScript()) {
|
||||
script->jitScript()->trace(trc);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -4554,7 +4554,7 @@ bool jit::AnalyzeNewScriptDefiniteProperties(
|
|||
}
|
||||
}
|
||||
|
||||
TypeScript::MonitorThisType(cx, script, TypeSet::ObjectType(group));
|
||||
JitScript::MonitorThisType(cx, script, TypeSet::ObjectType(group));
|
||||
|
||||
MIRGraph graph(&temp);
|
||||
InlineScriptTree* inlineScriptTree =
|
||||
|
@ -4800,8 +4800,8 @@ bool jit::AnalyzeArgumentsUsage(JSContext* cx, JSScript* scriptArg) {
|
|||
return false;
|
||||
}
|
||||
|
||||
AutoKeepTypeScripts keepTypes(cx);
|
||||
if (!script->ensureHasTypes(cx, keepTypes)) {
|
||||
AutoKeepJitScripts keepJitScript(cx);
|
||||
if (!script->ensureHasJitScript(cx, keepJitScript)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -755,7 +755,7 @@ AbortReasonOr<Ok> IonBuilder::analyzeNewLoopTypes(
|
|||
AbortReasonOr<Ok> IonBuilder::init() {
|
||||
{
|
||||
LifoAlloc::AutoFallibleScope fallibleAllocator(alloc().lifoAlloc());
|
||||
if (!TypeScript::FreezeTypeSets(constraints(), script(), &thisTypes,
|
||||
if (!JitScript::FreezeTypeSets(constraints(), script(), &thisTypes,
|
||||
&argTypes, &typeArray)) {
|
||||
return abort(AbortReason::Alloc);
|
||||
}
|
||||
|
@ -773,7 +773,7 @@ AbortReasonOr<Ok> IonBuilder::init() {
|
|||
argTypes = nullptr;
|
||||
}
|
||||
|
||||
bytecodeTypeMap = script()->types()->bytecodeTypeMap();
|
||||
bytecodeTypeMap = script()->jitScript()->bytecodeTypeMap();
|
||||
|
||||
return Ok();
|
||||
}
|
||||
|
@ -4050,8 +4050,9 @@ IonBuilder::InliningResult IonBuilder::inlineScriptedCall(CallInfo& callInfo,
|
|||
|
||||
// Improve type information of |this| when not set.
|
||||
if (callInfo.constructing() && !callInfo.thisArg()->resultTypeSet()) {
|
||||
AutoSweepTypeScript sweep(calleeScript);
|
||||
StackTypeSet* types = calleeScript->types()->thisTypes(sweep, calleeScript);
|
||||
AutoSweepJitScript sweep(calleeScript);
|
||||
StackTypeSet* types =
|
||||
calleeScript->jitScript()->thisTypes(sweep, calleeScript);
|
||||
if (!types->unknown()) {
|
||||
TemporaryTypeSet* clonedTypes = types->clone(alloc_->lifoAlloc());
|
||||
if (!clonedTypes) {
|
||||
|
@ -5332,13 +5333,13 @@ MDefinition* IonBuilder::createThisScriptedSingleton(JSFunction* target) {
|
|||
}
|
||||
|
||||
JSScript* targetScript = target->nonLazyScript();
|
||||
TypeScript* typeScript = targetScript->types();
|
||||
if (!typeScript) {
|
||||
JitScript* jitScript = targetScript->jitScript();
|
||||
if (!jitScript) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
AutoSweepTypeScript sweep(targetScript);
|
||||
StackTypeSet* thisTypes = typeScript->thisTypes(sweep, targetScript);
|
||||
AutoSweepJitScript sweep(targetScript);
|
||||
StackTypeSet* thisTypes = jitScript->thisTypes(sweep, targetScript);
|
||||
if (!thisTypes->hasType(TypeSet::ObjectType(templateObject))) {
|
||||
return nullptr;
|
||||
}
|
||||
|
@ -5402,13 +5403,13 @@ MDefinition* IonBuilder::createThisScriptedBaseline(MDefinition* callee) {
|
|||
}
|
||||
|
||||
JSScript* targetScript = target->nonLazyScript();
|
||||
TypeScript* typeScript = targetScript->types();
|
||||
if (!typeScript) {
|
||||
JitScript* jitScript = targetScript->jitScript();
|
||||
if (!jitScript) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
AutoSweepTypeScript sweep(targetScript);
|
||||
StackTypeSet* thisTypes = typeScript->thisTypes(sweep, targetScript);
|
||||
AutoSweepJitScript sweep(targetScript);
|
||||
StackTypeSet* thisTypes = jitScript->thisTypes(sweep, targetScript);
|
||||
if (!thisTypes->hasType(TypeSet::ObjectType(templateObject))) {
|
||||
return nullptr;
|
||||
}
|
||||
|
@ -6095,25 +6096,25 @@ bool IonBuilder::testNeedsArgumentCheck(JSFunction* target,
|
|||
}
|
||||
|
||||
JSScript* targetScript = target->nonLazyScript();
|
||||
TypeScript* typeScript = targetScript->types();
|
||||
if (!typeScript) {
|
||||
JitScript* jitScript = targetScript->jitScript();
|
||||
if (!jitScript) {
|
||||
return true;
|
||||
}
|
||||
|
||||
AutoSweepTypeScript sweep(targetScript);
|
||||
AutoSweepJitScript sweep(targetScript);
|
||||
if (!ArgumentTypesMatch(callInfo.thisArg(),
|
||||
typeScript->thisTypes(sweep, targetScript))) {
|
||||
jitScript->thisTypes(sweep, targetScript))) {
|
||||
return true;
|
||||
}
|
||||
uint32_t expected_args = Min<uint32_t>(callInfo.argc(), target->nargs());
|
||||
for (size_t i = 0; i < expected_args; i++) {
|
||||
if (!ArgumentTypesMatch(callInfo.getArg(i),
|
||||
typeScript->argTypes(sweep, targetScript, i))) {
|
||||
jitScript->argTypes(sweep, targetScript, i))) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
for (size_t i = callInfo.argc(); i < target->nargs(); i++) {
|
||||
StackTypeSet* types = typeScript->argTypes(sweep, targetScript, i);
|
||||
StackTypeSet* types = jitScript->argTypes(sweep, targetScript, i);
|
||||
if (!types->mightBeMIRType(MIRType::Undefined)) {
|
||||
return true;
|
||||
}
|
||||
|
@ -13585,8 +13586,8 @@ MInstruction* IonBuilder::addSharedTypedArrayGuard(MDefinition* obj) {
|
|||
}
|
||||
|
||||
TemporaryTypeSet* IonBuilder::bytecodeTypes(jsbytecode* pc) {
|
||||
return TypeScript::BytecodeTypes(script(), pc, bytecodeTypeMap,
|
||||
&typeArrayHint, typeArray);
|
||||
return JitScript::BytecodeTypes(script(), pc, bytecodeTypeMap, &typeArrayHint,
|
||||
typeArray);
|
||||
}
|
||||
|
||||
TypedObjectPrediction IonBuilder::typedObjectPrediction(MDefinition* typedObj) {
|
||||
|
|
|
@ -228,7 +228,7 @@ bool IonGetPropertyIC::update(JSContext* cx, HandleScript outerScript,
|
|||
if (!ic->idempotent()) {
|
||||
// Monitor changes to cache entry.
|
||||
if (!ic->monitoredResult()) {
|
||||
TypeScript::MonitorBytecodeType(cx, ic->script(), ic->pc(), res);
|
||||
JitScript::MonitorBytecodeType(cx, ic->script(), ic->pc(), res);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -263,7 +263,7 @@ bool IonGetPropSuperIC::update(JSContext* cx, HandleScript outerScript,
|
|||
}
|
||||
|
||||
// Monitor changes to cache entry.
|
||||
TypeScript::MonitorBytecodeType(cx, ic->script(), ic->pc(), res);
|
||||
JitScript::MonitorBytecodeType(cx, ic->script(), ic->pc(), res);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -425,7 +425,7 @@ bool IonGetNameIC::update(JSContext* cx, HandleScript outerScript,
|
|||
}
|
||||
}
|
||||
|
||||
// No need to call TypeScript::Monitor, IonBuilder always inserts a type
|
||||
// No need to call JitScript::Monitor, IonBuilder always inserts a type
|
||||
// barrier after GetName ICs.
|
||||
|
||||
return true;
|
||||
|
|
|
@ -141,7 +141,7 @@ EnterJitStatus js::jit::MaybeEnterJit(JSContext* cx, RunState& state) {
|
|||
// Make sure we can enter Baseline Interpreter or JIT code. Note that
|
||||
// the prologue has warm-up checks to tier up if needed.
|
||||
if (JitOptions.baselineInterpreter) {
|
||||
if (script->types()) {
|
||||
if (script->jitScript()) {
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
|
|
|
@ -0,0 +1,106 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
* vim: set ts=8 sts=2 et sw=2 tw=80:
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef jit_JitScript_inl_h
|
||||
#define jit_JitScript_inl_h
|
||||
|
||||
#include "jit/JitScript.h"
|
||||
|
||||
#include "mozilla/BinarySearch.h"
|
||||
|
||||
#include "vm/JSScript.h"
|
||||
#include "vm/TypeInference.h"
|
||||
|
||||
#include "vm/JSContext-inl.h"
|
||||
|
||||
namespace js {
|
||||
|
||||
inline StackTypeSet* JitScript::thisTypes(const AutoSweepJitScript& sweep,
|
||||
JSScript* script) {
|
||||
return typeArray(sweep) + script->numBytecodeTypeSets();
|
||||
}
|
||||
|
||||
/*
|
||||
* Note: for non-escaping arguments, argTypes reflect only the initial type of
|
||||
* the variable (e.g. passed values for argTypes, or undefined for localTypes)
|
||||
* and not types from subsequent assignments.
|
||||
*/
|
||||
|
||||
inline StackTypeSet* JitScript::argTypes(const AutoSweepJitScript& sweep,
|
||||
JSScript* script, unsigned i) {
|
||||
MOZ_ASSERT(i < script->functionNonDelazifying()->nargs());
|
||||
return typeArray(sweep) + script->numBytecodeTypeSets() + 1 /* this */ + i;
|
||||
}
|
||||
|
||||
template <typename TYPESET>
|
||||
/* static */ inline TYPESET* JitScript::BytecodeTypes(JSScript* script,
|
||||
jsbytecode* pc,
|
||||
uint32_t* bytecodeMap,
|
||||
uint32_t* hint,
|
||||
TYPESET* typeArray) {
|
||||
MOZ_ASSERT(CodeSpec[*pc].format & JOF_TYPESET);
|
||||
uint32_t offset = script->pcToOffset(pc);
|
||||
|
||||
// See if this pc is the next typeset opcode after the last one looked up.
|
||||
size_t numBytecodeTypeSets = script->numBytecodeTypeSets();
|
||||
if ((*hint + 1) < numBytecodeTypeSets && bytecodeMap[*hint + 1] == offset) {
|
||||
(*hint)++;
|
||||
return typeArray + *hint;
|
||||
}
|
||||
|
||||
// See if this pc is the same as the last one looked up.
|
||||
if (bytecodeMap[*hint] == offset) {
|
||||
return typeArray + *hint;
|
||||
}
|
||||
|
||||
// Fall back to a binary search. We'll either find the exact offset, or
|
||||
// there are more JOF_TYPESET opcodes than nTypeSets in the script (as can
|
||||
// happen if the script is very long) and we'll use the last location.
|
||||
size_t loc;
|
||||
bool found =
|
||||
mozilla::BinarySearch(bytecodeMap, 0, numBytecodeTypeSets, offset, &loc);
|
||||
if (found) {
|
||||
MOZ_ASSERT(bytecodeMap[loc] == offset);
|
||||
} else {
|
||||
MOZ_ASSERT(numBytecodeTypeSets == JSScript::MaxBytecodeTypeSets);
|
||||
loc = numBytecodeTypeSets - 1;
|
||||
}
|
||||
|
||||
*hint = mozilla::AssertedCast<uint32_t>(loc);
|
||||
return typeArray + *hint;
|
||||
}
|
||||
|
||||
inline StackTypeSet* JitScript::bytecodeTypes(const AutoSweepJitScript& sweep,
|
||||
JSScript* script,
|
||||
jsbytecode* pc) {
|
||||
MOZ_ASSERT(CurrentThreadCanAccessZone(script->zone()));
|
||||
return BytecodeTypes(script, pc, bytecodeTypeMap(), bytecodeTypeMapHint(),
|
||||
typeArray(sweep));
|
||||
}
|
||||
|
||||
inline AutoKeepJitScripts::AutoKeepJitScripts(JSContext* cx)
|
||||
: zone_(cx->zone()->types), prev_(zone_.keepJitScripts) {
|
||||
zone_.keepJitScripts = true;
|
||||
}
|
||||
|
||||
inline AutoKeepJitScripts::~AutoKeepJitScripts() {
|
||||
MOZ_ASSERT(zone_.keepJitScripts);
|
||||
zone_.keepJitScripts = prev_;
|
||||
}
|
||||
|
||||
inline bool JitScript::typesNeedsSweep(Zone* zone) const {
|
||||
MOZ_ASSERT(!js::TlsContext.get()->inUnsafeCallWithABI);
|
||||
return typesGeneration() != zone->types.generation;
|
||||
}
|
||||
|
||||
} // namespace js
|
||||
|
||||
inline bool JSScript::ensureHasJitScript(JSContext* cx,
|
||||
js::AutoKeepJitScripts&) {
|
||||
return jitScript() || createJitScript(cx);
|
||||
}
|
||||
|
||||
#endif /* jit_JitScript_inl_h */
|
|
@ -0,0 +1,237 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
* vim: set ts=8 sts=2 et sw=2 tw=80:
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "jit/JitScript-inl.h"
|
||||
|
||||
#include "mozilla/IntegerPrintfMacros.h"
|
||||
#include "mozilla/Move.h"
|
||||
#include "mozilla/ScopeExit.h"
|
||||
|
||||
#include "jit/BaselineIC.h"
|
||||
#include "vm/JSScript.h"
|
||||
#include "vm/TypeInference.h"
|
||||
|
||||
#include "vm/JSScript-inl.h"
|
||||
#include "vm/TypeInference-inl.h"
|
||||
|
||||
using namespace js;
|
||||
using namespace js::jit;
|
||||
|
||||
static void FillBytecodeTypeMap(JSScript* script, uint32_t* bytecodeMap) {
|
||||
uint32_t added = 0;
|
||||
for (jsbytecode* pc = script->code(); pc < script->codeEnd();
|
||||
pc += GetBytecodeLength(pc)) {
|
||||
JSOp op = JSOp(*pc);
|
||||
if (CodeSpec[op].format & JOF_TYPESET) {
|
||||
bytecodeMap[added++] = script->pcToOffset(pc);
|
||||
if (added == script->numBytecodeTypeSets()) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
MOZ_ASSERT(added == script->numBytecodeTypeSets());
|
||||
}
|
||||
|
||||
static size_t NumTypeSets(JSScript* script) {
|
||||
// We rely on |num| not overflowing below.
|
||||
static_assert(JSScript::MaxBytecodeTypeSets == UINT16_MAX,
|
||||
"JSScript typesets should have safe range to avoid overflow");
|
||||
static_assert(JSFunction::NArgsBits == 16,
|
||||
"JSFunction nargs should have safe range to avoid overflow");
|
||||
|
||||
size_t num = script->numBytecodeTypeSets() + 1 /* this */;
|
||||
if (JSFunction* fun = script->functionNonDelazifying()) {
|
||||
num += fun->nargs();
|
||||
}
|
||||
|
||||
return num;
|
||||
}
|
||||
|
||||
JitScript::JitScript(JSScript* script, uint32_t typeSetOffset,
|
||||
uint32_t bytecodeTypeMapOffset)
|
||||
: typeSetOffset_(typeSetOffset),
|
||||
bytecodeTypeMapOffset_(bytecodeTypeMapOffset) {
|
||||
setTypesGeneration(script->zone()->types.generation);
|
||||
|
||||
StackTypeSet* array = typeArrayDontCheckGeneration();
|
||||
for (uint32_t i = 0, len = numTypeSets(); i < len; i++) {
|
||||
new (&array[i]) StackTypeSet();
|
||||
}
|
||||
|
||||
FillBytecodeTypeMap(script, bytecodeTypeMap());
|
||||
}
|
||||
|
||||
bool JSScript::createJitScript(JSContext* cx) {
|
||||
MOZ_ASSERT(!jitScript_);
|
||||
cx->check(this);
|
||||
|
||||
// Scripts that will never run in the Baseline Interpreter or the JITs don't
|
||||
// need a JitScript.
|
||||
MOZ_ASSERT(!hasForceInterpreterOp());
|
||||
|
||||
AutoEnterAnalysis enter(cx);
|
||||
|
||||
// Run the arguments-analysis if needed. Both the Baseline Interpreter and
|
||||
// Compiler rely on this.
|
||||
if (!ensureHasAnalyzedArgsUsage(cx)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// If ensureHasAnalyzedArgsUsage allocated the JitScript we're done.
|
||||
if (jitScript_) {
|
||||
return true;
|
||||
}
|
||||
|
||||
size_t numTypeSets = NumTypeSets(this);
|
||||
|
||||
static_assert(sizeof(JitScript) % sizeof(uintptr_t) == 0,
|
||||
"Trailing arrays must be aligned properly");
|
||||
static_assert(sizeof(ICEntry) % sizeof(uintptr_t) == 0,
|
||||
"Trailing arrays must be aligned properly");
|
||||
static_assert(sizeof(StackTypeSet) % sizeof(uintptr_t) == 0,
|
||||
"Trailing arrays must be aligned properly");
|
||||
|
||||
// Calculate allocation size.
|
||||
CheckedInt<uint32_t> allocSize = sizeof(JitScript);
|
||||
allocSize += CheckedInt<uint32_t>(numICEntries()) * sizeof(ICEntry);
|
||||
allocSize += CheckedInt<uint32_t>(numTypeSets) * sizeof(StackTypeSet);
|
||||
allocSize += CheckedInt<uint32_t>(numBytecodeTypeSets()) * sizeof(uint32_t);
|
||||
if (!allocSize.isValid()) {
|
||||
ReportAllocationOverflow(cx);
|
||||
return false;
|
||||
}
|
||||
|
||||
void* raw = cx->pod_malloc<uint8_t>(allocSize.value());
|
||||
MOZ_ASSERT(uintptr_t(raw) % alignof(JitScript) == 0);
|
||||
if (!raw) {
|
||||
return false;
|
||||
}
|
||||
|
||||
uint32_t typeSetOffset = sizeof(JitScript) + numICEntries() * sizeof(ICEntry);
|
||||
uint32_t bytecodeTypeMapOffset =
|
||||
typeSetOffset + numTypeSets * sizeof(StackTypeSet);
|
||||
UniquePtr<JitScript> jitScript(
|
||||
new (raw) JitScript(this, typeSetOffset, bytecodeTypeMapOffset));
|
||||
|
||||
// Sanity check the length computations.
|
||||
MOZ_ASSERT(jitScript->numICEntries() == numICEntries());
|
||||
MOZ_ASSERT(jitScript->numTypeSets() == numTypeSets);
|
||||
|
||||
// We need to call prepareForDestruction on JitScript before we |delete| it.
|
||||
auto prepareForDestruction = mozilla::MakeScopeExit(
|
||||
[&] { jitScript->prepareForDestruction(cx->zone()); });
|
||||
|
||||
if (!jitScript->initICEntries(cx, this)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(!jitScript_);
|
||||
prepareForDestruction.release();
|
||||
jitScript_ = jitScript.release();
|
||||
|
||||
// We have a JitScript so we can set the script's jitCodeRaw_ pointer to the
|
||||
// Baseline Interpreter code.
|
||||
updateJitCodeRaw(cx->runtime());
|
||||
|
||||
#ifdef DEBUG
|
||||
AutoSweepJitScript sweep(this);
|
||||
StackTypeSet* typeArray = jitScript_->typeArrayDontCheckGeneration();
|
||||
for (unsigned i = 0; i < numBytecodeTypeSets(); i++) {
|
||||
InferSpew(ISpewOps, "typeSet: %sT%p%s bytecode%u %p",
|
||||
InferSpewColor(&typeArray[i]), &typeArray[i],
|
||||
InferSpewColorReset(), i, this);
|
||||
}
|
||||
StackTypeSet* thisTypes = jitScript_->thisTypes(sweep, this);
|
||||
InferSpew(ISpewOps, "typeSet: %sT%p%s this %p", InferSpewColor(thisTypes),
|
||||
thisTypes, InferSpewColorReset(), this);
|
||||
unsigned nargs =
|
||||
functionNonDelazifying() ? functionNonDelazifying()->nargs() : 0;
|
||||
for (unsigned i = 0; i < nargs; i++) {
|
||||
StackTypeSet* types = jitScript_->argTypes(sweep, this, i);
|
||||
InferSpew(ISpewOps, "typeSet: %sT%p%s arg%u %p", InferSpewColor(types),
|
||||
types, InferSpewColorReset(), i, this);
|
||||
}
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void JSScript::maybeReleaseJitScript() {
|
||||
if (!jitScript_ || zone()->types.keepJitScripts || hasBaselineScript() ||
|
||||
jitScript_->active()) {
|
||||
return;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(!hasIonScript());
|
||||
|
||||
jitScript_->destroy(zone());
|
||||
jitScript_ = nullptr;
|
||||
updateJitCodeRaw(runtimeFromMainThread());
|
||||
}
|
||||
|
||||
void JitScript::destroy(Zone* zone) {
|
||||
prepareForDestruction(zone);
|
||||
js_delete(this);
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
void JitScript::printTypes(JSContext* cx, HandleScript script) {
|
||||
AutoSweepJitScript sweep(script);
|
||||
MOZ_ASSERT(script->jitScript() == this);
|
||||
|
||||
AutoEnterAnalysis enter(nullptr, script->zone());
|
||||
Fprinter out(stderr);
|
||||
|
||||
if (script->functionNonDelazifying()) {
|
||||
fprintf(stderr, "Function");
|
||||
} else if (script->isForEval()) {
|
||||
fprintf(stderr, "Eval");
|
||||
} else {
|
||||
fprintf(stderr, "Main");
|
||||
}
|
||||
fprintf(stderr, " %#" PRIxPTR " %s:%u ", uintptr_t(script.get()),
|
||||
script->filename(), script->lineno());
|
||||
|
||||
if (script->functionNonDelazifying()) {
|
||||
if (JSAtom* name = script->functionNonDelazifying()->explicitName()) {
|
||||
name->dumpCharsNoNewline(out);
|
||||
}
|
||||
}
|
||||
|
||||
fprintf(stderr, "\n this:");
|
||||
thisTypes(sweep, script)->print();
|
||||
|
||||
for (unsigned i = 0; script->functionNonDelazifying() &&
|
||||
i < script->functionNonDelazifying()->nargs();
|
||||
i++) {
|
||||
fprintf(stderr, "\n arg%u:", i);
|
||||
argTypes(sweep, script, i)->print();
|
||||
}
|
||||
fprintf(stderr, "\n");
|
||||
|
||||
for (jsbytecode* pc = script->code(); pc < script->codeEnd();
|
||||
pc += GetBytecodeLength(pc)) {
|
||||
{
|
||||
fprintf(stderr, "%p:", script.get());
|
||||
Sprinter sprinter(cx);
|
||||
if (!sprinter.init()) {
|
||||
return;
|
||||
}
|
||||
Disassemble1(cx, script, pc, script->pcToOffset(pc), true, &sprinter);
|
||||
fprintf(stderr, "%s", sprinter.string());
|
||||
}
|
||||
|
||||
if (CodeSpec[*pc].format & JOF_TYPESET) {
|
||||
StackTypeSet* types = bytecodeTypes(sweep, script, pc);
|
||||
fprintf(stderr, " typeset %u:", unsigned(types - typeArray(sweep)));
|
||||
types->print();
|
||||
fprintf(stderr, "\n");
|
||||
}
|
||||
}
|
||||
|
||||
fprintf(stderr, "\n");
|
||||
}
|
||||
#endif /* DEBUG */
|
|
@ -0,0 +1,308 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
* vim: set ts=8 sts=2 et sw=2 tw=80:
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef jit_JitScript_h
|
||||
#define jit_JitScript_h
|
||||
|
||||
#include "jit/BaselineIC.h"
|
||||
#include "js/UniquePtr.h"
|
||||
#include "vm/TypeInference.h"
|
||||
|
||||
class JSScript;
|
||||
|
||||
namespace js {
|
||||
|
||||
// [SMDOC] JitScript
|
||||
//
|
||||
// JitScript stores type inference data, Baseline ICs and other JIT-related data
|
||||
// for a script. Scripts with a JitScript can run in the Baseline Interpreter.
|
||||
//
|
||||
// IC Data
|
||||
// -------
|
||||
//
|
||||
// JitScript contains IC data used by Baseline (Interpreter and JIT). Ion has
|
||||
// its own IC chains stored in IonScript.
|
||||
//
|
||||
// For each IC we store an ICEntry, which points to the first ICStub in the
|
||||
// chain. Note that multiple stubs in the same zone can share Baseline IC code.
|
||||
// This works because the stub data is stored in the ICStub instead of baked in
|
||||
// in the stub code.
|
||||
//
|
||||
// Storing this separate from BaselineScript allows us to use the same ICs in
|
||||
// the Baseline Interpreter and Baseline JIT. It also simplifies debug mode OSR
|
||||
// because the JitScript can be reused when we have to recompile the
|
||||
// BaselineScript.
|
||||
//
|
||||
// JitScript contains the following IC data structures:
|
||||
//
|
||||
// * Fallback stub space: this stores all fallback stubs and the "can GC" stubs.
|
||||
// These stubs are never purged before destroying the JitScript. (Other stubs
|
||||
// are stored in the optimized stub space stored in JitZone and can be
|
||||
// discarded more eagerly. See JitScript::purgeOptimizedStubs.)
|
||||
//
|
||||
// * List of IC entries, in the following order:
|
||||
//
|
||||
// - Type monitor IC for |this|.
|
||||
// - Type monitor IC for each formal argument.
|
||||
// - IC for each JOF_IC bytecode op.
|
||||
//
|
||||
// Memory Layout
|
||||
// -------------
|
||||
//
|
||||
// JitScript has various trailing (variable-length) arrays. The memory layout is
|
||||
// as follows:
|
||||
//
|
||||
// Item | Offset
|
||||
// ------------------------+------------------------
|
||||
// JitScript | 0
|
||||
// ICEntry[] | sizeof(JitScript)
|
||||
// StackTypeSet[] | typeSetOffset_
|
||||
// uint32_t[] | bytecodeTypeMapOffset_
|
||||
// (= bytecode type map) |
|
||||
//
|
||||
// These offsets are also used to compute numICEntries and numTypeSets.
|
||||
class alignas(uintptr_t) JitScript final {
|
||||
friend class ::JSScript;
|
||||
|
||||
// Allocated space for fallback IC stubs.
|
||||
jit::FallbackICStubSpace fallbackStubSpace_ = {};
|
||||
|
||||
// The freeze constraints added to stack type sets will only directly
|
||||
// invalidate the script containing those stack type sets. This Vector
|
||||
// contains compilations that inlined this script, so we can invalidate
|
||||
// them as well.
|
||||
RecompileInfoVector inlinedCompilations_;
|
||||
|
||||
// Offset of the StackTypeSet array.
|
||||
uint32_t typeSetOffset_ = 0;
|
||||
|
||||
// Offset of the bytecode type map.
|
||||
uint32_t bytecodeTypeMapOffset_ = 0;
|
||||
|
||||
// This field is used to avoid binary searches for the sought entry when
|
||||
// bytecode map queries are in linear order.
|
||||
uint32_t bytecodeTypeMapHint_ = 0;
|
||||
|
||||
struct Flags {
|
||||
// Flag set when discarding JIT code to indicate this script is on the stack
|
||||
// and type information and JIT code should not be discarded.
|
||||
bool active : 1;
|
||||
|
||||
// Generation for type sweeping. If out of sync with the TypeZone's
|
||||
// generation, this JitScript needs to be swept.
|
||||
bool typesGeneration : 1;
|
||||
|
||||
// Whether freeze constraints for stack type sets have been generated.
|
||||
bool hasFreezeConstraints : 1;
|
||||
};
|
||||
Flags flags_ = {}; // Zero-initialize flags.
|
||||
|
||||
jit::ICEntry* icEntries() {
|
||||
uint8_t* base = reinterpret_cast<uint8_t*>(this);
|
||||
return reinterpret_cast<jit::ICEntry*>(base + offsetOfICEntries());
|
||||
}
|
||||
|
||||
StackTypeSet* typeArrayDontCheckGeneration() {
|
||||
uint8_t* base = reinterpret_cast<uint8_t*>(this);
|
||||
return reinterpret_cast<StackTypeSet*>(base + typeSetOffset_);
|
||||
}
|
||||
|
||||
uint32_t typesGeneration() const { return uint32_t(flags_.typesGeneration); }
|
||||
void setTypesGeneration(uint32_t generation) {
|
||||
MOZ_ASSERT(generation <= 1);
|
||||
flags_.typesGeneration = generation;
|
||||
}
|
||||
|
||||
public:
|
||||
JitScript(JSScript* script, uint32_t typeSetOffset,
|
||||
uint32_t bytecodeTypeMapOffset);
|
||||
|
||||
#ifdef DEBUG
|
||||
~JitScript() {
|
||||
// The contents of the fallback stub space are removed and freed
|
||||
// separately after the next minor GC. See prepareForDestruction.
|
||||
MOZ_ASSERT(fallbackStubSpace_.isEmpty());
|
||||
}
|
||||
#endif
|
||||
|
||||
MOZ_MUST_USE bool initICEntries(JSContext* cx, JSScript* script);
|
||||
|
||||
bool hasFreezeConstraints(const js::AutoSweepJitScript& sweep) const {
|
||||
MOZ_ASSERT(sweep.jitScript() == this);
|
||||
return flags_.hasFreezeConstraints;
|
||||
}
|
||||
void setHasFreezeConstraints(const js::AutoSweepJitScript& sweep) {
|
||||
MOZ_ASSERT(sweep.jitScript() == this);
|
||||
flags_.hasFreezeConstraints = true;
|
||||
}
|
||||
|
||||
inline bool typesNeedsSweep(Zone* zone) const;
|
||||
void sweepTypes(const js::AutoSweepJitScript& sweep, Zone* zone);
|
||||
|
||||
RecompileInfoVector& inlinedCompilations(
|
||||
const js::AutoSweepJitScript& sweep) {
|
||||
MOZ_ASSERT(sweep.jitScript() == this);
|
||||
return inlinedCompilations_;
|
||||
}
|
||||
MOZ_MUST_USE bool addInlinedCompilation(const js::AutoSweepJitScript& sweep,
|
||||
RecompileInfo info) {
|
||||
MOZ_ASSERT(sweep.jitScript() == this);
|
||||
if (!inlinedCompilations_.empty() && inlinedCompilations_.back() == info) {
|
||||
return true;
|
||||
}
|
||||
return inlinedCompilations_.append(info);
|
||||
}
|
||||
|
||||
uint32_t numICEntries() const {
|
||||
return (typeSetOffset_ - offsetOfICEntries()) / sizeof(jit::ICEntry);
|
||||
}
|
||||
uint32_t numTypeSets() const {
|
||||
return (bytecodeTypeMapOffset_ - typeSetOffset_) / sizeof(StackTypeSet);
|
||||
}
|
||||
|
||||
uint32_t* bytecodeTypeMapHint() { return &bytecodeTypeMapHint_; }
|
||||
|
||||
bool active() const { return flags_.active; }
|
||||
void setActive() { flags_.active = true; }
|
||||
void resetActive() { flags_.active = false; }
|
||||
|
||||
/* Array of type sets for variables and JOF_TYPESET ops. */
|
||||
StackTypeSet* typeArray(const js::AutoSweepJitScript& sweep) {
|
||||
MOZ_ASSERT(sweep.jitScript() == this);
|
||||
return typeArrayDontCheckGeneration();
|
||||
}
|
||||
|
||||
uint32_t* bytecodeTypeMap() {
|
||||
uint8_t* base = reinterpret_cast<uint8_t*>(this);
|
||||
return reinterpret_cast<uint32_t*>(base + bytecodeTypeMapOffset_);
|
||||
}
|
||||
|
||||
inline StackTypeSet* thisTypes(const AutoSweepJitScript& sweep,
|
||||
JSScript* script);
|
||||
inline StackTypeSet* argTypes(const AutoSweepJitScript& sweep,
|
||||
JSScript* script, unsigned i);
|
||||
|
||||
/* Get the type set for values observed at an opcode. */
|
||||
inline StackTypeSet* bytecodeTypes(const AutoSweepJitScript& sweep,
|
||||
JSScript* script, jsbytecode* pc);
|
||||
|
||||
template <typename TYPESET>
|
||||
static inline TYPESET* BytecodeTypes(JSScript* script, jsbytecode* pc,
|
||||
uint32_t* bytecodeMap, uint32_t* hint,
|
||||
TYPESET* typeArray);
|
||||
|
||||
/*
|
||||
* Monitor a bytecode pushing any value. This must be called for any opcode
|
||||
* which is JOF_TYPESET, and where either the script has not been analyzed
|
||||
* by type inference or where the pc has type barriers. For simplicity, we
|
||||
* always monitor JOF_TYPESET opcodes in the interpreter and stub calls,
|
||||
* and only look at barriers when generating JIT code for the script.
|
||||
*/
|
||||
static void MonitorBytecodeType(JSContext* cx, JSScript* script,
|
||||
jsbytecode* pc, const js::Value& val);
|
||||
static void MonitorBytecodeType(JSContext* cx, JSScript* script,
|
||||
jsbytecode* pc, TypeSet::Type type);
|
||||
|
||||
static inline void MonitorBytecodeType(JSContext* cx, JSScript* script,
|
||||
jsbytecode* pc, StackTypeSet* types,
|
||||
const js::Value& val);
|
||||
|
||||
private:
|
||||
static void MonitorBytecodeTypeSlow(JSContext* cx, JSScript* script,
|
||||
jsbytecode* pc, StackTypeSet* types,
|
||||
TypeSet::Type type);
|
||||
|
||||
public:
|
||||
/* Monitor an assignment at a SETELEM on a non-integer identifier. */
|
||||
static inline void MonitorAssign(JSContext* cx, HandleObject obj, jsid id);
|
||||
|
||||
/* Add a type for a variable in a script. */
|
||||
static inline void MonitorThisType(JSContext* cx, JSScript* script,
|
||||
TypeSet::Type type);
|
||||
static inline void MonitorThisType(JSContext* cx, JSScript* script,
|
||||
const js::Value& value);
|
||||
static inline void MonitorArgType(JSContext* cx, JSScript* script,
|
||||
unsigned arg, TypeSet::Type type);
|
||||
static inline void MonitorArgType(JSContext* cx, JSScript* script,
|
||||
unsigned arg, const js::Value& value);
|
||||
|
||||
/*
|
||||
* Freeze all the stack type sets in a script, for a compilation. Returns
|
||||
* copies of the type sets which will be checked against the actual ones
|
||||
* under FinishCompilation, to detect any type changes.
|
||||
*/
|
||||
static bool FreezeTypeSets(CompilerConstraintList* constraints,
|
||||
JSScript* script, TemporaryTypeSet** pThisTypes,
|
||||
TemporaryTypeSet** pArgTypes,
|
||||
TemporaryTypeSet** pBytecodeTypes);
|
||||
|
||||
void destroy(Zone* zone);
|
||||
|
||||
static constexpr size_t offsetOfICEntries() { return sizeof(JitScript); }
|
||||
|
||||
#ifdef DEBUG
|
||||
void printTypes(JSContext* cx, HandleScript script);
|
||||
#endif
|
||||
|
||||
void prepareForDestruction(Zone* zone) {
|
||||
// When the script contains pointers to nursery things, the store buffer can
|
||||
// contain entries that point into the fallback stub space. Since we can
|
||||
// destroy scripts outside the context of a GC, this situation could result
|
||||
// in us trying to mark invalid store buffer entries.
|
||||
//
|
||||
// Defer freeing any allocated blocks until after the next minor GC.
|
||||
fallbackStubSpace_.freeAllAfterMinorGC(zone);
|
||||
}
|
||||
|
||||
jit::FallbackICStubSpace* fallbackStubSpace() { return &fallbackStubSpace_; }
|
||||
|
||||
void addSizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf, size_t* data,
|
||||
size_t* fallbackStubs) const {
|
||||
*data += mallocSizeOf(this);
|
||||
|
||||
// |data| already includes the ICStubSpace itself, so use
|
||||
// sizeOfExcludingThis.
|
||||
*fallbackStubs += fallbackStubSpace_.sizeOfExcludingThis(mallocSizeOf);
|
||||
}
|
||||
|
||||
jit::ICEntry& icEntry(size_t index) {
|
||||
MOZ_ASSERT(index < numICEntries());
|
||||
return icEntries()[index];
|
||||
}
|
||||
|
||||
void noteAccessedGetter(uint32_t pcOffset);
|
||||
void noteHasDenseAdd(uint32_t pcOffset);
|
||||
|
||||
void trace(JSTracer* trc);
|
||||
void purgeOptimizedStubs(JSScript* script);
|
||||
|
||||
jit::ICEntry* interpreterICEntryFromPCOffset(uint32_t pcOffset);
|
||||
|
||||
jit::ICEntry* maybeICEntryFromPCOffset(uint32_t pcOffset);
|
||||
jit::ICEntry* maybeICEntryFromPCOffset(uint32_t pcOffset,
|
||||
jit::ICEntry* prevLookedUpEntry);
|
||||
|
||||
jit::ICEntry& icEntryFromPCOffset(uint32_t pcOffset);
|
||||
jit::ICEntry& icEntryFromPCOffset(uint32_t pcOffset,
|
||||
jit::ICEntry* prevLookedUpEntry);
|
||||
};
|
||||
|
||||
// Ensures no JitScripts are purged in the current zone.
|
||||
class MOZ_RAII AutoKeepJitScripts {
|
||||
TypeZone& zone_;
|
||||
bool prev_;
|
||||
|
||||
AutoKeepJitScripts(const AutoKeepJitScripts&) = delete;
|
||||
void operator=(const AutoKeepJitScripts&) = delete;
|
||||
|
||||
public:
|
||||
explicit inline AutoKeepJitScripts(JSContext* cx);
|
||||
inline ~AutoKeepJitScripts();
|
||||
};
|
||||
|
||||
} // namespace js
|
||||
|
||||
#endif /* jit_JitScript_h */
|
|
@ -464,7 +464,7 @@ bool ArrayPopDense(JSContext* cx, HandleObject obj, MutableHandleValue rval) {
|
|||
if (rval.isUndefined()) {
|
||||
jsbytecode* pc;
|
||||
JSScript* script = cx->currentScript(&pc);
|
||||
TypeScript::MonitorBytecodeType(cx, script, pc, rval);
|
||||
JitScript::MonitorBytecodeType(cx, script, pc, rval);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
@ -530,7 +530,7 @@ bool ArrayShiftDense(JSContext* cx, HandleObject obj, MutableHandleValue rval) {
|
|||
if (rval.isUndefined()) {
|
||||
jsbytecode* pc;
|
||||
JSScript* script = cx->currentScript(&pc);
|
||||
TypeScript::MonitorBytecodeType(cx, script, pc, rval);
|
||||
JitScript::MonitorBytecodeType(cx, script, pc, rval);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
@ -691,7 +691,7 @@ bool GetIntrinsicValue(JSContext* cx, HandlePropertyName name,
|
|||
// type info will not be reflowed. Manually monitor here.
|
||||
jsbytecode* pc;
|
||||
JSScript* script = cx->currentScript(&pc);
|
||||
TypeScript::MonitorBytecodeType(cx, script, pc, rval);
|
||||
JitScript::MonitorBytecodeType(cx, script, pc, rval);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -2008,8 +2008,8 @@ bool DoConcatStringObject(JSContext* cx, HandleValue lhs, HandleValue rhs,
|
|||
}
|
||||
}
|
||||
|
||||
// Technically, we need to call TypeScript::MonitorString for this PC, however
|
||||
// it was called when this stub was attached so it's OK.
|
||||
// Note: we don't have to call JitScript::MonitorBytecodeType because we
|
||||
// monitored the string-type when attaching the IC stub.
|
||||
|
||||
res.setString(str);
|
||||
return true;
|
||||
|
|
|
@ -67,6 +67,7 @@ UNIFIED_SOURCES += [
|
|||
'JitcodeMap.cpp',
|
||||
'JitFrames.cpp',
|
||||
'JitOptions.cpp',
|
||||
'JitScript.cpp',
|
||||
'JitSpewer.cpp',
|
||||
'JSJitFrameIter.cpp',
|
||||
'JSONSpewer.cpp',
|
||||
|
|
|
@ -514,7 +514,7 @@ static bool MappedArgSetter(JSContext* cx, HandleObject obj, HandleId id,
|
|||
if (arg < argsobj->initialLength() && !argsobj->isElementDeleted(arg)) {
|
||||
argsobj->setElement(cx, arg, v);
|
||||
if (arg < script->functionNonDelazifying()->nargs()) {
|
||||
TypeScript::MonitorArgType(cx, script, arg, v);
|
||||
JitScript::MonitorArgType(cx, script, arg, v);
|
||||
}
|
||||
return result.succeed();
|
||||
}
|
||||
|
@ -730,7 +730,7 @@ bool MappedArgumentsObject::obj_defineProperty(JSContext* cx, HandleObject obj,
|
|||
}
|
||||
argsobj->setElement(cx, arg, desc.value());
|
||||
if (arg < script->functionNonDelazifying()->nargs()) {
|
||||
TypeScript::MonitorArgType(cx, script, arg, desc.value());
|
||||
JitScript::MonitorArgType(cx, script, arg, desc.value());
|
||||
}
|
||||
}
|
||||
if (desc.hasWritable() && !desc.writable()) {
|
||||
|
|
|
@ -2574,7 +2574,7 @@ JS_FRIEND_API void js::StopPCCountProfiling(JSContext* cx) {
|
|||
for (ZonesIter zone(rt, SkipAtoms); !zone.done(); zone.next()) {
|
||||
for (auto script = zone->cellIter<JSScript>(); !script.done();
|
||||
script.next()) {
|
||||
if (script->hasScriptCounts() && script->types()) {
|
||||
if (script->hasScriptCounts() && script->jitScript()) {
|
||||
if (!vec->append(script)) {
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -2922,10 +2922,10 @@ bool Debugger::updateExecutionObservabilityOfFrames(
|
|||
return true;
|
||||
}
|
||||
|
||||
static inline void MarkTypeScriptActiveIfObservable(
|
||||
static inline void MarkJitScriptActiveIfObservable(
|
||||
JSScript* script, const Debugger::ExecutionObservableSet& obs) {
|
||||
if (obs.shouldRecompileOrInvalidate(script)) {
|
||||
script->types()->setActive();
|
||||
script->jitScript()->setActive();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2988,13 +2988,13 @@ static bool UpdateExecutionObservabilityOfScriptsInZone(
|
|||
const JSJitFrameIter& frame = iter.frame();
|
||||
switch (frame.type()) {
|
||||
case FrameType::BaselineJS:
|
||||
MarkTypeScriptActiveIfObservable(frame.script(), obs);
|
||||
MarkJitScriptActiveIfObservable(frame.script(), obs);
|
||||
break;
|
||||
case FrameType::IonJS:
|
||||
MarkTypeScriptActiveIfObservable(frame.script(), obs);
|
||||
MarkJitScriptActiveIfObservable(frame.script(), obs);
|
||||
for (InlineFrameIterator inlineIter(cx, &frame); inlineIter.more();
|
||||
++inlineIter) {
|
||||
MarkTypeScriptActiveIfObservable(inlineIter.script(), obs);
|
||||
MarkJitScriptActiveIfObservable(inlineIter.script(), obs);
|
||||
}
|
||||
break;
|
||||
default:;
|
||||
|
@ -3007,10 +3007,10 @@ static bool UpdateExecutionObservabilityOfScriptsInZone(
|
|||
// discard the BaselineScript on scripts that have no IonScript.
|
||||
for (size_t i = 0; i < scripts.length(); i++) {
|
||||
MOZ_ASSERT_IF(scripts[i]->isDebuggee(), observing);
|
||||
if (!scripts[i]->types()->active()) {
|
||||
if (!scripts[i]->jitScript()->active()) {
|
||||
FinishDiscardBaselineScript(fop, scripts[i]);
|
||||
}
|
||||
scripts[i]->types()->resetActive();
|
||||
scripts[i]->jitScript()->resetActive();
|
||||
}
|
||||
|
||||
// Iterate through all wasm instances to find ones that need to be updated.
|
||||
|
|
|
@ -1574,7 +1574,7 @@ class DebugEnvironmentProxyHandler : public BaseProxyHandler {
|
|||
}
|
||||
|
||||
if (action == SET) {
|
||||
TypeScript::MonitorArgType(cx, script, i, vp);
|
||||
JitScript::MonitorArgType(cx, script, i, vp);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1546,15 +1546,15 @@ static MOZ_ALWAYS_INLINE bool SetObjectElementOperation(
|
|||
// receiver != obj happens only at super[expr], where we expect to find the
|
||||
// property. People probably aren't building hashtables with |super|
|
||||
// anyway.
|
||||
TypeScript::MonitorAssign(cx, obj, id);
|
||||
JitScript::MonitorAssign(cx, obj, id);
|
||||
|
||||
if (obj->isNative() && JSID_IS_INT(id)) {
|
||||
uint32_t length = obj->as<NativeObject>().getDenseInitializedLength();
|
||||
int32_t i = JSID_TO_INT(id);
|
||||
if ((uint32_t)i >= length) {
|
||||
// Annotate script if provided with information (e.g. baseline)
|
||||
if (script && script->hasICScript() && IsSetElemPC(pc)) {
|
||||
script->icScript()->noteHasDenseAdd(script->pcToOffset(pc));
|
||||
if (script && script->hasJitScript() && IsSetElemPC(pc)) {
|
||||
script->jitScript()->noteHasDenseAdd(script->pcToOffset(pc));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2123,7 +2123,7 @@ static MOZ_NEVER_INLINE JS_HAZ_JSNATIVE_CALLER bool Interpret(JSContext* cx,
|
|||
ADVANCE_AND_DISPATCH(JSOP_RESUME_LENGTH);
|
||||
}
|
||||
|
||||
TypeScript::MonitorBytecodeType(cx, script, REGS.pc, REGS.sp[-1]);
|
||||
JitScript::MonitorBytecodeType(cx, script, REGS.pc, REGS.sp[-1]);
|
||||
MOZ_ASSERT(CodeSpec[*REGS.pc].length == JSOP_CALL_LENGTH);
|
||||
ADVANCE_AND_DISPATCH(JSOP_CALL_LENGTH);
|
||||
}
|
||||
|
@ -2773,7 +2773,7 @@ static MOZ_NEVER_INLINE JS_HAZ_JSNATIVE_CALLER bool Interpret(JSContext* cx,
|
|||
goto error;
|
||||
}
|
||||
|
||||
TypeScript::MonitorBytecodeType(cx, script, REGS.pc, lval);
|
||||
JitScript::MonitorBytecodeType(cx, script, REGS.pc, lval);
|
||||
cx->debugOnlyCheck(lval);
|
||||
}
|
||||
END_CASE(JSOP_GETPROP)
|
||||
|
@ -2787,7 +2787,7 @@ static MOZ_NEVER_INLINE JS_HAZ_JSNATIVE_CALLER bool Interpret(JSContext* cx,
|
|||
goto error;
|
||||
}
|
||||
|
||||
TypeScript::MonitorBytecodeType(cx, script, REGS.pc, rref);
|
||||
JitScript::MonitorBytecodeType(cx, script, REGS.pc, rref);
|
||||
cx->debugOnlyCheck(rref);
|
||||
|
||||
REGS.sp--;
|
||||
|
@ -2802,7 +2802,7 @@ static MOZ_NEVER_INLINE JS_HAZ_JSNATIVE_CALLER bool Interpret(JSContext* cx,
|
|||
goto error;
|
||||
}
|
||||
|
||||
TypeScript::MonitorBytecodeType(cx, script, REGS.pc, rval);
|
||||
JitScript::MonitorBytecodeType(cx, script, REGS.pc, rval);
|
||||
cx->debugOnlyCheck(rval);
|
||||
}
|
||||
END_CASE(JSOP_GETBOUNDNAME)
|
||||
|
@ -2895,7 +2895,7 @@ static MOZ_NEVER_INLINE JS_HAZ_JSNATIVE_CALLER bool Interpret(JSContext* cx,
|
|||
}
|
||||
}
|
||||
|
||||
TypeScript::MonitorBytecodeType(cx, script, REGS.pc, res);
|
||||
JitScript::MonitorBytecodeType(cx, script, REGS.pc, res);
|
||||
REGS.sp--;
|
||||
}
|
||||
END_CASE(JSOP_GETELEM)
|
||||
|
@ -2915,7 +2915,7 @@ static MOZ_NEVER_INLINE JS_HAZ_JSNATIVE_CALLER bool Interpret(JSContext* cx,
|
|||
goto error;
|
||||
}
|
||||
|
||||
TypeScript::MonitorBytecodeType(cx, script, REGS.pc, res);
|
||||
JitScript::MonitorBytecodeType(cx, script, REGS.pc, res);
|
||||
REGS.sp -= 2;
|
||||
}
|
||||
END_CASE(JSOP_GETELEM_SUPER)
|
||||
|
@ -2980,7 +2980,7 @@ static MOZ_NEVER_INLINE JS_HAZ_JSNATIVE_CALLER bool Interpret(JSContext* cx,
|
|||
}
|
||||
|
||||
REGS.sp = args.spAfterCall();
|
||||
TypeScript::MonitorBytecodeType(cx, script, REGS.pc, REGS.sp[-1]);
|
||||
JitScript::MonitorBytecodeType(cx, script, REGS.pc, REGS.sp[-1]);
|
||||
}
|
||||
END_CASE(JSOP_EVAL)
|
||||
|
||||
|
@ -3087,7 +3087,7 @@ static MOZ_NEVER_INLINE JS_HAZ_JSNATIVE_CALLER bool Interpret(JSContext* cx,
|
|||
}
|
||||
}
|
||||
Value* newsp = args.spAfterCall();
|
||||
TypeScript::MonitorBytecodeType(cx, script, REGS.pc, newsp[-1]);
|
||||
JitScript::MonitorBytecodeType(cx, script, REGS.pc, newsp[-1]);
|
||||
REGS.sp = newsp;
|
||||
ADVANCE_AND_DISPATCH(JSOP_CALL_LENGTH);
|
||||
}
|
||||
|
@ -3237,7 +3237,7 @@ static MOZ_NEVER_INLINE JS_HAZ_JSNATIVE_CALLER bool Interpret(JSContext* cx,
|
|||
}
|
||||
|
||||
PUSH_COPY(rval);
|
||||
TypeScript::MonitorBytecodeType(cx, script, REGS.pc, rval);
|
||||
JitScript::MonitorBytecodeType(cx, script, REGS.pc, rval);
|
||||
static_assert(JSOP_GETNAME_LENGTH == JSOP_GETGNAME_LENGTH,
|
||||
"We're sharing the END_CASE so the lengths better match");
|
||||
}
|
||||
|
@ -3251,7 +3251,7 @@ static MOZ_NEVER_INLINE JS_HAZ_JSNATIVE_CALLER bool Interpret(JSContext* cx,
|
|||
goto error;
|
||||
}
|
||||
|
||||
TypeScript::MonitorBytecodeType(cx, script, REGS.pc, rval);
|
||||
JitScript::MonitorBytecodeType(cx, script, REGS.pc, rval);
|
||||
}
|
||||
END_CASE(JSOP_GETIMPORT)
|
||||
|
||||
|
@ -3262,7 +3262,7 @@ static MOZ_NEVER_INLINE JS_HAZ_JSNATIVE_CALLER bool Interpret(JSContext* cx,
|
|||
}
|
||||
|
||||
PUSH_COPY(rval);
|
||||
TypeScript::MonitorBytecodeType(cx, script, REGS.pc, rval);
|
||||
JitScript::MonitorBytecodeType(cx, script, REGS.pc, rval);
|
||||
}
|
||||
END_CASE(JSOP_GETINTRINSIC)
|
||||
|
||||
|
@ -3424,7 +3424,7 @@ static MOZ_NEVER_INLINE JS_HAZ_JSNATIVE_CALLER bool Interpret(JSContext* cx,
|
|||
}
|
||||
#endif
|
||||
PUSH_COPY(val);
|
||||
TypeScript::MonitorBytecodeType(cx, script, REGS.pc, REGS.sp[-1]);
|
||||
JitScript::MonitorBytecodeType(cx, script, REGS.pc, REGS.sp[-1]);
|
||||
}
|
||||
END_CASE(JSOP_GETALIASEDVAR)
|
||||
|
||||
|
@ -5105,7 +5105,7 @@ bool js::SpreadCallOperation(JSContext* cx, HandleScript script, jsbytecode* pc,
|
|||
}
|
||||
}
|
||||
|
||||
TypeScript::MonitorBytecodeType(cx, script, pc, res);
|
||||
JitScript::MonitorBytecodeType(cx, script, pc, res);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -1156,7 +1156,7 @@ JSObject* js::CreateThisForFunctionWithProto(
|
|||
if (!script) {
|
||||
return nullptr;
|
||||
}
|
||||
TypeScript::MonitorThisType(cx, script, TypeSet::ObjectType(res));
|
||||
JitScript::MonitorThisType(cx, script, TypeSet::ObjectType(res));
|
||||
}
|
||||
|
||||
return res;
|
||||
|
@ -1225,7 +1225,7 @@ JSObject* js::CreateThisForFunction(JSContext* cx, HandleFunction callee,
|
|||
NativeObject::clear(cx, nobj);
|
||||
|
||||
JSScript* calleeScript = callee->nonLazyScript();
|
||||
TypeScript::MonitorThisType(cx, calleeScript, TypeSet::ObjectType(nobj));
|
||||
JitScript::MonitorThisType(cx, calleeScript, TypeSet::ObjectType(nobj));
|
||||
|
||||
return nobj;
|
||||
}
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
|
||||
#include "jit/BaselineJIT.h"
|
||||
#include "jit/IonAnalysis.h"
|
||||
#include "jit/JitScript.h"
|
||||
#include "vm/EnvironmentObject.h"
|
||||
#include "vm/RegExpObject.h"
|
||||
#include "wasm/AsmJS.h"
|
||||
|
@ -181,9 +182,4 @@ inline bool JSScript::isDebuggee() const {
|
|||
return realm_->debuggerObservesAllExecution() || hasDebugScript();
|
||||
}
|
||||
|
||||
inline js::jit::ICScript* JSScript::icScript() const {
|
||||
MOZ_ASSERT(hasICScript());
|
||||
return types_->icScript();
|
||||
}
|
||||
|
||||
#endif /* vm_JSScript_inl_h */
|
||||
|
|
|
@ -1725,8 +1725,7 @@ class ScriptSource::LoadSourceMatcher {
|
|||
}
|
||||
|
||||
if (!ss_->setRetrievedSource(
|
||||
cx_,
|
||||
EntryUnits<Utf8Unit>(reinterpret_cast<Utf8Unit*>(utf8Source)),
|
||||
cx_, EntryUnits<Utf8Unit>(reinterpret_cast<Utf8Unit*>(utf8Source)),
|
||||
*length)) {
|
||||
return false;
|
||||
}
|
||||
|
@ -2748,8 +2747,8 @@ XDRResult ScriptSource::codeBinASTData(XDRState<mode>* const xdr,
|
|||
// XDR the BinAST data.
|
||||
Maybe<SharedImmutableString> binASTData;
|
||||
if (mode == XDR_DECODE) {
|
||||
auto bytes = xdr->cx()->template make_pod_array<char>(Max<size_t>(
|
||||
binASTLength, 1));
|
||||
auto bytes =
|
||||
xdr->cx()->template make_pod_array<char>(Max<size_t>(binASTLength, 1));
|
||||
if (!bytes) {
|
||||
return xdr->fail(JS::TranscodeResult_Throw);
|
||||
}
|
||||
|
@ -2820,7 +2819,8 @@ XDRResult ScriptSource::codeBinASTData(XDRState<mode>* const xdr,
|
|||
JSAtom** atomsBase = binASTMetadata->atomsBase();
|
||||
auto slices = binASTMetadata->sliceBase();
|
||||
const char* sourceBase =
|
||||
(mode == XDR_ENCODE ? ss->data.as<BinAST>().string : *binASTData).chars();
|
||||
(mode == XDR_ENCODE ? ss->data.as<BinAST>().string : *binASTData)
|
||||
.chars();
|
||||
|
||||
for (uint32_t i = 0; i < numStrings; i++) {
|
||||
uint8_t isNull;
|
||||
|
@ -3373,7 +3373,8 @@ void js::FreeScriptData(JSRuntime* rt) {
|
|||
|
||||
#ifdef DEBUG
|
||||
if (numLive > 0) {
|
||||
fprintf(stderr, "ERROR: GC found %zu live SharedScriptData at shutdown\n", numLive);
|
||||
fprintf(stderr, "ERROR: GC found %zu live SharedScriptData at shutdown\n",
|
||||
numLive);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -4039,8 +4040,15 @@ size_t JSScript::sizeOfData(mozilla::MallocSizeOf mallocSizeOf) const {
|
|||
return mallocSizeOf(data_);
|
||||
}
|
||||
|
||||
size_t JSScript::sizeOfTypeScript(mozilla::MallocSizeOf mallocSizeOf) const {
|
||||
return types_ ? types_->sizeOfIncludingThis(mallocSizeOf) : 0;
|
||||
void JSScript::addSizeOfJitScript(mozilla::MallocSizeOf mallocSizeOf,
|
||||
size_t* sizeOfJitScript,
|
||||
size_t* sizeOfBaselineFallbackStubs) const {
|
||||
if (!jitScript_) {
|
||||
return;
|
||||
}
|
||||
|
||||
jitScript_->addSizeOfIncludingThis(mallocSizeOf, sizeOfJitScript,
|
||||
sizeOfBaselineFallbackStubs);
|
||||
}
|
||||
|
||||
js::GlobalObject& JSScript::uninlinedGlobal() const { return global(); }
|
||||
|
@ -4061,8 +4069,8 @@ void JSScript::finalize(FreeOp* fop) {
|
|||
|
||||
fop->runtime()->geckoProfiler().onScriptFinalized(this);
|
||||
|
||||
if (types_) {
|
||||
types_->destroy(zone());
|
||||
if (jitScript_) {
|
||||
jitScript_->destroy(zone());
|
||||
}
|
||||
|
||||
jit::DestroyJitScripts(fop, this);
|
||||
|
@ -5428,7 +5436,7 @@ void JSScript::updateJitCodeRaw(JSRuntime* rt) {
|
|||
} else if (hasBaselineScript()) {
|
||||
jitCodeRaw_ = baseline->method()->raw();
|
||||
jitCodeSkipArgCheck_ = jitCodeRaw_;
|
||||
} else if (types() && js::jit::JitOptions.baselineInterpreter) {
|
||||
} else if (jitScript() && js::jit::JitOptions.baselineInterpreter) {
|
||||
jitCodeRaw_ = rt->jitRuntime()->baselineInterpreter().codeRaw();
|
||||
jitCodeSkipArgCheck_ = jitCodeRaw_;
|
||||
} else {
|
||||
|
@ -5511,14 +5519,16 @@ JS::ubi::Base::Size JS::ubi::Concrete<JSScript>::size(
|
|||
Size size = gc::Arena::thingSize(get().asTenured().getAllocKind());
|
||||
|
||||
size += get().sizeOfData(mallocSizeOf);
|
||||
size += get().sizeOfTypeScript(mallocSizeOf);
|
||||
|
||||
size_t jitScriptSize = 0;
|
||||
size_t fallbackStubSize = 0;
|
||||
get().addSizeOfJitScript(mallocSizeOf, &jitScriptSize, &fallbackStubSize);
|
||||
size += jitScriptSize;
|
||||
size += fallbackStubSize;
|
||||
|
||||
size_t baselineSize = 0;
|
||||
size_t baselineStubsSize = 0;
|
||||
jit::AddSizeOfBaselineData(&get(), mallocSizeOf, &baselineSize,
|
||||
&baselineStubsSize);
|
||||
jit::AddSizeOfBaselineData(&get(), mallocSizeOf, &baselineSize);
|
||||
size += baselineSize;
|
||||
size += baselineStubsSize;
|
||||
|
||||
size += jit::SizeOfIonData(&get(), mallocSizeOf);
|
||||
|
||||
|
|
|
@ -55,7 +55,6 @@ namespace js {
|
|||
|
||||
namespace jit {
|
||||
struct BaselineScript;
|
||||
class ICScript;
|
||||
struct IonScriptCounts;
|
||||
} // namespace jit
|
||||
|
||||
|
@ -65,8 +64,8 @@ struct IonScriptCounts;
|
|||
|
||||
#define BASELINE_DISABLED_SCRIPT ((js::jit::BaselineScript*)0x1)
|
||||
|
||||
class AutoKeepTypeScripts;
|
||||
class AutoSweepTypeScript;
|
||||
class AutoKeepJitScripts;
|
||||
class AutoSweepJitScript;
|
||||
class BreakpointSite;
|
||||
class Debugger;
|
||||
class GCParallelTask;
|
||||
|
@ -75,7 +74,7 @@ class ModuleObject;
|
|||
class RegExpObject;
|
||||
class SourceCompressionTask;
|
||||
class Shape;
|
||||
class TypeScript;
|
||||
class JitScript;
|
||||
|
||||
namespace frontend {
|
||||
struct BytecodeEmitter;
|
||||
|
@ -1568,7 +1567,7 @@ class alignas(uintptr_t) SharedScriptData final {
|
|||
// Index into the scopes array of the body scope.
|
||||
uint32_t bodyScopeIndex = 0;
|
||||
|
||||
// Number of IC entries to allocate in ICScript for Baseline ICs.
|
||||
// Number of IC entries to allocate in JitScript for Baseline ICs.
|
||||
uint32_t numICEntries = 0;
|
||||
|
||||
// ES6 function length.
|
||||
|
@ -1741,8 +1740,8 @@ class JSScript : public js::gc::TenuredCell {
|
|||
JS::Realm* realm_ = nullptr;
|
||||
|
||||
private:
|
||||
/* Persistent type information retained across GCs. */
|
||||
js::TypeScript* types_ = nullptr;
|
||||
// JIT and type inference data for this script. May be purged on GC.
|
||||
js::JitScript* jitScript_ = nullptr;
|
||||
|
||||
// This script's ScriptSourceObject.
|
||||
js::GCPtr<js::ScriptSourceObject*> sourceObject_ = {};
|
||||
|
@ -2429,7 +2428,9 @@ class JSScript : public js::gc::TenuredCell {
|
|||
static constexpr size_t offsetOfScriptData() {
|
||||
return offsetof(JSScript, scriptData_);
|
||||
}
|
||||
static constexpr size_t offsetOfTypes() { return offsetof(JSScript, types_); }
|
||||
static constexpr size_t offsetOfJitScript() {
|
||||
return offsetof(JSScript, jitScript_);
|
||||
}
|
||||
|
||||
bool hasAnyIonScript() const { return hasIonScript(); }
|
||||
|
||||
|
@ -2465,14 +2466,6 @@ class JSScript : public js::gc::TenuredCell {
|
|||
inline void setBaselineScript(JSRuntime* rt,
|
||||
js::jit::BaselineScript* baselineScript);
|
||||
|
||||
inline js::jit::ICScript* icScript() const;
|
||||
|
||||
bool hasICScript() const {
|
||||
// ICScript is stored in TypeScript so we have an ICScript iff we have a
|
||||
// TypeScript.
|
||||
return !!types_;
|
||||
}
|
||||
|
||||
void updateJitCodeRaw(JSRuntime* rt);
|
||||
|
||||
static size_t offsetOfBaselineScript() {
|
||||
|
@ -2487,7 +2480,7 @@ class JSScript : public js::gc::TenuredCell {
|
|||
}
|
||||
uint8_t* jitCodeRaw() const { return jitCodeRaw_; }
|
||||
|
||||
// We don't relazify functions with a TypeScript or JIT code, but some
|
||||
// We don't relazify functions with a JitScript or JIT code, but some
|
||||
// callers (XDR, testing functions) want to know whether this script is
|
||||
// relazifiable ignoring (or after) discarding JIT code.
|
||||
bool isRelazifiableIgnoringJitCode() const {
|
||||
|
@ -2496,8 +2489,8 @@ class JSScript : public js::gc::TenuredCell {
|
|||
!hasFlag(MutableFlags::DoNotRelazify);
|
||||
}
|
||||
bool isRelazifiable() const {
|
||||
MOZ_ASSERT_IF(hasBaselineScript() || hasIonScript(), types_);
|
||||
return isRelazifiableIgnoringJitCode() && !types_;
|
||||
MOZ_ASSERT_IF(hasBaselineScript() || hasIonScript(), jitScript_);
|
||||
return isRelazifiableIgnoringJitCode() && !jitScript_;
|
||||
}
|
||||
void setLazyScript(js::LazyScript* lazy) { lazyScript = lazy; }
|
||||
js::LazyScript* maybeLazyScript() { return lazyScript; }
|
||||
|
@ -2599,12 +2592,13 @@ class JSScript : public js::gc::TenuredCell {
|
|||
*/
|
||||
bool isTopLevel() { return code() && !functionNonDelazifying(); }
|
||||
|
||||
/* Ensure the script has a TypeScript. */
|
||||
inline bool ensureHasTypes(JSContext* cx, js::AutoKeepTypeScripts&);
|
||||
/* Ensure the script has a JitScript. */
|
||||
inline bool ensureHasJitScript(JSContext* cx, js::AutoKeepJitScripts&);
|
||||
|
||||
js::TypeScript* types() { return types_; }
|
||||
bool hasJitScript() const { return jitScript_ != nullptr; }
|
||||
js::JitScript* jitScript() { return jitScript_; }
|
||||
|
||||
void maybeReleaseTypes();
|
||||
void maybeReleaseJitScript();
|
||||
|
||||
inline js::GlobalObject& global() const;
|
||||
inline bool hasGlobal(const js::GlobalObject* global) const;
|
||||
|
@ -2655,7 +2649,7 @@ class JSScript : public js::gc::TenuredCell {
|
|||
js::Scope* enclosingScope() const { return outermostScope()->enclosing(); }
|
||||
|
||||
private:
|
||||
bool makeTypes(JSContext* cx);
|
||||
bool createJitScript(JSContext* cx);
|
||||
|
||||
bool createSharedScriptData(JSContext* cx, uint32_t codeLength,
|
||||
uint32_t noteLength, uint32_t natoms);
|
||||
|
@ -2732,7 +2726,10 @@ class JSScript : public js::gc::TenuredCell {
|
|||
*/
|
||||
size_t computedSizeOfData() const;
|
||||
size_t sizeOfData(mozilla::MallocSizeOf mallocSizeOf) const;
|
||||
size_t sizeOfTypeScript(mozilla::MallocSizeOf mallocSizeOf) const;
|
||||
|
||||
void addSizeOfJitScript(mozilla::MallocSizeOf mallocSizeOf,
|
||||
size_t* sizeOfJitScript,
|
||||
size_t* sizeOfBaselineFallbackStubs) const;
|
||||
|
||||
size_t dataSize() const { return dataSize_; }
|
||||
|
||||
|
|
|
@ -445,11 +445,10 @@ static void StatsCellCallback(JSRuntime* rt, void* data, void* thing,
|
|||
realmStats.scriptsGCHeap += thingSize;
|
||||
realmStats.scriptsMallocHeapData +=
|
||||
script->sizeOfData(rtStats->mallocSizeOf_);
|
||||
realmStats.typeInferenceTypeScripts +=
|
||||
script->sizeOfTypeScript(rtStats->mallocSizeOf_);
|
||||
jit::AddSizeOfBaselineData(script, rtStats->mallocSizeOf_,
|
||||
&realmStats.baselineData,
|
||||
script->addSizeOfJitScript(rtStats->mallocSizeOf_, &realmStats.jitScripts,
|
||||
&realmStats.baselineStubsFallback);
|
||||
jit::AddSizeOfBaselineData(script, rtStats->mallocSizeOf_,
|
||||
&realmStats.baselineData);
|
||||
realmStats.ionData += jit::SizeOfIonData(script, rtStats->mallocSizeOf_);
|
||||
CollectScriptSourceStats<granularity>(closure, script->scriptSource());
|
||||
break;
|
||||
|
|
|
@ -2248,12 +2248,12 @@ static MOZ_ALWAYS_INLINE bool GetExistingProperty(
|
|||
{
|
||||
jsbytecode* pc;
|
||||
JSScript* script = cx->currentScript(&pc);
|
||||
if (script && script->hasICScript()) {
|
||||
if (script && script->hasJitScript()) {
|
||||
switch (JSOp(*pc)) {
|
||||
case JSOP_GETPROP:
|
||||
case JSOP_CALLPROP:
|
||||
case JSOP_LENGTH:
|
||||
script->icScript()->noteAccessedGetter(script->pcToOffset(pc));
|
||||
script->jitScript()->noteAccessedGetter(script->pcToOffset(pc));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
|
|
@ -1523,7 +1523,7 @@ bool ObjectGroup::setAllocationSiteObjectGroup(JSContext* cx,
|
|||
* objects, as these may not be created until after the script
|
||||
* has been analyzed.
|
||||
*/
|
||||
TypeScript::MonitorBytecodeType(cx, script, pc, ObjectValue(*obj));
|
||||
JitScript::MonitorBytecodeType(cx, script, pc, ObjectValue(*obj));
|
||||
} else {
|
||||
ObjectGroup* group = allocationSiteGroup(cx, script, pc, key);
|
||||
if (!group) {
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
#include "builtin/Symbol.h"
|
||||
#include "gc/GC.h"
|
||||
#include "jit/BaselineJIT.h"
|
||||
#include "jit/JitScript.h"
|
||||
#include "js/HeapAPI.h"
|
||||
#include "vm/ArrayObject.h"
|
||||
#include "vm/BooleanObject.h"
|
||||
|
@ -32,6 +33,7 @@
|
|||
#include "vm/StringObject.h"
|
||||
#include "vm/TypedArrayObject.h"
|
||||
|
||||
#include "jit/JitScript-inl.h"
|
||||
#include "vm/JSContext-inl.h"
|
||||
#include "vm/ObjectGroup-inl.h"
|
||||
|
||||
|
@ -443,7 +445,7 @@ inline void TypeMonitorCall(JSContext* cx, const js::CallArgs& args,
|
|||
bool constructing) {
|
||||
if (args.callee().is<JSFunction>()) {
|
||||
JSFunction* fun = &args.callee().as<JSFunction>();
|
||||
if (fun->isInterpreted() && fun->nonLazyScript()->types()) {
|
||||
if (fun->isInterpreted() && fun->nonLazyScript()->jitScript()) {
|
||||
TypeMonitorCallSlow(cx, &args.callee(), args, constructing);
|
||||
}
|
||||
}
|
||||
|
@ -586,75 +588,10 @@ inline void MarkObjectStateChange(JSContext* cx, JSObject* obj) {
|
|||
}
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////
|
||||
// Script interface functions
|
||||
/////////////////////////////////////////////////////////////////////
|
||||
|
||||
inline StackTypeSet* TypeScript::thisTypes(const AutoSweepTypeScript& sweep,
|
||||
JSScript* script) {
|
||||
return typeArray(sweep) + script->numBytecodeTypeSets();
|
||||
}
|
||||
|
||||
/*
|
||||
* Note: for non-escaping arguments, argTypes reflect only the initial type of
|
||||
* the variable (e.g. passed values for argTypes, or undefined for localTypes)
|
||||
* and not types from subsequent assignments.
|
||||
*/
|
||||
|
||||
inline StackTypeSet* TypeScript::argTypes(const AutoSweepTypeScript& sweep,
|
||||
JSScript* script, unsigned i) {
|
||||
MOZ_ASSERT(i < script->functionNonDelazifying()->nargs());
|
||||
return typeArray(sweep) + script->numBytecodeTypeSets() + 1 /* this */ + i;
|
||||
}
|
||||
|
||||
template <typename TYPESET>
|
||||
/* static */ inline TYPESET* TypeScript::BytecodeTypes(JSScript* script,
|
||||
jsbytecode* pc,
|
||||
uint32_t* bytecodeMap,
|
||||
uint32_t* hint,
|
||||
TYPESET* typeArray) {
|
||||
MOZ_ASSERT(CodeSpec[*pc].format & JOF_TYPESET);
|
||||
uint32_t offset = script->pcToOffset(pc);
|
||||
|
||||
// See if this pc is the next typeset opcode after the last one looked up.
|
||||
size_t numBytecodeTypeSets = script->numBytecodeTypeSets();
|
||||
if ((*hint + 1) < numBytecodeTypeSets && bytecodeMap[*hint + 1] == offset) {
|
||||
(*hint)++;
|
||||
return typeArray + *hint;
|
||||
}
|
||||
|
||||
// See if this pc is the same as the last one looked up.
|
||||
if (bytecodeMap[*hint] == offset) {
|
||||
return typeArray + *hint;
|
||||
}
|
||||
|
||||
// Fall back to a binary search. We'll either find the exact offset, or
|
||||
// there are more JOF_TYPESET opcodes than nTypeSets in the script (as can
|
||||
// happen if the script is very long) and we'll use the last location.
|
||||
size_t loc;
|
||||
bool found =
|
||||
mozilla::BinarySearch(bytecodeMap, 0, numBytecodeTypeSets, offset, &loc);
|
||||
if (found) {
|
||||
MOZ_ASSERT(bytecodeMap[loc] == offset);
|
||||
} else {
|
||||
MOZ_ASSERT(numBytecodeTypeSets == JSScript::MaxBytecodeTypeSets);
|
||||
loc = numBytecodeTypeSets - 1;
|
||||
}
|
||||
|
||||
*hint = mozilla::AssertedCast<uint32_t>(loc);
|
||||
return typeArray + *hint;
|
||||
}
|
||||
|
||||
inline StackTypeSet* TypeScript::bytecodeTypes(const AutoSweepTypeScript& sweep,
|
||||
/* static */ inline void JitScript::MonitorBytecodeType(JSContext* cx,
|
||||
JSScript* script,
|
||||
jsbytecode* pc) {
|
||||
MOZ_ASSERT(CurrentThreadCanAccessZone(script->zone()));
|
||||
return BytecodeTypes(script, pc, bytecodeTypeMap(), bytecodeTypeMapHint(),
|
||||
typeArray(sweep));
|
||||
}
|
||||
|
||||
/* static */ inline void TypeScript::MonitorBytecodeType(
|
||||
JSContext* cx, JSScript* script, jsbytecode* pc, StackTypeSet* types,
|
||||
jsbytecode* pc,
|
||||
StackTypeSet* types,
|
||||
const js::Value& rval) {
|
||||
TypeSet::Type type = TypeSet::GetValueType(rval);
|
||||
if (!types->hasType(type)) {
|
||||
|
@ -662,7 +599,7 @@ inline StackTypeSet* TypeScript::bytecodeTypes(const AutoSweepTypeScript& sweep,
|
|||
}
|
||||
}
|
||||
|
||||
/* static */ inline void TypeScript::MonitorAssign(JSContext* cx,
|
||||
/* static */ inline void JitScript::MonitorAssign(JSContext* cx,
|
||||
HandleObject obj, jsid id) {
|
||||
if (!obj->isSingleton()) {
|
||||
/*
|
||||
|
@ -689,18 +626,18 @@ inline StackTypeSet* TypeScript::bytecodeTypes(const AutoSweepTypeScript& sweep,
|
|||
}
|
||||
}
|
||||
|
||||
/* static */ inline void TypeScript::MonitorThisType(JSContext* cx,
|
||||
/* static */ inline void JitScript::MonitorThisType(JSContext* cx,
|
||||
JSScript* script,
|
||||
TypeSet::Type type) {
|
||||
cx->check(script, type);
|
||||
|
||||
TypeScript* typeScript = script->types();
|
||||
if (!typeScript) {
|
||||
JitScript* jitScript = script->jitScript();
|
||||
if (!jitScript) {
|
||||
return;
|
||||
}
|
||||
|
||||
AutoSweepTypeScript sweep(script);
|
||||
StackTypeSet* types = typeScript->thisTypes(sweep, script);
|
||||
AutoSweepJitScript sweep(script);
|
||||
StackTypeSet* types = jitScript->thisTypes(sweep, script);
|
||||
|
||||
if (!types->hasType(type)) {
|
||||
AutoEnterAnalysis enter(cx);
|
||||
|
@ -711,25 +648,25 @@ inline StackTypeSet* TypeScript::bytecodeTypes(const AutoSweepTypeScript& sweep,
|
|||
}
|
||||
}
|
||||
|
||||
/* static */ inline void TypeScript::MonitorThisType(JSContext* cx,
|
||||
/* static */ inline void JitScript::MonitorThisType(JSContext* cx,
|
||||
JSScript* script,
|
||||
const js::Value& value) {
|
||||
MonitorThisType(cx, script, TypeSet::GetValueType(value));
|
||||
}
|
||||
|
||||
/* static */ inline void TypeScript::MonitorArgType(JSContext* cx,
|
||||
/* static */ inline void JitScript::MonitorArgType(JSContext* cx,
|
||||
JSScript* script,
|
||||
unsigned arg,
|
||||
TypeSet::Type type) {
|
||||
cx->check(script->compartment(), type);
|
||||
|
||||
TypeScript* typeScript = script->types();
|
||||
if (!typeScript) {
|
||||
JitScript* jitScript = script->jitScript();
|
||||
if (!jitScript) {
|
||||
return;
|
||||
}
|
||||
|
||||
AutoSweepTypeScript sweep(script);
|
||||
StackTypeSet* types = typeScript->argTypes(sweep, script, arg);
|
||||
AutoSweepJitScript sweep(script);
|
||||
StackTypeSet* types = jitScript->argTypes(sweep, script, arg);
|
||||
|
||||
if (!types->hasType(type)) {
|
||||
AutoEnterAnalysis enter(cx);
|
||||
|
@ -740,23 +677,13 @@ inline StackTypeSet* TypeScript::bytecodeTypes(const AutoSweepTypeScript& sweep,
|
|||
}
|
||||
}
|
||||
|
||||
/* static */ inline void TypeScript::MonitorArgType(JSContext* cx,
|
||||
/* static */ inline void JitScript::MonitorArgType(JSContext* cx,
|
||||
JSScript* script,
|
||||
unsigned arg,
|
||||
const js::Value& value) {
|
||||
MonitorArgType(cx, script, arg, TypeSet::GetValueType(value));
|
||||
}
|
||||
|
||||
inline AutoKeepTypeScripts::AutoKeepTypeScripts(JSContext* cx)
|
||||
: zone_(cx->zone()->types), prev_(zone_.keepTypeScripts) {
|
||||
zone_.keepTypeScripts = true;
|
||||
}
|
||||
|
||||
inline AutoKeepTypeScripts::~AutoKeepTypeScripts() {
|
||||
MOZ_ASSERT(zone_.keepTypeScripts);
|
||||
zone_.keepTypeScripts = prev_;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////
|
||||
// TypeHashSet
|
||||
/////////////////////////////////////////////////////////////////////
|
||||
|
@ -1363,36 +1290,27 @@ inline AutoSweepObjectGroup::~AutoSweepObjectGroup() {
|
|||
}
|
||||
#endif
|
||||
|
||||
inline AutoSweepTypeScript::AutoSweepTypeScript(JSScript* script)
|
||||
inline AutoSweepJitScript::AutoSweepJitScript(JSScript* script)
|
||||
#ifdef DEBUG
|
||||
: zone_(script->zone()),
|
||||
typeScript_(script->types())
|
||||
jitScript_(script->jitScript())
|
||||
#endif
|
||||
{
|
||||
if (TypeScript* types = script->types()) {
|
||||
if (JitScript* jitScript = script->jitScript()) {
|
||||
Zone* zone = script->zone();
|
||||
if (types->typesNeedsSweep(zone)) {
|
||||
types->sweepTypes(*this, zone);
|
||||
if (jitScript->typesNeedsSweep(zone)) {
|
||||
jitScript->sweepTypes(*this, zone);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
inline AutoSweepTypeScript::~AutoSweepTypeScript() {
|
||||
inline AutoSweepJitScript::~AutoSweepJitScript() {
|
||||
// This should still hold.
|
||||
MOZ_ASSERT_IF(typeScript_, !typeScript_->typesNeedsSweep(zone_));
|
||||
MOZ_ASSERT_IF(jitScript_, !jitScript_->typesNeedsSweep(zone_));
|
||||
}
|
||||
#endif
|
||||
|
||||
inline bool TypeScript::typesNeedsSweep(Zone* zone) const {
|
||||
MOZ_ASSERT(!js::TlsContext.get()->inUnsafeCallWithABI);
|
||||
return typesGeneration() != zone->types.generation;
|
||||
}
|
||||
|
||||
} // namespace js
|
||||
|
||||
inline bool JSScript::ensureHasTypes(JSContext* cx, js::AutoKeepTypeScripts&) {
|
||||
return types() || makeTypes(cx);
|
||||
}
|
||||
|
||||
#endif /* vm_TypeInference_inl_h */
|
||||
|
|
|
@ -1186,16 +1186,16 @@ CompilerConstraintList* js::NewCompilerConstraintList(
|
|||
}
|
||||
|
||||
/* static */
|
||||
bool TypeScript::FreezeTypeSets(CompilerConstraintList* constraints,
|
||||
bool JitScript::FreezeTypeSets(CompilerConstraintList* constraints,
|
||||
JSScript* script, TemporaryTypeSet** pThisTypes,
|
||||
TemporaryTypeSet** pArgTypes,
|
||||
TemporaryTypeSet** pBytecodeTypes) {
|
||||
LifoAlloc* alloc = constraints->alloc();
|
||||
AutoSweepTypeScript sweep(script);
|
||||
TypeScript* typeScript = script->types();
|
||||
StackTypeSet* existing = typeScript->typeArray(sweep);
|
||||
AutoSweepJitScript sweep(script);
|
||||
JitScript* jitScript = script->jitScript();
|
||||
StackTypeSet* existing = jitScript->typeArray(sweep);
|
||||
|
||||
size_t count = typeScript->numTypeSets();
|
||||
size_t count = jitScript->numTypeSets();
|
||||
TemporaryTypeSet* types =
|
||||
alloc->newArrayUninitialized<TemporaryTypeSet>(count);
|
||||
if (!types) {
|
||||
|
@ -1208,12 +1208,12 @@ bool TypeScript::FreezeTypeSets(CompilerConstraintList* constraints,
|
|||
}
|
||||
}
|
||||
|
||||
size_t thisTypesIndex = typeScript->thisTypes(sweep, script) - existing;
|
||||
size_t thisTypesIndex = jitScript->thisTypes(sweep, script) - existing;
|
||||
*pThisTypes = types + thisTypesIndex;
|
||||
|
||||
if (script->functionNonDelazifying() &&
|
||||
script->functionNonDelazifying()->nargs() > 0) {
|
||||
size_t firstArgIndex = typeScript->argTypes(sweep, script, 0) - existing;
|
||||
size_t firstArgIndex = jitScript->argTypes(sweep, script, 0) - existing;
|
||||
*pArgTypes = types + firstArgIndex;
|
||||
} else {
|
||||
*pArgTypes = nullptr;
|
||||
|
@ -1426,7 +1426,7 @@ bool HeapTypeSetKey::instantiate(JSContext* cx) {
|
|||
return maybeTypes_ != nullptr;
|
||||
}
|
||||
|
||||
static bool CheckFrozenTypeSet(const AutoSweepTypeScript& sweep, JSContext* cx,
|
||||
static bool CheckFrozenTypeSet(const AutoSweepJitScript& sweep, JSContext* cx,
|
||||
TemporaryTypeSet* frozen, StackTypeSet* actual) {
|
||||
// Return whether the types frozen for a script during compilation are
|
||||
// still valid. Also check for any new types added to the frozen set during
|
||||
|
@ -1509,8 +1509,8 @@ bool js::FinishCompilation(JSContext* cx, HandleScript script,
|
|||
for (size_t i = 0; i < constraints->numFrozenScripts(); i++) {
|
||||
const CompilerConstraintList::FrozenScript& entry =
|
||||
constraints->frozenScript(i);
|
||||
TypeScript* types = entry.script->types();
|
||||
if (!types) {
|
||||
JitScript* jitScript = entry.script->jitScript();
|
||||
if (!jitScript) {
|
||||
succeeded = false;
|
||||
break;
|
||||
}
|
||||
|
@ -1523,10 +1523,9 @@ bool js::FinishCompilation(JSContext* cx, HandleScript script,
|
|||
break;
|
||||
}
|
||||
|
||||
AutoSweepTypeScript sweep(entry.script);
|
||||
TypeScript* typeScript = entry.script->types();
|
||||
AutoSweepJitScript sweep(entry.script);
|
||||
if (!CheckFrozenTypeSet(sweep, cx, entry.thisTypes,
|
||||
typeScript->thisTypes(sweep, entry.script))) {
|
||||
jitScript->thisTypes(sweep, entry.script))) {
|
||||
succeeded = false;
|
||||
}
|
||||
unsigned nargs = entry.script->functionNonDelazifying()
|
||||
|
@ -1534,13 +1533,13 @@ bool js::FinishCompilation(JSContext* cx, HandleScript script,
|
|||
: 0;
|
||||
for (size_t i = 0; i < nargs; i++) {
|
||||
if (!CheckFrozenTypeSet(sweep, cx, &entry.argTypes[i],
|
||||
typeScript->argTypes(sweep, entry.script, i))) {
|
||||
jitScript->argTypes(sweep, entry.script, i))) {
|
||||
succeeded = false;
|
||||
}
|
||||
}
|
||||
for (size_t i = 0; i < entry.script->numBytecodeTypeSets(); i++) {
|
||||
if (!CheckFrozenTypeSet(sweep, cx, &entry.bytecodeTypes[i],
|
||||
&types->typeArray(sweep)[i])) {
|
||||
&jitScript->typeArray(sweep)[i])) {
|
||||
succeeded = false;
|
||||
}
|
||||
}
|
||||
|
@ -1548,19 +1547,19 @@ bool js::FinishCompilation(JSContext* cx, HandleScript script,
|
|||
// Add this compilation to the inlinedCompilations list of each inlined
|
||||
// script, so we can invalidate it on changes to stack type sets.
|
||||
if (entry.script != script) {
|
||||
if (!types->addInlinedCompilation(sweep, recompileInfo)) {
|
||||
if (!jitScript->addInlinedCompilation(sweep, recompileInfo)) {
|
||||
succeeded = false;
|
||||
}
|
||||
}
|
||||
|
||||
// If necessary, add constraints to trigger invalidation on the script
|
||||
// after any future changes to the stack type sets.
|
||||
if (types->hasFreezeConstraints(sweep)) {
|
||||
if (jitScript->hasFreezeConstraints(sweep)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
size_t count = types->numTypeSets();
|
||||
StackTypeSet* array = types->typeArray(sweep);
|
||||
size_t count = jitScript->numTypeSets();
|
||||
StackTypeSet* array = jitScript->typeArray(sweep);
|
||||
for (size_t i = 0; i < count; i++) {
|
||||
if (!array[i].addConstraint(
|
||||
cx,
|
||||
|
@ -1571,7 +1570,7 @@ bool js::FinishCompilation(JSContext* cx, HandleScript script,
|
|||
}
|
||||
|
||||
if (succeeded) {
|
||||
types->setHasFreezeConstraints(sweep);
|
||||
jitScript->setHasFreezeConstraints(sweep);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1585,7 +1584,7 @@ bool js::FinishCompilation(JSContext* cx, HandleScript script,
|
|||
return true;
|
||||
}
|
||||
|
||||
static void CheckDefinitePropertiesTypeSet(const AutoSweepTypeScript& sweep,
|
||||
static void CheckDefinitePropertiesTypeSet(const AutoSweepJitScript& sweep,
|
||||
JSContext* cx,
|
||||
TemporaryTypeSet* frozen,
|
||||
StackTypeSet* actual) {
|
||||
|
@ -1615,22 +1614,22 @@ void js::FinishDefinitePropertiesAnalysis(JSContext* cx,
|
|||
const CompilerConstraintList::FrozenScript& entry =
|
||||
constraints->frozenScript(i);
|
||||
JSScript* script = entry.script;
|
||||
TypeScript* typeScript = script->types();
|
||||
MOZ_ASSERT(typeScript);
|
||||
JitScript* jitScript = script->jitScript();
|
||||
MOZ_ASSERT(jitScript);
|
||||
|
||||
AutoSweepTypeScript sweep(script);
|
||||
MOZ_ASSERT(typeScript->thisTypes(sweep, script)->isSubset(entry.thisTypes));
|
||||
AutoSweepJitScript sweep(script);
|
||||
MOZ_ASSERT(jitScript->thisTypes(sweep, script)->isSubset(entry.thisTypes));
|
||||
|
||||
unsigned nargs = entry.script->functionNonDelazifying()
|
||||
? entry.script->functionNonDelazifying()->nargs()
|
||||
: 0;
|
||||
for (size_t j = 0; j < nargs; j++) {
|
||||
StackTypeSet* argTypes = typeScript->argTypes(sweep, script, j);
|
||||
StackTypeSet* argTypes = jitScript->argTypes(sweep, script, j);
|
||||
MOZ_ASSERT(argTypes->isSubset(&entry.argTypes[j]));
|
||||
}
|
||||
|
||||
for (size_t j = 0; j < script->numBytecodeTypeSets(); j++) {
|
||||
MOZ_ASSERT(script->types()->typeArray(sweep)[j].isSubset(
|
||||
MOZ_ASSERT(script->jitScript()->typeArray(sweep)[j].isSubset(
|
||||
&entry.bytecodeTypes[j]));
|
||||
}
|
||||
}
|
||||
|
@ -1640,26 +1639,26 @@ void js::FinishDefinitePropertiesAnalysis(JSContext* cx,
|
|||
const CompilerConstraintList::FrozenScript& entry =
|
||||
constraints->frozenScript(i);
|
||||
JSScript* script = entry.script;
|
||||
TypeScript* types = script->types();
|
||||
if (!types) {
|
||||
JitScript* jitScript = script->jitScript();
|
||||
if (!jitScript) {
|
||||
MOZ_CRASH();
|
||||
}
|
||||
|
||||
AutoSweepTypeScript sweep(script);
|
||||
AutoSweepJitScript sweep(script);
|
||||
CheckDefinitePropertiesTypeSet(sweep, cx, entry.thisTypes,
|
||||
types->thisTypes(sweep, script));
|
||||
jitScript->thisTypes(sweep, script));
|
||||
|
||||
unsigned nargs = script->functionNonDelazifying()
|
||||
? script->functionNonDelazifying()->nargs()
|
||||
: 0;
|
||||
for (size_t j = 0; j < nargs; j++) {
|
||||
StackTypeSet* argTypes = types->argTypes(sweep, script, j);
|
||||
StackTypeSet* argTypes = jitScript->argTypes(sweep, script, j);
|
||||
CheckDefinitePropertiesTypeSet(sweep, cx, &entry.argTypes[j], argTypes);
|
||||
}
|
||||
|
||||
for (size_t j = 0; j < script->numBytecodeTypeSets(); j++) {
|
||||
CheckDefinitePropertiesTypeSet(sweep, cx, &entry.bytecodeTypes[j],
|
||||
&types->typeArray(sweep)[j]);
|
||||
&jitScript->typeArray(sweep)[j]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2696,12 +2695,12 @@ void TypeZone::addPendingRecompile(JSContext* cx, JSScript* script) {
|
|||
}
|
||||
|
||||
// Trigger recompilation of any callers inlining this script.
|
||||
if (TypeScript* types = script->types()) {
|
||||
AutoSweepTypeScript sweep(script);
|
||||
for (const RecompileInfo& info : types->inlinedCompilations(sweep)) {
|
||||
if (JitScript* jitScript = script->jitScript()) {
|
||||
AutoSweepJitScript sweep(script);
|
||||
for (const RecompileInfo& info : jitScript->inlinedCompilations(sweep)) {
|
||||
addPendingRecompile(cx, info);
|
||||
}
|
||||
types->inlinedCompilations(sweep).clearAndFree();
|
||||
jitScript->inlinedCompilations(sweep).clearAndFree();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2733,8 +2732,8 @@ void js::PrintTypes(JSContext* cx, Compartment* comp, bool force) {
|
|||
RootedScript script(cx);
|
||||
for (auto iter = zone->cellIter<JSScript>(); !iter.done(); iter.next()) {
|
||||
script = iter;
|
||||
if (TypeScript* types = script->types()) {
|
||||
types->printTypes(cx, script);
|
||||
if (JitScript* jitScript = script->jitScript()) {
|
||||
jitScript->printTypes(cx, script);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3334,10 +3333,10 @@ bool js::AddClearDefiniteFunctionUsesInScript(JSContext* cx, ObjectGroup* group,
|
|||
TypeSet::ObjectKey* calleeKey =
|
||||
TypeSet::ObjectType(calleeScript->functionNonDelazifying()).objectKey();
|
||||
|
||||
AutoSweepTypeScript sweep(script);
|
||||
TypeScript* typeScript = script->types();
|
||||
unsigned count = typeScript->numTypeSets();
|
||||
StackTypeSet* typeArray = typeScript->typeArray(sweep);
|
||||
AutoSweepJitScript sweep(script);
|
||||
JitScript* jitScript = script->jitScript();
|
||||
unsigned count = jitScript->numTypeSets();
|
||||
StackTypeSet* typeArray = jitScript->typeArray(sweep);
|
||||
|
||||
for (unsigned i = 0; i < count; i++) {
|
||||
StackTypeSet* types = &typeArray[i];
|
||||
|
@ -3381,7 +3380,7 @@ void js::TypeMonitorCallSlow(JSContext* cx, JSObject* callee,
|
|||
JSScript* script = callee->as<JSFunction>().nonLazyScript();
|
||||
|
||||
if (!constructing) {
|
||||
TypeScript::MonitorThisType(cx, script, args.thisv());
|
||||
JitScript::MonitorThisType(cx, script, args.thisv());
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -3391,39 +3390,24 @@ void js::TypeMonitorCallSlow(JSContext* cx, JSObject* callee,
|
|||
*/
|
||||
unsigned arg = 0;
|
||||
for (; arg < args.length() && arg < nargs; arg++) {
|
||||
TypeScript::MonitorArgType(cx, script, arg, args[arg]);
|
||||
JitScript::MonitorArgType(cx, script, arg, args[arg]);
|
||||
}
|
||||
|
||||
/* Watch for fewer actuals than formals to the call. */
|
||||
for (; arg < nargs; arg++) {
|
||||
TypeScript::MonitorArgType(cx, script, arg, UndefinedValue());
|
||||
JitScript::MonitorArgType(cx, script, arg, UndefinedValue());
|
||||
}
|
||||
}
|
||||
|
||||
static void FillBytecodeTypeMap(JSScript* script, uint32_t* bytecodeMap) {
|
||||
uint32_t added = 0;
|
||||
for (jsbytecode* pc = script->code(); pc < script->codeEnd();
|
||||
pc += GetBytecodeLength(pc)) {
|
||||
JSOp op = JSOp(*pc);
|
||||
if (CodeSpec[op].format & JOF_TYPESET) {
|
||||
bytecodeMap[added++] = script->pcToOffset(pc);
|
||||
if (added == script->numBytecodeTypeSets()) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
MOZ_ASSERT(added == script->numBytecodeTypeSets());
|
||||
}
|
||||
|
||||
/* static */
|
||||
void TypeScript::MonitorBytecodeType(JSContext* cx, JSScript* script,
|
||||
void JitScript::MonitorBytecodeType(JSContext* cx, JSScript* script,
|
||||
jsbytecode* pc, TypeSet::Type type) {
|
||||
cx->check(script, type);
|
||||
|
||||
AutoEnterAnalysis enter(cx);
|
||||
|
||||
AutoSweepTypeScript sweep(script);
|
||||
StackTypeSet* types = script->types()->bytecodeTypes(sweep, script, pc);
|
||||
AutoSweepJitScript sweep(script);
|
||||
StackTypeSet* types = script->jitScript()->bytecodeTypes(sweep, script, pc);
|
||||
if (types->hasType(type)) {
|
||||
return;
|
||||
}
|
||||
|
@ -3434,16 +3418,16 @@ void TypeScript::MonitorBytecodeType(JSContext* cx, JSScript* script,
|
|||
}
|
||||
|
||||
/* static */
|
||||
void TypeScript::MonitorBytecodeTypeSlow(JSContext* cx, JSScript* script,
|
||||
void JitScript::MonitorBytecodeTypeSlow(JSContext* cx, JSScript* script,
|
||||
jsbytecode* pc, StackTypeSet* types,
|
||||
TypeSet::Type type) {
|
||||
cx->check(script, type);
|
||||
|
||||
AutoEnterAnalysis enter(cx);
|
||||
|
||||
AutoSweepTypeScript sweep(script);
|
||||
AutoSweepJitScript sweep(script);
|
||||
|
||||
MOZ_ASSERT(types == script->types()->bytecodeTypes(sweep, script, pc));
|
||||
MOZ_ASSERT(types == script->jitScript()->bytecodeTypes(sweep, script, pc));
|
||||
MOZ_ASSERT(!types->hasType(type));
|
||||
|
||||
InferSpew(ISpewOps, "bytecodeType: %p %05zu: %s", script,
|
||||
|
@ -3452,130 +3436,17 @@ void TypeScript::MonitorBytecodeTypeSlow(JSContext* cx, JSScript* script,
|
|||
}
|
||||
|
||||
/* static */
|
||||
void TypeScript::MonitorBytecodeType(JSContext* cx, JSScript* script,
|
||||
void JitScript::MonitorBytecodeType(JSContext* cx, JSScript* script,
|
||||
jsbytecode* pc, const js::Value& rval) {
|
||||
MOZ_ASSERT(CodeSpec[*pc].format & JOF_TYPESET);
|
||||
|
||||
if (!script->types()) {
|
||||
if (!script->jitScript()) {
|
||||
return;
|
||||
}
|
||||
|
||||
MonitorBytecodeType(cx, script, pc, TypeSet::GetValueType(rval));
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////
|
||||
// TypeScript
|
||||
/////////////////////////////////////////////////////////////////////
|
||||
|
||||
static size_t NumTypeSets(JSScript* script) {
|
||||
size_t num = script->numBytecodeTypeSets() + 1 /* this */;
|
||||
if (JSFunction* fun = script->functionNonDelazifying()) {
|
||||
num += fun->nargs();
|
||||
}
|
||||
|
||||
// We rely on |num| being in a safe range to prevent overflow when allocating
|
||||
// TypeScript.
|
||||
static_assert(JSScript::MaxBytecodeTypeSets == UINT16_MAX,
|
||||
"JSScript typesets should have safe range to avoid overflow");
|
||||
static_assert(JSFunction::NArgsBits == 16,
|
||||
"JSFunction nargs should have safe range to avoid overflow");
|
||||
|
||||
return num;
|
||||
}
|
||||
|
||||
TypeScript::TypeScript(JSScript* script, ICScriptPtr&& icScript,
|
||||
uint32_t numTypeSets)
|
||||
: icScript_(std::move(icScript)), numTypeSets_(numTypeSets) {
|
||||
setTypesGeneration(script->zone()->types.generation);
|
||||
|
||||
StackTypeSet* array = typeArrayDontCheckGeneration();
|
||||
for (unsigned i = 0; i < numTypeSets; i++) {
|
||||
new (&array[i]) StackTypeSet();
|
||||
}
|
||||
|
||||
FillBytecodeTypeMap(script, bytecodeTypeMap());
|
||||
}
|
||||
|
||||
bool JSScript::makeTypes(JSContext* cx) {
|
||||
MOZ_ASSERT(!types_);
|
||||
cx->check(this);
|
||||
|
||||
// Scripts that will never run in the Baseline Interpreter or the JITs don't
|
||||
// need a TypeScript.
|
||||
MOZ_ASSERT(!hasForceInterpreterOp());
|
||||
|
||||
AutoEnterAnalysis enter(cx);
|
||||
|
||||
// Run the arguments-analysis if needed. Both the Baseline Interpreter and
|
||||
// Compiler rely on this.
|
||||
if (!ensureHasAnalyzedArgsUsage(cx)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// If ensureHasAnalyzedArgsUsage allocated the TypeScript we're done.
|
||||
if (types_) {
|
||||
return true;
|
||||
}
|
||||
|
||||
UniquePtr<jit::ICScript> icScript(jit::ICScript::create(cx, this));
|
||||
if (!icScript) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// We need to call prepareForDestruction on ICScript before we |delete| it.
|
||||
auto prepareForDestruction = mozilla::MakeScopeExit(
|
||||
[&] { icScript->prepareForDestruction(cx->zone()); });
|
||||
|
||||
size_t numTypeSets = NumTypeSets(this);
|
||||
size_t bytecodeTypeMapEntries = numBytecodeTypeSets();
|
||||
|
||||
// Calculate allocation size. This cannot overflow, see comment in
|
||||
// NumTypeSets.
|
||||
static_assert(sizeof(TypeScript) ==
|
||||
sizeof(StackTypeSet) + offsetof(TypeScript, typeArray_),
|
||||
"typeArray_ must be last member of TypeScript");
|
||||
size_t allocSize =
|
||||
(offsetof(TypeScript, typeArray_) + numTypeSets * sizeof(StackTypeSet) +
|
||||
bytecodeTypeMapEntries * sizeof(uint32_t));
|
||||
|
||||
auto typeScript =
|
||||
reinterpret_cast<TypeScript*>(cx->pod_malloc<uint8_t>(allocSize));
|
||||
if (!typeScript) {
|
||||
return false;
|
||||
}
|
||||
|
||||
prepareForDestruction.release();
|
||||
|
||||
MOZ_ASSERT(!types_);
|
||||
types_ = new (typeScript) TypeScript(this, std::move(icScript), numTypeSets);
|
||||
|
||||
// We have a TypeScript so we can set the script's jitCodeRaw_ pointer to the
|
||||
// Baseline Interpreter code.
|
||||
updateJitCodeRaw(cx->runtime());
|
||||
|
||||
#ifdef DEBUG
|
||||
AutoSweepTypeScript sweep(this);
|
||||
StackTypeSet* typeArray = typeScript->typeArrayDontCheckGeneration();
|
||||
for (unsigned i = 0; i < numBytecodeTypeSets(); i++) {
|
||||
InferSpew(ISpewOps, "typeSet: %sT%p%s bytecode%u %p",
|
||||
InferSpewColor(&typeArray[i]), &typeArray[i],
|
||||
InferSpewColorReset(), i, this);
|
||||
}
|
||||
StackTypeSet* thisTypes = typeScript->thisTypes(sweep, this);
|
||||
InferSpew(ISpewOps, "typeSet: %sT%p%s this %p", InferSpewColor(thisTypes),
|
||||
thisTypes, InferSpewColorReset(), this);
|
||||
unsigned nargs =
|
||||
functionNonDelazifying() ? functionNonDelazifying()->nargs() : 0;
|
||||
for (unsigned i = 0; i < nargs; i++) {
|
||||
StackTypeSet* types = typeScript->argTypes(sweep, this, i);
|
||||
InferSpew(ISpewOps, "typeSet: %sT%p%s arg%u %p", InferSpewColor(types),
|
||||
types, InferSpewColorReset(), i, this);
|
||||
}
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/* static */
|
||||
bool JSFunction::setTypeForScriptedFunction(JSContext* cx, HandleFunction fun,
|
||||
bool singleton /* = false */) {
|
||||
|
@ -4498,7 +4369,7 @@ void ObjectGroup::sweep(const AutoSweepObjectGroup& sweep) {
|
|||
}
|
||||
|
||||
/* static */
|
||||
void TypeScript::sweepTypes(const js::AutoSweepTypeScript& sweep, Zone* zone) {
|
||||
void JitScript::sweepTypes(const js::AutoSweepJitScript& sweep, Zone* zone) {
|
||||
MOZ_ASSERT(typesGeneration() != zone->types.generation);
|
||||
setTypesGeneration(zone->types.generation);
|
||||
|
||||
|
@ -4539,25 +4410,6 @@ void TypeScript::sweepTypes(const js::AutoSweepTypeScript& sweep, Zone* zone) {
|
|||
}
|
||||
}
|
||||
|
||||
void JSScript::maybeReleaseTypes() {
|
||||
if (!types_ || zone()->types.keepTypeScripts || hasBaselineScript() ||
|
||||
types_->active()) {
|
||||
return;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(!hasIonScript());
|
||||
|
||||
types_->destroy(zone());
|
||||
types_ = nullptr;
|
||||
updateJitCodeRaw(runtimeFromMainThread());
|
||||
}
|
||||
|
||||
void TypeScript::destroy(Zone* zone) {
|
||||
icScript_->prepareForDestruction(zone);
|
||||
|
||||
js_delete(this);
|
||||
}
|
||||
|
||||
void Zone::addSizeOfIncludingThis(
|
||||
mozilla::MallocSizeOf mallocSizeOf, size_t* typePool, size_t* regexpZone,
|
||||
size_t* jitZone, size_t* baselineStubsOptimized, size_t* cachedCFG,
|
||||
|
@ -4590,12 +4442,12 @@ TypeZone::TypeZone(Zone* zone)
|
|||
sweepTypeLifoAlloc(zone, (size_t)TYPE_LIFO_ALLOC_PRIMARY_CHUNK_SIZE),
|
||||
sweepingTypes(zone, false),
|
||||
oomSweepingTypes(zone, false),
|
||||
keepTypeScripts(zone, false),
|
||||
keepJitScripts(zone, false),
|
||||
activeAnalysis(zone, nullptr) {}
|
||||
|
||||
TypeZone::~TypeZone() {
|
||||
MOZ_RELEASE_ASSERT(!sweepingTypes);
|
||||
MOZ_ASSERT(!keepTypeScripts);
|
||||
MOZ_ASSERT(!keepJitScripts);
|
||||
}
|
||||
|
||||
void TypeZone::beginSweep() {
|
||||
|
@ -4638,65 +4490,6 @@ AutoClearTypeInferenceStateOnOOM::~AutoClearTypeInferenceStateOnOOM() {
|
|||
zone->types.setSweepingTypes(false);
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
void TypeScript::printTypes(JSContext* cx, HandleScript script) {
|
||||
AutoSweepTypeScript sweep(script);
|
||||
MOZ_ASSERT(script->types() == this);
|
||||
|
||||
AutoEnterAnalysis enter(nullptr, script->zone());
|
||||
Fprinter out(stderr);
|
||||
|
||||
if (script->functionNonDelazifying()) {
|
||||
fprintf(stderr, "Function");
|
||||
} else if (script->isForEval()) {
|
||||
fprintf(stderr, "Eval");
|
||||
} else {
|
||||
fprintf(stderr, "Main");
|
||||
}
|
||||
fprintf(stderr, " %#" PRIxPTR " %s:%u ", uintptr_t(script.get()),
|
||||
script->filename(), script->lineno());
|
||||
|
||||
if (script->functionNonDelazifying()) {
|
||||
if (JSAtom* name = script->functionNonDelazifying()->explicitName()) {
|
||||
name->dumpCharsNoNewline(out);
|
||||
}
|
||||
}
|
||||
|
||||
fprintf(stderr, "\n this:");
|
||||
thisTypes(sweep, script)->print();
|
||||
|
||||
for (unsigned i = 0; script->functionNonDelazifying() &&
|
||||
i < script->functionNonDelazifying()->nargs();
|
||||
i++) {
|
||||
fprintf(stderr, "\n arg%u:", i);
|
||||
argTypes(sweep, script, i)->print();
|
||||
}
|
||||
fprintf(stderr, "\n");
|
||||
|
||||
for (jsbytecode* pc = script->code(); pc < script->codeEnd();
|
||||
pc += GetBytecodeLength(pc)) {
|
||||
{
|
||||
fprintf(stderr, "%p:", script.get());
|
||||
Sprinter sprinter(cx);
|
||||
if (!sprinter.init()) {
|
||||
return;
|
||||
}
|
||||
Disassemble1(cx, script, pc, script->pcToOffset(pc), true, &sprinter);
|
||||
fprintf(stderr, "%s", sprinter.string());
|
||||
}
|
||||
|
||||
if (CodeSpec[*pc].format & JOF_TYPESET) {
|
||||
StackTypeSet* types = bytecodeTypes(sweep, script, pc);
|
||||
fprintf(stderr, " typeset %u:", unsigned(types - typeArray(sweep)));
|
||||
types->print();
|
||||
fprintf(stderr, "\n");
|
||||
}
|
||||
}
|
||||
|
||||
fprintf(stderr, "\n");
|
||||
}
|
||||
#endif /* DEBUG */
|
||||
|
||||
JS::ubi::Node::Size JS::ubi::Concrete<js::ObjectGroup>::size(
|
||||
mozilla::MallocSizeOf mallocSizeOf) const {
|
||||
Size size = js::gc::Arena::thingSize(get().asTenured().getAllocKind());
|
||||
|
|
|
@ -31,14 +31,13 @@
|
|||
namespace js {
|
||||
|
||||
class TypeConstraint;
|
||||
class TypeScript;
|
||||
class JitScript;
|
||||
class TypeZone;
|
||||
class CompilerConstraintList;
|
||||
class HeapTypeSetKey;
|
||||
|
||||
namespace jit {
|
||||
|
||||
class ICScript;
|
||||
struct IonScript;
|
||||
class TempAllocator;
|
||||
|
||||
|
@ -84,20 +83,20 @@ class MOZ_RAII AutoSweepObjectGroup : public AutoSweepBase {
|
|||
#endif
|
||||
};
|
||||
|
||||
// Sweep a TypeScript. Functions that expect a swept script should take a
|
||||
// reference to this class.
|
||||
class MOZ_RAII AutoSweepTypeScript : public AutoSweepBase {
|
||||
// Sweep the type inference data in a JitScript. Functions that expect a swept
|
||||
// script should take a reference to this class.
|
||||
class MOZ_RAII AutoSweepJitScript : public AutoSweepBase {
|
||||
#ifdef DEBUG
|
||||
Zone* zone_;
|
||||
TypeScript* typeScript_;
|
||||
JitScript* jitScript_;
|
||||
#endif
|
||||
|
||||
public:
|
||||
inline explicit AutoSweepTypeScript(JSScript* script);
|
||||
inline explicit AutoSweepJitScript(JSScript* script);
|
||||
#ifdef DEBUG
|
||||
inline ~AutoSweepTypeScript();
|
||||
inline ~AutoSweepJitScript();
|
||||
|
||||
TypeScript* typeScript() const { return typeScript_; }
|
||||
JitScript* jitScript() const { return jitScript_; }
|
||||
Zone* zone() const { return zone_; }
|
||||
#endif
|
||||
};
|
||||
|
@ -201,206 +200,6 @@ class RecompileInfo {
|
|||
// single IonScript doesn't require an allocation.
|
||||
typedef Vector<RecompileInfo, 1, SystemAllocPolicy> RecompileInfoVector;
|
||||
|
||||
/* Persistent type information for a script, retained across GCs. */
|
||||
class TypeScript {
|
||||
friend class ::JSScript;
|
||||
|
||||
// The freeze constraints added to stack type sets will only directly
|
||||
// invalidate the script containing those stack type sets. This Vector
|
||||
// contains compilations that inlined this script, so we can invalidate
|
||||
// them as well.
|
||||
RecompileInfoVector inlinedCompilations_;
|
||||
|
||||
// ICScript and TypeScript have the same lifetimes, so we store a pointer to
|
||||
// ICScript here to not increase sizeof(JSScript).
|
||||
using ICScriptPtr = js::UniquePtr<js::jit::ICScript>;
|
||||
ICScriptPtr icScript_;
|
||||
|
||||
// Number of TypeSets in typeArray_.
|
||||
uint32_t numTypeSets_;
|
||||
|
||||
// This field is used to avoid binary searches for the sought entry when
|
||||
// bytecode map queries are in linear order.
|
||||
uint32_t bytecodeTypeMapHint_ = 0;
|
||||
|
||||
struct Flags {
|
||||
// Flag set when discarding JIT code to indicate this script is on the stack
|
||||
// and type information and JIT code should not be discarded.
|
||||
bool active : 1;
|
||||
|
||||
// Generation for type sweeping. If out of sync with the TypeZone's
|
||||
// generation, this TypeScript needs to be swept.
|
||||
bool typesGeneration : 1;
|
||||
|
||||
// Whether freeze constraints for stack type sets have been generated.
|
||||
bool hasFreezeConstraints : 1;
|
||||
};
|
||||
Flags flags_ = {}; // Zero-initialize flags.
|
||||
|
||||
// Variable-size array. This is followed by the bytecode type map.
|
||||
StackTypeSet typeArray_[1];
|
||||
|
||||
StackTypeSet* typeArrayDontCheckGeneration() {
|
||||
// Ensure typeArray_ is the last data member of TypeScript.
|
||||
static_assert(sizeof(TypeScript) ==
|
||||
sizeof(typeArray_) + offsetof(TypeScript, typeArray_),
|
||||
"typeArray_ must be the last member of TypeScript");
|
||||
return const_cast<StackTypeSet*>(typeArray_);
|
||||
}
|
||||
|
||||
uint32_t typesGeneration() const { return uint32_t(flags_.typesGeneration); }
|
||||
void setTypesGeneration(uint32_t generation) {
|
||||
MOZ_ASSERT(generation <= 1);
|
||||
flags_.typesGeneration = generation;
|
||||
}
|
||||
|
||||
public:
|
||||
TypeScript(JSScript* script, ICScriptPtr&& icScript, uint32_t numTypeSets);
|
||||
|
||||
bool hasFreezeConstraints(const js::AutoSweepTypeScript& sweep) const {
|
||||
MOZ_ASSERT(sweep.typeScript() == this);
|
||||
return flags_.hasFreezeConstraints;
|
||||
}
|
||||
void setHasFreezeConstraints(const js::AutoSweepTypeScript& sweep) {
|
||||
MOZ_ASSERT(sweep.typeScript() == this);
|
||||
flags_.hasFreezeConstraints = true;
|
||||
}
|
||||
|
||||
inline bool typesNeedsSweep(Zone* zone) const;
|
||||
void sweepTypes(const js::AutoSweepTypeScript& sweep, Zone* zone);
|
||||
|
||||
RecompileInfoVector& inlinedCompilations(
|
||||
const js::AutoSweepTypeScript& sweep) {
|
||||
MOZ_ASSERT(sweep.typeScript() == this);
|
||||
return inlinedCompilations_;
|
||||
}
|
||||
MOZ_MUST_USE bool addInlinedCompilation(const js::AutoSweepTypeScript& sweep,
|
||||
RecompileInfo info) {
|
||||
MOZ_ASSERT(sweep.typeScript() == this);
|
||||
if (!inlinedCompilations_.empty() && inlinedCompilations_.back() == info) {
|
||||
return true;
|
||||
}
|
||||
return inlinedCompilations_.append(info);
|
||||
}
|
||||
|
||||
uint32_t numTypeSets() const { return numTypeSets_; }
|
||||
|
||||
uint32_t* bytecodeTypeMapHint() { return &bytecodeTypeMapHint_; }
|
||||
|
||||
bool active() const { return flags_.active; }
|
||||
void setActive() { flags_.active = true; }
|
||||
void resetActive() { flags_.active = false; }
|
||||
|
||||
jit::ICScript* icScript() const {
|
||||
MOZ_ASSERT(icScript_);
|
||||
return icScript_.get();
|
||||
}
|
||||
|
||||
/* Array of type sets for variables and JOF_TYPESET ops. */
|
||||
StackTypeSet* typeArray(const js::AutoSweepTypeScript& sweep) {
|
||||
MOZ_ASSERT(sweep.typeScript() == this);
|
||||
return typeArrayDontCheckGeneration();
|
||||
}
|
||||
|
||||
uint32_t* bytecodeTypeMap() {
|
||||
MOZ_ASSERT(numTypeSets_ > 0);
|
||||
return reinterpret_cast<uint32_t*>(typeArray_ + numTypeSets_);
|
||||
}
|
||||
|
||||
inline StackTypeSet* thisTypes(const AutoSweepTypeScript& sweep,
|
||||
JSScript* script);
|
||||
inline StackTypeSet* argTypes(const AutoSweepTypeScript& sweep,
|
||||
JSScript* script, unsigned i);
|
||||
|
||||
/* Get the type set for values observed at an opcode. */
|
||||
inline StackTypeSet* bytecodeTypes(const AutoSweepTypeScript& sweep,
|
||||
JSScript* script, jsbytecode* pc);
|
||||
|
||||
template <typename TYPESET>
|
||||
static inline TYPESET* BytecodeTypes(JSScript* script, jsbytecode* pc,
|
||||
uint32_t* bytecodeMap, uint32_t* hint,
|
||||
TYPESET* typeArray);
|
||||
|
||||
/*
|
||||
* Monitor a bytecode pushing any value. This must be called for any opcode
|
||||
* which is JOF_TYPESET, and where either the script has not been analyzed
|
||||
* by type inference or where the pc has type barriers. For simplicity, we
|
||||
* always monitor JOF_TYPESET opcodes in the interpreter and stub calls,
|
||||
* and only look at barriers when generating JIT code for the script.
|
||||
*/
|
||||
static void MonitorBytecodeType(JSContext* cx, JSScript* script,
|
||||
jsbytecode* pc, const js::Value& val);
|
||||
static void MonitorBytecodeType(JSContext* cx, JSScript* script,
|
||||
jsbytecode* pc, TypeSet::Type type);
|
||||
|
||||
static inline void MonitorBytecodeType(JSContext* cx, JSScript* script,
|
||||
jsbytecode* pc, StackTypeSet* types,
|
||||
const js::Value& val);
|
||||
|
||||
private:
|
||||
static void MonitorBytecodeTypeSlow(JSContext* cx, JSScript* script,
|
||||
jsbytecode* pc, StackTypeSet* types,
|
||||
TypeSet::Type type);
|
||||
|
||||
public:
|
||||
/* Monitor an assignment at a SETELEM on a non-integer identifier. */
|
||||
static inline void MonitorAssign(JSContext* cx, HandleObject obj, jsid id);
|
||||
|
||||
/* Add a type for a variable in a script. */
|
||||
static inline void MonitorThisType(JSContext* cx, JSScript* script,
|
||||
TypeSet::Type type);
|
||||
static inline void MonitorThisType(JSContext* cx, JSScript* script,
|
||||
const js::Value& value);
|
||||
static inline void MonitorArgType(JSContext* cx, JSScript* script,
|
||||
unsigned arg, TypeSet::Type type);
|
||||
static inline void MonitorArgType(JSContext* cx, JSScript* script,
|
||||
unsigned arg, const js::Value& value);
|
||||
|
||||
/*
|
||||
* Freeze all the stack type sets in a script, for a compilation. Returns
|
||||
* copies of the type sets which will be checked against the actual ones
|
||||
* under FinishCompilation, to detect any type changes.
|
||||
*/
|
||||
static bool FreezeTypeSets(CompilerConstraintList* constraints,
|
||||
JSScript* script, TemporaryTypeSet** pThisTypes,
|
||||
TemporaryTypeSet** pArgTypes,
|
||||
TemporaryTypeSet** pBytecodeTypes);
|
||||
|
||||
void destroy(Zone* zone);
|
||||
|
||||
size_t sizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const {
|
||||
// Note: icScript_ size is reported in jit::AddSizeOfBaselineData.
|
||||
return mallocSizeOf(this);
|
||||
}
|
||||
|
||||
static constexpr size_t offsetOfICScript() {
|
||||
// Note: icScript_ is a UniquePtr that stores the raw pointer. If that ever
|
||||
// changes and this assertion fails, we should stop using UniquePtr.
|
||||
static_assert(sizeof(icScript_) == sizeof(uintptr_t),
|
||||
"JIT code assumes icScript_ is pointer-sized");
|
||||
return offsetof(TypeScript, icScript_);
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
void printTypes(JSContext* cx, HandleScript script);
|
||||
#endif
|
||||
};
|
||||
|
||||
// Ensures no TypeScripts are purged in the current zone.
|
||||
class MOZ_RAII AutoKeepTypeScripts {
|
||||
TypeZone& zone_;
|
||||
bool prev_;
|
||||
|
||||
AutoKeepTypeScripts(const AutoKeepTypeScripts&) = delete;
|
||||
void operator=(const AutoKeepTypeScripts&) = delete;
|
||||
|
||||
public:
|
||||
explicit inline AutoKeepTypeScripts(JSContext* cx);
|
||||
inline ~AutoKeepTypeScripts();
|
||||
};
|
||||
|
||||
class RecompileInfo;
|
||||
|
||||
// Generate the type constraints for the compilation. Sets |isValidOut| based on
|
||||
// whether the type constraints still hold.
|
||||
bool FinishCompilation(JSContext* cx, HandleScript script,
|
||||
|
@ -438,7 +237,7 @@ class TypeZone {
|
|||
ZoneData<bool> sweepingTypes;
|
||||
ZoneData<bool> oomSweepingTypes;
|
||||
|
||||
ZoneData<bool> keepTypeScripts;
|
||||
ZoneData<bool> keepJitScripts;
|
||||
|
||||
// The topmost AutoEnterAnalysis on the stack, if there is one.
|
||||
ZoneData<AutoEnterAnalysis*> activeAnalysis;
|
||||
|
|
|
@ -235,7 +235,7 @@ class TemporaryTypeSet;
|
|||
* Information about the set of types associated with an lvalue. There are
|
||||
* three kinds of type sets:
|
||||
*
|
||||
* - StackTypeSet are associated with TypeScripts, for arguments and values
|
||||
* - StackTypeSet are associated with JitScripts, for arguments and values
|
||||
* observed at property reads. These are implicitly frozen on compilation
|
||||
* and only have constraints added to them which can trigger invalidation of
|
||||
* TypeNewScript information.
|
||||
|
@ -672,7 +672,7 @@ class ConstraintTypeSet : public TypeSet {
|
|||
}
|
||||
|
||||
// This takes a reference to AutoSweepBase to ensure we swept the owning
|
||||
// ObjectGroup or TypeScript.
|
||||
// ObjectGroup or JitScript.
|
||||
TypeConstraint* constraintList(const AutoSweepBase& sweep) const {
|
||||
checkMagic();
|
||||
if (constraintList_) {
|
||||
|
|
|
@ -188,17 +188,17 @@ bool Instance::callImport(JSContext* cx, uint32_t funcImportIndex,
|
|||
}
|
||||
|
||||
// Ensure the argument types are included in the argument TypeSets stored in
|
||||
// the TypeScript. This is necessary for Ion, because the import will use
|
||||
// the JitScript. This is necessary for Ion, because the import will use
|
||||
// the skip-arg-checks entry point.
|
||||
//
|
||||
// Note that the TypeScript is never discarded while the script has a
|
||||
// Note that the JitScript is never discarded while the script has a
|
||||
// BaselineScript, so if those checks hold now they must hold at least until
|
||||
// the BaselineScript is discarded and when that happens the import is
|
||||
// patched back.
|
||||
AutoSweepTypeScript sweep(script);
|
||||
TypeScript* typeScript = script->types();
|
||||
AutoSweepJitScript sweep(script);
|
||||
JitScript* jitScript = script->jitScript();
|
||||
|
||||
StackTypeSet* thisTypes = typeScript->thisTypes(sweep, script);
|
||||
StackTypeSet* thisTypes = jitScript->thisTypes(sweep, script);
|
||||
if (!thisTypes->hasType(TypeSet::UndefinedType())) {
|
||||
return true;
|
||||
}
|
||||
|
@ -233,7 +233,7 @@ bool Instance::callImport(JSContext* cx, uint32_t funcImportIndex,
|
|||
MOZ_CRASH("NullRef not expressible");
|
||||
}
|
||||
|
||||
StackTypeSet* argTypes = typeScript->argTypes(sweep, script, i);
|
||||
StackTypeSet* argTypes = jitScript->argTypes(sweep, script, i);
|
||||
if (!argTypes->hasType(type)) {
|
||||
return true;
|
||||
}
|
||||
|
@ -243,7 +243,7 @@ bool Instance::callImport(JSContext* cx, uint32_t funcImportIndex,
|
|||
// arguments rectifier: check that the imported function can handle
|
||||
// undefined there.
|
||||
for (uint32_t i = importArgs.length(); i < importFun->nargs(); i++) {
|
||||
StackTypeSet* argTypes = typeScript->argTypes(sweep, script, i);
|
||||
StackTypeSet* argTypes = jitScript->argTypes(sweep, script, i);
|
||||
if (!argTypes->hasType(TypeSet::UndefinedType())) {
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -1828,9 +1828,9 @@ static void ReportRealmStats(const JS::RealmStats& realmStats,
|
|||
"The IonMonkey JIT's compilation data (IonScripts).");
|
||||
|
||||
ZRREPORT_BYTES(
|
||||
realmJSPathPrefix + NS_LITERAL_CSTRING("type-inference/type-scripts"),
|
||||
realmStats.typeInferenceTypeScripts,
|
||||
"Type sets associated with scripts.");
|
||||
realmJSPathPrefix + NS_LITERAL_CSTRING("jit-scripts"),
|
||||
realmStats.jitScripts,
|
||||
"JIT and Type Inference data associated with scripts.");
|
||||
|
||||
ZRREPORT_BYTES(
|
||||
realmJSPathPrefix +
|
||||
|
|
|
@ -3583,8 +3583,14 @@ bool PresShell::ScrollFrameRectIntoView(nsIFrame* aFrame, const nsRect& aRect,
|
|||
targetRect = targetRect.Intersect(sf->GetScrolledRect());
|
||||
}
|
||||
|
||||
{
|
||||
AutoWeakFrame wf(container);
|
||||
ScrollToShowRect(this, sf, targetRect, aVertical, aHorizontal,
|
||||
aScrollFlags);
|
||||
if (!wf.IsAlive()) {
|
||||
return didScroll;
|
||||
}
|
||||
}
|
||||
|
||||
nsPoint newPosition = sf->LastScrollDestination();
|
||||
// If the scroll position increased, that means our content moved up,
|
||||
|
|
|
@ -2180,17 +2180,6 @@ void ScrollFrameHelper::ScrollToCSSPixels(
|
|||
aOrigin = nsGkAtoms::other;
|
||||
}
|
||||
|
||||
if (aSnap == nsIScrollableFrame::ENABLE_SNAP) {
|
||||
if (currentCSSPixels.x == aScrollPosition.x) {
|
||||
pt.x = current.x;
|
||||
}
|
||||
if (currentCSSPixels.y == aScrollPosition.y) {
|
||||
pt.y = current.y;
|
||||
}
|
||||
ScrollTo(pt, aMode, aOrigin, nullptr /* range */, aSnap);
|
||||
return;
|
||||
}
|
||||
|
||||
nscoord halfPixel = nsPresContext::CSSPixelsToAppUnits(0.5f);
|
||||
nsRect range(pt.x - halfPixel, pt.y - halfPixel, 2 * halfPixel - 1,
|
||||
2 * halfPixel - 1);
|
||||
|
@ -2238,9 +2227,10 @@ void ScrollFrameHelper::ScrollToWithOrigin(
|
|||
mRestorePos.x = mRestorePos.y = -1;
|
||||
}
|
||||
|
||||
bool willSnap = false;
|
||||
if (aSnap == nsIScrollableFrame::ENABLE_SNAP) {
|
||||
GetSnapPointForDestination(nsIScrollableFrame::DEVICE_PIXELS, mDestination,
|
||||
aScrollPosition);
|
||||
willSnap = GetSnapPointForDestination(nsIScrollableFrame::DEVICE_PIXELS,
|
||||
mDestination, aScrollPosition);
|
||||
}
|
||||
|
||||
nsRect scrollRange = GetLayoutScrollRange();
|
||||
|
@ -2252,7 +2242,8 @@ void ScrollFrameHelper::ScrollToWithOrigin(
|
|||
aOrigin = nsGkAtoms::other;
|
||||
}
|
||||
|
||||
nsRect range = aRange ? *aRange : nsRect(aScrollPosition, nsSize(0, 0));
|
||||
nsRect range =
|
||||
aRange && !willSnap ? *aRange : nsRect(aScrollPosition, nsSize(0, 0));
|
||||
|
||||
if (aMode != ScrollMode::SmoothMsd) {
|
||||
// If we get a non-smooth-scroll, reset the cached APZ scroll destination,
|
||||
|
@ -4315,17 +4306,6 @@ void ScrollFrameHelper::ScrollByCSSPixels(
|
|||
aOrigin = nsGkAtoms::other;
|
||||
}
|
||||
|
||||
if (aSnap == nsIScrollableFrame::ENABLE_SNAP) {
|
||||
if (aDelta.x == 0.0f) {
|
||||
pt.x = current.x;
|
||||
}
|
||||
if (aDelta.y == 0.0f) {
|
||||
pt.y = current.y;
|
||||
}
|
||||
ScrollToWithOrigin(pt, aMode, aOrigin, nullptr /* range */, aSnap);
|
||||
return;
|
||||
}
|
||||
|
||||
nscoord halfPixel = nsPresContext::CSSPixelsToAppUnits(0.5f);
|
||||
nsRect range(pt.x - halfPixel, pt.y - halfPixel, 2 * halfPixel - 1,
|
||||
2 * halfPixel - 1);
|
||||
|
@ -6747,6 +6727,13 @@ static void CollectScrollPositionsForSnap(
|
|||
WritingMode aWritingModeOnScroller, ScrollSnapInfo& aSnapInfo) {
|
||||
MOZ_ASSERT(StaticPrefs::layout_css_scroll_snap_v1_enabled());
|
||||
|
||||
// Snap positions only affect the nearest ancestor scroll container on the
|
||||
// element's containing block chain.
|
||||
nsIScrollableFrame* sf = do_QueryFrame(aFrame);
|
||||
if (sf) {
|
||||
return;
|
||||
}
|
||||
|
||||
nsIFrame::ChildListIterator childLists(aFrame);
|
||||
for (; !childLists.IsDone(); childLists.Next()) {
|
||||
nsFrameList::Enumerator childFrames(childLists.CurrentList());
|
||||
|
|
|
@ -416,6 +416,10 @@ nsLayoutStylesheetCache* nsLayoutStylesheetCache::Singleton() {
|
|||
}
|
||||
|
||||
void nsLayoutStylesheetCache::InitFromProfile() {
|
||||
if (!Preferences::GetBool(PREF_LEGACY_STYLESHEET_CUSTOMIZATION)) {
|
||||
return;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIXULRuntime> appInfo =
|
||||
do_GetService("@mozilla.org/xre/app-info;1");
|
||||
if (appInfo) {
|
||||
|
@ -442,28 +446,6 @@ void nsLayoutStylesheetCache::InitFromProfile() {
|
|||
eLogToConsole);
|
||||
LoadSheetFile(chromeFile, &mUserChromeSheet, eUserSheetFeatures,
|
||||
eLogToConsole);
|
||||
|
||||
if (XRE_IsParentProcess()) {
|
||||
if (mUserChromeSheet || mUserContentSheet) {
|
||||
// Bug 1541233 aims to avoid stat'ing or loading userContent.css or
|
||||
// userChrome.css during start-up by default. After that point,
|
||||
// PREF_LEGACY_STYLESHEET_CUSTOMIZATION pref is how users can opt-in
|
||||
// to continuing to use userChrome.css or userContent.css.
|
||||
//
|
||||
// Before bug 1541233 lands though, we'll ship a release which
|
||||
// continues to look for those files on start-up and sets a pref.
|
||||
// That way, in a subsequent release when loading those files is
|
||||
// off by default, those users will still get their userChrome.css
|
||||
// and userContent.css customizations without having to manually
|
||||
// set the pref themselves.
|
||||
Preferences::SetBool(PREF_LEGACY_STYLESHEET_CUSTOMIZATION, true);
|
||||
}
|
||||
|
||||
// We're interested specifically in potential chrome customizations,
|
||||
// so we only need data points from the parent process
|
||||
Telemetry::Accumulate(Telemetry::USER_CHROME_CSS_LOADED,
|
||||
mUserChromeSheet != nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
void nsLayoutStylesheetCache::LoadSheetURL(const char* aURL,
|
||||
|
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче