mirror of
https://repo.dactyloidae.xyz/Dactyloidae/UXP.git
synced 2026-09-09 17:31:47 +09:00
Merge remote-tracking branch 'origin/tracking' into custom
This commit is contained in:
commit
2cedfc1adf
84 changed files with 1255 additions and 1041 deletions
|
|
@ -50,21 +50,12 @@ struct GCPolicy<mozilla::OwningNonNull<T>>
|
|||
} // namespace JS
|
||||
|
||||
namespace js {
|
||||
template<typename T>
|
||||
struct RootedBase<mozilla::OwningNonNull<T>>
|
||||
template<typename T, typename Wrapper>
|
||||
struct WrappedPtrOperations<mozilla::OwningNonNull<T>, Wrapper>
|
||||
{
|
||||
typedef mozilla::OwningNonNull<T> SmartPtrType;
|
||||
|
||||
operator SmartPtrType& () const
|
||||
{
|
||||
auto& self = *static_cast<const JS::Rooted<SmartPtrType>*>(this);
|
||||
return self.get();
|
||||
}
|
||||
|
||||
operator T& () const
|
||||
{
|
||||
auto& self = *static_cast<const JS::Rooted<SmartPtrType>*>(this);
|
||||
return self.get();
|
||||
return static_cast<const Wrapper*>(this)->get();
|
||||
}
|
||||
};
|
||||
} // namespace js
|
||||
|
|
|
|||
|
|
@ -38,19 +38,12 @@ struct GCPolicy<RefPtr<T>>
|
|||
} // namespace JS
|
||||
|
||||
namespace js {
|
||||
template<typename T>
|
||||
struct RootedBase<RefPtr<T>>
|
||||
template<typename T, typename Wrapper>
|
||||
struct WrappedPtrOperations<RefPtr<T>, Wrapper>
|
||||
{
|
||||
operator RefPtr<T>& () const
|
||||
{
|
||||
auto& self = *static_cast<const JS::Rooted<RefPtr<T>>*>(this);
|
||||
return self.get();
|
||||
}
|
||||
|
||||
operator T*() const
|
||||
{
|
||||
auto& self = *static_cast<const JS::Rooted<RefPtr<T>>*>(this);
|
||||
return self.get();
|
||||
return static_cast<const Wrapper*>(this)->get();
|
||||
}
|
||||
};
|
||||
} // namespace js
|
||||
|
|
|
|||
|
|
@ -639,16 +639,11 @@ DataTransfer::PrincipalMaySetData(const nsAString& aType,
|
|||
return false;
|
||||
}
|
||||
|
||||
if (aType.EqualsASCII(kFileMime) ||
|
||||
aType.EqualsASCII(kFilePromiseMime)) {
|
||||
NS_WARNING("Disallowing adding x-moz-file or x-moz-file-promize types to DataTransfer");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Disallow content from creating x-moz-place flavors, so that it cannot
|
||||
// create fake Places smart queries exposing user data.
|
||||
if (StringBeginsWith(aType, NS_LITERAL_STRING("text/x-moz-place"))) {
|
||||
NS_WARNING("Disallowing adding moz-place types to DataTransfer");
|
||||
// Don't allow adding internal types of the form */x-moz-*, but
|
||||
// special-case the url types as they are simple variations of urls.
|
||||
if (FindInReadable(NS_LITERAL_STRING(kInternal_Mimetype_Prefix), aType) &&
|
||||
!StringBeginsWith(aType, NS_LITERAL_STRING("text/x-moz-url"))) {
|
||||
NS_WARNING("Disallowing adding requested internal type to DataTransfer");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1747,7 +1747,7 @@ NPObjWrapper_ObjectMoved(JSObject *obj, const JSObject *old)
|
|||
auto entry =
|
||||
static_cast<NPObjWrapperHashEntry*>(sNPObjWrappers->Search(npobj));
|
||||
MOZ_ASSERT(entry && entry->mJSObj);
|
||||
MOZ_ASSERT(entry->mJSObj.unbarrieredGetPtr() == old);
|
||||
MOZ_ASSERT(entry->mJSObj == old);
|
||||
entry->mJSObj = obj;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -126,15 +126,15 @@ struct IsHeapConstructibleType<nsXBLMaybeCompiled<T>>
|
|||
static const bool value = true;
|
||||
};
|
||||
|
||||
template <class UncompiledT>
|
||||
class HeapBase<nsXBLMaybeCompiled<UncompiledT>>
|
||||
template <class UncompiledT, class Wrapper>
|
||||
class HeapBase<nsXBLMaybeCompiled<UncompiledT>, Wrapper>
|
||||
{
|
||||
const JS::Heap<nsXBLMaybeCompiled<UncompiledT>>& wrapper() const {
|
||||
return *static_cast<const JS::Heap<nsXBLMaybeCompiled<UncompiledT>>*>(this);
|
||||
const Wrapper& wrapper() const {
|
||||
return *static_cast<const Wrapper*>(this);
|
||||
}
|
||||
|
||||
JS::Heap<nsXBLMaybeCompiled<UncompiledT>>& wrapper() {
|
||||
return *static_cast<JS::Heap<nsXBLMaybeCompiled<UncompiledT>>*>(this);
|
||||
Wrapper& wrapper() {
|
||||
return *static_cast<Wrapper*>(this);
|
||||
}
|
||||
|
||||
const nsXBLMaybeCompiled<UncompiledT>* extract() const {
|
||||
|
|
|
|||
|
|
@ -454,6 +454,7 @@ GLContext::GLContext(CreateContextFlags flags, const SurfaceCaps& caps,
|
|||
mTopError(LOCAL_GL_NO_ERROR),
|
||||
mDebugFlags(ChooseDebugFlags(flags)),
|
||||
mSharedContext(sharedContext),
|
||||
mSymbols{},
|
||||
mCaps(caps),
|
||||
mScreen(nullptr),
|
||||
mLockedSurface(nullptr),
|
||||
|
|
@ -519,7 +520,7 @@ GLContext::InitWithPrefix(const char* prefix, bool trygl)
|
|||
|
||||
if (!InitWithPrefixImpl(prefix, trygl)) {
|
||||
// If initialization fails, zero the symbols to avoid hard-to-understand bugs.
|
||||
mSymbols.Zero();
|
||||
mSymbols = {};
|
||||
NS_WARNING("GLContext::InitWithPrefix failed!");
|
||||
return false;
|
||||
}
|
||||
|
|
@ -2205,7 +2206,7 @@ GLContext::MarkDestroyed()
|
|||
mReadTexImageHelper = nullptr;
|
||||
|
||||
mIsDestroyed = true;
|
||||
mSymbols.Zero();
|
||||
mSymbols = {};
|
||||
if (MakeCurrent(true)) {
|
||||
mTexGarbageBin->GLContextTeardown();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -25,15 +25,9 @@
|
|||
namespace mozilla {
|
||||
namespace gl {
|
||||
|
||||
struct GLContextSymbols
|
||||
struct GLContextSymbols final
|
||||
{
|
||||
GLContextSymbols() {
|
||||
Zero();
|
||||
}
|
||||
|
||||
void Zero() {
|
||||
memset(this, 0, sizeof(GLContextSymbols));
|
||||
}
|
||||
GLContextSymbols() = delete; // Initialize with {}.
|
||||
|
||||
typedef void (GLAPIENTRY * PFNGLACTIVETEXTUREPROC) (GLenum texture);
|
||||
PFNGLACTIVETEXTUREPROC fActiveTexture;
|
||||
|
|
|
|||
|
|
@ -310,6 +310,8 @@ gfxCoreTextShaper::SetGlyphsFromRun(gfxShapedText *aShapedText,
|
|||
CTRunRef aCTRun,
|
||||
int32_t aStringOffset)
|
||||
{
|
||||
typedef gfxShapedText::CompressedGlyph CompressedGlyph;
|
||||
|
||||
// The word has been bidi-wrapped; aStringOffset is the number
|
||||
// of chars at the beginning of the CTLine that we should skip.
|
||||
// aCTRun is a glyph run from the CoreText layout process.
|
||||
|
|
@ -392,8 +394,7 @@ gfxCoreTextShaper::SetGlyphsFromRun(gfxShapedText *aShapedText,
|
|||
nullptr, nullptr, nullptr);
|
||||
|
||||
AutoTArray<gfxShapedText::DetailedGlyph,1> detailedGlyphs;
|
||||
gfxShapedText::CompressedGlyph *charGlyphs =
|
||||
aShapedText->GetCharacterGlyphs() + aOffset;
|
||||
CompressedGlyph* charGlyphs = aShapedText->GetCharacterGlyphs() + aOffset;
|
||||
|
||||
// CoreText gives us the glyphindex-to-charindex mapping, which relates each glyph
|
||||
// to a source text character; we also need the charindex-to-glyphindex mapping to
|
||||
|
|
@ -614,10 +615,10 @@ gfxCoreTextShaper::SetGlyphsFromRun(gfxShapedText *aShapedText,
|
|||
advance = int32_t(toNextGlyph * appUnitsPerDevUnit);
|
||||
}
|
||||
|
||||
gfxTextRun::CompressedGlyph textRunGlyph;
|
||||
textRunGlyph.SetComplex(charGlyphs[baseCharIndex].IsClusterStart(),
|
||||
true, detailedGlyphs.Length());
|
||||
aShapedText->SetGlyphs(aOffset + baseCharIndex, textRunGlyph,
|
||||
bool isClusterStart = charGlyphs[baseCharIndex].IsClusterStart();
|
||||
aShapedText->SetGlyphs(aOffset + baseCharIndex,
|
||||
CompressedGlyph::MakeComplex(isClusterStart, true,
|
||||
detailedGlyphs.Length()),
|
||||
detailedGlyphs.Elements());
|
||||
|
||||
detailedGlyphs.Clear();
|
||||
|
|
@ -625,7 +626,7 @@ gfxCoreTextShaper::SetGlyphsFromRun(gfxShapedText *aShapedText,
|
|||
|
||||
// the rest of the chars in the group are ligature continuations, no associated glyphs
|
||||
while (++baseCharIndex != endCharIndex && baseCharIndex < wordLength) {
|
||||
gfxShapedText::CompressedGlyph &shapedTextGlyph = charGlyphs[baseCharIndex];
|
||||
CompressedGlyph &shapedTextGlyph = charGlyphs[baseCharIndex];
|
||||
NS_ASSERTION(!shapedTextGlyph.IsSimpleGlyph(), "overwriting a simple glyph");
|
||||
shapedTextGlyph.SetComplex(inOrder && shapedTextGlyph.IsClusterStart(), false, 0);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -62,13 +62,14 @@ void
|
|||
gfxFT2Font::AddRange(const char16_t *aText, uint32_t aOffset,
|
||||
uint32_t aLength, gfxShapedText *aShapedText)
|
||||
{
|
||||
typedef gfxShapedText::CompressedGlyph CompressedGlyph;
|
||||
|
||||
const uint32_t appUnitsPerDevUnit = aShapedText->GetAppUnitsPerDevUnit();
|
||||
// we'll pass this in/figure it out dynamically, but at this point there can be only one face.
|
||||
gfxFT2LockedFace faceLock(this);
|
||||
FT_Face face = faceLock.get();
|
||||
|
||||
gfxShapedText::CompressedGlyph *charGlyphs =
|
||||
aShapedText->GetCharacterGlyphs();
|
||||
CompressedGlyph* charGlyphs = aShapedText->GetCharacterGlyphs();
|
||||
|
||||
const gfxFT2Font::CachedGlyphData *cgd = nullptr, *cgdNext = nullptr;
|
||||
|
||||
|
|
@ -135,8 +136,8 @@ gfxFT2Font::AddRange(const char16_t *aText, uint32_t aOffset,
|
|||
}
|
||||
|
||||
if (advance >= 0 &&
|
||||
gfxShapedText::CompressedGlyph::IsSimpleAdvance(advance) &&
|
||||
gfxShapedText::CompressedGlyph::IsSimpleGlyphID(gid)) {
|
||||
CompressedGlyph::IsSimpleAdvance(advance) &&
|
||||
CompressedGlyph::IsSimpleGlyphID(gid)) {
|
||||
charGlyphs[aOffset].SetSimpleGlyph(advance, gid);
|
||||
} else if (gid == 0) {
|
||||
// gid = 0 only happens when the glyph is missing from the font
|
||||
|
|
@ -149,9 +150,11 @@ gfxFT2Font::AddRange(const char16_t *aText, uint32_t aOffset,
|
|||
details.mAdvance = advance;
|
||||
details.mXOffset = 0;
|
||||
details.mYOffset = 0;
|
||||
gfxShapedText::CompressedGlyph g;
|
||||
g.SetComplex(charGlyphs[aOffset].IsClusterStart(), true, 1);
|
||||
aShapedText->SetGlyphs(aOffset, g, &details);
|
||||
bool isClusterStart = charGlyphs[aOffset].IsClusterStart();
|
||||
aShapedText->SetGlyphs(aOffset,
|
||||
CompressedGlyph::MakeComplex(isClusterStart,
|
||||
true, 1),
|
||||
&details);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -639,10 +639,10 @@ gfxShapedText::SetupClusterBoundaries(uint32_t aOffset,
|
|||
const char16_t *aString,
|
||||
uint32_t aLength)
|
||||
{
|
||||
CompressedGlyph *glyphs = GetCharacterGlyphs() + aOffset;
|
||||
CompressedGlyph* glyphs = GetCharacterGlyphs() + aOffset;
|
||||
|
||||
gfxTextRun::CompressedGlyph extendCluster;
|
||||
extendCluster.SetComplex(false, true, 0);
|
||||
CompressedGlyph extendCluster =
|
||||
CompressedGlyph::MakeComplex(false, true, 0);
|
||||
|
||||
ClusterIterator iter(aString, aLength);
|
||||
|
||||
|
|
|
|||
|
|
@ -245,7 +245,7 @@ struct gfxTextRange {
|
|||
|
||||
/**
|
||||
* Font cache design:
|
||||
*
|
||||
*
|
||||
* The mFonts hashtable contains most fonts, indexed by (gfxFontEntry*, style).
|
||||
* It does not add a reference to the fonts it contains.
|
||||
* When a font's refcount decreases to zero, instead of deleting it we
|
||||
|
|
@ -699,21 +699,19 @@ public:
|
|||
* This class records the information associated with a character in the
|
||||
* input string. It's optimized for the case where there is one glyph
|
||||
* representing that character alone.
|
||||
*
|
||||
*
|
||||
* A character can have zero or more associated glyphs. Each glyph
|
||||
* has an advance width and an x and y offset.
|
||||
* A character may be the start of a cluster.
|
||||
* A character may be the start of a ligature group.
|
||||
* A character can be "missing", indicating that the system is unable
|
||||
* to render the character.
|
||||
*
|
||||
*
|
||||
* All characters in a ligature group conceptually share all the glyphs
|
||||
* associated with the characters in a group.
|
||||
*/
|
||||
class CompressedGlyph {
|
||||
public:
|
||||
CompressedGlyph() { mValue = 0; }
|
||||
|
||||
enum {
|
||||
// Indicates that a cluster and ligature group starts at this
|
||||
// character; this character has a single glyph with a reasonable
|
||||
|
|
@ -843,25 +841,52 @@ public:
|
|||
return toggle;
|
||||
}
|
||||
|
||||
CompressedGlyph& SetSimpleGlyph(uint32_t aAdvanceAppUnits, uint32_t aGlyph) {
|
||||
// Create a CompressedGlyph value representing a simple glyph with
|
||||
// no extra flags (line-break or is_space) set.
|
||||
static CompressedGlyph
|
||||
MakeSimpleGlyph(uint32_t aAdvanceAppUnits, uint32_t aGlyph) {
|
||||
NS_ASSERTION(IsSimpleAdvance(aAdvanceAppUnits), "Advance overflow");
|
||||
NS_ASSERTION(IsSimpleGlyphID(aGlyph), "Glyph overflow");
|
||||
CompressedGlyph g;
|
||||
g.mValue = FLAG_IS_SIMPLE_GLYPH |
|
||||
(aAdvanceAppUnits << ADVANCE_SHIFT) |
|
||||
aGlyph;
|
||||
return g;
|
||||
}
|
||||
|
||||
// Assign a simple glyph value to an existing CompressedGlyph record,
|
||||
// preserving line-break/is-space flags if present.
|
||||
CompressedGlyph& SetSimpleGlyph(uint32_t aAdvanceAppUnits,
|
||||
uint32_t aGlyph) {
|
||||
NS_ASSERTION(!CharTypeFlags(), "Char type flags lost");
|
||||
mValue = (mValue & (FLAGS_CAN_BREAK_BEFORE | FLAG_CHAR_IS_SPACE)) |
|
||||
FLAG_IS_SIMPLE_GLYPH |
|
||||
(aAdvanceAppUnits << ADVANCE_SHIFT) | aGlyph;
|
||||
MakeSimpleGlyph(aAdvanceAppUnits, aGlyph).mValue;
|
||||
return *this;
|
||||
}
|
||||
|
||||
// Create a CompressedGlyph value representing a complex glyph record,
|
||||
// without any line-break or char-type flags.
|
||||
static CompressedGlyph
|
||||
MakeComplex(bool aClusterStart, bool aLigatureStart,
|
||||
uint32_t aGlyphCount) {
|
||||
CompressedGlyph g;
|
||||
g.mValue = FLAG_NOT_MISSING |
|
||||
(aClusterStart ? 0 : FLAG_NOT_CLUSTER_START) |
|
||||
(aLigatureStart ? 0 : FLAG_NOT_LIGATURE_GROUP_START) |
|
||||
(aGlyphCount << GLYPH_COUNT_SHIFT);
|
||||
return g;
|
||||
}
|
||||
|
||||
// Assign a complex glyph value to an existing CompressedGlyph record,
|
||||
// preserving line-break/char-type flags if present.
|
||||
CompressedGlyph& SetComplex(bool aClusterStart, bool aLigatureStart,
|
||||
uint32_t aGlyphCount) {
|
||||
uint32_t aGlyphCount) {
|
||||
mValue = (mValue & (FLAGS_CAN_BREAK_BEFORE | FLAG_CHAR_IS_SPACE)) |
|
||||
FLAG_NOT_MISSING |
|
||||
CharTypeFlags() |
|
||||
(aClusterStart ? 0 : FLAG_NOT_CLUSTER_START) |
|
||||
(aLigatureStart ? 0 : FLAG_NOT_LIGATURE_GROUP_START) |
|
||||
(aGlyphCount << GLYPH_COUNT_SHIFT);
|
||||
MakeComplex(aClusterStart, aLigatureStart, aGlyphCount).mValue;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Missing glyphs are treated as ligature group starts; don't mess with
|
||||
* the cluster-start flag (see bugs 618870 and 619286).
|
||||
|
|
@ -914,7 +939,7 @@ public:
|
|||
/** The advance, x-offset and y-offset of the glyph, in appunits
|
||||
* mAdvance is in the text direction (RTL or LTR)
|
||||
* mXOffset is always from left to right
|
||||
* mYOffset is always from top to bottom */
|
||||
* mYOffset is always from top to bottom */
|
||||
int32_t mAdvance;
|
||||
float mXOffset, mYOffset;
|
||||
};
|
||||
|
|
@ -1039,7 +1064,7 @@ protected:
|
|||
|
||||
// For characters whose glyph data does not fit the "simple" glyph criteria
|
||||
// in CompressedGlyph, we use a sorted array to store the association
|
||||
// between the source character offset and an index into an array
|
||||
// between the source character offset and an index into an array
|
||||
// DetailedGlyphs. The CompressedGlyph record includes a count of
|
||||
// the number of DetailedGlyph records that belong to the character,
|
||||
// starting at the given index.
|
||||
|
|
@ -1581,11 +1606,11 @@ public:
|
|||
// (offset1, length1) plus the advance width of (offset1 + length1,
|
||||
// length2) should be the advance width of (offset1, length1 + length2)
|
||||
gfxFloat mAdvanceWidth;
|
||||
|
||||
|
||||
// For zero-width substrings, these must be zero!
|
||||
gfxFloat mAscent; // always non-negative
|
||||
gfxFloat mDescent; // always non-negative
|
||||
|
||||
|
||||
// Bounding box that is guaranteed to include everything drawn.
|
||||
// If a tight boundingBox was requested when these metrics were
|
||||
// generated, this will tightly wrap the glyphs, otherwise it is
|
||||
|
|
@ -1648,11 +1673,11 @@ public:
|
|||
* @param aSpacing spacing to insert before and after glyphs. The bounding box
|
||||
* need not include the spacing itself, but the spacing affects the glyph
|
||||
* positions. null if there is no spacing.
|
||||
*
|
||||
*
|
||||
* Callers guarantee:
|
||||
* -- aStart and aEnd are aligned to cluster and ligature boundaries
|
||||
* -- all glyphs use this font
|
||||
*
|
||||
*
|
||||
* The default implementation just uses font metrics and aTextRun's
|
||||
* advances, and assumes no characters fall outside the font box. In
|
||||
* general this is insufficient, because that assumption is not always true.
|
||||
|
|
@ -1707,7 +1732,7 @@ public:
|
|||
(mUnicodeRangeMap && !mUnicodeRangeMap->test(ch))) {
|
||||
return false;
|
||||
}
|
||||
return mFontEntry->HasCharacter(ch);
|
||||
return mFontEntry->HasCharacter(ch);
|
||||
}
|
||||
|
||||
const gfxCharacterMap* GetUnicodeRangeMap() const {
|
||||
|
|
@ -1722,7 +1747,7 @@ public:
|
|||
if (!mIsValid) {
|
||||
return 0;
|
||||
}
|
||||
return mFontEntry->GetUVSGlyph(aCh, aVS);
|
||||
return mFontEntry->GetUVSGlyph(aCh, aVS);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
|
|
|
|||
|
|
@ -215,6 +215,8 @@ gfxGraphiteShaper::SetGlyphsFromSegment(DrawTarget *aDrawTarget,
|
|||
const char16_t *aText,
|
||||
gr_segment *aSegment)
|
||||
{
|
||||
typedef gfxShapedText::CompressedGlyph CompressedGlyph;
|
||||
|
||||
int32_t dev2appUnits = aShapedText->GetAppUnitsPerDevUnit();
|
||||
bool rtl = aShapedText->IsRightToLeft();
|
||||
|
||||
|
|
@ -291,8 +293,7 @@ gfxGraphiteShaper::SetGlyphsFromSegment(DrawTarget *aDrawTarget,
|
|||
bool roundX, roundY;
|
||||
GetRoundOffsetsToPixels(aDrawTarget, &roundX, &roundY);
|
||||
|
||||
gfxShapedText::CompressedGlyph *charGlyphs =
|
||||
aShapedText->GetCharacterGlyphs() + aOffset;
|
||||
CompressedGlyph* charGlyphs = aShapedText->GetCharacterGlyphs() + aOffset;
|
||||
|
||||
// now put glyphs into the textrun, one cluster at a time
|
||||
for (uint32_t i = 0; i <= cIndex; ++i) {
|
||||
|
|
@ -325,8 +326,8 @@ gfxGraphiteShaper::SetGlyphsFromSegment(DrawTarget *aDrawTarget,
|
|||
uint32_t appAdvance = roundX ? NSToIntRound(adv) * dev2appUnits :
|
||||
NSToIntRound(adv * dev2appUnits);
|
||||
if (c.nGlyphs == 1 &&
|
||||
gfxShapedText::CompressedGlyph::IsSimpleGlyphID(gids[c.baseGlyph]) &&
|
||||
gfxShapedText::CompressedGlyph::IsSimpleAdvance(appAdvance) &&
|
||||
CompressedGlyph::IsSimpleGlyphID(gids[c.baseGlyph]) &&
|
||||
CompressedGlyph::IsSimpleAdvance(appAdvance) &&
|
||||
charGlyphs[offs].IsClusterStart() &&
|
||||
yLocs[c.baseGlyph] == 0)
|
||||
{
|
||||
|
|
@ -352,15 +353,17 @@ gfxGraphiteShaper::SetGlyphsFromSegment(DrawTarget *aDrawTarget,
|
|||
d->mAdvance = 0;
|
||||
}
|
||||
}
|
||||
gfxShapedText::CompressedGlyph g;
|
||||
g.SetComplex(charGlyphs[offs].IsClusterStart(),
|
||||
true, details.Length());
|
||||
aShapedText->SetGlyphs(aOffset + offs, g, details.Elements());
|
||||
bool isClusterStart = charGlyphs[offs].IsClusterStart();
|
||||
aShapedText->SetGlyphs(aOffset + offs,
|
||||
CompressedGlyph::MakeComplex(isClusterStart,
|
||||
true,
|
||||
details.Length()),
|
||||
details.Elements());
|
||||
}
|
||||
|
||||
for (uint32_t j = c.baseChar + 1; j < c.baseChar + c.nChars; ++j) {
|
||||
NS_ASSERTION(j < aLength, "unexpected offset");
|
||||
gfxShapedText::CompressedGlyph &g = charGlyphs[j];
|
||||
CompressedGlyph &g = charGlyphs[j];
|
||||
NS_ASSERTION(!g.IsSimpleGlyph(), "overwriting a simple glyph");
|
||||
g.SetComplex(g.IsClusterStart(), false, 0);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -817,7 +817,7 @@ GetKernValueVersion1Fmt3(const void* aSubtable,
|
|||
hdr->leftClassCount * hdr->rightClassCount > aSubtableLen) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
if (aFirstGlyph >= glyphCount || aSecondGlyph >= glyphCount) {
|
||||
// glyphs are out of range for the class tables
|
||||
return 0;
|
||||
|
|
@ -1503,6 +1503,8 @@ gfxHarfBuzzShaper::SetGlyphsFromRun(DrawTarget *aDrawTarget,
|
|||
hb_buffer_t *aBuffer,
|
||||
bool aVertical)
|
||||
{
|
||||
typedef gfxShapedText::CompressedGlyph CompressedGlyph;
|
||||
|
||||
uint32_t numGlyphs;
|
||||
const hb_glyph_info_t *ginfo = hb_buffer_get_glyph_infos(aBuffer, &numGlyphs);
|
||||
if (numGlyphs == 0) {
|
||||
|
|
@ -1541,8 +1543,7 @@ gfxHarfBuzzShaper::SetGlyphsFromRun(DrawTarget *aDrawTarget,
|
|||
}
|
||||
|
||||
int32_t appUnitsPerDevUnit = aShapedText->GetAppUnitsPerDevUnit();
|
||||
gfxShapedText::CompressedGlyph *charGlyphs =
|
||||
aShapedText->GetCharacterGlyphs() + aOffset;
|
||||
CompressedGlyph* charGlyphs = aShapedText->GetCharacterGlyphs() + aOffset;
|
||||
|
||||
// factor to convert 16.16 fixed-point pixels to app units
|
||||
// (only used if not rounding)
|
||||
|
|
@ -1688,8 +1689,8 @@ gfxHarfBuzzShaper::SetGlyphsFromRun(DrawTarget *aDrawTarget,
|
|||
}
|
||||
// Check if it's a simple one-to-one mapping
|
||||
if (glyphsInClump == 1 &&
|
||||
gfxTextRun::CompressedGlyph::IsSimpleGlyphID(ginfo[glyphStart].codepoint) &&
|
||||
gfxTextRun::CompressedGlyph::IsSimpleAdvance(advance) &&
|
||||
CompressedGlyph::IsSimpleGlyphID(ginfo[glyphStart].codepoint) &&
|
||||
CompressedGlyph::IsSimpleAdvance(advance) &&
|
||||
charGlyphs[baseCharIndex].IsClusterStart() &&
|
||||
iOffset == 0 && b_offset == 0 &&
|
||||
b_advance == 0 && bPos == 0)
|
||||
|
|
@ -1760,11 +1761,12 @@ gfxHarfBuzzShaper::SetGlyphsFromRun(DrawTarget *aDrawTarget,
|
|||
}
|
||||
}
|
||||
|
||||
gfxShapedText::CompressedGlyph g;
|
||||
g.SetComplex(charGlyphs[baseCharIndex].IsClusterStart(),
|
||||
true, detailedGlyphs.Length());
|
||||
bool isClusterStart = charGlyphs[baseCharIndex].IsClusterStart();
|
||||
aShapedText->SetGlyphs(aOffset + baseCharIndex,
|
||||
g, detailedGlyphs.Elements());
|
||||
CompressedGlyph::MakeComplex(isClusterStart,
|
||||
true,
|
||||
detailedGlyphs.Length()),
|
||||
detailedGlyphs.Elements());
|
||||
|
||||
detailedGlyphs.Clear();
|
||||
}
|
||||
|
|
@ -1773,7 +1775,7 @@ gfxHarfBuzzShaper::SetGlyphsFromRun(DrawTarget *aDrawTarget,
|
|||
// no associated glyphs
|
||||
while (++baseCharIndex != endCharIndex &&
|
||||
baseCharIndex < int32_t(wordLength)) {
|
||||
gfxShapedText::CompressedGlyph &g = charGlyphs[baseCharIndex];
|
||||
CompressedGlyph &g = charGlyphs[baseCharIndex];
|
||||
NS_ASSERTION(!g.IsSimpleGlyph(), "overwriting a simple glyph");
|
||||
g.SetComplex(g.IsClusterStart(), false, 0);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -244,7 +244,7 @@ gfxTextRun::ComputeLigatureData(Range aPartRange,
|
|||
NS_ASSERTION(aPartRange.start < aPartRange.end,
|
||||
"Computing ligature data for empty range");
|
||||
NS_ASSERTION(aPartRange.end <= GetLength(), "Character length overflow");
|
||||
|
||||
|
||||
LigatureData result;
|
||||
const CompressedGlyph *charGlyphs = mCharacterGlyphs;
|
||||
|
||||
|
|
@ -392,7 +392,7 @@ gfxTextRun::ShrinkToLigatureBoundaries(Range* aRange) const
|
|||
{
|
||||
if (aRange->start >= aRange->end)
|
||||
return;
|
||||
|
||||
|
||||
const CompressedGlyph *charGlyphs = mCharacterGlyphs;
|
||||
|
||||
while (aRange->start < aRange->end &&
|
||||
|
|
@ -440,7 +440,7 @@ ClipPartialLigature(const gfxTextRun* aTextRun,
|
|||
} else {
|
||||
*aEnd = std::min(*aEnd, endEdge);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -789,7 +789,7 @@ gfxTextRun::AccumulatePartialLigatureMetrics(gfxFont *aFont, Range aRange,
|
|||
// ligature. Shift it left.
|
||||
metrics.mBoundingBox.x -=
|
||||
IsRightToLeft() ? metrics.mAdvanceWidth - (data.mPartAdvance + data.mPartWidth)
|
||||
: data.mPartAdvance;
|
||||
: data.mPartAdvance;
|
||||
metrics.mAdvanceWidth = data.mPartWidth;
|
||||
|
||||
aMetrics->CombineWith(metrics, IsRightToLeft());
|
||||
|
|
@ -905,7 +905,7 @@ gfxTextRun::BreakAndMeasureText(uint32_t aStart, uint32_t aMaxLength,
|
|||
}
|
||||
|
||||
// There can't be a word-wrap break opportunity at the beginning of the
|
||||
// line: if the width is too small for even one character to fit, it
|
||||
// line: if the width is too small for even one character to fit, it
|
||||
// could be the first and last break opportunity on the line, and that
|
||||
// would trigger an infinite loop.
|
||||
if (aSuppressBreak != eSuppressAllBreaks &&
|
||||
|
|
@ -923,7 +923,7 @@ gfxTextRun::BreakAndMeasureText(uint32_t aStart, uint32_t aMaxLength,
|
|||
if (atHyphenationBreak) {
|
||||
hyphenatedAdvance += aProvider->GetHyphenWidth();
|
||||
}
|
||||
|
||||
|
||||
if (lastBreak < 0 || width + hyphenatedAdvance - trimmableAdvance <= aWidth) {
|
||||
// We can break here.
|
||||
lastBreak = i;
|
||||
|
|
@ -943,7 +943,7 @@ gfxTextRun::BreakAndMeasureText(uint32_t aStart, uint32_t aMaxLength,
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
gfxFloat charAdvance;
|
||||
if (i >= ligatureRange.start && i < ligatureRange.end) {
|
||||
charAdvance = GetAdvanceForGlyphs(Range(i, i + 1));
|
||||
|
|
@ -956,7 +956,7 @@ gfxTextRun::BreakAndMeasureText(uint32_t aStart, uint32_t aMaxLength,
|
|||
charAdvance =
|
||||
ComputePartialLigatureWidth(Range(i, i + 1), aProvider);
|
||||
}
|
||||
|
||||
|
||||
advance += charAdvance;
|
||||
if (aTrimWhitespace || aWhitespaceCanHang) {
|
||||
if (mCharacterGlyphs[i].CharIsSpace()) {
|
||||
|
|
@ -1145,7 +1145,7 @@ gfxTextRun::AddGlyphRun(gfxFont *aFont, uint8_t aMatchType,
|
|||
"mixed orientation should have been resolved");
|
||||
if (!aFont) {
|
||||
return NS_OK;
|
||||
}
|
||||
}
|
||||
uint32_t numGlyphRuns = mGlyphRuns.Length();
|
||||
if (!aForceNewRun && numGlyphRuns > 0) {
|
||||
GlyphRun *lastGlyphRun = &mGlyphRuns[numGlyphRuns - 1];
|
||||
|
|
@ -1405,7 +1405,7 @@ gfxTextRun::SetSpaceGlyph(gfxFont* aFont, DrawTarget* aDrawTarget,
|
|||
(GetFlags() & gfxTextRunFactory::TEXT_ORIENT_VERTICAL_UPRIGHT) != 0;
|
||||
gfxShapedWord* sw = aFont->GetShapedWord(aDrawTarget,
|
||||
&space, 1,
|
||||
gfxShapedWord::HashMix(0, ' '),
|
||||
gfxShapedWord::HashMix(0, ' '),
|
||||
Script::LATIN,
|
||||
vertical,
|
||||
mAppUnitsPerDevUnit,
|
||||
|
|
@ -1439,8 +1439,8 @@ gfxTextRun::SetSpaceGlyphIfSimple(gfxFont* aFont, uint32_t aCharIndex,
|
|||
|
||||
AddGlyphRun(aFont, gfxTextRange::kFontGroup, aCharIndex, false,
|
||||
aOrientation);
|
||||
CompressedGlyph g;
|
||||
g.SetSimpleGlyph(spaceWidthAppUnits, spaceGlyph);
|
||||
CompressedGlyph g =
|
||||
CompressedGlyph::MakeSimpleGlyph(spaceWidthAppUnits, spaceGlyph);
|
||||
if (aSpaceChar == ' ') {
|
||||
g.SetIsSpace();
|
||||
}
|
||||
|
|
@ -1471,7 +1471,7 @@ gfxTextRun::FetchGlyphExtents(DrawTarget* aRefDrawTarget)
|
|||
bool fontIsSetup = false;
|
||||
uint32_t j;
|
||||
gfxGlyphExtents *extents = font->GetOrCreateGlyphExtents(mAppUnitsPerDevUnit);
|
||||
|
||||
|
||||
for (j = start; j < end; ++j) {
|
||||
const gfxTextRun::CompressedGlyph *glyphData = &charGlyphs[j];
|
||||
if (glyphData->IsSimpleGlyph()) {
|
||||
|
|
@ -1943,13 +1943,13 @@ gfxFontGroup::Copy(const gfxFontStyle *aStyle)
|
|||
return fg;
|
||||
}
|
||||
|
||||
bool
|
||||
bool
|
||||
gfxFontGroup::IsInvalidChar(uint8_t ch)
|
||||
{
|
||||
return ((ch & 0x7f) < 0x20 || ch == 0x7f);
|
||||
}
|
||||
|
||||
bool
|
||||
bool
|
||||
gfxFontGroup::IsInvalidChar(char16_t ch)
|
||||
{
|
||||
// All printable 7-bit ASCII values are OK
|
||||
|
|
@ -2514,8 +2514,8 @@ gfxFontGroup::InitScriptRun(DrawTarget* aDrawTarget,
|
|||
detailedGlyph.mGlyphID = mainFont->GetSpaceGlyph();
|
||||
detailedGlyph.mAdvance = advance;
|
||||
detailedGlyph.mXOffset = detailedGlyph.mYOffset = 0;
|
||||
gfxShapedText::CompressedGlyph g;
|
||||
g.SetComplex(true, true, 1);
|
||||
CompressedGlyph g =
|
||||
CompressedGlyph::MakeComplex(true, true, 1);
|
||||
aTextRun->SetGlyphs(aOffset + index,
|
||||
g, &detailedGlyph);
|
||||
}
|
||||
|
|
@ -3128,7 +3128,7 @@ gfxFontGroup::WhichPrefFontSupportsChar(uint32_t aCh, uint32_t aNextCh)
|
|||
uint32_t unicodeRange = FindCharUnicodeRange(aCh);
|
||||
charLang = pfl->GetFontPrefLangFor(unicodeRange);
|
||||
}
|
||||
|
||||
|
||||
// if the last pref font was the first family in the pref list, no need to recheck through a list of families
|
||||
if (mLastPrefFont && charLang == mLastPrefLang &&
|
||||
mLastPrefFirstFont && mLastPrefFont->HasCharacter(aCh)) {
|
||||
|
|
@ -3190,7 +3190,7 @@ already_AddRefed<gfxFont>
|
|||
gfxFontGroup::WhichSystemFontSupportsChar(uint32_t aCh, uint32_t aNextCh,
|
||||
Script aRunScript)
|
||||
{
|
||||
gfxFontEntry *fe =
|
||||
gfxFontEntry *fe =
|
||||
gfxPlatformFontList::PlatformFontList()->
|
||||
SystemFindFontForChar(aCh, aNextCh, aRunScript, &mStyle);
|
||||
if (fe) {
|
||||
|
|
|
|||
|
|
@ -70,7 +70,7 @@ struct gfxTextRunDrawCallbacks {
|
|||
* of text. It stores runs of positioned glyph data, each run having a single
|
||||
* gfxFont. The glyphs are associated with a string of source text, and the
|
||||
* gfxTextRun APIs take parameters that are offsets into that source text.
|
||||
*
|
||||
*
|
||||
* gfxTextRuns are mostly immutable. The only things that can change are
|
||||
* inter-cluster spacing and line break placement. Spacing is always obtained
|
||||
* lazily by methods that need it, it is not cached. Line breaks are stored
|
||||
|
|
@ -78,7 +78,7 @@ struct gfxTextRunDrawCallbacks {
|
|||
* not actually do anything to explicitly account for line breaks). Initially
|
||||
* there are no line breaks. The textrun can record line breaks before or after
|
||||
* any given cluster. (Line breaks specified inside clusters are ignored.)
|
||||
*
|
||||
*
|
||||
* It is important that zero-length substrings are handled correctly. This will
|
||||
* be on the test!
|
||||
*/
|
||||
|
|
@ -163,11 +163,11 @@ public:
|
|||
* Set the potential linebreaks for a substring of the textrun. These are
|
||||
* the "allow break before" points. Initially, there are no potential
|
||||
* linebreaks.
|
||||
*
|
||||
*
|
||||
* This can change glyphs and/or geometry! Some textruns' shapes
|
||||
* depend on potential line breaks (e.g., title-case-converting textruns).
|
||||
* This function is virtual so that those textruns can reshape themselves.
|
||||
*
|
||||
*
|
||||
* @return true if this changed the linebreaks, false if the new line
|
||||
* breaks are the same as the old
|
||||
*/
|
||||
|
|
@ -179,7 +179,7 @@ public:
|
|||
* potential line break points and computation of spacing. We pass the data
|
||||
* this way to allow lazy data acquisition; for example BreakAndMeasureText
|
||||
* will want to only ask for properties of text it's actually looking at.
|
||||
*
|
||||
*
|
||||
* NOTE that requested spacing may not actually be applied, if the textrun
|
||||
* is unable to apply it in some context. Exception: spacing around a
|
||||
* whitespace character MUST always be applied.
|
||||
|
|
@ -238,7 +238,7 @@ public:
|
|||
* Draws a substring. Uses only GetSpacing from aBreakProvider.
|
||||
* The provided point is the baseline origin on the left of the string
|
||||
* for LTR, on the right of the string for RTL.
|
||||
*
|
||||
*
|
||||
* Drawing should respect advance widths in the sense that for LTR runs,
|
||||
* Draw(Range(start, middle), pt, ...) followed by
|
||||
* Draw(Range(middle, end), gfxPoint(pt.x + advance, pt.y), ...)
|
||||
|
|
@ -250,7 +250,7 @@ public:
|
|||
* Draw(Range(start, middle), gfxPoint(pt.x + advance, pt.y), ...)
|
||||
* should have the same effect as
|
||||
* Draw(Range(start, end), pt, ...)
|
||||
*
|
||||
*
|
||||
* Glyphs should be drawn in logical content order, which can be significant
|
||||
* if they overlap (perhaps due to negative spacing).
|
||||
*/
|
||||
|
|
@ -307,14 +307,14 @@ public:
|
|||
* Clear all stored line breaks for the given range (both before and after),
|
||||
* and then set the line-break state before aRange.start to aBreakBefore and
|
||||
* after the last cluster to aBreakAfter.
|
||||
*
|
||||
*
|
||||
* We require that before and after line breaks be consistent. For clusters
|
||||
* i and i+1, we require that if there is a break after cluster i, a break
|
||||
* will be specified before cluster i+1. This may be temporarily violated
|
||||
* (e.g. after reflowing line L and before reflowing line L+1); to handle
|
||||
* these temporary violations, we say that there is a break betwen i and i+1
|
||||
* if a break is specified after i OR a break is specified before i+1.
|
||||
*
|
||||
*
|
||||
* This can change textrun geometry! The existence of a linebreak can affect
|
||||
* the advance width of the cluster before the break (when kerning) or the
|
||||
* geometry of one cluster before the break or any number of clusters
|
||||
|
|
@ -322,11 +322,11 @@ public:
|
|||
* arbitrary; if some scripts require breaking it, then we need to
|
||||
* alter nsTextFrame::TrimTrailingWhitespace, perhaps drastically becase
|
||||
* it could affect the layout of frames before it...)
|
||||
*
|
||||
*
|
||||
* We return true if glyphs or geometry changed, false otherwise. This
|
||||
* function is virtual so that gfxTextRun subclasses can reshape
|
||||
* properly.
|
||||
*
|
||||
*
|
||||
* @param aAdvanceWidthDelta if non-null, returns the change in advance
|
||||
* width of the given range.
|
||||
*/
|
||||
|
|
@ -393,7 +393,7 @@ public:
|
|||
* @param aBreakPriority in/out the priority of the break opportunity
|
||||
* saved in the line. If we are prioritizing break opportunities, we will
|
||||
* not set a break with a lower priority. @see gfxBreakPriority.
|
||||
*
|
||||
*
|
||||
* Note that negative advance widths are possible especially if negative
|
||||
* spacing is provided.
|
||||
*/
|
||||
|
|
@ -596,11 +596,11 @@ public:
|
|||
// when the part is at the start of the ligature, and after-spacing
|
||||
// when the part is as the end of the ligature
|
||||
gfxFloat mPartWidth;
|
||||
|
||||
|
||||
bool mClipBeforePart;
|
||||
bool mClipAfterPart;
|
||||
};
|
||||
|
||||
|
||||
// return storage used by this run, for memory reporter;
|
||||
// nsTransformedTextRun needs to override this as it holds additional data
|
||||
virtual size_t SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf)
|
||||
|
|
@ -681,7 +681,7 @@ protected:
|
|||
CompressedGlyph *mCharacterGlyphs;
|
||||
|
||||
private:
|
||||
// **** general helpers ****
|
||||
// **** general helpers ****
|
||||
|
||||
// Get the total advance for a range of glyphs.
|
||||
int32_t GetAdvanceForGlyphs(Range aRange) const;
|
||||
|
|
@ -765,6 +765,7 @@ private:
|
|||
class gfxFontGroup : public gfxTextRunFactory {
|
||||
public:
|
||||
typedef mozilla::unicode::Script Script;
|
||||
typedef gfxShapedText::CompressedGlyph CompressedGlyph;
|
||||
|
||||
static void Shutdown(); // platform must call this to release the languageAtomService
|
||||
|
||||
|
|
|
|||
|
|
@ -123,7 +123,7 @@ AllowedImageSize(int32_t aWidth, int32_t aHeight)
|
|||
return false;
|
||||
}
|
||||
|
||||
// check to make sure we don't overflow a 32-bit
|
||||
// check to make sure we don't overflow 32-bit size for RGBA
|
||||
CheckedInt32 requiredBytes = CheckedInt32(aWidth) * CheckedInt32(aHeight) * 4;
|
||||
if (MOZ_UNLIKELY(!requiredBytes.isValid())) {
|
||||
NS_WARNING("width or height too large");
|
||||
|
|
|
|||
|
|
@ -100,7 +100,7 @@ IdToObjectMap::has(const ObjectId& id, const JSObject* obj) const
|
|||
auto p = table_.lookup(id);
|
||||
if (!p)
|
||||
return false;
|
||||
return p->value().unbarrieredGet() == obj;
|
||||
return p->value() == obj;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
|
|||
|
|
@ -271,8 +271,119 @@ class ObjectOpResult
|
|||
}
|
||||
};
|
||||
|
||||
class PropertyResult
|
||||
{
|
||||
union {
|
||||
js::Shape* shape_;
|
||||
uintptr_t bits_;
|
||||
};
|
||||
|
||||
static const uintptr_t NotFound = 0;
|
||||
static const uintptr_t NonNativeProperty = 1;
|
||||
static const uintptr_t DenseOrTypedArrayElement = 1;
|
||||
|
||||
public:
|
||||
PropertyResult() : bits_(NotFound) {}
|
||||
|
||||
explicit PropertyResult(js::Shape* propertyShape)
|
||||
: shape_(propertyShape)
|
||||
{
|
||||
MOZ_ASSERT(!isFound() || isNativeProperty());
|
||||
}
|
||||
|
||||
explicit operator bool() const {
|
||||
return isFound();
|
||||
}
|
||||
|
||||
bool isFound() const {
|
||||
return bits_ != NotFound;
|
||||
}
|
||||
|
||||
bool isNonNativeProperty() const {
|
||||
return bits_ == NonNativeProperty;
|
||||
}
|
||||
|
||||
bool isDenseOrTypedArrayElement() const {
|
||||
return bits_ == DenseOrTypedArrayElement;
|
||||
}
|
||||
|
||||
bool isNativeProperty() const {
|
||||
return isFound() && !isNonNativeProperty();
|
||||
}
|
||||
|
||||
js::Shape* maybeShape() const {
|
||||
MOZ_ASSERT(!isNonNativeProperty());
|
||||
return isFound() ? shape_ : nullptr;
|
||||
}
|
||||
|
||||
js::Shape* shape() const {
|
||||
MOZ_ASSERT(isNativeProperty());
|
||||
return shape_;
|
||||
}
|
||||
|
||||
void setNotFound() {
|
||||
bits_ = NotFound;
|
||||
}
|
||||
|
||||
void setNativeProperty(js::Shape* propertyShape) {
|
||||
shape_ = propertyShape;
|
||||
MOZ_ASSERT(isNativeProperty());
|
||||
}
|
||||
|
||||
void setNonNativeProperty() {
|
||||
bits_ = NonNativeProperty;
|
||||
}
|
||||
|
||||
void setDenseOrTypedArrayElement() {
|
||||
bits_ = DenseOrTypedArrayElement;
|
||||
}
|
||||
|
||||
void trace(JSTracer* trc);
|
||||
};
|
||||
|
||||
} // namespace JS
|
||||
|
||||
namespace js {
|
||||
|
||||
template <class Wrapper>
|
||||
class WrappedPtrOperations<JS::PropertyResult, Wrapper>
|
||||
{
|
||||
const JS::PropertyResult& value() const { return static_cast<const Wrapper*>(this)->get(); }
|
||||
|
||||
public:
|
||||
bool isFound() const { return value().isFound(); }
|
||||
explicit operator bool() const { return bool(value()); }
|
||||
js::Shape* maybeShape() const { return value().maybeShape(); }
|
||||
js::Shape* shape() const { return value().shape(); }
|
||||
bool isNativeProperty() const { return value().isNativeProperty(); }
|
||||
bool isNonNativeProperty() const { return value().isNonNativeProperty(); }
|
||||
bool isDenseOrTypedArrayElement() const { return value().isDenseOrTypedArrayElement(); }
|
||||
js::Shape* asTaggedShape() const { return value().asTaggedShape(); }
|
||||
};
|
||||
|
||||
template <class Wrapper>
|
||||
class MutableWrappedPtrOperations<JS::PropertyResult, Wrapper>
|
||||
: public WrappedPtrOperations<JS::PropertyResult, Wrapper>
|
||||
{
|
||||
JS::PropertyResult& value() { return static_cast<Wrapper*>(this)->get(); }
|
||||
|
||||
public:
|
||||
void setNotFound() {
|
||||
value().setNotFound();
|
||||
}
|
||||
void setNativeProperty(js::Shape* shape) {
|
||||
value().setNativeProperty(shape);
|
||||
}
|
||||
void setNonNativeProperty() {
|
||||
value().setNonNativeProperty();
|
||||
}
|
||||
void setDenseOrTypedArrayElement() {
|
||||
value().setDenseOrTypedArrayElement();
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace js
|
||||
|
||||
// JSClass operation signatures.
|
||||
|
||||
/**
|
||||
|
|
@ -428,7 +539,7 @@ namespace js {
|
|||
|
||||
typedef bool
|
||||
(* LookupPropertyOp)(JSContext* cx, JS::HandleObject obj, JS::HandleId id,
|
||||
JS::MutableHandleObject objp, JS::MutableHandle<Shape*> propp);
|
||||
JS::MutableHandleObject objp, JS::MutableHandle<JS::PropertyResult> propp);
|
||||
typedef bool
|
||||
(* DefinePropertyOp)(JSContext* cx, JS::HandleObject obj, JS::HandleId id,
|
||||
JS::Handle<JS::PropertyDescriptor> desc,
|
||||
|
|
|
|||
|
|
@ -133,13 +133,13 @@ class GCRekeyableHashMap : public JS::GCHashMap<Key, Value, HashPolicy, AllocPol
|
|||
}
|
||||
};
|
||||
|
||||
template <typename Outer, typename... Args>
|
||||
class GCHashMapOperations
|
||||
template <typename Wrapper, typename... Args>
|
||||
class WrappedPtrOperations<JS::GCHashMap<Args...>, Wrapper>
|
||||
{
|
||||
using Map = JS::GCHashMap<Args...>;
|
||||
using Lookup = typename Map::Lookup;
|
||||
|
||||
const Map& map() const { return static_cast<const Outer*>(this)->get(); }
|
||||
const Map& map() const { return static_cast<const Wrapper*>(this)->get(); }
|
||||
|
||||
public:
|
||||
using AddPtr = typename Map::AddPtr;
|
||||
|
|
@ -162,18 +162,18 @@ class GCHashMapOperations
|
|||
}
|
||||
};
|
||||
|
||||
template <typename Outer, typename... Args>
|
||||
class MutableGCHashMapOperations
|
||||
: public GCHashMapOperations<Outer, Args...>
|
||||
template <typename Wrapper, typename... Args>
|
||||
class MutableWrappedPtrOperations<JS::GCHashMap<Args...>, Wrapper>
|
||||
: public WrappedPtrOperations<JS::GCHashMap<Args...>, Wrapper>
|
||||
{
|
||||
using Map = JS::GCHashMap<Args...>;
|
||||
using Lookup = typename Map::Lookup;
|
||||
|
||||
Map& map() { return static_cast<Outer*>(this)->get(); }
|
||||
Map& map() { return static_cast<Wrapper*>(this)->get(); }
|
||||
|
||||
public:
|
||||
using AddPtr = typename Map::AddPtr;
|
||||
struct Enum : public Map::Enum { explicit Enum(Outer& o) : Map::Enum(o.map()) {} };
|
||||
struct Enum : public Map::Enum { explicit Enum(Wrapper& o) : Map::Enum(o.map()) {} };
|
||||
using Ptr = typename Map::Ptr;
|
||||
using Range = typename Map::Range;
|
||||
|
||||
|
|
@ -210,26 +210,6 @@ class MutableGCHashMapOperations
|
|||
}
|
||||
};
|
||||
|
||||
template <typename A, typename B, typename C, typename D, typename E>
|
||||
class RootedBase<JS::GCHashMap<A,B,C,D,E>>
|
||||
: public MutableGCHashMapOperations<JS::Rooted<JS::GCHashMap<A,B,C,D,E>>, A,B,C,D,E>
|
||||
{};
|
||||
|
||||
template <typename A, typename B, typename C, typename D, typename E>
|
||||
class MutableHandleBase<JS::GCHashMap<A,B,C,D,E>>
|
||||
: public MutableGCHashMapOperations<JS::MutableHandle<JS::GCHashMap<A,B,C,D,E>>, A,B,C,D,E>
|
||||
{};
|
||||
|
||||
template <typename A, typename B, typename C, typename D, typename E>
|
||||
class HandleBase<JS::GCHashMap<A,B,C,D,E>>
|
||||
: public GCHashMapOperations<JS::Handle<JS::GCHashMap<A,B,C,D,E>>, A,B,C,D,E>
|
||||
{};
|
||||
|
||||
template <typename A, typename B, typename C, typename D, typename E>
|
||||
class WeakCacheBase<JS::GCHashMap<A,B,C,D,E>>
|
||||
: public MutableGCHashMapOperations<JS::WeakCache<JS::GCHashMap<A,B,C,D,E>>, A,B,C,D,E>
|
||||
{};
|
||||
|
||||
} // namespace js
|
||||
|
||||
namespace JS {
|
||||
|
|
@ -291,13 +271,13 @@ class GCHashSet : public js::HashSet<T, HashPolicy, AllocPolicy>
|
|||
|
||||
namespace js {
|
||||
|
||||
template <typename Outer, typename... Args>
|
||||
class GCHashSetOperations
|
||||
template <typename Wrapper, typename... Args>
|
||||
class WrappedPtrOperations<JS::GCHashSet<Args...>, Wrapper>
|
||||
{
|
||||
using Set = JS::GCHashSet<Args...>;
|
||||
using Lookup = typename Set::Lookup;
|
||||
|
||||
const Set& set() const { return static_cast<const Outer*>(this)->get(); }
|
||||
const Set& set() const { return static_cast<const Wrapper*>(this)->get(); }
|
||||
|
||||
public:
|
||||
using AddPtr = typename Set::AddPtr;
|
||||
|
|
@ -321,19 +301,19 @@ class GCHashSetOperations
|
|||
}
|
||||
};
|
||||
|
||||
template <typename Outer, typename... Args>
|
||||
class MutableGCHashSetOperations
|
||||
: public GCHashSetOperations<Outer, Args...>
|
||||
template <typename Wrapper, typename... Args>
|
||||
class MutableWrappedPtrOperations<JS::GCHashSet<Args...>, Wrapper>
|
||||
: public WrappedPtrOperations<JS::GCHashSet<Args...>, Wrapper>
|
||||
{
|
||||
using Set = JS::GCHashSet<Args...>;
|
||||
using Lookup = typename Set::Lookup;
|
||||
|
||||
Set& set() { return static_cast<Outer*>(this)->get(); }
|
||||
Set& set() { return static_cast<Wrapper*>(this)->get(); }
|
||||
|
||||
public:
|
||||
using AddPtr = typename Set::AddPtr;
|
||||
using Entry = typename Set::Entry;
|
||||
struct Enum : public Set::Enum { explicit Enum(Outer& o) : Set::Enum(o.set()) {} };
|
||||
struct Enum : public Set::Enum { explicit Enum(Wrapper& o) : Set::Enum(o.set()) {} };
|
||||
using Ptr = typename Set::Ptr;
|
||||
using Range = typename Set::Range;
|
||||
|
||||
|
|
@ -369,30 +349,6 @@ class MutableGCHashSetOperations
|
|||
}
|
||||
};
|
||||
|
||||
template <typename T, typename HP, typename AP>
|
||||
class RootedBase<JS::GCHashSet<T, HP, AP>>
|
||||
: public MutableGCHashSetOperations<JS::Rooted<JS::GCHashSet<T, HP, AP>>, T, HP, AP>
|
||||
{
|
||||
};
|
||||
|
||||
template <typename T, typename HP, typename AP>
|
||||
class MutableHandleBase<JS::GCHashSet<T, HP, AP>>
|
||||
: public MutableGCHashSetOperations<JS::MutableHandle<JS::GCHashSet<T, HP, AP>>, T, HP, AP>
|
||||
{
|
||||
};
|
||||
|
||||
template <typename T, typename HP, typename AP>
|
||||
class HandleBase<JS::GCHashSet<T, HP, AP>>
|
||||
: public GCHashSetOperations<JS::Handle<JS::GCHashSet<T, HP, AP>>, T, HP, AP>
|
||||
{
|
||||
};
|
||||
|
||||
template <typename T, typename HP, typename AP>
|
||||
class WeakCacheBase<JS::GCHashSet<T, HP, AP>>
|
||||
: public MutableGCHashSetOperations<JS::WeakCache<JS::GCHashSet<T, HP, AP>>, T, HP, AP>
|
||||
{
|
||||
};
|
||||
|
||||
} /* namespace js */
|
||||
|
||||
#endif /* GCHashTable_h */
|
||||
|
|
|
|||
|
|
@ -123,13 +123,13 @@ struct GCPolicy<mozilla::Variant<Ts...>>
|
|||
|
||||
namespace js {
|
||||
|
||||
template <typename Outer, typename... Ts>
|
||||
class GCVariantOperations
|
||||
template <typename Wrapper, typename... Ts>
|
||||
class WrappedPtrOperations<mozilla::Variant<Ts...>, Wrapper>
|
||||
{
|
||||
using Impl = JS::detail::GCVariantImplementation<Ts...>;
|
||||
using Variant = mozilla::Variant<Ts...>;
|
||||
|
||||
const Variant& variant() const { return static_cast<const Outer*>(this)->get(); }
|
||||
const Variant& variant() const { return static_cast<const Wrapper*>(this)->get(); }
|
||||
|
||||
public:
|
||||
template <typename T>
|
||||
|
|
@ -149,15 +149,15 @@ class GCVariantOperations
|
|||
}
|
||||
};
|
||||
|
||||
template <typename Outer, typename... Ts>
|
||||
class MutableGCVariantOperations
|
||||
: public GCVariantOperations<Outer, Ts...>
|
||||
template <typename Wrapper, typename... Ts>
|
||||
class MutableWrappedPtrOperations<mozilla::Variant<Ts...>, Wrapper>
|
||||
: public WrappedPtrOperations<mozilla::Variant<Ts...>, Wrapper>
|
||||
{
|
||||
using Impl = JS::detail::GCVariantImplementation<Ts...>;
|
||||
using Variant = mozilla::Variant<Ts...>;
|
||||
|
||||
const Variant& variant() const { return static_cast<const Outer*>(this)->get(); }
|
||||
Variant& variant() { return static_cast<Outer*>(this)->get(); }
|
||||
const Variant& variant() const { return static_cast<const Wrapper*>(this)->get(); }
|
||||
Variant& variant() { return static_cast<Wrapper*>(this)->get(); }
|
||||
|
||||
public:
|
||||
template <typename T>
|
||||
|
|
@ -172,26 +172,6 @@ class MutableGCVariantOperations
|
|||
}
|
||||
};
|
||||
|
||||
template <typename... Ts>
|
||||
class RootedBase<mozilla::Variant<Ts...>>
|
||||
: public MutableGCVariantOperations<JS::Rooted<mozilla::Variant<Ts...>>, Ts...>
|
||||
{ };
|
||||
|
||||
template <typename... Ts>
|
||||
class MutableHandleBase<mozilla::Variant<Ts...>>
|
||||
: public MutableGCVariantOperations<JS::MutableHandle<mozilla::Variant<Ts...>>, Ts...>
|
||||
{ };
|
||||
|
||||
template <typename... Ts>
|
||||
class HandleBase<mozilla::Variant<Ts...>>
|
||||
: public GCVariantOperations<JS::Handle<mozilla::Variant<Ts...>>, Ts...>
|
||||
{ };
|
||||
|
||||
template <typename... Ts>
|
||||
class PersistentRootedBase<mozilla::Variant<Ts...>>
|
||||
: public MutableGCVariantOperations<JS::PersistentRooted<mozilla::Variant<Ts...>>, Ts...>
|
||||
{ };
|
||||
|
||||
} // namespace js
|
||||
|
||||
#endif // js_GCVariant_h
|
||||
|
|
|
|||
|
|
@ -134,11 +134,11 @@ class GCVector
|
|||
|
||||
namespace js {
|
||||
|
||||
template <typename Outer, typename T, size_t Capacity, typename AllocPolicy>
|
||||
class GCVectorOperations
|
||||
template <typename Wrapper, typename T, size_t Capacity, typename AllocPolicy>
|
||||
class WrappedPtrOperations<JS::GCVector<T, Capacity, AllocPolicy>, Wrapper>
|
||||
{
|
||||
using Vec = JS::GCVector<T, Capacity, AllocPolicy>;
|
||||
const Vec& vec() const { return static_cast<const Outer*>(this)->get(); }
|
||||
const Vec& vec() const { return static_cast<const Wrapper*>(this)->get(); }
|
||||
|
||||
public:
|
||||
const AllocPolicy& allocPolicy() const { return vec().allocPolicy(); }
|
||||
|
|
@ -154,13 +154,13 @@ class GCVectorOperations
|
|||
}
|
||||
};
|
||||
|
||||
template <typename Outer, typename T, size_t Capacity, typename AllocPolicy>
|
||||
class MutableGCVectorOperations
|
||||
: public GCVectorOperations<Outer, T, Capacity, AllocPolicy>
|
||||
template <typename Wrapper, typename T, size_t Capacity, typename AllocPolicy>
|
||||
class MutableWrappedPtrOperations<JS::GCVector<T, Capacity, AllocPolicy>, Wrapper>
|
||||
: public WrappedPtrOperations<JS::GCVector<T, Capacity, AllocPolicy>, Wrapper>
|
||||
{
|
||||
using Vec = JS::GCVector<T, Capacity, AllocPolicy>;
|
||||
const Vec& vec() const { return static_cast<const Outer*>(this)->get(); }
|
||||
Vec& vec() { return static_cast<Outer*>(this)->get(); }
|
||||
const Vec& vec() const { return static_cast<const Wrapper*>(this)->get(); }
|
||||
Vec& vec() { return static_cast<Wrapper*>(this)->get(); }
|
||||
|
||||
public:
|
||||
const AllocPolicy& allocPolicy() const { return vec().allocPolicy(); }
|
||||
|
|
@ -223,26 +223,6 @@ class MutableGCVectorOperations
|
|||
void erase(T* aBegin, T* aEnd) { vec().erase(aBegin, aEnd); }
|
||||
};
|
||||
|
||||
template <typename T, size_t N, typename AP>
|
||||
class RootedBase<JS::GCVector<T,N,AP>>
|
||||
: public MutableGCVectorOperations<JS::Rooted<JS::GCVector<T,N,AP>>, T,N,AP>
|
||||
{};
|
||||
|
||||
template <typename T, size_t N, typename AP>
|
||||
class MutableHandleBase<JS::GCVector<T,N,AP>>
|
||||
: public MutableGCVectorOperations<JS::MutableHandle<JS::GCVector<T,N,AP>>, T,N,AP>
|
||||
{};
|
||||
|
||||
template <typename T, size_t N, typename AP>
|
||||
class HandleBase<JS::GCVector<T,N,AP>>
|
||||
: public GCVectorOperations<JS::Handle<JS::GCVector<T,N,AP>>, T,N,AP>
|
||||
{};
|
||||
|
||||
template <typename T, size_t N, typename AP>
|
||||
class PersistentRootedBase<JS::GCVector<T,N,AP>>
|
||||
: public MutableGCVectorOperations<JS::PersistentRooted<JS::GCVector<T,N,AP>>, T,N,AP>
|
||||
{};
|
||||
|
||||
} // namespace js
|
||||
|
||||
#endif // js_GCVector_h
|
||||
|
|
|
|||
|
|
@ -112,17 +112,23 @@ template <typename T>
|
|||
struct BarrierMethods {
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
class RootedBase {};
|
||||
template <typename Element, typename Wrapper>
|
||||
class WrappedPtrOperations {};
|
||||
|
||||
template <typename T>
|
||||
class HandleBase {};
|
||||
template <typename Element, typename Wrapper>
|
||||
class MutableWrappedPtrOperations : public WrappedPtrOperations<Element, Wrapper> {};
|
||||
|
||||
template <typename T>
|
||||
class MutableHandleBase {};
|
||||
template <typename T, typename Wrapper>
|
||||
class RootedBase : public MutableWrappedPtrOperations<T, Wrapper> {};
|
||||
|
||||
template <typename T>
|
||||
class HeapBase {};
|
||||
template <typename T, typename Wrapper>
|
||||
class HandleBase : public WrappedPtrOperations<T, Wrapper> {};
|
||||
|
||||
template <typename T, typename Wrapper>
|
||||
class MutableHandleBase : public MutableWrappedPtrOperations<T, Wrapper> {};
|
||||
|
||||
template <typename T, typename Wrapper>
|
||||
class HeapBase : public MutableWrappedPtrOperations<T, Wrapper> {};
|
||||
|
||||
// Cannot use FOR_EACH_HEAP_ABLE_GC_POINTER_TYPE, as this would import too many macros into scope
|
||||
template <typename T> struct IsHeapConstructibleType { static constexpr bool value = false; };
|
||||
|
|
@ -132,8 +138,8 @@ FOR_EACH_PUBLIC_GC_POINTER_TYPE(DECLARE_IS_HEAP_CONSTRUCTIBLE_TYPE)
|
|||
FOR_EACH_PUBLIC_TAGGED_GC_POINTER_TYPE(DECLARE_IS_HEAP_CONSTRUCTIBLE_TYPE)
|
||||
#undef DECLARE_IS_HEAP_CONSTRUCTIBLE_TYPE
|
||||
|
||||
template <typename T>
|
||||
class PersistentRootedBase {};
|
||||
template <typename T, typename Wrapper>
|
||||
class PersistentRootedBase : public MutableWrappedPtrOperations<T, Wrapper> {};
|
||||
|
||||
static void* const ConstNullValue = nullptr;
|
||||
|
||||
|
|
@ -143,10 +149,6 @@ template<typename T>
|
|||
struct PersistentRootedMarker;
|
||||
} /* namespace gc */
|
||||
|
||||
#define DECLARE_POINTER_COMPARISON_OPS(T) \
|
||||
bool operator==(const T& other) const { return get() == other; } \
|
||||
bool operator!=(const T& other) const { return get() != other; }
|
||||
|
||||
// Important: Return a reference so passing a Rooted<T>, etc. to
|
||||
// something that takes a |const T&| is not a GC hazard.
|
||||
#define DECLARE_POINTER_CONSTREF_OPS(T) \
|
||||
|
|
@ -230,12 +232,14 @@ AssertGCThingIsNotAnObjectSubclass(js::gc::Cell* cell) {}
|
|||
* Type T must be a public GC pointer type.
|
||||
*/
|
||||
template <typename T>
|
||||
class MOZ_NON_MEMMOVABLE Heap : public js::HeapBase<T>
|
||||
class MOZ_NON_MEMMOVABLE Heap : public js::HeapBase<T, Heap<T>>
|
||||
{
|
||||
// Please note: this can actually also be used by nsXBLMaybeCompiled<T>, for legacy reasons.
|
||||
static_assert(js::IsHeapConstructibleType<T>::value,
|
||||
"Type T must be a public GC pointer type");
|
||||
public:
|
||||
using ElementType = T;
|
||||
|
||||
Heap() {
|
||||
static_assert(sizeof(T) == sizeof(Heap<T>),
|
||||
"Heap<T> must be binary compatible with T.");
|
||||
|
|
@ -367,9 +371,11 @@ ScriptIsMarkedGray(const Heap<JSScript*>& script)
|
|||
* - It is not possible to store flag bits in a Heap<T>.
|
||||
*/
|
||||
template <typename T>
|
||||
class TenuredHeap : public js::HeapBase<T>
|
||||
class TenuredHeap : public js::HeapBase<T, TenuredHeap<T>>
|
||||
{
|
||||
public:
|
||||
using ElementType = T;
|
||||
|
||||
TenuredHeap() : bits(0) {
|
||||
static_assert(sizeof(T) == sizeof(TenuredHeap<T>),
|
||||
"TenuredHeap<T> must be binary compatible with T.");
|
||||
|
|
@ -377,9 +383,6 @@ class TenuredHeap : public js::HeapBase<T>
|
|||
explicit TenuredHeap(T p) : bits(0) { setPtr(p); }
|
||||
explicit TenuredHeap(const TenuredHeap<T>& p) : bits(0) { setPtr(p.getPtr()); }
|
||||
|
||||
bool operator==(const TenuredHeap<T>& other) { return bits == other.bits; }
|
||||
bool operator!=(const TenuredHeap<T>& other) { return bits != other.bits; }
|
||||
|
||||
void setPtr(T newPtr) {
|
||||
MOZ_ASSERT((reinterpret_cast<uintptr_t>(newPtr) & flagsMask) == 0);
|
||||
if (newPtr)
|
||||
|
|
@ -451,11 +454,13 @@ class TenuredHeap : public js::HeapBase<T>
|
|||
* specialization, define a HandleBase<T> specialization containing them.
|
||||
*/
|
||||
template <typename T>
|
||||
class MOZ_NONHEAP_CLASS Handle : public js::HandleBase<T>
|
||||
class MOZ_NONHEAP_CLASS Handle : public js::HandleBase<T, Handle<T>>
|
||||
{
|
||||
friend class JS::MutableHandle<T>;
|
||||
|
||||
public:
|
||||
using ElementType = T;
|
||||
|
||||
/* Creates a handle from a handle of a type convertible to T. */
|
||||
template <typename S>
|
||||
MOZ_IMPLICIT Handle(Handle<S> handle,
|
||||
|
|
@ -516,7 +521,6 @@ class MOZ_NONHEAP_CLASS Handle : public js::HandleBase<T>
|
|||
MOZ_IMPLICIT Handle(MutableHandle<S>& root,
|
||||
typename mozilla::EnableIf<mozilla::IsConvertible<S, T>::value, int>::Type dummy = 0);
|
||||
|
||||
DECLARE_POINTER_COMPARISON_OPS(T);
|
||||
DECLARE_POINTER_CONSTREF_OPS(T);
|
||||
DECLARE_NONPOINTER_ACCESSOR_METHODS(*ptr);
|
||||
|
||||
|
|
@ -540,9 +544,11 @@ class MOZ_NONHEAP_CLASS Handle : public js::HandleBase<T>
|
|||
* them.
|
||||
*/
|
||||
template <typename T>
|
||||
class MOZ_STACK_CLASS MutableHandle : public js::MutableHandleBase<T>
|
||||
class MOZ_STACK_CLASS MutableHandle : public js::MutableHandleBase<T, MutableHandle<T>>
|
||||
{
|
||||
public:
|
||||
using ElementType = T;
|
||||
|
||||
inline MOZ_IMPLICIT MutableHandle(Rooted<T>* root);
|
||||
inline MOZ_IMPLICIT MutableHandle(PersistentRooted<T>* root);
|
||||
|
||||
|
|
@ -753,7 +759,7 @@ namespace JS {
|
|||
* specialization, define a RootedBase<T> specialization containing them.
|
||||
*/
|
||||
template <typename T>
|
||||
class MOZ_RAII Rooted : public js::RootedBase<T>
|
||||
class MOZ_RAII Rooted : public js::RootedBase<T, Rooted<T>>
|
||||
{
|
||||
inline void registerWithRootLists(js::RootedListHeads& roots) {
|
||||
this->stack = &roots[JS::MapTypeToRootKind<T>::kind];
|
||||
|
|
@ -775,6 +781,8 @@ class MOZ_RAII Rooted : public js::RootedBase<T>
|
|||
}
|
||||
|
||||
public:
|
||||
using ElementType = T;
|
||||
|
||||
template <typename RootingContext>
|
||||
explicit Rooted(const RootingContext& cx)
|
||||
: ptr(GCPolicy<T>::initial())
|
||||
|
|
@ -807,7 +815,6 @@ class MOZ_RAII Rooted : public js::RootedBase<T>
|
|||
ptr = mozilla::Move(value);
|
||||
}
|
||||
|
||||
DECLARE_POINTER_COMPARISON_OPS(T);
|
||||
DECLARE_POINTER_CONSTREF_OPS(T);
|
||||
DECLARE_POINTER_ASSIGN_OPS(Rooted, T);
|
||||
DECLARE_NONPOINTER_ACCESSOR_METHODS(ptr);
|
||||
|
|
@ -853,8 +860,8 @@ namespace js {
|
|||
* Rooted<StringObject*> rooted(cx, &obj->as<StringObject*>());
|
||||
* Handle<StringObject*> h = rooted;
|
||||
*/
|
||||
template <>
|
||||
class RootedBase<JSObject*>
|
||||
template <typename Container>
|
||||
class RootedBase<JSObject*, Container> : public MutableWrappedPtrOperations<JSObject*, Container>
|
||||
{
|
||||
public:
|
||||
template <class U>
|
||||
|
|
@ -871,8 +878,8 @@ class RootedBase<JSObject*>
|
|||
* Rooted<StringObject*> rooted(cx, &obj->as<StringObject*>());
|
||||
* Handle<StringObject*> h = rooted;
|
||||
*/
|
||||
template <>
|
||||
class HandleBase<JSObject*>
|
||||
template <typename Container>
|
||||
class HandleBase<JSObject*, Container> : public WrappedPtrOperations<JSObject*, Container>
|
||||
{
|
||||
public:
|
||||
template <class U>
|
||||
|
|
@ -881,16 +888,17 @@ class HandleBase<JSObject*>
|
|||
|
||||
/** Interface substitute for Rooted<T> which does not root the variable's memory. */
|
||||
template <typename T>
|
||||
class MOZ_RAII FakeRooted : public RootedBase<T>
|
||||
class MOZ_RAII FakeRooted : public RootedBase<T, FakeRooted<T>>
|
||||
{
|
||||
public:
|
||||
using ElementType = T;
|
||||
|
||||
template <typename CX>
|
||||
explicit FakeRooted(CX* cx) : ptr(JS::GCPolicy<T>::initial()) {}
|
||||
|
||||
template <typename CX>
|
||||
FakeRooted(CX* cx, T initial) : ptr(initial) {}
|
||||
|
||||
DECLARE_POINTER_COMPARISON_OPS(T);
|
||||
DECLARE_POINTER_CONSTREF_OPS(T);
|
||||
DECLARE_POINTER_ASSIGN_OPS(FakeRooted, T);
|
||||
DECLARE_NONPOINTER_ACCESSOR_METHODS(ptr);
|
||||
|
|
@ -908,9 +916,11 @@ class MOZ_RAII FakeRooted : public RootedBase<T>
|
|||
|
||||
/** Interface substitute for MutableHandle<T> which is not required to point to rooted memory. */
|
||||
template <typename T>
|
||||
class FakeMutableHandle : public js::MutableHandleBase<T>
|
||||
class FakeMutableHandle : public js::MutableHandleBase<T, FakeMutableHandle<T>>
|
||||
{
|
||||
public:
|
||||
using ElementType = T;
|
||||
|
||||
MOZ_IMPLICIT FakeMutableHandle(T* t) {
|
||||
ptr = t;
|
||||
}
|
||||
|
|
@ -1075,7 +1085,7 @@ MutableHandle<T>::MutableHandle(PersistentRooted<T>* root)
|
|||
* marked when the object itself is marked.
|
||||
*/
|
||||
template<typename T>
|
||||
class PersistentRooted : public js::PersistentRootedBase<T>,
|
||||
class PersistentRooted : public js::RootedBase<T, PersistentRooted<T>>,
|
||||
private mozilla::LinkedListElement<PersistentRooted<T>>
|
||||
{
|
||||
using ListBase = mozilla::LinkedListElement<PersistentRooted<T>>;
|
||||
|
|
@ -1101,6 +1111,8 @@ class PersistentRooted : public js::PersistentRootedBase<T>,
|
|||
js::RootLists& rootLists(js::ContextFriendFields* cx) = delete;
|
||||
|
||||
public:
|
||||
using ElementType = T;
|
||||
|
||||
PersistentRooted() : ptr(GCPolicy<T>::initial()) {}
|
||||
|
||||
template <typename RootingContext>
|
||||
|
|
@ -1154,7 +1166,6 @@ class PersistentRooted : public js::PersistentRootedBase<T>,
|
|||
}
|
||||
}
|
||||
|
||||
DECLARE_POINTER_COMPARISON_OPS(T);
|
||||
DECLARE_POINTER_CONSTREF_OPS(T);
|
||||
DECLARE_POINTER_ASSIGN_OPS(PersistentRooted, T);
|
||||
DECLARE_NONPOINTER_ACCESSOR_METHODS(ptr);
|
||||
|
|
@ -1191,6 +1202,8 @@ class JS_PUBLIC_API(ObjectPtr)
|
|||
Heap<JSObject*> value;
|
||||
|
||||
public:
|
||||
using ElementType = JSObject*;
|
||||
|
||||
ObjectPtr() : value(nullptr) {}
|
||||
|
||||
explicit ObjectPtr(JSObject* obj) : value(obj) {}
|
||||
|
|
@ -1240,10 +1253,10 @@ class JS_PUBLIC_API(ObjectPtr)
|
|||
|
||||
namespace js {
|
||||
|
||||
template <typename Outer, typename T, typename D>
|
||||
class UniquePtrOperations
|
||||
template <typename T, typename D, typename Container>
|
||||
class WrappedPtrOperations<UniquePtr<T, D>, Container>
|
||||
{
|
||||
const UniquePtr<T, D>& uniquePtr() const { return static_cast<const Outer*>(this)->get(); }
|
||||
const UniquePtr<T, D>& uniquePtr() const { return static_cast<const Container*>(this)->get(); }
|
||||
|
||||
public:
|
||||
explicit operator bool() const { return !!uniquePtr(); }
|
||||
|
|
@ -1252,36 +1265,17 @@ class UniquePtrOperations
|
|||
T& operator*() const { return *uniquePtr(); }
|
||||
};
|
||||
|
||||
template <typename Outer, typename T, typename D>
|
||||
class MutableUniquePtrOperations : public UniquePtrOperations<Outer, T, D>
|
||||
template <typename T, typename D, typename Container>
|
||||
class MutableWrappedPtrOperations<UniquePtr<T, D>, Container>
|
||||
: public WrappedPtrOperations<UniquePtr<T, D>, Container>
|
||||
{
|
||||
UniquePtr<T, D>& uniquePtr() { return static_cast<Outer*>(this)->get(); }
|
||||
UniquePtr<T, D>& uniquePtr() { return static_cast<Container*>(this)->get(); }
|
||||
|
||||
public:
|
||||
MOZ_MUST_USE typename UniquePtr<T, D>::Pointer release() { return uniquePtr().release(); }
|
||||
void reset(T* ptr = T()) { uniquePtr().reset(ptr); }
|
||||
};
|
||||
|
||||
template <typename T, typename D>
|
||||
class RootedBase<UniquePtr<T, D>>
|
||||
: public MutableUniquePtrOperations<JS::Rooted<UniquePtr<T, D>>, T, D>
|
||||
{ };
|
||||
|
||||
template <typename T, typename D>
|
||||
class MutableHandleBase<UniquePtr<T, D>>
|
||||
: public MutableUniquePtrOperations<JS::MutableHandle<UniquePtr<T, D>>, T, D>
|
||||
{ };
|
||||
|
||||
template <typename T, typename D>
|
||||
class HandleBase<UniquePtr<T, D>>
|
||||
: public UniquePtrOperations<JS::Handle<UniquePtr<T, D>>, T, D>
|
||||
{ };
|
||||
|
||||
template <typename T, typename D>
|
||||
class PersistentRootedBase<UniquePtr<T, D>>
|
||||
: public MutableUniquePtrOperations<JS::PersistentRooted<UniquePtr<T, D>>, T, D>
|
||||
{ };
|
||||
|
||||
namespace gc {
|
||||
|
||||
template <typename T, typename TraceCallbacks>
|
||||
|
|
@ -1324,6 +1318,177 @@ Swap(JS::TenuredHeap<T>& aX, JS::TenuredHeap<T>& aY)
|
|||
|
||||
} /* namespace mozilla */
|
||||
|
||||
namespace js {
|
||||
namespace detail {
|
||||
|
||||
// DefineComparisonOps is a trait which selects which wrapper classes to define
|
||||
// operator== and operator!= for. It supplies a getter function to extract the
|
||||
// value to compare. This is used to avoid triggering the automatic read
|
||||
// barriers where appropriate.
|
||||
//
|
||||
// If DefineComparisonOps is not specialized for a particular wrapper you may
|
||||
// get errors such as 'invalid operands to binary expression' or 'no match for
|
||||
// operator==' when trying to compare against instances of the wrapper.
|
||||
|
||||
template <typename T>
|
||||
struct DefineComparisonOps : mozilla::FalseType {};
|
||||
|
||||
template <typename T>
|
||||
struct DefineComparisonOps<JS::Heap<T>> : mozilla::TrueType {
|
||||
static const T& get(const JS::Heap<T>& v) { return v.unbarrieredGet(); }
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct DefineComparisonOps<JS::TenuredHeap<T>> : mozilla::TrueType {
|
||||
static const T get(const JS::TenuredHeap<T>& v) { return v.unbarrieredGetPtr(); }
|
||||
};
|
||||
|
||||
template <>
|
||||
struct DefineComparisonOps<JS::ObjectPtr> : mozilla::TrueType {
|
||||
static const JSObject* get(const JS::ObjectPtr& v) { return v.unbarrieredGet(); }
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct DefineComparisonOps<JS::Rooted<T>> : mozilla::TrueType {
|
||||
static const T& get(const JS::Rooted<T>& v) { return v.get(); }
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct DefineComparisonOps<JS::Handle<T>> : mozilla::TrueType {
|
||||
static const T& get(const JS::Handle<T>& v) { return v.get(); }
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct DefineComparisonOps<JS::MutableHandle<T>> : mozilla::TrueType {
|
||||
static const T& get(const JS::MutableHandle<T>& v) { return v.get(); }
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct DefineComparisonOps<JS::PersistentRooted<T>> : mozilla::TrueType {
|
||||
static const T& get(const JS::PersistentRooted<T>& v) { return v.get(); }
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct DefineComparisonOps<js::FakeRooted<T>> : mozilla::TrueType {
|
||||
static const T& get(const js::FakeRooted<T>& v) { return v.get(); }
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct DefineComparisonOps<js::FakeMutableHandle<T>> : mozilla::TrueType {
|
||||
static const T& get(const js::FakeMutableHandle<T>& v) { return v.get(); }
|
||||
};
|
||||
|
||||
} /* namespace detail */
|
||||
} /* namespace js */
|
||||
|
||||
// Overload operator== and operator!= for all types with the DefineComparisonOps
|
||||
// trait using the supplied getter.
|
||||
//
|
||||
// There are four cases:
|
||||
|
||||
// Case 1: comparison between two wrapper objects.
|
||||
|
||||
template <typename T, typename U>
|
||||
typename mozilla::EnableIf<js::detail::DefineComparisonOps<T>::value &&
|
||||
js::detail::DefineComparisonOps<U>::value, bool>::Type
|
||||
operator==(const T& a, const U& b) {
|
||||
return js::detail::DefineComparisonOps<T>::get(a) == js::detail::DefineComparisonOps<U>::get(b);
|
||||
}
|
||||
|
||||
template <typename T, typename U>
|
||||
typename mozilla::EnableIf<js::detail::DefineComparisonOps<T>::value &&
|
||||
js::detail::DefineComparisonOps<U>::value, bool>::Type
|
||||
operator!=(const T& a, const U& b) {
|
||||
return !(a == b);
|
||||
}
|
||||
|
||||
// Case 2: comparison between a wrapper object and its unwrapped element type.
|
||||
|
||||
template <typename T>
|
||||
typename mozilla::EnableIf<js::detail::DefineComparisonOps<T>::value, bool>::Type
|
||||
operator==(const T& a, const typename T::ElementType& b) {
|
||||
return js::detail::DefineComparisonOps<T>::get(a) == b;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
typename mozilla::EnableIf<js::detail::DefineComparisonOps<T>::value, bool>::Type
|
||||
operator!=(const T& a, const typename T::ElementType& b) {
|
||||
return !(a == b);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
typename mozilla::EnableIf<js::detail::DefineComparisonOps<T>::value, bool>::Type
|
||||
operator==(const typename T::ElementType& a, const T& b) {
|
||||
return a == js::detail::DefineComparisonOps<T>::get(b);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
typename mozilla::EnableIf<js::detail::DefineComparisonOps<T>::value, bool>::Type
|
||||
operator!=(const typename T::ElementType& a, const T& b) {
|
||||
return !(a == b);
|
||||
}
|
||||
|
||||
// Case 3: For pointer wrappers, comparison between the wrapper and a const
|
||||
// element pointer.
|
||||
|
||||
template <typename T>
|
||||
typename mozilla::EnableIf<js::detail::DefineComparisonOps<T>::value &&
|
||||
mozilla::IsPointer<typename T::ElementType>::value, bool>::Type
|
||||
operator==(const typename mozilla::RemovePointer<typename T::ElementType>::Type* a, const T& b) {
|
||||
return a == js::detail::DefineComparisonOps<T>::get(b);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
typename mozilla::EnableIf<js::detail::DefineComparisonOps<T>::value &&
|
||||
mozilla::IsPointer<typename T::ElementType>::value, bool>::Type
|
||||
operator!=(const typename mozilla::RemovePointer<typename T::ElementType>::Type* a, const T& b) {
|
||||
return !(a == b);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
typename mozilla::EnableIf<js::detail::DefineComparisonOps<T>::value &&
|
||||
mozilla::IsPointer<typename T::ElementType>::value, bool>::Type
|
||||
operator==(const T& a, const typename mozilla::RemovePointer<typename T::ElementType>::Type* b) {
|
||||
return js::detail::DefineComparisonOps<T>::get(a) == b;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
typename mozilla::EnableIf<js::detail::DefineComparisonOps<T>::value &&
|
||||
mozilla::IsPointer<typename T::ElementType>::value, bool>::Type
|
||||
operator!=(const T& a, const typename mozilla::RemovePointer<typename T::ElementType>::Type* b) {
|
||||
return !(a == b);
|
||||
}
|
||||
|
||||
// Case 4: For pointer wrappers, comparison between the wrapper and nullptr.
|
||||
|
||||
template <typename T>
|
||||
typename mozilla::EnableIf<js::detail::DefineComparisonOps<T>::value &&
|
||||
mozilla::IsPointer<typename T::ElementType>::value, bool>::Type
|
||||
operator==(std::nullptr_t a, const T& b) {
|
||||
return a == js::detail::DefineComparisonOps<T>::get(b);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
typename mozilla::EnableIf<js::detail::DefineComparisonOps<T>::value &&
|
||||
mozilla::IsPointer<typename T::ElementType>::value, bool>::Type
|
||||
operator!=(std::nullptr_t a, const T& b) {
|
||||
return !(a == b);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
typename mozilla::EnableIf<js::detail::DefineComparisonOps<T>::value &&
|
||||
mozilla::IsPointer<typename T::ElementType>::value, bool>::Type
|
||||
operator==(const T& a, std::nullptr_t b) {
|
||||
return js::detail::DefineComparisonOps<T>::get(a) == b;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
typename mozilla::EnableIf<js::detail::DefineComparisonOps<T>::value &&
|
||||
mozilla::IsPointer<typename T::ElementType>::value, bool>::Type
|
||||
operator!=(const T& a, std::nullptr_t b) {
|
||||
return !(a == b);
|
||||
}
|
||||
|
||||
#undef DELETE_ASSIGNMENT_OPS
|
||||
|
||||
#endif /* js_RootingAPI_h */
|
||||
|
|
|
|||
|
|
@ -8,11 +8,6 @@
|
|||
|
||||
#include "js/HeapAPI.h"
|
||||
|
||||
namespace js {
|
||||
template <typename T>
|
||||
class WeakCacheBase {};
|
||||
} // namespace js
|
||||
|
||||
namespace JS {
|
||||
template <typename T> class WeakCache;
|
||||
|
||||
|
|
@ -24,7 +19,7 @@ RegisterWeakCache(JS::Zone* zone, JS::WeakCache<void*>* cachep);
|
|||
// A WeakCache stores the given Sweepable container and links itself into a
|
||||
// list of such caches that are swept during each GC.
|
||||
template <typename T>
|
||||
class WeakCache : public js::WeakCacheBase<T>,
|
||||
class WeakCache : public js::MutableWrappedPtrOperations<T, WeakCache<T>>,
|
||||
private mozilla::LinkedListElement<WeakCache<T>>
|
||||
{
|
||||
friend class mozilla::LinkedListElement<WeakCache<T>>;
|
||||
|
|
|
|||
|
|
@ -1340,20 +1340,18 @@ struct BarrierMethods<JS::Value>
|
|||
}
|
||||
};
|
||||
|
||||
template <class Outer> class MutableValueOperations;
|
||||
template <class Wrapper> class MutableValueOperations;
|
||||
|
||||
/**
|
||||
* A class designed for CRTP use in implementing the non-mutating parts of the
|
||||
* Value interface in Value-like classes. Outer must be a class inheriting
|
||||
* ValueOperations<Outer> with a visible get() method returning a const
|
||||
* reference to the Value abstracted by Outer.
|
||||
* Value interface in Value-like classes. Wrapper must be a class inheriting
|
||||
* ValueOperations<Wrapper> with a visible get() method returning a const
|
||||
* reference to the Value abstracted by Wrapper.
|
||||
*/
|
||||
template <class Outer>
|
||||
class ValueOperations
|
||||
template <class Wrapper>
|
||||
class WrappedPtrOperations<JS::Value, Wrapper>
|
||||
{
|
||||
friend class MutableValueOperations<Outer>;
|
||||
|
||||
const JS::Value& value() const { return static_cast<const Outer*>(this)->get(); }
|
||||
const JS::Value& value() const { return static_cast<const Wrapper*>(this)->get(); }
|
||||
|
||||
public:
|
||||
bool isUndefined() const { return value().isUndefined(); }
|
||||
|
|
@ -1398,17 +1396,17 @@ class ValueOperations
|
|||
|
||||
/**
|
||||
* A class designed for CRTP use in implementing all the mutating parts of the
|
||||
* Value interface in Value-like classes. Outer must be a class inheriting
|
||||
* MutableValueOperations<Outer> with visible get() methods returning const and
|
||||
* non-const references to the Value abstracted by Outer.
|
||||
* Value interface in Value-like classes. Wrapper must be a class inheriting
|
||||
* MutableWrappedPtrOperations<Wrapper> with visible get() methods returning const and
|
||||
* non-const references to the Value abstracted by Wrapper.
|
||||
*/
|
||||
template <class Outer>
|
||||
class MutableValueOperations : public ValueOperations<Outer>
|
||||
template <class Wrapper>
|
||||
class MutableWrappedPtrOperations<JS::Value, Wrapper> : public WrappedPtrOperations<JS::Value, Wrapper>
|
||||
{
|
||||
protected:
|
||||
void set(const JS::Value& v) {
|
||||
// Call Outer::set to trigger any barriers.
|
||||
static_cast<Outer*>(this)->set(v);
|
||||
static_cast<Wrapper*>(this)->set(v);
|
||||
}
|
||||
|
||||
public:
|
||||
|
|
@ -1434,13 +1432,9 @@ class MutableValueOperations : public ValueOperations<Outer>
|
|||
* Augment the generic Heap<T> interface when T = Value with
|
||||
* type-querying, value-extracting, and mutating operations.
|
||||
*/
|
||||
template <>
|
||||
class HeapBase<JS::Value> : public MutableValueOperations<JS::Heap<JS::Value> >
|
||||
template <typename Wrapper>
|
||||
class HeapBase<JS::Value, Wrapper> : public MutableWrappedPtrOperations<JS::Value, Wrapper>
|
||||
{
|
||||
typedef JS::Heap<JS::Value> Outer;
|
||||
|
||||
friend class ValueOperations<Outer>;
|
||||
|
||||
public:
|
||||
void setNumber(uint32_t ui) {
|
||||
if (ui > JSVAL_INT_MAX) {
|
||||
|
|
@ -1460,22 +1454,6 @@ class HeapBase<JS::Value> : public MutableValueOperations<JS::Heap<JS::Value> >
|
|||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
class HandleBase<JS::Value> : public ValueOperations<JS::Handle<JS::Value> >
|
||||
{};
|
||||
|
||||
template <>
|
||||
class MutableHandleBase<JS::Value> : public MutableValueOperations<JS::MutableHandle<JS::Value> >
|
||||
{};
|
||||
|
||||
template <>
|
||||
class RootedBase<JS::Value> : public MutableValueOperations<JS::Rooted<JS::Value> >
|
||||
{};
|
||||
|
||||
template <>
|
||||
class PersistentRootedBase<JS::Value> : public MutableValueOperations<JS::PersistentRooted<JS::Value>>
|
||||
{};
|
||||
|
||||
/*
|
||||
* If the Value is a GC pointer type, convert to that type and call |f| with
|
||||
* the pointer. If the Value is not a GC type, calls F::defaultValue.
|
||||
|
|
|
|||
|
|
@ -45,6 +45,7 @@ class MOZ_STACK_CLASS SourceBufferHolder;
|
|||
class HandleValueArray;
|
||||
|
||||
class ObjectOpResult;
|
||||
class PropertyResult;
|
||||
|
||||
class Symbol;
|
||||
enum class SymbolCode: uint32_t;
|
||||
|
|
@ -150,6 +151,7 @@ using JS::FalseHandleValue;
|
|||
using JS::HandleValueArray;
|
||||
|
||||
using JS::ObjectOpResult;
|
||||
using JS::PropertyResult;
|
||||
|
||||
using JS::Zone;
|
||||
|
||||
|
|
|
|||
|
|
@ -52,14 +52,22 @@ class HashableValue
|
|||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
class RootedBase<HashableValue> {
|
||||
template <typename Wrapper>
|
||||
class WrappedPtrOperations<HashableValue, Wrapper>
|
||||
{
|
||||
public:
|
||||
Value value() const {
|
||||
return static_cast<const Wrapper*>(this)->get().get();
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Wrapper>
|
||||
class MutableWrappedPtrOperations<HashableValue, Wrapper>
|
||||
: public WrappedPtrOperations<HashableValue, Wrapper>
|
||||
{
|
||||
public:
|
||||
MOZ_MUST_USE bool setValue(JSContext* cx, HandleValue v) {
|
||||
return static_cast<JS::Rooted<HashableValue>*>(this)->get().setValue(cx, v);
|
||||
}
|
||||
Value value() const {
|
||||
return static_cast<const JS::Rooted<HashableValue>*>(this)->get().get();
|
||||
return static_cast<Wrapper*>(this)->get().setValue(cx, v);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -69,18 +69,18 @@ js::obj_propertyIsEnumerable(JSContext* cx, unsigned argc, Value* vp)
|
|||
JSObject* obj = &args.thisv().toObject();
|
||||
|
||||
/* Step 3. */
|
||||
Shape* shape;
|
||||
PropertyResult prop;
|
||||
if (obj->isNative() &&
|
||||
NativeLookupOwnProperty<NoGC>(cx, &obj->as<NativeObject>(), id, &shape))
|
||||
NativeLookupOwnProperty<NoGC>(cx, &obj->as<NativeObject>(), id, &prop))
|
||||
{
|
||||
/* Step 4. */
|
||||
if (!shape) {
|
||||
if (!prop) {
|
||||
args.rval().setBoolean(false);
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Step 5. */
|
||||
unsigned attrs = GetShapeAttributes(obj, shape);
|
||||
unsigned attrs = GetPropertyAttributes(obj, prop);
|
||||
args.rval().setBoolean((attrs & JSPROP_ENUMERATE) != 0);
|
||||
return true;
|
||||
}
|
||||
|
|
@ -582,11 +582,11 @@ js::obj_hasOwnProperty(JSContext* cx, unsigned argc, Value* vp)
|
|||
jsid id;
|
||||
if (args.thisv().isObject() && ValueToId<NoGC>(cx, idValue, &id)) {
|
||||
JSObject* obj = &args.thisv().toObject();
|
||||
Shape* prop;
|
||||
PropertyResult prop;
|
||||
if (obj->isNative() &&
|
||||
NativeLookupOwnProperty<NoGC>(cx, &obj->as<NativeObject>(), id, &prop))
|
||||
{
|
||||
args.rval().setBoolean(!!prop);
|
||||
args.rval().setBoolean(prop.isFound());
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
@ -839,7 +839,7 @@ EnumerableOwnProperties(JSContext* cx, const JS::CallArgs& args, EnumerableOwnPr
|
|||
value = nobj->getDenseOrTypedArrayElement(JSID_TO_INT(id));
|
||||
} else {
|
||||
shape = nobj->lookup(cx, id);
|
||||
if (!shape || !(GetShapeAttributes(nobj, shape) & JSPROP_ENUMERATE))
|
||||
if (!shape || !(shape->attributes() & JSPROP_ENUMERATE))
|
||||
continue;
|
||||
if (!shape->isAccessorShape()) {
|
||||
if (!NativeGetExistingProperty(cx, nobj, nobj, shape, &value))
|
||||
|
|
|
|||
|
|
@ -1671,10 +1671,10 @@ TypeDescr::hasProperty(const JSAtomState& names, jsid id)
|
|||
|
||||
/* static */ bool
|
||||
TypedObject::obj_lookupProperty(JSContext* cx, HandleObject obj, HandleId id,
|
||||
MutableHandleObject objp, MutableHandleShape propp)
|
||||
MutableHandleObject objp, MutableHandle<PropertyResult> propp)
|
||||
{
|
||||
if (obj->as<TypedObject>().typeDescr().hasProperty(cx->names(), id)) {
|
||||
MarkNonNativePropertyFound<CanGC>(propp);
|
||||
propp.setNonNativeProperty();
|
||||
objp.set(obj);
|
||||
return true;
|
||||
}
|
||||
|
|
@ -1682,7 +1682,7 @@ TypedObject::obj_lookupProperty(JSContext* cx, HandleObject obj, HandleId id,
|
|||
RootedObject proto(cx, obj->staticPrototype());
|
||||
if (!proto) {
|
||||
objp.set(nullptr);
|
||||
propp.set(nullptr);
|
||||
propp.setNotFound();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -509,7 +509,7 @@ class TypedObject : public ShapedObject
|
|||
|
||||
static MOZ_MUST_USE bool obj_lookupProperty(JSContext* cx, HandleObject obj,
|
||||
HandleId id, MutableHandleObject objp,
|
||||
MutableHandleShape propp);
|
||||
MutableHandle<PropertyResult> propp);
|
||||
|
||||
static MOZ_MUST_USE bool obj_defineProperty(JSContext* cx, HandleObject obj, HandleId id,
|
||||
Handle<PropertyDescriptor> desc,
|
||||
|
|
|
|||
|
|
@ -51,11 +51,11 @@ class TraceableFifo : public js::Fifo<T, MinInlineCapacity, AllocPolicy>
|
|||
}
|
||||
};
|
||||
|
||||
template <typename Outer, typename T, size_t Capacity, typename AllocPolicy>
|
||||
class TraceableFifoOperations
|
||||
template <typename Wrapper, typename T, size_t Capacity, typename AllocPolicy>
|
||||
class WrappedPtrOperations<TraceableFifo<T, Capacity, AllocPolicy>, Wrapper>
|
||||
{
|
||||
using TF = TraceableFifo<T, Capacity, AllocPolicy>;
|
||||
const TF& fifo() const { return static_cast<const Outer*>(this)->extract(); }
|
||||
const TF& fifo() const { return static_cast<const Wrapper*>(this)->get(); }
|
||||
|
||||
public:
|
||||
size_t length() const { return fifo().length(); }
|
||||
|
|
@ -63,12 +63,12 @@ class TraceableFifoOperations
|
|||
const T& front() const { return fifo().front(); }
|
||||
};
|
||||
|
||||
template <typename Outer, typename T, size_t Capacity, typename AllocPolicy>
|
||||
class MutableTraceableFifoOperations
|
||||
: public TraceableFifoOperations<Outer, T, Capacity, AllocPolicy>
|
||||
template <typename Wrapper, typename T, size_t Capacity, typename AllocPolicy>
|
||||
class MutableWrappedPtrOperations<TraceableFifo<T, Capacity, AllocPolicy>, Wrapper>
|
||||
: public WrappedPtrOperations<TraceableFifo<T, Capacity, AllocPolicy>, Wrapper>
|
||||
{
|
||||
using TF = TraceableFifo<T, Capacity, AllocPolicy>;
|
||||
TF& fifo() { return static_cast<Outer*>(this)->extract(); }
|
||||
TF& fifo() { return static_cast<Wrapper*>(this)->get(); }
|
||||
|
||||
public:
|
||||
T& front() { return fifo().front(); }
|
||||
|
|
@ -82,46 +82,6 @@ class MutableTraceableFifoOperations
|
|||
void clear() { fifo().clear(); }
|
||||
};
|
||||
|
||||
template <typename A, size_t B, typename C>
|
||||
class RootedBase<TraceableFifo<A,B,C>>
|
||||
: public MutableTraceableFifoOperations<JS::Rooted<TraceableFifo<A,B,C>>, A,B,C>
|
||||
{
|
||||
using TF = TraceableFifo<A,B,C>;
|
||||
|
||||
friend class TraceableFifoOperations<JS::Rooted<TF>, A,B,C>;
|
||||
const TF& extract() const { return *static_cast<const JS::Rooted<TF>*>(this)->address(); }
|
||||
|
||||
friend class MutableTraceableFifoOperations<JS::Rooted<TF>, A,B,C>;
|
||||
TF& extract() { return *static_cast<JS::Rooted<TF>*>(this)->address(); }
|
||||
};
|
||||
|
||||
template <typename A, size_t B, typename C>
|
||||
class MutableHandleBase<TraceableFifo<A,B,C>>
|
||||
: public MutableTraceableFifoOperations<JS::MutableHandle<TraceableFifo<A,B,C>>, A,B,C>
|
||||
{
|
||||
using TF = TraceableFifo<A,B,C>;
|
||||
|
||||
friend class TraceableFifoOperations<JS::MutableHandle<TF>, A,B,C>;
|
||||
const TF& extract() const {
|
||||
return *static_cast<const JS::MutableHandle<TF>*>(this)->address();
|
||||
}
|
||||
|
||||
friend class MutableTraceableFifoOperations<JS::MutableHandle<TF>, A,B,C>;
|
||||
TF& extract() { return *static_cast<JS::MutableHandle<TF>*>(this)->address(); }
|
||||
};
|
||||
|
||||
template <typename A, size_t B, typename C>
|
||||
class HandleBase<TraceableFifo<A,B,C>>
|
||||
: public TraceableFifoOperations<JS::Handle<TraceableFifo<A,B,C>>, A,B,C>
|
||||
{
|
||||
using TF = TraceableFifo<A,B,C>;
|
||||
|
||||
friend class TraceableFifoOperations<JS::Handle<TF>, A,B,C>;
|
||||
const TF& extract() const {
|
||||
return *static_cast<const JS::Handle<TF>*>(this)->address();
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace js
|
||||
|
||||
#endif // js_TraceableFifo_h
|
||||
|
|
|
|||
|
|
@ -261,8 +261,6 @@ struct InternalBarrierMethods<T*>
|
|||
{
|
||||
static bool isMarkable(T* v) { return v != nullptr; }
|
||||
|
||||
static bool isMarkableTaggedPointer(T* v) { return !IsNullTaggedPointer(v); }
|
||||
|
||||
static void preBarrier(T* v) { T::writeBarrierPre(v); }
|
||||
|
||||
static void postBarrier(T** vp, T* prev, T* next) { T::writeBarrierPost(vp, prev, next); }
|
||||
|
|
@ -282,7 +280,6 @@ template <>
|
|||
struct InternalBarrierMethods<Value>
|
||||
{
|
||||
static bool isMarkable(const Value& v) { return v.isGCThing(); }
|
||||
static bool isMarkableTaggedPointer(const Value& v) { return isMarkable(v); }
|
||||
|
||||
static void preBarrier(const Value& v) {
|
||||
DispatchTyped(PreBarrierFunctor<Value>(), v);
|
||||
|
|
@ -318,24 +315,17 @@ template <>
|
|||
struct InternalBarrierMethods<jsid>
|
||||
{
|
||||
static bool isMarkable(jsid id) { return JSID_IS_GCTHING(id); }
|
||||
static bool isMarkableTaggedPointer(jsid id) { return isMarkable(id); }
|
||||
|
||||
static void preBarrier(jsid id) { DispatchTyped(PreBarrierFunctor<jsid>(), id); }
|
||||
static void postBarrier(jsid* idp, jsid prev, jsid next) {}
|
||||
};
|
||||
|
||||
// Barrier classes can use Mixins to add methods to a set of barrier
|
||||
// instantiations, to make the barriered thing look and feel more like the
|
||||
// thing itself.
|
||||
template <typename T>
|
||||
class BarrieredBaseMixins {};
|
||||
|
||||
// Base class of all barrier types.
|
||||
//
|
||||
// This is marked non-memmovable since post barriers added by derived classes
|
||||
// can add pointers to class instances to the store buffer.
|
||||
template <typename T>
|
||||
class MOZ_NON_MEMMOVABLE BarrieredBase : public BarrieredBaseMixins<T>
|
||||
class MOZ_NON_MEMMOVABLE BarrieredBase
|
||||
{
|
||||
protected:
|
||||
// BarrieredBase is not directly instantiable.
|
||||
|
|
@ -356,14 +346,18 @@ class MOZ_NON_MEMMOVABLE BarrieredBase : public BarrieredBaseMixins<T>
|
|||
|
||||
// Base class for barriered pointer types that intercept only writes.
|
||||
template <class T>
|
||||
class WriteBarrieredBase : public BarrieredBase<T>
|
||||
class WriteBarrieredBase : public BarrieredBase<T>,
|
||||
public WrappedPtrOperations<T, WriteBarrieredBase<T>>
|
||||
{
|
||||
protected:
|
||||
using BarrieredBase<T>::value;
|
||||
|
||||
// WriteBarrieredBase is not directly instantiable.
|
||||
explicit WriteBarrieredBase(const T& v) : BarrieredBase<T>(v) {}
|
||||
|
||||
public:
|
||||
DECLARE_POINTER_COMPARISON_OPS(T);
|
||||
using ElementType = T;
|
||||
|
||||
DECLARE_POINTER_CONSTREF_OPS(T);
|
||||
|
||||
// Use this if the automatic coercion to T isn't working.
|
||||
|
|
@ -460,10 +454,6 @@ class GCPtr : public WriteBarrieredBase<T>
|
|||
|
||||
DECLARE_POINTER_ASSIGN_OPS(GCPtr, T);
|
||||
|
||||
T unbarrieredGet() const {
|
||||
return this->value;
|
||||
}
|
||||
|
||||
private:
|
||||
void set(const T& v) {
|
||||
this->pre();
|
||||
|
|
@ -580,8 +570,12 @@ class ReadBarrieredBase : public BarrieredBase<T>
|
|||
// insert manual post-barriers on the table for rekeying if the key is based in
|
||||
// any way on the address of the object.
|
||||
template <typename T>
|
||||
class ReadBarriered : public ReadBarrieredBase<T>
|
||||
class ReadBarriered : public ReadBarrieredBase<T>,
|
||||
public WrappedPtrOperations<T, ReadBarriered<T>>
|
||||
{
|
||||
protected:
|
||||
using ReadBarrieredBase<T>::value;
|
||||
|
||||
public:
|
||||
ReadBarriered() : ReadBarrieredBase<T>(JS::GCPolicy<T>::initial()) {}
|
||||
|
||||
|
|
@ -614,14 +608,13 @@ class ReadBarriered : public ReadBarrieredBase<T>
|
|||
return *this;
|
||||
}
|
||||
|
||||
const T get() const {
|
||||
if (!InternalBarrierMethods<T>::isMarkable(this->value))
|
||||
return JS::GCPolicy<T>::initial();
|
||||
this->read();
|
||||
const T& get() const {
|
||||
if (InternalBarrierMethods<T>::isMarkable(this->value))
|
||||
this->read();
|
||||
return this->value;
|
||||
}
|
||||
|
||||
const T unbarrieredGet() const {
|
||||
const T& unbarrieredGet() const {
|
||||
return this->value;
|
||||
}
|
||||
|
||||
|
|
@ -629,9 +622,9 @@ class ReadBarriered : public ReadBarrieredBase<T>
|
|||
return bool(this->value);
|
||||
}
|
||||
|
||||
operator const T() const { return get(); }
|
||||
operator const T&() const { return get(); }
|
||||
|
||||
const T operator->() const { return get(); }
|
||||
const T& operator->() const { return get(); }
|
||||
|
||||
T* unsafeGet() { return &this->value; }
|
||||
T const* unsafeGet() const { return &this->value; }
|
||||
|
|
@ -649,12 +642,6 @@ class ReadBarriered : public ReadBarrieredBase<T>
|
|||
template <typename T>
|
||||
using WeakRef = ReadBarriered<T>;
|
||||
|
||||
// Add Value operations to all Barrier types. Note, this must be defined before
|
||||
// HeapSlot for HeapSlot's base to get these operations.
|
||||
template <>
|
||||
class BarrieredBaseMixins<JS::Value> : public ValueOperations<WriteBarrieredBase<JS::Value>>
|
||||
{};
|
||||
|
||||
// A pre- and post-barriered Value that is specialized to be aware that it
|
||||
// resides in a slots or elements vector. This allows it to be relocated in
|
||||
// memory, but with substantially less overhead than a HeapPtr.
|
||||
|
|
@ -943,6 +930,36 @@ typedef ReadBarriered<WasmTableObject*> ReadBarrieredWasmTableObject;
|
|||
|
||||
typedef ReadBarriered<Value> ReadBarrieredValue;
|
||||
|
||||
namespace detail {
|
||||
|
||||
template <typename T>
|
||||
struct DefineComparisonOps<PreBarriered<T>> : mozilla::TrueType {
|
||||
static const T& get(const PreBarriered<T>& v) { return v.get(); }
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct DefineComparisonOps<GCPtr<T>> : mozilla::TrueType {
|
||||
static const T& get(const GCPtr<T>& v) { return v.get(); }
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct DefineComparisonOps<HeapPtr<T>> : mozilla::TrueType {
|
||||
static const T& get(const HeapPtr<T>& v) { return v.get(); }
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct DefineComparisonOps<ReadBarriered<T>> : mozilla::TrueType {
|
||||
static const T& get(const ReadBarriered<T>& v) { return v.unbarrieredGet(); }
|
||||
};
|
||||
|
||||
template <>
|
||||
struct DefineComparisonOps<HeapSlot> : mozilla::TrueType {
|
||||
static const Value& get(const HeapSlot& v) { return v.get(); }
|
||||
};
|
||||
|
||||
} /* namespace detail */
|
||||
|
||||
|
||||
} /* namespace js */
|
||||
|
||||
#endif /* gc_Barrier_h */
|
||||
|
|
|
|||
|
|
@ -317,10 +317,6 @@ class TenuredCell : public Cell
|
|||
MOZ_ALWAYS_INLINE void unmark(uint32_t color) const;
|
||||
MOZ_ALWAYS_INLINE void copyMarkBitsFrom(const TenuredCell* src);
|
||||
|
||||
// Note: this is in TenuredCell because JSObject subclasses are sometimes
|
||||
// used tagged.
|
||||
static MOZ_ALWAYS_INLINE bool isNullLike(const Cell* thing) { return !thing; }
|
||||
|
||||
// Access to the arena.
|
||||
inline Arena* arena() const;
|
||||
inline AllocKind getAllocKind() const;
|
||||
|
|
@ -1302,7 +1298,7 @@ TenuredCell::isInsideZone(JS::Zone* zone) const
|
|||
TenuredCell::readBarrier(TenuredCell* thing)
|
||||
{
|
||||
MOZ_ASSERT(!CurrentThreadIsIonCompiling());
|
||||
MOZ_ASSERT(!isNullLike(thing));
|
||||
MOZ_ASSERT(thing);
|
||||
|
||||
// It would be good if barriers were never triggered during collection, but
|
||||
// at the moment this can happen e.g. when rekeying tables containing
|
||||
|
|
@ -1335,7 +1331,6 @@ AssertSafeToSkipBarrier(TenuredCell* thing);
|
|||
TenuredCell::writeBarrierPre(TenuredCell* thing)
|
||||
{
|
||||
MOZ_ASSERT(!CurrentThreadIsIonCompiling());
|
||||
MOZ_ASSERT_IF(thing, !isNullLike(thing));
|
||||
if (!thing)
|
||||
return;
|
||||
|
||||
|
|
|
|||
|
|
@ -501,7 +501,7 @@ void
|
|||
js::TraceNullableRoot(JSTracer* trc, T* thingp, const char* name)
|
||||
{
|
||||
AssertRootMarkingPhase(trc);
|
||||
if (InternalBarrierMethods<T>::isMarkableTaggedPointer(*thingp))
|
||||
if (InternalBarrierMethods<T>::isMarkable(*thingp))
|
||||
DispatchToTracer(trc, ConvertToBase(thingp), name);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -414,14 +414,6 @@ ToMarkable(Cell* cell)
|
|||
return cell;
|
||||
}
|
||||
|
||||
// Return true if the pointer is nullptr, or if it is a tagged pointer to
|
||||
// nullptr.
|
||||
MOZ_ALWAYS_INLINE bool
|
||||
IsNullTaggedPointer(void* p)
|
||||
{
|
||||
return uintptr_t(p) <= LargestTaggedNullCellPointer;
|
||||
}
|
||||
|
||||
// Wrap a GC thing pointer into a new Value or jsid. The type system enforces
|
||||
// that the thing pointer is a wrappable type.
|
||||
template <typename S, typename T>
|
||||
|
|
|
|||
|
|
@ -1145,9 +1145,9 @@ TryAttachNativeOrUnboxedGetValueElemStub(JSContext* cx, HandleScript script, jsb
|
|||
return true;
|
||||
bool needsAtomize = checkAtomize<T>(keyVal);
|
||||
|
||||
RootedShape shape(cx);
|
||||
Rooted<PropertyResult> prop(cx);
|
||||
RootedObject holder(cx);
|
||||
if (!EffectlesslyLookupProperty(cx, obj, id, &holder, &shape))
|
||||
if (!EffectlesslyLookupProperty(cx, obj, id, &holder, &prop))
|
||||
return false;
|
||||
if (!holder || (holder != obj && !holder->isNative()))
|
||||
return true;
|
||||
|
|
@ -1214,6 +1214,8 @@ TryAttachNativeOrUnboxedGetValueElemStub(JSContext* cx, HandleScript script, jsb
|
|||
if (!holder->isNative())
|
||||
return true;
|
||||
|
||||
RootedShape shape(cx, prop.shape());
|
||||
|
||||
if (IsCacheableGetPropReadSlot(obj, holder, shape)) {
|
||||
bool isFixedSlot;
|
||||
uint32_t offset;
|
||||
|
|
@ -1264,13 +1266,14 @@ TryAttachNativeGetAccessorElemStub(JSContext* cx, HandleScript script, jsbytecod
|
|||
return true;
|
||||
bool needsAtomize = checkAtomize<T>(keyVal);
|
||||
|
||||
RootedShape shape(cx);
|
||||
Rooted<PropertyResult> prop(cx);
|
||||
RootedObject baseHolder(cx);
|
||||
if (!EffectlesslyLookupProperty(cx, obj, id, &baseHolder, &shape))
|
||||
if (!EffectlesslyLookupProperty(cx, obj, id, &baseHolder, &prop))
|
||||
return false;
|
||||
if (!baseHolder || !baseHolder->isNative())
|
||||
return true;
|
||||
|
||||
RootedShape shape(cx, prop.shape());
|
||||
HandleNativeObject holder = baseHolder.as<NativeObject>();
|
||||
|
||||
bool getterIsScripted = false;
|
||||
|
|
@ -3348,11 +3351,17 @@ TryAttachNativeInStub(JSContext* cx, HandleScript outerScript, ICIn_Fallback* st
|
|||
return true;
|
||||
|
||||
RootedPropertyName name(cx, JSID_TO_ATOM(id)->asPropertyName());
|
||||
RootedShape shape(cx);
|
||||
Rooted<PropertyResult> prop(cx);
|
||||
RootedObject holder(cx);
|
||||
if (!EffectlesslyLookupProperty(cx, obj, id, &holder, &shape))
|
||||
if (!EffectlesslyLookupProperty(cx, obj, id, &holder, &prop))
|
||||
return false;
|
||||
|
||||
if (prop.isNonNativeProperty()) {
|
||||
MOZ_ASSERT(!IsCacheableProtoChain(obj, holder, false));
|
||||
return true;
|
||||
}
|
||||
|
||||
RootedShape shape(cx, prop.maybeShape());
|
||||
if (IsCacheableGetPropReadSlot(obj, holder, shape)) {
|
||||
ICStub::Kind kind = (obj == holder) ? ICStub::In_Native
|
||||
: ICStub::In_NativePrototype;
|
||||
|
|
@ -4259,14 +4268,17 @@ TryAttachSetValuePropStub(JSContext* cx, HandleScript script, jsbytecode* pc, IC
|
|||
{
|
||||
MOZ_ASSERT(!*attached);
|
||||
|
||||
RootedShape shape(cx);
|
||||
Rooted<PropertyResult> prop(cx);
|
||||
RootedObject holder(cx);
|
||||
if (!EffectlesslyLookupProperty(cx, obj, id, &holder, &shape))
|
||||
if (!EffectlesslyLookupProperty(cx, obj, id, &holder, &prop))
|
||||
return false;
|
||||
if (obj != holder)
|
||||
return true;
|
||||
|
||||
if (!obj->isNative()) {
|
||||
RootedShape shape(cx);
|
||||
if (obj->isNative()) {
|
||||
shape = prop.shape();
|
||||
} else {
|
||||
if (obj->is<UnboxedPlainObject>()) {
|
||||
UnboxedExpandoObject* expando = obj->as<UnboxedPlainObject>().maybeExpando();
|
||||
if (expando) {
|
||||
|
|
@ -4365,11 +4377,17 @@ TryAttachSetAccessorPropStub(JSContext* cx, HandleScript script, jsbytecode* pc,
|
|||
MOZ_ASSERT(!*attached);
|
||||
MOZ_ASSERT(!*isTemporarilyUnoptimizable);
|
||||
|
||||
RootedShape shape(cx);
|
||||
Rooted<PropertyResult> prop(cx);
|
||||
RootedObject holder(cx);
|
||||
if (!EffectlesslyLookupProperty(cx, obj, id, &holder, &shape))
|
||||
if (!EffectlesslyLookupProperty(cx, obj, id, &holder, &prop))
|
||||
return false;
|
||||
|
||||
if (prop.isNonNativeProperty()) {
|
||||
MOZ_ASSERT(!IsCacheableProtoChain(obj, holder));
|
||||
return true;
|
||||
}
|
||||
|
||||
RootedShape shape(cx, prop.maybeShape());
|
||||
bool isScripted = false;
|
||||
bool cacheableCall = IsCacheableSetPropCall(cx, obj, holder, shape,
|
||||
&isScripted, isTemporarilyUnoptimizable);
|
||||
|
|
|
|||
|
|
@ -109,7 +109,8 @@ CanAttachNativeGetProp(JSContext* cx, HandleObject obj, HandleId id,
|
|||
// only miss out on shape hashification, which is only a temporary perf cost.
|
||||
// The limits were arbitrarily set, anyways.
|
||||
JSObject* baseHolder = nullptr;
|
||||
if (!LookupPropertyPure(cx, obj, id, &baseHolder, shape.address()))
|
||||
PropertyResult prop;
|
||||
if (!LookupPropertyPure(cx, obj, id, &baseHolder, &prop))
|
||||
return CanAttachNone;
|
||||
|
||||
MOZ_ASSERT(!holder);
|
||||
|
|
@ -118,8 +119,9 @@ CanAttachNativeGetProp(JSContext* cx, HandleObject obj, HandleId id,
|
|||
return CanAttachNone;
|
||||
holder.set(&baseHolder->as<NativeObject>());
|
||||
}
|
||||
shape.set(prop.maybeShape());
|
||||
|
||||
if (IsCacheableGetPropReadSlotForIonOrCacheIR(obj, holder, shape) ||
|
||||
if (IsCacheableGetPropReadSlotForIonOrCacheIR(obj, holder, prop) ||
|
||||
IsCacheableNoProperty(cx, obj, holder, shape, id, pc))
|
||||
{
|
||||
return CanAttachReadSlot;
|
||||
|
|
|
|||
|
|
@ -468,11 +468,12 @@ jit::IsCacheableProtoChainForIonOrCacheIR(JSObject* obj, JSObject* holder)
|
|||
}
|
||||
|
||||
bool
|
||||
jit::IsCacheableGetPropReadSlotForIonOrCacheIR(JSObject* obj, JSObject* holder, Shape* shape)
|
||||
jit::IsCacheableGetPropReadSlotForIonOrCacheIR(JSObject* obj, JSObject* holder, PropertyResult prop)
|
||||
{
|
||||
if (!shape || !IsCacheableProtoChainForIonOrCacheIR(obj, holder))
|
||||
if (!prop || !IsCacheableProtoChainForIonOrCacheIR(obj, holder))
|
||||
return false;
|
||||
|
||||
Shape* shape = prop.shape();
|
||||
if (!shape->hasSlot() || !shape->hasDefaultGetter())
|
||||
return false;
|
||||
|
||||
|
|
@ -480,10 +481,10 @@ jit::IsCacheableGetPropReadSlotForIonOrCacheIR(JSObject* obj, JSObject* holder,
|
|||
}
|
||||
|
||||
static bool
|
||||
IsCacheableNoProperty(JSObject* obj, JSObject* holder, Shape* shape, jsbytecode* pc,
|
||||
IsCacheableNoProperty(JSObject* obj, JSObject* holder, PropertyResult prop, jsbytecode* pc,
|
||||
const TypedOrValueRegister& output)
|
||||
{
|
||||
if (shape)
|
||||
if (prop)
|
||||
return false;
|
||||
|
||||
MOZ_ASSERT(!holder);
|
||||
|
|
@ -751,7 +752,7 @@ CheckDOMProxyExpandoDoesNotShadow(JSContext* cx, MacroAssembler& masm, JSObject*
|
|||
static void
|
||||
GenerateReadSlot(JSContext* cx, IonScript* ion, MacroAssembler& masm,
|
||||
IonCache::StubAttacher& attacher, MaybeCheckTDZ checkTDZ,
|
||||
JSObject* obj, JSObject* holder, Shape* shape, Register object,
|
||||
JSObject* obj, JSObject* holder, PropertyResult prop, Register object,
|
||||
TypedOrValueRegister output, Label* failures = nullptr)
|
||||
{
|
||||
// If there's a single jump to |failures|, we can patch the shape guard
|
||||
|
|
@ -778,7 +779,7 @@ GenerateReadSlot(JSContext* cx, IonScript* ion, MacroAssembler& masm,
|
|||
|
||||
if (obj != holder ||
|
||||
obj->is<UnboxedPlainObject>() ||
|
||||
!holder->as<NativeObject>().isFixedSlot(shape->slot()))
|
||||
!holder->as<NativeObject>().isFixedSlot(prop.shape()->slot()))
|
||||
{
|
||||
if (output.hasValue()) {
|
||||
scratchReg = output.valueReg().scratchReg();
|
||||
|
|
@ -793,7 +794,7 @@ GenerateReadSlot(JSContext* cx, IonScript* ion, MacroAssembler& masm,
|
|||
|
||||
// Fast path: single failure jump, no prototype guards.
|
||||
if (!multipleFailureJumps) {
|
||||
EmitLoadSlot(masm, &holder->as<NativeObject>(), shape, object, output, scratchReg);
|
||||
EmitLoadSlot(masm, &holder->as<NativeObject>(), prop.shape(), object, output, scratchReg);
|
||||
if (restoreScratch)
|
||||
masm.pop(scratchReg);
|
||||
attacher.jumpRejoin(masm);
|
||||
|
|
@ -848,7 +849,8 @@ GenerateReadSlot(JSContext* cx, IonScript* ion, MacroAssembler& masm,
|
|||
|
||||
// Slot access.
|
||||
if (holder) {
|
||||
EmitLoadSlot(masm, &holder->as<NativeObject>(), shape, holderReg, output, scratchReg);
|
||||
EmitLoadSlot(masm, &holder->as<NativeObject>(), prop.shape(), holderReg, output,
|
||||
scratchReg);
|
||||
if (checkTDZ && output.hasValue())
|
||||
masm.branchTestMagic(Assembler::Equal, output.valueReg(), failures);
|
||||
} else {
|
||||
|
|
@ -1294,7 +1296,8 @@ CanAttachNativeGetProp(JSContext* cx, const GetPropCache& cache,
|
|||
// only miss out on shape hashification, which is only a temporary perf cost.
|
||||
// The limits were arbitrarily set, anyways.
|
||||
JSObject* baseHolder = nullptr;
|
||||
if (!LookupPropertyPure(cx, obj, id, &baseHolder, shape.address()))
|
||||
PropertyResult prop;
|
||||
if (!LookupPropertyPure(cx, obj, id, &baseHolder, &prop))
|
||||
return GetPropertyIC::CanAttachNone;
|
||||
|
||||
MOZ_ASSERT(!holder);
|
||||
|
|
@ -1303,12 +1306,13 @@ CanAttachNativeGetProp(JSContext* cx, const GetPropCache& cache,
|
|||
return GetPropertyIC::CanAttachNone;
|
||||
holder.set(&baseHolder->as<NativeObject>());
|
||||
}
|
||||
shape.set(prop.maybeShape());
|
||||
|
||||
RootedScript script(cx);
|
||||
jsbytecode* pc;
|
||||
cache.getScriptedLocation(&script, &pc);
|
||||
if (IsCacheableGetPropReadSlotForIonOrCacheIR(obj, holder, shape) ||
|
||||
IsCacheableNoProperty(obj, holder, shape, pc, cache.output()))
|
||||
if (IsCacheableGetPropReadSlotForIonOrCacheIR(obj, holder, prop) ||
|
||||
IsCacheableNoProperty(obj, holder, prop, pc, cache.output()))
|
||||
{
|
||||
return GetPropertyIC::CanAttachReadSlot;
|
||||
}
|
||||
|
|
@ -1505,7 +1509,7 @@ GetPropertyIC::tryAttachNative(JSContext* cx, HandleScript outerScript, IonScrip
|
|||
switch (type) {
|
||||
case CanAttachReadSlot:
|
||||
GenerateReadSlot(cx, ion, masm, attacher, DontCheckTDZ, obj, holder,
|
||||
shape, object(), output(), maybeFailures);
|
||||
PropertyResult(shape), object(), output(), maybeFailures);
|
||||
attachKind = idempotent() ? "idempotent reading"
|
||||
: "non idempotent reading";
|
||||
outcome = JS::TrackedOutcome::ICGetPropStub_ReadSlot;
|
||||
|
|
@ -1588,7 +1592,7 @@ GetPropertyIC::tryAttachUnboxedExpando(JSContext* cx, HandleScript outerScript,
|
|||
|
||||
StubAttacher attacher(*this);
|
||||
GenerateReadSlot(cx, ion, masm, attacher, DontCheckTDZ, obj, obj,
|
||||
shape, object(), output(), maybeFailures);
|
||||
PropertyResult(shape), object(), output(), maybeFailures);
|
||||
return linkAndAttachStub(cx, masm, attacher, ion, "read unboxed expando",
|
||||
JS::TrackedOutcome::ICGetPropStub_UnboxedReadExpando);
|
||||
}
|
||||
|
|
@ -2927,12 +2931,14 @@ IsCacheableDOMProxyUnshadowedSetterCall(JSContext* cx, HandleObject obj, HandleI
|
|||
if (!checkObj)
|
||||
return false;
|
||||
|
||||
if (!LookupPropertyPure(cx, obj, id, holder.address(), shape.address()))
|
||||
PropertyResult prop;
|
||||
if (!LookupPropertyPure(cx, obj, id, holder.address(), &prop))
|
||||
return false;
|
||||
|
||||
if (!holder)
|
||||
if (!holder || !holder->isNative())
|
||||
return false;
|
||||
|
||||
shape.set(prop.shape());
|
||||
return IsCacheableSetPropCallNative(checkObj, holder, shape) ||
|
||||
IsCacheableSetPropCallPropertyOp(checkObj, holder, shape) ||
|
||||
IsCacheableSetPropCallScripted(checkObj, holder, shape);
|
||||
|
|
@ -3344,22 +3350,26 @@ CanAttachNativeSetProp(JSContext* cx, HandleObject obj, HandleId id, const Const
|
|||
|
||||
// If we couldn't find the property on the object itself, do a full, but
|
||||
// still pure lookup for setters.
|
||||
if (!LookupPropertyPure(cx, obj, id, holder.address(), shape.address()))
|
||||
Rooted<PropertyResult> prop(cx);
|
||||
if (!LookupPropertyPure(cx, obj, id, holder.address(), prop.address()))
|
||||
return SetPropertyIC::CanAttachNone;
|
||||
|
||||
// If the object doesn't have the property, we don't know if we can attach
|
||||
// a stub to add the property until we do the VM call to add. If the
|
||||
// property exists as a data property on the prototype, we should add
|
||||
// a new, shadowing property.
|
||||
if (obj->isNative() && (!shape || (obj != holder && holder->isNative() &&
|
||||
shape->hasDefaultSetter() && shape->hasSlot())))
|
||||
if (obj->isNative() &&
|
||||
(!prop || (obj != holder && holder->isNative() &&
|
||||
prop.shape()->hasDefaultSetter() && prop.shape()->hasSlot())))
|
||||
{
|
||||
shape.set(prop.maybeShape());
|
||||
return SetPropertyIC::MaybeCanAttachAddSlot;
|
||||
}
|
||||
|
||||
if (IsImplicitNonNativeProperty(shape))
|
||||
if (prop.isNonNativeProperty())
|
||||
return SetPropertyIC::CanAttachNone;
|
||||
|
||||
shape.set(prop.maybeShape());
|
||||
if (IsCacheableSetPropCallPropertyOp(obj, holder, shape) ||
|
||||
IsCacheableSetPropCallNative(obj, holder, shape) ||
|
||||
IsCacheableSetPropCallScripted(obj, holder, shape))
|
||||
|
|
@ -4836,7 +4846,7 @@ BindNameIC::update(JSContext* cx, HandleScript outerScript, size_t cacheIndex,
|
|||
bool
|
||||
NameIC::attachReadSlot(JSContext* cx, HandleScript outerScript, IonScript* ion,
|
||||
HandleObject envChain, HandleObject holderBase,
|
||||
HandleNativeObject holder, HandleShape shape)
|
||||
HandleNativeObject holder, Handle<PropertyResult> prop)
|
||||
{
|
||||
MacroAssembler masm(cx, ion, outerScript, profilerLeavePc_);
|
||||
Label failures;
|
||||
|
|
@ -4854,7 +4864,7 @@ NameIC::attachReadSlot(JSContext* cx, HandleScript outerScript, IonScript* ion,
|
|||
// doesn't generate the extra guard.
|
||||
//
|
||||
// NAME ops must do their own TDZ checks.
|
||||
GenerateReadSlot(cx, ion, masm, attacher, CheckTDZ, holderBase, holder, shape, scratchReg,
|
||||
GenerateReadSlot(cx, ion, masm, attacher, CheckTDZ, holderBase, holder, prop, scratchReg,
|
||||
outputReg(), failures.used() ? &failures : nullptr);
|
||||
|
||||
return linkAndAttachStub(cx, masm, attacher, ion, "generic",
|
||||
|
|
@ -4880,26 +4890,26 @@ IsCacheableEnvironmentChain(JSObject* envChain, JSObject* obj)
|
|||
}
|
||||
|
||||
static bool
|
||||
IsCacheableNameReadSlot(HandleObject envChain, HandleObject obj,
|
||||
HandleObject holder, HandleShape shape, jsbytecode* pc,
|
||||
IsCacheableNameReadSlot(JSContext* cx, HandleObject envChain, HandleObject obj,
|
||||
HandleObject holder, Handle<PropertyResult> prop, jsbytecode* pc,
|
||||
const TypedOrValueRegister& output)
|
||||
{
|
||||
if (!shape)
|
||||
if (!prop)
|
||||
return false;
|
||||
if (!obj->isNative())
|
||||
return false;
|
||||
|
||||
if (obj->is<GlobalObject>()) {
|
||||
// Support only simple property lookups.
|
||||
if (!IsCacheableGetPropReadSlotForIonOrCacheIR(obj, holder, shape) &&
|
||||
!IsCacheableNoProperty(obj, holder, shape, pc, output))
|
||||
if (!IsCacheableGetPropReadSlotForIonOrCacheIR(obj, holder, prop) &&
|
||||
!IsCacheableNoProperty(obj, holder, prop, pc, output))
|
||||
return false;
|
||||
} else if (obj->is<ModuleEnvironmentObject>()) {
|
||||
// We don't yet support lookups in a module environment.
|
||||
return false;
|
||||
} else if (obj->is<CallObject>()) {
|
||||
MOZ_ASSERT(obj == holder);
|
||||
if (!shape->hasDefaultGetter())
|
||||
if (!prop.shape()->hasDefaultGetter())
|
||||
return false;
|
||||
} else {
|
||||
// We don't yet support lookups on Block or DeclEnv objects.
|
||||
|
|
@ -4942,9 +4952,9 @@ NameIC::attachCallGetter(JSContext* cx, HandleScript outerScript, IonScript* ion
|
|||
|
||||
static bool
|
||||
IsCacheableNameCallGetter(HandleObject envChain, HandleObject obj, HandleObject holder,
|
||||
HandleShape shape)
|
||||
Handle<PropertyResult> prop)
|
||||
{
|
||||
if (!shape)
|
||||
if (!prop)
|
||||
return false;
|
||||
if (!obj->is<GlobalObject>())
|
||||
return false;
|
||||
|
|
@ -4952,6 +4962,10 @@ IsCacheableNameCallGetter(HandleObject envChain, HandleObject obj, HandleObject
|
|||
if (!IsCacheableEnvironmentChain(envChain, obj))
|
||||
return false;
|
||||
|
||||
if (!prop || !IsCacheableProtoChainForIonOrCacheIR(obj, holder))
|
||||
return false;
|
||||
|
||||
Shape* shape = prop.shape();
|
||||
return IsCacheableGetPropCallNative(obj, holder, shape) ||
|
||||
IsCacheableGetPropCallPropertyOp(obj, holder, shape) ||
|
||||
IsCacheableGetPropCallScripted(obj, holder, shape);
|
||||
|
|
@ -4996,10 +5010,10 @@ NameIC::attachTypeOfNoProperty(JSContext* cx, HandleScript outerScript, IonScrip
|
|||
|
||||
static bool
|
||||
IsCacheableNameNoProperty(HandleObject envChain, HandleObject obj,
|
||||
HandleObject holder, HandleShape shape, jsbytecode* pc,
|
||||
HandleObject holder, Handle<PropertyResult> prop, jsbytecode* pc,
|
||||
NameIC& cache)
|
||||
{
|
||||
if (cache.isTypeOf() && !shape) {
|
||||
if (cache.isTypeOf() && !prop) {
|
||||
MOZ_ASSERT(!obj);
|
||||
MOZ_ASSERT(!holder);
|
||||
MOZ_ASSERT(envChain);
|
||||
|
|
@ -5029,34 +5043,35 @@ NameIC::update(JSContext* cx, HandleScript outerScript, size_t cacheIndex, Handl
|
|||
|
||||
RootedObject obj(cx);
|
||||
RootedObject holder(cx);
|
||||
RootedShape shape(cx);
|
||||
if (!LookupName(cx, name, envChain, &obj, &holder, &shape))
|
||||
Rooted<PropertyResult> prop(cx);
|
||||
if (!LookupName(cx, name, envChain, &obj, &holder, &prop))
|
||||
return false;
|
||||
|
||||
// Look first. Don't generate cache entries if the lookup fails.
|
||||
if (cache.isTypeOf()) {
|
||||
if (!FetchName<true>(cx, obj, holder, name, shape, vp))
|
||||
if (!FetchName<true>(cx, obj, holder, name, prop, vp))
|
||||
return false;
|
||||
} else {
|
||||
if (!FetchName<false>(cx, obj, holder, name, shape, vp))
|
||||
if (!FetchName<false>(cx, obj, holder, name, prop, vp))
|
||||
return false;
|
||||
}
|
||||
|
||||
if (cache.canAttachStub()) {
|
||||
if (IsCacheableNameReadSlot(envChain, obj, holder, shape, pc, cache.outputReg())) {
|
||||
if (IsCacheableNameReadSlot(cx, envChain, obj, holder, prop, pc, cache.outputReg())) {
|
||||
if (!cache.attachReadSlot(cx, outerScript, ion, envChain, obj,
|
||||
holder.as<NativeObject>(), shape))
|
||||
holder.as<NativeObject>(), prop))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
} else if (IsCacheableNameCallGetter(envChain, obj, holder, shape)) {
|
||||
} else if (IsCacheableNameCallGetter(envChain, obj, holder, prop)) {
|
||||
void* returnAddr = GetReturnAddressToIonCode(cx);
|
||||
RootedShape shape(cx, prop.shape());
|
||||
if (!cache.attachCallGetter(cx, outerScript, ion, envChain, obj, holder, shape,
|
||||
returnAddr))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
} else if (IsCacheableNameNoProperty(envChain, obj, holder, shape, pc, cache)) {
|
||||
} else if (IsCacheableNameNoProperty(envChain, obj, holder, prop, pc, cache)) {
|
||||
if (!cache.attachTypeOfNoProperty(cx, outerScript, ion, envChain))
|
||||
return false;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -806,7 +806,7 @@ class NameIC : public IonCache
|
|||
|
||||
MOZ_MUST_USE bool attachReadSlot(JSContext* cx, HandleScript outerScript, IonScript* ion,
|
||||
HandleObject envChain, HandleObject holderBase,
|
||||
HandleNativeObject holder, HandleShape shape);
|
||||
HandleNativeObject holder, Handle<PropertyResult> prop);
|
||||
|
||||
MOZ_MUST_USE bool attachCallGetter(JSContext* cx, HandleScript outerScript, IonScript* ion,
|
||||
HandleObject envChain, HandleObject obj,
|
||||
|
|
@ -839,7 +839,7 @@ IONCACHE_KIND_LIST(CACHE_CASTS)
|
|||
#undef OPCODE_CASTS
|
||||
|
||||
bool IsCacheableProtoChainForIonOrCacheIR(JSObject* obj, JSObject* holder);
|
||||
bool IsCacheableGetPropReadSlotForIonOrCacheIR(JSObject* obj, JSObject* holder, Shape* shape);
|
||||
bool IsCacheableGetPropReadSlotForIonOrCacheIR(JSObject* obj, JSObject* holder, PropertyResult prop);
|
||||
|
||||
} // namespace jit
|
||||
} // namespace js
|
||||
|
|
|
|||
|
|
@ -2192,12 +2192,12 @@ GetDOMProxyProto(JSObject* obj)
|
|||
// existence of the property on the object.
|
||||
bool
|
||||
EffectlesslyLookupProperty(JSContext* cx, HandleObject obj, HandleId id,
|
||||
MutableHandleObject holder, MutableHandleShape shape,
|
||||
MutableHandleObject holder, MutableHandle<PropertyResult> prop,
|
||||
bool* checkDOMProxy,
|
||||
DOMProxyShadowsResult* shadowsResult,
|
||||
bool* domProxyHasGeneration)
|
||||
{
|
||||
shape.set(nullptr);
|
||||
prop.setNotFound();
|
||||
holder.set(nullptr);
|
||||
|
||||
if (checkDOMProxy) {
|
||||
|
|
@ -2231,11 +2231,11 @@ EffectlesslyLookupProperty(JSContext* cx, HandleObject obj, HandleId id,
|
|||
return true;
|
||||
}
|
||||
|
||||
if (LookupPropertyPure(cx, checkObj, id, holder.address(), shape.address()))
|
||||
if (LookupPropertyPure(cx, checkObj, id, holder.address(), prop.address()))
|
||||
return true;
|
||||
|
||||
holder.set(nullptr);
|
||||
shape.set(nullptr);
|
||||
prop.setNotFound();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -2421,15 +2421,16 @@ TryAttachNativeGetAccessorPropStub(JSContext* cx, SharedStubInfo* info,
|
|||
bool isDOMProxy;
|
||||
bool domProxyHasGeneration;
|
||||
DOMProxyShadowsResult domProxyShadowsResult;
|
||||
RootedShape shape(cx);
|
||||
Rooted<PropertyResult> prop(cx);
|
||||
RootedObject holder(cx);
|
||||
RootedId id(cx, NameToId(name));
|
||||
if (!EffectlesslyLookupProperty(cx, obj, id, &holder, &shape, &isDOMProxy,
|
||||
if (!EffectlesslyLookupProperty(cx, obj, id, &holder, &prop, &isDOMProxy,
|
||||
&domProxyShadowsResult, &domProxyHasGeneration))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
RootedShape shape(cx, prop.maybeShape());
|
||||
ICStub* monitorStub = stub->fallbackMonitorStub()->firstMonitorStub();
|
||||
|
||||
bool isScripted = false;
|
||||
|
|
@ -2492,7 +2493,7 @@ TryAttachNativeGetAccessorPropStub(JSContext* cx, SharedStubInfo* info,
|
|||
MOZ_ASSERT(ToWindowIfWindowProxy(obj) == cx->global());
|
||||
obj = cx->global();
|
||||
|
||||
if (!EffectlesslyLookupProperty(cx, obj, id, &holder, &shape, &isDOMProxy,
|
||||
if (!EffectlesslyLookupProperty(cx, obj, id, &holder, &prop, &isDOMProxy,
|
||||
&domProxyShadowsResult, &domProxyHasGeneration))
|
||||
{
|
||||
return false;
|
||||
|
|
|
|||
|
|
@ -2249,7 +2249,7 @@ StripPreliminaryObjectStubs(JSContext* cx, ICFallbackStub* stub);
|
|||
|
||||
MOZ_MUST_USE bool
|
||||
EffectlesslyLookupProperty(JSContext* cx, HandleObject obj, HandleId name,
|
||||
MutableHandleObject holder, MutableHandleShape shape,
|
||||
MutableHandleObject holder, MutableHandle<PropertyResult> prop,
|
||||
bool* checkDOMProxy=nullptr,
|
||||
DOMProxyShadowsResult* shadowsResult=nullptr,
|
||||
bool* domProxyHasGeneration=nullptr);
|
||||
|
|
|
|||
|
|
@ -583,11 +583,11 @@ GetDynamicName(JSContext* cx, JSObject* envChain, JSString* str, Value* vp)
|
|||
return;
|
||||
}
|
||||
|
||||
Shape* shape = nullptr;
|
||||
PropertyResult prop;
|
||||
JSObject* scope = nullptr;
|
||||
JSObject* pobj = nullptr;
|
||||
if (LookupNameNoGC(cx, atom->asPropertyName(), envChain, &scope, &pobj, &shape)) {
|
||||
if (FetchNameNoGC(pobj, shape, MutableHandleValue::fromMarkedLocation(vp)))
|
||||
if (LookupNameNoGC(cx, atom->asPropertyName(), envChain, &scope, &pobj, &prop)) {
|
||||
if (FetchNameNoGC(pobj, prop, MutableHandleValue::fromMarkedLocation(vp)))
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -56,19 +56,10 @@ struct MyContainer
|
|||
};
|
||||
|
||||
namespace js {
|
||||
template <>
|
||||
struct RootedBase<MyContainer> {
|
||||
HeapPtr<JSObject*>& obj() { return static_cast<Rooted<MyContainer>*>(this)->get().obj; }
|
||||
HeapPtr<JSString*>& str() { return static_cast<Rooted<MyContainer>*>(this)->get().str; }
|
||||
};
|
||||
template <>
|
||||
struct PersistentRootedBase<MyContainer> {
|
||||
HeapPtr<JSObject*>& obj() {
|
||||
return static_cast<PersistentRooted<MyContainer>*>(this)->get().obj;
|
||||
}
|
||||
HeapPtr<JSString*>& str() {
|
||||
return static_cast<PersistentRooted<MyContainer>*>(this)->get().str;
|
||||
}
|
||||
template <typename Wrapper>
|
||||
struct MutableWrappedPtrOperations<MyContainer, Wrapper> {
|
||||
HeapPtr<JSObject*>& obj() { return static_cast<Wrapper*>(this)->get().obj; }
|
||||
HeapPtr<JSString*>& str() { return static_cast<Wrapper*>(this)->get().str; }
|
||||
};
|
||||
} // namespace js
|
||||
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@
|
|||
* 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/. */
|
||||
|
||||
#include "mozilla/TypeTraits.h"
|
||||
#include "mozilla/UniquePtr.h"
|
||||
|
||||
#include "js/RootingAPI.h"
|
||||
|
|
@ -146,3 +147,110 @@ TestHeapPostBarrierInitFailure()
|
|||
}
|
||||
|
||||
END_TEST(testGCHeapPostBarriers)
|
||||
|
||||
BEGIN_TEST(testUnbarrieredEquality)
|
||||
{
|
||||
// Use ArrayBuffers because they have finalizers, which allows using them
|
||||
// in ObjectPtr without awkward conversations about nursery allocatability.
|
||||
JS::RootedObject robj(cx, JS_NewArrayBuffer(cx, 20));
|
||||
JS::RootedObject robj2(cx, JS_NewArrayBuffer(cx, 30));
|
||||
cx->gc.evictNursery(); // Need tenured objects
|
||||
|
||||
// Need some bare pointers to compare against.
|
||||
JSObject* obj = robj;
|
||||
JSObject* obj2 = robj2;
|
||||
const JSObject* constobj = robj;
|
||||
const JSObject* constobj2 = robj2;
|
||||
|
||||
// Make them gray. We will make sure they stay gray. (For most reads, the
|
||||
// barrier will unmark gray.)
|
||||
using namespace js::gc;
|
||||
TenuredCell* cell = &obj->asTenured();
|
||||
TenuredCell* cell2 = &obj2->asTenured();
|
||||
cell->markIfUnmarked(GRAY);
|
||||
cell2->markIfUnmarked(GRAY);
|
||||
MOZ_ASSERT(cell->isMarked(GRAY));
|
||||
MOZ_ASSERT(cell2->isMarked(GRAY));
|
||||
|
||||
{
|
||||
JS::Heap<JSObject*> heap(obj);
|
||||
JS::Heap<JSObject*> heap2(obj2);
|
||||
CHECK(TestWrapper(obj, obj2, heap, heap2));
|
||||
CHECK(TestWrapper(constobj, constobj2, heap, heap2));
|
||||
}
|
||||
|
||||
{
|
||||
JS::TenuredHeap<JSObject*> heap(obj);
|
||||
JS::TenuredHeap<JSObject*> heap2(obj2);
|
||||
CHECK(TestWrapper(obj, obj2, heap, heap2));
|
||||
CHECK(TestWrapper(constobj, constobj2, heap, heap2));
|
||||
}
|
||||
|
||||
{
|
||||
JS::ObjectPtr objptr(obj);
|
||||
JS::ObjectPtr objptr2(obj2);
|
||||
CHECK(TestWrapper(obj, obj2, objptr, objptr2));
|
||||
CHECK(TestWrapper(constobj, constobj2, objptr, objptr2));
|
||||
objptr.finalize(cx);
|
||||
objptr2.finalize(cx);
|
||||
}
|
||||
// Sanity check that the barriers normally mark things black.
|
||||
{
|
||||
JS::Heap<JSObject*> heap(obj);
|
||||
JS::Heap<JSObject*> heap2(obj2);
|
||||
heap.get();
|
||||
heap2.get();
|
||||
CHECK(cell->isMarked(BLACK));
|
||||
CHECK(cell2->isMarked(BLACK));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename ObjectT, typename WrapperT>
|
||||
bool
|
||||
TestWrapper(ObjectT obj, ObjectT obj2, WrapperT& wrapper, WrapperT& wrapper2)
|
||||
{
|
||||
using namespace js::gc;
|
||||
|
||||
const TenuredCell& cell = obj->asTenured();
|
||||
const TenuredCell& cell2 = obj2->asTenured();
|
||||
|
||||
int x = 0;
|
||||
|
||||
CHECK(cell.isMarked(GRAY));
|
||||
CHECK(cell2.isMarked(GRAY));
|
||||
x += obj == obj2;
|
||||
CHECK(cell.isMarked(GRAY));
|
||||
CHECK(cell2.isMarked(GRAY));
|
||||
x += obj == wrapper2;
|
||||
CHECK(cell.isMarked(GRAY));
|
||||
CHECK(cell2.isMarked(GRAY));
|
||||
x += wrapper == obj2;
|
||||
CHECK(cell.isMarked(GRAY));
|
||||
CHECK(cell2.isMarked(GRAY));
|
||||
x += wrapper == wrapper2;
|
||||
CHECK(cell.isMarked(GRAY));
|
||||
CHECK(cell2.isMarked(GRAY));
|
||||
|
||||
CHECK(x == 0);
|
||||
|
||||
x += obj != obj2;
|
||||
CHECK(cell.isMarked(GRAY));
|
||||
CHECK(cell2.isMarked(GRAY));
|
||||
x += obj != wrapper2;
|
||||
CHECK(cell.isMarked(GRAY));
|
||||
CHECK(cell2.isMarked(GRAY));
|
||||
x += wrapper != obj2;
|
||||
CHECK(cell.isMarked(GRAY));
|
||||
CHECK(cell2.isMarked(GRAY));
|
||||
x += wrapper != wrapper2;
|
||||
CHECK(cell.isMarked(GRAY));
|
||||
CHECK(cell2.isMarked(GRAY));
|
||||
|
||||
CHECK(x == 4);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
END_TEST(testUnbarrieredEquality)
|
||||
|
|
|
|||
|
|
@ -2947,9 +2947,9 @@ JS_AlreadyHasOwnPropertyById(JSContext* cx, HandleObject obj, HandleId id, bool*
|
|||
return js::HasOwnProperty(cx, obj, id, foundp);
|
||||
|
||||
RootedNativeObject nativeObj(cx, &obj->as<NativeObject>());
|
||||
RootedShape prop(cx);
|
||||
Rooted<PropertyResult> prop(cx);
|
||||
NativeLookupOwnPropertyNoResolve(cx, nativeObj, id, &prop);
|
||||
*foundp = !!prop;
|
||||
*foundp = prop.isFound();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -2546,10 +2546,14 @@ struct JS_PUBLIC_API(PropertyDescriptor) {
|
|||
void trace(JSTracer* trc);
|
||||
};
|
||||
|
||||
template <typename Outer>
|
||||
class PropertyDescriptorOperations
|
||||
} // namespace JS
|
||||
|
||||
namespace js {
|
||||
|
||||
template <typename Wrapper>
|
||||
class WrappedPtrOperations<JS::PropertyDescriptor, Wrapper>
|
||||
{
|
||||
const PropertyDescriptor& desc() const { return static_cast<const Outer*>(this)->get(); }
|
||||
const JS::PropertyDescriptor& desc() const { return static_cast<const Wrapper*>(this)->get(); }
|
||||
|
||||
bool has(unsigned bit) const {
|
||||
MOZ_ASSERT(bit != 0);
|
||||
|
|
@ -2678,10 +2682,11 @@ class PropertyDescriptorOperations
|
|||
}
|
||||
};
|
||||
|
||||
template <typename Outer>
|
||||
class MutablePropertyDescriptorOperations : public PropertyDescriptorOperations<Outer>
|
||||
template <typename Wrapper>
|
||||
class MutableWrappedPtrOperations<JS::PropertyDescriptor, Wrapper>
|
||||
: public js::WrappedPtrOperations<JS::PropertyDescriptor, Wrapper>
|
||||
{
|
||||
PropertyDescriptor& desc() { return static_cast<Outer*>(this)->get(); }
|
||||
JS::PropertyDescriptor& desc() { return static_cast<Wrapper*>(this)->get(); }
|
||||
|
||||
public:
|
||||
void clear() {
|
||||
|
|
@ -2692,7 +2697,7 @@ class MutablePropertyDescriptorOperations : public PropertyDescriptorOperations<
|
|||
value().setUndefined();
|
||||
}
|
||||
|
||||
void initFields(HandleObject obj, HandleValue v, unsigned attrs,
|
||||
void initFields(JS::HandleObject obj, JS::HandleValue v, unsigned attrs,
|
||||
JSGetterOp getterOp, JSSetterOp setterOp) {
|
||||
MOZ_ASSERT(getterOp != JS_PropertyStub);
|
||||
MOZ_ASSERT(setterOp != JS_StrictPropertyStub);
|
||||
|
|
@ -2704,7 +2709,7 @@ class MutablePropertyDescriptorOperations : public PropertyDescriptorOperations<
|
|||
setSetter(setterOp);
|
||||
}
|
||||
|
||||
void assign(PropertyDescriptor& other) {
|
||||
void assign(JS::PropertyDescriptor& other) {
|
||||
object().set(other.obj);
|
||||
setAttributes(other.attrs);
|
||||
setGetter(other.getter);
|
||||
|
|
@ -2712,7 +2717,7 @@ class MutablePropertyDescriptorOperations : public PropertyDescriptorOperations<
|
|||
value().set(other.value);
|
||||
}
|
||||
|
||||
void setDataDescriptor(HandleValue v, unsigned attrs) {
|
||||
void setDataDescriptor(JS::HandleValue v, unsigned attrs) {
|
||||
MOZ_ASSERT((attrs & ~(JSPROP_ENUMERATE |
|
||||
JSPROP_PERMANENT |
|
||||
JSPROP_READONLY |
|
||||
|
|
@ -2787,26 +2792,7 @@ class MutablePropertyDescriptorOperations : public PropertyDescriptorOperations<
|
|||
}
|
||||
};
|
||||
|
||||
} /* namespace JS */
|
||||
|
||||
namespace js {
|
||||
|
||||
template <>
|
||||
class RootedBase<JS::PropertyDescriptor>
|
||||
: public JS::MutablePropertyDescriptorOperations<JS::Rooted<JS::PropertyDescriptor>>
|
||||
{};
|
||||
|
||||
template <>
|
||||
class HandleBase<JS::PropertyDescriptor>
|
||||
: public JS::PropertyDescriptorOperations<JS::Handle<JS::PropertyDescriptor>>
|
||||
{};
|
||||
|
||||
template <>
|
||||
class MutableHandleBase<JS::PropertyDescriptor>
|
||||
: public JS::MutablePropertyDescriptorOperations<JS::MutableHandle<JS::PropertyDescriptor>>
|
||||
{};
|
||||
|
||||
} /* namespace js */
|
||||
} // namespace js
|
||||
|
||||
namespace JS {
|
||||
|
||||
|
|
|
|||
|
|
@ -722,8 +722,9 @@ JSCompartment::sweepAfterMinorGC(JSTracer* trc)
|
|||
{
|
||||
globalWriteBarriered = 0;
|
||||
|
||||
if (innerViews.needsSweepAfterMinorGC())
|
||||
innerViews.sweepAfterMinorGC();
|
||||
InnerViewTable& table = innerViews.get();
|
||||
if (table.needsSweepAfterMinorGC())
|
||||
table.sweepAfterMinorGC();
|
||||
|
||||
crossCompartmentWrappers.sweepAfterMinorGC(trc);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -331,7 +331,7 @@ extern JS_FRIEND_DATA(const js::ObjectOps) ProxyObjectOps;
|
|||
|
||||
extern JS_FRIEND_API(bool)
|
||||
proxy_LookupProperty(JSContext* cx, JS::HandleObject obj, JS::HandleId id, JS::MutableHandleObject objp,
|
||||
JS::MutableHandle<Shape*> propp);
|
||||
JS::MutableHandle<JS::PropertyResult> propp);
|
||||
extern JS_FRIEND_API(bool)
|
||||
proxy_DefineProperty(JSContext* cx, JS::HandleObject obj, JS::HandleId id,
|
||||
JS::Handle<JS::PropertyDescriptor> desc,
|
||||
|
|
|
|||
104
js/src/jsobj.cpp
104
js/src/jsobj.cpp
|
|
@ -2116,7 +2116,7 @@ JSObject::constructHook() const
|
|||
|
||||
bool
|
||||
js::LookupProperty(JSContext* cx, HandleObject obj, js::HandleId id,
|
||||
MutableHandleObject objp, MutableHandleShape propp)
|
||||
MutableHandleObject objp, MutableHandle<PropertyResult> propp)
|
||||
{
|
||||
/* NB: The logic of lookupProperty is implicitly reflected in
|
||||
* BaselineIC.cpp's |EffectlesslyLookupProperty| logic.
|
||||
|
|
@ -2129,7 +2129,7 @@ js::LookupProperty(JSContext* cx, HandleObject obj, js::HandleId id,
|
|||
|
||||
bool
|
||||
js::LookupName(JSContext* cx, HandlePropertyName name, HandleObject envChain,
|
||||
MutableHandleObject objp, MutableHandleObject pobjp, MutableHandleShape propp)
|
||||
MutableHandleObject objp, MutableHandleObject pobjp, MutableHandle<PropertyResult> propp)
|
||||
{
|
||||
RootedId id(cx, NameToId(name));
|
||||
|
||||
|
|
@ -2144,13 +2144,13 @@ js::LookupName(JSContext* cx, HandlePropertyName name, HandleObject envChain,
|
|||
|
||||
objp.set(nullptr);
|
||||
pobjp.set(nullptr);
|
||||
propp.set(nullptr);
|
||||
propp.setNotFound();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
js::LookupNameNoGC(JSContext* cx, PropertyName* name, JSObject* envChain,
|
||||
JSObject** objp, JSObject** pobjp, Shape** propp)
|
||||
JSObject** objp, JSObject** pobjp, PropertyResult* propp)
|
||||
{
|
||||
AutoAssertNoException nogc(cx);
|
||||
|
||||
|
|
@ -2177,13 +2177,13 @@ js::LookupNameWithGlobalDefault(JSContext* cx, HandlePropertyName name, HandleOb
|
|||
RootedId id(cx, NameToId(name));
|
||||
|
||||
RootedObject pobj(cx);
|
||||
RootedShape shape(cx);
|
||||
Rooted<PropertyResult> prop(cx);
|
||||
|
||||
RootedObject env(cx, envChain);
|
||||
for (; !env->is<GlobalObject>(); env = env->enclosingEnvironment()) {
|
||||
if (!LookupProperty(cx, env, id, &pobj, &shape))
|
||||
if (!LookupProperty(cx, env, id, &pobj, &prop))
|
||||
return false;
|
||||
if (shape)
|
||||
if (prop)
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
@ -2198,20 +2198,20 @@ js::LookupNameUnqualified(JSContext* cx, HandlePropertyName name, HandleObject e
|
|||
RootedId id(cx, NameToId(name));
|
||||
|
||||
RootedObject pobj(cx);
|
||||
RootedShape shape(cx);
|
||||
Rooted<PropertyResult> prop(cx);
|
||||
|
||||
RootedObject env(cx, envChain);
|
||||
for (; !env->isUnqualifiedVarObj(); env = env->enclosingEnvironment()) {
|
||||
if (!LookupProperty(cx, env, id, &pobj, &shape))
|
||||
if (!LookupProperty(cx, env, id, &pobj, &prop))
|
||||
return false;
|
||||
if (shape)
|
||||
if (prop)
|
||||
break;
|
||||
}
|
||||
|
||||
// See note above RuntimeLexicalErrorObject.
|
||||
if (pobj == env) {
|
||||
bool isTDZ = false;
|
||||
if (shape && name != cx->names().dotThis) {
|
||||
if (prop && name != cx->names().dotThis) {
|
||||
// Treat Debugger environments specially for TDZ checks, as they
|
||||
// look like non-native environments but in fact wrap native
|
||||
// environments.
|
||||
|
|
@ -2222,7 +2222,7 @@ js::LookupNameUnqualified(JSContext* cx, HandlePropertyName name, HandleObject e
|
|||
return false;
|
||||
isTDZ = IsUninitializedLexical(v);
|
||||
} else {
|
||||
isTDZ = IsUninitializedLexicalSlot(env, shape);
|
||||
isTDZ = IsUninitializedLexicalSlot(env, prop);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -2230,7 +2230,7 @@ js::LookupNameUnqualified(JSContext* cx, HandlePropertyName name, HandleObject e
|
|||
env = RuntimeLexicalErrorObject::create(cx, env, JSMSG_UNINITIALIZED_LEXICAL);
|
||||
if (!env)
|
||||
return false;
|
||||
} else if (env->is<LexicalEnvironmentObject>() && !shape->writable()) {
|
||||
} else if (env->is<LexicalEnvironmentObject>() && !prop.shape()->writable()) {
|
||||
// Assigning to a named lambda callee name is a no-op in sloppy mode.
|
||||
Rooted<LexicalEnvironmentObject*> lexicalEnv(cx, &env->as<LexicalEnvironmentObject>());
|
||||
if (lexicalEnv->isExtensible() ||
|
||||
|
|
@ -2262,16 +2262,16 @@ js::HasOwnProperty(JSContext* cx, HandleObject obj, HandleId id, bool* result)
|
|||
return true;
|
||||
}
|
||||
|
||||
RootedShape shape(cx);
|
||||
if (!NativeLookupOwnProperty<CanGC>(cx, obj.as<NativeObject>(), id, &shape))
|
||||
Rooted<PropertyResult> prop(cx);
|
||||
if (!NativeLookupOwnProperty<CanGC>(cx, obj.as<NativeObject>(), id, &prop))
|
||||
return false;
|
||||
*result = (shape != nullptr);
|
||||
*result = prop.isFound();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
js::LookupPropertyPure(ExclusiveContext* cx, JSObject* obj, jsid id, JSObject** objp,
|
||||
Shape** propp)
|
||||
PropertyResult* propp)
|
||||
{
|
||||
bool isTypedArrayOutOfRange = false;
|
||||
do {
|
||||
|
|
@ -2292,12 +2292,12 @@ js::LookupPropertyPure(ExclusiveContext* cx, JSObject* obj, jsid id, JSObject**
|
|||
} while (obj);
|
||||
|
||||
*objp = nullptr;
|
||||
*propp = nullptr;
|
||||
propp->setNotFound();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
js::LookupOwnPropertyPure(ExclusiveContext* cx, JSObject* obj, jsid id, Shape** propp,
|
||||
js::LookupOwnPropertyPure(ExclusiveContext* cx, JSObject* obj, jsid id, PropertyResult* propp,
|
||||
bool* isTypedArrayOutOfRange /* = nullptr */)
|
||||
{
|
||||
JS::AutoCheckCannotGC nogc;
|
||||
|
|
@ -2308,7 +2308,7 @@ js::LookupOwnPropertyPure(ExclusiveContext* cx, JSObject* obj, jsid id, Shape**
|
|||
// Search for a native dense element, typed array element, or property.
|
||||
|
||||
if (JSID_IS_INT(id) && obj->as<NativeObject>().containsDenseElement(JSID_TO_INT(id))) {
|
||||
MarkDenseOrTypedArrayElementFound<NoGC>(propp);
|
||||
propp->setDenseOrTypedArrayElement();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -2316,9 +2316,9 @@ js::LookupOwnPropertyPure(ExclusiveContext* cx, JSObject* obj, jsid id, Shape**
|
|||
uint64_t index;
|
||||
if (IsTypedArrayIndex(id, &index)) {
|
||||
if (index < obj->as<TypedArrayObject>().length()) {
|
||||
MarkDenseOrTypedArrayElementFound<NoGC>(propp);
|
||||
propp->setDenseOrTypedArrayElement();
|
||||
} else {
|
||||
*propp = nullptr;
|
||||
propp->setNotFound();
|
||||
if (isTypedArrayOutOfRange)
|
||||
*isTypedArrayOutOfRange = true;
|
||||
}
|
||||
|
|
@ -2327,7 +2327,7 @@ js::LookupOwnPropertyPure(ExclusiveContext* cx, JSObject* obj, jsid id, Shape**
|
|||
}
|
||||
|
||||
if (Shape* shape = obj->as<NativeObject>().lookupPure(id)) {
|
||||
*propp = shape;
|
||||
propp->setNativeProperty(shape);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -2337,31 +2337,31 @@ js::LookupOwnPropertyPure(ExclusiveContext* cx, JSObject* obj, jsid id, Shape**
|
|||
return false;
|
||||
} else if (obj->is<UnboxedPlainObject>()) {
|
||||
if (obj->as<UnboxedPlainObject>().containsUnboxedOrExpandoProperty(cx, id)) {
|
||||
MarkNonNativePropertyFound<NoGC>(propp);
|
||||
propp->setNonNativeProperty();
|
||||
return true;
|
||||
}
|
||||
} else if (obj->is<UnboxedArrayObject>()) {
|
||||
if (obj->as<UnboxedArrayObject>().containsProperty(cx, id)) {
|
||||
MarkNonNativePropertyFound<NoGC>(propp);
|
||||
propp->setNonNativeProperty();
|
||||
return true;
|
||||
}
|
||||
} else if (obj->is<TypedObject>()) {
|
||||
if (obj->as<TypedObject>().typeDescr().hasProperty(cx->names(), id)) {
|
||||
MarkNonNativePropertyFound<NoGC>(propp);
|
||||
propp->setNonNativeProperty();
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
||||
*propp = nullptr;
|
||||
propp->setNotFound();
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline bool
|
||||
NativeGetPureInline(NativeObject* pobj, jsid id, Shape* shape, Value* vp)
|
||||
NativeGetPureInline(NativeObject* pobj, jsid id, PropertyResult prop, Value* vp)
|
||||
{
|
||||
if (IsImplicitDenseOrTypedArrayElement(shape)) {
|
||||
if (prop.isDenseOrTypedArrayElement()) {
|
||||
// For simplicity we ignore the TypedArray with string index case.
|
||||
if (!JSID_IS_INT(id))
|
||||
return false;
|
||||
|
|
@ -2371,6 +2371,7 @@ NativeGetPureInline(NativeObject* pobj, jsid id, Shape* shape, Value* vp)
|
|||
}
|
||||
|
||||
// Fail if we have a custom getter.
|
||||
Shape* shape = prop.shape();
|
||||
if (!shape->hasDefaultGetter())
|
||||
return false;
|
||||
|
||||
|
|
@ -2388,22 +2389,23 @@ bool
|
|||
js::GetPropertyPure(ExclusiveContext* cx, JSObject* obj, jsid id, Value* vp)
|
||||
{
|
||||
JSObject* pobj;
|
||||
Shape* shape;
|
||||
if (!LookupPropertyPure(cx, obj, id, &pobj, &shape))
|
||||
PropertyResult prop;
|
||||
if (!LookupPropertyPure(cx, obj, id, &pobj, &prop))
|
||||
return false;
|
||||
|
||||
if (!shape) {
|
||||
if (!prop) {
|
||||
vp->setUndefined();
|
||||
return true;
|
||||
}
|
||||
|
||||
return pobj->isNative() && NativeGetPureInline(&pobj->as<NativeObject>(), id, shape, vp);
|
||||
return pobj->isNative() && NativeGetPureInline(&pobj->as<NativeObject>(), id, prop, vp);
|
||||
}
|
||||
|
||||
static inline bool
|
||||
NativeGetGetterPureInline(Shape* shape, JSFunction** fp)
|
||||
NativeGetGetterPureInline(PropertyResult prop, JSFunction** fp)
|
||||
{
|
||||
if (!IsImplicitDenseOrTypedArrayElement(shape) && shape->hasGetterObject()) {
|
||||
if (!prop.isDenseOrTypedArrayElement() && prop.shape()->hasGetterObject()) {
|
||||
Shape* shape = prop.shape();
|
||||
if (shape->getterObject()->is<JSFunction>()) {
|
||||
*fp = &shape->getterObject()->as<JSFunction>();
|
||||
return true;
|
||||
|
|
@ -2420,32 +2422,32 @@ js::GetGetterPure(ExclusiveContext* cx, JSObject* obj, jsid id, JSFunction** fp)
|
|||
/* Just like GetPropertyPure, but get getter function, without invoking
|
||||
* it. */
|
||||
JSObject* pobj;
|
||||
Shape* shape;
|
||||
if (!LookupPropertyPure(cx, obj, id, &pobj, &shape))
|
||||
PropertyResult prop;
|
||||
if (!LookupPropertyPure(cx, obj, id, &pobj, &prop))
|
||||
return false;
|
||||
|
||||
if (!shape) {
|
||||
if (!prop) {
|
||||
*fp = nullptr;
|
||||
return true;
|
||||
}
|
||||
|
||||
return pobj->isNative() && NativeGetGetterPureInline(shape, fp);
|
||||
return prop.isNativeProperty() && NativeGetGetterPureInline(prop, fp);
|
||||
}
|
||||
|
||||
bool
|
||||
js::GetOwnGetterPure(ExclusiveContext* cx, JSObject* obj, jsid id, JSFunction** fp)
|
||||
{
|
||||
JS::AutoCheckCannotGC nogc;
|
||||
Shape* shape;
|
||||
if (!LookupOwnPropertyPure(cx, obj, id, &shape))
|
||||
PropertyResult prop;
|
||||
if (!LookupOwnPropertyPure(cx, obj, id, &prop))
|
||||
return false;
|
||||
|
||||
if (!shape) {
|
||||
if (!prop) {
|
||||
*fp = nullptr;
|
||||
return true;
|
||||
}
|
||||
|
||||
return NativeGetGetterPureInline(shape, fp);
|
||||
return prop.isNativeProperty() && NativeGetGetterPureInline(prop, fp);
|
||||
}
|
||||
|
||||
bool
|
||||
|
|
@ -2453,14 +2455,14 @@ js::GetOwnNativeGetterPure(JSContext* cx, JSObject* obj, jsid id, JSNative* nati
|
|||
{
|
||||
JS::AutoCheckCannotGC nogc;
|
||||
*native = nullptr;
|
||||
Shape* shape;
|
||||
if (!LookupOwnPropertyPure(cx, obj, id, &shape))
|
||||
PropertyResult prop;
|
||||
if (!LookupOwnPropertyPure(cx, obj, id, &prop))
|
||||
return false;
|
||||
|
||||
if (!shape || IsImplicitDenseOrTypedArrayElement(shape) || !shape->hasGetterObject())
|
||||
if (!prop || prop.isDenseOrTypedArrayElement() || !prop.shape()->hasGetterObject())
|
||||
return true;
|
||||
|
||||
JSObject* getterObj = shape->getterObject();
|
||||
JSObject* getterObj = prop.shape()->getterObject();
|
||||
if (!getterObj->is<JSFunction>())
|
||||
return true;
|
||||
|
||||
|
|
@ -2475,12 +2477,12 @@ js::GetOwnNativeGetterPure(JSContext* cx, JSObject* obj, jsid id, JSNative* nati
|
|||
bool
|
||||
js::HasOwnDataPropertyPure(JSContext* cx, JSObject* obj, jsid id, bool* result)
|
||||
{
|
||||
Shape* shape = nullptr;
|
||||
if (!LookupOwnPropertyPure(cx, obj, id, &shape))
|
||||
PropertyResult prop;
|
||||
if (!LookupOwnPropertyPure(cx, obj, id, &prop))
|
||||
return false;
|
||||
|
||||
*result = shape && !IsImplicitDenseOrTypedArrayElement(shape) && shape->hasDefaultGetter() &&
|
||||
shape->hasSlot();
|
||||
*result = prop && !prop.isDenseOrTypedArrayElement() && prop.shape()->hasDefaultGetter() &&
|
||||
prop.shape()->hasSlot();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -299,7 +299,6 @@ class JSObject : public js::gc::Cell
|
|||
|
||||
static const JS::TraceKind TraceKind = JS::TraceKind::Object;
|
||||
static const size_t MaxTagBits = 3;
|
||||
static bool isNullLike(const JSObject* obj) { return uintptr_t(obj) < (1 << MaxTagBits); }
|
||||
|
||||
MOZ_ALWAYS_INLINE JS::Zone* zone() const {
|
||||
return group_->zone();
|
||||
|
|
@ -587,21 +586,23 @@ class JSObject : public js::gc::Cell
|
|||
void operator=(const JSObject& other) = delete;
|
||||
};
|
||||
|
||||
template <class U>
|
||||
template <typename Wrapper>
|
||||
template <typename U>
|
||||
MOZ_ALWAYS_INLINE JS::Handle<U*>
|
||||
js::RootedBase<JSObject*>::as() const
|
||||
js::RootedBase<JSObject*, Wrapper>::as() const
|
||||
{
|
||||
const JS::Rooted<JSObject*>& self = *static_cast<const JS::Rooted<JSObject*>*>(this);
|
||||
MOZ_ASSERT(self->is<U>());
|
||||
const Wrapper& self = *static_cast<const Wrapper*>(this);
|
||||
MOZ_ASSERT(self->template is<U>());
|
||||
return Handle<U*>::fromMarkedLocation(reinterpret_cast<U* const*>(self.address()));
|
||||
}
|
||||
|
||||
template <typename Wrapper>
|
||||
template <class U>
|
||||
MOZ_ALWAYS_INLINE JS::Handle<U*>
|
||||
js::HandleBase<JSObject*>::as() const
|
||||
js::HandleBase<JSObject*, Wrapper>::as() const
|
||||
{
|
||||
const JS::Handle<JSObject*>& self = *static_cast<const JS::Handle<JSObject*>*>(this);
|
||||
MOZ_ASSERT(self->is<U>());
|
||||
MOZ_ASSERT(self->template is<U>());
|
||||
return Handle<U*>::fromMarkedLocation(reinterpret_cast<U* const*>(self.address()));
|
||||
}
|
||||
|
||||
|
|
@ -633,7 +634,6 @@ struct JSObject_Slots16 : JSObject { void* data[3]; js::Value fslots[16]; };
|
|||
/* static */ MOZ_ALWAYS_INLINE void
|
||||
JSObject::readBarrier(JSObject* obj)
|
||||
{
|
||||
MOZ_ASSERT_IF(obj, !isNullLike(obj));
|
||||
if (obj && obj->isTenured())
|
||||
obj->asTenured().readBarrier(&obj->asTenured());
|
||||
}
|
||||
|
|
@ -641,7 +641,6 @@ JSObject::readBarrier(JSObject* obj)
|
|||
/* static */ MOZ_ALWAYS_INLINE void
|
||||
JSObject::writeBarrierPre(JSObject* obj)
|
||||
{
|
||||
MOZ_ASSERT_IF(obj, !isNullLike(obj));
|
||||
if (obj && obj->isTenured())
|
||||
obj->asTenured().writeBarrierPre(&obj->asTenured());
|
||||
}
|
||||
|
|
@ -650,8 +649,6 @@ JSObject::writeBarrierPre(JSObject* obj)
|
|||
JSObject::writeBarrierPost(void* cellp, JSObject* prev, JSObject* next)
|
||||
{
|
||||
MOZ_ASSERT(cellp);
|
||||
MOZ_ASSERT_IF(next, !IsNullTaggedPointer(next));
|
||||
MOZ_ASSERT_IF(prev, !IsNullTaggedPointer(prev));
|
||||
|
||||
// If the target needs an entry, add it.
|
||||
js::gc::StoreBuffer* buffer;
|
||||
|
|
@ -997,11 +994,11 @@ GetPropertyDescriptor(JSContext* cx, HandleObject obj, HandleId id,
|
|||
*/
|
||||
extern bool
|
||||
LookupProperty(JSContext* cx, HandleObject obj, HandleId id,
|
||||
MutableHandleObject objp, MutableHandleShape propp);
|
||||
MutableHandleObject objp, MutableHandle<PropertyResult> propp);
|
||||
|
||||
inline bool
|
||||
LookupProperty(JSContext* cx, HandleObject obj, PropertyName* name,
|
||||
MutableHandleObject objp, MutableHandleShape propp)
|
||||
MutableHandleObject objp, MutableHandle<PropertyResult> propp)
|
||||
{
|
||||
RootedId id(cx, NameToId(name));
|
||||
return LookupProperty(cx, obj, id, objp, propp);
|
||||
|
|
@ -1193,11 +1190,11 @@ ReadPropertyDescriptors(JSContext* cx, HandleObject props, bool checkAccessors,
|
|||
/* Read the name using a dynamic lookup on the scopeChain. */
|
||||
extern bool
|
||||
LookupName(JSContext* cx, HandlePropertyName name, HandleObject scopeChain,
|
||||
MutableHandleObject objp, MutableHandleObject pobjp, MutableHandleShape propp);
|
||||
MutableHandleObject objp, MutableHandleObject pobjp, MutableHandle<PropertyResult> propp);
|
||||
|
||||
extern bool
|
||||
LookupNameNoGC(JSContext* cx, PropertyName* name, JSObject* scopeChain,
|
||||
JSObject** objp, JSObject** pobjp, Shape** propp);
|
||||
JSObject** objp, JSObject** pobjp, PropertyResult* propp);
|
||||
|
||||
/*
|
||||
* Like LookupName except returns the global object if 'name' is not found in
|
||||
|
|
@ -1231,10 +1228,10 @@ FindVariableScope(JSContext* cx, JSFunction** funp);
|
|||
|
||||
bool
|
||||
LookupPropertyPure(ExclusiveContext* cx, JSObject* obj, jsid id, JSObject** objp,
|
||||
Shape** propp);
|
||||
PropertyResult* propp);
|
||||
|
||||
bool
|
||||
LookupOwnPropertyPure(ExclusiveContext* cx, JSObject* obj, jsid id, Shape** propp,
|
||||
LookupOwnPropertyPure(ExclusiveContext* cx, JSObject* obj, jsid id, PropertyResult* propp,
|
||||
bool* isTypedArrayOutOfRange = nullptr);
|
||||
|
||||
bool
|
||||
|
|
|
|||
|
|
@ -585,11 +585,11 @@ HasNoToPrimitiveMethodPure(JSObject* obj, JSContext* cx)
|
|||
{
|
||||
jsid id = SYMBOL_TO_JSID(cx->wellKnownSymbols().toPrimitive);
|
||||
JSObject* pobj;
|
||||
Shape* shape;
|
||||
if (!LookupPropertyPure(cx, obj, id, &pobj, &shape))
|
||||
PropertyResult prop;
|
||||
if (!LookupPropertyPure(cx, obj, id, &pobj, &prop))
|
||||
return false;
|
||||
|
||||
return !shape;
|
||||
return !prop;
|
||||
}
|
||||
|
||||
/* ES6 draft rev 28 (2014 Oct 14) 7.1.14 */
|
||||
|
|
|
|||
|
|
@ -445,9 +445,9 @@ JO(JSContext* cx, HandleObject obj, StringifyContext* scx)
|
|||
#ifdef DEBUG
|
||||
if (scx->maybeSafely) {
|
||||
RootedNativeObject nativeObj(cx, &obj->as<NativeObject>());
|
||||
RootedShape prop(cx);
|
||||
Rooted<PropertyResult> prop(cx);
|
||||
NativeLookupOwnPropertyNoResolve(cx, nativeObj, id, &prop);
|
||||
MOZ_ASSERT(prop && prop->isDataDescriptor());
|
||||
MOZ_ASSERT(prop && prop.isNativeProperty() && prop.shape()->isDataDescriptor());
|
||||
}
|
||||
#endif // DEBUG
|
||||
if (!GetProperty(cx, obj, obj, id, &outputValue))
|
||||
|
|
|
|||
|
|
@ -530,18 +530,18 @@ Proxy::trace(JSTracer* trc, JSObject* proxy)
|
|||
|
||||
bool
|
||||
js::proxy_LookupProperty(JSContext* cx, HandleObject obj, HandleId id,
|
||||
MutableHandleObject objp, MutableHandleShape propp)
|
||||
MutableHandleObject objp, MutableHandle<JS::PropertyResult> propp)
|
||||
{
|
||||
bool found;
|
||||
if (!Proxy::has(cx, obj, id, &found))
|
||||
return false;
|
||||
|
||||
if (found) {
|
||||
MarkNonNativePropertyFound<CanGC>(propp);
|
||||
propp.setNonNativeProperty();
|
||||
objp.set(obj);
|
||||
} else {
|
||||
propp.setNotFound();
|
||||
objp.set(nullptr);
|
||||
propp.set(nullptr);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -352,7 +352,7 @@ ArrayBufferObject::detach(JSContext* cx, Handle<ArrayBufferObject*> buffer,
|
|||
// Update all views of the buffer to account for the buffer having been
|
||||
// detached, and clear the buffer's data and list of views.
|
||||
|
||||
auto& innerViews = cx->compartment()->innerViews;
|
||||
auto& innerViews = cx->compartment()->innerViews.get();
|
||||
if (InnerViewTable::ViewVector* views = innerViews.maybeViewsUnbarriered(buffer)) {
|
||||
for (size_t i = 0; i < views->length(); i++)
|
||||
NoteViewBufferWasDetached((*views)[i], newContents, cx);
|
||||
|
|
@ -427,7 +427,7 @@ ArrayBufferObject::changeContents(JSContext* cx, BufferContents newContents,
|
|||
setNewData(cx->runtime()->defaultFreeOp(), newContents, ownsState);
|
||||
|
||||
// Update all views.
|
||||
auto& innerViews = cx->compartment()->innerViews;
|
||||
auto& innerViews = cx->compartment()->innerViews.get();
|
||||
if (InnerViewTable::ViewVector* views = innerViews.maybeViewsUnbarriered(this)) {
|
||||
for (size_t i = 0; i < views->length(); i++)
|
||||
changeViewContents(cx, (*views)[i], oldDataPointer, newContents);
|
||||
|
|
|
|||
|
|
@ -541,7 +541,6 @@ class InnerViewTable
|
|||
typedef Vector<ArrayBufferViewObject*, 1, SystemAllocPolicy> ViewVector;
|
||||
|
||||
friend class ArrayBufferObject;
|
||||
friend class WeakCacheBase<InnerViewTable>;
|
||||
|
||||
private:
|
||||
struct MapGCPolicy {
|
||||
|
|
@ -602,23 +601,15 @@ class InnerViewTable
|
|||
size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf);
|
||||
};
|
||||
|
||||
template <>
|
||||
class WeakCacheBase<InnerViewTable>
|
||||
template <typename Wrapper>
|
||||
class MutableWrappedPtrOperations<InnerViewTable, Wrapper>
|
||||
: public WrappedPtrOperations<InnerViewTable, Wrapper>
|
||||
{
|
||||
InnerViewTable& table() {
|
||||
return static_cast<JS::WeakCache<InnerViewTable>*>(this)->get();
|
||||
}
|
||||
const InnerViewTable& table() const {
|
||||
return static_cast<const JS::WeakCache<InnerViewTable>*>(this)->get();
|
||||
return static_cast<Wrapper*>(this)->get();
|
||||
}
|
||||
|
||||
public:
|
||||
InnerViewTable::ViewVector* maybeViewsUnbarriered(ArrayBufferObject* obj) {
|
||||
return table().maybeViewsUnbarriered(obj);
|
||||
}
|
||||
void removeViews(ArrayBufferObject* obj) { table().removeViews(obj); }
|
||||
void sweepAfterMinorGC() { table().sweepAfterMinorGC(); }
|
||||
bool needsSweepAfterMinorGC() const { return table().needsSweepAfterMinorGC(); }
|
||||
size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) {
|
||||
return table().sizeOfExcludingThis(mallocSizeOf);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10098,12 +10098,14 @@ DebuggerObject::forceLexicalInitializationByName(JSContext* cx, HandleDebuggerOb
|
|||
|
||||
RootedObject globalLexical(cx, &referent->lexicalEnvironment());
|
||||
RootedObject pobj(cx);
|
||||
RootedShape shape(cx);
|
||||
if (!LookupProperty(cx, globalLexical, id, &pobj, &shape))
|
||||
Rooted<PropertyResult> prop(cx);
|
||||
if (!LookupProperty(cx, globalLexical, id, &pobj, &prop))
|
||||
return false;
|
||||
|
||||
result = false;
|
||||
if (shape) {
|
||||
if (prop) {
|
||||
MOZ_ASSERT(prop.isNativeProperty());
|
||||
Shape* shape = prop.shape();
|
||||
Value v = globalLexical->as<NativeObject>().getSlot(shape->slot());
|
||||
if (shape->hasSlot() && v.isMagic() && v.whyMagic() == JS_UNINITIALIZED_LEXICAL) {
|
||||
globalLexical->as<NativeObject>().setSlot(shape->slot(), UndefinedValue());
|
||||
|
|
|
|||
|
|
@ -518,14 +518,14 @@ ModuleEnvironmentObject::fixEnclosingEnvironmentAfterCompartmentMerge(GlobalObje
|
|||
|
||||
/* static */ bool
|
||||
ModuleEnvironmentObject::lookupProperty(JSContext* cx, HandleObject obj, HandleId id,
|
||||
MutableHandleObject objp, MutableHandleShape propp)
|
||||
MutableHandleObject objp, MutableHandle<PropertyResult> propp)
|
||||
{
|
||||
const IndirectBindingMap& bindings = obj->as<ModuleEnvironmentObject>().importBindings();
|
||||
Shape* shape;
|
||||
ModuleEnvironmentObject* env;
|
||||
if (bindings.lookup(id, &env, &shape)) {
|
||||
objp.set(env);
|
||||
propp.set(shape);
|
||||
propp.setNativeProperty(shape);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -688,13 +688,13 @@ CheckUnscopables(JSContext *cx, HandleObject obj, HandleId id, bool *scopable)
|
|||
|
||||
static bool
|
||||
with_LookupProperty(JSContext* cx, HandleObject obj, HandleId id,
|
||||
MutableHandleObject objp, MutableHandleShape propp)
|
||||
MutableHandleObject objp, MutableHandle<PropertyResult> propp)
|
||||
{
|
||||
// SpiderMonkey-specific: consider internal '.generator' and '.this' names
|
||||
// to be unscopable.
|
||||
if (IsUnscopableDotName(cx, id)) {
|
||||
objp.set(nullptr);
|
||||
propp.set(nullptr);
|
||||
propp.setNotFound();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -708,7 +708,7 @@ with_LookupProperty(JSContext* cx, HandleObject obj, HandleId id,
|
|||
return false;
|
||||
if (!scopable) {
|
||||
objp.set(nullptr);
|
||||
propp.set(nullptr);
|
||||
propp.setNotFound();
|
||||
}
|
||||
}
|
||||
return true;
|
||||
|
|
@ -1104,7 +1104,7 @@ ReportRuntimeLexicalErrorId(JSContext* cx, unsigned errorNumber, HandleId id)
|
|||
|
||||
static bool
|
||||
lexicalError_LookupProperty(JSContext* cx, HandleObject obj, HandleId id,
|
||||
MutableHandleObject objp, MutableHandleShape propp)
|
||||
MutableHandleObject objp, MutableHandle<PropertyResult> propp)
|
||||
{
|
||||
ReportRuntimeLexicalErrorId(cx, obj->as<RuntimeLexicalErrorObject>().errorNumber(), id);
|
||||
return false;
|
||||
|
|
|
|||
|
|
@ -407,7 +407,7 @@ class ModuleEnvironmentObject : public EnvironmentObject
|
|||
|
||||
private:
|
||||
static bool lookupProperty(JSContext* cx, HandleObject obj, HandleId id,
|
||||
MutableHandleObject objp, MutableHandleShape propp);
|
||||
MutableHandleObject objp, MutableHandle<PropertyResult> propp);
|
||||
static bool hasProperty(JSContext* cx, HandleObject obj, HandleId id, bool* foundp);
|
||||
static bool getProperty(JSContext* cx, HandleObject obj, HandleValue receiver, HandleId id,
|
||||
MutableHandleValue vp);
|
||||
|
|
|
|||
|
|
@ -363,12 +363,14 @@ js::CheckStarGeneratorResumptionValue(JSContext* cx, HandleValue v)
|
|||
|
||||
// It should have `value` data property, but the type doesn't matter
|
||||
JSObject* ignored;
|
||||
Shape* shape;
|
||||
if (!LookupPropertyPure(cx, obj, NameToId(cx->names().value), &ignored, &shape))
|
||||
PropertyResult prop;
|
||||
if (!LookupPropertyPure(cx, obj, NameToId(cx->names().value), &ignored, &prop))
|
||||
return false;
|
||||
if (!shape)
|
||||
if (!prop)
|
||||
return false;
|
||||
if (!shape->hasDefaultGetter())
|
||||
if (!prop.isNativeProperty())
|
||||
return false;
|
||||
if (!prop.shape()->hasDefaultGetter())
|
||||
return false;
|
||||
|
||||
return true;
|
||||
|
|
|
|||
|
|
@ -78,17 +78,18 @@ IsUninitializedLexical(const Value& val)
|
|||
}
|
||||
|
||||
static inline bool
|
||||
IsUninitializedLexicalSlot(HandleObject obj, HandleShape shape)
|
||||
IsUninitializedLexicalSlot(HandleObject obj, Handle<PropertyResult> prop)
|
||||
{
|
||||
MOZ_ASSERT(shape);
|
||||
MOZ_ASSERT(prop);
|
||||
if (obj->is<WithEnvironmentObject>())
|
||||
return false;
|
||||
// We check for IsImplicitDenseOrTypedArrayElement even though the shape
|
||||
// is always a non-indexed property because proxy hooks may return a
|
||||
// "non-native property found" shape, which happens to be encoded in the
|
||||
// same way as the "dense element" shape. See MarkNonNativePropertyFound.
|
||||
if (IsImplicitDenseOrTypedArrayElement(shape) ||
|
||||
!shape->hasSlot() ||
|
||||
|
||||
// Proxy hooks may return a non-native property.
|
||||
if (prop.isNonNativeProperty())
|
||||
return false;
|
||||
|
||||
Shape* shape = prop.shape();
|
||||
if (!shape->hasSlot() ||
|
||||
!shape->hasDefaultGetter() ||
|
||||
!shape->hasDefaultSetter())
|
||||
{
|
||||
|
|
@ -174,9 +175,9 @@ GetLengthProperty(const Value& lval, MutableHandleValue vp)
|
|||
|
||||
template <bool TypeOf> inline bool
|
||||
FetchName(JSContext* cx, HandleObject obj, HandleObject obj2, HandlePropertyName name,
|
||||
HandleShape shape, MutableHandleValue vp)
|
||||
Handle<PropertyResult> prop, MutableHandleValue vp)
|
||||
{
|
||||
if (!shape) {
|
||||
if (!prop) {
|
||||
if (TypeOf) {
|
||||
vp.setUndefined();
|
||||
return true;
|
||||
|
|
@ -190,6 +191,7 @@ FetchName(JSContext* cx, HandleObject obj, HandleObject obj2, HandlePropertyName
|
|||
if (!GetProperty(cx, obj, obj, id, vp))
|
||||
return false;
|
||||
} else {
|
||||
RootedShape shape(cx, prop.shape());
|
||||
RootedObject normalized(cx, obj);
|
||||
if (normalized->is<WithEnvironmentObject>() && !shape->hasDefaultGetter())
|
||||
normalized = &normalized->as<WithEnvironmentObject>().object();
|
||||
|
|
@ -213,9 +215,13 @@ FetchName(JSContext* cx, HandleObject obj, HandleObject obj2, HandlePropertyName
|
|||
}
|
||||
|
||||
inline bool
|
||||
FetchNameNoGC(JSObject* pobj, Shape* shape, MutableHandleValue vp)
|
||||
FetchNameNoGC(JSObject* pobj, PropertyResult prop, MutableHandleValue vp)
|
||||
{
|
||||
if (!shape || !pobj->isNative() || !shape->isDataDescriptor() || !shape->hasDefaultGetter())
|
||||
if (!prop || !pobj->isNative())
|
||||
return false;
|
||||
|
||||
Shape* shape = prop.shape();
|
||||
if (!shape->isDataDescriptor() || !shape->hasDefaultGetter())
|
||||
return false;
|
||||
|
||||
vp.set(pobj->as<NativeObject>().getSlot(shape->slot()));
|
||||
|
|
@ -361,7 +367,7 @@ DefVarOperation(JSContext* cx, HandleObject varobj, HandlePropertyName dn, unsig
|
|||
}
|
||||
#endif
|
||||
|
||||
RootedShape prop(cx);
|
||||
Rooted<PropertyResult> prop(cx);
|
||||
RootedObject obj2(cx);
|
||||
if (!LookupProperty(cx, varobj, dn, &obj2, &prop))
|
||||
return false;
|
||||
|
|
|
|||
|
|
@ -210,27 +210,27 @@ GetNameOperation(JSContext* cx, InterpreterFrame* fp, jsbytecode* pc, MutableHan
|
|||
if (IsGlobalOp(JSOp(*pc)) && !fp->script()->hasNonSyntacticScope())
|
||||
obj = &obj->global().lexicalEnvironment();
|
||||
|
||||
Shape* shape = nullptr;
|
||||
PropertyResult prop;
|
||||
JSObject* env = nullptr;
|
||||
JSObject* pobj = nullptr;
|
||||
if (LookupNameNoGC(cx, name, obj, &env, &pobj, &shape)) {
|
||||
if (FetchNameNoGC(pobj, shape, vp))
|
||||
if (LookupNameNoGC(cx, name, obj, &env, &pobj, &prop)) {
|
||||
if (FetchNameNoGC(pobj, prop, vp))
|
||||
return true;
|
||||
}
|
||||
|
||||
RootedObject objRoot(cx, obj), envRoot(cx), pobjRoot(cx);
|
||||
RootedPropertyName nameRoot(cx, name);
|
||||
RootedShape shapeRoot(cx);
|
||||
Rooted<PropertyResult> propRoot(cx);
|
||||
|
||||
if (!LookupName(cx, nameRoot, objRoot, &envRoot, &pobjRoot, &shapeRoot))
|
||||
if (!LookupName(cx, nameRoot, objRoot, &envRoot, &pobjRoot, &propRoot))
|
||||
return false;
|
||||
|
||||
/* Kludge to allow (typeof foo == "undefined") tests. */
|
||||
JSOp op2 = JSOp(pc[JSOP_GETNAME_LENGTH]);
|
||||
if (op2 == JSOP_TYPEOF)
|
||||
return FetchName<true>(cx, envRoot, pobjRoot, nameRoot, shapeRoot, vp);
|
||||
return FetchName<true>(cx, envRoot, pobjRoot, nameRoot, propRoot, vp);
|
||||
|
||||
return FetchName<false>(cx, envRoot, pobjRoot, nameRoot, shapeRoot, vp);
|
||||
return FetchName<false>(cx, envRoot, pobjRoot, nameRoot, propRoot, vp);
|
||||
}
|
||||
|
||||
static inline bool
|
||||
|
|
@ -238,12 +238,12 @@ GetImportOperation(JSContext* cx, InterpreterFrame* fp, jsbytecode* pc, MutableH
|
|||
{
|
||||
RootedObject obj(cx, fp->environmentChain()), env(cx), pobj(cx);
|
||||
RootedPropertyName name(cx, fp->script()->getName(pc));
|
||||
RootedShape shape(cx);
|
||||
Rooted<PropertyResult> prop(cx);
|
||||
|
||||
MOZ_ALWAYS_TRUE(LookupName(cx, name, obj, &env, &pobj, &shape));
|
||||
MOZ_ALWAYS_TRUE(LookupName(cx, name, obj, &env, &pobj, &prop));
|
||||
MOZ_ASSERT(env && env->is<ModuleEnvironmentObject>());
|
||||
MOZ_ASSERT(env->as<ModuleEnvironmentObject>().hasImportBinding(name));
|
||||
return FetchName<false>(cx, env, pobj, name, shape, vp);
|
||||
return FetchName<false>(cx, env, pobj, name, prop, vp);
|
||||
}
|
||||
|
||||
static bool
|
||||
|
|
@ -1613,11 +1613,7 @@ GetSuperEnvFunction(JSContext* cx, InterpreterRegs& regs)
|
|||
*/
|
||||
|
||||
template<typename T>
|
||||
class ReservedRootedBase {
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
class ReservedRooted : public ReservedRootedBase<T>
|
||||
class ReservedRooted : public RootedBase<T, ReservedRooted<T>>
|
||||
{
|
||||
Rooted<T>* savedRoot;
|
||||
|
||||
|
|
@ -1645,14 +1641,6 @@ class ReservedRooted : public ReservedRootedBase<T>
|
|||
DECLARE_POINTER_ASSIGN_OPS(ReservedRooted, T)
|
||||
};
|
||||
|
||||
template <>
|
||||
class ReservedRootedBase<Value> : public ValueOperations<ReservedRooted<Value>>
|
||||
{};
|
||||
|
||||
template <>
|
||||
class ReservedRootedBase<Scope*> : public ScopeCastOperation<ReservedRooted<Scope*>>
|
||||
{};
|
||||
|
||||
static MOZ_NEVER_INLINE bool
|
||||
Interpret(JSContext* cx, RunState& state)
|
||||
{
|
||||
|
|
@ -4400,12 +4388,12 @@ bool
|
|||
js::GetEnvironmentName(JSContext* cx, HandleObject envChain, HandlePropertyName name,
|
||||
MutableHandleValue vp)
|
||||
{
|
||||
RootedShape shape(cx);
|
||||
Rooted<PropertyResult> prop(cx);
|
||||
RootedObject obj(cx), pobj(cx);
|
||||
if (!LookupName(cx, name, envChain, &obj, &pobj, &shape))
|
||||
if (!LookupName(cx, name, envChain, &obj, &pobj, &prop))
|
||||
return false;
|
||||
|
||||
if (!shape)
|
||||
if (!prop)
|
||||
return ReportIsNotDefined(cx, name);
|
||||
|
||||
if (!GetProperty(cx, obj, obj, name, vp))
|
||||
|
|
@ -4427,12 +4415,12 @@ bool
|
|||
js::GetEnvironmentNameForTypeOf(JSContext* cx, HandleObject envChain, HandlePropertyName name,
|
||||
MutableHandleValue vp)
|
||||
{
|
||||
RootedShape shape(cx);
|
||||
Rooted<PropertyResult> prop(cx);
|
||||
RootedObject obj(cx), pobj(cx);
|
||||
if (!LookupName(cx, name, envChain, &obj, &pobj, &shape))
|
||||
if (!LookupName(cx, name, envChain, &obj, &pobj, &prop))
|
||||
return false;
|
||||
|
||||
if (!shape) {
|
||||
if (!prop) {
|
||||
vp.set(UndefinedValue());
|
||||
return true;
|
||||
}
|
||||
|
|
@ -4490,9 +4478,9 @@ js::DefFunOperation(JSContext* cx, HandleScript script, HandleObject envChain,
|
|||
/* ES5 10.5 (NB: with subsequent errata). */
|
||||
RootedPropertyName name(cx, fun->explicitName()->asPropertyName());
|
||||
|
||||
RootedShape shape(cx);
|
||||
Rooted<PropertyResult> prop(cx);
|
||||
RootedObject pobj(cx);
|
||||
if (!LookupProperty(cx, parent, name, &pobj, &shape))
|
||||
if (!LookupProperty(cx, parent, name, &pobj, &prop))
|
||||
return false;
|
||||
|
||||
RootedValue rval(cx, ObjectValue(*fun));
|
||||
|
|
@ -4506,7 +4494,7 @@ js::DefFunOperation(JSContext* cx, HandleScript script, HandleObject envChain,
|
|||
: JSPROP_ENUMERATE | JSPROP_PERMANENT;
|
||||
|
||||
/* Steps 5d, 5f. */
|
||||
if (!shape || pobj != parent) {
|
||||
if (!prop || pobj != parent) {
|
||||
if (!DefineProperty(cx, parent, name, rval, nullptr, nullptr, attrs))
|
||||
return false;
|
||||
|
||||
|
|
@ -4524,6 +4512,7 @@ js::DefFunOperation(JSContext* cx, HandleScript script, HandleObject envChain,
|
|||
*/
|
||||
MOZ_ASSERT(parent->isNative() || parent->is<DebugEnvironmentProxy>());
|
||||
if (parent->is<GlobalObject>()) {
|
||||
Shape* shape = prop.shape();
|
||||
if (shape->configurable()) {
|
||||
if (!DefineProperty(cx, parent, name, rval, nullptr, nullptr, attrs))
|
||||
return false;
|
||||
|
|
@ -4728,8 +4717,8 @@ js::DeleteNameOperation(JSContext* cx, HandlePropertyName name, HandleObject sco
|
|||
MutableHandleValue res)
|
||||
{
|
||||
RootedObject scope(cx), pobj(cx);
|
||||
RootedShape shape(cx);
|
||||
if (!LookupName(cx, name, scopeObj, &scope, &pobj, &shape))
|
||||
Rooted<PropertyResult> prop(cx);
|
||||
if (!LookupName(cx, name, scopeObj, &scope, &pobj, &prop))
|
||||
return false;
|
||||
|
||||
if (!scope) {
|
||||
|
|
|
|||
|
|
@ -255,10 +255,13 @@ class MOZ_STACK_CLASS JSONParser : public JSONParserBase
|
|||
void operator=(const JSONParser& other) = delete;
|
||||
};
|
||||
|
||||
template <typename CharT>
|
||||
struct RootedBase<JSONParser<CharT>> {
|
||||
template <typename CharT, typename Wrapper>
|
||||
class MutableWrappedPtrOperations<JSONParser<CharT>, Wrapper>
|
||||
: public WrappedPtrOperations<JSONParser<CharT>, Wrapper>
|
||||
{
|
||||
public:
|
||||
bool parse(MutableHandleValue vp) {
|
||||
return static_cast<Rooted<JSONParser<CharT>>*>(this)->get().parse(vp);
|
||||
return static_cast<Wrapper*>(this)->get().parse(vp);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -290,7 +290,7 @@ NativeObject::setSlotWithType(ExclusiveContext* cx, Shape* shape,
|
|||
inline void
|
||||
NativeObject::updateShapeAfterMovingGC()
|
||||
{
|
||||
Shape* shape = shape_.unbarrieredGet();
|
||||
Shape* shape = shape_;
|
||||
if (IsForwarded(shape))
|
||||
shape_.unsafeSet(Forwarded(shape));
|
||||
}
|
||||
|
|
@ -382,8 +382,8 @@ NewNativeObjectWithClassProto(ExclusiveContext* cx, const Class* clasp, HandleOb
|
|||
* *recursedp = false and return true.
|
||||
*/
|
||||
static MOZ_ALWAYS_INLINE bool
|
||||
CallResolveOp(JSContext* cx, HandleNativeObject obj, HandleId id, MutableHandleShape propp,
|
||||
bool* recursedp)
|
||||
CallResolveOp(JSContext* cx, HandleNativeObject obj, HandleId id,
|
||||
MutableHandle<PropertyResult> propp, bool* recursedp)
|
||||
{
|
||||
// Avoid recursion on (obj, id) already being resolved on cx.
|
||||
AutoResolving resolving(cx, obj, id);
|
||||
|
|
@ -407,13 +407,18 @@ CallResolveOp(JSContext* cx, HandleNativeObject obj, HandleId id, MutableHandleS
|
|||
obj->getClass()->getMayResolve()(cx->names(), id, obj));
|
||||
|
||||
if (JSID_IS_INT(id) && obj->containsDenseElement(JSID_TO_INT(id))) {
|
||||
MarkDenseOrTypedArrayElementFound<CanGC>(propp);
|
||||
propp.setDenseOrTypedArrayElement();
|
||||
return true;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(!obj->is<TypedArrayObject>());
|
||||
|
||||
propp.set(obj->lookup(cx, id));
|
||||
RootedShape shape(cx, obj->lookup(cx, id));
|
||||
if (shape)
|
||||
propp.setNativeProperty(shape);
|
||||
else
|
||||
propp.setNotFound();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -444,12 +449,12 @@ static MOZ_ALWAYS_INLINE bool
|
|||
LookupOwnPropertyInline(ExclusiveContext* cx,
|
||||
typename MaybeRooted<NativeObject*, allowGC>::HandleType obj,
|
||||
typename MaybeRooted<jsid, allowGC>::HandleType id,
|
||||
typename MaybeRooted<Shape*, allowGC>::MutableHandleType propp,
|
||||
typename MaybeRooted<PropertyResult, allowGC>::MutableHandleType propp,
|
||||
bool* donep)
|
||||
{
|
||||
// Check for a native dense element.
|
||||
if (JSID_IS_INT(id) && obj->containsDenseElement(JSID_TO_INT(id))) {
|
||||
MarkDenseOrTypedArrayElementFound<allowGC>(propp);
|
||||
propp.setDenseOrTypedArrayElement();
|
||||
*donep = true;
|
||||
return true;
|
||||
}
|
||||
|
|
@ -460,11 +465,10 @@ LookupOwnPropertyInline(ExclusiveContext* cx,
|
|||
if (obj->template is<TypedArrayObject>()) {
|
||||
uint64_t index;
|
||||
if (IsTypedArrayIndex(id, &index)) {
|
||||
if (index < obj->template as<TypedArrayObject>().length()) {
|
||||
MarkDenseOrTypedArrayElementFound<allowGC>(propp);
|
||||
} else {
|
||||
propp.set(nullptr);
|
||||
}
|
||||
if (index < obj->template as<TypedArrayObject>().length())
|
||||
propp.setDenseOrTypedArrayElement();
|
||||
else
|
||||
propp.setNotFound();
|
||||
*donep = true;
|
||||
return true;
|
||||
}
|
||||
|
|
@ -472,7 +476,7 @@ LookupOwnPropertyInline(ExclusiveContext* cx,
|
|||
|
||||
// Check for a native property.
|
||||
if (Shape* shape = obj->lookup(cx, id)) {
|
||||
propp.set(shape);
|
||||
propp.setNativeProperty(shape);
|
||||
*donep = true;
|
||||
return true;
|
||||
}
|
||||
|
|
@ -486,14 +490,14 @@ LookupOwnPropertyInline(ExclusiveContext* cx,
|
|||
if (!CallResolveOp(cx->asJSContext(),
|
||||
MaybeRooted<NativeObject*, allowGC>::toHandle(obj),
|
||||
MaybeRooted<jsid, allowGC>::toHandle(id),
|
||||
MaybeRooted<Shape*, allowGC>::toMutableHandle(propp),
|
||||
MaybeRooted<PropertyResult, allowGC>::toMutableHandle(propp),
|
||||
&recursed))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (recursed) {
|
||||
propp.set(nullptr);
|
||||
propp.setNotFound();
|
||||
*donep = true;
|
||||
return true;
|
||||
}
|
||||
|
|
@ -504,7 +508,7 @@ LookupOwnPropertyInline(ExclusiveContext* cx,
|
|||
}
|
||||
}
|
||||
|
||||
propp.set(nullptr);
|
||||
propp.setNotFound();
|
||||
*donep = false;
|
||||
return true;
|
||||
}
|
||||
|
|
@ -515,11 +519,11 @@ LookupOwnPropertyInline(ExclusiveContext* cx,
|
|||
*/
|
||||
static inline void
|
||||
NativeLookupOwnPropertyNoResolve(ExclusiveContext* cx, HandleNativeObject obj, HandleId id,
|
||||
MutableHandleShape result)
|
||||
MutableHandle<PropertyResult> result)
|
||||
{
|
||||
// Check for a native dense element.
|
||||
if (JSID_IS_INT(id) && obj->containsDenseElement(JSID_TO_INT(id))) {
|
||||
MarkDenseOrTypedArrayElementFound<CanGC>(result);
|
||||
result.setDenseOrTypedArrayElement();
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -528,15 +532,18 @@ NativeLookupOwnPropertyNoResolve(ExclusiveContext* cx, HandleNativeObject obj, H
|
|||
uint64_t index;
|
||||
if (IsTypedArrayIndex(id, &index)) {
|
||||
if (index < obj->as<TypedArrayObject>().length())
|
||||
MarkDenseOrTypedArrayElementFound<CanGC>(result);
|
||||
result.setDenseOrTypedArrayElement();
|
||||
else
|
||||
result.set(nullptr);
|
||||
result.setNotFound();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Check for a native property.
|
||||
result.set(obj->lookup(cx, id));
|
||||
if (Shape* shape = obj->lookup(cx, id))
|
||||
result.setNativeProperty(shape);
|
||||
else
|
||||
result.setNotFound();
|
||||
}
|
||||
|
||||
template <AllowGC allowGC>
|
||||
|
|
@ -545,7 +552,7 @@ LookupPropertyInline(ExclusiveContext* cx,
|
|||
typename MaybeRooted<NativeObject*, allowGC>::HandleType obj,
|
||||
typename MaybeRooted<jsid, allowGC>::HandleType id,
|
||||
typename MaybeRooted<JSObject*, allowGC>::MutableHandleType objp,
|
||||
typename MaybeRooted<Shape*, allowGC>::MutableHandleType propp)
|
||||
typename MaybeRooted<PropertyResult, allowGC>::MutableHandleType propp)
|
||||
{
|
||||
/* NB: The logic of this procedure is implicitly reflected in
|
||||
* BaselineIC.cpp's |EffectlesslyLookupProperty| logic.
|
||||
|
|
@ -578,14 +585,14 @@ LookupPropertyInline(ExclusiveContext* cx,
|
|||
MaybeRooted<JSObject*, allowGC>::toHandle(proto),
|
||||
MaybeRooted<jsid, allowGC>::toHandle(id),
|
||||
MaybeRooted<JSObject*, allowGC>::toMutableHandle(objp),
|
||||
MaybeRooted<Shape*, allowGC>::toMutableHandle(propp));
|
||||
MaybeRooted<PropertyResult, allowGC>::toMutableHandle(propp));
|
||||
}
|
||||
|
||||
current = &proto->template as<NativeObject>();
|
||||
}
|
||||
|
||||
objp.set(nullptr);
|
||||
propp.set(nullptr);
|
||||
propp.setNotFound();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1044,7 +1044,7 @@ bool
|
|||
js::NativeLookupOwnProperty(ExclusiveContext* cx,
|
||||
typename MaybeRooted<NativeObject*, allowGC>::HandleType obj,
|
||||
typename MaybeRooted<jsid, allowGC>::HandleType id,
|
||||
typename MaybeRooted<Shape*, allowGC>::MutableHandleType propp)
|
||||
typename MaybeRooted<PropertyResult, allowGC>::MutableHandleType propp)
|
||||
{
|
||||
bool done;
|
||||
return LookupOwnPropertyInline<allowGC>(cx, obj, id, propp, &done);
|
||||
|
|
@ -1052,11 +1052,11 @@ js::NativeLookupOwnProperty(ExclusiveContext* cx,
|
|||
|
||||
template bool
|
||||
js::NativeLookupOwnProperty<CanGC>(ExclusiveContext* cx, HandleNativeObject obj, HandleId id,
|
||||
MutableHandleShape propp);
|
||||
MutableHandle<PropertyResult> propp);
|
||||
|
||||
template bool
|
||||
js::NativeLookupOwnProperty<NoGC>(ExclusiveContext* cx, NativeObject* const& obj, const jsid& id,
|
||||
FakeMutableHandle<Shape*> propp);
|
||||
FakeMutableHandle<PropertyResult> propp);
|
||||
|
||||
/*** [[DefineOwnProperty]] ***********************************************************************/
|
||||
|
||||
|
|
@ -1279,19 +1279,20 @@ GetExistingProperty(JSContext* cx,
|
|||
|
||||
static bool
|
||||
GetExistingPropertyValue(ExclusiveContext* cx, HandleNativeObject obj, HandleId id,
|
||||
HandleShape shape, MutableHandleValue vp)
|
||||
Handle<PropertyResult> prop, MutableHandleValue vp)
|
||||
{
|
||||
if (IsImplicitDenseOrTypedArrayElement(shape)) {
|
||||
if (prop.isDenseOrTypedArrayElement()) {
|
||||
vp.set(obj->getDenseOrTypedArrayElement(JSID_TO_INT(id)));
|
||||
return true;
|
||||
}
|
||||
if (!cx->shouldBeJSContext())
|
||||
return false;
|
||||
|
||||
MOZ_ASSERT(shape->propid() == id);
|
||||
MOZ_ASSERT(obj->contains(cx, shape));
|
||||
MOZ_ASSERT(prop.shape()->propid() == id);
|
||||
MOZ_ASSERT(obj->contains(cx, prop.shape()));
|
||||
|
||||
RootedValue receiver(cx, ObjectValue(*obj));
|
||||
RootedShape shape(cx, prop.shape());
|
||||
return GetExistingProperty<CanGC>(cx->asJSContext(), receiver, obj, shape, vp);
|
||||
}
|
||||
|
||||
|
|
@ -1302,7 +1303,7 @@ GetExistingPropertyValue(ExclusiveContext* cx, HandleNativeObject obj, HandleId
|
|||
*/
|
||||
static bool
|
||||
DefinePropertyIsRedundant(ExclusiveContext* cx, HandleNativeObject obj, HandleId id,
|
||||
HandleShape shape, unsigned shapeAttrs,
|
||||
Handle<PropertyResult> prop, unsigned shapeAttrs,
|
||||
Handle<PropertyDescriptor> desc, bool *redundant)
|
||||
{
|
||||
*redundant = false;
|
||||
|
|
@ -1319,16 +1320,16 @@ DefinePropertyIsRedundant(ExclusiveContext* cx, HandleNativeObject obj, HandleId
|
|||
if (desc.hasValue()) {
|
||||
// Get the current value of the existing property.
|
||||
RootedValue currentValue(cx);
|
||||
if (!IsImplicitDenseOrTypedArrayElement(shape) &&
|
||||
shape->hasSlot() &&
|
||||
shape->hasDefaultGetter())
|
||||
if (!prop.isDenseOrTypedArrayElement() &&
|
||||
prop.shape()->hasSlot() &&
|
||||
prop.shape()->hasDefaultGetter())
|
||||
{
|
||||
// Inline GetExistingPropertyValue in order to omit a type
|
||||
// correctness assertion that's too strict for this particular
|
||||
// call site. For details, see bug 1125624 comments 13-16.
|
||||
currentValue.set(obj->getSlot(shape->slot()));
|
||||
currentValue.set(obj->getSlot(prop.shape()->slot()));
|
||||
} else {
|
||||
if (!GetExistingPropertyValue(cx, obj, id, shape, ¤tValue))
|
||||
if (!GetExistingPropertyValue(cx, obj, id, prop, ¤tValue))
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -1339,22 +1340,24 @@ DefinePropertyIsRedundant(ExclusiveContext* cx, HandleNativeObject obj, HandleId
|
|||
}
|
||||
|
||||
GetterOp existingGetterOp =
|
||||
IsImplicitDenseOrTypedArrayElement(shape) ? nullptr : shape->getter();
|
||||
prop.isDenseOrTypedArrayElement() ? nullptr : prop.shape()->getter();
|
||||
if (desc.getter() != existingGetterOp)
|
||||
return true;
|
||||
|
||||
SetterOp existingSetterOp =
|
||||
IsImplicitDenseOrTypedArrayElement(shape) ? nullptr : shape->setter();
|
||||
prop.isDenseOrTypedArrayElement() ? nullptr : prop.shape()->setter();
|
||||
if (desc.setter() != existingSetterOp)
|
||||
return true;
|
||||
} else {
|
||||
if (desc.hasGetterObject()) {
|
||||
if (!(shapeAttrs & JSPROP_GETTER) || desc.getterObject() != shape->getterObject())
|
||||
return true;
|
||||
if (desc.hasGetterObject() &&
|
||||
(!(shapeAttrs & JSPROP_GETTER) || desc.getterObject() != prop.shape()->getterObject()))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
if (desc.hasSetterObject()) {
|
||||
if (!(shapeAttrs & JSPROP_SETTER) || desc.setterObject() != shape->setterObject())
|
||||
return true;
|
||||
if (desc.hasSetterObject() &&
|
||||
(!(shapeAttrs & JSPROP_SETTER) || desc.setterObject() != prop.shape()->setterObject()))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1421,14 +1424,14 @@ js::NativeDefineProperty(ExclusiveContext* cx, HandleNativeObject obj, HandleId
|
|||
}
|
||||
|
||||
// 9.1.6.1 OrdinaryDefineOwnProperty steps 1-2.
|
||||
RootedShape shape(cx);
|
||||
Rooted<PropertyResult> prop(cx);
|
||||
if (desc_.attributes() & JSPROP_RESOLVING) {
|
||||
// We are being called from a resolve or enumerate hook to reify a
|
||||
// lazily-resolved property. To avoid reentering the resolve hook and
|
||||
// recursing forever, skip the resolve hook when doing this lookup.
|
||||
NativeLookupOwnPropertyNoResolve(cx, obj, id, &shape);
|
||||
NativeLookupOwnPropertyNoResolve(cx, obj, id, &prop);
|
||||
} else {
|
||||
if (!NativeLookupOwnProperty<CanGC>(cx, obj, id, &shape))
|
||||
if (!NativeLookupOwnProperty<CanGC>(cx, obj, id, &prop))
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -1443,7 +1446,7 @@ js::NativeDefineProperty(ExclusiveContext* cx, HandleNativeObject obj, HandleId
|
|||
Rooted<PropertyDescriptor> desc(cx, desc_);
|
||||
|
||||
// Step 2.
|
||||
if (!shape) {
|
||||
if (!prop) {
|
||||
if (!obj->nonProxyIsExtensible())
|
||||
return result.fail(JSMSG_CANT_DEFINE_PROP_OBJECT_NOT_EXTENSIBLE);
|
||||
|
||||
|
|
@ -1455,21 +1458,20 @@ js::NativeDefineProperty(ExclusiveContext* cx, HandleNativeObject obj, HandleId
|
|||
return result.succeed();
|
||||
}
|
||||
|
||||
MOZ_ASSERT(shape);
|
||||
|
||||
// Steps 3-4. (Step 3 is a special case of step 4.) We use shapeAttrs as a
|
||||
// stand-in for shape in many places below, since shape might not be a
|
||||
// pointer to a real Shape (see IsImplicitDenseOrTypedArrayElement).
|
||||
unsigned shapeAttrs = GetShapeAttributes(obj, shape);
|
||||
unsigned shapeAttrs = GetPropertyAttributes(obj, prop);
|
||||
bool redundant;
|
||||
if (!DefinePropertyIsRedundant(cx, obj, id, shape, shapeAttrs, desc, &redundant))
|
||||
if (!DefinePropertyIsRedundant(cx, obj, id, prop, shapeAttrs, desc, &redundant))
|
||||
return false;
|
||||
if (redundant) {
|
||||
// In cases involving JSOP_NEWOBJECT and JSOP_INITPROP, obj can have a
|
||||
// type for this property that doesn't match the value in the slot.
|
||||
// Update the type here, even though this DefineProperty call is
|
||||
// otherwise a no-op. (See bug 1125624 comment 13.)
|
||||
if (!IsImplicitDenseOrTypedArrayElement(shape) && desc.hasValue()) {
|
||||
if (!prop.isDenseOrTypedArrayElement() && desc.hasValue()) {
|
||||
RootedShape shape(cx, prop.shape());
|
||||
if (!UpdateShapeTypeAndValue(cx, obj, shape, desc.value()))
|
||||
return false;
|
||||
}
|
||||
|
|
@ -1512,24 +1514,24 @@ js::NativeDefineProperty(ExclusiveContext* cx, HandleNativeObject obj, HandleId
|
|||
MOZ_ASSERT(!desc.hasSetterObject());
|
||||
if (IsDataDescriptor(shapeAttrs)) {
|
||||
RootedValue currentValue(cx);
|
||||
if (!GetExistingPropertyValue(cx, obj, id, shape, ¤tValue))
|
||||
if (!GetExistingPropertyValue(cx, obj, id, prop, ¤tValue))
|
||||
return false;
|
||||
desc.setValue(currentValue);
|
||||
desc.setWritable(IsWritable(shapeAttrs));
|
||||
} else {
|
||||
desc.setGetterObject(shape->getterObject());
|
||||
desc.setSetterObject(shape->setterObject());
|
||||
desc.setGetterObject(prop.shape()->getterObject());
|
||||
desc.setSetterObject(prop.shape()->setterObject());
|
||||
}
|
||||
} else if (desc.isDataDescriptor() != IsDataDescriptor(shapeAttrs)) {
|
||||
// Step 7.
|
||||
if (!IsConfigurable(shapeAttrs) && !skipRedefineChecks)
|
||||
return result.fail(JSMSG_CANT_REDEFINE_PROP);
|
||||
|
||||
if (IsImplicitDenseOrTypedArrayElement(shape)) {
|
||||
if (prop.isDenseOrTypedArrayElement()) {
|
||||
MOZ_ASSERT(!obj->is<TypedArrayObject>());
|
||||
if (!NativeObject::sparsifyDenseElement(cx, obj, JSID_TO_INT(id)))
|
||||
return false;
|
||||
shape = obj->lookup(cx, id);
|
||||
prop.setNativeProperty(obj->lookup(cx, id));
|
||||
}
|
||||
|
||||
// Fill in desc fields with default values (steps 7.b.i and 7.c.i).
|
||||
|
|
@ -1541,15 +1543,15 @@ js::NativeDefineProperty(ExclusiveContext* cx, HandleNativeObject obj, HandleId
|
|||
return result.fail(JSMSG_CANT_REDEFINE_PROP);
|
||||
|
||||
if (frozen || !desc.hasValue()) {
|
||||
if (IsImplicitDenseOrTypedArrayElement(shape)) {
|
||||
if (prop.isDenseOrTypedArrayElement()) {
|
||||
MOZ_ASSERT(!obj->is<TypedArrayObject>());
|
||||
if (!NativeObject::sparsifyDenseElement(cx, obj, JSID_TO_INT(id)))
|
||||
return false;
|
||||
shape = obj->lookup(cx, id);
|
||||
prop.setNativeProperty(obj->lookup(cx, id));
|
||||
}
|
||||
|
||||
RootedValue currentValue(cx);
|
||||
if (!GetExistingPropertyValue(cx, obj, id, shape, ¤tValue))
|
||||
if (!GetExistingPropertyValue(cx, obj, id, prop, ¤tValue))
|
||||
return false;
|
||||
|
||||
if (!desc.hasValue()) {
|
||||
|
|
@ -1571,32 +1573,32 @@ js::NativeDefineProperty(ExclusiveContext* cx, HandleNativeObject obj, HandleId
|
|||
desc.setWritable(IsWritable(shapeAttrs));
|
||||
} else {
|
||||
// Step 9.
|
||||
MOZ_ASSERT(shape->isAccessorDescriptor());
|
||||
MOZ_ASSERT(prop.shape()->isAccessorDescriptor());
|
||||
MOZ_ASSERT(desc.isAccessorDescriptor());
|
||||
|
||||
// The spec says to use SameValue, but since the values in
|
||||
// question are objects, we can just compare pointers.
|
||||
if (desc.hasSetterObject()) {
|
||||
if (!IsConfigurable(shapeAttrs) &&
|
||||
desc.setterObject() != shape->setterObject() &&
|
||||
desc.setterObject() != prop.shape()->setterObject() &&
|
||||
!skipRedefineChecks)
|
||||
{
|
||||
return result.fail(JSMSG_CANT_REDEFINE_PROP);
|
||||
}
|
||||
} else {
|
||||
// Fill in desc.[[Set]] from shape.
|
||||
desc.setSetterObject(shape->setterObject());
|
||||
desc.setSetterObject(prop.shape()->setterObject());
|
||||
}
|
||||
if (desc.hasGetterObject()) {
|
||||
if (!IsConfigurable(shapeAttrs) &&
|
||||
desc.getterObject() != shape->getterObject() &&
|
||||
desc.getterObject() != prop.shape()->getterObject() &&
|
||||
!skipRedefineChecks)
|
||||
{
|
||||
return result.fail(JSMSG_CANT_REDEFINE_PROP);
|
||||
}
|
||||
} else {
|
||||
// Fill in desc.[[Get]] from shape.
|
||||
desc.setGetterObject(shape->getterObject());
|
||||
desc.setGetterObject(prop.shape()->getterObject());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1681,18 +1683,18 @@ bool
|
|||
js::NativeHasProperty(JSContext* cx, HandleNativeObject obj, HandleId id, bool* foundp)
|
||||
{
|
||||
RootedNativeObject pobj(cx, obj);
|
||||
RootedShape shape(cx);
|
||||
Rooted<PropertyResult> prop(cx);
|
||||
|
||||
// This loop isn't explicit in the spec algorithm. See the comment on step
|
||||
// 7.a. below.
|
||||
for (;;) {
|
||||
// Steps 2-3. ('done' is a SpiderMonkey-specific thing, used below.)
|
||||
bool done;
|
||||
if (!LookupOwnPropertyInline<CanGC>(cx, pobj, id, &shape, &done))
|
||||
if (!LookupOwnPropertyInline<CanGC>(cx, pobj, id, &prop, &done))
|
||||
return false;
|
||||
|
||||
// Step 4.
|
||||
if (shape) {
|
||||
if (prop) {
|
||||
*foundp = true;
|
||||
return true;
|
||||
}
|
||||
|
|
@ -1733,15 +1735,15 @@ bool
|
|||
js::NativeGetOwnPropertyDescriptor(JSContext* cx, HandleNativeObject obj, HandleId id,
|
||||
MutableHandle<PropertyDescriptor> desc)
|
||||
{
|
||||
RootedShape shape(cx);
|
||||
if (!NativeLookupOwnProperty<CanGC>(cx, obj, id, &shape))
|
||||
Rooted<PropertyResult> prop(cx);
|
||||
if (!NativeLookupOwnProperty<CanGC>(cx, obj, id, &prop))
|
||||
return false;
|
||||
if (!shape) {
|
||||
if (!prop) {
|
||||
desc.object().set(nullptr);
|
||||
return true;
|
||||
}
|
||||
|
||||
desc.setAttributes(GetShapeAttributes(obj, shape));
|
||||
desc.setAttributes(GetPropertyAttributes(obj, prop));
|
||||
if (desc.isAccessorDescriptor()) {
|
||||
MOZ_ASSERT(desc.isShared());
|
||||
|
||||
|
|
@ -1754,13 +1756,13 @@ js::NativeGetOwnPropertyDescriptor(JSContext* cx, HandleNativeObject obj, Handle
|
|||
// than return true with desc incomplete, we fill out the missing
|
||||
// getter or setter with a null, following CompletePropertyDescriptor.
|
||||
if (desc.hasGetterObject()) {
|
||||
desc.setGetterObject(shape->getterObject());
|
||||
desc.setGetterObject(prop.shape()->getterObject());
|
||||
} else {
|
||||
desc.setGetterObject(nullptr);
|
||||
desc.attributesRef() |= JSPROP_GETTER;
|
||||
}
|
||||
if (desc.hasSetterObject()) {
|
||||
desc.setSetterObject(shape->setterObject());
|
||||
desc.setSetterObject(prop.shape()->setterObject());
|
||||
} else {
|
||||
desc.setSetterObject(nullptr);
|
||||
desc.attributesRef() |= JSPROP_SETTER;
|
||||
|
|
@ -1776,9 +1778,10 @@ js::NativeGetOwnPropertyDescriptor(JSContext* cx, HandleNativeObject obj, Handle
|
|||
desc.setSetter(nullptr);
|
||||
desc.attributesRef() &= ~JSPROP_SHARED;
|
||||
|
||||
if (IsImplicitDenseOrTypedArrayElement(shape)) {
|
||||
if (prop.isDenseOrTypedArrayElement()) {
|
||||
desc.value().set(obj->getDenseOrTypedArrayElement(JSID_TO_INT(id)));
|
||||
} else {
|
||||
RootedShape shape(cx, prop.shape());
|
||||
if (!NativeGetExistingProperty(cx, obj, obj, shape, desc.value()))
|
||||
return false;
|
||||
}
|
||||
|
|
@ -2058,23 +2061,25 @@ NativeGetPropertyInline(JSContext* cx,
|
|||
typename MaybeRooted<Value, allowGC>::MutableHandleType vp)
|
||||
{
|
||||
typename MaybeRooted<NativeObject*, allowGC>::RootType pobj(cx, obj);
|
||||
typename MaybeRooted<Shape*, allowGC>::RootType shape(cx);
|
||||
typename MaybeRooted<PropertyResult, allowGC>::RootType prop(cx);
|
||||
|
||||
// This loop isn't explicit in the spec algorithm. See the comment on step
|
||||
// 4.d below.
|
||||
for (;;) {
|
||||
// Steps 2-3. ('done' is a SpiderMonkey-specific thing, used below.)
|
||||
bool done;
|
||||
if (!LookupOwnPropertyInline<allowGC>(cx, pobj, id, &shape, &done))
|
||||
if (!LookupOwnPropertyInline<allowGC>(cx, pobj, id, &prop, &done))
|
||||
return false;
|
||||
|
||||
if (shape) {
|
||||
if (prop) {
|
||||
// Steps 5-8. Special case for dense elements because
|
||||
// GetExistingProperty doesn't support those.
|
||||
if (IsImplicitDenseOrTypedArrayElement(shape)) {
|
||||
if (prop.isDenseOrTypedArrayElement()) {
|
||||
vp.set(pobj->getDenseOrTypedArrayElement(JSID_TO_INT(id)));
|
||||
return true;
|
||||
}
|
||||
|
||||
typename MaybeRooted<Shape*, allowGC>::RootType shape(cx, prop.shape());
|
||||
return GetExistingProperty<allowGC>(cx, receiver, pobj, shape, vp);
|
||||
}
|
||||
|
||||
|
|
@ -2366,11 +2371,11 @@ SetDenseOrTypedArrayElement(JSContext* cx, HandleNativeObject obj, uint32_t inde
|
|||
*/
|
||||
static bool
|
||||
SetExistingProperty(JSContext* cx, HandleNativeObject obj, HandleId id, HandleValue v,
|
||||
HandleValue receiver, HandleNativeObject pobj, HandleShape shape,
|
||||
HandleValue receiver, HandleNativeObject pobj, Handle<PropertyResult> prop,
|
||||
ObjectOpResult& result)
|
||||
{
|
||||
// Step 5 for dense elements.
|
||||
if (IsImplicitDenseOrTypedArrayElement(shape)) {
|
||||
if (prop.isDenseOrTypedArrayElement()) {
|
||||
// Step 5.a.
|
||||
if (pobj->getElementsHeader()->isFrozen())
|
||||
return result.fail(JSMSG_READ_ONLY);
|
||||
|
|
@ -2384,6 +2389,7 @@ SetExistingProperty(JSContext* cx, HandleNativeObject obj, HandleId id, HandleVa
|
|||
}
|
||||
|
||||
// Step 5 for all other properties.
|
||||
RootedShape shape(cx, prop.shape());
|
||||
if (shape->isDataDescriptor()) {
|
||||
// Step 5.a.
|
||||
if (!shape->writable())
|
||||
|
|
@ -2441,7 +2447,7 @@ js::NativeSetProperty(JSContext* cx, HandleNativeObject obj, HandleId id, Handle
|
|||
// Step numbers below reference ES6 rev 27 9.1.9, the [[Set]] internal
|
||||
// method for ordinary objects. We substitute our own names for these names
|
||||
// used in the spec: O -> pobj, P -> id, ownDesc -> shape.
|
||||
RootedShape shape(cx);
|
||||
Rooted<PropertyResult> prop(cx);
|
||||
RootedNativeObject pobj(cx, obj);
|
||||
|
||||
// This loop isn't explicit in the spec algorithm. See the comment on step
|
||||
|
|
@ -2450,12 +2456,12 @@ js::NativeSetProperty(JSContext* cx, HandleNativeObject obj, HandleId id, Handle
|
|||
for (;;) {
|
||||
// Steps 2-3. ('done' is a SpiderMonkey-specific thing, used below.)
|
||||
bool done;
|
||||
if (!LookupOwnPropertyInline<CanGC>(cx, pobj, id, &shape, &done))
|
||||
if (!LookupOwnPropertyInline<CanGC>(cx, pobj, id, &prop, &done))
|
||||
return false;
|
||||
|
||||
if (shape) {
|
||||
if (prop) {
|
||||
// Steps 5-6.
|
||||
return SetExistingProperty(cx, obj, id, v, receiver, pobj, shape, result);
|
||||
return SetExistingProperty(cx, obj, id, v, receiver, pobj, prop, result);
|
||||
}
|
||||
|
||||
// Steps 4.a-b. The check for 'done' on this next line is tricky.
|
||||
|
|
@ -2513,12 +2519,12 @@ js::NativeDeleteProperty(JSContext* cx, HandleNativeObject obj, HandleId id,
|
|||
ObjectOpResult& result)
|
||||
{
|
||||
// Steps 2-3.
|
||||
RootedShape shape(cx);
|
||||
if (!NativeLookupOwnProperty<CanGC>(cx, obj, id, &shape))
|
||||
Rooted<PropertyResult> prop(cx);
|
||||
if (!NativeLookupOwnProperty<CanGC>(cx, obj, id, &prop))
|
||||
return false;
|
||||
|
||||
// Step 4.
|
||||
if (!shape) {
|
||||
if (!prop) {
|
||||
// If no property call the class's delProperty hook, passing succeeded
|
||||
// as the result parameter. This always succeeds when there is no hook.
|
||||
return CallJSDeletePropertyOp(cx, obj->getClass()->getDelProperty(), obj, id, result);
|
||||
|
|
@ -2527,7 +2533,7 @@ js::NativeDeleteProperty(JSContext* cx, HandleNativeObject obj, HandleId id,
|
|||
cx->runtime()->gc.poke();
|
||||
|
||||
// Step 6. Non-configurable property.
|
||||
if (GetShapeAttributes(obj, shape) & JSPROP_PERMANENT)
|
||||
if (GetPropertyAttributes(obj, prop) & JSPROP_PERMANENT)
|
||||
return result.failCantDelete();
|
||||
|
||||
if (!CallJSDeletePropertyOp(cx, obj->getClass()->getDelProperty(), obj, id, result))
|
||||
|
|
@ -2536,7 +2542,7 @@ js::NativeDeleteProperty(JSContext* cx, HandleNativeObject obj, HandleId id,
|
|||
return true;
|
||||
|
||||
// Step 5.
|
||||
if (IsImplicitDenseOrTypedArrayElement(shape)) {
|
||||
if (prop.isDenseOrTypedArrayElement()) {
|
||||
// Typed array elements are non-configurable.
|
||||
MOZ_ASSERT(!obj->is<TypedArrayObject>());
|
||||
|
||||
|
|
|
|||
|
|
@ -1459,7 +1459,7 @@ extern bool
|
|||
NativeLookupOwnProperty(ExclusiveContext* cx,
|
||||
typename MaybeRooted<NativeObject*, allowGC>::HandleType obj,
|
||||
typename MaybeRooted<jsid, allowGC>::HandleType id,
|
||||
typename MaybeRooted<Shape*, allowGC>::MutableHandleType propp);
|
||||
typename MaybeRooted<PropertyResult, allowGC>::MutableHandleType propp);
|
||||
|
||||
/*
|
||||
* Get a property from `receiver`, after having already done a lookup and found
|
||||
|
|
|
|||
|
|
@ -421,7 +421,7 @@ struct ObjectGroupCompartment::NewEntry
|
|||
}
|
||||
|
||||
static inline bool match(const ObjectGroupCompartment::NewEntry& key, const Lookup& lookup) {
|
||||
TaggedProto proto = key.group.unbarrieredGet()->proto().unbarrieredGet();
|
||||
TaggedProto proto = key.group.unbarrieredGet()->proto();
|
||||
JSObject* assoc = key.associated;
|
||||
MOZ_ASSERT(proto.hasUniqueId());
|
||||
MOZ_ASSERT_IF(assoc, assoc->zone()->hasUniqueId(assoc));
|
||||
|
|
|
|||
|
|
@ -265,24 +265,6 @@ class SavedStacks {
|
|||
uint32_t column;
|
||||
};
|
||||
|
||||
template <typename Outer>
|
||||
struct LocationValueOperations {
|
||||
JSAtom* source() const { return loc().source; }
|
||||
size_t line() const { return loc().line; }
|
||||
uint32_t column() const { return loc().column; }
|
||||
private:
|
||||
const LocationValue& loc() const { return static_cast<const Outer*>(this)->get(); }
|
||||
};
|
||||
|
||||
template <typename Outer>
|
||||
struct MutableLocationValueOperations : public LocationValueOperations<Outer> {
|
||||
void setSource(JSAtom* v) { loc().source = v; }
|
||||
void setLine(size_t v) { loc().line = v; }
|
||||
void setColumn(uint32_t v) { loc().column = v; }
|
||||
private:
|
||||
LocationValue& loc() { return static_cast<Outer*>(this)->get(); }
|
||||
};
|
||||
|
||||
private:
|
||||
struct PCLocationHasher : public DefaultHasher<PCKey> {
|
||||
using ScriptPtrHasher = DefaultHasher<JSScript*>;
|
||||
|
|
@ -313,15 +295,32 @@ class SavedStacks {
|
|||
MutableHandle<LocationValue> locationp);
|
||||
};
|
||||
|
||||
template <>
|
||||
class RootedBase<SavedStacks::LocationValue>
|
||||
: public SavedStacks::MutableLocationValueOperations<JS::Rooted<SavedStacks::LocationValue>>
|
||||
{};
|
||||
template <typename Wrapper>
|
||||
struct WrappedPtrOperations<SavedStacks::LocationValue, Wrapper>
|
||||
{
|
||||
JSAtom* source() const { return loc().source; }
|
||||
size_t line() const { return loc().line; }
|
||||
uint32_t column() const { return loc().column; }
|
||||
|
||||
template <>
|
||||
class MutableHandleBase<SavedStacks::LocationValue>
|
||||
: public SavedStacks::MutableLocationValueOperations<JS::MutableHandle<SavedStacks::LocationValue>>
|
||||
{};
|
||||
private:
|
||||
const SavedStacks::LocationValue& loc() const {
|
||||
return static_cast<const Wrapper*>(this)->get();
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Wrapper>
|
||||
struct MutableWrappedPtrOperations<SavedStacks::LocationValue, Wrapper>
|
||||
: public WrappedPtrOperations<SavedStacks::LocationValue, Wrapper>
|
||||
{
|
||||
void setSource(JSAtom* v) { loc().source = v; }
|
||||
void setLine(size_t v) { loc().line = v; }
|
||||
void setColumn(uint32_t v) { loc().column = v; }
|
||||
|
||||
private:
|
||||
SavedStacks::LocationValue& loc() {
|
||||
return static_cast<Wrapper*>(this)->get();
|
||||
}
|
||||
};
|
||||
|
||||
UTF8CharsZ
|
||||
BuildUTF8StackString(JSContext* cx, HandleObject stack);
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@
|
|||
namespace js {
|
||||
|
||||
class ModuleObject;
|
||||
class Scope;
|
||||
|
||||
enum class BindingKind : uint8_t
|
||||
{
|
||||
|
|
@ -223,6 +224,21 @@ class BindingLocation
|
|||
}
|
||||
};
|
||||
|
||||
//
|
||||
// Allow using is<T> and as<T> on Rooted<Scope*> and Handle<Scope*>.
|
||||
//
|
||||
template <typename Wrapper>
|
||||
class WrappedPtrOperations<Scope*, Wrapper>
|
||||
{
|
||||
public:
|
||||
template <class U>
|
||||
JS::Handle<U*> as() const {
|
||||
const Wrapper& self = *static_cast<const Wrapper*>(this);
|
||||
MOZ_ASSERT_IF(self, self->template is<U>());
|
||||
return Handle<U*>::fromMarkedLocation(reinterpret_cast<U* const*>(self.address()));
|
||||
}
|
||||
};
|
||||
|
||||
//
|
||||
// The base class of all Scopes.
|
||||
//
|
||||
|
|
@ -1338,10 +1354,10 @@ class MOZ_STACK_CLASS ScopeIter
|
|||
// Specializations of Rooted containers for the iterators.
|
||||
//
|
||||
|
||||
template <typename Outer>
|
||||
class BindingIterOperations
|
||||
template <typename Wrapper>
|
||||
class WrappedPtrOperations<BindingIter, Wrapper>
|
||||
{
|
||||
const BindingIter& iter() const { return static_cast<const Outer*>(this)->get(); }
|
||||
const BindingIter& iter() const { return static_cast<const Wrapper*>(this)->get(); }
|
||||
|
||||
public:
|
||||
bool done() const { return iter().done(); }
|
||||
|
|
@ -1361,19 +1377,20 @@ class BindingIterOperations
|
|||
uint32_t nextEnvironmentSlot() const { return iter().nextEnvironmentSlot(); }
|
||||
};
|
||||
|
||||
template <typename Outer>
|
||||
class MutableBindingIterOperations : public BindingIterOperations<Outer>
|
||||
template <typename Wrapper>
|
||||
class MutableWrappedPtrOperations<BindingIter, Wrapper>
|
||||
: public WrappedPtrOperations<BindingIter, Wrapper>
|
||||
{
|
||||
BindingIter& iter() { return static_cast<Outer*>(this)->get(); }
|
||||
BindingIter& iter() { return static_cast<Wrapper*>(this)->get(); }
|
||||
|
||||
public:
|
||||
void operator++(int) { iter().operator++(1); }
|
||||
};
|
||||
|
||||
template <typename Outer>
|
||||
class ScopeIterOperations
|
||||
template <typename Wrapper>
|
||||
class WrappedPtrOperations<ScopeIter, Wrapper>
|
||||
{
|
||||
const ScopeIter& iter() const { return static_cast<const Outer*>(this)->get(); }
|
||||
const ScopeIter& iter() const { return static_cast<const Wrapper*>(this)->get(); }
|
||||
|
||||
public:
|
||||
bool done() const { return iter().done(); }
|
||||
|
|
@ -1384,69 +1401,16 @@ class ScopeIterOperations
|
|||
bool hasSyntacticEnvironment() const { return iter().hasSyntacticEnvironment(); }
|
||||
};
|
||||
|
||||
template <typename Outer>
|
||||
class MutableScopeIterOperations : public ScopeIterOperations<Outer>
|
||||
template <typename Wrapper>
|
||||
class MutableWrappedPtrOperations<ScopeIter, Wrapper>
|
||||
: public WrappedPtrOperations<ScopeIter, Wrapper>
|
||||
{
|
||||
ScopeIter& iter() { return static_cast<Outer*>(this)->get(); }
|
||||
ScopeIter& iter() { return static_cast<Wrapper*>(this)->get(); }
|
||||
|
||||
public:
|
||||
void operator++(int) { iter().operator++(1); }
|
||||
};
|
||||
|
||||
#define SPECIALIZE_ROOTING_CONTAINERS(Iter, BaseIter) \
|
||||
template <> \
|
||||
class RootedBase<Iter> \
|
||||
: public Mutable##BaseIter##Operations<JS::Rooted<Iter>> \
|
||||
{ }; \
|
||||
\
|
||||
template <> \
|
||||
class MutableHandleBase<Iter> \
|
||||
: public Mutable##BaseIter##Operations<JS::MutableHandle<Iter>> \
|
||||
{ }; \
|
||||
\
|
||||
template <> \
|
||||
class HandleBase<Iter> \
|
||||
: public BaseIter##Operations<JS::Handle<Iter>> \
|
||||
{ }; \
|
||||
\
|
||||
template <> \
|
||||
class PersistentRootedBase<Iter> \
|
||||
: public Mutable##BaseIter##Operations<JS::PersistentRooted<Iter>> \
|
||||
{ }
|
||||
|
||||
SPECIALIZE_ROOTING_CONTAINERS(BindingIter, BindingIter);
|
||||
SPECIALIZE_ROOTING_CONTAINERS(PositionalFormalParameterIter, BindingIter);
|
||||
SPECIALIZE_ROOTING_CONTAINERS(ScopeIter, ScopeIter);
|
||||
|
||||
#undef SPECIALIZE_ROOTING_CONTAINERS
|
||||
|
||||
//
|
||||
// Allow using is<T> and as<T> on Rooted<Scope*> and Handle<Scope*>.
|
||||
//
|
||||
|
||||
template <typename Outer>
|
||||
struct ScopeCastOperation
|
||||
{
|
||||
template <class U>
|
||||
JS::Handle<U*> as() const {
|
||||
const Outer& self = *static_cast<const Outer*>(this);
|
||||
MOZ_ASSERT_IF(self, self->template is<U>());
|
||||
return Handle<U*>::fromMarkedLocation(reinterpret_cast<U* const*>(self.address()));
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
class RootedBase<Scope*> : public ScopeCastOperation<JS::Rooted<Scope*>>
|
||||
{ };
|
||||
|
||||
template <>
|
||||
class HandleBase<Scope*> : public ScopeCastOperation<JS::Handle<Scope*>>
|
||||
{ };
|
||||
|
||||
template <>
|
||||
class MutableHandleBase<Scope*> : public ScopeCastOperation<JS::MutableHandle<Scope*>>
|
||||
{ };
|
||||
|
||||
} // namespace js
|
||||
|
||||
namespace JS {
|
||||
|
|
|
|||
|
|
@ -123,7 +123,7 @@ Shape::new_(ExclusiveContext* cx, Handle<StackShape> other, uint32_t nfixed)
|
|||
inline void
|
||||
Shape::updateBaseShapeAfterMovingGC()
|
||||
{
|
||||
BaseShape* base = base_.unbarrieredGet();
|
||||
BaseShape* base = base_;
|
||||
if (IsForwarded(base))
|
||||
base_.unsafeSet(Forwarded(base));
|
||||
}
|
||||
|
|
@ -191,17 +191,17 @@ AutoRooterGetterSetter::AutoRooterGetterSetter(ExclusiveContext* cx, uint8_t att
|
|||
}
|
||||
|
||||
static inline uint8_t
|
||||
GetShapeAttributes(JSObject* obj, Shape* shape)
|
||||
GetPropertyAttributes(JSObject* obj, PropertyResult prop)
|
||||
{
|
||||
MOZ_ASSERT(obj->isNative());
|
||||
|
||||
if (IsImplicitDenseOrTypedArrayElement(shape)) {
|
||||
if (prop.isDenseOrTypedArrayElement()) {
|
||||
if (obj->is<TypedArrayObject>())
|
||||
return JSPROP_ENUMERATE | JSPROP_PERMANENT;
|
||||
return obj->as<NativeObject>().getElementsHeader()->elementAttributes();
|
||||
}
|
||||
|
||||
return shape->attributes();
|
||||
return prop.shape()->attributes();
|
||||
}
|
||||
|
||||
} /* namespace js */
|
||||
|
|
|
|||
|
|
@ -1771,3 +1771,10 @@ JS::ubi::Concrete<js::BaseShape>::size(mozilla::MallocSizeOf mallocSizeOf) const
|
|||
{
|
||||
return js::gc::Arena::thingSize(get().asTenured().getAllocKind());
|
||||
}
|
||||
|
||||
void
|
||||
PropertyResult::trace(JSTracer* trc)
|
||||
{
|
||||
if (isNativeProperty())
|
||||
TraceRoot(trc, &shape_, "PropertyResult::shape_");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1264,9 +1264,10 @@ struct InitialShapeEntry
|
|||
|
||||
bool needsSweep() {
|
||||
Shape* ushape = shape.unbarrieredGet();
|
||||
JSObject* protoObj = proto.proto().raw();
|
||||
TaggedProto uproto = proto.proto().unbarrieredGet();
|
||||
JSObject* protoObj = uproto.raw();
|
||||
return (gc::IsAboutToBeFinalizedUnbarriered(&ushape) ||
|
||||
(proto.proto().isObject() && gc::IsAboutToBeFinalizedUnbarriered(&protoObj)));
|
||||
(uproto.isObject() && gc::IsAboutToBeFinalizedUnbarriered(&protoObj)));
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -1356,9 +1357,10 @@ struct StackShape
|
|||
void trace(JSTracer* trc);
|
||||
};
|
||||
|
||||
template <typename Outer>
|
||||
class StackShapeOperations {
|
||||
const StackShape& ss() const { return static_cast<const Outer*>(this)->get(); }
|
||||
template <typename Wrapper>
|
||||
class WrappedPtrOperations<StackShape, Wrapper>
|
||||
{
|
||||
const StackShape& ss() const { return static_cast<const Wrapper*>(this)->get(); }
|
||||
|
||||
public:
|
||||
bool hasSlot() const { return ss().hasSlot(); }
|
||||
|
|
@ -1370,9 +1372,11 @@ class StackShapeOperations {
|
|||
uint8_t attrs() const { return ss().attrs; }
|
||||
};
|
||||
|
||||
template <typename Outer>
|
||||
class MutableStackShapeOperations : public StackShapeOperations<Outer> {
|
||||
StackShape& ss() { return static_cast<Outer*>(this)->get(); }
|
||||
template <typename Wrapper>
|
||||
class MutableWrappedPtrOperations<StackShape, Wrapper>
|
||||
: public WrappedPtrOperations<StackShape, Wrapper>
|
||||
{
|
||||
StackShape& ss() { return static_cast<Wrapper*>(this)->get(); }
|
||||
|
||||
public:
|
||||
void updateGetterSetter(GetterOp rawGetter, SetterOp rawSetter) {
|
||||
|
|
@ -1383,19 +1387,6 @@ class MutableStackShapeOperations : public StackShapeOperations<Outer> {
|
|||
void setAttrs(uint8_t attrs) { ss().attrs = attrs; }
|
||||
};
|
||||
|
||||
template <>
|
||||
class RootedBase<StackShape> : public MutableStackShapeOperations<JS::Rooted<StackShape>>
|
||||
{};
|
||||
|
||||
template <>
|
||||
class HandleBase<StackShape> : public StackShapeOperations<JS::Handle<StackShape>>
|
||||
{};
|
||||
|
||||
template <>
|
||||
class MutableHandleBase<StackShape>
|
||||
: public MutableStackShapeOperations<JS::MutableHandle<StackShape>>
|
||||
{};
|
||||
|
||||
inline
|
||||
Shape::Shape(const StackShape& other, uint32_t nfixed)
|
||||
: base_(other.base),
|
||||
|
|
@ -1550,38 +1541,6 @@ Shape::matches(const StackShape& other) const
|
|||
other.rawGetter, other.rawSetter);
|
||||
}
|
||||
|
||||
// Property lookup hooks on objects are required to return a non-nullptr shape
|
||||
// to signify that the property has been found. For cases where the property is
|
||||
// not actually represented by a Shape, use a dummy value. This includes all
|
||||
// properties of non-native objects, and dense elements for native objects.
|
||||
// Use separate APIs for these two cases.
|
||||
|
||||
template <AllowGC allowGC>
|
||||
static inline void
|
||||
MarkNonNativePropertyFound(typename MaybeRooted<Shape*, allowGC>::MutableHandleType propp)
|
||||
{
|
||||
propp.set(reinterpret_cast<Shape*>(1));
|
||||
}
|
||||
|
||||
template <AllowGC allowGC>
|
||||
static inline void
|
||||
MarkDenseOrTypedArrayElementFound(typename MaybeRooted<Shape*, allowGC>::MutableHandleType propp)
|
||||
{
|
||||
propp.set(reinterpret_cast<Shape*>(1));
|
||||
}
|
||||
|
||||
static inline bool
|
||||
IsImplicitDenseOrTypedArrayElement(Shape* prop)
|
||||
{
|
||||
return prop == reinterpret_cast<Shape*>(1);
|
||||
}
|
||||
|
||||
static inline bool
|
||||
IsImplicitNonNativeProperty(Shape* prop)
|
||||
{
|
||||
return prop == reinterpret_cast<Shape*>(1);
|
||||
}
|
||||
|
||||
Shape*
|
||||
ReshapeForAllocKind(JSContext* cx, Shape* shape, TaggedProto proto,
|
||||
gc::AllocKind allocKind);
|
||||
|
|
|
|||
|
|
@ -11,8 +11,8 @@
|
|||
template<typename T>
|
||||
class SharedMem
|
||||
{
|
||||
static_assert(mozilla::IsPointer<T>::value,
|
||||
"SharedMem encapsulates pointer types");
|
||||
// static_assert(mozilla::IsPointer<T>::value,
|
||||
// "SharedMem encapsulates pointer types");
|
||||
|
||||
enum Sharedness {
|
||||
IsUnshared,
|
||||
|
|
|
|||
|
|
@ -521,7 +521,7 @@ class JSString : public js::gc::TenuredCell
|
|||
}
|
||||
|
||||
static MOZ_ALWAYS_INLINE void writeBarrierPre(JSString* thing) {
|
||||
if (isNullLike(thing) || thing->isPermanentAtom())
|
||||
if (!thing || thing->isPermanentAtom())
|
||||
return;
|
||||
|
||||
TenuredCell::writeBarrierPre(thing);
|
||||
|
|
|
|||
|
|
@ -68,20 +68,16 @@ struct InternalBarrierMethods<TaggedProto>
|
|||
|
||||
static void readBarrier(const TaggedProto& proto);
|
||||
|
||||
static bool isMarkableTaggedPointer(TaggedProto proto) {
|
||||
return proto.isObject();
|
||||
}
|
||||
|
||||
static bool isMarkable(TaggedProto proto) {
|
||||
return proto.isObject();
|
||||
}
|
||||
};
|
||||
|
||||
template<class Outer>
|
||||
class TaggedProtoOperations
|
||||
template <class Wrapper>
|
||||
class WrappedPtrOperations<TaggedProto, Wrapper>
|
||||
{
|
||||
const TaggedProto& value() const {
|
||||
return static_cast<const Outer*>(this)->get();
|
||||
return static_cast<const Wrapper*>(this)->get();
|
||||
}
|
||||
|
||||
public:
|
||||
|
|
@ -95,18 +91,6 @@ class TaggedProtoOperations
|
|||
uint64_t uniqueId() const { return value().uniqueId(); }
|
||||
};
|
||||
|
||||
template <>
|
||||
class HandleBase<TaggedProto> : public TaggedProtoOperations<Handle<TaggedProto>>
|
||||
{};
|
||||
|
||||
template <>
|
||||
class RootedBase<TaggedProto> : public TaggedProtoOperations<Rooted<TaggedProto>>
|
||||
{};
|
||||
|
||||
template <>
|
||||
class BarrieredBaseMixins<TaggedProto> : public TaggedProtoOperations<GCPtr<TaggedProto>>
|
||||
{};
|
||||
|
||||
// If the TaggedProto is a JSObject pointer, convert to that type and call |f|
|
||||
// with the pointer. If the TaggedProto is lazy, calls F::defaultValue.
|
||||
template <typename F, typename... Args>
|
||||
|
|
|
|||
|
|
@ -720,10 +720,10 @@ UnboxedPlainObject::createWithProperties(ExclusiveContext* cx, HandleObjectGroup
|
|||
/* static */ bool
|
||||
UnboxedPlainObject::obj_lookupProperty(JSContext* cx, HandleObject obj,
|
||||
HandleId id, MutableHandleObject objp,
|
||||
MutableHandleShape propp)
|
||||
MutableHandle<PropertyResult> propp)
|
||||
{
|
||||
if (obj->as<UnboxedPlainObject>().containsUnboxedOrExpandoProperty(cx, id)) {
|
||||
MarkNonNativePropertyFound<CanGC>(propp);
|
||||
propp.setNonNativeProperty();
|
||||
objp.set(obj);
|
||||
return true;
|
||||
}
|
||||
|
|
@ -731,7 +731,7 @@ UnboxedPlainObject::obj_lookupProperty(JSContext* cx, HandleObject obj,
|
|||
RootedObject proto(cx, obj->staticPrototype());
|
||||
if (!proto) {
|
||||
objp.set(nullptr);
|
||||
propp.set(nullptr);
|
||||
propp.setNotFound();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -1411,10 +1411,10 @@ UnboxedArrayObject::containsProperty(ExclusiveContext* cx, jsid id)
|
|||
/* static */ bool
|
||||
UnboxedArrayObject::obj_lookupProperty(JSContext* cx, HandleObject obj,
|
||||
HandleId id, MutableHandleObject objp,
|
||||
MutableHandleShape propp)
|
||||
MutableHandle<PropertyResult> propp)
|
||||
{
|
||||
if (obj->as<UnboxedArrayObject>().containsProperty(cx, id)) {
|
||||
MarkNonNativePropertyFound<CanGC>(propp);
|
||||
propp.setNonNativeProperty();
|
||||
objp.set(obj);
|
||||
return true;
|
||||
}
|
||||
|
|
@ -1422,7 +1422,7 @@ UnboxedArrayObject::obj_lookupProperty(JSContext* cx, HandleObject obj,
|
|||
RootedObject proto(cx, obj->staticPrototype());
|
||||
if (!proto) {
|
||||
objp.set(nullptr);
|
||||
propp.set(nullptr);
|
||||
propp.setNotFound();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -242,7 +242,7 @@ class UnboxedPlainObject : public JSObject
|
|||
|
||||
static bool obj_lookupProperty(JSContext* cx, HandleObject obj,
|
||||
HandleId id, MutableHandleObject objp,
|
||||
MutableHandleShape propp);
|
||||
MutableHandle<PropertyResult> propp);
|
||||
|
||||
static bool obj_defineProperty(JSContext* cx, HandleObject obj, HandleId id,
|
||||
Handle<PropertyDescriptor> desc,
|
||||
|
|
@ -378,7 +378,7 @@ class UnboxedArrayObject : public JSObject
|
|||
|
||||
static bool obj_lookupProperty(JSContext* cx, HandleObject obj,
|
||||
HandleId id, MutableHandleObject objp,
|
||||
MutableHandleShape propp);
|
||||
MutableHandle<PropertyResult> propp);
|
||||
|
||||
static bool obj_defineProperty(JSContext* cx, HandleObject obj, HandleId id,
|
||||
Handle<PropertyDescriptor> desc,
|
||||
|
|
|
|||
|
|
@ -470,7 +470,7 @@ inline
|
|||
void XPCWrappedNativeTearOff::JSObjectMoved(JSObject* obj, const JSObject* old)
|
||||
{
|
||||
MOZ_ASSERT(!IsMarked());
|
||||
MOZ_ASSERT(mJSObject.unbarrieredGetPtr() == old);
|
||||
MOZ_ASSERT(mJSObject == old);
|
||||
mJSObject = obj;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -935,7 +935,7 @@ void
|
|||
XPCWrappedNative::FlatJSObjectMoved(JSObject* obj, const JSObject* old)
|
||||
{
|
||||
JS::AutoAssertGCCallback inCallback(obj);
|
||||
MOZ_ASSERT(mFlatJSObject.unbarrieredGetPtr() == old);
|
||||
MOZ_ASSERT(mFlatJSObject == old);
|
||||
|
||||
nsWrapperCache* cache = nullptr;
|
||||
CallQueryInterface(mIdentity, &cache);
|
||||
|
|
|
|||
|
|
@ -114,7 +114,7 @@ XPCWrappedNativeProto::CallPostCreatePrototype()
|
|||
void
|
||||
XPCWrappedNativeProto::JSProtoObjectFinalized(js::FreeOp* fop, JSObject* obj)
|
||||
{
|
||||
MOZ_ASSERT(obj == mJSProtoObject.unbarrieredGet(), "huh?");
|
||||
MOZ_ASSERT(obj == mJSProtoObject, "huh?");
|
||||
|
||||
// Only remove this proto from the map if it is the one in the map.
|
||||
ClassInfo2WrappedNativeProtoMap* map = GetScope()->GetWrappedNativeProtoMap();
|
||||
|
|
@ -129,7 +129,7 @@ XPCWrappedNativeProto::JSProtoObjectFinalized(js::FreeOp* fop, JSObject* obj)
|
|||
void
|
||||
XPCWrappedNativeProto::JSProtoObjectMoved(JSObject* obj, const JSObject* old)
|
||||
{
|
||||
MOZ_ASSERT(mJSProtoObject.unbarrieredGet() == old);
|
||||
MOZ_ASSERT(mJSProtoObject == old);
|
||||
mJSProtoObject.init(obj); // Update without triggering barriers.
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -581,9 +581,9 @@ nsOpenTypeTable::MakeTextRun(DrawTarget* aDrawTarget,
|
|||
aFontGroup->GetFirstValidFont()->
|
||||
GetGlyphHAdvance(aDrawTarget, aGlyph.glyphID));
|
||||
detailedGlyph.mXOffset = detailedGlyph.mYOffset = 0;
|
||||
gfxShapedText::CompressedGlyph g;
|
||||
g.SetComplex(true, true, 1);
|
||||
textRun->SetGlyphs(0, g, &detailedGlyph);
|
||||
textRun->SetGlyphs(0,
|
||||
gfxShapedText::CompressedGlyph::MakeComplex(true, true, 1),
|
||||
&detailedGlyph);
|
||||
|
||||
return textRun.forget();
|
||||
}
|
||||
|
|
@ -1459,7 +1459,7 @@ nsMathMLChar::StretchEnumContext::EnumCallback(const FontFamilyName& aFamily,
|
|||
if (!openTypeTable) {
|
||||
if (context->mTablesTried.Contains(glyphTable))
|
||||
return true; // already tried this one
|
||||
|
||||
|
||||
// Only try this table once.
|
||||
context->mTablesTried.AppendElement(glyphTable);
|
||||
}
|
||||
|
|
@ -1626,7 +1626,7 @@ nsMathMLChar::StretchInternal(nsPresContext* aPresContext,
|
|||
if (!maxWidth && !largeop) {
|
||||
// Doing Stretch() not GetMaxWidth(),
|
||||
// and not a largeop in display mode; we're done if size fits
|
||||
if ((targetSize <= 0) ||
|
||||
if ((targetSize <= 0) ||
|
||||
((isVertical && charSize >= targetSize) ||
|
||||
IsSizeOK(charSize, targetSize, aStretchHint)))
|
||||
done = true;
|
||||
|
|
@ -1678,7 +1678,7 @@ nsMathMLChar::StretchInternal(nsPresContext* aPresContext,
|
|||
// variables accordingly.
|
||||
mUnscaledAscent = aDesiredStretchSize.ascent;
|
||||
}
|
||||
|
||||
|
||||
if (glyphFound) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
|
@ -1695,7 +1695,7 @@ nsMathMLChar::StretchInternal(nsPresContext* aPresContext,
|
|||
if (!Preferences::GetBool("mathml.scale_stretchy_operators.enabled", true)) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
// stretchy character
|
||||
if (stretchy) {
|
||||
if (isVertical) {
|
||||
|
|
@ -1863,7 +1863,7 @@ public:
|
|||
nsDisplayMathMLCharForeground(nsDisplayListBuilder* aBuilder,
|
||||
nsIFrame* aFrame, nsMathMLChar* aChar,
|
||||
uint32_t aIndex, bool aIsSelected)
|
||||
: nsDisplayItem(aBuilder, aFrame), mChar(aChar),
|
||||
: nsDisplayItem(aBuilder, aFrame), mChar(aChar),
|
||||
mIndex(aIndex), mIsSelected(aIsSelected) {
|
||||
MOZ_COUNT_CTOR(nsDisplayMathMLCharForeground);
|
||||
}
|
||||
|
|
@ -1886,7 +1886,7 @@ public:
|
|||
temp.Inflate(mFrame->PresContext()->AppUnitsPerDevPixel());
|
||||
return temp;
|
||||
}
|
||||
|
||||
|
||||
virtual void Paint(nsDisplayListBuilder* aBuilder,
|
||||
nsRenderingContext* aCtx) override
|
||||
{
|
||||
|
|
@ -1901,7 +1901,7 @@ public:
|
|||
bool snap;
|
||||
return GetBounds(aBuilder, &snap);
|
||||
}
|
||||
|
||||
|
||||
virtual uint32_t GetPerFrameKey() override {
|
||||
return (mIndex << nsDisplayItem::TYPE_BITS)
|
||||
| nsDisplayItem::GetPerFrameKey();
|
||||
|
|
@ -2355,7 +2355,7 @@ nsMathMLChar::PaintHorizontally(nsPresContext* aPresContext,
|
|||
// _cairo_scaled_font_glyph_device_extents rounds outwards to the nearest
|
||||
// pixel, so the bm values can include 1 row of faint pixels on each edge.
|
||||
// Don't rely on this pixel as it can look like a gap.
|
||||
if (bm.rightBearing - bm.leftBearing >= 2 * oneDevPixel) {
|
||||
if (bm.rightBearing - bm.leftBearing >= 2 * oneDevPixel) {
|
||||
start[i] = dx + bm.leftBearing + oneDevPixel; // left join
|
||||
end[i] = dx + bm.rightBearing - oneDevPixel; // right join
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -931,7 +931,6 @@ nsresult
|
|||
nsSocketTransport::InitWithConnectedSocket(PRFileDesc *fd, const NetAddr *addr)
|
||||
{
|
||||
MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread, "wrong thread");
|
||||
NS_ASSERTION(!mFD.IsInitialized(), "already initialized");
|
||||
|
||||
char buf[kNetAddrMaxCStrBufSize];
|
||||
NetAddrToString(addr, buf, sizeof(buf));
|
||||
|
|
@ -957,6 +956,7 @@ nsSocketTransport::InitWithConnectedSocket(PRFileDesc *fd, const NetAddr *addr)
|
|||
{
|
||||
MutexAutoLock lock(mLock);
|
||||
|
||||
NS_ASSERTION(!mFD.IsInitialized(), "already initialized");
|
||||
mFD = fd;
|
||||
mFDref = 1;
|
||||
mFDconnected = 1;
|
||||
|
|
@ -1320,11 +1320,14 @@ nsSocketTransport::InitiateSocket()
|
|||
//
|
||||
// if we already have a connected socket, then just attach and return.
|
||||
//
|
||||
if (mFD.IsInitialized()) {
|
||||
{
|
||||
MutexAutoLock lock(mLock);
|
||||
if (mFD.IsInitialized()) {
|
||||
rv = mSocketTransportService->AttachSocket(mFD, this);
|
||||
if (NS_SUCCEEDED(rv))
|
||||
mAttached = true;
|
||||
mAttached = true;
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
|
|
@ -1390,18 +1393,18 @@ nsSocketTransport::InitiateSocket()
|
|||
PR_SetSocketOption(fd, &opt);
|
||||
#endif
|
||||
|
||||
// inform socket transport about this newly created socket...
|
||||
rv = mSocketTransportService->AttachSocket(fd, this);
|
||||
if (NS_FAILED(rv)) {
|
||||
CloseSocket(fd);
|
||||
return rv;
|
||||
}
|
||||
mAttached = true;
|
||||
|
||||
// assign mFD so that we can properly handle OnSocketDetached before we've
|
||||
// established a connection.
|
||||
{
|
||||
MutexAutoLock lock(mLock);
|
||||
// inform socket transport about this newly created socket...
|
||||
rv = mSocketTransportService->AttachSocket(fd, this);
|
||||
if (NS_FAILED(rv)) {
|
||||
CloseSocket(fd);
|
||||
return rv;
|
||||
}
|
||||
mAttached = true;
|
||||
|
||||
mFD = fd;
|
||||
mFDref = 1;
|
||||
mFDconnected = false;
|
||||
|
|
@ -1546,8 +1549,12 @@ nsSocketTransport::RecoverFromError()
|
|||
|
||||
nsresult rv;
|
||||
|
||||
// OK to check this outside mLock
|
||||
NS_ASSERTION(!mFDconnected, "socket should not be connected");
|
||||
#ifdef DEBUG
|
||||
{
|
||||
MutexAutoLock lock(mLock);
|
||||
NS_ASSERTION(!mFDconnected, "socket should not be connected");
|
||||
}
|
||||
#endif
|
||||
|
||||
// all connection failures need to be reported to DNS so that the next
|
||||
// time we will use a different address if available.
|
||||
|
|
|
|||
|
|
@ -350,11 +350,13 @@ private:
|
|||
|
||||
void OnMsgInputPending()
|
||||
{
|
||||
MOZ_ASSERT(OnSocketThread(), "not on socket thread");
|
||||
if (mState == STATE_TRANSFERRING)
|
||||
mPollFlags |= (PR_POLL_READ | PR_POLL_EXCEPT);
|
||||
}
|
||||
void OnMsgOutputPending()
|
||||
{
|
||||
MOZ_ASSERT(OnSocketThread(), "not on socket thread");
|
||||
if (mState == STATE_TRANSFERRING)
|
||||
mPollFlags |= (PR_POLL_WRITE | PR_POLL_EXCEPT);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -611,6 +611,14 @@ function UpdateParser(aId, aUpdateKey, aUrl, aObserver) {
|
|||
let requireBuiltIn = Services.prefs.getBoolPref(PREF_UPDATE_REQUIREBUILTINCERTS, true);
|
||||
|
||||
logger.debug("Requesting " + aUrl);
|
||||
|
||||
if (!aUrl) {
|
||||
logger.warn("Request failed: empty update manifest URL");
|
||||
this._doneAt = new Error("UP_emptyManifestURL");
|
||||
this.notifyError(AddonUpdateChecker.ERROR_DOWNLOAD_ERROR);
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
this.request = new ServiceRequest();
|
||||
this.request.open("GET", this.url, true);
|
||||
|
|
|
|||
|
|
@ -6135,7 +6135,11 @@ function UpdateChecker(aAddon, aListener, aReason, aAppVersion, aPlatformVersion
|
|||
if ("onUpdateAvailable" in this.listener)
|
||||
aReason |= UPDATE_TYPE_NEWVERSION;
|
||||
|
||||
let url = escapeAddonURI(aAddon, updateURL, aReason, aAppVersion);
|
||||
// Don't perform substitutions on the update URL if we still don't
|
||||
// have one at this point.
|
||||
let url = updateURL ?
|
||||
escapeAddonURI(aAddon, url, aReason, aAppVersion) :
|
||||
updateURL;
|
||||
this._parser = AddonUpdateChecker.checkForUpdates(aAddon.id, aAddon.updateKey,
|
||||
url, this);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,12 +13,17 @@ interface nsIPrincipal;
|
|||
|
||||
%{ C++
|
||||
|
||||
// Internal formats must have their second part starting with 'x-moz-',
|
||||
// for example text/x-moz-internaltype. These cannot be assigned by
|
||||
// unprivileged content but all other types can.
|
||||
#define kInternal_Mimetype_Prefix "/x-moz-"
|
||||
|
||||
// these probably shouldn't live here, but in some central repository shared
|
||||
// by the entire app.
|
||||
#define kTextMime "text/plain"
|
||||
#define kRTFMime "text/rtf"
|
||||
#define kUnicodeMime "text/unicode"
|
||||
#define kMozTextInternal "text/x-moz-text-internal" // text data which isn't suppoed to be parsed by other apps.
|
||||
#define kMozTextInternal "text/x-moz-text-internal" // text data which isn't suppoed to be parsed by other apps.
|
||||
#define kHTMLMime "text/html"
|
||||
#define kAOLMailMime "AOLMAIL"
|
||||
#define kPNGImageMime "image/png"
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue