diff --git a/browser/extensions/webcompat/bootstrap.js b/browser/extensions/webcompat/bootstrap.js index e08358f0c746..89e4b157d81b 100644 --- a/browser/extensions/webcompat/bootstrap.js +++ b/browser/extensions/webcompat/bootstrap.js @@ -76,7 +76,7 @@ this.startup = function({webExtension}) { // Listen to the useragentoverrides-initialized notification we get and // initialize our overrider there. This is done to avoid slowing down the - // apparent startup proces, since we avoid loading anything before the first + // apparent startup process, since we avoid loading anything before the first // window is visible to the user. See bug 1371442 for details. let uaStartupObserver = { observe(aSubject, aTopic, aData) { diff --git a/dom/payments/PaymentRequestManager.h b/dom/payments/PaymentRequestManager.h index 24033eff8433..80dd2f9c4376 100644 --- a/dom/payments/PaymentRequestManager.h +++ b/dom/payments/PaymentRequestManager.h @@ -23,7 +23,7 @@ class IPCPaymentActionRequest; /* * PaymentRequestManager is a singleton used to manage the created PaymentRequests. - * It is also the communication agent to chrome proces. + * It is also the communication agent to chrome process. */ class PaymentRequestManager final { diff --git a/gfx/thebes/gfxPlatform.cpp b/gfx/thebes/gfxPlatform.cpp index 61c32bb4d361..7fce979921da 100644 --- a/gfx/thebes/gfxPlatform.cpp +++ b/gfx/thebes/gfxPlatform.cpp @@ -629,7 +629,7 @@ static uint32_t GetSkiaGlyphCacheSize() // Chromium uses 20mb and skia default uses 2mb. // We don't need to change the font cache count since we usually // cache thrash due to asian character sets in talos. - // Only increase memory on the content proces + // Only increase memory on the content process uint32_t cacheSize = gfxPrefs::SkiaContentFontCacheSize() * 1024 * 1024; if (mozilla::BrowserTabsRemoteAutostart()) { return XRE_IsContentProcess() ? cacheSize : kDefaultGlyphCacheSize; diff --git a/ipc/glue/MessageChannel.cpp b/ipc/glue/MessageChannel.cpp index 59a229e4670d..11f263597fa5 100644 --- a/ipc/glue/MessageChannel.cpp +++ b/ipc/glue/MessageChannel.cpp @@ -13,6 +13,7 @@ #include "mozilla/ipc/ProtocolUtils.h" #include "mozilla/Logging.h" #include "mozilla/Move.h" +#include "mozilla/ScopeExit.h" #include "mozilla/Sprintf.h" #include "mozilla/Telemetry.h" #include "mozilla/TimeStamp.h" @@ -2696,7 +2697,16 @@ MessageChannel::Close() AssertWorkerThread(); { - MonitorAutoLock lock(*mMonitor); + // We don't use MonitorAutoLock here as that causes some sort of + // deadlock in the error/timeout-with-a-listener state below when + // compiling an optimized msvc build. + mMonitor->Lock(); + + // Instead just use a ScopeExit to manage the unlock. + RefPtr monitor(mMonitor); + auto exit = MakeScopeExit([m = Move(monitor)] () { + m->Unlock(); + }); if (ChannelError == mChannelState || ChannelTimeout == mChannelState) { // See bug 538586: if the listener gets deleted while the @@ -2705,7 +2715,8 @@ MessageChannel::Close() // also be deleted and the listener will never be notified // of the channel error. if (mListener) { - MonitorAutoUnlock unlock(*mMonitor); + exit.release(); // Explicitly unlocking, clear scope exit. + mMonitor->Unlock(); NotifyMaybeChannelError(); } return; diff --git a/js/src/jit/BaselineIC.cpp b/js/src/jit/BaselineIC.cpp index 75ccee0b1974..c6fbb4e72c9d 100644 --- a/js/src/jit/BaselineIC.cpp +++ b/js/src/jit/BaselineIC.cpp @@ -3211,7 +3211,8 @@ ICCall_ConstStringSplit::Compiler::generateStubCode(MacroAssembler& masm) masm.loadValue(sepAddr, sepVal); masm.branchTestString(Assembler::NotEqual, sepVal, &failureRestoreArgc); - Register sep = masm.extractString(sepVal, ExtractTemp0); + Register sep = sepVal.scratchReg(); + masm.unboxString(sepVal, sep); masm.branchPtr(Assembler::NotEqual, Address(ICStubReg, offsetOfExpectedSep()), sep, &failureRestoreArgc); regs.add(sepVal); @@ -3226,7 +3227,8 @@ ICCall_ConstStringSplit::Compiler::generateStubCode(MacroAssembler& masm) masm.loadValue(strAddr, strVal); masm.branchTestString(Assembler::NotEqual, strVal, &failureRestoreArgc); - Register str = masm.extractString(strVal, ExtractTemp0); + Register str = strVal.scratchReg(); + masm.unboxString(strVal, str); masm.branchPtr(Assembler::NotEqual, Address(ICStubReg, offsetOfExpectedStr()), str, &failureRestoreArgc); regs.add(strVal); diff --git a/js/src/jit/CodeGenerator.cpp b/js/src/jit/CodeGenerator.cpp index 106925750b29..707853cd1174 100644 --- a/js/src/jit/CodeGenerator.cpp +++ b/js/src/jit/CodeGenerator.cpp @@ -7745,7 +7745,6 @@ CodeGenerator::visitCompareStrictS(LCompareStrictS* lir) const ValueOperand leftV = ToValue(lir, LCompareStrictS::Lhs); Register right = ToRegister(lir->right()); Register output = ToRegister(lir->output()); - Register tempToUnbox = ToTempUnboxRegister(lir->tempToUnbox()); Label string, done; @@ -7754,7 +7753,12 @@ CodeGenerator::visitCompareStrictS(LCompareStrictS* lir) masm.jump(&done); masm.bind(&string); - Register left = masm.extractString(leftV, tempToUnbox); +#ifdef JS_NUNBOX32 + Register left = leftV.payloadReg(); +#else + Register left = ToTempUnboxRegister(lir->tempToUnbox()); +#endif + masm.unboxString(leftV, left); emitCompareS(lir, op, left, right, output); masm.bind(&done); diff --git a/js/src/jit/MacroAssembler.cpp b/js/src/jit/MacroAssembler.cpp index ce29f5908e0d..1247a1580814 100644 --- a/js/src/jit/MacroAssembler.cpp +++ b/js/src/jit/MacroAssembler.cpp @@ -1496,6 +1496,8 @@ void MacroAssembler::compareStrings(JSOp op, Register left, Register right, Register result, Label* fail) { + MOZ_ASSERT(left != result); + MOZ_ASSERT(right != result); MOZ_ASSERT(IsEqualityOp(op)); Label done; diff --git a/js/src/jit/SharedIC.cpp b/js/src/jit/SharedIC.cpp index 573238b98f31..838bc4040118 100644 --- a/js/src/jit/SharedIC.cpp +++ b/js/src/jit/SharedIC.cpp @@ -1485,22 +1485,29 @@ ICCompare_Fallback::Compiler::generateStubCode(MacroAssembler& masm) bool ICCompare_String::Compiler::generateStubCode(MacroAssembler& masm) { - Label failure; + Label failure, restore; masm.branchTestString(Assembler::NotEqual, R0, &failure); masm.branchTestString(Assembler::NotEqual, R1, &failure); MOZ_ASSERT(IsEqualityOp(op)); - Register left = masm.extractString(R0, ExtractTemp0); - Register right = masm.extractString(R1, ExtractTemp1); + // left/right are part of R0/R1. Restore R0 and R1 in the failure case. + Register left = R0.scratchReg(); + Register right = R1.scratchReg(); + masm.unboxString(R0, left); + masm.unboxString(R1, right); AllocatableGeneralRegisterSet regs(availableGeneralRegs(2)); Register scratchReg = regs.takeAny(); - masm.compareStrings(op, left, right, scratchReg, &failure); + masm.compareStrings(op, left, right, scratchReg, &restore); masm.tagValue(JSVAL_TYPE_BOOLEAN, scratchReg, R0); EmitReturnFromIC(masm); + masm.bind(&restore); + masm.tagValue(JSVAL_TYPE_STRING, left, R0); + masm.tagValue(JSVAL_TYPE_STRING, right, R1); + masm.bind(&failure); EmitStubGuardFailure(masm); return true; diff --git a/js/src/jit/arm/MacroAssembler-arm.h b/js/src/jit/arm/MacroAssembler-arm.h index 058d41e27741..569b77dff731 100644 --- a/js/src/jit/arm/MacroAssembler-arm.h +++ b/js/src/jit/arm/MacroAssembler-arm.h @@ -832,10 +832,6 @@ class MacroAssemblerARMCompat : public MacroAssemblerARM unboxNonDouble(value, value.payloadReg(), JSVAL_TYPE_OBJECT); return value.payloadReg(); } - Register extractString(const ValueOperand& value, Register scratch) { - unboxNonDouble(value, value.payloadReg(), JSVAL_TYPE_STRING); - return value.payloadReg(); - } Register extractSymbol(const ValueOperand& value, Register scratch) { unboxNonDouble(value, value.payloadReg(), JSVAL_TYPE_SYMBOL); return value.payloadReg(); diff --git a/js/src/jit/arm64/MacroAssembler-arm64.h b/js/src/jit/arm64/MacroAssembler-arm64.h index 4e5453cb1bc8..dc0c9a83655f 100644 --- a/js/src/jit/arm64/MacroAssembler-arm64.h +++ b/js/src/jit/arm64/MacroAssembler-arm64.h @@ -418,10 +418,6 @@ class MacroAssemblerCompat : public vixl::MacroAssembler unboxObject(value, scratch); return scratch; } - Register extractString(const ValueOperand& value, Register scratch) { - unboxString(value, scratch); - return scratch; - } Register extractSymbol(const ValueOperand& value, Register scratch) { unboxSymbol(value, scratch); return scratch; diff --git a/js/src/jit/none/MacroAssembler-none.h b/js/src/jit/none/MacroAssembler-none.h index 1eff305b785d..7b0598ef12d4 100644 --- a/js/src/jit/none/MacroAssembler-none.h +++ b/js/src/jit/none/MacroAssembler-none.h @@ -334,7 +334,6 @@ class MacroAssemblerNone : public Assembler void notBoolean(ValueOperand) { MOZ_CRASH(); } Register extractObject(Address, Register) { MOZ_CRASH(); } Register extractObject(ValueOperand, Register) { MOZ_CRASH(); } - Register extractString(ValueOperand, Register) { MOZ_CRASH(); } Register extractSymbol(ValueOperand, Register) { MOZ_CRASH(); } Register extractInt32(ValueOperand, Register) { MOZ_CRASH(); } Register extractBoolean(ValueOperand, Register) { MOZ_CRASH(); } diff --git a/js/src/jit/x64/MacroAssembler-x64.h b/js/src/jit/x64/MacroAssembler-x64.h index 2418f8615a67..d292671709de 100644 --- a/js/src/jit/x64/MacroAssembler-x64.h +++ b/js/src/jit/x64/MacroAssembler-x64.h @@ -885,11 +885,6 @@ class MacroAssemblerX64 : public MacroAssemblerX86Shared unboxObject(value, scratch); return scratch; } - Register extractString(const ValueOperand& value, Register scratch) { - MOZ_ASSERT(scratch != ScratchReg); - unboxString(value, scratch); - return scratch; - } Register extractSymbol(const ValueOperand& value, Register scratch) { MOZ_ASSERT(scratch != ScratchReg); unboxSymbol(value, scratch); diff --git a/js/src/jit/x86/MacroAssembler-x86.h b/js/src/jit/x86/MacroAssembler-x86.h index 231f65b8beb5..588ae1d2fbc0 100644 --- a/js/src/jit/x86/MacroAssembler-x86.h +++ b/js/src/jit/x86/MacroAssembler-x86.h @@ -837,10 +837,6 @@ class MacroAssemblerX86 : public MacroAssemblerX86Shared unboxNonDouble(value, value.payloadReg(), JSVAL_TYPE_OBJECT, scratch); return value.payloadReg(); } - Register extractString(const ValueOperand& value, Register scratch) { - unboxNonDouble(value, value.payloadReg(), JSVAL_TYPE_STRING, scratch); - return value.payloadReg(); - } Register extractSymbol(const ValueOperand& value, Register scratch) { unboxNonDouble(value, value.payloadReg(), JSVAL_TYPE_SYMBOL, scratch); return value.payloadReg(); diff --git a/js/src/wasm/WasmCode.cpp b/js/src/wasm/WasmCode.cpp index 9e19c0b51a0a..63c8a11fa461 100644 --- a/js/src/wasm/WasmCode.cpp +++ b/js/src/wasm/WasmCode.cpp @@ -40,18 +40,9 @@ using mozilla::BinarySearch; using mozilla::MakeEnumeratedRange; using mozilla::PodAssign; -bool -CodeSegment::registerInProcessMap() -{ - if (!RegisterCodeSegment(this)) - return false; - registered_ = true; - return true; -} - CodeSegment::~CodeSegment() { - if (registered_) + if (unregisterOnDestroy_) UnregisterCodeSegment(this); } @@ -97,6 +88,26 @@ CodeSegment::AllocateCodeBytes(uint32_t codeLength) return UniqueCodeBytes((uint8_t*)p, FreeCode(roundedCodeLength)); } +bool +CodeSegment::initialize(const CodeTier& codeTier) +{ + MOZ_ASSERT(!initialized()); + codeTier_ = &codeTier; + MOZ_ASSERT(initialized()); + + // In the case of tiering, RegisterCodeSegment() immediately makes this code + // segment live to access from other threads executing the containing + // module. So only call once the CodeSegment is fully initialized. + if (!RegisterCodeSegment(this)) + return false; + + // This bool is only used by the destructor which cannot be called racily + // and so it is not a problem to mutate it after RegisterCodeSegment(). + MOZ_ASSERT(!unregisterOnDestroy_); + unregisterOnDestroy_ = true; + return true; +} + const Code& CodeSegment::code() const { @@ -107,7 +118,7 @@ CodeSegment::code() const void CodeSegment::addSizeOfMisc(MallocSizeOf mallocSizeOf, size_t* code) const { - *code += RoundupCodeLength(length_); + *code += RoundupCodeLength(length()); } void @@ -261,13 +272,20 @@ SendCodeRangesToProfiler(const ModuleSegment& ms, const Bytes& bytecode, const M } } +ModuleSegment::ModuleSegment(Tier tier, + UniqueCodeBytes codeBytes, + uint32_t codeLength, + const LinkDataTier& linkData) + : CodeSegment(Move(codeBytes), codeLength, CodeSegment::Kind::Module), + tier_(tier), + outOfBoundsCode_(base() + linkData.outOfBoundsOffset), + unalignedAccessCode_(base() + linkData.unalignedAccessOffset), + trapCode_(base() + linkData.trapOffset) +{ +} + /* static */ UniqueModuleSegment -ModuleSegment::create(Tier tier, - MacroAssembler& masm, - const ShareableBytes& bytecode, - const LinkDataTier& linkData, - const Metadata& metadata, - const CodeRangeVector& codeRanges) +ModuleSegment::create(Tier tier, MacroAssembler& masm, const LinkDataTier& linkData) { uint32_t codeLength = masm.bytesNeeded(); @@ -278,16 +296,11 @@ ModuleSegment::create(Tier tier, // We'll flush the icache after static linking, in initialize(). masm.executableCopy(codeBytes.get(), /* flushICache = */ false); - return create(tier, Move(codeBytes), codeLength, bytecode, linkData, metadata, codeRanges); + return js::MakeUnique(tier, Move(codeBytes), codeLength, linkData); } /* static */ UniqueModuleSegment -ModuleSegment::create(Tier tier, - const Bytes& unlinkedBytes, - const ShareableBytes& bytecode, - const LinkDataTier& linkData, - const Metadata& metadata, - const CodeRangeVector& codeRanges) +ModuleSegment::create(Tier tier, const Bytes& unlinkedBytes, const LinkDataTier& linkData) { uint32_t codeLength = unlinkedBytes.length(); @@ -297,69 +310,35 @@ ModuleSegment::create(Tier tier, memcpy(codeBytes.get(), unlinkedBytes.begin(), codeLength); - return create(tier, Move(codeBytes), codeLength, bytecode, linkData, metadata, codeRanges); -} - -/* static */ UniqueModuleSegment -ModuleSegment::create(Tier tier, - UniqueCodeBytes codeBytes, - uint32_t codeLength, - const ShareableBytes& bytecode, - const LinkDataTier& linkData, - const Metadata& metadata, - const CodeRangeVector& codeRanges) -{ - // These should always exist and should never be first in the code segment. - - auto ms = js::MakeUnique(); - if (!ms) - return nullptr; - - if (!ms->initialize(tier, Move(codeBytes), codeLength, bytecode, linkData, metadata, codeRanges)) - return nullptr; - - return UniqueModuleSegment(ms.release()); + return js::MakeUnique(tier, Move(codeBytes), codeLength, linkData); } bool -ModuleSegment::initialize(Tier tier, - UniqueCodeBytes codeBytes, - uint32_t codeLength, +ModuleSegment::initialize(const CodeTier& codeTier, const ShareableBytes& bytecode, const LinkDataTier& linkData, const Metadata& metadata, - const CodeRangeVector& codeRanges) + const MetadataTier& metadataTier) { - MOZ_ASSERT(!bytes_); - - tier_ = tier; - bytes_ = Move(codeBytes); - length_ = codeLength; - outOfBoundsCode_ = bytes_.get() + linkData.outOfBoundsOffset; - unalignedAccessCode_ = bytes_.get() + linkData.unalignedAccessOffset; - trapCode_ = bytes_.get() + linkData.trapOffset; - if (!StaticallyLink(*this, linkData)) return false; - ExecutableAllocator::cacheFlush(bytes_.get(), RoundupCodeLength(codeLength)); + ExecutableAllocator::cacheFlush(base(), RoundupCodeLength(length())); // Reprotect the whole region to avoid having separate RW and RX mappings. - if (!ExecutableAllocator::makeExecutable(bytes_.get(), RoundupCodeLength(codeLength))) + if (!ExecutableAllocator::makeExecutable(base(), RoundupCodeLength(length()))) return false; - if (!registerInProcessMap()) - return false; + SendCodeRangesToProfiler(*this, bytecode.bytes, metadata, metadataTier.codeRanges); - SendCodeRangesToProfiler(*this, bytecode.bytes, metadata, codeRanges); - - return true; + // See comments in CodeSegment::initialize() for why this must be last. + return CodeSegment::initialize(codeTier); } size_t ModuleSegment::serializedSize() const { - return sizeof(uint32_t) + length_; + return sizeof(uint32_t) + length(); } void @@ -374,17 +353,16 @@ ModuleSegment::serialize(uint8_t* cursor, const LinkDataTier& linkData) const { MOZ_ASSERT(tier() == Tier::Serialized); - cursor = WriteScalar(cursor, length_); - uint8_t* base = cursor; - cursor = WriteBytes(cursor, bytes_.get(), length_); - StaticallyUnlink(base, linkData); + cursor = WriteScalar(cursor, length()); + uint8_t* serializedBase = cursor; + cursor = WriteBytes(cursor, base(), length()); + StaticallyUnlink(serializedBase, linkData); return cursor; } -const uint8_t* -ModuleSegment::deserialize(const uint8_t* cursor, const ShareableBytes& bytecode, - const LinkDataTier& linkData, const Metadata& metadata, - const CodeRangeVector& codeRanges) +/* static */ const uint8_t* +ModuleSegment::deserialize(const uint8_t* cursor, const LinkDataTier& linkData, + UniqueModuleSegment* segment) { uint32_t length; cursor = ReadScalar(cursor, &length); @@ -399,7 +377,8 @@ ModuleSegment::deserialize(const uint8_t* cursor, const ShareableBytes& bytecode if (!cursor) return nullptr; - if (!initialize(Tier::Serialized, Move(bytes), length, bytecode, linkData, metadata, codeRanges)) + *segment = js::MakeUnique(Tier::Serialized, Move(bytes), length, linkData); + if (!*segment) return nullptr; return cursor; @@ -560,17 +539,6 @@ MetadataTier::deserialize(const uint8_t* cursor) return cursor; } -bool -LazyStubSegment::initialize(UniqueCodeBytes codeBytes, size_t length) -{ - MOZ_ASSERT(bytes_ == nullptr); - - bytes_ = Move(codeBytes); - length_ = length; - - return registerInProcessMap(); -} - UniqueLazyStubSegment LazyStubSegment::create(const CodeTier& codeTier, size_t length) { @@ -578,9 +546,10 @@ LazyStubSegment::create(const CodeTier& codeTier, size_t length) if (!codeBytes) return nullptr; - auto segment = js::MakeUnique(codeTier); - if (!segment || !segment->initialize(Move(codeBytes), length)) + auto segment = js::MakeUnique(Move(codeBytes), length); + if (!segment || !segment->initialize(codeTier)) return nullptr; + return segment; } @@ -588,8 +557,8 @@ bool LazyStubSegment::hasSpace(size_t bytes) const { MOZ_ASSERT(bytes % MPROTECT_PAGE_SIZE == 0); - return bytes <= length_ && - usedBytes_ <= length_ - bytes; + return bytes <= length() && + usedBytes_ <= length() - bytes; } bool @@ -1021,24 +990,25 @@ CodeTier::serialize(uint8_t* cursor, const LinkDataTier& linkData) const return cursor; } -const uint8_t* -CodeTier::deserialize(const uint8_t* cursor, const SharedBytes& bytecode, Metadata& metadata, - const LinkDataTier& linkData) +/* static */ const uint8_t* +CodeTier::deserialize(const uint8_t* cursor, const LinkDataTier& linkData, + UniqueCodeTier* codeTier) { - metadata_ = js::MakeUnique(Tier::Serialized); - if (!metadata_) + auto metadata = js::MakeUnique(Tier::Serialized); + if (!metadata) return nullptr; - cursor = metadata_->deserialize(cursor); + cursor = metadata->deserialize(cursor); if (!cursor) return nullptr; - auto segment = Move(js::MakeUnique()); - if (!segment) - return nullptr; - cursor = segment->deserialize(cursor, *bytecode, linkData, metadata, metadata_->codeRanges); + UniqueModuleSegment segment; + cursor = ModuleSegment::deserialize(cursor, linkData, &segment); if (!cursor) return nullptr; - segment_ = takeOwnership(Move(segment)); + + *codeTier = js::MakeUnique(Move(metadata), Move(segment)); + if (!*codeTier) + return nullptr; return cursor; } @@ -1108,25 +1078,38 @@ JumpTables::init(CompileMode mode, const ModuleSegment& ms, const CodeRangeVecto return true; } -Code::Code(UniqueCodeTier codeTier, const Metadata& metadata, JumpTables&& maybeJumpTables) - : tier1_(takeOwnership(Move(codeTier))), +Code::Code(UniqueCodeTier tier1, const Metadata& metadata, JumpTables&& maybeJumpTables) + : tier1_(Move(tier1)), metadata_(&metadata), profilingLabels_(mutexid::WasmCodeProfilingLabels, CacheableCharsVector()), jumpTables_(Move(maybeJumpTables)) +{} + +bool +Code::initialize(const ShareableBytes& bytecode, const LinkDataTier& linkData) { + MOZ_ASSERT(!initialized()); + + if (!tier1_->initialize(*this, bytecode, linkData, *metadata_)) + return false; + + MOZ_ASSERT(initialized()); + return true; } -Code::Code() - : profilingLabels_(mutexid::WasmCodeProfilingLabels, CacheableCharsVector()) -{ -} - -void -Code::setTier2(UniqueCodeTier tier2) const +bool +Code::setTier2(UniqueCodeTier tier2, const ShareableBytes& bytecode, + const LinkDataTier& linkData) const { MOZ_RELEASE_ASSERT(!hasTier2()); MOZ_RELEASE_ASSERT(tier2->tier() == Tier::Ion && tier1_->tier() == Tier::Baseline); - tier2_ = takeOwnership(Move(tier2)); + + if (!tier2->initialize(*this, bytecode, linkData, *metadata_)) + return false; + + tier2_ = Move(tier2); + + return true; } void @@ -1135,6 +1118,7 @@ Code::commitTier2() const MOZ_RELEASE_ASSERT(!hasTier2()); MOZ_RELEASE_ASSERT(tier2_.get()); hasTier2_ = true; + MOZ_ASSERT(hasTier2()); } uint32_t @@ -1180,14 +1164,20 @@ Code::codeTier(Tier tier) const { switch (tier) { case Tier::Baseline: - if (tier1_->tier() == Tier::Baseline) + if (tier1_->tier() == Tier::Baseline) { + MOZ_ASSERT(tier1_->initialized()); return *tier1_; + } MOZ_CRASH("No code segment at this tier"); case Tier::Ion: - if (tier1_->tier() == Tier::Ion) + if (tier1_->tier() == Tier::Ion) { + MOZ_ASSERT(tier1_->initialized()); return *tier1_; - if (hasTier2()) + } + if (tier2_) { + MOZ_ASSERT(tier2_->initialized()); return *tier2_; + } MOZ_CRASH("No code segment at this tier"); default: MOZ_CRASH(); @@ -1370,6 +1360,25 @@ Code::addSizeOfMiscIfNotSeen(MallocSizeOf mallocSizeOf, codeTier(t).addSizeOfMisc(mallocSizeOf, code, data); } +bool +CodeTier::initialize(const Code& code, + const ShareableBytes& bytecode, + const LinkDataTier& linkData, + const Metadata& metadata) +{ + MOZ_ASSERT(!initialized()); + code_ = &code; + + MOZ_ASSERT(lazyStubs_.lock()->empty()); + + // See comments in CodeSegment::initialize() for why this must be last. + if (!segment_->initialize(*this, bytecode, linkData, metadata, *metadata_)) + return false; + + MOZ_ASSERT(initialized()); + return true; +} + size_t Code::serializedSize() const { @@ -1378,35 +1387,39 @@ Code::serializedSize() const } uint8_t* -Code::serialize(uint8_t* cursor, const LinkDataTier& linkDataTier) const +Code::serialize(uint8_t* cursor, const LinkData& linkData) const { MOZ_RELEASE_ASSERT(!metadata().debugEnabled); cursor = metadata().serialize(cursor); - cursor = codeTier(Tier::Serialized).serialize(cursor, linkDataTier); + cursor = codeTier(Tier::Serialized).serialize(cursor, linkData.tier(Tier::Serialized)); return cursor; } -const uint8_t* -Code::deserialize(const uint8_t* cursor, const SharedBytes& bytecode, - const LinkDataTier& linkDataTier, Metadata& metadata) +/* static */ const uint8_t* +Code::deserialize(const uint8_t* cursor, + const ShareableBytes& bytecode, + const LinkData& linkData, + Metadata& metadata, + SharedCode* out) { cursor = metadata.deserialize(cursor); if (!cursor) return nullptr; - auto codeTier = js::MakeUnique(Tier::Serialized); - if (!codeTier) - return nullptr; - cursor = codeTier->deserialize(cursor, bytecode, metadata, linkDataTier); + UniqueCodeTier codeTier; + cursor = CodeTier::deserialize(cursor, linkData.tier(Tier::Serialized), &codeTier); if (!cursor) return nullptr; - tier1_ = takeOwnership(Move(codeTier)); - metadata_ = &metadata; - - if (!jumpTables_.init(CompileMode::Once, tier1_->segment(), tier1_->metadata().codeRanges)) + JumpTables jumpTables; + if (!jumpTables.init(CompileMode::Once, codeTier->segment(), codeTier->metadata().codeRanges)) return nullptr; + MutableCode code = js_new(Move(codeTier), metadata, Move(jumpTables)); + if (!code || !code->initialize(bytecode, linkData.tier(Tier::Serialized))) + return nullptr; + + *out = code; return cursor; } diff --git a/js/src/wasm/WasmCode.h b/js/src/wasm/WasmCode.h index dbd5f44c065a..7b51c1eb0182 100644 --- a/js/src/wasm/WasmCode.h +++ b/js/src/wasm/WasmCode.h @@ -34,6 +34,7 @@ namespace wasm { struct LinkDataTier; struct MetadataTier; struct Metadata; +class LinkData; // ShareableBytes is a reference-counted Vector of bytes. @@ -81,30 +82,30 @@ class CodeSegment protected: static UniqueCodeBytes AllocateCodeBytes(uint32_t codeLength); - UniqueCodeBytes bytes_; - uint32_t length_; - - // A back reference to the owning code. - const CodeTier* codeTier_; - enum class Kind { LazyStubs, Module - } kind_; + }; - bool registerInProcessMap(); - - private: - bool registered_; - - public: - explicit CodeSegment(Kind kind = Kind::Module) - : length_(UINT32_MAX), - codeTier_(nullptr), + CodeSegment(UniqueCodeBytes bytes, uint32_t length, Kind kind) + : bytes_(Move(bytes)), + length_(length), kind_(kind), - registered_(false) + codeTier_(nullptr), + unregisterOnDestroy_(false) {} + bool initialize(const CodeTier& codeTier); + + private: + const UniqueCodeBytes bytes_; + const uint32_t length_; + const Kind kind_; + const CodeTier* codeTier_; + bool unregisterOnDestroy_; + + public: + bool initialized() const { return !!codeTier_; } ~CodeSegment(); bool isLazyStubs() const { return kind_ == Kind::LazyStubs; } @@ -125,11 +126,7 @@ class CodeSegment return pc >= base() && pc < (base() + length_); } - void initCodeTier(const CodeTier* codeTier) { - MOZ_ASSERT(!codeTier_); - codeTier_ = codeTier; - } - const CodeTier& codeTier() const { return *codeTier_; } + const CodeTier& codeTier() const { MOZ_ASSERT(initialized()); return *codeTier_; } const Code& code() const; void addSizeOfMisc(MallocSizeOf mallocSizeOf, size_t* code) const; @@ -138,61 +135,37 @@ class CodeSegment // A wasm ModuleSegment owns the allocated executable code for a wasm module. typedef UniquePtr UniqueModuleSegment; -typedef UniquePtr UniqueConstModuleSegment; class ModuleSegment : public CodeSegment { - Tier tier_; + const Tier tier_; + uint8_t* const outOfBoundsCode_; + uint8_t* const unalignedAccessCode_; + uint8_t* const trapCode_; - // These are pointers into code for stubs used for signal-handler - // control-flow transfer. - uint8_t* outOfBoundsCode_; - uint8_t* unalignedAccessCode_; - uint8_t* trapCode_; - - bool initialize(Tier tier, - UniqueCodeBytes bytes, - uint32_t codeLength, - const ShareableBytes& bytecode, - const LinkDataTier& linkData, - const Metadata& metadata, - const CodeRangeVector& codeRanges); - - static UniqueModuleSegment create(Tier tier, - UniqueCodeBytes bytes, - uint32_t codeLength, - const ShareableBytes& bytecode, - const LinkDataTier& linkData, - const Metadata& metadata, - const CodeRangeVector& codeRanges); public: - ModuleSegment(const ModuleSegment&) = delete; - void operator=(const ModuleSegment&) = delete; - - ModuleSegment() - : CodeSegment(), - tier_(Tier(-1)), - outOfBoundsCode_(nullptr), - unalignedAccessCode_(nullptr), - trapCode_(nullptr) - {} + ModuleSegment(Tier tier, + UniqueCodeBytes codeBytes, + uint32_t codeLength, + const LinkDataTier& linkData); static UniqueModuleSegment create(Tier tier, jit::MacroAssembler& masm, - const ShareableBytes& bytecode, - const LinkDataTier& linkData, - const Metadata& metadata, - const CodeRangeVector& codeRanges); - + const LinkDataTier& linkData); static UniqueModuleSegment create(Tier tier, const Bytes& unlinkedBytes, - const ShareableBytes& bytecode, - const LinkDataTier& linkData, - const Metadata& metadata, - const CodeRangeVector& codeRanges); + const LinkDataTier& linkData); + + bool initialize(const CodeTier& codeTier, + const ShareableBytes& bytecode, + const LinkDataTier& linkData, + const Metadata& metadata, + const MetadataTier& metadataTier); Tier tier() const { return tier_; } + // Pointers to stubs to which PC is redirected from the signal-handler. + uint8_t* outOfBoundsCode() const { return outOfBoundsCode_; } uint8_t* unalignedAccessCode() const { return unalignedAccessCode_; } uint8_t* trapCode() const { return trapCode_; } @@ -200,10 +173,9 @@ class ModuleSegment : public CodeSegment // Structured clone support: size_t serializedSize() const; - uint8_t* serialize(uint8_t* cursor, const LinkDataTier& linkDataTier) const; - const uint8_t* deserialize(const uint8_t* cursor, const ShareableBytes& bytecode, - const LinkDataTier& linkDataTier, const Metadata& metadata, - const CodeRangeVector& codeRanges); + uint8_t* serialize(uint8_t* cursor, const LinkDataTier& linkData) const; + static const uint8_t* deserialize(const uint8_t* cursor, const LinkDataTier& linkData, + UniqueModuleSegment* segment); const CodeRange* lookupRange(const void* pc) const; @@ -527,6 +499,9 @@ using UniqueMetadataTier = UniquePtr; // isn't (64KiB), a given stub segment can contain entry stubs of many // functions. +using UniqueLazyStubSegment = UniquePtr; +using LazyStubSegmentVector = Vector; + class LazyStubSegment : public CodeSegment { CodeRangeVector codeRanges_; @@ -534,17 +509,14 @@ class LazyStubSegment : public CodeSegment static constexpr size_t MPROTECT_PAGE_SIZE = 4 * 1024; - bool initialize(UniqueCodeBytes codeBytes, size_t length); - public: - explicit LazyStubSegment(const CodeTier& codeTier) - : CodeSegment(CodeSegment::Kind::LazyStubs), + LazyStubSegment(UniqueCodeBytes bytes, size_t length) + : CodeSegment(Move(bytes), length, CodeSegment::Kind::LazyStubs), usedBytes_(0) - { - initCodeTier(&codeTier); - } + {} + + static UniqueLazyStubSegment create(const CodeTier& codeTier, size_t codeLength); - static UniquePtr create(const CodeTier& codeTier, size_t length); static size_t AlignBytesNeeded(size_t bytes) { return AlignBytes(bytes, MPROTECT_PAGE_SIZE); } bool hasSpace(size_t bytes) const; @@ -558,9 +530,6 @@ class LazyStubSegment : public CodeSegment void addSizeOfMisc(MallocSizeOf mallocSizeOf, size_t* code, size_t* data) const; }; -using UniqueLazyStubSegment = UniquePtr; -using LazyStubSegmentVector = Vector; - // LazyFuncExport helps to efficiently lookup a CodeRange from a given function // index. It is inserted in a vector sorted by function index, to perform // binary search on it later. @@ -623,23 +592,20 @@ class LazyStubTier // CodeTier contains all the data related to a given compilation tier. It is // built during module generation and then immutably stored in a Code. +typedef UniquePtr UniqueCodeTier; +typedef UniquePtr UniqueConstCodeTier; + class CodeTier { - const Tier tier_; - const Code* code_; + const Code* code_; // Serialized information. - UniqueMetadataTier metadata_; - UniqueConstModuleSegment segment_; + const UniqueMetadataTier metadata_; + const UniqueModuleSegment segment_; // Lazy stubs, not serialized. ExclusiveData lazyStubs_; - UniqueConstModuleSegment takeOwnership(UniqueModuleSegment segment) const { - segment->initCodeTier(this); - return UniqueConstModuleSegment(segment.release()); - } - static const MutexId& mutexForTier(Tier tier) { if (tier == Tier::Baseline) return mutexid::WasmLazyStubsTier1; @@ -648,45 +614,35 @@ class CodeTier } public: - explicit CodeTier(Tier tier) - : tier_(tier), - code_(nullptr), - metadata_(nullptr), - segment_(nullptr), - lazyStubs_(mutexForTier(tier)) - {} - - CodeTier(Tier tier, UniqueMetadataTier metadata, UniqueModuleSegment segment) - : tier_(tier), - code_(nullptr), + CodeTier(UniqueMetadataTier metadata, UniqueModuleSegment segment) + : code_(nullptr), metadata_(Move(metadata)), - segment_(takeOwnership(Move(segment))), - lazyStubs_(mutexForTier(tier)) + segment_(Move(segment)), + lazyStubs_(mutexForTier(segment_->tier())) {} - void initCode(const Code* code) { - MOZ_ASSERT(!code_); - code_ = code; - } + bool initialized() const { return !!code_ && segment_->initialized(); } - Tier tier() const { return tier_; } + bool initialize(const Code& code, + const ShareableBytes& bytecode, + const LinkDataTier& linkData, + const Metadata& metadata); + + Tier tier() const { return segment_->tier(); } const ExclusiveData& lazyStubs() const { return lazyStubs_; } const MetadataTier& metadata() const { return *metadata_.get(); } const ModuleSegment& segment() const { return *segment_.get(); } - const Code& code() const { return *code_; } + const Code& code() const { MOZ_ASSERT(initialized()); return *code_; } const CodeRange* lookupRange(const void* pc) const; size_t serializedSize() const; uint8_t* serialize(uint8_t* cursor, const LinkDataTier& linkData) const; - const uint8_t* deserialize(const uint8_t* cursor, const SharedBytes& bytecode, - Metadata& metadata, const LinkDataTier& linkData); + static const uint8_t* deserialize(const uint8_t* cursor, const LinkDataTier& linkData, + UniqueCodeTier* codeTier); void addSizeOfMisc(MallocSizeOf mallocSizeOf, size_t* code, size_t* data) const; }; -typedef UniquePtr UniqueCodeTier; -typedef UniquePtr UniqueConstCodeTier; - // Jump tables to take tiering into account, when calling either from wasm to // wasm (through rabaldr) or from jit to wasm (jit entry). @@ -743,23 +699,23 @@ class JumpTables // // profilingLabels_ is lazily initialized, but behind a lock. +typedef RefPtr SharedCode; +typedef RefPtr MutableCode; + class Code : public ShareableBase { - UniqueConstCodeTier tier1_; + UniqueCodeTier tier1_; mutable UniqueConstCodeTier tier2_; // Access only when hasTier2() is true mutable Atomic hasTier2_; SharedMetadata metadata_; ExclusiveData profilingLabels_; JumpTables jumpTables_; - UniqueConstCodeTier takeOwnership(UniqueCodeTier codeTier) const { - codeTier->initCode(this); - return UniqueConstCodeTier(codeTier.release()); - } - public: - Code(); - Code(UniqueCodeTier tier, const Metadata& metadata, JumpTables&& maybeJumpTables); + Code(UniqueCodeTier tier1, const Metadata& metadata, JumpTables&& maybeJumpTables); + bool initialized() const { return tier1_->initialized(); } + + bool initialize(const ShareableBytes& bytecode, const LinkDataTier& linkData); void setTieringEntry(size_t i, void* target) const { jumpTables_.setTieringEntry(i, target); } void** tieringJumpTable() const { return jumpTables_.tiering(); } @@ -768,7 +724,8 @@ class Code : public ShareableBase void** getAddressOfJitEntry(size_t i) const { return jumpTables_.getAddressOfJitEntry(i); } uint32_t getFuncIndex(JSFunction* fun) const; - void setTier2(UniqueCodeTier tier2) const; + bool setTier2(UniqueCodeTier tier2, const ShareableBytes& bytecode, + const LinkDataTier& linkData) const; void commitTier2() const; bool hasTier2() const { return hasTier2_; } @@ -814,14 +771,14 @@ class Code : public ShareableBase // machine code and other parts. size_t serializedSize() const; - uint8_t* serialize(uint8_t* cursor, const LinkDataTier& linkDataTier) const; - const uint8_t* deserialize(const uint8_t* cursor, const SharedBytes& bytecode, - const LinkDataTier& linkDataTier, Metadata& metadata); + uint8_t* serialize(uint8_t* cursor, const LinkData& linkData) const; + static const uint8_t* deserialize(const uint8_t* cursor, + const ShareableBytes& bytecode, + const LinkData& linkData, + Metadata& metadata, + SharedCode* code); }; -typedef RefPtr SharedCode; -typedef RefPtr MutableCode; - } // namespace wasm } // namespace js diff --git a/js/src/wasm/WasmGenerator.cpp b/js/src/wasm/WasmGenerator.cpp index 655669d3a91f..6b46cfe08340 100644 --- a/js/src/wasm/WasmGenerator.cpp +++ b/js/src/wasm/WasmGenerator.cpp @@ -943,8 +943,7 @@ ModuleGenerator::finish(const ShareableBytes& bytecode) if (!finishMetadata(bytecode)) return nullptr; - return ModuleSegment::create(tier(), masm_, bytecode, *linkDataTier_, *metadata_, - metadataTier_->codeRanges); + return ModuleSegment::create(tier(), masm_, *linkDataTier_); } SharedModule @@ -972,12 +971,12 @@ ModuleGenerator::finishModule(const ShareableBytes& bytecode) return nullptr; } - auto codeTier = js::MakeUnique(tier(), Move(metadataTier_), Move(moduleSegment)); + auto codeTier = js::MakeUnique(Move(metadataTier_), Move(moduleSegment)); if (!codeTier) return nullptr; - SharedCode code = js_new(Move(codeTier), *metadata_, Move(jumpTables)); - if (!code) + MutableCode code = js_new(Move(codeTier), *metadata_, Move(jumpTables)); + if (!code || !code->initialize(bytecode, *linkDataTier_)) return nullptr; SharedModule module(js_new(Move(assumptions_), @@ -1012,7 +1011,7 @@ ModuleGenerator::finishTier2(Module& module) if (!moduleSegment) return false; - auto tier2 = js::MakeUnique(tier(), Move(metadataTier_), Move(moduleSegment)); + auto tier2 = js::MakeUnique(Move(metadataTier_), Move(moduleSegment)); if (!tier2) return false; diff --git a/js/src/wasm/WasmModule.cpp b/js/src/wasm/WasmModule.cpp index 04f5d5942010..61df5d50dea2 100644 --- a/js/src/wasm/WasmModule.cpp +++ b/js/src/wasm/WasmModule.cpp @@ -110,26 +110,26 @@ LinkDataTier::sizeOfExcludingThis(MallocSizeOf mallocSizeOf) const } void -LinkData::setTier2(UniqueLinkDataTier linkData) const +LinkData::setTier2(UniqueLinkDataTier tier) const { - MOZ_RELEASE_ASSERT(linkData->tier == Tier::Ion && linkData1_->tier == Tier::Baseline); - MOZ_RELEASE_ASSERT(!linkData2_.get()); - linkData2_ = Move(linkData); + MOZ_RELEASE_ASSERT(tier->tier == Tier::Ion && tier1_->tier == Tier::Baseline); + MOZ_RELEASE_ASSERT(!tier2_.get()); + tier2_ = Move(tier); } const LinkDataTier& -LinkData::linkData(Tier tier) const +LinkData::tier(Tier tier) const { switch (tier) { case Tier::Baseline: - if (linkData1_->tier == Tier::Baseline) - return *linkData1_; + if (tier1_->tier == Tier::Baseline) + return *tier1_; MOZ_CRASH("No linkData at this tier"); case Tier::Ion: - if (linkData1_->tier == Tier::Ion) - return *linkData1_; - if (linkData2_) - return *linkData2_; + if (tier1_->tier == Tier::Ion) + return *tier1_; + if (tier2_) + return *tier2_; MOZ_CRASH("No linkData at this tier"); default: MOZ_CRASH(); @@ -139,24 +139,24 @@ LinkData::linkData(Tier tier) const size_t LinkData::serializedSize() const { - return linkData(Tier::Serialized).serializedSize(); + return tier(Tier::Serialized).serializedSize(); } uint8_t* LinkData::serialize(uint8_t* cursor) const { - cursor = linkData(Tier::Serialized).serialize(cursor); + cursor = tier(Tier::Serialized).serialize(cursor); return cursor; } const uint8_t* LinkData::deserialize(const uint8_t* cursor) { - MOZ_ASSERT(!linkData1_); - linkData1_ = js::MakeUnique(Tier::Serialized); - if (!linkData1_) + MOZ_ASSERT(!tier1_); + tier1_ = js::MakeUnique(Tier::Serialized); + if (!tier1_) return nullptr; - cursor = linkData1_->deserialize(cursor); + cursor = tier1_->deserialize(cursor); return cursor; } @@ -164,9 +164,9 @@ size_t LinkData::sizeOfExcludingThis(MallocSizeOf mallocSizeOf) const { size_t sum = 0; - sum += linkData1_->sizeOfExcludingThis(mallocSizeOf); - if (linkData2_) - sum += linkData2_->sizeOfExcludingThis(mallocSizeOf); + sum += tier1_->sizeOfExcludingThis(mallocSizeOf); + if (tier2_) + sum += tier2_->sizeOfExcludingThis(mallocSizeOf); return sum; } @@ -243,10 +243,23 @@ Module::notifyCompilationListeners() } bool -Module::finishTier2(UniqueLinkDataTier linkData2, UniqueCodeTier tier2, ModuleEnvironment* env2) +Module::finishTier2(UniqueLinkDataTier linkData2, UniqueCodeTier tier2Arg, ModuleEnvironment* env2) { - MOZ_ASSERT(code().bestTier() == Tier::Baseline && tier2->tier() == Tier::Ion); + MOZ_ASSERT(code().bestTier() == Tier::Baseline && tier2Arg->tier() == Tier::Ion); + // Install the data in the data structures. They will not be visible + // until commitTier2(). + + if (!code().setTier2(Move(tier2Arg), *bytecode_, *linkData2)) + return false; + linkData().setTier2(Move(linkData2)); + for (uint32_t i = 0; i < elemSegments_.length(); i++) + elemSegments_[i].setTier2(Move(env2->elemSegments[i].elemCodeRangeIndices(Tier::Ion))); + + // Before we can make tier-2 live, we need to compile tier2 versions of any + // extant tier1 lazy stubs (otherwise, tiering would break the assumption + // that any extant exported wasm function has had a lazy entry stub already + // compiled for it). { // We need to prevent new tier1 stubs generation until we've committed // the newer tier2 stubs, otherwise we might not generate one tier2 @@ -255,7 +268,7 @@ Module::finishTier2(UniqueLinkDataTier linkData2, UniqueCodeTier tier2, ModuleEn const MetadataTier& metadataTier1 = metadata(Tier::Baseline); auto stubs1 = code().codeTier(Tier::Baseline).lazyStubs().lock(); - auto stubs2 = tier2->lazyStubs().lock(); + auto stubs2 = code().codeTier(Tier::Ion).lazyStubs().lock(); MOZ_ASSERT(stubs2->empty()); @@ -272,23 +285,15 @@ Module::finishTier2(UniqueLinkDataTier linkData2, UniqueCodeTier tier2, ModuleEn } HasGcTypes gcTypesEnabled = code().metadata().temporaryHasGcTypes; + const CodeTier& tier2 = code().codeTier(Tier::Ion); Maybe stub2Index; - if (!stubs2->createTier2(gcTypesEnabled, funcExportIndices, *tier2, &stub2Index)) + if (!stubs2->createTier2(gcTypesEnabled, funcExportIndices, tier2, &stub2Index)) return false; - // Install the data in the data structures. They will not be visible - // yet. + // Now that we can't fail or otherwise abort tier2, make it live. MOZ_ASSERT(!code().hasTier2()); - linkData().setTier2(Move(linkData2)); - code().setTier2(Move(tier2)); - for (uint32_t i = 0; i < elemSegments_.length(); i++) - elemSegments_[i].setTier2(Move(env2->elemSegments[i].elemCodeRangeIndices(Tier::Ion))); - - // Now that all the code and metadata is valid, make tier 2 code - // visible and unblock anyone waiting on it. - code().commitTier2(); // Now tier2 is committed and we can update jump tables entries to @@ -418,7 +423,7 @@ Module::compiledSerialize(uint8_t* compiledBegin, size_t compiledSize) const cursor = SerializeVector(cursor, exports_); cursor = SerializePodVector(cursor, dataSegments_); cursor = SerializeVector(cursor, elemSegments_); - cursor = code_->serialize(cursor, linkData_.linkData(Tier::Serialized)); + cursor = code_->serialize(cursor, linkData_); MOZ_RELEASE_ASSERT(cursor == compiledBegin + compiledSize); } @@ -481,8 +486,8 @@ Module::deserialize(const uint8_t* bytecodeBegin, size_t bytecodeSize, if (!cursor) return nullptr; - MutableCode code = js_new(); - cursor = code->deserialize(cursor, bytecode, linkData.linkData(Tier::Serialized), *metadata); + SharedCode code; + cursor = Code::deserialize(cursor, *bytecode, linkData, *metadata, &code); if (!cursor) return nullptr; @@ -1245,12 +1250,7 @@ Module::instantiate(JSContext* cx, // may patch the pre-linked code at any time. if (!codeIsBusy_.compareExchange(false, true)) { Tier tier = Tier::Baseline; - auto segment = ModuleSegment::create(tier, - *unlinkedCodeForDebugging_, - *bytecode_, - linkData(tier), - metadata(), - metadata(tier).codeRanges); + auto segment = ModuleSegment::create(tier, *unlinkedCodeForDebugging_, linkData(tier)); if (!segment) { ReportOutOfMemory(cx); return false; @@ -1260,7 +1260,7 @@ Module::instantiate(JSContext* cx, if (!metadataTier || !metadataTier->clone(metadata(tier))) return false; - auto codeTier = js::MakeUnique(tier, Move(metadataTier), Move(segment)); + auto codeTier = js::MakeUnique(Move(metadataTier), Move(segment)); if (!codeTier) return false; @@ -1268,11 +1268,13 @@ Module::instantiate(JSContext* cx, if (!jumpTables.init(CompileMode::Once, codeTier->segment(), metadata(tier).codeRanges)) return false; - code = js_new(Move(codeTier), metadata(), Move(jumpTables)); - if (!code) { + MutableCode debugCode = js_new(Move(codeTier), metadata(), Move(jumpTables)); + if (!debugCode || !debugCode->initialize(*bytecode_, linkData(tier))) { ReportOutOfMemory(cx); return false; } + + code = debugCode; } } diff --git a/js/src/wasm/WasmModule.h b/js/src/wasm/WasmModule.h index 1bda6b5345f3..5b8fdca8e541 100644 --- a/js/src/wasm/WasmModule.h +++ b/js/src/wasm/WasmModule.h @@ -82,15 +82,15 @@ typedef UniquePtr UniqueLinkDataTier; class LinkData { - UniqueLinkDataTier linkData1_; // Always present - mutable UniqueLinkDataTier linkData2_; // Access only if hasTier2() is true + UniqueLinkDataTier tier1_; // Always present + mutable UniqueLinkDataTier tier2_; // Access only if hasTier2() is true public: LinkData() {} - explicit LinkData(UniqueLinkDataTier linkData) : linkData1_(Move(linkData)) {} + explicit LinkData(UniqueLinkDataTier tier) : tier1_(Move(tier)) {} void setTier2(UniqueLinkDataTier linkData) const; - const LinkDataTier& linkData(Tier tier) const; + const LinkDataTier& tier(Tier tier) const; WASM_DECLARE_SERIALIZABLE(LinkData) }; @@ -192,7 +192,7 @@ class Module : public JS::WasmModule const Metadata& metadata() const { return code_->metadata(); } const MetadataTier& metadata(Tier t) const { return code_->metadata(t); } const LinkData& linkData() const { return linkData_; } - const LinkDataTier& linkData(Tier t) const { return linkData_.linkData(t); } + const LinkDataTier& linkData(Tier t) const { return linkData_.tier(t); } const ImportVector& imports() const { return imports_; } const ExportVector& exports() const { return exports_; } const ShareableBytes& bytecode() const { return *bytecode_; } diff --git a/js/src/wasm/WasmProcess.cpp b/js/src/wasm/WasmProcess.cpp index 2fa681e78fb1..50070d115505 100644 --- a/js/src/wasm/WasmProcess.cpp +++ b/js/src/wasm/WasmProcess.cpp @@ -217,6 +217,7 @@ static ProcessCodeSegmentMap processCodeSegmentMap; bool wasm::RegisterCodeSegment(const CodeSegment* cs) { + MOZ_ASSERT(cs->codeTier().code().initialized()); return processCodeSegmentMap.insert(cs); } diff --git a/layout/generic/nsCanvasFrame.cpp b/layout/generic/nsCanvasFrame.cpp index c8275c24cc32..a676c3253fce 100644 --- a/layout/generic/nsCanvasFrame.cpp +++ b/layout/generic/nsCanvasFrame.cpp @@ -375,7 +375,7 @@ nsDisplayCanvasBackgroundImage::IsSingleFixedPositionImage(nsDisplayListBuilder* nsRect borderArea = nsRect(ToReferenceFrame(), mFrame->GetSize()); const nsStyleImageLayers::Layer &layer = mBackgroundStyle->StyleBackground()->mImage.mLayers[mLayer]; - if (layer.mAttachment != NS_STYLE_IMAGELAYER_ATTACHMENT_FIXED) + if (layer.mAttachment != StyleImageLayerAttachment::Fixed) return false; nsBackgroundLayerState state = diff --git a/layout/painting/nsCSSRendering.cpp b/layout/painting/nsCSSRendering.cpp index 048ab2c5d740..8ed0d73a2a02 100644 --- a/layout/painting/nsCSSRendering.cpp +++ b/layout/painting/nsCSSRendering.cpp @@ -2334,7 +2334,7 @@ nsCSSRendering::GetImageLayerClip(const nsStyleImageLayers::Layer& aLayer, aClipState->mBGClipArea = clipBorderArea; if (aForFrame->IsScrollFrame() && - NS_STYLE_IMAGELAYER_ATTACHMENT_LOCAL == aLayer.mAttachment) { + StyleImageLayerAttachment::Local == aLayer.mAttachment) { // As of this writing, this is still in discussion in the CSS Working Group // http://lists.w3.org/Archives/Public/www-style/2013Jul/0250.html @@ -2947,7 +2947,7 @@ nsCSSRendering::ComputeImageLayerPositioningArea(nsPresContext* aPresContext, LayoutFrameType frameType = aForFrame->Type(); nsIFrame* geometryFrame = aForFrame; if (MOZ_UNLIKELY(frameType == LayoutFrameType::Scroll && - NS_STYLE_IMAGELAYER_ATTACHMENT_LOCAL == aLayer.mAttachment)) { + StyleImageLayerAttachment::Local == aLayer.mAttachment)) { nsIScrollableFrame* scrollableFrame = do_QueryFrame(aForFrame); positionArea = nsRect( scrollableFrame->GetScrolledFrame()->GetPosition() @@ -3008,7 +3008,7 @@ nsCSSRendering::ComputeImageLayerPositioningArea(nsPresContext* aPresContext, } nsIFrame* attachedToFrame = aForFrame; - if (NS_STYLE_IMAGELAYER_ATTACHMENT_FIXED == aLayer.mAttachment) { + if (StyleImageLayerAttachment::Fixed == aLayer.mAttachment) { // If it's a fixed background attachment, then the image is placed // relative to the viewport, which is the area of the root frame // in a screen context or the page content frame in a print context. @@ -3283,7 +3283,7 @@ nsCSSRendering::PrepareImageLayer(nsPresContext* aPresContext, // where the background can be drawn to the viewport. nsRect bgClipRect = aBGClipRect; - if (NS_STYLE_IMAGELAYER_ATTACHMENT_FIXED == aLayer.mAttachment && + if (StyleImageLayerAttachment::Fixed == aLayer.mAttachment && !transformedFixed && (aFlags & nsCSSRendering::PAINTBG_TO_WINDOW)) { bgClipRect = positionArea + aBorderArea.TopLeft(); diff --git a/layout/painting/nsDisplayList.cpp b/layout/painting/nsDisplayList.cpp index 54d712fddbae..7bc15110548f 100644 --- a/layout/painting/nsDisplayList.cpp +++ b/layout/painting/nsDisplayList.cpp @@ -3501,7 +3501,7 @@ nsDisplayBackgroundImage::GetInitData(nsDisplayListBuilder* aBuilder, // if it's affected by a transform. // See https://www.w3.org/Bugs/Public/show_bug.cgi?id=17521. bool shouldTreatAsFixed = - layer.mAttachment == NS_STYLE_IMAGELAYER_ATTACHMENT_FIXED && !isTransformedFixed; + layer.mAttachment == StyleImageLayerAttachment::Fixed && !isTransformedFixed; bool shouldFixToViewport = shouldTreatAsFixed && !layer.mImage.IsEmpty(); bool isRasterImage = state.mImageRenderer.IsRasterImage(); diff --git a/layout/style/ServoBindings.toml b/layout/style/ServoBindings.toml index ad882ac9cb66..2c95653c999d 100644 --- a/layout/style/ServoBindings.toml +++ b/layout/style/ServoBindings.toml @@ -173,6 +173,7 @@ rusty-enums = [ "mozilla::StyleUserFocus", "mozilla::StyleUserSelect", "mozilla::StyleImageLayerRepeat", + "mozilla::StyleImageLayerAttachment", "mozilla::StyleBoxDecorationBreak", "mozilla::StyleRuleInclusion", "mozilla::StyleGridTrackBreadth", @@ -243,6 +244,7 @@ whitelist-types = [ "mozilla::LookAndFeel", "mozilla::gfx::Float", "mozilla::gfx::FontVariation", + "mozilla::StyleImageLayerAttachment", ".*ThreadSafe.*Holder", "AnonymousContent", "AudioContext", diff --git a/layout/style/nsCSSProps.cpp b/layout/style/nsCSSProps.cpp index 5dc8cbfc9e39..a037d6bc4fa0 100644 --- a/layout/style/nsCSSProps.cpp +++ b/layout/style/nsCSSProps.cpp @@ -447,9 +447,9 @@ const KTableEntry nsCSSProps::kTransformStyleKTable[] = { }; const KTableEntry nsCSSProps::kImageLayerAttachmentKTable[] = { - { eCSSKeyword_fixed, NS_STYLE_IMAGELAYER_ATTACHMENT_FIXED }, - { eCSSKeyword_scroll, NS_STYLE_IMAGELAYER_ATTACHMENT_SCROLL }, - { eCSSKeyword_local, NS_STYLE_IMAGELAYER_ATTACHMENT_LOCAL }, + { eCSSKeyword_fixed, StyleImageLayerAttachment::Fixed }, + { eCSSKeyword_scroll, StyleImageLayerAttachment::Scroll }, + { eCSSKeyword_local, StyleImageLayerAttachment::Local }, { eCSSKeyword_UNKNOWN, -1 } }; diff --git a/layout/style/nsStyleConsts.h b/layout/style/nsStyleConsts.h index 313ba2e3e06d..1473bb8b53c2 100644 --- a/layout/style/nsStyleConsts.h +++ b/layout/style/nsStyleConsts.h @@ -254,9 +254,11 @@ enum class FillMode : uint8_t; #define NS_STYLE_ANIMATION_PLAY_STATE_PAUSED 1 // See nsStyleImageLayers -#define NS_STYLE_IMAGELAYER_ATTACHMENT_SCROLL 0 -#define NS_STYLE_IMAGELAYER_ATTACHMENT_FIXED 1 -#define NS_STYLE_IMAGELAYER_ATTACHMENT_LOCAL 2 +enum class StyleImageLayerAttachment : uint8_t { + Scroll, + Fixed, + Local +}; // A magic value that we use for our "pretend that background-clip is // 'padding' when we have a solid border" optimization. This isn't diff --git a/layout/style/nsStyleStruct.cpp b/layout/style/nsStyleStruct.cpp index d6b474f88078..9dc16bbb514e 100644 --- a/layout/style/nsStyleStruct.cpp +++ b/layout/style/nsStyleStruct.cpp @@ -3111,7 +3111,7 @@ nsStyleImageLayers::Size::operator==(const Size& aOther) const nsStyleImageLayers::Layer::Layer() : mClip(StyleGeometryBox::BorderBox) - , mAttachment(NS_STYLE_IMAGELAYER_ATTACHMENT_SCROLL) + , mAttachment(StyleImageLayerAttachment::Scroll) , mBlendMode(NS_STYLE_BLEND_NORMAL) , mComposite(NS_STYLE_MASK_COMPOSITE_ADD) , mMaskMode(NS_STYLE_MASK_MODE_MATCH_SOURCE) @@ -3350,7 +3350,7 @@ nsStyleBackground::HasFixedBackground(nsIFrame* aFrame) const { NS_FOR_VISIBLE_IMAGE_LAYERS_BACK_TO_FRONT(i, mImage) { const nsStyleImageLayers::Layer &layer = mImage.mLayers[i]; - if (layer.mAttachment == NS_STYLE_IMAGELAYER_ATTACHMENT_FIXED && + if (layer.mAttachment == StyleImageLayerAttachment::Fixed && !layer.mImage.IsEmpty() && !nsLayoutUtils::IsTransformed(aFrame)) { return true; diff --git a/layout/style/nsStyleStruct.h b/layout/style/nsStyleStruct.h index ca6475a77aed..ce8b08aa3d16 100644 --- a/layout/style/nsStyleStruct.h +++ b/layout/style/nsStyleStruct.h @@ -653,6 +653,7 @@ struct nsStyleImageLayers { struct Layer { typedef mozilla::StyleGeometryBox StyleGeometryBox; + typedef mozilla::StyleImageLayerAttachment StyleImageLayerAttachment; nsStyleImage mImage; // [reset] mozilla::Position mPosition; // [reset] @@ -660,12 +661,13 @@ struct nsStyleImageLayers { StyleGeometryBox mClip; // [reset] See nsStyleConsts.h MOZ_INIT_OUTSIDE_CTOR StyleGeometryBox mOrigin; // [reset] See nsStyleConsts.h - uint8_t mAttachment; // [reset] See nsStyleConsts.h + StyleImageLayerAttachment mAttachment; + // [reset] See nsStyleConsts.h // background-only property // This property is used for background layer // only. For a mask layer, it should always // be the initial value, which is - // NS_STYLE_IMAGELAYER_ATTACHMENT_SCROLL. + // StyleImageLayerAttachment::Scroll. uint8_t mBlendMode; // [reset] See nsStyleConsts.h // background-only property // This property is used for background layer diff --git a/layout/style/nsStyleStructInlines.h b/layout/style/nsStyleStructInlines.h index 5e0fd1accf04..48fd263e6c15 100644 --- a/layout/style/nsStyleStructInlines.h +++ b/layout/style/nsStyleStructInlines.h @@ -266,7 +266,7 @@ nsStyleBackground::HasLocalBackground() const NS_FOR_VISIBLE_IMAGE_LAYERS_BACK_TO_FRONT(i, mImage) { const nsStyleImageLayers::Layer& layer = mImage.mLayers[i]; if (!layer.mImage.IsEmpty() && - layer.mAttachment == NS_STYLE_IMAGELAYER_ATTACHMENT_LOCAL) { + layer.mAttachment == mozilla::StyleImageLayerAttachment::Local) { return true; } } diff --git a/media/libyuv/libyuv/source/convert_argb.cc.orig b/media/libyuv/libyuv/source/convert_argb.cc.orig deleted file mode 100644 index 4c317ae30c68..000000000000 --- a/media/libyuv/libyuv/source/convert_argb.cc.orig +++ /dev/null @@ -1,2199 +0,0 @@ -/* - * Copyright 2011 The LibYuv Project Authors. All rights reserved. - * - * Use of this source code is governed by a BSD-style license - * that can be found in the LICENSE file in the root of the source - * tree. An additional intellectual property rights grant can be found - * in the file PATENTS. All contributing project authors may - * be found in the AUTHORS file in the root of the source tree. - */ - -#include "libyuv/convert_argb.h" - -#include "libyuv/cpu_id.h" -#ifdef HAVE_JPEG -#include "libyuv/mjpeg_decoder.h" -#endif -#include "libyuv/planar_functions.h" // For CopyPlane and ARGBShuffle. -#include "libyuv/rotate_argb.h" -#include "libyuv/row.h" -#include "libyuv/video_common.h" - -#ifdef __cplusplus -namespace libyuv { -extern "C" { -#endif - -// Copy ARGB with optional flipping -LIBYUV_API -int ARGBCopy(const uint8_t* src_argb, - int src_stride_argb, - uint8_t* dst_argb, - int dst_stride_argb, - int width, - int height) { - if (!src_argb || !dst_argb || width <= 0 || height == 0) { - return -1; - } - // Negative height means invert the image. - if (height < 0) { - height = -height; - src_argb = src_argb + (height - 1) * src_stride_argb; - src_stride_argb = -src_stride_argb; - } - - CopyPlane(src_argb, src_stride_argb, dst_argb, dst_stride_argb, width * 4, - height); - return 0; -} - -// Convert I420 to ARGB with matrix -static int I420ToARGBMatrix(const uint8_t* src_y, - int src_stride_y, - const uint8_t* src_u, - int src_stride_u, - const uint8_t* src_v, - int src_stride_v, - uint8_t* dst_argb, - int dst_stride_argb, - const struct YuvConstants* yuvconstants, - int width, - int height) { - int y; - void (*I422ToARGBRow)(const uint8_t* y_buf, const uint8_t* u_buf, - const uint8_t* v_buf, uint8_t* rgb_buf, - const struct YuvConstants* yuvconstants, int width) = - I422ToARGBRow_C; - if (!src_y || !src_u || !src_v || !dst_argb || width <= 0 || height == 0) { - return -1; - } - // Negative height means invert the image. - if (height < 0) { - height = -height; - dst_argb = dst_argb + (height - 1) * dst_stride_argb; - dst_stride_argb = -dst_stride_argb; - } -#if defined(HAS_I422TOARGBROW_SSSE3) - if (TestCpuFlag(kCpuHasSSSE3)) { - I422ToARGBRow = I422ToARGBRow_Any_SSSE3; - if (IS_ALIGNED(width, 8)) { - I422ToARGBRow = I422ToARGBRow_SSSE3; - } - } -#endif -#if defined(HAS_I422TOARGBROW_AVX2) - if (TestCpuFlag(kCpuHasAVX2)) { - I422ToARGBRow = I422ToARGBRow_Any_AVX2; - if (IS_ALIGNED(width, 16)) { - I422ToARGBRow = I422ToARGBRow_AVX2; - } - } -#endif -#if defined(HAS_I422TOARGBROW_NEON) - if (TestCpuFlag(kCpuHasNEON)) { - I422ToARGBRow = I422ToARGBRow_Any_NEON; - if (IS_ALIGNED(width, 8)) { - I422ToARGBRow = I422ToARGBRow_NEON; - } - } -#endif -#if defined(HAS_I422TOARGBROW_MSA) - if (TestCpuFlag(kCpuHasMSA)) { - I422ToARGBRow = I422ToARGBRow_Any_MSA; - if (IS_ALIGNED(width, 8)) { - I422ToARGBRow = I422ToARGBRow_MSA; - } - } -#endif - - for (y = 0; y < height; ++y) { - I422ToARGBRow(src_y, src_u, src_v, dst_argb, yuvconstants, width); - dst_argb += dst_stride_argb; - src_y += src_stride_y; - if (y & 1) { - src_u += src_stride_u; - src_v += src_stride_v; - } - } - return 0; -} - -// Convert I420 to ARGB. -LIBYUV_API -int I420ToARGB(const uint8_t* src_y, - int src_stride_y, - const uint8_t* src_u, - int src_stride_u, - const uint8_t* src_v, - int src_stride_v, - uint8_t* dst_argb, - int dst_stride_argb, - int width, - int height) { - return I420ToARGBMatrix(src_y, src_stride_y, src_u, src_stride_u, src_v, - src_stride_v, dst_argb, dst_stride_argb, - &kYuvI601Constants, width, height); -} - -// Convert I420 to ABGR. -LIBYUV_API -int I420ToABGR(const uint8_t* src_y, - int src_stride_y, - const uint8_t* src_u, - int src_stride_u, - const uint8_t* src_v, - int src_stride_v, - uint8_t* dst_abgr, - int dst_stride_abgr, - int width, - int height) { - return I420ToARGBMatrix(src_y, src_stride_y, src_v, - src_stride_v, // Swap U and V - src_u, src_stride_u, dst_abgr, dst_stride_abgr, - &kYvuI601Constants, // Use Yvu matrix - width, height); -} - -// Convert J420 to ARGB. -LIBYUV_API -int J420ToARGB(const uint8_t* src_y, - int src_stride_y, - const uint8_t* src_u, - int src_stride_u, - const uint8_t* src_v, - int src_stride_v, - uint8_t* dst_argb, - int dst_stride_argb, - int width, - int height) { - return I420ToARGBMatrix(src_y, src_stride_y, src_u, src_stride_u, src_v, - src_stride_v, dst_argb, dst_stride_argb, - &kYuvJPEGConstants, width, height); -} - -// Convert J420 to ABGR. -LIBYUV_API -int J420ToABGR(const uint8_t* src_y, - int src_stride_y, - const uint8_t* src_u, - int src_stride_u, - const uint8_t* src_v, - int src_stride_v, - uint8_t* dst_abgr, - int dst_stride_abgr, - int width, - int height) { - return I420ToARGBMatrix(src_y, src_stride_y, src_v, - src_stride_v, // Swap U and V - src_u, src_stride_u, dst_abgr, dst_stride_abgr, - &kYvuJPEGConstants, // Use Yvu matrix - width, height); -} - -// Convert H420 to ARGB. -LIBYUV_API -int H420ToARGB(const uint8_t* src_y, - int src_stride_y, - const uint8_t* src_u, - int src_stride_u, - const uint8_t* src_v, - int src_stride_v, - uint8_t* dst_argb, - int dst_stride_argb, - int width, - int height) { - return I420ToARGBMatrix(src_y, src_stride_y, src_u, src_stride_u, src_v, - src_stride_v, dst_argb, dst_stride_argb, - &kYuvH709Constants, width, height); -} - -// Convert H420 to ABGR. -LIBYUV_API -int H420ToABGR(const uint8_t* src_y, - int src_stride_y, - const uint8_t* src_u, - int src_stride_u, - const uint8_t* src_v, - int src_stride_v, - uint8_t* dst_abgr, - int dst_stride_abgr, - int width, - int height) { - return I420ToARGBMatrix(src_y, src_stride_y, src_v, - src_stride_v, // Swap U and V - src_u, src_stride_u, dst_abgr, dst_stride_abgr, - &kYvuH709Constants, // Use Yvu matrix - width, height); -} - -// Convert I422 to ARGB with matrix -static int I422ToARGBMatrix(const uint8_t* src_y, - int src_stride_y, - const uint8_t* src_u, - int src_stride_u, - const uint8_t* src_v, - int src_stride_v, - uint8_t* dst_argb, - int dst_stride_argb, - const struct YuvConstants* yuvconstants, - int width, - int height) { - int y; - void (*I422ToARGBRow)(const uint8_t* y_buf, const uint8_t* u_buf, - const uint8_t* v_buf, uint8_t* rgb_buf, - const struct YuvConstants* yuvconstants, int width) = - I422ToARGBRow_C; - if (!src_y || !src_u || !src_v || !dst_argb || width <= 0 || height == 0) { - return -1; - } - // Negative height means invert the image. - if (height < 0) { - height = -height; - dst_argb = dst_argb + (height - 1) * dst_stride_argb; - dst_stride_argb = -dst_stride_argb; - } - // Coalesce rows. - if (src_stride_y == width && src_stride_u * 2 == width && - src_stride_v * 2 == width && dst_stride_argb == width * 4) { - width *= height; - height = 1; - src_stride_y = src_stride_u = src_stride_v = dst_stride_argb = 0; - } -#if defined(HAS_I422TOARGBROW_SSSE3) - if (TestCpuFlag(kCpuHasSSSE3)) { - I422ToARGBRow = I422ToARGBRow_Any_SSSE3; - if (IS_ALIGNED(width, 8)) { - I422ToARGBRow = I422ToARGBRow_SSSE3; - } - } -#endif -#if defined(HAS_I422TOARGBROW_AVX2) - if (TestCpuFlag(kCpuHasAVX2)) { - I422ToARGBRow = I422ToARGBRow_Any_AVX2; - if (IS_ALIGNED(width, 16)) { - I422ToARGBRow = I422ToARGBRow_AVX2; - } - } -#endif -#if defined(HAS_I422TOARGBROW_NEON) - if (TestCpuFlag(kCpuHasNEON)) { - I422ToARGBRow = I422ToARGBRow_Any_NEON; - if (IS_ALIGNED(width, 8)) { - I422ToARGBRow = I422ToARGBRow_NEON; - } - } -#endif -#if defined(HAS_I422TOARGBROW_MSA) - if (TestCpuFlag(kCpuHasMSA)) { - I422ToARGBRow = I422ToARGBRow_Any_MSA; - if (IS_ALIGNED(width, 8)) { - I422ToARGBRow = I422ToARGBRow_MSA; - } - } -#endif - - for (y = 0; y < height; ++y) { - I422ToARGBRow(src_y, src_u, src_v, dst_argb, yuvconstants, width); - dst_argb += dst_stride_argb; - src_y += src_stride_y; - src_u += src_stride_u; - src_v += src_stride_v; - } - return 0; -} - -// Convert I422 to ARGB. -LIBYUV_API -int I422ToARGB(const uint8_t* src_y, - int src_stride_y, - const uint8_t* src_u, - int src_stride_u, - const uint8_t* src_v, - int src_stride_v, - uint8_t* dst_argb, - int dst_stride_argb, - int width, - int height) { - return I422ToARGBMatrix(src_y, src_stride_y, src_u, src_stride_u, src_v, - src_stride_v, dst_argb, dst_stride_argb, - &kYuvI601Constants, width, height); -} - -// Convert I422 to ABGR. -LIBYUV_API -int I422ToABGR(const uint8_t* src_y, - int src_stride_y, - const uint8_t* src_u, - int src_stride_u, - const uint8_t* src_v, - int src_stride_v, - uint8_t* dst_abgr, - int dst_stride_abgr, - int width, - int height) { - return I422ToARGBMatrix(src_y, src_stride_y, src_v, - src_stride_v, // Swap U and V - src_u, src_stride_u, dst_abgr, dst_stride_abgr, - &kYvuI601Constants, // Use Yvu matrix - width, height); -} - -// Convert J422 to ARGB. -LIBYUV_API -int J422ToARGB(const uint8_t* src_y, - int src_stride_y, - const uint8_t* src_u, - int src_stride_u, - const uint8_t* src_v, - int src_stride_v, - uint8_t* dst_argb, - int dst_stride_argb, - int width, - int height) { - return I422ToARGBMatrix(src_y, src_stride_y, src_u, src_stride_u, src_v, - src_stride_v, dst_argb, dst_stride_argb, - &kYuvJPEGConstants, width, height); -} - -// Convert J422 to ABGR. -LIBYUV_API -int J422ToABGR(const uint8_t* src_y, - int src_stride_y, - const uint8_t* src_u, - int src_stride_u, - const uint8_t* src_v, - int src_stride_v, - uint8_t* dst_abgr, - int dst_stride_abgr, - int width, - int height) { - return I422ToARGBMatrix(src_y, src_stride_y, src_v, - src_stride_v, // Swap U and V - src_u, src_stride_u, dst_abgr, dst_stride_abgr, - &kYvuJPEGConstants, // Use Yvu matrix - width, height); -} - -// Convert H422 to ARGB. -LIBYUV_API -int H422ToARGB(const uint8_t* src_y, - int src_stride_y, - const uint8_t* src_u, - int src_stride_u, - const uint8_t* src_v, - int src_stride_v, - uint8_t* dst_argb, - int dst_stride_argb, - int width, - int height) { - return I422ToARGBMatrix(src_y, src_stride_y, src_u, src_stride_u, src_v, - src_stride_v, dst_argb, dst_stride_argb, - &kYuvH709Constants, width, height); -} - -// Convert H422 to ABGR. -LIBYUV_API -int H422ToABGR(const uint8_t* src_y, - int src_stride_y, - const uint8_t* src_u, - int src_stride_u, - const uint8_t* src_v, - int src_stride_v, - uint8_t* dst_abgr, - int dst_stride_abgr, - int width, - int height) { - return I422ToARGBMatrix(src_y, src_stride_y, src_v, - src_stride_v, // Swap U and V - src_u, src_stride_u, dst_abgr, dst_stride_abgr, - &kYvuH709Constants, // Use Yvu matrix - width, height); -} - -// Convert 10 bit YUV to ARGB with matrix -// TODO(fbarchard): Consider passing scale multiplier to I210ToARGB to -// multiply 10 bit yuv into high bits to allow any number of bits. -static int I010ToAR30Matrix(const uint16_t* src_y, - int src_stride_y, - const uint16_t* src_u, - int src_stride_u, - const uint16_t* src_v, - int src_stride_v, - uint8_t* dst_ar30, - int dst_stride_ar30, - const struct YuvConstants* yuvconstants, - int width, - int height) { - int y; - void (*I210ToAR30Row)(const uint16_t* y_buf, const uint16_t* u_buf, - const uint16_t* v_buf, uint8_t* rgb_buf, - const struct YuvConstants* yuvconstants, int width) = - I210ToAR30Row_C; - if (!src_y || !src_u || !src_v || !dst_ar30 || width <= 0 || height == 0) { - return -1; - } - // Negative height means invert the image. - if (height < 0) { - height = -height; - dst_ar30 = dst_ar30 + (height - 1) * dst_stride_ar30; - dst_stride_ar30 = -dst_stride_ar30; - } -#if defined(HAS_I210TOAR30ROW_SSSE3) - if (TestCpuFlag(kCpuHasSSSE3)) { - I210ToAR30Row = I210ToAR30Row_Any_SSSE3; - if (IS_ALIGNED(width, 8)) { - I210ToAR30Row = I210ToAR30Row_SSSE3; - } - } -#endif -#if defined(HAS_I210TOAR30ROW_AVX2) - if (TestCpuFlag(kCpuHasAVX2)) { - I210ToAR30Row = I210ToAR30Row_Any_AVX2; - if (IS_ALIGNED(width, 16)) { - I210ToAR30Row = I210ToAR30Row_AVX2; - } - } -#endif - for (y = 0; y < height; ++y) { - I210ToAR30Row(src_y, src_u, src_v, dst_ar30, yuvconstants, width); - dst_ar30 += dst_stride_ar30; - src_y += src_stride_y; - if (y & 1) { - src_u += src_stride_u; - src_v += src_stride_v; - } - } - return 0; -} - -// Convert I010 to AR30. -LIBYUV_API -int I010ToAR30(const uint16_t* src_y, - int src_stride_y, - const uint16_t* src_u, - int src_stride_u, - const uint16_t* src_v, - int src_stride_v, - uint8_t* dst_ar30, - int dst_stride_ar30, - int width, - int height) { - return I010ToAR30Matrix(src_y, src_stride_y, src_u, src_stride_u, src_v, - src_stride_v, dst_ar30, dst_stride_ar30, - &kYuvI601Constants, width, height); -} - -// Convert H010 to AR30. -LIBYUV_API -int H010ToAR30(const uint16_t* src_y, - int src_stride_y, - const uint16_t* src_u, - int src_stride_u, - const uint16_t* src_v, - int src_stride_v, - uint8_t* dst_ar30, - int dst_stride_ar30, - int width, - int height) { - return I010ToAR30Matrix(src_y, src_stride_y, src_u, src_stride_u, src_v, - src_stride_v, dst_ar30, dst_stride_ar30, - &kYuvH709Constants, width, height); -} - -// Convert I010 to AB30. -LIBYUV_API -int I010ToAB30(const uint16_t* src_y, - int src_stride_y, - const uint16_t* src_u, - int src_stride_u, - const uint16_t* src_v, - int src_stride_v, - uint8_t* dst_ab30, - int dst_stride_ab30, - int width, - int height) { - return I010ToAR30Matrix(src_y, src_stride_y, src_v, src_stride_v, src_u, - src_stride_u, dst_ab30, dst_stride_ab30, - &kYvuI601Constants, width, height); -} - -// Convert H010 to AB30. -LIBYUV_API -int H010ToAB30(const uint16_t* src_y, - int src_stride_y, - const uint16_t* src_u, - int src_stride_u, - const uint16_t* src_v, - int src_stride_v, - uint8_t* dst_ab30, - int dst_stride_ab30, - int width, - int height) { - return I010ToAR30Matrix(src_y, src_stride_y, src_v, src_stride_v, src_u, - src_stride_u, dst_ab30, dst_stride_ab30, - &kYvuH709Constants, width, height); -} - -// Convert 10 bit YUV to ARGB with matrix -static int I010ToARGBMatrix(const uint16_t* src_y, - int src_stride_y, - const uint16_t* src_u, - int src_stride_u, - const uint16_t* src_v, - int src_stride_v, - uint8_t* dst_argb, - int dst_stride_argb, - const struct YuvConstants* yuvconstants, - int width, - int height) { - int y; - void (*I210ToARGBRow)(const uint16_t* y_buf, const uint16_t* u_buf, - const uint16_t* v_buf, uint8_t* rgb_buf, - const struct YuvConstants* yuvconstants, int width) = - I210ToARGBRow_C; - if (!src_y || !src_u || !src_v || !dst_argb || width <= 0 || height == 0) { - return -1; - } - // Negative height means invert the image. - if (height < 0) { - height = -height; - dst_argb = dst_argb + (height - 1) * dst_stride_argb; - dst_stride_argb = -dst_stride_argb; - } -#if defined(HAS_I210TOARGBROW_SSSE3) - if (TestCpuFlag(kCpuHasSSSE3)) { - I210ToARGBRow = I210ToARGBRow_Any_SSSE3; - if (IS_ALIGNED(width, 8)) { - I210ToARGBRow = I210ToARGBRow_SSSE3; - } - } -#endif -#if defined(HAS_I210TOARGBROW_AVX2) - if (TestCpuFlag(kCpuHasAVX2)) { - I210ToARGBRow = I210ToARGBRow_Any_AVX2; - if (IS_ALIGNED(width, 16)) { - I210ToARGBRow = I210ToARGBRow_AVX2; - } - } -#endif - for (y = 0; y < height; ++y) { - I210ToARGBRow(src_y, src_u, src_v, dst_argb, yuvconstants, width); - dst_argb += dst_stride_argb; - src_y += src_stride_y; - if (y & 1) { - src_u += src_stride_u; - src_v += src_stride_v; - } - } - return 0; -} - -// Convert I010 to ARGB. -LIBYUV_API -int I010ToARGB(const uint16_t* src_y, - int src_stride_y, - const uint16_t* src_u, - int src_stride_u, - const uint16_t* src_v, - int src_stride_v, - uint8_t* dst_argb, - int dst_stride_argb, - int width, - int height) { - return I010ToARGBMatrix(src_y, src_stride_y, src_u, src_stride_u, src_v, - src_stride_v, dst_argb, dst_stride_argb, - &kYuvI601Constants, width, height); -} - -// Convert I010 to ABGR. -LIBYUV_API -int I010ToABGR(const uint16_t* src_y, - int src_stride_y, - const uint16_t* src_u, - int src_stride_u, - const uint16_t* src_v, - int src_stride_v, - uint8_t* dst_abgr, - int dst_stride_abgr, - int width, - int height) { - return I010ToARGBMatrix(src_y, src_stride_y, src_v, - src_stride_v, // Swap U and V - src_u, src_stride_u, dst_abgr, dst_stride_abgr, - &kYvuI601Constants, // Use Yvu matrix - width, height); -} - -// Convert H010 to ARGB. -LIBYUV_API -int H010ToARGB(const uint16_t* src_y, - int src_stride_y, - const uint16_t* src_u, - int src_stride_u, - const uint16_t* src_v, - int src_stride_v, - uint8_t* dst_argb, - int dst_stride_argb, - int width, - int height) { - return I010ToARGBMatrix(src_y, src_stride_y, src_u, src_stride_u, src_v, - src_stride_v, dst_argb, dst_stride_argb, - &kYuvH709Constants, width, height); -} - -// Convert H010 to ABGR. -LIBYUV_API -int H010ToABGR(const uint16_t* src_y, - int src_stride_y, - const uint16_t* src_u, - int src_stride_u, - const uint16_t* src_v, - int src_stride_v, - uint8_t* dst_abgr, - int dst_stride_abgr, - int width, - int height) { - return I010ToARGBMatrix(src_y, src_stride_y, src_v, - src_stride_v, // Swap U and V - src_u, src_stride_u, dst_abgr, dst_stride_abgr, - &kYvuH709Constants, // Use Yvu matrix - width, height); -} - -// Convert I444 to ARGB with matrix -static int I444ToARGBMatrix(const uint8_t* src_y, - int src_stride_y, - const uint8_t* src_u, - int src_stride_u, - const uint8_t* src_v, - int src_stride_v, - uint8_t* dst_argb, - int dst_stride_argb, - const struct YuvConstants* yuvconstants, - int width, - int height) { - int y; - void (*I444ToARGBRow)(const uint8_t* y_buf, const uint8_t* u_buf, - const uint8_t* v_buf, uint8_t* rgb_buf, - const struct YuvConstants* yuvconstants, int width) = - I444ToARGBRow_C; - if (!src_y || !src_u || !src_v || !dst_argb || width <= 0 || height == 0) { - return -1; - } - // Negative height means invert the image. - if (height < 0) { - height = -height; - dst_argb = dst_argb + (height - 1) * dst_stride_argb; - dst_stride_argb = -dst_stride_argb; - } - // Coalesce rows. - if (src_stride_y == width && src_stride_u == width && src_stride_v == width && - dst_stride_argb == width * 4) { - width *= height; - height = 1; - src_stride_y = src_stride_u = src_stride_v = dst_stride_argb = 0; - } -#if defined(HAS_I444TOARGBROW_SSSE3) - if (TestCpuFlag(kCpuHasSSSE3)) { - I444ToARGBRow = I444ToARGBRow_Any_SSSE3; - if (IS_ALIGNED(width, 8)) { - I444ToARGBRow = I444ToARGBRow_SSSE3; - } - } -#endif -#if defined(HAS_I444TOARGBROW_AVX2) - if (TestCpuFlag(kCpuHasAVX2)) { - I444ToARGBRow = I444ToARGBRow_Any_AVX2; - if (IS_ALIGNED(width, 16)) { - I444ToARGBRow = I444ToARGBRow_AVX2; - } - } -#endif -#if defined(HAS_I444TOARGBROW_NEON) - if (TestCpuFlag(kCpuHasNEON)) { - I444ToARGBRow = I444ToARGBRow_Any_NEON; - if (IS_ALIGNED(width, 8)) { - I444ToARGBRow = I444ToARGBRow_NEON; - } - } -#endif -#if defined(HAS_I444TOARGBROW_MSA) - if (TestCpuFlag(kCpuHasMSA)) { - I444ToARGBRow = I444ToARGBRow_Any_MSA; - if (IS_ALIGNED(width, 8)) { - I444ToARGBRow = I444ToARGBRow_MSA; - } - } -#endif - - for (y = 0; y < height; ++y) { - I444ToARGBRow(src_y, src_u, src_v, dst_argb, yuvconstants, width); - dst_argb += dst_stride_argb; - src_y += src_stride_y; - src_u += src_stride_u; - src_v += src_stride_v; - } - return 0; -} - -// Convert I444 to ARGB. -LIBYUV_API -int I444ToARGB(const uint8_t* src_y, - int src_stride_y, - const uint8_t* src_u, - int src_stride_u, - const uint8_t* src_v, - int src_stride_v, - uint8_t* dst_argb, - int dst_stride_argb, - int width, - int height) { - return I444ToARGBMatrix(src_y, src_stride_y, src_u, src_stride_u, src_v, - src_stride_v, dst_argb, dst_stride_argb, - &kYuvI601Constants, width, height); -} - -// Convert I444 to ABGR. -LIBYUV_API -int I444ToABGR(const uint8_t* src_y, - int src_stride_y, - const uint8_t* src_u, - int src_stride_u, - const uint8_t* src_v, - int src_stride_v, - uint8_t* dst_abgr, - int dst_stride_abgr, - int width, - int height) { - return I444ToARGBMatrix(src_y, src_stride_y, src_v, - src_stride_v, // Swap U and V - src_u, src_stride_u, dst_abgr, dst_stride_abgr, - &kYvuI601Constants, // Use Yvu matrix - width, height); -} - -// Convert J444 to ARGB. -LIBYUV_API -int J444ToARGB(const uint8_t* src_y, - int src_stride_y, - const uint8_t* src_u, - int src_stride_u, - const uint8_t* src_v, - int src_stride_v, - uint8_t* dst_argb, - int dst_stride_argb, - int width, - int height) { - return I444ToARGBMatrix(src_y, src_stride_y, src_u, src_stride_u, src_v, - src_stride_v, dst_argb, dst_stride_argb, - &kYuvJPEGConstants, width, height); -} - -// Convert I420 with Alpha to preattenuated ARGB. -static int I420AlphaToARGBMatrix(const uint8_t* src_y, - int src_stride_y, - const uint8_t* src_u, - int src_stride_u, - const uint8_t* src_v, - int src_stride_v, - const uint8_t* src_a, - int src_stride_a, - uint8_t* dst_argb, - int dst_stride_argb, - const struct YuvConstants* yuvconstants, - int width, - int height, - int attenuate) { - int y; - void (*I422AlphaToARGBRow)(const uint8_t* y_buf, const uint8_t* u_buf, - const uint8_t* v_buf, const uint8_t* a_buf, - uint8_t* dst_argb, - const struct YuvConstants* yuvconstants, - int width) = I422AlphaToARGBRow_C; - void (*ARGBAttenuateRow)(const uint8_t* src_argb, uint8_t* dst_argb, - int width) = ARGBAttenuateRow_C; - if (!src_y || !src_u || !src_v || !dst_argb || width <= 0 || height == 0) { - return -1; - } - // Negative height means invert the image. - if (height < 0) { - height = -height; - dst_argb = dst_argb + (height - 1) * dst_stride_argb; - dst_stride_argb = -dst_stride_argb; - } -#if defined(HAS_I422ALPHATOARGBROW_SSSE3) - if (TestCpuFlag(kCpuHasSSSE3)) { - I422AlphaToARGBRow = I422AlphaToARGBRow_Any_SSSE3; - if (IS_ALIGNED(width, 8)) { - I422AlphaToARGBRow = I422AlphaToARGBRow_SSSE3; - } - } -#endif -#if defined(HAS_I422ALPHATOARGBROW_AVX2) - if (TestCpuFlag(kCpuHasAVX2)) { - I422AlphaToARGBRow = I422AlphaToARGBRow_Any_AVX2; - if (IS_ALIGNED(width, 16)) { - I422AlphaToARGBRow = I422AlphaToARGBRow_AVX2; - } - } -#endif -#if defined(HAS_I422ALPHATOARGBROW_NEON) - if (TestCpuFlag(kCpuHasNEON)) { - I422AlphaToARGBRow = I422AlphaToARGBRow_Any_NEON; - if (IS_ALIGNED(width, 8)) { - I422AlphaToARGBRow = I422AlphaToARGBRow_NEON; - } - } -#endif -#if defined(HAS_I422ALPHATOARGBROW_MSA) - if (TestCpuFlag(kCpuHasMSA)) { - I422AlphaToARGBRow = I422AlphaToARGBRow_Any_MSA; - if (IS_ALIGNED(width, 8)) { - I422AlphaToARGBRow = I422AlphaToARGBRow_MSA; - } - } -#endif -#if defined(HAS_ARGBATTENUATEROW_SSSE3) - if (TestCpuFlag(kCpuHasSSSE3)) { - ARGBAttenuateRow = ARGBAttenuateRow_Any_SSSE3; - if (IS_ALIGNED(width, 4)) { - ARGBAttenuateRow = ARGBAttenuateRow_SSSE3; - } - } -#endif -#if defined(HAS_ARGBATTENUATEROW_AVX2) - if (TestCpuFlag(kCpuHasAVX2)) { - ARGBAttenuateRow = ARGBAttenuateRow_Any_AVX2; - if (IS_ALIGNED(width, 8)) { - ARGBAttenuateRow = ARGBAttenuateRow_AVX2; - } - } -#endif -#if defined(HAS_ARGBATTENUATEROW_NEON) - if (TestCpuFlag(kCpuHasNEON)) { - ARGBAttenuateRow = ARGBAttenuateRow_Any_NEON; - if (IS_ALIGNED(width, 8)) { - ARGBAttenuateRow = ARGBAttenuateRow_NEON; - } - } -#endif -#if defined(HAS_ARGBATTENUATEROW_MSA) - if (TestCpuFlag(kCpuHasMSA)) { - ARGBAttenuateRow = ARGBAttenuateRow_Any_MSA; - if (IS_ALIGNED(width, 8)) { - ARGBAttenuateRow = ARGBAttenuateRow_MSA; - } - } -#endif - - for (y = 0; y < height; ++y) { - I422AlphaToARGBRow(src_y, src_u, src_v, src_a, dst_argb, yuvconstants, - width); - if (attenuate) { - ARGBAttenuateRow(dst_argb, dst_argb, width); - } - dst_argb += dst_stride_argb; - src_a += src_stride_a; - src_y += src_stride_y; - if (y & 1) { - src_u += src_stride_u; - src_v += src_stride_v; - } - } - return 0; -} - -// Convert I420 with Alpha to ARGB. -LIBYUV_API -int I420AlphaToARGB(const uint8_t* src_y, - int src_stride_y, - const uint8_t* src_u, - int src_stride_u, - const uint8_t* src_v, - int src_stride_v, - const uint8_t* src_a, - int src_stride_a, - uint8_t* dst_argb, - int dst_stride_argb, - int width, - int height, - int attenuate) { - return I420AlphaToARGBMatrix(src_y, src_stride_y, src_u, src_stride_u, src_v, - src_stride_v, src_a, src_stride_a, dst_argb, - dst_stride_argb, &kYuvI601Constants, width, - height, attenuate); -} - -// Convert I420 with Alpha to ABGR. -LIBYUV_API -int I420AlphaToABGR(const uint8_t* src_y, - int src_stride_y, - const uint8_t* src_u, - int src_stride_u, - const uint8_t* src_v, - int src_stride_v, - const uint8_t* src_a, - int src_stride_a, - uint8_t* dst_abgr, - int dst_stride_abgr, - int width, - int height, - int attenuate) { - return I420AlphaToARGBMatrix( - src_y, src_stride_y, src_v, src_stride_v, // Swap U and V - src_u, src_stride_u, src_a, src_stride_a, dst_abgr, dst_stride_abgr, - &kYvuI601Constants, // Use Yvu matrix - width, height, attenuate); -} - -// Convert I400 to ARGB. -LIBYUV_API -int I400ToARGB(const uint8_t* src_y, - int src_stride_y, - uint8_t* dst_argb, - int dst_stride_argb, - int width, - int height) { - int y; - void (*I400ToARGBRow)(const uint8_t* y_buf, uint8_t* rgb_buf, int width) = - I400ToARGBRow_C; - if (!src_y || !dst_argb || width <= 0 || height == 0) { - return -1; - } - // Negative height means invert the image. - if (height < 0) { - height = -height; - dst_argb = dst_argb + (height - 1) * dst_stride_argb; - dst_stride_argb = -dst_stride_argb; - } - // Coalesce rows. - if (src_stride_y == width && dst_stride_argb == width * 4) { - width *= height; - height = 1; - src_stride_y = dst_stride_argb = 0; - } -#if defined(HAS_I400TOARGBROW_SSE2) - if (TestCpuFlag(kCpuHasSSE2)) { - I400ToARGBRow = I400ToARGBRow_Any_SSE2; - if (IS_ALIGNED(width, 8)) { - I400ToARGBRow = I400ToARGBRow_SSE2; - } - } -#endif -#if defined(HAS_I400TOARGBROW_AVX2) - if (TestCpuFlag(kCpuHasAVX2)) { - I400ToARGBRow = I400ToARGBRow_Any_AVX2; - if (IS_ALIGNED(width, 16)) { - I400ToARGBRow = I400ToARGBRow_AVX2; - } - } -#endif -#if defined(HAS_I400TOARGBROW_NEON) - if (TestCpuFlag(kCpuHasNEON)) { - I400ToARGBRow = I400ToARGBRow_Any_NEON; - if (IS_ALIGNED(width, 8)) { - I400ToARGBRow = I400ToARGBRow_NEON; - } - } -#endif -#if defined(HAS_I400TOARGBROW_MSA) - if (TestCpuFlag(kCpuHasMSA)) { - I400ToARGBRow = I400ToARGBRow_Any_MSA; - if (IS_ALIGNED(width, 16)) { - I400ToARGBRow = I400ToARGBRow_MSA; - } - } -#endif - - for (y = 0; y < height; ++y) { - I400ToARGBRow(src_y, dst_argb, width); - dst_argb += dst_stride_argb; - src_y += src_stride_y; - } - return 0; -} - -// Convert J400 to ARGB. -LIBYUV_API -int J400ToARGB(const uint8_t* src_y, - int src_stride_y, - uint8_t* dst_argb, - int dst_stride_argb, - int width, - int height) { - int y; - void (*J400ToARGBRow)(const uint8_t* src_y, uint8_t* dst_argb, int width) = - J400ToARGBRow_C; - if (!src_y || !dst_argb || width <= 0 || height == 0) { - return -1; - } - // Negative height means invert the image. - if (height < 0) { - height = -height; - src_y = src_y + (height - 1) * src_stride_y; - src_stride_y = -src_stride_y; - } - // Coalesce rows. - if (src_stride_y == width && dst_stride_argb == width * 4) { - width *= height; - height = 1; - src_stride_y = dst_stride_argb = 0; - } -#if defined(HAS_J400TOARGBROW_SSE2) - if (TestCpuFlag(kCpuHasSSE2)) { - J400ToARGBRow = J400ToARGBRow_Any_SSE2; - if (IS_ALIGNED(width, 8)) { - J400ToARGBRow = J400ToARGBRow_SSE2; - } - } -#endif -#if defined(HAS_J400TOARGBROW_AVX2) - if (TestCpuFlag(kCpuHasAVX2)) { - J400ToARGBRow = J400ToARGBRow_Any_AVX2; - if (IS_ALIGNED(width, 16)) { - J400ToARGBRow = J400ToARGBRow_AVX2; - } - } -#endif -#if defined(HAS_J400TOARGBROW_NEON) - if (TestCpuFlag(kCpuHasNEON)) { - J400ToARGBRow = J400ToARGBRow_Any_NEON; - if (IS_ALIGNED(width, 8)) { - J400ToARGBRow = J400ToARGBRow_NEON; - } - } -#endif -#if defined(HAS_J400TOARGBROW_MSA) - if (TestCpuFlag(kCpuHasMSA)) { - J400ToARGBRow = J400ToARGBRow_Any_MSA; - if (IS_ALIGNED(width, 16)) { - J400ToARGBRow = J400ToARGBRow_MSA; - } - } -#endif - for (y = 0; y < height; ++y) { - J400ToARGBRow(src_y, dst_argb, width); - src_y += src_stride_y; - dst_argb += dst_stride_argb; - } - return 0; -} - -// Shuffle table for converting BGRA to ARGB. -static const uvec8 kShuffleMaskBGRAToARGB = { - 3u, 2u, 1u, 0u, 7u, 6u, 5u, 4u, 11u, 10u, 9u, 8u, 15u, 14u, 13u, 12u}; - -// Shuffle table for converting ABGR to ARGB. -static const uvec8 kShuffleMaskABGRToARGB = { - 2u, 1u, 0u, 3u, 6u, 5u, 4u, 7u, 10u, 9u, 8u, 11u, 14u, 13u, 12u, 15u}; - -// Shuffle table for converting RGBA to ARGB. -static const uvec8 kShuffleMaskRGBAToARGB = { - 1u, 2u, 3u, 0u, 5u, 6u, 7u, 4u, 9u, 10u, 11u, 8u, 13u, 14u, 15u, 12u}; - -// Convert BGRA to ARGB. -LIBYUV_API -int BGRAToARGB(const uint8_t* src_bgra, - int src_stride_bgra, - uint8_t* dst_argb, - int dst_stride_argb, - int width, - int height) { - return ARGBShuffle(src_bgra, src_stride_bgra, dst_argb, dst_stride_argb, - (const uint8_t*)(&kShuffleMaskBGRAToARGB), width, height); -} - -// Convert ARGB to BGRA (same as BGRAToARGB). -LIBYUV_API -int ARGBToBGRA(const uint8_t* src_bgra, - int src_stride_bgra, - uint8_t* dst_argb, - int dst_stride_argb, - int width, - int height) { - return ARGBShuffle(src_bgra, src_stride_bgra, dst_argb, dst_stride_argb, - (const uint8_t*)(&kShuffleMaskBGRAToARGB), width, height); -} - -// Convert ABGR to ARGB. -LIBYUV_API -int ABGRToARGB(const uint8_t* src_abgr, - int src_stride_abgr, - uint8_t* dst_argb, - int dst_stride_argb, - int width, - int height) { - return ARGBShuffle(src_abgr, src_stride_abgr, dst_argb, dst_stride_argb, - (const uint8_t*)(&kShuffleMaskABGRToARGB), width, height); -} - -// Convert ARGB to ABGR to (same as ABGRToARGB). -LIBYUV_API -int ARGBToABGR(const uint8_t* src_abgr, - int src_stride_abgr, - uint8_t* dst_argb, - int dst_stride_argb, - int width, - int height) { - return ARGBShuffle(src_abgr, src_stride_abgr, dst_argb, dst_stride_argb, - (const uint8_t*)(&kShuffleMaskABGRToARGB), width, height); -} - -// Convert RGBA to ARGB. -LIBYUV_API -int RGBAToARGB(const uint8_t* src_rgba, - int src_stride_rgba, - uint8_t* dst_argb, - int dst_stride_argb, - int width, - int height) { - return ARGBShuffle(src_rgba, src_stride_rgba, dst_argb, dst_stride_argb, - (const uint8_t*)(&kShuffleMaskRGBAToARGB), width, height); -} - -// Convert RGB24 to ARGB. -LIBYUV_API -int RGB24ToARGB(const uint8_t* src_rgb24, - int src_stride_rgb24, - uint8_t* dst_argb, - int dst_stride_argb, - int width, - int height) { - int y; - void (*RGB24ToARGBRow)(const uint8_t* src_rgb, uint8_t* dst_argb, int width) = - RGB24ToARGBRow_C; - if (!src_rgb24 || !dst_argb || width <= 0 || height == 0) { - return -1; - } - // Negative height means invert the image. - if (height < 0) { - height = -height; - src_rgb24 = src_rgb24 + (height - 1) * src_stride_rgb24; - src_stride_rgb24 = -src_stride_rgb24; - } - // Coalesce rows. - if (src_stride_rgb24 == width * 3 && dst_stride_argb == width * 4) { - width *= height; - height = 1; - src_stride_rgb24 = dst_stride_argb = 0; - } -#if defined(HAS_RGB24TOARGBROW_SSSE3) - if (TestCpuFlag(kCpuHasSSSE3)) { - RGB24ToARGBRow = RGB24ToARGBRow_Any_SSSE3; - if (IS_ALIGNED(width, 16)) { - RGB24ToARGBRow = RGB24ToARGBRow_SSSE3; - } - } -#endif -#if defined(HAS_RGB24TOARGBROW_NEON) - if (TestCpuFlag(kCpuHasNEON)) { - RGB24ToARGBRow = RGB24ToARGBRow_Any_NEON; - if (IS_ALIGNED(width, 8)) { - RGB24ToARGBRow = RGB24ToARGBRow_NEON; - } - } -#endif -#if defined(HAS_RGB24TOARGBROW_MSA) - if (TestCpuFlag(kCpuHasMSA)) { - RGB24ToARGBRow = RGB24ToARGBRow_Any_MSA; - if (IS_ALIGNED(width, 16)) { - RGB24ToARGBRow = RGB24ToARGBRow_MSA; - } - } -#endif - - for (y = 0; y < height; ++y) { - RGB24ToARGBRow(src_rgb24, dst_argb, width); - src_rgb24 += src_stride_rgb24; - dst_argb += dst_stride_argb; - } - return 0; -} - -// Convert RAW to ARGB. -LIBYUV_API -int RAWToARGB(const uint8_t* src_raw, - int src_stride_raw, - uint8_t* dst_argb, - int dst_stride_argb, - int width, - int height) { - int y; - void (*RAWToARGBRow)(const uint8_t* src_rgb, uint8_t* dst_argb, int width) = - RAWToARGBRow_C; - if (!src_raw || !dst_argb || width <= 0 || height == 0) { - return -1; - } - // Negative height means invert the image. - if (height < 0) { - height = -height; - src_raw = src_raw + (height - 1) * src_stride_raw; - src_stride_raw = -src_stride_raw; - } - // Coalesce rows. - if (src_stride_raw == width * 3 && dst_stride_argb == width * 4) { - width *= height; - height = 1; - src_stride_raw = dst_stride_argb = 0; - } -#if defined(HAS_RAWTOARGBROW_SSSE3) - if (TestCpuFlag(kCpuHasSSSE3)) { - RAWToARGBRow = RAWToARGBRow_Any_SSSE3; - if (IS_ALIGNED(width, 16)) { - RAWToARGBRow = RAWToARGBRow_SSSE3; - } - } -#endif -#if defined(HAS_RAWTOARGBROW_NEON) - if (TestCpuFlag(kCpuHasNEON)) { - RAWToARGBRow = RAWToARGBRow_Any_NEON; - if (IS_ALIGNED(width, 8)) { - RAWToARGBRow = RAWToARGBRow_NEON; - } - } -#endif -#if defined(HAS_RAWTOARGBROW_MSA) - if (TestCpuFlag(kCpuHasMSA)) { - RAWToARGBRow = RAWToARGBRow_Any_MSA; - if (IS_ALIGNED(width, 16)) { - RAWToARGBRow = RAWToARGBRow_MSA; - } - } -#endif - - for (y = 0; y < height; ++y) { - RAWToARGBRow(src_raw, dst_argb, width); - src_raw += src_stride_raw; - dst_argb += dst_stride_argb; - } - return 0; -} - -// Convert RGB565 to ARGB. -LIBYUV_API -int RGB565ToARGB(const uint8_t* src_rgb565, - int src_stride_rgb565, - uint8_t* dst_argb, - int dst_stride_argb, - int width, - int height) { - int y; - void (*RGB565ToARGBRow)(const uint8_t* src_rgb565, uint8_t* dst_argb, - int width) = RGB565ToARGBRow_C; - if (!src_rgb565 || !dst_argb || width <= 0 || height == 0) { - return -1; - } - // Negative height means invert the image. - if (height < 0) { - height = -height; - src_rgb565 = src_rgb565 + (height - 1) * src_stride_rgb565; - src_stride_rgb565 = -src_stride_rgb565; - } - // Coalesce rows. - if (src_stride_rgb565 == width * 2 && dst_stride_argb == width * 4) { - width *= height; - height = 1; - src_stride_rgb565 = dst_stride_argb = 0; - } -#if defined(HAS_RGB565TOARGBROW_SSE2) - if (TestCpuFlag(kCpuHasSSE2)) { - RGB565ToARGBRow = RGB565ToARGBRow_Any_SSE2; - if (IS_ALIGNED(width, 8)) { - RGB565ToARGBRow = RGB565ToARGBRow_SSE2; - } - } -#endif -#if defined(HAS_RGB565TOARGBROW_AVX2) - if (TestCpuFlag(kCpuHasAVX2)) { - RGB565ToARGBRow = RGB565ToARGBRow_Any_AVX2; - if (IS_ALIGNED(width, 16)) { - RGB565ToARGBRow = RGB565ToARGBRow_AVX2; - } - } -#endif -#if defined(HAS_RGB565TOARGBROW_NEON) - if (TestCpuFlag(kCpuHasNEON)) { - RGB565ToARGBRow = RGB565ToARGBRow_Any_NEON; - if (IS_ALIGNED(width, 8)) { - RGB565ToARGBRow = RGB565ToARGBRow_NEON; - } - } -#endif -#if defined(HAS_RGB565TOARGBROW_MSA) - if (TestCpuFlag(kCpuHasMSA)) { - RGB565ToARGBRow = RGB565ToARGBRow_Any_MSA; - if (IS_ALIGNED(width, 16)) { - RGB565ToARGBRow = RGB565ToARGBRow_MSA; - } - } -#endif - - for (y = 0; y < height; ++y) { - RGB565ToARGBRow(src_rgb565, dst_argb, width); - src_rgb565 += src_stride_rgb565; - dst_argb += dst_stride_argb; - } - return 0; -} - -// Convert ARGB1555 to ARGB. -LIBYUV_API -int ARGB1555ToARGB(const uint8_t* src_argb1555, - int src_stride_argb1555, - uint8_t* dst_argb, - int dst_stride_argb, - int width, - int height) { - int y; - void (*ARGB1555ToARGBRow)(const uint8_t* src_argb1555, uint8_t* dst_argb, - int width) = ARGB1555ToARGBRow_C; - if (!src_argb1555 || !dst_argb || width <= 0 || height == 0) { - return -1; - } - // Negative height means invert the image. - if (height < 0) { - height = -height; - src_argb1555 = src_argb1555 + (height - 1) * src_stride_argb1555; - src_stride_argb1555 = -src_stride_argb1555; - } - // Coalesce rows. - if (src_stride_argb1555 == width * 2 && dst_stride_argb == width * 4) { - width *= height; - height = 1; - src_stride_argb1555 = dst_stride_argb = 0; - } -#if defined(HAS_ARGB1555TOARGBROW_SSE2) - if (TestCpuFlag(kCpuHasSSE2)) { - ARGB1555ToARGBRow = ARGB1555ToARGBRow_Any_SSE2; - if (IS_ALIGNED(width, 8)) { - ARGB1555ToARGBRow = ARGB1555ToARGBRow_SSE2; - } - } -#endif -#if defined(HAS_ARGB1555TOARGBROW_AVX2) - if (TestCpuFlag(kCpuHasAVX2)) { - ARGB1555ToARGBRow = ARGB1555ToARGBRow_Any_AVX2; - if (IS_ALIGNED(width, 16)) { - ARGB1555ToARGBRow = ARGB1555ToARGBRow_AVX2; - } - } -#endif -#if defined(HAS_ARGB1555TOARGBROW_NEON) - if (TestCpuFlag(kCpuHasNEON)) { - ARGB1555ToARGBRow = ARGB1555ToARGBRow_Any_NEON; - if (IS_ALIGNED(width, 8)) { - ARGB1555ToARGBRow = ARGB1555ToARGBRow_NEON; - } - } -#endif -#if defined(HAS_ARGB1555TOARGBROW_MSA) - if (TestCpuFlag(kCpuHasMSA)) { - ARGB1555ToARGBRow = ARGB1555ToARGBRow_Any_MSA; - if (IS_ALIGNED(width, 16)) { - ARGB1555ToARGBRow = ARGB1555ToARGBRow_MSA; - } - } -#endif - - for (y = 0; y < height; ++y) { - ARGB1555ToARGBRow(src_argb1555, dst_argb, width); - src_argb1555 += src_stride_argb1555; - dst_argb += dst_stride_argb; - } - return 0; -} - -// Convert ARGB4444 to ARGB. -LIBYUV_API -int ARGB4444ToARGB(const uint8_t* src_argb4444, - int src_stride_argb4444, - uint8_t* dst_argb, - int dst_stride_argb, - int width, - int height) { - int y; - void (*ARGB4444ToARGBRow)(const uint8_t* src_argb4444, uint8_t* dst_argb, - int width) = ARGB4444ToARGBRow_C; - if (!src_argb4444 || !dst_argb || width <= 0 || height == 0) { - return -1; - } - // Negative height means invert the image. - if (height < 0) { - height = -height; - src_argb4444 = src_argb4444 + (height - 1) * src_stride_argb4444; - src_stride_argb4444 = -src_stride_argb4444; - } - // Coalesce rows. - if (src_stride_argb4444 == width * 2 && dst_stride_argb == width * 4) { - width *= height; - height = 1; - src_stride_argb4444 = dst_stride_argb = 0; - } -#if defined(HAS_ARGB4444TOARGBROW_SSE2) - if (TestCpuFlag(kCpuHasSSE2)) { - ARGB4444ToARGBRow = ARGB4444ToARGBRow_Any_SSE2; - if (IS_ALIGNED(width, 8)) { - ARGB4444ToARGBRow = ARGB4444ToARGBRow_SSE2; - } - } -#endif -#if defined(HAS_ARGB4444TOARGBROW_AVX2) - if (TestCpuFlag(kCpuHasAVX2)) { - ARGB4444ToARGBRow = ARGB4444ToARGBRow_Any_AVX2; - if (IS_ALIGNED(width, 16)) { - ARGB4444ToARGBRow = ARGB4444ToARGBRow_AVX2; - } - } -#endif -#if defined(HAS_ARGB4444TOARGBROW_NEON) - if (TestCpuFlag(kCpuHasNEON)) { - ARGB4444ToARGBRow = ARGB4444ToARGBRow_Any_NEON; - if (IS_ALIGNED(width, 8)) { - ARGB4444ToARGBRow = ARGB4444ToARGBRow_NEON; - } - } -#endif -#if defined(HAS_ARGB4444TOARGBROW_MSA) - if (TestCpuFlag(kCpuHasMSA)) { - ARGB4444ToARGBRow = ARGB4444ToARGBRow_Any_MSA; - if (IS_ALIGNED(width, 16)) { - ARGB4444ToARGBRow = ARGB4444ToARGBRow_MSA; - } - } -#endif - - for (y = 0; y < height; ++y) { - ARGB4444ToARGBRow(src_argb4444, dst_argb, width); - src_argb4444 += src_stride_argb4444; - dst_argb += dst_stride_argb; - } - return 0; -} - -// Convert AR30 to ARGB. -LIBYUV_API -int AR30ToARGB(const uint8_t* src_ar30, - int src_stride_ar30, - uint8_t* dst_argb, - int dst_stride_argb, - int width, - int height) { - int y; - if (!src_ar30 || !dst_argb || width <= 0 || height == 0) { - return -1; - } - // Negative height means invert the image. - if (height < 0) { - height = -height; - src_ar30 = src_ar30 + (height - 1) * src_stride_ar30; - src_stride_ar30 = -src_stride_ar30; - } - // Coalesce rows. - if (src_stride_ar30 == width * 4 && dst_stride_argb == width * 4) { - width *= height; - height = 1; - src_stride_ar30 = dst_stride_argb = 0; - } - for (y = 0; y < height; ++y) { - AR30ToARGBRow_C(src_ar30, dst_argb, width); - src_ar30 += src_stride_ar30; - dst_argb += dst_stride_argb; - } - return 0; -} - -// Convert AR30 to ABGR. -LIBYUV_API -int AR30ToABGR(const uint8_t* src_ar30, - int src_stride_ar30, - uint8_t* dst_abgr, - int dst_stride_abgr, - int width, - int height) { - int y; - if (!src_ar30 || !dst_abgr || width <= 0 || height == 0) { - return -1; - } - // Negative height means invert the image. - if (height < 0) { - height = -height; - src_ar30 = src_ar30 + (height - 1) * src_stride_ar30; - src_stride_ar30 = -src_stride_ar30; - } - // Coalesce rows. - if (src_stride_ar30 == width * 4 && dst_stride_abgr == width * 4) { - width *= height; - height = 1; - src_stride_ar30 = dst_stride_abgr = 0; - } - for (y = 0; y < height; ++y) { - AR30ToABGRRow_C(src_ar30, dst_abgr, width); - src_ar30 += src_stride_ar30; - dst_abgr += dst_stride_abgr; - } - return 0; -} - -// Convert AR30 to AB30. -LIBYUV_API -int AR30ToAB30(const uint8_t* src_ar30, - int src_stride_ar30, - uint8_t* dst_ab30, - int dst_stride_ab30, - int width, - int height) { - int y; - if (!src_ar30 || !dst_ab30 || width <= 0 || height == 0) { - return -1; - } - // Negative height means invert the image. - if (height < 0) { - height = -height; - src_ar30 = src_ar30 + (height - 1) * src_stride_ar30; - src_stride_ar30 = -src_stride_ar30; - } - // Coalesce rows. - if (src_stride_ar30 == width * 4 && dst_stride_ab30 == width * 4) { - width *= height; - height = 1; - src_stride_ar30 = dst_stride_ab30 = 0; - } - for (y = 0; y < height; ++y) { - AR30ToAB30Row_C(src_ar30, dst_ab30, width); - src_ar30 += src_stride_ar30; - dst_ab30 += dst_stride_ab30; - } - return 0; -} - -// Convert NV12 to ARGB with matrix -static int NV12ToARGBMatrix(const uint8_t* src_y, - int src_stride_y, - const uint8_t* src_uv, - int src_stride_uv, - uint8_t* dst_argb, - int dst_stride_argb, - const struct YuvConstants* yuvconstants, - int width, - int height) { - int y; - void (*NV12ToARGBRow)( - const uint8_t* y_buf, const uint8_t* uv_buf, uint8_t* rgb_buf, - const struct YuvConstants* yuvconstants, int width) = NV12ToARGBRow_C; - if (!src_y || !src_uv || !dst_argb || width <= 0 || height == 0) { - return -1; - } - // Negative height means invert the image. - if (height < 0) { - height = -height; - dst_argb = dst_argb + (height - 1) * dst_stride_argb; - dst_stride_argb = -dst_stride_argb; - } -#if defined(HAS_NV12TOARGBROW_SSSE3) - if (TestCpuFlag(kCpuHasSSSE3)) { - NV12ToARGBRow = NV12ToARGBRow_Any_SSSE3; - if (IS_ALIGNED(width, 8)) { - NV12ToARGBRow = NV12ToARGBRow_SSSE3; - } - } -#endif -#if defined(HAS_NV12TOARGBROW_AVX2) - if (TestCpuFlag(kCpuHasAVX2)) { - NV12ToARGBRow = NV12ToARGBRow_Any_AVX2; - if (IS_ALIGNED(width, 16)) { - NV12ToARGBRow = NV12ToARGBRow_AVX2; - } - } -#endif -#if defined(HAS_NV12TOARGBROW_NEON) - if (TestCpuFlag(kCpuHasNEON)) { - NV12ToARGBRow = NV12ToARGBRow_Any_NEON; - if (IS_ALIGNED(width, 8)) { - NV12ToARGBRow = NV12ToARGBRow_NEON; - } - } -#endif -#if defined(HAS_NV12TOARGBROW_MSA) - if (TestCpuFlag(kCpuHasMSA)) { - NV12ToARGBRow = NV12ToARGBRow_Any_MSA; - if (IS_ALIGNED(width, 8)) { - NV12ToARGBRow = NV12ToARGBRow_MSA; - } - } -#endif - - for (y = 0; y < height; ++y) { - NV12ToARGBRow(src_y, src_uv, dst_argb, yuvconstants, width); - dst_argb += dst_stride_argb; - src_y += src_stride_y; - if (y & 1) { - src_uv += src_stride_uv; - } - } - return 0; -} - -// Convert NV21 to ARGB with matrix -static int NV21ToARGBMatrix(const uint8_t* src_y, - int src_stride_y, - const uint8_t* src_vu, - int src_stride_vu, - uint8_t* dst_argb, - int dst_stride_argb, - const struct YuvConstants* yuvconstants, - int width, - int height) { - int y; - void (*NV21ToARGBRow)( - const uint8_t* y_buf, const uint8_t* uv_buf, uint8_t* rgb_buf, - const struct YuvConstants* yuvconstants, int width) = NV21ToARGBRow_C; - if (!src_y || !src_vu || !dst_argb || width <= 0 || height == 0) { - return -1; - } - // Negative height means invert the image. - if (height < 0) { - height = -height; - dst_argb = dst_argb + (height - 1) * dst_stride_argb; - dst_stride_argb = -dst_stride_argb; - } -#if defined(HAS_NV21TOARGBROW_SSSE3) - if (TestCpuFlag(kCpuHasSSSE3)) { - NV21ToARGBRow = NV21ToARGBRow_Any_SSSE3; - if (IS_ALIGNED(width, 8)) { - NV21ToARGBRow = NV21ToARGBRow_SSSE3; - } - } -#endif -#if defined(HAS_NV21TOARGBROW_AVX2) - if (TestCpuFlag(kCpuHasAVX2)) { - NV21ToARGBRow = NV21ToARGBRow_Any_AVX2; - if (IS_ALIGNED(width, 16)) { - NV21ToARGBRow = NV21ToARGBRow_AVX2; - } - } -#endif -#if defined(HAS_NV21TOARGBROW_NEON) - if (TestCpuFlag(kCpuHasNEON)) { - NV21ToARGBRow = NV21ToARGBRow_Any_NEON; - if (IS_ALIGNED(width, 8)) { - NV21ToARGBRow = NV21ToARGBRow_NEON; - } - } -#endif -#if defined(HAS_NV21TOARGBROW_MSA) - if (TestCpuFlag(kCpuHasMSA)) { - NV21ToARGBRow = NV21ToARGBRow_Any_MSA; - if (IS_ALIGNED(width, 8)) { - NV21ToARGBRow = NV21ToARGBRow_MSA; - } - } -#endif - - for (y = 0; y < height; ++y) { - NV21ToARGBRow(src_y, src_vu, dst_argb, yuvconstants, width); - dst_argb += dst_stride_argb; - src_y += src_stride_y; - if (y & 1) { - src_vu += src_stride_vu; - } - } - return 0; -} - -// Convert NV12 to ARGB. -LIBYUV_API -int NV12ToARGB(const uint8_t* src_y, - int src_stride_y, - const uint8_t* src_uv, - int src_stride_uv, - uint8_t* dst_argb, - int dst_stride_argb, - int width, - int height) { - return NV12ToARGBMatrix(src_y, src_stride_y, src_uv, src_stride_uv, dst_argb, - dst_stride_argb, &kYuvI601Constants, width, height); -} - -// Convert NV21 to ARGB. -LIBYUV_API -int NV21ToARGB(const uint8_t* src_y, - int src_stride_y, - const uint8_t* src_vu, - int src_stride_vu, - uint8_t* dst_argb, - int dst_stride_argb, - int width, - int height) { - return NV21ToARGBMatrix(src_y, src_stride_y, src_vu, src_stride_vu, dst_argb, - dst_stride_argb, &kYuvI601Constants, width, height); -} - -// Convert NV12 to ABGR. -// To output ABGR instead of ARGB swap the UV and use a mirrrored yuc matrix. -// To swap the UV use NV12 instead of NV21.LIBYUV_API -int NV12ToABGR(const uint8_t* src_y, - int src_stride_y, - const uint8_t* src_uv, - int src_stride_uv, - uint8_t* dst_abgr, - int dst_stride_abgr, - int width, - int height) { - return NV21ToARGBMatrix(src_y, src_stride_y, src_uv, src_stride_uv, dst_abgr, - dst_stride_abgr, &kYvuI601Constants, width, height); -} - -// Convert NV21 to ABGR. -LIBYUV_API -int NV21ToABGR(const uint8_t* src_y, - int src_stride_y, - const uint8_t* src_vu, - int src_stride_vu, - uint8_t* dst_abgr, - int dst_stride_abgr, - int width, - int height) { - return NV12ToARGBMatrix(src_y, src_stride_y, src_vu, src_stride_vu, dst_abgr, - dst_stride_abgr, &kYvuI601Constants, width, height); -} - -// TODO(fbarchard): Consider SSSE3 2 step conversion. -// Convert NV12 to RGB24 with matrix -static int NV12ToRGB24Matrix(const uint8_t* src_y, - int src_stride_y, - const uint8_t* src_uv, - int src_stride_uv, - uint8_t* dst_rgb24, - int dst_stride_rgb24, - const struct YuvConstants* yuvconstants, - int width, - int height) { - int y; - void (*NV12ToRGB24Row)( - const uint8_t* y_buf, const uint8_t* uv_buf, uint8_t* rgb_buf, - const struct YuvConstants* yuvconstants, int width) = NV12ToRGB24Row_C; - if (!src_y || !src_uv || !dst_rgb24 || width <= 0 || height == 0) { - return -1; - } - // Negative height means invert the image. - if (height < 0) { - height = -height; - dst_rgb24 = dst_rgb24 + (height - 1) * dst_stride_rgb24; - dst_stride_rgb24 = -dst_stride_rgb24; - } -#if defined(HAS_NV12TORGB24ROW_NEON) - if (TestCpuFlag(kCpuHasNEON)) { - NV12ToRGB24Row = NV12ToRGB24Row_Any_NEON; - if (IS_ALIGNED(width, 8)) { - NV12ToRGB24Row = NV12ToRGB24Row_NEON; - } - } -#endif - - for (y = 0; y < height; ++y) { - NV12ToRGB24Row(src_y, src_uv, dst_rgb24, yuvconstants, width); - dst_rgb24 += dst_stride_rgb24; - src_y += src_stride_y; - if (y & 1) { - src_uv += src_stride_uv; - } - } - return 0; -} - -// Convert NV21 to RGB24 with matrix -static int NV21ToRGB24Matrix(const uint8_t* src_y, - int src_stride_y, - const uint8_t* src_vu, - int src_stride_vu, - uint8_t* dst_rgb24, - int dst_stride_rgb24, - const struct YuvConstants* yuvconstants, - int width, - int height) { - int y; - void (*NV21ToRGB24Row)( - const uint8_t* y_buf, const uint8_t* uv_buf, uint8_t* rgb_buf, - const struct YuvConstants* yuvconstants, int width) = NV21ToRGB24Row_C; - if (!src_y || !src_vu || !dst_rgb24 || width <= 0 || height == 0) { - return -1; - } - // Negative height means invert the image. - if (height < 0) { - height = -height; - dst_rgb24 = dst_rgb24 + (height - 1) * dst_stride_rgb24; - dst_stride_rgb24 = -dst_stride_rgb24; - } -#if defined(HAS_NV21TORGB24ROW_NEON) - if (TestCpuFlag(kCpuHasNEON)) { - NV21ToRGB24Row = NV21ToRGB24Row_Any_NEON; - if (IS_ALIGNED(width, 8)) { - NV21ToRGB24Row = NV21ToRGB24Row_NEON; - } - } -#endif - - for (y = 0; y < height; ++y) { - NV21ToRGB24Row(src_y, src_vu, dst_rgb24, yuvconstants, width); - dst_rgb24 += dst_stride_rgb24; - src_y += src_stride_y; - if (y & 1) { - src_vu += src_stride_vu; - } - } - return 0; -} - -// TODO(fbarchard): \(fbarchard): NV12ToRAW can be implemented by mirrored -// matrix. Convert NV12 to RGB24. -LIBYUV_API -int NV12ToRGB24(const uint8_t* src_y, - int src_stride_y, - const uint8_t* src_uv, - int src_stride_uv, - uint8_t* dst_rgb24, - int dst_stride_rgb24, - int width, - int height) { - return NV12ToRGB24Matrix(src_y, src_stride_y, src_uv, src_stride_uv, - dst_rgb24, dst_stride_rgb24, &kYuvI601Constants, - width, height); -} - -// Convert NV21 to RGB24. -LIBYUV_API -int NV21ToRGB24(const uint8_t* src_y, - int src_stride_y, - const uint8_t* src_vu, - int src_stride_vu, - uint8_t* dst_rgb24, - int dst_stride_rgb24, - int width, - int height) { - return NV21ToRGB24Matrix(src_y, src_stride_y, src_vu, src_stride_vu, - dst_rgb24, dst_stride_rgb24, &kYuvI601Constants, - width, height); -} - -// Convert M420 to ARGB. -LIBYUV_API -int M420ToARGB(const uint8_t* src_m420, - int src_stride_m420, - uint8_t* dst_argb, - int dst_stride_argb, - int width, - int height) { - int y; - void (*NV12ToARGBRow)( - const uint8_t* y_buf, const uint8_t* uv_buf, uint8_t* rgb_buf, - const struct YuvConstants* yuvconstants, int width) = NV12ToARGBRow_C; - if (!src_m420 || !dst_argb || width <= 0 || height == 0) { - return -1; - } - // Negative height means invert the image. - if (height < 0) { - height = -height; - dst_argb = dst_argb + (height - 1) * dst_stride_argb; - dst_stride_argb = -dst_stride_argb; - } -#if defined(HAS_NV12TOARGBROW_SSSE3) - if (TestCpuFlag(kCpuHasSSSE3)) { - NV12ToARGBRow = NV12ToARGBRow_Any_SSSE3; - if (IS_ALIGNED(width, 8)) { - NV12ToARGBRow = NV12ToARGBRow_SSSE3; - } - } -#endif -#if defined(HAS_NV12TOARGBROW_AVX2) - if (TestCpuFlag(kCpuHasAVX2)) { - NV12ToARGBRow = NV12ToARGBRow_Any_AVX2; - if (IS_ALIGNED(width, 16)) { - NV12ToARGBRow = NV12ToARGBRow_AVX2; - } - } -#endif -#if defined(HAS_NV12TOARGBROW_NEON) - if (TestCpuFlag(kCpuHasNEON)) { - NV12ToARGBRow = NV12ToARGBRow_Any_NEON; - if (IS_ALIGNED(width, 8)) { - NV12ToARGBRow = NV12ToARGBRow_NEON; - } - } -#endif -#if defined(HAS_NV12TOARGBROW_MSA) - if (TestCpuFlag(kCpuHasMSA)) { - NV12ToARGBRow = NV12ToARGBRow_Any_MSA; - if (IS_ALIGNED(width, 8)) { - NV12ToARGBRow = NV12ToARGBRow_MSA; - } - } -#endif - - for (y = 0; y < height - 1; y += 2) { - NV12ToARGBRow(src_m420, src_m420 + src_stride_m420 * 2, dst_argb, - &kYuvI601Constants, width); - NV12ToARGBRow(src_m420 + src_stride_m420, src_m420 + src_stride_m420 * 2, - dst_argb + dst_stride_argb, &kYuvI601Constants, width); - dst_argb += dst_stride_argb * 2; - src_m420 += src_stride_m420 * 3; - } - if (height & 1) { - NV12ToARGBRow(src_m420, src_m420 + src_stride_m420 * 2, dst_argb, - &kYuvI601Constants, width); - } - return 0; -} - -// Convert YUY2 to ARGB. -LIBYUV_API -int YUY2ToARGB(const uint8_t* src_yuy2, - int src_stride_yuy2, - uint8_t* dst_argb, - int dst_stride_argb, - int width, - int height) { - int y; - void (*YUY2ToARGBRow)(const uint8_t* src_yuy2, uint8_t* dst_argb, - const struct YuvConstants* yuvconstants, int width) = - YUY2ToARGBRow_C; - if (!src_yuy2 || !dst_argb || width <= 0 || height == 0) { - return -1; - } - // Negative height means invert the image. - if (height < 0) { - height = -height; - src_yuy2 = src_yuy2 + (height - 1) * src_stride_yuy2; - src_stride_yuy2 = -src_stride_yuy2; - } - // Coalesce rows. - if (src_stride_yuy2 == width * 2 && dst_stride_argb == width * 4) { - width *= height; - height = 1; - src_stride_yuy2 = dst_stride_argb = 0; - } -#if defined(HAS_YUY2TOARGBROW_SSSE3) - if (TestCpuFlag(kCpuHasSSSE3)) { - YUY2ToARGBRow = YUY2ToARGBRow_Any_SSSE3; - if (IS_ALIGNED(width, 16)) { - YUY2ToARGBRow = YUY2ToARGBRow_SSSE3; - } - } -#endif -#if defined(HAS_YUY2TOARGBROW_AVX2) - if (TestCpuFlag(kCpuHasAVX2)) { - YUY2ToARGBRow = YUY2ToARGBRow_Any_AVX2; - if (IS_ALIGNED(width, 32)) { - YUY2ToARGBRow = YUY2ToARGBRow_AVX2; - } - } -#endif -#if defined(HAS_YUY2TOARGBROW_NEON) - if (TestCpuFlag(kCpuHasNEON)) { - YUY2ToARGBRow = YUY2ToARGBRow_Any_NEON; - if (IS_ALIGNED(width, 8)) { - YUY2ToARGBRow = YUY2ToARGBRow_NEON; - } - } -#endif -#if defined(HAS_YUY2TOARGBROW_MSA) - if (TestCpuFlag(kCpuHasMSA)) { - YUY2ToARGBRow = YUY2ToARGBRow_Any_MSA; - if (IS_ALIGNED(width, 8)) { - YUY2ToARGBRow = YUY2ToARGBRow_MSA; - } - } -#endif - for (y = 0; y < height; ++y) { - YUY2ToARGBRow(src_yuy2, dst_argb, &kYuvI601Constants, width); - src_yuy2 += src_stride_yuy2; - dst_argb += dst_stride_argb; - } - return 0; -} - -// Convert UYVY to ARGB. -LIBYUV_API -int UYVYToARGB(const uint8_t* src_uyvy, - int src_stride_uyvy, - uint8_t* dst_argb, - int dst_stride_argb, - int width, - int height) { - int y; - void (*UYVYToARGBRow)(const uint8_t* src_uyvy, uint8_t* dst_argb, - const struct YuvConstants* yuvconstants, int width) = - UYVYToARGBRow_C; - if (!src_uyvy || !dst_argb || width <= 0 || height == 0) { - return -1; - } - // Negative height means invert the image. - if (height < 0) { - height = -height; - src_uyvy = src_uyvy + (height - 1) * src_stride_uyvy; - src_stride_uyvy = -src_stride_uyvy; - } - // Coalesce rows. - if (src_stride_uyvy == width * 2 && dst_stride_argb == width * 4) { - width *= height; - height = 1; - src_stride_uyvy = dst_stride_argb = 0; - } -#if defined(HAS_UYVYTOARGBROW_SSSE3) - if (TestCpuFlag(kCpuHasSSSE3)) { - UYVYToARGBRow = UYVYToARGBRow_Any_SSSE3; - if (IS_ALIGNED(width, 16)) { - UYVYToARGBRow = UYVYToARGBRow_SSSE3; - } - } -#endif -#if defined(HAS_UYVYTOARGBROW_AVX2) - if (TestCpuFlag(kCpuHasAVX2)) { - UYVYToARGBRow = UYVYToARGBRow_Any_AVX2; - if (IS_ALIGNED(width, 32)) { - UYVYToARGBRow = UYVYToARGBRow_AVX2; - } - } -#endif -#if defined(HAS_UYVYTOARGBROW_NEON) - if (TestCpuFlag(kCpuHasNEON)) { - UYVYToARGBRow = UYVYToARGBRow_Any_NEON; - if (IS_ALIGNED(width, 8)) { - UYVYToARGBRow = UYVYToARGBRow_NEON; - } - } -#endif -#if defined(HAS_UYVYTOARGBROW_MSA) - if (TestCpuFlag(kCpuHasMSA)) { - UYVYToARGBRow = UYVYToARGBRow_Any_MSA; - if (IS_ALIGNED(width, 8)) { - UYVYToARGBRow = UYVYToARGBRow_MSA; - } - } -#endif - for (y = 0; y < height; ++y) { - UYVYToARGBRow(src_uyvy, dst_argb, &kYuvI601Constants, width); - src_uyvy += src_stride_uyvy; - dst_argb += dst_stride_argb; - } - return 0; -} -static void WeavePixels(const uint8_t* src_u, - const uint8_t* src_v, - int src_pixel_stride_uv, - uint8_t* dst_uv, - int width) { - int i; - for (i = 0; i < width; ++i) { - dst_uv[0] = *src_u; - dst_uv[1] = *src_v; - dst_uv += 2; - src_u += src_pixel_stride_uv; - src_v += src_pixel_stride_uv; - } -} - -// Convert Android420 to ARGB. -LIBYUV_API -int Android420ToARGBMatrix(const uint8_t* src_y, - int src_stride_y, - const uint8_t* src_u, - int src_stride_u, - const uint8_t* src_v, - int src_stride_v, - int src_pixel_stride_uv, - uint8_t* dst_argb, - int dst_stride_argb, - const struct YuvConstants* yuvconstants, - int width, - int height) { - int y; - uint8_t* dst_uv; - const ptrdiff_t vu_off = src_v - src_u; - int halfwidth = (width + 1) >> 1; - int halfheight = (height + 1) >> 1; - if (!src_y || !src_u || !src_v || !dst_argb || width <= 0 || height == 0) { - return -1; - } - // Negative height means invert the image. - if (height < 0) { - height = -height; - halfheight = (height + 1) >> 1; - dst_argb = dst_argb + (height - 1) * dst_stride_argb; - dst_stride_argb = -dst_stride_argb; - } - - // I420 - if (src_pixel_stride_uv == 1) { - return I420ToARGBMatrix(src_y, src_stride_y, src_u, src_stride_u, src_v, - src_stride_v, dst_argb, dst_stride_argb, - yuvconstants, width, height); - // NV21 - } - if (src_pixel_stride_uv == 2 && vu_off == -1 && - src_stride_u == src_stride_v) { - return NV21ToARGBMatrix(src_y, src_stride_y, src_v, src_stride_v, dst_argb, - dst_stride_argb, yuvconstants, width, height); - // NV12 - } - if (src_pixel_stride_uv == 2 && vu_off == 1 && src_stride_u == src_stride_v) { - return NV12ToARGBMatrix(src_y, src_stride_y, src_u, src_stride_u, dst_argb, - dst_stride_argb, yuvconstants, width, height); - } - - // General case fallback creates NV12 - align_buffer_64(plane_uv, halfwidth * 2 * halfheight); - dst_uv = plane_uv; - for (y = 0; y < halfheight; ++y) { - WeavePixels(src_u, src_v, src_pixel_stride_uv, dst_uv, halfwidth); - src_u += src_stride_u; - src_v += src_stride_v; - dst_uv += halfwidth * 2; - } - NV12ToARGBMatrix(src_y, src_stride_y, plane_uv, halfwidth * 2, dst_argb, - dst_stride_argb, yuvconstants, width, height); - free_aligned_buffer_64(plane_uv); - return 0; -} - -// Convert Android420 to ARGB. -LIBYUV_API -int Android420ToARGB(const uint8_t* src_y, - int src_stride_y, - const uint8_t* src_u, - int src_stride_u, - const uint8_t* src_v, - int src_stride_v, - int src_pixel_stride_uv, - uint8_t* dst_argb, - int dst_stride_argb, - int width, - int height) { - return Android420ToARGBMatrix(src_y, src_stride_y, src_u, src_stride_u, src_v, - src_stride_v, src_pixel_stride_uv, dst_argb, - dst_stride_argb, &kYuvI601Constants, width, - height); -} - -// Convert Android420 to ABGR. -LIBYUV_API -int Android420ToABGR(const uint8_t* src_y, - int src_stride_y, - const uint8_t* src_u, - int src_stride_u, - const uint8_t* src_v, - int src_stride_v, - int src_pixel_stride_uv, - uint8_t* dst_abgr, - int dst_stride_abgr, - int width, - int height) { - return Android420ToARGBMatrix(src_y, src_stride_y, src_v, src_stride_v, src_u, - src_stride_u, src_pixel_stride_uv, dst_abgr, - dst_stride_abgr, &kYvuI601Constants, width, - height); -} - -#ifdef __cplusplus -} // extern "C" -} // namespace libyuv -#endif diff --git a/mobile/android/app/build.gradle b/mobile/android/app/build.gradle index 888553c73c03..7d8d311b5b77 100644 --- a/mobile/android/app/build.gradle +++ b/mobile/android/app/build.gradle @@ -122,7 +122,7 @@ android { } if (!mozconfig.substs.MOZ_CRASHREPORTER) { - exclude 'org/mozilla/gecko/CrashReporter.java' + exclude 'org/mozilla/gecko/CrashReporterActivity.java' } if (!mozconfig.substs.MOZ_NATIVE_DEVICES) { diff --git a/mobile/android/app/lint.xml b/mobile/android/app/lint.xml index 1250e8b5fbad..8cc567123d14 100644 --- a/mobile/android/app/lint.xml +++ b/mobile/android/app/lint.xml @@ -64,7 +64,7 @@ diff --git a/mobile/android/base/AndroidManifest.xml.in b/mobile/android/base/AndroidManifest.xml.in index ce22b7ca4583..7eb135fbfa78 100644 --- a/mobile/android/base/AndroidManifest.xml.in +++ b/mobile/android/base/AndroidManifest.xml.in @@ -272,7 +272,7 @@ #include ../services/manifests/FxAccountAndroidManifest_activities.xml.in #ifdef MOZ_CRASHREPORTER - + package="org.mozilla.geckoview"> @@ -12,62 +13,88 @@ - - - + + - - - + + + + + + + + + --> + + --> + + --> + + --> + - - - --> - --> - --> - --> - - + + + android:name="org.mozilla.gecko.media.MediaManager" + android:enabled="true" + android:exported="false" + android:isolatedProcess="false" + android:process=":media"> - + android:name="org.mozilla.gecko.process.GeckoServiceChildProcess$geckomediaplugin" + android:enabled="true" + android:exported="false" + android:isolatedProcess="false" + android:process=":geckomediaplugin"> - + android:name="org.mozilla.gecko.process.GeckoServiceChildProcess$tab" + android:enabled="true" + android:exported="false" + android:isolatedProcess="false" + android:process=":tab"> - + android:name="org.mozilla.gecko.gfx.SurfaceAllocatorService" + android:enabled="true" + android:exported="false" + android:isolatedProcess="false"> - + + + - + \ No newline at end of file diff --git a/mobile/android/geckoview/src/main/aidl/org/mozilla/gecko/process/IChildProcess.aidl b/mobile/android/geckoview/src/main/aidl/org/mozilla/gecko/process/IChildProcess.aidl index bf80de133b3c..c731a3d0cc0c 100644 --- a/mobile/android/geckoview/src/main/aidl/org/mozilla/gecko/process/IChildProcess.aidl +++ b/mobile/android/geckoview/src/main/aidl/org/mozilla/gecko/process/IChildProcess.aidl @@ -11,7 +11,7 @@ import android.os.ParcelFileDescriptor; interface IChildProcess { int getPid(); - boolean start(in IProcessManager procMan, in String[] args, in Bundle extras, + boolean start(in IProcessManager procMan, in String[] args, in Bundle extras, int flags, in ParcelFileDescriptor prefsPfd, in ParcelFileDescriptor ipcPfd, in ParcelFileDescriptor crashReporterPfd, in ParcelFileDescriptor crashAnnotationPfd); diff --git a/mobile/android/geckoview/src/main/java/org/mozilla/gecko/CrashHandler.java b/mobile/android/geckoview/src/main/java/org/mozilla/gecko/CrashHandler.java index 03bbf350ad36..c9a04dfb5e12 100644 --- a/mobile/android/geckoview/src/main/java/org/mozilla/gecko/CrashHandler.java +++ b/mobile/android/geckoview/src/main/java/org/mozilla/gecko/CrashHandler.java @@ -297,7 +297,7 @@ public class CrashHandler implements Thread.UncaughtExceptionHandler { final Context context = getAppContext(); final String javaPkg = getJavaPackageName(); final String pkg = getAppPackageName(); - final String component = javaPkg + ".CrashReporter"; + final String component = javaPkg + ".CrashReporterService"; final String action = javaPkg + ".reportCrash"; final ProcessBuilder pb; @@ -305,8 +305,7 @@ public class CrashHandler implements Thread.UncaughtExceptionHandler { final Intent intent = new Intent(action); intent.setComponent(new ComponentName(pkg, component)); intent.putExtra("minidumpPath", dumpFile); - intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - context.startActivity(intent); + context.startService(intent); return true; } diff --git a/mobile/android/geckoview/src/main/java/org/mozilla/gecko/CrashReporterService.java b/mobile/android/geckoview/src/main/java/org/mozilla/gecko/CrashReporterService.java new file mode 100644 index 000000000000..f4a3b2f072d1 --- /dev/null +++ b/mobile/android/geckoview/src/main/java/org/mozilla/gecko/CrashReporterService.java @@ -0,0 +1,373 @@ +package org.mozilla.gecko; + +import org.mozilla.gecko.mozglue.GeckoLoader; +import org.mozilla.gecko.mozglue.MinidumpAnalyzer; +import org.mozilla.gecko.util.INIParser; +import org.mozilla.gecko.util.INISection; +import org.mozilla.gecko.util.ProxySelector; + +import android.app.IntentService; +import android.content.Intent; +import android.os.Build; +import android.util.Log; + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.FileReader; +import java.io.FileWriter; +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.OutputStream; +import java.net.HttpURLConnection; +import java.net.URI; +import java.net.URISyntaxException; +import java.net.URL; +import java.net.URLDecoder; +import java.nio.channels.Channels; +import java.nio.channels.FileChannel; +import java.security.MessageDigest; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.Map; +import java.util.zip.GZIPOutputStream; + +public class CrashReporterService extends IntentService { + private static final String LOGTAG = "CrashReporter"; + private static final String ACTION_REPORT_CRASH = "org.mozilla.gecko.reportCrash"; + private static final String PASSED_MINI_DUMP_KEY = "minidumpPath"; + private static final String PASSED_MINI_DUMP_SUCCESS_KEY = "minidumpSuccess"; + private static final String MINI_DUMP_PATH_KEY = "upload_file_minidump"; + private static final String PAGE_URL_KEY = "URL"; + private static final String NOTES_KEY = "Notes"; + private static final String SERVER_URL_KEY = "ServerURL"; + + private static final String CRASH_REPORT_SUFFIX = "/mozilla/Crash Reports/"; + private static final String PENDING_SUFFIX = CRASH_REPORT_SUFFIX + "pending"; + private static final String SUBMITTED_SUFFIX = CRASH_REPORT_SUFFIX + "submitted"; + + private File mPendingMinidumpFile; + private File mPendingExtrasFile; + private HashMap mExtrasStringMap; + private boolean mMinidumpSucceeded; + + public CrashReporterService() { + super("CrashReporterService"); + } + + @Override + protected void onHandleIntent(Intent intent) { + if (intent == null || !intent.getAction().equals(ACTION_REPORT_CRASH)) { + Log.d(LOGTAG, "Invalid or unknown action"); + return; + } + + Class reporterActivityCls = getFennecReporterActivity(); + if (reporterActivityCls != null) { + intent.setClass(this, reporterActivityCls); + startActivity(intent); + return; + } + + submitCrash(intent); + } + + private Class getFennecReporterActivity() { + try { + return Class.forName("org.mozilla.gecko.CrashReporterActivity"); + } catch (ClassNotFoundException e) { + return null; + } + } + + private boolean moveFile(File inFile, File outFile) { + Log.i(LOGTAG, "moving " + inFile + " to " + outFile); + if (inFile.renameTo(outFile)) + return true; + try { + outFile.createNewFile(); + Log.i(LOGTAG, "couldn't rename minidump file"); + // so copy it instead + FileChannel inChannel = new FileInputStream(inFile).getChannel(); + FileChannel outChannel = new FileOutputStream(outFile).getChannel(); + long transferred = inChannel.transferTo(0, inChannel.size(), outChannel); + inChannel.close(); + outChannel.close(); + + if (transferred > 0) + inFile.delete(); + } catch (Exception e) { + Log.e(LOGTAG, "exception while copying minidump file: ", e); + return false; + } + return true; + } + + private void submitCrash(Intent intent) { + mMinidumpSucceeded = intent.getBooleanExtra(PASSED_MINI_DUMP_SUCCESS_KEY, false); + if (!mMinidumpSucceeded) { + Log.i(LOGTAG, "Failed to get minidump."); + } + String passedMinidumpPath = intent.getStringExtra(PASSED_MINI_DUMP_KEY); + File passedMinidumpFile = new File(passedMinidumpPath); + File pendingDir = new File(getFilesDir(), PENDING_SUFFIX); + pendingDir.mkdirs(); + mPendingMinidumpFile = new File(pendingDir, passedMinidumpFile.getName()); + moveFile(passedMinidumpFile, mPendingMinidumpFile); + + File extrasFile = new File(passedMinidumpPath.replaceAll("\\.dmp", ".extra")); + mPendingExtrasFile = new File(pendingDir, extrasFile.getName()); + moveFile(extrasFile, mPendingExtrasFile); + + // Compute the minidump hash and generate the stack traces + computeMinidumpHash(mPendingExtrasFile, mPendingMinidumpFile); + + try { + GeckoLoader.loadMozGlue(this); + + if (!MinidumpAnalyzer.GenerateStacks(mPendingMinidumpFile.getPath(), /* fullStacks */ false)) { + Log.e(LOGTAG, "Could not generate stacks for this minidump: " + passedMinidumpPath); + } + } catch (UnsatisfiedLinkError e) { + Log.e(LOGTAG, "Could not load libmozglue.so, stacks for this crash won't be generated"); + } + + // Extract the annotations from the .extra file + mExtrasStringMap = new HashMap(); + readStringsFromFile(mPendingExtrasFile.getPath(), mExtrasStringMap); + + try { + // Find the profile name and path. Since we don't have any other way of getting it within + // this context we extract it from the crash dump path. + final File profileDir = passedMinidumpFile.getParentFile().getParentFile(); + final String profileName = getProfileName(profileDir); + + if (profileName != null) { + // Extract the crash dump ID and telemetry client ID, we need profile access for the latter. + final String passedMinidumpName = passedMinidumpFile.getName(); + // Strip the .dmp suffix from the minidump name to obtain the crash ID. + final String crashId = passedMinidumpName.substring(0, passedMinidumpName.length() - 4); + final GeckoProfile profile = GeckoProfile.get(this, profileName, profileDir); + final String clientId = profile.getClientId(); + } + } catch (GeckoProfileDirectories.NoMozillaDirectoryException | IOException e) { + Log.e(LOGTAG, "Cannot send the crash ping: ", e); + } + + // Notify GeckoApp that we've crashed, so it can react appropriately during the next start. + try { + File crashFlag = new File(GeckoProfileDirectories.getMozillaDirectory(this), "CRASHED"); + crashFlag.createNewFile(); + } catch (GeckoProfileDirectories.NoMozillaDirectoryException | IOException e) { + Log.e(LOGTAG, "Cannot set crash flag: ", e); + } + + sendReport(mPendingMinidumpFile, mExtrasStringMap, mPendingExtrasFile); + } + + + private String getProfileName(File profileDir) throws GeckoProfileDirectories.NoMozillaDirectoryException { + final File mozillaDir = GeckoProfileDirectories.getMozillaDirectory(this); + final INIParser parser = GeckoProfileDirectories.getProfilesINI(mozillaDir); + String profileName = null; + + if (parser.getSections() != null) { + for (Enumeration e = parser.getSections().elements(); e.hasMoreElements(); ) { + final INISection section = e.nextElement(); + final String path = section.getStringProperty("Path"); + final boolean isRelative = (section.getIntProperty("IsRelative") == 1); + + if ((isRelative && path.equals(profileDir.getName())) || + path.equals(profileDir.getPath())) { + profileName = section.getStringProperty("Name"); + break; + } + } + } + + return profileName; + } + + + private void computeMinidumpHash(File extraFile, File minidump) { + try { + FileInputStream stream = new FileInputStream(minidump); + MessageDigest md = MessageDigest.getInstance("SHA-256"); + + try { + byte[] buffer = new byte[4096]; + int readBytes; + + while ((readBytes = stream.read(buffer)) != -1) { + md.update(buffer, 0, readBytes); + } + } finally { + stream.close(); + } + + byte[] digest = md.digest(); + StringBuilder hash = new StringBuilder(84); + + hash.append("MinidumpSha256Hash="); + + for (int i = 0; i < digest.length; i++) { + hash.append(Integer.toHexString((digest[i] & 0xf0) >> 4)); + hash.append(Integer.toHexString(digest[i] & 0x0f)); + } + + hash.append('\n'); + + FileWriter writer = new FileWriter(extraFile, /* append */ true); + + try { + writer.write(hash.toString()); + } finally { + writer.close(); + } + } catch (Exception e) { + Log.e(LOGTAG, "exception while computing the minidump hash: ", e); + } + } + + private boolean readStringsFromFile(String filePath, Map stringMap) { + try { + BufferedReader reader = new BufferedReader(new FileReader(filePath)); + return readStringsFromReader(reader, stringMap); + } catch (Exception e) { + Log.e(LOGTAG, "exception while reading strings: ", e); + return false; + } + } + + private boolean readStringsFromReader(BufferedReader reader, Map stringMap) throws IOException { + String line; + while ((line = reader.readLine()) != null) { + int equalsPos = -1; + if ((equalsPos = line.indexOf('=')) != -1) { + String key = line.substring(0, equalsPos); + String val = unescape(line.substring(equalsPos + 1)); + stringMap.put(key, val); + } + } + reader.close(); + return true; + } + + private String generateBoundary() { + // Generate some random numbers to fill out the boundary + int r0 = (int)(Integer.MAX_VALUE * Math.random()); + int r1 = (int)(Integer.MAX_VALUE * Math.random()); + return String.format("---------------------------%08X%08X", r0, r1); + } + + private void sendPart(OutputStream os, String boundary, String name, String data) { + try { + os.write(("--" + boundary + "\r\n" + + "Content-Disposition: form-data; name=\"" + name + "\"\r\n" + + "\r\n" + + data + "\r\n" + ).getBytes()); + } catch (Exception ex) { + Log.e(LOGTAG, "Exception when sending \"" + name + "\"", ex); + } + } + + private void sendFile(OutputStream os, String boundary, String name, File file) throws IOException { + os.write(("--" + boundary + "\r\n" + + "Content-Disposition: form-data; name=\"" + name + "\"; " + + "filename=\"" + file.getName() + "\"\r\n" + + "Content-Type: application/octet-stream\r\n" + + "\r\n" + ).getBytes()); + FileChannel fc = new FileInputStream(file).getChannel(); + fc.transferTo(0, fc.size(), Channels.newChannel(os)); + fc.close(); + } + + private void sendReport(File minidumpFile, Map extras, File extrasFile) { + Log.i(LOGTAG, "sendReport: " + minidumpFile.getPath()); + + String spec = extras.get(SERVER_URL_KEY); + if (spec == null) { + return; + } + + try { + final URL url = new URL(URLDecoder.decode(spec, "UTF-8")); + final URI uri = new URI(url.getProtocol(), url.getUserInfo(), + url.getHost(), url.getPort(), + url.getPath(), url.getQuery(), url.getRef()); + HttpURLConnection conn = (HttpURLConnection) ProxySelector.openConnectionWithProxy(uri); + conn.setRequestMethod("POST"); + String boundary = generateBoundary(); + conn.setDoOutput(true); + conn.setRequestProperty("Content-Type", "multipart/form-data; boundary=" + boundary); + conn.setRequestProperty("Content-Encoding", "gzip"); + + OutputStream os = new GZIPOutputStream(conn.getOutputStream()); + for (String key : extras.keySet()) { + if (!key.equals(SERVER_URL_KEY) && !key.equals(NOTES_KEY)) { + sendPart(os, boundary, key, extras.get(key)); + } + } + + StringBuilder sb = new StringBuilder(); + sb.append(extras.containsKey(NOTES_KEY) ? extras.get(NOTES_KEY) + "\n" : ""); + sb.append(Build.MANUFACTURER).append(' ') + .append(Build.MODEL).append('\n') + .append(Build.FINGERPRINT); + sendPart(os, boundary, NOTES_KEY, sb.toString()); + + sendPart(os, boundary, "Android_Manufacturer", Build.MANUFACTURER); + sendPart(os, boundary, "Android_Model", Build.MODEL); + sendPart(os, boundary, "Android_Board", Build.BOARD); + sendPart(os, boundary, "Android_Brand", Build.BRAND); + sendPart(os, boundary, "Android_Device", Build.DEVICE); + sendPart(os, boundary, "Android_Display", Build.DISPLAY); + sendPart(os, boundary, "Android_Fingerprint", Build.FINGERPRINT); + sendPart(os, boundary, "Android_CPU_ABI", Build.CPU_ABI); + try { + sendPart(os, boundary, "Android_CPU_ABI2", Build.CPU_ABI2); + sendPart(os, boundary, "Android_Hardware", Build.HARDWARE); + } catch (Exception ex) { + Log.e(LOGTAG, "Exception while sending SDK version 8 keys", ex); + } + sendPart(os, boundary, "Android_Version", Build.VERSION.SDK_INT + " (" + Build.VERSION.CODENAME + ")"); + sendPart(os, boundary, PASSED_MINI_DUMP_SUCCESS_KEY, mMinidumpSucceeded ? "True" : "False"); + sendFile(os, boundary, MINI_DUMP_PATH_KEY, minidumpFile); + os.write(("\r\n--" + boundary + "--\r\n").getBytes()); + os.flush(); + os.close(); + BufferedReader br = new BufferedReader( + new InputStreamReader(conn.getInputStream())); + HashMap responseMap = new HashMap(); + readStringsFromReader(br, responseMap); + + if (conn.getResponseCode() == HttpURLConnection.HTTP_OK) { + File submittedDir = new File(getFilesDir(), + SUBMITTED_SUFFIX); + submittedDir.mkdirs(); + minidumpFile.delete(); + extrasFile.delete(); + String crashid = responseMap.get("CrashID"); + File file = new File(submittedDir, crashid + ".txt"); + FileOutputStream fos = new FileOutputStream(file); + fos.write("Crash ID: ".getBytes()); + fos.write(crashid.getBytes()); + fos.close(); + Log.i(LOGTAG, "Successfully sent crash report: " + crashid); + } else { + Log.w(LOGTAG, "Received failure HTTP response code from server: " + conn.getResponseCode()); + } + } catch (IOException e) { + Log.e(LOGTAG, "exception during send: ", e); + } catch (URISyntaxException e) { + Log.e(LOGTAG, "exception during new URI: ", e); + } + } + + private String unescape(String string) { + return string.replaceAll("\\\\\\\\", "\\").replaceAll("\\\\n", "\n").replaceAll("\\\\t", "\t"); + } +} diff --git a/mobile/android/geckoview/src/main/java/org/mozilla/gecko/GeckoAppShell.java b/mobile/android/geckoview/src/main/java/org/mozilla/gecko/GeckoAppShell.java index cc5a0c5b81f2..10d5439d0d32 100644 --- a/mobile/android/geckoview/src/main/java/org/mozilla/gecko/GeckoAppShell.java +++ b/mobile/android/geckoview/src/main/java/org/mozilla/gecko/GeckoAppShell.java @@ -111,7 +111,7 @@ public class GeckoAppShell // We have static members only. private GeckoAppShell() { } - private static final CrashHandler CRASH_HANDLER = new CrashHandler() { + private static class GeckoCrashHandler extends CrashHandler { @Override protected String getAppPackageName() { final Context appContext = getAppContext(); @@ -174,10 +174,18 @@ public class GeckoAppShell }; private static String sAppNotes; + private static CrashHandler sCrashHandler; - public static CrashHandler ensureCrashHandling() { - // Crash handling is automatically enabled when GeckoAppShell is loaded. - return CRASH_HANDLER; + public static synchronized CrashHandler ensureCrashHandling() { + if (sCrashHandler == null) { + sCrashHandler = new GeckoCrashHandler(); + } + + return sCrashHandler; + } + + public static synchronized boolean isCrashHandlingEnabled() { + return sCrashHandler != null; } @WrapForJNI(exceptionMode = "ignore") @@ -280,8 +288,10 @@ public class GeckoAppShell } @WrapForJNI(exceptionMode = "ignore") - private static void handleUncaughtException(Throwable e) { - CRASH_HANDLER.uncaughtException(null, e); + private static synchronized void handleUncaughtException(Throwable e) { + if (sCrashHandler != null) { + sCrashHandler.uncaughtException(null, e); + } } private static float getLocationAccuracy(Location location) { diff --git a/mobile/android/geckoview/src/main/java/org/mozilla/gecko/GeckoThread.java b/mobile/android/geckoview/src/main/java/org/mozilla/gecko/GeckoThread.java index 9d0be0dea28e..076d7b92ee99 100644 --- a/mobile/android/geckoview/src/main/java/org/mozilla/gecko/GeckoThread.java +++ b/mobile/android/geckoview/src/main/java/org/mozilla/gecko/GeckoThread.java @@ -12,6 +12,7 @@ import org.mozilla.gecko.process.GeckoProcessManager; import org.mozilla.gecko.util.GeckoBundle; import org.mozilla.gecko.util.FileUtils; import org.mozilla.gecko.util.ThreadUtils; +import org.mozilla.geckoview.BuildConfig; import android.content.Context; import android.content.res.Configuration; @@ -27,10 +28,10 @@ import android.text.TextUtils; import android.util.Log; import java.io.File; -import java.io.FilenameFilter; import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; +import java.util.List; import java.util.Locale; import java.util.StringTokenizer; @@ -124,10 +125,12 @@ public class GeckoThread extends Thread { private static int uiThreadId; // Main process parameters - public static final int FLAG_DEBUGGING = 1; // Debugging mode. - public static final int FLAG_PRELOAD_CHILD = 2; // Preload child during main thread start. + public static final int FLAG_DEBUGGING = 1 << 0; // Debugging mode. + public static final int FLAG_PRELOAD_CHILD = 1 << 1; // Preload child during main thread start. + public static final int FLAG_ENABLE_NATIVE_CRASHREPORTER = 1 << 2; // Enable native crash reporting + public static final int FLAG_ENABLE_JAVA_CRASHREPORTER = 1 << 3; // Enable java crash reporting - private static final String EXTRA_ARGS = "args"; + /* package */ static final String EXTRA_ARGS = "args"; private static final String EXTRA_PREFS_FD = "prefsFd"; private static final String EXTRA_IPC_FD = "ipcFd"; private static final String EXTRA_CRASH_FD = "crashFd"; @@ -181,11 +184,14 @@ public class GeckoThread extends Thread { /* fd */ -1, /* fd */ -1, /* fd */ -1); } - public static boolean initChildProcess(final String[] args, final Bundle extras, - final int prefsFd, final int ipcFd, + public static boolean initChildProcess(final String[] args, + final Bundle extras, + final int flags, + final int prefsFd, + final int ipcFd, final int crashFd, final int crashAnnotationFd) { - return INSTANCE.init(/* profile */ null, args, extras, /* flags */ 0, + return INSTANCE.init(/* profile */ null, args, extras, flags, prefsFd, ipcFd, crashFd, crashAnnotationFd); } @@ -377,10 +383,40 @@ public class GeckoThread extends Thread { if (!INSTANCE.mInitialized) { return null; } - return INSTANCE.mExtras; + return new Bundle(INSTANCE.mExtras); } } + public static int getActiveFlags() { + synchronized (INSTANCE) { + if (!INSTANCE.mInitialized) { + return 0; + } + + return INSTANCE.mFlags; + } + } + + private static ArrayList getEnvFromExtras(final Bundle extras) { + if (extras == null) { + return new ArrayList<>(); + } + + ArrayList result = new ArrayList<>(); + if (extras != null) { + String env = extras.getString("env0"); + for (int c = 1; env != null; c++) { + if (BuildConfig.DEBUG) { + Log.d(LOGTAG, "env var: " + env); + } + result.add(env); + env = extras.getString("env" + c); + } + } + + return result; + } + @Override public void run() { Log.i(LOGTAG, "preparing to run Gecko"); @@ -442,7 +478,21 @@ public class GeckoThread extends Thread { Log.i(LOGTAG, "RunGecko - args = " + TextUtils.join(" ", args)); } - GeckoLoader.setupGeckoEnvironment(context, context.getFilesDir().getPath(), mExtras); + final List env = getEnvFromExtras(mExtras); + + // In Gecko, the native crash reporter is enabled by default in opt builds, and + // disabled by default in debug builds. + if ((mFlags & FLAG_ENABLE_NATIVE_CRASHREPORTER) == 0 && !BuildConfig.DEBUG_BUILD) { + env.add(0, "MOZ_CRASHREPORTER_DISABLE=1"); + } else if ((mFlags & FLAG_ENABLE_NATIVE_CRASHREPORTER) != 0 && BuildConfig.DEBUG_BUILD) { + env.add(0, "MOZ_CRASHREPORTER=1"); + } + + if ((mFlags & FLAG_ENABLE_JAVA_CRASHREPORTER) != 0) { + GeckoAppShell.ensureCrashHandling(); + } + + GeckoLoader.setupGeckoEnvironment(context, context.getFilesDir().getPath(), env); // And go. GeckoLoader.nativeRun(args, diff --git a/mobile/android/geckoview/src/main/java/org/mozilla/gecko/mozglue/GeckoLoader.java b/mobile/android/geckoview/src/main/java/org/mozilla/gecko/mozglue/GeckoLoader.java index ac128b651e7b..6ea25710f0b3 100644 --- a/mobile/android/geckoview/src/main/java/org/mozilla/gecko/mozglue/GeckoLoader.java +++ b/mobile/android/geckoview/src/main/java/org/mozilla/gecko/mozglue/GeckoLoader.java @@ -8,6 +8,7 @@ package org.mozilla.gecko.mozglue; import java.io.File; import java.io.FileOutputStream; import java.io.InputStream; +import java.util.Collection; import java.util.Locale; import java.util.zip.ZipEntry; import java.util.zip.ZipFile; @@ -92,17 +93,9 @@ public final class GeckoLoader { public synchronized static void setupGeckoEnvironment(final Context context, final String profilePath, - final Bundle extras) { - // if we have an intent (we're being launched by an activity) - // read in any environmental variables from it here - if (extras != null) { - String env = extras.getString("env0"); - Log.d(LOGTAG, "Gecko environment env0: " + env); - for (int c = 1; env != null; c++) { - putenv(env); - env = extras.getString("env" + c); - Log.d(LOGTAG, "env" + c + ": " + env); - } + final Collection env) { + for (final String e : env) { + putenv(e); } try { diff --git a/mobile/android/geckoview/src/main/java/org/mozilla/gecko/process/GeckoProcessManager.java b/mobile/android/geckoview/src/main/java/org/mozilla/gecko/process/GeckoProcessManager.java index 93d63bd18450..0c22c34a998f 100644 --- a/mobile/android/geckoview/src/main/java/org/mozilla/gecko/process/GeckoProcessManager.java +++ b/mobile/android/geckoview/src/main/java/org/mozilla/gecko/process/GeckoProcessManager.java @@ -181,6 +181,11 @@ public final class GeckoProcessManager extends IProcessManager.Stub { return INSTANCE.start(type, args, prefsFd, ipcFd, crashFd, crashAnnotationFd, /* retry */ false); } + private int filterFlagsForChild(int flags) { + return flags & (GeckoThread.FLAG_ENABLE_JAVA_CRASHREPORTER | + GeckoThread.FLAG_ENABLE_NATIVE_CRASHREPORTER); + } + private int start(final String type, final String[] args, final int prefsFd, final int ipcFd, final int crashFd, final int crashAnnotationFd, final boolean retry) { @@ -205,9 +210,11 @@ public final class GeckoProcessManager extends IProcessManager.Stub { return 0; } + final int flags = filterFlagsForChild(GeckoThread.getActiveFlags()); + boolean started = false; try { - started = child.start(this, args, extras, prefsPfd, ipcPfd, crashPfd, + started = child.start(this, args, extras, flags, prefsPfd, ipcPfd, crashPfd, crashAnnotationPfd); } catch (final RemoteException e) { } diff --git a/mobile/android/geckoview/src/main/java/org/mozilla/gecko/process/GeckoServiceChildProcess.java b/mobile/android/geckoview/src/main/java/org/mozilla/gecko/process/GeckoServiceChildProcess.java index 0f29b39fb455..062516af238a 100644 --- a/mobile/android/geckoview/src/main/java/org/mozilla/gecko/process/GeckoServiceChildProcess.java +++ b/mobile/android/geckoview/src/main/java/org/mozilla/gecko/process/GeckoServiceChildProcess.java @@ -24,9 +24,7 @@ import android.os.RemoteException; import android.util.Log; public class GeckoServiceChildProcess extends Service { - private static final String LOGTAG = "GeckoServiceChildProcess"; - private static IProcessManager sProcessManager; @WrapForJNI(calledFrom = "gecko") @@ -44,7 +42,6 @@ public class GeckoServiceChildProcess extends Service { public void onCreate() { super.onCreate(); - GeckoAppShell.ensureCrashHandling(); GeckoAppShell.setApplicationContext(getApplicationContext()); } @@ -63,6 +60,7 @@ public class GeckoServiceChildProcess extends Service { public boolean start(final IProcessManager procMan, final String[] args, final Bundle extras, + final int flags, final ParcelFileDescriptor prefsPfd, final ParcelFileDescriptor ipcPfd, final ParcelFileDescriptor crashReporterPfd, @@ -85,7 +83,7 @@ public class GeckoServiceChildProcess extends Service { ThreadUtils.postToUiThread(new Runnable() { @Override public void run() { - if (GeckoThread.initChildProcess(args, extras, prefsFd, ipcFd, crashReporterFd, + if (GeckoThread.initChildProcess(args, extras, flags, prefsFd, ipcFd, crashReporterFd, crashAnnotationFd)) { GeckoThread.launch(); } diff --git a/mobile/android/geckoview/src/main/java/org/mozilla/geckoview/GeckoRuntime.java b/mobile/android/geckoview/src/main/java/org/mozilla/geckoview/GeckoRuntime.java index e4a46329ca92..a55bee0f65d0 100644 --- a/mobile/android/geckoview/src/main/java/org/mozilla/geckoview/GeckoRuntime.java +++ b/mobile/android/geckoview/src/main/java/org/mozilla/geckoview/GeckoRuntime.java @@ -84,9 +84,23 @@ public final class GeckoRuntime implements Parcelable { if (DEBUG) { Log.d(LOGTAG, "init"); } - final int flags = settings.getUseContentProcessHint() - ? GeckoThread.FLAG_PRELOAD_CHILD - : 0; + int flags = 0; + if (settings.getUseContentProcessHint()) { + flags |= GeckoThread.FLAG_PRELOAD_CHILD; + } + + if (settings.getNativeCrashReportingEnabled()) { + flags |= GeckoThread.FLAG_ENABLE_NATIVE_CRASHREPORTER; + } + + if (settings.getJavaCrashReportingEnabled()) { + flags |= GeckoThread.FLAG_ENABLE_JAVA_CRASHREPORTER; + } + + if (settings.getPauseForDebuggerEnabled()) { + flags |= GeckoThread.FLAG_DEBUGGING; + } + if (GeckoThread.initMainProcess(/* profile */ null, settings.getArguments(), settings.getExtras(), diff --git a/mobile/android/geckoview/src/main/java/org/mozilla/geckoview/GeckoRuntimeSettings.java b/mobile/android/geckoview/src/main/java/org/mozilla/geckoview/GeckoRuntimeSettings.java index 64975dc75bb1..8c54e080cd38 100644 --- a/mobile/android/geckoview/src/main/java/org/mozilla/geckoview/GeckoRuntimeSettings.java +++ b/mobile/android/geckoview/src/main/java/org/mozilla/geckoview/GeckoRuntimeSettings.java @@ -40,7 +40,9 @@ public final class GeckoRuntimeSettings implements Parcelable { * Set the content process hint flag. * * @param use If true, this will reload the content process for future use. + * Default is false. * @return This Builder instance. + */ public @NonNull Builder useContentProcessHint(final boolean use) { mSettings.mUseContentProcess = use; @@ -79,6 +81,7 @@ public final class GeckoRuntimeSettings implements Parcelable { * Set whether JavaScript support should be enabled. * * @param flag A flag determining whether JavaScript should be enabled. + * Default is true. * @return This Builder instance. */ public @NonNull Builder javaScriptEnabled(final boolean flag) { @@ -101,12 +104,54 @@ public final class GeckoRuntimeSettings implements Parcelable { * Set whether support for web fonts should be enabled. * * @param flag A flag determining whether web fonts should be enabled. + * Default is true. * @return This Builder instance. */ public @NonNull Builder webFontsEnabled(final boolean flag) { mSettings.mWebFonts.set(flag); return this; } + + /** + * Set whether crash reporting for native code should be enabled. This will cause + * a SIGSEGV handler to be installed, and any crash encountered there will be + * reported to Mozilla. + * + * @param enabled A flag determining whether native crash reporting should be enabled. + * Defaults to false. + * @return This Builder. + */ + public @NonNull Builder nativeCrashReportingEnabled(final boolean enabled) { + mSettings.mNativeCrashReporting = enabled; + return this; + } + + /** + * Set whether crash reporting for Java code should be enabled. This will cause + * a default unhandled exception handler to be installed, and any exceptions encountered + * will automatically reported to Mozilla. + * + * @param enabled A flag determining whether Java crash reporting should be enabled. + * Defaults to false. + * @return This Builder. + */ + public @NonNull Builder javaCrashReportingEnabled(final boolean enabled) { + mSettings.mJavaCrashReporting = enabled; + return this; + } + + /** + * Set whether there should be a pause during startup. This is useful if you need to + * wait for a debugger to attach. + * + * @param enabled A flag determining whether there will be a pause early in startup. + * Defaults to false. + * @return This Builder. + */ + public @NonNull Builder pauseForDebugger(boolean enabled) { + mSettings.mDebugPause = enabled; + return this; + } } /* package */ GeckoRuntime runtime; @@ -150,6 +195,9 @@ public final class GeckoRuntimeSettings implements Parcelable { "devtools.debugger.remote-enabled", false); /* package */ Pref mWebFonts = new Pref( "browser.display.use_document_fonts", true); + /* package */ boolean mNativeCrashReporting; + /* package */ boolean mJavaCrashReporting; + /* package */ boolean mDebugPause; private final Pref[] mPrefs = new Pref[] { mJavaScript, mRemoteDebugging, mWebFonts @@ -180,6 +228,9 @@ public final class GeckoRuntimeSettings implements Parcelable { final Pref uncheckedPref = (Pref) mPrefs[i]; uncheckedPref.set(settings.mPrefs[i].get()); } + + mNativeCrashReporting = settings.mNativeCrashReporting; + mJavaCrashReporting = settings.mJavaCrashReporting; } /* package */ void flush() { @@ -275,6 +326,31 @@ public final class GeckoRuntimeSettings implements Parcelable { return this; } + /** + * Get whether native crash reporting is enabled or not. + * + * @return True if native crash reporting is enabled. + */ + public boolean getNativeCrashReportingEnabled() { + return mNativeCrashReporting; + } + + /** + * Get whether Java crash reporting is enabled or not. + * + * @return True if Java crash reporting is enabled. + */ + public boolean getJavaCrashReportingEnabled() { + return mJavaCrashReporting; + } + + /** + * Gets whether the pause-for-debugger is enabled or not. + * + * @return True if the pause is enabled. + */ + public boolean getPauseForDebuggerEnabled() { return mDebugPause; } + @Override // Parcelable public int describeContents() { return 0; @@ -282,18 +358,22 @@ public final class GeckoRuntimeSettings implements Parcelable { @Override // Parcelable public void writeToParcel(Parcel out, int flags) { - out.writeByte((byte) (mUseContentProcess ? 1 : 0)); + ParcelableUtils.writeBoolean(out, mUseContentProcess); out.writeStringArray(mArgs); mExtras.writeToParcel(out, flags); for (final Pref pref : mPrefs) { out.writeValue(pref.get()); } + + ParcelableUtils.writeBoolean(out, mNativeCrashReporting); + ParcelableUtils.writeBoolean(out, mJavaCrashReporting); + ParcelableUtils.writeBoolean(out, mDebugPause); } // AIDL code may call readFromParcel even though it's not part of Parcelable. public void readFromParcel(final Parcel source) { - mUseContentProcess = source.readByte() == 1; + mUseContentProcess = ParcelableUtils.readBoolean(source); mArgs = source.createStringArray(); mExtras.readFromParcel(source); @@ -303,6 +383,10 @@ public final class GeckoRuntimeSettings implements Parcelable { final Pref uncheckedPref = (Pref) pref; uncheckedPref.set(source.readValue(getClass().getClassLoader())); } + + mNativeCrashReporting = ParcelableUtils.readBoolean(source); + mJavaCrashReporting = ParcelableUtils.readBoolean(source); + mJavaCrashReporting = ParcelableUtils.readBoolean(source); } public static final Parcelable.Creator CREATOR diff --git a/mobile/android/geckoview/src/main/java/org/mozilla/geckoview/ParcelableUtils.java b/mobile/android/geckoview/src/main/java/org/mozilla/geckoview/ParcelableUtils.java new file mode 100644 index 000000000000..a13e193576fd --- /dev/null +++ b/mobile/android/geckoview/src/main/java/org/mozilla/geckoview/ParcelableUtils.java @@ -0,0 +1,19 @@ +/* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*- + * vim: ts=4 sw=4 expandtab: + * 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/. */ + +package org.mozilla.geckoview; + +import android.os.Parcel; + +class ParcelableUtils { + public static void writeBoolean(Parcel out, boolean val) { + out.writeByte((byte) (val ? 1 : 0)); + } + + public static boolean readBoolean(Parcel source) { + return source.readByte() == 1; + } +} diff --git a/mobile/android/geckoview_example/src/main/java/org/mozilla/geckoview_example/GeckoViewActivity.java b/mobile/android/geckoview_example/src/main/java/org/mozilla/geckoview_example/GeckoViewActivity.java index 0bc0ef70f069..62b08f4f185b 100644 --- a/mobile/android/geckoview_example/src/main/java/org/mozilla/geckoview_example/GeckoViewActivity.java +++ b/mobile/android/geckoview_example/src/main/java/org/mozilla/geckoview_example/GeckoViewActivity.java @@ -67,7 +67,12 @@ public class GeckoViewActivity extends Activity { if (extras != null) { runtimeSettingsBuilder.extras(extras); } - runtimeSettingsBuilder.useContentProcessHint(useMultiprocess); + + runtimeSettingsBuilder + .useContentProcessHint(useMultiprocess) + .nativeCrashReportingEnabled(true) + .javaCrashReportingEnabled(true); + sGeckoRuntime = GeckoRuntime.create(this, runtimeSettingsBuilder.build()); } diff --git a/mozglue/misc/ConditionVariable_windows.cpp b/mozglue/misc/ConditionVariable_windows.cpp index fa450310a81e..97ea499335a4 100644 --- a/mozglue/misc/ConditionVariable_windows.cpp +++ b/mozglue/misc/ConditionVariable_windows.cpp @@ -54,8 +54,8 @@ mozilla::detail::ConditionVariableImpl::notify_all() void mozilla::detail::ConditionVariableImpl::wait(MutexImpl& lock) { - CRITICAL_SECTION* cs = &lock.platformData()->criticalSection; - bool r = SleepConditionVariableCS(&platformData()->cv_, cs, INFINITE); + SRWLOCK* srwlock = &lock.platformData()->lock; + bool r = SleepConditionVariableSRW(&platformData()->cv_, srwlock, INFINITE, 0); MOZ_RELEASE_ASSERT(r); } @@ -68,7 +68,7 @@ mozilla::detail::ConditionVariableImpl::wait_for(MutexImpl& lock, return CVStatus::NoTimeout; } - CRITICAL_SECTION* cs = &lock.platformData()->criticalSection; + SRWLOCK* srwlock = &lock.platformData()->lock; // Note that DWORD is unsigned, so we have to be careful to clamp at 0. If // rel_time is Forever, then ToMilliseconds is +inf, which evaluates as @@ -89,7 +89,7 @@ mozilla::detail::ConditionVariableImpl::wait_for(MutexImpl& lock, } } - BOOL r = SleepConditionVariableCS(&platformData()->cv_, cs, msec); + BOOL r = SleepConditionVariableSRW(&platformData()->cv_, srwlock, msec, 0); if (r) return CVStatus::NoTimeout; MOZ_RELEASE_ASSERT(GetLastError() == ERROR_TIMEOUT); diff --git a/mozglue/misc/MutexPlatformData_windows.h b/mozglue/misc/MutexPlatformData_windows.h index fd9b2f320f8b..40d9f693da1d 100644 --- a/mozglue/misc/MutexPlatformData_windows.h +++ b/mozglue/misc/MutexPlatformData_windows.h @@ -13,7 +13,7 @@ struct mozilla::detail::MutexImpl::PlatformData { - CRITICAL_SECTION criticalSection; + SRWLOCK lock; }; #endif // MutexPlatformData_windows_h diff --git a/mozglue/misc/Mutex_windows.cpp b/mozglue/misc/Mutex_windows.cpp index 990e59faaede..4a43efc578d3 100644 --- a/mozglue/misc/Mutex_windows.cpp +++ b/mozglue/misc/Mutex_windows.cpp @@ -14,38 +14,23 @@ mozilla::detail::MutexImpl::MutexImpl() { - // This number was adopted from NSPR. - const static DWORD LockSpinCount = 1500; - -#if defined(RELEASE_OR_BETA) - // Vista and later automatically allocate and subsequently leak a debug info - // object for each critical section that we allocate unless we tell the - // system not to do that. - DWORD flags = CRITICAL_SECTION_NO_DEBUG_INFO; -#else - DWORD flags = 0; -#endif // defined(RELEASE_OR_BETA) - - BOOL r = InitializeCriticalSectionEx(&platformData()->criticalSection, - LockSpinCount, flags); - MOZ_RELEASE_ASSERT(r); + InitializeSRWLock(&platformData()->lock); } mozilla::detail::MutexImpl::~MutexImpl() { - DeleteCriticalSection(&platformData()->criticalSection); } void mozilla::detail::MutexImpl::lock() { - EnterCriticalSection(&platformData()->criticalSection); + AcquireSRWLockExclusive(&platformData()->lock); } void mozilla::detail::MutexImpl::unlock() { - LeaveCriticalSection(&platformData()->criticalSection); + ReleaseSRWLockExclusive(&platformData()->lock); } mozilla::detail::MutexImpl::PlatformData* diff --git a/netwerk/dns/nsHostResolver.cpp b/netwerk/dns/nsHostResolver.cpp index 7763e455b4bf..ae95d29d12d0 100644 --- a/netwerk/dns/nsHostResolver.cpp +++ b/netwerk/dns/nsHostResolver.cpp @@ -298,6 +298,15 @@ nsHostRecord::ResolveComplete() } } + if (mTRRUsed && mNativeUsed) { + // both were used, accumulate comparative success + AccumulateCategorical(mNativeSuccess && mTRRSuccess? + Telemetry::LABELS_DNS_TRR_COMPARE::BothWorked : + ((mNativeSuccess ? Telemetry::LABELS_DNS_TRR_COMPARE::NativeWorked : + (mTRRSuccess ? Telemetry::LABELS_DNS_TRR_COMPARE::TRRWorked: + Telemetry::LABELS_DNS_TRR_COMPARE::BothFailed)))); + } + switch(mResolverMode) { case MODE_NATIVEONLY: case MODE_TRROFF: @@ -1686,6 +1695,11 @@ nsHostResolver::CompleteLookup(nsHostRecord* rec, nsresult status, AddrInfo* aNe TimeDuration age = TimeStamp::NowLoRes() - head->mValidStart; Telemetry::Accumulate(Telemetry::DNS_CLEANUP_AGE, static_cast(age.ToSeconds() / 60)); + if (head->CheckExpiration(TimeStamp::Now()) != + nsHostRecord::EXP_EXPIRED) { + Telemetry::Accumulate(Telemetry::DNS_PREMATURE_EVICTION, + static_cast(age.ToSeconds() / 60)); + } } } } diff --git a/netwerk/sctp/src/netinet/sctp_crc32.c b/netwerk/sctp/src/netinet/sctp_crc32.c index 16ce971c7d2f..a15095c97085 100755 --- a/netwerk/sctp/src/netinet/sctp_crc32.c +++ b/netwerk/sctp/src/netinet/sctp_crc32.c @@ -60,7 +60,7 @@ __FBSDID("$FreeBSD: head/sys/netinet/sctp_crc32.c 310590 2016-12-26 11:06:41Z tu * non-NULL if the mode argument is equal to CONT or END * p_buf - the packet buffer where crc computations are being performed * length - the length of p_buf in bytes - * init_bytes - the number of initial bytes that need to be procesed before + * init_bytes - the number of initial bytes that need to be processed before * aligning p_buf to multiples of 4 bytes * mode - can be any of the following: BEGIN, CONT, END, BODY, ALIGN * diff --git a/security/certverifier/CertVerifier.h b/security/certverifier/CertVerifier.h index 93c534c154b0..61e2bd41f264 100644 --- a/security/certverifier/CertVerifier.h +++ b/security/certverifier/CertVerifier.h @@ -63,12 +63,16 @@ enum class SHA1ModeResult { // Whether or not we are enforcing one of our CA distrust policies. For context, // see Bug 1437754 and Bug 1409257. -enum class DistrustedCAPolicy : uint32_t { - Permit = 0, - DistrustSymantecRoots = 1, - DistrustSymantecRootsRegardlessOfDate = 2, +enum DistrustedCAPolicy : uint32_t { + Permit = 0b0000, + DistrustSymantecRoots = 0b0001, + DistrustSymantecRootsRegardlessOfDate = 0b0010, }; +// Bitmask by nsNSSComponent to check for wholly-invalid values; be sure to +// update this to account for new entries in DistrustedCAPolicy. +const uint32_t DistrustedCAPolicyMaxAllowedValueMask = 0b0011; + enum class NetscapeStepUpPolicy : uint32_t; class PinningTelemetryInfo diff --git a/security/certverifier/NSSCertDBTrustDomain.cpp b/security/certverifier/NSSCertDBTrustDomain.cpp index 24626b6d836c..a4f17ed814bb 100644 --- a/security/certverifier/NSSCertDBTrustDomain.cpp +++ b/security/certverifier/NSSCertDBTrustDomain.cpp @@ -877,7 +877,8 @@ NSSCertDBTrustDomain::IsChainValid(const DERArray& certArray, Time time, // handshake. To determine this, we check mHostname: If it isn't set, this is // not TLS, so don't run the algorithm. if (mHostname && CertDNIsInList(root.get(), RootSymantecDNs) && - mDistrustedCAPolicy != DistrustedCAPolicy::Permit) { + ((mDistrustedCAPolicy & DistrustedCAPolicy::DistrustSymantecRoots) || + (mDistrustedCAPolicy & DistrustedCAPolicy::DistrustSymantecRootsRegardlessOfDate))) { rootCert = nullptr; // Clear the state for Segment... nsCOMPtr intCerts; @@ -893,9 +894,9 @@ NSSCertDBTrustDomain::IsChainValid(const DERArray& certArray, Time time, // (new Date("2016-06-01T00:00:00Z")).getTime() * 1000 static const PRTime JUNE_1_2016 = 1464739200000000; - PRTime permitAfterDate = 0; // 0 indicates there is no permitAfterDate - if (mDistrustedCAPolicy == DistrustedCAPolicy::DistrustSymantecRoots) { - permitAfterDate = JUNE_1_2016; + PRTime permitAfterDate = JUNE_1_2016; + if (mDistrustedCAPolicy & DistrustedCAPolicy::DistrustSymantecRootsRegardlessOfDate) { + permitAfterDate = 0; // 0 indicates there is no permitAfterDate } bool isDistrusted = false; diff --git a/security/manager/ssl/nsNSSComponent.cpp b/security/manager/ssl/nsNSSComponent.cpp index 94ca1bac4add..e05a70ad6fa6 100644 --- a/security/manager/ssl/nsNSSComponent.cpp +++ b/security/manager/ssl/nsNSSComponent.cpp @@ -1688,14 +1688,10 @@ void nsNSSComponent::setValidationOptions(bool isInitialSetting) static_cast (Preferences::GetUint("security.pki.distrust_ca_policy", static_cast(defaultCAPolicyMode))); - switch(distrustedCAPolicy) { - case DistrustedCAPolicy::Permit: - case DistrustedCAPolicy::DistrustSymantecRoots: - case DistrustedCAPolicy::DistrustSymantecRootsRegardlessOfDate: - break; - default: - distrustedCAPolicy = defaultCAPolicyMode; - break; + // If distrustedCAPolicy sets any bits larger than the maximum mask, fall back + // to the default. + if (distrustedCAPolicy & ~DistrustedCAPolicyMaxAllowedValueMask) { + distrustedCAPolicy = defaultCAPolicyMode; } CertVerifier::OcspDownloadConfig odc; diff --git a/security/manager/ssl/tests/unit/test_symantec_apple_google.js b/security/manager/ssl/tests/unit/test_symantec_apple_google.js index 2fe90553a826..8d2100f2274a 100644 --- a/security/manager/ssl/tests/unit/test_symantec_apple_google.js +++ b/security/manager/ssl/tests/unit/test_symantec_apple_google.js @@ -40,11 +40,11 @@ add_connection_test("symantec-not-whitelisted-before-cutoff.example.com", null, null); // Enable the Firefox 63 total distrust; before or after cutoff should now all -// behave the same. +// behave the same. This will be made the default in Bug 1460062. add_test(function() { clearSessionCache(); Services.prefs.setIntPref("security.pki.distrust_ca_policy", - /* DistrustedCAPolicy::DistrustSymantecRootsRegardlessOfDate */ 2); + /* DistrustedCAPolicy::DistrustSymantecRootsRegardlessOfDate */ 0b10); run_next_test(); }); @@ -60,7 +60,7 @@ add_connection_test("symantec-not-whitelisted-after-cutoff.example.com", add_test(function() { clearSessionCache(); Services.prefs.setIntPref("security.pki.distrust_ca_policy", - /* DistrustedCAPolicy::Permit */ 0); + /* DistrustedCAPolicy::Permit */ 0b00); run_next_test(); }); @@ -96,7 +96,7 @@ add_task(async function() { // Try with the policy for 60 Services.prefs.setIntPref("security.pki.distrust_ca_policy", - /* DistrustedCAPolicy::DistrustSymantecRoots */ 1); + /* DistrustedCAPolicy::DistrustSymantecRoots */ 0b01); // (new Date("2018-02-16")).getTime() / 1000 const VALIDATION_TIME = 1518739200; @@ -106,8 +106,23 @@ add_task(async function() { // Try with the policy for 63 Services.prefs.setIntPref("security.pki.distrust_ca_policy", - /* DistrustedCAPolicy::DistrustSymantecRootsRegardlessOfDate */ 2); + /* DistrustedCAPolicy::DistrustSymantecRootsRegardlessOfDate */ 0b10); await checkCertErrorGenericAtTime(certDB, whitelistedCert, PRErrorCodeSuccess, certificateUsageSSLServer, VALIDATION_TIME); }); + +// Check invalid policy values; should default to current default +add_test(function() { + clearSessionCache(); + Services.prefs.setIntPref("security.pki.distrust_ca_policy", + /* Larger than Max Value */ 0b1111); + run_next_test(); +}); + +add_connection_test("symantec-not-whitelisted-before-cutoff.example.com", + MOZILLA_PKIX_ERROR_ADDITIONAL_POLICY_CONSTRAINT_FAILED, + null, null); + +add_connection_test("symantec-not-whitelisted-after-cutoff.example.com", + PRErrorCodeSuccess, null, shouldBeImminentlyDistrusted); diff --git a/servo/components/style/properties/longhand/background.mako.rs b/servo/components/style/properties/longhand/background.mako.rs index d6b9e6e69ba8..a1f1b0394340 100644 --- a/servo/components/style/properties/longhand/background.mako.rs +++ b/servo/components/style/properties/longhand/background.mako.rs @@ -54,7 +54,7 @@ ${helpers.predefined_type( ${helpers.single_keyword("background-attachment", "scroll fixed" + (" local" if product == "gecko" else ""), vector=True, - gecko_constant_prefix="NS_STYLE_IMAGELAYER_ATTACHMENT", + gecko_enum_prefix="StyleImageLayerAttachment", spec="https://drafts.csswg.org/css-backgrounds/#the-background-attachment", animation_value_type="discrete", flags="APPLIES_TO_FIRST_LETTER APPLIES_TO_FIRST_LINE APPLIES_TO_PLACEHOLDER")} diff --git a/toolkit/components/telemetry/Histograms.json b/toolkit/components/telemetry/Histograms.json index 58ba7df83442..2aa4ccf71677 100644 --- a/toolkit/components/telemetry/Histograms.json +++ b/toolkit/components/telemetry/Histograms.json @@ -3231,6 +3231,17 @@ "n_buckets": 50, "description": "DNS Cache Entry Age at Removal Time (minutes)" }, + "DNS_PREMATURE_EVICTION": { + "record_in_processes": ["main"], + "expires_in_version": "never", + "kind": "exponential", + "high": 1440, + "releaseChannelCollection": "opt-out", + "alert_emails": ["necko@mozilla.com", "dstenberg@mozilla.com"], + "bug_numbers": [1460305], + "n_buckets": 50, + "description": "DNS Cache Entry Age at Removal Time of non-expired entries (minutes)" + }, "DNS_LOOKUP_TIME": { "record_in_processes": ["main"], "expires_in_version": "never", @@ -3272,6 +3283,15 @@ "bug_numbers": [1434852], "description": "DNS: TRR parallel resolve racing results" }, + "DNS_TRR_COMPARE": { + "record_in_processes": ["main"], + "alert_emails": ["necko@mozilla.com", "dstenberg@mozilla.com"], + "expires_in_version": "never", + "kind": "categorical", + "labels": ["BothWorked", "NativeWorked", "TRRWorked", "BothFailed"], + "bug_numbers": [1460589], + "description": "DNS: success distribution when both native and TRR were used" + }, "DNS_TRR_BLACKLISTED": { "record_in_processes": ["main"], "expires_in_version": "never", diff --git a/toolkit/crashreporter/nsExceptionHandler.cpp b/toolkit/crashreporter/nsExceptionHandler.cpp index 3818cf708d85..43adda9234d8 100644 --- a/toolkit/crashreporter/nsExceptionHandler.cpp +++ b/toolkit/crashreporter/nsExceptionHandler.cpp @@ -840,7 +840,7 @@ LaunchCrashReporterActivity(XP_CHAR* aProgramPath, XP_CHAR* aMinidumpPath, if (androidUserSerial) { Unused << execlp("/system/bin/am", "/system/bin/am", - "start", + "startservice", "--user", androidUserSerial, "-a", "org.mozilla.gecko.reportCrash", "-n", aProgramPath, @@ -850,7 +850,7 @@ LaunchCrashReporterActivity(XP_CHAR* aProgramPath, XP_CHAR* aMinidumpPath, } else { Unused << execlp("/system/bin/am", "/system/bin/am", - "start", + "startservice", "-a", "org.mozilla.gecko.reportCrash", "-n", aProgramPath, "--es", "minidumpPath", aMinidumpPath, @@ -1544,10 +1544,10 @@ nsresult SetExceptionHandler(nsIFile* aXREDirectory, const char* androidPackageName = PR_GetEnv("MOZ_ANDROID_PACKAGE_NAME"); if (androidPackageName != nullptr) { nsCString package(androidPackageName); - package.AppendLiteral("/org.mozilla.gecko.CrashReporter"); + package.AppendLiteral("/org.mozilla.gecko.CrashReporterService"); crashReporterPath = ToNewCString(package); } else { - nsCString package(ANDROID_PACKAGE_NAME "/org.mozilla.gecko.CrashReporter"); + nsCString package(ANDROID_PACKAGE_NAME "/org.mozilla.gecko.CrashReporterService"); crashReporterPath = ToNewCString(package); } #endif // !defined(MOZ_WIDGET_ANDROID) diff --git a/widget/android/nsAppShell.cpp b/widget/android/nsAppShell.cpp index f7e4cf29359a..11f4cb8c2823 100644 --- a/widget/android/nsAppShell.cpp +++ b/widget/android/nsAppShell.cpp @@ -407,6 +407,7 @@ nsAppShell::nsAppShell() if (!XRE_IsParentProcess()) { if (jni::IsAvailable()) { GeckoThreadSupport::Init(); + GeckoAppShellSupport::Init(); // Set the corresponding state in GeckoThread. java::GeckoThread::SetState(java::GeckoThread::State::RUNNING()); diff --git a/widget/cocoa/TextInputHandler.mm b/widget/cocoa/TextInputHandler.mm index eb2057a85a08..d0fd66217992 100644 --- a/widget/cocoa/TextInputHandler.mm +++ b/widget/cocoa/TextInputHandler.mm @@ -3752,7 +3752,7 @@ IMEInputHandler::MaybeDispatchCurrentKeydownEvent(bool aIsProcessedByIME) MOZ_LOG(gLog, LogLevel::Info, ("%p IMEInputHandler::MaybeDispatchKeydownEvent, aIsProcessedByIME=%s " "currentKeyEvent={ mKeyEvent(%p)={ type=%s, keyCode=%s (0x%X) } }, " - "aIsProcesedBy=%s, IsDeadKeyComposing()=%s", + "aIsProcessedBy=%s, IsDeadKeyComposing()=%s", this, TrueOrFalse(aIsProcessedByIME), nativeEvent, GetNativeKeyEventType(nativeEvent), GetKeyNameForNativeKeyCode([nativeEvent keyCode]), [nativeEvent keyCode],