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:
Jeff Walden 2019-03-08 22:28:08 -08:00
Родитель 1bba596e1d
Коммит 8c1d08c491
8 изменённых файлов: 85 добавлений и 123 удалений

Просмотреть файл

@ -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;
}