Merge inbound to central, a=merge

This commit is contained in:
Wes Kocher 2015-10-15 11:17:56 -07:00
Родитель 2a09224700 f20ce8a104
Коммит ac656a7d21
75 изменённых файлов: 1214 добавлений и 638 удалений

12
.gitignore поставляемый
Просмотреть файл

@ -74,3 +74,15 @@ mobile/android/gradle/.gradle
# Ignore node_modules from eslint-plugin-mozilla
testing/eslint-plugin-mozilla/node_modules/
# Ignore talos virtualenv and tp5n files.
# The tp5n set is supposed to be decompressed at
# testing/talos/talos/page_load_test/tp5n in order to run tests like tps
# locally. Similarly, running talos requires a Python package virtual
# environment. Both the virtual environment and tp5n files end up littering
# the status command, so we ignore them.
testing/talos/.Python
testing/talos/bin/
testing/talos/include/
testing/talos/lib/
testing/talos/talos/page_load_test/tp5n/

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

@ -96,3 +96,15 @@ GPATH
# Ignore node_modules from eslint-plugin-mozilla
^testing/eslint-plugin-mozilla/node_modules/
# Ignore talos virtualenv and tp5n files.
# The tp5n set is supposed to be decompressed at
# testing/talos/talos/page_load_test/tp5n in order to run tests like tps
# locally. Similarly, running talos requires a Python package virtual
# environment. Both the virtual environment and tp5n files end up littering
# the status command, so we ignore them.
^testing/talos/.Python
^testing/talos/bin/
^testing/talos/include/
^testing/talos/lib/
^testing/talos/talos/page_load_test/tp5n/

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

@ -10,6 +10,7 @@
border-radius: 2px;
box-shadow: 1px 1px 1px #444;
display: none;
z-index: 10;
}
#virtual-cursor-box.show {

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

@ -522,7 +522,9 @@ var Output = {
stop: function stop() {
if (this.highlightBox) {
Utils.win.document.documentElement.removeChild(this.highlightBox.get());
let doc = Utils.win.document;
(doc.body || doc.documentElement).documentElement.removeChild(
this.highlightBox.get());
delete this.highlightBox;
}
},
@ -538,16 +540,17 @@ var Output = {
{
let highlightBox = null;
if (!this.highlightBox) {
let doc = Utils.win.document;
// Add highlight box
highlightBox = Utils.win.document.
createElementNS('http://www.w3.org/1999/xhtml', 'div');
Utils.win.document.documentElement.appendChild(highlightBox);
let parent = doc.body || doc.documentElement;
parent.appendChild(highlightBox);
highlightBox.id = 'virtual-cursor-box';
// Add highlight inset for inner shadow
highlightBox.appendChild(
Utils.win.document.createElementNS(
'http://www.w3.org/1999/xhtml', 'div'));
doc.createElementNS('http://www.w3.org/1999/xhtml', 'div'));
this.highlightBox = Cu.getWeakReference(highlightBox);
} else {

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

@ -20,11 +20,11 @@ MOZ_ARG_WITH_STRING(android-gnu-compiler-version,
gnu compiler version to use],
android_gnu_compiler_version=$withval)
MOZ_ARG_ENABLE_BOOL(android-libstdcxx,
[ --enable-android-libstdcxx
use GNU libstdc++ instead of STLPort],
MOZ_ANDROID_LIBSTDCXX=1,
MOZ_ANDROID_LIBSTDCXX= )
MOZ_ARG_WITH_STRING(android-cxx-stl,
[ --with-android-cxx-stl=VALUE
use the specified C++ STL (stlport, libstdc++, libc++)],
android_cxx_stl=$withval,
android_cxx_stl=mozstlport)
define([MIN_ANDROID_VERSION], [9])
android_version=MIN_ANDROID_VERSION
@ -210,26 +210,60 @@ if test "$OS_TARGET" = "Android" -a -z "$gonkdir"; then
AC_SUBST(ANDROID_CPU_ARCH)
cpu_arch_dir="$ANDROID_CPU_ARCH"
if test "$MOZ_THUMB2" = 1; then
cpu_arch_dir="$cpu_arch_dir/thumb"
fi
if test -z "$STLPORT_CPPFLAGS$STLPORT_LIBS"; then
if test -n "$MOZ_ANDROID_LIBSTDCXX" ; then
case "$android_cxx_stl" in
libstdc++)
# android-ndk-r8b and later
ndk_base="$android_ndk/sources/cxx-stl/gnu-libstdc++/$android_gnu_compiler_version"
ndk_libs="$ndk_base/libs/$ANDROID_CPU_ARCH"
ndk_libs_include="$ndk_base/libs/$ANDROID_CPU_ARCH"
ndk_libs="$ndk_base/libs/$cpu_arch_dir"
ndk_include="$ndk_base/include"
if test -e "$ndk_libs/libgnustl_static.a"; then
STLPORT_LIBS="-L$ndk_libs -lgnustl_static"
STLPORT_CPPFLAGS="-I$ndk_include -I$ndk_include/backward -I$ndk_libs/include"
else
if ! test -e "$ndk_libs/libgnustl_static.a"; then
AC_MSG_ERROR([Couldn't find path to gnu-libstdc++ in the android ndk])
fi
else
STLPORT_LIBS="-L$ndk_libs -lgnustl_static"
STLPORT_CPPFLAGS="-I$ndk_include -I$ndk_include/backward -I$ndk_libs_include/include"
;;
libc++)
# android-ndk-r8b and later
ndk_base="$android_ndk/sources/cxx-stl"
cxx_base="$ndk_base/llvm-libc++"
cxx_libs="$cxx_base/libs/$cpu_arch_dir"
cxx_include="$cxx_base/libcxx/include"
cxxabi_base="$ndk_base/llvm-libc++abi"
cxxabi_include="$cxxabi_base/libcxxabi/include"
if ! test -e "$cxx_libs/libc++_static.a"; then
AC_MSG_ERROR([Couldn't find path to llvm-libc++ in the android ndk])
fi
STLPORT_LIBS="-L$cxx_libs -lc++_static"
# Add android/support/include/ for prototyping long double math
# functions, locale-specific C library functions, multibyte support,
# etc.
STLPORT_CPPFLAGS="-I$android_ndk/sources/android/support/include -I$cxx_include -I$cxxabi_include"
;;
mozstlport)
# We don't need to set STLPORT_LIBS, because the build system will
# take care of linking in our home-built stlport where it is needed.
STLPORT_CPPFLAGS="-isystem $_topsrcdir/build/stlport/stlport -isystem $_topsrcdir/build/stlport/overrides -isystem $android_ndk/sources/cxx-stl/system/include"
fi
;;
*)
AC_MSG_ERROR([Bad value for --enable-android-cxx-stl])
;;
esac
fi
CXXFLAGS="$CXXFLAGS $STLPORT_CPPFLAGS"
fi
AC_SUBST([MOZ_ANDROID_LIBSTDCXX])
MOZ_ANDROID_CXX_STL=$android_cxx_stl
AC_SUBST([MOZ_ANDROID_CXX_STL])
AC_SUBST([STLPORT_LIBS])
])

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

@ -279,6 +279,8 @@ public:
CustomTypeAnnotation(const char *Spelling, const char *Pretty)
: Spelling(Spelling), Pretty(Pretty){};
virtual ~CustomTypeAnnotation() {}
// Checks if this custom annotation "effectively affects" the given type.
bool hasEffectiveAnnotation(QualType T) {
return directAnnotationReason(T).valid();
@ -299,6 +301,10 @@ public:
private:
bool hasLiteralAnnotation(QualType T) const;
AnnotationReason directAnnotationReason(QualType T);
protected:
// Allow subclasses to apply annotations to external code:
virtual bool hasFakeAnnotation(const TagDecl *D) const { return false; }
};
static CustomTypeAnnotation StackClass =
@ -313,8 +319,32 @@ static CustomTypeAnnotation NonTemporaryClass =
CustomTypeAnnotation("moz_non_temporary_class", "non-temporary");
static CustomTypeAnnotation MustUse =
CustomTypeAnnotation("moz_must_use", "must-use");
static CustomTypeAnnotation NonMemMovable =
CustomTypeAnnotation("moz_non_memmovable", "non-memmove()able");
class MemMoveAnnotation final : public CustomTypeAnnotation {
public:
MemMoveAnnotation()
: CustomTypeAnnotation("moz_non_memmovable", "non-memmove()able") {}
virtual ~MemMoveAnnotation() {}
protected:
bool hasFakeAnnotation(const TagDecl *D) const override {
// Annotate everything in ::std, with a few exceptions; see bug
// 1201314 for discussion.
if (getDeclarationNamespace(D) == "std") {
// This doesn't check that it's really ::std::pair and not
// ::std::something_else::pair, but should be good enough.
StringRef Name = D->getName();
if (Name == "pair" || Name == "atomic" || Name == "__atomic_base") {
return false;
}
return true;
}
return false;
}
};
static MemMoveAnnotation NonMemMovable = MemMoveAnnotation();
class MozChecker : public ASTConsumer, public RecursiveASTVisitor<MozChecker> {
DiagnosticsEngine &Diag;
@ -768,7 +798,7 @@ bool CustomTypeAnnotation::hasLiteralAnnotation(QualType T) const {
#else
if (const CXXRecordDecl *D = T->getAsCXXRecordDecl()) {
#endif
return MozChecker::hasCustomAnnotation(D, Spelling);
return hasFakeAnnotation(D) || MozChecker::hasCustomAnnotation(D, Spelling);
}
return false;
}

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

@ -0,0 +1,21 @@
#define MOZ_NEEDS_MEMMOVABLE_TYPE __attribute__((annotate("moz_needs_memmovable_type")))
template<class T>
class MOZ_NEEDS_MEMMOVABLE_TYPE Mover { T mForceInst; }; // expected-error-re 4 {{Cannot instantiate 'Mover<{{.*}}>' with non-memmovable template argument '{{.*}}'}}
namespace std {
// In theory defining things in std:: like this invokes undefined
// behavior, but in practice it's good enough for this test case.
template<class C> class basic_string { };
typedef basic_string<char> string;
template<class T, class U> class pair { T mT; U mU; }; // expected-note {{std::pair<bool, std::basic_string<char> >' is a non-memmove()able type because member 'mU' is a non-memmove()able type 'std::basic_string<char>'}}
class arbitrary_name { };
}
class HasString { std::string m; }; // expected-note {{'HasString' is a non-memmove()able type because member 'm' is a non-memmove()able type 'std::string' (aka 'basic_string<char>')}}
static Mover<std::string> bad; // expected-note {{instantiation of 'Mover<std::basic_string<char> >' requested here}}
static Mover<HasString> bad_mem; // expected-note {{instantiation of 'Mover<HasString>' requested here}}
static Mover<std::arbitrary_name> assumed_bad; // expected-note {{instantiation of 'Mover<std::arbitrary_name>' requested here}}
static Mover<std::pair<bool, int>> good;
static Mover<std::pair<bool, std::string>> not_good; // expected-note {{instantiation of 'Mover<std::pair<bool, std::basic_string<char> > >' requested here}}

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

@ -24,6 +24,7 @@ SOURCES += [
'TestNoExplicitMoveConstructor.cpp',
'TestNonHeapClass.cpp',
'TestNonMemMovable.cpp',
'TestNonMemMovableStd.cpp',
'TestNonTemporaryClass.cpp',
'TestNoRefcountedInsideLambdas.cpp',
'TestRefCountedCopyConstructor.cpp',

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

@ -15,7 +15,7 @@ if CONFIG['OS_ARCH'] == 'WINNT':
else:
DIRS += ['unix']
if CONFIG['OS_TARGET'] == 'Android' and not CONFIG['MOZ_ANDROID_LIBSTDCXX']:
if CONFIG['OS_TARGET'] == 'Android' and CONFIG['MOZ_ANDROID_CXX_STL'] == 'mozstlport':
DIRS += ['stlport']
if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'android':

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

@ -21,7 +21,8 @@ def Binary():
if CONFIG['STLPORT_LIBS']:
OS_LIBS += [CONFIG['STLPORT_LIBS']]
elif CONFIG['OS_TARGET'] == 'Android':
USE_LIBS += ['stlport']
if CONFIG['MOZ_ANDROID_CXX_STL'] == 'mozstlport':
USE_LIBS += ['stlport']
@template

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

@ -318,6 +318,7 @@ if test -n "$gonkdir" ; then
AC_DEFINE(HAVE_PTHREADS)
MOZ_CHROME_FILE_FORMAT=omni
direct_nspr_config=1
android_cxx_stl=mozstlport
else
MOZ_ANDROID_NDK

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

@ -419,16 +419,26 @@ GetDataInfo(const nsACString& aUri)
}
DataInfo* res;
nsCString uriIgnoringRef;
int32_t hashPos = aUri.FindChar('#');
if (hashPos < 0) {
uriIgnoringRef = aUri;
// Let's remove any fragment and query from this URI.
int32_t hasFragmentPos = aUri.FindChar('#');
int32_t hasQueryPos = aUri.FindChar('?');
int32_t pos = -1;
if (hasFragmentPos >= 0 && hasQueryPos >= 0) {
pos = std::min(hasFragmentPos, hasQueryPos);
} else if (hasFragmentPos >= 0) {
pos = hasFragmentPos;
} else {
pos = hasQueryPos;
}
else {
uriIgnoringRef = StringHead(aUri, hashPos);
if (pos < 0) {
gDataTable->Get(aUri, &res);
} else {
gDataTable->Get(StringHead(aUri, pos), &res);
}
gDataTable->Get(uriIgnoringRef, &res);
return res;
}

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

@ -383,6 +383,7 @@ skip-if = buildapp == 'b2g' || (android_version == '18' && debug) # b2g(flaky on
support-files = test_XHR_timeout.js
[test_base.xhtml]
[test_blobconstructor.html]
[test_blob_fragment_and_query.html]
[test_bug166235.html]
skip-if = buildapp == 'b2g' || toolkit == 'android' || e10s # b2g(clipboard undefined) b2g-debug(clipboard undefined) b2g-desktop(clipboard undefined)
[test_bug199959.html]

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

@ -0,0 +1,48 @@
<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
<title>Test for Blob URI with fragments</title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head>
<body>
<script>
var blob = new Blob(['hello world']);
ok(blob, "We have a blob.");
var url = URL.createObjectURL(blob);
ok(url, "We have a URI");
var tests = [
url,
url + "?aa",
url + "#bb",
url + "?cc#dd",
url + "#ee?ff",
];
function runTest() {
if (!tests.length) {
SimpleTest.finish();
return;
}
var test = tests.shift();
var xhr = new XMLHttpRequest();
xhr.open('GET', test);
xhr.onload = function() {
is(xhr.responseText, 'hello world', 'URL: ' + test);
runTest();
}
xhr.send();
}
SimpleTest.waitForExplicitFinish();
runTest();
</script>
</body>
</html>

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

@ -2758,17 +2758,12 @@ nsresult HTMLMediaElement::InitializeDecoderAsClone(MediaDecoder* aOriginal)
MediaResource* originalResource = aOriginal->GetResource();
if (!originalResource)
return NS_ERROR_FAILURE;
nsRefPtr<MediaDecoder> decoder = aOriginal->Clone();
nsRefPtr<MediaDecoder> decoder = aOriginal->Clone(this);
if (!decoder)
return NS_ERROR_FAILURE;
LOG(LogLevel::Debug, ("%p Cloned decoder %p from %p", this, decoder.get(), aOriginal));
if (!decoder->Init(this)) {
LOG(LogLevel::Debug, ("%p Failed to init cloned decoder %p", this, decoder.get()));
return NS_ERROR_FAILURE;
}
decoder->SetMediaSeekable(aOriginal->IsMediaSeekable());
nsRefPtr<MediaResource> resource = originalResource->CloneData(decoder);

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

@ -586,33 +586,33 @@ InstantiateDecoder(const nsACString& aType, MediaDecoderOwner* aOwner)
#ifdef MOZ_FMP4
if (IsMP4SupportedType(aType)) {
decoder = new MP4Decoder();
decoder = new MP4Decoder(aOwner);
return decoder.forget();
}
#endif
if (IsMP3SupportedType(aType)) {
decoder = new MP3Decoder();
decoder = new MP3Decoder(aOwner);
return decoder.forget();
}
#ifdef MOZ_GSTREAMER
if (IsGStreamerSupportedType(aType)) {
decoder = new GStreamerDecoder();
decoder = new GStreamerDecoder(aOwner);
return decoder.forget();
}
#endif
#ifdef MOZ_RAW
if (IsRawType(aType)) {
decoder = new RawDecoder();
decoder = new RawDecoder(aOwner);
return decoder.forget();
}
#endif
if (IsOggType(aType)) {
decoder = new OggDecoder();
decoder = new OggDecoder(aOwner);
return decoder.forget();
}
#ifdef MOZ_WAVE
if (IsWaveType(aType)) {
decoder = new WaveDecoder();
decoder = new WaveDecoder(aOwner);
return decoder.forget();
}
#endif
@ -635,10 +635,10 @@ InstantiateDecoder(const nsACString& aType, MediaDecoderOwner* aOwner)
}
#if ANDROID_VERSION >= 18
decoder = MediaDecoder::IsOmxAsyncEnabled()
? static_cast<MediaDecoder*>(new MediaCodecDecoder())
: static_cast<MediaDecoder*>(new MediaOmxDecoder());
? static_cast<MediaDecoder*>(new MediaCodecDecoder(aOwner))
: static_cast<MediaDecoder*>(new MediaOmxDecoder(aOwner));
#else
decoder = new MediaOmxDecoder();
decoder = new MediaOmxDecoder(aOwner);
#endif
return decoder.forget();
}
@ -647,10 +647,10 @@ InstantiateDecoder(const nsACString& aType, MediaDecoderOwner* aOwner)
if (IsRtspSupportedType(aType)) {
#if ANDROID_VERSION >= 18
decoder = MediaDecoder::IsOmxAsyncEnabled()
? static_cast<MediaDecoder*>(new RtspMediaCodecDecoder())
: static_cast<MediaDecoder*>(new RtspOmxDecoder());
? static_cast<MediaDecoder*>(new RtspMediaCodecDecoder(aOwner))
: static_cast<MediaDecoder*>(new RtspOmxDecoder(aOwner));
#else
decoder = new RtspOmxDecoder();
decoder = new RtspOmxDecoder(aOwner);
#endif
return decoder.forget();
}
@ -658,25 +658,25 @@ InstantiateDecoder(const nsACString& aType, MediaDecoderOwner* aOwner)
#ifdef MOZ_ANDROID_OMX
if (MediaDecoder::IsAndroidMediaEnabled() &&
EnsureAndroidMediaPluginHost()->FindDecoder(aType, nullptr)) {
decoder = new AndroidMediaDecoder(aType);
decoder = new AndroidMediaDecoder(aOwner, aType);
return decoder.forget();
}
#endif
if (DecoderTraits::IsWebMType(aType)) {
decoder = new WebMDecoder();
decoder = new WebMDecoder(aOwner);
return decoder.forget();
}
#ifdef MOZ_DIRECTSHOW
// Note: DirectShow should come before WMF, so that we prefer DirectShow's
// MP3 support over WMF's.
if (IsDirectShowSupportedType(aType)) {
decoder = new DirectShowDecoder();
decoder = new DirectShowDecoder(aOwner);
return decoder.forget();
}
#endif
#ifdef MOZ_APPLEMEDIA
if (IsAppleMediaSupportedType(aType)) {
decoder = new AppleDecoder();
decoder = new AppleDecoder(aOwner);
return decoder.forget();
}
#endif
@ -689,11 +689,7 @@ already_AddRefed<MediaDecoder>
DecoderTraits::CreateDecoder(const nsACString& aType, MediaDecoderOwner* aOwner)
{
MOZ_ASSERT(NS_IsMainThread());
nsRefPtr<MediaDecoder> decoder(InstantiateDecoder(aType, aOwner));
NS_ENSURE_TRUE(decoder != nullptr, nullptr);
NS_ENSURE_TRUE(decoder->Init(aOwner), nullptr);
return decoder.forget();
return InstantiateDecoder(aType, aOwner);
}
/* static */

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

