Bug 1586683 - Remove flat strings from JSAPI. r=jwalden,bzbarsky

We want to remove flat strings (JSFlatString). With this patch we only expose
linear strings (JSLinearString) to API consumers.

This is very mechanical for the most part, because code typically only cares
about linear strings and not the null-termination aspect.

CTypes's Library.cpp has some Windows-specific code where we relied on null-terminated
strings. This patch adds JS_CopyStringCharsZ for that use case.

Differential Revision: https://phabricator.services.mozilla.com/D48314

--HG--
extra : moz-landing-system : lando
This commit is contained in:
Jan de Mooij 2019-10-14 09:32:07 +00:00
parent 05bbb86d41
commit 6febd292ea
42 changed files with 283 additions and 284 deletions

View File

@ -130,11 +130,11 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INTERNAL(CallbackTimeoutHandler)
JSFunction* fun =
JS_GetObjectFunction(js::UncheckedUnwrapWithoutExpose(obj));
if (fun && JS_GetFunctionId(fun)) {
JSFlatString* funId = JS_ASSERT_STRING_IS_FLAT(JS_GetFunctionId(fun));
size_t size = 1 + JS_PutEscapedFlatString(nullptr, 0, funId, 0);
JSLinearString* funId = JS_ASSERT_STRING_IS_LINEAR(JS_GetFunctionId(fun));
size_t size = 1 + JS_PutEscapedLinearString(nullptr, 0, funId, 0);
char* funIdName = new char[size];
if (funIdName) {
JS_PutEscapedFlatString(funIdName, size, funId, 0);
JS_PutEscapedLinearString(funIdName, size, funId, 0);
name.AppendLiteral(" [");
name.Append(funIdName);
delete[] funIdName;

View File

@ -270,12 +270,12 @@ inline bool AssignJSString(JSContext* cx, T& dest, JSString* s) {
return js::CopyStringChars(cx, dest.BeginWriting(), s, len);
}
inline void AssignJSFlatString(nsAString& dest, JSFlatString* s) {
size_t len = js::GetFlatStringLength(s);
inline void AssignJSLinearString(nsAString& dest, JSLinearString* s) {
size_t len = js::GetLinearStringLength(s);
static_assert(js::MaxStringLength < (1 << 30),
"Shouldn't overflow here or in SetCapacity");
dest.SetLength(len);
js::CopyFlatStringChars(dest.BeginWriting(), s, len);
js::CopyLinearStringChars(dest.BeginWriting(), s, len);
}
class nsAutoJSString : public nsAutoString {

View File

@ -20,8 +20,7 @@ bool CallbackInterface::GetCallableProperty(
return false;
}
if (!aCallable.isObject() || !JS::IsCallable(&aCallable.toObject())) {
JS::RootedString propId(
cx, JS_FORGET_STRING_FLATNESS(JSID_TO_FLAT_STRING(aPropId)));
JS::RootedString propId(cx, JSID_TO_STRING(aPropId));
JS::UniqueChars propName = JS_EncodeStringToUTF8(cx, propId);
nsPrintfCString description("Property '%s'", propName.get());
ThrowErrorMessage(cx, MSG_NOT_CALLABLE, description.get());

View File

@ -11836,7 +11836,7 @@ def missingPropUseCountersForDescriptor(desc):
# We're down to one string: just check whether we match it.
return fill(
"""
if (JS_FlatStringEqualsLiteral(str, "${name}")) {
if (JS_LinearStringEqualsLiteral(str, "${name}")) {
counter.emplace(eUseCounter_${iface}_${name});
}
""",
@ -11846,7 +11846,7 @@ def missingPropUseCountersForDescriptor(desc):
switch = dict()
if charIndex == 0:
switch['precondition'] = \
'StringIdChars chars(nogc, js::FlatStringToLinearString(str));\n'
'StringIdChars chars(nogc, str);\n'
else:
switch['precondition'] = ""
@ -11874,7 +11874,7 @@ def missingPropUseCountersForDescriptor(desc):
return switch
lengths = set(len(prop[1]) for prop in instrumentedProps)
switchDesc = { 'condition': 'js::GetFlatStringLength(str)',
switchDesc = { 'condition': 'js::GetLinearStringLength(str)',
'precondition': '' }
switchDesc['cases'] = dict()
for length in sorted(lengths):
@ -11890,7 +11890,7 @@ def missingPropUseCountersForDescriptor(desc):
{
// Scope for our no-GC section, so we don't need to rely on SetUseCounter not GCing.
JS::AutoCheckCannotGC nogc;
JSFlatString* str = js::AtomToFlatString(JSID_TO_ATOM(id));
JSLinearString* str = js::AtomToLinearString(JSID_TO_ATOM(id));
// Don't waste time fetching the chars until we've done the length switch.
$*{switch}
}
@ -14536,11 +14536,11 @@ class CGGlobalNames(CGGeneric):
phfCodegen = phf.codegen('WebIDLGlobalNameHash::sEntries',
'WebIDLNameTableEntry')
entries = phfCodegen.gen_entries(lambda e: e[1])
getter = phfCodegen.gen_jsflatstr_getter(
getter = phfCodegen.gen_jslinearstr_getter(
name='WebIDLGlobalNameHash::GetEntry',
return_type='const WebIDLNameTableEntry*',
return_entry=dedent("""
if (JS_FlatStringEqualsAscii(aKey, sNames + entry.mNameOffset, entry.mNameLength)) {
if (JS_LinearStringEqualsAscii(aKey, sNames + entry.mNameOffset, entry.mNameLength)) {
return &entry;
}
return nullptr;

View File

@ -62,9 +62,7 @@ bool WebIDLGlobalNameHash::DefineIfEnabled(
JS::MutableHandle<JS::PropertyDescriptor> aDesc, bool* aFound) {
MOZ_ASSERT(JSID_IS_STRING(aId), "Check for string id before calling this!");
const WebIDLNameTableEntry* entry;
{ entry = GetEntry(JSID_TO_FLAT_STRING(aId)); }
const WebIDLNameTableEntry* entry = GetEntry(JSID_TO_LINEAR_STRING(aId));
if (!entry) {
*aFound = false;
return true;
@ -175,7 +173,7 @@ bool WebIDLGlobalNameHash::DefineIfEnabled(
/* static */
bool WebIDLGlobalNameHash::MayResolve(jsid aId) {
return GetEntry(JSID_TO_FLAT_STRING(aId)) != nullptr;
return GetEntry(JSID_TO_LINEAR_STRING(aId)) != nullptr;
}
/* static */
@ -228,7 +226,7 @@ bool WebIDLGlobalNameHash::ResolveForSystemGlobal(JSContext* aCx,
MOZ_ASSERT(!xpc::WrapperFactory::IsXrayWrapper(aObj), "Xrays not supported!");
// Look up the corresponding entry in the name table, and resolve if enabled.
const WebIDLNameTableEntry* entry = GetEntry(JSID_TO_FLAT_STRING(aId));
const WebIDLNameTableEntry* entry = GetEntry(JSID_TO_LINEAR_STRING(aId));
if (entry && (!entry->mEnabled || entry->mEnabled(aCx, aObj))) {
if (NS_WARN_IF(!GetPerInterfaceObjectHandle(
aCx, entry->mConstructorId, entry->mCreate,

View File

@ -11,7 +11,7 @@
#include "nsTArray.h"
#include "mozilla/dom/BindingDeclarations.h"
class JSFlatString;
class JSLinearString;
namespace mozilla {
namespace dom {
@ -77,7 +77,7 @@ class WebIDLGlobalNameHash {
// Look up an entry by key name. `nullptr` if the entry was not found.
// The impl of GetEntry is generated by Codegen.py in RegisterBindings.cpp
static const WebIDLNameTableEntry* GetEntry(JSFlatString* aKey);
static const WebIDLNameTableEntry* GetEntry(JSLinearString* aKey);
// The total number of names in the hash.
// The value of sCount is generated by Codegen.py in RegisterBindings.cpp.

View File

@ -209,9 +209,9 @@ void FileReader::OnLoadEndArrayBuffer() {
}
nsAutoString errorName;
JSFlatString* name = js::GetErrorTypeName(cx, er->exnType);
JSLinearString* name = js::GetErrorTypeName(cx, er->exnType);
if (name) {
AssignJSFlatString(errorName, name);
AssignJSLinearString(errorName, name);
}
nsAutoCString errorMsg(er->message().c_str());

View File

@ -751,7 +751,7 @@ NPUTF8* _utf8fromidentifier(NPIdentifier id) {
JSString* str = NPIdentifierToString(id);
nsAutoString autoStr;
AssignJSFlatString(autoStr, JS_ASSERT_STRING_IS_FLAT(str));
AssignJSLinearString(autoStr, JS_ASSERT_STRING_IS_LINEAR(str));
return ToNewUTF8String(autoStr);
}

View File

@ -13,7 +13,7 @@
#include "js/TypeDecls.h"
#include "js/Utility.h"
class JSFlatString;
class JSLinearString;
namespace JS {
@ -283,7 +283,7 @@ LossyUTF8CharsToNewTwoByteCharsZ(JSContext* cx, const ConstUTF8CharsZ& utf8,
* Returns the length of the char buffer required to encode |s| as UTF8.
* Does not include the null-terminator.
*/
JS_PUBLIC_API size_t GetDeflatedUTF8StringLength(JSFlatString* s);
JS_PUBLIC_API size_t GetDeflatedUTF8StringLength(JSLinearString* s);
/*
* Encode whole scalar values of |src| into |dst| as UTF-8 until |src| is
@ -292,16 +292,16 @@ JS_PUBLIC_API size_t GetDeflatedUTF8StringLength(JSFlatString* s);
* the number of bytes of |dst| that were filled.
*
* Use |JS_EncodeStringToUTF8BufferPartial| if your string isn't already
* flat.
* linear.
*
* Given |JSString* str = JS_FORGET_STRING_FLATNESS(src)|,
* Given |JSString* str = JS_FORGET_STRING_LINEARNESS(src)|,
* if |JS_StringHasLatin1Chars(str)|, then |src| is always fully converted
* if |dst.Length() >= JS_GetStringLength(str) * 2|. Otherwise |src| is
* always fully converted if |dst.Length() >= JS_GetStringLength(str) * 3|.
*
* The exact space required is always |GetDeflatedUTF8StringLength(str)|.
*/
JS_PUBLIC_API size_t DeflateStringToUTF8Buffer(JSFlatString* src,
JS_PUBLIC_API size_t DeflateStringToUTF8Buffer(JSLinearString* src,
mozilla::Span<char> dst);
/*

View File

@ -263,8 +263,6 @@ class JS_FRIEND_API GCCellPtr {
: ptr(checkedCast(p, JS::MapTypeToTraceKind<T>::kind)) {}
explicit GCCellPtr(JSFunction* p)
: ptr(checkedCast(p, JS::TraceKind::Object)) {}
explicit GCCellPtr(JSFlatString* str)
: ptr(checkedCast(str, JS::TraceKind::String)) {}
explicit GCCellPtr(const Value& v);
JS::TraceKind kind() const {

View File

@ -178,7 +178,7 @@ const WHITELIST_TYPES: &'static [&'static str] = &[
"JSErrorFormatString",
"JSErrorReport",
"JSExnType",
"JSFlatString",
"JSLinearString",
"JSFunction",
"JSFunctionSpec",
"JS::GCDescription",

View File

@ -283,7 +283,7 @@ impl RootKind for *mut JSObject {
fn rootKind() -> JS::RootKind { JS::RootKind::Object }
}
impl RootKind for *mut JSFlatString {
impl RootKind for *mut JSLinearString {
#[inline(always)]
fn rootKind() -> JS::RootKind { JS::RootKind::String }
}

View File

@ -582,8 +582,8 @@ static bool GCParameter(JSContext* cx, unsigned argc, Value* vp) {
return false;
}
JSFlatString* flatStr = JS_FlattenString(cx, str);
if (!flatStr) {
JSLinearString* linearStr = JS_EnsureLinearString(cx, str);
if (!linearStr) {
return false;
}
@ -594,7 +594,7 @@ static bool GCParameter(JSContext* cx, unsigned argc, Value* vp) {
cx, "the first argument must be one of:" GC_PARAMETER_ARGS_LIST);
return false;
}
if (JS_FlatStringEqualsAscii(flatStr, paramMap[paramIndex].name)) {
if (JS_LinearStringEqualsAscii(linearStr, paramMap[paramIndex].name)) {
break;
}
}
@ -1116,13 +1116,13 @@ static bool InternalConst(JSContext* cx, unsigned argc, Value* vp) {
if (!str) {
return false;
}
JSFlatString* flat = JS_FlattenString(cx, str);
if (!flat) {
JSLinearString* linear = JS_EnsureLinearString(cx, str);
if (!linear) {
return false;
}
if (JS_FlatStringEqualsLiteral(flat,
"INCREMENTAL_MARK_STACK_BASE_CAPACITY")) {
if (JS_LinearStringEqualsLiteral(linear,
"INCREMENTAL_MARK_STACK_BASE_CAPACITY")) {
args.rval().setNumber(uint32_t(js::INCREMENTAL_MARK_STACK_BASE_CAPACITY));
} else {
JS_ReportErrorASCII(cx, "unknown const name");

View File

@ -994,7 +994,8 @@ static void BuildConversionPosition(JSContext* cx, ConversionType convType,
}
}
static JSFlatString* GetFieldName(HandleObject structObj, unsigned fieldIndex) {
static JSLinearString* GetFieldName(HandleObject structObj,
unsigned fieldIndex) {
const FieldInfoHash* fields = StructType::GetFieldInfo(structObj);
for (FieldInfoHash::Range r = fields->all(); !r.empty(); r.popFront()) {
if (r.front().value().mIndex == fieldIndex) {
@ -1274,7 +1275,7 @@ static bool CannotConstructError(JSContext* cx, const char* type) {
return false;
}
static bool DuplicateFieldError(JSContext* cx, Handle<JSFlatString*> name) {
static bool DuplicateFieldError(JSContext* cx, Handle<JSLinearString*> name) {
JS::UniqueChars nameStr = JS_EncodeStringToUTF8(cx, name);
if (!nameStr) {
return false;
@ -1423,7 +1424,7 @@ static bool FieldDescriptorTypeError(JSContext* cx, HandleValue poroVal,
}
static bool FieldMissingError(JSContext* cx, JSObject* typeObj,
JSFlatString* name_) {
JSLinearString* name_) {
JS::UniqueChars typeBytes;
RootedString name(cx, name_);
RootedValue typeVal(cx, ObjectValue(*typeObj));
@ -3646,7 +3647,7 @@ static bool ImplicitConvert(JSContext* cx, HandleValue val,
argIndex);
}
JSFlatString* name = JSID_TO_FLAT_STRING(id);
JSLinearString* name = JSID_TO_LINEAR_STRING(id);
const FieldInfo* field =
StructType::LookupField(cx, targetType, name);
if (!field) {
@ -5705,8 +5706,8 @@ bool ArrayType::AddressOfElement(JSContext* cx, unsigned argc, Value* vp) {
// For a struct field descriptor 'val' of the form { name : type }, extract
// 'name' and 'type'.
static JSFlatString* ExtractStructField(JSContext* cx, HandleValue val,
MutableHandleObject typeObj) {
static JSLinearString* ExtractStructField(JSContext* cx, HandleValue val,
MutableHandleObject typeObj) {
if (val.isPrimitive()) {
FieldDescriptorNameTypeError(cx, val);
return nullptr;
@ -5750,15 +5751,15 @@ static JSFlatString* ExtractStructField(JSContext* cx, HandleValue val,
return nullptr;
}
return JSID_TO_FLAT_STRING(nameid);
return JSID_TO_LINEAR_STRING(nameid);
}
// For a struct field with 'name' and 'type', add an element of the form
// { name : type }.
static bool AddFieldToArray(JSContext* cx, MutableHandleValue element,
JSFlatString* name_, JSObject* typeObj_) {
JSLinearString* name_, JSObject* typeObj_) {
RootedObject typeObj(cx, typeObj_);
Rooted<JSFlatString*> name(cx, name_);
Rooted<JSLinearString*> name(cx, name_);
RootedObject fieldObj(cx, JS_NewPlainObject(cx));
if (!fieldObj) {
return false;
@ -5876,7 +5877,8 @@ bool StructType::DefineInternal(JSContext* cx, JSObject* typeObj_,
}
RootedObject fieldType(cx, nullptr);
Rooted<JSFlatString*> name(cx, ExtractStructField(cx, item, &fieldType));
Rooted<JSLinearString*> name(cx,
ExtractStructField(cx, item, &fieldType));
if (!name) {
return false;
}
@ -5900,7 +5902,7 @@ bool StructType::DefineInternal(JSContext* cx, JSObject* typeObj_,
return false;
}
SetFunctionNativeReserved(getter, StructType::SLOT_FIELDNAME,
StringValue(JS_FORGET_STRING_FLATNESS(name)));
StringValue(JS_FORGET_STRING_LINEARNESS(name)));
RootedObject getterObj(cx, JS_GetFunctionObject(getter));
RootedFunction setter(
@ -5910,7 +5912,7 @@ bool StructType::DefineInternal(JSContext* cx, JSObject* typeObj_,
return false;
}
SetFunctionNativeReserved(setter, StructType::SLOT_FIELDNAME,
StringValue(JS_FORGET_STRING_FLATNESS(name)));
StringValue(JS_FORGET_STRING_LINEARNESS(name)));
RootedObject setterObj(cx, JS_GetFunctionObject(setter));
if (!JS_DefineUCProperty(cx, prototype, nameChars.twoByteChars(),
@ -6197,7 +6199,7 @@ const FieldInfoHash* StructType::GetFieldInfo(JSObject* obj) {
}
const FieldInfo* StructType::LookupField(JSContext* cx, JSObject* obj,
JSFlatString* name) {
JSLinearString* name) {
MOZ_ASSERT(CType::IsCType(obj));
MOZ_ASSERT(CType::GetTypeCode(obj) == TYPE_struct);
@ -6301,7 +6303,8 @@ bool StructType::FieldGetter(JSContext* cx, unsigned argc, Value* vp) {
RootedValue nameVal(
cx, GetFunctionNativeReserved(&args.callee(), SLOT_FIELDNAME));
Rooted<JSFlatString*> name(cx, JS_FlattenString(cx, nameVal.toString()));
Rooted<JSLinearString*> name(cx,
JS_EnsureLinearString(cx, nameVal.toString()));
if (!name) {
return false;
}
@ -6338,7 +6341,8 @@ bool StructType::FieldSetter(JSContext* cx, unsigned argc, Value* vp) {
RootedValue nameVal(
cx, GetFunctionNativeReserved(&args.callee(), SLOT_FIELDNAME));
Rooted<JSFlatString*> name(cx, JS_FlattenString(cx, nameVal.toString()));
Rooted<JSLinearString*> name(cx,
JS_EnsureLinearString(cx, nameVal.toString()));
if (!name) {
return false;
}
@ -6385,7 +6389,7 @@ bool StructType::AddressOfField(JSContext* cx, unsigned argc, Value* vp) {
"a string");
}
JSFlatString* str = JS_FlattenString(cx, args[0].toString());
JSLinearString* str = JS_EnsureLinearString(cx, args[0].toString());
if (!str) {
return false;
}

View File

@ -325,8 +325,8 @@ static_assert(sizeof(UnbarrieredFieldInfo) == sizeof(FieldInfo),
"unbarriered mType");
// Hash policy for FieldInfos.
struct FieldHashPolicy : DefaultHasher<JSFlatString*> {
typedef JSFlatString* Key;
struct FieldHashPolicy : DefaultHasher<JSLinearString*> {
typedef JSLinearString* Key;
typedef Key Lookup;
template <typename CharT>
@ -357,7 +357,7 @@ struct FieldHashPolicy : DefaultHasher<JSFlatString*> {
}
};
using FieldInfoHash = GCHashMap<js::HeapPtr<JSFlatString*>, FieldInfo,
using FieldInfoHash = GCHashMap<js::HeapPtr<JSLinearString*>, FieldInfo,
FieldHashPolicy, ZoneAllocPolicy>;
// Descriptor of ABI, return type, argument types, and variadicity for a
@ -567,7 +567,8 @@ MOZ_MUST_USE bool DefineInternal(JSContext* cx, JSObject* typeObj,
JSObject* fieldsObj);
const FieldInfoHash* GetFieldInfo(JSObject* obj);
const FieldInfo* LookupField(JSContext* cx, JSObject* obj, JSFlatString* name);
const FieldInfo* LookupField(JSContext* cx, JSObject* obj,
JSLinearString* name);
JSObject* BuildFieldsArray(JSContext* cx, JSObject* obj);
UniquePtrFFIType BuildFFIType(JSContext* cx, JSObject* obj);
} // namespace StructType

View File

@ -107,18 +107,18 @@ JSObject* Library::Create(JSContext* cx, HandleValue path,
}
PRLibSpec libSpec;
RootedFlatString pathStr(cx, JS_FlattenString(cx, path.toString()));
RootedLinearString pathStr(cx, JS_EnsureLinearString(cx, path.toString()));
if (!pathStr) {
return nullptr;
}
#ifdef XP_WIN
// On Windows, converting to native charset may corrupt path string.
// So, we have to use Unicode path directly.
AutoStableStringChars pathStrChars(cx);
if (!pathStrChars.initTwoByte(cx, pathStr)) {
JS::UniqueTwoByteChars pathZeroTerminated(JS_CopyStringCharsZ(cx, pathStr));
if (!pathZeroTerminated) {
return nullptr;
}
char16ptr_t pathChars = pathStrChars.twoByteChars();
char16ptr_t pathChars = pathZeroTerminated.get();
libSpec.value.pathname_u = pathChars;
libSpec.type = PR_LibSpec_PathnameU;
#else

View File

@ -1,8 +1,8 @@
#include "gdb-tests.h"
#include "vm/JSContext.h"
// When JSGC_ANALYSIS is #defined, Rooted<JSFlatString*> needs the definition
// of JSFlatString in order to figure out its ThingRootKind
// When JSGC_ANALYSIS is #defined, Rooted<JSLinearString*> needs the definition
// of JSLinearString in order to figure out its ThingRootKind
#include "vm/StringType.h"
FRAGMENT(JSString, simple) {
@ -53,12 +53,12 @@ FRAGMENT(JSString, null) {
}
FRAGMENT(JSString, subclasses) {
JS::Rooted<JSFlatString*> flat(
cx, JS_FlattenString(cx, JS_NewStringCopyZ(cx, "Hi!")));
JS::Rooted<JSLinearString*> linear(
cx, JS_EnsureLinearString(cx, JS_NewStringCopyZ(cx, "Hi!")));
breakpoint();
use(flat);
use(linear);
}
FRAGMENT(JSString, atom) {

View File

@ -8,7 +8,7 @@ using namespace JS;
BEGIN_TEST(test_DeflateStringToUTF8Buffer) {
JSString* str;
JSFlatString* flatStr;
JSLinearString* linearStr;
// DeflateStringToUTF8Buffer does not write a null terminator, so the byte
// following the last byte written to the |actual| buffer should retain
@ -18,18 +18,18 @@ BEGIN_TEST(test_DeflateStringToUTF8Buffer) {
char actual[100];
auto span = mozilla::MakeSpan(actual);
// Test with an ASCII string, which calls JSFlatString::latin1Chars
// Test with an ASCII string, which calls JSLinearString::latin1Chars
// to retrieve the characters from the string and generates UTF-8 output
// that is identical to the ASCII input.
str = JS_NewStringCopyZ(cx, "Ohai"); // { 0x4F, 0x68, 0x61, 0x69 }
MOZ_RELEASE_ASSERT(str);
flatStr = JS_FlattenString(cx, str);
linearStr = JS_EnsureLinearString(cx, str);
{
const char expected[] = {0x4F, 0x68, 0x61, 0x69, 0x1};
memset(actual, 0x1, 100);
size_t dstlen = JS::DeflateStringToUTF8Buffer(flatStr, span);
size_t dstlen = JS::DeflateStringToUTF8Buffer(linearStr, span);
CHECK_EQUAL(memcmp(actual, expected, sizeof(expected)), 0);
CHECK_EQUAL(dstlen, 4u);
}
@ -37,7 +37,7 @@ BEGIN_TEST(test_DeflateStringToUTF8Buffer) {
{
const char expected[] = {0x4F, 0x68, 0x61, 0x1};
memset(actual, 0x1, 100);
size_t dstlen = JS::DeflateStringToUTF8Buffer(flatStr, span.To(3));
size_t dstlen = JS::DeflateStringToUTF8Buffer(linearStr, span.To(3));
CHECK_EQUAL(memcmp(actual, expected, sizeof(expected)), 0);
CHECK_EQUAL(dstlen, 3u);
}
@ -45,24 +45,24 @@ BEGIN_TEST(test_DeflateStringToUTF8Buffer) {
{
const unsigned char expected[] = {0x1};
memset(actual, 0x1, 100);
size_t dstlen = JS::DeflateStringToUTF8Buffer(flatStr, span.To(0));
size_t dstlen = JS::DeflateStringToUTF8Buffer(linearStr, span.To(0));
CHECK_EQUAL(memcmp(actual, expected, sizeof(expected)), 0);
CHECK_EQUAL(dstlen, 0u);
}
// Test with a Latin-1 string, which calls JSFlatString::latin1Chars
// Test with a Latin-1 string, which calls JSLinearString::latin1Chars
// like with the ASCII string but generates UTF-8 output that is different
// from the ASCII input.
str = JS_NewUCStringCopyZ(cx, u"\xD3\x68\xE3\xEF"); // u"Óhãï"
MOZ_RELEASE_ASSERT(str);
flatStr = JS_FlattenString(cx, str);
linearStr = JS_EnsureLinearString(cx, str);
{
const unsigned char expected[] = {0xC3, 0x93, 0x68, 0xC3,
0xA3, 0xC3, 0xAF, 0x1};
memset(actual, 0x1, 100);
JS::DeflateStringToUTF8Buffer(flatStr, span);
JS::DeflateStringToUTF8Buffer(linearStr, span);
CHECK_EQUAL(memcmp(actual, expected, sizeof(expected)), 0);
}
@ -70,7 +70,7 @@ BEGIN_TEST(test_DeflateStringToUTF8Buffer) {
const unsigned char expected[] = {0xC3, 0x93, 0x68, 0xC3,
0xA3, 0xC3, 0xAF, 0x1};
memset(actual, 0x1, 100);
size_t dstlen = JS::DeflateStringToUTF8Buffer(flatStr, span.To(7));
size_t dstlen = JS::DeflateStringToUTF8Buffer(linearStr, span.To(7));
CHECK_EQUAL(memcmp(actual, expected, sizeof(expected)), 0);
CHECK_EQUAL(dstlen, 7u);
}
@ -80,7 +80,7 @@ BEGIN_TEST(test_DeflateStringToUTF8Buffer) {
// space to encode the first two characters, which takes three bytes.
const unsigned char expected[] = {0xC3, 0x93, 0x68, 0x1};
memset(actual, 0x1, 100);
size_t dstlen = JS::DeflateStringToUTF8Buffer(flatStr, span.To(3));
size_t dstlen = JS::DeflateStringToUTF8Buffer(linearStr, span.To(3));
CHECK_EQUAL(memcmp(actual, expected, sizeof(expected)), 0);
CHECK_EQUAL(dstlen, 3u);
}
@ -91,7 +91,7 @@ BEGIN_TEST(test_DeflateStringToUTF8Buffer) {
// the third character would take another two bytes.
const unsigned char expected[] = {0xC3, 0x93, 0x68, 0x1};
memset(actual, 0x1, 100);
size_t dstlen = JS::DeflateStringToUTF8Buffer(flatStr, span.To(4));
size_t dstlen = JS::DeflateStringToUTF8Buffer(linearStr, span.To(4));
CHECK_EQUAL(memcmp(actual, expected, sizeof(expected)), 0);
CHECK_EQUAL(dstlen, 3u);
}
@ -99,23 +99,23 @@ BEGIN_TEST(test_DeflateStringToUTF8Buffer) {
{
const unsigned char expected[] = {0x1};
memset(actual, 0x1, 100);
size_t dstlen = JS::DeflateStringToUTF8Buffer(flatStr, span.To(0));
size_t dstlen = JS::DeflateStringToUTF8Buffer(linearStr, span.To(0));
CHECK_EQUAL(memcmp(actual, expected, sizeof(expected)), 0);
CHECK_EQUAL(dstlen, 0u);
}
// Test with a UTF-16 string, which calls JSFlatString::twoByteChars
// Test with a UTF-16 string, which calls JSLinearString::twoByteChars
// to retrieve the characters from the string.
str = JS_NewUCStringCopyZ(cx, u"\x038C\x0068\x0203\x0457"); // u"Όhȃї"
MOZ_RELEASE_ASSERT(str);
flatStr = JS_FlattenString(cx, str);
linearStr = JS_EnsureLinearString(cx, str);
{
const unsigned char expected[] = {0xCE, 0x8C, 0x68, 0xC8,
0x83, 0xD1, 0x97, 0x1};
memset(actual, 0x1, 100);
JS::DeflateStringToUTF8Buffer(flatStr, span);
JS::DeflateStringToUTF8Buffer(linearStr, span);
CHECK_EQUAL(memcmp(actual, expected, sizeof(expected)), 0);
}
@ -123,7 +123,7 @@ BEGIN_TEST(test_DeflateStringToUTF8Buffer) {
const unsigned char expected[] = {0xCE, 0x8C, 0x68, 0xC8,
0x83, 0xD1, 0x97, 0x1};
memset(actual, 0x1, 100);
size_t dstlen = JS::DeflateStringToUTF8Buffer(flatStr, span.To(7));
size_t dstlen = JS::DeflateStringToUTF8Buffer(linearStr, span.To(7));
CHECK_EQUAL(memcmp(actual, expected, sizeof(expected)), 0);
CHECK_EQUAL(dstlen, 7u);
}
@ -133,7 +133,7 @@ BEGIN_TEST(test_DeflateStringToUTF8Buffer) {
// space to encode the first two characters, which takes three bytes.
const unsigned char expected[] = {0xCE, 0x8C, 0x68, 0x1};
memset(actual, 0x1, 100);
size_t dstlen = JS::DeflateStringToUTF8Buffer(flatStr, span.To(3));
size_t dstlen = JS::DeflateStringToUTF8Buffer(linearStr, span.To(3));
CHECK_EQUAL(memcmp(actual, expected, sizeof(expected)), 0);
CHECK_EQUAL(dstlen, 3u);
}
@ -144,7 +144,7 @@ BEGIN_TEST(test_DeflateStringToUTF8Buffer) {
// the third character would take another two bytes.
const unsigned char expected[] = {0xCE, 0x8C, 0x68, 0x1};
memset(actual, 0x1, 100);
size_t dstlen = JS::DeflateStringToUTF8Buffer(flatStr, span.To(4));
size_t dstlen = JS::DeflateStringToUTF8Buffer(linearStr, span.To(4));
CHECK_EQUAL(memcmp(actual, expected, sizeof(expected)), 0);
CHECK_EQUAL(dstlen, 3u);
}
@ -152,7 +152,7 @@ BEGIN_TEST(test_DeflateStringToUTF8Buffer) {
{
const unsigned char expected[] = {0x1};
memset(actual, 0x1, 100);
size_t dstlen = JS::DeflateStringToUTF8Buffer(flatStr, span.To(0));
size_t dstlen = JS::DeflateStringToUTF8Buffer(linearStr, span.To(0));
CHECK_EQUAL(memcmp(actual, expected, sizeof(expected)), 0);
CHECK_EQUAL(dstlen, 0u);
}

View File

@ -13,28 +13,28 @@ BEGIN_TEST(testIntString_bug515273) {
EVAL("'1';", &v);
JSString* str = v.toString();
CHECK(JS_StringHasBeenPinned(cx, str));
CHECK(JS_FlatStringEqualsLiteral(JS_ASSERT_STRING_IS_FLAT(str), "1"));
CHECK(JS_LinearStringEqualsLiteral(JS_ASSERT_STRING_IS_LINEAR(str), "1"));
EVAL("'42';", &v);
str = v.toString();
CHECK(JS_StringHasBeenPinned(cx, str));
CHECK(JS_FlatStringEqualsLiteral(JS_ASSERT_STRING_IS_FLAT(str), "42"));
CHECK(JS_LinearStringEqualsLiteral(JS_ASSERT_STRING_IS_LINEAR(str), "42"));
EVAL("'111';", &v);
str = v.toString();
CHECK(JS_StringHasBeenPinned(cx, str));
CHECK(JS_FlatStringEqualsLiteral(JS_ASSERT_STRING_IS_FLAT(str), "111"));
CHECK(JS_LinearStringEqualsLiteral(JS_ASSERT_STRING_IS_LINEAR(str), "111"));
/* Test other types of static strings. */
EVAL("'a';", &v);
str = v.toString();
CHECK(JS_StringHasBeenPinned(cx, str));
CHECK(JS_FlatStringEqualsLiteral(JS_ASSERT_STRING_IS_FLAT(str), "a"));
CHECK(JS_LinearStringEqualsLiteral(JS_ASSERT_STRING_IS_LINEAR(str), "a"));
EVAL("'bc';", &v);
str = v.toString();
CHECK(JS_StringHasBeenPinned(cx, str));
CHECK(JS_FlatStringEqualsLiteral(JS_ASSERT_STRING_IS_FLAT(str), "bc"));
CHECK(JS_LinearStringEqualsLiteral(JS_ASSERT_STRING_IS_LINEAR(str), "bc"));
return true;
}

View File

@ -49,11 +49,11 @@ bool document_resolve(JSContext* cx, JS::HandleObject obj, JS::HandleId id,
if (v.isString()) {
JSString* str = v.toString();
JSFlatString* flatStr = JS_FlattenString(cx, str);
if (!flatStr) {
JSLinearString* linearStr = JS_EnsureLinearString(cx, str);
if (!linearStr) {
return false;
}
if (JS_FlatStringEqualsLiteral(flatStr, "all")) {
if (JS_LinearStringEqualsLiteral(linearStr, "all")) {
JS::Rooted<JSObject*> docAll(cx, JS_NewObject(cx, &DocumentAllClass));
if (!docAll) {
return false;

View File

@ -57,7 +57,8 @@ BEGIN_TEST(testGetRegExpSource) {
obj = val.toObjectOrNull();
JSString* source = JS::GetRegExpSource(cx, obj);
CHECK(source);
CHECK(JS_FlatStringEqualsLiteral(JS_ASSERT_STRING_IS_FLAT(source), "foopy"));
CHECK(JS_LinearStringEqualsLiteral(JS_ASSERT_STRING_IS_LINEAR(source),
"foopy"));
return true;
}

View File

@ -70,10 +70,10 @@ bool doResolve(JS::HandleObject obj, JS::HandleId id, bool* resolvedp) {
CHECK(JSID_IS_STRING(id));
JSFlatString* str = JS_FlattenString(cx, JSID_TO_STRING(id));
JSLinearString* str = JS_EnsureLinearString(cx, JSID_TO_STRING(id));
CHECK(str);
JS::RootedValue v(cx);
if (JS_FlatStringEqualsLiteral(str, "x")) {
if (JS_LinearStringEqualsLiteral(str, "x")) {
if (obj == obj1) {
/* First resolve hook invocation. */
CHECK_EQUAL(resolveEntryCount, 1);
@ -89,7 +89,7 @@ bool doResolve(JS::HandleObject obj, JS::HandleId id, bool* resolvedp) {
*resolvedp = false;
return true;
}
} else if (JS_FlatStringEqualsLiteral(str, "y")) {
} else if (JS_LinearStringEqualsLiteral(str, "y")) {
if (obj == obj2) {
CHECK_EQUAL(resolveEntryCount, 2);
CHECK(JS_DefinePropertyById(cx, obj, id, JS::NullHandleValue,

View File

@ -14,7 +14,7 @@
#include <stddef.h> // size_t
#include <stdint.h> // uint32_t
#include "jsapi.h" // JS_FlattenString, JS_GC, JS_Get{Latin1,TwoByte}FlatStringChars, JS_GetStringLength, JS_ValueToFunction
#include "jsapi.h" // JS_EnsureLinearString, JS_GC, JS_Get{Latin1,TwoByte}LinearStringChars, JS_GetStringLength, JS_ValueToFunction
#include "js/CompilationAndEvaluation.h" // JS::Evaluate{,DontInflate}
#include "js/CompileOptions.h" // JS::CompileOptions
@ -162,8 +162,8 @@ static JSString* DecompressSource(JSContext* cx, JS::Handle<JSFunction*> fun) {
static bool IsExpectedFunctionString(JS::Handle<JSString*> str,
char functionName, JSContext* cx) {
JSFlatString* fstr = JS_FlattenString(cx, str);
MOZ_RELEASE_ASSERT(fstr);
JSLinearString* lstr = JS_EnsureLinearString(cx, str);
MOZ_RELEASE_ASSERT(lstr);
size_t len = JS_GetStringLength(str);
if (len < FunctionStartLength || len < FunctionEndLength) {
@ -194,10 +194,10 @@ static bool IsExpectedFunctionString(JS::Handle<JSString*> str,
bool hasExpectedContents;
if (JS_StringHasLatin1Chars(str)) {
const JS::Latin1Char* chars = JS_GetLatin1FlatStringChars(nogc, fstr);
const JS::Latin1Char* chars = JS_GetLatin1LinearStringChars(nogc, lstr);
hasExpectedContents = CheckContents(chars);
} else {
const char16_t* chars = JS_GetTwoByteFlatStringChars(nogc, fstr);
const char16_t* chars = JS_GetTwoByteLinearStringChars(nogc, lstr);
hasExpectedContents = CheckContents(chars);
}

View File

@ -19,7 +19,7 @@ class CustomProxyHandler : public Wrapper {
JSContext* cx, HandleObject proxy, HandleId id,
MutableHandle<PropertyDescriptor> desc) const override {
if (JSID_IS_STRING(id) &&
JS_FlatStringEqualsLiteral(JSID_TO_FLAT_STRING(id), "phantom")) {
JS_LinearStringEqualsLiteral(JSID_TO_LINEAR_STRING(id), "phantom")) {
desc.object().set(proxy);
desc.attributesRef() = JSPROP_ENUMERATE;
desc.value().setInt32(42);

View File

@ -3273,7 +3273,7 @@ JS_PUBLIC_API JSFunction* JS::NewFunctionFromSpec(JSContext* cx,
id);
} else {
MOZ_ASSERT(JSID_IS_STRING(id) &&
StringEqualsAscii(JSID_TO_FLAT_STRING(id), fs->name.string()));
StringEqualsAscii(JSID_TO_LINEAR_STRING(id), fs->name.string()));
}
#endif
@ -4310,7 +4310,7 @@ JS_PUBLIC_API JSString* JS_AtomizeAndPinUCString(JSContext* cx,
JS_PUBLIC_API size_t JS_GetStringLength(JSString* str) { return str->length(); }
JS_PUBLIC_API bool JS_StringIsFlat(JSString* str) { return str->isFlat(); }
JS_PUBLIC_API bool JS_StringIsLinear(JSString* str) { return str->isLinear(); }
JS_PUBLIC_API bool JS_StringHasLatin1Chars(JSString* str) {
return str->hasLatin1Chars();
@ -4365,7 +4365,8 @@ JS_PUBLIC_API bool JS_GetStringCharAt(JSContext* cx, JSString* str,
return true;
}
JS_PUBLIC_API char16_t JS_GetFlatStringCharAt(JSFlatString* str, size_t index) {
JS_PUBLIC_API char16_t JS_GetLinearStringCharAt(JSLinearString* str,
size_t index) {
return str->latin1OrTwoByteChar(index);
}
@ -4386,45 +4387,48 @@ JS_PUBLIC_API bool JS_CopyStringChars(JSContext* cx,
return true;
}
JS_PUBLIC_API const Latin1Char* JS_GetLatin1InternedStringChars(
const JS::AutoRequireNoGC& nogc, JSString* str) {
MOZ_ASSERT(str->isAtom());
JSFlatString* flat = str->ensureFlat(nullptr);
if (!flat) {
return nullptr;
}
return flat->latin1Chars(nogc);
}
JS_PUBLIC_API const char16_t* JS_GetTwoByteInternedStringChars(
const JS::AutoRequireNoGC& nogc, JSString* str) {
MOZ_ASSERT(str->isAtom());
JSFlatString* flat = str->ensureFlat(nullptr);
if (!flat) {
return nullptr;
}
return flat->twoByteChars(nogc);
}
extern JS_PUBLIC_API JSFlatString* JS_FlattenString(JSContext* cx,
JSString* str) {
extern JS_PUBLIC_API JS::UniqueTwoByteChars JS_CopyStringCharsZ(JSContext* cx,
JSString* str) {
AssertHeapIsIdle();
CHECK_THREAD(cx);
cx->check(str);
JSFlatString* flat = str->ensureFlat(cx);
if (!flat) {
JSLinearString* linear = str->ensureLinear(cx);
if (!linear) {
return nullptr;
}
return flat;
size_t len = linear->length();
static_assert(js::MaxStringLength < UINT32_MAX,
"len + 1 must not overflow on 32-bit platforms");
UniqueTwoByteChars chars(cx->pod_malloc<char16_t>(len + 1));
if (!chars) {
return nullptr;
}
CopyChars(chars.get(), *linear);
chars[len] = '\0';
return chars;
}
extern JS_PUBLIC_API const Latin1Char* JS_GetLatin1FlatStringChars(
const JS::AutoRequireNoGC& nogc, JSFlatString* str) {
extern JS_PUBLIC_API JSLinearString* JS_EnsureLinearString(JSContext* cx,
JSString* str) {
AssertHeapIsIdle();
CHECK_THREAD(cx);
cx->check(str);
return str->ensureLinear(cx);
}
extern JS_PUBLIC_API const Latin1Char* JS_GetLatin1LinearStringChars(
const JS::AutoRequireNoGC& nogc, JSLinearString* str) {
return str->latin1Chars(nogc);
}
extern JS_PUBLIC_API const char16_t* JS_GetTwoByteFlatStringChars(
const JS::AutoRequireNoGC& nogc, JSFlatString* str) {
extern JS_PUBLIC_API const char16_t* JS_GetTwoByteLinearStringChars(
const JS::AutoRequireNoGC& nogc, JSLinearString* str) {
return str->twoByteChars(nogc);
}
@ -4463,19 +4467,20 @@ JS_PUBLIC_API bool JS_StringEqualsAscii(JSContext* cx, JSString* str,
return true;
}
JS_PUBLIC_API bool JS_FlatStringEqualsAscii(JSFlatString* str,
const char* asciiBytes) {
JS_PUBLIC_API bool JS_LinearStringEqualsAscii(JSLinearString* str,
const char* asciiBytes) {
return StringEqualsAscii(str, asciiBytes);
}
JS_PUBLIC_API bool JS_FlatStringEqualsAscii(JSFlatString* str,
const char* asciiBytes,
size_t length) {
JS_PUBLIC_API bool JS_LinearStringEqualsAscii(JSLinearString* str,
const char* asciiBytes,
size_t length) {
return StringEqualsAscii(str, asciiBytes, length);
}
JS_PUBLIC_API size_t JS_PutEscapedFlatString(char* buffer, size_t size,
JSFlatString* str, char quote) {
JS_PUBLIC_API size_t JS_PutEscapedLinearString(char* buffer, size_t size,
JSLinearString* str,
char quote) {
return PutEscapedString(buffer, size, str, quote);
}
@ -4659,7 +4664,7 @@ JS_PUBLIC_API bool JS::PropertySpecNameEqualsId(JSPropertySpec::Name name,
MOZ_ASSERT(!PropertySpecNameIsDigits(name));
return JSID_IS_ATOM(id) &&
JS_FlatStringEqualsAscii(JSID_TO_ATOM(id), name.string());
JS_LinearStringEqualsAscii(JSID_TO_ATOM(id), name.string());
}
JS_PUBLIC_API bool JS_Stringify(JSContext* cx, MutableHandleValue vp,

View File

@ -2315,28 +2315,28 @@ extern JS_PUBLIC_API size_t JS_PutEscapedString(JSContext* cx, char* buffer,
* The first case is for strings that have been atomized, e.g. directly by
* JS_AtomizeAndPinString or implicitly because it is stored in a jsid.
*
* The second case is "flat" strings that have been explicitly prepared in a
* fallible context by JS_FlattenString. To catch errors, a separate opaque
* JSFlatString type is returned by JS_FlattenString and expected by
* JS_GetFlatStringChars. Note, though, that this is purely a syntactic
* distinction: the input and output of JS_FlattenString are the same actual
* GC-thing. If a JSString is known to be flat, JS_ASSERT_STRING_IS_FLAT can be
* used to make a debug-checked cast. Example:
* The second case is "linear" strings that have been explicitly prepared in a
* fallible context by JS_EnsureLinearString. To catch errors, a separate opaque
* JSLinearString type is returned by JS_EnsureLinearString and expected by
* JS_Get{Latin1,TwoByte}StringCharsAndLength. Note, though, that this is purely
* a syntactic distinction: the input and output of JS_EnsureLinearString are
* the same actual GC-thing. If a JSString is known to be linear,
* JS_ASSERT_STRING_IS_LINEAR can be used to make a debug-checked cast. Example:
*
* // in a fallible context
* JSFlatString* fstr = JS_FlattenString(cx, str);
* if (!fstr) {
* // In a fallible context.
* JSLinearString* lstr = JS_EnsureLinearString(cx, str);
* if (!lstr) {
* return false;
* }
* MOZ_ASSERT(fstr == JS_ASSERT_STRING_IS_FLAT(str));
* MOZ_ASSERT(lstr == JS_ASSERT_STRING_IS_LINEAR(str));
*
* // in an infallible context, for the same 'str'
* // In an infallible context, for the same 'str'.
* AutoCheckCannotGC nogc;
* const char16_t* chars = JS_GetTwoByteFlatStringChars(nogc, fstr)
* const char16_t* chars = JS_GetTwoByteLinearStringChars(nogc, lstr)
* MOZ_ASSERT(chars);
*
* Flat strings and interned strings are always null-terminated, so
* JS_FlattenString can be used to get a null-terminated string.
* Note: JS strings (including linear strings and atoms) are not
* null-terminated!
*
* Additionally, string characters are stored as either Latin1Char (8-bit)
* or char16_t (16-bit). Clients can use JS_StringHasLatin1Chars and can then
@ -2347,7 +2347,7 @@ extern JS_PUBLIC_API size_t JS_PutEscapedString(JSContext* cx, char* buffer,
extern JS_PUBLIC_API size_t JS_GetStringLength(JSString* str);
extern JS_PUBLIC_API bool JS_StringIsFlat(JSString* str);
extern JS_PUBLIC_API bool JS_StringIsLinear(JSString* str);
/** Returns true iff the string's characters are stored as Latin1. */
extern JS_PUBLIC_API bool JS_StringHasLatin1Chars(JSString* str);
@ -2363,8 +2363,8 @@ extern JS_PUBLIC_API const char16_t* JS_GetTwoByteStringCharsAndLength(
extern JS_PUBLIC_API bool JS_GetStringCharAt(JSContext* cx, JSString* str,
size_t index, char16_t* res);
extern JS_PUBLIC_API char16_t JS_GetFlatStringCharAt(JSFlatString* str,
size_t index);
extern JS_PUBLIC_API char16_t JS_GetLinearStringCharAt(JSLinearString* str,
size_t index);
extern JS_PUBLIC_API const char16_t* JS_GetTwoByteExternalStringChars(
JSString* str);
@ -2373,50 +2373,59 @@ extern JS_PUBLIC_API bool JS_CopyStringChars(JSContext* cx,
mozilla::Range<char16_t> dest,
JSString* str);
extern JS_PUBLIC_API JSFlatString* JS_FlattenString(JSContext* cx,
JSString* str);
/**
* Copies the string's characters to a null-terminated char16_t buffer.
*
* Returns nullptr on OOM.
*/
extern JS_PUBLIC_API JS::UniqueTwoByteChars JS_CopyStringCharsZ(JSContext* cx,
JSString* str);
extern JS_PUBLIC_API const JS::Latin1Char* JS_GetLatin1FlatStringChars(
const JS::AutoRequireNoGC& nogc, JSFlatString* str);
extern JS_PUBLIC_API JSLinearString* JS_EnsureLinearString(JSContext* cx,
JSString* str);
extern JS_PUBLIC_API const char16_t* JS_GetTwoByteFlatStringChars(
const JS::AutoRequireNoGC& nogc, JSFlatString* str);
extern JS_PUBLIC_API const JS::Latin1Char* JS_GetLatin1LinearStringChars(
const JS::AutoRequireNoGC& nogc, JSLinearString* str);
static MOZ_ALWAYS_INLINE JSFlatString* JSID_TO_FLAT_STRING(jsid id) {
extern JS_PUBLIC_API const char16_t* JS_GetTwoByteLinearStringChars(
const JS::AutoRequireNoGC& nogc, JSLinearString* str);
static MOZ_ALWAYS_INLINE JSLinearString* JSID_TO_LINEAR_STRING(jsid id) {
MOZ_ASSERT(JSID_IS_STRING(id));
return (JSFlatString*)JSID_TO_STRING(id);
return reinterpret_cast<JSLinearString*>(JSID_TO_STRING(id));
}
static MOZ_ALWAYS_INLINE JSFlatString* JS_ASSERT_STRING_IS_FLAT(JSString* str) {
MOZ_ASSERT(JS_StringIsFlat(str));
return (JSFlatString*)str;
static MOZ_ALWAYS_INLINE JSLinearString* JS_ASSERT_STRING_IS_LINEAR(
JSString* str) {
MOZ_ASSERT(JS_StringIsLinear(str));
return reinterpret_cast<JSLinearString*>(str);
}
static MOZ_ALWAYS_INLINE JSString* JS_FORGET_STRING_FLATNESS(
JSFlatString* fstr) {
return (JSString*)fstr;
static MOZ_ALWAYS_INLINE JSString* JS_FORGET_STRING_LINEARNESS(
JSLinearString* str) {
return reinterpret_cast<JSString*>(str);
}
/*
* Additional APIs that avoid fallibility when given a flat string.
* Additional APIs that avoid fallibility when given a linear string.
*/
extern JS_PUBLIC_API bool JS_FlatStringEqualsAscii(JSFlatString* str,
const char* asciiBytes);
extern JS_PUBLIC_API bool JS_FlatStringEqualsAscii(JSFlatString* str,
const char* asciiBytes,
size_t length);
extern JS_PUBLIC_API bool JS_LinearStringEqualsAscii(JSLinearString* str,
const char* asciiBytes);
extern JS_PUBLIC_API bool JS_LinearStringEqualsAscii(JSLinearString* str,
const char* asciiBytes,
size_t length);
template <size_t N>
bool JS_FlatStringEqualsLiteral(JSFlatString* str,
const char (&asciiBytes)[N]) {
bool JS_LinearStringEqualsLiteral(JSLinearString* str,
const char (&asciiBytes)[N]) {
MOZ_ASSERT(asciiBytes[N - 1] == '\0');
return JS_FlatStringEqualsAscii(str, asciiBytes, N - 1);
return JS_LinearStringEqualsAscii(str, asciiBytes, N - 1);
}
extern JS_PUBLIC_API size_t JS_PutEscapedFlatString(char* buffer, size_t size,
JSFlatString* str,
char quote);
extern JS_PUBLIC_API size_t JS_PutEscapedLinearString(char* buffer, size_t size,
JSLinearString* str,
char quote);
/**
* Create a dependent string, i.e., a string that owns no character storage,

View File

@ -594,8 +594,8 @@ JSObject* ErrorObject::createConstructor(JSContext* cx, JSProtoKey key) {
return ctor;
}
JS_FRIEND_API JSFlatString* js::GetErrorTypeName(JSContext* cx,
int16_t exnType) {
JS_FRIEND_API JSLinearString* js::GetErrorTypeName(JSContext* cx,
int16_t exnType) {
/*
* JSEXN_INTERNALERR returns null to prevent that "InternalError: "
* is prepended before "uncaught exception: "

View File

@ -756,10 +756,6 @@ static_assert((uint64_t(MaxStringLength) + 1) * sizeof(char16_t) <= INT32_MAX,
"size of null-terminated JSString char buffer must fit in "
"INT32_MAX");
MOZ_ALWAYS_INLINE size_t GetFlatStringLength(JSFlatString* s) {
return reinterpret_cast<JS::shadow::String*>(s)->length();
}
MOZ_ALWAYS_INLINE size_t GetLinearStringLength(JSLinearString* s) {
return reinterpret_cast<JS::shadow::String*>(s)->length();
}
@ -807,14 +803,6 @@ MOZ_ALWAYS_INLINE JSLinearString* AtomToLinearString(JSAtom* atom) {
return reinterpret_cast<JSLinearString*>(atom);
}
MOZ_ALWAYS_INLINE JSFlatString* AtomToFlatString(JSAtom* atom) {
return reinterpret_cast<JSFlatString*>(atom);
}
MOZ_ALWAYS_INLINE JSLinearString* FlatStringToLinearString(JSFlatString* s) {
return reinterpret_cast<JSLinearString*>(s);
}
MOZ_ALWAYS_INLINE const JS::Latin1Char* GetLatin1AtomChars(
const JS::AutoRequireNoGC& nogc, JSAtom* atom) {
return GetLatin1LinearStringChars(nogc, AtomToLinearString(atom));
@ -902,10 +890,6 @@ inline bool CopyStringChars(JSContext* cx, CharType* dest, JSString* s,
return true;
}
inline void CopyFlatStringChars(char16_t* dest, JSFlatString* s, size_t len) {
CopyLinearStringChars(dest, FlatStringToLinearString(s), len);
}
/**
* Add some or all property keys of obj to the id vector *props.
*
@ -1136,8 +1120,8 @@ extern JS_FRIEND_API JSObject* GetTestingFunctions(JSContext* cx);
* Get an error type name from a JSExnType constant.
* Returns nullptr for invalid arguments and JSEXN_INTERNALERR
*/
extern JS_FRIEND_API JSFlatString* GetErrorTypeName(JSContext* cx,
int16_t exnType);
extern JS_FRIEND_API JSLinearString* GetErrorTypeName(JSContext* cx,
int16_t exnType);
extern JS_FRIEND_API RegExpShared* RegExpToSharedNonInline(
JSContext* cx, JS::HandleObject regexp);

View File

@ -65,7 +65,7 @@ struct JSStructuredCloneReader;
struct JSStructuredCloneWriter;
class JS_PUBLIC_API JSTracer;
class JSFlatString;
class JSLinearString;
template <typename T>
struct JSConstScalarSpec;

View File

@ -3358,15 +3358,15 @@ struct DisassembleOptionParser {
/* Read options off early arguments */
while (argc > 0 && argv[0].isString()) {
JSString* str = argv[0].toString();
JSFlatString* flatStr = JS_FlattenString(cx, str);
if (!flatStr) {
JSLinearString* linearStr = JS_EnsureLinearString(cx, str);
if (!linearStr) {
return false;
}
if (JS_FlatStringEqualsLiteral(flatStr, "-l")) {
if (JS_LinearStringEqualsLiteral(linearStr, "-l")) {
lines = true;
} else if (JS_FlatStringEqualsLiteral(flatStr, "-r")) {
} else if (JS_LinearStringEqualsLiteral(linearStr, "-r")) {
recursive = true;
} else if (JS_FlatStringEqualsLiteral(flatStr, "-S")) {
} else if (JS_LinearStringEqualsLiteral(linearStr, "-S")) {
sourceNotes = false;
} else {
break;
@ -4542,13 +4542,13 @@ static bool SetJitCompilerOption(JSContext* cx, unsigned argc, Value* vp) {
return false;
}
JSFlatString* strArg = JS_FlattenString(cx, args[0].toString());
JSLinearString* strArg = JS_EnsureLinearString(cx, args[0].toString());
if (!strArg) {
return false;
}
#define JIT_COMPILER_MATCH(key, string) \
else if (JS_FlatStringEqualsLiteral(strArg, string)) opt = \
#define JIT_COMPILER_MATCH(key, string) \
else if (JS_LinearStringEqualsLiteral(strArg, string)) opt = \
JSJITCOMPILER_##key;
JSJitCompilerOption opt = JSJITCOMPILER_NOT_AN_OPTION;

View File

@ -72,8 +72,7 @@ bool GenerateInterfaceHelp(JSContext* cx, HandleObject obj, const char* name) {
return false;
}
if (!buf.append(usage.isString() ? usage.toString()
: JSID_TO_FLAT_STRING(id))) {
if (!buf.append(usage.isString() ? usage.toString() : JSID_TO_STRING(id))) {
return false;
}
}

View File

@ -87,7 +87,7 @@ static size_t GetDeflatedUTF8StringLength(const CharT* chars, size_t nchars) {
return nbytes;
}
JS_PUBLIC_API size_t JS::GetDeflatedUTF8StringLength(JSFlatString* s) {
JS_PUBLIC_API size_t JS::GetDeflatedUTF8StringLength(JSLinearString* s) {
JS::AutoCheckCannotGC nogc;
return s->hasLatin1Chars()
? ::GetDeflatedUTF8StringLength(s->latin1Chars(nogc), s->length())
@ -95,7 +95,7 @@ JS_PUBLIC_API size_t JS::GetDeflatedUTF8StringLength(JSFlatString* s) {
s->length());
}
JS_PUBLIC_API size_t JS::DeflateStringToUTF8Buffer(JSFlatString* src,
JS_PUBLIC_API size_t JS::DeflateStringToUTF8Buffer(JSLinearString* src,
mozilla::Span<char> dst) {
JS::AutoCheckCannotGC nogc;
if (src->hasLatin1Chars()) {

View File

@ -80,7 +80,7 @@ const char* js::TypeIdStringImpl(jsid id) {
static char bufs[4][100];
static unsigned which = 0;
which = (which + 1) & 3;
PutEscapedString(bufs[which], 100, JSID_TO_FLAT_STRING(id), 0);
PutEscapedString(bufs[which], 100, JSID_TO_LINEAR_STRING(id), 0);
return bufs[which];
}

View File

@ -816,68 +816,68 @@ bool xpc::GlobalProperties::Parse(JSContext* cx, JS::HandleObject obj) {
JS_ReportErrorASCII(cx, "Property names must be strings");
return false;
}
JSFlatString* nameStr = JS_FlattenString(cx, nameValue.toString());
JSLinearString* nameStr = JS_EnsureLinearString(cx, nameValue.toString());
if (!nameStr) {
return false;
}
if (JS_FlatStringEqualsLiteral(nameStr, "Blob")) {
if (JS_LinearStringEqualsLiteral(nameStr, "Blob")) {
Blob = true;
} else if (JS_FlatStringEqualsLiteral(nameStr, "ChromeUtils")) {
} else if (JS_LinearStringEqualsLiteral(nameStr, "ChromeUtils")) {
ChromeUtils = true;
} else if (JS_FlatStringEqualsLiteral(nameStr, "CSS")) {
} else if (JS_LinearStringEqualsLiteral(nameStr, "CSS")) {
CSS = true;
} else if (JS_FlatStringEqualsLiteral(nameStr, "CSSRule")) {
} else if (JS_LinearStringEqualsLiteral(nameStr, "CSSRule")) {
CSSRule = true;
} else if (JS_FlatStringEqualsLiteral(nameStr, "Directory")) {
} else if (JS_LinearStringEqualsLiteral(nameStr, "Directory")) {
Directory = true;
} else if (JS_FlatStringEqualsLiteral(nameStr, "DOMParser")) {
} else if (JS_LinearStringEqualsLiteral(nameStr, "DOMParser")) {
DOMParser = true;
} else if (JS_FlatStringEqualsLiteral(nameStr, "Element")) {
} else if (JS_LinearStringEqualsLiteral(nameStr, "Element")) {
Element = true;
} else if (JS_FlatStringEqualsLiteral(nameStr, "Event")) {
} else if (JS_LinearStringEqualsLiteral(nameStr, "Event")) {
Event = true;
} else if (JS_FlatStringEqualsLiteral(nameStr, "File")) {
} else if (JS_LinearStringEqualsLiteral(nameStr, "File")) {
File = true;
} else if (JS_FlatStringEqualsLiteral(nameStr, "FileReader")) {
} else if (JS_LinearStringEqualsLiteral(nameStr, "FileReader")) {
FileReader = true;
} else if (JS_FlatStringEqualsLiteral(nameStr, "FormData")) {
} else if (JS_LinearStringEqualsLiteral(nameStr, "FormData")) {
FormData = true;
} else if (JS_FlatStringEqualsLiteral(nameStr, "InspectorUtils")) {
} else if (JS_LinearStringEqualsLiteral(nameStr, "InspectorUtils")) {
InspectorUtils = true;
} else if (JS_FlatStringEqualsLiteral(nameStr, "MessageChannel")) {
} else if (JS_LinearStringEqualsLiteral(nameStr, "MessageChannel")) {
MessageChannel = true;
} else if (JS_FlatStringEqualsLiteral(nameStr, "Node")) {
} else if (JS_LinearStringEqualsLiteral(nameStr, "Node")) {
Node = true;
} else if (JS_FlatStringEqualsLiteral(nameStr, "NodeFilter")) {
} else if (JS_LinearStringEqualsLiteral(nameStr, "NodeFilter")) {
NodeFilter = true;
} else if (JS_FlatStringEqualsLiteral(nameStr, "PromiseDebugging")) {
} else if (JS_LinearStringEqualsLiteral(nameStr, "PromiseDebugging")) {
PromiseDebugging = true;
} else if (JS_FlatStringEqualsLiteral(nameStr, "TextDecoder")) {
} else if (JS_LinearStringEqualsLiteral(nameStr, "TextDecoder")) {
TextDecoder = true;
} else if (JS_FlatStringEqualsLiteral(nameStr, "TextEncoder")) {
} else if (JS_LinearStringEqualsLiteral(nameStr, "TextEncoder")) {
TextEncoder = true;
} else if (JS_FlatStringEqualsLiteral(nameStr, "URL")) {
} else if (JS_LinearStringEqualsLiteral(nameStr, "URL")) {
URL = true;
} else if (JS_FlatStringEqualsLiteral(nameStr, "URLSearchParams")) {
} else if (JS_LinearStringEqualsLiteral(nameStr, "URLSearchParams")) {
URLSearchParams = true;
} else if (JS_FlatStringEqualsLiteral(nameStr, "XMLHttpRequest")) {
} else if (JS_LinearStringEqualsLiteral(nameStr, "XMLHttpRequest")) {
XMLHttpRequest = true;
} else if (JS_FlatStringEqualsLiteral(nameStr, "XMLSerializer")) {
} else if (JS_LinearStringEqualsLiteral(nameStr, "XMLSerializer")) {
XMLSerializer = true;
} else if (JS_FlatStringEqualsLiteral(nameStr, "atob")) {
} else if (JS_LinearStringEqualsLiteral(nameStr, "atob")) {
atob = true;
} else if (JS_FlatStringEqualsLiteral(nameStr, "btoa")) {
} else if (JS_LinearStringEqualsLiteral(nameStr, "btoa")) {
btoa = true;
} else if (JS_FlatStringEqualsLiteral(nameStr, "caches")) {
} else if (JS_LinearStringEqualsLiteral(nameStr, "caches")) {
caches = true;
} else if (JS_FlatStringEqualsLiteral(nameStr, "crypto")) {
} else if (JS_LinearStringEqualsLiteral(nameStr, "crypto")) {
crypto = true;
} else if (JS_FlatStringEqualsLiteral(nameStr, "fetch")) {
} else if (JS_LinearStringEqualsLiteral(nameStr, "fetch")) {
fetch = true;
} else if (JS_FlatStringEqualsLiteral(nameStr, "indexedDB")) {
} else if (JS_LinearStringEqualsLiteral(nameStr, "indexedDB")) {
indexedDB = true;
#ifdef MOZ_WEBRTC
} else if (JS_FlatStringEqualsLiteral(nameStr, "rtcIdentityProvider")) {
} else if (JS_LinearStringEqualsLiteral(nameStr, "rtcIdentityProvider")) {
rtcIdentityProvider = true;
#endif
} else {

View File

@ -709,16 +709,16 @@ bool XPCConvert::JSData2Native(JSContext* cx, void* d, HandleValue s,
return true;
}
JSFlatString* flat = JS_FlattenString(cx, str);
if (!flat) {
JSLinearString* linear = JS_EnsureLinearString(cx, str);
if (!linear) {
return false;
}
size_t utf8Length = JS::GetDeflatedUTF8StringLength(flat);
size_t utf8Length = JS::GetDeflatedUTF8StringLength(linear);
rs->SetLength(utf8Length);
mozilla::DebugOnly<size_t> written = JS::DeflateStringToUTF8Buffer(
flat, mozilla::MakeSpan(rs->BeginWriting(), utf8Length));
linear, mozilla::MakeSpan(rs->BeginWriting(), utf8Length));
MOZ_ASSERT(written == utf8Length);
return true;

View File

@ -380,10 +380,10 @@ void xpc::ErrorReport::ErrorReportToMessageString(JSErrorReport* aReport,
nsAString& aString) {
aString.Truncate();
if (aReport->message()) {
JSFlatString* name = js::GetErrorTypeName(
JSLinearString* name = js::GetErrorTypeName(
CycleCollectedJSContext::Get()->Context(), aReport->exnType);
if (name) {
AssignJSFlatString(aString, name);
AssignJSLinearString(aString, name);
aString.AppendLiteral(": ");
}
aString.Append(NS_ConvertUTF8toUTF16(aReport->message().c_str()));
@ -470,10 +470,11 @@ JSObject* CreateGlobalObject(JSContext* cx, const JSClass* clasp,
#endif
const char* className = clasp->name;
AllocateProtoAndIfaceCache(global, (strcmp(className, "Window") == 0 ||
strcmp(className, "ChromeWindow") == 0)
? ProtoAndIfaceCache::WindowLike
: ProtoAndIfaceCache::NonWindowLike);
AllocateProtoAndIfaceCache(global,
(strcmp(className, "Window") == 0 ||
strcmp(className, "ChromeWindow") == 0)
? ProtoAndIfaceCache::WindowLike
: ProtoAndIfaceCache::NonWindowLike);
}
}

View File

@ -114,7 +114,7 @@ AsyncStatementJSHelper::Resolve(nsIXPConnectWrappedNative* aWrapper,
}
#endif
if (::JS_FlatStringEqualsLiteral(JSID_TO_FLAT_STRING(id), "params")) {
if (::JS_LinearStringEqualsLiteral(JSID_TO_LINEAR_STRING(id), "params")) {
JS::RootedValue val(aCtx);
nsresult rv = getParams(stmt, aCtx, scope, val.address());
NS_ENSURE_SUCCESS(rv, rv);

View File

@ -206,8 +206,8 @@ StatementJSHelper::Resolve(nsIXPConnectWrappedNative* aWrapper, JSContext* aCtx,
Statement* stmt = static_cast<Statement*>(
static_cast<mozIStorageStatement*>(aWrapper->Native()));
JSFlatString* str = JSID_TO_FLAT_STRING(id);
if (::JS_FlatStringEqualsLiteral(str, "step")) {
JSLinearString* str = JSID_TO_LINEAR_STRING(id);
if (::JS_LinearStringEqualsLiteral(str, "step")) {
*_retval = ::JS_DefineFunction(aCtx, scope, "step", stepFunc, 0,
JSPROP_RESOLVING) != nullptr;
*aResolvedp = true;
@ -216,7 +216,7 @@ StatementJSHelper::Resolve(nsIXPConnectWrappedNative* aWrapper, JSContext* aCtx,
JS::RootedValue val(aCtx);
if (::JS_FlatStringEqualsLiteral(str, "row")) {
if (::JS_LinearStringEqualsLiteral(str, "row")) {
nsresult rv = getRow(stmt, aCtx, scope, val.address());
NS_ENSURE_SUCCESS(rv, rv);
*_retval = ::JS_DefinePropertyById(aCtx, scope, id, val, JSPROP_RESOLVING);
@ -224,7 +224,7 @@ StatementJSHelper::Resolve(nsIXPConnectWrappedNative* aWrapper, JSContext* aCtx,
return NS_OK;
}
if (::JS_FlatStringEqualsLiteral(str, "params")) {
if (::JS_LinearStringEqualsLiteral(str, "params")) {
nsresult rv = getParams(stmt, aCtx, scope, val.address());
NS_ENSURE_SUCCESS(rv, rv);
*_retval = ::JS_DefinePropertyById(aCtx, scope, id, val, JSPROP_RESOLVING);

View File

@ -599,7 +599,8 @@ static bool FetchContent(JSContext* aCx, HandleString aURL,
// the HTML itself and for each inline script.
ContentInfo* best = nullptr;
for (ContentInfo& info : gContent) {
if (JS_FlatStringEqualsAscii(JS_ASSERT_STRING_IS_FLAT(aURL), info.mURL)) {
if (JS_LinearStringEqualsAscii(JS_ASSERT_STRING_IS_LINEAR(aURL),
info.mURL)) {
if (!best || info.Length() > best->Length()) {
best = &info;
}

View File

@ -564,8 +564,8 @@ static void StreamJITFrameOptimizations(
if (JSAtom* name = js::GetPropertyNameFromPC(script, pc)) {
char buf[512];
JS_PutEscapedFlatString(buf, ArrayLength(buf), js::AtomToFlatString(name),
0);
JS_PutEscapedLinearString(buf, ArrayLength(buf),
js::AtomToLinearString(name), 0);
aUniqueStrings.WriteProperty(aWriter, "propertyName", buf);
}

View File

@ -629,9 +629,9 @@ void CycleCollectedJSRuntime::DescribeGCThing(
JSFunction* fun = JS_GetObjectFunction(obj);
JSString* str = JS_GetFunctionDisplayId(fun);
if (str) {
JSFlatString* flat = JS_ASSERT_STRING_IS_FLAT(str);
JSLinearString* linear = JS_ASSERT_STRING_IS_LINEAR(str);
nsAutoString chars;
AssignJSFlatString(chars, flat);
AssignJSLinearString(chars, linear);
NS_ConvertUTF16toUTF8 fname(chars);
SprintfLiteral(name, "JS Object (Function - %s)", fname.get());
} else {

View File

@ -275,9 +275,9 @@ class CGHelper(object):
'key_length': key_length,
}
def gen_jsflatstr_getter(self, name, return_type=None,
return_entry='return entry;'):
"""Generate code for a specialized getter taking JSFlatStrings.
def gen_jslinearstr_getter(self, name, return_type=None,
return_entry='return entry;'):
"""Generate code for a specialized getter taking JSLinearStrings.
This getter avoids copying the JS string, but only supports ASCII keys.
@param name Name for the entry getter function.
@ -297,23 +297,22 @@ class CGHelper(object):
return textwrap.dedent("""
%(return_type)s
%(name)s(JSFlatString* aKey)
%(name)s(JSLinearString* aKey)
{
%(basis_table)s
size_t length = js::GetFlatStringLength(aKey);
JSLinearString* jsString = js::FlatStringToLinearString(aKey);
size_t length = js::GetLinearStringLength(aKey);
JS::AutoCheckCannotGC nogc;
if (js::LinearStringHasLatin1Chars(jsString)) {
if (js::LinearStringHasLatin1Chars(aKey)) {
auto& entry = mozilla::perfecthash::Lookup(
js::GetLatin1LinearStringChars(nogc, jsString),
js::GetLatin1LinearStringChars(nogc, aKey),
length, BASES, %(entries_name)s);
%(return_entry)s
} else {
auto& entry = mozilla::perfecthash::Lookup(
js::GetTwoByteLinearStringChars(nogc, jsString),
js::GetTwoByteLinearStringChars(nogc, aKey),
length, BASES, %(entries_name)s);
%(return_entry)s