Bug 609440, part 4 - make JSString::chars() fallible (r=waldo,dvander,igor,dwitte,njn)

This commit is contained in:
Luke Wagner 2010-12-06 10:26:58 -08:00
parent 56b2810a26
commit e4bb2ca2a9
54 changed files with 1749 additions and 1216 deletions

View File

@ -1292,7 +1292,10 @@ StringToInteger(JSContext* cx, JSString* string, IntegerType* result)
{
JS_STATIC_ASSERT(numeric_limits<IntegerType>::is_exact);
const jschar* cp = string->chars();
const jschar* cp = string->getChars(NULL);
if (!cp)
return false;
const jschar* end = cp + string->length();
if (cp == end)
return false;
@ -1780,9 +1783,10 @@ ImplicitConvert(JSContext* cx,
JSString* str = JSVAL_TO_STRING(val); \
if (str->length() != 1) \
return TypeError(cx, #name, val); \
\
result = str->chars()[0]; \
\
const jschar *chars = str->getChars(cx); \
if (!chars) \
return false; \
result = chars[0]; \
} else if (!jsvalToInteger(cx, val, &result)) { \
return TypeError(cx, #name, val); \
} \
@ -1824,8 +1828,10 @@ ImplicitConvert(JSContext* cx,
// which the caller assumes ownership of.
// TODO: Extend this so we can safely convert strings at other times also.
JSString* sourceString = JSVAL_TO_STRING(val);
const jschar* sourceChars = sourceString->chars();
size_t sourceLength = sourceString->length();
const jschar* sourceChars = sourceString->getChars(cx);
if (!sourceChars)
return false;
switch (CType::GetTypeCode(cx, baseType)) {
case TYPE_char:
@ -1879,8 +1885,10 @@ ImplicitConvert(JSContext* cx,
if (JSVAL_IS_STRING(val)) {
JSString* sourceString = JSVAL_TO_STRING(val);
const jschar* sourceChars = sourceString->chars();
size_t sourceLength = sourceString->length();
const jschar* sourceChars = sourceString->getChars(cx);
if (!sourceChars)
return false;
switch (CType::GetTypeCode(cx, baseType)) {
case TYPE_char:
@ -1989,21 +1997,18 @@ ImplicitConvert(JSContext* cx,
if (JSID_IS_VOID(id))
break;
js::AutoValueRooter fieldVal(cx);
JS_IdToValue(cx, id, fieldVal.jsval_addr());
if (!JSVAL_IS_STRING(fieldVal.jsval_value())) {
if (!JSID_IS_STRING(id)) {
JS_ReportError(cx, "property name is not a string");
return false;
}
const FieldInfo* field = StructType::LookupField(cx, targetType,
JSVAL_TO_STRING(fieldVal.jsval_value()));
JSFlatString *name = JSID_TO_FLAT_STRING(id);
const FieldInfo* field = StructType::LookupField(cx, targetType, name);
if (!field)
return false;
JSString* name = JSVAL_TO_STRING(fieldVal.jsval_value());
js::AutoValueRooter prop(cx);
if (!JS_GetUCProperty(cx, obj, name->chars(), name->length(), prop.jsval_addr()))
if (!JS_GetPropertyById(cx, obj, id, prop.jsval_addr()))
return false;
// Convert the field via ImplicitConvert().
@ -3567,8 +3572,10 @@ ArrayType::ConstructData(JSContext* cx,
// We were given a string. Size the array to the appropriate length,
// including space for the terminator.
JSString* sourceString = JSVAL_TO_STRING(argv[0]);
const jschar* sourceChars = sourceString->chars();
size_t sourceLength = sourceString->length();
const jschar* sourceChars = sourceString->getChars(cx);
if (!sourceChars)
return false;
switch (CType::GetTypeCode(cx, baseType)) {
case TYPE_char:
@ -3871,7 +3878,7 @@ ArrayType::AddressOfElement(JSContext* cx, uintN argc, jsval* vp)
// For a struct field descriptor 'val' of the form { name : type }, extract
// 'name' and 'type'.
static JSString*
static JSFlatString*
ExtractStructField(JSContext* cx, jsval val, JSObject** typeObj)
{
if (JSVAL_IS_PRIMITIVE(val)) {
@ -3885,23 +3892,21 @@ ExtractStructField(JSContext* cx, jsval val, JSObject** typeObj)
return NULL;
js::AutoObjectRooter iterroot(cx, iter);
jsid id;
if (!JS_NextProperty(cx, iter, &id))
jsid nameid;
if (!JS_NextProperty(cx, iter, &nameid))
return NULL;
if (JSID_IS_VOID(id)) {
if (JSID_IS_VOID(nameid)) {
JS_ReportError(cx, "struct field descriptors require a valid name and type");
return NULL;
}
js::AutoValueRooter nameVal(cx);
JS_IdToValue(cx, id, nameVal.jsval_addr());
if (!JSVAL_IS_STRING(nameVal.jsval_value())) {
if (!JSID_IS_STRING(nameid)) {
JS_ReportError(cx, "struct field descriptors require a valid name and type");
return NULL;
}
JSString* name = JSVAL_TO_STRING(nameVal.jsval_value());
// make sure we have one, and only one, property
jsid id;
if (!JS_NextProperty(cx, iter, &id))
return NULL;
if (!JSID_IS_VOID(id)) {
@ -3910,7 +3915,7 @@ ExtractStructField(JSContext* cx, jsval val, JSObject** typeObj)
}
js::AutoValueRooter propVal(cx);
if (!JS_GetUCProperty(cx, obj, name->chars(), name->length(), propVal.jsval_addr()))
if (!JS_GetPropertyById(cx, obj, nameid, propVal.jsval_addr()))
return NULL;
if (propVal.value().isPrimitive() ||
@ -3929,7 +3934,7 @@ ExtractStructField(JSContext* cx, jsval val, JSObject** typeObj)
return NULL;
}
return name;
return JSID_TO_FLAT_STRING(nameid);
}
// For a struct field with 'name' and 'type', add an element of the form
@ -3937,7 +3942,7 @@ ExtractStructField(JSContext* cx, jsval val, JSObject** typeObj)
static JSBool
AddFieldToArray(JSContext* cx,
jsval* element,
JSString* name,
JSFlatString* name,
JSObject* typeObj)
{
JSObject* fieldObj = JS_NewObject(cx, NULL, NULL, NULL);
@ -4048,7 +4053,7 @@ StructType::DefineInternal(JSContext* cx, JSObject* typeObj, JSObject* fieldsObj
return JS_FALSE;
JSObject* fieldType = NULL;
JSString* name = ExtractStructField(cx, item.jsval_value(), &fieldType);
JSFlatString* name = ExtractStructField(cx, item.jsval_value(), &fieldType);
if (!name)
return JS_FALSE;
fieldRootsArray[i] = OBJECT_TO_JSVAL(fieldType);
@ -4321,7 +4326,7 @@ StructType::GetFieldInfo(JSContext* cx, JSObject* obj)
}
const FieldInfo*
StructType::LookupField(JSContext* cx, JSObject* obj, JSString *name)
StructType::LookupField(JSContext* cx, JSObject* obj, JSFlatString *name)
{
JS_ASSERT(CType::IsCType(cx, obj));
JS_ASSERT(CType::GetTypeCode(cx, obj) == TYPE_struct);
@ -4417,7 +4422,7 @@ StructType::FieldGetter(JSContext* cx, JSObject* obj, jsid idval, jsval* vp)
return JS_FALSE;
}
const FieldInfo* field = LookupField(cx, typeObj, JSID_TO_STRING(idval));
const FieldInfo* field = LookupField(cx, typeObj, JSID_TO_FLAT_STRING(idval));
if (!field)
return JS_FALSE;
@ -4439,7 +4444,7 @@ StructType::FieldSetter(JSContext* cx, JSObject* obj, jsid idval, jsval* vp)
return JS_FALSE;
}
const FieldInfo* field = LookupField(cx, typeObj, JSID_TO_STRING(idval));
const FieldInfo* field = LookupField(cx, typeObj, JSID_TO_FLAT_STRING(idval));
if (!field)
return JS_FALSE;
@ -4467,8 +4472,11 @@ StructType::AddressOfField(JSContext* cx, uintN argc, jsval* vp)
return JS_FALSE;
}
const FieldInfo* field = LookupField(cx, typeObj,
JSVAL_TO_STRING(JS_ARGV(cx, vp)[0]));
JSFlatString *str = JS_FlattenString(cx, JSVAL_TO_STRING(JS_ARGV(cx, vp)[0]));
if (!str)
return JS_FALSE;
const FieldInfo* field = LookupField(cx, typeObj, str);
if (!field)
return JS_FALSE;
@ -4611,18 +4619,23 @@ PrepareReturnType(JSContext* cx, jsval type)
return result;
}
static JS_ALWAYS_INLINE bool
IsEllipsis(jsval v)
static JS_ALWAYS_INLINE JSBool
IsEllipsis(JSContext* cx, jsval v, bool* isEllipsis)
{
*isEllipsis = false;
if (!JSVAL_IS_STRING(v))
return false;
return true;
JSString* str = JSVAL_TO_STRING(v);
if (str->length() != 3)
return true;
const jschar* chars = str->getChars(cx);
if (!chars)
return false;
const jschar* chars = str->chars(), dot('.');
return (chars[0] == dot &&
chars[1] == dot &&
chars[2] == dot);
jschar dot = '.';
*isEllipsis = (chars[0] == dot &&
chars[1] == dot &&
chars[2] == dot);
return true;
}
static JSBool
@ -4737,7 +4750,10 @@ NewFunctionInfo(JSContext* cx,
fninfo->mIsVariadic = false;
for (JSUint32 i = 0; i < argLength; ++i) {
if (IsEllipsis(argTypes[i])) {
bool isEllipsis;
if (!IsEllipsis(cx, argTypes[i], &isEllipsis))
return false;
if (isEllipsis) {
fninfo->mIsVariadic = true;
if (i < 1) {
JS_ReportError(cx, "\"...\" may not be the first and only parameter "

View File

@ -141,7 +141,10 @@ void
AppendString(Vector<jschar, N, AP> &v, JSString* str)
{
JS_ASSERT(str);
v.append(str->chars(), str->length());
const jschar *chars = str->getChars(NULL);
if (!chars)
return;
v.append(chars, str->length());
}
template <size_t N, class AP>
@ -154,8 +157,12 @@ AppendString(Vector<char, N, AP> &v, JSString* str)
if (!v.resize(vlen + alen))
return;
const jschar *chars = str->getChars(NULL);
if (!chars)
return;
for (size_t i = 0; i < alen; ++i)
v[i + vlen] = char(str->chars()[i]);
v[i + vlen] = char(chars[i]);
}
template <class T, size_t N, class AP, size_t ArrayLength>
@ -186,33 +193,15 @@ PrependString(Vector<jschar, N, AP> &v, JSString* str)
if (!v.resize(vlen + alen))
return;
const jschar *chars = str->getChars(NULL);
if (!chars)
return;
// Move vector data forward. This is safe since we've already resized.
memmove(v.begin() + alen, v.begin(), vlen * sizeof(jschar));
// Copy data to insert.
memcpy(v.begin(), str->chars(), alen * sizeof(jschar));
}
template <class T, size_t N, size_t M, class AP>
bool
StringsEqual(Vector<T, N, AP> &v, Vector<T, M, AP> &w)
{
if (v.length() != w.length())
return false;
return memcmp(v.begin(), w.begin(), v.length() * sizeof(T)) == 0;
}
template <size_t N, class AP>
bool
StringsEqual(Vector<jschar, N, AP> &v, JSString* str)
{
JS_ASSERT(str);
size_t length = str->length();
if (v.length() != length)
return false;
return memcmp(v.begin(), str->chars(), length * sizeof(jschar)) == 0;
memcpy(v.begin(), chars, alen * sizeof(jschar));
}
/*******************************************************************************
@ -274,7 +263,7 @@ struct FieldInfo
// Hash policy for FieldInfos.
struct FieldHashPolicy
{
typedef JSString* Key;
typedef JSFlatString* Key;
typedef Key Lookup;
static uint32 hash(const Lookup &l) {
@ -297,7 +286,7 @@ struct FieldHashPolicy
}
};
typedef HashMap<JSString*, FieldInfo, FieldHashPolicy, SystemAllocPolicy> FieldInfoHash;
typedef HashMap<JSFlatString*, FieldInfo, FieldHashPolicy, SystemAllocPolicy> FieldInfoHash;
// Descriptor of ABI, return type, argument types, and variadicity for a
// FunctionType.
@ -482,7 +471,7 @@ namespace StructType {
JSBool DefineInternal(JSContext* cx, JSObject* typeObj, JSObject* fieldsObj);
const FieldInfoHash* GetFieldInfo(JSContext* cx, JSObject* obj);
const FieldInfo* LookupField(JSContext* cx, JSObject* obj, JSString *name);
const FieldInfo* LookupField(JSContext* cx, JSObject* obj, JSFlatString *name);
JSObject* BuildFieldsArray(JSContext* cx, JSObject* obj);
ffi_type* BuildFFIType(JSContext* cx, JSObject* obj);
}

View File

@ -133,12 +133,13 @@ Library::Create(JSContext* cx, jsval path, JSCTypesCallbacks* callbacks)
}
PRLibSpec libSpec;
JSString* pathStr = JSVAL_TO_STRING(path);
JSFlatString* pathStr = JS_FlattenString(cx, JSVAL_TO_STRING(path));
if (!pathStr)
return NULL;
#ifdef XP_WIN
// On Windows, converting to native charset may corrupt path string.
// So, we have to use Unicode path directly.
const PRUnichar* pathChars = reinterpret_cast<const PRUnichar*>(
JS_GetStringCharsZ(cx, pathStr));
const PRUnichar* pathChars = JS_GetFlatStringChars(pathStr);
if (!pathChars)
return NULL;

View File

@ -584,16 +584,14 @@ JS_PUBLIC_API(JSBool)
JS_StrictlyEqual(JSContext *cx, jsval v1, jsval v2, JSBool *equal)
{
assertSameCompartment(cx, v1, v2);
*equal = StrictlyEqual(cx, Valueify(v1), Valueify(v2));
return JS_TRUE;
return StrictlyEqual(cx, Valueify(v1), Valueify(v2), equal);
}
JS_PUBLIC_API(JSBool)
JS_SameValue(JSContext *cx, jsval v1, jsval v2, JSBool *same)
{
assertSameCompartment(cx, v1, v2);
*same = SameValue(Valueify(v1), Valueify(v2), cx);
return JS_TRUE;
return SameValue(cx, Valueify(v1), Valueify(v2), same);
}
/************************************************************************/
@ -2239,8 +2237,14 @@ JS_PrintTraceThingInfo(char *buf, size_t bufsize, JSTracer *trc, void *thing, ui
}
case JSTRACE_STRING:
PutEscapedString(buf, bufsize, (JSString *)thing, 0);
{
JSString *str = (JSString *)thing;
if (str->isLinear())
PutEscapedString(buf, bufsize, str->assertIsLinear(), 0);
else
JS_snprintf(buf, bufsize, "<rope: length %d>", (int)str->length());
break;
}
#if JS_HAS_XML_SUPPORT
case JSTRACE_XML:
@ -5208,17 +5212,8 @@ JS_RestoreFrameChain(JSContext *cx, JSStackFrame *fp)
JS_PUBLIC_API(JSString *)
JS_NewStringCopyN(JSContext *cx, const char *s, size_t n)
{
jschar *js;
JSString *str;
CHECK_REQUEST(cx);
js = js_InflateString(cx, s, &n);
if (!js)
return NULL;
str = js_NewString(cx, js, n);
if (!str)
cx->free(js);
return str;
return js_NewStringCopyN(cx, s, n);
}
JS_PUBLIC_API(JSString *)
@ -5338,9 +5333,8 @@ JS_GetStringCharsAndLength(JSContext *cx, JSString *str, size_t *plength)
{
CHECK_REQUEST(cx);
assertSameCompartment(cx, str);
const jschar *chars;
str->getCharsAndLength(chars, *plength);
return chars;
*plength = str->length();
return str->getChars(cx);
}
JS_PUBLIC_API(const jschar *)
@ -5369,26 +5363,29 @@ JS_FlattenString(JSContext *cx, JSString *str)
extern JS_PUBLIC_API(const jschar *)
JS_GetFlatStringChars(JSFlatString *str)
{
return reinterpret_cast<JSString *>(str)->flatChars();
return str->chars();
}
JS_PUBLIC_API(JSBool)
JS_CompareStrings(JSContext *cx, JSString *str1, JSString *str2, int32 *result)
{
*result = js_CompareStrings(str1, str2);
return JS_TRUE;
return CompareStrings(cx, str1, str2, result);
}
JS_PUBLIC_API(JSBool)
JS_StringEqualsAscii(JSContext *cx, JSString *str, const char *asciiBytes, JSBool *match)
{
return MatchStringAndAscii(str, asciiBytes);
JSLinearString *linearStr = str->ensureLinear(cx);
if (!linearStr)
return false;
*match = StringEqualsAscii(linearStr, asciiBytes);
return true;
}
JS_PUBLIC_API(JSBool)
JS_FlatStringEqualsAscii(JSFlatString *str, const char *asciiBytes)
{
return MatchStringAndAscii(str, asciiBytes);
return StringEqualsAscii(str, asciiBytes);
}
JS_PUBLIC_API(size_t)
@ -5400,13 +5397,17 @@ JS_PutEscapedFlatString(char *buffer, size_t size, JSFlatString *str, char quote
JS_PUBLIC_API(size_t)
JS_PutEscapedString(JSContext *cx, char *buffer, size_t size, JSString *str, char quote)
{
return PutEscapedString(buffer, size, str, quote);
JSLinearString *linearStr = str->ensureLinear(cx);
if (!linearStr)
return size_t(-1);
return PutEscapedString(buffer, size, linearStr, quote);
}
JS_PUBLIC_API(JSBool)
JS_FileEscapedString(FILE *fp, JSString *str, char quote)
{
return FileEscapedString(fp, str, quote);
JSLinearString *linearStr = str->ensureLinear(NULL);
return linearStr && FileEscapedString(fp, linearStr, quote);
}
JS_PUBLIC_API(JSString *)
@ -5470,13 +5471,19 @@ JS_DecodeBytes(JSContext *cx, const char *src, size_t srclen, jschar *dst, size_
JS_PUBLIC_API(char *)
JS_EncodeString(JSContext *cx, JSString *str)
{
return js_DeflateString(cx, str->chars(), str->length());
const jschar *chars = str->getChars(cx);
if (!chars)
return NULL;
return js_DeflateString(cx, chars, str->length());
}
JS_PUBLIC_API(size_t)
JS_GetStringEncodingLength(JSContext *cx, JSString *str)
{
return js_GetDeflatedStringLength(cx, str->chars(), str->length());
const jschar *chars = str->getChars(cx);
if (!chars)
return size_t(-1);
return js_GetDeflatedStringLength(cx, chars, str->length());
}
JS_PUBLIC_API(size_t)
@ -5488,12 +5495,15 @@ JS_EncodeStringToBuffer(JSString *str, char *buffer, size_t length)
* error.
*/
size_t writtenLength = length;
if (js_DeflateStringToBuffer(NULL, str->chars(), str->length(), buffer, &writtenLength)) {
const jschar *chars = str->getChars(NULL);
if (!chars)
return size_t(-1);
if (js_DeflateStringToBuffer(NULL, chars, str->length(), buffer, &writtenLength)) {
JS_ASSERT(writtenLength <= length);
return writtenLength;
}
JS_ASSERT(writtenLength <= length);
size_t necessaryLength = js_GetDeflatedStringLength(NULL, str->chars(), str->length());
size_t necessaryLength = js_GetDeflatedStringLength(NULL, chars, str->length());
if (necessaryLength == size_t(-1))
return size_t(-1);
if (writtenLength != length) {

View File

@ -143,10 +143,10 @@ ENSURE_SLOW_ARRAY(JSContext *cx, JSObject *obj)
* 'id' is passed as a jsboxedword since the given id need not necessarily hold
* an atomized string.
*/
JSBool
js_StringIsIndex(JSString *str, jsuint *indexp)
bool
js_StringIsIndex(JSLinearString *str, jsuint *indexp)
{
jschar *cp = str->chars();
const jschar *cp = str->chars();
if (JS7_ISDEC(*cp) && str->length() < sizeof(MAXSTR)) {
jsuint index = JS7_UNDEC(*cp++);
jsuint oldIndex = 0;
@ -166,10 +166,10 @@ js_StringIsIndex(JSString *str, jsuint *indexp)
(oldIndex == (MAXINDEX / 10) && c < (MAXINDEX % 10))))
{
*indexp = index;
return JS_TRUE;
return true;
}
}
return JS_FALSE;
return false;
}
static bool
@ -1149,12 +1149,13 @@ array_toSource(JSContext *cx, uintN argc, Value *vp)
goto out;
}
vp->setString(str);
const jschar *chars;
size_t charlen;
str->getCharsAndLength(chars, charlen);
const jschar *chars = str->getChars(cx);
if (!chars)
goto out;
/* Append element to buffer. */
if (!cb.append(chars, charlen))
if (!cb.append(chars, chars + str->length()))
goto out;
if (index + 1 != length) {
if (!js_AppendLiteral(cb, ", "))
@ -1188,6 +1189,20 @@ array_toString_sub(JSContext *cx, JSObject *obj, JSBool locale,
{
JS_CHECK_RECURSION(cx, return false);
/* Get characters to use for the separator. */
static const jschar comma = ',';
const jschar *sep;
size_t seplen;
if (sepstr) {
seplen = sepstr->length();
sep = sepstr->getChars(cx);
if (!sep)
return false;
} else {
sep = &comma;
seplen = 1;
}
/*
* Use HashTable entry as the cycle indicator. On first visit, create the
* entry, and, when leaving, remove the entry.
@ -1197,10 +1212,8 @@ array_toString_sub(JSContext *cx, JSObject *obj, JSBool locale,
uint32 genBefore;
if (!hashp) {
/* Not in hash table, so not a cycle. */
if (!cx->busyArrays.add(hashp, obj)) {
JS_ReportOutOfMemory(cx);
if (!cx->busyArrays.add(hashp, obj))
return false;
}
genBefore = cx->busyArrays.generation();
} else {
/* Cycle, so return empty string. */
@ -1214,17 +1227,6 @@ array_toString_sub(JSContext *cx, JSObject *obj, JSBool locale,
MUST_FLOW_THROUGH("out");
bool ok = false;
/* Get characters to use for the separator. */
static const jschar comma = ',';
const jschar *sep;
size_t seplen;
if (sepstr) {
sepstr->getCharsAndLength(sep, seplen);
} else {
sep = &comma;
seplen = 1;
}
/*
* This object will take responsibility for the jschar buffer until the
* buffer is transferred to the returned JSString.
@ -1710,15 +1712,10 @@ comparator_stack_cast(JSRedComparator func)
static int
sort_compare_strings(void *arg, const void *a, const void *b, int *result)
{
const Value *av = (const Value *)a, *bv = (const Value *)b;
JS_ASSERT(av->isString());
JS_ASSERT(bv->isString());
if (!JS_CHECK_OPERATION_LIMIT((JSContext *)arg))
return JS_FALSE;
*result = (int) js_CompareStrings(av->toString(), bv->toString());
return JS_TRUE;
JSContext *cx = (JSContext *)arg;
JSString *astr = ((const Value *)a)->toString();
JSString *bstr = ((const Value *)b)->toString();
return JS_CHECK_OPERATION_LIMIT(cx) && CompareStrings(cx, astr, bstr, result);
}
JSBool
@ -2615,9 +2612,14 @@ array_indexOfHelper(JSContext *cx, JSBool isLast, uintN argc, Value *vp)
!GetElement(cx, obj, (jsuint)i, &hole, vp)) {
return JS_FALSE;
}
if (!hole && StrictlyEqual(cx, *vp, tosearch)) {
vp->setNumber(i);
return JS_TRUE;
if (!hole) {
JSBool equal;
if (!StrictlyEqual(cx, *vp, tosearch, &equal))
return JS_FALSE;
if (equal) {
vp->setNumber(i);
return JS_TRUE;
}
}
if (i == stop)
goto not_found;

View File

@ -44,6 +44,7 @@
*/
#include "jsprvtd.h"
#include "jspubtd.h"
#include "jsatom.h"
#include "jsobj.h"
#include "jsstr.h"
@ -87,8 +88,8 @@ JSObject::ensureDenseArrayElements(JSContext *cx, uintN index, uintN extra)
return growSlots(cx, requiredCapacity) ? ED_OK : ED_FAILED;
}
extern JSBool
js_StringIsIndex(JSString *str, jsuint *indexp);
extern bool
js_StringIsIndex(JSLinearString *str, jsuint *indexp);
inline JSBool
js_IdIsIndex(jsid id, jsuint *indexp)
@ -105,26 +106,36 @@ js_IdIsIndex(jsid id, jsuint *indexp)
if (JS_UNLIKELY(!JSID_IS_STRING(id)))
return JS_FALSE;
return js_StringIsIndex(JSID_TO_STRING(id), indexp);
return js_StringIsIndex(JSID_TO_ATOM(id), indexp);
}
/* XML really wants to pretend jsvals are jsids. */
inline JSBool
js_IdValIsIndex(jsval id, jsuint *indexp)
inline bool
js_IdValIsIndex(JSContext *cx, jsval id, jsuint *indexp, bool *isIndex)
{
if (JSVAL_IS_INT(id)) {
jsint i;
i = JSVAL_TO_INT(id);
if (i < 0)
return JS_FALSE;
if (i < 0) {
*isIndex = false;
return true;
}
*indexp = (jsuint)i;
return JS_TRUE;
*isIndex = true;
return true;
}
if (!JSVAL_IS_STRING(id))
return JS_FALSE;
if (!JSVAL_IS_STRING(id)) {
*isIndex = false;
return true;
}
return js_StringIsIndex(JSVAL_TO_STRING(id), indexp);
JSLinearString *str = JSVAL_TO_STRING(id)->ensureLinear(cx);
if (!str)
return false;
*isIndex = js_StringIsIndex(str, indexp);
return true;
}
extern js::Class js_ArrayClass, js_SlowArrayClass;

View File

@ -457,17 +457,20 @@ js_SweepAtomState(JSContext *cx)
}
JSAtom *
js_AtomizeString(JSContext *cx, JSString *str, uintN flags)
js_AtomizeString(JSContext *cx, JSString *strArg, uintN flags)
{
JS_ASSERT(!(flags & ~(ATOM_PINNED|ATOM_INTERNED|ATOM_TMPSTR|ATOM_NOCOPY)));
JS_ASSERT_IF(flags & ATOM_NOCOPY, flags & ATOM_TMPSTR);
if (str->isAtomized())
return STRING_TO_ATOM(str);
if (strArg->isAtomized())
return STRING_TO_ATOM(strArg);
const jschar *chars;
size_t length;
str->getCharsAndLength(chars, length);
JSLinearString *str = strArg->ensureLinear(cx);
if (!str)
return NULL;
const jschar *chars = str->chars();
size_t length = str->length();
JSString *staticStr = JSString::lookupStaticString(chars, length);
if (staticStr)
@ -482,7 +485,7 @@ js_AtomizeString(JSContext *cx, JSString *str, uintN flags)
/* Hashing the string should have flattened it if it was a rope. */
JS_ASSERT(str->isFlat() || str->isDependent());
JSString *key;
JSLinearString *key;
if (p) {
key = AtomEntryToKey(*p);
} else {
@ -506,9 +509,8 @@ js_AtomizeString(JSContext *cx, JSString *str, uintN flags)
} else {
if (needNewString) {
SwitchToCompartment sc(cx, cx->runtime->defaultCompartment);
jschar *chars = str->chars();
if (flags & ATOM_NOCOPY) {
key = js_NewString(cx, chars, length);
key = js_NewString(cx, const_cast<jschar *>(str->flatChars()), length);
if (!key)
return NULL;
@ -537,7 +539,6 @@ js_AtomizeString(JSContext *cx, JSString *str, uintN flags)
AddAtomEntryFlags(*p, flags & (ATOM_PINNED | ATOM_INTERNED));
JS_ASSERT(key->isAtomized());
JSAtom *atom = STRING_TO_ATOM(key);
return atom;
}
@ -607,7 +608,7 @@ js_GetExistingStringAtom(JSContext *cx, const jschar *chars, size_t length)
state = &cx->runtime->atomState;
JS_LOCK(cx, &state->lock);
AtomSet::Ptr p = state->atoms.lookup(&str);
AtomSet::Ptr p = state->atoms.lookup(str.assertIsFlat());
str2 = p ? AtomEntryToKey(*p) : NULL;
JS_UNLOCK(cx, &state->lock);
@ -628,7 +629,7 @@ js_DumpAtoms(JSContext *cx, FILE *fp)
if (entry == 0) {
fputs("<uninitialized>", fp);
} else {
JSString *key = AtomEntryToKey(entry);
JSAtom *key = AtomEntryToKey(entry);
FileEscapedString(fp, key, '"');
uintN flags = AtomEntryFlags(entry);
if (flags != 0) {

View File

@ -60,7 +60,7 @@
#define STRING_TO_ATOM(str) (JS_ASSERT(str->isAtomized()), \
(JSAtom *)str)
#define ATOM_TO_STRING(atom) (JS_ASSERT_STRING_IS_FLAT((JSString *)(atom)))
#define ATOM_TO_STRING(atom) (atom)
#define ATOM_TO_JSVAL(atom) STRING_TO_JSVAL(ATOM_TO_STRING(atom))
/* Engine-internal extensions of jsid */
@ -265,23 +265,23 @@ JS_STATIC_ASSERT(ATOM_ENTRY_FLAG_MASK < JS_GCTHING_ALIGN);
typedef uintptr_t AtomEntryType;
static JS_ALWAYS_INLINE JSString *
static JS_ALWAYS_INLINE JSAtom *
AtomEntryToKey(AtomEntryType entry)
{
JS_ASSERT(entry != 0);
return (JSString *)(entry & ~ATOM_ENTRY_FLAG_MASK);
return (JSAtom *)(entry & ~ATOM_ENTRY_FLAG_MASK);
}
struct AtomHasher
{
typedef JSString *Lookup;
typedef JSLinearString *Lookup;
static HashNumber hash(JSString *str) {
static HashNumber hash(JSLinearString *str) {
return js_HashString(str);
}
static bool match(AtomEntryType entry, JSString *lookup) {
return entry ? js_EqualStrings(AtomEntryToKey(entry), lookup) : false;
static bool match(AtomEntryType entry, JSLinearString *lookup) {
return entry ? EqualStrings(AtomEntryToKey(entry), lookup) : false;
}
};

View File

@ -168,18 +168,22 @@ js_DoubleToUint32(jsdouble d)
JS_DEFINE_CALLINFO_1(extern, UINT32, js_DoubleToUint32, DOUBLE, 1, ACCSET_NONE)
jsdouble FASTCALL
js_StringToNumber(JSContext* cx, JSString* str)
js_StringToNumber(JSContext* cx, JSString* str, JSBool *ok)
{
return StringToNumberType<jsdouble>(cx, str);
double out = 0; /* silence warnings. */
*ok = StringToNumberType<jsdouble>(cx, str, &out);
return out;
}
JS_DEFINE_CALLINFO_2(extern, DOUBLE, js_StringToNumber, CONTEXT, STRING, 1, ACCSET_NONE)
JS_DEFINE_CALLINFO_3(extern, DOUBLE, js_StringToNumber, CONTEXT, STRING, BOOLPTR, 1, ACCSET_NONE)
int32 FASTCALL
js_StringToInt32(JSContext* cx, JSString* str)
js_StringToInt32(JSContext* cx, JSString* str, JSBool *ok)
{
return StringToNumberType<int32>(cx, str);
int32 out = 0; /* silence warnings. */
*ok = StringToNumberType<int32>(cx, str, &out);
return out;
}
JS_DEFINE_CALLINFO_2(extern, INT32, js_StringToInt32, CONTEXT, STRING, 1, ACCSET_NONE)
JS_DEFINE_CALLINFO_3(extern, INT32, js_StringToInt32, CONTEXT, STRING, BOOLPTR, 1, ACCSET_NONE)
/* Nb: it's always safe to set isDefinitelyAtom to false if you're unsure or don't know. */
static inline JSBool

View File

@ -547,7 +547,7 @@ struct ClosureVarInfo;
#define _JS_DEFINE_CALLINFO_n(n, args) JS_DEFINE_CALLINFO_##n args
jsdouble FASTCALL
js_StringToNumber(JSContext* cx, JSString* str);
js_StringToNumber(JSContext* cx, JSString* str, JSBool *ok);
/* Extern version of SetBuiltinError. */
extern JS_FRIEND_API(void)
@ -623,9 +623,9 @@ JS_DECLARE_CALLINFO(js_CloneRegExpObject)
/* Defined in jsstr.cpp. */
JS_DECLARE_CALLINFO(js_String_tn)
JS_DECLARE_CALLINFO(js_CompareStrings)
JS_DECLARE_CALLINFO(js_CompareStringsOnTrace)
JS_DECLARE_CALLINFO(js_ConcatStrings)
JS_DECLARE_CALLINFO(js_EqualStrings)
JS_DECLARE_CALLINFO(js_EqualStringsOnTrace)
JS_DECLARE_CALLINFO(js_Flatten)
/* Defined in jstypedarray.cpp. */

View File

@ -350,9 +350,10 @@ JS_STATIC_ASSERT(JSString::MAX_LENGTH < UINT32_MAX);
bool
JSStructuredCloneWriter::writeString(uint32_t tag, JSString *str)
{
const jschar *chars;
size_t length;
str->getCharsAndLength(chars, length);
size_t length = str->length();
const jschar *chars = str->getChars(context());
if (!chars)
return false;
return out.writePair(tag, uint32_t(length)) && out.writeChars(chars, length);
}
@ -750,9 +751,10 @@ JSStructuredCloneReader::startRead(Value *vp)
JSString *str = readString(nchars);
if (!str)
return false;
const jschar *chars;
size_t length;
str->getCharsAndLength(chars, length);
size_t length = str->length();
const jschar *chars = str->getChars(context());
if (!chars)
return false;
JSObject *obj = RegExp::createObjectNoStatics(context(), chars, length, data);
if (!obj)
return false;

View File

@ -1369,7 +1369,7 @@ struct JSRuntime {
js::Value negativeInfinityValue;
js::Value positiveInfinityValue;
JSString *emptyString;
JSFlatString *emptyString;
/* List of active contexts sharing this runtime; protected by gcLock. */
JSCList contextList;
@ -2386,10 +2386,10 @@ struct JSContext
#ifdef XP_WIN
volatile DollarPath *dollarPath;
volatile JSSubString *sub;
volatile jschar *blackBox;
volatile jschar **repstrChars;
volatile jschar **repstrDollar;
volatile jschar **repstrDollarEnd;
volatile const jschar *blackBox;
volatile const jschar **repstrChars;
volatile const jschar **repstrDollar;
volatile const jschar **repstrDollarEnd;
volatile size_t *peekLen;
#endif

View File

@ -204,7 +204,10 @@ JSCompartment::wrap(JSContext *cx, Value *vp)
if (vp->isString()) {
Value orig = *vp;
JSString *str = vp->toString();
JSString *wrapped = js_NewStringCopyN(cx, str->chars(), str->length());
const jschar *chars = str->getChars(cx);
if (!chars)
return false;
JSString *wrapped = js_NewStringCopyN(cx, chars, str->length());
if (!wrapped)
return false;
vp->setString(wrapped);

View File

@ -750,7 +750,7 @@ ndigits(size_t n, size_t *result, const jschar *s, size_t* i, size_t limit)
*/
static JSBool
date_parseISOString(JSString *str, jsdouble *result, JSContext *cx)
date_parseISOString(JSLinearString *str, jsdouble *result, JSContext *cx)
{
jsdouble msec;
@ -792,7 +792,8 @@ date_parseISOString(JSString *str, jsdouble *result, JSContext *cx)
if (!ndigits(n, &field, s, &i, limit)) { goto syntax; } \
JS_END_MACRO
str->getCharsAndLength(s, limit);
s = str->chars();
limit = str->length();
if (PEEK('+') || PEEK('-')) {
if (PEEK('-'))
@ -883,7 +884,7 @@ date_parseISOString(JSString *str, jsdouble *result, JSContext *cx)
}
static JSBool
date_parseString(JSString *str, jsdouble *result, JSContext *cx)
date_parseString(JSLinearString *str, jsdouble *result, JSContext *cx)
{
jsdouble msec;
@ -907,7 +908,8 @@ date_parseString(JSString *str, jsdouble *result, JSContext *cx)
if (date_parseISOString(str, result, cx))
return JS_TRUE;
str->getCharsAndLength(s, limit);
s = str->chars();
limit = str->length();
if (limit == 0)
goto syntax;
while (i < limit) {
@ -1167,7 +1169,11 @@ date_parse(JSContext *cx, uintN argc, Value *vp)
if (!str)
return JS_FALSE;
vp[2].setString(str);
if (!date_parseString(str, &result, cx)) {
JSLinearString *linearStr = str->ensureLinear(cx);
if (!linearStr)
return false;
if (!date_parseString(linearStr, &result, cx)) {
vp->setDouble(js_NaN);
return true;
}
@ -2377,8 +2383,6 @@ date_toString(JSContext *cx, uintN argc, Value *vp)
static JSBool
date_valueOf(JSContext *cx, uintN argc, Value *vp)
{
JSString *str, *number_str;
/* It is an error to call date_valueOf on a non-date object, but we don't
* need to check for that explicitly here because every path calls
* GetUTCTime, which does the check.
@ -2389,11 +2393,14 @@ date_valueOf(JSContext *cx, uintN argc, Value *vp)
return date_getTime(cx, argc, vp);
/* Convert to number only if the hint was given, otherwise favor string. */
str = js_ValueToString(cx, vp[2]);
JSString *str = js_ValueToString(cx, vp[2]);
if (!str)
return JS_FALSE;
number_str = ATOM_TO_STRING(cx->runtime->atomState.typeAtoms[JSTYPE_NUMBER]);
if (js_EqualStrings(str, number_str))
JSLinearString *linear_str = str->ensureLinear(cx);
if (!linear_str)
return JS_FALSE;
JSAtom *number_str = cx->runtime->atomState.typeAtoms[JSTYPE_NUMBER];
if (EqualStrings(linear_str, number_str))
return date_getTime(cx, argc, vp);
return date_toString(cx, argc, vp);
}
@ -2487,8 +2494,11 @@ js_Date(JSContext *cx, uintN argc, Value *vp)
if (!str)
return false;
argv[0].setString(str);
JSLinearString *linearStr = str->ensureLinear(cx);
if (!linearStr)
return false;
if (!date_parseString(str, &d, cx))
if (!date_parseString(linearStr, &d, cx))
d = js_NaN;
else
d = TIMECLIP(d);

View File

@ -612,10 +612,11 @@ StackTraceToString(JSContext *cx, JSExnPrivate *priv)
#define APPEND_STRING_TO_STACK(str) \
JS_BEGIN_MACRO \
JSString *str_ = str; \
const jschar *chars_; \
size_t length_; \
size_t length_ = str_->length(); \
const jschar *chars_ = str_->getChars(cx); \
if (!chars_) \
goto bad; \
\
str_->getCharsAndLength(chars_, length_); \
if (length_ > stackmax - stacklen) { \
void *ptr_; \
if (stackmax >= STACK_LENGTH_LIMIT || \
@ -813,11 +814,17 @@ exn_toString(JSContext *cx, uintN argc, Value *vp)
return JS_FALSE;
if (name_length) {
js_strncpy(cp, name->chars(), name_length);
const jschar *name_chars = name->getChars(cx);
if (!name_chars)
return JS_FALSE;
js_strncpy(cp, name_chars, name_length);
cp += name_length;
*cp++ = ':'; *cp++ = ' ';
}
js_strncpy(cp, message->chars(), message_length);
const jschar *message_chars = message->getChars(cx);
if (!message_chars)
return JS_FALSE;
js_strncpy(cp, message_chars, message_length);
cp += message_length;
*cp = 0;
@ -917,18 +924,27 @@ exn_toSource(JSContext *cx, uintN argc, Value *vp)
return false;
*cp++ = '('; *cp++ = 'n'; *cp++ = 'e'; *cp++ = 'w'; *cp++ = ' ';
js_strncpy(cp, name->chars(), name_length);
const jschar *name_chars = name->getChars(cx);
if (!name_chars)
return false;
js_strncpy(cp, name_chars, name_length);
cp += name_length;
*cp++ = '(';
const jschar *message_chars = message->getChars(cx);
if (!message_chars)
return false;
if (message_length != 0) {
js_strncpy(cp, message->chars(), message_length);
js_strncpy(cp, message_chars, message_length);
cp += message_length;
}
if (filename_length != 0) {
/* append filename as ``, {filename}'' */
*cp++ = ','; *cp++ = ' ';
js_strncpy(cp, filename->chars(), filename_length);
const jschar *filename_chars = filename->getChars(cx);
if (!filename_chars)
return false;
js_strncpy(cp, filename_chars, filename_length);
cp += filename_length;
} else {
if (lineno_as_str) {
@ -942,7 +958,10 @@ exn_toSource(JSContext *cx, uintN argc, Value *vp)
if (lineno_as_str) {
/* append lineno as ``, {lineno_as_str}'' */
*cp++ = ','; *cp++ = ' ';
js_strncpy(cp, lineno_as_str->chars(), lineno_length);
const jschar *lineno_chars = lineno_as_str->getChars(cx);
if (!lineno_chars)
return false;
js_strncpy(cp, lineno_chars, lineno_length);
cp += lineno_length;
}

View File

@ -2603,7 +2603,12 @@ Function(JSContext *cx, uintN argc, Value *vp)
for (uintN i = 0; i < n; i++) {
JSString *arg = argv[i].toString();
size_t arg_length = arg->length();
(void) js_strncpy(cp, arg->chars(), arg_length);
const jschar *arg_chars = arg->getChars(cx);
if (!arg_chars) {
JS_ARENA_RELEASE(&cx->tempPool, mark);
return JS_FALSE;
}
(void) js_strncpy(cp, arg_chars, arg_length);
cp += arg_length;
/* Add separating comma or terminating 0. */
@ -2690,8 +2695,11 @@ Function(JSContext *cx, uintN argc, Value *vp)
str = cx->runtime->emptyString;
}
return Compiler::compileFunctionBody(cx, fun, principals,
str->chars(), str->length(),
size_t length = str->length();
const jschar *chars = str->getChars(cx);
if (!chars)
return JS_FALSE;
return Compiler::compileFunctionBody(cx, fun, principals, chars, length,
filename, lineno);
}

View File

@ -1767,7 +1767,7 @@ js_FinalizeStringRT(JSRuntime *rt, JSString *str)
JS_ASSERT(IsFinalizableStringKind(thingKind));
/* A stillborn string has null chars, so is not valid. */
jschar *chars = str->flatChars();
jschar *chars = const_cast<jschar *>(str->flatChars());
if (!chars)
return;
if (thingKind == FINALIZE_STRING) {

View File

@ -362,9 +362,13 @@ GCMarker::dumpConservativeRoots()
}
case JSTRACE_STRING: {
JSString *str = (JSString *) i->thing;
char buf[50];
PutEscapedString(buf, sizeof buf, str, '"');
fprintf(fp, "string %s", buf);
if (str->isLinear()) {
char buf[50];
PutEscapedString(buf, sizeof buf, str->assertIsLinear(), '"');
fprintf(fp, "string %s", buf);
} else {
fprintf(fp, "rope: length %d", (int)str->length());
}
break;
}
# if JS_HAS_XML_SUPPORT

View File

@ -1130,40 +1130,44 @@ HasInstance(JSContext *cx, JSObject *obj, const Value *v, JSBool *bp)
return JS_FALSE;
}
static JS_ALWAYS_INLINE bool
EqualObjects(JSContext *cx, JSObject *lobj, JSObject *robj)
{
return lobj == robj;
}
bool
StrictlyEqual(JSContext *cx, const Value &lref, const Value &rref)
StrictlyEqual(JSContext *cx, const Value &lref, const Value &rref, JSBool *equal)
{
Value lval = lref, rval = rref;
if (SameType(lval, rval)) {
if (lval.isString())
return js_EqualStrings(lval.toString(), rval.toString());
if (lval.isDouble())
return JSDOUBLE_COMPARE(lval.toDouble(), ==, rval.toDouble(), JS_FALSE);
if (lval.isObject())
return EqualObjects(cx, &lval.toObject(), &rval.toObject());
if (lval.isUndefined())
return true;
return lval.payloadAsRawUint32() == rval.payloadAsRawUint32();
return EqualStrings(cx, lval.toString(), rval.toString(), equal);
if (lval.isDouble()) {
*equal = JSDOUBLE_COMPARE(lval.toDouble(), ==, rval.toDouble(), JS_FALSE);
return true;
}
if (lval.isObject()) {
*equal = &lval.toObject() == &rval.toObject();
return true;
}
if (lval.isUndefined()) {
*equal = true;
return true;
}
*equal = lval.payloadAsRawUint32() == rval.payloadAsRawUint32();
return true;
}
if (lval.isDouble() && rval.isInt32()) {
double ld = lval.toDouble();
double rd = rval.toInt32();
return JSDOUBLE_COMPARE(ld, ==, rd, JS_FALSE);
*equal = JSDOUBLE_COMPARE(ld, ==, rd, JS_FALSE);
return true;
}
if (lval.isInt32() && rval.isDouble()) {
double ld = lval.toInt32();
double rd = rval.toDouble();
return JSDOUBLE_COMPARE(ld, ==, rd, JS_FALSE);
*equal = JSDOUBLE_COMPARE(ld, ==, rd, JS_FALSE);
return true;
}
return false;
*equal = false;
return true;
}
static inline bool
@ -1179,15 +1183,21 @@ IsNaN(const Value &v)
}
bool
SameValue(const Value &v1, const Value &v2, JSContext *cx)
SameValue(JSContext *cx, const Value &v1, const Value &v2, JSBool *same)
{
if (IsNegativeZero(v1))
return IsNegativeZero(v2);
if (IsNegativeZero(v2))
return false;
if (IsNaN(v1) && IsNaN(v2))
if (IsNegativeZero(v1)) {
*same = IsNegativeZero(v2);
return true;
return StrictlyEqual(cx, v1, v2);
}
if (IsNegativeZero(v2)) {
*same = false;
return true;
}
if (IsNaN(v1) && IsNaN(v2)) {
*same = true;
return true;
}
return StrictlyEqual(cx, v1, v2, same);
}
JSType
@ -1516,7 +1526,6 @@ js_LogOpcode(JSContext *cx)
JSStackFrame *fp;
JSFrameRegs *regs;
intN ndefs, n, nuses;
JSString *str;
JSOp op;
logfp = (FILE *) cx->logfp;
@ -1562,12 +1571,13 @@ js_LogOpcode(JSContext *cx)
*/
fputs("<call>", logfp);
} else {
str = js_ValueToString(cx, *siter);
if (!str) {
JSString *str = js_ValueToString(cx, *siter);
JSLinearString *linearStr = str ? str->ensureLinear(cx) : NULL;
if (!linearStr) {
fputs("<null>", logfp);
} else {
JS_ClearPendingException(cx);
FileEscapedString(logfp, str, 0);
} else {
FileEscapedString(logfp, linearStr, 0);
}
}
fputc(' ', logfp);
@ -3389,7 +3399,10 @@ END_CASE(JSOP_BITAND)
if (SameType(lval, rval)) { \
if (lval.isString()) { \
JSString *l = lval.toString(), *r = rval.toString(); \
cond = js_EqualStrings(l, r) OP JS_TRUE; \
JSBool equal; \
if (!EqualStrings(cx, l, r, &equal)) \
goto error; \
cond = equal OP JS_TRUE; \
} else if (lval.isDouble()) { \
double l = lval.toDouble(), r = rval.toDouble(); \
cond = JSDOUBLE_COMPARE(l, OP, r, IFNAN); \
@ -3418,7 +3431,10 @@ END_CASE(JSOP_BITAND)
DEFAULT_VALUE(cx, -1, JSTYPE_VOID, rval); \
if (lval.isString() && rval.isString()) { \
JSString *l = lval.toString(), *r = rval.toString(); \
cond = js_EqualStrings(l, r) OP JS_TRUE; \
JSBool equal; \
if (!EqualStrings(cx, l, r, &equal)) \
goto error; \
cond = equal OP JS_TRUE; \
} else { \
double l, r; \
if (!ValueToNumber(cx, lval, &l) || \
@ -3450,7 +3466,10 @@ END_CASE(JSOP_NE)
JS_BEGIN_MACRO \
const Value &rref = regs.sp[-1]; \
const Value &lref = regs.sp[-2]; \
COND = StrictlyEqual(cx, lref, rref) OP true; \
JSBool equal; \
if (!StrictlyEqual(cx, lref, rref, &equal)) \
goto error; \
COND = equal OP true; \
regs.sp--; \
JS_END_MACRO
@ -3511,7 +3530,10 @@ END_CASE(JSOP_CASEX)
DEFAULT_VALUE(cx, -1, JSTYPE_NUMBER, rval); \
if (lval.isString() && rval.isString()) { \
JSString *l = lval.toString(), *r = rval.toString(); \
cond = js_CompareStrings(l, r) OP 0; \
int32 result; \
if (!CompareStrings(cx, l, r, &result)) \
goto error; \
cond = result OP 0; \
} else { \
double l, r; \
if (!ValueToNumber(cx, lval, &l) || \
@ -5094,12 +5116,14 @@ BEGIN_CASE(JSOP_LOOKUPSWITCH)
}
if (lval.isString()) {
JSString *str = lval.toString();
JSString *str2;
JSLinearString *str = lval.toString()->ensureLinear(cx);
if (!str)
goto error;
JSLinearString *str2;
SEARCH_PAIRS(
match = (rval.isString() &&
((str2 = rval.toString()) == str ||
js_EqualStrings(str2, str)));
((str2 = rval.toString()->assertIsLinear()) == str ||
EqualStrings(str2, str)));
)
} else if (lval.isNumber()) {
double ldbl = lval.toNumber();

View File

@ -1030,11 +1030,11 @@ CheckRedeclaration(JSContext *cx, JSObject *obj, jsid id, uintN attrs,
JSObject **objp, JSProperty **propp);
extern bool
StrictlyEqual(JSContext *cx, const Value &lval, const Value &rval);
StrictlyEqual(JSContext *cx, const Value &lval, const Value &rval, JSBool *equal);
/* === except that NaN is the same as NaN and -0 is not the same as +0. */
extern bool
SameValue(const Value &v1, const Value &v2, JSContext *cx);
SameValue(JSContext *cx, const Value &v1, const Value &v2, JSBool *same);
extern JSType
TypeOfValue(JSContext *cx, const Value &v);

View File

@ -315,7 +315,10 @@ num_parseFloat(JSContext *cx, uintN argc, Value *vp)
str = js_ValueToString(cx, vp[2]);
if (!str)
return JS_FALSE;
str->getCharsAndEnd(bp, end);
bp = str->getChars(cx);
if (!bp)
return JS_FALSE;
end = bp + str->length();
if (!js_strtod(cx, bp, end, &ep, &d))
return JS_FALSE;
if (ep == bp) {
@ -330,12 +333,15 @@ num_parseFloat(JSContext *cx, uintN argc, Value *vp)
static jsdouble FASTCALL
ParseFloat(JSContext* cx, JSString* str)
{
const jschar* bp;
const jschar* end;
const jschar* ep;
jsdouble d;
const jschar *bp = str->getChars(cx);
if (!bp) {
SetBuiltinError(cx);
return js_NaN;
}
const jschar *end = bp + str->length();
str->getCharsAndEnd(bp, end);
const jschar *ep;
double d;
if (!js_strtod(cx, bp, end, &ep, &d) || ep == bp)
return js_NaN;
return d;
@ -451,8 +457,10 @@ num_parseInt(JSContext *cx, uintN argc, Value *vp)
}
/* Steps 2-5, 9-14. */
const jschar *ws, *end;
inputString->getCharsAndEnd(ws, end);
const jschar *ws = inputString->getChars(cx);
if (!ws)
return false;
const jschar *end = ws + inputString->length();
jsdouble number;
if (!ParseIntStringHelper(cx, ws, end, radix, stripPrefix, &number))
@ -467,8 +475,12 @@ num_parseInt(JSContext *cx, uintN argc, Value *vp)
static jsdouble FASTCALL
ParseInt(JSContext* cx, JSString* str)
{
const jschar *start, *end;
str->getCharsAndEnd(start, end);
const jschar *start = str->getChars(cx);
if (!start) {
SetBuiltinError(cx);
return js_NaN;
}
const jschar *end = start + str->length();
jsdouble d;
if (!ParseIntStringHelper(cx, start, end, 0, true, &d)) {
@ -499,7 +511,7 @@ JS_DEFINE_TRCINFO_2(num_parseInt,
(1, (static, DOUBLE, ParseIntDouble, DOUBLE, 1, nanojit::ACCSET_NONE)))
JS_DEFINE_TRCINFO_1(num_parseFloat,
(2, (static, DOUBLE, ParseFloat, CONTEXT, STRING, 1, nanojit::ACCSET_NONE)))
(2, (static, DOUBLE_FAIL, ParseFloat, CONTEXT, STRING, 1, nanojit::ACCSET_NONE)))
#endif /* JS_TRACER */
@ -1184,6 +1196,14 @@ js_NumberToString(JSContext *cx, jsdouble d)
return js_NumberToStringWithBase(cx, d, 10);
}
JSFlatString *
js::NumberToString(JSContext *cx, jsdouble d)
{
if (JSString *str = js_NumberToStringWithBase(cx, d, 10))
return str->assertIsFlat();
return NULL;
}
JSBool JS_FASTCALL
js_NumberValueToCharBuffer(JSContext *cx, const Value &v, JSCharBuffer &cb)
{
@ -1232,13 +1252,8 @@ ValueToNumberSlow(JSContext *cx, Value v, double *out)
return true;
}
skip_int_double:
if (v.isString()) {
jsdouble d = StringToNumberType<jsdouble>(cx, v.toString());
if (JSDOUBLE_IS_NaN(d))
break;
*out = d;
return true;
}
if (v.isString())
return StringToNumberType<jsdouble>(cx, v.toString(), out);
if (v.isBoolean()) {
if (v.toBoolean()) {
*out = 1.0;

View File

@ -206,6 +206,10 @@ js_NumberValueToCharBuffer(JSContext *cx, const js::Value &v, JSCharBuffer &cb);
namespace js {
/* Same as js_NumberToString, different signature. */
extern JSFlatString *
NumberToString(JSContext *cx, jsdouble d);
/*
* Usually a small amount of static storage is enough, but sometimes we need
* to dynamically allocate much more. This struct encapsulates that.
@ -643,35 +647,44 @@ template<> struct NumberTraits<jsdouble> {
};
template<typename T>
static JS_ALWAYS_INLINE T
StringToNumberType(JSContext *cx, JSString *str)
static JS_ALWAYS_INLINE bool
StringToNumberType(JSContext *cx, JSString *str, T *result)
{
if (str->length() == 1) {
jschar c = str->chars()[0];
if ('0' <= c && c <= '9')
return NumberTraits<T>::toSelfType(T(c - '0'));
if (JS_ISSPACE(c))
return NumberTraits<T>::toSelfType(T(0));
return NumberTraits<T>::NaN();
size_t length = str->length();
const jschar *chars = str->getChars(NULL);
if (!chars)
return false;
if (length == 1) {
jschar c = chars[0];
if ('0' <= c && c <= '9') {
*result = NumberTraits<T>::toSelfType(T(c - '0'));
return true;
}
if (JS_ISSPACE(c)) {
*result = NumberTraits<T>::toSelfType(T(0));
return true;
}
*result = NumberTraits<T>::NaN();
return true;
}
const jschar* bp;
const jschar* end;
const jschar* ep;
jsdouble d;
str->getCharsAndEnd(bp, end);
const jschar *bp = chars;
const jschar *end = chars + length;
bp = js_SkipWhiteSpace(bp, end);
/* ECMA doesn't allow signed hex numbers (bug 273467). */
if (end - bp >= 2 && bp[0] == '0' && (bp[1] == 'x' || bp[1] == 'X')) {
/* Looks like a hex number. */
const jschar *endptr;
double d;
if (!GetPrefixInteger(cx, bp + 2, end, 16, &endptr, &d) ||
js_SkipWhiteSpace(endptr, end) != end) {
return NumberTraits<T>::NaN();
*result = NumberTraits<T>::NaN();
return true;
}
return NumberTraits<T>::toSelfType(d);
*result = NumberTraits<T>::toSelfType(d);
return true;
}
/*
@ -681,12 +694,14 @@ StringToNumberType(JSContext *cx, JSString *str)
* that have made it here (which can only be negative ones) will
* be treated as 0 without consuming the 'x' by js_strtod.
*/
if (!js_strtod(cx, bp, end, &ep, &d) ||
js_SkipWhiteSpace(ep, end) != end) {
return NumberTraits<T>::NaN();
const jschar *ep;
double d;
if (!js_strtod(cx, bp, end, &ep, &d) || js_SkipWhiteSpace(ep, end) != end) {
*result = NumberTraits<T>::NaN();
return true;
}
return NumberTraits<T>::toSelfType(d);
*result = NumberTraits<T>::toSelfType(d);
return true;
}
}

View File

@ -484,7 +484,8 @@ obj_toSource(JSContext *cx, uintN argc, Value *vp)
JSProperty *prop;
Value *val;
JSString *gsop[2];
JSString *idstr, *valstr, *str;
JSString *valstr, *str;
JSLinearString *idstr;
JS_CHECK_RECURSION(cx, return JS_FALSE);
@ -570,8 +571,8 @@ obj_toSource(JSContext *cx, uintN argc, Value *vp)
* Convert id to a value and then to a string. Decide early whether we
* prefer get/set or old getter/setter syntax.
*/
idstr = js_ValueToString(cx, IdToValue(id));
if (!idstr) {
JSString *s = js_ValueToString(cx, IdToValue(id));
if (!s || !(idstr = s->ensureLinear(cx))) {
ok = JS_FALSE;
goto error;
}
@ -609,18 +610,23 @@ obj_toSource(JSContext *cx, uintN argc, Value *vp)
* If id is a string that's not an identifier, or if it's a negative
* integer, then it must be quoted.
*/
bool idIsLexicalIdentifier = !!js_IsIdentifier(idstr);
bool idIsLexicalIdentifier = js_IsIdentifier(idstr);
if (JSID_IS_ATOM(id)
? !idIsLexicalIdentifier
: (!JSID_IS_INT(id) || JSID_TO_INT(id) < 0)) {
idstr = js_QuoteString(cx, idstr, jschar('\''));
if (!idstr) {
s = js_QuoteString(cx, idstr, jschar('\''));
if (!s || !(idstr = s->ensureLinear(cx))) {
ok = JS_FALSE;
goto error;
}
vp->setString(idstr); /* local root */
}
idstr->getCharsAndLength(idstrchars, idstrlength);
idstrlength = idstr->length();
idstrchars = idstr->getChars(cx);
if (!idstrchars) {
ok = JS_FALSE;
goto error;
}
for (jsint j = 0; j < valcnt; j++) {
/*
@ -637,7 +643,12 @@ obj_toSource(JSContext *cx, uintN argc, Value *vp)
goto error;
}
localroot[j].setString(valstr); /* local root */
valstr->getCharsAndLength(vchars, vlength);
vchars = valstr->getChars(cx);
if (!vchars) {
ok = JS_FALSE;
goto error;
}
vlength = valstr->length();
/*
* If val[j] is a non-sharp object, and we're not serializing an
@ -727,10 +738,8 @@ obj_toSource(JSContext *cx, uintN argc, Value *vp)
/* Allocate 1 + 1 at end for closing brace and terminating 0. */
chars = (jschar *) js_realloc((ochars = chars), curlen * sizeof(jschar));
if (!chars) {
/* Save code space on error: let JS_free ignore null vsharp. */
cx->free(vsharp);
js_free(ochars);
goto error;
chars = ochars;
goto overflow;
}
if (comma) {
@ -741,8 +750,10 @@ obj_toSource(JSContext *cx, uintN argc, Value *vp)
if (gsop[j]) {
gsoplength = gsop[j]->length();
js_strncpy(&chars[nchars], gsop[j]->chars(),
gsoplength);
const jschar *gsopchars = gsop[j]->getChars(cx);
if (!gsopchars)
goto overflow;
js_strncpy(&chars[nchars], gsopchars, gsoplength);
nchars += gsoplength;
chars[nchars++] = ' ';
}
@ -987,15 +998,14 @@ js_ComputeFilename(JSContext *cx, JSStackFrame *caller,
#endif
static inline JSScript **
EvalCacheHash(JSContext *cx, JSString *str)
EvalCacheHash(JSContext *cx, JSLinearString *str)
{
const jschar *s;
size_t n;
uint32 h;
const jschar *s = str->chars();
size_t n = str->length();
str->getCharsAndLength(s, n);
if (n > 100)
n = 100;
uint32 h;
for (h = 0; n; s++, n--)
h = JS_ROTATE_LEFT32(h, 4) ^ *s;
@ -1005,7 +1015,7 @@ EvalCacheHash(JSContext *cx, JSString *str)
}
static JS_ALWAYS_INLINE JSScript *
EvalCacheLookup(JSContext *cx, JSString *str, JSStackFrame *caller, uintN staticLevel,
EvalCacheLookup(JSContext *cx, JSLinearString *str, JSStackFrame *caller, uintN staticLevel,
JSPrincipals *principals, JSObject *scopeobj, JSScript **bucket)
{
/*
@ -1041,9 +1051,9 @@ EvalCacheLookup(JSContext *cx, JSString *str, JSStackFrame *caller, uintN static
* Get the source string passed for safekeeping in the
* atom map by the prior eval to Compiler::compileScript.
*/
JSString *src = ATOM_TO_STRING(script->atomMap.vector[0]);
JSAtom *src = script->atomMap.vector[0];
if (src == str || js_EqualStrings(src, str)) {
if (src == str || EqualStrings(src, str)) {
/*
* Source matches, qualify by comparing scopeobj to the
* COMPILE_N_GO-memoized parent of the first literal
@ -1184,9 +1194,11 @@ EvalKernel(JSContext *cx, uintN argc, Value *vp, EvalType evalType, JSStackFrame
if (!CheckScopeChainValidity(cx, scopeobj))
return false;
const jschar *chars;
size_t length;
str->getCharsAndLength(chars, length);
JSLinearString *linearStr = str->ensureLinear(cx);
if (!linearStr)
return false;
const jschar *chars = linearStr->chars();
size_t length = linearStr->length();
/*
* If the eval string starts with '(' and ends with ')', it may be JSON.
@ -1214,9 +1226,9 @@ EvalKernel(JSContext *cx, uintN argc, Value *vp, EvalType evalType, JSStackFrame
return false;
JSScript *script = NULL;
JSScript **bucket = EvalCacheHash(cx, str);
JSScript **bucket = EvalCacheHash(cx, linearStr);
if (evalType == DIRECT_EVAL && caller->isFunctionFrame())
script = EvalCacheLookup(cx, str, caller, staticLevel, principals, scopeobj, bucket);
script = EvalCacheLookup(cx, linearStr, caller, staticLevel, principals, scopeobj, bucket);
/*
* We can't have a callerFrame (down in js::Execute's terms) if we're in
@ -1229,9 +1241,8 @@ EvalKernel(JSContext *cx, uintN argc, Value *vp, EvalType evalType, JSStackFrame
uint32 tcflags = TCF_COMPILE_N_GO | TCF_NEED_MUTABLE_SCRIPT | TCF_COMPILE_FOR_EVAL;
script = Compiler::compileScript(cx, scopeobj, callerFrame,
principals, tcflags,
chars, length,
filename, lineno, str, staticLevel);
principals, tcflags, chars, length,
filename, lineno, linearStr, staticLevel);
if (!script)
return false;
}
@ -2040,14 +2051,20 @@ DefinePropertyOnObject(JSContext *cx, JSObject *obj, const PropDesc &desc,
if (!shape->isAccessorDescriptor())
break;
if (desc.hasGet &&
!SameValue(desc.getterValue(), shape->getterOrUndefined(), cx)) {
break;
if (desc.hasGet) {
JSBool same;
if (!SameValue(cx, desc.getterValue(), shape->getterOrUndefined(), &same))
return JS_FALSE;
if (!same)
break;
}
if (desc.hasSet &&
!SameValue(desc.setterValue(), shape->setterOrUndefined(), cx)) {
break;
if (desc.hasSet) {
JSBool same;
if (!SameValue(cx, desc.setterValue(), shape->setterOrUndefined(), &same))
return JS_FALSE;
if (!same)
break;
}
} else {
/*
@ -2096,8 +2113,13 @@ DefinePropertyOnObject(JSContext *cx, JSObject *obj, const PropDesc &desc,
if (!shape->isDataDescriptor())
break;
if (desc.hasValue && !SameValue(desc.value, v, cx))
break;
JSBool same;
if (desc.hasValue) {
if (!SameValue(cx, desc.value, v, &same))
return JS_FALSE;
if (!same)
break;
}
if (desc.hasWritable && desc.writable() != shape->writable())
break;
} else {
@ -2144,9 +2166,14 @@ DefinePropertyOnObject(JSContext *cx, JSObject *obj, const PropDesc &desc,
/* 8.12.9 step 10. */
JS_ASSERT(shape->isDataDescriptor());
if (!shape->configurable() && !shape->writable()) {
if ((desc.hasWritable && desc.writable()) ||
(desc.hasValue && !SameValue(desc.value, v, cx))) {
if (desc.hasWritable && desc.writable())
return Reject(cx, JSMSG_CANT_REDEFINE_PROP, throwError, desc.id, rval);
if (desc.hasValue) {
JSBool same;
if (!SameValue(cx, desc.value, v, &same))
return JS_FALSE;
if (!same)
return Reject(cx, JSMSG_CANT_REDEFINE_PROP, throwError, desc.id, rval);
}
}
@ -2155,11 +2182,20 @@ DefinePropertyOnObject(JSContext *cx, JSObject *obj, const PropDesc &desc,
/* 8.12.9 step 11. */
JS_ASSERT(desc.isAccessorDescriptor() && shape->isAccessorDescriptor());
if (!shape->configurable()) {
if ((desc.hasSet &&
!SameValue(desc.setterValue(), shape->setterOrUndefined(), cx)) ||
(desc.hasGet &&
!SameValue(desc.getterValue(), shape->getterOrUndefined(), cx))) {
return Reject(cx, JSMSG_CANT_REDEFINE_PROP, throwError, desc.id, rval);
if (desc.hasSet) {
JSBool same;
if (!SameValue(cx, desc.setterValue(), shape->setterOrUndefined(), &same))
return JS_FALSE;
if (!same)
return Reject(cx, JSMSG_CANT_REDEFINE_PROP, throwError, desc.id, rval);
}
if (desc.hasGet) {
JSBool same;
if (!SameValue(cx, desc.getterValue(), shape->getterOrUndefined(), &same))
return JS_FALSE;
if (!same)
return Reject(cx, JSMSG_CANT_REDEFINE_PROP, throwError, desc.id, rval);
}
}
}
@ -6312,7 +6348,7 @@ js_PrintObjectSlotName(JSTracer *trc, char *buf, size_t bufsize)
if (JSID_IS_INT(id)) {
JS_snprintf(buf, bufsize, "%ld", (long)JSID_TO_INT(id));
} else if (JSID_IS_ATOM(id)) {
PutEscapedString(buf, bufsize, JSID_TO_STRING(id), 0);
PutEscapedString(buf, bufsize, JSID_TO_ATOM(id), 0);
} else {
JS_snprintf(buf, bufsize, "**FINALIZED ATOM KEY**");
}
@ -6505,15 +6541,22 @@ js_DumpChars(const jschar *s, size_t n)
void
dumpString(JSString *str)
{
dumpChars(str->chars(), str->length());
if (const jschar *chars = str->getChars(NULL))
dumpChars(chars, str->length());
else
fprintf(stderr, "(oom in dumpString)");
}
JS_FRIEND_API(void)
js_DumpString(JSString *str)
{
fprintf(stderr, "JSString* (%p) = jschar * (%p) = ",
(void *) str, (void *) str->chars());
dumpString(str);
if (const jschar *chars = str->getChars(NULL)) {
fprintf(stderr, "JSString* (%p) = jschar * (%p) = ",
(void *) str, (void *) chars);
dumpString(str);
} else {
fprintf(stderr, "(oom in JS_DumpString)");
}
fputc('\n', stderr);
}

View File

@ -986,17 +986,21 @@ struct JSObject : js::gc::Cell {
static const uint32 NAMESPACE_CLASS_RESERVED_SLOTS = 3;
static const uint32 QNAME_CLASS_RESERVED_SLOTS = 3;
inline jsval getNamePrefix() const;
inline void setNamePrefix(jsval prefix);
inline JSLinearString *getNamePrefix() const;
inline jsval getNamePrefixVal() const;
inline void setNamePrefix(JSLinearString *prefix);
inline void clearNamePrefix();
inline jsval getNameURI() const;
inline void setNameURI(jsval uri);
inline JSLinearString *getNameURI() const;
inline jsval getNameURIVal() const;
inline void setNameURI(JSLinearString *uri);
inline jsval getNamespaceDeclared() const;
inline void setNamespaceDeclared(jsval decl);
inline jsval getQNameLocalName() const;
inline void setQNameLocalName(jsval decl);
inline JSLinearString *getQNameLocalName() const;
inline jsval getQNameLocalNameVal() const;
inline void setQNameLocalName(JSLinearString *name);
/*
* Proxy-specific getters and setters.

View File

@ -530,32 +530,55 @@ JSObject::setNativeIterator(js::NativeIterator *ni)
setPrivate(ni);
}
inline jsval
inline JSLinearString *
JSObject::getNamePrefix() const
{
JS_ASSERT(isNamespace() || isQName());
const js::Value &v = getSlot(JSSLOT_NAME_PREFIX);
return !v.isUndefined() ? v.toString()->assertIsLinear() : NULL;
}
inline jsval
JSObject::getNamePrefixVal() const
{
JS_ASSERT(isNamespace() || isQName());
return js::Jsvalify(getSlot(JSSLOT_NAME_PREFIX));
}
inline void
JSObject::setNamePrefix(jsval prefix)
JSObject::setNamePrefix(JSLinearString *prefix)
{
JS_ASSERT(isNamespace() || isQName());
setSlot(JSSLOT_NAME_PREFIX, js::Valueify(prefix));
setSlot(JSSLOT_NAME_PREFIX, prefix ? js::StringValue(prefix) : js::UndefinedValue());
}
inline void
JSObject::clearNamePrefix()
{
JS_ASSERT(isNamespace() || isQName());
setSlot(JSSLOT_NAME_PREFIX, js::UndefinedValue());
}
inline JSLinearString *
JSObject::getNameURI() const
{
JS_ASSERT(isNamespace() || isQName());
const js::Value &v = getSlot(JSSLOT_NAME_URI);
return !v.isUndefined() ? v.toString()->assertIsLinear() : NULL;
}
inline jsval
JSObject::getNameURI() const
JSObject::getNameURIVal() const
{
JS_ASSERT(isNamespace() || isQName());
return js::Jsvalify(getSlot(JSSLOT_NAME_URI));
}
inline void
JSObject::setNameURI(jsval uri)
JSObject::setNameURI(JSLinearString *uri)
{
JS_ASSERT(isNamespace() || isQName());
setSlot(JSSLOT_NAME_URI, js::Valueify(uri));
setSlot(JSSLOT_NAME_URI, uri ? js::StringValue(uri) : js::UndefinedValue());
}
inline jsval
@ -572,18 +595,26 @@ JSObject::setNamespaceDeclared(jsval decl)
setSlot(JSSLOT_NAMESPACE_DECLARED, js::Valueify(decl));
}
inline jsval
inline JSLinearString *
JSObject::getQNameLocalName() const
{
JS_ASSERT(isQName());
const js::Value &v = getSlot(JSSLOT_QNAME_LOCAL_NAME);
return !v.isUndefined() ? v.toString()->assertIsLinear() : NULL;
}
inline jsval
JSObject::getQNameLocalNameVal() const
{
JS_ASSERT(isQName());
return js::Jsvalify(getSlot(JSSLOT_QNAME_LOCAL_NAME));
}
inline void
JSObject::setQNameLocalName(jsval name)
JSObject::setQNameLocalName(JSLinearString *name)
{
JS_ASSERT(isQName());
setSlot(JSSLOT_QNAME_LOCAL_NAME, js::Valueify(name));
setSlot(JSSLOT_QNAME_LOCAL_NAME, name ? js::StringValue(name) : js::UndefinedValue());
}
inline JSObject *

View File

@ -119,12 +119,15 @@ js_json_parse(JSContext *cx, uintN argc, Value *vp)
if (!JS_ConvertArguments(cx, argc, Jsvalify(argv), "S / v", &s, reviver.addr()))
return JS_FALSE;
JSLinearString *linearStr = s->ensureLinear(cx);
if (!linearStr)
return JS_FALSE;
JSONParser *jp = js_BeginJSONParse(cx, vp);
JSBool ok = jp != NULL;
if (ok) {
const jschar *chars;
size_t length;
s->getCharsAndLength(chars, length);
const jschar *chars = linearStr->chars();
size_t length = linearStr->length();
ok = js_ConsumeJSONText(cx, jp, chars, length);
ok &= !!js_FinishJSONParse(cx, jp, reviver.value());
}
@ -403,9 +406,11 @@ JO(JSContext *cx, Value *vp, StringifyContext *scx)
if (!s)
return JS_FALSE;
const jschar *chars;
size_t length;
s->getCharsAndLength(chars, length);
size_t length = s->length();
const jschar *chars = s->getChars(cx);
if (!chars)
return JS_FALSE;
if (!write_string(cx, scx->cb, chars, length) ||
!scx->cb.append(':') ||
!(scx->gap.empty() || scx->cb.append(' ')) ||
@ -505,9 +510,11 @@ Str(JSContext *cx, jsid id, JSObject *holder, StringifyContext *scx, Value *vp,
}
if (vp->isString()) {
const jschar *chars;
size_t length;
vp->toString()->getCharsAndLength(chars, length);
JSString *str = vp->toString();
size_t length = str->length();
const jschar *chars = str->getChars(cx);
if (!chars)
return JS_FALSE;
return write_string(cx, scx->cb, chars, length);
}

View File

@ -655,19 +655,16 @@ SprintCString(Sprinter *sp, const char *s)
static ptrdiff_t
SprintString(Sprinter *sp, JSString *str)
{
const jschar *chars;
size_t length, size;
ptrdiff_t offset;
size_t length = str->length();
const jschar *chars = str->getChars(sp->context);
if (!chars)
return -1;
str->getCharsAndLength(chars, length);
if (length == 0)
return sp->offset;
size = js_GetDeflatedStringLength(sp->context, chars, length);
size_t size = js_GetDeflatedStringLength(sp->context, chars, length);
if (size == (size_t)-1 || !SprintEnsureBuffer(sp, size))
return -1;
offset = sp->offset;
ptrdiff_t offset = sp->offset;
sp->offset += size;
js_DeflateStringToBuffer(sp->context, chars, length, sp->base + offset,
&size);
@ -713,39 +710,36 @@ const char js_EscapeMap[] = {
static char *
QuoteString(Sprinter *sp, JSString *str, uint32 quote)
{
JSBool dontEscape, ok;
jschar qc, c;
ptrdiff_t off, len;
const jschar *s, *t, *z;
const char *e;
char *bp;
/* Sample off first for later return value pointer computation. */
dontEscape = (quote & DONT_ESCAPE) != 0;
qc = (jschar) quote;
off = sp->offset;
JSBool dontEscape = (quote & DONT_ESCAPE) != 0;
jschar qc = (jschar) quote;
ptrdiff_t off = sp->offset;
if (qc && Sprint(sp, "%c", (char)qc) < 0)
return NULL;
const jschar *s = str->getChars(sp->context);
if (!s)
return NULL;
const jschar *z = s + str->length();
/* Loop control variables: z points at end of string sentinel. */
str->getCharsAndEnd(s, z);
for (t = s; t < z; s = ++t) {
for (const jschar *t = s; t < z; s = ++t) {
/* Move t forward from s past un-quote-worthy characters. */
c = *t;
jschar c = *t;
while (JS_ISPRINT(c) && c != qc && c != '\\' && c != '\t' &&
!(c >> 8)) {
c = *++t;
if (t == z)
break;
}
len = t - s;
ptrdiff_t len = t - s;
/* Allocate space for s, including the '\0' at the end. */
if (!SprintEnsureBuffer(sp, len))
return NULL;
/* Advance sp->offset and copy s into sp's buffer. */
bp = sp->base + sp->offset;
char *bp = sp->base + sp->offset;
sp->offset += len;
while (--len >= 0)
*bp++ = (char) *s++;
@ -755,6 +749,8 @@ QuoteString(Sprinter *sp, JSString *str, uint32 quote)
break;
/* Use js_EscapeMap, \u, or \x only if necessary. */
bool ok;
const char *e;
if (!(c >> 8) && (e = strchr(js_EscapeMap, (int)c)) != NULL) {
ok = dontEscape
? Sprint(sp, "%c", (char)c) >= 0
@ -1580,7 +1576,6 @@ DecompileDestructuring(SprintStack *ss, jsbytecode *pc, jsbytecode *endpc)
const char *lval;
JSAtom *atom;
jssrcnote *sn;
JSString *str;
JSBool hole;
LOCAL_ASSERT(*pc == JSOP_DUP);
@ -1661,18 +1656,19 @@ DecompileDestructuring(SprintStack *ss, jsbytecode *pc, jsbytecode *endpc)
case JSOP_GETPROP:
LOAD_ATOM(0);
do_destructure_atom:
{
*OFF2STR(&ss->sprinter, head) = '{';
str = ATOM_TO_STRING(atom);
#if JS_HAS_DESTRUCTURING_SHORTHAND
nameoff = ss->sprinter.offset;
#endif
if (!QuoteString(&ss->sprinter, str,
js_IsIdentifier(str) ? 0 : (jschar)'\'')) {
if (!QuoteString(&ss->sprinter, atom,
js_IsIdentifier(atom) ? 0 : (jschar)'\'')) {
return NULL;
}
if (SprintPut(&ss->sprinter, ": ", 2) < 0)
return NULL;
break;
}
default:
LOCAL_ASSERT(0);
@ -5198,7 +5194,11 @@ js_DecompileValueGenerator(JSContext *cx, intN spindex, jsval v_in,
if (!fallback)
return NULL;
}
return js_DeflateString(cx, fallback->chars(), fallback->length());
size_t length = fallback->length();
const jschar *chars = fallback->getChars(cx);
if (!chars)
return NULL;
return js_DeflateString(cx, chars, length);
}
static char *

View File

@ -8003,11 +8003,9 @@ Parser::xmlElementOrList(JSBool allowList)
return NULL;
}
if (endAtom && startAtom && endAtom != startAtom) {
JSString *str = ATOM_TO_STRING(startAtom);
/* End vs. start tag name mismatch: point to the tag name. */
reportErrorNumber(pn2, JSREPORT_UC | JSREPORT_ERROR, JSMSG_XML_TAG_NAME_MISMATCH,
str->chars());
startAtom->chars());
return NULL;
}
@ -8676,15 +8674,12 @@ Parser::primaryExpr(TokenKind tt, JSBool afterDot)
#if JS_HAS_XML_SUPPORT
if (tokenStream.matchToken(TOK_DBLCOLON)) {
if (afterDot) {
JSString *str;
/*
* Here primaryExpr is called after . or .. followed by a name
* followed by ::. This is the only case where a keyword after
* . or .. is not treated as a property name.
*/
str = ATOM_TO_STRING(pn->pn_atom);
tt = js_CheckKeyword(str->chars(), str->length());
tt = js_CheckKeyword(pn->pn_atom->chars(), pn->pn_atom->length());
if (tt == TOK_FUNCTION) {
pn->pn_arity = PN_NULLARY;
pn->pn_type = TOK_FUNCTION;

View File

@ -480,13 +480,14 @@ Shape::dump(JSContext *cx, FILE *fp) const
if (JSID_IS_INT(id)) {
fprintf(fp, "[%ld]", (long) JSID_TO_INT(id));
} else {
JSString *str;
JSLinearString *str;
if (JSID_IS_ATOM(id)) {
str = JSID_TO_STRING(id);
str = JSID_TO_ATOM(id);
} else {
JS_ASSERT(JSID_IS_OBJECT(id));
str = js_ValueToString(cx, IdToValue(id));
JSString *s = js_ValueToString(cx, IdToValue(id));
fputs("object ", fp);
str = s ? s->ensureLinear(cx) : NULL;
}
if (!str)
fputs("<error>", fp);

View File

@ -92,6 +92,7 @@ typedef struct JSTreeContext JSTreeContext;
typedef struct JSTryNote JSTryNote;
/* Friend "Advanced API" typedefs. */
typedef struct JSLinearString JSLinearString;
typedef struct JSAtom JSAtom;
typedef struct JSAtomList JSAtomList;
typedef struct JSAtomListElement JSAtomListElement;

View File

@ -2829,7 +2829,12 @@ reflect_parse(JSContext *cx, uint32 argc, jsval *vp)
if (!str)
return JS_FALSE;
filename = js_DeflateString(cx, str->chars(), str->length());
size_t length = str->length();
const jschar *chars = str->getChars(cx);
if (!chars)
return JS_FALSE;
filename = js_DeflateString(cx, chars, length);
if (!filename)
return JS_FALSE;
filenamep.reset(filename);
@ -2844,10 +2849,10 @@ reflect_parse(JSContext *cx, uint32 argc, jsval *vp)
}
}
const jschar *chars;
size_t length;
src->getCharsAndLength(chars, length);
size_t length = src->length();
const jschar *chars = src->getChars(cx);
if (!chars)
return JS_FALSE;
Parser parser(cx);

View File

@ -243,9 +243,11 @@ RegExp::handlePCREError(JSContext *cx, int error)
bool
RegExp::parseFlags(JSContext *cx, JSString *flagStr, uint32 &flagsOut)
{
const jschar *s;
size_t n;
flagStr->getCharsAndLength(s, n);
size_t n = flagStr->length();
const jschar *s = flagStr->getChars(cx);
if (!s)
return false;
flagsOut = 0;
for (size_t i = 0; i < n; i++) {
#define HANDLE_FLAG(__name) \
@ -578,9 +580,12 @@ js_regexp_toString(JSContext *cx, JSObject *obj, Value *vp)
return true;
}
const jschar *source;
size_t length;
re->getSource()->getCharsAndLength(source, length);
JSLinearString *src = re->getSource();
size_t length = src->length();
const jschar *source = src->getChars(cx);
if (!source)
return false;
if (length == 0) {
source = empty_regexp_ucstr;
length = JS_ARRAY_LENGTH(empty_regexp_ucstr) - 1;
@ -632,9 +637,11 @@ regexp_toString(JSContext *cx, uintN argc, Value *vp)
static JSString *
EscapeNakedForwardSlashes(JSContext *cx, JSString *unescaped)
{
const jschar *oldChars;
size_t oldLen;
unescaped->getCharsAndLength(oldChars, oldLen);
size_t oldLen = unescaped->length();
const jschar *oldChars = unescaped->getChars(cx);
if (!oldChars)
return NULL;
js::Vector<jschar, 128> newChars(cx);
for (const jschar *it = oldChars; it < oldChars + oldLen; ++it) {
if (*it == '/' && (it == oldChars || it[-1] != '\\')) {

View File

@ -61,7 +61,7 @@ class RegExpStatics
typedef Vector<int, 20, SystemAllocPolicy> MatchPairs;
MatchPairs matchPairs;
/* The input that was used to produce matchPairs. */
JSString *matchPairsInput;
JSLinearString *matchPairsInput;
/* The input last set on the statics. */
JSString *pendingInput;
uintN flags;
@ -180,7 +180,7 @@ class RegExpStatics
/* Mutators. */
bool updateFromMatch(JSContext *cx, JSString *input, int *buf, size_t matchItemCount) {
bool updateFromMatch(JSContext *cx, JSLinearString *input, int *buf, size_t matchItemCount) {
aboutToWrite();
pendingInput = input;

View File

@ -76,7 +76,7 @@ regexp_statics_construct(JSContext *cx, JSObject *parent)
class RegExp
{
jsrefcount refCount;
JSString *source;
JSLinearString *source;
#if ENABLE_YARR_JIT
JSC::Yarr::RegexCodeBlock compiled;
#else
@ -85,9 +85,9 @@ class RegExp
unsigned parenCount;
uint32 flags;
RegExp(JSString *source, uint32 flags)
RegExp(JSLinearString *source, uint32 flags)
: refCount(1), source(source), compiled(), parenCount(0), flags(flags) {}
bool compileHelper(JSContext *cx, UString &pattern);
bool compileHelper(JSContext *cx, JSLinearString &pattern);
bool compile(JSContext *cx);
static const uint32 allFlags = JSREG_FOLD | JSREG_GLOB | JSREG_MULTILINE | JSREG_STICKY;
void handlePCREError(JSContext *cx, int error);
@ -154,7 +154,7 @@ class RegExp
void decref(JSContext *cx);
/* Accessors. */
JSString *getSource() const { return source; }
JSLinearString *getSource() const { return source; }
size_t getParenCount() const { return parenCount; }
bool ignoreCase() const { return flags & JSREG_FOLD; }
bool global() const { return flags & JSREG_GLOB; }
@ -274,7 +274,7 @@ RegExp::createResult(JSContext *cx, JSString *input, int *buf, size_t matchItemC
}
inline bool
RegExp::executeInternal(JSContext *cx, RegExpStatics *res, JSString *input,
RegExp::executeInternal(JSContext *cx, RegExpStatics *res, JSString *inputstr,
size_t *lastIndex, bool test, Value *rval)
{
#if !ENABLE_YARR_JIT
@ -299,8 +299,12 @@ RegExp::executeInternal(JSContext *cx, RegExpStatics *res, JSString *input,
for (int *it = buf; it != buf + matchItemCount; ++it)
*it = -1;
const jschar *chars = input->chars();
JSLinearString *input = inputstr->ensureLinear(cx);
if (!input)
return false;
size_t len = input->length();
const jschar *chars = input->chars();
/*
* inputOffset emulates sticky mode by matching from this offset into the char buf and
@ -360,11 +364,14 @@ RegExp::executeInternal(JSContext *cx, RegExpStatics *res, JSString *input,
inline RegExp *
RegExp::create(JSContext *cx, JSString *source, uint32 flags)
{
JSLinearString *flatSource = source->ensureLinear(cx);
if (!flatSource)
return NULL;
RegExp *self;
void *mem = cx->malloc(sizeof(*self));
if (!mem)
return NULL;
self = new (mem) RegExp(source, flags);
self = new (mem) RegExp(flatSource, flags);
if (!self->compile(cx)) {
cx->destroy<RegExp>(self);
return NULL;
@ -418,7 +425,7 @@ YarrJITIsBroken(JSContext *cx)
#endif /* ANDROID */
inline bool
RegExp::compileHelper(JSContext *cx, UString &pattern)
RegExp::compileHelper(JSContext *cx, JSLinearString &pattern)
{
#if ENABLE_YARR_JIT
bool fellBack = false;
@ -452,8 +459,13 @@ RegExp::compileHelper(JSContext *cx, UString &pattern)
inline bool
RegExp::compile(JSContext *cx)
{
/* Flatten source early for the rest of compilation. */
if (!source->ensureLinear(cx))
return false;
if (!sticky())
return compileHelper(cx, *source);
/*
* The sticky case we implement hackily by prepending a caret onto the front
* and relying on |::execute| to pseudo-slice the string when it sees a sticky regexp.
@ -465,10 +477,10 @@ RegExp::compile(JSContext *cx)
if (!cb.reserve(JS_ARRAY_LENGTH(prefix) + source->length() + JS_ARRAY_LENGTH(postfix)))
return false;
JS_ALWAYS_TRUE(cb.append(prefix, JS_ARRAY_LENGTH(prefix)));
JS_ALWAYS_TRUE(cb.append(source->chars(), source->length()));
JS_ALWAYS_TRUE(cb.append(source->flatChars(), source->length()));
JS_ALWAYS_TRUE(cb.append(postfix, JS_ARRAY_LENGTH(postfix)));
JSString *fakeySource = js_NewStringFromCharBuffer(cx, cb);
JSLinearString *fakeySource = js_NewStringFromCharBuffer(cx, cb);
if (!fakeySource)
return false;
return compileHelper(cx, *fakeySource);

View File

@ -147,19 +147,17 @@ js_CheckKeyword(const jschar *str, size_t length)
}
JSBool
js_IsIdentifier(JSString *str)
js_IsIdentifier(JSLinearString *str)
{
size_t length;
jschar c;
const jschar *chars, *end;
const jschar *chars = str->chars();
size_t length = str->length();
str->getCharsAndLength(chars, length);
if (length == 0)
return JS_FALSE;
c = *chars;
jschar c = *chars;
if (!JS_ISIDSTART(c))
return JS_FALSE;
end = chars + length;
const jschar *end = chars + length;
while (++chars != end) {
c = *chars;
if (!JS_ISIDENT(c))

View File

@ -537,7 +537,7 @@ typedef void (*JSMapKeywordFun)(const char *);
* check if str is a JS keyword.
*/
extern JSBool
js_IsIdentifier(JSString *str);
js_IsIdentifier(JSLinearString *str);
/*
* Steal one JSREPORT_* bit (see jsapi.h) to tell that arguments to the error

View File

@ -1453,8 +1453,8 @@ PrintPropertyGetterOrSetter(JSTracer *trc, char *buf, size_t bufsize)
name = trc->debugPrintIndex ? js_setter_str : js_getter_str;
if (JSID_IS_ATOM(id)) {
n = PutEscapedString(buf, bufsize - 1, JSID_TO_STRING(id), 0);
if (n < bufsize - 1)
n = PutEscapedString(buf, bufsize, JSID_TO_ATOM(id), 0);
if (n < bufsize)
JS_snprintf(buf + n, bufsize - n, " %s", name);
} else if (JSID_IS_INT(shape->id)) {
JS_snprintf(buf, bufsize, "%d %s", JSID_TO_INT(id), name);
@ -1476,8 +1476,8 @@ PrintPropertyMethod(JSTracer *trc, char *buf, size_t bufsize)
JS_ASSERT(!JSID_IS_VOID(id));
JS_ASSERT(JSID_IS_ATOM(id));
n = PutEscapedString(buf, bufsize - 1, JSID_TO_STRING(id), 0);
if (n < bufsize - 1)
n = PutEscapedString(buf, bufsize, JSID_TO_ATOM(id), 0);
if (n < bufsize)
JS_snprintf(buf + n, bufsize - n, " method");
}
#endif

File diff suppressed because it is too large Load Diff

View File

@ -83,6 +83,8 @@ namespace js { namespace mjit {
class Compiler;
}}
struct JSLinearString;
/*
* The GC-thing "string" type.
*
@ -110,6 +112,10 @@ namespace js { namespace mjit {
*
* When a string is a ROPE, it represents the lazy concatenation of other
* strings. In general, the nodes reachable from any rope form a dag.
*
* To allow static type-based checking that a given JSString* always points
* to a flat or non-rope string, the JSFlatString and JSLinearString types may
* be used. Instead of casting, callers should use ensureX() and assertIsX().
*/
struct JSString
{
@ -124,7 +130,7 @@ struct JSString
*/
size_t lengthAndFlags; /* in all strings */
union {
jschar *chars; /* in non-rope strings */
const jschar *chars; /* in non-rope strings */
JSString *left; /* in rope strings */
} u;
union {
@ -211,11 +217,6 @@ struct JSString
return lengthAndFlags & ROPE_BIT;
}
JS_ALWAYS_INLINE jschar *chars() {
ensureNotRope();
return u.chars;
}
JS_ALWAYS_INLINE size_t length() const {
return lengthAndFlags >> LENGTH_SHIFT;
}
@ -224,13 +225,18 @@ struct JSString
return lengthAndFlags <= TYPE_FLAGS_MASK;
}
JS_ALWAYS_INLINE void getCharsAndLength(const jschar *&chars, size_t &length) {
chars = this->chars();
length = this->length();
/* This can fail by returning null and reporting an error on cx. */
JS_ALWAYS_INLINE const jschar *getChars(JSContext *cx) {
if (isRope())
return flatten(cx);
return nonRopeChars();
}
JS_ALWAYS_INLINE void getCharsAndEnd(const jschar *&chars, const jschar *&end) {
end = length() + (chars = this->chars());
/* This can fail by returning null and reporting an error on cx. */
JS_ALWAYS_INLINE const jschar *getCharsZ(JSContext *cx) {
if (!isFlat())
return undepend(cx);
return flatChars();
}
JS_ALWAYS_INLINE void initFlatNotTerminated(jschar *chars, size_t length) {
@ -246,7 +252,7 @@ struct JSString
JS_ASSERT(chars[length] == jschar(0));
}
JS_ALWAYS_INLINE void initShortString(jschar *chars, size_t length) {
JS_ALWAYS_INLINE void initShortString(const jschar *chars, size_t length) {
JS_ASSERT(length <= MAX_LENGTH);
JS_ASSERT(chars >= inlineStorage && chars < (jschar *)(this + 2));
JS_ASSERT(!isStatic(this));
@ -263,7 +269,12 @@ struct JSString
s.capacity = cap;
}
JS_ALWAYS_INLINE jschar *flatChars() const {
JS_ALWAYS_INLINE JSFlatString *assertIsFlat() {
JS_ASSERT(isFlat());
return reinterpret_cast<JSFlatString *>(this);
}
JS_ALWAYS_INLINE const jschar *flatChars() const {
JS_ASSERT(isFlat());
return u.chars;
}
@ -293,22 +304,22 @@ struct JSString
* The chars pointer should point somewhere inside the buffer owned by base.
* The caller still needs to pass base for GC purposes.
*/
inline void initDependent(JSString *base, jschar *chars, size_t length) {
inline void initDependent(JSString *base, const jschar *chars, size_t length) {
JS_ASSERT(!isStatic(this));
JS_ASSERT(base->isFlat());
JS_ASSERT(chars >= base->chars() && chars < base->chars() + base->length());
JS_ASSERT(length <= base->length() - (chars - base->chars()));
JS_ASSERT(chars >= base->flatChars() && chars < base->flatChars() + base->length());
JS_ASSERT(length <= base->length() - (chars - base->flatChars()));
lengthAndFlags = buildLengthAndFlags(length, DEPENDENT);
u.chars = chars;
s.base = base;
}
inline JSString *dependentBase() const {
inline JSLinearString *dependentBase() const {
JS_ASSERT(isDependent());
return s.base;
return s.base->assertIsLinear();
}
JS_ALWAYS_INLINE jschar *dependentChars() {
JS_ALWAYS_INLINE const jschar *dependentChars() {
JS_ASSERT(isDependent());
return u.chars;
}
@ -320,16 +331,6 @@ struct JSString
const jschar *undepend(JSContext *cx);
const jschar *getCharsZ(JSContext *cx) {
if (!isFlat())
return undepend(cx);
return flatChars();
}
inline bool ensureNotDependent(JSContext *cx) {
return !isDependent() || undepend(cx);
}
const jschar *nonRopeChars() const {
JS_ASSERT(!isRope());
return u.chars;
@ -353,17 +354,27 @@ struct JSString
return s.right;
}
inline void finishTraversalConversion(JSString *base, jschar *baseBegin, jschar *end) {
inline void finishTraversalConversion(JSString *base, const jschar *baseBegin, const jschar *end) {
JS_ASSERT(baseBegin <= u.chars && u.chars <= end);
lengthAndFlags = buildLengthAndFlags(end - u.chars, DEPENDENT);
s.base = base;
}
void flatten();
const jschar *flatten(JSContext *maybecx);
void ensureNotRope() {
if (isRope())
flatten();
JSLinearString *ensureLinear(JSContext *cx) {
if (isRope() && !flatten(cx))
return NULL;
return reinterpret_cast<JSLinearString *>(this);
}
bool isLinear() const {
return !isRope();
}
JSLinearString *assertIsLinear() {
JS_ASSERT(isLinear());
return reinterpret_cast<JSLinearString *>(this);
}
typedef uint8 SmallChar;
@ -426,13 +437,13 @@ struct JSString
*/
static const JSString *const intStringTable[];
static JSString *unitString(jschar c);
static JSString *getUnitString(JSContext *cx, JSString *str, size_t index);
static JSString *length2String(jschar c1, jschar c2);
static JSString *length2String(uint32 i);
static JSString *intString(jsint i);
static JSFlatString *unitString(jschar c);
static JSLinearString *getUnitString(JSContext *cx, JSString *str, size_t index);
static JSFlatString *length2String(jschar c1, jschar c2);
static JSFlatString *length2String(uint32 i);
static JSFlatString *intString(jsint i);
static JSString *lookupStaticString(const jschar *chars, size_t length);
static JSFlatString *lookupStaticString(const jschar *chars, size_t length);
JS_ALWAYS_INLINE void finalize(JSContext *cx);
@ -450,12 +461,37 @@ struct JSString
}
};
struct JSFlatString : JSString
/*
* A "linear" string may or may not be null-terminated, but it provides
* infallible access to a linear array of characters. Namely, this means the
* string is not a rope.
*/
struct JSLinearString : JSString
{
const jschar *chars() const { return JSString::nonRopeChars(); }
};
JS_STATIC_ASSERT(sizeof(JSLinearString) == sizeof(JSString));
/*
* A linear string where, additionally, chars()[length()] == '\0'. Namely, this
* means the string is not a dependent string or rope.
*/
struct JSFlatString : JSLinearString
{
const jschar *charsZ() const { return chars(); }
};
JS_STATIC_ASSERT(sizeof(JSFlatString) == sizeof(JSString));
/*
* A flat string which has been "atomized", i.e., that is a unique string among
* other atomized strings and therefore allows equality via pointer comparison.
*/
struct JSAtom : JSFlatString
{
};
struct JSExternalString : JSString
{
static const uintN TYPE_LIMIT = 8;
@ -548,6 +584,7 @@ namespace js {
* Implemented in jsstrinlines.h.
*/
class StringSegmentRange;
class MutatingRopeSegmentRange;
/*
* Utility for building a rope (lazy concatenation) of strings.
@ -747,7 +784,7 @@ extern const char js_decodeURIComponent_str[];
extern const char js_encodeURIComponent_str[];
/* GC-allocate a string descriptor for the given malloc-allocated chars. */
extern JSString *
extern JSFlatString *
js_NewString(JSContext *cx, jschar *chars, size_t length);
/*
@ -755,25 +792,25 @@ js_NewString(JSContext *cx, jschar *chars, size_t length);
* This function takes responsibility for adding the terminating '\0' required
* by js_NewString.
*/
extern JSString *
extern JSFlatString *
js_NewStringFromCharBuffer(JSContext *cx, JSCharBuffer &cb);
extern JSString *
extern JSLinearString *
js_NewDependentString(JSContext *cx, JSString *base, size_t start,
size_t length);
/* Copy a counted string and GC-allocate a descriptor for it. */
extern JSString *
extern JSFlatString *
js_NewStringCopyN(JSContext *cx, const jschar *s, size_t n);
extern JSString *
extern JSFlatString *
js_NewStringCopyN(JSContext *cx, const char *s, size_t n);
/* Copy a C string and GC-allocate a descriptor for it. */
extern JSString *
extern JSFlatString *
js_NewStringCopyZ(JSContext *cx, const jschar *s);
extern JSString *
extern JSFlatString *
js_NewStringCopyZ(JSContext *cx, const char *s);
/*
@ -826,29 +863,42 @@ js_ValueToSource(JSContext *cx, const js::Value &v);
* Compute a hash function from str. The caller can call this function even if
* str is not a GC-allocated thing.
*/
extern uint32
js_HashString(JSString *str);
inline uint32
js_HashString(JSLinearString *str)
{
const jschar *s = str->chars();
size_t n = str->length();
uint32 h;
for (h = 0; n; s++, n--)
h = JS_ROTATE_LEFT32(h, 4) ^ *s;
return h;
}
namespace js {
/*
* Test if strings are equal. The caller can call the function even if str1
* or str2 are not GC-allocated things.
*/
extern JSBool JS_FASTCALL
js_EqualStrings(JSString *str1, JSString *str2);
extern bool
EqualStrings(JSContext *cx, JSString *str1, JSString *str2, JSBool *result);
/* EqualStrings is infallible on linear strings. */
extern bool
EqualStrings(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 int32 JS_FASTCALL
js_CompareStrings(JSString *str1, JSString *str2);
extern bool
CompareStrings(JSContext *cx, JSString *str1, JSString *str2, int32 *result);
namespace js {
/*
* Return true if the string matches the given sequence of ASCII bytes.
*/
extern JSBool
MatchStringAndAscii(JSString *str, const char *asciiBytes);
extern bool
StringEqualsAscii(JSLinearString *str, const char *asciiBytes);
} /* namespacejs */
@ -994,7 +1044,7 @@ js_OneUcs4ToUtf8Char(uint8 *utf8Buffer, uint32 ucs4Char);
namespace js {
extern size_t
PutEscapedStringImpl(char *buffer, size_t size, FILE *fp, JSString *str, uint32 quote);
PutEscapedStringImpl(char *buffer, size_t size, FILE *fp, JSLinearString *str, uint32 quote);
/*
* Write str into buffer escaping any non-printable or non-ASCII character
@ -1006,7 +1056,7 @@ PutEscapedStringImpl(char *buffer, size_t size, FILE *fp, JSString *str, uint32
* be a single or double quote character that will quote the output.
*/
inline size_t
PutEscapedString(char *buffer, size_t size, JSString *str, uint32 quote)
PutEscapedString(char *buffer, size_t size, JSLinearString *str, uint32 quote)
{
size_t n = PutEscapedStringImpl(buffer, size, NULL, str, quote);
@ -1021,7 +1071,7 @@ PutEscapedString(char *buffer, size_t size, JSString *str, uint32 quote)
* will quote the output.
*/
inline bool
FileEscapedString(FILE *fp, JSString *str, uint32 quote)
FileEscapedString(FILE *fp, JSLinearString *str, uint32 quote)
{
return PutEscapedStringImpl(NULL, 0, fp, str, quote) != size_t(-1);
}

View File

@ -42,49 +42,53 @@
#include "jsstr.h"
inline JSString *
inline JSFlatString *
JSString::unitString(jschar c)
{
JS_ASSERT(c < UNIT_STRING_LIMIT);
return const_cast<JSString *>(&unitStringTable[c]);
return const_cast<JSString *>(&unitStringTable[c])->assertIsFlat();
}
inline JSString *
inline JSLinearString *
JSString::getUnitString(JSContext *cx, JSString *str, size_t index)
{
JS_ASSERT(index < str->length());
jschar c = str->chars()[index];
const jschar *chars = str->getChars(cx);
if (!chars)
return NULL;
jschar c = chars[index];
if (c < UNIT_STRING_LIMIT)
return unitString(c);
return js_NewDependentString(cx, str, index, 1);
}
inline JSString *
inline JSFlatString *
JSString::length2String(jschar c1, jschar c2)
{
JS_ASSERT(fitsInSmallChar(c1));
JS_ASSERT(fitsInSmallChar(c2));
return const_cast<JSString *>
(&length2StringTable[(((size_t)toSmallChar[c1]) << 6) + toSmallChar[c2]]);
return const_cast<JSString *> (
&length2StringTable[(((size_t)toSmallChar[c1]) << 6) + toSmallChar[c2]]
)->assertIsFlat();
}
inline JSString *
inline JSFlatString *
JSString::length2String(uint32 i)
{
JS_ASSERT(i < 100);
return length2String('0' + i / 10, '0' + i % 10);
}
inline JSString *
inline JSFlatString *
JSString::intString(jsint i)
{
jsuint u = jsuint(i);
JS_ASSERT(u < INT_STRING_LIMIT);
return const_cast<JSString *>(JSString::intStringTable[u]);
return const_cast<JSString *>(JSString::intStringTable[u])->assertIsFlat();
}
/* Get a static atomized string for chars if possible. */
inline JSString *
inline JSFlatString *
JSString::lookupStaticString(const jschar *chars, size_t length)
{
if (length == 1) {
@ -125,14 +129,13 @@ JSString::finalize(JSContext *cx) {
JS_ASSERT(!JSString::isStatic(this));
JS_RUNTIME_UNMETER(cx->runtime, liveStrings);
if (isDependent()) {
JS_ASSERT(dependentBase());
JS_RUNTIME_UNMETER(cx->runtime, liveDependentStrings);
} else if (isFlat()) {
/*
* flatChars for stillborn string is null, but cx->free checks
* for a null pointer on its own.
*/
cx->free(flatChars());
cx->free(const_cast<jschar *>(flatChars()));
}
}
@ -153,7 +156,7 @@ JSExternalString::finalize(JSContext *cx)
JS_RUNTIME_UNMETER(cx->runtime, liveStrings);
/* A stillborn string has null chars. */
jschar *chars = flatChars();
jschar *chars = const_cast<jschar *>(flatChars());
if (!chars)
return;
JSStringFinalizeOp finalizer = str_finalizers[externalStringType];

View File

@ -437,14 +437,14 @@ jitstats_getProperty(JSContext *cx, JSObject *obj, jsid id, jsval *vp)
int index = -1;
if (JSID_IS_STRING(id)) {
JSString* str = JSID_TO_STRING(id);
if (MatchStringAndAscii(str, "HOTLOOP")) {
JSAtom* str = JSID_TO_ATOM(id);
if (StringEqualsAscii(str, "HOTLOOP")) {
*vp = INT_TO_JSVAL(HOTLOOP);
return JS_TRUE;
}
#ifdef JS_METHODJIT
if (MatchStringAndAscii(str, "profiler")) {
if (StringEqualsAscii(str, "profiler")) {
*vp = BOOLEAN_TO_JSVAL(cx->profilingEnabled);
return JS_TRUE;
}
@ -910,7 +910,11 @@ PrintOnTrace(char* format, uint32 argc, double *argv)
// protect against massive spew if u.s is a bad pointer.
if (length > 1 << 16)
length = 1 << 16;
jschar *chars = u.s->chars();
if (u.s->isRope()) {
fprintf(out, "<rope>");
break;
}
const jschar *chars = u.s->nonRopeChars();
for (unsigned i = 0; i < length; ++i) {
jschar co = chars[i];
if (co < 128)
@ -8429,8 +8433,13 @@ TraceRecorder::d2i(LIns* d, bool resultCanBeImpreciseIfFractional)
#endif
}
if (ci == &js_StringToNumber_ci) {
LIns* args[] = { d->callArgN(1), d->callArgN(0) };
return w.call(&js_StringToInt32_ci, args);
LIns* ok_ins = w.allocp(sizeof(JSBool));
LIns* args[] = { ok_ins, d->callArgN(1), d->callArgN(0) };
LIns* ret_ins = w.call(&js_StringToInt32_ci, args);
guard(false,
w.name(w.eqi0(w.ldiAlloc(ok_ins)), "guard(oom)"),
OOM_EXIT);
return ret_ins;
}
}
return resultCanBeImpreciseIfFractional
@ -8646,10 +8655,13 @@ TraceRecorder::switchop()
w.name(w.eqd(v_ins, w.immd(d)), "guard(switch on numeric)"),
BRANCH_EXIT);
} else if (v.isString()) {
LIns* args[] = { w.immpStrGC(v.toString()), v_ins };
guard(true,
w.name(w.eqi0(w.eqi0(w.call(&js_EqualStrings_ci, args))),
"guard(switch on string)"),
LIns* args[] = { w.immpStrGC(v.toString()), v_ins, cx_ins };
LIns* equal_rval = w.call(&js_EqualStringsOnTrace_ci, args);
guard(false,
w.name(w.eqiN(equal_rval, JS_NEITHER), "guard(oom)"),
OOM_EXIT);
guard(false,
w.name(w.eqi0(equal_rval), "guard(switch on string)"),
BRANCH_EXIT);
} else if (v.isBoolean()) {
guard(true,
@ -8711,8 +8723,12 @@ TraceRecorder::incHelper(const Value &v, LIns*& v_ins, LIns*& v_after, jsint inc
if (v.isBoolean()) {
v_ins = w.i2d(v_ins);
} else if (v.isString()) {
LIns* args[] = { v_ins, cx_ins };
LIns* ok_ins = w.allocp(sizeof(JSBool));
LIns* args[] = { ok_ins, v_ins, cx_ins };
v_ins = w.call(&js_StringToNumber_ci, args);
guard(false,
w.name(w.eqi0(w.ldiAlloc(ok_ins)), "guard(oom)"),
OOM_EXIT);
} else {
JS_ASSERT(v.isNumber());
}
@ -8804,14 +8820,18 @@ EvalCmp(LOpcode op, double l, double r)
}
static bool
EvalCmp(LOpcode op, JSString* l, JSString* r)
EvalCmp(JSContext *cx, LOpcode op, JSString* l, JSString* r, JSBool *ret)
{
if (op == LIR_eqd)
return !!js_EqualStrings(l, r);
return EvalCmp(op, js_CompareStrings(l, r), 0);
return EqualStrings(cx, l, r, ret);
JSBool cmp;
if (!CompareStrings(cx, l, r, &cmp))
return false;
*ret = EvalCmp(op, cmp, 0);
return true;
}
JS_REQUIRES_STACK void
JS_REQUIRES_STACK RecordingStatus
TraceRecorder::strictEquality(bool equal, bool cmpCase)
{
Value& r = stackval(-1);
@ -8819,16 +8839,21 @@ TraceRecorder::strictEquality(bool equal, bool cmpCase)
LIns* l_ins = get(&l);
LIns* r_ins = get(&r);
LIns* x;
bool cond;
JSBool cond;
JSValueType ltag = getPromotedType(l);
if (ltag != getPromotedType(r)) {
cond = !equal;
x = w.immi(cond);
} else if (ltag == JSVAL_TYPE_STRING) {
LIns* args[] = { r_ins, l_ins };
x = w.eqiN(w.call(&js_EqualStrings_ci, args), equal);
cond = !!js_EqualStrings(l.toString(), r.toString());
LIns* args[] = { r_ins, l_ins, cx_ins };
LIns* equal_ins = w.call(&js_EqualStringsOnTrace_ci, args);
guard(false,
w.name(w.eqiN(equal_ins, JS_NEITHER), "guard(oom)"),
OOM_EXIT);
x = w.eqiN(equal_ins, equal);
if (!EqualStrings(cx, l.toString(), r.toString(), &cond))
RETURN_ERROR("oom");
} else {
if (ltag == JSVAL_TYPE_DOUBLE)
x = w.eqd(l_ins, r_ins);
@ -8848,10 +8873,11 @@ TraceRecorder::strictEquality(bool equal, bool cmpCase)
/* Only guard if the same path may not always be taken. */
if (!x->isImmI())
guard(cond, x, BRANCH_EXIT);
return;
return RECORD_CONTINUE;
}
set(&l, x);
return RECORD_CONTINUE;
}
JS_REQUIRES_STACK AbortableRecordingStatus
@ -8871,8 +8897,8 @@ TraceRecorder::equalityHelper(Value& l, Value& r, LIns* l_ins, LIns* r_ins,
Value& rval)
{
LOpcode op = LIR_eqi;
bool cond;
LIns* args[] = { NULL, NULL };
JSBool cond;
LIns* args[] = { NULL, NULL, NULL };
/*
* The if chain below closely mirrors that found in 11.9.3, in general
@ -8913,11 +8939,16 @@ TraceRecorder::equalityHelper(Value& l, Value& r, LIns* l_ins, LIns* r_ins,
l_ins = w.getStringChar(l_ins, w.immpNonGC(0));
r_ins = w.getStringChar(r_ins, w.immpNonGC(0));
} else {
args[0] = r_ins, args[1] = l_ins;
l_ins = w.call(&js_EqualStrings_ci, args);
args[0] = r_ins, args[1] = l_ins, args[2] = cx_ins;
LIns *equal_ins = w.call(&js_EqualStringsOnTrace_ci, args);
guard(false,
w.name(w.eqiN(equal_ins, JS_NEITHER), "guard(oom)"),
OOM_EXIT);
l_ins = equal_ins;
r_ins = w.immi(1);
}
cond = !!js_EqualStrings(l.toString(), r.toString());
if (!EqualStrings(cx, l.toString(), r.toString(), &cond))
RETURN_ERROR_A("oom");
} else {
JS_ASSERT(l.isNumber() && r.isNumber());
cond = (l.toNumber() == r.toNumber());
@ -8930,14 +8961,30 @@ TraceRecorder::equalityHelper(Value& l, Value& r, LIns* l_ins, LIns* r_ins,
r_ins = w.immiUndefined();
cond = true;
} else if (l.isNumber() && r.isString()) {
args[0] = r_ins, args[1] = cx_ins;
LIns* ok_ins = w.allocp(sizeof(JSBool));
args[0] = ok_ins, args[1] = r_ins, args[2] = cx_ins;
r_ins = w.call(&js_StringToNumber_ci, args);
cond = (l.toNumber() == js_StringToNumber(cx, r.toString()));
guard(false,
w.name(w.eqi0(w.ldiAlloc(ok_ins)), "guard(oom)"),
OOM_EXIT);
JSBool ok;
double d = js_StringToNumber(cx, r.toString(), &ok);
if (!ok)
RETURN_ERROR_A("oom");
cond = (l.toNumber() == d);
op = LIR_eqd;
} else if (l.isString() && r.isNumber()) {
args[0] = l_ins, args[1] = cx_ins;
LIns* ok_ins = w.allocp(sizeof(JSBool));
args[0] = ok_ins, args[1] = l_ins, args[2] = cx_ins;
l_ins = w.call(&js_StringToNumber_ci, args);
cond = (js_StringToNumber(cx, l.toString()) == r.toNumber());
guard(false,
w.name(w.eqi0(w.ldiAlloc(ok_ins)), "guard(oom)"),
OOM_EXIT);
JSBool ok;
double d = js_StringToNumber(cx, l.toString(), &ok);
if (!ok)
RETURN_ERROR_A("oom");
cond = (d == r.toNumber());
op = LIR_eqd;
} else {
// Below we may assign to l or r, which modifies the interpreter state.
@ -9011,7 +9058,7 @@ TraceRecorder::relational(LOpcode op, bool tryBranchAfterCond)
Value& r = stackval(-1);
Value& l = stackval(-2);
LIns* x = NULL;
bool cond;
JSBool cond;
LIns* l_ins = get(&l);
LIns* r_ins = get(&r);
bool fp = false;
@ -9037,22 +9084,31 @@ TraceRecorder::relational(LOpcode op, bool tryBranchAfterCond)
/* 11.8.5 steps 3, 16-21. */
if (l.isString() && r.isString()) {
LIns* args[] = { r_ins, l_ins };
l_ins = w.call(&js_CompareStrings_ci, args);
LIns* args[] = { r_ins, l_ins, cx_ins };
LIns* result_ins = w.call(&js_CompareStringsOnTrace_ci, args);
guard(false,
w.name(w.eqiN(result_ins, INT32_MIN), "guard(oom)"),
OOM_EXIT);
l_ins = result_ins;
r_ins = w.immi(0);
cond = EvalCmp(op, l.toString(), r.toString());
if (!EvalCmp(cx, op, l.toString(), r.toString(), &cond))
RETURN_ERROR_A("oom");
goto do_comparison;
}
/* 11.8.5 steps 4-5. */
if (!l.isNumber()) {
LIns* args[] = { l_ins, cx_ins };
if (l.isBoolean()) {
l_ins = w.i2d(l_ins);
} else if (l.isUndefined()) {
l_ins = w.immd(js_NaN);
} else if (l.isString()) {
LIns* ok_ins = w.allocp(sizeof(JSBool));
LIns* args[] = { ok_ins, l_ins, cx_ins };
l_ins = w.call(&js_StringToNumber_ci, args);
guard(false,
w.name(w.eqi0(w.ldiAlloc(ok_ins)), "guard(oom)"),
OOM_EXIT);
} else if (l.isNull()) {
l_ins = w.immd(0.0);
} else {
@ -9062,13 +9118,17 @@ TraceRecorder::relational(LOpcode op, bool tryBranchAfterCond)
}
}
if (!r.isNumber()) {
LIns* args[] = { r_ins, cx_ins };
if (r.isBoolean()) {
r_ins = w.i2d(r_ins);
} else if (r.isUndefined()) {
r_ins = w.immd(js_NaN);
} else if (r.isString()) {
LIns* ok_ins = w.allocp(sizeof(JSBool));
LIns* args[] = { ok_ins, r_ins, cx_ins };
r_ins = w.call(&js_StringToNumber_ci, args);
guard(false,
w.name(w.eqi0(w.ldiAlloc(ok_ins)), "guard(oom)"),
OOM_EXIT);
} else if (r.isNull()) {
r_ins = w.immd(0.0);
} else {
@ -9176,16 +9236,30 @@ TraceRecorder::binary(LOpcode op)
if (l.isString()) {
NanoAssert(op != LIR_addd); // LIR_addd/IS_STRING case handled by record_JSOP_ADD()
LIns* args[] = { a, cx_ins };
LIns* ok_ins = w.allocp(sizeof(JSBool));
LIns* args[] = { ok_ins, a, cx_ins };
a = w.call(&js_StringToNumber_ci, args);
lnum = js_StringToNumber(cx, l.toString());
guard(false,
w.name(w.eqi0(w.ldiAlloc(ok_ins)), "guard(oom)"),
OOM_EXIT);
JSBool ok;
lnum = js_StringToNumber(cx, l.toString(), &ok);
if (!ok)
RETURN_ERROR("oom");
leftIsNumber = true;
}
if (r.isString()) {
NanoAssert(op != LIR_addd); // LIR_addd/IS_STRING case handled by record_JSOP_ADD()
LIns* args[] = { b, cx_ins };
LIns* ok_ins = w.allocp(sizeof(JSBool));
LIns* args[] = { ok_ins, b, cx_ins };
b = w.call(&js_StringToNumber_ci, args);
rnum = js_StringToNumber(cx, r.toString());
guard(false,
w.name(w.eqi0(w.ldiAlloc(ok_ins)), "guard(oom)"),
OOM_EXIT);
JSBool ok;
rnum = js_StringToNumber(cx, r.toString(), &ok);
if (!ok)
RETURN_ERROR("oom");
rightIsNumber = true;
}
if (l.isBoolean()) {
@ -10706,8 +10780,13 @@ TraceRecorder::record_JSOP_NEG()
}
if (v.isString()) {
LIns* args[] = { get(&v), cx_ins };
set(&v, w.negd(w.call(&js_StringToNumber_ci, args)));
LIns* ok_ins = w.allocp(sizeof(JSBool));
LIns* args[] = { ok_ins, get(&v), cx_ins };
LIns* num_ins = w.call(&js_StringToNumber_ci, args);
guard(false,
w.name(w.eqi0(w.ldiAlloc(ok_ins)), "guard(oom)"),
OOM_EXIT);
set(&v, w.negd(num_ins));
return ARECORD_CONTINUE;
}
@ -10739,8 +10818,13 @@ TraceRecorder::record_JSOP_POS()
}
if (v.isString()) {
LIns* args[] = { get(&v), cx_ins };
set(&v, w.call(&js_StringToNumber_ci, args));
LIns* ok_ins = w.allocp(sizeof(JSBool));
LIns* args[] = { ok_ins, get(&v), cx_ins };
LIns* num_ins = w.call(&js_StringToNumber_ci, args);
guard(false,
w.name(w.eqi0(w.ldiAlloc(ok_ins)), "guard(oom)"),
OOM_EXIT);
set(&v, num_ins);
return ARECORD_CONTINUE;
}
@ -12425,7 +12509,9 @@ TraceRecorder::getCharCodeAt(JSString *str, LIns* str_ins, LIns* idx_ins, LIns**
LIns *lengthAndFlags_ins = w.ldpStringLengthAndFlags(str_ins);
if (MaybeBranch mbr = w.jt(w.eqp0(w.andp(lengthAndFlags_ins, w.nameImmw(JSString::ROPE_BIT)))))
{
w.call(&js_Flatten_ci, &str_ins);
LIns *args[] = { str_ins, cx_ins };
LIns *ok_ins = w.call(&js_Flatten_ci, args);
guard(false, w.eqi0(ok_ins), OOM_EXIT);
w.label(mbr);
}
@ -12457,7 +12543,9 @@ TraceRecorder::getCharAt(JSString *str, LIns* str_ins, LIns* idx_ins, JSOp mode,
if (MaybeBranch mbr = w.jt(w.eqp0(w.andp(lengthAndFlags_ins,
w.nameImmw(JSString::ROPE_BIT)))))
{
w.call(&js_Flatten_ci, &str_ins);
LIns *args[] = { str_ins, cx_ins };
LIns *ok_ins = w.call(&js_Flatten_ci, args);
guard(false, w.eqi0(ok_ins), OOM_EXIT);
w.label(mbr);
}
@ -12827,8 +12915,12 @@ TraceRecorder::setElem(int lval_spindex, int idx_spindex, int v_spindex)
} else if (v.isUndefined()) {
typed_v_ins = w.immd(js_NaN);
} else if (v.isString()) {
LIns* args[] = { typed_v_ins, cx_ins };
LIns* ok_ins = w.allocp(sizeof(JSBool));
LIns* args[] = { ok_ins, typed_v_ins, cx_ins };
typed_v_ins = w.call(&js_StringToNumber_ci, args);
guard(false,
w.name(w.eqi0(w.ldiAlloc(ok_ins)), "guard(oom)"),
OOM_EXIT);
} else if (v.isBoolean()) {
JS_ASSERT(v.isBoolean());
typed_v_ins = w.i2d(typed_v_ins);
@ -14025,14 +14117,14 @@ TraceRecorder::record_JSOP_LOOKUPSWITCH()
JS_REQUIRES_STACK AbortableRecordingStatus
TraceRecorder::record_JSOP_STRICTEQ()
{
strictEquality(true, false);
CHECK_STATUS_A(strictEquality(true, false));
return ARECORD_CONTINUE;
}
JS_REQUIRES_STACK AbortableRecordingStatus
TraceRecorder::record_JSOP_STRICTNE()
{
strictEquality(false, false);
CHECK_STATUS_A(strictEquality(false, false));
return ARECORD_CONTINUE;
}
@ -14937,7 +15029,7 @@ TraceRecorder::record_JSOP_CONDSWITCH()
JS_REQUIRES_STACK AbortableRecordingStatus
TraceRecorder::record_JSOP_CASE()
{
strictEquality(true, true);
CHECK_STATUS_A(strictEquality(true, true));
return ARECORD_CONTINUE;
}
@ -15315,7 +15407,7 @@ TraceRecorder::record_JSOP_GOSUBX()
JS_REQUIRES_STACK AbortableRecordingStatus
TraceRecorder::record_JSOP_CASEX()
{
strictEquality(true, true);
CHECK_STATUS_A(strictEquality(true, true));
return ARECORD_CONTINUE;
}

View File

@ -1300,7 +1300,7 @@ class TraceRecorder
JS_REQUIRES_STACK RecordingStatus incElem(jsint incr, bool pre = true);
JS_REQUIRES_STACK AbortableRecordingStatus incName(jsint incr, bool pre = true);
JS_REQUIRES_STACK void strictEquality(bool equal, bool cmpCase);
JS_REQUIRES_STACK RecordingStatus strictEquality(bool equal, bool cmpCase);
JS_REQUIRES_STACK AbortableRecordingStatus equality(bool negate, bool tryBranchAfterCond);
JS_REQUIRES_STACK AbortableRecordingStatus equalityHelper(Value& l, Value& r,
nanojit::LIns* l_ins, nanojit::LIns* r_ins,

View File

@ -357,10 +357,11 @@ PodArrayZero(T (&t)[N])
template <class T>
JS_ALWAYS_INLINE static void
PodCopy(T *dst, T *src, size_t nelem)
PodCopy(T *dst, const T *src, size_t nelem)
{
JS_ASSERT(abs(dst - src) >= ptrdiff_t(nelem));
if (nelem < 128) {
for (T *srcend = src + nelem; src != srcend; ++src, ++dst)
for (const T *srcend = src + nelem; src != srcend; ++src, ++dst)
*dst = *src;
} else {
memcpy(dst, src, nelem * sizeof(T));

View File

@ -352,7 +352,7 @@ typedef union jsval_layout
static JS_ALWAYS_INLINE JSBool
JSVAL_IS_DOUBLE_IMPL(jsval_layout l)
{
return (uint32)l.s.tag < (uint32)JSVAL_TAG_CLEAR;
return (uint32)l.s.tag <= (uint32)JSVAL_TAG_CLEAR;
}
static JS_ALWAYS_INLINE jsval_layout

View File

@ -265,6 +265,10 @@ class Vector : AllocPolicy
/* accessors */
const AllocPolicy &allocPolicy() const {
return *this;
}
enum { InlineLength = N };
size_t length() const {

View File

@ -456,13 +456,12 @@ JS_XDRString(JSXDRState *xdr, JSString **strp)
if (!JS_XDRUint32(xdr, &nchars))
return JS_FALSE;
if (xdr->mode == JSXDR_DECODE) {
if (xdr->mode == JSXDR_DECODE)
chars = (jschar *) xdr->cx->malloc((nchars + 1) * sizeof(jschar));
if (!chars)
return JS_FALSE;
} else {
chars = (*strp)->chars();
}
else
chars = const_cast<jschar *>((*strp)->getChars(xdr->cx));
if (!chars)
return JS_FALSE;
if (!XDRChars(xdr, chars, nchars))
goto bad;

File diff suppressed because it is too large Load Diff

View File

@ -312,7 +312,7 @@ js_IsXMLName(JSContext *cx, jsval v);
extern JSBool
js_ToAttributeName(JSContext *cx, js::Value *vp);
extern JSString *
extern JSLinearString *
js_EscapeAttributeValue(JSContext *cx, JSString *str, JSBool quote);
extern JSString *

View File

@ -2830,7 +2830,8 @@ mjit::Compiler::compareTwoValues(JSContext *cx, JSOp op, const Value &lhs, const
JS_ASSERT(rhs.isPrimitive());
if (lhs.isString() && rhs.isString()) {
int cmp = js_CompareStrings(lhs.toString(), rhs.toString());
int32 cmp;
CompareStrings(cx, lhs.toString(), rhs.toString(), &cmp);
switch (op) {
case JSOP_LT:
return cmp < 0;

View File

@ -1562,7 +1562,8 @@ mjit::Compiler::jsop_stricteq(JSOp op)
/* Constant-fold. */
if (lhs->isConstant() && rhs->isConstant()) {
bool b = StrictlyEqual(cx, lhs->getValue(), rhs->getValue());
JSBool b;
StrictlyEqual(cx, lhs->getValue(), rhs->getValue(), &b);
frame.popn(2);
frame.push(BooleanValue((op == JSOP_STRICTEQ) ? b : !b));
return;

View File

@ -2136,7 +2136,7 @@ GetElementIC::attachGetProp(JSContext *cx, JSObject *obj, const Value &v, jsid i
CodeLocationLabel cs = buffer.finalize();
#if DEBUG
char *chars = js_DeflateString(cx, v.toString()->chars(), v.toString()->length());
char *chars = js_DeflateString(cx, v.toString()->nonRopeChars(), v.toString()->length());
JaegerSpew(JSpew_PICs, "generated %s stub at %p for atom 0x%x (\"%s\") shape 0x%x (%s: %d)\n",
js_CodeName[op], cs.executableAddress(), id, chars, holder->shape(),
cx->fp()->script()->filename, js_FramePCToLineNumber(cx, cx->fp()));

View File

@ -940,7 +940,10 @@ template void JS_FASTCALL stubs::DefFun<false>(VMFrame &f, JSFunction *fun);
DEFAULT_VALUE(cx, -1, JSTYPE_NUMBER, rval); \
if (lval.isString() && rval.isString()) { \
JSString *l = lval.toString(), *r = rval.toString(); \
cond = js_CompareStrings(l, r) OP 0; \
JSBool cmp; \
if (!CompareStrings(cx, l, r, &cmp)) \
THROWV(JS_FALSE); \
cond = cmp OP 0; \
} else { \
double l, r; \
if (!ValueToNumber(cx, lval, &l) || \
@ -1006,7 +1009,10 @@ StubEqualityOp(VMFrame &f)
if (lval.isString() && rval.isString()) {
JSString *l = lval.toString();
JSString *r = rval.toString();
cond = js_EqualStrings(l, r) == EQ;
JSBool equal;
if (!EqualStrings(cx, l, r, &equal))
return false;
cond = equal == EQ;
} else
#if JS_HAS_XML_SUPPORT
if ((lval.isObject() && lval.toObject().isXML()) ||
@ -1066,7 +1072,10 @@ StubEqualityOp(VMFrame &f)
if (lval.isString() && rval.isString()) {
JSString *l = lval.toString();
JSString *r = rval.toString();
cond = js_EqualStrings(l, r) == EQ;
JSBool equal;
if (!EqualStrings(cx, l, r, &equal))
return false;
cond = equal == EQ;
} else {
double l, r;
if (!ValueToNumber(cx, lval, &l) ||
@ -2302,9 +2311,11 @@ stubs::StrictEq(VMFrame &f)
{
const Value &rhs = f.regs.sp[-1];
const Value &lhs = f.regs.sp[-2];
const bool b = StrictlyEqual(f.cx, lhs, rhs) == true;
JSBool equal;
if (!StrictlyEqual(f.cx, lhs, rhs, &equal))
THROW();
f.regs.sp--;
f.regs.sp[-1].setBoolean(b);
f.regs.sp[-1].setBoolean(equal == true);
}
void JS_FASTCALL
@ -2312,9 +2323,11 @@ stubs::StrictNe(VMFrame &f)
{
const Value &rhs = f.regs.sp[-1];
const Value &lhs = f.regs.sp[-2];
const bool b = StrictlyEqual(f.cx, lhs, rhs) != true;
JSBool equal;
if (!StrictlyEqual(f.cx, lhs, rhs, &equal))
THROW();
f.regs.sp--;
f.regs.sp[-1].setBoolean(b);
f.regs.sp[-1].setBoolean(equal != true);
}
void JS_FASTCALL
@ -2487,13 +2500,15 @@ stubs::LookupSwitch(VMFrame &f, jsbytecode *pc)
JS_ASSERT(npairs);
if (lval.isString()) {
JSString *str = lval.toString();
JSLinearString *str = lval.toString()->ensureLinear(f.cx);
if (!str)
THROWV(NULL);
for (uint32 i = 1; i <= npairs; i++) {
Value rval = script->getConst(GET_INDEX(pc));
pc += INDEX_LEN;
if (rval.isString()) {
JSString *rhs = rval.toString();
if (rhs == str || js_EqualStrings(str, rhs)) {
JSLinearString *rhs = rval.toString()->assertIsLinear();
if (rhs == str || EqualStrings(str, rhs)) {
void* native = script->nativeCodeForPC(ctor,
jpc + GET_JUMP_OFFSET(pc));
JS_ASSERT(native);

View File

@ -3402,7 +3402,12 @@ EvalInFrame(JSContext *cx, uintN argc, jsval *vp)
if (saveCurrent)
oldfp = JS_SaveFrameChain(cx);
JSBool ok = JS_EvaluateUCInStackFrame(cx, fp, str->chars(), str->length(),
size_t length;
const jschar *chars = JS_GetStringCharsAndLength(cx, str, &length);
if (!chars)
return JS_FALSE;
JSBool ok = JS_EvaluateUCInStackFrame(cx, fp, chars, length,
fp->script()->filename,
JS_PCToLineNumber(cx, fp->script(),
fi.pc()),

View File

@ -50,7 +50,7 @@
#include "jstl.h"
typedef jschar UChar;
typedef JSString UString;
typedef JSLinearString UString;
template <typename T>
class ValueDeleter