diff --git a/dom/ipc/ContentProcess.cpp b/dom/ipc/ContentProcess.cpp index ae4bb3f06a..4a4697e2c0 100644 --- a/dom/ipc/ContentProcess.cpp +++ b/dom/ipc/ContentProcess.cpp @@ -12,8 +12,13 @@ #include "mozilla/WindowsVersion.h" #endif +#if defined(XP_MACOSX) && defined(MOZ_CONTENT_SANDBOX) +#include +#endif + #if (defined(XP_WIN) || defined(XP_MACOSX)) && defined(MOZ_CONTENT_SANDBOX) #include "mozilla/Preferences.h" +#include "nsAppDirectoryServiceDefs.h" #include "nsDirectoryService.h" #include "nsDirectoryServiceDefs.h" #endif @@ -33,12 +38,21 @@ IsSandboxTempDirRequired() (Preferences::GetInt("security.sandbox.content.level") >= 1)); } -static const char* -SandboxTempDirParent() +static void +SetTmpEnvironmentVariable(nsIFile* aValue) { - // On Windows, the sandbox-writable temp directory resides in the - // low integrity sandbox base directory. - return NS_WIN_LOW_INTEGRITY_TEMP_BASE; + // Save the TMP environment variable so that is is picked up by GetTempPath(). + // Note that we specifically write to the TMP variable, as that is the first + // variable that is checked by GetTempPath() to determine its output. + nsAutoString fullTmpPath; + nsresult rv = aValue->GetPath(fullTmpPath); + if (NS_WARN_IF(NS_FAILED(rv))) { + return; + } + NS_WARN_IF(!SetEnvironmentVariableW(L"TMP", fullTmpPath.get())); + // We also set TEMP in case there is naughty third-party code that is + // referencing the environment variable directly. + NS_WARN_IF(!SetEnvironmentVariableW(L"TEMP", fullTmpPath.get())); } #endif @@ -50,10 +64,15 @@ IsSandboxTempDirRequired() return (Preferences::GetInt("security.sandbox.content.level") >= 1); } -static const char* -SandboxTempDirParent() +static void +SetTmpEnvironmentVariable(nsIFile* aValue) { - return NS_OS_TEMP_DIR; + nsAutoCString fullTmpPath; + nsresult rv = aValue->GetNativePath(fullTmpPath); + if (NS_WARN_IF(NS_FAILED(rv))) { + return; + } + NS_WARN_IF(setenv("TMPDIR", fullTmpPath.get(), 1) != 0); } #endif @@ -68,24 +87,11 @@ SetUpSandboxEnvironment() return; } - nsAdoptingString tempDirSuffix = - Preferences::GetString("security.sandbox.content.tempDirSuffix"); - if (tempDirSuffix.IsEmpty()) { - NS_WARNING("Sandbox-writable temp directory suffix pref not set."); - return; - } - - // Get the parent of our sandbox writable temp directory. - nsCOMPtr lowIntegrityTemp; - nsresult rv = nsDirectoryService::gService->Get(SandboxTempDirParent(), - NS_GET_IID(nsIFile), - getter_AddRefs(lowIntegrityTemp)); - if (NS_WARN_IF(NS_FAILED(rv))) { - return; - } - - // Append our profile specific temp name. - rv = lowIntegrityTemp->Append(NS_LITERAL_STRING("Temp-") + tempDirSuffix); + nsCOMPtr sandboxedContentTemp; + nsresult rv = + nsDirectoryService::gService->Get(NS_APP_CONTENT_PROCESS_TEMP_DIR, + NS_GET_IID(nsIFile), + getter_AddRefs(sandboxedContentTemp)); if (NS_WARN_IF(NS_FAILED(rv))) { return; } @@ -93,10 +99,12 @@ SetUpSandboxEnvironment() // Change the gecko defined temp directory to our sandbox-writable one. // Undefine returns a failure if the property is not already set. Unused << nsDirectoryService::gService->Undefine(NS_OS_TEMP_DIR); - rv = nsDirectoryService::gService->Set(NS_OS_TEMP_DIR, lowIntegrityTemp); + rv = nsDirectoryService::gService->Set(NS_OS_TEMP_DIR, sandboxedContentTemp); if (NS_WARN_IF(NS_FAILED(rv))) { return; } + + SetTmpEnvironmentVariable(sandboxedContentTemp); } #endif diff --git a/dom/media/AudioConverter.cpp b/dom/media/AudioConverter.cpp index 5275d02d03..b8456359d4 100644 --- a/dom/media/AudioConverter.cpp +++ b/dom/media/AudioConverter.cpp @@ -6,6 +6,7 @@ #include "AudioConverter.h" #include +#include /* * Parts derived from MythTV AudioConvert Class @@ -20,9 +21,9 @@ namespace mozilla { AudioConverter::AudioConverter(const AudioConfig& aIn, const AudioConfig& aOut) : mIn(aIn) , mOut(aOut) + , mResampler(nullptr) { - MOZ_DIAGNOSTIC_ASSERT(aIn.Rate() == aOut.Rate() && - aIn.Format() == aOut.Format() && + MOZ_DIAGNOSTIC_ASSERT(aIn.Format() == aOut.Format() && aIn.Interleaved() == aOut.Interleaved(), "No format or rate conversion is supported at this stage"); MOZ_DIAGNOSTIC_ASSERT((aIn.Channels() > aOut.Channels() && aOut.Channels() <= 2) || @@ -30,26 +31,57 @@ AudioConverter::AudioConverter(const AudioConfig& aIn, const AudioConfig& aOut) "Only downmixing to mono or stereo is supported at this stage"); MOZ_DIAGNOSTIC_ASSERT(aOut.Interleaved(), "planar audio format not supported"); mIn.Layout().MappingTable(mOut.Layout(), mChannelOrderMap); + if (aIn.Rate() != aOut.Rate()) { + int error; + mResampler = speex_resampler_init(aOut.Channels(), + aIn.Rate(), + aOut.Rate(), + SPEEX_RESAMPLER_QUALITY_DEFAULT, + &error); + + if (error == RESAMPLER_ERR_SUCCESS) { + speex_resampler_skip_zeros(mResampler); + } else { + NS_WARNING("Failed to initialize resampler."); + mResampler = nullptr; + } + } +} + +AudioConverter::~AudioConverter() +{ + if (mResampler) { + speex_resampler_destroy(mResampler); + mResampler = nullptr; + } } bool AudioConverter::CanWorkInPlace() const { - return mIn.Channels() * mIn.Rate() * AudioConfig::SampleSize(mIn.Format()) >= - mOut.Channels() * mOut.Rate() * AudioConfig::SampleSize(mOut.Format()); + bool needDownmix = mIn.Channels() > mOut.Channels(); + bool canDownmixInPlace = + mIn.Channels() * AudioConfig::SampleSize(mIn.Format()) >= + mOut.Channels() * AudioConfig::SampleSize(mOut.Format()); + bool needResample = mIn.Rate() != mOut.Rate(); + bool canResampleInPlace = mIn.Rate() >= mOut.Rate(); + // We should be able to work in place if 1s of audio input takes less space + // than 1s of audio output. However, as we downmix before resampling we can't + // perform any upsampling in place (e.g. if incoming rate >= outgoing rate) + return (!needDownmix || canDownmixInPlace) && + (!needResample || canResampleInPlace); } size_t -AudioConverter::Process(void* aOut, const void* aIn, size_t aBytes) +AudioConverter::ProcessInternal(void* aOut, const void* aIn, size_t aBytes) { - if (!CanWorkInPlace()) { - return 0; - } if (mIn.Channels() > mOut.Channels()) { return DownmixAudio(aOut, aIn, aBytes); } else if (mIn.Layout() != mOut.Layout() && CanReorderAudio()) { ReOrderInterleavedChannels(aOut, aIn, aBytes); + } else if (aIn != aOut) { + memmove(aOut, aIn, aBytes); } return aBytes; } @@ -223,7 +255,41 @@ AudioConverter::DownmixAudio(void* aOut, const void* aIn, size_t aDataSize) cons MOZ_DIAGNOSTIC_ASSERT(false, "Unsupported data type"); } } - return frames * AudioConfig::SampleSize(mOut.Format()) * mOut.Channels(); + return (size_t)frames * AudioConfig::SampleSize(mOut.Format()) * mOut.Channels(); } -} // namespace mozilla \ No newline at end of file +size_t +AudioConverter::ResampleAudio(void* aOut, const void* aIn, size_t aDataSize) +{ + if (!mResampler) { + return 0; + } + uint32_t frames = + aDataSize / AudioConfig::SampleSize(mOut.Format()) / mOut.Channels(); + uint32_t outframes = ResampleRecipientFrames(frames); + uint32_t inframes = frames; + + if (mOut.Format() == AudioConfig::FORMAT_FLT) { + const float* in = reinterpret_cast(aIn); + float* out = reinterpret_cast(aOut); + speex_resampler_process_interleaved_float(mResampler, in, &inframes, + out, &outframes); + } else if (mOut.Format() == AudioConfig::FORMAT_S16) { + const int16_t* in = reinterpret_cast(aIn); + int16_t* out = reinterpret_cast(aOut); + speex_resampler_process_interleaved_int(mResampler, in, &inframes, + out, &outframes); + } else { + MOZ_DIAGNOSTIC_ASSERT(false, "Unsupported data type"); + } + MOZ_ASSERT(inframes == frames, "Some frames will be dropped"); + return (size_t)outframes * AudioConfig::SampleSize(mOut.Format()) * mOut.Channels(); +} + +size_t +AudioConverter::ResampleRecipientFrames(size_t aFrames) const +{ + return (uint64_t)aFrames * mOut.Rate() / mIn.Rate() + 1; +} + +} // namespace mozilla diff --git a/dom/media/AudioConverter.h b/dom/media/AudioConverter.h index 384da54552..3b351bb16a 100644 --- a/dom/media/AudioConverter.h +++ b/dom/media/AudioConverter.h @@ -9,6 +9,9 @@ #include "MediaInfo.h" +// Forward declaration +typedef struct SpeexResamplerState_ SpeexResamplerState; + namespace mozilla { template struct AudioDataBufferTypeChooser; @@ -115,23 +118,77 @@ typedef AudioDataBuffer AudioSampleBuffer; class AudioConverter { public: AudioConverter(const AudioConfig& aIn, const AudioConfig& aOut); + ~AudioConverter(); + + // Convert the AudioDataBuffer. + // Conversion will be done in place if possible. Otherwise a new buffer will + // be returned. + template + AudioDataBuffer Process(AudioDataBuffer&& aBuffer) + { + MOZ_DIAGNOSTIC_ASSERT(mIn.Format() == mOut.Format() && mIn.Format() == Format); + AudioDataBuffer buffer = Move(aBuffer); + if (CanWorkInPlace()) { + size_t bytes = ProcessInternal(buffer.Data(), buffer.Data(), buffer.Size()); + if (bytes && mIn.Rate() != mOut.Rate()) { + bytes = ResampleAudio(buffer.Data(), buffer.Data(), bytes); + } + AlignedBuffer temp = buffer.Forget(); + temp.SetLength(bytes / AudioConfig::SampleSize(mOut.Format())); + return AudioDataBuffer(Move(temp));; + } + return Process(buffer); + } + + template + AudioDataBuffer Process(const AudioDataBuffer& aBuffer) + { + MOZ_DIAGNOSTIC_ASSERT(mIn.Format() == mOut.Format() && mIn.Format() == Format); + // Perform the downmixing / reordering in temporary buffer. + uint32_t frames = aBuffer.Length() / mIn.Channels(); + AlignedBuffer temp1; + if (!temp1.SetLength(frames * mOut.Channels())) { + return AudioDataBuffer(Move(temp1)); + } + size_t bytes = ProcessInternal(temp1.Data(), aBuffer.Data(), aBuffer.Size()); + if (!bytes || mIn.Rate() == mOut.Rate()) { + temp1.SetLength(bytes / AudioConfig::SampleSize(mOut.Format())); + return AudioDataBuffer(Move(temp1)); + } + + // At this point, temp1 contains the buffer reordered and downmixed. + // If we are downsampling we can re-use it. + AlignedBuffer* outputBuffer = &temp1; + AlignedBuffer temp2; + if (mOut.Rate() > mIn.Rate()) { + // We are upsampling, we can't work in place. Allocate another temporary + // buffer where the upsampling will occur. + temp2.SetLength(ResampleRecipientFrames(frames) * mOut.Channels()); + outputBuffer = &temp2; + } + bytes = ResampleAudio(outputBuffer->Data(), temp1.Data(), bytes); + outputBuffer->SetLength(bytes / AudioConfig::SampleSize(mOut.Format())); + return AudioDataBuffer(Move(*outputBuffer)); + } // Attempt to convert the AudioDataBuffer in place. // Will return 0 if the conversion wasn't possible. - // Process may allocate memory internally should intermediary steps be - // required. - template - size_t Process(AudioDataBuffer& aBuffer) - { - MOZ_DIAGNOSTIC_ASSERT(mIn.Format() == mOut.Format() && mIn.Format() == Type); - return Process(aBuffer.Data(), aBuffer.Data(), aBuffer.Size()); - } template size_t Process(Value* aBuffer, size_t aSamples) { MOZ_DIAGNOSTIC_ASSERT(mIn.Format() == mOut.Format()); - return Process(aBuffer, aBuffer, aSamples * AudioConfig::SampleSize(mIn.Format())); + if (!CanWorkInPlace()) { + return 0; + } + size_t bytes = + ProcessInternal(aBuffer, aBuffer, + aSamples * AudioConfig::SampleSize(mIn.Format())); + if (bytes && mIn.Rate() != mOut.Rate()) { + bytes = ResampleAudio(aBuffer, aBuffer, bytes); + } + return bytes; } + bool CanWorkInPlace() const; bool CanReorderAudio() const { @@ -146,7 +203,7 @@ private: const AudioConfig mOut; uint8_t mChannelOrderMap[MAX_AUDIO_CHANNELS]; /** - * Process + * ProcessInternal * Parameters: * aOut : destination buffer where converted samples will be copied * aIn : source buffer @@ -154,9 +211,14 @@ private: * * Return Value: size in bytes of samples converted or 0 if error */ - size_t Process(void* aOut, const void* aIn, size_t aBytes); + size_t ProcessInternal(void* aOut, const void* aIn, size_t aBytes); void ReOrderInterleavedChannels(void* aOut, const void* aIn, size_t aDataSize) const; size_t DownmixAudio(void* aOut, const void* aIn, size_t aDataSize) const; + + // Resampler context. + SpeexResamplerState* mResampler; + size_t ResampleAudio(void* aOut, const void* aIn, size_t aDataSize); + size_t ResampleRecipientFrames(size_t aFrames) const; }; } // namespace mozilla diff --git a/dom/media/platforms/MediaTelemetryConstants.h b/dom/media/platforms/MediaTelemetryConstants.h new file mode 100644 index 0000000000..5024949a8e --- /dev/null +++ b/dom/media/platforms/MediaTelemetryConstants.h @@ -0,0 +1,22 @@ +/* -*- Mode: IDL; 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/. */ +#ifndef dom_media_platforms_MediaTelemetryConstants_h___ +#define dom_media_platforms_MediaTelemetryConstants_h___ + +namespace mozilla { +namespace media { + +enum class MediaDecoderBackend : uint32_t +{ + WMFSoftware = 0, + WMFDXVA2D3D9 = 1, + WMFDXVA2D3D11 = 2 +}; + +} // namespace media +} // namespace mozilla + +#endif // dom_media_platforms_MediaTelemetryConstants_h___ diff --git a/dom/media/platforms/agnostic/VorbisDecoder.cpp b/dom/media/platforms/agnostic/VorbisDecoder.cpp index 1d22c3e20a..b8883d5614 100644 --- a/dom/media/platforms/agnostic/VorbisDecoder.cpp +++ b/dom/media/platforms/agnostic/VorbisDecoder.cpp @@ -227,7 +227,7 @@ VorbisDataDecoder::DoDecode(MediaRawData* aSample) } MOZ_ASSERT(mAudioConverter->CanWorkInPlace()); AudioSampleBuffer data(Move(buffer)); - mAudioConverter->Process(data); + data = mAudioConverter->Process(Move(data)); aTotalFrames += frames; mCallback->Output(new AudioData(aOffset, diff --git a/dom/media/platforms/apple/AppleATDecoder.cpp b/dom/media/platforms/apple/AppleATDecoder.cpp index 77f241edd4..29612167ae 100644 --- a/dom/media/platforms/apple/AppleATDecoder.cpp +++ b/dom/media/platforms/apple/AppleATDecoder.cpp @@ -287,7 +287,7 @@ AppleATDecoder::DecodeSample(MediaRawData* aSample) } if (mAudioConverter) { MOZ_ASSERT(mAudioConverter->CanWorkInPlace()); - mAudioConverter->Process(data); + data = mAudioConverter->Process(Move(data)); } RefPtr audio = new AudioData(aSample->mOffset, diff --git a/dom/media/platforms/moz.build b/dom/media/platforms/moz.build index bed528b9be..dfdcedc639 100644 --- a/dom/media/platforms/moz.build +++ b/dom/media/platforms/moz.build @@ -9,6 +9,7 @@ EXPORTS += [ 'agnostic/OpusDecoder.h', 'agnostic/VorbisDecoder.h', 'agnostic/VPXDecoder.h', + 'MediaTelemetryConstants.h', 'PDMFactory.h', 'PlatformDecoderModule.h', 'wrappers/FuzzingWrapper.h', @@ -73,7 +74,7 @@ if CONFIG['MOZ_APPLEMEDIA']: '-framework AudioToolbox', ] -if CONFIG['MOZ_FMP4'] and CONFIG['ANDROID_VERSION'] >= '18'and CONFIG['MOZ_WIDGET_TOOLKIT'] == 'gonk': +if CONFIG['MOZ_GONK_MEDIACODEC']: DEFINES['MOZ_GONK_MEDIACODEC'] = True DIRS += ['gonk'] diff --git a/dom/media/platforms/wmf/DXVA2Manager.cpp b/dom/media/platforms/wmf/DXVA2Manager.cpp index 2244d6a8f6..e500a00a6e 100644 --- a/dom/media/platforms/wmf/DXVA2Manager.cpp +++ b/dom/media/platforms/wmf/DXVA2Manager.cpp @@ -13,6 +13,8 @@ #include "mozilla/layers/D3D11ShareHandleImage.h" #include "mozilla/layers/ImageBridgeChild.h" #include "mozilla/Preferences.h" +#include "mozilla/Telemetry.h" +#include "MediaTelemetryConstants.h" #include "mfapi.h" #include "MFTDecoder.h" #include "DriverCrashGuard.h" diff --git a/dom/media/platforms/wmf/WMFVideoMFTManager.cpp b/dom/media/platforms/wmf/WMFVideoMFTManager.cpp index 0a60276d26..be7cf4cc4f 100644 --- a/dom/media/platforms/wmf/WMFVideoMFTManager.cpp +++ b/dom/media/platforms/wmf/WMFVideoMFTManager.cpp @@ -23,6 +23,7 @@ #include "mozilla/Preferences.h" #include "mozilla/Telemetry.h" #include "nsPrintfCString.h" +#include "MediaTelemetryConstants.h" extern mozilla::LogModule* GetPDMLog(); #define LOG(...) MOZ_LOG(GetPDMLog(), mozilla::LogLevel::Debug, (__VA_ARGS__)) diff --git a/embedding/components/find/nsFind.cpp b/embedding/components/find/nsFind.cpp index 64d74d4602..1337507e1e 100644 --- a/embedding/components/find/nsFind.cpp +++ b/embedding/components/find/nsFind.cpp @@ -1257,4 +1257,3 @@ nsFind::CreateRange(nsINode* aNode) range->SetMaySpanAnonymousSubtrees(true); return range.forget(); } - diff --git a/js/src/jit-test/tests/baseline/bug1238815.js b/js/src/jit-test/tests/baseline/bug1238815.js new file mode 100644 index 0000000000..e64955ee1a --- /dev/null +++ b/js/src/jit-test/tests/baseline/bug1238815.js @@ -0,0 +1,13 @@ +// This program crashes the ARM code generator because the machine code is +// longer than the 32MB range of ARM branch instructions. +// +// Baseline should not attempt to compile the script. + +i = 1; +function test(s) eval("line0 = Error.lineNumber\ndebugger\n" + s); +function repeat(s) { + return Array(65 << 13).join(s) +} +long_expr = repeat(" + i") +long_throw_stmt = long_expr; +test(long_throw_stmt); diff --git a/js/src/jit-test/tests/baseline/long-proto-chains.js b/js/src/jit-test/tests/baseline/long-proto-chains.js new file mode 100644 index 0000000000..ceb387b087 --- /dev/null +++ b/js/src/jit-test/tests/baseline/long-proto-chains.js @@ -0,0 +1,10 @@ +function f() { + var o = {x: 1}; + for (var i = 0; i < 300; i++) + o = Object.create(o); + for (var i = 0; i < 15; i++) { + assertEq(o.x, 1); + assertEq(o.y, undefined); + } +} +f(); diff --git a/js/src/jit-test/tests/ion/bug1247915.js b/js/src/jit-test/tests/ion/bug1247915.js new file mode 100644 index 0000000000..e66faf559b --- /dev/null +++ b/js/src/jit-test/tests/ion/bug1247915.js @@ -0,0 +1,7 @@ +// |jit-test| --ion-pgo=on + +evaluate(` + var i = 0; + while (!inIon()) + a = [] ? i: () => 5; +`); diff --git a/js/src/jit-test/tests/ion/osr-with-optimized-out.js b/js/src/jit-test/tests/ion/osr-with-optimized-out.js new file mode 100644 index 0000000000..5f4ae86e36 --- /dev/null +++ b/js/src/jit-test/tests/ion/osr-with-optimized-out.js @@ -0,0 +1,22 @@ +// |jit-test| --ion-offthread-compile=off; + +// We disable any off-main thread compilation, and set a definite trigger for +// Ion compilation, such that we can garantee that we would OSR into the inner +// loop before we reach the end of the loop. +setJitCompilerOption("ion.warmup.trigger", 30); + +function f (n) { + while (!inIon()) { + var inner = 0; + let x = {}; + for (var i = 0; i < n; i++) { + inner += inIon() == true ? 1 : 0; + if (inner <= 1) + bailout(); + } + assertEq(inner != 1, true); + } +} + +// Iterate enough to ensure that we OSR in this inner loop. +f(300); diff --git a/js/src/jit-test/tests/ion/pgo-bug1259476.js b/js/src/jit-test/tests/ion/pgo-bug1259476.js new file mode 100644 index 0000000000..2a6bc66d1c --- /dev/null +++ b/js/src/jit-test/tests/ion/pgo-bug1259476.js @@ -0,0 +1,16 @@ +// |jit-test| --ion-pgo=on; + +try { + x = evalcx(''); + x.__proto__ = 0; +} catch (e) {} +(function() { + for (var i = 0; i < 1; ++i) { + if (i % 5 == 0) { + for (let z of[0, 0, new Boolean(false), new Boolean(false), + new Boolean(false), new Boolean(false)]) { + this.x; + } + } + } +})() diff --git a/js/src/jit-test/tests/ion/recover-bug1236114.js b/js/src/jit-test/tests/ion/recover-bug1236114.js new file mode 100644 index 0000000000..0956a3ee8a --- /dev/null +++ b/js/src/jit-test/tests/ion/recover-bug1236114.js @@ -0,0 +1,5 @@ +function f(x) { + return (!(Math.round(Math.hypot(Number.MIN_VALUE, Math.fround(x))) | 0) | 0) !== (Math.atanh(x) ? false : Math.tan(0)) +} +f(Number.MIN_VALUE) +assertEq(f(4294967295), true) diff --git a/js/src/jit-test/tests/profiler/bug1233921.js b/js/src/jit-test/tests/profiler/bug1233921.js new file mode 100644 index 0000000000..def8b7c7e3 --- /dev/null +++ b/js/src/jit-test/tests/profiler/bug1233921.js @@ -0,0 +1,19 @@ +g = newGlobal(); +g.parent = this; +g.eval("new Debugger(parent).onExceptionUnwind = function () {}"); +enableSPSProfiling(); +try { + enableSingleStepProfiling(); +} catch(e) { + quit(); +} +f(); +f(); +function $ERROR() { + throw Error; +} +function f() { + try { + $ERROR() + } catch (ex) {} +} diff --git a/js/src/jit/BaselineBailouts.cpp b/js/src/jit/BaselineBailouts.cpp index 56aa4e6a40..1cd15b4d94 100644 --- a/js/src/jit/BaselineBailouts.cpp +++ b/js/src/jit/BaselineBailouts.cpp @@ -1090,16 +1090,13 @@ InitFromBailout(JSContext* cx, HandleScript caller, jsbytecode* callerPC, // // Note that we never resume at this pc, it is set for the sake // of frame iterators giving the correct answer. - // - // We also set nativeCodeForPC to nullptr as this address - // won't be used anywhere. jsbytecode* throwPC = script->offsetToPC(iter.pcOffset()); builder.setResumePC(throwPC); - nativeCodeForPC = nullptr; + nativeCodeForPC = baselineScript->nativeCodeForPC(script, throwPC); } else { nativeCodeForPC = baselineScript->nativeCodeForPC(script, pc, &slotInfo); - MOZ_ASSERT(nativeCodeForPC); } + MOZ_ASSERT(nativeCodeForPC); unsigned numUnsynced = slotInfo.numUnsynced(); diff --git a/js/src/jit/BaselineIC.cpp b/js/src/jit/BaselineIC.cpp index 87a117a3d0..43bcc0cd92 100644 --- a/js/src/jit/BaselineIC.cpp +++ b/js/src/jit/BaselineIC.cpp @@ -2962,6 +2962,8 @@ ICSetElemDenseOrUnboxedArrayAddCompiler::generateStubCode(MacroAssembler& masm) // But R0 and R1 still hold their values. EmitStowICValues(masm, 2); + uint32_t framePushedAfterStow = masm.framePushed(); + // We may need to free up some registers. regs = availableGeneralRegs(0); regs.take(R0); @@ -3123,6 +3125,7 @@ ICSetElemDenseOrUnboxedArrayAddCompiler::generateStubCode(MacroAssembler& masm) // Failure case - fail but first unstow R0 and R1 masm.bind(&failureUnstow); + masm.setFramePushed(framePushedAfterStow); EmitUnstowICValues(masm, 2); // Failure case - jump to next stub @@ -4955,8 +4958,6 @@ ICSetProp_Unboxed::Compiler::generateStubCode(MacroAssembler& masm) if (needsUpdateStubs()) { // Stow both R0 and R1 (object and value). - masm.push(object); - masm.push(ICStubReg); EmitStowICValues(masm, 2); // Move RHS into R0 for TypeUpdate check. @@ -4968,8 +4969,9 @@ ICSetProp_Unboxed::Compiler::generateStubCode(MacroAssembler& masm) // Unstow R0 and R1 (object and key) EmitUnstowICValues(masm, 2); - masm.pop(ICStubReg); - masm.pop(object); + + // The TypeUpdate IC may have smashed object. Rederive it. + masm.unboxObject(R0, object); // Trigger post barriers here on the values being written. Fields which // objects can be written to also need update stubs. @@ -5026,8 +5028,6 @@ ICSetProp_TypedObject::Compiler::generateStubCode(MacroAssembler& masm) if (needsUpdateStubs()) { // Stow both R0 and R1 (object and value). - masm.push(object); - masm.push(ICStubReg); EmitStowICValues(masm, 2); // Move RHS into R0 for TypeUpdate check. @@ -5039,8 +5039,9 @@ ICSetProp_TypedObject::Compiler::generateStubCode(MacroAssembler& masm) // Unstow R0 and R1 (object and key) EmitUnstowICValues(masm, 2); - masm.pop(ICStubReg); - masm.pop(object); + + // We may have clobbered object in the TypeUpdate IC. Rederive it. + masm.unboxObject(R0, object); // Trigger post barriers here on the values being written. Descriptors // which can write objects also need update stubs. diff --git a/js/src/jit/BaselineJIT.h b/js/src/jit/BaselineJIT.h index 10927fa2b6..cee7db3dc1 100644 --- a/js/src/jit/BaselineJIT.h +++ b/js/src/jit/BaselineJIT.h @@ -110,7 +110,15 @@ struct DependentWasmModuleImport struct BaselineScript { public: + // Largest script that the baseline compiler will attempt to compile. +#if defined(JS_CODEGEN_ARM) + // ARM branches can only reach 32MB, and the macroassembler doesn't mitigate + // that limitation. Use a stricter limit on the acceptable script size to + // avoid crashing when branches go out of range. + static const uint32_t MAX_JSSCRIPT_LENGTH = 1000000u; +#else static const uint32_t MAX_JSSCRIPT_LENGTH = 0x0fffffffu; +#endif // Limit the locals on a given script so that stack check on baseline frames // doesn't overflow a uint32_t value. diff --git a/js/src/jit/CacheIR.h b/js/src/jit/CacheIR.h index 26396aed7a..d79b949b1f 100644 --- a/js/src/jit/CacheIR.h +++ b/js/src/jit/CacheIR.h @@ -162,8 +162,8 @@ class MOZ_RAII CacheIRWriter } void writeOperandId(OperandId opId) { - MOZ_ASSERT(size_t(opId.id()) <= UINT8_MAX); if (opId.id() < MaxOperandIds) { + static_assert(MaxOperandIds <= UINT8_MAX, "operand id must fit in a single byte"); buffer_.writeByte(opId.id()); } else { tooLarge_ = true; diff --git a/js/src/jit/FixedList.h b/js/src/jit/FixedList.h index b6b37bbebe..04658c7191 100644 --- a/js/src/jit/FixedList.h +++ b/js/src/jit/FixedList.h @@ -32,7 +32,7 @@ class FixedList { } // Dynamic memory allocation requires the ability to report failure. - bool init(TempAllocator& alloc, size_t length) { + MOZ_WARN_UNUSED_RESULT bool init(TempAllocator& alloc, size_t length) { length_ = length; if (length == 0) return true; @@ -57,7 +57,7 @@ class FixedList length_ -= num; } - bool growBy(TempAllocator& alloc, size_t num) { + MOZ_WARN_UNUSED_RESULT bool growBy(TempAllocator& alloc, size_t num) { size_t newlength = length_ + num; if (newlength < length_) return false; diff --git a/js/src/jit/InstructionReordering.cpp b/js/src/jit/InstructionReordering.cpp index 05b4c5234b..cdaa5056e4 100644 --- a/js/src/jit/InstructionReordering.cpp +++ b/js/src/jit/InstructionReordering.cpp @@ -53,6 +53,13 @@ jit::ReorderInstructions(MIRGenerator* mir, MIRGraph& graph) Vector loopHeaders; for (ReversePostorderIterator block(graph.rpoBegin()); block != graph.rpoEnd(); block++) { + // Renumber all definitions inside the basic blocks. + for (MPhiIterator iter(block->phisBegin()); iter != block->phisEnd(); iter++) + iter->setId(nextId++); + + for (MInstructionIterator iter(block->begin()); iter != block->end(); iter++) + iter->setId(nextId++); + // Don't reorder instructions within entry blocks, which have special requirements. if (*block == graph.entryBlock() || *block == graph.osrBlock()) continue; @@ -64,13 +71,9 @@ jit::ReorderInstructions(MIRGenerator* mir, MIRGraph& graph) MBasicBlock* innerLoop = loopHeaders.empty() ? nullptr : loopHeaders.back(); - for (MPhiIterator iter(block->phisBegin()); iter != block->phisEnd(); iter++) - iter->setId(nextId++); - - for (MInstructionIterator iter(block->begin()); iter != block->end(); iter++) - iter->setId(nextId++); - - for (MInstructionIterator iter(block->begin()); iter != block->end(); ) { + MInstruction* top = block->safeInsertTop(); + MInstructionReverseIterator rtop = ++block->rbegin(top); + for (MInstructionIterator iter(block->begin(top)); iter != block->end(); ) { MInstruction* ins = *iter; // Filter out some instructions which are never reordered. @@ -126,7 +129,7 @@ jit::ReorderInstructions(MIRGenerator* mir, MIRGraph& graph) } MInstruction* target = ins; - for (MInstructionReverseIterator riter = ++block->rbegin(ins); riter != block->rend(); riter++) { + for (MInstructionReverseIterator riter = ++block->rbegin(ins); riter != rtop; riter++) { MInstruction* prev = *riter; if (prev->isInterruptCheck()) break; diff --git a/js/src/jit/Ion.cpp b/js/src/jit/Ion.cpp index 96b5832bb2..eedc9e31a7 100644 --- a/js/src/jit/Ion.cpp +++ b/js/src/jit/Ion.cpp @@ -1020,6 +1020,10 @@ IonScript::trace(JSTracer* trc) ICEntry& ent = sharedStubList()[i]; ent.trace(trc); } + + // Trace caches so that the JSScript pointer can be updated if moved. + for (size_t i = 0; i < numCaches(); i++) + getCacheFromIndex(i).trace(trc); } /* static */ void @@ -1508,8 +1512,7 @@ OptimizeMIR(MIRGenerator* mir) { AutoTraceLog log(logger, TraceLogger_RenumberBlocks); - if (!RenumberBlocks(graph)) - return false; + RenumberBlocks(graph); gs.spewPass("Renumber Blocks"); AssertGraphCoherency(graph); @@ -1657,9 +1660,9 @@ OptimizeMIR(MIRGenerator* mir) } } + RangeAnalysis r(mir, graph); if (mir->optimizationInfo().rangeAnalysisEnabled()) { AutoTraceLog log(logger, TraceLogger_RangeAnalysis); - RangeAnalysis r(mir, graph); if (!r.addBetaNodes()) return false; gs.spewPass("Beta"); @@ -1726,6 +1729,28 @@ OptimizeMIR(MIRGenerator* mir) } } + { + AutoTraceLog log(logger, TraceLogger_Sink); + if (!Sink(mir, graph)) + return false; + gs.spewPass("Sink"); + AssertExtendedGraphCoherency(graph); + + if (mir->shouldCancel("Sink")) + return false; + } + + if (mir->optimizationInfo().rangeAnalysisEnabled()) { + AutoTraceLog log(logger, TraceLogger_RemoveUnnecessaryBitops); + if (!r.removeUnnecessaryBitops()) + return false; + gs.spewPass("Remove Unnecessary Bitops"); + AssertExtendedGraphCoherency(graph); + + if (mir->shouldCancel("Remove Unnecessary Bitops")) + return false; + } + if (mir->optimizationInfo().eaaEnabled()) { AutoTraceLog log(logger, TraceLogger_EffectiveAddressAnalysis); EffectiveAddressAnalysis eaa(mir, graph); @@ -1759,17 +1784,6 @@ OptimizeMIR(MIRGenerator* mir) return false; } - { - AutoTraceLog log(logger, TraceLogger_EliminateDeadCode); - if (!Sink(mir, graph)) - return false; - gs.spewPass("Sink"); - AssertExtendedGraphCoherency(graph); - - if (mir->shouldCancel("Sink")) - return false; - } - if (mir->optimizationInfo().instructionReorderingEnabled()) { AutoTraceLog log(logger, TraceLogger_ReorderInstructions); if (!ReorderInstructions(mir, graph)) diff --git a/js/src/jit/IonAnalysis.cpp b/js/src/jit/IonAnalysis.cpp index 1430c32e67..b2c1d17bd7 100644 --- a/js/src/jit/IonAnalysis.cpp +++ b/js/src/jit/IonAnalysis.cpp @@ -120,6 +120,12 @@ FlagPhiInputsAsHavingRemovedUses(MBasicBlock* block, MBasicBlock* succ, MPhiVect bool isUsed = false; for (size_t idx = 0; !isUsed && idx < worklist.length(); idx++) { phi = worklist[idx]; + if (phi->isUseRemoved() || phi->isImplicitlyUsed()) { + // The phi is implicitly used. + isUsed = true; + break; + } + MUseIterator usesEnd(phi->usesEnd()); for (MUseIterator use(phi->usesBegin()); use != usesEnd; use++) { MNode* consumer = (*use)->consumer(); @@ -144,12 +150,6 @@ FlagPhiInputsAsHavingRemovedUses(MBasicBlock* block, MBasicBlock* succ, MPhiVect if (phi->isInWorklist()) continue; - if (phi->isUseRemoved() || phi->isImplicitlyUsed()) { - // The phi is implicitly used. - isUsed = true; - break; - } - phi->setInWorklist(); if (!worklist.append(phi)) return false; @@ -421,27 +421,11 @@ SplitCriticalEdgesForBlock(MIRGraph& graph, MBasicBlock* block) if (target->numPredecessors() < 2) continue; - // Create a new block inheriting from the predecessor. - MBasicBlock* split = MBasicBlock::NewSplitEdge(graph, block->info(), block); + // Create a simple new block which contains a goto and which split the + // edge between block and target. + MBasicBlock* split = MBasicBlock::NewSplitEdge(graph, block->info(), block, i, target); if (!split) return false; - split->setLoopDepth(block->loopDepth()); - graph.insertBlockAfter(block, split); - split->end(MGoto::New(graph.alloc(), target)); - - // The entry resume point won't properly reflect state at the start of - // the split edge, so remove it. Split edges start out empty, but might - // have fallible code moved into them later. Rather than immediately - // figure out a valid resume point and pc we can use for the split edge, - // we wait until lowering (see LIRGenerator::visitBlock), where this - // will be easier. - if (MResumePoint* rp = split->entryResumePoint()) { - rp->releaseUses(); - split->clearEntryResumePoint(); - } - - block->replaceSuccessor(i, split); - target->replacePredecessor(block, split); } return true; } @@ -950,7 +934,9 @@ jit::EliminateDeadResumePointOperands(MIRGenerator* mir, MIRGraph& graph) bool js::jit::DeadIfUnused(const MDefinition* def) { - return !def->isEffectful() && !def->isGuard() && !def->isGuardRangeBailouts() && + return !def->isEffectful() && + (!def->isGuard() || def->block() == def->block()->graph().osrBlock()) && + !def->isGuardRangeBailouts() && !def->isControlInstruction() && (!def->isInstruction() || !def->toInstruction()->resumePoint()); } @@ -1483,17 +1469,20 @@ TypeAnalyzer::adjustPhiInputs(MPhi* phi) if (in->type() == MIRType_Value) continue; - if (in->isUnbox() && phi->typeIncludes(in->toUnbox()->input())) { - // The input is being explicitly unboxed, so sneak past and grab - // the original box. - phi->replaceOperand(i, in->toUnbox()->input()); - } else { + // The input is being explicitly unboxed, so sneak past and grab + // the original box. + if (in->isUnbox() && phi->typeIncludes(in->toUnbox()->input())) + in = in->toUnbox()->input(); + + if (in->type() != MIRType_Value) { if (!alloc().ensureBallast()) return false; - MDefinition* box = AlwaysBoxAt(alloc(), in->block()->lastIns(), in); - phi->replaceOperand(i, box); + MBasicBlock* pred = phi->block()->getPredecessor(i); + in = AlwaysBoxAt(alloc(), pred->lastIns(), in); } + + phi->replaceOperand(i, in); } return true; @@ -1848,6 +1837,9 @@ jit::MakeMRegExpHoistable(MIRGraph& graph) for (ReversePostorderIterator block(graph.rpoBegin()); block != graph.rpoEnd(); block++) { for (MDefinitionIterator iter(*block); iter; iter++) { + if (!*iter) + MOZ_CRASH("confirm bug 1263794."); + if (!iter->isRegExp()) continue; @@ -1896,14 +1888,12 @@ jit::MakeMRegExpHoistable(MIRGraph& graph) return true; } -bool +void jit::RenumberBlocks(MIRGraph& graph) { size_t id = 0; for (ReversePostorderIterator block(graph.rpoBegin()); block != graph.rpoEnd(); block++) block->setId(id++); - - return true; } // A utility for code which deletes blocks. Renumber the remaining blocks, @@ -2285,6 +2275,32 @@ CheckUse(const MDefinition* producer, const MUse* use, int32_t* usesBalance) #endif ++*usesBalance; } + +// To properly encode entry resume points, we have to ensure that all the +// operands of the entry resume point are located before the safeInsertTop +// location. +static void +AssertOperandsBeforeSafeInsertTop(MResumePoint* resume) +{ + MBasicBlock* block = resume->block(); + if (block == block->graph().osrBlock()) + return; + MInstruction* stop = block->safeInsertTop(); + for (size_t i = 0, e = resume->numOperands(); i < e; ++i) { + MDefinition* def = resume->getOperand(i); + if (def->block() != block) + continue; + if (def->isPhi()) + continue; + + for (MInstructionIterator ins = block->begin(); true; ins++) { + if (*ins == def) + break; + MOZ_ASSERT(*ins != stop, + "Resume point operand located after the safeInsertTop location"); + } + } +} #endif // DEBUG void @@ -2322,13 +2338,14 @@ jit::AssertBasicGraphCoherency(MIRGraph& graph) for (size_t i = 0; i < block->numPredecessors(); i++) MOZ_ASSERT(CheckPredecessorImpliesSuccessor(*block, block->getPredecessor(i))); - if (block->entryResumePoint()) { - MOZ_ASSERT(!block->entryResumePoint()->instruction()); - MOZ_ASSERT(block->entryResumePoint()->block() == *block); + if (MResumePoint* resume = block->entryResumePoint()) { + MOZ_ASSERT(!resume->instruction()); + MOZ_ASSERT(resume->block() == *block); + AssertOperandsBeforeSafeInsertTop(resume); } - if (block->outerResumePoint()) { - MOZ_ASSERT(!block->outerResumePoint()->instruction()); - MOZ_ASSERT(block->outerResumePoint()->block() == *block); + if (MResumePoint* resume = block->outerResumePoint()) { + MOZ_ASSERT(!resume->instruction()); + MOZ_ASSERT(resume->block() == *block); } for (MResumePointIterator iter(block->resumePointsBegin()); iter != block->resumePointsEnd(); iter++) { // We cannot yet assert that is there is no instruction then this is @@ -2834,6 +2851,9 @@ TryEliminateBoundsCheck(BoundsCheckMap& checks, size_t blockIndex, MBoundsCheck* if (!dominated->isMovable()) return true; + if (!dominated->fallible()) + return true; + MBoundsCheck* dominating = FindDominatingBoundsCheck(checks, dominated, blockIndex); if (!dominating) return false; @@ -3755,19 +3775,22 @@ jit::AnalyzeNewScriptDefiniteProperties(JSContext* cx, JSFunction* fun, FinishDefinitePropertiesAnalysis(cx, constraints); - if (!SplitCriticalEdges(graph)) + if (!SplitCriticalEdges(graph)) { + ReportOutOfMemory(cx); return false; + } - if (!RenumberBlocks(graph)) - return false; + RenumberBlocks(graph); if (!BuildDominatorTree(graph)) { ReportOutOfMemory(cx); return false; } - if (!EliminatePhis(&builder, graph, AggressiveObservability)) + if (!EliminatePhis(&builder, graph, AggressiveObservability)) { + ReportOutOfMemory(cx); return false; + } MDefinition* thisValue = graph.entryBlock()->getSlot(info.thisSlot()); @@ -3976,19 +3999,22 @@ jit::AnalyzeArgumentsUsage(JSContext* cx, JSScript* scriptArg) return true; } - if (!SplitCriticalEdges(graph)) + if (!SplitCriticalEdges(graph)) { + ReportOutOfMemory(cx); return false; + } - if (!RenumberBlocks(graph)) - return false; + RenumberBlocks(graph); if (!BuildDominatorTree(graph)) { ReportOutOfMemory(cx); return false; } - if (!EliminatePhis(&builder, graph, AggressiveObservability)) + if (!EliminatePhis(&builder, graph, AggressiveObservability)) { + ReportOutOfMemory(cx); return false; + } MDefinition* argumentsValue = graph.entryBlock()->getSlot(info.argsObjSlot()); diff --git a/js/src/jit/IonAnalysis.h b/js/src/jit/IonAnalysis.h index 652a1ec473..df06a31f0b 100644 --- a/js/src/jit/IonAnalysis.h +++ b/js/src/jit/IonAnalysis.h @@ -56,7 +56,7 @@ ApplyTypeInformation(MIRGenerator* mir, MIRGraph& graph); bool MakeMRegExpHoistable(MIRGraph& graph); -bool +void RenumberBlocks(MIRGraph& graph); bool diff --git a/js/src/jit/IonBuilder.cpp b/js/src/jit/IonBuilder.cpp index c3ddf6b203..e50d65976e 100644 --- a/js/src/jit/IonBuilder.cpp +++ b/js/src/jit/IonBuilder.cpp @@ -5932,7 +5932,8 @@ IonBuilder::inlineCalls(CallInfo& callInfo, const ObjectVector& targets, BoolVec returnBlock->push(retPhi); // Create a resume point from current stack state. - returnBlock->initEntrySlots(alloc()); + if (!returnBlock->initEntrySlots(alloc())) + return false; // Reserve the capacity for the phi. // Note: this is an upperbound. Unreachable targets and uninlineable natives are also counted. diff --git a/js/src/jit/IonCaches.cpp b/js/src/jit/IonCaches.cpp index d24efc63df..3974096f40 100644 --- a/js/src/jit/IonCaches.cpp +++ b/js/src/jit/IonCaches.cpp @@ -383,6 +383,12 @@ IonCache::updateBaseAddress(JitCode* code, MacroAssembler& masm) rejoinLabel_.repoint(code, &masm); } +void IonCache::trace(JSTracer* trc) +{ + if (script_) + TraceManuallyBarrieredEdge(trc, &script_, "IonCache::script_"); +} + static void* GetReturnAddressToIonCode(JSContext* cx) { diff --git a/js/src/jit/IonCaches.h b/js/src/jit/IonCaches.h index b7018aa73d..5eb34a7086 100644 --- a/js/src/jit/IonCaches.h +++ b/js/src/jit/IonCaches.h @@ -341,6 +341,8 @@ class IonCache MOZ_ASSERT(pc_); return pc_; } + + void trace(JSTracer* trc); }; // Define the cache kind and pre-declare data structures used for calling inline diff --git a/js/src/jit/Lowering.cpp b/js/src/jit/Lowering.cpp index a6d86e6228..96c0df38d2 100644 --- a/js/src/jit/Lowering.cpp +++ b/js/src/jit/Lowering.cpp @@ -4718,6 +4718,7 @@ LIRGenerator::updateResumeState(MInstruction* ins) void LIRGenerator::updateResumeState(MBasicBlock* block) { + MOZ_ASSERT_IF(!mir()->compilingAsmJS(), block->entryResumePoint()); lastResumePoint_ = block->entryResumePoint(); if (JitSpewEnabled(JitSpew_IonSnapshots) && lastResumePoint_) SpewResumePoint(block, nullptr, lastResumePoint_); @@ -4762,27 +4763,6 @@ LIRGenerator::visitBlock(MBasicBlock* block) if (!visitInstruction(block->lastIns())) return false; - // If we have a resume point check that all the following blocks have one, - // otherwise reuse the last resume point as the entry resume point of the - // basic block. This is used to handle fallible code which is moved/added - // into split edge blocks, which do not have resume points. See - // SplitCriticalEdgesForBlock. - // - // When folding conditions, we might create split-edge blocks which have - // multiple predecessors, in such case it is invalid to have any instruction - // in these blocks, as these blocks have no associated pc, thus we cannot - // safely bailout from such block. - if (lastResumePoint_) { - for (size_t s = 0; s < block->numSuccessors(); s++) { - MBasicBlock* succ = block->getSuccessor(s); - if (!succ->entryResumePoint() && succ->numPredecessors() == 1) { - MOZ_ASSERT(succ->isSplitEdge()); - MOZ_ASSERT(succ->phisBegin() == succ->phisEnd()); - succ->setEntryResumePoint(lastResumePoint_); - } - } - } - return true; } diff --git a/js/src/jit/MIR.h b/js/src/jit/MIR.h index d2f71f01bc..dd20be4b75 100644 --- a/js/src/jit/MIR.h +++ b/js/src/jit/MIR.h @@ -1221,7 +1221,7 @@ class MVariadicT : public T FixedList operands_; protected: - bool init(TempAllocator& alloc, size_t length) { + MOZ_WARN_UNUSED_RESULT bool init(TempAllocator& alloc, size_t length) { return operands_.init(alloc, length); } void initOperand(size_t index, MDefinition* operand) { @@ -2022,7 +2022,7 @@ class MSimdGeneralShuffle : return new(alloc) MSimdGeneralShuffle(numVectors, numLanes, type); } - bool init(TempAllocator& alloc) { + MOZ_WARN_UNUSED_RESULT bool init(TempAllocator& alloc) { return MVariadicInstruction::init(alloc, numVectors_ + numLanes_); } void setVector(unsigned i, MDefinition* vec) { @@ -2666,7 +2666,7 @@ class MTableSwitch final return successors_.length(); } - bool addSuccessor(MBasicBlock* successor, size_t* index) { + MOZ_WARN_UNUSED_RESULT bool addSuccessor(MBasicBlock* successor, size_t* index) { MOZ_ASSERT(successors_.length() < (size_t)(high_ - low_ + 2)); MOZ_ASSERT(!successors_.empty()); *index = successors_.length(); @@ -2711,14 +2711,14 @@ class MTableSwitch final return high() - low() + 1; } - bool addDefault(MBasicBlock* block, size_t* index = nullptr) { + MOZ_WARN_UNUSED_RESULT bool addDefault(MBasicBlock* block, size_t* index = nullptr) { MOZ_ASSERT(successors_.empty()); if (index) *index = 0; return successors_.append(block); } - bool addCase(size_t successorIndex) { + MOZ_WARN_UNUSED_RESULT bool addCase(size_t successorIndex) { return cases_.append(successorIndex); } @@ -2727,7 +2727,7 @@ class MTableSwitch final return blocks_[i]; } - bool addBlock(MBasicBlock* block) { + MOZ_WARN_UNUSED_RESULT bool addBlock(MBasicBlock* block) { return blocks_.append(block); } @@ -3630,7 +3630,7 @@ class MArrayState explicit MArrayState(MDefinition* arr); - bool init(TempAllocator& alloc, MDefinition* obj, MDefinition* len); + MOZ_WARN_UNUSED_RESULT bool init(TempAllocator& alloc, MDefinition* obj, MDefinition* len); void initElement(uint32_t index, MDefinition* def) { initOperand(index + 2, def); @@ -9123,12 +9123,14 @@ class MBoundsCheck return minimum_; } void setMinimum(int32_t n) { + MOZ_ASSERT(fallible_); minimum_ = n; } int32_t maximum() const { return maximum_; } void setMaximum(int32_t n) { + MOZ_ASSERT(fallible_); maximum_ = n; } MDefinition* foldsTo(TempAllocator& alloc) override; @@ -9138,6 +9140,8 @@ class MBoundsCheck const MBoundsCheck* other = ins->toBoundsCheck(); if (minimum() != other->minimum() || maximum() != other->maximum()) return false; + if (fallible() != other->fallible()) + return false; return congruentIfOperandsEqual(other); } virtual AliasSet getAliasSet() const override { @@ -13346,7 +13350,7 @@ class MResumePoint final : protected: // Initializes operands_ to an empty array of a fixed length. // The array may then be filled in by inherit(). - bool init(TempAllocator& alloc); + MOZ_WARN_UNUSED_RESULT bool init(TempAllocator& alloc); void clearOperand(size_t index) { // FixedList doesn't initialize its elements, so do an unchecked init. diff --git a/js/src/jit/MIRGraph.cpp b/js/src/jit/MIRGraph.cpp index 196a616d29..6fa7784971 100644 --- a/js/src/jit/MIRGraph.cpp +++ b/js/src/jit/MIRGraph.cpp @@ -334,13 +334,76 @@ MBasicBlock::NewPendingLoopHeader(MIRGraph& graph, const CompileInfo& info, } MBasicBlock* -MBasicBlock::NewSplitEdge(MIRGraph& graph, const CompileInfo& info, MBasicBlock* pred) +MBasicBlock::NewSplitEdge(MIRGraph& graph, const CompileInfo& info, MBasicBlock* pred, size_t predEdgeIdx, MBasicBlock* succ) { - return pred->pc() - ? MBasicBlock::New(graph, nullptr, info, pred, - new(graph.alloc()) BytecodeSite(pred->trackedTree(), pred->pc()), - SPLIT_EDGE) - : MBasicBlock::NewAsmJS(graph, info, pred, SPLIT_EDGE); + MBasicBlock* split = nullptr; + if (!pred->pc()) { + // The predecessor does not have a PC, this is an AsmJS compilation. + split = MBasicBlock::NewAsmJS(graph, info, pred, SPLIT_EDGE); + if (!split) + return nullptr; + } else { + // The predecessor has a PC, this is an IonBuilder compilation. + MResumePoint* succEntry = succ->entryResumePoint(); + + BytecodeSite* site = new(graph.alloc()) BytecodeSite(succ->trackedTree(), succEntry->pc()); + split = new(graph.alloc()) MBasicBlock(graph, info, site, SPLIT_EDGE); + + if (!split->init()) + return nullptr; + + // A split edge is used to simplify the graph to avoid having a + // predecessor with multiple successors as well as a successor with + // multiple predecessors. As instructions can be moved in this + // split-edge block, we need to give this block a resume point. To do + // so, we copy the entry resume points of the successor and filter the + // phis to keep inputs from the current edge. + + // Propagate the caller resume point from the inherited block. + split->callerResumePoint_ = succ->callerResumePoint(); + + // Split-edge are created after the interpreter stack emulation. Thus, + // there is no need for creating slots. + split->stackPosition_ = succEntry->stackDepth(); + + // Create a resume point using our initial stack position. + MResumePoint* splitEntry = new(graph.alloc()) MResumePoint(split, succEntry->pc(), + MResumePoint::ResumeAt); + if (!splitEntry->init(graph.alloc())) + return nullptr; + split->entryResumePoint_ = splitEntry; + + // The target entry resume point might have phi operands, keep the + // operands of the phi coming from our edge. + size_t succEdgeIdx = succ->indexForPredecessor(pred); + + for (size_t i = 0, e = splitEntry->numOperands(); i < e; i++) { + MDefinition* def = succEntry->getOperand(i); + // This early in the pipeline, we have no recover instructions in + // any entry resume point. + MOZ_ASSERT_IF(def->block() == succ, def->isPhi()); + if (def->block() == succ) + def = def->toPhi()->getOperand(succEdgeIdx); + + splitEntry->initOperand(i, def); + } + + // This is done in the NewAsmJS, so we cannot keep this line below, + // where the rest of the graph is modified. + if (!split->predecessors_.append(pred)) + return nullptr; + } + + split->setLoopDepth(succ->loopDepth()); + + // Insert the split edge block in-between. + split->end(MGoto::New(graph.alloc(), succ)); + + graph.insertBlockAfter(pred, split); + + pred->replaceSuccessor(predEdgeIdx, split); + succ->replacePredecessor(pred, split); + return split; } MBasicBlock* @@ -849,6 +912,9 @@ MBasicBlock::moveBefore(MInstruction* at, MInstruction* ins) MInstruction* MBasicBlock::safeInsertTop(MDefinition* ins, IgnoreTop ignore) { + MOZ_ASSERT(graph().osrBlock() != this, + "We are not supposed to add any instruction in OSR blocks."); + // Beta nodes and interrupt checks are required to be located at the // beginnings of basic blocks, so we must insert new instructions after any // such instructions. @@ -858,6 +924,7 @@ MBasicBlock::safeInsertTop(MDefinition* ins, IgnoreTop ignore) while (insertIter->isBeta() || insertIter->isInterruptCheck() || insertIter->isConstant() || + insertIter->isParameter() || (!(ignore & IgnoreRecover) && insertIter->isRecoveredOnBailout())) { insertIter++; diff --git a/js/src/jit/MIRGraph.h b/js/src/jit/MIRGraph.h index c43797b85b..16ff92ed5d 100644 --- a/js/src/jit/MIRGraph.h +++ b/js/src/jit/MIRGraph.h @@ -47,11 +47,11 @@ class MBasicBlock : public TempObject, public InlineListNode private: MBasicBlock(MIRGraph& graph, const CompileInfo& info, BytecodeSite* site, Kind kind); - bool init(); + MOZ_WARN_UNUSED_RESULT bool init(); void copySlots(MBasicBlock* from); - bool inherit(TempAllocator& alloc, BytecodeAnalysis* analysis, MBasicBlock* pred, - uint32_t popped, unsigned stackPhiCount = 0); - bool inheritResumePoint(MBasicBlock* pred); + MOZ_WARN_UNUSED_RESULT bool inherit(TempAllocator& alloc, BytecodeAnalysis* analysis, MBasicBlock* pred, + uint32_t popped, unsigned stackPhiCount = 0); + MOZ_WARN_UNUSED_RESULT bool inheritResumePoint(MBasicBlock* pred); void assertUsesAreNotWithin(MUseIterator use, MUseIterator end); // This block cannot be reached by any means. @@ -116,7 +116,9 @@ class MBasicBlock : public TempObject, public InlineListNode static MBasicBlock* NewPendingLoopHeader(MIRGraph& graph, const CompileInfo& info, MBasicBlock* pred, BytecodeSite* site, unsigned loopStateSlots); - static MBasicBlock* NewSplitEdge(MIRGraph& graph, const CompileInfo& info, MBasicBlock* pred); + static MBasicBlock* NewSplitEdge(MIRGraph& graph, const CompileInfo& info, + MBasicBlock* pred, size_t predEdgeIdx, + MBasicBlock* succ); static MBasicBlock* NewAsmJS(MIRGraph& graph, const CompileInfo& info, MBasicBlock* pred, Kind kind); @@ -152,8 +154,8 @@ class MBasicBlock : public TempObject, public InlineListNode MDefinition* argumentsObject(); // Increase the number of slots available - bool increaseSlots(size_t num); - bool ensureHasSlots(size_t num); + MOZ_WARN_UNUSED_RESULT bool increaseSlots(size_t num); + MOZ_WARN_UNUSED_RESULT bool ensureHasSlots(size_t num); // Initializes a slot value; must not be called for normal stack // operations, as it will not create new SSA names for copies. @@ -164,7 +166,7 @@ class MBasicBlock : public TempObject, public InlineListNode // In an OSR block, set all MOsrValues to use the MResumePoint attached to // the MStart. - bool linkOsrValues(MStart* start); + MOZ_WARN_UNUSED_RESULT bool linkOsrValues(MStart* start); // Sets the instruction associated with various slot types. The // instruction must lie at the top of the stack. @@ -218,17 +220,17 @@ class MBasicBlock : public TempObject, public InlineListNode // Adds a predecessor. Every predecessor must have the same exit stack // depth as the entry state to this block. Adding a predecessor // automatically creates phi nodes and rewrites uses as needed. - bool addPredecessor(TempAllocator& alloc, MBasicBlock* pred); - bool addPredecessorPopN(TempAllocator& alloc, MBasicBlock* pred, uint32_t popped); + MOZ_WARN_UNUSED_RESULT bool addPredecessor(TempAllocator& alloc, MBasicBlock* pred); + MOZ_WARN_UNUSED_RESULT bool addPredecessorPopN(TempAllocator& alloc, MBasicBlock* pred, uint32_t popped); // Add a predecessor which won't introduce any new phis to this block. // This may be called after the contents of this block have been built. void addPredecessorSameInputsAs(MBasicBlock* pred, MBasicBlock* existingPred); // Stranger utilities used for inlining. - bool addPredecessorWithoutPhis(MBasicBlock* pred); + MOZ_WARN_UNUSED_RESULT bool addPredecessorWithoutPhis(MBasicBlock* pred); void inheritSlots(MBasicBlock* parent); - bool initEntrySlots(TempAllocator& alloc); + MOZ_WARN_UNUSED_RESULT bool initEntrySlots(TempAllocator& alloc); // Replaces an edge for a given block with a new block. This is // used for critical edge splitting. @@ -253,8 +255,8 @@ class MBasicBlock : public TempObject, public InlineListNode // Sets a back edge. This places phi nodes and rewrites instructions within // the current loop as necessary. If the backedge introduces new types for // phis at the loop header, returns a disabling abort. - AbortReason setBackedge(MBasicBlock* block); - bool setBackedgeAsmJS(MBasicBlock* block); + MOZ_WARN_UNUSED_RESULT AbortReason setBackedge(MBasicBlock* block); + MOZ_WARN_UNUSED_RESULT bool setBackedgeAsmJS(MBasicBlock* block); // Resets a LOOP_HEADER block to a NORMAL block. This is needed when // optimizations remove the backedge. @@ -269,10 +271,10 @@ class MBasicBlock : public TempObject, public InlineListNode void inheritPhis(MBasicBlock* header); // Propagates backedge slots into phis operands of the loop header. - bool inheritPhisFromBackedge(MBasicBlock* backedge, bool* hadTypeChange); + MOZ_WARN_UNUSED_RESULT bool inheritPhisFromBackedge(MBasicBlock* backedge, bool* hadTypeChange); // Compute the types for phis in this block according to their inputs. - bool specializePhis(); + MOZ_WARN_UNUSED_RESULT bool specializePhis(); void insertBefore(MInstruction* at, MInstruction* ins); void insertAfter(MInstruction* at, MInstruction* ins); @@ -771,7 +773,7 @@ class MIRGraph return returnAccumulator_; } - bool addReturn(MBasicBlock* returnBlock) { + MOZ_WARN_UNUSED_RESULT bool addReturn(MBasicBlock* returnBlock) { if (!returnAccumulator_) return true; diff --git a/js/src/jit/RangeAnalysis.cpp b/js/src/jit/RangeAnalysis.cpp index b444699de3..9badc50b89 100644 --- a/js/src/jit/RangeAnalysis.cpp +++ b/js/src/jit/RangeAnalysis.cpp @@ -3048,7 +3048,6 @@ RangeAnalysis::truncate() MOZ_ASSERT(!mir->compilingAsmJS()); Vector worklist; - Vector bitops; for (PostorderIterator block(graph_.poBegin()); block != graph_.poEnd(); block++) { for (MInstructionReverseIterator iter(block->rbegin()); iter != block->rend(); iter++) { @@ -3147,11 +3146,26 @@ RangeAnalysis::truncate() AdjustTruncatedInputs(alloc(), def); } + return true; +} + +bool +RangeAnalysis::removeUnnecessaryBitops() +{ + // Note: This operation change the semantic of the program in a way which + // uniquely works with Int32, Recover Instructions added by the Sink phase + // expects the MIR Graph to still have a valid flow as-if they were double + // operations instead of Int32 operations. Thus, this phase should be + // executed after the Sink phase, and before DCE. + // Fold any unnecessary bitops in the graph, such as (x | 0) on an integer // input. This is done after range analysis rather than during GVN as the // presence of the bitop can change which instructions are truncated. for (size_t i = 0; i < bitops.length(); i++) { MBinaryBitwiseInstruction* ins = bitops[i]; + if (ins->isRecoveredOnBailout()) + continue; + MDefinition* folded = ins->foldUnnecessaryBitop(); if (folded != ins) { ins->replaceAllLiveUsesWith(folded); @@ -3159,9 +3173,11 @@ RangeAnalysis::truncate() } } + bitops.clear(); return true; } + /////////////////////////////////////////////////////////////////////////////// // Collect Range information of operands /////////////////////////////////////////////////////////////////////////////// diff --git a/js/src/jit/RangeAnalysis.h b/js/src/jit/RangeAnalysis.h index 9115498818..301094bb5a 100644 --- a/js/src/jit/RangeAnalysis.h +++ b/js/src/jit/RangeAnalysis.h @@ -95,6 +95,7 @@ class RangeAnalysis protected: MIRGenerator* mir; MIRGraph& graph_; + Vector bitops; TempAllocator& alloc() const; @@ -108,6 +109,7 @@ class RangeAnalysis bool prepareForUCE(bool* shouldRemoveDeadCode); bool tryRemovingGuards(); bool truncate(); + bool removeUnnecessaryBitops(); // Any iteration bounds discovered for loops in the graph. LoopIterationBoundVector loopIterationBounds; diff --git a/js/src/jsapi-tests/testJitDCEinGVN.cpp b/js/src/jsapi-tests/testJitDCEinGVN.cpp index 9d3a949210..3512d0932a 100644 --- a/js/src/jsapi-tests/testJitDCEinGVN.cpp +++ b/js/src/jsapi-tests/testJitDCEinGVN.cpp @@ -91,7 +91,7 @@ BEGIN_TEST(testJitDCEinGVN_phi) thenBlock1->add(c3); y->addInputSlow(c3); thenBlock1->end(MGoto::New(func.alloc, joinBlock)); - joinBlock->addPredecessor(func.alloc, thenBlock1); + MOZ_ALWAYS_TRUE(joinBlock->addPredecessor(func.alloc, thenBlock1)); // } else if (q) { MParameter* q = func.createParameter(); @@ -107,7 +107,7 @@ BEGIN_TEST(testJitDCEinGVN_phi) thenBlock2->add(c4); y->addInputSlow(c4); thenBlock2->end(MGoto::New(func.alloc, joinBlock)); - joinBlock->addPredecessor(func.alloc, thenBlock2); + MOZ_ALWAYS_TRUE(joinBlock->addPredecessor(func.alloc, thenBlock2)); // } else { // x = 1.0 @@ -118,7 +118,7 @@ BEGIN_TEST(testJitDCEinGVN_phi) elseBlock->add(c5); y->addInputSlow(c5); elseBlock->end(MGoto::New(func.alloc, joinBlock)); - joinBlock->addPredecessor(func.alloc, elseBlock); + MOZ_ALWAYS_TRUE(joinBlock->addPredecessor(func.alloc, elseBlock)); // x = phi(1.0, 2.0, 1.0) // y = phi(3.0, 4.0, 5.0) diff --git a/js/src/jsapi-tests/testJitFoldsTo.cpp b/js/src/jsapi-tests/testJitFoldsTo.cpp index 4b5e2c0f1a..cf88919d63 100644 --- a/js/src/jsapi-tests/testJitFoldsTo.cpp +++ b/js/src/jsapi-tests/testJitFoldsTo.cpp @@ -156,7 +156,7 @@ BEGIN_TEST(testJitNotTest) MReturn* ret = MReturn::New(func.alloc, p); exit->end(ret); - exit->addPredecessorWithoutPhis(then); + MOZ_ALWAYS_TRUE(exit->addPredecessorWithoutPhis(then)); if (!func.runGVN()) return false; @@ -195,7 +195,7 @@ BEGIN_TEST(testJitNotNotTest) MReturn* ret = MReturn::New(func.alloc, p); exit->end(ret); - exit->addPredecessorWithoutPhis(then); + MOZ_ALWAYS_TRUE(exit->addPredecessorWithoutPhis(then)); if (!func.runGVN()) return false; diff --git a/js/src/jsapi-tests/testJitGVN.cpp b/js/src/jsapi-tests/testJitGVN.cpp index 5d36f14862..2fd6c8c603 100644 --- a/js/src/jsapi-tests/testJitGVN.cpp +++ b/js/src/jsapi-tests/testJitGVN.cpp @@ -68,10 +68,10 @@ BEGIN_TEST(testJitGVN_FixupOSROnlyLoop) exit->add(u); exit->end(MReturn::New(func.alloc, u)); - innerHeader->addPredecessorWithoutPhis(innerBackedge); - outerHeader->addPredecessorWithoutPhis(outerBackedge); - exit->addPredecessorWithoutPhis(entry); - merge->addPredecessorWithoutPhis(osrEntry); + MOZ_ALWAYS_TRUE(innerHeader->addPredecessorWithoutPhis(innerBackedge)); + MOZ_ALWAYS_TRUE(outerHeader->addPredecessorWithoutPhis(outerBackedge)); + MOZ_ALWAYS_TRUE(exit->addPredecessorWithoutPhis(entry)); + MOZ_ALWAYS_TRUE(merge->addPredecessorWithoutPhis(osrEntry)); outerHeader->setLoopHeader(outerBackedge); innerHeader->setLoopHeader(innerBackedge); @@ -160,11 +160,11 @@ BEGIN_TEST(testJitGVN_FixupOSROnlyLoopNested) exit->add(u); exit->end(MReturn::New(func.alloc, u)); - innerHeader->addPredecessorWithoutPhis(innerBackedge); - middleHeader->addPredecessorWithoutPhis(middleBackedge); - outerHeader->addPredecessorWithoutPhis(outerBackedge); - exit->addPredecessorWithoutPhis(entry); - merge->addPredecessorWithoutPhis(osrEntry); + MOZ_ALWAYS_TRUE(innerHeader->addPredecessorWithoutPhis(innerBackedge)); + MOZ_ALWAYS_TRUE(middleHeader->addPredecessorWithoutPhis(middleBackedge)); + MOZ_ALWAYS_TRUE(outerHeader->addPredecessorWithoutPhis(outerBackedge)); + MOZ_ALWAYS_TRUE(exit->addPredecessorWithoutPhis(entry)); + MOZ_ALWAYS_TRUE(merge->addPredecessorWithoutPhis(osrEntry)); outerHeader->setLoopHeader(outerBackedge); middleHeader->setLoopHeader(middleBackedge); @@ -269,8 +269,8 @@ BEGIN_TEST(testJitGVN_PinnedPhis) exit->add(z7); exit->end(MGoto::New(func.alloc, outerHeader)); - innerHeader->addPredecessorWithoutPhis(innerBackedge); - outerHeader->addPredecessorWithoutPhis(exit); + MOZ_ALWAYS_TRUE(innerHeader->addPredecessorWithoutPhis(innerBackedge)); + MOZ_ALWAYS_TRUE(outerHeader->addPredecessorWithoutPhis(exit)); outerHeader->setLoopHeader(exit); innerHeader->setLoopHeader(innerBackedge); diff --git a/js/src/jsapi-tests/testJitMinimalFunc.h b/js/src/jsapi-tests/testJitMinimalFunc.h index 6d56a7b474..34fc712781 100644 --- a/js/src/jsapi-tests/testJitMinimalFunc.h +++ b/js/src/jsapi-tests/testJitMinimalFunc.h @@ -75,8 +75,7 @@ struct MinimalFunc : MinimalAlloc { if (!SplitCriticalEdges(graph)) return false; - if (!RenumberBlocks(graph)) - return false; + RenumberBlocks(graph); if (!BuildDominatorTree(graph)) return false; if (!BuildPhiReverseMapping(graph)) @@ -93,8 +92,7 @@ struct MinimalFunc : MinimalAlloc { if (!SplitCriticalEdges(graph)) return false; - if (!RenumberBlocks(graph)) - return false; + RenumberBlocks(graph); if (!BuildDominatorTree(graph)) return false; if (!BuildPhiReverseMapping(graph)) diff --git a/js/src/vm/TraceLoggingTypes.h b/js/src/vm/TraceLoggingTypes.h index 87b9abb7fd..05766e833c 100644 --- a/js/src/vm/TraceLoggingTypes.h +++ b/js/src/vm/TraceLoggingTypes.h @@ -52,6 +52,8 @@ _(Sincos) \ _(RangeAnalysis) \ _(LoopUnrolling) \ + _(Sink) \ + _(RemoveUnnecessaryBitops) \ _(EffectiveAddressAnalysis) \ _(AlignmentMaskAnalysis) \ _(EliminateDeadCode) \ diff --git a/netwerk/protocol/http/HttpBaseChannel.cpp b/netwerk/protocol/http/HttpBaseChannel.cpp index a871a463ba..6ebfdac631 100644 --- a/netwerk/protocol/http/HttpBaseChannel.cpp +++ b/netwerk/protocol/http/HttpBaseChannel.cpp @@ -51,6 +51,7 @@ #include "mozilla/Telemetry.h" #include "nsIURL.h" #include "nsIConsoleService.h" +#include "mozilla/BinarySearch.h" #include @@ -2716,6 +2717,56 @@ HttpBaseChannel::ShouldRewriteRedirectToGET(uint32_t httpStatus, return false; } +static +bool IsHeaderBlacklistedForRedirectCopy(nsHttpAtom const& aHeader) +{ + // IMPORTANT: keep this list ASCII-code sorted + static nsHttpAtom const* blackList[] = { + &nsHttp::Accept, + &nsHttp::Accept_Encoding, + &nsHttp::Accept_Language, + &nsHttp::Authentication, + &nsHttp::Authorization, + &nsHttp::Connection, + &nsHttp::Content_Length, + &nsHttp::Cookie, + &nsHttp::Host, + &nsHttp::If, + &nsHttp::If_Match, + &nsHttp::If_Modified_Since, + &nsHttp::If_None_Match, + &nsHttp::If_None_Match_Any, + &nsHttp::If_Range, + &nsHttp::If_Unmodified_Since, + &nsHttp::Proxy_Authenticate, + &nsHttp::Proxy_Authorization, + &nsHttp::Range, + &nsHttp::TE, + &nsHttp::Transfer_Encoding, + &nsHttp::Upgrade, + &nsHttp::User_Agent, + &nsHttp::WWW_Authenticate + }; + + class HttpAtomComparator + { + nsHttpAtom const& mTarget; + public: + explicit HttpAtomComparator(nsHttpAtom const& aTarget) + : mTarget(aTarget) {} + int operator()(nsHttpAtom const* aVal) const { + if (mTarget == *aVal) { + return 0; + } + return strcmp(mTarget._val, aVal->_val); + } + }; + + size_t unused; + return BinarySearchIf(blackList, 0, ArrayLength(blackList), + HttpAtomComparator(aHeader), &unused); +} + nsresult HttpBaseChannel::SetupReplacementChannel(nsIURI *newURI, nsIChannel *newChannel, @@ -2850,6 +2901,9 @@ HttpBaseChannel::SetupReplacementChannel(nsIURI *newURI, } } + // share the scheduling context - see bug 1236650 + httpChannel->SetSchedulingContextID(mSchedulingContextID); + if (httpInternal) { // Convey third party cookie and spdy flags. httpInternal->SetThirdPartyFlags(mThirdPartyFlags); @@ -2950,6 +3004,23 @@ HttpBaseChannel::SetupReplacementChannel(nsIURI *newURI, } } + if (redirectFlags & (nsIChannelEventSink::REDIRECT_INTERNAL | + nsIChannelEventSink::REDIRECT_STS_UPGRADE)) { + // Copy non-origin related headers to the new channel. + nsHttpHeaderArray& requestHeaders = mRequestHead.Headers(); + uint32_t requestHeaderCount = requestHeaders.Count(); + for (uint32_t i = 0; i < requestHeaderCount; ++i) { + nsHttpAtom header; + const char *val = requestHeaders.PeekHeaderAt(i, header); + if (!val || IsHeaderBlacklistedForRedirectCopy(header)) { + continue; + } + + httpChannel->SetRequestHeader(nsDependentCString(header.get()), + nsDependentCString(val), false); + } + } + // This channel has been redirected. Don't report timing info. mTimingEnabled = false; return NS_OK; diff --git a/security/sandbox/win/src/sandboxbroker/sandboxBroker.cpp b/security/sandbox/win/src/sandboxbroker/sandboxBroker.cpp index 20f42042a0..14f25afcf5 100644 --- a/security/sandbox/win/src/sandboxbroker/sandboxBroker.cpp +++ b/security/sandbox/win/src/sandboxbroker/sandboxBroker.cpp @@ -406,6 +406,10 @@ SandboxBroker::SetSecurityLevelForGMPlugin() bool SandboxBroker::AllowReadFile(wchar_t const *file) { + if (!mPolicy) { + return false; + } + auto result = mPolicy->AddRule(sandbox::TargetPolicy::SUBSYS_FILES, sandbox::TargetPolicy::FILES_ALLOW_READONLY, @@ -416,6 +420,10 @@ SandboxBroker::AllowReadFile(wchar_t const *file) bool SandboxBroker::AllowReadWriteFile(wchar_t const *file) { + if (!mPolicy) { + return false; + } + auto result = mPolicy->AddRule(sandbox::TargetPolicy::SUBSYS_FILES, sandbox::TargetPolicy::FILES_ALLOW_ANY, @@ -426,6 +434,10 @@ SandboxBroker::AllowReadWriteFile(wchar_t const *file) bool SandboxBroker::AllowDirectory(wchar_t const *dir) { + if (!mPolicy) { + return false; + } + auto result = mPolicy->AddRule(sandbox::TargetPolicy::SUBSYS_FILES, sandbox::TargetPolicy::FILES_ALLOW_DIR_ANY, @@ -436,6 +448,10 @@ SandboxBroker::AllowDirectory(wchar_t const *dir) bool SandboxBroker::AddTargetPeer(HANDLE aPeerProcess) { + if (!sBrokerService) { + return false; + } + sandbox::ResultCode result = sBrokerService->AddTargetPeer(aPeerProcess); return (sandbox::SBOX_ALL_OK == result); } diff --git a/toolkit/components/telemetry/Histograms.json b/toolkit/components/telemetry/Histograms.json index 733da7e2a6..e1e80d804b 100644 --- a/toolkit/components/telemetry/Histograms.json +++ b/toolkit/components/telemetry/Histograms.json @@ -10122,6 +10122,14 @@ "kind": "count", "description": "Remote JAR protocol usage" }, + "MEDIA_DECODER_BACKEND_USED": { + "alert_emails": ["danderson@mozilla.com"], + "bug_numbers": [1259695], + "expires_in_version": "never", + "kind": "enumerated", + "n_values": 10, + "description": "Media decoder backend (0=WMF Software, 1=DXVA2D3D9, 2=DXVA2D3D11)" + }, "PLUGIN_BLOCKED_FOR_STABILITY": { "alert_emails": ["cpeterson@mozilla.com"], "expires_in_version": "52", @@ -10155,5 +10163,12 @@ "n_buckets": 50, "keyed": true, "description": "Measures the size of message manager messages by message name" + }, + "SANDBOX_BROKER_INITIALIZED": { + "alert_emails": ["bowen@mozilla.com"], + "bug_numbers": [1256992], + "expires_in_version": "55", + "kind": "boolean", + "description": "Result of call to SandboxBroker::Initialize" } } diff --git a/toolkit/xre/nsAppRunner.cpp b/toolkit/xre/nsAppRunner.cpp index a6c7c018ea..47205dbde3 100644 --- a/toolkit/xre/nsAppRunner.cpp +++ b/toolkit/xre/nsAppRunner.cpp @@ -604,37 +604,15 @@ CanShowProfileManager() return true; } -#if defined(XP_WIN) && defined(MOZ_CONTENT_SANDBOX) -static const char* -SandboxTempDirParent() -{ - return NS_WIN_LOW_INTEGRITY_TEMP_BASE; -} -#endif - -#if defined(XP_MACOSX) && defined(MOZ_CONTENT_SANDBOX) -static const char* -SandboxTempDirParent() -{ - return NS_OS_TEMP_DIR; -} -#endif - #if (defined(XP_WIN) || defined(XP_MACOSX)) && defined(MOZ_CONTENT_SANDBOX) static already_AddRefed -GetAndCleanTempDir(const nsAString& aTempDirSuffix) +GetAndCleanTempDir() { // Get the directory within which we'll place the // sandbox-writable temp directory nsCOMPtr tempDir; - nsresult rv = NS_GetSpecialDirectory(SandboxTempDirParent(), - getter_AddRefs(tempDir)); - if (NS_WARN_IF(NS_FAILED(rv))) { - return nullptr; - } - - // Append our profile specific temp name. - rv = tempDir->Append(NS_LITERAL_STRING("Temp-") + aTempDirSuffix); + nsresult rv = NS_GetSpecialDirectory(NS_APP_CONTENT_PROCESS_TEMP_DIR, + getter_AddRefs(tempDir)); if (NS_WARN_IF(NS_FAILED(rv))) { return nullptr; } @@ -715,7 +693,7 @@ SetUpSandboxEnvironment() } // Get (and clean up if still there) the sandbox-writable temp directory. - nsCOMPtr tempDir = GetAndCleanTempDir(tempDirSuffix); + nsCOMPtr tempDir = GetAndCleanTempDir(); if (!tempDir) { NS_WARNING("Failed to get or clean sandboxed temp directory."); return; @@ -737,16 +715,9 @@ CleanUpSandboxEnvironment() } #endif - // Get temp directory suffix pref. - nsAdoptingString tempDirSuffix = - Preferences::GetString("security.sandbox.content.tempDirSuffix"); - if (tempDirSuffix.IsEmpty()) { - return; - } - // Get and remove the sandbox-writable temp directory. // This function already warns if the deletion fails. - unused << GetAndCleanTempDir(tempDirSuffix); + unused << GetAndCleanTempDir(); #if defined(NIGHTLY_BUILD) // Temporary code to clean up the old low integrity temp directories. @@ -3441,6 +3412,24 @@ XREMain::XRE_mainInit(bool* aExitFlag) } #endif +#if defined(MOZ_SANDBOX) && defined(XP_WIN) + bool brokerInitialized = SandboxBroker::Initialize(); + Telemetry::Accumulate(Telemetry::SANDBOX_BROKER_INITIALIZED, + brokerInitialized); + if (!brokerInitialized) { +#if defined(MOZ_CONTENT_SANDBOX) + // If we're sandboxing content and we fail to initialize, then crashing here + // seems like the sensible option. + if (BrowserTabsRemoteAutostart()) { + MOZ_CRASH("Failed to initialize broker services, can't continue."); + } +#endif + // Otherwise just warn for the moment, as most things will work. + NS_WARNING("Failed to initialize broker services, sandboxed processes will " + "fail to start."); + } +#endif + #ifdef XP_MACOSX if (EnvHasValue("MOZ_LAUNCHED_CHILD")) { // This is needed, on relaunch, to force the OS to use the "Cocoa Dock @@ -3795,12 +3784,6 @@ XREMain::XRE_mainStartup(bool* aExitFlag) int result; #ifdef XP_WIN UseParentConsole(); -#if defined(MOZ_SANDBOX) - if (!SandboxBroker::Initialize()) { - NS_WARNING("Failed to initialize broker services, sandboxed processes " - "will fail to start."); - } -#endif #endif // RunGTest will only be set if we're in xul-unit if (mozilla::RunGTest) { @@ -4425,20 +4408,6 @@ XREMain::XRE_mainRun() } #endif /* MOZ_INSTRUMENT_EVENT_LOOP */ -#if defined(MOZ_SANDBOX) && defined(XP_WIN) - if (!SandboxBroker::Initialize()) { -#if defined(MOZ_CONTENT_SANDBOX) - // If we're sandboxing content and we fail to initialize, then crashing here - // seems like the sensible option. - if (BrowserTabsRemoteAutostart()) { - MOZ_CRASH("Failed to initialize broker services, can't continue."); - } -#endif - // Otherwise just warn for the moment, as most things will work. - NS_WARNING("Failed to initialize broker services, sandboxed processes will " - "fail to start."); - } -#endif #if (defined(XP_WIN) || defined(XP_MACOSX)) && defined(MOZ_CONTENT_SANDBOX) SetUpSandboxEnvironment(); #endif