Bug 1554362 - Accumulate external source text as either UTF-8 or UTF-16, in pref-controlled fashion, and then compile the accumulated text using corresponding JSAPI entrypoints without inflating UTF-8 to UTF-16. r=bzbarsky

Differential Revision: https://phabricator.services.mozilla.com/D34825
This commit is contained in:
Jeff Walden
2019-06-15 20:48:40 +00:00
parent 9a2fbd4e3e
commit 338aa62605
7 changed files with 237 additions and 92 deletions

View File

@@ -42,6 +42,97 @@ ScriptLoadHandler::~ScriptLoadHandler() {}
NS_IMPL_ISUPPORTS(ScriptLoadHandler, nsIIncrementalStreamLoaderObserver)
template <typename Unit>
struct RawDataDecoding;
template <>
struct RawDataDecoding<char16_t> {
static CheckedInt<size_t> MaxBufferLength(const UniquePtr<Decoder>& aDecoder,
uint32_t aDataLength) {
return aDecoder->MaxUTF16BufferLength(aDataLength);
}
static void PerformDecode(UniquePtr<Decoder>& aDecoder,
Span<const uint8_t> aSrc, Span<char16_t> aDst,
bool aEndOfStream, uint32_t* aResult, size_t* aRead,
size_t* aWritten, bool* aHadErrors) {
Tie(*aResult, *aRead, *aWritten, *aHadErrors) =
aDecoder->DecodeToUTF16(aSrc, aDst, aEndOfStream);
}
};
template <>
struct RawDataDecoding<Utf8Unit> {
static CheckedInt<size_t> MaxBufferLength(const UniquePtr<Decoder>& aDecoder,
uint32_t aDataLength) {
return aDecoder->MaxUTF8BufferLength(aDataLength);
}
static void PerformDecode(UniquePtr<Decoder>& aDecoder,
Span<const uint8_t> aSrc, Span<Utf8Unit> aDst,
bool aEndOfStream, uint32_t* aResult, size_t* aRead,
size_t* aWritten, bool* aHadErrors) {
Tie(*aResult, *aRead, *aWritten, *aHadErrors) =
aDecoder->DecodeToUTF8(aSrc, AsWritableBytes(aDst), aEndOfStream);
}
};
template <typename Unit>
nsresult ScriptLoadHandler::DecodeRawDataHelper(const uint8_t* aData,
uint32_t aDataLength,
bool aEndOfStream) {
using Decoding = RawDataDecoding<Unit>;
CheckedInt<size_t> needed = Decoding::MaxBufferLength(mDecoder, aDataLength);
if (!needed.isValid()) {
return NS_ERROR_OUT_OF_MEMORY;
}
// Reference to the script source buffer which we will update.
ScriptLoadRequest::ScriptTextBuffer<Unit>& scriptText =
mRequest->ScriptText<Unit>();
uint32_t haveRead = scriptText.length();
CheckedInt<uint32_t> capacity = haveRead;
capacity += needed.value();
if (!capacity.isValid() || !scriptText.resize(capacity.value())) {
return NS_ERROR_OUT_OF_MEMORY;
}
uint32_t result;
size_t read;
size_t written;
bool hadErrors;
Decoding::PerformDecode(
mDecoder, MakeSpan(aData, aDataLength),
MakeSpan(scriptText.begin() + haveRead, needed.value()), aEndOfStream,
&result, &read, &written, &hadErrors);
MOZ_ASSERT(result == kInputEmpty);
MOZ_ASSERT(read == aDataLength);
MOZ_ASSERT(written <= needed.value());
Unused << hadErrors;
haveRead += written;
MOZ_ASSERT(haveRead <= capacity.value(),
"mDecoder produced more data than expected");
MOZ_ALWAYS_TRUE(scriptText.resize(haveRead));
mRequest->mScriptTextLength = scriptText.length();
return NS_OK;
}
nsresult ScriptLoadHandler::DecodeRawData(const uint8_t* aData,
uint32_t aDataLength,
bool aEndOfStream) {
if (mRequest->IsUTF16Text()) {
return DecodeRawDataHelper<char16_t>(aData, aDataLength, aEndOfStream);
}
return DecodeRawDataHelper<Utf8Unit>(aData, aDataLength, aEndOfStream);
}
NS_IMETHODIMP
ScriptLoadHandler::OnIncrementalData(nsIIncrementalStreamLoader* aLoader,
nsISupports* aContext,
@@ -107,47 +198,6 @@ ScriptLoadHandler::OnIncrementalData(nsIIncrementalStreamLoader* aLoader,
return rv;
}
nsresult ScriptLoadHandler::DecodeRawData(const uint8_t* aData,
uint32_t aDataLength,
bool aEndOfStream) {
CheckedInt<size_t> needed = mDecoder->MaxUTF16BufferLength(aDataLength);
if (!needed.isValid()) {
return NS_ERROR_OUT_OF_MEMORY;
}
// Reference to the script source buffer which we will update.
ScriptLoadRequest::ScriptTextBuffer& scriptText = mRequest->ScriptText();
uint32_t haveRead = scriptText.length();
CheckedInt<uint32_t> capacity = haveRead;
capacity += needed.value();
if (!capacity.isValid() || !scriptText.resize(capacity.value())) {
return NS_ERROR_OUT_OF_MEMORY;
}
uint32_t result;
size_t read;
size_t written;
bool hadErrors;
Tie(result, read, written, hadErrors) = mDecoder->DecodeToUTF16(
MakeSpan(aData, aDataLength),
MakeSpan(scriptText.begin() + haveRead, needed.value()), aEndOfStream);
MOZ_ASSERT(result == kInputEmpty);
MOZ_ASSERT(read == aDataLength);
MOZ_ASSERT(written <= needed.value());
Unused << hadErrors;
haveRead += written;
MOZ_ASSERT(haveRead <= capacity.value(),
"mDecoder produced more data than expected");
MOZ_ALWAYS_TRUE(scriptText.resize(haveRead));
mRequest->mScriptTextLength = scriptText.length();
return NS_OK;
}
bool ScriptLoadHandler::TrySetDecoder(nsIIncrementalStreamLoader* aLoader,
const uint8_t* aData,
uint32_t aDataLength, bool aEndOfStream) {
@@ -341,8 +391,8 @@ ScriptLoadHandler::OnStreamComplete(nsIIncrementalStreamLoader* aLoader,
rv = DecodeRawData(aData, aDataLength, /* aEndOfStream = */ true);
NS_ENSURE_SUCCESS(rv, rv);
LOG(("ScriptLoadRequest (%p): Source length = %u", mRequest.get(),
unsigned(mRequest->ScriptText().length())));
LOG(("ScriptLoadRequest (%p): Source length in code units = %u",
mRequest.get(), unsigned(mRequest->ScriptTextLength())));
// If SRI is required for this load, appending new bytes to the hash.
if (mSRIDataVerifier && NS_SUCCEEDED(mSRIStatus)) {