MFH: r470749

www/waterfox: apply some FF61 fixes

Approved by:	ports-secteam blanket
This commit is contained in:
Jan Beich 2018-05-24 00:58:44 +00:00
parent 5fda617d5d
commit 616686dc42
Notes: svn2git 2021-03-31 03:12:20 +00:00
svn path=/branches/2018Q2/; revision=470751
6 changed files with 1325 additions and 1 deletions

View File

@ -3,7 +3,7 @@
PORTNAME= waterfox
DISTVERSION= 56.2.0-13
DISTVERSIONSUFFIX= -gd2cdd42f4115b
PORTREVISION= 1
PORTREVISION= 4
CATEGORIES= www ipv6
MAINTAINER= jbeich@FreeBSD.org

View 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;

View 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, &currentScope);
return emitGetNameAtLocation(cx->names().dotGenerator, loc);
}
@@ -8726,7 +8744,7 @@ BytecodeEmitter::emitYield(ParseNode* pn)
return false;
}
- if (!emitGetDotGenerator())
+ if (!emitGetDotGeneratorInInnermostScope())
return false;
if (!emitYieldOp(JSOP_YIELD))
@@ -8736,24 +8754,24 @@ BytecodeEmitter::emitYield(ParseNode* pn)
}
bool
-BytecodeEmitter::emitAwait()
+BytecodeEmitter::emitAwaitInInnermostScope(ParseNode* pn)
{
- if (!emitGetDotGenerator())
- return false;
- if (!emitYieldOp(JSOP_AWAIT))
+ MOZ_ASSERT(sc->isFunctionBox());
+ MOZ_ASSERT(pn->getOp() == JSOP_AWAIT);
+
+ if (!emitTree(pn->pn_kid))
return false;
- return true;
+ return emitAwaitInInnermostScope();
}
bool
-BytecodeEmitter::emitAwait(ParseNode* pn)
+BytecodeEmitter::emitAwaitInScope(EmitterScope& currentScope)
{
- MOZ_ASSERT(sc->isFunctionBox());
- MOZ_ASSERT(pn->getOp() == JSOP_AWAIT);
-
- if (!emitTree(pn->pn_kid))
+ if (!emitGetDotGeneratorInScope(currentScope))
return false;
- return emitAwait();
+ if (!emitYieldOp(JSOP_AWAIT))
+ return false;
+ return true;
}
bool
@@ -8794,7 +8812,7 @@ BytecodeEmitter::emitYieldStar(ParseNode* iter)
MOZ_ASSERT(this->stackDepth == startDepth);
// Load the generator object.
- if (!emitGetDotGenerator()) // ITER RESULT GENOBJ
+ if (!emitGetDotGeneratorInInnermostScope()) // ITER RESULT GENOBJ
return false;
// Yield RESULT as-is, without re-boxing.
@@ -8831,7 +8849,7 @@ BytecodeEmitter::emitYieldStar(ParseNode* iter)
// If the iterator does not have a "throw" method, it calls IteratorClose
// and then throws a TypeError.
IteratorKind iterKind = isAsyncGenerator ? IteratorKind::Async : IteratorKind::Sync;
- if (!emitIteratorClose(iterKind)) // ITER RESULT EXCEPTION
+ if (!emitIteratorCloseInInnermostScope(iterKind)) // ITER RESULT EXCEPTION
return false;
if (!emitUint16Operand(JSOP_THROWMSG, JSMSG_ITERATOR_NO_THROW)) // throw
return false;
@@ -8849,7 +8867,7 @@ BytecodeEmitter::emitYieldStar(ParseNode* iter)
checkTypeSet(JSOP_CALL);
if (isAsyncGenerator) {
- if (!emitAwait()) // ITER OLDRESULT RESULT
+ if (!emitAwaitInInnermostScope()) // ITER OLDRESULT RESULT
return false;
}
@@ -8920,7 +8938,7 @@ BytecodeEmitter::emitYieldStar(ParseNode* iter)
checkTypeSet(JSOP_CALL);
if (iterKind == IteratorKind::Async) {
- if (!emitAwait()) // ... FTYPE FVALUE RESULT
+ if (!emitAwaitInInnermostScope()) // ... FTYPE FVALUE RESULT
return false;
}
@@ -8943,7 +8961,7 @@ BytecodeEmitter::emitYieldStar(ParseNode* iter)
return false;
if (isAsyncGenerator) {
- if (!emitAwait()) // ITER OLDRESULT FTYPE FVALUE VALUE
+ if (!emitAwaitInInnermostScope()) // ITER OLDRESULT FTYPE FVALUE VALUE
return false;
}
@@ -9005,7 +9023,7 @@ BytecodeEmitter::emitYieldStar(ParseNode* iter)
checkTypeSet(JSOP_CALL);
if (isAsyncGenerator) {
- if (!emitAwait()) // ITER RESULT RESULT
+ if (!emitAwaitInInnermostScope()) // ITER RESULT RESULT
return false;
}
@@ -9038,7 +9056,7 @@ BytecodeEmitter::emitYieldStar(ParseNode* iter)
return false;
if (isAsyncGenerator) {
- if (!emitAwait()) // VALUE
+ if (!emitAwaitInInnermostScope()) // VALUE
return false;
}
@@ -10592,7 +10610,7 @@ BytecodeEmitter::emitFunctionBody(ParseNode* funBody)
if (!emit1(JSOP_SETRVAL))
return false;
- if (!emitGetDotGenerator())
+ if (!emitGetDotGeneratorInInnermostScope())
return false;
// No need to check for finally blocks, etc as in EmitReturn.
@@ -10954,7 +10972,7 @@ BytecodeEmitter::emitTree(ParseNode* pn, ValueUsage valueUsage /* = ValueUsage::
break;
case PNK_AWAIT:
- if (!emitAwait(pn))
+ if (!emitAwaitInInnermostScope(pn))
return false;
break;
diff --git js/src/frontend/BytecodeEmitter.h js/src/frontend/BytecodeEmitter.h
index f238cc12c0247..039d271e4d965 100644
--- js/src/frontend/BytecodeEmitter.h
+++ js/src/frontend/BytecodeEmitter.h
@@ -634,14 +634,20 @@ struct MOZ_STACK_CLASS BytecodeEmitter
MOZ_MUST_USE bool iteratorResultShape(unsigned* shape);
MOZ_MUST_USE bool emitToIteratorResult(bool done);
- MOZ_MUST_USE bool emitGetDotGenerator();
+ MOZ_MUST_USE bool emitGetDotGeneratorInInnermostScope() {
+ return emitGetDotGeneratorInScope(*innermostEmitterScope);
+ }
+ MOZ_MUST_USE bool emitGetDotGeneratorInScope(EmitterScope& currentScope);
MOZ_MUST_USE bool emitInitialYield(ParseNode* pn);
MOZ_MUST_USE bool emitYield(ParseNode* pn);
MOZ_MUST_USE bool emitYieldOp(JSOp op);
MOZ_MUST_USE bool emitYieldStar(ParseNode* iter);
- MOZ_MUST_USE bool emitAwait();
- MOZ_MUST_USE bool emitAwait(ParseNode* pn);
+ MOZ_MUST_USE bool emitAwaitInInnermostScope() {
+ return emitAwaitInScope(*innermostEmitterScope);
+ }
+ MOZ_MUST_USE bool emitAwaitInInnermostScope(ParseNode* pn);
+ MOZ_MUST_USE bool emitAwaitInScope(EmitterScope& currentScope);
MOZ_MUST_USE bool emitPropLHS(ParseNode* pn);
MOZ_MUST_USE bool emitPropOp(ParseNode* pn, JSOp op);
@@ -738,9 +744,16 @@ struct MOZ_STACK_CLASS BytecodeEmitter
// onto the stack.
MOZ_MUST_USE bool emitIteratorNext(ParseNode* pn, IteratorKind kind = IteratorKind::Sync,
bool allowSelfHosted = false);
- MOZ_MUST_USE bool emitIteratorClose(IteratorKind iterKind = IteratorKind::Sync,
- CompletionKind completionKind = CompletionKind::Normal,
- bool allowSelfHosted = false);
+ MOZ_MUST_USE bool emitIteratorCloseInScope(EmitterScope& currentScope,
+ IteratorKind iterKind = IteratorKind::Sync,
+ CompletionKind completionKind = CompletionKind::Normal,
+ bool allowSelfHosted = false);
+ MOZ_MUST_USE bool emitIteratorCloseInInnermostScope(IteratorKind iterKind = IteratorKind::Sync,
+ CompletionKind completionKind = CompletionKind::Normal,
+ bool allowSelfHosted = false) {
+ return emitIteratorCloseInScope(*innermostEmitterScope, iterKind, completionKind,
+ allowSelfHosted);
+ }
template <typename InnerEmitter>
MOZ_MUST_USE bool wrapWithDestructuringIteratorCloseTryNote(int32_t iterDepth,
commit 0cd861187fc0
Author: Tooru Fujisawa <arai_a@mac.com>
Date: Tue May 22 18:10:28 2018 +0900
Bug 1454285 - Part 2: Disallow using innermostEmitterScope while the value does not match the bytecode environment. r=jwalden, a=RyanVM
--HG--
extra : source : 567757b97ff0f511bb142b966f5b5777bad7fdc2
---
js/src/frontend/BytecodeEmitter.cpp | 59 ++++++++++++++++++++-----------------
js/src/frontend/BytecodeEmitter.h | 49 ++++++++++++++++++++++++++----
2 files changed, 76 insertions(+), 32 deletions(-)
diff --git js/src/frontend/BytecodeEmitter.cpp js/src/frontend/BytecodeEmitter.cpp
index e8edc66658804..e13f5bfdd243b 100644
--- js/src/frontend/BytecodeEmitter.cpp
+++ js/src/frontend/BytecodeEmitter.cpp
@@ -102,7 +102,7 @@ class BytecodeEmitter::NestableControl : public Nestable<BytecodeEmitter::Nestab
NestableControl(BytecodeEmitter* bce, StatementKind kind)
: Nestable<NestableControl>(&bce->innermostNestableControl),
kind_(kind),
- emitterScope_(bce->innermostEmitterScope)
+ emitterScope_(bce->innermostEmitterScopeNoCheck())
{ }
public:
@@ -436,7 +436,7 @@ class BytecodeEmitter::EmitterScope : public Nestable<BytecodeEmitter::EmitterSc
// enclosing BCE.
if ((*bce)->parent) {
*bce = (*bce)->parent;
- return (*bce)->innermostEmitterScope;
+ return (*bce)->innermostEmitterScopeNoCheck();
}
return nullptr;
@@ -470,7 +470,7 @@ class BytecodeEmitter::EmitterScope : public Nestable<BytecodeEmitter::EmitterSc
public:
explicit EmitterScope(BytecodeEmitter* bce)
- : Nestable<EmitterScope>(&bce->innermostEmitterScope),
+ : Nestable<EmitterScope>(&bce->innermostEmitterScope_),
nameCache_(bce->cx->frontendCollectionPool()),
hasEnvironment_(false),
environmentChainLength_(0),
@@ -879,7 +879,7 @@ BytecodeEmitter::EmitterScope::enterLexical(BytecodeEmitter* bce, ScopeKind kind
Handle<LexicalScope::Data*> bindings)
{
MOZ_ASSERT(kind != ScopeKind::NamedLambda && kind != ScopeKind::StrictNamedLambda);
- MOZ_ASSERT(this == bce->innermostEmitterScope);
+ MOZ_ASSERT(this == bce->innermostEmitterScopeNoCheck());
if (!ensureCache(bce))
return false;
@@ -948,7 +948,7 @@ BytecodeEmitter::EmitterScope::enterLexical(BytecodeEmitter* bce, ScopeKind kind
bool
BytecodeEmitter::EmitterScope::enterNamedLambda(BytecodeEmitter* bce, FunctionBox* funbox)
{
- MOZ_ASSERT(this == bce->innermostEmitterScope);
+ MOZ_ASSERT(this == bce->innermostEmitterScopeNoCheck());
MOZ_ASSERT(funbox->namedLambdaBindings());
if (!ensureCache(bce))
@@ -1015,7 +1015,7 @@ BytecodeEmitter::EmitterScope::enterComprehensionFor(BytecodeEmitter* bce,
bool
BytecodeEmitter::EmitterScope::enterParameterExpressionVar(BytecodeEmitter* bce)
{
- MOZ_ASSERT(this == bce->innermostEmitterScope);
+ MOZ_ASSERT(this == bce->innermostEmitterScopeNoCheck());
if (!ensureCache(bce))
return false;
@@ -1048,7 +1048,7 @@ BytecodeEmitter::EmitterScope::enterParameterExpressionVar(BytecodeEmitter* bce)
bool
BytecodeEmitter::EmitterScope::enterFunction(BytecodeEmitter* bce, FunctionBox* funbox)
{
- MOZ_ASSERT(this == bce->innermostEmitterScope);
+ MOZ_ASSERT(this == bce->innermostEmitterScopeNoCheck());
// If there are parameter expressions, there is an extra var scope.
if (!funbox->hasExtraBodyVarScope())
@@ -1139,7 +1139,7 @@ BytecodeEmitter::EmitterScope::enterFunctionExtraBodyVar(BytecodeEmitter* bce, F
MOZ_ASSERT(funbox->hasParameterExprs);
MOZ_ASSERT(funbox->extraVarScopeBindings() ||
funbox->needsExtraBodyVarEnvironmentRegardlessOfBindings());
- MOZ_ASSERT(this == bce->innermostEmitterScope);
+ MOZ_ASSERT(this == bce->innermostEmitterScopeNoCheck());
// The extra var scope is never popped once it's entered. It replaces the
// function scope as the var emitter scope.
@@ -1225,7 +1225,7 @@ class DynamicBindingIter : public BindingIter
bool
BytecodeEmitter::EmitterScope::enterGlobal(BytecodeEmitter* bce, GlobalSharedContext* globalsc)
{
- MOZ_ASSERT(this == bce->innermostEmitterScope);
+ MOZ_ASSERT(this == bce->innermostEmitterScopeNoCheck());
bce->setVarEmitterScope(this);
@@ -1285,7 +1285,7 @@ BytecodeEmitter::EmitterScope::enterGlobal(BytecodeEmitter* bce, GlobalSharedCon
bool
BytecodeEmitter::EmitterScope::enterEval(BytecodeEmitter* bce, EvalSharedContext* evalsc)
{
- MOZ_ASSERT(this == bce->innermostEmitterScope);
+ MOZ_ASSERT(this == bce->innermostEmitterScopeNoCheck());
bce->setVarEmitterScope(this);
@@ -1340,7 +1340,7 @@ BytecodeEmitter::EmitterScope::enterEval(BytecodeEmitter* bce, EvalSharedContext
bool
BytecodeEmitter::EmitterScope::enterModule(BytecodeEmitter* bce, ModuleSharedContext* modulesc)
{
- MOZ_ASSERT(this == bce->innermostEmitterScope);
+ MOZ_ASSERT(this == bce->innermostEmitterScopeNoCheck());
bce->setVarEmitterScope(this);
@@ -1397,7 +1397,7 @@ BytecodeEmitter::EmitterScope::enterModule(BytecodeEmitter* bce, ModuleSharedCon
bool
BytecodeEmitter::EmitterScope::enterWith(BytecodeEmitter* bce)
{
- MOZ_ASSERT(this == bce->innermostEmitterScope);
+ MOZ_ASSERT(this == bce->innermostEmitterScopeNoCheck());
if (!ensureCache(bce))
return false;
@@ -1425,7 +1425,7 @@ BytecodeEmitter::EmitterScope::leave(BytecodeEmitter* bce, bool nonLocal)
{
// If we aren't leaving the scope due to a non-local jump (e.g., break),
// we must be the innermost scope.
- MOZ_ASSERT_IF(!nonLocal, this == bce->innermostEmitterScope);
+ MOZ_ASSERT_IF(!nonLocal, this == bce->innermostEmitterScopeNoCheck());
ScopeKind kind = scope(bce)->kind();
switch (kind) {
@@ -2139,7 +2139,7 @@ class ForOfLoopControl : public LoopControl
bool emitIteratorCloseInInnermostScope(BytecodeEmitter* bce,
CompletionKind completionKind = CompletionKind::Normal) {
- return emitIteratorCloseInScope(bce, *bce->innermostEmitterScope, completionKind);
+ return emitIteratorCloseInScope(bce, *bce->innermostEmitterScope(), completionKind);
}
bool emitIteratorCloseInScope(BytecodeEmitter* bce,
@@ -2213,8 +2213,11 @@ BytecodeEmitter::BytecodeEmitter(BytecodeEmitter* parent,
bodyScopeIndex(UINT32_MAX),
varEmitterScope(nullptr),
innermostNestableControl(nullptr),
- innermostEmitterScope(nullptr),
+ innermostEmitterScope_(nullptr),
innermostTDZCheckCache(nullptr),
+#ifdef DEBUG
+ unstableEmitterScope(false),
+#endif
constList(cx),
scopeList(cx),
tryNoteList(cx),
@@ -2271,13 +2274,13 @@ BytecodeEmitter::findInnermostNestableControl(Predicate predicate) const
NameLocation
BytecodeEmitter::lookupName(JSAtom* name)
{
- return innermostEmitterScope->lookup(this, name);
+ return innermostEmitterScope()->lookup(this, name);
}
Maybe<NameLocation>
BytecodeEmitter::locationOfNameBoundInScope(JSAtom* name, EmitterScope* target)
{
- return innermostEmitterScope->locationBoundInScope(this, name, target);
+ return innermostEmitterScope()->locationBoundInScope(this, name, target);
}
Maybe<NameLocation>
@@ -2757,7 +2760,7 @@ class NonLocalExitControl
: bce_(bce),
savedScopeNoteIndex_(bce->scopeNoteList.length()),
savedDepth_(bce->stackDepth),
- openScopeNoteIndex_(bce->innermostEmitterScope->noteIndex()),
+ openScopeNoteIndex_(bce->innermostEmitterScope()->noteIndex()),
kind_(kind)
{ }
@@ -2803,9 +2806,11 @@ NonLocalExitControl::prepareForNonLocalJump(BytecodeEmitter::NestableControl* ta
using NestableControl = BytecodeEmitter::NestableControl;
using EmitterScope = BytecodeEmitter::EmitterScope;
- EmitterScope* es = bce_->innermostEmitterScope;
+ EmitterScope* es = bce_->innermostEmitterScope();
int npops = 0;
+ AutoCheckUnstableEmitterScope cues(bce_);
+
// For 'continue', 'break', and 'return' statements, emit IteratorClose
// bytecode inline. 'continue' statements do not call IteratorClose for
// the loop they are continuing.
@@ -2924,7 +2929,7 @@ BytecodeEmitter::emitGoto(NestableControl* target, JumpList* jumplist, SrcNoteTy
Scope*
BytecodeEmitter::innermostScope() const
{
- return innermostEmitterScope->scope(this);
+ return innermostEmitterScope()->scope(this);
}
bool
@@ -3585,7 +3590,7 @@ BytecodeEmitter::needsImplicitThis()
return true;
// Otherwise see if the current point is under a 'with'.
- for (EmitterScope* es = innermostEmitterScope; es; es = es->enclosingInFrame()) {
+ for (EmitterScope* es = innermostEmitterScope(); es; es = es->enclosingInFrame()) {
if (es->scope(this)->kind() == ScopeKind::With)
return true;
}
@@ -5262,7 +5267,7 @@ BytecodeEmitter::emitSetOrInitializeDestructuring(ParseNode* target, Destructuri
// destructuring declaration needs to initialize the name in
// the function scope. The innermost scope is the var scope,
// and its enclosing scope is the function scope.
- EmitterScope* funScope = innermostEmitterScope->enclosingInFrame();
+ EmitterScope* funScope = innermostEmitterScope()->enclosingInFrame();
NameLocation paramLoc = *locationOfNameBoundInScope(name, funScope);
if (!emitSetOrInitializeNameAtLocation(name, paramLoc, emitSwapScopeAndRhs, true))
return false;
@@ -7304,7 +7309,7 @@ BytecodeEmitter::emitForOf(ParseNode* forOfLoop, EmitterScope* headLexicalEmitte
// bindings inducing an environment, recreate the current environment.
DebugOnly<ParseNode*> forOfTarget = forOfHead->pn_kid1;
MOZ_ASSERT(forOfTarget->isKind(PNK_LET) || forOfTarget->isKind(PNK_CONST));
- MOZ_ASSERT(headLexicalEmitterScope == innermostEmitterScope);
+ MOZ_ASSERT(headLexicalEmitterScope == innermostEmitterScope());
MOZ_ASSERT(headLexicalEmitterScope->scope(this)->kind() == ScopeKind::Lexical);
if (headLexicalEmitterScope->hasEnvironment()) {
@@ -7502,7 +7507,7 @@ BytecodeEmitter::emitForIn(ParseNode* forInLoop, EmitterScope* headLexicalEmitte
// it must be the innermost one. If that scope has closed-over
// bindings inducing an environment, recreate the current environment.
MOZ_ASSERT(forInTarget->isKind(PNK_LET) || forInTarget->isKind(PNK_CONST));
- MOZ_ASSERT(headLexicalEmitterScope == innermostEmitterScope);
+ MOZ_ASSERT(headLexicalEmitterScope == innermostEmitterScope());
MOZ_ASSERT(headLexicalEmitterScope->scope(this)->kind() == ScopeKind::Lexical);
if (headLexicalEmitterScope->hasEnvironment()) {
@@ -7635,7 +7640,7 @@ BytecodeEmitter::emitCStyleFor(ParseNode* pn, EmitterScope* headLexicalEmitterSc
// exists for the head, it must be the innermost one. If that scope
// has closed-over bindings inducing an environment, recreate the
// current environment.
- MOZ_ASSERT(headLexicalEmitterScope == innermostEmitterScope);
+ MOZ_ASSERT(headLexicalEmitterScope == innermostEmitterScope());
MOZ_ASSERT(headLexicalEmitterScope->scope(this)->kind() == ScopeKind::Lexical);
if (headLexicalEmitterScope->hasEnvironment()) {
@@ -7683,7 +7688,7 @@ BytecodeEmitter::emitCStyleFor(ParseNode* pn, EmitterScope* headLexicalEmitterSc
// ES 13.7.4.8 step 3.e. The per-iteration freshening.
if (forLoopRequiresFreshening) {
- MOZ_ASSERT(headLexicalEmitterScope == innermostEmitterScope);
+ MOZ_ASSERT(headLexicalEmitterScope == innermostEmitterScope());
MOZ_ASSERT(headLexicalEmitterScope->scope(this)->kind() == ScopeKind::Lexical);
if (headLexicalEmitterScope->hasEnvironment()) {
@@ -10410,7 +10415,7 @@ BytecodeEmitter::emitFunctionFormalParameters(ParseNode* pn)
{
ParseNode* funBody = pn->last();
FunctionBox* funbox = sc->asFunctionBox();
- EmitterScope* funScope = innermostEmitterScope;
+ EmitterScope* funScope = innermostEmitterScope();
bool hasParameterExprs = funbox->hasParameterExprs;
bool hasRest = funbox->hasRest();
diff --git js/src/frontend/BytecodeEmitter.h js/src/frontend/BytecodeEmitter.h
index 039d271e4d965..91826f27bf9fd 100644
--- js/src/frontend/BytecodeEmitter.h
+++ js/src/frontend/BytecodeEmitter.h
@@ -232,9 +232,23 @@ struct MOZ_STACK_CLASS BytecodeEmitter
EmitterScope* varEmitterScope;
NestableControl* innermostNestableControl;
- EmitterScope* innermostEmitterScope;
+ EmitterScope* innermostEmitterScope_;
TDZCheckCache* innermostTDZCheckCache;
+#ifdef DEBUG
+ bool unstableEmitterScope;
+
+ friend class AutoCheckUnstableEmitterScope;
+#endif
+
+ EmitterScope* innermostEmitterScope() const {
+ MOZ_ASSERT(!unstableEmitterScope);
+ return innermostEmitterScopeNoCheck();
+ }
+ EmitterScope* innermostEmitterScopeNoCheck() const {
+ return innermostEmitterScope_;
+ }
+
CGConstList constList; /* constants to be included with the script */
CGObjectList objectList; /* list of emitted objects */
CGScopeList scopeList; /* list of emitted scopes */
@@ -339,7 +353,7 @@ struct MOZ_STACK_CLASS BytecodeEmitter
EmitterScope* source);
mozilla::Maybe<NameLocation> locationOfNameBoundInFunctionScope(JSAtom* name) {
- return locationOfNameBoundInFunctionScope(name, innermostEmitterScope);
+ return locationOfNameBoundInFunctionScope(name, innermostEmitterScope());
}
void setVarEmitterScope(EmitterScope* emitterScope) {
@@ -635,7 +649,7 @@ struct MOZ_STACK_CLASS BytecodeEmitter
MOZ_MUST_USE bool emitToIteratorResult(bool done);
MOZ_MUST_USE bool emitGetDotGeneratorInInnermostScope() {
- return emitGetDotGeneratorInScope(*innermostEmitterScope);
+ return emitGetDotGeneratorInScope(*innermostEmitterScope());
}
MOZ_MUST_USE bool emitGetDotGeneratorInScope(EmitterScope& currentScope);
@@ -644,7 +658,7 @@ struct MOZ_STACK_CLASS BytecodeEmitter
MOZ_MUST_USE bool emitYieldOp(JSOp op);
MOZ_MUST_USE bool emitYieldStar(ParseNode* iter);
MOZ_MUST_USE bool emitAwaitInInnermostScope() {
- return emitAwaitInScope(*innermostEmitterScope);
+ return emitAwaitInScope(*innermostEmitterScope());
}
MOZ_MUST_USE bool emitAwaitInInnermostScope(ParseNode* pn);
MOZ_MUST_USE bool emitAwaitInScope(EmitterScope& currentScope);
@@ -751,7 +765,7 @@ struct MOZ_STACK_CLASS BytecodeEmitter
MOZ_MUST_USE bool emitIteratorCloseInInnermostScope(IteratorKind iterKind = IteratorKind::Sync,
CompletionKind completionKind = CompletionKind::Normal,
bool allowSelfHosted = false) {
- return emitIteratorCloseInScope(*innermostEmitterScope, iterKind, completionKind,
+ return emitIteratorCloseInScope(*innermostEmitterScope(), iterKind, completionKind,
allowSelfHosted);
}
@@ -852,6 +866,31 @@ struct MOZ_STACK_CLASS BytecodeEmitter
MOZ_MUST_USE bool emitSuperElemOp(ParseNode* pn, JSOp op, bool isCall = false);
};
+class MOZ_RAII AutoCheckUnstableEmitterScope {
+#ifdef DEBUG
+ bool prev_;
+ BytecodeEmitter* bce_;
+#endif
+
+ public:
+ AutoCheckUnstableEmitterScope() = delete;
+ explicit AutoCheckUnstableEmitterScope(BytecodeEmitter* bce)
+#ifdef DEBUG
+ : bce_(bce)
+#endif
+ {
+#ifdef DEBUG
+ prev_ = bce_->unstableEmitterScope;
+ bce_->unstableEmitterScope = true;
+#endif
+ }
+ ~AutoCheckUnstableEmitterScope() {
+#ifdef DEBUG
+ bce_->unstableEmitterScope = prev_;
+#endif
+ }
+};
+
} /* namespace frontend */
} /* namespace js */

View 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;
}

View 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");

View 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;
}