aboutsummaryrefslogtreecommitdiffstats
path: root/src/qml/jsruntime
diff options
context:
space:
mode:
authorLars Knoll <lars.knoll@digia.com>2013-11-02 17:11:06 +0100
committerThe Qt Project <gerrit-noreply@qt-project.org>2013-11-05 22:23:25 +0100
commit26db9863f18d7f7e89cec88b720e4fb4c674dd5b (patch)
treefe5443f04e6c6adf47ac45e2e46b7c3965faf08a /src/qml/jsruntime
parent4ffa7d3f651757b7bc10ae9801b7802a8f2e260f (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.cpp2
-rw-r--r--src/qml/jsruntime/qv4numberobject.cpp2
-rw-r--r--src/qml/jsruntime/qv4regexpobject.cpp8
-rw-r--r--src/qml/jsruntime/qv4runtime.cpp110
-rw-r--r--src/qml/jsruntime/qv4runtime_p.h3
-rw-r--r--src/qml/jsruntime/qv4stringobject.cpp6
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();
}