icecat: add release icecat-140.8.0-2 for aramo
This commit is contained in:
parent
d9a6c0aa96
commit
d570f39e11
616 changed files with 39955 additions and 33937 deletions
|
|
@ -100,9 +100,9 @@ git = "https://github.com/mozilla/midir.git"
|
|||
rev = "85156e360a37d851734118104619f86bd18e94c6"
|
||||
replace-with = "vendored-sources"
|
||||
|
||||
[source."git+https://github.com/mozilla/mp4parse-rust?rev=e64650a686e5c5732395cd059e17cfd3b1e5b63b"]
|
||||
[source."git+https://github.com/mozilla/mp4parse-rust?rev=25ebfa59a21dc0d223052d73a2fafdd55307c2d7"]
|
||||
git = "https://github.com/mozilla/mp4parse-rust"
|
||||
rev = "e64650a686e5c5732395cd059e17cfd3b1e5b63b"
|
||||
rev = "25ebfa59a21dc0d223052d73a2fafdd55307c2d7"
|
||||
replace-with = "vendored-sources"
|
||||
|
||||
[source."git+https://github.com/mozilla/neqo?tag=v0.13.4"]
|
||||
|
|
|
|||
4
icecat/.gitignore
vendored
4
icecat/.gitignore
vendored
|
|
@ -37,6 +37,10 @@ ID
|
|||
# third-party packages is dealt with by the script vendoring them.
|
||||
*.egg-info/
|
||||
|
||||
# Ignore pywebsocket3 intermediate files.
|
||||
testing/web-platform/tests/tools/third_party/pywebsocket3/pywebsocket3.egg-info
|
||||
testing/web-platform/tests/tools/third_party/pywebsocket3/build
|
||||
|
||||
# Vim swap files.
|
||||
.*.sw[a-z]
|
||||
.sw[a-z]
|
||||
|
|
|
|||
|
|
@ -22,4 +22,4 @@
|
|||
# changes to stick? As of bug 928195, this shouldn't be necessary! Please
|
||||
# don't change CLOBBER for WebIDL changes any more.
|
||||
|
||||
Merge day clobber 2025-12-08
|
||||
Merge day clobber 2026-01-12
|
||||
4
icecat/Cargo.lock
generated
4
icecat/Cargo.lock
generated
|
|
@ -4607,7 +4607,7 @@ dependencies = [
|
|||
[[package]]
|
||||
name = "mp4parse"
|
||||
version = "0.17.0"
|
||||
source = "git+https://github.com/mozilla/mp4parse-rust?rev=e64650a686e5c5732395cd059e17cfd3b1e5b63b#e64650a686e5c5732395cd059e17cfd3b1e5b63b"
|
||||
source = "git+https://github.com/mozilla/mp4parse-rust?rev=25ebfa59a21dc0d223052d73a2fafdd55307c2d7#25ebfa59a21dc0d223052d73a2fafdd55307c2d7"
|
||||
dependencies = [
|
||||
"bitreader",
|
||||
"byteorder",
|
||||
|
|
@ -4624,7 +4624,7 @@ version = "0.1.0"
|
|||
[[package]]
|
||||
name = "mp4parse_capi"
|
||||
version = "0.17.0"
|
||||
source = "git+https://github.com/mozilla/mp4parse-rust?rev=e64650a686e5c5732395cd059e17cfd3b1e5b63b#e64650a686e5c5732395cd059e17cfd3b1e5b63b"
|
||||
source = "git+https://github.com/mozilla/mp4parse-rust?rev=25ebfa59a21dc0d223052d73a2fafdd55307c2d7#25ebfa59a21dc0d223052d73a2fafdd55307c2d7"
|
||||
dependencies = [
|
||||
"byteorder",
|
||||
"fallible_collections",
|
||||
|
|
|
|||
|
|
@ -11,7 +11,6 @@
|
|||
#include "mozilla/Attributes.h"
|
||||
#include "mozilla/CmdLineAndEnvUtils.h"
|
||||
#include "mozilla/DebugOnly.h"
|
||||
#include "mozilla/DynamicallyLinkedFunctionPtr.h"
|
||||
#include "mozilla/glue/Debug.h"
|
||||
#include "mozilla/GeckoArgs.h"
|
||||
#include "mozilla/Maybe.h"
|
||||
|
|
@ -19,12 +18,14 @@
|
|||
#include "mozilla/SafeMode.h"
|
||||
#include "mozilla/UniquePtr.h"
|
||||
#include "mozilla/WindowsConsole.h"
|
||||
#include "mozilla/WindowsProcessMitigations.h"
|
||||
#include "mozilla/WindowsVersion.h"
|
||||
#include "mozilla/WinHeaderOnlyUtils.h"
|
||||
#include "nsWindowsHelpers.h"
|
||||
|
||||
#include <windows.h>
|
||||
#include <processthreadsapi.h>
|
||||
#include <shlwapi.h>
|
||||
|
||||
#include "DllBlocklistInit.h"
|
||||
#include "ErrorHandler.h"
|
||||
|
|
@ -111,16 +112,82 @@ static nsReturnRef<HANDLE> CreateJobAndAssignProcess(HANDLE aProcess) {
|
|||
return job.out();
|
||||
}
|
||||
|
||||
#if !defined( \
|
||||
PROCESS_CREATION_MITIGATION_POLICY_IMAGE_LOAD_PREFER_SYSTEM32_ALWAYS_ON)
|
||||
# define PROCESS_CREATION_MITIGATION_POLICY_IMAGE_LOAD_PREFER_SYSTEM32_ALWAYS_ON \
|
||||
(0x00000001ULL << 60)
|
||||
#endif // !defined(PROCESS_CREATION_MITIGATION_POLICY_IMAGE_LOAD_PREFER_SYSTEM32_ALWAYS_ON)
|
||||
enum class VCRuntimeDLLDir : bool {
|
||||
Application,
|
||||
System,
|
||||
};
|
||||
static bool GetMSVCP140VersionInfo(VCRuntimeDLLDir aDir,
|
||||
uint64_t& aOutVersion) {
|
||||
wchar_t dllPath[MAX_PATH];
|
||||
if (aDir == VCRuntimeDLLDir::Application) {
|
||||
DWORD size = ::GetModuleFileNameW(nullptr, dllPath, MAX_PATH);
|
||||
if (!size ||
|
||||
(size == MAX_PATH && ::GetLastError() == ERROR_INSUFFICIENT_BUFFER) ||
|
||||
!::PathRemoveFileSpecW(dllPath)) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
MOZ_ASSERT(aDir == VCRuntimeDLLDir::System);
|
||||
UINT size = ::GetSystemDirectoryW(dllPath, MAX_PATH);
|
||||
if (!size || size >= MAX_PATH) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
#if !defined(PROCESS_CREATION_MITIGATION_POLICY_CONTROL_FLOW_GUARD_ALWAYS_OFF)
|
||||
# define PROCESS_CREATION_MITIGATION_POLICY_CONTROL_FLOW_GUARD_ALWAYS_OFF \
|
||||
(0x00000002ULL << 40)
|
||||
#endif // !defined(PROCESS_CREATION_MITIGATION_POLICY_CONTROL_FLOW_GUARD_ALWAYS_OFF)
|
||||
if (!::PathAppendW(dllPath, L"msvcp140.dll")) {
|
||||
return false;
|
||||
}
|
||||
HMODULE crt =
|
||||
::LoadLibraryExW(dllPath, nullptr, LOAD_LIBRARY_AS_IMAGE_RESOURCE);
|
||||
if (!crt) {
|
||||
return false;
|
||||
}
|
||||
|
||||
mozilla::nt::PEHeaders headers{crt};
|
||||
bool result = headers.GetVersionInfo(aOutVersion);
|
||||
::FreeLibrary(crt);
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Choose whether we want to favor loading DLLs from the system directory over
|
||||
* the application directory. This choice automatically propagates to all child
|
||||
* processes. In particular, it determines whether child processes will load
|
||||
* Visual C++ runtime DLLs from the system or the application directory at
|
||||
* startup.
|
||||
*
|
||||
* Whenever possible, we want all processes to favor loading DLLs from the
|
||||
* system directory. But if old Visual C++ runtime DLLs are installed
|
||||
* system-wide, then we must favor loading from the application directory
|
||||
* instead to ensure compatibility, at least during startup. So in this case we
|
||||
* only apply the delayed variant of the mitigation and only in sandboxed
|
||||
* processes, which is the best compromise (see SandboxBroker::LaunchApp).
|
||||
*
|
||||
* This function is called from the launcher process *and* the browser process.
|
||||
* This is because if the launcher process is disabled, we still want the
|
||||
* browser process to go through this code so that it enforces the correct
|
||||
* choice for itself and for child processes.
|
||||
*/
|
||||
static void EnablePreferLoadFromSystem32IfCompatible() {
|
||||
// We may already have the mitigation if we are the browser process and we
|
||||
// inherited it from the launcher process.
|
||||
if (!mozilla::IsPreferLoadFromSystem32Available() ||
|
||||
mozilla::IsPreferLoadFromSystem32Enabled()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Only bail out if (1) there is a conflict because the two DLLs exist *and*
|
||||
// (2) the version of the system DLL is problematic.
|
||||
uint64_t systemDirVersion = 0, appDirVersion = 0;
|
||||
if (GetMSVCP140VersionInfo(VCRuntimeDLLDir::System, systemDirVersion) &&
|
||||
GetMSVCP140VersionInfo(VCRuntimeDLLDir::Application, appDirVersion) &&
|
||||
systemDirVersion < appDirVersion) {
|
||||
return;
|
||||
}
|
||||
|
||||
mozilla::DebugOnly<bool> setOk = mozilla::EnablePreferLoadFromSystem32();
|
||||
MOZ_ASSERT(setOk);
|
||||
}
|
||||
|
||||
/**
|
||||
* Any mitigation policies that should be set on the browser process should go
|
||||
|
|
@ -128,10 +195,11 @@ static nsReturnRef<HANDLE> CreateJobAndAssignProcess(HANDLE aProcess) {
|
|||
*/
|
||||
static void SetMitigationPolicies(mozilla::ProcThreadAttributes& aAttrs,
|
||||
const bool aIsSafeMode) {
|
||||
if (mozilla::IsWin10AnniversaryUpdateOrLater()) {
|
||||
aAttrs.AddMitigationPolicy(
|
||||
PROCESS_CREATION_MITIGATION_POLICY_IMAGE_LOAD_PREFER_SYSTEM32_ALWAYS_ON);
|
||||
}
|
||||
// Note: Do *not* handle IMAGE_LOAD_PREFER_SYSTEM32_ALWAYS_ON here. For this
|
||||
// mitigation we rely on EnablePreferLoadFromSystem32IfCompatible().
|
||||
// The launcher process or the browser process will choose whether we
|
||||
// want to apply the mitigation or not, and child processes will
|
||||
// automatically inherit that choice.
|
||||
|
||||
#if defined(_M_ARM64)
|
||||
// Disable CFG on older versions of ARM64 Windows to avoid a crash in COM.
|
||||
|
|
@ -286,6 +354,9 @@ Maybe<int> LauncherMain(int& argc, wchar_t* argv[],
|
|||
return Nothing();
|
||||
}
|
||||
|
||||
// Called from the launcher process *and* the browser process.
|
||||
EnablePreferLoadFromSystem32IfCompatible();
|
||||
|
||||
#if defined(MOZ_LAUNCHER_PROCESS)
|
||||
LauncherRegistryInfo regInfo;
|
||||
Maybe<bool> runAsLauncher = RunAsLauncherProcess(regInfo, argc, argv);
|
||||
|
|
@ -309,22 +380,6 @@ Maybe<int> LauncherMain(int& argc, wchar_t* argv[],
|
|||
return Nothing();
|
||||
}
|
||||
|
||||
// Make sure that the launcher process itself has image load policies set
|
||||
if (IsWin10AnniversaryUpdateOrLater()) {
|
||||
static const StaticDynamicallyLinkedFunctionPtr<
|
||||
decltype(&SetProcessMitigationPolicy)>
|
||||
pSetProcessMitigationPolicy(L"kernel32.dll",
|
||||
"SetProcessMitigationPolicy");
|
||||
if (pSetProcessMitigationPolicy) {
|
||||
PROCESS_MITIGATION_IMAGE_LOAD_POLICY imgLoadPol = {};
|
||||
imgLoadPol.PreferSystem32Images = 1;
|
||||
|
||||
DebugOnly<BOOL> setOk = pSetProcessMitigationPolicy(
|
||||
ProcessImageLoadPolicy, &imgLoadPol, sizeof(imgLoadPol));
|
||||
MOZ_ASSERT(setOk);
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(MOZ_SANDBOX)
|
||||
// Ensure the relevant mitigations are enforced.
|
||||
mozilla::sandboxing::ApplyParentProcessMitigations();
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@ OS_LIBS += [
|
|||
"oleaut32",
|
||||
"ole32",
|
||||
"rpcrt4",
|
||||
"shlwapi",
|
||||
"version",
|
||||
]
|
||||
|
||||
|
|
|
|||
|
|
@ -127,6 +127,9 @@ let JSWINDOWACTORS = {
|
|||
},
|
||||
},
|
||||
matches: ["about:messagepreview", "about:messagepreview?*"],
|
||||
remoteTypes: ["privilegedabout"],
|
||||
enablePreference:
|
||||
"browser.newtabpage.activity-stream.asrouter.devtoolsEnabled",
|
||||
},
|
||||
|
||||
AboutPocket: {
|
||||
|
|
|
|||
|
|
@ -110,6 +110,7 @@ static const RedirEntry kRedirMap[] = {
|
|||
{"messagepreview",
|
||||
"chrome://browser/content/messagepreview/messagepreview.html",
|
||||
nsIAboutModule::URI_MUST_LOAD_IN_CHILD |
|
||||
nsIAboutModule::URI_CAN_LOAD_IN_PRIVILEGEDABOUT_PROCESS |
|
||||
nsIAboutModule::URI_SAFE_FOR_UNTRUSTED_CONTENT |
|
||||
nsIAboutModule::ALLOW_SCRIPT | nsIAboutModule::HIDE_FROM_ABOUTABOUT},
|
||||
{"pocket-saved", "chrome://pocket/content/panels/saved.html",
|
||||
|
|
|
|||
|
|
@ -14,8 +14,8 @@ add_task(async function test_recover_storeID() {
|
|||
await SelectableProfileService.init();
|
||||
|
||||
Assert.ok(
|
||||
!ProfilesDatastoreService.initialized,
|
||||
"Didn't initialize the datastore service"
|
||||
ProfilesDatastoreService.initialized,
|
||||
"Initialized the datastore service"
|
||||
);
|
||||
Assert.ok(
|
||||
!SelectableProfileService.initialized,
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@
|
|||
#include "mozilla/Result.h"
|
||||
#include "mozilla/ResultVariant.h"
|
||||
#include "mozilla/UniquePtr.h"
|
||||
#include "mozilla/WindowsVersion.h"
|
||||
#include "mozilla/WinHeaderOnlyUtils.h"
|
||||
#include "mozilla/widget/WinTaskbar.h"
|
||||
#include "WinUtils.h"
|
||||
|
|
@ -186,7 +187,16 @@ Win11PinToTaskBarResult PinCurrentAppToTaskbarWin11(
|
|||
Win11PinToTaskBarResult unlockStatus =
|
||||
UnlockLimitedAccessFeature(Win11LimitedAccessFeatureType::Taskbar);
|
||||
if (unlockStatus.result != Win11PinToTaskBarResultStatus::Success) {
|
||||
return unlockStatus;
|
||||
// Limited Access Feature no longer necessary for Windows 11 26200 Build
|
||||
// 7840, and possibly other channels.
|
||||
if (!IsWin11OrLater()) {
|
||||
return unlockStatus;
|
||||
}
|
||||
|
||||
TASKBAR_PINNING_LOG(
|
||||
LogLevel::Warning,
|
||||
"Limited Access Feature failed to unlock, attempting to use Taskbar "
|
||||
"Pinning API assuming LAF is no longer necessary.");
|
||||
}
|
||||
|
||||
HRESULT hr;
|
||||
|
|
@ -407,7 +417,16 @@ Win11PinToTaskBarResult IsCurrentAppPinnedToTaskbarWin11(bool aCheckOnly) {
|
|||
Win11PinToTaskBarResult unlockStatus =
|
||||
UnlockLimitedAccessFeature(Win11LimitedAccessFeatureType::Taskbar);
|
||||
if (unlockStatus.result != Win11PinToTaskBarResultStatus::Success) {
|
||||
return unlockStatus;
|
||||
// Limited Access Feature no longer necessary for Windows 11 26200 Build
|
||||
// 7840, and possibly other channels.
|
||||
if (!IsWin11OrLater()) {
|
||||
return unlockStatus;
|
||||
}
|
||||
|
||||
TASKBAR_PINNING_LOG(
|
||||
LogLevel::Warning,
|
||||
"Limited Access Feature failed to unlock, attempting to use Taskbar "
|
||||
"Pinning API assuming LAF is no longer necessary.");
|
||||
}
|
||||
|
||||
HRESULT hr;
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
140.7.1
|
||||
140.8.0
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
140.7.1esr
|
||||
140.8.0esr
|
||||
|
|
|
|||
|
|
@ -13,5 +13,5 @@ MOZ_BRANDING_DIRECTORY=browser/branding/unofficial
|
|||
MOZ_OFFICIAL_BRANDING_DIRECTORY=browser/branding/official
|
||||
# IceCat settings
|
||||
MOZ_APP_BASENAME=IceCat
|
||||
MOZ_APP_VERSION=140.7.1
|
||||
MOZ_APP_VERSION=140.8.0
|
||||
MOZ_DATA_REPORTING=0
|
||||
|
|
|
|||
|
|
@ -1473,6 +1473,9 @@ async function triggerCapture(browser, submitButtonSelector, fillSelectors) {
|
|||
* @param {object} patterns.captureExpectedRecord
|
||||
* The expected saved record after capturing the form. Keyed by field name. This
|
||||
* parameter is only used when `options.testCapture` is set.
|
||||
* @param {boolean} patterns.useTestYear
|
||||
* Set to the current year to assign while running the test, useful for credit
|
||||
* card expiry tests with a manual set of year options in the dropdown.
|
||||
* @param {object} patterns.only
|
||||
* This parameter is used solely for debugging purposes. When set to true,
|
||||
* it restricts the execution to only the specified testcase.
|
||||
|
|
@ -1597,16 +1600,32 @@ async function add_heuristic_tests(
|
|||
const sleepAfterFocus = contexts.length > 1;
|
||||
|
||||
for (const context of contexts) {
|
||||
await SpecialPowers.spawn(context, [], async () => {
|
||||
const elements = Array.from(
|
||||
content.document.querySelectorAll("input, select")
|
||||
);
|
||||
// Focus on each field in the test document to trigger autofill field detection
|
||||
// on all the fields.
|
||||
elements.forEach(element => {
|
||||
element.focus();
|
||||
});
|
||||
});
|
||||
await SpecialPowers.spawn(
|
||||
context,
|
||||
[testPattern.useTestYear],
|
||||
async year => {
|
||||
let FormAutofillHeuristics;
|
||||
if (year) {
|
||||
FormAutofillHeuristics = ChromeUtils.importESModule(
|
||||
"resource://gre/modules/shared/FormAutofillHeuristics.sys.mjs"
|
||||
).FormAutofillHeuristics;
|
||||
FormAutofillHeuristics.useTestYear = year;
|
||||
}
|
||||
|
||||
const elements = Array.from(
|
||||
content.document.querySelectorAll("input, select")
|
||||
);
|
||||
// Focus on each field in the test document to trigger autofill field detection
|
||||
// on all the fields.
|
||||
elements.forEach(element => {
|
||||
element.focus();
|
||||
});
|
||||
|
||||
if (year) {
|
||||
FormAutofillHeuristics.useTestYear = null;
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
try {
|
||||
await BrowserTestUtils.synthesizeKey("VK_ESCAPE", {}, context);
|
||||
|
|
|
|||
|
|
@ -8,7 +8,6 @@ support-files = [
|
|||
["browser_BestBuy.js"]
|
||||
|
||||
["browser_CDW.js"]
|
||||
skip-if = ["true"] # Bug 1939626
|
||||
|
||||
["browser_CostCo.js"]
|
||||
|
||||
|
|
|
|||
|
|
@ -30,6 +30,7 @@ add_heuristic_tests(
|
|||
},
|
||||
{
|
||||
fixturePath: "Checkout_BillingPaymentInfo.html",
|
||||
useTestYear: 2024,
|
||||
expectedResult: [
|
||||
{
|
||||
default: {
|
||||
|
|
|
|||
|
|
@ -74,6 +74,7 @@ add_heuristic_tests(
|
|||
},
|
||||
{
|
||||
fixturePath: "Payment.html",
|
||||
useTestYear: 2025,
|
||||
expectedResult: [
|
||||
{
|
||||
default: {
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ add_heuristic_tests(
|
|||
[
|
||||
{
|
||||
fixturePath: "Payment.html",
|
||||
useTestYear: 2024,
|
||||
expectedResult: [
|
||||
{
|
||||
default: {
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ add_heuristic_tests(
|
|||
[
|
||||
{
|
||||
fixturePath: "Checkout_Payment.html",
|
||||
useTestYear: 2024,
|
||||
expectedResult: [
|
||||
{
|
||||
default: {
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ add_heuristic_tests(
|
|||
[
|
||||
{
|
||||
fixturePath: "index.html",
|
||||
useTestYear: 2024,
|
||||
expectedResult: [
|
||||
{
|
||||
default: {
|
||||
|
|
|
|||
|
|
@ -120,3 +120,65 @@ window.wrappedJSObject.chrome = cloneInto(
|
|||
window,
|
||||
{ cloneFunctions: true }
|
||||
);
|
||||
|
||||
const ua = navigator.userAgent;
|
||||
const mobile = ua.includes("Mobile") || ua.includes("Tablet");
|
||||
|
||||
// Very roughly matches Chromium's GetPlatformForUAMetadata()
|
||||
let platform = "Linux";
|
||||
if (mobile) {
|
||||
platform = "Android";
|
||||
} else if (navigator.platform.startsWith("Win")) {
|
||||
platform = "Windows";
|
||||
} else if (navigator.platform.startsWith("Mac")) {
|
||||
platform = "macOS";
|
||||
}
|
||||
|
||||
const version = (ua.match(/IceCat\/([0-9]+)/) || ["", "58.0"])[1];
|
||||
|
||||
// These match Chrome's output as of version 126.
|
||||
const brands = [
|
||||
{
|
||||
brand: "Not/A)Brand",
|
||||
version: "8",
|
||||
},
|
||||
{
|
||||
brand: "Chromium",
|
||||
version,
|
||||
},
|
||||
{
|
||||
brand: "Google Chrome",
|
||||
version,
|
||||
},
|
||||
];
|
||||
|
||||
const userAgentData = cloneInto(
|
||||
{
|
||||
brands,
|
||||
mobile,
|
||||
platform,
|
||||
getHighEntropyValues() {
|
||||
return window.wrappedJSObject.Promise.resolve(
|
||||
cloneInto(
|
||||
{
|
||||
brands,
|
||||
mobile,
|
||||
platform,
|
||||
platformVersion: "19.0.0",
|
||||
},
|
||||
window
|
||||
)
|
||||
);
|
||||
},
|
||||
},
|
||||
window,
|
||||
{ cloneFunctions: true }
|
||||
);
|
||||
|
||||
Object.defineProperty(window.navigator.wrappedJSObject, "userAgentData", {
|
||||
get: exportFunction(function () {
|
||||
return userAgentData;
|
||||
}, window),
|
||||
|
||||
set: exportFunction(function () {}, window),
|
||||
});
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
"manifest_version": 2,
|
||||
"name": "Web Compatibility Interventions",
|
||||
"description": "Urgent post-release fixes for web compatibility.",
|
||||
"version": "140.11.0",
|
||||
"version": "140.12.0",
|
||||
"browser_specific_settings": {
|
||||
"gecko": {
|
||||
"id": "webcompat@mozilla.org",
|
||||
|
|
|
|||
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
|
@ -10,4 +10,4 @@
|
|||
# hardcoded milestones in the tree from these two files.
|
||||
#--------------------------------------------------------
|
||||
|
||||
140.7.1
|
||||
140.8.0
|
||||
|
|
|
|||
|
|
@ -157,8 +157,12 @@ ifeq (official, $(MOZ_BRANDING))
|
|||
MOZ_DEFINES += -DMOZ_OFFICIAL_BRANDING
|
||||
endif
|
||||
ifneq (,$(DEB_PARALLEL_JOBS))
|
||||
ifneq (,$(filter armhf, $(DEB_HOST_ARCH)))
|
||||
MOZ_DEFINES += -DDEB_PARALLEL_JOBS=1
|
||||
else
|
||||
MOZ_DEFINES += -DDEB_PARALLEL_JOBS=$(DEB_PARALLEL_JOBS)
|
||||
endif
|
||||
endif
|
||||
|
||||
MOZ_EXECUTABLES_$(MOZ_PKG_NAME) += $(MOZ_LIBDIR)/$(MOZ_PKG_BASENAME).sh \
|
||||
$(NULL)
|
||||
|
|
|
|||
|
|
@ -1,3 +1,9 @@
|
|||
icecat (140.8.0-2gnu1+build1-0.11.0) aramo; urgency=medium
|
||||
|
||||
* New upstream stable release (icecat-140.8.0-2gnu1)
|
||||
|
||||
-- Capitulo Mexicano de Software Libre <devel@cmxsl.org> Tue, 10 Mar 2026 22:35:37 -0600
|
||||
|
||||
icecat (140.7.1-1gnu1+build1-0.11.0) aramo; urgency=medium
|
||||
|
||||
* New upstream stable release (icecat-140.7.1-1gnu1)
|
||||
|
|
|
|||
|
|
@ -11,7 +11,11 @@ ac_add_options --disable-updater
|
|||
ac_add_options --enable-application=browser
|
||||
ac_add_options --with-distribution-id=org.trisquel
|
||||
%%if DEB_BUILD_ARCH_BITS == 32
|
||||
%%if DEB_HOST_ARCH == armhf
|
||||
ac_add_options --disable-debug-symbols
|
||||
%%else
|
||||
ac_add_options --enable-debug-symbols=-g1
|
||||
%%endif
|
||||
%%else
|
||||
ac_add_options --enable-debug-symbols
|
||||
%%endif
|
||||
|
|
|
|||
|
|
@ -1,22 +1,30 @@
|
|||
Description: Do not enable LTO for rustc when building on arm64 and armhf,
|
||||
Description: Do not enable LTO for rustc when building on armhf,
|
||||
to work around OOM failures on Launchpad builders. Note that this alone is not
|
||||
sufficient, because by default cargo will also enable full LTO when building
|
||||
with a release profile, so the top-level Cargo.toml file needs to be
|
||||
conditionally patched (this is done in debian/build/rules.mk).
|
||||
Author: Olivier Tilloy <olivier.tilloy@canonical.com>
|
||||
Author: Nathan Pratte Teodosio <nteodosio@ubuntu.com>
|
||||
Forwarded: not-needed
|
||||
|
||||
--- a/config/makefiles/rust.mk
|
||||
+++ b/config/makefiles/rust.mk
|
||||
@@ -70,8 +70,10 @@ ifndef MOZ_DEBUG_RUST
|
||||
@@ -70,10 +70,18 @@ ifndef MOZ_DEBUG_RUST
|
||||
# Never enable when coverage is enabled to work around https://github.com/rust-lang/rust/issues/90045.
|
||||
ifndef MOZ_CODE_COVERAGE
|
||||
ifeq (,$(findstring gkrust_gtest,$(RUST_LIBRARY_FILE)))
|
||||
+ifeq (,$(filter aarch64 arm,$(TARGET_CPU)))
|
||||
+ifneq (,$(filter arm,$(TARGET_CPU)))
|
||||
+cargo_rustc_flags += -Clto=off
|
||||
+else
|
||||
cargo_rustc_flags += -Clto$(if $(filter full,$(MOZ_LTO_RUST_CROSS)),=fat)
|
||||
endif
|
||||
+endif
|
||||
# We need -Cembed-bitcode=yes for all crates when using -Clto.
|
||||
RUSTFLAGS += -Cembed-bitcode=yes
|
||||
endif
|
||||
|
||||
# We need -Cembed-bitcode=yes for all crates when using -Clto.
|
||||
+ifneq (,$(filter arm,$(TARGET_CPU)))
|
||||
+RUSTFLAGS += -Cembed-bitcode=no
|
||||
+else
|
||||
RUSTFLAGS += -Cembed-bitcode=yes
|
||||
+endif
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
|
|
@ -7,7 +7,7 @@ webrtc-fix-compiler-flags-for-armhf.patch
|
|||
s390x-ycbcr.patch
|
||||
reduce-rust-debuginfo.patch
|
||||
armhf-reduce-linker-memory-use.patch
|
||||
armhf-rustc-thin-lto.patch
|
||||
armhf-rustc-lto-off.patch
|
||||
ppc64el-workaround-bug-1555531.patch
|
||||
ppc64el-workaround-gcc-ice.patch
|
||||
armhf-clang-no-integrated-as-for-neon.patch
|
||||
|
|
|
|||
|
|
@ -124,30 +124,34 @@ class RequestPanel extends Component {
|
|||
}
|
||||
|
||||
/**
|
||||
* Mapping array to dict for TreeView usage.
|
||||
* Since TreeView only support Object(dict) format.
|
||||
* This function also deal with duplicate key case
|
||||
* (for multiple selection and query params with same keys)
|
||||
* This maps an array to a dictionary for TreeView usage,
|
||||
* sincs the treeView only supports the Object(dict) format.
|
||||
*
|
||||
* This function is not sorting result properties since it can
|
||||
* results in unexpected order of params. See bug 1469533
|
||||
* This function also deals with the duplicate key scenario
|
||||
* (i.e multiple selections and query params with same keys)
|
||||
*
|
||||
* @param {Object[]} arr - key-value pair array or form params
|
||||
* @returns {Object} Rep compatible object
|
||||
* Note: This is not sorting the result properties since it can
|
||||
* result in an unexpected order of parameters. See bug 1469533
|
||||
*
|
||||
* @param {object[]} arrOfKeyValuePairs - An array of key-value pairs or form params.
|
||||
* @param {string} arrOfKeyValuePairs[].name
|
||||
* @param {string|Array} arrOfKeyValuePairs[].value
|
||||
*
|
||||
* @returns {object} Rep compatible object
|
||||
*/
|
||||
getProperties(arr) {
|
||||
return arr.reduce((map, obj) => {
|
||||
const value = map[obj.name];
|
||||
if (value || value === "") {
|
||||
if (typeof value !== "object") {
|
||||
map[obj.name] = [value];
|
||||
getProperties(arrOfKeyValuePairs) {
|
||||
return arrOfKeyValuePairs.reduce((dict, { name, value }) => {
|
||||
if (name in dict) {
|
||||
const dictValue = dict[name];
|
||||
if (!Array.isArray(dictValue)) {
|
||||
dict[name] = [dictValue];
|
||||
}
|
||||
map[obj.name].push(obj.value);
|
||||
dict[name].push(value);
|
||||
} else {
|
||||
map[obj.name] = obj.value;
|
||||
dict[name] = value;
|
||||
}
|
||||
return map;
|
||||
}, {});
|
||||
return dict;
|
||||
}, Object.create(null));
|
||||
}
|
||||
|
||||
toggleRawRequestPayload() {
|
||||
|
|
@ -205,10 +209,9 @@ class RequestPanel extends Component {
|
|||
|
||||
// Form Data section
|
||||
if (formDataSections && formDataSections.length) {
|
||||
const sections = formDataSections.filter(str => /\S/.test(str)).join("&");
|
||||
component = PropertiesView;
|
||||
componentProps = {
|
||||
object: this.getProperties(parseFormData(sections)),
|
||||
object: this.getProperties(parseFormData(formDataSections)),
|
||||
filterText,
|
||||
targetSearchResult,
|
||||
defaultSelectFirstNode: false,
|
||||
|
|
|
|||
|
|
@ -83,7 +83,6 @@ async function getFormDataSections(
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
return formDataSections;
|
||||
}
|
||||
|
||||
|
|
@ -418,28 +417,29 @@ function parseQueryString(query) {
|
|||
/**
|
||||
* Parse a string of formdata sections into its components
|
||||
*
|
||||
* @param {string} sections - sections of formdata joined by &
|
||||
* @return {array} array of formdata params { name, value }
|
||||
* @param {Array<string>} sections Array of sections of formdata
|
||||
* e.g ["", "a=x&b=y", "c=z"]
|
||||
* @return {Array<object>} Array of formdata params
|
||||
* e.g [{ name: 'a', value: 'x' }, { name: 'b', value: 'y'}, { name: 'c', value: 'z'}]
|
||||
*/
|
||||
function parseFormData(sections) {
|
||||
if (!sections) {
|
||||
if (!sections || !sections.length) {
|
||||
return [];
|
||||
}
|
||||
const formDataParams = [];
|
||||
const searchStr = sections
|
||||
// Filter out empty sections
|
||||
.filter(str => /\S/.test(str))
|
||||
.join("&");
|
||||
|
||||
return sections
|
||||
.replace(/^&/, "")
|
||||
.split("&")
|
||||
.map(e => {
|
||||
const firstEqualSignIndex = e.indexOf("=");
|
||||
const paramName =
|
||||
firstEqualSignIndex !== -1 ? e.slice(0, firstEqualSignIndex) : e;
|
||||
const paramValue =
|
||||
firstEqualSignIndex !== -1 ? e.slice(firstEqualSignIndex + 1) : "";
|
||||
return {
|
||||
name: paramName ? getUnicodeUrlPath(paramName) : "",
|
||||
value: paramValue ? getUnicodeUrlPath(paramValue) : "",
|
||||
};
|
||||
const params = new URLSearchParams(searchStr);
|
||||
for (const [key, value] of params) {
|
||||
formDataParams.push({
|
||||
name: getUnicodeUrlPath(key),
|
||||
value: getUnicodeUrlPath(value),
|
||||
});
|
||||
}
|
||||
return formDataParams;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ add_task(async function () {
|
|||
store.dispatch(Actions.batchEnable(false));
|
||||
|
||||
// Execute requests.
|
||||
await performRequests(monitor, tab, 12);
|
||||
await performRequests(monitor, tab, 13);
|
||||
|
||||
const requestListItems = document.querySelectorAll(
|
||||
".network-monitor .request-list-item"
|
||||
|
|
@ -49,7 +49,7 @@ add_task(async function () {
|
|||
await testRequestWithFormattedView(
|
||||
monitor,
|
||||
requestListItems[2],
|
||||
"?foo",
|
||||
"foo",
|
||||
"bar=123=xyz",
|
||||
"?foo=bar=123=xyz",
|
||||
1
|
||||
|
|
@ -92,6 +92,14 @@ add_task(async function () {
|
|||
'{ "foo": "bar" }',
|
||||
1
|
||||
);
|
||||
await testRequestWithFormattedView(
|
||||
monitor,
|
||||
requestListItems[12],
|
||||
"__proto__",
|
||||
"evil_value",
|
||||
"__proto__=evil_value",
|
||||
1
|
||||
);
|
||||
|
||||
await teardown(monitor);
|
||||
});
|
||||
|
|
|
|||
|
|
@ -326,10 +326,10 @@ function testEscapeStringWin() {
|
|||
"Percent signs should be escaped."
|
||||
);
|
||||
|
||||
const backslashes = "\\A simple string\\";
|
||||
const backslashes = " - \\A simple string\\ - ";
|
||||
is(
|
||||
CurlUtils.escapeStringWin(backslashes),
|
||||
'^\"^\\A simple string^\\^\"',
|
||||
'^\" - ^\\^\\A simple string^\\^\\ - ^\"',
|
||||
"Backslashes should be escaped."
|
||||
);
|
||||
|
||||
|
|
|
|||
|
|
@ -71,6 +71,7 @@
|
|||
await get("baz", "?species=in=(52,60)");
|
||||
await get("baz", "?a=&a=b");
|
||||
await get("baz", "?a=b&a=c&d=1");
|
||||
await post("baz", "", urlencoded, "__proto__=evil_value");
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
|
|
|
|||
|
|
@ -458,6 +458,9 @@ const CurlUtils = {
|
|||
return (
|
||||
encapsChars +
|
||||
str
|
||||
// Replace all the \ (used as the escape character in the next replace) with \\
|
||||
.replace(/\\/g, "\\\\")
|
||||
|
||||
// Replace all " with \" to ensure the first parser does not remove it.
|
||||
.replace(/"/g, '\\"')
|
||||
|
||||
|
|
|
|||
|
|
@ -4049,6 +4049,10 @@ bool IPDLParamTraits<dom::MaybeDiscarded<dom::BrowsingContext>>::Read(
|
|||
if (id == 0) {
|
||||
*aResult = nullptr;
|
||||
} else if (RefPtr<dom::BrowsingContext> bc = dom::BrowsingContext::Get(id)) {
|
||||
if (!bc->Group()->IsKnownForMessageReader(aReader)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
*aResult = std::move(bc);
|
||||
} else {
|
||||
aResult->SetDiscarded(id);
|
||||
|
|
|
|||
|
|
@ -251,6 +251,42 @@ ContentParent* BrowsingContextGroup::GetHostProcess(
|
|||
return mHosts.GetWeak(aRemoteType);
|
||||
}
|
||||
|
||||
bool BrowsingContextGroup::IsKnownForMessageReader(
|
||||
IPC::MessageReader* aReader) {
|
||||
if (!aReader->GetActor()) {
|
||||
aReader->FatalError(
|
||||
"No actor for BrowsingContextGroup::IsKnownForMessageReader");
|
||||
return false;
|
||||
}
|
||||
|
||||
mozilla::ipc::IToplevelProtocol* topActor =
|
||||
aReader->GetActor()->ToplevelProtocol();
|
||||
switch (topActor->GetProtocolId()) {
|
||||
case PInProcessMsgStart:
|
||||
// PInProcess always exists only within a single process, so we don't need
|
||||
// to do any validation on it.
|
||||
return true;
|
||||
|
||||
case PContentMsgStart:
|
||||
// The process should only be able to name this BCG if it is
|
||||
// subscribed, or if the BCG has been destroyed (and has therefore
|
||||
// stopped tracking subscribers).
|
||||
if (topActor->GetSide() == mozilla::ipc::ParentSide && !mDestroyed &&
|
||||
!mSubscribers.Contains(static_cast<ContentParent*>(topActor))) {
|
||||
aReader->FatalError(
|
||||
"Process is not subscribed to this BrowsingContextGroup");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
|
||||
default:
|
||||
aReader->FatalError(
|
||||
"Unsupported toplevel actor for "
|
||||
"BrowsingContextGroup::IsKnownForMessageReader");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void BrowsingContextGroup::UpdateToplevelsSuspendedIfNeeded() {
|
||||
if (!StaticPrefs::dom_suspend_inactive_enabled()) {
|
||||
return;
|
||||
|
|
@ -296,8 +332,8 @@ void BrowsingContextGroup::Destroy() {
|
|||
!sBrowsingContextGroups->Contains(Id()) ||
|
||||
*sBrowsingContextGroups->Lookup(Id()) != this);
|
||||
}
|
||||
mDestroyed = true;
|
||||
#endif
|
||||
mDestroyed = true;
|
||||
|
||||
// Make sure to call `RemoveBrowsingContextGroup` for every entry in both
|
||||
// `mHosts` and `mSubscribers`. This will visit most entries twice, but
|
||||
|
|
|
|||
|
|
@ -87,6 +87,12 @@ class BrowsingContextGroup final : public nsWrapperCache {
|
|||
// BrowsingContextGroup, if possible.
|
||||
ContentParent* GetHostProcess(const nsACString& aRemoteType);
|
||||
|
||||
// Check if the process which sent the message being read from aReader is
|
||||
// aware of this BrowsingContextGroup's existence.
|
||||
// If this returns false, it will first set a fatal error on aReader with more
|
||||
// details.
|
||||
bool IsKnownForMessageReader(IPC::MessageReader* aReader);
|
||||
|
||||
// When a BrowsingContext is being discarded, we may want to keep the
|
||||
// corresponding BrowsingContextGroup alive until the other process
|
||||
// acknowledges that the BrowsingContext has been discarded. A `KeepAlive`
|
||||
|
|
@ -260,9 +266,7 @@ class BrowsingContextGroup final : public nsWrapperCache {
|
|||
|
||||
uint32_t mKeepAliveCount = 0;
|
||||
|
||||
#ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
|
||||
bool mDestroyed = false;
|
||||
#endif
|
||||
|
||||
// A BrowsingContextGroup contains a series of {Browsing,Window}Context
|
||||
// objects. They are addressed using a hashtable to avoid linear lookup when
|
||||
|
|
|
|||
|
|
@ -764,6 +764,10 @@ bool IPDLParamTraits<dom::MaybeDiscarded<dom::WindowContext>>::Read(
|
|||
if (id == 0) {
|
||||
*aResult = nullptr;
|
||||
} else if (RefPtr<dom::WindowContext> wc = dom::WindowContext::GetById(id)) {
|
||||
if (!wc->Group()->IsKnownForMessageReader(aReader)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
*aResult = std::move(wc);
|
||||
} else {
|
||||
aResult->SetDiscarded(id);
|
||||
|
|
|
|||
|
|
@ -687,7 +687,10 @@ class SimpleHTMLCollection final : public nsSimpleContentList,
|
|||
}
|
||||
virtual uint32_t Length() override { return nsSimpleContentList::Length(); }
|
||||
virtual Element* GetElementAt(uint32_t aIndex) override {
|
||||
return mElements.SafeElementAt(aIndex)->AsElement();
|
||||
if (nsIContent* content = mElements.SafeElementAt(aIndex)) {
|
||||
return content->AsElement();
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
virtual Element* GetFirstNamedElement(const nsAString& aName,
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@
|
|||
#include "mozilla/Assertions.h"
|
||||
#include "mozilla/ErrorResult.h"
|
||||
#include "mozilla/Maybe.h"
|
||||
#include "mozilla/Span.h"
|
||||
#include "mozilla/UniquePtr.h"
|
||||
#include "mozilla/dom/BindingDeclarations.h"
|
||||
#include "mozilla/dom/BlobImpl.h"
|
||||
|
|
@ -173,7 +174,8 @@ bool StructuredCloneBlob::Holder::ReadStructuredCloneInternal(
|
|||
return false;
|
||||
}
|
||||
#endif
|
||||
BlobImpls().AppendElements(&aHolder->BlobImpls()[blobOffset], blobCount);
|
||||
BlobImpls().AppendElements(
|
||||
Span(aHolder->BlobImpls()).Subspan(blobOffset, blobCount));
|
||||
}
|
||||
|
||||
JSStructuredCloneData data(mStructuredCloneScope);
|
||||
|
|
|
|||
|
|
@ -3583,6 +3583,7 @@ void nsRange::CreateOrUpdateCrossShadowBoundaryRangeIfNeeded(
|
|||
// Nodes at least needs to be in the same document.
|
||||
if (startNode && endNode &&
|
||||
startNode->GetComposedDoc() != endNode->GetComposedDoc()) {
|
||||
ResetCrossShadowBoundaryRange();
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -3597,6 +3598,13 @@ void nsRange::CreateOrUpdateCrossShadowBoundaryRangeIfNeeded(
|
|||
return false;
|
||||
}
|
||||
|
||||
// We don't allow ranges to span different NAC subtrees (because we don't
|
||||
// notify when unbinding NAC roots historically). nsRange can already deal
|
||||
// with the "same anonymous subtree" case.
|
||||
if (aContainer->IsInNativeAnonymousSubtree()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// AbstractRange::GetClosestCommonInclusiveAncestor only supports
|
||||
// Document and Content nodes.
|
||||
return aContainer->IsDocument() || aContainer->IsContent();
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@
|
|||
#include "mozilla/DebugOnly.h"
|
||||
#include "mozilla/Encoding.h"
|
||||
#include "mozilla/FloatingPoint.h"
|
||||
#include "mozilla/Maybe.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
#include "mozilla/ScopeExit.h"
|
||||
#include "mozilla/StaticPrefs_dom.h"
|
||||
|
|
@ -3800,7 +3801,7 @@ bool HTMLConstructor(JSContext* aCx, unsigned aArgc, JS::Value* aVp,
|
|||
// Technically, per spec, a window always has a document. In Gecko, a
|
||||
// sufficiently torn-down window might not, so check for that case. We're
|
||||
// going to need a document to create an element.
|
||||
Document* doc = window->GetExtantDoc();
|
||||
RefPtr<Document> doc = window->GetExtantDoc();
|
||||
if (!doc) {
|
||||
rv.Throw(NS_ERROR_UNEXPECTED);
|
||||
return false;
|
||||
|
|
@ -3843,7 +3844,7 @@ bool HTMLConstructor(JSContext* aCx, unsigned aArgc, JS::Value* aVp,
|
|||
}
|
||||
|
||||
// Step 3.
|
||||
CustomElementDefinition* definition =
|
||||
RefPtr<CustomElementDefinition> definition =
|
||||
registry->LookupCustomElementDefinition(aCx, newTarget);
|
||||
if (!definition) {
|
||||
rv.ThrowTypeError<MSG_ILLEGAL_CONSTRUCTOR>();
|
||||
|
|
@ -3943,6 +3944,21 @@ bool HTMLConstructor(JSContext* aCx, unsigned aArgc, JS::Value* aVp,
|
|||
|
||||
// Steps 7 and 8.
|
||||
JS::Rooted<JSObject*> desiredProto(aCx);
|
||||
|
||||
// Check which construction path we're taking before running any JS.
|
||||
// This determines whether we need AutoConstructionDepth protection.
|
||||
nsTArray<RefPtr<Element>>& constructionStack = definition->mConstructionStack;
|
||||
const bool isDirectConstruction = constructionStack.IsEmpty();
|
||||
|
||||
// For direct construction (not upgrade), create AutoConstructionDepth before
|
||||
// GetDesiredProto. This ensures mConstructionDepth is incremented before any
|
||||
// re-entrant JS can run via Proxy traps, preventing desynchronization with
|
||||
// mPrefixStack which may be pushed by nsContentUtils::NewXULOrHTMLElement.
|
||||
mozilla::Maybe<AutoConstructionDepth> autoDepth;
|
||||
if (isDirectConstruction) {
|
||||
autoDepth.emplace(definition);
|
||||
}
|
||||
|
||||
if (!GetDesiredProto(aCx, args, aProtoId, aCreator, &desiredProto)) {
|
||||
return false;
|
||||
}
|
||||
|
|
@ -3953,14 +3969,12 @@ bool HTMLConstructor(JSContext* aCx, unsigned aArgc, JS::Value* aVp,
|
|||
// one branch and steps 9-12 on another branch, then common up the "return
|
||||
// element" work.
|
||||
RefPtr<Element> element;
|
||||
nsTArray<RefPtr<Element>>& constructionStack = definition->mConstructionStack;
|
||||
if (constructionStack.IsEmpty()) {
|
||||
if (isDirectConstruction) {
|
||||
// Step 8.
|
||||
// Now we go to construct an element. We want to do this in global's
|
||||
// realm, not caller realm (the normal constructor behavior),
|
||||
// just in case those elements create JS things.
|
||||
JSAutoRealm ar(aCx, global.Get());
|
||||
AutoConstructionDepth acd(definition);
|
||||
|
||||
RefPtr<NodeInfo> nodeInfo = doc->NodeInfoManager()->GetNodeInfo(
|
||||
definition->mLocalName, definition->mPrefixStack.LastElement(), ns,
|
||||
|
|
|
|||
|
|
@ -580,7 +580,7 @@ bool TexUnpackBytes::TexOrSubImage(bool isSubImage, bool needsRespec,
|
|||
const auto& unpacking = unpackingRes.inspect();
|
||||
const auto stride = unpacking.metrics.bytesPerRowStride;
|
||||
// clang-format off
|
||||
if (!ConvertIfNeeded(webgl, unpacking.state.rowLength,
|
||||
if (!ConvertIfNeeded(webgl, unpacking.metrics.usedPixelsPerRow,
|
||||
unpacking.metrics.totalRows,
|
||||
format, uploadPtr, AutoAssertCast(stride),
|
||||
format, AutoAssertCast(stride), &uploadPtr, &tempBuffer)) {
|
||||
|
|
@ -1109,6 +1109,12 @@ bool TexUnpackSurface::TexOrSubImage(bool isSubImage, bool needsRespec,
|
|||
|
||||
////
|
||||
|
||||
const auto surfSize = surf->GetSize();
|
||||
if (uint32_t(surfSize.width) < size.x || uint32_t(surfSize.height) < size.y) {
|
||||
gfxCriticalError() << "Source surface size too small for upload.";
|
||||
return false;
|
||||
}
|
||||
|
||||
WebGLTexelFormat srcFormat;
|
||||
uint8_t srcBPP;
|
||||
if (!GetFormatForSurf(surf, &srcFormat, &srcBPP)) {
|
||||
|
|
@ -1133,7 +1139,7 @@ bool TexUnpackSurface::TexOrSubImage(bool isSubImage, bool needsRespec,
|
|||
|
||||
const auto dstFormat = FormatForPackingInfo(dstPI);
|
||||
const size_t dstBpp = BytesPerPixel(dstPI);
|
||||
const size_t dstUsedBytesPerRow = dstBpp * surf->GetSize().width;
|
||||
const size_t dstUsedBytesPerRow = dstBpp * surfSize.width;
|
||||
size_t dstStride = dstFormat == srcFormat ? srcStride // Try To match
|
||||
: dstUsedBytesPerRow;
|
||||
|
||||
|
|
@ -1164,7 +1170,7 @@ bool TexUnpackSurface::TexOrSubImage(bool isSubImage, bool needsRespec,
|
|||
const uint8_t* dstBegin = srcBegin;
|
||||
UniqueBuffer tempBuffer;
|
||||
// clang-format off
|
||||
if (!ConvertIfNeeded(webgl, surf->GetSize().width, surf->GetSize().height,
|
||||
if (!ConvertIfNeeded(webgl, surfSize.width, surfSize.height,
|
||||
srcFormat, srcBegin, AutoAssertCast(srcStride),
|
||||
dstFormat, AutoAssertCast(dstUnpacking.metrics.bytesPerRowStride), &dstBegin,
|
||||
&tempBuffer)) {
|
||||
|
|
|
|||
|
|
@ -2885,6 +2885,7 @@ webgl::ExplicitPixelPackingState::ForUseWith(
|
|||
auto metrics = Metrics{};
|
||||
|
||||
metrics.usedSize = subrectSize;
|
||||
metrics.usedPixelsPerRow = usedPixelsPerRow.value();
|
||||
metrics.bytesPerPixel = BytesPerPixel(pi);
|
||||
|
||||
// -
|
||||
|
|
|
|||
|
|
@ -1142,6 +1142,9 @@ struct ExplicitPixelPackingState final {
|
|||
// ...aligned to ALIGNMENT.
|
||||
size_t bytesPerRowStride = 0;
|
||||
|
||||
// SKIP_PIXELS+size.x
|
||||
size_t usedPixelsPerRow = 0;
|
||||
|
||||
// structuredSrcSize.y, otherwise IMAGE_HEIGHT*(SKIP_IMAGES+size.z)
|
||||
size_t totalRows = 0;
|
||||
|
||||
|
|
|
|||
|
|
@ -9,6 +9,9 @@
|
|||
#include "ClientManager.h"
|
||||
#include "ClientSource.h"
|
||||
#include "MainThreadUtils.h"
|
||||
#include "mozilla/AntiTrackingUtils.h"
|
||||
#include "mozilla/StaticPrefs_privacy.h"
|
||||
#include "mozilla/StoragePrincipalHelper.h"
|
||||
#include "mozilla/dom/ClientsBinding.h"
|
||||
#include "mozilla/dom/ServiceWorkerDescriptor.h"
|
||||
#include "mozilla/ipc/BackgroundUtils.h"
|
||||
|
|
@ -133,6 +136,13 @@ class ClientChannelHelper : public nsIInterfaceRequestor,
|
|||
// If it's a cross-origin redirect then we discard the old reserved client
|
||||
// and create a new one.
|
||||
else {
|
||||
// The partition-key, and in particular the foreign bit, can change on a
|
||||
// cross-origin redirect so it is essential to update the anti-tracking
|
||||
// info for the channel. This will happen in nsHttpChannel::AsyncOpen but
|
||||
// that happens strictly after now, whereas we are sampling the principal
|
||||
// now.
|
||||
AntiTrackingUtils::UpdateAntiTrackingInfoForChannel(aNewChannel);
|
||||
|
||||
nsCOMPtr<nsIPrincipal> foreignPartitionedPrincipal;
|
||||
rv = StoragePrincipalHelper::GetPrincipal(
|
||||
aNewChannel,
|
||||
|
|
|
|||
|
|
@ -194,6 +194,12 @@ already_AddRefed<Promise> CredentialsContainer::Get(
|
|||
return promise.forget();
|
||||
}
|
||||
|
||||
if (aOptions.mMediation != CredentialMediationRequirement::Conditional &&
|
||||
aOptions.mMediation != CredentialMediationRequirement::Optional &&
|
||||
aOptions.mMediation != CredentialMediationRequirement::Required) {
|
||||
return CreateAndRejectWithNotSupported(mParent, aRv);
|
||||
}
|
||||
|
||||
EnsureWebAuthnHandler();
|
||||
return mWebAuthnHandler->GetAssertion(aOptions.mPublicKey.Value(),
|
||||
conditionallyMediated,
|
||||
|
|
@ -269,6 +275,11 @@ already_AddRefed<Promise> CredentialsContainer::Create(
|
|||
return CreateAndRejectWithNotAllowed(mParent, aRv);
|
||||
}
|
||||
|
||||
if (aOptions.mMediation != CredentialMediationRequirement::Optional &&
|
||||
aOptions.mMediation != CredentialMediationRequirement::Required) {
|
||||
return CreateAndRejectWithNotSupported(mParent, aRv);
|
||||
}
|
||||
|
||||
EnsureWebAuthnHandler();
|
||||
return mWebAuthnHandler->MakeCredential(aOptions.mPublicKey.Value(),
|
||||
aOptions.mSignal, aRv);
|
||||
|
|
|
|||
|
|
@ -176,7 +176,7 @@ IPCResult FetchParent::RecvFetchOp(FetchOpArgs&& aArgs) {
|
|||
self->mResponsePromises =
|
||||
fetchService->Fetch(AsVariant(FetchService::WorkerFetchArgs(
|
||||
{self->mRequest.clonePtr(), self->mPrincipalInfo,
|
||||
self->mWorkerScript, self->mClientInfo, self->mController,
|
||||
self->mWorkerScript, *self->mClientInfo, self->mController,
|
||||
self->mCookieJarSettings, self->mNeedOnDataAvailable,
|
||||
self->mCSPEventListener, self->mAssociatedBrowsingContextID,
|
||||
self->mBackgroundEventTarget, self->mID,
|
||||
|
|
@ -189,6 +189,7 @@ IPCResult FetchParent::RecvFetchOp(FetchOpArgs&& aArgs) {
|
|||
fetchService->Fetch(AsVariant(FetchService::MainThreadFetchArgs({
|
||||
self->mRequest.clonePtr(),
|
||||
self->mPrincipalInfo,
|
||||
*self->mClientInfo,
|
||||
self->mCookieJarSettings,
|
||||
self->mNeedOnDataAvailable,
|
||||
self->mCSPEventListener,
|
||||
|
|
|
|||
|
|
@ -271,8 +271,7 @@ RefPtr<FetchServicePromises> FetchService::FetchInstance::Fetch() {
|
|||
if (mArgsType == FetchArgsType::WorkerFetch) {
|
||||
auto& args = mArgs.as<WorkerFetchArgs>();
|
||||
mFetchDriver->SetWorkerScript(args.mWorkerScript);
|
||||
MOZ_ASSERT(args.mClientInfo.isSome());
|
||||
mFetchDriver->SetClientInfo(args.mClientInfo.ref());
|
||||
mFetchDriver->SetClientInfo(args.mClientInfo);
|
||||
mFetchDriver->SetController(args.mController);
|
||||
if (args.mCSPEventListener) {
|
||||
mFetchDriver->SetCSPEventListener(args.mCSPEventListener);
|
||||
|
|
@ -285,6 +284,7 @@ RefPtr<FetchServicePromises> FetchService::FetchInstance::Fetch() {
|
|||
|
||||
if (mArgsType == FetchArgsType::MainThreadFetch) {
|
||||
auto& args = mArgs.as<MainThreadFetchArgs>();
|
||||
mFetchDriver->SetClientInfo(args.mClientInfo);
|
||||
mFetchDriver->SetIsThirdPartyContext(Some(args.mIsThirdPartyContext));
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -108,7 +108,7 @@ class FetchService final : public nsIObserver {
|
|||
SafeRefPtr<InternalRequest> mRequest;
|
||||
mozilla::ipc::PrincipalInfo mPrincipalInfo;
|
||||
nsCString mWorkerScript;
|
||||
Maybe<ClientInfo> mClientInfo;
|
||||
ClientInfo mClientInfo;
|
||||
Maybe<ServiceWorkerDescriptor> mController;
|
||||
Maybe<net::CookieJarSettingsArgs> mCookieJarSettings;
|
||||
bool mNeedOnDataAvailable;
|
||||
|
|
@ -131,6 +131,7 @@ class FetchService final : public nsIObserver {
|
|||
struct MainThreadFetchArgs {
|
||||
SafeRefPtr<InternalRequest> mRequest;
|
||||
mozilla::ipc::PrincipalInfo mPrincipalInfo;
|
||||
ClientInfo mClientInfo;
|
||||
Maybe<net::CookieJarSettingsArgs> mCookieJarSettings;
|
||||
bool mNeedOnDataAvailable;
|
||||
nsCOMPtr<nsICSPEventListener> mCSPEventListener;
|
||||
|
|
|
|||
|
|
@ -1316,6 +1316,7 @@ class DatabaseConnection::UpdateRefcountFunction::FileInfoEntry final {
|
|||
}
|
||||
}
|
||||
void DecBySavepointDelta() { mDelta -= mSavepointDelta; }
|
||||
void ResetSavepointDelta() { mSavepointDelta = 0; }
|
||||
SafeRefPtr<DatabaseFileInfo> ReleaseFileInfo() {
|
||||
return std::move(mFileInfo);
|
||||
}
|
||||
|
|
@ -7583,6 +7584,7 @@ void DatabaseConnection::UpdateRefcountFunction::RollbackSavepoint() {
|
|||
|
||||
for (const auto& entry : mSavepointEntriesIndex.Values()) {
|
||||
entry->DecBySavepointDelta();
|
||||
entry->ResetSavepointDelta();
|
||||
}
|
||||
|
||||
mInSavepoint = false;
|
||||
|
|
@ -10548,8 +10550,8 @@ already_AddRefed<PBackgroundIDBCursorParent> TransactionBase::AllocCursor(
|
|||
if (NS_AUUF_OR_WARN_IF(!objectStoreMetadata)) {
|
||||
return nullptr;
|
||||
}
|
||||
if (aTrustParams && NS_AUUF_OR_WARN_IF(!VerifyRequestParams(
|
||||
commonParams.optionalKeyRange()))) {
|
||||
if (!aTrustParams && NS_AUUF_OR_WARN_IF(!VerifyRequestParams(
|
||||
commonParams.optionalKeyRange()))) {
|
||||
return nullptr;
|
||||
}
|
||||
direction = commonParams.direction();
|
||||
|
|
@ -18974,7 +18976,8 @@ nsresult ObjectStoreAddOrPutRequestOp::DoDatabaseWork(
|
|||
|
||||
// Update index keys if primary key is preserved in child.
|
||||
for (auto& updateInfo : mParams.indexUpdateInfos()) {
|
||||
updateInfo.value().MaybeUpdateAutoIncrementKey(autoIncrementNum);
|
||||
QM_TRY(
|
||||
updateInfo.value().MaybeUpdateAutoIncrementKey(autoIncrementNum));
|
||||
}
|
||||
} else if (key.IsFloat()) {
|
||||
double numericKey = key.ToFloat();
|
||||
|
|
|
|||
|
|
@ -585,19 +585,34 @@ void Key::ReserveAutoIncrementKey(bool aFirstOfArray) {
|
|||
mozilla::BigEndian::writeUint64(buffer, UINT64_MAX);
|
||||
}
|
||||
|
||||
void Key::MaybeUpdateAutoIncrementKey(int64_t aKey) {
|
||||
Result<Ok, nsresult> Key::MaybeUpdateAutoIncrementKey(int64_t aKey) {
|
||||
if (mAutoIncrementKeyOffsets.IsEmpty()) {
|
||||
return;
|
||||
return Ok{};
|
||||
}
|
||||
|
||||
static constexpr auto maxOffset =
|
||||
KEY_MAXIMUM_BUFFER_LENGTH - sizeof(double) - 1;
|
||||
|
||||
for (uint32_t offset : mAutoIncrementKeyOffsets) {
|
||||
if (offset > maxOffset) {
|
||||
return Err(NS_ERROR_DOM_INDEXEDDB_KEY_ERR);
|
||||
}
|
||||
|
||||
char* buffer;
|
||||
MOZ_ALWAYS_TRUE(mBuffer.GetMutableData(&buffer));
|
||||
const auto capacity = mBuffer.GetMutableData(&buffer);
|
||||
MOZ_ALWAYS_TRUE(capacity);
|
||||
|
||||
if (offset + sizeof(double) > capacity) {
|
||||
return Err(NS_ERROR_DOM_INDEXEDDB_KEY_ERR);
|
||||
}
|
||||
|
||||
buffer += offset;
|
||||
WriteDoubleToUint64(buffer, double(aKey));
|
||||
}
|
||||
|
||||
TrimBuffer();
|
||||
|
||||
return Ok{};
|
||||
}
|
||||
|
||||
void Key::WriteDoubleToUint64(char* aBuffer, double aValue) {
|
||||
|
|
|
|||
|
|
@ -185,7 +185,7 @@ class Key {
|
|||
|
||||
void ReserveAutoIncrementKey(bool aFirstOfArray);
|
||||
|
||||
void MaybeUpdateAutoIncrementKey(int64_t aKey);
|
||||
Result<Ok, nsresult> MaybeUpdateAutoIncrementKey(int64_t aKey);
|
||||
|
||||
private:
|
||||
class MOZ_STACK_CLASS ArrayValueEncoder;
|
||||
|
|
|
|||
|
|
@ -325,6 +325,7 @@ void MediaKeys::RejectPromise(PromiseId aId, ErrorResult&& aException,
|
|||
this, aId, errorCodeAsInt);
|
||||
return;
|
||||
}
|
||||
RefPtr<MediaKeys> keys(this);
|
||||
|
||||
// This promise could be a createSession or loadSession promise,
|
||||
// so we might have a pending session waiting to be resolved into
|
||||
|
|
@ -379,6 +380,7 @@ void MediaKeys::ResolvePromise(PromiseId aId) {
|
|||
if (!promise) {
|
||||
return;
|
||||
}
|
||||
RefPtr<MediaKeys> keys(this);
|
||||
|
||||
uint32_t token = 0;
|
||||
if (!mPromiseIdToken.Get(aId, &token)) {
|
||||
|
|
|
|||
|
|
@ -189,8 +189,10 @@ bool ClearKeyUtils::DecryptCbcs(const vector<uint8_t>& aKey,
|
|||
/* static */
|
||||
bool ClearKeyUtils::DecryptAES(const vector<uint8_t>& aKey,
|
||||
vector<uint8_t>& aData, vector<uint8_t>& aIV) {
|
||||
assert(aIV.size() == CENC_KEY_LEN);
|
||||
assert(aKey.size() == CENC_KEY_LEN);
|
||||
if (aKey.size() != CENC_KEY_LEN || aIV.size() != CENC_KEY_LEN) {
|
||||
CK_LOGE("Key and IV size should be 16!");
|
||||
return false;
|
||||
}
|
||||
|
||||
PK11SlotInfo* slot = PK11_GetInternalKeySlot();
|
||||
if (!slot) {
|
||||
|
|
|
|||
|
|
@ -1200,7 +1200,7 @@ MediaResult MediaChangeMonitor::CreateDecoderAndInit(MediaRawData* aSample) {
|
|||
return;
|
||||
}
|
||||
|
||||
mDecodePromise.Reject(
|
||||
mDecodePromise.RejectIfExists(
|
||||
MediaResult(
|
||||
aError.Code(),
|
||||
RESULT_DETAIL("Unable to initialize decoder")),
|
||||
|
|
@ -1215,7 +1215,7 @@ MediaResult MediaChangeMonitor::CreateDecoderAndInit(MediaRawData* aSample) {
|
|||
mFlushPromise.Reject(aError, __func__);
|
||||
return;
|
||||
}
|
||||
mDecodePromise.Reject(
|
||||
mDecodePromise.RejectIfExists(
|
||||
MediaResult(NS_ERROR_DOM_MEDIA_FATAL_ERR,
|
||||
RESULT_DETAIL("Unable to create decoder")),
|
||||
__func__);
|
||||
|
|
@ -1259,12 +1259,12 @@ void MediaChangeMonitor::DecodeFirstSample(MediaRawData* aSample) {
|
|||
[self, this](MediaDataDecoder::DecodedData&& aResults) {
|
||||
mDecodePromiseRequest.Complete();
|
||||
mPendingFrames.AppendElements(std::move(aResults));
|
||||
mDecodePromise.Resolve(std::move(mPendingFrames), __func__);
|
||||
mDecodePromise.ResolveIfExists(std::move(mPendingFrames), __func__);
|
||||
mPendingFrames = DecodedData();
|
||||
},
|
||||
[self, this](const MediaResult& aError) {
|
||||
mDecodePromiseRequest.Complete();
|
||||
mDecodePromise.Reject(aError, __func__);
|
||||
mDecodePromise.RejectIfExists(aError, __func__);
|
||||
})
|
||||
->Track(mDecodePromiseRequest);
|
||||
}
|
||||
|
|
@ -1323,7 +1323,7 @@ void MediaChangeMonitor::DrainThenFlushDecoder(MediaRawData* aPendingSample) {
|
|||
mFlushPromise.Reject(aError, __func__);
|
||||
return;
|
||||
}
|
||||
mDecodePromise.Reject(aError, __func__);
|
||||
mDecodePromise.RejectIfExists(aError, __func__);
|
||||
})
|
||||
->Track(mDrainRequest);
|
||||
}
|
||||
|
|
@ -1367,7 +1367,7 @@ void MediaChangeMonitor::FlushThenShutdownDecoder(
|
|||
return;
|
||||
}
|
||||
MOZ_ASSERT(NS_FAILED(rv));
|
||||
mDecodePromise.Reject(rv, __func__);
|
||||
mDecodePromise.RejectIfExists(rv, __func__);
|
||||
return;
|
||||
},
|
||||
[] { MOZ_CRASH("Can't reach here'"); })
|
||||
|
|
@ -1380,7 +1380,7 @@ void MediaChangeMonitor::FlushThenShutdownDecoder(
|
|||
mFlushPromise.Reject(aError, __func__);
|
||||
return;
|
||||
}
|
||||
mDecodePromise.Reject(aError, __func__);
|
||||
mDecodePromise.RejectIfExists(aError, __func__);
|
||||
})
|
||||
->Track(mFlushRequest);
|
||||
}
|
||||
|
|
|
|||
100
icecat/dom/media/test/crashtests/2014824.html
Normal file
100
icecat/dom/media/test/crashtests/2014824.html
Normal file
File diff suppressed because one or more lines are too long
|
|
@ -187,3 +187,4 @@ load 1905234.html
|
|||
load 1905231.webm
|
||||
load 1917627.mp4
|
||||
skip-if(Android) load audioworkletprocessor-recursion.html
|
||||
load 2014824.html
|
||||
|
|
|
|||
|
|
@ -229,7 +229,12 @@ class AutoResampler final {
|
|||
MOZ_ASSERT(mResampler);
|
||||
return mResampler;
|
||||
}
|
||||
void operator=(SpeexResamplerState* aResampler) { mResampler = aResampler; }
|
||||
void operator=(SpeexResamplerState* aResampler) {
|
||||
if (mResampler) {
|
||||
speex_resampler_destroy(mResampler);
|
||||
}
|
||||
mResampler = aResampler;
|
||||
}
|
||||
|
||||
private:
|
||||
SpeexResamplerState* mResampler;
|
||||
|
|
@ -564,6 +569,13 @@ void MediaDecodeTask::FinishDecode() {
|
|||
}
|
||||
mDecodeJob.mBuffer.mBuffer = std::move(newBuffers);
|
||||
channelCount = audioData->mChannels;
|
||||
|
||||
// Don't bother draining the previous resampler for unexpected edge case.
|
||||
if (sampleRate != destSampleRate) {
|
||||
resampler = speex_resampler_init(channelCount, sampleRate, destSampleRate,
|
||||
SPEEX_RESAMPLER_QUALITY_DEFAULT, nullptr);
|
||||
speex_resampler_skip_zeros(resampler);
|
||||
}
|
||||
}
|
||||
|
||||
const AudioDataValue* bufferData =
|
||||
|
|
|
|||
|
|
@ -900,6 +900,12 @@ nsresult WebMDemuxer::GetNextPacket(TrackInfo::TrackType aType,
|
|||
|
||||
for (uint8_t i = 0; i < numPartitions; i++) {
|
||||
uint32_t partition = partitions[i];
|
||||
if (partition > length || partition < lastOffset) {
|
||||
WEBM_DEBUG(
|
||||
"Invalid partition offset: %u (length: %zu, lastOffset: %u)",
|
||||
partition, length, lastOffset);
|
||||
return NS_ERROR_DOM_MEDIA_DEMUXER_ERR;
|
||||
}
|
||||
uint32_t currentLength = partition - lastOffset;
|
||||
|
||||
if (encrypted) {
|
||||
|
|
@ -910,8 +916,6 @@ nsresult WebMDemuxer::GetNextPacket(TrackInfo::TrackType aType,
|
|||
|
||||
encrypted = !encrypted;
|
||||
lastOffset = partition;
|
||||
|
||||
MOZ_ASSERT(lastOffset <= length);
|
||||
}
|
||||
|
||||
// Add the data between the last offset and the end of the data.
|
||||
|
|
|
|||
|
|
@ -855,6 +855,15 @@ int32_t WebrtcGmpVideoDecoder::Decode(const webrtc::EncodedImage& aInputImage,
|
|||
}
|
||||
|
||||
void WebrtcGmpVideoDecoder::Decode_g(UniquePtr<GMPDecodeData>&& aDecodeData) {
|
||||
CheckedInt<uint32_t> dataSize(aDecodeData->mImage.size());
|
||||
dataSize -= 4;
|
||||
if (!dataSize.isValid()) {
|
||||
GMP_LOG_ERROR("%s: bad input size (%zu)!", __PRETTY_FUNCTION__,
|
||||
aDecodeData->mImage.size());
|
||||
mDecoderStatus = GMPInvalidArgErr;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!mGMP) {
|
||||
if (mInitting) {
|
||||
// InitDone hasn't been called yet (race)
|
||||
|
|
|
|||
|
|
@ -47,6 +47,7 @@
|
|||
add_task(test_empty_credential_list);
|
||||
add_task(test_credential_protection_policy_uv_optional_with_list);
|
||||
add_task(test_credential_protection_policy_uv_required);
|
||||
add_task(test_unsupported_mediation_requirements);
|
||||
|
||||
function requestGetAssertion(params) {
|
||||
return navigator.credentials.get(params);
|
||||
|
|
@ -80,6 +81,11 @@
|
|||
is(aResult.code, DOMException.ABORT_ERR, "Expecting an AbortError");
|
||||
}
|
||||
|
||||
function expectNotSupportedError(aResult) {
|
||||
ok(aResult.toString().startsWith("NotSupportedError"), "Expecting a NotSupportedError");
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
// Set up a valid credential
|
||||
async function test_setup_valid_credential() {
|
||||
let publicKey = {
|
||||
|
|
@ -293,6 +299,19 @@
|
|||
|
||||
setUserVerified(authenticatorId, true)
|
||||
}
|
||||
|
||||
async function test_unsupported_mediation_requirements() {
|
||||
let publicKey = {
|
||||
challenge: gAssertionChallenge,
|
||||
allowCredentials: [validCred]
|
||||
};
|
||||
|
||||
for (const mediation of ["silent"]) {
|
||||
await requestGetAssertion({publicKey, mediation})
|
||||
.then(arrivingHereIsBad)
|
||||
.catch(expectNotSupportedError);
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
</body>
|
||||
|
|
|
|||
|
|
@ -78,6 +78,7 @@
|
|||
add_task(test_no_unexpected_extensions);
|
||||
add_task(test_cred_props_with_rk_required);
|
||||
add_task(test_cred_props_with_rk_discouraged);
|
||||
add_task(test_unsupported_mediation_requirements);
|
||||
|
||||
function arrivingHereIsGood(aResult) {
|
||||
ok(true, "Good result! Received a: " + aResult);
|
||||
|
|
@ -453,6 +454,17 @@
|
|||
is(extensionResults.credProps?.rk, false, "rk is false");
|
||||
}
|
||||
|
||||
async function test_unsupported_mediation_requirements() {
|
||||
let makeCredentialOptions = {
|
||||
rp, user, challenge: gCredentialChallenge, pubKeyCredParams: [param]
|
||||
};
|
||||
for (const mediation of ["conditional", "silent"]) {
|
||||
await credm.create({publicKey: makeCredentialOptions, mediation})
|
||||
.then(arrivingHereIsBad)
|
||||
.catch(expectNotSupportedError);
|
||||
}
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
</body>
|
||||
|
|
|
|||
|
|
@ -50,6 +50,7 @@ enum CredentialMediationRequirement {
|
|||
};
|
||||
|
||||
dictionary CredentialCreationOptions {
|
||||
CredentialMediationRequirement mediation = "optional";
|
||||
// This is taken from the partial definition in
|
||||
// https://w3c.github.io/webauthn/#sctn-credentialcreationoptions-extension
|
||||
[Pref="security.webauth.webauthn"]
|
||||
|
|
|
|||
27
icecat/dom/xml/crashtests/1192544.xhtml
Normal file
27
icecat/dom/xml/crashtests/1192544.xhtml
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
<!DOCTYPE html
|
||||
PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"
|
||||
[
|
||||
<!ENTITY bomb0 "bomb">
|
||||
<!ENTITY bomb1 "&bomb0;&bomb0;&bomb0;&bomb0;&bomb0;&bomb0;&bomb0;&bomb0;&bomb0;&bomb0;&bomb0;">
|
||||
<!ENTITY bomb2 "&bomb1;&bomb1;&bomb1;&bomb1;&bomb1;&bomb1;&bomb1;&bomb1;&bomb1;&bomb1;&bomb1;">
|
||||
<!ENTITY bomb3 "&bomb2;&bomb2;&bomb2;&bomb2;&bomb2;&bomb2;&bomb2;&bomb2;&bomb2;&bomb2;&bomb2;">
|
||||
<!ENTITY bomb4 "&bomb3;&bomb3;&bomb3;&bomb3;&bomb3;&bomb3;&bomb3;&bomb3;&bomb3;&bomb3;&bomb3;">
|
||||
<!ENTITY bomb5 "&bomb4;&bomb4;&bomb4;&bomb4;&bomb4;&bomb4;&bomb4;&bomb4;&bomb4;&bomb4;&bomb4;">
|
||||
<!ENTITY bomb6 "&bomb5;&bomb5;&bomb5;&bomb5;&bomb5;&bomb5;&bomb5;&bomb5;&bomb5;&bomb5;&bomb5;">
|
||||
<!ENTITY bomb7 "&bomb6;&bomb6;&bomb6;&bomb6;&bomb6;&bomb6;&bomb6;&bomb6;&bomb6;&bomb6;&bomb6;">
|
||||
<!ENTITY bomb8 "&bomb7;&bomb7;&bomb7;&bomb7;&bomb7;&bomb7;&bomb7;&bomb7;&bomb7;&bomb7;&bomb7;">
|
||||
<!ENTITY bomb9 "&bomb8;&bomb8;&bomb8;&bomb8;&bomb8;&bomb8;&bomb8;&bomb8;&bomb8;&bomb8;&bomb8;">
|
||||
<!ENTITY bomb10 "&bomb9;&bomb9;&bomb9;&bomb9;&bomb9;&bomb9;&bomb9;&bomb9;&bomb9;&bomb9;&bomb9;">]>
|
||||
<html>
|
||||
<body>
|
||||
<div someAttr="&bomb10;"></div>
|
||||
<div someAttr="&bomb10;"></div>
|
||||
<div someAttr="&bomb10;"></div>
|
||||
<div someAttr="&bomb10;"></div>
|
||||
<div someAttr="&bomb10;"></div>
|
||||
<div someAttr="&bomb10;"></div>
|
||||
<div someAttr="&bomb10;"></div>
|
||||
<div someAttr="&bomb10;"></div>
|
||||
<div someAttr="&bomb10;"></div>
|
||||
<div someAttr="&bomb10;"></div>
|
||||
<div someAttr="&bomb10;"></div>
|
||||
|
|
@ -10,5 +10,6 @@ load 453278.html
|
|||
load 803586.xhtml
|
||||
load 994740-1.xhtml
|
||||
load 1038887.xhtml
|
||||
load 1192544.xhtml
|
||||
load 1405878.xml
|
||||
load 1523655.xml
|
||||
|
|
|
|||
|
|
@ -2878,13 +2878,26 @@ void EditorBase::DispatchInputEvent() {
|
|||
return;
|
||||
}
|
||||
RefPtr<DataTransfer> dataTransfer = GetInputEventDataTransfer();
|
||||
const EditAction editAction = GetEditAction();
|
||||
if (editAction == EditAction::eCancelComposition ||
|
||||
editAction == EditAction::eCommitComposition) {
|
||||
MOZ_ASSERT(!mComposition);
|
||||
if (MOZ_UNLIKELY(!CanDispatchInputEventAfterCompositionEnd())) {
|
||||
MOZ_LOG(gEventLog, LogLevel::Info,
|
||||
("%p %s: Blocked to dispatch \"input\" event immediately after "
|
||||
"eCompositionEnd",
|
||||
this, mIsHTMLEditorClass ? "HTMLEditor" : "TextEditor"));
|
||||
return;
|
||||
}
|
||||
}
|
||||
const EditorInputType inputType = ToInputType(editAction);
|
||||
mEditActionData->WillDispatchInputEvent();
|
||||
MOZ_LOG(gEventLog, LogLevel::Info,
|
||||
("%p %s: Dispatching \"input\" event: { inputType=\"%s\" }...", this,
|
||||
mIsHTMLEditorClass ? "HTMLEditor" : "TextEditor",
|
||||
ToString(ToInputType(GetEditAction())).c_str()));
|
||||
ToString(inputType).c_str()));
|
||||
DebugOnly<nsresult> rvIgnored = nsContentUtils::DispatchInputEvent(
|
||||
targetElement, eEditorInput, ToInputType(GetEditAction()), this,
|
||||
targetElement, eEditorInput, inputType, this,
|
||||
dataTransfer ? InputEventOptions(dataTransfer,
|
||||
InputEventOptions::NeverCancelable::No)
|
||||
: InputEventOptions(GetInputEventData(),
|
||||
|
|
@ -2892,7 +2905,7 @@ void EditorBase::DispatchInputEvent() {
|
|||
MOZ_LOG(gEventLog, LogLevel::Debug,
|
||||
("%p %s: Dispatched \"input\" event: { inputType=\"%s\" }", this,
|
||||
mIsHTMLEditorClass ? "HTMLEditor" : "TextEditor",
|
||||
ToString(ToInputType(GetEditAction())).c_str()));
|
||||
ToString(inputType).c_str()));
|
||||
mEditActionData->DidDispatchInputEvent();
|
||||
NS_WARNING_ASSERTION(
|
||||
NS_SUCCEEDED(rvIgnored),
|
||||
|
|
@ -4215,8 +4228,10 @@ nsresult EditorBase::OnCompositionChange(
|
|||
// NOTE: When the pref is enabled, the last `input` event which will be fired
|
||||
// after `compositionend` won't be paired with corresponding `beforeinput`
|
||||
// event.
|
||||
else if (StaticPrefs::dom_input_events_dispatch_before_compositionend() &&
|
||||
mDispatchInputEvent && !IsEditActionAborted()) {
|
||||
else if (MOZ_LIKELY(
|
||||
StaticPrefs::dom_input_events_dispatch_before_compositionend() &&
|
||||
mDispatchInputEvent && !IsEditActionAborted() &&
|
||||
CanDispatchInputEventBeforeCompositionEnd())) {
|
||||
DispatchInputEvent();
|
||||
}
|
||||
|
||||
|
|
@ -4297,6 +4312,56 @@ void EditorBase::OnCompositionEnd(
|
|||
NotifyEditorObservers(eNotifyEditorObserversOfEnd);
|
||||
}
|
||||
|
||||
bool EditorBase::CanDispatchInputEventBeforeCompositionEnd() const {
|
||||
Document* const doc = GetDocument();
|
||||
if (NS_WARN_IF(!doc)) {
|
||||
return false;
|
||||
}
|
||||
nsIPrincipal* const principal = doc->GetPrincipalForPrefBasedHacks();
|
||||
if (!principal) {
|
||||
return true;
|
||||
}
|
||||
constexpr static auto* kTextEditorPref =
|
||||
"editor.texteditor.inputevent.hack.no_dispatch_before_compositionend";
|
||||
constexpr static auto* kTextEditorAddlPref =
|
||||
"editor.texteditor.inputevent.hack.no_dispatch_before_compositionend."
|
||||
"addl";
|
||||
constexpr static auto* kHTMLEditorPref =
|
||||
"editor.htmleditor.inputevent.hack.no_dispatch_before_compositionend";
|
||||
constexpr static auto* kHTMLEditorAddlPref =
|
||||
"editor.htmleditor.inputevent.hack.no_dispatch_before_compositionend."
|
||||
"addl";
|
||||
return !principal->IsURIInPrefList(IsTextEditor() ? kTextEditorPref
|
||||
: kHTMLEditorPref) &&
|
||||
!principal->IsURIInPrefList(IsTextEditor() ? kTextEditorAddlPref
|
||||
: kHTMLEditorAddlPref);
|
||||
}
|
||||
|
||||
bool EditorBase::CanDispatchInputEventAfterCompositionEnd() const {
|
||||
Document* const doc = GetDocument();
|
||||
if (NS_WARN_IF(!doc)) {
|
||||
return false;
|
||||
}
|
||||
nsIPrincipal* const principal = doc->GetPrincipalForPrefBasedHacks();
|
||||
if (!principal) {
|
||||
return true;
|
||||
}
|
||||
constexpr static auto* kTextEditorPref =
|
||||
"editor.texteditor.inputevent.hack.no_dispatch_after_compositionend";
|
||||
constexpr static auto* kTextEditorAddlPref =
|
||||
"editor.texteditor.inputevent.hack.no_dispatch_after_compositionend."
|
||||
"addl";
|
||||
constexpr static auto* kHTMLEditorPref =
|
||||
"editor.htmleditor.inputevent.hack.no_dispatch_after_compositionend";
|
||||
constexpr static auto* kHTMLEditorAddlPref =
|
||||
"editor.htmleditor.inputevent.hack.no_dispatch_after_compositionend."
|
||||
"addl";
|
||||
return !principal->IsURIInPrefList(IsTextEditor() ? kTextEditorPref
|
||||
: kHTMLEditorPref) &&
|
||||
!principal->IsURIInPrefList(IsTextEditor() ? kTextEditorAddlPref
|
||||
: kHTMLEditorAddlPref);
|
||||
}
|
||||
|
||||
bool EditorBase::WillHandleMouseButtonEvent(WidgetMouseEvent& aMouseEvent) {
|
||||
MOZ_ASSERT(aMouseEvent.mMessage == eMouseDown ||
|
||||
aMouseEvent.mMessage == eMouseUp);
|
||||
|
|
|
|||
|
|
@ -2514,6 +2514,18 @@ class EditorBase : public nsIEditor,
|
|||
*/
|
||||
MOZ_CAN_RUN_SCRIPT void DispatchInputEvent();
|
||||
|
||||
/**
|
||||
* Return true if it's NOT blocked by the pref to dispatch `input` event
|
||||
* immediately before `compositionend`.
|
||||
*/
|
||||
[[nodiscard]] bool CanDispatchInputEventBeforeCompositionEnd() const;
|
||||
|
||||
/**
|
||||
* Return true if it's NOT blocked by the pref to dispatch `input` event
|
||||
* immediately after `compositionend`.
|
||||
*/
|
||||
[[nodiscard]] bool CanDispatchInputEventAfterCompositionEnd() const;
|
||||
|
||||
/**
|
||||
* Called after a transaction is done successfully.
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -622,6 +622,8 @@ support-files = ["file_sanitizer_on_paste.sjs"]
|
|||
["test_select_all_without_body.html"]
|
||||
support-files = ["file_select_all_without_body.html"]
|
||||
|
||||
["test_selectable_input_event_dispatching_for_compositionend.html"]
|
||||
|
||||
["test_selection_move_commands.html"]
|
||||
support-files = ["!/gfx/layers/apz/test/mochitest/apz_test_utils.js"]
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,108 @@
|
|||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Test for block list of dispatching `input` event around `compositionend`</title>
|
||||
<script src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script src="/tests/SimpleTest/EventUtils.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css">
|
||||
<script>
|
||||
"use strict";
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
SimpleTest.waitForFocus(async () => {
|
||||
for (const pref of [
|
||||
"editor.texteditor.inputevent.hack.no_dispatch_before_compositionend",
|
||||
"editor.htmleditor.inputevent.hack.no_dispatch_before_compositionend",
|
||||
"editor.texteditor.inputevent.hack.no_dispatch_before_compositionend.addl",
|
||||
"editor.htmleditor.inputevent.hack.no_dispatch_before_compositionend.addl",
|
||||
"editor.texteditor.inputevent.hack.no_dispatch_after_compositionend",
|
||||
"editor.htmleditor.inputevent.hack.no_dispatch_after_compositionend",
|
||||
"editor.texteditor.inputevent.hack.no_dispatch_after_compositionend.addl",
|
||||
"editor.htmleditor.inputevent.hack.no_dispatch_after_compositionend.addl",
|
||||
]) {
|
||||
for (const selector of ["input", "textarea", "div[contenteditable]"]) {
|
||||
const element = document.querySelector(selector);
|
||||
const isTextEditor = !selector.includes("[contenteditable]");
|
||||
if (isTextEditor) {
|
||||
element.value = "";
|
||||
} else {
|
||||
element.innerHTML = "<br>";
|
||||
}
|
||||
element.focus();
|
||||
synthesizeCompositionChange({
|
||||
composition: {
|
||||
string: "abc",
|
||||
clauses: [
|
||||
{ length: 3, attr: COMPOSITION_ATTR_RAW_CLAUSE },
|
||||
]
|
||||
},
|
||||
caret: {
|
||||
start: 3,
|
||||
length: 0,
|
||||
}
|
||||
});
|
||||
const events = [];
|
||||
function recordEvent(aEvent) {
|
||||
events.push(aEvent);
|
||||
}
|
||||
element.addEventListener("compositionend", recordEvent);
|
||||
element.addEventListener("input", recordEvent);
|
||||
|
||||
await SpecialPowers.pushPrefEnv({
|
||||
set: [[pref, document.domain]],
|
||||
});
|
||||
synthesizeComposition({type: "compositioncommitasis"});
|
||||
await SpecialPowers.clearUserPref(pref);
|
||||
|
||||
element.removeEventListener("compositionend", recordEvent);
|
||||
element.removeEventListener("input", recordEvent);
|
||||
|
||||
const expectInputBeforeCompositionEnd =
|
||||
!pref.startsWith(
|
||||
`editor.${isTextEditor ? "texteditor" : "htmleditor"}.inputevent.hack.no_dispatch_before_compositionend`
|
||||
);
|
||||
const expectInputAfterCompositionEnd =
|
||||
!pref.startsWith(
|
||||
`editor.${isTextEditor ? "texteditor" : "htmleditor"}.inputevent.hack.no_dispatch_after_compositionend`
|
||||
);
|
||||
const expectedEvents = [];
|
||||
if (expectInputBeforeCompositionEnd) {
|
||||
expectedEvents.push({type: "input", inputType: "insertCompositionText", isComposing: true});
|
||||
}
|
||||
expectedEvents.push({type: "compositionend"});
|
||||
if (expectInputAfterCompositionEnd) {
|
||||
expectedEvents.push({type: "input", inputType: "insertCompositionText", isComposing: false});
|
||||
}
|
||||
function stringifyEvents(aEvents) {
|
||||
function stringifyEvent(aEvent) {
|
||||
return aEvent.type == "input"
|
||||
? `input(inputType=${aEvent.inputType},isComposing=${aEvent.isComposing})`
|
||||
: aEvent.type;
|
||||
}
|
||||
let ret = "[";
|
||||
for (const e of aEvents) {
|
||||
if (ret != "[") {
|
||||
ret += ","
|
||||
}
|
||||
ret += stringifyEvent(e);
|
||||
}
|
||||
return ret + "]";
|
||||
}
|
||||
is(
|
||||
stringifyEvents(events),
|
||||
stringifyEvents(expectedEvents),
|
||||
`Events should be dispatched as expected on ${selector} when ${pref} has current domain`
|
||||
);
|
||||
}
|
||||
}
|
||||
SimpleTest.finish();
|
||||
});
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<input>
|
||||
<textarea></textarea>
|
||||
<div contenteditable><br></div>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -263,6 +263,8 @@ nsAuthGSSAPI::nsAuthGSSAPI(pType package) : mServiceFlags(REQ_DEFAULT) {
|
|||
|
||||
LOG(("entering nsAuthGSSAPI::nsAuthGSSAPI()\n"));
|
||||
|
||||
mComplete = false;
|
||||
|
||||
if (!gssLibrary && NS_FAILED(gssInit())) return;
|
||||
|
||||
mCtx = GSS_C_NO_CONTEXT;
|
||||
|
|
@ -308,8 +310,6 @@ void nsAuthGSSAPI::Reset() {
|
|||
}
|
||||
mCtx = GSS_C_NO_CONTEXT;
|
||||
mComplete = false;
|
||||
mDelegationRequested = false;
|
||||
mDelegationSupported = false;
|
||||
}
|
||||
|
||||
/* static */
|
||||
|
|
@ -358,7 +358,6 @@ nsAuthGSSAPI::GetNextToken(const void* inToken, uint32_t inTokenLen,
|
|||
void** outToken, uint32_t* outTokenLen) {
|
||||
OM_uint32 major_status, minor_status;
|
||||
OM_uint32 req_flags = 0;
|
||||
OM_uint32 ret_flags = 0;
|
||||
gss_buffer_desc input_token = GSS_C_EMPTY_BUFFER;
|
||||
gss_buffer_desc output_token = GSS_C_EMPTY_BUFFER;
|
||||
gss_buffer_t in_token_ptr = GSS_C_NO_BUFFER;
|
||||
|
|
@ -373,22 +372,7 @@ nsAuthGSSAPI::GetNextToken(const void* inToken, uint32_t inTokenLen,
|
|||
// If they've called us again after we're complete, reset to start afresh.
|
||||
if (mComplete) Reset();
|
||||
|
||||
// Two-phase delegation logic
|
||||
// Phase 1: Try authentication without delegation first
|
||||
// Phase 2: Only retry with delegation if server supports it (ret_flags)
|
||||
bool delegationConfigured = (mServiceFlags & REQ_DELEGATE) != 0;
|
||||
|
||||
if (delegationConfigured) {
|
||||
if (!mDelegationRequested) {
|
||||
// First attempt: don't request delegation yet
|
||||
LOG(("First auth attempt without delegation"));
|
||||
mDelegationRequested = true;
|
||||
} else if (mDelegationSupported) {
|
||||
// Second attempt: server supports delegation, now request it
|
||||
LOG(("Retrying auth with delegation - server supports it"));
|
||||
req_flags |= GSS_C_DELEG_FLAG;
|
||||
}
|
||||
}
|
||||
if (mServiceFlags & REQ_DELEGATE) req_flags |= GSS_C_DELEG_FLAG;
|
||||
|
||||
if (mServiceFlags & REQ_MUTUAL_AUTH) req_flags |= GSS_C_MUTUAL_FLAG;
|
||||
|
||||
|
|
@ -442,7 +426,7 @@ nsAuthGSSAPI::GetNextToken(const void* inToken, uint32_t inTokenLen,
|
|||
major_status = gss_init_sec_context_ptr(
|
||||
&minor_status, GSS_C_NO_CREDENTIAL, &mCtx, server, mMechOID, req_flags,
|
||||
GSS_C_INDEFINITE, GSS_C_NO_CHANNEL_BINDINGS, in_token_ptr, nullptr,
|
||||
&output_token, &ret_flags, nullptr);
|
||||
&output_token, nullptr, nullptr);
|
||||
|
||||
if (GSS_ERROR(major_status)) {
|
||||
LogGssError(major_status, minor_status, "gss_init_sec_context() failed");
|
||||
|
|
@ -450,27 +434,6 @@ nsAuthGSSAPI::GetNextToken(const void* inToken, uint32_t inTokenLen,
|
|||
rv = NS_ERROR_FAILURE;
|
||||
goto end;
|
||||
}
|
||||
// Check if server supports delegation (OK-AS-DELEGATE equivalent)
|
||||
if (delegationConfigured && !mDelegationSupported &&
|
||||
(ret_flags & GSS_C_DELEG_FLAG)) {
|
||||
LOG(("Server supports delegation (GSS_C_DELEG_FLAG in ret_flags)"));
|
||||
|
||||
// If we completed without requesting delegation, but server supports it,
|
||||
// we need to restart with delegation
|
||||
if (major_status == GSS_S_COMPLETE && !(req_flags & GSS_C_DELEG_FLAG)) {
|
||||
LOG(("Restarting authentication to request delegation"));
|
||||
Reset();
|
||||
|
||||
// These flags get cleared by Reset().
|
||||
// Set them again to make sure the next call sets GSS_C_DELEG_FLAG
|
||||
mDelegationRequested = true;
|
||||
mDelegationSupported = true;
|
||||
|
||||
gss_release_name_ptr(&minor_status, &server);
|
||||
return GetNextToken(inToken, inTokenLen, outToken, outTokenLen);
|
||||
}
|
||||
}
|
||||
|
||||
if (major_status == GSS_S_COMPLETE) {
|
||||
// Mark ourselves as being complete, so that if we're called again
|
||||
// we know to start afresh.
|
||||
|
|
|
|||
|
|
@ -54,11 +54,9 @@ class nsAuthGSSAPI final : public nsIAuthModule {
|
|||
gss_ctx_id_t mCtx;
|
||||
gss_OID mMechOID;
|
||||
nsCString mServiceName;
|
||||
uint32_t mServiceFlags = REQ_DEFAULT;
|
||||
uint32_t mServiceFlags;
|
||||
nsString mUsername;
|
||||
bool mComplete = false;
|
||||
bool mDelegationRequested = false;
|
||||
bool mDelegationSupported = false;
|
||||
bool mComplete;
|
||||
};
|
||||
|
||||
#endif /* nsAuthGSSAPI_h__ */
|
||||
|
|
|
|||
|
|
@ -52,7 +52,18 @@ void convolve_vertically_avx2(
|
|||
};
|
||||
|
||||
int i = 0;
|
||||
for (; i < filterLen / 2 * 2; i += 2) {
|
||||
if (i < filterLen && (reinterpret_cast<uintptr_t>(filter) & 2) != 0) {
|
||||
// _mm256_set1_epi32 may generate instructions that require 4-byte align
|
||||
// for the memory load. ConvolutionFixed is 2 bytes, so a random offset
|
||||
// into the filter array might be only 2-byte aligned. Process the first
|
||||
// entry individually so that subsequent blocks will be 4-byte aligned.
|
||||
convolve_16_pixels(
|
||||
_mm256_set1_epi32(*(const int16_t*)(filter + i)),
|
||||
_mm256_loadu_si256((const __m256i*)(srcRows[i] + x * 4)),
|
||||
_mm256_setzero_si256());
|
||||
i++;
|
||||
}
|
||||
for (; i + 1 < filterLen; i += 2) {
|
||||
convolve_16_pixels(
|
||||
_mm256_set1_epi32(*(const int32_t*)(filter + i)),
|
||||
_mm256_loadu_si256((const __m256i*)(srcRows[i + 0] + x * 4)),
|
||||
|
|
|
|||
|
|
@ -1843,20 +1843,28 @@ mozilla::ipc::IPCResult WebRenderBridgeParent::RecvGetSnapshot(
|
|||
TimeStamp start = TimeStamp::Now();
|
||||
MOZ_ASSERT(bufferTexture->GetBufferDescriptor().type() ==
|
||||
BufferDescriptor::TRGBDescriptor);
|
||||
DebugOnly<uint32_t> stride = ImageDataSerializer::GetRGBStride(
|
||||
bufferTexture->GetBufferDescriptor().get_RGBDescriptor());
|
||||
if (bufferTexture->GetBufferDescriptor().type() !=
|
||||
BufferDescriptor::TRGBDescriptor) {
|
||||
return IPC_FAIL_NO_REASON(this);
|
||||
}
|
||||
|
||||
uint8_t* buffer = bufferTexture->GetBuffer();
|
||||
MOZ_ASSERT(buffer);
|
||||
if (!buffer) {
|
||||
return IPC_FAIL_NO_REASON(this);
|
||||
}
|
||||
|
||||
IntSize size = bufferTexture->GetSize();
|
||||
|
||||
MOZ_ASSERT(buffer);
|
||||
// For now the only formats we get here are RGBA and BGRA, and code below is
|
||||
// assuming a bpp of 4. If we allow other formats, the code needs adjusting
|
||||
// accordingly.
|
||||
MOZ_ASSERT(BytesPerPixel(bufferTexture->GetFormat()) == 4);
|
||||
uint32_t buffer_size = size.width * size.height * 4;
|
||||
if (BytesPerPixel(bufferTexture->GetFormat()) != 4) {
|
||||
return IPC_FAIL_NO_REASON(this);
|
||||
}
|
||||
|
||||
// Assert the stride of the buffer is what webrender expects
|
||||
MOZ_ASSERT((uint32_t)(size.width * 4) == stride);
|
||||
uint32_t buffer_size = size.width * size.height * 4;
|
||||
|
||||
FlushSceneBuilds();
|
||||
FlushFrameGeneration(wr::RenderReasons::SNAPSHOT);
|
||||
|
|
|
|||
|
|
@ -3542,6 +3542,14 @@ void gfxPlatform::ReInitFrameRate(const char* aPrefIgnored,
|
|||
gPlatform->mVsyncDispatcher->SetVsyncSource(vsyncSource);
|
||||
}
|
||||
|
||||
/* static */
|
||||
void gfxPlatform::ResetHardwareVsyncSource() {
|
||||
if (gPlatform->mGlobalHardwareVsyncSource) {
|
||||
gPlatform->mGlobalHardwareVsyncSource->Shutdown();
|
||||
gPlatform->mGlobalHardwareVsyncSource = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
const char* gfxPlatform::GetAzureCanvasBackend() const {
|
||||
BackendType backend{};
|
||||
|
||||
|
|
|
|||
|
|
@ -695,6 +695,12 @@ class gfxPlatform : public mozilla::layers::MemoryPressureListener {
|
|||
*/
|
||||
static void ReInitFrameRate(const char* aPrefIgnored, void* aDataIgnored);
|
||||
|
||||
/**
|
||||
* Reset the global hardware vsync source. The next call to ReInitFrameRate
|
||||
* will attempt to reestablish it, and fall back to software if needed.
|
||||
*/
|
||||
static void ResetHardwareVsyncSource();
|
||||
|
||||
/**
|
||||
* Update force subpixel AA quality setting (called after pref
|
||||
* changes).
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@
|
|||
#include "gfxQuartzSurface.h"
|
||||
#include "mozilla/DataMutex.h"
|
||||
#include "mozilla/gfx/2D.h"
|
||||
#include "mozilla/gfx/Logging.h"
|
||||
|
||||
#include "gfxMacFont.h"
|
||||
#include "gfxCoreTextShaper.h"
|
||||
|
|
@ -734,33 +735,48 @@ class OSXVsyncSource final : public VsyncSource {
|
|||
OSXVsyncSource() : mDisplayLink(nullptr, "OSXVsyncSource::mDisplayLink") {
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
mTimer = NS_NewTimer();
|
||||
CGDisplayRegisterReconfigurationCallback(DisplayReconfigurationCallback,
|
||||
this);
|
||||
CGError err = CGDisplayRegisterReconfigurationCallback(
|
||||
DisplayReconfigurationCallback, this);
|
||||
if (err != kCGErrorSuccess) {
|
||||
gfxWarning() << "Failed to register display reconfiguration callback";
|
||||
// We're in a tricky situation. Without a working reconfiguration
|
||||
// callback, we might fail to recover from sleep. Best to early exit
|
||||
// without creating a display link, and fall back to software vsync.
|
||||
return;
|
||||
}
|
||||
|
||||
CreateDisplayLink();
|
||||
auto displayLink = mDisplayLink.Lock();
|
||||
if (!*displayLink) {
|
||||
gfxWarning()
|
||||
<< "Could not create a display link during construction. This is "
|
||||
"unrecoverable. We'll fallback to software vsync.";
|
||||
}
|
||||
}
|
||||
|
||||
virtual ~OSXVsyncSource() {
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
CGDisplayRemoveReconfigurationCallback(DisplayReconfigurationCallback,
|
||||
this);
|
||||
DisableVsync();
|
||||
DestroyDisplayLink();
|
||||
Shutdown();
|
||||
}
|
||||
|
||||
static void RetryCreateDisplayLink(nsITimer* aTimer, void* aOsxVsyncSource) {
|
||||
static void RetryCreateDisplayLinkAndEnableVsync(nsITimer* aTimer,
|
||||
void* aOsxVsyncSource) {
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
OSXVsyncSource* osxVsyncSource =
|
||||
static_cast<OSXVsyncSource*>(aOsxVsyncSource);
|
||||
MOZ_ASSERT(osxVsyncSource);
|
||||
|
||||
osxVsyncSource->DisableVsync();
|
||||
osxVsyncSource->DestroyDisplayLink();
|
||||
osxVsyncSource->CreateDisplayLink();
|
||||
}
|
||||
|
||||
static void RetryEnableVsync(nsITimer* aTimer, void* aOsxVsyncSource) {
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
OSXVsyncSource* osxVsyncSource =
|
||||
static_cast<OSXVsyncSource*>(aOsxVsyncSource);
|
||||
MOZ_ASSERT(osxVsyncSource);
|
||||
osxVsyncSource->EnableVsync();
|
||||
|
||||
if (!osxVsyncSource->IsVsyncEnabled()) {
|
||||
gfxWarning() << "Display reconfiguration vsync has failed; giving up.";
|
||||
osxVsyncSource->Shutdown();
|
||||
gfxPlatform::ResetHardwareVsyncSource();
|
||||
gfxPlatform::ReInitFrameRate(nullptr, nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
void CreateDisplayLink() {
|
||||
|
|
@ -774,6 +790,11 @@ class OSXVsyncSource final : public VsyncSource {
|
|||
// with all displays running on the computer But if we have different
|
||||
// monitors at different display rates, we may hit issues.
|
||||
CVReturn retval = CVDisplayLinkCreateWithActiveCGDisplays(&*displayLink);
|
||||
if (!*displayLink) {
|
||||
gfxWarning()
|
||||
<< "Could not create a display link with all active displays.";
|
||||
return;
|
||||
}
|
||||
|
||||
// Workaround for bug 1201401: CVDisplayLinkCreateWithCGDisplays()
|
||||
// (called by CVDisplayLinkCreateWithActiveCGDisplays()) sometimes
|
||||
|
|
@ -789,37 +810,18 @@ class OSXVsyncSource final : public VsyncSource {
|
|||
retval = kCVReturnInvalidDisplay;
|
||||
}
|
||||
|
||||
if (!*displayLink || (retval != kCVReturnSuccess)) {
|
||||
NS_WARNING(
|
||||
"Could not create a display link with all active displays. "
|
||||
"Retrying");
|
||||
if (*displayLink) {
|
||||
CVDisplayLinkRelease(*displayLink);
|
||||
*displayLink = nullptr;
|
||||
}
|
||||
|
||||
// bug 1142708 - When coming back from sleep,
|
||||
// or when changing displays, active displays may not be ready yet,
|
||||
// even if listening for the kIOMessageSystemHasPoweredOn event
|
||||
// from OS X sleep notifications.
|
||||
// Active displays are those that are drawable.
|
||||
// bug 1144638 - When changing display configurations and getting
|
||||
// notifications from CGDisplayReconfigurationCallBack, the
|
||||
// callback gets called twice for each active display
|
||||
// so it's difficult to know when all displays are active.
|
||||
// Instead, try again soon. The delay is arbitrary. 100ms chosen
|
||||
// because on a late 2013 15" retina, it takes about that
|
||||
// long to come back up from sleep.
|
||||
uint32_t delay = 100;
|
||||
mTimer->InitWithNamedFuncCallback(RetryCreateDisplayLink, this, delay,
|
||||
nsITimer::TYPE_ONE_SHOT,
|
||||
"RetryCreateDisplayLink");
|
||||
if (retval != kCVReturnSuccess) {
|
||||
gfxWarning()
|
||||
<< "Display link was created, but is malformed; destroying it.";
|
||||
CVDisplayLinkRelease(*displayLink);
|
||||
*displayLink = nullptr;
|
||||
return;
|
||||
}
|
||||
|
||||
if (CVDisplayLinkSetOutputCallback(*displayLink, &VsyncCallback, this) !=
|
||||
kCVReturnSuccess) {
|
||||
NS_WARNING("Could not set displaylink output callback");
|
||||
gfxWarning()
|
||||
<< "Could not set display link output callback; destroying it.";
|
||||
CVDisplayLinkRelease(*displayLink);
|
||||
*displayLink = nullptr;
|
||||
}
|
||||
|
|
@ -842,20 +844,20 @@ class OSXVsyncSource final : public VsyncSource {
|
|||
|
||||
auto displayLink = mDisplayLink.Lock();
|
||||
if (!*displayLink) {
|
||||
NS_WARNING("No display link available when starting vsync");
|
||||
gfxWarning() << "No display link available when starting vsync.";
|
||||
return;
|
||||
}
|
||||
|
||||
mPreviousTimestamp = TimeStamp::Now();
|
||||
if (CVDisplayLinkStart(*displayLink) != kCVReturnSuccess) {
|
||||
NS_WARNING("Could not activate the display link");
|
||||
gfxWarning() << "Could not activate the display link.";
|
||||
return;
|
||||
}
|
||||
|
||||
CVTime vsyncRate =
|
||||
CVDisplayLinkGetNominalOutputVideoRefreshPeriod(*displayLink);
|
||||
if (vsyncRate.flags & kCVTimeIsIndefinite) {
|
||||
NS_WARNING("Could not get vsync rate, setting to 60.");
|
||||
gfxWarning() << "Could not get vsync rate, setting to 60.";
|
||||
mVsyncRate = TimeDuration::FromMilliseconds(1000.0 / 60.0);
|
||||
} else {
|
||||
int64_t timeValue = vsyncRate.timeValue;
|
||||
|
|
@ -892,8 +894,12 @@ class OSXVsyncSource final : public VsyncSource {
|
|||
|
||||
void Shutdown() override {
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
mTimer->Cancel();
|
||||
mTimer = nullptr;
|
||||
if (mTimer) {
|
||||
mTimer->Cancel();
|
||||
mTimer = nullptr;
|
||||
}
|
||||
CGDisplayRemoveReconfigurationCallback(DisplayReconfigurationCallback,
|
||||
this);
|
||||
DisableVsync();
|
||||
DestroyDisplayLink();
|
||||
}
|
||||
|
|
@ -950,10 +956,12 @@ class OSXVsyncSource final : public VsyncSource {
|
|||
// Check if we actually succeeded in enabling vsync, and if we didn't,
|
||||
// retry one time.
|
||||
if (!IsVsyncEnabled()) {
|
||||
gfxWarning()
|
||||
<< "Display reconfiguration vsync has failed; retrying one time.";
|
||||
uint32_t delay = 100;
|
||||
mTimer->InitWithNamedFuncCallback(RetryCreateDisplayLink, this, delay,
|
||||
nsITimer::TYPE_ONE_SHOT,
|
||||
"RetryEnableVsync");
|
||||
mTimer->InitWithNamedFuncCallback(
|
||||
RetryCreateDisplayLinkAndEnableVsync, this, delay,
|
||||
nsITimer::TYPE_ONE_SHOT, "RetryCreateDisplayLinkAndEnableVsync");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1007,8 +1015,8 @@ gfxPlatformMac::CreateGlobalHardwareVsyncSource() {
|
|||
RefPtr<VsyncSource> osxVsyncSource = new OSXVsyncSource();
|
||||
osxVsyncSource->EnableVsync();
|
||||
if (!osxVsyncSource->IsVsyncEnabled()) {
|
||||
NS_WARNING(
|
||||
"OS X Vsync source not enabled. Falling back to software vsync.");
|
||||
gfxWarning()
|
||||
<< "OS X Vsync source not enabled. Falling back to software vsync.";
|
||||
return GetSoftwareVsyncSource();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -96,6 +96,11 @@ ConvertYCbCrToRGB32(const uint8_t* y_buf,
|
|||
YUVColorSpace yuv_color_space,
|
||||
ColorRange color_range,
|
||||
RGB32Type rgb32_type) {
|
||||
if (pic_x < 0 || pic_y < 0 || y_pitch < 0 || uv_pitch < 0 || rgb_pitch < 0) {
|
||||
NS_WARNING("Negative origin or pitch is unsupported");
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
// Deprecated function's conversion is accurate.
|
||||
// libyuv converion is a bit inaccurate to get performance. It dynamically
|
||||
// calculates RGB from YUV to use simd. In it, signed byte is used for
|
||||
|
|
|
|||
|
|
@ -206,7 +206,11 @@ nsresult SourceBuffer::Compact() {
|
|||
if (capacity == MAX_CHUNK_CAPACITY) {
|
||||
size_t lastLength = mChunks.LastElement().Length();
|
||||
if (lastLength != capacity) {
|
||||
mChunks.LastElement().SetCapacity(lastLength);
|
||||
if (lastLength == 0) {
|
||||
mChunks.RemoveLastElement();
|
||||
} else {
|
||||
mChunks.LastElement().SetCapacity(lastLength);
|
||||
}
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -419,6 +419,10 @@ class SourceBuffer final {
|
|||
|
||||
bool SetCapacity(size_t aCapacity) {
|
||||
MOZ_ASSERT(mData, "Allocation failed but nobody checked for it");
|
||||
MOZ_ASSERT(aCapacity > 0, "zero sized resize");
|
||||
if (aCapacity == 0) {
|
||||
return false;
|
||||
}
|
||||
char* data = static_cast<char*>(realloc(mData, aCapacity));
|
||||
if (!data) {
|
||||
return false;
|
||||
|
|
|
|||
|
|
@ -139,13 +139,19 @@ Orientation GetImageOrientation(const Mp4parseAvifInfo& aInfo) {
|
|||
}
|
||||
bool AVIFDecoderStream::ReadAt(int64_t offset, void* data, size_t size,
|
||||
size_t* bytes_read) {
|
||||
size = std::min(size, size_t(mBuffer->length() - offset));
|
||||
|
||||
if (size <= 0) {
|
||||
CheckedInt<size_t> checkedOffset(offset);
|
||||
if (!checkedOffset.isValid() || offset < 0 ||
|
||||
checkedOffset.value() >= mBuffer->length()) {
|
||||
return false;
|
||||
}
|
||||
CheckedInt<size_t> endPoint = checkedOffset + size;
|
||||
if (!endPoint.isValid() || endPoint.value() > mBuffer->length()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
memcpy(data, mBuffer->begin() + offset, size);
|
||||
size = std::min<size_t>(size, mBuffer->length() - checkedOffset.value());
|
||||
|
||||
memcpy(data, mBuffer->begin() + checkedOffset.value(), size);
|
||||
*bytes_read = size;
|
||||
return true;
|
||||
}
|
||||
|
|
@ -158,11 +164,14 @@ bool AVIFDecoderStream::Length(int64_t* size) {
|
|||
|
||||
const uint8_t* AVIFDecoderStream::GetContiguousAccess(int64_t aOffset,
|
||||
size_t aSize) {
|
||||
if (aOffset + aSize >= mBuffer->length()) {
|
||||
CheckedInt<size_t> checkedOffset(aOffset);
|
||||
CheckedInt<size_t> endPoint = checkedOffset + aSize;
|
||||
if (!checkedOffset.isValid() || !endPoint.isValid() ||
|
||||
endPoint.value() > mBuffer->length()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return mBuffer->begin() + aOffset;
|
||||
return mBuffer->begin() + checkedOffset.value();
|
||||
}
|
||||
|
||||
AVIFParser::~AVIFParser() {
|
||||
|
|
|
|||
|
|
@ -21,8 +21,8 @@
|
|||
|
||||
namespace js {
|
||||
namespace gc {
|
||||
JS_PUBLIC_API void TraceRealm(JSTracer* trc, JS::Realm* realm,
|
||||
const char* name);
|
||||
JS_PUBLIC_API void TraceRealmRoot(JSTracer* trc, JS::Realm* realm,
|
||||
const char* name);
|
||||
} // namespace gc
|
||||
} // namespace js
|
||||
|
||||
|
|
@ -34,7 +34,7 @@ template <>
|
|||
struct GCPolicy<Realm*> : public NonGCPointerPolicy<Realm*> {
|
||||
static void trace(JSTracer* trc, Realm** vp, const char* name) {
|
||||
if (*vp) {
|
||||
::js::gc::TraceRealm(trc, *vp, name);
|
||||
::js::gc::TraceRealmRoot(trc, *vp, name);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -36,6 +36,7 @@
|
|||
|
||||
#include "vm/Compartment-inl.h"
|
||||
#include "vm/JSObject-inl.h"
|
||||
#include "vm/Realm-inl.h"
|
||||
|
||||
using namespace js;
|
||||
|
||||
|
|
@ -1451,6 +1452,7 @@ bool js::atomics_notify_impl(JSContext* cx, SharedArrayRawBuffer* sarb,
|
|||
// avoid mutex ordering problems.
|
||||
RootedValue resultMsg(cx, StringValue(cx->names().ok));
|
||||
for (uint32_t i = 0; i < promisesToResolve.length(); i++) {
|
||||
AutoRealm ar(cx, promisesToResolve[i]);
|
||||
if (!PromiseObject::resolve(cx, promisesToResolve[i], resultMsg)) {
|
||||
MOZ_ASSERT(cx->isThrowingOutOfMemory() || cx->isThrowingOverRecursed());
|
||||
return false;
|
||||
|
|
|
|||
|
|
@ -913,8 +913,9 @@ bool ModuleObject::isInstance(HandleValue value) {
|
|||
}
|
||||
|
||||
bool ModuleObject::hasCyclicModuleFields() const {
|
||||
// This currently only returns false if we GC during initialization.
|
||||
return !getReservedSlot(CyclicModuleFieldsSlot).isUndefined();
|
||||
bool result = !getReservedSlot(CyclicModuleFieldsSlot).isUndefined();
|
||||
MOZ_ASSERT_IF(result, !hasSyntheticModuleFields());
|
||||
return result;
|
||||
}
|
||||
|
||||
CyclicModuleFields* ModuleObject::cyclicModuleFields() {
|
||||
|
|
@ -1496,7 +1497,9 @@ bool ModuleObject::createSyntheticEnvironment(JSContext* cx,
|
|||
return false;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(env->shape()->propMapLength() == values.length());
|
||||
// We expect one property per synthetic value plus one for the *namespace*
|
||||
// binding.
|
||||
MOZ_ASSERT(env->shape()->propMapLength() == values.length() + 1);
|
||||
|
||||
for (uint32_t i = 0; i < values.length(); i++) {
|
||||
env->setAliasedBinding(env->firstSyntheticValueSlot() + i, values[i]);
|
||||
|
|
|
|||
|
|
@ -1058,7 +1058,7 @@ static constexpr auto AsciiRegExpEscapeMap() {
|
|||
*/
|
||||
template <typename CharT>
|
||||
[[nodiscard]] static bool EncodeForRegExpEscape(
|
||||
mozilla::Span<const CharT> chars, JSStringBuilder& sb) {
|
||||
JSContext* cx, mozilla::Span<const CharT> chars, JSStringBuilder& sb) {
|
||||
MOZ_ASSERT(sb.empty());
|
||||
|
||||
const size_t length = chars.size();
|
||||
|
|
@ -1075,7 +1075,7 @@ template <typename CharT>
|
|||
|
||||
// Initial scan to determine if escape sequences are needed and to compute
|
||||
// the output length.
|
||||
size_t outLength = length;
|
||||
mozilla::CheckedInt<size_t> outLength = length;
|
||||
|
||||
// Leading Ascii alpha-numeric character is hex-escaped.
|
||||
size_t scanStart = 0;
|
||||
|
|
@ -1115,12 +1115,16 @@ template <typename CharT>
|
|||
outLength += UnicodeEscapeAddLength;
|
||||
}
|
||||
}
|
||||
if (!outLength.isValid()) {
|
||||
ReportAllocationOverflow(cx);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Return if no escape sequences are needed.
|
||||
if (outLength == length) {
|
||||
if (outLength.value() == length) {
|
||||
return true;
|
||||
}
|
||||
MOZ_ASSERT(outLength > length);
|
||||
MOZ_ASSERT(outLength.value() > length);
|
||||
|
||||
// Inflating is fallible, so we have to convert to two-byte upfront.
|
||||
if constexpr (std::is_same_v<CharT, char16_t>) {
|
||||
|
|
@ -1130,7 +1134,7 @@ template <typename CharT>
|
|||
}
|
||||
|
||||
// Allocate memory for the output using the final length.
|
||||
if (!sb.reserve(outLength)) {
|
||||
if (!sb.reserve(outLength.value())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -1230,19 +1234,20 @@ template <typename CharT>
|
|||
appendUnescaped(length);
|
||||
}
|
||||
|
||||
MOZ_ASSERT(sb.length() == outLength, "all characters were written");
|
||||
MOZ_ASSERT(sb.length() == outLength.value(), "all characters were written");
|
||||
return true;
|
||||
}
|
||||
|
||||
[[nodiscard]] static bool EncodeForRegExpEscape(JSLinearString* string,
|
||||
[[nodiscard]] static bool EncodeForRegExpEscape(JSContext* cx,
|
||||
JSLinearString* string,
|
||||
JSStringBuilder& sb) {
|
||||
JS::AutoCheckCannotGC nogc;
|
||||
if (string->hasLatin1Chars()) {
|
||||
auto chars = mozilla::Span(string->latin1Range(nogc));
|
||||
return EncodeForRegExpEscape(chars, sb);
|
||||
return EncodeForRegExpEscape(cx, chars, sb);
|
||||
}
|
||||
auto chars = mozilla::Span(string->twoByteRange(nogc));
|
||||
return EncodeForRegExpEscape(chars, sb);
|
||||
return EncodeForRegExpEscape(cx, chars, sb);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -1266,7 +1271,7 @@ static bool regexp_escape(JSContext* cx, unsigned argc, Value* vp) {
|
|||
|
||||
// Step 2-5.
|
||||
JSStringBuilder sb(cx);
|
||||
if (!EncodeForRegExpEscape(string, sb)) {
|
||||
if (!EncodeForRegExpEscape(cx, string, sb)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -6180,6 +6180,14 @@ static bool Deserialize(JSContext* cx, unsigned argc, Value* vp) {
|
|||
}
|
||||
}
|
||||
|
||||
if (scope > JS::StructuredCloneScope::SameProcess &&
|
||||
(policy.areIntraClusterClonableSharedObjectsAllowed() ||
|
||||
policy.areSharedMemoryObjectsAllowed())) {
|
||||
JS_ReportErrorASCII(
|
||||
cx, "deserialize in DifferentProcess scope cannot allow shared memory");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Clone buffer was already consumed?
|
||||
if (!obj->data()) {
|
||||
JS_ReportErrorASCII(cx,
|
||||
|
|
|
|||
|
|
@ -24,3 +24,47 @@ assertEq(ex.toString(),
|
|||
`TypeError: The SharedArrayBuffer object cannot be serialized. The ` +
|
||||
`Cross-Origin-Opener-Policy and Cross-Origin-Embedder-Policy HTTP ` +
|
||||
`headers can be used to enable this.`);
|
||||
|
||||
try {
|
||||
const s = serialize([sab], undefined, { scope: "DifferentProcess", SharedArrayBuffer: "allow" });
|
||||
deserialize(s, { scope: "DifferentProcess" });
|
||||
assertEq("threw exception?", true);
|
||||
} catch (e) {
|
||||
ex = e;
|
||||
}
|
||||
assertEq(ex.toString().includes("Policy object must forbid cloning shared memory objects cross-process"), true);
|
||||
|
||||
// Can't deserialize a SameProcess buffer when only allowing DifferentProcess scope.
|
||||
try {
|
||||
const s = serialize([sab], undefined, { SharedArrayBuffer: "allow" });
|
||||
deserialize(s, { scope: "DifferentProcess" });
|
||||
assertEq("threw exception?", true);
|
||||
} catch (e) {
|
||||
ex = e;
|
||||
}
|
||||
assertEq(ex.toString().includes("incompatible structured clone scope"), true);
|
||||
|
||||
// If a buffer is tampered with, it can only be deserialized as DifferentProcess.
|
||||
try {
|
||||
const s = serialize([sab], undefined, { SharedArrayBuffer: "allow" });
|
||||
const s2 = serialize([sab], undefined, { SharedArrayBuffer: "allow" });
|
||||
const ta = new Uint32Array(s.arraybuffer);
|
||||
ta[2] = 2; // DifferentProcess
|
||||
// synthetic buffer! Forces scope to DifferentProcess despite what we say below.
|
||||
s2.clonebuffer = ta.buffer;
|
||||
const result = deserialize(s2, { SharedArrayBuffer: "allow", scope: "SameProcess" });
|
||||
assertEq("threw exception?", true);
|
||||
} catch (e) {
|
||||
ex = e;
|
||||
}
|
||||
assertEq(ex.toString().includes("Cannot use less restrictive scope"), true);
|
||||
|
||||
// You can't deserialize with both scope=DifferentProcess and allowing shared memory.
|
||||
try {
|
||||
const s = serialize([sab], undefined, { SharedArrayBuffer: "allow" });
|
||||
const result = deserialize(s, { SharedArrayBuffer: "allow", scope: "DifferentProcess" });
|
||||
assertEq("threw exception?", true);
|
||||
} catch (e) {
|
||||
ex = e;
|
||||
}
|
||||
assertEq(ex.toString().includes("deserialize in DifferentProcess scope cannot allow shared memory"), true);
|
||||
|
|
|
|||
|
|
@ -42,7 +42,7 @@ for ( let memtype of memtypes ) {
|
|||
|
||||
// Serialization and deserialization of shared memories work:
|
||||
|
||||
let mem2 = deserialize(serialize(mem1, [], {SharedArrayBuffer: 'allow'}), {SharedArrayBuffer: 'allow'});
|
||||
let mem2 = deserialize(serialize(mem1, [], {SharedArrayBuffer: 'allow'}), {SharedArrayBuffer: 'allow', scope: 'SameProcess'});
|
||||
assertEq(mem2 instanceof WebAssembly.Memory, true);
|
||||
let buf2 = mem2.buffer;
|
||||
assertEq(buf2 instanceof SharedArrayBuffer, true);
|
||||
|
|
@ -102,6 +102,6 @@ for ( let memtype of memtypes ) {
|
|||
let buf = mem.buffer;
|
||||
let clonedbuf = serialize(buf, [], {SharedArrayBuffer: 'allow'});
|
||||
mem.grow(Idx(memtype, 1));
|
||||
let buf2 = deserialize(clonedbuf, {SharedArrayBuffer: 'allow'});
|
||||
let buf2 = deserialize(clonedbuf, {SharedArrayBuffer: 'allow', scope: 'SameProcess'});
|
||||
assertEq(buf.byteLength, buf2.byteLength);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2980,14 +2980,23 @@ void BaselineCacheIRCompiler::pushArguments(Register argcReg,
|
|||
Register scratch, Register scratch2,
|
||||
CallFlags flags, uint32_t argcFixed,
|
||||
bool isJitCall) {
|
||||
bool isConstructing = flags.isConstructing();
|
||||
|
||||
// Push the formal arguments, and possibly `this` and/or `callee`.
|
||||
// There are three cases:
|
||||
// 1. Non-scripted call: all arguments are pushed here.
|
||||
// 2. Scripted call: all arguments except `callee` are pushed here. `callee`
|
||||
// must be passed as a CalleeToken, and is pushed below.
|
||||
// 3. Scripted constructor: only formal arguments are pushed here. We must
|
||||
// push a new `this` value using createThis, and then push `callee` as
|
||||
// a CalleeToken. Note that constructors must be Standard or Spread.
|
||||
switch (flags.getArgFormat()) {
|
||||
case CallFlags::Standard:
|
||||
pushStandardArguments(argcReg, scratch, scratch2, argcFixed, isJitCall,
|
||||
flags.isConstructing());
|
||||
isConstructing);
|
||||
break;
|
||||
case CallFlags::Spread:
|
||||
pushArrayArguments(argcReg, scratch, scratch2, isJitCall,
|
||||
flags.isConstructing());
|
||||
pushArrayArguments(argcReg, scratch, scratch2, isJitCall, isConstructing);
|
||||
break;
|
||||
case CallFlags::FunCall:
|
||||
pushFunCallArguments(argcReg, calleeReg, scratch, scratch2, argcFixed,
|
||||
|
|
@ -3006,6 +3015,16 @@ void BaselineCacheIRCompiler::pushArguments(Register argcReg,
|
|||
default:
|
||||
MOZ_CRASH("Invalid arg format");
|
||||
}
|
||||
|
||||
if (isJitCall) {
|
||||
if (isConstructing) {
|
||||
createThis(argcReg, calleeReg, scratch, scratch2, flags);
|
||||
}
|
||||
|
||||
// Note that we use Push, not push, so that callJit will align the stack
|
||||
// properly on ARM.
|
||||
masm.PushCalleeToken(calleeReg, isConstructing);
|
||||
}
|
||||
}
|
||||
|
||||
void BaselineCacheIRCompiler::pushStandardArguments(
|
||||
|
|
@ -3013,11 +3032,16 @@ void BaselineCacheIRCompiler::pushStandardArguments(
|
|||
bool isJitCall, bool isConstructing) {
|
||||
MOZ_ASSERT(enteredStubFrame_);
|
||||
|
||||
// The arguments to the call IC are pushed on the stack left-to-right.
|
||||
// Our calling conventions want them right-to-left in the callee, so
|
||||
// we duplicate them on the stack in reverse order.
|
||||
// The arguments to the call IC were pushed on the stack from left to right,
|
||||
// meaning that the first argument is at the highest address and the last
|
||||
// argument is at the lowest address. Our callee needs them to be in the
|
||||
// opposite order, so we duplicate them now.
|
||||
|
||||
bool shouldCopyCallee = !isJitCall;
|
||||
bool shouldCopyThis = shouldCopyCallee || !isConstructing;
|
||||
bool shouldCopyNewTarget = isConstructing;
|
||||
int additionalArgc = shouldCopyCallee + shouldCopyThis + shouldCopyNewTarget;
|
||||
|
||||
int additionalArgc = 1 + !isJitCall + isConstructing;
|
||||
if (argcFixed < MaxUnrolledArgCopy) {
|
||||
#ifdef DEBUG
|
||||
Label ok;
|
||||
|
|
@ -3029,7 +3053,8 @@ void BaselineCacheIRCompiler::pushStandardArguments(
|
|||
size_t realArgc = argcFixed + additionalArgc;
|
||||
|
||||
if (isJitCall) {
|
||||
masm.alignJitStackBasedOnNArgs(realArgc, /*countIncludesThis = */ true);
|
||||
masm.alignJitStackBasedOnNArgs(realArgc,
|
||||
/*countIncludesThis = */ shouldCopyThis);
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < realArgc; ++i) {
|
||||
|
|
@ -3057,7 +3082,8 @@ void BaselineCacheIRCompiler::pushStandardArguments(
|
|||
// Align the stack such that the JitFrameLayout is aligned on the
|
||||
// JitStackAlignment.
|
||||
if (isJitCall) {
|
||||
masm.alignJitStackBasedOnNArgs(countReg, /*countIncludesThis = */ true);
|
||||
masm.alignJitStackBasedOnNArgs(countReg,
|
||||
/*countIncludesThis = */ shouldCopyThis);
|
||||
}
|
||||
|
||||
// Push all values, starting at the last one.
|
||||
|
|
@ -3120,15 +3146,15 @@ void BaselineCacheIRCompiler::pushArrayArguments(Register argcReg,
|
|||
masm.jump(©Start);
|
||||
masm.bind(©Done);
|
||||
|
||||
// Push |this|.
|
||||
size_t thisvOffset =
|
||||
BaselineStubFrameLayout::Size() + (1 + isConstructing) * sizeof(Value);
|
||||
masm.pushValue(Address(FramePointer, thisvOffset));
|
||||
bool shouldPushCallee = !isJitCall;
|
||||
bool shouldPushThis = shouldPushCallee || !isConstructing;
|
||||
|
||||
// Push |callee| if needed.
|
||||
if (!isJitCall) {
|
||||
size_t calleeOffset =
|
||||
BaselineStubFrameLayout::Size() + (2 + isConstructing) * sizeof(Value);
|
||||
if (shouldPushThis) {
|
||||
size_t thisvOffset = arrayOffset + sizeof(Value);
|
||||
masm.pushValue(Address(FramePointer, thisvOffset));
|
||||
}
|
||||
if (shouldPushCallee) {
|
||||
size_t calleeOffset = arrayOffset + 2 * sizeof(Value);
|
||||
masm.pushValue(Address(FramePointer, calleeOffset));
|
||||
}
|
||||
}
|
||||
|
|
@ -3355,14 +3381,7 @@ void BaselineCacheIRCompiler::pushBoundFunctionArguments(
|
|||
}
|
||||
}
|
||||
|
||||
if (isConstructing) {
|
||||
// Push the |this| Value. This is either the object we allocated or the
|
||||
// JS_UNINITIALIZED_LEXICAL magic value. It's stored in the BaselineFrame,
|
||||
// so skip past the stub frame, (unbound) arguments and newTarget.
|
||||
BaseValueIndex thisAddress(FramePointer, argcReg,
|
||||
BaselineStubFrameLayout::Size() + sizeof(Value));
|
||||
masm.pushValue(thisAddress, scratch);
|
||||
} else {
|
||||
if (!isConstructing) {
|
||||
// Push the bound |this|.
|
||||
Address boundThis(calleeReg, BoundFunctionObject::offsetOfBoundThisSlot());
|
||||
masm.pushValue(boundThis);
|
||||
|
|
@ -3578,15 +3597,16 @@ bool BaselineCacheIRCompiler::emitCallClassHook(ObjOperandId calleeId,
|
|||
// and unboxes an object from a specific slot.
|
||||
void BaselineCacheIRCompiler::loadStackObject(ArgumentKind kind,
|
||||
CallFlags flags, Register argcReg,
|
||||
Register dest) {
|
||||
Register dest,
|
||||
uint32_t extraArgs) {
|
||||
MOZ_ASSERT(enteredStubFrame_);
|
||||
|
||||
bool addArgc = false;
|
||||
int32_t slotIndex = GetIndexOfArgument(kind, flags, &addArgc);
|
||||
|
||||
if (addArgc) {
|
||||
int32_t slotOffset =
|
||||
slotIndex * sizeof(JS::Value) + BaselineStubFrameLayout::Size();
|
||||
int32_t slotOffset = (slotIndex - extraArgs) * sizeof(JS::Value) +
|
||||
BaselineStubFrameLayout::Size();
|
||||
BaseValueIndex slotAddr(FramePointer, argcReg, slotOffset);
|
||||
masm.unboxObject(slotAddr, dest);
|
||||
} else {
|
||||
|
|
@ -3597,50 +3617,33 @@ void BaselineCacheIRCompiler::loadStackObject(ArgumentKind kind,
|
|||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void BaselineCacheIRCompiler::storeThis(const T& newThis, Register argcReg,
|
||||
CallFlags flags) {
|
||||
switch (flags.getArgFormat()) {
|
||||
case CallFlags::Standard: {
|
||||
BaseValueIndex thisAddress(
|
||||
FramePointer,
|
||||
argcReg, // Arguments
|
||||
1 * sizeof(Value) + // NewTarget
|
||||
BaselineStubFrameLayout::Size()); // Stub frame
|
||||
masm.storeValue(newThis, thisAddress);
|
||||
} break;
|
||||
case CallFlags::Spread: {
|
||||
Address thisAddress(FramePointer,
|
||||
2 * sizeof(Value) + // Arg array, NewTarget
|
||||
BaselineStubFrameLayout::Size()); // Stub frame
|
||||
masm.storeValue(newThis, thisAddress);
|
||||
} break;
|
||||
default:
|
||||
MOZ_CRASH("Invalid arg format for scripted constructor");
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Scripted constructors require a |this| object to be created prior to the
|
||||
* call. When this function is called, the stack looks like (bottom->top):
|
||||
*
|
||||
* [..., Callee, ThisV, Arg0V, ..., ArgNV, NewTarget, StubFrameHeader]
|
||||
*
|
||||
* At this point, |ThisV| is JSWhyMagic::JS_IS_CONSTRUCTING.
|
||||
*
|
||||
* This function calls CreateThis to generate a new |this| object, then
|
||||
* overwrites the magic ThisV on the stack.
|
||||
* call. This is called after we have pushed the formal arguments, but before
|
||||
* pushing the callee token. When this is called, argcReg must contain the
|
||||
* number of actual arguments (including bound or spread arguments; not
|
||||
* including `undef` pushed in cases of argument underflow). calleeReg should
|
||||
* contain the actual callee.
|
||||
*/
|
||||
void BaselineCacheIRCompiler::createThis(Register argcReg, Register calleeReg,
|
||||
Register scratch, CallFlags flags,
|
||||
bool isBoundFunction) {
|
||||
Register scratch, Register scratch2,
|
||||
CallFlags flags,
|
||||
Maybe<uint32_t> numBoundArgs) {
|
||||
MOZ_ASSERT(flags.isConstructing());
|
||||
bool isBoundFunction = numBoundArgs.isSome();
|
||||
|
||||
// Derived constructors don't allocate a `this` object. They instead call
|
||||
// `super`, and the base class constructor will allocate `this`.
|
||||
if (flags.needsUninitializedThis()) {
|
||||
storeThis(MagicValue(JS_UNINITIALIZED_LEXICAL), argcReg, flags);
|
||||
masm.Push(MagicValue(JS_UNINITIALIZED_LEXICAL));
|
||||
return;
|
||||
}
|
||||
|
||||
// Save a reference to the start of the arguments, so that we can root
|
||||
// them in CreateThisFromIC.
|
||||
Register argvReg = scratch2;
|
||||
masm.moveStackPtrTo(argvReg);
|
||||
|
||||
// Save live registers that don't have to be traced.
|
||||
LiveGeneralRegisterSet liveNonGCRegs;
|
||||
liveNonGCRegs.add(argcReg);
|
||||
|
|
@ -3648,25 +3651,27 @@ void BaselineCacheIRCompiler::createThis(Register argcReg, Register calleeReg,
|
|||
|
||||
// CreateThis takes two arguments: callee, and newTarget.
|
||||
|
||||
// Push argv/argc for rooting in CreateThisFromIC
|
||||
masm.push(argcReg);
|
||||
masm.push(argvReg);
|
||||
|
||||
if (isBoundFunction) {
|
||||
// Push the bound function's target as callee and newTarget.
|
||||
Address boundTarget(calleeReg, BoundFunctionObject::offsetOfTargetSlot());
|
||||
masm.unboxObject(boundTarget, scratch);
|
||||
masm.push(scratch);
|
||||
masm.push(scratch);
|
||||
masm.push(calleeReg);
|
||||
masm.push(calleeReg);
|
||||
} else {
|
||||
// Push newTarget:
|
||||
loadStackObject(ArgumentKind::NewTarget, flags, argcReg, scratch);
|
||||
masm.push(scratch);
|
||||
|
||||
// Push callee:
|
||||
loadStackObject(ArgumentKind::Callee, flags, argcReg, scratch);
|
||||
masm.push(scratch);
|
||||
// Push callee.
|
||||
masm.push(calleeReg);
|
||||
}
|
||||
|
||||
// Call CreateThisFromIC.
|
||||
using Fn =
|
||||
bool (*)(JSContext*, HandleObject, HandleObject, MutableHandleValue);
|
||||
bool (*)(JSContext*, HandleObject, HandleObject, Value*, uint32_t,
|
||||
MutableHandleValue);
|
||||
callVM<Fn, CreateThisFromIC>(masm);
|
||||
|
||||
#ifdef DEBUG
|
||||
|
|
@ -3686,14 +3691,29 @@ void BaselineCacheIRCompiler::createThis(Register argcReg, Register calleeReg,
|
|||
Address stubAddr(FramePointer, BaselineStubFrameLayout::ICStubOffsetFromFP);
|
||||
masm.loadPtr(stubAddr, ICStubReg);
|
||||
|
||||
// Save |this| value back into pushed arguments on stack.
|
||||
// Push |this|.
|
||||
MOZ_ASSERT(!liveNonGCRegs.aliases(JSReturnOperand));
|
||||
storeThis(JSReturnOperand, argcReg, flags);
|
||||
masm.Push(TypedOrValueRegister(JSReturnOperand));
|
||||
|
||||
// Restore calleeReg. CreateThisFromIC may trigger a GC, so we reload the
|
||||
// callee from the stub frame (which is traced) instead of spilling it to
|
||||
// callee from the caller's frame (which is traced) instead of spilling it to
|
||||
// the stack.
|
||||
loadStackObject(ArgumentKind::Callee, flags, argcReg, calleeReg);
|
||||
if (isBoundFunction) {
|
||||
// Load the callee (which is a bound function).
|
||||
// At this point, argcReg is the number of actual arguments being passed.
|
||||
// For bound functions, this includes bound arguments. However, to compute
|
||||
// the address of `callee` in the caller's frame, we need to know how many
|
||||
// arguments were passed by the caller. This is argcReg - numBoundArgs.
|
||||
// We pass in `numBoundArgs` so that loadStackObject can adjust accordingly.
|
||||
loadStackObject(ArgumentKind::Callee, flags, argcReg, calleeReg,
|
||||
*numBoundArgs);
|
||||
|
||||
// Load the target JSFunction.
|
||||
Address boundTarget(calleeReg, BoundFunctionObject::offsetOfTargetSlot());
|
||||
masm.unboxObject(boundTarget, calleeReg);
|
||||
} else {
|
||||
loadStackObject(ArgumentKind::Callee, flags, argcReg, calleeReg);
|
||||
}
|
||||
}
|
||||
|
||||
void BaselineCacheIRCompiler::updateReturnValue() {
|
||||
|
|
@ -3753,11 +3773,6 @@ bool BaselineCacheIRCompiler::emitCallScriptedFunction(ObjOperandId calleeId,
|
|||
masm.switchToObjectRealm(calleeReg, scratch);
|
||||
}
|
||||
|
||||
if (isConstructing) {
|
||||
createThis(argcReg, calleeReg, scratch, flags,
|
||||
/* isBoundFunction = */ false);
|
||||
}
|
||||
|
||||
pushArguments(argcReg, calleeReg, scratch, scratch2, flags, argcFixed,
|
||||
/*isJitCall =*/true);
|
||||
|
||||
|
|
@ -3767,7 +3782,6 @@ bool BaselineCacheIRCompiler::emitCallScriptedFunction(ObjOperandId calleeId,
|
|||
|
||||
// Note that we use Push, not push, so that callJit will align the stack
|
||||
// properly on ARM.
|
||||
masm.PushCalleeToken(calleeReg, isConstructing);
|
||||
masm.PushFrameDescriptorForJitCall(FrameType::BaselineStub, argcReg, scratch);
|
||||
|
||||
// Handle arguments underflow.
|
||||
|
|
@ -3843,11 +3857,11 @@ bool BaselineCacheIRCompiler::emitCallInlinedFunction(ObjOperandId calleeId,
|
|||
masm.switchToObjectRealm(calleeReg, scratch);
|
||||
}
|
||||
|
||||
pushArguments(argcReg, calleeReg, scratch, scratch2, flags, argcFixed,
|
||||
/*isJitCall =*/true);
|
||||
|
||||
Label baselineScriptDiscarded;
|
||||
if (isConstructing) {
|
||||
createThis(argcReg, calleeReg, scratch, flags,
|
||||
/* isBoundFunction = */ false);
|
||||
|
||||
// CreateThisFromIC may trigger a GC and discard the BaselineScript.
|
||||
// We have already called discardStack, so we can't use a FailurePath.
|
||||
// Instead, we skip storing the ICScript in the JSContext and use a
|
||||
|
|
@ -3868,12 +3882,8 @@ bool BaselineCacheIRCompiler::emitCallInlinedFunction(ObjOperandId calleeId,
|
|||
masm.bind(&skip);
|
||||
}
|
||||
|
||||
pushArguments(argcReg, calleeReg, scratch, scratch2, flags, argcFixed,
|
||||
/*isJitCall =*/true);
|
||||
|
||||
// Note that we use Push, not push, so that callJit will align the stack
|
||||
// properly on ARM.
|
||||
masm.PushCalleeToken(calleeReg, isConstructing);
|
||||
masm.PushFrameDescriptorForJitCall(FrameType::BaselineStub, argcReg, scratch);
|
||||
|
||||
// Handle arguments underflow.
|
||||
|
|
@ -4035,34 +4045,26 @@ bool BaselineCacheIRCompiler::emitCallBoundScriptedFunction(
|
|||
AutoStubFrame stubFrame(*this);
|
||||
stubFrame.enter(masm, scratch);
|
||||
|
||||
Address boundTarget(calleeReg, BoundFunctionObject::offsetOfTargetSlot());
|
||||
|
||||
// If we're constructing, switch to the target's realm and create |this|. If
|
||||
// we're not constructing, we switch to the target's realm after pushing the
|
||||
// arguments and loading the target.
|
||||
if (isConstructing) {
|
||||
if (!isSameRealm) {
|
||||
masm.unboxObject(boundTarget, scratch);
|
||||
masm.switchToObjectRealm(scratch, scratch);
|
||||
}
|
||||
createThis(argcReg, calleeReg, scratch, flags,
|
||||
/* isBoundFunction = */ true);
|
||||
}
|
||||
|
||||
// Push all arguments, including |this|.
|
||||
pushBoundFunctionArguments(argcReg, calleeReg, scratch, scratch2, flags,
|
||||
numBoundArgs, /* isJitCall = */ true);
|
||||
|
||||
// Load the target JSFunction.
|
||||
Address boundTarget(calleeReg, BoundFunctionObject::offsetOfTargetSlot());
|
||||
masm.unboxObject(boundTarget, calleeReg);
|
||||
|
||||
if (!isConstructing && !isSameRealm) {
|
||||
if (!isSameRealm) {
|
||||
masm.switchToObjectRealm(calleeReg, scratch);
|
||||
}
|
||||
|
||||
// Update argc.
|
||||
masm.add32(Imm32(numBoundArgs), argcReg);
|
||||
|
||||
if (isConstructing) {
|
||||
createThis(argcReg, calleeReg, scratch, scratch2, flags,
|
||||
mozilla::Some(numBoundArgs));
|
||||
}
|
||||
|
||||
// Load the start of the target JitCode.
|
||||
Register code = scratch2;
|
||||
masm.loadJitCodeRaw(calleeReg, code);
|
||||
|
|
|
|||
|
|
@ -73,7 +73,7 @@ class MOZ_RAII BaselineCacheIRCompiler : public CacheIRCompiler {
|
|||
|
||||
bool updateArgc(CallFlags flags, Register argcReg, Register scratch);
|
||||
void loadStackObject(ArgumentKind kind, CallFlags flags, Register argcReg,
|
||||
Register dest);
|
||||
Register dest, uint32_t extraArgs = 0);
|
||||
void pushArguments(Register argcReg, Register calleeReg, Register scratch,
|
||||
Register scratch2, CallFlags flags, uint32_t argcFixed,
|
||||
bool isJitCall);
|
||||
|
|
@ -93,9 +93,8 @@ class MOZ_RAII BaselineCacheIRCompiler : public CacheIRCompiler {
|
|||
CallFlags flags, uint32_t numBoundArgs,
|
||||
bool isJitCall);
|
||||
void createThis(Register argcReg, Register calleeReg, Register scratch,
|
||||
CallFlags flags, bool isBoundFunction);
|
||||
template <typename T>
|
||||
void storeThis(const T& newThis, Register argcReg, CallFlags flags);
|
||||
Register scratch2, CallFlags flags,
|
||||
mozilla::Maybe<uint32_t> numBoundArgs = mozilla::Nothing());
|
||||
void updateReturnValue();
|
||||
|
||||
enum class NativeCallType { Native, ClassHook };
|
||||
|
|
|
|||
|
|
@ -299,7 +299,9 @@ class ICCacheIRStub final : public ICStub {
|
|||
void trace(JSTracer* trc);
|
||||
bool traceWeak(JSTracer* trc);
|
||||
|
||||
ICCacheIRStub* clone(JSRuntime* rt, ICStubSpace& newSpace);
|
||||
enum class ICScriptHandling { MarkActive, AssertActive };
|
||||
ICCacheIRStub* clone(JSRuntime* rt, ICStubSpace& newSpace,
|
||||
ICScriptHandling icScriptHandling);
|
||||
|
||||
// Returns true if this stub can call JS or VM code that can trigger a GC.
|
||||
bool makesGCCalls() const;
|
||||
|
|
|
|||
|
|
@ -243,6 +243,9 @@ uint32_t CacheIRCloner::getRawInt32Field(uint32_t stubOffset) {
|
|||
const void* CacheIRCloner::getRawPointerField(uint32_t stubOffset) {
|
||||
return reinterpret_cast<const void*>(readStubWord(stubOffset));
|
||||
}
|
||||
const ICScript* CacheIRCloner::getICScriptField(uint32_t stubOffset) {
|
||||
return reinterpret_cast<const ICScript*>(readStubWord(stubOffset));
|
||||
}
|
||||
uint64_t CacheIRCloner::getRawInt64Field(uint32_t stubOffset) {
|
||||
return static_cast<uint64_t>(readStubInt64(stubOffset));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -239,6 +239,7 @@ class StubField {
|
|||
// These fields take up a single word.
|
||||
RawInt32,
|
||||
RawPointer,
|
||||
ICScript,
|
||||
Shape,
|
||||
WeakShape,
|
||||
WeakGetterSetter,
|
||||
|
|
@ -312,6 +313,8 @@ inline const char* StubFieldTypeName(StubField::Type ty) {
|
|||
return "RawInt32";
|
||||
case StubField::Type::RawPointer:
|
||||
return "RawPointer";
|
||||
case StubField::Type::ICScript:
|
||||
return "ICScript";
|
||||
case StubField::Type::Shape:
|
||||
return "Shape";
|
||||
case StubField::Type::WeakShape:
|
||||
|
|
|
|||
|
|
@ -71,6 +71,7 @@ class MOZ_RAII CacheIRCloner {
|
|||
JitCode* getJitCodeField(uint32_t stubOffset);
|
||||
uint32_t getRawInt32Field(uint32_t stubOffset);
|
||||
const void* getRawPointerField(uint32_t stubOffset);
|
||||
const ICScript* getICScriptField(uint32_t stubOffset);
|
||||
jsid getIdField(uint32_t stubOffset);
|
||||
const Value getValueField(uint32_t stubOffset);
|
||||
uint64_t getRawInt64Field(uint32_t stubOffset);
|
||||
|
|
|
|||
|
|
@ -1119,6 +1119,7 @@ static void InitWordStubField(StubField::Type type, void* dest,
|
|||
switch (type) {
|
||||
case StubField::Type::RawInt32:
|
||||
case StubField::Type::RawPointer:
|
||||
case StubField::Type::ICScript:
|
||||
case StubField::Type::AllocSite:
|
||||
*static_cast<uintptr_t*>(dest) = value;
|
||||
break;
|
||||
|
|
@ -1179,6 +1180,7 @@ static void InitInt64StubField(StubField::Type type, void* dest,
|
|||
break;
|
||||
case StubField::Type::RawInt32:
|
||||
case StubField::Type::RawPointer:
|
||||
case StubField::Type::ICScript:
|
||||
case StubField::Type::AllocSite:
|
||||
case StubField::Type::Shape:
|
||||
case StubField::Type::WeakShape:
|
||||
|
|
@ -1209,7 +1211,8 @@ void CacheIRWriter::copyStubData(uint8_t* dest) const {
|
|||
}
|
||||
}
|
||||
|
||||
ICCacheIRStub* ICCacheIRStub::clone(JSRuntime* rt, ICStubSpace& newSpace) {
|
||||
ICCacheIRStub* ICCacheIRStub::clone(JSRuntime* rt, ICStubSpace& newSpace,
|
||||
ICScriptHandling icScriptHandling) {
|
||||
const CacheIRStubInfo* info = stubInfo();
|
||||
MOZ_ASSERT(info->makesGCCalls());
|
||||
|
||||
|
|
@ -1242,6 +1245,15 @@ ICCacheIRStub* ICCacheIRStub::clone(JSRuntime* rt, ICStubSpace& newSpace) {
|
|||
InitWordStubField(type, dest, *srcField);
|
||||
src += sizeof(uintptr_t);
|
||||
dest += sizeof(uintptr_t);
|
||||
if (type == StubField::Type::ICScript) {
|
||||
auto* icScript = reinterpret_cast<ICScript*>(*srcField);
|
||||
if (icScriptHandling == ICScriptHandling::MarkActive) {
|
||||
icScript->setActive();
|
||||
} else {
|
||||
MOZ_ASSERT(icScriptHandling == ICScriptHandling::AssertActive);
|
||||
MOZ_RELEASE_ASSERT(icScript->active());
|
||||
}
|
||||
}
|
||||
} else {
|
||||
const uint64_t* srcField = reinterpret_cast<const uint64_t*>(src);
|
||||
InitInt64StubField(type, dest, *srcField);
|
||||
|
|
@ -1278,6 +1290,7 @@ void jit::TraceCacheIRStub(JSTracer* trc, T* stub,
|
|||
switch (fieldType) {
|
||||
case Type::RawInt32:
|
||||
case Type::RawPointer:
|
||||
case Type::ICScript:
|
||||
case Type::RawInt64:
|
||||
case Type::Double:
|
||||
break;
|
||||
|
|
@ -1425,6 +1438,7 @@ bool jit::TraceWeakCacheIRStub(JSTracer* trc, T* stub,
|
|||
return !isDead;
|
||||
case Type::RawInt32:
|
||||
case Type::RawPointer:
|
||||
case Type::ICScript:
|
||||
case Type::Shape:
|
||||
case Type::JSObject:
|
||||
case Type::Symbol:
|
||||
|
|
|
|||
|
|
@ -1931,7 +1931,7 @@
|
|||
receiver: ObjId
|
||||
setter: ObjectField
|
||||
rhs: ValId
|
||||
icScript: RawPointerField
|
||||
icScript: ICScriptField
|
||||
sameRealm: BoolImm
|
||||
nargsAndFlags: RawInt32Field
|
||||
|
||||
|
|
@ -2124,7 +2124,7 @@
|
|||
args:
|
||||
callee: ObjId
|
||||
argc: Int32Id
|
||||
icScript: RawPointerField
|
||||
icScript: ICScriptField
|
||||
flags: CallFlagsImm
|
||||
argcFixed: UInt32Imm
|
||||
|
||||
|
|
@ -2558,7 +2558,7 @@
|
|||
args:
|
||||
receiver: ValId
|
||||
getter: ObjectField
|
||||
icScript: RawPointerField
|
||||
icScript: ICScriptField
|
||||
sameRealm: BoolImm
|
||||
nargsAndFlags: RawInt32Field
|
||||
|
||||
|
|
|
|||
|
|
@ -238,6 +238,9 @@ class MOZ_RAII CacheIRWriter : public JS::CustomAutoRooter {
|
|||
void writeRawPointerField(const void* ptr) {
|
||||
addStubField(uintptr_t(ptr), StubField::Type::RawPointer);
|
||||
}
|
||||
void writeICScriptField(const ICScript* icScript) {
|
||||
addStubField(uintptr_t(icScript), StubField::Type::ICScript);
|
||||
}
|
||||
void writeIdField(jsid id) {
|
||||
addStubField(id.asRawBits(), StubField::Type::Id);
|
||||
}
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue