Merge autoland to mozilla-central. a=merge
|
@ -1,5 +1,15 @@
|
|||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
[[package]]
|
||||
name = "Inflector"
|
||||
version = "0.11.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fe438c63458706e03479442743baae6c88256498e6431708f6dfc520a26515d3"
|
||||
dependencies = [
|
||||
"lazy_static",
|
||||
"regex",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "adler"
|
||||
version = "0.2.3"
|
||||
|
@ -1497,9 +1507,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "fluent"
|
||||
version = "0.13.1"
|
||||
version = "0.14.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ef9e54ec7b674ae3477d948ae790e90ae24d54fb31c2e7173252978d9b09bdfa"
|
||||
checksum = "e4f3359832f932e4ddbb4c56851623cb50bd08d1ae36e9ec80cfc44f412e1400"
|
||||
dependencies = [
|
||||
"fluent-bundle",
|
||||
"fluent-pseudo",
|
||||
|
@ -1508,15 +1518,15 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "fluent-bundle"
|
||||
version = "0.13.1"
|
||||
version = "0.14.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a79916560098f0a57215a489e37b7fc83088949eab7f7977dcc329b254d50c17"
|
||||
checksum = "4c0cd40fee9f6eb74dfb38f0fa700a92ac4fe702868b04e52018ead90d415332"
|
||||
dependencies = [
|
||||
"fluent-langneg",
|
||||
"fluent-syntax",
|
||||
"intl-memoizer",
|
||||
"intl_pluralrules",
|
||||
"rental",
|
||||
"ouroboros",
|
||||
"smallvec",
|
||||
"unic-langid",
|
||||
]
|
||||
|
@ -1566,9 +1576,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "fluent-syntax"
|
||||
version = "0.10.0"
|
||||
version = "0.10.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9389354f858e38f37d9a249133611a1fcaec469f44773b04ddbd82f4f08d49eb"
|
||||
checksum = "edb1016e8c600060e0099218442fff329a204f6316d6ec974d590d3281517a52"
|
||||
|
||||
[[package]]
|
||||
name = "fnv"
|
||||
|
@ -1797,7 +1807,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "geckodriver"
|
||||
version = "0.28.0"
|
||||
version = "0.29.0"
|
||||
dependencies = [
|
||||
"base64 0.12.0",
|
||||
"chrono",
|
||||
|
@ -2526,9 +2536,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "intl_pluralrules"
|
||||
version = "7.0.0"
|
||||
version = "7.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6c271cdb1f12a9feb3a017619c3ee681f971f270f6757341d6abe1f9f7a98bc3"
|
||||
checksum = "b18f988384267d7066cc2be425e6faf352900652c046b6971d2e228d3b1c5ecf"
|
||||
dependencies = [
|
||||
"tinystr",
|
||||
"unic-langid",
|
||||
|
@ -3237,7 +3247,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "mozdevice"
|
||||
version = "0.3.0"
|
||||
version = "0.3.1"
|
||||
dependencies = [
|
||||
"log",
|
||||
"once_cell",
|
||||
|
@ -3281,14 +3291,14 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "mozprofile"
|
||||
version = "0.7.0"
|
||||
version = "0.7.1"
|
||||
dependencies = [
|
||||
"tempfile",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "mozrunner"
|
||||
version = "0.12.0"
|
||||
version = "0.12.1"
|
||||
dependencies = [
|
||||
"dirs",
|
||||
"log",
|
||||
|
@ -3310,7 +3320,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "mozversion"
|
||||
version = "0.4.0"
|
||||
version = "0.4.1"
|
||||
dependencies = [
|
||||
"regex",
|
||||
"rust-ini",
|
||||
|
@ -3710,6 +3720,28 @@ dependencies = [
|
|||
"winapi 0.3.9",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ouroboros"
|
||||
version = "0.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b0b666c900ea45a357bc7915a4dc8fab7e295f2e756e843aa3c0788d94aa3a29"
|
||||
dependencies = [
|
||||
"ouroboros_macro",
|
||||
"stable_deref_trait",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ouroboros_macro"
|
||||
version = "0.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dfc618f205c0adc415923c74369d45f5f298462fc473711dfc33056a23f23619"
|
||||
dependencies = [
|
||||
"Inflector",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "owning_ref"
|
||||
version = "0.4.0"
|
||||
|
@ -4820,9 +4852,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "stable_deref_trait"
|
||||
version = "1.0.0"
|
||||
version = "1.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "15132e0e364248108c5e2c02e3ab539be8d6f5d52a01ca9bbf27ed657316f02b"
|
||||
checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3"
|
||||
|
||||
[[package]]
|
||||
name = "static_assertions"
|
||||
|
@ -5725,7 +5757,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "webdriver"
|
||||
version = "0.42.0"
|
||||
version = "0.43.0"
|
||||
dependencies = [
|
||||
"base64 0.12.0",
|
||||
"bytes 0.5.3",
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
#include "nsCOMPtr.h"
|
||||
|
||||
#ifdef XP_WIN
|
||||
# include "freestanding/SharedSection.h"
|
||||
# include "LauncherProcessWin.h"
|
||||
# include "mozilla/WindowsDllBlocklist.h"
|
||||
|
||||
|
@ -320,6 +321,12 @@ int main(int argc, char* argv[], char* envp[]) {
|
|||
#endif
|
||||
|
||||
#if defined(XP_WIN)
|
||||
// Once the browser process hits the main function, we no longer need
|
||||
// a writable section handle because all dependent modules have been
|
||||
// loaded.
|
||||
mozilla::freestanding::gSharedSection.ConvertToReadOnly();
|
||||
::RtlRunOnceInitialize(&mozilla::freestanding::gK32ExportsResolveOnce);
|
||||
|
||||
mozilla::CreateAndStorePreXULSkeletonUI(GetModuleHandle(nullptr), argc, argv);
|
||||
#endif
|
||||
|
||||
|
|
|
@ -1710,12 +1710,7 @@ pref("browser.contentblocking.state-partitioning.mvp.ui.enabled", true);
|
|||
// "cookieBehavior4": cookie behaviour BEHAVIOR_REJECT_TRACKER
|
||||
// "cookieBehavior5": cookie behaviour BEHAVIOR_REJECT_TRACKER_AND_PARTITION_FOREIGN
|
||||
// One value from each section must be included in the browser.contentblocking.features.strict pref.
|
||||
#ifdef NIGHTLY_BUILD
|
||||
// Enable Dynamic First-Party Isolation in Nightly.
|
||||
pref("browser.contentblocking.features.strict", "tp,tpPrivate,cookieBehavior5,cm,fp,stp,lvl2");
|
||||
#else
|
||||
pref("browser.contentblocking.features.strict", "tp,tpPrivate,cookieBehavior4,cm,fp,stp,lvl2");
|
||||
#endif
|
||||
|
||||
// Hide the "Change Block List" link for trackers/tracking content in the custom
|
||||
// Content Blocking/ETP panel. By default, it will not be visible. There is also
|
||||
|
|
|
@ -44,12 +44,6 @@ LauncherVoidResultWithLineInfo InitializeDllBlocklistOOPFromLauncher(
|
|||
static LauncherVoidResultWithLineInfo InitializeDllBlocklistOOPInternal(
|
||||
const wchar_t* aFullImagePath, nt::CrossExecTransferManager& aTransferMgr,
|
||||
const IMAGE_THUNK_DATA* aCachedNtdllThunk) {
|
||||
LauncherVoidResult transferResult =
|
||||
freestanding::gSharedSection.TransferHandle(aTransferMgr);
|
||||
if (transferResult.isErr()) {
|
||||
return transferResult.propagateErr();
|
||||
}
|
||||
|
||||
CrossProcessDllInterceptor intcpt(aTransferMgr.RemoteProcess());
|
||||
intcpt.Init(L"ntdll.dll");
|
||||
|
||||
|
@ -169,6 +163,14 @@ LauncherVoidResultWithLineInfo InitializeDllBlocklistOOP(
|
|||
return RestoreImportDirectory(aFullImagePath, transferMgr);
|
||||
}
|
||||
|
||||
// Transfer a readonly handle to the child processes because all information
|
||||
// are already written to the section by the launcher and main process.
|
||||
LauncherVoidResult transferResult =
|
||||
freestanding::gSharedSection.TransferHandle(transferMgr, GENERIC_READ);
|
||||
if (transferResult.isErr()) {
|
||||
return transferResult.propagateErr();
|
||||
}
|
||||
|
||||
return InitializeDllBlocklistOOPInternal(aFullImagePath, transferMgr,
|
||||
aCachedNtdllThunk);
|
||||
}
|
||||
|
@ -189,6 +191,15 @@ LauncherVoidResultWithLineInfo InitializeDllBlocklistOOPFromLauncher(
|
|||
return result.propagateErr();
|
||||
}
|
||||
|
||||
// Transfer a writable handle to the main process because it needs to append
|
||||
// dependent module paths to the section.
|
||||
LauncherVoidResult transferResult =
|
||||
freestanding::gSharedSection.TransferHandle(transferMgr,
|
||||
GENERIC_READ | GENERIC_WRITE);
|
||||
if (transferResult.isErr()) {
|
||||
return transferResult.propagateErr();
|
||||
}
|
||||
|
||||
auto clearInstance = MakeScopeExit([]() {
|
||||
// After transfer, the launcher process does not need the object anymore.
|
||||
freestanding::gSharedSection.Reset(nullptr);
|
||||
|
|
|
@ -242,6 +242,48 @@ struct DllBlockInfoComparator {
|
|||
|
||||
static BOOL WINAPI NoOp_DllMain(HINSTANCE, DWORD, LPVOID) { return TRUE; }
|
||||
|
||||
// This helper function checks whether a given module is included
|
||||
// in the executable's Import Table. Because an injected module's
|
||||
// DllMain may revert the Import Table to the original state, we parse
|
||||
// the Import Table every time a module is loaded without creating a cache.
|
||||
static bool IsDependentModule(
|
||||
const UNICODE_STRING& aModuleLeafName,
|
||||
mozilla::freestanding::Kernel32ExportsSolver& aK32Exports) {
|
||||
// We enable automatic DLL blocking only in Nightly for now because it caused
|
||||
// a compat issue (bug 1682304).
|
||||
#if defined(NIGHTLY_BUILD)
|
||||
aK32Exports.Resolve(mozilla::freestanding::gK32ExportsResolveOnce);
|
||||
if (!aK32Exports.IsResolved()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
mozilla::nt::PEHeaders exeHeaders(aK32Exports.mGetModuleHandleW(nullptr));
|
||||
if (!exeHeaders || !exeHeaders.IsImportDirectoryTampered()) {
|
||||
// If no tampering is detected, no need to enumerate the Import Table.
|
||||
return false;
|
||||
}
|
||||
|
||||
bool isDependent = false;
|
||||
exeHeaders.EnumImportChunks(
|
||||
[&isDependent, &aModuleLeafName, &exeHeaders](const char* aDepModule) {
|
||||
// If |aDepModule| is within the PE image, it's not an injected module
|
||||
// but a legitimate dependent module.
|
||||
if (isDependent || exeHeaders.IsWithinImage(aDepModule)) {
|
||||
return;
|
||||
}
|
||||
|
||||
UNICODE_STRING depModuleLeafName;
|
||||
mozilla::nt::AllocatedUnicodeString depModuleName(aDepModule);
|
||||
mozilla::nt::GetLeafName(&depModuleLeafName, depModuleName);
|
||||
isDependent = (::RtlCompareUnicodeString(
|
||||
&aModuleLeafName, &depModuleLeafName, TRUE) == 0);
|
||||
});
|
||||
return isDependent;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
// Allowing a module to be loaded but detour the entrypoint to NoOp_DllMain
|
||||
// so that the module has no chance to interact with our code. We need this
|
||||
// technique to safely block a module injected by IAT tampering because
|
||||
|
@ -249,8 +291,7 @@ static BOOL WINAPI NoOp_DllMain(HINSTANCE, DWORD, LPVOID) { return TRUE; }
|
|||
static bool RedirectToNoOpEntryPoint(
|
||||
const mozilla::nt::PEHeaders& aModule,
|
||||
mozilla::freestanding::Kernel32ExportsSolver& aK32Exports) {
|
||||
static RTL_RUN_ONCE sRunOnce = RTL_RUN_ONCE_INIT;
|
||||
aK32Exports.Resolve(sRunOnce);
|
||||
aK32Exports.Resolve(mozilla::freestanding::gK32ExportsResolveOnce);
|
||||
if (!aK32Exports.IsResolved()) {
|
||||
return false;
|
||||
}
|
||||
|
@ -305,6 +346,7 @@ namespace mozilla {
|
|||
namespace freestanding {
|
||||
|
||||
CrossProcessDllInterceptor::FuncHookType<LdrLoadDllPtr> stub_LdrLoadDll;
|
||||
RTL_RUN_ONCE gK32ExportsResolveOnce = RTL_RUN_ONCE_INIT;
|
||||
|
||||
NTSTATUS NTAPI patched_LdrLoadDll(PWCHAR aDllPath, PULONG aFlags,
|
||||
PUNICODE_STRING aDllName,
|
||||
|
@ -360,31 +402,27 @@ NTSTATUS NTAPI patched_NtMapViewOfSection(
|
|||
return STATUS_ACCESS_DENIED;
|
||||
}
|
||||
|
||||
bool isDependent = false;
|
||||
auto resultView = mozilla::freestanding::gSharedSection.GetView();
|
||||
if (resultView.isOk()) {
|
||||
uint32_t arrayLen = resultView.inspect()->mModulePathArrayLength;
|
||||
const uint32_t* array = resultView.inspect()->mModulePathArray;
|
||||
size_t match;
|
||||
isDependent = mozilla::BinarySearchIf(
|
||||
array, 0, arrayLen,
|
||||
[§ionFileName, arrayBase = reinterpret_cast<const uint8_t*>(array)](
|
||||
const uint32_t& aOffset) {
|
||||
UNICODE_STRING str;
|
||||
::RtlInitUnicodeString(
|
||||
&str, reinterpret_cast<const wchar_t*>(arrayBase + aOffset));
|
||||
return static_cast<int>(
|
||||
::RtlCompareUnicodeString(sectionFileName, &str, TRUE));
|
||||
},
|
||||
&match);
|
||||
}
|
||||
|
||||
// Find the leaf name
|
||||
UNICODE_STRING leafOnStack;
|
||||
nt::GetLeafName(&leafOnStack, sectionFileName);
|
||||
|
||||
bool isDependent = false;
|
||||
auto resultView = freestanding::gSharedSection.GetView();
|
||||
// Small optimization: Since loading a dependent module does not involve
|
||||
// LdrLoadDll, we know isDependent is false if we hold a top frame.
|
||||
if (resultView.isOk() && !ModuleLoadFrame::ExistsTopFrame()) {
|
||||
isDependent =
|
||||
IsDependentModule(leafOnStack, resultView.inspect()->mK32Exports);
|
||||
}
|
||||
|
||||
BlockAction blockAction;
|
||||
if (isDependent) {
|
||||
// Add an NT dv\path to the shared section so that a sandbox process can
|
||||
// use it to bypass CIG. In a sandbox process, this addition fails
|
||||
// because we cannot map the section to a writable region, but it's
|
||||
// ignorable because the paths have been added by the browser process.
|
||||
Unused << freestanding::gSharedSection.AddDepenentModule(sectionFileName);
|
||||
|
||||
// For a dependent module, try redirection instead of blocking it.
|
||||
// If we fail, we reluctantly allow the module for free.
|
||||
mozilla::nt::PEHeaders headers(*aBaseAddress);
|
||||
|
|
|
@ -85,6 +85,9 @@ void ModuleLoadFrame::NotifySectionMap(
|
|||
topFrame->OnSectionMap(std::move(aSectionName), aMapBaseAddr, aMapNtStatus);
|
||||
}
|
||||
|
||||
/* static */
|
||||
bool ModuleLoadFrame::ExistsTopFrame() { return !!sTopFrame.get(); }
|
||||
|
||||
void ModuleLoadFrame::OnSectionMap(nt::AllocatedUnicodeString&& aSectionName,
|
||||
const void* aMapBaseAddr,
|
||||
NTSTATUS aMapNtStatus) {
|
||||
|
|
|
@ -37,6 +37,7 @@ class MOZ_RAII ModuleLoadFrame final {
|
|||
*/
|
||||
static void NotifySectionMap(nt::AllocatedUnicodeString&& aSectionName,
|
||||
const void* aMapBaseAddr, NTSTATUS aMapNtStatus);
|
||||
static bool ExistsTopFrame();
|
||||
|
||||
/**
|
||||
* Called by the LdrLoadDll hook to indicate the status of the load and for
|
||||
|
|
|
@ -8,6 +8,43 @@
|
|||
|
||||
#include "CheckForCaller.h"
|
||||
|
||||
namespace {
|
||||
|
||||
bool AddString(void* aBuffer, size_t aBufferSize, const UNICODE_STRING& aStr) {
|
||||
size_t offset = 0;
|
||||
while (offset < aBufferSize) {
|
||||
UNICODE_STRING uniStr;
|
||||
::RtlInitUnicodeString(&uniStr,
|
||||
reinterpret_cast<wchar_t*>(
|
||||
reinterpret_cast<uintptr_t>(aBuffer) + offset));
|
||||
|
||||
if (uniStr.Length == 0) {
|
||||
// Reached to the array's last item.
|
||||
break;
|
||||
}
|
||||
|
||||
if (::RtlCompareUnicodeString(&uniStr, &aStr, TRUE) == 0) {
|
||||
// Already included in the array.
|
||||
return true;
|
||||
}
|
||||
|
||||
// Go to the next string.
|
||||
offset += uniStr.MaximumLength;
|
||||
}
|
||||
|
||||
// Ensure enough space including the last empty string at the end.
|
||||
if (offset + aStr.MaximumLength + sizeof(wchar_t) > aBufferSize) {
|
||||
return false;
|
||||
}
|
||||
|
||||
auto newStr = reinterpret_cast<uint8_t*>(aBuffer) + offset;
|
||||
memcpy(newStr, aStr.Buffer, aStr.Length);
|
||||
memset(newStr + aStr.Length, 0, sizeof(wchar_t));
|
||||
return true;
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
namespace mozilla {
|
||||
namespace freestanding {
|
||||
|
||||
|
@ -56,6 +93,7 @@ void Kernel32ExportsSolver::Init() {
|
|||
|
||||
// Please make sure these functions are not forwarded to another DLL.
|
||||
INIT_FUNCTION(k32Exports, FlushInstructionCache);
|
||||
INIT_FUNCTION(k32Exports, GetModuleHandleW);
|
||||
INIT_FUNCTION(k32Exports, GetSystemInfo);
|
||||
INIT_FUNCTION(k32Exports, VirtualProtect);
|
||||
|
||||
|
@ -81,6 +119,7 @@ void Kernel32ExportsSolver::ResolveInternal() {
|
|||
nt::PEHeaders::HModuleToBaseAddr<uintptr_t>(k32Module.unwrap());
|
||||
|
||||
RESOLVE_FUNCTION(k32Base, FlushInstructionCache);
|
||||
RESOLVE_FUNCTION(k32Base, GetModuleHandleW);
|
||||
RESOLVE_FUNCTION(k32Base, GetSystemInfo);
|
||||
RESOLVE_FUNCTION(k32Base, VirtualProtect);
|
||||
|
||||
|
@ -107,74 +146,37 @@ void SharedSection::Reset(HANDLE aNewSecionObject) {
|
|||
sWriteCopyView = nullptr;
|
||||
}
|
||||
|
||||
if (sSectionHandle) {
|
||||
::CloseHandle(sSectionHandle);
|
||||
if (sSectionHandle != aNewSecionObject) {
|
||||
if (sSectionHandle) {
|
||||
::CloseHandle(sSectionHandle);
|
||||
}
|
||||
sSectionHandle = aNewSecionObject;
|
||||
}
|
||||
sSectionHandle = aNewSecionObject;
|
||||
}
|
||||
|
||||
static void PackOffsetVector(const Vector<nt::MemorySectionNameOnHeap>& aSource,
|
||||
SharedSection::Layout& aDestination,
|
||||
size_t aStringBufferOffset) {
|
||||
aDestination.mModulePathArrayLength = aSource.length();
|
||||
|
||||
uint32_t* curItem = aDestination.mModulePathArray;
|
||||
uint8_t* const arrayBase = reinterpret_cast<uint8_t*>(curItem);
|
||||
for (const auto& it : aSource) {
|
||||
// Fill the current offset value
|
||||
*(curItem++) = aStringBufferOffset;
|
||||
|
||||
// Fill a string and a null character
|
||||
uint32_t lenInBytes = it.AsUnicodeString()->Length;
|
||||
memcpy(arrayBase + aStringBufferOffset, it.AsUnicodeString()->Buffer,
|
||||
lenInBytes);
|
||||
memset(arrayBase + aStringBufferOffset + lenInBytes, 0, sizeof(WCHAR));
|
||||
|
||||
// Advance the offset
|
||||
aStringBufferOffset += (lenInBytes + sizeof(WCHAR));
|
||||
void SharedSection::ConvertToReadOnly() {
|
||||
if (!sSectionHandle) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Sort the offset array so that we can binary-search it
|
||||
std::sort(aDestination.mModulePathArray,
|
||||
aDestination.mModulePathArray + aSource.length(),
|
||||
[arrayBase](uint32_t a, uint32_t b) {
|
||||
auto s1 = reinterpret_cast<const wchar_t*>(arrayBase + a);
|
||||
auto s2 = reinterpret_cast<const wchar_t*>(arrayBase + b);
|
||||
return wcsicmp(s1, s2) < 0;
|
||||
});
|
||||
HANDLE readonlyHandle;
|
||||
if (!::DuplicateHandle(nt::kCurrentProcess, sSectionHandle,
|
||||
nt::kCurrentProcess, &readonlyHandle, GENERIC_READ,
|
||||
FALSE, 0)) {
|
||||
return;
|
||||
}
|
||||
|
||||
Reset(readonlyHandle);
|
||||
}
|
||||
|
||||
LauncherVoidResult SharedSection::Init(const nt::PEHeaders& aPEHeaders) {
|
||||
size_t stringBufferSize = 0;
|
||||
Vector<nt::MemorySectionNameOnHeap> modules;
|
||||
static_assert(
|
||||
kSharedViewSize >= sizeof(Layout),
|
||||
"kSharedViewSize is too small to represent SharedSection::Layout.");
|
||||
|
||||
// We enable automatic DLL blocking only in Nightly for now because it caused
|
||||
// a compat issue (bug 1682304).
|
||||
#if defined(NIGHTLY_BUILD)
|
||||
aPEHeaders.EnumImportChunks(
|
||||
[&stringBufferSize, &modules, &aPEHeaders](const char* aModule) {
|
||||
# if defined(DONT_SKIP_DEFAULT_DEPENDENT_MODULES)
|
||||
Unused << aPEHeaders;
|
||||
# else
|
||||
if (aPEHeaders.IsWithinImage(aModule)) {
|
||||
return;
|
||||
}
|
||||
# endif
|
||||
HMODULE module = ::GetModuleHandleA(aModule);
|
||||
nt::MemorySectionNameOnHeap ntPath =
|
||||
nt::MemorySectionNameOnHeap::GetBackingFilePath(nt::kCurrentProcess,
|
||||
module);
|
||||
stringBufferSize += (ntPath.AsUnicodeString()->Length + sizeof(WCHAR));
|
||||
Unused << modules.emplaceBack(std::move(ntPath));
|
||||
});
|
||||
#endif
|
||||
|
||||
size_t arraySize = modules.length() * sizeof(Layout::mModulePathArray[0]);
|
||||
size_t totalSize =
|
||||
sizeof(Kernel32ExportsSolver) + arraySize + stringBufferSize;
|
||||
|
||||
HANDLE section = ::CreateFileMappingW(INVALID_HANDLE_VALUE, nullptr,
|
||||
PAGE_READWRITE, 0, totalSize, nullptr);
|
||||
HANDLE section =
|
||||
::CreateFileMappingW(INVALID_HANDLE_VALUE, nullptr, PAGE_READWRITE, 0,
|
||||
kSharedViewSize, nullptr);
|
||||
if (!section) {
|
||||
return LAUNCHER_ERROR_FROM_LAST();
|
||||
}
|
||||
|
@ -191,7 +193,21 @@ LauncherVoidResult SharedSection::Init(const nt::PEHeaders& aPEHeaders) {
|
|||
|
||||
SharedSection::Layout* view = writableView.as<SharedSection::Layout>();
|
||||
view->mK32Exports.Init();
|
||||
PackOffsetVector(modules, *view, arraySize);
|
||||
|
||||
return Ok();
|
||||
}
|
||||
|
||||
LauncherVoidResult SharedSection::AddDepenentModule(PCUNICODE_STRING aNtPath) {
|
||||
nt::AutoMappedView writableView(sSectionHandle, PAGE_READWRITE);
|
||||
if (!writableView) {
|
||||
return LAUNCHER_ERROR_FROM_WIN32(::RtlGetLastWin32Error());
|
||||
}
|
||||
|
||||
SharedSection::Layout* view = writableView.as<SharedSection::Layout>();
|
||||
if (!AddString(view->mModulePathArray,
|
||||
kSharedViewSize - sizeof(Kernel32ExportsSolver), *aNtPath)) {
|
||||
return LAUNCHER_ERROR_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
|
||||
}
|
||||
|
||||
return Ok();
|
||||
}
|
||||
|
@ -200,7 +216,7 @@ LauncherResult<SharedSection::Layout*> SharedSection::GetView() {
|
|||
if (!sWriteCopyView) {
|
||||
nt::AutoMappedView view(sSectionHandle, PAGE_WRITECOPY);
|
||||
if (!view) {
|
||||
return LAUNCHER_ERROR_FROM_LAST();
|
||||
return LAUNCHER_ERROR_FROM_WIN32(::RtlGetLastWin32Error());
|
||||
}
|
||||
sWriteCopyView = view.release();
|
||||
}
|
||||
|
@ -208,11 +224,12 @@ LauncherResult<SharedSection::Layout*> SharedSection::GetView() {
|
|||
}
|
||||
|
||||
LauncherVoidResult SharedSection::TransferHandle(
|
||||
nt::CrossExecTransferManager& aTransferMgr, HANDLE* aDestinationAddress) {
|
||||
nt::CrossExecTransferManager& aTransferMgr, DWORD aDesiredAccess,
|
||||
HANDLE* aDestinationAddress) {
|
||||
HANDLE remoteHandle;
|
||||
if (!::DuplicateHandle(nt::kCurrentProcess, sSectionHandle,
|
||||
aTransferMgr.RemoteProcess(), &remoteHandle,
|
||||
GENERIC_READ, FALSE, 0)) {
|
||||
aDesiredAccess, FALSE, 0)) {
|
||||
return LAUNCHER_ERROR_FROM_LAST();
|
||||
}
|
||||
|
||||
|
@ -220,33 +237,29 @@ LauncherVoidResult SharedSection::TransferHandle(
|
|||
sizeof(remoteHandle));
|
||||
}
|
||||
|
||||
extern "C" MOZ_EXPORT uint32_t GetDependentModulePaths(uint32_t** aOutArray) {
|
||||
if (aOutArray) {
|
||||
*aOutArray = nullptr;
|
||||
}
|
||||
|
||||
// This exported function is invoked by SandboxBroker of xul.dll
|
||||
// in order to add dependent modules to the CIG exception list.
|
||||
extern "C" MOZ_EXPORT const wchar_t* GetDependentModulePaths() {
|
||||
// We enable pre-spawn CIG only in Nightly for now because it caused
|
||||
// a compat issue (bug 1682304).
|
||||
#if defined(NIGHTLY_BUILD)
|
||||
const bool isCallerXul = CheckForAddress(RETURN_ADDRESS(), L"xul.dll");
|
||||
MOZ_ASSERT(isCallerXul);
|
||||
if (!isCallerXul) {
|
||||
return 0;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Remap a write-copy section to take the latest update in mModulePathArray.
|
||||
gSharedSection.Reset();
|
||||
|
||||
LauncherResult<SharedSection::Layout*> resultView = gSharedSection.GetView();
|
||||
if (resultView.isErr()) {
|
||||
return 0;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (aOutArray) {
|
||||
// Return a valid address even if the array length is zero
|
||||
// to distinguish it from an error case.
|
||||
*aOutArray = resultView.inspect()->mModulePathArray;
|
||||
}
|
||||
return resultView.inspect()->mModulePathArrayLength;
|
||||
return resultView.inspect()->mModulePathArray;
|
||||
#else
|
||||
return 0;
|
||||
return nullptr;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
|
|
@ -45,31 +45,27 @@ class MOZ_TRIVIAL_CTOR_DTOR Kernel32ExportsSolver final
|
|||
};
|
||||
|
||||
// This class manages a section which is created in the launcher process and
|
||||
// mapped in the browser process and the sandboxed processes as a copy-on-write
|
||||
// region. The section's layout is represented as SharedSection::Layout.
|
||||
// mapped in the browser process and the sandboxed processes. The section's
|
||||
// layout is represented as SharedSection::Layout.
|
||||
//
|
||||
// (1) Kernel32's functions required for MMPolicyInProcessEarlyStage
|
||||
// Formatted as Kernel32ExportsSolver.
|
||||
//
|
||||
// (2) Array of NT paths of the executable's dependent modules
|
||||
// Array item is an offset to a string buffer of a module's
|
||||
// NT path, relative to the beginning of the array.
|
||||
// Array is case-insensitive sorted.
|
||||
// Formatted as a null-delimited wide-character string set ending with
|
||||
// an empty string.
|
||||
//
|
||||
// +--------------------------------------------------------------+
|
||||
// | (1) | FlushInstructionCache |
|
||||
// | | GetModuleHandleW |
|
||||
// | | GetSystemInfo |
|
||||
// | | VirtualProtect |
|
||||
// | | State [Uninitialized|Initialized|Resolved] |
|
||||
// +--------------------------------------------------------------+
|
||||
// | (2) | The length of the offset array |
|
||||
// | | Offset1 to String1 |
|
||||
// | | * Offset is relative to the beginning of the array |
|
||||
// | | * String is an NT path in wchar_t |
|
||||
// | | Offset2 to String2 |
|
||||
// | (2) | L"NT path 1" |
|
||||
// | | L"NT path 2" |
|
||||
// | | ... |
|
||||
// | | OffsetN to StringN |
|
||||
// | | String1, 2, ..., N (null delimited strings) |
|
||||
// | | L"" |
|
||||
// +--------------------------------------------------------------+
|
||||
class MOZ_TRIVIAL_CTOR_DTOR SharedSection final {
|
||||
// As we define a global variable of this class and use it in our blocklist
|
||||
|
@ -81,25 +77,40 @@ class MOZ_TRIVIAL_CTOR_DTOR SharedSection final {
|
|||
static HANDLE sSectionHandle;
|
||||
static void* sWriteCopyView;
|
||||
|
||||
static constexpr size_t kSharedViewSize = 0x1000;
|
||||
|
||||
public:
|
||||
struct Layout final {
|
||||
Kernel32ExportsSolver mK32Exports;
|
||||
uint32_t mModulePathArrayLength;
|
||||
uint32_t mModulePathArray[1];
|
||||
wchar_t mModulePathArray[1];
|
||||
|
||||
Layout() = delete; // disallow instantiation
|
||||
};
|
||||
|
||||
static void Reset(HANDLE aNewSecionObject);
|
||||
// Replace |sSectionHandle| with a given handle.
|
||||
static void Reset(HANDLE aNewSecionObject = sSectionHandle);
|
||||
|
||||
// Replace |sSectionHandle| with a new readonly handle.
|
||||
static void ConvertToReadOnly();
|
||||
|
||||
// Create a new writable section and initialize the Kernel32ExportsSolver
|
||||
// part.
|
||||
static LauncherVoidResult Init(const nt::PEHeaders& aPEHeaders);
|
||||
|
||||
// Append a new string to the |sSectionHandle|
|
||||
static LauncherVoidResult AddDepenentModule(PCUNICODE_STRING aNtPath);
|
||||
|
||||
// Map |sSectionHandle| to a copy-on-write page and return its address.
|
||||
static LauncherResult<Layout*> GetView();
|
||||
|
||||
// Transfer |sSectionHandle| to a process associated with |aTransferMgr|.
|
||||
static LauncherVoidResult TransferHandle(
|
||||
nt::CrossExecTransferManager& aTransferMgr,
|
||||
nt::CrossExecTransferManager& aTransferMgr, DWORD aDesiredAccess,
|
||||
HANDLE* aDestinationAddress = &sSectionHandle);
|
||||
};
|
||||
|
||||
extern SharedSection gSharedSection;
|
||||
extern RTL_RUN_ONCE gK32ExportsResolveOnce;
|
||||
|
||||
} // namespace freestanding
|
||||
} // namespace mozilla
|
||||
|
|
|
@ -5,28 +5,20 @@
|
|||
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#define MOZ_USE_LAUNCHER_ERROR
|
||||
#define DONT_SKIP_DEFAULT_DEPENDENT_MODULES
|
||||
|
||||
#include "freestanding/SharedSection.cpp"
|
||||
#include "mozilla/CmdLineAndEnvUtils.h"
|
||||
#include "mozilla/NativeNt.h"
|
||||
|
||||
const wchar_t kChildArg[] = L"--child";
|
||||
|
||||
#if !defined(__MINGW32__)
|
||||
// MinGW includes an old winternl.h that defines FILE_BASIC_INFORMATION.
|
||||
typedef struct FILE_BASIC_INFORMATION {
|
||||
LARGE_INTEGER CreationTime;
|
||||
LARGE_INTEGER LastAccessTime;
|
||||
LARGE_INTEGER LastWriteTime;
|
||||
LARGE_INTEGER ChangeTime;
|
||||
ULONG FileAttributes;
|
||||
} FILE_BASIC_INFORMATION, *PFILE_BASIC_INFORMATION;
|
||||
#endif // !defined(__MINGW32__)
|
||||
|
||||
extern "C" NTSTATUS NTAPI
|
||||
NtQueryAttributesFile(POBJECT_ATTRIBUTES aObjectAttributes,
|
||||
PFILE_BASIC_INFORMATION aFileInformation);
|
||||
const char kTestStrings[][6] = {
|
||||
"a b c", "A B C", "a b c", "A B C", "X Y Z",
|
||||
};
|
||||
const wchar_t kTestStringsMerged[] =
|
||||
L"a b c"
|
||||
L"\0"
|
||||
L"X Y Z"
|
||||
L"\0";
|
||||
|
||||
using namespace mozilla;
|
||||
using namespace mozilla::freestanding;
|
||||
|
@ -65,32 +57,55 @@ static bool VerifySharedSection(SharedSection& aSharedSection) {
|
|||
|
||||
HMODULE k32mod = ::GetModuleHandleW(L"kernel32.dll");
|
||||
VERIFY_FUNCTION_RESOLVED(k32mod, view->mK32Exports, FlushInstructionCache);
|
||||
VERIFY_FUNCTION_RESOLVED(k32mod, view->mK32Exports, GetModuleHandleW);
|
||||
VERIFY_FUNCTION_RESOLVED(k32mod, view->mK32Exports, GetSystemInfo);
|
||||
VERIFY_FUNCTION_RESOLVED(k32mod, view->mK32Exports, VirtualProtect);
|
||||
|
||||
const uint8_t* const arrayBase =
|
||||
reinterpret_cast<const uint8_t*>(view->mModulePathArray);
|
||||
for (uint32_t i = 0; i < view->mModulePathArrayLength; ++i) {
|
||||
uint32_t offset = view->mModulePathArray[i];
|
||||
// Use NtQueryAttributesFile to check the validity of an NT path.
|
||||
UNICODE_STRING ntpath;
|
||||
::RtlInitUnicodeString(
|
||||
&ntpath, reinterpret_cast<const wchar_t*>(arrayBase + offset));
|
||||
OBJECT_ATTRIBUTES oa;
|
||||
InitializeObjectAttributes(&oa, &ntpath, OBJ_CASE_INSENSITIVE, nullptr,
|
||||
nullptr);
|
||||
FILE_BASIC_INFORMATION info;
|
||||
NTSTATUS status = ::NtQueryAttributesFile(&oa, &info);
|
||||
if (!NT_SUCCESS(status)) {
|
||||
printf(
|
||||
"TEST-FAILED | TestCrossProcessWin | "
|
||||
"Invalid path %ls - %08lx.\n",
|
||||
ntpath.Buffer, status);
|
||||
return false;
|
||||
bool matched = memcmp(view->mModulePathArray, kTestStringsMerged,
|
||||
sizeof(kTestStringsMerged)) == 0;
|
||||
if (!matched) {
|
||||
// Print actual strings on error
|
||||
for (const wchar_t* p = view->mModulePathArray; *p;) {
|
||||
printf("%p: %ls\n", p, p);
|
||||
while (*p) {
|
||||
++p;
|
||||
}
|
||||
++p;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
printf("%p: %ls\n", &offset,
|
||||
reinterpret_cast<const wchar_t*>(arrayBase + offset));
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool TestAddString() {
|
||||
wchar_t testBuffer[3] = {0};
|
||||
UNICODE_STRING ustr;
|
||||
|
||||
// This makes |testBuffer| full.
|
||||
::RtlInitUnicodeString(&ustr, L"a");
|
||||
if (!AddString(testBuffer, sizeof(testBuffer), ustr)) {
|
||||
printf(
|
||||
"TEST-FAILED | TestCrossProcessWin | "
|
||||
"AddString failed.\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Adding a string to a full buffer should fail.
|
||||
::RtlInitUnicodeString(&ustr, L"b");
|
||||
if (AddString(testBuffer, sizeof(testBuffer), ustr)) {
|
||||
printf(
|
||||
"TEST-FAILED | TestCrossProcessWin | "
|
||||
"AddString caused OOB memory access.\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
bool matched = memcmp(testBuffer, L"a\0", sizeof(testBuffer)) == 0;
|
||||
if (!matched) {
|
||||
printf(
|
||||
"TEST-FAILED | TestCrossProcessWin | "
|
||||
"AddString wrote wrong values.\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
|
@ -133,7 +148,7 @@ class ChildProcess final {
|
|||
}
|
||||
|
||||
auto getDependentModulePaths =
|
||||
reinterpret_cast<uint32_t (*)(uint32_t**)>(::GetProcAddress(
|
||||
reinterpret_cast<const wchar_t (*)()>(::GetProcAddress(
|
||||
::GetModuleHandleW(nullptr), "GetDependentModulePaths"));
|
||||
if (!getDependentModulePaths) {
|
||||
printf(
|
||||
|
@ -146,8 +161,7 @@ class ChildProcess final {
|
|||
#if !defined(DEBUG)
|
||||
// GetDependentModulePaths does not allow a caller other than xul.dll.
|
||||
// Skip on Debug build because it hits MOZ_ASSERT.
|
||||
uint32_t* modulePathArray;
|
||||
if (getDependentModulePaths(&modulePathArray) || modulePathArray) {
|
||||
if (getDependentModulePaths()) {
|
||||
printf(
|
||||
"TEST-FAILED | TestCrossProcessWin | "
|
||||
"GetDependentModulePaths should return zero if the caller is "
|
||||
|
@ -160,17 +174,27 @@ class ChildProcess final {
|
|||
return 1;
|
||||
}
|
||||
|
||||
// Test a scenario to transfer a transferred section
|
||||
// Test a scenario to transfer a transferred section as a readonly handle
|
||||
static HANDLE copiedHandle = nullptr;
|
||||
nt::CrossExecTransferManager tansferToSelf(::GetCurrentProcess());
|
||||
LauncherVoidResult result =
|
||||
gSharedSection.TransferHandle(tansferToSelf, &copiedHandle);
|
||||
LauncherVoidResult result = gSharedSection.TransferHandle(
|
||||
tansferToSelf, GENERIC_READ, &copiedHandle);
|
||||
if (result.isErr()) {
|
||||
PrintLauncherError(result, "SharedSection::TransferHandle(self) failed");
|
||||
return 1;
|
||||
}
|
||||
|
||||
gSharedSection.Reset(copiedHandle);
|
||||
|
||||
UNICODE_STRING ustr;
|
||||
::RtlInitUnicodeString(&ustr, L"test");
|
||||
result = gSharedSection.AddDepenentModule(&ustr);
|
||||
if (result.inspectErr() !=
|
||||
WindowsError::FromWin32Error(ERROR_ACCESS_DENIED)) {
|
||||
PrintLauncherError(result, "The readonly section was writable");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!VerifySharedSection(gSharedSection)) {
|
||||
return 1;
|
||||
}
|
||||
|
@ -253,6 +277,10 @@ int wmain(int argc, wchar_t* argv[]) {
|
|||
return 1;
|
||||
}
|
||||
|
||||
if (!TestAddString()) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
LauncherResult<HMODULE> remoteImageBase =
|
||||
nt::GetProcessExeModule(childProcess);
|
||||
if (remoteImageBase.isErr()) {
|
||||
|
@ -312,7 +340,17 @@ int wmain(int argc, wchar_t* argv[]) {
|
|||
return 1;
|
||||
}
|
||||
|
||||
result = gSharedSection.TransferHandle(transferMgr);
|
||||
for (const auto& testString : kTestStrings) {
|
||||
nt::AllocatedUnicodeString ustr(testString);
|
||||
result = gSharedSection.AddDepenentModule(ustr);
|
||||
if (result.isErr()) {
|
||||
PrintLauncherError(result, "SharedSection::AddDepenentModule failed");
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
result = gSharedSection.TransferHandle(transferMgr,
|
||||
GENERIC_READ | GENERIC_WRITE);
|
||||
if (result.isErr()) {
|
||||
PrintLauncherError(result, "SharedSection::TransferHandle failed");
|
||||
return 1;
|
||||
|
|
|
@ -255,13 +255,19 @@
|
|||
<span class="origin-label field-label" data-l10n-id="login-item-origin-label"></span>
|
||||
<!-- Default text inputs to readonly to reduce jumping of the field
|
||||
size on page load since it always starts readonly. -->
|
||||
|
||||
<input type="url"
|
||||
name="origin"
|
||||
required
|
||||
data-l10n-id="login-item-origin"
|
||||
dir="auto"
|
||||
readonly/>
|
||||
name="origin"
|
||||
required
|
||||
data-l10n-id="login-item-origin"
|
||||
dir="auto"
|
||||
readonly/>
|
||||
<a class="origin-input" dir="auto" target="_blank" rel="noreferrer" name="origin" href=""></a>
|
||||
<div class="tooltip-container">
|
||||
<div class="arrow-box">
|
||||
<p class="tooltip-message" data-l10n-id="login-item-tooltip-message"></p>
|
||||
</div>
|
||||
</div>
|
||||
</label>
|
||||
</div>
|
||||
<div class="detail-grid">
|
||||
|
|
|
@ -149,6 +149,57 @@ input[type="url"]:read-only:hover:active {
|
|||
color: var(--in-content-link-color-active) !important;
|
||||
}
|
||||
|
||||
input[type = "url"]:focus:not(:-moz-ui-invalid):invalid ~ .tooltip-container {
|
||||
display: block;
|
||||
}
|
||||
|
||||
input[type = "url"]:focus:-moz-ui-invalid:not(:placeholder-shown) ~ .tooltip-container {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.tooltip-container {
|
||||
display: none;
|
||||
position: absolute;
|
||||
inset-inline-start: 315px;
|
||||
width: 232px;
|
||||
box-shadow: 2px 2px 10px 1px rgba(0,0,0,0.18);
|
||||
top: 0;
|
||||
}
|
||||
|
||||
.tooltip-message {
|
||||
margin: 0;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.arrow-box {
|
||||
position: relative;
|
||||
padding: 12px;
|
||||
background: var(--in-content-box-background);
|
||||
border: 1px solid var(--in-content-border-color);
|
||||
}
|
||||
|
||||
.arrow-box::after, .arrow-box::before {
|
||||
inset-inline-end: 100%;
|
||||
top: 40px; /* This allows the arrow to stay in the correct position, even if the text length is changed */
|
||||
border: solid transparent;
|
||||
content: "";
|
||||
height: 0;
|
||||
width: 0;
|
||||
position: absolute;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.arrow-box::after {
|
||||
border-inline-end-color: var(--in-content-box-background);
|
||||
border-width: 10px;
|
||||
margin-top: -10px;
|
||||
}
|
||||
.arrow-box::before {
|
||||
border-inline-end-color: var(--in-content-border-color);
|
||||
border-width: 11px;
|
||||
margin-top: -11px;
|
||||
}
|
||||
|
||||
.reveal-password-wrapper {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
@ -184,6 +235,7 @@ input[type="url"]:read-only:hover:active {
|
|||
|
||||
.detail-row {
|
||||
display: flex;
|
||||
position: relative; /* Allows for the hint message to be positioned correctly */
|
||||
}
|
||||
|
||||
.detail-grid,
|
||||
|
|
|
@ -397,6 +397,10 @@ DownloadsPlacesView.prototype = {
|
|||
},
|
||||
set searchTerm(aValue) {
|
||||
if (this._searchTerm != aValue) {
|
||||
// Always clear selection on a new search, since the user is starting a
|
||||
// different workflow. This also solves the fact we could end up
|
||||
// retaining selection on hidden elements.
|
||||
this._richlistbox.clearSelection();
|
||||
for (let element of this._richlistbox.childNodes) {
|
||||
element.hidden = !element._shell.matchesSearchTerm(aValue);
|
||||
}
|
||||
|
@ -678,7 +682,23 @@ DownloadsPlacesView.prototype = {
|
|||
},
|
||||
|
||||
cmd_selectAll() {
|
||||
this._richlistbox.selectAll();
|
||||
if (!this.searchTerm) {
|
||||
this._richlistbox.selectAll();
|
||||
return;
|
||||
}
|
||||
// If there is a filtering search term, some rows are hidden and should not
|
||||
// be selected.
|
||||
let oldSuppressOnSelect = this._richlistbox.suppressOnSelect;
|
||||
this._richlistbox.suppressOnSelect = true;
|
||||
this._richlistbox.clearSelection();
|
||||
var item = this._richlistbox.getItemAtIndex(0);
|
||||
while (item) {
|
||||
if (!item.hidden) {
|
||||
this._richlistbox.addItemToSelection(item);
|
||||
}
|
||||
item = this._richlistbox.getNextItem(item, 1);
|
||||
}
|
||||
this._richlistbox.suppressOnSelect = oldSuppressOnSelect;
|
||||
},
|
||||
|
||||
cmd_paste() {
|
||||
|
|
|
@ -15,6 +15,7 @@ support-files =
|
|||
not-really-a-jpeg.jpeg
|
||||
not-really-a-jpeg.jpeg^headers^
|
||||
blank.JPG
|
||||
[browser_library_select_all.js]
|
||||
[browser_overflow_anchor.js]
|
||||
skip-if = os == "linux" # Bug 952422
|
||||
[browser_confirm_unblock_download.js]
|
||||
|
|
|
@ -0,0 +1,77 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
let gDownloadDir;
|
||||
|
||||
add_task(async function setup() {
|
||||
await task_resetState();
|
||||
|
||||
if (!gDownloadDir) {
|
||||
gDownloadDir = await setDownloadDir();
|
||||
}
|
||||
|
||||
await task_addDownloads([
|
||||
{
|
||||
state: DownloadsCommon.DOWNLOAD_FINISHED,
|
||||
target: await createDownloadedFile(
|
||||
PathUtils.join(gDownloadDir, "downloaded_one.txt"),
|
||||
"Test file 1"
|
||||
),
|
||||
},
|
||||
{
|
||||
state: DownloadsCommon.DOWNLOAD_FINISHED,
|
||||
target: await createDownloadedFile(
|
||||
PathUtils.join(gDownloadDir, "downloaded_two.txt"),
|
||||
"Test file 2"
|
||||
),
|
||||
},
|
||||
]);
|
||||
registerCleanupFunction(async function() {
|
||||
await task_resetState();
|
||||
await PlacesUtils.history.clear();
|
||||
});
|
||||
});
|
||||
|
||||
add_task(async function test_select_all() {
|
||||
let win = await openLibrary("Downloads");
|
||||
registerCleanupFunction(() => {
|
||||
win.close();
|
||||
});
|
||||
|
||||
let listbox = win.document.getElementById("downloadsRichListBox");
|
||||
Assert.ok(listbox, "download list box present");
|
||||
listbox.focus();
|
||||
await TestUtils.waitForCondition(
|
||||
() => listbox.children.length == 2 && listbox.selectedItems.length == 1,
|
||||
"waiting for both items to be present with one selected"
|
||||
);
|
||||
info("Select all the downloads");
|
||||
win.goDoCommand("cmd_selectAll");
|
||||
Assert.equal(
|
||||
listbox.selectedItems.length,
|
||||
listbox.children.length,
|
||||
"All the items should be selected"
|
||||
);
|
||||
|
||||
info("Search for a specific download");
|
||||
let searchBox = win.document.getElementById("searchFilter");
|
||||
searchBox.value = "_one";
|
||||
win.PlacesSearchBox.search(searchBox.value);
|
||||
await TestUtils.waitForCondition(() => {
|
||||
let visibleItems = Array.from(listbox.children).filter(c => !c.hidden);
|
||||
return (
|
||||
visibleItems.length == 1 &&
|
||||
visibleItems[0]._shell.download.target.path.includes("_one")
|
||||
);
|
||||
}, "Waiting for the search to complete");
|
||||
Assert.equal(
|
||||
listbox.selectedItems.length,
|
||||
0,
|
||||
"Check previous selection has been cleared by the search"
|
||||
);
|
||||
info("Select all the downloads");
|
||||
win.goDoCommand("cmd_selectAll");
|
||||
Assert.equal(listbox.children.length, 2, "Both items are present");
|
||||
Assert.equal(listbox.selectedItems.length, 1, "Only one item is selected");
|
||||
Assert.ok(!listbox.selectedItem.hidden, "The selected item is not hidden");
|
||||
});
|
После Ширина: | Высота: | Размер: 15 KiB |
После Ширина: | Высота: | Размер: 4.2 KiB |
После Ширина: | Высота: | Размер: 34 KiB |
После Ширина: | Высота: | Размер: 3.9 KiB |
После Ширина: | Высота: | Размер: 1.1 KiB |
После Ширина: | Высота: | Размер: 4.2 KiB |
После Ширина: | Высота: | Размер: 3.7 KiB |
После Ширина: | Высота: | Размер: 1.7 KiB |
После Ширина: | Высота: | Размер: 1.0 KiB |
После Ширина: | Высота: | Размер: 14 KiB |
После Ширина: | Высота: | Размер: 4.0 KiB |
После Ширина: | Высота: | Размер: 12 KiB |
После Ширина: | Высота: | Размер: 28 KiB |
После Ширина: | Высота: | Размер: 5.0 KiB |
После Ширина: | Высота: | Размер: 3.3 KiB |
После Ширина: | Высота: | Размер: 12 KiB |
После Ширина: | Высота: | Размер: 6.9 KiB |
После Ширина: | Высота: | Размер: 8.5 KiB |
|
@ -1,4 +1,10 @@
|
|||
[
|
||||
{
|
||||
"title": "adidas",
|
||||
"urls": ["https://www.adidas.co.uk/", "https://www.adidas.de/", "https://www.adidas.fr/"],
|
||||
"image_url": "images/adidas@2x.jpg",
|
||||
"favicon_url": "favicons/adidas.ico"
|
||||
},
|
||||
{
|
||||
"title": "aliexpress",
|
||||
"url": "https://www.aliexpress.com/",
|
||||
|
@ -59,18 +65,36 @@
|
|||
"image_url": "images/ebay@2x.png",
|
||||
"favicon_url": "favicons/ebay.ico"
|
||||
},
|
||||
{
|
||||
"title": "etsy",
|
||||
"url": "https://www.etsy.com/",
|
||||
"image_url": "images/etsy@2x.jpg",
|
||||
"favicon_url": "favicons/etsy.ico"
|
||||
},
|
||||
{
|
||||
"title": "facebook",
|
||||
"url": "https://www.facebook.com/",
|
||||
"image_url": "images/facebook-com@2x.png",
|
||||
"favicon_url": "favicons/facebook-com.ico"
|
||||
},
|
||||
{
|
||||
"title": "geico",
|
||||
"url": "https://www.geico.com/",
|
||||
"image_url": "images/geico@2x.jpg",
|
||||
"favicon_url": "favicons/geico.ico"
|
||||
},
|
||||
{
|
||||
"title": "google",
|
||||
"url": "https://www.google.com/",
|
||||
"image_url": "images/google-com@2x.png",
|
||||
"favicon_url": "favicons/google-com.ico"
|
||||
},
|
||||
{
|
||||
"title": "hrblock",
|
||||
"url": "https://www.hrblock.com/",
|
||||
"image_url": "images/hrblock@2x.jpg",
|
||||
"favicon_url": "favicons/hrblock.ico"
|
||||
},
|
||||
{
|
||||
"title": "ifeng",
|
||||
"url": "https://www.ifeng.com/",
|
||||
|
@ -89,6 +113,12 @@
|
|||
"image_url": "images/leboncoin-fr@2x.png",
|
||||
"favicon_url": "favicons/leboncoin-fr.png"
|
||||
},
|
||||
{
|
||||
"title": "nike",
|
||||
"url": "https://www.nike.com/",
|
||||
"image_url": "images/nike@2x.jpg",
|
||||
"favicon_url": "favicons/nike.ico"
|
||||
},
|
||||
{
|
||||
"title": "ok",
|
||||
"url": "https://www.ok.ru/",
|
||||
|
@ -107,6 +137,18 @@
|
|||
"image_url": "images/reddit-com@2x.png",
|
||||
"favicon_url": "favicons/reddit-com.png"
|
||||
},
|
||||
{
|
||||
"title": "samsung",
|
||||
"url": "https://samsung.com/",
|
||||
"image_url": "images/samsung@2x.jpg",
|
||||
"favicon_url": "favicons/samsung.ico"
|
||||
},
|
||||
{
|
||||
"title": "turbotax",
|
||||
"url": "https://turbotax.intuit.com/",
|
||||
"image_url": "images/turbotax@2x.jpg",
|
||||
"favicon_url": "favicons/turbotax.png"
|
||||
},
|
||||
{
|
||||
"title": "twitter",
|
||||
"url": "https://twitter.com/",
|
||||
|
@ -119,6 +161,12 @@
|
|||
"image_url": "images/vk-com@2x.png",
|
||||
"favicon_url": "favicons/vk-com.ico"
|
||||
},
|
||||
{
|
||||
"title": "vodafone",
|
||||
"url": "https://www.vodafone.co.uk/",
|
||||
"image_url": "images/vodafone@2x.jpg",
|
||||
"favicon_url": "favicons/vodafone.png"
|
||||
},
|
||||
{
|
||||
"title": "weibo",
|
||||
"url": "https://weibo.com/",
|
||||
|
@ -131,6 +179,12 @@
|
|||
"image_url": "images/wikipedia-org@2x.png",
|
||||
"favicon_url": "favicons/wikipedia-org.ico"
|
||||
},
|
||||
{
|
||||
"title": "wix",
|
||||
"url": "https://www.wix.com/",
|
||||
"image_url": "images/wix@2x.jpg",
|
||||
"favicon_url": "favicons/wix.ico"
|
||||
},
|
||||
{
|
||||
"title": "wykop",
|
||||
"url": "https://www.wykop.pl/",
|
||||
|
|
|
@ -75,6 +75,7 @@ login-item-new-login-title = Create New Login
|
|||
login-item-edit-button = Edit
|
||||
about-logins-login-item-remove-button = Remove
|
||||
login-item-origin-label = Website address
|
||||
login-item-tooltip-message = Make sure this matches the exact address of the website where you log in.
|
||||
login-item-origin =
|
||||
.placeholder = https://www.example.com
|
||||
login-item-username-label = Username
|
||||
|
|
|
@ -1,11 +0,0 @@
|
|||
{
|
||||
"stages": "2",
|
||||
"build_libcxx": false,
|
||||
"build_type": "Release",
|
||||
"assertions": false,
|
||||
"python_path": "c:/mozilla-build/python/python.exe",
|
||||
"cc": "cl.exe",
|
||||
"cxx": "cl.exe",
|
||||
"ml": "ml64.exe",
|
||||
"patches": []
|
||||
}
|
|
@ -1,19 +0,0 @@
|
|||
{
|
||||
"stages": "4",
|
||||
"pgo" : true,
|
||||
"build_libcxx": false,
|
||||
"build_type": "Release",
|
||||
"assertions": false,
|
||||
"python_path": "c:/mozilla-build/python/python.exe",
|
||||
"cc": "cl.exe",
|
||||
"cxx": "cl.exe",
|
||||
"ml": "ml64.exe",
|
||||
"patches": [
|
||||
"unpoison-thread-stacks.patch",
|
||||
"downgrade-mangling-error.patch",
|
||||
"rG7e18aeba5062.patch",
|
||||
"llvmorg-10-init-5191-ga84b200e604-windows-pgo.patch",
|
||||
"llvmorg-11-init-15486-gfc937806efd-dont-jump-to-landing-pads.patch",
|
||||
"loosen-msvc-detection.patch"
|
||||
]
|
||||
}
|
|
@ -1,115 +0,0 @@
|
|||
[cmake] Changes to get Windows self-host working with PGO
|
||||
|
||||
Fixes quoting of profile arguments to work on Windows
|
||||
Suppresses adding profile arguments to linker flags when using lld-link
|
||||
Avoids -fprofile-instr-use being added to rc.exe flags
|
||||
Removes duplicated adding of -fprofile-instr-use to linker flags (since
|
||||
r355541)
|
||||
Move handling LLVM_PROFDATA_FILE to HandleLLVMOptions.cmake
|
||||
|
||||
Differential Revision: https://reviews.llvm.org/D62063
|
||||
|
||||
llvm-svn: 372209
|
||||
|
||||
diff --git a/llvm/CMakeLists.txt b/llvm/CMakeLists.txt
|
||||
index b9a10685b99..73f8664cdcf 100644
|
||||
--- a/llvm/CMakeLists.txt
|
||||
+++ b/llvm/CMakeLists.txt
|
||||
@@ -612,6 +612,9 @@ mark_as_advanced(LLVM_TARGET_TRIPLE_ENV)
|
||||
set(LLVM_ENABLE_PER_TARGET_RUNTIME_DIR OFF CACHE BOOL
|
||||
"Enable per-target runtimes directory")
|
||||
|
||||
+set(LLVM_PROFDATA_FILE "" CACHE FILEPATH
|
||||
+ "Profiling data file to use when compiling in order to improve runtime performance.")
|
||||
+
|
||||
# All options referred to from HandleLLVMOptions have to be specified
|
||||
# BEFORE this include, otherwise options will not be correctly set on
|
||||
# first cmake run
|
||||
@@ -873,17 +876,6 @@ endif( ${CMAKE_SYSTEM_NAME} MATCHES SunOS )
|
||||
# use export_executable_symbols(target).
|
||||
set(CMAKE_SHARED_LIBRARY_LINK_CXX_FLAGS "")
|
||||
|
||||
-set(LLVM_PROFDATA_FILE "" CACHE FILEPATH
|
||||
- "Profiling data file to use when compiling in order to improve runtime performance.")
|
||||
-
|
||||
-if(LLVM_PROFDATA_FILE AND EXISTS ${LLVM_PROFDATA_FILE})
|
||||
- if ("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang" )
|
||||
- add_definitions("-fprofile-instr-use=${LLVM_PROFDATA_FILE}")
|
||||
- else()
|
||||
- message(FATAL_ERROR "LLVM_PROFDATA_FILE can only be specified when compiling with clang")
|
||||
- endif()
|
||||
-endif()
|
||||
-
|
||||
include(AddLLVM)
|
||||
include(TableGen)
|
||||
|
||||
diff --git a/llvm/cmake/modules/HandleLLVMOptions.cmake b/llvm/cmake/modules/HandleLLVMOptions.cmake
|
||||
index 4425eb91a5f..2e780d56254 100644
|
||||
--- a/llvm/cmake/modules/HandleLLVMOptions.cmake
|
||||
+++ b/llvm/cmake/modules/HandleLLVMOptions.cmake
|
||||
@@ -846,32 +846,48 @@ string(TOUPPER "${LLVM_BUILD_INSTRUMENTED}" uppercase_LLVM_BUILD_INSTRUMENTED)
|
||||
|
||||
if (LLVM_BUILD_INSTRUMENTED)
|
||||
if (LLVM_ENABLE_IR_PGO OR uppercase_LLVM_BUILD_INSTRUMENTED STREQUAL "IR")
|
||||
- append("-fprofile-generate='${LLVM_PROFILE_DATA_DIR}'"
|
||||
+ append("-fprofile-generate=\"${LLVM_PROFILE_DATA_DIR}\""
|
||||
CMAKE_CXX_FLAGS
|
||||
- CMAKE_C_FLAGS
|
||||
- CMAKE_EXE_LINKER_FLAGS
|
||||
- CMAKE_SHARED_LINKER_FLAGS)
|
||||
+ CMAKE_C_FLAGS)
|
||||
+ if(NOT LINKER_IS_LLD_LINK)
|
||||
+ append("-fprofile-generate=\"${LLVM_PROFILE_DATA_DIR}\""
|
||||
+ CMAKE_EXE_LINKER_FLAGS
|
||||
+ CMAKE_SHARED_LINKER_FLAGS)
|
||||
+ endif()
|
||||
elseif(uppercase_LLVM_BUILD_INSTRUMENTED STREQUAL "CSIR")
|
||||
- append("-fcs-profile-generate='${LLVM_CSPROFILE_DATA_DIR}'"
|
||||
+ append("-fcs-profile-generate=\"${LLVM_CSPROFILE_DATA_DIR}\""
|
||||
CMAKE_CXX_FLAGS
|
||||
- CMAKE_C_FLAGS
|
||||
- CMAKE_EXE_LINKER_FLAGS
|
||||
- CMAKE_SHARED_LINKER_FLAGS)
|
||||
+ CMAKE_C_FLAGS)
|
||||
+ if(NOT LINKER_IS_LLD_LINK)
|
||||
+ append("-fcs-profile-generate=\"${LLVM_CSPROFILE_DATA_DIR}\""
|
||||
+ CMAKE_EXE_LINKER_FLAGS
|
||||
+ CMAKE_SHARED_LINKER_FLAGS)
|
||||
+ endif()
|
||||
else()
|
||||
- append("-fprofile-instr-generate='${LLVM_PROFILE_FILE_PATTERN}'"
|
||||
+ append("-fprofile-instr-generate=\"${LLVM_PROFILE_FILE_PATTERN}\""
|
||||
CMAKE_CXX_FLAGS
|
||||
- CMAKE_C_FLAGS
|
||||
- CMAKE_EXE_LINKER_FLAGS
|
||||
- CMAKE_SHARED_LINKER_FLAGS)
|
||||
+ CMAKE_C_FLAGS)
|
||||
+ if(NOT LINKER_IS_LLD_LINK)
|
||||
+ append("-fprofile-instr-generate=\"${LLVM_PROFILE_FILE_PATTERN}\""
|
||||
+ CMAKE_EXE_LINKER_FLAGS
|
||||
+ CMAKE_SHARED_LINKER_FLAGS)
|
||||
+ endif()
|
||||
endif()
|
||||
endif()
|
||||
|
||||
-# Need to pass -fprofile-instr-use to linker for context-sensitive PGO
|
||||
-# compilation.
|
||||
if(LLVM_PROFDATA_FILE AND EXISTS ${LLVM_PROFDATA_FILE})
|
||||
- append("-fprofile-instr-use='${LLVM_PROFDATA_FILE}'"
|
||||
- CMAKE_EXE_LINKER_FLAGS
|
||||
- CMAKE_SHARED_LINKER_FLAGS)
|
||||
+ if ("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang" )
|
||||
+ append("-fprofile-instr-use=\"${LLVM_PROFDATA_FILE}\""
|
||||
+ CMAKE_CXX_FLAGS
|
||||
+ CMAKE_C_FLAGS)
|
||||
+ if(NOT LINKER_IS_LLD_LINK)
|
||||
+ append("-fprofile-instr-use=\"${LLVM_PROFDATA_FILE}\""
|
||||
+ CMAKE_EXE_LINKER_FLAGS
|
||||
+ CMAKE_SHARED_LINKER_FLAGS)
|
||||
+ endif()
|
||||
+ else()
|
||||
+ message(FATAL_ERROR "LLVM_PROFDATA_FILE can only be specified when compiling with clang")
|
||||
+ endif()
|
||||
endif()
|
||||
|
||||
option(LLVM_BUILD_INSTRUMENTED_COVERAGE "Build LLVM and tools with Code Coverage instrumentation" Off)
|
|
@ -78,13 +78,13 @@ def generate(fd, consts_path, unicodes_path, template_path, compiler):
|
|||
#undef {name}
|
||||
static inline {ty} WINAPI
|
||||
{name}({params})
|
||||
{{
|
||||
#ifdef UNICODE
|
||||
{{
|
||||
return {name}W({args});
|
||||
#else
|
||||
return {name}A({args});
|
||||
#endif
|
||||
}}
|
||||
#else
|
||||
= delete;
|
||||
#endif
|
||||
#endif
|
||||
""".format(
|
||||
ty=ty, name=name, params=params, args=args
|
||||
|
|
|
@ -146,6 +146,14 @@ rust_cc_env_name := $(subst -,_,$(RUST_TARGET))
|
|||
export CC_$(rust_cc_env_name)=$(filter-out $(CC_BASE_FLAGS),$(CC))
|
||||
export CXX_$(rust_cc_env_name)=$(filter-out $(CXX_BASE_FLAGS),$(CXX))
|
||||
export AR_$(rust_cc_env_name)=$(AR)
|
||||
|
||||
ifeq (WINNT,$(HOST_OS_ARCH))
|
||||
HOST_CC_BASE_FLAGS += -DUNICODE
|
||||
HOST_CXX_BASE_FLAGS += -DUNICODE
|
||||
CC_BASE_FLAGS += -DUNICODE
|
||||
CXX_BASE_FLAGS += -DUNICODE
|
||||
endif
|
||||
|
||||
ifeq (,$(NATIVE_SANITIZERS)$(MOZ_CODE_COVERAGE))
|
||||
# -DMOZILLA_CONFIG_H is added to prevent mozilla-config.h from injecting anything
|
||||
# in C/C++ compiles from rust. That's not needed in the other branch because the
|
||||
|
|
|
@ -171,6 +171,11 @@ widget/android/export: mobile/android/base/export
|
|||
# android_apks is not built on artifact builds without this dependency.
|
||||
mobile/android/base/export: mobile/android/base/android_apks
|
||||
|
||||
# This is required so that the pre-export tier sees the rules in mobile/android/base
|
||||
ifeq ($(MOZ_WIDGET_TOOLKIT),android)
|
||||
recurse_pre-export:: mobile/android/base/pre-export
|
||||
endif
|
||||
|
||||
# CSS2Properties.webidl needs ServoCSSPropList.py from layout/style
|
||||
dom/bindings/export: layout/style/ServoCSSPropList.py
|
||||
|
||||
|
|
|
@ -122,7 +122,33 @@ const TEST_DATA = [
|
|||
}`
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
selector: "#doublebind",
|
||||
expected: [
|
||||
{
|
||||
type: "click",
|
||||
filename: TEST_LIB + ":93:417",
|
||||
attributes: [
|
||||
"Bubbling",
|
||||
"DOM2"
|
||||
],
|
||||
handler: `function() {}`
|
||||
},
|
||||
{
|
||||
type: "onClick",
|
||||
filename: TEST_URL + ":21:22",
|
||||
attributes: [
|
||||
"Bubbling",
|
||||
"React"
|
||||
],
|
||||
handler: `
|
||||
function() {
|
||||
alert("inlineFunction");
|
||||
}`
|
||||
}
|
||||
]
|
||||
},
|
||||
];
|
||||
/* eslint-enable */
|
||||
|
||||
|
|
|
@ -58,6 +58,14 @@
|
|||
onClickCapture: externalCapturingFunction
|
||||
},
|
||||
"Click for externalCapturingFunction"
|
||||
),
|
||||
React.createElement(
|
||||
"h3",
|
||||
{
|
||||
id: "doublebind",
|
||||
onClick: this.inlineFunction.bind(this).bind(this)
|
||||
},
|
||||
"Click for inlineFunction bound twice"
|
||||
)
|
||||
);
|
||||
}
|
||||
|
|
|
@ -730,8 +730,10 @@ class ReactEventCollector extends MainEventCollector {
|
|||
handlerDO = handlerDO.boundTargetFunction;
|
||||
}
|
||||
|
||||
const introScript = handlerDO.script.source.introductionScript;
|
||||
const script = handlerDO.script;
|
||||
// Script might be undefined (eg for methods bound several times, see
|
||||
// https://bugzilla.mozilla.org/show_bug.cgi?id=1589658)
|
||||
const introScript = script?.source.introductionScript;
|
||||
|
||||
// If this is a Babel transpiled function we have no access to the
|
||||
// source location so we need to hide the filename and debugger
|
||||
|
|
|
@ -96,13 +96,7 @@ class InactivePropertyHelper {
|
|||
},
|
||||
// Flex item property used on non-flex item.
|
||||
{
|
||||
invalidProperties: [
|
||||
"flex",
|
||||
"flex-basis",
|
||||
"flex-grow",
|
||||
"flex-shrink",
|
||||
"order",
|
||||
],
|
||||
invalidProperties: ["flex", "flex-basis", "flex-grow", "flex-shrink"],
|
||||
when: () => !this.flexItem,
|
||||
fixId: "inactive-css-not-flex-item-fix-2",
|
||||
msgId: "inactive-css-not-flex-item",
|
||||
|
@ -141,7 +135,7 @@ class InactivePropertyHelper {
|
|||
},
|
||||
// Grid and flex item properties used on non-grid or non-flex item.
|
||||
{
|
||||
invalidProperties: ["align-self", "place-self"],
|
||||
invalidProperties: ["align-self", "place-self", "order"],
|
||||
when: () =>
|
||||
!this.gridItem && !this.flexItem && !this.isAbsPosGridElement(),
|
||||
fixId: "inactive-css-not-grid-or-flex-item-fix-2",
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
// InactivePropertyHelper `align-self` and `place-self` test cases.
|
||||
// InactivePropertyHelper `align-self`, `place-self`, and `order` test cases.
|
||||
export default [
|
||||
{
|
||||
info: "align-self is inactive on block element",
|
||||
|
@ -156,4 +156,74 @@ export default [
|
|||
ruleIndex: 1,
|
||||
isActive: true,
|
||||
},
|
||||
{
|
||||
info: "order is inactive on block element",
|
||||
property: "order",
|
||||
tagName: "div",
|
||||
rules: ["div { order: 1; }"],
|
||||
isActive: false,
|
||||
},
|
||||
{
|
||||
info: "order is inactive on flex container",
|
||||
property: "order",
|
||||
tagName: "div",
|
||||
rules: ["div { order: 1; display: flex;}"],
|
||||
isActive: false,
|
||||
},
|
||||
{
|
||||
info: "order is inactive on inline-flex container",
|
||||
property: "order",
|
||||
tagName: "div",
|
||||
rules: ["div { order: 1; display: inline-flex;}"],
|
||||
isActive: false,
|
||||
},
|
||||
{
|
||||
info: "order is inactive on grid container",
|
||||
property: "order",
|
||||
tagName: "div",
|
||||
rules: ["div { order: 1; display: grid;}"],
|
||||
isActive: false,
|
||||
},
|
||||
{
|
||||
info: "order is inactive on inline grid container",
|
||||
property: "order",
|
||||
tagName: "div",
|
||||
rules: ["div { order: 1; display: inline-grid;}"],
|
||||
isActive: false,
|
||||
},
|
||||
{
|
||||
info: "order is inactive on inline element",
|
||||
property: "order",
|
||||
tagName: "span",
|
||||
rules: ["span { order: 1; }"],
|
||||
isActive: false,
|
||||
},
|
||||
{
|
||||
info: "order is active on flex item",
|
||||
property: "order",
|
||||
createTestElement: rootNode => {
|
||||
const container = document.createElement("div");
|
||||
const element = document.createElement("span");
|
||||
container.append(element);
|
||||
rootNode.append(container);
|
||||
return element;
|
||||
},
|
||||
rules: ["div { display: flex; }", "span { order: 1; }"],
|
||||
ruleIndex: 1,
|
||||
isActive: true,
|
||||
},
|
||||
{
|
||||
info: "order is active on grid item",
|
||||
property: "order",
|
||||
createTestElement: rootNode => {
|
||||
const container = document.createElement("div");
|
||||
const element = document.createElement("span");
|
||||
container.append(element);
|
||||
rootNode.append(container);
|
||||
return element;
|
||||
},
|
||||
rules: ["div { display: grid; }", "span { order: 1; }"],
|
||||
ruleIndex: 1,
|
||||
isActive: true,
|
||||
},
|
||||
];
|
|
@ -43,7 +43,7 @@ SimpleTest.waitForExplicitFinish();
|
|||
// - {Boolean} isActive: should the property be active (isPropertyUsed `used` result).
|
||||
const testFiles = [
|
||||
"align-content.js",
|
||||
"align-place-self.js",
|
||||
"flex-grid-item-properties.js",
|
||||
"float.js",
|
||||
"gap.js",
|
||||
"grid-with-absolute-properties.js",
|
||||
|
|
|
@ -11,7 +11,6 @@ Cc["@mozilla.org/psm;1"].getService(Ci.nsISupports);
|
|||
|
||||
var Services = require("Services");
|
||||
var promise = require("promise");
|
||||
var defer = require("devtools/shared/defer");
|
||||
var DevToolsUtils = require("devtools/shared/DevToolsUtils");
|
||||
var { dumpn, dumpv } = DevToolsUtils;
|
||||
loader.lazyRequireGetter(
|
||||
|
@ -294,49 +293,48 @@ var _attemptConnect = async function({ host, port, encryption }) {
|
|||
clientCert = await cert.local.getOrCreate();
|
||||
}
|
||||
|
||||
const deferred = defer();
|
||||
let input;
|
||||
let output;
|
||||
// Delay opening the input stream until the transport has fully connected.
|
||||
// The goal is to avoid showing the user a client cert UI prompt when
|
||||
// encryption is used. This prompt is shown when the client opens the input
|
||||
// stream and does not know which client cert to present to the server. To
|
||||
// specify a client cert programmatically, we need to access the transport's
|
||||
// nsISSLSocketControl interface, which is not accessible until the transport
|
||||
// has connected.
|
||||
s.setEventSink(
|
||||
{
|
||||
onTransportStatus(transport, status) {
|
||||
if (status != Ci.nsISocketTransport.STATUS_CONNECTING_TO) {
|
||||
return;
|
||||
}
|
||||
if (encryption) {
|
||||
const sslSocketControl = transport.securityInfo.QueryInterface(
|
||||
Ci.nsISSLSocketControl
|
||||
);
|
||||
sslSocketControl.clientCert = clientCert;
|
||||
}
|
||||
try {
|
||||
input = s.openInputStream(0, 0, 0);
|
||||
} catch (e) {
|
||||
deferred.reject(e);
|
||||
}
|
||||
deferred.resolve({ s, input, output });
|
||||
return new Promise((resolve, reject) => {
|
||||
// Delay opening the input stream until the transport has fully connected.
|
||||
// The goal is to avoid showing the user a client cert UI prompt when
|
||||
// encryption is used. This prompt is shown when the client opens the input
|
||||
// stream and does not know which client cert to present to the server. To
|
||||
// specify a client cert programmatically, we need to access the transport's
|
||||
// nsISSLSocketControl interface, which is not accessible until the transport
|
||||
// has connected.
|
||||
s.setEventSink(
|
||||
{
|
||||
onTransportStatus(transport, status) {
|
||||
if (status != Ci.nsISocketTransport.STATUS_CONNECTING_TO) {
|
||||
return;
|
||||
}
|
||||
if (encryption) {
|
||||
const sslSocketControl = transport.securityInfo.QueryInterface(
|
||||
Ci.nsISSLSocketControl
|
||||
);
|
||||
sslSocketControl.clientCert = clientCert;
|
||||
}
|
||||
try {
|
||||
input = s.openInputStream(0, 0, 0);
|
||||
} catch (e) {
|
||||
reject(e);
|
||||
}
|
||||
resolve({ s, input, output });
|
||||
},
|
||||
},
|
||||
},
|
||||
Services.tm.currentThread
|
||||
);
|
||||
Services.tm.currentThread
|
||||
);
|
||||
|
||||
// openOutputStream may throw NS_ERROR_NOT_INITIALIZED if we hit some race
|
||||
// where the nsISocketTransport gets shutdown in between its instantiation and
|
||||
// the call to this method.
|
||||
try {
|
||||
output = s.openOutputStream(0, 0, 0);
|
||||
} catch (e) {
|
||||
deferred.reject(e);
|
||||
}
|
||||
|
||||
deferred.promise.catch(e => {
|
||||
// openOutputStream may throw NS_ERROR_NOT_INITIALIZED if we hit some race
|
||||
// where the nsISocketTransport gets shutdown in between its instantiation and
|
||||
// the call to this method.
|
||||
try {
|
||||
output = s.openOutputStream(0, 0, 0);
|
||||
} catch (e) {
|
||||
reject(e);
|
||||
}
|
||||
}).catch(e => {
|
||||
if (input) {
|
||||
input.close();
|
||||
}
|
||||
|
@ -345,8 +343,6 @@ var _attemptConnect = async function({ host, port, encryption }) {
|
|||
}
|
||||
DevToolsUtils.reportException("_attemptConnect", e);
|
||||
});
|
||||
|
||||
return deferred.promise;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -355,33 +351,33 @@ var _attemptConnect = async function({ host, port, encryption }) {
|
|||
* first connection to a new host because the cert is self-signed.
|
||||
*/
|
||||
function _isInputAlive(input) {
|
||||
const deferred = defer();
|
||||
input.asyncWait(
|
||||
{
|
||||
onInputStreamReady(stream) {
|
||||
try {
|
||||
stream.available();
|
||||
deferred.resolve({ alive: true });
|
||||
} catch (e) {
|
||||
return new Promise((resolve, reject) => {
|
||||
input.asyncWait(
|
||||
{
|
||||
onInputStreamReady(stream) {
|
||||
try {
|
||||
// getErrorClass may throw if you pass a non-NSS error
|
||||
const errorClass = nssErrorsService.getErrorClass(e.result);
|
||||
if (errorClass === Ci.nsINSSErrorsService.ERROR_CLASS_BAD_CERT) {
|
||||
deferred.resolve({ certError: true });
|
||||
} else {
|
||||
deferred.reject(e);
|
||||
stream.available();
|
||||
resolve({ alive: true });
|
||||
} catch (e) {
|
||||
try {
|
||||
// getErrorClass may throw if you pass a non-NSS error
|
||||
const errorClass = nssErrorsService.getErrorClass(e.result);
|
||||
if (errorClass === Ci.nsINSSErrorsService.ERROR_CLASS_BAD_CERT) {
|
||||
resolve({ certError: true });
|
||||
} else {
|
||||
reject(e);
|
||||
}
|
||||
} catch (nssErr) {
|
||||
reject(e);
|
||||
}
|
||||
} catch (nssErr) {
|
||||
deferred.reject(e);
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
},
|
||||
0,
|
||||
0,
|
||||
Services.tm.currentThread
|
||||
);
|
||||
return deferred.promise;
|
||||
0,
|
||||
0,
|
||||
Services.tm.currentThread
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -779,50 +775,50 @@ ServerSocketConnection.prototype = {
|
|||
* |onHandshakeDone|.
|
||||
*/
|
||||
_listenForTLSHandshake() {
|
||||
this._handshakeDeferred = defer();
|
||||
if (!this._listener.encryption) {
|
||||
this._handshakeDeferred.resolve();
|
||||
this._handshakePromise = Promise.resolve();
|
||||
return;
|
||||
}
|
||||
this._setSecurityObserver(this);
|
||||
this._handshakeTimeout = setTimeout(
|
||||
this._onHandshakeTimeout.bind(this),
|
||||
HANDSHAKE_TIMEOUT
|
||||
);
|
||||
|
||||
this._handshakePromise = new Promise((resolve, reject) => {
|
||||
this._observer = {
|
||||
// nsITLSServerSecurityObserver implementation
|
||||
onHandshakeDone: (socket, clientStatus) => {
|
||||
clearTimeout(this._handshakeTimeout);
|
||||
this._setSecurityObserver(null);
|
||||
dumpv("TLS version: " + clientStatus.tlsVersionUsed.toString(16));
|
||||
dumpv("TLS cipher: " + clientStatus.cipherName);
|
||||
dumpv("TLS key length: " + clientStatus.keyLength);
|
||||
dumpv("TLS MAC length: " + clientStatus.macLength);
|
||||
this._clientCert = clientStatus.peerCert;
|
||||
/*
|
||||
* TODO: These rules should be really be set on the TLS socket directly, but
|
||||
* this would need more platform work to expose it via XPCOM.
|
||||
*
|
||||
* Enforcing cipher suites here would be a bad idea, as we want TLS
|
||||
* cipher negotiation to work correctly. The server already allows only
|
||||
* Gecko's normal set of cipher suites.
|
||||
*/
|
||||
if (
|
||||
clientStatus.tlsVersionUsed < Ci.nsITLSClientStatus.TLS_VERSION_1_2
|
||||
) {
|
||||
reject(Cr.NS_ERROR_CONNECTION_REFUSED);
|
||||
return;
|
||||
}
|
||||
|
||||
resolve();
|
||||
},
|
||||
};
|
||||
this._setSecurityObserver(this._observer);
|
||||
this._handshakeTimeout = setTimeout(() => {
|
||||
dumpv("Client failed to complete TLS handshake");
|
||||
reject(Cr.NS_ERROR_NET_TIMEOUT);
|
||||
}, HANDSHAKE_TIMEOUT);
|
||||
});
|
||||
},
|
||||
|
||||
_awaitTLSHandshake() {
|
||||
return this._handshakeDeferred.promise;
|
||||
},
|
||||
|
||||
_onHandshakeTimeout() {
|
||||
dumpv("Client failed to complete TLS handshake");
|
||||
this._handshakeDeferred.reject(Cr.NS_ERROR_NET_TIMEOUT);
|
||||
},
|
||||
|
||||
// nsITLSServerSecurityObserver implementation
|
||||
onHandshakeDone(socket, clientStatus) {
|
||||
clearTimeout(this._handshakeTimeout);
|
||||
this._setSecurityObserver(null);
|
||||
dumpv("TLS version: " + clientStatus.tlsVersionUsed.toString(16));
|
||||
dumpv("TLS cipher: " + clientStatus.cipherName);
|
||||
dumpv("TLS key length: " + clientStatus.keyLength);
|
||||
dumpv("TLS MAC length: " + clientStatus.macLength);
|
||||
this._clientCert = clientStatus.peerCert;
|
||||
/*
|
||||
* TODO: These rules should be really be set on the TLS socket directly, but
|
||||
* this would need more platform work to expose it via XPCOM.
|
||||
*
|
||||
* Enforcing cipher suites here would be a bad idea, as we want TLS
|
||||
* cipher negotiation to work correctly. The server already allows only
|
||||
* Gecko's normal set of cipher suites.
|
||||
*/
|
||||
if (clientStatus.tlsVersionUsed < Ci.nsITLSClientStatus.TLS_VERSION_1_2) {
|
||||
this._handshakeDeferred.reject(Cr.NS_ERROR_CONNECTION_REFUSED);
|
||||
return;
|
||||
}
|
||||
|
||||
this._handshakeDeferred.resolve();
|
||||
return this._handshakePromise;
|
||||
},
|
||||
|
||||
async _authenticate() {
|
||||
|
|
|
@ -323,7 +323,8 @@ PopupBlocker::PopupControlState PopupBlocker::GetEventPopupControlState(
|
|||
break;
|
||||
case ePointerEventClass:
|
||||
if (aEvent->IsTrusted() &&
|
||||
aEvent->AsPointerEvent()->mButton == MouseButton::ePrimary) {
|
||||
(aEvent->AsPointerEvent()->mButton == MouseButton::ePrimary ||
|
||||
aEvent->AsPointerEvent()->mButton == MouseButton::eMiddle)) {
|
||||
switch (aEvent->mMessage) {
|
||||
case ePointerUp:
|
||||
if (PopupAllowedForEvent("pointerup")) {
|
||||
|
|
|
@ -760,7 +760,6 @@ skip-if = toolkit == 'android' # We don't ship pdf.js on Android
|
|||
[test_plugin_freezing.html]
|
||||
skip-if = (os == 'win' && processor == 'aarch64')
|
||||
reason = Plugins are not supported on Windows/AArch64
|
||||
[test_popup_middle_click.html]
|
||||
[test_postMessage_solidus.html]
|
||||
[test_postMessages_window.html]
|
||||
[test_postMessages_workers.html]
|
||||
|
|
|
@ -1,64 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Test for triggering popup by middle-click mouse events</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"/>
|
||||
</head>
|
||||
<body>
|
||||
<div id="target" style="width: 50px; height: 50px; background: green"></div>
|
||||
<script>
|
||||
|
||||
function sendMouseEvent(element, eventName, listenEventName, handler) {
|
||||
element.addEventListener(listenEventName, handler, {once: true});
|
||||
synthesizeMouseAtCenter(element, {type: eventName, button: 0});
|
||||
|
||||
element.addEventListener(listenEventName, handler, {once: true});
|
||||
synthesizeMouseAtCenter(element, {type: eventName, button: 1});
|
||||
}
|
||||
|
||||
function checkAllowOpenPopup(e) {
|
||||
let w = window.open("about:blank");
|
||||
ok(w, "Should allow popup in the " + e.type + " listener");
|
||||
if (w) {
|
||||
w.close();
|
||||
}
|
||||
}
|
||||
|
||||
function checkBlockOpenPopup(e) {
|
||||
let w = window.open("about:blank");
|
||||
ok(!w, "Should block popup in the " + e.type + " listener");
|
||||
if (w) {
|
||||
w.close();
|
||||
}
|
||||
}
|
||||
|
||||
function startTest() {
|
||||
let target = document.getElementById("target");
|
||||
sendMouseEvent(target, "mousemove", "mousemove", checkBlockOpenPopup);
|
||||
sendMouseEvent(target, "mousedown", "mousedown", checkBlockOpenPopup);
|
||||
sendMouseEvent(target, "mousemove", "mousemove", checkBlockOpenPopup);
|
||||
sendMouseEvent(target, "mouseup", "mouseup", checkAllowOpenPopup);
|
||||
}
|
||||
|
||||
const DENY_ACTION = SpecialPowers.Ci.nsIPermissionManager.DENY_ACTION;
|
||||
|
||||
let xorigin = SimpleTest.getTestFileURL("").replace(location.hostname, 'mochi.xorigin-test');
|
||||
add_task(async () => {
|
||||
await SpecialPowers.pushPermissions([
|
||||
{'type': 'popup', 'allow': DENY_ACTION,
|
||||
'context': document},
|
||||
{'type': 'popup', 'allow': DENY_ACTION,
|
||||
'context': xorigin}
|
||||
]);
|
||||
|
||||
await new Promise(resolve => SimpleTest.waitForFocus(resolve));
|
||||
|
||||
startTest();
|
||||
});
|
||||
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -17,3 +17,5 @@ support-files = file_useractivation_sandbox_transient_popup.html
|
|||
[test_useractivation_transient_consuming.html]
|
||||
[test_clipboard_editor.html]
|
||||
[test_clipboard_noeditor.html]
|
||||
[test_popup_blocker_mouse_event.html]
|
||||
[test_popup_blocker_pointer_event.html]
|
||||
|
|
|
@ -0,0 +1,98 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Test for triggering popup by mouse events</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"/>
|
||||
</head>
|
||||
<body>
|
||||
<div id="target" style="width: 50px; height: 50px; background: green"></div>
|
||||
<script>
|
||||
|
||||
function sendMouseEvent(element, eventName, button, listenEventName, handler) {
|
||||
let needToCheckHandler = false;
|
||||
let handlerIsCalled = false;
|
||||
if (listenEventName && handler) {
|
||||
needToCheckHandler = true;
|
||||
element.addEventListener(listenEventName, (e) => {
|
||||
handler(e);
|
||||
handlerIsCalled = true;
|
||||
}, {once: true});
|
||||
}
|
||||
synthesizeMouseAtCenter(element, {type: eventName, button});
|
||||
if (needToCheckHandler) {
|
||||
ok(handlerIsCalled, "Handler should be called");
|
||||
}
|
||||
}
|
||||
|
||||
function checkAllowOpenPopup(e) {
|
||||
let w = window.open("about:blank");
|
||||
ok(w, `Should allow popup in the ${e.type} listener with button=${e.button}`);
|
||||
if (w) {
|
||||
w.close();
|
||||
}
|
||||
}
|
||||
|
||||
function checkBlockOpenPopup(e) {
|
||||
let w = window.open("about:blank");
|
||||
ok(!w, `Should block popup in the ${e.type} listener with button=${e.button}`);
|
||||
if (w) {
|
||||
w.close();
|
||||
}
|
||||
}
|
||||
|
||||
add_task(async function init() {
|
||||
const DENY_ACTION = SpecialPowers.Ci.nsIPermissionManager.DENY_ACTION;
|
||||
let xorigin = SimpleTest.getTestFileURL("").replace(location.hostname, 'mochi.xorigin-test');
|
||||
await SpecialPowers.pushPermissions([
|
||||
{'type': 'popup', 'allow': DENY_ACTION,
|
||||
'context': document},
|
||||
{'type': 'popup', 'allow': DENY_ACTION,
|
||||
'context': xorigin}
|
||||
]);
|
||||
|
||||
await new Promise(resolve => SimpleTest.waitForFocus(resolve));
|
||||
});
|
||||
|
||||
const LEFT_BUTTON = 0;
|
||||
const MIDDLE_BUTTON = 1;
|
||||
const RIGHT_BUTTON = 2;
|
||||
let target = document.getElementById("target");
|
||||
|
||||
add_task(function testMouseDownUpMove() {
|
||||
// Left button
|
||||
sendMouseEvent(target, "mousedown", LEFT_BUTTON, "mousedown", checkAllowOpenPopup);
|
||||
sendMouseEvent(target, "mousemove", LEFT_BUTTON, "mousemove", checkBlockOpenPopup);
|
||||
sendMouseEvent(target, "mouseup", LEFT_BUTTON, "mouseup", checkAllowOpenPopup);
|
||||
|
||||
// Middle button
|
||||
sendMouseEvent(target, "mousedown", MIDDLE_BUTTON, "mousedown", checkAllowOpenPopup);
|
||||
sendMouseEvent(target, "mousemove", MIDDLE_BUTTON, "mousemove", checkBlockOpenPopup);
|
||||
sendMouseEvent(target, "mouseup", MIDDLE_BUTTON, "mouseup", checkAllowOpenPopup);
|
||||
|
||||
// Right button
|
||||
sendMouseEvent(target, "mousedown", RIGHT_BUTTON, "mousedown", checkBlockOpenPopup);
|
||||
sendMouseEvent(target, "mousemove", RIGHT_BUTTON, "mousemove", checkBlockOpenPopup);
|
||||
sendMouseEvent(target, "mouseup", RIGHT_BUTTON, "mouseup", checkBlockOpenPopup);
|
||||
});
|
||||
|
||||
add_task(function testMouseClick() {
|
||||
// Left button
|
||||
sendMouseEvent(target, "mousedown", LEFT_BUTTON);
|
||||
sendMouseEvent(target, "mouseup", LEFT_BUTTON, "click", checkAllowOpenPopup);
|
||||
});
|
||||
|
||||
add_task(function testMouseAuxclick() {
|
||||
// Middle button
|
||||
sendMouseEvent(target, "mousedown", MIDDLE_BUTTON);
|
||||
sendMouseEvent(target, "mouseup", MIDDLE_BUTTON, "auxclick", checkAllowOpenPopup);
|
||||
|
||||
// Right button
|
||||
sendMouseEvent(target, "mousedown", RIGHT_BUTTON);
|
||||
sendMouseEvent(target, "mouseup", RIGHT_BUTTON, "auxclick", checkAllowOpenPopup);
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,126 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Test for triggering popup by pointer events</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"/>
|
||||
</head>
|
||||
<body>
|
||||
<div id="target" style="width: 50px; height: 50px; background: green"></div>
|
||||
<script>
|
||||
|
||||
function sendMouseEvent(element, eventName, button, listenEventName, handler) {
|
||||
let needToCheckHandler = false;
|
||||
let handlerIsCalled = false;
|
||||
if (listenEventName && handler) {
|
||||
needToCheckHandler = true;
|
||||
element.addEventListener(listenEventName, (e) => {
|
||||
handler(e);
|
||||
handlerIsCalled = true;
|
||||
}, {once: true});
|
||||
}
|
||||
synthesizeMouseAtCenter(element, {type: eventName, button});
|
||||
if (needToCheckHandler) {
|
||||
ok(handlerIsCalled, "Handler should be called");
|
||||
}
|
||||
}
|
||||
|
||||
function checkAllowOpenPopup(e) {
|
||||
let w = window.open("about:blank");
|
||||
ok(w, `Should allow popup in the ${e.type} listener with button=${e.button}`);
|
||||
if (w) {
|
||||
w.close();
|
||||
}
|
||||
}
|
||||
|
||||
function checkBlockOpenPopup(e) {
|
||||
let w = window.open("about:blank");
|
||||
ok(!w, `Should block popup in the ${e.type} listener with button=${e.button}`);
|
||||
if (w) {
|
||||
w.close();
|
||||
}
|
||||
}
|
||||
|
||||
add_task(async function init() {
|
||||
const DENY_ACTION = SpecialPowers.Ci.nsIPermissionManager.DENY_ACTION;
|
||||
let xorigin = SimpleTest.getTestFileURL("").replace(location.hostname, 'mochi.xorigin-test');
|
||||
await SpecialPowers.pushPermissions([
|
||||
{'type': 'popup', 'allow': DENY_ACTION,
|
||||
'context': document},
|
||||
{'type': 'popup', 'allow': DENY_ACTION,
|
||||
'context': xorigin}
|
||||
]);
|
||||
await SpecialPowers.pushPrefEnv({
|
||||
"set": [["dom.w3c_pointer_events.enabled", true]]
|
||||
});
|
||||
|
||||
await new Promise(resolve => SimpleTest.waitForFocus(resolve));
|
||||
});
|
||||
|
||||
const LEFT_BUTTON = 0;
|
||||
const MIDDLE_BUTTON = 1;
|
||||
const RIGHT_BUTTON = 2;
|
||||
let target = document.getElementById("target");
|
||||
|
||||
add_task(function testPointerEventDefault() {
|
||||
// By default, only allow opening popup in the pointerup listener.
|
||||
// Left button
|
||||
sendMouseEvent(target, "mousedown", LEFT_BUTTON, "pointerdown", checkAllowOpenPopup);
|
||||
sendMouseEvent(target, "mousemove", LEFT_BUTTON, "pointermove", checkBlockOpenPopup);
|
||||
sendMouseEvent(target, "mouseup", LEFT_BUTTON, "pointerup", checkAllowOpenPopup);
|
||||
|
||||
// Middle button
|
||||
sendMouseEvent(target, "mousedown", MIDDLE_BUTTON, "pointerdown", checkAllowOpenPopup);
|
||||
sendMouseEvent(target, "mousemove", MIDDLE_BUTTON, "pointermove", checkBlockOpenPopup);
|
||||
sendMouseEvent(target, "mouseup", MIDDLE_BUTTON, "pointerup", checkAllowOpenPopup);
|
||||
|
||||
// Right button
|
||||
sendMouseEvent(target, "mousedown", RIGHT_BUTTON, "pointerdown", checkBlockOpenPopup);
|
||||
sendMouseEvent(target, "mousemove", RIGHT_BUTTON, "pointermove", checkBlockOpenPopup);
|
||||
sendMouseEvent(target, "mouseup", RIGHT_BUTTON, "pointerup", checkBlockOpenPopup);
|
||||
});
|
||||
|
||||
add_task(async function testPointerEventAddPointerDownToPref() {
|
||||
// Adding pointerdown to preference
|
||||
await SpecialPowers.pushPrefEnv({"set": [["dom.popup_allowed_events",
|
||||
"pointerdown pointerup"]]});
|
||||
// Left button
|
||||
sendMouseEvent(target, "mousedown", LEFT_BUTTON, "pointerdown", checkAllowOpenPopup);
|
||||
sendMouseEvent(target, "mousemove", LEFT_BUTTON, "pointermove", checkBlockOpenPopup);
|
||||
sendMouseEvent(target, "mouseup", LEFT_BUTTON, "pointerup", checkAllowOpenPopup);
|
||||
|
||||
// Middle button
|
||||
sendMouseEvent(target, "mousedown", MIDDLE_BUTTON, "pointerdown", checkAllowOpenPopup);
|
||||
sendMouseEvent(target, "mousemove", MIDDLE_BUTTON, "pointermove", checkBlockOpenPopup);
|
||||
sendMouseEvent(target, "mouseup", MIDDLE_BUTTON, "pointerup", checkAllowOpenPopup);
|
||||
|
||||
// Right button
|
||||
sendMouseEvent(target, "mousedown", RIGHT_BUTTON, "pointerdown", checkBlockOpenPopup);
|
||||
sendMouseEvent(target, "mousemove", RIGHT_BUTTON, "pointermove", checkBlockOpenPopup);
|
||||
sendMouseEvent(target, "mouseup", RIGHT_BUTTON, "pointerup", checkBlockOpenPopup);
|
||||
});
|
||||
|
||||
add_task(async function testPointerEventAddPointerMoveToPref() {
|
||||
// Adding pointermove to preference should have no effect.
|
||||
await SpecialPowers.pushPrefEnv({"set": [["dom.popup_allowed_events",
|
||||
"pointerdown pointerup pointermove"]]});
|
||||
// Left button
|
||||
sendMouseEvent(target, "mousedown", LEFT_BUTTON, "pointerdown", checkAllowOpenPopup);
|
||||
sendMouseEvent(target, "mousemove", LEFT_BUTTON, "pointermove", checkBlockOpenPopup);
|
||||
sendMouseEvent(target, "mouseup", LEFT_BUTTON, "pointerup", checkAllowOpenPopup);
|
||||
|
||||
// Middle button
|
||||
sendMouseEvent(target, "mousedown", MIDDLE_BUTTON, "pointerdown", checkAllowOpenPopup);
|
||||
sendMouseEvent(target, "mousemove", MIDDLE_BUTTON, "pointermove", checkBlockOpenPopup);
|
||||
sendMouseEvent(target, "mouseup", MIDDLE_BUTTON, "pointerup", checkAllowOpenPopup);
|
||||
|
||||
// Right button
|
||||
sendMouseEvent(target, "mousedown", RIGHT_BUTTON, "pointerdown", checkBlockOpenPopup);
|
||||
sendMouseEvent(target, "mousemove", RIGHT_BUTTON, "pointermove", checkBlockOpenPopup);
|
||||
sendMouseEvent(target, "mouseup", RIGHT_BUTTON, "pointerup", checkBlockOpenPopup);
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -45,10 +45,7 @@ struct TypedArray_base : public SpiderMonkeyInterfaceObjectStorage,
|
|||
mLength(aOther.mLength),
|
||||
mShared(aOther.mShared),
|
||||
mComputed(aOther.mComputed) {
|
||||
aOther.mData = nullptr;
|
||||
aOther.mLength = 0;
|
||||
aOther.mShared = false;
|
||||
aOther.mComputed = false;
|
||||
aOther.Reset();
|
||||
}
|
||||
|
||||
private:
|
||||
|
@ -115,6 +112,18 @@ struct TypedArray_base : public SpiderMonkeyInterfaceObjectStorage,
|
|||
return mData;
|
||||
}
|
||||
|
||||
// Return a pointer to data that will not move during a GC.
|
||||
//
|
||||
// For some smaller views, this will copy the data into the provided buffer
|
||||
// and return that buffer as the pointer. Otherwise, this will return a
|
||||
// direct pointer to the actual data with no copying. If the provided buffer
|
||||
// is not large enough, nullptr will be returned. If bufSize is at least
|
||||
// JS_MaxMovableTypedArraySize(), the data is guaranteed to fit.
|
||||
inline T* FixedData(uint8_t* buffer, size_t bufSize) const {
|
||||
MOZ_ASSERT(mComputed);
|
||||
return JS_GetArrayBufferViewFixedData(mImplObj, buffer, bufSize);
|
||||
}
|
||||
|
||||
inline uint32_t Length() const {
|
||||
MOZ_ASSERT(mComputed);
|
||||
return mLength;
|
||||
|
@ -127,6 +136,16 @@ struct TypedArray_base : public SpiderMonkeyInterfaceObjectStorage,
|
|||
mComputed = true;
|
||||
}
|
||||
|
||||
inline void Reset() {
|
||||
// This method mostly exists to inform the GC rooting hazard analysis that
|
||||
// the variable can be considered dead, at least until you do anything else
|
||||
// with it.
|
||||
mData = nullptr;
|
||||
mLength = 0;
|
||||
mShared = false;
|
||||
mComputed = false;
|
||||
}
|
||||
|
||||
private:
|
||||
TypedArray_base(const TypedArray_base&) = delete;
|
||||
};
|
||||
|
|
|
@ -3934,6 +3934,10 @@ void ClientWebGLContext::TexImage(uint8_t funcDims, GLenum imageTarget,
|
|||
|
||||
// -
|
||||
|
||||
// Demarcate the region within which GC is disallowed. Typed arrays can move
|
||||
// their data during a GC, so this will allow the rooting hazard analysis to
|
||||
// report if a GC is possible while any data pointers extracted from the
|
||||
// typed array are still live.
|
||||
dom::Uint8ClampedArray scopedArr;
|
||||
|
||||
// -
|
||||
|
@ -4007,7 +4011,10 @@ void ClientWebGLContext::TexImage(uint8_t funcDims, GLenum imageTarget,
|
|||
return Some(webgl::TexUnpackBlobDesc{
|
||||
imageTarget, explicitSize, gfxAlphaType::NonPremult, {}, {}});
|
||||
}();
|
||||
if (!desc) return;
|
||||
if (!desc) {
|
||||
scopedArr.Reset();
|
||||
return;
|
||||
}
|
||||
|
||||
// -
|
||||
// Further, for uploads from TexImageSource, implied UNPACK_ROW_LENGTH and
|
||||
|
@ -4041,6 +4048,7 @@ void ClientWebGLContext::TexImage(uint8_t funcDims, GLenum imageTarget,
|
|||
EnqueueError(LOCAL_GL_INVALID_OPERATION,
|
||||
"Non-DOM-Element uploads with alpha-premult"
|
||||
" or y-flip do not support subrect selection.");
|
||||
scopedArr.Reset(); // (For the hazard analysis) Done with the data.
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -4052,6 +4060,7 @@ void ClientWebGLContext::TexImage(uint8_t funcDims, GLenum imageTarget,
|
|||
desc->Shrink(pi);
|
||||
Run<RPROC(TexImage)>(static_cast<uint32_t>(level), respecFormat,
|
||||
CastUvec3(offset), pi, std::move(*desc));
|
||||
scopedArr.Reset(); // (For the hazard analysis) Done with the data.
|
||||
}
|
||||
|
||||
void ClientWebGLContext::CompressedTexImage(bool sub, uint8_t funcDims,
|
||||
|
|
|
@ -881,13 +881,26 @@ already_AddRefed<ImageBitmap> ImageBitmap::CreateInternal(
|
|||
|
||||
// Create and Crop the raw data into a layers::Image
|
||||
RefPtr<layers::Image> data;
|
||||
|
||||
// If the data could move during a GC, copy it out into a local buffer that
|
||||
// lives until a CreateImageFromRawData lower in the stack copies it.
|
||||
// Reassure the static analysis that we know what we're doing.
|
||||
size_t maxInline = JS_MaxMovableTypedArraySize();
|
||||
uint8_t inlineDataBuffer[maxInline];
|
||||
uint8_t* fixedData = array.FixedData(inlineDataBuffer, maxInline);
|
||||
|
||||
// Lie to the hazard analysis and say that we're done with everything that
|
||||
// `array` was using (safe because the data buffer is fixed, and the holding
|
||||
// JSObject is being kept alive elsewhere.)
|
||||
array.Reset();
|
||||
|
||||
if (NS_IsMainThread()) {
|
||||
data = CreateImageFromRawData(imageSize, imageStride, FORMAT, array.Data(),
|
||||
dataLength, aCropRect);
|
||||
data = CreateImageFromRawData(imageSize, imageStride, FORMAT,
|
||||
fixedData, dataLength, aCropRect);
|
||||
} else {
|
||||
RefPtr<CreateImageFromRawDataInMainThreadSyncTask> task =
|
||||
new CreateImageFromRawDataInMainThreadSyncTask(
|
||||
array.Data(), dataLength, imageStride, FORMAT, imageSize, aCropRect,
|
||||
fixedData, dataLength, imageStride, FORMAT, imageSize, aCropRect,
|
||||
getter_AddRefs(data));
|
||||
task->Dispatch(Canceling, aRv);
|
||||
}
|
||||
|
@ -897,7 +910,7 @@ already_AddRefed<ImageBitmap> ImageBitmap::CreateInternal(
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
// Create an ImageBimtap.
|
||||
// Create an ImageBitmap.
|
||||
RefPtr<ImageBitmap> ret =
|
||||
new ImageBitmap(aGlobal, data, false /* write-only */, alphaType);
|
||||
|
||||
|
|
|
@ -118,7 +118,6 @@ support-files =
|
|||
[test_trigger_fullscreen_by_pointer_events.html]
|
||||
support-files =
|
||||
file_test_trigger_fullscreen.html
|
||||
[test_trigger_popup_by_pointer_events.html]
|
||||
[test_remove_frame_when_got_pointer_capture.html]
|
||||
[test_getCoalescedEvents.html]
|
||||
skip-if =
|
||||
|
|
|
@ -1,81 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Test for triggering popup by pointer events</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"/>
|
||||
</head>
|
||||
<body>
|
||||
<div id="target" style="width: 50px; height: 50px; background: green"></div>
|
||||
<script>
|
||||
|
||||
function sendMouseEvent(element, eventName, listenEventName, handler) {
|
||||
element.addEventListener(listenEventName, handler, {once: true});
|
||||
synthesizeMouseAtCenter(element, {type: eventName});
|
||||
}
|
||||
|
||||
function checkAllowOpenPopup(e) {
|
||||
let w = window.open("about:blank");
|
||||
ok(w, "Should allow popup in the " + e.type + " listener");
|
||||
if (w) {
|
||||
w.close();
|
||||
}
|
||||
}
|
||||
|
||||
function checkBlockOpenPopup(e) {
|
||||
let w = window.open("about:blank");
|
||||
ok(!w, "Should block popup in the " + e.type + " listener");
|
||||
if (w) {
|
||||
w.close();
|
||||
}
|
||||
}
|
||||
|
||||
async function startTest() {
|
||||
let target = document.getElementById("target");
|
||||
// By default, only allow opening popup in the pointerup listener.
|
||||
sendMouseEvent(target, "mousemove", "pointermove", checkBlockOpenPopup);
|
||||
sendMouseEvent(target, "mousedown", "pointerdown", checkBlockOpenPopup);
|
||||
sendMouseEvent(target, "mousemove", "pointermove", checkBlockOpenPopup);
|
||||
sendMouseEvent(target, "mouseup", "pointerup", checkAllowOpenPopup);
|
||||
|
||||
await SpecialPowers.pushPrefEnv({"set": [["dom.popup_allowed_events",
|
||||
"pointerdown pointerup"]]});
|
||||
// Adding pointerdown to preference should work
|
||||
sendMouseEvent(target, "mousemove", "pointermove", checkBlockOpenPopup);
|
||||
sendMouseEvent(target, "mousedown", "pointerdown", checkAllowOpenPopup);
|
||||
sendMouseEvent(target, "mousemove", "pointermove", checkBlockOpenPopup);
|
||||
sendMouseEvent(target, "mouseup", "pointerup", checkAllowOpenPopup);
|
||||
|
||||
await SpecialPowers.pushPrefEnv({"set": [["dom.popup_allowed_events",
|
||||
"pointerdown pointerup pointermove"]]});
|
||||
// Adding pointermove to preference should be no effect.
|
||||
sendMouseEvent(target, "mousemove", "pointermove", checkBlockOpenPopup);
|
||||
sendMouseEvent(target, "mousedown", "pointerdown", checkAllowOpenPopup);
|
||||
sendMouseEvent(target, "mousemove", "pointermove", checkBlockOpenPopup);
|
||||
sendMouseEvent(target, "mouseup", "pointerup", checkAllowOpenPopup);
|
||||
}
|
||||
|
||||
const DENY_ACTION = SpecialPowers.Ci.nsIPermissionManager.DENY_ACTION;
|
||||
|
||||
let xorigin = SimpleTest.getTestFileURL("").replace(location.hostname, 'mochi.xorigin-test');
|
||||
add_task(async () => {
|
||||
await SpecialPowers.pushPermissions([
|
||||
{'type': 'popup', 'allow': DENY_ACTION,
|
||||
'context': document},
|
||||
{'type': 'popup', 'allow': DENY_ACTION,
|
||||
'context': xorigin}
|
||||
]);
|
||||
await SpecialPowers.pushPrefEnv({
|
||||
"set": [["dom.w3c_pointer_events.enabled", true]]
|
||||
});
|
||||
|
||||
await new Promise(resolve => SimpleTest.waitForFocus(resolve));
|
||||
|
||||
await startTest();
|
||||
});
|
||||
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -2415,6 +2415,11 @@ nsresult ScriptLoader::AttemptAsyncScriptCompile(ScriptLoadRequest* aRequest,
|
|||
}
|
||||
} else {
|
||||
MOZ_ASSERT(aRequest->IsBytecode());
|
||||
|
||||
// NOTE: Regardless of using stencil XDR or not, we use off-thread parse
|
||||
// global and instantiate off-thread, to avoid regressing performance.
|
||||
options.useOffThreadParseGlobal = true;
|
||||
|
||||
size_t length =
|
||||
aRequest->mScriptBytecode.length() - aRequest->mBytecodeOffset;
|
||||
if (!JS::CanDecodeOffThread(cx, options, length)) {
|
||||
|
|
|
@ -429,6 +429,10 @@
|
|||
|
||||
let firstPath = PathUtils.createUniquePath(path);
|
||||
let secondPath = PathUtils.createUniquePath(path);
|
||||
SimpleTest.registerCleanupFunction(async () => {
|
||||
await IOUtils.remove(firstPath);
|
||||
await IOUtils.remove(secondPath);
|
||||
});
|
||||
|
||||
isnot(firstPath, secondPath, "Create unique paths returns different paths");
|
||||
is(PathUtils.filename(firstPath), ".test", "PathUtils.createUniquePath() matches filename for first path");
|
||||
|
|
|
@ -122,3 +122,6 @@ DEFINES['DEBUG'] = False
|
|||
if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'android':
|
||||
DEFINES['HAVE_MMAP'] = 1
|
||||
DEFINES['HAVE_SYS_MMAN_H'] = 1
|
||||
|
||||
if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'windows':
|
||||
DEFINES['UNICODE'] = True
|
||||
|
|
|
@ -762,8 +762,8 @@ function promiseMoveMouseAndScrollWheelOver(
|
|||
|
||||
// Synthesizes events to drag |target|'s vertical scrollbar by the distance
|
||||
// specified, synthesizing a mousemove for each increment as specified.
|
||||
// Returns false if the element doesn't have a vertical scrollbar. Otherwise,
|
||||
// returns a generator that should be invoked after the mousemoves have been
|
||||
// Returns null if the element doesn't have a vertical scrollbar. Otherwise,
|
||||
// returns an async function that should be invoked after the mousemoves have been
|
||||
// processed by the widget code, to end the scrollbar drag. Mousemoves being
|
||||
// processed by the widget code can be detected by listening for the mousemove
|
||||
// events in the caller, or for some other event that is triggered by the
|
||||
|
@ -775,9 +775,8 @@ function promiseMoveMouseAndScrollWheelOver(
|
|||
// Note: helper_scrollbar_snap_bug1501062.html contains a copy of this code
|
||||
// with modifications. Fixes here should be copied there if appropriate.
|
||||
// |target| can be an element (for subframes) or a window (for root frames).
|
||||
function* dragVerticalScrollbar(
|
||||
async function promiseVerticalScrollbarDrag(
|
||||
target,
|
||||
testDriver,
|
||||
distance = 20,
|
||||
increment = 5,
|
||||
scaleFactor = 1
|
||||
|
@ -788,7 +787,7 @@ function* dragVerticalScrollbar(
|
|||
utilsForTarget(target).getScrollbarSizes(targetElement, w, h);
|
||||
var verticalScrollbarWidth = w.value;
|
||||
if (verticalScrollbarWidth == 0) {
|
||||
return false;
|
||||
return null;
|
||||
}
|
||||
|
||||
var upArrowHeight = verticalScrollbarWidth; // assume square scrollbar buttons
|
||||
|
@ -808,48 +807,43 @@ function* dragVerticalScrollbar(
|
|||
);
|
||||
|
||||
// Move the mouse to the scrollbar thumb and drag it down
|
||||
yield synthesizeNativeMouseEvent(
|
||||
await promiseNativeMouseEvent(
|
||||
target,
|
||||
mouseX,
|
||||
mouseY,
|
||||
nativeMouseMoveEventMsg(),
|
||||
testDriver
|
||||
nativeMouseMoveEventMsg()
|
||||
);
|
||||
// mouse down
|
||||
yield synthesizeNativeMouseEvent(
|
||||
await promiseNativeMouseEvent(
|
||||
target,
|
||||
mouseX,
|
||||
mouseY,
|
||||
nativeMouseDownEventMsg(),
|
||||
testDriver
|
||||
nativeMouseDownEventMsg()
|
||||
);
|
||||
// drag vertically by |increment| until we reach the specified distance
|
||||
for (var y = increment; y < distance; y += increment) {
|
||||
yield synthesizeNativeMouseEvent(
|
||||
await promiseNativeMouseEvent(
|
||||
target,
|
||||
mouseX,
|
||||
mouseY + y,
|
||||
nativeMouseMoveEventMsg(),
|
||||
testDriver
|
||||
nativeMouseMoveEventMsg()
|
||||
);
|
||||
}
|
||||
yield synthesizeNativeMouseEvent(
|
||||
await promiseNativeMouseEvent(
|
||||
target,
|
||||
mouseX,
|
||||
mouseY + distance,
|
||||
nativeMouseMoveEventMsg(),
|
||||
testDriver
|
||||
nativeMouseMoveEventMsg()
|
||||
);
|
||||
|
||||
// and return a generator to call afterwards to finish up the drag
|
||||
return function*() {
|
||||
// and return an async function to call afterwards to finish up the drag
|
||||
return async function() {
|
||||
dump("Finishing drag of #" + targetElement.id + "\n");
|
||||
yield synthesizeNativeMouseEvent(
|
||||
await promiseNativeMouseEvent(
|
||||
target,
|
||||
mouseX,
|
||||
mouseY + distance,
|
||||
nativeMouseUpEventMsg(),
|
||||
testDriver
|
||||
nativeMouseUpEventMsg()
|
||||
);
|
||||
};
|
||||
}
|
||||
|
|
|
@ -20,11 +20,13 @@
|
|||
</style>
|
||||
<script type="text/javascript">
|
||||
|
||||
function* test(testDriver) {
|
||||
async function test() {
|
||||
var scrollableDiv = document.getElementById("scrollable");
|
||||
scrollableDiv.addEventListener("scroll", () => setTimeout(testDriver, 0), {once: true});
|
||||
let scrollPromise = new Promise(resolve => {
|
||||
scrollableDiv.addEventListener("scroll", resolve, {once: true});
|
||||
});
|
||||
|
||||
var dragFinisher = yield* dragVerticalScrollbar(scrollableDiv, testDriver);
|
||||
var dragFinisher = await promiseVerticalScrollbarDrag(scrollableDiv);
|
||||
if (!dragFinisher) {
|
||||
ok(true, "No scrollbar, can't do this test");
|
||||
return;
|
||||
|
@ -33,12 +35,12 @@ function* test(testDriver) {
|
|||
// the events above might be stuck in APZ input queue for a bit until the
|
||||
// layer is activated, so we wait here until the scroll event listener is
|
||||
// triggered.
|
||||
yield;
|
||||
await scrollPromise;
|
||||
|
||||
yield* dragFinisher();
|
||||
await dragFinisher();
|
||||
|
||||
// Flush everything just to be safe
|
||||
yield flushApzRepaints(testDriver);
|
||||
await promiseApzRepaintsFlushed();
|
||||
|
||||
// After dragging the scrollbar 20px on a 200px-high scrollable div, we should
|
||||
// have scrolled approx 10% of the 2000px high content. There might have been
|
||||
|
@ -47,7 +49,7 @@ function* test(testDriver) {
|
|||
}
|
||||
|
||||
waitUntilApzStable()
|
||||
.then(runContinuation(test))
|
||||
.then(test)
|
||||
.then(subtestDone, subtestFailed);
|
||||
|
||||
</script>
|
||||
|
|
|
@ -9,11 +9,13 @@
|
|||
<script src="/tests/SimpleTest/paint_listener.js"></script>
|
||||
<script type="text/javascript">
|
||||
|
||||
function* test(testDriver) {
|
||||
async function test() {
|
||||
var scrollableDiv = document.getElementById("scrollable");
|
||||
scrollableDiv.addEventListener("scroll", () => setTimeout(testDriver, 0), {once: true});
|
||||
let scrollPromise = new Promise(resolve => {
|
||||
scrollableDiv.addEventListener("scroll", resolve, {once: true});
|
||||
});
|
||||
|
||||
var dragFinisher = yield* dragVerticalScrollbar(scrollableDiv, testDriver);
|
||||
var dragFinisher = await promiseVerticalScrollbarDrag(scrollableDiv);
|
||||
if (!dragFinisher) {
|
||||
ok(true, "No scrollbar, can't do this test");
|
||||
return;
|
||||
|
@ -22,12 +24,12 @@ function* test(testDriver) {
|
|||
// the events above might be stuck in APZ input queue for a bit until the
|
||||
// layer is activated, so we wait here until the scroll event listener is
|
||||
// triggered.
|
||||
yield;
|
||||
await scrollPromise;
|
||||
|
||||
yield* dragFinisher();
|
||||
await dragFinisher();
|
||||
|
||||
// Flush everything just to be safe
|
||||
yield flushApzRepaints(testDriver);
|
||||
await promiseApzRepaintsFlushed();
|
||||
|
||||
// After dragging the scrollbar 20px on a 200px-high scrollable div, we should
|
||||
// have scrolled approx 10% of the 2000px high content. There might have been
|
||||
|
@ -36,7 +38,7 @@ function* test(testDriver) {
|
|||
}
|
||||
|
||||
waitUntilApzStable()
|
||||
.then(runContinuation(test))
|
||||
.then(test)
|
||||
.then(subtestDone, subtestFailed);
|
||||
|
||||
</script>
|
||||
|
|
|
@ -9,15 +9,17 @@
|
|||
<script src="/tests/SimpleTest/paint_listener.js"></script>
|
||||
<script type="text/javascript">
|
||||
|
||||
function* test(testDriver) {
|
||||
async function test() {
|
||||
var scrollableDiv = document.getElementById("scrollable");
|
||||
scrollableDiv.addEventListener("scroll", () => setTimeout(testDriver, 0), {once: true});
|
||||
let scrollPromise = new Promise(resolve => {
|
||||
scrollableDiv.addEventListener("scroll", resolve, {once: true});
|
||||
});
|
||||
|
||||
// Scroll down a small amount (10px). The bug in this case is that the
|
||||
// scrollthumb remains a little "above" where it's supposed to be, so if the
|
||||
// bug manifests here, then the thumb will remain at the top of the track
|
||||
// and the scroll position will remain at 0.
|
||||
var dragFinisher = yield* dragVerticalScrollbar(scrollableDiv, testDriver, 10, 10);
|
||||
var dragFinisher = await promiseVerticalScrollbarDrag(scrollableDiv, 10, 10);
|
||||
if (!dragFinisher) {
|
||||
ok(true, "No scrollbar, can't do this test");
|
||||
return;
|
||||
|
@ -26,12 +28,12 @@ function* test(testDriver) {
|
|||
// the events above might be stuck in APZ input queue for a bit until the
|
||||
// layer is activated, so we wait here until the scroll event listener is
|
||||
// triggered.
|
||||
yield;
|
||||
await scrollPromise;
|
||||
|
||||
yield* dragFinisher();
|
||||
await dragFinisher();
|
||||
|
||||
// Flush everything just to be safe
|
||||
yield flushApzRepaints(testDriver);
|
||||
await promiseApzRepaintsFlushed();
|
||||
|
||||
// In this case we just want to make sure the scroll position moved from 0
|
||||
// which indicates the thumb dragging worked properly.
|
||||
|
@ -39,7 +41,7 @@ function* test(testDriver) {
|
|||
}
|
||||
|
||||
waitUntilApzStable()
|
||||
.then(runContinuation(test))
|
||||
.then(test)
|
||||
.then(subtestDone, subtestFailed);
|
||||
|
||||
</script>
|
||||
|
|
|
@ -9,9 +9,11 @@
|
|||
<script src="/tests/SimpleTest/paint_listener.js"></script>
|
||||
<script type="text/javascript">
|
||||
|
||||
function* test(testDriver) {
|
||||
async function test() {
|
||||
var scrollableDiv = document.getElementById("scrollable");
|
||||
scrollableDiv.addEventListener("scroll", () => setTimeout(testDriver, 0), {once: true});
|
||||
let scrollPromise = new Promise(resolve => {
|
||||
scrollableDiv.addEventListener("scroll", resolve, {once: true});
|
||||
});
|
||||
|
||||
// Scroll down a small amount (10px). The bug in this case is that the
|
||||
// scrollthumb "jumps" by an additional 40 pixels (height of the "gap" div)
|
||||
|
@ -22,7 +24,7 @@ function* test(testDriver) {
|
|||
// the scrollthumb should be approximately 80px tall, and dragging it 10px
|
||||
// should scroll approximately 50 pixels. If the bug manifests, it will get
|
||||
// dragged 50px and scroll approximately 250px.
|
||||
var dragFinisher = yield* dragVerticalScrollbar(scrollableDiv, testDriver, 10, 10);
|
||||
var dragFinisher = await promiseVerticalScrollbarDrag(scrollableDiv, 10, 10);
|
||||
if (!dragFinisher) {
|
||||
ok(true, "No scrollbar, can't do this test");
|
||||
return;
|
||||
|
@ -31,12 +33,12 @@ function* test(testDriver) {
|
|||
// the events above might be stuck in APZ input queue for a bit until the
|
||||
// layer is activated, so we wait here until the scroll event listener is
|
||||
// triggered.
|
||||
yield;
|
||||
await scrollPromise;
|
||||
|
||||
yield* dragFinisher();
|
||||
await dragFinisher();
|
||||
|
||||
// Flush everything just to be safe
|
||||
yield flushApzRepaints(testDriver);
|
||||
await promiseApzRepaintsFlushed();
|
||||
|
||||
// In this case we just want to make sure the scroll position moved from 0
|
||||
// which indicates the thumb dragging worked properly.
|
||||
|
@ -44,7 +46,7 @@ function* test(testDriver) {
|
|||
}
|
||||
|
||||
waitUntilApzStable()
|
||||
.then(runContinuation(test))
|
||||
.then(test)
|
||||
.then(subtestDone, subtestFailed);
|
||||
|
||||
</script>
|
||||
|
|
|
@ -9,9 +9,11 @@
|
|||
<script src="/tests/SimpleTest/paint_listener.js"></script>
|
||||
<script type="text/javascript">
|
||||
|
||||
function* test(testDriver) {
|
||||
async function test() {
|
||||
var scrollableDiv = document.getElementById("scrollable");
|
||||
scrollableDiv.addEventListener("scroll", () => setTimeout(testDriver, 0), {once: true});
|
||||
let scrollPromise = new Promise(resolve => {
|
||||
scrollableDiv.addEventListener("scroll", resolve, {once: true});
|
||||
});
|
||||
|
||||
// Scroll down a small amount (10px). The bug in this case is that the
|
||||
// scrollthumb "jumps" by an additional 40 pixels (height of the "gap" div)
|
||||
|
@ -22,7 +24,7 @@ function* test(testDriver) {
|
|||
// the scrollthumb should be approximately 80px tall, and dragging it 10px
|
||||
// should scroll approximately 50 pixels. If the bug manifests, it will get
|
||||
// dragged 50px and scroll approximately 250px.
|
||||
var dragFinisher = yield* dragVerticalScrollbar(scrollableDiv, testDriver, 10, 10);
|
||||
var dragFinisher = await promiseVerticalScrollbarDrag(scrollableDiv, 10, 10);
|
||||
if (!dragFinisher) {
|
||||
ok(true, "No scrollbar, can't do this test");
|
||||
return;
|
||||
|
@ -31,12 +33,12 @@ function* test(testDriver) {
|
|||
// the events above might be stuck in APZ input queue for a bit until the
|
||||
// layer is activated, so we wait here until the scroll event listener is
|
||||
// triggered.
|
||||
yield;
|
||||
await scrollPromise;
|
||||
|
||||
yield* dragFinisher();
|
||||
await dragFinisher();
|
||||
|
||||
// Flush everything just to be safe
|
||||
yield flushApzRepaints(testDriver);
|
||||
await promiseApzRepaintsFlushed();
|
||||
|
||||
// In this case we just want to make sure the scroll position moved from 0
|
||||
// which indicates the thumb dragging worked properly.
|
||||
|
@ -44,7 +46,7 @@ function* test(testDriver) {
|
|||
}
|
||||
|
||||
waitUntilApzStable()
|
||||
.then(runContinuation(test))
|
||||
.then(test)
|
||||
.then(subtestDone, subtestFailed);
|
||||
|
||||
</script>
|
||||
|
|
|
@ -9,9 +9,11 @@
|
|||
<script src="/tests/SimpleTest/paint_listener.js"></script>
|
||||
<script type="text/javascript">
|
||||
|
||||
function* test(testDriver) {
|
||||
async function test() {
|
||||
var scrollableDiv = document.getElementById("scrollable");
|
||||
scrollableDiv.addEventListener("scroll", () => setTimeout(testDriver, 0), {once: true});
|
||||
let scrollPromise = new Promise(resolve => {
|
||||
scrollableDiv.addEventListener("scroll", resolve, {once: true});
|
||||
});
|
||||
|
||||
// Scroll down a small amount (10px). The bug in this case is that the
|
||||
// scrollthumb "jumps" most of the way down the scroll track because with
|
||||
|
@ -21,7 +23,7 @@ function* test(testDriver) {
|
|||
// the scrollthumb should be approximately 80px tall, and dragging it 10px
|
||||
// should scroll approximately 50 pixels. If the bug manifests, it will get
|
||||
// dragged an extra ~150px and scroll to approximately 1250px.
|
||||
var dragFinisher = yield* dragVerticalScrollbar(scrollableDiv, testDriver, 10, 10);
|
||||
var dragFinisher = await promiseVerticalScrollbarDrag(scrollableDiv, 10, 10);
|
||||
if (!dragFinisher) {
|
||||
ok(true, "No scrollbar, can't do this test");
|
||||
return;
|
||||
|
@ -30,12 +32,12 @@ function* test(testDriver) {
|
|||
// the events above might be stuck in APZ input queue for a bit until the
|
||||
// layer is activated, so we wait here until the scroll event listener is
|
||||
// triggered.
|
||||
yield;
|
||||
await scrollPromise;
|
||||
|
||||
yield* dragFinisher();
|
||||
await dragFinisher();
|
||||
|
||||
// Flush everything just to be safe
|
||||
yield flushApzRepaints(testDriver);
|
||||
await promiseApzRepaintsFlushed();
|
||||
|
||||
// In this case we just want to make sure the scroll position moved from 0
|
||||
// which indicates the thumb dragging worked properly.
|
||||
|
@ -43,7 +45,7 @@ function* test(testDriver) {
|
|||
}
|
||||
|
||||
waitUntilApzStable()
|
||||
.then(runContinuation(test))
|
||||
.then(test)
|
||||
.then(subtestDone, subtestFailed);
|
||||
|
||||
</script>
|
||||
|
|
|
@ -9,9 +9,11 @@
|
|||
<script src="/tests/SimpleTest/paint_listener.js"></script>
|
||||
<script type="text/javascript">
|
||||
|
||||
function* test(testDriver) {
|
||||
async function test() {
|
||||
var scrollableDiv = document.getElementById("scrollable");
|
||||
scrollableDiv.addEventListener("scroll", () => setTimeout(testDriver, 0), {once: true});
|
||||
let scrollPromise = new Promise(resolve => {
|
||||
scrollableDiv.addEventListener("scroll", resolve, {once: true});
|
||||
});
|
||||
|
||||
// Scroll down a small amount (7px). The bug in this case is that the
|
||||
// scrollthumb "jumps" most of the way down the scroll track because with
|
||||
|
@ -20,7 +22,7 @@ function* test(testDriver) {
|
|||
// the scrollthumb should be approximately 0.7*80px = 56px tall. Dragging it 7px
|
||||
// should scroll approximately 50 (unscaled) pixels. If the bug manifests, it will get
|
||||
// dragged by a lot more and scroll to approximately 1300px.
|
||||
var dragFinisher = yield* dragVerticalScrollbar(scrollableDiv, testDriver, 7, 7, 0.7);
|
||||
var dragFinisher = await promiseVerticalScrollbarDrag(scrollableDiv, 7, 7, 0.7);
|
||||
if (!dragFinisher) {
|
||||
ok(true, "No scrollbar, can't do this test");
|
||||
return;
|
||||
|
@ -29,12 +31,12 @@ function* test(testDriver) {
|
|||
// the events above might be stuck in APZ input queue for a bit until the
|
||||
// layer is activated, so we wait here until the scroll event listener is
|
||||
// triggered.
|
||||
yield;
|
||||
await scrollPromise;
|
||||
|
||||
yield* dragFinisher();
|
||||
await dragFinisher();
|
||||
|
||||
// Flush everything just to be safe
|
||||
yield flushApzRepaints(testDriver);
|
||||
await promiseApzRepaintsFlushed();
|
||||
|
||||
// Ensure the scroll position ended up roughly where we wanted it (around
|
||||
// 50px, but definitely less than 1300px).
|
||||
|
@ -42,7 +44,7 @@ function* test(testDriver) {
|
|||
}
|
||||
|
||||
waitUntilApzStable()
|
||||
.then(runContinuation(test))
|
||||
.then(test)
|
||||
.then(subtestDone, subtestFailed);
|
||||
|
||||
</script>
|
||||
|
|
|
@ -15,12 +15,14 @@
|
|||
</style>
|
||||
<script type="text/javascript">
|
||||
|
||||
function* test(testDriver) {
|
||||
window.addEventListener("scroll", () => setTimeout(testDriver, 0), {once: true});
|
||||
async function test() {
|
||||
let scrollPromise = new Promise(resolve => {
|
||||
window.addEventListener("scroll", resolve, {once: true});
|
||||
});
|
||||
|
||||
// Do the scroll in one increment so that when the scroll event fires
|
||||
// we're done all the scrolling we're going to do.
|
||||
var dragFinisher = yield* dragVerticalScrollbar(window, testDriver, 20, 20);
|
||||
var dragFinisher = await promiseVerticalScrollbarDrag(window, 20, 20);
|
||||
if (!dragFinisher) {
|
||||
ok(true, "No scrollbar, can't do this test");
|
||||
return;
|
||||
|
@ -29,12 +31,12 @@ function* test(testDriver) {
|
|||
// the events above might be stuck in APZ input queue for a bit until the
|
||||
// layer is activated, so we wait here until the scroll event listener is
|
||||
// triggered.
|
||||
yield;
|
||||
await scrollPromise;
|
||||
|
||||
yield* dragFinisher();
|
||||
await dragFinisher();
|
||||
|
||||
// Flush everything just to be safe
|
||||
yield flushApzRepaints(testDriver);
|
||||
await promiseApzRepaintsFlushed();
|
||||
|
||||
// After dragging the scrollbar 20px on a 1000px-high viewport, we should
|
||||
// have scrolled approx 2% of the 5000px high content. There might have been
|
||||
|
@ -48,7 +50,7 @@ function* test(testDriver) {
|
|||
}
|
||||
|
||||
waitUntilApzStable()
|
||||
.then(runContinuation(test))
|
||||
.then(test)
|
||||
.then(subtestDone, subtestFailed);
|
||||
|
||||
</script>
|
||||
|
|
|
@ -20,7 +20,7 @@ async function test() {
|
|||
// what the expected behaviour is.
|
||||
var snapMultiplier = SpecialPowers.getIntPref("slider.snapMultiplier");
|
||||
|
||||
// Much of the code below is "inlined" from dragVerticalScrollbar. Reusing
|
||||
// Much of the code below is "inlined" from promiseVerticalScrollbarDrag. Reusing
|
||||
// that code was nontrivial given the modifications we needed to make, and
|
||||
// would have increased the complexity of that helper function more than I'd
|
||||
// like. However if any bugfixes are made to that function this code might
|
||||
|
|
|
@ -1588,19 +1588,25 @@ impl Device {
|
|||
// && renderer_name.starts_with("AMD");
|
||||
// (XXX: we apply this restriction to all GPUs to handle switching)
|
||||
|
||||
let is_angle = renderer_name.starts_with("ANGLE");
|
||||
|
||||
// On certain GPUs PBO texture upload is only performed asynchronously
|
||||
// if the stride of the data is a multiple of a certain value.
|
||||
// On Adreno it must be a multiple of 64 pixels, meaning value in bytes
|
||||
// varies with the texture format.
|
||||
// On AMD Mac, it must always be a multiple of 256 bytes.
|
||||
// Other platforms may have similar requirements and should be added
|
||||
// here.
|
||||
// The default value should be 4 bytes.
|
||||
let optimal_pbo_stride = if is_adreno {
|
||||
// On Adreno it must be a multiple of 64 pixels, meaning value in bytes
|
||||
// varies with the texture format.
|
||||
StrideAlignment::Pixels(NonZeroUsize::new(64).unwrap())
|
||||
} else if is_macos {
|
||||
// On AMD Mac, it must always be a multiple of 256 bytes.
|
||||
// We apply this restriction to all GPUs to handle switching
|
||||
StrideAlignment::Bytes(NonZeroUsize::new(256).unwrap())
|
||||
} else if is_angle {
|
||||
// On ANGLE, PBO texture uploads get incorrectly truncated if
|
||||
// the stride is greater than the width * bpp.
|
||||
StrideAlignment::Bytes(NonZeroUsize::new(1).unwrap())
|
||||
} else {
|
||||
// Other platforms may have similar requirements and should be added
|
||||
// here. The default value should be 4 bytes.
|
||||
StrideAlignment::Bytes(NonZeroUsize::new(4).unwrap())
|
||||
};
|
||||
|
||||
|
|
|
@ -168,6 +168,9 @@ pub struct FrameGraphBuilder {
|
|||
// Keep a map of `texture_id` to metadata about surfaces that are currently
|
||||
// borrowed from the render target pool.
|
||||
active_surfaces: FastHashMap<CacheTextureId, Surface>,
|
||||
|
||||
/// A temporary buffer used by assign_free_pass. Kept here to avoid heap reallocs
|
||||
child_task_buffer: Vec<RenderTaskId>,
|
||||
}
|
||||
|
||||
impl FrameGraphBuilder {
|
||||
|
@ -181,6 +184,7 @@ impl FrameGraphBuilder {
|
|||
frame_id: FrameId::INVALID,
|
||||
textures_to_free: FastHashSet::default(),
|
||||
active_surfaces: FastHashMap::default(),
|
||||
child_task_buffer: Vec::new(),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -304,6 +308,7 @@ impl FrameGraphBuilder {
|
|||
match roots.get(&target_id) {
|
||||
Some(root_task_id) => {
|
||||
graph.tasks[task_id.index as usize].children.push(*root_task_id);
|
||||
self.roots.remove(root_task_id);
|
||||
}
|
||||
None => {
|
||||
println!("WARN: {:?} depends on root {:?} but it has no tasks!",
|
||||
|
@ -333,10 +338,13 @@ impl FrameGraphBuilder {
|
|||
);
|
||||
}
|
||||
|
||||
// Traverse each root, and assign `free_after` for each task
|
||||
for root_id in &self.roots {
|
||||
// Determine which pass each task can be freed on, which depends on which is
|
||||
// the last task that has this as an input.
|
||||
for i in 0 .. graph.tasks.len() {
|
||||
let task_id = RenderTaskId { index: i as u32 };
|
||||
assign_free_pass(
|
||||
*root_id,
|
||||
task_id,
|
||||
&mut self.child_task_buffer,
|
||||
&mut graph,
|
||||
);
|
||||
}
|
||||
|
@ -624,6 +632,12 @@ fn assign_render_pass(
|
|||
let mut child_task_ids: SmallVec<[RenderTaskId; 8]> = SmallVec::new();
|
||||
child_task_ids.extend_from_slice(&task.children);
|
||||
|
||||
// No point in recursing into paths in the graph if this task already
|
||||
// has been set to draw after this pass.
|
||||
if task.render_on > pass {
|
||||
return;
|
||||
}
|
||||
|
||||
// A task should be rendered on the earliest pass in the dependency
|
||||
// graph that it's required. Using max here ensures the correct value
|
||||
// in the presense of multiple paths to this task from the root(s).
|
||||
|
@ -641,20 +655,20 @@ fn assign_render_pass(
|
|||
}
|
||||
}
|
||||
|
||||
/// Recursive helper to assign pass that a task should free its backing surface on
|
||||
fn assign_free_pass(
|
||||
id: RenderTaskId,
|
||||
child_task_buffer: &mut Vec<RenderTaskId>,
|
||||
graph: &mut FrameGraph,
|
||||
) {
|
||||
let task = &graph.tasks[id.index as usize];
|
||||
let render_on = task.render_on;
|
||||
debug_assert!(child_task_buffer.is_empty());
|
||||
|
||||
// TODO(gw): Work around the borrowck - maybe we could structure the dependencies
|
||||
// storage better, to avoid this?
|
||||
let mut child_task_ids: SmallVec<[RenderTaskId; 8]> = SmallVec::new();
|
||||
child_task_ids.extend_from_slice(&task.children);
|
||||
child_task_buffer.extend_from_slice(&task.children);
|
||||
|
||||
for child_id in child_task_ids {
|
||||
for child_id in child_task_buffer.drain(..) {
|
||||
let child_task = &mut graph.tasks[child_id.index as usize];
|
||||
|
||||
// Each dynamic child task can free its backing surface after the last
|
||||
|
@ -673,11 +687,6 @@ fn assign_free_pass(
|
|||
panic!("bug: should not be allocated yet");
|
||||
}
|
||||
}
|
||||
|
||||
assign_free_pass(
|
||||
child_id,
|
||||
graph,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@ authors = ["Zibi Braniecki <zibi@braniecki.net>"]
|
|||
edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
fluent = { version = "0.13.1", features = ["fluent-pseudo"] }
|
||||
fluent = { version = "0.14.1", features = ["fluent-pseudo"] }
|
||||
fluent-pseudo = "0.2.3"
|
||||
intl-memoizer = "0.5"
|
||||
unic-langid = "0.9"
|
||||
|
|
|
@ -3,7 +3,6 @@
|
|||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
use crate::builtins::{FluentDateTime, FluentDateTimeOptions, NumberFormat};
|
||||
use fluent::resolver::ResolverError;
|
||||
pub use fluent::{FluentArgs, FluentBundle, FluentError, FluentResource, FluentValue};
|
||||
use fluent_pseudo::transform_dom;
|
||||
pub use intl_memoizer::IntlLangMemoizer;
|
||||
|
@ -92,7 +91,7 @@ fn fluent_bundle_new_internal(
|
|||
use_isolating: bool,
|
||||
pseudo_strategy: &nsACString,
|
||||
) -> Box<FluentBundleRc> {
|
||||
let mut bundle = FluentBundle::new(langids.iter());
|
||||
let mut bundle = FluentBundle::new(langids.to_vec());
|
||||
bundle.set_use_isolating(use_isolating);
|
||||
|
||||
bundle.set_formatter(Some(format_numbers));
|
||||
|
@ -265,40 +264,6 @@ fn convert_args<'a>(
|
|||
|
||||
fn append_fluent_errors_to_ret_errors(ret_errors: &mut ThinVec<nsCString>, errors: &[FluentError]) {
|
||||
for error in errors {
|
||||
match error {
|
||||
FluentError::ResolverError(ref err) => match err {
|
||||
ResolverError::Reference(ref s) => {
|
||||
let error = format!("ReferenceError: {}", s);
|
||||
ret_errors.push(error.into());
|
||||
}
|
||||
ResolverError::MissingDefault => {
|
||||
let error = "RangeError: No default value for selector";
|
||||
ret_errors.push(error.into());
|
||||
}
|
||||
ResolverError::Cyclic => {
|
||||
let error =
|
||||
"RangeError: Cyclic reference encountered while resolving a message";
|
||||
ret_errors.push(error.into());
|
||||
}
|
||||
ResolverError::TooManyPlaceables => {
|
||||
let error = "RangeError: Too many placeables in a message";
|
||||
ret_errors.push(error.into());
|
||||
}
|
||||
},
|
||||
FluentError::Overriding { kind, id } => {
|
||||
let error = format!(
|
||||
"OverrideError: An entry {} of type {} is already defined in this bundle",
|
||||
id, kind
|
||||
);
|
||||
ret_errors.push(error.into());
|
||||
}
|
||||
FluentError::ParserError(pe) => {
|
||||
let error = format!(
|
||||
"ParserError: Error of kind {:#?} in position: ({}, {})",
|
||||
pe.kind, pe.pos.0, pe.pos.1
|
||||
);
|
||||
ret_errors.push(error.into());
|
||||
}
|
||||
}
|
||||
ret_errors.push(error.to_string().into());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -69,7 +69,7 @@ key2 =
|
|||
ok(false, "Missing argument didn't cause an exception.");
|
||||
} catch (e) {
|
||||
is(e,
|
||||
"[fluent][resolver] errors in en-US/key2: ReferenceError: Unknown variable: $user.",
|
||||
"[fluent][resolver] errors in en-US/key2: Resolver error: Unknown variable: $user.",
|
||||
"Missing key causes an exception.");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -54,7 +54,7 @@ key3 = Value { $count }
|
|||
ok(false, "Missing argument didn't cause an exception.");
|
||||
} catch (e) {
|
||||
is(e,
|
||||
"[fluent][resolver] errors in en-US/key3: ReferenceError: Unknown variable: $count.",
|
||||
"[fluent][resolver] errors in en-US/key3: Resolver error: Unknown variable: $count.",
|
||||
"Missing key causes an exception.");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -52,7 +52,7 @@ key3 = Value { $count }
|
|||
ok(false, "Missing argument didn't cause an exception.");
|
||||
} catch (e) {
|
||||
is(e,
|
||||
"[fluent][resolver] errors in en-US/key2: ReferenceError: Unknown variable: $user.",
|
||||
"[fluent][resolver] errors in en-US/key2: Resolver error: Unknown variable: $user.",
|
||||
"Missing key causes an exception.");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -378,6 +378,27 @@ extern JS_FRIEND_API double* JS_GetFloat64ArrayData(JSObject* obj,
|
|||
extern JS_FRIEND_API void* JS_GetArrayBufferViewData(
|
||||
JSObject* obj, bool* isSharedMemory, const JS::AutoRequireNoGC&);
|
||||
|
||||
/**
|
||||
* Return a "fixed" pointer (one that will not move during a GC) to the
|
||||
* ArrayBufferView's data. Note that this will not keep the object alive; the
|
||||
* holding object should be rooted or traced. If the view is storing the data
|
||||
* inline, this will copy the data to the provided buffer, returning nullptr if
|
||||
* bufSize is inadequate.
|
||||
*
|
||||
* Avoid using this unless necessary. JS_GetArrayBufferViewData is simpler and
|
||||
* more efficient because it requires the caller to ensure that a GC will not
|
||||
* occur and thus does not need to handle movable data.
|
||||
*/
|
||||
extern JS_FRIEND_API uint8_t* JS_GetArrayBufferViewFixedData(
|
||||
JSObject* obj, uint8_t* buffer, size_t bufSize);
|
||||
|
||||
/**
|
||||
* If the bufSize passed to JS_GetArrayBufferViewFixedData is at least this
|
||||
* many bytes, then any copied data is guaranteed to fit into the provided
|
||||
* buffer.
|
||||
*/
|
||||
extern JS_FRIEND_API size_t JS_MaxMovableTypedArraySize();
|
||||
|
||||
/**
|
||||
* Return the ArrayBuffer or SharedArrayBuffer underlying an ArrayBufferView.
|
||||
* This may return a detached buffer. |obj| must be an object that would
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
#include "jsapi.h"
|
||||
|
||||
#include "gc/Tracer.h"
|
||||
#include "jit/InlinableNatives.h"
|
||||
#include "js/friend/ErrorMessages.h" // js::GetErrorMessage, JSMSG_*
|
||||
#include "js/PropertySpec.h"
|
||||
#include "js/TracingAPI.h"
|
||||
|
@ -231,4 +232,5 @@ const JSFunctionSpec BigIntObject::methods[] = {
|
|||
JS_FS_END};
|
||||
|
||||
const JSFunctionSpec BigIntObject::staticMethods[] = {
|
||||
JS_FN("asUintN", asUintN, 2, 0), JS_FN("asIntN", asIntN, 2, 0), JS_FS_END};
|
||||
JS_INLINABLE_FN("asUintN", asUintN, 2, 0, BigIntAsUintN),
|
||||
JS_INLINABLE_FN("asIntN", asIntN, 2, 0, BigIntAsIntN), JS_FS_END};
|
||||
|
|
|
@ -182,11 +182,15 @@ function edgeUsesVariable(edge, variable, body)
|
|||
switch (edge.Kind) {
|
||||
|
||||
case "Assign": {
|
||||
// Detect `Return := nullptr`.
|
||||
if (isReturningImmobileValue(edge, variable))
|
||||
return 0;
|
||||
const [lhs, rhs] = edge.Exp;
|
||||
// Detect `lhs := ...variable...`
|
||||
if (expressionUsesVariable(rhs, variable))
|
||||
return src;
|
||||
// Detect `...variable... := rhs` but not `variable := rhs`. The latter
|
||||
// overwrites the previous value of `variable` without using it.
|
||||
if (expressionUsesVariable(lhs, variable) && !expressionIsVariable(lhs, variable))
|
||||
return src;
|
||||
return 0;
|
||||
|
@ -276,6 +280,16 @@ function expressionIsVariable(exp, variable)
|
|||
return exp.Kind == "Var" && sameVariable(exp.Variable, variable);
|
||||
}
|
||||
|
||||
function expressionIsMethodOnVariable(exp, variable)
|
||||
{
|
||||
// This might be calling a method on a base class, in which case exp will
|
||||
// be an unnamed field of the variable instead of the variable itself.
|
||||
while (exp.Kind == "Fld" && exp.Field.Name[0].startsWith("field:"))
|
||||
exp = exp.Exp[0];
|
||||
|
||||
return exp.Kind == "Var" && sameVariable(exp.Variable, variable);
|
||||
}
|
||||
|
||||
// Return whether the edge terminates the live range of a variable's value when
|
||||
// searching in reverse through the CFG, by setting it to some new value.
|
||||
// Examples of killing 'obj's live range:
|
||||
|
@ -453,33 +467,32 @@ function edgeInvalidatesVariable(edge, variable, body)
|
|||
if (edge.Type.Kind == 'Function' &&
|
||||
edge.Type.TypeFunctionCSU &&
|
||||
edge.PEdgeCallInstance &&
|
||||
edge.PEdgeCallInstance.Exp.Kind == 'Var' &&
|
||||
expressionIsVariable(edge.PEdgeCallInstance.Exp, variable))
|
||||
do {
|
||||
expressionIsMethodOnVariable(edge.PEdgeCallInstance.Exp, variable))
|
||||
{
|
||||
const typeName = edge.Type.TypeFunctionCSU.Type.Name;
|
||||
const m = typeName.match(/^(((\w|::)+?)(\w+))</);
|
||||
if (!m)
|
||||
break;
|
||||
const [, type, namespace,, classname] = m;
|
||||
if (m) {
|
||||
const [, type, namespace,, classname] = m;
|
||||
|
||||
// special-case: the initial constructor that doesn't provide a value.
|
||||
// Useful for things like Maybe<T>.
|
||||
if (callee.Kind == 'Var' &&
|
||||
typesWithSafeConstructors.has(type) &&
|
||||
callee.Variable.Name[0].includes(`${namespace}${classname}<T>::${classname}()`))
|
||||
{
|
||||
return true;
|
||||
// special-case: the initial constructor that doesn't provide a value.
|
||||
// Useful for things like Maybe<T>.
|
||||
const ctorName = `${namespace}${classname}<T>::${classname}()`;
|
||||
if (callee.Kind == 'Var' &&
|
||||
typesWithSafeConstructors.has(type) &&
|
||||
callee.Variable.Name[0].includes(ctorName))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
// special-case: UniquePtr::reset() and similar.
|
||||
if (callee.Kind == 'Var' &&
|
||||
type in resetterMethods &&
|
||||
resetterMethods[type].has(callee.Variable.Name[1]))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// special-case: UniquePtr::reset() and similar.
|
||||
if (callee.Kind == 'Var' &&
|
||||
type in resetterMethods &&
|
||||
resetterMethods[type].has(callee.Variable.Name[1]))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
} while(0);
|
||||
}
|
||||
|
||||
// special-case: passing UniquePtr<T> by value.
|
||||
if (edge.Type.Kind == 'Function' &&
|
||||
|
|
|
@ -31,6 +31,7 @@ var resetterMethods = {
|
|||
'mozilla::UniquePtr': new Set(["reset"]),
|
||||
'js::UniquePtr': new Set(["reset"]),
|
||||
'mozilla::dom::Nullable': new Set(["SetNull"]),
|
||||
'mozilla::dom::TypedArray_base': new Set(["Reset"]),
|
||||
};
|
||||
|
||||
function indirectCallCannotGC(fullCaller, fullVariable)
|
||||
|
|
|
@ -812,40 +812,22 @@ XDRResult XDRParserAtomEntry(XDRState<mode>* xdr, ParserAtomEntry** entryp) {
|
|||
static_assert(CanCopyDataToDisk<ParserAtomEntry>::value,
|
||||
"ParserAtomEntry cannot be bulk-copied to disk.");
|
||||
|
||||
constexpr size_t HeaderSize = sizeof(ParserAtomEntry);
|
||||
auto ComputeTotalLength = [](bool hasLatin1Chars, size_t length) {
|
||||
const size_t CharSize =
|
||||
hasLatin1Chars ? sizeof(JS::Latin1Char) : sizeof(char16_t);
|
||||
return HeaderSize + (CharSize * length);
|
||||
};
|
||||
MOZ_TRY(xdr->align32());
|
||||
|
||||
const ParserAtomEntry* header;
|
||||
if (mode == XDR_ENCODE) {
|
||||
size_t totalLength =
|
||||
ComputeTotalLength((*entryp)->hasLatin1Chars(), (*entryp)->length());
|
||||
MOZ_TRY(xdr->codeBytes(*entryp, totalLength));
|
||||
header = *entryp;
|
||||
} else {
|
||||
// Peek the header bytes without consuming buffer yet. Once we compute the
|
||||
// total length, we will read the entire atom at once.
|
||||
ParserAtomEntry header;
|
||||
const uint8_t* cursor = nullptr;
|
||||
MOZ_TRY(xdr->peekData(&cursor, HeaderSize));
|
||||
memcpy(&header, cursor, HeaderSize);
|
||||
|
||||
// Get the entire atom at once. The `raw` pointer is into the XDR buffer and
|
||||
// has no particular alignment.
|
||||
const uint8_t* raw = nullptr;
|
||||
size_t totalLength =
|
||||
ComputeTotalLength(header.hasLatin1Chars(), header.length());
|
||||
MOZ_TRY(xdr->readData(&raw, totalLength));
|
||||
|
||||
// Copy into the LifoAlloc and properly align the data.
|
||||
(*entryp) = ParserAtomEntry::allocateRaw(xdr->cx(), xdr->stencilAlloc(),
|
||||
raw, totalLength);
|
||||
if (!*entryp) {
|
||||
return xdr->fail(JS::TranscodeResult_Throw);
|
||||
}
|
||||
MOZ_TRY(xdr->peekData(&header));
|
||||
}
|
||||
|
||||
const uint32_t CharSize =
|
||||
header->hasLatin1Chars() ? sizeof(JS::Latin1Char) : sizeof(char16_t);
|
||||
uint32_t totalLength =
|
||||
sizeof(ParserAtomEntry) + (CharSize * header->length());
|
||||
|
||||
MOZ_TRY(xdr->borrowedData(entryp, totalLength));
|
||||
|
||||
return Ok();
|
||||
}
|
||||
|
||||
|
|
|
@ -46,39 +46,21 @@ template <XDRMode mode, typename ScopeT>
|
|||
static_assert(offsetof(ScopeDataT, trailingNames) == sizeof(SlotInfo),
|
||||
"trailingNames should be the second field");
|
||||
|
||||
constexpr size_t SlotInfoSize = sizeof(SlotInfo);
|
||||
auto ComputeTotalLength = [](size_t length) {
|
||||
return SlotInfoSize +
|
||||
sizeof(AbstractBindingName<TaggedParserAtomIndex>) * length;
|
||||
};
|
||||
MOZ_TRY(xdr->align32());
|
||||
|
||||
const SlotInfo* slotInfo;
|
||||
if (mode == XDR_ENCODE) {
|
||||
ScopeDataT* scopeData = static_cast<ScopeDataT*>(baseScopeData);
|
||||
const SlotInfo* slotInfo = &scopeData->slotInfo;
|
||||
uint32_t totalLength = ComputeTotalLength(slotInfo->length);
|
||||
MOZ_TRY(xdr->codeBytes(scopeData, totalLength));
|
||||
slotInfo = &scopeData->slotInfo;
|
||||
} else {
|
||||
// Peek the SlotInfo bytes without consuming buffer yet. Once we compute the
|
||||
// total length, we will read the entire scope data at once.
|
||||
SlotInfo slotInfo;
|
||||
const uint8_t* cursor = nullptr;
|
||||
MOZ_TRY(xdr->peekData(&cursor, SlotInfoSize));
|
||||
memcpy(&slotInfo, cursor, SlotInfoSize);
|
||||
|
||||
// Allocate scope data with trailing names.
|
||||
uint32_t totalLength = ComputeTotalLength(slotInfo.length);
|
||||
ScopeDataT* scopeData =
|
||||
reinterpret_cast<ScopeDataT*>(xdr->stencilAlloc().alloc(totalLength));
|
||||
if (!scopeData) {
|
||||
js::ReportOutOfMemory(xdr->cx());
|
||||
return xdr->fail(JS::TranscodeResult_Throw);
|
||||
}
|
||||
|
||||
// Decode SlotInfo and trailing names at once.
|
||||
MOZ_TRY(xdr->codeBytes(scopeData, totalLength));
|
||||
baseScopeData = scopeData;
|
||||
MOZ_TRY(xdr->peekData(&slotInfo));
|
||||
}
|
||||
|
||||
uint32_t totalLength =
|
||||
sizeof(SlotInfo) +
|
||||
sizeof(AbstractBindingName<TaggedParserAtomIndex>) * slotInfo->length;
|
||||
MOZ_TRY(xdr->borrowedData(&baseScopeData, totalLength));
|
||||
|
||||
return Ok();
|
||||
}
|
||||
|
||||
|
@ -183,9 +165,24 @@ static XDRResult XDRSpanContent(XDRState<mode>* xdr, mozilla::Span<T>& span) {
|
|||
"Span cannot be bulk-copied to disk.");
|
||||
|
||||
uint32_t size;
|
||||
MOZ_TRY(XDRSpanUninitialized(xdr, span, size));
|
||||
if (mode == XDR_ENCODE) {
|
||||
MOZ_ASSERT(span.size() <= UINT32_MAX);
|
||||
size = span.size();
|
||||
}
|
||||
|
||||
MOZ_TRY(xdr->codeUint32(&size));
|
||||
|
||||
if (size) {
|
||||
MOZ_TRY(xdr->codeBytes(span.data(), sizeof(T) * size));
|
||||
MOZ_TRY(xdr->align32());
|
||||
|
||||
T* data;
|
||||
if (mode == XDR_ENCODE) {
|
||||
data = span.data();
|
||||
}
|
||||
MOZ_TRY(xdr->borrowedData(&data, sizeof(T) * size));
|
||||
if (mode == XDR_DECODE) {
|
||||
span = mozilla::Span(data, size);
|
||||
}
|
||||
}
|
||||
|
||||
return Ok();
|
||||
|
|
|
@ -0,0 +1,473 @@
|
|||
const tests = [
|
||||
[-0x10000000000000001n, 0, 0n],
|
||||
[-0x10000000000000000n, 0, 0n],
|
||||
[-0xffffffffffffffffn, 0, 0n],
|
||||
[-0xfffffffffffffffen, 0, 0n],
|
||||
[-0x8000000000000001n, 0, 0n],
|
||||
[-0x8000000000000000n, 0, 0n],
|
||||
[-0x7fffffffffffffffn, 0, 0n],
|
||||
[-0x7ffffffffffffffen, 0, 0n],
|
||||
[-0x100000001n, 0, 0n],
|
||||
[-0x100000000n, 0, 0n],
|
||||
[-0xffffffffn, 0, 0n],
|
||||
[-0xfffffffen, 0, 0n],
|
||||
[-0x80000001n, 0, 0n],
|
||||
[-0x80000000n, 0, 0n],
|
||||
[-0x7fffffffn, 0, 0n],
|
||||
[-0x7ffffffen, 0, 0n],
|
||||
[-9n, 0, 0n],
|
||||
[-8n, 0, 0n],
|
||||
[-7n, 0, 0n],
|
||||
[-6n, 0, 0n],
|
||||
[-5n, 0, 0n],
|
||||
[-4n, 0, 0n],
|
||||
[-3n, 0, 0n],
|
||||
[-2n, 0, 0n],
|
||||
[-1n, 0, 0n],
|
||||
[0n, 0, 0n],
|
||||
[1n, 0, 0n],
|
||||
[2n, 0, 0n],
|
||||
[3n, 0, 0n],
|
||||
[4n, 0, 0n],
|
||||
[5n, 0, 0n],
|
||||
[6n, 0, 0n],
|
||||
[7n, 0, 0n],
|
||||
[8n, 0, 0n],
|
||||
[9n, 0, 0n],
|
||||
[0x7ffffffen, 0, 0n],
|
||||
[0x7fffffffn, 0, 0n],
|
||||
[0x80000000n, 0, 0n],
|
||||
[0x80000001n, 0, 0n],
|
||||
[0xfffffffen, 0, 0n],
|
||||
[0xffffffffn, 0, 0n],
|
||||
[0x100000000n, 0, 0n],
|
||||
[0x100000001n, 0, 0n],
|
||||
[0x7ffffffffffffffen, 0, 0n],
|
||||
[0x7fffffffffffffffn, 0, 0n],
|
||||
[0x8000000000000000n, 0, 0n],
|
||||
[0x8000000000000001n, 0, 0n],
|
||||
[0xfffffffffffffffen, 0, 0n],
|
||||
[0xffffffffffffffffn, 0, 0n],
|
||||
[0x10000000000000000n, 0, 0n],
|
||||
[0x10000000000000001n, 0, 0n],
|
||||
[-0x10000000000000001n, 1, -1n],
|
||||
[-0x10000000000000000n, 1, 0n],
|
||||
[-0xffffffffffffffffn, 1, -1n],
|
||||
[-0xfffffffffffffffen, 1, 0n],
|
||||
[-0x8000000000000001n, 1, -1n],
|
||||
[-0x8000000000000000n, 1, 0n],
|
||||
[-0x7fffffffffffffffn, 1, -1n],
|
||||
[-0x7ffffffffffffffen, 1, 0n],
|
||||
[-0x100000001n, 1, -1n],
|
||||
[-0x100000000n, 1, 0n],
|
||||
[-0xffffffffn, 1, -1n],
|
||||
[-0xfffffffen, 1, 0n],
|
||||
[-0x80000001n, 1, -1n],
|
||||
[-0x80000000n, 1, 0n],
|
||||
[-0x7fffffffn, 1, -1n],
|
||||
[-0x7ffffffen, 1, 0n],
|
||||
[-9n, 1, -1n],
|
||||
[-8n, 1, 0n],
|
||||
[-7n, 1, -1n],
|
||||
[-6n, 1, 0n],
|
||||
[-5n, 1, -1n],
|
||||
[-4n, 1, 0n],
|
||||
[-3n, 1, -1n],
|
||||
[-2n, 1, 0n],
|
||||
[-1n, 1, -1n],
|
||||
[0n, 1, 0n],
|
||||
[1n, 1, -1n],
|
||||
[2n, 1, 0n],
|
||||
[3n, 1, -1n],
|
||||
[4n, 1, 0n],
|
||||
[5n, 1, -1n],
|
||||
[6n, 1, 0n],
|
||||
[7n, 1, -1n],
|
||||
[8n, 1, 0n],
|
||||
[9n, 1, -1n],
|
||||
[0x7ffffffen, 1, 0n],
|
||||
[0x7fffffffn, 1, -1n],
|
||||
[0x80000000n, 1, 0n],
|
||||
[0x80000001n, 1, -1n],
|
||||
[0xfffffffen, 1, 0n],
|
||||
[0xffffffffn, 1, -1n],
|
||||
[0x100000000n, 1, 0n],
|
||||
[0x100000001n, 1, -1n],
|
||||
[0x7ffffffffffffffen, 1, 0n],
|
||||
[0x7fffffffffffffffn, 1, -1n],
|
||||
[0x8000000000000000n, 1, 0n],
|
||||
[0x8000000000000001n, 1, -1n],
|
||||
[0xfffffffffffffffen, 1, 0n],
|
||||
[0xffffffffffffffffn, 1, -1n],
|
||||
[0x10000000000000000n, 1, 0n],
|
||||
[0x10000000000000001n, 1, -1n],
|
||||
[-0x10000000000000001n, 2, -1n],
|
||||
[-0x10000000000000000n, 2, 0n],
|
||||
[-0xffffffffffffffffn, 2, 1n],
|
||||
[-0xfffffffffffffffen, 2, -2n],
|
||||
[-0x8000000000000001n, 2, -1n],
|
||||
[-0x8000000000000000n, 2, 0n],
|
||||
[-0x7fffffffffffffffn, 2, 1n],
|
||||
[-0x7ffffffffffffffen, 2, -2n],
|
||||
[-0x100000001n, 2, -1n],
|
||||
[-0x100000000n, 2, 0n],
|
||||
[-0xffffffffn, 2, 1n],
|
||||
[-0xfffffffen, 2, -2n],
|
||||
[-0x80000001n, 2, -1n],
|
||||
[-0x80000000n, 2, 0n],
|
||||
[-0x7fffffffn, 2, 1n],
|
||||
[-0x7ffffffen, 2, -2n],
|
||||
[-9n, 2, -1n],
|
||||
[-8n, 2, 0n],
|
||||
[-7n, 2, 1n],
|
||||
[-6n, 2, -2n],
|
||||
[-5n, 2, -1n],
|
||||
[-4n, 2, 0n],
|
||||
[-3n, 2, 1n],
|
||||
[-2n, 2, -2n],
|
||||
[-1n, 2, -1n],
|
||||
[0n, 2, 0n],
|
||||
[1n, 2, 1n],
|
||||
[2n, 2, -2n],
|
||||
[3n, 2, -1n],
|
||||
[4n, 2, 0n],
|
||||
[5n, 2, 1n],
|
||||
[6n, 2, -2n],
|
||||
[7n, 2, -1n],
|
||||
[8n, 2, 0n],
|
||||
[9n, 2, 1n],
|
||||
[0x7ffffffen, 2, -2n],
|
||||
[0x7fffffffn, 2, -1n],
|
||||
[0x80000000n, 2, 0n],
|
||||
[0x80000001n, 2, 1n],
|
||||
[0xfffffffen, 2, -2n],
|
||||
[0xffffffffn, 2, -1n],
|
||||
[0x100000000n, 2, 0n],
|
||||
[0x100000001n, 2, 1n],
|
||||
[0x7ffffffffffffffen, 2, -2n],
|
||||
[0x7fffffffffffffffn, 2, -1n],
|
||||
[0x8000000000000000n, 2, 0n],
|
||||
[0x8000000000000001n, 2, 1n],
|
||||
[0xfffffffffffffffen, 2, -2n],
|
||||
[0xffffffffffffffffn, 2, -1n],
|
||||
[0x10000000000000000n, 2, 0n],
|
||||
[0x10000000000000001n, 2, 1n],
|
||||
[-0x10000000000000001n, 31, -1n],
|
||||
[-0x10000000000000000n, 31, 0n],
|
||||
[-0xffffffffffffffffn, 31, 1n],
|
||||
[-0xfffffffffffffffen, 31, 2n],
|
||||
[-0x8000000000000001n, 31, -1n],
|
||||
[-0x8000000000000000n, 31, 0n],
|
||||
[-0x7fffffffffffffffn, 31, 1n],
|
||||
[-0x7ffffffffffffffen, 31, 2n],
|
||||
[-0x100000001n, 31, -1n],
|
||||
[-0x100000000n, 31, 0n],
|
||||
[-0xffffffffn, 31, 1n],
|
||||
[-0xfffffffen, 31, 2n],
|
||||
[-0x80000001n, 31, -1n],
|
||||
[-0x80000000n, 31, 0n],
|
||||
[-0x7fffffffn, 31, 1n],
|
||||
[-0x7ffffffen, 31, 2n],
|
||||
[-9n, 31, -9n],
|
||||
[-8n, 31, -8n],
|
||||
[-7n, 31, -7n],
|
||||
[-6n, 31, -6n],
|
||||
[-5n, 31, -5n],
|
||||
[-4n, 31, -4n],
|
||||
[-3n, 31, -3n],
|
||||
[-2n, 31, -2n],
|
||||
[-1n, 31, -1n],
|
||||
[0n, 31, 0n],
|
||||
[1n, 31, 1n],
|
||||
[2n, 31, 2n],
|
||||
[3n, 31, 3n],
|
||||
[4n, 31, 4n],
|
||||
[5n, 31, 5n],
|
||||
[6n, 31, 6n],
|
||||
[7n, 31, 7n],
|
||||
[8n, 31, 8n],
|
||||
[9n, 31, 9n],
|
||||
[0x7ffffffen, 31, -2n],
|
||||
[0x7fffffffn, 31, -1n],
|
||||
[0x80000000n, 31, 0n],
|
||||
[0x80000001n, 31, 1n],
|
||||
[0xfffffffen, 31, -2n],
|
||||
[0xffffffffn, 31, -1n],
|
||||
[0x100000000n, 31, 0n],
|
||||
[0x100000001n, 31, 1n],
|
||||
[0x7ffffffffffffffen, 31, -2n],
|
||||
[0x7fffffffffffffffn, 31, -1n],
|
||||
[0x8000000000000000n, 31, 0n],
|
||||
[0x8000000000000001n, 31, 1n],
|
||||
[0xfffffffffffffffen, 31, -2n],
|
||||
[0xffffffffffffffffn, 31, -1n],
|
||||
[0x10000000000000000n, 31, 0n],
|
||||
[0x10000000000000001n, 31, 1n],
|
||||
[-0x10000000000000001n, 32, -1n],
|
||||
[-0x10000000000000000n, 32, 0n],
|
||||
[-0xffffffffffffffffn, 32, 1n],
|
||||
[-0xfffffffffffffffen, 32, 2n],
|
||||
[-0x8000000000000001n, 32, -1n],
|
||||
[-0x8000000000000000n, 32, 0n],
|
||||
[-0x7fffffffffffffffn, 32, 1n],
|
||||
[-0x7ffffffffffffffen, 32, 2n],
|
||||
[-0x100000001n, 32, -1n],
|
||||
[-0x100000000n, 32, 0n],
|
||||
[-0xffffffffn, 32, 1n],
|
||||
[-0xfffffffen, 32, 2n],
|
||||
[-0x80000001n, 32, 0x7fffffffn],
|
||||
[-0x80000000n, 32, -0x80000000n],
|
||||
[-0x7fffffffn, 32, -0x7fffffffn],
|
||||
[-0x7ffffffen, 32, -0x7ffffffen],
|
||||
[-9n, 32, -9n],
|
||||
[-8n, 32, -8n],
|
||||
[-7n, 32, -7n],
|
||||
[-6n, 32, -6n],
|
||||
[-5n, 32, -5n],
|
||||
[-4n, 32, -4n],
|
||||
[-3n, 32, -3n],
|
||||
[-2n, 32, -2n],
|
||||
[-1n, 32, -1n],
|
||||
[0n, 32, 0n],
|
||||
[1n, 32, 1n],
|
||||
[2n, 32, 2n],
|
||||
[3n, 32, 3n],
|
||||
[4n, 32, 4n],
|
||||
[5n, 32, 5n],
|
||||
[6n, 32, 6n],
|
||||
[7n, 32, 7n],
|
||||
[8n, 32, 8n],
|
||||
[9n, 32, 9n],
|
||||
[0x7ffffffen, 32, 0x7ffffffen],
|
||||
[0x7fffffffn, 32, 0x7fffffffn],
|
||||
[0x80000000n, 32, -0x80000000n],
|
||||
[0x80000001n, 32, -0x7fffffffn],
|
||||
[0xfffffffen, 32, -2n],
|
||||
[0xffffffffn, 32, -1n],
|
||||
[0x100000000n, 32, 0n],
|
||||
[0x100000001n, 32, 1n],
|
||||
[0x7ffffffffffffffen, 32, -2n],
|
||||
[0x7fffffffffffffffn, 32, -1n],
|
||||
[0x8000000000000000n, 32, 0n],
|
||||
[0x8000000000000001n, 32, 1n],
|
||||
[0xfffffffffffffffen, 32, -2n],
|
||||
[0xffffffffffffffffn, 32, -1n],
|
||||
[0x10000000000000000n, 32, 0n],
|
||||
[0x10000000000000001n, 32, 1n],
|
||||
[-0x10000000000000001n, 33, -1n],
|
||||
[-0x10000000000000000n, 33, 0n],
|
||||
[-0xffffffffffffffffn, 33, 1n],
|
||||
[-0xfffffffffffffffen, 33, 2n],
|
||||
[-0x8000000000000001n, 33, -1n],
|
||||
[-0x8000000000000000n, 33, 0n],
|
||||
[-0x7fffffffffffffffn, 33, 1n],
|
||||
[-0x7ffffffffffffffen, 33, 2n],
|
||||
[-0x100000001n, 33, 0xffffffffn],
|
||||
[-0x100000000n, 33, -0x100000000n],
|
||||
[-0xffffffffn, 33, -0xffffffffn],
|
||||
[-0xfffffffen, 33, -0xfffffffen],
|
||||
[-0x80000001n, 33, -0x80000001n],
|
||||
[-0x80000000n, 33, -0x80000000n],
|
||||
[-0x7fffffffn, 33, -0x7fffffffn],
|
||||
[-0x7ffffffen, 33, -0x7ffffffen],
|
||||
[-9n, 33, -9n],
|
||||
[-8n, 33, -8n],
|
||||
[-7n, 33, -7n],
|
||||
[-6n, 33, -6n],
|
||||
[-5n, 33, -5n],
|
||||
[-4n, 33, -4n],
|
||||
[-3n, 33, -3n],
|
||||
[-2n, 33, -2n],
|
||||
[-1n, 33, -1n],
|
||||
[0n, 33, 0n],
|
||||
[1n, 33, 1n],
|
||||
[2n, 33, 2n],
|
||||
[3n, 33, 3n],
|
||||
[4n, 33, 4n],
|
||||
[5n, 33, 5n],
|
||||
[6n, 33, 6n],
|
||||
[7n, 33, 7n],
|
||||
[8n, 33, 8n],
|
||||
[9n, 33, 9n],
|
||||
[0x7ffffffen, 33, 0x7ffffffen],
|
||||
[0x7fffffffn, 33, 0x7fffffffn],
|
||||
[0x80000000n, 33, 0x80000000n],
|
||||
[0x80000001n, 33, 0x80000001n],
|
||||
[0xfffffffen, 33, 0xfffffffen],
|
||||
[0xffffffffn, 33, 0xffffffffn],
|
||||
[0x100000000n, 33, -0x100000000n],
|
||||
[0x100000001n, 33, -0xffffffffn],
|
||||
[0x7ffffffffffffffen, 33, -2n],
|
||||
[0x7fffffffffffffffn, 33, -1n],
|
||||
[0x8000000000000000n, 33, 0n],
|
||||
[0x8000000000000001n, 33, 1n],
|
||||
[0xfffffffffffffffen, 33, -2n],
|
||||
[0xffffffffffffffffn, 33, -1n],
|
||||
[0x10000000000000000n, 33, 0n],
|
||||
[0x10000000000000001n, 33, 1n],
|
||||
[-0x10000000000000001n, 63, -1n],
|
||||
[-0x10000000000000000n, 63, 0n],
|
||||
[-0xffffffffffffffffn, 63, 1n],
|
||||
[-0xfffffffffffffffen, 63, 2n],
|
||||
[-0x8000000000000001n, 63, -1n],
|
||||
[-0x8000000000000000n, 63, 0n],
|
||||
[-0x7fffffffffffffffn, 63, 1n],
|
||||
[-0x7ffffffffffffffen, 63, 2n],
|
||||
[-0x100000001n, 63, -0x100000001n],
|
||||
[-0x100000000n, 63, -0x100000000n],
|
||||
[-0xffffffffn, 63, -0xffffffffn],
|
||||
[-0xfffffffen, 63, -0xfffffffen],
|
||||
[-0x80000001n, 63, -0x80000001n],
|
||||
[-0x80000000n, 63, -0x80000000n],
|
||||
[-0x7fffffffn, 63, -0x7fffffffn],
|
||||
[-0x7ffffffen, 63, -0x7ffffffen],
|
||||
[-9n, 63, -9n],
|
||||
[-8n, 63, -8n],
|
||||
[-7n, 63, -7n],
|
||||
[-6n, 63, -6n],
|
||||
[-5n, 63, -5n],
|
||||
[-4n, 63, -4n],
|
||||
[-3n, 63, -3n],
|
||||
[-2n, 63, -2n],
|
||||
[-1n, 63, -1n],
|
||||
[0n, 63, 0n],
|
||||
[1n, 63, 1n],
|
||||
[2n, 63, 2n],
|
||||
[3n, 63, 3n],
|
||||
[4n, 63, 4n],
|
||||
[5n, 63, 5n],
|
||||
[6n, 63, 6n],
|
||||
[7n, 63, 7n],
|
||||
[8n, 63, 8n],
|
||||
[9n, 63, 9n],
|
||||
[0x7ffffffen, 63, 0x7ffffffen],
|
||||
[0x7fffffffn, 63, 0x7fffffffn],
|
||||
[0x80000000n, 63, 0x80000000n],
|
||||
[0x80000001n, 63, 0x80000001n],
|
||||
[0xfffffffen, 63, 0xfffffffen],
|
||||
[0xffffffffn, 63, 0xffffffffn],
|
||||
[0x100000000n, 63, 0x100000000n],
|
||||
[0x100000001n, 63, 0x100000001n],
|
||||
[0x7ffffffffffffffen, 63, -2n],
|
||||
[0x7fffffffffffffffn, 63, -1n],
|
||||
[0x8000000000000000n, 63, 0n],
|
||||
[0x8000000000000001n, 63, 1n],
|
||||
[0xfffffffffffffffen, 63, -2n],
|
||||
[0xffffffffffffffffn, 63, -1n],
|
||||
[0x10000000000000000n, 63, 0n],
|
||||
[0x10000000000000001n, 63, 1n],
|
||||
[-0x10000000000000001n, 64, -1n],
|
||||
[-0x10000000000000000n, 64, 0n],
|
||||
[-0xffffffffffffffffn, 64, 1n],
|
||||
[-0xfffffffffffffffen, 64, 2n],
|
||||
[-0x8000000000000001n, 64, 0x7fffffffffffffffn],
|
||||
[-0x8000000000000000n, 64, -0x8000000000000000n],
|
||||
[-0x7fffffffffffffffn, 64, -0x7fffffffffffffffn],
|
||||
[-0x7ffffffffffffffen, 64, -0x7ffffffffffffffen],
|
||||
[-0x100000001n, 64, -0x100000001n],
|
||||
[-0x100000000n, 64, -0x100000000n],
|
||||
[-0xffffffffn, 64, -0xffffffffn],
|
||||
[-0xfffffffen, 64, -0xfffffffen],
|
||||
[-0x80000001n, 64, -0x80000001n],
|
||||
[-0x80000000n, 64, -0x80000000n],
|
||||
[-0x7fffffffn, 64, -0x7fffffffn],
|
||||
[-0x7ffffffen, 64, -0x7ffffffen],
|
||||
[-9n, 64, -9n],
|
||||
[-8n, 64, -8n],
|
||||
[-7n, 64, -7n],
|
||||
[-6n, 64, -6n],
|
||||
[-5n, 64, -5n],
|
||||
[-4n, 64, -4n],
|
||||
[-3n, 64, -3n],
|
||||
[-2n, 64, -2n],
|
||||
[-1n, 64, -1n],
|
||||
[0n, 64, 0n],
|
||||
[1n, 64, 1n],
|
||||
[2n, 64, 2n],
|
||||
[3n, 64, 3n],
|
||||
[4n, 64, 4n],
|
||||
[5n, 64, 5n],
|
||||
[6n, 64, 6n],
|
||||
[7n, 64, 7n],
|
||||
[8n, 64, 8n],
|
||||
[9n, 64, 9n],
|
||||
[0x7ffffffen, 64, 0x7ffffffen],
|
||||
[0x7fffffffn, 64, 0x7fffffffn],
|
||||
[0x80000000n, 64, 0x80000000n],
|
||||
[0x80000001n, 64, 0x80000001n],
|
||||
[0xfffffffen, 64, 0xfffffffen],
|
||||
[0xffffffffn, 64, 0xffffffffn],
|
||||
[0x100000000n, 64, 0x100000000n],
|
||||
[0x100000001n, 64, 0x100000001n],
|
||||
[0x7ffffffffffffffen, 64, 0x7ffffffffffffffen],
|
||||
[0x7fffffffffffffffn, 64, 0x7fffffffffffffffn],
|
||||
[0x8000000000000000n, 64, -0x8000000000000000n],
|
||||
[0x8000000000000001n, 64, -0x7fffffffffffffffn],
|
||||
[0xfffffffffffffffen, 64, -2n],
|
||||
[0xffffffffffffffffn, 64, -1n],
|
||||
[0x10000000000000000n, 64, 0n],
|
||||
[0x10000000000000001n, 64, 1n],
|
||||
[-0x10000000000000001n, 65, 0xffffffffffffffffn],
|
||||
[-0x10000000000000000n, 65, -0x10000000000000000n],
|
||||
[-0xffffffffffffffffn, 65, -0xffffffffffffffffn],
|
||||
[-0xfffffffffffffffen, 65, -0xfffffffffffffffen],
|
||||
[-0x8000000000000001n, 65, -0x8000000000000001n],
|
||||
[-0x8000000000000000n, 65, -0x8000000000000000n],
|
||||
[-0x7fffffffffffffffn, 65, -0x7fffffffffffffffn],
|
||||
[-0x7ffffffffffffffen, 65, -0x7ffffffffffffffen],
|
||||
[-0x100000001n, 65, -0x100000001n],
|
||||
[-0x100000000n, 65, -0x100000000n],
|
||||
[-0xffffffffn, 65, -0xffffffffn],
|
||||
[-0xfffffffen, 65, -0xfffffffen],
|
||||
[-0x80000001n, 65, -0x80000001n],
|
||||
[-0x80000000n, 65, -0x80000000n],
|
||||
[-0x7fffffffn, 65, -0x7fffffffn],
|
||||
[-0x7ffffffen, 65, -0x7ffffffen],
|
||||
[-9n, 65, -9n],
|
||||
[-8n, 65, -8n],
|
||||
[-7n, 65, -7n],
|
||||
[-6n, 65, -6n],
|
||||
[-5n, 65, -5n],
|
||||
[-4n, 65, -4n],
|
||||
[-3n, 65, -3n],
|
||||
[-2n, 65, -2n],
|
||||
[-1n, 65, -1n],
|
||||
[0n, 65, 0n],
|
||||
[1n, 65, 1n],
|
||||
[2n, 65, 2n],
|
||||
[3n, 65, 3n],
|
||||
[4n, 65, 4n],
|
||||
[5n, 65, 5n],
|
||||
[6n, 65, 6n],
|
||||
[7n, 65, 7n],
|
||||
[8n, 65, 8n],
|
||||
[9n, 65, 9n],
|
||||
[0x7ffffffen, 65, 0x7ffffffen],
|
||||
[0x7fffffffn, 65, 0x7fffffffn],
|
||||
[0x80000000n, 65, 0x80000000n],
|
||||
[0x80000001n, 65, 0x80000001n],
|
||||
[0xfffffffen, 65, 0xfffffffen],
|
||||
[0xffffffffn, 65, 0xffffffffn],
|
||||
[0x100000000n, 65, 0x100000000n],
|
||||
[0x100000001n, 65, 0x100000001n],
|
||||
[0x7ffffffffffffffen, 65, 0x7ffffffffffffffen],
|
||||
[0x7fffffffffffffffn, 65, 0x7fffffffffffffffn],
|
||||
[0x8000000000000000n, 65, 0x8000000000000000n],
|
||||
[0x8000000000000001n, 65, 0x8000000000000001n],
|
||||
[0xfffffffffffffffen, 65, 0xfffffffffffffffen],
|
||||
[0xffffffffffffffffn, 65, 0xffffffffffffffffn],
|
||||
[0x10000000000000000n, 65, -0x10000000000000000n],
|
||||
[0x10000000000000001n, 65, -0xffffffffffffffffn],
|
||||
];
|
||||
|
||||
function f(tests) {
|
||||
for (let test of tests) {
|
||||
let input = test[0], bits = test[1], expected = test[2];
|
||||
|
||||
assertEq(BigInt.asIntN(bits, input), expected);
|
||||
}
|
||||
}
|
||||
|
||||
for (let i = 0; i < 10; ++i) {
|
||||
f(tests);
|
||||
}
|
|
@ -0,0 +1,65 @@
|
|||
const tests = [
|
||||
[-0x10000000000000001n, -1n],
|
||||
[-0x10000000000000000n, 0n],
|
||||
[-0xffffffffffffffffn, 1n],
|
||||
[-0xfffffffffffffffen, 2n],
|
||||
[-0x8000000000000001n, -1n],
|
||||
[-0x8000000000000000n, 0n],
|
||||
[-0x7fffffffffffffffn, 1n],
|
||||
[-0x7ffffffffffffffen, 2n],
|
||||
[-0x100000001n, -1n],
|
||||
[-0x100000000n, 0n],
|
||||
[-0xffffffffn, 1n],
|
||||
[-0xfffffffen, 2n],
|
||||
[-0x80000001n, 0x7fffffffn],
|
||||
[-0x80000000n, -0x80000000n],
|
||||
[-0x7fffffffn, -0x7fffffffn],
|
||||
[-0x7ffffffen, -0x7ffffffen],
|
||||
[-9n, -9n],
|
||||
[-8n, -8n],
|
||||
[-7n, -7n],
|
||||
[-6n, -6n],
|
||||
[-5n, -5n],
|
||||
[-4n, -4n],
|
||||
[-3n, -3n],
|
||||
[-2n, -2n],
|
||||
[-1n, -1n],
|
||||
[0n, 0n],
|
||||
[1n, 1n],
|
||||
[2n, 2n],
|
||||
[3n, 3n],
|
||||
[4n, 4n],
|
||||
[5n, 5n],
|
||||
[6n, 6n],
|
||||
[7n, 7n],
|
||||
[8n, 8n],
|
||||
[9n, 9n],
|
||||
[0x7ffffffen, 0x7ffffffen],
|
||||
[0x7fffffffn, 0x7fffffffn],
|
||||
[0x80000000n, -0x80000000n],
|
||||
[0x80000001n, -0x7fffffffn],
|
||||
[0xfffffffen, -2n],
|
||||
[0xffffffffn, -1n],
|
||||
[0x100000000n, 0n],
|
||||
[0x100000001n, 1n],
|
||||
[0x7ffffffffffffffen, -2n],
|
||||
[0x7fffffffffffffffn, -1n],
|
||||
[0x8000000000000000n, 0n],
|
||||
[0x8000000000000001n, 1n],
|
||||
[0xfffffffffffffffen, -2n],
|
||||
[0xffffffffffffffffn, -1n],
|
||||
[0x10000000000000000n, 0n],
|
||||
[0x10000000000000001n, 1n],
|
||||
];
|
||||
|
||||
function f(tests) {
|
||||
for (let test of tests) {
|
||||
let input = test[0], expected = test[1];
|
||||
|
||||
assertEq(BigInt.asIntN(32, input), expected);
|
||||
}
|
||||
}
|
||||
|
||||
for (let i = 0; i < 100; ++i) {
|
||||
f(tests);
|
||||
}
|
|
@ -0,0 +1,65 @@
|
|||
const tests = [
|
||||
[-0x10000000000000001n, -1n],
|
||||
[-0x10000000000000000n, 0n],
|
||||
[-0xffffffffffffffffn, 1n],
|
||||
[-0xfffffffffffffffen, 2n],
|
||||
[-0x8000000000000001n, 0x7fffffffffffffffn],
|
||||
[-0x8000000000000000n, -0x8000000000000000n],
|
||||
[-0x7fffffffffffffffn, -0x7fffffffffffffffn],
|
||||
[-0x7ffffffffffffffen, -0x7ffffffffffffffen],
|
||||
[-0x100000001n, -0x100000001n],
|
||||
[-0x100000000n, -0x100000000n],
|
||||
[-0xffffffffn, -0xffffffffn],
|
||||
[-0xfffffffen, -0xfffffffen],
|
||||
[-0x80000001n, -0x80000001n],
|
||||
[-0x80000000n, -0x80000000n],
|
||||
[-0x7fffffffn, -0x7fffffffn],
|
||||
[-0x7ffffffen, -0x7ffffffen],
|
||||
[-9n, -9n],
|
||||
[-8n, -8n],
|
||||
[-7n, -7n],
|
||||
[-6n, -6n],
|
||||
[-5n, -5n],
|
||||
[-4n, -4n],
|
||||
[-3n, -3n],
|
||||
[-2n, -2n],
|
||||
[-1n, -1n],
|
||||
[0n, 0n],
|
||||
[1n, 1n],
|
||||
[2n, 2n],
|
||||
[3n, 3n],
|
||||
[4n, 4n],
|
||||
[5n, 5n],
|
||||
[6n, 6n],
|
||||
[7n, 7n],
|
||||
[8n, 8n],
|
||||
[9n, 9n],
|
||||
[0x7ffffffen, 0x7ffffffen],
|
||||
[0x7fffffffn, 0x7fffffffn],
|
||||
[0x80000000n, 0x80000000n],
|
||||
[0x80000001n, 0x80000001n],
|
||||
[0xfffffffen, 0xfffffffen],
|
||||
[0xffffffffn, 0xffffffffn],
|
||||
[0x100000000n, 0x100000000n],
|
||||
[0x100000001n, 0x100000001n],
|
||||
[0x7ffffffffffffffen, 0x7ffffffffffffffen],
|
||||
[0x7fffffffffffffffn, 0x7fffffffffffffffn],
|
||||
[0x8000000000000000n, -0x8000000000000000n],
|
||||
[0x8000000000000001n, -0x7fffffffffffffffn],
|
||||
[0xfffffffffffffffen, -2n],
|
||||
[0xffffffffffffffffn, -1n],
|
||||
[0x10000000000000000n, 0n],
|
||||
[0x10000000000000001n, 1n],
|
||||
];
|
||||
|
||||
function f(tests) {
|
||||
for (let test of tests) {
|
||||
let input = test[0], expected = test[1];
|
||||
|
||||
assertEq(BigInt.asIntN(64, input), expected);
|
||||
}
|
||||
}
|
||||
|
||||
for (let i = 0; i < 100; ++i) {
|
||||
f(tests);
|
||||
}
|
|
@ -0,0 +1,473 @@
|
|||
const tests = [
|
||||
[-0x10000000000000001n, 0, 0n],
|
||||
[-0x10000000000000000n, 0, 0n],
|
||||
[-0xffffffffffffffffn, 0, 0n],
|
||||
[-0xfffffffffffffffen, 0, 0n],
|
||||
[-0x8000000000000001n, 0, 0n],
|
||||
[-0x8000000000000000n, 0, 0n],
|
||||
[-0x7fffffffffffffffn, 0, 0n],
|
||||
[-0x7ffffffffffffffen, 0, 0n],
|
||||
[-0x100000001n, 0, 0n],
|
||||
[-0x100000000n, 0, 0n],
|
||||
[-0xffffffffn, 0, 0n],
|
||||
[-0xfffffffen, 0, 0n],
|
||||
[-0x80000001n, 0, 0n],
|
||||
[-0x80000000n, 0, 0n],
|
||||
[-0x7fffffffn, 0, 0n],
|
||||
[-0x7ffffffen, 0, 0n],
|
||||
[-9n, 0, 0n],
|
||||
[-8n, 0, 0n],
|
||||
[-7n, 0, 0n],
|
||||
[-6n, 0, 0n],
|
||||
[-5n, 0, 0n],
|
||||
[-4n, 0, 0n],
|
||||
[-3n, 0, 0n],
|
||||
[-2n, 0, 0n],
|
||||
[-1n, 0, 0n],
|
||||
[0n, 0, 0n],
|
||||
[1n, 0, 0n],
|
||||
[2n, 0, 0n],
|
||||
[3n, 0, 0n],
|
||||
[4n, 0, 0n],
|
||||
[5n, 0, 0n],
|
||||
[6n, 0, 0n],
|
||||
[7n, 0, 0n],
|
||||
[8n, 0, 0n],
|
||||
[9n, 0, 0n],
|
||||
[0x7ffffffen, 0, 0n],
|
||||
[0x7fffffffn, 0, 0n],
|
||||
[0x80000000n, 0, 0n],
|
||||
[0x80000001n, 0, 0n],
|
||||
[0xfffffffen, 0, 0n],
|
||||
[0xffffffffn, 0, 0n],
|
||||
[0x100000000n, 0, 0n],
|
||||
[0x100000001n, 0, 0n],
|
||||
[0x7ffffffffffffffen, 0, 0n],
|
||||
[0x7fffffffffffffffn, 0, 0n],
|
||||
[0x8000000000000000n, 0, 0n],
|
||||
[0x8000000000000001n, 0, 0n],
|
||||
[0xfffffffffffffffen, 0, 0n],
|
||||
[0xffffffffffffffffn, 0, 0n],
|
||||
[0x10000000000000000n, 0, 0n],
|
||||
[0x10000000000000001n, 0, 0n],
|
||||
[-0x10000000000000001n, 1, 1n],
|
||||
[-0x10000000000000000n, 1, 0n],
|
||||
[-0xffffffffffffffffn, 1, 1n],
|
||||
[-0xfffffffffffffffen, 1, 0n],
|
||||
[-0x8000000000000001n, 1, 1n],
|
||||
[-0x8000000000000000n, 1, 0n],
|
||||
[-0x7fffffffffffffffn, 1, 1n],
|
||||
[-0x7ffffffffffffffen, 1, 0n],
|
||||
[-0x100000001n, 1, 1n],
|
||||
[-0x100000000n, 1, 0n],
|
||||
[-0xffffffffn, 1, 1n],
|
||||
[-0xfffffffen, 1, 0n],
|
||||
[-0x80000001n, 1, 1n],
|
||||
[-0x80000000n, 1, 0n],
|
||||
[-0x7fffffffn, 1, 1n],
|
||||
[-0x7ffffffen, 1, 0n],
|
||||
[-9n, 1, 1n],
|
||||
[-8n, 1, 0n],
|
||||
[-7n, 1, 1n],
|
||||
[-6n, 1, 0n],
|
||||
[-5n, 1, 1n],
|
||||
[-4n, 1, 0n],
|
||||
[-3n, 1, 1n],
|
||||
[-2n, 1, 0n],
|
||||
[-1n, 1, 1n],
|
||||
[0n, 1, 0n],
|
||||
[1n, 1, 1n],
|
||||
[2n, 1, 0n],
|
||||
[3n, 1, 1n],
|
||||
[4n, 1, 0n],
|
||||
[5n, 1, 1n],
|
||||
[6n, 1, 0n],
|
||||
[7n, 1, 1n],
|
||||
[8n, 1, 0n],
|
||||
[9n, 1, 1n],
|
||||
[0x7ffffffen, 1, 0n],
|
||||
[0x7fffffffn, 1, 1n],
|
||||
[0x80000000n, 1, 0n],
|
||||
[0x80000001n, 1, 1n],
|
||||
[0xfffffffen, 1, 0n],
|
||||
[0xffffffffn, 1, 1n],
|
||||
[0x100000000n, 1, 0n],
|
||||
[0x100000001n, 1, 1n],
|
||||
[0x7ffffffffffffffen, 1, 0n],
|
||||
[0x7fffffffffffffffn, 1, 1n],
|
||||
[0x8000000000000000n, 1, 0n],
|
||||
[0x8000000000000001n, 1, 1n],
|
||||
[0xfffffffffffffffen, 1, 0n],
|
||||
[0xffffffffffffffffn, 1, 1n],
|
||||
[0x10000000000000000n, 1, 0n],
|
||||
[0x10000000000000001n, 1, 1n],
|
||||
[-0x10000000000000001n, 2, 3n],
|
||||
[-0x10000000000000000n, 2, 0n],
|
||||
[-0xffffffffffffffffn, 2, 1n],
|
||||
[-0xfffffffffffffffen, 2, 2n],
|
||||
[-0x8000000000000001n, 2, 3n],
|
||||
[-0x8000000000000000n, 2, 0n],
|
||||
[-0x7fffffffffffffffn, 2, 1n],
|
||||
[-0x7ffffffffffffffen, 2, 2n],
|
||||
[-0x100000001n, 2, 3n],
|
||||
[-0x100000000n, 2, 0n],
|
||||
[-0xffffffffn, 2, 1n],
|
||||
[-0xfffffffen, 2, 2n],
|
||||
[-0x80000001n, 2, 3n],
|
||||
[-0x80000000n, 2, 0n],
|
||||
[-0x7fffffffn, 2, 1n],
|
||||
[-0x7ffffffen, 2, 2n],
|
||||
[-9n, 2, 3n],
|
||||
[-8n, 2, 0n],
|
||||
[-7n, 2, 1n],
|
||||
[-6n, 2, 2n],
|
||||
[-5n, 2, 3n],
|
||||
[-4n, 2, 0n],
|
||||
[-3n, 2, 1n],
|
||||
[-2n, 2, 2n],
|
||||
[-1n, 2, 3n],
|
||||
[0n, 2, 0n],
|
||||
[1n, 2, 1n],
|
||||
[2n, 2, 2n],
|
||||
[3n, 2, 3n],
|
||||
[4n, 2, 0n],
|
||||
[5n, 2, 1n],
|
||||
[6n, 2, 2n],
|
||||
[7n, 2, 3n],
|
||||
[8n, 2, 0n],
|
||||
[9n, 2, 1n],
|
||||
[0x7ffffffen, 2, 2n],
|
||||
[0x7fffffffn, 2, 3n],
|
||||
[0x80000000n, 2, 0n],
|
||||
[0x80000001n, 2, 1n],
|
||||
[0xfffffffen, 2, 2n],
|
||||
[0xffffffffn, 2, 3n],
|
||||
[0x100000000n, 2, 0n],
|
||||
[0x100000001n, 2, 1n],
|
||||
[0x7ffffffffffffffen, 2, 2n],
|
||||
[0x7fffffffffffffffn, 2, 3n],
|
||||
[0x8000000000000000n, 2, 0n],
|
||||
[0x8000000000000001n, 2, 1n],
|
||||
[0xfffffffffffffffen, 2, 2n],
|
||||
[0xffffffffffffffffn, 2, 3n],
|
||||
[0x10000000000000000n, 2, 0n],
|
||||
[0x10000000000000001n, 2, 1n],
|
||||
[-0x10000000000000001n, 31, 0x7fffffffn],
|
||||
[-0x10000000000000000n, 31, 0n],
|
||||
[-0xffffffffffffffffn, 31, 1n],
|
||||
[-0xfffffffffffffffen, 31, 2n],
|
||||
[-0x8000000000000001n, 31, 0x7fffffffn],
|
||||
[-0x8000000000000000n, 31, 0n],
|
||||
[-0x7fffffffffffffffn, 31, 1n],
|
||||
[-0x7ffffffffffffffen, 31, 2n],
|
||||
[-0x100000001n, 31, 0x7fffffffn],
|
||||
[-0x100000000n, 31, 0n],
|
||||
[-0xffffffffn, 31, 1n],
|
||||
[-0xfffffffen, 31, 2n],
|
||||
[-0x80000001n, 31, 0x7fffffffn],
|
||||
[-0x80000000n, 31, 0n],
|
||||
[-0x7fffffffn, 31, 1n],
|
||||
[-0x7ffffffen, 31, 2n],
|
||||
[-9n, 31, 0x7ffffff7n],
|
||||
[-8n, 31, 0x7ffffff8n],
|
||||
[-7n, 31, 0x7ffffff9n],
|
||||
[-6n, 31, 0x7ffffffan],
|
||||
[-5n, 31, 0x7ffffffbn],
|
||||
[-4n, 31, 0x7ffffffcn],
|
||||
[-3n, 31, 0x7ffffffdn],
|
||||
[-2n, 31, 0x7ffffffen],
|
||||
[-1n, 31, 0x7fffffffn],
|
||||
[0n, 31, 0n],
|
||||
[1n, 31, 1n],
|
||||
[2n, 31, 2n],
|
||||
[3n, 31, 3n],
|
||||
[4n, 31, 4n],
|
||||
[5n, 31, 5n],
|
||||
[6n, 31, 6n],
|
||||
[7n, 31, 7n],
|
||||
[8n, 31, 8n],
|
||||
[9n, 31, 9n],
|
||||
[0x7ffffffen, 31, 0x7ffffffen],
|
||||
[0x7fffffffn, 31, 0x7fffffffn],
|
||||
[0x80000000n, 31, 0n],
|
||||
[0x80000001n, 31, 1n],
|
||||
[0xfffffffen, 31, 0x7ffffffen],
|
||||
[0xffffffffn, 31, 0x7fffffffn],
|
||||
[0x100000000n, 31, 0n],
|
||||
[0x100000001n, 31, 1n],
|
||||
[0x7ffffffffffffffen, 31, 0x7ffffffen],
|
||||
[0x7fffffffffffffffn, 31, 0x7fffffffn],
|
||||
[0x8000000000000000n, 31, 0n],
|
||||
[0x8000000000000001n, 31, 1n],
|
||||
[0xfffffffffffffffen, 31, 0x7ffffffen],
|
||||
[0xffffffffffffffffn, 31, 0x7fffffffn],
|
||||
[0x10000000000000000n, 31, 0n],
|
||||
[0x10000000000000001n, 31, 1n],
|
||||
[-0x10000000000000001n, 32, 0xffffffffn],
|
||||
[-0x10000000000000000n, 32, 0n],
|
||||
[-0xffffffffffffffffn, 32, 1n],
|
||||
[-0xfffffffffffffffen, 32, 2n],
|
||||
[-0x8000000000000001n, 32, 0xffffffffn],
|
||||
[-0x8000000000000000n, 32, 0n],
|
||||
[-0x7fffffffffffffffn, 32, 1n],
|
||||
[-0x7ffffffffffffffen, 32, 2n],
|
||||
[-0x100000001n, 32, 0xffffffffn],
|
||||
[-0x100000000n, 32, 0n],
|
||||
[-0xffffffffn, 32, 1n],
|
||||
[-0xfffffffen, 32, 2n],
|
||||
[-0x80000001n, 32, 0x7fffffffn],
|
||||
[-0x80000000n, 32, 0x80000000n],
|
||||
[-0x7fffffffn, 32, 0x80000001n],
|
||||
[-0x7ffffffen, 32, 0x80000002n],
|
||||
[-9n, 32, 0xfffffff7n],
|
||||
[-8n, 32, 0xfffffff8n],
|
||||
[-7n, 32, 0xfffffff9n],
|
||||
[-6n, 32, 0xfffffffan],
|
||||
[-5n, 32, 0xfffffffbn],
|
||||
[-4n, 32, 0xfffffffcn],
|
||||
[-3n, 32, 0xfffffffdn],
|
||||
[-2n, 32, 0xfffffffen],
|
||||
[-1n, 32, 0xffffffffn],
|
||||
[0n, 32, 0n],
|
||||
[1n, 32, 1n],
|
||||
[2n, 32, 2n],
|
||||
[3n, 32, 3n],
|
||||
[4n, 32, 4n],
|
||||
[5n, 32, 5n],
|
||||
[6n, 32, 6n],
|
||||
[7n, 32, 7n],
|
||||
[8n, 32, 8n],
|
||||
[9n, 32, 9n],
|
||||
[0x7ffffffen, 32, 0x7ffffffen],
|
||||
[0x7fffffffn, 32, 0x7fffffffn],
|
||||
[0x80000000n, 32, 0x80000000n],
|
||||
[0x80000001n, 32, 0x80000001n],
|
||||
[0xfffffffen, 32, 0xfffffffen],
|
||||
[0xffffffffn, 32, 0xffffffffn],
|
||||
[0x100000000n, 32, 0n],
|
||||
[0x100000001n, 32, 1n],
|
||||
[0x7ffffffffffffffen, 32, 0xfffffffen],
|
||||
[0x7fffffffffffffffn, 32, 0xffffffffn],
|
||||
[0x8000000000000000n, 32, 0n],
|
||||
[0x8000000000000001n, 32, 1n],
|
||||
[0xfffffffffffffffen, 32, 0xfffffffen],
|
||||
[0xffffffffffffffffn, 32, 0xffffffffn],
|
||||
[0x10000000000000000n, 32, 0n],
|
||||
[0x10000000000000001n, 32, 1n],
|
||||
[-0x10000000000000001n, 33, 0x1ffffffffn],
|
||||
[-0x10000000000000000n, 33, 0n],
|
||||
[-0xffffffffffffffffn, 33, 1n],
|
||||
[-0xfffffffffffffffen, 33, 2n],
|
||||
[-0x8000000000000001n, 33, 0x1ffffffffn],
|
||||
[-0x8000000000000000n, 33, 0n],
|
||||
[-0x7fffffffffffffffn, 33, 1n],
|
||||
[-0x7ffffffffffffffen, 33, 2n],
|
||||
[-0x100000001n, 33, 0xffffffffn],
|
||||
[-0x100000000n, 33, 0x100000000n],
|
||||
[-0xffffffffn, 33, 0x100000001n],
|
||||
[-0xfffffffen, 33, 0x100000002n],
|
||||
[-0x80000001n, 33, 0x17fffffffn],
|
||||
[-0x80000000n, 33, 0x180000000n],
|
||||
[-0x7fffffffn, 33, 0x180000001n],
|
||||
[-0x7ffffffen, 33, 0x180000002n],
|
||||
[-9n, 33, 0x1fffffff7n],
|
||||
[-8n, 33, 0x1fffffff8n],
|
||||
[-7n, 33, 0x1fffffff9n],
|
||||
[-6n, 33, 0x1fffffffan],
|
||||
[-5n, 33, 0x1fffffffbn],
|
||||
[-4n, 33, 0x1fffffffcn],
|
||||
[-3n, 33, 0x1fffffffdn],
|
||||
[-2n, 33, 0x1fffffffen],
|
||||
[-1n, 33, 0x1ffffffffn],
|
||||
[0n, 33, 0n],
|
||||
[1n, 33, 1n],
|
||||
[2n, 33, 2n],
|
||||
[3n, 33, 3n],
|
||||
[4n, 33, 4n],
|
||||
[5n, 33, 5n],
|
||||
[6n, 33, 6n],
|
||||
[7n, 33, 7n],
|
||||
[8n, 33, 8n],
|
||||
[9n, 33, 9n],
|
||||
[0x7ffffffen, 33, 0x7ffffffen],
|
||||
[0x7fffffffn, 33, 0x7fffffffn],
|
||||
[0x80000000n, 33, 0x80000000n],
|
||||
[0x80000001n, 33, 0x80000001n],
|
||||
[0xfffffffen, 33, 0xfffffffen],
|
||||
[0xffffffffn, 33, 0xffffffffn],
|
||||
[0x100000000n, 33, 0x100000000n],
|
||||
[0x100000001n, 33, 0x100000001n],
|
||||
[0x7ffffffffffffffen, 33, 0x1fffffffen],
|
||||
[0x7fffffffffffffffn, 33, 0x1ffffffffn],
|
||||
[0x8000000000000000n, 33, 0n],
|
||||
[0x8000000000000001n, 33, 1n],
|
||||
[0xfffffffffffffffen, 33, 0x1fffffffen],
|
||||
[0xffffffffffffffffn, 33, 0x1ffffffffn],
|
||||
[0x10000000000000000n, 33, 0n],
|
||||
[0x10000000000000001n, 33, 1n],
|
||||
[-0x10000000000000001n, 63, 0x7fffffffffffffffn],
|
||||
[-0x10000000000000000n, 63, 0n],
|
||||
[-0xffffffffffffffffn, 63, 1n],
|
||||
[-0xfffffffffffffffen, 63, 2n],
|
||||
[-0x8000000000000001n, 63, 0x7fffffffffffffffn],
|
||||
[-0x8000000000000000n, 63, 0n],
|
||||
[-0x7fffffffffffffffn, 63, 1n],
|
||||
[-0x7ffffffffffffffen, 63, 2n],
|
||||
[-0x100000001n, 63, 0x7ffffffeffffffffn],
|
||||
[-0x100000000n, 63, 0x7fffffff00000000n],
|
||||
[-0xffffffffn, 63, 0x7fffffff00000001n],
|
||||
[-0xfffffffen, 63, 0x7fffffff00000002n],
|
||||
[-0x80000001n, 63, 0x7fffffff7fffffffn],
|
||||
[-0x80000000n, 63, 0x7fffffff80000000n],
|
||||
[-0x7fffffffn, 63, 0x7fffffff80000001n],
|
||||
[-0x7ffffffen, 63, 0x7fffffff80000002n],
|
||||
[-9n, 63, 0x7ffffffffffffff7n],
|
||||
[-8n, 63, 0x7ffffffffffffff8n],
|
||||
[-7n, 63, 0x7ffffffffffffff9n],
|
||||
[-6n, 63, 0x7ffffffffffffffan],
|
||||
[-5n, 63, 0x7ffffffffffffffbn],
|
||||
[-4n, 63, 0x7ffffffffffffffcn],
|
||||
[-3n, 63, 0x7ffffffffffffffdn],
|
||||
[-2n, 63, 0x7ffffffffffffffen],
|
||||
[-1n, 63, 0x7fffffffffffffffn],
|
||||
[0n, 63, 0n],
|
||||
[1n, 63, 1n],
|
||||
[2n, 63, 2n],
|
||||
[3n, 63, 3n],
|
||||
[4n, 63, 4n],
|
||||
[5n, 63, 5n],
|
||||
[6n, 63, 6n],
|
||||
[7n, 63, 7n],
|
||||
[8n, 63, 8n],
|
||||
[9n, 63, 9n],
|
||||
[0x7ffffffen, 63, 0x7ffffffen],
|
||||
[0x7fffffffn, 63, 0x7fffffffn],
|
||||
[0x80000000n, 63, 0x80000000n],
|
||||
[0x80000001n, 63, 0x80000001n],
|
||||
[0xfffffffen, 63, 0xfffffffen],
|
||||
[0xffffffffn, 63, 0xffffffffn],
|
||||
[0x100000000n, 63, 0x100000000n],
|
||||
[0x100000001n, 63, 0x100000001n],
|
||||
[0x7ffffffffffffffen, 63, 0x7ffffffffffffffen],
|
||||
[0x7fffffffffffffffn, 63, 0x7fffffffffffffffn],
|
||||
[0x8000000000000000n, 63, 0n],
|
||||
[0x8000000000000001n, 63, 1n],
|
||||
[0xfffffffffffffffen, 63, 0x7ffffffffffffffen],
|
||||
[0xffffffffffffffffn, 63, 0x7fffffffffffffffn],
|
||||
[0x10000000000000000n, 63, 0n],
|
||||
[0x10000000000000001n, 63, 1n],
|
||||
[-0x10000000000000001n, 64, 0xffffffffffffffffn],
|
||||
[-0x10000000000000000n, 64, 0n],
|
||||
[-0xffffffffffffffffn, 64, 1n],
|
||||
[-0xfffffffffffffffen, 64, 2n],
|
||||
[-0x8000000000000001n, 64, 0x7fffffffffffffffn],
|
||||
[-0x8000000000000000n, 64, 0x8000000000000000n],
|
||||
[-0x7fffffffffffffffn, 64, 0x8000000000000001n],
|
||||
[-0x7ffffffffffffffen, 64, 0x8000000000000002n],
|
||||
[-0x100000001n, 64, 0xfffffffeffffffffn],
|
||||
[-0x100000000n, 64, 0xffffffff00000000n],
|
||||
[-0xffffffffn, 64, 0xffffffff00000001n],
|
||||
[-0xfffffffen, 64, 0xffffffff00000002n],
|
||||
[-0x80000001n, 64, 0xffffffff7fffffffn],
|
||||
[-0x80000000n, 64, 0xffffffff80000000n],
|
||||
[-0x7fffffffn, 64, 0xffffffff80000001n],
|
||||
[-0x7ffffffen, 64, 0xffffffff80000002n],
|
||||
[-9n, 64, 0xfffffffffffffff7n],
|
||||
[-8n, 64, 0xfffffffffffffff8n],
|
||||
[-7n, 64, 0xfffffffffffffff9n],
|
||||
[-6n, 64, 0xfffffffffffffffan],
|
||||
[-5n, 64, 0xfffffffffffffffbn],
|
||||
[-4n, 64, 0xfffffffffffffffcn],
|
||||
[-3n, 64, 0xfffffffffffffffdn],
|
||||
[-2n, 64, 0xfffffffffffffffen],
|
||||
[-1n, 64, 0xffffffffffffffffn],
|
||||
[0n, 64, 0n],
|
||||
[1n, 64, 1n],
|
||||
[2n, 64, 2n],
|
||||
[3n, 64, 3n],
|
||||
[4n, 64, 4n],
|
||||
[5n, 64, 5n],
|
||||
[6n, 64, 6n],
|
||||
[7n, 64, 7n],
|
||||
[8n, 64, 8n],
|
||||
[9n, 64, 9n],
|
||||
[0x7ffffffen, 64, 0x7ffffffen],
|
||||
[0x7fffffffn, 64, 0x7fffffffn],
|
||||
[0x80000000n, 64, 0x80000000n],
|
||||
[0x80000001n, 64, 0x80000001n],
|
||||
[0xfffffffen, 64, 0xfffffffen],
|
||||
[0xffffffffn, 64, 0xffffffffn],
|
||||
[0x100000000n, 64, 0x100000000n],
|
||||
[0x100000001n, 64, 0x100000001n],
|
||||
[0x7ffffffffffffffen, 64, 0x7ffffffffffffffen],
|
||||
[0x7fffffffffffffffn, 64, 0x7fffffffffffffffn],
|
||||
[0x8000000000000000n, 64, 0x8000000000000000n],
|
||||
[0x8000000000000001n, 64, 0x8000000000000001n],
|
||||
[0xfffffffffffffffen, 64, 0xfffffffffffffffen],
|
||||
[0xffffffffffffffffn, 64, 0xffffffffffffffffn],
|
||||
[0x10000000000000000n, 64, 0n],
|
||||
[0x10000000000000001n, 64, 1n],
|
||||
[-0x10000000000000001n, 65, 0xffffffffffffffffn],
|
||||
[-0x10000000000000000n, 65, 0x10000000000000000n],
|
||||
[-0xffffffffffffffffn, 65, 0x10000000000000001n],
|
||||
[-0xfffffffffffffffen, 65, 0x10000000000000002n],
|
||||
[-0x8000000000000001n, 65, 0x17fffffffffffffffn],
|
||||
[-0x8000000000000000n, 65, 0x18000000000000000n],
|
||||
[-0x7fffffffffffffffn, 65, 0x18000000000000001n],
|
||||
[-0x7ffffffffffffffen, 65, 0x18000000000000002n],
|
||||
[-0x100000001n, 65, 0x1fffffffeffffffffn],
|
||||
[-0x100000000n, 65, 0x1ffffffff00000000n],
|
||||
[-0xffffffffn, 65, 0x1ffffffff00000001n],
|
||||
[-0xfffffffen, 65, 0x1ffffffff00000002n],
|
||||
[-0x80000001n, 65, 0x1ffffffff7fffffffn],
|
||||
[-0x80000000n, 65, 0x1ffffffff80000000n],
|
||||
[-0x7fffffffn, 65, 0x1ffffffff80000001n],
|
||||
[-0x7ffffffen, 65, 0x1ffffffff80000002n],
|
||||
[-9n, 65, 0x1fffffffffffffff7n],
|
||||
[-8n, 65, 0x1fffffffffffffff8n],
|
||||
[-7n, 65, 0x1fffffffffffffff9n],
|
||||
[-6n, 65, 0x1fffffffffffffffan],
|
||||
[-5n, 65, 0x1fffffffffffffffbn],
|
||||
[-4n, 65, 0x1fffffffffffffffcn],
|
||||
[-3n, 65, 0x1fffffffffffffffdn],
|
||||
[-2n, 65, 0x1fffffffffffffffen],
|
||||
[-1n, 65, 0x1ffffffffffffffffn],
|
||||
[0n, 65, 0n],
|
||||
[1n, 65, 1n],
|
||||
[2n, 65, 2n],
|
||||
[3n, 65, 3n],
|
||||
[4n, 65, 4n],
|
||||
[5n, 65, 5n],
|
||||
[6n, 65, 6n],
|
||||
[7n, 65, 7n],
|
||||
[8n, 65, 8n],
|
||||
[9n, 65, 9n],
|
||||
[0x7ffffffen, 65, 0x7ffffffen],
|
||||
[0x7fffffffn, 65, 0x7fffffffn],
|
||||
[0x80000000n, 65, 0x80000000n],
|
||||
[0x80000001n, 65, 0x80000001n],
|
||||
[0xfffffffen, 65, 0xfffffffen],
|
||||
[0xffffffffn, 65, 0xffffffffn],
|
||||
[0x100000000n, 65, 0x100000000n],
|
||||
[0x100000001n, 65, 0x100000001n],
|
||||
[0x7ffffffffffffffen, 65, 0x7ffffffffffffffen],
|
||||
[0x7fffffffffffffffn, 65, 0x7fffffffffffffffn],
|
||||
[0x8000000000000000n, 65, 0x8000000000000000n],
|
||||
[0x8000000000000001n, 65, 0x8000000000000001n],
|
||||
[0xfffffffffffffffen, 65, 0xfffffffffffffffen],
|
||||
[0xffffffffffffffffn, 65, 0xffffffffffffffffn],
|
||||
[0x10000000000000000n, 65, 0x10000000000000000n],
|
||||
[0x10000000000000001n, 65, 0x10000000000000001n],
|
||||
];
|
||||
|
||||
function f(tests) {
|
||||
for (let test of tests) {
|
||||
let input = test[0], bits = test[1], expected = test[2];
|
||||
|
||||
assertEq(BigInt.asUintN(bits, input), expected);
|
||||
}
|
||||
}
|
||||
|
||||
for (let i = 0; i < 10; ++i) {
|
||||
f(tests);
|
||||
}
|
|
@ -0,0 +1,65 @@
|
|||
const tests = [
|
||||
[-0x10000000000000001n, 0xffffffffn],
|
||||
[-0x10000000000000000n, 0n],
|
||||
[-0xffffffffffffffffn, 1n],
|
||||
[-0xfffffffffffffffen, 2n],
|
||||
[-0x8000000000000001n, 0xffffffffn],
|
||||
[-0x8000000000000000n, 0n],
|
||||
[-0x7fffffffffffffffn, 1n],
|
||||
[-0x7ffffffffffffffen, 2n],
|
||||
[-0x100000001n, 0xffffffffn],
|
||||
[-0x100000000n, 0n],
|
||||
[-0xffffffffn, 1n],
|
||||
[-0xfffffffen, 2n],
|
||||
[-0x80000001n, 0x7fffffffn],
|
||||
[-0x80000000n, 0x80000000n],
|
||||
[-0x7fffffffn, 0x80000001n],
|
||||
[-0x7ffffffen, 0x80000002n],
|
||||
[-9n, 0xfffffff7n],
|
||||
[-8n, 0xfffffff8n],
|
||||
[-7n, 0xfffffff9n],
|
||||
[-6n, 0xfffffffan],
|
||||
[-5n, 0xfffffffbn],
|
||||
[-4n, 0xfffffffcn],
|
||||
[-3n, 0xfffffffdn],
|
||||
[-2n, 0xfffffffen],
|
||||
[-1n, 0xffffffffn],
|
||||
[0n, 0n],
|
||||
[1n, 1n],
|
||||
[2n, 2n],
|
||||
[3n, 3n],
|
||||
[4n, 4n],
|
||||
[5n, 5n],
|
||||
[6n, 6n],
|
||||
[7n, 7n],
|
||||
[8n, 8n],
|
||||
[9n, 9n],
|
||||
[0x7ffffffen, 0x7ffffffen],
|
||||
[0x7fffffffn, 0x7fffffffn],
|
||||
[0x80000000n, 0x80000000n],
|
||||
[0x80000001n, 0x80000001n],
|
||||
[0xfffffffen, 0xfffffffen],
|
||||
[0xffffffffn, 0xffffffffn],
|
||||
[0x100000000n, 0n],
|
||||
[0x100000001n, 1n],
|
||||
[0x7ffffffffffffffen, 0xfffffffen],
|
||||
[0x7fffffffffffffffn, 0xffffffffn],
|
||||
[0x8000000000000000n, 0n],
|
||||
[0x8000000000000001n, 1n],
|
||||
[0xfffffffffffffffen, 0xfffffffen],
|
||||
[0xffffffffffffffffn, 0xffffffffn],
|
||||
[0x10000000000000000n, 0n],
|
||||
[0x10000000000000001n, 1n],
|
||||
];
|
||||
|
||||
function f(tests) {
|
||||
for (let test of tests) {
|
||||
let input = test[0], expected = test[1];
|
||||
|
||||
assertEq(BigInt.asUintN(32, input), expected);
|
||||
}
|
||||
}
|
||||
|
||||
for (let i = 0; i < 100; ++i) {
|
||||
f(tests);
|
||||
}
|
|
@ -0,0 +1,65 @@
|
|||
const tests = [
|
||||
[-0x10000000000000001n, 0xffffffffffffffffn],
|
||||
[-0x10000000000000000n, 0n],
|
||||
[-0xffffffffffffffffn, 1n],
|
||||
[-0xfffffffffffffffen, 2n],
|
||||
[-0x8000000000000001n, 0x7fffffffffffffffn],
|
||||
[-0x8000000000000000n, 0x8000000000000000n],
|
||||
[-0x7fffffffffffffffn, 0x8000000000000001n],
|
||||
[-0x7ffffffffffffffen, 0x8000000000000002n],
|
||||
[-0x100000001n, 0xfffffffeffffffffn],
|
||||
[-0x100000000n, 0xffffffff00000000n],
|
||||
[-0xffffffffn, 0xffffffff00000001n],
|
||||
[-0xfffffffen, 0xffffffff00000002n],
|
||||
[-0x80000001n, 0xffffffff7fffffffn],
|
||||
[-0x80000000n, 0xffffffff80000000n],
|
||||
[-0x7fffffffn, 0xffffffff80000001n],
|
||||
[-0x7ffffffen, 0xffffffff80000002n],
|
||||
[-9n, 0xfffffffffffffff7n],
|
||||
[-8n, 0xfffffffffffffff8n],
|
||||
[-7n, 0xfffffffffffffff9n],
|
||||
[-6n, 0xfffffffffffffffan],
|
||||
[-5n, 0xfffffffffffffffbn],
|
||||
[-4n, 0xfffffffffffffffcn],
|
||||
[-3n, 0xfffffffffffffffdn],
|
||||
[-2n, 0xfffffffffffffffen],
|
||||
[-1n, 0xffffffffffffffffn],
|
||||
[0n, 0n],
|
||||
[1n, 1n],
|
||||
[2n, 2n],
|
||||
[3n, 3n],
|
||||
[4n, 4n],
|
||||
[5n, 5n],
|
||||
[6n, 6n],
|
||||
[7n, 7n],
|
||||
[8n, 8n],
|
||||
[9n, 9n],
|
||||
[0x7ffffffen, 0x7ffffffen],
|
||||
[0x7fffffffn, 0x7fffffffn],
|
||||
[0x80000000n, 0x80000000n],
|
||||
[0x80000001n, 0x80000001n],
|
||||
[0xfffffffen, 0xfffffffen],
|
||||
[0xffffffffn, 0xffffffffn],
|
||||
[0x100000000n, 0x100000000n],
|
||||
[0x100000001n, 0x100000001n],
|
||||
[0x7ffffffffffffffen, 0x7ffffffffffffffen],
|
||||
[0x7fffffffffffffffn, 0x7fffffffffffffffn],
|
||||
[0x8000000000000000n, 0x8000000000000000n],
|
||||
[0x8000000000000001n, 0x8000000000000001n],
|
||||
[0xfffffffffffffffen, 0xfffffffffffffffen],
|
||||
[0xffffffffffffffffn, 0xffffffffffffffffn],
|
||||
[0x10000000000000000n, 0n],
|
||||
[0x10000000000000001n, 1n],
|
||||
];
|
||||
|
||||
function f(tests) {
|
||||
for (let test of tests) {
|
||||
let input = test[0], expected = test[1];
|
||||
|
||||
assertEq(BigInt.asUintN(64, input), expected);
|
||||
}
|
||||
}
|
||||
|
||||
for (let i = 0; i < 100; ++i) {
|
||||
f(tests);
|
||||
}
|
|
@ -1544,6 +1544,24 @@ function rbigintrsh(i) {
|
|||
return i;
|
||||
}
|
||||
|
||||
let uceFault_bigintasint = eval(`(${uceFault})`.replace('uceFault', 'uceFault_bigintasint'));
|
||||
function rbigintasint(i) {
|
||||
var x = BigInt.asIntN(6, i);
|
||||
if (uceFault_bigintasint(i) || uceFault_bigintasint(i))
|
||||
assertEq(x, -29n);
|
||||
assertRecoveredOnBailout(x, true);
|
||||
return i;
|
||||
}
|
||||
|
||||
let uceFault_bigintasuint = eval(`(${uceFault})`.replace('uceFault', 'uceFault_bigintasuint'));
|
||||
function rbigintasuint(i) {
|
||||
var x = BigInt.asUintN(6, i);
|
||||
if (uceFault_bigintasuint(i) || uceFault_bigintasuint(i))
|
||||
assertEq(x, 35n);
|
||||
assertRecoveredOnBailout(x, true);
|
||||
return i;
|
||||
}
|
||||
|
||||
for (j = 100 - max; j < 100; j++) {
|
||||
with({}){} // Do not Ion-compile this loop.
|
||||
let i = j < 2 ? (Math.abs(j) % 50) + 2 : j;
|
||||
|
@ -1697,6 +1715,8 @@ for (j = 100 - max; j < 100; j++) {
|
|||
rbigintbitnot(BigInt(i));
|
||||
rbigintlsh(BigInt(i));
|
||||
rbigintrsh(BigInt(i));
|
||||
rbigintasint(BigInt(i));
|
||||
rbigintasuint(BigInt(i));
|
||||
}
|
||||
|
||||
// Test that we can refer multiple time to the same recover instruction, as well
|
||||
|
|
|
@ -118,6 +118,19 @@ function bigIntRshBail(i) {
|
|||
if (i >= 99) bailout();
|
||||
}
|
||||
|
||||
function bigIntAsUintBail(i) {
|
||||
var x = [0, maxBitLength + 1][0 + (i >= 99)];
|
||||
|
||||
var a = BigInt.asUintN(x, -1n);
|
||||
|
||||
// Add a function call to capture a resumepoint at the end of the call or
|
||||
// inside the inlined block, such as the bailout does not rewind to the
|
||||
// beginning of the function.
|
||||
resumeHere();
|
||||
|
||||
if (i >= 99) bailout();
|
||||
}
|
||||
|
||||
// Prevent compilation of the top-level
|
||||
eval(`(${resumeHere})`);
|
||||
|
||||
|
@ -196,3 +209,12 @@ try {
|
|||
} catch (e) {
|
||||
assertEq(e instanceof RangeError || e === "out of memory", true, String(e));
|
||||
}
|
||||
|
||||
try {
|
||||
for (let i = 0; i < 100; i++) {
|
||||
bigIntAsUintBail(i);
|
||||
}
|
||||
throw new Error("missing exception");
|
||||
} catch (e) {
|
||||
assertEq(e instanceof RangeError || e === "out of memory", true, String(e));
|
||||
}
|
||||
|
|
|
@ -0,0 +1,11 @@
|
|||
function f(x, y) {
|
||||
x >> (y >>> 0)
|
||||
}
|
||||
|
||||
with ({}) {}
|
||||
|
||||
f(-1, -1)
|
||||
f(1.5, 0)
|
||||
for (var i = 0; i < 100; i++) {
|
||||
f(0, 0);
|
||||
}
|
|
@ -2112,7 +2112,8 @@ bool jit::FinishBailoutToBaseline(BaselineBailoutInfo* bailoutInfoArg) {
|
|||
IonScript* ionScript = outerScript->ionScript();
|
||||
switch (action) {
|
||||
case BailoutAction::InvalidateImmediately:
|
||||
MOZ_CRASH("The IonScript should already have been invalidated.");
|
||||
// The IonScript should already have been invalidated.
|
||||
MOZ_ASSERT(false);
|
||||
break;
|
||||
case BailoutAction::InvalidateIfFrequent:
|
||||
ionScript->incNumFixableBailouts();
|
||||
|
|
|
@ -2266,7 +2266,7 @@ AttachDecision GetPropIRGenerator::tryAttachSparseElement(
|
|||
writer.guardIndexGreaterThanDenseInitLength(objId, indexId);
|
||||
|
||||
// Ensures we are able to efficiently able to map to an integral jsid.
|
||||
writer.guardIndexIsNonNegative(indexId);
|
||||
writer.guardInt32IsNonNegative(indexId);
|
||||
|
||||
// Shape guard the prototype chain to avoid shadowing indexes from appearing.
|
||||
// The helper function also ensures that the index does not appear within the
|
||||
|
@ -3906,7 +3906,7 @@ AttachDecision SetPropIRGenerator::tryAttachAddOrUpdateSparseElement(
|
|||
writer.guardIsExtensible(objId);
|
||||
|
||||
// Ensures we are able to efficiently able to map to an integral jsid.
|
||||
writer.guardIndexIsNonNegative(indexId);
|
||||
writer.guardInt32IsNonNegative(indexId);
|
||||
|
||||
// Shape guard the prototype chain to avoid shadowing indexes from appearing.
|
||||
// Guard the prototype of the receiver explicitly, because the receiver's
|
||||
|
@ -7462,6 +7462,74 @@ AttachDecision CallIRGenerator::tryAttachObjectIsPrototypeOf(
|
|||
return AttachDecision::Attach;
|
||||
}
|
||||
|
||||
AttachDecision CallIRGenerator::tryAttachBigIntAsIntN(HandleFunction callee) {
|
||||
// Need two arguments (Int32, BigInt).
|
||||
if (argc_ != 2 || !args_[0].isInt32() || !args_[1].isBigInt()) {
|
||||
return AttachDecision::NoAction;
|
||||
}
|
||||
|
||||
// Negative bits throws an error.
|
||||
if (args_[0].toInt32() < 0) {
|
||||
return AttachDecision::NoAction;
|
||||
}
|
||||
|
||||
// Initialize the input operand.
|
||||
Int32OperandId argcId(writer.setInputOperandId(0));
|
||||
|
||||
// Guard callee is the 'BigInt.asIntN' native function.
|
||||
emitNativeCalleeGuard(callee);
|
||||
|
||||
// Convert bits to int32.
|
||||
ValOperandId bitsId = writer.loadArgumentFixedSlot(ArgumentKind::Arg0, argc_);
|
||||
Int32OperandId int32BitsId = writer.guardToInt32Index(bitsId);
|
||||
|
||||
// Number of bits mustn't be negative.
|
||||
writer.guardInt32IsNonNegative(int32BitsId);
|
||||
|
||||
ValOperandId arg1Id = writer.loadArgumentFixedSlot(ArgumentKind::Arg1, argc_);
|
||||
BigIntOperandId bigIntId = writer.guardToBigInt(arg1Id);
|
||||
|
||||
writer.bigIntAsIntNResult(int32BitsId, bigIntId);
|
||||
writer.returnFromIC();
|
||||
|
||||
trackAttached("BigIntAsIntN");
|
||||
return AttachDecision::Attach;
|
||||
}
|
||||
|
||||
AttachDecision CallIRGenerator::tryAttachBigIntAsUintN(HandleFunction callee) {
|
||||
// Need two arguments (Int32, BigInt).
|
||||
if (argc_ != 2 || !args_[0].isInt32() || !args_[1].isBigInt()) {
|
||||
return AttachDecision::NoAction;
|
||||
}
|
||||
|
||||
// Negative bits throws an error.
|
||||
if (args_[0].toInt32() < 0) {
|
||||
return AttachDecision::NoAction;
|
||||
}
|
||||
|
||||
// Initialize the input operand.
|
||||
Int32OperandId argcId(writer.setInputOperandId(0));
|
||||
|
||||
// Guard callee is the 'BigInt.asUintN' native function.
|
||||
emitNativeCalleeGuard(callee);
|
||||
|
||||
// Convert bits to int32.
|
||||
ValOperandId bitsId = writer.loadArgumentFixedSlot(ArgumentKind::Arg0, argc_);
|
||||
Int32OperandId int32BitsId = writer.guardToInt32Index(bitsId);
|
||||
|
||||
// Number of bits mustn't be negative.
|
||||
writer.guardInt32IsNonNegative(int32BitsId);
|
||||
|
||||
ValOperandId arg1Id = writer.loadArgumentFixedSlot(ArgumentKind::Arg1, argc_);
|
||||
BigIntOperandId bigIntId = writer.guardToBigInt(arg1Id);
|
||||
|
||||
writer.bigIntAsUintNResult(int32BitsId, bigIntId);
|
||||
writer.returnFromIC();
|
||||
|
||||
trackAttached("BigIntAsUintN");
|
||||
return AttachDecision::Attach;
|
||||
}
|
||||
|
||||
AttachDecision CallIRGenerator::tryAttachFunCall(HandleFunction callee) {
|
||||
if (!callee->isNativeWithoutJitEntry() || callee->native() != fun_call) {
|
||||
return AttachDecision::NoAction;
|
||||
|
@ -8647,6 +8715,12 @@ AttachDecision CallIRGenerator::tryAttachInlinableNative(
|
|||
case InlinableNative::AtomicsIsLockFree:
|
||||
return tryAttachAtomicsIsLockFree(callee);
|
||||
|
||||
// BigInt natives.
|
||||
case InlinableNative::BigIntAsIntN:
|
||||
return tryAttachBigIntAsIntN(callee);
|
||||
case InlinableNative::BigIntAsUintN:
|
||||
return tryAttachBigIntAsUintN(callee);
|
||||
|
||||
// Boolean natives.
|
||||
case InlinableNative::Boolean:
|
||||
return tryAttachBoolean(callee);
|
||||
|
|
|
@ -1731,6 +1731,8 @@ class MOZ_RAII CallIRGenerator : public IRGenerator {
|
|||
AttachDecision tryAttachAssertRecoveredOnBailout(HandleFunction callee);
|
||||
AttachDecision tryAttachObjectIs(HandleFunction callee);
|
||||
AttachDecision tryAttachObjectIsPrototypeOf(HandleFunction callee);
|
||||
AttachDecision tryAttachBigIntAsIntN(HandleFunction callee);
|
||||
AttachDecision tryAttachBigIntAsUintN(HandleFunction callee);
|
||||
|
||||
AttachDecision tryAttachFunCall(HandleFunction calleeFunc);
|
||||
AttachDecision tryAttachFunApply(HandleFunction calleeFunc);
|
||||
|
|
|
@ -2828,23 +2828,14 @@ bool CacheIRCompiler::emitInt32URightShiftResult(Int32OperandId lhsId,
|
|||
|
||||
masm.mov(lhs, scratch);
|
||||
masm.flexibleRshift32(rhs, scratch);
|
||||
Label intDone, floatDone;
|
||||
if (allowDouble) {
|
||||
Label toUint;
|
||||
masm.branchTest32(Assembler::Signed, scratch, scratch, &toUint);
|
||||
masm.jump(&intDone);
|
||||
|
||||
masm.bind(&toUint);
|
||||
ScratchDoubleScope fpscratch(masm);
|
||||
masm.convertUInt32ToDouble(scratch, fpscratch);
|
||||
masm.boxDouble(fpscratch, output.valueReg(), fpscratch);
|
||||
masm.jump(&floatDone);
|
||||
} else {
|
||||
masm.branchTest32(Assembler::Signed, scratch, scratch, failure->label());
|
||||
masm.tagValue(JSVAL_TYPE_INT32, scratch, output.valueReg());
|
||||
}
|
||||
masm.bind(&intDone);
|
||||
masm.tagValue(JSVAL_TYPE_INT32, scratch, output.valueReg());
|
||||
masm.bind(&floatDone);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -3350,7 +3341,7 @@ bool CacheIRCompiler::emitLoadDenseElementResult(ObjOperandId objId,
|
|||
return true;
|
||||
}
|
||||
|
||||
bool CacheIRCompiler::emitGuardIndexIsNonNegative(Int32OperandId indexId) {
|
||||
bool CacheIRCompiler::emitGuardInt32IsNonNegative(Int32OperandId indexId) {
|
||||
JitSpew(JitSpew_Codegen, "%s", __FUNCTION__);
|
||||
Register index = allocator.useRegister(masm, indexId);
|
||||
|
||||
|
@ -7684,6 +7675,42 @@ bool CacheIRCompiler::emitAtomicsIsLockFreeResult(Int32OperandId valueId) {
|
|||
return true;
|
||||
}
|
||||
|
||||
bool CacheIRCompiler::emitBigIntAsIntNResult(Int32OperandId bitsId,
|
||||
BigIntOperandId bigIntId) {
|
||||
JitSpew(JitSpew_Codegen, "%s", __FUNCTION__);
|
||||
|
||||
AutoCallVM callvm(masm, this, allocator);
|
||||
|
||||
Register bits = allocator.useRegister(masm, bitsId);
|
||||
Register bigInt = allocator.useRegister(masm, bigIntId);
|
||||
|
||||
callvm.prepare();
|
||||
masm.Push(bits);
|
||||
masm.Push(bigInt);
|
||||
|
||||
using Fn = BigInt* (*)(JSContext*, HandleBigInt, int32_t);
|
||||
callvm.call<Fn, jit::BigIntAsIntN>();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CacheIRCompiler::emitBigIntAsUintNResult(Int32OperandId bitsId,
|
||||
BigIntOperandId bigIntId) {
|
||||
JitSpew(JitSpew_Codegen, "%s", __FUNCTION__);
|
||||
|
||||
AutoCallVM callvm(masm, this, allocator);
|
||||
|
||||
Register bits = allocator.useRegister(masm, bitsId);
|
||||
Register bigInt = allocator.useRegister(masm, bigIntId);
|
||||
|
||||
callvm.prepare();
|
||||
masm.Push(bits);
|
||||
masm.Push(bigInt);
|
||||
|
||||
using Fn = BigInt* (*)(JSContext*, HandleBigInt, int32_t);
|
||||
callvm.call<Fn, jit::BigIntAsUintN>();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CacheIRCompiler::emitBailout() {
|
||||
JitSpew(JitSpew_Codegen, "%s", __FUNCTION__);
|
||||
|
||||
|
|
|
@ -529,7 +529,7 @@
|
|||
obj: ObjId
|
||||
shape: ShapeField
|
||||
|
||||
- name: GuardIndexIsNonNegative
|
||||
- name: GuardInt32IsNonNegative
|
||||
shared: true
|
||||
transpile: true
|
||||
cost_estimate: 1
|
||||
|
@ -2512,6 +2512,22 @@
|
|||
args:
|
||||
val: Int32Id
|
||||
|
||||
- name: BigIntAsIntNResult
|
||||
shared: true
|
||||
transpile: true
|
||||
cost_estimate: 5
|
||||
args:
|
||||
bits: Int32Id
|
||||
bigInt: BigIntId
|
||||
|
||||
- name: BigIntAsUintNResult
|
||||
shared: true
|
||||
transpile: true
|
||||
cost_estimate: 5
|
||||
args:
|
||||
bits: Int32Id
|
||||
bigInt: BigIntId
|
||||
|
||||
- name: CallPrintString
|
||||
shared: true
|
||||
transpile: false
|
||||
|
|
|
@ -15477,8 +15477,8 @@ void CodeGenerator::visitGuardIsExtensible(LGuardIsExtensible* lir) {
|
|||
bailoutFrom(&bail, lir->snapshot());
|
||||
}
|
||||
|
||||
void CodeGenerator::visitGuardIndexIsNonNegative(
|
||||
LGuardIndexIsNonNegative* lir) {
|
||||
void CodeGenerator::visitGuardInt32IsNonNegative(
|
||||
LGuardInt32IsNonNegative* lir) {
|
||||
Register index = ToRegister(lir->index());
|
||||
|
||||
bailoutCmp32(Assembler::LessThan, index, Imm32(0), lir->snapshot());
|
||||
|
@ -15605,6 +15605,159 @@ void CodeGenerator::visitCallObjectHasSparseElement(
|
|||
bailoutFrom(&bail, lir->snapshot());
|
||||
}
|
||||
|
||||
void CodeGenerator::visitBigIntAsIntN(LBigIntAsIntN* ins) {
|
||||
Register bits = ToRegister(ins->bits());
|
||||
Register input = ToRegister(ins->input());
|
||||
|
||||
pushArg(bits);
|
||||
pushArg(input);
|
||||
|
||||
using Fn = BigInt* (*)(JSContext*, HandleBigInt, int32_t);
|
||||
callVM<Fn, jit::BigIntAsIntN>(ins);
|
||||
}
|
||||
|
||||
void CodeGenerator::visitBigIntAsIntN64(LBigIntAsIntN64* ins) {
|
||||
Register input = ToRegister(ins->input());
|
||||
Register temp = ToRegister(ins->temp());
|
||||
Register64 temp64 = ToRegister64(ins->temp64());
|
||||
Register output = ToRegister(ins->output());
|
||||
|
||||
Label done, create;
|
||||
|
||||
masm.movePtr(input, output);
|
||||
|
||||
// Load the BigInt value as an int64.
|
||||
masm.loadBigInt64(input, temp64);
|
||||
|
||||
// Create a new BigInt when the input exceeds the int64 range.
|
||||
masm.branch32(Assembler::Above, Address(input, BigInt::offsetOfLength()),
|
||||
Imm32(64 / BigInt::DigitBits), &create);
|
||||
|
||||
// And create a new BigInt when the value and the BigInt have different signs.
|
||||
Label nonNegative;
|
||||
masm.branchIfBigIntIsNonNegative(input, &nonNegative);
|
||||
masm.branchTest64(Assembler::NotSigned, temp64, temp64, temp, &create);
|
||||
masm.jump(&done);
|
||||
|
||||
masm.bind(&nonNegative);
|
||||
masm.branchTest64(Assembler::NotSigned, temp64, temp64, temp, &done);
|
||||
|
||||
masm.bind(&create);
|
||||
emitCreateBigInt(ins, Scalar::BigInt64, temp64, output, temp);
|
||||
|
||||
masm.bind(&done);
|
||||
}
|
||||
|
||||
void CodeGenerator::visitBigIntAsIntN32(LBigIntAsIntN32* ins) {
|
||||
Register input = ToRegister(ins->input());
|
||||
Register temp = ToRegister(ins->temp());
|
||||
Register64 temp64 = ToRegister64(ins->temp64());
|
||||
Register output = ToRegister(ins->output());
|
||||
|
||||
Label done, create;
|
||||
|
||||
masm.movePtr(input, output);
|
||||
|
||||
// Load the absolute value of the first digit.
|
||||
masm.loadFirstBigIntDigitOrZero(input, temp);
|
||||
|
||||
// If the absolute value exceeds the int32 range, create a new BigInt.
|
||||
masm.branchPtr(Assembler::Above, temp, Imm32(INT32_MAX), &create);
|
||||
|
||||
// Also create a new BigInt if we have more than one digit.
|
||||
masm.branch32(Assembler::BelowOrEqual,
|
||||
Address(input, BigInt::offsetOfLength()), Imm32(1), &done);
|
||||
|
||||
masm.bind(&create);
|
||||
|
||||
// |temp| stores the absolute value, negate it when the sign flag is set.
|
||||
Label nonNegative;
|
||||
masm.branchIfBigIntIsNonNegative(input, &nonNegative);
|
||||
masm.negPtr(temp);
|
||||
masm.bind(&nonNegative);
|
||||
|
||||
masm.move32To64SignExtend(temp, temp64);
|
||||
emitCreateBigInt(ins, Scalar::BigInt64, temp64, output, temp);
|
||||
|
||||
masm.bind(&done);
|
||||
}
|
||||
|
||||
void CodeGenerator::visitBigIntAsUintN(LBigIntAsUintN* ins) {
|
||||
Register bits = ToRegister(ins->bits());
|
||||
Register input = ToRegister(ins->input());
|
||||
|
||||
pushArg(bits);
|
||||
pushArg(input);
|
||||
|
||||
using Fn = BigInt* (*)(JSContext*, HandleBigInt, int32_t);
|
||||
callVM<Fn, jit::BigIntAsUintN>(ins);
|
||||
}
|
||||
|
||||
void CodeGenerator::visitBigIntAsUintN64(LBigIntAsUintN64* ins) {
|
||||
Register input = ToRegister(ins->input());
|
||||
Register temp = ToRegister(ins->temp());
|
||||
Register64 temp64 = ToRegister64(ins->temp64());
|
||||
Register output = ToRegister(ins->output());
|
||||
|
||||
Label done, create;
|
||||
|
||||
masm.movePtr(input, output);
|
||||
|
||||
// Load the BigInt value as an uint64.
|
||||
masm.loadBigInt64(input, temp64);
|
||||
|
||||
// Create a new BigInt when the input exceeds the uint64 range.
|
||||
masm.branch32(Assembler::Above, Address(input, BigInt::offsetOfLength()),
|
||||
Imm32(64 / BigInt::DigitBits), &create);
|
||||
|
||||
// And create a new BigInt when the input has the sign flag set.
|
||||
masm.branchIfBigIntIsNonNegative(input, &done);
|
||||
|
||||
masm.bind(&create);
|
||||
emitCreateBigInt(ins, Scalar::BigUint64, temp64, output, temp);
|
||||
|
||||
masm.bind(&done);
|
||||
}
|
||||
|
||||
void CodeGenerator::visitBigIntAsUintN32(LBigIntAsUintN32* ins) {
|
||||
Register input = ToRegister(ins->input());
|
||||
Register temp = ToRegister(ins->temp());
|
||||
Register64 temp64 = ToRegister64(ins->temp64());
|
||||
Register output = ToRegister(ins->output());
|
||||
|
||||
Label done, create;
|
||||
|
||||
masm.movePtr(input, output);
|
||||
|
||||
// Load the absolute value of the first digit.
|
||||
masm.loadFirstBigIntDigitOrZero(input, temp);
|
||||
|
||||
// If the absolute value exceeds the uint32 range, create a new BigInt.
|
||||
#if JS_PUNBOX64
|
||||
masm.branchPtr(Assembler::Above, temp, ImmWord(UINT32_MAX), &create);
|
||||
#endif
|
||||
|
||||
// Also create a new BigInt if we have more than one digit.
|
||||
masm.branch32(Assembler::Above, Address(input, BigInt::offsetOfLength()),
|
||||
Imm32(1), &create);
|
||||
|
||||
// And create a new BigInt when the input has the sign flag set.
|
||||
masm.branchIfBigIntIsNonNegative(input, &done);
|
||||
|
||||
masm.bind(&create);
|
||||
|
||||
// |temp| stores the absolute value, negate it when the sign flag is set.
|
||||
Label nonNegative;
|
||||
masm.branchIfBigIntIsNonNegative(input, &nonNegative);
|
||||
masm.negPtr(temp);
|
||||
masm.bind(&nonNegative);
|
||||
|
||||
masm.move32To64ZeroExtend(temp, temp64);
|
||||
emitCreateBigInt(ins, Scalar::BigUint64, temp64, output, temp);
|
||||
|
||||
masm.bind(&done);
|
||||
}
|
||||
|
||||
template <size_t NumDefs>
|
||||
void CodeGenerator::emitIonToWasmCallBase(LIonToWasmCallBase<NumDefs>* lir) {
|
||||
wasm::JitCallStackArgVector stackArgs;
|
||||
|
|