merge mozilla-inbound to mozilla-central a=merge

This commit is contained in:
Carsten "Tomcat" Book 2015-11-04 11:59:46 +01:00
commit 7fd446b11f
283 changed files with 12435 additions and 4932 deletions

View File

@ -22,4 +22,4 @@
# changes to stick? As of bug 928195, this shouldn't be necessary! Please
# don't change CLOBBER for WebIDL changes any more.
Merge day clobber
Bug 1214058 New xpcshell test not getting picked up

View File

@ -1238,11 +1238,13 @@ Accessible::ApplyARIAState(uint64_t* aState) const
*aState &= ~states::READONLY;
if (mContent->HasID()) {
// If has a role & ID and aria-activedescendant on the container, assume focusable
nsIContent *ancestorContent = mContent;
while ((ancestorContent = ancestorContent->GetParent()) != nullptr) {
if (ancestorContent->HasAttr(kNameSpaceID_None, nsGkAtoms::aria_activedescendant)) {
// ancestor has activedescendant property, this content could be active
// If has a role & ID and aria-activedescendant on the container, assume
// focusable.
const Accessible* ancestor = this;
while ((ancestor = ancestor->Parent()) && !ancestor->IsDoc()) {
dom::Element* el = ancestor->Elm();
if (el &&
el->HasAttr(kNameSpaceID_None, nsGkAtoms::aria_activedescendant)) {
*aState |= states::FOCUSABLE;
break;
}
@ -1251,12 +1253,12 @@ Accessible::ApplyARIAState(uint64_t* aState) const
}
if (*aState & states::FOCUSABLE) {
// Special case: aria-disabled propagates from ancestors down to any focusable descendant
nsIContent *ancestorContent = mContent;
while ((ancestorContent = ancestorContent->GetParent()) != nullptr) {
if (ancestorContent->AttrValueIs(kNameSpaceID_None, nsGkAtoms::aria_disabled,
nsGkAtoms::_true, eCaseMatters)) {
// ancestor has aria-disabled property, this is disabled
// Propogate aria-disabled from ancestors down to any focusable descendant.
const Accessible* ancestor = this;
while ((ancestor = ancestor->Parent()) && !ancestor->IsDoc()) {
dom::Element* el = ancestor->Elm();
if (el && el->AttrValueIs(kNameSpaceID_None, nsGkAtoms::aria_disabled,
nsGkAtoms::_true, eCaseMatters)) {
*aState |= states::UNAVAILABLE;
break;
}

View File

@ -191,6 +191,12 @@
testGroupAttrs("table_cell", 3, 4);
testGroupAttrs("table_row", 2, 2);
//////////////////////////////////////////////////////////////////////////
// ARIA list constructed by ARIA owns
testGroupAttrs("t1_li1", 1, 3);
testGroupAttrs("t1_li2", 2, 3);
testGroupAttrs("t1_li3", 3, 3);
// Test that group position information updates after deleting node.
testGroupAttrs("tree4_ti1", 1, 2, 1);
testGroupAttrs("tree4_ti2", 2, 2, 1);
@ -453,5 +459,11 @@
<div role="cell" id="table_cell" aria-colindex="3">cell</div>
</div>
</div>
<div role="list" aria-owns="t1_li1 t1_li2 t1_li3">
<div role="listitem" id="t1_li2">Apples</div>
<div role="listitem" id="t1_li1">Oranges</div>
</span>
<div role="listitem" id="t1_li3">Bananas</div>
</body>
</html>

View File

@ -51,7 +51,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=429547
var container = getNode(aID);
var itemNode = document.createElement("div");
itemNode.setAttribute("id", aNewItemID);
itemNode.textContent = "item3";
itemNode.textContent = aNewItemID;
container.appendChild(itemNode);
container.setAttribute("aria-activedescendant", aNewItemID);
@ -68,14 +68,15 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=429547
{
gQueue = new eventQueue();
gQueue.push(new synthFocus("container", new focusChecker("item1")));
gQueue.push(new changeARIAActiveDescendant("container", "item2"));
gQueue.push(new synthFocus("listbox", new focusChecker("item1")));
gQueue.push(new changeARIAActiveDescendant("listbox", "item2"));
gQueue.push(new changeARIAActiveDescendant("listbox", "item3"));
gQueue.push(new synthFocus("combobox_entry", new focusChecker("combobox_entry")));
gQueue.push(new changeARIAActiveDescendant("combobox", "combobox_option2"));
todo(false, "No focus for inserted element, bug 687011");
//gQueue.push(new insertItemNFocus("container", "item3"));
//gQueue.push(new insertItemNFocus("listbox", "item4"));
gQueue.invoke(); // Will call SimpleTest.finish();
}
@ -101,10 +102,12 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=429547
<pre id="test">
</pre>
<div role="listbox" aria-activedescendant="item1" id="container" tabindex="1">
<div role="listbox" aria-activedescendant="item1" id="listbox" tabindex="1"
aria-owns="item3">
<div role="listitem" id="item1">item1</div>
<div role="listitem" id="item2">item2</div>
</div>
<div role="listitem" id="item3">item3</div>
<div role="combobox" id="combobox">
<input id="combobox_entry">

View File

@ -500,7 +500,8 @@
<!-- Test that aria-disabled state gets propagated to all descendants -->
<div id="group" role="group" aria-disabled="true">
<button>hi</button>
<div tabindex="0" role="listbox" aria-activedescendant="item1">
<div tabindex="0" role="listbox" aria-activedescendant="item1"
aria-owns="item5">
<div role="option" id="item1">Item 1</div>
<div role="option" id="item2">Item 2</div>
<div role="option" id="item3">Item 3</div>
@ -508,6 +509,7 @@
</div>
<div role="slider" tabindex="0">A slider</div>
</div>
<div role="option" id="item5">Item 5</div>
<!-- Test active state -->
<div id="as_listbox" tabindex="0" role="listbox"

View File

@ -2934,8 +2934,8 @@ var SessionStoreInternal = {
// In case we didn't collect/receive data for any tabs yet we'll have to
// fill the array with at least empty tabData objects until |_tPos| or
// we'll end up with |null| entries.
for (let tab of Array.slice(tabbrowser.tabs, 0, tab._tPos)) {
let emptyState = {entries: [], lastAccessed: tab.lastAccessed};
for (let otherTab of Array.slice(tabbrowser.tabs, 0, tab._tPos)) {
let emptyState = {entries: [], lastAccessed: otherTab.lastAccessed};
this._windows[window.__SSi].tabs.push(emptyState);
}

View File

@ -2162,8 +2162,8 @@ if (AppConstants.MOZ_SERVICES_HEALTHREPORT) {
_serializeJSONDaily: function(data) {
let result = {_v: this.version };
for (let [field, data] of data) {
result[field] = data;
for (let [field, value] of data) {
result[field] = value;
}
return result;

View File

@ -8,5 +8,13 @@
"algorithm": "sha512",
"filename": "clang.tar.bz2",
"unpack": true
},
{
"size": 12057960,
"digest": "6105d6432943141cffb40020dc5ba3a793650bdeb3af9bd5e56d3796c5f03df9962a73e521646cd71fbfb5e266c1e74716ad722fb6055589dfb7d35175bca89e",
"algorithm": "sha512",
"filename": "gtk3.tar.xz",
"setup": "setup.sh",
"unpack": true
}
]

View File

@ -109,6 +109,7 @@ leak:libdricore.so
leak:libGL.so
leak:libglib-2.0.so
leak:libp11-kit.so
leak:libpixman-1.so
leak:libpulse.so
leak:libpulsecommon-1.1.so
leak:libresolv.so

View File

@ -1,30 +1,29 @@
# To do try builds with Gtk+2, uncomment the following line, and remove
# everything after that.
#ac_add_options --enable-default-toolkit=cairo-gtk2
TOOLTOOL_DIR=${TOOLTOOL_DIR:-$topsrcdir}
# $TOOLTOOL_DIR/gtk3 comes from tooltool, when the tooltool manifest contains it.
if [ -d "$TOOLTOOL_DIR/gtk3" ]; then
if [ -z "$PKG_CONFIG_LIBDIR" ]; then
echo PKG_CONFIG_LIBDIR must be set >&2
exit 1
fi
export PKG_CONFIG_SYSROOT_DIR="$TOOLTOOL_DIR/gtk3"
export PKG_CONFIG_PATH="$TOOLTOOL_DIR/gtk3/usr/local/lib/pkgconfig"
PKG_CONFIG="$TOOLTOOL_DIR/gtk3/usr/local/bin/pkg-config"
export PATH="$TOOLTOOL_DIR/gtk3/usr/local/bin:${PATH}"
# Ensure cairo, gdk-pixbuf, etc. are not taken from the system installed packages.
LDFLAGS="-L$TOOLTOOL_DIR/gtk3/usr/local/lib ${LDFLAGS}"
ac_add_options --enable-default-toolkit=cairo-gtk3
# Set things up to use Gtk+3 from the tooltool package
mk_add_options "export FONTCONFIG_PATH=$TOOLTOOL_DIR/gtk3/usr/local/etc/fonts"
mk_add_options "export PANGO_SYSCONFDIR=$TOOLTOOL_DIR/gtk3/usr/local/etc"
mk_add_options "export PANGO_LIBDIR=$TOOLTOOL_DIR/gtk3/usr/local/lib"
mk_add_options "export GDK_PIXBUF_MODULE_FILE=$TOOLTOOL_DIR/gtk3/usr/local/lib/gdk-pixbuf-2.0/2.10.0/loaders.cache"
mk_add_options "export GDK_PIXBUF_MODULEDIR=$TOOLTOOL_DIR/gtk3/usr/local/lib/gdk-pixbuf-2.0/2.10.0/loaders"
mk_add_options "export LD_LIBRARY_PATH=$TOOLTOOL_DIR/gtk3/usr/local/lib"
# Until a tooltool with bug 1188571 landed is available everywhere
$TOOLTOOL_DIR/gtk3/setup.sh
else
PKG_CONFIG=pkg-config
ac_add_options --enable-default-toolkit=cairo-gtk2
# $TOOLTOOL_DIR/gtk3 comes from tooltool, and must be included in the tooltool manifest.
if [ -z "$PKG_CONFIG_LIBDIR" ]; then
echo PKG_CONFIG_LIBDIR must be set >&2
exit 1
fi
export PKG_CONFIG_SYSROOT_DIR="$TOOLTOOL_DIR/gtk3"
export PKG_CONFIG_PATH="$TOOLTOOL_DIR/gtk3/usr/local/lib/pkgconfig"
PKG_CONFIG="$TOOLTOOL_DIR/gtk3/usr/local/bin/pkg-config"
export PATH="$TOOLTOOL_DIR/gtk3/usr/local/bin:${PATH}"
# Ensure cairo, gdk-pixbuf, etc. are not taken from the system installed packages.
LDFLAGS="-L$TOOLTOOL_DIR/gtk3/usr/local/lib ${LDFLAGS}"
ac_add_options --enable-default-toolkit=cairo-gtk3
# Set things up to use Gtk+3 from the tooltool package
mk_add_options "export FONTCONFIG_PATH=$TOOLTOOL_DIR/gtk3/usr/local/etc/fonts"
mk_add_options "export PANGO_SYSCONFDIR=$TOOLTOOL_DIR/gtk3/usr/local/etc"
mk_add_options "export PANGO_LIBDIR=$TOOLTOOL_DIR/gtk3/usr/local/lib"
mk_add_options "export GDK_PIXBUF_MODULE_FILE=$TOOLTOOL_DIR/gtk3/usr/local/lib/gdk-pixbuf-2.0/2.10.0/loaders.cache"
mk_add_options "export GDK_PIXBUF_MODULEDIR=$TOOLTOOL_DIR/gtk3/usr/local/lib/gdk-pixbuf-2.0/2.10.0/loaders"
mk_add_options "export LD_LIBRARY_PATH=$TOOLTOOL_DIR/gtk3/usr/local/lib"
# Until a tooltool with bug 1188571 landed is available everywhere
$TOOLTOOL_DIR/gtk3/setup.sh

View File

@ -1341,7 +1341,7 @@ endif
# it.
ifneq (,$(filter-out all chrome default export realchrome clean clobber clobber_all distclean realclean,$(MAKECMDGOALS)))
MDDEPEND_FILES := $(strip $(wildcard $(addprefix $(MDDEPDIR)/,$(EXTRA_MDDEPEND_FILES) $(addsuffix .pp,$(notdir $(sort $(OBJS) $(PROGOBJS) $(HOST_OBJS) $(HOST_PROGOBJS)))))))
MDDEPEND_FILES := $(strip $(wildcard $(addprefix $(MDDEPDIR)/,$(addsuffix .pp,$(notdir $(sort $(OBJS) $(PROGOBJS) $(HOST_OBJS) $(HOST_PROGOBJS)))))))
ifneq (,$(MDDEPEND_FILES))
$(call include_deps,$(MDDEPEND_FILES))
@ -1349,16 +1349,12 @@ endif
endif
ifneq (,$(filter export,$(MAKECMDGOALS)))
MDDEPEND_FILES := $(strip $(wildcard $(addprefix $(MDDEPDIR)/,$(EXTRA_EXPORT_MDDEPEND_FILES))))
MDDEPEND_FILES := $(strip $(wildcard $(addprefix $(MDDEPDIR)/,$(EXTRA_MDDEPEND_FILES))))
ifneq (,$(MDDEPEND_FILES))
$(call include_deps,$(MDDEPEND_FILES))
endif
endif
#############################################################################
-include $(topsrcdir)/$(MOZ_BUILD_APP)/app-rules.mk

View File

@ -265,7 +265,8 @@ self.random = {
{
let h, n = 0xefc8249d;
for (let i = 0, data = data.toString(), len = data.length; i < len; i++) {
data = data.toString();
for (let i = 0, len = data.length; i < len; i++) {
n += data.charCodeAt(i);
h = 0.02519603282416938 * n;
n = h >>> 0;

View File

@ -126,8 +126,8 @@ function recursiveWalk(breakdown, edge, report, visitor) {
visitor.exit(breakdown, report, edge);
} else {
visitor.enter(breakdown, report, edge);
for (let { edge, referent, breakdown } of getReportEdges(breakdown, report)) {
recursiveWalk(breakdown, edge, referent, visitor);
for (let { edge, referent, breakdown: subBreakdown } of getReportEdges(breakdown, report)) {
recursiveWalk(subBreakdown, edge, referent, visitor);
}
visitor.exit(breakdown, report, edge);
}

View File

@ -79,6 +79,27 @@ ConsoleReportCollector::FlushConsoleReports(nsIDocument* aDocument)
}
}
void
ConsoleReportCollector::FlushConsoleReports(nsIConsoleReportCollector* aCollector)
{
MOZ_ASSERT(aCollector);
nsTArray<PendingReport> reports;
{
MutexAutoLock lock(mMutex);
mPendingReports.SwapElements(reports);
}
for (uint32_t i = 0; i < reports.Length(); ++i) {
PendingReport& report = reports[i];
aCollector->AddConsoleReport(report.mErrorFlags, report.mCategory,
report.mPropertiesFile, report.mSourceFileURI,
report.mLineNumber, report.mColumnNumber,
report.mMessageName, report.mStringParams);
}
}
ConsoleReportCollector::~ConsoleReportCollector()
{
}

View File

@ -29,6 +29,9 @@ public:
void
FlushConsoleReports(nsIDocument* aDocument) override;
void
FlushConsoleReports(nsIConsoleReportCollector* aCollector) override;
private:
~ConsoleReportCollector();

View File

@ -32,6 +32,7 @@
#include "nsIDocument.h"
#include "nsIDOMEvent.h"
#include "nsWeakPtr.h"
#include "ScriptSettings.h"
using mozilla::Unused; // <snicker>
using namespace mozilla::dom;
@ -650,7 +651,10 @@ nsContentPermissionRequestProxy::Allow(JS::HandleValue aChoices)
for (uint32_t i = 0; i < mPermissionRequests.Length(); ++i) {
nsCString type = mPermissionRequests[i].type();
mozilla::AutoSafeJSContext cx;
AutoJSAPI jsapi;
jsapi.Init();
JSContext* cx = jsapi.cx();
JS::Rooted<JSObject*> obj(cx, &aChoices.toObject());
JSAutoCompartment ac(cx, obj);
@ -658,10 +662,12 @@ nsContentPermissionRequestProxy::Allow(JS::HandleValue aChoices)
if (!JS_GetProperty(cx, obj, type.BeginReading(), &val) ||
!val.isString()) {
// no setting for the permission type, skip it
// no setting for the permission type, clear exception and skip it
jsapi.ClearException();
} else {
nsAutoJSString choice;
if (!choice.init(cx, val)) {
jsapi.ClearException();
return NS_ERROR_FAILURE;
}
choices.AppendElement(PermissionChoice(type, choice));

View File

@ -66,7 +66,7 @@ public:
aLineNumber, aColumnNumber, aMessageName, params);
}
// Flush all pending reports to the console.
// Flush all pending reports to the console. Main thread only.
//
// aDocument An optional document representing where to flush the
// reports. If provided, then the corresponding window's
@ -74,6 +74,14 @@ public:
// go to the browser console.
virtual void
FlushConsoleReports(nsIDocument* aDocument) = 0;
// Flush all pending reports to another collector. May be called from any
// thread.
//
// aCollector A required collector object that will effectively take
// ownership of our currently console reports.
virtual void
FlushConsoleReports(nsIConsoleReportCollector* aCollector) = 0;
};
NS_DEFINE_STATIC_IID_ACCESSOR(nsIConsoleReportCollector, NS_NSICONSOLEREPORTCOLLECTOR_IID)

View File

@ -329,6 +329,12 @@ JSObject* GetDefaultScopeFromJSContext(JSContext *cx)
bool nsAutoJSString::init(const JS::Value &v)
{
return init(nsContentUtils::RootingCxForThread(), v);
JSContext* cx = nsContentUtils::RootingCxForThread();
if (!init(nsContentUtils::RootingCxForThread(), v)) {
JS_ClearPendingException(cx);
return false;
}
return true;
}

View File

@ -102,6 +102,8 @@ skip-if = (toolkit == 'gonk' && !debug)
[test_browserElement_oop_VisibilityChange.html]
[test_browserElement_oop_XFrameOptions.html]
[test_browserElement_oop_XFrameOptionsAllowFrom.html]
# bug 1189592
skip-if = asan
[test_browserElement_oop_XFrameOptionsDeny.html]
[test_browserElement_oop_XFrameOptionsSameOrigin.html]
# Disabled until bug 930449 makes it stop timing out

View File

@ -21,10 +21,16 @@ using namespace dom;
using namespace gfx;
struct ImageCacheKey {
ImageCacheKey(Element* aImage, HTMLCanvasElement* aCanvas)
: mImage(aImage), mCanvas(aCanvas) {}
ImageCacheKey(Element* aImage,
HTMLCanvasElement* aCanvas,
bool aIsAccelerated)
: mImage(aImage)
, mCanvas(aCanvas)
, mIsAccelerated(aIsAccelerated)
{}
Element* mImage;
HTMLCanvasElement* mCanvas;
bool mIsAccelerated;
};
struct ImageCacheEntryData {
@ -32,6 +38,7 @@ struct ImageCacheEntryData {
: mImage(aOther.mImage)
, mILC(aOther.mILC)
, mCanvas(aOther.mCanvas)
, mIsAccelerated(aOther.mIsAccelerated)
, mRequest(aOther.mRequest)
, mSourceSurface(aOther.mSourceSurface)
, mSize(aOther.mSize)
@ -40,6 +47,7 @@ struct ImageCacheEntryData {
: mImage(aKey.mImage)
, mILC(nullptr)
, mCanvas(aKey.mCanvas)
, mIsAccelerated(aKey.mIsAccelerated)
{}
nsExpirationState* GetExpirationState() { return &mState; }
@ -50,6 +58,7 @@ struct ImageCacheEntryData {
RefPtr<Element> mImage;
nsIImageLoadingContent* mILC;
RefPtr<HTMLCanvasElement> mCanvas;
bool mIsAccelerated;
// Value
nsCOMPtr<imgIRequest> mRequest;
RefPtr<SourceSurface> mSourceSurface;
@ -70,46 +79,61 @@ public:
bool KeyEquals(KeyTypePointer key) const
{
return mData->mImage == key->mImage && mData->mCanvas == key->mCanvas;
return mData->mImage == key->mImage &&
mData->mCanvas == key->mCanvas &&
mData->mIsAccelerated == key->mIsAccelerated;
}
static KeyTypePointer KeyToPointer(KeyType& key) { return &key; }
static PLDHashNumber HashKey(KeyTypePointer key)
{
return HashGeneric(key->mImage, key->mCanvas);
return HashGeneric(key->mImage, key->mCanvas, key->mIsAccelerated);
}
enum { ALLOW_MEMMOVE = true };
nsAutoPtr<ImageCacheEntryData> mData;
};
struct SimpleImageCacheKey {
SimpleImageCacheKey(const imgIRequest* aImage,
bool aIsAccelerated)
: mImage(aImage)
, mIsAccelerated(aIsAccelerated)
{}
const imgIRequest* mImage;
bool mIsAccelerated;
};
class SimpleImageCacheEntry : public PLDHashEntryHdr {
public:
typedef imgIRequest& KeyType;
typedef const imgIRequest* KeyTypePointer;
typedef SimpleImageCacheKey KeyType;
typedef const SimpleImageCacheKey* KeyTypePointer;
explicit SimpleImageCacheEntry(KeyTypePointer aKey)
: mRequest(const_cast<imgIRequest*>(aKey))
: mRequest(const_cast<imgIRequest*>(aKey->mImage))
, mIsAccelerated(aKey->mIsAccelerated)
{}
SimpleImageCacheEntry(const SimpleImageCacheEntry &toCopy)
: mRequest(toCopy.mRequest)
, mIsAccelerated(toCopy.mIsAccelerated)
, mSourceSurface(toCopy.mSourceSurface)
{}
~SimpleImageCacheEntry() {}
bool KeyEquals(KeyTypePointer key) const
{
return key == mRequest;
return key->mImage == mRequest && key->mIsAccelerated == mIsAccelerated;
}
static KeyTypePointer KeyToPointer(KeyType key) { return &key; }
static KeyTypePointer KeyToPointer(KeyType& key) { return &key; }
static PLDHashNumber HashKey(KeyTypePointer key)
{
return NS_PTR_TO_UINT32(key) >> 2;
return HashGeneric(key->mImage, key->mIsAccelerated);
}
enum { ALLOW_MEMMOVE = true };
nsCOMPtr<imgIRequest> mRequest;
bool mIsAccelerated;
RefPtr<SourceSurface> mSourceSurface;
};
@ -130,8 +154,8 @@ public:
mTotal -= aObject->SizeInBytes();
RemoveObject(aObject);
// Deleting the entry will delete aObject since the entry owns aObject
mSimpleCache.RemoveEntry(*aObject->mRequest);
mCache.RemoveEntry(ImageCacheKey(aObject->mImage, aObject->mCanvas));
mSimpleCache.RemoveEntry(SimpleImageCacheKey(aObject->mRequest, aObject->mIsAccelerated));
mCache.RemoveEntry(ImageCacheKey(aObject->mImage, aObject->mCanvas, aObject->mIsAccelerated));
}
nsTHashtable<ImageCacheEntry> mCache;
@ -237,20 +261,22 @@ CanvasImageCache::NotifyDrawImage(Element* aImage,
HTMLCanvasElement* aCanvas,
imgIRequest* aRequest,
SourceSurface* aSource,
const IntSize& aSize)
const IntSize& aSize,
bool aIsAccelerated)
{
if (!gImageCache) {
gImageCache = new ImageCache();
nsContentUtils::RegisterShutdownObserver(new CanvasImageCacheShutdownObserver());
}
ImageCacheEntry* entry = gImageCache->mCache.PutEntry(ImageCacheKey(aImage, aCanvas));
ImageCacheEntry* entry =
gImageCache->mCache.PutEntry(ImageCacheKey(aImage, aCanvas, aIsAccelerated));
if (entry) {
if (entry->mData->mSourceSurface) {
// We are overwriting an existing entry.
gImageCache->mTotal -= entry->mData->SizeInBytes();
gImageCache->RemoveObject(entry->mData);
gImageCache->mSimpleCache.RemoveEntry(*entry->mData->mRequest);
gImageCache->mSimpleCache.RemoveEntry(SimpleImageCacheKey(entry->mData->mRequest, entry->mData->mIsAccelerated));
}
gImageCache->AddObject(entry->mData);
@ -267,7 +293,7 @@ CanvasImageCache::NotifyDrawImage(Element* aImage,
if (entry->mData->mRequest) {
SimpleImageCacheEntry* simpleentry =
gImageCache->mSimpleCache.PutEntry(*entry->mData->mRequest);
gImageCache->mSimpleCache.PutEntry(SimpleImageCacheKey(entry->mData->mRequest, aIsAccelerated));
simpleentry->mSourceSurface = aSource;
}
}
@ -283,12 +309,14 @@ CanvasImageCache::NotifyDrawImage(Element* aImage,
SourceSurface*
CanvasImageCache::Lookup(Element* aImage,
HTMLCanvasElement* aCanvas,
gfx::IntSize* aSize)
gfx::IntSize* aSize,
bool aIsAccelerated)
{
if (!gImageCache)
return nullptr;
ImageCacheEntry* entry = gImageCache->mCache.GetEntry(ImageCacheKey(aImage, aCanvas));
ImageCacheEntry* entry =
gImageCache->mCache.GetEntry(ImageCacheKey(aImage, aCanvas, aIsAccelerated));
if (!entry || !entry->mData->mILC)
return nullptr;
@ -304,7 +332,8 @@ CanvasImageCache::Lookup(Element* aImage,
}
SourceSurface*
CanvasImageCache::SimpleLookup(Element* aImage)
CanvasImageCache::SimpleLookup(Element* aImage,
bool aIsAccelerated)
{
if (!gImageCache)
return nullptr;
@ -319,7 +348,7 @@ CanvasImageCache::SimpleLookup(Element* aImage)
if (!request)
return nullptr;
SimpleImageCacheEntry* entry = gImageCache->mSimpleCache.GetEntry(*request);
SimpleImageCacheEntry* entry = gImageCache->mSimpleCache.GetEntry(SimpleImageCacheKey(request, aIsAccelerated));
if (!entry)
return nullptr;

View File

@ -33,7 +33,8 @@ public:
dom::HTMLCanvasElement* aCanvas,
imgIRequest* aRequest,
SourceSurface* aSource,
const gfx::IntSize& aSize);
const gfx::IntSize& aSize,
bool aIsAccelerated);
/**
* Check whether aImage has recently been drawn into aCanvas. If we return
@ -43,14 +44,16 @@ public:
*/
static SourceSurface* Lookup(dom::Element* aImage,
dom::HTMLCanvasElement* aCanvas,
gfx::IntSize* aSize);
gfx::IntSize* aSize,
bool aIsAccelerated);
/**
* This is the same as Lookup, except it works on any image recently drawn
* into any canvas. Security checks need to be done again if using the
* results from this.
*/
static SourceSurface* SimpleLookup(dom::Element* aImage);
static SourceSurface* SimpleLookup(dom::Element* aImage,
bool aIsAccelerated);
};
} // namespace mozilla

View File

@ -4312,7 +4312,8 @@ CanvasRenderingContext2D::CachedSurfaceFromElement(Element* aElement)
return res;
}
res.mSourceSurface = CanvasImageCache::SimpleLookup(aElement);
res.mSourceSurface =
CanvasImageCache::SimpleLookup(aElement, mIsSkiaGL);
if (!res.mSourceSurface) {
return res;
}
@ -4418,7 +4419,7 @@ CanvasRenderingContext2D::DrawImage(const CanvasImageSource& image,
}
srcSurf =
CanvasImageCache::Lookup(element, mCanvasElement, &imgSize);
CanvasImageCache::Lookup(element, mCanvasElement, &imgSize, mIsSkiaGL);
}
nsLayoutUtils::DirectDrawInfo drawInfo;
@ -4566,7 +4567,7 @@ CanvasRenderingContext2D::DrawImage(const CanvasImageSource& image,
if (res.mSourceSurface) {
if (res.mImageRequest) {
CanvasImageCache::NotifyDrawImage(element, mCanvasElement, res.mImageRequest,
res.mSourceSurface, imgSize);
res.mSourceSurface, imgSize, mIsSkiaGL);
}
srcSurf = res.mSourceSurface;

View File

@ -508,6 +508,7 @@ skip-if = os == 'android'
skip-if = os == 'mac'
[webgl-conformance/_wrappers/test_conformance__canvas__drawingbuffer-test.html]
[webgl-conformance/_wrappers/test_conformance__canvas__viewport-unchanged-upon-resize.html]
skip-if = os == 'mac'
[webgl-conformance/_wrappers/test_conformance__context__constants.html]
[webgl-conformance/_wrappers/test_conformance__context__context-attributes-alpha-depth-stencil-antialias.html]
skip-if = (os == 'b2g')

View File

@ -108,6 +108,9 @@ fail-if = (os == 'linux')
[_wrappers/test_conformance__canvas__drawingbuffer-static-canvas-test.html]
# Intermittent crash on OSX.
skip-if = os == 'mac'
[_wrappers/test_conformance__canvas__viewport-unchanged-upon-resize.html]
# New OSX r7 machines and 10.10.5 is causing perma failure (bug 1216549)
skip-if = os == 'mac'
########################################################################
# Win

View File

@ -2557,6 +2557,8 @@ EventStateManager::DoScrollText(nsIScrollableFrame* aScrollableFrame,
case WidgetWheelEvent::SCROLL_DEFAULT:
if (isDeltaModePixel) {
mode = nsIScrollableFrame::NORMAL;
} else if (aEvent->mFlags.mHandledByAPZ) {
mode = nsIScrollableFrame::SMOOTH_MSD;
} else {
mode = nsIScrollableFrame::SMOOTH;
}
@ -3119,6 +3121,14 @@ EventStateManager::PostHandleEvent(nsPresContext* aPresContext,
if (pluginFrame) {
MOZ_ASSERT(pluginFrame->WantsToHandleWheelEventAsDefaultAction());
action = WheelPrefs::ACTION_SEND_TO_PLUGIN;
} else if (nsLayoutUtils::IsScrollFrameWithSnapping(frameToScroll)) {
// If the target has scroll-snapping points then we want to handle
// the wheel event on the main thread even if we have APZ enabled. Do
// so and let the APZ know that it should ignore this event.
if (wheelEvent->mFlags.mHandledByAPZ) {
wheelEvent->mFlags.mDefaultPrevented = true;
}
action = WheelPrefs::GetInstance()->ComputeActionFor(wheelEvent);
} else if (wheelEvent->mFlags.mHandledByAPZ) {
action = WheelPrefs::ACTION_NONE;
} else {

View File

@ -459,25 +459,22 @@ HangMonitorParent::HangMonitorParent(ProcessHangMonitor* aMonitor)
mReportHangs = mozilla::Preferences::GetBool("dom.ipc.reportProcessHangs", false);
}
static PLDHashOperator
DeleteMinidump(const uint32_t& aPluginId, nsString aCrashId, void* aUserData)
{
#ifdef MOZ_CRASHREPORTER
if (!aCrashId.IsEmpty()) {
CrashReporter::DeleteMinidumpFilesForID(aCrashId);
}
#endif
return PL_DHASH_NEXT;
}
HangMonitorParent::~HangMonitorParent()
{
// For some reason IPDL doesn't automatically delete the channel for a
// bridged protocol (bug 1090570). So we have to do it ourselves.
XRE_GetIOMessageLoop()->PostTask(FROM_HERE, new DeleteTask<Transport>(GetTransport()));
#ifdef MOZ_CRASHREPORTER
MutexAutoLock lock(mBrowserCrashDumpHashLock);
mBrowserCrashDumpIds.EnumerateRead(DeleteMinidump, nullptr);
for (auto iter = mBrowserCrashDumpIds.Iter(); !iter.Done(); iter.Next()) {
nsString crashId = iter.UserData();
if (!crashId.IsEmpty()) {
CrashReporter::DeleteMinidumpFilesForID(crashId);
}
}
#endif
}
void

View File

@ -599,37 +599,19 @@ ProcessPriorityManagerImpl::ObserveContentParentDestroyed(nsISupports* aSubject)
}
}
static PLDHashOperator
FreezeParticularProcessPriorityManagers(
const uint64_t& aKey,
RefPtr<ParticularProcessPriorityManager> aValue,
void* aUserData)
{
aValue->Freeze();
return PL_DHASH_NEXT;
}
static PLDHashOperator
UnfreezeParticularProcessPriorityManagers(
const uint64_t& aKey,
RefPtr<ParticularProcessPriorityManager> aValue,
void* aUserData)
{
aValue->Unfreeze();
return PL_DHASH_NEXT;
}
void
ProcessPriorityManagerImpl::ObserveScreenStateChanged(const char16_t* aData)
{
if (NS_LITERAL_STRING("on").Equals(aData)) {
sFrozen = false;
mParticularManagers.EnumerateRead(
&UnfreezeParticularProcessPriorityManagers, nullptr);
for (auto iter = mParticularManagers.Iter(); !iter.Done(); iter.Next()) {
iter.UserData()->Unfreeze();
}
} else {
sFrozen = true;
mParticularManagers.EnumerateRead(
&FreezeParticularProcessPriorityManagers, nullptr);
for (auto iter = mParticularManagers.Iter(); !iter.Done(); iter.Next()) {
iter.UserData()->Freeze();
}
}
}

View File

@ -198,14 +198,14 @@ VideoData::ShallowCopyUpdateTimestampAndDuration(const VideoData* aOther,
}
/* static */
void VideoData::SetVideoDataToImage(PlanarYCbCrImage* aVideoImage,
bool VideoData::SetVideoDataToImage(PlanarYCbCrImage* aVideoImage,
const VideoInfo& aInfo,
const YCbCrBuffer &aBuffer,
const IntRect& aPicture,
bool aCopyData)
{
if (!aVideoImage) {
return;
return false;
}
const YCbCrBuffer::Plane &Y = aBuffer.mPlanes[0];
const YCbCrBuffer::Plane &Cb = aBuffer.mPlanes[1];
@ -229,9 +229,9 @@ void VideoData::SetVideoDataToImage(PlanarYCbCrImage* aVideoImage,
aVideoImage->SetDelayedConversion(true);
if (aCopyData) {
aVideoImage->SetData(data);
return aVideoImage->SetData(data);
} else {
aVideoImage->SetDataNoCopy(data);
return aVideoImage->SetDataNoCopy(data);
}
}
@ -330,12 +330,10 @@ VideoData::Create(const VideoInfo& aInfo,
"Wrong format?");
PlanarYCbCrImage* videoImage = static_cast<PlanarYCbCrImage*>(v->mImage.get());
if (!aImage) {
VideoData::SetVideoDataToImage(videoImage, aInfo, aBuffer, aPicture,
true /* aCopyData */);
} else {
VideoData::SetVideoDataToImage(videoImage, aInfo, aBuffer, aPicture,
false /* aCopyData */);
bool shouldCopyData = (aImage == nullptr);
if (!VideoData::SetVideoDataToImage(videoImage, aInfo, aBuffer, aPicture,
shouldCopyData)) {
return nullptr;
}
#ifdef MOZ_WIDGET_GONK
@ -346,8 +344,10 @@ VideoData::Create(const VideoInfo& aInfo,
return nullptr;
}
videoImage = static_cast<PlanarYCbCrImage*>(v->mImage.get());
VideoData::SetVideoDataToImage(videoImage, aInfo, aBuffer, aPicture,
true /* aCopyData */);
if(!VideoData::SetVideoDataToImage(videoImage, aInfo, aBuffer, aPicture,
true /* aCopyData */)) {
return nullptr;
}
}
#endif
return v.forget();
@ -473,7 +473,9 @@ VideoData::Create(const VideoInfo& aInfo,
data.mPicSize = aPicture.Size();
data.mGraphicBuffer = aBuffer;
videoImage->SetData(data);
if (!videoImage->SetData(data)) {
return nullptr;
}
return v.forget();
}

View File

@ -283,7 +283,7 @@ public:
// Initialize PlanarYCbCrImage. Only When aCopyData is true,
// video data is copied to PlanarYCbCrImage.
static void SetVideoDataToImage(PlanarYCbCrImage* aVideoImage,
static bool SetVideoDataToImage(PlanarYCbCrImage* aVideoImage,
const VideoInfo& aInfo,
const YCbCrBuffer &aBuffer,
const IntRect& aPicture,

View File

@ -745,6 +745,9 @@ MediaDecoder::NotifyDataEnded(nsresult aStatus)
{
RefPtr<MediaDecoder> self = this;
nsCOMPtr<nsIRunnable> r = NS_NewRunnableFunction([=] () {
if (self->mShuttingDown) {
return;
}
self->NotifyDownloadEnded(aStatus);
if (NS_SUCCEEDED(aStatus)) {
HTMLMediaElement* element = self->mOwner->GetMediaElement();

View File

@ -80,7 +80,10 @@ VideoFrame::CreateBlackImage(const gfx::IntSize& aSize)
data.mStereoMode = StereoMode::MONO;
// SetData copies data, so we can free data.
planar->SetData(data);
if (!planar->SetData(data)) {
MOZ_ASSERT(false);
return nullptr;
}
return image.forget();
}

View File

@ -58,6 +58,12 @@ var gVideoTests = [
{ name:"bogus.duh", type:"bogus/duh" }
];
// Temp hack for trackIDs and captureStream() -- bug 1215769
var gLongerTests = [
{ name:"seek.webm", type:"video/webm", width:320, height:240, duration:3.966 },
{ name:"gizmo.mp4", type:"video/mp4", width:560, height:320, duration:5.56 },
];
// Used by test_progress to ensure we get the correct progress information
// during resource download.
var gProgressTests = [

View File

@ -14,7 +14,7 @@ createHTML({
title: "Captured video-only over peer connection",
visible: true
}).then(() => new Promise(resolve => {
manager.runTests(getPlayableVideos(gSmallTests), startTest);
manager.runTests(getPlayableVideos(gLongerTests), startTest);
manager.onFinished = () => {
// Tear down before SimpleTest.finish.
if ("nsINetworkInterfaceListService" in SpecialPowers.Ci) {

View File

@ -250,10 +250,16 @@ MediaEngineDefaultVideoSource::Notify(nsITimer* aTimer)
0, 0);
#endif
ycbcr_image->SetData(data);
bool setData = ycbcr_image->SetData(data);
MOZ_ASSERT(setData);
// SetData copies data, so we can free the frame
ReleaseFrame(data);
if (!setData) {
return NS_ERROR_FAILURE;
}
MonitorAutoLock lock(mMonitor);
// implicitly releases last image

View File

@ -315,7 +315,10 @@ MediaEngineRemoteVideoSource::DeliverFrame(unsigned char* buffer,
data.mPicSize = IntSize(mWidth, mHeight);
data.mStereoMode = StereoMode::MONO;
videoImage->SetData(data);
if (!videoImage->SetData(data)) {
MOZ_ASSERT(false);
return 0;
}
#ifdef DEBUG
static uint32_t frame_num = 0;

View File

@ -1444,31 +1444,6 @@ PluginInstanceParent::AllocPPluginScriptableObjectParent()
return new PluginScriptableObjectParent(Proxy);
}
#ifdef DEBUG
namespace {
struct ActorSearchData
{
PluginScriptableObjectParent* actor;
bool found;
};
PLDHashOperator
ActorSearch(NPObject* aKey,
PluginScriptableObjectParent* aData,
void* aUserData)
{
ActorSearchData* asd = reinterpret_cast<ActorSearchData*>(aUserData);
if (asd->actor == aData) {
asd->found = true;
return PL_DHASH_STOP;
}
return PL_DHASH_NEXT;
}
} // namespace
#endif // DEBUG
bool
PluginInstanceParent::DeallocPPluginScriptableObjectParent(
PPluginScriptableObjectParent* aObject)
@ -1484,9 +1459,10 @@ PluginInstanceParent::DeallocPPluginScriptableObjectParent(
}
#ifdef DEBUG
else {
ActorSearchData asd = { actor, false };
mScriptableObjects.EnumerateRead(ActorSearch, &asd);
NS_ASSERTION(!asd.found, "Actor in the hash with a null NPObject!");
for (auto iter = mScriptableObjects.Iter(); !iter.Done(); iter.Next()) {
NS_ASSERTION(actor != iter.UserData(),
"Actor in the hash with a null NPObject!");
}
}
#endif

View File

@ -22,16 +22,17 @@ interface nsITCPDeviceInfo: nsISupports
readonly attribute uint16_t port;
};
[scriptable, uuid(fbb890a9-9e95-47d1-a425-86fd95881d81)]
[scriptable, uuid(09bddfaf-fcc2-4dc9-b33e-a509a1c2fb6d)]
interface nsITCPPresentationServerListener: nsISupports
{
/**
* Callback while the server socket stops listening.
* @param aReason
* The reason of the socket close. NS_OK for manually |close|.
* <other-error> on failure.
* Callback while the server socket changes port.
* This event won't be cached so you should get current port after setting
* this listener to make sure the value is updated.
* @param aPort
* The port of the server socket.
*/
void onClose(in nsresult aReason);
void onPortChange(in uint16_t aPort);
/**
* Callback while the remote host is requesting to start a presentation session.

View File

@ -13,6 +13,7 @@
#include "nsComponentManagerUtils.h"
#include "nsIObserverService.h"
#include "nsServiceManagerUtils.h"
#include "nsThreadUtils.h"
#ifdef MOZ_WIDGET_ANDROID
#include "nsIPropertyBag2.h"
@ -25,16 +26,12 @@
#define SERVICE_TYPE "_mozilla_papi._tcp."
inline static PRLogModuleInfo*
GetProviderLog()
{
static PRLogModuleInfo* log = PR_NewLogModule("MulticastDNSDeviceProvider");
return log;
}
static mozilla::LazyLogModule sMulticastDNSProviderLogModule("MulticastDNSDeviceProvider");
#undef LOG_I
#define LOG_I(...) MOZ_LOG(GetProviderLog(), mozilla::LogLevel::Debug, (__VA_ARGS__))
#define LOG_I(...) MOZ_LOG(sMulticastDNSProviderLogModule, mozilla::LogLevel::Debug, (__VA_ARGS__))
#undef LOG_E
#define LOG_E(...) MOZ_LOG(GetProviderLog(), mozilla::LogLevel::Error, (__VA_ARGS__))
#define LOG_E(...) MOZ_LOG(sMulticastDNSProviderLogModule, mozilla::LogLevel::Error, (__VA_ARGS__))
namespace mozilla {
namespace dom {
@ -261,20 +258,35 @@ MulticastDNSDeviceProvider::RegisterService()
return NS_OK;
}
MOZ_ASSERT(!mRegisterRequest);
nsresult rv;
if (NS_WARN_IF(NS_FAILED(rv = mPresentationServer->SetListener(mWrappedListener)))) {
return rv;
}
if (NS_WARN_IF(NS_FAILED(rv = mPresentationServer->StartService(0)))) {
return rv;
}
uint16_t servicePort;
if (NS_WARN_IF(NS_FAILED(rv = mPresentationServer->GetPort(&servicePort)))) {
return rv;
}
/**
* If |servicePort| is non-zero, it means PresentationServer is running.
* Otherwise, we should make it start serving.
*/
if (!servicePort) {
if (NS_WARN_IF(NS_FAILED(rv = mPresentationServer->SetListener(mWrappedListener)))) {
return rv;
}
if (NS_WARN_IF(NS_FAILED(rv = mPresentationServer->StartService(0)))) {
return rv;
}
if (NS_WARN_IF(NS_FAILED(rv = mPresentationServer->GetPort(&servicePort)))) {
return rv;
}
}
// Cancel on going service registration.
if (mRegisterRequest) {
mRegisterRequest->Cancel(NS_OK);
mRegisterRequest = nullptr;
}
/**
* Register the presentation control channel server as an mDNS service.
*/
@ -755,12 +767,9 @@ MulticastDNSDeviceProvider::OnRegistrationFailed(nsIDNSServiceInfo* aServiceInfo
mRegisterRequest = nullptr;
nsresult rv;
if (aErrorCode == nsIDNSRegistrationListener::ERROR_SERVICE_NOT_RUNNING) {
if (NS_WARN_IF(NS_FAILED(rv = RegisterService()))) {
return rv;
}
return NS_DispatchToMainThread(
NS_NewRunnableMethod(this, &MulticastDNSDeviceProvider::RegisterService));
}
return NS_OK;
@ -855,17 +864,13 @@ MulticastDNSDeviceProvider::OnResolveFailed(nsIDNSServiceInfo* aServiceInfo,
// nsITCPPresentationServerListener
NS_IMETHODIMP
MulticastDNSDeviceProvider::OnClose(nsresult aReason)
MulticastDNSDeviceProvider::OnPortChange(uint16_t aPort)
{
LOG_I("OnClose: %x", aReason);
LOG_I("OnPortChange: %d", aPort);
MOZ_ASSERT(NS_IsMainThread());
UnregisterService(aReason);
nsresult rv;
if (mDiscoverable && NS_WARN_IF(NS_FAILED(rv = RegisterService()))) {
return rv;
if (mDiscoverable) {
RegisterService();
}
return NS_OK;

View File

@ -40,16 +40,11 @@ TCPPresentationServer.prototype = {
throw Cr.NS_ERROR_FAILURE;
}
if (typeof aPort === "undefined") {
DEBUG && log("TCPPresentationServer - aPort should not be undefined");
throw Cr.NS_ERROR_FAILURE;
}
/**
* 0 or undefined indicates opt-out parameter, and a port will be selected
* automatically.
*/
let serverSocketPort = (aPort !== 0) ? aPort : -1;
let serverSocketPort = (typeof aPort !== "undefined" && aPort !== 0) ? aPort : -1;
this._serverSocket = Cc["@mozilla.org/network/server-socket;1"]
.createInstance(Ci.nsIServerSocket);
@ -70,7 +65,12 @@ TCPPresentationServer.prototype = {
this._port = this._serverSocket.port;
DEBUG && log("TCPPresentationServer - service start on port: " + aPort);
DEBUG && log("TCPPresentationServer - service start on port: " + this._port);
// Monitor network interface change to restart server socket.
// Only B2G has nsINetworkManager
Services.obs.addObserver(this, "network-active-changed", false);
Services.obs.addObserver(this, "network:offline-status-changed", false);
},
get id() {
@ -178,31 +178,74 @@ TCPPresentationServer.prototype = {
// nsIServerSocketListener (Triggered by nsIServerSocket.init)
onStopListening: function(aServerSocket, aStatus) {
DEBUG && log("TCPPresentationServer - onStopListening: " + aStatus);
if (this._serverSocket) {
DEBUG && log("TCPPresentationServer - should be non-manually closed");
this.close();
} else if (aStatus === Cr.NS_BINDING_ABORTED) {
DEBUG && log("TCPPresentationServer - should be manually closed");
aStatus = Cr.NS_OK;
}
this._listener && this._listener.onClose(aStatus);
},
close: function() {
DEBUG && log("TCPPresentationServer - close");
if (this._serverSocket) {
if (this._isServiceInit()) {
DEBUG && log("TCPPresentationServer - close server socket");
this._serverSocket.close();
this._serverSocket = null;
Services.obs.removeObserver(this, "network-active-changed");
Services.obs.removeObserver(this, "network:offline-status-changed");
}
this._port = 0;
},
// nsIObserver
observe: function(aSubject, aTopic, aData) {
DEBUG && log("TCPPresentationServer - observe: " + aTopic);
switch (aTopic) {
case "network-active-changed": {
if (!aSubject) {
DEBUG && log("No active network");
return;
}
/**
* Restart service only when original status is online because other
* cases will be handled by "network:offline-status-changed".
*/
if (!Services.io.offline) {
this._restartService();
}
break;
}
case "network:offline-status-changed": {
if (aData == "offline") {
DEBUG && log("network offline");
return;
}
this._restartService();
break;
}
}
},
_restartService: function() {
DEBUG && log("TCPPresentationServer - restart service");
// restart server socket
if (this._isServiceInit()) {
let port = this._port;
this.close();
try {
this.startService();
if (this._listener && this._port !== port) {
this._listener.onPortChange(this._port);
}
} catch (e) {
DEBUG && log("TCPPresentationServer - restart service fail: " + e);
}
}
},
classID: Components.ID("{f4079b8b-ede5-4b90-a112-5b415a931deb}"),
QueryInterface : XPCOMUtils.generateQI([Ci.nsIServerSocketListener,
Ci.nsITCPPresentationServer]),
Ci.nsITCPPresentationServer,
Ci.nsIObserver]),
};
function ChannelDescription(aInit) {

View File

@ -1002,7 +1002,8 @@ function serverClosed() {
Assert.equal(listener.devices.length, 1);
let serverListener = provider.QueryInterface(Ci.nsITCPPresentationServerListener);
serverListener.onClose(Cr.NS_ERROR_UNEXPECTED);
let randomPort = 9527;
serverListener.onPortChange(randomPort);
Assert.equal(mockObj.serviceRegistered, 2);
Assert.equal(mockObj.serviceUnregistered, 1);

View File

@ -183,17 +183,17 @@ function testPresentationServer() {
}
function setOffline() {
let expectedReason;
tps.listener = {
onClose: function(aReason) {
Assert.equal(aReason, Cr.NS_ERROR_ABORT, 'TCPPresentationServer close as expected');
Services.io.offline = false;
onPortChange: function(aPort) {
Assert.notEqual(aPort, 0, 'TCPPresentationServer port changed and the port should be valid');
tps.close();
run_next_test();
},
}
};
// Let the server socket be closed non-manually
// Let the server socket restart automatically.
Services.io.offline = true;
Services.io.offline = false;
}
function oneMoreLoop() {
@ -210,12 +210,13 @@ function oneMoreLoop() {
function shutdown()
{
tps.listener = {
onClose: function(aReason) {
Assert.equal(aReason, Cr.NS_OK, 'TCPPresentationServer close success');
run_next_test();
onPortChange: function(aPort) {
Assert.ok(false, 'TCPPresentationServer port changed');
},
}
};
tps.close();
Assert.equal(tps.port, 0, "TCPPresentationServer closed");
run_next_test();
}
// Test manually close control channel with NS_ERROR_FAILURE

View File

@ -113,10 +113,7 @@ AsyncLog(nsIInterceptedChannel *aInterceptedChannel,
const nsACString& aMessageName, const nsTArray<nsString>& aParams)
{
MOZ_ASSERT(aInterceptedChannel);
// Since the intercepted channel is kept alive and paused while handling
// the FetchEvent, we are guaranteed the reporter is stable on the worker
// thread.
nsIConsoleReportCollector* reporter =
nsCOMPtr<nsIConsoleReportCollector> reporter =
aInterceptedChannel->GetConsoleReportCollector();
if (reporter) {
reporter->AddConsoleReport(nsIScriptError::errorFlag,

View File

@ -27,14 +27,12 @@ public:
protected:
virtual ~nsGroupsEnumerator();
static PLDHashOperator HashEnum(const nsACString& aKey,
nsTArray<nsCString>* aData, void* aClosure);
nsresult Initialize();
protected:
nsControllerCommandGroup::GroupsHashtable& mHashTable;
int32_t mIndex;
char** mGroupNames; // array of pointers to char16_t* in the hash table
const char** mGroupNames; // array of pointers to char16_t* in the hash table
bool mInitted;
};
@ -92,7 +90,7 @@ nsGroupsEnumerator::GetNext(nsISupports** aResult)
return NS_ERROR_FAILURE;
}
char* thisGroupName = mGroupNames[mIndex];
const char* thisGroupName = mGroupNames[mIndex];
nsCOMPtr<nsISupportsCString> supportsString =
do_CreateInstance(NS_SUPPORTS_CSTRING_CONTRACTID, &rv);
@ -104,18 +102,6 @@ nsGroupsEnumerator::GetNext(nsISupports** aResult)
return CallQueryInterface(supportsString, aResult);
}
/* static */
/* return false to stop */
PLDHashOperator
nsGroupsEnumerator::HashEnum(const nsACString& aKey, nsTArray<nsCString>* aData,
void* aClosure)
{
nsGroupsEnumerator* groupsEnum = static_cast<nsGroupsEnumerator*>(aClosure);
groupsEnum->mGroupNames[groupsEnum->mIndex] = (char*)aKey.Data();
groupsEnum->mIndex++;
return PL_DHASH_NEXT;
}
nsresult
nsGroupsEnumerator::Initialize()
{
@ -123,13 +109,16 @@ nsGroupsEnumerator::Initialize()
return NS_OK;
}
mGroupNames = new char*[mHashTable.Count()];
mGroupNames = new const char*[mHashTable.Count()];
if (!mGroupNames) {
return NS_ERROR_OUT_OF_MEMORY;
}
mIndex = 0;
mHashTable.EnumerateRead(HashEnum, this);
for (auto iter = mHashTable.Iter(); !iter.Done(); iter.Next()) {
mGroupNames[mIndex] = iter.Key().Data();
mIndex++;
}
mIndex = -1;
mInitted = true;

View File

@ -34,29 +34,19 @@ nsCommandManager::~nsCommandManager()
{
}
static PLDHashOperator
TraverseCommandObservers(const char* aKey,
nsCommandManager::ObserverList* aObservers,
void* aClosure)
{
nsCycleCollectionTraversalCallback* cb =
static_cast<nsCycleCollectionTraversalCallback*>(aClosure);
int32_t i, numItems = aObservers->Length();
for (i = 0; i < numItems; ++i) {
cb->NoteXPCOMChild(aObservers->ElementAt(i));
}
return PL_DHASH_NEXT;
}
NS_IMPL_CYCLE_COLLECTION_CLASS(nsCommandManager)
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsCommandManager)
tmp->mObserversTable.Clear();
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsCommandManager)
tmp->mObserversTable.EnumerateRead(TraverseCommandObservers, &cb);
for (auto iter = tmp->mObserversTable.Iter(); !iter.Done(); iter.Next()) {
nsCommandManager::ObserverList* observers = iter.UserData();
int32_t numItems = observers->Length();
for (int32_t i = 0; i < numItems; ++i) {
cb.NoteXPCOMChild(observers->ElementAt(i));
}
}
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
NS_IMPL_CYCLE_COLLECTING_ADDREF(nsCommandManager)

View File

@ -178,18 +178,6 @@ nsControllerCommandTable::GetCommandState(const char* aCommandName,
aCommandRefCon);
}
static PLDHashOperator
AddCommand(const nsACString& aKey, nsIControllerCommand* aData, void* aArg)
{
// aArg is a pointer to a array of strings. It gets incremented after
// allocating each one so that it points to the next location for AddCommand
// to assign a string to.
char*** commands = static_cast<char***>(aArg);
(**commands) = ToNewCString(aKey);
(*commands)++;
return PL_DHASH_NEXT;
}
NS_IMETHODIMP
nsControllerCommandTable::GetSupportedCommands(uint32_t* aCount,
char*** aCommands)
@ -199,7 +187,10 @@ nsControllerCommandTable::GetSupportedCommands(uint32_t* aCount,
*aCount = mCommandsTable.Count();
*aCommands = commands;
mCommandsTable.EnumerateRead(AddCommand, &commands);
for (auto iter = mCommandsTable.Iter(); !iter.Done(); iter.Next()) {
*commands = ToNewCString(iter.Key());
commands++;
}
return NS_OK;
}

View File

@ -103,12 +103,6 @@ struct nsWebBrowserPersist::URIData
nsresult GetLocalURI(nsIURI *targetBaseURI, nsCString& aSpecOut);
};
struct nsWebBrowserPersist::URIFixupData
{
RefPtr<FlatURIMap> mFlatMap;
nsCOMPtr<nsIURI> mTargetBaseURI;
};
// Information about the output stream
struct nsWebBrowserPersist::OutputData
{
@ -593,13 +587,69 @@ nsWebBrowserPersist::SerializeNextFile()
// number of times this method is called. If it becomes a
// bottleneck, the count of not-yet-persisted URIs could be
// maintained separately.
mURIMap.EnumerateRead(EnumCountURIsToPersist, &urisToPersist);
for (auto iter = mURIMap.Iter(); !iter.Done(); iter.Next()) {
URIData *data = iter.UserData();
if (data->mNeedsPersisting && !data->mSaved) {
urisToPersist++;
}
}
}
if (urisToPersist > 0) {
// Persist each file in the uri map. The document(s)
// will be saved after the last one of these is saved.
mURIMap.EnumerateRead(EnumPersistURIs, this);
for (auto iter = mURIMap.Iter(); !iter.Done(); iter.Next()) {
URIData *data = iter.UserData();
if (!data->mNeedsPersisting || data->mSaved) {
continue;
}
nsresult rv;
// Create a URI from the key.
nsCOMPtr<nsIURI> uri;
rv = NS_NewURI(getter_AddRefs(uri), iter.Key(),
data->mCharset.get());
if (NS_WARN_IF(NS_FAILED(rv))) {
break;
}
// Make a URI to save the data to.
nsCOMPtr<nsIURI> fileAsURI;
rv = data->mDataPath->Clone(getter_AddRefs(fileAsURI));
if (NS_WARN_IF(NS_FAILED(rv))) {
break;
}
rv = AppendPathToURI(fileAsURI, data->mFilename);
if (NS_WARN_IF(NS_FAILED(rv))) {
break;
}
// The Referrer Policy doesn't matter here since the referrer is
// nullptr.
rv = SaveURIInternal(uri, nullptr, nullptr,
mozilla::net::RP_Default, nullptr, nullptr,
fileAsURI, true, mIsPrivate);
// If SaveURIInternal fails, then it will have called EndDownload,
// which means that |data| is no longer valid memory. We MUST bail.
if (NS_WARN_IF(NS_FAILED(rv))) {
break;
}
if (rv == NS_OK) {
// Store the actual object because once it's persisted this
// will be fixed up with the right file extension.
data->mFile = fileAsURI;
data->mSaved = true;
} else {
data->mNeedsFixup = false;
}
if (mSerializingOutput) {
break;
}
}
}
// If there are downloads happening, wait until they're done; the
@ -652,17 +702,18 @@ nsWebBrowserPersist::SerializeNextFile()
return;
}
}
// mFlatURIMap must be rebuilt each time through SerializeNextFile, as
// mTargetBaseURI is used to create the relative URLs and will be different
// with each serialized document.
RefPtr<FlatURIMap> flatMap = new FlatURIMap(targetBaseSpec);
URIFixupData fixupData;
fixupData.mFlatMap = flatMap;
fixupData.mTargetBaseURI = mTargetBaseURI;
mURIMap.EnumerateRead(EnumCopyURIsToFlatMap, &fixupData);
for (auto iter = mURIMap.Iter(); !iter.Done(); iter.Next()) {
nsAutoCString mapTo;
nsresult rv = iter.UserData()->GetLocalURI(mTargetBaseURI, mapTo);
if (NS_SUCCEEDED(rv) || !mapTo.IsVoid()) {
flatMap->Add(iter.Key(), mapTo);
}
}
mFlatURIMap = flatMap.forget();
nsCOMPtr<nsIFile> localFile;
@ -1755,23 +1806,35 @@ nsWebBrowserPersist::FinishSaveDocumentInternal(nsIURI* aFile,
void nsWebBrowserPersist::Cleanup()
{
mURIMap.Clear();
mOutputMap.EnumerateRead(EnumCleanupOutputMap, this);
for (auto iter = mOutputMap.Iter(); !iter.Done(); iter.Next()) {
nsCOMPtr<nsIChannel> channel = do_QueryInterface(iter.Key());
if (channel) {
channel->Cancel(NS_BINDING_ABORTED);
}
}
mOutputMap.Clear();
mUploadList.EnumerateRead(EnumCleanupUploadList, this);
for (auto iter = mUploadList.Iter(); !iter.Done(); iter.Next()) {
nsCOMPtr<nsIChannel> channel = do_QueryInterface(iter.Key());
if (channel) {
channel->Cancel(NS_BINDING_ABORTED);
}
}
mUploadList.Clear();
uint32_t i;
for (i = 0; i < mDocList.Length(); i++)
{
for (i = 0; i < mDocList.Length(); i++) {
DocData *docData = mDocList.ElementAt(i);
delete docData;
}
mDocList.Clear();
for (i = 0; i < mCleanupList.Length(); i++)
{
for (i = 0; i < mCleanupList.Length(); i++) {
CleanupData *cleanupData = mCleanupList.ElementAt(i);
delete cleanupData;
}
mCleanupList.Clear();
mFilenameList.Clear();
}
@ -2319,85 +2382,72 @@ nsWebBrowserPersist::EndDownload(nsresult aResult)
mEventSink = nullptr;
}
struct MOZ_STACK_CLASS FixRedirectData
{
nsCOMPtr<nsIChannel> mNewChannel;
nsCOMPtr<nsIURI> mOriginalURI;
nsCOMPtr<nsISupports> mMatchingKey;
};
nsresult
nsWebBrowserPersist::FixRedirectedChannelEntry(nsIChannel *aNewChannel)
{
NS_ENSURE_ARG_POINTER(aNewChannel);
// Iterate through existing open channels looking for one with a URI
// matching the one specified.
nsCOMPtr<nsIURI> originalURI;
aNewChannel->GetOriginalURI(getter_AddRefs(originalURI));
for (auto iter = mOutputMap.Iter(); !iter.Done(); iter.Next()) {
nsISupports* key = iter.Key();
nsCOMPtr<nsIChannel> thisChannel = do_QueryInterface(key);
nsCOMPtr<nsIURI> thisURI;
// Enumerate through existing open channels looking for one with
// a URI matching the one specified.
thisChannel->GetOriginalURI(getter_AddRefs(thisURI));
FixRedirectData data;
data.mNewChannel = aNewChannel;
data.mNewChannel->GetOriginalURI(getter_AddRefs(data.mOriginalURI));
mOutputMap.EnumerateRead(EnumFixRedirect, &data);
// Compare this channel's URI to the one passed in.
bool matchingURI = false;
thisURI->Equals(originalURI, &matchingURI);
if (matchingURI) {
// If a match is found, remove the data entry with the old channel
// key and re-add it with the new channel key.
nsAutoPtr<OutputData> outputData;
mOutputMap.RemoveAndForget(key, outputData);
NS_ENSURE_TRUE(outputData, NS_ERROR_FAILURE);
// If a match is found, remove the data entry with the old channel key
// and re-add it with the new channel key.
// Store data again with new channel unless told to ignore redirects
if (!(mPersistFlags & PERSIST_FLAGS_IGNORE_REDIRECTED_DATA)) {
nsCOMPtr<nsISupports> keyPtr = do_QueryInterface(aNewChannel);
mOutputMap.Put(keyPtr, outputData.forget());
}
if (data.mMatchingKey)
{
nsAutoPtr<OutputData> outputData;
mOutputMap.RemoveAndForget(data.mMatchingKey, outputData);
NS_ENSURE_TRUE(outputData, NS_ERROR_FAILURE);
// Store data again with new channel unless told to ignore redirects
if (!(mPersistFlags & PERSIST_FLAGS_IGNORE_REDIRECTED_DATA))
{
nsCOMPtr<nsISupports> keyPtr = do_QueryInterface(aNewChannel);
mOutputMap.Put(keyPtr, outputData.forget());
break;
}
}
return NS_OK;
}
PLDHashOperator
nsWebBrowserPersist::EnumFixRedirect(nsISupports *aKey, OutputData *aData, void* aClosure)
{
FixRedirectData *data = static_cast<FixRedirectData*>(aClosure);
nsCOMPtr<nsIChannel> thisChannel = do_QueryInterface(aKey);
nsCOMPtr<nsIURI> thisURI;
thisChannel->GetOriginalURI(getter_AddRefs(thisURI));
// Compare this channel's URI to the one passed in.
bool matchingURI = false;
thisURI->Equals(data->mOriginalURI, &matchingURI);
if (matchingURI)
{
data->mMatchingKey = aKey;
return PL_DHASH_STOP;
}
return PL_DHASH_NEXT;
}
void
nsWebBrowserPersist::CalcTotalProgress()
{
mTotalCurrentProgress = 0;
mTotalMaxProgress = 0;
if (mOutputMap.Count() > 0)
{
if (mOutputMap.Count() > 0) {
// Total up the progress of each output stream
mOutputMap.EnumerateRead(EnumCalcProgress, this);
for (auto iter = mOutputMap.Iter(); !iter.Done(); iter.Next()) {
// Only count toward total progress if destination file is local.
OutputData* data = iter.UserData();
nsCOMPtr<nsIFileURL> fileURL = do_QueryInterface(data->mFile);
if (fileURL) {
mTotalCurrentProgress += data->mSelfProgress;
mTotalMaxProgress += data->mSelfProgressMax;
}
}
}
if (mUploadList.Count() > 0)
{
if (mUploadList.Count() > 0) {
// Total up the progress of each upload
mUploadList.EnumerateRead(EnumCalcUploadProgress, this);
for (auto iter = mUploadList.Iter(); !iter.Done(); iter.Next()) {
UploadData* data = iter.UserData();
if (data) {
mTotalCurrentProgress += data->mSelfProgress;
mTotalMaxProgress += data->mSelfProgressMax;
}
}
}
// XXX this code seems pretty bogus and pointless
@ -2409,133 +2459,6 @@ nsWebBrowserPersist::CalcTotalProgress()
}
}
PLDHashOperator
nsWebBrowserPersist::EnumCalcProgress(nsISupports *aKey, OutputData *aData, void* aClosure)
{
nsWebBrowserPersist *pthis = static_cast<nsWebBrowserPersist*>(aClosure);
// only count toward total progress if destination file is local
nsCOMPtr<nsIFileURL> fileURL = do_QueryInterface(aData->mFile);
if (fileURL)
{
pthis->mTotalCurrentProgress += aData->mSelfProgress;
pthis->mTotalMaxProgress += aData->mSelfProgressMax;
}
return PL_DHASH_NEXT;
}
PLDHashOperator
nsWebBrowserPersist::EnumCalcUploadProgress(nsISupports *aKey, UploadData *aData, void* aClosure)
{
if (aData && aClosure)
{
nsWebBrowserPersist *pthis = static_cast<nsWebBrowserPersist*>(aClosure);
pthis->mTotalCurrentProgress += aData->mSelfProgress;
pthis->mTotalMaxProgress += aData->mSelfProgressMax;
}
return PL_DHASH_NEXT;
}
PLDHashOperator
nsWebBrowserPersist::EnumCountURIsToPersist(const nsACString &aKey, URIData *aData, void* aClosure)
{
uint32_t *count = static_cast<uint32_t*>(aClosure);
if (aData->mNeedsPersisting && !aData->mSaved)
{
(*count)++;
}
return PL_DHASH_NEXT;
}
PLDHashOperator
nsWebBrowserPersist::EnumPersistURIs(const nsACString &aKey, URIData *aData, void* aClosure)
{
if (!aData->mNeedsPersisting || aData->mSaved)
{
return PL_DHASH_NEXT;
}
nsWebBrowserPersist *pthis = static_cast<nsWebBrowserPersist*>(aClosure);
nsresult rv;
// Create a URI from the key
nsAutoCString key = nsAutoCString(aKey);
nsCOMPtr<nsIURI> uri;
rv = NS_NewURI(getter_AddRefs(uri),
nsDependentCString(key.get(), key.Length()),
aData->mCharset.get());
NS_ENSURE_SUCCESS(rv, PL_DHASH_STOP);
// Make a URI to save the data to
nsCOMPtr<nsIURI> fileAsURI;
rv = aData->mDataPath->Clone(getter_AddRefs(fileAsURI));
NS_ENSURE_SUCCESS(rv, PL_DHASH_STOP);
rv = pthis->AppendPathToURI(fileAsURI, aData->mFilename);
NS_ENSURE_SUCCESS(rv, PL_DHASH_STOP);
// The Referrer Policy doesn't matter here since the referrer is nullptr.
rv = pthis->SaveURIInternal(uri, nullptr, nullptr, mozilla::net::RP_Default,
nullptr, nullptr, fileAsURI, true, pthis->mIsPrivate);
// if SaveURIInternal fails, then it will have called EndDownload,
// which means that |aData| is no longer valid memory. we MUST bail.
NS_ENSURE_SUCCESS(rv, PL_DHASH_STOP);
if (rv == NS_OK)
{
// Store the actual object because once it's persisted this
// will be fixed up with the right file extension.
aData->mFile = fileAsURI;
aData->mSaved = true;
}
else
{
aData->mNeedsFixup = false;
}
if (pthis->mSerializingOutput)
return PL_DHASH_STOP;
return PL_DHASH_NEXT;
}
PLDHashOperator
nsWebBrowserPersist::EnumCleanupOutputMap(nsISupports *aKey, OutputData *aData, void* aClosure)
{
nsCOMPtr<nsIChannel> channel = do_QueryInterface(aKey);
if (channel)
{
channel->Cancel(NS_BINDING_ABORTED);
}
return PL_DHASH_NEXT;
}
PLDHashOperator
nsWebBrowserPersist::EnumCleanupUploadList(nsISupports *aKey, UploadData *aData, void* aClosure)
{
nsCOMPtr<nsIChannel> channel = do_QueryInterface(aKey);
if (channel)
{
channel->Cancel(NS_BINDING_ABORTED);
}
return PL_DHASH_NEXT;
}
/* static */ PLDHashOperator
nsWebBrowserPersist::EnumCopyURIsToFlatMap(const nsACString &aKey,
URIData *aData,
void* aClosure)
{
URIFixupData *fixupData = static_cast<URIFixupData*>(aClosure);
FlatURIMap* theMap = fixupData->mFlatMap;
nsAutoCString mapTo;
nsresult rv = aData->GetLocalURI(fixupData->mTargetBaseURI, mapTo);
if (NS_SUCCEEDED(rv) || !mapTo.IsVoid()) {
theMap->Add(aKey, mapTo);
}
return PL_DHASH_NEXT;
}
nsresult
nsWebBrowserPersist::StoreURI(
const char *aURI, bool aNeedsPersisting, URIData **aData)

View File

@ -136,24 +136,6 @@ private:
void SetApplyConversionIfNeeded(nsIChannel *aChannel);
// Hash table enumerators
static PLDHashOperator EnumPersistURIs(
const nsACString &aKey, URIData *aData, void* aClosure);
static PLDHashOperator EnumCleanupOutputMap(
nsISupports *aKey, OutputData *aData, void* aClosure);
static PLDHashOperator EnumCleanupUploadList(
nsISupports *aKey, UploadData *aData, void* aClosure);
static PLDHashOperator EnumCalcProgress(
nsISupports *aKey, OutputData *aData, void* aClosure);
static PLDHashOperator EnumCalcUploadProgress(
nsISupports *aKey, UploadData *aData, void* aClosure);
static PLDHashOperator EnumFixRedirect(
nsISupports *aKey, OutputData *aData, void* aClosure);
static PLDHashOperator EnumCountURIsToPersist(
const nsACString &aKey, URIData *aData, void* aClosure);
static PLDHashOperator EnumCopyURIsToFlatMap(
const nsACString &aKey, URIData *aData, void* aClosure);
nsCOMPtr<nsIURI> mCurrentDataPath;
bool mCurrentDataPathIsRelative;
nsCString mCurrentRelativePathToData;

View File

@ -57,7 +57,7 @@ GrallocImage::~GrallocImage()
{
}
void
bool
GrallocImage::SetData(const Data& aData)
{
MOZ_ASSERT(!mTextureClient, "TextureClient is already set");
@ -70,7 +70,7 @@ GrallocImage::SetData(const Data& aData)
if (gfxPlatform::GetPlatform()->IsInGonkEmulator()) {
// Emulator does not support HAL_PIXEL_FORMAT_YV12.
return;
return false;
}
RefPtr<GrallocTextureClientOGL> textureClient =
@ -88,7 +88,7 @@ GrallocImage::SetData(const Data& aData)
sp<GraphicBuffer> graphicBuffer = textureClient->GetGraphicBuffer();
if (!result || !graphicBuffer.get()) {
mTextureClient = nullptr;
return;
return false;
}
mTextureClient = textureClient;
@ -96,7 +96,7 @@ GrallocImage::SetData(const Data& aData)
void* vaddr;
if (graphicBuffer->lock(GraphicBuffer::USAGE_SW_WRITE_OFTEN,
&vaddr) != OK) {
return;
return false;
}
uint8_t* yChannel = static_cast<uint8_t*>(vaddr);
@ -144,12 +144,14 @@ GrallocImage::SetData(const Data& aData)
mData.mYChannel = nullptr;
mData.mCrChannel = nullptr;
mData.mCbChannel = nullptr;
return true;
}
void GrallocImage::SetData(const GrallocData& aData)
bool GrallocImage::SetData(const GrallocData& aData)
{
mTextureClient = static_cast<GrallocTextureClientOGL*>(aData.mGraphicBuffer.get());
mSize = aData.mPicSize;
return true;
}
/**

View File

@ -66,13 +66,13 @@ public:
* This makes a copy of the data buffers, in order to support functioning
* in all different layer managers.
*/
virtual void SetData(const Data& aData);
virtual bool SetData(const Data& aData);
/**
* Share the SurfaceDescriptor without making the copy, in order
* to support functioning in all different layer managers.
*/
virtual void SetData(const GrallocData& aData);
virtual bool SetData(const GrallocData& aData);
// From [android 4.0.4]/hardware/msm7k/libgralloc-qsd8k/gralloc_priv.h
enum {

View File

@ -484,7 +484,7 @@ CopyPlane(uint8_t *aDst, const uint8_t *aSrc,
}
}
void
bool
PlanarYCbCrImage::CopyData(const Data& aData)
{
mData = aData;
@ -496,7 +496,7 @@ PlanarYCbCrImage::CopyData(const Data& aData)
// get new buffer
mBuffer = AllocateBuffer(size);
if (!mBuffer)
return;
return false;
// update buffer size
mBufferSize = size;
@ -513,12 +513,13 @@ PlanarYCbCrImage::CopyData(const Data& aData)
mData.mCbCrSize, mData.mCbCrStride, mData.mCrSkip);
mSize = aData.mPicSize;
return true;
}
void
bool
PlanarYCbCrImage::SetData(const Data &aData)
{
CopyData(aData);
return CopyData(aData);
}
gfxImageFormat
@ -529,11 +530,12 @@ PlanarYCbCrImage::GetOffscreenFormat()
mOffscreenFormat;
}
void
bool
PlanarYCbCrImage::SetDataNoCopy(const Data &aData)
{
mData = aData;
mSize = aData.mPicSize;
return true;
}
uint8_t*

View File

@ -656,7 +656,7 @@ public:
* This makes a copy of the data buffers, in order to support functioning
* in all different layer managers.
*/
virtual void SetData(const Data& aData);
virtual bool SetData(const Data& aData);
/**
* This doesn't make a copy of the data buffers. Can be used when mBuffer is
@ -665,7 +665,7 @@ public:
* The GStreamer media backend uses this to decode into PlanarYCbCrImage(s)
* directly.
*/
virtual void SetDataNoCopy(const Data &aData);
virtual bool SetDataNoCopy(const Data &aData);
/**
* This allocates and returns a new buffer
@ -709,7 +709,7 @@ protected:
*
* @param aData Input image data.
*/
void CopyData(const Data& aData);
bool CopyData(const Data& aData);
/**
* Return a buffer to store image data in.

View File

@ -1051,6 +1051,11 @@ APZCTreeManager::ProcessMouseEvent(WidgetMouseEventBase& aEvent,
ScrollableLayerGuid* aOutTargetGuid,
uint64_t* aOutInputBlockId)
{
MOZ_ASSERT(NS_IsMainThread());
// Note, we call this before having transformed the reference point.
UpdateWheelTransaction(aEvent);
MouseInput input(aEvent);
input.mOrigin = ScreenPoint(aEvent.refPoint.x, aEvent.refPoint.y);

View File

@ -3351,11 +3351,8 @@ AsyncPanZoomController::CurrentPanGestureBlock()
}
void
AsyncPanZoomController::ResetInputState()
AsyncPanZoomController::ResetTouchInputState()
{
// This may be called during non-touch input blocks as well. We send
// a fake cancel touch event here but on the assumption that none of the
// code in GEL assumes a CurrentTouchBlock()
MultiTouchInput cancel(MultiTouchInput::MULTITOUCH_CANCEL, 0, TimeStamp::Now(), 0);
RefPtr<GestureEventListener> listener = GetGestureEventListener();
if (listener) {

View File

@ -834,9 +834,9 @@ public:
bool ArePointerEventsConsumable(TouchBlockState* aBlock, uint32_t aTouchPoints);
/**
* Clear internal state relating to input handling.
* Clear internal state relating to touch input handling.
*/
void ResetInputState();
void ResetTouchInputState();
private:
void CancelAnimationAndGestureState();

View File

@ -651,7 +651,9 @@ InputQueue::ProcessInputBlocks() {
curBlock->DropEvents();
} else if (curBlock->IsDefaultPrevented()) {
curBlock->DropEvents();
target->ResetInputState();
if (curBlock->AsTouchBlock()) {
target->ResetTouchInputState();
}
} else {
UpdateActiveApzc(curBlock->GetTargetApzc());
curBlock->HandleEvents();
@ -677,7 +679,7 @@ void
InputQueue::UpdateActiveApzc(const RefPtr<AsyncPanZoomController>& aNewActive) {
if (mLastActiveApzc && mLastActiveApzc != aNewActive
&& mTouchCounter.GetActiveTouchCount() > 0) {
mLastActiveApzc->ResetInputState();
mLastActiveApzc->ResetTouchInputState();
}
mLastActiveApzc = aNewActive;
}

View File

@ -48,7 +48,7 @@ public:
}
}
virtual void SetData(const Data& aData) override;
virtual bool SetData(const Data& aData) override;
virtual void SetDelayedConversion(bool aDelayed) override { mDelayedConversion = aDelayed; }
already_AddRefed<gfx::SourceSurface> GetAsSourceSurface() override;
@ -91,20 +91,20 @@ public:
}
};
void
bool
BasicPlanarYCbCrImage::SetData(const Data& aData)
{
PlanarYCbCrImage::SetData(aData);
if (mDelayedConversion) {
return;
return false;
}
// Do some sanity checks to prevent integer overflow
if (aData.mYSize.width > PlanarYCbCrImage::MAX_DIMENSION ||
aData.mYSize.height > PlanarYCbCrImage::MAX_DIMENSION) {
NS_ERROR("Illegal image source width or height");
return;
return false;
}
gfx::SurfaceFormat format = gfx::ImageFormatToSurfaceFormat(GetOffscreenFormat());
@ -114,7 +114,7 @@ BasicPlanarYCbCrImage::SetData(const Data& aData)
if (size.width > PlanarYCbCrImage::MAX_DIMENSION ||
size.height > PlanarYCbCrImage::MAX_DIMENSION) {
NS_ERROR("Illegal image dest width or height");
return;
return false;
}
gfxImageFormat iFormat = gfx::SurfaceFormatToImageFormat(format);
@ -122,12 +122,14 @@ BasicPlanarYCbCrImage::SetData(const Data& aData)
mDecodedBuffer = AllocateBuffer(size.height * mStride);
if (!mDecodedBuffer) {
// out of memory
return;
return false;
}
gfx::ConvertYCbCrToRGB(aData, format, size, mDecodedBuffer, mStride);
SetOffscreenFormat(iFormat);
mSize = size;
return true;
}
already_AddRefed<gfx::SourceSurface>

View File

@ -1650,6 +1650,7 @@ CompositorParent::SetControllerForLayerTree(uint64_t aLayersId,
/*static*/ APZCTreeManager*
CompositorParent::GetAPZCTreeManager(uint64_t aLayersId)
{
EnsureLayerTreeMapReady();
const CompositorParent::LayerTreeState* state = CompositorParent::GetIndirectShadowTree(aLayersId);
if (state && state->mParent) {
return state->mParent->mApzcTreeManager;

View File

@ -80,7 +80,7 @@ SharedPlanarYCbCrImage::GetAsSourceSurface()
return PlanarYCbCrImage::GetAsSourceSurface();
}
void
bool
SharedPlanarYCbCrImage::SetData(const PlanarYCbCrData& aData)
{
// If mTextureClient has not already been allocated (through Allocate(aData))
@ -88,20 +88,21 @@ SharedPlanarYCbCrImage::SetData(const PlanarYCbCrData& aData)
// been called since it will trigger a full copy.
PlanarYCbCrData data = aData;
if (!mTextureClient && !Allocate(data)) {
return;
return false;
}
MOZ_ASSERT(mTextureClient->AsTextureClientYCbCr());
if (!mTextureClient->Lock(OpenMode::OPEN_WRITE_ONLY)) {
MOZ_ASSERT(false, "Failed to lock the texture.");
return;
return false;
}
TextureClientAutoUnlock unlock(mTextureClient);
if (!mTextureClient->AsTextureClientYCbCr()->UpdateYCbCr(aData)) {
MOZ_ASSERT(false, "Failed to copy YCbCr data into the TextureClient");
return;
return false;
}
mTextureClient->MarkImmutable();
return true;
}
// needs to be overriden because the parent class sets mBuffer which we
@ -131,12 +132,12 @@ SharedPlanarYCbCrImage::AllocateAndGetNewBuffer(uint32_t aSize)
return serializer.GetData();
}
void
bool
SharedPlanarYCbCrImage::SetDataNoCopy(const Data &aData)
{
MOZ_ASSERT(mTextureClient, "This Image should have already allocated data");
if (!mTextureClient) {
return;
return false;
}
mData = aData;
mSize = aData.mPicSize;
@ -159,6 +160,7 @@ SharedPlanarYCbCrImage::SetDataNoCopy(const Data &aData)
aData.mYSize,
aData.mCbCrSize,
aData.mStereoMode);
return true;
}
uint8_t*

View File

@ -35,8 +35,8 @@ public:
virtual uint8_t* GetBuffer() override;
virtual already_AddRefed<gfx::SourceSurface> GetAsSourceSurface() override;
virtual void SetData(const PlanarYCbCrData& aData) override;
virtual void SetDataNoCopy(const Data &aData) override;
virtual bool SetData(const PlanarYCbCrData& aData) override;
virtual bool SetDataNoCopy(const Data &aData) override;
virtual bool Allocate(PlanarYCbCrData& aData);
virtual uint8_t* AllocateBuffer(uint32_t aSize) override;

View File

@ -11,6 +11,7 @@
#include "nsMathUtils.h"
#include <math.h>
#include <float.h>
#include <stdlib.h>
#include "nsDebug.h"
#include <algorithm>
@ -57,6 +58,22 @@ inline void VERIFY_COORD(nscoord aCoord) {
#endif
}
/**
* Divide aSpace by aN. Assign the resulting quotient to aQuotient and
* return the remainder.
*/
inline nscoord NSCoordDivRem(nscoord aSpace, size_t aN, nscoord* aQuotient)
{
#ifdef NS_COORD_IS_FLOAT
*aQuotient = aSpace / aN;
return 0.0f;
#else
div_t result = div(aSpace, aN);
*aQuotient = nscoord(result.quot);
return nscoord(result.rem);
#endif
}
inline nscoord NSCoordMulDiv(nscoord aMult1, nscoord aMult2, nscoord aDiv) {
#ifdef NS_COORD_IS_FLOAT
return (aMult1 * aMult2 / aDiv);

View File

@ -1297,7 +1297,7 @@ js::AsmJSFunctionToString(JSContext* cx, HandleFunction fun)
size_t nameEnd = begin + fun->atom()->length();
Rooted<JSFlatString*> src(cx, source->substring(cx, nameEnd, end));
if (!AppendUseStrictSource(cx, fun, src, out))
if (!src || !AppendUseStrictSource(cx, fun, src, out))
return nullptr;
} else {
Rooted<JSFlatString*> src(cx, source->substring(cx, begin, end));

View File

@ -1928,6 +1928,27 @@ NewUDateFormat(JSContext* cx, HandleObject dateTimeFormat)
UErrorCode status = U_ZERO_ERROR;
if (!uTimeZone) {
#if ENABLE_INTL_API && defined(ICU_TZ_HAS_RECREATE_DEFAULT)
// JS::ResetTimeZone() recomputes the JS language's LocalTZA value. It
// *should* also recreate ICU's default time zone (used for formatting
// when no time zone has been specified), but this operation is slow.
// Doing it eagerly introduces a perf regression -- see bug 1220693.
// Therefore we perform it lazily, responding to the value of a global
// atomic variable that records whether ICU's default time zone is
// accurate. Baroque, but it's the only way to get the job done.
//
// Beware: this is kosher *only* if every place using ICU's default
// time zone performs the atomic compare-exchange and possible
// recreation song and dance routine here.
if (js::DefaultTimeZoneStatus.compareExchange(IcuTimeZoneStatus::NeedsUpdate,
IcuTimeZoneStatus::Updating))
{
icu::TimeZone::recreateDefault();
}
#endif
}
// If building with ICU headers before 50.1, use UDAT_IGNORE instead of
// UDAT_PATTERN.
UDateFormat* df =

View File

@ -793,7 +793,10 @@ ModuleObject::evaluate(JSContext* cx, HandleModuleObject self, MutableHandleValu
{
RootedScript script(cx, self->script());
RootedModuleEnvironmentObject scope(cx, self->environment());
MOZ_ASSERT(scope);
if (!scope) {
JS_ReportError(cx, "Module declarations have not yet been instantiated");
return false;
}
return Execute(cx, script, *scope, rval.address());
}

View File

@ -83,7 +83,7 @@ js::obj_propertyIsEnumerable(JSContext* cx, unsigned argc, Value* vp)
/* Step 1. */
RootedId idRoot(cx);
if (!ValueToId<CanGC>(cx, idValue, &idRoot))
if (!ToPropertyKey(cx, idValue, &idRoot))
return false;
/* Step 2. */
@ -531,7 +531,7 @@ js::obj_hasOwnProperty(JSContext* cx, unsigned argc, Value* vp)
/* Step 1. */
RootedId idRoot(cx);
if (!ValueToId<CanGC>(cx, idValue, &idRoot))
if (!ToPropertyKey(cx, idValue, &idRoot))
return false;
/* Step 2. */
@ -774,7 +774,7 @@ js::obj_defineProperty(JSContext* cx, unsigned argc, Value* vp)
if (!GetFirstArgumentAsObject(cx, args, "Object.defineProperty", &obj))
return false;
RootedId id(cx);
if (!ValueToId<CanGC>(cx, args.get(1), &id))
if (!ToPropertyKey(cx, args.get(1), &id))
return false;
// Steps 4-5.

View File

@ -2491,8 +2491,9 @@ ASTSerializer::forInit(ParseNode* pn, MutableHandleValue dst)
return true;
}
return (pn->isKind(PNK_VAR))
? variableDeclaration(pn, false, dst)
bool lexical = pn->isKind(PNK_LET) || pn->isKind(PNK_CONST);
return (lexical || pn->isKind(PNK_VAR))
? variableDeclaration(pn, lexical, dst)
: expression(pn, dst);
}
@ -2641,32 +2642,31 @@ ASTSerializer::statement(ParseNode* pn, MutableHandleValue dst)
if (!statement(pn->pn_right, &stmt))
return false;
if (head->isKind(PNK_FORIN)) {
if (head->isKind(PNK_FORIN) || head->isKind(PNK_FOROF)) {
RootedValue var(cx);
return (!head->pn_kid1
? pattern(head->pn_kid2, &var)
: head->pn_kid1->isKind(PNK_LEXICALSCOPE)
? variableDeclaration(head->pn_kid1->pn_expr, true, &var)
: variableDeclaration(head->pn_kid1, false, &var)) &&
forIn(pn, head, var, stmt, dst);
}
if (head->isKind(PNK_FOROF)) {
RootedValue var(cx);
return (!head->pn_kid1
? pattern(head->pn_kid2, &var)
: head->pn_kid1->isKind(PNK_LEXICALSCOPE)
? variableDeclaration(head->pn_kid1->pn_expr, true, &var)
: variableDeclaration(head->pn_kid1, false, &var)) &&
forOf(pn, head, var, stmt, dst);
if (!head->pn_kid1) {
if (!pattern(head->pn_kid2, &var))
return false;
} else if (head->pn_kid1->isKind(PNK_LEXICALSCOPE)) {
if (!variableDeclaration(head->pn_kid1->pn_expr, true, &var))
return false;
} else {
if (!variableDeclaration(head->pn_kid1,
head->pn_kid1->isKind(PNK_LET) ||
head->pn_kid1->isKind(PNK_CONST),
&var))
{
return false;
}
}
if (head->isKind(PNK_FORIN))
return forIn(pn, head, var, stmt, dst);
return forOf(pn, head, var, stmt, dst);
}
RootedValue init(cx), test(cx), update(cx);
return forInit(head->pn_kid1 && !head->pn_kid1->isKind(PNK_FRESHENBLOCK)
? head->pn_kid1
: nullptr,
&init) &&
return forInit(head->pn_kid1, &init) &&
optExpression(head->pn_kid2, &test) &&
optExpression(head->pn_kid3, &update) &&
builder.forStatement(init, test, update, stmt, &pn->pn_pos, dst);

View File

@ -2323,7 +2323,6 @@ BytecodeEmitter::checkSideEffects(ParseNode* pn, bool* answer)
case PNK_FORIN: // by PNK_FOR
case PNK_FOROF: // by PNK_FOR
case PNK_FORHEAD: // by PNK_FOR
case PNK_FRESHENBLOCK: // by PNK_FOR
case PNK_CLASSMETHOD: // by PNK_CLASS
case PNK_CLASSNAMES: // by PNK_CLASS
case PNK_CLASSMETHODLIST: // by PNK_CLASS
@ -5289,6 +5288,15 @@ BytecodeEmitter::emitIterator()
bool
BytecodeEmitter::emitForInOrOfVariables(ParseNode* pn, bool* letDecl)
{
// ES6 specifies that loop variables get a fresh binding in each iteration.
// This is currently implemented for C-style for(;;) loops, but not
// for-in/of loops, though a similar approach should work. See bug 449811.
//
// In `for (let x in/of EXPR)`, ES6 specifies that EXPR is evaluated in a
// scope containing an uninitialized `x`. If EXPR accesses `x`, we should
// get a ReferenceError due to the TDZ violation. This is not yet
// implemented. See bug 1069480.
*letDecl = pn->isKind(PNK_LEXICALSCOPE);
MOZ_ASSERT_IF(*letDecl, pn->isLexical());
@ -5318,7 +5326,6 @@ BytecodeEmitter::emitForInOrOfVariables(ParseNode* pn, bool* letDecl)
return true;
}
bool
BytecodeEmitter::emitForOf(StmtType type, ParseNode* pn, ptrdiff_t top)
{
@ -5591,8 +5598,9 @@ BytecodeEmitter::emitForIn(ParseNode* pn, ptrdiff_t top)
return true;
}
/* C-style `for (init; cond; update) ...` loop. */
bool
BytecodeEmitter::emitNormalFor(ParseNode* pn, ptrdiff_t top)
BytecodeEmitter::emitCStyleFor(ParseNode* pn, ptrdiff_t top)
{
LoopStmtInfo stmtInfo(cx);
pushLoopStatement(&stmtInfo, StmtType::FOR_LOOP, top);
@ -5600,28 +5608,48 @@ BytecodeEmitter::emitNormalFor(ParseNode* pn, ptrdiff_t top)
ParseNode* forHead = pn->pn_left;
ParseNode* forBody = pn->pn_right;
/* C-style for (init; cond; update) ... loop. */
// If the head of this for-loop declared any lexical variables, the parser
// wrapped this PNK_FOR node in a PNK_LEXICALSCOPE representing the
// implicit scope of those variables. By the time we get here, we have
// already entered that scope. So far, so good.
//
// ### Scope freshening
//
// Each iteration of a `for (let V...)` loop creates a fresh loop variable
// binding for V, even if the loop is a C-style `for(;;)` loop:
//
// var funcs = [];
// for (let i = 0; i < 2; i++)
// funcs.push(function() { return i; });
// assertEq(funcs[0](), 0); // the two closures capture...
// assertEq(funcs[1](), 1); // ...two different `i` bindings
//
// This is implemented by "freshening" the implicit block -- changing the
// scope chain to a fresh clone of the instantaneous block object -- each
// iteration, just before evaluating the "update" in for(;;) loops.
//
// No freshening occurs in `for (const ...;;)` as there's no point: you
// can't reassign consts. This is observable through the Debugger API. (The
// ES6 spec also skips cloning the environment in this case.)
bool forLoopRequiresFreshening = false;
if (ParseNode* init = forHead->pn_kid1) {
if (init->isKind(PNK_FRESHENBLOCK)) {
// The loop's init declaration was hoisted into an enclosing lexical
// scope node. Note that the block scope must be freshened each
// iteration.
forLoopRequiresFreshening = true;
} else {
emittingForInit = true;
if (!updateSourceCoordNotes(init->pn_pos.begin))
return false;
if (!emitTree(init))
return false;
emittingForInit = false;
forLoopRequiresFreshening = init->isKind(PNK_LET);
if (!init->isKind(PNK_VAR) && !init->isKind(PNK_LET) && !init->isKind(PNK_CONST)) {
// 'init' is an expression, not a declaration. emitTree left
// its value on the stack.
if (!emit1(JSOP_POP))
return false;
}
// Emit the `init` clause, whether it's an expression or a variable
// declaration. (The loop variables were hoisted into an enclosing
// scope, but we still need to emit code for the initializers.)
emittingForInit = true;
if (!updateSourceCoordNotes(init->pn_pos.begin))
return false;
if (!emitTree(init))
return false;
emittingForInit = false;
if (!init->isKind(PNK_VAR) && !init->isKind(PNK_LET) && !init->isKind(PNK_CONST)) {
// 'init' is an expression, not a declaration. emitTree left its
// value on the stack.
if (!emit1(JSOP_POP))
return false;
}
}
@ -5749,7 +5777,7 @@ BytecodeEmitter::emitFor(ParseNode* pn, ptrdiff_t top)
return emitForOf(StmtType::FOR_OF_LOOP, pn, top);
MOZ_ASSERT(pn->pn_left->isKind(PNK_FORHEAD));
return emitNormalFor(pn, top);
return emitCStyleFor(pn, top);
}
MOZ_NEVER_INLINE bool

View File

@ -586,7 +586,7 @@ struct BytecodeEmitter
bool emitFor(ParseNode* pn, ptrdiff_t top);
bool emitForIn(ParseNode* pn, ptrdiff_t top);
bool emitForInOrOfVariables(ParseNode* pn, bool* letDecl);
bool emitNormalFor(ParseNode* pn, ptrdiff_t top);
bool emitCStyleFor(ParseNode* pn, ptrdiff_t top);
bool emitWhile(ParseNode* pn, ptrdiff_t top);
bool emitBreak(PropertyName* label);

View File

@ -408,7 +408,6 @@ ContainsHoistedDeclaration(ExclusiveContext* cx, ParseNode* node, bool* result)
case PNK_FORIN:
case PNK_FOROF:
case PNK_FORHEAD:
case PNK_FRESHENBLOCK:
case PNK_CLASSMETHOD:
case PNK_CLASSMETHODLIST:
case PNK_CLASSNAMES:
@ -1710,7 +1709,6 @@ Fold(ExclusiveContext* cx, ParseNode** pnp, Parser<FullParseHandler>& parser, bo
case PNK_GENERATOR:
case PNK_EXPORT_BATCH_SPEC:
case PNK_OBJECT_PROPERTY_NAME:
case PNK_FRESHENBLOCK:
case PNK_POSHOLDER:
MOZ_ASSERT(pn->isArity(PN_NULLARY));
return true;

View File

@ -571,10 +571,6 @@ class FullParseHandler
return new_<TernaryNode>(kind, JSOP_NOP, pn1, pn2, pn3, pos);
}
ParseNode* newFreshenBlock(const TokenPos& pos) {
return new_<NullaryNode>(PNK_FRESHENBLOCK, pos);
}
ParseNode* newSwitchStatement(uint32_t begin, ParseNode* discriminant, ParseNode* caseList) {
TokenPos pos(begin, caseList->pn_pos.end);
return new_<BinaryNode>(PNK_SWITCH, JSOP_NOP, pos, discriminant, caseList);

View File

@ -374,7 +374,6 @@ class NameResolver
case PNK_CONTINUE:
case PNK_DEBUGGER:
case PNK_EXPORT_BATCH_SPEC:
case PNK_FRESHENBLOCK:
case PNK_OBJECT_PROPERTY_NAME:
case PNK_POSHOLDER:
MOZ_ASSERT(cur->isArity(PN_NULLARY));

View File

@ -214,7 +214,6 @@ PushNodeChildren(ParseNode* pn, NodeStack* stack)
case PNK_DEBUGGER:
case PNK_EXPORT_BATCH_SPEC:
case PNK_OBJECT_PROPERTY_NAME:
case PNK_FRESHENBLOCK:
case PNK_POSHOLDER:
MOZ_ASSERT(pn->isArity(PN_NULLARY));
MOZ_ASSERT(!pn->isUsed(), "handle non-trivial cases separately");

View File

@ -165,7 +165,6 @@ class PackedScopeCoordinate
F(FORIN) \
F(FOROF) \
F(FORHEAD) \
F(FRESHENBLOCK) \
F(ARGSBODY) \
F(SPREAD) \
F(MUTATEPROTO) \

View File

@ -4063,7 +4063,8 @@ Parser<FullParseHandler>::pushLetScope(HandleStaticBlockObject blockObj, AutoPus
template <>
SyntaxParseHandler::Node
Parser<SyntaxParseHandler>::pushLetScope(HandleStaticBlockObject blockObj, AutoPushStmtInfoPC& stmt)
Parser<SyntaxParseHandler>::pushLetScope(HandleStaticBlockObject blockObj,
AutoPushStmtInfoPC& stmt)
{
JS_ALWAYS_FALSE(abortIfSyntaxParser());
return SyntaxParseHandler::NodeFailure;
@ -5187,19 +5188,37 @@ Parser<FullParseHandler>::forStatement(YieldHandling yieldHandling)
MUST_MATCH_TOKEN(TOK_LP, JSMSG_PAREN_AFTER_FOR);
/*
* True if we have 'for (var/let/const ...)'.
*/
// True if we have 'for (var/let/const ...)'.
bool isForDecl = false;
// The next three variables are used to implement `for (let/const ...)`.
//
// We generate an implicit block, wrapping the whole loop, to store loop
// variables declared this way. Note that if the loop uses `for (var...)`
// instead, those variables go on some existing enclosing scope, so no
// implicit block scope is created.
//
// All three variables remain null/none if the loop is any other form.
//
// blockObj is the static block object for the implicit block scope.
RootedStaticBlockObject blockObj(context);
// letStmt is the BLOCK StmtInfo for the implicit block.
//
// Caution: `letStmt.emplace()` creates some Rooted objects. Rooteds must
// be created/destroyed in FIFO order. Therefore adding a Rooted in this
// function, between this point and the .emplace() call below, would trip
// assertions.
Maybe<AutoPushStmtInfoPC> letStmt;
// The PNK_LEXICALSCOPE node containing blockObj's ObjectBox.
ParseNode* forLetImpliedBlock = nullptr;
// True if a 'let' token at the head is parsed as an identifier instead of
// as starting a declaration.
bool letIsIdentifier = false;
/* Non-null when isForDecl is true for a 'for (let ...)' statement. */
RootedStaticBlockObject blockObj(context);
/* Set to 'x' in 'for (x ;... ;...)' or 'for (x in ...)'. */
// Set to 'x' in 'for (x; ...; ...)' or 'for (x in ...)'.
ParseNode* pn1;
TokenStream::Modifier modifier = TokenStream::Operand;
@ -5249,9 +5268,19 @@ Parser<FullParseHandler>::forStatement(YieldHandling yieldHandling)
// Initialize the enclosing scope manually for the call to
// |variables| below.
blockObj = StaticBlockObject::create(context);
if (!blockObj)
return null();
blockObj->initEnclosingScopeFromParser(pc->innermostStaticScope());
letStmt.emplace(*this, StmtType::BLOCK);
forLetImpliedBlock = pushLetScope(blockObj, *letStmt);
if (!forLetImpliedBlock)
return null();
(*letStmt)->isForLetBlock = true;
MOZ_ASSERT(CurrentLexicalStaticBlock(pc) == blockObj);
pn1 = variables(yieldHandling, constDecl ? PNK_CONST : PNK_LET, InForInit,
nullptr, blockObj, DontHoistVars);
nullptr, blockObj, HoistVars);
} else {
pn1 = expr(InProhibited, yieldHandling, TripledotProhibited);
}
@ -5269,60 +5298,10 @@ Parser<FullParseHandler>::forStatement(YieldHandling yieldHandling)
}
MOZ_ASSERT_IF(isForDecl, pn1->isArity(PN_LIST));
MOZ_ASSERT(!!blockObj == (isForDecl && (pn1->isOp(JSOP_DEFLET) || pn1->isOp(JSOP_DEFCONST))));
// If the head of a for-loop declares any lexical variables, we generate an
// implicit block to store them. We implement this by desugaring. These:
//
// for (let/const <bindings>; <test>; <update>) <stmt>
// for (let <pattern> in <expr>) <stmt>
// for (let <pattern> of <expr>) <stmt>
//
// transform into roughly the same parse trees as these (using deprecated
// let-block syntax):
//
// let (<bindings>) { for (; <test>; <update>) <stmt> }
// let (<pattern>) { for (<pattern> in <expr>) <stmt> }
// let (<pattern>) { for (<pattern> of <expr>) <stmt> }
//
// This desugaring is not ES6 compliant. Initializers in the head of a
// let-block are evaluated *outside* the scope of the variables being
// initialized. ES6 mandates that they be evaluated in the same scope,
// triggering used-before-initialization temporal dead zone errors as
// necessary. See bug 1216623 on scoping and bug 1069480 on TDZ.
//
// Additionally, in ES6, each iteration of a for-loop creates a fresh
// binding of the loop variables. For example:
//
// var funcs = [];
// for (let i = 0; i < 2; i++)
// funcs.push(function() { return i; });
// assertEq(funcs[0](), 0); // the two closures capture...
// assertEq(funcs[1](), 1); // ...two different `i` bindings
//
// These semantics are implemented by "freshening" the implicit block --
// changing the scope chain to a fresh clone of the instantaneous block
// object -- each iteration, just before evaluating the "update" in
// for(;;) loops. We don't implement this freshening for for-in/of loops
// yet: bug 449811.
//
// No freshening occurs in `for (const ...;;)` as there's no point: you
// can't reassign consts. This is observable through the Debugger API. (The
// ES6 spec also skips cloning the environment in this case.)
//
// If the for-loop head includes a lexical declaration, then we create an
// implicit block scope, and:
//
// * forLetImpliedBlock is the node for the implicit block scope.
// * forLetDecl is the node for the decl 'let/const <pattern>'.
//
// Otherwise both are null.
ParseNode* forLetImpliedBlock = nullptr;
ParseNode* forLetDecl = nullptr;
MOZ_ASSERT(letStmt.isSome() == (isForDecl && (pn1->isOp(JSOP_DEFLET) || pn1->isOp(JSOP_DEFCONST))));
// If there's an |in| keyword here, it's a for-in loop, by dint of careful
// parsing of |pn1|.
Maybe<AutoPushStmtInfoPC> letStmt; /* used if blockObj != nullptr. */
ParseNode* pn2; /* forHead->pn_kid2 */
ParseNode* pn3; /* forHead->pn_kid3 */
ParseNodeKind headKind = PNK_FORHEAD;
@ -5393,7 +5372,7 @@ Parser<FullParseHandler>::forStatement(YieldHandling yieldHandling)
}
} else {
/* Not a declaration. */
MOZ_ASSERT(!blockObj);
MOZ_ASSERT(!letStmt);
pn2 = pn1;
pn1 = nullptr;
@ -5408,27 +5387,10 @@ Parser<FullParseHandler>::forStatement(YieldHandling yieldHandling)
return null();
modifier = TokenStream::None;
if (blockObj) {
/*
* Now that the pn3 has been parsed, push the let scope. To hold
* the blockObj for the emitter, wrap the PNK_LEXICALSCOPE node
* created by pushLetScope around the for's initializer. This also
* serves to indicate the let-decl to the emitter.
*/
letStmt.emplace(*this, StmtType::BLOCK);
ParseNode* block = pushLetScope(blockObj, *letStmt);
if (!block)
return null();
(*letStmt)->isForLetBlock = true;
block->pn_expr = pn1;
block->pn_pos = pn1->pn_pos;
pn1 = block;
}
if (isForDecl) {
/*
* pn2 is part of a declaration. Make a copy that can be passed to
* EmitAssignment. Take care to do this after pushLetScope.
* BytecodeEmitter::emitAssignment.
*/
pn2 = cloneLeftHandSide(pn2);
if (!pn2)
@ -5450,47 +5412,13 @@ Parser<FullParseHandler>::forStatement(YieldHandling yieldHandling)
MOZ_ASSERT(headKind == PNK_FORHEAD);
if (blockObj) {
if (letStmt) {
// Ensure here that the previously-unchecked assignment mandate for
// const declarations holds.
if (!checkForHeadConstInitializers(pn1)) {
report(ParseError, false, nullptr, JSMSG_BAD_CONST_DECL);
return null();
}
// Desugar
//
// for (let INIT; TEST; UPDATE) STMT
//
// into
//
// let (INIT) { for (; TEST; UPDATE) STMT }
//
// to provide a block scope for INIT.
letStmt.emplace(*this, StmtType::BLOCK);
forLetImpliedBlock = pushLetScope(blockObj, *letStmt);
if (!forLetImpliedBlock)
return null();
(*letStmt)->isForLetBlock = true;
forLetDecl = pn1;
// The above transformation isn't enough to implement |INIT|
// scoping, because each loop iteration must see separate bindings
// of |INIT|. We handle this by replacing the block on the scope
// chain with a new block, copying the old one's contents, each
// iteration. We supply a special PNK_FRESHENBLOCK node as the
// |let INIT| node for |for(let INIT;;)| loop heads to distinguish
// such nodes from *actual*, non-desugared use of the above syntax.
// (We don't do this for PNK_CONST nodes because the spec says no
// freshening happens -- observable with the Debugger API.)
if (pn1->isKind(PNK_CONST)) {
pn1 = nullptr;
} else {
pn1 = handler.newFreshenBlock(pn1->pn_pos);
if (!pn1)
return null();
}
}
/* Parse the loop condition or null into pn2. */
@ -5542,7 +5470,7 @@ Parser<FullParseHandler>::forStatement(YieldHandling yieldHandling)
if (forLetImpliedBlock) {
forLetImpliedBlock->pn_expr = forLoop;
forLetImpliedBlock->pn_pos = forLoop->pn_pos;
return handler.newLetBlock(forLetDecl, forLetImpliedBlock, forLoop->pn_pos);
return forLetImpliedBlock;
}
return forLoop;
}
@ -8293,6 +8221,7 @@ Parser<ParseHandler>::comprehensionFor(GeneratorKind comprehensionKind)
RootedStaticBlockObject blockObj(context, StaticBlockObject::create(context));
if (!blockObj)
return null();
// Initialize the enclosing scope manually for the call to |bind|
// below, which is before the call to |pushLetScope|.
blockObj->initEnclosingScopeFromParser(pc->innermostStaticScope());

View File

@ -0,0 +1,12 @@
"use strict";
if (!('oomTest' in this))
quit();
let g = (function() {
"use asm";
function f() {}
return f;
})();
oomTest(() => "" + g);

View File

@ -0,0 +1,9 @@
var x = [1, 2, , 4]
x[100000] = 1;
var y = Object.create(x);
y.a = 1;
y.b = 1;
var arr = [];
for (var z in y)
arr.push(z);
assertEq(arr.join(), "a,b,0,1,3,100000");

View File

@ -1,16 +1,16 @@
var s, x = 0;
var s, v = "NOPE";
s = '';
for (let x = x; x < 3; x++)
for (let v = 0, x = v; x < 3; x++)
s += x;
assertEq(s, '012');
s = '';
for (let x = eval('x'); x < 3; x++)
for (let v = 0, x = eval('v'); x < 3; x++)
s += x;
assertEq(s, '012');
s = ''
for (let x = function () { with ({}) return x; }(); x < 3; x++)
for (let v = 0, x = function () { with ({}) return v; }(); x < 3; x++)
s += x;
assertEq(s, '012');

View File

@ -1,4 +1,8 @@
var s = '', x = {a: 1, b: 2, c: 3};
// Scoping: `x` in the head of a `for (let x...)` loop refers to the loop variable.
// For now, this means it evaluates to undefined. It ought to throw a
// ReferenceError instead, but the TDZ isn't implemented here (bug 1069480).
var s = "", x = {a: 1, b: 2, c: 3};
for (let x in eval('x'))
s += x;
assertEq(s, 'abc');
assertEq(s, "");

View File

@ -0,0 +1,16 @@
// In `for (let x = EXPR; ;)`, if `x` appears within EXPR, it refers to the
// loop variable. Actually doing this is typically a TDZ error.
load(libdir + "asserts.js");
assertThrowsInstanceOf(() => {
for (let x = x; null.foo; null.foo++) {}
}, ReferenceError);
assertThrowsInstanceOf(() => {
for (let x = eval('x'); null.foo; null.foo++) {}
}, ReferenceError);
assertThrowsInstanceOf(() => {
for (let x = function () { with ({}) return x; }(); null.foo; null.foo++) {}
}, ReferenceError);

View File

@ -1,5 +0,0 @@
var x = "foobar";
{ for (let x of x) assertEq(x.length, 1, "second x refers to outer x"); }
var x = "foobar";
{ for (let x in x) assertEq(x.length, 1, "second x refers to outer x"); }

View File

@ -3,7 +3,8 @@ var otherGlobal = newGlobal();
function test(str, arg, result)
{
arg = arg || 'ponies';
result = result || 'ponies';
if (arguments.length < 3)
result = 'ponies';
var fun = new Function('x', str);
@ -136,11 +137,7 @@ test('for (let y = 1;; ++y) {return x;}');
test('for (let y = 1; ++y;) {return x;}');
test('for (let [[a, [b, c]]] = [[x, []]];;) {return a;}');
test('var sum = 0;for (let y = x; y < 4; ++y) {sum += y;}return sum;', 1, 6);
test('var sum = 0;for (let x = x, y = 10; x < 4; ++x) {sum += x;}return sum;', 1, 6);
test('var sum = 0;for (let x = x; x < 4; ++x) {sum += x;}return x;', 1, 1);
test('var sum = 0;for (let x = eval("x"); x < 4; ++x) {sum += x;}return sum;', 1, 6);
test('var sum = 0;for (let x = x; eval("x") < 4; ++x) {sum += eval("x");}return sum;', 1, 6);
test('var sum = 0;for (let x = eval("x"); eval("x") < 4; ++x) {sum += eval("x");}return sum;', 1, 6);
test('var sum = 0;for (let x = 1; eval("x") < 4; ++x) {sum += eval("x");}return sum;', 1, 6);
test('for (var y = 1;;) {return x;}');
test('for (var y = 1;; ++y) {return x;}');
test('for (var y = 1; ++y;) {return x;}');
@ -151,8 +148,6 @@ test('var sum = 0;for (var X = x; X < 4; ++X) {sum += X;}return x;', 1, 1);
test('var sum = 0;for (var X = eval("x"); X < 4; ++X) {sum += X;}return sum;', 1, 6);
test('var sum = 0;for (var X = x; eval("X") < 4; ++X) {sum += eval("X");}return sum;', 1, 6);
test('var sum = 0;for (var X = eval("x"); eval("X") < 4; ++X) {sum += eval("X");}return sum;', 1, 6);
test('try {for (let x = eval("throw x");;) {}} catch (e) {return e;}');
test('try {for (let x = x + "s"; eval("throw x");) {}} catch (e) {return e;}', 'ponie');
test('for (let y = x;;) {let x;return y;}');
test('for (let y = x;;) {let y;return x;}');
test('for (let y;;) {let y;return x;}');
@ -170,28 +165,31 @@ test('for (let i in x) {return x;}');
test('for (let i in x) {let y;return x;}');
test('for each (let [a, b] in x) {let y;return x;}');
test('for (let i in x) {let i = x;return i;}');
test('for each (let [x, y] in x) {return x + y;}', [['ponies', '']]);
test('for each (let [{0: x, 1: y}, z] in x) {return x + y + z;}', [[['po','nies'], '']]);
test('var s = "";for (let a in x) {for (let b in x) {s += a + b;}}return s;', [1,2], '00011011');
test('var res = "";for (let i in x) {res += x[i];}return res;');
test('var res = "";for (var i in x) {res += x[i];}return res;');
test('for each (let {x: y, y: x} in [{x: x, y: x}]) {return y;}');
test('for (let x in eval("x")) {return x;}', {ponies:true});
test('for (let x in x) {return eval("x");}', {ponies:true});
test('for (let x in eval("x")) {return eval("x");}', {ponies:true});
isParseError('for ((let (x = {y: true}) x).y in eval("x")) {return eval("x");}');
test('for (let i in x) {break;}return x;');
test('for (let i in x) {break;}return eval("x");');
test('for (let x in x) {break;}return x;');
test('for (let x in x) {break;}return eval("x");');
test('a:for (let i in x) {for (let j in x) {break a;}}return x;');
test('a:for (let i in x) {for (let j in x) {break a;}}return eval("x");');
test('var j;for (let i in x) {j = i;break;}return j;', {ponies:true});
test('try {for (let x in eval("throw x")) {}} catch (e) {return e;}');
test('try {for each (let x in x) {eval("throw x");}} catch (e) {return e;}', ['ponies']);
isParseError('for (let [x, x] in o) {}');
isParseError('for (let [x, y, x] in o) {}');
isParseError('for (let [x, [y, [x]]] in o) {}');
// for(let ... in ...) scoping bugs (bug 1069480)
test('for each (let [x, y] in x) {return x + y;}', [['ponies', '']], undefined);
test('for each (let [{0: x, 1: y}, z] in x) {return x + y + z;}', [[['po','nies'], '']], undefined);
test('for (let x in eval("x")) {return x;}', {ponies:true}, undefined);
test('for (let x in x) {return eval("x");}', {ponies:true}, undefined);
test('for (let x in eval("x")) {return eval("x");}', {ponies:true}, undefined);
test('for (let x in x) {break;}return x;');
test('for (let x in x) {break;}return eval("x");');
test('try {for (let x in eval("throw x")) {}} catch (e) {return e;}', undefined, undefined);
test('try {for each (let x in x) {eval("throw x");}} catch (e) {return e;}', ['ponies'], undefined);
test('for each (let {x: y, y: x} in [{x: x, y: x}]) {return y;}', undefined, undefined);
// genexps
test('return (i for (i in x)).next();', {ponies:true});
test('return (eval("i") for (i in x)).next();', {ponies:true});
@ -222,6 +220,13 @@ isReferenceError('let {x} = {x:x};');
isReferenceError('switch (x) {case 3:let x;break;default:if (x === undefined) {return "ponies";}}');
isReferenceError('let x = function() {} ? x() : function() {}');
isReferenceError('(function() { let x = (function() { return x }()); }())');
isReferenceError('var sum = 0;for (let x = x, y = 10; x < 4; ++x) {sum += x;}return sum;');
isReferenceError('var sum = 0;for (let x = x; x < 4; ++x) {sum += x;}return x;');
isReferenceError('var sum = 0;for (let x = eval("x"); x < 4; ++x) {sum += x;}return sum;');
isReferenceError('var sum = 0;for (let x = x; eval("x") < 4; ++x) {sum += eval("x");}return sum;');
isReferenceError('var sum = 0;for (let x = eval("x"); eval("x") < 4; ++x) {sum += eval("x");}return sum;');
isReferenceError('for (let x = eval("throw x");;) {}');
isReferenceError('for (let x = x + "s"; eval("throw x");) {}');
// redecl with function statements
isParseError('let a; function a() {}');

View File

@ -0,0 +1,2 @@
// |jit-test| error: Error
parseModule("").evaluation();

View File

@ -9299,49 +9299,6 @@ CodeGenerator::visitAtomicIsLockFree(LAtomicIsLockFree* lir)
masm.bind(&Ldone);
}
void
CodeGenerator::visitCompareExchangeTypedArrayElement(LCompareExchangeTypedArrayElement* lir)
{
Register elements = ToRegister(lir->elements());
AnyRegister output = ToAnyRegister(lir->output());
Register temp = lir->temp()->isBogusTemp() ? InvalidReg : ToRegister(lir->temp());
Register oldval = ToRegister(lir->oldval());
Register newval = ToRegister(lir->newval());
Scalar::Type arrayType = lir->mir()->arrayType();
int width = Scalar::byteSize(arrayType);
if (lir->index()->isConstant()) {
Address dest(elements, ToInt32(lir->index()) * width);
masm.compareExchangeToTypedIntArray(arrayType, dest, oldval, newval, temp, output);
} else {
BaseIndex dest(elements, ToRegister(lir->index()), ScaleFromElemWidth(width));
masm.compareExchangeToTypedIntArray(arrayType, dest, oldval, newval, temp, output);
}
}
void
CodeGenerator::visitAtomicExchangeTypedArrayElement(LAtomicExchangeTypedArrayElement* lir)
{
Register elements = ToRegister(lir->elements());
AnyRegister output = ToAnyRegister(lir->output());
Register temp = lir->temp()->isBogusTemp() ? InvalidReg : ToRegister(lir->temp());
Register value = ToRegister(lir->value());
Scalar::Type arrayType = lir->mir()->arrayType();
int width = Scalar::byteSize(arrayType);
if (lir->index()->isConstant()) {
Address dest(elements, ToInt32(lir->index()) * width);
masm.atomicExchangeToTypedIntArray(arrayType, dest, value, temp, output);
} else {
BaseIndex dest(elements, ToRegister(lir->index()), ScaleFromElemWidth(width));
masm.atomicExchangeToTypedIntArray(arrayType, dest, value, temp, output);
}
}
void
CodeGenerator::visitClampIToUint8(LClampIToUint8* lir)
{

View File

@ -286,8 +286,6 @@ class CodeGenerator : public CodeGeneratorSpecific
void visitStoreUnboxedScalar(LStoreUnboxedScalar* lir);
void visitStoreTypedArrayElementHole(LStoreTypedArrayElementHole* lir);
void visitAtomicIsLockFree(LAtomicIsLockFree* lir);
void visitCompareExchangeTypedArrayElement(LCompareExchangeTypedArrayElement* lir);
void visitAtomicExchangeTypedArrayElement(LAtomicExchangeTypedArrayElement* lir);
void visitClampIToUint8(LClampIToUint8* lir);
void visitClampDToUint8(LClampDToUint8* lir);
void visitClampVToUint8(LClampVToUint8* lir);

View File

@ -11869,6 +11869,11 @@ IonBuilder::getPropTryInnerize(bool* emitted, MDefinition* obj, PropertyName* na
{
// See the comment in tryInnerizeWindow for how this works.
// Note that it's important that we do this _before_ we'd try to
// do the optimizations below on obj normally, since some of those
// optimizations have fallback paths that are slower than the path
// we'd produce here.
MOZ_ASSERT(*emitted == false);
MDefinition* inner = tryInnerizeWindow(obj);
@ -11876,15 +11881,6 @@ IonBuilder::getPropTryInnerize(bool* emitted, MDefinition* obj, PropertyName* na
return true;
if (!forceInlineCaches()) {
// Note: the Baseline ICs don't know about this optimization, so it's
// possible the global property's HeapTypeSet has not been initialized
// yet. In this case we'll fall back to getPropTryCache for now.
// Note that it's important that we do this _before_ we'd try to
// do the optimizations below on obj normally, since some of those
// optimizations have fallback paths that are slower than the path
// we'd produce here.
trackOptimizationAttempt(TrackedStrategy::GetProp_Constant);
if (!getPropTryConstant(emitted, inner, NameToId(name), types) || *emitted)
return *emitted;

View File

@ -446,95 +446,6 @@ template void MacroAssembler::loadFromTypedArray(Scalar::Type arrayType, const A
template void MacroAssembler::loadFromTypedArray(Scalar::Type arrayType, const BaseIndex& src, const ValueOperand& dest,
bool allowDouble, Register temp, Label* fail);
template<typename T>
void
MacroAssembler::compareExchangeToTypedIntArray(Scalar::Type arrayType, const T& mem,
Register oldval, Register newval,
Register temp, AnyRegister output)
{
switch (arrayType) {
case Scalar::Int8:
compareExchange8SignExtend(mem, oldval, newval, output.gpr());
break;
case Scalar::Uint8:
compareExchange8ZeroExtend(mem, oldval, newval, output.gpr());
break;
case Scalar::Uint8Clamped:
compareExchange8ZeroExtend(mem, oldval, newval, output.gpr());
break;
case Scalar::Int16:
compareExchange16SignExtend(mem, oldval, newval, output.gpr());
break;
case Scalar::Uint16:
compareExchange16ZeroExtend(mem, oldval, newval, output.gpr());
break;
case Scalar::Int32:
compareExchange32(mem, oldval, newval, output.gpr());
break;
case Scalar::Uint32:
// At the moment, the code in MCallOptimize.cpp requires the output
// type to be double for uint32 arrays. See bug 1077305.
MOZ_ASSERT(output.isFloat());
compareExchange32(mem, oldval, newval, temp);
convertUInt32ToDouble(temp, output.fpu());
break;
default:
MOZ_CRASH("Invalid typed array type");
}
}
template void
MacroAssembler::compareExchangeToTypedIntArray(Scalar::Type arrayType, const Address& mem,
Register oldval, Register newval, Register temp,
AnyRegister output);
template void
MacroAssembler::compareExchangeToTypedIntArray(Scalar::Type arrayType, const BaseIndex& mem,
Register oldval, Register newval, Register temp,
AnyRegister output);
template<typename T>
void
MacroAssembler::atomicExchangeToTypedIntArray(Scalar::Type arrayType, const T& mem,
Register value, Register temp, AnyRegister output)
{
switch (arrayType) {
case Scalar::Int8:
atomicExchange8SignExtend(mem, value, output.gpr());
break;
case Scalar::Uint8:
atomicExchange8ZeroExtend(mem, value, output.gpr());
break;
case Scalar::Uint8Clamped:
atomicExchange8ZeroExtend(mem, value, output.gpr());
break;
case Scalar::Int16:
atomicExchange16SignExtend(mem, value, output.gpr());
break;
case Scalar::Uint16:
atomicExchange16ZeroExtend(mem, value, output.gpr());
break;
case Scalar::Int32:
atomicExchange32(mem, value, output.gpr());
break;
case Scalar::Uint32:
// At the moment, the code in MCallOptimize.cpp requires the output
// type to be double for uint32 arrays. See bug 1077305.
MOZ_ASSERT(output.isFloat());
atomicExchange32(mem, value, temp);
convertUInt32ToDouble(temp, output.fpu());
break;
default:
MOZ_CRASH("Invalid typed array type");
}
}
template void
MacroAssembler::atomicExchangeToTypedIntArray(Scalar::Type arrayType, const Address& mem,
Register value, Register temp, AnyRegister output);
template void
MacroAssembler::atomicExchangeToTypedIntArray(Scalar::Type arrayType, const BaseIndex& mem,
Register value, Register temp, AnyRegister output);
template <typename T>
void
MacroAssembler::loadUnboxedProperty(T address, JSValueType type, TypedOrValueRegister output)

View File

@ -1074,14 +1074,6 @@ class MacroAssembler : public MacroAssemblerSpecific
}
}
template<typename T>
void compareExchangeToTypedIntArray(Scalar::Type arrayType, const T& mem, Register oldval, Register newval,
Register temp, AnyRegister output);
template<typename T>
void atomicExchangeToTypedIntArray(Scalar::Type arrayType, const T& mem, Register value,
Register temp, AnyRegister output);
void storeToTypedFloatArray(Scalar::Type arrayType, FloatRegister value, const BaseIndex& dest,
unsigned numElems = 0);
void storeToTypedFloatArray(Scalar::Type arrayType, FloatRegister value, const Address& dest,

View File

@ -537,7 +537,7 @@ bool
OperatorIn(JSContext* cx, HandleValue key, HandleObject obj, bool* out)
{
RootedId id(cx);
return ValueToId<CanGC>(cx, key, &id) &&
return ToPropertyKey(cx, key, &id) &&
HasProperty(cx, obj, id, out);
}

View File

@ -1690,6 +1690,48 @@ CodeGeneratorARM::visitStoreTypedArrayElementStatic(LStoreTypedArrayElementStati
MOZ_CRASH("NYI");
}
void
CodeGeneratorARM::visitCompareExchangeTypedArrayElement(LCompareExchangeTypedArrayElement* lir)
{
Register elements = ToRegister(lir->elements());
AnyRegister output = ToAnyRegister(lir->output());
Register temp = lir->temp()->isBogusTemp() ? InvalidReg : ToRegister(lir->temp());
Register oldval = ToRegister(lir->oldval());
Register newval = ToRegister(lir->newval());
Scalar::Type arrayType = lir->mir()->arrayType();
int width = Scalar::byteSize(arrayType);
if (lir->index()->isConstant()) {
Address dest(elements, ToInt32(lir->index()) * width);
masm.compareExchangeToTypedIntArray(arrayType, dest, oldval, newval, temp, output);
} else {
BaseIndex dest(elements, ToRegister(lir->index()), ScaleFromElemWidth(width));
masm.compareExchangeToTypedIntArray(arrayType, dest, oldval, newval, temp, output);
}
}
void
CodeGeneratorARM::visitAtomicExchangeTypedArrayElement(LAtomicExchangeTypedArrayElement* lir)
{
Register elements = ToRegister(lir->elements());
AnyRegister output = ToAnyRegister(lir->output());
Register temp = lir->temp()->isBogusTemp() ? InvalidReg : ToRegister(lir->temp());
Register value = ToRegister(lir->value());
Scalar::Type arrayType = lir->mir()->arrayType();
int width = Scalar::byteSize(arrayType);
if (lir->index()->isConstant()) {
Address dest(elements, ToInt32(lir->index()) * width);
masm.atomicExchangeToTypedIntArray(arrayType, dest, value, temp, output);
} else {
BaseIndex dest(elements, ToRegister(lir->index()), ScaleFromElemWidth(width));
masm.atomicExchangeToTypedIntArray(arrayType, dest, value, temp, output);
}
}
template<typename S, typename T>
void

View File

@ -196,6 +196,8 @@ class CodeGeneratorARM : public CodeGeneratorShared
void visitStoreTypedArrayElementStatic(LStoreTypedArrayElementStatic* ins);
void visitAtomicTypedArrayElementBinop(LAtomicTypedArrayElementBinop* lir);
void visitAtomicTypedArrayElementBinopForEffect(LAtomicTypedArrayElementBinopForEffect* lir);
void visitCompareExchangeTypedArrayElement(LCompareExchangeTypedArrayElement* lir);
void visitAtomicExchangeTypedArrayElement(LAtomicExchangeTypedArrayElement* lir);
void visitAsmJSCall(LAsmJSCall* ins);
void visitAsmJSLoadHeap(LAsmJSLoadHeap* ins);
void visitAsmJSStoreHeap(LAsmJSStoreHeap* ins);

View File

@ -4827,6 +4827,95 @@ template void
js::jit::MacroAssemblerARMCompat::atomicEffectOp(int nbytes, AtomicOp op, const Register& value,
const BaseIndex& mem, Register flagTemp);
template<typename T>
void
MacroAssemblerARMCompat::compareExchangeToTypedIntArray(Scalar::Type arrayType, const T& mem,
Register oldval, Register newval,
Register temp, AnyRegister output)
{
switch (arrayType) {
case Scalar::Int8:
compareExchange8SignExtend(mem, oldval, newval, output.gpr());
break;
case Scalar::Uint8:
compareExchange8ZeroExtend(mem, oldval, newval, output.gpr());
break;
case Scalar::Uint8Clamped:
compareExchange8ZeroExtend(mem, oldval, newval, output.gpr());
break;
case Scalar::Int16:
compareExchange16SignExtend(mem, oldval, newval, output.gpr());
break;
case Scalar::Uint16:
compareExchange16ZeroExtend(mem, oldval, newval, output.gpr());
break;
case Scalar::Int32:
compareExchange32(mem, oldval, newval, output.gpr());
break;
case Scalar::Uint32:
// At the moment, the code in MCallOptimize.cpp requires the output
// type to be double for uint32 arrays. See bug 1077305.
MOZ_ASSERT(output.isFloat());
compareExchange32(mem, oldval, newval, temp);
convertUInt32ToDouble(temp, output.fpu());
break;
default:
MOZ_CRASH("Invalid typed array type");
}
}
template void
MacroAssemblerARMCompat::compareExchangeToTypedIntArray(Scalar::Type arrayType, const Address& mem,
Register oldval, Register newval, Register temp,
AnyRegister output);
template void
MacroAssemblerARMCompat::compareExchangeToTypedIntArray(Scalar::Type arrayType, const BaseIndex& mem,
Register oldval, Register newval, Register temp,
AnyRegister output);
template<typename T>
void
MacroAssemblerARMCompat::atomicExchangeToTypedIntArray(Scalar::Type arrayType, const T& mem,
Register value, Register temp, AnyRegister output)
{
switch (arrayType) {
case Scalar::Int8:
atomicExchange8SignExtend(mem, value, output.gpr());
break;
case Scalar::Uint8:
atomicExchange8ZeroExtend(mem, value, output.gpr());
break;
case Scalar::Uint8Clamped:
atomicExchange8ZeroExtend(mem, value, output.gpr());
break;
case Scalar::Int16:
atomicExchange16SignExtend(mem, value, output.gpr());
break;
case Scalar::Uint16:
atomicExchange16ZeroExtend(mem, value, output.gpr());
break;
case Scalar::Int32:
atomicExchange32(mem, value, output.gpr());
break;
case Scalar::Uint32:
// At the moment, the code in MCallOptimize.cpp requires the output
// type to be double for uint32 arrays. See bug 1077305.
MOZ_ASSERT(output.isFloat());
atomicExchange32(mem, value, temp);
convertUInt32ToDouble(temp, output.fpu());
break;
default:
MOZ_CRASH("Invalid typed array type");
}
}
template void
MacroAssemblerARMCompat::atomicExchangeToTypedIntArray(Scalar::Type arrayType, const Address& mem,
Register value, Register temp, AnyRegister output);
template void
MacroAssemblerARMCompat::atomicExchangeToTypedIntArray(Scalar::Type arrayType, const BaseIndex& mem,
Register value, Register temp, AnyRegister output);
void
MacroAssemblerARMCompat::profilerEnterFrame(Register framePtr, Register scratch)
{

View File

@ -1616,6 +1616,14 @@ class MacroAssemblerARMCompat : public MacroAssemblerARM
atomicEffectOp(4, AtomicFetchXorOp, value, mem, flagTemp);
}
template<typename T>
void compareExchangeToTypedIntArray(Scalar::Type arrayType, const T& mem, Register oldval, Register newval,
Register temp, AnyRegister output);
template<typename T>
void atomicExchangeToTypedIntArray(Scalar::Type arrayType, const T& mem, Register value,
Register temp, AnyRegister output);
void clampIntToUint8(Register reg) {
// Look at (reg >> 8) if it is 0, then reg shouldn't be clamped if it is
// <0, then we want to clamp to 0, otherwise, we wish to clamp to 255

View File

@ -737,3 +737,47 @@ CodeGeneratorARM64::setReturnDoubleRegs(LiveRegisterSet* regs)
regs->add(s1);
regs->add(ReturnDoubleReg);
}
void
CodeGeneratorARM64::visitCompareExchangeTypedArrayElement(LCompareExchangeTypedArrayElement* lir)
{
Register elements = ToRegister(lir->elements());
AnyRegister output = ToAnyRegister(lir->output());
Register temp = lir->temp()->isBogusTemp() ? InvalidReg : ToRegister(lir->temp());
Register oldval = ToRegister(lir->oldval());
Register newval = ToRegister(lir->newval());
Scalar::Type arrayType = lir->mir()->arrayType();
int width = Scalar::byteSize(arrayType);
if (lir->index()->isConstant()) {
Address dest(elements, ToInt32(lir->index()) * width);
masm.compareExchangeToTypedIntArray(arrayType, dest, oldval, newval, temp, output);
} else {
BaseIndex dest(elements, ToRegister(lir->index()), ScaleFromElemWidth(width));
masm.compareExchangeToTypedIntArray(arrayType, dest, oldval, newval, temp, output);
}
}
void
CodeGeneratorARM64::visitAtomicExchangeTypedArrayElement(LAtomicExchangeTypedArrayElement* lir)
{
Register elements = ToRegister(lir->elements());
AnyRegister output = ToAnyRegister(lir->output());
Register temp = lir->temp()->isBogusTemp() ? InvalidReg : ToRegister(lir->temp());
Register value = ToRegister(lir->value());
Scalar::Type arrayType = lir->mir()->arrayType();
int width = Scalar::byteSize(arrayType);
if (lir->index()->isConstant()) {
Address dest(elements, ToInt32(lir->index()) * width);
masm.atomicExchangeToTypedIntArray(arrayType, dest, value, temp, output);
} else {
BaseIndex dest(elements, ToRegister(lir->index()), ScaleFromElemWidth(width));
masm.atomicExchangeToTypedIntArray(arrayType, dest, value, temp, output);
}
}

View File

@ -207,6 +207,8 @@ class CodeGeneratorARM64 : public CodeGeneratorShared
void visitNegF(LNegF* lir);
void visitLoadTypedArrayElementStatic(LLoadTypedArrayElementStatic* ins);
void visitStoreTypedArrayElementStatic(LStoreTypedArrayElementStatic* ins);
void visitCompareExchangeTypedArrayElement(LCompareExchangeTypedArrayElement* lir);
void visitAtomicExchangeTypedArrayElement(LAtomicExchangeTypedArrayElement* lir);
void visitAsmJSCall(LAsmJSCall* ins);
void visitAsmJSLoadHeap(LAsmJSLoadHeap* ins);
void visitAsmJSStoreHeap(LAsmJSStoreHeap* ins);

View File

@ -260,6 +260,95 @@ MacroAssemblerCompat::breakpoint()
Brk((code++) & 0xffff);
}
template<typename T>
void
MacroAssemblerCompat::compareExchangeToTypedIntArray(Scalar::Type arrayType, const T& mem,
Register oldval, Register newval,
Register temp, AnyRegister output)
{
switch (arrayType) {
case Scalar::Int8:
compareExchange8SignExtend(mem, oldval, newval, output.gpr());
break;
case Scalar::Uint8:
compareExchange8ZeroExtend(mem, oldval, newval, output.gpr());
break;
case Scalar::Uint8Clamped:
compareExchange8ZeroExtend(mem, oldval, newval, output.gpr());
break;
case Scalar::Int16:
compareExchange16SignExtend(mem, oldval, newval, output.gpr());
break;
case Scalar::Uint16:
compareExchange16ZeroExtend(mem, oldval, newval, output.gpr());
break;
case Scalar::Int32:
compareExchange32(mem, oldval, newval, output.gpr());
break;
case Scalar::Uint32:
// At the moment, the code in MCallOptimize.cpp requires the output
// type to be double for uint32 arrays. See bug 1077305.
MOZ_ASSERT(output.isFloat());
compareExchange32(mem, oldval, newval, temp);
convertUInt32ToDouble(temp, output.fpu());
break;
default:
MOZ_CRASH("Invalid typed array type");
}
}
template void
MacroAssemblerCompat::compareExchangeToTypedIntArray(Scalar::Type arrayType, const Address& mem,
Register oldval, Register newval, Register temp,
AnyRegister output);
template void
MacroAssemblerCompat::compareExchangeToTypedIntArray(Scalar::Type arrayType, const BaseIndex& mem,
Register oldval, Register newval, Register temp,
AnyRegister output);
template<typename T>
void
MacroAssemblerCompat::atomicExchangeToTypedIntArray(Scalar::Type arrayType, const T& mem,
Register value, Register temp, AnyRegister output)
{
switch (arrayType) {
case Scalar::Int8:
atomicExchange8SignExtend(mem, value, output.gpr());
break;
case Scalar::Uint8:
atomicExchange8ZeroExtend(mem, value, output.gpr());
break;
case Scalar::Uint8Clamped:
atomicExchange8ZeroExtend(mem, value, output.gpr());
break;
case Scalar::Int16:
atomicExchange16SignExtend(mem, value, output.gpr());
break;
case Scalar::Uint16:
atomicExchange16ZeroExtend(mem, value, output.gpr());
break;
case Scalar::Int32:
atomicExchange32(mem, value, output.gpr());
break;
case Scalar::Uint32:
// At the moment, the code in MCallOptimize.cpp requires the output
// type to be double for uint32 arrays. See bug 1077305.
MOZ_ASSERT(output.isFloat());
atomicExchange32(mem, value, temp);
convertUInt32ToDouble(temp, output.fpu());
break;
default:
MOZ_CRASH("Invalid typed array type");
}
}
template void
MacroAssemblerCompat::atomicExchangeToTypedIntArray(Scalar::Type arrayType, const Address& mem,
Register value, Register temp, AnyRegister output);
template void
MacroAssemblerCompat::atomicExchangeToTypedIntArray(Scalar::Type arrayType, const BaseIndex& mem,
Register value, Register temp, AnyRegister output);
//{{{ check_macroassembler_style
// ===============================================================
// Stack manipulation functions.

View File

@ -2863,6 +2863,14 @@ class MacroAssemblerCompat : public vixl::MacroAssembler
atomicEffectOp(4, AtomicFetchXorOp, value, mem);
}
template<typename T>
void compareExchangeToTypedIntArray(Scalar::Type arrayType, const T& mem, Register oldval, Register newval,
Register temp, AnyRegister output);
template<typename T>
void atomicExchangeToTypedIntArray(Scalar::Type arrayType, const T& mem, Register value,
Register temp, AnyRegister output);
// Emit a BLR or NOP instruction. ToggleCall can be used to patch
// this instruction.
CodeOffsetLabel toggledCall(JitCode* target, bool enabled) {

View File

@ -3320,6 +3320,49 @@ CodeGeneratorX86Shared::visitSimdSelect(LSimdSelect* ins)
masm.bitwiseOrX4(Operand(temp), output);
}
void
CodeGeneratorX86Shared::visitCompareExchangeTypedArrayElement(LCompareExchangeTypedArrayElement* lir)
{
Register elements = ToRegister(lir->elements());
AnyRegister output = ToAnyRegister(lir->output());
Register temp = lir->temp()->isBogusTemp() ? InvalidReg : ToRegister(lir->temp());
Register oldval = ToRegister(lir->oldval());
Register newval = ToRegister(lir->newval());
Scalar::Type arrayType = lir->mir()->arrayType();
int width = Scalar::byteSize(arrayType);
if (lir->index()->isConstant()) {
Address dest(elements, ToInt32(lir->index()) * width);
masm.compareExchangeToTypedIntArray(arrayType, dest, oldval, newval, temp, output);
} else {
BaseIndex dest(elements, ToRegister(lir->index()), ScaleFromElemWidth(width));
masm.compareExchangeToTypedIntArray(arrayType, dest, oldval, newval, temp, output);
}
}
void
CodeGeneratorX86Shared::visitAtomicExchangeTypedArrayElement(LAtomicExchangeTypedArrayElement* lir)
{
Register elements = ToRegister(lir->elements());
AnyRegister output = ToAnyRegister(lir->output());
Register temp = lir->temp()->isBogusTemp() ? InvalidReg : ToRegister(lir->temp());
Register value = ToRegister(lir->value());
Scalar::Type arrayType = lir->mir()->arrayType();
int width = Scalar::byteSize(arrayType);
if (lir->index()->isConstant()) {
Address dest(elements, ToInt32(lir->index()) * width);
masm.atomicExchangeToTypedIntArray(arrayType, dest, value, temp, output);
} else {
BaseIndex dest(elements, ToRegister(lir->index()), ScaleFromElemWidth(width));
masm.atomicExchangeToTypedIntArray(arrayType, dest, value, temp, output);
}
}
template<typename S, typename T>
void
CodeGeneratorX86Shared::atomicBinopToTypedIntArray(AtomicOp op, Scalar::Type arrayType, const S& value,

View File

@ -243,6 +243,8 @@ class CodeGeneratorX86Shared : public CodeGeneratorShared
virtual void visitMemoryBarrier(LMemoryBarrier* ins);
virtual void visitAtomicTypedArrayElementBinop(LAtomicTypedArrayElementBinop* lir);
virtual void visitAtomicTypedArrayElementBinopForEffect(LAtomicTypedArrayElementBinopForEffect* lir);
virtual void visitCompareExchangeTypedArrayElement(LCompareExchangeTypedArrayElement* lir);
virtual void visitAtomicExchangeTypedArrayElement(LAtomicExchangeTypedArrayElement* lir);
void visitOutOfLineLoadTypedArrayOutOfBounds(OutOfLineLoadTypedArrayOutOfBounds* ool);
void visitOffsetBoundsCheck(OffsetBoundsCheck* oolCheck);

View File

@ -143,6 +143,96 @@ MacroAssemblerX86Shared::asMasm() const
return *static_cast<const MacroAssembler*>(this);
}
template<typename T>
void
MacroAssemblerX86Shared::compareExchangeToTypedIntArray(Scalar::Type arrayType, const T& mem,
Register oldval, Register newval,
Register temp, AnyRegister output)
{
switch (arrayType) {
case Scalar::Int8:
compareExchange8SignExtend(mem, oldval, newval, output.gpr());
break;
case Scalar::Uint8:
compareExchange8ZeroExtend(mem, oldval, newval, output.gpr());
break;
case Scalar::Uint8Clamped:
compareExchange8ZeroExtend(mem, oldval, newval, output.gpr());
break;
case Scalar::Int16:
compareExchange16SignExtend(mem, oldval, newval, output.gpr());
break;
case Scalar::Uint16:
compareExchange16ZeroExtend(mem, oldval, newval, output.gpr());
break;
case Scalar::Int32:
compareExchange32(mem, oldval, newval, output.gpr());
break;
case Scalar::Uint32:
// At the moment, the code in MCallOptimize.cpp requires the output
// type to be double for uint32 arrays. See bug 1077305.
MOZ_ASSERT(output.isFloat());
compareExchange32(mem, oldval, newval, temp);
asMasm().convertUInt32ToDouble(temp, output.fpu());
break;
default:
MOZ_CRASH("Invalid typed array type");
}
}
template void
MacroAssemblerX86Shared::compareExchangeToTypedIntArray(Scalar::Type arrayType, const Address& mem,
Register oldval, Register newval, Register temp,
AnyRegister output);
template void
MacroAssemblerX86Shared::compareExchangeToTypedIntArray(Scalar::Type arrayType, const BaseIndex& mem,
Register oldval, Register newval, Register temp,
AnyRegister output);
template<typename T>
void
MacroAssemblerX86Shared::atomicExchangeToTypedIntArray(Scalar::Type arrayType, const T& mem,
Register value, Register temp, AnyRegister output)
{
switch (arrayType) {
case Scalar::Int8:
atomicExchange8SignExtend(mem, value, output.gpr());
break;
case Scalar::Uint8:
atomicExchange8ZeroExtend(mem, value, output.gpr());
break;
case Scalar::Uint8Clamped:
atomicExchange8ZeroExtend(mem, value, output.gpr());
break;
case Scalar::Int16:
atomicExchange16SignExtend(mem, value, output.gpr());
break;
case Scalar::Uint16:
atomicExchange16ZeroExtend(mem, value, output.gpr());
break;
case Scalar::Int32:
atomicExchange32(mem, value, output.gpr());
break;
case Scalar::Uint32:
// At the moment, the code in MCallOptimize.cpp requires the output
// type to be double for uint32 arrays. See bug 1077305.
MOZ_ASSERT(output.isFloat());
atomicExchange32(mem, value, temp);
asMasm().convertUInt32ToDouble(temp, output.fpu());
break;
default:
MOZ_CRASH("Invalid typed array type");
}
}
template void
MacroAssemblerX86Shared::atomicExchangeToTypedIntArray(Scalar::Type arrayType, const Address& mem,
Register value, Register temp, AnyRegister output);
template void
MacroAssemblerX86Shared::atomicExchangeToTypedIntArray(Scalar::Type arrayType, const BaseIndex& mem,
Register value, Register temp, AnyRegister output);
//{{{ check_macroassembler_style
// ===============================================================
// Stack manipulation functions.

View File

@ -1455,6 +1455,14 @@ class MacroAssemblerX86Shared : public Assembler
ret();
}
template<typename T>
void compareExchangeToTypedIntArray(Scalar::Type arrayType, const T& mem, Register oldval, Register newval,
Register temp, AnyRegister output);
template<typename T>
void atomicExchangeToTypedIntArray(Scalar::Type arrayType, const T& mem, Register value,
Register temp, AnyRegister output);
protected:
bool buildOOLFakeExitFrame(void* fakeReturnAddr);
};

View File

@ -181,6 +181,7 @@ EnumerateNativeProperties(JSContext* cx, HandleNativeObject pobj, unsigned flags
enumerateSymbols = true;
} else {
/* Collect any dense elements from this object. */
size_t firstElemIndex = props->length();
size_t initlen = pobj->getDenseInitializedLength();
const Value* vp = pobj->getDenseElements();
bool hasHoles = false;
@ -206,7 +207,10 @@ EnumerateNativeProperties(JSContext* cx, HandleNativeObject pobj, unsigned flags
// Collect any sparse elements from this object.
bool isIndexed = pobj->isIndexed();
if (isIndexed) {
size_t numElements = props->length();
// If the dense elements didn't have holes, we don't need to include
// them in the sort.
if (!hasHoles)
firstElemIndex = props->length();
for (Shape::Range<NoGC> r(pobj->lastProperty()); !r.empty(); r.popFront()) {
Shape& shape = r.front();
@ -218,12 +222,10 @@ EnumerateNativeProperties(JSContext* cx, HandleNativeObject pobj, unsigned flags
}
}
// If the dense elements didn't have holes, we don't need to include
// them in the sort.
size_t startIndex = hasHoles ? 0 : numElements;
MOZ_ASSERT(firstElemIndex <= props->length());
jsid* ids = props->begin() + startIndex;
size_t n = props->length() - startIndex;
jsid* ids = props->begin() + firstElemIndex;
size_t n = props->length() - firstElemIndex;
AutoIdVector tmp(cx);
if (!tmp.resize(n))

Some files were not shown because too many files have changed in this diff Show More