зеркало из https://github.com/mozilla/gecko-dev.git
Merge inbound to central, a=merge CLOSED TREE
UPGRADE_NSS_RELEASE UPGRADE_NSPR_RELEASE MozReview-Commit-ID: 2CXltQtu4Y1 --HG-- extra : amend_source : 16333c0fa5342dfbbb2a4ded71f94119a022e27b
This commit is contained in:
Коммит
bb1d061819
|
@ -15,6 +15,7 @@
|
|||
#include "nsFocusManager.h"
|
||||
#include "mozilla/EventStateManager.h"
|
||||
#include "mozilla/dom/Element.h"
|
||||
#include "mozilla/dom/TabParent.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace a11y {
|
||||
|
@ -190,13 +191,35 @@ FocusManager::ActiveItemChanged(Accessible* aItem, bool aCheckIfActive)
|
|||
}
|
||||
mActiveItem = aItem;
|
||||
|
||||
// If mActiveItem is null, we might need to shift a11y focus to a remote
|
||||
// element.
|
||||
if (!mActiveItem && XRE_IsParentProcess()) {
|
||||
nsFocusManager* domfm = nsFocusManager::GetFocusManager();
|
||||
if (domfm) {
|
||||
nsIContent* focusedElm = domfm->GetFocusedContent();
|
||||
if (focusedElm) {
|
||||
bool remote = EventStateManager::IsRemoteTarget(focusedElm);
|
||||
if (remote) {
|
||||
dom::TabParent* tab = dom::TabParent::GetFrom(focusedElm);
|
||||
if (tab) {
|
||||
a11y::DocAccessibleParent* dap = tab->GetTopLevelDocAccessible();
|
||||
if (dap) {
|
||||
Unused << dap->SendRestoreFocus();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If active item is changed then fire accessible focus event on it, otherwise
|
||||
// if there's no an active item then fire focus event to accessible having
|
||||
// DOM focus.
|
||||
Accessible* target = FocusedAccessible();
|
||||
if (target)
|
||||
if (target) {
|
||||
DispatchFocusEvent(target->Document(), target);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
FocusManager::ForceFocusEvent()
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
|
||||
#include "DocAccessibleChild.h"
|
||||
|
||||
#include "nsAccessibilityService.h"
|
||||
#include "Accessible-inl.h"
|
||||
#include "ProxyAccessible.h"
|
||||
#include "Relation.h"
|
||||
|
@ -2003,5 +2004,12 @@ DocAccessibleChild::RecvDOMNodeID(const uint64_t& aID, nsString* aDOMNodeID)
|
|||
return IPC_OK();
|
||||
}
|
||||
|
||||
mozilla::ipc::IPCResult
|
||||
DocAccessibleChild::RecvRestoreFocus()
|
||||
{
|
||||
FocusMgr()->ForceFocusEvent();
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -38,6 +38,8 @@ public:
|
|||
MOZ_COUNT_DTOR_INHERITED(DocAccessibleChild, DocAccessibleChildBase);
|
||||
}
|
||||
|
||||
virtual mozilla::ipc::IPCResult RecvRestoreFocus() override;
|
||||
|
||||
/*
|
||||
* Return the state for the accessible with given ID.
|
||||
*/
|
||||
|
|
|
@ -73,6 +73,12 @@ parent:
|
|||
child:
|
||||
async __delete__();
|
||||
|
||||
/*
|
||||
* Called as a result of focus shifting from chrome to content
|
||||
* elements through keyboard navigation.
|
||||
*/
|
||||
async RestoreFocus();
|
||||
|
||||
// Accessible
|
||||
nested(inside_sync) sync State(uint64_t aID) returns(uint64_t states);
|
||||
nested(inside_sync) sync NativeState(uint64_t aID) returns(uint64_t states);
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
|
||||
#include "DocAccessibleChild.h"
|
||||
|
||||
#include "nsAccessibilityService.h"
|
||||
#include "Accessible-inl.h"
|
||||
#include "mozilla/a11y/PlatformChild.h"
|
||||
#include "mozilla/ClearOnShutdown.h"
|
||||
|
@ -307,6 +308,13 @@ DocAccessibleChild::SendBindChildDoc(DocAccessibleChild* aChildDoc,
|
|||
return true;
|
||||
}
|
||||
|
||||
ipc::IPCResult
|
||||
DocAccessibleChild::RecvRestoreFocus()
|
||||
{
|
||||
FocusMgr()->ForceFocusEvent();
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
} // namespace a11y
|
||||
} // namespace mozilla
|
||||
|
||||
|
|
|
@ -32,6 +32,8 @@ public:
|
|||
virtual ipc::IPCResult
|
||||
RecvEmulatedWindow(const WindowsHandle& aEmulatedWindowHandle,
|
||||
const IAccessibleHolder& aEmulatedWindowCOMProxy) override;
|
||||
virtual ipc::IPCResult
|
||||
RecvRestoreFocus() override;
|
||||
|
||||
HWND GetNativeWindowHandle() const;
|
||||
IAccessible* GetEmulatedWindowIAccessible() const { return mEmulatedWindowProxy.get(); }
|
||||
|
|
|
@ -74,6 +74,11 @@ child:
|
|||
async ParentCOMProxy(IAccessibleHolder aParentCOMProxy);
|
||||
async EmulatedWindow(WindowsHandle aEmulatedWindowHandle,
|
||||
IAccessibleHolder aEmulatedWindowCOMProxy);
|
||||
/*
|
||||
* Called as a result of focus shifting from chrome to content
|
||||
* elements through keyboard navigation.
|
||||
*/
|
||||
async RestoreFocus();
|
||||
|
||||
async __delete__();
|
||||
};
|
||||
|
|
|
@ -72,7 +72,7 @@ pref("extensions.startupScanScopes", 0);
|
|||
// This is where the profiler WebExtension API will look for breakpad symbols.
|
||||
// NOTE: deliberately http right now since https://symbols.mozilla.org is not supported.
|
||||
pref("extensions.geckoProfiler.symbols.url", "http://symbols.mozilla.org/");
|
||||
pref("extensions.geckoProfiler.acceptedExtensionIds", "geckoprofiler@mozilla.com");
|
||||
pref("extensions.geckoProfiler.acceptedExtensionIds", "geckoprofiler@mozilla.com,quantum-foxfooding@mozilla.com");
|
||||
#if defined(XP_LINUX) || defined (XP_MACOSX)
|
||||
pref("extensions.geckoProfiler.getSymbolRules", "localBreakpad,remoteBreakpad,nm");
|
||||
#else // defined(XP_WIN)
|
||||
|
|
|
@ -1,6 +1,10 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
// Note to run this test similar to try server, you need to run:
|
||||
// ./mach package
|
||||
// ./mach mochitest --appname dist <path to test>
|
||||
|
||||
// Slow on asan builds.
|
||||
requestLongerTimeout(5);
|
||||
|
||||
|
@ -324,7 +328,7 @@ function parseCodeFile(fileUri) {
|
|||
let baseUri;
|
||||
for (let line of data.split("\n")) {
|
||||
let urls =
|
||||
line.match(/["']chrome:\/\/[a-zA-Z0-9 -]+\/(content|skin|locale)\/[^"' ]*["']/g);
|
||||
line.match(/["'`]chrome:\/\/[a-zA-Z0-9 -]+\/(content|skin|locale)\/[^"'` ]*["'`]/g);
|
||||
if (!urls) {
|
||||
urls = line.match(/["']resource:\/\/[^"']+["']/g);
|
||||
if (urls && isDevtools &&
|
||||
|
@ -388,8 +392,14 @@ function parseCodeFile(fileUri) {
|
|||
// Remove quotes.
|
||||
url = url.slice(1, -1);
|
||||
// Remove ? or \ trailing characters.
|
||||
if (url.endsWith("?") || url.endsWith("\\"))
|
||||
if (url.endsWith("\\")) {
|
||||
url = url.slice(0, -1);
|
||||
}
|
||||
|
||||
let pos = url.indexOf("?");
|
||||
if (pos != -1) {
|
||||
url = url.slice(0, pos);
|
||||
}
|
||||
|
||||
// Make urls like chrome://browser/skin/ point to an actual file,
|
||||
// and remove the ref if any.
|
||||
|
|
|
@ -6,11 +6,11 @@
|
|||
%ifdef CAN_DRAW_IN_TITLEBAR
|
||||
/* Add space for dragging the window */
|
||||
%ifdef MENUBAR_CAN_AUTOHIDE
|
||||
:root[tabsintitlebar] #toolbar-menubar[autohide=true] ~ #TabsToolbar {
|
||||
:root[tabsintitlebar][sizemode=normal] #toolbar-menubar[autohide=true] ~ #TabsToolbar {
|
||||
padding-inline-start: 40px;
|
||||
}
|
||||
%else
|
||||
:root[tabsintitlebar] #TabsToolbar {
|
||||
:root[tabsintitlebar][sizemode=normal] #TabsToolbar {
|
||||
padding-inline-start: 40px;
|
||||
}
|
||||
%endif
|
||||
|
|
|
@ -1,46 +0,0 @@
|
|||
<?xml version="1.0"?>
|
||||
<!-- This Source Code Form is subject to the terms of the Mozilla Public
|
||||
- License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 16 16">
|
||||
<style>
|
||||
use:not(:target) {
|
||||
display: none;
|
||||
}
|
||||
use {
|
||||
fill: menutext;
|
||||
}
|
||||
use[id$="-active"] {
|
||||
fill: -moz-menuhovertext;
|
||||
}
|
||||
use[id$="-disabled"] {
|
||||
fill: graytext;
|
||||
}
|
||||
</style>
|
||||
<defs>
|
||||
<path id="back-shape" fill-rule="evenodd" d="M1.192,8.893L2.21,9.964c0.064,0.065,0.136,0.117,0.214,0.159 l5.199,5.301c0.607,0.63,1.465,0.764,1.915,0.297l1.02-1.082c0.449-0.467,0.32-1.357-0.288-1.99l-2.116-2.158h5.705 c0.671,0,1.215-0.544,1.215-1.215v-2.43c0-0.671-0.544-1.215-1.215-1.215H8.094l2.271-2.309c0.609-0.626,0.737-1.512,0.288-1.974 L9.635,0.278C9.184-0.188,8.327-0.055,7.718,0.575L2.479,5.901C2.38,5.946,2.289,6.008,2.21,6.089L1.192,7.171 c-0.21,0.219-0.293,0.53-0.26,0.864C0.899,8.367,0.981,8.676,1.192,8.893z"/>
|
||||
<path id="forward-shape" fill-rule="evenodd" d="M14.808,7.107L13.79,6.036c-0.064-0.065-0.136-0.117-0.214-0.159 L8.377,0.576C7.77-0.054,6.912-0.189,6.461,0.278L5.441,1.36c-0.449,0.467-0.32,1.357,0.288,1.99l2.116,2.158H2.14 c-0.671,0-1.215,0.544-1.215,1.215v2.43c0,0.671,0.544,1.215,1.215,1.215h5.765l-2.271,2.309c-0.609,0.626-0.737,1.512-0.288,1.974 l1.019,1.072c0.451,0.465,1.308,0.332,1.917-0.297l5.238-5.326c0.1-0.045,0.191-0.107,0.269-0.188l1.019-1.082 c0.21-0.219,0.293-0.53,0.26-0.864C15.101,7.633,15.019,7.324,14.808,7.107z"/>
|
||||
<path id="reload-shape" fill-rule="evenodd" d="M15.429,8h-8l3.207-3.207C9.889,4.265,8.986,3.947,8,3.947 c-2.554,0-4.625,2.071-4.625,4.625S5.446,13.196,8,13.196c1.638,0,3.069-0.857,3.891-2.141l2.576,1.104 C13.199,14.439,10.794,16,8,16c-4.103,0-7.429-3.326-7.429-7.429S3.897,1.143,8,1.143c1.762,0,3.366,0.624,4.631,1.654L15.429,0V8z"/>
|
||||
<polygon id="stop-shape" points="16,2.748 13.338,0.079 8.038,5.391 2.661,0 0,2.669 5.377,8.059 0.157,13.292 2.819,15.961 8.039,10.728 13.298,16 15.959,13.331 10.701,8.06"/>
|
||||
<path id="bookmark-shape" d="M8.008,3.632l0.986,2.012l0.452,0.922l1.014,0.169l2.326,0.389l-1.719,1.799l-0.676,0.708l0.145,0.967 L10.896,13l-1.959-1.039l-0.937-0.497l-0.937,0.497l-1.957,1.038L5.468,10.6l0.146-0.968L4.937,8.924L3.219,7.126l2.351-0.39 l1.023-0.17l0.45-0.934L8.008,3.632 M8,0C7.72,0,7.44,0.217,7.228,0.65L5.242,4.766L0.907,5.485c-0.958,0.159-1.195,0.861-0.53,1.56 l3.113,3.258l-0.69,4.583c-0.105,0.689,0.172,1.092,0.658,1.092c0.185,0,0.399-0.058,0.635-0.181l3.906-2.072l3.906,2.072 c0.236,0.123,0.45,0.181,0.635,0.181c0.486,0,0.762-0.403,0.659-1.092l-0.687-4.583l3.109-3.255c0.666-0.702,0.428-1.404-0.53-1.564 l-4.303-0.719L8.772,0.65C8.56,0.217,8.28,0,8,0L8,0z"/>
|
||||
<path id="bookmarked-shape" d="M8,0C7.719,0,7.438,0.217,7.225,0.651L5.233,4.773l-4.35,0.72c-0.961,0.159-1.199,0.862-0.531,1.562 l3.124,3.262l-0.692,4.589C2.679,15.596,2.957,16,3.444,16c0.185,0,0.401-0.058,0.637-0.181L8,13.744l3.919,2.075 C12.156,15.942,12.372,16,12.557,16c0.487,0,0.764-0.404,0.661-1.094l-0.69-4.589l3.12-3.259c0.668-0.703,0.43-1.406-0.532-1.566 l-4.317-0.72L8.775,0.651C8.562,0.217,8.281,0,8,0L8,0z"/>
|
||||
</defs>
|
||||
<use id="back" xlink:href="#back-shape"/>
|
||||
<use id="back-active" xlink:href="#back-shape"/>
|
||||
<use id="back-disabled" xlink:href="#back-shape"/>
|
||||
<use id="forward" xlink:href="#forward-shape"/>
|
||||
<use id="forward-active" xlink:href="#forward-shape"/>
|
||||
<use id="forward-disabled" xlink:href="#forward-shape"/>
|
||||
<use id="reload" xlink:href="#reload-shape"/>
|
||||
<use id="reload-active" xlink:href="#reload-shape"/>
|
||||
<use id="reload-disabled" xlink:href="#reload-shape"/>
|
||||
<use id="stop" xlink:href="#stop-shape"/>
|
||||
<use id="stop-active" xlink:href="#stop-shape"/>
|
||||
<use id="stop-disabled" xlink:href="#stop-shape"/>
|
||||
<use id="bookmark" xlink:href="#bookmark-shape"/>
|
||||
<use id="bookmark-active" xlink:href="#bookmark-shape"/>
|
||||
<use id="bookmark-disabled" xlink:href="#bookmark-shape"/>
|
||||
<use id="bookmarked" xlink:href="#bookmarked-shape"/>
|
||||
<use id="bookmarked-active" xlink:href="#bookmarked-shape"/>
|
||||
<use id="bookmarked-disabled" xlink:href="#bookmarked-shape"/>
|
||||
</svg>
|
До Ширина: | Высота: | Размер: 4.2 KiB |
|
@ -56,6 +56,19 @@ elif CONFIG['OS_TARGET'] == 'Darwin':
|
|||
]
|
||||
if not CONFIG['MOZ_IOS']:
|
||||
DEFINES['HAVE_CRT_EXTERNS_H'] = True
|
||||
elif CONFIG['OS_TARGET'] == 'SunOS':
|
||||
DEFINES.update(
|
||||
HAVE_FCNTL_FILE_LOCKING=True,
|
||||
HAVE_SOCKLEN_T=True,
|
||||
_PR_HAVE_OFF64_T=True,
|
||||
_PR_INET6=True,
|
||||
)
|
||||
DEFINES['SOLARIS'] = True
|
||||
SOURCES += ['/nsprpub/pr/src/md/unix/solaris.c']
|
||||
if CONFIG['CPU_ARCH'] == 'x86_64':
|
||||
SOURCES += ['/nsprpub/pr/src/md/unix/os_SunOS_x86_64.s']
|
||||
elif CONFIG['CPU_ARCH'] == 'x86':
|
||||
SOURCES += ['/nsprpub/pr/src/md/unix/os_SunOS_x86.s']
|
||||
elif CONFIG['OS_TARGET'] == 'WINNT':
|
||||
OS_LIBS += [
|
||||
'advapi32',
|
||||
|
@ -229,6 +242,7 @@ EXPORTS.nspr.md += [
|
|||
'/nsprpub/pr/include/md/_linux.cfg',
|
||||
'/nsprpub/pr/include/md/_netbsd.cfg',
|
||||
'/nsprpub/pr/include/md/_openbsd.cfg',
|
||||
'/nsprpub/pr/include/md/_solaris.cfg',
|
||||
'/nsprpub/pr/include/md/_win95.cfg',
|
||||
]
|
||||
|
||||
|
|
|
@ -22,6 +22,8 @@
|
|||
#include "md/_openbsd.cfg"
|
||||
#elif defined(__linux__)
|
||||
#include "md/_linux.cfg"
|
||||
#elif defined(__sun__)
|
||||
#include "md/_solaris.cfg"
|
||||
#else
|
||||
#error "Unsupported platform!"
|
||||
#endif
|
||||
|
|
|
@ -0,0 +1,10 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Do not save bytecode on compilation errors</title>
|
||||
</head>
|
||||
<body>
|
||||
<script id="watchme" src="file_js_cache_syntax_error.js"></script>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1 @@
|
|||
var // SyntaxError: missing variable name.
|
|
@ -760,6 +760,8 @@ support-files =
|
|||
file_js_cache.js
|
||||
file_js_cache_save_after_load.html
|
||||
file_js_cache_save_after_load.js
|
||||
file_js_cache_syntax_error.html
|
||||
file_js_cache_syntax_error.js
|
||||
[test_setInterval_uncatchable_exception.html]
|
||||
skip-if = debug == false
|
||||
[test_settimeout_extra_arguments.html]
|
||||
|
|
|
@ -191,6 +191,23 @@
|
|||
|
||||
}, "Save bytecode after the initialization of the page");
|
||||
|
||||
promise_test(async function() {
|
||||
// (see above)
|
||||
await SpecialPowers.pushPrefEnv({set: [
|
||||
['dom.script_loader.bytecode_cache.enabled', true],
|
||||
['dom.expose_test_interfaces', true],
|
||||
['dom.script_loader.bytecode_cache.strategy', -1]
|
||||
]});
|
||||
|
||||
// The test page loads a script which contains a syntax error, we should
|
||||
// not attempt to encode any bytecode for it.
|
||||
var stateMachineResult =
|
||||
WaitForScriptTagEvent("file_js_cache_syntax_error.html");
|
||||
assert_equals(await stateMachineResult, "source_exec",
|
||||
"Check the lack of bytecode encoding");
|
||||
|
||||
}, "Do not save bytecode on compilation errors");
|
||||
|
||||
done();
|
||||
</script>
|
||||
</head>
|
||||
|
|
|
@ -657,6 +657,53 @@ public:
|
|||
}
|
||||
};
|
||||
|
||||
struct SRIVerifierAndOutputHolder {
|
||||
SRIVerifierAndOutputHolder(SRICheckDataVerifier* aVerifier,
|
||||
nsIOutputStream* aOutputStream)
|
||||
: mVerifier(aVerifier)
|
||||
, mOutputStream(aOutputStream)
|
||||
{}
|
||||
|
||||
SRICheckDataVerifier* mVerifier;
|
||||
nsIOutputStream* mOutputStream;
|
||||
|
||||
private:
|
||||
SRIVerifierAndOutputHolder() = delete;
|
||||
};
|
||||
|
||||
// Just like NS_CopySegmentToStream, but also sends the data into an
|
||||
// SRICheckDataVerifier.
|
||||
nsresult
|
||||
CopySegmentToStreamAndSRI(nsIInputStream* aInStr,
|
||||
void* aClosure,
|
||||
const char* aBuffer,
|
||||
uint32_t aOffset,
|
||||
uint32_t aCount,
|
||||
uint32_t* aCountWritten)
|
||||
{
|
||||
auto holder = static_cast<SRIVerifierAndOutputHolder*>(aClosure);
|
||||
MOZ_DIAGNOSTIC_ASSERT(holder && holder->mVerifier && holder->mOutputStream,
|
||||
"Bogus holder");
|
||||
nsresult rv =
|
||||
holder->mVerifier->Update(aCount,
|
||||
reinterpret_cast<const uint8_t*>(aBuffer));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// The rest is just like NS_CopySegmentToStream.
|
||||
*aCountWritten = 0;
|
||||
while (aCount) {
|
||||
uint32_t n = 0;
|
||||
rv = holder->mOutputStream->Write(aBuffer, aCount, &n);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
aBuffer += n;
|
||||
aCount -= n;
|
||||
*aCountWritten += n;
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
NS_IMETHODIMP
|
||||
|
@ -692,41 +739,12 @@ FetchDriver::OnDataAvailable(nsIRequest* aRequest,
|
|||
!mRequest->GetIntegrity().IsEmpty()) {
|
||||
MOZ_ASSERT(mSRIDataVerifier);
|
||||
|
||||
uint32_t aWrite;
|
||||
nsTArray<uint8_t> buffer;
|
||||
nsresult rv;
|
||||
buffer.SetCapacity(aCount);
|
||||
while (aCount > 0) {
|
||||
rv = aInputStream->Read(reinterpret_cast<char*>(buffer.Elements()),
|
||||
aCount, &aRead);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
SRIVerifierAndOutputHolder holder(mSRIDataVerifier, mPipeOutputStream);
|
||||
nsresult rv = aInputStream->ReadSegments(CopySegmentToStreamAndSRI,
|
||||
&holder, aCount, &aRead);
|
||||
return rv;
|
||||
}
|
||||
|
||||
rv = mSRIDataVerifier->Update(aRead, (uint8_t*)buffer.Elements());
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
while (aRead > 0) {
|
||||
rv = mPipeOutputStream->Write(reinterpret_cast<char*>(buffer.Elements()),
|
||||
aRead, &aWrite);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
if (aRead < aWrite) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
aRead -= aWrite;
|
||||
}
|
||||
|
||||
|
||||
aCount -= aWrite;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult rv = aInputStream->ReadSegments(NS_CopySegmentToStream,
|
||||
mPipeOutputStream,
|
||||
aCount, &aRead);
|
||||
|
|
|
@ -48,6 +48,10 @@ function runTest() {
|
|||
checkCueEvents();
|
||||
}
|
||||
|
||||
video.onloadedmetadata = function () {
|
||||
ok(video.duration > 2, "video.duration should larger than 2");
|
||||
}
|
||||
|
||||
info("--- create the type of track ---");
|
||||
isnot(window.TextTrack, undefined, "TextTrack should be defined.");
|
||||
|
||||
|
@ -59,7 +63,7 @@ function runTest() {
|
|||
isnot(window.TextTrackCue, undefined, "TextTrackCue should be defined.");
|
||||
isnot(window.VTTCue, undefined, "VTTCue should be defined.");
|
||||
|
||||
var cue = new VTTCue(0, 1, "Test cue");
|
||||
var cue = new VTTCue(1, 2, "Test cue");
|
||||
ok(cue instanceof TextTrackCue, "Cue should be an instanceof TextTrackCue.");
|
||||
ok(cue instanceof VTTCue, "Cue should be an instanceof VTTCue.");
|
||||
|
||||
|
@ -76,7 +80,7 @@ function runTest() {
|
|||
if (cueChrome.getActive) {
|
||||
checkCueDisplayState(cue, true /* has display-state */);
|
||||
} else {
|
||||
ok(false, "The cue start time is 0, should be always active!?");
|
||||
info("This is a missing cue, video.currentTime is "+ video.currentTime);
|
||||
}
|
||||
|
||||
cue.onexit = function () {
|
||||
|
|
|
@ -2132,7 +2132,7 @@ ScriptLoader::EvaluateScript(ScriptLoadRequest* aRequest)
|
|||
}
|
||||
|
||||
// Queue the current script load request to later save the bytecode.
|
||||
if (NS_SUCCEEDED(rv) && encodeBytecode) {
|
||||
if (script && encodeBytecode) {
|
||||
aRequest->mScript = script;
|
||||
HoldJSObjects(aRequest);
|
||||
TRACE_FOR_TEST(aRequest->mElement, "scriptloader_encode");
|
||||
|
|
|
@ -135,6 +135,7 @@ nsCSPParser::nsCSPParser(cspTokens& aTokens,
|
|||
, mUnsafeInlineKeywordSrc(nullptr)
|
||||
, mChildSrc(nullptr)
|
||||
, mFrameSrc(nullptr)
|
||||
, mParsingFrameAncestorsDir(false)
|
||||
, mTokens(aTokens)
|
||||
, mSelfURI(aSelfURI)
|
||||
, mPolicy(nullptr)
|
||||
|
@ -813,6 +814,7 @@ nsCSPParser::sourceExpression()
|
|||
if (nsCSPHostSrc *cspHost = hostSource()) {
|
||||
// Do not forget to set the parsed scheme.
|
||||
cspHost->setScheme(parsedScheme);
|
||||
cspHost->setWithinFrameAncestorsDir(mParsingFrameAncestorsDir);
|
||||
return cspHost;
|
||||
}
|
||||
// Error was reported in hostSource()
|
||||
|
@ -1220,6 +1222,9 @@ nsCSPParser::directive()
|
|||
mStrictDynamic = false;
|
||||
mUnsafeInlineKeywordSrc = nullptr;
|
||||
|
||||
mParsingFrameAncestorsDir =
|
||||
CSP_IsDirective(mCurDir[0], nsIContentSecurityPolicy::FRAME_ANCESTORS_DIRECTIVE);
|
||||
|
||||
// Try to parse all the srcs by handing the array off to directiveValue
|
||||
nsTArray<nsCSPBaseSrc*> srcs;
|
||||
directiveValue(srcs);
|
||||
|
|
|
@ -251,6 +251,10 @@ class nsCSPParser {
|
|||
nsCSPChildSrcDirective* mChildSrc;
|
||||
nsCSPDirective* mFrameSrc;
|
||||
|
||||
// cache variable to let nsCSPHostSrc know that it's within
|
||||
// the frame-ancestors directive.
|
||||
bool mParsingFrameAncestorsDir;
|
||||
|
||||
cspTokens mTokens;
|
||||
nsIURI* mSelfURI;
|
||||
nsCSPPolicy* mPolicy;
|
||||
|
|
|
@ -522,6 +522,7 @@ nsCSPSchemeSrc::toString(nsAString& outStr) const
|
|||
nsCSPHostSrc::nsCSPHostSrc(const nsAString& aHost)
|
||||
: mHost(aHost)
|
||||
, mGeneratedFromSelfKeyword(false)
|
||||
, mWithinFrameAncstorsDir(false)
|
||||
{
|
||||
ToLowerCase(mHost);
|
||||
}
|
||||
|
@ -705,6 +706,11 @@ nsCSPHostSrc::permits(nsIURI* aUri, const nsAString& aNonce, bool aWasRedirected
|
|||
rv = url->GetFilePath(uriPath);
|
||||
NS_ENSURE_SUCCESS(rv, false);
|
||||
|
||||
if (mWithinFrameAncstorsDir) {
|
||||
// no path matching for frame-ancestors to not leak any path information.
|
||||
return true;
|
||||
}
|
||||
|
||||
nsString decodedUriPath;
|
||||
CSP_PercentDecodeStr(NS_ConvertUTF8toUTF16(uriPath), decodedUriPath);
|
||||
|
||||
|
|
|
@ -259,6 +259,9 @@ class nsCSPHostSrc : public nsCSPBaseSrc {
|
|||
inline void setGeneratedFromSelfKeyword() const
|
||||
{ mGeneratedFromSelfKeyword = true; }
|
||||
|
||||
inline void setWithinFrameAncestorsDir(bool aValue) const
|
||||
{ mWithinFrameAncstorsDir = aValue; }
|
||||
|
||||
inline void getScheme(nsAString& outStr) const
|
||||
{ outStr.Assign(mScheme); };
|
||||
|
||||
|
@ -277,6 +280,7 @@ class nsCSPHostSrc : public nsCSPBaseSrc {
|
|||
nsString mPort;
|
||||
nsString mPath;
|
||||
mutable bool mGeneratedFromSelfKeyword;
|
||||
mutable bool mWithinFrameAncstorsDir;
|
||||
};
|
||||
|
||||
/* =============== nsCSPKeywordSrc ============ */
|
||||
|
|
|
@ -9,7 +9,10 @@ function setupFrames() {
|
|||
b: 'http://example.com/tests/dom/security/test/csp/file_frameancestors.sjs'
|
||||
};
|
||||
|
||||
var host = { a: 'http://mochi.test:8888', b: 'http://example.com:80' };
|
||||
// In both cases (base.a, base.b) the path starts with /tests/. Let's make sure this
|
||||
// path within the CSP policy is completely ignored when enforcing frame ancestors.
|
||||
// To test this behavior we use /foo/ and /bar/ as dummy values for the path.
|
||||
var host = { a: 'http://mochi.test:8888/foo/', b: 'http://example.com:80/bar/' };
|
||||
|
||||
var innerframeuri = null;
|
||||
var elt = null;
|
||||
|
|
|
@ -2250,6 +2250,12 @@ public:
|
|||
return mEventRegionsOverride;
|
||||
}
|
||||
|
||||
void SetFilterChain(nsTArray<CSSFilter>&& aFilterChain) {
|
||||
mFilterChain = aFilterChain;
|
||||
}
|
||||
|
||||
nsTArray<CSSFilter>& GetFilterChain() { return mFilterChain; }
|
||||
|
||||
protected:
|
||||
friend class ReadbackProcessor;
|
||||
|
||||
|
@ -2336,6 +2342,7 @@ protected:
|
|||
// the intermediate surface.
|
||||
bool mChildrenChanged;
|
||||
EventRegionsOverride mEventRegionsOverride;
|
||||
nsTArray<CSSFilter> mFilterChain;
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
@ -0,0 +1,38 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "LayersTypes.h"
|
||||
|
||||
#include "nsStyleStruct.h" // for nsStyleFilter
|
||||
|
||||
namespace mozilla {
|
||||
namespace layers {
|
||||
|
||||
CSSFilter ToCSSFilter(const nsStyleFilter& filter)
|
||||
{
|
||||
switch (filter.GetType()) {
|
||||
case NS_STYLE_FILTER_BRIGHTNESS: {
|
||||
return {
|
||||
CSSFilterType::BRIGHTNESS,
|
||||
filter.GetFilterParameter().GetFactorOrPercentValue(),
|
||||
};
|
||||
}
|
||||
case NS_STYLE_FILTER_CONTRAST: {
|
||||
return {
|
||||
CSSFilterType::CONTRAST,
|
||||
filter.GetFilterParameter().GetFactorOrPercentValue(),
|
||||
};
|
||||
}
|
||||
// All other filter types should be prevented by the code which converts
|
||||
// display items into layers.
|
||||
default:
|
||||
MOZ_ASSERT_UNREACHABLE("Tried to convert an unsupported filter");
|
||||
return { CSSFilterType::CONTRAST, 0 };
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace layers
|
||||
} // namespace mozilla
|
||||
|
|
@ -35,6 +35,8 @@ namespace android {
|
|||
class MOZ_EXPORT GraphicBuffer;
|
||||
} // namespace android
|
||||
|
||||
struct nsStyleFilter;
|
||||
|
||||
namespace mozilla {
|
||||
namespace layers {
|
||||
|
||||
|
@ -309,6 +311,25 @@ enum class ScrollDirection : uint32_t {
|
|||
SENTINEL /* for IPC serialization */
|
||||
};
|
||||
|
||||
enum class CSSFilterType : int8_t {
|
||||
BLUR,
|
||||
BRIGHTNESS,
|
||||
CONTRAST,
|
||||
GRAYSCALE,
|
||||
HUE_ROTATE,
|
||||
INVERT,
|
||||
OPACITY,
|
||||
SATURATE,
|
||||
SEPIA,
|
||||
};
|
||||
|
||||
struct CSSFilter {
|
||||
CSSFilterType type;
|
||||
float argument;
|
||||
};
|
||||
|
||||
CSSFilter ToCSSFilter(const nsStyleFilter& filter);
|
||||
|
||||
} // namespace layers
|
||||
} // namespace mozilla
|
||||
|
||||
|
|
|
@ -383,6 +383,7 @@ UNIFIED_SOURCES += [
|
|||
'LayerScope.cpp',
|
||||
'LayersLogging.cpp',
|
||||
'LayerSorter.cpp',
|
||||
'LayersTypes.cpp',
|
||||
'opengl/CompositingRenderTargetOGL.cpp',
|
||||
'opengl/CompositorOGL.cpp',
|
||||
'opengl/GLBlitTextureImageHelper.cpp',
|
||||
|
|
|
@ -20,16 +20,19 @@ StackingContextHelper::StackingContextHelper()
|
|||
StackingContextHelper::StackingContextHelper(const StackingContextHelper& aParentSC,
|
||||
wr::DisplayListBuilder& aBuilder,
|
||||
WebRenderLayer* aLayer,
|
||||
const Maybe<gfx::Matrix4x4>& aTransform)
|
||||
const Maybe<gfx::Matrix4x4>& aTransform,
|
||||
const nsTArray<WrFilterOp>& aFilters)
|
||||
: mBuilder(&aBuilder)
|
||||
{
|
||||
WrRect scBounds = aParentSC.ToRelativeWrRect(aLayer->BoundsForStackingContext());
|
||||
Layer* layer = aLayer->GetLayer();
|
||||
mTransform = aTransform.valueOr(layer->GetTransform());
|
||||
|
||||
float opacity = 1.0f;
|
||||
mBuilder->PushStackingContext(scBounds, 0, &opacity,
|
||||
mTransform.IsIdentity() ? nullptr : &mTransform,
|
||||
wr::ToWrMixBlendMode(layer->GetMixBlendMode()));
|
||||
wr::ToWrMixBlendMode(layer->GetMixBlendMode()),
|
||||
aFilters);
|
||||
mOrigin = aLayer->Bounds().TopLeft();
|
||||
}
|
||||
|
||||
|
@ -38,18 +41,21 @@ StackingContextHelper::StackingContextHelper(const StackingContextHelper& aParen
|
|||
WebRenderLayer* aLayer,
|
||||
uint64_t aAnimationsId,
|
||||
float* aOpacityPtr,
|
||||
gfx::Matrix4x4* aTransformPtr)
|
||||
gfx::Matrix4x4* aTransformPtr,
|
||||
const nsTArray<WrFilterOp>& aFilters)
|
||||
: mBuilder(&aBuilder)
|
||||
{
|
||||
WrRect scBounds = aParentSC.ToRelativeWrRect(aLayer->BoundsForStackingContext());
|
||||
if (aTransformPtr) {
|
||||
mTransform = *aTransformPtr;
|
||||
}
|
||||
|
||||
mBuilder->PushStackingContext(scBounds,
|
||||
aAnimationsId,
|
||||
aOpacityPtr,
|
||||
aTransformPtr,
|
||||
wr::ToWrMixBlendMode(aLayer->GetLayer()->GetMixBlendMode()));
|
||||
wr::ToWrMixBlendMode(aLayer->GetLayer()->GetMixBlendMode()),
|
||||
aFilters);
|
||||
mOrigin = aLayer->Bounds().TopLeft();
|
||||
}
|
||||
|
||||
|
|
|
@ -31,7 +31,8 @@ public:
|
|||
StackingContextHelper(const StackingContextHelper& aParentSC,
|
||||
wr::DisplayListBuilder& aBuilder,
|
||||
WebRenderLayer* aLayer,
|
||||
const Maybe<gfx::Matrix4x4>& aTransform = Nothing());
|
||||
const Maybe<gfx::Matrix4x4>& aTransform = Nothing(),
|
||||
const nsTArray<WrFilterOp>& aFilters = nsTArray<WrFilterOp>());
|
||||
// Alternate constructor which invokes the version of PushStackingContext
|
||||
// for animations.
|
||||
StackingContextHelper(const StackingContextHelper& aParentSC,
|
||||
|
@ -39,7 +40,8 @@ public:
|
|||
WebRenderLayer* aLayer,
|
||||
uint64_t aAnimationsId,
|
||||
float* aOpacityPtr,
|
||||
gfx::Matrix4x4* aTransformPtr);
|
||||
gfx::Matrix4x4* aTransformPtr,
|
||||
const nsTArray<WrFilterOp>& aFilters = nsTArray<WrFilterOp>());
|
||||
// This version of the constructor should only be used at the root level
|
||||
// of the tree, so that we have a StackingContextHelper to pass down into
|
||||
// the RenderLayer traversal, but don't actually want it to push a stacking
|
||||
|
|
|
@ -352,7 +352,8 @@ WebRenderCompositableHolder::ApplyAsyncImages(wr::WebRenderAPI* aApi)
|
|||
0,
|
||||
&opacity,
|
||||
holder->mScTransform.IsIdentity() ? nullptr : &holder->mScTransform,
|
||||
holder->mMixBlendMode);
|
||||
holder->mMixBlendMode,
|
||||
nsTArray<WrFilterOp>());
|
||||
|
||||
LayerRect rect(0, 0, holder->mCurrentTexture->GetSize().width, holder->mCurrentTexture->GetSize().height);
|
||||
if (holder->mScaleToSize.isSome()) {
|
||||
|
|
|
@ -114,8 +114,13 @@ WebRenderContainerLayer::RenderLayer(wr::DisplayListBuilder& aBuilder,
|
|||
transformForSC = nullptr;
|
||||
}
|
||||
|
||||
nsTArray<WrFilterOp> filters;
|
||||
for (const CSSFilter& filter : this->GetFilterChain()) {
|
||||
filters.AppendElement(wr::ToWrFilterOp(filter));
|
||||
}
|
||||
|
||||
ScrollingLayersHelper scroller(this, aBuilder, aSc);
|
||||
StackingContextHelper sc(aSc, aBuilder, this, animationsId, opacityForSC, transformForSC);
|
||||
StackingContextHelper sc(aSc, aBuilder, this, animationsId, opacityForSC, transformForSC, filters);
|
||||
|
||||
LayerRect rect = Bounds();
|
||||
DumpLayerInfo("ContainerLayer", rect);
|
||||
|
|
|
@ -504,6 +504,7 @@ private:
|
|||
DECL_OVERRIDE_PREF(Live, "layers.advanced.caret-layers", LayersAllowCaretLayers, gfxPrefs::OverrideBase_WebRender());
|
||||
DECL_OVERRIDE_PREF(Live, "layers.advanced.columnRule-layers", LayersAllowColumnRuleLayers, gfxPrefs::OverrideBase_WebRender());
|
||||
DECL_OVERRIDE_PREF(Live, "layers.advanced.displaybuttonborder-layers", LayersAllowDisplayButtonBorder, gfxPrefs::OverrideBase_WebRender());
|
||||
DECL_OVERRIDE_PREF(Live, "layers.advanced.filter-layers", LayersAllowFilterLayers, gfxPrefs::OverrideBase_WebRender());
|
||||
DECL_OVERRIDE_PREF(Live, "layers.advanced.image-layers", LayersAllowImageLayers, gfxPrefs::OverrideBase_WebRendest());
|
||||
DECL_OVERRIDE_PREF(Live, "layers.advanced.outline-layers", LayersAllowOutlineLayers, gfxPrefs::OverrideBase_WebRender());
|
||||
DECL_OVERRIDE_PREF(Live, "layers.advanced.solid-color", LayersAllowSolidColorLayers, gfxPrefs::OverrideBase_WebRender());
|
||||
|
|
|
@ -556,7 +556,8 @@ DisplayListBuilder::PushStackingContext(const WrRect& aBounds,
|
|||
const uint64_t& aAnimationId,
|
||||
const float* aOpacity,
|
||||
const gfx::Matrix4x4* aTransform,
|
||||
const WrMixBlendMode& aMixBlendMode)
|
||||
const WrMixBlendMode& aMixBlendMode,
|
||||
const nsTArray<WrFilterOp>& aFilters)
|
||||
{
|
||||
WrMatrix matrix;
|
||||
if (aTransform) {
|
||||
|
@ -566,7 +567,8 @@ DisplayListBuilder::PushStackingContext(const WrRect& aBounds,
|
|||
WRDL_LOG("PushStackingContext b=%s t=%s\n", Stringify(aBounds).c_str(),
|
||||
aTransform ? Stringify(*aTransform).c_str() : "none");
|
||||
wr_dp_push_stacking_context(mWrState, aBounds, aAnimationId, aOpacity,
|
||||
maybeTransform, aMixBlendMode);
|
||||
maybeTransform, aMixBlendMode,
|
||||
aFilters.Elements(), aFilters.Length());
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
@ -150,7 +150,8 @@ public:
|
|||
const uint64_t& aAnimationId,
|
||||
const float* aOpacity,
|
||||
const gfx::Matrix4x4* aTransform,
|
||||
const WrMixBlendMode& aMixBlendMode);
|
||||
const WrMixBlendMode& aMixBlendMode,
|
||||
const nsTArray<WrFilterOp>& aFilters);
|
||||
void PopStackingContext();
|
||||
|
||||
void PushClip(const WrRect& aClipRect,
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
#include "mozilla/gfx/Matrix.h"
|
||||
#include "mozilla/gfx/Types.h"
|
||||
#include "mozilla/gfx/Tools.h"
|
||||
#include "mozilla/layers/LayersTypes.h"
|
||||
#include "mozilla/Range.h"
|
||||
#include "Units.h"
|
||||
#include "nsStyleConsts.h"
|
||||
|
@ -551,6 +552,38 @@ struct BuiltDisplayList {
|
|||
WrBuiltDisplayListDescriptor dl_desc;
|
||||
};
|
||||
|
||||
static inline WrFilterOpType ToWrFilterOpType(const layers::CSSFilterType type) {
|
||||
switch (type) {
|
||||
case layers::CSSFilterType::BLUR:
|
||||
return WrFilterOpType::Blur;
|
||||
case layers::CSSFilterType::BRIGHTNESS:
|
||||
return WrFilterOpType::Brightness;
|
||||
case layers::CSSFilterType::CONTRAST:
|
||||
return WrFilterOpType::Contrast;
|
||||
case layers::CSSFilterType::GRAYSCALE:
|
||||
return WrFilterOpType::Grayscale;
|
||||
case layers::CSSFilterType::HUE_ROTATE:
|
||||
return WrFilterOpType::HueRotate;
|
||||
case layers::CSSFilterType::INVERT:
|
||||
return WrFilterOpType::Invert;
|
||||
case layers::CSSFilterType::OPACITY:
|
||||
return WrFilterOpType::Opacity;
|
||||
case layers::CSSFilterType::SATURATE:
|
||||
return WrFilterOpType::Saturate;
|
||||
case layers::CSSFilterType::SEPIA:
|
||||
return WrFilterOpType::Sepia;
|
||||
}
|
||||
MOZ_ASSERT_UNREACHABLE("Tried to convert unknown filter type.");
|
||||
return WrFilterOpType::Grayscale;
|
||||
}
|
||||
|
||||
static inline WrFilterOp ToWrFilterOp(const layers::CSSFilter& filter) {
|
||||
return {
|
||||
ToWrFilterOpType(filter.type),
|
||||
filter.argument,
|
||||
};
|
||||
}
|
||||
|
||||
} // namespace wr
|
||||
} // namespace mozilla
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@ use std::collections::HashSet;
|
|||
use std::ffi::CString;
|
||||
use std::{mem, slice};
|
||||
use std::path::PathBuf;
|
||||
use std::os::raw::{c_void, c_char};
|
||||
use std::os::raw::{c_void, c_char, c_float};
|
||||
use std::collections::HashMap;
|
||||
use gleam::gl;
|
||||
|
||||
|
@ -59,6 +59,27 @@ type WrYuvColorSpace = YuvColorSpace;
|
|||
#[derive(Copy, Clone)]
|
||||
pub struct WrExternalImageId(pub u64);
|
||||
|
||||
#[repr(u32)]
|
||||
#[derive(Copy, Clone)]
|
||||
pub enum WrFilterOpType {
|
||||
Blur = 0,
|
||||
Brightness = 1,
|
||||
Contrast = 2,
|
||||
Grayscale = 3,
|
||||
HueRotate = 4,
|
||||
Invert = 5,
|
||||
Opacity = 6,
|
||||
Saturate = 7,
|
||||
Sepia = 8,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct WrFilterOp {
|
||||
filter_type: WrFilterOpType,
|
||||
argument: c_float,
|
||||
}
|
||||
|
||||
impl Into<ExternalImageId> for WrExternalImageId {
|
||||
fn into(self) -> ExternalImageId {
|
||||
ExternalImageId(self.0)
|
||||
|
@ -1245,12 +1266,28 @@ pub extern "C" fn wr_dp_push_stacking_context(state: &mut WrState,
|
|||
animation_id: u64,
|
||||
opacity: *const f32,
|
||||
transform: *const WrMatrix,
|
||||
mix_blend_mode: WrMixBlendMode) {
|
||||
mix_blend_mode: WrMixBlendMode,
|
||||
filters: *const WrFilterOp,
|
||||
filter_count: usize) {
|
||||
assert!(unsafe { !is_in_render_thread() });
|
||||
|
||||
let bounds = bounds.into();
|
||||
|
||||
let mut filters: Vec<FilterOp> = Vec::new();
|
||||
let c_filters = make_slice(filters, filter_count);
|
||||
let mut filters : Vec<FilterOp> = c_filters.iter().map(|c_filter| {
|
||||
match c_filter.filter_type {
|
||||
WrFilterOpType::Blur => FilterOp::Blur(Au::from_f32_px(c_filter.argument)),
|
||||
WrFilterOpType::Brightness => FilterOp::Brightness(c_filter.argument),
|
||||
WrFilterOpType::Contrast => FilterOp::Contrast(c_filter.argument),
|
||||
WrFilterOpType::Grayscale => FilterOp::Grayscale(c_filter.argument),
|
||||
WrFilterOpType::HueRotate => FilterOp::HueRotate(c_filter.argument),
|
||||
WrFilterOpType::Invert => FilterOp::Invert(c_filter.argument),
|
||||
WrFilterOpType::Opacity => FilterOp::Opacity(PropertyBinding::Value(c_filter.argument)),
|
||||
WrFilterOpType::Saturate => FilterOp::Saturate(c_filter.argument),
|
||||
WrFilterOpType::Sepia => FilterOp::Sepia(c_filter.argument),
|
||||
}
|
||||
}).collect();
|
||||
|
||||
let opacity = unsafe { opacity.as_ref() };
|
||||
if let Some(opacity) = opacity {
|
||||
if *opacity < 1.0 {
|
||||
|
|
|
@ -51,6 +51,20 @@ enum class WrExternalImageType : uint32_t {
|
|||
Sentinel /* this must be last for serialization purposes. */
|
||||
};
|
||||
|
||||
enum class WrFilterOpType : uint32_t {
|
||||
Blur = 0,
|
||||
Brightness = 1,
|
||||
Contrast = 2,
|
||||
Grayscale = 3,
|
||||
HueRotate = 4,
|
||||
Invert = 5,
|
||||
Opacity = 6,
|
||||
Saturate = 7,
|
||||
Sepia = 8,
|
||||
|
||||
Sentinel /* this must be last for serialization purposes. */
|
||||
};
|
||||
|
||||
enum class WrGradientExtendMode : uint32_t {
|
||||
Clamp = 0,
|
||||
Repeat = 1,
|
||||
|
@ -423,6 +437,16 @@ struct WrComplexClipRegion {
|
|||
}
|
||||
};
|
||||
|
||||
struct WrFilterOp {
|
||||
WrFilterOpType filter_type;
|
||||
float argument;
|
||||
|
||||
bool operator==(const WrFilterOp& aOther) const {
|
||||
return filter_type == aOther.filter_type &&
|
||||
argument == aOther.argument;
|
||||
}
|
||||
};
|
||||
|
||||
struct WrGlyphInstance {
|
||||
uint32_t index;
|
||||
WrPoint point;
|
||||
|
@ -784,7 +808,9 @@ void wr_dp_push_stacking_context(WrState *aState,
|
|||
uint64_t aAnimationId,
|
||||
const float *aOpacity,
|
||||
const WrMatrix *aTransform,
|
||||
WrMixBlendMode aMixBlendMode)
|
||||
WrMixBlendMode aMixBlendMode,
|
||||
const WrFilterOp *aFilters,
|
||||
size_t aFilterCount)
|
||||
WR_FUNC;
|
||||
|
||||
WR_INLINE
|
||||
|
|
|
@ -471,6 +471,7 @@ RasterImage::OnSurfaceDiscardedInternal(bool aAnimatedFramesDiscarded)
|
|||
|
||||
if (aAnimatedFramesDiscarded && mAnimationState) {
|
||||
MOZ_ASSERT(gfxPrefs::ImageMemAnimatedDiscardable());
|
||||
mImageContainer = nullptr;
|
||||
gfx::IntRect rect =
|
||||
mAnimationState->UpdateState(mAnimationFinished, this, mSize);
|
||||
NotifyProgress(NoProgress, rect);
|
||||
|
@ -1086,6 +1087,7 @@ RasterImage::Discard()
|
|||
SurfaceCache::RemoveImage(ImageKey(this));
|
||||
|
||||
if (mAnimationState) {
|
||||
mImageContainer = nullptr;
|
||||
gfx::IntRect rect =
|
||||
mAnimationState->UpdateState(mAnimationFinished, this, mSize);
|
||||
NotifyProgress(NoProgress, rect);
|
||||
|
|
|
@ -915,11 +915,11 @@ class HashTable : private AllocPolicy
|
|||
{}
|
||||
|
||||
bool isValid() const {
|
||||
return !entry_;
|
||||
return !!entry_;
|
||||
}
|
||||
|
||||
bool found() const {
|
||||
if (isValid())
|
||||
if (!isValid())
|
||||
return false;
|
||||
#ifdef JS_DEBUG
|
||||
MOZ_ASSERT(generation == table_->generation());
|
||||
|
@ -1789,11 +1789,12 @@ class HashTable : private AllocPolicy
|
|||
{
|
||||
mozilla::ReentrancyGuard g(*this);
|
||||
MOZ_ASSERT(table);
|
||||
MOZ_ASSERT_IF(p.isValid(), p.table_ == this);
|
||||
MOZ_ASSERT(!p.found());
|
||||
MOZ_ASSERT(!(p.keyHash & sCollisionBit));
|
||||
|
||||
// Check for error from ensureHash() here.
|
||||
if (p.isValid())
|
||||
if (!p.isValid())
|
||||
return false;
|
||||
|
||||
// Changing an entry from removed to live does not affect whether we
|
||||
|
@ -1859,7 +1860,7 @@ class HashTable : private AllocPolicy
|
|||
MOZ_MUST_USE bool relookupOrAdd(AddPtr& p, const Lookup& l, Args&&... args)
|
||||
{
|
||||
// Check for error from ensureHash() here.
|
||||
if (p.isValid())
|
||||
if (!p.isValid())
|
||||
return false;
|
||||
|
||||
#ifdef JS_DEBUG
|
||||
|
|
|
@ -37,7 +37,7 @@ struct ForEachTrackedOptimizationAttemptOp;
|
|||
struct ForEachTrackedOptimizationTypeInfoOp;
|
||||
|
||||
// This iterator can be used to walk the stack of a thread suspended at an
|
||||
// arbitrary pc. To provide acurate results, profiling must have been enabled
|
||||
// arbitrary pc. To provide accurate results, profiling must have been enabled
|
||||
// (via EnableRuntimeProfilingStack) before executing the callstack being
|
||||
// unwound.
|
||||
//
|
||||
|
@ -50,11 +50,6 @@ class MOZ_NON_PARAM JS_PUBLIC_API(ProfilingFrameIterator)
|
|||
uint32_t sampleBufferGen_;
|
||||
js::Activation* activation_;
|
||||
|
||||
// When moving past a JitActivation, we need to save the prevJitTop
|
||||
// from it to use as the exit-frame pointer when the next caller jit
|
||||
// activation (if any) comes around.
|
||||
void* savedPrevJitTop_;
|
||||
|
||||
static const unsigned StorageSpace = 8 * sizeof(void*);
|
||||
alignas(void*) unsigned char storage_[StorageSpace];
|
||||
|
||||
|
|
|
@ -50,11 +50,20 @@ function FunctionBind(thisArg, ...boundArgs) {
|
|||
* construct helper functions. This avoids having to use rest parameters and
|
||||
* destructuring in the fast path.
|
||||
*
|
||||
* Directly embedding the for-loop to combine bound and call arguments may
|
||||
* inhibit inlining of the bound function, so we use a separate combiner
|
||||
* function to perform this task. This combiner function is created lazily to
|
||||
* ensure we only pay its construction cost when needed.
|
||||
*
|
||||
* All bind_bindFunction{X} functions have the same signature to enable simple
|
||||
* reading out of closed-over state by debugging functions.
|
||||
*/
|
||||
function bind_bindFunction0(fun, thisArg, boundArgs) {
|
||||
return function bound() {
|
||||
// Ensure we allocate a call-object slot for |boundArgs|, so the
|
||||
// debugger can access this value.
|
||||
if (false) void boundArgs;
|
||||
|
||||
var newTarget;
|
||||
if (_IsConstructing()) {
|
||||
newTarget = new.target;
|
||||
|
@ -73,6 +82,9 @@ function bind_bindFunction0(fun, thisArg, boundArgs) {
|
|||
return constructContentFunction(fun, newTarget, SPREAD(arguments, 4));
|
||||
case 5:
|
||||
return constructContentFunction(fun, newTarget, SPREAD(arguments, 5));
|
||||
default:
|
||||
var args = FUN_APPLY(bind_mapArguments, null, arguments);
|
||||
return bind_constructFunctionN(fun, newTarget, args);
|
||||
}
|
||||
} else {
|
||||
switch (arguments.length) {
|
||||
|
@ -88,16 +100,21 @@ function bind_bindFunction0(fun, thisArg, boundArgs) {
|
|||
return callContentFunction(fun, thisArg, SPREAD(arguments, 4));
|
||||
case 5:
|
||||
return callContentFunction(fun, thisArg, SPREAD(arguments, 5));
|
||||
default:
|
||||
return FUN_APPLY(fun, thisArg, arguments);
|
||||
}
|
||||
}
|
||||
var callArgs = FUN_APPLY(bind_mapArguments, null, arguments);
|
||||
return bind_invokeFunctionN(fun, thisArg, newTarget, boundArgs, callArgs);
|
||||
};
|
||||
}
|
||||
|
||||
function bind_bindFunction1(fun, thisArg, boundArgs) {
|
||||
var bound1 = boundArgs[0];
|
||||
var combiner = null;
|
||||
return function bound() {
|
||||
// Ensure we allocate a call-object slot for |boundArgs|, so the
|
||||
// debugger can access this value.
|
||||
if (false) void boundArgs;
|
||||
|
||||
var newTarget;
|
||||
if (_IsConstructing()) {
|
||||
newTarget = new.target;
|
||||
|
@ -133,15 +150,34 @@ function bind_bindFunction1(fun, thisArg, boundArgs) {
|
|||
return callContentFunction(fun, thisArg, bound1, SPREAD(arguments, 5));
|
||||
}
|
||||
}
|
||||
var callArgs = FUN_APPLY(bind_mapArguments, null, arguments);
|
||||
return bind_invokeFunctionN(fun, thisArg, newTarget, boundArgs, callArgs);
|
||||
|
||||
if (combiner === null) {
|
||||
combiner = function() {
|
||||
var callArgsCount = arguments.length;
|
||||
var args = std_Array(1 + callArgsCount);
|
||||
_DefineDataProperty(args, 0, bound1);
|
||||
for (var i = 0; i < callArgsCount; i++)
|
||||
_DefineDataProperty(args, i + 1, arguments[i]);
|
||||
return args;
|
||||
};
|
||||
}
|
||||
|
||||
var args = FUN_APPLY(combiner, null, arguments);
|
||||
if (newTarget === undefined)
|
||||
return bind_applyFunctionN(fun, thisArg, args);
|
||||
return bind_constructFunctionN(fun, newTarget, args);
|
||||
};
|
||||
}
|
||||
|
||||
function bind_bindFunction2(fun, thisArg, boundArgs) {
|
||||
var bound1 = boundArgs[0];
|
||||
var bound2 = boundArgs[1];
|
||||
var combiner = null;
|
||||
return function bound() {
|
||||
// Ensure we allocate a call-object slot for |boundArgs|, so the
|
||||
// debugger can access this value.
|
||||
if (false) void boundArgs;
|
||||
|
||||
var newTarget;
|
||||
if (_IsConstructing()) {
|
||||
newTarget = new.target;
|
||||
|
@ -177,13 +213,29 @@ function bind_bindFunction2(fun, thisArg, boundArgs) {
|
|||
return callContentFunction(fun, thisArg, bound1, bound2, SPREAD(arguments, 5));
|
||||
}
|
||||
}
|
||||
var callArgs = FUN_APPLY(bind_mapArguments, null, arguments);
|
||||
return bind_invokeFunctionN(fun, thisArg, newTarget, boundArgs, callArgs);
|
||||
|
||||
if (combiner === null) {
|
||||
combiner = function() {
|
||||
var callArgsCount = arguments.length;
|
||||
var args = std_Array(2 + callArgsCount);
|
||||
_DefineDataProperty(args, 0, bound1);
|
||||
_DefineDataProperty(args, 1, bound2);
|
||||
for (var i = 0; i < callArgsCount; i++)
|
||||
_DefineDataProperty(args, i + 2, arguments[i]);
|
||||
return args;
|
||||
};
|
||||
}
|
||||
|
||||
var args = FUN_APPLY(combiner, null, arguments);
|
||||
if (newTarget === undefined)
|
||||
return bind_applyFunctionN(fun, thisArg, args);
|
||||
return bind_constructFunctionN(fun, newTarget, args);
|
||||
};
|
||||
}
|
||||
|
||||
function bind_bindFunctionN(fun, thisArg, boundArgs) {
|
||||
assert(boundArgs.length > 2, "Fast paths should be used for few-bound-args cases.");
|
||||
var combiner = null;
|
||||
return function bound() {
|
||||
var newTarget;
|
||||
if (_IsConstructing()) {
|
||||
|
@ -194,11 +246,26 @@ function bind_bindFunctionN(fun, thisArg, boundArgs) {
|
|||
if (arguments.length === 0) {
|
||||
if (newTarget !== undefined)
|
||||
return bind_constructFunctionN(fun, newTarget, boundArgs);
|
||||
|
||||
return bind_applyFunctionN(fun, thisArg, boundArgs);
|
||||
}
|
||||
var callArgs = FUN_APPLY(bind_mapArguments, null, arguments);
|
||||
return bind_invokeFunctionN(fun, thisArg, newTarget, boundArgs, callArgs);
|
||||
|
||||
if (combiner === null) {
|
||||
combiner = function() {
|
||||
var boundArgsCount = boundArgs.length;
|
||||
var callArgsCount = arguments.length;
|
||||
var args = std_Array(boundArgsCount + callArgsCount);
|
||||
for (var i = 0; i < boundArgsCount; i++)
|
||||
_DefineDataProperty(args, i, boundArgs[i]);
|
||||
for (var i = 0; i < callArgsCount; i++)
|
||||
_DefineDataProperty(args, i + boundArgsCount, arguments[i]);
|
||||
return args;
|
||||
};
|
||||
}
|
||||
|
||||
var args = FUN_APPLY(combiner, null, arguments);
|
||||
if (newTarget !== undefined)
|
||||
return bind_constructFunctionN(fun, newTarget, args);
|
||||
return bind_applyFunctionN(fun, thisArg, args);
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -210,19 +277,6 @@ function bind_mapArguments() {
|
|||
return args;
|
||||
}
|
||||
|
||||
function bind_invokeFunctionN(fun, thisArg, newTarget, boundArgs, callArgs) {
|
||||
var boundArgsCount = boundArgs.length;
|
||||
var callArgsCount = callArgs.length;
|
||||
var args = std_Array(boundArgsCount + callArgsCount);
|
||||
for (var i = 0; i < boundArgsCount; i++)
|
||||
_DefineDataProperty(args, i, boundArgs[i]);
|
||||
for (var i = 0; i < callArgsCount; i++)
|
||||
_DefineDataProperty(args, i + boundArgsCount, callArgs[i]);
|
||||
if (newTarget !== undefined)
|
||||
return bind_constructFunctionN(fun, newTarget, args);
|
||||
return bind_applyFunctionN(fun, thisArg, args);
|
||||
}
|
||||
|
||||
function bind_applyFunctionN(fun, thisArg, args) {
|
||||
switch (args.length) {
|
||||
case 0:
|
||||
|
|
|
@ -436,18 +436,24 @@ function CanonicalizeLanguageTag(locale) {
|
|||
subtags[i] = subtag;
|
||||
i++;
|
||||
}
|
||||
|
||||
// Directly return when the language tag doesn't contain any extension or
|
||||
// private use sub-tags.
|
||||
if (i === subtags.length)
|
||||
return callFunction(std_Array_join, subtags, "-");
|
||||
|
||||
var normal = callFunction(std_Array_join, callFunction(std_Array_slice, subtags, 0, i), "-");
|
||||
|
||||
// Extension sequences are sorted by their singleton characters.
|
||||
// "u-ca-chinese-t-zh-latn" -> "t-zh-latn-u-ca-chinese"
|
||||
var extensions = new List();
|
||||
var extensions = [];
|
||||
while (i < subtags.length && subtags[i] !== "x") {
|
||||
var extensionStart = i;
|
||||
i++;
|
||||
while (i < subtags.length && subtags[i].length > 1)
|
||||
i++;
|
||||
var extension = callFunction(std_Array_join, callFunction(std_Array_slice, subtags, extensionStart, i), "-");
|
||||
callFunction(std_Array_push, extensions, extension);
|
||||
_DefineDataProperty(extensions, extensions.length, extension);
|
||||
}
|
||||
callFunction(std_Array_sort, extensions);
|
||||
|
||||
|
@ -806,10 +812,13 @@ function addSpecialMissingLanguageTags(availableLocales) {
|
|||
*/
|
||||
function CanonicalizeLocaleList(locales) {
|
||||
if (locales === undefined)
|
||||
return new List();
|
||||
var seen = new List();
|
||||
if (typeof locales === "string")
|
||||
locales = [locales];
|
||||
return [];
|
||||
if (typeof locales === "string") {
|
||||
if (!IsStructurallyValidLanguageTag(locales))
|
||||
ThrowRangeError(JSMSG_INVALID_LANGUAGE_TAG, locales);
|
||||
return [CanonicalizeLanguageTag(locales)];
|
||||
}
|
||||
var seen = [];
|
||||
var O = ToObject(locales);
|
||||
var len = ToLength(O.length);
|
||||
var k = 0;
|
||||
|
@ -825,7 +834,7 @@ function CanonicalizeLocaleList(locales) {
|
|||
ThrowRangeError(JSMSG_INVALID_LANGUAGE_TAG, tag);
|
||||
tag = CanonicalizeLanguageTag(tag);
|
||||
if (callFunction(ArrayIndexOf, seen, tag) === -1)
|
||||
callFunction(std_Array_push, seen, tag);
|
||||
_DefineDataProperty(seen, seen.length, tag);
|
||||
}
|
||||
k++;
|
||||
}
|
||||
|
@ -1181,7 +1190,7 @@ function ResolveLocale(availableLocales, requestedLocales, options, relevantExte
|
|||
function LookupSupportedLocales(availableLocales, requestedLocales) {
|
||||
// Steps 1-2.
|
||||
var len = requestedLocales.length;
|
||||
var subset = new List();
|
||||
var subset = [];
|
||||
|
||||
// Steps 3-4.
|
||||
var k = 0;
|
||||
|
@ -1193,14 +1202,14 @@ function LookupSupportedLocales(availableLocales, requestedLocales) {
|
|||
// Step 4.c-d.
|
||||
var availableLocale = BestAvailableLocale(availableLocales, noExtensionsLocale);
|
||||
if (availableLocale !== undefined)
|
||||
callFunction(std_Array_push, subset, locale);
|
||||
_DefineDataProperty(subset, subset.length, locale);
|
||||
|
||||
// Step 4.e.
|
||||
k++;
|
||||
}
|
||||
|
||||
// Steps 5-6.
|
||||
return callFunction(std_Array_slice, subset, 0);
|
||||
return subset;
|
||||
}
|
||||
|
||||
|
||||
|
@ -3438,16 +3447,8 @@ function Intl_PluralRules_resolvedOptions() {
|
|||
* ES2017 Intl draft rev 947aa9a0c853422824a0c9510d8f09be3eb416b9
|
||||
*/
|
||||
function Intl_getCanonicalLocales(locales) {
|
||||
// Step 1.
|
||||
var localeList = CanonicalizeLocaleList(locales);
|
||||
|
||||
// Step 2 (Inlined CreateArrayFromList).
|
||||
var array = [];
|
||||
|
||||
for (var n = 0, len = localeList.length; n < len; n++)
|
||||
_DefineDataProperty(array, n, localeList[n]);
|
||||
|
||||
return array;
|
||||
// Steps 1-2.
|
||||
return CanonicalizeLocaleList(locales);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -31,7 +31,7 @@ function FUNC_NAME(rx, S, lengthS, replaceValue, fullUnicode
|
|||
var lastIndex = 0;
|
||||
rx.lastIndex = 0;
|
||||
|
||||
#if defined(FUNCTIONAL)
|
||||
#if defined(FUNCTIONAL) || defined(ELEMBASE)
|
||||
// Save the original source and flags, so we can check if the replacer
|
||||
// function recompiled the regexp.
|
||||
var originalSource = UnsafeGetStringFromReservedSlot(rx, REGEXP_SOURCE_SLOT);
|
||||
|
@ -109,7 +109,7 @@ function FUNC_NAME(rx, S, lengthS, replaceValue, fullUnicode
|
|||
break;
|
||||
}
|
||||
|
||||
#if defined(FUNCTIONAL)
|
||||
#if defined(FUNCTIONAL) || defined(ELEMBASE)
|
||||
// Ensure the current source and flags match the original regexp, the
|
||||
// replaceValue function may have called RegExp#compile.
|
||||
if (UnsafeGetStringFromReservedSlot(rx, REGEXP_SOURCE_SLOT) !== originalSource ||
|
||||
|
|
|
@ -2265,7 +2265,7 @@ Parser<FullParseHandler, char16_t>::moduleBody(ModuleSharedContext* modulesc)
|
|||
DeclaredNamePtr p = modulepc.varScope().lookupDeclaredName(name);
|
||||
if (!p) {
|
||||
JSAutoByteString str;
|
||||
if (!str.encodeLatin1(context, name))
|
||||
if (!AtomToPrintableString(context, name, &str))
|
||||
return null();
|
||||
|
||||
JS_ReportErrorNumberLatin1(context, GetErrorMessage, nullptr,
|
||||
|
|
|
@ -1005,6 +1005,7 @@ class GCRuntime
|
|||
SliceBudget& budget, AllocKind kind);
|
||||
static IncrementalProgress sweepAtomsTable(GCRuntime* gc, FreeOp* fop, Zone* zone,
|
||||
SliceBudget& budget, AllocKind kind);
|
||||
void startSweepingAtomsTable();
|
||||
IncrementalProgress sweepAtomsTable(SliceBudget& budget);
|
||||
static IncrementalProgress finalizeAllocKind(GCRuntime* gc, FreeOp* fop, Zone* zone,
|
||||
SliceBudget& budget, AllocKind kind);
|
||||
|
|
|
@ -434,17 +434,16 @@ class UnwinderState(object):
|
|||
elif self.activation is None:
|
||||
cx = self.get_tls_context()
|
||||
self.activation = cx['jitActivation']
|
||||
jittop = cx['jitTop']
|
||||
else:
|
||||
jittop = self.activation['prevJitTop_']
|
||||
self.activation = self.activation['prevJitActivation_']
|
||||
|
||||
if jittop == 0:
|
||||
exitFP = self.activation['exitFP_']
|
||||
if exitFP == 0:
|
||||
return None
|
||||
|
||||
exit_sp = pending_frame.read_register(self.SP_REGISTER)
|
||||
frame_type = self.typecache.JitFrame_Exit
|
||||
return self.create_frame(pc, exit_sp, jittop, frame_type, pending_frame)
|
||||
return self.create_frame(pc, exit_sp, exitFP, frame_type, pending_frame)
|
||||
|
||||
# A wrapper for unwind_entry_frame_registers that handles
|
||||
# architecture-independent boilerplate.
|
||||
|
|
|
@ -0,0 +1,14 @@
|
|||
function t()
|
||||
{
|
||||
var a = arguments;
|
||||
Object.defineProperty(a, Symbol.iterator, { });
|
||||
for (var i = 0; i < 5; i++)
|
||||
assertEq(a[Symbol.iterator], Array.prototype[Symbol.iterator]);
|
||||
|
||||
var desc = Object.getOwnPropertyDescriptor(a, Symbol.iterator);
|
||||
assertEq(desc.value, Array.prototype[Symbol.iterator]);
|
||||
assertEq(desc.writable, true);
|
||||
assertEq(desc.enumerable, false);
|
||||
assertEq(desc.configurable, true);
|
||||
}
|
||||
t();
|
|
@ -0,0 +1,14 @@
|
|||
function t()
|
||||
{
|
||||
var a = arguments;
|
||||
Object.defineProperty(a, Symbol.iterator, { writable: false, enumerable: true, configurable: false });
|
||||
for (var i = 0; i < 5; i++)
|
||||
assertEq(a[Symbol.iterator], Array.prototype[Symbol.iterator]);
|
||||
|
||||
var desc = Object.getOwnPropertyDescriptor(a, Symbol.iterator);
|
||||
assertEq(desc.value, Array.prototype[Symbol.iterator]);
|
||||
assertEq(desc.writable, false);
|
||||
assertEq(desc.enumerable, true);
|
||||
assertEq(desc.configurable, false);
|
||||
}
|
||||
t();
|
|
@ -0,0 +1,14 @@
|
|||
function t()
|
||||
{
|
||||
var a = arguments;
|
||||
Object.defineProperty(a, "length", { });
|
||||
for (var i = 0; i < 5; i++)
|
||||
assertEq(a.length, 0);
|
||||
|
||||
var desc = Object.getOwnPropertyDescriptor(a, "length");
|
||||
assertEq(desc.value, 0);
|
||||
assertEq(desc.writable, true);
|
||||
assertEq(desc.enumerable, false);
|
||||
assertEq(desc.configurable, true);
|
||||
}
|
||||
t();
|
|
@ -0,0 +1,14 @@
|
|||
function t()
|
||||
{
|
||||
var a = arguments;
|
||||
Object.defineProperty(a, "length", { writable: false });
|
||||
for (var i = 0; i < 5; i++)
|
||||
assertEq(a.length, 0);
|
||||
|
||||
var desc = Object.getOwnPropertyDescriptor(a, "length");
|
||||
assertEq(desc.value, 0);
|
||||
assertEq(desc.writable, false);
|
||||
assertEq(desc.enumerable, false);
|
||||
assertEq(desc.configurable, true);
|
||||
}
|
||||
t();
|
|
@ -0,0 +1,14 @@
|
|||
function t()
|
||||
{
|
||||
var a = arguments;
|
||||
Object.defineProperty(a, "length", { enumerable: true });
|
||||
for (var i = 0; i < 5; i++)
|
||||
assertEq(a.length, 0);
|
||||
|
||||
var desc = Object.getOwnPropertyDescriptor(a, "length");
|
||||
assertEq(desc.value, 0);
|
||||
assertEq(desc.writable, true);
|
||||
assertEq(desc.enumerable, true);
|
||||
assertEq(desc.configurable, true);
|
||||
}
|
||||
t();
|
|
@ -0,0 +1,14 @@
|
|||
function t()
|
||||
{
|
||||
var a = arguments;
|
||||
Object.defineProperty(a, "length", { configurable: false });
|
||||
for (var i = 0; i < 5; i++)
|
||||
assertEq(a.length, 0);
|
||||
|
||||
var desc = Object.getOwnPropertyDescriptor(a, "length");
|
||||
assertEq(desc.value, 0);
|
||||
assertEq(desc.writable, true);
|
||||
assertEq(desc.enumerable, false);
|
||||
assertEq(desc.configurable, false);
|
||||
}
|
||||
t();
|
|
@ -0,0 +1,14 @@
|
|||
function t()
|
||||
{
|
||||
var a = arguments;
|
||||
Object.defineProperty(a, "length", { value: 0 });
|
||||
for (var i = 0; i < 5; i++)
|
||||
assertEq(a.length, 0);
|
||||
|
||||
var desc = Object.getOwnPropertyDescriptor(a, "length");
|
||||
assertEq(desc.value, 0);
|
||||
assertEq(desc.writable, true);
|
||||
assertEq(desc.enumerable, false);
|
||||
assertEq(desc.configurable, true);
|
||||
}
|
||||
t();
|
|
@ -1,3 +1,4 @@
|
|||
gczeal(0);
|
||||
startgc(1, "shrinking");
|
||||
for (var i=0; i<100; i++) {
|
||||
gcslice(100000);
|
||||
|
|
|
@ -0,0 +1,47 @@
|
|||
function test1() {
|
||||
var a = [];
|
||||
for (var i = 0; i < 100; i++)
|
||||
a.unshift("foo" + i);
|
||||
for (var i = 99; i >= 0; i--) {
|
||||
assertEq(a.shift(), "foo" + i);
|
||||
a.unshift("foo" + (i - 1));
|
||||
}
|
||||
assertEq(a.length, 100);
|
||||
}
|
||||
test1();
|
||||
|
||||
function sum(arr) {
|
||||
var res = 0;
|
||||
for (var i = 0; i < arr.length; i++)
|
||||
res += arr[i];
|
||||
return res;
|
||||
}
|
||||
function test2() {
|
||||
var a = [];
|
||||
for (var i = 0; i < 200; i++)
|
||||
a.push(i);
|
||||
for (var i = 0; i < 100; i++)
|
||||
a.shift();
|
||||
for (var i = 0; i < 200; i++)
|
||||
a.unshift(i);
|
||||
assertEq(a.length, 300);
|
||||
assertEq(sum(a), 34850);
|
||||
}
|
||||
test2();
|
||||
|
||||
function test3() {
|
||||
var a = [];
|
||||
for (var i = 0; i < 200; i++)
|
||||
a.push(i);
|
||||
var toAdd = [];
|
||||
var step = 1;
|
||||
for (var i = 0; i < 2500; i += step) {
|
||||
for (var j = 0; j < step; j++)
|
||||
toAdd.unshift(i + j);
|
||||
a.unshift(...toAdd);
|
||||
step = Math.max((i / 16)|0, 1);
|
||||
}
|
||||
assertEq(a.length, 41463);
|
||||
assertEq(sum(a), 26657756);
|
||||
}
|
||||
test3();
|
|
@ -0,0 +1,18 @@
|
|||
g = newGlobal();
|
||||
hits = 0;
|
||||
Debugger(g).onDebuggerStatement = function(frame) {
|
||||
// Set a breakpoint at the JSOP_DEBUGAFTERYIELD op.
|
||||
frame.script.setBreakpoint(71, {hit: function() { hits++; }});
|
||||
}
|
||||
g.eval(`
|
||||
function* range() {
|
||||
debugger;
|
||||
for (var i = 0; i < 3; i++) {
|
||||
yield i;
|
||||
}
|
||||
}
|
||||
var iter = range();
|
||||
for (var i = 0; i < 3; i++)
|
||||
assertEq(iter.next().value, i);
|
||||
`);
|
||||
assertEq(hits, 2);
|
|
@ -1,6 +1,8 @@
|
|||
if (!('oomTest' in this))
|
||||
quit();
|
||||
|
||||
gczeal(0);
|
||||
|
||||
var x1 = [];
|
||||
var x2 = [];
|
||||
var x3 = [];
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
if (helperThreadCount() == 0)
|
||||
quit();
|
||||
gczeal(0);
|
||||
startgc(1, 'shrinking');
|
||||
offThreadCompileScript("");
|
||||
// Adapted from randomly chosen test: js/src/jit-test/tests/parser/bug-1263355-13.js
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
if (helperThreadCount() == 0)
|
||||
quit();
|
||||
gczeal(0);
|
||||
print = function(s) {}
|
||||
startgc(1);
|
||||
offThreadCompileScript("");
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
if (helperThreadCount() == 0)
|
||||
quit();
|
||||
gczeal(0);
|
||||
startgc(8301);
|
||||
offThreadCompileScript("(({a,b,c}))");
|
||||
gcparam("maxBytes", gcparam("gcBytes"));
|
||||
|
|
|
@ -2,6 +2,7 @@ if (helperThreadCount() === 0)
|
|||
quit();
|
||||
if (!('deterministicgc' in this))
|
||||
quit();
|
||||
gczeal(0);
|
||||
|
||||
gc();
|
||||
function weighted(wa) {
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
// |jit-test| error:SyntaxError
|
||||
try {
|
||||
eval("}");
|
||||
} catch (exc) {}
|
||||
gczeal(17, 1);
|
||||
6.900653737167637, (yield);
|
|
@ -1,4 +1,5 @@
|
|||
if (helperThreadCount() === 0)
|
||||
quit(0);
|
||||
gczeal(0);
|
||||
startgc(45);
|
||||
offThreadCompileScript("print(1)");
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
gczeal(0);
|
||||
|
||||
function testGetParam(key) {
|
||||
gcparam(key);
|
||||
}
|
||||
|
|
|
@ -3,6 +3,8 @@
|
|||
// everything in functions because it seems like the toplevel script hangs onto
|
||||
// its object literals.
|
||||
|
||||
gczeal(0);
|
||||
|
||||
// All reachable keys should be found, and the rest should be swept.
|
||||
function basicSweeping() {
|
||||
var wm1 = new WeakMap();
|
||||
|
|
|
@ -7,6 +7,8 @@
|
|||
// in the WeakMap, and the actual "delegate" object in the target compartment
|
||||
// is the thing whose liveness is checked.
|
||||
|
||||
gczeal(0);
|
||||
|
||||
var g2 = newGlobal();
|
||||
g2.eval('function genObj(name) { return {"name": name} }');
|
||||
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
gczeal(0);
|
||||
function g() {
|
||||
for (var j = 0; j < 999; ++j) {
|
||||
try {
|
||||
|
|
|
@ -33,10 +33,11 @@ jit::Bailout(BailoutStack* sp, BaselineBailoutInfo** bailoutInfo)
|
|||
MOZ_ASSERT(bailoutInfo);
|
||||
|
||||
// We don't have an exit frame.
|
||||
MOZ_ASSERT(IsInRange(FAKE_JIT_TOP_FOR_BAILOUT, 0, 0x1000) &&
|
||||
IsInRange(FAKE_JIT_TOP_FOR_BAILOUT + sizeof(CommonFrameLayout), 0, 0x1000),
|
||||
"Fake jitTop pointer should be within the first page.");
|
||||
cx->jitTop = FAKE_JIT_TOP_FOR_BAILOUT;
|
||||
MOZ_ASSERT(IsInRange(FAKE_EXITFP_FOR_BAILOUT, 0, 0x1000) &&
|
||||
IsInRange(FAKE_EXITFP_FOR_BAILOUT + sizeof(CommonFrameLayout), 0, 0x1000),
|
||||
"Fake exitfp pointer should be within the first page.");
|
||||
|
||||
cx->activation()->asJit()->setExitFP(FAKE_EXITFP_FOR_BAILOUT);
|
||||
|
||||
JitActivationIterator jitActivations(cx);
|
||||
BailoutFrameInfo bailoutData(jitActivations, sp);
|
||||
|
@ -108,7 +109,7 @@ jit::InvalidationBailout(InvalidationBailoutStack* sp, size_t* frameSizeOut,
|
|||
JSContext* cx = TlsContext.get();
|
||||
|
||||
// We don't have an exit frame.
|
||||
cx->jitTop = FAKE_JIT_TOP_FOR_BAILOUT;
|
||||
cx->activation()->asJit()->setExitFP(FAKE_EXITFP_FOR_BAILOUT);
|
||||
|
||||
JitActivationIterator jitActivations(cx);
|
||||
BailoutFrameInfo bailoutData(jitActivations, sp);
|
||||
|
@ -192,9 +193,10 @@ jit::ExceptionHandlerBailout(JSContext* cx, const InlineFrameIterator& frame,
|
|||
// operation callback like a timeout handler.
|
||||
MOZ_ASSERT_IF(!excInfo.propagatingIonExceptionForDebugMode(), cx->isExceptionPending());
|
||||
|
||||
uint8_t* prevJitTop = cx->jitTop;
|
||||
auto restoreJitTop = mozilla::MakeScopeExit([&]() { cx->jitTop = prevJitTop; });
|
||||
cx->jitTop = FAKE_JIT_TOP_FOR_BAILOUT;
|
||||
JitActivation* act = cx->activation()->asJit();
|
||||
uint8_t* prevExitFP = act->exitFP();
|
||||
auto restoreExitFP = mozilla::MakeScopeExit([&]() { act->setExitFP(prevExitFP); });
|
||||
act->setExitFP(FAKE_EXITFP_FOR_BAILOUT);
|
||||
|
||||
gc::AutoSuppressGC suppress(cx);
|
||||
|
||||
|
@ -303,7 +305,7 @@ jit::CheckFrequentBailouts(JSContext* cx, JSScript* script, BailoutKind bailoutK
|
|||
void
|
||||
BailoutFrameInfo::attachOnJitActivation(const JitActivationIterator& jitActivations)
|
||||
{
|
||||
MOZ_ASSERT(jitActivations.jitTop() == FAKE_JIT_TOP_FOR_BAILOUT);
|
||||
MOZ_ASSERT(jitActivations.exitFP() == FAKE_EXITFP_FOR_BAILOUT);
|
||||
activation_ = jitActivations->asJit();
|
||||
activation_->setBailoutData(this);
|
||||
}
|
||||
|
|
|
@ -102,7 +102,7 @@ static const uint32_t BAILOUT_RETURN_OVERRECURSED = 2;
|
|||
|
||||
// This address is a magic number made to cause crashes while indicating that we
|
||||
// are making an attempt to mark the stack during a bailout.
|
||||
static uint8_t * const FAKE_JIT_TOP_FOR_BAILOUT = reinterpret_cast<uint8_t*>(0xba1);
|
||||
static uint8_t* const FAKE_EXITFP_FOR_BAILOUT = reinterpret_cast<uint8_t*>(0xba1);
|
||||
|
||||
// BailoutStack is an architecture specific pointer to the stack, given by the
|
||||
// bailout handler.
|
||||
|
|
|
@ -3460,7 +3460,7 @@ ICCall_Native::Compiler::generateStubCode(MacroAssembler& masm)
|
|||
masm.push(scratch);
|
||||
masm.push(ICTailCallReg);
|
||||
masm.loadJSContext(scratch);
|
||||
masm.enterFakeExitFrameForNative(scratch, isConstructing_);
|
||||
masm.enterFakeExitFrameForNative(scratch, scratch, isConstructing_);
|
||||
|
||||
// Execute call.
|
||||
masm.setupUnalignedABICall(scratch);
|
||||
|
@ -3558,7 +3558,7 @@ ICCall_ClassHook::Compiler::generateStubCode(MacroAssembler& masm)
|
|||
masm.push(scratch);
|
||||
masm.push(ICTailCallReg);
|
||||
masm.loadJSContext(scratch);
|
||||
masm.enterFakeExitFrameForNative(scratch, isConstructing_);
|
||||
masm.enterFakeExitFrameForNative(scratch, scratch, isConstructing_);
|
||||
|
||||
// Execute call.
|
||||
masm.setupUnalignedABICall(scratch);
|
||||
|
|
|
@ -3918,7 +3918,7 @@ CodeGenerator::visitCallNative(LCallNative* call)
|
|||
|
||||
// Construct native exit frame.
|
||||
uint32_t safepointOffset = masm.buildFakeExitFrame(tempReg);
|
||||
masm.enterFakeExitFrameForNative(argContextReg, call->mir()->isConstructing());
|
||||
masm.enterFakeExitFrameForNative(argContextReg, tempReg, call->mir()->isConstructing());
|
||||
|
||||
markSafepointAt(safepointOffset, call);
|
||||
|
||||
|
@ -4047,7 +4047,7 @@ CodeGenerator::visitCallDOMNative(LCallDOMNative* call)
|
|||
// Construct native exit frame.
|
||||
uint32_t safepointOffset = masm.buildFakeExitFrame(argJSContext);
|
||||
masm.loadJSContext(argJSContext);
|
||||
masm.enterFakeExitFrame(argJSContext, IonDOMMethodExitFrameLayoutToken);
|
||||
masm.enterFakeExitFrame(argJSContext, argJSContext, IonDOMMethodExitFrameLayoutToken);
|
||||
|
||||
markSafepointAt(safepointOffset, call);
|
||||
|
||||
|
@ -7945,7 +7945,7 @@ JitRuntime::generateLazyLinkStub(JSContext* cx)
|
|||
Register temp0 = regs.takeAny();
|
||||
|
||||
masm.loadJSContext(temp0);
|
||||
masm.enterFakeExitFrame(temp0, LazyLinkExitFrameLayoutToken);
|
||||
masm.enterFakeExitFrame(temp0, temp0, LazyLinkExitFrameLayoutToken);
|
||||
masm.PushStubCode();
|
||||
|
||||
masm.setupUnalignedABICall(temp0);
|
||||
|
@ -11569,7 +11569,7 @@ CodeGenerator::visitGetDOMProperty(LGetDOMProperty* ins)
|
|||
|
||||
uint32_t safepointOffset = masm.buildFakeExitFrame(JSContextReg);
|
||||
masm.loadJSContext(JSContextReg);
|
||||
masm.enterFakeExitFrame(JSContextReg, IonDOMExitFrameLayoutGetterToken);
|
||||
masm.enterFakeExitFrame(JSContextReg, JSContextReg, IonDOMExitFrameLayoutGetterToken);
|
||||
|
||||
markSafepointAt(safepointOffset, ins);
|
||||
|
||||
|
@ -11667,7 +11667,7 @@ CodeGenerator::visitSetDOMProperty(LSetDOMProperty* ins)
|
|||
|
||||
uint32_t safepointOffset = masm.buildFakeExitFrame(JSContextReg);
|
||||
masm.loadJSContext(JSContextReg);
|
||||
masm.enterFakeExitFrame(JSContextReg, IonDOMExitFrameLayoutSetterToken);
|
||||
masm.enterFakeExitFrame(JSContextReg, JSContextReg, IonDOMExitFrameLayoutSetterToken);
|
||||
|
||||
markSafepointAt(safepointOffset, ins);
|
||||
|
||||
|
|
|
@ -1216,6 +1216,11 @@ IonBuilder::addOsrValueTypeBarrier(uint32_t slot, MInstruction** def_,
|
|||
osrBlock->insertBefore(osrBlock->lastIns(), barrier);
|
||||
osrBlock->rewriteSlot(slot, barrier);
|
||||
def = barrier;
|
||||
|
||||
// If the TypeSet is more precise than |type|, adjust |type| for the
|
||||
// code below.
|
||||
if (type == MIRType::Value)
|
||||
type = barrier->type();
|
||||
} else if (type == MIRType::Null ||
|
||||
type == MIRType::Undefined ||
|
||||
type == MIRType::MagicOptimizedArguments)
|
||||
|
|
|
@ -945,7 +945,7 @@ IonCacheIRCompiler::emitCallNativeGetterResult()
|
|||
|
||||
if (!masm.icBuildOOLFakeExitFrame(GetReturnAddressToIonCode(cx_), save))
|
||||
return false;
|
||||
masm.enterFakeExitFrame(argJSContext, IonOOLNativeExitFrameLayoutToken);
|
||||
masm.enterFakeExitFrame(argJSContext, scratch, IonOOLNativeExitFrameLayoutToken);
|
||||
|
||||
// Construct and execute call.
|
||||
masm.setupUnalignedABICall(scratch);
|
||||
|
@ -1002,7 +1002,7 @@ IonCacheIRCompiler::emitCallProxyGetResult()
|
|||
|
||||
if (!masm.icBuildOOLFakeExitFrame(GetReturnAddressToIonCode(cx_), save))
|
||||
return false;
|
||||
masm.enterFakeExitFrame(argJSContext, IonOOLProxyExitFrameLayoutToken);
|
||||
masm.enterFakeExitFrame(argJSContext, scratch, IonOOLProxyExitFrameLayoutToken);
|
||||
|
||||
// Make the call.
|
||||
masm.setupUnalignedABICall(scratch);
|
||||
|
@ -1766,7 +1766,7 @@ IonCacheIRCompiler::emitCallNativeSetter()
|
|||
|
||||
if (!masm.icBuildOOLFakeExitFrame(GetReturnAddressToIonCode(cx_), save))
|
||||
return false;
|
||||
masm.enterFakeExitFrame(argJSContext, IonOOLNativeExitFrameLayoutToken);
|
||||
masm.enterFakeExitFrame(argJSContext, scratch, IonOOLNativeExitFrameLayoutToken);
|
||||
|
||||
// Make the call.
|
||||
masm.setupUnalignedABICall(scratch);
|
||||
|
|
|
@ -107,7 +107,7 @@ JitFrameIterator::JitFrameIterator()
|
|||
}
|
||||
|
||||
JitFrameIterator::JitFrameIterator(JSContext* cx)
|
||||
: current_(cx->jitTop),
|
||||
: current_(cx->activation()->asJit()->exitFP()),
|
||||
type_(JitFrame_Exit),
|
||||
returnAddressToFp_(nullptr),
|
||||
frameSize_(0),
|
||||
|
@ -122,7 +122,7 @@ JitFrameIterator::JitFrameIterator(JSContext* cx)
|
|||
}
|
||||
|
||||
JitFrameIterator::JitFrameIterator(const ActivationIterator& activations)
|
||||
: current_(activations.jitTop()),
|
||||
: current_(activations->asJit()->exitFP()),
|
||||
type_(JitFrame_Exit),
|
||||
returnAddressToFp_(nullptr),
|
||||
frameSize_(0),
|
||||
|
@ -948,7 +948,7 @@ HandleException(ResumeFromException* rfe)
|
|||
++iter;
|
||||
|
||||
if (current) {
|
||||
// Unwind the frame by updating jitTop. This is necessary so that
|
||||
// Unwind the frame by updating exitFP. This is necessary so that
|
||||
// (1) debugger exception unwind and leave frame hooks don't see this
|
||||
// frame when they use ScriptFrameIter, and (2) ScriptFrameIter does
|
||||
// not crash when accessing an IonScript that's destroyed by the
|
||||
|
@ -972,7 +972,7 @@ EnsureBareExitFrame(JSContext* cx, JitFrameLayout* frame)
|
|||
{
|
||||
ExitFrameLayout* exitFrame = reinterpret_cast<ExitFrameLayout*>(frame);
|
||||
|
||||
if (cx->jitTop == (uint8_t*)frame) {
|
||||
if (cx->activation()->asJit()->exitFP() == (uint8_t*)frame) {
|
||||
// If we already called this function for the current frame, do
|
||||
// nothing.
|
||||
MOZ_ASSERT(exitFrame->isBareExit());
|
||||
|
@ -985,11 +985,12 @@ EnsureBareExitFrame(JSContext* cx, JitFrameLayout* frame)
|
|||
++iter;
|
||||
MOZ_ASSERT(iter.current() == frame, "|frame| must be the top JS frame");
|
||||
|
||||
MOZ_ASSERT((uint8_t*)exitFrame->footer() >= cx->jitTop,
|
||||
"Must have space for ExitFooterFrame before jitTop");
|
||||
MOZ_ASSERT(!!cx->activation()->asJit()->exitFP());
|
||||
MOZ_ASSERT((uint8_t*)exitFrame->footer() >= cx->activation()->asJit()->exitFP(),
|
||||
"Must have space for ExitFooterFrame before exitFP");
|
||||
#endif
|
||||
|
||||
cx->jitTop = (uint8_t*)frame;
|
||||
cx->activation()->asJit()->setExitFP((uint8_t*)frame);
|
||||
*exitFrame->footer()->addressOfJitCode() = ExitFrameLayout::BareToken();
|
||||
MOZ_ASSERT(exitFrame->isBareExit());
|
||||
}
|
||||
|
|
|
@ -291,9 +291,9 @@ MacroAssembler::PushStubCode()
|
|||
}
|
||||
|
||||
void
|
||||
MacroAssembler::enterExitFrame(Register cxreg, const VMFunction* f)
|
||||
MacroAssembler::enterExitFrame(Register cxreg, Register scratch, const VMFunction* f)
|
||||
{
|
||||
linkExitFrame(cxreg);
|
||||
linkExitFrame(cxreg, scratch);
|
||||
// Push the JitCode pointer. (Keep the code alive, when on the stack)
|
||||
PushStubCode();
|
||||
// Push VMFunction pointer, to mark arguments.
|
||||
|
@ -301,17 +301,17 @@ MacroAssembler::enterExitFrame(Register cxreg, const VMFunction* f)
|
|||
}
|
||||
|
||||
void
|
||||
MacroAssembler::enterFakeExitFrame(Register cxreg, enum ExitFrameTokenValues token)
|
||||
MacroAssembler::enterFakeExitFrame(Register cxreg, Register scratch, enum ExitFrameTokenValues token)
|
||||
{
|
||||
linkExitFrame(cxreg);
|
||||
linkExitFrame(cxreg, scratch);
|
||||
Push(Imm32(token));
|
||||
Push(ImmPtr(nullptr));
|
||||
}
|
||||
|
||||
void
|
||||
MacroAssembler::enterFakeExitFrameForNative(Register cxreg, bool isConstructing)
|
||||
MacroAssembler::enterFakeExitFrameForNative(Register cxreg, Register scratch, bool isConstructing)
|
||||
{
|
||||
enterFakeExitFrame(cxreg, isConstructing ? ConstructNativeExitFrameLayoutToken
|
||||
enterFakeExitFrame(cxreg, scratch, isConstructing ? ConstructNativeExitFrameLayoutToken
|
||||
: CallNativeExitFrameLayoutToken);
|
||||
}
|
||||
|
||||
|
|
|
@ -1510,7 +1510,7 @@ void
|
|||
MacroAssembler::generateBailoutTail(Register scratch, Register bailoutInfo)
|
||||
{
|
||||
loadJSContext(scratch);
|
||||
enterExitFrame(scratch);
|
||||
enterExitFrame(scratch, scratch);
|
||||
|
||||
Label baseline;
|
||||
|
||||
|
@ -1572,7 +1572,7 @@ MacroAssembler::generateBailoutTail(Register scratch, Register bailoutInfo)
|
|||
push(Address(bailoutInfo, offsetof(BaselineBailoutInfo, resumeAddr)));
|
||||
// No GC things to mark on the stack, push a bare token.
|
||||
loadJSContext(scratch);
|
||||
enterFakeExitFrame(scratch, ExitFrameLayoutBareToken);
|
||||
enterFakeExitFrame(scratch, scratch, ExitFrameLayoutBareToken);
|
||||
|
||||
// If monitorStub is non-null, handle resumeAddr appropriately.
|
||||
Label noMonitor;
|
||||
|
@ -2822,9 +2822,10 @@ MacroAssembler::callWithABI(wasm::BytecodeOffset callOffset, wasm::SymbolicAddre
|
|||
// Exit frame footer.
|
||||
|
||||
void
|
||||
MacroAssembler::linkExitFrame(Register cxreg)
|
||||
MacroAssembler::linkExitFrame(Register cxreg, Register scratch)
|
||||
{
|
||||
storeStackPtr(Address(cxreg, offsetof(JSContext, jitTop)));
|
||||
loadPtr(Address(cxreg, JSContext::offsetOfActivation()), scratch);
|
||||
storeStackPtr(Address(scratch, JitActivation::offsetOfExitFP()));
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
@ -698,22 +698,22 @@ class MacroAssembler : public MacroAssemblerSpecific
|
|||
inline bool hasSelfReference() const;
|
||||
|
||||
// Push stub code and the VMFunction pointer.
|
||||
inline void enterExitFrame(Register cxreg, const VMFunction* f = nullptr);
|
||||
inline void enterExitFrame(Register cxreg, Register scratch, const VMFunction* f = nullptr);
|
||||
|
||||
// Push an exit frame token to identify which fake exit frame this footer
|
||||
// corresponds to.
|
||||
inline void enterFakeExitFrame(Register cxreg, enum ExitFrameTokenValues token);
|
||||
inline void enterFakeExitFrame(Register cxreg, Register scratch, enum ExitFrameTokenValues token);
|
||||
|
||||
// Push an exit frame token for a native call.
|
||||
inline void enterFakeExitFrameForNative(Register cxreg, bool isConstructing);
|
||||
inline void enterFakeExitFrameForNative(Register cxreg, Register scratch, bool isConstructing);
|
||||
|
||||
// Pop ExitFrame footer in addition to the extra frame.
|
||||
inline void leaveExitFrame(size_t extraFrame = 0);
|
||||
|
||||
private:
|
||||
// Save the top of the stack into JSontext::jitTop of the current thread,
|
||||
// which should be the location of the latest exit frame.
|
||||
void linkExitFrame(Register cxreg);
|
||||
// Save the top of the stack into JitActivation::exitFP of the current
|
||||
// thread, which should be the location of the latest exit frame.
|
||||
void linkExitFrame(Register cxreg, Register scratch);
|
||||
|
||||
// Patch the value of PushStubCode with the pointer to the finalized code.
|
||||
void linkSelfReference(JitCode* code);
|
||||
|
|
|
@ -810,8 +810,8 @@ bool
|
|||
DebugEpilogueOnBaselineReturn(JSContext* cx, BaselineFrame* frame, jsbytecode* pc)
|
||||
{
|
||||
if (!DebugEpilogue(cx, frame, pc, true)) {
|
||||
// DebugEpilogue popped the frame by updating jitTop, so run the stop event
|
||||
// here before we enter the exception handler.
|
||||
// DebugEpilogue popped the frame by updating exitFP, so run the stop
|
||||
// event here before we enter the exception handler.
|
||||
TraceLoggerThread* logger = TraceLoggerForCurrentThread(cx);
|
||||
TraceLogStopEvent(logger, TraceLogger_Baseline);
|
||||
TraceLogStopEvent(logger, TraceLogger_Scripts);
|
||||
|
@ -837,9 +837,8 @@ DebugEpilogue(JSContext* cx, BaselineFrame* frame, jsbytecode* pc, bool ok)
|
|||
frame->setOverridePc(script->lastPC());
|
||||
|
||||
if (!ok) {
|
||||
// Pop this frame by updating jitTop, so that the exception handling
|
||||
// Pop this frame by updating exitFP, so that the exception handling
|
||||
// code will start at the previous frame.
|
||||
|
||||
JitFrameLayout* prefix = frame->framePrefix();
|
||||
EnsureBareExitFrame(cx, prefix);
|
||||
return false;
|
||||
|
@ -1061,6 +1060,14 @@ HandleDebugTrap(JSContext* cx, BaselineFrame* frame, uint8_t* retAddr, bool* mus
|
|||
RootedScript script(cx, frame->script());
|
||||
jsbytecode* pc = script->baselineScript()->icEntryFromReturnAddress(retAddr).pc(script);
|
||||
|
||||
if (*pc == JSOP_DEBUGAFTERYIELD) {
|
||||
// JSOP_DEBUGAFTERYIELD will set the frame's debuggee flag, but if we
|
||||
// set a breakpoint there we have to do it now.
|
||||
MOZ_ASSERT(!frame->isDebuggee());
|
||||
if (!DebugAfterYield(cx, frame))
|
||||
return false;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(frame->isDebuggee());
|
||||
MOZ_ASSERT(script->stepModeEnabled() || script->hasBreakpointsAt(pc));
|
||||
|
||||
|
|
|
@ -288,7 +288,7 @@ JitRuntime::generateEnterJIT(JSContext* cx, EnterJitType type)
|
|||
masm.push(Imm32(0)); // Fake return address.
|
||||
// No GC things to mark on the stack, push a bare token.
|
||||
masm.loadJSContext(scratch);
|
||||
masm.enterFakeExitFrame(scratch, ExitFrameLayoutBareToken);
|
||||
masm.enterFakeExitFrame(scratch, scratch, ExitFrameLayoutBareToken);
|
||||
|
||||
masm.push(framePtr); // BaselineFrame
|
||||
masm.push(r0); // jitcode
|
||||
|
@ -777,8 +777,8 @@ JitRuntime::generateVMWrapper(JSContext* cx, const VMFunction& f)
|
|||
MacroAssembler masm(cx);
|
||||
AllocatableGeneralRegisterSet regs(Register::Codes::WrapperMask);
|
||||
|
||||
// Wrapper register set is a superset of Volatile register set.
|
||||
JS_STATIC_ASSERT((Register::Codes::VolatileMask & ~Register::Codes::WrapperMask) == 0);
|
||||
static_assert((Register::Codes::VolatileMask & ~Register::Codes::WrapperMask) == 0,
|
||||
"Wrapper register set must be a superset of Volatile register set.");
|
||||
|
||||
// The context is the first argument; r0 is the first argument register.
|
||||
Register cxreg = r0;
|
||||
|
@ -795,7 +795,7 @@ JitRuntime::generateVMWrapper(JSContext* cx, const VMFunction& f)
|
|||
masm.pushReturnAddress();
|
||||
|
||||
masm.loadJSContext(cxreg);
|
||||
masm.enterExitFrame(cxreg, &f);
|
||||
masm.enterExitFrame(cxreg, regs.getAny(), &f);
|
||||
|
||||
// Save the base of the argument set stored on the stack.
|
||||
Register argsBase = InvalidReg;
|
||||
|
|
|
@ -190,7 +190,7 @@ JitRuntime::generateEnterJIT(JSContext* cx, EnterJitType type)
|
|||
masm.asVIXL().Push(x19, xzr); // Push xzr for a fake return address.
|
||||
// No GC things to mark: push a bare token.
|
||||
masm.loadJSContext(r19);
|
||||
masm.enterFakeExitFrame(r19, ExitFrameLayoutBareToken);
|
||||
masm.enterFakeExitFrame(r19, r19, ExitFrameLayoutBareToken);
|
||||
|
||||
masm.push(BaselineFrameReg, reg_code);
|
||||
|
||||
|
@ -567,8 +567,8 @@ JitRuntime::generateVMWrapper(JSContext* cx, const VMFunction& f)
|
|||
// the function call.
|
||||
AllocatableGeneralRegisterSet regs(Register::Codes::WrapperMask);
|
||||
|
||||
// Wrapper register set is a superset of the Volatile register set.
|
||||
JS_STATIC_ASSERT((Register::Codes::VolatileMask & ~Register::Codes::WrapperMask) == 0);
|
||||
static_assert((Register::Codes::VolatileMask & ~Register::Codes::WrapperMask) == 0,
|
||||
"Wrapper register set must be a superset of the Volatile register set.");
|
||||
|
||||
// Unlike on other platforms, it is the responsibility of the VM *callee* to
|
||||
// push the return address, while the caller must ensure that the address
|
||||
|
@ -588,7 +588,7 @@ JitRuntime::generateVMWrapper(JSContext* cx, const VMFunction& f)
|
|||
//
|
||||
// We're aligned to an exit frame, so link it up.
|
||||
masm.loadJSContext(reg_cx);
|
||||
masm.enterExitFrame(reg_cx, &f);
|
||||
masm.enterExitFrame(reg_cx, regs.getAny(), &f);
|
||||
|
||||
// Save the current stack pointer as the base for copying arguments.
|
||||
Register argsBase = InvalidReg;
|
||||
|
|
|
@ -255,7 +255,7 @@ JitRuntime::generateEnterJIT(JSContext* cx, EnterJitType type)
|
|||
|
||||
// No GC things to mark, push a bare token.
|
||||
masm.loadJSContext(scratch);
|
||||
masm.enterFakeExitFrame(scratch, ExitFrameLayoutBareToken);
|
||||
masm.enterFakeExitFrame(scratch, scratch, ExitFrameLayoutBareToken);
|
||||
|
||||
masm.reserveStack(2 * sizeof(uintptr_t));
|
||||
masm.storePtr(framePtr, Address(StackPointer, sizeof(uintptr_t))); // BaselineFrame
|
||||
|
@ -738,7 +738,7 @@ JitRuntime::generateVMWrapper(JSContext* cx, const VMFunction& f)
|
|||
|
||||
// We're aligned to an exit frame, so link it up.
|
||||
masm.loadJSContext(cxreg);
|
||||
masm.enterExitFrame(cxreg, &f);
|
||||
masm.enterExitFrame(cxreg, regs.getAny(), &f);
|
||||
|
||||
// Save the base of the argument set stored on the stack.
|
||||
Register argsBase = InvalidReg;
|
||||
|
|
|
@ -272,7 +272,7 @@ JitRuntime::generateEnterJIT(JSContext* cx, EnterJitType type)
|
|||
|
||||
// No GC things to mark, push a bare token.
|
||||
masm.loadJSContext(scratch);
|
||||
masm.enterFakeExitFrame(scratch, ExitFrameLayoutBareToken);
|
||||
masm.enterFakeExitFrame(scratch, scratch, ExitFrameLayoutBareToken);
|
||||
|
||||
masm.reserveStack(2 * sizeof(uintptr_t));
|
||||
masm.storePtr(framePtr, Address(StackPointer, sizeof(uintptr_t))); // BaselineFrame
|
||||
|
@ -708,7 +708,7 @@ JitRuntime::generateVMWrapper(JSContext* cx, const VMFunction& f)
|
|||
|
||||
// We're aligned to an exit frame, so link it up.
|
||||
masm.loadJSContext(cxreg);
|
||||
masm.enterExitFrame(cxreg, &f);
|
||||
masm.enterExitFrame(cxreg, regs.getAny(), &f);
|
||||
|
||||
// Save the base of the argument set stored on the stack.
|
||||
Register argsBase = InvalidReg;
|
||||
|
|
|
@ -231,7 +231,7 @@ JitRuntime::generateEnterJIT(JSContext* cx, EnterJitType type)
|
|||
masm.push(Imm32(0)); // Fake return address.
|
||||
// No GC things to mark, push a bare token.
|
||||
masm.loadJSContext(scratch);
|
||||
masm.enterFakeExitFrame(scratch, ExitFrameLayoutBareToken);
|
||||
masm.enterFakeExitFrame(scratch, scratch, ExitFrameLayoutBareToken);
|
||||
|
||||
regs.add(valuesSize);
|
||||
|
||||
|
@ -667,8 +667,8 @@ JitRuntime::generateVMWrapper(JSContext* cx, const VMFunction& f)
|
|||
// the function call.
|
||||
AllocatableGeneralRegisterSet regs(Register::Codes::WrapperMask);
|
||||
|
||||
// Wrapper register set is a superset of Volatile register set.
|
||||
JS_STATIC_ASSERT((Register::Codes::VolatileMask & ~Register::Codes::WrapperMask) == 0);
|
||||
static_assert((Register::Codes::VolatileMask & ~Register::Codes::WrapperMask) == 0,
|
||||
"Wrapper register set must be a superset of Volatile register set");
|
||||
|
||||
// The context is the first argument.
|
||||
Register cxreg = IntArgReg0;
|
||||
|
@ -682,7 +682,7 @@ JitRuntime::generateVMWrapper(JSContext* cx, const VMFunction& f)
|
|||
//
|
||||
// We're aligned to an exit frame, so link it up.
|
||||
masm.loadJSContext(cxreg);
|
||||
masm.enterExitFrame(cxreg, &f);
|
||||
masm.enterExitFrame(cxreg, regs.getAny(), &f);
|
||||
|
||||
// Save the current stack pointer as the base for copying arguments.
|
||||
Register argsBase = InvalidReg;
|
||||
|
|
|
@ -226,7 +226,7 @@ JitRuntime::generateEnterJIT(JSContext* cx, EnterJitType type)
|
|||
masm.push(Imm32(0));
|
||||
// No GC things to mark on the stack, push a bare token.
|
||||
masm.loadJSContext(scratch);
|
||||
masm.enterFakeExitFrame(scratch, ExitFrameLayoutBareToken);
|
||||
masm.enterFakeExitFrame(scratch, scratch, ExitFrameLayoutBareToken);
|
||||
|
||||
masm.push(framePtr);
|
||||
masm.push(jitcode);
|
||||
|
@ -697,8 +697,8 @@ JitRuntime::generateVMWrapper(JSContext* cx, const VMFunction& f)
|
|||
// the function call.
|
||||
AllocatableGeneralRegisterSet regs(Register::Codes::WrapperMask);
|
||||
|
||||
// Wrapper register set is a superset of Volatile register set.
|
||||
JS_STATIC_ASSERT((Register::Codes::VolatileMask & ~Register::Codes::WrapperMask) == 0);
|
||||
static_assert((Register::Codes::VolatileMask & ~Register::Codes::WrapperMask) == 0,
|
||||
"Wrapper register set must be a superset of Volatile register set.");
|
||||
|
||||
// The context is the first argument.
|
||||
Register cxreg = regs.takeAny();
|
||||
|
@ -711,7 +711,7 @@ JitRuntime::generateVMWrapper(JSContext* cx, const VMFunction& f)
|
|||
//
|
||||
// We're aligned to an exit frame, so link it up.
|
||||
masm.loadJSContext(cxreg);
|
||||
masm.enterExitFrame(cxreg, &f);
|
||||
masm.enterExitFrame(cxreg, regs.getAny(), &f);
|
||||
|
||||
// Save the current stack pointer as the base for copying arguments.
|
||||
Register argsBase = InvalidReg;
|
||||
|
|
|
@ -2504,6 +2504,7 @@ js::array_unshift(JSContext* cx, unsigned argc, Value* vp)
|
|||
NativeObject* nobj = &obj->as<NativeObject>();
|
||||
if (nobj->is<ArrayObject>() && !nobj->as<ArrayObject>().lengthIsWritable())
|
||||
break;
|
||||
if (!nobj->tryUnshiftDenseElements(args.length())) {
|
||||
DenseElementResult result = nobj->ensureDenseElements(cx, uint32_t(length), args.length());
|
||||
if (result != DenseElementResult::Success) {
|
||||
if (result == DenseElementResult::Failure)
|
||||
|
@ -2513,6 +2514,7 @@ js::array_unshift(JSContext* cx, unsigned argc, Value* vp)
|
|||
}
|
||||
if (length > 0)
|
||||
nobj->moveDenseElements(args.length(), 0, uint32_t(length));
|
||||
}
|
||||
for (uint32_t i = 0; i < args.length(); i++)
|
||||
nobj->setDenseElementWithType(cx, i, args[i]);
|
||||
optimized = true;
|
||||
|
|
|
@ -170,6 +170,19 @@ JSRuntime::finishAtoms()
|
|||
emptyString = nullptr;
|
||||
}
|
||||
|
||||
static inline void
|
||||
TracePinnedAtoms(JSTracer* trc, const AtomSet& atoms)
|
||||
{
|
||||
for (auto r = atoms.all(); !r.empty(); r.popFront()) {
|
||||
const AtomStateEntry& entry = r.front();
|
||||
if (entry.isPinned()) {
|
||||
JSAtom* atom = entry.asPtrUnbarriered();
|
||||
TraceRoot(trc, &atom, "interned_atom");
|
||||
MOZ_ASSERT(entry.asPtrUnbarriered() == atom);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
js::TraceAtoms(JSTracer* trc, AutoLockForExclusiveAccess& lock)
|
||||
{
|
||||
|
@ -178,15 +191,9 @@ js::TraceAtoms(JSTracer* trc, AutoLockForExclusiveAccess& lock)
|
|||
if (rt->atomsAreFinished())
|
||||
return;
|
||||
|
||||
for (AtomSet::Enum e(rt->atoms(lock)); !e.empty(); e.popFront()) {
|
||||
const AtomStateEntry& entry = e.front();
|
||||
if (!entry.isPinned())
|
||||
continue;
|
||||
|
||||
JSAtom* atom = entry.asPtrUnbarriered();
|
||||
TraceRoot(trc, &atom, "interned_atom");
|
||||
MOZ_ASSERT(entry.asPtrUnbarriered() == atom);
|
||||
}
|
||||
TracePinnedAtoms(trc, rt->atoms(lock));
|
||||
if (rt->atomsAddedWhileSweeping())
|
||||
TracePinnedAtoms(trc, *rt->atomsAddedWhileSweeping());
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -250,6 +257,17 @@ JSRuntime::transformToPermanentAtoms(JSContext* cx)
|
|||
return true;
|
||||
}
|
||||
|
||||
static inline AtomSet::Ptr
|
||||
LookupAtomState(JSRuntime* rt, const AtomHasher::Lookup& lookup)
|
||||
{
|
||||
MOZ_ASSERT(rt->currentThreadHasExclusiveAccess());
|
||||
|
||||
AtomSet::Ptr p = rt->unsafeAtoms().lookup(lookup); // Safe because we hold the lock.
|
||||
if (!p && rt->atomsAddedWhileSweeping())
|
||||
p = rt->atomsAddedWhileSweeping()->lookup(lookup);
|
||||
return p;
|
||||
}
|
||||
|
||||
bool
|
||||
AtomIsPinned(JSContext* cx, JSAtom* atom)
|
||||
{
|
||||
|
@ -267,7 +285,7 @@ AtomIsPinned(JSContext* cx, JSAtom* atom)
|
|||
|
||||
AutoLockForExclusiveAccess lock(cx);
|
||||
|
||||
p = cx->runtime()->atoms(lock).lookup(lookup);
|
||||
p = LookupAtomState(cx->runtime(), lookup);
|
||||
if (!p)
|
||||
return false;
|
||||
|
||||
|
@ -285,7 +303,7 @@ AtomIsPinnedInRuntime(JSRuntime* rt, JSAtom* atom)
|
|||
|
||||
AtomHasher::Lookup lookup(atom);
|
||||
|
||||
AtomSet::Ptr p = rt->unsafeAtoms().lookup(lookup);
|
||||
AtomSet::Ptr p = LookupAtomState(rt, lookup);
|
||||
MOZ_ASSERT(p);
|
||||
|
||||
return p->isPinned();
|
||||
|
@ -362,7 +380,7 @@ AtomizeAndCopyChars(JSContext* cx, const CharT* tbchars, size_t length, PinningB
|
|||
// is dead.
|
||||
if (!p) {
|
||||
if (AtomSet::AddPtr p2 = atoms.lookupForAdd(lookup)) {
|
||||
JSAtom* atom = p2->asPtr(cx);
|
||||
JSAtom* atom = p2->asPtrUnbarriered();
|
||||
if (!IsAboutToBeFinalizedUnbarriered(&atom))
|
||||
p = p2;
|
||||
}
|
||||
|
@ -400,7 +418,8 @@ AtomizeAndCopyChars(JSContext* cx, const CharT* tbchars, size_t length, PinningB
|
|||
// We have held the lock since looking up p, and the operations we've done
|
||||
// since then can't GC; therefore the atoms table has not been modified and
|
||||
// p is still valid.
|
||||
if (!atoms.add(p, AtomStateEntry(atom, bool(pin)))) {
|
||||
AtomSet* addSet = atomsAddedWhileSweeping ? atomsAddedWhileSweeping : &atoms;
|
||||
if (!addSet->add(p, AtomStateEntry(atom, bool(pin)))) {
|
||||
ReportOutOfMemory(cx); /* SystemAllocPolicy does not report OOM. */
|
||||
return nullptr;
|
||||
}
|
||||
|
@ -440,7 +459,7 @@ js::AtomizeString(JSContext* cx, JSString* str,
|
|||
|
||||
AutoLockForExclusiveAccess lock(cx);
|
||||
|
||||
p = cx->atoms(lock).lookup(lookup);
|
||||
p = LookupAtomState(cx->runtime(), lookup);
|
||||
MOZ_ASSERT(p); /* Non-static atom must exist in atom state set. */
|
||||
MOZ_ASSERT(p->asPtrUnbarriered() == &atom);
|
||||
MOZ_ASSERT(pin == PinAtom);
|
||||
|
|
|
@ -1392,7 +1392,6 @@ JSContext::JSContext(JSRuntime* runtime, const JS::ContextOptions& options)
|
|||
handlingJitInterrupt_(false),
|
||||
osrTempData_(nullptr),
|
||||
ionReturnOverride_(MagicValue(JS_ARG_POISON)),
|
||||
jitTop(nullptr),
|
||||
jitStackLimit(UINTPTR_MAX),
|
||||
jitStackLimitNoInterrupt(UINTPTR_MAX),
|
||||
getIncumbentGlobalCallback(nullptr),
|
||||
|
|
|
@ -309,12 +309,6 @@ struct JSContext : public JS::RootingContext,
|
|||
|
||||
JSRuntime* runtime() { return runtime_; }
|
||||
|
||||
static size_t offsetOfActivation() {
|
||||
return offsetof(JSContext, activation_);
|
||||
}
|
||||
static size_t offsetOfProfilingActivation() {
|
||||
return offsetof(JSContext, profilingActivation_);
|
||||
}
|
||||
static size_t offsetOfCompartment() {
|
||||
return offsetof(JSContext, compartment_);
|
||||
}
|
||||
|
@ -388,12 +382,19 @@ struct JSContext : public JS::RootingContext,
|
|||
js::Activation* activation() const {
|
||||
return activation_;
|
||||
}
|
||||
static size_t offsetOfActivation() {
|
||||
return offsetof(JSContext, activation_);
|
||||
}
|
||||
|
||||
js::Activation* profilingActivation() const {
|
||||
return profilingActivation_;
|
||||
}
|
||||
void* addressOfProfilingActivation() {
|
||||
return (void*) &profilingActivation_;
|
||||
}
|
||||
static size_t offsetOfProfilingActivation() {
|
||||
return offsetof(JSContext, profilingActivation_);
|
||||
}
|
||||
|
||||
private:
|
||||
/* Space for interpreter frames. */
|
||||
|
@ -910,12 +911,6 @@ struct JSContext : public JS::RootingContext,
|
|||
ionReturnOverride_ = v;
|
||||
}
|
||||
|
||||
/*
|
||||
* If Baseline or Ion code is on the stack, and has called into C++, this
|
||||
* will be aligned to an exit frame.
|
||||
*/
|
||||
js::ThreadLocalData<uint8_t*> jitTop;
|
||||
|
||||
mozilla::Atomic<uintptr_t, mozilla::Relaxed> jitStackLimit;
|
||||
|
||||
// Like jitStackLimit, but not reset to trigger interrupts.
|
||||
|
|
|
@ -77,16 +77,16 @@ fun_enumerate(JSContext* cx, HandleObject obj)
|
|||
|
||||
if (!obj->isBoundFunction() && !obj->as<JSFunction>().isArrow()) {
|
||||
id = NameToId(cx->names().prototype);
|
||||
if (!HasProperty(cx, obj, id, &found))
|
||||
if (!HasOwnProperty(cx, obj, id, &found))
|
||||
return false;
|
||||
}
|
||||
|
||||
id = NameToId(cx->names().length);
|
||||
if (!HasProperty(cx, obj, id, &found))
|
||||
if (!HasOwnProperty(cx, obj, id, &found))
|
||||
return false;
|
||||
|
||||
id = NameToId(cx->names().name);
|
||||
if (!HasProperty(cx, obj, id, &found))
|
||||
if (!HasOwnProperty(cx, obj, id, &found))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
|
@ -1394,13 +1394,18 @@ JSFunction::getUnresolvedName(JSContext* cx, HandleFunction fun, MutableHandleAt
|
|||
// Bound functions are never unnamed.
|
||||
MOZ_ASSERT(name);
|
||||
|
||||
JSAtom* boundName;
|
||||
if (name->length() > 0) {
|
||||
StringBuffer sb(cx);
|
||||
if (!sb.append(cx->names().boundWithSpace) || !sb.append(name))
|
||||
return false;
|
||||
|
||||
JSAtom* boundName = sb.finishAtom();
|
||||
boundName = sb.finishAtom();
|
||||
if (!boundName)
|
||||
return false;
|
||||
} else {
|
||||
boundName = cx->names().boundWithSpace;
|
||||
}
|
||||
|
||||
v.set(boundName);
|
||||
return true;
|
||||
|
|
|
@ -991,11 +991,16 @@ GCRuntime::setZeal(uint8_t zeal, uint32_t frequency)
|
|||
if (verifyPreData)
|
||||
VerifyBarriers(rt, PreBarrierVerifier);
|
||||
|
||||
if (zeal == 0 && hasZealMode(ZealMode::GenerationalGC)) {
|
||||
if (zeal == 0) {
|
||||
if (hasZealMode(ZealMode::GenerationalGC)) {
|
||||
evictNursery(JS::gcreason::DEBUG_GC);
|
||||
nursery().leaveZealMode();
|
||||
}
|
||||
|
||||
if (isIncrementalGCInProgress())
|
||||
finishGC(JS::gcreason::DEBUG_GC);
|
||||
}
|
||||
|
||||
ZealMode zealMode = ZealMode(zeal);
|
||||
if (zealMode == ZealMode::GenerationalGC) {
|
||||
for (ZoneGroupsIter group(rt); !group.done(); group.next())
|
||||
|
@ -5276,6 +5281,9 @@ GCRuntime::beginSweepingSweepGroup()
|
|||
joinTask(task, PhaseKind::SWEEP_WEAK_CACHES, lock);
|
||||
}
|
||||
|
||||
if (sweepingAtoms)
|
||||
startSweepingAtomsTable();
|
||||
|
||||
// Queue all GC things in all zones for sweeping, either on the foreground
|
||||
// or on the background thread.
|
||||
|
||||
|
@ -5493,6 +5501,27 @@ GCRuntime::mergeSweptObjectArenas(GCRuntime* gc, FreeOp* fop, Zone* zone, SliceB
|
|||
return Finished;
|
||||
}
|
||||
|
||||
void
|
||||
GCRuntime::startSweepingAtomsTable()
|
||||
{
|
||||
auto& maybeAtoms = maybeAtomsToSweep.ref();
|
||||
MOZ_ASSERT(maybeAtoms.isNothing());
|
||||
|
||||
AtomSet* atomsTable = rt->atomsForSweeping();
|
||||
if (!atomsTable)
|
||||
return;
|
||||
|
||||
// Create a secondary table to hold new atoms added while we're sweeping
|
||||
// the main table incrementally.
|
||||
if (!rt->createAtomsAddedWhileSweepingTable()) {
|
||||
atomsTable->sweep();
|
||||
return;
|
||||
}
|
||||
|
||||
// Initialize remaining atoms to sweep.
|
||||
maybeAtoms.emplace(*atomsTable);
|
||||
}
|
||||
|
||||
/* static */ IncrementalProgress
|
||||
GCRuntime::sweepAtomsTable(GCRuntime* gc, FreeOp* fop, Zone* zone, SliceBudget& budget,
|
||||
AllocKind kind)
|
||||
|
@ -5503,33 +5532,22 @@ GCRuntime::sweepAtomsTable(GCRuntime* gc, FreeOp* fop, Zone* zone, SliceBudget&
|
|||
return gc->sweepAtomsTable(budget);
|
||||
}
|
||||
|
||||
|
||||
IncrementalProgress
|
||||
GCRuntime::sweepAtomsTable(SliceBudget& budget)
|
||||
{
|
||||
gcstats::AutoPhase ap(stats(), gcstats::PhaseKind::SWEEP_ATOMS_TABLE);
|
||||
|
||||
auto& maybeAtoms = maybeAtomsToSweep.ref();
|
||||
MOZ_ASSERT_IF(maybeAtoms.isSome(), !maybeAtoms.ref().empty());
|
||||
|
||||
AtomSet* atomsTable = rt->atomsForSweeping();
|
||||
if (!atomsTable)
|
||||
if (!maybeAtoms)
|
||||
return Finished;
|
||||
|
||||
if (maybeAtoms.isNothing()) {
|
||||
// Create a secondary table to hold new atoms added while we're sweeping
|
||||
// the main table incrementally.
|
||||
if (!rt->createAtomsAddedWhileSweepingTable()) {
|
||||
atomsTable->sweep();
|
||||
return Finished;
|
||||
}
|
||||
|
||||
// Initialize remaining atoms to sweep.
|
||||
maybeAtoms.emplace(*atomsTable);
|
||||
}
|
||||
MOZ_ASSERT(rt->atomsAddedWhileSweeping());
|
||||
|
||||
// Sweep the table incrementally until we run out of work or budget.
|
||||
auto& atomsToSweep = *maybeAtoms;
|
||||
while (!atomsToSweep.empty()) {
|
||||
budget.step();
|
||||
if (budget.isOverBudget())
|
||||
return NotFinished;
|
||||
|
||||
|
@ -5541,6 +5559,8 @@ GCRuntime::sweepAtomsTable(SliceBudget& budget)
|
|||
|
||||
// Add any new atoms from the secondary table.
|
||||
AutoEnterOOMUnsafeRegion oomUnsafe;
|
||||
AtomSet* atomsTable = rt->atomsForSweeping();
|
||||
MOZ_ASSERT(atomsTable);
|
||||
for (auto r = rt->atomsAddedWhileSweeping()->all(); !r.empty(); r.popFront()) {
|
||||
if (!atomsTable->putNew(AtomHasher::Lookup(r.front().asPtrUnbarriered()), r.front()))
|
||||
oomUnsafe.crash("Adding atom from secondary table after sweep");
|
||||
|
|
|
@ -2065,7 +2065,9 @@ ScriptSource::xdrEncodeFunction(JSContext* cx, HandleFunction fun, HandleScriptS
|
|||
bool
|
||||
ScriptSource::xdrFinalizeEncoder(JS::TranscodeBuffer& buffer)
|
||||
{
|
||||
MOZ_ASSERT(hasEncoder());
|
||||
if (!hasEncoder())
|
||||
return false;
|
||||
|
||||
auto cleanup = mozilla::MakeScopeExit([&] {
|
||||
xdrEncoder_.reset(nullptr);
|
||||
});
|
||||
|
|
|
@ -0,0 +1,63 @@
|
|||
function makeProxyPrototype(target) {
|
||||
return Object.setPrototypeOf(target, new Proxy({}, new Proxy({
|
||||
getPrototypeOf() {
|
||||
return null;
|
||||
},
|
||||
ownKeys() {
|
||||
return [];
|
||||
},
|
||||
get(t, pk, r) {
|
||||
// Handle the non-standard __iterator__ hook.
|
||||
if (pk !== "__iterator__")
|
||||
throw new Error("Unexpected [[Get]]: " + String(pk));
|
||||
}
|
||||
}, {
|
||||
get(t, pk, r) {
|
||||
if (pk in t)
|
||||
return Reflect.get(t, pk, r);
|
||||
throw new Error("Unexpected trap called: " + pk);
|
||||
}
|
||||
})));
|
||||
}
|
||||
|
||||
function enumerateMappedArgs(x) {
|
||||
var a = makeProxyPrototype(arguments);
|
||||
|
||||
// Delete all lazy properties and ensure no [[Has]] trap is called for them
|
||||
// on the prototype chain.
|
||||
delete a.length;
|
||||
delete a.callee;
|
||||
delete a[Symbol.iterator];
|
||||
delete a[0];
|
||||
|
||||
for (var k in a);
|
||||
}
|
||||
enumerateMappedArgs(0);
|
||||
|
||||
function enumerateUnmappedArgs(x) {
|
||||
"use strict";
|
||||
var a = makeProxyPrototype(arguments);
|
||||
|
||||
delete a.length;
|
||||
// delete a.callee; // .callee is non-configurable
|
||||
delete a[Symbol.iterator];
|
||||
delete a[0];
|
||||
|
||||
for (var k in a);
|
||||
}
|
||||
enumerateUnmappedArgs(0);
|
||||
|
||||
function enumerateFunction() {
|
||||
var f = makeProxyPrototype(function named() {});
|
||||
|
||||
// delete f.prototype; // .prototype is non-configurable
|
||||
delete f.length;
|
||||
delete f.name;
|
||||
|
||||
for (var k in f);
|
||||
}
|
||||
enumerateFunction();
|
||||
|
||||
|
||||
if (typeof reportCompare === "function")
|
||||
reportCompare(0, 0);
|
|
@ -0,0 +1,22 @@
|
|||
(function() {
|
||||
var rx = /a/g;
|
||||
var b = {
|
||||
get a() {
|
||||
rx.compile("b");
|
||||
return "A";
|
||||
}
|
||||
};
|
||||
|
||||
// Replacer function which is applicable for the elem-base optimization in
|
||||
// RegExp.prototype.@@replace.
|
||||
function replacer(a) {
|
||||
return b[a];
|
||||
}
|
||||
|
||||
var result = rx[Symbol.replace]("aaa", replacer);
|
||||
|
||||
assertEq(result, "AAA");
|
||||
})();
|
||||
|
||||
if (typeof reportCompare === "function")
|
||||
reportCompare(true, true);
|
|
@ -510,7 +510,7 @@ MappedArgSetter(JSContext* cx, HandleObject obj, HandleId id, MutableHandleValue
|
|||
/*
|
||||
* For simplicity we use delete/define to replace the property with a
|
||||
* simple data property. Note that we rely on ArgumentsObject::obj_delProperty
|
||||
* to clear the corresponding reserved slot so the GC can collect its value.
|
||||
* to set the corresponding override-bit.
|
||||
* Note also that we must define the property instead of setting it in case
|
||||
* the user has changed the prototype to an object that has a setter for
|
||||
* this id.
|
||||
|
@ -529,10 +529,37 @@ DefineArgumentsIterator(JSContext* cx, Handle<ArgumentsObject*> argsobj)
|
|||
RootedValue val(cx);
|
||||
if (!GlobalObject::getSelfHostedFunction(cx, cx->global(), shName, name, 0, &val))
|
||||
return false;
|
||||
|
||||
return NativeDefineProperty(cx, argsobj, iteratorId, val, nullptr, nullptr, JSPROP_RESOLVING);
|
||||
}
|
||||
|
||||
/* static */ bool
|
||||
ArgumentsObject::reifyLength(JSContext* cx, Handle<ArgumentsObject*> obj)
|
||||
{
|
||||
if (obj->hasOverriddenLength())
|
||||
return true;
|
||||
|
||||
RootedId id(cx, NameToId(cx->names().length));
|
||||
RootedValue val(cx, Int32Value(obj->initialLength()));
|
||||
if (!NativeDefineProperty(cx, obj, id, val, nullptr, nullptr, JSPROP_RESOLVING))
|
||||
return false;
|
||||
|
||||
obj->markLengthOverridden();
|
||||
return true;
|
||||
}
|
||||
|
||||
/* static */ bool
|
||||
ArgumentsObject::reifyIterator(JSContext* cx, Handle<ArgumentsObject*> obj)
|
||||
{
|
||||
if (obj->hasOverriddenIterator())
|
||||
return true;
|
||||
|
||||
if (!DefineArgumentsIterator(cx, obj))
|
||||
return false;
|
||||
|
||||
obj->markIteratorOverridden();
|
||||
return true;
|
||||
}
|
||||
|
||||
/* static */ bool
|
||||
MappedArgumentsObject::obj_resolve(JSContext* cx, HandleObject obj, HandleId id, bool* resolvedp)
|
||||
{
|
||||
|
@ -586,20 +613,20 @@ MappedArgumentsObject::obj_enumerate(JSContext* cx, HandleObject obj)
|
|||
|
||||
// Trigger reflection.
|
||||
id = NameToId(cx->names().length);
|
||||
if (!HasProperty(cx, argsobj, id, &found))
|
||||
if (!HasOwnProperty(cx, argsobj, id, &found))
|
||||
return false;
|
||||
|
||||
id = NameToId(cx->names().callee);
|
||||
if (!HasProperty(cx, argsobj, id, &found))
|
||||
if (!HasOwnProperty(cx, argsobj, id, &found))
|
||||
return false;
|
||||
|
||||
id = SYMBOL_TO_JSID(cx->wellKnownSymbols().iterator);
|
||||
if (!HasProperty(cx, argsobj, id, &found))
|
||||
if (!HasOwnProperty(cx, argsobj, id, &found))
|
||||
return false;
|
||||
|
||||
for (unsigned i = 0; i < argsobj->initialLength(); i++) {
|
||||
id = INT_TO_JSID(i);
|
||||
if (!HasProperty(cx, argsobj, id, &found))
|
||||
if (!HasOwnProperty(cx, argsobj, id, &found))
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -714,7 +741,7 @@ UnmappedArgSetter(JSContext* cx, HandleObject obj, HandleId id, MutableHandleVal
|
|||
/*
|
||||
* For simplicity we use delete/define to replace the property with a
|
||||
* simple data property. Note that we rely on ArgumentsObject::obj_delProperty
|
||||
* to clear the corresponding reserved slot so the GC can collect its value.
|
||||
* to set the corresponding override-bit.
|
||||
*/
|
||||
ObjectOpResult ignored;
|
||||
return NativeDeleteProperty(cx, argsobj, id, ignored) &&
|
||||
|
@ -776,20 +803,20 @@ UnmappedArgumentsObject::obj_enumerate(JSContext* cx, HandleObject obj)
|
|||
|
||||
// Trigger reflection.
|
||||
id = NameToId(cx->names().length);
|
||||
if (!HasProperty(cx, argsobj, id, &found))
|
||||
if (!HasOwnProperty(cx, argsobj, id, &found))
|
||||
return false;
|
||||
|
||||
id = NameToId(cx->names().callee);
|
||||
if (!HasProperty(cx, argsobj, id, &found))
|
||||
if (!HasOwnProperty(cx, argsobj, id, &found))
|
||||
return false;
|
||||
|
||||
id = SYMBOL_TO_JSID(cx->wellKnownSymbols().iterator);
|
||||
if (!HasProperty(cx, argsobj, id, &found))
|
||||
if (!HasOwnProperty(cx, argsobj, id, &found))
|
||||
return false;
|
||||
|
||||
for (unsigned i = 0; i < argsobj->initialLength(); i++) {
|
||||
id = INT_TO_JSID(i);
|
||||
if (!HasProperty(cx, argsobj, id, &found))
|
||||
if (!HasOwnProperty(cx, argsobj, id, &found))
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -52,12 +52,10 @@ class RareArgumentsData
|
|||
}
|
||||
};
|
||||
|
||||
/*
|
||||
* ArgumentsData stores the initial indexed arguments provided to the
|
||||
* corresponding and that function itself. It is used to store arguments[i]
|
||||
* and arguments.callee -- up until the corresponding property is modified,
|
||||
* when the relevant value is flagged to memorialize the modification.
|
||||
*/
|
||||
// ArgumentsData stores the initial indexed arguments provided to a function
|
||||
// call. It is used to store arguments[i] -- up until the corresponding
|
||||
// property is modified, when the relevant value is flagged to memorialize the
|
||||
// modification.
|
||||
struct ArgumentsData
|
||||
{
|
||||
/*
|
||||
|
@ -235,6 +233,11 @@ class ArgumentsObject : public NativeObject
|
|||
setFixedSlot(INITIAL_LENGTH_SLOT, Int32Value(v));
|
||||
}
|
||||
|
||||
/*
|
||||
* Create the default "length" property and set LENGTH_OVERRIDDEN_BIT.
|
||||
*/
|
||||
static bool reifyLength(JSContext* cx, Handle<ArgumentsObject*> obj);
|
||||
|
||||
/* True iff arguments[@@iterator] has been assigned or its attributes
|
||||
* changed. */
|
||||
bool hasOverriddenIterator() const {
|
||||
|
@ -247,6 +250,11 @@ class ArgumentsObject : public NativeObject
|
|||
setFixedSlot(INITIAL_LENGTH_SLOT, Int32Value(v));
|
||||
}
|
||||
|
||||
/*
|
||||
* Create the default @@iterator property and set ITERATOR_OVERRIDDEN_BIT.
|
||||
*/
|
||||
static bool reifyIterator(JSContext* cx, Handle<ArgumentsObject*> obj);
|
||||
|
||||
/* True iff any element has been assigned or its attributes
|
||||
* changed. */
|
||||
bool hasOverriddenElement() const {
|
||||
|
|
|
@ -61,6 +61,23 @@ GeckoProfiler::setEventMarker(void (*fn)(const char*))
|
|||
eventMarker_ = fn;
|
||||
}
|
||||
|
||||
/* Get a pointer to the top-most profiling frame, given the exit frame pointer. */
|
||||
static void*
|
||||
GetTopProfilingJitFrame(Activation* act)
|
||||
{
|
||||
if (!act || !act->isJit())
|
||||
return nullptr;
|
||||
|
||||
// For null exitFrame, there is no previous exit frame, just return.
|
||||
uint8_t* exitFP = act->asJit()->exitFP();
|
||||
if (!exitFP)
|
||||
return nullptr;
|
||||
|
||||
jit::JitProfilingFrameIterator iter(exitFP);
|
||||
MOZ_ASSERT(!iter.done());
|
||||
return iter.fp();
|
||||
}
|
||||
|
||||
bool
|
||||
GeckoProfiler::enable(bool enabled)
|
||||
{
|
||||
|
@ -119,14 +136,16 @@ GeckoProfiler::enable(bool enabled)
|
|||
if (target.context()->jitActivation) {
|
||||
// Walk through all activations, and set their lastProfilingFrame appropriately.
|
||||
if (enabled) {
|
||||
void* lastProfilingFrame = GetTopProfilingJitFrame(target.context()->jitTop);
|
||||
Activation* act = target.context()->activation();
|
||||
void* lastProfilingFrame = GetTopProfilingJitFrame(act);
|
||||
|
||||
jit::JitActivation* jitActivation = target.context()->jitActivation;
|
||||
while (jitActivation) {
|
||||
jitActivation->setLastProfilingFrame(lastProfilingFrame);
|
||||
jitActivation->setLastProfilingCallSite(nullptr);
|
||||
|
||||
lastProfilingFrame = GetTopProfilingJitFrame(jitActivation->prevJitTop());
|
||||
jitActivation = jitActivation->prevJitActivation();
|
||||
lastProfilingFrame = GetTopProfilingJitFrame(jitActivation);
|
||||
}
|
||||
} else {
|
||||
jit::JitActivation* jitActivation = target.context()->jitActivation;
|
||||
|
@ -544,15 +563,3 @@ AutoSuppressProfilerSampling::~AutoSuppressProfilerSampling()
|
|||
if (previouslyEnabled_)
|
||||
cx_->enableProfilerSampling();
|
||||
}
|
||||
|
||||
void*
|
||||
js::GetTopProfilingJitFrame(uint8_t* exitFramePtr)
|
||||
{
|
||||
// For null exitFrame, there is no previous exit frame, just return.
|
||||
if (!exitFramePtr)
|
||||
return nullptr;
|
||||
|
||||
jit::JitProfilingFrameIterator iter(exitFramePtr);
|
||||
MOZ_ASSERT(!iter.done());
|
||||
return iter.fp();
|
||||
}
|
||||
|
|
|
@ -294,10 +294,6 @@ class GeckoProfilerInstrumentation
|
|||
void disable() { profiler_ = nullptr; }
|
||||
};
|
||||
|
||||
|
||||
/* Get a pointer to the top-most profiling frame, given the exit frame pointer. */
|
||||
void* GetTopProfilingJitFrame(uint8_t* exitFramePtr);
|
||||
|
||||
} /* namespace js */
|
||||
|
||||
#endif /* vm_GeckoProfiler_h */
|
||||
|
|
|
@ -181,6 +181,14 @@ NativeObject::tryShiftDenseElements(uint32_t count)
|
|||
return false;
|
||||
}
|
||||
|
||||
shiftDenseElementsUnchecked(count);
|
||||
return true;
|
||||
}
|
||||
|
||||
inline void
|
||||
NativeObject::shiftDenseElementsUnchecked(uint32_t count)
|
||||
{
|
||||
ObjectElements* header = getElementsHeader();
|
||||
MOZ_ASSERT(count > 0);
|
||||
MOZ_ASSERT(count < header->initializedLength);
|
||||
|
||||
|
@ -195,7 +203,6 @@ NativeObject::tryShiftDenseElements(uint32_t count)
|
|||
elements_ += count;
|
||||
ObjectElements* newHeader = getElementsHeader();
|
||||
memmove(newHeader, header, sizeof(ObjectElements));
|
||||
return true;
|
||||
}
|
||||
|
||||
inline void
|
||||
|
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче