mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-19 00:05:36 +00:00
Bug 903519 - Force non-atom strings to have their low flag bit set in order to distinguish them from JSObjects in the nursery, r=jandem
Atoms will not be nursery-allocated, so if a cell is in the nursery and its low bit is set, we can be sure it's a string. --HG-- extra : rebase_source : 22a9b99c4053532dbe33597ef33335574ef4c98b
This commit is contained in:
parent
055f32d6b8
commit
a5d00c04c8
@ -16,7 +16,7 @@ mozilla.prettyprinters.clear_module_printers(__name__)
|
||||
class JSStringTypeCache(object):
|
||||
def __init__(self, cache):
|
||||
dummy = gdb.Value(0).cast(cache.JSString_ptr_t)
|
||||
self.ATOM_BIT = dummy['ATOM_BIT']
|
||||
self.NON_ATOM_BIT = dummy['NON_ATOM_BIT']
|
||||
self.LINEAR_BIT = dummy['LINEAR_BIT']
|
||||
self.INLINE_CHARS_BIT = dummy['INLINE_CHARS_BIT']
|
||||
self.TYPE_FLAGS_MASK = dummy['TYPE_FLAGS_MASK']
|
||||
|
@ -356,8 +356,8 @@ BaselineCacheIRCompiler::emitGuardSpecificAtom()
|
||||
|
||||
// The pointers are not equal, so if the input string is also an atom it
|
||||
// must be a different string.
|
||||
masm.branchTest32(Assembler::NonZero, Address(str, JSString::offsetOfFlags()),
|
||||
Imm32(JSString::ATOM_BIT), failure->label());
|
||||
masm.branchTest32(Assembler::Zero, Address(str, JSString::offsetOfFlags()),
|
||||
Imm32(JSString::NON_ATOM_BIT), failure->label());
|
||||
|
||||
// Check the length.
|
||||
masm.loadPtr(atomAddr, scratch);
|
||||
|
@ -8049,10 +8049,13 @@ JitCompartment::generateStringConcatStub(JSContext* cx)
|
||||
masm.newGCString(output, temp3, &failure);
|
||||
|
||||
// Store rope length and flags. temp1 still holds the result of AND'ing the
|
||||
// lhs and rhs flags, so we just have to clear the other flags to get our
|
||||
// rope flags (Latin1 if both lhs and rhs are Latin1).
|
||||
static_assert(JSString::INIT_ROPE_FLAGS == 0, "Rope type flags must be 0");
|
||||
// lhs and rhs flags, so we just have to clear the other flags and set
|
||||
// NON_ATOM_BIT to get our rope flags (Latin1 if both lhs and rhs are
|
||||
// Latin1).
|
||||
static_assert(JSString::INIT_ROPE_FLAGS == JSString::NON_ATOM_BIT,
|
||||
"Rope type flags must be NON_ATOM_BIT only");
|
||||
masm.and32(Imm32(JSString::LATIN1_CHARS_BIT), temp1);
|
||||
masm.or32(Imm32(JSString::NON_ATOM_BIT), temp1);
|
||||
masm.store32(temp1, Address(output, JSString::offsetOfFlags()));
|
||||
masm.store32(temp2, Address(output, JSString::offsetOfLength()));
|
||||
|
||||
|
@ -767,8 +767,8 @@ IonCacheIRCompiler::emitGuardSpecificAtom()
|
||||
|
||||
// The pointers are not equal, so if the input string is also an atom it
|
||||
// must be a different string.
|
||||
masm.branchTest32(Assembler::NonZero, Address(str, JSString::offsetOfFlags()),
|
||||
Imm32(JSString::ATOM_BIT), failure->label());
|
||||
masm.branchTest32(Assembler::Zero, Address(str, JSString::offsetOfFlags()),
|
||||
Imm32(JSString::NON_ATOM_BIT), failure->label());
|
||||
|
||||
// Check the length.
|
||||
masm.branch32(Assembler::NotEqual, Address(str, JSString::offsetOfLength()),
|
||||
|
@ -408,7 +408,6 @@ MacroAssembler::branchIfRopeOrExternal(Register str, Register temp, Label* label
|
||||
and32(flags, temp);
|
||||
|
||||
branchTest32(Assembler::Zero, temp, Imm32(JSString::LINEAR_BIT), label);
|
||||
|
||||
branch32(Assembler::Equal, temp, Imm32(JSString::EXTERNAL_FLAGS), label);
|
||||
}
|
||||
|
||||
|
@ -1349,9 +1349,9 @@ MacroAssembler::compareStrings(JSOp op, Register left, Register right, Register
|
||||
|
||||
Label notAtom;
|
||||
// Optimize the equality operation to a pointer compare for two atoms.
|
||||
Imm32 atomBit(JSString::ATOM_BIT);
|
||||
branchTest32(Assembler::Zero, Address(left, JSString::offsetOfFlags()), atomBit, ¬Atom);
|
||||
branchTest32(Assembler::Zero, Address(right, JSString::offsetOfFlags()), atomBit, ¬Atom);
|
||||
Imm32 nonAtomBit(JSString::NON_ATOM_BIT);
|
||||
branchTest32(Assembler::NonZero, Address(left, JSString::offsetOfFlags()), nonAtomBit, ¬Atom);
|
||||
branchTest32(Assembler::NonZero, Address(right, JSString::offsetOfFlags()), nonAtomBit, ¬Atom);
|
||||
|
||||
cmpPtrSet(JSOpToCondition(MCompare::Compare_String, op), left, right, result);
|
||||
jump(&done);
|
||||
|
@ -616,10 +616,11 @@ struct Function {
|
||||
|
||||
struct String
|
||||
{
|
||||
static const uint32_t LINEAR_BIT = JS_BIT(0);
|
||||
static const uint32_t INLINE_CHARS_BIT = JS_BIT(2);
|
||||
static const uint32_t NON_ATOM_BIT = JS_BIT(0);
|
||||
static const uint32_t LINEAR_BIT = JS_BIT(1);
|
||||
static const uint32_t INLINE_CHARS_BIT = JS_BIT(3);
|
||||
static const uint32_t LATIN1_CHARS_BIT = JS_BIT(6);
|
||||
static const uint32_t EXTERNAL_FLAGS = JS_BIT(0) | JS_BIT(5);
|
||||
static const uint32_t EXTERNAL_FLAGS = LINEAR_BIT | NON_ATOM_BIT | JS_BIT(5);
|
||||
static const uint32_t TYPE_FLAGS_MASK = JS_BIT(6) - 1;
|
||||
uint32_t flags;
|
||||
uint32_t length;
|
||||
@ -630,6 +631,11 @@ struct String
|
||||
char16_t inlineStorageTwoByte[1];
|
||||
};
|
||||
const JSStringFinalizer* externalFinalizer;
|
||||
|
||||
static bool nurseryCellIsString(const js::gc::Cell* cell) {
|
||||
MOZ_ASSERT(IsInsideNursery(cell));
|
||||
return reinterpret_cast<const String*>(cell)->flags & NON_ATOM_BIT;
|
||||
}
|
||||
};
|
||||
|
||||
} /* namespace shadow */
|
||||
|
@ -205,7 +205,7 @@ MOZ_ALWAYS_INLINE void
|
||||
JSFlatString::init(const char16_t* chars, size_t length)
|
||||
{
|
||||
d.u1.length = length;
|
||||
d.u1.flags = LINEAR_BIT;
|
||||
d.u1.flags = INIT_FLAT_FLAGS;
|
||||
d.s.u2.nonInlineCharsTwoByte = chars;
|
||||
}
|
||||
|
||||
@ -213,7 +213,7 @@ MOZ_ALWAYS_INLINE void
|
||||
JSFlatString::init(const JS::Latin1Char* chars, size_t length)
|
||||
{
|
||||
d.u1.length = length;
|
||||
d.u1.flags = LINEAR_BIT | LATIN1_CHARS_BIT;
|
||||
d.u1.flags = INIT_FLAT_FLAGS | LATIN1_CHARS_BIT;
|
||||
d.s.u2.nonInlineCharsLatin1 = chars;
|
||||
}
|
||||
|
||||
|
@ -207,7 +207,7 @@ JSString::dumpRepresentationHeader(js::GenericPrinter& out, int indent, const ch
|
||||
if (flags & LINEAR_BIT) out.put(" LINEAR");
|
||||
if (flags & HAS_BASE_BIT) out.put(" HAS_BASE");
|
||||
if (flags & INLINE_CHARS_BIT) out.put(" INLINE_CHARS");
|
||||
if (flags & ATOM_BIT) out.put(" ATOM");
|
||||
if (flags & NON_ATOM_BIT) out.put(" NON_ATOM");
|
||||
if (isPermanentAtom()) out.put(" PERMANENT");
|
||||
if (flags & LATIN1_CHARS_BIT) out.put(" LATIN1");
|
||||
if (flags & INDEX_VALUE_BIT) out.printf(" INDEX_VALUE(%u)", getIndexValue());
|
||||
@ -1103,7 +1103,7 @@ JSExternalString::ensureFlat(JSContext* cx)
|
||||
|
||||
// Transform the string into a non-external, flat string.
|
||||
setNonInlineChars<char16_t>(s);
|
||||
d.u1.flags = LINEAR_BIT;
|
||||
d.u1.flags = INIT_FLAT_FLAGS;
|
||||
|
||||
return &this->asFlat();
|
||||
}
|
||||
|
@ -221,28 +221,28 @@ class JSString : public js::gc::Cell
|
||||
* String Instance Subtype
|
||||
* type encoding predicate
|
||||
* ------------------------------------
|
||||
* Rope 000000 xxxxx0
|
||||
* Linear - xxxxx1
|
||||
* HasBase - xxxx1x
|
||||
* Dependent 000011 000011
|
||||
* External 100001 100001
|
||||
* Rope 000001 xxxx0x
|
||||
* Linear - xxxx1x
|
||||
* HasBase - xxx1xx
|
||||
* Dependent 000111 000111
|
||||
* External 100011 100011
|
||||
* Flat - Linear && !Dependent && !External
|
||||
* Undepended 010011 010011
|
||||
* Extensible 010001 010001
|
||||
* Inline 000101 xxx1xx
|
||||
* FatInline 010101 x1x1xx
|
||||
* Atom 001001 xx1xxx
|
||||
* PermanentAtom 101001 1x1xxx
|
||||
* InlineAtom - xx11xx
|
||||
* FatInlineAtom - x111xx
|
||||
* Undepended 010111 010111
|
||||
* Extensible 010011 010011
|
||||
* Inline 001011 xx1xxx
|
||||
* FatInline 011011 x11xxx
|
||||
* NormalAtom 000010 xxxxx0
|
||||
* PermanentAtom 100010 1xxxx0
|
||||
* InlineAtom - xx1xx0
|
||||
* FatInlineAtom - x11xx0
|
||||
*
|
||||
* Note that the first 4 flag bits (from right to left in the previous table)
|
||||
* have the following meaning and can be used for some hot queries:
|
||||
*
|
||||
* Bit 0: IsLinear
|
||||
* Bit 1: HasBase (Dependent, Undepended)
|
||||
* Bit 2: IsInline (Inline, FatInline)
|
||||
* Bit 3: IsAtom (Atom, PermanentAtom)
|
||||
* Bit 0: !IsAtom (Atom, PermanentAtom)
|
||||
* Bit 1: IsLinear
|
||||
* Bit 2: HasBase (Dependent, Undepended)
|
||||
* Bit 3: IsInline (Inline, FatInline)
|
||||
*
|
||||
* "HasBase" here refers to the two string types that have a 'base' field:
|
||||
* JSDependentString and JSUndependedString.
|
||||
@ -250,27 +250,37 @@ class JSString : public js::gc::Cell
|
||||
* to be null-terminated. In such cases, the string must keep marking its base since
|
||||
* there may be any number of *other* JSDependentStrings transitively depending on it.
|
||||
*
|
||||
* The atom bit (NON_ATOM_BIT) is inverted so that objects and strings can
|
||||
* be differentiated in the nursery: atoms are never in the nursery, so
|
||||
* this bit is always 1 for a nursery string. For an object on a
|
||||
* little-endian architecture, this is the low-order bit of the ObjectGroup
|
||||
* pointer in a JSObject, which will always be zero. A 64-bit big-endian
|
||||
* architecture will need to do something else (the ObjectGroup* is in the
|
||||
* same place as a string's struct { uint32_t flags; uint32_t length; }).
|
||||
*
|
||||
* If the INDEX_VALUE_BIT is set the upper 16 bits of the flag word hold the integer
|
||||
* index.
|
||||
*/
|
||||
|
||||
static const uint32_t LINEAR_BIT = JS_BIT(0);
|
||||
static const uint32_t HAS_BASE_BIT = JS_BIT(1);
|
||||
static const uint32_t INLINE_CHARS_BIT = JS_BIT(2);
|
||||
static const uint32_t ATOM_BIT = JS_BIT(3);
|
||||
static const uint32_t NON_ATOM_BIT = JS_BIT(0);
|
||||
static const uint32_t LINEAR_BIT = JS_BIT(1);
|
||||
static const uint32_t HAS_BASE_BIT = JS_BIT(2);
|
||||
static const uint32_t INLINE_CHARS_BIT = JS_BIT(3);
|
||||
|
||||
static const uint32_t DEPENDENT_FLAGS = LINEAR_BIT | HAS_BASE_BIT;
|
||||
static const uint32_t UNDEPENDED_FLAGS = LINEAR_BIT | HAS_BASE_BIT | JS_BIT(4);
|
||||
static const uint32_t EXTENSIBLE_FLAGS = LINEAR_BIT | JS_BIT(4);
|
||||
static const uint32_t EXTERNAL_FLAGS = LINEAR_BIT | JS_BIT(5);
|
||||
static const uint32_t DEPENDENT_FLAGS = NON_ATOM_BIT | LINEAR_BIT | HAS_BASE_BIT;
|
||||
static const uint32_t UNDEPENDED_FLAGS = NON_ATOM_BIT | LINEAR_BIT | HAS_BASE_BIT | JS_BIT(4);
|
||||
static const uint32_t EXTENSIBLE_FLAGS = NON_ATOM_BIT | LINEAR_BIT | JS_BIT(4);
|
||||
static const uint32_t EXTERNAL_FLAGS = NON_ATOM_BIT | LINEAR_BIT | JS_BIT(5);
|
||||
|
||||
static const uint32_t FAT_INLINE_MASK = INLINE_CHARS_BIT | JS_BIT(4);
|
||||
static const uint32_t PERMANENT_ATOM_MASK = ATOM_BIT | JS_BIT(5);
|
||||
static const uint32_t PERMANENT_ATOM_MASK = NON_ATOM_BIT | JS_BIT(5);
|
||||
static const uint32_t PERMANENT_ATOM_FLAGS = JS_BIT(5);
|
||||
|
||||
/* Initial flags for thin inline and fat inline strings. */
|
||||
static const uint32_t INIT_THIN_INLINE_FLAGS = LINEAR_BIT | INLINE_CHARS_BIT;
|
||||
static const uint32_t INIT_FAT_INLINE_FLAGS = LINEAR_BIT | FAT_INLINE_MASK;
|
||||
static const uint32_t INIT_ROPE_FLAGS = 0;
|
||||
static const uint32_t INIT_THIN_INLINE_FLAGS = NON_ATOM_BIT | LINEAR_BIT | INLINE_CHARS_BIT;
|
||||
static const uint32_t INIT_FAT_INLINE_FLAGS = NON_ATOM_BIT | LINEAR_BIT | FAT_INLINE_MASK;
|
||||
static const uint32_t INIT_ROPE_FLAGS = NON_ATOM_BIT;
|
||||
static const uint32_t INIT_FLAT_FLAGS = NON_ATOM_BIT | LINEAR_BIT;
|
||||
|
||||
static const uint32_t TYPE_FLAGS_MASK = JS_BIT(6) - 1;
|
||||
|
||||
@ -317,6 +327,8 @@ class JSString : public js::gc::Cell
|
||||
"shadow::String inlineStorage offset must match JSString");
|
||||
static_assert(offsetof(JSString, d.inlineStorageTwoByte) == offsetof(String, inlineStorageTwoByte),
|
||||
"shadow::String inlineStorage offset must match JSString");
|
||||
static_assert(NON_ATOM_BIT == String::NON_ATOM_BIT,
|
||||
"shadow::String::NON_ATOM_BIT must match JSString::NON_ATOM_BIT");
|
||||
static_assert(LINEAR_BIT == String::LINEAR_BIT,
|
||||
"shadow::String::LINEAR_BIT must match JSString::LINEAR_BIT");
|
||||
static_assert(INLINE_CHARS_BIT == String::INLINE_CHARS_BIT,
|
||||
@ -472,12 +484,12 @@ class JSString : public js::gc::Cell
|
||||
|
||||
MOZ_ALWAYS_INLINE
|
||||
bool isAtom() const {
|
||||
return d.u1.flags & ATOM_BIT;
|
||||
return !(d.u1.flags & NON_ATOM_BIT);
|
||||
}
|
||||
|
||||
MOZ_ALWAYS_INLINE
|
||||
bool isPermanentAtom() const {
|
||||
return (d.u1.flags & PERMANENT_ATOM_MASK) == PERMANENT_ATOM_MASK;
|
||||
return (d.u1.flags & PERMANENT_ATOM_MASK) == PERMANENT_ATOM_FLAGS;
|
||||
}
|
||||
|
||||
MOZ_ALWAYS_INLINE
|
||||
@ -486,6 +498,14 @@ class JSString : public js::gc::Cell
|
||||
return *(JSAtom*)this;
|
||||
}
|
||||
|
||||
// Used for distinguishing strings from objects in the nursery. 'cell' must
|
||||
// be in the nursery.
|
||||
MOZ_ALWAYS_INLINE
|
||||
static bool nurseryCellIsString(js::gc::Cell* cell) {
|
||||
MOZ_ASSERT(!cell->isTenured());
|
||||
return !static_cast<JSString*>(cell)->isAtom();
|
||||
}
|
||||
|
||||
// Fills |array| with various strings that represent the different string
|
||||
// kinds and character encodings.
|
||||
static bool fillWithRepresentatives(JSContext* cx, js::HandleArrayObject array);
|
||||
@ -1091,7 +1111,8 @@ class JSAtom : public JSFlatString
|
||||
// Transform this atom into a permanent atom. This is only done during
|
||||
// initialization of the runtime.
|
||||
MOZ_ALWAYS_INLINE void morphIntoPermanentAtom() {
|
||||
d.u1.flags |= PERMANENT_ATOM_MASK;
|
||||
MOZ_ASSERT(static_cast<JSString*>(this)->isAtom());
|
||||
d.u1.flags |= PERMANENT_ATOM_FLAGS;
|
||||
}
|
||||
|
||||
inline js::HashNumber hash() const;
|
||||
@ -1170,7 +1191,8 @@ JSAtom::initHash(js::HashNumber hash)
|
||||
MOZ_ALWAYS_INLINE JSAtom*
|
||||
JSFlatString::morphAtomizedStringIntoAtom(js::HashNumber hash)
|
||||
{
|
||||
d.u1.flags |= ATOM_BIT;
|
||||
MOZ_ASSERT(!isAtom());
|
||||
d.u1.flags &= ~NON_ATOM_BIT;
|
||||
JSAtom* atom = &asAtom();
|
||||
atom->initHash(hash);
|
||||
return atom;
|
||||
@ -1179,7 +1201,9 @@ JSFlatString::morphAtomizedStringIntoAtom(js::HashNumber hash)
|
||||
MOZ_ALWAYS_INLINE JSAtom*
|
||||
JSFlatString::morphAtomizedStringIntoPermanentAtom(js::HashNumber hash)
|
||||
{
|
||||
d.u1.flags |= PERMANENT_ATOM_MASK;
|
||||
MOZ_ASSERT(!isAtom());
|
||||
d.u1.flags |= PERMANENT_ATOM_FLAGS;
|
||||
d.u1.flags &= ~NON_ATOM_BIT;
|
||||
JSAtom* atom = &asAtom();
|
||||
atom->initHash(hash);
|
||||
return atom;
|
||||
|
Loading…
Reference in New Issue
Block a user