MFH: r470749
www/waterfox: apply some FF61 fixes Approved by: ports-secteam blanket
This commit is contained in:
parent
5fda617d5d
commit
616686dc42
Notes:
svn2git
2021-03-31 03:12:20 +00:00
svn path=/branches/2018Q2/; revision=470751
@ -3,7 +3,7 @@
|
||||
PORTNAME= waterfox
|
||||
DISTVERSION= 56.2.0-13
|
||||
DISTVERSIONSUFFIX= -gd2cdd42f4115b
|
||||
PORTREVISION= 1
|
||||
PORTREVISION= 4
|
||||
CATEGORIES= www ipv6
|
||||
|
||||
MAINTAINER= jbeich@FreeBSD.org
|
||||
|
192
www/waterfox/files/patch-bug1412882
Normal file
192
www/waterfox/files/patch-bug1412882
Normal file
@ -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;
|
713
www/waterfox/files/patch-bug1454285
Normal file
713
www/waterfox/files/patch-bug1454285
Normal file
@ -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 */
|
||||
|
218
www/waterfox/files/patch-bug1456189
Normal file
218
www/waterfox/files/patch-bug1456189
Normal file
@ -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;
|
||||
}
|
144
www/waterfox/files/patch-bug1456512
Normal file
144
www/waterfox/files/patch-bug1456512
Normal file
@ -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");
|
57
www/waterfox/files/patch-bug1462912
Normal file
57
www/waterfox/files/patch-bug1462912
Normal file
@ -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;
|
||||
}
|
Loading…
Reference in New Issue
Block a user