mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 892634 - Part 1: Add thread safe number conversion functions. (r=billm)
This commit is contained in:
parent
2e435e83b4
commit
811fd3643c
@ -4038,7 +4038,7 @@ CodeGenerator::visitEmulatesUndefinedAndBranch(LEmulatesUndefinedAndBranch *lir)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
typedef JSString *(*ConcatStringsFn)(JSContext *, HandleString, HandleString);
|
typedef JSString *(*ConcatStringsFn)(ThreadSafeContext *, HandleString, HandleString);
|
||||||
typedef ParallelResult (*ConcatStringsParFn)(ForkJoinSlice *, HandleString, HandleString,
|
typedef ParallelResult (*ConcatStringsParFn)(ForkJoinSlice *, HandleString, HandleString,
|
||||||
MutableHandleString);
|
MutableHandleString);
|
||||||
static const VMFunctionsModal ConcatStringsInfo = VMFunctionsModal(
|
static const VMFunctionsModal ConcatStringsInfo = VMFunctionsModal(
|
||||||
|
@ -191,7 +191,7 @@ ParallelResult
|
|||||||
ion::ConcatStringsPar(ForkJoinSlice *slice, HandleString left, HandleString right,
|
ion::ConcatStringsPar(ForkJoinSlice *slice, HandleString left, HandleString right,
|
||||||
MutableHandleString out)
|
MutableHandleString out)
|
||||||
{
|
{
|
||||||
JSString *str = ConcatStringsPure(slice, left, right);
|
JSString *str = ConcatStrings<NoGC>(slice, left, right);
|
||||||
if (!str)
|
if (!str)
|
||||||
return TP_RETRY_SEQUENTIALLY;
|
return TP_RETRY_SEQUENTIALLY;
|
||||||
out.set(str);
|
out.set(str);
|
||||||
|
128
js/src/jsnum.cpp
128
js/src/jsnum.cpp
@ -54,7 +54,7 @@ using mozilla::RangedPtr;
|
|||||||
* Call js_strtod_harder to get the correct answer.
|
* Call js_strtod_harder to get the correct answer.
|
||||||
*/
|
*/
|
||||||
static bool
|
static bool
|
||||||
ComputeAccurateDecimalInteger(ExclusiveContext *cx,
|
ComputeAccurateDecimalInteger(ThreadSafeContext *cx,
|
||||||
const jschar *start, const jschar *end, double *dp)
|
const jschar *start, const jschar *end, double *dp)
|
||||||
{
|
{
|
||||||
size_t length = end - start;
|
size_t length = end - start;
|
||||||
@ -188,7 +188,7 @@ js::ParseDecimalNumber(const JS::TwoByteChars chars)
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool
|
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)
|
const jschar **endp, double *dp)
|
||||||
{
|
{
|
||||||
JS_ASSERT(start <= end);
|
JS_ASSERT(start <= end);
|
||||||
@ -1390,26 +1390,18 @@ js::NumberValueToStringBuffer(JSContext *cx, const Value &v, StringBuffer &sb)
|
|||||||
return sb.appendInflated(cstr, cstrlen);
|
return sb.appendInflated(cstr, cstrlen);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
static void
|
||||||
js::StringToNumber(ExclusiveContext *cx, JSString *str, double *result)
|
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) {
|
if (length == 1) {
|
||||||
jschar c = chars[0];
|
jschar c = chars[0];
|
||||||
if ('0' <= c && c <= '9') {
|
if ('0' <= c && c <= '9')
|
||||||
*result = c - '0';
|
*result = c - '0';
|
||||||
return true;
|
else if (unicode::IsSpace(c))
|
||||||
}
|
|
||||||
if (unicode::IsSpace(c)) {
|
|
||||||
*result = 0.0;
|
*result = 0.0;
|
||||||
return true;
|
else
|
||||||
}
|
|
||||||
*result = js_NaN;
|
*result = js_NaN;
|
||||||
return true;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const jschar *end = chars + length;
|
const jschar *end = chars + length;
|
||||||
@ -1429,10 +1421,10 @@ js::StringToNumber(ExclusiveContext *cx, JSString *str, double *result)
|
|||||||
SkipSpace(endptr, end) != end)
|
SkipSpace(endptr, end) != end)
|
||||||
{
|
{
|
||||||
*result = js_NaN;
|
*result = js_NaN;
|
||||||
return true;
|
} else {
|
||||||
}
|
|
||||||
*result = d;
|
*result = d;
|
||||||
return true;
|
}
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -1444,11 +1436,41 @@ js::StringToNumber(ExclusiveContext *cx, JSString *str, double *result)
|
|||||||
*/
|
*/
|
||||||
const jschar *ep;
|
const jschar *ep;
|
||||||
double d;
|
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;
|
*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;
|
return true;
|
||||||
}
|
}
|
||||||
*result = d;
|
if (v.isNull()) {
|
||||||
|
*out = 0.0;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
JS_ASSERT(v.isUndefined());
|
||||||
|
*out = js_NaN;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1485,25 +1507,11 @@ js::ToNumberSlow(ExclusiveContext *cx, Value v, double *out)
|
|||||||
*out = v.toNumber();
|
*out = v.toNumber();
|
||||||
return true;
|
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())
|
if (!cx->isJSContext())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
@ -1567,15 +1575,18 @@ js::ToUint64Slow(JSContext *cx, const HandleValue v, uint64_t *out)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
JS_PUBLIC_API(bool)
|
template <typename ContextType,
|
||||||
js::ToInt32Slow(JSContext *cx, const HandleValue v, int32_t *out)
|
bool (*ToNumberSlowFn)(ContextType *, Value, double *),
|
||||||
|
typename ValueType>
|
||||||
|
static bool
|
||||||
|
ToInt32SlowImpl(ContextType *cx, const ValueType v, int32_t *out)
|
||||||
{
|
{
|
||||||
JS_ASSERT(!v.isInt32());
|
JS_ASSERT(!v.isInt32());
|
||||||
double d;
|
double d;
|
||||||
if (v.isDouble()) {
|
if (v.isDouble()) {
|
||||||
d = v.toDouble();
|
d = v.toDouble();
|
||||||
} else {
|
} else {
|
||||||
if (!ToNumberSlow(cx, v, &d))
|
if (!ToNumberSlowFn(cx, v, &d))
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
*out = ToInt32(d);
|
*out = ToInt32(d);
|
||||||
@ -1583,20 +1594,47 @@ js::ToInt32Slow(JSContext *cx, const HandleValue v, int32_t *out)
|
|||||||
}
|
}
|
||||||
|
|
||||||
JS_PUBLIC_API(bool)
|
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());
|
JS_ASSERT(!v.isInt32());
|
||||||
double d;
|
double d;
|
||||||
if (v.isDouble()) {
|
if (v.isDouble()) {
|
||||||
d = v.toDouble();
|
d = v.toDouble();
|
||||||
} else {
|
} else {
|
||||||
if (!ToNumberSlow(cx, v, &d))
|
if (!ToNumberSlowFn(cx, v, &d))
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
*out = ToUint32(d);
|
*out = ToUint32(d);
|
||||||
return true;
|
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_PUBLIC_API(bool)
|
||||||
js::ToUint16Slow(JSContext *cx, const HandleValue v, uint16_t *out)
|
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
|
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)
|
const jschar **ep, double *dp)
|
||||||
{
|
{
|
||||||
size_t i;
|
size_t i;
|
||||||
|
@ -128,7 +128,7 @@ ParseDecimalNumber(const JS::TwoByteChars chars);
|
|||||||
* *dp == 0 and *endp == start upon return.
|
* *dp == 0 and *endp == start upon return.
|
||||||
*/
|
*/
|
||||||
extern bool
|
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);
|
const jschar **endp, double *dp);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -140,7 +140,7 @@ extern bool
|
|||||||
GetDecimalInteger(ExclusiveContext *cx, const jschar *start, const jschar *end, double *dp);
|
GetDecimalInteger(ExclusiveContext *cx, const jschar *start, const jschar *end, double *dp);
|
||||||
|
|
||||||
extern bool
|
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. */
|
/* ES5 9.3 ToNumber, overwriting *vp with the appropriate number value. */
|
||||||
JS_ALWAYS_INLINE bool
|
JS_ALWAYS_INLINE bool
|
||||||
@ -177,7 +177,7 @@ num_parseInt(JSContext *cx, unsigned argc, Value *vp);
|
|||||||
* Return false if out of memory.
|
* Return false if out of memory.
|
||||||
*/
|
*/
|
||||||
extern JSBool
|
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);
|
const jschar **ep, double *dp);
|
||||||
|
|
||||||
extern JSBool
|
extern JSBool
|
||||||
@ -289,6 +289,49 @@ ToNumber(ExclusiveContext *cx, const Value &v, double *out)
|
|||||||
return ToNumberSlow(cx, v, 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 */
|
} /* namespace js */
|
||||||
|
|
||||||
#endif /* jsnum_h */
|
#endif /* jsnum_h */
|
||||||
|
@ -44,13 +44,10 @@ class RopeBuilder;
|
|||||||
|
|
||||||
template <AllowGC allowGC>
|
template <AllowGC allowGC>
|
||||||
extern JSString *
|
extern JSString *
|
||||||
ConcatStrings(JSContext *cx,
|
ConcatStrings(ThreadSafeContext *cx,
|
||||||
typename MaybeRooted<JSString*, allowGC>::HandleType left,
|
typename MaybeRooted<JSString*, allowGC>::HandleType left,
|
||||||
typename MaybeRooted<JSString*, allowGC>::HandleType right);
|
typename MaybeRooted<JSString*, allowGC>::HandleType right);
|
||||||
|
|
||||||
extern JSString *
|
|
||||||
ConcatStringsPure(ThreadSafeContext *cx, JSString *left, JSString *right);
|
|
||||||
|
|
||||||
// Return s advanced past any Unicode white space characters.
|
// Return s advanced past any Unicode white space characters.
|
||||||
static inline const jschar *
|
static inline const jschar *
|
||||||
SkipSpace(const jschar *s, const jschar *end)
|
SkipSpace(const jschar *s, const jschar *end)
|
||||||
|
@ -401,7 +401,7 @@ JSRope::flatten(JSContext *maybecx)
|
|||||||
|
|
||||||
template <AllowGC allowGC>
|
template <AllowGC allowGC>
|
||||||
JSString *
|
JSString *
|
||||||
js::ConcatStrings(JSContext *cx,
|
js::ConcatStrings(ThreadSafeContext *cx,
|
||||||
typename MaybeRooted<JSString*, allowGC>::HandleType left,
|
typename MaybeRooted<JSString*, allowGC>::HandleType left,
|
||||||
typename MaybeRooted<JSString*, allowGC>::HandleType right)
|
typename MaybeRooted<JSString*, allowGC>::HandleType right)
|
||||||
{
|
{
|
||||||
@ -424,16 +424,16 @@ js::ConcatStrings(JSContext *cx,
|
|||||||
JSShortString *str = js_NewGCShortString<allowGC>(cx);
|
JSShortString *str = js_NewGCShortString<allowGC>(cx);
|
||||||
if (!str)
|
if (!str)
|
||||||
return NULL;
|
return NULL;
|
||||||
const jschar *leftChars = left->getChars(cx);
|
|
||||||
if (!leftChars)
|
ScopedThreadSafeStringInspector leftInspector(left);
|
||||||
return NULL;
|
ScopedThreadSafeStringInspector rightInspector(right);
|
||||||
const jschar *rightChars = right->getChars(cx);
|
if (!leftInspector.ensureChars(cx) || !rightInspector.ensureChars(cx))
|
||||||
if (!rightChars)
|
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
jschar *buf = str->init(wholeLength);
|
jschar *buf = str->init(wholeLength);
|
||||||
PodCopy(buf, leftChars, leftLen);
|
PodCopy(buf, leftInspector.chars(), leftLen);
|
||||||
PodCopy(buf + leftLen, rightChars, rightLen);
|
PodCopy(buf + leftLen, rightInspector.chars(), rightLen);
|
||||||
|
|
||||||
buf[wholeLength] = 0;
|
buf[wholeLength] = 0;
|
||||||
return str;
|
return str;
|
||||||
}
|
}
|
||||||
@ -442,50 +442,10 @@ js::ConcatStrings(JSContext *cx,
|
|||||||
}
|
}
|
||||||
|
|
||||||
template JSString *
|
template JSString *
|
||||||
js::ConcatStrings<CanGC>(JSContext *cx, HandleString left, HandleString right);
|
js::ConcatStrings<CanGC>(ThreadSafeContext *cx, HandleString left, HandleString right);
|
||||||
|
|
||||||
template JSString *
|
template JSString *
|
||||||
js::ConcatStrings<NoGC>(JSContext *cx, JSString *left, JSString *right);
|
js::ConcatStrings<NoGC>(ThreadSafeContext *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);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
bool
|
||||||
JSDependentString::getCharsZNonDestructive(ThreadSafeContext *cx, ScopedJSFreePtr<jschar> &out) const
|
JSDependentString::getCharsZNonDestructive(ThreadSafeContext *cx, ScopedJSFreePtr<jschar> &out) const
|
||||||
|
Loading…
Reference in New Issue
Block a user