Merge inbound to mozilla-central. a=merge

This commit is contained in:
Tiberius Oros 2018-08-09 13:02:05 +03:00
commit aff5d4ad5d
487 changed files with 16157 additions and 6240 deletions

View File

@ -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"
]
}

View File

@ -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

View File

@ -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

View File

@ -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"

View File

@ -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

View File

@ -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

View File

@ -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;
}

View File

@ -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

View File

@ -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

View File

@ -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
};
}

View File

@ -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=[],
)

View File

@ -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;

View File

@ -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": [

View File

@ -51,7 +51,6 @@ function onInspect(aState, aResponse)
let expectedProps = {
"addBroadcastListenerFor": { value: { type: "object" } },
"commandDispatcher": { get: { type: "object" } },
};
let props = aResponse.ownProperties;

View File

@ -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

View File

@ -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)
{

View File

@ -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));

View File

@ -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)

View File

@ -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.

View File

@ -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__

View File

@ -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;
}

View File

@ -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.

View File

@ -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));

View File

@ -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',

View File

@ -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

View File

@ -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

View File

@ -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);
}

View File

@ -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,

View File

@ -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

View File

@ -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;
}

View File

@ -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:

View File

@ -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(&current)) && 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,

View 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]

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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);

View File

@ -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();
}

View File

@ -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();
}

View File

@ -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();
}

View File

@ -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();
}

View File

@ -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();
}

View File

@ -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");

View File

@ -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();
}

View File

@ -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);

View File

@ -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

View File

@ -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

View File

@ -5361,10 +5361,6 @@ QuotaManager::EnsureOriginIsInitializedInternal(
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
mTemporaryStorageInitialized = true;
CheckTemporaryStorageLimits();
}
bool created;

View File

@ -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;

View File

@ -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

View File

@ -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);
}
}
}

View File

@ -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

View File

@ -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,

View File

@ -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);

View File

@ -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

View File

@ -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;

View File

@ -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;

View File

@ -21,6 +21,8 @@ interface SVGImageElement : SVGGraphicsElement {
readonly attribute SVGAnimatedLength height;
[Constant]
readonly attribute SVGAnimatedPreserveAspectRatio preserveAspectRatio;
[CEReactions, SetterThrows]
attribute DOMString decoding;
};
SVGImageElement implements MozImageLoadingContent;

View File

@ -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 {

View File

@ -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.
*/

View File

@ -10,8 +10,6 @@ interface MozObserver;
[Func="IsChromeOrXBL"]
interface XULDocument : Document {
readonly attribute XULCommandDispatcher? commandDispatcher;
[Throws]
void addBroadcastListenerFor(Element broadcaster, Element observer,
DOMString attr);

View File

@ -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

View File

@ -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;
/**

View File

@ -16,6 +16,7 @@ MOCHITEST_CHROME_MANIFESTS += ['test/chrome.ini']
if CONFIG['MOZ_XUL']:
EXPORTS += [
'nsXULCommandDispatcher.h',
'nsXULElement.h',
]

View File

@ -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;
}

View File

@ -45,9 +45,6 @@ public:
nsAtom* aTag,
mozilla::dom::Element** aResult);
static nsresult
SetCommandUpdater(nsIDocument* aDocument, mozilla::dom::Element* aElement);
static nsICollation*
GetCollation();
};

View File

@ -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>

View File

@ -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

View File

@ -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:

View File

@ -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() {}

View File

@ -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:

View File

@ -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.

View File

@ -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);
}

View File

@ -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
{

View File

@ -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 */

View File

@ -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);
}

View File

@ -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()) {

View File

@ -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));

View File

@ -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

View File

@ -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

View File

@ -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;

View File

@ -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.

View File

@ -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

View File

@ -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);

View File

@ -412,7 +412,7 @@ class MOZ_STACK_CLASS ModuleBuilder
};
JSObject*
GetOrCreateModuleMetaObject(JSContext* cx, HandleObject module);
GetOrCreateModuleMetaObject(JSContext* cx, HandleScript script);
} // namespace js

View File

@ -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;
}

View File

@ -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:

View File

@ -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);

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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

View File

@ -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>

View File

@ -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));

View File

@ -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;
}

View File

@ -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

View File

@ -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);

View 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