From b959074afb43d25c1a8818e0528004f8cf073ae2 Mon Sep 17 00:00:00 2001 From: Ulf Hermann Date: Fri, 22 Feb 2019 17:13:36 +0100 Subject: Unify and fix number to string conversion with radix Previously, the loop that generated the string could fail to terminate with certain numbers as input. Also, the algorithm was duplicated in two places. Change-Id: Ie2075148d931e7cfcedb5bcd23af61e2e8afc232 Fixes: QTBUG-73999 Reviewed-by: Robert Loehning Reviewed-by: Lars Knoll --- src/qml/jsruntime/qv4numberobject.cpp | 38 +++-------------------------------- src/qml/jsruntime/qv4runtime.cpp | 17 ++++++++++++---- 2 files changed, 16 insertions(+), 39 deletions(-) (limited to 'src/qml/jsruntime') diff --git a/src/qml/jsruntime/qv4numberobject.cpp b/src/qml/jsruntime/qv4numberobject.cpp index d26e888069..13f6912371 100644 --- a/src/qml/jsruntime/qv4numberobject.cpp +++ b/src/qml/jsruntime/qv4numberobject.cpp @@ -223,41 +223,9 @@ ReturnedValue NumberPrototype::method_toString(const FunctionObject *b, const Va return v4->throwError(QStringLiteral("Number.prototype.toString: %0 is not a valid radix").arg(radix)); } - if (std::isnan(num)) { - return Encode(v4->newString(QStringLiteral("NaN"))); - } else if (qt_is_inf(num)) { - return Encode(v4->newString(QLatin1String(num < 0 ? "-Infinity" : "Infinity"))); - } - - if (radix != 10) { - QString str; - bool negative = false; - if (num < 0) { - negative = true; - num = -num; - } - double frac = num - std::floor(num); - num = Value::toInteger(num); - do { - char c = (char)std::fmod(num, radix); - c = (c < 10) ? (c + '0') : (c - 10 + 'a'); - str.prepend(QLatin1Char(c)); - num = std::floor(num / radix); - } while (num != 0); - if (frac != 0) { - str.append(QLatin1Char('.')); - do { - frac = frac * radix; - char c = (char)std::floor(frac); - c = (c < 10) ? (c + '0') : (c - 10 + 'a'); - str.append(QLatin1Char(c)); - frac = frac - std::floor(frac); - } while (frac != 0); - } - if (negative) - str.prepend(QLatin1Char('-')); - return Encode(v4->newString(str)); - } + QString str; + RuntimeHelpers::numberToString(&str, num, radix); + return Encode(v4->newString(str)); } return Encode(Value::fromDouble(num).toString(v4)); diff --git a/src/qml/jsruntime/qv4runtime.cpp b/src/qml/jsruntime/qv4runtime.cpp index 13244fdd95..424103cb08 100644 --- a/src/qml/jsruntime/qv4runtime.cpp +++ b/src/qml/jsruntime/qv4runtime.cpp @@ -298,13 +298,22 @@ void RuntimeHelpers::numberToString(QString *result, double num, int radix) if (frac != 0) { result->append(QLatin1Char('.')); + double magnitude = 1; + double next = frac; do { - frac = frac * radix; - char c = (char)::floor(frac); + next *= radix; + const int floored = ::floor(next); + char c = char(floored); c = (c < 10) ? (c + '0') : (c - 10 + 'a'); result->append(QLatin1Char(c)); - frac = frac - ::floor(frac); - } while (frac != 0); + magnitude /= radix; + frac -= double(floored) * magnitude; + next -= double(floored); + + // The next digit still makes a difference + // if a value of "radix" for it would change frac. + // Otherwise we've reached the limit of numerical precision. + } while (frac > 0 && frac - magnitude != frac); } if (negative) -- cgit v1.2.3 From 783ec60774a565f3a16c25af076b720de0e6acbd Mon Sep 17 00:00:00 2001 From: Ulf Hermann Date: Fri, 1 Mar 2019 14:57:21 +0100 Subject: Disable tail calls for function called with more arguments than formals We cannot easily find the required stack space to store the extra arguments without adding a new stack frame. In principle it would be possible, but heavily recursing on such functions should be a rare problem. Change-Id: I1a53a6d29e37ce67aa7bd64acb7b1f41197e84c0 Fixes: QTBUG-72807 Reviewed-by: Simon Hausmann --- src/qml/jsruntime/qv4runtime.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'src/qml/jsruntime') diff --git a/src/qml/jsruntime/qv4runtime.cpp b/src/qml/jsruntime/qv4runtime.cpp index 424103cb08..53dd3a66dd 100644 --- a/src/qml/jsruntime/qv4runtime.cpp +++ b/src/qml/jsruntime/qv4runtime.cpp @@ -1561,12 +1561,14 @@ ReturnedValue Runtime::method_tailCall(CppStackFrame *frame, ExecutionEngine *en const Value &thisObject = tos[StackOffsets::tailCall_thisObject]; Value *argv = reinterpret_cast(frame->jsFrame) + tos[StackOffsets::tailCall_argv].int_32(); int argc = tos[StackOffsets::tailCall_argc].int_32(); + Q_ASSERT(argc >= 0); if (!function.isFunctionObject()) return engine->throwTypeError(); const FunctionObject &fo = static_cast(function); - if (!frame->callerCanHandleTailCall || !fo.canBeTailCalled() || engine->debugger()) { + if (!frame->callerCanHandleTailCall || !fo.canBeTailCalled() || engine->debugger() + || unsigned(argc) > fo.formalParameterCount()) { // Cannot tailcall, do a normal call: return fo.call(&thisObject, argv, argc); } -- cgit v1.2.3