aboutsummaryrefslogtreecommitdiffstats
path: root/www
diff options
context:
space:
mode:
authorjbeich <jbeich@FreeBSD.org>2018-05-24 08:53:46 +0800
committerjbeich <jbeich@FreeBSD.org>2018-05-24 08:53:46 +0800
commit3e8cf7dc65f07ad09139c5bd2828a6ef85b13e98 (patch)
tree6cf8666c88555a8160ca80a017a10fdc18399161 /www
parent35c2152e178d190af273bdc1e4ad4af74f7d7b4f (diff)
downloadfreebsd-ports-gnome-3e8cf7dc65f07ad09139c5bd2828a6ef85b13e98.tar.gz
freebsd-ports-gnome-3e8cf7dc65f07ad09139c5bd2828a6ef85b13e98.tar.zst
freebsd-ports-gnome-3e8cf7dc65f07ad09139c5bd2828a6ef85b13e98.zip
www/waterfox: apply some FF61 fixes
Diffstat (limited to 'www')
-rw-r--r--www/waterfox/Makefile2
-rw-r--r--www/waterfox/files/patch-bug1412882192
-rw-r--r--www/waterfox/files/patch-bug1454285713
-rw-r--r--www/waterfox/files/patch-bug1456189218
-rw-r--r--www/waterfox/files/patch-bug1456512144
-rw-r--r--www/waterfox/files/patch-bug146291257
6 files changed, 1325 insertions, 1 deletions
diff --git a/www/waterfox/Makefile b/www/waterfox/Makefile
index b1ff6ecbad9d..d0ebaeca4e13 100644
--- a/www/waterfox/Makefile
+++ b/www/waterfox/Makefile
@@ -3,7 +3,7 @@
PORTNAME= waterfox
DISTVERSION= 56.2.0-13
DISTVERSIONSUFFIX= -gd2cdd42f4115b
-PORTREVISION= 3
+PORTREVISION= 4
CATEGORIES= www ipv6
MAINTAINER= jbeich@FreeBSD.org
diff --git a/www/waterfox/files/patch-bug1412882 b/www/waterfox/files/patch-bug1412882
new file mode 100644
index 000000000000..327b6da45b9b
--- /dev/null
+++ b/www/waterfox/files/patch-bug1412882
@@ -0,0 +1,192 @@
+commit 7513891383a1
+Author: Jonathan Kew <jkew@mozilla.com>
+Date: Sat May 19 08:32:22 2018 +0100
+
+ Bug 1412882 - Rework gfxFontUtils::MapCharToGlyphFormat4 to be more robust. r=lsalzman, a=RyanVM
+
+ --HG--
+ extra : source : e96eaa6603005c3e2361d9d32ef59adb718d4203
+---
+ gfx/thebes/gfxFontUtils.cpp | 89 ++++++++++++++++++++++------------------
+ gfx/thebes/gfxFontUtils.h | 2 +-
+ gfx/thebes/gfxHarfBuzzShaper.cpp | 8 +++-
+ 3 files changed, 57 insertions(+), 42 deletions(-)
+
+diff --git gfx/thebes/gfxFontUtils.cpp gfx/thebes/gfxFontUtils.cpp
+index b3c1cae1bbb67..1590fb52ab6b7 100644
+--- gfx/thebes/gfxFontUtils.cpp
++++ gfx/thebes/gfxFontUtils.cpp
+@@ -569,55 +569,64 @@ typedef struct {
+ #pragma pack()
+
+ uint32_t
+-gfxFontUtils::MapCharToGlyphFormat4(const uint8_t *aBuf, char16_t aCh)
++gfxFontUtils::MapCharToGlyphFormat4(const uint8_t* aBuf, uint32_t aLength,
++ char16_t aCh)
+ {
+ const Format4Cmap *cmap4 = reinterpret_cast<const Format4Cmap*>(aBuf);
+- uint16_t segCount;
+- const AutoSwap_PRUint16 *endCodes;
+- const AutoSwap_PRUint16 *startCodes;
+- const AutoSwap_PRUint16 *idDelta;
+- const AutoSwap_PRUint16 *idRangeOffset;
+- uint16_t probe;
+- uint16_t rangeShiftOver2;
+- uint16_t index;
+-
+- segCount = (uint16_t)(cmap4->segCountX2) / 2;
+-
+- endCodes = &cmap4->arrays[0];
+- startCodes = &cmap4->arrays[segCount + 1]; // +1 for reserved word between arrays
+- idDelta = &startCodes[segCount];
+- idRangeOffset = &idDelta[segCount];
+-
+- probe = 1 << (uint16_t)(cmap4->entrySelector);
+- rangeShiftOver2 = (uint16_t)(cmap4->rangeShift) / 2;
+-
+- if ((uint16_t)(startCodes[rangeShiftOver2]) <= aCh) {
+- index = rangeShiftOver2;
+- } else {
+- index = 0;
+- }
+-
+- while (probe > 1) {
+- probe >>= 1;
+- if ((uint16_t)(startCodes[index + probe]) <= aCh) {
+- index += probe;
++
++ uint16_t segCount = (uint16_t)(cmap4->segCountX2) / 2;
++
++ const AutoSwap_PRUint16* endCodes = &cmap4->arrays[0];
++ const AutoSwap_PRUint16* startCodes = &cmap4->arrays[segCount + 1];
++ const AutoSwap_PRUint16* idDelta = &startCodes[segCount];
++ const AutoSwap_PRUint16* idRangeOffset = &idDelta[segCount];
++
++ // Sanity-check that the fixed-size arrays don't exceed the buffer.
++ const uint8_t* const limit = aBuf + aLength;
++ if ((const uint8_t*)(&idRangeOffset[segCount]) > limit) {
++ return 0; // broken font, just bail out safely
++ }
++
++ // For most efficient binary search, we want to work on a range of segment
++ // indexes that is a power of 2 so that we can always halve it by shifting.
++ // So we find the largest power of 2 that is <= segCount.
++ // We will offset this range by segOffset so as to reach the end
++ // of the table, provided that doesn't put us beyond the target
++ // value from the outset.
++ uint32_t powerOf2 = mozilla::FindHighestBit(segCount);
++ uint32_t segOffset = segCount - powerOf2;
++ uint32_t idx = 0;
++
++ if (uint16_t(startCodes[segOffset]) <= aCh) {
++ idx = segOffset;
++ }
++
++ // Repeatedly halve the size of the range until we find the target group
++ while (powerOf2 > 1) {
++ powerOf2 >>= 1;
++ if (uint16_t(startCodes[idx + powerOf2]) <= aCh) {
++ idx += powerOf2;
+ }
+ }
+
+- if (aCh >= (uint16_t)(startCodes[index]) && aCh <= (uint16_t)(endCodes[index])) {
++ if (aCh >= uint16_t(startCodes[idx]) && aCh <= uint16_t(endCodes[idx])) {
+ uint16_t result;
+- if ((uint16_t)(idRangeOffset[index]) == 0) {
++ if (uint16_t(idRangeOffset[idx]) == 0) {
+ result = aCh;
+ } else {
+- uint16_t offset = aCh - (uint16_t)(startCodes[index]);
+- const AutoSwap_PRUint16 *glyphIndexTable =
+- (const AutoSwap_PRUint16*)((const char*)&idRangeOffset[index] +
+- (uint16_t)(idRangeOffset[index]));
++ uint16_t offset = aCh - uint16_t(startCodes[idx]);
++ const AutoSwap_PRUint16* glyphIndexTable =
++ (const AutoSwap_PRUint16*)((const char*)&idRangeOffset[idx] +
++ uint16_t(idRangeOffset[idx]));
++ if ((const uint8_t*)(glyphIndexTable + offset + 1) > limit) {
++ return 0; // broken font, just bail out safely
++ }
+ result = glyphIndexTable[offset];
+ }
+
+- // note that this is unsigned 16-bit arithmetic, and may wrap around
+- result += (uint16_t)(idDelta[index]);
++ // Note that this is unsigned 16-bit arithmetic, and may wrap around
++ // (which is required behavior per spec)
++ result += uint16_t(idDelta[idx]);
+ return result;
+ }
+
+@@ -761,7 +770,8 @@ gfxFontUtils::MapCharToGlyph(const uint8_t *aCmapBuf, uint32_t aBufLength,
+ switch (format) {
+ case 4:
+ gid = aUnicode < UNICODE_BMP_LIMIT ?
+- MapCharToGlyphFormat4(aCmapBuf + offset, char16_t(aUnicode)) : 0;
++ MapCharToGlyphFormat4(aCmapBuf + offset, aBufLength - offset,
++ char16_t(aUnicode)) : 0;
+ break;
+ case 10:
+ gid = MapCharToGlyphFormat10(aCmapBuf + offset, aUnicode);
+@@ -786,6 +796,7 @@ gfxFontUtils::MapCharToGlyph(const uint8_t *aCmapBuf, uint32_t aBufLength,
+ case 4:
+ if (aUnicode < UNICODE_BMP_LIMIT) {
+ varGID = MapCharToGlyphFormat4(aCmapBuf + offset,
++ aBufLength - offset,
+ char16_t(aUnicode));
+ }
+ break;
+diff --git gfx/thebes/gfxFontUtils.h gfx/thebes/gfxFontUtils.h
+index 250df442c3a2e..be2f54a9a7026 100644
+--- gfx/thebes/gfxFontUtils.h
++++ gfx/thebes/gfxFontUtils.h
+@@ -804,7 +804,7 @@ public:
+ uint32_t& aUVSOffset);
+
+ static uint32_t
+- MapCharToGlyphFormat4(const uint8_t *aBuf, char16_t aCh);
++ MapCharToGlyphFormat4(const uint8_t *aBuf, uint32_t aLength, char16_t aCh);
+
+ static uint32_t
+ MapCharToGlyphFormat10(const uint8_t *aBuf, uint32_t aCh);
+diff --git gfx/thebes/gfxHarfBuzzShaper.cpp gfx/thebes/gfxHarfBuzzShaper.cpp
+index c57504a4d9db4..ff638dcef73ad 100644
+--- gfx/thebes/gfxHarfBuzzShaper.cpp
++++ gfx/thebes/gfxHarfBuzzShaper.cpp
+@@ -116,13 +116,15 @@ gfxHarfBuzzShaper::GetNominalGlyph(hb_codepoint_t unicode) const
+ NS_ASSERTION(mCmapTable && (mCmapFormat > 0) && (mSubtableOffset > 0),
+ "cmap data not correctly set up, expect disaster");
+
++ uint32_t length;
+ const uint8_t* data =
+- (const uint8_t*)hb_blob_get_data(mCmapTable, nullptr);
++ (const uint8_t*)hb_blob_get_data(mCmapTable, &length);
+
+ switch (mCmapFormat) {
+ case 4:
+ gid = unicode < UNICODE_BMP_LIMIT ?
+ gfxFontUtils::MapCharToGlyphFormat4(data + mSubtableOffset,
++ length - mSubtableOffset,
+ unicode) : 0;
+ break;
+ case 10:
+@@ -164,8 +166,9 @@ gfxHarfBuzzShaper::GetVariationGlyph(hb_codepoint_t unicode,
+ NS_ASSERTION(mCmapTable && (mCmapFormat > 0) && (mSubtableOffset > 0),
+ "cmap data not correctly set up, expect disaster");
+
++ uint32_t length;
+ const uint8_t* data =
+- (const uint8_t*)hb_blob_get_data(mCmapTable, nullptr);
++ (const uint8_t*)hb_blob_get_data(mCmapTable, &length);
+
+ if (mUVSTableOffset) {
+ hb_codepoint_t gid =
+@@ -183,6 +186,7 @@ gfxHarfBuzzShaper::GetVariationGlyph(hb_codepoint_t unicode,
+ case 4:
+ if (compat < UNICODE_BMP_LIMIT) {
+ return gfxFontUtils::MapCharToGlyphFormat4(data + mSubtableOffset,
++ length - mSubtableOffset,
+ compat);
+ }
+ break;
diff --git a/www/waterfox/files/patch-bug1454285 b/www/waterfox/files/patch-bug1454285
new file mode 100644
index 000000000000..f5f38eca6411
--- /dev/null
+++ b/www/waterfox/files/patch-bug1454285
@@ -0,0 +1,713 @@
+commit 58db23895d95
+Author: Tooru Fujisawa <arai_a@mac.com>
+Date: Tue May 22 18:10:28 2018 +0900
+
+ Bug 1454285 - Part 1: Specify the current scope when emitting await and .generator. r=jwalden, a=RyanVM
+
+ --HG--
+ extra : source : 6ca6ced5189a5760c96afa31a6575cd3d3f56639
+---
+ js/src/frontend/BytecodeEmitter.cpp | 104 +++++++++++++++++++++---------------
+ js/src/frontend/BytecodeEmitter.h | 25 ++++++---
+ 2 files changed, 81 insertions(+), 48 deletions(-)
+
+diff --git js/src/frontend/BytecodeEmitter.cpp js/src/frontend/BytecodeEmitter.cpp
+index df999dfb2b0dc..e8edc66658804 100644
+--- js/src/frontend/BytecodeEmitter.cpp
++++ js/src/frontend/BytecodeEmitter.cpp
+@@ -2004,6 +2004,8 @@ class MOZ_STACK_CLASS IfThenElseEmitter
+
+ class ForOfLoopControl : public LoopControl
+ {
++ using EmitterScope = BytecodeEmitter::EmitterScope;
++
+ // The stack depth of the iterator.
+ int32_t iterDepth_;
+
+@@ -2096,8 +2098,8 @@ class ForOfLoopControl : public LoopControl
+ MOZ_ASSERT(slotFromTop == unsigned(bce->stackDepth - iterDepth_));
+ if (!bce->emitDupAt(slotFromTop)) // ITER ... EXCEPTION ITER
+ return false;
+- if (!emitIteratorClose(bce, CompletionKind::Throw)) // ITER ... EXCEPTION
+- return false;
++ if (!emitIteratorCloseInInnermostScope(bce, CompletionKind::Throw))
++ return false; // ITER ... EXCEPTION
+
+ if (!ifIteratorIsNotClosed.emitEnd()) // ITER ... EXCEPTION
+ return false;
+@@ -2120,8 +2122,8 @@ class ForOfLoopControl : public LoopControl
+ return false;
+ if (!bce->emitDupAt(slotFromTop + 1)) // ITER ... FTYPE FVALUE ITER
+ return false;
+- if (!emitIteratorClose(bce, CompletionKind::Normal)) // ITER ... FTYPE FVALUE
+- return false;
++ if (!emitIteratorCloseInInnermostScope(bce, CompletionKind::Normal))
++ return false; // ITER ... FTYPE FVALUE
+ if (!ifGeneratorClosing.emitEnd()) // ITER ... FTYPE FVALUE
+ return false;
+ }
+@@ -2135,16 +2137,27 @@ class ForOfLoopControl : public LoopControl
+ return true;
+ }
+
+- bool emitIteratorClose(BytecodeEmitter* bce,
+- CompletionKind completionKind = CompletionKind::Normal) {
++ bool emitIteratorCloseInInnermostScope(BytecodeEmitter* bce,
++ CompletionKind completionKind = CompletionKind::Normal) {
++ return emitIteratorCloseInScope(bce, *bce->innermostEmitterScope, completionKind);
++ }
++
++ bool emitIteratorCloseInScope(BytecodeEmitter* bce,
++ EmitterScope& currentScope,
++ CompletionKind completionKind = CompletionKind::Normal) {
+ ptrdiff_t start = bce->offset();
+- if (!bce->emitIteratorClose(iterKind_, completionKind, allowSelfHosted_))
++ if (!bce->emitIteratorCloseInScope(currentScope, iterKind_, completionKind,
++ allowSelfHosted_))
++ {
+ return false;
++ }
+ ptrdiff_t end = bce->offset();
+ return bce->tryNoteList.append(JSTRY_FOR_OF_ITERCLOSE, 0, start, end);
+ }
+
+- bool emitPrepareForNonLocalJump(BytecodeEmitter* bce, bool isTarget) {
++ bool emitPrepareForNonLocalJumpFromScope(BytecodeEmitter* bce,
++ EmitterScope& currentScope,
++ bool isTarget) {
+ // Pop unnecessary value from the stack. Effectively this means
+ // leaving try-catch block. However, the performing IteratorClose can
+ // reach the depth for try-catch, and effectively re-enter the
+@@ -2159,7 +2172,7 @@ class ForOfLoopControl : public LoopControl
+ if (!bce->emit1(JSOP_SWAP)) // UNDEF ITER
+ return false;
+
+- if (!emitIteratorClose(bce)) // UNDEF
++ if (!emitIteratorCloseInScope(bce, currentScope, CompletionKind::Normal)) // UNDEF
+ return false;
+
+ if (isTarget) {
+@@ -2843,8 +2856,11 @@ NonLocalExitControl::prepareForNonLocalJump(BytecodeEmitter::NestableControl* ta
+ return false;
+
+ ForOfLoopControl& loopinfo = control->as<ForOfLoopControl>();
+- if (!loopinfo.emitPrepareForNonLocalJump(bce_, /* isTarget = */ false)) // ...
++ if (!loopinfo.emitPrepareForNonLocalJumpFromScope(bce_, *es,
++ /* isTarget = */ false))
++ { // ...
+ return false;
++ }
+ } else {
+ npops += 2;
+ }
+@@ -2871,8 +2887,9 @@ NonLocalExitControl::prepareForNonLocalJump(BytecodeEmitter::NestableControl* ta
+
+ if (target && emitIteratorCloseAtTarget && target->is<ForOfLoopControl>()) {
+ ForOfLoopControl& loopinfo = target->as<ForOfLoopControl>();
+- if (!loopinfo.emitPrepareForNonLocalJump(bce_, /* isTarget = */ true)) // ... UNDEF UNDEF
++ if (!loopinfo.emitPrepareForNonLocalJumpFromScope(bce_, *es, /* isTarget = */ true)) { // ... UNDEF UNDEF
+ return false;
++ }
+ }
+
+ EmitterScope* targetEmitterScope = target ? target->emitterScope() : bce_->varEmitterScope;
+@@ -5325,7 +5342,7 @@ BytecodeEmitter::emitIteratorNext(ParseNode* pn, IteratorKind iterKind /* = Iter
+ return false;
+
+ if (iterKind == IteratorKind::Async) {
+- if (!emitAwait()) // ... RESULT
++ if (!emitAwaitInInnermostScope()) // ... RESULT
+ return false;
+ }
+
+@@ -5336,9 +5353,10 @@ BytecodeEmitter::emitIteratorNext(ParseNode* pn, IteratorKind iterKind /* = Iter
+ }
+
+ bool
+-BytecodeEmitter::emitIteratorClose(IteratorKind iterKind /* = IteratorKind::Sync */,
+- CompletionKind completionKind /* = CompletionKind::Normal */,
+- bool allowSelfHosted /* = false */)
++BytecodeEmitter::emitIteratorCloseInScope(EmitterScope& currentScope,
++ IteratorKind iterKind /* = IteratorKind::Sync */,
++ CompletionKind completionKind /* = CompletionKind::Normal */,
++ bool allowSelfHosted /* = false */)
+ {
+ MOZ_ASSERT(allowSelfHosted || emitterMode != BytecodeEmitter::SelfHosting,
+ ".close() on iterators is prohibited in self-hosted code because it "
+@@ -5430,7 +5448,7 @@ BytecodeEmitter::emitIteratorClose(IteratorKind iterKind /* = IteratorKind::Sync
+ if (!emit1(JSOP_SWAP)) // ... ... RVAL RESULT
+ return false;
+ }
+- if (!emitAwait()) // ... ... RVAL? RESULT
++ if (!emitAwaitInScope(currentScope)) // ... ... RVAL? RESULT
+ return false;
+ }
+
+@@ -5690,7 +5708,7 @@ BytecodeEmitter::emitDestructuringOpsArray(ParseNode* pattern, DestructuringFlav
+ // For an empty pattern [], call IteratorClose unconditionally. Nothing
+ // else needs to be done.
+ if (!pattern->pn_head)
+- return emitIteratorClose(); // ... OBJ
++ return emitIteratorCloseInInnermostScope(); // ... OBJ
+
+ // Push an initial FALSE value for DONE.
+ if (!emit1(JSOP_FALSE)) // ... OBJ ITER FALSE
+@@ -5886,7 +5904,7 @@ BytecodeEmitter::emitDestructuringOpsArray(ParseNode* pattern, DestructuringFlav
+ return false;
+ if (!ifDone.emitElse()) // ... OBJ ITER
+ return false;
+- if (!emitIteratorClose()) // ... OBJ
++ if (!emitIteratorCloseInInnermostScope()) // ... OBJ
+ return false;
+ if (!ifDone.emitEnd())
+ return false;
+@@ -8682,9 +8700,9 @@ BytecodeEmitter::emitReturn(ParseNode* pn)
+ }
+
+ bool
+-BytecodeEmitter::emitGetDotGenerator()
++BytecodeEmitter::emitGetDotGeneratorInScope(EmitterScope& currentScope)
+ {
+- NameLocation loc = *locationOfNameBoundInFunctionScope(cx->names().dotGenerator);
++ NameLocation loc = *locationOfNameBoundInFunctionScope(cx->names().dotGenerator, &currentScope);
+ return emitGetNameAtLocation(cx->names().dotGenerator, loc);
+ }
+
+@@ -8726,7 +8744,7 @@ BytecodeEmitter::emitYield(ParseNode* pn)
+ return false;
+ }
+
+- if (!emitGetDotGenerator())
++ if (!emitGetDotGeneratorInInnermostScope())
+ return false;
+
+ if (!emitYieldOp(JSOP_YIELD))
+@@ -8736,24 +8754,24 @@ BytecodeEmitter::emitYield(ParseNode* pn)
+ }
+
+ bool
+-BytecodeEmitter::emitAwait()
++BytecodeEmitter::emitAwaitInInnermostScope(ParseNode* pn)
+ {
+- if (!emitGetDotGenerator())
+- return false;
+- if (!emitYieldOp(JSOP_AWAIT))
++ MOZ_ASSERT(sc->isFunctionBox());
++ MOZ_ASSERT(pn->getOp() == JSOP_AWAIT);
++
++ if (!emitTree(pn->pn_kid))
+ return false;
+- return true;
++ return emitAwaitInInnermostScope();
+ }
+
+ bool
+-BytecodeEmitter::emitAwait(ParseNode* pn)
++BytecodeEmitter::emitAwaitInScope(EmitterScope& currentScope)
+ {
+- MOZ_ASSERT(sc->isFunctionBox());
+- MOZ_ASSERT(pn->getOp() == JSOP_AWAIT);
+-
+- if (!emitTree(pn->pn_kid))
++ if (!emitGetDotGeneratorInScope(currentScope))
+ return false;
+- return emitAwait();
++ if (!emitYieldOp(JSOP_AWAIT))
++ return false;
++ return true;
+ }
+
+ bool
+@@ -8794,7 +8812,7 @@ BytecodeEmitter::emitYieldStar(ParseNode* iter)
+ MOZ_ASSERT(this->stackDepth == startDepth);
+
+ // Load the generator object.
+- if (!emitGetDotGenerator()) // ITER RESULT GENOBJ
++ if (!emitGetDotGeneratorInInnermostScope()) // ITER RESULT GENOBJ
+ return false;
+
+ // Yield RESULT as-is, without re-boxing.
+@@ -8831,7 +8849,7 @@ BytecodeEmitter::emitYieldStar(ParseNode* iter)
+ // If the iterator does not have a "throw" method, it calls IteratorClose
+ // and then throws a TypeError.
+ IteratorKind iterKind = isAsyncGenerator ? IteratorKind::Async : IteratorKind::Sync;
+- if (!emitIteratorClose(iterKind)) // ITER RESULT EXCEPTION
++ if (!emitIteratorCloseInInnermostScope(iterKind)) // ITER RESULT EXCEPTION
+ return false;
+ if (!emitUint16Operand(JSOP_THROWMSG, JSMSG_ITERATOR_NO_THROW)) // throw
+ return false;
+@@ -8849,7 +8867,7 @@ BytecodeEmitter::emitYieldStar(ParseNode* iter)
+ checkTypeSet(JSOP_CALL);
+
+ if (isAsyncGenerator) {
+- if (!emitAwait()) // ITER OLDRESULT RESULT
++ if (!emitAwaitInInnermostScope()) // ITER OLDRESULT RESULT
+ return false;
+ }
+
+@@ -8920,7 +8938,7 @@ BytecodeEmitter::emitYieldStar(ParseNode* iter)
+ checkTypeSet(JSOP_CALL);
+
+ if (iterKind == IteratorKind::Async) {
+- if (!emitAwait()) // ... FTYPE FVALUE RESULT
++ if (!emitAwaitInInnermostScope()) // ... FTYPE FVALUE RESULT
+ return false;
+ }
+
+@@ -8943,7 +8961,7 @@ BytecodeEmitter::emitYieldStar(ParseNode* iter)
+ return false;
+
+ if (isAsyncGenerator) {
+- if (!emitAwait()) // ITER OLDRESULT FTYPE FVALUE VALUE
++ if (!emitAwaitInInnermostScope()) // ITER OLDRESULT FTYPE FVALUE VALUE
+ return false;
+ }
+
+@@ -9005,7 +9023,7 @@ BytecodeEmitter::emitYieldStar(ParseNode* iter)
+ checkTypeSet(JSOP_CALL);
+
+ if (isAsyncGenerator) {
+- if (!emitAwait()) // ITER RESULT RESULT
++ if (!emitAwaitInInnermostScope()) // ITER RESULT RESULT
+ return false;
+ }
+
+@@ -9038,7 +9056,7 @@ BytecodeEmitter::emitYieldStar(ParseNode* iter)
+ return false;
+
+ if (isAsyncGenerator) {
+- if (!emitAwait()) // VALUE
++ if (!emitAwaitInInnermostScope()) // VALUE
+ return false;
+ }
+
+@@ -10592,7 +10610,7 @@ BytecodeEmitter::emitFunctionBody(ParseNode* funBody)
+ if (!emit1(JSOP_SETRVAL))
+ return false;
+
+- if (!emitGetDotGenerator())
++ if (!emitGetDotGeneratorInInnermostScope())
+ return false;
+
+ // No need to check for finally blocks, etc as in EmitReturn.
+@@ -10954,7 +10972,7 @@ BytecodeEmitter::emitTree(ParseNode* pn, ValueUsage valueUsage /* = ValueUsage::
+ break;
+
+ case PNK_AWAIT:
+- if (!emitAwait(pn))
++ if (!emitAwaitInInnermostScope(pn))
+ return false;
+ break;
+
+diff --git js/src/frontend/BytecodeEmitter.h js/src/frontend/BytecodeEmitter.h
+index f238cc12c0247..039d271e4d965 100644
+--- js/src/frontend/BytecodeEmitter.h
++++ js/src/frontend/BytecodeEmitter.h
+@@ -634,14 +634,20 @@ struct MOZ_STACK_CLASS BytecodeEmitter
+ MOZ_MUST_USE bool iteratorResultShape(unsigned* shape);
+ MOZ_MUST_USE bool emitToIteratorResult(bool done);
+
+- MOZ_MUST_USE bool emitGetDotGenerator();
++ MOZ_MUST_USE bool emitGetDotGeneratorInInnermostScope() {
++ return emitGetDotGeneratorInScope(*innermostEmitterScope);
++ }
++ MOZ_MUST_USE bool emitGetDotGeneratorInScope(EmitterScope& currentScope);
+
+ MOZ_MUST_USE bool emitInitialYield(ParseNode* pn);
+ MOZ_MUST_USE bool emitYield(ParseNode* pn);
+ MOZ_MUST_USE bool emitYieldOp(JSOp op);
+ MOZ_MUST_USE bool emitYieldStar(ParseNode* iter);
+- MOZ_MUST_USE bool emitAwait();
+- MOZ_MUST_USE bool emitAwait(ParseNode* pn);
++ MOZ_MUST_USE bool emitAwaitInInnermostScope() {
++ return emitAwaitInScope(*innermostEmitterScope);
++ }
++ MOZ_MUST_USE bool emitAwaitInInnermostScope(ParseNode* pn);
++ MOZ_MUST_USE bool emitAwaitInScope(EmitterScope& currentScope);
+
+ MOZ_MUST_USE bool emitPropLHS(ParseNode* pn);
+ MOZ_MUST_USE bool emitPropOp(ParseNode* pn, JSOp op);
+@@ -738,9 +744,16 @@ struct MOZ_STACK_CLASS BytecodeEmitter
+ // onto the stack.
+ MOZ_MUST_USE bool emitIteratorNext(ParseNode* pn, IteratorKind kind = IteratorKind::Sync,
+ bool allowSelfHosted = false);
+- MOZ_MUST_USE bool emitIteratorClose(IteratorKind iterKind = IteratorKind::Sync,
+- CompletionKind completionKind = CompletionKind::Normal,
+- bool allowSelfHosted = false);
++ MOZ_MUST_USE bool emitIteratorCloseInScope(EmitterScope& currentScope,
++ IteratorKind iterKind = IteratorKind::Sync,
++ CompletionKind completionKind = CompletionKind::Normal,
++ bool allowSelfHosted = false);
++ MOZ_MUST_USE bool emitIteratorCloseInInnermostScope(IteratorKind iterKind = IteratorKind::Sync,
++ CompletionKind completionKind = CompletionKind::Normal,
++ bool allowSelfHosted = false) {
++ return emitIteratorCloseInScope(*innermostEmitterScope, iterKind, completionKind,
++ allowSelfHosted);
++ }
+
+ template <typename InnerEmitter>
+ MOZ_MUST_USE bool wrapWithDestructuringIteratorCloseTryNote(int32_t iterDepth,
+
+commit 0cd861187fc0
+Author: Tooru Fujisawa <arai_a@mac.com>
+Date: Tue May 22 18:10:28 2018 +0900
+
+ Bug 1454285 - Part 2: Disallow using innermostEmitterScope while the value does not match the bytecode environment. r=jwalden, a=RyanVM
+
+ --HG--
+ extra : source : 567757b97ff0f511bb142b966f5b5777bad7fdc2
+---
+ js/src/frontend/BytecodeEmitter.cpp | 59 ++++++++++++++++++++-----------------
+ js/src/frontend/BytecodeEmitter.h | 49 ++++++++++++++++++++++++++----
+ 2 files changed, 76 insertions(+), 32 deletions(-)
+
+diff --git js/src/frontend/BytecodeEmitter.cpp js/src/frontend/BytecodeEmitter.cpp
+index e8edc66658804..e13f5bfdd243b 100644
+--- js/src/frontend/BytecodeEmitter.cpp
++++ js/src/frontend/BytecodeEmitter.cpp
+@@ -102,7 +102,7 @@ class BytecodeEmitter::NestableControl : public Nestable<BytecodeEmitter::Nestab
+ NestableControl(BytecodeEmitter* bce, StatementKind kind)
+ : Nestable<NestableControl>(&bce->innermostNestableControl),
+ kind_(kind),
+- emitterScope_(bce->innermostEmitterScope)
++ emitterScope_(bce->innermostEmitterScopeNoCheck())
+ { }
+
+ public:
+@@ -436,7 +436,7 @@ class BytecodeEmitter::EmitterScope : public Nestable<BytecodeEmitter::EmitterSc
+ // enclosing BCE.
+ if ((*bce)->parent) {
+ *bce = (*bce)->parent;
+- return (*bce)->innermostEmitterScope;
++ return (*bce)->innermostEmitterScopeNoCheck();
+ }
+
+ return nullptr;
+@@ -470,7 +470,7 @@ class BytecodeEmitter::EmitterScope : public Nestable<BytecodeEmitter::EmitterSc
+
+ public:
+ explicit EmitterScope(BytecodeEmitter* bce)
+- : Nestable<EmitterScope>(&bce->innermostEmitterScope),
++ : Nestable<EmitterScope>(&bce->innermostEmitterScope_),
+ nameCache_(bce->cx->frontendCollectionPool()),
+ hasEnvironment_(false),
+ environmentChainLength_(0),
+@@ -879,7 +879,7 @@ BytecodeEmitter::EmitterScope::enterLexical(BytecodeEmitter* bce, ScopeKind kind
+ Handle<LexicalScope::Data*> bindings)
+ {
+ MOZ_ASSERT(kind != ScopeKind::NamedLambda && kind != ScopeKind::StrictNamedLambda);
+- MOZ_ASSERT(this == bce->innermostEmitterScope);
++ MOZ_ASSERT(this == bce->innermostEmitterScopeNoCheck());
+
+ if (!ensureCache(bce))
+ return false;
+@@ -948,7 +948,7 @@ BytecodeEmitter::EmitterScope::enterLexical(BytecodeEmitter* bce, ScopeKind kind
+ bool
+ BytecodeEmitter::EmitterScope::enterNamedLambda(BytecodeEmitter* bce, FunctionBox* funbox)
+ {
+- MOZ_ASSERT(this == bce->innermostEmitterScope);
++ MOZ_ASSERT(this == bce->innermostEmitterScopeNoCheck());
+ MOZ_ASSERT(funbox->namedLambdaBindings());
+
+ if (!ensureCache(bce))
+@@ -1015,7 +1015,7 @@ BytecodeEmitter::EmitterScope::enterComprehensionFor(BytecodeEmitter* bce,
+ bool
+ BytecodeEmitter::EmitterScope::enterParameterExpressionVar(BytecodeEmitter* bce)
+ {
+- MOZ_ASSERT(this == bce->innermostEmitterScope);
++ MOZ_ASSERT(this == bce->innermostEmitterScopeNoCheck());
+
+ if (!ensureCache(bce))
+ return false;
+@@ -1048,7 +1048,7 @@ BytecodeEmitter::EmitterScope::enterParameterExpressionVar(BytecodeEmitter* bce)
+ bool
+ BytecodeEmitter::EmitterScope::enterFunction(BytecodeEmitter* bce, FunctionBox* funbox)
+ {
+- MOZ_ASSERT(this == bce->innermostEmitterScope);
++ MOZ_ASSERT(this == bce->innermostEmitterScopeNoCheck());
+
+ // If there are parameter expressions, there is an extra var scope.
+ if (!funbox->hasExtraBodyVarScope())
+@@ -1139,7 +1139,7 @@ BytecodeEmitter::EmitterScope::enterFunctionExtraBodyVar(BytecodeEmitter* bce, F
+ MOZ_ASSERT(funbox->hasParameterExprs);
+ MOZ_ASSERT(funbox->extraVarScopeBindings() ||
+ funbox->needsExtraBodyVarEnvironmentRegardlessOfBindings());
+- MOZ_ASSERT(this == bce->innermostEmitterScope);
++ MOZ_ASSERT(this == bce->innermostEmitterScopeNoCheck());
+
+ // The extra var scope is never popped once it's entered. It replaces the
+ // function scope as the var emitter scope.
+@@ -1225,7 +1225,7 @@ class DynamicBindingIter : public BindingIter
+ bool
+ BytecodeEmitter::EmitterScope::enterGlobal(BytecodeEmitter* bce, GlobalSharedContext* globalsc)
+ {
+- MOZ_ASSERT(this == bce->innermostEmitterScope);
++ MOZ_ASSERT(this == bce->innermostEmitterScopeNoCheck());
+
+ bce->setVarEmitterScope(this);
+
+@@ -1285,7 +1285,7 @@ BytecodeEmitter::EmitterScope::enterGlobal(BytecodeEmitter* bce, GlobalSharedCon
+ bool
+ BytecodeEmitter::EmitterScope::enterEval(BytecodeEmitter* bce, EvalSharedContext* evalsc)
+ {
+- MOZ_ASSERT(this == bce->innermostEmitterScope);
++ MOZ_ASSERT(this == bce->innermostEmitterScopeNoCheck());
+
+ bce->setVarEmitterScope(this);
+
+@@ -1340,7 +1340,7 @@ BytecodeEmitter::EmitterScope::enterEval(BytecodeEmitter* bce, EvalSharedContext
+ bool
+ BytecodeEmitter::EmitterScope::enterModule(BytecodeEmitter* bce, ModuleSharedContext* modulesc)
+ {
+- MOZ_ASSERT(this == bce->innermostEmitterScope);
++ MOZ_ASSERT(this == bce->innermostEmitterScopeNoCheck());
+
+ bce->setVarEmitterScope(this);
+
+@@ -1397,7 +1397,7 @@ BytecodeEmitter::EmitterScope::enterModule(BytecodeEmitter* bce, ModuleSharedCon
+ bool
+ BytecodeEmitter::EmitterScope::enterWith(BytecodeEmitter* bce)
+ {
+- MOZ_ASSERT(this == bce->innermostEmitterScope);
++ MOZ_ASSERT(this == bce->innermostEmitterScopeNoCheck());
+
+ if (!ensureCache(bce))
+ return false;
+@@ -1425,7 +1425,7 @@ BytecodeEmitter::EmitterScope::leave(BytecodeEmitter* bce, bool nonLocal)
+ {
+ // If we aren't leaving the scope due to a non-local jump (e.g., break),
+ // we must be the innermost scope.
+- MOZ_ASSERT_IF(!nonLocal, this == bce->innermostEmitterScope);
++ MOZ_ASSERT_IF(!nonLocal, this == bce->innermostEmitterScopeNoCheck());
+
+ ScopeKind kind = scope(bce)->kind();
+ switch (kind) {
+@@ -2139,7 +2139,7 @@ class ForOfLoopControl : public LoopControl
+
+ bool emitIteratorCloseInInnermostScope(BytecodeEmitter* bce,
+ CompletionKind completionKind = CompletionKind::Normal) {
+- return emitIteratorCloseInScope(bce, *bce->innermostEmitterScope, completionKind);
++ return emitIteratorCloseInScope(bce, *bce->innermostEmitterScope(), completionKind);
+ }
+
+ bool emitIteratorCloseInScope(BytecodeEmitter* bce,
+@@ -2213,8 +2213,11 @@ BytecodeEmitter::BytecodeEmitter(BytecodeEmitter* parent,
+ bodyScopeIndex(UINT32_MAX),
+ varEmitterScope(nullptr),
+ innermostNestableControl(nullptr),
+- innermostEmitterScope(nullptr),
++ innermostEmitterScope_(nullptr),
+ innermostTDZCheckCache(nullptr),
++#ifdef DEBUG
++ unstableEmitterScope(false),
++#endif
+ constList(cx),
+ scopeList(cx),
+ tryNoteList(cx),
+@@ -2271,13 +2274,13 @@ BytecodeEmitter::findInnermostNestableControl(Predicate predicate) const
+ NameLocation
+ BytecodeEmitter::lookupName(JSAtom* name)
+ {
+- return innermostEmitterScope->lookup(this, name);
++ return innermostEmitterScope()->lookup(this, name);
+ }
+
+ Maybe<NameLocation>
+ BytecodeEmitter::locationOfNameBoundInScope(JSAtom* name, EmitterScope* target)
+ {
+- return innermostEmitterScope->locationBoundInScope(this, name, target);
++ return innermostEmitterScope()->locationBoundInScope(this, name, target);
+ }
+
+ Maybe<NameLocation>
+@@ -2757,7 +2760,7 @@ class NonLocalExitControl
+ : bce_(bce),
+ savedScopeNoteIndex_(bce->scopeNoteList.length()),
+ savedDepth_(bce->stackDepth),
+- openScopeNoteIndex_(bce->innermostEmitterScope->noteIndex()),
++ openScopeNoteIndex_(bce->innermostEmitterScope()->noteIndex()),
+ kind_(kind)
+ { }
+
+@@ -2803,9 +2806,11 @@ NonLocalExitControl::prepareForNonLocalJump(BytecodeEmitter::NestableControl* ta
+ using NestableControl = BytecodeEmitter::NestableControl;
+ using EmitterScope = BytecodeEmitter::EmitterScope;
+
+- EmitterScope* es = bce_->innermostEmitterScope;
++ EmitterScope* es = bce_->innermostEmitterScope();
+ int npops = 0;
+
++ AutoCheckUnstableEmitterScope cues(bce_);
++
+ // For 'continue', 'break', and 'return' statements, emit IteratorClose
+ // bytecode inline. 'continue' statements do not call IteratorClose for
+ // the loop they are continuing.
+@@ -2924,7 +2929,7 @@ BytecodeEmitter::emitGoto(NestableControl* target, JumpList* jumplist, SrcNoteTy
+ Scope*
+ BytecodeEmitter::innermostScope() const
+ {
+- return innermostEmitterScope->scope(this);
++ return innermostEmitterScope()->scope(this);
+ }
+
+ bool
+@@ -3585,7 +3590,7 @@ BytecodeEmitter::needsImplicitThis()
+ return true;
+
+ // Otherwise see if the current point is under a 'with'.
+- for (EmitterScope* es = innermostEmitterScope; es; es = es->enclosingInFrame()) {
++ for (EmitterScope* es = innermostEmitterScope(); es; es = es->enclosingInFrame()) {
+ if (es->scope(this)->kind() == ScopeKind::With)
+ return true;
+ }
+@@ -5262,7 +5267,7 @@ BytecodeEmitter::emitSetOrInitializeDestructuring(ParseNode* target, Destructuri
+ // destructuring declaration needs to initialize the name in
+ // the function scope. The innermost scope is the var scope,
+ // and its enclosing scope is the function scope.
+- EmitterScope* funScope = innermostEmitterScope->enclosingInFrame();
++ EmitterScope* funScope = innermostEmitterScope()->enclosingInFrame();
+ NameLocation paramLoc = *locationOfNameBoundInScope(name, funScope);
+ if (!emitSetOrInitializeNameAtLocation(name, paramLoc, emitSwapScopeAndRhs, true))
+ return false;
+@@ -7304,7 +7309,7 @@ BytecodeEmitter::emitForOf(ParseNode* forOfLoop, EmitterScope* headLexicalEmitte
+ // bindings inducing an environment, recreate the current environment.
+ DebugOnly<ParseNode*> forOfTarget = forOfHead->pn_kid1;
+ MOZ_ASSERT(forOfTarget->isKind(PNK_LET) || forOfTarget->isKind(PNK_CONST));
+- MOZ_ASSERT(headLexicalEmitterScope == innermostEmitterScope);
++ MOZ_ASSERT(headLexicalEmitterScope == innermostEmitterScope());
+ MOZ_ASSERT(headLexicalEmitterScope->scope(this)->kind() == ScopeKind::Lexical);
+
+ if (headLexicalEmitterScope->hasEnvironment()) {
+@@ -7502,7 +7507,7 @@ BytecodeEmitter::emitForIn(ParseNode* forInLoop, EmitterScope* headLexicalEmitte
+ // it must be the innermost one. If that scope has closed-over
+ // bindings inducing an environment, recreate the current environment.
+ MOZ_ASSERT(forInTarget->isKind(PNK_LET) || forInTarget->isKind(PNK_CONST));
+- MOZ_ASSERT(headLexicalEmitterScope == innermostEmitterScope);
++ MOZ_ASSERT(headLexicalEmitterScope == innermostEmitterScope());
+ MOZ_ASSERT(headLexicalEmitterScope->scope(this)->kind() == ScopeKind::Lexical);
+
+ if (headLexicalEmitterScope->hasEnvironment()) {
+@@ -7635,7 +7640,7 @@ BytecodeEmitter::emitCStyleFor(ParseNode* pn, EmitterScope* headLexicalEmitterSc
+ // exists for the head, it must be the innermost one. If that scope
+ // has closed-over bindings inducing an environment, recreate the
+ // current environment.
+- MOZ_ASSERT(headLexicalEmitterScope == innermostEmitterScope);
++ MOZ_ASSERT(headLexicalEmitterScope == innermostEmitterScope());
+ MOZ_ASSERT(headLexicalEmitterScope->scope(this)->kind() == ScopeKind::Lexical);
+
+ if (headLexicalEmitterScope->hasEnvironment()) {
+@@ -7683,7 +7688,7 @@ BytecodeEmitter::emitCStyleFor(ParseNode* pn, EmitterScope* headLexicalEmitterSc
+
+ // ES 13.7.4.8 step 3.e. The per-iteration freshening.
+ if (forLoopRequiresFreshening) {
+- MOZ_ASSERT(headLexicalEmitterScope == innermostEmitterScope);
++ MOZ_ASSERT(headLexicalEmitterScope == innermostEmitterScope());
+ MOZ_ASSERT(headLexicalEmitterScope->scope(this)->kind() == ScopeKind::Lexical);
+
+ if (headLexicalEmitterScope->hasEnvironment()) {
+@@ -10410,7 +10415,7 @@ BytecodeEmitter::emitFunctionFormalParameters(ParseNode* pn)
+ {
+ ParseNode* funBody = pn->last();
+ FunctionBox* funbox = sc->asFunctionBox();
+- EmitterScope* funScope = innermostEmitterScope;
++ EmitterScope* funScope = innermostEmitterScope();
+
+ bool hasParameterExprs = funbox->hasParameterExprs;
+ bool hasRest = funbox->hasRest();
+diff --git js/src/frontend/BytecodeEmitter.h js/src/frontend/BytecodeEmitter.h
+index 039d271e4d965..91826f27bf9fd 100644
+--- js/src/frontend/BytecodeEmitter.h
++++ js/src/frontend/BytecodeEmitter.h
+@@ -232,9 +232,23 @@ struct MOZ_STACK_CLASS BytecodeEmitter
+
+ EmitterScope* varEmitterScope;
+ NestableControl* innermostNestableControl;
+- EmitterScope* innermostEmitterScope;
++ EmitterScope* innermostEmitterScope_;
+ TDZCheckCache* innermostTDZCheckCache;
+
++#ifdef DEBUG
++ bool unstableEmitterScope;
++
++ friend class AutoCheckUnstableEmitterScope;
++#endif
++
++ EmitterScope* innermostEmitterScope() const {
++ MOZ_ASSERT(!unstableEmitterScope);
++ return innermostEmitterScopeNoCheck();
++ }
++ EmitterScope* innermostEmitterScopeNoCheck() const {
++ return innermostEmitterScope_;
++ }
++
+ CGConstList constList; /* constants to be included with the script */
+ CGObjectList objectList; /* list of emitted objects */
+ CGScopeList scopeList; /* list of emitted scopes */
+@@ -339,7 +353,7 @@ struct MOZ_STACK_CLASS BytecodeEmitter
+ EmitterScope* source);
+
+ mozilla::Maybe<NameLocation> locationOfNameBoundInFunctionScope(JSAtom* name) {
+- return locationOfNameBoundInFunctionScope(name, innermostEmitterScope);
++ return locationOfNameBoundInFunctionScope(name, innermostEmitterScope());
+ }
+
+ void setVarEmitterScope(EmitterScope* emitterScope) {
+@@ -635,7 +649,7 @@ struct MOZ_STACK_CLASS BytecodeEmitter
+ MOZ_MUST_USE bool emitToIteratorResult(bool done);
+
+ MOZ_MUST_USE bool emitGetDotGeneratorInInnermostScope() {
+- return emitGetDotGeneratorInScope(*innermostEmitterScope);
++ return emitGetDotGeneratorInScope(*innermostEmitterScope());
+ }
+ MOZ_MUST_USE bool emitGetDotGeneratorInScope(EmitterScope& currentScope);
+
+@@ -644,7 +658,7 @@ struct MOZ_STACK_CLASS BytecodeEmitter
+ MOZ_MUST_USE bool emitYieldOp(JSOp op);
+ MOZ_MUST_USE bool emitYieldStar(ParseNode* iter);
+ MOZ_MUST_USE bool emitAwaitInInnermostScope() {
+- return emitAwaitInScope(*innermostEmitterScope);
++ return emitAwaitInScope(*innermostEmitterScope());
+ }
+ MOZ_MUST_USE bool emitAwaitInInnermostScope(ParseNode* pn);
+ MOZ_MUST_USE bool emitAwaitInScope(EmitterScope& currentScope);
+@@ -751,7 +765,7 @@ struct MOZ_STACK_CLASS BytecodeEmitter
+ MOZ_MUST_USE bool emitIteratorCloseInInnermostScope(IteratorKind iterKind = IteratorKind::Sync,
+ CompletionKind completionKind = CompletionKind::Normal,
+ bool allowSelfHosted = false) {
+- return emitIteratorCloseInScope(*innermostEmitterScope, iterKind, completionKind,
++ return emitIteratorCloseInScope(*innermostEmitterScope(), iterKind, completionKind,
+ allowSelfHosted);
+ }
+
+@@ -852,6 +866,31 @@ struct MOZ_STACK_CLASS BytecodeEmitter
+ MOZ_MUST_USE bool emitSuperElemOp(ParseNode* pn, JSOp op, bool isCall = false);
+ };
+
++class MOZ_RAII AutoCheckUnstableEmitterScope {
++#ifdef DEBUG
++ bool prev_;
++ BytecodeEmitter* bce_;
++#endif
++
++ public:
++ AutoCheckUnstableEmitterScope() = delete;
++ explicit AutoCheckUnstableEmitterScope(BytecodeEmitter* bce)
++#ifdef DEBUG
++ : bce_(bce)
++#endif
++ {
++#ifdef DEBUG
++ prev_ = bce_->unstableEmitterScope;
++ bce_->unstableEmitterScope = true;
++#endif
++ }
++ ~AutoCheckUnstableEmitterScope() {
++#ifdef DEBUG
++ bce_->unstableEmitterScope = prev_;
++#endif
++ }
++};
++
+ } /* namespace frontend */
+ } /* namespace js */
+
diff --git a/www/waterfox/files/patch-bug1456189 b/www/waterfox/files/patch-bug1456189
new file mode 100644
index 000000000000..2663e82dbc28
--- /dev/null
+++ b/www/waterfox/files/patch-bug1456189
@@ -0,0 +1,218 @@
+commit e5c1015f6968
+Author: Alex Gaynor <agaynor@mozilla.com>
+Date: Fri May 18 18:59:00 2018 -0400
+
+ Bug 1456189 - Simplify BufferList::Extract to make the lifetimes clearer. r=froydnj, a=RyanVM
+
+ --HG--
+ extra : source : 9d8c922db947eadeca8278bb33d4f5fe271cef05
+---
+ mfbt/BufferList.h | 129 ++++++++++++++++++++++++++++--------------
+ mfbt/tests/TestBufferList.cpp | 33 ++++++++++-
+ 2 files changed, 115 insertions(+), 47 deletions(-)
+
+diff --git mfbt/BufferList.h mfbt/BufferList.h
+index 62ab540df0fbb..a2e7aac32a9f3 100644
+--- mfbt/BufferList.h
++++ mfbt/BufferList.h
+@@ -9,6 +9,7 @@
+
+ #include <algorithm>
+ #include "mozilla/AllocPolicy.h"
++#include "mozilla/Maybe.h"
+ #include "mozilla/MemoryReporting.h"
+ #include "mozilla/Move.h"
+ #include "mozilla/ScopeExit.h"
+@@ -538,61 +539,101 @@ BufferList<AllocPolicy>::Extract(IterImpl& aIter, size_t aSize, bool* aSuccess)
+ MOZ_ASSERT(aSize % kSegmentAlignment == 0);
+ MOZ_ASSERT(intptr_t(aIter.mData) % kSegmentAlignment == 0);
+
+- IterImpl iter = aIter;
+- size_t size = aSize;
+- size_t toCopy = std::min(size, aIter.RemainingInSegment());
+- MOZ_ASSERT(toCopy % kSegmentAlignment == 0);
++ auto failure = [this, aSuccess]() {
++ *aSuccess = false;
++ return BufferList(0, 0, mStandardCapacity);
++ };
+
+- BufferList result(0, toCopy, mStandardCapacity);
+- BufferList error(0, 0, mStandardCapacity);
++ // Number of segments we'll need to copy data from to satisfy the request.
++ size_t segmentsNeeded = 0;
++ // If this is None then the last segment is a full segment, otherwise we need
++ // to copy this many bytes.
++ Maybe<size_t> lastSegmentSize;
++ {
++ // Copy of the iterator to walk the BufferList and see how many segments we
++ // need to copy.
++ IterImpl iter = aIter;
++ size_t remaining = aSize;
++ while (!iter.Done() && remaining &&
++ remaining >= iter.RemainingInSegment()) {
++ remaining -= iter.RemainingInSegment();
++ iter.Advance(*this, iter.RemainingInSegment());
++ segmentsNeeded++;
++ }
+
+- // Copy the head
+- if (!result.WriteBytes(aIter.mData, toCopy)) {
+- *aSuccess = false;
+- return error;
++ if (remaining) {
++ if (iter.Done()) {
++ // We reached the end of the BufferList and there wasn't enough data to
++ // satisfy the request.
++ return failure();
++ }
++ lastSegmentSize.emplace(remaining);
++ // The last block also counts as a segment. This makes the conditionals
++ // on segmentsNeeded work in the rest of the function.
++ segmentsNeeded++;
++ }
+ }
+- iter.Advance(*this, toCopy);
+- size -= toCopy;
+
+- // Move segments to result
+- auto resultGuard = MakeScopeExit([&] {
+- *aSuccess = false;
+- result.mSegments.erase(result.mSegments.begin()+1, result.mSegments.end());
+- });
+-
+- size_t movedSize = 0;
+- uintptr_t toRemoveStart = iter.mSegment;
+- uintptr_t toRemoveEnd = iter.mSegment;
+- while (!iter.Done() &&
+- !iter.HasRoomFor(size)) {
+- if (!result.mSegments.append(Segment(mSegments[iter.mSegment].mData,
+- mSegments[iter.mSegment].mSize,
+- mSegments[iter.mSegment].mCapacity))) {
+- return error;
+- }
+- movedSize += iter.RemainingInSegment();
+- size -= iter.RemainingInSegment();
+- toRemoveEnd++;
+- iter.Advance(*this, iter.RemainingInSegment());
++ BufferList result(0, 0, mStandardCapacity);
++ if (!result.mSegments.reserve(segmentsNeeded + lastSegmentSize.isSome())) {
++ return failure();
+ }
+
+- if (size) {
+- if (!iter.HasRoomFor(size) ||
+- !result.WriteBytes(iter.Data(), size)) {
+- return error;
++ // Copy the first segment, it's special because we can't just steal the
++ // entire Segment struct from this->mSegments.
++ size_t firstSegmentSize = std::min(aSize, aIter.RemainingInSegment());
++ if (!result.WriteBytes(aIter.Data(), firstSegmentSize)) {
++ return failure();
++ }
++ aIter.Advance(*this, firstSegmentSize);
++ segmentsNeeded--;
++
++ // The entirety of the request wasn't in the first segment, now copy the
++ // rest.
++ if (segmentsNeeded) {
++ char* finalSegment = nullptr;
++ // Pre-allocate the final segment so that if this fails, we return before
++ // we delete the elements from |this->mSegments|.
++ if (lastSegmentSize.isSome()) {
++ MOZ_RELEASE_ASSERT(mStandardCapacity >= *lastSegmentSize);
++ finalSegment = this->template pod_malloc<char>(mStandardCapacity);
++ if (!finalSegment) {
++ return failure();
++ }
++ }
++
++ size_t copyStart = aIter.mSegment;
++ // Copy segments from this over to the result and remove them from our
++ // storage. Not needed if the only segment we need to copy is the last
++ // partial one.
++ size_t segmentsToCopy = segmentsNeeded - lastSegmentSize.isSome();
++ for (size_t i = 0; i < segmentsToCopy; ++i) {
++ result.mSegments.infallibleAppend(
++ Segment(mSegments[aIter.mSegment].mData,
++ mSegments[aIter.mSegment].mSize,
++ mSegments[aIter.mSegment].mCapacity));
++ aIter.Advance(*this, aIter.RemainingInSegment());
++ }
++ MOZ_RELEASE_ASSERT(aIter.mSegment == copyStart + segmentsToCopy);
++ mSegments.erase(mSegments.begin() + copyStart,
++ mSegments.begin() + copyStart + segmentsToCopy);
++
++ // Reset the iter's position for what we just deleted.
++ aIter.mSegment -= segmentsToCopy;
++
++ if (lastSegmentSize.isSome()) {
++ // We called reserve() on result.mSegments so infallibleAppend is safe.
++ result.mSegments.infallibleAppend(
++ Segment(finalSegment, 0, mStandardCapacity));
++ bool r = result.WriteBytes(aIter.Data(), *lastSegmentSize);
++ MOZ_RELEASE_ASSERT(r);
++ aIter.Advance(*this, *lastSegmentSize);
+ }
+- iter.Advance(*this, size);
+ }
+
+- mSegments.erase(mSegments.begin() + toRemoveStart, mSegments.begin() + toRemoveEnd);
+- mSize -= movedSize;
+- aIter.mSegment = iter.mSegment - (toRemoveEnd - toRemoveStart);
+- aIter.mData = iter.mData;
+- aIter.mDataEnd = iter.mDataEnd;
+- MOZ_ASSERT(aIter.mDataEnd == mSegments[aIter.mSegment].End());
++ mSize -= aSize;
+ result.mSize = aSize;
+
+- resultGuard.release();
+ *aSuccess = true;
+ return result;
+ }
+diff --git mfbt/tests/TestBufferList.cpp mfbt/tests/TestBufferList.cpp
+index cccaac021b4a7..207fa106f556f 100644
+--- mfbt/tests/TestBufferList.cpp
++++ mfbt/tests/TestBufferList.cpp
+@@ -245,12 +245,39 @@ int main(void)
+ BufferList bl3 = bl.Extract(iter, kExtractOverSize, &success);
+ MOZ_RELEASE_ASSERT(!success);
+
+- MOZ_RELEASE_ASSERT(iter.AdvanceAcrossSegments(bl, kSmallWrite * 3 - kExtractSize - kExtractStart));
+- MOZ_RELEASE_ASSERT(iter.Done());
+-
+ iter = bl2.Iter();
+ MOZ_RELEASE_ASSERT(iter.AdvanceAcrossSegments(bl2, kExtractSize));
+ MOZ_RELEASE_ASSERT(iter.Done());
+
++ BufferList bl4(8, 8, 8);
++ bl4.WriteBytes("abcd1234", 8);
++ iter = bl4.Iter();
++ iter.Advance(bl4, 8);
++
++ BufferList bl5 = bl4.Extract(iter, kExtractSize, &success);
++ MOZ_RELEASE_ASSERT(!success);
++
++ BufferList bl6(0, 0, 16);
++ bl6.WriteBytes("abcdefgh12345678", 16);
++ bl6.WriteBytes("ijklmnop87654321", 16);
++ iter = bl6.Iter();
++ iter.Advance(bl6, 8);
++ BufferList bl7 = bl6.Extract(iter, 16, &success);
++ MOZ_RELEASE_ASSERT(success);
++ char data[16];
++ MOZ_RELEASE_ASSERT(bl6.ReadBytes(iter, data, 8));
++ MOZ_RELEASE_ASSERT(memcmp(data, "87654321", 8) == 0);
++ iter = bl7.Iter();
++ MOZ_RELEASE_ASSERT(bl7.ReadBytes(iter, data, 16));
++ MOZ_RELEASE_ASSERT(memcmp(data, "12345678ijklmnop", 16) == 0);
++
++ BufferList bl8(0, 0, 16);
++ bl8.WriteBytes("abcdefgh12345678", 16);
++ iter = bl8.Iter();
++ BufferList bl9 = bl8.Extract(iter, 8, &success);
++ MOZ_RELEASE_ASSERT(success);
++ MOZ_RELEASE_ASSERT(bl9.Size() == 8);
++ MOZ_RELEASE_ASSERT(!iter.Done());
++
+ return 0;
+ }
diff --git a/www/waterfox/files/patch-bug1456512 b/www/waterfox/files/patch-bug1456512
new file mode 100644
index 000000000000..4f52fe92bdf5
--- /dev/null
+++ b/www/waterfox/files/patch-bug1456512
@@ -0,0 +1,144 @@
+commit 501094be302c
+Author: Steve Fink <sfink@mozilla.com>
+Date: Tue May 22 16:08:40 2018 -0700
+
+ Bug 1456512 - Fixes for unwanted read barriers during minor GC: move JS::operator==(GCCellPtr,GCCellPtr) to the global scope to avoid shadowing, and add a dynamic check. r=jonco, a=RyanVM
+---
+ js/public/HeapAPI.h | 27 +++++++++++---------
+ js/src/gc/Cell.h | 2 +-
+ .../regress/regress-1456512-greyreadbarrier.js | 7 ++++++
+ js/src/tests/non262/regress/regress-1456512.js | 19 ++++++++++++++
+ js/src/tests/non262/regress/regress-1463421.js | 29 ++++++++++++++++++++++
+ 5 files changed, 71 insertions(+), 13 deletions(-)
+
+diff --git js/public/HeapAPI.h js/public/HeapAPI.h
+index 34a3e156e66da..a14e1a813adfd 100644
+--- js/public/HeapAPI.h
++++ js/public/HeapAPI.h
+@@ -269,18 +269,6 @@ class JS_FRIEND_API(GCCellPtr)
+ uintptr_t ptr;
+ };
+
+-inline bool
+-operator==(const GCCellPtr& ptr1, const GCCellPtr& ptr2)
+-{
+- return ptr1.asCell() == ptr2.asCell();
+-}
+-
+-inline bool
+-operator!=(const GCCellPtr& ptr1, const GCCellPtr& ptr2)
+-{
+- return !(ptr1 == ptr2);
+-}
+-
+ // Unwraps the given GCCellPtr and calls the given functor with a template
+ // argument of the actual type of the pointer.
+ template <typename F, typename... Args>
+@@ -301,6 +289,21 @@ DispatchTyped(F f, GCCellPtr thing, Args&&... args)
+
+ } /* namespace JS */
+
++// These are defined in the toplevel namespace instead of within JS so that
++// they won't shadow other operator== overloads (see bug 1456512.)
++
++inline bool
++operator==(const JS::GCCellPtr& ptr1, const JS::GCCellPtr& ptr2)
++{
++ return ptr1.asCell() == ptr2.asCell();
++}
++
++inline bool
++operator!=(const JS::GCCellPtr& ptr1, const JS::GCCellPtr& ptr2)
++{
++ return !(ptr1 == ptr2);
++}
++
+ namespace js {
+ namespace gc {
+ namespace detail {
+diff --git js/src/gc/Heap.h js/src/gc/Heap.h
+index c14f8bfc2005e..340287e8322e9 100644
+--- js/src/gc/Heap.h
++++ js/src/gc/Heap.h
+@@ -1381,7 +1381,7 @@ TenuredCell::readBarrier(TenuredCell* thing)
+ if (thing->isMarkedGray()) {
+ // There shouldn't be anything marked grey unless we're on the active thread.
+ MOZ_ASSERT(CurrentThreadCanAccessRuntime(thing->runtimeFromAnyThread()));
+- if (!RuntimeFromActiveCooperatingThreadIsHeapMajorCollecting(shadowZone))
++ if (!JS::CurrentThreadIsHeapCollecting())
+ JS::UnmarkGrayGCThingRecursively(JS::GCCellPtr(thing, thing->getTraceKind()));
+ }
+ }
+diff --git js/src/tests/non262/regress/regress-1456512-greyreadbarrier.js js/src/tests/non262/regress/regress-1456512-greyreadbarrier.js
+new file mode 100644
+index 0000000000000..bb883eeffbeab
+--- /dev/null
++++ js/src/tests/non262/regress/regress-1456512-greyreadbarrier.js
+@@ -0,0 +1,7 @@
++var wm = new WeakMap();
++grayRoot().map = wm;
++wm = null;
++gczeal(13, 7);
++var lfOffThreadGlobal = newGlobal();
++
++reportCompare('do not crash', 'do not crash', 'did not crash!');
+diff --git js/src/tests/non262/regress/regress-1456512.js js/src/tests/non262/regress/regress-1456512.js
+new file mode 100644
+index 0000000000000..87faeca39ad15
+--- /dev/null
++++ js/src/tests/non262/regress/regress-1456512.js
+@@ -0,0 +1,19 @@
++/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
++/* This Source Code Form is subject to the terms of the Mozilla Public
++ * License, v. 2.0. If a copy of the MPL was not distributed with this
++ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
++
++var BUGNUMBER = 1456512;
++var summary = 'rogue read barrier';
++
++printBugNumber(BUGNUMBER);
++printStatus (summary);
++
++var wm = new WeakMap();
++grayRoot().map = wm;
++wm = null;
++gczeal(13, 7);
++var lfOffThreadGlobal = newGlobal();
++
++if (typeof reportCompare == 'function')
++ reportCompare(true, true, "ok");
+diff --git js/src/tests/non262/regress/regress-1463421.js js/src/tests/non262/regress/regress-1463421.js
+new file mode 100644
+index 0000000000000..e037ade3b9fd0
+--- /dev/null
++++ js/src/tests/non262/regress/regress-1463421.js
+@@ -0,0 +1,29 @@
++/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
++/* This Source Code Form is subject to the terms of the Mozilla Public
++ * License, v. 2.0. If a copy of the MPL was not distributed with this
++ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
++
++var BUGNUMBER = 1463421;
++var summary = 'rogue read barrier';
++
++printBugNumber(BUGNUMBER);
++printStatus (summary);
++
++var exc;
++try {
++var __v_1173 = new WeakMap();
++ grayRoot().map = __v_1173;
++ __v_1173 = null;
++ gczeal(13, 7);
++if (!isNaN()) {
++}
++ (function __f_252() {
++ ( {
++ })()
++ })();
++} catch (e) {
++ exc = e;
++}
++
++if (typeof reportCompare == 'function')
++ reportCompare("" + exc, "TypeError: ({}) is not a function", "ok");
diff --git a/www/waterfox/files/patch-bug1462912 b/www/waterfox/files/patch-bug1462912
new file mode 100644
index 000000000000..ae24d4178fe6
--- /dev/null
+++ b/www/waterfox/files/patch-bug1462912
@@ -0,0 +1,57 @@
+commit 8fbbe9d566d3 (origin/beta)
+Author: Alex Gaynor <agaynor@mozilla.com>
+Date: Tue May 22 13:04:59 2018 -0400
+
+ Bug 1462912 - Fixed BufferList::Extract to handle the case where the call consumes the entirety of the BufferList. r=froydnj, a=RyanVM
+
+ MozReview-Commit-ID: 1LWODn8JaNL
+
+ --HG--
+ extra : source : 96a6ea5ea3468b4c9e20ff8d9795a7ef136213a9
+---
+ mfbt/BufferList.h | 9 ++++++++-
+ mfbt/tests/TestBufferList.cpp | 12 ++++++++++++
+ 2 files changed, 20 insertions(+), 1 deletion(-)
+
+diff --git mfbt/BufferList.h mfbt/BufferList.h
+index a2e7aac32a9f3..1b35874f3df0d 100644
+--- mfbt/BufferList.h
++++ mfbt/BufferList.h
+@@ -614,7 +614,14 @@ BufferList<AllocPolicy>::Extract(IterImpl& aIter, size_t aSize, bool* aSuccess)
+ mSegments[aIter.mSegment].mCapacity));
+ aIter.Advance(*this, aIter.RemainingInSegment());
+ }
+- MOZ_RELEASE_ASSERT(aIter.mSegment == copyStart + segmentsToCopy);
++ // Due to the way IterImpl works, there are two cases here: (1) if we've
++ // consumed the entirety of the BufferList, then the iterator is pointed at
++ // the end of the final segment, (2) otherwise it is pointed at the start
++ // of the next segment. We want to verify that we really consumed all
++ // |segmentsToCopy| segments.
++ MOZ_RELEASE_ASSERT(
++ (aIter.mSegment == copyStart + segmentsToCopy) ||
++ (aIter.Done() && aIter.mSegment == copyStart + segmentsToCopy - 1));
+ mSegments.erase(mSegments.begin() + copyStart,
+ mSegments.begin() + copyStart + segmentsToCopy);
+
+diff --git mfbt/tests/TestBufferList.cpp mfbt/tests/TestBufferList.cpp
+index 207fa106f556f..325f8a3aa7ada 100644
+--- mfbt/tests/TestBufferList.cpp
++++ mfbt/tests/TestBufferList.cpp
+@@ -279,5 +279,17 @@ int main(void)
+ MOZ_RELEASE_ASSERT(bl9.Size() == 8);
+ MOZ_RELEASE_ASSERT(!iter.Done());
+
++ BufferList bl10(0, 0, 8);
++ bl10.WriteBytes("abcdefgh", 8);
++ bl10.WriteBytes("12345678", 8);
++ iter = bl10.Iter();
++ BufferList bl11 = bl10.Extract(iter, 16, &success);
++ MOZ_RELEASE_ASSERT(success);
++ MOZ_RELEASE_ASSERT(bl11.Size() == 16);
++ MOZ_RELEASE_ASSERT(iter.Done());
++ iter = bl11.Iter();
++ MOZ_RELEASE_ASSERT(bl11.ReadBytes(iter, data, 16));
++ MOZ_RELEASE_ASSERT(memcmp(data, "abcdefgh12345678", 16) == 0);
++
+ return 0;
+ }