Bug 1552435 - Reading Huffman tables of interfaces, optional interfaces;r=arai

Depends on D32725

Differential Revision: https://phabricator.services.mozilla.com/D32807

--HG--
extra : moz-landing-system : lando
This commit is contained in:
David Teller 2019-06-11 10:15:15 +00:00
parent a32e0dc331
commit af2f181932
2 changed files with 108 additions and 16 deletions

View File

@ -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<Table>{}, cx_};
return readSingleValueTable<Table, Entry>(table.as<Table>(), entry);
auto& tableRef = table.as<Table>();
// The table contains a single value.
MOZ_TRY((readSingleValueTable<Table, Entry>(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, Entry>(table.as<Table>(), entry,
numberOfSymbols);
// Construct in-place.
table = {mozilla::VariantType<Table>{}, cx_};
auto& tableRef = table.as<Table>();
MOZ_TRY((readMultipleValuesTable<Table, Entry>(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<bool> readSymbol<Boolean>() {
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<bool> readSymbol<Boolean>() {
MOZ_MUST_USE JS::Result<Nullable> readSymbol<MaybeInterface>() {
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<Ok> 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<Ok> 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<HuffmanTableIndexedSymbolsMaybeInterface,
MaybeInterface>(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<HuffmanTableUnreachable>()) {
return Ok();
}
const auto& tableRef =
table.as<HuffmanTableIndexedSymbolsMaybeInterface>();
if (!tableRef.isAlwaysNull()) {
owner.pushFields(entry.kind);
}
return Ok();
}

View File

@ -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 <typename T, int N = HUFFMAN_TABLE_DEFAULT_INLINE_BUFFER_LENGTH>
class HuffmanTableImpl {
public:
@ -439,6 +449,10 @@ class HuffmanTableImpl {
HuffmanTableImpl() = delete;
HuffmanTableImpl(HuffmanTableImpl&) = delete;
size_t length() const { return values.length(); }
const HuffmanEntry<T>* begin() const { return values.begin(); }
const HuffmanEntry<T>* 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<Nullable, 2> 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<uint8_t> 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>;