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>;