Bug 1816776 - Support initializing SourceText with FrontendContext. r=bthrall

Differential Revision: https://phabricator.services.mozilla.com/D176510
This commit is contained in:
Tooru Fujisawa 2023-05-11 10:18:37 +00:00
parent 3b979f198c
commit 4230b3e7e5
3 changed files with 108 additions and 22 deletions

View file

@ -62,13 +62,19 @@ namespace mozilla {
union Utf8Unit;
}
namespace js {
class FrontendContext;
} // namespace js
namespace JS {
class JS_PUBLIC_API AutoStableStringChars;
using FrontendContext = js::FrontendContext;
namespace detail {
MOZ_COLD extern JS_PUBLIC_API void ReportSourceTooLong(JSContext* cx);
MOZ_COLD extern JS_PUBLIC_API void ReportSourceTooLong(JS::FrontendContext* fc);
} // namespace detail
@ -131,21 +137,12 @@ class SourceText final {
}
}
/**
* Initialize this with source unit data: |char16_t| for UTF-16 source
* units, or |Utf8Unit| for UTF-8 source units.
*
* If |ownership == TakeOwnership|, *this function* takes ownership of
* |units|, *even if* this function fails, and you MUST NOT free |units|
* yourself. This single-owner-friendly approach reduces risk of leaks on
* failure.
*
* |units| may be null if |unitsLength == 0|; if so, this will silently be
* initialized using non-null, unowned units.
*/
[[nodiscard]] MOZ_IS_CLASS_INIT bool init(JSContext* cx, const Unit* units,
size_t unitsLength,
SourceOwnership ownership) {
private:
template <typename ContextT>
[[nodiscard]] MOZ_IS_CLASS_INIT bool initImpl(ContextT* context,
const Unit* units,
size_t unitsLength,
SourceOwnership ownership) {
MOZ_ASSERT_IF(units == nullptr, unitsLength == 0);
// Ideally we'd use |Unit| and not cast below, but the risk of a static
@ -169,13 +166,38 @@ class SourceText final {
// store offsets in |JSScript|s as |uint32_t|. It could be lifted
// fairly easily if desired, as the compiler uses |size_t| internally.
if (MOZ_UNLIKELY(unitsLength > UINT32_MAX)) {
detail::ReportSourceTooLong(cx);
detail::ReportSourceTooLong(context);
return false;
}
return true;
}
public:
/**
* Initialize this with source unit data: |char16_t| for UTF-16 source
* units, or |Utf8Unit| for UTF-8 source units.
*
* If |ownership == TakeOwnership|, *this function* takes ownership of
* |units|, *even if* this function fails, and you MUST NOT free |units|
* yourself. This single-owner-friendly approach reduces risk of leaks on
* failure.
*
* |units| may be null if |unitsLength == 0|; if so, this will silently be
* initialized using non-null, unowned units.
*/
[[nodiscard]] MOZ_IS_CLASS_INIT bool init(JSContext* cx, const Unit* units,
size_t unitsLength,
SourceOwnership ownership) {
return initImpl(cx, units, unitsLength, ownership);
}
[[nodiscard]] MOZ_IS_CLASS_INIT bool init(JS::FrontendContext* fc,
const Unit* units,
size_t unitsLength,
SourceOwnership ownership) {
return initImpl(fc, units, unitsLength, ownership);
}
/**
* Exactly identical to the |init()| overload above that accepts
* |const Unit*|, but instead takes character data: |const CharT*|.
@ -190,8 +212,18 @@ class SourceText final {
[[nodiscard]] MOZ_IS_CLASS_INIT bool init(JSContext* cx, const Char* chars,
size_t charsLength,
SourceOwnership ownership) {
return init(cx, reinterpret_cast<const Unit*>(chars), charsLength,
ownership);
return initImpl(cx, reinterpret_cast<const Unit*>(chars), charsLength,
ownership);
}
template <typename Char,
typename = std::enable_if_t<std::is_same_v<Char, CharT> &&
!std::is_same_v<Char, Unit>>>
[[nodiscard]] MOZ_IS_CLASS_INIT bool init(JS::FrontendContext* fc,
const Char* chars,
size_t charsLength,
SourceOwnership ownership) {
return initImpl(fc, reinterpret_cast<const Unit*>(chars), charsLength,
ownership);
}
/**
@ -200,7 +232,14 @@ class SourceText final {
[[nodiscard]] bool init(JSContext* cx,
js::UniquePtr<Unit[], JS::FreePolicy> data,
size_t dataLength) {
return init(cx, data.release(), dataLength, SourceOwnership::TakeOwnership);
return initImpl(cx, data.release(), dataLength,
SourceOwnership::TakeOwnership);
}
[[nodiscard]] bool init(JS::FrontendContext* fc,
js::UniquePtr<Unit[], JS::FreePolicy> data,
size_t dataLength) {
return initImpl(fc, data.release(), dataLength,
SourceOwnership::TakeOwnership);
}
/**
@ -220,6 +259,14 @@ class SourceText final {
size_t dataLength) {
return init(cx, data.release(), dataLength, SourceOwnership::TakeOwnership);
}
template <typename Char,
typename = std::enable_if_t<std::is_same_v<Char, CharT> &&
!std::is_same_v<Char, Unit>>>
[[nodiscard]] bool init(JS::FrontendContext* fc,
js::UniquePtr<Char[], JS::FreePolicy> data,
size_t dataLength) {
return init(fc, data.release(), dataLength, SourceOwnership::TakeOwnership);
}
/**
* Initialize this using an AutoStableStringChars. Transfers the code units if
@ -230,6 +277,8 @@ class SourceText final {
*/
[[nodiscard]] bool initMaybeBorrowed(JSContext* cx,
AutoStableStringChars& linearChars);
[[nodiscard]] bool initMaybeBorrowed(JS::FrontendContext* fc,
AutoStableStringChars& linearChars);
/**
* Access the encapsulated data using a code unit type.

View file

@ -33,8 +33,9 @@
#include "util/CompleteFile.h" // js::FileContents, js::ReadCompleteFile
#include "util/StringBuffer.h" // js::StringBuffer
#include "vm/EnvironmentObject.h" // js::CreateNonSyntacticEnvironmentChain
#include "vm/Interpreter.h" // js::Execute
#include "vm/JSContext.h" // JSContext
#include "vm/ErrorReporting.h" // js::ErrorMetadata, js::ReportCompileErrorLatin1
#include "vm/Interpreter.h" // js::Execute
#include "vm/JSContext.h" // JSContext
#include "vm/JSContext-inl.h" // JSContext::check
@ -56,6 +57,28 @@ JS_PUBLIC_API void JS::detail::ReportSourceTooLong(JSContext* cx) {
JSMSG_SOURCE_TOO_LONG);
}
static void ReportSourceTooLongImpl(JS::FrontendContext* fc, ...) {
va_list args;
va_start(args, fc);
js::ErrorMetadata metadata;
metadata.filename = "<unknown>";
metadata.lineNumber = 0;
metadata.columnNumber = 0;
metadata.lineLength = 0;
metadata.tokenOffset = 0;
metadata.isMuted = false;
js::ReportCompileErrorLatin1(fc, std::move(metadata), nullptr,
JSMSG_SOURCE_TOO_LONG, &args);
va_end(args);
}
JS_PUBLIC_API void JS::detail::ReportSourceTooLong(JS::FrontendContext* fc) {
ReportSourceTooLongImpl(fc);
}
template <typename Unit>
static JSScript* CompileSourceBuffer(JSContext* cx,
const ReadOnlyCompileOptions& options,

View file

@ -1457,7 +1457,21 @@ bool JS::SourceText<char16_t>::initMaybeBorrowed(
JS::SourceOwnership ownership = linearChars.maybeGiveOwnershipToCaller()
? JS::SourceOwnership::TakeOwnership
: JS::SourceOwnership::Borrowed;
return init(cx, chars, length, ownership);
return initImpl(cx, chars, length, ownership);
}
template <>
bool JS::SourceText<char16_t>::initMaybeBorrowed(
JS::FrontendContext* fc, JS::AutoStableStringChars& linearChars) {
MOZ_ASSERT(linearChars.isTwoByte(),
"AutoStableStringChars must be initialized with char16_t");
const char16_t* chars = linearChars.twoByteChars();
size_t length = linearChars.length();
JS::SourceOwnership ownership = linearChars.maybeGiveOwnershipToCaller()
? JS::SourceOwnership::TakeOwnership
: JS::SourceOwnership::Borrowed;
return initImpl(fc, chars, length, ownership);
}
#if defined(DEBUG) || defined(JS_JITSPEW) || defined(JS_CACHEIR_SPEW)