author | Tooru Fujisawa <arai_a@mac.com> |
Fri, 11 Oct 2019 14:42:41 +0000 | |
changeset 497276 | 15ff5c7542067cfa94da1ce0c896141be4afea78 |
parent 497275 | c9ea9966d4cdc4007eb3c4a023ad87fa891eda33 |
child 497277 | ac3d70b6b575df0460216c306f2b3e2d35634b26 |
push id | 36681 |
push user | cbrindusan@mozilla.com |
push date | Fri, 11 Oct 2019 21:50:12 +0000 |
treeherder | mozilla-central@c5e6477c3a24 [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | Yoric |
bugs | 1587663 |
milestone | 71.0a1 |
first release with | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
js/src/frontend/BinASTTokenReaderContext.cpp | file | annotate | diff | comparison | revisions | |
js/src/frontend/BinASTTokenReaderContext.h | file | annotate | diff | comparison | revisions |
--- a/js/src/frontend/BinASTTokenReaderContext.cpp +++ b/js/src/frontend/BinASTTokenReaderContext.cpp @@ -180,54 +180,49 @@ class HuffmanPreludeReader { using Explicit = Ok; explicit EntryExplicit(const NormalizedInterfaceAndField identity) : EntryBase(identity) {} }; // A string. // May be a literal string, identifier name or property key. May not be null. struct String : EntryExplicit { - using SymbolType = JSAtom*; using Table = HuffmanTableIndexedSymbolsLiteralString; explicit String(const NormalizedInterfaceAndField identity) : EntryExplicit(identity) {} }; using IdentifierName = String; using PropertyKey = String; // An optional string. // May be a literal string, identifier name or property key. struct MaybeString : EntryExplicit { - using SymbolType = JSAtom*; using Table = HuffmanTableIndexedSymbolsOptionalLiteralString; explicit MaybeString(const NormalizedInterfaceAndField identity) : EntryExplicit(identity) {} }; using MaybeIdentifierName = MaybeString; using MaybePropertyKey = MaybeString; // A JavaScript number. May not be null. struct Number : EntryExplicit { - using SymbolType = double; using Table = HuffmanTableExplicitSymbolsF64; explicit Number(const NormalizedInterfaceAndField identity) : EntryExplicit(identity) {} }; // A 32-bit integer. May not be null. struct UnsignedLong : EntryExplicit { - using SymbolType = uint32_t; using Table = HuffmanTableExplicitSymbolsU32; explicit UnsignedLong(const NormalizedInterfaceAndField identity) : EntryExplicit(identity) {} }; // A boolean. May not be null. struct Boolean : EntryIndexed { - using SymbolType = bool; using Table = HuffmanTableIndexedSymbolsBool; explicit Boolean(const NormalizedInterfaceAndField identity) : EntryIndexed(identity) {} // Comparing booleans. // // As 0 == False < True == 1, we only compare indices. @@ -241,18 +236,16 @@ class HuffmanPreludeReader { // A field encoding a lazy offset. struct Lazy : EntryExplicit { explicit Lazy(const NormalizedInterfaceAndField identity) : EntryExplicit(identity) {} }; // A value of a given interface. May not be null. struct Interface : EntryIndexed { - using SymbolType = BinASTKind; - // The kind of the interface. const BinASTKind kind_; Interface(const NormalizedInterfaceAndField identity, BinASTKind kind) : EntryIndexed(identity), kind_(kind) {} // Utility struct, used in macros to call the constructor as // `Interface::Maker(kind)(identity)`. struct Maker { @@ -261,17 +254,16 @@ class HuffmanPreludeReader { Interface operator()(const NormalizedInterfaceAndField identity) { return Interface(identity, kind_); } }; }; // An optional value of a given interface. struct MaybeInterface : EntryIndexed { - using SymbolType = BinASTKind; using Table = HuffmanTableIndexedSymbolsMaybeInterface; // The kind of the interface. const BinASTKind kind_; // Comparing optional interfaces. // // As 0 == Null < _ == 1, we only compare indices. inline bool lessThan(uint32_t aIndex, uint32_t bIndex) { @@ -298,19 +290,16 @@ class HuffmanPreludeReader { }; // A FrozenArray. May not be null. // // In practice, this type is used to represent the length of the list. // Once we have read the model for the length of the list, we push a // `ListContents` to read the model for the contents of the list. struct List : EntryExplicit { - // The symbol type for the length of the list. - using SymbolType = uint32_t; - // The table for the length of the list. using Table = HuffmanTableExplicitSymbolsListLength; // The type of the list, e.g. list of numbers. // All lists with the same type share a model for their length. const BinASTList contents_; List(const NormalizedInterfaceAndField identity, const BinASTList contents) @@ -330,17 +319,16 @@ class HuffmanPreludeReader { // A FrozenArray. May not be null. struct ListContents : EntryBase { explicit ListContents(const NormalizedInterfaceAndField identity) : EntryBase(identity) {} }; // A choice between several interfaces. May not be null. struct Sum : EntryIndexed { - using SymbolType = BinASTKind; // The type of table used for this entry. using Table = HuffmanTableIndexedSymbolsSum; // The type of values in the sum. const BinASTSum contents_; // Comparing sum entries alphabetically. inline bool lessThan(uint32_t aIndex, uint32_t bIndex) { @@ -371,24 +359,22 @@ class HuffmanPreludeReader { Sum operator()(const NormalizedInterfaceAndField identity) { return Sum(identity, contents_); } }; }; // An optional choice between several interfaces. struct MaybeSum : EntryIndexed { - // The type of symbols for this entry. - // We use `BinASTKind::_Null` to represent the null case. - using SymbolType = BinASTKind; // The type of table used for this entry. // We use `BinASTKind::_Null` to represent the null case. using Table = HuffmanTableIndexedSymbolsSum; // The type of values in the sum. + // We use `BinASTKind::_Null` to represent the null case. const BinASTSum contents_; inline bool lessThan(uint32_t aIndex, uint32_t bIndex) { return aIndex < bIndex; } MaybeSum(const NormalizedInterfaceAndField identity, const BinASTSum contents) @@ -414,17 +400,16 @@ class HuffmanPreludeReader { MaybeSum operator()(const NormalizedInterfaceAndField identity) { return MaybeSum(identity, contents_); } }; }; // A choice between several strings. May not be null. struct StringEnum : EntryIndexed { - using SymbolType = BinASTVariant; using Table = HuffmanTableIndexedSymbolsStringEnum; // Comparing string enums alphabetically. inline bool lessThan(uint32_t aIndex, uint32_t bIndex) { MOZ_ASSERT(aIndex <= maxNumberOfSymbols()); MOZ_ASSERT(bIndex <= maxNumberOfSymbols()); const size_t aKey = getBinASTVariantSortKey(variantAt(aIndex)); const size_t bKey = getBinASTVariantSortKey(variantAt(bIndex)); @@ -514,17 +499,17 @@ class HuffmanPreludeReader { // Spec: // 3. If the field has a FrozenArray type // a. Determine if the array type is always empty // b. If so, stop auto& lengthTable = table.as<HuffmanTableExplicitSymbolsListLength>(); bool empty = true; for (auto iter : lengthTable) { - if (*iter > 0) { + if (iter->toListLength() > 0) { empty = false; break; } } if (empty) { return Ok(); } @@ -554,17 +539,18 @@ class HuffmanPreludeReader { MOZ_MUST_USE JS::Result<Ok> pushValue(NormalizedInterfaceAndField identity, const Interface& interface) { // Note: In this case, for compatibility, we do *not* check whether // the interface has already been visited. auto& table = dictionary_.tableForField(identity); if (table.is<HuffmanTableUnreachable>()) { // Effectively, an `Interface` is a sum with a single entry. HuffmanTableIndexedSymbolsSum sum(cx_); - MOZ_TRY(sum.initWithSingleValue(cx_, BinASTKind(interface.kind_))); + MOZ_TRY(sum.initWithSingleValue( + cx_, BinASTSymbol::fromKind(BinASTKind(interface.kind_)))); table = {mozilla::VariantType<HuffmanTableIndexedSymbolsSum>{}, std::move(sum)}; } // Spec: // 4. If the effective type is a monomorphic interface, push all of the // interface’s fields return pushFields(interface.kind_); @@ -629,18 +615,17 @@ class HuffmanPreludeReader { return Ok(); } // Read a single symbol. // For an indexed type, the symbol is fetched from the grammar using `index`. // We have a guarantee that `index` is always in [0, numberOfSymbols). template <typename Entry> - MOZ_MUST_USE JS::Result<typename Entry::SymbolType> readSymbol(const Entry&, - size_t index); + MOZ_MUST_USE JS::Result<BinASTSymbol> readSymbol(const Entry&, size_t index); // Read the number of symbols in an entry. // For an indexed type, theis number is fetched from the grammar. // We have a guarantee that `index` is always in [0, numberOfSymbols) template <typename Entry> MOZ_MUST_USE JS::Result<uint32_t> readNumberOfSymbols(const Entry&); // Read a table in the optimized "only one value" format. @@ -671,17 +656,17 @@ class HuffmanPreludeReader { return raiseInvalidTableData(entry.identity_); } // Read the symbol. // If `Entry` is an indexed type, it is fetched directly from the grammar. BINJS_MOZ_TRY_DECL( symbol, readSymbol<Entry>(entry, /* First and only value */ 0)); - MOZ_TRY(table.initWithSingleValue(cx_, std::move(symbol))); + MOZ_TRY(table.initWithSingleValue(cx_, symbol)); return Ok(); } MOZ_TRY(readMultipleValuesTableAndAssignCode<Entry>(table, entry, numberOfSymbols)); // Note that the table may be empty, in the case of a list that never has // any elements. @@ -736,17 +721,17 @@ class HuffmanPreludeReader { // By format invariant, bit lengths are always non-0 // and always ranked by increasing order. return raiseInvalidTableData(entry.identity_); } // Read and add symbol. BINJS_MOZ_TRY_DECL( symbol, readSymbol<Entry>(entry, i)); // Symbol is read from disk. - MOZ_TRY(table.addSymbol(code, bitLength, std::move(symbol))); + MOZ_TRY(table.addSymbol(code, bitLength, symbol)); // Prepare next code. code = (code + 1) << (nextBitLength - bitLength); } MOZ_TRY(table.initComplete()); auxStorageLength_.clear(); return Ok(); @@ -819,17 +804,17 @@ class HuffmanPreludeReader { // Read symbol from memory and add it. BINJS_MOZ_TRY_DECL( symbol, readSymbol<Entry>( entry, auxStorageLength_[i].index_)); // Symbol is read from memory. - MOZ_TRY(table.addSymbol(code, bitLength, std::move(symbol))); + MOZ_TRY(table.addSymbol(code, bitLength, symbol)); // Prepare next code. code = (code + 1) << (nextBitLength - bitLength); } MOZ_TRY(table.initComplete()); auxStorageLength_.clear(); @@ -963,17 +948,17 @@ class HuffmanPreludeReader { const auto& table = owner.dictionary_.tableForField(entry.identity_); if (table.is<HuffmanTableInitializing>()) { return Ok(); } const auto& tableRef = table.as<HuffmanTableIndexedSymbolsSum>(); for (auto iter : tableRef) { MOZ_TRY(owner.pushValue(entry.identity_, - Interface(entry.identity_, *iter))); + Interface(entry.identity_, iter->toKind()))); } return Ok(); } // Sum of interfaces, nullable. // Values: `null`, followed by interfaces by the order in // `FOR_EACH_BIN_INTERFACE_IN_SUM_*`. MOZ_MUST_USE JS::Result<Ok> operator()(const MaybeSum& entry) { @@ -987,17 +972,17 @@ class HuffmanPreludeReader { const auto& table = owner.dictionary_.tableForField(entry.identity_); if (table.is<HuffmanTableUnreachable>()) { return Ok(); } const auto& tableRef = table.as<HuffmanTableIndexedSymbolsSum>(); for (auto iter : tableRef) { MOZ_TRY(owner.pushValue(entry.identity_, - Interface(entry.identity_, *iter))); + Interface(entry.identity_, iter->toKind()))); } return Ok(); } MOZ_MUST_USE JS::Result<Ok> operator()(const Number& entry) { return owner.readTable<Number>(entry); } @@ -1295,39 +1280,36 @@ JS::Result<HuffmanLookup> BinASTTokenRea // Now, we may prepare a `HuffmanLookup` with up to 32 bits. if (bitLength_ <= MAX_PREFIX_BIT_LENGTH) { return HuffmanLookup(bits_, bitLength_); } } // Keep only 32 bits. We perform the operation on 64 bits to avoid any // arithmetics surprise. - const uint64_t bitPrefix = - bits_ >> (bitLength_ - MAX_PREFIX_BIT_LENGTH); + const uint64_t bitPrefix = bits_ >> (bitLength_ - MAX_PREFIX_BIT_LENGTH); MOZ_ASSERT(bitPrefix <= uint32_t(-1)); return HuffmanLookup(bitPrefix, MAX_PREFIX_BIT_LENGTH); } template <> void BinASTTokenReaderContext::BitBuffer::advanceBitBuffer<Compression::No>( const uint8_t bitLength) { // It should be impossible to call `advanceBitBuffer` // with more bits than what we just handed out. MOZ_ASSERT(bitLength <= bitLength_); bitLength_ -= bitLength; // Now zero out the bits that are beyond `bitLength_`. - const uint64_t mask = - bitLength_ == 0 - ? 0 // >> 64 is UB for a uint64_t - : uint64_t(-1) >> (BIT_BUFFER_SIZE - bitLength_); + const uint64_t mask = bitLength_ == 0 + ? 0 // >> 64 is UB for a uint64_t + : uint64_t(-1) >> (BIT_BUFFER_SIZE - bitLength_); bits_ &= mask; - MOZ_ASSERT_IF(bitLength_ != BIT_BUFFER_SIZE, - bits_ >> bitLength_ == 0); + MOZ_ASSERT_IF(bitLength_ != BIT_BUFFER_SIZE, bits_ >> bitLength_ == 0); } void BinASTTokenReaderContext::traceMetadata(JSTracer* trc) { if (metadata_) { metadata_->trace(trc); } } @@ -1365,76 +1347,83 @@ JS::Result<BinASTKind> BinASTTokenReader dictionary_.tableForField(NormalizedInterfaceAndField(identity)); BINJS_MOZ_TRY_DECL(bits_, (bitBuffer.getHuffmanLookup<Compression::No>(*this))); if (table.is<HuffmanTableIndexedSymbolsSum>()) { const auto& specialized = table.as<HuffmanTableIndexedSymbolsSum>(); // We're entering either a single interface or a sum. - const auto lookup = specialized.lookup(bits_); - bitBuffer.advanceBitBuffer<Compression::No>(lookup.key_.bitLength_); - if (MOZ_UNLIKELY(!lookup.value_)) { + const auto result = specialized.lookup(bits_); + if (MOZ_UNLIKELY(!result.isFound())) { return raiseInvalidValue(); } - return *lookup.value_; + bitBuffer.advanceBitBuffer<Compression::No>(result.bitLength()); + return result.value().toKind(); } MOZ_ASSERT(table.is<HuffmanTableIndexedSymbolsMaybeInterface>()); const auto& specialized = table.as<HuffmanTableIndexedSymbolsMaybeInterface>(); // We're entering an optional interface. - const auto lookup = specialized.lookup(bits_); - bitBuffer.advanceBitBuffer<Compression::No>(lookup.key_.bitLength_); - if (MOZ_UNLIKELY(!lookup.value_)) { + const auto result = specialized.lookup(bits_); + if (MOZ_UNLIKELY(!result.isFound())) { return raiseInvalidValue(); } - return *lookup.value_; + bitBuffer.advanceBitBuffer<Compression::No>(result.bitLength()); + return result.value().toKind(); } template <typename Table> -JS::Result<typename Table::Contents> -BinASTTokenReaderContext::readFieldFromTable( +JS::Result<BinASTSymbol> BinASTTokenReaderContext::readFieldFromTable( const BinASTInterfaceAndField& identity) { // Extract the table. const auto& table = dictionary_.tableForField(NormalizedInterfaceAndField(identity)); if (MOZ_UNLIKELY(!table.is<Table>())) { return raiseNotInPrelude(); } BINJS_MOZ_TRY_DECL(bits_, bitBuffer.getHuffmanLookup<Compression::No>(*this)); - const auto lookup = table.as<Table>().lookup(bits_); - - bitBuffer.advanceBitBuffer<Compression::No>(lookup.key_.bitLength_); - if (MOZ_UNLIKELY(!lookup.value_)) { + const auto result = table.as<Table>().lookup(bits_); + if (MOZ_UNLIKELY(!result.isFound())) { return raiseInvalidValue(); } - return *lookup.value_; + bitBuffer.advanceBitBuffer<Compression::No>(result.bitLength()); + return result.value(); } JS::Result<bool> BinASTTokenReaderContext::readBool( const FieldContext& context) { - return readFieldFromTable<HuffmanTableIndexedSymbolsBool>(context.position_); + BINJS_MOZ_TRY_DECL(result, readFieldFromTable<HuffmanTableIndexedSymbolsBool>( + context.position_)); + return result.toBool(); } JS::Result<double> BinASTTokenReaderContext::readDouble( const FieldContext& context) { - return readFieldFromTable<HuffmanTableExplicitSymbolsF64>(context.position_); + BINJS_MOZ_TRY_DECL(result, readFieldFromTable<HuffmanTableExplicitSymbolsF64>( + context.position_)); + return result.toDouble(); } JS::Result<JSAtom*> BinASTTokenReaderContext::readMaybeAtom( const FieldContext& context) { - return readFieldFromTable<HuffmanTableIndexedSymbolsOptionalLiteralString>( - context.position_); + BINJS_MOZ_TRY_DECL( + result, + readFieldFromTable<HuffmanTableIndexedSymbolsOptionalLiteralString>( + context.position_)); + return result.toAtom(); } JS::Result<JSAtom*> BinASTTokenReaderContext::readAtom( const FieldContext& context) { - return readFieldFromTable<HuffmanTableIndexedSymbolsLiteralString>( - context.position_); + BINJS_MOZ_TRY_DECL( + result, readFieldFromTable<HuffmanTableIndexedSymbolsLiteralString>( + context.position_)); + return result.toAtom(); } JS::Result<JSAtom*> BinASTTokenReaderContext::readMaybeIdentifierName( const FieldContext& context) { return readMaybeAtom(context); } JS::Result<JSAtom*> BinASTTokenReaderContext::readIdentifierName( @@ -1452,30 +1441,32 @@ JS::Result<Ok> BinASTTokenReaderContext: return raiseError("readChars is not implemented in BinASTTokenReaderContext"); } JS::Result<BinASTVariant> BinASTTokenReaderContext::readVariant( const ListContext& context) { BINJS_MOZ_TRY_DECL(result, readFieldFromTable<HuffmanTableIndexedSymbolsStringEnum>( context.position_)); - return result; + return result.toVariant(); } JS::Result<BinASTVariant> BinASTTokenReaderContext::readVariant( const FieldContext& context) { BINJS_MOZ_TRY_DECL(result, readFieldFromTable<HuffmanTableIndexedSymbolsStringEnum>( context.position_)); - return result; + return result.toVariant(); } JS::Result<uint32_t> BinASTTokenReaderContext::readUnsignedLong( const FieldContext& context) { - return readFieldFromTable<HuffmanTableExplicitSymbolsU32>(context.position_); + BINJS_MOZ_TRY_DECL(result, readFieldFromTable<HuffmanTableExplicitSymbolsU32>( + context.position_)); + return result.toUnsignedLong(); } JS::Result<BinASTTokenReaderBase::SkippableSubTree> BinASTTokenReaderContext::readSkippableSubTree(const FieldContext&) { return raiseError("Not Yet Implemented"); } JS::Result<Ok> BinASTTokenReaderContext::enterSum( @@ -1534,22 +1525,22 @@ JS::Result<Ok> BinASTTokenReaderContext: JS::Result<Ok> BinASTTokenReaderContext::enterList(uint32_t& items, const ListContext& context) { const auto identity = context.content_; const auto& table = dictionary_.tableForListLength(identity); BINJS_MOZ_TRY_DECL(bits_, bitBuffer.getHuffmanLookup<Compression::No>(*this)); const auto& tableForLookup = table.as<HuffmanTableExplicitSymbolsListLength>(); - const auto lookup = tableForLookup.lookup(bits_); - bitBuffer.advanceBitBuffer<Compression::No>(lookup.key_.bitLength_); - if (MOZ_UNLIKELY(!lookup.value_)) { + const auto result = tableForLookup.lookup(bits_); + if (MOZ_UNLIKELY(!result.isFound())) { return raiseInvalidValue(); } - items = *lookup.value_; + bitBuffer.advanceBitBuffer<Compression::No>(result.bitLength()); + items = result.value().toListLength(); return Ok(); } // Internal uint32_t // Note that this is different than varnum in multipart. // // Encoded as variable length number. @@ -1593,416 +1584,403 @@ JS::Result<uint32_t> BinASTTokenReaderCo HuffmanKey::HuffmanKey(const uint32_t bits, const uint8_t bitLength) : bits_(bits), bitLength_(bitLength) { MOZ_ASSERT(bitLength_ <= MAX_PREFIX_BIT_LENGTH); MOZ_ASSERT_IF(bitLength_ != 32 /* >> 32 is UB */, bits >> bitLength == 0); } // ---- Implementation of Huffman Tables -template <typename T> -GenericHuffmanTable<T>::Iterator::Iterator( - typename SingleEntryHuffmanTable<T>::Iterator&& iterator) +GenericHuffmanTable::Iterator::Iterator( + typename SingleEntryHuffmanTable::Iterator&& iterator) : implementation_(std::move(iterator)) {} -template <typename T> -GenericHuffmanTable<T>::Iterator::Iterator( - typename SingleLookupHuffmanTable<T>::Iterator&& iterator) +GenericHuffmanTable::Iterator::Iterator( + typename SingleLookupHuffmanTable::Iterator&& iterator) : implementation_(std::move(iterator)) {} -template <typename T> -GenericHuffmanTable<T>::Iterator::Iterator( - typename TwoLookupsHuffmanTable<T>::Iterator&& iterator) +GenericHuffmanTable::Iterator::Iterator( + typename TwoLookupsHuffmanTable::Iterator&& iterator) : implementation_(std::move(iterator)) {} -template <typename T> -GenericHuffmanTable<T>::Iterator::Iterator( - typename ThreeLookupsHuffmanTable<T>::Iterator&& iterator) +GenericHuffmanTable::Iterator::Iterator( + typename ThreeLookupsHuffmanTable::Iterator&& iterator) : implementation_(std::move(iterator)) {} -template <typename T> -void GenericHuffmanTable<T>::Iterator::operator++() { +void GenericHuffmanTable::Iterator::operator++() { implementation_.match( - [](typename SingleEntryHuffmanTable<T>::Iterator& iterator) { + [](typename SingleEntryHuffmanTable::Iterator& iterator) { iterator.operator++(); }, - [](typename SingleLookupHuffmanTable<T>::Iterator& iterator) { + [](typename SingleLookupHuffmanTable::Iterator& iterator) { iterator.operator++(); }, - [](typename TwoLookupsHuffmanTable<T>::Iterator& iterator) { + [](typename TwoLookupsHuffmanTable::Iterator& iterator) { iterator.operator++(); }, - [](typename ThreeLookupsHuffmanTable<T>::Iterator& iterator) { + [](typename ThreeLookupsHuffmanTable::Iterator& iterator) { iterator.operator++(); }); } -template <typename T> -bool GenericHuffmanTable<T>::Iterator::operator==( - const GenericHuffmanTable<T>::Iterator& other) const { +bool GenericHuffmanTable::Iterator::operator==( + const GenericHuffmanTable::Iterator& other) const { return implementation_.match( - [other](const typename SingleEntryHuffmanTable<T>::Iterator& iterator) { - return iterator == other.implementation_.template as< - typename SingleEntryHuffmanTable<T>::Iterator>(); + [other](const typename SingleEntryHuffmanTable::Iterator& iterator) { + return iterator == + other.implementation_ + .template as<typename SingleEntryHuffmanTable::Iterator>(); }, - [other](const typename SingleLookupHuffmanTable<T>::Iterator& iterator) { - return iterator == - other.implementation_.template as< - typename SingleLookupHuffmanTable<T>::Iterator>(); - }, - [other](const typename TwoLookupsHuffmanTable<T>::Iterator& iterator) { + [other](const typename SingleLookupHuffmanTable::Iterator& iterator) { return iterator == other.implementation_ - .template as<typename TwoLookupsHuffmanTable<T>::Iterator>(); + .template as<typename SingleLookupHuffmanTable::Iterator>(); }, - [other](const typename ThreeLookupsHuffmanTable<T>::Iterator& iterator) { + [other](const typename TwoLookupsHuffmanTable::Iterator& iterator) { return iterator == - other.implementation_.template as< - typename ThreeLookupsHuffmanTable<T>::Iterator>(); + other.implementation_ + .template as<typename TwoLookupsHuffmanTable::Iterator>(); + }, + [other](const typename ThreeLookupsHuffmanTable::Iterator& iterator) { + return iterator == + other.implementation_ + .template as<typename ThreeLookupsHuffmanTable::Iterator>(); }); } -template <typename T> -bool GenericHuffmanTable<T>::Iterator::operator!=( - const GenericHuffmanTable<T>::Iterator& other) const { +bool GenericHuffmanTable::Iterator::operator!=( + const GenericHuffmanTable::Iterator& other) const { return implementation_.match( - [other](const typename SingleEntryHuffmanTable<T>::Iterator& iterator) { - return iterator != other.implementation_.template as< - typename SingleEntryHuffmanTable<T>::Iterator>(); + [other](const typename SingleEntryHuffmanTable::Iterator& iterator) { + return iterator != + other.implementation_ + .template as<typename SingleEntryHuffmanTable::Iterator>(); }, - [other](const typename SingleLookupHuffmanTable<T>::Iterator& iterator) { + [other](const typename SingleLookupHuffmanTable::Iterator& iterator) { return iterator != - other.implementation_.template as< - typename SingleLookupHuffmanTable<T>::Iterator>(); + other.implementation_ + .template as<typename SingleLookupHuffmanTable::Iterator>(); }, - [other](const typename TwoLookupsHuffmanTable<T>::Iterator& iterator) { + [other](const typename TwoLookupsHuffmanTable::Iterator& iterator) { return iterator != other.implementation_ - .template as<typename TwoLookupsHuffmanTable<T>::Iterator>(); + .template as<typename TwoLookupsHuffmanTable::Iterator>(); }, - [other](const typename ThreeLookupsHuffmanTable<T>::Iterator& iterator) { + [other](const typename ThreeLookupsHuffmanTable::Iterator& iterator) { return iterator != - other.implementation_.template as< - typename ThreeLookupsHuffmanTable<T>::Iterator>(); + other.implementation_ + .template as<typename ThreeLookupsHuffmanTable::Iterator>(); }); } -template <typename T> -const T* GenericHuffmanTable<T>::Iterator::operator*() const { +const BinASTSymbol* GenericHuffmanTable::Iterator::operator*() const { return implementation_.match( - [](const typename SingleEntryHuffmanTable<T>::Iterator& iterator) { + [](const typename SingleEntryHuffmanTable::Iterator& iterator) { return iterator.operator*(); }, - [](const typename SingleLookupHuffmanTable<T>::Iterator& iterator) { + [](const typename SingleLookupHuffmanTable::Iterator& iterator) { return iterator.operator*(); }, - [](const typename TwoLookupsHuffmanTable<T>::Iterator& iterator) { + [](const typename TwoLookupsHuffmanTable::Iterator& iterator) { return iterator.operator*(); }, - [](const typename ThreeLookupsHuffmanTable<T>::Iterator& iterator) { + [](const typename ThreeLookupsHuffmanTable::Iterator& iterator) { return iterator.operator*(); }); } -template <typename T> -GenericHuffmanTable<T>::GenericHuffmanTable(JSContext*) +const BinASTSymbol* GenericHuffmanTable::Iterator::operator->() const { + return implementation_.match( + [](const typename SingleEntryHuffmanTable::Iterator& iterator) { + return iterator.operator->(); + }, + [](const typename SingleLookupHuffmanTable::Iterator& iterator) { + return iterator.operator->(); + }, + [](const typename TwoLookupsHuffmanTable::Iterator& iterator) { + return iterator.operator->(); + }, + [](const typename ThreeLookupsHuffmanTable::Iterator& iterator) { + return iterator.operator->(); + }); +} + +GenericHuffmanTable::GenericHuffmanTable(JSContext*) : implementation_(HuffmanTableUnreachable{}) {} -template <typename T> -JS::Result<Ok> GenericHuffmanTable<T>::initComplete() { +JS::Result<Ok> GenericHuffmanTable::initComplete() { return implementation_.match( - [](SingleEntryHuffmanTable<T>& implementation) -> JS::Result<Ok> { + [](SingleEntryHuffmanTable& implementation) -> JS::Result<Ok> { MOZ_CRASH("SingleEntryHuffmanTable shouldn't have multiple entries!"); }, - [](SingleLookupHuffmanTable<T>& implementation) -> JS::Result<Ok> { + [](SingleLookupHuffmanTable& implementation) -> JS::Result<Ok> { return implementation.initComplete(); }, - [](TwoLookupsHuffmanTable<T>& implementation) -> JS::Result<Ok> { + [](TwoLookupsHuffmanTable& implementation) -> JS::Result<Ok> { return implementation.initComplete(); }, - [](ThreeLookupsHuffmanTable<T>& implementation) -> JS::Result<Ok> { + [](ThreeLookupsHuffmanTable& implementation) -> JS::Result<Ok> { return implementation.initComplete(); }, [](HuffmanTableUnreachable&) -> JS::Result<Ok> { MOZ_CRASH("GenericHuffmanTable is unitialized!"); }); } -template <typename T> -typename GenericHuffmanTable<T>::Iterator GenericHuffmanTable<T>::begin() - const { +typename GenericHuffmanTable::Iterator GenericHuffmanTable::begin() const { return implementation_.match( - [](const SingleEntryHuffmanTable<T>& implementation) - -> GenericHuffmanTable<T>::Iterator { + [](const SingleEntryHuffmanTable& implementation) + -> GenericHuffmanTable::Iterator { + return Iterator(implementation.begin()); + }, + [](const SingleLookupHuffmanTable& implementation) + -> GenericHuffmanTable::Iterator { return Iterator(implementation.begin()); }, - [](const SingleLookupHuffmanTable<T>& implementation) - -> GenericHuffmanTable<T>::Iterator { + [](const TwoLookupsHuffmanTable& implementation) + -> GenericHuffmanTable::Iterator { return Iterator(implementation.begin()); }, - [](const TwoLookupsHuffmanTable<T>& implementation) - -> GenericHuffmanTable<T>::Iterator { + [](const ThreeLookupsHuffmanTable& implementation) + -> GenericHuffmanTable::Iterator { return Iterator(implementation.begin()); }, - [](const ThreeLookupsHuffmanTable<T>& implementation) - -> GenericHuffmanTable<T>::Iterator { - return Iterator(implementation.begin()); - }, - [](const HuffmanTableUnreachable&) -> GenericHuffmanTable<T>::Iterator { + [](const HuffmanTableUnreachable&) -> GenericHuffmanTable::Iterator { MOZ_CRASH("GenericHuffmanTable is unitialized!"); }); } -template <typename T> -typename GenericHuffmanTable<T>::Iterator GenericHuffmanTable<T>::end() const { +typename GenericHuffmanTable::Iterator GenericHuffmanTable::end() const { return implementation_.match( - [](const SingleEntryHuffmanTable<T>& implementation) - -> GenericHuffmanTable<T>::Iterator { + [](const SingleEntryHuffmanTable& implementation) + -> GenericHuffmanTable::Iterator { + return Iterator(implementation.end()); + }, + [](const SingleLookupHuffmanTable& implementation) + -> GenericHuffmanTable::Iterator { return Iterator(implementation.end()); }, - [](const SingleLookupHuffmanTable<T>& implementation) - -> GenericHuffmanTable<T>::Iterator { + [](const TwoLookupsHuffmanTable& implementation) + -> GenericHuffmanTable::Iterator { return Iterator(implementation.end()); }, - [](const TwoLookupsHuffmanTable<T>& implementation) - -> GenericHuffmanTable<T>::Iterator { + [](const ThreeLookupsHuffmanTable& implementation) + -> GenericHuffmanTable::Iterator { return Iterator(implementation.end()); }, - [](const ThreeLookupsHuffmanTable<T>& implementation) - -> GenericHuffmanTable<T>::Iterator { - return Iterator(implementation.end()); - }, - [](const HuffmanTableUnreachable&) -> GenericHuffmanTable<T>::Iterator { + [](const HuffmanTableUnreachable&) -> GenericHuffmanTable::Iterator { MOZ_CRASH("GenericHuffmanTable is unitialized!"); }); } -template <typename T> -JS::Result<Ok> GenericHuffmanTable<T>::initWithSingleValue(JSContext* cx, - T&& value) { +JS::Result<Ok> GenericHuffmanTable::initWithSingleValue( + JSContext* cx, const BinASTSymbol& value) { // Only one value: use HuffmanImplementationSaturated MOZ_ASSERT(implementation_.template is< HuffmanTableUnreachable>()); // Make sure that we're initializing. - implementation_ = {mozilla::VariantType<SingleEntryHuffmanTable<T>>{}, - std::move(value)}; + implementation_ = {mozilla::VariantType<SingleEntryHuffmanTable>{}, value}; return Ok(); } -template <typename T> -JS::Result<Ok> GenericHuffmanTable<T>::initStart(JSContext* cx, - size_t numberOfSymbols, - uint8_t largestBitLength) { +JS::Result<Ok> GenericHuffmanTable::initStart(JSContext* cx, + size_t numberOfSymbols, + uint8_t largestBitLength) { // Make sure that we have a way to represent all legal bit lengths. - static_assert( - MAX_CODE_BIT_LENGTH <= ThreeLookupsHuffmanTable<T>::MAX_BIT_LENGTH, - "ThreeLookupsHuffmanTable cannot hold all bit lengths"); + static_assert(MAX_CODE_BIT_LENGTH <= ThreeLookupsHuffmanTable::MAX_BIT_LENGTH, + "ThreeLookupsHuffmanTable cannot hold all bit lengths"); // Make sure that we're initializing. MOZ_ASSERT(implementation_.template is<HuffmanTableUnreachable>()); // Find the (hopefully) fastest implementation of HuffmanTable for // `largestBitLength`. // ...hopefully, only one lookup. - if (largestBitLength <= SingleLookupHuffmanTable<T>::MAX_BIT_LENGTH) { - implementation_ = {mozilla::VariantType<SingleLookupHuffmanTable<T>>{}, cx}; - return implementation_.template as<SingleLookupHuffmanTable<T>>().initStart( + if (largestBitLength <= SingleLookupHuffmanTable::MAX_BIT_LENGTH) { + implementation_ = {mozilla::VariantType<SingleLookupHuffmanTable>{}, cx}; + return implementation_.template as<SingleLookupHuffmanTable>().initStart( cx, numberOfSymbols, largestBitLength); } // ...if a single-lookup table would be too large, let's see if // we can fit in a two-lookup table. - if (largestBitLength <= TwoLookupsHuffmanTable<T>::MAX_BIT_LENGTH) { - implementation_ = {mozilla::VariantType<TwoLookupsHuffmanTable<T>>{}, cx}; - return implementation_.template as<TwoLookupsHuffmanTable<T>>().initStart( + if (largestBitLength <= TwoLookupsHuffmanTable::MAX_BIT_LENGTH) { + implementation_ = {mozilla::VariantType<TwoLookupsHuffmanTable>{}, cx}; + return implementation_.template as<TwoLookupsHuffmanTable>().initStart( cx, numberOfSymbols, largestBitLength); } // ...otherwise, we'll need three lookups. - implementation_ = {mozilla::VariantType<ThreeLookupsHuffmanTable<T>>{}, cx}; - return implementation_.template as<ThreeLookupsHuffmanTable<T>>().initStart( + implementation_ = {mozilla::VariantType<ThreeLookupsHuffmanTable>{}, cx}; + return implementation_.template as<ThreeLookupsHuffmanTable>().initStart( cx, numberOfSymbols, largestBitLength); } -template <typename T> -JS::Result<Ok> GenericHuffmanTable<T>::addSymbol(uint32_t bits, - uint8_t bitLength, T&& value) { +JS::Result<Ok> GenericHuffmanTable::addSymbol(uint32_t bits, uint8_t bitLength, + const BinASTSymbol& value) { return implementation_.match( - [](SingleEntryHuffmanTable<T>&) -> JS::Result<Ok> { + [](SingleEntryHuffmanTable&) -> JS::Result<Ok> { MOZ_CRASH("SingleEntryHuffmanTable shouldn't have multiple entries!"); return Ok(); }, - [bits, bitLength, value = std::move(value)]( - SingleLookupHuffmanTable<T>& - implementation) mutable /* discard implicit const */ + [bits, bitLength, + value](SingleLookupHuffmanTable& + implementation) mutable /* discard implicit const */ -> JS::Result<Ok> { - return implementation.addSymbol(bits, bitLength, std::move(value)); + return implementation.addSymbol(bits, bitLength, value); }, - [bits, bitLength, value = std::move(value)]( - TwoLookupsHuffmanTable<T>& - implementation) mutable /* discard implicit const */ + [bits, bitLength, + value](TwoLookupsHuffmanTable& + implementation) mutable /* discard implicit const */ -> JS::Result<Ok> { - return implementation.addSymbol(bits, bitLength, std::move(value)); + return implementation.addSymbol(bits, bitLength, value); }, - [bits, bitLength, value = std::move(value)]( - ThreeLookupsHuffmanTable<T>& - implementation) mutable /* discard implicit const */ + [bits, bitLength, + value = value](ThreeLookupsHuffmanTable& + implementation) mutable /* discard implicit const */ -> JS::Result<Ok> { - return implementation.addSymbol(bits, bitLength, std::move(value)); + return implementation.addSymbol(bits, bitLength, value); }, [](HuffmanTableUnreachable&) -> JS::Result<Ok> { MOZ_CRASH("GenericHuffmanTable is unitialized!"); return Ok(); }); } -template <typename T> -HuffmanEntry<const T*> GenericHuffmanTable<T>::lookup( - HuffmanLookup lookup) const { +HuffmanLookupResult GenericHuffmanTable::lookup(HuffmanLookup key) const { return implementation_.match( - [lookup](const SingleEntryHuffmanTable<T>& implementation) - -> HuffmanEntry<const T*> { return implementation.lookup(lookup); }, - [lookup](const SingleLookupHuffmanTable<T>& implementation) - -> HuffmanEntry<const T*> { return implementation.lookup(lookup); }, - [lookup](const TwoLookupsHuffmanTable<T>& implementation) - -> HuffmanEntry<const T*> { return implementation.lookup(lookup); }, - [lookup](const ThreeLookupsHuffmanTable<T>& implementation) - -> HuffmanEntry<const T*> { return implementation.lookup(lookup); }, - [](const HuffmanTableUnreachable&) -> HuffmanEntry<const T*> { + [key](const SingleEntryHuffmanTable& implementation) + -> HuffmanLookupResult { return implementation.lookup(key); }, + [key](const SingleLookupHuffmanTable& implementation) + -> HuffmanLookupResult { return implementation.lookup(key); }, + [key](const TwoLookupsHuffmanTable& implementation) + -> HuffmanLookupResult { return implementation.lookup(key); }, + [key](const ThreeLookupsHuffmanTable& implementation) + -> HuffmanLookupResult { return implementation.lookup(key); }, + [](const HuffmanTableUnreachable&) -> HuffmanLookupResult { MOZ_CRASH("GenericHuffmanTable is unitialized!"); }); } -template <typename T, int N> -JS::Result<Ok> NaiveHuffmanTable<T, N>::initWithSingleValue(JSContext* cx, - T&& value) { +template <int N> +JS::Result<Ok> NaiveHuffmanTable<N>::initWithSingleValue( + JSContext* cx, const BinASTSymbol& value) { MOZ_ASSERT(values_.empty()); // Make sure that we're initializing. - if (MOZ_UNLIKELY(!values_.append(HuffmanEntry<T>(0, 0, std::move(value))))) { + if (MOZ_UNLIKELY(!values_.append(HuffmanEntry(0, 0, value)))) { return cx->alreadyReportedError(); } return Ok(); } -template <typename T, int N> -JS::Result<Ok> NaiveHuffmanTable<T, N>::initStart(JSContext* cx, - size_t numberOfSymbols, - uint8_t) { +template <int N> +JS::Result<Ok> NaiveHuffmanTable<N>::initStart(JSContext* cx, + size_t numberOfSymbols, + uint8_t) { MOZ_ASSERT(values_.empty()); // Make sure that we're initializing. if (MOZ_UNLIKELY(!values_.initCapacity(numberOfSymbols))) { return cx->alreadyReportedError(); } return Ok(); } -template <typename T, int N> -JS::Result<Ok> NaiveHuffmanTable<T, N>::initComplete() { +template <int N> +JS::Result<Ok> NaiveHuffmanTable<N>::initComplete() { MOZ_ASSERT(values_.length() <= N); return Ok(); } -template <typename T, int N> -JS::Result<Ok> NaiveHuffmanTable<T, N>::addSymbol(uint32_t bits, - uint8_t bitLength, - T&& value) { +template <int N> +JS::Result<Ok> NaiveHuffmanTable<N>::addSymbol(uint32_t bits, uint8_t bitLength, + const BinASTSymbol& value) { MOZ_ASSERT(bitLength != 0, "Adding a symbol with a bitLength of 0 doesn't make sense."); - MOZ_ASSERT(values_.empty() || values_.back().key_.bitLength_ <= bitLength, + MOZ_ASSERT(values_.empty() || values_.back().key().bitLength_ <= bitLength, "Symbols must be ranked by increasing bits length"); MOZ_ASSERT_IF(bitLength != 32 /* >> 32 is UB */, bits >> bitLength == 0); // Memory was reserved in `init()`. - MOZ_ALWAYS_TRUE(values_.emplaceBack(bits, bitLength, std::move(value))); + MOZ_ALWAYS_TRUE(values_.emplaceBack(bits, bitLength, value)); return Ok(); } -template <typename T, int N> -HuffmanEntry<const T*> NaiveHuffmanTable<T, N>::lookup( - HuffmanLookup key) const { +template <int N> +HuffmanLookupResult NaiveHuffmanTable<N>::lookup(HuffmanLookup key) const { // This current implementation is O(length) and designed mostly for testing. // Future versions will presumably adapt the underlying data structure to // provide bounded-time lookup. for (const auto& iter : values_) { - if (iter.key_.bitLength_ > key.bitLength_) { + if (iter.key().bitLength_ > key.bitLength_) { // We can't find the entry. break; } - const uint32_t keyBits = key.leadingBits(iter.key_.bitLength_); - if (keyBits == iter.key_.bits_) { - // Entry found. - return HuffmanEntry<const T*>(iter.key_.bits_, iter.key_.bitLength_, - &iter.value_); + const uint32_t keyBits = key.leadingBits(iter.key().bitLength_); + if (keyBits == iter.key().bits_) { + return HuffmanLookupResult::found(iter.key().bitLength_, &iter.value()); } } - // Error: no entry found. - return HuffmanEntry<const T*>(0, 0, nullptr); + return HuffmanLookupResult::notFound(); } -template <typename T> -SingleEntryHuffmanTable<T>::Iterator::Iterator(const T* position) +SingleEntryHuffmanTable::Iterator::Iterator(const BinASTSymbol* position) : position_(position) {} -template <typename T> -void SingleEntryHuffmanTable<T>::Iterator::operator++() { +void SingleEntryHuffmanTable::Iterator::operator++() { // There's only one entry, and `nullptr` means `end`. position_ = nullptr; } -template <typename T> -const T* SingleEntryHuffmanTable<T>::Iterator::operator*() const { +const BinASTSymbol* SingleEntryHuffmanTable::Iterator::operator*() const { return position_; } -template <typename T> -bool SingleEntryHuffmanTable<T>::Iterator::operator==( +const BinASTSymbol* SingleEntryHuffmanTable::Iterator::operator->() const { + return position_; +} + +bool SingleEntryHuffmanTable::Iterator::operator==( const Iterator& other) const { return position_ == other.position_; } -template <typename T> -bool SingleEntryHuffmanTable<T>::Iterator::operator!=( +bool SingleEntryHuffmanTable::Iterator::operator!=( const Iterator& other) const { return position_ != other.position_; } -template <typename T> -HuffmanEntry<const T*> SingleEntryHuffmanTable<T>::lookup( - HuffmanLookup key) const { - return HuffmanEntry<const T*>(0, 0, &value_); +HuffmanLookupResult SingleEntryHuffmanTable::lookup(HuffmanLookup key) const { + return HuffmanLookupResult::found(0, &value_); } -template <typename T> -SingleLookupHuffmanTable<T>::Iterator::Iterator(const HuffmanEntry<T>* position) +SingleLookupHuffmanTable::Iterator::Iterator(const HuffmanEntry* position) : position_(position) {} -template <typename T> -void SingleLookupHuffmanTable<T>::Iterator::operator++() { - position_++; +void SingleLookupHuffmanTable::Iterator::operator++() { position_++; } + +const BinASTSymbol* SingleLookupHuffmanTable::Iterator::operator*() const { + return &position_->value(); } -template <typename T> -const T* SingleLookupHuffmanTable<T>::Iterator::operator*() const { - return &position_->value_; +const BinASTSymbol* SingleLookupHuffmanTable::Iterator::operator->() const { + return &position_->value(); } -template <typename T> -bool SingleLookupHuffmanTable<T>::Iterator::operator==( +bool SingleLookupHuffmanTable::Iterator::operator==( const Iterator& other) const { return position_ == other.position_; } -template <typename T> -bool SingleLookupHuffmanTable<T>::Iterator::operator!=( +bool SingleLookupHuffmanTable::Iterator::operator!=( const Iterator& other) const { return position_ != other.position_; } -template <typename T> -JS::Result<Ok> SingleLookupHuffmanTable<T>::initStart( - JSContext* cx, size_t numberOfSymbols, uint8_t largestBitLength) { +JS::Result<Ok> SingleLookupHuffmanTable::initStart(JSContext* cx, + size_t numberOfSymbols, + uint8_t largestBitLength) { MOZ_ASSERT_IF(largestBitLength != 32, (uint32_t(1) << largestBitLength) - 1 <= mozilla::MaxValue<InternalIndex>::value); MOZ_ASSERT(values_.empty()); // Make sure that we're initializing. largestBitLength_ = largestBitLength; if (MOZ_UNLIKELY(!values_.initCapacity(numberOfSymbols))) { @@ -2015,55 +1993,53 @@ JS::Result<Ok> SingleLookupHuffmanTable< // Enlarge `saturated_`, as we're going to fill it in random order. for (size_t i = 0; i < saturatedLength; ++i) { // Capacity reserved in this method. saturated_.infallibleAppend(InternalIndex(-1)); } return Ok(); } -template <typename T> -JS::Result<Ok> SingleLookupHuffmanTable<T>::initComplete() { +JS::Result<Ok> SingleLookupHuffmanTable::initComplete() { // Double-check that we've initialized properly. MOZ_ASSERT(largestBitLength_ <= MAX_CODE_BIT_LENGTH); // We can end up with empty tables, if this `SingleLookupHuffmanTable` // is used to store suffixes in a `MultiLookupHuffmanTable` and // the corresponding prefix is never used. if (values_.length() == 0) { MOZ_ASSERT(largestBitLength_ == 0); return Ok(); } #ifdef DEBUG bool foundMaxBitLength = false; for (size_t i = 0; i < saturated_.length(); ++i) { const uint8_t index = saturated_[i]; - MOZ_ASSERT(values_[index].key_.bitLength_ <= largestBitLength_); - if (values_[index].key_.bitLength_ == largestBitLength_) { + MOZ_ASSERT(values_[index].key().bitLength_ <= largestBitLength_); + if (values_[index].key().bitLength_ == largestBitLength_) { foundMaxBitLength = true; } } MOZ_ASSERT(foundMaxBitLength); #endif // DEBUG return Ok(); } -template <typename T> -JS::Result<Ok> SingleLookupHuffmanTable<T>::addSymbol(uint32_t bits, - uint8_t bitLength, - T&& value) { +JS::Result<Ok> SingleLookupHuffmanTable::addSymbol(uint32_t bits, + uint8_t bitLength, + const BinASTSymbol& value) { MOZ_ASSERT_IF(largestBitLength_ != 0, bitLength != 0); MOZ_ASSERT_IF(bitLength != 32 /* >> 32 is UB */, bits >> bitLength == 0); MOZ_ASSERT(bitLength <= largestBitLength_); const size_t index = values_.length(); // First add the value to `values_`. // Memory was reserved in `init()`. - values_.infallibleEmplaceBack(bits, bitLength, std::move(value)); + values_.infallibleEmplaceBack(bits, bitLength, value); // Notation: in the following, unless otherwise specified, we consider // values with `largestBitLength_` bits exactly. // // When we perform lookup, we will extract `largestBitLength_` bits from the // key into a value `0bB...B`. We have a match for `value` if and only if // `0bB...B` may be decomposed into `0bC...CX...X` such that // - `0bC...C` is `bitLength` bits long; @@ -2075,114 +2051,117 @@ JS::Result<Ok> SingleLookupHuffmanTable< const HuffmanLookup base(bits, bitLength); for (size_t i : base.suffixes(largestBitLength_)) { saturated_[i] = index; } return Ok(); } -template <typename T> -HuffmanEntry<const T*> SingleLookupHuffmanTable<T>::lookup( - HuffmanLookup key) const { +HuffmanLookupResult SingleLookupHuffmanTable::lookup(HuffmanLookup key) const { if (values_.length() == 0) { // If the table is empty, any lookup fails. - return HuffmanEntry<const T*>(0, 0, nullptr); + return HuffmanLookupResult::notFound(); } // ...otherwise, all lookups succeed. // Take the `largestBitLength_` highest weight bits of `key`. // In the documentation of `addSymbol`, this is // `0bB...B`. const uint32_t bits = key.leadingBits(largestBitLength_); // Invariants: `saturated_.length() == 1 << largestBitLength_` // and `bits <= 1 << largestBitLength_`. const size_t index = saturated_[bits]; // Invariants: `saturated_[i] < values_.length()`. const auto& entry = values_[index]; - return HuffmanEntry<const T*>(entry.key_.bits_, entry.key_.bitLength_, - &entry.value_); + return HuffmanLookupResult::found(entry.key().bitLength_, &entry.value()); } -template <typename T, typename Subtable, uint8_t PrefixBitLength> -MultiLookupHuffmanTable<T, Subtable, PrefixBitLength>::Iterator::Iterator( - const HuffmanEntry<T>* position) +template <typename Subtable, uint8_t PrefixBitLength> +MultiLookupHuffmanTable<Subtable, PrefixBitLength>::Iterator::Iterator( + const HuffmanEntry* position) : position_(position) {} -template <typename T, typename Subtable, uint8_t PrefixBitLength> -void MultiLookupHuffmanTable<T, Subtable, PrefixBitLength>::Iterator:: -operator++() { +template <typename Subtable, uint8_t PrefixBitLength> +void MultiLookupHuffmanTable<Subtable, + PrefixBitLength>::Iterator::operator++() { position_++; } -template <typename T, typename Subtable, uint8_t PrefixBitLength> -const T* MultiLookupHuffmanTable<T, Subtable, PrefixBitLength>::Iterator:: -operator*() const { - return &position_->value_; +template <typename Subtable, uint8_t PrefixBitLength> +const BinASTSymbol* MultiLookupHuffmanTable< + Subtable, PrefixBitLength>::Iterator::operator*() const { + return &position_->value(); } -template <typename T, typename Subtable, uint8_t PrefixBitLength> -bool MultiLookupHuffmanTable<T, Subtable, PrefixBitLength>::Iterator:: -operator==(const Iterator& other) const { +template <typename Subtable, uint8_t PrefixBitLength> +const BinASTSymbol* MultiLookupHuffmanTable< + Subtable, PrefixBitLength>::Iterator::operator->() const { + return &position_->value(); +} + +template <typename Subtable, uint8_t PrefixBitLength> +bool MultiLookupHuffmanTable<Subtable, PrefixBitLength>::Iterator::operator==( + const Iterator& other) const { return position_ == other.position_; } -template <typename T, typename Subtable, uint8_t PrefixBitLength> -bool MultiLookupHuffmanTable<T, Subtable, PrefixBitLength>::Iterator:: -operator!=(const Iterator& other) const { +template <typename Subtable, uint8_t PrefixBitLength> +bool MultiLookupHuffmanTable<Subtable, PrefixBitLength>::Iterator::operator!=( + const Iterator& other) const { return position_ != other.position_; } -template <typename T, typename Subtable, uint8_t PrefixBitLength> -JS::Result<Ok> MultiLookupHuffmanTable<T, Subtable, PrefixBitLength>::initStart( +template <typename Subtable, uint8_t PrefixBitLength> +JS::Result<Ok> MultiLookupHuffmanTable<Subtable, PrefixBitLength>::initStart( JSContext* cx, size_t numberOfSymbols, uint8_t largestBitLength) { static_assert(PrefixBitLength < MAX_CODE_BIT_LENGTH, "Invalid PrefixBitLength"); MOZ_ASSERT(values_.empty()); // Make sure that we're initializing. MOZ_ASSERT(subTables_.empty()); largestBitLength_ = largestBitLength; if (MOZ_UNLIKELY(!values_.initCapacity(numberOfSymbols))) { return cx->alreadyReportedError(); } if (MOZ_UNLIKELY(!subTables_.initCapacity(1 << PrefixBitLength))) { return cx->alreadyReportedError(); } return Ok(); } -template <typename T, typename Subtable, uint8_t PrefixBitLength> -JS::Result<Ok> MultiLookupHuffmanTable<T, Subtable, PrefixBitLength>::addSymbol( - uint32_t bits, uint8_t bitLength, T&& value) { +template <typename Subtable, uint8_t PrefixBitLength> +JS::Result<Ok> MultiLookupHuffmanTable<Subtable, PrefixBitLength>::addSymbol( + uint32_t bits, uint8_t bitLength, const BinASTSymbol& value) { MOZ_ASSERT_IF(largestBitLength_ != 0, bitLength != 0); - MOZ_ASSERT(values_.empty() || values_.back().key_.bitLength_ <= bitLength, + MOZ_ASSERT(values_.empty() || values_.back().key().bitLength_ <= bitLength, "Symbols must be ranked by increasing bits length"); MOZ_ASSERT_IF(bitLength != 32 /* >> 32 is UB */, bits >> bitLength == 0); - values_.infallibleEmplaceBack(bits, bitLength, std::move(value)); + values_.infallibleEmplaceBack(bits, bitLength, value); return Ok(); } -template <typename T, typename Subtable, uint8_t PrefixBitLength> +template <typename Subtable, uint8_t PrefixBitLength> JS::Result<Ok> -MultiLookupHuffmanTable<T, Subtable, PrefixBitLength>::initComplete() { +MultiLookupHuffmanTable<Subtable, PrefixBitLength>::initComplete() { // First, we need to collect the `largestBitLength_` // and `numberofSymbols` for each subtable. struct Bucket { Bucket() : largestBitLength_(0), numberOfSymbols_(0){}; uint8_t largestBitLength_; uint32_t numberOfSymbols_; }; Vector<Bucket> buckets{cx_}; BINJS_TRY(buckets.resize(1 << PrefixBitLength)); for (const auto& entry : values_) { - const HuffmanLookup lookup(entry.key_.bits_, entry.key_.bitLength_); + const HuffmanLookup lookup(entry.key().bits_, entry.key().bitLength_); const auto split = lookup.split(PrefixBitLength); MOZ_ASSERT_IF(split.suffix_.bitLength_ != 32, split.suffix_.bits_ >> split.suffix_.bitLength_ == 0); // Entries that have a sufficient number of bits will be dispatched // to a single subtable (e.g. A, B, C, D, E, F in the documentation). // Other entries need to be dispatched to several subtables // (e.g. G, H in the documentation). @@ -2205,60 +2184,56 @@ MultiLookupHuffmanTable<T, Subtable, Pre } // Now that the subtables are created, let's dispatch the values // among these tables. for (size_t i = 0; i < values_.length(); ++i) { const auto& entry = values_[i]; // Find the relevant subtables. - const HuffmanLookup lookup(entry.key_.bits_, entry.key_.bitLength_); + const HuffmanLookup lookup(entry.key().bits_, entry.key().bitLength_); const auto split = lookup.split(PrefixBitLength); MOZ_ASSERT_IF(split.suffix_.bitLength_ != 32, split.suffix_.bits_ >> split.suffix_.bitLength_ == 0); for (const auto index : lookup.suffixes(PrefixBitLength)) { auto& sub = subTables_[index]; // We may now add a reference to `entry` into the sybtable. MOZ_TRY(sub.addSymbol(split.suffix_.bits_, split.suffix_.bitLength_, - std::move(i))); + BinASTSymbol::fromSubtableIndex(i))); } } // Finally, complete initialization of subtables. for (auto& sub : subTables_) { MOZ_TRY(sub.initComplete()); } return Ok(); } -template <typename T, typename Subtable, uint8_t PrefixBitLength> -HuffmanEntry<const T*> -MultiLookupHuffmanTable<T, Subtable, PrefixBitLength>::lookup( +template <typename Subtable, uint8_t PrefixBitLength> +HuffmanLookupResult MultiLookupHuffmanTable<Subtable, PrefixBitLength>::lookup( HuffmanLookup key) const { const auto split = key.split(PrefixBitLength); if (split.prefix_.bits_ >= subTables_.length()) { - return HuffmanEntry<const T*>(0, 0, nullptr); + return HuffmanLookupResult::notFound(); } const Subtable& subtable = subTables_[split.prefix_.bits_]; - auto found = subtable.lookup(split.suffix_); - - if (found.value_ == nullptr) { + auto subResult = subtable.lookup(split.suffix_); + if (!subResult.isFound()) { // Propagate "not found". - return {0, 0, nullptr}; + return HuffmanLookupResult::notFound(); } // Otherwise, restore the entire `HuffmanEntry`. - const auto& result = values_[*found.value_]; - - return /* HuffmanEntry */ {/* bits */ result.key_.bits_, - /* bitLength */ result.key_.bitLength_, - /* value */ std::move(&result.value_)}; + const auto& result = values_[subResult.value().toSubtableIndex()]; + + return HuffmanLookupResult::found(result.key().bitLength_, &result.value()); } // ----- // The number of possible interfaces in each sum, indexed by // `static_cast<size_t>(BinASTSum)`. const size_t SUM_LIMITS[]{ #define WITH_SUM(_ENUM_NAME, _HUMAN_NAME, MACRO_NAME, _TYPE_NAME) \ @@ -2345,33 +2320,34 @@ template <> MOZ_MUST_USE JS::Result<uint32_t> HuffmanPreludeReader::readNumberOfSymbols( const Boolean&) { // Sadly, there are only two booleans known to this date. return 2; } // Extract symbol from the grammar. template <> -MOZ_MUST_USE JS::Result<bool> HuffmanPreludeReader::readSymbol(const Boolean&, - size_t index) { +MOZ_MUST_USE JS::Result<BinASTSymbol> HuffmanPreludeReader::readSymbol( + const Boolean&, size_t index) { MOZ_ASSERT(index < 2); - return index != 0; + return BinASTSymbol::fromBool(index != 0); } // Reading a single-value table of booleans template <> MOZ_MUST_USE JS::Result<Ok> HuffmanPreludeReader::readSingleValueTable<Boolean>( Boolean::Table& table, const Boolean& entry) { uint8_t indexByte; MOZ_TRY_VAR(indexByte, reader_.readByte<Compression::No>()); if (MOZ_UNLIKELY(indexByte >= 2)) { return raiseInvalidTableData(entry.identity_); } - MOZ_TRY(table.initWithSingleValue(cx_, indexByte != 0)); + MOZ_TRY( + table.initWithSingleValue(cx_, BinASTSymbol::fromBool(indexByte != 0))); return Ok(); } // ------ Optional interfaces. // 0 -> Null // 1 -> NonNull // Extract the number of symbols from the grammar. @@ -2379,67 +2355,69 @@ template <> MOZ_MUST_USE JS::Result<uint32_t> HuffmanPreludeReader::readNumberOfSymbols( const MaybeInterface&) { // Null, NonNull return 2; } // Extract symbol from the grammar. template <> -MOZ_MUST_USE JS::Result<BinASTKind> HuffmanPreludeReader::readSymbol( +MOZ_MUST_USE JS::Result<BinASTSymbol> HuffmanPreludeReader::readSymbol( const MaybeInterface& entry, size_t index) { MOZ_ASSERT(index < 2); - return index == 0 ? BinASTKind::_Null : entry.kind_; + return BinASTSymbol::fromKind(index == 0 ? BinASTKind::_Null : entry.kind_); } // Reading a single-value table of optional interfaces template <> MOZ_MUST_USE JS::Result<Ok> HuffmanPreludeReader::readSingleValueTable<MaybeInterface>( MaybeInterface::Table& table, const MaybeInterface& entry) { uint8_t indexByte; MOZ_TRY_VAR(indexByte, reader_.readByte<Compression::No>()); if (MOZ_UNLIKELY(indexByte >= 2)) { return raiseInvalidTableData(entry.identity_); } MOZ_TRY(table.initWithSingleValue( - cx_, indexByte == 0 ? BinASTKind::_Null : entry.kind_)); + cx_, BinASTSymbol::fromKind(indexByte == 0 ? BinASTKind::_Null + : entry.kind_))); return Ok(); } // ------ Sums of interfaces // varnum i -> index `i` in the order defined by // `FOR_EACH_BIN_INTERFACE_IN_SUM_*` // Extract the number of symbols from the grammar. template <> MOZ_MUST_USE JS::Result<uint32_t> HuffmanPreludeReader::readNumberOfSymbols( const Sum& sum) { return sum.maxNumberOfSymbols(); } // Extract symbol from the grammar. template <> -MOZ_MUST_USE JS::Result<BinASTKind> HuffmanPreludeReader::readSymbol( +MOZ_MUST_USE JS::Result<BinASTSymbol> HuffmanPreludeReader::readSymbol( const Sum& entry, size_t index) { MOZ_ASSERT(index < entry.maxNumberOfSymbols()); - return entry.interfaceAt(index); + return BinASTSymbol::fromKind(entry.interfaceAt(index)); } // Reading a single-value table of sums of interfaces. template <> MOZ_MUST_USE JS::Result<Ok> HuffmanPreludeReader::readSingleValueTable<Sum>( HuffmanTableIndexedSymbolsSum& table, const Sum& sum) { BINJS_MOZ_TRY_DECL(index, reader_.readVarU32<Compression::No>()); if (MOZ_UNLIKELY(index >= sum.maxNumberOfSymbols())) { return raiseInvalidTableData(sum.identity_); } - MOZ_TRY(table.initWithSingleValue(cx_, sum.interfaceAt(index))); + MOZ_TRY(table.initWithSingleValue( + cx_, BinASTSymbol::fromKind(sum.interfaceAt(index)))); return Ok(); } // ------ Optional sums of interfaces // varnum 0 -> null // varnum i > 0 -> index `i - 1` in the order defined by // `FOR_EACH_BIN_INTERFACE_IN_SUM_*` @@ -2447,33 +2425,34 @@ MOZ_MUST_USE JS::Result<Ok> HuffmanPrelu template <> MOZ_MUST_USE JS::Result<uint32_t> HuffmanPreludeReader::readNumberOfSymbols( const MaybeSum& sum) { return sum.maxNumberOfSymbols(); } // Extract symbol from the grammar. template <> -MOZ_MUST_USE JS::Result<BinASTKind> HuffmanPreludeReader::readSymbol( +MOZ_MUST_USE JS::Result<BinASTSymbol> HuffmanPreludeReader::readSymbol( const MaybeSum& sum, size_t index) { MOZ_ASSERT(index < sum.maxNumberOfSymbols()); - return sum.interfaceAt(index); + return BinASTSymbol::fromKind(sum.interfaceAt(index)); } // Reading a single-value table of sums of interfaces. template <> MOZ_MUST_USE JS::Result<Ok> HuffmanPreludeReader::readSingleValueTable<MaybeSum>( HuffmanTableIndexedSymbolsSum& table, const MaybeSum& sum) { BINJS_MOZ_TRY_DECL(index, reader_.readVarU32<Compression::No>()); if (MOZ_UNLIKELY(index >= sum.maxNumberOfSymbols())) { return raiseInvalidTableData(sum.identity_); } - MOZ_TRY(table.initWithSingleValue(cx_, sum.interfaceAt(index))); + MOZ_TRY(table.initWithSingleValue( + cx_, BinASTSymbol::fromKind(sum.interfaceAt(index)))); return Ok(); } // ------ Numbers // 64 bits, IEEE 754, big endian // Read the number of symbols from the stream. template <> @@ -2483,43 +2462,40 @@ MOZ_MUST_USE JS::Result<uint32_t> Huffma if (MOZ_UNLIKELY(length > MAX_NUMBER_OF_SYMBOLS)) { return raiseInvalidTableData(number.identity_); } return length; } // Read a single symbol from the stream. template <> -MOZ_MUST_USE JS::Result<double> HuffmanPreludeReader::readSymbol( +MOZ_MUST_USE JS::Result<BinASTSymbol> HuffmanPreludeReader::readSymbol( const Number& number, size_t) { uint8_t bytes[8]; MOZ_ASSERT(sizeof(bytes) == sizeof(double)); uint32_t len = mozilla::ArrayLength(bytes); MOZ_TRY((reader_.readBuf<Compression::No, EndOfFilePolicy::RaiseError>( reinterpret_cast<uint8_t*>(bytes), len))); // Decode big-endian. const uint64_t asInt = mozilla::BigEndian::readUint64(bytes); // Canonicalize NaN, just to make sure another form of signalling NaN // doesn't slip past us. - return JS::CanonicalizeNaN(mozilla::BitwiseCast<double>(asInt)); + return BinASTSymbol::fromDouble( + JS::CanonicalizeNaN(mozilla::BitwiseCast<double>(asInt))); } // Reading a single-value table of numbers. template <> MOZ_MUST_USE JS::Result<Ok> HuffmanPreludeReader::readSingleValueTable<Number>( HuffmanTableExplicitSymbolsF64& table, const Number& number) { BINJS_MOZ_TRY_DECL(value, readSymbol(number, 0 /* ignored */)); - // Note: The `std::move` is useless for performance, but necessary to keep - // a consistent API. - MOZ_TRY(table.initWithSingleValue( - cx_, - /* NOLINT(performance-move-const-arg) */ std::move(value))); + MOZ_TRY(table.initWithSingleValue(cx_, value)); return Ok(); } // ------ List lengths // varnum // Read the number of symbols from the grammar. template <> @@ -2529,34 +2505,34 @@ MOZ_MUST_USE JS::Result<uint32_t> Huffma if (MOZ_UNLIKELY(length > MAX_NUMBER_OF_SYMBOLS)) { return raiseInvalidTableData(list.identity_); } return length; } // Read a single symbol from the stream. template <> -MOZ_MUST_USE JS::Result<uint32_t> HuffmanPreludeReader::readSymbol( +MOZ_MUST_USE JS::Result<BinASTSymbol> HuffmanPreludeReader::readSymbol( const List& list, size_t) { BINJS_MOZ_TRY_DECL(length, reader_.readUnpackedLong()); if (MOZ_UNLIKELY(length > MAX_LIST_LENGTH)) { return raiseInvalidTableData(list.identity_); } - return length; + return BinASTSymbol::fromListLength(length); } // Reading a single-value table of list lengths. template <> MOZ_MUST_USE JS::Result<Ok> HuffmanPreludeReader::readSingleValueTable<List>( HuffmanTableExplicitSymbolsListLength& table, const List& list) { BINJS_MOZ_TRY_DECL(length, reader_.readUnpackedLong()); if (MOZ_UNLIKELY(length > MAX_LIST_LENGTH)) { return raiseInvalidTableData(list.identity_); } - MOZ_TRY(table.initWithSingleValue(cx_, std::move(length))); + MOZ_TRY(table.initWithSingleValue(cx_, BinASTSymbol::fromListLength(length))); return Ok(); } // ------ Strings, non-nullable // varnum (index) // Read the number of symbols from the stream. template <> @@ -2567,39 +2543,35 @@ MOZ_MUST_USE JS::Result<uint32_t> Huffma length > reader_.metadata_->numStrings())) { return raiseInvalidTableData(string.identity_); } return length; } // Read a single symbol from the stream. template <> -MOZ_MUST_USE JS::Result<JSAtom*> HuffmanPreludeReader::readSymbol( +MOZ_MUST_USE JS::Result<BinASTSymbol> HuffmanPreludeReader::readSymbol( const String& entry, size_t) { BINJS_MOZ_TRY_DECL(index, reader_.readVarU32<Compression::No>()); if (MOZ_UNLIKELY(index > reader_.metadata_->numStrings())) { return raiseInvalidTableData(entry.identity_); } - return reader_.metadata_->getAtom(index); + return BinASTSymbol::fromAtom(reader_.metadata_->getAtom(index)); } // Reading a single-value table of string indices. template <> MOZ_MUST_USE JS::Result<Ok> HuffmanPreludeReader::readSingleValueTable<String>( HuffmanTableIndexedSymbolsLiteralString& table, const String& entry) { BINJS_MOZ_TRY_DECL(index, reader_.readVarU32<Compression::No>()); if (MOZ_UNLIKELY(index > reader_.metadata_->numStrings())) { return raiseInvalidTableData(entry.identity_); } - // Note: The `std::move` is useless for performance, but necessary to keep - // a consistent API. JSAtom* value = reader_.metadata_->getAtom(index); - MOZ_TRY(table.initWithSingleValue( - cx_, - /* NOLINT(performance-move-const-arg) */ std::move(value))); + MOZ_TRY(table.initWithSingleValue(cx_, BinASTSymbol::fromAtom(value))); return Ok(); } // ------ Optional strings // varnum 0 -> null // varnum i > 0 -> string at index i - 1 // Read the number of symbols from the metadata. @@ -2611,80 +2583,72 @@ MOZ_MUST_USE JS::Result<uint32_t> Huffma length > reader_.metadata_->numStrings() + 1)) { return raiseInvalidTableData(entry.identity_); } return length; } // Read a single symbol from the stream. template <> -MOZ_MUST_USE JS::Result<JSAtom*> HuffmanPreludeReader::readSymbol( +MOZ_MUST_USE JS::Result<BinASTSymbol> HuffmanPreludeReader::readSymbol( const MaybeString& entry, size_t) { BINJS_MOZ_TRY_DECL(index, reader_.readVarU32<Compression::No>()); if (index == 0) { - return nullptr; + return BinASTSymbol::fromAtom(nullptr); } if (MOZ_UNLIKELY(index > reader_.metadata_->numStrings() + 1)) { return raiseInvalidTableData(entry.identity_); } - return reader_.metadata_->getAtom(index - 1); + return BinASTSymbol::fromAtom(reader_.metadata_->getAtom(index - 1)); } // Reading a single-value table of string indices. template <> MOZ_MUST_USE JS::Result<Ok> HuffmanPreludeReader::readSingleValueTable<MaybeString>( HuffmanTableIndexedSymbolsOptionalLiteralString& table, const MaybeString& entry) { BINJS_MOZ_TRY_DECL(index, reader_.readVarU32<Compression::No>()); if (MOZ_UNLIKELY(index > reader_.metadata_->numStrings() + 1)) { return raiseInvalidTableData(entry.identity_); } JSAtom* symbol = index == 0 ? nullptr : reader_.metadata_->getAtom(index - 1); - // Note: The `std::move` is useless for performance, but necessary to keep - // a consistent API. - MOZ_TRY(table.initWithSingleValue( - cx_, - /* NOLINT(performance-move-const-arg) */ std::move(symbol))); + MOZ_TRY(table.initWithSingleValue(cx_, BinASTSymbol::fromAtom(symbol))); return Ok(); } // ------ String Enums // varnum index in the enum // Read the number of symbols from the grammar. template <> MOZ_MUST_USE JS::Result<uint32_t> HuffmanPreludeReader::readNumberOfSymbols( const StringEnum& entry) { return entry.maxNumberOfSymbols(); } // Read a single symbol from the grammar. template <> -MOZ_MUST_USE JS::Result<BinASTVariant> HuffmanPreludeReader::readSymbol( +MOZ_MUST_USE JS::Result<BinASTSymbol> HuffmanPreludeReader::readSymbol( const StringEnum& entry, size_t index) { - return entry.variantAt(index); + return BinASTSymbol::fromVariant(entry.variantAt(index)); } // Reading a single-value table of string indices. template <> MOZ_MUST_USE JS::Result<Ok> HuffmanPreludeReader::readSingleValueTable<StringEnum>( HuffmanTableIndexedSymbolsStringEnum& table, const StringEnum& entry) { BINJS_MOZ_TRY_DECL(index, reader_.readVarU32<Compression::No>()); if (MOZ_UNLIKELY(index > entry.maxNumberOfSymbols())) { return raiseInvalidTableData(entry.identity_); } BinASTVariant symbol = entry.variantAt(index); - // Note: The `std::move` is useless for performance, but necessary to keep - // a consistent API. - MOZ_TRY(table.initWithSingleValue( - cx_, - /* NOLINT(performance-move-const-arg) */ std::move(symbol))); + MOZ_TRY(table.initWithSingleValue(cx_, BinASTSymbol::fromVariant(symbol))); return Ok(); } // ------ Unsigned Longs // Unpacked 32-bit // Read the number of symbols from the stream. template <> @@ -2694,32 +2658,30 @@ MOZ_MUST_USE JS::Result<uint32_t> Huffma if (MOZ_UNLIKELY(length > MAX_NUMBER_OF_SYMBOLS)) { return raiseInvalidTableData(entry.identity_); } return length; } // Read a single symbol from the stream. template <> -MOZ_MUST_USE JS::Result<uint32_t> HuffmanPreludeReader::readSymbol( +MOZ_MUST_USE JS::Result<BinASTSymbol> HuffmanPreludeReader::readSymbol( const UnsignedLong& entry, size_t) { - return reader_.readUnpackedLong(); + BINJS_MOZ_TRY_DECL(result, reader_.readUnpackedLong()); + return BinASTSymbol::fromUnsignedLong(result); } // Reading a single-value table of string indices. template <> MOZ_MUST_USE JS::Result<Ok> HuffmanPreludeReader::readSingleValueTable<UnsignedLong>( HuffmanTableExplicitSymbolsU32& table, const UnsignedLong& entry) { BINJS_MOZ_TRY_DECL(index, reader_.readUnpackedLong()); - // Note: The `std::move` is useless for performance, but necessary to keep - // a consistent API. - MOZ_TRY(table.initWithSingleValue( - cx_, - /* NOLINT(performance-move-const-arg) */ std::move(index))); + MOZ_TRY( + table.initWithSingleValue(cx_, BinASTSymbol::fromUnsignedLong(index))); return Ok(); } HuffmanDictionary::HuffmanDictionary(JSContext* cx) : fields_(BINAST_PARAM_NUMBER_OF_INTERFACE_AND_FIELD( mozilla::AsVariant(HuffmanTableUnreachable()))), listLengths_(BINAST_PARAM_NUMBER_OF_LIST_TYPES( mozilla::AsVariant(HuffmanTableUnreachable()))) {}
--- a/js/src/frontend/BinASTTokenReaderContext.h +++ b/js/src/frontend/BinASTTokenReaderContext.h @@ -151,25 +151,106 @@ struct HuffmanKey { // The actual length of buffer `bits_`. // // MUST be within `[0, 32]`. // // If `bitLength_ < 32`, it means that some of the highest bits are unused. const uint8_t bitLength_; }; +// Symbol appears in the table. +// This class is used to store symbols in `*HuffmanTable` classes without having +// multiple implementation or different generated code for each type. +// +// This class doesn't store any tag to determine which kind of symbol it is. +// The consumer MUST use the correct `from*`/`to*` pair. +class alignas(8) BinASTSymbol { + private: + uint64_t asBits_; + + explicit BinASTSymbol(uint64_t asBits) : asBits_(asBits) {} + + static BinASTSymbol fromRawBits(uint64_t asBits) { + return BinASTSymbol(asBits); + } + + public: + static BinASTSymbol fromUnsignedLong(uint32_t i) { return fromRawBits(i); } + static BinASTSymbol fromListLength(uint32_t i) { return fromRawBits(i); } + static BinASTSymbol fromSubtableIndex(size_t i) { return fromRawBits(i); } + static BinASTSymbol fromBool(bool b) { return fromRawBits(b); } + static BinASTSymbol fromDouble(double d) { + return fromRawBits(mozilla::BitwiseCast<uint64_t>(d)); + } + static BinASTSymbol fromKind(BinASTKind k) { + return fromRawBits(uint64_t(k)); + } + static BinASTSymbol fromVariant(BinASTVariant v) { + return fromRawBits(uint64_t(v)); + } + static BinASTSymbol fromAtom(JSAtom* v) { + return fromRawBits(reinterpret_cast<uint64_t>(v)); + } + + uint32_t toUnsignedLong() const { return uint32_t(asBits_); } + uint32_t toListLength() const { return uint32_t(asBits_); } + size_t toSubtableIndex() const { return size_t(asBits_); } + bool toBool() const { return bool(asBits_); } + double toDouble() const { return mozilla::BitwiseCast<double>(asBits_); } + BinASTKind toKind() const { return BinASTKind(asBits_); } + BinASTVariant toVariant() const { return BinASTVariant(asBits_); } + JSAtom* toAtom() const { return reinterpret_cast<JSAtom*>(asBits_); } +}; + // An entry in a Huffman table. -template <typename T> -struct HuffmanEntry { - HuffmanEntry(HuffmanKey key, T&& value) : key_(key), value_(value) {} - HuffmanEntry(uint32_t bits, uint8_t bitLength, T&& value) +class HuffmanEntry { + const HuffmanKey key_; + const BinASTSymbol value_; + + public: + HuffmanEntry(HuffmanKey key, const BinASTSymbol& value) + : key_(key), value_(value) {} + + HuffmanEntry(uint32_t bits, uint8_t bitLength, const BinASTSymbol& value) : key_(bits, bitLength), value_(value) {} - const HuffmanKey key_; - const T value_; + const HuffmanKey& key() const { return key_; }; + const BinASTSymbol& value() const { return value_; }; +}; + +// The result of lookup in Huffman table. +class HuffmanLookupResult { + uint8_t bitLength_; + const BinASTSymbol* value_; + + HuffmanLookupResult(uint8_t bitLength, const BinASTSymbol* value) + : bitLength_(bitLength), value_(value) {} + + public: + static HuffmanLookupResult found(uint8_t bitLength, + const BinASTSymbol* value) { + MOZ_ASSERT(value); + return HuffmanLookupResult(bitLength, value); + } + + static HuffmanLookupResult notFound() { + return HuffmanLookupResult(0, nullptr); + } + + bool isFound() const { return !!value_; }; + + uint8_t bitLength() const { + MOZ_ASSERT(isFound()); + return bitLength_; + } + + const BinASTSymbol& value() const { + MOZ_ASSERT(isFound()); + return *value_; + } }; // The default inline buffer length for instances of HuffmanTableValue. // Specific type (e.g. booleans) will override this to provide something // more suited to their type. const size_t HUFFMAN_TABLE_DEFAULT_INLINE_BUFFER_LENGTH = 8; // A flag that determines only whether a value is `null`. @@ -177,102 +258,103 @@ const size_t HUFFMAN_TABLE_DEFAULT_INLIN enum class Nullable { Null, NonNull, }; // An implementation of Huffman Tables as a vector, with `O(entries)` // lookup. Performance-wise, this implementation only makes sense for // very short tables. -template <typename T, int N = HUFFMAN_TABLE_DEFAULT_INLINE_BUFFER_LENGTH> +template <int N = HUFFMAN_TABLE_DEFAULT_INLINE_BUFFER_LENGTH> class NaiveHuffmanTable { public: explicit NaiveHuffmanTable(JSContext* cx) : values_(cx) {} NaiveHuffmanTable(NaiveHuffmanTable&& other) noexcept : values_(std::move(other.values_)) {} // Initialize a Huffman table containing a single value. - JS::Result<Ok> initWithSingleValue(JSContext* cx, T&& value); + JS::Result<Ok> initWithSingleValue(JSContext* cx, const BinASTSymbol& value); // Initialize a Huffman table containing `numberOfSymbols`. // Symbols must be added with `addSymbol`. // If you initialize with `initStart`, you MUST call `initComplete()` // at the end of initialization. JS::Result<Ok> initStart(JSContext* cx, size_t numberOfSymbols, uint8_t maxBitLength); JS::Result<Ok> initComplete(); // Add a symbol to a value. - JS::Result<Ok> addSymbol(uint32_t bits, uint8_t bitLength, T&& value); + JS::Result<Ok> addSymbol(uint32_t bits, uint8_t bitLength, + const BinASTSymbol& value); NaiveHuffmanTable() = delete; NaiveHuffmanTable(NaiveHuffmanTable&) = delete; // Lookup a value in the table. // // The return of this method contains: // // - the resulting value (`nullptr` if the value is not in the table); // - the number of bits in the entry associated to this value. // // Note that entries inside a single table are typically associated to // distinct bit lengths. The caller is responsible for checking // the result of this method and advancing the bitstream by - // `result.key_.bitLength_` bits. - HuffmanEntry<const T*> lookup(HuffmanLookup lookup) const; + // `result.key().bitLength_` bits. + HuffmanLookupResult lookup(HuffmanLookup key) const; // The number of values in the table. size_t length() const { return values_.length(); } - const HuffmanEntry<T>* begin() const { return values_.begin(); } - const HuffmanEntry<T>* end() const { return values_.end(); } + const HuffmanEntry* begin() const { return values_.begin(); } + const HuffmanEntry* end() const { return values_.end(); } private: // The entries in this Huffman table. // Entries are always ranked by increasing bit_length, and within // a bitlength by increasing value of `bits`. This representation // is good for small tables, but in the future, we may adopt a // representation more optimized for larger tables. - Vector<HuffmanEntry<T>, N> values_; + Vector<HuffmanEntry, N> values_; friend class HuffmanPreludeReader; }; // An implementation of Huffman Tables for single-entry table. -template <typename T> class SingleEntryHuffmanTable { public: - explicit SingleEntryHuffmanTable(T&& value) : value_(std::move(value)) {} + explicit SingleEntryHuffmanTable(const BinASTSymbol& value) : value_(value) {} SingleEntryHuffmanTable(SingleEntryHuffmanTable&& other) = default; SingleEntryHuffmanTable() = delete; SingleEntryHuffmanTable(SingleEntryHuffmanTable&) = delete; // Lookup a value in the table. // The key is 0-bit length and this always suceeds. - HuffmanEntry<const T*> lookup(HuffmanLookup key) const; + HuffmanLookupResult lookup(HuffmanLookup key) const; // The number of values in the table. size_t length() const { return 1; } // Iterating in the order of insertion. struct Iterator { - explicit Iterator(const T* position); + explicit Iterator(const BinASTSymbol* position); void operator++(); - const T* operator*() const; + const BinASTSymbol* operator*() const; + const BinASTSymbol* operator->() const; bool operator==(const Iterator& other) const; bool operator!=(const Iterator& other) const; private: - const T* position_; + const BinASTSymbol* position_; }; Iterator begin() const { return Iterator(&value_); } Iterator end() const { return Iterator(nullptr); } private: - T value_; + BinASTSymbol value_; friend class HuffmanPreludeReader; }; // An implementation of Huffman Tables as a vector designed to allow // constant-time lookups at the expense of high space complexity. // // # Time complexity @@ -339,17 +421,16 @@ class SingleEntryHuffmanTable { // // By using the next 5 bits in the bit buffer, we may, in // a single lookup, determine the symbol and the bit length. // // In the current implementation, to save some space, we have // two distinct arrays, one (`values_`) with a single instance of each // symbols bit length, and one (`saturated_`) with indices into that // array. -template <typename T> class SingleLookupHuffmanTable { public: // An index into table `values_`. // We use `uint8_t` instead of `size_t` to limit the space // used by the table. using InternalIndex = uint8_t; // The largest bit length that may be represented by this table. @@ -364,58 +445,60 @@ class SingleLookupHuffmanTable { // If you initialize with `initStart`, you MUST call `initComplete()` // at the end of initialization. JS::Result<Ok> initStart(JSContext* cx, size_t numberOfSymbols, uint8_t maxBitLength); JS::Result<Ok> initComplete(); // Add a `(bit, bitLength) => value` mapping. - JS::Result<Ok> addSymbol(uint32_t bits, uint8_t bitLength, T&& value); + JS::Result<Ok> addSymbol(uint32_t bits, uint8_t bitLength, + const BinASTSymbol& value); SingleLookupHuffmanTable() = delete; SingleLookupHuffmanTable(SingleLookupHuffmanTable&) = delete; // Lookup a value in the table. // // The return of this method contains: // // - the resulting value (`nullptr` if the value is not in the table); // - the number of bits in the entry associated to this value. // // Note that entries inside a single table are typically associated to // distinct bit lengths. The caller is responsible for checking // the result of this method and advancing the bitstream by - // `result.key_.bitLength_` bits. - HuffmanEntry<const T*> lookup(HuffmanLookup key) const; + // `result.key().bitLength_` bits. + HuffmanLookupResult lookup(HuffmanLookup key) const; // The number of values in the table. size_t length() const { return values_.length(); } // Iterating in the order of insertion. struct Iterator { - explicit Iterator(const HuffmanEntry<T>* position); + explicit Iterator(const HuffmanEntry* position); void operator++(); - const T* operator*() const; + const BinASTSymbol* operator*() const; + const BinASTSymbol* operator->() const; bool operator==(const Iterator& other) const; bool operator!=(const Iterator& other) const; private: - const HuffmanEntry<T>* position_; + const HuffmanEntry* position_; }; Iterator begin() const { return Iterator(values_.begin()); } Iterator end() const { return Iterator(values_.end()); } private: // The entries in this Huffman Table, sorted in the order of insertion. // // Invariant (once `init*` has been called): // - Length is the number of values inserted in the table. // - for all i, `values_[i].bitLength_ <= largestBitLength_`. - Vector<HuffmanEntry<T>> values_; + Vector<HuffmanEntry> values_; // The entries in this Huffman table, prepared for lookup. // // Invariant (once `init*` has been called): // - Length is `1 << largestBitLength_`. // - for all i, `saturated_[i] < values_.length()` Vector<InternalIndex> saturated_; @@ -541,17 +624,17 @@ class SingleLookupHuffmanTable { /// - 7 tables with a max bit length of 0. /// /// Consequently, instead of storing 2^5 = 32 internal references, /// as we would have done with a SingleLookupHuffmanTable, we only /// need to store: /// /// - 7 subtables with 1 reference each; /// - 1 subtable with 2^2 = 4 references. -template <typename T, typename Subtable, uint8_t PrefixBitLength> +template <typename Subtable, uint8_t PrefixBitLength> class MultiLookupHuffmanTable { public: // The largest bit length that may be represented by this table. static const uint8_t MAX_BIT_LENGTH = PrefixBitLength + Subtable::MAX_BIT_LENGTH; explicit MultiLookupHuffmanTable(JSContext* cx) : cx_(cx), values_(cx), subTables_(cx), largestBitLength_(-1) {} @@ -562,47 +645,49 @@ class MultiLookupHuffmanTable { // If you initialize with `initStart`, you MUST call `initComplete()` // at the end of initialization. JS::Result<Ok> initStart(JSContext* cx, size_t numberOfSymbols, uint8_t largestBitLength); JS::Result<Ok> initComplete(); // Add a `(bit, bitLength) => value` mapping. - JS::Result<Ok> addSymbol(uint32_t bits, uint8_t bitLength, T&& value); + JS::Result<Ok> addSymbol(uint32_t bits, uint8_t bitLength, + const BinASTSymbol& value); MultiLookupHuffmanTable() = delete; MultiLookupHuffmanTable(MultiLookupHuffmanTable&) = delete; // Lookup a value in the table. // // The return of this method contains: // // - the resulting value (`nullptr` if the value is not in the table); // - the number of bits in the entry associated to this value. // // Note that entries inside a single table are typically associated to // distinct bit lengths. The caller is responsible for checking // the result of this method and advancing the bitstream by - // `result.key_.bitLength_` bits. - HuffmanEntry<const T*> lookup(HuffmanLookup key) const; + // `result.key().bitLength_` bits. + HuffmanLookupResult lookup(HuffmanLookup key) const; // The number of values in the table. size_t length() const { return values_.length(); } // Iterating in the order of insertion. struct Iterator { - explicit Iterator(const HuffmanEntry<T>* position); + explicit Iterator(const HuffmanEntry* position); void operator++(); - const T* operator*() const; + const BinASTSymbol* operator*() const; + const BinASTSymbol* operator->() const; bool operator==(const Iterator& other) const; bool operator!=(const Iterator& other) const; private: - const HuffmanEntry<T>* position_; + const HuffmanEntry* position_; }; Iterator begin() const { return Iterator(values_.begin()); } Iterator end() const { return Iterator(values_.end()); } public: // An index into table `values_`. // We use `uint8_t` instead of `size_t` to limit the space // used by the table. @@ -614,17 +699,17 @@ class MultiLookupHuffmanTable { // The entries in this Huffman Table, sorted in the order of insertion. // // Invariant (once `init*` has been called): // - Length is the number of values inserted in the table. // - for all i, `values_[i].bitLength_ <= largestBitLength_`. // // FIXME: In a ThreeLookupsHuffmanTable, we currently store each value // three times. We could at least get down to twice. - Vector<HuffmanEntry<T>> values_; + Vector<HuffmanEntry> values_; // A mapping from 0..2^prefixBitLen such that index `i` // maps to a subtable that holds all values associated // with a key that starts with `HuffmanKey(i, prefixBitLen)`. // // Note that, to allow the use of smaller tables, keys // inside the subtables have been stripped // from the prefix `HuffmanKey(i, prefixBitLen)`. @@ -635,76 +720,75 @@ class MultiLookupHuffmanTable { // Invariant (once `init*` has been called): // - `largestBitLength_ <= MAX_CODE_BIT_LENGTH` uint8_t largestBitLength_; friend class HuffmanPreludeReader; }; /// A Huffman table suitable for max bit lengths in [8, 14] -template <typename T> -using TwoLookupsHuffmanTable = MultiLookupHuffmanTable< - T, SingleLookupHuffmanTable</* external index */ size_t>, 6>; +using TwoLookupsHuffmanTable = + MultiLookupHuffmanTable<SingleLookupHuffmanTable, 6>; /// A Huffman table suitable for max bit lengths in [15, 20] -template <typename T> -using ThreeLookupsHuffmanTable = MultiLookupHuffmanTable< - T, TwoLookupsHuffmanTable</* external index */ size_t>, 6>; +using ThreeLookupsHuffmanTable = + MultiLookupHuffmanTable<TwoLookupsHuffmanTable, 6>; // An empty Huffman table. Attempting to get a value from this table is a syntax // error. This is the default value for `HuffmanTableValue` and represents all // states that may not be reached. // // Part of variants `HuffmanTableValue`, `HuffmanTableListLength` and // `GenericHuffmanTable::implementation`. struct HuffmanTableUnreachable {}; // Generic implementation of Huffman tables. // // -template <typename T> struct GenericHuffmanTable { explicit GenericHuffmanTable(JSContext* cx); explicit GenericHuffmanTable() = delete; // Initialize a Huffman table containing a single value. - JS::Result<Ok> initWithSingleValue(JSContext* cx, T&& value); + JS::Result<Ok> initWithSingleValue(JSContext* cx, const BinASTSymbol& value); // Initialize a Huffman table containing `numberOfSymbols`. // Symbols must be added with `addSymbol`. // If you initialize with `initStart`, you MUST call `initComplete()` // at the end of initialization. JS::Result<Ok> initStart(JSContext* cx, size_t numberOfSymbols, uint8_t maxBitLength); // Add a `(bit, bitLength) => value` mapping. - JS::Result<Ok> addSymbol(uint32_t bits, uint8_t bitLength, T&& value); + JS::Result<Ok> addSymbol(uint32_t bits, uint8_t bitLength, + const BinASTSymbol& value); JS::Result<Ok> initComplete(); // The number of values in the table. size_t length() const; struct Iterator { - explicit Iterator(typename SingleEntryHuffmanTable<T>::Iterator&&); - explicit Iterator(typename SingleLookupHuffmanTable<T>::Iterator&&); - explicit Iterator(typename TwoLookupsHuffmanTable<T>::Iterator&&); - explicit Iterator(typename ThreeLookupsHuffmanTable<T>::Iterator&&); + explicit Iterator(typename SingleEntryHuffmanTable::Iterator&&); + explicit Iterator(typename SingleLookupHuffmanTable::Iterator&&); + explicit Iterator(typename TwoLookupsHuffmanTable::Iterator&&); + explicit Iterator(typename ThreeLookupsHuffmanTable::Iterator&&); Iterator(Iterator&&) = default; Iterator(const Iterator&) = default; void operator++(); - const T* operator*() const; + const BinASTSymbol* operator*() const; + const BinASTSymbol* operator->() const; bool operator==(const Iterator& other) const; bool operator!=(const Iterator& other) const; private: - mozilla::Variant<typename SingleEntryHuffmanTable<T>::Iterator, - typename SingleLookupHuffmanTable<T>::Iterator, - typename TwoLookupsHuffmanTable<T>::Iterator, - typename ThreeLookupsHuffmanTable<T>::Iterator> + mozilla::Variant<typename SingleEntryHuffmanTable::Iterator, + typename SingleLookupHuffmanTable::Iterator, + typename TwoLookupsHuffmanTable::Iterator, + typename ThreeLookupsHuffmanTable::Iterator> implementation_; }; // Iterating in the order of insertion. Iterator begin() const; Iterator end() const; // Lookup a value in the table. @@ -712,115 +796,103 @@ struct GenericHuffmanTable { // The return of this method contains: // // - the resulting value (`nullptr` if the value is not in the table); // - the number of bits in the entry associated to this value. // // Note that entries inside a single table are typically associated to // distinct bit lengths. The caller is responsible for checking // the result of this method and advancing the bitstream by - // `result.key_.bitLength_` bits. - HuffmanEntry<const T*> lookup(HuffmanLookup key) const; + // `result.key().bitLength_` bits. + HuffmanLookupResult lookup(HuffmanLookup key) const; private: - mozilla::Variant<SingleEntryHuffmanTable<T>, SingleLookupHuffmanTable<T>, - TwoLookupsHuffmanTable<T>, ThreeLookupsHuffmanTable<T>, + mozilla::Variant<SingleEntryHuffmanTable, SingleLookupHuffmanTable, + TwoLookupsHuffmanTable, ThreeLookupsHuffmanTable, HuffmanTableUnreachable> implementation_; }; // While reading the Huffman prelude, whenever we first encounter a // `HuffmanTableUnreachable`, we replace it with a `HuffmanTableInitializing` // to mark that we should not attempt to read/initialize it again. // // Attempting to get a value from this table is an internal error. // // Part of variants `HuffmanTableValue` and `HuffmanTableListLength`. struct HuffmanTableInitializing {}; // These classes are all parts of variant `HuffmanTableValue`. -struct HuffmanTableExplicitSymbolsF64 : GenericHuffmanTable<double> { - using Contents = double; +struct HuffmanTableExplicitSymbolsF64 : GenericHuffmanTable { explicit HuffmanTableExplicitSymbolsF64(JSContext* cx) : GenericHuffmanTable(cx) {} }; -struct HuffmanTableExplicitSymbolsU32 : GenericHuffmanTable<uint32_t> { - using Contents = uint32_t; +struct HuffmanTableExplicitSymbolsU32 : GenericHuffmanTable { explicit HuffmanTableExplicitSymbolsU32(JSContext* cx) : GenericHuffmanTable(cx) {} }; -struct HuffmanTableIndexedSymbolsSum : GenericHuffmanTable<BinASTKind> { - using Contents = BinASTKind; +struct HuffmanTableIndexedSymbolsSum : GenericHuffmanTable { explicit HuffmanTableIndexedSymbolsSum(JSContext* cx) : GenericHuffmanTable(cx) {} }; -struct HuffmanTableIndexedSymbolsBool : NaiveHuffmanTable<bool, 2> { - using Contents = bool; +struct HuffmanTableIndexedSymbolsBool : NaiveHuffmanTable<2> { explicit HuffmanTableIndexedSymbolsBool(JSContext* cx) : NaiveHuffmanTable(cx) {} }; // A Huffman table that may only ever contain two values: // `BinASTKind::_Null` and another `BinASTKind`. -struct HuffmanTableIndexedSymbolsMaybeInterface - : NaiveHuffmanTable<BinASTKind, 2> { - using Contents = BinASTKind; +struct HuffmanTableIndexedSymbolsMaybeInterface : NaiveHuffmanTable<2> { explicit HuffmanTableIndexedSymbolsMaybeInterface(JSContext* cx) : NaiveHuffmanTable(cx) {} // `true` if this table only contains values for `null`. bool isAlwaysNull() const { MOZ_ASSERT(length() > 0); // By definition, we have either 1 or 2 values. // By definition, if we have 2 values, one of them is not null. if (length() != 1) { return false; } // Otherwise, check the single value. - return begin()->value_ == BinASTKind::_Null; + return begin()->value().toKind() == BinASTKind::_Null; } }; -struct HuffmanTableIndexedSymbolsStringEnum - : GenericHuffmanTable<BinASTVariant> { - using Contents = BinASTVariant; +struct HuffmanTableIndexedSymbolsStringEnum : GenericHuffmanTable { explicit HuffmanTableIndexedSymbolsStringEnum(JSContext* cx) : GenericHuffmanTable(cx) {} }; -struct HuffmanTableIndexedSymbolsLiteralString : GenericHuffmanTable<JSAtom*> { - using Contents = JSAtom*; +struct HuffmanTableIndexedSymbolsLiteralString : GenericHuffmanTable { explicit HuffmanTableIndexedSymbolsLiteralString(JSContext* cx) : GenericHuffmanTable(cx) {} }; -struct HuffmanTableIndexedSymbolsOptionalLiteralString - : GenericHuffmanTable<JSAtom*> { - using Contents = JSAtom*; +struct HuffmanTableIndexedSymbolsOptionalLiteralString : GenericHuffmanTable { explicit HuffmanTableIndexedSymbolsOptionalLiteralString(JSContext* cx) : GenericHuffmanTable(cx) {} }; // A single Huffman table, used for values. using HuffmanTableValue = mozilla::Variant< HuffmanTableUnreachable, // Default value. HuffmanTableInitializing, HuffmanTableExplicitSymbolsF64, HuffmanTableExplicitSymbolsU32, HuffmanTableIndexedSymbolsSum, HuffmanTableIndexedSymbolsMaybeInterface, HuffmanTableIndexedSymbolsBool, HuffmanTableIndexedSymbolsStringEnum, HuffmanTableIndexedSymbolsLiteralString, HuffmanTableIndexedSymbolsOptionalLiteralString>; -struct HuffmanTableExplicitSymbolsListLength : GenericHuffmanTable<uint32_t> { - using Contents = uint32_t; +struct HuffmanTableExplicitSymbolsListLength : GenericHuffmanTable { explicit HuffmanTableExplicitSymbolsListLength(JSContext* cx) : GenericHuffmanTable(cx) {} }; // A single Huffman table, specialized for list lengths. using HuffmanTableListLength = mozilla::Variant<HuffmanTableUnreachable, // Default value. HuffmanTableInitializing, @@ -1169,17 +1241,17 @@ class MOZ_STACK_CLASS BinASTTokenReaderC MOZ_MUST_USE JS::Result<uint32_t> readUnsignedLong(const FieldContext&); MOZ_MUST_USE JS::Result<uint32_t> readUnpackedLong(); private: MOZ_MUST_USE JS::Result<BinASTKind> readTagFromTable( const BinASTInterfaceAndField&); template <typename Table> - MOZ_MUST_USE JS::Result<typename Table::Contents> readFieldFromTable( + MOZ_MUST_USE JS::Result<BinASTSymbol> readFieldFromTable( const BinASTInterfaceAndField&); /** * Report an "invalid value error". */ MOZ_MUST_USE ErrorResult<JS::Error&> raiseInvalidValue(); /**