Merge inbound to central, a=merge

MozReview-Commit-ID: AhUhSIjf0BX
This commit is contained in:
Wes Kocher 2017-07-07 15:58:55 -07:00
commit 5f00a2d1ab
78 changed files with 537 additions and 291 deletions

View File

@ -383,8 +383,6 @@
@RESPATH@/browser/components/devtools-startup.js
@RESPATH@/browser/components/aboutdebugging-registration.js
@RESPATH@/browser/components/aboutdebugging.manifest
@RESPATH@/browser/components/webideCli.js
@RESPATH@/browser/components/webideComponents.manifest
@RESPATH@/browser/components/Experiments.manifest
@RESPATH@/browser/components/ExperimentsService.js
@RESPATH@/browser/components/browser-newtab.xpt

View File

@ -1,10 +0,0 @@
# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
# vim: set filetype=python:
# 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/.
EXTRA_COMPONENTS += [
'webideCli.js',
'webideComponents.manifest',
]

View File

@ -1,58 +0,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/. */
"use strict";
const Ci = Components.interfaces;
const Cu = Components.utils;
const { XPCOMUtils } = Cu.import("resource://gre/modules/XPCOMUtils.jsm", {});
XPCOMUtils.defineLazyModuleGetter(this, "Services", "resource://gre/modules/Services.jsm");
/**
* Handles --webide command line option.
*/
function webideCli() { }
webideCli.prototype = {
handle: function (cmdLine) {
if (!cmdLine.handleFlag("webide", false)) {
return;
}
// If --webide is used remotely, we don't want to open
// a new tab.
//
// If --webide is used for a new Firefox instance, we
// want to open webide only.
cmdLine.preventDefault = true;
let win = Services.wm.getMostRecentWindow("devtools:webide");
if (win) {
win.focus();
} else {
win = Services.ww.openWindow(null,
"chrome://webide/content/",
"webide",
"chrome,centerscreen,resizable,dialog=no",
null);
}
if (cmdLine.state == Ci.nsICommandLine.STATE_INITIAL_LAUNCH) {
// If this is a new Firefox instance, and because we will only start
// webide, we need to notify "sessionstore-windows-restored" to trigger
// addons registration (for simulators and adb helper).
Services.obs.notifyObservers(null, "sessionstore-windows-restored");
}
},
helpInfo: "",
classID: Components.ID("{79b7b44e-de5e-4e4c-b7a2-044003c615d9}"),
QueryInterface: XPCOMUtils.generateQI([Ci.nsICommandLineHandler]),
};
this.NSGetFactory = XPCOMUtils.generateNSGetFactory([webideCli]);

View File

@ -1,4 +0,0 @@
# webide components
component {79b7b44e-de5e-4e4c-b7a2-044003c615d9} webideCli.js
contract @mozilla.org/browser/webide-clh;1 {79b7b44e-de5e-4e4c-b7a2-044003c615d9}
category command-line-handler a-webide @mozilla.org/browser/webide-clh;1

View File

@ -6,7 +6,6 @@
DIRS += [
'content',
'components',
'modules',
'themes',
]

View File

@ -197,7 +197,8 @@ Link::LinkState() const
// If we have not yet registered for notifications and need to,
// due to our href changing, register now!
if (!mRegistered && mNeedsRegistration && element->IsInComposedDoc()) {
if (!mRegistered && mNeedsRegistration && element->IsInComposedDoc() &&
!HasPendingLinkUpdate()) {
// Only try and register once.
self->mNeedsRegistration = false;

View File

@ -126,7 +126,7 @@ public:
void TryDNSPrefetchPreconnectOrPrefetchOrPrerender();
void CancelPrefetch();
bool HasPendingLinkUpdate() { return mHasPendingLinkUpdate; }
bool HasPendingLinkUpdate() const { return mHasPendingLinkUpdate; }
void SetHasPendingLinkUpdate() { mHasPendingLinkUpdate = true; }
void ClearHasPendingLinkUpdate() { mHasPendingLinkUpdate = false; }

View File

@ -245,6 +245,9 @@ public:
RefPtr<WebSocketEventService> mService;
// For dispatching runnables to main thread.
nsCOMPtr<nsIEventTarget> mMainThreadEventTarget;
private:
~WebSocketImpl()
{
@ -1872,6 +1875,10 @@ WebSocketImpl::InitializeConnection(nsIPrincipal* aPrincipal)
mChannel = wsChannel;
if (mIsMainThread && doc) {
mMainThreadEventTarget = doc->EventTargetFor(TaskCategory::Other);
}
return NS_OK;
}
@ -2844,9 +2851,12 @@ NS_IMETHODIMP
WebSocketImpl::Dispatch(already_AddRefed<nsIRunnable> aEvent, uint32_t aFlags)
{
nsCOMPtr<nsIRunnable> event_ref(aEvent);
// If the target is the main-thread we can just dispatch the runnable.
// If the target is the main-thread, we should try to dispatch the runnable
// to a labeled event target.
if (mIsMainThread) {
return NS_DispatchToMainThread(event_ref.forget());
return mMainThreadEventTarget
? mMainThreadEventTarget->Dispatch(event_ref.forget())
: GetMainThreadEventTarget()->Dispatch(event_ref.forget());
}
MutexAutoLock lock(mMutex);

View File

@ -11,7 +11,7 @@
}
</script>
<body onload="loadHandler();">
<iframe src="data:text/html,<input>"></iframe>
<iframe srcdoc="<input>"></iframe>
<input></input>
</body>
</html>

View File

@ -11,6 +11,6 @@
}
</script>
<body>
<iframe onload="frameLoadHandler();" src="data:text/html,<input autofocus>"></iframe>
<iframe onload="frameLoadHandler();" srcdoc="<input autofocus>"></iframe>
</body>
</html>

View File

@ -9,6 +9,6 @@
document.documentElement.className = "";
}
</script>
<iframe id=frame onload="loadFrame()" src="data:text/html,<body><span lang='en'>text</span></body>" marginwidth="100px" marginheight="100px" width=300px height=300px></iframe>
<iframe id=frame onload="loadFrame()" srcdoc="<body><span lang='en'>text</span></body>" marginwidth="100px" marginheight="100px" width=300px height=300px></iframe>
</body>
</html>

View File

@ -11,6 +11,6 @@
document.documentElement.className = "";
}
</script>
<iframe id=frame onload="loadFrame()" src="data:text/html,<body lang='en'>text</body>" marginwidth="100px" marginheight="100px" width=300px height=300px></iframe>
<iframe id=frame onload="loadFrame()" srcdoc="<body lang='en'>text</body>" marginwidth="100px" marginheight="100px" width=300px height=300px></iframe>
</body>
</html>

View File

@ -43,7 +43,7 @@ async protocol PWebAuthnTransaction {
async RequestSign(WebAuthnTransactionInfo aTransactionInfo);
async RequestCancel();
child:
async ConfirmRegister(uint8_t[] RegBuffer, uint8_t[] SigBuffer);
async ConfirmRegister(uint8_t[] RegBuffer);
async ConfirmSign(uint8_t[] CredentialID, uint8_t[] ReplyBuffer);
async Cancel(nsresult Error);
};

View File

@ -40,8 +40,7 @@ RefPtr<ResultPromise>
U2FHIDTokenManager::Register(const nsTArray<WebAuthnScopedCredentialDescriptor>& aDescriptors,
const nsTArray<uint8_t>& aApplication,
const nsTArray<uint8_t>& aChallenge,
/* out */ nsTArray<uint8_t>& aRegistration,
/* out */ nsTArray<uint8_t>& aSignature)
/* out */ nsTArray<uint8_t>& aRegistration)
{
return ResultPromise::CreateAndReject(NS_ERROR_NOT_IMPLEMENTED, __func__);
}

View File

