aboutsummaryrefslogtreecommitdiffstats
path: root/src/qml/jsruntime/qv4vme_moth.cpp
diff options
context:
space:
mode:
authorSimon Hausmann <simon.hausmann@qt.io>2018-06-22 11:45:08 +0200
committerSimon Hausmann <simon.hausmann@qt.io>2018-06-22 17:24:04 +0000
commitfb2f1089a017bf2c3cd83454cb06077d72fdaa6e (patch)
treef6b96717c9ab3bebda8645b74cea2876aab37503 /src/qml/jsruntime/qv4vme_moth.cpp
parent1916a25aaf57df9036783addc6d5af4aebfacd27 (diff)
Improve GC safety of compare function
When comparing values we may end up calling user-defined conversion functions, which in turn may accidentally end up triggering the GC. So any intermediate managed values we fetch, we must save on the JS stack. Change-Id: I810a46f740f22f8fd71a83ed362301cfc822190d Reviewed-by: Lars Knoll <lars.knoll@qt.io>
Diffstat (limited to 'src/qml/jsruntime/qv4vme_moth.cpp')
-rw-r--r--src/qml/jsruntime/qv4vme_moth.cpp37
1 files changed, 32 insertions, 5 deletions
diff --git a/src/qml/jsruntime/qv4vme_moth.cpp b/src/qml/jsruntime/qv4vme_moth.cpp
index 9bd19cbe6b..547c3fce7a 100644
--- a/src/qml/jsruntime/qv4vme_moth.cpp
+++ b/src/qml/jsruntime/qv4vme_moth.cpp
@@ -362,9 +362,32 @@ static inline const QV4::Value &constant(Function *function, int index)
return function->compilationUnit->constants[index];
}
+struct LazyScope
+{
+ ExecutionEngine *engine = nullptr;
+ Value *stackMark = nullptr;
+ ~LazyScope() {
+ if (engine)
+ engine->jsStackTop = stackMark;
+ }
+ template <typename T>
+ void set(Value **scopedValue, T value, ExecutionEngine *e) {
+ if (!engine) {
+ engine = e;
+ stackMark = engine->jsStackTop;
+ }
+ if (!*scopedValue)
+ *scopedValue = e->jsAlloca(1);
+ **scopedValue = value;
+ }
+};
static bool compareEqual(QV4::Value lhs, QV4::Value rhs)
{
+ LazyScope scope;
+ Value *lhsGuard = nullptr;
+ Value *rhsGuard = nullptr;
+
redo:
if (lhs.asReturnedValue() == rhs.asReturnedValue())
return !lhs.isNaN();
@@ -401,11 +424,13 @@ static bool compareEqual(QV4::Value lhs, QV4::Value rhs)
if (l->internalClass->vtable->isStringOrSymbol == r->internalClass->vtable->isStringOrSymbol)
return static_cast<QV4::Managed &>(lhs).isEqualTo(&static_cast<QV4::Managed &>(rhs));
if (l->internalClass->vtable->isStringOrSymbol) {
- rhs = Primitive::fromReturnedValue(RuntimeHelpers::objectDefaultValue(&static_cast<QV4::Object &>(rhs), PREFERREDTYPE_HINT));
+ scope.set(&rhsGuard, RuntimeHelpers::objectDefaultValue(&static_cast<QV4::Object &>(rhs), PREFERREDTYPE_HINT), r->internalClass->engine);
+ rhs = rhsGuard->asReturnedValue();
break;
} else {
Q_ASSERT(r->internalClass->vtable->isStringOrSymbol);
- lhs = Primitive::fromReturnedValue(RuntimeHelpers::objectDefaultValue(&static_cast<QV4::Object &>(lhs), PREFERREDTYPE_HINT));
+ scope.set(&lhsGuard, RuntimeHelpers::objectDefaultValue(&static_cast<QV4::Object &>(lhs), PREFERREDTYPE_HINT), l->internalClass->engine);
+ lhs = lhsGuard->asReturnedValue();
break;
}
return false;
@@ -419,10 +444,12 @@ static bool compareEqual(QV4::Value lhs, QV4::Value rhs)
rhs = Primitive::fromDouble(rhs.int_32());
// fall through
default: // double
- if (lhs.m()->internalClass->vtable->isStringOrSymbol)
+ if (lhs.m()->internalClass->vtable->isStringOrSymbol) {
return lhs.m()->internalClass->vtable->isString ? (RuntimeHelpers::toNumber(lhs) == rhs.doubleValue()) : false;
- else
- lhs = Primitive::fromReturnedValue(RuntimeHelpers::objectDefaultValue(&static_cast<QV4::Object &>(lhs), PREFERREDTYPE_HINT));
+ } else {
+ scope.set(&lhsGuard, RuntimeHelpers::objectDefaultValue(&static_cast<QV4::Object &>(lhs), PREFERREDTYPE_HINT), lhs.m()->internalClass->engine);
+ lhs = lhsGuard->asReturnedValue();
+ }
}
goto redo;
case QV4::Value::QT_Empty: