diff options
author | Lars Knoll <lars.knoll@digia.com> | 2013-11-02 17:11:06 +0100 |
---|---|---|
committer | The Qt Project <gerrit-noreply@qt-project.org> | 2013-11-05 22:23:25 +0100 |
commit | 26db9863f18d7f7e89cec88b720e4fb4c674dd5b (patch) | |
tree | fe5443f04e6c6adf47ac45e2e46b7c3965faf08a /src/qml/jsruntime | |
parent | 4ffa7d3f651757b7bc10ae9801b7802a8f2e260f (diff) |
Optimise string additions
Small optimisation for string additions, also add one more check
for exceptions in the code where required.
Change-Id: I6c14bc88ea5d03f7eeed0e0168c5195f9f823693
Reviewed-by: Simon Hausmann <simon.hausmann@digia.com>
Diffstat (limited to 'src/qml/jsruntime')
-rw-r--r-- | src/qml/jsruntime/qv4jsonobject.cpp | 2 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4numberobject.cpp | 2 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4regexpobject.cpp | 8 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4runtime.cpp | 110 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4runtime_p.h | 3 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4stringobject.cpp | 6 |
6 files changed, 98 insertions, 33 deletions
diff --git a/src/qml/jsruntime/qv4jsonobject.cpp b/src/qml/jsruntime/qv4jsonobject.cpp index 8d693f7705..c4d1ebc545 100644 --- a/src/qml/jsruntime/qv4jsonobject.cpp +++ b/src/qml/jsruntime/qv4jsonobject.cpp @@ -926,7 +926,7 @@ ReturnedValue JsonObject::method_stringify(SimpleCallContext *ctx) for (uint i = 0; i < arrayLen; ++i) { v = o->getIndexed(i); if (v->asNumberObject() || v->asStringObject() || v->isNumber()) - v = __qmljs_to_string(v, ctx); + v = __qmljs_to_string(ctx, v); if (v->isString()) { String *s = v->stringValue(); if (!stringify.propertyList.contains(s)) diff --git a/src/qml/jsruntime/qv4numberobject.cpp b/src/qml/jsruntime/qv4numberobject.cpp index 098afa8161..2000297b84 100644 --- a/src/qml/jsruntime/qv4numberobject.cpp +++ b/src/qml/jsruntime/qv4numberobject.cpp @@ -250,7 +250,7 @@ ReturnedValue NumberPrototype::method_toPrecision(SimpleCallContext *ctx) return Encode::undefined(); if (!ctx->callData->argc || ctx->callData->args[0].isUndefined()) - return __qmljs_to_string(v, ctx); + return __qmljs_to_string(ctx, v); double precision = ctx->callData->args[0].toInt32(); if (precision < 1 || precision > 21) { diff --git a/src/qml/jsruntime/qv4regexpobject.cpp b/src/qml/jsruntime/qv4regexpobject.cpp index 7322a58412..c2d04cc7ed 100644 --- a/src/qml/jsruntime/qv4regexpobject.cpp +++ b/src/qml/jsruntime/qv4regexpobject.cpp @@ -266,10 +266,10 @@ ReturnedValue RegExpCtor::construct(Managed *m, CallData *callData) bool ignoreCase = false; bool multiLine = false; if (!f->isUndefined()) { - f = __qmljs_to_string(f, ctx); - QString str = f->stringValue()->toQString(); + f = __qmljs_to_string(ctx, f); if (scope.hasException()) return Encode::undefined(); + QString str = f->stringValue()->toQString(); for (int i = 0; i < str.length(); ++i) { if (str.at(i) == QLatin1Char('g') && !global) { global = true; @@ -322,7 +322,9 @@ ReturnedValue RegExpPrototype::method_exec(SimpleCallContext *ctx) return ctx->throwTypeError(); ScopedValue arg(scope, ctx->argument(0)); - arg = __qmljs_to_string(arg, ctx); + arg = __qmljs_to_string(ctx, arg); + if (scope.hasException()) + return Encode::undefined(); QString s = arg->stringValue()->toQString(); int offset = r->global ? r->lastIndexProperty(ctx)->value.toInt32() : 0; diff --git a/src/qml/jsruntime/qv4runtime.cpp b/src/qml/jsruntime/qv4runtime.cpp index 4e40779c16..d8ebe635bd 100644 --- a/src/qml/jsruntime/qv4runtime.cpp +++ b/src/qml/jsruntime/qv4runtime.cpp @@ -297,30 +297,6 @@ ReturnedValue __qmljs_delete_name(ExecutionContext *ctx, const StringRef name) return Encode(ctx->deleteProperty(name)); } -QV4::ReturnedValue __qmljs_add_helper(ExecutionContext *ctx, const ValueRef left, const ValueRef right) -{ - Scope scope(ctx); - - ScopedValue pleft(scope, __qmljs_to_primitive(left, PREFERREDTYPE_HINT)); - ScopedValue pright(scope, __qmljs_to_primitive(right, PREFERREDTYPE_HINT)); - if (pleft->isString() || pright->isString()) { - if (!pleft->isString()) - pleft = __qmljs_to_string(pleft, ctx); - if (!pright->isString()) - pright = __qmljs_to_string(pright, ctx); - if (scope.engine->hasException) - return Encode::undefined(); - if (!pleft->stringValue()->length()) - return right->asReturnedValue(); - if (!pright->stringValue()->length()) - return pleft->asReturnedValue(); - return (new (ctx->engine->memoryManager) String(ctx->engine, pleft->stringValue(), pright->stringValue()))->asReturnedValue(); - } - double x = __qmljs_to_number(pleft); - double y = __qmljs_to_number(pright); - return Encode(x + y); -} - QV4::ReturnedValue __qmljs_instanceof(ExecutionContext *ctx, const ValueRef left, const ValueRef right) { Object *o = right->asObject(); @@ -469,6 +445,90 @@ Returned<String> *__qmljs_convert_to_string(ExecutionContext *ctx, const ValueRe } // switch } +// This is slightly different from the method above, as +// the + operator requires a slightly different conversion +static Returned<String> *convert_to_string_add(ExecutionContext *ctx, const ValueRef value) +{ + switch (value->type()) { + case Value::Empty_Type: + Q_ASSERT(!"empty Value encountered"); + case Value::Undefined_Type: + return ctx->engine->id_undefined.ret(); + case Value::Null_Type: + return ctx->engine->id_null.ret(); + case Value::Boolean_Type: + if (value->booleanValue()) + return ctx->engine->id_true.ret(); + else + return ctx->engine->id_false.ret(); + case Value::Managed_Type: + if (value->isString()) + return value->stringValue()->asReturned<String>(); + { + Scope scope(ctx); + ScopedValue prim(scope, __qmljs_to_primitive(value, PREFERREDTYPE_HINT)); + return __qmljs_convert_to_string(ctx, prim); + } + case Value::Integer_Type: + return __qmljs_string_from_number(ctx, value->int_32); + default: // double + return __qmljs_string_from_number(ctx, value->doubleValue()); + } // switch +} + +QV4::ReturnedValue __qmljs_add_helper(ExecutionContext *ctx, const ValueRef left, const ValueRef right) +{ + Scope scope(ctx); + + ScopedValue pleft(scope, __qmljs_to_primitive(left, PREFERREDTYPE_HINT)); + ScopedValue pright(scope, __qmljs_to_primitive(right, PREFERREDTYPE_HINT)); + if (pleft->isString() || pright->isString()) { + if (!pleft->isString()) + pleft = convert_to_string_add(ctx, pleft); + if (!pright->isString()) + pright = convert_to_string_add(ctx, pright); + if (scope.engine->hasException) + return Encode::undefined(); + if (!pleft->stringValue()->length()) + return pright->asReturnedValue(); + if (!pright->stringValue()->length()) + return pleft->asReturnedValue(); + return (new (ctx->engine->memoryManager) String(ctx->engine, pleft->stringValue(), pright->stringValue()))->asReturnedValue(); + } + double x = __qmljs_to_number(pleft); + double y = __qmljs_to_number(pright); + return Encode(x + y); +} + +QV4::ReturnedValue __qmljs_add_string(QV4::ExecutionContext *ctx, const QV4::ValueRef left, const QV4::ValueRef right) +{ + Q_ASSERT(left->isString() || right->isString()); + + if (left->isString() && right->isString()) { + if (!left->stringValue()->length()) + return right->asReturnedValue(); + if (!right->stringValue()->length()) + return left->asReturnedValue(); + return (new (ctx->engine->memoryManager) String(ctx->engine, left->stringValue(), right->stringValue()))->asReturnedValue(); + } + + Scope scope(ctx); + ScopedValue pleft(scope, *left); + ScopedValue pright(scope, *right); + + if (!pleft->isString()) + pleft = convert_to_string_add(ctx, left); + if (!pright->isString()) + pright = convert_to_string_add(ctx, right); + if (scope.engine->hasException) + return Encode::undefined(); + if (!pleft->stringValue()->length()) + return pright->asReturnedValue(); + if (!pright->stringValue()->length()) + return pleft->asReturnedValue(); + return (new (ctx->engine->memoryManager) String(ctx->engine, pleft->stringValue(), pright->stringValue()))->asReturnedValue(); +} + void __qmljs_set_property(ExecutionContext *ctx, const ValueRef object, const StringRef name, const ValueRef value) { Scope scope(ctx); @@ -1110,7 +1170,7 @@ QV4::ReturnedValue __qmljs_decrement(const QV4::ValueRef value) } } -QV4::ReturnedValue __qmljs_to_string(const QV4::ValueRef value, QV4::ExecutionContext *ctx) +QV4::ReturnedValue __qmljs_to_string(QV4::ExecutionContext *ctx, const QV4::ValueRef value) { if (value->isString()) return value.asReturnedValue(); diff --git a/src/qml/jsruntime/qv4runtime_p.h b/src/qml/jsruntime/qv4runtime_p.h index 1bd6805837..4f6f3a33d4 100644 --- a/src/qml/jsruntime/qv4runtime_p.h +++ b/src/qml/jsruntime/qv4runtime_p.h @@ -184,7 +184,7 @@ QV4::ReturnedValue __qmljs_foreach_next_property_name(const ValueRef foreach_ite QV4::ReturnedValue __qmljs_to_primitive(const ValueRef value, int typeHint); Q_QML_EXPORT QV4::Bool __qmljs_to_boolean(const QV4::ValueRef value); double __qmljs_to_number(const QV4::ValueRef value); -QV4::ReturnedValue __qmljs_to_string(const ValueRef value, QV4::ExecutionContext *ctx); +QV4::ReturnedValue __qmljs_to_string(QV4::ExecutionContext *ctx, const ValueRef value); Q_QML_EXPORT Returned<String> *__qmljs_convert_to_string(QV4::ExecutionContext *ctx, const ValueRef value); void __qmljs_numberToString(QString *result, double num, int radix = 10); ReturnedValue __qmljs_to_object(QV4::ExecutionContext *ctx, const ValueRef value); @@ -221,6 +221,7 @@ typedef QV4::ReturnedValue (*BinOpContext)(QV4::ExecutionContext *ctx, const QV4 QV4::ReturnedValue __qmljs_instanceof(QV4::ExecutionContext *ctx, const QV4::ValueRef left, const QV4::ValueRef right); QV4::ReturnedValue __qmljs_in(QV4::ExecutionContext *ctx, const QV4::ValueRef left, const QV4::ValueRef right); QV4::ReturnedValue __qmljs_add(ExecutionContext *ctx, const QV4::ValueRef left, const QV4::ValueRef right); +QV4::ReturnedValue __qmljs_add_string(QV4::ExecutionContext *ctx, const QV4::ValueRef left, const QV4::ValueRef right); QV4::ReturnedValue __qmljs_bit_or(const QV4::ValueRef left, const QV4::ValueRef right); QV4::ReturnedValue __qmljs_bit_xor(const QV4::ValueRef left, const QV4::ValueRef right); QV4::ReturnedValue __qmljs_bit_and(const QV4::ValueRef left, const QV4::ValueRef right); diff --git a/src/qml/jsruntime/qv4stringobject.cpp b/src/qml/jsruntime/qv4stringobject.cpp index 33dd403e9b..7ba7a38cc0 100644 --- a/src/qml/jsruntime/qv4stringobject.cpp +++ b/src/qml/jsruntime/qv4stringobject.cpp @@ -301,8 +301,10 @@ ReturnedValue StringPrototype::method_concat(SimpleCallContext *context) ScopedValue v(scope); for (int i = 0; i < context->callData->argc; ++i) { - v = __qmljs_to_string(ValueRef(&context->callData->args[i]), context); - assert(v->isString()); + v = __qmljs_to_string(context, ValueRef(&context->callData->args[i])); + if (scope.hasException()) + return Encode::undefined(); + Q_ASSERT(v->isString()); value += v->stringValue()->toQString(); } |