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;
|
||||
}
|
||||
|
||||
typedef JSString *(*ConcatStringsFn)(JSContext *, HandleString, HandleString);
|
||||
typedef JSString *(*ConcatStringsFn)(ThreadSafeContext *, HandleString, HandleString);
|
||||
typedef ParallelResult (*ConcatStringsParFn)(ForkJoinSlice *, HandleString, HandleString,
|
||||
MutableHandleString);
|
||||
static const VMFunctionsModal ConcatStringsInfo = VMFunctionsModal(
|
||||
|
@ -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);
|
||||
|
130
js/src/jsnum.cpp
130
js/src/jsnum.cpp
@ -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;
|
||||
}
|
||||
*result = js_NaN;
|
||||
return true;
|
||||
else
|
||||
*result = js_NaN;
|
||||
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;
|
||||
}
|
||||
*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;
|
||||
|
@ -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 */
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user