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:
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user