diff options
author | jbeich <jbeich@FreeBSD.org> | 2018-05-24 08:53:46 +0800 |
---|---|---|
committer | jbeich <jbeich@FreeBSD.org> | 2018-05-24 08:53:46 +0800 |
commit | 3e8cf7dc65f07ad09139c5bd2828a6ef85b13e98 (patch) | |
tree | 6cf8666c88555a8160ca80a017a10fdc18399161 /www | |
parent | 35c2152e178d190af273bdc1e4ad4af74f7d7b4f (diff) | |
download | freebsd-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/Makefile | 2 | ||||
-rw-r--r-- | www/waterfox/files/patch-bug1412882 | 192 | ||||
-rw-r--r-- | www/waterfox/files/patch-bug1454285 | 713 | ||||
-rw-r--r-- | www/waterfox/files/patch-bug1456189 | 218 | ||||
-rw-r--r-- | www/waterfox/files/patch-bug1456512 | 144 | ||||
-rw-r--r-- | www/waterfox/files/patch-bug1462912 | 57 |
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, ¤tScope); + 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; + } |