Bug 1439026 - Part 2: Move the most basic text-processing routines to util/Text.cpp. r=jandem.

Many operations on strings are also moved from builtin/String.cpp to vm/StringType.cpp.

--HG--
extra : rebase_source : 9239b1f1691962b5f1358d65eaae278780ae3f84
extra : source : cfd781da349e59c8d6b9fea7efed04a0b2124a61
This commit is contained in:
Jason Orendorff 2018-02-24 07:33:57 -06:00
Родитель 53395c4474
Коммит 4d670d3ab3
41 изменённых файлов: 1059 добавлений и 956 удалений

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

@ -63,10 +63,8 @@ using JS::SymbolCode;
using mozilla::CheckedInt;
using mozilla::IsNaN;
using mozilla::IsNegativeZero;
using mozilla::IsSame;
using mozilla::PodCopy;
using mozilla::PodEqual;
using mozilla::RangedPtr;
using JS::AutoCheckCannotGC;
@ -2416,29 +2414,6 @@ js::str_lastIndexOf(JSContext* cx, unsigned argc, Value* vp)
return true;
}
bool
js::HasSubstringAt(JSLinearString* text, JSLinearString* pat, size_t start)
{
MOZ_ASSERT(start + pat->length() <= text->length());
size_t patLen = pat->length();
AutoCheckCannotGC nogc;
if (text->hasLatin1Chars()) {
const Latin1Char* textChars = text->latin1Chars(nogc) + start;
if (pat->hasLatin1Chars())
return PodEqual(textChars, pat->latin1Chars(nogc), patLen);
return EqualChars(textChars, pat->twoByteChars(nogc), patLen);
}
const char16_t* textChars = text->twoByteChars(nogc) + start;
if (pat->hasTwoByteChars())
return PodEqual(textChars, pat->twoByteChars(nogc), patLen);
return EqualChars(pat->latin1Chars(nogc), textChars, patLen);
}
// ES2018 draft rev de77aaeffce115deaf948ed30c7dbe4c60983c0c
// 21.1.3.20 String.prototype.startsWith ( searchString [ , position ] )
bool
@ -3707,419 +3682,6 @@ js::InitStringClass(JSContext* cx, HandleObject obj)
return proto;
}
const char*
js::ValueToPrintable(JSContext* cx, const Value& vArg, JSAutoByteString* bytes, bool asSource)
{
RootedValue v(cx, vArg);
JSString* str;
if (asSource)
str = ValueToSource(cx, v);
else
str = ToString<CanGC>(cx, v);
if (!str)
return nullptr;
str = QuoteString(cx, str, 0);
if (!str)
return nullptr;
return bytes->encodeLatin1(cx, str);
}
template <AllowGC allowGC>
JSString*
js::ToStringSlow(JSContext* cx, typename MaybeRooted<Value, allowGC>::HandleType arg)
{
/* As with ToObjectSlow, callers must verify that |arg| isn't a string. */
MOZ_ASSERT(!arg.isString());
Value v = arg;
if (!v.isPrimitive()) {
MOZ_ASSERT(!cx->helperThread());
if (!allowGC)
return nullptr;
RootedValue v2(cx, v);
if (!ToPrimitive(cx, JSTYPE_STRING, &v2))
return nullptr;
v = v2;
}
JSString* str;
if (v.isString()) {
str = v.toString();
} else if (v.isInt32()) {
str = Int32ToString<allowGC>(cx, v.toInt32());
} else if (v.isDouble()) {
str = NumberToString<allowGC>(cx, v.toDouble());
} else if (v.isBoolean()) {
str = BooleanToString(cx, v.toBoolean());
} else if (v.isNull()) {
str = cx->names().null;
} else if (v.isSymbol()) {
MOZ_ASSERT(!cx->helperThread());
if (allowGC) {
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
JSMSG_SYMBOL_TO_STRING);
}
return nullptr;
} else {
MOZ_ASSERT(v.isUndefined());
str = cx->names().undefined;
}
return str;
}
template JSString*
js::ToStringSlow<CanGC>(JSContext* cx, HandleValue arg);
template JSString*
js::ToStringSlow<NoGC>(JSContext* cx, const Value& arg);
JS_PUBLIC_API(JSString*)
js::ToStringSlow(JSContext* cx, HandleValue v)
{
return ToStringSlow<CanGC>(cx, v);
}
static JSString*
SymbolToSource(JSContext* cx, Symbol* symbol)
{
RootedString desc(cx, symbol->description());
SymbolCode code = symbol->code();
if (code != SymbolCode::InSymbolRegistry && code != SymbolCode::UniqueSymbol) {
// Well-known symbol.
MOZ_ASSERT(uint32_t(code) < JS::WellKnownSymbolLimit);
return desc;
}
StringBuffer buf(cx);
if (code == SymbolCode::InSymbolRegistry ? !buf.append("Symbol.for(") : !buf.append("Symbol("))
return nullptr;
if (desc) {
desc = StringToSource(cx, desc);
if (!desc || !buf.append(desc))
return nullptr;
}
if (!buf.append(')'))
return nullptr;
return buf.finishString();
}
JSString*
js::ValueToSource(JSContext* cx, HandleValue v)
{
if (!CheckRecursionLimit(cx))
return nullptr;
assertSameCompartment(cx, v);
if (v.isUndefined())
return cx->names().void0;
if (v.isString())
return StringToSource(cx, v.toString());
if (v.isSymbol())
return SymbolToSource(cx, v.toSymbol());
if (v.isPrimitive()) {
/* Special case to preserve negative zero, _contra_ toString. */
if (v.isDouble() && IsNegativeZero(v.toDouble())) {
static const Latin1Char negativeZero[] = {'-', '0'};
return NewStringCopyN<CanGC>(cx, negativeZero, mozilla::ArrayLength(negativeZero));
}
return ToString<CanGC>(cx, v);
}
RootedValue fval(cx);
RootedObject obj(cx, &v.toObject());
if (!GetProperty(cx, obj, obj, cx->names().toSource, &fval))
return nullptr;
if (IsCallable(fval)) {
RootedValue v(cx);
if (!js::Call(cx, fval, obj, &v))
return nullptr;
return ToString<CanGC>(cx, v);
}
return ObjectToSource(cx, obj);
}
JSString*
js::StringToSource(JSContext* cx, JSString* str)
{
return QuoteString(cx, str, '"');
}
bool
js::EqualChars(JSLinearString* str1, JSLinearString* str2)
{
MOZ_ASSERT(str1->length() == str2->length());
size_t len = str1->length();
AutoCheckCannotGC nogc;
if (str1->hasTwoByteChars()) {
if (str2->hasTwoByteChars())
return PodEqual(str1->twoByteChars(nogc), str2->twoByteChars(nogc), len);
return EqualChars(str2->latin1Chars(nogc), str1->twoByteChars(nogc), len);
}
if (str2->hasLatin1Chars())
return PodEqual(str1->latin1Chars(nogc), str2->latin1Chars(nogc), len);
return EqualChars(str1->latin1Chars(nogc), str2->twoByteChars(nogc), len);
}
bool
js::EqualStrings(JSContext* cx, JSString* str1, JSString* str2, bool* result)
{
if (str1 == str2) {
*result = true;
return true;
}
size_t length1 = str1->length();
if (length1 != str2->length()) {
*result = false;
return true;
}
JSLinearString* linear1 = str1->ensureLinear(cx);
if (!linear1)
return false;
JSLinearString* linear2 = str2->ensureLinear(cx);
if (!linear2)
return false;
*result = EqualChars(linear1, linear2);
return true;
}
bool
js::EqualStrings(JSLinearString* str1, JSLinearString* str2)
{
if (str1 == str2)
return true;
size_t length1 = str1->length();
if (length1 != str2->length())
return false;
return EqualChars(str1, str2);
}
static int32_t
CompareStringsImpl(JSLinearString* str1, JSLinearString* str2)
{
size_t len1 = str1->length();
size_t len2 = str2->length();
AutoCheckCannotGC nogc;
if (str1->hasLatin1Chars()) {
const Latin1Char* chars1 = str1->latin1Chars(nogc);
return str2->hasLatin1Chars()
? CompareChars(chars1, len1, str2->latin1Chars(nogc), len2)
: CompareChars(chars1, len1, str2->twoByteChars(nogc), len2);
}
const char16_t* chars1 = str1->twoByteChars(nogc);
return str2->hasLatin1Chars()
? CompareChars(chars1, len1, str2->latin1Chars(nogc), len2)
: CompareChars(chars1, len1, str2->twoByteChars(nogc), len2);
}
int32_t
js::CompareChars(const char16_t* s1, size_t len1, JSLinearString* s2)
{
AutoCheckCannotGC nogc;
return s2->hasLatin1Chars()
? CompareChars(s1, len1, s2->latin1Chars(nogc), s2->length())
: CompareChars(s1, len1, s2->twoByteChars(nogc), s2->length());
}
bool
js::CompareStrings(JSContext* cx, JSString* str1, JSString* str2, int32_t* result)
{
MOZ_ASSERT(str1);
MOZ_ASSERT(str2);
if (str1 == str2) {
*result = 0;
return true;
}
JSLinearString* linear1 = str1->ensureLinear(cx);
if (!linear1)
return false;
JSLinearString* linear2 = str2->ensureLinear(cx);
if (!linear2)
return false;
*result = CompareStringsImpl(linear1, linear2);
return true;
}
int32_t
js::CompareAtoms(JSAtom* atom1, JSAtom* atom2)
{
return CompareStringsImpl(atom1, atom2);
}
bool
js::StringEqualsAscii(JSLinearString* str, const char* asciiBytes)
{
size_t length = strlen(asciiBytes);
#ifdef DEBUG
for (size_t i = 0; i != length; ++i)
MOZ_ASSERT(unsigned(asciiBytes[i]) <= 127);
#endif
if (length != str->length())
return false;
const Latin1Char* latin1 = reinterpret_cast<const Latin1Char*>(asciiBytes);
AutoCheckCannotGC nogc;
return str->hasLatin1Chars()
? PodEqual(latin1, str->latin1Chars(nogc), length)
: EqualChars(latin1, str->twoByteChars(nogc), length);
}
int32_t
js_fputs(const char16_t* s, FILE* f)
{
while (*s != 0) {
if (fputwc(wchar_t(*s), f) == WEOF)
return WEOF;
s++;
}
return 1;
}
UniqueChars
js::DuplicateString(JSContext* cx, const char* s)
{
size_t n = strlen(s) + 1;
auto ret = cx->make_pod_array<char>(n);
if (!ret)
return ret;
PodCopy(ret.get(), s, n);
return ret;
}
UniqueTwoByteChars
js::DuplicateString(JSContext* cx, const char16_t* s)
{
size_t n = js_strlen(s) + 1;
auto ret = cx->make_pod_array<char16_t>(n);
if (!ret)
return ret;
PodCopy(ret.get(), s, n);
return ret;
}
UniqueChars
js::DuplicateString(const char* s)
{
size_t n = strlen(s) + 1;
UniqueChars ret(js_pod_malloc<char>(n));
if (!ret)
return ret;
PodCopy(ret.get(), s, n);
return ret;
}
UniqueChars
js::DuplicateString(const char* s, size_t n)
{
UniqueChars ret(js_pod_malloc<char>(n + 1));
if (!ret)
return nullptr;
PodCopy(ret.get(), s, n);
ret[n] = 0;
return ret;
}
UniqueTwoByteChars
js::DuplicateString(const char16_t* s)
{
return DuplicateString(s, js_strlen(s));
}
UniqueTwoByteChars
js::DuplicateString(const char16_t* s, size_t n)
{
UniqueTwoByteChars ret(js_pod_malloc<char16_t>(n + 1));
if (!ret)
return nullptr;
PodCopy(ret.get(), s, n);
ret[n] = 0;
return ret;
}
JS_PUBLIC_API(char*)
js_strdup(const char* s)
{
return DuplicateString(s).release();
}
template <typename CharT>
const CharT*
js_strchr_limit(const CharT* s, char16_t c, const CharT* limit)
{
while (s < limit) {
if (*s == c)
return s;
s++;
}
return nullptr;
}
template const Latin1Char*
js_strchr_limit(const Latin1Char* s, char16_t c, const Latin1Char* limit);
template const char16_t*
js_strchr_limit(const char16_t* s, char16_t c, const char16_t* limit);
char16_t*
js::InflateString(JSContext* cx, const char* bytes, size_t length)
{
char16_t* chars = cx->pod_malloc<char16_t>(length + 1);
if (!chars)
return nullptr;
CopyAndInflateChars(chars, bytes, length);
chars[length] = 0;
return chars;
}
template <typename CharT>
bool
js::DeflateStringToBuffer(JSContext* maybecx, const CharT* src, size_t srclen,
char* dst, size_t* dstlenp)
{
size_t dstlen = *dstlenp;
if (srclen > dstlen) {
for (size_t i = 0; i < dstlen; i++)
dst[i] = char(src[i]);
if (maybecx) {
AutoSuppressGC suppress(maybecx);
JS_ReportErrorNumberASCII(maybecx, GetErrorMessage, nullptr,
JSMSG_BUFFER_TOO_SMALL);
}
return false;
}
for (size_t i = 0; i < srclen; i++)
dst[i] = char(src[i]);
*dstlenp = srclen;
return true;
}
template bool
js::DeflateStringToBuffer(JSContext* maybecx, const Latin1Char* src, size_t srclen,
char* dst, size_t* dstlenp);
template bool
js::DeflateStringToBuffer(JSContext* maybecx, const char16_t* src, size_t srclen,
char* dst, size_t* dstlenp);
#define ____ false
/*
@ -4475,182 +4037,6 @@ js::EncodeURI(JSContext* cx, StringBuffer& sb, const char* chars, size_t length)
return true;
}
/*
* Convert one UCS-4 char and write it into a UTF-8 buffer, which must be at
* least 4 bytes long. Return the number of UTF-8 bytes of data written.
*/
uint32_t
js::OneUcs4ToUtf8Char(uint8_t* utf8Buffer, uint32_t ucs4Char)
{
MOZ_ASSERT(ucs4Char <= unicode::NonBMPMax);
if (ucs4Char < 0x80) {
utf8Buffer[0] = uint8_t(ucs4Char);
return 1;
}
uint32_t a = ucs4Char >> 11;
uint32_t utf8Length = 2;
while (a) {
a >>= 5;
utf8Length++;
}
MOZ_ASSERT(utf8Length <= 4);
uint32_t i = utf8Length;
while (--i) {
utf8Buffer[i] = uint8_t((ucs4Char & 0x3F) | 0x80);
ucs4Char >>= 6;
}
utf8Buffer[0] = uint8_t(0x100 - (1 << (8 - utf8Length)) + ucs4Char);
return utf8Length;
}
size_t
js::PutEscapedStringImpl(char* buffer, size_t bufferSize, GenericPrinter* out, JSLinearString* str,
uint32_t quote)
{
size_t len = str->length();
AutoCheckCannotGC nogc;
return str->hasLatin1Chars()
? PutEscapedStringImpl(buffer, bufferSize, out, str->latin1Chars(nogc), len, quote)
: PutEscapedStringImpl(buffer, bufferSize, out, str->twoByteChars(nogc), len, quote);
}
template <typename CharT>
size_t
js::PutEscapedStringImpl(char* buffer, size_t bufferSize, GenericPrinter* out, const CharT* chars,
size_t length, uint32_t quote)
{
enum {
STOP, FIRST_QUOTE, LAST_QUOTE, CHARS, ESCAPE_START, ESCAPE_MORE
} state;
MOZ_ASSERT(quote == 0 || quote == '\'' || quote == '"');
MOZ_ASSERT_IF(!buffer, bufferSize == 0);
MOZ_ASSERT_IF(out, !buffer);
if (bufferSize == 0)
buffer = nullptr;
else
bufferSize--;
const CharT* charsEnd = chars + length;
size_t n = 0;
state = FIRST_QUOTE;
unsigned shift = 0;
unsigned hex = 0;
unsigned u = 0;
char c = 0; /* to quell GCC warnings */
for (;;) {
switch (state) {
case STOP:
goto stop;
case FIRST_QUOTE:
state = CHARS;
goto do_quote;
case LAST_QUOTE:
state = STOP;
do_quote:
if (quote == 0)
continue;
c = (char)quote;
break;
case CHARS:
if (chars == charsEnd) {
state = LAST_QUOTE;
continue;
}
u = *chars++;
if (u < ' ') {
if (u != 0) {
const char* escape = strchr(js_EscapeMap, (int)u);
if (escape) {
u = escape[1];
goto do_escape;
}
}
goto do_hex_escape;
}
if (u < 127) {
if (u == quote || u == '\\')
goto do_escape;
c = (char)u;
} else if (u < 0x100) {
goto do_hex_escape;
} else {
shift = 16;
hex = u;
u = 'u';
goto do_escape;
}
break;
do_hex_escape:
shift = 8;
hex = u;
u = 'x';
do_escape:
c = '\\';
state = ESCAPE_START;
break;
case ESCAPE_START:
MOZ_ASSERT(' ' <= u && u < 127);
c = (char)u;
state = ESCAPE_MORE;
break;
case ESCAPE_MORE:
if (shift == 0) {
state = CHARS;
continue;
}
shift -= 4;
u = 0xF & (hex >> shift);
c = (char)(u + (u < 10 ? '0' : 'A' - 10));
break;
}
if (buffer) {
MOZ_ASSERT(n <= bufferSize);
if (n != bufferSize) {
buffer[n] = c;
} else {
buffer[n] = '\0';
buffer = nullptr;
}
} else if (out) {
if (!out->put(&c, 1))
return size_t(-1);
}
n++;
}
stop:
if (buffer)
buffer[n] = '\0';
return n;
}
template size_t
js::PutEscapedStringImpl(char* buffer, size_t bufferSize, GenericPrinter* out, const Latin1Char* chars,
size_t length, uint32_t quote);
template size_t
js::PutEscapedStringImpl(char* buffer, size_t bufferSize, GenericPrinter* out, const char* chars,
size_t length, uint32_t quote);
template size_t
js::PutEscapedStringImpl(char* buffer, size_t bufferSize, GenericPrinter* out, const char16_t* chars,
size_t length, uint32_t quote);
template size_t
js::PutEscapedString(char* buffer, size_t bufferSize, const Latin1Char* chars, size_t length,
uint32_t quote);
template size_t
js::PutEscapedString(char* buffer, size_t bufferSize, const char16_t* chars, size_t length,
uint32_t quote);
static bool
FlatStringMatchHelper(JSContext* cx, HandleString str, HandleString pattern, bool* isFlat, int32_t* match)
{

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

@ -22,269 +22,12 @@
#include "util/Unicode.h"
#include "vm/Printer.h"
class JSAutoByteString;
class JSLinearString;
namespace js {
class StringBuffer;
template <AllowGC allowGC>
extern JSString*
ConcatStrings(JSContext* cx,
typename MaybeRooted<JSString*, allowGC>::HandleType left,
typename MaybeRooted<JSString*, allowGC>::HandleType right);
// Return s advanced past any Unicode white space characters.
template <typename CharT>
static inline const CharT*
SkipSpace(const CharT* s, const CharT* end)
{
MOZ_ASSERT(s <= end);
while (s < end && unicode::IsSpace(*s))
s++;
return s;
}
// Return less than, equal to, or greater than zero depending on whether
// s1 is less than, equal to, or greater than s2.
template <typename Char1, typename Char2>
inline int32_t
CompareChars(const Char1* s1, size_t len1, const Char2* s2, size_t len2)
{
size_t n = Min(len1, len2);
for (size_t i = 0; i < n; i++) {
if (int32_t cmp = s1[i] - s2[i])
return cmp;
}
return int32_t(len1 - len2);
}
extern int32_t
CompareChars(const char16_t* s1, size_t len1, JSLinearString* s2);
} /* namespace js */
/*
* Shorthands for ASCII (7-bit) decimal and hex conversion.
* Manually inline isdigit and isxdigit for performance; MSVC doesn't do this for us.
*/
#define JS7_ISDEC(c) ((((unsigned)(c)) - '0') <= 9)
#define JS7_ISA2F(c) ((((((unsigned)(c)) - 'a') <= 5) || (((unsigned)(c)) - 'A') <= 5))
#define JS7_UNDEC(c) ((c) - '0')
#define JS7_ISOCT(c) ((((unsigned)(c)) - '0') <= 7)
#define JS7_UNOCT(c) (JS7_UNDEC(c))
#define JS7_ISHEX(c) ((c) < 128 && (JS7_ISDEC(c) || JS7_ISA2F(c)))
#define JS7_UNHEX(c) (unsigned)(JS7_ISDEC(c) ? (c) - '0' : 10 + tolower(c) - 'a')
#define JS7_ISLET(c) ((c) < 128 && isalpha(c))
static MOZ_ALWAYS_INLINE size_t
js_strlen(const char16_t* s)
{
return std::char_traits<char16_t>::length(s);
}
template <typename CharT>
extern const CharT*
js_strchr_limit(const CharT* s, char16_t c, const CharT* limit);
extern int32_t
js_fputs(const char16_t* s, FILE* f);
namespace js {
/* Initialize the String class, returning its prototype object. */
extern JSObject*
InitStringClass(JSContext* cx, HandleObject obj);
/*
* Convert a value to a printable C string.
*/
extern const char*
ValueToPrintable(JSContext* cx, const Value&, JSAutoByteString* bytes, bool asSource = false);
extern UniqueChars
DuplicateString(JSContext* cx, const char* s);
extern UniqueTwoByteChars
DuplicateString(JSContext* cx, const char16_t* s);
/*
* These variants do not report OOMs, you must arrange for OOMs to be reported
* yourself.
*/
extern UniqueChars
DuplicateString(const char* s);
extern UniqueChars
DuplicateString(const char* s, size_t n);
extern UniqueTwoByteChars
DuplicateString(const char16_t* s);
extern UniqueTwoByteChars
DuplicateString(const char16_t* s, size_t n);
/*
* Convert a non-string value to a string, returning null after reporting an
* error, otherwise returning a new string reference.
*/
template <AllowGC allowGC>
extern JSString*
ToStringSlow(JSContext* cx, typename MaybeRooted<Value, allowGC>::HandleType arg);
/*
* Convert the given value to a string. This method includes an inline
* fast-path for the case where the value is already a string; if the value is
* known not to be a string, use ToStringSlow instead.
*/
template <AllowGC allowGC>
static MOZ_ALWAYS_INLINE JSString*
ToString(JSContext* cx, JS::HandleValue v)
{
if (v.isString())
return v.toString();
return ToStringSlow<allowGC>(cx, v);
}
/*
* This function implements E-262-3 section 9.8, toString. Convert the given
* value to a string of characters appended to the given buffer. On error, the
* passed buffer may have partial results appended.
*/
inline bool
ValueToStringBuffer(JSContext* cx, const Value& v, StringBuffer& sb);
/*
* Convert a value to its source expression, returning null after reporting
* an error, otherwise returning a new string reference.
*/
extern JSString*
ValueToSource(JSContext* cx, HandleValue v);
/*
* Convert a JSString to its source expression; returns null after reporting an
* error, otherwise returns a new string reference. No Handle needed since the
* input is dead after the GC.
*/
extern JSString*
StringToSource(JSContext* cx, JSString* str);
/*
* Test if strings are equal. The caller can call the function even if str1
* or str2 are not GC-allocated things.
*/
extern bool
EqualStrings(JSContext* cx, JSString* str1, JSString* str2, bool* result);
/* Use the infallible method instead! */
extern bool
EqualStrings(JSContext* cx, JSLinearString* str1, JSLinearString* str2, bool* result) = delete;
/* EqualStrings is infallible on linear strings. */
extern bool
EqualStrings(JSLinearString* str1, JSLinearString* str2);
extern bool
EqualChars(JSLinearString* str1, JSLinearString* str2);
/*
* Return less than, equal to, or greater than zero depending on whether
* str1 is less than, equal to, or greater than str2.
*/
extern bool
CompareStrings(JSContext* cx, JSString* str1, JSString* str2, int32_t* result);
/*
* Same as CompareStrings but for atoms. Don't use this to just test
* for equality; use this when you need an ordering on atoms.
*/
extern int32_t
CompareAtoms(JSAtom* atom1, JSAtom* atom2);
/*
* Return true if the string matches the given sequence of ASCII bytes.
*/
extern bool
StringEqualsAscii(JSLinearString* str, const char* asciiBytes);
extern int
StringFindPattern(JSLinearString* text, JSLinearString* pat, size_t start);
/* Return true if the string contains a pattern at |start|. */
extern bool
HasSubstringAt(JSLinearString* text, JSLinearString* pat, size_t start);
template <typename Char1, typename Char2>
inline bool
EqualChars(const Char1* s1, const Char2* s2, size_t len);
template <typename Char1>
inline bool
EqualChars(const Char1* s1, const Char1* s2, size_t len)
{
return mozilla::PodEqual(s1, s2, len);
}
template <typename Char1, typename Char2>
inline bool
EqualChars(const Char1* s1, const Char2* s2, size_t len)
{
for (const Char1* s1end = s1 + len; s1 < s1end; s1++, s2++) {
if (*s1 != *s2)
return false;
}
return true;
}
/*
* Computes |str|'s substring for the range [beginInt, beginInt + lengthInt).
* Negative, overlarge, swapped, etc. |beginInt| and |lengthInt| are forbidden
* and constitute API misuse.
*/
JSString*
SubstringKernel(JSContext* cx, HandleString str, int32_t beginInt, int32_t lengthInt);
/*
* Inflate bytes in ASCII encoding to char16_t code units. Return null on error,
* otherwise return the char16_t buffer that was malloc'ed. A null char is
* appended.
*/
extern char16_t*
InflateString(JSContext* cx, const char* bytes, size_t length);
/*
* Inflate bytes to JS chars in an existing buffer. 'dst' must be large
* enough for 'srclen' char16_t code units. The buffer is NOT null-terminated.
*/
inline void
CopyAndInflateChars(char16_t* dst, const char* src, size_t srclen)
{
for (size_t i = 0; i < srclen; i++)
dst[i] = (unsigned char) src[i];
}
inline void
CopyAndInflateChars(char16_t* dst, const JS::Latin1Char* src, size_t srclen)
{
for (size_t i = 0; i < srclen; i++)
dst[i] = src[i];
}
/*
* Deflate JS chars to bytes into a buffer. 'bytes' must be large enough for
* 'length chars. The buffer is NOT null-terminated. The destination length
* must to be initialized with the buffer size and will contain on return the
* number of copied bytes.
*/
template <typename CharT>
extern bool
DeflateStringToBuffer(JSContext* maybecx, const CharT* chars,
size_t charsLength, char* bytes, size_t* length);
extern bool
str_fromCharCode(JSContext* cx, unsigned argc, Value* vp);
@ -414,90 +157,6 @@ str_localeCompare(JSContext* cx, unsigned argc, Value* vp);
extern bool
str_concat(JSContext* cx, unsigned argc, Value* vp);
/*
* Convert one UCS-4 char and write it into a UTF-8 buffer, which must be at
* least 4 bytes long. Return the number of UTF-8 bytes of data written.
*/
extern uint32_t
OneUcs4ToUtf8Char(uint8_t* utf8Buffer, uint32_t ucs4Char);
extern size_t
PutEscapedStringImpl(char* buffer, size_t size, GenericPrinter* out, JSLinearString* str,
uint32_t quote);
template <typename CharT>
extern size_t
PutEscapedStringImpl(char* buffer, size_t bufferSize, GenericPrinter* out, const CharT* chars,
size_t length, uint32_t quote);
/*
* Write str into buffer escaping any non-printable or non-ASCII character
* using \escapes for JS string literals.
* Guarantees that a NUL is at the end of the buffer unless size is 0. Returns
* the length of the written output, NOT including the NUL. Thus, a return
* value of size or more means that the output was truncated. If buffer
* is null, just returns the length of the output. If quote is not 0, it must
* be a single or double quote character that will quote the output.
*/
inline size_t
PutEscapedString(char* buffer, size_t size, JSLinearString* str, uint32_t quote)
{
size_t n = PutEscapedStringImpl(buffer, size, nullptr, str, quote);
/* PutEscapedStringImpl can only fail with a file. */
MOZ_ASSERT(n != size_t(-1));
return n;
}
template <typename CharT>
inline size_t
PutEscapedString(char* buffer, size_t bufferSize, const CharT* chars, size_t length, uint32_t quote)
{
size_t n = PutEscapedStringImpl(buffer, bufferSize, nullptr, chars, length, quote);
/* PutEscapedStringImpl can only fail with a file. */
MOZ_ASSERT(n != size_t(-1));
return n;
}
inline bool
EscapedStringPrinter(GenericPrinter& out, JSLinearString* str, uint32_t quote)
{
return PutEscapedStringImpl(nullptr, 0, &out, str, quote) != size_t(-1);
}
inline bool
EscapedStringPrinter(GenericPrinter& out, const char* chars, size_t length, uint32_t quote)
{
return PutEscapedStringImpl(nullptr, 0, &out, chars, length, quote) != size_t(-1);
}
/*
* Write str into file escaping any non-printable or non-ASCII character.
* If quote is not 0, it must be a single or double quote character that
* will quote the output.
*/
inline bool
FileEscapedString(FILE* fp, JSLinearString* str, uint32_t quote)
{
Fprinter out(fp);
bool res = EscapedStringPrinter(out, str, quote);
out.finish();
return res;
}
inline bool
FileEscapedString(FILE* fp, const char* chars, size_t length, uint32_t quote)
{
Fprinter out(fp);
bool res = EscapedStringPrinter(out, chars, length, quote);
out.finish();
return res;
}
bool
EncodeURI(JSContext* cx, StringBuffer& sb, const char* chars, size_t length);
ArrayObject*
str_split_string(JSContext* cx, HandleObjectGroup group, HandleString str, HandleString sep,
uint32_t limit);

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

@ -39,6 +39,7 @@
#include "js/Vector.h"
#include "js/Wrapper.h"
#include "util/StringBuffer.h"
#include "util/Text.h"
#include "vm/AsyncFunction.h"
#include "vm/AsyncIteration.h"
#include "vm/Debugger.h"

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

@ -13,6 +13,7 @@
#include "frontend/ParseNode.h"
#include "frontend/Parser.h"
#include "js/Conversions.h"
#include "vm/StringType.h"
#include "vm/JSContext-inl.h"
#include "vm/JSObject-inl.h"

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

@ -38,6 +38,7 @@
#include "vm/JSFunction.h"
#include "vm/JSScript.h"
#include "vm/RegExpObject.h"
#include "vm/StringType.h"
#include "wasm/AsmJS.h"
#include "frontend/ParseContext-inl.h"

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

@ -20,6 +20,7 @@
#include "gc/GC.h"
#include "gc/Memory.h"
#include "util/Text.h"
#include "vm/Debugger.h"
#include "vm/HelperThreads.h"
#include "vm/Runtime.h"

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

@ -15,6 +15,7 @@
#include "gc/Marking.h"
#include "gc/PublicIterators.h"
#include "gc/Zone.h"
#include "util/Text.h"
#include "vm/JSFunction.h"
#include "vm/JSScript.h"
#include "vm/Shape.h"

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

@ -49,6 +49,7 @@
#include "vm/MatchPairs.h"
#include "vm/RegExpObject.h"
#include "vm/RegExpStatics.h"
#include "vm/StringType.h"
#include "vm/TraceLogging.h"
#include "vm/TypedArrayObject.h"
#include "vtune/VTuneWrapper.h"

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

@ -25,6 +25,7 @@
#include "jit/MIRGraph.h"
#include "jit/RangeAnalysis.h"
#include "js/Conversions.h"
#include "util/Text.h"
#include "jsboolinlines.h"

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

@ -11,6 +11,7 @@
#include "jit/JitcodeMap.h"
#include "jit/JitSpewer.h"
#include "js/TrackedOptimizationInfo.h"
#include "util/Text.h"
#include "vm/ObjectGroup-inl.h"
#include "vm/TypeInference-inl.h"

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

@ -25,6 +25,7 @@
#endif
#include "jit/VMFunctions.h"
#include "vm/Interpreter.h"
#include "vm/StringType.h"
#include "jit/MacroAssembler-inl.h"
#include "jit/SharedICHelpers-inl.h"

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

@ -9,6 +9,7 @@
#include "js/Vector.h"
#include "jsapi-tests/tests.h"
#include "threading/Thread.h"
#include "util/Text.h"
#include "vm/SharedImmutableStringsCache.h"
const int NUM_THREADS = 256;

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

@ -8,6 +8,7 @@
#include "js/UbiNodePostOrder.h"
#include "js/UbiNodeShortestPaths.h"
#include "jsapi-tests/tests.h"
#include "util/Text.h"
#include "vm/SavedFrame.h"
using JS::RootedObject;

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

@ -67,6 +67,7 @@
#include "js/Utility.h"
#include "js/Wrapper.h"
#include "util/StringBuffer.h"
#include "util/Text.h"
#include "vm/AsyncFunction.h"
#include "vm/AsyncIteration.h"
#include "vm/DateObject.h"

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

@ -25,6 +25,7 @@
#include "js/Class.h"
#include "js/Conversions.h"
#include "util/StringBuffer.h"
#include "util/Text.h"
#include "vm/ArgumentsObject.h"
#include "vm/Interpreter.h"
#include "vm/Iteration.h"

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

@ -32,6 +32,7 @@
#include "vm/JSScript.h"
#include "vm/SavedStacks.h"
#include "vm/SelfHosting.h"
#include "vm/StringType.h"
#include "vm/ErrorObject-inl.h"
#include "vm/JSObject-inl.h"

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

@ -307,6 +307,7 @@ UNIFIED_SOURCES += [
'util/NativeStack.cpp',
'util/Printf.cpp',
'util/StringBuffer.cpp',
'util/Text.cpp',
'util/Unicode.cpp',
'vm/ArgumentsObject.cpp',
'vm/ArrayBufferObject.cpp',

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

@ -29,6 +29,7 @@
#include "js/Wrapper.h"
#include "shell/jsshell.h"
#include "util/StringBuffer.h"
#include "util/Text.h"
#include "util/Windows.h"
#include "vm/JSObject.h"
#include "vm/TypedArrayObject.h"

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

@ -91,6 +91,7 @@
#include "threading/LockGuard.h"
#include "threading/Thread.h"
#include "util/StringBuffer.h"
#include "util/Text.h"
#include "util/Windows.h"
#include "vm/ArgumentsObject.h"
#include "vm/Compression.h"

332
js/src/util/Text.cpp Normal file
Просмотреть файл

@ -0,0 +1,332 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
* vim: set ts=8 sts=4 et sw=4 tw=99:
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "util/Text.h"
#include "mozilla/PodOperations.h"
#include "gc/GC.h"
#include "js/GCAPI.h"
#include "vm/JSContext.h"
#include "vm/StringType.h"
using namespace JS;
using namespace js;
using js::gc::AutoSuppressGC;
using mozilla::PodCopy;
template <typename CharT>
const CharT*
js_strchr_limit(const CharT* s, char16_t c, const CharT* limit)
{
while (s < limit) {
if (*s == c)
return s;
s++;
}
return nullptr;
}
template const Latin1Char*
js_strchr_limit(const Latin1Char* s, char16_t c, const Latin1Char* limit);
template const char16_t*
js_strchr_limit(const char16_t* s, char16_t c, const char16_t* limit);
JS_PUBLIC_API(char*)
js_strdup(const char* s)
{
return DuplicateString(s).release();
}
int32_t
js_fputs(const char16_t* s, FILE* f)
{
while (*s != 0) {
if (fputwc(wchar_t(*s), f) == WEOF)
return WEOF;
s++;
}
return 1;
}
UniqueChars
js::DuplicateString(JSContext* cx, const char* s)
{
size_t n = strlen(s) + 1;
auto ret = cx->make_pod_array<char>(n);
if (!ret)
return ret;
PodCopy(ret.get(), s, n);
return ret;
}
UniqueTwoByteChars
js::DuplicateString(JSContext* cx, const char16_t* s)
{
size_t n = js_strlen(s) + 1;
auto ret = cx->make_pod_array<char16_t>(n);
if (!ret)
return ret;
PodCopy(ret.get(), s, n);
return ret;
}
UniqueChars
js::DuplicateString(const char* s)
{
size_t n = strlen(s) + 1;
UniqueChars ret(js_pod_malloc<char>(n));
if (!ret)
return ret;
PodCopy(ret.get(), s, n);
return ret;
}
UniqueChars
js::DuplicateString(const char* s, size_t n)
{
UniqueChars ret(js_pod_malloc<char>(n + 1));
if (!ret)
return nullptr;
PodCopy(ret.get(), s, n);
ret[n] = 0;
return ret;
}
UniqueTwoByteChars
js::DuplicateString(const char16_t* s)
{
return DuplicateString(s, js_strlen(s));
}
UniqueTwoByteChars
js::DuplicateString(const char16_t* s, size_t n)
{
UniqueTwoByteChars ret(js_pod_malloc<char16_t>(n + 1));
if (!ret)
return nullptr;
PodCopy(ret.get(), s, n);
ret[n] = 0;
return ret;
}
char16_t*
js::InflateString(JSContext* cx, const char* bytes, size_t length)
{
char16_t* chars = cx->pod_malloc<char16_t>(length + 1);
if (!chars)
return nullptr;
CopyAndInflateChars(chars, bytes, length);
chars[length] = 0;
return chars;
}
template <typename CharT>
bool
js::DeflateStringToBuffer(JSContext* maybecx, const CharT* src, size_t srclen,
char* dst, size_t* dstlenp)
{
size_t dstlen = *dstlenp;
if (srclen > dstlen) {
for (size_t i = 0; i < dstlen; i++)
dst[i] = char(src[i]);
if (maybecx) {
AutoSuppressGC suppress(maybecx);
JS_ReportErrorNumberASCII(maybecx, GetErrorMessage, nullptr,
JSMSG_BUFFER_TOO_SMALL);
}
return false;
}
for (size_t i = 0; i < srclen; i++)
dst[i] = char(src[i]);
*dstlenp = srclen;
return true;
}
template bool
js::DeflateStringToBuffer(JSContext* maybecx, const Latin1Char* src, size_t srclen,
char* dst, size_t* dstlenp);
template bool
js::DeflateStringToBuffer(JSContext* maybecx, const char16_t* src, size_t srclen,
char* dst, size_t* dstlenp);
/*
* Convert one UCS-4 char and write it into a UTF-8 buffer, which must be at
* least 4 bytes long. Return the number of UTF-8 bytes of data written.
*/
uint32_t
js::OneUcs4ToUtf8Char(uint8_t* utf8Buffer, uint32_t ucs4Char)
{
MOZ_ASSERT(ucs4Char <= unicode::NonBMPMax);
if (ucs4Char < 0x80) {
utf8Buffer[0] = uint8_t(ucs4Char);
return 1;
}
uint32_t a = ucs4Char >> 11;
uint32_t utf8Length = 2;
while (a) {
a >>= 5;
utf8Length++;
}
MOZ_ASSERT(utf8Length <= 4);
uint32_t i = utf8Length;
while (--i) {
utf8Buffer[i] = uint8_t((ucs4Char & 0x3F) | 0x80);
ucs4Char >>= 6;
}
utf8Buffer[0] = uint8_t(0x100 - (1 << (8 - utf8Length)) + ucs4Char);
return utf8Length;
}
size_t
js::PutEscapedStringImpl(char* buffer, size_t bufferSize, GenericPrinter* out, JSLinearString* str,
uint32_t quote)
{
size_t len = str->length();
AutoCheckCannotGC nogc;
return str->hasLatin1Chars()
? PutEscapedStringImpl(buffer, bufferSize, out, str->latin1Chars(nogc), len, quote)
: PutEscapedStringImpl(buffer, bufferSize, out, str->twoByteChars(nogc), len, quote);
}
template <typename CharT>
size_t
js::PutEscapedStringImpl(char* buffer, size_t bufferSize, GenericPrinter* out, const CharT* chars,
size_t length, uint32_t quote)
{
enum {
STOP, FIRST_QUOTE, LAST_QUOTE, CHARS, ESCAPE_START, ESCAPE_MORE
} state;
MOZ_ASSERT(quote == 0 || quote == '\'' || quote == '"');
MOZ_ASSERT_IF(!buffer, bufferSize == 0);
MOZ_ASSERT_IF(out, !buffer);
if (bufferSize == 0)
buffer = nullptr;
else
bufferSize--;
const CharT* charsEnd = chars + length;
size_t n = 0;
state = FIRST_QUOTE;
unsigned shift = 0;
unsigned hex = 0;
unsigned u = 0;
char c = 0; /* to quell GCC warnings */
for (;;) {
switch (state) {
case STOP:
goto stop;
case FIRST_QUOTE:
state = CHARS;
goto do_quote;
case LAST_QUOTE:
state = STOP;
do_quote:
if (quote == 0)
continue;
c = (char)quote;
break;
case CHARS:
if (chars == charsEnd) {
state = LAST_QUOTE;
continue;
}
u = *chars++;
if (u < ' ') {
if (u != 0) {
const char* escape = strchr(js_EscapeMap, (int)u);
if (escape) {
u = escape[1];
goto do_escape;
}
}
goto do_hex_escape;
}
if (u < 127) {
if (u == quote || u == '\\')
goto do_escape;
c = (char)u;
} else if (u < 0x100) {
goto do_hex_escape;
} else {
shift = 16;
hex = u;
u = 'u';
goto do_escape;
}
break;
do_hex_escape:
shift = 8;
hex = u;
u = 'x';
do_escape:
c = '\\';
state = ESCAPE_START;
break;
case ESCAPE_START:
MOZ_ASSERT(' ' <= u && u < 127);
c = (char)u;
state = ESCAPE_MORE;
break;
case ESCAPE_MORE:
if (shift == 0) {
state = CHARS;
continue;
}
shift -= 4;
u = 0xF & (hex >> shift);
c = (char)(u + (u < 10 ? '0' : 'A' - 10));
break;
}
if (buffer) {
MOZ_ASSERT(n <= bufferSize);
if (n != bufferSize) {
buffer[n] = c;
} else {
buffer[n] = '\0';
buffer = nullptr;
}
} else if (out) {
if (!out->put(&c, 1))
return size_t(-1);
}
n++;
}
stop:
if (buffer)
buffer[n] = '\0';
return n;
}
template size_t
js::PutEscapedStringImpl(char* buffer, size_t bufferSize, GenericPrinter* out, const Latin1Char* chars,
size_t length, uint32_t quote);
template size_t
js::PutEscapedStringImpl(char* buffer, size_t bufferSize, GenericPrinter* out, const char* chars,
size_t length, uint32_t quote);
template size_t
js::PutEscapedStringImpl(char* buffer, size_t bufferSize, GenericPrinter* out, const char16_t* chars,
size_t length, uint32_t quote);
template size_t
js::PutEscapedString(char* buffer, size_t bufferSize, const Latin1Char* chars, size_t length,
uint32_t quote);
template size_t
js::PutEscapedString(char* buffer, size_t bufferSize, const char16_t* chars, size_t length,
uint32_t quote);

253
js/src/util/Text.h Normal file
Просмотреть файл

@ -0,0 +1,253 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
* vim: set ts=8 sts=4 et sw=4 tw=99:
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef util_Text_h
#define util_Text_h
#include "mozilla/Assertions.h"
#include "mozilla/Attributes.h"
#include <ctype.h>
#include <stddef.h>
#include <stdint.h>
#include <stdio.h>
#include <string>
#include "jsutil.h"
#include "NamespaceImports.h"
#include "js/Utility.h"
#include "util/Unicode.h"
#include "vm/Printer.h"
class JSLinearString;
/*
* Shorthands for ASCII (7-bit) decimal and hex conversion.
* Manually inline isdigit and isxdigit for performance; MSVC doesn't do this for us.
*/
#define JS7_ISDEC(c) ((((unsigned)(c)) - '0') <= 9)
#define JS7_ISA2F(c) ((((((unsigned)(c)) - 'a') <= 5) || (((unsigned)(c)) - 'A') <= 5))
#define JS7_UNDEC(c) ((c) - '0')
#define JS7_ISOCT(c) ((((unsigned)(c)) - '0') <= 7)
#define JS7_UNOCT(c) (JS7_UNDEC(c))
#define JS7_ISHEX(c) ((c) < 128 && (JS7_ISDEC(c) || JS7_ISA2F(c)))
#define JS7_UNHEX(c) (unsigned)(JS7_ISDEC(c) ? (c) - '0' : 10 + tolower(c) - 'a')
#define JS7_ISLET(c) ((c) < 128 && isalpha(c))
static MOZ_ALWAYS_INLINE size_t
js_strlen(const char16_t* s)
{
return std::char_traits<char16_t>::length(s);
}
template <typename CharT>
extern const CharT*
js_strchr_limit(const CharT* s, char16_t c, const CharT* limit);
extern int32_t
js_fputs(const char16_t* s, FILE* f);
namespace js {
class StringBuffer;
template <typename Char1, typename Char2>
inline bool
EqualChars(const Char1* s1, const Char2* s2, size_t len);
template <typename Char1>
inline bool
EqualChars(const Char1* s1, const Char1* s2, size_t len)
{
return mozilla::PodEqual(s1, s2, len);
}
template <typename Char1, typename Char2>
inline bool
EqualChars(const Char1* s1, const Char2* s2, size_t len)
{
for (const Char1* s1end = s1 + len; s1 < s1end; s1++, s2++) {
if (*s1 != *s2)
return false;
}
return true;
}
// Return less than, equal to, or greater than zero depending on whether
// s1 is less than, equal to, or greater than s2.
template <typename Char1, typename Char2>
inline int32_t
CompareChars(const Char1* s1, size_t len1, const Char2* s2, size_t len2)
{
size_t n = Min(len1, len2);
for (size_t i = 0; i < n; i++) {
if (int32_t cmp = s1[i] - s2[i])
return cmp;
}
return int32_t(len1 - len2);
}
// Return s advanced past any Unicode white space characters.
template <typename CharT>
static inline const CharT*
SkipSpace(const CharT* s, const CharT* end)
{
MOZ_ASSERT(s <= end);
while (s < end && unicode::IsSpace(*s))
s++;
return s;
}
extern UniqueChars
DuplicateString(JSContext* cx, const char* s);
extern UniqueTwoByteChars
DuplicateString(JSContext* cx, const char16_t* s);
/*
* These variants do not report OOMs, you must arrange for OOMs to be reported
* yourself.
*/
extern UniqueChars
DuplicateString(const char* s);
extern UniqueChars
DuplicateString(const char* s, size_t n);
extern UniqueTwoByteChars
DuplicateString(const char16_t* s);
extern UniqueTwoByteChars
DuplicateString(const char16_t* s, size_t n);
/*
* Inflate bytes in ASCII encoding to char16_t code units. Return null on error,
* otherwise return the char16_t buffer that was malloc'ed. A null char is
* appended.
*/
extern char16_t*
InflateString(JSContext* cx, const char* bytes, size_t length);
/*
* Inflate bytes to JS chars in an existing buffer. 'dst' must be large
* enough for 'srclen' char16_t code units. The buffer is NOT null-terminated.
*/
inline void
CopyAndInflateChars(char16_t* dst, const char* src, size_t srclen)
{
for (size_t i = 0; i < srclen; i++)
dst[i] = (unsigned char) src[i];
}
inline void
CopyAndInflateChars(char16_t* dst, const JS::Latin1Char* src, size_t srclen)
{
for (size_t i = 0; i < srclen; i++)
dst[i] = src[i];
}
/*
* Deflate JS chars to bytes into a buffer. 'bytes' must be large enough for
* 'length chars. The buffer is NOT null-terminated. The destination length
* must to be initialized with the buffer size and will contain on return the
* number of copied bytes.
*/
template <typename CharT>
extern bool
DeflateStringToBuffer(JSContext* maybecx, const CharT* chars,
size_t charsLength, char* bytes, size_t* length);
/*
* Convert one UCS-4 char and write it into a UTF-8 buffer, which must be at
* least 4 bytes long. Return the number of UTF-8 bytes of data written.
*/
extern uint32_t
OneUcs4ToUtf8Char(uint8_t* utf8Buffer, uint32_t ucs4Char);
extern size_t
PutEscapedStringImpl(char* buffer, size_t size, GenericPrinter* out, JSLinearString* str,
uint32_t quote);
template <typename CharT>
extern size_t
PutEscapedStringImpl(char* buffer, size_t bufferSize, GenericPrinter* out, const CharT* chars,
size_t length, uint32_t quote);
/*
* Write str into buffer escaping any non-printable or non-ASCII character
* using \escapes for JS string literals.
* Guarantees that a NUL is at the end of the buffer unless size is 0. Returns
* the length of the written output, NOT including the NUL. Thus, a return
* value of size or more means that the output was truncated. If buffer
* is null, just returns the length of the output. If quote is not 0, it must
* be a single or double quote character that will quote the output.
*/
inline size_t
PutEscapedString(char* buffer, size_t size, JSLinearString* str, uint32_t quote)
{
size_t n = PutEscapedStringImpl(buffer, size, nullptr, str, quote);
/* PutEscapedStringImpl can only fail with a file. */
MOZ_ASSERT(n != size_t(-1));
return n;
}
template <typename CharT>
inline size_t
PutEscapedString(char* buffer, size_t bufferSize, const CharT* chars, size_t length, uint32_t quote)
{
size_t n = PutEscapedStringImpl(buffer, bufferSize, nullptr, chars, length, quote);
/* PutEscapedStringImpl can only fail with a file. */
MOZ_ASSERT(n != size_t(-1));
return n;
}
inline bool
EscapedStringPrinter(GenericPrinter& out, JSLinearString* str, uint32_t quote)
{
return PutEscapedStringImpl(nullptr, 0, &out, str, quote) != size_t(-1);
}
inline bool
EscapedStringPrinter(GenericPrinter& out, const char* chars, size_t length, uint32_t quote)
{
return PutEscapedStringImpl(nullptr, 0, &out, chars, length, quote) != size_t(-1);
}
/*
* Write str into file escaping any non-printable or non-ASCII character.
* If quote is not 0, it must be a single or double quote character that
* will quote the output.
*/
inline bool
FileEscapedString(FILE* fp, JSLinearString* str, uint32_t quote)
{
Fprinter out(fp);
bool res = EscapedStringPrinter(out, str, quote);
out.finish();
return res;
}
inline bool
FileEscapedString(FILE* fp, const char* chars, size_t length, uint32_t quote)
{
Fprinter out(fp);
bool res = EscapedStringPrinter(out, chars, length, quote);
out.finish();
return res;
}
bool
EncodeURI(JSContext* cx, StringBuffer& sb, const char* chars, size_t length);
} // namespace js
#endif // util_Text_h

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

@ -18,6 +18,7 @@
# include <unistd.h>
#endif
#include "util/Text.h"
#include "vm/BytecodeUtil.h"
#include "vm/JSCompartment.h"
#include "vm/JSScript.h"

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

@ -44,6 +44,7 @@
#include "vm/Scope.h"
#include "vm/Shape.h"
#include "vm/Stopwatch.h"
#include "vm/StringType.h"
#include "vm/TraceLogging.h"
#include "jsboolinlines.h"

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

@ -21,6 +21,7 @@
#include "builtin/String.h"
#include "gc/Marking.h"
#include "util/Text.h"
#include "vm/JSContext.h"
#include "vm/SymbolType.h"
#include "vm/Xdr.h"

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

@ -37,6 +37,7 @@
#include "js/UbiNode.h"
#include "js/UniquePtr.h"
#include "js/Wrapper.h"
#include "util/Text.h"
#include "util/Windows.h"
#include "vm/ArgumentsObject.h"
#include "vm/BytecodeUtil.h"

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

@ -37,6 +37,7 @@
#include "js/Utility.h"
#include "js/Wrapper.h"
#include "util/StringBuffer.h"
#include "util/Text.h"
#include "vm/ArgumentsObject.h"
#include "vm/BytecodeUtil.h"
#include "vm/Compression.h"

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

@ -24,6 +24,7 @@
#include "util/StringBuffer.h"
#include "vm/MatchPairs.h"
#include "vm/RegExpStatics.h"
#include "vm/StringType.h"
#include "vm/TraceLogging.h"
#ifdef DEBUG
#include "util/Unicode.h"

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

@ -16,6 +16,7 @@
#include "gc/Policy.h"
#include "gc/PublicIterators.h"
#include "js/HashTable.h"
#include "util/Text.h"
#include "vm/JSAtom.h"
#include "vm/JSContext.h"
#include "vm/JSObject.h"

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

@ -7,6 +7,7 @@
#include "vm/SharedImmutableStringsCache-inl.h"
#include "builtin/String.h"
#include "util/Text.h"
namespace js {

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

@ -6,6 +6,7 @@
#include "vm/StringType-inl.h"
#include "mozilla/FloatingPoint.h"
#include "mozilla/MathAlgorithms.h"
#include "mozilla/MemoryReporting.h"
#include "mozilla/PodOperations.h"
@ -16,14 +17,17 @@
#include "gc/Marking.h"
#include "gc/Nursery.h"
#include "js/UbiNode.h"
#include "util/StringBuffer.h"
#include "vm/GeckoProfiler.h"
#include "vm/GeckoProfiler-inl.h"
#include "vm/JSCompartment-inl.h"
#include "vm/JSContext-inl.h"
#include "vm/JSObject-inl.h"
using namespace js;
using mozilla::IsNegativeZero;
using mozilla::IsSame;
using mozilla::PodCopy;
using mozilla::PodEqual;
@ -756,6 +760,165 @@ JSDependentString::dumpRepresentation(js::GenericPrinter& out, int indent) const
}
#endif
bool
js::EqualChars(JSLinearString* str1, JSLinearString* str2)
{
MOZ_ASSERT(str1->length() == str2->length());
size_t len = str1->length();
AutoCheckCannotGC nogc;
if (str1->hasTwoByteChars()) {
if (str2->hasTwoByteChars())
return PodEqual(str1->twoByteChars(nogc), str2->twoByteChars(nogc), len);
return EqualChars(str2->latin1Chars(nogc), str1->twoByteChars(nogc), len);
}
if (str2->hasLatin1Chars())
return PodEqual(str1->latin1Chars(nogc), str2->latin1Chars(nogc), len);
return EqualChars(str1->latin1Chars(nogc), str2->twoByteChars(nogc), len);
}
bool
js::HasSubstringAt(JSLinearString* text, JSLinearString* pat, size_t start)
{
MOZ_ASSERT(start + pat->length() <= text->length());
size_t patLen = pat->length();
AutoCheckCannotGC nogc;
if (text->hasLatin1Chars()) {
const Latin1Char* textChars = text->latin1Chars(nogc) + start;
if (pat->hasLatin1Chars())
return PodEqual(textChars, pat->latin1Chars(nogc), patLen);
return EqualChars(textChars, pat->twoByteChars(nogc), patLen);
}
const char16_t* textChars = text->twoByteChars(nogc) + start;
if (pat->hasTwoByteChars())
return PodEqual(textChars, pat->twoByteChars(nogc), patLen);
return EqualChars(pat->latin1Chars(nogc), textChars, patLen);
}
bool
js::EqualStrings(JSContext* cx, JSString* str1, JSString* str2, bool* result)
{
if (str1 == str2) {
*result = true;
return true;
}
size_t length1 = str1->length();
if (length1 != str2->length()) {
*result = false;
return true;
}
JSLinearString* linear1 = str1->ensureLinear(cx);
if (!linear1)
return false;
JSLinearString* linear2 = str2->ensureLinear(cx);
if (!linear2)
return false;
*result = EqualChars(linear1, linear2);
return true;
}
bool
js::EqualStrings(JSLinearString* str1, JSLinearString* str2)
{
if (str1 == str2)
return true;
size_t length1 = str1->length();
if (length1 != str2->length())
return false;
return EqualChars(str1, str2);
}
int32_t
js::CompareChars(const char16_t* s1, size_t len1, JSLinearString* s2)
{
AutoCheckCannotGC nogc;
return s2->hasLatin1Chars()
? CompareChars(s1, len1, s2->latin1Chars(nogc), s2->length())
: CompareChars(s1, len1, s2->twoByteChars(nogc), s2->length());
}
static int32_t
CompareStringsImpl(JSLinearString* str1, JSLinearString* str2)
{
size_t len1 = str1->length();
size_t len2 = str2->length();
AutoCheckCannotGC nogc;
if (str1->hasLatin1Chars()) {
const Latin1Char* chars1 = str1->latin1Chars(nogc);
return str2->hasLatin1Chars()
? CompareChars(chars1, len1, str2->latin1Chars(nogc), len2)
: CompareChars(chars1, len1, str2->twoByteChars(nogc), len2);
}
const char16_t* chars1 = str1->twoByteChars(nogc);
return str2->hasLatin1Chars()
? CompareChars(chars1, len1, str2->latin1Chars(nogc), len2)
: CompareChars(chars1, len1, str2->twoByteChars(nogc), len2);
}
bool
js::CompareStrings(JSContext* cx, JSString* str1, JSString* str2, int32_t* result)
{
MOZ_ASSERT(str1);
MOZ_ASSERT(str2);
if (str1 == str2) {
*result = 0;
return true;
}
JSLinearString* linear1 = str1->ensureLinear(cx);
if (!linear1)
return false;
JSLinearString* linear2 = str2->ensureLinear(cx);
if (!linear2)
return false;
*result = CompareStringsImpl(linear1, linear2);
return true;
}
int32_t
js::CompareAtoms(JSAtom* atom1, JSAtom* atom2)
{
return CompareStringsImpl(atom1, atom2);
}
bool
js::StringEqualsAscii(JSLinearString* str, const char* asciiBytes)
{
size_t length = strlen(asciiBytes);
#ifdef DEBUG
for (size_t i = 0; i != length; ++i)
MOZ_ASSERT(unsigned(asciiBytes[i]) <= 127);
#endif
if (length != str->length())
return false;
const Latin1Char* latin1 = reinterpret_cast<const Latin1Char*>(asciiBytes);
AutoCheckCannotGC nogc;
return str->hasLatin1Chars()
? PodEqual(latin1, str->latin1Chars(nogc), length)
: EqualChars(latin1, str->twoByteChars(nogc), length);
}
template <typename CharT>
/* static */ bool
JSFlatString::isIndexSlow(const CharT* s, size_t length, uint32_t* indexp)
@ -1732,3 +1895,146 @@ JSString::fillWithRepresentatives(JSContext* cx, HandleArrayObject array)
MOZ_ASSERT(index == 22);
return true;
}
/*** Conversions *********************************************************************************/
const char*
js::ValueToPrintable(JSContext* cx, const Value& vArg, JSAutoByteString* bytes, bool asSource)
{
RootedValue v(cx, vArg);
JSString* str;
if (asSource)
str = ValueToSource(cx, v);
else
str = ToString<CanGC>(cx, v);
if (!str)
return nullptr;
str = QuoteString(cx, str, 0);
if (!str)
return nullptr;
return bytes->encodeLatin1(cx, str);
}
template <AllowGC allowGC>
JSString*
js::ToStringSlow(JSContext* cx, typename MaybeRooted<Value, allowGC>::HandleType arg)
{
/* As with ToObjectSlow, callers must verify that |arg| isn't a string. */
MOZ_ASSERT(!arg.isString());
Value v = arg;
if (!v.isPrimitive()) {
MOZ_ASSERT(!cx->helperThread());
if (!allowGC)
return nullptr;
RootedValue v2(cx, v);
if (!ToPrimitive(cx, JSTYPE_STRING, &v2))
return nullptr;
v = v2;
}
JSString* str;
if (v.isString()) {
str = v.toString();
} else if (v.isInt32()) {
str = Int32ToString<allowGC>(cx, v.toInt32());
} else if (v.isDouble()) {
str = NumberToString<allowGC>(cx, v.toDouble());
} else if (v.isBoolean()) {
str = BooleanToString(cx, v.toBoolean());
} else if (v.isNull()) {
str = cx->names().null;
} else if (v.isSymbol()) {
MOZ_ASSERT(!cx->helperThread());
if (allowGC) {
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
JSMSG_SYMBOL_TO_STRING);
}
return nullptr;
} else {
MOZ_ASSERT(v.isUndefined());
str = cx->names().undefined;
}
return str;
}
template JSString*
js::ToStringSlow<CanGC>(JSContext* cx, HandleValue arg);
template JSString*
js::ToStringSlow<NoGC>(JSContext* cx, const Value& arg);
JS_PUBLIC_API(JSString*)
js::ToStringSlow(JSContext* cx, HandleValue v)
{
return ToStringSlow<CanGC>(cx, v);
}
static JSString*
SymbolToSource(JSContext* cx, Symbol* symbol)
{
RootedString desc(cx, symbol->description());
SymbolCode code = symbol->code();
if (code != SymbolCode::InSymbolRegistry && code != SymbolCode::UniqueSymbol) {
// Well-known symbol.
MOZ_ASSERT(uint32_t(code) < JS::WellKnownSymbolLimit);
return desc;
}
StringBuffer buf(cx);
if (code == SymbolCode::InSymbolRegistry ? !buf.append("Symbol.for(") : !buf.append("Symbol("))
return nullptr;
if (desc) {
desc = StringToSource(cx, desc);
if (!desc || !buf.append(desc))
return nullptr;
}
if (!buf.append(')'))
return nullptr;
return buf.finishString();
}
JSString*
js::ValueToSource(JSContext* cx, HandleValue v)
{
if (!CheckRecursionLimit(cx))
return nullptr;
assertSameCompartment(cx, v);
if (v.isUndefined())
return cx->names().void0;
if (v.isString())
return StringToSource(cx, v.toString());
if (v.isSymbol())
return SymbolToSource(cx, v.toSymbol());
if (v.isPrimitive()) {
/* Special case to preserve negative zero, _contra_ toString. */
if (v.isDouble() && IsNegativeZero(v.toDouble())) {
static const Latin1Char negativeZero[] = {'-', '0'};
return NewStringCopyN<CanGC>(cx, negativeZero, mozilla::ArrayLength(negativeZero));
}
return ToString<CanGC>(cx, v);
}
RootedValue fval(cx);
RootedObject obj(cx, &v.toObject());
if (!GetProperty(cx, obj, obj, cx->names().toSource, &fval))
return nullptr;
if (IsCallable(fval)) {
RootedValue v(cx);
if (!js::Call(cx, fval, obj, &v))
return nullptr;
return ToString<CanGC>(cx, v);
}
return ObjectToSource(cx, obj);
}
JSString*
js::StringToSource(JSContext* cx, JSString* str)
{
return QuoteString(cx, str, '"');
}

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

@ -22,7 +22,7 @@
#include "gc/Rooting.h"
#include "js/CharacterEncoding.h"
#include "js/RootingAPI.h"
#include "util/Text.h"
#include "vm/Printer.h"
class JSDependentString;
@ -1491,6 +1491,137 @@ NewMaybeExternalString(JSContext* cx, const char16_t* s, size_t n, const JSStrin
JS_STATIC_ASSERT(sizeof(HashNumber) == 4);
template <AllowGC allowGC>
extern JSString*
ConcatStrings(JSContext* cx,
typename MaybeRooted<JSString*, allowGC>::HandleType left,
typename MaybeRooted<JSString*, allowGC>::HandleType right);
/*
* Test if strings are equal. The caller can call the function even if str1
* or str2 are not GC-allocated things.
*/
extern bool
EqualStrings(JSContext* cx, JSString* str1, JSString* str2, bool* result);
/* Use the infallible method instead! */
extern bool
EqualStrings(JSContext* cx, JSLinearString* str1, JSLinearString* str2, bool* result) = delete;
/* EqualStrings is infallible on linear strings. */
extern bool
EqualStrings(JSLinearString* str1, JSLinearString* str2);
/**
* Compare two strings that are known to be the same length.
* Exposed for the JITs; for ordinary uses, EqualStrings() is more sensible.
*
* Precondition: str1->length() == str2->length().
*/
extern bool
EqualChars(JSLinearString* str1, JSLinearString* str2);
/*
* Return less than, equal to, or greater than zero depending on whether
* `s1[0..len1]` is less than, equal to, or greater than `s2`.
*/
extern int32_t
CompareChars(const char16_t* s1, size_t len1, JSLinearString* s2);
/*
* Compare two strings, like CompareChars, but store the result in `*result`.
* This flattens the strings and therefore can fail.
*/
extern bool
CompareStrings(JSContext* cx, JSString* str1, JSString* str2, int32_t* result);
/*
* Same as CompareStrings but for atoms. Don't use this to just test
* for equality; use this when you need an ordering on atoms.
*/
extern int32_t
CompareAtoms(JSAtom* atom1, JSAtom* atom2);
/*
* Return true if the string matches the given sequence of ASCII bytes.
*/
extern bool
StringEqualsAscii(JSLinearString* str, const char* asciiBytes);
extern int
StringFindPattern(JSLinearString* text, JSLinearString* pat, size_t start);
/**
* Return true if the string contains a pattern at |start|.
*
* Precondition: `text` is long enough that this might be true;
* that is, it has at least `start + pat->length()` characters.
*/
extern bool
HasSubstringAt(JSLinearString* text, JSLinearString* pat, size_t start);
/*
* Computes |str|'s substring for the range [beginInt, beginInt + lengthInt).
* Negative, overlarge, swapped, etc. |beginInt| and |lengthInt| are forbidden
* and constitute API misuse.
*/
JSString*
SubstringKernel(JSContext* cx, HandleString str, int32_t beginInt, int32_t lengthInt);
/*** Conversions *********************************************************************************/
/*
* Convert a value to a printable C string.
*/
extern const char*
ValueToPrintable(JSContext* cx, const Value&, JSAutoByteString* bytes, bool asSource = false);
/*
* Convert a non-string value to a string, returning null after reporting an
* error, otherwise returning a new string reference.
*/
template <AllowGC allowGC>
extern JSString*
ToStringSlow(JSContext* cx, typename MaybeRooted<Value, allowGC>::HandleType arg);
/*
* Convert the given value to a string. This method includes an inline
* fast-path for the case where the value is already a string; if the value is
* known not to be a string, use ToStringSlow instead.
*/
template <AllowGC allowGC>
static MOZ_ALWAYS_INLINE JSString*
ToString(JSContext* cx, JS::HandleValue v)
{
if (v.isString())
return v.toString();
return ToStringSlow<allowGC>(cx, v);
}
/*
* This function implements E-262-3 section 9.8, toString. Convert the given
* value to a string of characters appended to the given buffer. On error, the
* passed buffer may have partial results appended.
*/
inline bool
ValueToStringBuffer(JSContext* cx, const Value& v, StringBuffer& sb);
/*
* Convert a value to its source expression, returning null after reporting
* an error, otherwise returning a new string reference.
*/
extern JSString*
ValueToSource(JSContext* cx, HandleValue v);
/*
* Convert a JSString to its source expression; returns null after reporting an
* error, otherwise returns a new string reference. No Handle needed since the
* input is dead after the GC.
*/
extern JSString*
StringToSource(JSContext* cx, JSString* str);
} /* namespace js */
// Addon IDs are interned atoms which are never destroyed. This detail is

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

@ -22,6 +22,7 @@
#include "js/UniquePtr.h"
#include "threading/LockGuard.h"
#include "threading/Thread.h"
#include "util/Text.h"
#include "vm/TraceLogging.h"
#ifndef DEFAULT_TRACE_LOG_DIR

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

@ -6,6 +6,8 @@
#include "vm/TraceLoggingTypes.h"
#include "vm/StringType.h"
class JSLinearString;
uint32_t

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

@ -21,6 +21,7 @@
#include "js/TypeDecls.h"
#include "js/Utility.h"
#include "js/Vector.h"
#include "util/Text.h"
#include "vm/Debugger.h"
#include "vm/EnvironmentObject.h"
#include "vm/GlobalObject.h"

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

@ -6,6 +6,7 @@
#include "js/UbiNodeCensus.h"
#include "util/Text.h"
#include "vm/JSCompartment.h"
#include "vm/JSContext.h"

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

@ -10,6 +10,7 @@
#include "mozilla/Move.h"
#include "builtin/String.h"
#include "util/Text.h"
namespace JS {
namespace ubi {

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

@ -35,6 +35,7 @@
#include "js/Printf.h"
#include "js/Wrapper.h"
#include "util/StringBuffer.h"
#include "util/Text.h"
#include "vm/ErrorReporting.h"
#include "vm/SelfHosting.h"
#include "vm/Time.h"

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

@ -22,6 +22,7 @@
#include "mozilla/Unused.h"
#include "jit/ProcessExecutableMemory.h"
#include "util/Text.h"
#include "wasm/WasmBaselineCompile.h"
#include "wasm/WasmBinaryIterator.h"
#include "wasm/WasmGenerator.h"

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

@ -25,6 +25,7 @@
#include "jit/ExecutableAllocator.h"
#include "jit/MacroAssembler.h"
#include "util/StringBuffer.h"
#include "util/Text.h"
#include "vm/Debugger.h"
#include "wasm/WasmBinaryToText.h"
#include "wasm/WasmInstance.h"

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

@ -24,6 +24,7 @@
#include <algorithm>
#include "util/Text.h"
#include "wasm/WasmBaselineCompile.h"
#include "wasm/WasmCompile.h"
#include "wasm/WasmIonCompile.h"

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

@ -29,6 +29,7 @@
#include "jit/JitOptions.h"
#include "js/Printf.h"
#include "util/StringBuffer.h"
#include "util/Text.h"
#include "vm/Interpreter.h"
#include "vm/StringType.h"
#include "wasm/WasmBaselineCompile.h"