Merge autoland to mozilla-central. a=merge

This commit is contained in:
smolnar 2021-01-14 10:31:00 +02:00
Родитель b9267b9a87 4e682be3b2
Коммит 2a24205479
243 изменённых файлов: 12527 добавлений и 1435 удалений

66
Cargo.lock сгенерированный
Просмотреть файл

@ -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,
[&sectionFileName, 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

Двоичные данные
browser/components/newtab/data/content/tippytop/favicons/etsy.ico Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 4.2 KiB

Двоичные данные
browser/components/newtab/data/content/tippytop/favicons/geico.ico Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 34 KiB

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 3.9 KiB

Двоичные данные
browser/components/newtab/data/content/tippytop/favicons/nike.ico Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 1.1 KiB

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 4.2 KiB

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 3.7 KiB

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 1.7 KiB

Двоичные данные
browser/components/newtab/data/content/tippytop/favicons/wix.ico Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 1.0 KiB

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 14 KiB

Двоичные данные
browser/components/newtab/data/content/tippytop/images/etsy@2x.jpg Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 4.0 KiB

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 12 KiB

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 28 KiB

Двоичные данные
browser/components/newtab/data/content/tippytop/images/nike@2x.jpg Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 5.0 KiB

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 3.3 KiB

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 12 KiB

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 6.9 KiB

Двоичные данные
browser/components/newtab/data/content/tippytop/images/wix@2x.jpg Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 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;

Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше