mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-24 21:31:04 +00:00
Merge inbound to mozilla-central. a=merge
This commit is contained in:
commit
aff5d4ad5d
@ -1,7 +0,0 @@
|
||||
{
|
||||
"infer-blacklist-path-regex": [
|
||||
// This is full of issues, and is a dependency we need to discard
|
||||
// sooner rather than later anyway:
|
||||
"mobile/android/thirdparty/ch/boye/httpclientandroidlib"
|
||||
]
|
||||
}
|
@ -98,6 +98,3 @@ if CONFIG['CC_TYPE'] == 'clang-cl':
|
||||
'-Wno-missing-braces',
|
||||
'-Wno-unused-const-variable',
|
||||
]
|
||||
|
||||
if CONFIG['MOZ_PGO'] and CONFIG['CC_TYPE'] == 'clang-cl':
|
||||
AllowCompilerWarnings() # workaround for bug 1090497
|
||||
|
@ -44,6 +44,3 @@ if CONFIG['CC_TYPE'] == 'clang-cl':
|
||||
'-Wno-missing-braces',
|
||||
'-Wno-unused-const-variable',
|
||||
]
|
||||
|
||||
if CONFIG['MOZ_PGO'] and CONFIG['CC_TYPE'] == 'clang-cl':
|
||||
AllowCompilerWarnings() # workaround for bug 1090497
|
||||
|
@ -25,8 +25,7 @@
|
||||
{ MOZ_LITERAL_UNICODE_STRING(L##name), __VA_ARGS__ },
|
||||
#define DLL_BLOCKLIST_STRING_TYPE UNICODE_STRING
|
||||
|
||||
// Restrict the blocklist definitions to Nightly-only for now
|
||||
#if defined(NIGHTLY_BUILD)
|
||||
#if defined(MOZ_LAUNCHER_PROCESS) || defined(NIGHTLY_BUILD)
|
||||
#include "mozilla/WindowsDllBlocklistDefs.h"
|
||||
#else
|
||||
#include "mozilla/WindowsDllBlocklistCommon.h"
|
||||
|
@ -6,6 +6,7 @@
|
||||
|
||||
#include "LaunchUnelevated.h"
|
||||
|
||||
#include "mozilla/Assertions.h"
|
||||
#include "mozilla/CmdLineAndEnvUtils.h"
|
||||
#include "mozilla/mscom/COMApartmentRegion.h"
|
||||
#include "mozilla/RefPtr.h"
|
||||
@ -22,6 +23,76 @@
|
||||
#include <shlobj.h>
|
||||
#include <shobjidl.h>
|
||||
|
||||
static mozilla::Maybe<TOKEN_ELEVATION_TYPE>
|
||||
GetElevationType(const nsAutoHandle& aToken)
|
||||
{
|
||||
DWORD retLen;
|
||||
TOKEN_ELEVATION_TYPE elevationType;
|
||||
if (!::GetTokenInformation(aToken.get(), TokenElevationType, &elevationType,
|
||||
sizeof(elevationType), &retLen)) {
|
||||
return mozilla::Nothing();
|
||||
}
|
||||
|
||||
return mozilla::Some(elevationType);
|
||||
}
|
||||
|
||||
static mozilla::Maybe<bool>
|
||||
IsHighIntegrity(const nsAutoHandle& aToken)
|
||||
{
|
||||
DWORD reqdLen;
|
||||
if (!::GetTokenInformation(aToken.get(), TokenIntegrityLevel, nullptr, 0,
|
||||
&reqdLen) &&
|
||||
::GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
|
||||
return mozilla::Nothing();
|
||||
}
|
||||
|
||||
auto buf = mozilla::MakeUnique<char[]>(reqdLen);
|
||||
|
||||
if (!::GetTokenInformation(aToken.get(), TokenIntegrityLevel, buf.get(),
|
||||
reqdLen, &reqdLen)) {
|
||||
return mozilla::Nothing();
|
||||
}
|
||||
|
||||
auto tokenLabel = reinterpret_cast<PTOKEN_MANDATORY_LABEL>(buf.get());
|
||||
|
||||
DWORD subAuthCount = *::GetSidSubAuthorityCount(tokenLabel->Label.Sid);
|
||||
DWORD integrityLevel = *::GetSidSubAuthority(tokenLabel->Label.Sid,
|
||||
subAuthCount - 1);
|
||||
return mozilla::Some(integrityLevel > SECURITY_MANDATORY_MEDIUM_RID);
|
||||
}
|
||||
|
||||
static nsReturnRef<HANDLE>
|
||||
GetMediumIntegrityToken(const nsAutoHandle& aProcessToken)
|
||||
{
|
||||
nsAutoHandle empty;
|
||||
|
||||
HANDLE rawResult;
|
||||
if (!::DuplicateTokenEx(aProcessToken.get(), 0, nullptr,
|
||||
SecurityImpersonation, TokenPrimary, &rawResult)) {
|
||||
return empty.out();
|
||||
}
|
||||
|
||||
nsAutoHandle result(rawResult);
|
||||
|
||||
BYTE mediumIlSid[SECURITY_MAX_SID_SIZE];
|
||||
DWORD mediumIlSidSize = sizeof(mediumIlSid);
|
||||
if (!::CreateWellKnownSid(WinMediumLabelSid, nullptr, mediumIlSid,
|
||||
&mediumIlSidSize)) {
|
||||
return empty.out();
|
||||
}
|
||||
|
||||
TOKEN_MANDATORY_LABEL integrityLevel = {};
|
||||
integrityLevel.Label.Attributes = SE_GROUP_INTEGRITY;
|
||||
integrityLevel.Label.Sid = reinterpret_cast<PSID>(mediumIlSid);
|
||||
|
||||
if (!::SetTokenInformation(rawResult, TokenIntegrityLevel, &integrityLevel,
|
||||
sizeof(integrityLevel))) {
|
||||
return empty.out();
|
||||
}
|
||||
|
||||
return result.out();
|
||||
}
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
// If we're running at an elevated integrity level, re-run ourselves at the
|
||||
@ -125,36 +196,62 @@ LaunchUnelevated(int aArgc, wchar_t* aArgv[])
|
||||
return SUCCEEDED(hr);
|
||||
}
|
||||
|
||||
mozilla::Maybe<bool>
|
||||
IsElevated()
|
||||
Maybe<ElevationState>
|
||||
GetElevationState(mozilla::LauncherFlags aFlags, nsAutoHandle& aOutMediumIlToken)
|
||||
{
|
||||
aOutMediumIlToken.reset();
|
||||
|
||||
const DWORD tokenFlags = TOKEN_QUERY | TOKEN_DUPLICATE |
|
||||
TOKEN_ADJUST_DEFAULT | TOKEN_ASSIGN_PRIMARY;
|
||||
HANDLE rawToken;
|
||||
if (!::OpenProcessToken(::GetCurrentProcess(), TOKEN_QUERY, &rawToken)) {
|
||||
return mozilla::Nothing();
|
||||
if (!::OpenProcessToken(::GetCurrentProcess(), tokenFlags, &rawToken)) {
|
||||
return Nothing();
|
||||
}
|
||||
|
||||
nsAutoHandle token(rawToken);
|
||||
|
||||
DWORD reqdLen;
|
||||
if (!::GetTokenInformation(token.get(), TokenIntegrityLevel, nullptr, 0,
|
||||
&reqdLen) &&
|
||||
::GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
|
||||
return mozilla::Nothing();
|
||||
Maybe<TOKEN_ELEVATION_TYPE> elevationType = GetElevationType(token);
|
||||
if (!elevationType) {
|
||||
return Nothing();
|
||||
}
|
||||
|
||||
auto buf = mozilla::MakeUnique<char[]>(reqdLen);
|
||||
switch (elevationType.value()) {
|
||||
case TokenElevationTypeLimited:
|
||||
return Some(ElevationState::eNormalUser);
|
||||
case TokenElevationTypeFull:
|
||||
// If we want to start a non-elevated browser process and wait on it,
|
||||
// we're going to need a medium IL token.
|
||||
if ((aFlags & (mozilla::LauncherFlags::eWaitForBrowser |
|
||||
mozilla::LauncherFlags::eNoDeelevate)) ==
|
||||
mozilla::LauncherFlags::eWaitForBrowser) {
|
||||
aOutMediumIlToken = GetMediumIntegrityToken(token);
|
||||
}
|
||||
|
||||
if (!::GetTokenInformation(token.get(), TokenIntegrityLevel, buf.get(),
|
||||
reqdLen, &reqdLen)) {
|
||||
return mozilla::Nothing();
|
||||
return Some(ElevationState::eElevated);
|
||||
case TokenElevationTypeDefault:
|
||||
break;
|
||||
default:
|
||||
MOZ_ASSERT_UNREACHABLE("Was a new value added to the enumeration?");
|
||||
return Nothing();
|
||||
}
|
||||
|
||||
auto tokenLabel = reinterpret_cast<PTOKEN_MANDATORY_LABEL>(buf.get());
|
||||
// In this case, UAC is disabled. We do not yet know whether or not we are
|
||||
// running at high integrity. If we are at high integrity, we can't relaunch
|
||||
// ourselves in a non-elevated state via Explorer, as we would just end up in
|
||||
// an infinite loop of launcher processes re-launching themselves.
|
||||
|
||||
DWORD subAuthCount = *::GetSidSubAuthorityCount(tokenLabel->Label.Sid);
|
||||
DWORD integrityLevel = *::GetSidSubAuthority(tokenLabel->Label.Sid,
|
||||
subAuthCount - 1);
|
||||
return mozilla::Some(integrityLevel > SECURITY_MANDATORY_MEDIUM_RID);
|
||||
Maybe<bool> isHighIntegrity = IsHighIntegrity(token);
|
||||
if (!isHighIntegrity) {
|
||||
return Nothing();
|
||||
}
|
||||
|
||||
if (!isHighIntegrity.value()) {
|
||||
return Some(ElevationState::eNormalUser);
|
||||
}
|
||||
|
||||
aOutMediumIlToken = GetMediumIntegrityToken(token);
|
||||
|
||||
return Some(ElevationState::eHighIntegrityNoUAC);
|
||||
}
|
||||
|
||||
} // namespace mozilla
|
||||
|
@ -7,11 +7,22 @@
|
||||
#ifndef mozilla_LaunchUnelevated_h
|
||||
#define mozilla_LaunchUnelevated_h
|
||||
|
||||
#include "LauncherProcessWin.h"
|
||||
#include "mozilla/Maybe.h"
|
||||
#include "nsWindowsHelpers.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
mozilla::Maybe<bool> IsElevated();
|
||||
enum class ElevationState
|
||||
{
|
||||
eNormalUser = 0,
|
||||
eElevated = (1 << 0),
|
||||
eHighIntegrityNoUAC = (1 << 1),
|
||||
};
|
||||
|
||||
mozilla::Maybe<ElevationState>
|
||||
GetElevationState(LauncherFlags aFlags, nsAutoHandle& aOutMediumIlToken);
|
||||
|
||||
bool LaunchUnelevated(int aArgc, wchar_t* aArgv[]);
|
||||
|
||||
} // namespace mozilla
|
||||
|
@ -82,16 +82,82 @@ ShowError(DWORD aError = ::GetLastError())
|
||||
::LocalFree(rawMsgBuf);
|
||||
}
|
||||
|
||||
static mozilla::LauncherFlags
|
||||
ProcessCmdLine(int& aArgc, wchar_t* aArgv[])
|
||||
{
|
||||
mozilla::LauncherFlags result = mozilla::LauncherFlags::eNone;
|
||||
|
||||
if (mozilla::CheckArg(aArgc, aArgv, L"wait-for-browser",
|
||||
static_cast<const wchar_t**>(nullptr),
|
||||
mozilla::CheckArgFlag::RemoveArg) == mozilla::ARG_FOUND ||
|
||||
mozilla::EnvHasValue("MOZ_AUTOMATION")) {
|
||||
result |= mozilla::LauncherFlags::eWaitForBrowser;
|
||||
}
|
||||
|
||||
if (mozilla::CheckArg(aArgc, aArgv, L"no-deelevate",
|
||||
static_cast<const wchar_t**>(nullptr),
|
||||
mozilla::CheckArgFlag::CheckOSInt |
|
||||
mozilla::CheckArgFlag::RemoveArg) == mozilla::ARG_FOUND) {
|
||||
result |= mozilla::LauncherFlags::eNoDeelevate;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
#if defined(MOZ_LAUNCHER_PROCESS)
|
||||
|
||||
static mozilla::Maybe<bool>
|
||||
IsSameBinaryAsParentProcess()
|
||||
{
|
||||
mozilla::Maybe<DWORD> parentPid = mozilla::nt::GetParentProcessId();
|
||||
if (!parentPid) {
|
||||
return mozilla::Nothing();
|
||||
}
|
||||
|
||||
nsAutoHandle parentProcess(::OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION,
|
||||
FALSE, parentPid.value()));
|
||||
if (!parentProcess.get()) {
|
||||
return mozilla::Nothing();
|
||||
}
|
||||
|
||||
WCHAR parentExe[MAX_PATH + 1] = {};
|
||||
DWORD parentExeLen = mozilla::ArrayLength(parentExe);
|
||||
if (!::QueryFullProcessImageNameW(parentProcess.get(), 0, parentExe,
|
||||
&parentExeLen)) {
|
||||
return mozilla::Nothing();
|
||||
}
|
||||
|
||||
WCHAR ourExe[MAX_PATH + 1] = {};
|
||||
DWORD ourExeOk = ::GetModuleFileNameW(nullptr, ourExe,
|
||||
mozilla::ArrayLength(ourExe));
|
||||
if (!ourExeOk || ourExeOk == mozilla::ArrayLength(ourExe)) {
|
||||
return mozilla::Nothing();
|
||||
}
|
||||
|
||||
bool isSame = parentExeLen == ourExeOk &&
|
||||
!_wcsnicmp(ourExe, parentExe, ourExeOk);
|
||||
return mozilla::Some(isSame);
|
||||
}
|
||||
|
||||
#endif // defined(MOZ_LAUNCHER_PROCESS)
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
// Eventually we want to be able to set a build config flag such that, when set,
|
||||
// this function will always return true.
|
||||
bool
|
||||
RunAsLauncherProcess(int& argc, wchar_t** argv)
|
||||
{
|
||||
#if defined(MOZ_LAUNCHER_PROCESS)
|
||||
Maybe<bool> isChildOfFirefox = IsSameBinaryAsParentProcess();
|
||||
if (!isChildOfFirefox) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return !isChildOfFirefox.value();
|
||||
#else
|
||||
return CheckArg(argc, argv, L"launcher",
|
||||
static_cast<const wchar_t**>(nullptr),
|
||||
CheckArgFlag::CheckOSInt | CheckArgFlag::RemoveArg);
|
||||
CheckArgFlag::CheckOSInt | CheckArgFlag::RemoveArg) == ARG_FOUND;
|
||||
#endif // defined(MOZ_LAUNCHER_PROCESS)
|
||||
}
|
||||
|
||||
int
|
||||
@ -117,13 +183,20 @@ LauncherMain(int argc, wchar_t* argv[])
|
||||
return 1;
|
||||
}
|
||||
|
||||
// If we're elevated, we should relaunch ourselves as a normal user
|
||||
Maybe<bool> isElevated = IsElevated();
|
||||
if (!isElevated) {
|
||||
LauncherFlags flags = ProcessCmdLine(argc, argv);
|
||||
|
||||
nsAutoHandle mediumIlToken;
|
||||
Maybe<ElevationState> elevationState = GetElevationState(flags, mediumIlToken);
|
||||
if (!elevationState) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (isElevated.value()) {
|
||||
// If we're elevated, we should relaunch ourselves as a normal user.
|
||||
// Note that we only call LaunchUnelevated when we don't need to wait for the
|
||||
// browser process.
|
||||
if (elevationState.value() == ElevationState::eElevated &&
|
||||
!(flags & (LauncherFlags::eWaitForBrowser | LauncherFlags::eNoDeelevate)) &&
|
||||
!mediumIlToken.get()) {
|
||||
return !LaunchUnelevated(argc, argv);
|
||||
}
|
||||
|
||||
@ -178,8 +251,20 @@ LauncherMain(int argc, wchar_t* argv[])
|
||||
}
|
||||
|
||||
PROCESS_INFORMATION pi = {};
|
||||
if (!::CreateProcessW(argv[0], cmdLine.get(), nullptr, nullptr, inheritHandles,
|
||||
creationFlags, nullptr, nullptr, &siex.StartupInfo, &pi)) {
|
||||
BOOL createOk;
|
||||
|
||||
if (mediumIlToken.get()) {
|
||||
createOk = ::CreateProcessAsUserW(mediumIlToken.get(), argv[0], cmdLine.get(),
|
||||
nullptr, nullptr, inheritHandles,
|
||||
creationFlags, nullptr, nullptr,
|
||||
&siex.StartupInfo, &pi);
|
||||
} else {
|
||||
createOk = ::CreateProcessW(argv[0], cmdLine.get(), nullptr, nullptr,
|
||||
inheritHandles, creationFlags, nullptr, nullptr,
|
||||
&siex.StartupInfo, &pi);
|
||||
}
|
||||
|
||||
if (!createOk) {
|
||||
ShowError();
|
||||
return 1;
|
||||
}
|
||||
@ -194,13 +279,22 @@ LauncherMain(int argc, wchar_t* argv[])
|
||||
return 1;
|
||||
}
|
||||
|
||||
const DWORD timeout = ::IsDebuggerPresent() ? INFINITE :
|
||||
kWaitForInputIdleTimeoutMS;
|
||||
if (flags & LauncherFlags::eWaitForBrowser) {
|
||||
DWORD exitCode;
|
||||
if (::WaitForSingleObject(process.get(), INFINITE) == WAIT_OBJECT_0 &&
|
||||
::GetExitCodeProcess(process.get(), &exitCode)) {
|
||||
// Propagate the browser process's exit code as our exit code.
|
||||
return static_cast<int>(exitCode);
|
||||
}
|
||||
} else {
|
||||
const DWORD timeout = ::IsDebuggerPresent() ? INFINITE :
|
||||
kWaitForInputIdleTimeoutMS;
|
||||
|
||||
// Keep the current process around until the callback process has created
|
||||
// its message queue, to avoid the launched process's windows being forced
|
||||
// into the background.
|
||||
mozilla::WaitForInputIdle(process.get(), timeout);
|
||||
// Keep the current process around until the callback process has created
|
||||
// its message queue, to avoid the launched process's windows being forced
|
||||
// into the background.
|
||||
mozilla::WaitForInputIdle(process.get(), timeout);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -7,11 +7,24 @@
|
||||
#ifndef mozilla_LauncherProcessWin_h
|
||||
#define mozilla_LauncherProcessWin_h
|
||||
|
||||
#include "mozilla/TypedEnumBits.h"
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
bool RunAsLauncherProcess(int& argc, wchar_t* argv[]);
|
||||
int LauncherMain(int argc, wchar_t* argv[]);
|
||||
|
||||
enum class LauncherFlags : uint32_t
|
||||
{
|
||||
eNone = 0,
|
||||
eWaitForBrowser = (1 << 0), // Launcher should block until browser finishes
|
||||
eNoDeelevate = (1 << 1), // If elevated, do not attempt to de-elevate
|
||||
};
|
||||
|
||||
MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(LauncherFlags)
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_LauncherProcessWin_h
|
||||
|
@ -18,6 +18,7 @@
|
||||
|
||||
#include "mozilla/ArrayUtils.h"
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "mozilla/Maybe.h"
|
||||
|
||||
extern "C" {
|
||||
|
||||
@ -449,8 +450,15 @@ private:
|
||||
return;
|
||||
}
|
||||
|
||||
DWORD imageSize = mPeHeader->OptionalHeader.SizeOfImage;
|
||||
// This is a coarse-grained check to ensure that the image size is
|
||||
// reasonable. It we aren't big enough to contain headers, we have a problem!
|
||||
if (imageSize < sizeof(IMAGE_DOS_HEADER) + sizeof(IMAGE_NT_HEADERS)) {
|
||||
return;
|
||||
}
|
||||
|
||||
mImageLimit =
|
||||
RVAToPtrUnchecked<void*>(mPeHeader->OptionalHeader.SizeOfImage - 1UL);
|
||||
RVAToPtrUnchecked<void*>(imageSize - 1UL);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
@ -511,8 +519,7 @@ private:
|
||||
GetFixedFileInfo(VS_VERSIONINFO_HEADER* aVerInfo)
|
||||
{
|
||||
WORD length = aVerInfo->wLength;
|
||||
WORD offset = sizeof(VS_VERSIONINFO_HEADER);
|
||||
if (!offset) {
|
||||
if (length < sizeof(VS_VERSIONINFO_HEADER)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
@ -523,12 +530,19 @@ private:
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (aVerInfo->wValueLength != sizeof(VS_FIXEDFILEINFO)) {
|
||||
// Fixed file info does not exist
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
WORD offset = sizeof(VS_VERSIONINFO_HEADER);
|
||||
|
||||
uintptr_t base = reinterpret_cast<uintptr_t>(aVerInfo);
|
||||
// Align up to 4-byte boundary
|
||||
#pragma warning(suppress: 4146)
|
||||
offset += (-(base + offset) & 3);
|
||||
|
||||
if (offset > length) {
|
||||
if (offset >= length) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
@ -554,6 +568,32 @@ RtlGetProcessHeap()
|
||||
return peb->Reserved4[1];
|
||||
}
|
||||
|
||||
inline Maybe<DWORD>
|
||||
GetParentProcessId()
|
||||
{
|
||||
struct PROCESS_BASIC_INFORMATION
|
||||
{
|
||||
NTSTATUS ExitStatus;
|
||||
PPEB PebBaseAddress;
|
||||
ULONG_PTR AffinityMask;
|
||||
LONG BasePriority;
|
||||
ULONG_PTR UniqueProcessId;
|
||||
ULONG_PTR InheritedFromUniqueProcessId;
|
||||
};
|
||||
|
||||
ULONG returnLength;
|
||||
PROCESS_BASIC_INFORMATION pbi = {};
|
||||
NTSTATUS status = ::NtQueryInformationProcess(::GetCurrentProcess(),
|
||||
ProcessBasicInformation,
|
||||
&pbi, sizeof(pbi),
|
||||
&returnLength);
|
||||
if (!NT_SUCCESS(status)) {
|
||||
return Nothing();
|
||||
}
|
||||
|
||||
return Some(static_cast<DWORD>(pbi.InheritedFromUniqueProcessId & 0xFFFFFFFF));
|
||||
}
|
||||
|
||||
} // namespace nt
|
||||
} // namespace mozilla
|
||||
|
||||
|
@ -108,12 +108,15 @@ async function getRectForSidebarItem(guid) {
|
||||
let sidebar = document.getElementById("sidebar");
|
||||
let tree = sidebar.contentDocument.getElementById("bookmarks-view");
|
||||
tree.selectItems([guid]);
|
||||
let rect = {};
|
||||
[rect.left, rect.top, rect.width, rect.height] = tree.treeBoxObject
|
||||
.selectionRegion
|
||||
.getRects();
|
||||
// Adjust the position for the sidebar.
|
||||
rect.left += sidebar.getBoundingClientRect().left;
|
||||
rect.top += sidebar.getBoundingClientRect().top;
|
||||
return rect;
|
||||
let treerect = tree.getBoundingClientRect();
|
||||
let cellrect = tree.treeBoxObject.
|
||||
getCoordsForCellItem(tree.currentIndex, tree.columns[0], "cell");
|
||||
|
||||
// Adjust the position for the tree and sidebar.
|
||||
return {
|
||||
left: treerect.left + cellrect.left + sidebar.getBoundingClientRect().left,
|
||||
top: treerect.top + cellrect.top + sidebar.getBoundingClientRect().top,
|
||||
width: cellrect.width,
|
||||
height: cellrect.height
|
||||
};
|
||||
}
|
||||
|
@ -1267,6 +1267,7 @@ def pgo_flags(compiler, build_env, target):
|
||||
gen_cflags=['-fprofile-instr-generate'],
|
||||
gen_ldflags=['clang_rt.profile-x86_64.lib'],
|
||||
use_cflags=['-fprofile-instr-use=%s' % profdata,
|
||||
'-Wno-error=profile-instr-out-of-date',
|
||||
'-Wno-error=profile-instr-unprofiled'],
|
||||
use_ldflags=[],
|
||||
)
|
||||
|
@ -1079,8 +1079,11 @@ int do_relocation_section(Elf *elf, unsigned int rel_type, unsigned int rel_type
|
||||
relhackcode->insertBefore(first_executable);
|
||||
|
||||
// Don't try further if we can't gain from the relocation section size change.
|
||||
// We account for the fact we're going to split the PT_LOAD before the injected
|
||||
// code section, so the overhead of the page alignment for section needs to be
|
||||
// accounted for.
|
||||
size_t align = first_executable->getSegmentByType(PT_LOAD)->getAlign();
|
||||
size_t new_size = relhack->getSize() + relhackcode->getSize();
|
||||
size_t new_size = relhack->getSize() + relhackcode->getSize() + (relhackcode->getAddr() & (align - 1));
|
||||
if (!force && (new_size >= old_size || old_size - new_size < align)) {
|
||||
fprintf(stderr, "No gain. Skipping\n");
|
||||
return -1;
|
||||
|
@ -1632,6 +1632,146 @@ exports.CSS_PROPERTIES = {
|
||||
"unset"
|
||||
]
|
||||
},
|
||||
"-webkit-appearance": {
|
||||
"isInherited": false,
|
||||
"subproperties": [
|
||||
"-moz-appearance"
|
||||
],
|
||||
"supports": [],
|
||||
"values": [
|
||||
"-moz-gtk-info-bar",
|
||||
"-moz-mac-active-source-list-selection",
|
||||
"-moz-mac-disclosure-button-closed",
|
||||
"-moz-mac-disclosure-button-open",
|
||||
"-moz-mac-fullscreen-button",
|
||||
"-moz-mac-help-button",
|
||||
"-moz-mac-source-list",
|
||||
"-moz-mac-source-list-selection",
|
||||
"-moz-mac-vibrancy-dark",
|
||||
"-moz-mac-vibrancy-light",
|
||||
"-moz-mac-vibrant-titlebar-dark",
|
||||
"-moz-mac-vibrant-titlebar-light",
|
||||
"-moz-menulist-button",
|
||||
"-moz-win-borderless-glass",
|
||||
"-moz-win-browsertabbar-toolbox",
|
||||
"-moz-win-communications-toolbox",
|
||||
"-moz-win-exclude-glass",
|
||||
"-moz-win-glass",
|
||||
"-moz-win-media-toolbox",
|
||||
"-moz-window-button-box",
|
||||
"-moz-window-button-box-maximized",
|
||||
"-moz-window-button-close",
|
||||
"-moz-window-button-maximize",
|
||||
"-moz-window-button-minimize",
|
||||
"-moz-window-button-restore",
|
||||
"-moz-window-frame-bottom",
|
||||
"-moz-window-frame-left",
|
||||
"-moz-window-frame-right",
|
||||
"-moz-window-titlebar",
|
||||
"-moz-window-titlebar-maximized",
|
||||
"button",
|
||||
"button-arrow-down",
|
||||
"button-arrow-next",
|
||||
"button-arrow-previous",
|
||||
"button-arrow-up",
|
||||
"button-bevel",
|
||||
"button-focus",
|
||||
"caret",
|
||||
"checkbox",
|
||||
"checkbox-container",
|
||||
"checkbox-label",
|
||||
"checkmenuitem",
|
||||
"dialog",
|
||||
"dualbutton",
|
||||
"groupbox",
|
||||
"inherit",
|
||||
"initial",
|
||||
"inner-spin-button",
|
||||
"listbox",
|
||||
"listitem",
|
||||
"menuarrow",
|
||||
"menubar",
|
||||
"menucheckbox",
|
||||
"menuimage",
|
||||
"menuitem",
|
||||
"menuitemtext",
|
||||
"menulist",
|
||||
"menulist-button",
|
||||
"menulist-text",
|
||||
"menulist-textfield",
|
||||
"menupopup",
|
||||
"menuradio",
|
||||
"menuseparator",
|
||||
"meterbar",
|
||||
"meterchunk",
|
||||
"none",
|
||||
"number-input",
|
||||
"progressbar",
|
||||
"progressbar-vertical",
|
||||
"progresschunk",
|
||||
"progresschunk-vertical",
|
||||
"radio",
|
||||
"radio-container",
|
||||
"radio-label",
|
||||
"radiomenuitem",
|
||||
"range",
|
||||
"range-thumb",
|
||||
"resizer",
|
||||
"resizerpanel",
|
||||
"scale-horizontal",
|
||||
"scale-vertical",
|
||||
"scalethumb-horizontal",
|
||||
"scalethumb-vertical",
|
||||
"scalethumbend",
|
||||
"scalethumbstart",
|
||||
"scalethumbtick",
|
||||
"scrollbar",
|
||||
"scrollbar-horizontal",
|
||||
"scrollbar-small",
|
||||
"scrollbar-vertical",
|
||||
"scrollbarbutton-down",
|
||||
"scrollbarbutton-left",
|
||||
"scrollbarbutton-right",
|
||||
"scrollbarbutton-up",
|
||||
"scrollbarthumb-horizontal",
|
||||
"scrollbarthumb-vertical",
|
||||
"scrollbartrack-horizontal",
|
||||
"scrollbartrack-vertical",
|
||||
"scrollcorner",
|
||||
"searchfield",
|
||||
"separator",
|
||||
"spinner",
|
||||
"spinner-downbutton",
|
||||
"spinner-textfield",
|
||||
"spinner-upbutton",
|
||||
"splitter",
|
||||
"statusbar",
|
||||
"statusbarpanel",
|
||||
"tab",
|
||||
"tab-scroll-arrow-back",
|
||||
"tab-scroll-arrow-forward",
|
||||
"tabpanel",
|
||||
"tabpanels",
|
||||
"textfield",
|
||||
"textfield-multiline",
|
||||
"toolbar",
|
||||
"toolbarbutton",
|
||||
"toolbarbutton-dropdown",
|
||||
"toolbargripper",
|
||||
"toolbox",
|
||||
"tooltip",
|
||||
"treeheader",
|
||||
"treeheadercell",
|
||||
"treeheadersortarrow",
|
||||
"treeitem",
|
||||
"treeline",
|
||||
"treetwisty",
|
||||
"treetwistyopen",
|
||||
"treeview",
|
||||
"unset",
|
||||
"window"
|
||||
]
|
||||
},
|
||||
"-webkit-backface-visibility": {
|
||||
"isInherited": false,
|
||||
"subproperties": [
|
||||
|
@ -51,7 +51,6 @@ function onInspect(aState, aResponse)
|
||||
|
||||
let expectedProps = {
|
||||
"addBroadcastListenerFor": { value: { type: "object" } },
|
||||
"commandDispatcher": { get: { type: "object" } },
|
||||
};
|
||||
|
||||
let props = aResponse.ownProperties;
|
||||
|
@ -124,3 +124,5 @@ method console.profileEnd
|
||||
// document.open information
|
||||
custom DocumentOpen calls document.open in a way that creates a new Window object
|
||||
custom DocumentOpenReplace calls document.open in a way that creates a new Window object and replaces the old history entry.
|
||||
|
||||
custom FilteredCrossOriginIFrame cross-origin <iframe> within a CSS/SVG filter
|
||||
|
@ -259,6 +259,7 @@
|
||||
#include "mozilla/dom/MenuBoxObject.h"
|
||||
#include "mozilla/dom/TreeBoxObject.h"
|
||||
#include "nsIXULWindow.h"
|
||||
#include "nsXULCommandDispatcher.h"
|
||||
#include "nsXULPopupManager.h"
|
||||
#include "nsIDocShellTreeOwner.h"
|
||||
#endif
|
||||
@ -1924,6 +1925,7 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INTERNAL(nsDocument)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mApplets);
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mAnchors);
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mAnonymousContents)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mCommandDispatcher)
|
||||
|
||||
// Traverse all our nsCOMArrays.
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mStyleSheets)
|
||||
@ -2014,6 +2016,7 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsDocument)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mOrientationPendingPromise)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mFontFaceSet)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mReadyForIdle);
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mCommandDispatcher)
|
||||
|
||||
tmp->mParentDocument = nullptr;
|
||||
|
||||
@ -10149,6 +10152,20 @@ nsIDocument::MaybeResolveReadyForIdle()
|
||||
}
|
||||
}
|
||||
|
||||
nsIDOMXULCommandDispatcher*
|
||||
nsIDocument::GetCommandDispatcher()
|
||||
{
|
||||
// Only chrome documents are allowed to use command dispatcher.
|
||||
if (!nsContentUtils::IsChromeDoc(this)) {
|
||||
return nullptr;
|
||||
}
|
||||
if (!mCommandDispatcher) {
|
||||
// Create our command dispatcher and hook it up.
|
||||
mCommandDispatcher = new nsXULCommandDispatcher(this);
|
||||
}
|
||||
return mCommandDispatcher;
|
||||
}
|
||||
|
||||
static JSObject*
|
||||
GetScopeObjectOfNode(nsINode* node)
|
||||
{
|
||||
|
@ -6267,8 +6267,8 @@ nsGlobalWindowOuter::UpdateCommands(const nsAString& anAction,
|
||||
}
|
||||
|
||||
nsIDocument* doc = rootWindow->GetExtantDoc();
|
||||
// See if we contain a XUL document.
|
||||
if (!doc || !doc->IsXULDocument()) {
|
||||
|
||||
if (!doc) {
|
||||
return;
|
||||
}
|
||||
// selectionchange action is only used for mozbrowser, not for XUL. So we bypass
|
||||
@ -6276,7 +6276,7 @@ nsGlobalWindowOuter::UpdateCommands(const nsAString& anAction,
|
||||
if (!anAction.EqualsLiteral("selectionchange")) {
|
||||
// Retrieve the command dispatcher and call updateCommands on it.
|
||||
nsIDOMXULCommandDispatcher* xulCommandDispatcher =
|
||||
doc->AsXULDocument()->GetCommandDispatcher();
|
||||
doc->GetCommandDispatcher();
|
||||
if (xulCommandDispatcher) {
|
||||
nsContentUtils::AddScriptRunner(new CommandDispatcher(xulCommandDispatcher,
|
||||
anAction));
|
||||
|
@ -15,6 +15,7 @@
|
||||
#include "nsIApplicationCache.h"
|
||||
#include "nsIApplicationCacheContainer.h"
|
||||
#include "nsIContentViewer.h"
|
||||
#include "nsIDOMXULCommandDispatcher.h"
|
||||
#include "nsIInterfaceRequestor.h"
|
||||
#include "nsILoadContext.h"
|
||||
#include "nsILoadGroup.h" // for member (in nsCOMPtr)
|
||||
@ -3324,6 +3325,7 @@ public:
|
||||
|
||||
mozilla::dom::Promise* GetDocumentReadyForIdle(mozilla::ErrorResult& aRv);
|
||||
|
||||
nsIDOMXULCommandDispatcher* GetCommandDispatcher();
|
||||
already_AddRefed<nsINode> GetPopupNode();
|
||||
void SetPopupNode(nsINode* aNode);
|
||||
nsINode* GetPopupRangeParent(ErrorResult& aRv);
|
||||
@ -4497,6 +4499,8 @@ protected:
|
||||
|
||||
// Count of unload/beforeunload/pagehide operations in progress.
|
||||
uint32_t mIgnoreOpensDuringUnloadCounter;
|
||||
|
||||
nsCOMPtr<nsIDOMXULCommandDispatcher> mCommandDispatcher; // [OWNER] of the focus tracker
|
||||
};
|
||||
|
||||
NS_DEFINE_STATIC_IID_ACCESSOR(nsIDocument, NS_IDOCUMENT_IID)
|
||||
|
@ -81,6 +81,15 @@ static void PrintReqURL(imgIRequest* req) {
|
||||
}
|
||||
#endif /* DEBUG_chb */
|
||||
|
||||
const nsAttrValue::EnumTable nsImageLoadingContent::kDecodingTable[] = {
|
||||
{ "auto", nsImageLoadingContent::ImageDecodingType::Auto },
|
||||
{ "async", nsImageLoadingContent::ImageDecodingType::Async },
|
||||
{ "sync", nsImageLoadingContent::ImageDecodingType::Sync },
|
||||
{ nullptr, 0 }
|
||||
};
|
||||
|
||||
const nsAttrValue::EnumTable* nsImageLoadingContent::kDecodingTableDefault =
|
||||
&nsImageLoadingContent::kDecodingTable[0];
|
||||
|
||||
nsImageLoadingContent::nsImageLoadingContent()
|
||||
: mCurrentRequestFlags(0),
|
||||
@ -99,7 +108,8 @@ nsImageLoadingContent::nsImageLoadingContent()
|
||||
mStateChangerDepth(0),
|
||||
mCurrentRequestRegistered(false),
|
||||
mPendingRequestRegistered(false),
|
||||
mIsStartingImageLoad(false)
|
||||
mIsStartingImageLoad(false),
|
||||
mSyncDecodingHint(false)
|
||||
{
|
||||
if (!nsContentUtils::GetImgLoaderForChannel(nullptr, nullptr)) {
|
||||
mLoadingEnabled = false;
|
||||
@ -335,6 +345,50 @@ nsImageLoadingContent::SetLoadingEnabled(bool aLoadingEnabled)
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
nsImageLoadingContent::SetSyncDecodingHint(bool aHint)
|
||||
{
|
||||
if (mSyncDecodingHint == aHint) {
|
||||
return;
|
||||
}
|
||||
|
||||
mSyncDecodingHint = aHint;
|
||||
MaybeForceSyncDecoding(/* aPrepareNextRequest */ false);
|
||||
}
|
||||
|
||||
void
|
||||
nsImageLoadingContent::MaybeForceSyncDecoding(bool aPrepareNextRequest,
|
||||
nsIFrame* aFrame /* = nullptr */)
|
||||
{
|
||||
nsIFrame* frame = aFrame ? aFrame : GetOurPrimaryFrame();
|
||||
nsImageFrame* imageFrame = do_QueryFrame(frame);
|
||||
nsSVGImageFrame* svgImageFrame = do_QueryFrame(frame);
|
||||
if (!imageFrame && !svgImageFrame) {
|
||||
return;
|
||||
}
|
||||
|
||||
bool forceSync = mSyncDecodingHint;
|
||||
if (!forceSync && aPrepareNextRequest) {
|
||||
// Detect JavaScript-based animations created by changing the |src|
|
||||
// attribute on a timer.
|
||||
TimeStamp now = TimeStamp::Now();
|
||||
TimeDuration threshold =
|
||||
TimeDuration::FromMilliseconds(
|
||||
gfxPrefs::ImageInferSrcAnimationThresholdMS());
|
||||
|
||||
// If the length of time between request changes is less than the threshold,
|
||||
// then force sync decoding to eliminate flicker from the animation.
|
||||
forceSync = (now - mMostRecentRequestChange < threshold);
|
||||
mMostRecentRequestChange = now;
|
||||
}
|
||||
|
||||
if (imageFrame) {
|
||||
imageFrame->SetForceSyncDecoding(forceSync);
|
||||
} else {
|
||||
svgImageFrame->SetForceSyncDecoding(forceSync);
|
||||
}
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsImageLoadingContent::GetImageBlockingStatus(int16_t* aStatus)
|
||||
{
|
||||
@ -629,6 +683,7 @@ nsImageLoadingContent::FrameCreated(nsIFrame* aFrame)
|
||||
{
|
||||
NS_ASSERTION(aFrame, "aFrame is null");
|
||||
|
||||
MaybeForceSyncDecoding(/* aPrepareNextRequest */ false, aFrame);
|
||||
TrackImage(mCurrentRequest, aFrame);
|
||||
TrackImage(mPendingRequest, aFrame);
|
||||
|
||||
@ -1263,27 +1318,7 @@ nsImageLoadingContent::CancelPendingEvent()
|
||||
RefPtr<imgRequestProxy>&
|
||||
nsImageLoadingContent::PrepareNextRequest(ImageLoadType aImageLoadType)
|
||||
{
|
||||
nsImageFrame* imageFrame = do_QueryFrame(GetOurPrimaryFrame());
|
||||
nsSVGImageFrame* svgImageFrame = do_QueryFrame(GetOurPrimaryFrame());
|
||||
if (imageFrame || svgImageFrame) {
|
||||
// Detect JavaScript-based animations created by changing the |src|
|
||||
// attribute on a timer.
|
||||
TimeStamp now = TimeStamp::Now();
|
||||
TimeDuration threshold =
|
||||
TimeDuration::FromMilliseconds(
|
||||
gfxPrefs::ImageInferSrcAnimationThresholdMS());
|
||||
|
||||
// If the length of time between request changes is less than the threshold,
|
||||
// then force sync decoding to eliminate flicker from the animation.
|
||||
bool forceSync = (now - mMostRecentRequestChange < threshold);
|
||||
if (imageFrame) {
|
||||
imageFrame->SetForceSyncDecoding(forceSync);
|
||||
} else {
|
||||
svgImageFrame->SetForceSyncDecoding(forceSync);
|
||||
}
|
||||
|
||||
mMostRecentRequestChange = now;
|
||||
}
|
||||
MaybeForceSyncDecoding(/* aPrepareNextRequest */ true);
|
||||
|
||||
// We only want to cancel the existing current request if size is not
|
||||
// available. bz says the web depends on this behavior.
|
||||
|
@ -24,6 +24,7 @@
|
||||
#include "nsIContentPolicy.h"
|
||||
#include "mozilla/dom/BindingDeclarations.h"
|
||||
#include "mozilla/net/ReferrerPolicy.h"
|
||||
#include "nsAttrValue.h"
|
||||
|
||||
class nsIURI;
|
||||
class nsIDocument;
|
||||
@ -80,6 +81,11 @@ public:
|
||||
|
||||
mozilla::dom::Element* FindImageMap();
|
||||
|
||||
/**
|
||||
* Toggle whether or not to synchronously decode an image on draw.
|
||||
*/
|
||||
void SetSyncDecodingHint(bool aHint);
|
||||
|
||||
protected:
|
||||
enum ImageLoadType {
|
||||
// Most normal image loads
|
||||
@ -228,6 +234,15 @@ protected:
|
||||
// want a non-const nsIContent.
|
||||
virtual nsIContent* AsContent() = 0;
|
||||
|
||||
enum class ImageDecodingType : uint8_t {
|
||||
Auto,
|
||||
Async,
|
||||
Sync,
|
||||
};
|
||||
|
||||
static const nsAttrValue::EnumTable kDecodingTable[];
|
||||
static const nsAttrValue::EnumTable* kDecodingTableDefault;
|
||||
|
||||
private:
|
||||
/**
|
||||
* Struct used to manage the native image observers.
|
||||
@ -443,6 +458,19 @@ private:
|
||||
*/
|
||||
void MakePendingScriptedRequestsCurrent();
|
||||
|
||||
/**
|
||||
* Depending on the configured decoding hint, and/or how recently we updated
|
||||
* the image request, force or stop the frame from decoding the image
|
||||
* synchronously when it is drawn.
|
||||
* @param aPrepareNextRequest True if this is when updating the image request.
|
||||
* @param aFrame If called from FrameCreated the frame passed to FrameCreated.
|
||||
* This is our frame, but at the time of the FrameCreated call
|
||||
* our primary frame pointer hasn't been set yet, so this is
|
||||
* only way to get our frame.
|
||||
*/
|
||||
void MaybeForceSyncDecoding(bool aPrepareNextRequest,
|
||||
nsIFrame* aFrame = nullptr);
|
||||
|
||||
/**
|
||||
* Typically we will have only one observer (our frame in the screen
|
||||
* prescontext), so we want to only make space for one and to
|
||||
@ -522,6 +550,9 @@ private:
|
||||
//
|
||||
// Also we use this variable to check if some evil code is reentering LoadImage.
|
||||
bool mIsStartingImageLoad;
|
||||
|
||||
// If true, force frames to synchronously decode images on draw.
|
||||
bool mSyncDecodingHint;
|
||||
};
|
||||
|
||||
#endif // nsImageLoadingContent_h__
|
||||
|
@ -473,7 +473,7 @@ nsJSUtils::CompileModule(JSContext* aCx,
|
||||
JS::SourceBufferHolder& aSrcBuf,
|
||||
JS::Handle<JSObject*> aEvaluationGlobal,
|
||||
JS::CompileOptions &aCompileOptions,
|
||||
JS::MutableHandle<JSObject*> aModule)
|
||||
JS::MutableHandle<JSScript*> aScript)
|
||||
{
|
||||
AUTO_PROFILER_LABEL("nsJSUtils::CompileModule", JS);
|
||||
|
||||
@ -487,7 +487,7 @@ nsJSUtils::CompileModule(JSContext* aCx,
|
||||
|
||||
NS_ENSURE_TRUE(xpc::Scriptability::Get(aEvaluationGlobal).Allowed(), NS_OK);
|
||||
|
||||
if (!JS::CompileModule(aCx, aCompileOptions, aSrcBuf, aModule)) {
|
||||
if (!JS::CompileModule(aCx, aCompileOptions, aSrcBuf, aScript)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
@ -496,7 +496,7 @@ nsJSUtils::CompileModule(JSContext* aCx,
|
||||
|
||||
nsresult
|
||||
nsJSUtils::InitModuleSourceElement(JSContext* aCx,
|
||||
JS::Handle<JSObject*> aModule,
|
||||
JS::Handle<JSScript*> aScript,
|
||||
nsIScriptElement* aElement)
|
||||
{
|
||||
JS::Rooted<JS::Value> value(aCx);
|
||||
@ -509,8 +509,7 @@ nsJSUtils::InitModuleSourceElement(JSContext* aCx,
|
||||
MOZ_ASSERT(value.isObject());
|
||||
JS::Rooted<JSObject*> object(aCx, &value.toObject());
|
||||
|
||||
JS::Rooted<JSScript*> script(aCx, JS::GetModuleScript(aModule));
|
||||
if (!JS::InitScriptSourceElement(aCx, script, object, nullptr)) {
|
||||
if (!JS::InitScriptSourceElement(aCx, aScript, object, nullptr)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
@ -518,7 +517,7 @@ nsJSUtils::InitModuleSourceElement(JSContext* aCx,
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsJSUtils::ModuleInstantiate(JSContext* aCx, JS::Handle<JSObject*> aModule)
|
||||
nsJSUtils::ModuleInstantiate(JSContext* aCx, JS::Handle<JSScript*> aScript)
|
||||
{
|
||||
AUTO_PROFILER_LABEL("nsJSUtils::ModuleInstantiate", JS);
|
||||
|
||||
@ -527,9 +526,9 @@ nsJSUtils::ModuleInstantiate(JSContext* aCx, JS::Handle<JSObject*> aModule)
|
||||
MOZ_ASSERT(CycleCollectedJSContext::Get() &&
|
||||
CycleCollectedJSContext::Get()->MicroTaskLevel());
|
||||
|
||||
NS_ENSURE_TRUE(xpc::Scriptability::Get(aModule).Allowed(), NS_OK);
|
||||
NS_ENSURE_TRUE(xpc::Scriptability::Get(aScript).Allowed(), NS_OK);
|
||||
|
||||
if (!JS::ModuleInstantiate(aCx, aModule)) {
|
||||
if (!JS::ModuleInstantiate(aCx, aScript)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
@ -537,7 +536,7 @@ nsJSUtils::ModuleInstantiate(JSContext* aCx, JS::Handle<JSObject*> aModule)
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsJSUtils::ModuleEvaluate(JSContext* aCx, JS::Handle<JSObject*> aModule)
|
||||
nsJSUtils::ModuleEvaluate(JSContext* aCx, JS::Handle<JSScript*> aScript)
|
||||
{
|
||||
AUTO_PROFILER_LABEL("nsJSUtils::ModuleEvaluate", JS);
|
||||
|
||||
@ -546,9 +545,9 @@ nsJSUtils::ModuleEvaluate(JSContext* aCx, JS::Handle<JSObject*> aModule)
|
||||
MOZ_ASSERT(CycleCollectedJSContext::Get() &&
|
||||
CycleCollectedJSContext::Get()->MicroTaskLevel());
|
||||
|
||||
NS_ENSURE_TRUE(xpc::Scriptability::Get(aModule).Allowed(), NS_OK);
|
||||
NS_ENSURE_TRUE(xpc::Scriptability::Get(aScript).Allowed(), NS_OK);
|
||||
|
||||
if (!JS::ModuleEvaluate(aCx, aModule)) {
|
||||
if (!JS::ModuleEvaluate(aCx, aScript)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
|
@ -189,17 +189,17 @@ public:
|
||||
JS::SourceBufferHolder& aSrcBuf,
|
||||
JS::Handle<JSObject*> aEvaluationGlobal,
|
||||
JS::CompileOptions &aCompileOptions,
|
||||
JS::MutableHandle<JSObject*> aModule);
|
||||
JS::MutableHandle<JSScript*> aScript);
|
||||
|
||||
static nsresult InitModuleSourceElement(JSContext* aCx,
|
||||
JS::Handle<JSObject*> aModule,
|
||||
JS::Handle<JSScript*> aScript,
|
||||
nsIScriptElement* aElement);
|
||||
|
||||
static nsresult ModuleInstantiate(JSContext* aCx,
|
||||
JS::Handle<JSObject*> aModule);
|
||||
JS::Handle<JSScript*> aScript);
|
||||
|
||||
static nsresult ModuleEvaluate(JSContext* aCx,
|
||||
JS::Handle<JSObject*> aModule);
|
||||
JS::Handle<JSScript*> aScript);
|
||||
|
||||
// Returns false if an exception got thrown on aCx. Passing a null
|
||||
// aElement is allowed; that wil produce an empty aScopeChain.
|
||||
|
@ -1721,7 +1721,9 @@ FindAssociatedGlobal(JSContext* cx, nsIGlobalObject* const& p)
|
||||
|
||||
JSObject* global = p->GetGlobalJSObject();
|
||||
if (!global) {
|
||||
return nullptr;
|
||||
// nsIGlobalObject doesn't have a JS object anymore,
|
||||
// fallback to the current global.
|
||||
return JS::CurrentGlobalOrNull(cx);
|
||||
}
|
||||
|
||||
MOZ_ASSERT(JS_IsGlobalObject(global));
|
||||
|
@ -1860,7 +1860,6 @@ addExternalIface('nsIWebBrowserPersistDocumentReceiver',
|
||||
notflattened=True)
|
||||
addExternalIface('nsIWebProgressListener', nativeType='nsIWebProgressListener',
|
||||
notflattened=True)
|
||||
addExternalIface('nsIScriptableRegion', nativeType='nsIScriptableRegion', notflattened=True)
|
||||
addExternalIface('OutputStream', nativeType='nsIOutputStream',
|
||||
notflattened=True)
|
||||
addExternalIface('Principal', nativeType='nsIPrincipal',
|
||||
|
@ -15,7 +15,8 @@ namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
void
|
||||
TextDecoder::Init(const nsAString& aLabel, const bool aFatal,
|
||||
TextDecoder::Init(const nsAString& aLabel,
|
||||
const TextDecoderOptions& aOptions,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
// Let encoding be the result of getting an encoding from label.
|
||||
@ -28,21 +29,24 @@ TextDecoder::Init(const nsAString& aLabel, const bool aFatal,
|
||||
aRv.ThrowRangeError<MSG_ENCODING_NOT_SUPPORTED>(label);
|
||||
return;
|
||||
}
|
||||
InitWithEncoding(WrapNotNull(encoding), aFatal);
|
||||
InitWithEncoding(WrapNotNull(encoding), aOptions);
|
||||
}
|
||||
|
||||
void
|
||||
TextDecoder::InitWithEncoding(NotNull<const Encoding*> aEncoding,
|
||||
const bool aFatal)
|
||||
const TextDecoderOptions& aOptions)
|
||||
{
|
||||
aEncoding->Name(mEncoding);
|
||||
// If the constructor is called with an options argument,
|
||||
// and the fatal property of the dictionary is set,
|
||||
// set the internal fatal flag of the decoder object.
|
||||
mFatal = aFatal;
|
||||
// Store the flags passed via our options dictionary.
|
||||
mFatal = aOptions.mFatal;
|
||||
mIgnoreBOM = aOptions.mIgnoreBOM;
|
||||
|
||||
// Create a decoder object for mEncoding.
|
||||
mDecoder = aEncoding->NewDecoderWithBOMRemoval();
|
||||
if (mIgnoreBOM) {
|
||||
mDecoder = aEncoding->NewDecoderWithoutBOMHandling();
|
||||
} else {
|
||||
mDecoder = aEncoding->NewDecoderWithBOMRemoval();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -33,7 +33,7 @@ public:
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
nsAutoPtr<TextDecoder> txtDecoder(new TextDecoder());
|
||||
txtDecoder->Init(aEncoding, aOptions.mFatal, aRv);
|
||||
txtDecoder->Init(aEncoding, aOptions, aRv);
|
||||
if (aRv.Failed()) {
|
||||
return nullptr;
|
||||
}
|
||||
@ -42,6 +42,7 @@ public:
|
||||
|
||||
TextDecoder()
|
||||
: mFatal(false)
|
||||
, mIgnoreBOM(false)
|
||||
{
|
||||
MOZ_COUNT_CTOR(TextDecoder);
|
||||
}
|
||||
@ -60,22 +61,21 @@ public:
|
||||
* Validates provided label and throws an exception if invalid label.
|
||||
*
|
||||
* @param aLabel The encoding label (case insensitive) provided.
|
||||
* @param aFatal indicates whether to throw an 'EncodingError'
|
||||
* exception or not when decoding.
|
||||
* @param aOptions The TextDecoderOptions to use.
|
||||
* @return aRv EncodingError exception else null.
|
||||
*/
|
||||
void Init(const nsAString& aLabel, const bool aFatal, ErrorResult& aRv);
|
||||
void Init(const nsAString& aLabel, const TextDecoderOptions& aOptions,
|
||||
ErrorResult& aRv);
|
||||
|
||||
/**
|
||||
* Performs initialization with a Gecko-canonical encoding name (as opposed
|
||||
* to a label.)
|
||||
*
|
||||
* @param aEncoding An Encoding object
|
||||
* @param aFatal indicates whether to throw an 'EncodingError'
|
||||
* exception or not when decoding.
|
||||
* @param aOptions The TextDecoderOptions to use.
|
||||
*/
|
||||
void InitWithEncoding(NotNull<const Encoding*> aEncoding,
|
||||
const bool aFatal);
|
||||
const TextDecoderOptions& aOptions);
|
||||
|
||||
/**
|
||||
* Return the encoding name.
|
||||
@ -114,10 +114,15 @@ public:
|
||||
return mFatal;
|
||||
}
|
||||
|
||||
bool IgnoreBOM() const {
|
||||
return mIgnoreBOM;
|
||||
}
|
||||
|
||||
private:
|
||||
nsCString mEncoding;
|
||||
mozilla::UniquePtr<mozilla::Decoder> mDecoder;
|
||||
bool mFatal;
|
||||
bool mIgnoreBOM;
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
|
@ -2139,29 +2139,9 @@ EventStateManager::DoDefaultDragStart(nsPresContext* aPresContext,
|
||||
action, event, dataTransfer);
|
||||
}
|
||||
else {
|
||||
// if dragging within a XUL tree and no custom drag image was
|
||||
// set, the region argument to InvokeDragSessionWithImage needs
|
||||
// to be set to the area encompassing the selected rows of the
|
||||
// tree to ensure that the drag feedback gets clipped to those
|
||||
// rows. For other content, region should be null.
|
||||
nsCOMPtr<nsIScriptableRegion> region;
|
||||
#ifdef MOZ_XUL
|
||||
if (dragTarget && !dragImage) {
|
||||
if (dragTarget->NodeInfo()->Equals(nsGkAtoms::treechildren,
|
||||
kNameSpaceID_XUL)) {
|
||||
nsTreeBodyFrame* treeBody =
|
||||
do_QueryFrame(dragTarget->GetPrimaryFrame());
|
||||
if (treeBody) {
|
||||
treeBody->GetSelectionRegion(getter_AddRefs(region));
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
dragService->InvokeDragSessionWithImage(dragTarget,
|
||||
aPrincipalURISpec, transArray,
|
||||
region, action,
|
||||
dragImage,
|
||||
action, dragImage,
|
||||
imageX, imageY, event,
|
||||
dataTransfer);
|
||||
}
|
||||
|
@ -222,6 +222,12 @@ HTMLImageElement::Y()
|
||||
return GetXY().y;
|
||||
}
|
||||
|
||||
void
|
||||
HTMLImageElement::GetDecoding(nsAString& aValue)
|
||||
{
|
||||
GetEnumAttr(nsGkAtoms::decoding, kDecodingTableDefault->tag, aValue);
|
||||
}
|
||||
|
||||
bool
|
||||
HTMLImageElement::ParseAttribute(int32_t aNamespaceID,
|
||||
nsAtom* aAttribute,
|
||||
@ -237,6 +243,10 @@ HTMLImageElement::ParseAttribute(int32_t aNamespaceID,
|
||||
ParseCORSValue(aValue, aResult);
|
||||
return true;
|
||||
}
|
||||
if (aAttribute == nsGkAtoms::decoding) {
|
||||
return aResult.ParseEnumValue(aValue, kDecodingTable, false,
|
||||
kDecodingTableDefault);
|
||||
}
|
||||
if (ParseImageAttribute(aAttribute, aValue, aResult)) {
|
||||
return true;
|
||||
}
|
||||
@ -378,6 +388,12 @@ HTMLImageElement::AfterSetAttr(int32_t aNameSpaceID, nsAtom* aName,
|
||||
mUseUrgentStartForChannel = EventStateManager::IsHandlingUserInput();
|
||||
|
||||
PictureSourceSizesChanged(this, attrVal.String(), aNotify);
|
||||
} else if (aName == nsGkAtoms::decoding &&
|
||||
aNameSpaceID == kNameSpaceID_None) {
|
||||
// Request sync or async image decoding.
|
||||
SetSyncDecodingHint(aValue &&
|
||||
static_cast<ImageDecodingType>(aValue->GetEnumValue()) ==
|
||||
ImageDecodingType::Sync);
|
||||
}
|
||||
|
||||
return nsGenericHTMLElement::AfterSetAttr(aNameSpaceID, aName,
|
||||
|
@ -232,6 +232,11 @@ public:
|
||||
{
|
||||
GetEnumAttr(nsGkAtoms::referrerpolicy, EmptyCString().get(), aReferrer);
|
||||
}
|
||||
void SetDecoding(const nsAString& aDecoding, ErrorResult& aError)
|
||||
{
|
||||
SetHTMLAttr(nsGkAtoms::decoding, aDecoding, aError);
|
||||
}
|
||||
void GetDecoding(nsAString& aValue);
|
||||
|
||||
net::ReferrerPolicy
|
||||
GetImageReferrerPolicy() override
|
||||
|
@ -675,22 +675,19 @@ DeserializeStructuredCloneFiles(
|
||||
break;
|
||||
}
|
||||
|
||||
case StructuredCloneFile::eWasmBytecode:
|
||||
case StructuredCloneFile::eWasmCompiled: {
|
||||
case StructuredCloneFile::eWasmBytecode: {
|
||||
if (aModuleSet) {
|
||||
MOZ_ASSERT(blobOrMutableFile.type() == BlobOrMutableFile::Tnull_t);
|
||||
|
||||
StructuredCloneFile* file = aFiles.AppendElement();
|
||||
MOZ_ASSERT(file);
|
||||
|
||||
file->mType = serializedFile.type();
|
||||
file->mType = StructuredCloneFile::eWasmBytecode;
|
||||
|
||||
MOZ_ASSERT(moduleIndex < aModuleSet->Length());
|
||||
file->mWasmModule = aModuleSet->ElementAt(moduleIndex);
|
||||
|
||||
if (serializedFile.type() == StructuredCloneFile::eWasmCompiled) {
|
||||
moduleIndex++;
|
||||
}
|
||||
moduleIndex++;
|
||||
|
||||
break;
|
||||
}
|
||||
@ -707,12 +704,21 @@ DeserializeStructuredCloneFiles(
|
||||
StructuredCloneFile* file = aFiles.AppendElement();
|
||||
MOZ_ASSERT(file);
|
||||
|
||||
file->mType = serializedFile.type();
|
||||
file->mType = StructuredCloneFile::eWasmBytecode;
|
||||
file->mBlob.swap(blob);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case StructuredCloneFile::eWasmCompiled: {
|
||||
StructuredCloneFile* file = aFiles.AppendElement();
|
||||
MOZ_ASSERT(file);
|
||||
|
||||
file->mType = StructuredCloneFile::eWasmCompiled;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
MOZ_CRASH("Should never get here!");
|
||||
}
|
||||
@ -1481,17 +1487,13 @@ class BackgroundRequestChild::PreprocessHelper final
|
||||
, public nsIInputStreamCallback
|
||||
, public nsIFileMetadataCallback
|
||||
{
|
||||
typedef std::pair<nsCOMPtr<nsIInputStream>,
|
||||
nsCOMPtr<nsIInputStream>> StreamPair;
|
||||
|
||||
nsCOMPtr<nsIEventTarget> mOwningEventTarget;
|
||||
nsTArray<StreamPair> mStreamPairs;
|
||||
nsTArray<nsCOMPtr<nsIInputStream>> mStreams;
|
||||
nsTArray<RefPtr<JS::WasmModule>> mModuleSet;
|
||||
BackgroundRequestChild* mActor;
|
||||
|
||||
// These 2 are populated when the processing of the stream pairs runs.
|
||||
// This is populated when the processing of the stream runs.
|
||||
PRFileDesc* mCurrentBytecodeFileDesc;
|
||||
PRFileDesc* mCurrentCompiledFileDesc;
|
||||
|
||||
RefPtr<TaskQueue> mTaskQueue;
|
||||
nsCOMPtr<nsIEventTarget> mTaskQueueEventTarget;
|
||||
@ -1505,7 +1507,6 @@ public:
|
||||
, mOwningEventTarget(aActor->GetActorEventTarget())
|
||||
, mActor(aActor)
|
||||
, mCurrentBytecodeFileDesc(nullptr)
|
||||
, mCurrentCompiledFileDesc(nullptr)
|
||||
, mModuleSetIndex(aModuleSetIndex)
|
||||
, mResultCode(NS_OK)
|
||||
{
|
||||
@ -1555,7 +1556,7 @@ private:
|
||||
RunOnOwningThread();
|
||||
|
||||
void
|
||||
ProcessCurrentStreamPair();
|
||||
ProcessCurrentStream();
|
||||
|
||||
nsresult
|
||||
WaitForStreamReady(nsIInputStream* aInputStream);
|
||||
@ -3387,26 +3388,12 @@ PreprocessHelper::Init(const nsTArray<StructuredCloneFile>& aFiles)
|
||||
AssertIsOnOwningThread();
|
||||
MOZ_ASSERT(!aFiles.IsEmpty());
|
||||
|
||||
uint32_t count = aFiles.Length();
|
||||
|
||||
// We should receive even number of files.
|
||||
MOZ_ASSERT(count % 2 == 0);
|
||||
|
||||
// Let's process it as pairs.
|
||||
count = count / 2;
|
||||
|
||||
nsTArray<StreamPair> streamPairs;
|
||||
for (uint32_t index = 0; index < count; index++) {
|
||||
uint32_t bytecodeIndex = index * 2;
|
||||
uint32_t compiledIndex = bytecodeIndex + 1;
|
||||
|
||||
const StructuredCloneFile& bytecodeFile = aFiles[bytecodeIndex];
|
||||
const StructuredCloneFile& compiledFile = aFiles[compiledIndex];
|
||||
nsTArray<nsCOMPtr<nsIInputStream>> streams;
|
||||
for (uint32_t index = 0; index < aFiles.Length(); index++) {
|
||||
const StructuredCloneFile& bytecodeFile = aFiles[index];
|
||||
|
||||
MOZ_ASSERT(bytecodeFile.mType == StructuredCloneFile::eWasmBytecode);
|
||||
MOZ_ASSERT(bytecodeFile.mBlob);
|
||||
MOZ_ASSERT(compiledFile.mType == StructuredCloneFile::eWasmCompiled);
|
||||
MOZ_ASSERT(compiledFile.mBlob);
|
||||
|
||||
ErrorResult errorResult;
|
||||
|
||||
@ -3417,17 +3404,10 @@ PreprocessHelper::Init(const nsTArray<StructuredCloneFile>& aFiles)
|
||||
return errorResult.StealNSResult();
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIInputStream> compiledStream;
|
||||
compiledFile.mBlob->CreateInputStream(getter_AddRefs(compiledStream),
|
||||
errorResult);
|
||||
if (NS_WARN_IF(errorResult.Failed())) {
|
||||
return errorResult.StealNSResult();
|
||||
}
|
||||
|
||||
streamPairs.AppendElement(StreamPair(bytecodeStream, compiledStream));
|
||||
streams.AppendElement(bytecodeStream);
|
||||
}
|
||||
|
||||
mStreamPairs = std::move(streamPairs);
|
||||
mStreams = std::move(streams);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
@ -3480,23 +3460,19 @@ PreprocessHelper::RunOnOwningThread()
|
||||
|
||||
void
|
||||
BackgroundRequestChild::
|
||||
PreprocessHelper::ProcessCurrentStreamPair()
|
||||
PreprocessHelper::ProcessCurrentStream()
|
||||
{
|
||||
MOZ_ASSERT(!IsOnOwningThread());
|
||||
MOZ_ASSERT(!mStreamPairs.IsEmpty());
|
||||
|
||||
nsresult rv;
|
||||
|
||||
const StreamPair& streamPair = mStreamPairs[0];
|
||||
MOZ_ASSERT(!mStreams.IsEmpty());
|
||||
|
||||
// We still don't have the current bytecode FileDesc.
|
||||
if (!mCurrentBytecodeFileDesc) {
|
||||
const nsCOMPtr<nsIInputStream>& bytecodeStream = streamPair.first;
|
||||
const nsCOMPtr<nsIInputStream>& bytecodeStream = mStreams[0];
|
||||
MOZ_ASSERT(bytecodeStream);
|
||||
|
||||
mCurrentBytecodeFileDesc = GetFileDescriptorFromStream(bytecodeStream);
|
||||
if (!mCurrentBytecodeFileDesc) {
|
||||
rv = WaitForStreamReady(bytecodeStream);
|
||||
nsresult rv = WaitForStreamReady(bytecodeStream);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
ContinueWithStatus(rv);
|
||||
}
|
||||
@ -3504,21 +3480,7 @@ PreprocessHelper::ProcessCurrentStreamPair()
|
||||
}
|
||||
}
|
||||
|
||||
if (!mCurrentCompiledFileDesc) {
|
||||
const nsCOMPtr<nsIInputStream>& compiledStream = streamPair.second;
|
||||
MOZ_ASSERT(compiledStream);
|
||||
|
||||
mCurrentCompiledFileDesc = GetFileDescriptorFromStream(compiledStream);
|
||||
if (!mCurrentCompiledFileDesc) {
|
||||
rv = WaitForStreamReady(compiledStream);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
ContinueWithStatus(rv);
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
MOZ_ASSERT(mCurrentBytecodeFileDesc && mCurrentCompiledFileDesc);
|
||||
MOZ_ASSERT(mCurrentBytecodeFileDesc);
|
||||
|
||||
JS::BuildIdCharVector buildId;
|
||||
bool ok = GetBuildId(&buildId);
|
||||
@ -3529,7 +3491,6 @@ PreprocessHelper::ProcessCurrentStreamPair()
|
||||
|
||||
RefPtr<JS::WasmModule> module =
|
||||
JS::DeserializeWasmModule(mCurrentBytecodeFileDesc,
|
||||
mCurrentCompiledFileDesc,
|
||||
std::move(buildId),
|
||||
nullptr,
|
||||
0);
|
||||
@ -3539,7 +3500,7 @@ PreprocessHelper::ProcessCurrentStreamPair()
|
||||
}
|
||||
|
||||
mModuleSet.AppendElement(module);
|
||||
mStreamPairs.RemoveElementAt(0);
|
||||
mStreams.RemoveElementAt(0);
|
||||
|
||||
ContinueWithStatus(NS_OK);
|
||||
}
|
||||
@ -3584,18 +3545,17 @@ PreprocessHelper::ContinueWithStatus(nsresult aStatus)
|
||||
|
||||
// Let's reset the value for the next operation.
|
||||
mCurrentBytecodeFileDesc = nullptr;
|
||||
mCurrentCompiledFileDesc = nullptr;
|
||||
|
||||
nsCOMPtr<nsIEventTarget> eventTarget;
|
||||
|
||||
if (NS_WARN_IF(NS_FAILED(aStatus))) {
|
||||
// If the previous operation failed, we don't continue the processing of the
|
||||
// other stream pairs.
|
||||
// other streams.
|
||||
MOZ_ASSERT(mResultCode == NS_OK);
|
||||
mResultCode = aStatus;
|
||||
|
||||
eventTarget = mOwningEventTarget;
|
||||
} else if (mStreamPairs.IsEmpty()) {
|
||||
} else if (mStreams.IsEmpty()) {
|
||||
// If all the streams have been processed, we can go back to the owning
|
||||
// thread.
|
||||
eventTarget = mOwningEventTarget;
|
||||
@ -3619,7 +3579,7 @@ PreprocessHelper::Run()
|
||||
if (IsOnOwningThread()) {
|
||||
RunOnOwningThread();
|
||||
} else {
|
||||
ProcessCurrentStreamPair();
|
||||
ProcessCurrentStream();
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
@ -3648,7 +3608,7 @@ PreprocessHelper::DataIsReady(nsIInputStream* aStream)
|
||||
{
|
||||
MOZ_ASSERT(!IsOnOwningThread());
|
||||
MOZ_ASSERT(aStream);
|
||||
MOZ_ASSERT(!mStreamPairs.IsEmpty());
|
||||
MOZ_ASSERT(!mStreams.IsEmpty());
|
||||
|
||||
// We still don't have the current bytecode FileDesc.
|
||||
if (!mCurrentBytecodeFileDesc) {
|
||||
@ -3658,20 +3618,8 @@ PreprocessHelper::DataIsReady(nsIInputStream* aStream)
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Let's continue with the processing of the current pair.
|
||||
ProcessCurrentStreamPair();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
if (!mCurrentCompiledFileDesc) {
|
||||
mCurrentCompiledFileDesc = GetFileDescriptorFromStream(aStream);
|
||||
if (!mCurrentCompiledFileDesc) {
|
||||
ContinueWithStatus(NS_ERROR_FAILURE);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Let's continue with the processing of the current pair.
|
||||
ProcessCurrentStreamPair();
|
||||
// Let's continue with the processing of the current stream.
|
||||
ProcessCurrentStream();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -9633,9 +9633,6 @@ public:
|
||||
already_AddRefed<nsIFile>
|
||||
GetFile(FileInfo* aFileInfo);
|
||||
|
||||
already_AddRefed<nsIFile>
|
||||
GetCheckedFile(FileInfo* aFileInfo);
|
||||
|
||||
already_AddRefed<nsIFile>
|
||||
GetJournalFile(FileInfo* aFileInfo);
|
||||
|
||||
@ -9645,18 +9642,10 @@ public:
|
||||
nsIInputStream* aInputStream,
|
||||
bool aCompress);
|
||||
|
||||
nsresult
|
||||
ReplaceFile(nsIFile* aFile,
|
||||
nsIFile* aNewFile,
|
||||
nsIFile* aNewJournalFile);
|
||||
|
||||
nsresult
|
||||
RemoveFile(nsIFile* aFile,
|
||||
nsIFile* aJournalFile);
|
||||
|
||||
already_AddRefed<FileInfo>
|
||||
GetNewFileInfo();
|
||||
|
||||
private:
|
||||
nsresult
|
||||
SyncCopy(nsIInputStream* aInputStream,
|
||||
@ -9735,136 +9724,6 @@ DeserializeStructuredCloneFile(FileManager* aFileManager,
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
CheckWasmModule(FileHelper* aFileHelper,
|
||||
StructuredCloneFile* aBytecodeFile,
|
||||
StructuredCloneFile* aCompiledFile)
|
||||
{
|
||||
MOZ_ASSERT(!IsOnBackgroundThread());
|
||||
MOZ_ASSERT(aFileHelper);
|
||||
MOZ_ASSERT(aBytecodeFile);
|
||||
MOZ_ASSERT(aCompiledFile);
|
||||
MOZ_ASSERT(aBytecodeFile->mType == StructuredCloneFile::eWasmBytecode);
|
||||
MOZ_ASSERT(aCompiledFile->mType == StructuredCloneFile::eWasmCompiled);
|
||||
|
||||
nsCOMPtr<nsIFile> compiledFile =
|
||||
aFileHelper->GetCheckedFile(aCompiledFile->mFileInfo);
|
||||
if (NS_WARN_IF(!compiledFile)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
nsresult rv;
|
||||
|
||||
bool match;
|
||||
{
|
||||
ScopedPRFileDesc compiledFileDesc;
|
||||
rv = compiledFile->OpenNSPRFileDesc(PR_RDONLY,
|
||||
0644,
|
||||
&compiledFileDesc.rwget());
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
JS::BuildIdCharVector buildId;
|
||||
bool ok = GetBuildId(&buildId);
|
||||
if (NS_WARN_IF(!ok)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
match = JS::CompiledWasmModuleAssumptionsMatch(compiledFileDesc,
|
||||
std::move(buildId));
|
||||
}
|
||||
if (match) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Re-compile the module. It would be preferable to do this in the child
|
||||
// (content process) instead of here in the parent, but that would be way more
|
||||
// complex and without significant memory allocation or security benefits.
|
||||
// See the discussion starting from
|
||||
// https://bugzilla.mozilla.org/show_bug.cgi?id=1312808#c9 for more details.
|
||||
nsCOMPtr<nsIFile> bytecodeFile =
|
||||
aFileHelper->GetCheckedFile(aBytecodeFile->mFileInfo);
|
||||
if (NS_WARN_IF(!bytecodeFile)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
ScopedPRFileDesc bytecodeFileDesc;
|
||||
rv = bytecodeFile->OpenNSPRFileDesc(PR_RDONLY,
|
||||
0644,
|
||||
&bytecodeFileDesc.rwget());
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
JS::BuildIdCharVector buildId;
|
||||
bool ok = GetBuildId(&buildId);
|
||||
if (NS_WARN_IF(!ok)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
RefPtr<JS::WasmModule> module = JS::DeserializeWasmModule(bytecodeFileDesc,
|
||||
nullptr,
|
||||
std::move(buildId),
|
||||
nullptr,
|
||||
0);
|
||||
if (NS_WARN_IF(!module)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
size_t compiledSize = module->compiledSerializedSize();
|
||||
UniquePtr<uint8_t[]> compiled(new (fallible) uint8_t[compiledSize]);
|
||||
if (NS_WARN_IF(!compiled)) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
module->compiledSerialize(compiled.get(), compiledSize);
|
||||
|
||||
nsCOMPtr<nsIInputStream> inputStream;
|
||||
rv = NS_NewByteInputStream(getter_AddRefs(inputStream),
|
||||
reinterpret_cast<const char*>(compiled.get()),
|
||||
compiledSize);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
RefPtr<FileInfo> newFileInfo = aFileHelper->GetNewFileInfo();
|
||||
|
||||
nsCOMPtr<nsIFile> newFile = aFileHelper->GetFile(newFileInfo);
|
||||
if (NS_WARN_IF(!newFile)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIFile> newJournalFile =
|
||||
aFileHelper->GetJournalFile(newFileInfo);
|
||||
if (NS_WARN_IF(!newJournalFile)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
rv = aFileHelper->CreateFileFromStream(newFile,
|
||||
newJournalFile,
|
||||
inputStream,
|
||||
/* aCompress */ false);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
nsresult rv2 = aFileHelper->RemoveFile(newFile, newJournalFile);
|
||||
if (NS_WARN_IF(NS_FAILED(rv2))) {
|
||||
return rv;
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
rv = aFileHelper->ReplaceFile(compiledFile, newFile, newJournalFile);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
nsresult rv2 = aFileHelper->RemoveFile(newFile, newJournalFile);
|
||||
if (NS_WARN_IF(NS_FAILED(rv2))) {
|
||||
return rv;
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
DeserializeStructuredCloneFiles(FileManager* aFileManager,
|
||||
const nsAString& aText,
|
||||
@ -9878,7 +9737,6 @@ DeserializeStructuredCloneFiles(FileManager* aFileManager,
|
||||
|
||||
nsAutoString token;
|
||||
nsresult rv;
|
||||
Maybe<FileHelper> fileHelper;
|
||||
|
||||
while (tokenizer.hasMoreTokens()) {
|
||||
token = tokenizer.nextToken();
|
||||
@ -9898,26 +9756,10 @@ DeserializeStructuredCloneFiles(FileManager* aFileManager,
|
||||
*aHasPreprocessInfo = true;
|
||||
}
|
||||
else if (file->mType == StructuredCloneFile::eWasmCompiled) {
|
||||
if (fileHelper.isNothing()) {
|
||||
fileHelper.emplace(aFileManager);
|
||||
|
||||
rv = fileHelper->Init();
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
|
||||
MOZ_ASSERT(aResult.Length() > 1);
|
||||
MOZ_ASSERT(aResult[aResult.Length() - 2].mType ==
|
||||
StructuredCloneFile::eWasmBytecode);
|
||||
|
||||
StructuredCloneFile* previousFile = &aResult[aResult.Length() - 2];
|
||||
|
||||
rv = CheckWasmModule(fileHelper.ptr(), previousFile, file);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
*aHasPreprocessInfo = true;
|
||||
}
|
||||
}
|
||||
@ -9978,9 +9820,7 @@ SerializeStructuredCloneFiles(
|
||||
for (uint32_t index = 0; index < count; index++) {
|
||||
const StructuredCloneFile& file = aFiles[index];
|
||||
|
||||
if (aForPreprocess &&
|
||||
file.mType != StructuredCloneFile::eWasmBytecode &&
|
||||
file.mType != StructuredCloneFile::eWasmCompiled) {
|
||||
if (aForPreprocess && file.mType != StructuredCloneFile::eWasmBytecode) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -10064,15 +9904,14 @@ SerializeStructuredCloneFiles(
|
||||
break;
|
||||
}
|
||||
|
||||
case StructuredCloneFile::eWasmBytecode:
|
||||
case StructuredCloneFile::eWasmCompiled: {
|
||||
case StructuredCloneFile::eWasmBytecode: {
|
||||
if (!aForPreprocess) {
|
||||
SerializedStructuredCloneFile* serializedFile =
|
||||
aResult.AppendElement(fallible);
|
||||
MOZ_ASSERT(serializedFile);
|
||||
|
||||
serializedFile->file() = null_t();
|
||||
serializedFile->type() = file.mType;
|
||||
serializedFile->type() = StructuredCloneFile::eWasmBytecode;
|
||||
} else {
|
||||
RefPtr<FileBlobImpl> impl = new FileBlobImpl(nativeFile);
|
||||
impl->SetFileId(file.mFileInfo->Id());
|
||||
@ -10091,7 +9930,7 @@ SerializeStructuredCloneFiles(
|
||||
MOZ_ASSERT(serializedFile);
|
||||
|
||||
serializedFile->file() = ipcBlob;
|
||||
serializedFile->type() = file.mType;
|
||||
serializedFile->type() = StructuredCloneFile::eWasmBytecode;
|
||||
|
||||
aDatabase->MapBlob(ipcBlob, file.mFileInfo);
|
||||
}
|
||||
@ -10099,6 +9938,16 @@ SerializeStructuredCloneFiles(
|
||||
break;
|
||||
}
|
||||
|
||||
case StructuredCloneFile::eWasmCompiled: {
|
||||
SerializedStructuredCloneFile* serializedFile =
|
||||
aResult.AppendElement(fallible);
|
||||
MOZ_ASSERT(serializedFile);
|
||||
|
||||
serializedFile->file() = null_t();
|
||||
serializedFile->type() = StructuredCloneFile::eWasmCompiled;
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
MOZ_CRASH("Should never get here!");
|
||||
}
|
||||
@ -29137,22 +28986,6 @@ FileHelper::GetFile(FileInfo* aFileInfo)
|
||||
return file.forget();
|
||||
}
|
||||
|
||||
already_AddRefed<nsIFile>
|
||||
FileHelper::GetCheckedFile(FileInfo* aFileInfo)
|
||||
{
|
||||
MOZ_ASSERT(!IsOnBackgroundThread());
|
||||
MOZ_ASSERT(aFileInfo);
|
||||
MOZ_ASSERT(mFileManager);
|
||||
MOZ_ASSERT(mFileDirectory);
|
||||
|
||||
const int64_t fileId = aFileInfo->Id();
|
||||
MOZ_ASSERT(fileId > 0);
|
||||
|
||||
nsCOMPtr<nsIFile> file =
|
||||
mFileManager->GetCheckedFileForId(mFileDirectory, fileId);
|
||||
return file.forget();
|
||||
}
|
||||
|
||||
already_AddRefed<nsIFile>
|
||||
FileHelper::GetJournalFile(FileInfo* aFileInfo)
|
||||
{
|
||||
@ -29279,59 +29112,6 @@ FileHelper::CreateFileFromStream(nsIFile* aFile,
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
FileHelper::ReplaceFile(nsIFile* aFile,
|
||||
nsIFile* aNewFile,
|
||||
nsIFile* aNewJournalFile)
|
||||
{
|
||||
MOZ_ASSERT(!IsOnBackgroundThread());
|
||||
MOZ_ASSERT(aFile);
|
||||
MOZ_ASSERT(aNewFile);
|
||||
MOZ_ASSERT(aNewJournalFile);
|
||||
MOZ_ASSERT(mFileManager);
|
||||
MOZ_ASSERT(mFileDirectory);
|
||||
MOZ_ASSERT(mJournalDirectory);
|
||||
|
||||
nsresult rv;
|
||||
|
||||
int64_t fileSize;
|
||||
|
||||
if (mFileManager->EnforcingQuota()) {
|
||||
rv = aFile->GetFileSize(&fileSize);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
|
||||
nsAutoString fileName;
|
||||
rv = aFile->GetLeafName(fileName);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
rv = aNewFile->RenameTo(nullptr, fileName);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
if (mFileManager->EnforcingQuota()) {
|
||||
QuotaManager* quotaManager = QuotaManager::Get();
|
||||
MOZ_ASSERT(quotaManager);
|
||||
|
||||
quotaManager->DecreaseUsageForOrigin(mFileManager->Type(),
|
||||
mFileManager->Group(),
|
||||
mFileManager->Origin(),
|
||||
fileSize);
|
||||
}
|
||||
|
||||
rv = aNewJournalFile->Remove(false);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
FileHelper::RemoveFile(nsIFile* aFile,
|
||||
nsIFile* aJournalFile)
|
||||
@ -29370,14 +29150,6 @@ FileHelper::RemoveFile(nsIFile* aFile,
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
already_AddRefed<FileInfo>
|
||||
FileHelper::GetNewFileInfo()
|
||||
{
|
||||
MOZ_ASSERT(mFileManager);
|
||||
|
||||
return mFileManager->GetNewFileInfo();
|
||||
}
|
||||
|
||||
class FileHelper::ReadCallback final : public nsIInputStreamCallback
|
||||
{
|
||||
public:
|
||||
|
@ -209,288 +209,6 @@ GenerateRequest(JSContext* aCx, IDBObjectStore* aObjectStore)
|
||||
return request.forget();
|
||||
}
|
||||
|
||||
// Blob internal code clones this stream before it's passed to IPC, so we
|
||||
// serialize module's optimized code only when AsyncWait() is called.
|
||||
class WasmCompiledModuleStream final
|
||||
: public nsIAsyncInputStream
|
||||
, public nsICloneableInputStream
|
||||
, private JS::WasmModuleListener
|
||||
{
|
||||
nsCOMPtr<nsISerialEventTarget> mOwningThread;
|
||||
|
||||
// Initially and while waiting for compilation to complete, the mModule field
|
||||
// is non-null, keeping alive the module whose code needs to be serialized.
|
||||
RefPtr<JS::WasmModule> mModule;
|
||||
|
||||
// A module stream can have up to one input stream callback.
|
||||
nsCOMPtr<nsIInputStreamCallback> mCallback;
|
||||
|
||||
// When a module's optimized code is ready to be serialized, it will be
|
||||
// serialized into mStream and the mModule will be released. At this point,
|
||||
// stream reads will succeed.
|
||||
nsCOMPtr<nsIInputStream> mStream;
|
||||
|
||||
// When the stream is finished reading or closed, mStatus will be changed from
|
||||
// NS_OK to NS_BASE_STREAM_CLOSED or whatever status was passed to
|
||||
// CloseWithStatus.
|
||||
nsresult mStatus;
|
||||
|
||||
public:
|
||||
explicit WasmCompiledModuleStream(JS::WasmModule* aModule)
|
||||
: mOwningThread(GetCurrentThreadSerialEventTarget())
|
||||
, mModule(aModule)
|
||||
, mStatus(NS_OK)
|
||||
{
|
||||
AssertIsOnOwningThread();
|
||||
MOZ_ASSERT(aModule);
|
||||
}
|
||||
|
||||
bool
|
||||
IsOnOwningThread() const
|
||||
{
|
||||
MOZ_ASSERT(mOwningThread);
|
||||
|
||||
bool current;
|
||||
return NS_SUCCEEDED(mOwningThread->IsOnCurrentThread(¤t)) && current;
|
||||
}
|
||||
|
||||
void
|
||||
AssertIsOnOwningThread() const
|
||||
{
|
||||
MOZ_ASSERT(IsOnOwningThread());
|
||||
}
|
||||
|
||||
private:
|
||||
// Copy constructor for cloning.
|
||||
explicit WasmCompiledModuleStream(const WasmCompiledModuleStream& aOther)
|
||||
: mOwningThread(aOther.mOwningThread)
|
||||
, mModule(aOther.mModule)
|
||||
, mStatus(aOther.mStatus)
|
||||
{
|
||||
AssertIsOnOwningThread();
|
||||
|
||||
if (aOther.mStream) {
|
||||
nsCOMPtr<nsICloneableInputStream> cloneableStream =
|
||||
do_QueryInterface(aOther.mStream);
|
||||
MOZ_ASSERT(cloneableStream);
|
||||
|
||||
MOZ_ALWAYS_SUCCEEDS(cloneableStream->Clone(getter_AddRefs(mStream)));
|
||||
}
|
||||
}
|
||||
|
||||
~WasmCompiledModuleStream() override
|
||||
{
|
||||
AssertIsOnOwningThread();
|
||||
|
||||
MOZ_ALWAYS_SUCCEEDS(Close());
|
||||
}
|
||||
|
||||
void
|
||||
CallCallback()
|
||||
{
|
||||
AssertIsOnOwningThread();
|
||||
MOZ_ASSERT(mCallback);
|
||||
|
||||
nsCOMPtr<nsIInputStreamCallback> callback;
|
||||
callback.swap(mCallback);
|
||||
|
||||
callback->OnInputStreamReady(this);
|
||||
}
|
||||
|
||||
NS_DECL_THREADSAFE_ISUPPORTS
|
||||
|
||||
// nsIInputStream:
|
||||
|
||||
NS_IMETHOD
|
||||
Close() override
|
||||
{
|
||||
AssertIsOnOwningThread();
|
||||
|
||||
return CloseWithStatus(NS_BASE_STREAM_CLOSED);
|
||||
}
|
||||
|
||||
NS_IMETHOD
|
||||
Available(uint64_t* _retval) override
|
||||
{
|
||||
AssertIsOnOwningThread();
|
||||
|
||||
if (NS_FAILED(mStatus)) {
|
||||
return mStatus;
|
||||
}
|
||||
|
||||
if (!mStream) {
|
||||
*_retval = 0;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
return mStream->Available(_retval);
|
||||
}
|
||||
|
||||
NS_IMETHOD
|
||||
Read(char* aBuf, uint32_t aCount, uint32_t* _retval) override
|
||||
{
|
||||
AssertIsOnOwningThread();
|
||||
|
||||
return ReadSegments(NS_CopySegmentToBuffer, aBuf, aCount, _retval);
|
||||
}
|
||||
|
||||
NS_IMETHOD
|
||||
ReadSegments(nsWriteSegmentFun aWriter,
|
||||
void* aClosure,
|
||||
uint32_t aCount,
|
||||
uint32_t* _retval) override
|
||||
{
|
||||
AssertIsOnOwningThread();
|
||||
|
||||
if (NS_FAILED(mStatus)) {
|
||||
*_retval = 0;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
if (!mStream) {
|
||||
return NS_BASE_STREAM_WOULD_BLOCK;
|
||||
}
|
||||
|
||||
return mStream->ReadSegments(aWriter, aClosure, aCount, _retval);
|
||||
}
|
||||
|
||||
NS_IMETHOD
|
||||
IsNonBlocking(bool* _retval) override
|
||||
{
|
||||
AssertIsOnOwningThread();
|
||||
|
||||
*_retval = true;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// nsIAsyncInputStream:
|
||||
|
||||
NS_IMETHOD
|
||||
CloseWithStatus(nsresult aStatus) override
|
||||
{
|
||||
AssertIsOnOwningThread();
|
||||
|
||||
if (NS_FAILED(mStatus)) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
mModule = nullptr;
|
||||
|
||||
if (mStream) {
|
||||
MOZ_ALWAYS_SUCCEEDS(mStream->Close());
|
||||
mStream = nullptr;
|
||||
}
|
||||
|
||||
mStatus = NS_FAILED(aStatus) ? aStatus : NS_BASE_STREAM_CLOSED;
|
||||
|
||||
if (mCallback) {
|
||||
CallCallback();
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHOD
|
||||
AsyncWait(nsIInputStreamCallback* aCallback,
|
||||
uint32_t aFlags,
|
||||
uint32_t aRequestedCount,
|
||||
nsIEventTarget* aEventTarget) override
|
||||
{
|
||||
AssertIsOnOwningThread();
|
||||
MOZ_ASSERT_IF(mCallback, !aCallback);
|
||||
|
||||
if (aFlags) {
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
if (!aCallback) {
|
||||
mCallback = nullptr;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
if (aEventTarget) {
|
||||
mCallback =
|
||||
NS_NewInputStreamReadyEvent("WasmCompiledModuleStream::AsyncWait",
|
||||
aCallback,
|
||||
aEventTarget);
|
||||
} else {
|
||||
mCallback = aCallback;
|
||||
}
|
||||
|
||||
if (NS_FAILED(mStatus) || mStream) {
|
||||
CallCallback();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(mModule);
|
||||
mModule->notifyWhenCompilationComplete(this);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// nsICloneableInputStream:
|
||||
|
||||
NS_IMETHOD
|
||||
GetCloneable(bool* aCloneable) override
|
||||
{
|
||||
AssertIsOnOwningThread();
|
||||
|
||||
*aCloneable = true;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHOD
|
||||
Clone(nsIInputStream** _retval) override
|
||||
{
|
||||
AssertIsOnOwningThread();
|
||||
|
||||
nsCOMPtr<nsIInputStream> clone = new WasmCompiledModuleStream(*this);
|
||||
|
||||
clone.forget(_retval);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// JS::WasmModuleListener:
|
||||
|
||||
void
|
||||
onCompilationComplete() override
|
||||
{
|
||||
if (!IsOnOwningThread()) {
|
||||
MOZ_ALWAYS_SUCCEEDS(mOwningThread->Dispatch(NewCancelableRunnableMethod(
|
||||
"WasmCompiledModuleStream::onCompilationComplete",
|
||||
this,
|
||||
&WasmCompiledModuleStream::onCompilationComplete)));
|
||||
return;
|
||||
}
|
||||
|
||||
if (NS_FAILED(mStatus) || !mCallback) {
|
||||
return;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(mModule);
|
||||
|
||||
size_t compiledSize = mModule->compiledSerializedSize();
|
||||
|
||||
nsCString compiled;
|
||||
compiled.SetLength(compiledSize);
|
||||
|
||||
mModule->compiledSerialize(
|
||||
reinterpret_cast<uint8_t*>(compiled.BeginWriting()), compiledSize);
|
||||
|
||||
MOZ_ALWAYS_SUCCEEDS(NS_NewCStringInputStream(getter_AddRefs(mStream),
|
||||
std::move(compiled)));
|
||||
|
||||
mModule = nullptr;
|
||||
|
||||
CallCallback();
|
||||
}
|
||||
};
|
||||
|
||||
NS_IMPL_ISUPPORTS(WasmCompiledModuleStream,
|
||||
nsIInputStream,
|
||||
nsIAsyncInputStream,
|
||||
nsICloneableInputStream)
|
||||
|
||||
bool
|
||||
StructuredCloneWriteCallback(JSContext* aCx,
|
||||
JSStructuredCloneWriter* aWriter,
|
||||
@ -647,61 +365,6 @@ StructuredCloneWriteCallback(JSContext* aCx,
|
||||
}
|
||||
}
|
||||
|
||||
if (JS::IsWasmModuleObject(aObj)) {
|
||||
RefPtr<JS::WasmModule> module = JS::GetWasmModule(aObj);
|
||||
MOZ_ASSERT(module);
|
||||
|
||||
size_t bytecodeSize = module->bytecodeSerializedSize();
|
||||
UniquePtr<uint8_t[], JS::FreePolicy> bytecode(js_pod_malloc<uint8_t>(bytecodeSize));
|
||||
module->bytecodeSerialize(bytecode.get(), bytecodeSize);
|
||||
|
||||
RefPtr<BlobImpl> blobImpl =
|
||||
new MemoryBlobImpl(bytecode.release(), bytecodeSize, EmptyString());
|
||||
|
||||
RefPtr<Blob> bytecodeBlob = Blob::Create(nullptr, blobImpl);
|
||||
|
||||
if (module->compilationComplete()) {
|
||||
size_t compiledSize = module->compiledSerializedSize();
|
||||
UniquePtr<uint8_t[]> compiled(new uint8_t[compiledSize]);
|
||||
module->compiledSerialize(compiled.get(), compiledSize);
|
||||
|
||||
blobImpl =
|
||||
new MemoryBlobImpl(compiled.release(), compiledSize, EmptyString());
|
||||
} else {
|
||||
nsCOMPtr<nsIInputStream> stream(new WasmCompiledModuleStream(module));
|
||||
|
||||
blobImpl = StreamBlobImpl::Create(stream.forget(), EmptyString(),
|
||||
UINT64_MAX);
|
||||
}
|
||||
|
||||
RefPtr<Blob> compiledBlob = Blob::Create(nullptr, blobImpl);
|
||||
|
||||
if (cloneWriteInfo->mFiles.Length() + 1 > size_t(UINT32_MAX)) {
|
||||
MOZ_ASSERT(false, "Fix the structured clone data to use a bigger type!");
|
||||
return false;
|
||||
}
|
||||
|
||||
const uint32_t index = cloneWriteInfo->mFiles.Length();
|
||||
|
||||
// The ordering of the bytecode and compiled file is significant and must
|
||||
// never be changed. These two files must always form a pair
|
||||
// [eWasmBytecode, eWasmCompiled]. Everything else depends on it!
|
||||
if (!JS_WriteUint32Pair(aWriter, SCTAG_DOM_WASM, /* flags */ 0) ||
|
||||
!JS_WriteUint32Pair(aWriter, index, index + 1)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
StructuredCloneFile* newFile = cloneWriteInfo->mFiles.AppendElement();
|
||||
newFile->mBlob = bytecodeBlob;
|
||||
newFile->mType = StructuredCloneFile::eWasmBytecode;
|
||||
|
||||
newFile = cloneWriteInfo->mFiles.AppendElement();
|
||||
newFile->mBlob = compiledBlob;
|
||||
newFile->mType = StructuredCloneFile::eWasmCompiled;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return StructuredCloneHolder::WriteFullySerializableObjects(aCx, aWriter, aObj);
|
||||
}
|
||||
|
||||
@ -768,29 +431,6 @@ CopyingStructuredCloneWriteCallback(JSContext* aCx,
|
||||
}
|
||||
}
|
||||
|
||||
if (JS::IsWasmModuleObject(aObj)) {
|
||||
RefPtr<JS::WasmModule> module = JS::GetWasmModule(aObj);
|
||||
MOZ_ASSERT(module);
|
||||
|
||||
if (cloneInfo->mFiles.Length() > size_t(UINT32_MAX)) {
|
||||
MOZ_ASSERT(false,
|
||||
"Fix the structured clone data to use a bigger type!");
|
||||
return false;
|
||||
}
|
||||
|
||||
const uint32_t index = cloneInfo->mFiles.Length();
|
||||
|
||||
if (!JS_WriteUint32Pair(aWriter, SCTAG_DOM_WASM, index)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
StructuredCloneFile* newFile = cloneInfo->mFiles.AppendElement();
|
||||
newFile->mWasmModule = module;
|
||||
newFile->mType = StructuredCloneFile::eWasmBytecode;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return StructuredCloneHolder::WriteFullySerializableObjects(aCx, aWriter, aObj);
|
||||
}
|
||||
|
||||
@ -1116,7 +756,7 @@ public:
|
||||
JS::MutableHandle<JSObject*> aResult)
|
||||
{
|
||||
MOZ_ASSERT(aCx);
|
||||
MOZ_ASSERT(aFile.mType == StructuredCloneFile::eWasmCompiled);
|
||||
MOZ_ASSERT(aFile.mType == StructuredCloneFile::eWasmBytecode);
|
||||
MOZ_ASSERT(!aFile.mBlob);
|
||||
|
||||
// If we don't have a WasmModule, we are probably using it for an index
|
||||
@ -1184,7 +824,7 @@ CommonStructuredCloneReadCallback(JSContext* aCx,
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
StructuredCloneFile& file = cloneReadInfo->mFiles[data.compiledIndex];
|
||||
StructuredCloneFile& file = cloneReadInfo->mFiles[data.bytecodeIndex];
|
||||
|
||||
if (NS_WARN_IF(!ValueDeserializationHelper::CreateAndWrapWasmModule(aCx,
|
||||
file,
|
||||
|
@ -114,12 +114,7 @@ support-files =
|
||||
unit/test_upgrade_add_index.js
|
||||
unit/test_unique_index_update.js
|
||||
unit/test_view_put_get_values.js
|
||||
unit/test_wasm_cursors.js
|
||||
unit/test_wasm_getAll.js
|
||||
unit/test_wasm_index_getAllObjects.js
|
||||
unit/test_wasm_indexes.js
|
||||
unit/test_wasm_put_get_values.js
|
||||
unit/test_wasm_serialize_tiering.js
|
||||
unit/test_writer_starvation.js
|
||||
|
||||
[test_abort_deleted_index.html]
|
||||
@ -271,9 +266,4 @@ scheme=https
|
||||
[test_unique_index_update.html]
|
||||
[test_upgrade_add_index.html]
|
||||
[test_view_put_get_values.html]
|
||||
[test_wasm_cursors.html]
|
||||
[test_wasm_getAll.html]
|
||||
[test_wasm_index_getAllObjects.html]
|
||||
[test_wasm_indexes.html]
|
||||
[test_wasm_put_get_values.html]
|
||||
[test_wasm_serialize_tiering.html]
|
||||
|
@ -1,20 +0,0 @@
|
||||
<!--
|
||||
Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/
|
||||
-->
|
||||
<html>
|
||||
<head>
|
||||
<title>Indexed Database Property Test</title>
|
||||
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
|
||||
<script type="text/javascript" src="unit/test_wasm_cursors.js"></script>
|
||||
<script type="text/javascript" src="file.js"></script>
|
||||
<script type="text/javascript" src="helpers.js"></script>
|
||||
|
||||
</head>
|
||||
|
||||
<body onload="runTest();"></body>
|
||||
|
||||
</html>
|
@ -1,20 +0,0 @@
|
||||
<!--
|
||||
Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/
|
||||
-->
|
||||
<html>
|
||||
<head>
|
||||
<title>Indexed Database Property Test</title>
|
||||
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
|
||||
<script type="text/javascript" src="unit/test_wasm_getAll.js"></script>
|
||||
<script type="text/javascript" src="file.js"></script>
|
||||
<script type="text/javascript" src="helpers.js"></script>
|
||||
|
||||
</head>
|
||||
|
||||
<body onload="runTest();"></body>
|
||||
|
||||
</html>
|
@ -1,20 +0,0 @@
|
||||
<!--
|
||||
Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/
|
||||
-->
|
||||
<html>
|
||||
<head>
|
||||
<title>Indexed Database Property Test</title>
|
||||
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
|
||||
<script type="text/javascript" src="unit/test_wasm_index_getAllObjects.js"></script>
|
||||
<script type="text/javascript" src="file.js"></script>
|
||||
<script type="text/javascript" src="helpers.js"></script>
|
||||
|
||||
</head>
|
||||
|
||||
<body onload="runTest();"></body>
|
||||
|
||||
</html>
|
@ -1,20 +0,0 @@
|
||||
<!--
|
||||
Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/
|
||||
-->
|
||||
<html>
|
||||
<head>
|
||||
<title>Indexed Database Property Test</title>
|
||||
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
|
||||
<script type="text/javascript" src="unit/test_wasm_indexes.js"></script>
|
||||
<script type="text/javascript" src="file.js"></script>
|
||||
<script type="text/javascript" src="helpers.js"></script>
|
||||
|
||||
</head>
|
||||
|
||||
<body onload="runTest();"></body>
|
||||
|
||||
</html>
|
@ -1,20 +0,0 @@
|
||||
<!--
|
||||
Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/
|
||||
-->
|
||||
<html>
|
||||
<head>
|
||||
<title>Indexed Database Property Test</title>
|
||||
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
|
||||
<script type="text/javascript" src="unit/test_wasm_serialize_tiering.js"></script>
|
||||
<script type="text/javascript" src="file.js"></script>
|
||||
<script type="text/javascript" src="helpers.js"></script>
|
||||
|
||||
</head>
|
||||
|
||||
<body onload="runTest();"></body>
|
||||
|
||||
</html>
|
@ -54,19 +54,6 @@ function* testSteps()
|
||||
info("not storing crypto key");
|
||||
}
|
||||
|
||||
if (isWasmSupported()) {
|
||||
info("creating wasm");
|
||||
getWasmBinary("(module (func (nop)))");
|
||||
let binary = yield undefined;
|
||||
allData.push({
|
||||
id: 2,
|
||||
what: "wasm",
|
||||
data: getWasmModule(binary)
|
||||
});
|
||||
} else {
|
||||
info("not storing wasm");
|
||||
}
|
||||
|
||||
// -- Create the IDB and populate it with the base data.
|
||||
info("opening initial database");
|
||||
let request = indexedDB.open(this.window ? window.location.pathname : "Splendid Test", 1);
|
||||
|
@ -1,66 +0,0 @@
|
||||
/**
|
||||
* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/
|
||||
*/
|
||||
|
||||
var testGenerator = testSteps();
|
||||
|
||||
function* testSteps()
|
||||
{
|
||||
const name =
|
||||
this.window ? window.location.pathname : "test_wasm_cursors.js";
|
||||
|
||||
const objectStoreName = "Wasm";
|
||||
|
||||
const wasmData = { key: 1, value: null };
|
||||
|
||||
if (!isWasmSupported()) {
|
||||
finishTest();
|
||||
return;
|
||||
}
|
||||
|
||||
getWasmBinary("(module (func (nop)))");
|
||||
let binary = yield undefined;
|
||||
wasmData.value = getWasmModule(binary);
|
||||
|
||||
info("Opening database");
|
||||
|
||||
let request = indexedDB.open(name);
|
||||
request.onerror = errorHandler;
|
||||
request.onupgradeneeded = continueToNextStepSync;
|
||||
request.onsuccess = unexpectedSuccessHandler;
|
||||
yield undefined;
|
||||
|
||||
// upgradeneeded
|
||||
request.onupgradeneeded = unexpectedSuccessHandler;
|
||||
request.onsuccess = continueToNextStepSync;
|
||||
|
||||
info("Creating objectStore");
|
||||
|
||||
request.result.createObjectStore(objectStoreName);
|
||||
|
||||
yield undefined;
|
||||
|
||||
// success
|
||||
let db = request.result;
|
||||
db.onerror = errorHandler;
|
||||
|
||||
info("Storing wasm");
|
||||
|
||||
let objectStore = db.transaction([objectStoreName], "readwrite")
|
||||
.objectStore(objectStoreName);
|
||||
request = objectStore.add(wasmData.value, wasmData.key);
|
||||
request.onsuccess = continueToNextStepSync;
|
||||
yield undefined;
|
||||
|
||||
is(request.result, wasmData.key, "Got correct key");
|
||||
|
||||
info("Opening cursor");
|
||||
|
||||
request = objectStore.openCursor();
|
||||
request.addEventListener("error", new ExpectError("UnknownError", true));
|
||||
request.onsuccess = unexpectedSuccessHandler;
|
||||
yield undefined;
|
||||
|
||||
finishTest();
|
||||
}
|
@ -1,135 +0,0 @@
|
||||
/**
|
||||
* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/
|
||||
*/
|
||||
|
||||
var testGenerator = testSteps();
|
||||
|
||||
function* testSteps()
|
||||
{
|
||||
const name =
|
||||
this.window ? window.location.pathname : "test_wasm_getAll.js";
|
||||
|
||||
const objectStoreName = "Wasm";
|
||||
|
||||
const wasmData = [
|
||||
{ key: 1, value: 42 },
|
||||
{ key: 2, value: [null, null, null] },
|
||||
{ key: 3, value: [null, null, null, null, null] }
|
||||
];
|
||||
|
||||
if (!isWasmSupported()) {
|
||||
finishTest();
|
||||
return;
|
||||
}
|
||||
|
||||
getWasmBinary(`(module (func (export "run") (result i32) (i32.const 1)))`);
|
||||
let binary = yield undefined;
|
||||
wasmData[1].value[0] = getWasmModule(binary);
|
||||
|
||||
getWasmBinary(`(module (func (export "run") (result i32) (i32.const 2)))`);
|
||||
binary = yield undefined;
|
||||
wasmData[1].value[1] = getWasmModule(binary);
|
||||
|
||||
getWasmBinary(`(module (func (export "run") (result i32) (i32.const 3)))`);
|
||||
binary = yield undefined;
|
||||
wasmData[1].value[2] = getWasmModule(binary);
|
||||
|
||||
getWasmBinary(`(module (func (export "run") (result i32) (i32.const 4)))`);
|
||||
binary = yield undefined;
|
||||
wasmData[2].value[0] = getWasmModule(binary);
|
||||
|
||||
getWasmBinary(`(module (func (export "run") (result i32) (i32.const 5)))`);
|
||||
binary = yield undefined;
|
||||
wasmData[2].value[1] = getWasmModule(binary);
|
||||
|
||||
getWasmBinary(`(module (func (export "run") (result i32) (i32.const 6)))`);
|
||||
binary = yield undefined;
|
||||
wasmData[2].value[2] = getWasmModule(binary);
|
||||
|
||||
getWasmBinary(`(module (func (export "run") (result i32) (i32.const 7)))`);
|
||||
binary = yield undefined;
|
||||
wasmData[2].value[3] = getWasmModule(binary);
|
||||
|
||||
getWasmBinary(`(module (func (export "run") (result i32) (i32.const 8)))`);
|
||||
binary = yield undefined;
|
||||
wasmData[2].value[4] = getWasmModule(binary);
|
||||
|
||||
let request = indexedDB.open(name, 1);
|
||||
request.onerror = errorHandler;
|
||||
request.onupgradeneeded = continueToNextStepSync;
|
||||
request.onsuccess = unexpectedSuccessHandler;
|
||||
yield undefined;
|
||||
|
||||
// upgradeneeded
|
||||
request.onupgradeneeded = unexpectedSuccessHandler;
|
||||
request.onsuccess = continueToNextStepSync;
|
||||
|
||||
info("Creating objectStore");
|
||||
|
||||
request.result.createObjectStore(objectStoreName);
|
||||
|
||||
yield undefined;
|
||||
|
||||
// success
|
||||
let db = request.result;
|
||||
db.onerror = errorHandler;
|
||||
|
||||
info("Storing values");
|
||||
|
||||
let objectStore = db.transaction([objectStoreName], "readwrite")
|
||||
.objectStore(objectStoreName);
|
||||
let addedCount = 0;
|
||||
for (let i in wasmData) {
|
||||
request = objectStore.add(wasmData[i].value, wasmData[i].key);
|
||||
request.onsuccess = function(event) {
|
||||
if (++addedCount == wasmData.length) {
|
||||
continueToNextStep();
|
||||
}
|
||||
};
|
||||
}
|
||||
yield undefined;
|
||||
|
||||
info("Getting values");
|
||||
|
||||
request = db.transaction(objectStoreName)
|
||||
.objectStore(objectStoreName)
|
||||
.getAll();
|
||||
request.onsuccess = continueToNextStepSync;
|
||||
yield undefined;
|
||||
|
||||
info("Verifying values");
|
||||
|
||||
// Can't call yield inside of the verify function.
|
||||
let modulesToProcess = [];
|
||||
|
||||
function verifyArray(array1, array2) {
|
||||
is(array1 instanceof Array, true, "Got an array object");
|
||||
is(array1.length, array2.length, "Same length");
|
||||
}
|
||||
|
||||
function verifyData(data1, data2) {
|
||||
if (data2 instanceof Array) {
|
||||
verifyArray(data1, data2);
|
||||
for (let i in data2) {
|
||||
verifyData(data1[i], data2[i]);
|
||||
}
|
||||
} else if (data2 instanceof WebAssembly.Module) {
|
||||
modulesToProcess.push({ module1: data1, module2: data2 });
|
||||
} else {
|
||||
is(data1, data2, "Same value");
|
||||
}
|
||||
}
|
||||
|
||||
verifyArray(request.result, wasmData);
|
||||
for (let i in wasmData) {
|
||||
verifyData(request.result[i], wasmData[i].value);
|
||||
}
|
||||
|
||||
for (let moduleToProcess of modulesToProcess) {
|
||||
verifyWasmModule(moduleToProcess.module1, moduleToProcess.module2);
|
||||
yield undefined;
|
||||
}
|
||||
|
||||
finishTest();
|
||||
}
|
@ -1,110 +0,0 @@
|
||||
/**
|
||||
* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/
|
||||
*/
|
||||
|
||||
var testGenerator = testSteps();
|
||||
|
||||
function* testSteps()
|
||||
{
|
||||
const name =
|
||||
this.window ? window.location.pathname : "test_wasm_getAll.js";
|
||||
|
||||
const objectStoreName = "Wasm";
|
||||
|
||||
const wasmData = [
|
||||
{ key: 1, value: { name: "foo1", data: 42 } },
|
||||
{ key: 2, value: { name: "foo2", data: [null, null, null] } },
|
||||
{ key: 3, value: { name: "foo3", data: [null, null, null, null, null] } }
|
||||
];
|
||||
|
||||
const indexData = { name: "nameIndex", keyPath: "name", options: { } };
|
||||
|
||||
if (!isWasmSupported()) {
|
||||
finishTest();
|
||||
return;
|
||||
}
|
||||
|
||||
getWasmBinary("(module (func (result i32) (i32.const 1)))");
|
||||
let binary = yield undefined;
|
||||
wasmData[1].value.data[0] = getWasmModule(binary);
|
||||
|
||||
getWasmBinary("(module (func (result i32) (i32.const 2)))");
|
||||
binary = yield undefined;
|
||||
wasmData[1].value.data[1] = getWasmModule(binary);
|
||||
|
||||
getWasmBinary("(module (func (result i32) (i32.const 3)))");
|
||||
binary = yield undefined;
|
||||
wasmData[1].value.data[2] = getWasmModule(binary);
|
||||
|
||||
getWasmBinary("(module (func (result i32) (i32.const 4)))");
|
||||
binary = yield undefined;
|
||||
wasmData[2].value.data[0] = getWasmModule(binary);
|
||||
|
||||
getWasmBinary("(module (func (result i32) (i32.const 5)))");
|
||||
binary = yield undefined;
|
||||
wasmData[2].value.data[1] = getWasmModule(binary);
|
||||
|
||||
getWasmBinary("(module (func (result i32) (i32.const 6)))");
|
||||
binary = yield undefined;
|
||||
wasmData[2].value.data[2] = getWasmModule(binary);
|
||||
|
||||
getWasmBinary("(module (func (result i32) (i32.const 7)))");
|
||||
binary = yield undefined;
|
||||
wasmData[2].value.data[3] = getWasmModule(binary);
|
||||
|
||||
getWasmBinary("(module (func (result i32) (i32.const 8)))");
|
||||
binary = yield undefined;
|
||||
wasmData[2].value.data[4] = getWasmModule(binary);
|
||||
|
||||
let request = indexedDB.open(name, 1);
|
||||
request.onerror = errorHandler;
|
||||
request.onupgradeneeded = continueToNextStepSync;
|
||||
request.onsuccess = unexpectedSuccessHandler;
|
||||
yield undefined;
|
||||
|
||||
// upgradeneeded
|
||||
request.onupgradeneeded = unexpectedSuccessHandler;
|
||||
request.onsuccess = continueToNextStepSync;
|
||||
|
||||
info("Creating objectStore");
|
||||
|
||||
let objectStore = request.result.createObjectStore(objectStoreName);
|
||||
|
||||
info("Creating index");
|
||||
|
||||
objectStore.createIndex(indexData.name, indexData.keyPath, indexData.options);
|
||||
|
||||
yield undefined;
|
||||
|
||||
// success
|
||||
let db = request.result;
|
||||
db.onerror = errorHandler;
|
||||
|
||||
info("Storing values");
|
||||
|
||||
objectStore = db.transaction([objectStoreName], "readwrite")
|
||||
.objectStore(objectStoreName);
|
||||
let addedCount = 0;
|
||||
for (let i in wasmData) {
|
||||
request = objectStore.add(wasmData[i].value, wasmData[i].key);
|
||||
request.onsuccess = function(event) {
|
||||
if (++addedCount == wasmData.length) {
|
||||
continueToNextStep();
|
||||
}
|
||||
};
|
||||
}
|
||||
yield undefined;
|
||||
|
||||
info("Getting values");
|
||||
|
||||
request = db.transaction(objectStoreName)
|
||||
.objectStore(objectStoreName)
|
||||
.index("nameIndex")
|
||||
.getAll();
|
||||
request.addEventListener("error", new ExpectError("UnknownError", true));
|
||||
request.onsuccess = unexpectedSuccessHandler;
|
||||
yield undefined;
|
||||
|
||||
finishTest();
|
||||
}
|
@ -1,79 +0,0 @@
|
||||
/**
|
||||
* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/
|
||||
*/
|
||||
|
||||
var testGenerator = testSteps();
|
||||
|
||||
function* testSteps()
|
||||
{
|
||||
const name =
|
||||
this.window ? window.location.pathname : "test_wasm_indexes.js";
|
||||
|
||||
const objectStoreName = "Wasm";
|
||||
|
||||
const wasmData = { key: 1, value: { name: "foo", data: null } };
|
||||
|
||||
const indexData = { name: "nameIndex", keyPath: "name", options: { } };
|
||||
|
||||
if (!isWasmSupported()) {
|
||||
finishTest();
|
||||
return;
|
||||
}
|
||||
|
||||
getWasmBinary("(module (func (nop)))");
|
||||
let binary = yield undefined;
|
||||
wasmData.value.data = getWasmModule(binary);
|
||||
|
||||
info("Opening database");
|
||||
|
||||
let request = indexedDB.open(name);
|
||||
request.onerror = errorHandler;
|
||||
request.onupgradeneeded = continueToNextStepSync;
|
||||
request.onsuccess = unexpectedSuccessHandler;
|
||||
yield undefined;
|
||||
|
||||
// upgradeneeded
|
||||
request.onupgradeneeded = unexpectedSuccessHandler;
|
||||
request.onsuccess = continueToNextStepSync;
|
||||
|
||||
info("Creating objectStore");
|
||||
|
||||
let objectStore = request.result.createObjectStore(objectStoreName);
|
||||
|
||||
info("Creating index");
|
||||
|
||||
objectStore.createIndex(indexData.name, indexData.keyPath, indexData.options);
|
||||
|
||||
yield undefined;
|
||||
|
||||
// success
|
||||
let db = request.result;
|
||||
db.onerror = errorHandler;
|
||||
|
||||
info("Storing wasm");
|
||||
|
||||
objectStore = db.transaction([objectStoreName], "readwrite")
|
||||
.objectStore(objectStoreName);
|
||||
request = objectStore.add(wasmData.value, wasmData.key);
|
||||
request.onsuccess = continueToNextStepSync;
|
||||
yield undefined;
|
||||
|
||||
is(request.result, wasmData.key, "Got correct key");
|
||||
|
||||
info("Getting wasm");
|
||||
|
||||
request = objectStore.index("nameIndex").get("foo");
|
||||
request.addEventListener("error", new ExpectError("UnknownError", true));
|
||||
request.onsuccess = unexpectedSuccessHandler;
|
||||
yield undefined;
|
||||
|
||||
info("Opening cursor");
|
||||
|
||||
request = objectStore.index("nameIndex").openCursor();
|
||||
request.addEventListener("error", new ExpectError("UnknownError", true));
|
||||
request.onsuccess = unexpectedSuccessHandler;
|
||||
yield undefined;
|
||||
|
||||
finishTest();
|
||||
}
|
@ -45,38 +45,21 @@ function* testSteps()
|
||||
let db = request.result;
|
||||
db.onerror = errorHandler;
|
||||
|
||||
info("Storing wasm");
|
||||
info("Testing failure to store wasm");
|
||||
|
||||
let objectStore = db.transaction([objectStoreName], "readwrite")
|
||||
.objectStore(objectStoreName);
|
||||
request = objectStore.add(wasmData.value, wasmData.key);
|
||||
request.onsuccess = continueToNextStepSync;
|
||||
yield undefined;
|
||||
|
||||
is(request.result, wasmData.key, "Got correct key");
|
||||
|
||||
info("Getting wasm");
|
||||
|
||||
request = objectStore.get(wasmData.key);
|
||||
request.onsuccess = continueToNextStepSync;
|
||||
yield undefined;
|
||||
|
||||
info("Verifying wasm");
|
||||
|
||||
verifyWasmModule(request.result, wasmData.value);
|
||||
yield undefined;
|
||||
|
||||
info("Getting wasm in new transaction");
|
||||
|
||||
request = db.transaction([objectStoreName])
|
||||
.objectStore(objectStoreName).get(wasmData.key);
|
||||
request.onsuccess = continueToNextStepSync;
|
||||
yield undefined;
|
||||
|
||||
info("Verifying wasm");
|
||||
|
||||
verifyWasmModule(request.result, wasmData.value);
|
||||
yield undefined;
|
||||
// storing a wasm module in IDB should now fail
|
||||
let failed = false;
|
||||
try {
|
||||
objectStore.add(wasmData.value, wasmData.key);
|
||||
} catch (err) {
|
||||
failed = true;
|
||||
ok(err instanceof DOMException, "caught right error type");
|
||||
is(err.name, "DataCloneError", "caught right error name");
|
||||
}
|
||||
ok(failed, "error was thrown");
|
||||
|
||||
finishTest();
|
||||
}
|
||||
|
@ -94,9 +94,9 @@ function* testSteps()
|
||||
|
||||
let newCompiledBuffer = fileReader.result;
|
||||
|
||||
info("Verifying blobs differ");
|
||||
info("Verifying that re-storing of re-compiled code has been disabled");
|
||||
|
||||
ok(!compareBuffers(newCompiledBuffer, compiledBuffer), "Blobs differ");
|
||||
ok(compareBuffers(newCompiledBuffer, compiledBuffer), "Blobs don't differ");
|
||||
|
||||
info("Getting wasm again");
|
||||
|
||||
|
@ -1,106 +0,0 @@
|
||||
/**
|
||||
* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/
|
||||
*/
|
||||
|
||||
var testGenerator = testSteps();
|
||||
|
||||
function* testSteps()
|
||||
{
|
||||
const name =
|
||||
this.window ? window.location.pathname : "test_wasm_serialize_tiering.js";
|
||||
|
||||
const objectStoreName = "Wasm";
|
||||
|
||||
if (!isWasmSupported()) {
|
||||
finishTest();
|
||||
return;
|
||||
}
|
||||
|
||||
// Make a module big enough so that tiering is significant.
|
||||
const N = 50;
|
||||
let bigFunc = `(func (result f64)\n`;
|
||||
for (let i = 0; i < N; i++) {
|
||||
bigFunc += ` f64.const 1.0\n`;
|
||||
}
|
||||
for (let i = 0; i < N - 1; i++) {
|
||||
bigFunc += ` f64.add\n`;
|
||||
}
|
||||
bigFunc += `)`;
|
||||
let bigModule = `(module \n`;
|
||||
for (let i = 0; i < 100; i++) {
|
||||
bigModule += bigFunc;
|
||||
}
|
||||
bigModule += ` (export "run" (func 10))\n`;
|
||||
bigModule += `)`;
|
||||
|
||||
getWasmBinary(bigModule);
|
||||
let bigBinary = yield undefined;
|
||||
|
||||
info("Opening database");
|
||||
|
||||
let request = indexedDB.open(name);
|
||||
request.onerror = errorHandler;
|
||||
request.onupgradeneeded = continueToNextStepSync;
|
||||
request.onsuccess = unexpectedSuccessHandler;
|
||||
yield undefined;
|
||||
|
||||
// upgradeneeded
|
||||
request.onupgradeneeded = unexpectedSuccessHandler;
|
||||
request.onsuccess = continueToNextStepSync;
|
||||
|
||||
info("Creating objectStore");
|
||||
|
||||
request.result.createObjectStore(objectStoreName);
|
||||
|
||||
yield undefined;
|
||||
|
||||
// success
|
||||
let db = request.result;
|
||||
db.onerror = errorHandler;
|
||||
|
||||
info("Storing wasm modules");
|
||||
|
||||
let objectStore = db.transaction([objectStoreName], "readwrite")
|
||||
.objectStore(objectStoreName);
|
||||
|
||||
const NumModules = 5;
|
||||
const NumCopies = 5;
|
||||
|
||||
let finishedAdds = 0;
|
||||
for (let moduleIndex = 0; moduleIndex < NumModules; moduleIndex++) {
|
||||
let module = new WebAssembly.Module(bigBinary);
|
||||
for (let copyIndex = 0; copyIndex < NumCopies; copyIndex++) {
|
||||
let key = String(moduleIndex) + " " + String(copyIndex);
|
||||
let request = objectStore.add(module, key);
|
||||
request.onsuccess = function() {
|
||||
is(request.result, key, "Got correct key");
|
||||
if (++finishedAdds === NumModules * NumCopies) {
|
||||
continueToNextStepSync();
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
yield undefined;
|
||||
|
||||
info("Getting wasm");
|
||||
|
||||
let finishedGets = 0;
|
||||
for (let moduleIndex = 0; moduleIndex < NumModules; moduleIndex++) {
|
||||
for (let copyIndex = 0; copyIndex < NumCopies; copyIndex++) {
|
||||
let key = String(moduleIndex) + " " + String(copyIndex);
|
||||
let request = objectStore.get(key);
|
||||
request.onsuccess = function() {
|
||||
let module = request.result;
|
||||
let instance = new WebAssembly.Instance(module);
|
||||
is(instance.exports.run(), N, "Got correct run() result");
|
||||
if (++finishedGets === NumModules * NumCopies) {
|
||||
continueToNextStepSync();
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
yield undefined;
|
||||
|
||||
finishTest();
|
||||
}
|
@ -646,7 +646,3 @@ var SpecialPowers = {
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
// This can be removed soon when on by default.
|
||||
if (SpecialPowers.isMainProcess())
|
||||
SpecialPowers.setBoolPref("javascript.options.wasm_baselinejit", true);
|
||||
|
@ -66,15 +66,6 @@ skip-if = os == "android"
|
||||
[test_temporary_storage.js]
|
||||
# bug 951017: intermittent failure on Android x86 emulator
|
||||
skip-if = os == "android" && processor == "x86"
|
||||
[test_view_put_get_values.js]
|
||||
[test_wasm_cursors.js]
|
||||
[test_wasm_getAll.js]
|
||||
skip-if = coverage # bug 1336727
|
||||
[test_wasm_index_getAllObjects.js]
|
||||
[test_wasm_indexes.js]
|
||||
[test_wasm_put_get_values.js]
|
||||
skip-if = coverage # bug 1336727
|
||||
[test_wasm_recompile.js]
|
||||
skip-if = coverage # bug 1336727
|
||||
[test_wasm_serialize_tiering.js]
|
||||
skip-if = coverage # bug 1336727
|
||||
|
@ -26,7 +26,6 @@ OS_LIBS += [
|
||||
'comctl32',
|
||||
]
|
||||
|
||||
if ((CONFIG['MOZ_PGO'] or
|
||||
(not CONFIG['HAVE_64BIT_BUILD'] and CONFIG['ENABLE_CLANG_PLUGIN']))
|
||||
if (not CONFIG['HAVE_64BIT_BUILD'] and CONFIG['ENABLE_CLANG_PLUGIN']
|
||||
and CONFIG['CC_TYPE'] == 'clang-cl'):
|
||||
AllowCompilerWarnings() # workaround for bug 1090497
|
||||
|
@ -5361,10 +5361,6 @@ QuotaManager::EnsureOriginIsInitializedInternal(
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
mTemporaryStorageInitialized = true;
|
||||
|
||||
CheckTemporaryStorageLimits();
|
||||
}
|
||||
|
||||
bool created;
|
||||
|
@ -21,7 +21,7 @@ NS_IMPL_CYCLE_COLLECTION_CLASS(ModuleScript)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(ModuleScript)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mLoader)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mBaseURL)
|
||||
tmp->UnlinkModuleRecord();
|
||||
tmp->UnlinkScript();
|
||||
tmp->mParseError.setUndefined();
|
||||
tmp->mErrorToRethrow.setUndefined();
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
|
||||
@ -31,7 +31,7 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(ModuleScript)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(ModuleScript)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mModuleRecord)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mScript)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mParseError)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mErrorToRethrow)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRACE_END
|
||||
@ -46,42 +46,42 @@ ModuleScript::ModuleScript(ScriptLoader* aLoader, nsIURI* aBaseURL)
|
||||
{
|
||||
MOZ_ASSERT(mLoader);
|
||||
MOZ_ASSERT(mBaseURL);
|
||||
MOZ_ASSERT(!mModuleRecord);
|
||||
MOZ_ASSERT(!mScript);
|
||||
MOZ_ASSERT(!HasParseError());
|
||||
MOZ_ASSERT(!HasErrorToRethrow());
|
||||
}
|
||||
|
||||
void
|
||||
ModuleScript::UnlinkModuleRecord()
|
||||
ModuleScript::UnlinkScript()
|
||||
{
|
||||
// Remove module's back reference to this object request if present.
|
||||
if (mModuleRecord) {
|
||||
MOZ_ASSERT(JS::GetModuleHostDefinedField(mModuleRecord).toPrivate() ==
|
||||
if (mScript) {
|
||||
MOZ_ASSERT(JS::GetModuleHostDefinedField(mScript).toPrivate() ==
|
||||
this);
|
||||
JS::SetModuleHostDefinedField(mModuleRecord, JS::UndefinedValue());
|
||||
mModuleRecord = nullptr;
|
||||
JS::SetModuleHostDefinedField(mScript, JS::UndefinedValue());
|
||||
mScript = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
ModuleScript::~ModuleScript()
|
||||
{
|
||||
// The object may be destroyed without being unlinked first.
|
||||
UnlinkModuleRecord();
|
||||
UnlinkScript();
|
||||
DropJSObjects(this);
|
||||
}
|
||||
|
||||
void
|
||||
ModuleScript::SetModuleRecord(JS::Handle<JSObject*> aModuleRecord)
|
||||
ModuleScript::SetScript(JS::Handle<JSScript*> aScript)
|
||||
{
|
||||
MOZ_ASSERT(!mModuleRecord);
|
||||
MOZ_ASSERT(!mScript);
|
||||
MOZ_ASSERT(!HasParseError());
|
||||
MOZ_ASSERT(!HasErrorToRethrow());
|
||||
|
||||
mModuleRecord = aModuleRecord;
|
||||
mScript = aScript;
|
||||
|
||||
// Make module's host defined field point to this module script object.
|
||||
// This is cleared in the UnlinkModuleRecord().
|
||||
JS::SetModuleHostDefinedField(mModuleRecord, JS::PrivateValue(this));
|
||||
// This is cleared in the UnlinkScript().
|
||||
JS::SetModuleHostDefinedField(mScript, JS::PrivateValue(this));
|
||||
HoldJSObjects(this);
|
||||
}
|
||||
|
||||
@ -92,7 +92,7 @@ ModuleScript::SetParseError(const JS::Value& aError)
|
||||
MOZ_ASSERT(!HasParseError());
|
||||
MOZ_ASSERT(!HasErrorToRethrow());
|
||||
|
||||
UnlinkModuleRecord();
|
||||
UnlinkScript();
|
||||
mParseError = aError;
|
||||
HoldJSObjects(this);
|
||||
}
|
||||
@ -103,9 +103,9 @@ ModuleScript::SetErrorToRethrow(const JS::Value& aError)
|
||||
MOZ_ASSERT(!aError.isUndefined());
|
||||
MOZ_ASSERT(!HasErrorToRethrow());
|
||||
|
||||
// This is only called after SetModuleRecord() or SetParseError() so we don't
|
||||
// This is only called after SetScript() or SetParseError() so we don't
|
||||
// need to call HoldJSObjects() here.
|
||||
MOZ_ASSERT(mModuleRecord || HasParseError());
|
||||
MOZ_ASSERT(mScript || HasParseError());
|
||||
|
||||
mErrorToRethrow = aError;
|
||||
}
|
||||
@ -113,7 +113,7 @@ ModuleScript::SetErrorToRethrow(const JS::Value& aError)
|
||||
void
|
||||
ModuleScript::SetSourceElementAssociated()
|
||||
{
|
||||
MOZ_ASSERT(mModuleRecord);
|
||||
MOZ_ASSERT(mScript);
|
||||
MOZ_ASSERT(!mSourceElementAssociated);
|
||||
|
||||
mSourceElementAssociated = true;
|
||||
|
@ -22,7 +22,7 @@ class ModuleScript final : public nsISupports
|
||||
{
|
||||
RefPtr<ScriptLoader> mLoader;
|
||||
nsCOMPtr<nsIURI> mBaseURL;
|
||||
JS::Heap<JSObject*> mModuleRecord;
|
||||
JS::Heap<JSScript*> mScript;
|
||||
JS::Heap<JS::Value> mParseError;
|
||||
JS::Heap<JS::Value> mErrorToRethrow;
|
||||
bool mSourceElementAssociated;
|
||||
@ -36,13 +36,13 @@ public:
|
||||
ModuleScript(ScriptLoader* aLoader,
|
||||
nsIURI* aBaseURL);
|
||||
|
||||
void SetModuleRecord(JS::Handle<JSObject*> aModuleRecord);
|
||||
void SetScript(JS::Handle<JSScript*> aScript);
|
||||
void SetParseError(const JS::Value& aError);
|
||||
void SetErrorToRethrow(const JS::Value& aError);
|
||||
void SetSourceElementAssociated();
|
||||
|
||||
ScriptLoader* Loader() const { return mLoader; }
|
||||
JSObject* ModuleRecord() const { return mModuleRecord; }
|
||||
JSScript* Script() const { return mScript; }
|
||||
nsIURI* BaseURL() const { return mBaseURL; }
|
||||
JS::Value ParseError() const { return mParseError; }
|
||||
JS::Value ErrorToRethrow() const { return mErrorToRethrow; }
|
||||
@ -50,7 +50,7 @@ public:
|
||||
bool HasErrorToRethrow() const { return !mErrorToRethrow.isUndefined(); }
|
||||
bool SourceElementAssociated() const { return mSourceElementAssociated; }
|
||||
|
||||
void UnlinkModuleRecord();
|
||||
void UnlinkScript();
|
||||
};
|
||||
|
||||
} // dom namespace
|
||||
|
@ -478,12 +478,12 @@ ScriptLoader::CreateModuleScript(ModuleLoadRequest* aRequest)
|
||||
nsresult rv;
|
||||
{
|
||||
JSContext* cx = aes.cx();
|
||||
JS::Rooted<JSObject*> module(cx);
|
||||
JS::Rooted<JSScript*> script(cx);
|
||||
|
||||
if (aRequest->mWasCompiledOMT) {
|
||||
module = JS::FinishOffThreadModule(cx, aRequest->mOffThreadToken);
|
||||
script = JS::FinishOffThreadModule(cx, aRequest->mOffThreadToken);
|
||||
aRequest->mOffThreadToken = nullptr;
|
||||
rv = module ? NS_OK : NS_ERROR_FAILURE;
|
||||
rv = script ? NS_OK : NS_ERROR_FAILURE;
|
||||
} else {
|
||||
JS::Rooted<JSObject*> global(cx, globalObject->GetGlobalJSObject());
|
||||
|
||||
@ -491,17 +491,21 @@ ScriptLoader::CreateModuleScript(ModuleLoadRequest* aRequest)
|
||||
rv = FillCompileOptionsForRequest(aes, aRequest, global, &options);
|
||||
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
SourceBufferHolder srcBuf = GetScriptSource(cx, aRequest);
|
||||
rv = nsJSUtils::CompileModule(cx, srcBuf, global, options, &module);
|
||||
auto srcBuf = GetScriptSource(cx, aRequest);
|
||||
if (srcBuf) {
|
||||
rv = nsJSUtils::CompileModule(cx, *srcBuf, global, options, &script);
|
||||
} else {
|
||||
rv = NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MOZ_ASSERT(NS_SUCCEEDED(rv) == (module != nullptr));
|
||||
MOZ_ASSERT(NS_SUCCEEDED(rv) == (script != nullptr));
|
||||
|
||||
RefPtr<ModuleScript> moduleScript = new ModuleScript(this, aRequest->mBaseURL);
|
||||
aRequest->mModuleScript = moduleScript;
|
||||
|
||||
if (!module) {
|
||||
if (!script) {
|
||||
LOG(("ScriptLoadRequest (%p): compilation failed (%d)",
|
||||
aRequest, unsigned(rv)));
|
||||
|
||||
@ -517,7 +521,7 @@ ScriptLoader::CreateModuleScript(ModuleLoadRequest* aRequest)
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
moduleScript->SetModuleRecord(module);
|
||||
moduleScript->SetScript(script);
|
||||
|
||||
// Validate requested modules and treat failure to resolve module specifiers
|
||||
// the same as a parse error.
|
||||
@ -610,14 +614,14 @@ ResolveRequestedModules(ModuleLoadRequest* aRequest, nsCOMArray<nsIURI>* aUrlsOu
|
||||
ModuleScript* ms = aRequest->mModuleScript;
|
||||
|
||||
AutoJSAPI jsapi;
|
||||
if (!jsapi.Init(ms->ModuleRecord())) {
|
||||
if (!jsapi.Init(JS::GetScriptGlobal(ms->Script()))) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
JSContext* cx = jsapi.cx();
|
||||
JS::Rooted<JSObject*> moduleRecord(cx, ms->ModuleRecord());
|
||||
JS::Rooted<JSScript*> script(cx, ms->Script());
|
||||
JS::Rooted<JSObject*> requestedModules(cx);
|
||||
requestedModules = JS::GetRequestedModules(cx, moduleRecord);
|
||||
requestedModules = JS::GetRequestedModules(cx, script);
|
||||
MOZ_ASSERT(requestedModules);
|
||||
|
||||
uint32_t length;
|
||||
@ -751,14 +755,14 @@ ScriptLoader::StartFetchingModuleAndDependencies(ModuleLoadRequest* aParent,
|
||||
}
|
||||
|
||||
// 8.1.3.8.1 HostResolveImportedModule(referencingModule, specifier)
|
||||
JSObject*
|
||||
HostResolveImportedModule(JSContext* aCx, JS::Handle<JSObject*> aModule,
|
||||
JSScript*
|
||||
HostResolveImportedModule(JSContext* aCx, JS::Handle<JSScript*> aScript,
|
||||
JS::Handle<JSString*> aSpecifier)
|
||||
{
|
||||
// Let referencing module script be referencingModule.[[HostDefined]].
|
||||
JS::Value value = JS::GetModuleHostDefinedField(aModule);
|
||||
JS::Value value = JS::GetModuleHostDefinedField(aScript);
|
||||
auto script = static_cast<ModuleScript*>(value.toPrivate());
|
||||
MOZ_ASSERT(script->ModuleRecord() == aModule);
|
||||
MOZ_ASSERT(script->Script() == aScript);
|
||||
|
||||
// Let url be the result of resolving a module specifier given referencing
|
||||
// module script and specifier.
|
||||
@ -779,25 +783,25 @@ HostResolveImportedModule(JSContext* aCx, JS::Handle<JSObject*> aModule,
|
||||
MOZ_ASSERT(ms, "Resolved module not found in module map");
|
||||
|
||||
MOZ_ASSERT(!ms->HasParseError());
|
||||
MOZ_ASSERT(ms->ModuleRecord());
|
||||
MOZ_ASSERT(ms->Script());
|
||||
|
||||
return ms->ModuleRecord();
|
||||
return ms->Script();
|
||||
}
|
||||
|
||||
bool
|
||||
HostPopulateImportMeta(JSContext* aCx, JS::Handle<JSObject*> aModule,
|
||||
HostPopulateImportMeta(JSContext* aCx, JS::Handle<JSScript*> aScript,
|
||||
JS::Handle<JSObject*> aMetaObject)
|
||||
{
|
||||
MOZ_DIAGNOSTIC_ASSERT(aModule);
|
||||
MOZ_DIAGNOSTIC_ASSERT(aScript);
|
||||
|
||||
JS::Value value = JS::GetModuleHostDefinedField(aModule);
|
||||
JS::Value value = JS::GetModuleHostDefinedField(aScript);
|
||||
if (value.isUndefined()) {
|
||||
JS_ReportErrorASCII(aCx, "Module script not found");
|
||||
return false;
|
||||
}
|
||||
|
||||
auto script = static_cast<ModuleScript*>(value.toPrivate());
|
||||
MOZ_DIAGNOSTIC_ASSERT(script->ModuleRecord() == aModule);
|
||||
MOZ_DIAGNOSTIC_ASSERT(script->Script() == aScript);
|
||||
|
||||
nsAutoCString url;
|
||||
MOZ_DIAGNOSTIC_ASSERT(script->BaseURL());
|
||||
@ -928,18 +932,18 @@ ScriptLoader::InstantiateModuleTree(ModuleLoadRequest* aRequest)
|
||||
return true;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(moduleScript->ModuleRecord());
|
||||
MOZ_ASSERT(moduleScript->Script());
|
||||
|
||||
nsAutoMicroTask mt;
|
||||
AutoJSAPI jsapi;
|
||||
if (NS_WARN_IF(!jsapi.Init(moduleScript->ModuleRecord()))) {
|
||||
if (NS_WARN_IF(!jsapi.Init(JS::GetScriptGlobal(moduleScript->Script())))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
EnsureModuleResolveHook(jsapi.cx());
|
||||
|
||||
JS::Rooted<JSObject*> module(jsapi.cx(), moduleScript->ModuleRecord());
|
||||
bool ok = NS_SUCCEEDED(nsJSUtils::ModuleInstantiate(jsapi.cx(), module));
|
||||
JS::Rooted<JSScript*> script(jsapi.cx(), moduleScript->Script());
|
||||
bool ok = NS_SUCCEEDED(nsJSUtils::ModuleInstantiate(jsapi.cx(), script));
|
||||
|
||||
if (!ok) {
|
||||
LOG(("ScriptLoadRequest (%p): Instantiate failed", aRequest));
|
||||
@ -1824,11 +1828,11 @@ ScriptLoader::AttemptAsyncScriptCompile(ScriptLoadRequest* aRequest,
|
||||
|
||||
if (aRequest->IsModuleRequest()) {
|
||||
MOZ_ASSERT(aRequest->IsTextSource());
|
||||
SourceBufferHolder srcBuf = GetScriptSource(cx, aRequest);
|
||||
if (!JS::CompileOffThreadModule(cx, options,
|
||||
srcBuf,
|
||||
OffThreadScriptLoaderCallback,
|
||||
static_cast<void*>(runnable))) {
|
||||
auto srcBuf = GetScriptSource(cx, aRequest);
|
||||
if (!srcBuf || !JS::CompileOffThreadModule(cx, options,
|
||||
*srcBuf,
|
||||
OffThreadScriptLoaderCallback,
|
||||
static_cast<void*>(runnable))) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
} else if (aRequest->IsBytecode()) {
|
||||
@ -1852,11 +1856,11 @@ ScriptLoader::AttemptAsyncScriptCompile(ScriptLoadRequest* aRequest,
|
||||
#endif
|
||||
} else {
|
||||
MOZ_ASSERT(aRequest->IsTextSource());
|
||||
SourceBufferHolder srcBuf = GetScriptSource(cx, aRequest);
|
||||
if (!JS::CompileOffThread(cx, options,
|
||||
srcBuf,
|
||||
OffThreadScriptLoaderCallback,
|
||||
static_cast<void*>(runnable))) {
|
||||
auto srcBuf = GetScriptSource(cx, aRequest);
|
||||
if (!srcBuf || !JS::CompileOffThread(cx, options,
|
||||
*srcBuf,
|
||||
OffThreadScriptLoaderCallback,
|
||||
static_cast<void*>(runnable))) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
}
|
||||
@ -1896,7 +1900,7 @@ ScriptLoader::CompileOffThreadOrProcessRequest(ScriptLoadRequest* aRequest)
|
||||
return ProcessRequest(aRequest);
|
||||
}
|
||||
|
||||
SourceBufferHolder
|
||||
mozilla::Maybe<SourceBufferHolder>
|
||||
ScriptLoader::GetScriptSource(JSContext* aCx, ScriptLoadRequest* aRequest)
|
||||
{
|
||||
// Return a SourceBufferHolder object holding the script's source text.
|
||||
@ -1909,15 +1913,17 @@ ScriptLoader::GetScriptSource(JSContext* aCx, ScriptLoadRequest* aRequest)
|
||||
|
||||
size_t nbytes = inlineData.Length() * sizeof(char16_t);
|
||||
JS::UniqueTwoByteChars chars(static_cast<char16_t*>(JS_malloc(aCx, nbytes)));
|
||||
MOZ_RELEASE_ASSERT(chars);
|
||||
if (!chars) {
|
||||
return Nothing();
|
||||
}
|
||||
|
||||
memcpy(chars.get(), inlineData.get(), nbytes);
|
||||
return SourceBufferHolder(std::move(chars), inlineData.Length());
|
||||
return Some(SourceBufferHolder(std::move(chars), inlineData.Length()));
|
||||
}
|
||||
|
||||
size_t length = aRequest->ScriptText().length();
|
||||
return SourceBufferHolder(aRequest->ScriptText().extractOrCopyRawBuffer(),
|
||||
length,
|
||||
SourceBufferHolder::GiveOwnership);
|
||||
JS::UniqueTwoByteChars chars(aRequest->ScriptText().extractOrCopyRawBuffer());
|
||||
return Some(SourceBufferHolder(std::move(chars), length));
|
||||
}
|
||||
|
||||
nsresult
|
||||
@ -2297,20 +2303,19 @@ ScriptLoader::EvaluateScript(ScriptLoadRequest* aRequest)
|
||||
return NS_OK; // An error is reported by AutoEntryScript.
|
||||
}
|
||||
|
||||
JS::Rooted<JSObject*> module(cx, moduleScript->ModuleRecord());
|
||||
MOZ_ASSERT(module);
|
||||
JS::Rooted<JSScript*> script(cx, moduleScript->Script());
|
||||
MOZ_ASSERT(script);
|
||||
|
||||
if (!moduleScript->SourceElementAssociated()) {
|
||||
rv = nsJSUtils::InitModuleSourceElement(cx, module, aRequest->Element());
|
||||
rv = nsJSUtils::InitModuleSourceElement(cx, script, aRequest->Element());
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
moduleScript->SetSourceElementAssociated();
|
||||
|
||||
// The script is now ready to be exposed to the debugger.
|
||||
JS::Rooted<JSScript*> script(cx, JS::GetModuleScript(module));
|
||||
JS::ExposeScriptToDebugger(cx, script);
|
||||
}
|
||||
|
||||
rv = nsJSUtils::ModuleEvaluate(cx, module);
|
||||
rv = nsJSUtils::ModuleEvaluate(cx, script);
|
||||
MOZ_ASSERT(NS_FAILED(rv) == aes.HasException());
|
||||
if (NS_FAILED(rv)) {
|
||||
LOG(("ScriptLoadRequest (%p): evaluation failed", aRequest));
|
||||
@ -2369,14 +2374,17 @@ ScriptLoader::EvaluateScript(ScriptLoadRequest* aRequest)
|
||||
&script);
|
||||
} else {
|
||||
MOZ_ASSERT(aRequest->IsTextSource());
|
||||
SourceBufferHolder srcBuf = GetScriptSource(cx, aRequest);
|
||||
auto srcBuf = GetScriptSource(cx, aRequest);
|
||||
|
||||
if (recordreplay::IsRecordingOrReplaying()) {
|
||||
recordreplay::NoteContentParse(this, options.filename(), "application/javascript",
|
||||
srcBuf.get(), srcBuf.length());
|
||||
if (srcBuf) {
|
||||
if (recordreplay::IsRecordingOrReplaying()) {
|
||||
recordreplay::NoteContentParse(this, options.filename(), "application/javascript",
|
||||
srcBuf->get(), srcBuf->length());
|
||||
}
|
||||
rv = exec.CompileAndExec(options, *srcBuf, &script);
|
||||
} else {
|
||||
rv = NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
rv = exec.CompileAndExec(options, srcBuf, &script);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -24,6 +24,7 @@
|
||||
#include "mozilla/dom/ScriptLoadRequest.h"
|
||||
#include "mozilla/dom/SRIMetadata.h"
|
||||
#include "mozilla/dom/SRICheck.h"
|
||||
#include "mozilla/Maybe.h"
|
||||
#include "mozilla/MozPromise.h"
|
||||
#include "mozilla/net/ReferrerPolicy.h"
|
||||
#include "mozilla/Vector.h"
|
||||
@ -506,8 +507,8 @@ private:
|
||||
|
||||
void MaybeMoveToLoadedList(ScriptLoadRequest* aRequest);
|
||||
|
||||
JS::SourceBufferHolder GetScriptSource(JSContext* aCx,
|
||||
ScriptLoadRequest* aRequest);
|
||||
mozilla::Maybe<JS::SourceBufferHolder> GetScriptSource(JSContext* aCx,
|
||||
ScriptLoadRequest* aRequest);
|
||||
|
||||
void SetModuleFetchStarted(ModuleLoadRequest *aRequest);
|
||||
void SetModuleFetchFinishedAndResumeWaitingRequests(ModuleLoadRequest* aRequest,
|
||||
@ -519,8 +520,8 @@ private:
|
||||
RefPtr<mozilla::GenericPromise> WaitForModuleFetch(nsIURI* aURL);
|
||||
ModuleScript* GetFetchedModule(nsIURI* aURL) const;
|
||||
|
||||
friend JSObject*
|
||||
HostResolveImportedModule(JSContext* aCx, JS::Handle<JSObject*> aModule,
|
||||
friend JSScript*
|
||||
HostResolveImportedModule(JSContext* aCx, JS::Handle<JSScript*> aScript,
|
||||
JS::Handle<JSString*> aSpecifier);
|
||||
|
||||
// Returns wether we should save the bytecode of this script after the
|
||||
|
@ -114,6 +114,12 @@ SVGImageElement::Href()
|
||||
: mStringAttributes[XLINK_HREF].ToDOMAnimatedString(this);
|
||||
}
|
||||
|
||||
void
|
||||
SVGImageElement::GetDecoding(nsAString& aValue)
|
||||
{
|
||||
GetEnumAttr(nsGkAtoms::decoding, kDecodingTableDefault->tag, aValue);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
nsresult
|
||||
@ -152,6 +158,24 @@ SVGImageElement::AsyncEventRunning(AsyncEventDispatcher* aEvent)
|
||||
//----------------------------------------------------------------------
|
||||
// nsIContent methods:
|
||||
|
||||
bool
|
||||
SVGImageElement::ParseAttribute(int32_t aNamespaceID,
|
||||
nsAtom* aAttribute,
|
||||
const nsAString& aValue,
|
||||
nsIPrincipal* aMaybeScriptedPrincipal,
|
||||
nsAttrValue& aResult)
|
||||
{
|
||||
if (aNamespaceID == kNameSpaceID_None) {
|
||||
if (aAttribute == nsGkAtoms::decoding) {
|
||||
return aResult.ParseEnumValue(aValue, kDecodingTable, false,
|
||||
kDecodingTableDefault);
|
||||
}
|
||||
}
|
||||
|
||||
return SVGImageElementBase::ParseAttribute(aNamespaceID, aAttribute, aValue,
|
||||
aMaybeScriptedPrincipal, aResult);
|
||||
}
|
||||
|
||||
nsresult
|
||||
SVGImageElement::AfterSetAttr(int32_t aNamespaceID, nsAtom* aName,
|
||||
const nsAttrValue* aValue,
|
||||
@ -168,6 +192,12 @@ SVGImageElement::AfterSetAttr(int32_t aNamespaceID, nsAtom* aName,
|
||||
} else {
|
||||
CancelImageRequests(aNotify);
|
||||
}
|
||||
} else if (aName == nsGkAtoms::decoding &&
|
||||
aNamespaceID == kNameSpaceID_None) {
|
||||
// Request sync or async image decoding.
|
||||
SetSyncDecodingHint(aValue &&
|
||||
static_cast<ImageDecodingType>(aValue->GetEnumValue())
|
||||
== ImageDecodingType::Sync);
|
||||
}
|
||||
return SVGImageElementBase::AfterSetAttr(aNamespaceID, aName,
|
||||
aValue, aOldValue,
|
||||
|
@ -45,6 +45,11 @@ public:
|
||||
virtual void AsyncEventRunning(AsyncEventDispatcher* aEvent) override;
|
||||
|
||||
// nsIContent interface
|
||||
bool ParseAttribute(int32_t aNamespaceID,
|
||||
nsAtom* aAttribute,
|
||||
const nsAString& aValue,
|
||||
nsIPrincipal* aMaybeScriptedPrincipal,
|
||||
nsAttrValue& aResult) override;
|
||||
virtual nsresult AfterSetAttr(int32_t aNamespaceID, nsAtom* aName,
|
||||
const nsAttrValue* aValue,
|
||||
const nsAttrValue* aOldValue,
|
||||
@ -81,6 +86,12 @@ public:
|
||||
already_AddRefed<DOMSVGAnimatedPreserveAspectRatio> PreserveAspectRatio();
|
||||
already_AddRefed<SVGAnimatedString> Href();
|
||||
|
||||
void SetDecoding(const nsAString& aDecoding, ErrorResult& aError)
|
||||
{
|
||||
SetAttr(nsGkAtoms::decoding, aDecoding, aError);
|
||||
}
|
||||
void GetDecoding(nsAString& aValue);
|
||||
|
||||
protected:
|
||||
nsresult LoadSVGImage(bool aForce, bool aNotify);
|
||||
|
||||
|
@ -30,6 +30,3 @@ BROWSER_CHROME_MANIFESTS += [ 'tests/browser.ini' ]
|
||||
include('/ipc/chromium/chromium-config.mozbuild')
|
||||
|
||||
FINAL_LIBRARY = 'xul'
|
||||
|
||||
if CONFIG['MOZ_PGO'] and CONFIG['CC_TYPE'] == 'clang-cl':
|
||||
AllowCompilerWarnings() # workaround for bug 1090497
|
||||
|
@ -407,6 +407,11 @@ partial interface Document {
|
||||
[ChromeOnly, Throws]
|
||||
readonly attribute Promise<Document> documentReadyForIdle;
|
||||
|
||||
// Lazily created command dispatcher, returns null if the document is not
|
||||
// chrome privileged.
|
||||
[ChromeOnly]
|
||||
readonly attribute XULCommandDispatcher? commandDispatcher;
|
||||
|
||||
[ChromeOnly]
|
||||
attribute Node? popupNode;
|
||||
|
||||
|
@ -37,6 +37,8 @@ interface HTMLImageElement : HTMLElement {
|
||||
attribute unsigned long width;
|
||||
[CEReactions, SetterThrows]
|
||||
attribute unsigned long height;
|
||||
[CEReactions, SetterThrows]
|
||||
attribute DOMString decoding;
|
||||
readonly attribute unsigned long naturalWidth;
|
||||
readonly attribute unsigned long naturalHeight;
|
||||
readonly attribute boolean complete;
|
||||
|
@ -21,6 +21,8 @@ interface SVGImageElement : SVGGraphicsElement {
|
||||
readonly attribute SVGAnimatedLength height;
|
||||
[Constant]
|
||||
readonly attribute SVGAnimatedPreserveAspectRatio preserveAspectRatio;
|
||||
[CEReactions, SetterThrows]
|
||||
attribute DOMString decoding;
|
||||
};
|
||||
|
||||
SVGImageElement implements MozImageLoadingContent;
|
||||
|
@ -17,12 +17,15 @@ interface TextDecoder {
|
||||
readonly attribute DOMString encoding;
|
||||
[Constant]
|
||||
readonly attribute boolean fatal;
|
||||
[Constant]
|
||||
readonly attribute boolean ignoreBOM;
|
||||
[Throws]
|
||||
USVString decode(optional BufferSource input, optional TextDecodeOptions options);
|
||||
};
|
||||
|
||||
dictionary TextDecoderOptions {
|
||||
boolean fatal = false;
|
||||
boolean ignoreBOM = false;
|
||||
};
|
||||
|
||||
dictionary TextDecodeOptions {
|
||||
|
@ -6,7 +6,6 @@
|
||||
*/
|
||||
|
||||
interface MozTreeView;
|
||||
interface nsIScriptableRegion;
|
||||
|
||||
dictionary TreeCellInfo {
|
||||
long row = 0;
|
||||
@ -55,11 +54,6 @@ interface TreeBoxObject : BoxObject {
|
||||
*/
|
||||
readonly attribute long horizontalPosition;
|
||||
|
||||
/**
|
||||
* Return the region for the visible parts of the selection, in device pixels
|
||||
*/
|
||||
readonly attribute nsIScriptableRegion selectionRegion;
|
||||
|
||||
/**
|
||||
* Get the index of the first visible row.
|
||||
*/
|
||||
|
@ -10,8 +10,6 @@ interface MozObserver;
|
||||
[Func="IsChromeOrXBL"]
|
||||
interface XULDocument : Document {
|
||||
|
||||
readonly attribute XULCommandDispatcher? commandDispatcher;
|
||||
|
||||
[Throws]
|
||||
void addBroadcastListenerFor(Element broadcaster, Element observer,
|
||||
DOMString attr);
|
||||
|
@ -47,7 +47,6 @@
|
||||
#include "nsString.h"
|
||||
#include "nsPIDOMWindow.h"
|
||||
#include "nsPIWindowRoot.h"
|
||||
#include "nsXULCommandDispatcher.h"
|
||||
#include "nsXULElement.h"
|
||||
#include "nsXULPrototypeCache.h"
|
||||
#include "mozilla/Logging.h"
|
||||
@ -235,14 +234,12 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(XULDocument, XMLDocument)
|
||||
// XXX tmp->mContextStack?
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mCurrentPrototype)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mCommandDispatcher)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPrototypes)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mLocalStore)
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(XULDocument, XMLDocument)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mCommandDispatcher)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mLocalStore)
|
||||
//XXX We should probably unlink all the objects we traverse.
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
|
||||
@ -1019,16 +1016,7 @@ XULDocument::AddElementToDocumentPre(Element* aElement)
|
||||
AddToIdTable(aElement, id);
|
||||
}
|
||||
|
||||
// 2. If the element is a 'command updater' (i.e., has a
|
||||
// "commandupdater='true'" attribute), then add the element to the
|
||||
// document's command dispatcher
|
||||
if (aElement->AttrValueIs(kNameSpaceID_None, nsGkAtoms::commandupdater,
|
||||
nsGkAtoms::_true, eCaseMatters)) {
|
||||
rv = nsXULContentUtils::SetCommandUpdater(this, aElement);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
}
|
||||
|
||||
// 3. Check for a broadcaster hookup attribute, in which case
|
||||
// 2. Check for a broadcaster hookup attribute, in which case
|
||||
// we'll hook the node up as a listener on a broadcaster.
|
||||
bool listener, resolved;
|
||||
rv = CheckBroadcasterHookup(aElement, &listener, &resolved);
|
||||
@ -1106,7 +1094,7 @@ XULDocument::RemoveSubtreeFromDocument(nsIContent* aContent)
|
||||
nsXBLService::DetachGlobalKeyHandler(aElement);
|
||||
}
|
||||
|
||||
// 1. Remove any children from the document.
|
||||
// Remove any children from the document.
|
||||
for (nsIContent* child = aElement->GetLastChild();
|
||||
child;
|
||||
child = child->GetPreviousSibling()) {
|
||||
@ -1125,15 +1113,7 @@ XULDocument::RemoveSubtreeFromDocument(nsIContent* aContent)
|
||||
RemoveFromIdTable(aElement, id);
|
||||
}
|
||||
|
||||
// 3. If the element is a 'command updater', then remove the
|
||||
// element from the document's command dispatcher.
|
||||
if (aElement->AttrValueIs(kNameSpaceID_None, nsGkAtoms::commandupdater,
|
||||
nsGkAtoms::_true, eCaseMatters)) {
|
||||
rv = mCommandDispatcher->RemoveCommandUpdater(aElement);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
}
|
||||
|
||||
// 4. Remove the element from our broadcaster map, since it is no longer
|
||||
// Remove the element from our broadcaster map, since it is no longer
|
||||
// in the document.
|
||||
nsCOMPtr<Element> broadcaster, listener;
|
||||
nsAutoString attribute, broadcasterID;
|
||||
@ -1171,9 +1151,6 @@ XULDocument::Init()
|
||||
nsresult rv = XMLDocument::Init();
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// Create our command dispatcher and hook it up.
|
||||
mCommandDispatcher = new nsXULCommandDispatcher(this);
|
||||
|
||||
if (gRefCnt++ == 0) {
|
||||
// ensure that the XUL prototype cache is instantiated successfully,
|
||||
// so that we can use nsXULPrototypeCache::GetInstance() without
|
||||
|
@ -15,7 +15,6 @@
|
||||
#include "mozilla/StyleSheet.h"
|
||||
#include "nsForwardReference.h"
|
||||
#include "nsIContent.h"
|
||||
#include "nsIDOMXULCommandDispatcher.h"
|
||||
#include "nsCOMArray.h"
|
||||
#include "nsIURI.h"
|
||||
#include "nsIStreamListener.h"
|
||||
@ -136,10 +135,6 @@ public:
|
||||
void TraceProtos(JSTracer* aTrc);
|
||||
|
||||
// WebIDL API
|
||||
nsIDOMXULCommandDispatcher* GetCommandDispatcher() const
|
||||
{
|
||||
return mCommandDispatcher;
|
||||
}
|
||||
void AddBroadcastListenerFor(Element& aBroadcaster, Element& aListener,
|
||||
const nsAString& aAttr, ErrorResult& aRv);
|
||||
void RemoveBroadcastListenerFor(Element& aBroadcaster, Element& aListener,
|
||||
@ -220,8 +215,6 @@ protected:
|
||||
*/
|
||||
bool mStillWalking;
|
||||
|
||||
nsCOMPtr<nsIDOMXULCommandDispatcher> mCommandDispatcher; // [OWNER] of the focus tracker
|
||||
|
||||
uint32_t mPendingSheets;
|
||||
|
||||
/**
|
||||
|
@ -16,6 +16,7 @@ MOCHITEST_CHROME_MANIFESTS += ['test/chrome.ini']
|
||||
|
||||
if CONFIG['MOZ_XUL']:
|
||||
EXPORTS += [
|
||||
'nsXULCommandDispatcher.h',
|
||||
'nsXULElement.h',
|
||||
]
|
||||
|
||||
|
@ -86,48 +86,3 @@ nsXULContentUtils::FindChildByTag(nsIContent* aElement,
|
||||
*aResult = nullptr;
|
||||
return NS_RDF_NO_VALUE; // not found
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsXULContentUtils::SetCommandUpdater(nsIDocument* aDocument, Element* aElement)
|
||||
{
|
||||
// Deal with setting up a 'commandupdater'. Pulls the 'events' and
|
||||
// 'targets' attributes off of aElement, and adds it to the
|
||||
// document's command dispatcher.
|
||||
MOZ_ASSERT(aDocument != nullptr, "null ptr");
|
||||
if (! aDocument)
|
||||
return NS_ERROR_NULL_POINTER;
|
||||
|
||||
MOZ_ASSERT(aElement != nullptr, "null ptr");
|
||||
if (! aElement)
|
||||
return NS_ERROR_NULL_POINTER;
|
||||
|
||||
nsresult rv;
|
||||
|
||||
NS_ASSERTION(aDocument->IsXULDocument(), "not a xul document");
|
||||
if (! aDocument->IsXULDocument())
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
|
||||
XULDocument* xuldoc = aDocument->AsXULDocument();
|
||||
nsCOMPtr<nsIDOMXULCommandDispatcher> dispatcher =
|
||||
xuldoc->GetCommandDispatcher();
|
||||
NS_ASSERTION(dispatcher != nullptr, "no dispatcher");
|
||||
if (! dispatcher)
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
|
||||
nsAutoString events;
|
||||
aElement->GetAttr(kNameSpaceID_None, nsGkAtoms::events, events);
|
||||
if (events.IsEmpty())
|
||||
events.Assign('*');
|
||||
|
||||
nsAutoString targets;
|
||||
aElement->GetAttr(kNameSpaceID_None, nsGkAtoms::targets, targets);
|
||||
|
||||
if (targets.IsEmpty())
|
||||
targets.Assign('*');
|
||||
|
||||
rv = dispatcher->AddCommandUpdater(aElement, events, targets);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -45,9 +45,6 @@ public:
|
||||
nsAtom* aTag,
|
||||
mozilla::dom::Element** aResult);
|
||||
|
||||
static nsresult
|
||||
SetCommandUpdater(nsIDocument* aDocument, mozilla::dom::Element* aElement);
|
||||
|
||||
static nsICollation*
|
||||
GetCollation();
|
||||
};
|
||||
|
@ -56,6 +56,16 @@ public:
|
||||
MOZ_ALWAYS_INLINE T& Right() { return right; }
|
||||
MOZ_ALWAYS_INLINE T& Top() { return top; }
|
||||
MOZ_ALWAYS_INLINE T& Bottom() { return bottom; }
|
||||
T Area() const { return Width() * Height(); }
|
||||
|
||||
void Inflate(T aD) { Inflate(aD, aD); }
|
||||
void Inflate(T aDx, T aDy)
|
||||
{
|
||||
left -= aDx;
|
||||
top -= aDy;
|
||||
right += aDx;
|
||||
bottom += aDy;
|
||||
}
|
||||
|
||||
MOZ_ALWAYS_INLINE void SetBox(T aLeft, T aTop, T aRight, T aBottom)
|
||||
{
|
||||
@ -80,7 +90,9 @@ public:
|
||||
|
||||
static Sub FromRect(const Rect& aRect)
|
||||
{
|
||||
MOZ_ASSERT(!aRect.Overflows());
|
||||
if (aRect.Overflows()) {
|
||||
return Sub();
|
||||
}
|
||||
return Sub(aRect.x, aRect.y, aRect.XMost(), aRect.YMost());
|
||||
}
|
||||
|
||||
@ -91,6 +103,9 @@ public:
|
||||
result.top = std::max<T>(top, aOther.top);
|
||||
result.right = std::min<T>(right, aOther.right);
|
||||
result.bottom = std::min<T>(bottom, aOther.bottom);
|
||||
if (result.right < result.left || result.bottom < result.top) {
|
||||
result.SizeTo(0, 0);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -103,6 +118,137 @@ public:
|
||||
return left == aOther.left && top == aOther.top &&
|
||||
right == aOther.right && bottom == aOther.bottom;
|
||||
}
|
||||
|
||||
bool IsEqualInterior(const Sub& aRect) const
|
||||
{
|
||||
return IsEqualEdges(aRect) || (IsEmpty() && aRect.IsEmpty());
|
||||
}
|
||||
|
||||
MOZ_ALWAYS_INLINE void MoveBy(T aDx, T aDy) { left += aDx; right += aDx; top += aDy; bottom += aDy; }
|
||||
MOZ_ALWAYS_INLINE void MoveBy(const Point& aPoint) { left += aPoint.x; right += aPoint.x; top += aPoint.y; bottom += aPoint.y; }
|
||||
MOZ_ALWAYS_INLINE void SizeTo(T aWidth, T aHeight) { right = left + aWidth; bottom = top + aHeight; }
|
||||
|
||||
bool Contains(const Sub& aRect) const
|
||||
{
|
||||
return aRect.IsEmpty() ||
|
||||
(left <= aRect.left && aRect.right <= right &&
|
||||
top <= aRect.top && aRect.bottom <= bottom);
|
||||
}
|
||||
bool Contains(T aX, T aY) const
|
||||
{
|
||||
return (left <= aX && aX < right &&
|
||||
top <= aY && aY < bottom);
|
||||
}
|
||||
|
||||
bool Intersects(const Sub& aRect) const
|
||||
{
|
||||
return !IsEmpty() && !aRect.IsEmpty() &&
|
||||
left < aRect.right && aRect.left < right &&
|
||||
top < aRect.bottom && aRect.top < bottom;
|
||||
}
|
||||
|
||||
void SetEmpty() {
|
||||
left = right = top = bottom = 0;
|
||||
}
|
||||
|
||||
// Returns the smallest rectangle that contains both the area of both
|
||||
// this and aRect2.
|
||||
// Thus, empty input rectangles are ignored.
|
||||
// If both rectangles are empty, returns this.
|
||||
// WARNING! This is not safe against overflow, prefer using SafeUnion instead
|
||||
// when dealing with int-based rects.
|
||||
MOZ_MUST_USE Sub Union(const Sub& aRect) const
|
||||
{
|
||||
if (IsEmpty()) {
|
||||
return aRect;
|
||||
} else if (aRect.IsEmpty()) {
|
||||
return *static_cast<const Sub*>(this);
|
||||
} else {
|
||||
return UnionEdges(aRect);
|
||||
}
|
||||
}
|
||||
// Returns the smallest rectangle that contains both the points (including
|
||||
// edges) of both aRect1 and aRect2.
|
||||
// Thus, empty input rectangles are allowed to affect the result.
|
||||
// WARNING! This is not safe against overflow, prefer using SafeUnionEdges
|
||||
// instead when dealing with int-based rects.
|
||||
MOZ_MUST_USE Sub UnionEdges(const Sub& aRect) const
|
||||
{
|
||||
Sub result;
|
||||
result.left = std::min(left, aRect.left);
|
||||
result.top = std::min(top, aRect.top);
|
||||
result.right = std::max(XMost(), aRect.XMost());
|
||||
result.bottom = std::max(YMost(), aRect.YMost());
|
||||
return result;
|
||||
}
|
||||
|
||||
// Scale 'this' by aScale without doing any rounding.
|
||||
void Scale(T aScale) { Scale(aScale, aScale); }
|
||||
// Scale 'this' by aXScale and aYScale, without doing any rounding.
|
||||
void Scale(T aXScale, T aYScale)
|
||||
{
|
||||
right = XMost() * aXScale;
|
||||
bottom = YMost() * aYScale;
|
||||
left = left * aXScale;
|
||||
top = top * aYScale;
|
||||
}
|
||||
// Scale 'this' by aScale, converting coordinates to integers so that the result is
|
||||
// the smallest integer-coordinate rectangle containing the unrounded result.
|
||||
// Note: this can turn an empty rectangle into a non-empty rectangle
|
||||
void ScaleRoundOut(double aScale) { ScaleRoundOut(aScale, aScale); }
|
||||
// Scale 'this' by aXScale and aYScale, converting coordinates to integers so
|
||||
// that the result is the smallest integer-coordinate rectangle containing the
|
||||
// unrounded result.
|
||||
// Note: this can turn an empty rectangle into a non-empty rectangle
|
||||
void ScaleRoundOut(double aXScale, double aYScale)
|
||||
{
|
||||
right = static_cast<T>(ceil(double(XMost()) * aXScale));
|
||||
bottom = static_cast<T>(ceil(double(YMost()) * aYScale));
|
||||
left = static_cast<T>(floor(double(left) * aXScale));
|
||||
top = static_cast<T>(floor(double(top) * aYScale));
|
||||
}
|
||||
// Scale 'this' by aScale, converting coordinates to integers so that the result is
|
||||
// the largest integer-coordinate rectangle contained by the unrounded result.
|
||||
void ScaleRoundIn(double aScale) { ScaleRoundIn(aScale, aScale); }
|
||||
// Scale 'this' by aXScale and aYScale, converting coordinates to integers so
|
||||
// that the result is the largest integer-coordinate rectangle contained by the
|
||||
// unrounded result.
|
||||
void ScaleRoundIn(double aXScale, double aYScale)
|
||||
{
|
||||
right = static_cast<T>(floor(double(XMost()) * aXScale));
|
||||
bottom = static_cast<T>(floor(double(YMost()) * aYScale));
|
||||
left = static_cast<T>(ceil(double(left) * aXScale));
|
||||
top = static_cast<T>(ceil(double(top) * aYScale));
|
||||
}
|
||||
// Scale 'this' by 1/aScale, converting coordinates to integers so that the result is
|
||||
// the smallest integer-coordinate rectangle containing the unrounded result.
|
||||
// Note: this can turn an empty rectangle into a non-empty rectangle
|
||||
void ScaleInverseRoundOut(double aScale) { ScaleInverseRoundOut(aScale, aScale); }
|
||||
// Scale 'this' by 1/aXScale and 1/aYScale, converting coordinates to integers so
|
||||
// that the result is the smallest integer-coordinate rectangle containing the
|
||||
// unrounded result.
|
||||
// Note: this can turn an empty rectangle into a non-empty rectangle
|
||||
void ScaleInverseRoundOut(double aXScale, double aYScale)
|
||||
{
|
||||
right = static_cast<T>(ceil(double(XMost()) / aXScale));
|
||||
bottom = static_cast<T>(ceil(double(YMost()) / aYScale));
|
||||
left = static_cast<T>(floor(double(left) / aXScale));
|
||||
top = static_cast<T>(floor(double(top) / aYScale));
|
||||
}
|
||||
// Scale 'this' by 1/aScale, converting coordinates to integers so that the result is
|
||||
// the largest integer-coordinate rectangle contained by the unrounded result.
|
||||
void ScaleInverseRoundIn(double aScale) { ScaleInverseRoundIn(aScale, aScale); }
|
||||
// Scale 'this' by 1/aXScale and 1/aYScale, converting coordinates to integers so
|
||||
// that the result is the largest integer-coordinate rectangle contained by the
|
||||
// unrounded result.
|
||||
void ScaleInverseRoundIn(double aXScale, double aYScale)
|
||||
{
|
||||
right = static_cast<T>(floor(double(XMost()) / aXScale));
|
||||
bottom = static_cast<T>(floor(double(YMost()) / aYScale));
|
||||
left = static_cast<T>(ceil(double(left) / aXScale));
|
||||
top = static_cast<T>(ceil(double(top) / aYScale));
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
template <class Units>
|
||||
|
@ -2,7 +2,7 @@ This is the Sanitiser for OpenType project, from http://code.google.com/p/ots/.
|
||||
|
||||
Our reference repository is https://github.com/khaledhosny/ots/.
|
||||
|
||||
Current revision: 7c8f3fc9cf8b79edb241d94a4847968a5009e78d (7.0.0)
|
||||
Current revision: b2d8733abf5b141f20881b071b68d2dbe73c5baf (7.1.7)
|
||||
|
||||
Upstream files included: LICENSE, src/, include/, tests/*.cc
|
||||
|
||||
|
@ -1,7 +1,8 @@
|
||||
diff --git a/gfx/ots/src/glat.cc b/gfx/ots/src/glat.cc
|
||||
--- a/gfx/ots/src/glat.cc
|
||||
+++ b/gfx/ots/src/glat.cc
|
||||
@@ -5,7 +5,7 @@
|
||||
@@ -4,9 +4,9 @@
|
||||
|
||||
#include "glat.h"
|
||||
|
||||
#include "gloc.h"
|
||||
@ -10,7 +11,9 @@ diff --git a/gfx/ots/src/glat.cc b/gfx/ots/src/glat.cc
|
||||
#include <list>
|
||||
|
||||
namespace ots {
|
||||
@@ -201,14 +201,15 @@ bool OpenTypeGLAT_v3::Parse(const uint8_t* data, size_t length,
|
||||
|
||||
@@ -200,16 +200,17 @@ bool OpenTypeGLAT_v3::Parse(const uint8_
|
||||
if (prevent_decompression) {
|
||||
return DropGraphite("Illegal nested compression");
|
||||
}
|
||||
std::vector<uint8_t> decompressed(this->compHead & FULL_SIZE);
|
||||
@ -23,7 +26,7 @@ diff --git a/gfx/ots/src/glat.cc b/gfx/ots/src/glat.cc
|
||||
+ reinterpret_cast<char*>(decompressed.data()),
|
||||
decompressed.size(), // target output size
|
||||
- decompressed.size()); // output buffer size
|
||||
- if (ret != decompressed.size()) {
|
||||
- if (ret < 0 || unsigned(ret) != decompressed.size()) {
|
||||
- return DropGraphite("Decompression failed with error code %d", ret);
|
||||
+ &outputSize); // return output size
|
||||
+ if (!ret || outputSize != decompressed.size()) {
|
||||
@ -31,10 +34,12 @@ diff --git a/gfx/ots/src/glat.cc b/gfx/ots/src/glat.cc
|
||||
}
|
||||
return this->Parse(decompressed.data(), decompressed.size(), true);
|
||||
}
|
||||
default:
|
||||
diff --git a/gfx/ots/src/silf.cc b/gfx/ots/src/silf.cc
|
||||
--- a/gfx/ots/src/silf.cc
|
||||
+++ b/gfx/ots/src/silf.cc
|
||||
@@ -5,7 +5,7 @@
|
||||
@@ -4,9 +4,9 @@
|
||||
|
||||
#include "silf.h"
|
||||
|
||||
#include "name.h"
|
||||
@ -43,7 +48,9 @@ diff --git a/gfx/ots/src/silf.cc b/gfx/ots/src/silf.cc
|
||||
#include <cmath>
|
||||
|
||||
namespace ots {
|
||||
@@ -39,14 +39,15 @@ bool OpenTypeSILF::Parse(const uint8_t* data, size_t length,
|
||||
|
||||
@@ -38,16 +38,17 @@ bool OpenTypeSILF::Parse(const uint8_t*
|
||||
if (prevent_decompression) {
|
||||
return DropGraphite("Illegal nested compression");
|
||||
}
|
||||
std::vector<uint8_t> decompressed(this->compHead & FULL_SIZE);
|
||||
@ -56,7 +63,7 @@ diff --git a/gfx/ots/src/silf.cc b/gfx/ots/src/silf.cc
|
||||
+ reinterpret_cast<char*>(decompressed.data()),
|
||||
decompressed.size(), // target output size
|
||||
- decompressed.size()); // output buffer size
|
||||
- if (ret != decompressed.size()) {
|
||||
- if (ret < 0 || unsigned(ret) != decompressed.size()) {
|
||||
- return DropGraphite("Decompression failed with error code %d", ret);
|
||||
+ &outputSize); // return output size
|
||||
+ if (!ret || outputSize != decompressed.size()) {
|
||||
@ -64,3 +71,4 @@ diff --git a/gfx/ots/src/silf.cc b/gfx/ots/src/silf.cc
|
||||
}
|
||||
return this->Parse(decompressed.data(), decompressed.size(), true);
|
||||
}
|
||||
default:
|
||||
|
@ -1,7 +1,8 @@
|
||||
diff --git a/gfx/ots/include/opentype-sanitiser.h b/gfx/ots/include/opentype-sanitiser.h
|
||||
--- a/gfx/ots/include/opentype-sanitiser.h
|
||||
+++ b/gfx/ots/include/opentype-sanitiser.h
|
||||
@@ -5,6 +5,26 @@
|
||||
@@ -4,8 +4,28 @@
|
||||
|
||||
#ifndef OPENTYPE_SANITISER_H_
|
||||
#define OPENTYPE_SANITISER_H_
|
||||
|
||||
@ -28,7 +29,9 @@ diff --git a/gfx/ots/include/opentype-sanitiser.h b/gfx/ots/include/opentype-san
|
||||
#if defined(_WIN32)
|
||||
#include <stdlib.h>
|
||||
typedef signed char int8_t;
|
||||
@@ -161,7 +181,7 @@ enum TableAction {
|
||||
typedef unsigned char uint8_t;
|
||||
@@ -164,9 +184,9 @@ enum TableAction {
|
||||
TABLE_ACTION_PASSTHRU, // Serialize the table unchanged
|
||||
TABLE_ACTION_DROP // Drop the table
|
||||
};
|
||||
|
||||
@ -37,3 +40,4 @@ diff --git a/gfx/ots/include/opentype-sanitiser.h b/gfx/ots/include/opentype-san
|
||||
public:
|
||||
OTSContext() {}
|
||||
virtual ~OTSContext() {}
|
||||
|
||||
|
@ -14,6 +14,7 @@ template<typename ParentType>
|
||||
class TablePart {
|
||||
public:
|
||||
TablePart(ParentType* parent) : parent(parent) { }
|
||||
virtual ~TablePart() { }
|
||||
virtual bool ParsePart(Buffer& table) = 0;
|
||||
virtual bool SerializePart(OTSStream* out) const = 0;
|
||||
protected:
|
||||
|
@ -1393,10 +1393,10 @@ bool ParseDeviceTable(const ots::Font *font,
|
||||
return true;
|
||||
}
|
||||
if (start_size > end_size) {
|
||||
return OTS_FAILURE_MSG("bad size range: %u > %u", start_size, end_size);
|
||||
return OTS_FAILURE_MSG("Bad device table size range: %u > %u", start_size, end_size);
|
||||
}
|
||||
if (delta_format == 0 || delta_format > kMaxDeltaFormatType) {
|
||||
return OTS_FAILURE_MSG("bad delta format: %u", delta_format);
|
||||
return OTS_FAILURE_MSG("Bad device table delta format: 0x%x", delta_format);
|
||||
}
|
||||
// The number of delta values per uint16. The device table should contain
|
||||
// at least |num_units| * 2 bytes compressed data.
|
||||
|
@ -152,7 +152,7 @@ bool OpenTypeOS2::Parse(const uint8_t *data, size_t length) {
|
||||
if ((this->table.version < 4) &&
|
||||
(this->table.selection & 0x300)) {
|
||||
// bit 8 and 9 must be unset in OS/2 table versions less than 4.
|
||||
Warning("fSelection bits 8 and 9 must be unset for table version %d",
|
||||
Warning("fsSelection bits 8 and 9 must be unset for table version %d",
|
||||
this->table.version);
|
||||
}
|
||||
|
||||
|
@ -130,7 +130,7 @@ struct nsRect :
|
||||
*this = aRect1.Union(aRect2);
|
||||
}
|
||||
|
||||
#if defined(_MSC_VER) && !defined(__clang__)
|
||||
#if defined(_MSC_VER) && !defined(__clang__) && (defined(_M_X64) || defined(_M_IX86))
|
||||
// Only MSVC supports inlining intrinsics for archs you're not compiling for.
|
||||
MOZ_MUST_USE nsRect Intersect(const nsRect& aRect) const
|
||||
{
|
||||
|
@ -18,6 +18,39 @@ struct nsRectAbsolute :
|
||||
nsRectAbsolute() : Super() {}
|
||||
nsRectAbsolute(nscoord aX1, nscoord aY1, nscoord aX2, nscoord aY2) :
|
||||
Super(aX1, aY1, aX2, aY2) {}
|
||||
|
||||
MOZ_ALWAYS_INLINE nscoord SafeWidth() const
|
||||
{
|
||||
int64_t width = right;
|
||||
width -= left;
|
||||
return nscoord(std::min<int64_t>(std::numeric_limits<nscoord>::max(), width));
|
||||
}
|
||||
MOZ_ALWAYS_INLINE nscoord SafeHeight() const
|
||||
{
|
||||
int64_t height = bottom;
|
||||
height -= top;
|
||||
return nscoord(std::min<int64_t>(std::numeric_limits<nscoord>::max(), height));
|
||||
}
|
||||
|
||||
nsRect ToNSRect() const
|
||||
{
|
||||
return nsRect(left, top, nscoord(SafeWidth()), nscoord(SafeHeight()));
|
||||
}
|
||||
|
||||
MOZ_MUST_USE nsRectAbsolute UnsafeUnion(const nsRectAbsolute& aRect) const
|
||||
{
|
||||
return Super::Union(aRect);
|
||||
}
|
||||
|
||||
MOZ_ALWAYS_INLINE void MoveBy(const nsPoint& aPoint) { left += aPoint.x; right += aPoint.x; top += aPoint.y; bottom += aPoint.y; }
|
||||
|
||||
void Inflate(const nsMargin& aMargin)
|
||||
{
|
||||
left -= aMargin.left;
|
||||
top -= aMargin.top;
|
||||
right += aMargin.right;
|
||||
bottom += aMargin.bottom;
|
||||
}
|
||||
};
|
||||
|
||||
#endif /* NSRECTABSOLUTE_H */
|
||||
|
@ -63,7 +63,7 @@ nsRegion::AssertStateInternal() const
|
||||
}
|
||||
}
|
||||
|
||||
if (!(mBounds == CalculateBounds())) {
|
||||
if (!(mBounds.IsEqualEdges(CalculateBounds()))) {
|
||||
failed = true;
|
||||
}
|
||||
|
||||
@ -89,7 +89,7 @@ bool nsRegion::Contains(const nsRegion& aRgn) const
|
||||
return true;
|
||||
}
|
||||
|
||||
bool nsRegion::Intersects(const nsRect& aRect) const
|
||||
bool nsRegion::Intersects(const nsRectAbsolute& aRect) const
|
||||
{
|
||||
if (mBands.IsEmpty()) {
|
||||
return mBounds.Intersects(aRect);
|
||||
@ -130,7 +130,7 @@ void nsRegion::Inflate(const nsMargin& aMargin)
|
||||
{
|
||||
nsRegion newRegion;
|
||||
for (RectIterator iter = RectIterator(*this); !iter.Done(); iter.Next()) {
|
||||
nsRect rect = iter.Get();
|
||||
nsRectAbsolute rect = iter.GetAbsolute();
|
||||
rect.Inflate(aMargin);
|
||||
newRegion.AddRect(rect);
|
||||
}
|
||||
@ -489,7 +489,7 @@ nsRegion& nsRegion::ScaleRoundOut (float aXScale, float aYScale)
|
||||
|
||||
nsRegion newRegion;
|
||||
for (RectIterator iter = RectIterator(*this); !iter.Done(); iter.Next()) {
|
||||
nsRect rect = iter.Get();
|
||||
nsRectAbsolute rect = iter.GetAbsolute();
|
||||
rect.ScaleRoundOut(aXScale, aYScale);
|
||||
newRegion.AddRect(rect);
|
||||
}
|
||||
@ -502,7 +502,7 @@ nsRegion& nsRegion::ScaleInverseRoundOut (float aXScale, float aYScale)
|
||||
{
|
||||
nsRegion newRegion;
|
||||
for (RectIterator iter = RectIterator(*this); !iter.Done(); iter.Next()) {
|
||||
nsRect rect = iter.Get();
|
||||
nsRectAbsolute rect = iter.GetAbsolute();
|
||||
rect.ScaleInverseRoundOut(aXScale, aYScale);
|
||||
newRegion.AddRect(rect);
|
||||
}
|
||||
@ -535,7 +535,7 @@ nsRegion& nsRegion::Transform (const mozilla::gfx::Matrix4x4 &aTransform)
|
||||
nsRegion newRegion;
|
||||
for (RectIterator iter = RectIterator(*this); !iter.Done(); iter.Next()) {
|
||||
nsRect rect = nsIntRegion::ToRect(TransformRect(nsIntRegion::FromRect(iter.Get()), aTransform));
|
||||
newRegion.AddRect(rect);
|
||||
newRegion.AddRect(nsRectAbsolute::FromRect(rect));
|
||||
}
|
||||
|
||||
*this = std::move(newRegion);
|
||||
@ -552,7 +552,7 @@ nsRegion nsRegion::ScaleToOtherAppUnitsRoundOut (int32_t aFromAPP, int32_t aToAP
|
||||
for (RectIterator iter = RectIterator(*this); !iter.Done(); iter.Next()) {
|
||||
nsRect rect = iter.Get();
|
||||
rect = rect.ScaleToOtherAppUnitsRoundOut(aFromAPP, aToAPP);
|
||||
newRegion.AddRect(rect);
|
||||
newRegion.AddRect(nsRectAbsolute::FromRect(rect));
|
||||
}
|
||||
|
||||
return newRegion;
|
||||
@ -568,7 +568,7 @@ nsRegion nsRegion::ScaleToOtherAppUnitsRoundIn (int32_t aFromAPP, int32_t aToAPP
|
||||
for (RectIterator iter = RectIterator(*this); !iter.Done(); iter.Next()) {
|
||||
nsRect rect = iter.Get();
|
||||
rect = rect.ScaleToOtherAppUnitsRoundIn(aFromAPP, aToAPP);
|
||||
newRegion.AddRect(rect);
|
||||
newRegion.AddRect(nsRectAbsolute::FromRect(rect));
|
||||
}
|
||||
|
||||
return newRegion;
|
||||
@ -641,7 +641,7 @@ nsIntRegion nsRegion::ScaleToInsidePixels (float aScaleX, float aScaleY,
|
||||
*/
|
||||
|
||||
if (mBands.IsEmpty()) {
|
||||
nsIntRect rect = mBounds.ScaleToInsidePixels(aScaleX, aScaleY, aAppUnitsPerPixel);
|
||||
nsIntRect rect = mBounds.ToNSRect().ScaleToInsidePixels(aScaleX, aScaleY, aAppUnitsPerPixel);
|
||||
return nsIntRegion(rect);
|
||||
}
|
||||
|
||||
|
@ -16,6 +16,7 @@
|
||||
#include "nsError.h" // for nsresult
|
||||
#include "nsPoint.h" // for nsIntPoint, nsPoint
|
||||
#include "nsRect.h" // for mozilla::gfx::IntRect, nsRect
|
||||
#include "nsRectAbsolute.h"
|
||||
#include "nsMargin.h" // for nsIntMargin
|
||||
#include "nsRegionFwd.h" // for nsIntRegion
|
||||
#include "nsString.h" // for nsCString
|
||||
@ -120,7 +121,7 @@ struct Band
|
||||
using StripArray = AutoTArray<Strip, 2>;
|
||||
#endif
|
||||
|
||||
MOZ_IMPLICIT Band(const nsRect& aRect)
|
||||
MOZ_IMPLICIT Band(const nsRectAbsolute& aRect)
|
||||
: top(aRect.Y()), bottom(aRect.YMost())
|
||||
{
|
||||
mStrips.AppendElement(Strip{ aRect.X(), aRect.XMost() });
|
||||
@ -511,6 +512,9 @@ public:
|
||||
|
||||
nsRegion() { }
|
||||
MOZ_IMPLICIT nsRegion(const nsRect& aRect) {
|
||||
mBounds = nsRectAbsolute::FromRect(aRect);
|
||||
}
|
||||
MOZ_IMPLICIT nsRegion(const nsRectAbsolute& aRect) {
|
||||
mBounds = aRect;
|
||||
}
|
||||
explicit nsRegion(mozilla::gfx::ArrayView<pixman_box32_t> aRects)
|
||||
@ -701,7 +705,7 @@ public:
|
||||
|
||||
mBands = std::move(newBands);
|
||||
if (!mBands.Length()) {
|
||||
mBounds = nsRect();
|
||||
mBounds = nsRectAbsolute();
|
||||
} else {
|
||||
mBounds = CalculateBounds();
|
||||
}
|
||||
@ -711,13 +715,13 @@ public:
|
||||
return *this;
|
||||
}
|
||||
|
||||
nsRegion& AndWith(const nsRect& aRect)
|
||||
nsRegion& AndWith(const nsRectAbsolute& aRect)
|
||||
{
|
||||
#ifdef DEBUG_REGIONS
|
||||
class OperationStringGeneratorAndWith : public OperationStringGenerator
|
||||
{
|
||||
public:
|
||||
OperationStringGeneratorAndWith(nsRegion& aRegion, const nsRect& aRect)
|
||||
OperationStringGeneratorAndWith(nsRegion& aRegion, const nsRectAbsolute& aRect)
|
||||
: mRegion(&aRegion), mRegionCopy(aRegion), mRect(aRect)
|
||||
{
|
||||
aRegion.mCurrentOpGenerator = this;
|
||||
@ -737,7 +741,7 @@ public:
|
||||
private:
|
||||
nsRegion * mRegion;
|
||||
nsRegion mRegionCopy;
|
||||
nsRect mRect;
|
||||
nsRectAbsolute mRect;
|
||||
};
|
||||
|
||||
OperationStringGeneratorAndWith opGenerator(*this, aRect);
|
||||
@ -801,6 +805,9 @@ public:
|
||||
AssertState();
|
||||
return *this;
|
||||
}
|
||||
nsRegion& AndWith(const nsRect& aRect) {
|
||||
return AndWith(nsRectAbsolute::FromRect(aRect));
|
||||
}
|
||||
nsRegion& And(const nsRegion& aRgn1, const nsRegion& aRgn2)
|
||||
{
|
||||
if (&aRgn1 == this) {
|
||||
@ -855,7 +862,7 @@ public:
|
||||
And(mBands, aRgn1.mBands, aRgn2.mBands);
|
||||
|
||||
if (!mBands.Length()) {
|
||||
mBounds = nsRect();
|
||||
mBounds = nsRectAbsolute();
|
||||
} else {
|
||||
mBounds = CalculateBounds();
|
||||
}
|
||||
@ -868,7 +875,7 @@ public:
|
||||
{
|
||||
return And(aRegion, aRect);
|
||||
}
|
||||
nsRegion& And(const nsRegion& aRegion, const nsRect& aRect)
|
||||
nsRegion& And(const nsRegion& aRegion, const nsRectAbsolute& aRect)
|
||||
{
|
||||
if (&aRegion == this) {
|
||||
return AndWith(aRect);
|
||||
@ -877,7 +884,7 @@ public:
|
||||
class OperationStringGeneratorAnd : public OperationStringGenerator
|
||||
{
|
||||
public:
|
||||
OperationStringGeneratorAnd(nsRegion& aThisRegion, const nsRegion& aRegion, const nsRect& aRect)
|
||||
OperationStringGeneratorAnd(nsRegion& aThisRegion, const nsRegion& aRegion, const nsRectAbsolute& aRect)
|
||||
: mThisRegion(&aThisRegion), mRegion(aRegion), mRect(aRect)
|
||||
{
|
||||
aThisRegion.mCurrentOpGenerator = this;
|
||||
@ -897,7 +904,7 @@ public:
|
||||
private:
|
||||
nsRegion* mThisRegion;
|
||||
nsRegion mRegion;
|
||||
nsRect mRect;
|
||||
nsRectAbsolute mRect;
|
||||
};
|
||||
|
||||
OperationStringGeneratorAnd opGenerator(*this, aRegion, aRect);
|
||||
@ -958,6 +965,10 @@ public:
|
||||
AssertState();
|
||||
return *this;
|
||||
}
|
||||
nsRegion& And(const nsRegion& aRegion, const nsRect& aRect)
|
||||
{
|
||||
return And(aRegion, nsRectAbsolute::FromRect(aRect));
|
||||
}
|
||||
nsRegion& And(const nsRect& aRect1, const nsRect& aRect2)
|
||||
{
|
||||
nsRect tmpRect;
|
||||
@ -969,13 +980,13 @@ public:
|
||||
nsRegion& OrWith(const nsRegion& aOther)
|
||||
{
|
||||
for (RectIterator idx(aOther); !idx.Done(); idx.Next()) {
|
||||
AddRect(idx.Get());
|
||||
AddRect(idx.GetAbsolute());
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
nsRegion& OrWith(const nsRect& aOther)
|
||||
{
|
||||
AddRect(aOther);
|
||||
AddRect(nsRectAbsolute::FromRect(aOther));
|
||||
return *this;
|
||||
}
|
||||
nsRegion& Or(const nsRegion& aRgn1, const nsRegion& aRgn2)
|
||||
@ -984,7 +995,7 @@ public:
|
||||
*this = aRgn1;
|
||||
}
|
||||
for (RectIterator idx(aRgn2); !idx.Done(); idx.Next()) {
|
||||
AddRect(idx.Get());
|
||||
AddRect(idx.GetAbsolute());
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
@ -993,7 +1004,7 @@ public:
|
||||
if (&aRegion != this) {
|
||||
*this = aRegion;
|
||||
}
|
||||
AddRect(aRect);
|
||||
AddRect(nsRectAbsolute::FromRect(aRect));
|
||||
return *this;
|
||||
}
|
||||
nsRegion& Or(const nsRect& aRect, const nsRegion& aRegion)
|
||||
@ -1381,7 +1392,7 @@ public:
|
||||
|
||||
private:
|
||||
// Internal helper for executing subtraction.
|
||||
void RunSubtraction(const nsRect& aRect)
|
||||
void RunSubtraction(const nsRectAbsolute& aRect)
|
||||
{
|
||||
Strip rectStrip(aRect.X(), aRect.XMost());
|
||||
|
||||
@ -1448,7 +1459,7 @@ private:
|
||||
}
|
||||
|
||||
public:
|
||||
nsRegion& SubWith(const nsRect& aRect) {
|
||||
nsRegion& SubWith(const nsRectAbsolute& aRect) {
|
||||
if (!mBounds.Intersects(aRect)) {
|
||||
return *this;
|
||||
}
|
||||
@ -1462,7 +1473,7 @@ public:
|
||||
class OperationStringGeneratorSubWith : public OperationStringGenerator
|
||||
{
|
||||
public:
|
||||
OperationStringGeneratorSubWith(nsRegion& aRegion, const nsRect& aRect)
|
||||
OperationStringGeneratorSubWith(nsRegion& aRegion, const nsRectAbsolute& aRect)
|
||||
: mRegion(&aRegion), mRegionCopy(aRegion), mRect(aRect)
|
||||
{
|
||||
aRegion.mCurrentOpGenerator = this;
|
||||
@ -1482,7 +1493,7 @@ public:
|
||||
private:
|
||||
nsRegion * mRegion;
|
||||
nsRegion mRegionCopy;
|
||||
nsRect mRect;
|
||||
nsRectAbsolute mRect;
|
||||
};
|
||||
|
||||
OperationStringGeneratorSubWith opGenerator(*this, aRect);
|
||||
@ -1494,7 +1505,7 @@ public:
|
||||
|
||||
RunSubtraction(aRect);
|
||||
|
||||
if (aRect.x <= mBounds.x || aRect.y <= mBounds.y ||
|
||||
if (aRect.X() <= mBounds.X() || aRect.Y() <= mBounds.Y() ||
|
||||
aRect.XMost() >= mBounds.XMost() || aRect.YMost() >= mBounds.YMost()) {
|
||||
mBounds = CalculateBounds();
|
||||
}
|
||||
@ -1502,7 +1513,7 @@ public:
|
||||
AssertState();
|
||||
return *this;
|
||||
}
|
||||
nsRegion& Sub(const nsRegion& aRegion, const nsRect& aRect)
|
||||
nsRegion& Sub(const nsRegion& aRegion, const nsRectAbsolute& aRect)
|
||||
{
|
||||
if (aRect.Contains(aRegion.mBounds)) {
|
||||
SetEmpty();
|
||||
@ -1515,7 +1526,7 @@ public:
|
||||
class OperationStringGeneratorSub : public OperationStringGenerator
|
||||
{
|
||||
public:
|
||||
OperationStringGeneratorSub(nsRegion& aRegion, const nsRegion& aRegionOther, const nsRect& aRect)
|
||||
OperationStringGeneratorSub(nsRegion& aRegion, const nsRegion& aRegionOther, const nsRectAbsolute& aRect)
|
||||
: mRegion(&aRegion), mRegionOther(aRegionOther), mRect(aRect)
|
||||
{
|
||||
aRegion.mCurrentOpGenerator = this;
|
||||
@ -1535,7 +1546,7 @@ public:
|
||||
private:
|
||||
nsRegion * mRegion;
|
||||
nsRegion mRegionOther;
|
||||
nsRect mRect;
|
||||
nsRectAbsolute mRect;
|
||||
};
|
||||
|
||||
OperationStringGeneratorSub opGenerator(*this, aRegion, aRect);
|
||||
@ -1632,16 +1643,33 @@ public:
|
||||
EnsureSimplified();
|
||||
return *this;
|
||||
}
|
||||
nsRegion& SubWith(const nsRect& aRect) {
|
||||
return SubWith(nsRectAbsolute::FromRect(aRect));
|
||||
}
|
||||
nsRegion& Sub(const nsRect& aRect, const nsRegion& aRegion)
|
||||
{
|
||||
Copy(aRect);
|
||||
return SubWith(aRegion);
|
||||
}
|
||||
nsRegion& Sub(const nsRectAbsolute& aRect, const nsRegion& aRegion)
|
||||
{
|
||||
Copy(aRect);
|
||||
return SubWith(aRegion);
|
||||
}
|
||||
nsRegion& Sub(const nsRect& aRect1, const nsRect& aRect2)
|
||||
{
|
||||
Copy(aRect1);
|
||||
return SubWith(aRect2);
|
||||
}
|
||||
nsRegion& Sub(const nsRegion& aRegion, const nsRect& aRect)
|
||||
{
|
||||
return Sub(aRegion, nsRectAbsolute::FromRect(aRect));
|
||||
}
|
||||
nsRegion& Sub(const nsRectAbsolute& aRect1, const nsRectAbsolute& aRect2)
|
||||
{
|
||||
Copy(aRect1);
|
||||
return SubWith(aRect2);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the given point is inside the region. A region
|
||||
@ -1673,7 +1701,7 @@ public:
|
||||
}
|
||||
return false;
|
||||
}
|
||||
bool Contains(const nsRect& aRect) const
|
||||
bool Contains(const nsRectAbsolute& aRect) const
|
||||
{
|
||||
if (aRect.IsEmpty()) {
|
||||
return false;
|
||||
@ -1726,9 +1754,16 @@ public:
|
||||
}
|
||||
return false;
|
||||
}
|
||||
bool Contains(const nsRect& aRect) const
|
||||
{
|
||||
return Contains(nsRectAbsolute::FromRect(aRect));
|
||||
}
|
||||
|
||||
bool Contains(const nsRegion& aRgn) const;
|
||||
bool Intersects(const nsRect& aRect) const;
|
||||
bool Intersects(const nsRectAbsolute& aRect) const;
|
||||
bool Intersects(const nsRect& aRect) const {
|
||||
return Intersects(nsRectAbsolute::FromRect(aRect));
|
||||
}
|
||||
|
||||
void MoveBy(int32_t aXOffset, int32_t aYOffset)
|
||||
{
|
||||
@ -1848,7 +1883,8 @@ public:
|
||||
|
||||
return rects;
|
||||
}
|
||||
const nsRect GetBounds() const { return mBounds; }
|
||||
const nsRect GetBounds() const { return mBounds.ToNSRect(); }
|
||||
const nsRectAbsolute GetAbsoluteBounds() const { return mBounds; }
|
||||
uint64_t Area() const;
|
||||
|
||||
/**
|
||||
@ -1940,6 +1976,13 @@ private:
|
||||
}
|
||||
|
||||
nsRegion& Copy(const nsRect& aRect)
|
||||
{
|
||||
mBands.Clear();
|
||||
mBounds = nsRectAbsolute::FromRect(aRect);
|
||||
return *this;
|
||||
}
|
||||
|
||||
nsRegion& Copy(const nsRectAbsolute& aRect)
|
||||
{
|
||||
mBands.Clear();
|
||||
mBounds = aRect;
|
||||
@ -1952,20 +1995,19 @@ private:
|
||||
}
|
||||
}
|
||||
|
||||
static inline nsRect BoxToRect(const pixman_box32_t &aBox)
|
||||
static inline nsRectAbsolute BoxToRect(const pixman_box32_t &aBox)
|
||||
{
|
||||
return nsRect(aBox.x1, aBox.y1,
|
||||
aBox.x2 - aBox.x1,
|
||||
aBox.y2 - aBox.y1);
|
||||
return nsRectAbsolute(aBox.x1, aBox.y1,
|
||||
aBox.x2, aBox.y2);
|
||||
}
|
||||
|
||||
void AddRect(const nsRect& aRect)
|
||||
void AddRect(const nsRectAbsolute& aRect)
|
||||
{
|
||||
#ifdef DEBUG_REGIONS
|
||||
class OperationStringGeneratorAddRect : public OperationStringGenerator
|
||||
{
|
||||
public:
|
||||
OperationStringGeneratorAddRect(nsRegion& aRegion, const nsRect& aRect)
|
||||
OperationStringGeneratorAddRect(nsRegion& aRegion, const nsRectAbsolute& aRect)
|
||||
: mRegion(&aRegion), mRegionCopy(aRegion), mRect(aRect)
|
||||
{
|
||||
aRegion.mCurrentOpGenerator = this;
|
||||
@ -1985,7 +2027,7 @@ private:
|
||||
private:
|
||||
nsRegion* mRegion;
|
||||
nsRegion mRegionCopy;
|
||||
nsRect mRect;
|
||||
nsRectAbsolute mRect;
|
||||
};
|
||||
|
||||
OperationStringGeneratorAddRect opGenerator(*this, aRect);
|
||||
@ -1994,12 +2036,6 @@ private:
|
||||
return;
|
||||
}
|
||||
|
||||
if (aRect.Overflows()) {
|
||||
// We don't accept rects which overflow.
|
||||
gfxWarning() << "Passing overflowing rect to AddRect.";
|
||||
return;
|
||||
}
|
||||
|
||||
if (mBands.IsEmpty()) {
|
||||
if (mBounds.IsEmpty()) {
|
||||
mBounds = aRect;
|
||||
@ -2109,7 +2145,7 @@ private:
|
||||
|
||||
// Most callers could probably do this on the fly, if this ever shows up
|
||||
// in profiles we could optimize this.
|
||||
nsRect CalculateBounds() const
|
||||
nsRectAbsolute CalculateBounds() const
|
||||
{
|
||||
if (mBands.IsEmpty()) {
|
||||
return mBounds;
|
||||
@ -2125,7 +2161,7 @@ private:
|
||||
rightMost = std::max(rightMost, band.mStrips.LastElement().right);
|
||||
}
|
||||
|
||||
return nsRect(leftMost, top, rightMost - leftMost, bottom - top);
|
||||
return nsRectAbsolute(leftMost, top, rightMost, bottom);
|
||||
}
|
||||
|
||||
static uint32_t ComputeMergedAreaIncrease(const Band& aTopBand,
|
||||
@ -2164,7 +2200,7 @@ private:
|
||||
|
||||
BandArray mBands;
|
||||
// Considering we only ever OR with nsRects, the bounds should fit in an nsRect as well.
|
||||
nsRect mBounds;
|
||||
nsRectAbsolute mBounds;
|
||||
#ifdef DEBUG_REGIONS
|
||||
friend class OperationStringGenerator;
|
||||
OperationStringGenerator* mCurrentOpGenerator;
|
||||
@ -2196,13 +2232,22 @@ public:
|
||||
const nsRect Get() const
|
||||
{
|
||||
if (mRegion.mBands.IsEmpty()) {
|
||||
return mRegion.mBounds;
|
||||
return mRegion.GetBounds();
|
||||
}
|
||||
return nsRect(mCurrentStrip->left, mCurrentBand->top,
|
||||
mCurrentStrip->right - mCurrentStrip->left,
|
||||
mCurrentBand->bottom - mCurrentBand->top);
|
||||
}
|
||||
|
||||
const nsRectAbsolute GetAbsolute() const
|
||||
{
|
||||
if (mRegion.mBands.IsEmpty()) {
|
||||
return mRegion.mBounds;
|
||||
}
|
||||
return nsRectAbsolute(mCurrentStrip->left, mCurrentBand->top,
|
||||
mCurrentStrip->right, mCurrentBand->bottom);
|
||||
}
|
||||
|
||||
void Next()
|
||||
{
|
||||
if (mRegion.mBands.IsEmpty()) {
|
||||
|
@ -224,6 +224,11 @@ TEST(Gfx, RegionIsEqual)
|
||||
}
|
||||
|
||||
TEST(Gfx, RegionOrWith) {
|
||||
PR_Sleep(PR_SecondsToInterval(10));
|
||||
{
|
||||
nsRegion r(nsRect(11840, 11840, 4640, -10880));
|
||||
r.OrWith(nsRect(160, 160, 7720, 880));
|
||||
}
|
||||
{
|
||||
nsRegion r(nsRect(79, 31, 75, 12));
|
||||
r.OrWith(nsRect(22, 43, 132, 5));
|
||||
|
@ -243,7 +243,7 @@ gfxFontMissingGlyphs::DrawMissingGlyph(uint32_t aChar,
|
||||
rect.Height() - 2.0 * halfBorderWidth);
|
||||
if (!borderStrokeRect.IsEmpty()) {
|
||||
ColorPattern adjustedColor = color;
|
||||
color.mColor.a *= BOX_BORDER_OPACITY;
|
||||
adjustedColor.mColor.a *= BOX_BORDER_OPACITY;
|
||||
#ifdef MOZ_GFX_OPTIMIZE_MOBILE
|
||||
aDrawTarget.FillRect(borderStrokeRect, adjustedColor);
|
||||
#else
|
||||
|
@ -23,6 +23,3 @@ if CONFIG['MOZ_SANDBOX'] and CONFIG['OS_ARCH'] == 'WINNT':
|
||||
'/security/sandbox/chromium',
|
||||
'/security/sandbox/chromium-shim',
|
||||
]
|
||||
|
||||
if CONFIG['MOZ_PGO'] and CONFIG['CC_TYPE'] == 'clang-cl':
|
||||
AllowCompilerWarnings() # workaround for bug 1090497
|
||||
|
@ -26,12 +26,6 @@ namespace gc {
|
||||
|
||||
struct Cell;
|
||||
|
||||
/*
|
||||
* The low bit is set so this should never equal a normal pointer, and the high
|
||||
* bit is set so this should never equal the upper 32 bits of a 64-bit pointer.
|
||||
*/
|
||||
const uint32_t Relocated = uintptr_t(0xbad0bad1);
|
||||
|
||||
const size_t ArenaShift = 12;
|
||||
const size_t ArenaSize = size_t(1) << ArenaShift;
|
||||
const size_t ArenaMask = ArenaSize - 1;
|
||||
@ -205,17 +199,20 @@ struct Zone
|
||||
|
||||
struct String
|
||||
{
|
||||
static const uint32_t NON_ATOM_BIT = JS_BIT(0);
|
||||
static const uint32_t LINEAR_BIT = JS_BIT(1);
|
||||
static const uint32_t INLINE_CHARS_BIT = JS_BIT(3);
|
||||
static const uint32_t LATIN1_CHARS_BIT = JS_BIT(6);
|
||||
static const uint32_t EXTERNAL_FLAGS = LINEAR_BIT | NON_ATOM_BIT | JS_BIT(5);
|
||||
static const uint32_t TYPE_FLAGS_MASK = JS_BIT(6) - 1;
|
||||
static const uint32_t PERMANENT_ATOM_MASK = NON_ATOM_BIT | JS_BIT(5);
|
||||
static const uint32_t PERMANENT_ATOM_FLAGS = JS_BIT(5);
|
||||
static const uint32_t NON_ATOM_BIT = JS_BIT(1);
|
||||
static const uint32_t LINEAR_BIT = JS_BIT(4);
|
||||
static const uint32_t INLINE_CHARS_BIT = JS_BIT(6);
|
||||
static const uint32_t LATIN1_CHARS_BIT = JS_BIT(9);
|
||||
static const uint32_t EXTERNAL_FLAGS = LINEAR_BIT | NON_ATOM_BIT | JS_BIT(8);
|
||||
static const uint32_t TYPE_FLAGS_MASK = JS_BITMASK(9) - JS_BIT(2) - JS_BIT(0);
|
||||
static const uint32_t PERMANENT_ATOM_MASK = NON_ATOM_BIT | JS_BIT(8);
|
||||
static const uint32_t PERMANENT_ATOM_FLAGS = JS_BIT(8);
|
||||
|
||||
uintptr_t flags_;
|
||||
#if JS_BITS_PER_WORD == 32
|
||||
uint32_t length_;
|
||||
#endif
|
||||
|
||||
uint32_t flags;
|
||||
uint32_t length;
|
||||
union {
|
||||
const JS::Latin1Char* nonInlineCharsLatin1;
|
||||
const char16_t* nonInlineCharsTwoByte;
|
||||
@ -224,18 +221,25 @@ struct String
|
||||
};
|
||||
const JSStringFinalizer* externalFinalizer;
|
||||
|
||||
static bool nurseryCellIsString(const js::gc::Cell* cell) {
|
||||
MOZ_ASSERT(IsInsideNursery(cell));
|
||||
return reinterpret_cast<const String*>(cell)->flags & NON_ATOM_BIT;
|
||||
inline uint32_t flags() const {
|
||||
return uint32_t(flags_);
|
||||
}
|
||||
inline uint32_t length() const {
|
||||
#if JS_BITS_PER_WORD == 32
|
||||
return length_;
|
||||
#else
|
||||
return uint32_t(flags_ >> 32);
|
||||
#endif
|
||||
}
|
||||
|
||||
static bool isPermanentAtom(const js::gc::Cell* cell) {
|
||||
uint32_t flags = reinterpret_cast<const String*>(cell)->flags;
|
||||
uint32_t flags = reinterpret_cast<const String*>(cell)->flags();
|
||||
return (flags & PERMANENT_ATOM_MASK) == PERMANENT_ATOM_FLAGS;
|
||||
}
|
||||
};
|
||||
|
||||
struct Symbol {
|
||||
uintptr_t reserved_;
|
||||
uint32_t code_;
|
||||
static const uint32_t WellKnownAPILimit = 0x80000000;
|
||||
|
||||
|
@ -73,6 +73,11 @@ GetCompartmentForRealm(Realm* realm)
|
||||
extern JS_PUBLIC_API(Realm*)
|
||||
GetObjectRealmOrNull(JSObject* obj);
|
||||
|
||||
// Return a script's realm. All scripts are created in a particular realm, which
|
||||
// never changes.
|
||||
extern JS_PUBLIC_API(Realm*)
|
||||
GetScriptRealm(JSScript* script);
|
||||
|
||||
// Get the value of the "private data" internal field of the given Realm.
|
||||
// This field is initially null and is set using SetRealmPrivate.
|
||||
// It's a pointer to embeddding-specific data that SpiderMonkey never uses.
|
||||
|
@ -791,8 +791,12 @@ js::ArraySetLength(JSContext* cx, Handle<ArrayObject*> arr, HandleId id,
|
||||
MOZ_ASSERT(oldCapacity >= oldInitializedLength);
|
||||
if (oldInitializedLength > newLen)
|
||||
arr->setDenseInitializedLengthMaybeNonExtensible(cx, newLen);
|
||||
if (oldCapacity > newLen)
|
||||
arr->shrinkElements(cx, newLen);
|
||||
if (oldCapacity > newLen) {
|
||||
if (arr->isExtensible())
|
||||
arr->shrinkElements(cx, newLen);
|
||||
else
|
||||
MOZ_ASSERT(arr->getDenseInitializedLength() == arr->getDenseCapacity());
|
||||
}
|
||||
|
||||
// We've done the work of deleting any dense elements needing
|
||||
// deletion, and there are no sparse elements. Thus we can skip
|
||||
|
@ -1643,9 +1643,10 @@ ArrayObject* ModuleBuilder::createArray(const JS::Rooted<GCHashMap<K, V>>& map)
|
||||
}
|
||||
|
||||
JSObject*
|
||||
js::GetOrCreateModuleMetaObject(JSContext* cx, HandleObject moduleArg)
|
||||
js::GetOrCreateModuleMetaObject(JSContext* cx, HandleScript script)
|
||||
{
|
||||
HandleModuleObject module = moduleArg.as<ModuleObject>();
|
||||
MOZ_ASSERT(script->module());
|
||||
RootedModuleObject module(cx, script->module());
|
||||
if (JSObject* obj = module->metaObject())
|
||||
return obj;
|
||||
|
||||
@ -1659,7 +1660,7 @@ js::GetOrCreateModuleMetaObject(JSContext* cx, HandleObject moduleArg)
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (!func(cx, module, metaObject))
|
||||
if (!func(cx, script, metaObject))
|
||||
return nullptr;
|
||||
|
||||
module->setMetaObject(metaObject);
|
||||
|
@ -412,7 +412,7 @@ class MOZ_STACK_CLASS ModuleBuilder
|
||||
};
|
||||
|
||||
JSObject*
|
||||
GetOrCreateModuleMetaObject(JSContext* cx, HandleObject module);
|
||||
GetOrCreateModuleMetaObject(JSContext* cx, HandleScript script);
|
||||
|
||||
} // namespace js
|
||||
|
||||
|
@ -796,7 +796,7 @@ WasmHasTier2CompilationCompleted(JSContext* cx, unsigned argc, Value* vp)
|
||||
}
|
||||
|
||||
Rooted<WasmModuleObject*> module(cx, &unwrapped->as<WasmModuleObject>());
|
||||
args.rval().set(BooleanValue(module->module().compilationComplete()));
|
||||
args.rval().set(BooleanValue(!module->module().testingTier2Active()));
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -47,7 +47,7 @@ class MOZ_STACK_CLASS BytecodeCompiler
|
||||
|
||||
JSScript* compileGlobalScript(ScopeKind scopeKind);
|
||||
JSScript* compileEvalScript(HandleObject environment, HandleScope enclosingScope);
|
||||
ModuleObject* compileModule();
|
||||
JSScript* compileModule();
|
||||
bool compileStandaloneFunction(MutableHandleFunction fun, GeneratorKind generatorKind,
|
||||
FunctionAsyncKind asyncKind,
|
||||
const Maybe<uint32_t>& parameterListEnd);
|
||||
@ -394,7 +394,7 @@ BytecodeCompiler::compileEvalScript(HandleObject environment, HandleScope enclos
|
||||
return compileScript(environment, &evalsc);
|
||||
}
|
||||
|
||||
ModuleObject*
|
||||
JSScript*
|
||||
BytecodeCompiler::compileModule()
|
||||
{
|
||||
if (!createSourceAndParser(ParseGoal::Module))
|
||||
@ -438,7 +438,7 @@ BytecodeCompiler::compileModule()
|
||||
return nullptr;
|
||||
|
||||
MOZ_ASSERT_IF(!cx->helperThread(), !cx->isExceptionPending());
|
||||
return module;
|
||||
return script;
|
||||
}
|
||||
|
||||
// Compile a standalone JS function, which might appear as the value of an
|
||||
@ -687,7 +687,7 @@ frontend::CompileEvalScript(JSContext* cx, LifoAlloc& alloc,
|
||||
|
||||
}
|
||||
|
||||
ModuleObject*
|
||||
JSScript*
|
||||
frontend::CompileModule(JSContext* cx, const ReadOnlyCompileOptions& optionsInput,
|
||||
SourceBufferHolder& srcBuf, LifoAlloc& alloc,
|
||||
ScriptSourceObject** sourceObjectOut)
|
||||
@ -705,15 +705,15 @@ frontend::CompileModule(JSContext* cx, const ReadOnlyCompileOptions& optionsInpu
|
||||
RootedScope emptyGlobalScope(cx, &cx->global()->emptyGlobalScope());
|
||||
BytecodeCompiler compiler(cx, alloc, options, srcBuf, emptyGlobalScope);
|
||||
AutoInitializeSourceObject autoSSO(compiler, sourceObjectOut);
|
||||
ModuleObject* module = compiler.compileModule();
|
||||
if (!module)
|
||||
JSScript* script = compiler.compileModule();
|
||||
if (!script)
|
||||
return nullptr;
|
||||
|
||||
assertException.reset();
|
||||
return module;
|
||||
return script;
|
||||
}
|
||||
|
||||
ModuleObject*
|
||||
JSScript*
|
||||
frontend::CompileModule(JSContext* cx, const ReadOnlyCompileOptions& options,
|
||||
SourceBufferHolder& srcBuf)
|
||||
{
|
||||
@ -723,17 +723,18 @@ frontend::CompileModule(JSContext* cx, const ReadOnlyCompileOptions& options,
|
||||
return nullptr;
|
||||
|
||||
LifoAlloc& alloc = cx->tempLifoAlloc();
|
||||
RootedModuleObject module(cx, CompileModule(cx, options, srcBuf, alloc));
|
||||
if (!module)
|
||||
RootedScript script(cx, CompileModule(cx, options, srcBuf, alloc));
|
||||
if (!script)
|
||||
return nullptr;
|
||||
|
||||
// This happens in GlobalHelperThreadState::finishModuleParseTask() when a
|
||||
// module is compiled off thread.
|
||||
RootedModuleObject module(cx, script->module());
|
||||
if (!ModuleObject::Freeze(cx, module))
|
||||
return nullptr;
|
||||
|
||||
assertException.reset();
|
||||
return module;
|
||||
return script;
|
||||
}
|
||||
|
||||
// When leaving this scope, the given function should either:
|
||||
|
@ -21,7 +21,6 @@ namespace js {
|
||||
|
||||
class LazyScript;
|
||||
class LifoAlloc;
|
||||
class ModuleObject;
|
||||
class ScriptSourceObject;
|
||||
|
||||
namespace frontend {
|
||||
@ -53,11 +52,11 @@ CompileEvalScript(JSContext* cx, LifoAlloc& alloc,
|
||||
SourceBufferHolder& srcBuf,
|
||||
ScriptSourceObject** sourceObjectOut = nullptr);
|
||||
|
||||
ModuleObject*
|
||||
JSScript*
|
||||
CompileModule(JSContext* cx, const ReadOnlyCompileOptions& options,
|
||||
SourceBufferHolder& srcBuf);
|
||||
|
||||
ModuleObject*
|
||||
JSScript*
|
||||
CompileModule(JSContext* cx, const ReadOnlyCompileOptions& options,
|
||||
SourceBufferHolder& srcBuf, LifoAlloc& alloc,
|
||||
ScriptSourceObject** sourceObjectOut = nullptr);
|
||||
|
@ -6070,11 +6070,13 @@ BytecodeEmitter::emitYieldStar(ParseNode* iter)
|
||||
MOZ_ASSERT(sc->isFunctionBox());
|
||||
MOZ_ASSERT(sc->asFunctionBox()->isGenerator());
|
||||
|
||||
bool isAsyncGenerator = sc->asFunctionBox()->isAsync();
|
||||
IteratorKind iterKind = sc->asFunctionBox()->isAsync()
|
||||
? IteratorKind::Async
|
||||
: IteratorKind::Sync;
|
||||
|
||||
if (!emitTree(iter)) // ITERABLE
|
||||
return false;
|
||||
if (isAsyncGenerator) {
|
||||
if (iterKind == IteratorKind::Async) {
|
||||
if (!emitAsyncIterator()) // NEXT ITER
|
||||
return false;
|
||||
} else {
|
||||
@ -6102,7 +6104,7 @@ BytecodeEmitter::emitYieldStar(ParseNode* iter)
|
||||
MOZ_ASSERT(this->stackDepth == startDepth);
|
||||
|
||||
// 11.4.3.7 AsyncGeneratorYield step 5.
|
||||
if (isAsyncGenerator) {
|
||||
if (iterKind == IteratorKind::Async) {
|
||||
if (!emitAwaitInInnermostScope()) // NEXT ITER RESULT
|
||||
return false;
|
||||
}
|
||||
@ -6118,7 +6120,8 @@ BytecodeEmitter::emitYieldStar(ParseNode* iter)
|
||||
if (!tryCatch.emitCatch()) // NEXT ITER RESULT
|
||||
return false;
|
||||
|
||||
stackDepth = startDepth; // NEXT ITER RESULT
|
||||
MOZ_ASSERT(stackDepth == startDepth);
|
||||
|
||||
if (!emit1(JSOP_EXCEPTION)) // NEXT ITER RESULT EXCEPTION
|
||||
return false;
|
||||
if (!emitDupAt(2)) // NEXT ITER RESULT EXCEPTION ITER
|
||||
@ -6127,31 +6130,15 @@ BytecodeEmitter::emitYieldStar(ParseNode* iter)
|
||||
return false;
|
||||
if (!emitAtomOp(cx->names().throw_, JSOP_CALLPROP)) // NEXT ITER RESULT EXCEPTION ITER THROW
|
||||
return false;
|
||||
if (!emit1(JSOP_DUP)) // NEXT ITER RESULT EXCEPTION ITER THROW THROW
|
||||
return false;
|
||||
if (!emit1(JSOP_UNDEFINED)) // NEXT ITER RESULT EXCEPTION ITER THROW THROW UNDEFINED
|
||||
return false;
|
||||
if (!emit1(JSOP_EQ)) // NEXT ITER RESULT EXCEPTION ITER THROW ?EQL
|
||||
|
||||
savedDepthTemp = stackDepth;
|
||||
InternalIfEmitter ifThrowMethodIsNotDefined(this);
|
||||
if (!emitPushNotUndefinedOrNull()) // NEXT ITER RESULT EXCEPTION ITER THROW NOT-UNDEF-OR-NULL
|
||||
return false;
|
||||
|
||||
InternalIfEmitter ifThrowMethodIsNotDefined(this);
|
||||
if (!ifThrowMethodIsNotDefined.emitThen()) // NEXT ITER RESULT EXCEPTION ITER THROW
|
||||
return false;
|
||||
savedDepthTemp = stackDepth;
|
||||
if (!emit1(JSOP_POP)) // NEXT ITER RESULT EXCEPTION ITER
|
||||
return false;
|
||||
// ES 14.4.13, YieldExpression : yield * AssignmentExpression, step 5.b.iii.2
|
||||
//
|
||||
// If the iterator does not have a "throw" method, it calls IteratorClose
|
||||
// and then throws a TypeError.
|
||||
IteratorKind iterKind = isAsyncGenerator ? IteratorKind::Async : IteratorKind::Sync;
|
||||
if (!emitIteratorCloseInInnermostScope(iterKind)) // NEXT ITER RESULT EXCEPTION
|
||||
return false;
|
||||
if (!emitUint16Operand(JSOP_THROWMSG, JSMSG_ITERATOR_NO_THROW)) // throw
|
||||
return false;
|
||||
stackDepth = savedDepthTemp;
|
||||
if (!ifThrowMethodIsNotDefined.emitEnd()) // NEXT ITER OLDRESULT EXCEPTION ITER THROW
|
||||
if (!ifThrowMethodIsNotDefined.emitThenElse()) // NEXT ITER RESULT EXCEPTION ITER THROW
|
||||
return false;
|
||||
|
||||
// ES 14.4.13, YieldExpression : yield * AssignmentExpression, step 5.b.iii.4.
|
||||
// RESULT = ITER.throw(EXCEPTION) // NEXT ITER OLDRESULT EXCEPTION ITER THROW
|
||||
if (!emit1(JSOP_SWAP)) // NEXT ITER OLDRESULT EXCEPTION THROW ITER
|
||||
@ -6162,7 +6149,7 @@ BytecodeEmitter::emitYieldStar(ParseNode* iter)
|
||||
return false;
|
||||
checkTypeSet(JSOP_CALL);
|
||||
|
||||
if (isAsyncGenerator) {
|
||||
if (iterKind == IteratorKind::Async) {
|
||||
if (!emitAwaitInInnermostScope()) // NEXT ITER OLDRESULT RESULT
|
||||
return false;
|
||||
}
|
||||
@ -6182,6 +6169,26 @@ BytecodeEmitter::emitYieldStar(ParseNode* iter)
|
||||
if (!emitJump(JSOP_GOTO, &checkResult)) // goto checkResult
|
||||
return false;
|
||||
|
||||
stackDepth = savedDepthTemp;
|
||||
if (!ifThrowMethodIsNotDefined.emitElse()) // NEXT ITER RESULT EXCEPTION ITER THROW
|
||||
return false;
|
||||
|
||||
if (!emit1(JSOP_POP)) // NEXT ITER RESULT EXCEPTION ITER
|
||||
return false;
|
||||
// ES 14.4.13, YieldExpression : yield * AssignmentExpression, step 5.b.iii.2
|
||||
//
|
||||
// If the iterator does not have a "throw" method, it calls IteratorClose
|
||||
// and then throws a TypeError.
|
||||
if (!emitIteratorCloseInInnermostScope(iterKind)) // NEXT ITER RESULT EXCEPTION
|
||||
return false;
|
||||
if (!emitUint16Operand(JSOP_THROWMSG, JSMSG_ITERATOR_NO_THROW)) // throw
|
||||
return false;
|
||||
|
||||
stackDepth = savedDepthTemp;
|
||||
if (!ifThrowMethodIsNotDefined.emitEnd())
|
||||
return false;
|
||||
|
||||
stackDepth = startDepth;
|
||||
if (!tryCatch.emitFinally())
|
||||
return false;
|
||||
|
||||
@ -6303,7 +6310,7 @@ BytecodeEmitter::emitYieldStar(ParseNode* iter)
|
||||
return false;
|
||||
checkTypeSet(JSOP_CALL);
|
||||
|
||||
if (isAsyncGenerator) {
|
||||
if (iterKind == IteratorKind::Async) {
|
||||
if (!emitAwaitInInnermostScope()) // NEXT ITER RESULT RESULT
|
||||
return false;
|
||||
}
|
||||
|
@ -48,10 +48,35 @@ struct Chunk;
|
||||
class StoreBuffer;
|
||||
class TenuredCell;
|
||||
|
||||
// A GC cell is the base class for all GC things.
|
||||
// [SMDOC] GC Cell
|
||||
//
|
||||
// A GC cell is the base class for all GC things. All types allocated on the GC
|
||||
// heap extend either gc::Cell or gc::TenuredCell. If a type is always tenured,
|
||||
// prefer the TenuredCell class as base.
|
||||
//
|
||||
// The first word (a pointer or uintptr_t) of each Cell must reserve the low
|
||||
// Cell::ReservedBits bits for GC purposes. The remaining bits are available to
|
||||
// sub-classes and typically store a pointer to another gc::Cell.
|
||||
//
|
||||
// During moving GC operation a Cell may be marked as forwarded. This indicates
|
||||
// that a gc::RelocationOverlay is currently stored in the Cell's memory and
|
||||
// should be used to find the new location of the Cell.
|
||||
struct alignas(gc::CellAlignBytes) Cell
|
||||
{
|
||||
public:
|
||||
// The low bits of the first word of each Cell are reserved for GC flags.
|
||||
static constexpr int ReservedBits = 2;
|
||||
static constexpr uintptr_t RESERVED_MASK = JS_BITMASK(ReservedBits);
|
||||
|
||||
// Indicates if the cell is currently a RelocationOverlay
|
||||
static constexpr uintptr_t FORWARD_BIT = JS_BIT(0);
|
||||
|
||||
// When a Cell is in the nursery, this will indicate if it is a JSString (1)
|
||||
// or JSObject (0). When not in nursery, this bit is still reserved for
|
||||
// JSString to use as JSString::NON_ATOM bit. This may be removed by Bug
|
||||
// 1376646.
|
||||
static constexpr uintptr_t JSSTRING_BIT = JS_BIT(1);
|
||||
|
||||
MOZ_ALWAYS_INLINE bool isTenured() const { return !IsInsideNursery(this); }
|
||||
MOZ_ALWAYS_INLINE const TenuredCell& asTenured() const;
|
||||
MOZ_ALWAYS_INLINE TenuredCell& asTenured();
|
||||
@ -77,6 +102,17 @@ struct alignas(gc::CellAlignBytes) Cell
|
||||
|
||||
static MOZ_ALWAYS_INLINE bool needWriteBarrierPre(JS::Zone* zone);
|
||||
|
||||
inline bool isForwarded() const {
|
||||
uintptr_t firstWord = *reinterpret_cast<const uintptr_t*>(this);
|
||||
return firstWord & FORWARD_BIT;
|
||||
}
|
||||
|
||||
inline bool nurseryCellIsString() const {
|
||||
MOZ_ASSERT(!isTenured());
|
||||
uintptr_t firstWord = *reinterpret_cast<const uintptr_t*>(this);
|
||||
return firstWord & JSSTRING_BIT;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
inline bool is() const {
|
||||
return getTraceKind() == JS::MapTypeToTraceKind<T>::kind;
|
||||
@ -255,7 +291,7 @@ Cell::getTraceKind() const
|
||||
{
|
||||
if (isTenured())
|
||||
return asTenured().getTraceKind();
|
||||
if (JS::shadow::String::nurseryCellIsString(this))
|
||||
if (nurseryCellIsString())
|
||||
return JS::TraceKind::String;
|
||||
return JS::TraceKind::Object;
|
||||
}
|
||||
|
@ -224,6 +224,7 @@
|
||||
#include "jit/IonCode.h"
|
||||
#include "jit/JitcodeMap.h"
|
||||
#include "jit/JitRealm.h"
|
||||
#include "jit/MacroAssembler.h"
|
||||
#include "js/SliceBudget.h"
|
||||
#include "proxy/DeadObjectProxy.h"
|
||||
#include "util/Windows.h"
|
||||
@ -384,6 +385,17 @@ const AllocKind gc::slotsToThingKind[] = {
|
||||
/* 16 */ AllocKind::OBJECT16
|
||||
};
|
||||
|
||||
// Check that reserved bits of a Cell are compatible with our typical allocators
|
||||
// since most derived classes will store a pointer in the first word.
|
||||
static_assert(js::detail::LIFO_ALLOC_ALIGN > JS_BITMASK(Cell::ReservedBits),
|
||||
"Cell::ReservedBits should support LifoAlloc");
|
||||
static_assert(CellAlignBytes > JS_BITMASK(Cell::ReservedBits),
|
||||
"Cell::ReservedBits should support gc::Cell");
|
||||
static_assert(sizeof(uintptr_t) > JS_BITMASK(Cell::ReservedBits),
|
||||
"Cell::ReservedBits should support small malloc / aligned globals");
|
||||
static_assert(js::jit::CodeAlignment > JS_BITMASK(Cell::ReservedBits),
|
||||
"Cell::ReservedBits should support JIT code");
|
||||
|
||||
static_assert(mozilla::ArrayLength(slotsToThingKind) == SLOTS_TO_THING_KIND_LIMIT,
|
||||
"We have defined a slot count for each kind.");
|
||||
|
||||
@ -2344,7 +2356,7 @@ RelocateArena(Arena* arena, SliceBudget& sliceBudget)
|
||||
#ifdef DEBUG
|
||||
for (ArenaCellIterUnderGC i(arena); !i.done(); i.next()) {
|
||||
TenuredCell* src = i.getCell();
|
||||
MOZ_ASSERT(RelocationOverlay::isCellForwarded(src));
|
||||
MOZ_ASSERT(src->isForwarded());
|
||||
TenuredCell* dest = Forwarded(src);
|
||||
MOZ_ASSERT(src->isMarkedBlack() == dest->isMarkedBlack());
|
||||
MOZ_ASSERT(src->isMarkedGray() == dest->isMarkedGray());
|
||||
@ -8472,8 +8484,8 @@ js::gc::AssertGCThingHasType(js::gc::Cell* cell, JS::TraceKind kind)
|
||||
MOZ_ASSERT(IsCellPointerValid(cell));
|
||||
|
||||
if (IsInsideNursery(cell)) {
|
||||
MOZ_ASSERT(kind == (JSString::nurseryCellIsString(cell) ? JS::TraceKind::String
|
||||
: JS::TraceKind::Object));
|
||||
MOZ_ASSERT(kind == (cell->nurseryCellIsString() ? JS::TraceKind::String
|
||||
: JS::TraceKind::Object));
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -177,7 +177,7 @@ struct MovingTracer : JS::CallbackTracer
|
||||
void onScopeEdge(Scope** basep) override;
|
||||
void onRegExpSharedEdge(RegExpShared** sharedp) override;
|
||||
void onChild(const JS::GCCellPtr& thing) override {
|
||||
MOZ_ASSERT(!RelocationOverlay::isCellForwarded(thing.asCell()));
|
||||
MOZ_ASSERT(!thing.asCell()->isForwarded());
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
|
@ -40,13 +40,12 @@ template <typename T>
|
||||
inline bool
|
||||
IsForwarded(const T* t)
|
||||
{
|
||||
const RelocationOverlay* overlay = RelocationOverlay::fromCell(t);
|
||||
if (!MightBeForwarded<T>::value) {
|
||||
MOZ_ASSERT(!overlay->isForwarded());
|
||||
MOZ_ASSERT(!t->isForwarded());
|
||||
return false;
|
||||
}
|
||||
|
||||
return overlay->isForwarded();
|
||||
return t->isForwarded();
|
||||
}
|
||||
|
||||
struct IsForwardedFunctor : public BoolDefaultAdaptor<Value, false> {
|
||||
@ -93,16 +92,14 @@ inline void
|
||||
RelocationOverlay::forwardTo(Cell* cell)
|
||||
{
|
||||
MOZ_ASSERT(!isForwarded());
|
||||
// The location of magic_ is important because it must never be valid to see
|
||||
// the value Relocated there in a GC thing that has not been moved.
|
||||
static_assert(offsetof(RelocationOverlay, magic_) == offsetof(JSObject, group_) + sizeof(uint32_t),
|
||||
"RelocationOverlay::magic_ is in the wrong location");
|
||||
static_assert(offsetof(RelocationOverlay, magic_) == offsetof(js::Shape, base_) + sizeof(uint32_t),
|
||||
"RelocationOverlay::magic_ is in the wrong location");
|
||||
static_assert(offsetof(RelocationOverlay, magic_) == offsetof(JSString, d.u1.length),
|
||||
"RelocationOverlay::magic_ is in the wrong location");
|
||||
magic_ = Relocated;
|
||||
newLocation_ = cell;
|
||||
|
||||
// Preserve old flags because nursery may check them before checking
|
||||
// if this is a forwarded Cell.
|
||||
//
|
||||
// This is pretty terrible and we should find a better way to implement
|
||||
// Cell::getTrackKind() that doesn't rely on this behavior.
|
||||
uintptr_t gcFlags = dataWithTag_ & Cell::RESERVED_MASK;
|
||||
dataWithTag_ = uintptr_t(cell) | gcFlags | Cell::FORWARD_BIT;
|
||||
}
|
||||
|
||||
#ifdef JSGC_HASH_TABLE_CHECKS
|
||||
@ -111,7 +108,7 @@ template <typename T>
|
||||
inline bool
|
||||
IsGCThingValidAfterMovingGC(T* t)
|
||||
{
|
||||
return !IsInsideNursery(t) && !RelocationOverlay::isCellForwarded(t);
|
||||
return !IsInsideNursery(t) && !t->isForwarded();
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
|
@ -1237,37 +1237,37 @@ Scope::traceChildren(JSTracer* trc)
|
||||
TraceNullableEdge(trc, &environmentShape_, "scope env shape");
|
||||
switch (kind_) {
|
||||
case ScopeKind::Function:
|
||||
reinterpret_cast<FunctionScope::Data*>(data_)->trace(trc);
|
||||
static_cast<FunctionScope::Data*>(data_)->trace(trc);
|
||||
break;
|
||||
case ScopeKind::FunctionBodyVar:
|
||||
case ScopeKind::ParameterExpressionVar:
|
||||
reinterpret_cast<VarScope::Data*>(data_)->trace(trc);
|
||||
static_cast<VarScope::Data*>(data_)->trace(trc);
|
||||
break;
|
||||
case ScopeKind::Lexical:
|
||||
case ScopeKind::SimpleCatch:
|
||||
case ScopeKind::Catch:
|
||||
case ScopeKind::NamedLambda:
|
||||
case ScopeKind::StrictNamedLambda:
|
||||
reinterpret_cast<LexicalScope::Data*>(data_)->trace(trc);
|
||||
static_cast<LexicalScope::Data*>(data_)->trace(trc);
|
||||
break;
|
||||
case ScopeKind::Global:
|
||||
case ScopeKind::NonSyntactic:
|
||||
reinterpret_cast<GlobalScope::Data*>(data_)->trace(trc);
|
||||
static_cast<GlobalScope::Data*>(data_)->trace(trc);
|
||||
break;
|
||||
case ScopeKind::Eval:
|
||||
case ScopeKind::StrictEval:
|
||||
reinterpret_cast<EvalScope::Data*>(data_)->trace(trc);
|
||||
static_cast<EvalScope::Data*>(data_)->trace(trc);
|
||||
break;
|
||||
case ScopeKind::Module:
|
||||
reinterpret_cast<ModuleScope::Data*>(data_)->trace(trc);
|
||||
static_cast<ModuleScope::Data*>(data_)->trace(trc);
|
||||
break;
|
||||
case ScopeKind::With:
|
||||
break;
|
||||
case ScopeKind::WasmInstance:
|
||||
reinterpret_cast<WasmInstanceScope::Data*>(data_)->trace(trc);
|
||||
static_cast<WasmInstanceScope::Data*>(data_)->trace(trc);
|
||||
break;
|
||||
case ScopeKind::WasmFunction:
|
||||
reinterpret_cast<WasmFunctionScope::Data*>(data_)->trace(trc);
|
||||
static_cast<WasmFunctionScope::Data*>(data_)->trace(trc);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -1282,7 +1282,7 @@ js::GCMarker::eagerlyMarkChildren(Scope* scope)
|
||||
uint32_t length = 0;
|
||||
switch (scope->kind_) {
|
||||
case ScopeKind::Function: {
|
||||
FunctionScope::Data* data = reinterpret_cast<FunctionScope::Data*>(scope->data_);
|
||||
FunctionScope::Data* data = static_cast<FunctionScope::Data*>(scope->data_);
|
||||
traverseEdge(scope, static_cast<JSObject*>(data->canonicalFunction));
|
||||
names = &data->trailingNames;
|
||||
length = data->length;
|
||||
@ -1291,7 +1291,7 @@ js::GCMarker::eagerlyMarkChildren(Scope* scope)
|
||||
|
||||
case ScopeKind::FunctionBodyVar:
|
||||
case ScopeKind::ParameterExpressionVar: {
|
||||
VarScope::Data* data = reinterpret_cast<VarScope::Data*>(scope->data_);
|
||||
VarScope::Data* data = static_cast<VarScope::Data*>(scope->data_);
|
||||
names = &data->trailingNames;
|
||||
length = data->length;
|
||||
break;
|
||||
@ -1302,7 +1302,7 @@ js::GCMarker::eagerlyMarkChildren(Scope* scope)
|
||||
case ScopeKind::Catch:
|
||||
case ScopeKind::NamedLambda:
|
||||
case ScopeKind::StrictNamedLambda: {
|
||||
LexicalScope::Data* data = reinterpret_cast<LexicalScope::Data*>(scope->data_);
|
||||
LexicalScope::Data* data = static_cast<LexicalScope::Data*>(scope->data_);
|
||||
names = &data->trailingNames;
|
||||
length = data->length;
|
||||
break;
|
||||
@ -1310,7 +1310,7 @@ js::GCMarker::eagerlyMarkChildren(Scope* scope)
|
||||
|
||||
case ScopeKind::Global:
|
||||
case ScopeKind::NonSyntactic: {
|
||||
GlobalScope::Data* data = reinterpret_cast<GlobalScope::Data*>(scope->data_);
|
||||
GlobalScope::Data* data = static_cast<GlobalScope::Data*>(scope->data_);
|
||||
names = &data->trailingNames;
|
||||
length = data->length;
|
||||
break;
|
||||
@ -1318,14 +1318,14 @@ js::GCMarker::eagerlyMarkChildren(Scope* scope)
|
||||
|
||||
case ScopeKind::Eval:
|
||||
case ScopeKind::StrictEval: {
|
||||
EvalScope::Data* data = reinterpret_cast<EvalScope::Data*>(scope->data_);
|
||||
EvalScope::Data* data = static_cast<EvalScope::Data*>(scope->data_);
|
||||
names = &data->trailingNames;
|
||||
length = data->length;
|
||||
break;
|
||||
}
|
||||
|
||||
case ScopeKind::Module: {
|
||||
ModuleScope::Data* data = reinterpret_cast<ModuleScope::Data*>(scope->data_);
|
||||
ModuleScope::Data* data = static_cast<ModuleScope::Data*>(scope->data_);
|
||||
traverseEdge(scope, static_cast<JSObject*>(data->module));
|
||||
names = &data->trailingNames;
|
||||
length = data->length;
|
||||
@ -1336,7 +1336,7 @@ js::GCMarker::eagerlyMarkChildren(Scope* scope)
|
||||
break;
|
||||
|
||||
case ScopeKind::WasmInstance: {
|
||||
WasmInstanceScope::Data* data = reinterpret_cast<WasmInstanceScope::Data*>(scope->data_);
|
||||
WasmInstanceScope::Data* data = static_cast<WasmInstanceScope::Data*>(scope->data_);
|
||||
traverseEdge(scope, static_cast<JSObject*>(data->instance));
|
||||
names = &data->trailingNames;
|
||||
length = data->length;
|
||||
@ -1344,7 +1344,7 @@ js::GCMarker::eagerlyMarkChildren(Scope* scope)
|
||||
}
|
||||
|
||||
case ScopeKind::WasmFunction: {
|
||||
WasmFunctionScope::Data* data = reinterpret_cast<WasmFunctionScope::Data*>(scope->data_);
|
||||
WasmFunctionScope::Data* data = static_cast<WasmFunctionScope::Data*>(scope->data_);
|
||||
names = &data->trailingNames;
|
||||
length = data->length;
|
||||
break;
|
||||
@ -2862,7 +2862,7 @@ js::gc::StoreBuffer::CellPtrEdge::trace(TenuringTracer& mover) const
|
||||
if (!IsInsideNursery(*edge))
|
||||
return;
|
||||
|
||||
if (JSString::nurseryCellIsString(*edge))
|
||||
if ((*edge)->nurseryCellIsString())
|
||||
mover.traverse(reinterpret_cast<JSString**>(edge));
|
||||
else
|
||||
mover.traverse(reinterpret_cast<JSObject**>(edge));
|
||||
|
@ -28,11 +28,11 @@ js::Nursery::isInside(const SharedMem<T>& p) const
|
||||
MOZ_ALWAYS_INLINE /* static */ bool
|
||||
js::Nursery::getForwardedPointer(js::gc::Cell** ref)
|
||||
{
|
||||
MOZ_ASSERT(ref);
|
||||
MOZ_ASSERT(IsInsideNursery(*ref));
|
||||
const gc::RelocationOverlay* overlay = reinterpret_cast<const gc::RelocationOverlay*>(*ref);
|
||||
if (!overlay->isForwarded())
|
||||
js::gc::Cell* cell = (*ref);
|
||||
MOZ_ASSERT(IsInsideNursery(cell));
|
||||
if (!cell->isForwarded())
|
||||
return false;
|
||||
const gc::RelocationOverlay* overlay = gc::RelocationOverlay::fromCell(cell);
|
||||
*ref = overlay->forwardingAddress();
|
||||
return true;
|
||||
}
|
||||
|
@ -16,6 +16,7 @@
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "gc/Cell.h"
|
||||
#include "js/HeapAPI.h"
|
||||
#include "vm/JSObject.h"
|
||||
#include "vm/Shape.h"
|
||||
@ -23,49 +24,36 @@
|
||||
namespace js {
|
||||
namespace gc {
|
||||
|
||||
struct Cell;
|
||||
|
||||
/*
|
||||
* This structure overlays a Cell that has been moved and provides a way to find
|
||||
* its new location. It's used during generational and compacting GC.
|
||||
*/
|
||||
class RelocationOverlay
|
||||
class RelocationOverlay : public Cell
|
||||
{
|
||||
/* See comment in js/public/HeapAPI.h. */
|
||||
static const uint32_t Relocated = js::gc::Relocated;
|
||||
|
||||
/*
|
||||
* Keep the low 32 bits untouched. Use them to distinguish strings from
|
||||
* objects in the nursery.
|
||||
*/
|
||||
uint32_t preserve_;
|
||||
|
||||
/* Set to Relocated when moved. */
|
||||
uint32_t magic_;
|
||||
|
||||
/* The location |this| was moved to. */
|
||||
Cell* newLocation_;
|
||||
// First word of a Cell has additional requirements from GC. The GC flags
|
||||
// determine if a Cell is a normal entry or is a RelocationOverlay.
|
||||
// 3 0
|
||||
// -------------------------
|
||||
// | NewLocation | GCFlags |
|
||||
// -------------------------
|
||||
uintptr_t dataWithTag_;
|
||||
|
||||
/* A list entry to track all relocated things. */
|
||||
RelocationOverlay* next_;
|
||||
|
||||
public:
|
||||
static const RelocationOverlay* fromCell(const Cell* cell) {
|
||||
return reinterpret_cast<const RelocationOverlay*>(cell);
|
||||
return static_cast<const RelocationOverlay*>(cell);
|
||||
}
|
||||
|
||||
static RelocationOverlay* fromCell(Cell* cell) {
|
||||
return reinterpret_cast<RelocationOverlay*>(cell);
|
||||
}
|
||||
|
||||
bool isForwarded() const {
|
||||
(void) preserve_; // Suppress warning
|
||||
return magic_ == Relocated;
|
||||
return static_cast<RelocationOverlay*>(cell);
|
||||
}
|
||||
|
||||
Cell* forwardingAddress() const {
|
||||
MOZ_ASSERT(isForwarded());
|
||||
return newLocation_;
|
||||
uintptr_t newLocation = dataWithTag_ & ~Cell::RESERVED_MASK;
|
||||
return reinterpret_cast<Cell*>(newLocation);
|
||||
}
|
||||
|
||||
void forwardTo(Cell* cell);
|
||||
@ -79,10 +67,6 @@ class RelocationOverlay
|
||||
MOZ_ASSERT(isForwarded());
|
||||
return next_;
|
||||
}
|
||||
|
||||
static bool isCellForwarded(const Cell* cell) {
|
||||
return fromCell(cell)->isForwarded();
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace gc
|
||||
|
@ -643,8 +643,7 @@ CheckHeapTracer::checkCell(Cell* cell)
|
||||
// Moving
|
||||
if (!IsValidGCThingPointer(cell) ||
|
||||
((gcType == GCType::Moving) && !IsGCThingValidAfterMovingGC(cell)) ||
|
||||
((gcType == GCType::NonMoving) &&
|
||||
RelocationOverlay::isCellForwarded(cell)))
|
||||
((gcType == GCType::NonMoving) && cell->isForwarded()))
|
||||
{
|
||||
failures++;
|
||||
fprintf(stderr, "Bad pointer %p\n", cell);
|
||||
|
6
js/src/jit-test/tests/auto-regress/bug1481032.js
Normal file
6
js/src/jit-test/tests/auto-regress/bug1481032.js
Normal file
@ -0,0 +1,6 @@
|
||||
x = [];
|
||||
x[6] = 0;
|
||||
Object.preventExtensions(x);
|
||||
|
||||
// Don't assert.
|
||||
x.length = 1;
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user