aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/plugins/qmltooling/qmldbg_profiler/qqmlprofileradapter.cpp2
-rw-r--r--src/plugins/qmltooling/qmldbg_quickprofiler/qquickprofileradapter.cpp2
-rw-r--r--src/qml/compiler/qv4isel_moth.cpp4
-rw-r--r--src/qml/compiler/qv4ssa.cpp6
-rw-r--r--src/qml/jit/qv4isel_masm.cpp4
-rw-r--r--src/qml/jsruntime/qv4arraydata.cpp2
-rw-r--r--src/qml/jsruntime/qv4executableallocator_p.h2
-rw-r--r--src/qml/jsruntime/qv4internalclass.cpp33
-rw-r--r--src/qml/jsruntime/qv4lookup.cpp198
-rw-r--r--src/qml/jsruntime/qv4lookup_p.h19
-rw-r--r--src/qml/jsruntime/qv4managed.cpp2
-rw-r--r--src/qml/jsruntime/qv4managed_p.h3
-rw-r--r--src/qml/jsruntime/qv4object.cpp28
-rw-r--r--src/qml/jsruntime/qv4object_p.h25
-rw-r--r--src/qml/jsruntime/qv4runtime.cpp104
-rw-r--r--src/qml/memory/qv4heap_p.h2
-rw-r--r--src/qml/memory/qv4mm.cpp7
-rw-r--r--src/qml/memory/qv4mm_p.h6
-rw-r--r--src/qml/qtqmlglobal_p.h6
-rw-r--r--src/qml/types/qqmlconnections.cpp1
-rw-r--r--src/quick/designer/qquickdesignersupportitems.cpp8
-rw-r--r--src/quick/items/qquickwindow.cpp2
22 files changed, 369 insertions, 97 deletions
diff --git a/src/plugins/qmltooling/qmldbg_profiler/qqmlprofileradapter.cpp b/src/plugins/qmltooling/qmldbg_profiler/qqmlprofileradapter.cpp
index 90e817e2fc..510c745d4e 100644
--- a/src/plugins/qmltooling/qmldbg_profiler/qqmlprofileradapter.cpp
+++ b/src/plugins/qmltooling/qmldbg_profiler/qqmlprofileradapter.cpp
@@ -66,8 +66,6 @@ QQmlProfilerAdapter::QQmlProfilerAdapter(QQmlProfilerService *service, QQmlEngin
}
// convert to QByteArrays that can be sent to the debug client
-// use of QDataStream can skew results
-// (see tst_qqmldebugtrace::trace() benchmark)
static void qQmlProfilerDataToByteArrays(const QQmlProfilerData &d,
QQmlProfiler::LocationHash &locations,
QList<QByteArray> &messages,
diff --git a/src/plugins/qmltooling/qmldbg_quickprofiler/qquickprofileradapter.cpp b/src/plugins/qmltooling/qmldbg_quickprofiler/qquickprofileradapter.cpp
index 0c9fc36463..35beb0ee0d 100644
--- a/src/plugins/qmltooling/qmldbg_quickprofiler/qquickprofileradapter.cpp
+++ b/src/plugins/qmltooling/qmldbg_quickprofiler/qquickprofileradapter.cpp
@@ -74,8 +74,6 @@ QQuickProfilerAdapter::~QQuickProfilerAdapter()
}
// convert to QByteArrays that can be sent to the debug client
-// use of QDataStream can skew results
-// (see tst_qqmldebugtrace::trace() benchmark)
static void qQuickProfilerDataToByteArrays(const QQuickProfilerData &data,
QList<QByteArray> &messages)
{
diff --git a/src/qml/compiler/qv4isel_moth.cpp b/src/qml/compiler/qv4isel_moth.cpp
index aefb084971..dc6fe317e5 100644
--- a/src/qml/compiler/qv4isel_moth.cpp
+++ b/src/qml/compiler/qv4isel_moth.cpp
@@ -638,7 +638,7 @@ void InstructionSelection::getQObjectProperty(IR::Expr *base, int propertyIndex,
void InstructionSelection::getElement(IR::Expr *base, IR::Expr *index, IR::Expr *target)
{
- if (useFastLookups) {
+ if (0 && useFastLookups) {
Instruction::LoadElementLookup load;
load.lookup = registerIndexedGetterLookup();
load.base = getParam(base);
@@ -657,7 +657,7 @@ void InstructionSelection::getElement(IR::Expr *base, IR::Expr *index, IR::Expr
void InstructionSelection::setElement(IR::Expr *source, IR::Expr *targetBase,
IR::Expr *targetIndex)
{
- if (useFastLookups) {
+ if (0 && useFastLookups) {
Instruction::StoreElementLookup store;
store.lookup = registerIndexedSetterLookup();
store.base = getParam(targetBase);
diff --git a/src/qml/compiler/qv4ssa.cpp b/src/qml/compiler/qv4ssa.cpp
index 731c6ad38f..fc136b09ff 100644
--- a/src/qml/compiler/qv4ssa.cpp
+++ b/src/qml/compiler/qv4ssa.cpp
@@ -5417,7 +5417,11 @@ void Optimizer::run(QQmlEnginePrivate *qmlEngine, bool doTypeInference, bool pee
showMeTheCode(function, "After loop detection");
// cfg2dot(function, loopDetection.allLoops());
- if (peelLoops) {
+ // ### disable loop peeling for now. It doesn't give any measurable performance
+ // improvements at this time, but significantly increases the size of the
+ // JIT generated code
+ Q_UNUSED(peelLoops);
+ if (0 && peelLoops) {
QVector<LoopDetection::LoopInfo *> innerLoops = loopDetection.innermostLoops();
LoopPeeling(df).run(innerLoops);
diff --git a/src/qml/jit/qv4isel_masm.cpp b/src/qml/jit/qv4isel_masm.cpp
index ac72d2e8f5..50d40f6f98 100644
--- a/src/qml/jit/qv4isel_masm.cpp
+++ b/src/qml/jit/qv4isel_masm.cpp
@@ -618,7 +618,7 @@ void InstructionSelection<JITAssembler>::setQObjectProperty(IR::Expr *source, IR
template <typename JITAssembler>
void InstructionSelection<JITAssembler>::getElement(IR::Expr *base, IR::Expr *index, IR::Expr *target)
{
- if (useFastLookups) {
+ if (0 && useFastLookups) {
uint lookup = registerIndexedGetterLookup();
generateLookupCall(target, lookup, offsetof(QV4::Lookup, indexedGetter),
PointerToValue(base),
@@ -633,7 +633,7 @@ void InstructionSelection<JITAssembler>::getElement(IR::Expr *base, IR::Expr *in
template <typename JITAssembler>
void InstructionSelection<JITAssembler>::setElement(IR::Expr *source, IR::Expr *targetBase, IR::Expr *targetIndex)
{
- if (useFastLookups) {
+ if (0 && useFastLookups) {
uint lookup = registerIndexedSetterLookup();
generateLookupCall(JITAssembler::Void, lookup, offsetof(QV4::Lookup, indexedSetter),
PointerToValue(targetBase), PointerToValue(targetIndex),
diff --git a/src/qml/jsruntime/qv4arraydata.cpp b/src/qml/jsruntime/qv4arraydata.cpp
index c29cedaa9b..6d1fb62e0a 100644
--- a/src/qml/jsruntime/qv4arraydata.cpp
+++ b/src/qml/jsruntime/qv4arraydata.cpp
@@ -50,6 +50,8 @@ QT_WARNING_SUPPRESS_GCC_TAUTOLOGICAL_COMPARE_ON
const QV4::VTable QV4::ArrayData::static_vtbl = {
0,
+ 0,
+ 0,
QV4::ArrayData::IsExecutionContext,
QV4::ArrayData::IsString,
QV4::ArrayData::IsObject,
diff --git a/src/qml/jsruntime/qv4executableallocator_p.h b/src/qml/jsruntime/qv4executableallocator_p.h
index f13f70e01a..353a6eacff 100644
--- a/src/qml/jsruntime/qv4executableallocator_p.h
+++ b/src/qml/jsruntime/qv4executableallocator_p.h
@@ -67,7 +67,7 @@ QT_BEGIN_NAMESPACE
namespace QV4 {
-class Q_AUTOTEST_EXPORT ExecutableAllocator
+class Q_QML_AUTOTEST_EXPORT ExecutableAllocator
{
public:
struct ChunkOfPages;
diff --git a/src/qml/jsruntime/qv4internalclass.cpp b/src/qml/jsruntime/qv4internalclass.cpp
index bac71b4537..7e3fd7dc12 100644
--- a/src/qml/jsruntime/qv4internalclass.cpp
+++ b/src/qml/jsruntime/qv4internalclass.cpp
@@ -43,6 +43,7 @@
#include <qv4identifier_p.h>
#include "qv4object_p.h"
#include "qv4identifiertable_p.h"
+#include "qv4value_p.h"
QT_BEGIN_NAMESPACE
@@ -128,22 +129,48 @@ InternalClass::InternalClass(const QV4::InternalClass &other)
static void insertHoleIntoPropertyData(Object *object, int idx)
{
+ int inlineSize = object->d()->vt->nInlineProperties;
int icSize = object->internalClass()->size;
- int from = idx;
+ int from = qMax(idx, inlineSize);
int to = from + 1;
- if (from < icSize)
+ if (from < icSize) {
memmove(object->propertyData(to), object->propertyData(from),
(icSize - from - 1) * sizeof(Value));
+ }
+ if (from == idx)
+ return;
+ if (inlineSize < icSize)
+ *object->propertyData(inlineSize) = *object->propertyData(inlineSize - 1);
+ from = idx;
+ to = from + 1;
+ if (from < inlineSize - 1) {
+ memmove(object->propertyData(to), object->propertyData(from),
+ (inlineSize - from - 1) * sizeof(Value));
+ }
}
static void removeFromPropertyData(Object *object, int idx, bool accessor = false)
{
+ int inlineSize = object->d()->vt->nInlineProperties;
int delta = (accessor ? 2 : 1);
int oldSize = object->internalClass()->size + delta;
int to = idx;
int from = to + delta;
- if (from < oldSize)
+ if (from < inlineSize) {
+ memmove(object->propertyData(to), object->d()->propertyData(from), (inlineSize - from)*sizeof(Value));
+ to = inlineSize - delta;
+ from = inlineSize;
+ }
+ if (to < inlineSize && from < oldSize) {
+ Q_ASSERT(from >= inlineSize);
+ memcpy(object->propertyData(to), object->d()->propertyData(from), (inlineSize - to)*sizeof(Value));
+ to = inlineSize;
+ from = inlineSize + delta;
+ }
+ if (from < oldSize) {
+ Q_ASSERT(to >= inlineSize && from > to);
memmove(object->propertyData(to), object->d()->propertyData(from), (oldSize - to)*sizeof(Value));
+ }
}
void InternalClass::changeMember(Object *object, String *string, PropertyAttributes data, uint *index)
diff --git a/src/qml/jsruntime/qv4lookup.cpp b/src/qml/jsruntime/qv4lookup.cpp
index 52ed449664..0d467098fe 100644
--- a/src/qml/jsruntime/qv4lookup.cpp
+++ b/src/qml/jsruntime/qv4lookup.cpp
@@ -284,11 +284,17 @@ ReturnedValue Lookup::getterGeneric(Lookup *l, ExecutionEngine *engine, const Va
ReturnedValue v = l->lookup(object, proto, &attrs);
if (v != Primitive::emptyValue().asReturnedValue()) {
l->type = object.type();
- l->proto = proto;
+ l->proto = proto->d();
if (attrs.isData()) {
- if (l->level == 0)
- l->getter = Lookup::primitiveGetter0;
- else if (l->level == 1)
+ if (l->level == 0) {
+ uint nInline = l->proto->vt->nInlineProperties;
+ if (l->index < nInline)
+ l->getter = Lookup::primitiveGetter0Inline;
+ else {
+ l->index -= nInline;
+ l->getter = Lookup::primitiveGetter0MemberData;
+ }
+ } else if (l->level == 1)
l->getter = Lookup::primitiveGetter1;
return v;
} else {
@@ -307,15 +313,18 @@ ReturnedValue Lookup::getterTwoClasses(Lookup *l, ExecutionEngine *engine, const
{
Lookup l1 = *l;
- if (l1.getter == Lookup::getter0 || l1.getter == Lookup::getter1) {
+ if (l1.getter == Lookup::getter0MemberData || l1.getter == Lookup::getter0Inline || l1.getter == Lookup::getter1) {
if (const Object *o = object.as<Object>()) {
ReturnedValue v = o->getLookup(l);
Lookup l2 = *l;
- if (l->index != UINT_MAX && (l2.getter == Lookup::getter0 || l2.getter == Lookup::getter1)) {
- // if we have a getter0, make sure it comes first
- if (l2.getter == Lookup::getter0)
- qSwap(l1, l2);
+ if (l2.index != UINT_MAX) {
+ if (l1.getter != Lookup::getter0Inline) {
+ if (l2.getter == Lookup::getter0Inline ||
+ (l1.getter != Lookup::getter0MemberData && l2.getter == Lookup::getter0MemberData))
+ // sort the better getter first
+ qSwap(l1, l2);
+ }
l->classList[0] = l1.classList[0];
l->classList[1] = l1.classList[1];
@@ -324,8 +333,22 @@ ReturnedValue Lookup::getterTwoClasses(Lookup *l, ExecutionEngine *engine, const
l->index = l1.index;
l->index2 = l2.index;
- if (l1.getter == Lookup::getter0) {
- l->getter = (l2.getter == Lookup::getter0) ? Lookup::getter0getter0 : Lookup::getter0getter1;
+ if (l1.getter == Lookup::getter0Inline) {
+ if (l2.getter == Lookup::getter0Inline)
+ l->getter = Lookup::getter0Inlinegetter0Inline;
+ else if (l2.getter == Lookup::getter0MemberData)
+ l->getter = Lookup::getter0Inlinegetter0MemberData;
+ else if (l2.getter == Lookup::getter1)
+ l->getter = Lookup::getter0Inlinegetter1;
+ else
+ Q_UNREACHABLE();
+ } else if (l1.getter == Lookup::getter0MemberData) {
+ if (l2.getter == Lookup::getter0MemberData)
+ l->getter = Lookup::getter0MemberDatagetter0MemberData;
+ else if (l2.getter == Lookup::getter1)
+ l->getter = Lookup::getter0MemberDatagetter1;
+ else
+ Q_UNREACHABLE();
} else {
Q_ASSERT(l1.getter == Lookup::getter1 && l2.getter == Lookup::getter1);
l->getter = Lookup::getter1getter1;
@@ -349,14 +372,26 @@ ReturnedValue Lookup::getterFallback(Lookup *l, ExecutionEngine *engine, const V
return o->get(name);
}
-ReturnedValue Lookup::getter0(Lookup *l, ExecutionEngine *engine, const Value &object)
+ReturnedValue Lookup::getter0MemberData(Lookup *l, ExecutionEngine *engine, const Value &object)
{
// we can safely cast to a QV4::Object here. If object is actually a string,
// the internal class won't match
Heap::Object *o = static_cast<Heap::Object *>(object.heapObject());
if (o) {
if (l->classList[0] == o->internalClass)
- return o->propertyData(l->index)->asReturnedValue();
+ return o->memberData->data[l->index].asReturnedValue();
+ }
+ return getterTwoClasses(l, engine, object);
+}
+
+ReturnedValue Lookup::getter0Inline(Lookup *l, ExecutionEngine *engine, const Value &object)
+{
+ // we can safely cast to a QV4::Object here. If object is actually a string,
+ // the internal class won't match
+ Heap::Object *o = static_cast<Heap::Object *>(object.heapObject());
+ if (o) {
+ if (l->classList[0] == o->internalClass)
+ return o->inlinePropertyData(l->index)->asReturnedValue();
}
return getterTwoClasses(l, engine, object);
}
@@ -392,29 +427,74 @@ ReturnedValue Lookup::getter2(Lookup *l, ExecutionEngine *engine, const Value &o
return getterFallback(l, engine, object);
}
-ReturnedValue Lookup::getter0getter0(Lookup *l, ExecutionEngine *engine, const Value &object)
+ReturnedValue Lookup::getter0Inlinegetter0Inline(Lookup *l, ExecutionEngine *engine, const Value &object)
{
// we can safely cast to a QV4::Object here. If object is actually a string,
// the internal class won't match
Heap::Object *o = static_cast<Heap::Object *>(object.heapObject());
if (o) {
if (l->classList[0] == o->internalClass)
- return o->propertyData(l->index)->asReturnedValue();
+ return o->inlinePropertyData(l->index)->asReturnedValue();
if (l->classList[2] == o->internalClass)
- return o->propertyData(l->index2)->asReturnedValue();
+ return o->inlinePropertyData(l->index2)->asReturnedValue();
}
l->getter = getterFallback;
return getterFallback(l, engine, object);
}
-ReturnedValue Lookup::getter0getter1(Lookup *l, ExecutionEngine *engine, const Value &object)
+ReturnedValue Lookup::getter0Inlinegetter0MemberData(Lookup *l, ExecutionEngine *engine, const Value &object)
{
// we can safely cast to a QV4::Object here. If object is actually a string,
// the internal class won't match
Heap::Object *o = static_cast<Heap::Object *>(object.heapObject());
if (o) {
if (l->classList[0] == o->internalClass)
- return o->propertyData(l->index)->asReturnedValue();
+ return o->inlinePropertyData(l->index)->asReturnedValue();
+ if (l->classList[2] == o->internalClass)
+ return o->memberData->data[l->index2].asReturnedValue();
+ }
+ l->getter = getterFallback;
+ return getterFallback(l, engine, object);
+}
+
+ReturnedValue Lookup::getter0MemberDatagetter0MemberData(Lookup *l, ExecutionEngine *engine, const Value &object)
+{
+ // we can safely cast to a QV4::Object here. If object is actually a string,
+ // the internal class won't match
+ Heap::Object *o = static_cast<Heap::Object *>(object.heapObject());
+ if (o) {
+ if (l->classList[0] == o->internalClass)
+ return o->memberData->data[l->index].asReturnedValue();
+ if (l->classList[2] == o->internalClass)
+ return o->memberData->data[l->index2].asReturnedValue();
+ }
+ l->getter = getterFallback;
+ return getterFallback(l, engine, object);
+}
+
+ReturnedValue Lookup::getter0Inlinegetter1(Lookup *l, ExecutionEngine *engine, const Value &object)
+{
+ // we can safely cast to a QV4::Object here. If object is actually a string,
+ // the internal class won't match
+ Heap::Object *o = static_cast<Heap::Object *>(object.heapObject());
+ if (o) {
+ if (l->classList[0] == o->internalClass)
+ return o->inlinePropertyData(l->index)->asReturnedValue();
+ if (l->classList[2] == o->internalClass && l->classList[3] == o->prototype->internalClass)
+ return o->prototype->propertyData(l->index2)->asReturnedValue();
+ }
+ l->getter = getterFallback;
+ return getterFallback(l, engine, object);
+}
+
+ReturnedValue Lookup::getter0MemberDatagetter1(Lookup *l, ExecutionEngine *engine, const Value &object)
+{
+ // we can safely cast to a QV4::Object here. If object is actually a string,
+ // the internal class won't match
+ Heap::Object *o = static_cast<Heap::Object *>(object.heapObject());
+ if (o) {
+ if (l->classList[0] == o->internalClass)
+ return o->memberData->data[l->index].asReturnedValue();
if (l->classList[2] == o->internalClass && l->classList[3] == o->prototype->internalClass)
return o->prototype->propertyData(l->index2)->asReturnedValue();
}
@@ -514,12 +594,23 @@ ReturnedValue Lookup::getterAccessor2(Lookup *l, ExecutionEngine *engine, const
return getterFallback(l, engine, object);
}
-ReturnedValue Lookup::primitiveGetter0(Lookup *l, ExecutionEngine *engine, const Value &object)
+ReturnedValue Lookup::primitiveGetter0Inline(Lookup *l, ExecutionEngine *engine, const Value &object)
+{
+ if (object.type() == l->type) {
+ Heap::Object *o = l->proto;
+ if (l->classList[0] == o->internalClass)
+ return o->inlinePropertyData(l->index)->asReturnedValue();
+ }
+ l->getter = getterGeneric;
+ return getterGeneric(l, engine, object);
+}
+
+ReturnedValue Lookup::primitiveGetter0MemberData(Lookup *l, ExecutionEngine *engine, const Value &object)
{
if (object.type() == l->type) {
- Object *o = l->proto;
- if (l->classList[0] == o->internalClass())
- return o->propertyData(l->index)->asReturnedValue();
+ Heap::Object *o = l->proto;
+ if (l->classList[0] == o->internalClass)
+ return o->memberData->data[l->index].asReturnedValue();
}
l->getter = getterGeneric;
return getterGeneric(l, engine, object);
@@ -528,10 +619,10 @@ ReturnedValue Lookup::primitiveGetter0(Lookup *l, ExecutionEngine *engine, const
ReturnedValue Lookup::primitiveGetter1(Lookup *l, ExecutionEngine *engine, const Value &object)
{
if (object.type() == l->type) {
- Object *o = l->proto;
- if (l->classList[0] == o->internalClass() &&
- l->classList[1] == o->prototype()->internalClass)
- return o->prototype()->propertyData(l->index)->asReturnedValue();
+ Heap::Object *o = l->proto;
+ if (l->classList[0] == o->internalClass &&
+ l->classList[1] == o->prototype->internalClass)
+ return o->prototype->propertyData(l->index)->asReturnedValue();
}
l->getter = getterGeneric;
return getterGeneric(l, engine, object);
@@ -540,9 +631,9 @@ ReturnedValue Lookup::primitiveGetter1(Lookup *l, ExecutionEngine *engine, const
ReturnedValue Lookup::primitiveGetterAccessor0(Lookup *l, ExecutionEngine *engine, const Value &object)
{
if (object.type() == l->type) {
- Object *o = l->proto;
- if (l->classList[0] == o->internalClass()) {
- Scope scope(o->engine());
+ Heap::Object *o = l->proto;
+ if (l->classList[0] == o->internalClass) {
+ Scope scope(o->internalClass->engine);
ScopedFunctionObject getter(scope, o->propertyData(l->index + Object::GetterOffset));
if (!getter)
return Encode::undefined();
@@ -560,11 +651,11 @@ ReturnedValue Lookup::primitiveGetterAccessor0(Lookup *l, ExecutionEngine *engin
ReturnedValue Lookup::primitiveGetterAccessor1(Lookup *l, ExecutionEngine *engine, const Value &object)
{
if (object.type() == l->type) {
- Object *o = l->proto;
- if (l->classList[0] == o->internalClass() &&
- l->classList[1] == o->prototype()->internalClass) {
- Scope scope(o->engine());
- ScopedFunctionObject getter(scope, o->prototype()->propertyData(l->index + Object::GetterOffset));
+ Heap::Object *o = l->proto;
+ if (l->classList[0] == o->internalClass &&
+ l->classList[1] == o->prototype->internalClass) {
+ Scope scope(o->internalClass->engine);
+ ScopedFunctionObject getter(scope, o->prototype->propertyData(l->index + Object::GetterOffset));
if (!getter)
return Encode::undefined();
@@ -604,9 +695,15 @@ ReturnedValue Lookup::globalGetterGeneric(Lookup *l, ExecutionEngine *engine)
ReturnedValue v = l->lookup(o, &attrs);
if (v != Primitive::emptyValue().asReturnedValue()) {
if (attrs.isData()) {
- if (l->level == 0)
- l->globalGetter = globalGetter0;
- else if (l->level == 1)
+ if (l->level == 0) {
+ uint nInline = o->d()->vt->nInlineProperties;
+ if (l->index < nInline)
+ l->globalGetter = globalGetter0Inline;
+ else {
+ l->index -= nInline;
+ l->globalGetter = globalGetter0MemberData;
+ }
+ } else if (l->level == 1)
l->globalGetter = globalGetter1;
else if (l->level == 2)
l->globalGetter = globalGetter2;
@@ -626,11 +723,21 @@ ReturnedValue Lookup::globalGetterGeneric(Lookup *l, ExecutionEngine *engine)
return engine->throwReferenceError(n);
}
-ReturnedValue Lookup::globalGetter0(Lookup *l, ExecutionEngine *engine)
+ReturnedValue Lookup::globalGetter0Inline(Lookup *l, ExecutionEngine *engine)
+{
+ Object *o = engine->globalObject;
+ if (l->classList[0] == o->internalClass())
+ return o->d()->inlinePropertyData(l->index)->asReturnedValue();
+
+ l->globalGetter = globalGetterGeneric;
+ return globalGetterGeneric(l, engine);
+}
+
+ReturnedValue Lookup::globalGetter0MemberData(Lookup *l, ExecutionEngine *engine)
{
Object *o = engine->globalObject;
if (l->classList[0] == o->internalClass())
- return o->propertyData(l->index)->asReturnedValue();
+ return o->d()->memberData->data[l->index].asReturnedValue();
l->globalGetter = globalGetterGeneric;
return globalGetterGeneric(l, engine);
@@ -746,7 +853,7 @@ void Lookup::setterTwoClasses(Lookup *l, ExecutionEngine *engine, Value &object,
if (Object *o = object.as<Object>()) {
o->setLookup(l, value);
- if (l->setter == Lookup::setter0) {
+ if (l->setter == Lookup::setter0 || l->setter == Lookup::setter0Inline) {
l->setter = setter0setter0;
l->classList[1] = l1.classList[0];
l->index2 = l1.index;
@@ -779,6 +886,17 @@ void Lookup::setter0(Lookup *l, ExecutionEngine *engine, Value &object, const Va
setterTwoClasses(l, engine, object, value);
}
+void Lookup::setter0Inline(Lookup *l, ExecutionEngine *engine, Value &object, const Value &value)
+{
+ Object *o = object.as<Object>();
+ if (o && o->internalClass() == l->classList[0]) {
+ *o->d()->inlinePropertyData(l->index) = value;
+ return;
+ }
+
+ setterTwoClasses(l, engine, object, value);
+}
+
void Lookup::setterInsert0(Lookup *l, ExecutionEngine *engine, Value &object, const Value &value)
{
Object *o = object.as<Object>();
diff --git a/src/qml/jsruntime/qv4lookup_p.h b/src/qml/jsruntime/qv4lookup_p.h
index 2ffb43cce9..9e50235b73 100644
--- a/src/qml/jsruntime/qv4lookup_p.h
+++ b/src/qml/jsruntime/qv4lookup_p.h
@@ -79,7 +79,7 @@ struct Lookup {
struct {
void *dummy0;
void *dummy1;
- Object *proto;
+ Heap::Object *proto;
unsigned type;
};
};
@@ -102,17 +102,22 @@ struct Lookup {
static ReturnedValue getterTwoClasses(Lookup *l, ExecutionEngine *engine, const Value &object);
static ReturnedValue getterFallback(Lookup *l, ExecutionEngine *engine, const Value &object);
- static ReturnedValue getter0(Lookup *l, ExecutionEngine *engine, const Value &object);
+ static ReturnedValue getter0MemberData(Lookup *l, ExecutionEngine *engine, const Value &object);
+ static ReturnedValue getter0Inline(Lookup *l, ExecutionEngine *engine, const Value &object);
static ReturnedValue getter1(Lookup *l, ExecutionEngine *engine, const Value &object);
static ReturnedValue getter2(Lookup *l, ExecutionEngine *engine, const Value &object);
- static ReturnedValue getter0getter0(Lookup *l, ExecutionEngine *engine, const Value &object);
- static ReturnedValue getter0getter1(Lookup *l, ExecutionEngine *engine, const Value &object);
+ static ReturnedValue getter0Inlinegetter0Inline(Lookup *l, ExecutionEngine *engine, const Value &object);
+ static ReturnedValue getter0Inlinegetter0MemberData(Lookup *l, ExecutionEngine *engine, const Value &object);
+ static ReturnedValue getter0MemberDatagetter0MemberData(Lookup *l, ExecutionEngine *engine, const Value &object);
+ static ReturnedValue getter0Inlinegetter1(Lookup *l, ExecutionEngine *engine, const Value &object);
+ static ReturnedValue getter0MemberDatagetter1(Lookup *l, ExecutionEngine *engine, const Value &object);
static ReturnedValue getter1getter1(Lookup *l, ExecutionEngine *engine, const Value &object);
static ReturnedValue getterAccessor0(Lookup *l, ExecutionEngine *engine, const Value &object);
static ReturnedValue getterAccessor1(Lookup *l, ExecutionEngine *engine, const Value &object);
static ReturnedValue getterAccessor2(Lookup *l, ExecutionEngine *engine, const Value &object);
- static ReturnedValue primitiveGetter0(Lookup *l, ExecutionEngine *engine, const Value &object);
+ static ReturnedValue primitiveGetter0Inline(Lookup *l, ExecutionEngine *engine, const Value &object);
+ static ReturnedValue primitiveGetter0MemberData(Lookup *l, ExecutionEngine *engine, const Value &object);
static ReturnedValue primitiveGetter1(Lookup *l, ExecutionEngine *engine, const Value &object);
static ReturnedValue primitiveGetterAccessor0(Lookup *l, ExecutionEngine *engine, const Value &object);
static ReturnedValue primitiveGetterAccessor1(Lookup *l, ExecutionEngine *engine, const Value &object);
@@ -120,7 +125,8 @@ struct Lookup {
static ReturnedValue arrayLengthGetter(Lookup *l, ExecutionEngine *engine, const Value &object);
static ReturnedValue globalGetterGeneric(Lookup *l, ExecutionEngine *engine);
- static ReturnedValue globalGetter0(Lookup *l, ExecutionEngine *engine);
+ static ReturnedValue globalGetter0Inline(Lookup *l, ExecutionEngine *engine);
+ static ReturnedValue globalGetter0MemberData(Lookup *l, ExecutionEngine *engine);
static ReturnedValue globalGetter1(Lookup *l, ExecutionEngine *engine);
static ReturnedValue globalGetter2(Lookup *l, ExecutionEngine *engine);
static ReturnedValue globalGetterAccessor0(Lookup *l, ExecutionEngine *engine);
@@ -131,6 +137,7 @@ struct Lookup {
static void setterTwoClasses(Lookup *l, ExecutionEngine *engine, Value &object, const Value &value);
static void setterFallback(Lookup *l, ExecutionEngine *engine, Value &object, const Value &value);
static void setter0(Lookup *l, ExecutionEngine *engine, Value &object, const Value &value);
+ static void setter0Inline(Lookup *l, ExecutionEngine *engine, Value &object, const Value &value);
static void setterInsert0(Lookup *l, ExecutionEngine *engine, Value &object, const Value &value);
static void setterInsert1(Lookup *l, ExecutionEngine *engine, Value &object, const Value &value);
static void setterInsert2(Lookup *l, ExecutionEngine *engine, Value &object, const Value &value);
diff --git a/src/qml/jsruntime/qv4managed.cpp b/src/qml/jsruntime/qv4managed.cpp
index 3a84a83b9c..200380eda0 100644
--- a/src/qml/jsruntime/qv4managed.cpp
+++ b/src/qml/jsruntime/qv4managed.cpp
@@ -47,6 +47,8 @@ using namespace QV4;
const VTable Managed::static_vtbl =
{
0,
+ 0,
+ 0,
Managed::IsExecutionContext,
Managed::IsString,
Managed::IsObject,
diff --git a/src/qml/jsruntime/qv4managed_p.h b/src/qml/jsruntime/qv4managed_p.h
index 5c764e7ff0..7e674c6ec7 100644
--- a/src/qml/jsruntime/qv4managed_p.h
+++ b/src/qml/jsruntime/qv4managed_p.h
@@ -129,6 +129,9 @@ inline void qYouForgotTheQ_MANAGED_Macro(T1, T2) {}
#define DEFINE_MANAGED_VTABLE_INT(classname, parentVTable) \
{ \
parentVTable, \
+ (sizeof(classname::Data) + sizeof(QV4::Value) - 1)/sizeof(QV4::Value), \
+ (sizeof(classname::Data) + QV4::Chunk::SlotSize - 1)/QV4::Chunk::SlotSize*QV4::Chunk::SlotSize/sizeof(QV4::Value) \
+ - (sizeof(classname::Data) + sizeof(QV4::Value) - 1)/sizeof(QV4::Value), \
classname::IsExecutionContext, \
classname::IsString, \
classname::IsObject, \
diff --git a/src/qml/jsruntime/qv4object.cpp b/src/qml/jsruntime/qv4object.cpp
index 12157af728..3d8e8f3ddf 100644
--- a/src/qml/jsruntime/qv4object.cpp
+++ b/src/qml/jsruntime/qv4object.cpp
@@ -61,9 +61,13 @@ DEFINE_OBJECT_VTABLE(Object);
void Object::setInternalClass(InternalClass *ic)
{
d()->internalClass = ic;
+ uint nInline = d()->vtable()->nInlineProperties;
+ if (ic->size <= nInline)
+ return;
bool hasMD = d()->memberData != nullptr;
- if ((!hasMD && ic->size) || (hasMD && d()->memberData->size < ic->size))
- d()->memberData = MemberData::allocate(ic->engine, ic->size, d()->memberData);
+ uint requiredSize = ic->size - nInline;
+ if (!hasMD || (hasMD && d()->memberData->size < requiredSize))
+ d()->memberData = MemberData::allocate(ic->engine, requiredSize, d()->memberData);
}
void Object::getProperty(uint index, Property *p, PropertyAttributes *attrs) const
@@ -261,6 +265,13 @@ void Object::markObjects(Heap::Base *that, ExecutionEngine *e)
o->arrayData->mark(e);
if (o->prototype)
o->prototype->mark(e);
+ uint nInline = o->vtable()->nInlineProperties;
+ Value *v = reinterpret_cast<Value *>(o) + o->vt->inlinePropertyOffset;
+ const Value *end = v + nInline;
+ while (v < end) {
+ v->mark(e);
+ ++v;
+ }
}
void Object::insertMember(String *s, const Property *p, PropertyAttributes attributes)
@@ -495,8 +506,15 @@ ReturnedValue Object::getLookup(const Managed *m, Lookup *l)
ReturnedValue v = l->lookup(o, &attrs);
if (v != Primitive::emptyValue().asReturnedValue()) {
if (attrs.isData()) {
- if (l->level == 0)
- l->getter = Lookup::getter0;
+ if (l->level == 0) {
+ uint nInline = o->d()->vt->nInlineProperties;
+ if (l->index < nInline)
+ l->getter = Lookup::getter0Inline;
+ else {
+ l->index -= nInline;
+ l->getter = Lookup::getter0MemberData;
+ }
+ }
else if (l->level == 1)
l->getter = Lookup::getter1;
else if (l->level == 2)
@@ -531,7 +549,7 @@ void Object::setLookup(Managed *m, Lookup *l, const Value &value)
if (idx != UINT_MAX && o->internalClass()->propertyData[idx].isData() && o->internalClass()->propertyData[idx].isWritable()) {
l->classList[0] = o->internalClass();
l->index = idx;
- l->setter = Lookup::setter0;
+ l->setter = idx < o->d()->vt->nInlineProperties ? Lookup::setter0Inline : Lookup::setter0;
*o->propertyData(idx) = value;
return;
}
diff --git a/src/qml/jsruntime/qv4object_p.h b/src/qml/jsruntime/qv4object_p.h
index 6a543ae1a8..45392c0486 100644
--- a/src/qml/jsruntime/qv4object_p.h
+++ b/src/qml/jsruntime/qv4object_p.h
@@ -71,8 +71,29 @@ struct Object : Base {
void init() { Base::init(); }
void destroy() { Base::destroy(); }
- const Value *propertyData(uint index) const { return memberData->data + index; }
- Value *propertyData(uint index) { return memberData->data + index; }
+ const Value *inlinePropertyData(uint index) const {
+ Q_ASSERT(index < vt->nInlineProperties);
+ return reinterpret_cast<const Value *>(this) + vt->inlinePropertyOffset + index;
+ }
+ Value *inlinePropertyData(uint index) {
+ Q_ASSERT(index < vt->nInlineProperties);
+ return reinterpret_cast<Value *>(this) + vt->inlinePropertyOffset + index;
+ }
+
+ const Value *propertyData(uint index) const {
+ uint nInline = vt->nInlineProperties;
+ if (index < nInline)
+ return reinterpret_cast<const Value *>(this) + vt->inlinePropertyOffset + index;
+ index -= nInline;
+ return memberData->data + index;
+ }
+ Value *propertyData(uint index) {
+ uint nInline = vt->nInlineProperties;
+ if (index < nInline)
+ return reinterpret_cast<Value *>(this) + vt->inlinePropertyOffset + index;
+ index -= nInline;
+ return memberData->data + index;
+ }
InternalClass *internalClass;
Pointer<Object> prototype;
diff --git a/src/qml/jsruntime/qv4runtime.cpp b/src/qml/jsruntime/qv4runtime.cpp
index 42bf24d7f3..4b440f5335 100644
--- a/src/qml/jsruntime/qv4runtime.cpp
+++ b/src/qml/jsruntime/qv4runtime.cpp
@@ -599,41 +599,53 @@ void Runtime::method_setProperty(ExecutionEngine *engine, const Value &object, i
o->put(name, value);
}
-ReturnedValue Runtime::method_getElement(ExecutionEngine *engine, const Value &object, const Value &index)
+static Q_NEVER_INLINE ReturnedValue getElementIntFallback(ExecutionEngine *engine, const Value &object, uint idx)
{
+ Q_ASSERT(idx < UINT_MAX);
Scope scope(engine);
- uint idx = index.asArrayIndex();
ScopedObject o(scope, object);
if (!o) {
- if (idx < UINT_MAX) {
- if (const String *str = object.as<String>()) {
- if (idx >= (uint)str->toQString().length()) {
- return Encode::undefined();
- }
- const QString s = str->toQString().mid(idx, 1);
- return scope.engine->newString(s)->asReturnedValue();
+ if (const String *str = object.as<String>()) {
+ if (idx >= (uint)str->toQString().length()) {
+ return Encode::undefined();
}
+ const QString s = str->toQString().mid(idx, 1);
+ return scope.engine->newString(s)->asReturnedValue();
}
if (object.isNullOrUndefined()) {
- QString message = QStringLiteral("Cannot read property '%1' of %2").arg(index.toQStringNoThrow()).arg(object.toQStringNoThrow());
+ QString message = QStringLiteral("Cannot read property '%1' of %2").arg(idx).arg(object.toQStringNoThrow());
return engine->throwTypeError(message);
}
o = RuntimeHelpers::convertToObject(scope.engine, object);
- if (!o) // type error
- return Encode::undefined();
+ Q_ASSERT(!!o); // can't fail as null/undefined is covered above
+ }
+
+ if (o->arrayData() && !o->arrayData()->attrs) {
+ ScopedValue v(scope, o->arrayData()->get(idx));
+ if (!v->isEmpty())
+ return v->asReturnedValue();
}
- if (idx < UINT_MAX) {
- if (o->arrayData() && !o->arrayData()->attrs) {
- ScopedValue v(scope, o->arrayData()->get(idx));
- if (!v->isEmpty())
- return v->asReturnedValue();
+ return o->getIndexed(idx);
+}
+
+static Q_NEVER_INLINE ReturnedValue getElementFallback(ExecutionEngine *engine, const Value &object, const Value &index)
+{
+ Q_ASSERT(index.asArrayIndex() == UINT_MAX);
+ Scope scope(engine);
+
+ ScopedObject o(scope, object);
+ if (!o) {
+ if (object.isNullOrUndefined()) {
+ QString message = QStringLiteral("Cannot read property '%1' of %2").arg(index.toQStringNoThrow()).arg(object.toQStringNoThrow());
+ return engine->throwTypeError(message);
}
- return o->getIndexed(idx);
+ o = RuntimeHelpers::convertToObject(scope.engine, object);
+ Q_ASSERT(!!o); // can't fail as null/undefined is covered above
}
ScopedString name(scope, index.toString(engine));
@@ -642,18 +654,39 @@ ReturnedValue Runtime::method_getElement(ExecutionEngine *engine, const Value &o
return o->get(name);
}
-void Runtime::method_setElement(ExecutionEngine *engine, const Value &object, const Value &index, const Value &value)
+ReturnedValue Runtime::method_getElement(ExecutionEngine *engine, const Value &object, const Value &index)
+{
+ uint idx;
+ if (index.asArrayIndex(idx)) {
+ if (Heap::Base *b = object.heapObject()) {
+ if (b->vtable()->isObject) {
+ Heap::Object *o = static_cast<Heap::Object *>(b);
+ if (o->arrayData && o->arrayData->type == Heap::ArrayData::Simple) {
+ Heap::SimpleArrayData *s = o->arrayData.cast<Heap::SimpleArrayData>();
+ if (idx < s->len)
+ if (!s->data(idx).isEmpty())
+ return s->data(idx).asReturnedValue();
+ }
+ }
+ }
+ return getElementIntFallback(engine, object, idx);
+ }
+
+ return getElementFallback(engine, object, index);
+}
+
+static Q_NEVER_INLINE void setElementFallback(ExecutionEngine *engine, const Value &object, const Value &index, const Value &value)
{
Scope scope(engine);
ScopedObject o(scope, object.toObject(engine));
- if (scope.engine->hasException)
+ if (engine->hasException)
return;
- uint idx = index.asArrayIndex();
- if (idx < UINT_MAX) {
- if (o->arrayType() == Heap::ArrayData::Simple) {
- Heap::SimpleArrayData *s = static_cast<Heap::SimpleArrayData *>(o->arrayData());
- if (s && idx < s->len && !s->data(idx).isEmpty()) {
+ uint idx;
+ if (index.asArrayIndex(idx)) {
+ if (o->d()->arrayData && o->d()->arrayData->type == Heap::ArrayData::Simple) {
+ Heap::SimpleArrayData *s = o->d()->arrayData.cast<Heap::SimpleArrayData>();
+ if (idx < s->len) {
s->data(idx) = value;
return;
}
@@ -666,6 +699,27 @@ void Runtime::method_setElement(ExecutionEngine *engine, const Value &object, co
o->put(name, value);
}
+void Runtime::method_setElement(ExecutionEngine *engine, const Value &object, const Value &index, const Value &value)
+{
+ uint idx;
+ if (index.asArrayIndex(idx)) {
+ if (Heap::Base *b = object.heapObject()) {
+ if (b->vtable()->isObject) {
+ Heap::Object *o = static_cast<Heap::Object *>(b);
+ if (o->arrayData && o->arrayData->type == Heap::ArrayData::Simple) {
+ Heap::SimpleArrayData *s = o->arrayData.cast<Heap::SimpleArrayData>();
+ if (idx < s->len) {
+ s->data(idx) = value;
+ return;
+ }
+ }
+ }
+ }
+ }
+
+ return setElementFallback(engine, object, index, value);
+}
+
ReturnedValue Runtime::method_foreachIterator(ExecutionEngine *engine, const Value &in)
{
Scope scope(engine);
diff --git a/src/qml/memory/qv4heap_p.h b/src/qml/memory/qv4heap_p.h
index 173c0a3e20..cd0a6d9a81 100644
--- a/src/qml/memory/qv4heap_p.h
+++ b/src/qml/memory/qv4heap_p.h
@@ -72,6 +72,8 @@ namespace QV4 {
struct VTable
{
const VTable * const parent;
+ uint inlinePropertyOffset : 16;
+ uint nInlineProperties : 16;
uint isExecutionContext : 1;
uint isString : 1;
uint isObject : 1;
diff --git a/src/qml/memory/qv4mm.cpp b/src/qml/memory/qv4mm.cpp
index 7aa8f91503..0a6dfb9170 100644
--- a/src/qml/memory/qv4mm.cpp
+++ b/src/qml/memory/qv4mm.cpp
@@ -757,12 +757,15 @@ Heap::Base *MemoryManager::allocData(std::size_t size)
return *m;
}
-Heap::Object *MemoryManager::allocObjectWithMemberData(std::size_t size, uint nMembers)
+Heap::Object *MemoryManager::allocObjectWithMemberData(const QV4::VTable *vtable, uint nMembers)
{
+ uint size = (vtable->nInlineProperties + vtable->inlinePropertyOffset)*sizeof(Value);
+ Q_ASSERT(!(size % sizeof(HeapItem)));
Heap::Object *o = static_cast<Heap::Object *>(allocData(size));
// ### Could optimize this and allocate both in one go through the block allocator
- if (nMembers) {
+ if (nMembers > vtable->nInlineProperties) {
+ nMembers -= vtable->nInlineProperties;
std::size_t memberSize = align(sizeof(Heap::MemberData) + (nMembers - 1)*sizeof(Value));
// qDebug() << "allocating member data for" << o << nMembers << memberSize;
Heap::Base *m;
diff --git a/src/qml/memory/qv4mm_p.h b/src/qml/memory/qv4mm_p.h
index 00daf8a622..9b4c2cd8df 100644
--- a/src/qml/memory/qv4mm_p.h
+++ b/src/qml/memory/qv4mm_p.h
@@ -231,7 +231,7 @@ public:
template <typename ObjectType>
typename ObjectType::Data *allocateObject(InternalClass *ic)
{
- Heap::Object *o = allocObjectWithMemberData(align(sizeof(typename ObjectType::Data)), ic->size);
+ Heap::Object *o = allocObjectWithMemberData(ObjectType::staticVTable(), ic->size);
o->setVtable(ObjectType::staticVTable());
o->internalClass = ic;
return static_cast<typename ObjectType::Data *>(o);
@@ -241,7 +241,7 @@ public:
typename ObjectType::Data *allocateObject()
{
InternalClass *ic = ObjectType::defaultInternalClass(engine);
- Heap::Object *o = allocObjectWithMemberData(align(sizeof(typename ObjectType::Data)), ic->size);
+ Heap::Object *o = allocObjectWithMemberData(ObjectType::staticVTable(), ic->size);
o->setVtable(ObjectType::staticVTable());
Object *prototype = ObjectType::defaultPrototype(engine);
o->internalClass = ic;
@@ -433,7 +433,7 @@ protected:
/// expects size to be aligned
Heap::Base *allocString(std::size_t unmanagedSize);
Heap::Base *allocData(std::size_t size);
- Heap::Object *allocObjectWithMemberData(std::size_t size, uint nMembers);
+ Heap::Object *allocObjectWithMemberData(const QV4::VTable *vtable, uint nMembers);
#ifdef DETAILED_MM_STATS
void willAllocate(std::size_t size);
diff --git a/src/qml/qtqmlglobal_p.h b/src/qml/qtqmlglobal_p.h
index e9834ffc4c..3314e73d19 100644
--- a/src/qml/qtqmlglobal_p.h
+++ b/src/qml/qtqmlglobal_p.h
@@ -57,4 +57,10 @@
#define Q_QML_PRIVATE_EXPORT Q_QML_EXPORT
+#if !defined(QT_QMLDEVTOOLS_LIB) && !defined(QT_BUILD_QMLDEVTOOLS_LIB)
+# define Q_QML_AUTOTEST_EXPORT Q_AUTOTEST_EXPORT
+#else
+# define Q_QML_AUTOTEST_EXPORT
+#endif
+
#endif // QTQMLGLOBAL_P_H
diff --git a/src/qml/types/qqmlconnections.cpp b/src/qml/types/qqmlconnections.cpp
index cbf0f69093..7607c19374 100644
--- a/src/qml/types/qqmlconnections.cpp
+++ b/src/qml/types/qqmlconnections.cpp
@@ -287,6 +287,7 @@ void QQmlConnections::connectSignals()
int signalIndex = QQmlPropertyPrivate::get(prop)->signalIndex();
QQmlBoundSignal *signal =
new QQmlBoundSignal(target, signalIndex, this, qmlEngine(this));
+ signal->setEnabled(d->enabled);
QQmlBoundSignalExpression *expression = ctxtdata ?
new QQmlBoundSignalExpression(target, signalIndex,
diff --git a/src/quick/designer/qquickdesignersupportitems.cpp b/src/quick/designer/qquickdesignersupportitems.cpp
index 2003b484ad..874faed0af 100644
--- a/src/quick/designer/qquickdesignersupportitems.cpp
+++ b/src/quick/designer/qquickdesignersupportitems.cpp
@@ -47,6 +47,7 @@
#include <private/qquicktextinput_p.h>
#include <private/qquicktextedit_p.h>
#include <private/qquicktransition_p.h>
+#include <private/qquickloader_p.h>
#include <private/qquickanimation_p.h>
#include <private/qqmlmetatype_p.h>
@@ -79,6 +80,12 @@ static void stopAnimation(QObject *object)
}
}
+static void makeLoaderSynchronous(QObject *object)
+{
+ if (QQuickLoader *loader = qobject_cast<QQuickLoader*>(object))
+ loader->setAsynchronous(false);
+}
+
static void allSubObjects(QObject *object, QObjectList &objectList)
{
// don't add null pointer and stop if the object is already in the list
@@ -137,6 +144,7 @@ void QQuickDesignerSupportItems::tweakObjects(QObject *object)
allSubObjects(object, objectList);
for (QObject* childObject : qAsConst(objectList)) {
stopAnimation(childObject);
+ makeLoaderSynchronous(childObject);
if (fixResourcePathsForObjectCallBack)
fixResourcePathsForObjectCallBack(childObject);
}
diff --git a/src/quick/items/qquickwindow.cpp b/src/quick/items/qquickwindow.cpp
index 816c057ab0..67069c7d15 100644
--- a/src/quick/items/qquickwindow.cpp
+++ b/src/quick/items/qquickwindow.cpp
@@ -3865,7 +3865,7 @@ QSGTexture *QQuickWindow::createTextureFromImage(const QImage &image) const
QSGTexture *QQuickWindow::createTextureFromImage(const QImage &image, CreateTextureOptions options) const
{
Q_D(const QQuickWindow);
- if (!isSceneGraphInitialized()) // check both for d->context and d->context->isValid()
+ if (!isSceneGraphInitialized() || image.isNull()) // check both for d->context and d->context->isValid()
return 0;
uint flags = 0;
if (options & TextureCanUseAtlas) flags |= QSGRenderContext::CreateTexture_Atlas;