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-20 18:25:40 +00:00
parent 827cd45046
commit fc29361ac3
6 changed files with 221 additions and 93 deletions

View File

@@ -8,6 +8,7 @@
#include <stdlib.h>
#include <utility>
#include "ScriptCompression.h"
#include "ScriptLoader.h"
#include "ScriptTrace.h"
#include "js/Transcoding.h"
@@ -40,14 +41,6 @@
#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 {
#undef LOG
@@ -410,45 +403,14 @@ 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;
}
Vector<uint8_t> compressedBytecode;
// mRequest has the compressed bytecode, but will be filled with the
// uncompressed bytecode
compressedBytecode.swap(mRequest->mScriptBytecode);
if (!JS::loader::ScriptBytecodeDecompress(compressedBytecode,
mRequest->mBytecodeOffset,
mRequest->mScriptBytecode)) {
return NS_ERROR_UNEXPECTED;
}
}
}