@ -15,11 +15,11 @@
namespace mozilla {
MediaDecoder*
MP3Decoder::Clone() {
MP3Decoder::Clone(MediaDecoderOwner* aOwner) {
if (!IsEnabled()) {
return nullptr;
}
return new MP3Decoder();
return new MP3Decoder(aOwner);
}
MediaDecoderStateMachine*

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

@ -13,7 +13,8 @@ namespace mozilla {
class MP3Decoder : public MediaDecoder {
public:
// MediaDecoder interface.
MediaDecoder* Clone() override;
explicit MP3Decoder(MediaDecoderOwner* aOwner) : MediaDecoder(aOwner) {}
MediaDecoder* Clone(MediaDecoderOwner* aOwner) override;
MediaDecoderStateMachine* CreateStateMachine() override;
// Returns true if the MP3 backend is preffed on, and we're running on a

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

@ -348,7 +348,7 @@ MediaDecoder::IsInfinite()
return mInfiniteStream;
}
MediaDecoder::MediaDecoder()
MediaDecoder::MediaDecoder(MediaDecoderOwner* aOwner)
: mWatchManager(this, AbstractThread::MainThread())
, mDormantSupported(false)
, mLogicalPosition(0.0)
@ -358,7 +358,8 @@ MediaDecoder::MediaDecoder()
#endif
, mIgnoreProgressData(false)
, mInfiniteStream(false)
, mOwner(nullptr)
, mOwner(aOwner)
, mVideoFrameContainer(aOwner->GetVideoFrameContainer())
, mPlaybackStatistics(new MediaChannelStatistics())
, mPinnedForSeek(false)
, mShuttingDown(false)
@ -441,16 +442,8 @@ MediaDecoder::MediaDecoder()
// mIgnoreProgressData
mWatchManager.Watch(mLogicallySeeking, &MediaDecoder::SeekingChanged);
}
bool
MediaDecoder::Init(MediaDecoderOwner* aOwner)
{
MOZ_ASSERT(NS_IsMainThread());
mOwner = aOwner;
mVideoFrameContainer = aOwner->GetVideoFrameContainer();
MediaShutdownManager::Instance().Register(this);
return true;
}
void

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

@ -299,24 +299,18 @@ public:
// Must be called exactly once, on the main thread, during startup.
static void InitStatics();
MediaDecoder();
explicit MediaDecoder(MediaDecoderOwner* aOwner);
// Reset the decoder and notify the media element that
// server connection is closed.
virtual void ResetConnectionState();
// Create a new decoder of the same type as this one.
// Subclasses must implement this.
virtual MediaDecoder* Clone() = 0;
virtual MediaDecoder* Clone(MediaDecoderOwner* aOwner) = 0;
// Create a new state machine to run this decoder.
// Subclasses must implement this.
virtual MediaDecoderStateMachine* CreateStateMachine() = 0;
// Call on the main thread only.
// Perform any initialization required for the decoder.
// Return true on successful initialisation, false
// on failure.
virtual bool Init(MediaDecoderOwner* aOwner);
// Cleanup internal data structures. Must be called on the main
// thread by the owning object before that object disposes of this object.
virtual void Shutdown();

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

@ -10,7 +10,9 @@
namespace mozilla {
AndroidMediaDecoder::AndroidMediaDecoder(const nsACString& aType) : mType(aType)
AndroidMediaDecoder::AndroidMediaDecoder(MediaDecoderOwner* aOwner,
const nsACString& aType)
: MediaDecoder(aOwner), mType(aType)
{
}

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

@ -15,14 +15,16 @@ class AndroidMediaDecoder : public MediaDecoder
{
nsCString mType;
public:
AndroidMediaDecoder(const nsACString& aType);
AndroidMediaDecoder(MediaDecoderOwner* aOwner, const nsACString& aType);
const nsresult GetContentType(nsACString& aType) const {
aType = mType;
return NS_OK;
}
virtual MediaDecoder* Clone() { return new AndroidMediaDecoder(mType); }
virtual MediaDecoder* Clone(MediaDecoderOwner* aOwner) {
return new AndroidMediaDecoder(aOwner, mType);
}
virtual MediaDecoderStateMachine* CreateStateMachine();
};

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

@ -9,15 +9,15 @@
namespace mozilla {
AppleDecoder::AppleDecoder()
: MediaDecoder()
AppleDecoder::AppleDecoder(MediaDecoderOwner* aOwner)
: MediaDecoder(aOwner)
{
}
MediaDecoder *
AppleDecoder::Clone()
AppleDecoder::Clone(MediaDecoderOwner* aOwner)
{
return new AppleDecoder();
return new AppleDecoder(aOwner);
}
MediaDecoderStateMachine *

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

@ -12,9 +12,9 @@ namespace mozilla {
class AppleDecoder : public MediaDecoder
{
public:
AppleDecoder();
explicit AppleDecoder(MediaDecoderOwner* aOwner);
virtual MediaDecoder* Clone() override;
virtual MediaDecoder* Clone(MediaDecoderOwner* aOwner) override;
virtual MediaDecoderStateMachine* CreateStateMachine() override;
};

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

@ -49,7 +49,8 @@ DirectShowDecoder::IsEnabled()
Preferences::GetBool("media.directshow.enabled");
}
DirectShowDecoder::DirectShowDecoder()
DirectShowDecoder::DirectShowDecoder(MediaDecoderOwner* aOwner)
: MediaDecoder(aOwner)
{
MOZ_COUNT_CTOR(DirectShowDecoder);
}

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

@ -16,14 +16,14 @@ class DirectShowDecoder : public MediaDecoder
{
public:
DirectShowDecoder();
explicit DirectShowDecoder(MediaDecoderOwner* aOwner);
virtual ~DirectShowDecoder();
MediaDecoder* Clone() override {
MediaDecoder* Clone(MediaDecoderOwner* aOwner) override {
if (!IsEnabled()) {
return nullptr;
}
return new DirectShowDecoder();
return new DirectShowDecoder(aOwner);
}
MediaDecoderStateMachine* CreateStateMachine() override;

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

@ -37,7 +37,8 @@ namespace mozilla {
#undef MP4_READER_DORMANT_HEURISTIC
#endif
MP4Decoder::MP4Decoder()
MP4Decoder::MP4Decoder(MediaDecoderOwner* aOwner)
: MediaDecoder(aOwner)
{
#if defined(MP4_READER_DORMANT_HEURISTIC)
mDormantSupported = Preferences::GetBool("media.decoder.heuristic.dormant.enabled", false);

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

@ -14,13 +14,13 @@ namespace mozilla {
class MP4Decoder : public MediaDecoder
{
public:
MP4Decoder();
explicit MP4Decoder(MediaDecoderOwner* aOwner);
virtual MediaDecoder* Clone() override {
virtual MediaDecoder* Clone(MediaDecoderOwner* aOwner) override {
if (!IsEnabled()) {
return nullptr;
}
return new MP4Decoder();
return new MP4Decoder(aOwner);
}
virtual MediaDecoderStateMachine* CreateStateMachine() override;

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

@ -15,7 +15,10 @@ namespace mozilla {
class GStreamerDecoder : public MediaDecoder
{
public:
virtual MediaDecoder* Clone() { return new GStreamerDecoder(); }
explicit GStreamerDecoder(MediaDecoderOwner* aOwner) : MediaDecoder(aOwner) {}
virtual MediaDecoder* Clone(MediaDecoderOwner* aOwner) {
return new GStreamerDecoder(aOwner);
}
virtual MediaDecoderStateMachine* CreateStateMachine();
static bool CanHandleMediaType(const nsACString& aMIMEType, const nsAString* aCodecs);
};

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

@ -27,15 +27,15 @@ using namespace mozilla::media;
namespace mozilla {
MediaSourceDecoder::MediaSourceDecoder(dom::HTMLMediaElement* aElement)
: mMediaSource(nullptr)
: MediaDecoder(aElement)
, mMediaSource(nullptr)
, mEnded(false)
{
SetExplicitDuration(UnspecifiedNaN<double>());
Init(aElement);
}
MediaDecoder*
MediaSourceDecoder::Clone()
MediaSourceDecoder::Clone(MediaDecoderOwner* aOwner)
{
// TODO: Sort out cloning.
return nullptr;

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

@ -36,7 +36,7 @@ class MediaSourceDecoder : public MediaDecoder
public:
explicit MediaSourceDecoder(dom::HTMLMediaElement* aElement);
virtual MediaDecoder* Clone() override;
virtual MediaDecoder* Clone(MediaDecoderOwner* aOwner) override;
virtual MediaDecoderStateMachine* CreateStateMachine() override;
virtual nsresult Load(nsIStreamListener**) override;
virtual media::TimeIntervals GetSeekable() override;

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

@ -13,16 +13,17 @@ namespace mozilla {
class OggDecoder : public MediaDecoder
{
public:
OggDecoder()
: mShutdownBitMonitor("mShutdownBitMonitor")
explicit OggDecoder(MediaDecoderOwner* aOwner)
: MediaDecoder(aOwner)
, mShutdownBitMonitor("mShutdownBitMonitor")
, mShutdownBit(false)
{}
virtual MediaDecoder* Clone() override {
virtual MediaDecoder* Clone(MediaDecoderOwner* aOwner) override {
if (!IsOggEnabled()) {
return nullptr;
}
return new OggDecoder();
return new OggDecoder(aOwner);
}
virtual MediaDecoderStateMachine* CreateStateMachine() override;

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

@ -12,9 +12,9 @@
namespace mozilla {
MediaDecoder*
MediaCodecDecoder::Clone()
MediaCodecDecoder::Clone(MediaDecoderOwner* aOwner)
{
return new MediaCodecDecoder();
return new MediaCodecDecoder(aOwner);
}
MediaOmxCommonReader*

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

@ -15,8 +15,10 @@ namespace mozilla {
class MediaCodecDecoder : public MediaOmxCommonDecoder
{
public:
explicit MediaCodecDecoder(MediaDecoderOwner* aOwner)
: MediaOmxCommonDecoder(aOwner) {}
virtual MediaDecoder* Clone();
virtual MediaDecoder* Clone(MediaDecoderOwner* aOwner);
virtual MediaOmxCommonReader* CreateReader();

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

@ -23,8 +23,8 @@ namespace mozilla {
extern PRLogModuleInfo* gMediaDecoderLog;
#define DECODER_LOG(type, msg) MOZ_LOG(gMediaDecoderLog, type, msg)
MediaOmxCommonDecoder::MediaOmxCommonDecoder()
: MediaDecoder()
MediaOmxCommonDecoder::MediaOmxCommonDecoder(MediaDecoderOwner* aOwner)
: MediaDecoder(aOwner)
, mReader(nullptr)
, mCanOffloadAudio(false)
, mFallbackToStateMachine(false)

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

@ -21,7 +21,7 @@ class MediaOmxCommonReader;
class MediaOmxCommonDecoder : public MediaDecoder
{
public:
MediaOmxCommonDecoder();
explicit MediaOmxCommonDecoder(MediaDecoderOwner* aOwner);
virtual void FirstFrameLoaded(nsAutoPtr<MediaInfo> aInfo,
MediaDecoderEventVisibility aEventVisibility) override;

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

@ -13,9 +13,9 @@ using namespace android;
namespace mozilla {
MediaDecoder*
MediaOmxDecoder::Clone()
MediaOmxDecoder::Clone(MediaDecoderOwner* aOwner)
{
return new MediaOmxDecoder();
return new MediaOmxDecoder(aOwner);
}
MediaOmxCommonReader*

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

@ -13,7 +13,9 @@ namespace mozilla {
class MediaOmxDecoder : public MediaOmxCommonDecoder
{
public:
virtual MediaDecoder* Clone();
explicit MediaOmxDecoder(MediaDecoderOwner* aOwner)
: MediaOmxCommonDecoder(aOwner) {}
virtual MediaDecoder* Clone(MediaDecoderOwner* aOwner);
virtual MediaOmxCommonReader* CreateReader();
virtual MediaDecoderStateMachine* CreateStateMachineFromReader(MediaOmxCommonReader* aReader);
};

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

@ -13,9 +13,9 @@
namespace mozilla {
MediaDecoder*
RtspMediaCodecDecoder::Clone()
RtspMediaCodecDecoder::Clone(MediaDecoderOwner* aOwner)
{
return new RtspMediaCodecDecoder();
return new RtspMediaCodecDecoder(aOwner);
}
MediaOmxCommonReader*

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

@ -14,7 +14,10 @@ namespace mozilla {
class RtspMediaCodecDecoder final : public MediaOmxCommonDecoder
{
public:
virtual MediaDecoder* Clone() override;
explicit RtspMediaCodecDecoder(MediaDecoderOwner* aOwner)
: MediaOmxCommonDecoder(aOwner) {}
virtual MediaDecoder* Clone(MediaDecoderOwner* aOwner) override;
virtual MediaOmxCommonReader* CreateReader() override;

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

@ -11,9 +11,9 @@
namespace mozilla {
MediaDecoder* RtspOmxDecoder::Clone()
MediaDecoder* RtspOmxDecoder::Clone(MediaDecoderOwner* aOwner)
{
return new RtspOmxDecoder();
return new RtspOmxDecoder(aOwner);
}
MediaDecoderStateMachine*

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

@ -21,8 +21,7 @@ namespace mozilla {
class RtspOmxDecoder : public MediaDecoder
{
public:
RtspOmxDecoder()
: MediaDecoder() {
explicit RtspOmxDecoder(MediaDecoderOwner* aOwner) : MediaDecoder(aOwner) {
MOZ_COUNT_CTOR(RtspOmxDecoder);
}
@ -30,7 +29,7 @@ public:
MOZ_COUNT_DTOR(RtspOmxDecoder);
}
virtual MediaDecoder* Clone() override final;
virtual MediaDecoder* Clone(MediaDecoderOwner* aOwner) override final;
virtual MediaDecoderStateMachine* CreateStateMachine() override final;
virtual void ChangeState(PlayState aState) override final;
};

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

@ -12,11 +12,12 @@ namespace mozilla {
class RawDecoder : public MediaDecoder
{
public:
virtual MediaDecoder* Clone() {
explicit RawDecoder(MediaDecoderOwner* aOwner) : MediaDecoder(aOwner) {}
virtual MediaDecoder* Clone(MediaDecoderOwner* aOwner) {
if (!IsRawEnabled()) {
return nullptr;
}
return new RawDecoder();
return new RawDecoder(aOwner);
}
virtual MediaDecoderStateMachine* CreateStateMachine();
};

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

@ -24,11 +24,12 @@ namespace mozilla {
class WaveDecoder : public MediaDecoder
{
public:
virtual MediaDecoder* Clone() {
explicit WaveDecoder(MediaDecoderOwner* aOwner) : MediaDecoder(aOwner) {}
virtual MediaDecoder* Clone(MediaDecoderOwner* aOwner) {
if (!IsWaveEnabled()) {
return nullptr;
}
return new WaveDecoder();
return new WaveDecoder(aOwner);
}
virtual MediaDecoderStateMachine* CreateStateMachine();
};

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

@ -13,11 +13,12 @@ namespace mozilla {
class WebMDecoder : public MediaDecoder
{
public:
virtual MediaDecoder* Clone() {
explicit WebMDecoder(MediaDecoderOwner* aOwner) : MediaDecoder(aOwner) {}
virtual MediaDecoder* Clone(MediaDecoderOwner* aOwner) {
if (!IsWebMEnabled()) {
return nullptr;
}
return new WebMDecoder();
return new WebMDecoder(aOwner);
}
virtual MediaDecoderStateMachine* CreateStateMachine();
};

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

@ -26,7 +26,7 @@ function queryIfBeaconSucceeded() {
var xhr = new XMLHttpRequest();
xhr.open("GET", "beacon-preflight-handler.sjs?verify", true);
xhr.onload = function() {
is(xhr.responseText, "red", "SendBeacon should have failed because of a failed preflight!");
is(xhr.responseText, "green", "SendBeacon should have failed because of a failed preflight!");
SimpleTest.finish();
};
xhr.onerror = function() {

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

@ -906,5 +906,13 @@ CriticalLogger::OutputMessage(const std::string &aString,
BasicLogger::OutputMessage(aString, aLevel, aNoNewline);
}
void
CriticalLogger::CrashAction(LogReason aReason)
{
if (Factory::GetLogForwarder()) {
Factory::GetLogForwarder()->CrashAction(aReason);
}
}
} // namespace gfx
} // namespace mozilla

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

@ -127,6 +127,17 @@ private:
/// is further controlled by "gfx2d" PR logging module. However, in the case
/// where such module would disable the output, in all but gfxDebug cases,
/// we will still send a printf.
// The range is due to the values set in Histograms.json
enum class LogReason : int {
MustBeMoreThanThis = -1,
// Start. Do not insert, always add at end. If you remove items,
// make sure the other items retain their values.
// End
MustBeLessThanThis = 101,
};
struct BasicLogger
{
// For efficiency, this method exists and copies the logic of the
@ -151,6 +162,9 @@ struct BasicLogger
return false;
}
// Only for really critical errors.
static void CrashAction(LogReason aReason) {}
static void OutputMessage(const std::string &aString,
int aLevel,
bool aNoNewline) {
@ -183,6 +197,7 @@ struct BasicLogger
struct CriticalLogger {
static void OutputMessage(const std::string &aString, int aLevel, bool aNoNewline);
static void CrashAction(LogReason aReason);
};
// Implement this interface and init the Factory with an instance to
@ -191,6 +206,7 @@ class LogForwarder {
public:
virtual ~LogForwarder() {}
virtual void Log(const std::string &aString) = 0;
virtual void CrashAction(LogReason aReason) = 0;
// Provide a copy of the logs to the caller. The int is the index
// of the Log call, if the number of logs exceeds some preset capacity
@ -215,7 +231,8 @@ public:
enum class LogOptions : int {
NoNewline = 0x01,
AutoPrefix = 0x02,
AssertOnCall = 0x04
AssertOnCall = 0x04,
CrashAction = 0x08,
};
template<typename T>
@ -241,8 +258,9 @@ public:
// Logger::ShouldOutputMessage. Since we currently don't have a different
// version of that method for different loggers, this is OK. Once we do,
// change BasicLogger::ShouldOutputMessage to Logger::ShouldOutputMessage.
explicit Log(int aOptions = Log::DefaultOptions(L == LOG_CRITICAL)) {
Init(aOptions, BasicLogger::ShouldOutputMessage(L));
explicit Log(int aOptions = Log::DefaultOptions(L == LOG_CRITICAL),
LogReason aReason = LogReason::MustBeMoreThanThis) {
Init(aOptions, BasicLogger::ShouldOutputMessage(L), aReason);
}
~Log() {
@ -451,22 +469,30 @@ public:
inline bool LogIt() const { return mLogIt; }
inline bool NoNewline() const { return mOptions & int(LogOptions::NoNewline); }
inline bool AutoPrefix() const { return mOptions & int(LogOptions::AutoPrefix); }
inline bool ValidReason() const { return (int)mReason > (int)LogReason::MustBeMoreThanThis && (int)mReason < (int)LogReason::MustBeLessThanThis; }
// We do not want this version to do any work, and stringstream can't be
// copied anyway. It does come in handy for the "Once" macro defined below.
MOZ_IMPLICIT Log(const Log& log) { Init(log.mOptions, false); }
MOZ_IMPLICIT Log(const Log& log) { Init(log.mOptions, false, log.mReason); }
private:
// Initialization common to two constructors
void Init(int aOptions, bool aLogIt) {
void Init(int aOptions, bool aLogIt, LogReason aReason) {
mOptions = aOptions;
mReason = aReason;
mLogIt = aLogIt;
if (mLogIt && AutoPrefix()) {
if (mOptions & int(LogOptions::AssertOnCall)) {
mMessage << "[GFX" << L << "]: ";
} else {
mMessage << "[GFX" << L << "-]: ";
if (mLogIt) {
if (AutoPrefix()) {
if (mOptions & int(LogOptions::AssertOnCall)) {
mMessage << "[GFX" << L;
} else {
mMessage << "[GFX" << L << "-";
}
}
if ((mOptions & int(LogOptions::CrashAction)) && ValidReason()) {
mMessage << " " << (int)mReason;
}
mMessage << "]: ";
}
}
@ -476,11 +502,15 @@ private:
if (mOptions & int(LogOptions::AssertOnCall)) {
MOZ_ASSERT(false, "An assert from the graphics logger");
}
if ((mOptions & int(LogOptions::CrashAction)) && ValidReason()) {
Logger::CrashAction(mReason);
}
}
}
std::stringstream mMessage;
int mOptions;
LogReason mReason;
bool mLogIt;
};
@ -531,6 +561,14 @@ typedef Log<LOG_CRITICAL, CriticalLogger> CriticalLog;
#define gfxWarningOnce if (1) ; else mozilla::gfx::NoLog
#endif
// In the debug build, this is equivalent to the default gfxCriticalError.
// In the non-debug build, on nightly and dev edition, it will MOZ_CRASH.
// On beta and release versions, it will telemetry count, but proceed.
//
// You should create a (new) enum in the LogReason and use it for the reason
// parameter to ensure uniqueness.
#define gfxCrash(reason) gfxCriticalError(int(LogOptions::AutoPrefix) | int(LogOptions::AssertOnCall) | int(LogOptions::CrashAction), (reason))
// See nsDebug.h and the NS_WARN_IF macro
#ifdef __cplusplus

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

@ -172,6 +172,15 @@ _cairo_error (cairo_status_t status)
CAIRO_ENSURE_UNIQUE;
assert (_cairo_status_is_error (status));
#ifdef MOZILLA_VERSION
static int abort_on_error = -1;
if (abort_on_error < 0) {
abort_on_error = (getenv("MOZ_CAIRO_ERROR_ABORT") != NULL) ? 1 : 0;
}
if (abort_on_error) {
*(int*)0x0 = 10;
}
#endif
return status;
}

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

@ -9,6 +9,7 @@
#include "mozilla/layers/ImageBridgeChild.h"
#include "mozilla/layers/SharedBufferManagerChild.h"
#include "mozilla/layers/ISurfaceAllocator.h" // for GfxMemoryImageReporter
#include "mozilla/Telemetry.h"
#include "mozilla/Logging.h"
#include "mozilla/Services.h"
@ -185,6 +186,7 @@ class CrashStatsLogForwarder: public mozilla::gfx::LogForwarder
public:
explicit CrashStatsLogForwarder(const char* aKey);
virtual void Log(const std::string& aString) override;
virtual void CrashAction(LogReason aReason) override;
virtual std::vector<std::pair<int32_t,std::string> > StringsVectorCopy() override;
@ -282,6 +284,55 @@ void CrashStatsLogForwarder::Log(const std::string& aString)
}
}
class CrashTelemetryEvent : public nsRunnable
{
virtual ~CrashTelemetryEvent() {}
NS_DECL_ISUPPORTS_INHERITED
explicit CrashTelemetryEvent(uint32_t aReason) : mReason(aReason) {}
NS_IMETHOD Run() override {
MOZ_ASSERT(NS_IsMainThread());
Telemetry::Accumulate(Telemetry::GFX_CRASH, mReason);
return NS_OK;
}
protected:
uint32_t mReason;
};
NS_IMPL_ISUPPORTS_INHERITED0(CrashTelemetryEvent, nsRunnable);
void
CrashStatsLogForwarder::CrashAction(LogReason aReason)
{
#ifndef RELEASE_BUILD
// Non-release builds crash by default, but will use telemetry
// if this environment variable is present.
static bool useTelemetry = getenv("MOZ_GFX_CRASH_TELEMETRY") != 0;
#else
// Release builds use telemetry bu default, but will crash
// if this environment variable is present. Double negative
// to make the intent clear.
static bool useTelemetry = !(getenv("MOZ_GFX_CRASH_MOZ_CRASH") != 0);
#endif
if (useTelemetry) {
// The callers need to assure that aReason is in the range
// that the telemetry call below supports.
if (NS_IsMainThread()) {
Telemetry::Accumulate(Telemetry::GFX_CRASH, (uint32_t)aReason);
} else {
nsCOMPtr<nsIRunnable> r1 = new CrashTelemetryEvent((uint32_t)aReason);
NS_DispatchToMainThread(r1);
}
} else {
// ignoring aReason, we can get the information we need from the stack
MOZ_CRASH("GFX_CRASH");
}
}
NS_IMPL_ISUPPORTS(SRGBOverrideObserver, nsIObserver, nsISupportsWeakReference)
#define GFX_DOWNLOADABLE_FONTS_ENABLED "gfx.downloadable_fonts.enabled"
@ -755,7 +806,7 @@ gfxPlatform::CreateDrawTargetForUpdateSurface(gfxASurface *aSurface, const IntSi
return Factory::CreateDrawTargetForCairoCGContext(static_cast<gfxQuartzSurface*>(aSurface)->GetCGContext(), aSize);
}
#endif
MOZ_CRASH();
MOZ_CRASH("unused function");
return nullptr;
}

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

@ -6352,8 +6352,7 @@ ParseFunction(ModuleValidator& m, ParseNode** fnOut)
return false;
Directives newDirectives = directives;
AsmJSParseContext funpc(&m.parser(), outerpc, fn, funbox, &newDirectives,
/* blockScopeDepth = */ 0);
AsmJSParseContext funpc(&m.parser(), outerpc, fn, funbox, &newDirectives);
if (!funpc.init(m.parser()))
return false;

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

@ -77,14 +77,9 @@ class MOZ_STACK_CLASS BytecodeCompiler
bool isEvalCompilationUnit();
bool isNonGlobalEvalCompilationUnit();
bool isNonSyntacticCompilationUnit();
bool createParseContext(Maybe<ParseContext<FullParseHandler>>& parseContext,
SharedContext& globalsc, uint32_t blockScopeDepth = 0);
bool saveCallerFun(HandleScript evalCaller, ParseContext<FullParseHandler>& parseContext);
bool handleStatementParseFailure(HandleObject scopeChain, HandleScript evalCaller,
Maybe<ParseContext<FullParseHandler>>& parseContext,
SharedContext& globalsc);
bool saveCallerFun(HandleScript evalCaller);
bool handleParseFailure(const Directives& newDirectives);
bool prepareAndEmitTree(ParseNode** pn, ParseContext<FullParseHandler>& pc);
bool prepareAndEmitTree(ParseNode** pn);
bool checkArgumentsWithinEval(JSContext* cx, HandleFunction fun);
bool maybeCheckEvalFreeVariables(HandleScript evalCaller, HandleObject scopeChain,
ParseContext<FullParseHandler>& pc);
@ -92,9 +87,7 @@ class MOZ_STACK_CLASS BytecodeCompiler
bool maybeSetSourceMap(TokenStream& tokenStream);
bool maybeSetSourceMapFromOptions();
bool emitFinalReturn();
bool initGlobalOrEvalBindings(ParseContext<FullParseHandler>& pc,
Handle<TraceableVector<Binding>> vars,
Handle<TraceableVector<Binding>> lexicals);
bool initGlobalOrEvalBindings(ParseContext<FullParseHandler>& pc);
bool maybeCompleteCompressSource();
AutoCompilationTraceLogger traceLogger;
@ -303,17 +296,7 @@ BytecodeCompiler::isNonSyntacticCompilationUnit()
}
bool
BytecodeCompiler::createParseContext(Maybe<ParseContext<FullParseHandler>>& parseContext,
SharedContext& globalsc, uint32_t blockScopeDepth)
{
parseContext.emplace(parser.ptr(), (GenericParseContext*) nullptr, (ParseNode*) nullptr,
&globalsc, (Directives*) nullptr, blockScopeDepth);
return parseContext->init(*parser);
}
bool
BytecodeCompiler::saveCallerFun(HandleScript evalCaller,
ParseContext<FullParseHandler>& parseContext)
BytecodeCompiler::saveCallerFun(HandleScript evalCaller)
{
/*
* An eval script in a caller frame needs to have its enclosing
@ -325,8 +308,9 @@ BytecodeCompiler::saveCallerFun(HandleScript evalCaller,
RootedFunction fun(cx, evalCaller->functionOrCallerFunction());
MOZ_ASSERT_IF(fun->strict(), options.strictOption);
Directives directives(/* strict = */ options.strictOption);
ObjectBox* funbox = parser->newFunctionBox(/* fn = */ nullptr, fun, &parseContext,
directives, fun->generatorKind());
ObjectBox* funbox = parser->newFunctionBox(/* fn = */ nullptr, fun,
directives, fun->generatorKind(),
enclosingStaticScope);
if (!funbox)
return false;
@ -334,36 +318,6 @@ BytecodeCompiler::saveCallerFun(HandleScript evalCaller,
return true;
}
bool
BytecodeCompiler::handleStatementParseFailure(HandleObject scopeChain, HandleScript evalCaller,
Maybe<ParseContext<FullParseHandler>>& parseContext,
SharedContext& globalsc)
{
if (!parser->hadAbortedSyntaxParse())
return false;
// Parsing inner functions lazily may lead the parser into an
// unrecoverable state and may require starting over on the top
// level statement. Restart the parse; syntax parsing has
// already been disabled for the parser and the result will not
// be ambiguous.
parser->clearAbortedSyntaxParse();
parser->tokenStream.seek(startPosition);
parser->blockScopes.clear();
// Destroying the parse context will destroy its free
// variables, so check if any deoptimization is needed.
if (!maybeCheckEvalFreeVariables(evalCaller, scopeChain, parseContext.ref()))
return false;
parseContext.reset();
if (!createParseContext(parseContext, globalsc, script->bindings.numBlockScoped()))
return false;
MOZ_ASSERT(parser->pc == parseContext.ptr());
return true;
}
bool
BytecodeCompiler::handleParseFailure(const Directives& newDirectives)
{
@ -386,13 +340,8 @@ BytecodeCompiler::handleParseFailure(const Directives& newDirectives)
}
bool
BytecodeCompiler::prepareAndEmitTree(ParseNode** ppn, ParseContext<FullParseHandler>& pc)
BytecodeCompiler::prepareAndEmitTree(ParseNode** ppn)
{
// Accumulate the maximum block scope depth, so that emitTree can assert
// when emitting JSOP_GETLOCAL that the local is indeed within the fixed
// part of the stack frame.
script->bindings.updateNumBlockScoped(pc.blockScopeDepth);
if (!FoldConstants(cx, ppn, parser.ptr()) ||
!NameFunctions(cx, *ppn) ||
!emitter->updateLocalsToFrameSlots() ||
@ -524,35 +473,11 @@ BytecodeCompiler::emitFinalReturn()
}
bool
BytecodeCompiler::initGlobalOrEvalBindings(ParseContext<FullParseHandler>& pc,
Handle<TraceableVector<Binding>> vars,
Handle<TraceableVector<Binding>> lexicals)
BytecodeCompiler::initGlobalOrEvalBindings(ParseContext<FullParseHandler>& pc)
{
Rooted<Bindings> bindings(cx, script->bindings);
Binding* packedBindings = alloc->newArrayUninitialized<Binding>(vars.length() +
lexicals.length());
if (!packedBindings) {
ReportOutOfMemory(cx);
if (!pc.generateBindings(cx, parser->tokenStream, *alloc, &bindings))
return false;
}
// Bindings for global and eval scripts are used solely for redeclaration
// checks in the prologue. Neither 'true' nor 'false' accurately describe
// their aliased-ness. These bindings don't live in CallObjects or the
// frame, but either on the global object and the global lexical
// scope. Force aliased to be false to avoid confusing other analyses in
// the engine that assumes the frame has a call object if there are
// aliased bindings.
Binding* packedIter = packedBindings;
for (const Binding& b: vars)
*packedIter++ = Binding(b.name(), b.kind(), false);
for (const Binding& b: lexicals)
*packedIter++ = Binding(b.name(), b.kind(), false);
if (!Bindings::initWithTemporaryStorage(cx, &bindings, 0, vars.length(), lexicals.length(),
pc.blockScopeDepth, 0, 0, packedBindings))
return false;
script->bindings = bindings;
return true;
}
@ -577,86 +502,46 @@ BytecodeCompiler::compileScript(HandleObject scopeChain, HandleScript evalCaller
if (!createEmitter(&globalsc, evalCaller, isNonGlobalEvalCompilationUnit()))
return nullptr;
Rooted<TraceableVector<Binding>> vars(cx, TraceableVector<Binding>(cx));
Rooted<TraceableVector<Binding>> lexicals(cx, TraceableVector<Binding>(cx));
// Syntax parsing may cause us to restart processing of top level
// statements in the script. Use Maybe<> so that the parse context can be
// reset when this occurs.
//
// WARNING: ParseContext contains instances of Rooted and may be
// reset(). Do not make any new Rooted instances below this point to avoid
// violating the Rooted LIFO invariant.
Maybe<ParseContext<FullParseHandler>> pc;
if (!createParseContext(pc, globalsc))
if (savedCallerFun && !saveCallerFun(evalCaller))
return nullptr;
if (savedCallerFun && !saveCallerFun(evalCaller, pc.ref()))
return nullptr;
for (;;) {
ParseContext<FullParseHandler> pc(parser.ptr(),
/* parent = */ nullptr,
/* maybeFunction = */ nullptr,
&globalsc,
/* newDirectives = */ nullptr);
if (!pc.init(*parser))
return nullptr;
// Global scripts are parsed incrementally, statement by statement.
//
// Eval scripts cannot be, as the block depth needs to be computed for all
// lexical bindings in the entire eval script.
if (isEvalCompilationUnit()) {
ParseNode* pn;
do {
if (isEvalCompilationUnit())
pn = parser->evalBody();
if (!pn && !handleStatementParseFailure(scopeChain, evalCaller, pc, globalsc))
else
pn = parser->globalBody();
// Successfully parsed. Emit the script.
if (pn) {
if (!initGlobalOrEvalBindings(pc))
return nullptr;
} while (!pn);
if (!prepareAndEmitTree(&pn, *pc))
return nullptr;
if (!pc->drainGlobalOrEvalBindings(cx, &vars, &lexicals))
return nullptr;
parser->handler.freeTree(pn);
} else {
bool canHaveDirectives = true;
for (;;) {
TokenKind tt;
if (!parser->tokenStream.peekToken(&tt, TokenStream::Operand))
if (!maybeCheckEvalFreeVariables(evalCaller, scopeChain, pc))
return nullptr;
if (tt == TOK_EOF)
break;
parser->tokenStream.tell(&startPosition);
ParseNode* pn = parser->statement(YieldIsName, canHaveDirectives);
if (!pn) {
if (!handleStatementParseFailure(scopeChain, evalCaller, pc, globalsc))
return nullptr;
pn = parser->statement(YieldIsName);
if (!pn) {
MOZ_ASSERT(!parser->hadAbortedSyntaxParse());
return nullptr;
}
}
if (canHaveDirectives) {
if (!parser->maybeParseDirective(/* stmtList = */ nullptr, pn, &canHaveDirectives))
return nullptr;
}
if (!prepareAndEmitTree(&pn, *pc))
if (!prepareAndEmitTree(&pn))
return nullptr;
if (!pc->drainGlobalOrEvalBindings(cx, &vars, &lexicals))
return nullptr;
parser->handler.freeTree(pn);
break;
}
// Maybe we aborted a syntax parse. See if we can try again.
if (!handleParseFailure(directives))
return nullptr;
}
if (!maybeCheckEvalFreeVariables(evalCaller, scopeChain, *pc) ||
!maybeSetDisplayURL(parser->tokenStream) ||
if (!maybeSetDisplayURL(parser->tokenStream) ||
!maybeSetSourceMap(parser->tokenStream) ||
!maybeSetSourceMapFromOptions() ||
!emitFinalReturn() ||
!initGlobalOrEvalBindings(pc.ref(), vars, lexicals) ||
!JSScript::fullyInitFromEmitter(cx, script, emitter.ptr()))
{
return nullptr;

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

@ -362,7 +362,13 @@ ParseContext<ParseHandler>::updateDecl(TokenStream& ts, JSAtom* atom, Node pn)
// Terribly, deoptimized bindings may be updated with
// optimized bindings due to hoisted function statements, so
// give the new declaration a slot.
if (oldDecl->isDeoptimized() && !newDecl->isDeoptimized()) {
//
// Global bindings are excluded as currently they are never
// frame slots. The notion of being deoptimized is not
// applicable to them.
if (oldDecl->isDeoptimized() && !newDecl->isDeoptimized() &&
!sc->isGlobalContext())
{
newDecl->pn_dflags |= PND_BOUND;
newDecl->pn_scopecoord.setSlot(ts, i);
newDecl->setOp(JSOP_GETLOCAL);
@ -431,15 +437,27 @@ AppendPackedBindings(const ParseContext<ParseHandler>* pc, const DeclVector& vec
MOZ_CRASH("unexpected dn->kind");
}
/*
* Bindings::init does not check for duplicates so we must ensure that
* only one binding with a given name is marked aliased. pc->decls
* maintains the canonical definition for each name, so use that.
*/
MOZ_ASSERT_IF(dn->isClosed(), pc->decls().lookupFirst(name) == dn);
bool aliased = dn->isClosed() ||
(pc->sc->allLocalsAliased() &&
pc->decls().lookupFirst(name) == dn);
bool aliased;
if (pc->sc->isGlobalContext()) {
// Bindings for global and eval scripts are used solely for redeclaration
// checks in the prologue. Neither 'true' nor 'false' accurately describe
// their aliased-ness. These bindings don't live in CallObjects or the
// frame, but either on the global object and the global lexical
// scope. Force aliased to be false to avoid confusing other analyses in
// the engine that assumes the frame has a call object if there are
// aliased bindings.
aliased = false;
} else {
/*
* Bindings::init does not check for duplicates so we must ensure that
* only one binding with a given name is marked aliased. pc->decls
* maintains the canonical definition for each name, so use that.
*/
MOZ_ASSERT_IF(dn->isClosed(), pc->decls().lookupFirst(name) == dn);
aliased = dn->isClosed() ||
(pc->sc->allLocalsAliased() &&
pc->decls().lookupFirst(name) == dn);
}
*dst = Binding(name, kind, aliased);
if (!aliased && numUnaliased)
@ -463,18 +481,23 @@ ParseContext<ParseHandler>::generateBindings(ExclusiveContext* cx, TokenStream&
if (UINT32_MAX - args_.length() <= vars_.length() + bodyLevelLexicals_.length())
return ts.reportError(JSMSG_TOO_MANY_LOCALS);
// Fix up the blockids of vars, whose static scope is always at the body
// level. This could not be done up front in ParseContext::Define, as
// the original blockids are used for redeclaration checks.
for (size_t i = 0; i < vars_.length(); i++)
vars_[i]->pn_blockid = bodyid;
// Fix up slots in non-global contexts. In global contexts all body-level
// names are dynamically defined and do not live in either frame or
// CallObject slots.
if (!sc->isGlobalContext()) {
// Fix up the blockids of vars, whose static scope is always at the body
// level. This could not be done up front in ParseContext::define, as
// the original blockids are used for redeclaration checks.
for (size_t i = 0; i < vars_.length(); i++)
vars_[i]->pn_blockid = bodyid;
// Fix up the slots of body-level lets to come after the vars now that we
// know how many vars there are.
for (size_t i = 0; i < bodyLevelLexicals_.length(); i++) {
Definition* dn = bodyLevelLexicals_[i];
if (!dn->pn_scopecoord.setSlot(ts, vars_.length() + i))
return false;
// Fix up the slots of body-level lets to come after the vars now that we
// know how many vars there are.
for (size_t i = 0; i < bodyLevelLexicals_.length(); i++) {
Definition* dn = bodyLevelLexicals_[i];
if (!dn->pn_scopecoord.setSlot(ts, vars_.length() + i))
return false;
}
}
uint32_t count = args_.length() + vars_.length() + bodyLevelLexicals_.length();
@ -498,32 +521,6 @@ ParseContext<ParseHandler>::generateBindings(ExclusiveContext* cx, TokenStream&
packedBindings, sc->isModuleBox());
}
template <>
bool
ParseContext<FullParseHandler>::drainGlobalOrEvalBindings(ExclusiveContext* cx,
MutableHandle<TraceableVector<Binding>> vars,
MutableHandle<TraceableVector<Binding>> lexicals)
{
MOZ_ASSERT(sc->isGlobalContext());
uint32_t newVarsPos = vars.length();
uint32_t newLexicalsPos = lexicals.length();
if (!vars.growBy(vars_.length()))
return false;
AppendPackedBindings(this, vars_, vars.begin() + newVarsPos);
vars_.clear();
if (!sc->staticScope()->is<StaticEvalObject>()) {
if (!lexicals.growBy(bodyLevelLexicals_.length()))
return false;
AppendPackedBindings(this, bodyLevelLexicals_, lexicals.begin() + newLexicalsPos);
}
bodyLevelLexicals_.clear();
return true;
}
template <typename ParseHandler>
bool
Parser<ParseHandler>::reportHelper(ParseReportKind kind, bool strict, uint32_t offset,
@ -841,8 +838,7 @@ Parser<ParseHandler>::parse()
GlobalSharedContext globalsc(context, staticLexical, directives,
options().extraWarningsOption);
ParseContext<ParseHandler> globalpc(this, /* parent = */ nullptr, ParseHandler::null(),
&globalsc, /* newDirectives = */ nullptr,
/* blockScopeDepth = */ 0);
&globalsc, /* newDirectives = */ nullptr);
if (!globalpc.init(*this))
return null();
@ -919,7 +915,7 @@ Parser<ParseHandler>::standaloneModule(HandleModuleObject module)
return null();
handler.setModuleBox(mn, modulebox);
ParseContext<FullParseHandler> modulepc(this, pc, mn, modulebox, nullptr, 0);
ParseContext<FullParseHandler> modulepc(this, pc, mn, modulebox, nullptr);
if (!modulepc.init(*this))
return null();
@ -960,6 +956,26 @@ Parser<SyntaxParseHandler>::standaloneModule(HandleModuleObject module)
return SyntaxParseHandler::NodeFailure;
}
template <>
bool
Parser<FullParseHandler>::checkStatementsEOF()
{
// This is designed to be paired with parsing a statement list at the top
// level.
//
// The statements() call breaks on TOK_RC, so make sure we've
// reached EOF here.
TokenKind tt;
if (!tokenStream.peekToken(&tt, TokenStream::Operand))
return false;
if (tt != TOK_EOF) {
report(ParseError, false, null(), JSMSG_UNEXPECTED_TOKEN,
"expression", TokenKindToDesc(tt));
return false;
}
return true;
}
template <>
ParseNode*
Parser<FullParseHandler>::evalBody()
@ -977,22 +993,30 @@ Parser<FullParseHandler>::evalBody()
if (!body)
return nullptr;
// The statements() call above breaks on TOK_RC, so make sure we've
// reached EOF here.
TokenKind tt;
if (!tokenStream.peekToken(&tt, TokenStream::Operand))
if (!checkStatementsEOF())
return nullptr;
if (tt != TOK_EOF) {
report(ParseError, false, null(), JSMSG_UNEXPECTED_TOKEN,
"expression", TokenKindToDesc(tt));
return nullptr;
}
block->pn_expr = body;
block->pn_pos = body->pn_pos;
return block;
}
template <>
ParseNode*
Parser<FullParseHandler>::globalBody()
{
MOZ_ASSERT(pc->atGlobalLevel());
ParseNode* body = statements(YieldIsName);
if (!body)
return nullptr;
if (!checkStatementsEOF())
return nullptr;
return body;
}
template <>
ParseNode*
Parser<FullParseHandler>::standaloneFunctionBody(HandleFunction fun,
@ -1020,8 +1044,7 @@ Parser<FullParseHandler>::standaloneFunctionBody(HandleFunction fun,
funbox->length = fun->nargs() - fun->hasRest();
handler.setFunctionBox(fn, funbox);
ParseContext<FullParseHandler> funpc(this, pc, fn, funbox, newDirectives,
/* blockScopeDepth = */ 0);
ParseContext<FullParseHandler> funpc(this, pc, fn, funbox, newDirectives);
if (!funpc.init(*this))
return null();
@ -2643,8 +2666,7 @@ Parser<FullParseHandler>::functionArgsAndBody(InHandling inHandling, ParseNode*
return false;
ParseContext<SyntaxParseHandler> funpc(parser, outerpc, SyntaxParseHandler::null(),
funbox, newDirectives,
/* blockScopeDepth = */ 0);
funbox, newDirectives);
if (!funpc.init(*parser))
return false;
@ -2681,8 +2703,7 @@ Parser<FullParseHandler>::functionArgsAndBody(InHandling inHandling, ParseNode*
blockScopes.resize(oldBlockScopesLength);
// Continue doing a full parse for this inner function.
ParseContext<FullParseHandler> funpc(this, pc, pn, funbox, newDirectives,
/* blockScopeDepth = */ 0);
ParseContext<FullParseHandler> funpc(this, pc, pn, funbox, newDirectives);
if (!funpc.init(*this))
return false;
@ -2720,8 +2741,7 @@ Parser<SyntaxParseHandler>::functionArgsAndBody(InHandling inHandling, Node pn,
return false;
// Initialize early for possible flags mutation via destructuringExpr.
ParseContext<SyntaxParseHandler> funpc(this, pc, handler.null(), funbox, newDirectives,
/* blockScopeDepth = */ 0);
ParseContext<SyntaxParseHandler> funpc(this, pc, handler.null(), funbox, newDirectives);
if (!funpc.init(*this))
return false;
@ -2785,7 +2805,7 @@ Parser<FullParseHandler>::standaloneLazyFunction(HandleFunction fun, bool strict
Directives newDirectives = directives;
ParseContext<FullParseHandler> funpc(this, /* parent = */ nullptr, pn, funbox,
&newDirectives, /* blockScopeDepth = */ 0);
&newDirectives);
if (!funpc.init(*this))
return null();
@ -8101,8 +8121,7 @@ Parser<ParseHandler>::generatorComprehensionLambda(GeneratorKind comprehensionKi
return null();
ParseContext<ParseHandler> genpc(this, outerpc, genfn, genFunbox,
/* newDirectives = */ nullptr,
/* blockScopeDepth = */ 0);
/* newDirectives = */ nullptr);
if (!genpc.init(*this))
return null();

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

@ -197,38 +197,29 @@ struct MOZ_STACK_CLASS ParseContext : public GenericParseContext
/* See the sad story in MakeDefIntoUse. */
void updateDecl(TokenStream& ts, JSAtom* atom, Node newDecl);
/*
* After a function body or module has been parsed, the parser generates the
* code's "bindings". Bindings are a data-structure, ultimately stored in
* the compiled JSScript, that serve three purposes:
* - After parsing, the ParseContext is destroyed and 'decls' along with
* it. Mostly, the emitter just uses the binding information stored in
* the use/def nodes, but the emitter occasionally needs 'bindings' for
* various scope-related queries.
* - Bindings provide the initial js::Shape to use when creating a dynamic
* scope object (js::CallObject). This shape is used during dynamic name
* lookup.
* - Sometimes a script's bindings are accessed at runtime to retrieve the
* contents of the lexical scope (e.g., from the debugger).
*/
// After a script has been parsed, the parser generates the code's
// "bindings". Bindings are a data-structure, ultimately stored in the
// compiled JSScript, that serve three purposes:
//
// - After parsing, the ParseContext is destroyed and 'decls' along with
// it. Mostly, the emitter just uses the binding information stored in
// the use/def nodes, but the emitter occasionally needs 'bindings' for
// various scope-related queries.
//
// - For functions, bindings provide the initial js::Shape to use when
// creating a dynamic scope object (js::CallObject). This shape is used
// during dynamic name lookup.
//
// - Sometimes a script's bindings are accessed at runtime to retrieve the
// contents of the lexical scope (e.g., from the debugger).
//
// - For global and eval scripts, ES6 15.1.8 specifies that if there are
// name conflicts in the script, *no* bindings from the script are
// instantiated. So, record the vars and lexical bindings to check for
// redeclarations in the prologue.
bool generateBindings(ExclusiveContext* cx, TokenStream& ts, LifoAlloc& alloc,
MutableHandle<Bindings> bindings) const;
// All global names in global scripts are added to the scope dynamically
// via JSOP_DEF{FUN,VAR,LET,CONST}, but ES6 15.1.8 specifies that if there
// are name conflicts in the script, *no* bindings from the script are
// instantiated. So, record the vars and lexical bindings to check for
// redeclarations in the prologue.
//
// Eval scripts do not need this mechanism as they always have a
// non-extensible lexical scope.
//
// Global and eval scripts may have block-scoped locals, however, which
// are allocated to the fixed part of the stack frame.
bool drainGlobalOrEvalBindings(ExclusiveContext* cx,
MutableHandle<TraceableVector<Binding>> vars,
MutableHandle<TraceableVector<Binding>> lexicals);
private:
ParseContext** parserPC; /* this points to the Parser's active pc
and holds either |this| or one of
@ -268,14 +259,13 @@ struct MOZ_STACK_CLASS ParseContext : public GenericParseContext
bool inDeclDestructuring:1;
ParseContext(Parser<ParseHandler>* prs, GenericParseContext* parent,
Node maybeFunction, SharedContext* sc, Directives* newDirectives,
uint32_t blockScopeDepth)
Node maybeFunction, SharedContext* sc, Directives* newDirectives)
: GenericParseContext(parent, sc),
bodyid(0), // initialized in init()
stmtStack(prs->context),
maybeFunction(maybeFunction),
lastYieldOffset(NoYieldOffset),
blockScopeDepth(blockScopeDepth),
blockScopeDepth(0),
blockNode(ParseHandler::null()),
decls_(prs->context, prs->alloc),
args_(prs->context),
@ -581,6 +571,7 @@ class Parser : private JS::AutoGCRooter, public StrictModeGetter
bool appendToCallSiteObj(Node callSiteObj);
bool addExprAndGetNextTemplStrToken(YieldHandling yieldHandling, Node nodeList,
TokenKind* ttp);
bool checkStatementsEOF();
inline Node newName(PropertyName* name);
inline Node newYieldExpression(uint32_t begin, Node expr, bool isYieldStar = false);
@ -600,6 +591,9 @@ class Parser : private JS::AutoGCRooter, public StrictModeGetter
// lexical scope.
Node evalBody();
// Parse the body of a global script.
Node globalBody();
// Parse a module.
Node standaloneModule(Handle<ModuleObject*> module);

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

@ -0,0 +1,91 @@
// Let a few threads hammer on memory with atomics to provoke errors
// in exclusion work. This test is not 100% fail-safe: the test may
// pass despite a bug, but this is unlikely.
if (!(this.SharedArrayBuffer && this.getSharedArrayBuffer && this.setSharedArrayBuffer && this.evalInWorker))
quit(0);
try {
// This will fail with --no-threads.
evalInWorker("37");
}
catch (e) {
quit(0);
}
// Map an Int32Array on shared memory. The first location is used as
// a counter, each worker counts up on exit and the main thread will
// wait until the counter reaches the number of workers. The other
// elements are contended accumulators where we count up and down very
// rapidly and for a long time, any failure in mutual exclusion should
// lead to errors in the result. (For example, the test fails almost
// immediately when I disable simulation of mutual exclusion in the
// ARM simulator.)
const numWorkers = 4; // You're not meant to change this
const iterCount = 255; // Nor this
const sabLength = 1024; // Nor this
const oddResult = (function () {
var v = 0;
for ( var j=0 ; j < numWorkers ; j++ )
v |= (iterCount << (8 * j));
return v;
})();
const evenResult = 0;
const sab = new SharedArrayBuffer(sabLength);
setSharedArrayBuffer(sab);
const iab = new SharedInt32Array(sab);
function testRun(limit) {
console.log("Limit = " + limit);
// Fork off workers to hammer on memory.
for ( var i=0 ; i < numWorkers ; i++ ) {
evalInWorker(`
const iab = new SharedInt32Array(getSharedArrayBuffer());
const v = 1 << (8 * ${i});
for ( var i=0 ; i < ${limit} ; i++ ) {
for ( var k=0 ; k < ${iterCount} ; k++ ) {
if (i & 1) {
for ( var j=1 ; j < iab.length ; j++ )
Atomics.sub(iab, j, v);
}
else {
for ( var j=1 ; j < iab.length ; j++ )
Atomics.add(iab, j, v);
}
}
}
Atomics.add(iab, 0, 1);
`);
}
// Wait...
while (Atomics.load(iab, 0) != numWorkers)
;
Atomics.store(iab, 0, 0);
// Check the results and clear the array again.
const v = (limit & 1) ? oddResult : evenResult;
for ( var i=1 ; i < iab.length ; i++ ) {
assertEq(iab[i], v);
iab[i] = 0;
}
}
// Under some configurations the test can take a while to run (and may
// saturate the CPU since it runs four workers); try not to time out.
var then = new Date();
testRun(1);
if (new Date() - then < 20000) {
testRun(2);
if (new Date() - then < 30000) {
testRun(3);
}
}

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

@ -0,0 +1,7 @@
// |jit-test| error: TypeError
var hits = 0;
with(f_arg => constructor.f_arg([3, 4, 5], null)) var length = 257751;
let get = () => 4,
hits = new Intl.Proxy([f_arg]),
y = ($ERROR < 1970) ? 1969 : 1970;

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

@ -0,0 +1,6 @@
eval(`
with ({}) {
var f = function() {};
}
function f() {}
`);

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

@ -38,7 +38,9 @@
#include "asmjs/AsmJSValidate.h"
#include "jit/arm/Assembler-arm.h"
#include "jit/arm/disasm/Constants-arm.h"
#include "jit/AtomicOperations.h"
#include "vm/Runtime.h"
#include "vm/SharedMem.h"
extern "C" {
@ -1127,6 +1129,8 @@ Simulator::Simulator()
cacheLockHolder_ = nullptr;
#endif
redirection_ = nullptr;
exclusiveMonitorHeld_ = false;
exclusiveMonitor_ = 0;
}
bool
@ -1478,6 +1482,27 @@ Simulator::setCallResult(int64_t res)
set_register(r1, static_cast<int32_t>(res >> 32));
}
void
Simulator::exclusiveMonitorSet(uint64_t value)
{
exclusiveMonitor_ = value;
exclusiveMonitorHeld_ = true;
}
uint64_t
Simulator::exclusiveMonitorGetAndClear(bool* held)
{
*held = exclusiveMonitorHeld_;
exclusiveMonitorHeld_ = false;
return *held ? exclusiveMonitor_ : 0;
}
void
Simulator::exclusiveMonitorClear()
{
exclusiveMonitorHeld_ = false;
}
int
Simulator::readW(int32_t addr, SimInstruction* instr)
{
@ -1504,14 +1529,66 @@ Simulator::writeW(int32_t addr, int value, SimInstruction* instr)
}
}
// For the time being, define Relaxed operations in terms of SeqCst
// operations - we don't yet need Relaxed operations anywhere else in
// the system, and the distinction is not important to the simulation
// at the level where we're operating.
template<typename T>
static
T loadRelaxed(SharedMem<T*> addr)
{
return AtomicOperations::loadSeqCst(addr);
}
template<typename T>
static
T compareExchangeRelaxed(SharedMem<T*> addr, T oldval, T newval)
{
return AtomicOperations::compareExchangeSeqCst(addr, oldval, newval);
}
int
Simulator::readExW(int32_t addr, SimInstruction* instr)
{
// The regexp engine emits unaligned loads, so we don't check for them here
// like most of the other methods do.
if ((addr & 3) == 0 || !HasAlignmentFault()) {
SharedMem<int32_t*> ptr = SharedMem<int32_t*>::shared(reinterpret_cast<int32_t*>(addr));
int32_t value = loadRelaxed(ptr);
exclusiveMonitorSet(value);
return value;
} else {
printf("Unaligned write at 0x%08x, pc=%p\n", addr, instr);
MOZ_CRASH();
}
}
int32_t
Simulator::writeExW(int32_t addr, int value, SimInstruction* instr)
{
if ((addr & 3) == 0) {
SharedMem<int32_t*> ptr = SharedMem<int32_t*>::shared(reinterpret_cast<int32_t*>(addr));
bool held;
int32_t expected = int32_t(exclusiveMonitorGetAndClear(&held));
if (!held)
return 1;
int32_t old = compareExchangeRelaxed(ptr, expected, int32_t(value));
return old != expected;
} else {
printf("Unaligned write at 0x%08x, pc=%p\n", addr, instr);
MOZ_CRASH();
}
}
uint16_t
Simulator::readHU(int32_t addr, SimInstruction* instr)
{
// The regexp engine emits unaligned loads, so we don't check for them here
// like most of the other methods do.
if ((addr & 1) == 0 || !HasAlignmentFault()) {
uint16_t* ptr = reinterpret_cast<uint16_t*>(addr);
return *ptr;
uint16_t* ptr = reinterpret_cast<uint16_t*>(addr);
return *ptr;
}
printf("Unaligned unsigned halfword read at 0x%08x, pc=%p\n", addr, instr);
MOZ_CRASH();
@ -1554,6 +1631,39 @@ Simulator::writeH(int32_t addr, int16_t value, SimInstruction* instr)
}
}
uint16_t
Simulator::readExHU(int32_t addr, SimInstruction* instr)
{
// The regexp engine emits unaligned loads, so we don't check for them here
// like most of the other methods do.
if ((addr & 1) == 0 || !HasAlignmentFault()) {
SharedMem<uint16_t*> ptr = SharedMem<uint16_t*>::shared(reinterpret_cast<uint16_t*>(addr));
uint16_t value = loadRelaxed(ptr);
exclusiveMonitorSet(value);
return value;
}
printf("Unaligned atomic unsigned halfword read at 0x%08x, pc=%p\n", addr, instr);
MOZ_CRASH();
return 0;
}
int32_t
Simulator::writeExH(int32_t addr, uint16_t value, SimInstruction* instr)
{
if ((addr & 1) == 0) {
SharedMem<uint16_t*> ptr = SharedMem<uint16_t*>::shared(reinterpret_cast<uint16_t*>(addr));
bool held;
uint16_t expected = uint16_t(exclusiveMonitorGetAndClear(&held));
if (!held)
return 1;
uint16_t old = compareExchangeRelaxed(ptr, expected, value);
return old != expected;
} else {
printf("Unaligned atomic unsigned halfword write at 0x%08x, pc=%p\n", addr, instr);
MOZ_CRASH();
}
}
uint8_t
Simulator::readBU(int32_t addr)
{
@ -1561,6 +1671,27 @@ Simulator::readBU(int32_t addr)
return *ptr;
}
uint8_t
Simulator::readExBU(int32_t addr)
{
SharedMem<uint8_t*> ptr = SharedMem<uint8_t*>::shared(reinterpret_cast<uint8_t*>(addr));
uint8_t value = loadRelaxed(ptr);
exclusiveMonitorSet(value);
return value;
}
int32_t
Simulator::writeExB(int32_t addr, uint8_t value)
{
SharedMem<uint8_t*> ptr = SharedMem<uint8_t*>::shared(reinterpret_cast<uint8_t*>(addr));
bool held;
uint8_t expected = uint8_t(exclusiveMonitorGetAndClear(&held));
if (!held)
return 1;
uint8_t old = compareExchangeRelaxed(ptr, expected, value);
return old != expected;
}
int8_t
Simulator::readB(int32_t addr)
{
@ -1607,6 +1738,49 @@ Simulator::writeDW(int32_t addr, int32_t value1, int32_t value2)
}
}
int32_t
Simulator::readExDW(int32_t addr, int32_t* hibits)
{
#if defined(__clang__) && defined(__i386)
// This is OK for now, we don't yet generate LDREXD.
MOZ_CRASH("Unimplemented - 8-byte atomics are unsupported in Clang on i386");
#else
if ((addr & 3) == 0) {
SharedMem<uint64_t*> ptr = SharedMem<uint64_t*>::shared(reinterpret_cast<uint64_t*>(addr));
uint64_t value = loadRelaxed(ptr);
exclusiveMonitorSet(value);
*hibits = int32_t(value);
return int32_t(value >> 32);
}
printf("Unaligned read at 0x%08x\n", addr);
MOZ_CRASH();
return 0;
#endif
}
int32_t
Simulator::writeExDW(int32_t addr, int32_t value1, int32_t value2)
{
#if defined(__clang__) && defined(__i386)
// This is OK for now, we don't yet generate STREXD.
MOZ_CRASH("Unimplemented - 8-byte atomics are unsupported in Clang on i386");
#else
if ((addr & 3) == 0) {
SharedMem<uint64_t*> ptr = SharedMem<uint64_t*>::shared(reinterpret_cast<uint64_t*>(addr));
uint64_t value = (uint64_t(value1) << 32) | uint32_t(value2);
bool held;
uint64_t expected = exclusiveMonitorGetAndClear(&held);
if (!held)
return 1;
uint64_t old = compareExchangeRelaxed(ptr, expected, value);
return old != expected;
} else {
printf("Unaligned write at 0x%08x\n", addr);
MOZ_CRASH();
}
#endif
}
uintptr_t
Simulator::stackLimit() const
{
@ -2554,33 +2728,27 @@ Simulator::decodeType01(SimInstruction* instr)
} else {
if (instr->bits(disasm::ExclusiveOpHi, disasm::ExclusiveOpLo) == disasm::ExclusiveOpcode) {
// Load-exclusive / store-exclusive.
//
// Bare-bones simulation: the store always succeeds, and we
// do not execute any fences. Also, we allow readDW and
// writeDW to split the memory transaction.
//
// The next step up would involve remembering the value
// that was read with load-exclusive so that we could use
// compareExchange for the store-exclusive, and to
// implement atomic doubleword read and write.
//
// Also see DMB/DSB/ISB below.
if (instr->bit(disasm::ExclusiveLoad)) {
int rn = instr->rnValue();
int rt = instr->rtValue();
int32_t address = get_register(rn);
switch (instr->bits(disasm::ExclusiveSizeHi, disasm::ExclusiveSizeLo)) {
case disasm::ExclusiveWord:
set_register(rt, readW(address, instr));
set_register(rt, readExW(address, instr));
break;
case disasm::ExclusiveDouble:
set_dw_register(rt, readDW(address));
case disasm::ExclusiveDouble: {
MOZ_ASSERT((rt % 2) == 0);
int32_t hibits;
int32_t lobits = readExDW(address, &hibits);
set_register(rt, lobits);
set_register(rt+1, hibits);
break;
}
case disasm::ExclusiveByte:
set_register(rt, readBU(address));
set_register(rt, readExBU(address));
break;
case disasm::ExclusiveHalf:
set_register(rt, readHU(address, instr));
set_register(rt, readExHU(address, instr));
break;
}
} else {
@ -2589,24 +2757,25 @@ Simulator::decodeType01(SimInstruction* instr)
int rt = instr->bits(3,0);
int32_t address = get_register(rn);
int32_t value = get_register(rt);
int32_t result = 0;
switch (instr->bits(disasm::ExclusiveSizeHi, disasm::ExclusiveSizeLo)) {
case disasm::ExclusiveWord:
writeW(address, value, instr);
result = writeExW(address, value, instr);
break;
case disasm::ExclusiveDouble: {
MOZ_ASSERT((rt % 2) == 0);
int32_t value2 = get_register(rt+1);
writeDW(address, value, value2);
break;
MOZ_ASSERT((rt % 2) == 0);
int32_t value2 = get_register(rt+1);
result = writeExDW(address, value, value2);
break;
}
case disasm::ExclusiveByte:
writeB(address, (uint8_t)value);
result = writeExB(address, (uint8_t)value);
break;
case disasm::ExclusiveHalf:
writeH(address, (uint16_t)value, instr);
result = writeExH(address, (uint16_t)value, instr);
break;
}
set_register(rd, 0);
set_register(rd, result);
}
} else {
MOZ_CRASH(); // Not used atm
@ -3329,12 +3498,15 @@ Simulator::decodeType7CoprocessorIns(SimInstruction* instr)
int CRn = instr->bits(19,16);
int CRm = instr->bits(3,0);
if (opc1 == 0 && opc2 == 4 && CRn == 7 && CRm == 10) {
// ARMv6 DSB instruction - do nothing now, see comments above
// ARMv6 DSB instruction. We do not use DSB.
MOZ_CRASH("DSB not implemented");
} else if (opc1 == 0 && opc2 == 5 && CRn == 7 && CRm == 10) {
// ARMv6 DMB instruction - do nothing now, see comments above
// ARMv6 DMB instruction.
AtomicOperations::fenceSeqCst();
}
else if (opc1 == 0 && opc2 == 4 && CRn == 7 && CRm == 5) {
// ARMv6 ISB instruction - do nothing now, see comments above
// ARMv6 ISB instruction. We do not use ISB.
MOZ_CRASH("ISB not implemented");
}
else {
MOZ_CRASH();
@ -4156,16 +4328,16 @@ Simulator::decodeSpecialCondition(SimInstruction* instr)
break;
case 0xA:
if (instr->bits(31,20) == 0xf57) {
// Minimal simulation: do nothing.
//
// If/when we upgrade load-exclusive and store-exclusive (above) to
// do something useful concurrency-wise, we should also upgrade
// these instructions.
switch (instr->bits(7,4)) {
case 5: // DMB
case 4: // DSB
case 6: // ISB
AtomicOperations::fenceSeqCst();
break;
case 4: // DSB
// We do not use DSB.
MOZ_CRASH("DSB unimplemented");
case 6: // ISB
// We do not use ISB.
MOZ_CRASH("ISB unimplemented");
default:
MOZ_CRASH();
}

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

@ -248,18 +248,30 @@ class Simulator
inline void writeB(int32_t addr, uint8_t value);
inline void writeB(int32_t addr, int8_t value);
inline uint8_t readExBU(int32_t addr);
inline int32_t writeExB(int32_t addr, uint8_t value);
inline uint16_t readHU(int32_t addr, SimInstruction* instr);
inline int16_t readH(int32_t addr, SimInstruction* instr);
// Note: Overloaded on the sign of the value.
inline void writeH(int32_t addr, uint16_t value, SimInstruction* instr);
inline void writeH(int32_t addr, int16_t value, SimInstruction* instr);
inline uint16_t readExHU(int32_t addr, SimInstruction* instr);
inline int32_t writeExH(int32_t addr, uint16_t value, SimInstruction* instr);
inline int readW(int32_t addr, SimInstruction* instr);
inline void writeW(int32_t addr, int value, SimInstruction* instr);
inline int readExW(int32_t addr, SimInstruction* instr);
inline int writeExW(int32_t addr, int value, SimInstruction* instr);
int32_t* readDW(int32_t addr);
void writeDW(int32_t addr, int32_t value1, int32_t value2);
int32_t readExDW(int32_t addr, int32_t* hibits);
int32_t writeExDW(int32_t addr, int32_t value1, int32_t value2);
// Executing is handled based on the instruction type.
// Both type 0 and type 1 rolled into one.
void decodeType01(SimInstruction* instr);
@ -432,6 +444,15 @@ class Simulator
MOZ_ASSERT(cacheLockHolder_);
redirection_ = redirection;
}
private:
// Exclusive access monitor
void exclusiveMonitorSet(uint64_t value);
uint64_t exclusiveMonitorGetAndClear(bool* held);
void exclusiveMonitorClear();
bool exclusiveMonitorHeld_;
uint64_t exclusiveMonitor_;
};
#define JS_CHECK_SIMULATOR_RECURSION_WITH_EXTRA(cx, extra, onerror) \

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

@ -324,7 +324,7 @@ struct FloatRegister
k_(k)
{ }
constexpr FloatRegister(uint32_t code)
explicit constexpr FloatRegister(uint32_t code)
: code_(FloatRegisters::Code(code & 31)),
k_(FloatRegisters::Kind(code >> 5))
{ }

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

@ -34,14 +34,14 @@ static constexpr ARMRegister ScratchReg64 = { ScratchReg, 64 };
static constexpr Register ScratchReg2 = { Registers::ip1 };
static constexpr ARMRegister ScratchReg2_64 = { ScratchReg2, 64 };
static constexpr FloatRegister ScratchDoubleReg = { FloatRegisters::d31 };
static constexpr FloatRegister ReturnDoubleReg = { FloatRegisters::d0 };
static constexpr FloatRegister ScratchDoubleReg = { FloatRegisters::d31, FloatRegisters::Double };
static constexpr FloatRegister ReturnDoubleReg = { FloatRegisters::d0, FloatRegisters::Double };
static constexpr FloatRegister ReturnFloat32Reg = { FloatRegisters::s0 , FloatRegisters::Single };
static constexpr FloatRegister ScratchFloat32Reg = { FloatRegisters::s31 , FloatRegisters::Single };
static constexpr FloatRegister ReturnFloat32Reg = { FloatRegisters::s0, FloatRegisters::Single };
static constexpr FloatRegister ScratchFloat32Reg = { FloatRegisters::s31, FloatRegisters::Single };
static constexpr Register InvalidReg = { Registers::invalid_reg };
static constexpr FloatRegister InvalidFloatReg = { FloatRegisters::invalid_fpreg };
static constexpr FloatRegister InvalidFloatReg = { FloatRegisters::invalid_fpreg, FloatRegisters::Single };
static constexpr FloatRegister ReturnInt32x4Reg = InvalidFloatReg;
static constexpr FloatRegister ReturnFloat32x4Reg = InvalidFloatReg;
@ -64,8 +64,8 @@ static constexpr Register ZeroRegister = { Registers::sp };
static constexpr ARMRegister ZeroRegister64 = { Registers::sp, 64 };
static constexpr ARMRegister ZeroRegister32 = { Registers::sp, 32 };
static constexpr FloatRegister ReturnFloatReg = { FloatRegisters::d0 };
static constexpr FloatRegister ScratchFloatReg = { FloatRegisters::d31 };
static constexpr FloatRegister ReturnFloatReg = { FloatRegisters::d0, FloatRegisters::Single };
static constexpr FloatRegister ScratchFloatReg = { FloatRegisters::d31, FloatRegisters::Single };
static constexpr FloatRegister ReturnSimdReg = InvalidFloatReg;
static constexpr FloatRegister ScratchSimdReg = InvalidFloatReg;
@ -142,7 +142,7 @@ static constexpr Register AsmJSIonExitRegD2 = r4;
static constexpr Register JSReturnReg_Type = r3;
static constexpr Register JSReturnReg_Data = r2;
static constexpr FloatRegister NANReg = { FloatRegisters::d14 };
static constexpr FloatRegister NANReg = { FloatRegisters::d14, FloatRegisters::Single };
// N.B. r8 isn't listed as an aapcs temp register, but we can use it as such because we never
// use return-structs.
static constexpr Register CallTempNonArgRegs[] = { r8, r9, r10, r11, r12, r13, r14, r15 };

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

@ -50,8 +50,8 @@ static constexpr Register ExtractTemp1 = r25;
// since we keep the return address for calls there.
// FloatReg0 must be equal to ReturnFloatReg.
static constexpr FloatRegister FloatReg0 = { FloatRegisters::v0 };
static constexpr FloatRegister FloatReg1 = { FloatRegisters::v1 };
static constexpr FloatRegister FloatReg0 = { FloatRegisters::v0, FloatRegisters::Single };
static constexpr FloatRegister FloatReg1 = { FloatRegisters::v1, FloatRegisters::Single };
} // namespace jit
} // namespace js

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

@ -312,24 +312,43 @@ Shape::fixupAfterMovingGC()
void
Shape::fixupGetterSetterForBarrier(JSTracer* trc)
{
// Relocating the getterObj or setterObj will change our location in our
// parent's KidsHash, so remove ourself first if we're going to get moved.
if (parent && !parent->inDictionary() && parent->kids.isHash()) {
KidsHash* kh = parent->kids.toHash();
MOZ_ASSERT(kh->lookup(StackShape(this)));
kh->remove(StackShape(this));
}
if (!hasGetterValue() && !hasSetterValue())
return;
if (hasGetterObject())
TraceManuallyBarrieredEdge(trc, &asAccessorShape().getterObj, "getterObj");
if (hasSetterObject())
TraceManuallyBarrieredEdge(trc, &asAccessorShape().setterObj, "setterObj");
JSObject* priorGetter = asAccessorShape().getterObj;
JSObject* priorSetter = asAccessorShape().setterObj;
if (!priorGetter && !priorSetter)
return;
JSObject* postGetter = priorGetter;
JSObject* postSetter = priorSetter;
if (priorGetter)
TraceManuallyBarrieredEdge(trc, &postGetter, "getterObj");
if (priorSetter)
TraceManuallyBarrieredEdge(trc, &postSetter, "setterObj");
if (priorGetter == postGetter && priorSetter == postSetter)
return;
if (parent && !parent->inDictionary() && parent->kids.isHash()) {
// Relocating the getterObj or setterObj will have changed our location
// in our parent's KidsHash, so take care to update it. We must do this
// before we update the shape itself, since the shape is used to match
// the original entry in the hash set.
StackShape original(this);
StackShape updated(this);
updated.rawGetter = reinterpret_cast<GetterOp>(postGetter);
updated.rawSetter = reinterpret_cast<SetterOp>(postSetter);
KidsHash* kh = parent->kids.toHash();
MOZ_ASSERT(!kh->lookup(StackShape(this)));
MOZ_ALWAYS_TRUE(kh->putNew(StackShape(this), this));
MOZ_ALWAYS_TRUE(kh->rekeyAs(original, updated, this));
}
asAccessorShape().getterObj = postGetter;
asAccessorShape().setterObj = postSetter;
MOZ_ASSERT_IF(parent && !parent->inDictionary() && parent->kids.isHash(),
parent->kids.toHash()->has(StackShape(this)));
}
#ifdef DEBUG

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

@ -396,8 +396,8 @@ inline bool
CheckEvalDeclarationConflicts(JSContext* cx, HandleScript script,
HandleObject scopeChain, HandleObject varObj)
{
MOZ_ASSERT(script->bindings.numBodyLevelLexicals() == 0);
// We don't need to check body-level lexical bindings for conflict. Eval
// scripts always execute under their own lexical scope.
if (script->bindings.numVars() == 0)
return true;

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

@ -51,7 +51,6 @@ skip-if = buildapp == 'mulet'
[test_bug793433.xul]
[test_bug795275.xul]
[test_bug799348.xul]
skip-if = os == 'win' && debug #Bug 1210876
[test_bug801241.xul]
skip-if = buildapp == 'mulet'
[test_bug812415.xul]

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

@ -1126,6 +1126,7 @@ protected:
enum GradientParsingFlags {
eGradient_Repeating = 1 << 0, // repeating-{linear|radial}-gradient
eGradient_MozLegacy = 1 << 1, // -moz-{linear|radial}-gradient
eGradient_WebkitLegacy = 1 << 2, // -webkit-{linear|radial}-gradient
};
bool ParseLinearGradient(nsCSSValue& aValue, uint8_t aFlags);
bool ParseRadialGradient(nsCSSValue& aValue, uint8_t aFlags);
@ -7481,6 +7482,10 @@ CSSParserImpl::ParseVariant(nsCSSValue& aValue,
StringBeginsWith(tmp, NS_LITERAL_STRING("-moz-"))) {
tmp.Rebind(tmp, 5);
gradientFlags |= eGradient_MozLegacy;
} else if (sWebkitPrefixedAliasesEnabled &&
StringBeginsWith(tmp, NS_LITERAL_STRING("-webkit-"))) {
tmp.Rebind(tmp, 8);
gradientFlags |= eGradient_WebkitLegacy;
}
if (StringBeginsWith(tmp, NS_LITERAL_STRING("repeating-"))) {
tmp.Rebind(tmp, 10);
@ -10681,10 +10686,12 @@ CSSParserImpl::IsFunctionTokenValidForBackgroundImage(
funcName.LowerCaseEqualsLiteral("-moz-repeating-radial-gradient") ||
funcName.LowerCaseEqualsLiteral("-moz-image-rect") ||
funcName.LowerCaseEqualsLiteral("-moz-element") ||
(ShouldUseUnprefixingService() &&
((sWebkitPrefixedAliasesEnabled || ShouldUseUnprefixingService()) &&
(funcName.LowerCaseEqualsLiteral("-webkit-gradient") ||
funcName.LowerCaseEqualsLiteral("-webkit-linear-gradient") ||
funcName.LowerCaseEqualsLiteral("-webkit-radial-gradient")));
funcName.LowerCaseEqualsLiteral("-webkit-radial-gradient") ||
funcName.LowerCaseEqualsLiteral("-webkit-repeating-linear-gradient") ||
funcName.LowerCaseEqualsLiteral("-webkit-repeating-radial-gradient")));
}
// Parse one item of the background shorthand property.

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

@ -616,6 +616,49 @@ var unbalancedGradientAndElementValues = [
"-moz-element(#a()",
];
if (IsCSSPropertyPrefEnabled("layout.css.prefixes.webkit")) {
// Extend gradient lists with valid/invalid webkit-prefixed expressions:
validGradientAndElementValues.push(
// Basic linear-gradient syntax (valid when prefixed or unprefixed):
"-webkit-linear-gradient(red, green, blue)",
// Angled linear-gradients (valid when prefixed or unprefixed):
"-webkit-linear-gradient(135deg, red, blue)",
"-webkit-linear-gradient(280deg, red 60%, blue)",
// Basic radial-gradient syntax (valid when prefixed or unprefixed):
"-webkit-radial-gradient(circle, white, black)",
"-webkit-radial-gradient(circle, white, black)",
"-webkit-radial-gradient(ellipse closest-side, white, black)",
"-webkit-radial-gradient(circle farthest-corner, white, black)",
// Repeating examples:
"-webkit-repeating-linear-gradient(red 10%, blue 30%)",
"-webkit-repeating-linear-gradient(30deg, pink 20px, orange 70px)",
"-webkit-repeating-radial-gradient(circle, red, blue 10%, red 20%)",
"-webkit-repeating-radial-gradient(circle farthest-corner, gray 10px, yellow 20px)"
);
invalidGradientAndElementValues.push(
// Syntax that's invalid for all types of gradients:
// * empty gradient expressions:
"-webkit-linear-gradient()",
"-webkit-radial-gradient()",
"-webkit-repeating-linear-gradient()",
"-webkit-repeating-radial-gradient()",
// Syntax that's invalid for both -webkit & -moz, but valid for unprefixed:
// XXXdholbert (populated in a later patch)
// Syntax that's invalid for both -webkit & unprefixed, but valid for -moz:
// * initial length
"-webkit-linear-gradient(10px, red, blue)"
// Syntax that's invalid for -webkit, but valid for -moz & unprefixed:
// XXXdholbert (populated in a later patch)
);
}
var gCSSProperties = {
"animation": {
domProp: "animation",

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

@ -727,9 +727,9 @@ Http2Stream::AdjustInitialWindow()
return;
}
uint8_t *packet = mTxInlineFrame.get() + mTxInlineFrameUsed;
EnsureBuffer(mTxInlineFrame, mTxInlineFrameUsed + Http2Session::kFrameHeaderBytes + 4,
mTxInlineFrameUsed, mTxInlineFrameSize);
uint8_t *packet = mTxInlineFrame.get() + mTxInlineFrameUsed;
mTxInlineFrameUsed += Http2Session::kFrameHeaderBytes + 4;
mSession->CreateFrameHeader(packet, 4,
@ -757,9 +757,9 @@ Http2Stream::AdjustPushedPriority()
if (mPushSource->RecvdFin() || mPushSource->RecvdReset())
return;
uint8_t *packet = mTxInlineFrame.get() + mTxInlineFrameUsed;
EnsureBuffer(mTxInlineFrame, mTxInlineFrameUsed + Http2Session::kFrameHeaderBytes + 5,
mTxInlineFrameUsed, mTxInlineFrameSize);
uint8_t *packet = mTxInlineFrame.get() + mTxInlineFrameUsed;
mTxInlineFrameUsed += Http2Session::kFrameHeaderBytes + 5;
mSession->CreateFrameHeader(packet, 5,

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

@ -443,35 +443,10 @@ nsCORSListenerProxy::nsCORSListenerProxy(nsIStreamListener* aOuter,
mOriginHeaderPrincipal(aRequestingPrincipal),
mWithCredentials(aWithCredentials && !gDisableCORSPrivateData),
mRequestApproved(false),
mHasBeenCrossSite(false),
mIsPreflight(false)
mHasBeenCrossSite(false)
{
}
nsCORSListenerProxy::nsCORSListenerProxy(nsIStreamListener* aOuter,
nsIPrincipal* aRequestingPrincipal,
bool aWithCredentials,
const nsCString& aPreflightMethod,
const nsTArray<nsCString>& aPreflightHeaders)
: mOuterListener(aOuter),
mRequestingPrincipal(aRequestingPrincipal),
mOriginHeaderPrincipal(aRequestingPrincipal),
mWithCredentials(aWithCredentials && !gDisableCORSPrivateData),
mRequestApproved(false),
mHasBeenCrossSite(false),
mIsPreflight(true),
#ifdef DEBUG
mInited(false),
#endif
mPreflightMethod(aPreflightMethod),
mPreflightHeaders(aPreflightHeaders)
{
for (uint32_t i = 0; i < mPreflightHeaders.Length(); ++i) {
ToLowerCase(mPreflightHeaders[i]);
}
mPreflightHeaders.Sort();
}
nsCORSListenerProxy::~nsCORSListenerProxy()
{
}
@ -570,7 +545,6 @@ nsCORSListenerProxy::CheckRequestApproved(nsIRequest* aRequest)
// For synthesized responses, we don't need to perform any checks.
// Note: This would be unsafe if we ever changed our behavior to allow
// service workers to intercept CORS preflights.
MOZ_ASSERT(!mIsPreflight);
return NS_OK;
}
@ -606,68 +580,6 @@ nsCORSListenerProxy::CheckRequestApproved(nsIRequest* aRequest)
}
}
if (mIsPreflight) {
bool succeedded;
rv = http->GetRequestSucceeded(&succeedded);
if (NS_FAILED(rv) || !succeedded) {
LogBlockedRequest(aRequest, "CORSPreflightDidNotSucceed", nullptr);
return NS_ERROR_DOM_BAD_URI;
}
nsAutoCString headerVal;
// The "Access-Control-Allow-Methods" header contains a comma separated
// list of method names.
http->GetResponseHeader(NS_LITERAL_CSTRING("Access-Control-Allow-Methods"),
headerVal);
bool foundMethod = mPreflightMethod.EqualsLiteral("GET") ||
mPreflightMethod.EqualsLiteral("HEAD") ||
mPreflightMethod.EqualsLiteral("POST");
nsCCharSeparatedTokenizer methodTokens(headerVal, ',');
while(methodTokens.hasMoreTokens()) {
const nsDependentCSubstring& method = methodTokens.nextToken();
if (method.IsEmpty()) {
continue;
}
if (!NS_IsValidHTTPToken(method)) {
LogBlockedRequest(aRequest, "CORSInvalidAllowMethod",
NS_ConvertUTF8toUTF16(method).get());
return NS_ERROR_DOM_BAD_URI;
}
foundMethod |= mPreflightMethod.Equals(method);
}
if (!foundMethod) {
LogBlockedRequest(aRequest, "CORSMethodNotFound", nullptr);
return NS_ERROR_DOM_BAD_URI;
}
// The "Access-Control-Allow-Headers" header contains a comma separated
// list of header names.
http->GetResponseHeader(NS_LITERAL_CSTRING("Access-Control-Allow-Headers"),
headerVal);
nsTArray<nsCString> headers;
nsCCharSeparatedTokenizer headerTokens(headerVal, ',');
while(headerTokens.hasMoreTokens()) {
const nsDependentCSubstring& header = headerTokens.nextToken();
if (header.IsEmpty()) {
continue;
}
if (!NS_IsValidHTTPToken(header)) {
LogBlockedRequest(aRequest, "CORSInvalidAllowHeader",
NS_ConvertUTF8toUTF16(header).get());
return NS_ERROR_DOM_BAD_URI;
}
headers.AppendElement(header);
}
for (uint32_t i = 0; i < mPreflightHeaders.Length(); ++i) {
if (!headers.Contains(mPreflightHeaders[i],
nsCaseInsensitiveCStringArrayComparator())) {
LogBlockedRequest(aRequest, "CORSMissingAllowHeaderFromPreflight",
NS_ConvertUTF8toUTF16(mPreflightHeaders[i]).get());
return NS_ERROR_DOM_BAD_URI;
}
}
}
return NS_OK;
}
@ -959,11 +871,7 @@ nsCORSListenerProxy::UpdateChannel(nsIChannel* aChannel,
// can't return early on failure.
nsCOMPtr<nsIHttpChannelInternal> internal = do_QueryInterface(aChannel);
if (internal) {
if (mIsPreflight) {
rv = internal->SetCorsMode(nsIHttpChannelInternal::CORS_MODE_CORS_WITH_FORCED_PREFLIGHT);
} else {
rv = internal->SetCorsMode(nsIHttpChannelInternal::CORS_MODE_CORS);
}
rv = internal->SetCorsMode(nsIHttpChannelInternal::CORS_MODE_CORS);
NS_ENSURE_SUCCESS(rv, rv);
rv = internal->SetCorsIncludeCredentials(mWithCredentials);
NS_ENSURE_SUCCESS(rv, rv);
@ -1019,30 +927,8 @@ nsCORSListenerProxy::UpdateChannel(nsIChannel* aChannel,
rv = http->SetRequestHeader(NS_LITERAL_CSTRING("Origin"), origin, false);
NS_ENSURE_SUCCESS(rv, rv);
// Add preflight headers if this is a preflight request
if (mIsPreflight) {
rv = http->
SetRequestHeader(NS_LITERAL_CSTRING("Access-Control-Request-Method"),
mPreflightMethod, false);
NS_ENSURE_SUCCESS(rv, rv);
if (!mPreflightHeaders.IsEmpty()) {
nsAutoCString headers;
for (uint32_t i = 0; i < mPreflightHeaders.Length(); ++i) {
if (i != 0) {
headers += ',';
}
headers += mPreflightHeaders[i];
}
rv = http->
SetRequestHeader(NS_LITERAL_CSTRING("Access-Control-Request-Headers"),
headers, false);
NS_ENSURE_SUCCESS(rv, rv);
}
}
// Make cookie-less if needed
if (mIsPreflight || !mWithCredentials) {
if (!mWithCredentials) {
nsLoadFlags flags;
rv = http->GetLoadFlags(&flags);
NS_ENSURE_SUCCESS(rv, rv);
@ -1065,16 +951,18 @@ class nsCORSPreflightListener final : public nsIStreamListener,
public nsIChannelEventSink
{
public:
nsCORSPreflightListener(nsIChannel* aOuterChannel,
nsIStreamListener* aOuterListener,
nsISupports* aOuterContext,
nsIPrincipal* aReferrerPrincipal,
nsCORSPreflightListener(nsIPrincipal* aReferrerPrincipal,
nsICorsPreflightCallback* aCallback,
bool aWithCredentials)
: mOuterChannel(aOuterChannel), mOuterListener(aOuterListener),
mOuterContext(aOuterContext), mReferrerPrincipal(aReferrerPrincipal),
mCallback(aCallback), mWithCredentials(aWithCredentials)
{ }
bool aWithCredentials,
const nsCString& aPreflightMethod,
const nsTArray<nsCString>& aPreflightHeaders)
: mPreflightMethod(aPreflightMethod),
mPreflightHeaders(aPreflightHeaders),
mReferrerPrincipal(aReferrerPrincipal),
mCallback(aCallback),
mWithCredentials(aWithCredentials)
{
}
NS_DECL_ISUPPORTS
NS_DECL_NSISTREAMLISTENER
@ -1082,14 +970,15 @@ public:
NS_DECL_NSIINTERFACEREQUESTOR
NS_DECL_NSICHANNELEVENTSINK
nsresult CheckPreflightRequestApproved(nsIRequest* aRequest);
private:
~nsCORSPreflightListener() {}
void AddResultToCache(nsIRequest* aRequest);
nsCOMPtr<nsIChannel> mOuterChannel;
nsCOMPtr<nsIStreamListener> mOuterListener;
nsCOMPtr<nsISupports> mOuterContext;
nsCString mPreflightMethod;
nsTArray<nsCString> mPreflightHeaders;
nsCOMPtr<nsIPrincipal> mReferrerPrincipal;
nsCOMPtr<nsICorsPreflightCallback> mCallback;
bool mWithCredentials;
@ -1216,12 +1105,21 @@ NS_IMETHODIMP
nsCORSPreflightListener::OnStartRequest(nsIRequest *aRequest,
nsISupports *aContext)
{
nsresult status;
nsresult rv = aRequest->GetStatus(&status);
if (NS_SUCCEEDED(rv)) {
rv = status;
#ifdef DEBUG
{
nsCOMPtr<nsIHttpChannelInternal> internal = do_QueryInterface(aRequest);
bool responseSynthesized = false;
if (internal &&
NS_SUCCEEDED(internal->GetResponseSynthesized(&responseSynthesized))) {
// For synthesized responses, we don't need to perform any checks.
// This would be unsafe if we ever changed our behavior to allow
// service workers to intercept CORS preflights.
MOZ_ASSERT(!responseSynthesized);
}
}
#endif
nsresult rv = CheckPreflightRequestApproved(aRequest);
if (NS_SUCCEEDED(rv)) {
// Everything worked, try to cache and then fire off the actual request.
@ -1240,9 +1138,6 @@ nsCORSPreflightListener::OnStopRequest(nsIRequest *aRequest,
nsISupports *aContext,
nsresult aStatus)
{
mOuterChannel = nullptr;
mOuterListener = nullptr;
mOuterContext = nullptr;
mCallback = nullptr;
return NS_OK;
}
@ -1275,6 +1170,82 @@ nsCORSPreflightListener::AsyncOnChannelRedirect(nsIChannel *aOldChannel,
return NS_OK;
}
nsresult
nsCORSPreflightListener::CheckPreflightRequestApproved(nsIRequest* aRequest)
{
nsresult status;
nsresult rv = aRequest->GetStatus(&status);
NS_ENSURE_SUCCESS(rv, rv);
NS_ENSURE_SUCCESS(status, status);
// Test that things worked on a HTTP level
nsCOMPtr<nsIHttpChannel> http = do_QueryInterface(aRequest);
nsCOMPtr<nsIHttpChannelInternal> internal = do_QueryInterface(aRequest);
NS_ENSURE_STATE(internal);
bool succeedded;
rv = http->GetRequestSucceeded(&succeedded);
if (NS_FAILED(rv) || !succeedded) {
LogBlockedRequest(aRequest, "CORSPreflightDidNotSucceed", nullptr);
return NS_ERROR_DOM_BAD_URI;
}
nsAutoCString headerVal;
// The "Access-Control-Allow-Methods" header contains a comma separated
// list of method names.
http->GetResponseHeader(NS_LITERAL_CSTRING("Access-Control-Allow-Methods"),
headerVal);
bool foundMethod = mPreflightMethod.EqualsLiteral("GET") ||
mPreflightMethod.EqualsLiteral("HEAD") ||
mPreflightMethod.EqualsLiteral("POST");
nsCCharSeparatedTokenizer methodTokens(headerVal, ',');
while(methodTokens.hasMoreTokens()) {
const nsDependentCSubstring& method = methodTokens.nextToken();
if (method.IsEmpty()) {
continue;
}
if (!NS_IsValidHTTPToken(method)) {
LogBlockedRequest(aRequest, "CORSInvalidAllowMethod",
NS_ConvertUTF8toUTF16(method).get());
return NS_ERROR_DOM_BAD_URI;
}
foundMethod |= mPreflightMethod.Equals(method);
}
if (!foundMethod) {
LogBlockedRequest(aRequest, "CORSMethodNotFound", nullptr);
return NS_ERROR_DOM_BAD_URI;
}
// The "Access-Control-Allow-Headers" header contains a comma separated
// list of header names.
http->GetResponseHeader(NS_LITERAL_CSTRING("Access-Control-Allow-Headers"),
headerVal);
nsTArray<nsCString> headers;
nsCCharSeparatedTokenizer headerTokens(headerVal, ',');
while(headerTokens.hasMoreTokens()) {
const nsDependentCSubstring& header = headerTokens.nextToken();
if (header.IsEmpty()) {
continue;
}
if (!NS_IsValidHTTPToken(header)) {
LogBlockedRequest(aRequest, "CORSInvalidAllowHeader",
NS_ConvertUTF8toUTF16(header).get());
return NS_ERROR_DOM_BAD_URI;
}
headers.AppendElement(header);
}
for (uint32_t i = 0; i < mPreflightHeaders.Length(); ++i) {
if (!headers.Contains(mPreflightHeaders[i],
nsCaseInsensitiveCStringArrayComparator())) {
LogBlockedRequest(aRequest, "CORSMissingAllowHeaderFromPreflight",
NS_ConvertUTF8toUTF16(mPreflightHeaders[i]).get());
return NS_ERROR_DOM_BAD_URI;
}
}
return NS_OK;
}
NS_IMETHODIMP
nsCORSPreflightListener::GetInterface(const nsIID & aIID, void **aResult)
{
@ -1293,7 +1264,6 @@ nsCORSListenerProxy::RemoveFromCorsPreflightCache(nsIURI* aURI,
nsresult
nsCORSListenerProxy::StartCORSPreflight(nsIChannel* aRequestChannel,
nsIStreamListener* aListener,
nsIPrincipal* aPrincipal,
nsICorsPreflightCallback* aCallback,
bool aWithCredentials,
@ -1302,6 +1272,11 @@ nsCORSListenerProxy::StartCORSPreflight(nsIChannel* aRequestChannel,
{
*aPreflightChannel = nullptr;
if (gDisableCORS) {
LogBlockedRequest(aRequestChannel, "CORSDisabled", nullptr);
return NS_ERROR_DOM_BAD_URI;
}
nsAutoCString method;
nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(aRequestChannel));
NS_ENSURE_TRUE(httpChannel, NS_ERROR_UNEXPECTED);
@ -1347,13 +1322,15 @@ nsCORSListenerProxy::StartCORSPreflight(nsIChannel* aRequestChannel,
rv = aRequestChannel->GetLoadFlags(&loadFlags);
NS_ENSURE_SUCCESS(rv, rv);
// Preflight requests should never be intercepted by service workers.
// Preflight requests should never be intercepted by service workers and
// are always anonymous.
// NOTE: We ignore CORS checks on synthesized responses (see the CORS
// preflights, then we need to extend the GetResponseSynthesized() check in
// nsCORSListenerProxy::CheckRequestApproved()). If we change our behavior
// here and allow service workers to intercept CORS preflights, then that
// check won't be safe any more.
loadFlags |= nsIChannel::LOAD_BYPASS_SERVICE_WORKER;
loadFlags |= nsIChannel::LOAD_BYPASS_SERVICE_WORKER |
nsIRequest::LOAD_ANONYMOUS;
nsCOMPtr<nsIChannel> preflightChannel;
rv = NS_NewChannelInternal(getter_AddRefs(preflightChannel),
@ -1364,17 +1341,45 @@ nsCORSListenerProxy::StartCORSPreflight(nsIChannel* aRequestChannel,
loadFlags);
NS_ENSURE_SUCCESS(rv, rv);
// Set method and headers
nsCOMPtr<nsIHttpChannel> preHttp = do_QueryInterface(preflightChannel);
NS_ASSERTION(preHttp, "Failed to QI to nsIHttpChannel!");
rv = preHttp->SetRequestMethod(NS_LITERAL_CSTRING("OPTIONS"));
NS_ENSURE_SUCCESS(rv, rv);
rv = preHttp->
SetRequestHeader(NS_LITERAL_CSTRING("Access-Control-Request-Method"),
method, false);
NS_ENSURE_SUCCESS(rv, rv);
nsTArray<nsCString> preflightHeaders;
if (!aUnsafeHeaders.IsEmpty()) {
for (uint32_t i = 0; i < aUnsafeHeaders.Length(); ++i) {
preflightHeaders.AppendElement();
ToLowerCase(aUnsafeHeaders[i], preflightHeaders[i]);
}
preflightHeaders.Sort();
nsAutoCString headers;
for (uint32_t i = 0; i < preflightHeaders.Length(); ++i) {
if (i != 0) {
headers += ',';
}
headers += preflightHeaders[i];
}
rv = preHttp->
SetRequestHeader(NS_LITERAL_CSTRING("Access-Control-Request-Headers"),
headers, false);
NS_ENSURE_SUCCESS(rv, rv);
}
// Set up listener which will start the original channel
nsCOMPtr<nsIStreamListener> preflightListener =
new nsCORSPreflightListener(aRequestChannel, aListener, nullptr, aPrincipal,
aCallback, aWithCredentials);
NS_ENSURE_TRUE(preflightListener, NS_ERROR_OUT_OF_MEMORY);
nsRefPtr<nsCORSPreflightListener> preflightListener =
new nsCORSPreflightListener(aPrincipal, aCallback, aWithCredentials,
method, preflightHeaders);
rv = preflightChannel->SetNotificationCallbacks(preflightListener);
NS_ENSURE_SUCCESS(rv, rv);
// Start preflight
if (securityMode == nsILoadInfo::SEC_REQUIRE_CORS_DATA_INHERITS) {
@ -1383,8 +1388,7 @@ nsCORSListenerProxy::StartCORSPreflight(nsIChannel* aRequestChannel,
else {
nsRefPtr<nsCORSListenerProxy> corsListener =
new nsCORSListenerProxy(preflightListener, aPrincipal,
aWithCredentials, method,
aUnsafeHeaders);
aWithCredentials);
rv = corsListener->Init(preflightChannel, DataURIHandling::Disallow);
NS_ENSURE_SUCCESS(rv, rv);
rv = preflightChannel->AsyncOpen(corsListener, nullptr);

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

@ -73,15 +73,7 @@ private:
static void RemoveFromCorsPreflightCache(nsIURI* aURI,
nsIPrincipal* aRequestingPrincipal);
nsCORSListenerProxy(nsIStreamListener* aOuter,
nsIPrincipal* aRequestingPrincipal,
bool aWithCredentials,
const nsCString& aPreflightMethod,
const nsTArray<nsCString>& aPreflightHeaders);
static nsresult StartCORSPreflight(nsIChannel* aRequestChannel,
nsIStreamListener* aListener,
nsIPrincipal* aPrincipal,
nsICorsPreflightCallback* aCallback,
bool aWithCredentials,
@ -108,12 +100,9 @@ private:
// an http: request to https: in nsHttpChannel::Connect() and hence
// a request might not be marked as cross site request based on that promise.
bool mHasBeenCrossSite;
bool mIsPreflight;
#ifdef DEBUG
bool mInited;
#endif
nsCString mPreflightMethod;
nsTArray<nsCString> mPreflightHeaders;
nsCOMPtr<nsIAsyncVerifyRedirectCallback> mRedirectCallback;
nsCOMPtr<nsIChannel> mOldRedirectChannel;
nsCOMPtr<nsIChannel> mNewRedirectChannel;

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

@ -456,7 +456,7 @@ nsHttpChannel::ContinueConnect()
mInterceptCache != INTERCEPTED) {
MOZ_ASSERT(!mPreflightChannel);
nsresult rv =
nsCORSListenerProxy::StartCORSPreflight(this, mListener,
nsCORSListenerProxy::StartCORSPreflight(this,
mPreflightPrincipal, this,
mWithCredentials,
mUnsafeHeaders,

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

@ -9851,6 +9851,13 @@
"kind": "count",
"description": "Number of times the D3D11 compositor failed to get a texture sync handle."
},
"GFX_CRASH": {
"expires_in_version": "never",
"kind": "enumerated",
"n_values": 100,
"releaseChannelCollection": "opt-out",
"description": "Graphics Crash Reason (...)"
},
"PLUGIN_ACTIVATION_COUNT": {
"alert_emails": ["cpeterson@mozilla.com"],
"expires_in_version": "48",

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

@ -15,7 +15,7 @@ DEFINES['CFLAGS'] = CONFIG['OS_CFLAGS']
if CONFIG['OS_TARGET'] == 'Android':
DEFINES['ANDROID_PACKAGE_NAME'] = CONFIG['ANDROID_PACKAGE_NAME']
if 'stlport' in CONFIG['STLPORT_LIBS']:
if CONFIG['MOZ_ANDROID_CXX_STL'] == 'mozstlport':
DEFINES['USE_STLPORT'] = True
JAR_MANIFESTS += ['jar.mn']

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

@ -66,9 +66,9 @@ static nsWindow *gFocusedWindow = nullptr;
NS_IMPL_ISUPPORTS_INHERITED0(nsWindow, nsBaseWidget)
nsWindow::nsWindow()
: mFramebuffer(nullptr)
, mMappedBuffer(nullptr)
{
mFramebuffer = nullptr;
nsRefPtr<nsScreenManagerGonk> screenManager = nsScreenManagerGonk::GetInstance();
screenManager->Initialize();
@ -630,20 +630,18 @@ gralloc_module()
}
static SurfaceFormat
HalFormatToSurfaceFormat(int aHalFormat, int* bytepp)
HalFormatToSurfaceFormat(int aHalFormat)
{
switch (aHalFormat) {
case HAL_PIXEL_FORMAT_RGBA_8888:
*bytepp = 4;
return SurfaceFormat::R8G8B8A8;
// Needs RB swap
return SurfaceFormat::B8G8R8A8;
case HAL_PIXEL_FORMAT_RGBX_8888:
*bytepp = 4;
return SurfaceFormat::R8G8B8X8;
// Needs RB swap
return SurfaceFormat::B8G8R8X8;
case HAL_PIXEL_FORMAT_BGRA_8888:
*bytepp = 4;
return SurfaceFormat::B8G8R8A8;
case HAL_PIXEL_FORMAT_RGB_565:
*bytepp = 2;
return SurfaceFormat::R5G6B5;
default:
MOZ_CRASH("Unhandled HAL pixel format");
@ -651,26 +649,46 @@ HalFormatToSurfaceFormat(int aHalFormat, int* bytepp)
}
}
static bool
NeedsRBSwap(int aHalFormat)
{
switch (aHalFormat) {
case HAL_PIXEL_FORMAT_RGBA_8888:
return true;
case HAL_PIXEL_FORMAT_RGBX_8888:
return true;
case HAL_PIXEL_FORMAT_BGRA_8888:
return false;
case HAL_PIXEL_FORMAT_RGB_565:
return false;
default:
MOZ_CRASH("Unhandled HAL pixel format");
return false; // not reached
}
}
already_AddRefed<DrawTarget>
nsWindow::StartRemoteDrawing()
{
mFramebuffer = mScreen->DequeueBuffer();
int width = mFramebuffer->width, height = mFramebuffer->height;
void *vaddr;
if (gralloc_module()->lock(gralloc_module(), mFramebuffer->handle,
GRALLOC_USAGE_SW_READ_NEVER |
GRALLOC_USAGE_SW_WRITE_OFTEN |
GRALLOC_USAGE_HW_FB,
0, 0, width, height, &vaddr)) {
0, 0, width, height,
reinterpret_cast<void**>(&mMappedBuffer))) {
EndRemoteDrawing();
return nullptr;
}
int bytepp;
SurfaceFormat format = HalFormatToSurfaceFormat(mScreen->GetSurfaceFormat(),
&bytepp);
SurfaceFormat format = HalFormatToSurfaceFormat(mScreen->GetSurfaceFormat());
mFramebufferTarget = Factory::CreateDrawTargetForData(
BackendType::CAIRO, (uint8_t*)vaddr,
IntSize(width, height), mFramebuffer->stride * bytepp, format);
BackendType::CAIRO,
mMappedBuffer,
IntSize(width, height),
mFramebuffer->stride * gfx::BytesPerPixel(format),
format);
if (!mFramebufferTarget) {
MOZ_CRASH("nsWindow::StartRemoteDrawing failed in CreateDrawTargetForData");
}
@ -687,12 +705,24 @@ nsWindow::StartRemoteDrawing()
void
nsWindow::EndRemoteDrawing()
{
if (mFramebufferTarget) {
if (mFramebufferTarget && mFramebuffer) {
IntSize size = mFramebufferTarget->GetSize();
Rect rect(0, 0, size.width, size.height);
RefPtr<SourceSurface> source = mBackBuffer->Snapshot();
mFramebufferTarget->DrawSurface(source, rect, rect);
gralloc_module()->unlock(gralloc_module(), mFramebuffer->handle);
// Convert from BGR to RGB
// XXX this is a temporary solution. It consumes extra cpu cycles,
// it should not be used on product device.
if (NeedsRBSwap(mScreen->GetSurfaceFormat())) {
LOGE("Very slow composition path, it should not be used on product!!!");
SurfaceFormat format = HalFormatToSurfaceFormat(mScreen->GetSurfaceFormat());
gfxUtils::ConvertBGRAtoRGBA(
mMappedBuffer,
mFramebuffer->stride * mFramebuffer->height * gfx::BytesPerPixel(format));
mMappedBuffer = nullptr;
gralloc_module()->unlock(gralloc_module(), mFramebuffer->handle);
}
}
if (mFramebuffer) {
mScreen->QueueBuffer(mFramebuffer);

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

@ -142,6 +142,11 @@ protected:
// framebuffer.
mozilla::RefPtr<mozilla::gfx::DrawTarget> mFramebufferTarget;
ANativeWindowBuffer* mFramebuffer;
/**
* Points to a mapped gralloc buffer between calls to lock and unlock.
* Should be null outside of the lock-unlock pair.
*/
uint8_t* mMappedBuffer;
// If we're using a BasicCompositor, this is our window back
// buffer. The gralloc framebuffer driver expects us to draw the
// entire framebuffer on every frame, but gecko expects the