Bug 1757833 - Compress Stencil bytecode before writing to cache r=nbp

The SRI hash at the beginning of ScriptLoadRequest::mScriptBytecode is left
uncompressed because ScriptLoader::OnIncrementalData() tries to decode it
as soon as enough data is read (instead of waiting until OnStreamComplete()).

ScriptLoader writes the length of the uncompressed bytecode to the buffer
to make it easy for ScriptLoadHandler to allocate an buffer of the right size
to decompress the bytecode.

These changes are based on the bytecode compression implemented for WASM in
dom/fetch/FetchUtil.cpp.

Differential Revision: https://phabricator.services.mozilla.com/D141524
This commit is contained in:
Bryan Thrall
2022-05-18 21:03:47 +00:00
parent eb35d93ded
commit b528dbd218
2 changed files with 110 additions and 9 deletions

View File

@@ -38,6 +38,15 @@
#include "nsMimeTypes.h"
#include "nsString.h"
#include "nsTArray.h"
#include "zlib.h"
namespace {
// A LengthPrefixType is stored at the start of the compressed optimized
// encoding, allowing the decompressed buffer to be allocated to exactly
// the right size.
using LengthPrefixType = uint32_t;
const unsigned PREFIX_BYTES = sizeof(LengthPrefixType);
} // namespace
namespace mozilla::dom {
@@ -400,6 +409,47 @@ ScriptLoadHandler::OnStreamComplete(nsIIncrementalStreamLoader* aLoader,
}
mRequest->mBytecodeOffset = JS::AlignTranscodingBytecodeOffset(sriLength);
{
Vector<uint8_t>
compressedBytecode; // starts with SRI hash, followed by length
// prefix, then compressed bytecode
compressedBytecode.swap(mRequest->mScriptBytecode);
LengthPrefixType uncompressedLength;
memcpy(&uncompressedLength,
compressedBytecode.begin() + mRequest->mBytecodeOffset,
PREFIX_BYTES);
if (!mRequest->mScriptBytecode.resizeUninitialized(
mRequest->mBytecodeOffset + uncompressedLength)) {
return NS_ERROR_OUT_OF_MEMORY;
}
memcpy(mRequest->mScriptBytecode.begin(), compressedBytecode.begin(),
mRequest->mBytecodeOffset); // SRI hash
z_stream zstream{.next_in = compressedBytecode.begin() +
mRequest->mBytecodeOffset + PREFIX_BYTES,
.avail_in = static_cast<uint32_t>(
compressedBytecode.length() -
mRequest->mBytecodeOffset - PREFIX_BYTES),
.next_out = mRequest->mScriptBytecode.begin() +
mRequest->mBytecodeOffset,
.avail_out = uncompressedLength};
if (inflateInit(&zstream) != Z_OK) {
LOG(("ScriptLoadRequest (%p): inflateInit FAILED (%s)",
mRequest.get(), zstream.msg));
return nsresult::NS_ERROR_UNEXPECTED;
}
auto autoDestroy = MakeScopeExit([&]() { inflateEnd(&zstream); });
int ret = inflate(&zstream, Z_NO_FLUSH);
bool ok = (ret == Z_OK || ret == Z_STREAM_END) && zstream.avail_in == 0;
if (!ok) {
LOG(("ScriptLoadRequest (%p): inflate FAILED (%s)", mRequest.get(),
zstream.msg));
return NS_ERROR_UNEXPECTED;
}
}
}
}