diff --git a/js/src/frontend/BinASTTokenReaderContext.cpp b/js/src/frontend/BinASTTokenReaderContext.cpp index dc283b9ba3cf..6c3ef05200ee 100644 --- a/js/src/frontend/BinASTTokenReaderContext.cpp +++ b/js/src/frontend/BinASTTokenReaderContext.cpp @@ -511,8 +511,11 @@ class HuffmanPreludeReader { struct Boolean : EntryBase { // The C++ type of values for this grammar type. using Type = bool; + Boolean(const NormalizedInterfaceAndField identity) : EntryBase(identity) {} - size_t maxMumberOfSymbols() { + + // The max number of symbols in a table for this type. + size_t maxMumberOfSymbols() const { // Sadly, to this day, there are only two known booleans. return 2; } @@ -543,11 +546,18 @@ class HuffmanPreludeReader { // An optional value of a given interface. struct MaybeInterface : EntryBase { + // The C++ type of values for this grammar type. + using Type = Nullable; + // The kind of the interface. const BinASTKind kind; + MaybeInterface(const NormalizedInterfaceAndField identity, BinASTKind kind) : EntryBase(identity), kind(kind) {} + // The max number of symbols in a table for this type. + size_t maxMumberOfSymbols() const { return 2; } + // Utility struct, used in macros to call the constructor as // `MaybeInterface::Maker(kind)(identity)`. struct Maker { @@ -803,9 +813,13 @@ class HuffmanPreludeReader { MOZ_TRY_VAR(headerByte, reader.readByte()); switch (headerByte) { case TableHeader::SingleValue: { - // The table contains a single value. + // Construct in-place. table = {mozilla::VariantType{}, cx_}; - return readSingleValueTable(table.as
(), entry); + auto& tableRef = table.as
(); + + // The table contains a single value. + MOZ_TRY((readSingleValueTable(tableRef, entry))); + return Ok(); } case TableHeader::MultipleValues: { // Table contains multiple values. @@ -814,8 +828,12 @@ class HuffmanPreludeReader { if (numberOfSymbols > entry.maxMumberOfSymbols()) { return raiseInvalidTableData(entry.identity); } - return readMultipleValuesTable(table.as
(), entry, - numberOfSymbols); + // Construct in-place. + table = {mozilla::VariantType
{}, cx_}; + auto& tableRef = table.as
(); + MOZ_TRY((readMultipleValuesTable(tableRef, entry, + numberOfSymbols))); + return Ok(); } case TableHeader::Unreachable: // Table is unreachable, nothing to do. @@ -825,6 +843,15 @@ class HuffmanPreludeReader { } } + // Reading a single boolean. + // 0 -> False + // _ -> True + template <> + MOZ_MUST_USE JS::Result readSymbol() { + BINJS_MOZ_TRY_DECL(symbol, reader.readByte()); + return symbol != 0; + } + // Reading tables of booleans // 0 -> False // _ -> True @@ -842,13 +869,31 @@ class HuffmanPreludeReader { return Ok(); } - // Reading a single boolean. - // 0 -> False - // _ -> True + // Reading a single `Foo?` where `Foo` is an interface. + // 0 -> null + // 1 -> Foo template <> - MOZ_MUST_USE JS::Result readSymbol() { + MOZ_MUST_USE JS::Result readSymbol() { BINJS_MOZ_TRY_DECL(symbol, reader.readByte()); - return symbol != 0; + return symbol == 0 ? Nullable::Null : Nullable::NonNull; + } + + // Reading a table for `Foo?` where `Foo` is an interface. + // 0 -> null + // 1 -> Foo + template <> + MOZ_MUST_USE JS::Result readSingleValueTable< + HuffmanTableIndexedSymbolsMaybeInterface, MaybeInterface>( + HuffmanTableIndexedSymbolsMaybeInterface& table, MaybeInterface entry) { + uint8_t indexByte; + MOZ_TRY_VAR(indexByte, reader.readByte()); + if (indexByte >= 2) { + return raiseInvalidTableData(entry.identity); + } + + MOZ_TRY(table.impl.initWithSingleValue( + cx_, indexByte == 0 ? Nullable::Null : Nullable::NonNull)); + return Ok(); } private: @@ -885,11 +930,26 @@ class HuffmanPreludeReader { return Ok(); } + // Optional Interface. + // Values: [null, non-null]. MOZ_MUST_USE JS::Result operator()(const MaybeInterface& entry) { - // FIXME: Enqueue fields. - // FIXME: Read table. - // FIXME: Initialize table. - MOZ_CRASH("Unimplemented"); + // First, we need a table to determine whether the value is `null`. + MOZ_TRY((owner.readTable(entry))); + + // Then, if the table contains `true`, we need the fields of the + // interface. + // FIXME: readTable could return a reference to the table, eliminating an + // array lookup. + const auto& table = owner.dictionary.tableForField(entry.identity); + if (table.is()) { + return Ok(); + } + const auto& tableRef = + table.as(); + if (!tableRef.isAlwaysNull()) { + owner.pushFields(entry.kind); + } return Ok(); } diff --git a/js/src/frontend/BinASTTokenReaderContext.h b/js/src/frontend/BinASTTokenReaderContext.h index 54a7fd5cfa2c..dcc1e0b553c6 100644 --- a/js/src/frontend/BinASTTokenReaderContext.h +++ b/js/src/frontend/BinASTTokenReaderContext.h @@ -417,8 +417,18 @@ struct HuffmanEntry { const T value; }; +// The default inline buffer length for instances of HuffmanTable. +// 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`. +// Used for optional interface. +enum class Nullable { + Null, + NonNull, +}; + template class HuffmanTableImpl { public: @@ -439,6 +449,10 @@ class HuffmanTableImpl { HuffmanTableImpl() = delete; HuffmanTableImpl(HuffmanTableImpl&) = delete; + size_t length() const { return values.length(); } + 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 @@ -475,6 +489,24 @@ struct HuffmanTableIndexedSymbolsBool { HuffmanTableIndexedSymbolsBool(JSContext* cx) : impl(cx) {} }; +struct HuffmanTableIndexedSymbolsMaybeInterface { + HuffmanTableImpl impl; + HuffmanTableIndexedSymbolsMaybeInterface(JSContext* cx) : impl(cx) {} + + // `true` if this table only contains values for `null`. + bool isAlwaysNull() const { + MOZ_ASSERT(impl.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 (impl.length() != 1) { + return false; + } + // Otherwise, check the single value. + return impl.begin()->value == Nullable::Null; + } +}; + struct HuffmanTableIndexedSymbolsStringEnum { HuffmanTableImpl impl; }; @@ -491,8 +523,8 @@ struct HuffmanTableIndexedSymbolsOptionalLiteralString { using HuffmanTable = mozilla::Variant< HuffmanTableUnreachable, // Default value. HuffmanTableExplicitSymbolsF64, HuffmanTableExplicitSymbolsU32, - HuffmanTableIndexedSymbolsTag, HuffmanTableIndexedSymbolsBool, - HuffmanTableIndexedSymbolsStringEnum, + HuffmanTableIndexedSymbolsTag, HuffmanTableIndexedSymbolsMaybeInterface, + HuffmanTableIndexedSymbolsBool, HuffmanTableIndexedSymbolsStringEnum, HuffmanTableIndexedSymbolsLiteralString, HuffmanTableIndexedSymbolsOptionalLiteralString>;