зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1534437 - Make JSFlatString::new_ always take ownership of the |chars| passed to it, and add the same sensible ownership handling to a bunch of callers. r=tcampbell
Differential Revision: https://phabricator.services.mozilla.com/D23043 --HG-- extra : rebase_source : 60741661edc946794e97736dd013ed6eb9609d56 extra : amend_source : 0379248e2bee7588180739224b8008d927ab03f7
This commit is contained in:
Родитель
1bba596e1d
Коммит
8c1d08c491
|
@ -7753,12 +7753,11 @@ static bool ReadStringCommon(JSContext* cx, InflateUTF8Method inflateUTF8,
|
|||
return false;
|
||||
}
|
||||
|
||||
result = JS_NewUCString(cx, dst.get(), length);
|
||||
result = JS_NewUCString(cx, std::move(dst), length);
|
||||
if (!result) {
|
||||
return false;
|
||||
}
|
||||
|
||||
mozilla::Unused << dst.release();
|
||||
break;
|
||||
}
|
||||
case TYPE_int16_t:
|
||||
|
|
|
@ -4278,26 +4278,28 @@ JS_PUBLIC_API JSString* JS_AtomizeAndPinStringN(JSContext* cx, const char* s,
|
|||
return atom;
|
||||
}
|
||||
|
||||
JS_PUBLIC_API JSString* JS_NewLatin1String(JSContext* cx, JS::Latin1Char* chars,
|
||||
size_t length) {
|
||||
JS_PUBLIC_API JSString* JS_NewLatin1String(
|
||||
JSContext* cx, js::UniquePtr<JS::Latin1Char[], JS::FreePolicy> chars,
|
||||
size_t length) {
|
||||
AssertHeapIsIdle();
|
||||
CHECK_THREAD(cx);
|
||||
return NewString(cx, chars, length);
|
||||
return NewString(cx, std::move(chars), length);
|
||||
}
|
||||
|
||||
JS_PUBLIC_API JSString* JS_NewUCString(JSContext* cx, char16_t* chars,
|
||||
JS_PUBLIC_API JSString* JS_NewUCString(JSContext* cx,
|
||||
JS::UniqueTwoByteChars chars,
|
||||
size_t length) {
|
||||
AssertHeapIsIdle();
|
||||
CHECK_THREAD(cx);
|
||||
return NewString(cx, chars, length);
|
||||
return NewString(cx, std::move(chars), length);
|
||||
}
|
||||
|
||||
JS_PUBLIC_API JSString* JS_NewUCStringDontDeflate(JSContext* cx,
|
||||
char16_t* chars,
|
||||
JS::UniqueTwoByteChars chars,
|
||||
size_t length) {
|
||||
AssertHeapIsIdle();
|
||||
CHECK_THREAD(cx);
|
||||
return NewStringDontDeflate(cx, chars, length);
|
||||
return NewStringDontDeflate(cx, std::move(chars), length);
|
||||
}
|
||||
|
||||
JS_PUBLIC_API JSString* JS_NewUCStringCopyN(JSContext* cx, const char16_t* s,
|
||||
|
|
|
@ -2604,16 +2604,16 @@ extern JS_PUBLIC_API JSString* JS_AtomizeAndPinStringN(JSContext* cx,
|
|||
extern JS_PUBLIC_API JSString* JS_AtomizeAndPinString(JSContext* cx,
|
||||
const char* s);
|
||||
|
||||
extern JS_PUBLIC_API JSString* JS_NewLatin1String(JSContext* cx,
|
||||
JS::Latin1Char* chars,
|
||||
size_t length);
|
||||
extern JS_PUBLIC_API JSString* JS_NewLatin1String(
|
||||
JSContext* cx, js::UniquePtr<JS::Latin1Char[], JS::FreePolicy> chars,
|
||||
size_t length);
|
||||
|
||||
extern JS_PUBLIC_API JSString* JS_NewUCString(JSContext* cx, char16_t* chars,
|
||||
extern JS_PUBLIC_API JSString* JS_NewUCString(JSContext* cx,
|
||||
JS::UniqueTwoByteChars chars,
|
||||
size_t length);
|
||||
|
||||
extern JS_PUBLIC_API JSString* JS_NewUCStringDontDeflate(JSContext* cx,
|
||||
char16_t* chars,
|
||||
size_t length);
|
||||
extern JS_PUBLIC_API JSString* JS_NewUCStringDontDeflate(
|
||||
JSContext* cx, JS::UniqueTwoByteChars chars, size_t length);
|
||||
|
||||
extern JS_PUBLIC_API JSString* JS_NewUCStringCopyN(JSContext* cx,
|
||||
const char16_t* s, size_t n);
|
||||
|
|
|
@ -902,13 +902,7 @@ static MOZ_ALWAYS_INLINE JSFlatString* MakeUTF8AtomHelper(JSContext* cx,
|
|||
InflateUTF8CharsToBufferAndTerminate(chars->utf8, newStr.get(), length,
|
||||
chars->encoding);
|
||||
|
||||
JSFlatString* str = JSFlatString::new_<NoGC>(cx, newStr.get(), length);
|
||||
if (!str) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
mozilla::Unused << newStr.release();
|
||||
return str;
|
||||
return JSFlatString::new_<NoGC>(cx, std::move(newStr), length);
|
||||
}
|
||||
|
||||
// Another 2 variants of MakeFlatStringForAtomization.
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
#include "gc/FreeOp.h"
|
||||
#include "gc/Marking.h"
|
||||
#include "gc/StoreBuffer.h"
|
||||
#include "js/UniquePtr.h"
|
||||
#include "vm/JSContext.h"
|
||||
#include "vm/Realm.h"
|
||||
|
||||
|
@ -258,9 +259,9 @@ MOZ_ALWAYS_INLINE void JSFlatString::init(const JS::Latin1Char* chars,
|
|||
}
|
||||
|
||||
template <js::AllowGC allowGC, typename CharT>
|
||||
MOZ_ALWAYS_INLINE JSFlatString* JSFlatString::new_(JSContext* cx,
|
||||
const CharT* chars,
|
||||
size_t length) {
|
||||
MOZ_ALWAYS_INLINE JSFlatString* JSFlatString::new_(
|
||||
JSContext* cx, js::UniquePtr<CharT[], JS::FreePolicy> chars,
|
||||
size_t length) {
|
||||
MOZ_ASSERT(chars[length] == CharT(0));
|
||||
|
||||
if (!validateLength(cx, length)) {
|
||||
|
@ -278,13 +279,11 @@ MOZ_ALWAYS_INLINE JSFlatString* JSFlatString::new_(JSContext* cx,
|
|||
}
|
||||
|
||||
if (!str->isTenured()) {
|
||||
// The chars pointer is only considered to be handed over to this
|
||||
// function on a successful return. If the following registration
|
||||
// fails, the string is partially initialized and must be made valid,
|
||||
// or its finalizer may attempt to free uninitialized memory.
|
||||
void* ptr = const_cast<void*>(static_cast<const void*>(chars));
|
||||
if (!cx->runtime()->gc.nursery().registerMallocedBuffer(ptr)) {
|
||||
str->init((JS::Latin1Char*)nullptr, 0);
|
||||
// If the following registration fails, the string is partially initialized
|
||||
// and must be made valid, or its finalizer may attempt to free
|
||||
// uninitialized memory.
|
||||
if (!cx->runtime()->gc.nursery().registerMallocedBuffer(chars.get())) {
|
||||
str->init(static_cast<JS::Latin1Char*>(nullptr), 0);
|
||||
if (allowGC) {
|
||||
ReportOutOfMemory(cx);
|
||||
}
|
||||
|
@ -292,7 +291,7 @@ MOZ_ALWAYS_INLINE JSFlatString* JSFlatString::new_(JSContext* cx,
|
|||
}
|
||||
}
|
||||
|
||||
str->init(chars, length);
|
||||
str->init(chars.release(), length);
|
||||
return str;
|
||||
}
|
||||
|
||||
|
|
|
@ -1584,13 +1584,7 @@ static JSFlatString* NewStringDeflated(JSContext* cx, const char16_t* s,
|
|||
MOZ_ASSERT(CanStoreCharsAsLatin1(s, n));
|
||||
FillFromCompatibleAndTerminate(news.get(), s, n);
|
||||
|
||||
JSFlatString* str = JSFlatString::new_<allowGC>(cx, news.get(), n);
|
||||
if (!str) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
mozilla::Unused << news.release();
|
||||
return str;
|
||||
return JSFlatString::new_<allowGC>(cx, std::move(news), n);
|
||||
}
|
||||
|
||||
template <AllowGC allowGC>
|
||||
|
@ -1622,66 +1616,52 @@ static JSFlatString* NewStringDeflatedFromLittleEndianNoGC(
|
|||
|
||||
FillFromCompatibleAndTerminate(news.get(), chars, length);
|
||||
|
||||
JSFlatString* str = JSFlatString::new_<NoGC>(cx, news.get(), length);
|
||||
if (!str) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
mozilla::Unused << news.release();
|
||||
return str;
|
||||
return JSFlatString::new_<NoGC>(cx, std::move(news), length);
|
||||
}
|
||||
|
||||
template <typename CharT>
|
||||
JSFlatString* js::NewStringDontDeflate(JSContext* cx, CharT* chars,
|
||||
JSFlatString* js::NewStringDontDeflate(JSContext* cx,
|
||||
UniquePtr<CharT[], JS::FreePolicy> chars,
|
||||
size_t length) {
|
||||
if (JSFlatString* str = TryEmptyOrStaticString(cx, chars, length)) {
|
||||
// Free |chars| because we're taking possession of it, but it's no
|
||||
// longer needed because we use the static string instead.
|
||||
js_free(chars);
|
||||
if (JSFlatString* str = TryEmptyOrStaticString(cx, chars.get(), length)) {
|
||||
return str;
|
||||
}
|
||||
|
||||
if (JSInlineString::lengthFits<CharT>(length)) {
|
||||
JSInlineString* str =
|
||||
NewInlineString<CanGC>(cx, mozilla::Range<const CharT>(chars, length));
|
||||
if (!str) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
js_free(chars);
|
||||
return str;
|
||||
// |chars.get()| is safe because 1) |NewInlineString| necessarily *copies*,
|
||||
// and 2) |chars| frees its contents only when this function returns.
|
||||
return NewInlineString<CanGC>(
|
||||
cx, mozilla::Range<const CharT>(chars.get(), length));
|
||||
}
|
||||
|
||||
return JSFlatString::new_<CanGC>(cx, chars, length);
|
||||
return JSFlatString::new_<CanGC>(cx, std::move(chars), length);
|
||||
}
|
||||
|
||||
template JSFlatString* js::NewStringDontDeflate(JSContext* cx, char16_t* chars,
|
||||
template JSFlatString* js::NewStringDontDeflate(JSContext* cx,
|
||||
UniqueTwoByteChars chars,
|
||||
size_t length);
|
||||
|
||||
template JSFlatString* js::NewStringDontDeflate(JSContext* cx,
|
||||
Latin1Char* chars,
|
||||
UniqueLatin1Chars chars,
|
||||
size_t length);
|
||||
|
||||
template <typename CharT>
|
||||
JSFlatString* js::NewString(JSContext* cx, CharT* chars, size_t length) {
|
||||
if (IsSame<CharT, char16_t>::value && CanStoreCharsAsLatin1(chars, length)) {
|
||||
JSFlatString* s = NewStringDeflated<CanGC>(cx, chars, length);
|
||||
if (!s) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Free |chars| because we're taking possession of it but not using it.
|
||||
js_free(chars);
|
||||
return s;
|
||||
JSFlatString* js::NewString(JSContext* cx,
|
||||
UniquePtr<CharT[], JS::FreePolicy> chars,
|
||||
size_t length) {
|
||||
if (IsSame<CharT, char16_t>::value &&
|
||||
CanStoreCharsAsLatin1(chars.get(), length)) {
|
||||
// Deflating copies from |chars.get()| and lets |chars| be freed on return.
|
||||
return NewStringDeflated<CanGC>(cx, chars.get(), length);
|
||||
}
|
||||
|
||||
return NewStringDontDeflate(cx, chars, length);
|
||||
return NewStringDontDeflate(cx, std::move(chars), length);
|
||||
}
|
||||
|
||||
template JSFlatString* js::NewString(JSContext* cx, char16_t* chars,
|
||||
template JSFlatString* js::NewString(JSContext* cx, UniqueTwoByteChars chars,
|
||||
size_t length);
|
||||
|
||||
template JSFlatString* js::NewString(JSContext* cx, Latin1Char* chars,
|
||||
template JSFlatString* js::NewString(JSContext* cx, UniqueLatin1Chars chars,
|
||||
size_t length);
|
||||
|
||||
template <AllowGC allowGC, typename CharT>
|
||||
|
@ -1697,13 +1677,7 @@ JSFlatString* js::NewStringDontDeflate(JSContext* cx,
|
|||
cx, mozilla::Range<const CharT>(chars.get(), length));
|
||||
}
|
||||
|
||||
JSFlatString* str = JSFlatString::new_<allowGC>(cx, chars.get(), length);
|
||||
if (!str) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
mozilla::Unused << chars.release();
|
||||
return str;
|
||||
return JSFlatString::new_<allowGC>(cx, std::move(chars), length);
|
||||
}
|
||||
|
||||
template JSFlatString* js::NewStringDontDeflate<CanGC>(JSContext* cx,
|
||||
|
@ -1773,13 +1747,7 @@ JSFlatString* NewStringCopyNDontDeflate(JSContext* cx, const CharT* s,
|
|||
|
||||
FillAndTerminate(news.get(), s, n);
|
||||
|
||||
JSFlatString* str = JSFlatString::new_<allowGC>(cx, news.get(), n);
|
||||
if (!str) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
mozilla::Unused << news.release();
|
||||
return str;
|
||||
return JSFlatString::new_<allowGC>(cx, std::move(news), n);
|
||||
}
|
||||
|
||||
template JSFlatString* NewStringCopyNDontDeflate<CanGC>(JSContext* cx,
|
||||
|
@ -1819,13 +1787,7 @@ static JSFlatString* NewUndeflatedStringFromLittleEndianNoGC(
|
|||
|
||||
FillAndTerminate(news.get(), chars, length);
|
||||
|
||||
if (JSFlatString* str = JSFlatString::new_<NoGC>(cx, news.get(), length)) {
|
||||
// Successful JSFlatString::new_ took ownership of |news.release()|.
|
||||
mozilla::Unused << news.release();
|
||||
return str;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
return JSFlatString::new_<NoGC>(cx, std::move(news), length);
|
||||
}
|
||||
|
||||
JSFlatString* NewLatin1StringZ(JSContext* cx, UniqueChars chars) {
|
||||
|
|
|
@ -970,7 +970,8 @@ class JSFlatString : public JSLinearString {
|
|||
|
||||
public:
|
||||
template <js::AllowGC allowGC, typename CharT>
|
||||
static inline JSFlatString* new_(JSContext* cx, const CharT* chars,
|
||||
static inline JSFlatString* new_(JSContext* cx,
|
||||
js::UniquePtr<CharT[], JS::FreePolicy> chars,
|
||||
size_t length);
|
||||
|
||||
inline bool isIndexSlow(uint32_t* indexp) const {
|
||||
|
@ -1533,16 +1534,23 @@ static inline UniqueChars StringToNewUTF8CharsZ(JSContext* maybecx,
|
|||
.c_str());
|
||||
}
|
||||
|
||||
/* GC-allocate a string descriptor for the given malloc-allocated chars. */
|
||||
/**
|
||||
* Allocate a string with the given contents, potentially GCing in the process.
|
||||
*/
|
||||
template <typename CharT>
|
||||
extern JSFlatString* NewString(JSContext* cx, CharT* chars, size_t length);
|
||||
extern JSFlatString* NewString(JSContext* cx,
|
||||
UniquePtr<CharT[], JS::FreePolicy> chars,
|
||||
size_t length);
|
||||
|
||||
/* Like NewString, but doesn't try to deflate to Latin1. */
|
||||
/* Like NewString, but doesn't attempt to deflate to Latin1. */
|
||||
template <typename CharT>
|
||||
extern JSFlatString* NewStringDontDeflate(JSContext* cx, CharT* chars,
|
||||
size_t length);
|
||||
extern JSFlatString* NewStringDontDeflate(
|
||||
JSContext* cx, UniquePtr<CharT[], JS::FreePolicy> chars, size_t length);
|
||||
|
||||
/* GC-allocate a string descriptor for the given malloc-allocated chars. */
|
||||
/**
|
||||
* Allocate a string with the given contents. If |allowGC == CanGC|, this may
|
||||
* trigger a GC.
|
||||
*/
|
||||
template <js::AllowGC allowGC, typename CharT>
|
||||
extern JSFlatString* NewString(JSContext* cx,
|
||||
UniquePtr<CharT[], JS::FreePolicy> chars,
|
||||
|
|
|
@ -281,24 +281,25 @@ bool XPCConvert::NativeData2JS(MutableHandleValue d, const void* s,
|
|||
// should be fine.
|
||||
|
||||
if (IsUTF8Latin1(*utf8String)) {
|
||||
char* buffer = static_cast<char*>(JS_malloc(cx, allocLen.value()));
|
||||
using UniqueLatin1Chars =
|
||||
js::UniquePtr<JS::Latin1Char[], JS::FreePolicy>;
|
||||
|
||||
UniqueLatin1Chars buffer(
|
||||
static_cast<JS::Latin1Char*>(JS_malloc(cx, allocLen.value())));
|
||||
if (!buffer) {
|
||||
return false;
|
||||
}
|
||||
size_t written =
|
||||
LossyConvertUTF8toLatin1(*utf8String, MakeSpan(buffer, len));
|
||||
|
||||
size_t written = LossyConvertUTF8toLatin1(
|
||||
*utf8String, MakeSpan(reinterpret_cast<char*>(buffer.get()), len));
|
||||
buffer[written] = 0;
|
||||
|
||||
// JS_NewLatin1String takes ownership on success, i.e. a
|
||||
// successful call will make it the responsiblity of the JS VM
|
||||
// to free the buffer.
|
||||
// written can never exceed len, so the truncation is OK.
|
||||
JSString* str = JS_NewLatin1String(
|
||||
cx, reinterpret_cast<JS::Latin1Char*>(buffer), written);
|
||||
JSString* str = JS_NewLatin1String(cx, std::move(buffer), written);
|
||||
if (!str) {
|
||||
JS_free(cx, buffer);
|
||||
return false;
|
||||
}
|
||||
|
||||
d.setString(str);
|
||||
return true;
|
||||
}
|
||||
|
@ -316,8 +317,8 @@ bool XPCConvert::NativeData2JS(MutableHandleValue d, const void* s,
|
|||
return false;
|
||||
}
|
||||
|
||||
char16_t* buffer =
|
||||
static_cast<char16_t*>(JS_malloc(cx, allocLen.value()));
|
||||
JS::UniqueTwoByteChars buffer(
|
||||
static_cast<char16_t*>(JS_malloc(cx, allocLen.value())));
|
||||
if (!buffer) {
|
||||
return false;
|
||||
}
|
||||
|
@ -328,19 +329,16 @@ bool XPCConvert::NativeData2JS(MutableHandleValue d, const void* s,
|
|||
// code units in the source. That's why it's OK to claim the
|
||||
// output buffer has len + 1 space but then still expect to
|
||||
// have space for the zero terminator.
|
||||
size_t written =
|
||||
ConvertUTF8toUTF16(*utf8String, MakeSpan(buffer, allocLen.value()));
|
||||
size_t written = ConvertUTF8toUTF16(
|
||||
*utf8String, MakeSpan(buffer.get(), allocLen.value()));
|
||||
MOZ_RELEASE_ASSERT(written <= len);
|
||||
buffer[written] = 0;
|
||||
|
||||
// JS_NewUCStringDontDeflate takes ownership on success, i.e. a
|
||||
// successful call will make it the responsiblity of the JS VM
|
||||
// to free the buffer.
|
||||
JSString* str = JS_NewUCStringDontDeflate(cx, buffer, written);
|
||||
JSString* str = JS_NewUCStringDontDeflate(cx, std::move(buffer), written);
|
||||
if (!str) {
|
||||
JS_free(cx, buffer);
|
||||
return false;
|
||||
}
|
||||
|
||||
d.setString(str);
|
||||
return true;
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче