Merge mozilla-inbound to mozilla-central a=merge

This commit is contained in:
Daniel Varga 2018-09-08 06:53:43 +03:00
Родитель ef2ff61afa 22d4bb0074
Коммит 1539df295b
80 изменённых файлов: 924 добавлений и 3212 удалений

Просмотреть файл

@ -370,6 +370,7 @@ toolkit/components/reader/Readability.js
toolkit/components/reader/JSDOMParser.js
# Uses preprocessing
toolkit/components/reader/Readerable.jsm
toolkit/content/widgets/wizard.xml
toolkit/modules/AppConstants.jsm
toolkit/mozapps/update/tests/data/xpcshellConstantsPP.js

Просмотреть файл

@ -12,6 +12,8 @@ ChromeUtils.defineModuleGetter(this, "AboutReader",
"resource://gre/modules/AboutReader.jsm");
ChromeUtils.defineModuleGetter(this, "ReaderMode",
"resource://gre/modules/ReaderMode.jsm");
ChromeUtils.defineModuleGetter(this, "Readerable",
"resource://gre/modules/Readerable.jsm");
class AboutReaderChild extends ActorChild {
constructor(mm) {
@ -102,7 +104,7 @@ class AboutReaderChild extends ActorChild {
* painted is not going to work.
*/
updateReaderButton(forceNonArticle) {
if (!ReaderMode.isEnabledForParseOnLoad || this.isAboutReader ||
if (!Readerable.isEnabledForParseOnLoad || this.isAboutReader ||
!this.content || !(this.content.document instanceof this.content.HTMLDocument) ||
this.content.document.mozSyntheticDocument) {
return;
@ -141,7 +143,7 @@ class AboutReaderChild extends ActorChild {
this.cancelPotentialPendingReadabilityCheck();
// Only send updates when there are articles; there's no point updating with
// |false| all the time.
if (ReaderMode.isProbablyReaderable(this.content.document)) {
if (Readerable.isProbablyReaderable(this.content.document)) {
this.mm.sendAsyncMessage("Reader:UpdateReaderButton", { isArticle: true });
} else if (forceNonArticle) {
this.mm.sendAsyncMessage("Reader:UpdateReaderButton", { isArticle: false });

Просмотреть файл

@ -41,9 +41,11 @@ include $(topsrcdir)/config/rules.mk
ifneq (,$(filter-out WINNT,$(OS_ARCH)))
ifdef COMPILE_ENVIRONMENT
ifndef MOZ_NO_PIE_COMPAT
libs::
cp -p $(DIST)/bin/$(MOZ_APP_NAME)$(BIN_SUFFIX) $(DIST)/bin/$(MOZ_APP_NAME)-bin$(BIN_SUFFIX)
endif
endif
GARBAGE += $(addprefix $(FINAL_TARGET)/defaults/pref/, firefox.js)

Просмотреть файл

@ -29,7 +29,12 @@ with Files("profile/channel-prefs.js"):
with Files("profile/firefox.js"):
BUG_COMPONENT = ("Firefox", "General")
GeckoProgram(CONFIG['MOZ_APP_NAME'])
if CONFIG['MOZ_NO_PIE_COMPAT']:
GeckoProgram(CONFIG['MOZ_APP_NAME'] + '-bin')
DIRS += ['no-pie']
else:
GeckoProgram(CONFIG['MOZ_APP_NAME'])
SOURCES += [
'nsBrowserApp.cpp',

Просмотреть файл

@ -0,0 +1,27 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include <errno.h>
#include <limits.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
int main(int argc, char* argv[])
{
// Ideally, we'd use mozilla::BinaryPath, but that pulls in stdc++compat,
// and further causes trouble linking with LTO.
char path[PATH_MAX + 4];
ssize_t len = readlink("/proc/self/exe", path, PATH_MAX - 1);
if (len < 0) {
fprintf(stderr, "Couldn't find the application directory.\n");
return 255;
}
strcpy(path + len, "-bin");
execv(path, argv);
// execv never returns. If it did, there was an error.
fprintf(stderr, "Exec failed with error: %s\n", strerror(errno));
return 255;
}

Просмотреть файл

@ -0,0 +1,22 @@
# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
# vim: set filetype=python:
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
Program(CONFIG['MOZ_APP_NAME'])
SOURCES += [
'NoPie.c',
]
# For some reason, LTO messes things up. We don't care anyways.
CFLAGS += [
'-fno-lto',
]
# Use OS_LIBS instead of LDFLAGS to "force" the flag to come after -pie
# from MOZ_PROGRAM_LDFLAGS.
OS_LIBS += [
'-no-pie'
]

Просмотреть файл

@ -56,7 +56,7 @@ const whitelist = {
"resource://gre/modules/ActorChild.jsm",
"resource://gre/modules/ActorManagerChild.jsm",
"resource://gre/modules/E10SUtils.jsm",
"resource://gre/modules/ReaderMode.jsm",
"resource://gre/modules/Readerable.jsm",
"resource://gre/modules/WebProgressChild.jsm",
// Pocket

Просмотреть файл

@ -8,4 +8,11 @@ imply_option('MOZ_PLACES', True)
imply_option('MOZ_SERVICES_HEALTHREPORT', True)
imply_option('MOZ_SERVICES_SYNC', True)
with only_when(target_is_linux & compile_environment):
option(env='MOZ_NO_PIE_COMPAT',
help='Enable non-PIE wrapper')
set_config('MOZ_NO_PIE_COMPAT',
depends_if('MOZ_NO_PIE_COMPAT')(lambda _: True))
include('../toolkit/moz.configure')

Просмотреть файл

@ -208,29 +208,8 @@ if test "$GNU_CC" -a "$GCC_USE_GNU_LD" -a -z "$DEVELOPER_OPTIONS"; then
fi
fi
# On OSX, the linker defaults to building PIE programs when targeting OSX 10.7.
# On other Unix systems, some file managers (Nautilus) can't start PIE programs
if test "$OS_TARGET" = Android; then
# bionic in Android >= 4.1 supports PIE, and we target those versions.
MOZ_PIE=1
else
MOZ_PIE=
fi
MOZ_ARG_ENABLE_BOOL(pie,
[ --enable-pie Enable Position Independent Executables],
MOZ_PIE=1,
MOZ_PIE= )
if test "$GNU_CC$CLANG_CC" -a -n "$MOZ_PIE"; then
AC_MSG_CHECKING([for PIE support])
_SAVE_LDFLAGS=$LDFLAGS
LDFLAGS="$LDFLAGS $DSO_PIC_CFLAGS -pie"
AC_TRY_LINK(,,AC_MSG_RESULT([yes])
[MOZ_PROGRAM_LDFLAGS="$MOZ_PROGRAM_LDFLAGS -pie"],
AC_MSG_RESULT([no])
AC_MSG_ERROR([--enable-pie requires PIE support from the linker.]))
LDFLAGS=$_SAVE_LDFLAGS
if test "$GNU_CC$CLANG_CC"; then
MOZ_PROGRAM_LDFLAGS="$MOZ_PROGRAM_LDFLAGS -pie"
fi
AC_SUBST(MOZ_PROGRAM_LDFLAGS)

Просмотреть файл

@ -30,7 +30,7 @@ if test -n "$MOZ_ASAN"; then
CFLAGS="-fsanitize=address $CFLAGS"
CXXFLAGS="-fsanitize=address $CXXFLAGS"
if test -z "$CLANG_CL"; then
LDFLAGS="-fsanitize=address $LDFLAGS"
LDFLAGS="-fsanitize=address -rdynamic $LDFLAGS"
fi
AC_DEFINE(MOZ_ASAN)
MOZ_PATH_PROG(LLVM_SYMBOLIZER, llvm-symbolizer)
@ -48,7 +48,7 @@ if test -n "$MOZ_MSAN"; then
CFLAGS="-fsanitize=memory -fsanitize-memory-track-origins $CFLAGS"
CXXFLAGS="-fsanitize=memory -fsanitize-memory-track-origins $CXXFLAGS"
if test -z "$CLANG_CL"; then
LDFLAGS="-fsanitize=memory -fsanitize-memory-track-origins $LDFLAGS"
LDFLAGS="-fsanitize=memory -fsanitize-memory-track-origins -rdynamic $LDFLAGS"
fi
AC_DEFINE(MOZ_MSAN)
MOZ_PATH_PROG(LLVM_SYMBOLIZER, llvm-symbolizer)
@ -66,7 +66,7 @@ if test -n "$MOZ_TSAN"; then
CFLAGS="-fsanitize=thread $CFLAGS"
CXXFLAGS="-fsanitize=thread $CXXFLAGS"
if test -z "$CLANG_CL"; then
LDFLAGS="-fsanitize=thread $LDFLAGS"
LDFLAGS="-fsanitize=thread -rdynamic $LDFLAGS"
fi
AC_DEFINE(MOZ_TSAN)
MOZ_PATH_PROG(LLVM_SYMBOLIZER, llvm-symbolizer)
@ -94,7 +94,7 @@ if test -n "$MOZ_SIGNED_OVERFLOW_SANITIZE$MOZ_UNSIGNED_OVERFLOW_SANITIZE"; then
CFLAGS="-fsanitize=signed-integer-overflow $CFLAGS"
CXXFLAGS="-fsanitize=signed-integer-overflow $CXXFLAGS"
if test -z "$CLANG_CL"; then
LDFLAGS="-fsanitize=signed-integer-overflow $LDFLAGS"
LDFLAGS="-fsanitize=signed-integer-overflow -rdynamic $LDFLAGS"
fi
AC_DEFINE(MOZ_SIGNED_OVERFLOW_SANITIZE)
fi
@ -103,7 +103,7 @@ if test -n "$MOZ_SIGNED_OVERFLOW_SANITIZE$MOZ_UNSIGNED_OVERFLOW_SANITIZE"; then
CFLAGS="-fsanitize=unsigned-integer-overflow $CFLAGS"
CXXFLAGS="-fsanitize=unsigned-integer-overflow $CXXFLAGS"
if test -z "$CLANG_CL"; then
LDFLAGS="-fsanitize=unsigned-integer-overflow $LDFLAGS"
LDFLAGS="-fsanitize=unsigned-integer-overflow -rdynamic $LDFLAGS"
fi
AC_DEFINE(MOZ_UNSIGNED_OVERFLOW_SANITIZE)
fi

Просмотреть файл

@ -1,5 +1,5 @@
#include <functional>
#define MOZ_STRONG_REF __attribute__((annotate("moz_strong_ref")))
#define MOZ_STRONG_REF
#define MOZ_IMPLICIT __attribute__((annotate("moz_implicit")))
struct RefCountedBase {

Просмотреть файл

@ -202,7 +202,6 @@ def old_configure_options(*options):
'--enable-nspr-build',
'--enable-official-branding',
'--enable-parental-controls',
'--enable-pie',
'--enable-posix-nspr-emulation',
'--enable-pref-extensions',
'--enable-raw',

Просмотреть файл

@ -1479,7 +1479,6 @@ def security_hardening_cflags(hardening_flag, asan, optimize, c_compiler, target
add_old_configure_assignment('MOZ_HARDENING_CFLAGS', security_hardening_cflags.flags)
add_old_configure_assignment('MOZ_HARDENING_CFLAGS_JS', security_hardening_cflags.js_flags)
imply_option('--enable-pie', depends_if('--enable-hardening')(lambda v: v))
# Code Coverage
# ==============================================================

Просмотреть файл

@ -26,3 +26,4 @@ unset WIN64_LIB
unset ENABLE_CLANG_PLUGIN
unset MOZ_STDCXX_COMPAT
unset MOZ_NO_PIE_COMPAT

Просмотреть файл

@ -1,9 +1,7 @@
MOZ_AUTOMATION_L10N_CHECK=0
. "$topsrcdir/build/unix/mozconfig.linux"
. "$topsrcdir/build/unix/mozconfig.unix"
# Enabling the clang plugin triggers leaks. bug 1487622
unset ENABLE_CLANG_PLUGIN
export LLVM_SYMBOLIZER="$topsrcdir/clang/bin/llvm-symbolizer"
#
# Enable ASan specific code and build workarounds

Просмотреть файл

@ -1,25 +1,3 @@
if [ "x$IS_NIGHTLY" = "xyes" ]; then
# Some nightlies (eg: Mulet) don't want these set.
MOZ_AUTOMATION_UPDATE_PACKAGING=${MOZ_AUTOMATION_UPDATE_PACKAGING-1}
fi
. "$topsrcdir/build/unix/mozconfig.unix"
. "$topsrcdir/build/mozconfig.common"
TOOLTOOL_DIR=${TOOLTOOL_DIR:-$topsrcdir}
if [ -n "$FORCE_GCC" -o -n "$MOZ_PGO" ]; then
CC="$TOOLTOOL_DIR/gcc/bin/gcc"
CXX="$TOOLTOOL_DIR/gcc/bin/g++"
# We want to make sure we use binutils and other binaries in the tooltool
# package.
mk_add_options "export PATH=$TOOLTOOL_DIR/gcc/bin:$PATH"
else
CC="$TOOLTOOL_DIR/clang/bin/clang"
CXX="$TOOLTOOL_DIR/clang/bin/clang++"
export ENABLE_CLANG_PLUGIN=1
mk_add_options "export PATH=$TOOLTOOL_DIR/binutils/bin:$PATH"
fi
. "$topsrcdir/build/unix/mozconfig.stdcxx"
export MOZ_NO_PIE_COMPAT=1

Просмотреть файл

@ -8,6 +8,3 @@ export NM="$topsrcdir/clang/bin/llvm-nm"
export RANLIB="$topsrcdir/clang/bin/llvm-ranlib"
ac_add_options --enable-lto
# Until it's either made the default or we figure a way to remove the
# copy locations that LTO induces in non-PIE executables.
ac_add_options --enable-pie

Просмотреть файл

@ -1,6 +1,6 @@
MOZ_AUTOMATION_L10N_CHECK=0
. "$topsrcdir/build/unix/mozconfig.linux"
. "$topsrcdir/build/unix/mozconfig.unix"
export LLVM_SYMBOLIZER="$topsrcdir/clang/bin/llvm-symbolizer"
@ -15,7 +15,6 @@ ac_add_options --disable-sandbox
ac_add_options --disable-jemalloc
ac_add_options --disable-crashreporter
ac_add_options --disable-elf-hack
ac_add_options --enable-pie
# Keep symbols to symbolize TSan traces
ac_add_options --disable-install-strip

25
build/unix/mozconfig.unix Normal file
Просмотреть файл

@ -0,0 +1,25 @@
if [ "x$IS_NIGHTLY" = "xyes" ]; then
# Some nightlies (eg: Mulet) don't want these set.
MOZ_AUTOMATION_UPDATE_PACKAGING=${MOZ_AUTOMATION_UPDATE_PACKAGING-1}
fi
. "$topsrcdir/build/mozconfig.common"
TOOLTOOL_DIR=${TOOLTOOL_DIR:-$topsrcdir}
if [ -n "$FORCE_GCC" -o -n "$MOZ_PGO" ]; then
CC="$TOOLTOOL_DIR/gcc/bin/gcc"
CXX="$TOOLTOOL_DIR/gcc/bin/g++"
# We want to make sure we use binutils and other binaries in the tooltool
# package.
mk_add_options "export PATH=$TOOLTOOL_DIR/gcc/bin:$PATH"
else
CC="$TOOLTOOL_DIR/clang/bin/clang"
CXX="$TOOLTOOL_DIR/clang/bin/clang++"
export ENABLE_CLANG_PLUGIN=1
mk_add_options "export PATH=$TOOLTOOL_DIR/binutils/bin:$PATH"
fi
. "$topsrcdir/build/unix/mozconfig.stdcxx"

Просмотреть файл

@ -1503,6 +1503,7 @@ WebRenderCommandBuilder::CreateImageKey(nsDisplayItem* aItem,
ImageContainer* aContainer,
mozilla::wr::DisplayListBuilder& aBuilder,
mozilla::wr::IpcResourceUpdateQueue& aResources,
mozilla::wr::ImageRendering aRendering,
const StackingContextHelper& aSc,
gfx::IntSize& aSize,
const Maybe<LayoutDeviceRect>& aAsyncImageBounds)
@ -1530,7 +1531,7 @@ WebRenderCommandBuilder::CreateImageKey(nsDisplayItem* aItem,
scBounds,
transform,
scaleToSize,
wr::ImageRendering::Auto,
aRendering,
wr::MixBlendMode::Normal,
!aItem->BackfaceIsHidden());
return Nothing();
@ -1554,10 +1555,11 @@ WebRenderCommandBuilder::PushImage(nsDisplayItem* aItem,
const StackingContextHelper& aSc,
const LayoutDeviceRect& aRect)
{
mozilla::wr::ImageRendering rendering = wr::ToImageRendering(
nsLayoutUtils::GetSamplingFilterForFrame(aItem->Frame()));
gfx::IntSize size;
Maybe<wr::ImageKey> key = CreateImageKey(aItem, aContainer,
aBuilder, aResources,
aSc, size, Some(aRect));
Maybe<wr::ImageKey> key = CreateImageKey(
aItem, aContainer, aBuilder, aResources, rendering, aSc, size, Some(aRect));
if (aContainer->IsAsync()) {
// Async ImageContainer does not create ImageKey, instead it uses Pipeline.
MOZ_ASSERT(key.isNothing());
@ -1568,8 +1570,7 @@ WebRenderCommandBuilder::PushImage(nsDisplayItem* aItem,
}
auto r = wr::ToRoundedLayoutRect(aRect);
gfx::SamplingFilter sampleFilter = nsLayoutUtils::GetSamplingFilterForFrame(aItem->Frame());
aBuilder.PushImage(r, r, !aItem->BackfaceIsHidden(), wr::ToImageRendering(sampleFilter), key.value());
aBuilder.PushImage(r, r, !aItem->BackfaceIsHidden(), rendering, key.value());
return true;
}

Просмотреть файл

@ -65,6 +65,7 @@ public:
ImageContainer* aContainer,
mozilla::wr::DisplayListBuilder& aBuilder,
mozilla::wr::IpcResourceUpdateQueue& aResources,
mozilla::wr::ImageRendering aRendering,
const StackingContextHelper& aSc,
gfx::IntSize& aSize,
const Maybe<LayoutDeviceRect>& aAsyncImageBounds);

Просмотреть файл

@ -26,12 +26,12 @@
# RUN TESTS NOT AFFECTED BY DOWNSCALE-DURING-DECODE:
# ==================================================
fuzzy-if(skiaContent,0-14,0-416) fuzzy-if(webrender,14-14,397-473) == downscale-svg-1a.html downscale-svg-1-ref.html?80
fuzzy(0-80,0-468) fuzzy-if(webrender,65-65,579-580) == downscale-svg-1b.html downscale-svg-1-ref.html?72
fuzzy-if(/^Windows\x20NT\x2010\.0/.test(http.oscpu),0-1,0-62) fuzzy-if(skiaContent,0-8,0-292) fuzzy-if(webrender,14-14,316-316) == downscale-svg-1c.html downscale-svg-1-ref.html?64
fuzzy(0-17,0-208) fuzzy-if(webrender,83-84,274-325) == downscale-svg-1d.html downscale-svg-1-ref.html?53
fuzzy(0-80,0-216) fuzzy-if(skiaContent,0-110,0-181) fuzzy-if(webrender,84-84,216-216) == downscale-svg-1e.html downscale-svg-1-ref.html?40
fuzzy(0-51,0-90) fuzzy-if(skiaContent,0-142,0-77) fuzzy-if(webrender,62-62,98-98) == downscale-svg-1f.html downscale-svg-1-ref.html?24
fuzzy-if(skiaContent,0-14,0-416) fuzzy-if(webrender,1-1,2-2) == downscale-svg-1a.html downscale-svg-1-ref.html?80
fuzzy(0-80,0-468) fuzzy-if(webrender,65-65,468-468) == downscale-svg-1b.html downscale-svg-1-ref.html?72
fuzzy-if(/^Windows\x20NT\x2010\.0/.test(http.oscpu),0-1,0-62) fuzzy-if(skiaContent,0-8,0-292) fuzzy-if(webrender,1-1,2-2) == downscale-svg-1c.html downscale-svg-1-ref.html?64
fuzzy(0-17,0-208) fuzzy-if(webrender,7-7,208-208) == downscale-svg-1d.html downscale-svg-1-ref.html?53
fuzzy(0-80,0-216) fuzzy-if(skiaContent,0-110,0-181) fuzzy-if(webrender,54-54,178-178) == downscale-svg-1e.html downscale-svg-1-ref.html?40
fuzzy(0-51,0-90) fuzzy-if(skiaContent,0-142,0-77) fuzzy-if(webrender,64-64,31-31) == downscale-svg-1f.html downscale-svg-1-ref.html?24
# RUN TESTS WITH DOWNSCALE-DURING-DECODE DISABLED:
# ================================================

Просмотреть файл

@ -43,10 +43,14 @@ CrashReporterClient::AppendAppNotes(const nsCString& aData)
/* static */ void
CrashReporterClient::InitSingletonWithShmem(const Shmem& aShmem)
{
StaticMutexAutoLock lock(sLock);
{
StaticMutexAutoLock lock(sLock);
MOZ_ASSERT(!sClientSingleton);
sClientSingleton = new CrashReporterClient(aShmem);
MOZ_ASSERT(!sClientSingleton);
sClientSingleton = new CrashReporterClient(aShmem);
}
CrashReporter::NotifyCrashReporterClientCreated();
}
/* static */ void

Просмотреть файл

@ -249,7 +249,7 @@ class JS_PUBLIC_API(OwningCompileOptions) final
bool copy(JSContext* cx, const ReadOnlyCompileOptions& rhs);
/* These setters make copies of their string arguments and are fallible. */
bool setFile(JSContext* cx, const char* f);
MOZ_MUST_USE bool setFile(JSContext* cx, const char* f);
MOZ_MUST_USE bool setFileAndLine(JSContext* cx, const char* f, unsigned l);
MOZ_MUST_USE bool setSourceMapURL(JSContext* cx, const char16_t* s);
MOZ_MUST_USE bool setIntroducerFilename(JSContext* cx, const char* s);

Просмотреть файл

@ -6,6 +6,7 @@
#include "ds/LifoAlloc.h"
#include "mozilla/Likely.h"
#include "mozilla/MathAlgorithms.h"
#include "ds/MemoryProtectionExceptionHandler.h"
@ -142,23 +143,17 @@ LifoAlloc::newChunkWithCapacity(size_t n)
// Compute the size which should be requested in order to be able to fit |n|
// bytes in a newly allocated chunk, or default to |defaultChunkSize_|.
uint8_t* u8begin = nullptr;
uint8_t* u8end = u8begin + detail::BumpChunkReservedSpace;
u8end = detail::BumpChunk::nextAllocEnd(detail::BumpChunk::nextAllocBase(u8end), n);
size_t allocSizeWithCanaries = u8end - u8begin;
// Guard for overflow.
if (allocSizeWithCanaries < n ||
(allocSizeWithCanaries & (size_t(1) << (BitSize<size_t>::value - 1))))
size_t minSize;
if (MOZ_UNLIKELY(!detail::BumpChunk::allocSizeWithRedZone(n, &minSize) ||
(minSize & (size_t(1) << (BitSize<size_t>::value - 1)))))
{
return nullptr;
}
size_t chunkSize;
if (allocSizeWithCanaries > defaultChunkSize_)
chunkSize = RoundUpPow2(allocSizeWithCanaries);
else
chunkSize = defaultChunkSize_;
const size_t chunkSize = minSize > defaultChunkSize_
? RoundUpPow2(minSize)
: defaultChunkSize_;
// Create a new BumpChunk, and allocate space for it.
UniqueBumpChunk result = detail::BumpChunk::newWithCapacity(chunkSize);

Просмотреть файл

@ -17,6 +17,7 @@
#include "mozilla/TypeTraits.h"
#include <new>
#include <stddef.h> // size_t
// This data structure supports stacky LIFO allocation (mark/release and
// LifoAllocScope). It does not maintain one contiguous segment; instead, it
@ -196,7 +197,8 @@ static const size_t LIFO_ALLOC_ALIGN = 8;
MOZ_ALWAYS_INLINE
uint8_t*
AlignPtr(uint8_t* orig) {
AlignPtr(uint8_t* orig)
{
static_assert(mozilla::IsPowerOfTwo(LIFO_ALLOC_ALIGN),
"LIFO_ALLOC_ALIGN must be a power of two");
@ -415,6 +417,11 @@ class BumpChunk : public SingleLinkedListElement<BumpChunk>
setBump(m.bump_);
}
// Given an amount, compute the total size of a chunk for it: reserved
// space before |begin()|, space for |amount| bytes, and red-zone space
// after those bytes that will ultimately end at |capacity_|.
static inline MOZ_MUST_USE bool allocSizeWithRedZone(size_t amount, size_t* size);
// Given a bump chunk pointer, find the next base/end pointers. This is
// useful for having consistent allocations, and iterating over known size
// allocations.
@ -473,6 +480,23 @@ class BumpChunk : public SingleLinkedListElement<BumpChunk>
// for the next allocation (see LifoAlloc::newChunkWithCapacity).
static constexpr size_t BumpChunkReservedSpace = AlignBytes(sizeof(BumpChunk), LIFO_ALLOC_ALIGN);
/* static */ inline MOZ_MUST_USE bool
BumpChunk::allocSizeWithRedZone(size_t amount, size_t* size)
{
constexpr size_t SpaceBefore = BumpChunkReservedSpace;
static_assert((SpaceBefore % LIFO_ALLOC_ALIGN) == 0,
"reserved space presumed already aligned");
constexpr size_t SpaceAfter = RedZoneSize; // may be zero
constexpr size_t SpaceBeforeAndAfter = SpaceBefore + SpaceAfter;
static_assert(SpaceBeforeAndAfter >= SpaceBefore,
"intermediate addition must not overflow");
*size = SpaceBeforeAndAfter + amount;
return MOZ_LIKELY(*size >= SpaceBeforeAndAfter);
}
inline const uint8_t*
BumpChunk::begin() const
{

Просмотреть файл

@ -10425,6 +10425,7 @@ CodeGenerator::link(JSContext* cx, CompilerConstraintList* constraints)
allTypes);
} else {
cx->recoverFromOutOfMemory();
js_delete(allTypes);
}
}

Просмотреть файл

@ -61,7 +61,9 @@ inline void
js::jit::AtomicOperations::fenceSeqCst()
{
_ReadWriteBarrier();
MemoryBarrier();
// MemoryBarrier is defined in winnt.h, which we don't want to include here.
// This expression is the expansion of MemoryBarrier.
__dmb(_ARM64_BARRIER_SY);
}
template<typename T>

Просмотреть файл

@ -64,28 +64,17 @@ enum {
JOF_PROP = 2 << 5, /* obj.prop operation */
JOF_ELEM = 3 << 5, /* obj[index] operation */
JOF_MODEMASK = 3 << 5, /* mask for above addressing modes */
JOF_PROPSET = 1 << 7, /* property/element/name set operation */
JOF_PROPINIT = 1 << 8, /* property/element/name init operation */
/* 1 << 9 is unused */
/* 1 << 10 is unused */
/* 1 << 11 is unused */
/* 1 << 12 is unused */
/* 1 << 13 is unused */
JOF_DETECTING = 1 << 14, /* object detection for warning-quelling */
/* 1 << 15 is unused */
JOF_LEFTASSOC = 1 << 16, /* left-associative operator */
/* 1 << 17 is unused */
/* 1 << 18 is unused */
JOF_CHECKSLOPPY = 1 << 19, /* Op can only be generated in sloppy mode */
JOF_CHECKSTRICT = 1 << 20, /* Op can only be generated in strict mode */
JOF_INVOKE = 1 << 21, /* JSOP_CALL, JSOP_FUNCALL, JSOP_FUNAPPLY,
JOF_DETECTING = 1 << 9, /* object detection for warning-quelling */
JOF_CHECKSLOPPY = 1 << 10, /* Op can only be generated in sloppy mode */
JOF_CHECKSTRICT = 1 << 11, /* Op can only be generated in strict mode */
JOF_INVOKE = 1 << 12, /* JSOP_CALL, JSOP_FUNCALL, JSOP_FUNAPPLY,
JSOP_NEW, JSOP_EVAL, JSOP_CALLITER */
/* 1 << 22 is unused */
/* 1 << 23 is unused */
/* 1 << 24 is unused */
JOF_GNAME = 1 << 25, /* predicted global name */
JOF_TYPESET = 1 << 26, /* has an entry in a script's type sets */
JOF_ARITH = 1 << 27 /* unary or binary arithmetic opcode */
JOF_GNAME = 1 << 13, /* predicted global name */
JOF_TYPESET = 1 << 14, /* has an entry in a script's type sets */
JOF_ARITH = 1 << 15 /* unary or binary arithmetic opcode */
};
/* Shorthand for type from format. */

Просмотреть файл

@ -244,9 +244,9 @@
* Operands:
* Stack: lval, rval => (lval OP rval)
*/ \
macro(JSOP_BITOR, 15, "bitor", "|", 1, 2, 1, JOF_BYTE|JOF_LEFTASSOC|JOF_ARITH) \
macro(JSOP_BITXOR, 16, "bitxor", "^", 1, 2, 1, JOF_BYTE|JOF_LEFTASSOC|JOF_ARITH) \
macro(JSOP_BITAND, 17, "bitand", "&", 1, 2, 1, JOF_BYTE|JOF_LEFTASSOC|JOF_ARITH) \
macro(JSOP_BITOR, 15, "bitor", "|", 1, 2, 1, JOF_BYTE|JOF_ARITH) \
macro(JSOP_BITXOR, 16, "bitxor", "^", 1, 2, 1, JOF_BYTE|JOF_ARITH) \
macro(JSOP_BITAND, 17, "bitand", "&", 1, 2, 1, JOF_BYTE|JOF_ARITH) \
/*
* Pops the top two values from the stack and pushes the result of
* comparing them.
@ -255,12 +255,12 @@
* Operands:
* Stack: lval, rval => (lval OP rval)
*/ \
macro(JSOP_EQ, 18, "eq", "==", 1, 2, 1, JOF_BYTE|JOF_LEFTASSOC|JOF_ARITH|JOF_DETECTING) \
macro(JSOP_NE, 19, "ne", "!=", 1, 2, 1, JOF_BYTE|JOF_LEFTASSOC|JOF_ARITH|JOF_DETECTING) \
macro(JSOP_LT, 20, "lt", "<", 1, 2, 1, JOF_BYTE|JOF_LEFTASSOC|JOF_ARITH) \
macro(JSOP_LE, 21, "le", "<=", 1, 2, 1, JOF_BYTE|JOF_LEFTASSOC|JOF_ARITH) \
macro(JSOP_GT, 22, "gt", ">", 1, 2, 1, JOF_BYTE|JOF_LEFTASSOC|JOF_ARITH) \
macro(JSOP_GE, 23, "ge", ">=", 1, 2, 1, JOF_BYTE|JOF_LEFTASSOC|JOF_ARITH) \
macro(JSOP_EQ, 18, "eq", "==", 1, 2, 1, JOF_BYTE|JOF_ARITH|JOF_DETECTING) \
macro(JSOP_NE, 19, "ne", "!=", 1, 2, 1, JOF_BYTE|JOF_ARITH|JOF_DETECTING) \
macro(JSOP_LT, 20, "lt", "<", 1, 2, 1, JOF_BYTE|JOF_ARITH) \
macro(JSOP_LE, 21, "le", "<=", 1, 2, 1, JOF_BYTE|JOF_ARITH) \
macro(JSOP_GT, 22, "gt", ">", 1, 2, 1, JOF_BYTE|JOF_ARITH) \
macro(JSOP_GE, 23, "ge", ">=", 1, 2, 1, JOF_BYTE|JOF_ARITH) \
/*
* Pops the top two values 'lval' and 'rval' from the stack, then pushes
* the result of the operation applied to the operands.
@ -269,8 +269,8 @@
* Operands:
* Stack: lval, rval => (lval OP rval)
*/ \
macro(JSOP_LSH, 24, "lsh", "<<", 1, 2, 1, JOF_BYTE|JOF_LEFTASSOC|JOF_ARITH) \
macro(JSOP_RSH, 25, "rsh", ">>", 1, 2, 1, JOF_BYTE|JOF_LEFTASSOC|JOF_ARITH) \
macro(JSOP_LSH, 24, "lsh", "<<", 1, 2, 1, JOF_BYTE|JOF_ARITH) \
macro(JSOP_RSH, 25, "rsh", ">>", 1, 2, 1, JOF_BYTE|JOF_ARITH) \
/*
* Pops the top two values 'lval' and 'rval' from the stack, then pushes
* 'lval >>> rval'.
@ -279,7 +279,7 @@
* Operands:
* Stack: lval, rval => (lval >>> rval)
*/ \
macro(JSOP_URSH, 26, "ursh", ">>>", 1, 2, 1, JOF_BYTE|JOF_LEFTASSOC|JOF_ARITH) \
macro(JSOP_URSH, 26, "ursh", ">>>", 1, 2, 1, JOF_BYTE|JOF_ARITH) \
/*
* Pops the top two values 'lval' and 'rval' from the stack, then pushes
* the result of 'lval + rval'.
@ -288,7 +288,7 @@
* Operands:
* Stack: lval, rval => (lval + rval)
*/ \
macro(JSOP_ADD, 27, "add", "+", 1, 2, 1, JOF_BYTE|JOF_LEFTASSOC|JOF_ARITH) \
macro(JSOP_ADD, 27, "add", "+", 1, 2, 1, JOF_BYTE|JOF_ARITH) \
/*
* Pops the top two values 'lval' and 'rval' from the stack, then pushes
* the result of applying the arithmetic operation to them.
@ -297,10 +297,10 @@
* Operands:
* Stack: lval, rval => (lval OP rval)
*/ \
macro(JSOP_SUB, 28, "sub", "-", 1, 2, 1, JOF_BYTE|JOF_LEFTASSOC|JOF_ARITH) \
macro(JSOP_MUL, 29, "mul", "*", 1, 2, 1, JOF_BYTE|JOF_LEFTASSOC|JOF_ARITH) \
macro(JSOP_DIV, 30, "div", "/", 1, 2, 1, JOF_BYTE|JOF_LEFTASSOC|JOF_ARITH) \
macro(JSOP_MOD, 31, "mod", "%", 1, 2, 1, JOF_BYTE|JOF_LEFTASSOC|JOF_ARITH) \
macro(JSOP_SUB, 28, "sub", "-", 1, 2, 1, JOF_BYTE|JOF_ARITH) \
macro(JSOP_MUL, 29, "mul", "*", 1, 2, 1, JOF_BYTE|JOF_ARITH) \
macro(JSOP_DIV, 30, "div", "/", 1, 2, 1, JOF_BYTE|JOF_ARITH) \
macro(JSOP_MOD, 31, "mod", "%", 1, 2, 1, JOF_BYTE|JOF_ARITH) \
/*
* Pops the value 'val' from the stack, then pushes '!val'.
* Category: Operators
@ -535,7 +535,7 @@
* Operands:
* Stack: obj, propval => obj[propval]
*/ \
macro(JSOP_GETELEM, 55, "getelem", NULL, 1, 2, 1, JOF_BYTE |JOF_ELEM|JOF_TYPESET|JOF_LEFTASSOC) \
macro(JSOP_GETELEM, 55, "getelem", NULL, 1, 2, 1, JOF_BYTE |JOF_ELEM|JOF_TYPESET) \
/*
* Pops the top three values on the stack as 'val', 'propval' and 'obj',
* sets 'propval' property of 'obj' as 'val', pushes 'val' onto the
@ -640,7 +640,7 @@
* Operands: int32_t offset
* Stack: cond => cond
*/ \
macro(JSOP_OR, 68, "or", NULL, 5, 1, 1, JOF_JUMP|JOF_DETECTING|JOF_LEFTASSOC) \
macro(JSOP_OR, 68, "or", NULL, 5, 1, 1, JOF_JUMP|JOF_DETECTING) \
/*
* Converts the top of stack value into a boolean, if the result is 'false',
* jumps to a 32-bit offset from the current bytecode.
@ -649,7 +649,7 @@
* Operands: int32_t offset
* Stack: cond => cond
*/ \
macro(JSOP_AND, 69, "and", NULL, 5, 1, 1, JOF_JUMP|JOF_DETECTING|JOF_LEFTASSOC) \
macro(JSOP_AND, 69, "and", NULL, 5, 1, 1, JOF_JUMP|JOF_DETECTING) \
\
/*
* Pops the top of stack value as 'i', if 'low <= i <= high',
@ -685,8 +685,8 @@
* Operands:
* Stack: lval, rval => (lval OP rval)
*/ \
macro(JSOP_STRICTEQ, 72, "stricteq", "===", 1, 2, 1, JOF_BYTE|JOF_DETECTING|JOF_LEFTASSOC|JOF_ARITH) \
macro(JSOP_STRICTNE, 73, "strictne", "!==", 1, 2, 1, JOF_BYTE|JOF_DETECTING|JOF_LEFTASSOC|JOF_ARITH) \
macro(JSOP_STRICTEQ, 72, "stricteq", "===", 1, 2, 1, JOF_BYTE|JOF_DETECTING|JOF_ARITH) \
macro(JSOP_STRICTNE, 73, "strictne", "!==", 1, 2, 1, JOF_BYTE|JOF_DETECTING|JOF_ARITH) \
\
/*
* Sometimes we know when emitting that an operation will always throw.
@ -1122,7 +1122,7 @@
* Operands:
* Stack: id, obj => (id in obj)
*/ \
macro(JSOP_IN, 113,js_in_str, js_in_str, 1, 2, 1, JOF_BYTE|JOF_LEFTASSOC) \
macro(JSOP_IN, 113,js_in_str, js_in_str, 1, 2, 1, JOF_BYTE) \
/*
* Pops the top two values 'obj' and 'ctor' from the stack, then pushes
* 'obj instanceof ctor'. This will throw a 'TypeError' if 'obj' is not an
@ -1132,7 +1132,7 @@
* Operands:
* Stack: obj, ctor => (obj instanceof ctor)
*/ \
macro(JSOP_INSTANCEOF,114,js_instanceof_str,js_instanceof_str,1,2,1,JOF_BYTE|JOF_LEFTASSOC) \
macro(JSOP_INSTANCEOF,114,js_instanceof_str,js_instanceof_str,1,2,1,JOF_BYTE) \
\
/*
* Invokes debugger.
@ -1280,7 +1280,7 @@
* Operands:
* Stack: receiver, propval, obj => obj[propval]
*/ \
macro(JSOP_GETELEM_SUPER, 125, "getelem-super", NULL, 1, 3, 1, JOF_BYTE|JOF_ELEM|JOF_TYPESET|JOF_LEFTASSOC) \
macro(JSOP_GETELEM_SUPER, 125, "getelem-super", NULL, 1, 3, 1, JOF_BYTE|JOF_ELEM|JOF_TYPESET) \
macro(JSOP_UNUSED126, 126, "unused126", NULL, 5, 0, 1, JOF_UINT32) \
\
/*
@ -1981,7 +1981,7 @@
* Operands:
* Stack: obj, propval => obj[propval]
*/ \
macro(JSOP_CALLELEM, 193, "callelem", NULL, 1, 2, 1, JOF_BYTE |JOF_ELEM|JOF_TYPESET|JOF_LEFTASSOC) \
macro(JSOP_CALLELEM, 193, "callelem", NULL, 1, 2, 1, JOF_BYTE |JOF_ELEM|JOF_TYPESET) \
\
/*
* '__proto__: v' inside an object initializer.

Просмотреть файл

@ -17,6 +17,7 @@
#include "js/SourceBufferHolder.h"
#include "js/Utility.h"
#include "mozilla/Attributes.h"
#include "mozilla/dom/ChromeUtils.h"
#include "mozilla/dom/Promise.h"
#include "mozilla/dom/ScriptLoader.h"
@ -43,23 +44,19 @@ public:
AsyncScriptCompiler(JSContext* aCx,
nsIGlobalObject* aGlobal,
const nsACString& aURL,
const CompileScriptOptionsDictionary& aOptions,
Promise* aPromise)
: mozilla::Runnable("AsyncScriptCompiler")
, mOptions(aCx)
, mURL(aURL)
, mGlobalObject(aGlobal)
, mPromise(aPromise)
, mCharset(aOptions.mCharset)
, mToken(nullptr)
, mScriptLength(0)
{
mOptions.setNoScriptRval(!aOptions.mHasReturnValue)
.setCanLazilyParse(aOptions.mLazilyParse)
.setFile(aCx, mURL.get());
}
{}
nsresult Start(nsIPrincipal* aPrincipal);
MOZ_MUST_USE nsresult Start(JSContext* aCx,
const CompileScriptOptionsDictionary& aOptions,
nsIPrincipal* aPrincipal);
inline void
SetToken(JS::OffThreadToken* aToken)
@ -97,8 +94,19 @@ NS_IMPL_ADDREF_INHERITED(AsyncScriptCompiler, Runnable)
NS_IMPL_RELEASE_INHERITED(AsyncScriptCompiler, Runnable)
nsresult
AsyncScriptCompiler::Start(nsIPrincipal* aPrincipal)
AsyncScriptCompiler::Start(JSContext* aCx,
const CompileScriptOptionsDictionary& aOptions,
nsIPrincipal* aPrincipal)
{
mCharset = aOptions.mCharset;
mOptions.setNoScriptRval(!aOptions.mHasReturnValue)
.setCanLazilyParse(aOptions.mLazilyParse);
if (NS_WARN_IF(!mOptions.setFile(aCx, mURL.get()))) {
return NS_ERROR_OUT_OF_MEMORY;
}
nsCOMPtr<nsIURI> uri;
nsresult rv = NS_NewURI(getter_AddRefs(uri), mURL);
NS_ENSURE_SUCCESS(rv, rv);
@ -279,9 +287,9 @@ ChromeUtils::CompileScript(GlobalObject& aGlobal,
}
NS_ConvertUTF16toUTF8 url(aURL);
RefPtr<AsyncScriptCompiler> compiler = new AsyncScriptCompiler(aGlobal.Context(), global, url, aOptions, promise);
RefPtr<AsyncScriptCompiler> compiler = new AsyncScriptCompiler(aGlobal.Context(), global, url, promise);
nsresult rv = compiler->Start(aGlobal.GetSubjectPrincipal());
nsresult rv = compiler->Start(aGlobal.Context(), aOptions, aGlobal.GetSubjectPrincipal());
if (NS_FAILED(rv)) {
promise->MaybeReject(rv);
}

Просмотреть файл

@ -586,6 +586,29 @@ nsXPCWrappedJSClass::DelegatedQueryInterface(nsXPCWrappedJS* self,
return NS_OK;
}
// If we're asked to QI to nsISimpleEnumerator and the wrapped object does not have a
// QueryInterface method, assume it is a JS iterator, and wrap it into an equivalent
// nsISimpleEnumerator.
if (aIID.Equals(NS_GET_IID(nsISimpleEnumerator))) {
bool found;
XPCJSContext* xpccx = ccx.GetContext();
if (JS_HasPropertyById(aes.cx(), obj,
xpccx->GetStringID(xpccx->IDX_QUERY_INTERFACE),
&found) && !found) {
nsresult rv;
nsCOMPtr<nsIJSEnumerator> jsEnum;
if (!XPCConvert::JSObject2NativeInterface(aes.cx(),
getter_AddRefs(jsEnum), obj,
&NS_GET_IID(nsIJSEnumerator),
nullptr, &rv)) {
return rv;
}
nsCOMPtr<nsISimpleEnumerator> res = new XPCWrappedJSIterator(jsEnum);
res.forget(aInstancePtr);
return NS_OK;
}
}
// Checks for any existing wrapper explicitly constructed for this iid.
// This includes the current 'self' wrapper. This also deals with the
// nsISupports case (for which it returns mRoot).
@ -611,29 +634,6 @@ nsXPCWrappedJSClass::DelegatedQueryInterface(nsXPCWrappedJS* self,
return rv;
}
// If we're asked to QI to nsISimpleEnumerator and the wrapped object does not have a
// QueryInterface method, assume it is a JS iterator, and wrap it into an equivalent
// nsISimpleEnumerator.
if (aIID.Equals(NS_GET_IID(nsISimpleEnumerator))) {
bool found;
XPCJSContext* xpccx = ccx.GetContext();
if (JS_HasPropertyById(aes.cx(), obj,
xpccx->GetStringID(xpccx->IDX_QUERY_INTERFACE),
&found) && !found) {
nsresult rv;
nsCOMPtr<nsIJSEnumerator> jsEnum;
if (!XPCConvert::JSObject2NativeInterface(aes.cx(),
getter_AddRefs(jsEnum), obj,
&NS_GET_IID(nsIJSEnumerator),
nullptr, &rv)) {
return rv;
}
nsCOMPtr<nsISimpleEnumerator> res = new XPCWrappedJSIterator(jsEnum);
res.forget(aInstancePtr);
return NS_OK;
}
}
// else we do the more expensive stuff...
// check if the JSObject claims to implement this interface

Просмотреть файл

@ -9,12 +9,24 @@ const Variant = Components.Constructor("@mozilla.org/variant;1",
const SupportsInterfacePointer = Components.Constructor(
"@mozilla.org/supports-interface-pointer;1", "nsISupportsInterfacePointer");
function wrapEnumerator(iter) {
function wrapEnumerator1(iter) {
var ip = SupportsInterfacePointer();
ip.data = iter;
return ip.data.QueryInterface(Ci.nsISimpleEnumerator);
}
function wrapEnumerator2(iter) {
var ip = SupportsInterfacePointer();
ip.data = {
QueryInterface: ChromeUtils.generateQI([Ci.nsIFilePicker]),
get files() {
return iter;
},
};
return ip.data.QueryInterface(Ci.nsIFilePicker).files;
}
function enumToArray(iter) {
let result = [];
while (iter.hasMoreElements()) {
@ -26,32 +38,34 @@ function enumToArray(iter) {
add_task(async function test_wrapped_js_enumerator() {
let array = [1, 2, 3, 4];
// Test a plain JS iterator. This should automatically be wrapped into
// an equivalent nsISimpleEnumerator.
{
let iter = wrapEnumerator(array.values());
let result = enumToArray(iter);
for (let wrapEnumerator of [wrapEnumerator1, wrapEnumerator2]) {
// Test a plain JS iterator. This should automatically be wrapped into
// an equivalent nsISimpleEnumerator.
{
let iter = wrapEnumerator(array.values());
let result = enumToArray(iter);
deepEqual(result, array, "Got correct result");
}
deepEqual(result, array, "Got correct result");
}
// Test an object with a QueryInterface method, which implements
// nsISimpleEnumerator. This should be wrapped and used directly.
{
let obj = {
QueryInterface: ChromeUtils.generateQI(["nsISimpleEnumerator"]),
_idx: 0,
hasMoreElements() {
return this._idx < array.length;
},
getNext() {
return Variant(array[this._idx++]);
},
};
// Test an object with a QueryInterface method, which implements
// nsISimpleEnumerator. This should be wrapped and used directly.
{
let obj = {
QueryInterface: ChromeUtils.generateQI(["nsISimpleEnumerator"]),
_idx: 0,
hasMoreElements() {
return this._idx < array.length;
},
getNext() {
return Variant(array[this._idx++]);
},
};
let iter = wrapEnumerator(obj);
let result = enumToArray(iter);
let iter = wrapEnumerator(obj);
let result = enumToArray(iter);
deepEqual(result, array, "Got correct result");
deepEqual(result, array, "Got correct result");
}
}
});

Просмотреть файл

@ -485,20 +485,19 @@ BulletRenderer::CreateWebRenderCommandsForImage(nsDisplayItem* aItem,
return false;
}
mozilla::wr::ImageRendering rendering = wr::ToImageRendering(
nsLayoutUtils::GetSamplingFilterForFrame(aItem->Frame()));
gfx::IntSize size;
Maybe<wr::ImageKey> key = aManager->CommandBuilder().CreateImageKey(aItem, container, aBuilder, aResources,
aSc, size, Nothing());
Maybe<wr::ImageKey> key = aManager->CommandBuilder().CreateImageKey(
aItem, container, aBuilder, aResources, rendering, aSc, size, Nothing());
if (key.isNothing()) {
return true; // Nothing to do
}
wr::LayoutRect dest = wr::ToRoundedLayoutRect(destRect);
aBuilder.PushImage(dest,
dest,
!aItem->BackfaceIsHidden(),
wr::ImageRendering::Auto,
key.value());
aBuilder.PushImage(
dest, dest, !aItem->BackfaceIsHidden(), rendering, key.value());
return true;
}

Просмотреть файл

@ -3859,9 +3859,18 @@ nsCSSBorderImageRenderer::CreateWebRenderCommands(
return;
}
mozilla::wr::ImageRendering rendering = wr::ToImageRendering(
nsLayoutUtils::GetSamplingFilterForFrame(aItem->Frame()));
gfx::IntSize size;
Maybe<wr::ImageKey> key = aManager->CommandBuilder().CreateImageKey(
aItem, container, aBuilder, aResources, aSc, size, Nothing());
Maybe<wr::ImageKey> key =
aManager->CommandBuilder().CreateImageKey(aItem,
container,
aBuilder,
aResources,
rendering,
aSc,
size,
Nothing());
if (key.isNothing()) {
return;
}

Просмотреть файл

@ -649,9 +649,18 @@ nsImageRenderer::BuildWebRenderDisplayItems(
return ImgDrawResult::NOT_READY;
}
mozilla::wr::ImageRendering rendering = wr::ToImageRendering(
nsLayoutUtils::GetSamplingFilterForFrame(aItem->Frame()));
gfx::IntSize size;
Maybe<wr::ImageKey> key = aManager->CommandBuilder().CreateImageKey(
aItem, container, aBuilder, aResources, aSc, size, Nothing());
Maybe<wr::ImageKey> key =
aManager->CommandBuilder().CreateImageKey(aItem,
container,
aBuilder,
aResources,
rendering,
aSc,
size,
Nothing());
if (key.isNothing()) {
return ImgDrawResult::NOT_READY;
@ -666,20 +675,45 @@ nsImageRenderer::BuildWebRenderDisplayItems(
aFill.YMost() - firstTilePos.y),
appUnitsPerDevPixel);
wr::LayoutRect fill = wr::ToRoundedLayoutRect(fillRect);
wr::LayoutRect roundedDest = wr::ToRoundedLayoutRect(destRect);
auto stretchSize = wr::ToLayoutSize(destRect.Size());
// WebRender special cases situations where stretchSize == fillSize to
// infer that it shouldn't use repeat sampling. This makes sure
// we hit those special cases when not repeating.
switch (mExtendMode) {
case ExtendMode::CLAMP:
fill = roundedDest;
stretchSize = roundedDest.size;
break;
case ExtendMode::REPEAT_Y:
fill.origin.x = roundedDest.origin.x;
fill.size.width = roundedDest.size.width;
stretchSize.width = roundedDest.size.width;
break;
case ExtendMode::REPEAT_X:
fill.origin.y = roundedDest.origin.y;
fill.size.height = roundedDest.size.height;
stretchSize.height = roundedDest.size.height;
break;
default:
break;
}
wr::LayoutRect clip = wr::ToRoundedLayoutRect(
LayoutDeviceRect::FromAppUnits(aFill, appUnitsPerDevPixel));
LayoutDeviceSize gapSize = LayoutDeviceSize::FromAppUnits(
aRepeatSize - aDest.Size(), appUnitsPerDevPixel);
SamplingFilter samplingFilter =
nsLayoutUtils::GetSamplingFilterForFrame(mForFrame);
aBuilder.PushImage(fill,
clip,
!aItem->BackfaceIsHidden(),
wr::ToLayoutSize(destRect.Size()),
stretchSize,
wr::ToLayoutSize(gapSize),
wr::ToImageRendering(samplingFilter),
rendering,
key.value());
break;
}

Просмотреть файл

@ -459,20 +459,24 @@ nsImageBoxFrame::CreateWebRenderCommands(mozilla::wr::DisplayListBuilder& aBuild
return Nothing();
}
mozilla::wr::ImageRendering rendering = wr::ToImageRendering(
nsLayoutUtils::GetSamplingFilterForFrame(aItem->Frame()));
gfx::IntSize size;
Maybe<wr::ImageKey> key = aManager->CommandBuilder().CreateImageKey(aItem, container,
aBuilder, aResources,
aSc, size, Nothing());
Maybe<wr::ImageKey> key = aManager->CommandBuilder().CreateImageKey(
aItem, container, aBuilder, aResources, rendering, aSc, size, Nothing());
if (key.isNothing()) {
return Some(ImgDrawResult::NOT_READY);
}
wr::LayoutRect fill = wr::ToRoundedLayoutRect(fillRect);
LayoutDeviceSize gapSize(0, 0);
SamplingFilter sampleFilter = nsLayoutUtils::GetSamplingFilterForFrame(aItem->Frame());
aBuilder.PushImage(fill, fill, !BackfaceIsHidden(),
wr::ToLayoutSize(fillRect.Size()), wr::ToLayoutSize(gapSize),
wr::ToImageRendering(sampleFilter), key.value());
aBuilder.PushImage(fill,
fill,
!BackfaceIsHidden(),
wr::ToLayoutSize(fillRect.Size()),
wr::ToLayoutSize(gapSize),
rendering,
key.value());
return Some(ImgDrawResult::SUCCESS);
}

Просмотреть файл

@ -730,12 +730,11 @@
# endif
# define MOZ_IMPLICIT __attribute__((annotate("moz_implicit")))
# define MOZ_IS_SMARTPTR_TO_REFCOUNTED __attribute__((annotate("moz_is_smartptr_to_refcounted")))
# define MOZ_IS_REFPTR __attribute__((annotate("moz_is_refptr"))) \
MOZ_IS_SMARTPTR_TO_REFCOUNTED
# define MOZ_IS_REFPTR MOZ_IS_SMARTPTR_TO_REFCOUNTED
# define MOZ_NO_ARITHMETIC_EXPR_IN_ARGUMENT __attribute__((annotate("moz_no_arith_expr_in_arg")))
# define MOZ_OWNING_REF __attribute__((annotate("moz_strong_ref")))
# define MOZ_NON_OWNING_REF __attribute__((annotate("moz_weak_ref")))
# define MOZ_UNSAFE_REF(reason) __attribute__((annotate("moz_weak_ref")))
# define MOZ_OWNING_REF
# define MOZ_NON_OWNING_REF
# define MOZ_UNSAFE_REF(reason)
# define MOZ_NO_ADDREF_RELEASE_ON_RETURN __attribute__((annotate("moz_no_addref_release_on_return")))
# define MOZ_MUST_USE_TYPE __attribute__((annotate("moz_must_use_type")))
# define MOZ_NEEDS_NO_VTABLE_TYPE __attribute__((annotate("moz_needs_no_vtable_type")))
@ -746,10 +745,8 @@
# define MOZ_INHERIT_TYPE_ANNOTATIONS_FROM_TEMPLATE_ARGS \
__attribute__((annotate("moz_inherit_type_annotations_from_template_args")))
# define MOZ_NON_AUTOABLE __attribute__((annotate("moz_non_autoable")))
# define MOZ_INIT_OUTSIDE_CTOR \
__attribute__((annotate("moz_ignore_ctor_initialization")))
# define MOZ_IS_CLASS_INIT \
__attribute__((annotate("moz_is_class_init")))
# define MOZ_INIT_OUTSIDE_CTOR
# define MOZ_IS_CLASS_INIT
# define MOZ_NON_PARAM \
__attribute__((annotate("moz_non_param")))
# define MOZ_REQUIRED_BASE_METHOD \

Просмотреть файл

@ -47,8 +47,6 @@ namespace recordreplay {
Macro(InternalEndPassThroughThreadEvents, (), ()) \
Macro(InternalBeginDisallowThreadEvents, (), ()) \
Macro(InternalEndDisallowThreadEvents, (), ()) \
Macro(InternalBeginCaptureEventStacks, (), ()) \
Macro(InternalEndCaptureEventStacks, (), ()) \
Macro(InternalRecordReplayBytes, \
(void* aData, size_t aSize), (aData, aSize)) \
Macro(NotifyUnrecordedWait, \

Просмотреть файл

@ -167,18 +167,6 @@ struct MOZ_RAII AutoDisallowThreadEvents
~AutoDisallowThreadEvents() { EndDisallowThreadEvents(); }
};
// Mark a region where thread events should have stack information captured.
// These stacks help in tracking down record/replay inconsistencies.
static inline void BeginCaptureEventStacks();
static inline void EndCaptureEventStacks();
// RAII class for a region where thread event stacks should be captured.
struct MOZ_RAII AutoCaptureEventStacks
{
AutoCaptureEventStacks() { BeginCaptureEventStacks(); }
~AutoCaptureEventStacks() { EndCaptureEventStacks(); }
};
// Record or replay a value in the current thread's event stream.
static inline size_t RecordReplayValue(size_t aValue);
@ -430,8 +418,6 @@ MOZ_MakeRecordReplayWrapper(AreThreadEventsPassedThrough, bool, false, (), ())
MOZ_MakeRecordReplayWrapperVoid(BeginDisallowThreadEvents, (), ())
MOZ_MakeRecordReplayWrapperVoid(EndDisallowThreadEvents, (), ())
MOZ_MakeRecordReplayWrapper(AreThreadEventsDisallowed, bool, false, (), ())
MOZ_MakeRecordReplayWrapperVoid(BeginCaptureEventStacks, (), ())
MOZ_MakeRecordReplayWrapperVoid(EndCaptureEventStacks, (), ())
MOZ_MakeRecordReplayWrapper(RecordReplayValue, size_t, aValue, (size_t aValue), (aValue))
MOZ_MakeRecordReplayWrapperVoid(RecordReplayBytes, (void* aData, size_t aSize), (aData, aSize))
MOZ_MakeRecordReplayWrapper(HasDivergedFromRecording, bool, false, (), ())

Просмотреть файл

@ -8,6 +8,7 @@ ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
ChromeUtils.defineModuleGetter(this, "AboutReader", "resource://gre/modules/AboutReader.jsm");
ChromeUtils.defineModuleGetter(this, "ReaderMode", "resource://gre/modules/ReaderMode.jsm");
ChromeUtils.defineModuleGetter(this, "Readerable", "resource://gre/modules/Readerable.jsm");
ChromeUtils.defineModuleGetter(this, "LoginManagerContent", "resource://gre/modules/LoginManagerContent.jsm");
XPCOMUtils.defineLazyGetter(this, "gPipNSSBundle", function() {
@ -486,7 +487,7 @@ var AboutReaderListener = {
// Do not show Reader View icon on error pages (bug 1320900)
if (this.isErrorPage) {
sendAsyncMessage("Reader:UpdateReaderButton", { isArticle: false });
} else if (!ReaderMode.isEnabledForParseOnLoad || this.isAboutReader ||
} else if (!Readerable.isEnabledForParseOnLoad || this.isAboutReader ||
!(content.document instanceof content.HTMLDocument) ||
content.document.mozSyntheticDocument) {
@ -522,11 +523,12 @@ var AboutReaderListener = {
return;
}
Services.console.logStringMessage(`ON PAINT WHEN WAITED FOR\n`);
this.cancelPotentialPendingReadabilityCheck();
// Only send updates when there are articles; there's no point updating with
// |false| all the time.
if (ReaderMode.isProbablyReaderable(content.document)) {
if (Readerable.isProbablyReaderable(content.document)) {
sendAsyncMessage("Reader:UpdateReaderButton", { isArticle: true });
} else if (forceNonArticle) {
sendAsyncMessage("Reader:UpdateReaderButton", { isArticle: false });

Просмотреть файл

@ -175,15 +175,11 @@ NS_GENERIC_FACTORY_CONSTRUCTOR(nsMIMEHeaderParamImpl)
#include "nsRequestObserverProxy.h"
#include "nsSimpleStreamListener.h"
#include "nsDirIndexParser.h"
#include "nsDirIndex.h"
typedef mozilla::net::nsRequestObserverProxy nsRequestObserverProxy;
NS_GENERIC_FACTORY_CONSTRUCTOR(nsRequestObserverProxy)
typedef mozilla::net::nsSimpleStreamListener nsSimpleStreamListener;
NS_GENERIC_FACTORY_CONSTRUCTOR(nsSimpleStreamListener)
NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(nsDirIndexParser, Init)
NS_GENERIC_FACTORY_CONSTRUCTOR(nsDirIndex)
///////////////////////////////////////////////////////////////////////////////
@ -704,13 +700,11 @@ NS_DEFINE_NAMED_CID(NS_NAMEDPIPESERVICE_CID);
NS_DEFINE_NAMED_CID(NS_DASHBOARD_CID);
NS_DEFINE_NAMED_CID(NS_FTPDIRLISTINGCONVERTER_CID);
NS_DEFINE_NAMED_CID(NS_NSINDEXEDTOHTMLCONVERTER_CID);
NS_DEFINE_NAMED_CID(NS_DIRINDEXPARSER_CID);
NS_DEFINE_NAMED_CID(NS_MULTIMIXEDCONVERTER_CID);
NS_DEFINE_NAMED_CID(NS_UNKNOWNDECODER_CID);
NS_DEFINE_NAMED_CID(NS_BINARYDETECTOR_CID);
NS_DEFINE_NAMED_CID(NS_HTTPCOMPRESSCONVERTER_CID);
NS_DEFINE_NAMED_CID(MOZITXTTOHTMLCONV_CID);
NS_DEFINE_NAMED_CID(NS_DIRINDEX_CID);
NS_DEFINE_NAMED_CID(NS_MIMEHEADERPARAM_CID);
NS_DEFINE_NAMED_CID(NS_FILEPROTOCOLHANDLER_CID);
NS_DEFINE_NAMED_CID(NS_HTTPPROTOCOLHANDLER_CID);
@ -824,13 +818,11 @@ static const mozilla::Module::CIDEntry kNeckoCIDs[] = {
{ &kNS_DASHBOARD_CID, false, nullptr, mozilla::net::DashboardConstructor },
{ &kNS_FTPDIRLISTINGCONVERTER_CID, false, nullptr, CreateNewFTPDirListingConv },
{ &kNS_NSINDEXEDTOHTMLCONVERTER_CID, false, nullptr, nsIndexedToHTML::Create },
{ &kNS_DIRINDEXPARSER_CID, false, nullptr, nsDirIndexParserConstructor },
{ &kNS_MULTIMIXEDCONVERTER_CID, false, nullptr, CreateNewMultiMixedConvFactory },
{ &kNS_UNKNOWNDECODER_CID, false, nullptr, CreateNewUnknownDecoderFactory },
{ &kNS_BINARYDETECTOR_CID, false, nullptr, CreateNewBinaryDetectorFactory },
{ &kNS_HTTPCOMPRESSCONVERTER_CID, false, nullptr, CreateNewHTTPCompressConvFactory },
{ &kMOZITXTTOHTMLCONV_CID, false, nullptr, CreateNewTXTToHTMLConvFactory },
{ &kNS_DIRINDEX_CID, false, nullptr, nsDirIndexConstructor },
{ &kNS_MIMEHEADERPARAM_CID, false, nullptr, nsMIMEHeaderParamImplConstructor },
{ &kNS_FILEPROTOCOLHANDLER_CID, false, nullptr, nsFileProtocolHandlerConstructor },
{ &kNS_HTTPPROTOCOLHANDLER_CID, false, nullptr, mozilla::net::nsHttpHandlerConstructor },
@ -943,7 +935,6 @@ static const mozilla::Module::ContractIDEntry kNeckoContracts[] = {
{ NS_DASHBOARD_CONTRACTID, &kNS_DASHBOARD_CID },
{ NS_ISTREAMCONVERTER_KEY FTP_TO_INDEX, &kNS_FTPDIRLISTINGCONVERTER_CID },
{ NS_ISTREAMCONVERTER_KEY INDEX_TO_HTML, &kNS_NSINDEXEDTOHTMLCONVERTER_CID },
{ NS_DIRINDEXPARSER_CONTRACTID, &kNS_DIRINDEXPARSER_CID },
{ NS_ISTREAMCONVERTER_KEY MULTI_MIXED_X, &kNS_MULTIMIXEDCONVERTER_CID },
{ NS_ISTREAMCONVERTER_KEY MULTI_BYTERANGES, &kNS_MULTIMIXEDCONVERTER_CID },
{ NS_ISTREAMCONVERTER_KEY MULTI_MIXED, &kNS_MULTIMIXEDCONVERTER_CID },
@ -956,7 +947,6 @@ static const mozilla::Module::ContractIDEntry kNeckoContracts[] = {
{ NS_ISTREAMCONVERTER_KEY XCOMPRESS_TO_UNCOMPRESSED, &kNS_HTTPCOMPRESSCONVERTER_CID },
{ NS_ISTREAMCONVERTER_KEY DEFLATE_TO_UNCOMPRESSED, &kNS_HTTPCOMPRESSCONVERTER_CID },
{ MOZ_TXTTOHTMLCONV_CONTRACTID, &kMOZITXTTOHTMLCONV_CID },
{ "@mozilla.org/dirIndex;1", &kNS_DIRINDEX_CID },
{ NS_MIMEHEADERPARAM_CONTRACTID, &kNS_MIMEHEADERPARAM_CID },
{ NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX "file", &kNS_FILEPROTOCOLHANDLER_CID },
{ NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX "http", &kNS_HTTPPROTOCOLHANDLER_CID },

Просмотреть файл

@ -3,12 +3,13 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef nsDirIndex_h__
#define nsDirIndex_h__
#include "nsIDirIndex.h"
#include "nsString.h"
#include "mozilla/Attributes.h"
/* CID: {f6913e2e-1dd1-11b2-84be-f455dee342af} */
class nsDirIndex final : public nsIDirIndex {
private:
@ -28,3 +29,5 @@ protected:
int64_t mSize;
PRTime mLastModified;
};
#endif

Просмотреть файл

@ -12,6 +12,7 @@
#include "mozilla/Encoding.h"
#include "prprf.h"
#include "nsCRT.h"
#include "nsDirIndex.h"
#include "nsEscape.h"
#include "nsIDirIndex.h"
#include "nsIInputStream.h"
@ -395,9 +396,7 @@ nsDirIndexParser::ProcessData(nsIRequest *aRequest, nsISupports *aCtxt) {
}
} else if (buf[2] == '1' && buf[3] == ':') {
// 201. Field data
nsCOMPtr<nsIDirIndex> idx = do_CreateInstance("@mozilla.org/dirIndex;1",&rv);
if (NS_FAILED(rv))
return rv;
nsCOMPtr<nsIDirIndex> idx = new nsDirIndex();
rv = ParseData(idx, ((char *)buf) + 4, lineLen - 4);
if (NS_FAILED(rv)) {

Просмотреть файл

@ -9,6 +9,7 @@
#include "nsString.h"
#include "nsCOMPtr.h"
#include "nsIDirIndexListener.h"
#include "mozilla/RefPtr.h"
class nsIDirIndex;
class nsITextToSubURI;
@ -20,14 +21,24 @@ class nsDirIndexParser : public nsIDirIndexParser {
private:
virtual ~nsDirIndexParser();
nsDirIndexParser();
nsresult Init();
public:
NS_DECL_ISUPPORTS
NS_DECL_NSISTREAMLISTENER
NS_DECL_NSIREQUESTOBSERVER
NS_DECL_NSIDIRINDEXPARSER
nsDirIndexParser();
nsresult Init();
static already_AddRefed<nsIDirIndexParser>
CreateInstance()
{
RefPtr<nsDirIndexParser> parser = new nsDirIndexParser();
if (NS_FAILED(parser->Init())) {
return nullptr;
}
return parser.forget();
}
enum fieldType {
FIELD_UNKNOWN = 0, // MUST be 0

Просмотреть файл

@ -22,6 +22,7 @@
#include "nsIPrefLocalizedString.h"
#include "nsIStringBundle.h"
#include "nsITextToSubURI.h"
#include "nsDirIndexParser.h"
#include "nsNativeCharsetUtils.h"
#include "nsString.h"
#include <algorithm>
@ -151,8 +152,8 @@ nsIndexedToHTML::DoOnStartRequest(nsIRequest* request, nsISupports *aContext,
channel->SetContentType(NS_LITERAL_CSTRING("text/html"));
mParser = do_CreateInstance("@mozilla.org/dirIndexParser;1",&rv);
if (NS_FAILED(rv)) return rv;
mParser = nsDirIndexParser::CreateInstance();
if (!mParser) return NS_ERROR_FAILURE;
rv = mParser->SetListener(this);
if (NS_FAILED(rv)) return rv;

Просмотреть файл

@ -70,13 +70,3 @@ interface nsIDirIndex : nsISupports
attribute PRTime lastModified;
};
%{C++
#define NS_DIRINDEX_CID \
/* { f6913e2e-1dd1-11b2-84be-f455dee342af } */ \
{ 0xf6913e2e, \
0x1dd1, \
0x11b2, \
{ 0x84, 0xbe, 0xf4, 0x55, 0xde, 0xe3, 0x42, 0xaf } \
}
%}

Просмотреть файл

@ -38,10 +38,6 @@ interface nsIDirIndexListener : nsISupports {
};
%{C++
#define NS_IDIRINDEXLISTENER_KEY "@mozilla.org/dirIndexListener;1"
%}
/**
* A parser for application/http-index-format
*/
@ -65,15 +61,3 @@ interface nsIDirIndexParser : nsIStreamListener {
attribute string encoding;
};
%{C++
#define NS_DIRINDEXPARSER_CID \
{ /* a0d6ad32-1dd1-11b2-aa55-a40187b54036 */ \
0xa0d6ad32, \
0x1dd1, \
0x11b2, \
{ 0xaa, 0x55, 0xa4, 0x01, 0x87, 0xb5, 0x40, 0x36 } \
}
#define NS_DIRINDEXPARSER_CONTRACTID "@mozilla.org/dirIndexParser;1"
%}

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -100,8 +100,8 @@ jobs:
run:
using: debian-package
tarball:
url: https://www.mercurial-scm.org/release/mercurial-4.7.tar.gz
sha256: 098cb1437f77fb7f75dc2f008742933c729ec0b63cfa3e4e2f0a8fbc3d0d349f
url: https://www.mercurial-scm.org/release/mercurial-4.7.1.tar.gz
sha256: 8503383c1c31842576516b803d07564216470887ca6388719e4c4089663b410c
pre-build-command: >-
cp -r contrib/packaging/debian debian &&
sed -i -e "s/__VERSION__/$(awk -F\" '$2 {print $2}' mercurial/__version__.py)-1.deb7moz1/" \
@ -116,8 +116,8 @@ jobs:
using: debian-package
dist: stretch
tarball:
url: https://www.mercurial-scm.org/release/mercurial-4.7.tar.gz
sha256: 098cb1437f77fb7f75dc2f008742933c729ec0b63cfa3e4e2f0a8fbc3d0d349f
url: https://www.mercurial-scm.org/release/mercurial-4.7.1.tar.gz
sha256: 8503383c1c31842576516b803d07564216470887ca6388719e4c4089663b410c
pre-build-command: >-
cp -r contrib/packaging/debian debian &&
sed -i -e "s/__VERSION__/$(awk -F\" '$2 {print $2}' mercurial/__version__.py)-1.deb9moz1/" \

Просмотреть файл

@ -62,7 +62,7 @@ mochitest:
default: virtual
chunks:
by-test-platform:
android-em-4.3-arm7-api-16/debug: 48
android-em-4.3-arm7-api-16/debug: 60
android-em-7.0-x86/opt: 4
android-em.*: 24
linux.*/debug: 16

Просмотреть файл

@ -16,13 +16,13 @@ if [ -f /etc/lsb-release ]; then
if [ "${DISTRIB_ID}" = "Ubuntu" ] && [[ "${DISTRIB_RELEASE}" = "16.04" || "${DISTRIB_RELEASE}" = "17.10" || "${DISTRIB_RELEASE}" = "18.04" ]]
then
HG_DEB=1
HG_DIGEST=21a5ca8170bdb05527b04cbc93f00ecef39680a2c7b80aa625f9add8b7dba0a7bff0ad58e0ba40b1956ae310f681d04302d033e398eca0e001dce10d74d0dbdc
HG_SIZE=250748
HG_FILENAME=mercurial_4.7_amd64.deb
HG_DIGEST=cbc3eafbc7598c7eafee81f4fb95f8d58dea5fede0fca6a04334eaa29667b9b464e3070fa24be91276d7294ba4629d7b7a648cbf969256289e9a28f5da684d09
HG_SIZE=250774
HG_FILENAME=mercurial_4.7.1_amd64.deb
HG_COMMON_DIGEST=521e0c150b142d0bbb69fa100b96bac5bee7a108605eea1c484e8544540dcf764efffab2e3a9ad640f56674ad85c1b47647e3d504c96f7567d7d7c21299c2c25
HG_COMMON_SIZE=2315590
HG_COMMON_FILENAME=mercurial-common_4.7_all.deb
HG_COMMON_DIGEST=15f9c72dba116d33c2d60831bc17cd714d66b830089aebe547c846b910dbc929200f7863e167a8dade67c77c4347b8e967e6da505c2fdffa4faaa7143eccdfd8
HG_COMMON_SIZE=2315652
HG_COMMON_FILENAME=mercurial-common_4.7.1_all.deb
elif [ "${DISTRIB_ID}" = "Ubuntu" ] && [ "${DISTRIB_RELEASE}" = "12.04" ]
then
echo "Ubuntu 12.04 not supported"
@ -106,15 +106,15 @@ elif [ -n "${PIP_PATH}" ]; then
tooltool_fetch <<EOF
[
{
"size": 6476268,
"digest": "a08dfc4e296b5d162097769ab38ab85b7c5de16710bce0b6dce2a39f56cb517455c0ed634f689d07e9bd082fb7641501b7da51963844aee7ab28233cf721dec8",
"size": 6480135,
"digest": "04d3f97dd4a0f36c6f6d639d8eccc7e4f29b2dc211fa69e7fc17dae0eb954f2ddaaf04f70facc6b968a166db7c07ed80792575d7a27e80bc0c1a43fc38b5e536",
"algorithm": "sha512",
"filename": "mercurial-4.7.tar.gz"
"filename": "mercurial-4.7.1.tar.gz"
}
]
EOF
${PIP_PATH} install mercurial-4.7.tar.gz
${PIP_PATH} install mercurial-4.7.1.tar.gz
else
echo "Do not know how to install Mercurial on this OS"
exit 1

Просмотреть файл

@ -0,0 +1,96 @@
/* eslint-env es6:false */
/* globals exports */
/*
* Copyright (c) 2010 Arc90 Inc
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
* This code is heavily based on Arc90's readability.js (1.7.1) script
* available at: http://code.google.com/p/arc90labs-readability
*/
var REGEXPS = {
// NOTE: These two regular expressions are duplicated in
// Readability.js. Please keep both copies in sync.
unlikelyCandidates: /-ad-|banner|breadcrumbs|combx|comment|community|cover-wrap|disqus|extra|foot|header|legends|menu|related|remark|replies|rss|shoutbox|sidebar|skyscraper|social|sponsor|supplemental|ad-break|agegate|pagination|pager|popup|yom-remote/i,
okMaybeItsACandidate: /and|article|body|column|main|shadow/i,
};
function isNodeVisible(node) {
return node.style.display != "none" && !node.hasAttribute("hidden");
}
/**
* Decides whether or not the document is reader-able without parsing the whole thing.
*
* @return boolean Whether or not we suspect Readability.parse() will suceeed at returning an article object.
*/
function isProbablyReaderable(doc, isVisible) {
if (!isVisible) {
isVisible = isNodeVisible;
}
var nodes = doc.querySelectorAll("p, pre");
// Get <div> nodes which have <br> node(s) and append them into the `nodes` variable.
// Some articles' DOM structures might look like
// <div>
// Sentences<br>
// <br>
// Sentences<br>
// </div>
var brNodes = doc.querySelectorAll("div > br");
if (brNodes.length) {
var set = new Set(nodes);
[].forEach.call(brNodes, function(node) {
set.add(node.parentNode);
});
nodes = Array.from(set);
}
var score = 0;
// This is a little cheeky, we use the accumulator 'score' to decide what to return from
// this callback:
return [].some.call(nodes, function(node) {
if (!isVisible(node))
return false;
var matchString = node.className + " " + node.id;
if (REGEXPS.unlikelyCandidates.test(matchString) &&
!REGEXPS.okMaybeItsACandidate.test(matchString)) {
return false;
}
if (node.matches("li p")) {
return false;
}
var textContentLength = node.textContent.trim().length;
if (textContentLength < 140) {
return false;
}
score += Math.sqrt(textContentLength - 140);
if (score > 20) {
return true;
}
return false;
});
}
if (typeof exports === "object") {
exports.isProbablyReaderable = isProbablyReaderable;
}

Просмотреть файл

@ -1,11 +1,4 @@
/*eslint-env es6:false*/
/*
* DO NOT MODIFY THIS FILE DIRECTLY!
*
* This is a shared library that is maintained in an external repo:
* https://github.com/mozilla/readability
*/
/*
* Copyright (c) 2010 Arc90 Inc
*
@ -118,8 +111,11 @@ Readability.prototype = {
// All of the regular expressions in use within readability.
// Defined up here so we don't instantiate them repeatedly in loops.
REGEXPS: {
// NOTE: These two regular expressions are duplicated in
// Readability-readerable.js. Please keep both copies in sync.
unlikelyCandidates: /-ad-|banner|breadcrumbs|combx|comment|community|cover-wrap|disqus|extra|foot|header|legends|menu|related|remark|replies|rss|shoutbox|sidebar|skyscraper|social|sponsor|supplemental|ad-break|agegate|pagination|pager|popup|yom-remote/i,
okMaybeItsACandidate: /and|article|body|column|main|shadow/i,
positive: /article|body|content|entry|hentry|h-entry|main|page|pagination|post|text|blog|story/i,
negative: /hidden|^hid$| hid$| hid |^hid |banner|combx|comment|com-|contact|foot|footer|footnote|masthead|media|meta|outbrain|promo|related|scroll|share|shoutbox|sidebar|skyscraper|sponsor|shopping|tags|tool|widget/i,
extraneous: /print|archive|comment|discuss|e[\-]?mail|share|reply|all|login|sign|single|utility/i,
@ -1711,65 +1707,6 @@ Readability.prototype = {
return node.style.display != "none" && !node.hasAttribute("hidden");
},
/**
* Decides whether or not the document is reader-able without parsing the whole thing.
*
* @return boolean Whether or not we suspect parse() will suceeed at returning an article object.
*/
isProbablyReaderable: function(helperIsVisible) {
var nodes = this._getAllNodesWithTag(this._doc, ["p", "pre"]);
// Get <div> nodes which have <br> node(s) and append them into the `nodes` variable.
// Some articles' DOM structures might look like
// <div>
// Sentences<br>
// <br>
// Sentences<br>
// </div>
var brNodes = this._getAllNodesWithTag(this._doc, ["div > br"]);
if (brNodes.length) {
var set = new Set();
[].forEach.call(brNodes, function(node) {
set.add(node.parentNode);
});
nodes = [].concat.apply(Array.from(set), nodes);
}
if (!helperIsVisible) {
helperIsVisible = this._isProbablyVisible;
}
var score = 0;
// This is a little cheeky, we use the accumulator 'score' to decide what to return from
// this callback:
return this._someNode(nodes, function(node) {
if (helperIsVisible && !helperIsVisible(node))
return false;
var matchString = node.className + " " + node.id;
if (this.REGEXPS.unlikelyCandidates.test(matchString) &&
!this.REGEXPS.okMaybeItsACandidate.test(matchString)) {
return false;
}
if (node.matches && node.matches("li p")) {
return false;
}
var textContentLength = node.textContent.trim().length;
if (textContentLength < 140) {
return false;
}
score += Math.sqrt(textContentLength - 140);
if (score > 20) {
return true;
}
return false;
});
},
/**
* Runs readability.
*

Просмотреть файл

@ -41,13 +41,7 @@ ChromeUtils.defineModuleGetter(this, "EventDispatcher", "resource://gre/modules/
ChromeUtils.defineModuleGetter(this, "OS", "resource://gre/modules/osfile.jsm");
ChromeUtils.defineModuleGetter(this, "ReaderWorker", "resource://gre/modules/reader/ReaderWorker.jsm");
ChromeUtils.defineModuleGetter(this, "LanguageDetector", "resource:///modules/translation/LanguageDetector.jsm");
XPCOMUtils.defineLazyGetter(this, "Readability", function() {
let scope = {};
scope.dump = this.dump;
Services.scriptloader.loadSubScript("resource://gre/modules/reader/Readability.js", scope);
return scope.Readability;
});
ChromeUtils.defineModuleGetter(this, "Readerable", "resource://gre/modules/Readerable.jsm");
const gIsFirefoxDesktop = Services.appinfo.ID == "{ec8030f7-c20a-464f-9b0e-13a3a9e97384}";
@ -57,42 +51,6 @@ var ReaderMode = {
DEBUG: 0,
// Don't try to parse the page if it has too many elements (for memory and
// performance reasons)
get maxElemsToParse() {
delete this.parseNodeLimit;
Services.prefs.addObserver("reader.parse-node-limit", this);
return this.parseNodeLimit = Services.prefs.getIntPref("reader.parse-node-limit");
},
get isEnabledForParseOnLoad() {
delete this.isEnabledForParseOnLoad;
// Listen for future pref changes.
Services.prefs.addObserver("reader.parse-on-load.", this);
return this.isEnabledForParseOnLoad = this._getStateForParseOnLoad();
},
_getStateForParseOnLoad() {
let isEnabled = Services.prefs.getBoolPref("reader.parse-on-load.enabled");
let isForceEnabled = Services.prefs.getBoolPref("reader.parse-on-load.force-enabled");
return isForceEnabled || isEnabled;
},
observe(aMessage, aTopic, aData) {
switch (aTopic) {
case "nsPref:changed":
if (aData.startsWith("reader.parse-on-load.")) {
this.isEnabledForParseOnLoad = this._getStateForParseOnLoad();
} else if (aData === "reader.parse-node-limit") {
this.parseNodeLimit = Services.prefs.getIntPref(aData);
}
break;
}
},
/**
* Enter the reader mode by going forward one step in history if applicable,
* if not, append the about:reader page in the history instead.
@ -197,39 +155,6 @@ var ReaderMode = {
return null;
},
/**
* Decides whether or not a document is reader-able without parsing the whole thing.
*
* @param doc A document to parse.
* @return boolean Whether or not we should show the reader mode button.
*/
isProbablyReaderable(doc) {
// Only care about 'real' HTML documents:
if (doc.mozSyntheticDocument || !(doc instanceof doc.defaultView.HTMLDocument)) {
return false;
}
let uri = Services.io.newURI(doc.location.href);
if (!this._shouldCheckUri(uri)) {
return false;
}
let utils = this.getUtilsForWin(doc.defaultView);
// We pass in a helper function to determine if a node is visible, because
// it uses gecko APIs that the engine-agnostic readability code can't rely
// upon.
return new Readability(doc).isProbablyReaderable(this.isNodeVisible.bind(this, utils));
},
isNodeVisible(utils, node) {
let bounds = utils.getBoundsWithoutFlushing(node);
return bounds.height > 0 && bounds.width > 0;
},
getUtilsForWin(win) {
return win.windowUtils;
},
/**
* Gets an article from a loaded browser's document. This method will not attempt
* to parse certain URIs (e.g. about: URIs).
@ -239,7 +164,8 @@ var ReaderMode = {
* @resolves JS object representing the article, or null if no article is found.
*/
parseDocument(doc) {
if (!this._shouldCheckUri(doc.documentURIObject) || !this._shouldCheckUri(doc.baseURIObject, true)) {
if (!Readerable.shouldCheckUri(doc.documentURIObject) ||
!Readerable.shouldCheckUri(doc.baseURIObject, true)) {
this.log("Reader mode disabled for URI");
return null;
}
@ -259,7 +185,8 @@ var ReaderMode = {
if (!doc) {
return null;
}
if (!this._shouldCheckUri(doc.documentURIObject) || !this._shouldCheckUri(doc.baseURIObject, true)) {
if (!Readerable.shouldCheckUri(doc.documentURIObject) ||
!Readerable.shouldCheckUri(doc.baseURIObject, true)) {
this.log("Reader mode disabled for URI");
return null;
}
@ -269,7 +196,7 @@ var ReaderMode = {
_downloadDocument(url) {
try {
if (!this._shouldCheckUri(Services.io.newURI(url))) {
if (!Readerable.shouldCheckUri(Services.io.newURI(url))) {
return null;
}
} catch (ex) {
@ -415,42 +342,6 @@ var ReaderMode = {
dump("Reader: " + msg);
},
_blockedHosts: [
"amazon.com",
"github.com",
"mail.google.com",
"pinterest.com",
"reddit.com",
"twitter.com",
"youtube.com",
],
_shouldCheckUri(uri, isBaseUri = false) {
if (!(uri.schemeIs("http") || uri.schemeIs("https"))) {
this.log("Not parsing URI scheme: " + uri.scheme);
return false;
}
try {
uri.QueryInterface(Ci.nsIURL);
} catch (ex) {
// If this doesn't work, presumably the URL is not well-formed or something
return false;
}
// Sadly, some high-profile pages have false positives, so bail early for those:
let asciiHost = uri.asciiHost;
if (!isBaseUri && this._blockedHosts.some(blockedHost => asciiHost.endsWith(blockedHost))) {
return false;
}
if (!isBaseUri && (!uri.filePath || uri.filePath == "/")) {
this.log("Not parsing home page: " + uri.spec);
return false;
}
return true;
},
/**
* Attempts to parse a document into an article. Heavy lifting happens
* in readerWorker.js.
@ -641,3 +532,6 @@ var ReaderMode = {
return readingSpeed.get(lang) || readingSpeed.get("en");
},
};
XPCOMUtils.defineLazyPreferenceGetter(
ReaderMode, "maxElemsToParse", "reader.parse-node-limit", 0);

Просмотреть файл

@ -0,0 +1,79 @@
// -*- indent-tabs-mode: nil; js-indent-level: 2 -*-
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
// This file and Readability-readerable.js are merged together into
// Readerable.jsm.
/* exported Readerable */
/* import-globals-from Readability-readerable.js */
ChromeUtils.import("resource://gre/modules/Services.jsm");
ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
function isNodeVisible(node) {
return node.clientHeight > 0 && node.clientWidth > 0;
}
var Readerable = {
get isEnabledForParseOnLoad() {
return this.isEnabled || this.isForceEnabled;
},
/**
* Decides whether or not a document is reader-able without parsing the whole thing.
*
* @param doc A document to parse.
* @return boolean Whether or not we should show the reader mode button.
*/
isProbablyReaderable(doc) {
// Only care about 'real' HTML documents:
if (doc.mozSyntheticDocument || !(doc instanceof doc.defaultView.HTMLDocument)) {
return false;
}
let uri = Services.io.newURI(doc.location.href);
if (!this.shouldCheckUri(uri)) {
return false;
}
return isProbablyReaderable(doc, isNodeVisible);
},
_blockedHosts: [
"amazon.com",
"github.com",
"mail.google.com",
"pinterest.com",
"reddit.com",
"twitter.com",
"youtube.com",
],
shouldCheckUri(uri, isBaseUri = false) {
if (!["http", "https"].includes(uri.scheme)) {
return false;
}
if (!isBaseUri) {
// Sadly, some high-profile pages have false positives, so bail early for those:
let {host} = uri;
if (this._blockedHosts.some(blockedHost => host.endsWith(blockedHost))) {
return false;
}
if (uri.filePath == "/") {
return false;
}
}
return true;
},
};
XPCOMUtils.defineLazyPreferenceGetter(
Readerable, "isEnabled", "reader.parse-on-load.enabled", true);
XPCOMUtils.defineLazyPreferenceGetter(
Readerable, "isForceEnabled", "reader.parse-on-load.force-enabled", false);

Просмотреть файл

@ -0,0 +1,10 @@
// -*- indent-tabs-mode: nil; js-indent-level: 2 -*-
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
var EXPORTED_SYMBOLS = ["Readerable"];
#include Readability-readerable.js
#include Readerable.js

Просмотреть файл

@ -8,14 +8,18 @@ JAR_MANIFESTS += ['jar.mn']
EXTRA_JS_MODULES += [
'AboutReader.jsm',
'ReaderMode.jsm'
'ReaderMode.jsm',
]
EXTRA_PP_JS_MODULES += [
'Readerable.jsm',
]
EXTRA_JS_MODULES.reader = [
'JSDOMParser.js',
'Readability.js',
'ReaderWorker.js',
'ReaderWorker.jsm'
'ReaderWorker.jsm',
]
BROWSER_CHROME_MANIFESTS += [

Просмотреть файл

@ -578,6 +578,12 @@ ProxyStreamValid:
Set to "false" when encountering an invalid IPC proxy stream.
type: string
RecordReplay:
description: >
Set to 1 if this crash happened in a Web Replay middleman, recording,
or replaying process.
type: boolean
RecordReplayError:
description: >
Any fatal error that occurred while recording/replaying a tab.

Просмотреть файл

@ -65,6 +65,11 @@ UnsetExceptionHandler()
return NS_ERROR_NOT_IMPLEMENTED;
}
void
NotifyCrashReporterClientCreated()
{
}
nsresult
AnnotateCrashReport(Annotation key, bool data)
{

Просмотреть файл

@ -2130,8 +2130,8 @@ EnqueueDelayedNote(DelayedNote* aNote)
gDelayedAnnotations->AppendElement(aNote);
}
static void
RunAndCleanUpDelayedNotes()
void
NotifyCrashReporterClientCreated()
{
if (gDelayedAnnotations) {
for (nsAutoPtr<DelayedNote>& note : *gDelayedAnnotations) {
@ -3569,7 +3569,6 @@ SetRemoteExceptionHandler(const nsACString& crashPipe,
NS_ConvertASCIItoUTF16(crashPipe).get(),
nullptr);
gExceptionHandler->set_handle_debug_exceptions(true);
RunAndCleanUpDelayedNotes();
#ifdef _WIN64
SetJitExceptionHandler();
@ -3622,7 +3621,6 @@ SetRemoteExceptionHandler()
nullptr, // no callback context
true, // install signal handlers
gMagicChildCrashReportFd);
RunAndCleanUpDelayedNotes();
mozalloc_set_oom_abort_handler(AnnotateOOMAllocationSize);
@ -3653,7 +3651,6 @@ SetRemoteExceptionHandler(const nsACString& crashPipe)
nullptr, // no callback context
true, // install signal handlers
crashPipe.BeginReading());
RunAndCleanUpDelayedNotes();
mozalloc_set_oom_abort_handler(AnnotateOOMAllocationSize);

Просмотреть файл

@ -100,6 +100,10 @@ nsresult AnnotateCrashReport(Annotation key, const nsACString& data);
nsresult RemoveCrashReportAnnotation(Annotation key);
nsresult AppendAppNotesToCrashReport(const nsACString& data);
// Called after the crash reporter client has been created in a content
// process, allowing annotations to be processed.
void NotifyCrashReporterClientCreated();
void AnnotateOOMAllocationSize(size_t size);
void AnnotateTexturesSize(size_t size);
nsresult SetGarbageCollecting(bool collecting);

Просмотреть файл

@ -491,7 +491,7 @@ class TestFunctional(HelperMixin, unittest.TestCase):
'dist', 'host', 'bin',
'dump_syms')
self.target_bin = os.path.join(buildconfig.topobjdir,
'dist', 'bin', 'firefox')
'dist', 'bin', 'firefox-bin')
def tearDown(self):

Просмотреть файл

@ -19,7 +19,11 @@ const MOZ_APP_VENDOR = "";
// MOZ_APP_BASENAME is not optional for tests.
const MOZ_APP_BASENAME = "@MOZ_APP_BASENAME@";
#ifdef XP_LINUX
const APP_BIN_SUFFIX = "-bin";
#else
const APP_BIN_SUFFIX = "@BIN_SUFFIX@";
#endif
const APP_INFO_NAME = "XPCShell";
const APP_INFO_VENDOR = "Mozilla";

Просмотреть файл

@ -29,8 +29,6 @@ RegisterCallbackData(void* aData)
return;
}
RecordReplayAssert("RegisterCallbackData");
AutoOrderedAtomicAccess at;
StaticMutexAutoLock lock(gCallbackMutex);
if (!gCallbackData) {
@ -72,14 +70,10 @@ EndCallback()
void
SaveOrRestoreCallbackData(void** aData)
{
MOZ_RELEASE_ASSERT(IsRecordingOrReplaying());
MOZ_RELEASE_ASSERT(!AreThreadEventsPassedThrough());
MOZ_RELEASE_ASSERT(!AreThreadEventsDisallowed());
MOZ_RELEASE_ASSERT(gCallbackData);
Thread* thread = Thread::Current();
RecordReplayAssert("RestoreCallbackData");
MOZ_RELEASE_ASSERT(thread->CanAccessRecording());
thread->Events().RecordOrReplayThreadEvent(ThreadEvent::RestoreCallbackData);
@ -107,10 +101,8 @@ RemoveCallbackData(void* aData)
void
PassThroughThreadEventsAllowCallbacks(const std::function<void()>& aFn)
{
MOZ_RELEASE_ASSERT(IsRecordingOrReplaying());
MOZ_RELEASE_ASSERT(!AreThreadEventsDisallowed());
Thread* thread = Thread::Current();
MOZ_RELEASE_ASSERT(thread->CanAccessRecording());
if (IsRecording()) {
if (thread->IsMainThread()) {

Просмотреть файл

@ -51,7 +51,7 @@ Stream::ReadBytes(void* aData, size_t aSize)
// If we try to read off the end of a stream then we must have hit the end
// of the replay for this thread.
while (mChunkIndex == mChunks.length()) {
MOZ_RELEASE_ASSERT(mName == StreamName::Event || mName == StreamName::Assert);
MOZ_RELEASE_ASSERT(mName == StreamName::Event);
HitEndOfRecording();
}
@ -155,15 +155,74 @@ Stream::WriteScalar(size_t aValue)
} while (aValue);
}
void
Stream::RecordOrReplayThreadEvent(ThreadEvent aEvent)
{
if (IsRecording()) {
WriteScalar((size_t) aEvent);
} else {
ThreadEvent oldEvent = (ThreadEvent) ReadScalar();
if (oldEvent != aEvent) {
child::ReportFatalError(Nothing(), "Event Mismatch: Recorded %s Replayed %s",
ThreadEventName(oldEvent), ThreadEventName(aEvent));
}
mLastEvent = aEvent;
}
// Check the execution progress counter for events executing on the main thread.
if (mNameIndex == MainThreadId) {
CheckInput(*ExecutionProgressCounter());
}
}
void
Stream::CheckInput(size_t aValue)
{
size_t oldValue = aValue;
RecordOrReplayScalar(&oldValue);
if (oldValue != aValue) {
child::ReportFatalError(Nothing(), "Input Mismatch: Recorded: %zu Replayed %zu\n",
oldValue, aValue);
Unreachable();
if (IsRecording()) {
WriteScalar(aValue);
} else {
size_t oldValue = ReadScalar();
if (oldValue != aValue) {
child::ReportFatalError(Nothing(), "Input Mismatch: %s Recorded %llu Replayed %llu",
ThreadEventName(mLastEvent), oldValue, aValue);
}
}
}
void
Stream::CheckInput(const char* aValue)
{
size_t len = strlen(aValue);
if (IsRecording()) {
WriteScalar(len);
WriteBytes(aValue, len);
} else {
size_t oldLen = ReadScalar();
EnsureInputBallast(oldLen + 1);
ReadBytes(mInputBallast.get(), oldLen);
mInputBallast[oldLen] = 0;
if (len != oldLen || memcmp(aValue, mInputBallast.get(), len) != 0) {
child::ReportFatalError(Nothing(), "Input Mismatch: %s Recorded %s Replayed %s",
ThreadEventName(mLastEvent), mInputBallast.get(), aValue);
}
}
}
void
Stream::CheckInput(const void* aData, size_t aSize)
{
CheckInput(aSize);
if (IsRecording()) {
WriteBytes(aData, aSize);
} else {
EnsureInputBallast(aSize);
ReadBytes(mInputBallast.get(), aSize);
if (memcmp(aData, mInputBallast.get(), aSize) != 0) {
child::ReportFatalError(Nothing(), "Input Buffer Mismatch: %s",
ThreadEventName(mLastEvent));
}
}
}
@ -186,6 +245,12 @@ Stream::EnsureMemory(UniquePtr<char[]>* aBuf, size_t* aSize,
}
}
void
Stream::EnsureInputBallast(size_t aSize)
{
EnsureMemory(&mInputBallast, &mInputBallastSize, aSize, (size_t) -1, DontCopyExistingData);
}
void
Stream::Flush(bool aTakeLock)
{

Просмотреть файл

@ -56,7 +56,6 @@ enum class StreamName
Main,
Lock,
Event,
Assert,
Count
};
@ -103,6 +102,13 @@ class Stream
UniquePtr<char[]> mBallast;
size_t mBallastSize;
// Any buffer available to check for input mismatches.
UniquePtr<char[]> mInputBallast;
size_t mInputBallastSize;
// The last event in this stream, in case of an input mismatch.
ThreadEvent mLastEvent;
// The number of chunks that have been completely read or written. When
// writing, this equals mChunks.length().
size_t mChunkIndex;
@ -122,6 +128,9 @@ class Stream
, mStreamPos(0)
, mBallast(nullptr)
, mBallastSize(0)
, mInputBallast(nullptr)
, mInputBallastSize(0)
, mLastEvent((ThreadEvent) 0)
, mChunkIndex(0)
, mFlushedChunks(0)
{}
@ -158,17 +167,15 @@ public:
RecordOrReplayBytes(aPtr, sizeof(T));
}
// Make sure that a value is the same while replaying as it was while
// recording.
void CheckInput(size_t aValue);
// Note a new thread event for this stream, and make sure it is the same
// while replaying as it was while recording.
void RecordOrReplayThreadEvent(ThreadEvent aEvent);
// Add a thread event to this file. Each thread event in a file is followed
// by additional data specific to that event. Generally, CheckInput should be
// used while recording or replaying the data for a thread event so that any
// discrepancies with the recording are found immediately.
inline void RecordOrReplayThreadEvent(ThreadEvent aEvent) {
CheckInput((size_t)aEvent);
}
// Make sure that a value or buffer is the same while replaying as it was
// while recording.
void CheckInput(size_t aValue);
void CheckInput(const char* aValue);
void CheckInput(const void* aData, size_t aSize);
inline size_t StreamPosition() {
return mStreamPos;
@ -182,6 +189,7 @@ private:
void EnsureMemory(UniquePtr<char[]>* aBuf, size_t* aSize, size_t aNeededSize, size_t aMaxSize,
ShouldCopy aCopy);
void EnsureInputBallast(size_t aSize);
void Flush(bool aTakeLock);
static size_t BallastMaxSize();

Просмотреть файл

@ -68,15 +68,13 @@ static ReadWriteSpinLock gLocksLock;
/* static */ void
Lock::New(void* aNativeLock)
{
if (AreThreadEventsPassedThrough() || HasDivergedFromRecording()) {
Thread* thread = Thread::Current();
if (!thread || thread->PassThroughEvents() || HasDivergedFromRecording()) {
Destroy(aNativeLock); // Clean up any old lock, as below.
return;
}
MOZ_RELEASE_ASSERT(!AreThreadEventsDisallowed());
Thread* thread = Thread::Current();
RecordReplayAssert("CreateLock");
MOZ_RELEASE_ASSERT(thread->CanAccessRecording());
thread->Events().RecordOrReplayThreadEvent(ThreadEvent::CreateLock);
@ -94,7 +92,7 @@ Lock::New(void* aNativeLock)
}
// Tolerate new locks being created with identical pointers, even if there
// was no DestroyLock call for the old one.
// was no explicit Destroy() call for the old one.
Destroy(aNativeLock);
AutoWriteSpinLock ex(gLocksLock);
@ -153,16 +151,13 @@ Lock::Find(void* aNativeLock)
void
Lock::Enter()
{
MOZ_RELEASE_ASSERT(!AreThreadEventsPassedThrough() && !HasDivergedFromRecording());
MOZ_RELEASE_ASSERT(!AreThreadEventsDisallowed());
RecordReplayAssert("Lock %d", (int) mId);
Thread* thread = Thread::Current();
MOZ_RELEASE_ASSERT(thread->CanAccessRecording());
// Include an event in each thread's record when a lock acquire begins. This
// is not required by the replay but is used to check that lock acquire order
// is consistent with the recording and that we will fail explicitly instead
// of deadlocking.
Thread* thread = Thread::Current();
thread->Events().RecordOrReplayThreadEvent(ThreadEvent::Lock);
thread->Events().CheckInput(mId);

Просмотреть файл

@ -10,7 +10,6 @@
#include "mozilla/Compression.h"
#include "mozilla/Maybe.h"
#include "mozilla/Sprintf.h"
#include "mozilla/StackWalk.h"
#include "mozilla/StaticMutex.h"
#include "DirtyMemoryHandler.h"
#include "Lock.h"
@ -45,8 +44,6 @@ const char* gSnapshotStackPrefix;
char* gInitializationFailureMessage;
static void DumpRecordingAssertions();
bool gInitialized;
ProcessKind gProcessKind;
char* gRecordingFilename;
@ -141,10 +138,6 @@ RecordReplayInterface_Initialize(int aArgc, char* aArgv[])
thread->BindToCurrent();
thread->SetPassThrough(true);
if (IsReplaying() && TestEnv("DUMP_RECORDING")) {
DumpRecordingAssertions();
}
InitializeTriggers();
InitializeWeakPointers();
InitializeMemorySnapshots();
@ -166,17 +159,13 @@ RecordReplayInterface_Initialize(int aArgc, char* aArgv[])
MOZ_EXPORT size_t
RecordReplayInterface_InternalRecordReplayValue(size_t aValue)
{
MOZ_ASSERT(IsRecordingOrReplaying());
if (AreThreadEventsPassedThrough()) {
Thread* thread = Thread::Current();
if (thread->PassThroughEvents()) {
return aValue;
}
EnsureNotDivergedFromRecording();
MOZ_RELEASE_ASSERT(!AreThreadEventsDisallowed());
Thread* thread = Thread::Current();
RecordReplayAssert("Value");
MOZ_RELEASE_ASSERT(thread->CanAccessRecording());
thread->Events().RecordOrReplayThreadEvent(ThreadEvent::Value);
thread->Events().RecordOrReplayValue(&aValue);
return aValue;
@ -185,17 +174,13 @@ RecordReplayInterface_InternalRecordReplayValue(size_t aValue)
MOZ_EXPORT void
RecordReplayInterface_InternalRecordReplayBytes(void* aData, size_t aSize)
{
MOZ_ASSERT(IsRecordingOrReplaying());
if (AreThreadEventsPassedThrough()) {
Thread* thread = Thread::Current();
if (thread->PassThroughEvents()) {
return;
}
EnsureNotDivergedFromRecording();
MOZ_RELEASE_ASSERT(!AreThreadEventsDisallowed());
Thread* thread = Thread::Current();
RecordReplayAssert("Bytes %d", (int) aSize);
MOZ_RELEASE_ASSERT(thread->CanAccessRecording());
thread->Events().RecordOrReplayThreadEvent(ThreadEvent::Bytes);
thread->Events().CheckInput(aSize);
thread->Events().RecordOrReplayBytes(aData, aSize);
@ -327,292 +312,57 @@ InternalPrint(const char* aFormat, va_list aArgs)
DirectPrint(buf2);
}
const char*
ThreadEventName(ThreadEvent aEvent)
{
switch (aEvent) {
#define EnumToString(Kind) case ThreadEvent::Kind: return #Kind;
ForEachThreadEvent(EnumToString)
#undef EnumToString
case ThreadEvent::CallStart: break;
}
size_t callId = (size_t) aEvent - (size_t) ThreadEvent::CallStart;
return gRedirections[callId].mName;
}
///////////////////////////////////////////////////////////////////////////////
// Record/Replay Assertions
///////////////////////////////////////////////////////////////////////////////
struct StackWalkData
{
char* mBuf;
size_t mSize;
StackWalkData(char* aBuf, size_t aSize)
: mBuf(aBuf), mSize(aSize)
{}
void append(const char* aText) {
size_t len = strlen(aText);
if (len <= mSize) {
strcpy(mBuf, aText);
mBuf += len;
mSize -= len;
}
}
};
static void
StackWalkCallback(uint32_t aFrameNumber, void* aPC, void* aSP, void* aClosure)
{
StackWalkData* data = (StackWalkData*) aClosure;
MozCodeAddressDetails details;
MozDescribeCodeAddress(aPC, &details);
data->append(" ### ");
data->append(details.function[0] ? details.function : "???");
}
static void
SetCurrentStackString(const char* aAssertion, char* aBuf, size_t aSize)
{
size_t frameCount = 12;
// Locking operations usually have extra stack goop.
if (!strcmp(aAssertion, "Lock 1")) {
frameCount += 8;
} else if (!strncmp(aAssertion, "Lock ", 5)) {
frameCount += 4;
}
StackWalkData data(aBuf, aSize);
MozStackWalk(StackWalkCallback, /* aSkipFrames = */ 2, frameCount, &data);
}
// For debugging.
char*
PrintCurrentStackString()
{
AutoEnsurePassThroughThreadEvents pt;
char* buf = new char[1000];
SetCurrentStackString("", buf, 1000);
return buf;
}
static inline bool
AlwaysCaptureEventStack(const char* aText)
{
return false;
}
// Bit included in assertion stream when the assertion is a text assert, rather
// than a byte sequence.
static const size_t AssertionBit = 1;
extern "C" {
MOZ_EXPORT void
RecordReplayInterface_InternalRecordReplayAssert(const char* aFormat, va_list aArgs)
{
#ifdef INCLUDE_RECORD_REPLAY_ASSERTIONS
if (AreThreadEventsPassedThrough() || HasDivergedFromRecording()) {
Thread* thread = Thread::Current();
if (thread->PassThroughEvents() || thread->HasDivergedFromRecording()) {
return;
}
MOZ_RELEASE_ASSERT(thread->CanAccessRecording());
MOZ_RELEASE_ASSERT(!AreThreadEventsDisallowed());
Thread* thread = Thread::Current();
// Record an assertion string consisting of the name of the assertion and
// stack information about the current point of execution.
// Add the asserted string to the recording.
char text[1024];
VsprintfLiteral(text, aFormat, aArgs);
if (IsRecording() && (thread->ShouldCaptureEventStacks() || AlwaysCaptureEventStack(text))) {
AutoPassThroughThreadEvents pt;
SetCurrentStackString(text, text + strlen(text), sizeof(text) - strlen(text));
}
size_t textLen = strlen(text);
if (IsRecording()) {
thread->Asserts().WriteScalar(thread->Events().StreamPosition());
if (thread->IsMainThread()) {
thread->Asserts().WriteScalar(*ExecutionProgressCounter());
}
thread->Asserts().WriteScalar((textLen << 1) | AssertionBit);
thread->Asserts().WriteBytes(text, textLen);
} else {
// While replaying, both the assertion's name and the current position in
// the thread's events need to match up with what was recorded. The stack
// portion of the assertion text does not need to match, it is used to help
// track down the reason for the mismatch.
bool match = true;
size_t streamPos = thread->Asserts().ReadScalar();
if (streamPos != thread->Events().StreamPosition()) {
match = false;
}
size_t progress = 0;
if (thread->IsMainThread()) {
progress = thread->Asserts().ReadScalar();
if (progress != *ExecutionProgressCounter()) {
match = false;
}
}
size_t assertLen = thread->Asserts().ReadScalar() >> 1;
char* buffer = thread->TakeBuffer(assertLen + 1);
thread->Asserts().ReadBytes(buffer, assertLen);
buffer[assertLen] = 0;
if (assertLen < textLen || memcmp(buffer, text, textLen) != 0) {
match = false;
}
if (!match) {
for (int i = Thread::NumRecentAsserts - 1; i >= 0; i--) {
if (thread->RecentAssert(i).mText) {
Print("Thread %d Recent %d: %s [%d]\n",
(int) thread->Id(), (int) i,
thread->RecentAssert(i).mText, (int) thread->RecentAssert(i).mPosition);
}
}
{
AutoPassThroughThreadEvents pt;
SetCurrentStackString(text, text + strlen(text), sizeof(text) - strlen(text));
}
child::ReportFatalError(Nothing(),
"Assertion Mismatch: Thread %d\n"
"Recorded: %s [%d,%d]\n"
"Replayed: %s [%d,%d]\n",
(int) thread->Id(), buffer, (int) streamPos, (int) progress, text,
(int) thread->Events().StreamPosition(),
(int) (thread->IsMainThread() ? *ExecutionProgressCounter() : 0));
Unreachable();
}
thread->RestoreBuffer(buffer);
// Push this assert onto the recent assertions in the thread.
free(thread->RecentAssert(Thread::NumRecentAsserts - 1).mText);
for (size_t i = Thread::NumRecentAsserts - 1; i >= 1; i--) {
thread->RecentAssert(i) = thread->RecentAssert(i - 1);
}
thread->RecentAssert(0).mText = strdup(text);
thread->RecentAssert(0).mPosition = thread->Events().StreamPosition();
}
#endif // INCLUDE_RECORD_REPLAY_ASSERTIONS
thread->Events().RecordOrReplayThreadEvent(ThreadEvent::Assert);
thread->Events().CheckInput(text);
}
MOZ_EXPORT void
RecordReplayInterface_InternalRecordReplayAssertBytes(const void* aData, size_t aSize)
{
#ifdef INCLUDE_RECORD_REPLAY_ASSERTIONS
RecordReplayAssert("AssertBytes");
if (AreThreadEventsPassedThrough() || HasDivergedFromRecording()) {
Thread* thread = Thread::Current();
if (thread->PassThroughEvents() || thread->HasDivergedFromRecording()) {
return;
}
MOZ_RELEASE_ASSERT(thread->CanAccessRecording());
MOZ_ASSERT(!AreThreadEventsDisallowed());
Thread* thread = Thread::Current();
if (IsRecording()) {
thread->Asserts().WriteScalar(thread->Events().StreamPosition());
thread->Asserts().WriteScalar(aSize << 1);
thread->Asserts().WriteBytes(aData, aSize);
} else {
bool match = true;
size_t streamPos = thread->Asserts().ReadScalar();
if (streamPos != thread->Events().StreamPosition()) {
match = false;
}
size_t oldSize = thread->Asserts().ReadScalar() >> 1;
if (oldSize != aSize) {
match = false;
}
char* buffer = thread->TakeBuffer(oldSize);
thread->Asserts().ReadBytes(buffer, oldSize);
if (match && memcmp(buffer, aData, oldSize) != 0) {
match = false;
}
if (!match) {
// On a byte mismatch, print out some of the mismatched bytes, up to a
// cutoff in case there are many mismatched bytes.
if (oldSize == aSize) {
static const size_t MAX_MISMATCHES = 100;
size_t mismatches = 0;
for (size_t i = 0; i < aSize; i++) {
if (((char*)aData)[i] != buffer[i]) {
Print("Position %d: %d %d\n", (int) i, (int) buffer[i], (int) ((char*)aData)[i]);
if (++mismatches == MAX_MISMATCHES) {
break;
}
}
}
if (mismatches == MAX_MISMATCHES) {
Print("Position ...\n");
}
}
child::ReportFatalError(Nothing(),
"Byte Comparison Check Failed: Position %d %d Length %d %d\n",
(int) streamPos, (int) thread->Events().StreamPosition(),
(int) oldSize, (int) aSize);
Unreachable();
}
thread->RestoreBuffer(buffer);
}
#endif // INCLUDE_RECORD_REPLAY_ASSERTIONS
}
MOZ_EXPORT void
RecordReplayRust_Assert(const uint8_t* aBuffer)
{
RecordReplayAssert("%s", (const char*) aBuffer);
}
MOZ_EXPORT void
RecordReplayRust_BeginPassThroughThreadEvents()
{
BeginPassThroughThreadEvents();
}
MOZ_EXPORT void
RecordReplayRust_EndPassThroughThreadEvents()
{
EndPassThroughThreadEvents();
thread->Events().RecordOrReplayThreadEvent(ThreadEvent::AssertBytes);
thread->Events().CheckInput(aData, aSize);
}
} // extern "C"
static void
DumpRecordingAssertions()
{
Thread* thread = Thread::Current();
for (size_t id = MainThreadId; id <= MaxRecordedThreadId; id++) {
Stream* asserts = gRecordingFile->OpenStream(StreamName::Assert, id);
if (asserts->AtEnd()) {
continue;
}
fprintf(stderr, "Thread Assertions %d:\n", (int) id);
while (!asserts->AtEnd()) {
(void) asserts->ReadScalar();
size_t shiftedLen = asserts->ReadScalar();
size_t assertLen = shiftedLen >> 1;
char* buffer = thread->TakeBuffer(assertLen + 1);
asserts->ReadBytes(buffer, assertLen);
buffer[assertLen] = 0;
if (shiftedLen & AssertionBit) {
fprintf(stderr, "%s\n", buffer);
}
thread->RestoreBuffer(buffer);
}
}
fprintf(stderr, "Done with assertions, exiting...\n");
_exit(0);
}
static ValueIndex* gGenericThings;
static StaticMutexNotRecorded gGenericThingsMutex;

Просмотреть файл

@ -24,52 +24,61 @@ namespace recordreplay {
// process. The ipc subdirectory contains files used for IPC between a
// replaying and middleman process, and between a middleman and chrome process.
// Instantiate _Macro for each of the platform independent thread events.
#define ForEachThreadEvent(_Macro) \
/* Spawned another thread. */ \
_Macro(CreateThread) \
\
/* Created a recorded lock. */ \
_Macro(CreateLock) \
\
/* Acquired a recorded lock. */ \
_Macro(Lock) \
\
/* Called RecordReplayValue. */ \
_Macro(Value) \
\
/* Called RecordReplayBytes. */ \
_Macro(Bytes) \
\
/* Called RecordReplayAssert or RecordReplayAssertBytes. */ \
_Macro(Assert) \
_Macro(AssertBytes) \
\
/* Executed a nested callback (see Callback.h). */ \
_Macro(ExecuteCallback) \
\
/* Finished executing nested callbacks in a library API (see Callback.h). */ \
_Macro(CallbacksFinished) \
\
/* Restoring a data pointer used in a callback (see Callback.h). */ \
_Macro(RestoreCallbackData) \
\
/* Called RegisterTrigger. */ \
_Macro(RegisterTrigger) \
\
/* Executed a trigger within a call to ExecuteTriggers. */ \
_Macro(ExecuteTrigger) \
\
/* Finished executing triggers within a call to ExecuteTriggers. */ \
_Macro(ExecuteTriggersFinished)
// ID of an event in a thread's event stream. Each ID in the stream is followed
// by data associated with the event (see File::RecordOrReplayThreadEvent).
// by data associated with the event.
enum class ThreadEvent : uint32_t
{
// Spawned another thread.
CreateThread,
// Created a recorded lock.
CreateLock,
// Acquired a recorded lock.
Lock,
// Wait for a condition variable with a timeout.
WaitForCvarUntil,
// Called RecordReplayValue.
Value,
// Called RecordReplayBytes.
Bytes,
// Executed a nested callback (see Callback.h).
ExecuteCallback,
// Finished executing nested callbacks in a library API (see Callback.h).
CallbacksFinished,
// Restoring a data pointer used in a callback (see Callback.h).
RestoreCallbackData,
// Executed a trigger within a call to ExecuteTriggers.
ExecuteTrigger,
// Finished executing triggers within a call to ExecuteTriggers.
ExecuteTriggersFinished,
// Encoded information about an argument/rval used by a graphics call.
GraphicsArgument,
GraphicsRval,
#define DefineEnum(Kind) Kind,
ForEachThreadEvent(DefineEnum)
#undef DefineEnum
// The start of event IDs for redirected call events. Event IDs after this
// point are platform specific.
CallStart
};
// Get the printable name for a thread event.
const char* ThreadEventName(ThreadEvent aEvent);
class File;
// File used during recording and replay.
@ -81,11 +90,6 @@ extern bool gInitialized;
// If we failed to initialize, any associated message.
extern char* gInitializationFailureMessage;
// Whether record/replay assertions should be performed.
//#ifdef DEBUG
#define INCLUDE_RECORD_REPLAY_ASSERTIONS 1
//#endif
// Flush any new recording data to disk.
void FlushRecording();

Просмотреть файл

@ -137,6 +137,12 @@ OriginalFunction(size_t aCallId)
#define OriginalCall(aName, aReturnType, ...) \
OriginalCallABI(aName, aReturnType, DEFAULTABI, ##__VA_ARGS__)
static inline ThreadEvent
CallIdToThreadEvent(size_t aCallId)
{
return (ThreadEvent)((uint32_t)ThreadEvent::CallStart + aCallId);
}
// State for a function redirection which performs the standard steps (see the
// comment at the start of this file). This should not be created directly, but
// rather through one of the macros below.
@ -151,19 +157,19 @@ struct AutoRecordReplayFunctionVoid
protected:
// Information about the call being recorded.
size_t mCallId;
const char* mCallName;
public:
AutoRecordReplayFunctionVoid(size_t aCallId, const char* aCallName)
: mThread(AreThreadEventsPassedThrough() ? nullptr : Thread::Current()),
mError(0), mCallId(aCallId), mCallName(aCallName)
explicit AutoRecordReplayFunctionVoid(size_t aCallId)
: mThread(Thread::Current()), mError(0), mCallId(aCallId)
{
if (mThread) {
if (mThread && mThread->PassThroughEvents()) {
mThread = nullptr;
} else if (mThread) {
// Calling any redirection which performs the standard steps will cause
// debugger operations that have diverged from the recording to fail.
EnsureNotDivergedFromRecording();
MOZ_ASSERT(!AreThreadEventsDisallowed());
MOZ_RELEASE_ASSERT(mThread->CanAccessRecording());
// Pass through events in case we are calling the original function.
mThread->SetPassThrough(true);
@ -190,9 +196,7 @@ public:
mThread->SetPassThrough(false);
// Add an event for the thread.
RecordReplayAssert("%s", mCallName);
ThreadEvent ev = (ThreadEvent)((uint32_t)ThreadEvent::CallStart + mCallId);
mThread->Events().RecordOrReplayThreadEvent(ev);
mThread->Events().RecordOrReplayThreadEvent(CallIdToThreadEvent(mCallId));
}
};
@ -204,8 +208,8 @@ struct AutoRecordReplayFunction : AutoRecordReplayFunctionVoid
// The value which this function call should return.
ReturnType mRval;
AutoRecordReplayFunction(size_t aCallId, const char* aCallName)
: AutoRecordReplayFunctionVoid(aCallId, aCallName)
explicit AutoRecordReplayFunction(size_t aCallId)
: AutoRecordReplayFunctionVoid(aCallId)
{}
};
@ -221,7 +225,7 @@ struct AutoRecordReplayFunction : AutoRecordReplayFunctionVoid
// Record/replay a function that returns a value and has a particular ABI.
#define RecordReplayFunctionABI(aName, aReturnType, aABI, ...) \
AutoRecordReplayFunction<aReturnType> rrf(CallEvent_ ##aName, #aName); \
AutoRecordReplayFunction<aReturnType> rrf(CallEvent_ ##aName); \
if (!rrf.mThread) { \
return OriginalCallABI(aName, aReturnType, aABI, ##__VA_ARGS__); \
} \
@ -239,7 +243,7 @@ struct AutoRecordReplayFunction : AutoRecordReplayFunctionVoid
// Record/replay a function that has no return value and has a particular ABI.
#define RecordReplayFunctionVoidABI(aName, aABI, ...) \
AutoRecordReplayFunctionVoid rrf(CallEvent_ ##aName, #aName); \
AutoRecordReplayFunctionVoid rrf(CallEvent_ ##aName); \
if (!rrf.mThread) { \
OriginalCallABI(aName, void, aABI, ##__VA_ARGS__); \
return; \

Просмотреть файл

@ -664,8 +664,6 @@ RR_mmap(void* aAddress, size_t aSize, int aProt, int aFlags, int aFd, off_t aOff
if (!(aFlags & MAP_ANON) && !AreThreadEventsPassedThrough()) {
// Include the data just mapped in the recording.
MOZ_RELEASE_ASSERT(memory && memory != (void*)-1);
RecordReplayAssert("mmap");
MOZ_RELEASE_ASSERT(aSize == RecordReplayValue(aSize));
RecordReplayBytes(memory, aSize);
}
@ -1177,7 +1175,6 @@ WaitForCvar(pthread_mutex_t* aMutex, bool aRecordReturnValue,
AutoEnsurePassThroughThreadEvents pt;
return aCallback();
}
RecordReplayAssert("WaitForCvar %d", (int) lock->Id());
ssize_t rv = 0;
if (IsRecording()) {
AutoPassThroughThreadEvents pt;
@ -1734,13 +1731,15 @@ extern "C" {
size_t __attribute__((used))
RecordReplayInterceptObjCMessage(MessageArguments* aArguments)
{
if (AreThreadEventsPassedThrough()) {
Thread* thread = Thread::Current();
if (!thread || thread->PassThroughEvents()) {
aArguments->scratch = (size_t) OriginalFunction(CallEvent_objc_msgSend);
return 1;
}
EnsureNotDivergedFromRecording();
RecordReplayAssert("objc_msgSend: %s", aArguments->msg);
thread->Events().RecordOrReplayThreadEvent(CallIdToThreadEvent(CallEvent_objc_msgSend));
thread->Events().CheckInput(aArguments->msg);
size_t rval = 0;
double floatRval = 0;

Просмотреть файл

@ -183,15 +183,17 @@ NewCheckpoint(bool aTemporary)
return reachedCheckpoint;
}
static bool gRecordingDiverged;
static bool gUnhandledDivergeAllowed;
void
DivergeFromRecording()
{
MOZ_RELEASE_ASSERT(Thread::CurrentIsMainThread());
MOZ_RELEASE_ASSERT(IsReplaying());
gRecordingDiverged = true;
Thread* thread = Thread::Current();
MOZ_RELEASE_ASSERT(thread->IsMainThread());
thread->DivergeFromRecording();
gUnhandledDivergeAllowed = true;
}
@ -200,7 +202,8 @@ extern "C" {
MOZ_EXPORT bool
RecordReplayInterface_InternalHasDivergedFromRecording()
{
return Thread::CurrentIsMainThread() && gRecordingDiverged;
Thread* thread = Thread::Current();
return thread && thread->HasDivergedFromRecording();
}
} // extern "C"
@ -250,7 +253,7 @@ PauseMainThreadAndServiceCallbacks()
{
MOZ_RELEASE_ASSERT(Thread::CurrentIsMainThread());
MOZ_RELEASE_ASSERT(!AreThreadEventsPassedThrough());
MOZ_RELEASE_ASSERT(!gRecordingDiverged);
MOZ_RELEASE_ASSERT(!HasDivergedFromRecording());
// Whether there is a PauseMainThreadAndServiceCallbacks frame on the stack.
static bool gMainThreadIsPaused = false;
@ -283,7 +286,7 @@ PauseMainThreadAndServiceCallbacks()
// If we diverge from the recording the only way we can get back to resuming
// normal execution is to rewind to a checkpoint prior to the divergence.
MOZ_RELEASE_ASSERT(!gRecordingDiverged);
MOZ_RELEASE_ASSERT(!HasDivergedFromRecording());
gMainThreadIsPaused = false;
}

Просмотреть файл

@ -125,7 +125,6 @@ Thread::InitializeThreads()
if (i <= MaxRecordedThreadId) {
thread->mEvents = gRecordingFile->OpenStream(StreamName::Event, i);
thread->mAsserts = gRecordingFile->OpenStream(StreamName::Assert, i);
}
DirectCreatePipe(&thread->mNotifyfd, &thread->mIdlefd);
@ -235,14 +234,10 @@ Thread::SpawnThread(Thread* aThread)
/* static */ NativeThreadId
Thread::StartThread(Callback aStart, void* aArgument, bool aNeedsJoin)
{
MOZ_ASSERT(IsRecordingOrReplaying());
MOZ_ASSERT(!AreThreadEventsPassedThrough());
MOZ_ASSERT(!AreThreadEventsDisallowed());
EnsureNotDivergedFromRecording();
Thread* thread = Thread::Current();
RecordReplayAssert("StartThread");
Thread* thread = Thread::Current();
MOZ_RELEASE_ASSERT(thread->CanAccessRecording());
MonitorAutoLock lock(*gMonitor);
@ -300,33 +295,6 @@ Thread::Join()
}
}
///////////////////////////////////////////////////////////////////////////////
// Thread Buffers
///////////////////////////////////////////////////////////////////////////////
char*
Thread::TakeBuffer(size_t aSize)
{
MOZ_ASSERT(mBuffer != (char*) 0x1);
if (aSize > mBufferCapacity) {
mBufferCapacity = aSize;
mBuffer = (char*) realloc(mBuffer, aSize);
}
char* buf = mBuffer;
// Poison the buffer in case this thread tries to use it again reentrantly.
mBuffer = (char*) 0x1;
return buf;
}
void
Thread::RestoreBuffer(char* aBuf)
{
MOZ_ASSERT(mBuffer == (char*) 0x1);
mBuffer = aBuf;
}
///////////////////////////////////////////////////////////////////////////////
// Thread Public API Accessors
///////////////////////////////////////////////////////////////////////////////
@ -381,20 +349,6 @@ RecordReplayInterface_InternalAreThreadEventsDisallowed()
return thread && thread->AreEventsDisallowed();
}
MOZ_EXPORT void
RecordReplayInterface_InternalBeginCaptureEventStacks()
{
MOZ_ASSERT(IsRecordingOrReplaying());
Thread::Current()->BeginCaptureEventStacks();
}
MOZ_EXPORT void
RecordReplayInterface_InternalEndCaptureEventStacks()
{
MOZ_ASSERT(IsRecordingOrReplaying());
Thread::Current()->EndCaptureEventStacks();
}
} // extern "C"
///////////////////////////////////////////////////////////////////////////////

Просмотреть файл

@ -78,14 +78,6 @@ public:
// Signature for the start function of a thread.
typedef void (*Callback)(void*);
// Number of recent assertions remembered.
static const size_t NumRecentAsserts = 128;
struct RecentAssertInfo {
char* mText;
size_t mPosition;
};
private:
// Monitor used to protect various thread information (see Thread.h) and to
// wait on or signal progress for a thread.
@ -102,9 +94,9 @@ private:
// used by the associated thread.
size_t mDisallowEvents;
// Whether to capture stack information for events while recording. This is
// only used by the associated thread.
size_t mCaptureEventStacks;
// Whether execution has diverged from the recording and the thread's
// recorded events cannot be accessed.
bool mDivergedFromRecording;
// Start routine and argument which the thread is currently executing. This
// is cleared after the routine finishes and another start routine may be
@ -118,17 +110,8 @@ private:
// ID for this thread used by the system.
NativeThreadId mNativeId;
// Streams with events and assertions for the thread. These are only used by
// the associated thread.
// Stream with events for the thread. This is only used on the thread itself.
Stream* mEvents;
Stream* mAsserts;
// Recent assertions that have been encountered, for debugging.
RecentAssertInfo mRecentAsserts[NumRecentAsserts];
// Buffer for general use. This is only used by the associated thread.
char* mBuffer;
size_t mBufferCapacity;
// Stack boundary of the thread, protected by the thread monitor.
uint8_t* mStackBase;
@ -158,20 +141,19 @@ public:
size_t Id() { return mId; }
NativeThreadId NativeId() { return mNativeId; }
Stream& Events() { return *mEvents; }
Stream& Asserts() { return *mAsserts; }
uint8_t* StackBase() { return mStackBase; }
size_t StackSize() { return mStackSize; }
inline bool IsMainThread() { return mId == MainThreadId; }
inline bool IsRecordedThread() { return mId <= MaxRecordedThreadId; }
inline bool IsNonMainRecordedThread() { return IsRecordedThread() && !IsMainThread(); }
inline bool IsMainThread() const { return mId == MainThreadId; }
inline bool IsRecordedThread() const { return mId <= MaxRecordedThreadId; }
inline bool IsNonMainRecordedThread() const { return IsRecordedThread() && !IsMainThread(); }
// Access the flag for whether this thread is passing events through.
void SetPassThrough(bool aPassThrough) {
MOZ_RELEASE_ASSERT(mPassThroughEvents == !aPassThrough);
mPassThroughEvents = aPassThrough;
}
bool PassThroughEvents() {
bool PassThroughEvents() const {
return mPassThroughEvents;
}
@ -183,33 +165,25 @@ public:
MOZ_RELEASE_ASSERT(mDisallowEvents);
mDisallowEvents--;
}
bool AreEventsDisallowed() {
bool AreEventsDisallowed() const {
return mDisallowEvents != 0;
}
// Access the counter for whether event stacks are captured while recording.
void BeginCaptureEventStacks() {
mCaptureEventStacks++;
// Access the flag for whether this thread's execution has diverged from the
// recording. Once set, this is only unset by rewinding to a point where the
// flag is clear.
void DivergeFromRecording() {
mDivergedFromRecording = true;
}
void EndCaptureEventStacks() {
MOZ_RELEASE_ASSERT(mCaptureEventStacks);
mCaptureEventStacks--;
}
bool ShouldCaptureEventStacks() {
return mCaptureEventStacks != 0;
bool HasDivergedFromRecording() const {
return mDivergedFromRecording;
}
// Access the array of recent assertions in the thread.
RecentAssertInfo& RecentAssert(size_t i) {
MOZ_ASSERT(i < NumRecentAsserts);
return mRecentAsserts[i];
// Return whether this thread may read or write to its recorded event stream.
bool CanAccessRecording() const {
return !PassThroughEvents() && !AreEventsDisallowed() && !HasDivergedFromRecording();
}
// Access a thread local buffer of a guaranteed size. The buffer must be
// restored before it can be taken again.
char* TakeBuffer(size_t aSize);
void RestoreBuffer(char* aBuf);
// The actual start routine at the root of all recorded threads, and of all
// threads when replaying.
static void ThreadMain(void* aArgument);

Просмотреть файл

@ -58,17 +58,13 @@ extern "C" {
MOZ_EXPORT void
RecordReplayInterface_RegisterTrigger(void* aObj, const std::function<void()>& aCallback)
{
MOZ_ASSERT(IsRecordingOrReplaying());
MOZ_RELEASE_ASSERT(!AreThreadEventsPassedThrough());
MOZ_RELEASE_ASSERT(aObj);
if (HasDivergedFromRecording()) {
Thread* thread = Thread::Current();
if (thread->HasDivergedFromRecording()) {
return;
}
MOZ_RELEASE_ASSERT(!AreThreadEventsDisallowed());
size_t threadId = Thread::Current()->Id();
MOZ_RELEASE_ASSERT(thread->CanAccessRecording());
size_t id;
{
@ -78,17 +74,18 @@ RecordReplayInterface_RegisterTrigger(void* aObj, const std::function<void()>& a
TriggerInfoMap::iterator iter = gTriggerInfoMap->find(aObj);
if (iter != gTriggerInfoMap->end()) {
id = gTriggers->GetIndex(aObj);
MOZ_RELEASE_ASSERT(iter->second.mThreadId == threadId);
MOZ_RELEASE_ASSERT(iter->second.mThreadId == thread->Id());
iter->second.mCallback = aCallback;
iter->second.mRegisterCount++;
} else {
id = gTriggers->Insert(aObj);
TriggerInfo info(threadId, aCallback);
TriggerInfo info(thread->Id(), aCallback);
gTriggerInfoMap->insert(TriggerInfoMap::value_type(aObj, info));
}
}
RecordReplayAssert("RegisterTrigger %zu", id);
thread->Events().RecordOrReplayThreadEvent(ThreadEvent::RegisterTrigger);
thread->Events().CheckInput(id);
}
MOZ_EXPORT void
@ -159,13 +156,8 @@ RemoveTriggerCallbackForThreadId(size_t aThreadId)
MOZ_EXPORT void
RecordReplayInterface_ExecuteTriggers()
{
MOZ_ASSERT(IsRecordingOrReplaying());
MOZ_RELEASE_ASSERT(!AreThreadEventsPassedThrough());
MOZ_RELEASE_ASSERT(!AreThreadEventsDisallowed());
Thread* thread = Thread::Current();
RecordReplayAssert("ExecuteTriggers");
MOZ_RELEASE_ASSERT(thread->CanAccessRecording());
if (IsRecording()) {
// Invoke the callbacks for any triggers waiting for execution, including
@ -176,11 +168,11 @@ RecordReplayInterface_ExecuteTriggers()
break;
}
thread->Events().RecordOrReplayThreadEvent(ThreadEvent::ExecuteTrigger);
thread->Events().WriteScalar((size_t) ThreadEvent::ExecuteTrigger);
thread->Events().WriteScalar(id.ref());
InvokeTriggerCallback(id.ref());
}
thread->Events().RecordOrReplayThreadEvent(ThreadEvent::ExecuteTriggersFinished);
thread->Events().WriteScalar((size_t) ThreadEvent::ExecuteTriggersFinished);
} else {
// Execute the same callbacks which were executed at this point while
// recording.
@ -197,8 +189,6 @@ RecordReplayInterface_ExecuteTriggers()
InvokeTriggerCallback(id);
}
}
RecordReplayAssert("ExecuteTriggers DONE");
}
} // extern "C"

Просмотреть файл

@ -18,6 +18,7 @@
#include "mozilla/dom/ContentChild.h"
#include "mozilla/layers/ImageDataSerializer.h"
#include "mozilla/Sprintf.h"
#include "mozilla/StackWalk.h"
#include "mozilla/VsyncDispatcher.h"
#include "InfallibleVector.h"
@ -326,6 +327,46 @@ MaybeCreateInitialCheckpoint()
NewCheckpoint(/* aTemporary = */ false);
}
struct StackWalkData
{
// Current buffer and allocated size, which may be internal to the original
// allocation.
char* mBuf;
size_t mSize;
StackWalkData(char* aBuf, size_t aSize)
: mBuf(aBuf), mSize(aSize)
{}
void append(const char* aText) {
size_t len = strlen(aText);
if (len <= mSize) {
memcpy(mBuf, aText, len);
mBuf += len;
mSize -= len;
}
}
};
static void
StackWalkCallback(uint32_t aFrameNumber, void* aPC, void* aSP, void* aClosure)
{
StackWalkData* data = (StackWalkData*) aClosure;
MozCodeAddressDetails details;
MozDescribeCodeAddress(aPC, &details);
data->append(" ### ");
data->append(details.function[0] ? details.function : "???");
}
static void
SetCurrentStackString(const char* aAssertion, char* aBuf, size_t aSize)
{
StackWalkData data(aBuf, aSize);
MozStackWalk(StackWalkCallback, /* aSkipFrames = */ 2, /* aFrameCount = */ 32, &data);
}
void
ReportFatalError(const Maybe<MinidumpInfo>& aMinidump, const char* aFormat, ...)
{
@ -348,6 +389,13 @@ ReportFatalError(const Maybe<MinidumpInfo>& aMinidump, const char* aFormat, ...)
VsprintfLiteral(buf, aFormat, ap);
va_end(ap);
// Include stack information in the error message as well, if we are on the
// thread where the fatal error occurred.
if (aMinidump.isNothing()) {
size_t len = strlen(buf);
SetCurrentStackString(buf, buf + len, sizeof(buf) - len);
}
// Construct a FatalErrorMessage on the stack, to avoid touching the heap.
char msgBuf[4096];
size_t header = sizeof(FatalErrorMessage);

Просмотреть файл

@ -147,6 +147,15 @@ struct MOZ_RAII AutoMarkMainThreadWaitingForIPDLReply
}
};
static void
BeginShutdown()
{
// If there is a channel error or anything that could result from the child
// crashing, cleanly shutdown this process so that we don't generate a
// separate minidump which masks the initial failure.
MainThreadMessageLoop()->PostTask(NewRunnableFunction("Shutdown", Shutdown));
}
class MiddlemanProtocol : public ipc::IToplevelProtocol
{
public:
@ -172,7 +181,8 @@ public:
IPC::StringFromIPCMessageType(aMessage->type()),
(int) aMessage->routing_id());
if (!aProtocol->GetIPCChannel()->Send(aMessage)) {
MOZ_CRASH("MiddlemanProtocol::ForwardMessageAsync");
MOZ_RELEASE_ASSERT(aProtocol->mSide == ipc::ParentSide);
BeginShutdown();
}
} else {
delete aMessage;
@ -209,7 +219,8 @@ public:
MOZ_RELEASE_ASSERT(!*aReply);
Message* nReply = new Message();
if (!aProtocol->GetIPCChannel()->Send(aMessage, nReply)) {
MOZ_CRASH("MiddlemanProtocol::ForwardMessageSync");
MOZ_RELEASE_ASSERT(aProtocol->mSide == ipc::ParentSide);
BeginShutdown();
}
MonitorAutoLock lock(*gMonitor);
@ -245,7 +256,8 @@ public:
MOZ_RELEASE_ASSERT(!*aReply);
Message* nReply = new Message();
if (!aProtocol->GetIPCChannel()->Call(aMessage, nReply)) {
MOZ_CRASH("MiddlemanProtocol::ForwardCallMessage");
MOZ_RELEASE_ASSERT(aProtocol->mSide == ipc::ParentSide);
BeginShutdown();
}
MonitorAutoLock lock(*gMonitor);
@ -281,11 +293,11 @@ public:
virtual void OnChannelClose() override {
MOZ_RELEASE_ASSERT(mSide == ipc::ChildSide);
MainThreadMessageLoop()->PostTask(NewRunnableFunction("Shutdown", Shutdown));
BeginShutdown();
}
virtual void OnChannelError() override {
MainThreadMessageLoop()->PostTask(NewRunnableFunction("Shutdown", Shutdown));
BeginShutdown();
}
};

Просмотреть файл

@ -878,6 +878,8 @@ InitializeMiddleman(int aArgc, char* aArgv[], base::ProcessId aParentPid,
{
MOZ_RELEASE_ASSERT(NS_IsMainThread());
CrashReporter::AnnotateCrashReport(CrashReporter::Annotation::RecordReplay, true);
gParentPid = aParentPid;
// Construct the message that will be sent to each child when starting up.