Bug 1757833 - Extract methods ScriptBytecodeCompress and ScriptBytecodeDecompress r=nbp

This leaves the code in ScriptLoader and ScriptLoadHandler a lot more readable.

ScriptBytecodeCompressedDataLayout and ScriptBytecodeDataLayout simplify
locating data in the ScriptLoadRequest bytecode buffer when compressing and
decompressing it.

The interface is still error-prone. For example, these classes don't check
that the returned pointers are within the bounds of the buffer.

Differential Revision: https://phabricator.services.mozilla.com/D145011
This commit is contained in:
Bryan Thrall
2022-05-18 21:03:48 +00:00
parent b528dbd218
commit 55ed1fd8f6
6 changed files with 221 additions and 93 deletions

View File

@@ -19,6 +19,7 @@
#include "js/ContextOptions.h" // JS::ContextOptionsRef
#include "js/friend/ErrorMessages.h" // js::GetErrorMessage, JSMSG_*
#include "js/loader/ScriptLoadRequest.h"
#include "ScriptCompression.h"
#include "js/loader/LoadedScript.h"
#include "js/loader/ModuleLoadRequest.h"
#include "js/MemoryFunctions.h"
@@ -100,14 +101,6 @@ using namespace JS::loader;
using mozilla::Telemetry::LABELS_DOM_SCRIPT_PRELOAD_RESULT;
namespace { // TODO shared code with ScriptLoadHandler.cpp
// 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 {
LazyLogModule ScriptLoader::gCspPRLog("CSP");
@@ -2563,43 +2556,10 @@ void ScriptLoader::EncodeRequestBytecode(JSContext* aCx,
}
Vector<uint8_t> compressedBytecode;
{
// TODO probably need to move this to a helper thread
LengthPrefixType uncompressedLength =
aRequest->mScriptBytecode.length() - aRequest->mBytecodeOffset;
z_stream zstream{.next_in = aRequest->mScriptBytecode.begin() +
aRequest->mBytecodeOffset,
.avail_in = uncompressedLength};
auto compressedLength = deflateBound(&zstream, uncompressedLength);
if (!compressedBytecode.resizeUninitialized(
compressedLength + aRequest->mBytecodeOffset + PREFIX_BYTES)) {
return;
}
memcpy(compressedBytecode.begin(), aRequest->mScriptBytecode.begin(),
aRequest->mBytecodeOffset);
memcpy(compressedBytecode.begin() + aRequest->mBytecodeOffset,
&uncompressedLength, PREFIX_BYTES);
zstream.next_out =
compressedBytecode.begin() + aRequest->mBytecodeOffset + PREFIX_BYTES;
zstream.avail_out = compressedLength;
const int COMPRESSION = 2; // TODO find appropriate compression level
if (deflateInit(&zstream, COMPRESSION) != Z_OK) {
LOG(
("ScriptLoadRequest (%p): Unable to initialize bytecode cache "
"compression.",
aRequest));
return;
}
auto autoDestroy = MakeScopeExit([&]() { deflateEnd(&zstream); });
int ret = deflate(&zstream, Z_FINISH);
if (ret == Z_MEM_ERROR) {
return;
}
MOZ_RELEASE_ASSERT(ret == Z_STREAM_END);
compressedBytecode.shrinkTo(zstream.next_out - compressedBytecode.begin());
// TODO probably need to move this to a helper thread
if (!ScriptBytecodeCompress(aRequest->mScriptBytecode,
aRequest->mBytecodeOffset, compressedBytecode)) {
return;
}
if (compressedBytecode.length() >= UINT32_MAX) {