@ -26,8 +26,7 @@ public:
Register(const nsTArray<WebAuthnScopedCredentialDescriptor>& aDescriptors,
const nsTArray<uint8_t>& aApplication,
const nsTArray<uint8_t>& aChallenge,
/* out */ nsTArray<uint8_t>& aRegistration,
/* out */ nsTArray<uint8_t>& aSignature) override;
/* out */ nsTArray<uint8_t>& aRegistration) override;
virtual RefPtr<ResultPromise>
Sign(const nsTArray<WebAuthnScopedCredentialDescriptor>& aDescriptors,

View File

@ -637,8 +637,7 @@ RefPtr<ResultPromise>
U2FSoftTokenManager::Register(const nsTArray<WebAuthnScopedCredentialDescriptor>& aDescriptors,
const nsTArray<uint8_t>& aApplication,
const nsTArray<uint8_t>& aChallenge,
/* out */ nsTArray<uint8_t>& aRegistration,
/* out */ nsTArray<uint8_t>& aSignature)
/* out */ nsTArray<uint8_t>& aRegistration)
{
nsNSSShutDownPreventionLock locker;
if (NS_WARN_IF(isAlreadyShutDown())) {

View File

@ -29,8 +29,7 @@ public:
Register(const nsTArray<WebAuthnScopedCredentialDescriptor>& aDescriptors,
const nsTArray<uint8_t>& aApplication,
const nsTArray<uint8_t>& aChallenge,
/* out */ nsTArray<uint8_t>& aRegistration,
/* out */ nsTArray<uint8_t>& aSignature) override;
/* out */ nsTArray<uint8_t>& aRegistration) override;
virtual RefPtr<ResultPromise>
Sign(const nsTArray<WebAuthnScopedCredentialDescriptor>& aDescriptors,

View File

@ -252,18 +252,16 @@ U2FTokenManager::Register(WebAuthnTransactionParent* aTransactionParent,
}
nsTArray<uint8_t> reg;
nsTArray<uint8_t> sig;
mResultPromise = mTokenManagerImpl->Register(aTransactionInfo.Descriptors(),
aTransactionInfo.RpIdHash(),
aTransactionInfo.ClientDataHash(),
reg,
sig);
reg);
mResultPromise->Then(GetCurrentThreadSerialEventTarget(), __func__,
[tid, reg, sig](nsresult rv) {
[tid, reg](nsresult rv) {
MOZ_ASSERT(NS_SUCCEEDED(rv));
U2FTokenManager* mgr = U2FTokenManager::Get();
mgr->MaybeConfirmRegister(tid, reg, sig);
mgr->MaybeConfirmRegister(tid, reg);
},
[tid](nsresult rv) {
MOZ_ASSERT(NS_FAILED(rv));
@ -274,14 +272,13 @@ U2FTokenManager::Register(WebAuthnTransactionParent* aTransactionParent,
void
U2FTokenManager::MaybeConfirmRegister(uint64_t aTransactionId,
const nsTArray<uint8_t>& aRegister,
const nsTArray<uint8_t>& aSignature)
const nsTArray<uint8_t>& aRegister)
{
if (mTransactionId != aTransactionId) {
return;
}
Unused << mTransactionParent->SendConfirmRegister(aRegister, aSignature);
Unused << mTransactionParent->SendConfirmRegister(aRegister);
ClearTransaction();
}

View File

@ -52,8 +52,7 @@ private:
void MaybeAbortTransaction(uint64_t aTransactionId,
const nsresult& aError);
void MaybeConfirmRegister(uint64_t aTransactionId,
const nsTArray<uint8_t>& aRegister,
const nsTArray<uint8_t>& aSignature);
const nsTArray<uint8_t>& aRegister);
void MaybeConfirmSign(uint64_t aTransactionId,
const nsTArray<uint8_t>& aKeyHandle,
const nsTArray<uint8_t>& aSignature);

View File

@ -30,8 +30,7 @@ public:
Register(const nsTArray<WebAuthnScopedCredentialDescriptor>& aDescriptors,
const nsTArray<uint8_t>& aApplication,
const nsTArray<uint8_t>& aChallenge,
/* out */ nsTArray<uint8_t>& aRegistration,
/* out */ nsTArray<uint8_t>& aSignature) = 0;
/* out */ nsTArray<uint8_t>& aRegistration) = 0;
virtual RefPtr<ResultPromise>
Sign(const nsTArray<WebAuthnScopedCredentialDescriptor>& aDescriptors,

View File

@ -610,8 +610,7 @@ WebAuthnManager::GetAssertion(nsPIDOMWindowInner* aParent,
}
void
WebAuthnManager::FinishMakeCredential(nsTArray<uint8_t>& aRegBuffer,
nsTArray<uint8_t>& aSigBuffer)
WebAuthnManager::FinishMakeCredential(nsTArray<uint8_t>& aRegBuffer)
{
MOZ_ASSERT(mTransactionPromise);
MOZ_ASSERT(mInfo.isSome());
@ -635,12 +634,6 @@ WebAuthnManager::FinishMakeCredential(nsTArray<uint8_t>& aRegBuffer,
return;
}
CryptoBuffer signatureData;
if (NS_WARN_IF(!signatureData.Assign(aSigBuffer.Elements(), aSigBuffer.Length()))) {
Cancel(NS_ERROR_OUT_OF_MEMORY);
return;
}
CryptoBuffer clientDataBuf;
if (!clientDataBuf.Assign(mClientData.ref())) {
Cancel(NS_ERROR_OUT_OF_MEMORY);
@ -655,7 +648,7 @@ WebAuthnManager::FinishMakeCredential(nsTArray<uint8_t>& aRegBuffer,
CryptoBuffer authenticatorDataBuf;
rv = U2FAssembleAuthenticatorData(authenticatorDataBuf, rpIdHashBuf,
signatureData);
signatureBuf);
if (NS_WARN_IF(NS_FAILED(rv))) {
Cancel(NS_ERROR_OUT_OF_MEMORY);
return;

View File

@ -62,8 +62,7 @@ public:
static WebAuthnManager* Get();
void
FinishMakeCredential(nsTArray<uint8_t>& aRegBuffer,
nsTArray<uint8_t>& aSigBuffer);
FinishMakeCredential(nsTArray<uint8_t>& aRegBuffer);
void
FinishGetAssertion(nsTArray<uint8_t>& aCredentialId,

View File

@ -19,12 +19,11 @@ WebAuthnTransactionChild::WebAuthnTransactionChild()
}
mozilla::ipc::IPCResult
WebAuthnTransactionChild::RecvConfirmRegister(nsTArray<uint8_t>&& aRegBuffer,
nsTArray<uint8_t>&& aSigBuffer)
WebAuthnTransactionChild::RecvConfirmRegister(nsTArray<uint8_t>&& aRegBuffer)
{
RefPtr<WebAuthnManager> mgr = WebAuthnManager::Get();
MOZ_ASSERT(mgr);
mgr->FinishMakeCredential(aRegBuffer, aSigBuffer);
mgr->FinishMakeCredential(aRegBuffer);
return IPC_OK();
}

View File

@ -24,8 +24,7 @@ class WebAuthnTransactionChild final : public PWebAuthnTransactionChild
public:
NS_INLINE_DECL_REFCOUNTING(WebAuthnTransactionChild);
WebAuthnTransactionChild();
mozilla::ipc::IPCResult RecvConfirmRegister(nsTArray<uint8_t>&& aRegBuffer,
nsTArray<uint8_t>&& aSigBuffer) override;
mozilla::ipc::IPCResult RecvConfirmRegister(nsTArray<uint8_t>&& aRegBuffer) override;
mozilla::ipc::IPCResult RecvConfirmSign(nsTArray<uint8_t>&& aCredentialId,
nsTArray<uint8_t>&& aBuffer) override;
mozilla::ipc::IPCResult RecvCancel(const nsresult& aError) override;

View File

@ -16,7 +16,7 @@
<body>
<p id="text">normal text</p>
<iframe id="editor" onload="doTest();"
src="data:text/html,<body>editable text</body>"></iframe>
srcdoc="<body>editable text</body>"></iframe>
</body>
</html>

View File

@ -16,7 +16,7 @@
<body>
<p id="text">normal text</p>
<iframe id="editor" onload="doTest();"
src="data:text/html,<script>document.designMode='on';</script><body>editable text</body>"></iframe>
srcdoc="<script>document.designMode='on';</script><body>editable text</body>"></iframe>
</body>
</html>

View File

@ -15,7 +15,7 @@
<p id="text">normal text</p>
<div>content editable</div>
<iframe id="editor" onload="doTest();"
src="data:text/html,<body>editable text</body>"></iframe>
srcdoc="<body>editable text</body>"></iframe>
</body>
</html>

View File

@ -20,7 +20,7 @@
<p>normal text</p>
<div id="editor1" contenteditable>content editable</div>
<iframe id="editor2" onload="doTest();"
src="data:text/html,<script>document.designMode='on';</script><body>editable text</body>"></iframe>
srcdoc="<script>document.designMode='on';</script><body>editable text</body>"></iframe>
</body>
</html>

View File

@ -1,7 +1,7 @@
<!DOCTYPE html>
<html class="reftest-wait">
<body>
<iframe src="data:text/html,<body><div></div></body>"></iframe>
<iframe srcdoc="<body><div></div></body>"></iframe>
<script type="text/javascript">
onload = function() {
var i = document.querySelector("iframe");

View File

@ -2,7 +2,7 @@
<html>
<body>
<div style="position: absolute">
<iframe src="data:text/html,<body contenteditable>foo</body>"></iframe>
<iframe srcdoc="<body contenteditable>foo</body>"></iframe>
</div>
<script type="text/javascript">
onload = function() {

View File

@ -2,7 +2,7 @@
<html>
<body>
<div>
<iframe src="data:text/html,<body contenteditable>foo</body>"></iframe>
<iframe srcdoc="<body contenteditable>foo</body>"></iframe>
</div>
<script type="text/javascript">
onload = function() {

View File

@ -37,6 +37,10 @@ public:
bool ComputeResizeFilter(ResizeMethod aResizeMethod, int32_t aSrcSize, int32_t aDstSize);
static inline size_t PadBytesForSIMD(size_t aBytes) {
return (aBytes + 31) & ~31;
}
private:
UniquePtr<SkConvolutionFilter1D> mFilter;
};

View File

@ -105,8 +105,8 @@ Downscaler::BeginFrame(const nsIntSize& aOriginalSize,
}
// Allocate the buffer, which contains scanlines of the original image.
// pad by 15 to handle overreads by the simd code
size_t bufferLen = mOriginalSize.width * sizeof(uint32_t) + 15;
// pad to handle overreads by the simd code
size_t bufferLen = gfx::ConvolutionFilter::PadBytesForSIMD(mOriginalSize.width * sizeof(uint32_t));
mRowBuffer.reset(new (fallible) uint8_t[bufferLen]);
if (MOZ_UNLIKELY(!mRowBuffer)) {
return NS_ERROR_OUT_OF_MEMORY;
@ -125,8 +125,8 @@ Downscaler::BeginFrame(const nsIntSize& aOriginalSize,
}
bool anyAllocationFailed = false;
// pad by 15 to handle overreads by the simd code
const int rowSize = mTargetSize.width * sizeof(uint32_t) + 15;
// pad to handle overreads by the simd code
const size_t rowSize = gfx::ConvolutionFilter::PadBytesForSIMD(mTargetSize.width * sizeof(uint32_t));
for (int32_t i = 0; i < mWindowCapacity; ++i) {
mWindow[i] = new (fallible) uint8_t[rowSize];
anyAllocationFailed = anyAllocationFailed || mWindow[i] == nullptr;

View File

@ -177,7 +177,7 @@ public:
// either valid or nullptr. That in turn ensures that ReleaseWindow() can
// clean up correctly.
bool anyAllocationFailed = false;
const uint32_t windowRowSizeInBytes = PaddedWidthInBytes(outputSize.width);
const size_t windowRowSizeInBytes = PaddedWidthInBytes(outputSize.width);
for (int32_t i = 0; i < mWindowCapacity; ++i) {
mWindow[i] = new (fallible) uint8_t[windowRowSizeInBytes];
anyAllocationFailed = anyAllocationFailed || mWindow[i] == nullptr;
@ -261,11 +261,11 @@ protected:
private:
uint8_t* GetRowPointer() const { return mRowBuffer.get(); }
static uint32_t PaddedWidthInBytes(uint32_t aLogicalWidth)
static size_t PaddedWidthInBytes(size_t aLogicalWidth)
{
// Convert from width in BGRA/BGRX pixels to width in bytes, padding by 15
// Convert from width in BGRA/BGRX pixels to width in bytes, padding
// to handle overreads by the SIMD code inside Skia.
return aLogicalWidth * sizeof(uint32_t) + 15;
return gfx::ConvolutionFilter::PadBytesForSIMD(aLogicalWidth * sizeof(uint32_t));
}
void DownscaleInputRow()

View File

@ -0,0 +1,16 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<style>
textarea {
border: red;
transform: rotate(-0.01rad);
}
</style>
</head>
<body>
<textarea></textarea>
</body>
</html>

View File

@ -25,6 +25,7 @@ load 1242778-1.png
load 1249576-1.png
load 1253362-1.html
load 1355898-1.html
load 1375842-1.html
load colormap-range.gif
HTTP load delayedframe.sjs # A 3-frame animated GIF with an inordinate delay between the second and third frame

View File

@ -795,9 +795,9 @@ ScheduleGC(JSContext* cx, unsigned argc, Value* vp)
if (args.length() == 0) {
/* Fetch next zeal trigger only. */
} else if (args[0].isInt32()) {
} else if (args[0].isNumber()) {
/* Schedule a GC to happen after |arg| allocations. */
JS_ScheduleGC(cx, args[0].toInt32());
JS_ScheduleGC(cx, std::max(int(args[0].toNumber()), 0));
} else if (args[0].isObject()) {
/* Ensure that |zone| is collected during the next GC. */
Zone* zone = UncheckedUnwrap(&args[0].toObject())->zone();
@ -813,7 +813,7 @@ ScheduleGC(JSContext* cx, unsigned argc, Value* vp)
PrepareZoneForGC(zone);
} else {
RootedObject callee(cx, &args.callee());
ReportUsageErrorASCII(cx, callee, "Bad argument - expecting integer, object or string");
ReportUsageErrorASCII(cx, callee, "Bad argument - expecting number, object or string");
return false;
}

View File

@ -59,7 +59,12 @@ class ChunkPool
public:
ChunkPool() : head_(nullptr), count_(0) {}
~ChunkPool() {
// TODO: We should be able to assert that the chunk pool is empty but
// this causes XPCShell test failures on Windows 2012. See bug 1379232.
}
bool empty() const { return !head_; }
size_t count() const { return count_; }
Chunk* head() { MOZ_ASSERT(head_); return head_; }

View File

@ -882,23 +882,15 @@ Statistics::endGC()
runtime->addTelemetry(JS_TELEMETRY_GC_SCC_SWEEP_TOTAL_MS, t(sccTotal));
runtime->addTelemetry(JS_TELEMETRY_GC_SCC_SWEEP_MAX_PAUSE_MS, t(sccLongest));
if (!aborted) {
TimeDuration total, longest;
gcDuration(&total, &longest);
TimeDuration total, longest;
gcDuration(&total, &longest);
runtime->addTelemetry(JS_TELEMETRY_GC_MS, t(total));
runtime->addTelemetry(JS_TELEMETRY_GC_MAX_PAUSE_MS, t(longest));
runtime->addTelemetry(JS_TELEMETRY_GC_MAX_PAUSE_MS_2, t(longest));
runtime->addTelemetry(JS_TELEMETRY_GC_MS, t(total));
runtime->addTelemetry(JS_TELEMETRY_GC_MAX_PAUSE_MS, t(longest));
runtime->addTelemetry(JS_TELEMETRY_GC_MAX_PAUSE_MS_2, t(longest));
const double mmu50 = computeMMU(TimeDuration::FromMilliseconds(50));
runtime->addTelemetry(JS_TELEMETRY_GC_MMU_50, mmu50 * 100);
}
if (fp)
printStats();
// Clear the OOM flag.
aborted = false;
const double mmu50 = computeMMU(TimeDuration::FromMilliseconds(50));
runtime->addTelemetry(JS_TELEMETRY_GC_MMU_50, mmu50 * 100);
thresholdTriggered = false;
}
@ -994,8 +986,13 @@ Statistics::endSlice()
}
bool last = !runtime->gc.isIncrementalGCInProgress();
if (last)
endGC();
if (last) {
if (fp)
printStats();
if (!aborted)
endGC();
}
if (enableProfiling_ && !aborted && slices_.back().duration() >= profileThreshold_)
printSliceProfile();
@ -1025,6 +1022,8 @@ Statistics::endSlice()
phaseStartTimes[Phase::MUTATOR] = mutatorStartTime;
phaseTimes[Phase::MUTATOR] = mutatorTime;
}
aborted = false;
}
void
@ -1132,8 +1131,18 @@ Statistics::recordPhaseBegin(Phase phase)
MOZ_ASSERT(phases[phase].parent == current);
TimeStamp now = TimeStamp::Now();
if (current != Phase::NONE)
if (current != Phase::NONE) {
#ifdef ANDROID
// Sadly this happens sometimes.
if (now < phaseStartTimes[currentPhase()]) {
now = phaseStartTimes[currentPhase()];
aborted = true;
}
#endif
MOZ_RELEASE_ASSERT(now >= phaseStartTimes[currentPhase()]);
}
phaseStack.infallibleAppend(phase);
phaseStartTimes[phase] = now;
@ -1147,6 +1156,15 @@ Statistics::recordPhaseEnd(Phase phase)
MOZ_ASSERT(phaseStartTimes[phase]);
TimeStamp now = TimeStamp::Now();
#ifdef ANDROID
// Sadly this happens sometimes.
if (now < phaseStartTimes[phase]) {
now = phaseStartTimes[phase];
aborted = true;
}
#endif
MOZ_RELEASE_ASSERT(now >= phaseStartTimes[phase]);
if (phase == Phase::MUTATOR)

View File

@ -334,8 +334,8 @@ struct Statistics
JS::GCNurseryCollectionCallback nurseryCollectionCallback;
/*
* True if we saw an OOM while allocating slices. The statistics for this
* GC will be invalid.
* True if we saw an OOM while allocating slices or we saw an impossible
* timestamp. The statistics for this GC will be invalid.
*/
bool aborted;

View File

@ -65,10 +65,11 @@ using namespace js::jit;
* The tempN registers are free to use for computations.
*/
NativeRegExpMacroAssembler::NativeRegExpMacroAssembler(JSContext* cx, LifoAlloc* alloc, RegExpShared* shared,
Mode mode, int registers_to_save)
: RegExpMacroAssembler(cx, *alloc, shared, registers_to_save),
cx(cx), mode_(mode)
NativeRegExpMacroAssembler::NativeRegExpMacroAssembler(JSContext* cx, LifoAlloc* alloc,
Mode mode, int registers_to_save,
RegExpShared::JitCodeTables& tables)
: RegExpMacroAssembler(cx, *alloc, registers_to_save),
tables(tables), cx(cx), mode_(mode)
{
// Find physical registers for each compiler register.
AllocatableGeneralRegisterSet regs(GeneralRegisterSet::All());
@ -931,11 +932,11 @@ NativeRegExpMacroAssembler::CheckCharacterNotInRange(char16_t from, char16_t to,
}
void
NativeRegExpMacroAssembler::CheckBitInTable(uint8_t* table, Label* on_bit_set)
NativeRegExpMacroAssembler::CheckBitInTable(RegExpShared::JitCodeTable table, Label* on_bit_set)
{
JitSpew(SPEW_PREFIX "CheckBitInTable");
masm.movePtr(ImmPtr(table), temp0);
masm.movePtr(ImmPtr(table.get()), temp0);
// kTableMask is currently 127, so we need to mask even if the input is
// Latin1. V8 has the same issue.
@ -946,6 +947,13 @@ NativeRegExpMacroAssembler::CheckBitInTable(uint8_t* table, Label* on_bit_set)
masm.load8ZeroExtend(BaseIndex(temp0, temp1, TimesOne), temp0);
masm.branchTest32(Assembler::NonZero, temp0, temp0, BranchOrBacktrack(on_bit_set));
// Transfer ownership of |table| to the |tables| Vector.
{
AutoEnterOOMUnsafeRegion oomUnsafe;
if (!tables.append(Move(table)))
oomUnsafe.crash("RegExp table append");
}
}
void

View File

@ -88,8 +88,8 @@ class MOZ_STACK_CLASS NativeRegExpMacroAssembler final : public RegExpMacroAssem
// Type of input string to generate code for.
enum Mode { LATIN1 = 1, CHAR16 = 2 };
NativeRegExpMacroAssembler(JSContext* cx, LifoAlloc* alloc, RegExpShared* shared,
Mode mode, int registers_to_save);
NativeRegExpMacroAssembler(JSContext* cx, LifoAlloc* alloc, Mode mode, int registers_to_save,
RegExpShared::JitCodeTables& tables);
// Inherited virtual methods.
RegExpCode GenerateCode(JSContext* cx, bool match_only);
@ -116,7 +116,7 @@ class MOZ_STACK_CLASS NativeRegExpMacroAssembler final : public RegExpMacroAssem
jit::Label* on_in_range);
void CheckCharacterNotInRange(char16_t from, char16_t to,
jit::Label* on_not_in_range);
void CheckBitInTable(uint8_t* table, jit::Label* on_bit_set);
void CheckBitInTable(RegExpShared::JitCodeTable table, jit::Label* on_bit_set);
void CheckPosition(int cp_offset, jit::Label* on_outside_input);
void JumpOrBacktrack(jit::Label* to);
bool CheckSpecialCharacterClass(char16_t type, jit::Label* on_no_match);
@ -173,6 +173,7 @@ class MOZ_STACK_CLASS NativeRegExpMacroAssembler final : public RegExpMacroAssem
private:
jit::MacroAssembler masm;
RegExpShared::JitCodeTables& tables;
JSContext* cx;
Mode mode_;

View File

@ -1734,7 +1734,7 @@ RegExpCode
irregexp::CompilePattern(JSContext* cx, HandleRegExpShared shared, RegExpCompileData* data,
HandleLinearString sample, bool is_global, bool ignore_case,
bool is_latin1, bool match_only, bool force_bytecode, bool sticky,
bool unicode)
bool unicode, RegExpShared::JitCodeTables& tables)
{
if ((data->capture_count + 1) * 2 - 1 > RegExpMacroAssembler::kMaxRegister) {
JS_ReportErrorASCII(cx, "regexp too big");
@ -1829,10 +1829,10 @@ irregexp::CompilePattern(JSContext* cx, HandleRegExpShared shared, RegExpCompile
: NativeRegExpMacroAssembler::CHAR16;
ctx.emplace(cx, (jit::TempAllocator*) nullptr);
native_assembler.emplace(cx, &alloc, shared, mode, (data->capture_count + 1) * 2);
native_assembler.emplace(cx, &alloc, mode, (data->capture_count + 1) * 2, tables);
assembler = native_assembler.ptr();
} else {
interpreted_assembler.emplace(cx, &alloc, shared, (data->capture_count + 1) * 2);
interpreted_assembler.emplace(cx, &alloc, (data->capture_count + 1) * 2);
assembler = interpreted_assembler.ptr();
}
@ -2513,21 +2513,21 @@ BoyerMooreLookahead::EmitSkipInstructions(RegExpMacroAssembler* masm)
return true;
}
uint8_t* boolean_skip_table;
RegExpShared::JitCodeTable boolean_skip_table;
{
AutoEnterOOMUnsafeRegion oomUnsafe;
boolean_skip_table = static_cast<uint8_t*>(js_malloc(kSize));
if (!boolean_skip_table || !masm->shared->addTable(boolean_skip_table))
boolean_skip_table.reset(static_cast<uint8_t*>(js_malloc(kSize)));
if (!boolean_skip_table)
oomUnsafe.crash("Table malloc");
}
int skip_distance = GetSkipTable(min_lookahead, max_lookahead, boolean_skip_table);
int skip_distance = GetSkipTable(min_lookahead, max_lookahead, boolean_skip_table.get());
MOZ_ASSERT(skip_distance != 0);
jit::Label cont, again;
masm->Bind(&again);
masm->LoadCurrentCharacter(max_lookahead, &cont, true);
masm->CheckBitInTable(boolean_skip_table, &cont);
masm->CheckBitInTable(Move(boolean_skip_table), &cont);
masm->AdvanceCurrentPosition(skip_distance);
masm->JumpOrBacktrack(&again);
masm->Bind(&cont);
@ -3308,18 +3308,18 @@ EmitUseLookupTable(RegExpMacroAssembler* masm,
}
// TODO(erikcorry): Cache these.
uint8_t* ba;
RegExpShared::JitCodeTable ba;
{
AutoEnterOOMUnsafeRegion oomUnsafe;
ba = static_cast<uint8_t*>(js_malloc(kSize));
if (!ba || !masm->shared->addTable(ba))
ba.reset(static_cast<uint8_t*>(js_malloc(kSize)));
if (!ba)
oomUnsafe.crash("Table malloc");
}
for (int i = 0; i < kSize; i++)
ba[i] = templ[i];
masm->CheckBitInTable(ba, on_bit_set);
masm->CheckBitInTable(Move(ba), on_bit_set);
if (on_bit_clear != fall_through)
masm->JumpOrBacktrack(on_bit_clear);
}

View File

@ -89,7 +89,7 @@ RegExpCode
CompilePattern(JSContext* cx, HandleRegExpShared shared, RegExpCompileData* data,
HandleLinearString sample, bool is_global, bool ignore_case,
bool is_latin1, bool match_only, bool force_bytecode, bool sticky,
bool unicode);
bool unicode, RegExpShared::JitCodeTables& tables);
// Note: this may return RegExpRunStatus_Error if an interrupt was requested
// while the code was executing.

View File

@ -98,9 +98,8 @@ irregexp::CaseInsensitiveCompareUCStrings(const char16_t* substring1,
size_t byteLength);
InterpretedRegExpMacroAssembler::InterpretedRegExpMacroAssembler(JSContext* cx, LifoAlloc* alloc,
RegExpShared* shared,
size_t numSavedRegisters)
: RegExpMacroAssembler(cx, *alloc, shared, numSavedRegisters),
: RegExpMacroAssembler(cx, *alloc, numSavedRegisters),
pc_(0),
advance_current_start_(0),
advance_current_offset_(0),
@ -313,7 +312,8 @@ InterpretedRegExpMacroAssembler::CheckCharacterNotInRange(char16_t from, char16_
}
void
InterpretedRegExpMacroAssembler::CheckBitInTable(uint8_t* table, jit::Label* on_bit_set)
InterpretedRegExpMacroAssembler::CheckBitInTable(RegExpShared::JitCodeTable table,
jit::Label* on_bit_set)
{
static const int kBitsPerByte = 8;

View File

@ -41,14 +41,12 @@ namespace irregexp {
class MOZ_STACK_CLASS RegExpMacroAssembler
{
public:
RegExpMacroAssembler(JSContext* cx, LifoAlloc& alloc, RegExpShared* shared,
size_t numSavedRegisters)
RegExpMacroAssembler(JSContext* cx, LifoAlloc& alloc, size_t numSavedRegisters)
: slow_safe_compiler_(false),
global_mode_(NOT_GLOBAL),
alloc_(alloc),
num_registers_(numSavedRegisters),
num_saved_registers_(numSavedRegisters),
shared(cx, shared)
num_saved_registers_(numSavedRegisters)
{}
enum StackCheckFlag {
@ -138,7 +136,7 @@ class MOZ_STACK_CLASS RegExpMacroAssembler
// The current character (modulus the kTableSize) is looked up in the byte
// array, and if the found byte is non-zero, we jump to the on_bit_set label.
virtual void CheckBitInTable(uint8_t* table, jit::Label* on_bit_set) = 0;
virtual void CheckBitInTable(RegExpShared::JitCodeTable table, jit::Label* on_bit_set) = 0;
// Checks whether the given offset from the current position is before
// the end of the string. May overwrite the current character.
@ -214,9 +212,6 @@ class MOZ_STACK_CLASS RegExpMacroAssembler
if (num_registers_ <= reg)
num_registers_ = reg + 1;
}
public:
RootedRegExpShared shared;
};
template <typename CharT>
@ -231,8 +226,7 @@ CaseInsensitiveCompareUCStrings(const CharT* substring1, const CharT* substring2
class MOZ_STACK_CLASS InterpretedRegExpMacroAssembler final : public RegExpMacroAssembler
{
public:
InterpretedRegExpMacroAssembler(JSContext* cx, LifoAlloc* alloc, RegExpShared* shared,
size_t numSavedRegisters);
InterpretedRegExpMacroAssembler(JSContext* cx, LifoAlloc* alloc, size_t numSavedRegisters);
~InterpretedRegExpMacroAssembler();
// Inherited virtual methods.
@ -258,7 +252,7 @@ class MOZ_STACK_CLASS InterpretedRegExpMacroAssembler final : public RegExpMacro
jit::Label* on_in_range);
void CheckCharacterNotInRange(char16_t from, char16_t to,
jit::Label* on_not_in_range);
void CheckBitInTable(uint8_t* table, jit::Label* on_bit_set);
void CheckBitInTable(RegExpShared::JitCodeTable table, jit::Label* on_bit_set);
void JumpOrBacktrack(jit::Label* to);
void Fail();
void IfRegisterGE(int reg, int comparand, jit::Label* if_ge);

View File

@ -0,0 +1,17 @@
var g = newGlobal();
var w = g.eval("() => {}");
var v = g.eval("Array");
try {
Reflect.construct(Array, [], w);
assertEq(true, false, "Expected exception above");
} catch (e) {
assertEq(e.constructor, TypeError);
}
try {
Reflect.construct(v, [], w);
assertEq(true, false, "Expected exception above");
} catch (e) {
assertEq(e.constructor, TypeError);
}

View File

@ -328,7 +328,7 @@ DoTypeUpdateFallback(JSContext* cx, BaselineFrame* frame, ICUpdatedStub* stub, H
AddTypePropertyId(cx, group, maybeSingleton, id, value);
}
if (MOZ_UNLIKELY(!stub->addUpdateStubForValue(cx, script, obj, id, value))) {
if (MOZ_UNLIKELY(!stub->addUpdateStubForValue(cx, script, obj, group, id, value))) {
// The calling JIT code assumes this function is infallible (for
// instance we may reallocate dynamic slots before calling this),
// so ignore OOMs if we failed to attach a stub.

View File

@ -2637,20 +2637,22 @@ ICTypeMonitor_AnyValue::Compiler::generateStubCode(MacroAssembler& masm)
bool
ICUpdatedStub::addUpdateStubForValue(JSContext* cx, HandleScript outerScript, HandleObject obj,
HandleId id, HandleValue val)
HandleObjectGroup group, HandleId id, HandleValue val)
{
EnsureTrackPropertyTypes(cx, obj, id);
// Make sure that undefined values are explicitly included in the property
// types for an object if generating a stub to write an undefined value.
if (val.isUndefined() && CanHaveEmptyPropertyTypesForOwnProperty(obj))
if (val.isUndefined() && CanHaveEmptyPropertyTypesForOwnProperty(obj)) {
MOZ_ASSERT(obj->group() == group);
AddTypePropertyId(cx, obj, id, val);
}
bool unknown = false, unknownObject = false;
if (obj->group()->unknownProperties()) {
if (group->unknownProperties()) {
unknown = unknownObject = true;
} else {
if (HeapTypeSet* types = obj->group()->maybeGetProperty(id)) {
if (HeapTypeSet* types = group->maybeGetProperty(id)) {
unknown = types->unknown();
unknownObject = types->unknownObject();
} else {

View File

@ -939,7 +939,7 @@ class ICUpdatedStub : public ICStub
MOZ_MUST_USE bool initUpdatingChain(JSContext* cx, ICStubSpace* space);
MOZ_MUST_USE bool addUpdateStubForValue(JSContext* cx, HandleScript script, HandleObject obj,
HandleId id, HandleValue val);
HandleObjectGroup group, HandleId id, HandleValue val);
void addOptimizedUpdateStub(ICStub* stub) {
if (firstUpdateStub_->isTypeUpdate_Fallback()) {

View File

@ -35,6 +35,12 @@ BEGIN_TEST(testGCFinalizeCallback)
CHECK(checkFinalizeStatus());
CHECK(checkFinalizeIsZoneGC(false));
#ifdef JS_GC_ZEAL
// Bug 1377593 - the below tests want to control how many zones are GC'ing,
// and some zeal modes will convert them into all-zones GCs.
JS_SetGCZeal(cx, 0, 0);
#endif
JS::RootedObject global1(cx, createTestGlobal());
JS::RootedObject global2(cx, createTestGlobal());
JS::RootedObject global3(cx, createTestGlobal());

View File

@ -1193,10 +1193,10 @@ GCRuntime::init(uint32_t maxbytes, uint32_t maxNurseryBytes)
void
GCRuntime::finish()
{
/* Wait for the nursery sweeping to end. */
for (ZoneGroupsIter group(rt); !group.done(); group.next()) {
if (group->nursery().isEnabled())
group->nursery().waitBackgroundFreeEnd();
/* Wait for nursery background free to end and disable it to release memory. */
if (nursery().isEnabled()) {
nursery().waitBackgroundFreeEnd();
nursery().disable();
}
/*

View File

@ -178,11 +178,6 @@ IsMarkingTrace(JSTracer* trc)
void
RegExpObject::trace(JSTracer* trc)
{
// When marking the object normally we have the option of unlinking the
// object from its RegExpShared so that the RegExpShared may be collected.
if (IsMarkingTrace(trc) && !zone()->isPreservingCode())
sharedRef() = nullptr;
TraceNullableEdge(trc, &sharedRef(), "RegExpObject shared");
}
@ -966,6 +961,9 @@ RegExpShared::discardJitCode()
{
for (auto& comp : compilationArray)
comp.jitCode = nullptr;
// We can also purge the tables used by JIT code.
tables.clearAndFree();
}
void
@ -973,8 +971,6 @@ RegExpShared::finalize(FreeOp* fop)
{
for (auto& comp : compilationArray)
js_free(comp.byteCode);
for (size_t i = 0; i < tables.length(); i++)
js_free(tables[i]);
tables.~JitCodeTables();
}
@ -1012,6 +1008,7 @@ RegExpShared::compile(JSContext* cx, MutableHandleRegExpShared re, HandleAtom pa
re->parenCount = data.capture_count;
JitCodeTables tables;
irregexp::RegExpCode code = irregexp::CompilePattern(cx, re, &data, input,
false /* global() */,
re->ignoreCase(),
@ -1019,7 +1016,8 @@ RegExpShared::compile(JSContext* cx, MutableHandleRegExpShared re, HandleAtom pa
mode == MatchOnly,
force == ForceByteCode,
re->sticky(),
re->unicode());
re->unicode(),
tables);
if (code.empty())
return false;
@ -1027,10 +1025,20 @@ RegExpShared::compile(JSContext* cx, MutableHandleRegExpShared re, HandleAtom pa
MOZ_ASSERT_IF(force == ForceByteCode, code.byteCode);
RegExpCompilation& compilation = re->compilation(mode, input->hasLatin1Chars());
if (code.jitCode)
if (code.jitCode) {
// First copy the tables. GC can purge the tables if the RegExpShared
// has no JIT code, so it's important to do this right before setting
// compilation.jitCode (to ensure no purging happens between adding the
// tables and setting the JIT code).
for (size_t i = 0; i < tables.length(); i++) {
if (!re->addTable(Move(tables[i])))
return false;
}
compilation.jitCode = code.jitCode;
else if (code.byteCode)
} else if (code.byteCode) {
MOZ_ASSERT(tables.empty(), "RegExpInterpreter does not use data tables");
compilation.byteCode = code.byteCode;
}
return true;
}
@ -1186,7 +1194,7 @@ RegExpShared::sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf)
n += tables.sizeOfExcludingThis(mallocSizeOf);
for (size_t i = 0; i < tables.length(); i++)
n += mallocSizeOf(tables[i]);
n += mallocSizeOf(tables[i].get());
return n;
}

View File

@ -152,7 +152,7 @@ class RegExpObject : public NativeObject
void setShared(RegExpShared& shared) {
MOZ_ASSERT(!hasShared());
sharedRef() = &shared;
sharedRef().init(&shared);
}
static void trace(JSTracer* trc, JSObject* obj);
@ -178,9 +178,9 @@ class RegExpObject : public NativeObject
static MOZ_MUST_USE bool createShared(JSContext* cx, Handle<RegExpObject*> regexp,
MutableHandleRegExpShared shared);
ReadBarriered<RegExpShared*>& sharedRef() {
PreBarriered<RegExpShared*>& sharedRef() {
auto& ref = NativeObject::privateRef(PRIVATE_SLOT);
return reinterpret_cast<ReadBarriered<RegExpShared*>&>(ref);
return reinterpret_cast<PreBarriered<RegExpShared*>&>(ref);
}
/* Call setShared in preference to setPrivate. */

View File

@ -96,6 +96,9 @@ class RegExpShared : public gc::TenuredCell
ForceByteCode
};
using JitCodeTable = UniquePtr<uint8_t[], JS::FreePolicy>;
using JitCodeTables = Vector<JitCodeTable, 0, SystemAllocPolicy>;
private:
friend class RegExpStatics;
friend class RegExpZone;
@ -130,7 +133,6 @@ class RegExpShared : public gc::TenuredCell
}
// Tables referenced by JIT code.
using JitCodeTables = Vector<uint8_t*, 0, SystemAllocPolicy>;
JitCodeTables tables;
/* Internal functions. */
@ -163,8 +165,8 @@ class RegExpShared : public gc::TenuredCell
MatchPairs* matches, size_t* endIndex);
// Register a table with this RegExpShared, and take ownership.
bool addTable(uint8_t* table) {
return tables.append(table);
bool addTable(JitCodeTable table) {
return tables.append(Move(table));
}
/* Accessors */

View File

@ -185,7 +185,22 @@ static bool
intrinsic_IsConstructor(JSContext* cx, unsigned argc, Value* vp)
{
CallArgs args = CallArgsFromVp(argc, vp);
args.rval().setBoolean(IsConstructor(args[0]));
MOZ_ASSERT(args.length() == 1);
RootedValue val(cx, args[0]);
if (!IsConstructor(val)) {
args.rval().setBoolean(false);
return true;
}
RootedObject obj(cx, &val.toObject());
if (!IsWrapper(obj)) {
args.rval().setBoolean(true);
return true;
}
obj = UncheckedUnwrap(obj);
args.rval().setBoolean(obj && obj->isConstructor());
return true;
}

View File

@ -160,8 +160,10 @@ JSDependentString::new_(JSContext* cx, JSLinearString* baseArg, size_t start,
* entirely, however, due to how ropes are flattened.
*/
if (baseArg->isDependent()) {
start += baseArg->asDependent().baseOffset();
baseArg = baseArg->asDependent().base();
if (mozilla::Maybe<size_t> offset = baseArg->asDependent().baseOffset()) {
start += *offset;
baseArg = baseArg->asDependent().base();
}
}
MOZ_ASSERT(start + length <= baseArg->length());

View File

@ -719,7 +719,9 @@ JSDependentString::dumpRepresentation(FILE* fp, int indent) const
dumpRepresentationHeader(fp, indent, "JSDependentString");
indent += 2;
fprintf(fp, "%*soffset: %" PRIuSIZE "\n", indent, "", baseOffset());
if (mozilla::Maybe<size_t> offset = baseOffset())
fprintf(fp, "%*soffset: %" PRIuSIZE "\n", indent, "", *offset);
fprintf(fp, "%*sbase: ", indent, "");
base()->dumpRepresentation(fp, indent);
}

View File

@ -724,16 +724,18 @@ class JSDependentString : public JSLinearString
JSDependentString& asDependent() const = delete;
/* The offset of this string's chars in base->chars(). */
size_t baseOffset() const {
MOZ_ALWAYS_INLINE mozilla::Maybe<size_t> baseOffset() const {
MOZ_ASSERT(JSString::isDependent());
JS::AutoCheckCannotGC nogc;
if (MOZ_UNLIKELY(base()->isUndepended()))
return mozilla::Nothing();
size_t offset;
if (hasTwoByteChars())
offset = twoByteChars(nogc) - base()->twoByteChars(nogc);
else
offset = latin1Chars(nogc) - base()->latin1Chars(nogc);
MOZ_ASSERT(offset < base()->length());
return offset;
return mozilla::Some(offset);
}
public:

View File

@ -2540,7 +2540,7 @@ SizeComputationInput::InitOffsets(WritingMode aWM,
const nsMargin* aPadding,
const nsStyleDisplay* aDisplay)
{
DISPLAY_INIT_OFFSETS(mFrame, this, aPercentBasis, aBorder, aPadding);
DISPLAY_INIT_OFFSETS(mFrame, this, aPercentBasis, aWM, aBorder, aPadding);
// Since we are in reflow, we don't need to store these properties anymore
// unless they are dependent on width, in which case we store the new value.

View File

@ -247,6 +247,7 @@ public:
nsIFrame* aFrame,
SizeComputationInput* aState,
const mozilla::LogicalSize& aPercentBasis,
WritingMode aCBWritingMode,
const nsMargin* aBorder,
const nsMargin* aPadding);
static void DisplayInitOffsetsExit(nsIFrame* aFrame,

View File

@ -10918,8 +10918,9 @@ DR_init_constraints_cookie::~DR_init_constraints_cookie()
DR_init_offsets_cookie::DR_init_offsets_cookie(
nsIFrame* aFrame,
SizeComputationInput* aState,
SizeComputationInput* aState,
const LogicalSize& aPercentBasis,
WritingMode aCBWritingMode,
const nsMargin* aMargin,
const nsMargin* aPadding)
: mFrame(aFrame)
@ -10927,8 +10928,9 @@ DR_init_offsets_cookie::DR_init_offsets_cookie(
{
MOZ_COUNT_CTOR(DR_init_offsets_cookie);
mValue = SizeComputationInput::DisplayInitOffsetsEnter(mFrame, mState,
aPercentBasis,
aMargin, aPadding);
aPercentBasis,
aCBWritingMode,
aMargin, aPadding);
}
DR_init_offsets_cookie::~DR_init_offsets_cookie()
@ -11878,6 +11880,7 @@ ReflowInput::DisplayInitConstraintsExit(nsIFrame* aFrame,
SizeComputationInput::DisplayInitOffsetsEnter(nsIFrame* aFrame,
SizeComputationInput* aState,
const LogicalSize& aPercentBasis,
WritingMode aCBWritingMode,
const nsMargin* aBorder,
const nsMargin* aPadding)
{
@ -11894,9 +11897,10 @@ SizeComputationInput::DisplayInitOffsetsEnter(nsIFrame* aFrame,
char horizPctBasisStr[16];
char vertPctBasisStr[16];
WritingMode wm = aState->GetWritingMode();
DR_state->PrettyUC(aPercentBasis.ISize(wm), horizPctBasisStr, 16);
DR_state->PrettyUC(aPercentBasis.BSize(wm), vertPctBasisStr, 16);
DR_state->PrettyUC(aPercentBasis.ISize(aCBWritingMode),
horizPctBasisStr, 16);
DR_state->PrettyUC(aPercentBasis.BSize(aCBWritingMode),
vertPctBasisStr, 16);
printf("InitOffsets pct_basis=%s,%s", horizPctBasisStr, vertPctBasisStr);
DR_state->PrintMargin("b", aBorder);

View File

@ -865,6 +865,7 @@ public:
struct DR_init_offsets_cookie {
DR_init_offsets_cookie(nsIFrame* aFrame, mozilla::SizeComputationInput* aState,
const mozilla::LogicalSize& aPercentBasis,
mozilla::WritingMode aCBWritingMode,
const nsMargin* aBorder,
const nsMargin* aPadding);
~DR_init_offsets_cookie();
@ -903,8 +904,10 @@ public:
dr_bdr, dr_pad) \
DR_init_constraints_cookie dr_cookie(dr_frame, dr_state, dr_cbw, dr_cbh, \
dr_bdr, dr_pad)
#define DISPLAY_INIT_OFFSETS(dr_frame, dr_state, dr_pb, dr_bdr, dr_pad) \
DR_init_offsets_cookie dr_cookie(dr_frame, dr_state, dr_pb, dr_bdr, dr_pad)
#define DISPLAY_INIT_OFFSETS(dr_frame, dr_state, dr_pb, dr_cbwm, dr_bdr, \
dr_pad) \
DR_init_offsets_cookie dr_cookie(dr_frame, dr_state, dr_pb, dr_cbwm, \
dr_bdr, dr_pad)
#define DISPLAY_INIT_TYPE(dr_frame, dr_result) \
DR_init_type_cookie dr_cookie(dr_frame, dr_result)
@ -921,7 +924,8 @@ public:
#define DISPLAY_INIT_CONSTRAINTS(dr_frame, dr_state, dr_cbw, dr_cbh, \
dr_bdr, dr_pad) \
PR_BEGIN_MACRO PR_END_MACRO
#define DISPLAY_INIT_OFFSETS(dr_frame, dr_state, dr_pb, dr_bdr, dr_pad) \
#define DISPLAY_INIT_OFFSETS(dr_frame, dr_state, dr_pb, dr_cbwm, dr_bdr, \
dr_pad) \
PR_BEGIN_MACRO PR_END_MACRO
#define DISPLAY_INIT_TYPE(dr_frame, dr_result) PR_BEGIN_MACRO PR_END_MACRO

View File

@ -1,6 +1,6 @@
<!DOCTYPE html>
<html>
<body>
<iframe id="foo" src="data:text/html,<body bgcolor='lime'>PASS</body>"></iframe>
<iframe id="foo" srcdoc="<body bgcolor='lime'>PASS</body>"></iframe>
</body>
</html>

View File

@ -1,7 +1,7 @@
<!DOCTYPE html>
<html class="reftest-wait">
<body>
<iframe id="foo" src="data:text/html,<body bgcolor='red'>FAIL</body>"></iframe>
<iframe id="foo" srcdoc="<body bgcolor='red'>FAIL</body>"></iframe>
<script type="text/javascript">
// Globals
var foo = document.getElementById('foo');

View File

@ -13,6 +13,9 @@
#include "SandboxFilter.h"
#include "SandboxInternal.h"
#include "SandboxLogging.h"
#ifdef MOZ_GMP_SANDBOX
#include "SandboxOpenedFiles.h"
#endif
#include "SandboxReporterClient.h"
#include "SandboxUtil.h"
@ -34,9 +37,12 @@
#include <sys/time.h>
#include <unistd.h>
#include "mozilla/Array.h"
#include "mozilla/Atomics.h"
#include "mozilla/Maybe.h"
#include "mozilla/Range.h"
#include "mozilla/SandboxInfo.h"
#include "mozilla/Span.h"
#include "mozilla/UniquePtr.h"
#include "mozilla/Unused.h"
#include "sandbox/linux/bpf_dsl/codegen.h"
@ -82,13 +88,6 @@ static bool gSandboxCrashOnError = false;
// This is initialized by SandboxSetCrashFunc().
SandboxCrashFunc gSandboxCrashFunc;
#ifdef MOZ_GMP_SANDBOX
// For media plugins, we can start the sandbox before we dlopen the
// module, so we have to pre-open the file and simulate the sandboxed
// open().
static SandboxOpenedFile gMediaPluginFile;
#endif
static Maybe<SandboxReporterClient> gSandboxReporterClient;
static UniquePtr<SandboxChroot> gChrootHelper;
static void (*gChromiumSigSysHandler)(int, siginfo_t*, void*);
@ -713,26 +712,32 @@ SetContentProcessSandbox(int aBrokerFd, std::vector<int>& aSyscallWhitelist)
void
SetMediaPluginSandbox(const char *aFilePath)
{
MOZ_RELEASE_ASSERT(aFilePath != nullptr);
if (!SandboxInfo::Get().Test(SandboxInfo::kEnabledForMedia)) {
return;
}
gSandboxReporterClient.emplace(SandboxReport::ProcType::MEDIA_PLUGIN);
MOZ_ASSERT(!gMediaPluginFile.mPath);
if (aFilePath) {
gMediaPluginFile.mPath = strdup(aFilePath);
gMediaPluginFile.mFd = open(aFilePath, O_RDONLY | O_CLOEXEC);
if (gMediaPluginFile.mFd == -1) {
SANDBOX_LOG_ERROR("failed to open plugin file %s: %s",
aFilePath, strerror(errno));
MOZ_CRASH();
}
} else {
gMediaPluginFile.mFd = -1;
SandboxOpenedFile plugin(aFilePath);
if (!plugin.IsOpen()) {
SANDBOX_LOG_ERROR("failed to open plugin file %s: %s",
aFilePath, strerror(errno));
MOZ_CRASH();
}
auto files = new SandboxOpenedFiles();
files->Add(Move(plugin));
files->Add("/dev/urandom", true);
files->Add("/sys/devices/system/cpu/cpu0/tsc_freq_khz");
files->Add("/sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_max_freq");
files->Add("/proc/cpuinfo"); // Info also available via CPUID instruction.
#ifdef __i386__
files->Add("/proc/self/auxv"); // Info also in process's address space.
#endif
// Finally, start the sandbox.
SetCurrentProcessSandbox(GetMediaSandboxPolicy(&gMediaPluginFile));
SetCurrentProcessSandbox(GetMediaSandboxPolicy(files));
}
#endif // MOZ_GMP_SANDBOX

View File

@ -11,6 +11,10 @@
#include "SandboxInfo.h"
#include "SandboxInternal.h"
#include "SandboxLogging.h"
#ifdef MOZ_GMP_SANDBOX
#include "SandboxOpenedFiles.h"
#endif
#include "mozilla/PodOperations.h"
#include "mozilla/UniquePtr.h"
#include <errno.h>
@ -23,6 +27,7 @@
#include <sys/mman.h>
#include <sys/socket.h>
#include <sys/syscall.h>
#include <sys/utsname.h>
#include <time.h>
#include <unistd.h>
#include <vector>
@ -893,7 +898,7 @@ class GMPSandboxPolicy : public SandboxPolicyCommon {
static intptr_t OpenTrap(const sandbox::arch_seccomp_data& aArgs,
void* aux)
{
auto plugin = static_cast<SandboxOpenedFile*>(aux);
const auto files = static_cast<const SandboxOpenedFiles*>(aux);
const char* path;
int flags;
@ -914,20 +919,15 @@ class GMPSandboxPolicy : public SandboxPolicyCommon {
MOZ_CRASH("unexpected syscall number");
}
if (strcmp(path, plugin->mPath) != 0) {
SANDBOX_LOG_ERROR("attempt to open file %s (flags=0%o) which is not the"
" media plugin %s", path, flags, plugin->mPath);
return -EPERM;
}
if ((flags & O_ACCMODE) != O_RDONLY) {
SANDBOX_LOG_ERROR("non-read-only open of file %s attempted (flags=0%o)",
path, flags);
return -EPERM;
return -EROFS;
}
int fd = plugin->mFd.exchange(-1);
int fd = files->GetDesc(path);
if (fd < 0) {
SANDBOX_LOG_ERROR("multiple opens of media plugin file unimplemented");
return -ENOSYS;
// SandboxOpenedFile::GetDesc already logged about this, if appropriate.
return -ENOENT;
}
return fd;
}
@ -949,14 +949,40 @@ class GMPSandboxPolicy : public SandboxPolicyCommon {
return BlockedSyscallTrap(aArgs, nullptr);
}
SandboxOpenedFile* mPlugin;
public:
explicit GMPSandboxPolicy(SandboxOpenedFile* aPlugin)
: mPlugin(aPlugin)
static intptr_t UnameTrap(const sandbox::arch_seccomp_data& aArgs,
void* aux)
{
MOZ_ASSERT(aPlugin->mPath[0] == '/', "plugin path should be absolute");
const auto buf = reinterpret_cast<struct utsname*>(aArgs.args[0]);
PodZero(buf);
// The real uname() increases fingerprinting risk for no benefit.
// This is close enough.
strcpy(buf->sysname, "Linux");
strcpy(buf->version, "3");
return 0;
};
static intptr_t FcntlTrap(const sandbox::arch_seccomp_data& aArgs,
void* aux)
{
const auto cmd = static_cast<int>(aArgs.args[1]);
switch (cmd) {
// This process can't exec, so the actual close-on-exec flag
// doesn't matter; have it always read as true and ignore writes.
case F_GETFD:
return O_CLOEXEC;
case F_SETFD:
return 0;
default:
return -ENOSYS;
}
}
const SandboxOpenedFiles* mFiles;
public:
explicit GMPSandboxPolicy(const SandboxOpenedFiles* aFiles)
: mFiles(aFiles)
{ }
~GMPSandboxPolicy() override = default;
ResultExpr EvaluateSyscall(int sysno) const override {
@ -966,7 +992,7 @@ public:
case __NR_open:
#endif
case __NR_openat:
return Trap(OpenTrap, mPlugin);
return Trap(OpenTrap, mFiles);
// ipc::Shmem
case __NR_mprotect:
@ -999,6 +1025,15 @@ public:
case __NR_times:
return Allow();
// Bug 1372428
case __NR_uname:
return Trap(UnameTrap, nullptr);
CASES_FOR_fcntl:
return Trap(FcntlTrap, nullptr);
case __NR_dup:
return Allow();
default:
return SandboxPolicyCommon::EvaluateSyscall(sysno);
}
@ -1006,11 +1041,11 @@ public:
};
UniquePtr<sandbox::bpf_dsl::Policy>
GetMediaSandboxPolicy(SandboxOpenedFile* aPlugin)
GetMediaSandboxPolicy(const SandboxOpenedFiles* aFiles)
{
return UniquePtr<sandbox::bpf_dsl::Policy>(new GMPSandboxPolicy(aPlugin));
return UniquePtr<sandbox::bpf_dsl::Policy>(new GMPSandboxPolicy(aFiles));
}
#endif // MOZ_GMP_SANDBOX
}
} // namespace mozilla

View File

@ -9,6 +9,7 @@
#include <vector>
#include "mozilla/Atomics.h"
#include "mozilla/Range.h"
#include "mozilla/UniquePtr.h"
namespace sandbox {
@ -27,12 +28,10 @@ UniquePtr<sandbox::bpf_dsl::Policy> GetContentSandboxPolicy(SandboxBrokerClient*
#endif
#ifdef MOZ_GMP_SANDBOX
struct SandboxOpenedFile {
const char *mPath;
Atomic<int> mFd;
};
class SandboxOpenedFiles;
UniquePtr<sandbox::bpf_dsl::Policy> GetMediaSandboxPolicy(SandboxOpenedFile* aPlugin);
// The SandboxOpenedFiles object must live until the process exits.
UniquePtr<sandbox::bpf_dsl::Policy> GetMediaSandboxPolicy(const SandboxOpenedFiles* aFiles);
#endif
} // namespace mozilla

View File

@ -0,0 +1,79 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* 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 "SandboxOpenedFiles.h"
#include "mozilla/Move.h"
#include "SandboxLogging.h"
#include <fcntl.h>
#include <unistd.h>
namespace mozilla {
// The default move constructor almost works, but Atomic isn't
// move-constructable and the fd needs some special handling.
SandboxOpenedFile::SandboxOpenedFile(SandboxOpenedFile&& aMoved)
: mPath(Move(aMoved.mPath))
, mMaybeFd(aMoved.TakeDesc())
, mDup(aMoved.mDup)
, mExpectError(aMoved.mExpectError)
{ }
SandboxOpenedFile::SandboxOpenedFile(const char* aPath, bool aDup)
: mPath(aPath), mDup(aDup), mExpectError(false)
{
MOZ_ASSERT(aPath[0] == '/', "path should be absolute");
int fd = open(aPath, O_RDONLY | O_CLOEXEC);
if (fd < 0) {
mExpectError = true;
}
mMaybeFd = fd;
}
int
SandboxOpenedFile::GetDesc() const
{
int fd = -1;
if (mDup) {
fd = mMaybeFd;
if (fd >= 0) {
fd = dup(fd);
if (fd < 0) {
SANDBOX_LOG_ERROR("dup: %s", strerror(errno));
}
}
} else {
fd = TakeDesc();
}
if (fd < 0 && !mExpectError) {
SANDBOX_LOG_ERROR("unexpected multiple open of file %s", Path());
}
return fd;
}
SandboxOpenedFile::~SandboxOpenedFile()
{
int fd = TakeDesc();
if (fd >= 0) {
close(fd);
}
}
int
SandboxOpenedFiles::GetDesc(const char* aPath) const
{
for (const auto& file : mFiles) {
if (strcmp(file.Path(), aPath) == 0) {
return file.GetDesc();
}
}
SANDBOX_LOG_ERROR("attempt to open unexpected file %s", aPath);
return -1;
}
} // namespace mozilla

View File

@ -0,0 +1,89 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* 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/. */
#ifndef mozilla_SandboxOpenedFiles_h
#define mozilla_SandboxOpenedFiles_h
#include "mozilla/Atomics.h"
#include "mozilla/Range.h"
#include "mozilla/UniquePtr.h"
#include <vector>
#include <string>
// The use of C++ standard library containers here should be safe; the
// standard (section container.requirements.dataraces) requires that
// using const methods/pointers not introduce data races (e.g., from
// interior mutability or global state).
//
// Reentrancy isn't guaranteed, and the library could use async signal
// unsafe mutexes for "read-only" operations, but I'm assuming that that's
// not the case at least for simple containers like string and vector.
namespace mozilla {
// This class represents a file that's been pre-opened for a media
// plugin. It can be move-constructed but not copied.
class SandboxOpenedFile final {
public:
// This constructor opens the named file and saves the descriptor.
// If the open fails, IsOpen() will return false and GetDesc() will
// quietly return -1. If aDup is true, GetDesc() will return a
// dup() of the descriptor every time it's called; otherwise, the
// first call will return the descriptor and any further calls will
// log an error message and return -1.
explicit SandboxOpenedFile(const char* aPath, bool aDup = false);
// Simulates opening the pre-opened file; see the constructor's
// comment for details. Does not set errno on error, but may modify
// it as a side-effect. Thread-safe and intended to be async signal safe.
int GetDesc() const;
const char* Path() const { return mPath.c_str(); }
bool IsOpen() const { return mMaybeFd >= 0; }
~SandboxOpenedFile();
MOZ_IMPLICIT SandboxOpenedFile(SandboxOpenedFile&& aMoved);
private:
std::string mPath;
mutable Atomic<int> mMaybeFd;
bool mDup;
bool mExpectError;
int TakeDesc() const { return mMaybeFd.exchange(-1); }
};
// This class represents a collection of files to be used to handle
// open() calls from the media plugin (and the dynamic loader).
// Because the seccomp-bpf policy exists until the process exits, this
// object must not be destroyed after the syscall filter is installed.
class SandboxOpenedFiles {
public:
SandboxOpenedFiles() = default;
template<typename... Args>
void Add(Args&&... aArgs) {
mFiles.emplace_back(Forward<Args>(aArgs)...);
}
int GetDesc(const char* aPath) const;
private:
std::vector<SandboxOpenedFile> mFiles;
// We could allow destroying instances of this class that aren't
// used with seccomp-bpf (e.g., for unit testing) by having the
// destructor check a flag set by the syscall policy and crash,
// but let's not write that code until we actually need it.
~SandboxOpenedFiles() = delete;
};
} // namespace mozilla
#endif // mozilla_SandboxOpenedFiles_h

View File

@ -72,6 +72,11 @@ SOURCES += [
'SandboxUtil.cpp',
]
if CONFIG['MOZ_GMP_SANDBOX']:
SOURCES += [
'SandboxOpenedFiles.cpp',
]
# This copy of SafeSPrintf doesn't need to avoid the Chromium logging
# dependency like the one in libxul does, but this way the behavior is
# consistent. See also the comment in SandboxLogging.h.

View File

@ -288,8 +288,7 @@ Service::~Service()
if (rc != SQLITE_OK)
NS_WARNING("sqlite3 did not shutdown cleanly.");
DebugOnly<bool> shutdownObserved = !sXPConnect;
NS_ASSERTION(shutdownObserved, "Shutdown was not observed!");
shutdown(); // To release sXPConnect.
gService = nullptr;
delete mSqliteVFS;

View File

@ -235508,15 +235508,15 @@
"testharness"
],
"workers/semantics/navigation/001-1.html": [
"2f0df288870e99e80de02fe4a09c9cac141d4559",
"4dac7306512b047e8239c7f5c10e6b8ed83b9212",
"support"
],
"workers/semantics/navigation/001.html": [
"4a744751f35cbc67ec87ea76e22947a5f66959e9",
"fd9870c19b051c1580b4b7b366ea5ce71541b5dc",
"testharness"
],
"workers/semantics/navigation/002.html": [
"e28d7129aa2aa8fabe3641bea8f60ecd70335fa9",
"bc96fc2e64a3ffe6a71c314d7a65ed9a89cf440f",
"testharness"
],
"workers/semantics/reporting-errors/001.html": [

View File

@ -16,7 +16,7 @@ onload = function() {
}
}
</script>
<a href='data:text/html,<title>foo</title><script>onload=function(){parent.after_load()}</script>'>link</a>
<a href='data:text/html,<title>foo</title><script>onload=function(){window.parent.postMessage({title: window.document.title}, "*")}</script>'>link</a>
<!--
*/
//-->

View File

@ -20,15 +20,17 @@ onload = function() {
var start_test = function() {
window[0].document.links[0].click();
};
var after_load = function() {
var after_load = function(event) {
history.back();
newDate = new Date();
setTimeout(function() {
assert_greater_than(Number(date), Number(newDate));
assert_equals(window[0].document.title, '001-1');
window.removeEventListener("message", after_load);
done();
}, 2000);
};
window.addEventListener("message", after_load);
</script>
<!--
*/

View File

@ -21,14 +21,16 @@ onload = t.step_func(function() {
var start_test = t.step_func(function() {
window[0].document.links[0].click();
});
var after_load = t.step_func(function() {
var after_load = t.step_func(function(event) {
newDate = new Date();
setTimeout(this.step_func(function() {
assert_less_than(Number(date), Number(newDate));
assert_equals(window[0].document.title, 'foo');
assert_equals(event.data.title, 'foo');
window.removeEventListener("message", after_load);
this.done();
}), 500);
});
window.addEventListener("message", after_load);
</script>
<!--
*/

View File

@ -10071,6 +10071,7 @@
"description": "The amount of time spent in a specific performance tool view, keyed by view name (waterfall, js-calltree, js-flamegraph, etc)."
},
"DEVTOOLS_JAVASCRIPT_ERROR_DISPLAYED": {
"alert_emails": ["nicolas.b.pierron@mozilla.com"],
"record_in_processes": ["main", "content"],
"bug_numbers": [1255133, 1378449],
"expires_in_version": "never",

View File

@ -148,6 +148,7 @@ label.findbar-find-fast:-moz-lwtheme,
.findbar-textbox:-moz-locale-dir(rtl) {
border-radius: 0 10000px 10000px 0;
background-position-x: calc(100% - 5px);
}
@media (-moz-mac-yosemite-theme) {