Merge m-c to autoland, a=merge CLOSED TREE

UPGRADE_NSS_RELEASE UPGRADE_NSPR_RELEASE
MozReview-Commit-ID: 9AadPvosTet

--HG--
extra : amend_source : 5de33acae6003b4eb8fb3492b38b2856419e29ad
This commit is contained in:
Wes Kocher 2017-06-06 17:25:43 -07:00
commit 3782f0765c
323 changed files with 23106 additions and 21766 deletions

View File

@ -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,12 +191,34 @@ 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

View File

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

View File

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

View File

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

View File

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

View File

@ -28,10 +28,12 @@ public:
virtual void Shutdown() override;
virtual ipc::IPCResult
RecvParentCOMProxy(const IAccessibleHolder& aParentCOMProxy) override;
RecvParentCOMProxy(const IAccessibleHolder& aParentCOMProxy) override;
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(); }

View File

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

View File

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

View File

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

View File

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

View File

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

Before

Width:  |  Height:  |  Size: 4.2 KiB

View File

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

View File

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

View File

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

View File

@ -0,0 +1 @@
var // SyntaxError: missing variable name.

View File

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

View File

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

View File

@ -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,39 +739,10 @@ 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))) {
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;
SRIVerifierAndOutputHolder holder(mSRIDataVerifier, mPipeOutputStream);
nsresult rv = aInputStream->ReadSegments(CopySegmentToStreamAndSRI,
&holder, aCount, &aRead);
return rv;
}
nsresult rv = aInputStream->ReadSegments(NS_CopySegmentToStream,

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -257,7 +257,10 @@ class nsCSPHostSrc : public nsCSPBaseSrc {
void appendPath(const nsAString &aPath);
inline void setGeneratedFromSelfKeyword() const
{ mGeneratedFromSelfKeyword = true;}
{ 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 ============ */

View File

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

View File

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

View File

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

View File

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

View File

@ -383,6 +383,7 @@ UNIFIED_SOURCES += [
'LayerScope.cpp',
'LayersLogging.cpp',
'LayerSorter.cpp',
'LayersTypes.cpp',
'opengl/CompositingRenderTargetOGL.cpp',
'opengl/CompositorOGL.cpp',
'opengl/GLBlitTextureImageHelper.cpp',

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,3 +1,4 @@
gczeal(0);
startgc(1, "shrinking");
for (var i=0; i<100; i++) {
gcslice(100000);

View File

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

View File

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

View File

@ -1,6 +1,8 @@
if (!('oomTest' in this))
quit();
gczeal(0);
var x1 = [];
var x2 = [];
var x3 = [];

View File

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

View File

@ -1,5 +1,6 @@
if (helperThreadCount() == 0)
quit();
gczeal(0);
print = function(s) {}
startgc(1);
offThreadCompileScript("");

View File

@ -1,5 +1,6 @@
if (helperThreadCount() == 0)
quit();
gczeal(0);
startgc(8301);
offThreadCompileScript("(({a,b,c}))");
gcparam("maxBytes", gcparam("gcBytes"));

View File

@ -2,6 +2,7 @@ if (helperThreadCount() === 0)
quit();
if (!('deterministicgc' in this))
quit();
gczeal(0);
gc();
function weighted(wa) {

View File

@ -0,0 +1,6 @@
// |jit-test| error:SyntaxError
try {
eval("}");
} catch (exc) {}
gczeal(17, 1);
6.900653737167637, (yield);

View File

@ -1,4 +1,5 @@
if (helperThreadCount() === 0)
quit(0);
gczeal(0);
startgc(45);
offThreadCompileScript("print(1)");

View File

@ -1,3 +1,5 @@
gczeal(0);
function testGetParam(key) {
gcparam(key);
}

View File

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

View File

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

View File

@ -1,3 +1,4 @@
gczeal(0);
function g() {
for (var j = 0; j < 999; ++j) {
try {

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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,18 +301,18 @@ 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
: CallNativeExitFrameLayoutToken);
enterFakeExitFrame(cxreg, scratch, isConstructing ? ConstructNativeExitFrameLayoutToken
: CallNativeExitFrameLayoutToken);
}
void

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -2504,15 +2504,17 @@ js::array_unshift(JSContext* cx, unsigned argc, Value* vp)
NativeObject* nobj = &obj->as<NativeObject>();
if (nobj->is<ArrayObject>() && !nobj->as<ArrayObject>().lengthIsWritable())
break;
DenseElementResult result = nobj->ensureDenseElements(cx, uint32_t(length), args.length());
if (result != DenseElementResult::Success) {
if (result == DenseElementResult::Failure)
return false;
MOZ_ASSERT(result == DenseElementResult::Incomplete);
break;
if (!nobj->tryUnshiftDenseElements(args.length())) {
DenseElementResult result = nobj->ensureDenseElements(cx, uint32_t(length), args.length());
if (result != DenseElementResult::Success) {
if (result == DenseElementResult::Failure)
return false;
MOZ_ASSERT(result == DenseElementResult::Incomplete);
break;
}
if (length > 0)
nobj->moveDenseElements(args.length(), 0, uint32_t(length));
}
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;

View File

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

View File

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

View File

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

View File

@ -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);
StringBuffer sb(cx);
if (!sb.append(cx->names().boundWithSpace) || !sb.append(name))
return false;
JSAtom* boundName;
if (name->length() > 0) {
StringBuffer sb(cx);
if (!sb.append(cx->names().boundWithSpace) || !sb.append(name))
return false;
JSAtom* boundName = sb.finishAtom();
if (!boundName)
return false;
boundName = sb.finishAtom();
if (!boundName)
return false;
} else {
boundName = cx->names().boundWithSpace;
}
v.set(boundName);
return true;

View File

@ -991,9 +991,14 @@ GCRuntime::setZeal(uint8_t zeal, uint32_t frequency)
if (verifyPreData)
VerifyBarriers(rt, PreBarrierVerifier);
if (zeal == 0 && hasZealMode(ZealMode::GenerationalGC)) {
evictNursery(JS::gcreason::DEBUG_GC);
nursery().leaveZealMode();
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);
@ -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");

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

Some files were not shown because too many files have changed in this diff Show More