/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- * vim: set ts=8 sts=2 et sw=2 tw=80: * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "frontend/ParserAtom.h" #include // std::uninitialized_fill_n #include #include "jsnum.h" #include "frontend/CompilationInfo.h" #include "frontend/NameCollections.h" #include "frontend/StencilXdr.h" // CanCopyDataToDisk #include "vm/JSContext.h" #include "vm/Printer.h" #include "vm/Runtime.h" #include "vm/StringType.h" using namespace js; using namespace js::frontend; namespace js { // Iterates over a sequence of ParserAtoms and yield their sequence of // characters in order. This simulates concatenation of atoms. The underlying // ParserAtoms may be a mix of Latin1 and char16_t atoms. template <> class InflatedChar16Sequence { private: const ParserAtom** cur_ = nullptr; const ParserAtom** lim_ = nullptr; size_t index_ = 0; void settle() { // Check if we are out-of-bounds for current ParserAtom. auto outOfBounds = [this]() { return index_ >= (*cur_)->length(); }; while (hasMore() && outOfBounds()) { // Advance to start of next ParserAtom. cur_++; index_ = 0; } } public: explicit InflatedChar16Sequence( const mozilla::Range& atoms) : cur_(atoms.begin().get()), lim_(atoms.end().get()) { settle(); } bool hasMore() { return cur_ < lim_; } char16_t next() { MOZ_ASSERT(hasMore()); char16_t ch = (*cur_)->hasLatin1Chars() ? (*cur_)->latin1Chars()[index_] : (*cur_)->twoByteChars()[index_]; index_++; settle(); return ch; } HashNumber computeHash() const { auto copy = *this; HashNumber hash = 0; while (copy.hasMore()) { hash = mozilla::AddToHash(hash, copy.next()); } return hash; } }; } // namespace js namespace js { template <> class InflatedChar16Sequence { private: LittleEndianChars chars_; size_t idx_; size_t len_; public: InflatedChar16Sequence(LittleEndianChars chars, size_t length) : chars_(chars), idx_(0), len_(length) {} bool hasMore() { return idx_ < len_; } char16_t next() { MOZ_ASSERT(hasMore()); return chars_[idx_++]; } HashNumber computeHash() const { auto copy = *this; HashNumber hash = 0; while (copy.hasMore()) { hash = mozilla::AddToHash(hash, copy.next()); } return hash; } }; } // namespace js namespace js { namespace frontend { JSAtom* GetWellKnownAtom(JSContext* cx, WellKnownAtomId atomId) { #define ASSERT_OFFSET_(idpart, id, text) \ static_assert(offsetof(JSAtomState, id) == \ int32_t(WellKnownAtomId::id) * \ sizeof(js::ImmutablePropertyNamePtr)); FOR_EACH_COMMON_PROPERTYNAME(ASSERT_OFFSET_); #undef ASSERT_OFFSET_ #define ASSERT_OFFSET_(name, clasp) \ static_assert(offsetof(JSAtomState, name) == \ int32_t(WellKnownAtomId::name) * \ sizeof(js::ImmutablePropertyNamePtr)); JS_FOR_EACH_PROTOTYPE(ASSERT_OFFSET_); #undef ASSERT_OFFSET_ static_assert(int32_t(WellKnownAtomId::abort) == 0, "Unexpected order of WellKnownAtom"); return (&cx->names().abort)[int32_t(atomId)]; } #ifdef DEBUG void TaggedParserAtomIndex::validateRaw() { if (isParserAtomIndex()) { MOZ_ASSERT(toParserAtomIndex().index < IndexLimit); } else if (isWellKnownAtomId()) { MOZ_ASSERT(uint32_t(toWellKnownAtomId()) < uint32_t(WellKnownAtomId::Limit)); } else if (isStaticParserString1()) { MOZ_ASSERT(size_t(toStaticParserString1()) < WellKnownParserAtoms_ROM::ASCII_STATIC_LIMIT); } else if (isStaticParserString2()) { MOZ_ASSERT(size_t(toStaticParserString2()) < WellKnownParserAtoms_ROM::NUM_LENGTH2_ENTRIES); } else { MOZ_ASSERT(isNull()); } } #endif template /* static */ ParserAtomEntry* ParserAtomEntry::allocate( JSContext* cx, LifoAlloc& alloc, InflatedChar16Sequence seq, uint32_t length, HashNumber hash) { constexpr size_t HeaderSize = sizeof(ParserAtomEntry); void* raw = alloc.alloc(HeaderSize + (sizeof(CharT) * length)); if (!raw) { js::ReportOutOfMemory(cx); return nullptr; } constexpr bool hasTwoByteChars = (sizeof(CharT) == 2); static_assert(sizeof(CharT) == 1 || sizeof(CharT) == 2, "CharT should be 1 or 2 byte type"); ParserAtomEntry* entry = new (raw) ParserAtomEntry(length, hash, hasTwoByteChars); CharT* entryBuf = entry->chars(); drainChar16Seq(entryBuf, seq, length); return entry; } /* static */ ParserAtomEntry* ParserAtomEntry::allocateRaw( JSContext* cx, LifoAlloc& alloc, const uint8_t* srcRaw, size_t totalLength) { void* raw = alloc.alloc(totalLength); if (!raw) { js::ReportOutOfMemory(cx); return nullptr; } memcpy(raw, srcRaw, totalLength); return static_cast(raw); } bool ParserAtomEntry::equalsJSAtom(JSAtom* other) const { // Compare hashes and lengths first. if (hash_ != other->hash() || length_ != other->length()) { return false; } JS::AutoCheckCannotGC nogc; if (hasTwoByteChars()) { // Compare heap-allocated 16-bit chars to atom. return other->hasLatin1Chars() ? EqualChars(twoByteChars(), other->latin1Chars(nogc), length_) : EqualChars(twoByteChars(), other->twoByteChars(nogc), length_); } MOZ_ASSERT(hasLatin1Chars()); return other->hasLatin1Chars() ? EqualChars(latin1Chars(), other->latin1Chars(nogc), length_) : EqualChars(latin1Chars(), other->twoByteChars(nogc), length_); } template UniqueChars ToPrintableStringImpl(JSContext* cx, mozilla::Range str) { Sprinter sprinter(cx); if (!sprinter.init()) { return nullptr; } if (!QuoteString(&sprinter, str)) { return nullptr; } return sprinter.release(); } UniqueChars ParserAtomToPrintableString(JSContext* cx, const ParserAtom* atom) { size_t length = atom->length(); return atom->hasLatin1Chars() ? ToPrintableStringImpl( cx, mozilla::Range(atom->latin1Chars(), length)) : ToPrintableStringImpl( cx, mozilla::Range(atom->twoByteChars(), length)); } bool ParserAtomEntry::isIndex(uint32_t* indexp) const { size_t len = length(); if (len == 0 || len > UINT32_CHAR_BUFFER_LENGTH) { return false; } if (hasLatin1Chars()) { return mozilla::IsAsciiDigit(*latin1Chars()) && js::CheckStringIsIndex(latin1Chars(), len, indexp); } return mozilla::IsAsciiDigit(*twoByteChars()) && js::CheckStringIsIndex(twoByteChars(), len, indexp); } JSAtom* ParserAtomEntry::toJSAtom(JSContext* cx, CompilationAtomCache& atomCache) const { if (isParserAtomIndex()) { JSAtom* atom = atomCache.getAtomAt(toParserAtomIndex()); if (atom) { return atom; } return instantiate(cx, atomCache); } if (isWellKnownAtomId()) { return GetWellKnownAtom(cx, toWellKnownAtomId()); } if (isStaticParserString1()) { char16_t ch = static_cast(toStaticParserString1()); return cx->staticStrings().getUnit(ch); } MOZ_ASSERT(isStaticParserString2()); size_t s = static_cast(toStaticParserString2()); return cx->staticStrings().getLength2FromIndex(s); } JSAtom* ParserAtomEntry::toExistingJSAtom( JSContext* cx, CompilationAtomCache& atomCache) const { if (isParserAtomIndex()) { JSAtom* atom = atomCache.getExistingAtomAt(toParserAtomIndex()); MOZ_ASSERT(atom); return atom; } if (isWellKnownAtomId()) { return GetWellKnownAtom(cx, toWellKnownAtomId()); } if (isStaticParserString1()) { char16_t ch = static_cast(toStaticParserString1()); return cx->staticStrings().getUnit(ch); } MOZ_ASSERT(isStaticParserString2()); size_t s = static_cast(toStaticParserString2()); return cx->staticStrings().getLength2FromIndex(s); } JSAtom* ParserAtomEntry::instantiate(JSContext* cx, CompilationAtomCache& atomCache) const { JSAtom* atom; if (hasLatin1Chars()) { atom = AtomizeChars(cx, hash(), latin1Chars(), length()); } else { atom = AtomizeChars(cx, hash(), twoByteChars(), length()); } if (!atom) { js::ReportOutOfMemory(cx); return nullptr; } if (!atomCache.setAtomAt(cx, toParserAtomIndex(), atom)) { return nullptr; } return atom; } bool ParserAtomEntry::toNumber(JSContext* cx, double* result) const { return hasLatin1Chars() ? CharsToNumber(cx, latin1Chars(), length(), result) : CharsToNumber(cx, twoByteChars(), length(), result); } #if defined(DEBUG) || defined(JS_JITSPEW) void ParserAtomEntry::dump() const { js::Fprinter out(stderr); out.put("\""); dumpCharsNoQuote(out); out.put("\"\n"); } void ParserAtomEntry::dumpCharsNoQuote(js::GenericPrinter& out) const { if (hasLatin1Chars()) { JSString::dumpCharsNoQuote(latin1Chars(), length(), out); } else { JSString::dumpCharsNoQuote(twoByteChars(), length(), out); } } #endif ParserAtomsTable::ParserAtomsTable(JSRuntime* rt, LifoAlloc& alloc) : wellKnownTable_(*rt->commonParserNames), alloc_(alloc) {} const ParserAtom* ParserAtomsTable::addEntry(JSContext* cx, EntrySet::AddPtr& addPtr, ParserAtomEntry* entry) { MOZ_ASSERT(!addPtr); ParserAtomIndex index = ParserAtomIndex(entries_.length()); if (size_t(index) >= TaggedParserAtomIndex::IndexLimit) { ReportAllocationOverflow(cx); return nullptr; } if (!entries_.append(entry)) { js::ReportOutOfMemory(cx); return nullptr; } entry->setParserAtomIndex(index); if (!entrySet_.add(addPtr, entry)) { js::ReportOutOfMemory(cx); return nullptr; } return entry->asAtom(); } template const ParserAtom* ParserAtomsTable::internChar16Seq( JSContext* cx, EntrySet::AddPtr& addPtr, HashNumber hash, InflatedChar16Sequence seq, uint32_t length) { MOZ_ASSERT(!addPtr); ParserAtomEntry* entry = ParserAtomEntry::allocate(cx, alloc_, seq, length, hash); if (!entry) { return nullptr; } return addEntry(cx, addPtr, entry); } static const uint16_t MAX_LATIN1_CHAR = 0xff; const ParserAtom* ParserAtomsTable::internAscii(JSContext* cx, const char* asciiPtr, uint32_t length) { // ASCII strings are strict subsets of Latin1 strings. const Latin1Char* latin1Ptr = reinterpret_cast(asciiPtr); return internLatin1(cx, latin1Ptr, length); } const ParserAtom* ParserAtomsTable::internLatin1(JSContext* cx, const Latin1Char* latin1Ptr, uint32_t length) { // Check for tiny strings which are abundant in minified code. if (const ParserAtom* tiny = wellKnownTable_.lookupTiny(latin1Ptr, length)) { return tiny; } // Check for well-known atom. InflatedChar16Sequence seq(latin1Ptr, length); SpecificParserAtomLookup lookup(seq); if (const ParserAtom* wk = wellKnownTable_.lookupChar16Seq(lookup)) { return wk; } // Check for existing atom. auto addPtr = entrySet_.lookupForAdd(lookup); if (addPtr) { return (*addPtr)->asAtom(); } return internChar16Seq(cx, addPtr, lookup.hash(), seq, length); } ParserAtomSpanBuilder::ParserAtomSpanBuilder(JSRuntime* rt, ParserAtomSpan& entries) : wellKnownTable_(*rt->commonParserNames), entries_(entries) {} bool ParserAtomSpanBuilder::allocate(JSContext* cx, LifoAlloc& alloc, size_t count) { if (count >= TaggedParserAtomIndex::IndexLimit) { ReportAllocationOverflow(cx); return false; } auto* p = alloc.newArrayUninitialized(count); if (!p) { js::ReportOutOfMemory(cx); return false; } std::uninitialized_fill_n(p, count, nullptr); entries_ = mozilla::Span(p, count); return true; } const ParserAtom* ParserAtomsTable::internUtf8(JSContext* cx, const mozilla::Utf8Unit* utf8Ptr, uint32_t nbyte) { // Check for tiny strings which are abundant in minified code. // NOTE: The tiny atoms are all ASCII-only so we can directly look at the // UTF-8 data without worrying about surrogates. if (const ParserAtom* tiny = wellKnownTable_.lookupTiny( reinterpret_cast(utf8Ptr), nbyte)) { return tiny; } // If source text is ASCII, then the length of the target char buffer // is the same as the length of the UTF8 input. Convert it to a Latin1 // encoded string on the heap. JS::UTF8Chars utf8(utf8Ptr, nbyte); JS::SmallestEncoding minEncoding = FindSmallestEncoding(utf8); if (minEncoding == JS::SmallestEncoding::ASCII) { // As ascii strings are a subset of Latin1 strings, and each encoding // unit is the same size, we can reliably cast this `Utf8Unit*` // to a `Latin1Char*`. const Latin1Char* latin1Ptr = reinterpret_cast(utf8Ptr); return internLatin1(cx, latin1Ptr, nbyte); } // Check for existing. // NOTE: Well-known are all ASCII so have been handled above. InflatedChar16Sequence seq(utf8Ptr, nbyte); SpecificParserAtomLookup lookup(seq); MOZ_ASSERT(wellKnownTable_.lookupChar16Seq(lookup) == nullptr); EntrySet::AddPtr addPtr = entrySet_.lookupForAdd(lookup); if (addPtr) { return (*addPtr)->asAtom(); } // Compute length in code-points. uint32_t length = 0; InflatedChar16Sequence seqCopy = seq; while (seqCopy.hasMore()) { mozilla::Unused << seqCopy.next(); length += 1; } // Otherwise, add new entry. bool wide = (minEncoding == JS::SmallestEncoding::UTF16); return wide ? internChar16Seq(cx, addPtr, lookup.hash(), seq, length) : internChar16Seq(cx, addPtr, lookup.hash(), seq, length); } const ParserAtom* ParserAtomsTable::internChar16(JSContext* cx, const char16_t* char16Ptr, uint32_t length) { // Check for tiny strings which are abundant in minified code. if (const ParserAtom* tiny = wellKnownTable_.lookupTiny(char16Ptr, length)) { return tiny; } // Check against well-known. InflatedChar16Sequence seq(char16Ptr, length); SpecificParserAtomLookup lookup(seq); if (const ParserAtom* wk = wellKnownTable_.lookupChar16Seq(lookup)) { return wk; } // Check for existing atom. EntrySet::AddPtr addPtr = entrySet_.lookupForAdd(lookup); if (addPtr) { return (*addPtr)->asAtom(); } // Compute the target encoding. // NOTE: Length in code-points will be same, even if we deflate to Latin1. bool wide = false; InflatedChar16Sequence seqCopy = seq; while (seqCopy.hasMore()) { char16_t ch = seqCopy.next(); if (ch > MAX_LATIN1_CHAR) { wide = true; break; } } // Otherwise, add new entry. return wide ? internChar16Seq(cx, addPtr, lookup.hash(), seq, length) : internChar16Seq(cx, addPtr, lookup.hash(), seq, length); } const ParserAtom* ParserAtomsTable::internJSAtom(JSContext* cx, CompilationStencil& stencil, JSAtom* atom) { const ParserAtom* parserAtom; { JS::AutoCheckCannotGC nogc; parserAtom = atom->hasLatin1Chars() ? internLatin1(cx, atom->latin1Chars(nogc), atom->length()) : internChar16(cx, atom->twoByteChars(nogc), atom->length()); if (!parserAtom) { return nullptr; } } if (parserAtom->isParserAtomIndex()) { ParserAtomIndex index = parserAtom->toParserAtomIndex(); auto& atomCache = stencil.input.atomCache; if (!atomCache.hasAtomAt(index)) { if (!atomCache.setAtomAt(cx, index, atom)) { return nullptr; } } } // We should (infallibly) map back to the same JSAtom. MOZ_ASSERT(parserAtom->toJSAtom(cx, stencil.input.atomCache) == atom); return parserAtom; } const ParserAtom* ParserAtomsTable::concatAtoms( JSContext* cx, mozilla::Range atoms) { MOZ_ASSERT(atoms.length() >= 2, "concatAtoms should only be used for multiple inputs"); // Compute final length and encoding. bool catLatin1 = true; uint32_t catLen = 0; for (const ParserAtom* atom : atoms) { if (atom->hasTwoByteChars()) { catLatin1 = false; } // Overflow check here, length if (atom->length() >= (ParserAtomEntry::MAX_LENGTH - catLen)) { js::ReportOutOfMemory(cx); return nullptr; } catLen += atom->length(); } // Short Latin1 strings must check for both Tiny and WellKnown atoms so simple // concatenate onto stack and use `internLatin1`. if (catLatin1 && (catLen <= WellKnownParserAtoms::MaxWellKnownLength)) { Latin1Char buf[WellKnownParserAtoms::MaxWellKnownLength]; size_t offset = 0; for (const ParserAtom* atom : atoms) { mozilla::PodCopy(buf + offset, atom->latin1Chars(), atom->length()); offset += atom->length(); } return internLatin1(cx, buf, catLen); } // NOTE: We have ruled out Tiny and WellKnown atoms and can ignore below. InflatedChar16Sequence seq(atoms); SpecificParserAtomLookup lookup(seq); // Check for existing atom. auto addPtr = entrySet_.lookupForAdd(lookup); if (addPtr) { return (*addPtr)->asAtom(); } // Otherwise, add new entry. return catLatin1 ? internChar16Seq(cx, addPtr, lookup.hash(), seq, catLen) : internChar16Seq(cx, addPtr, lookup.hash(), seq, catLen); } const ParserAtom* WellKnownParserAtoms::getWellKnown( WellKnownAtomId atomId) const { #define ASSERT_OFFSET_(idpart, id, text) \ static_assert(offsetof(WellKnownParserAtoms, id) == \ int32_t(WellKnownAtomId::id) * sizeof(ParserAtom*)); FOR_EACH_COMMON_PROPERTYNAME(ASSERT_OFFSET_); #undef ASSERT_OFFSET_ #define ASSERT_OFFSET_(name, clasp) \ static_assert(offsetof(WellKnownParserAtoms, name) == \ int32_t(WellKnownAtomId::name) * sizeof(ParserAtom*)); JS_FOR_EACH_PROTOTYPE(ASSERT_OFFSET_); #undef ASSERT_OFFSET_ static_assert(int32_t(WellKnownAtomId::abort) == 0, "Unexpected order of WellKnownAtom"); return (&abort)[int32_t(atomId)]; } /* static */ const ParserAtom* WellKnownParserAtoms::getStatic1(StaticParserString1 s) { return WellKnownParserAtoms::rom_.length1Table[size_t(s)].asAtom(); } /* static */ const ParserAtom* WellKnownParserAtoms::getStatic2(StaticParserString2 s) { return WellKnownParserAtoms::rom_.length2Table[size_t(s)].asAtom(); } const ParserAtom* ParserAtomSpanBuilder::getWellKnown( WellKnownAtomId atomId) const { return wellKnownTable_.getWellKnown(atomId); } const ParserAtom* ParserAtomSpanBuilder::getStatic1( StaticParserString1 s) const { return WellKnownParserAtoms::getStatic1(s); } const ParserAtom* ParserAtomSpanBuilder::getStatic2( StaticParserString2 s) const { return WellKnownParserAtoms::getStatic2(s); } const ParserAtom* ParserAtomSpanBuilder::getParserAtom( ParserAtomIndex index) const { return entries_[index]->asAtom(); } template const ParserAtom* GetParserAtom(T self, TaggedParserAtomIndex index) { if (index.isParserAtomIndex()) { return self->getParserAtom(index.toParserAtomIndex()); } if (index.isWellKnownAtomId()) { return self->getWellKnown(index.toWellKnownAtomId()); } if (index.isStaticParserString1()) { return self->getStatic1(index.toStaticParserString1()); } if (index.isStaticParserString2()) { return self->getStatic2(index.toStaticParserString2()); } MOZ_ASSERT(index.isNull()); return nullptr; } const ParserAtom* ParserAtomSpanBuilder::getParserAtom( TaggedParserAtomIndex index) const { return GetParserAtom(this, index); } const ParserAtom* ParserAtomsTable::getWellKnown(WellKnownAtomId atomId) const { return wellKnownTable_.getWellKnown(atomId); } const ParserAtom* ParserAtomsTable::getStatic1(StaticParserString1 s) const { return WellKnownParserAtoms::getStatic1(s); } const ParserAtom* ParserAtomsTable::getStatic2(StaticParserString2 s) const { return WellKnownParserAtoms::getStatic2(s); } const ParserAtom* ParserAtomsTable::getParserAtom(ParserAtomIndex index) const { return entries_[index]->asAtom(); } const ParserAtom* ParserAtomsTable::getParserAtom( TaggedParserAtomIndex index) const { return GetParserAtom(this, index); } bool InstantiateMarkedAtoms(JSContext* cx, const ParserAtomSpan& entries, CompilationAtomCache& atomCache) { for (const auto& entry : entries) { if (!entry) { continue; } if (entry->isUsedByStencil() && entry->isParserAtomIndex() && !atomCache.hasAtomAt(entry->toParserAtomIndex())) { if (!entry->instantiate(cx, atomCache)) { return false; } } } return true; } template const ParserAtom* WellKnownParserAtoms::lookupChar16Seq( const SpecificParserAtomLookup& lookup) const { EntrySet::Ptr get = wellKnownSet_.readonlyThreadsafeLookup(lookup); if (get) { return (*get)->asAtom(); } return nullptr; } bool WellKnownParserAtoms::initSingle(JSContext* cx, const ParserName** name, const ParserAtomEntry& romEntry) { MOZ_ASSERT(name != nullptr); unsigned int len = romEntry.length(); const Latin1Char* str = romEntry.latin1Chars(); // Well-known atoms are all currently ASCII with length <= MaxWellKnownLength. MOZ_ASSERT(len <= MaxWellKnownLength); MOZ_ASSERT(romEntry.isAscii()); // Strings matched by lookupTiny are stored in static table and aliases should // only be added using initTinyStringAlias. MOZ_ASSERT(lookupTiny(str, len) == nullptr, "Well-known atom matches a tiny StaticString. Did you add it to " "the wrong CommonPropertyNames.h list?"); InflatedChar16Sequence seq(str, len); SpecificParserAtomLookup lookup(seq, romEntry.hash()); // Save name for returning after moving entry into set. if (!wellKnownSet_.putNew(lookup, &romEntry)) { js::ReportOutOfMemory(cx); return false; } *name = romEntry.asName(); return true; } bool WellKnownParserAtoms::initTinyStringAlias(JSContext* cx, const ParserName** name, const char* str) { MOZ_ASSERT(name != nullptr); unsigned int len = strlen(str); // Well-known atoms are all currently ASCII with length <= MaxWellKnownLength. MOZ_ASSERT(len <= MaxWellKnownLength); MOZ_ASSERT(FindSmallestEncoding(JS::UTF8Chars(str, len)) == JS::SmallestEncoding::ASCII); // NOTE: If this assert fails, you may need to change which list is it belongs // to in CommonPropertyNames.h. const ParserAtom* tiny = lookupTiny(str, len); MOZ_ASSERT(tiny, "Tiny common name was not found"); // Set alias to existing atom. *name = tiny->asName(); return true; } bool WellKnownParserAtoms::init(JSContext* cx) { // Tiny strings with a common name need a named alias to an entry in the // WellKnownParserAtoms_ROM. #define COMMON_NAME_INIT_(_, name, text) \ if (!initTinyStringAlias(cx, &(name), text)) { \ return false; \ } FOR_EACH_TINY_PROPERTYNAME(COMMON_NAME_INIT_) #undef COMMON_NAME_INIT_ // Initialize the named fields to point to entries in the ROM. This also adds // the atom to the lookup HashSet. The HashSet is used for dynamic lookups // later and does not change once this init method is complete. #define COMMON_NAME_INIT_(_, name, _2) \ if (!initSingle(cx, &(name), rom_.name)) { \ return false; \ } FOR_EACH_NONTINY_COMMON_PROPERTYNAME(COMMON_NAME_INIT_) #undef COMMON_NAME_INIT_ #define COMMON_NAME_INIT_(name, _) \ if (!initSingle(cx, &(name), rom_.name)) { \ return false; \ } JS_FOR_EACH_PROTOTYPE(COMMON_NAME_INIT_) #undef COMMON_NAME_INIT_ return true; } } /* namespace frontend */ } /* namespace js */ // XDR code. namespace js { template XDRResult XDRParserAtomEntry(XDRState* xdr, ParserAtomEntry** entryp) { static_assert(CanCopyDataToDisk::value, "ParserAtomEntry cannot be bulk-copied to disk."); MOZ_TRY(xdr->align32()); const ParserAtomEntry* header; if (mode == XDR_ENCODE) { header = *entryp; } else { MOZ_TRY(xdr->peekData(&header)); } const uint32_t CharSize = header->hasLatin1Chars() ? sizeof(JS::Latin1Char) : sizeof(char16_t); uint32_t totalLength = sizeof(ParserAtomEntry) + (CharSize * header->length()); MOZ_TRY(xdr->borrowedData(entryp, totalLength)); return Ok(); } template XDRResult XDRParserAtomEntry(XDRState* xdr, ParserAtomEntry** atomp); template XDRResult XDRParserAtomEntry(XDRState* xdr, ParserAtomEntry** atomp); } /* namespace js */ bool JSRuntime::initializeParserAtoms(JSContext* cx) { MOZ_ASSERT(!commonParserNames); if (parentRuntime) { commonParserNames = parentRuntime->commonParserNames; return true; } UniquePtr names( js_new()); if (!names || !names->init(cx)) { return false; } commonParserNames = names.release(); return true; } void JSRuntime::finishParserAtoms() { if (!parentRuntime) { js_delete(commonParserNames.ref()); } }