Bug 892634 - Part 1: Add thread safe number conversion functions. (r=billm)

This commit is contained in:
Shu-yu Guo 2013-08-02 08:24:57 -07:00
parent 2e435e83b4
commit 811fd3643c
6 changed files with 143 additions and 105 deletions

View File

@ -4038,7 +4038,7 @@ CodeGenerator::visitEmulatesUndefinedAndBranch(LEmulatesUndefinedAndBranch *lir)
return true;
}
typedef JSString *(*ConcatStringsFn)(JSContext *, HandleString, HandleString);
typedef JSString *(*ConcatStringsFn)(ThreadSafeContext *, HandleString, HandleString);
typedef ParallelResult (*ConcatStringsParFn)(ForkJoinSlice *, HandleString, HandleString,
MutableHandleString);
static const VMFunctionsModal ConcatStringsInfo = VMFunctionsModal(

View File

@ -191,7 +191,7 @@ ParallelResult
ion::ConcatStringsPar(ForkJoinSlice *slice, HandleString left, HandleString right,
MutableHandleString out)
{
JSString *str = ConcatStringsPure(slice, left, right);
JSString *str = ConcatStrings<NoGC>(slice, left, right);
if (!str)
return TP_RETRY_SEQUENTIALLY;
out.set(str);

View File

@ -54,7 +54,7 @@ using mozilla::RangedPtr;
* Call js_strtod_harder to get the correct answer.
*/
static bool
ComputeAccurateDecimalInteger(ExclusiveContext *cx,
ComputeAccurateDecimalInteger(ThreadSafeContext *cx,
const jschar *start, const jschar *end, double *dp)
{
size_t length = end - start;
@ -188,7 +188,7 @@ js::ParseDecimalNumber(const JS::TwoByteChars chars)
}
bool
js::GetPrefixInteger(ExclusiveContext *cx, const jschar *start, const jschar *end, int base,
js::GetPrefixInteger(ThreadSafeContext *cx, const jschar *start, const jschar *end, int base,
const jschar **endp, double *dp)
{
JS_ASSERT(start <= end);
@ -1390,26 +1390,18 @@ js::NumberValueToStringBuffer(JSContext *cx, const Value &v, StringBuffer &sb)
return sb.appendInflated(cstr, cstrlen);
}
bool
js::StringToNumber(ExclusiveContext *cx, JSString *str, double *result)
static void
CharsToNumber(ThreadSafeContext *cx, const jschar *chars, size_t length, double *result)
{
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') {
if ('0' <= c && c <= '9')
*result = c - '0';
return true;
}
if (unicode::IsSpace(c)) {
else if (unicode::IsSpace(c))
*result = 0.0;
return true;
}
else
*result = js_NaN;
return true;
return;
}
const jschar *end = chars + length;
@ -1429,10 +1421,10 @@ js::StringToNumber(ExclusiveContext *cx, JSString *str, double *result)
SkipSpace(endptr, end) != end)
{
*result = js_NaN;
return true;
}
} else {
*result = d;
return true;
}
return;
}
/*
@ -1444,11 +1436,41 @@ js::StringToNumber(ExclusiveContext *cx, JSString *str, double *result)
*/
const jschar *ep;
double d;
if (!js_strtod(cx, bp, end, &ep, &d) || SkipSpace(ep, end) != end) {
if (!js_strtod(cx, bp, end, &ep, &d) || SkipSpace(ep, end) != end)
*result = js_NaN;
else
*result = d;
}
bool
js::StringToNumber(ThreadSafeContext *cx, JSString *str, double *result)
{
ScopedThreadSafeStringInspector inspector(str);
if (!inspector.ensureChars(cx))
return false;
CharsToNumber(cx, inspector.chars(), str->length(), result);
return true;
}
bool
js::NonObjectToNumberSlow(ThreadSafeContext *cx, Value v, double *out)
{
JS_ASSERT(!v.isNumber());
JS_ASSERT(!v.isObject());
if (v.isString())
return StringToNumber(cx, v.toString(), out);
if (v.isBoolean()) {
*out = v.toBoolean() ? 1.0 : 0.0;
return true;
}
*result = d;
if (v.isNull()) {
*out = 0.0;
return true;
}
JS_ASSERT(v.isUndefined());
*out = js_NaN;
return true;
}
@ -1485,25 +1507,11 @@ js::ToNumberSlow(ExclusiveContext *cx, Value v, double *out)
*out = v.toNumber();
return true;
}
skip_int_double:
if (v.isString())
return StringToNumber(cx, v.toString(), out);
if (v.isBoolean()) {
if (v.toBoolean()) {
*out = 1.0;
return true;
}
*out = 0.0;
return true;
}
if (v.isNull()) {
*out = 0.0;
return true;
}
if (v.isUndefined())
break;
JS_ASSERT(v.isObject());
skip_int_double:
if (!v.isObject())
return NonObjectToNumberSlow(cx, v, out);
if (!cx->isJSContext())
return false;
@ -1567,15 +1575,18 @@ js::ToUint64Slow(JSContext *cx, const HandleValue v, uint64_t *out)
return true;
}
JS_PUBLIC_API(bool)
js::ToInt32Slow(JSContext *cx, const HandleValue v, int32_t *out)
template <typename ContextType,
bool (*ToNumberSlowFn)(ContextType *, Value, double *),
typename ValueType>
static bool
ToInt32SlowImpl(ContextType *cx, const ValueType v, int32_t *out)
{
JS_ASSERT(!v.isInt32());
double d;
if (v.isDouble()) {
d = v.toDouble();
} else {
if (!ToNumberSlow(cx, v, &d))
if (!ToNumberSlowFn(cx, v, &d))
return false;
}
*out = ToInt32(d);
@ -1583,20 +1594,47 @@ js::ToInt32Slow(JSContext *cx, const HandleValue v, int32_t *out)
}
JS_PUBLIC_API(bool)
js::ToUint32Slow(JSContext *cx, const HandleValue v, uint32_t *out)
js::ToInt32Slow(JSContext *cx, const HandleValue v, int32_t *out)
{
return ToInt32SlowImpl<JSContext, ToNumberSlow>(cx, v, out);
}
bool
js::NonObjectToInt32Slow(ThreadSafeContext *cx, const Value &v, int32_t *out)
{
return ToInt32SlowImpl<ThreadSafeContext, NonObjectToNumberSlow>(cx, v, out);
}
template <typename ContextType,
bool (*ToNumberSlowFn)(ContextType *, Value, double *),
typename ValueType>
static bool
ToUint32SlowImpl(ContextType *cx, const ValueType v, uint32_t *out)
{
JS_ASSERT(!v.isInt32());
double d;
if (v.isDouble()) {
d = v.toDouble();
} else {
if (!ToNumberSlow(cx, v, &d))
if (!ToNumberSlowFn(cx, v, &d))
return false;
}
*out = ToUint32(d);
return true;
}
JS_PUBLIC_API(bool)
js::ToUint32Slow(JSContext *cx, const HandleValue v, uint32_t *out)
{
return ToUint32SlowImpl<JSContext, ToNumberSlow>(cx, v, out);
}
bool
js::NonObjectToUint32Slow(ThreadSafeContext *cx, const Value &v, uint32_t *out)
{
return ToUint32SlowImpl<ThreadSafeContext, NonObjectToNumberSlow>(cx, v, out);
}
JS_PUBLIC_API(bool)
js::ToUint16Slow(JSContext *cx, const HandleValue v, uint16_t *out)
{
@ -1631,7 +1669,7 @@ js::ToUint16Slow(JSContext *cx, const HandleValue v, uint16_t *out)
}
JSBool
js_strtod(ExclusiveContext *cx, const jschar *s, const jschar *send,
js_strtod(ThreadSafeContext *cx, const jschar *s, const jschar *send,
const jschar **ep, double *dp)
{
size_t i;

View File

@ -128,7 +128,7 @@ ParseDecimalNumber(const JS::TwoByteChars chars);
* *dp == 0 and *endp == start upon return.
*/
extern bool
GetPrefixInteger(ExclusiveContext *cx, const jschar *start, const jschar *end, int base,
GetPrefixInteger(ThreadSafeContext *cx, const jschar *start, const jschar *end, int base,
const jschar **endp, double *dp);
/*
@ -140,7 +140,7 @@ extern bool
GetDecimalInteger(ExclusiveContext *cx, const jschar *start, const jschar *end, double *dp);
extern bool
StringToNumber(ExclusiveContext *cx, JSString *str, double *result);
StringToNumber(ThreadSafeContext *cx, JSString *str, double *result);
/* ES5 9.3 ToNumber, overwriting *vp with the appropriate number value. */
JS_ALWAYS_INLINE bool
@ -177,7 +177,7 @@ num_parseInt(JSContext *cx, unsigned argc, Value *vp);
* Return false if out of memory.
*/
extern JSBool
js_strtod(js::ExclusiveContext *cx, const jschar *s, const jschar *send,
js_strtod(js::ThreadSafeContext *cx, const jschar *s, const jschar *send,
const jschar **ep, double *dp);
extern JSBool
@ -289,6 +289,49 @@ ToNumber(ExclusiveContext *cx, const Value &v, double *out)
return ToNumberSlow(cx, v, out);
}
/*
* Thread safe variants of number conversion functions.
*/
bool
NonObjectToNumberSlow(ThreadSafeContext *cx, Value v, double *out);
inline bool
NonObjectToNumber(ThreadSafeContext *cx, const Value &v, double *out)
{
if (v.isNumber()) {
*out = v.toNumber();
return true;
}
return NonObjectToNumberSlow(cx, v, out);
}
bool
NonObjectToInt32Slow(ThreadSafeContext *cx, const Value &v, int32_t *out);
inline bool
NonObjectToInt32(ThreadSafeContext *cx, const Value &v, int32_t *out)
{
if (v.isInt32()) {
*out = v.toInt32();
return true;
}
return NonObjectToInt32Slow(cx, v, out);
}
bool
NonObjectToUint32Slow(ThreadSafeContext *cx, const Value &v, uint32_t *out);
JS_ALWAYS_INLINE bool
NonObjectToUint32(ThreadSafeContext *cx, const Value &v, uint32_t *out)
{
if (v.isInt32()) {
*out = uint32_t(v.toInt32());
return true;
}
return NonObjectToUint32Slow(cx, v, out);
}
} /* namespace js */
#endif /* jsnum_h */

View File

@ -44,13 +44,10 @@ class RopeBuilder;
template <AllowGC allowGC>
extern JSString *
ConcatStrings(JSContext *cx,
ConcatStrings(ThreadSafeContext *cx,
typename MaybeRooted<JSString*, allowGC>::HandleType left,
typename MaybeRooted<JSString*, allowGC>::HandleType right);
extern JSString *
ConcatStringsPure(ThreadSafeContext *cx, JSString *left, JSString *right);
// Return s advanced past any Unicode white space characters.
static inline const jschar *
SkipSpace(const jschar *s, const jschar *end)

View File

@ -401,7 +401,7 @@ JSRope::flatten(JSContext *maybecx)
template <AllowGC allowGC>
JSString *
js::ConcatStrings(JSContext *cx,
js::ConcatStrings(ThreadSafeContext *cx,
typename MaybeRooted<JSString*, allowGC>::HandleType left,
typename MaybeRooted<JSString*, allowGC>::HandleType right)
{
@ -424,16 +424,16 @@ js::ConcatStrings(JSContext *cx,
JSShortString *str = js_NewGCShortString<allowGC>(cx);
if (!str)
return NULL;
const jschar *leftChars = left->getChars(cx);
if (!leftChars)
return NULL;
const jschar *rightChars = right->getChars(cx);
if (!rightChars)
ScopedThreadSafeStringInspector leftInspector(left);
ScopedThreadSafeStringInspector rightInspector(right);
if (!leftInspector.ensureChars(cx) || !rightInspector.ensureChars(cx))
return NULL;
jschar *buf = str->init(wholeLength);
PodCopy(buf, leftChars, leftLen);
PodCopy(buf + leftLen, rightChars, rightLen);
PodCopy(buf, leftInspector.chars(), leftLen);
PodCopy(buf + leftLen, rightInspector.chars(), rightLen);
buf[wholeLength] = 0;
return str;
}
@ -442,50 +442,10 @@ js::ConcatStrings(JSContext *cx,
}
template JSString *
js::ConcatStrings<CanGC>(JSContext *cx, HandleString left, HandleString right);
js::ConcatStrings<CanGC>(ThreadSafeContext *cx, HandleString left, HandleString right);
template JSString *
js::ConcatStrings<NoGC>(JSContext *cx, JSString *left, JSString *right);
JSString *
js::ConcatStringsPure(ThreadSafeContext *cx, JSString *left, JSString *right)
{
JS_ASSERT_IF(!left->isAtom(), cx->isInsideCurrentZone(left));
JS_ASSERT_IF(!right->isAtom(), cx->isInsideCurrentZone(right));
size_t leftLen = left->length();
if (leftLen == 0)
return right;
size_t rightLen = right->length();
if (rightLen == 0)
return left;
size_t wholeLength = leftLen + rightLen;
if (!JSString::validateLength(NULL, wholeLength))
return NULL;
if (JSShortString::lengthFits(wholeLength)) {
JSShortString *str = js_NewGCShortString<NoGC>(cx);
if (!str)
return NULL;
jschar *buf = str->init(wholeLength);
ScopedThreadSafeStringInspector leftInspector(left);
ScopedThreadSafeStringInspector rightInspector(right);
if (!leftInspector.ensureChars(cx) || !rightInspector.ensureChars(cx))
return NULL;
PodCopy(buf, leftInspector.chars(), leftLen);
PodCopy(buf + leftLen, rightInspector.chars(), rightLen);
buf[wholeLength] = 0;
return str;
}
return JSRope::new_<NoGC>(cx, left, right, wholeLength);
}
js::ConcatStrings<NoGC>(ThreadSafeContext *cx, JSString *left, JSString *right);
bool
JSDependentString::getCharsZNonDestructive(ThreadSafeContext *cx, ScopedJSFreePtr<jschar> &out) const