зеркало из https://github.com/mozilla/gecko-dev.git
Merge inbound to mozilla-central. a=merge
This commit is contained in:
Коммит
4f9a2ba08e
|
@ -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) {
|
||||
|
|
|
@ -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
|
||||
{
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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<RefCountedMonitor> 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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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(); }
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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<ModuleSegment>(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<ModuleSegment>();
|
||||
if (!ms)
|
||||
return nullptr;
|
||||
|
||||
if (!ms->initialize(tier, Move(codeBytes), codeLength, bytecode, linkData, metadata, codeRanges))
|
||||
return nullptr;
|
||||
|
||||
return UniqueModuleSegment(ms.release());
|
||||
return js::MakeUnique<ModuleSegment>(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<uint32_t>(cursor, length_);
|
||||
uint8_t* base = cursor;
|
||||
cursor = WriteBytes(cursor, bytes_.get(), length_);
|
||||
StaticallyUnlink(base, linkData);
|
||||
cursor = WriteScalar<uint32_t>(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<uint32_t>(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<ModuleSegment>(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<LazyStubSegment>(codeTier);
|
||||
if (!segment || !segment->initialize(Move(codeBytes), length))
|
||||
auto segment = js::MakeUnique<LazyStubSegment>(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<MetadataTier>(Tier::Serialized);
|
||||
if (!metadata_)
|
||||
auto metadata = js::MakeUnique<MetadataTier>(Tier::Serialized);
|
||||
if (!metadata)
|
||||
return nullptr;
|
||||
cursor = metadata_->deserialize(cursor);
|
||||
cursor = metadata->deserialize(cursor);
|
||||
if (!cursor)
|
||||
return nullptr;
|
||||
|
||||
auto segment = Move(js::MakeUnique<ModuleSegment>());
|
||||
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<CodeTier>(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<CodeTier>(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<Code>(Move(codeTier), metadata, Move(jumpTables));
|
||||
if (!code || !code->initialize(bytecode, linkData.tier(Tier::Serialized)))
|
||||
return nullptr;
|
||||
|
||||
*out = code;
|
||||
return cursor;
|
||||
}
|
||||
|
|
|
@ -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<ModuleSegment> UniqueModuleSegment;
|
||||
typedef UniquePtr<const ModuleSegment> 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<MetadataTier>;
|
|||
// isn't (64KiB), a given stub segment can contain entry stubs of many
|
||||
// functions.
|
||||
|
||||
using UniqueLazyStubSegment = UniquePtr<LazyStubSegment>;
|
||||
using LazyStubSegmentVector = Vector<UniqueLazyStubSegment, 0, SystemAllocPolicy>;
|
||||
|
||||
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<LazyStubSegment> 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<LazyStubSegment>;
|
||||
using LazyStubSegmentVector = Vector<UniqueLazyStubSegment, 0, SystemAllocPolicy>;
|
||||
|
||||
// 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<CodeTier> UniqueCodeTier;
|
||||
typedef UniquePtr<const CodeTier> 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<LazyStubTier> 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<LazyStubTier>& 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<CodeTier> UniqueCodeTier;
|
||||
typedef UniquePtr<const CodeTier> 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<const Code> SharedCode;
|
||||
typedef RefPtr<Code> MutableCode;
|
||||
|
||||
class Code : public ShareableBase<Code>
|
||||
{
|
||||
UniqueConstCodeTier tier1_;
|
||||
UniqueCodeTier tier1_;
|
||||
mutable UniqueConstCodeTier tier2_; // Access only when hasTier2() is true
|
||||
mutable Atomic<bool> hasTier2_;
|
||||
SharedMetadata metadata_;
|
||||
ExclusiveData<CacheableCharsVector> 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<Code>
|
|||
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<Code>
|
|||
// 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<const Code> SharedCode;
|
||||
typedef RefPtr<Code> MutableCode;
|
||||
|
||||
} // namespace wasm
|
||||
} // namespace js
|
||||
|
||||
|
|
|
@ -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<CodeTier>(tier(), Move(metadataTier_), Move(moduleSegment));
|
||||
auto codeTier = js::MakeUnique<CodeTier>(Move(metadataTier_), Move(moduleSegment));
|
||||
if (!codeTier)
|
||||
return nullptr;
|
||||
|
||||
SharedCode code = js_new<Code>(Move(codeTier), *metadata_, Move(jumpTables));
|
||||
if (!code)
|
||||
MutableCode code = js_new<Code>(Move(codeTier), *metadata_, Move(jumpTables));
|
||||
if (!code || !code->initialize(bytecode, *linkDataTier_))
|
||||
return nullptr;
|
||||
|
||||
SharedModule module(js_new<Module>(Move(assumptions_),
|
||||
|
@ -1012,7 +1011,7 @@ ModuleGenerator::finishTier2(Module& module)
|
|||
if (!moduleSegment)
|
||||
return false;
|
||||
|
||||
auto tier2 = js::MakeUnique<CodeTier>(tier(), Move(metadataTier_), Move(moduleSegment));
|
||||
auto tier2 = js::MakeUnique<CodeTier>(Move(metadataTier_), Move(moduleSegment));
|
||||
if (!tier2)
|
||||
return false;
|
||||
|
||||
|
|
|
@ -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<LinkDataTier>(Tier::Serialized);
|
||||
if (!linkData1_)
|
||||
MOZ_ASSERT(!tier1_);
|
||||
tier1_ = js::MakeUnique<LinkDataTier>(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<size_t> 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<Code>();
|
||||
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<CodeTier>(tier, Move(metadataTier), Move(segment));
|
||||
auto codeTier = js::MakeUnique<CodeTier>(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<Code>(Move(codeTier), metadata(), Move(jumpTables));
|
||||
if (!code) {
|
||||
MutableCode debugCode = js_new<Code>(Move(codeTier), metadata(), Move(jumpTables));
|
||||
if (!debugCode || !debugCode->initialize(*bytecode_, linkData(tier))) {
|
||||
ReportOutOfMemory(cx);
|
||||
return false;
|
||||
}
|
||||
|
||||
code = debugCode;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -82,15 +82,15 @@ typedef UniquePtr<LinkDataTier> 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_; }
|
||||
|
|
|
@ -217,6 +217,7 @@ static ProcessCodeSegmentMap processCodeSegmentMap;
|
|||
bool
|
||||
wasm::RegisterCodeSegment(const CodeSegment* cs)
|
||||
{
|
||||
MOZ_ASSERT(cs->codeTier().code().initialized());
|
||||
return processCodeSegmentMap.insert(cs);
|
||||
}
|
||||
|
||||
|
|
|
@ -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 =
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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 }
|
||||
};
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -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) {
|
||||
|
|
|
@ -64,7 +64,7 @@
|
|||
</issue>
|
||||
|
||||
<!-- We fixed all "Registered" lint errors. However the current gradle plugin has a bug where
|
||||
it ignores @SuppressLint annotations for this check. See CrashReporter class and
|
||||
it ignores @SuppressLint annotations for this check. See CrashReporterActivity class and
|
||||
https://code.google.com/p/android/issues/detail?id=204846 -->
|
||||
<issue id="Registered" severity="warning" />
|
||||
|
||||
|
|
|
@ -272,7 +272,7 @@
|
|||
#include ../services/manifests/FxAccountAndroidManifest_activities.xml.in
|
||||
|
||||
#ifdef MOZ_CRASHREPORTER
|
||||
<activity android:name="org.mozilla.gecko.CrashReporter"
|
||||
<activity android:name="org.mozilla.gecko.CrashReporterActivity"
|
||||
android:process="@ANDROID_PACKAGE_NAME@.CrashReporter"
|
||||
android:label="@string/crash_reporter_title"
|
||||
android:icon="@drawable/crash_reporter"
|
||||
|
|
|
@ -28,7 +28,6 @@ import java.security.MessageDigest;
|
|||
import java.util.zip.GZIPOutputStream;
|
||||
|
||||
import org.mozilla.gecko.AppConstants.Versions;
|
||||
import org.mozilla.gecko.GeckoProfile;
|
||||
import org.mozilla.gecko.mozglue.GeckoLoader;
|
||||
import org.mozilla.gecko.mozglue.MinidumpAnalyzer;
|
||||
import org.mozilla.gecko.telemetry.pingbuilders.TelemetryCrashPingBuilder;
|
||||
|
@ -57,7 +56,7 @@ import android.widget.EditText;
|
|||
// Registered: This activity is only registered in the manifest if MOZ_CRASHREPORTER is set.
|
||||
// CutPasteId: This lint is not worth fixing. To fix it, cache all the findViewById results.
|
||||
@SuppressLint("Registered,CutPasteId")
|
||||
public class CrashReporter extends AppCompatActivity
|
||||
public class CrashReporterActivity extends AppCompatActivity
|
||||
{
|
||||
private static final String LOGTAG = "GeckoCrashReporter";
|
||||
|
||||
|
@ -210,7 +209,7 @@ public class CrashReporter extends AppCompatActivity
|
|||
final EditText commentsEditText = (EditText) findViewById(R.id.comment);
|
||||
final EditText emailEditText = (EditText) findViewById(R.id.email);
|
||||
|
||||
// Load CrashReporter preferences to avoid redundant user input.
|
||||
// Load CrashReporterActivity preferences to avoid redundant user input.
|
||||
SharedPreferences prefs = GeckoSharedPrefs.forCrashReporter(this);
|
||||
final boolean sendReport = prefs.getBoolean(PREFS_SEND_REPORT, true);
|
||||
final boolean includeUrl = prefs.getBoolean(PREFS_INCLUDE_URL, false);
|
||||
|
@ -271,7 +270,7 @@ public class CrashReporter extends AppCompatActivity
|
|||
builder.setPositiveButton(R.string.button_ok, new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
CrashReporter.this.finish();
|
||||
CrashReporterActivity.this.finish();
|
||||
}
|
||||
});
|
||||
builder.show();
|
||||
|
@ -293,7 +292,7 @@ public class CrashReporter extends AppCompatActivity
|
|||
public void run() {
|
||||
sendReport(mPendingMinidumpFile, mExtrasStringMap, mPendingExtrasFile);
|
||||
}
|
||||
}, "CrashReporter Thread").start();
|
||||
}, "CrashReporterActivity Thread").start();
|
||||
}
|
||||
|
||||
private void savePrefs() {
|
|
@ -123,7 +123,6 @@ public abstract class GeckoApp extends GeckoActivity
|
|||
public static final String ACTION_ALERT_CALLBACK = "org.mozilla.gecko.ALERT_CALLBACK";
|
||||
public static final String ACTION_HOMESCREEN_SHORTCUT = "org.mozilla.gecko.BOOKMARK";
|
||||
public static final String ACTION_WEBAPP = "org.mozilla.gecko.WEBAPP";
|
||||
public static final String ACTION_DEBUG = "org.mozilla.gecko.DEBUG";
|
||||
public static final String ACTION_LAUNCH_SETTINGS = "org.mozilla.gecko.SETTINGS";
|
||||
public static final String ACTION_LOAD = "org.mozilla.gecko.LOAD";
|
||||
public static final String ACTION_INIT_PW = "org.mozilla.gecko.INIT_PW";
|
||||
|
@ -998,6 +997,18 @@ public abstract class GeckoApp extends GeckoActivity
|
|||
return;
|
||||
}
|
||||
|
||||
// To prevent races, register startup events before launching the Gecko thread.
|
||||
EventDispatcher.getInstance().registerGeckoThreadListener(this,
|
||||
"Gecko:Ready",
|
||||
null);
|
||||
|
||||
EventDispatcher.getInstance().registerUiThreadListener(this,
|
||||
"Gecko:CorruptAPK",
|
||||
"Update:Check",
|
||||
"Update:Download",
|
||||
"Update:Install",
|
||||
null);
|
||||
|
||||
if (sAlreadyLoaded) {
|
||||
// This happens when the GeckoApp activity is destroyed by Android
|
||||
// without killing the entire application (see Bug 769269).
|
||||
|
@ -1005,15 +1016,14 @@ public abstract class GeckoApp extends GeckoActivity
|
|||
// also happen if we're not the first activity to run within a session.
|
||||
mIsRestoringActivity = true;
|
||||
Telemetry.addToHistogram("FENNEC_RESTORING_ACTIVITY", 1);
|
||||
|
||||
} else {
|
||||
final String action = intent.getAction();
|
||||
final String[] args = GeckoApplication.getDefaultGeckoArgs();
|
||||
final int flags = ACTION_DEBUG.equals(action) ? GeckoThread.FLAG_DEBUGGING : 0;
|
||||
|
||||
sAlreadyLoaded = true;
|
||||
GeckoThread.initMainProcess(/* profile */ null, args,
|
||||
intent.getExtras(), flags);
|
||||
if (GeckoApplication.getRuntime() == null) {
|
||||
GeckoApplication.createRuntime(this, intent);
|
||||
}
|
||||
|
||||
// Speculatively pre-fetch the profile in the background.
|
||||
ThreadUtils.postToBackgroundThread(new Runnable() {
|
||||
|
@ -1030,20 +1040,6 @@ public abstract class GeckoApp extends GeckoActivity
|
|||
}
|
||||
}
|
||||
|
||||
// To prevent races, register startup events before launching the Gecko thread.
|
||||
EventDispatcher.getInstance().registerGeckoThreadListener(this,
|
||||
"Gecko:Ready",
|
||||
null);
|
||||
|
||||
EventDispatcher.getInstance().registerUiThreadListener(this,
|
||||
"Gecko:CorruptAPK",
|
||||
"Update:Check",
|
||||
"Update:Download",
|
||||
"Update:Install",
|
||||
null);
|
||||
|
||||
GeckoThread.launch();
|
||||
|
||||
Bundle stateBundle = IntentUtils.getBundleExtraSafe(getIntent(), EXTRA_STATE_BUNDLE);
|
||||
if (stateBundle != null) {
|
||||
// Use the state bundle if it was given as an intent extra. This is
|
||||
|
@ -1081,7 +1077,7 @@ public abstract class GeckoApp extends GeckoActivity
|
|||
if (mLayerView.getSession() != null) {
|
||||
mLayerView.getSession().close();
|
||||
}
|
||||
mLayerView.setSession(session, GeckoRuntime.getDefault(this));
|
||||
mLayerView.setSession(session, GeckoApplication.getRuntime());
|
||||
mLayerView.setOverScrollMode(View.OVER_SCROLL_NEVER);
|
||||
|
||||
getAppEventDispatcher().registerGeckoThreadListener(this,
|
||||
|
|
|
@ -13,10 +13,12 @@ import android.content.Intent;
|
|||
import android.content.res.Configuration;
|
||||
import android.graphics.Bitmap;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.os.Environment;
|
||||
import android.os.Process;
|
||||
import android.os.SystemClock;
|
||||
import android.provider.MediaStore;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.design.widget.Snackbar;
|
||||
import android.text.TextUtils;
|
||||
|
@ -38,6 +40,7 @@ import org.mozilla.gecko.icons.Icons;
|
|||
import org.mozilla.gecko.lwt.LightweightTheme;
|
||||
import org.mozilla.gecko.mdns.MulticastDNSManager;
|
||||
import org.mozilla.gecko.media.AudioFocusAgent;
|
||||
import org.mozilla.gecko.mozglue.SafeIntent;
|
||||
import org.mozilla.gecko.notifications.NotificationClient;
|
||||
import org.mozilla.gecko.notifications.NotificationHelper;
|
||||
import org.mozilla.gecko.permissions.Permissions;
|
||||
|
@ -53,6 +56,8 @@ import org.mozilla.gecko.util.HardwareUtils;
|
|||
import org.mozilla.gecko.util.PRNGFixes;
|
||||
import org.mozilla.gecko.util.ShortcutUtils;
|
||||
import org.mozilla.gecko.util.ThreadUtils;
|
||||
import org.mozilla.geckoview.GeckoRuntime;
|
||||
import org.mozilla.geckoview.GeckoRuntimeSettings;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.File;
|
||||
|
@ -65,6 +70,7 @@ import java.util.UUID;
|
|||
public class GeckoApplication extends Application
|
||||
implements HapticFeedbackDelegate {
|
||||
private static final String LOG_TAG = "GeckoApplication";
|
||||
public static final String ACTION_DEBUG = "org.mozilla.gecko.DEBUG";
|
||||
private static final String MEDIA_DECODING_PROCESS_CRASH = "MEDIA_DECODING_PROCESS_CRASH";
|
||||
|
||||
private boolean mInBackground;
|
||||
|
@ -113,7 +119,7 @@ public class GeckoApplication extends Application
|
|||
"startup (JavaScript) caches.");
|
||||
return new String[] { "-purgecaches" };
|
||||
}
|
||||
return null;
|
||||
return new String[0];
|
||||
}
|
||||
|
||||
public static String getDefaultUAString() {
|
||||
|
@ -210,6 +216,50 @@ public class GeckoApplication extends Application
|
|||
mInBackground = false;
|
||||
}
|
||||
|
||||
private static GeckoRuntime sGeckoRuntime;
|
||||
public static GeckoRuntime getRuntime() {
|
||||
return sGeckoRuntime;
|
||||
}
|
||||
|
||||
public static GeckoRuntime ensureRuntime(@NonNull Context context) {
|
||||
if (sGeckoRuntime != null) {
|
||||
return sGeckoRuntime;
|
||||
}
|
||||
|
||||
return createRuntime(context, null);
|
||||
}
|
||||
|
||||
private static GeckoRuntimeSettings.Builder createSettingsBuilder() {
|
||||
return new GeckoRuntimeSettings.Builder()
|
||||
.javaCrashReportingEnabled(true)
|
||||
.nativeCrashReportingEnabled(true)
|
||||
.arguments(getDefaultGeckoArgs());
|
||||
}
|
||||
|
||||
public static GeckoRuntime createRuntime(@NonNull Context context,
|
||||
@Nullable SafeIntent intent) {
|
||||
if (sGeckoRuntime != null) {
|
||||
throw new IllegalStateException("Already have a GeckoRuntime!");
|
||||
}
|
||||
|
||||
if (context == null) {
|
||||
throw new IllegalArgumentException("Context must not be null");
|
||||
}
|
||||
|
||||
GeckoRuntimeSettings.Builder builder = createSettingsBuilder();
|
||||
if (intent != null) {
|
||||
builder.pauseForDebugger(ACTION_DEBUG.equals(intent.getAction()));
|
||||
|
||||
Bundle extras = intent.getExtras();
|
||||
if (extras != null) {
|
||||
builder.extras(extras);
|
||||
}
|
||||
}
|
||||
|
||||
sGeckoRuntime = GeckoRuntime.create(context, builder.build());
|
||||
return sGeckoRuntime;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate() {
|
||||
Log.i(LOG_TAG, "zerdatime " + SystemClock.elapsedRealtime() +
|
||||
|
|
|
@ -18,6 +18,7 @@ import android.util.Log;
|
|||
|
||||
import java.io.File;
|
||||
|
||||
import org.mozilla.gecko.mozglue.SafeIntent;
|
||||
import org.mozilla.gecko.util.BundleEventListener;
|
||||
import org.mozilla.gecko.util.GeckoBundle;
|
||||
import org.mozilla.gecko.util.EventCallback;
|
||||
|
@ -166,19 +167,22 @@ public class GeckoService extends Service {
|
|||
throw new IllegalArgumentException("Intent must specify profile.");
|
||||
}
|
||||
|
||||
if (!GeckoThread.initMainProcessWithProfile(
|
||||
profileName, profileDir != null ? new File(profileDir) : null,
|
||||
GeckoApplication.getDefaultGeckoArgs(), intent.getExtras())) {
|
||||
Log.w(LOGTAG, "Ignoring due to profile mismatch: " +
|
||||
profileName + " [" + profileDir + ']');
|
||||
|
||||
final GeckoProfile profile = GeckoThread.getActiveProfile();
|
||||
if (profile != null) {
|
||||
Log.w(LOGTAG, "Current profile is " + profile.getName() +
|
||||
" [" + profile.getDir().getAbsolutePath() + ']');
|
||||
}
|
||||
return false;
|
||||
if (GeckoApplication.getRuntime() != null) {
|
||||
// Gecko has already been initialized, make sure it's using the
|
||||
// expected profile.
|
||||
return GeckoThread.canUseProfile(profileName,
|
||||
profileDir != null ? new File(profileDir) : null);
|
||||
}
|
||||
|
||||
String args;
|
||||
if (profileDir != null) {
|
||||
args = "-profile " + profileDir;
|
||||
} else {
|
||||
args = "-P " + profileName;
|
||||
}
|
||||
|
||||
intent.putExtra(GeckoThread.EXTRA_ARGS, args);
|
||||
GeckoApplication.createRuntime(this, new SafeIntent(intent));
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -192,8 +196,6 @@ public class GeckoService extends Service {
|
|||
return Service.START_NOT_STICKY;
|
||||
}
|
||||
|
||||
GeckoThread.launch();
|
||||
|
||||
switch (intent.getAction()) {
|
||||
case INTENT_ACTION_UPDATE_ADDONS:
|
||||
// Run the add-on update service. Because the service is automatically invoked
|
||||
|
|
|
@ -132,7 +132,7 @@ class VirtualPresentation extends CastPresentation {
|
|||
|
||||
// Create new GeckoView
|
||||
view = new GeckoView(getContext());
|
||||
view.setSession(session, GeckoRuntime.getDefault(getContext()));
|
||||
view.setSession(session, GeckoApplication.ensureRuntime(getContext()));
|
||||
view.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT,
|
||||
LayoutParams.MATCH_PARENT));
|
||||
|
||||
|
|
|
@ -37,6 +37,7 @@ import org.mozilla.gecko.Clipboard;
|
|||
import org.mozilla.gecko.DoorHangerPopup;
|
||||
import org.mozilla.gecko.EventDispatcher;
|
||||
import org.mozilla.gecko.FormAssistPopup;
|
||||
import org.mozilla.gecko.GeckoApplication;
|
||||
import org.mozilla.gecko.GeckoSharedPrefs;
|
||||
import org.mozilla.gecko.preferences.GeckoPreferences;
|
||||
import org.mozilla.gecko.R;
|
||||
|
@ -131,7 +132,7 @@ public class CustomTabsActivity extends AppCompatActivity
|
|||
mGeckoSession.setProgressDelegate(this);
|
||||
mGeckoSession.setContentDelegate(this);
|
||||
|
||||
mGeckoView.setSession(mGeckoSession, GeckoRuntime.getDefault(this));
|
||||
mGeckoView.setSession(mGeckoSession, GeckoApplication.ensureRuntime(this));
|
||||
|
||||
mPromptService = new PromptService(this, mGeckoView.getEventDispatcher());
|
||||
mDoorHangerPopup = new DoorHangerPopup(this, mGeckoView.getEventDispatcher());
|
||||
|
|
|
@ -26,6 +26,7 @@ import org.mozilla.gecko.AppConstants;
|
|||
import org.mozilla.gecko.BrowserApp;
|
||||
import org.mozilla.gecko.DoorHangerPopup;
|
||||
import org.mozilla.gecko.FormAssistPopup;
|
||||
import org.mozilla.gecko.GeckoApplication;
|
||||
import org.mozilla.gecko.GeckoScreenOrientation;
|
||||
import org.mozilla.gecko.GeckoSharedPrefs;
|
||||
import org.mozilla.gecko.preferences.GeckoPreferences;
|
||||
|
@ -97,7 +98,7 @@ public class WebAppActivity extends AppCompatActivity
|
|||
final GeckoSessionSettings settings = new GeckoSessionSettings();
|
||||
settings.setBoolean(GeckoSessionSettings.USE_MULTIPROCESS, false);
|
||||
mGeckoSession = new GeckoSession(settings);
|
||||
mGeckoView.setSession(mGeckoSession, GeckoRuntime.getDefault(this));
|
||||
mGeckoView.setSession(mGeckoSession, GeckoApplication.ensureRuntime(this));
|
||||
|
||||
mGeckoSession.setNavigationDelegate(this);
|
||||
mGeckoSession.setContentDelegate(this);
|
||||
|
|
|
@ -139,6 +139,10 @@ android {
|
|||
exclude 'org/mozilla/gecko/media/Utils.java'
|
||||
}
|
||||
|
||||
if (!mozconfig.substs.MOZ_CRASHREPORTER) {
|
||||
exclude 'org/mozilla/gecko/CrashReporterService.java'
|
||||
}
|
||||
|
||||
if (mozconfig.substs.MOZ_WEBRTC) {
|
||||
srcDir "${topsrcdir}/media/webrtc/trunk/webrtc/base/java/src"
|
||||
srcDir "${topsrcdir}/media/webrtc/trunk/webrtc/modules/audio_device/android/java/src"
|
||||
|
|
|
@ -120,6 +120,10 @@ public class TestRunnerActivity extends Activity {
|
|||
runtimeSettingsBuilder.extras(extras);
|
||||
}
|
||||
|
||||
runtimeSettingsBuilder
|
||||
.nativeCrashReportingEnabled(true)
|
||||
.javaCrashReportingEnabled(true);
|
||||
|
||||
sRuntime = GeckoRuntime.create(this, runtimeSettingsBuilder.build());
|
||||
sRuntime.setDelegate(new GeckoRuntime.Delegate() {
|
||||
@Override
|
||||
|
|
|
@ -847,7 +847,10 @@ public class GeckoSessionTestRule extends UiThreadTestRule {
|
|||
final GeckoRuntimeSettings.Builder runtimeSettingsBuilder =
|
||||
new GeckoRuntimeSettings.Builder();
|
||||
runtimeSettingsBuilder.arguments(new String[] { "-purgecaches" })
|
||||
.extras(InstrumentationRegistry.getArguments());
|
||||
.extras(InstrumentationRegistry.getArguments())
|
||||
.nativeCrashReportingEnabled(true)
|
||||
.javaCrashReportingEnabled(true);
|
||||
|
||||
sRuntime = GeckoRuntime.create(
|
||||
InstrumentationRegistry.getTargetContext(),
|
||||
runtimeSettingsBuilder.build());
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="org.mozilla.geckoview">
|
||||
package="org.mozilla.geckoview">
|
||||
|
||||
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE"/>
|
||||
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
|
||||
|
@ -12,62 +13,88 @@
|
|||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
|
||||
<uses-permission android:name="com.android.launcher.permission.INSTALL_SHORTCUT"/>
|
||||
<uses-permission android:name="com.android.launcher.permission.UNINSTALL_SHORTCUT"/>
|
||||
|
||||
<uses-permission android:name="android.permission.WAKE_LOCK"/>
|
||||
<uses-permission android:name="android.permission.VIBRATE"/>
|
||||
|
||||
<uses-feature android:name="android.hardware.location" android:required="false"/>
|
||||
<uses-feature android:name="android.hardware.location.gps" android:required="false"/>
|
||||
<uses-feature
|
||||
android:name="android.hardware.location"
|
||||
android:required="false"/>
|
||||
<uses-feature
|
||||
android:name="android.hardware.location.gps"
|
||||
android:required="false"/>
|
||||
<uses-feature android:name="android.hardware.touchscreen"/>
|
||||
|
||||
<uses-permission android:name="android.permission.CAMERA" />
|
||||
<uses-feature android:name="android.hardware.camera" android:required="false"/>
|
||||
<uses-feature android:name="android.hardware.camera.autofocus" android:required="false"/>
|
||||
<uses-permission android:name="android.permission.CAMERA"/>
|
||||
|
||||
<uses-feature
|
||||
android:name="android.hardware.camera"
|
||||
android:required="false"/>
|
||||
<uses-feature
|
||||
android:name="android.hardware.camera.autofocus"
|
||||
android:required="false"/>
|
||||
|
||||
<!-- #ifdef MOZ_WEBRTC -->
|
||||
<!--
|
||||
TODO preprocess AndroidManifest.xml so that we can
|
||||
conditionally include WebRTC permissions based on MOZ_WEBRTC.
|
||||
-->
|
||||
<uses-permission android:name="android.permission.RECORD_AUDIO"/>
|
||||
-->
|
||||
<uses-feature
|
||||
android:name="android.hardware.audio.low_latency"
|
||||
android:required="false"/>
|
||||
-->
|
||||
<uses-feature
|
||||
android:name="android.hardware.microphone"
|
||||
android:required="false"/>
|
||||
-->
|
||||
<uses-feature
|
||||
android:name="android.hardware.camera.any"
|
||||
android:required="false"/>
|
||||
-->
|
||||
<!-- #endif -->
|
||||
|
||||
<!--#ifdef MOZ_WEBRTC-->
|
||||
<!-- TODO preprocess AndroidManifest.xml so that we can
|
||||
conditionally include WebRTC permissions based on MOZ_WEBRTC. -->
|
||||
<uses-permission android:name="android.permission.RECORD_AUDIO"/>-->
|
||||
<uses-feature android:name="android.hardware.audio.low_latency" android:required="false"/>-->
|
||||
<uses-feature android:name="android.hardware.microphone" android:required="false"/>-->
|
||||
<uses-feature android:name="android.hardware.camera.any" android:required="false"/>-->
|
||||
<!--#endif-->
|
||||
|
||||
<!-- App requires OpenGL ES 2.0 -->
|
||||
<uses-feature android:glEsVersion="0x00020000" android:required="true" />
|
||||
<uses-feature
|
||||
android:glEsVersion="0x00020000"
|
||||
android:required="true"/>
|
||||
|
||||
<application>
|
||||
|
||||
<!-- New child services must also be added to the Fennec AndroidManifest.xml.in -->
|
||||
<service
|
||||
android:name="org.mozilla.gecko.media.MediaManager"
|
||||
android:enabled="true"
|
||||
android:exported="false"
|
||||
android:process=":media"
|
||||
android:isolatedProcess="false">
|
||||
android:name="org.mozilla.gecko.media.MediaManager"
|
||||
android:enabled="true"
|
||||
android:exported="false"
|
||||
android:isolatedProcess="false"
|
||||
android:process=":media">
|
||||
</service>
|
||||
|
||||
<service
|
||||
android:name="org.mozilla.gecko.process.GeckoServiceChildProcess$geckomediaplugin"
|
||||
android:enabled="true"
|
||||
android:exported="false"
|
||||
android:process=":geckomediaplugin"
|
||||
android:isolatedProcess="false">
|
||||
android:name="org.mozilla.gecko.process.GeckoServiceChildProcess$geckomediaplugin"
|
||||
android:enabled="true"
|
||||
android:exported="false"
|
||||
android:isolatedProcess="false"
|
||||
android:process=":geckomediaplugin">
|
||||
</service>
|
||||
|
||||
<service
|
||||
android:name="org.mozilla.gecko.process.GeckoServiceChildProcess$tab"
|
||||
android:enabled="true"
|
||||
android:exported="false"
|
||||
android:process=":tab"
|
||||
android:isolatedProcess="false">
|
||||
android:name="org.mozilla.gecko.process.GeckoServiceChildProcess$tab"
|
||||
android:enabled="true"
|
||||
android:exported="false"
|
||||
android:isolatedProcess="false"
|
||||
android:process=":tab">
|
||||
</service>
|
||||
|
||||
<service
|
||||
android:name="org.mozilla.gecko.gfx.SurfaceAllocatorService"
|
||||
android:enabled="true"
|
||||
android:exported="false"
|
||||
android:isolatedProcess="false">
|
||||
android:name="org.mozilla.gecko.gfx.SurfaceAllocatorService"
|
||||
android:enabled="true"
|
||||
android:exported="false"
|
||||
android:isolatedProcess="false">
|
||||
</service>
|
||||
</application>
|
||||
<service
|
||||
android:name="org.mozilla.gecko.CrashReporterService"
|
||||
android:exported="false"
|
||||
android:process=":crashreporter">
|
||||
</service>
|
||||
</application>
|
||||
|
||||
</manifest>
|
||||
</manifest>
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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<String, String> 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<String, String>();
|
||||
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<INISection> 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<String, String> 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<String, String> 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<String, String> 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<String, String> responseMap = new HashMap<String, String>();
|
||||
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");
|
||||
}
|
||||
}
|
|
@ -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) {
|
||||
|
|
|
@ -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<String> getEnvFromExtras(final Bundle extras) {
|
||||
if (extras == null) {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
|
||||
ArrayList<String> 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<String> 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,
|
||||
|
|
|
@ -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<String> env) {
|
||||
for (final String e : env) {
|
||||
putenv(e);
|
||||
}
|
||||
|
||||
try {
|
||||
|
|
|
@ -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) {
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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(),
|
||||
|
|
|
@ -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<Boolean> mWebFonts = new Pref<Boolean>(
|
||||
"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<Object> uncheckedPref = (Pref<Object>) 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<Object> uncheckedPref = (Pref<Object>) pref;
|
||||
uncheckedPref.set(source.readValue(getClass().getClassLoader()));
|
||||
}
|
||||
|
||||
mNativeCrashReporting = ParcelableUtils.readBoolean(source);
|
||||
mJavaCrashReporting = ParcelableUtils.readBoolean(source);
|
||||
mJavaCrashReporting = ParcelableUtils.readBoolean(source);
|
||||
}
|
||||
|
||||
public static final Parcelable.Creator<GeckoRuntimeSettings> CREATOR
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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());
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
|
||||
struct mozilla::detail::MutexImpl::PlatformData
|
||||
{
|
||||
CRITICAL_SECTION criticalSection;
|
||||
SRWLOCK lock;
|
||||
};
|
||||
|
||||
#endif // MutexPlatformData_windows_h
|
||||
|
|
|
@ -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*
|
||||
|
|
|
@ -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<uint32_t>(age.ToSeconds() / 60));
|
||||
if (head->CheckExpiration(TimeStamp::Now()) !=
|
||||
nsHostRecord::EXP_EXPIRED) {
|
||||
Telemetry::Accumulate(Telemetry::DNS_PREMATURE_EVICTION,
|
||||
static_cast<uint32_t>(age.ToSeconds() / 60));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
*
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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<nsIX509CertList> 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;
|
||||
|
|
|
@ -1688,14 +1688,10 @@ void nsNSSComponent::setValidationOptions(bool isInitialSetting)
|
|||
static_cast<DistrustedCAPolicy>
|
||||
(Preferences::GetUint("security.pki.distrust_ca_policy",
|
||||
static_cast<uint32_t>(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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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")}
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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],
|
||||
|
|
Загрузка…
Ссылка в новой задаче