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