зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1551473 - Provide utility methods to read brotli stream in BinASTTokenReaderContext. r=Yoric
Differential Revision: https://phabricator.services.mozilla.com/D31212 --HG-- extra : moz-landing-system : lando
This commit is contained in:
Родитель
706c8c7b08
Коммит
b41725bb4f
|
@ -8,7 +8,7 @@
|
||||||
|
|
||||||
#include "mozilla/Result.h" // MOZ_TRY*
|
#include "mozilla/Result.h" // MOZ_TRY*
|
||||||
|
|
||||||
#include <string.h> // memcmp
|
#include <string.h> // memcmp, memmove
|
||||||
|
|
||||||
#include "frontend/BinAST-macros.h" // BINJS_TRY*, BINJS_MOZ_TRY*
|
#include "frontend/BinAST-macros.h" // BINJS_TRY*, BINJS_MOZ_TRY*
|
||||||
#include "vm/JSScript.h" // ScriptSource
|
#include "vm/JSScript.h" // ScriptSource
|
||||||
|
@ -43,6 +43,72 @@ BinASTTokenReaderContext::~BinASTTokenReaderContext() {
|
||||||
if (metadata_ && metadataOwned_ == MetadataOwnership::Owned) {
|
if (metadata_ && metadataOwned_ == MetadataOwnership::Owned) {
|
||||||
UniqueBinASTSourceMetadataPtr ptr(metadata_);
|
UniqueBinASTSourceMetadataPtr ptr(metadata_);
|
||||||
}
|
}
|
||||||
|
if (decoder_) {
|
||||||
|
BrotliDecoderDestroyInstance(decoder_);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <>
|
||||||
|
JS::Result<Ok>
|
||||||
|
BinASTTokenReaderContext::readBuf<BinASTTokenReaderContext::Compression::No>(
|
||||||
|
uint8_t* bytes, uint32_t len) {
|
||||||
|
return Base::readBuf(bytes, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <>
|
||||||
|
JS::Result<Ok>
|
||||||
|
BinASTTokenReaderContext::readBuf<BinASTTokenReaderContext::Compression::Yes>(
|
||||||
|
uint8_t* bytes, uint32_t len) {
|
||||||
|
while (availableDecodedLength() < len) {
|
||||||
|
if (availableDecodedLength()) {
|
||||||
|
memmove(bytes, decodedBufferBegin(), availableDecodedLength());
|
||||||
|
bytes += availableDecodedLength();
|
||||||
|
len -= availableDecodedLength();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isEOF()) {
|
||||||
|
return raiseError("Unexpected end of file");
|
||||||
|
}
|
||||||
|
|
||||||
|
// We have exhausted the in-memory buffer. Start from the beginning.
|
||||||
|
decodedBegin_ = 0;
|
||||||
|
|
||||||
|
size_t inSize = stop_ - current_;
|
||||||
|
size_t outSize = DECODED_BUFFER_SIZE;
|
||||||
|
uint8_t* out = decodedBuffer_;
|
||||||
|
|
||||||
|
BrotliDecoderResult result;
|
||||||
|
result = BrotliDecoderDecompressStream(decoder_, &inSize, ¤t_,
|
||||||
|
&outSize, &out,
|
||||||
|
/* total_out = */ nullptr);
|
||||||
|
if (result == BROTLI_DECODER_RESULT_ERROR) {
|
||||||
|
return raiseError("Failed to decompress brotli stream");
|
||||||
|
}
|
||||||
|
|
||||||
|
decodedEnd_ = out - decodedBuffer_;
|
||||||
|
}
|
||||||
|
|
||||||
|
memmove(bytes, decodedBufferBegin(), len);
|
||||||
|
decodedBegin_ += len;
|
||||||
|
return Ok();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool BinASTTokenReaderContext::isEOF() const {
|
||||||
|
return BrotliDecoderIsFinished(decoder_);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <>
|
||||||
|
JS::Result<uint8_t> BinASTTokenReaderContext::readByte<
|
||||||
|
BinASTTokenReaderContext::Compression::No>() {
|
||||||
|
return Base::readByte();
|
||||||
|
}
|
||||||
|
|
||||||
|
template <>
|
||||||
|
JS::Result<uint8_t> BinASTTokenReaderContext::readByte<
|
||||||
|
BinASTTokenReaderContext::Compression::Yes>() {
|
||||||
|
uint8_t buf;
|
||||||
|
MOZ_TRY(readBuf<Compression::Yes>(&buf, 1));
|
||||||
|
return buf;
|
||||||
}
|
}
|
||||||
|
|
||||||
BinASTSourceMetadata* BinASTTokenReaderContext::takeMetadata() {
|
BinASTSourceMetadata* BinASTTokenReaderContext::takeMetadata() {
|
||||||
|
@ -65,13 +131,20 @@ JS::Result<Ok> BinASTTokenReaderContext::readHeader() {
|
||||||
|
|
||||||
// Read global headers.
|
// Read global headers.
|
||||||
MOZ_TRY(readConst(CX_MAGIC_HEADER));
|
MOZ_TRY(readConst(CX_MAGIC_HEADER));
|
||||||
BINJS_MOZ_TRY_DECL(version, readVarU32());
|
BINJS_MOZ_TRY_DECL(version, readVarU32<Compression::No>());
|
||||||
|
|
||||||
if (version != MAGIC_FORMAT_VERSION) {
|
if (version != MAGIC_FORMAT_VERSION) {
|
||||||
return raiseError("Format version not implemented");
|
return raiseError("Format version not implemented");
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: handle `LinkToSharedDictionary` and remaining things here.
|
decoder_ = BrotliDecoderCreateInstance(/* alloc_func = */ nullptr,
|
||||||
|
/* free_func = */ nullptr,
|
||||||
|
/* opaque = */ nullptr);
|
||||||
|
if (!decoder_) {
|
||||||
|
return raiseError("Failed to create brotli decoder");
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: handle strings and models here.
|
||||||
|
|
||||||
return raiseError("Not Yet Implemented");
|
return raiseError("Not Yet Implemented");
|
||||||
}
|
}
|
||||||
|
@ -169,13 +242,14 @@ JS::Result<Ok> BinASTTokenReaderContext::AutoList::done() {
|
||||||
//
|
//
|
||||||
// Encoded as variable length number.
|
// Encoded as variable length number.
|
||||||
|
|
||||||
MOZ_MUST_USE JS::Result<uint32_t> BinASTTokenReaderContext::readVarU32() {
|
template <BinASTTokenReaderContext::Compression compression>
|
||||||
|
JS::Result<uint32_t> BinASTTokenReaderContext::readVarU32() {
|
||||||
uint32_t result = 0;
|
uint32_t result = 0;
|
||||||
uint32_t shift = 0;
|
uint32_t shift = 0;
|
||||||
while (true) {
|
while (true) {
|
||||||
MOZ_ASSERT(shift < 32);
|
MOZ_ASSERT(shift < 32);
|
||||||
uint32_t byte;
|
uint32_t byte;
|
||||||
MOZ_TRY_VAR(byte, readByte());
|
MOZ_TRY_VAR(byte, readByte<compression>());
|
||||||
|
|
||||||
const uint32_t newResult = result | (byte & 0x7f) << shift;
|
const uint32_t newResult = result | (byte & 0x7f) << shift;
|
||||||
if (newResult < result) {
|
if (newResult < result) {
|
||||||
|
@ -195,6 +269,10 @@ MOZ_MUST_USE JS::Result<uint32_t> BinASTTokenReaderContext::readVarU32() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
JS::Result<uint32_t> BinASTTokenReaderContext::readUnsignedLong(const Context&) {
|
||||||
|
return readVarU32<Compression::Yes>();
|
||||||
|
}
|
||||||
|
|
||||||
BinASTTokenReaderContext::AutoTaggedTuple::AutoTaggedTuple(
|
BinASTTokenReaderContext::AutoTaggedTuple::AutoTaggedTuple(
|
||||||
BinASTTokenReaderContext& reader)
|
BinASTTokenReaderContext& reader)
|
||||||
: AutoBase(reader) {}
|
: AutoBase(reader) {}
|
||||||
|
|
|
@ -12,6 +12,8 @@
|
||||||
|
|
||||||
#include "mozilla/Maybe.h" // mozilla::Maybe
|
#include "mozilla/Maybe.h" // mozilla::Maybe
|
||||||
|
|
||||||
|
#include <brotli/decode.h> // BrotliDecoderState
|
||||||
|
|
||||||
#include <stddef.h> // size_t
|
#include <stddef.h> // size_t
|
||||||
#include <stdint.h> // uint8_t, uint32_t
|
#include <stdint.h> // uint8_t, uint32_t
|
||||||
|
|
||||||
|
@ -48,6 +50,8 @@ class ErrorReporter;
|
||||||
* - the reader does not support lookahead or pushback.
|
* - the reader does not support lookahead or pushback.
|
||||||
*/
|
*/
|
||||||
class MOZ_STACK_CLASS BinASTTokenReaderContext : public BinASTTokenReaderBase {
|
class MOZ_STACK_CLASS BinASTTokenReaderContext : public BinASTTokenReaderBase {
|
||||||
|
using Base = BinASTTokenReaderBase;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
class AutoList;
|
class AutoList;
|
||||||
class AutoTaggedTuple;
|
class AutoTaggedTuple;
|
||||||
|
@ -82,6 +86,51 @@ class MOZ_STACK_CLASS BinASTTokenReaderContext : public BinASTTokenReaderBase {
|
||||||
|
|
||||||
~BinASTTokenReaderContext();
|
~BinASTTokenReaderContext();
|
||||||
|
|
||||||
|
private:
|
||||||
|
// {readByte, readBuf, readVarU32} are implemented both for uncompressed
|
||||||
|
// stream and brotli-compressed stream.
|
||||||
|
//
|
||||||
|
// Uncompressed variant is for reading the magic header, and compressed
|
||||||
|
// variant is for reading the remaining part.
|
||||||
|
//
|
||||||
|
// Once compressed variant is called, the underlying uncompressed stream is
|
||||||
|
// buffered and uncompressed variant cannot be called.
|
||||||
|
enum class Compression { No, Yes };
|
||||||
|
|
||||||
|
// Buffer that holds already brotli-decoded but not yet used data.
|
||||||
|
// decodedBuffer[decodedBegin, decodedEnd) holds the data.
|
||||||
|
static const size_t DECODED_BUFFER_SIZE = 128;
|
||||||
|
uint8_t decodedBuffer_[DECODED_BUFFER_SIZE];
|
||||||
|
size_t decodedBegin_ = 0;
|
||||||
|
size_t decodedEnd_ = 0;
|
||||||
|
|
||||||
|
// The number of already decoded bytes.
|
||||||
|
size_t availableDecodedLength() const { return decodedEnd_ - decodedBegin_; }
|
||||||
|
|
||||||
|
// The beginning of decoded buffer.
|
||||||
|
const uint8_t* decodedBufferBegin() const {
|
||||||
|
return decodedBuffer_ + decodedBegin_;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns true if the brotli stream finished.
|
||||||
|
bool isEOF() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Read a single byte.
|
||||||
|
*/
|
||||||
|
template <Compression compression>
|
||||||
|
MOZ_MUST_USE JS::Result<uint8_t> readByte();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Read several bytes.
|
||||||
|
*
|
||||||
|
* If there is not enough data, or if the tokenizer has previously been
|
||||||
|
* poisoned, return an error.
|
||||||
|
*/
|
||||||
|
template <Compression compression>
|
||||||
|
MOZ_MUST_USE JS::Result<Ok> readBuf(uint8_t* bytes, uint32_t len);
|
||||||
|
|
||||||
|
public:
|
||||||
/**
|
/**
|
||||||
* Read the header of the file.
|
* Read the header of the file.
|
||||||
*/
|
*/
|
||||||
|
@ -196,14 +245,13 @@ class MOZ_STACK_CLASS BinASTTokenReaderContext : public BinASTTokenReaderBase {
|
||||||
/**
|
/**
|
||||||
* Read a single unsigned long.
|
* Read a single unsigned long.
|
||||||
*/
|
*/
|
||||||
MOZ_MUST_USE JS::Result<uint32_t> readUnsignedLong(const Context&) {
|
MOZ_MUST_USE JS::Result<uint32_t> readUnsignedLong(const Context&);
|
||||||
return readVarU32();
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/**
|
/**
|
||||||
* Read a single uint32_t.
|
* Read a single uint32_t.
|
||||||
*/
|
*/
|
||||||
|
template <Compression compression>
|
||||||
MOZ_MUST_USE JS::Result<uint32_t> readVarU32();
|
MOZ_MUST_USE JS::Result<uint32_t> readVarU32();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -219,6 +267,8 @@ class MOZ_STACK_CLASS BinASTTokenReaderContext : public BinASTTokenReaderBase {
|
||||||
|
|
||||||
const uint8_t* posBeforeTree_;
|
const uint8_t* posBeforeTree_;
|
||||||
|
|
||||||
|
BrotliDecoderState* decoder_ = nullptr;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
BinASTTokenReaderContext(const BinASTTokenReaderContext&) = delete;
|
BinASTTokenReaderContext(const BinASTTokenReaderContext&) = delete;
|
||||||
BinASTTokenReaderContext(BinASTTokenReaderContext&&) = delete;
|
BinASTTokenReaderContext(BinASTTokenReaderContext&&) = delete;
|
||||||
|
|
Загрузка…
Ссылка в новой задаче